@noodleseed/one 0.173.0 → 0.175.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.
Files changed (170) hide show
  1. package/dist/commands/solutions-activity.js +1 -1
  2. package/dist/commands/solutions-activity.js.map +1 -1
  3. package/dist/commands/solutions-drafts.d.ts.map +1 -1
  4. package/dist/commands/solutions-drafts.js +36 -9
  5. package/dist/commands/solutions-drafts.js.map +1 -1
  6. package/dist/commands/solutions-native-lifecycle.d.ts +5 -0
  7. package/dist/commands/solutions-native-lifecycle.d.ts.map +1 -0
  8. package/dist/commands/solutions-native-lifecycle.js +77 -0
  9. package/dist/commands/solutions-native-lifecycle.js.map +1 -0
  10. package/dist/commands/solutions-ops-args.d.ts +42 -0
  11. package/dist/commands/solutions-ops-args.d.ts.map +1 -0
  12. package/dist/commands/solutions-ops-args.js +47 -0
  13. package/dist/commands/solutions-ops-args.js.map +1 -0
  14. package/dist/commands/solutions-ops.d.ts.map +1 -1
  15. package/dist/commands/solutions-ops.js +9 -46
  16. package/dist/commands/solutions-ops.js.map +1 -1
  17. package/dist/commands/solutions-workspace.d.ts +5 -0
  18. package/dist/commands/solutions-workspace.d.ts.map +1 -0
  19. package/dist/commands/solutions-workspace.js +157 -0
  20. package/dist/commands/solutions-workspace.js.map +1 -0
  21. package/dist/commands/whatsapp-output.d.ts.map +1 -1
  22. package/dist/commands/whatsapp-output.js +20 -4
  23. package/dist/commands/whatsapp-output.js.map +1 -1
  24. package/node_modules/@noodle-borg/admission-limits/dist/public-record-admission.d.ts +16 -9
  25. package/node_modules/@noodle-borg/admission-limits/dist/public-record-admission.js +5 -2
  26. package/node_modules/@noodle-borg/agent-kit/dist/curated/error-fixes.js +9 -0
  27. package/node_modules/@noodle-borg/agent-kit/dist/generated/example-files.js +5 -5
  28. package/node_modules/@noodle-borg/agent-kit/dist/generated/surface.js +9 -0
  29. package/node_modules/@noodle-borg/agent-kit/dist/skill-authoring-refs.js +1 -1
  30. package/node_modules/@noodle-borg/agent-kit/dist/skill-embedded-assistant-ref.js +13 -1
  31. package/node_modules/@noodle-borg/agent-kit/package.json +1 -1
  32. package/node_modules/@noodle-borg/assistant-gateway/dist/channel-coordinator.d.ts +5 -3
  33. package/node_modules/@noodle-borg/assistant-gateway/dist/channel-coordinator.js +5 -4
  34. package/node_modules/@noodle-borg/assistant-gateway/dist/channel-inbox.js +6 -2
  35. package/node_modules/@noodle-borg/assistant-gateway/dist/channel-store.d.ts +1 -1
  36. package/node_modules/@noodle-borg/assistant-gateway/dist/channel-types.d.ts +12 -0
  37. package/node_modules/@noodle-borg/assistant-gateway/dist/channel-work.d.ts +7 -2
  38. package/node_modules/@noodle-borg/assistant-gateway/dist/channel-work.js +14 -4
  39. package/node_modules/@noodle-borg/assistant-gateway/dist/collection-capture.js +104 -0
  40. package/node_modules/@noodle-borg/assistant-gateway/dist/collection-judgment.js +93 -0
  41. package/node_modules/@noodle-borg/assistant-gateway/dist/collection-ledger.d.ts +105 -0
  42. package/node_modules/@noodle-borg/assistant-gateway/dist/collection-ledger.js +183 -0
  43. package/node_modules/@noodle-borg/assistant-gateway/dist/collection-model-call.js +38 -0
  44. package/node_modules/@noodle-borg/assistant-gateway/dist/collection-parsers.d.ts +22 -0
  45. package/node_modules/@noodle-borg/assistant-gateway/dist/collection-parsers.js +109 -0
  46. package/node_modules/@noodle-borg/assistant-gateway/dist/collection-review.d.ts +21 -0
  47. package/node_modules/@noodle-borg/assistant-gateway/dist/collection-review.js +44 -0
  48. package/node_modules/@noodle-borg/assistant-gateway/dist/collection-spec.d.ts +18 -0
  49. package/node_modules/@noodle-borg/assistant-gateway/dist/collection-spec.js +86 -0
  50. package/node_modules/@noodle-borg/assistant-gateway/dist/collection-store.d.ts +11 -0
  51. package/node_modules/@noodle-borg/assistant-gateway/dist/collection-store.js +18 -0
  52. package/node_modules/@noodle-borg/assistant-gateway/dist/messaging-tool-dispatch.d.ts +20 -1
  53. package/node_modules/@noodle-borg/assistant-gateway/dist/messaging-tool-dispatch.js +38 -2
  54. package/node_modules/@noodle-borg/assistant-gateway/dist/model-runtime.js +3 -0
  55. package/node_modules/@noodle-borg/assistant-gateway/dist/portable.d.ts +5 -0
  56. package/node_modules/@noodle-borg/assistant-gateway/dist/portable.js +5 -0
  57. package/node_modules/@noodle-borg/authoring/dist/index.d.ts +1 -0
  58. package/node_modules/@noodle-borg/authoring/dist/interaction.d.ts +49 -0
  59. package/node_modules/@noodle-borg/authoring/dist/interaction.js +25 -0
  60. package/node_modules/@noodle-borg/authoring/dist/server.d.ts +3 -0
  61. package/node_modules/@noodle-borg/authoring/dist/server.js +4 -0
  62. package/node_modules/@noodle-borg/authoring/package.json +6 -1
  63. package/node_modules/@noodle-borg/cli-catalog/dist/catalog-data-channels.js +1 -1
  64. package/node_modules/@noodle-borg/cli-catalog/dist/catalog-data-solution-drafts.js +7 -0
  65. package/node_modules/@noodle-borg/cli-catalog/dist/catalog-data-solution-native-lifecycle.js +43 -0
  66. package/node_modules/@noodle-borg/cli-catalog/dist/catalog-data-solution-records.js +154 -0
  67. package/node_modules/@noodle-borg/cli-catalog/dist/catalog-data-solution-workspace.js +95 -0
  68. package/node_modules/@noodle-borg/cli-catalog/dist/catalog-data-solutions.js +4 -149
  69. package/node_modules/@noodle-borg/compiler/dist/artifact/assemble.js +2 -1
  70. package/node_modules/@noodle-borg/compiler/dist/artifact/types.d.ts +33 -0
  71. package/node_modules/@noodle-borg/compiler/dist/artifact/version.d.ts +2 -1
  72. package/node_modules/@noodle-borg/compiler/dist/artifact/version.js +2 -1
  73. package/node_modules/@noodle-borg/compiler/dist/compile.js +5 -0
  74. package/node_modules/@noodle-borg/compiler/dist/errors.d.ts +1 -1
  75. package/node_modules/@noodle-borg/compiler/dist/index.d.ts +2 -2
  76. package/node_modules/@noodle-borg/compiler/dist/index.js +1 -1
  77. package/node_modules/@noodle-borg/compiler/dist/manifest/interaction-schema.d.ts +41 -0
  78. package/node_modules/@noodle-borg/compiler/dist/manifest/interaction-schema.js +62 -0
  79. package/node_modules/@noodle-borg/compiler/dist/manifest/interaction-validation.js +220 -0
  80. package/node_modules/@noodle-borg/compiler/dist/manifest/schema.d.ts +60 -4
  81. package/node_modules/@noodle-borg/compiler/dist/manifest/schema.js +7 -1
  82. package/node_modules/@noodle-borg/compiler/dist/manifest/website-projection.d.ts +9 -1
  83. package/node_modules/@noodle-borg/compiler/dist/manifest/website-projection.js +58 -10
  84. package/node_modules/@noodle-borg/control-plane/dist/in-memory-atomic-state.d.ts +8 -0
  85. package/node_modules/@noodle-borg/control-plane/dist/in-memory-atomic-state.js +136 -0
  86. package/node_modules/@noodle-borg/control-plane/dist/in-memory-control-plane-store.d.ts +7 -0
  87. package/node_modules/@noodle-borg/control-plane/dist/in-memory-control-plane-store.js +16 -24
  88. package/node_modules/@noodle-borg/control-plane/dist/in-memory-organization-store.d.ts +4 -2
  89. package/node_modules/@noodle-borg/control-plane/dist/in-memory-organization-store.js +8 -6
  90. package/node_modules/@noodle-borg/control-plane/dist/mcp-subdomain-claims.d.ts +2 -1
  91. package/node_modules/@noodle-borg/control-plane/dist/mcp-subdomain-claims.js +13 -8
  92. package/node_modules/@noodle-borg/control-plane/dist/organization-agreements.d.ts +13 -4
  93. package/node_modules/@noodle-borg/control-plane/dist/organization-agreements.js +23 -7
  94. package/node_modules/@noodle-borg/control-plane/dist/portable.d.ts +2 -1
  95. package/node_modules/@noodle-borg/control-plane/dist/portable.js +1 -0
  96. package/node_modules/@noodle-borg/module/dist/platform-human-identity.d.ts +5 -2
  97. package/node_modules/@noodle-borg/runtime/dist/connector/types.d.ts +16 -4
  98. package/node_modules/@noodle-borg/runtime/dist/execute.d.ts +3 -6
  99. package/node_modules/@noodle-borg/runtime/dist/index.d.ts +1 -1
  100. package/node_modules/@noodle-borg/service/dist/application-activity.js +85 -63
  101. package/node_modules/@noodle-borg/service/dist/application-drafts/contracts.js +9 -0
  102. package/node_modules/@noodle-borg/service/dist/application-drafts/paths.js +2 -2
  103. package/node_modules/@noodle-borg/service/dist/application-runtime-target.js +1 -1
  104. package/node_modules/@noodle-borg/service/dist/business-information/contracts.d.ts +18 -4
  105. package/node_modules/@noodle-borg/service/dist/business-information/in-memory-business-pages.js +3 -5
  106. package/node_modules/@noodle-borg/service/dist/business-information/in-memory-installation-lifecycle.js +8 -6
  107. package/node_modules/@noodle-borg/service/dist/business-information/in-memory-native-lifecycle.js +80 -0
  108. package/node_modules/@noodle-borg/service/dist/business-information/in-memory-store.js +27 -31
  109. package/node_modules/@noodle-borg/service/dist/business-information/memory-native-retention.js +29 -0
  110. package/node_modules/@noodle-borg/service/dist/business-information/model.js +9 -2
  111. package/node_modules/@noodle-borg/service/dist/business-information/native-query.js +3 -1
  112. package/node_modules/@noodle-borg/service/dist/business-information/native-record-lifecycle.d.ts +27 -0
  113. package/node_modules/@noodle-borg/service/dist/business-information/native-record-lifecycle.js +63 -0
  114. package/node_modules/@noodle-borg/service/dist/business-information/principal-authority.d.ts +3 -1
  115. package/node_modules/@noodle-borg/service/dist/business-information/principal-authority.js +9 -4
  116. package/node_modules/@noodle-borg/service/dist/business-information/staff-authority.d.ts +16 -0
  117. package/node_modules/@noodle-borg/service/dist/business-information/staff-authority.js +60 -0
  118. package/node_modules/@noodle-borg/service/dist/business-information/workspace-permissions.js +18 -0
  119. package/node_modules/@noodle-borg/service/dist/business-information-runtime.js +1 -0
  120. package/node_modules/@noodle-borg/service/dist/business-onboarding.js +16 -3
  121. package/node_modules/@noodle-borg/service/dist/business-workspaces/contracts.d.ts +110 -0
  122. package/node_modules/@noodle-borg/service/dist/business-workspaces/contracts.js +52 -0
  123. package/node_modules/@noodle-borg/service/dist/business-workspaces/paths.js +17 -0
  124. package/node_modules/@noodle-borg/service/dist/business-workspaces/permissions.d.ts +7 -0
  125. package/node_modules/@noodle-borg/service/dist/business-workspaces/store.d.ts +102 -0
  126. package/node_modules/@noodle-borg/service/dist/channels/360dialog.js +70 -8
  127. package/node_modules/@noodle-borg/service/dist/channels/capability-report.js +73 -0
  128. package/node_modules/@noodle-borg/service/dist/channels/collection-turn.js +232 -0
  129. package/node_modules/@noodle-borg/service/dist/channels/composition.js +1 -0
  130. package/node_modules/@noodle-borg/service/dist/channels/messaging-eligibility.js +45 -0
  131. package/node_modules/@noodle-borg/service/dist/channels/reply-buttons.js +23 -0
  132. package/node_modules/@noodle-borg/service/dist/channels/runtime.js +127 -33
  133. package/node_modules/@noodle-borg/service/dist/native-record-connector.js +19 -4
  134. package/node_modules/@noodle-borg/service/dist/routes/application-drafts.js +44 -2
  135. package/node_modules/@noodle-borg/service/dist/routes/assistant-agent.js +4 -0
  136. package/node_modules/@noodle-borg/service/dist/routes/business-authoring-dispatch.js +23 -0
  137. package/node_modules/@noodle-borg/service/dist/routes/business-information-access.js +39 -0
  138. package/node_modules/@noodle-borg/service/dist/routes/business-information-activity.js +1 -1
  139. package/node_modules/@noodle-borg/service/dist/routes/business-information-channels.js +2 -2
  140. package/node_modules/@noodle-borg/service/dist/routes/business-information-connections.js +10 -4
  141. package/node_modules/@noodle-borg/service/dist/routes/business-information-dispatch.js +11 -6
  142. package/node_modules/@noodle-borg/service/dist/routes/business-information-installation.js +3 -1
  143. package/node_modules/@noodle-borg/service/dist/routes/business-information-notice.js +6 -2
  144. package/node_modules/@noodle-borg/service/dist/routes/business-information-pages.js +1 -1
  145. package/node_modules/@noodle-borg/service/dist/routes/business-information-paths.js +1 -1
  146. package/node_modules/@noodle-borg/service/dist/routes/business-information-record-create.js +7 -2
  147. package/node_modules/@noodle-borg/service/dist/routes/business-information-record-reads.js +2 -2
  148. package/node_modules/@noodle-borg/service/dist/routes/business-information-records.js +332 -0
  149. package/node_modules/@noodle-borg/service/dist/routes/business-information-settings.js +6 -3
  150. package/node_modules/@noodle-borg/service/dist/routes/business-information-staff.js +9 -5
  151. package/node_modules/@noodle-borg/service/dist/routes/business-information.js +12 -356
  152. package/node_modules/@noodle-borg/service/dist/routes/business-native-lifecycle.js +46 -0
  153. package/node_modules/@noodle-borg/service/dist/routes/business-workspaces.js +119 -0
  154. package/node_modules/@noodle-borg/service/dist/routes/service-probes.js +2 -1
  155. package/node_modules/@noodle-borg/service/dist/service.js +9 -2
  156. package/node_modules/@noodle-borg/service/dist/web-capabilities.js +3 -1
  157. package/node_modules/@noodle-borg/service/package.json +2 -1
  158. package/node_modules/@noodle-borg/wire-contracts/dist/application-draft-validation.d.ts +59 -0
  159. package/node_modules/@noodle-borg/wire-contracts/dist/application-draft-validation.js +38 -0
  160. package/node_modules/@noodle-borg/wire-contracts/dist/business-information.d.ts +144 -50
  161. package/node_modules/@noodle-borg/wire-contracts/dist/business-information.js +44 -4
  162. package/node_modules/@noodle-borg/wire-contracts/dist/business-workspaces.d.ts +258 -0
  163. package/node_modules/@noodle-borg/wire-contracts/dist/business-workspaces.js +118 -1
  164. package/node_modules/@noodle-borg/wire-contracts/dist/index.d.ts +2 -0
  165. package/node_modules/@noodle-borg/wire-contracts/dist/index.js +2 -0
  166. package/node_modules/@noodle-borg/wire-contracts/dist/native-record-lifecycle.d.ts +81 -0
  167. package/node_modules/@noodle-borg/wire-contracts/dist/native-record-lifecycle.js +39 -0
  168. package/node_modules/@noodle-borg/wire-contracts/dist/whatsapp.d.ts +26 -0
  169. package/node_modules/@noodle-borg/wire-contracts/dist/whatsapp.js +24 -1
  170. package/package.json +2 -2
