From afd058dccaeb03302706840cf59ec79ad67f7b41 Mon Sep 17 00:00:00 2001 From: Michal Raczka Date: Thu, 14 Sep 2017 09:46:29 +0200 Subject: [PATCH 1/6] Additional claims docs and consistent quoting --- README.md | 111 +++++++++++++++++++++++++++++++----------------------- 1 file changed, 64 insertions(+), 47 deletions(-) diff --git a/README.md b/README.md index 4c46f37..5e26251 100644 --- a/README.md +++ b/README.md @@ -26,12 +26,12 @@ Creating a new Hull client is pretty straightforward: `npm install -s hull-client` ```js -import Hull from 'hull-client'; +import Hull from "hull-client"; const client = new Hull({ - id: 'HULL_ID', - secret: 'HULL_SECRET', - organization: 'HULL_ORGANIZATION_DOMAIN' + id: "HULL_ID", + secret: "HULL_SECRET", + organization: "HULL_ORGANIZATION_DOMAIN" }); ``` @@ -76,21 +76,21 @@ Returns the global configuration object. ```js client.configuration(); // returns: -{ prefix: '/api/v1', - domain: 'hullapp.io', - protocol: 'https', - id: '58765f7de3aa14001999', - secret: '12347asc855041674dc961af50fc1', - organization: 'fa4321.hullapp.io', - version: '0.11.4' } +{ prefix: "/api/v1", + domain: "hullapp.io", + protocol: "https", + id: "58765f7de3aa14001999", + secret: "12347asc855041674dc961af50fc1", + organization: "fa4321.hullapp.io", + version: "0.11.4" } ``` ### client.token() ```js -client.asUser({ email:'xxx@example.com', external_id: "1234", name:'FooBar' }).token(optionalClaims); -client.asAccount({ domain:'example.com', external_id: "1234", name:'FooBar' }).token(optionalClaims); +client.asUser({ email: "xxx@example.com", external_id: "1234", name: "FooBar" }).token(optionalClaims); +client.asAccount({ domain: "example.com", external_id: "1234", name: "FooBar" }).token(optionalClaims); ``` Used for [Bring your own users](http://hull.io/docs/users/byou). @@ -136,9 +136,11 @@ the calls to another instance of `hull` client. This means `user` is an instance The second parameter lets you define additional options (JWT claims) passed to the user resolution script: * **create** - *boolean* - marks if the user should be lazily created if not found (default: *true*) -* **scopes** - *Array* - adds scopes claim to the JWT to impersonate a User with admin rights. +* **active** - *boolean* - marks if the user should be put on a fast-lane to process with minimal delay (default: *false*) +* **scopes** - *Array\* - adds scopes claim to the JWT to impersonate a User with admin rights. ### Possible usage + > Return a hull `client` scoped to the user identified by it's Hull ID. Not lazily created. Needs an existing User ```js @@ -148,32 +150,46 @@ client.asUser(userId); > Return a hull `client` scoped to the user identified by it's Social network ID. Lazily created if [Guest Users](http://www.hull.io/docs/users/guest_users) are enabled ```js -client.asUser('instagram|facebook|google:userId'); +client.asUser("instagram|facebook|google:userId"); ``` > Return a hull `client` scoped to the user identified by it's External ID (from your dashboard). Lazily created if [Guest Users](http://www.hull.io/docs/users/guest_users) are enabled ```js -client.asUser({ external_id: 'externalId' }); +client.asUser({ external_id: "externalId" }); ``` -> Return a hull `client` scoped to the user identified by it's External ID (from your dashboard). Lazily created if [Guest Users](http://www.hull.io/docs/users/guest_users) are enabled +> Return a hull `client` scoped to the user identified only by an anonymousId. Lets you start tracking and storing properties from a user before you have a UserID ready for him. Lazily created if [Guest Users](http://www.hull.io/docs/users/guest_users) are enabled +> When you have a UserId, just pass both to link them. ```js -client.asUser({ anonymous_id: 'anonymousId' }); +client.asUser({ anonymous_id: "anonymousId" }); +// or to link anonymousId with userId +client.asUser({ anonymous_id: "anonymousId", id: "userId" }); ``` -> Return a hull `client` scoped to the user identified by only by an anonymousId. Lets you start tracking and storing properties from a user before you have a UserID ready for him. Lazily created if [Guest Users](http://www.hull.io/docs/users/guest_users) are enabled -> When you have a UserId, just pass both to link them. +> Return a hull `client` scoped to the user identified only by an email. If not found would be created. ```js client.asUser({ email: "user@email.com" }); ``` +> Return a hull `client` scoped to the user identified only by an email, but won't be created when not found, only updates existing user. + +```js +client.asUser({ email: "user@email.com" }, { create: false }); +``` + +> Return a hull `client` scoped to the user identified only by an email and adds `active` flag to fast track recompute and notifications for that specific user while he remains active. . + +```js +client.asUser({ email: "user@email.com" }, { active: true }); +``` + > Return a hull `client` authenticated as the user but with admin privileges ```js -client.asUser({ email: 'user@email.com' }, { scopes: ['admin'] }); +client.asUser({ email: "user@email.com" }, { scopes: ["admin"] }); ``` ## Methods for user-scoped instance @@ -192,15 +208,15 @@ When you do this, you get a new client that has a different behaviour. It's now Stores a new event. ```js -user.track('new support ticket', { messages: 3, - priority:'high' +user.track("new support ticket", { messages: 3, + priority: "high" }, { - source: 'zendesk', - type: 'ticket', - event_id: 'uuid1234' //Pass a unique ID to ensure event de-duplication + source: "zendesk", + type: "ticket", + event_id: "uuid1234" //Pass a unique ID to ensure event de-duplication ip: null, //don't store ip - it's a server call referer: null, //don't store referer - it's a server call - created_at: '2013-02-08 09:30:26.123+07:00' //ISO 8601. moment.js does it very well + created_at: "2013-02-08 09:30:26.123+07:00" //ISO 8601. moment.js does it very well }); ``` @@ -221,7 +237,7 @@ Stores Attributes on the user: ```js user.traits({ opened_tickets: 12 -}, { source: 'zendesk' }); +}, { source: "zendesk" }); // 'source' is optional. Will store the traits grouped under the source name. // Alternatively, you can send properties for multiple groups with the flat syntax: user.traits({ "zendesk/opened_tickets": 12, "clearbit/name": "foo" }); @@ -233,7 +249,7 @@ By default the `traits` calls are grouped in background and send to the Hull API user.traits({ fetched_at: new Date().toISOString() }, { - source: 'mailchimp', + source: "mailchimp", sync: true }); ``` @@ -247,33 +263,34 @@ The Hull API returns traits in a "flat" format, with '/' delimiters in the key. ```js client.utils.traits.group({ - 'email': 'romain@user', - 'name': 'name', - 'traits_coconut_name': 'coconut', - 'traits_coconut_size': 'large', - 'traits_cb/twitter_bio': 'parisian', - 'traits_cb/twitter_name': 'parisian', - 'traits_group/name': 'groupname', - 'traits_zendesk/open_tickets': 18 + mail: "romain@user", + name: "name", + "traits_coconut_name": "coconut", + "traits_coconut_size": "large", + "traits_cb/twitter_bio": "parisian", + "traits_cb/twitter_name": "parisian", + "traits_group/name": "groupname", + "traits_zendesk/open_tickets": 18 }); + // returns { - 'id' : '31628736813n1283', - 'email': 'romain@user', - 'name': 'name', - 'traits': { - 'coconut_name': 'coconut', - 'coconut_size': 'large' + id : "31628736813n1283", + email: "romain@user", + name: "name", + traits: { + coconut_name: "coconut", + coconut_size: "large" }, cb: { - 'twitter_bio': 'parisian', - 'twitter_name': 'parisian' + twitter_bio: "parisian", + twitter_name: "parisian" }, group: { - 'name': 'groupname', + name: "groupname" }, zendesk: { - 'open_tickets': 18 + "open_tickets": 18 } }; ``` From 6db0c4bb285a90cd9f0774b5ff319fa4d04337e9 Mon Sep 17 00:00:00 2001 From: Michal Raczka Date: Fri, 29 Dec 2017 15:17:33 +0100 Subject: [PATCH 2/6] Alias claims for asUser and asAccount --- CHANGELOG.md | 3 +++ package.json | 2 +- src/lib/configuration.js | 4 ++-- tests/client-tests.js | 20 +++++++++++++++++++- 4 files changed, 25 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8ac97c6..b320fc2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +# 1.1.6 +* adds additional `alias` claim to `asAccount` and `asUser` methods + # 1.1.5 * retry all 5xx errors diff --git a/package.json b/package.json index b1fd6cb..014aa13 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "hull-client", - "version": "1.1.5", + "version": "1.1.6", "description": "A barebones Node.js API client for hull.io", "main": "lib", "repository": { diff --git a/src/lib/configuration.js b/src/lib/configuration.js index 365f459..1d186ba 100644 --- a/src/lib/configuration.js +++ b/src/lib/configuration.js @@ -54,13 +54,13 @@ const VALID_PROPS = { * All valid user claims, used for validation and filterind .asUser calls * @type {Array} */ -const USER_CLAIMS = ["id", "email", "external_id", "anonymous_id"]; +const USER_CLAIMS = ["id", "email", "external_id", "anonymous_id", "alias"]; /** * All valid accounts claims, used for validation and filtering .asAccount calls * @type {Array} */ -const ACCOUNT_CLAIMS = ["id", "external_id", "domain"]; +const ACCOUNT_CLAIMS = ["id", "external_id", "domain", "alias"]; /** * make sure that provided "identity claim" is valid diff --git a/tests/client-tests.js b/tests/client-tests.js index 8026e0f..f0eb72f 100644 --- a/tests/client-tests.js +++ b/tests/client-tests.js @@ -153,7 +153,7 @@ describe("Hull", () => { .to.not.throw(Error); }); - it("should filter all non standard claims", () => { + it("should filter all non standard claims", () => { const hull = new Hull({ id: "562123b470df84b740000042", secret: "1234", organization: "test" }); const scoped = hull.asUser({ email: "foo@bar.com", foo: "bar" }); @@ -161,5 +161,23 @@ describe("Hull", () => { expect(scopedJwtClaims["io.hull.asUser"]) .to.eql({ email: "foo@bar.com" }); }); + + it("should allow to pass an array of user aliases", () => { + const hull = new Hull({ id: "562123b470df84b740000042", secret: "1234", organization: "test" }); + + const scoped = hull.asUser({ email: "foo@bar.com", alias: ["namespace:123"] }); + const scopedJwtClaims = jwt.decode(scoped.configuration().accessToken, scoped.configuration().secret); + expect(scopedJwtClaims["io.hull.asUser"]) + .to.eql({ email: "foo@bar.com", alias: ["namespace:123"] }); + }); + + it("should allow to pass an array of account aliases", () => { + const hull = new Hull({ id: "562123b470df84b740000042", secret: "1234", organization: "test" }); + + const scoped = hull.asAccount({ domain: "bar.com", alias: ["namespace:123"] }); + const scopedJwtClaims = jwt.decode(scoped.configuration().accessToken, scoped.configuration().secret); + expect(scopedJwtClaims["io.hull.asAccount"]) + .to.eql({ domain: "bar.com", alias: ["namespace:123"] }); + }); }); }); From dafd014b41e24c8e9de19d41f4e10493453a6e8e Mon Sep 17 00:00:00 2001 From: Michal Raczka Date: Fri, 29 Dec 2017 15:25:12 +0100 Subject: [PATCH 3/6] Adds documentation part about alias claim --- README.md | 35 +++++++++++++++++++++-------------- 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index 671c84b..5ace93c 100644 --- a/README.md +++ b/README.md @@ -148,19 +148,19 @@ client.asUser(userId); > Return a hull `client` scoped to the user identified by it's Social network ID. Lazily created if [Guest Users](http://www.hull.io/docs/users/guest_users) are enabled ```js -client.asUser('instagram|facebook|google:userId'); +client.asUser("instagram|facebook|google:userId"); ``` > Return a hull `client` scoped to the user identified by it's External ID (from your dashboard). Lazily created if [Guest Users](http://www.hull.io/docs/users/guest_users) are enabled ```js -client.asUser({ external_id: 'externalId' }); +client.asUser({ external_id: "externalId" }); ``` > Return a hull `client` scoped to the user identified by it's External ID (from your dashboard). Lazily created if [Guest Users](http://www.hull.io/docs/users/guest_users) are enabled ```js -client.asUser({ anonymous_id: 'anonymousId' }); +client.asUser({ anonymous_id: "anonymousId" }); ``` > Return a hull `client` scoped to the user identified by only by an anonymousId. Lets you start tracking and storing properties from a user before you have a UserID ready for him. Lazily created if [Guest Users](http://www.hull.io/docs/users/guest_users) are enabled @@ -173,7 +173,13 @@ client.asUser({ email: "user@email.com" }); > Return a hull `client` authenticated as the user but with admin privileges ```js -client.asUser({ email: 'user@email.com' }, { scopes: ['admin'] }); +client.asUser({ email: "user@email.com" }, { scopes: ["admin"] }); +``` + +> Return a hull `client` identified by an email and additional aliases - which are passed as an array of unique identifiers + +```js +client.asUser({ email: "user@email.com", alias: ["namespace:123"] }); ``` ## Methods for user-scoped instance @@ -192,15 +198,16 @@ When you do this, you get a new client that has a different behaviour. It's now Stores a new event. ```js -user.track('new support ticket', { messages: 3, - priority:'high' +user.track("new support ticket", { + messages: 3, + priority: "high" }, { - source: 'zendesk', - type: 'ticket', - event_id: 'uuid1234' //Pass a unique ID to ensure event de-duplication - ip: null, //don't store ip - it's a server call - referer: null, //don't store referer - it's a server call - created_at: '2013-02-08 09:30:26.123+07:00' //ISO 8601. moment.js does it very well + source: "zendesk", + type: "ticket", + event_id: "uuid1234", // Pass a unique ID to ensure event de-duplication + ip: null, // don't store ip - it's a server call + referer: null, // don't store referer - it's a server call + created_at: "2013-02-08 09:30:26.123+07:00" // ISO 8601. moment.js does it very well }); ``` @@ -221,7 +228,7 @@ Stores Attributes on the user: ```js user.traits({ opened_tickets: 12 -}, { source: 'zendesk' }); +}, { source: "zendesk" }); // 'source' is optional. Will store the traits grouped under the source name. // Alternatively, you can send properties for multiple groups with the flat syntax: user.traits({ "zendesk/opened_tickets": 12, "clearbit/name": "foo" }); @@ -233,7 +240,7 @@ By default the `traits` calls are grouped in background and send to the Hull API user.traits({ fetched_at: new Date().toISOString() }, { - source: 'mailchimp', + source: "mailchimp", sync: true }); ``` From 5e2186dff9bf5004e434a0d6776d3bd6cf2dab39 Mon Sep 17 00:00:00 2001 From: Michal Raczka Date: Fri, 29 Dec 2017 17:05:28 +0100 Subject: [PATCH 4/6] Adds service_ids --- CHANGELOG.md | 2 +- README.md | 2 +- src/lib/configuration.js | 4 ++-- tests/client-tests.js | 26 ++++++++++++++++++++++---- 4 files changed, 26 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b320fc2..1bd248d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,5 @@ # 1.1.6 -* adds additional `alias` claim to `asAccount` and `asUser` methods +* adds additional `aliases` and `service_ids` claims to `asAccount` and `asUser` methods # 1.1.5 * retry all 5xx errors diff --git a/README.md b/README.md index 5ace93c..c0887f8 100644 --- a/README.md +++ b/README.md @@ -179,7 +179,7 @@ client.asUser({ email: "user@email.com" }, { scopes: ["admin"] }); > Return a hull `client` identified by an email and additional aliases - which are passed as an array of unique identifiers ```js -client.asUser({ email: "user@email.com", alias: ["namespace:123"] }); +client.asUser({ email: "user@email.com", aliases: ["namespace:123"] }); ``` ## Methods for user-scoped instance diff --git a/src/lib/configuration.js b/src/lib/configuration.js index 1d186ba..1649d74 100644 --- a/src/lib/configuration.js +++ b/src/lib/configuration.js @@ -54,13 +54,13 @@ const VALID_PROPS = { * All valid user claims, used for validation and filterind .asUser calls * @type {Array} */ -const USER_CLAIMS = ["id", "email", "external_id", "anonymous_id", "alias"]; +const USER_CLAIMS = ["id", "email", "external_id", "anonymous_id", "aliases", "service_ids"]; /** * All valid accounts claims, used for validation and filtering .asAccount calls * @type {Array} */ -const ACCOUNT_CLAIMS = ["id", "external_id", "domain", "alias"]; +const ACCOUNT_CLAIMS = ["id", "external_id", "domain", "aliases", "service_ids"]; /** * make sure that provided "identity claim" is valid diff --git a/tests/client-tests.js b/tests/client-tests.js index f0eb72f..71f1d30 100644 --- a/tests/client-tests.js +++ b/tests/client-tests.js @@ -165,19 +165,37 @@ describe("Hull", () => { it("should allow to pass an array of user aliases", () => { const hull = new Hull({ id: "562123b470df84b740000042", secret: "1234", organization: "test" }); - const scoped = hull.asUser({ email: "foo@bar.com", alias: ["namespace:123"] }); + const scoped = hull.asUser({ email: "foo@bar.com", aliases: ["namespace:123"] }); const scopedJwtClaims = jwt.decode(scoped.configuration().accessToken, scoped.configuration().secret); expect(scopedJwtClaims["io.hull.asUser"]) - .to.eql({ email: "foo@bar.com", alias: ["namespace:123"] }); + .to.eql({ email: "foo@bar.com", aliases: ["namespace:123"] }); }); it("should allow to pass an array of account aliases", () => { const hull = new Hull({ id: "562123b470df84b740000042", secret: "1234", organization: "test" }); - const scoped = hull.asAccount({ domain: "bar.com", alias: ["namespace:123"] }); + const scoped = hull.asAccount({ domain: "bar.com", aliases: ["namespace:123"] }); const scopedJwtClaims = jwt.decode(scoped.configuration().accessToken, scoped.configuration().secret); expect(scopedJwtClaims["io.hull.asAccount"]) - .to.eql({ domain: "bar.com", alias: ["namespace:123"] }); + .to.eql({ domain: "bar.com", aliases: ["namespace:123"] }); + }); + + it("should allow to pass an object of user service ids", () => { + const hull = new Hull({ id: "562123b470df84b740000042", secret: "1234", organization: "test" }); + + const scoped = hull.asUser({ email: "foo@bar.com", service_ids: { service: "abc123" } }); + const scopedJwtClaims = jwt.decode(scoped.configuration().accessToken, scoped.configuration().secret); + expect(scopedJwtClaims["io.hull.asUser"]) + .to.eql({ email: "foo@bar.com", service_ids: { service: "abc123" } }); + }); + + it("should allow to pass an object of account service ids", () => { + const hull = new Hull({ id: "562123b470df84b740000042", secret: "1234", organization: "test" }); + + const scoped = hull.asAccount({ domain: "bar.com", service_ids: { service: "abc123" } }); + const scopedJwtClaims = jwt.decode(scoped.configuration().accessToken, scoped.configuration().secret); + expect(scopedJwtClaims["io.hull.asAccount"]) + .to.eql({ domain: "bar.com", service_ids: { service: "abc123" } }); }); }); }); From 92bb357f8af3efae7995107a7ba00ef58233a484 Mon Sep 17 00:00:00 2001 From: Michal Raczka Date: Fri, 29 Dec 2017 17:10:02 +0100 Subject: [PATCH 5/6] Update readme --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index c0887f8..fcb04c6 100644 --- a/README.md +++ b/README.md @@ -182,6 +182,12 @@ client.asUser({ email: "user@email.com" }, { scopes: ["admin"] }); client.asUser({ email: "user@email.com", aliases: ["namespace:123"] }); ``` +> Return a hull `client` identified by an email and additional service_ids - which are passed as an object of unique identifiers + +```js +client.asUser({ email: "user@email.com", aliases: { serviceName: "serviceId123" } }); +``` + ## Methods for user-scoped instance ```js From 8108e4fa5acf465cd2e37831ce675ff43924d36a Mon Sep 17 00:00:00 2001 From: Michal Raczka Date: Thu, 8 Feb 2018 10:35:38 +0100 Subject: [PATCH 6/6] Fix readme and update circle ci configuration --- README.md | 2 +- circle.yml | 3 --- 2 files changed, 1 insertion(+), 4 deletions(-) delete mode 100644 circle.yml diff --git a/README.md b/README.md index fcb04c6..ab9d8ab 100644 --- a/README.md +++ b/README.md @@ -185,7 +185,7 @@ client.asUser({ email: "user@email.com", aliases: ["namespace:123"] }); > Return a hull `client` identified by an email and additional service_ids - which are passed as an object of unique identifiers ```js -client.asUser({ email: "user@email.com", aliases: { serviceName: "serviceId123" } }); +client.asUser({ email: "user@email.com", service_ids: { serviceName: "serviceId123" } }); ``` ## Methods for user-scoped instance diff --git a/circle.yml b/circle.yml deleted file mode 100644 index b00026e..0000000 --- a/circle.yml +++ /dev/null @@ -1,3 +0,0 @@ -machine: - node: - version: 6