@spotto/contract 1.0.69-alpha.25 → 1.0.69-alpha.27

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.
@@ -14,6 +14,34 @@ export declare type UnknownRoleAction<TRoleId = string> = {
14
14
  type: 'defaultRole';
15
15
  roleId: TRoleId;
16
16
  };
17
+ /**
18
+ * One row in the org's role-mapping list. At sign-in the IdP-emitted claim
19
+ * (captured into `custom:g2g_role` via the per-org Cognito IdP
20
+ * `AttributeMapping`) is normalised to `string[]` and walked against this
21
+ * list in order; the first entry whose `propertyValue` appears in the
22
+ * normalised values assigns its `roleId`.
23
+ *
24
+ * Generic over the identifier type so the same shape covers both the wire
25
+ * layer (string IDs) and the Mongo storage layer (ObjectId).
26
+ */
27
+ export interface RoleMapping<TId = string> {
28
+ _id: TId;
29
+ /**
30
+ * Value to look for in the IdP-emitted claim. Compared with `===` against
31
+ * each entry of the normalised `string[]` — case-sensitive, exact match.
32
+ */
33
+ propertyValue: string;
34
+ /** Spotto role to assign on match. */
35
+ roleId: TId;
36
+ }
37
+ /**
38
+ * Wire shape for creating / replacing mappings. `_id` is server-assigned on
39
+ * each write, so it's not part of the input.
40
+ */
41
+ export interface RoleMappingInput {
42
+ propertyValue: string;
43
+ roleId: string;
44
+ }
17
45
  export interface SsoEnabledBase<TRoleId = string> {
18
46
  enabled: true;
19
47
  /** Email domains owned by this org. One domain → one org (enforced at write time). */
@@ -26,6 +54,18 @@ export interface SsoEnabledBase<TRoleId = string> {
26
54
  inactivityTimeoutMinutes?: number;
27
55
  /** What to do when the role claim is missing or its value isn't a known Spotto role. */
28
56
  unknownRoleAction: UnknownRoleAction<TRoleId>;
57
+ /**
58
+ * IdP-side claim name that feeds the Cognito `custom:g2g_role` attribute.
59
+ * Pushed into the per-org Cognito IdP's `AttributeMapping` at onboard and
60
+ * any time it's updated. Examples: `g2g_role`, `roles`, `groups`, or a
61
+ * SAML AttributeName.
62
+ */
63
+ idpRoleClaim: string;
64
+ /**
65
+ * Org-scoped role-mapping list. Empty means every federated sign-in falls
66
+ * through to `unknownRoleAction`. See `RoleMapping`.
67
+ */
68
+ roleMappings: RoleMapping<TRoleId>[];
29
69
  }
30
70
  export interface SsoEnabledOidc<TRoleId = string> extends SsoEnabledBase<TRoleId> {
31
71
  mode: 'oidc';
@@ -4,3 +4,4 @@ export * from './idp-setup';
4
4
  export * from './onboard';
5
5
  export * from './offboard';
6
6
  export * from './revert';
7
+ export * from './sso-mappings';
package/dist/sso/index.js CHANGED
@@ -20,4 +20,5 @@ __exportStar(require("./idp-setup"), exports);
20
20
  __exportStar(require("./onboard"), exports);
21
21
  __exportStar(require("./offboard"), exports);
22
22
  __exportStar(require("./revert"), exports);
23
+ __exportStar(require("./sso-mappings"), exports);
23
24
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/sso/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,6CAA0B;AAC1B,wCAAqB;AACrB,8CAA2B;AAC3B,4CAAyB;AACzB,6CAA0B;AAC1B,2CAAwB"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/sso/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,6CAA0B;AAC1B,wCAAqB;AACrB,8CAA2B;AAC3B,4CAAyB;AACzB,6CAA0B;AAC1B,2CAAwB;AACxB,iDAA8B"}
@@ -1,3 +1,4 @@
1
+ import { RoleMappingInput } from '../../organisations/sso';
1
2
  /**
2
3
  * Wire shape for `POST /sso/orgs/:id/onboard`. Operator-supplied fields only.
3
4
  *
@@ -7,9 +8,10 @@
7
8
  * the org's `_id` (`buildSsoProviderName` → `sso-{orgId}`).
8
9
  * - `cognitoClientId` — orchestrator returns the Client ID it created.
9
10
  *
10
- * The IdP-side role claim name is also NOT a wire input: customers must
11
- * configure their IdP to emit a claim named `g2g_role`
12
- * (see `DEFAULT_IDP_ROLE_CLAIM`).
11
+ * `idpRoleClaim` IS a wire input it names the IdP claim that the per-org
12
+ * Cognito `AttributeMapping` should wire into `custom:g2g_role`. Customers
13
+ * pick whatever their IdP naturally emits (e.g. `roles`, `groups`); Spotto
14
+ * maps the captured values to roles via `roleMappings`.
13
15
  */
14
16
  interface OnboardSsoOrgWireBase {
15
17
  emailDomains: string[];
@@ -22,6 +24,13 @@ interface OnboardSsoOrgWireBase {
22
24
  };
23
25
  callbackUrls: string[];
24
26
  logoutUrls: string[];
27
+ idpRoleClaim: string;
28
+ /**
29
+ * Initial mappings. Optional — when absent or empty, every federated
30
+ * sign-in falls through to `unknownRoleAction` until the admin populates
31
+ * mappings via `PUT /sso/orgs/:id/sso-mappings`.
32
+ */
33
+ roleMappings?: RoleMappingInput[];
25
34
  }
26
35
  export interface OnboardSsoOrgOidcRequest extends OnboardSsoOrgWireBase {
27
36
  mode: 'oidc';
@@ -1,16 +1,3 @@
1
1
  "use strict";
2
- /**
3
- * Wire shape for `POST /sso/orgs/:id/onboard`. Operator-supplied fields only.
4
- *
5
- * Two persisted-shape fields are NOT wire inputs:
6
- *
7
- * - `cognitoProviderName` — orchestrator computes it deterministically from
8
- * the org's `_id` (`buildSsoProviderName` → `sso-{orgId}`).
9
- * - `cognitoClientId` — orchestrator returns the Client ID it created.
10
- *
11
- * The IdP-side role claim name is also NOT a wire input: customers must
12
- * configure their IdP to emit a claim named `g2g_role`
13
- * (see `DEFAULT_IDP_ROLE_CLAIM`).
14
- */
15
2
  Object.defineProperty(exports, "__esModule", { value: true });
16
3
  //# sourceMappingURL=request.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"request.js","sourceRoot":"","sources":["../../../src/sso/onboard/request.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;GAYG"}
1
+ {"version":3,"file":"request.js","sourceRoot":"","sources":["../../../src/sso/onboard/request.ts"],"names":[],"mappings":""}
@@ -0,0 +1,2 @@
1
+ export * from './request';
2
+ export * from './response';
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./request"), exports);
18
+ __exportStar(require("./response"), exports);
19
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/sso/sso-mappings/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,4CAAyB;AACzB,6CAA0B"}
@@ -0,0 +1,14 @@
1
+ import { RoleMappingInput } from '../../organisations/sso';
2
+ /**
3
+ * Wire shape for `PUT /sso/orgs/:id/sso-mappings`.
4
+ *
5
+ * Atomic full-replace of the org's role-mapping configuration. Sends both
6
+ * `idpRoleClaim` (which IdP claim feeds `custom:g2g_role`) and the whole
7
+ * `roleMappings` array. The orchestrator validates roleIds, pushes any
8
+ * `idpRoleClaim` change to Cognito via `UpdateIdentityProvider`, then
9
+ * persists. Mapping `_id` values are server-assigned on each write.
10
+ */
11
+ export interface UpdateSsoMappingsRequest {
12
+ idpRoleClaim: string;
13
+ roleMappings: RoleMappingInput[];
14
+ }
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=request.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"request.js","sourceRoot":"","sources":["../../../src/sso/sso-mappings/request.ts"],"names":[],"mappings":""}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Response shape for `PUT /sso/orgs/:id/sso-mappings`.
3
+ *
4
+ * Just a correlation id for stitching audit-log entries together. The FE
5
+ * re-fetches via `GET /sso/orgs/:id` to render the post-update state.
6
+ */
7
+ export interface UpdateSsoMappingsResponse {
8
+ correlationId: string;
9
+ }
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=response.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"response.js","sourceRoot":"","sources":["../../../src/sso/sso-mappings/response.ts"],"names":[],"mappings":""}
@@ -18,5 +18,18 @@ export interface GetInternalUserResponse extends BaseGetUserResponse {
18
18
  type: 'INTERNAL';
19
19
  email: string;
20
20
  lastLogin?: number;
21
+ /**
22
+ * True while the user has an outstanding invite and has not yet set a
23
+ * password (no Cognito record). Cleared on `POST /users/invites/:token/accept`
24
+ * and absent for users created via the linking branch (existing Cognito
25
+ * record from another org membership).
26
+ */
27
+ invitePending?: boolean;
28
+ /**
29
+ * Present-and-`'sso'` for users currently authenticated via SSO; absent for
30
+ * native (password / invite) users. Lets the admin UI distinguish SSO
31
+ * users without having to join against `organisation.sso.enabled`.
32
+ */
33
+ authProvider?: 'sso';
21
34
  }
