@streamoid/settings 0.4.7 → 0.6.0

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/dist/index.d.mts CHANGED
@@ -233,21 +233,46 @@ interface SettingsWorkspaceAdapter {
233
233
  /** Toggle this workspace's `orgVisibility` within its parent org. */
234
234
  setOrgVisibility?: (visibility: "private" | "shared") => Promise<void>;
235
235
  }
236
+ /**
237
+ * An organization membership role.
238
+ *
239
+ * `guest` is an outsider who accepted an invite to a single workspace inside
240
+ * the organization. They hold a membership row — so they show up in these
241
+ * responses — but inherit nothing from the org: no implicit access to its
242
+ * shared workspaces, and every org-level write is refused by the backend.
243
+ *
244
+ * Gate write affordances on `=== "admin"`, never on `!== "member"`: a role this
245
+ * union does not yet name must read as least-privileged, not as an editor.
246
+ *
247
+ * Deliberately NOT applied to `autoJoinRole` or to workspace/team roles — a
248
+ * domain claim that auto-joins its own company as guests is a contradiction,
249
+ * and a workspace role of "guest" is not a value the backend accepts.
250
+ */
251
+ type SettingsOrganizationRole = "admin" | "member" | "guest";
236
252
  interface SettingsOrganizationListItem {
237
253
  _id: string;
238
254
  name: string;
239
255
  imageUrl?: string;
240
- role?: "admin" | "member";
256
+ role?: SettingsOrganizationRole;
241
257
  }
242
258
  interface SettingsOrganizationCurrent {
243
259
  id: string;
244
260
  name?: string;
245
261
  imageUrl?: string;
246
- role?: "admin" | "member" | string;
262
+ role?: SettingsOrganizationRole | string;
263
+ /**
264
+ * Whether the viewer may invite into this organization.
265
+ *
266
+ * Orthogonal to `role`, not implied by it: a guest row can carry it too, so
267
+ * gate on `role !== "guest" && (role === "admin" || inviteAccess)`. The
268
+ * shorter `role === "admin" || inviteAccess` is the escalation the backend
269
+ * explicitly refuses.
270
+ */
271
+ inviteAccess?: boolean;
247
272
  }
248
273
  interface OrganizationMember {
249
274
  _id: string;
250
- role: "admin" | "member";
275
+ role: SettingsOrganizationRole;
251
276
  inviteAccess: boolean;
252
277
  /** Populated user. Rows whose user document was deleted come back from the
253
278
  * API with a null `user` — OrganizationContent drops those on fetch, so
@@ -357,9 +382,21 @@ interface SettingsOrganizationAdapter {
357
382
  role: "admin" | "member";
358
383
  inviteAccess?: boolean;
359
384
  }) => Promise<void>;
360
- /** Optional: gates write affordances inside the Organization tab. */
385
+ /** Optional: gates write affordances inside the Organization tab. Can report
386
+ * "guest", so callers must gate on `=== "admin"` rather than `!== "member"`. */
361
387
  getHighestRole?: () => Promise<{
362
- role: "admin" | "member";
388
+ role: SettingsOrganizationRole;
389
+ /**
390
+ * The viewer's own email domain, and whether it can be claimed at all.
391
+ *
392
+ * A self-serve domain claim can only ever be the claimer's OWN domain —
393
+ * there is no DNS verification, so the backend refuses any other — which
394
+ * makes one boolean about one known domain the entire answer. Server
395
+ * computed on purpose: the disposable-domain lists it consults are
396
+ * provisioned at runtime, so no bundled list could agree with it.
397
+ */
398
+ emailDomain?: string | null;
399
+ canClaimEmailDomain?: boolean;
363
400
  }>;
364
401
  fetchWorkspaces: () => Promise<OrganizationWorkspaceItem[]>;
365
402
  fetchJoinRequests: () => Promise<OrganizationJoinRequest[]>;
@@ -675,7 +712,18 @@ interface SettingsApiAdapter {
675
712
  /** Send an invitation to `email` with the given permissions. */
676
713
  inviteMember: (input: {
677
714
  email: string;
678
- } & MemberPermissionsPayload) => Promise<void>;
715
+ } & MemberPermissionsPayload & {
716
+ /**
717
+ * Standing in the workspace's ORGANIZATION, independent of `role`,
718
+ * which is the role inside the workspace. Omit for "no preference" —
719
+ * the backend then derives it from the invitee's email domain, which
720
+ * is what it has always done.
721
+ *
722
+ * Deliberately not on MemberPermissionsPayload: that type is shared
723
+ * with `updateMemberRole`, and org membership is not editable there.
724
+ */
725
+ organizationRole?: "member" | "guest";
726
+ }) => Promise<void>;
679
727
  /**
680
728
  * Canonical name for role updates. CXO's underlying service is named
681
729
  * `changeUserRole(workspaceId, payload)`; the adapter wraps that. Both
@@ -1135,7 +1183,36 @@ interface OrganizationInviteModalProps {
1135
1183
  mode: ModalMode$1;
1136
1184
  /** Update mode: the target member's email (read-only display). */