@@ -0,0 +1,29 @@
1
+ import { cloneRecord, deletedRecord } from './model.js';
2
+ export function expireNativeMemoryRecord(store, key, now) {
3
+ const current = store.records.get(key);
4
+ if (current === undefined ||
5
+ current.deletedAt !== undefined ||
6
+ current.retentionExpiresAt === null ||
7
+ current.retentionExpiresAt > now.toISOString())
8
+ return current;
9
+ const erased = deletedRecord(current, 'system:retention', now, 'retention_expired');
10
+ store.commit(key, erased, 'retention_expired');
11
+ return erased;
12
+ }
13
+ /** Recheck after acquiring the record lock: a reviewed migration may have won since sweep selection. */
14
+ export function eraseNativeMemoryRecord(store, key, expectedRevision, actorSubject, reason, now) {
15
+ const current = reason === 'retention_expired'
16
+ ? store.records.get(key)
17
+ : expireNativeMemoryRecord(store, key, now);
18
+ if (current === undefined || current.deletedAt !== undefined)
19
+ return { ok: false, reason: 'not_found', currentRevision: current?.revision ?? 0 };
20
+ if (current.revision !== expectedRevision)
21
+ return { ok: false, reason: 'conflict', currentRevision: current.revision };
22
+ if (reason === 'retention_expired' &&
23
+ (current.retentionExpiresAt === null || current.retentionExpiresAt > now.toISOString()))
24
+ return { ok: false, reason: 'invalid_transition', currentRevision: current.revision };
25
+ const erased = deletedRecord(current, actorSubject, now, reason);
26
+ store.commit(key, erased, reason === 'customer_request' ? 'deleted' : 'retention_expired');
27
+ return { ok: true, record: cloneRecord(erased) };
28
+ }
29
+ //# sourceMappingURL=memory-native-retention.js.map
@@ -4,6 +4,7 @@ import { collectionControlEnabled, creationPayload, patchedPayload, } from './co
4
4
  import { collectionForStoredRecord, resolveManagedInstallation, } from './managed-releases.js';