22
35
  export declare type GetUserResponse = GetExternalUserResponse | GetInternalUserResponse;
@@ -21,6 +21,13 @@ export interface CurrentUserResponse {
21
21
  homeLocationPath: string;
22
22
  meta?: IEntityMeta;
23
23
  systemSettings: System;
24
+ /**
25
+ * Present-and-`'sso'` if the current user is signed in via SSO; absent for
26
+ * native (password) users. Lets the FE conditionally drive things like the
27
+ * sign-out flow (RP-initiated logout vs. plain Cognito sign-out) without
28
+ * having to check `organisation.sso`.
29
+ */
30
+ authProvider?: 'sso';
24
31
  }
25
32
  export interface CurrentUserPublicResponse {
26
33
  id: string;
@@ -3,3 +3,4 @@ export * from './current';
3
3
  export * from './post';
4
4
  export * from './get';
5
5
  export * from './[id]';
6
+ export * from './invites';
@@ -19,4 +19,5 @@ __exportStar(require("./current"), exports);
19
19
  __exportStar(require("./post"), exports);
20
20
  __exportStar(require("./get"), exports);
21
21
  __exportStar(require("./[id]"), exports);
22
+ __exportStar(require("./invites"), exports);
22
23
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/users/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,8CAA2B;AAC3B,4CAAyB;AACzB,yCAAsB;AACtB,wCAAqB;AACrB,yCAAsB"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/users/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,8CAA2B;AAC3B,4CAAyB;AACzB,yCAAsB;AACtB,wCAAqB;AACrB,yCAAsB;AACtB,4CAAyB"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Response shape for `GET /users/invites/:token`. Returns minimal context
3
+ * so the FE can render "You've been invited to join <Org>" before the user
4
+ * sets their password. 404 is returned for not-found / expired / consumed
5
+ * (same response for all three to avoid enumeration).
6
+ */
7
+ export interface GetInviteResponse {
8
+ email: string;
9
+ organisationName: string;
10
+ }
11
+ export interface AcceptInviteRequest {
12
+ password: string;
13
+ }
14
+ /**
15
+ * Response shape for `POST /users/invites/:token/accept`. Empty body — a
16
+ * 200 means the Cognito user has been created and the password is set;
17
+ * the FE can redirect to login.
18
+ */
19
+ export declare type AcceptInviteResponse = Record<string, never>;
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=invites.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"invites.js","sourceRoot":"","sources":["../../src/users/invites.ts"],"names":[],"mappings":""}
@@ -10,6 +10,5 @@ export interface PostExternalUserRequest extends BasePostUserRequest {
10
10
  export interface PostInternalUserRequest extends BasePostUserRequest {
11
11
  type: 'INTERNAL';
12
12
  email: string;
13
- password?: string;
14
13
  }
15
14
  export declare type PostUserRequest = PostExternalUserRequest | PostInternalUserRequest;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@spotto/contract",
3
3
  "license": "ISC",
4
- "version": "1.0.69-alpha.25",
4
+ "version": "1.0.69-alpha.27",
5
5
  "description": "Spotto's API Contract type definitions",
6
6
  "main": "./dist/index.js",
7
7
  "files": [
@@ -18,5 +18,5 @@
18
18
  "@types/geojson": "^7946.0.11",
19
19
  "shx": "^0.3.4"
20
20
  },
21
- "gitHead": "2ab8570d50d19b2f98dc4da3708762a2d40eb66a"
21
+ "gitHead": "c8b22d77af2952f711eb68c129f7007b8c61e4af"
22
22
  }