1137
1185
  userEmail?: string;
1186
+ /** admin/member only — the toggle below cannot express any other role, so
1187
+ * pass `lockRole` for a target whose role is outside that pair. */
1138
1188
  initialRole?: "admin" | "member";
1189
+ /**
1190
+ * Show the target's role read-only and disable Save, leaving Remove as the
1191
+ * only action.
1192
+ *
1193
+ * For an organization guest: the toggle offers Admin and Member and nothing
1194
+ * else, so opening it on a guest preselected "Member" and quietly promoted
1195
+ * them the moment Save was pressed — even by an admin who came only to flip
1196
+ * `inviteAccess`, which is itself the thing a guest must never hold. Removing
1197
+ * a guest happens through this same modal, so refusing to open it was not an
1198
+ * option.
1199
+ */
1200
+ lockRole?: boolean;
1201
+ /**
1202
+ * Whether the viewer's own email domain can be claimed at all. Defaults to
1203
+ * true, preserving today's behaviour for any host that does not pass it.
1204
+ *
1205
+ * A domain claim can only ever be the claimer's OWN domain — there is no DNS
1206
+ * verification, so the backend refuses any other — and a public provider
1207
+ * like gmail.com can never be claimed by anybody. Offering the tab in that
1208
+ * case advertises the one mechanism that would solve bulk onboarding and
1209
+ * then fails after submit, which is worse than not offering it.
1210
+ */
1211
+ canClaimDomain?: boolean;
1212
+ /** The viewer's own email domain: the only one they could ever claim. */
1213
+ claimableDomain?: string | null;
1214
+ /** Label for the read-only role shown when `lockRole` is set. */
1215
+ lockedRoleLabel?: string;
1139
1216
  initialInviteAccess?: boolean;
1140
1217
  /** Lets a pending-invite row reopen this modal to resend without edits. */
1141
1218
  allowSubmitWithoutChanges?: boolean;
@@ -1156,7 +1233,7 @@ interface OrganizationInviteModalProps {
1156
1233
  }) => void;
1157
1234
  onRemove?: () => void;
1158
1235
  }
1159
- declare function OrganizationInviteModal({ open, mode, userEmail, initialRole, initialInviteAccess, allowSubmitWithoutChanges, canRemove, onClose, onInviteEmail, onInviteDomain, onUpdate, onRemove, }: OrganizationInviteModalProps): react.JSX.Element | null;
1236
+ declare function OrganizationInviteModal({ open, mode, userEmail, initialRole, lockRole, canClaimDomain, claimableDomain, lockedRoleLabel, initialInviteAccess, allowSubmitWithoutChanges, canRemove, onClose, onInviteEmail, onInviteDomain, onUpdate, onRemove, }: OrganizationInviteModalProps): react.JSX.Element | null;
1160
1237
 