5
5
  import { builtInDefinition } from './profiles.js';
6
6
  import { PayloadValidationError, validateEmail, validateManagedPayload, validateRetentionDays, validateRevision, validateScalar, validateScope, } from './validation.js';
7
+ import { workspacePermissionForBusinessOperation } from './workspace-permissions.js';
7
8
  const ROLE_PERMISSIONS = {
8
9
  administrator: [
9
10
  'installation:administer',
@@ -43,6 +44,10 @@ export function permissionsForBusinessRole(role) {
43
44
  return permissions;
44
45
  }
45
46
  export function businessGrantAllows(grant, permission) {
47
+ if (grant?.authorityVersion === 1) {
48
+ const mapped = workspacePermissionForBusinessOperation(permission);
49
+ return mapped !== undefined && grant.permissions.includes(mapped);
50
+ }
46
51
  return (grant !== undefined &&
47
52
  grant.revokedAt === undefined &&
48
53
  permissionsForBusinessRole(grant.role).includes(permission));
@@ -142,7 +147,9 @@ export function initialRecord(input) {
142
147
  ...(collection.behavior?.kind === 'request' ? { status: 'new' } : {}),
143
148
  origin: normalizeOrigin(input.origin),
144
149
  revision: 1,
145
- retentionExpiresAt: new Date(input.now.getTime() + input.installation.retentionDays * 24 * 60 * 60 * 1000).toISOString(),
150
+ retentionExpiresAt: input.installation.nativeRecordLifecycle === 'explicit_erasure'
151
+ ? null
152
+ : new Date(input.now.getTime() + input.installation.retentionDays * 24 * 60 * 60 * 1000).toISOString(),
146
153
  createdAt,
147
154
  createdBySubject: actor,
148
155
  updatedAt: createdAt,
@@ -315,7 +322,7 @@ export function validateExpectedRevision(value) {
315
322
  return validateRevision(value);
316
323
  }
317
324
  function normalizeOrigin(origin) {
318
- const kinds = ['embedded', 'mcp', 'portal', 'api', 'import'];
325
+ const kinds = ['embedded', 'mcp', 'portal', 'api', 'import', 'messaging'];
319
326
  if (!kinds.includes(origin.kind))
320
327
  throw new Error('unsupported managed request origin');
321
328
  return {
@@ -103,7 +103,9 @@ export function matchesNativeQueryMetadata(record, plan, now) {
103
103
  return (scopeKey(record.scope) === scopeKey(input.scope) &&
104
104
  record.collectionKey === input.collectionKey &&
105
105
  (input.includeDeleted === true || record.deletedAt === undefined) &&
106
- (record.deletedAt !== undefined || record.retentionExpiresAt > now.toISOString()) &&
106
+ (record.deletedAt !== undefined ||
107
+ record.retentionExpiresAt === null ||
108
+ record.retentionExpiresAt > now.toISOString()) &&
107
109
  (input.status === undefined || record.status === input.status) &&
108
110
  (input.assigneeSubject === undefined || record.assigneeSubject === input.assigneeSubject) &&
109
111
  record.createdAt <= plan.snapshotAt &&
@@ -0,0 +1,27 @@
1
+ import { type NativeRecordLifecyclePreview, type NativeRecordLifecycleResult } from '@noodle-borg/wire-contracts';
2
+ import type { InstallationScope, ManagedRequestRecord, SolutionInstallation } from './contracts.js';
3
+ export declare class NativeLifecycleError extends Error {
4
+ readonly code: 'lifecycle_denied' | 'lifecycle_conflict' | 'lifecycle_unavailable';
5
+ constructor(code: 'lifecycle_denied' | 'lifecycle_conflict' | 'lifecycle_unavailable');
6
+ }
7
+ export interface NativeRecordLifecycleStore {
8
+ preview(scope: InstallationScope, actor: string): Promise<NativeRecordLifecyclePreview>;
9
+ migrate(input: {
10
+ readonly scope: InstallationScope;
11
+ readonly actor: string;
12
+ readonly preview: NativeRecordLifecyclePreview;
13
+ }): Promise<NativeRecordLifecycleResult>;
14
+ }
15
+ export type LifecycleInventory = Pick<ManagedRequestRecord, 'collectionKey' | 'id' | 'revision' | 'retentionExpiresAt' | 'deletedAt'>;
16
+ export interface LifecycleReceipt {
17
+ readonly preview: NativeRecordLifecyclePreview;
18
+ readonly actor: string;
19
+ readonly result: NativeRecordLifecycleResult;
20
+ }
21
+ export declare const LIFECYCLE_REVIEW_MS: number;
22
+ export declare const LIFECYCLE_INVENTORY_LIMIT = 65536;
23
+ export declare function sameLifecycleReview(expected: NativeRecordLifecyclePreview, input: NativeRecordLifecyclePreview): boolean;
24
+ /** Digest is an optimistic review precondition, never a bearer authorization token. No payload reads. */
25
+ export declare function lifecyclePreview(installation: SolutionInstallation, records: readonly LifecycleInventory[], observedAt: string, now?: string): NativeRecordLifecyclePreview;
26
+ export declare function checkLifecycleReview(installation: SolutionInstallation, records: readonly LifecycleInventory[], input: NativeRecordLifecyclePreview, now: string): void;
27
+ //# sourceMappingURL=native-record-lifecycle.d.ts.map
@@ -0,0 +1,63 @@
1
+ import { createHash } from 'node:crypto';
2
+ import { NativeRecordLifecyclePreviewSchema, } from '@noodle-borg/wire-contracts';
3
+ import { scopeKey } from './pagination.js';
4
+ export class NativeLifecycleError extends Error {
5
+ code;
6
+ constructor(code) {
7
+ super(code);
8
+ this.code = code;
9
+ }
10
+ }
11
+ export const LIFECYCLE_REVIEW_MS = 5 * 60_000;
12
+ // A live record prepays a 16 KiB terminal reserve inside the 1 GiB custody ceiling.
13
+ export const LIFECYCLE_INVENTORY_LIMIT = 65_536;
14
+ export function sameLifecycleReview(expected, input) {
15
+ const parsed = NativeRecordLifecyclePreviewSchema.safeParse(input);
16
+ return (parsed.success &&
17
+ JSON.stringify(NativeRecordLifecyclePreviewSchema.parse(expected)) ===
18
+ JSON.stringify(parsed.data));
19
+ }
20
+ /** Digest is an optimistic review precondition, never a bearer authorization token. No payload reads. */
21
+ export function lifecyclePreview(installation, records, observedAt, now = observedAt) {
22
+ if (records.length > LIFECYCLE_INVENTORY_LIMIT)
23
+ throw new NativeLifecycleError('lifecycle_unavailable');
24
+ const sorted = [...records].sort((a, b) => {
25
+ const left = `${a.collectionKey}\0${a.id}`, right = `${b.collectionKey}\0${b.id}`;
26
+ return left < right ? -1 : left > right ? 1 : 0;
27
+ });
28
+ const rows = sorted.map((r) => [
29
+ r.collectionKey,
30
+ r.id,
31
+ r.revision,
32
+ r.retentionExpiresAt,
33
+ r.deletedAt ?? null,
34
+ r.retentionExpiresAt !== null && r.retentionExpiresAt <= now,
35
+ ]);
36
+ const values = {
37
+ policy: installation.nativeRecordLifecycle ?? 'legacy_expiry',
38
+ installationRevision: installation.revision,
39
+ observedAt,
40
+ recordsToPreserve: records.filter((r) => !r.deletedAt && r.retentionExpiresAt !== null && r.retentionExpiresAt > now).length,
41
+ expiredRecords: records.filter((r) => !r.deletedAt && r.retentionExpiresAt !== null && r.retentionExpiresAt <= now).length,
42
+ };
43
+ return NativeRecordLifecyclePreviewSchema.parse({
44
+ ...values,
45
+ digest: createHash('sha256')
46
+ .update(JSON.stringify([scopeKey(installation.scope), values, rows]))
47
+ .digest('hex'),
48
+ });
49
+ }
50
+ export function checkLifecycleReview(installation, records, input, now) {
51
+ const parsed = NativeRecordLifecyclePreviewSchema.safeParse(input);
52
+ if (!parsed.success)
53
+ throw new NativeLifecycleError('lifecycle_conflict');
54
+ const age = Date.parse(now) - Date.parse(input.observedAt);
55
+ if (!Number.isFinite(age) ||
56
+ age < 0 ||
57
+ age > LIFECYCLE_REVIEW_MS ||
58
+ JSON.stringify(lifecyclePreview(installation, records, input.observedAt, now)) !==
59
+ JSON.stringify(parsed.data) ||
60
+ input.policy !== 'legacy_expiry')
61
+ throw new NativeLifecycleError('lifecycle_conflict');
62
+ }
63
+ //# sourceMappingURL=native-record-lifecycle.js.map
@@ -5,7 +5,9 @@ export type BusinessPrincipalProvider = Pick<PlatformHumanIdentityContribution,
5
5
  export declare class BusinessPrincipalAuthority {
6
6
  #private;
7
7
  configure(provider: BusinessPrincipalProvider | undefined): void;
8
- allows(subject: string, transaction?: ModuleSqlTransaction): Promise<boolean>;
8
+ allows(subject: string, transaction?: ModuleSqlTransaction, options?: {
9
+ readonly requireKnown?: true;
10
+ }): Promise<boolean>;
9
11
  eligible(grants: readonly BusinessGrant[]): Promise<readonly BusinessGrant[]>;
10
12
  }
11
13
  //# sourceMappingURL=principal-authority.d.ts.map
@@ -5,18 +5,23 @@ export class BusinessPrincipalAuthority {
5
5
  configure(provider) {
6
6
  this.#provider = provider;
7
7
  }
8
- async allows(subject, transaction) {
8
+ async allows(subject, transaction, options = {}) {
9
9
  const provider = this.#provider;
10
10
  if (provider === undefined)
11
- return true;
11
+ return options.requireKnown !== true;
12
12
  try {
13
- if (transaction === undefined)
13
+ if (transaction === undefined) {
14
+ if (options.requireKnown)
15
+ return (await provider.principalResolver.resolveExisting(subject))?.subject === subject;
14
16
  await provider.principalResolver.assertActive(subject);
17
+ }
15
18
  else {
16
19
  if (provider.assertActivePrincipal === undefined) {
17
20
  throw new Error('Business assignment requires transactional principal authority');
18
21
  }
19
- await provider.assertActivePrincipal(transaction, subject);
22
+ const checked = await provider.assertActivePrincipal(transaction, subject);
23
+ if (options.requireKnown)
24
+ return checked?.known === true;
20
25
  }
21
26
  return true;
22
27
  }
@@ -0,0 +1,16 @@
1
+ import type { EligibleBusinessAssignee } from '@noodle-borg/wire-contracts';
2
+ import type { BusinessWorkspaceStore } from '../business-workspaces/store.js';
3
+ import type { BusinessGrant, BusinessPermission, BusinessStaffGrant, InstallationScope } from './contracts.js';
4
+ /** One version selector shared by HTTP reads and transaction-bound native store effects. */
5
+ export declare class BusinessStaffAuthority {
6
+ #private;
7
+ private readonly getLegacyGrant;
8
+ constructor(getLegacyGrant: (scope: InstallationScope, subject: string) => Promise<BusinessGrant | undefined>);
9
+ configure(workspaces: BusinessWorkspaceStore | undefined): void;
10
+ resolve(scope: InstallationScope, subject: string): Promise<BusinessStaffGrant | undefined>;
11
+ allows(scope: InstallationScope, subject: string, permission: BusinessPermission): Promise<boolean>;
12
+ eligibleAssignees(scope: InstallationScope, actor: string, legacy: () => Promise<readonly BusinessGrant[]>): Promise<readonly EligibleBusinessAssignee[]>;
13
+ /** Local effects only. The caller emits responses after this transaction has committed. */
14
+ run<T>(scope: InstallationScope, actor: string, permission: BusinessPermission, operation: () => Promise<T>, forbidden?: () => Error): Promise<T>;
15
+ }
16
+ //# sourceMappingURL=staff-authority.d.ts.map
@@ -0,0 +1,60 @@
1
+ import { BusinessWorkspaceError } from '../business-workspaces/contracts.js';
2
+ import { businessGrantAllows } from './model.js';
3
+ import { workspacePermissionForBusinessOperation } from './workspace-permissions.js';
4
+ /** One version selector shared by HTTP reads and transaction-bound native store effects. */
5
+ export class BusinessStaffAuthority {
6
+ getLegacyGrant;
7
+ #workspaces;
8
+ constructor(getLegacyGrant) {
9
+ this.getLegacyGrant = getLegacyGrant;
10
+ }
11
+ configure(workspaces) {
12
+ this.#workspaces = workspaces;
13
+ }
14
+ async resolve(scope, subject) {
15
+ try {
16
+ const access = await this.#workspaces?.resolveAccess(scope.org, subject);
17
+ if (access)
18
+ return { ...access, scope };
19
+ return this.getLegacyGrant(scope, subject);
20
+ }
21
+ catch (error) {
22
+ if (error instanceof BusinessWorkspaceError && error.code === 'forbidden')
23
+ return undefined;
24
+ throw error;
25
+ }
26
+ }
27
+ async allows(scope, subject, permission) {
28
+ return businessGrantAllows(await this.resolve(scope, subject), permission);
29
+ }
30
+ async eligibleAssignees(scope, actor, legacy) {
31
+ const current = await this.#workspaces?.listEligibleAssignees(scope.org, actor);
32
+ if (current)
33
+ return current;
34
+ const result = [];
35
+ for (const grant of await legacy()) {
36
+ if (grant.email && !grant.revokedAt && grant.role !== 'viewer')
37
+ result.push({ subject: grant.subject, role: grant.role, email: grant.email });
38
+ }
39
+ return result;
40
+ }
41
+ /** Local effects only. The caller emits responses after this transaction has committed. */
42
+ async run(scope, actor, permission, operation, forbidden) {
43
+ const legacy = async () => {
44
+ if (!businessGrantAllows(await this.getLegacyGrant(scope, actor), permission))
45
+ throw new BusinessWorkspaceError('forbidden');
46
+ return operation();
47
+ };
48
+ try {
49
+ if (!this.#workspaces)
50
+ return await legacy();
51
+ return await this.#workspaces.runAuthorized(scope.org, actor, workspacePermissionForBusinessOperation(permission) ?? null, operation, legacy);
52
+ }
53
+ catch (error) {
54
+ if (forbidden && error instanceof BusinessWorkspaceError && error.code === 'forbidden')
55
+ throw forbidden();
56
+ throw error;
57
+ }
58
+ }
59
+ }
60
+ //# sourceMappingURL=staff-authority.js.map
@@ -0,0 +1,18 @@
1
+ /** Legacy operation vocabulary mapped to the one workspace matrix, not a second role matrix. */
2
+ const operations = {
3
+ 'installation:administer': 'settings:manage',
4
+ // Workspace team APIs own versioned membership; old installation grants cannot mutate it.
5
+ 'grants:manage': undefined,
6
+ 'records:create': 'records:write',
7
+ 'records:read': 'records:read',
8
+ 'records:update': 'records:write',
9
+ 'records:assign': 'records:write',
10
+ 'records:status': 'records:write',
11
+ 'records:note': 'records:write',
12
+ 'records:delete': 'records:erase',
13
+ 'records:export': 'records:export',
14
+ };
15
+ export function workspacePermissionForBusinessOperation(permission) {
16
+ return operations[permission];
17
+ }
18
+ //# sourceMappingURL=workspace-permissions.js.map
@@ -9,6 +9,7 @@ export function createBusinessInformationRuntime(registry, options, publicCounte
9
9
  (options.businessInformationEnabled === false
10
10
  ? undefined
11
11
  : new InMemoryBusinessInformationStore());
12
+ businessInformationStore?.staff.configure(options.businessAuthoring?.workspaces);
12
13
  if (businessInformationStore)
13
14
  registry.setApplicationLifecycleObserver((org, app, at, retired) => businessInformationStore.pauseApplication(org, app, at, retired));
14
15
  if (businessInformationStore instanceof InMemoryBusinessInformationStore) {
@@ -18,14 +18,22 @@ export function parseBusinessOnboarding(serialized) {
18
18
  export class BusinessOnboarding {
19
19
  organizations;
20
20
  installations;
21
+ workspaces;
21
22
  #documents;
22
- constructor(options, organizations, installations) {
23
+ constructor(options, organizations, installations, workspaces) {
23
24
  this.organizations = organizations;
24
25
  this.installations = installations;
26
+ this.workspaces = workspaces;
25
27
  this.#documents = options.documents ? validateAgreementDocuments(options.documents) : undefined;
26
28
  }
27
29
  async status(org, subject) {
28
- const canAccept = (await this.organizations.getOrgMember({ org, subject }))?.role === 'owner';
30
+ const legacy = async () => this.readStatus(org, (await this.organizations.getOrgMember({ org, subject }))?.role === 'owner');
31
+ const workspaces = this.workspaces;
32
+ if (!workspaces)
33
+ return legacy();
34
+ return workspaces.runAuthorized(org, subject, 'settings:manage', async () => this.readStatus(org, (await workspaces.authorize(org, subject, 'owners:manage')) === 'allowed'), legacy);
35
+ }
36
+ async readStatus(org, canAccept) {
29
37
  const documents = this.#documents;
30
38
  if (!documents)
31
39
  return { canAccept, accepted: false, required: null };
@@ -58,7 +66,12 @@ export class BusinessOnboarding {
58
66
  const documents = this.#documents;
59
67
  if (!documents)
60
68
  throw new BusinessSetupError();
61
- await this.organizations.acceptOrganizationAgreement({ org, actorSubject: subject, documents });
69
+ const workspaces = this.workspaces;
70
+ await this.organizations.acceptOrganizationAgreement({ org, actorSubject: subject, documents }, workspaces
71
+ ? {
72
+ run: (selectedOrg, actor, commit, legacy) => workspaces.runAuthorized(selectedOrg, actor, 'owners:manage', commit, legacy),
73
+ }
74
+ : undefined);
62
75
  return this.status(org, subject);
63
76
  }
64
77
  async ready(installation) {
@@ -0,0 +1,110 @@
1
+ import type { ModuleSqlTransaction } from '@noodle-borg/module';
2
+ import { BusinessWorkspaceRoleSchema } from '@noodle-borg/wire-contracts';
3
+ import { z } from 'zod';
4
+ import type { WorkspacePermission } from './permissions.js';
5
+ export interface BusinessWorkspaceAccess {
6
+ readonly authorityVersion: 1;
7
+ readonly revision: number;
8
+ readonly subject: string;
9
+ readonly role: z.infer<typeof BusinessWorkspaceRoleSchema>;
10
+ readonly permissions: readonly WorkspacePermission[];
11
+ }
12
+ export declare const WorkspaceSubjectSchema: z.ZodString;
13
+ export declare const WorkspaceOrgSchema: z.ZodString;
14
+ export declare const WorkspaceRevisionSchema: z.ZodNumber;
15
+ export declare const WorkspaceMemberSchema: z.ZodObject<{
16
+ subject: z.ZodString;
17
+ role: z.ZodEnum<{
18
+ operator: "operator";
19
+ owner: "owner";
20
+ viewer: "viewer";
21
+ administrator: "administrator";
22
+ builder: "builder";
23
+ }>;
24
+ joinedAt: z.ZodISODateTime;
25
+ }, z.core.$strict>;
26
+ declare const invitation: z.ZodObject<{
27
+ id: z.ZodString;
28
+ email: z.ZodEmail;
29
+ role: z.ZodEnum<{
30
+ operator: "operator";
31
+ owner: "owner";
32
+ viewer: "viewer";
33
+ administrator: "administrator";
34
+ builder: "builder";
35
+ }>;
36
+ tokenDigest: z.ZodString;
37
+ createdBy: z.ZodString;
38
+ createdAt: z.ZodISODateTime;
39
+ expiresAt: z.ZodISODateTime;
40
+ }, z.core.$strict>;
41
+ /** Internal encrypted state. Never serialize pending invitation material into a staff response. */
42
+ export declare const WorkspaceStateSchema: z.ZodObject<{
43
+ org: z.ZodString;
44
+ authorityVersion: z.ZodLiteral<1>;
45
+ revision: z.ZodNumber;
46
+ initializedBy: z.ZodString;
47
+ activatedAt: z.ZodISODateTime;
48
+ members: z.ZodArray<z.ZodObject<{
49
+ subject: z.ZodString;
50
+ role: z.ZodEnum<{
51
+ operator: "operator";
52
+ owner: "owner";
53
+ viewer: "viewer";
54
+ administrator: "administrator";
55
+ builder: "builder";
56
+ }>;
57
+ joinedAt: z.ZodISODateTime;
58
+ }, z.core.$strict>>;
59
+ invitations: z.ZodArray<z.ZodObject<{
60
+ id: z.ZodString;
61
+ email: z.ZodEmail;
62
+ role: z.ZodEnum<{
63
+ operator: "operator";
64
+ owner: "owner";
65
+ viewer: "viewer";
66
+ administrator: "administrator";
67
+ builder: "builder";
68
+ }>;
69
+ tokenDigest: z.ZodString;
70
+ createdBy: z.ZodString;
71
+ createdAt: z.ZodISODateTime;
72
+ expiresAt: z.ZodISODateTime;
73
+ }, z.core.$strict>>;
74
+ }, z.core.$strict>;
75
+ export type WorkspaceState = z.infer<typeof WorkspaceStateSchema>;
76
+ export type WorkspaceInvitation = z.infer<typeof invitation>;
77
+ export interface WorkspaceAuditEvent {
78
+ readonly revision: number;
79
+ readonly actor: string;
80
+ readonly action: 'initialized' | 'invited' | 'accepted' | 'role_changed' | 'removed' | 'invitation_revoked';
81
+ readonly target: string;
82
+ readonly at: string;
83
+ }
84
+ export interface BusinessWorkspaceTransaction {
85
+ readonly now: string;
86
+ /** Borrowed authority transaction for canonical principal checks; never acquire a second connection. */
87
+ readonly principalTransaction?: ModuleSqlTransaction;
88
+ get(): Promise<WorkspaceState | undefined>;
89
+ save(state: WorkspaceState, event: WorkspaceAuditEvent): Promise<void>;
90
+ }
91
+ export interface BusinessWorkspaceBackend {
92
+ /** Existing caller transaction only; reads must not acquire a second identity connection. */
93
+ principalTransaction?(): ModuleSqlTransaction | undefined;
94
+ /** Candidate lookup only; the encrypted workspace state remains permission authority. */
95
+ findMemberships(subject: string, input: {
96
+ readonly after?: string;
97
+ readonly limit: number;
98
+ }): Promise<readonly string[]>;
99
+ /** Snapshot read; inherits a caller's authority transaction when one is already active. */
100
+ read(org: string): Promise<WorkspaceState | undefined>;
101
+ /** Uses the same organization authority lock as draft writes and publication. */
102
+ run<T>(org: string, work: (tx: BusinessWorkspaceTransaction) => Promise<T>): Promise<T>;
103
+ }
104
+ export declare class BusinessWorkspaceError extends Error {
105
+ readonly code: 'invalid_request' | 'forbidden' | 'legacy_authority' | 'already_activated' | 'revision_conflict' | 'not_found' | 'last_owner' | 'invalid_invitation' | 'member_exists' | 'workspace_limit';
106
+ readonly currentRevision?: number | undefined;
107
+ constructor(code: 'invalid_request' | 'forbidden' | 'legacy_authority' | 'already_activated' | 'revision_conflict' | 'not_found' | 'last_owner' | 'invalid_invitation' | 'member_exists' | 'workspace_limit', currentRevision?: number | undefined);
108
+ }
109
+ export {};
110
+ //# sourceMappingURL=contracts.d.ts.map
@@ -0,0 +1,52 @@
1
+ import { SLUG_PATTERN, validateSlug } from '@noodle-borg/control-plane/portable';
2
+ import { BusinessWorkspaceRoleSchema } from '@noodle-borg/wire-contracts';
3
+ import { z } from 'zod';
4
+ export const WorkspaceSubjectSchema = z.string().min(1).max(500);
5
+ export const WorkspaceOrgSchema = z
6
+ .string()
7
+ .regex(SLUG_PATTERN)
8
+ .refine((value) => {
9
+ try {
10
+ validateSlug('org', value);
11
+ return true;
12
+ }
13
+ catch {
14
+ return false;
15
+ }
16
+ });
17
+ export const WorkspaceRevisionSchema = z.number().int().positive().max(2147483647);
18
+ export const WorkspaceMemberSchema = z.strictObject({
19
+ subject: WorkspaceSubjectSchema,
20
+ role: BusinessWorkspaceRoleSchema,
21
+ joinedAt: z.iso.datetime(),
22
+ });
23
+ const invitation = z.strictObject({
24
+ id: z.string().uuid(),
25
+ email: z.email().max(254),
26
+ role: BusinessWorkspaceRoleSchema,
27
+ tokenDigest: z.string().regex(/^[a-f0-9]{64}$/),
28
+ createdBy: WorkspaceSubjectSchema,
29
+ createdAt: z.iso.datetime(),
30
+ expiresAt: z.iso.datetime(),
31
+ });
32
+ /** Internal encrypted state. Never serialize pending invitation material into a staff response. */
33
+ export const WorkspaceStateSchema = z.strictObject({
34
+ org: WorkspaceOrgSchema,
35
+ authorityVersion: z.literal(1),
36
+ revision: WorkspaceRevisionSchema,
37
+ initializedBy: WorkspaceSubjectSchema,
38
+ activatedAt: z.iso.datetime(),
39
+ members: z.array(WorkspaceMemberSchema).min(1).max(1000),
40
+ invitations: z.array(invitation).max(100),
41
+ });
42
+ export class BusinessWorkspaceError extends Error {
43
+ code;
44
+ currentRevision;
45
+ constructor(code, currentRevision) {
46
+ super(code);
47
+ this.code = code;
48
+ this.currentRevision = currentRevision;
49
+ this.name = 'BusinessWorkspaceError';
50
+ }
51
+ }
52
+ //# sourceMappingURL=contracts.js.map
@@ -0,0 +1,17 @@
1
+ const root = /^\/v1\/orgs\/([a-z0-9][a-z0-9-]{0,62})\/business-workspace(?:\/(members|accept|invitations)(?:\/([a-f0-9-]{36}))?)?$/;
2
+ export function parseBusinessWorkspacePath(path) {
3
+ const match = root.exec(path);
4
+ if (!match?.[1] || (match[3] && match[2] !== 'invitations'))
5
+ return undefined;
6
+ return { org: match[1], action: match[2], id: match[3] };
7
+ }
8
+ export function businessWorkspaceMethod(ref) {
9
+ if (!ref.action)
10
+ return 'GET';
11
+ if (ref.action === 'members')
12
+ return 'PATCH';
13
+ if (ref.action === 'invitations' && ref.id)
14
+ return 'DELETE';
15
+ return 'POST';
16
+ }
17
+ //# sourceMappingURL=paths.js.map
@@ -0,0 +1,7 @@
1
+ import type { BusinessWorkspacePermissionSchema, BusinessWorkspaceRole } from '@noodle-borg/wire-contracts';
2
+ import type { z } from 'zod';
3
+ export type WorkspacePermission = z.infer<typeof BusinessWorkspacePermissionSchema>;
4
+ /** One fixed matrix, projected by clients; client-side visibility never supplies authorization. */
5
+ export declare const WORKSPACE_ROLE_PERMISSIONS: Readonly<Record<BusinessWorkspaceRole, readonly WorkspacePermission[]>>;
6
+ export declare function mayDelegate(actor: BusinessWorkspaceRole | undefined, target: BusinessWorkspaceRole): boolean;
7
+ //# sourceMappingURL=permissions.d.ts.map
@@ -0,0 +1,102 @@
1
+ import type { ModuleSqlTransaction } from '@noodle-borg/module';
2
+ import { BusinessWorkspaceRoleSchema, type EligibleBusinessAssignee } from '@noodle-borg/wire-contracts';
3
+ import { z } from 'zod';
4
+ import { type BusinessWorkspaceAccess, type BusinessWorkspaceBackend, type WorkspaceState } from './contracts.js';
5
+ import { type WorkspacePermission } from './permissions.js';
6
+ export interface BusinessWorkspaceStoreOptions {
7
+ /** Canonical identity authority, never an email claim or a caller-supplied boolean. */
8
+ readonly isIdentityActive: (subject: string, transaction?: ModuleSqlTransaction) => Promise<boolean>;
9
+ }
10
+ interface Mutation {
11
+ readonly org: string;
12
+ readonly actor: string;
13
+ readonly expectedRevision: number;
14
+ }
15
+ export declare class BusinessWorkspaceStore {
16
+ private readonly backend;
17
+ private readonly options;
18
+ constructor(backend: BusinessWorkspaceBackend, options: BusinessWorkspaceStoreOptions);
19
+ listForSubject(subject: string, query: unknown): Promise<{
20
+ nextCursor?: string;
21
+ workspaces: {
22
+ org: string;
23
+ authorityVersion: 1;
24
+ revision: number;
25
+ role: "operator" | "owner" | "viewer" | "administrator" | "builder";
26
+ permissions: readonly ("records:read" | "records:write" | "records:export" | "records:erase" | "drafts:read" | "drafts:edit" | "drafts:preview" | "applications:publish" | "settings:manage" | "team:manage" | "owners:manage" | "billing:manage" | "workspace:delete")[];
27
+ }[];
28
+ }>;
29
+ /** Internal new-organization composition only; legacy activation uses reviewed migration, never this method. */
30
+ initializeNewWorkspace(input: {
31
+ readonly org: string;
32
+ readonly ownerSubject: string;
33
+ }): Promise<WorkspaceState>;
34
+ /** A dispatch that mutates data must call this again inside its workspace authority transaction. */
35
+ authorize(org: string, subject: string, permission: WorkspacePermission): Promise<'legacy' | 'allowed' | 'denied'>;
36
+ /** Undefined means retained legacy authority, never a versioned workspace with a missing member. */
37
+ resolveAccess(org: string, subject: string): Promise<BusinessWorkspaceAccess | undefined>;
38
+ /** Minimal assignment choices; not a team directory or a second identity profile store. */
39
+ listEligibleAssignees(org: string, actor: string): Promise<readonly EligibleBusinessAssignee[] | undefined>;
40
+ /** Commit a local authoritative effect under the same lock/transaction as membership changes.
41
+ * The callback must use this backend's transaction-aware stores, never send an HTTP response or
42
+ * perform a remote side effect. External operations use their own dispatch/confirmation boundary.
43
+ */
44
+ runAuthorized<T>(org: string, actor: string, permission: WorkspacePermission | null, operation: () => Promise<T>, legacy?: () => Promise<T>): Promise<T>;
45
+ inspect(org: string, actor: string): Promise<{
46
+ org: string;
47
+ authorityVersion: 1;
48
+ revision: number;
49
+ activatedAt: string;
50
+ role: "operator" | "owner" | "viewer" | "administrator" | "builder";
51
+ permissions: readonly ("records:read" | "records:write" | "records:export" | "records:erase" | "drafts:read" | "drafts:edit" | "drafts:preview" | "applications:publish" | "settings:manage" | "team:manage" | "owners:manage" | "billing:manage" | "workspace:delete")[];
52
+ members: {
53
+ subject: string;
54
+ role: "operator" | "owner" | "viewer" | "administrator" | "builder";
55
+ joinedAt: string;
56
+ }[];
57
+ invitations: {
58
+ id: string;
59
+ email: string;
60
+ role: "operator" | "owner" | "viewer" | "administrator" | "builder";
61
+ createdBy: string;
62
+ createdAt: string;
63
+ expiresAt: string;
64
+ }[];
65
+ }>;
66
+ changeRole(input: Mutation & {
67
+ readonly subject: string;
68
+ readonly role: z.infer<typeof BusinessWorkspaceRoleSchema> | null;
69
+ }): Promise<{
70
+ revision: number;
71
+ }>;
72
+ invite(input: Mutation & {
73
+ readonly email: string;
74
+ readonly role?: z.infer<typeof BusinessWorkspaceRoleSchema>;
75
+ }): Promise<{
76
+ id: `${string}-${string}-${string}-${string}-${string}`;
77
+ role: "operator" | "owner" | "viewer" | "administrator" | "builder";
78
+ token: string;
79
+ expiresAt: string;
80
+ revision: number;
81
+ }>;
82
+ /** Caller supplies the authenticated canonical identity's verified email, never form input. */
83
+ accept(input: {
84
+ readonly org: string;
85
+ readonly subject: string;
86
+ readonly verifiedEmail: string;
87
+ readonly token: string;
88
+ }): Promise<{
89
+ revision: number;
90
+ }>;
91
+ revokeInvitation(input: Mutation & {
92
+ readonly invitationId: string;
93
+ }): Promise<{
94
+ revision: number;
95
+ }>;
96
+ private mutate;
97
+ private commit;
98
+ private requireState;
99
+ private requireActive;
100
+ }
101
+ export {};
102
+ //# sourceMappingURL=store.d.ts.map