@owlmeans/server-auth-identity 0.1.18-rc.28 → 0.1.18-rc.29

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -10,7 +10,7 @@ whose grants decide access (use `@owlmeans/server-oidc-rp`'s guard and gate, or
10
10
  ## Installation
11
11
 
12
12
  ```bash
13
- bun add @owlmeans/server-auth-identity@^0.1.18-rc.28
13
+ bun add @owlmeans/server-auth-identity@^0.1.18-rc.29
14
14
  ```
15
15
 
16
16
  ## Concepts
@@ -28,6 +28,8 @@ bun add @owlmeans/server-auth-identity@^0.1.18-rc.28
28
28
  profile details and returns an `AuthPayload`.
29
29
  - **Entity resolver** — the `EntityResolverService` registered under `ENTITY_RESOLVER`. Registering
30
30
  it tells the server boundary that this deployment has organizations.
31
+ - **Identity events** — `identityEvents(ctx)` returns the `IdentityEventsService`; its
32
+ `onEntityCreated` listeners run once per newly registered organization entity.
31
33
 
32
34
  ## Usage
33
35
 
@@ -145,6 +147,23 @@ payload ??= await linking.linkProfile(details, { username: 'person@example.org'
145
147
  // payload: { type, role, userId, profileId, entitySlug, scopes }
146
148
  ```
147
149
 
150
+ ### Provision when an organization is created
151
+
152
+ ```ts
153
+ import { identityEvents } from '@owlmeans/server-auth-identity'
154
+
155
+ // in makeContext, after appendAuthIdentityResources
156
+ identityEvents(context)?.onEntityCreated(async (event, ctx) => {
157
+ await ctx.service<PlanService>(PLAN_SERVICE).grantStarterPlan(event.entityId)
158
+ })
159
+ ```
160
+
161
+ The event carries `entityId`, `entitySlug`, `iamKey`, `accountId`, `profileId`, `username`, the
162
+ login `type` and `service`, and `createdAt`. It fires only when `linkProfile` registers a new
163
+ identity (including `force: true`) — never when a second sign-in method links to an identity that
164
+ exists. Listeners run in order and are awaited; one that throws is logged and never fails the
165
+ sign-in, so anything a listener provisions needs its own backfill.
166
+
148
167
  ### Rename an organization and mint a durable name
149
168
 
150
169
  ```ts
@@ -168,13 +187,15 @@ const namespace = await resolver.mintName(entityId, 'namespace', entity => `my-a
168
187
 
169
188
  | Symbol | Kind | Purpose |
170
189
  |---|---|---|
171
- | `appendAuthIdentityResources(context, dbAlias?)` | function | Register the four resources, the linking service and the entity resolver |
190
+ | `appendAuthIdentityResources(context, dbAlias?)` | function | Register the four resources, the linking service, the entity resolver and (unless one is registered) the identity-events service |
172
191
  | `makeOrgEntityResource(dbAlias?)` | function | Mongo resource for `OrgEntity` |
173
192
  | `makeIdentityAccountResource(dbAlias?)` | function | Mongo resource for `IdentityAccount` |
174
193
  | `makeIdentityProfileResource(dbAlias?)` | function | Mongo resource for `IdentityProfile` |
175
194
  | `makeIdentityCredentialsResource(dbAlias?)` | function | Mongo resource for `IdentityCredentials` |
176
195
  | `makeIdentityLinkingService()` | function | The `IdentityLinkingService` implementation |
177
196
  | `makeEntityResolverService(alias = ENTITY_RESOLVER)` | function | The `EntityResolverService` implementation, cached 30 s per resolved name |
197
+ | `makeIdentityEventsService(alias = AUTH_IDENTITY_EVENTS)` | function | The `IdentityEventsService` implementation (lazy) |
198
+ | `identityEvents(ctx, alias?)` | function | The registered events service, or `null` |
178
199
 
179
200
  ### Constants
180
201
 
@@ -182,6 +203,7 @@ const namespace = await resolver.mintName(entityId, 'namespace', entity => `my-a
182
203
  |---|---|---|
183
204
  | `AUTH_IDENTITY_ORG_ENTITY`, `AUTH_IDENTITY_ACCOUNT`, `AUTH_IDENTITY_PROFILE`, `AUTH_IDENTITY_CREDENTIALS` | const | Resource aliases (`'auth-identity:…'`), lookup keys only |
184
205
  | `AUTH_IDENTITY_LINKING` | const | `'auth-identity:linking'` — linking service alias |
206
+ | `AUTH_IDENTITY_EVENTS` | const | `'auth-identity:events'` — identity-events service alias |
185
207
  | `AUTH_IDENTITY_DB_ALIAS` | const | `'auth-identity'` — suggested db config alias |
186
208
  | `AUTH_IDENTITY_ORG_ENTITY_COLLECTION`, `AUTH_IDENTITY_ACCOUNT_COLLECTION`, `AUTH_IDENTITY_PROFILE_COLLECTION`, `AUTH_IDENTITY_CREDENTIALS_COLLECTION` | const | Colon-free Mongo collection base names |
187
209
  | `MAX_ENTITY_SLUG_ATTEMPTS` | const | `8` — word slugs tried before minting gives up |
@@ -197,6 +219,8 @@ const namespace = await resolver.mintName(entityId, 'namespace', entity => `my-a
197
219
  | `IdentityCredentials` | type | `AuthCredentials` + `profileId` |
198
220
  | `IdentityLinkingService` | type | `getLinkedProfile`, `linkProfile`, `linkCredentials`, `unlinkCredentials`, `getOwnerProfiles`, `getOwnerCredentials` |
199
221
  | `AccountMeta` | type | `{ username, force? }` |
222
+ | `IdentityEventsService` | type | `onEntityCreated(callback)`, `propagateEntityCreated(event)` |
223
+ | `EntityCreatedEvent`, `EntityCreatedCallback` | type | The entity-created payload; `(event, ctx) => Promise<void>` |
200
224
  | `OrgEntityResource`, `IdentityAccountResource`, `IdentityProfileResource`, `IdentityCredentialsResource` | type | Typed `MongoResource` aliases |
201
225
  | `IdentityConfig`, `IdentityContext` | type | Server config and context shapes |
202
226
  | `GoogleUserInfo` | type | Google userinfo claims |
@@ -224,6 +248,8 @@ const namespace = await resolver.mintName(entityId, 'namespace', entity => `my-a
224
248
  is needed.
225
249
  - `linkProfile(details, { username, force: true })` always registers a new identity — use it only
226
250
  when a separate identity is intended.
251
+ - Provisioning in an `onEntityCreated` listener is best-effort: a throwing listener is logged and the
252
+ sign-in succeeds, so reconcile what it provisions periodically.
227
253
  - The resolver caches for 30 seconds, so a rename reaches other replicas within that window; the old
228
254
  slug keeps resolving meanwhile.
229
255
  - `rename` rejects a malformed slug and any slug an entity has ever answered to; `mintSlug` throws
@@ -247,7 +273,7 @@ This package ships embedded agent skills under `agent-meta/`. After installing y
247
273
  your project's skill store (`.agents/skills/`):
248
274
 
249
275
  ```sh
250
- npx @owlmeans/agent-skills@^0.1.18-rc.27
276
+ npx @owlmeans/agent-skills@^0.1.18-rc.28
251
277
  ```
252
278
 
253
279
  The embedded files are version-matched to this package release. Do not edit them
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "schemaVersion": 2,
3
3
  "package": "@owlmeans/server-auth-identity",
4
- "version": "0.1.18-rc.28",
5
- "generatedAt": "2026-09-15T13:19:14.330Z",
4
+ "version": "0.1.18-rc.29",
5
+ "generatedAt": "2026-09-16T17:32:31.932Z",
6
6
  "canonicalRepo": "https://github.com/owlmeans/common",
7
7
  "entries": [
8
8
  {
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: server-auth-identity
3
- description: How to use @owlmeans/server-auth-identity — the Mongo-backed local identity store behind provider logins. Registers the organization-entity registry plus account, profile and credentials resources, the IdentityLinkingService that maps an external provider account onto one local identity, and the EntityResolverService that turns the slug on a token into a stable entity id. Auto-invoked when importing appendAuthIdentityResources, an identity resource alias, IdentityLinkingService or the entity resolver.
3
+ description: How to use @owlmeans/server-auth-identity — the Mongo-backed local identity store behind provider logins. Registers the organization-entity registry plus account, profile and credentials resources, the IdentityLinkingService that maps an external provider account onto one local identity, the EntityResolverService that turns the slug on a token into a stable entity id, and the identity-events seam that announces a newly created organization entity. Auto-invoked when importing appendAuthIdentityResources, an identity resource alias, IdentityLinkingService, the entity resolver or identityEvents.
4
4
  user-invocable: false
5
5
  ---
6
6
  <!-- AUTO-GENERATED — do not edit. Regenerate via sync-agent-meta. -->
@@ -8,7 +8,7 @@ user-invocable: false
8
8
  # @owlmeans/server-auth-identity
9
9
 
10
10
  **Layer:** Server
11
- **Install:** `"@owlmeans/server-auth-identity": "^0.1.18-rc.28"` in `dependencies`
11
+ **Install:** `"@owlmeans/server-auth-identity": "^0.1.18-rc.29"` in `dependencies`
12
12
 
13
13
  The local identity store a deployment owns when it does not delegate identity to an external IAM.
14
14
  It answers two questions: *who is this person here* (account / profile / credentials) and *which
@@ -18,18 +18,21 @@ organization entity is this* (the org-entity registry and its resolver).
18
18
 
19
19
  | Export | Description |
20
20
  |--------|-------------|
21
- | `appendAuthIdentityResources(context, dbAlias?)` | Register the four resources, the linking service and the entity resolver in one call |
21
+ | `appendAuthIdentityResources(context, dbAlias?)` | Register the four resources, the linking service, the entity resolver and — unless one is already registered — the identity-events service |
22
22
  | `makeOrgEntityResource(dbAlias?)` | Mongo resource for `OrgEntity` — the organization-entity registry |
23
23
  | `makeIdentityAccountResource(dbAlias?)` | Mongo resource for `IdentityAccount` (one per person) |
24
24
  | `makeIdentityProfileResource(dbAlias?)` | Mongo resource for `IdentityProfile` (one person inside one organization entity, with a role) |
25
25
  | `makeIdentityCredentialsResource(dbAlias?)` | Mongo resource for `IdentityCredentials` (one provider link per profile) |
26
26
  | `makeIdentityLinkingService()` | The `IdentityLinkingService` implementation |
27
27
  | `makeEntityResolverService(alias?)` | The `EntityResolverService` implementation, cached for 30 s per resolved value |
28
+ | `makeIdentityEventsService(alias?)` | The lazy `IdentityEventsService` implementation |
29
+ | `identityEvents(ctx, alias?)` | The registered events service, or `null` |
28
30
  | `AUTH_IDENTITY_ORG_ENTITY` | Resource alias `'auth-identity:org-entity'` |
29
31
  | `AUTH_IDENTITY_ACCOUNT` | Resource alias `'auth-identity:account'` |
30
32
  | `AUTH_IDENTITY_PROFILE` | Resource alias `'auth-identity:profile'` |
31
33
  | `AUTH_IDENTITY_CREDENTIALS` | Resource alias `'auth-identity:credentials'` |
32
34
  | `AUTH_IDENTITY_LINKING` | Service alias `'auth-identity:linking'` |
35
+ | `AUTH_IDENTITY_EVENTS` | Service alias `'auth-identity:events'` |
33
36
  | `AUTH_IDENTITY_DB_ALIAS` | `'auth-identity'` — the suggested db-config alias whose `resourcePrefix` scopes the prefix to identity collections only |
34
37
  | `AUTH_IDENTITY_ORG_ENTITY_COLLECTION`, `AUTH_IDENTITY_ACCOUNT_COLLECTION`, `AUTH_IDENTITY_PROFILE_COLLECTION`, `AUTH_IDENTITY_CREDENTIALS_COLLECTION` | Colon-free Mongo collection base names (`org-entity`, `account`, `profile`, `credentials`) |
35
38
  | `MAX_ENTITY_SLUG_ATTEMPTS` | How many word slugs to try before giving up minting a free one |
@@ -49,6 +52,9 @@ collection names are the colon-free `*_COLLECTION` values, optionally prefixed b
49
52
  | `IdentityCredentials` | `AuthCredentials` + `profileId` |
50
53
  | `IdentityLinkingService` | `getLinkedProfile`, `linkProfile`, `linkCredentials`, `getOwnerProfiles`, `getOwnerCredentials` |
51
54
  | `AccountMeta` | `{ username, force? }` — the second argument to `linkProfile` |
55
+ | `IdentityEventsService` | `onEntityCreated(callback)`, `propagateEntityCreated(event)` |
56
+ | `EntityCreatedEvent` | `entityId`, `entitySlug`, `iamKey`, `accountId`, `profileId`, `username`, `type`, `service`, `createdAt` |
57
+ | `EntityCreatedCallback` | `(event, ctx) => Promise<void>` |
52
58
  | `OrgEntityResource`, `IdentityAccountResource`, `IdentityProfileResource`, `IdentityCredentialsResource` | Typed `MongoResource` aliases |
53
59
  | `IdentityConfig`, `IdentityContext` | Server config/context shapes |
54
60
  | `GoogleUserInfo` | The Google userinfo claim set |
@@ -154,6 +160,32 @@ profile carrying one is a platform login and a profile carrying none is somebody
154
160
  `linkProfile(details, { username, force: true })` skips the lookup and registers a fresh identity
155
161
  regardless. Use it only where a genuinely separate identity is intended.
156
162
 
163
+ ## Identity events
164
+
165
+ `linkProfile` is the only place an organization entity is minted, so it is where one is announced:
166
+
167
+ ```typescript
168
+ import { identityEvents } from '@owlmeans/server-auth-identity'
169
+
170
+ // while wiring the context, after appendAuthIdentityResources — the service is lazy
171
+ identityEvents(context)?.onEntityCreated(async (event, ctx) => {
172
+ await provisionStarterPlan(ctx, event.entityId)
173
+ })
174
+ ```
175
+
176
+ - **It fires at the end of the REGISTRATION branch only** — after the entity, account, profile and
177
+ credential rows exist, and on `force: true` too. A second sign-in method that links to a known
178
+ identity creates no entity and fires nothing. Provisioning keyed on "reached `linkProfile`"
179
+ would double-fund that person; key it on this event.
180
+ - **Listeners run in registration order and are awaited**, so the sign-in completes after them.
181
+ Keep them short: one row, one enqueue.
182
+ - **A throwing listener is logged and never fails the sign-in**, and the next listener still runs.
183
+ The person is registered either way, so whatever a listener provisions needs a periodic
184
+ reconciliation to backfill the misses.
185
+ - **`identityEvents(ctx)` answers `null` where the service is not registered** — write `?.` and a
186
+ deployment without the seam pays nothing.
187
+ - Key what a listener writes on `event.entityId`, never on `entitySlug`: the slug can be renamed.
188
+
157
189
  ## Key derivation conventions
158
190
 
159
191
  - **Account `credential`** — a unique 16-character Base58 slug, the account's own stable key.
package/build/consts.d.ts CHANGED
@@ -3,6 +3,7 @@ export declare const AUTH_IDENTITY_PROFILE = "auth-identity:profile";
3
3
  export declare const AUTH_IDENTITY_CREDENTIALS = "auth-identity:credentials";
4
4
  export declare const AUTH_IDENTITY_LINKING = "auth-identity:linking";
5
5
  export declare const AUTH_IDENTITY_ORG_ENTITY = "auth-identity:org-entity";
6
+ export declare const AUTH_IDENTITY_EVENTS = "auth-identity:events";
6
7
  export declare const AUTH_IDENTITY_ACCOUNT_COLLECTION = "account";
7
8
  export declare const AUTH_IDENTITY_PROFILE_COLLECTION = "profile";
8
9
  export declare const AUTH_IDENTITY_CREDENTIALS_COLLECTION = "credentials";
@@ -1 +1 @@
1
- {"version":3,"file":"consts.d.ts","sourceRoot":"","sources":["../src/consts.ts"],"names":[],"mappings":"AAKA,eAAO,MAAM,qBAAqB,0BAA0B,CAAA;AAC5D,eAAO,MAAM,qBAAqB,0BAA0B,CAAA;AAC5D,eAAO,MAAM,yBAAyB,8BAA8B,CAAA;AACpE,eAAO,MAAM,qBAAqB,0BAA0B,CAAA;AAC5D,eAAO,MAAM,wBAAwB,6BAA6B,CAAA;AAMlE,eAAO,MAAM,gCAAgC,YAAY,CAAA;AACzD,eAAO,MAAM,gCAAgC,YAAY,CAAA;AACzD,eAAO,MAAM,oCAAoC,gBAAgB,CAAA;AACjE,eAAO,MAAM,mCAAmC,eAAe,CAAA;AAI/D,eAAO,MAAM,sBAAsB,kBAAkB,CAAA;AAIrD,eAAO,MAAM,wBAAwB,IAAI,CAAA;AAGzC,eAAO,MAAM,oBAAoB,YAAY,CAAA;AAC7C,eAAO,MAAM,sBAAsB,MAAM,CAAA"}
1
+ {"version":3,"file":"consts.d.ts","sourceRoot":"","sources":["../src/consts.ts"],"names":[],"mappings":"AAKA,eAAO,MAAM,qBAAqB,0BAA0B,CAAA;AAC5D,eAAO,MAAM,qBAAqB,0BAA0B,CAAA;AAC5D,eAAO,MAAM,yBAAyB,8BAA8B,CAAA;AACpE,eAAO,MAAM,qBAAqB,0BAA0B,CAAA;AAC5D,eAAO,MAAM,wBAAwB,6BAA6B,CAAA;AAElE,eAAO,MAAM,oBAAoB,yBAAyB,CAAA;AAM1D,eAAO,MAAM,gCAAgC,YAAY,CAAA;AACzD,eAAO,MAAM,gCAAgC,YAAY,CAAA;AACzD,eAAO,MAAM,oCAAoC,gBAAgB,CAAA;AACjE,eAAO,MAAM,mCAAmC,eAAe,CAAA;AAI/D,eAAO,MAAM,sBAAsB,kBAAkB,CAAA;AAIrD,eAAO,MAAM,wBAAwB,IAAI,CAAA;AAGzC,eAAO,MAAM,oBAAoB,YAAY,CAAA;AAC7C,eAAO,MAAM,sBAAsB,MAAM,CAAA"}
package/build/consts.js CHANGED
@@ -7,6 +7,8 @@ export const AUTH_IDENTITY_PROFILE = 'auth-identity:profile';
7
7
  export const AUTH_IDENTITY_CREDENTIALS = 'auth-identity:credentials';
8
8
  export const AUTH_IDENTITY_LINKING = 'auth-identity:linking';
9
9
  export const AUTH_IDENTITY_ORG_ENTITY = 'auth-identity:org-entity';
10
+ // Service alias of the identity-events seam (`identityEvents(ctx)`).
11
+ export const AUTH_IDENTITY_EVENTS = 'auth-identity:events';
10
12
  // Colon-free Mongo collection base names. The final collection name is
11
13
  // `${resourcePrefix}${collection}` — e.g. with the project prefix 'viam-' this yields
12
14
  // 'viam-account'. Register the identity resources against a db config that carries the
@@ -1 +1 @@
1
- {"version":3,"file":"consts.js","sourceRoot":"","sources":["../src/consts.ts"],"names":[],"mappings":"AACA,wFAAwF;AACxF,sFAAsF;AACtF,sFAAsF;AACtF,uFAAuF;AACvF,MAAM,CAAC,MAAM,qBAAqB,GAAG,uBAAuB,CAAA;AAC5D,MAAM,CAAC,MAAM,qBAAqB,GAAG,uBAAuB,CAAA;AAC5D,MAAM,CAAC,MAAM,yBAAyB,GAAG,2BAA2B,CAAA;AACpE,MAAM,CAAC,MAAM,qBAAqB,GAAG,uBAAuB,CAAA;AAC5D,MAAM,CAAC,MAAM,wBAAwB,GAAG,0BAA0B,CAAA;AAElE,uEAAuE;AACvE,sFAAsF;AACtF,uFAAuF;AACvF,2FAA2F;AAC3F,MAAM,CAAC,MAAM,gCAAgC,GAAG,SAAS,CAAA;AACzD,MAAM,CAAC,MAAM,gCAAgC,GAAG,SAAS,CAAA;AACzD,MAAM,CAAC,MAAM,oCAAoC,GAAG,aAAa,CAAA;AACjE,MAAM,CAAC,MAAM,mCAAmC,GAAG,YAAY,CAAA;AAE/D,mFAAmF;AACnF,2EAA2E;AAC3E,MAAM,CAAC,MAAM,sBAAsB,GAAG,eAAe,CAAA;AAErD,iGAAiG;AACjG,uEAAuE;AACvE,MAAM,CAAC,MAAM,wBAAwB,GAAG,CAAC,CAAA;AAEzC,4CAA4C;AAC5C,MAAM,CAAC,MAAM,oBAAoB,GAAG,SAAS,CAAA;AAC7C,MAAM,CAAC,MAAM,sBAAsB,GAAG,GAAG,CAAA"}
1
+ {"version":3,"file":"consts.js","sourceRoot":"","sources":["../src/consts.ts"],"names":[],"mappings":"AACA,wFAAwF;AACxF,sFAAsF;AACtF,sFAAsF;AACtF,uFAAuF;AACvF,MAAM,CAAC,MAAM,qBAAqB,GAAG,uBAAuB,CAAA;AAC5D,MAAM,CAAC,MAAM,qBAAqB,GAAG,uBAAuB,CAAA;AAC5D,MAAM,CAAC,MAAM,yBAAyB,GAAG,2BAA2B,CAAA;AACpE,MAAM,CAAC,MAAM,qBAAqB,GAAG,uBAAuB,CAAA;AAC5D,MAAM,CAAC,MAAM,wBAAwB,GAAG,0BAA0B,CAAA;AAClE,qEAAqE;AACrE,MAAM,CAAC,MAAM,oBAAoB,GAAG,sBAAsB,CAAA;AAE1D,uEAAuE;AACvE,sFAAsF;AACtF,uFAAuF;AACvF,2FAA2F;AAC3F,MAAM,CAAC,MAAM,gCAAgC,GAAG,SAAS,CAAA;AACzD,MAAM,CAAC,MAAM,gCAAgC,GAAG,SAAS,CAAA;AACzD,MAAM,CAAC,MAAM,oCAAoC,GAAG,aAAa,CAAA;AACjE,MAAM,CAAC,MAAM,mCAAmC,GAAG,YAAY,CAAA;AAE/D,mFAAmF;AACnF,2EAA2E;AAC3E,MAAM,CAAC,MAAM,sBAAsB,GAAG,eAAe,CAAA;AAErD,iGAAiG;AACjG,uEAAuE;AACvE,MAAM,CAAC,MAAM,wBAAwB,GAAG,CAAC,CAAA;AAEzC,4CAA4C;AAC5C,MAAM,CAAC,MAAM,oBAAoB,GAAG,SAAS,CAAA;AAC7C,MAAM,CAAC,MAAM,sBAAsB,GAAG,GAAG,CAAA"}
@@ -0,0 +1,9 @@
1
+ import type { BasicContext } from '@owlmeans/context';
2
+ import type { IdentityEventsService } from './types.js';
3
+ export declare const makeIdentityEventsService: (alias?: string) => IdentityEventsService;
4
+ /**
5
+ * The identity-events service, or `null` where the context has none registered — so a caller
6
+ * writes `identityEvents(ctx)?.onEntityCreated(...)` and a deployment without the seam pays nothing.
7
+ */
8
+ export declare const identityEvents: (ctx: BasicContext<any>, alias?: string) => IdentityEventsService | null;
9
+ //# sourceMappingURL=events.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"events.d.ts","sourceRoot":"","sources":["../src/events.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAGrD,OAAO,KAAK,EAA0C,qBAAqB,EAAE,MAAM,YAAY,CAAA;AAE/F,eAAO,MAAM,yBAAyB,WAC7B,MAAM,KACZ,qBAsBF,CAAA;AAED;;;GAGG;AACH,eAAO,MAAM,cAAc,QACpB,YAAY,CAAC,GAAG,CAAC,UAAS,MAAM,KACpC,qBAAqB,GAAG,IAC+C,CAAA"}
@@ -0,0 +1,29 @@
1
+ import { createLazyService } from '@owlmeans/context';
2
+ import { AUTH_IDENTITY_EVENTS } from './consts.js';
3
+ export const makeIdentityEventsService = (alias = AUTH_IDENTITY_EVENTS) => {
4
+ const created = [];
5
+ const service = createLazyService(alias, {
6
+ onEntityCreated: callback => {
7
+ created.push(callback);
8
+ },
9
+ propagateEntityCreated: async (event) => {
10
+ for (const callback of created) {
11
+ try {
12
+ await callback(event, service.assertCtx());
13
+ }
14
+ catch (error) {
15
+ // The entity, the account and the profile already exist; failing here would turn a
16
+ // listener's problem into a sign-in that never completes for a person who is registered.
17
+ console.error(`${alias}: entity-created listener failed for ${event.entityId}`, error);
18
+ }
19
+ }
20
+ },
21
+ });
22
+ return service;
23
+ };
24
+ /**
25
+ * The identity-events service, or `null` where the context has none registered — so a caller
26
+ * writes `identityEvents(ctx)?.onEntityCreated(...)` and a deployment without the seam pays nothing.
27
+ */
28
+ export const identityEvents = (ctx, alias = AUTH_IDENTITY_EVENTS) => ctx.hasService(alias) ? ctx.service(alias) : null;
29
+ //# sourceMappingURL=events.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"events.js","sourceRoot":"","sources":["../src/events.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAA;AACrD,OAAO,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAA;AAGlD,MAAM,CAAC,MAAM,yBAAyB,GAAG,CACvC,KAAK,GAAW,oBAAoB,EACb,EAAE;IACzB,MAAM,OAAO,GAA4B,EAAE,CAAA;IAE3C,MAAM,OAAO,GAA0B,iBAAiB,CAAwB,KAAK,EAAE;QACrF,eAAe,EAAE,QAAQ,CAAC,EAAE;YAC1B,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;QACxB,CAAC;QAED,sBAAsB,EAAE,KAAK,EAAC,KAAK,EAAC,EAAE;YACpC,KAAK,MAAM,QAAQ,IAAI,OAAO,EAAE,CAAC;gBAC/B,IAAI,CAAC;oBACH,MAAM,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC,SAAS,EAA2C,CAAC,CAAA;gBACrF,CAAC;gBAAC,OAAO,KAAK,EAAE,CAAC;oBACf,mFAAmF;oBACnF,yFAAyF;oBACzF,OAAO,CAAC,KAAK,CAAC,GAAG,KAAK,wCAAwC,KAAK,CAAC,QAAQ,EAAE,EAAE,KAAK,CAAC,CAAA;gBACxF,CAAC;YACH,CAAC;QACH,CAAC;KACF,CAAC,CAAA;IAEF,OAAO,OAAO,CAAA;AAChB,CAAC,CAAA;AAED;;;GAGG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,CAC5B,GAAsB,EAAE,KAAK,GAAW,oBAAoB,EAC9B,EAAE,CAChC,GAAG,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAwB,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"helper.d.ts","sourceRoot":"","sources":["../src/helper.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAKrD,eAAO,MAAM,2BAA2B,YAC7B,YAAY,CAAC,GAAG,CAAC,YAChB,MAAM,KACf,IAUF,CAAA"}
1
+ {"version":3,"file":"helper.d.ts","sourceRoot":"","sources":["../src/helper.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAOrD,eAAO,MAAM,2BAA2B,YAC7B,YAAY,CAAC,GAAG,CAAC,YAChB,MAAM,KACf,IAcF,CAAA"}
package/build/helper.js CHANGED
@@ -1,6 +1,8 @@
1
1
  import { makeIdentityAccountResource, makeIdentityProfileResource, makeIdentityCredentialsResource, makeOrgEntityResource } from './resource.js';
2
2
  import { makeIdentityLinkingService } from './service.js';
3
3
  import { makeEntityResolverService } from './resolver.js';
4
+ import { makeIdentityEventsService } from './events.js';
5
+ import { AUTH_IDENTITY_EVENTS } from './consts.js';
4
6
  export const appendAuthIdentityResources = (context, dbAlias) => {
5
7
  context.registerResource(makeIdentityAccountResource(dbAlias));
6
8
  context.registerResource(makeIdentityProfileResource(dbAlias));
@@ -11,5 +13,9 @@ export const appendAuthIdentityResources = (context, dbAlias) => {
11
13
  // organizations: without it `request.entity` stays undefined and every consumer falls back to
12
14
  // treating the token's slug as the only entity value there is.
13
15
  context.registerService(makeEntityResolverService());
16
+ // Behind `hasService`, so an application that registered its own events service first keeps it.
17
+ if (!context.hasService(AUTH_IDENTITY_EVENTS)) {
18
+ context.registerService(makeIdentityEventsService());
19
+ }
14
20
  };
15
21
  //# sourceMappingURL=helper.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"helper.js","sourceRoot":"","sources":["../src/helper.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,2BAA2B,EAAE,2BAA2B,EAAE,+BAA+B,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAA;AAChJ,OAAO,EAAE,0BAA0B,EAAE,MAAM,cAAc,CAAA;AACzD,OAAO,EAAE,yBAAyB,EAAE,MAAM,eAAe,CAAA;AAEzD,MAAM,CAAC,MAAM,2BAA2B,GAAG,CACzC,OAA0B,EAC1B,OAAgB,EACV,EAAE;IACR,OAAO,CAAC,gBAAgB,CAAC,2BAA2B,CAAC,OAAO,CAAC,CAAC,CAAA;IAC9D,OAAO,CAAC,gBAAgB,CAAC,2BAA2B,CAAC,OAAO,CAAC,CAAC,CAAA;IAC9D,OAAO,CAAC,gBAAgB,CAAC,+BAA+B,CAAC,OAAO,CAAC,CAAC,CAAA;IAClE,OAAO,CAAC,gBAAgB,CAAC,qBAAqB,CAAC,OAAO,CAAC,CAAC,CAAA;IACxD,OAAO,CAAC,eAAe,CAAC,0BAA0B,EAAE,CAAC,CAAA;IACrD,sFAAsF;IACtF,8FAA8F;IAC9F,+DAA+D;IAC/D,OAAO,CAAC,eAAe,CAAC,yBAAyB,EAAE,CAAC,CAAA;AACtD,CAAC,CAAA"}
1
+ {"version":3,"file":"helper.js","sourceRoot":"","sources":["../src/helper.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,2BAA2B,EAAE,2BAA2B,EAAE,+BAA+B,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAA;AAChJ,OAAO,EAAE,0BAA0B,EAAE,MAAM,cAAc,CAAA;AACzD,OAAO,EAAE,yBAAyB,EAAE,MAAM,eAAe,CAAA;AACzD,OAAO,EAAE,yBAAyB,EAAE,MAAM,aAAa,CAAA;AACvD,OAAO,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAA;AAElD,MAAM,CAAC,MAAM,2BAA2B,GAAG,CACzC,OAA0B,EAC1B,OAAgB,EACV,EAAE;IACR,OAAO,CAAC,gBAAgB,CAAC,2BAA2B,CAAC,OAAO,CAAC,CAAC,CAAA;IAC9D,OAAO,CAAC,gBAAgB,CAAC,2BAA2B,CAAC,OAAO,CAAC,CAAC,CAAA;IAC9D,OAAO,CAAC,gBAAgB,CAAC,+BAA+B,CAAC,OAAO,CAAC,CAAC,CAAA;IAClE,OAAO,CAAC,gBAAgB,CAAC,qBAAqB,CAAC,OAAO,CAAC,CAAC,CAAA;IACxD,OAAO,CAAC,eAAe,CAAC,0BAA0B,EAAE,CAAC,CAAA;IACrD,sFAAsF;IACtF,8FAA8F;IAC9F,+DAA+D;IAC/D,OAAO,CAAC,eAAe,CAAC,yBAAyB,EAAE,CAAC,CAAA;IACpD,gGAAgG;IAChG,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,oBAAoB,CAAC,EAAE,CAAC;QAC9C,OAAO,CAAC,eAAe,CAAC,yBAAyB,EAAE,CAAC,CAAA;IACtD,CAAC;AACH,CAAC,CAAA"}
package/build/index.d.ts CHANGED
@@ -5,4 +5,5 @@ export * from './service.js';
5
5
  export * from './resolver.js';
6
6
  export * from './helper.js';
7
7
  export * from './iam.js';
8
+ export * from './events.js';
8
9
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAA;AAC3B,mBAAmB,YAAY,CAAA;AAC/B,cAAc,eAAe,CAAA;AAC7B,cAAc,cAAc,CAAA;AAC5B,cAAc,eAAe,CAAA;AAC7B,cAAc,aAAa,CAAA;AAC3B,cAAc,UAAU,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAA;AAC3B,mBAAmB,YAAY,CAAA;AAC/B,cAAc,eAAe,CAAA;AAC7B,cAAc,cAAc,CAAA;AAC5B,cAAc,eAAe,CAAA;AAC7B,cAAc,aAAa,CAAA;AAC3B,cAAc,UAAU,CAAA;AACxB,cAAc,aAAa,CAAA"}
package/build/index.js CHANGED
@@ -4,4 +4,5 @@ export * from './service.js';
4
4
  export * from './resolver.js';
5
5
  export * from './helper.js';
6
6
  export * from './iam.js';
7
+ export * from './events.js';
7
8
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAA;AAE3B,cAAc,eAAe,CAAA;AAC7B,cAAc,cAAc,CAAA;AAC5B,cAAc,eAAe,CAAA;AAC7B,cAAc,aAAa,CAAA;AAC3B,cAAc,UAAU,CAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAA;AAE3B,cAAc,eAAe,CAAA;AAC7B,cAAc,cAAc,CAAA;AAC5B,cAAc,eAAe,CAAA;AAC7B,cAAc,aAAa,CAAA;AAC3B,cAAc,UAAU,CAAA;AACxB,cAAc,aAAa,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../src/service.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAA8F,sBAAsB,EAAE,MAAM,YAAY,CAAA;AAmBpJ,eAAO,MAAM,0BAA0B,QAAO,sBA8Q7C,CAAA"}
1
+ {"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../src/service.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAA8F,sBAAsB,EAAE,MAAM,YAAY,CAAA;AAoBpJ,eAAO,MAAM,0BAA0B,QAAO,sBA6R7C,CAAA"}
package/build/service.js CHANGED
@@ -3,6 +3,7 @@ import { ALL_SCOPES, AuthRole } from '@owlmeans/auth';
3
3
  import { createIdOfLength, IdStyle } from '@owlmeans/basic-ids';
4
4
  import { ENTITY_RESOLVER } from '@owlmeans/auth-common';
5
5
  import { AUTH_IDENTITY_ACCOUNT, AUTH_IDENTITY_PROFILE, AUTH_IDENTITY_CREDENTIALS, AUTH_IDENTITY_LINKING, AUTH_IDENTITY_ORG_ENTITY, LOGIN_SERVICE_PREFIX, EXTERNAL_KEY_DELIMITER } from './consts.js';
6
+ import { identityEvents } from './events.js';
6
7
  const MAX_SLUG_RETRIES = 5;
7
8
  // Stable external login key: "{type}:{service}:{providerSub}"
8
9
  const externalKey = (details) => [details.type, details.service, details.userId].join(EXTERNAL_KEY_DELIMITER);
@@ -172,6 +173,20 @@ export const makeIdentityLinkingService = () => {
172
173
  profileId,
173
174
  credential: svc,
174
175
  });
176
+ // Only this branch creates an organization — the linking branch above adds a credential to
177
+ // one that exists — so this is the one place an entity is announced, once it is complete.
178
+ // Listeners are awaited and never throw (the service logs them).
179
+ await identityEvents(ctx)?.propagateEntityCreated({
180
+ entityId,
181
+ entitySlug: entity.slug,
182
+ iamKey: entity.iamKey,
183
+ accountId,
184
+ profileId: profile.profileId,
185
+ username: meta.username,
186
+ type: details.type,
187
+ service: details.service,
188
+ createdAt: entity.createdAt,
189
+ });
175
190
  return {
176
191
  type: details.type,
177
192
  role: profile.role,
@@ -1 +1 @@
1
- {"version":3,"file":"service.js","sourceRoot":"","sources":["../src/service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAA;AAGpD,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAA;AAErD,OAAO,EAAE,gBAAgB,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAM/D,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAA;AACvD,OAAO,EAAE,qBAAqB,EAAE,qBAAqB,EAAE,yBAAyB,EAAE,qBAAqB,EAAE,wBAAwB,EAAE,oBAAoB,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAA;AAIpM,MAAM,gBAAgB,GAAG,CAAC,CAAA;AAE1B,8DAA8D;AAC9D,MAAM,WAAW,GAAG,CAAC,OAA+B,EAAU,EAAE,CAC9D,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,OAAO,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,sBAAsB,CAAC,CAAA;AAE9E,yFAAyF;AACzF,MAAM,YAAY,GAAG,CAAC,OAA+B,EAAU,EAAE,CAC/D,CAAC,oBAAoB,EAAE,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,sBAAsB,CAAC,CAAA;AAEpF,MAAM,CAAC,MAAM,0BAA0B,GAAG,GAA2B,EAAE;IACrE;;;;;;OAMG;IACH,MAAM,MAAM,GAAG,KAAK,EAAE,QAAiB,EAA+B,EAAE;QACtE,IAAI,QAAQ,IAAI,IAAI,IAAI,QAAQ,KAAK,EAAE;YAAE,OAAO,SAAS,CAAA;QACzD,MAAM,GAAG,GAAG,OAAO,CAAC,GAAc,CAAA;QAClC,MAAM,MAAM,GAAG,MAAM,GAAG,CAAC,OAAO,CAAwB,eAAe,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;QAEvF,OAAO,MAAM,EAAE,IAAI,CAAA;IACrB,CAAC,CAAA;IAED;;;;;;;;;;;;;;;;;OAiBG;IACH,MAAM,oBAAoB,GAAG,KAAK,EAAE,QAAgB,EAAmC,EAAE;QACvF,MAAM,IAAI,GAAG,QAAQ,CAAC,IAAI,EAAE,CAAA;QAC5B,IAAI,IAAI,KAAK,EAAE;YAAE,OAAO,IAAI,CAAA;QAE5B,MAAM,GAAG,GAAG,OAAO,CAAC,GAAc,CAAA;QAClC,MAAM,eAAe,GAAG,GAAG,CAAC,QAAQ,CAA0B,qBAAqB,CAAC,CAAA;QACpF,MAAM,eAAe,GAAG,GAAG,CAAC,QAAQ,CAA0B,qBAAqB,CAAC,CAAA;QAEpF,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,GAAG,MAAM,eAAe,CAAC,IAAI,CAAC,EAAE,IAAI,EAA+B,CAAC,CAAA;QAC7F,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;YAC/B,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,GAAG,MAAM,eAAe,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,EAA+B,CAAC,CAAA;YAC3G,MAAM,QAAQ,GAAG,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CACvC,OAAO,CAAC,UAAU,EAAE,UAAU,CAAC,GAAG,oBAAoB,GAAG,sBAAsB,EAAE,CAAC,KAAK,IAAI,CAC5F,CAAA;YACD,IAAI,QAAQ,IAAI,IAAI;gBAAE,OAAO,QAAQ,CAAA;QACvC,CAAC;QAED,OAAO,IAAI,CAAA;IACb,CAAC,CAAA;IAED,MAAM,OAAO,GAA2B,gBAAgB,CAAyB,qBAAqB,EAAE;QACtG,gBAAgB,EAAE,KAAK,EAAE,OAA+B,EAA+B,EAAE;YACvF,MAAM,GAAG,GAAG,OAAO,CAAC,GAAc,CAAA;YAClC,MAAM,aAAa,GAAG,GAAG,CAAC,QAAQ,CAA8B,yBAAyB,CAAC,CAAA;YAE1F,MAAM,IAAI,GAAG,MAAM,aAAa,CAAC,IAAI,CAAC;gBACpC,IAAI,EAAE,OAAO,CAAC,IAAI;gBAClB,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC;gBAC5B,UAAU,EAAE,YAAY,CAAC,OAAO,CAAC;aAClC,CAAC,CAAA;YACF,IAAI,IAAI,IAAI,IAAI;gBAAE,OAAO,IAAI,CAAA;YAE7B,MAAM,eAAe,GAAG,GAAG,CAAC,QAAQ,CAA0B,qBAAqB,CAAC,CAAA;YACpF,MAAM,OAAO,GAAG,MAAM,eAAe,CAAC,IAAI,CAAC,EAAE,SAAS,EAAE,IAAI,CAAC,SAAS,EAAE,CAAC,CAAA;YACzE,IAAI,OAAO,IAAI,IAAI;gBAAE,OAAO,IAAI,CAAA;YAEhC,OAAO;gBACL,IAAI,EAAE,OAAO,CAAC,IAAI;gBAClB,IAAI,EAAE,OAAO,CAAC,IAAI;gBAClB,MAAM,EAAE,OAAO,CAAC,MAAM,IAAI,OAAO,CAAC,SAAS;gBAC3C,SAAS,EAAE,OAAO,CAAC,SAAS;gBAC5B,UAAU,EAAE,MAAM,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC;gBAC1C,MAAM,EAAE,OAAO,CAAC,MAAM;aACvB,CAAA;QACH,CAAC;QAED,WAAW,EAAE,KAAK,EAAE,OAA+B,EAAE,IAAiB,EAAwB,EAAE;YAC9F,MAAM,GAAG,GAAG,OAAO,CAAC,GAAc,CAAA;YAClC,MAAM,eAAe,GAAG,GAAG,CAAC,QAAQ,CAA0B,qBAAqB,CAAC,CAAA;YACpF,MAAM,eAAe,GAAG,GAAG,CAAC,QAAQ,CAA0B,qBAAqB,CAAC,CAAA;YACpF,MAAM,aAAa,GAAG,GAAG,CAAC,QAAQ,CAA8B,yBAAyB,CAAC,CAAA;YAC1F,MAAM,cAAc,GAAG,GAAG,CAAC,QAAQ,CAAoB,wBAAwB,CAAC,CAAA;YAChF,MAAM,QAAQ,GAAG,GAAG,CAAC,OAAO,CAAwB,eAAe,CAAC,CAAA;YAEpE,wFAAwF;YACxF,4FAA4F;YAC5F,sDAAsD;YACtD,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,oBAAoB,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;YACpF,IAAI,KAAK,IAAI,IAAI,EAAE,CAAC;gBAClB,MAAM,aAAa,CAAC,MAAM,CAAC;oBACzB,SAAS,EAAE,EAAE;oBACb,IAAI,EAAE,OAAO,CAAC,IAAI;oBAClB,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC;oBAC5B,SAAS,EAAE,KAAK,CAAC,SAAS;oBAC1B,UAAU,EAAE,YAAY,CAAC,OAAO,CAAC;iBAClC,CAAC,CAAA;gBAEF,OAAO;oBACL,IAAI,EAAE,OAAO,CAAC,IAAI;oBAClB,IAAI,EAAE,KAAK,CAAC,IAAI;oBAChB,MAAM,EAAE,KAAK,CAAC,MAAM,IAAI,KAAK,CAAC,SAAS;oBACvC,SAAS,EAAE,KAAK,CAAC,SAAS;oBAC1B,UAAU,EAAE,MAAM,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC;oBACxC,MAAM,EAAE,KAAK,CAAC,MAAM;iBACrB,CAAA;YACH,CAAC;YAED,yFAAyF;YACzF,6FAA6F;YAC7F,sFAAsF;YACtF,MAAM,MAAM,GAAc,MAAM,cAAc,CAAC,MAAM,CAAC;gBACpD,IAAI,EAAE,MAAM,QAAQ,CAAC,QAAQ,EAAE;gBAC/B,WAAW,EAAE,EAAE;gBACf,wFAAwF;gBACxF,2EAA2E;gBAC3E,MAAM,EAAE,gBAAgB,CAAC,EAAE,EAAE,OAAO,CAAC,MAAM,CAAC;gBAC5C,KAAK,EAAE,EAAE;gBACT,SAAS,EAAE,IAAI,IAAI,EAAE;aACtB,CAAC,CAAA;YACF,MAAM,QAAQ,GAAG,MAAM,CAAC,EAAG,CAAA;YAE3B,IAAI,SAAS,GAAkB,IAAI,CAAA;YACnC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,gBAAgB,EAAE,CAAC,EAAE,EAAE,CAAC;gBAC1C,MAAM,UAAU,GAAG,gBAAgB,CAAC,EAAE,EAAE,OAAO,CAAC,MAAM,CAAC,CAAA;gBACvD,IAAI,CAAC;oBACH,MAAM,OAAO,GAAG,MAAM,eAAe,CAAC,MAAM,CAAC;wBAC3C,UAAU;wBACV,IAAI,EAAE,IAAI,CAAC,QAAQ;wBACnB,QAAQ;qBACT,CAAC,CAAA;oBACF,SAAS,GAAG,OAAO,CAAC,EAAE,CAAA;oBACtB,MAAK;gBACP,CAAC;gBAAC,OAAO,GAAQ,EAAE,CAAC;oBAClB,IAAI,GAAG,EAAE,IAAI,KAAK,KAAK,IAAI,GAAG,EAAE,OAAO,EAAE,QAAQ,CAAC,WAAW,CAAC;wBAAE,SAAQ;oBACxE,MAAM,GAAG,CAAA;gBACX,CAAC;YACH,CAAC;YAED,IAAI,SAAS,IAAI,IAAI,EAAE,CAAC;gBACtB,MAAM,IAAI,KAAK,CAAC,4DAA4D,CAAC,CAAA;YAC/E,CAAC;YAED,MAAM,SAAS,GAAG,CAAC,OAAO,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC,IAAI,CAAC,sBAAsB,CAAC,CAAA;YACxE,MAAM,GAAG,GAAG,YAAY,CAAC,OAAO,CAAC,CAAA;YAEjC,IAAI,OAAO,CAAA;YACX,IAAI,CAAC;gBACH,OAAO,GAAG,MAAM,eAAe,CAAC,MAAM,CAAC;oBACrC,SAAS;oBACT,MAAM,EAAE,SAAS;oBACjB,UAAU,EAAE,GAAG;oBACf,IAAI,EAAE,QAAQ,CAAC,IAAI;oBACnB,IAAI,EAAE,IAAI,CAAC,QAAQ;oBACnB,QAAQ;oBACR,MAAM,EAAE,CAAC,UAAU,CAAC;iBACrB,CAAC,CAAA;YACJ,CAAC;YAAC,OAAO,GAAQ,EAAE,CAAC;gBAClB,IAAI,GAAG,EAAE,IAAI,KAAK,KAAK,IAAI,GAAG,EAAE,OAAO,EAAE,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC;oBAC/D,OAAO,GAAG,MAAM,eAAe,CAAC,GAAG,CAAC,EAAE,SAAS,EAAE,CAAC,CAAA;gBACpD,CAAC;qBAAM,CAAC;oBACN,MAAM,GAAG,CAAA;gBACX,CAAC;YACH,CAAC;YAED,MAAM,aAAa,CAAC,MAAM,CAAC;gBACzB,SAAS,EAAE,EAAE;gBACb,IAAI,EAAE,OAAO,CAAC,IAAI;gBAClB,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC;gBAC5B,SAAS;gBACT,UAAU,EAAE,GAAG;aAChB,CAAC,CAAA;YAEF,OAAO;gBACL,IAAI,EAAE,OAAO,CAAC,IAAI;gBAClB,IAAI,EAAE,OAAO,CAAC,IAAI;gBAClB,MAAM,EAAE,OAAO,CAAC,MAAM,IAAI,OAAO,CAAC,SAAS;gBAC3C,SAAS,EAAE,OAAO,CAAC,SAAS;gBAC5B,UAAU,EAAE,MAAM,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC;gBAC1C,MAAM,EAAE,OAAO,CAAC,MAAM;aACvB,CAAA;QACH,CAAC;QAED,eAAe,EAAE,KAAK,EAAE,OAA+B,EAAwB,EAAE;YAC/E,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAA;YACtD,IAAI,MAAM,IAAI,IAAI,EAAE,CAAC;gBACnB,MAAM,IAAI,KAAK,CAAC,4CAA4C,CAAC,CAAA;YAC/D,CAAC;YAED,IAAI,OAAO,CAAC,SAAS,IAAI,IAAI,EAAE,CAAC;gBAC9B,MAAM,GAAG,GAAG,OAAO,CAAC,GAAc,CAAA;gBAClC,MAAM,aAAa,GAAG,GAAG,CAAC,QAAQ,CAA8B,yBAAyB,CAAC,CAAA;gBAC1F,MAAM,aAAa,CAAC,MAAM,CAAC;oBACzB,SAAS,EAAE,EAAE;oBACb,IAAI,EAAE,OAAO,CAAC,IAAI;oBAClB,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC;oBAC5B,SAAS,EAAE,OAAO,CAAC,SAAS;oBAC5B,UAAU,EAAE,YAAY,CAAC,OAAO,CAAC;iBAClC,CAAC,CAAA;YACJ,CAAC;YAED,OAAO,MAAM,CAAA;QACf,CAAC;QAED,iBAAiB,EAAE,KAAK,EAAE,OAA+B,EAAiB,EAAE;YAC1E,MAAM,GAAG,GAAG,OAAO,CAAC,GAAc,CAAA;YAClC,MAAM,aAAa,GAAG,GAAG,CAAC,QAAQ,CAA8B,yBAAyB,CAAC,CAAA;YAC1F,MAAM,IAAI,GAAG,MAAM,aAAa,CAAC,IAAI,CAAC;gBACpC,IAAI,EAAE,OAAO,CAAC,IAAI;gBAClB,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC;gBAC5B,UAAU,EAAE,YAAY,CAAC,OAAO,CAAC;aAClC,CAAC,CAAA;YACF,IAAI,IAAI,EAAE,EAAE,IAAI,IAAI;gBAAE,OAAM;YAC5B,MAAM,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;QACrC,CAAC;QAED,gBAAgB,EAAE,KAAK,EAAE,QAAgB,EAAsB,EAAE;YAC/D,MAAM,GAAG,GAAG,OAAO,CAAC,GAAc,CAAA;YAClC,MAAM,eAAe,GAAG,GAAG,CAAC,QAAQ,CAA0B,qBAAqB,CAAC,CAAA;YACpF,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,GAAG,MAAM,eAAe,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAA;YAEpE,OAAO,MAAM,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,EAAC,CAAC,EAAC,EAAE,CAAC,CAAC;gBAChD,EAAE,EAAE,CAAC,CAAC,SAAS;gBACf,IAAI,EAAE,CAAC,CAAC,IAAI;gBACZ,UAAU,EAAE,CAAC,CAAC,UAAU;gBACxB,UAAU,EAAE,MAAM,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC;gBACpC,MAAM,EAAE,CAAC,CAAC,MAAM;gBAChB,MAAM,EAAE,CAAC,CAAC,MAAM;gBAChB,WAAW,EAAE,CAAC,CAAC,WAAW;gBAC1B,UAAU,EAAE,CAAC,CAAC,UAAU;aACzB,CAAC,CAAC,CAAC,CAAA;QACN,CAAC;QAED,mBAAmB,EAAE,KAAK,EAAE,MAAc,EAAE,QAAiB,EAAE,IAAa,EAAwC,EAAE;YACpH,MAAM,GAAG,GAAG,OAAO,CAAC,GAAc,CAAA;YAClC,MAAM,eAAe,GAAG,GAAG,CAAC,QAAQ,CAA0B,qBAAqB,CAAC,CAAA;YACpF,MAAM,aAAa,GAAG,GAAG,CAAC,QAAQ,CAA8B,yBAAyB,CAAC,CAAA;YAE1F,MAAM,aAAa,GAA8B,EAAE,MAAM,EAAE,CAAA;YAC3D,IAAI,QAAQ,IAAI,IAAI;gBAAE,aAAa,CAAC,QAAQ,GAAG,QAAQ,CAAA;YACvD,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,GAAG,MAAM,eAAe,CAAC,IAAI,CAAC,aAAa,CAAC,CAAA;YACrE,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC;gBAAE,OAAO,SAAS,CAAA;YAE3C,MAAM,WAAW,GAAkC;gBACjD,SAAS,EAAE,EAAE,GAAG,EAAE,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE;aACnD,CAAA;YACD,IAAI,IAAI,IAAI,IAAI;gBAAE,WAAW,CAAC,IAAI,GAAG,IAAI,CAAA;YACzC,MAAM,IAAI,GAAG,MAAM,aAAa,CAAC,IAAI,CAAC,WAAW,CAAC,CAAA;YAClD,IAAI,IAAI,IAAI,IAAI;gBAAE,OAAO,SAAS,CAAA;YAElC,MAAM,OAAO,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,KAAK,IAAI,CAAC,SAAS,CAAC,IAAI,QAAQ,CAAC,CAAC,CAAC,CAAA;YAEjF,OAAO;gBACL,IAAI,EAAE,IAAI,CAAC,IAAI;gBACf,IAAI,EAAE,OAAO,CAAC,IAAI;gBAClB,MAAM,EAAE,OAAO,CAAC,MAAM,IAAI,OAAO,CAAC,SAAS;gBAC3C,SAAS,EAAE,OAAO,CAAC,SAAS;gBAC5B,UAAU,EAAE,MAAM,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC;gBAC1C,MAAM,EAAE,OAAO,CAAC,MAAM;gBACtB,SAAS,EAAE,IAAI,CAAC,SAAS;gBACzB,UAAU,EAAE,IAAI,CAAC,UAAU;gBAC3B,SAAS,EAAE,IAAI,CAAC,SAAS;aAC1B,CAAA;QACH,CAAC;KACF,CAAC,CAAA;IAEF,OAAO,OAAO,CAAA;AAChB,CAAC,CAAA"}
1
+ {"version":3,"file":"service.js","sourceRoot":"","sources":["../src/service.ts"],"names":[],"mappings":"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"}
package/build/types.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import type { ResourceRecord } from '@owlmeans/resource';
2
2
  import type { MongoResource } from '@owlmeans/mongo-resource';
3
- import type { InitializedService } from '@owlmeans/context';
3
+ import type { InitializedService, LazyService } from '@owlmeans/context';
4
4
  import type { ServerConfig, ServerContext } from '@owlmeans/server-context';
5
5
  import type { AuthCredentials, AuthPayload, AuthRole, Profile } from '@owlmeans/auth';
6
6
  import type { ProviderProfileDetails } from '@owlmeans/oidc';
@@ -101,4 +101,40 @@ export interface GoogleUserInfo {
101
101
  family_name?: string;
102
102
  picture?: string;
103
103
  }
104
+ /**
105
+ * An organization entity was just registered, together with the account and profile of the person
106
+ * whose first sign-in created it. `entityId` is the stable id every per-organization record keys
107
+ * on; `entitySlug` is its name at this moment and may be renamed later.
108
+ */
109
+ export interface EntityCreatedEvent {
110
+ entityId: string;
111
+ entitySlug: string;
112
+ iamKey: string;
113
+ accountId: string;
114
+ profileId: string;
115
+ username: string;
116
+ /** The login's `AuthenticationType`. */
117
+ type: string;
118
+ /** The provider service alias the login came through. */
119
+ service: string;
120
+ createdAt: Date;
121
+ }
122
+ export interface EntityCreatedCallback {
123
+ (event: EntityCreatedEvent, ctx: IdentityContext): Promise<void>;
124
+ }
125
+ /**
126
+ * Lifecycle notifications from the identity store — the seam an application hangs provisioning on
127
+ * (a starting plan, a default workspace) without wrapping the linking service.
128
+ *
129
+ * Lazy, so a listener can be registered while the context is still being wired.
130
+ */
131
+ export interface IdentityEventsService extends LazyService {
132
+ /** Called for every entity registered from now on, in registration order. */
133
+ onEntityCreated: (callback: EntityCreatedCallback) => void;
134
+ /**
135
+ * Run every listener, one after another, each awaited. A listener that throws is logged and the
136
+ * rest still run: a listener's failure never fails the sign-in that created the entity.
137
+ */
138
+ propagateEntityCreated: (event: EntityCreatedEvent) => Promise<void>;
139
+ }
104
140
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@owlmeans/server-auth-identity",
3
- "version": "0.1.18-rc.28",
3
+ "version": "0.1.18-rc.29",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "scripts": {
@@ -22,14 +22,14 @@
22
22
  }
23
23
  },
24
24
  "dependencies": {
25
- "@owlmeans/auth": "^0.1.18-rc.26",
26
- "@owlmeans/auth-common": "^0.1.18-rc.28",
27
- "@owlmeans/basic-ids": "^0.1.18-rc.25",
28
- "@owlmeans/context": "^0.1.18-rc.24",
29
- "@owlmeans/mongo-resource": "^0.1.18-rc.27",
30
- "@owlmeans/oidc": "^0.1.18-rc.36",
31
- "@owlmeans/resource": "^0.1.18-rc.26",
32
- "@owlmeans/server-context": "^0.1.18-rc.27"
25
+ "@owlmeans/auth": "^0.1.18-rc.27",
26
+ "@owlmeans/auth-common": "^0.1.18-rc.29",
27
+ "@owlmeans/basic-ids": "^0.1.18-rc.26",
28
+ "@owlmeans/context": "^0.1.18-rc.25",
29
+ "@owlmeans/mongo-resource": "^0.1.18-rc.28",
30
+ "@owlmeans/oidc": "^0.1.18-rc.37",
31
+ "@owlmeans/resource": "^0.1.18-rc.27",
32
+ "@owlmeans/server-context": "^0.1.18-rc.28"
33
33
  },
34
34
  "peerDependencies": {
35
35
  "mongodb": "*"
package/src/consts.ts CHANGED
@@ -8,6 +8,8 @@ export const AUTH_IDENTITY_PROFILE = 'auth-identity:profile'
8
8
  export const AUTH_IDENTITY_CREDENTIALS = 'auth-identity:credentials'
9
9
  export const AUTH_IDENTITY_LINKING = 'auth-identity:linking'
10
10
  export const AUTH_IDENTITY_ORG_ENTITY = 'auth-identity:org-entity'
11
+ // Service alias of the identity-events seam (`identityEvents(ctx)`).
12
+ export const AUTH_IDENTITY_EVENTS = 'auth-identity:events'
11
13
 
12
14
  // Colon-free Mongo collection base names. The final collection name is
13
15
  // `${resourcePrefix}${collection}` — e.g. with the project prefix 'viam-' this yields
package/src/events.ts ADDED
@@ -0,0 +1,39 @@
1
+ import type { BasicContext } from '@owlmeans/context'
2
+ import { createLazyService } from '@owlmeans/context'
3
+ import { AUTH_IDENTITY_EVENTS } from './consts.js'
4
+ import type { EntityCreatedCallback, IdentityContext, IdentityEventsService } from './types.js'
5
+
6
+ export const makeIdentityEventsService = (
7
+ alias: string = AUTH_IDENTITY_EVENTS
8
+ ): IdentityEventsService => {
9
+ const created: EntityCreatedCallback[] = []
10
+
11
+ const service: IdentityEventsService = createLazyService<IdentityEventsService>(alias, {
12
+ onEntityCreated: callback => {
13
+ created.push(callback)
14
+ },
15
+
16
+ propagateEntityCreated: async event => {
17
+ for (const callback of created) {
18
+ try {
19
+ await callback(event, service.assertCtx<IdentityContext['cfg'], IdentityContext>())
20
+ } catch (error) {
21
+ // The entity, the account and the profile already exist; failing here would turn a
22
+ // listener's problem into a sign-in that never completes for a person who is registered.
23
+ console.error(`${alias}: entity-created listener failed for ${event.entityId}`, error)
24
+ }
25
+ }
26
+ },
27
+ })
28
+
29
+ return service
30
+ }
31
+
32
+ /**
33
+ * The identity-events service, or `null` where the context has none registered — so a caller
34
+ * writes `identityEvents(ctx)?.onEntityCreated(...)` and a deployment without the seam pays nothing.
35
+ */
36
+ export const identityEvents = (
37
+ ctx: BasicContext<any>, alias: string = AUTH_IDENTITY_EVENTS
38
+ ): IdentityEventsService | null =>
39
+ ctx.hasService(alias) ? ctx.service<IdentityEventsService>(alias) : null
package/src/helper.ts CHANGED
@@ -2,6 +2,8 @@ import type { BasicContext } from '@owlmeans/context'
2
2
  import { makeIdentityAccountResource, makeIdentityProfileResource, makeIdentityCredentialsResource, makeOrgEntityResource } from './resource.js'
3
3
  import { makeIdentityLinkingService } from './service.js'
4
4
  import { makeEntityResolverService } from './resolver.js'
5
+ import { makeIdentityEventsService } from './events.js'
6
+ import { AUTH_IDENTITY_EVENTS } from './consts.js'
5
7
 
6
8
  export const appendAuthIdentityResources = (
7
9
  context: BasicContext<any>,
@@ -16,4 +18,8 @@ export const appendAuthIdentityResources = (
16
18
  // organizations: without it `request.entity` stays undefined and every consumer falls back to
17
19
  // treating the token's slug as the only entity value there is.
18
20
  context.registerService(makeEntityResolverService())
21
+ // Behind `hasService`, so an application that registered its own events service first keeps it.
22
+ if (!context.hasService(AUTH_IDENTITY_EVENTS)) {
23
+ context.registerService(makeIdentityEventsService())
24
+ }
19
25
  }
package/src/index.ts CHANGED
@@ -5,3 +5,4 @@ export * from './service.js'
5
5
  export * from './resolver.js'
6
6
  export * from './helper.js'
7
7
  export * from './iam.js'
8
+ export * from './events.js'
package/src/service.ts CHANGED
@@ -11,6 +11,7 @@ import type { OrgEntity, OrgEntityResource } from './types.js'
11
11
  import type { EntityResolverService } from '@owlmeans/auth-common'
12
12
  import { ENTITY_RESOLVER } from '@owlmeans/auth-common'
13
13
  import { AUTH_IDENTITY_ACCOUNT, AUTH_IDENTITY_PROFILE, AUTH_IDENTITY_CREDENTIALS, AUTH_IDENTITY_LINKING, AUTH_IDENTITY_ORG_ENTITY, LOGIN_SERVICE_PREFIX, EXTERNAL_KEY_DELIMITER } from './consts.js'
14
+ import { identityEvents } from './events.js'
14
15
 
15
16
  type Context = ServerContext<ServerConfig>
16
17
 
@@ -200,6 +201,21 @@ export const makeIdentityLinkingService = (): IdentityLinkingService => {
200
201
  credential: svc,
201
202
  })
202
203
 
204
+ // Only this branch creates an organization — the linking branch above adds a credential to
205
+ // one that exists — so this is the one place an entity is announced, once it is complete.
206
+ // Listeners are awaited and never throw (the service logs them).
207
+ await identityEvents(ctx)?.propagateEntityCreated({
208
+ entityId,
209
+ entitySlug: entity.slug,
210
+ iamKey: entity.iamKey,
211
+ accountId,
212
+ profileId: profile.profileId,
213
+ username: meta.username,
214
+ type: details.type,
215
+ service: details.service,
216
+ createdAt: entity.createdAt,
217
+ })
218
+
203
219
  return {
204
220
  type: details.type,
205
221
  role: profile.role,
package/src/types.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import type { ResourceRecord } from '@owlmeans/resource'
2
2
  import type { MongoResource } from '@owlmeans/mongo-resource'
3
- import type { InitializedService } from '@owlmeans/context'
3
+ import type { InitializedService, LazyService } from '@owlmeans/context'
4
4
  import type { ServerConfig, ServerContext } from '@owlmeans/server-context'
5
5
  import type { AuthCredentials, AuthPayload, AuthRole, Profile } from '@owlmeans/auth'
6
6
  import type { ProviderProfileDetails } from '@owlmeans/oidc'
@@ -113,3 +113,41 @@ export interface GoogleUserInfo {
113
113
  picture?: string
114
114
  }
115
115
 
116
+ /**
117
+ * An organization entity was just registered, together with the account and profile of the person
118
+ * whose first sign-in created it. `entityId` is the stable id every per-organization record keys
119
+ * on; `entitySlug` is its name at this moment and may be renamed later.
120
+ */
121
+ export interface EntityCreatedEvent {
122
+ entityId: string
123
+ entitySlug: string
124
+ iamKey: string
125
+ accountId: string
126
+ profileId: string
127
+ username: string
128
+ /** The login's `AuthenticationType`. */
129
+ type: string
130
+ /** The provider service alias the login came through. */
131
+ service: string
132
+ createdAt: Date
133
+ }
134
+
135
+ export interface EntityCreatedCallback {
136
+ (event: EntityCreatedEvent, ctx: IdentityContext): Promise<void>
137
+ }
138
+
139
+ /**
140
+ * Lifecycle notifications from the identity store — the seam an application hangs provisioning on
141
+ * (a starting plan, a default workspace) without wrapping the linking service.
142
+ *
143
+ * Lazy, so a listener can be registered while the context is still being wired.
144
+ */
145
+ export interface IdentityEventsService extends LazyService {
146
+ /** Called for every entity registered from now on, in registration order. */
147
+ onEntityCreated: (callback: EntityCreatedCallback) => void
148
+ /**
149
+ * Run every listener, one after another, each awaited. A listener that throws is logged and the
150
+ * rest still run: a listener's failure never fails the sign-in that created the entity.
151
+ */
152
+ propagateEntityCreated: (event: EntityCreatedEvent) => Promise<void>
153
+ }
@@ -0,0 +1,98 @@
1
+ import { ENTITY_RESOLVER } from '@owlmeans/auth-common'
2
+ import type { BasicContext } from '@owlmeans/context'
3
+ import { makeIdentityLinkingService } from '../src/service.js'
4
+ import { makeIdentityEventsService } from '../src/events.js'
5
+ import {
6
+ AUTH_IDENTITY_ACCOUNT, AUTH_IDENTITY_CREDENTIALS, AUTH_IDENTITY_EVENTS, AUTH_IDENTITY_ORG_ENTITY,
7
+ AUTH_IDENTITY_PROFILE,
8
+ } from '../src/consts.js'
9
+ import type { IdentityEventsService } from '../src/types.js'
10
+
11
+ /**
12
+ * The rows are stubbed rather than mocked — the linking service's whole behaviour is which record
13
+ * it reads before it writes, so a stub that records writes is the subject, not a stand-in for it.
14
+ */
15
+ export const stubResource = <T extends { id?: string }>(alias: string, seed: T[] = []) => {
16
+ const items: T[] = [...seed]
17
+ let next = seed.length + 1
18
+
19
+ const matches = (record: any, where: any): boolean =>
20
+ where == null || Object.entries(where).every(([key, value]) => record[key] === value)
21
+
22
+ return {
23
+ alias,
24
+ items,
25
+ list: async (where?: unknown) => ({ items: items.filter(item => matches(item, where)) }),
26
+ load: async (where?: unknown) => items.find(item => matches(item, where)) ?? null,
27
+ get: async (where?: unknown) => {
28
+ const found = items.find(item => matches(item, where))
29
+ if (found == null) throw new Error(`${alias}: not found`)
30
+ return found
31
+ },
32
+ create: async (record: T) => {
33
+ const stored = { ...record, id: record.id ?? `${alias}-${next++}` } as T
34
+ items.push(stored)
35
+ return stored
36
+ },
37
+ delete: async (id: string) => {
38
+ const at = items.findIndex(item => item.id === id)
39
+ if (at < 0) return null
40
+ return items.splice(at, 1)[0]
41
+ },
42
+ registerContext: () => undefined,
43
+ }
44
+ }
45
+
46
+ export interface CtxSeed {
47
+ accounts?: any[]
48
+ profiles?: any[]
49
+ credentials?: any[]
50
+ /** Register the identity-events service, as `appendAuthIdentityResources` does. */
51
+ events?: boolean
52
+ }
53
+
54
+ export const makeCtx = (seed: CtxSeed = {}) => {
55
+ const resources: Record<string, any> = {
56
+ [AUTH_IDENTITY_ACCOUNT]: stubResource('account', seed.accounts),
57
+ [AUTH_IDENTITY_PROFILE]: stubResource('profile', seed.profiles),
58
+ [AUTH_IDENTITY_CREDENTIALS]: stubResource('credential', seed.credentials),
59
+ [AUTH_IDENTITY_ORG_ENTITY]: stubResource('entity'),
60
+ }
61
+ const services: Record<string, unknown> = {}
62
+ let minted = 0
63
+
64
+ const ctx = {
65
+ resources,
66
+ resource: (alias: string) => resources[alias],
67
+ hasService: (alias: string) => alias === ENTITY_RESOLVER || alias in services,
68
+ service: (alias: string) => {
69
+ if (alias in services) return services[alias]
70
+ if (alias !== ENTITY_RESOLVER) throw new Error(`unexpected service ${alias}`)
71
+ return {
72
+ mintSlug: async () => `slug-${++minted}`,
73
+ byId: async (id: string) => ({ id, slug: `slug-of-${id}` }),
74
+ }
75
+ },
76
+ }
77
+
78
+ if (seed.events === true) {
79
+ const events = makeIdentityEventsService()
80
+ events.registerContext(ctx as unknown as BasicContext<any>)
81
+ services[AUTH_IDENTITY_EVENTS] = events
82
+ }
83
+
84
+ return ctx
85
+ }
86
+
87
+ export const eventsOf = (ctx: ReturnType<typeof makeCtx>): IdentityEventsService =>
88
+ ctx.service(AUTH_IDENTITY_EVENTS) as IdentityEventsService
89
+
90
+ export const details = (type: string, sub: string) => ({
91
+ type, service: type, clientId: type, userId: sub, username: 'person@example.org',
92
+ })
93
+
94
+ export const linkingFor = (ctx: unknown) => {
95
+ const service = makeIdentityLinkingService()
96
+ service.registerContext(ctx as never)
97
+ return service
98
+ }
@@ -0,0 +1,81 @@
1
+ import { describe, expect, test } from 'bun:test'
2
+ import { AuthenticationType } from '@owlmeans/auth'
3
+ import type { EntityCreatedEvent } from '../src/types.js'
4
+ import { identityEvents } from '../src/events.js'
5
+ import { AUTH_IDENTITY_ACCOUNT, AUTH_IDENTITY_ORG_ENTITY } from '../src/consts.js'
6
+ import { details, eventsOf, linkingFor, makeCtx } from './context.js'
7
+
8
+ /**
9
+ * The organization entity is announced exactly when one is created — on a registration, never on
10
+ * a second sign-in method that links to an identity the platform already has. An application
11
+ * provisions on it (a starting plan, say), so a missed or doubled event is a missed or doubled
12
+ * provisioning, and a listener's failure must not become a login failure.
13
+ */
14
+ describe('identity events', () => {
15
+ test('a registration announces the entity it created, once', async () => {
16
+ const ctx = makeCtx({ events: true })
17
+ const received: EntityCreatedEvent[] = []
18
+ eventsOf(ctx).onEntityCreated(async event => { received.push(event) })
19
+
20
+ const payload = await linkingFor(ctx).linkProfile(
21
+ details('google-oauth', 'google-sub') as never, { username: 'person@example.org' }
22
+ )
23
+
24
+ const [entity] = ctx.resources[AUTH_IDENTITY_ORG_ENTITY].items
25
+ expect(received).toHaveLength(1)
26
+ expect(received[0]).toMatchObject({
27
+ entityId: entity.id,
28
+ entitySlug: entity.slug,
29
+ iamKey: entity.iamKey,
30
+ profileId: payload.profileId,
31
+ username: 'person@example.org',
32
+ type: 'google-oauth',
33
+ service: 'google-oauth',
34
+ })
35
+ expect(received[0].accountId).toBe(ctx.resources[AUTH_IDENTITY_ACCOUNT].items[0].id)
36
+ expect(received[0].createdAt).toBeInstanceOf(Date)
37
+ })
38
+
39
+ test('a second sign-in method links and announces nothing', async () => {
40
+ const ctx = makeCtx({ events: true })
41
+ const received: EntityCreatedEvent[] = []
42
+ eventsOf(ctx).onEntityCreated(async event => { received.push(event) })
43
+ const linking = linkingFor(ctx)
44
+
45
+ await linking.linkProfile(details('google-oauth', 'google-sub') as never, { username: 'person@example.org' })
46
+ await linking.linkProfile(
47
+ details(AuthenticationType.Supervisor, 'person@example.org') as never, { username: 'person@example.org' }
48
+ )
49
+ expect(received).toHaveLength(1)
50
+
51
+ await linking.linkProfile(
52
+ details('google-oauth', 'other-sub') as never, { username: 'person@example.org', force: true }
53
+ )
54
+ expect(received).toHaveLength(2)
55
+ expect(received[1].entityId).not.toBe(received[0].entityId)
56
+ })
57
+
58
+ test('a throwing listener neither fails the sign-in nor silences the next one', async () => {
59
+ const ctx = makeCtx({ events: true })
60
+ const reached: string[] = []
61
+ eventsOf(ctx).onEntityCreated(async () => { throw new Error('provisioning is down') })
62
+ eventsOf(ctx).onEntityCreated(async event => { reached.push(event.entityId) })
63
+
64
+ const payload = await linkingFor(ctx).linkProfile(
65
+ details('google-oauth', 'google-sub') as never, { username: 'person@example.org' }
66
+ )
67
+
68
+ expect(payload.profileId).toStartWith('google-oauth:')
69
+ expect(reached).toHaveLength(1)
70
+ })
71
+
72
+ test('without the service registered there is nothing to announce to', async () => {
73
+ const ctx = makeCtx()
74
+
75
+ expect(identityEvents(ctx as never)).toBeNull()
76
+ const payload = await linkingFor(ctx).linkProfile(
77
+ details('google-oauth', 'google-sub') as never, { username: 'person@example.org' }
78
+ )
79
+ expect(payload.profileId).toStartWith('google-oauth:')
80
+ })
81
+ })
@@ -1,12 +1,11 @@
1
1
  import { describe, expect, test } from 'bun:test'
2
2
  import { AuthRole } from '@owlmeans/auth'
3
3
  import { AuthenticationType } from '@owlmeans/auth'
4
- import { makeIdentityLinkingService } from '../src/service.js'
5
4
  import {
6
5
  AUTH_IDENTITY_ACCOUNT, AUTH_IDENTITY_CREDENTIALS, AUTH_IDENTITY_ORG_ENTITY,
7
6
  AUTH_IDENTITY_PROFILE,
8
7
  } from '../src/consts.js'
9
- import { ENTITY_RESOLVER } from '@owlmeans/auth-common'
8
+ import { details, linkingFor, makeCtx } from './context.js'
10
9
 
11
10
  /**
12
11
  * One human, one email, one platform profile — whichever way they sign in.
@@ -15,75 +14,7 @@ import { ENTITY_RESOLVER } from '@owlmeans/auth-common'
15
14
  * and registration is per METHOD. The same address signing in by Google and then by key ended up
16
15
  * in two entities that could not see each other's projects: `requireEntity` matched neither, and
17
16
  * ownership (`project.createdBy`) named a profile the other identity did not have.
18
- *
19
- * The rows are stubbed rather than mocked — the service's whole behaviour here is which record it
20
- * reads before it writes, so a stub that records writes is the subject, not a stand-in for it.
21
17
  */
22
- const stubResource = <T extends { id?: string }>(alias: string, seed: T[] = []) => {
23
- const items: T[] = [...seed]
24
- let next = seed.length + 1
25
-
26
- const matches = (record: any, where: any): boolean =>
27
- where == null || Object.entries(where).every(([key, value]) => record[key] === value)
28
-
29
- return {
30
- alias,
31
- items,
32
- list: async (where?: unknown) => ({ items: items.filter(item => matches(item, where)) }),
33
- load: async (where?: unknown) => items.find(item => matches(item, where)) ?? null,
34
- get: async (where?: unknown) => {
35
- const found = items.find(item => matches(item, where))
36
- if (found == null) throw new Error(`${alias}: not found`)
37
- return found
38
- },
39
- create: async (record: T) => {
40
- const stored = { ...record, id: record.id ?? `${alias}-${next++}` } as T
41
- items.push(stored)
42
- return stored
43
- },
44
- delete: async (id: string) => {
45
- const at = items.findIndex(item => item.id === id)
46
- if (at < 0) return null
47
- return items.splice(at, 1)[0]
48
- },
49
- registerContext: () => undefined,
50
- }
51
- }
52
-
53
- const makeCtx = (seed: {
54
- accounts?: any[], profiles?: any[], credentials?: any[]
55
- } = {}) => {
56
- const resources: Record<string, any> = {
57
- [AUTH_IDENTITY_ACCOUNT]: stubResource('account', seed.accounts),
58
- [AUTH_IDENTITY_PROFILE]: stubResource('profile', seed.profiles),
59
- [AUTH_IDENTITY_CREDENTIALS]: stubResource('credential', seed.credentials),
60
- [AUTH_IDENTITY_ORG_ENTITY]: stubResource('entity'),
61
- }
62
- let minted = 0
63
-
64
- return {
65
- resources,
66
- resource: (alias: string) => resources[alias],
67
- service: (alias: string) => {
68
- if (alias !== ENTITY_RESOLVER) throw new Error(`unexpected service ${alias}`)
69
- return {
70
- mintSlug: async () => `slug-${++minted}`,
71
- byId: async (id: string) => ({ id, slug: `slug-of-${id}` }),
72
- }
73
- },
74
- }
75
- }
76
-
77
- const details = (type: string, sub: string) => ({
78
- type, service: type, clientId: type, userId: sub, username: 'person@example.org',
79
- })
80
-
81
- const linkingFor = (ctx: unknown) => {
82
- const service = makeIdentityLinkingService()
83
- service.registerContext(ctx as never)
84
- return service
85
- }
86
-
87
18
  describe('linkProfile', () => {
88
19
  test('a first sign-in registers an organization, an account and a profile', async () => {
89
20
  const ctx = makeCtx()
package/tsconfig.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "extends": ["@owlmeans/dep-config/tsconfig.base.json", "@owlmeans/dep-config/tsconfig.server.json"],
2
+ "extends": ["@owlmeans/dep-config/tsconfig.base.json", "@owlmeans/dep-config/tsconfig.node.json"],
3
3
  "compilerOptions": {
4
4
  "rootDir": "./src",
5
5
  "outDir": "./build/"