1161
1238
  interface ConfirmLeaveModalProps {
1162
1239
  open: boolean;
@@ -1191,6 +1268,12 @@ interface StoreOption {
1191
1268
  _id: string;
1192
1269
  name?: string;
1193
1270
  }
1271
+ /**
1272
+ * Standing in the workspace's parent organization, as distinct from `role`,
1273
+ * which is the role inside the workspace itself. The two are independent: an
1274
+ * external collaborator is routinely a workspace admin and an org guest.
1275
+ */
1276
+ type OrganizationStanding = "colleague" | "guest";
1194
1277
  interface InviteUpdateModalProps {
1195
1278
  open: boolean;
1196
1279
  mode: ModalMode;
@@ -1233,10 +1316,32 @@ interface InviteUpdateModalProps {
1233
1316
  onRemove?: () => void;
1234
1317
  /** Controls whether the Remove user button is enabled. Defaults to true. */
1235
1318
  canRemove?: boolean;
1236
- /** Called only in invite mode; receives (permissions, email) */
1237
- onInvite?: (permissions: UserPermissions, email: string) => void;
1319
+ /**
1320
+ * Offer the invitee an explicit standing in the workspace's parent
1321
+ * organization.
1322
+ *
1323
+ * Omit it and nothing renders and nothing is submitted — the backend keeps
1324
+ * deriving the standing from the invitee's email domain, which is today's
1325
+ * behaviour. Pass it only when the workspace HAS an organization and the
1326
+ * inviter may grant membership in it; showing the choice to someone who
1327
+ * cannot grant it produces an invite the backend quietly downgrades.
1328
+ */
1329
+ showOrganizationStanding?: boolean;
1330
+ /** Name of the parent organization, for the option copy. */
1331
+ organizationName?: string;
1332
+ /**
1333
+ * Hide the Guest option. For an invitee whose email domain the organization
1334
+ * already claims, guest is not expressible: the backend takes the higher of
1335
+ * the requested and domain-derived roles, so choosing it would appear to
1336
+ * work and change nothing.
1337
+ */
1338
+ allowGuestStanding?: boolean;
1339
+ /** Defaults to "guest" — the least-privileged of the two. */
1340
+ initialOrganizationStanding?: OrganizationStanding;
1341
+ /** Called only in invite mode; receives (permissions, email, standing) */
1342
+ onInvite?: (permissions: UserPermissions, email: string, organizationStanding?: OrganizationStanding) => void;
1238
1343
  }
1239
- declare function InviteUpdateModal({ open, mode, userEmail, stores, hiddenApps, allowSubmitWithoutChanges, initialPermissions, onClose, onSave, onRemove, canRemove, onInvite, }: InviteUpdateModalProps): react.JSX.Element | null;
1344
+ declare function InviteUpdateModal({ open, mode, userEmail, stores, hiddenApps, allowSubmitWithoutChanges, initialPermissions, onClose, onSave, onRemove, canRemove, showOrganizationStanding, organizationName, allowGuestStanding, initialOrganizationStanding, onInvite, }: InviteUpdateModalProps): react.JSX.Element | null;
1240
1345
 
1241
1346
  interface ExportDateModalProps {
1242
1347
  title: string;
package/dist/index.d.ts CHANGED
@@ -233,21 +233,46 @@ interface SettingsWorkspaceAdapter {
233
233
  /** Toggle this workspace's `orgVisibility` within its parent org. */
234
234
  setOrgVisibility?: (visibility: "private" | "shared") => Promise<void>;
235
235
  }
236
+ /**
237
+ * An organization membership role.
238
+ *
239
+ * `guest` is an outsider who accepted an invite to a single workspace inside
240
+ * the organization. They hold a membership row — so they show up in these
241
+ * responses — but inherit nothing from the org: no implicit access to its
242
+ * shared workspaces, and every org-level write is refused by the backend.
243
+ *
244
+ * Gate write affordances on `=== "admin"`, never on `!== "member"`: a role this
245
+ * union does not yet name must read as least-privileged, not as an editor.
246
+ *
247
+ * Deliberately NOT applied to `autoJoinRole` or to workspace/team roles — a
248
+ * domain claim that auto-joins its own company as guests is a contradiction,
249
+ * and a workspace role of "guest" is not a value the backend accepts.
250
+ */
251
+ type SettingsOrganizationRole = "admin" | "member" | "guest";
236
252
  interface SettingsOrganizationListItem {
237
253
  _id: string;
238
254
  name: string;
239
255
  imageUrl?: string;
240
- role?: "admin" | "member";
256
+ role?: SettingsOrganizationRole;
241
257
  }
242
258
  interface SettingsOrganizationCurrent {
243
259
  id: string;
244
260
  name?: string;
245
261
  imageUrl?: string;
246
- role?: "admin" | "member" | string;
262
+ role?: SettingsOrganizationRole | string;
263
+ /**
264
+ * Whether the viewer may invite into this organization.
265
+ *
266
+ * Orthogonal to `role`, not implied by it: a guest row can carry it too, so
267
+ * gate on `role !== "guest" && (role === "admin" || inviteAccess)`. The
268
+ * shorter `role === "admin" || inviteAccess` is the escalation the backend
269
+ * explicitly refuses.
270
+ */
271
+ inviteAccess?: boolean;
247
272
  }
248
273
  interface OrganizationMember {
249
274
  _id: string;
250
- role: "admin" | "member";
275
+ role: SettingsOrganizationRole;
251
276
  inviteAccess: boolean;
252
277
  /** Populated user. Rows whose user document was deleted come back from the
253
278
  * API with a null `user` — OrganizationContent drops those on fetch, so
@@ -357,9 +382,21 @@ interface SettingsOrganizationAdapter {
357
382
  role: "admin" | "member";
358
383
  inviteAccess?: boolean;
359
384
  }) => Promise<void>;
360
- /** Optional: gates write affordances inside the Organization tab. */
385
+ /** Optional: gates write affordances inside the Organization tab. Can report
386
+ * "guest", so callers must gate on `=== "admin"` rather than `!== "member"`. */
361
387
  getHighestRole?: () => Promise<{
362
- role: "admin" | "member";
388
+ role: SettingsOrganizationRole;
389
+ /**
390
+ * The viewer's own email domain, and whether it can be claimed at all.
391
+ *
392
+ * A self-serve domain claim can only ever be the claimer's OWN domain —
393
+ * there is no DNS verification, so the backend refuses any other — which
394
+ * makes one boolean about one known domain the entire answer. Server
395
+ * computed on purpose: the disposable-domain lists it consults are
396
+ * provisioned at runtime, so no bundled list could agree with it.
397
+ */
398
+ emailDomain?: string | null;
399
+ canClaimEmailDomain?: boolean;
363
400
  }>;
364
401
  fetchWorkspaces: () => Promise<OrganizationWorkspaceItem[]>;
365
402
  fetchJoinRequests: () => Promise<OrganizationJoinRequest[]>;
@@ -675,7 +712,18 @@ interface SettingsApiAdapter {
675
712
  /** Send an invitation to `email` with the given permissions. */
676
713
  inviteMember: (input: {
677
714
  email: string;
678
- } & MemberPermissionsPayload) => Promise<void>;
715
+ } & MemberPermissionsPayload & {
716
+ /**
717
+ * Standing in the workspace's ORGANIZATION, independent of `role`,
718
+ * which is the role inside the workspace. Omit for "no preference" —
719
+ * the backend then derives it from the invitee's email domain, which
720
+ * is what it has always done.
721
+ *
722
+ * Deliberately not on MemberPermissionsPayload: that type is shared
723
+ * with `updateMemberRole`, and org membership is not editable there.
724
+ */
725
+ organizationRole?: "member" | "guest";
726
+ }) => Promise<void>;
679
727
  /**
680
728
  * Canonical name for role updates. CXO's underlying service is named
681
729
  * `changeUserRole(workspaceId, payload)`; the adapter wraps that. Both
@@ -1135,7 +1183,36 @@ interface OrganizationInviteModalProps {
1135
1183
  mode: ModalMode$1;
1136
1184
  /** Update mode: the target member's email (read-only display). */
1137
1185
  userEmail?: string;
1186
+ /** admin/member only — the toggle below cannot express any other role, so
1187
+ * pass `lockRole` for a target whose role is outside that pair. */
1138
1188
  initialRole?: "admin" | "member";
1189
+ /**
1190
+ * Show the target's role read-only and disable Save, leaving Remove as the
1191
+ * only action.
1192
+ *
1193
+ * For an organization guest: the toggle offers Admin and Member and nothing
1194
+ * else, so opening it on a guest preselected "Member" and quietly promoted
1195
+ * them the moment Save was pressed — even by an admin who came only to flip
1196
+ * `inviteAccess`, which is itself the thing a guest must never hold. Removing
1197
+ * a guest happens through this same modal, so refusing to open it was not an
1198
+ * option.
1199
+ */
1200
+ lockRole?: boolean;
1201
+ /**
1202
+ * Whether the viewer's own email domain can be claimed at all. Defaults to
1203
+ * true, preserving today's behaviour for any host that does not pass it.
1204
+ *
1205
+ * A domain claim can only ever be the claimer's OWN domain — there is no DNS
1206
+ * verification, so the backend refuses any other — and a public provider
1207
+ * like gmail.com can never be claimed by anybody. Offering the tab in that
1208
+ * case advertises the one mechanism that would solve bulk onboarding and
1209
+ * then fails after submit, which is worse than not offering it.
1210
+ */
1211
+ canClaimDomain?: boolean;
1212
+ /** The viewer's own email domain: the only one they could ever claim. */
1213
+ claimableDomain?: string | null;
1214
+ /** Label for the read-only role shown when `lockRole` is set. */
1215
+ lockedRoleLabel?: string;
1139
1216
  initialInviteAccess?: boolean;
1140
1217
  /** Lets a pending-invite row reopen this modal to resend without edits. */
1141
1218
  allowSubmitWithoutChanges?: boolean;
@@ -1156,7 +1233,7 @@ interface OrganizationInviteModalProps {
1156
1233
  }) => void;
1157
1234
  onRemove?: () => void;
1158
1235
  }
1159
- declare function OrganizationInviteModal({ open, mode, userEmail, initialRole, initialInviteAccess, allowSubmitWithoutChanges, canRemove, onClose, onInviteEmail, onInviteDomain, onUpdate, onRemove, }: OrganizationInviteModalProps): react.JSX.Element | null;
1236
+ declare function OrganizationInviteModal({ open, mode, userEmail, initialRole, lockRole, canClaimDomain, claimableDomain, lockedRoleLabel, initialInviteAccess, allowSubmitWithoutChanges, canRemove, onClose, onInviteEmail, onInviteDomain, onUpdate, onRemove, }: OrganizationInviteModalProps): react.JSX.Element | null;
1160
1237
 
1161
1238
  interface ConfirmLeaveModalProps {
1162
1239
  open: boolean;
@@ -1191,6 +1268,12 @@ interface StoreOption {
1191
1268
  _id: string;
1192
1269
  name?: string;
1193
1270
  }
1271
+ /**
1272
+ * Standing in the workspace's parent organization, as distinct from `role`,
1273
+ * which is the role inside the workspace itself. The two are independent: an
1274
+ * external collaborator is routinely a workspace admin and an org guest.
1275
+ */
1276
+ type OrganizationStanding = "colleague" | "guest";
1194
1277
  interface InviteUpdateModalProps {
1195
1278
  open: boolean;
1196
1279
  mode: ModalMode;
@@ -1233,10 +1316,32 @@ interface InviteUpdateModalProps {
1233
1316
  onRemove?: () => void;
1234
1317
  /** Controls whether the Remove user button is enabled. Defaults to true. */
1235
1318
  canRemove?: boolean;
1236
- /** Called only in invite mode; receives (permissions, email) */
1237
- onInvite?: (permissions: UserPermissions, email: string) => void;
1319
+ /**
1320
+ * Offer the invitee an explicit standing in the workspace's parent
1321
+ * organization.
1322
+ *
1323
+ * Omit it and nothing renders and nothing is submitted — the backend keeps
1324
+ * deriving the standing from the invitee's email domain, which is today's
1325
+ * behaviour. Pass it only when the workspace HAS an organization and the
1326
+ * inviter may grant membership in it; showing the choice to someone who
1327
+ * cannot grant it produces an invite the backend quietly downgrades.
1328
+ */
1329
+ showOrganizationStanding?: boolean;
1330
+ /** Name of the parent organization, for the option copy. */
1331
+ organizationName?: string;
1332
+ /**
1333
+ * Hide the Guest option. For an invitee whose email domain the organization
1334
+ * already claims, guest is not expressible: the backend takes the higher of
1335
+ * the requested and domain-derived roles, so choosing it would appear to
1336
+ * work and change nothing.
1337
+ */
1338
+ allowGuestStanding?: boolean;
1339
+ /** Defaults to "guest" — the least-privileged of the two. */
1340
+ initialOrganizationStanding?: OrganizationStanding;
1341
+ /** Called only in invite mode; receives (permissions, email, standing) */
1342
+ onInvite?: (permissions: UserPermissions, email: string, organizationStanding?: OrganizationStanding) => void;
1238
1343
  }
1239
- declare function InviteUpdateModal({ open, mode, userEmail, stores, hiddenApps, allowSubmitWithoutChanges, initialPermissions, onClose, onSave, onRemove, canRemove, onInvite, }: InviteUpdateModalProps): react.JSX.Element | null;
1344
+ declare function InviteUpdateModal({ open, mode, userEmail, stores, hiddenApps, allowSubmitWithoutChanges, initialPermissions, onClose, onSave, onRemove, canRemove, showOrganizationStanding, organizationName, allowGuestStanding, initialOrganizationStanding, onInvite, }: InviteUpdateModalProps): react.JSX.Element | null;
1240
1345
 
1241
1346
  interface ExportDateModalProps {
1242
1347
  title: string;