@finueva/auth 0.29.0 → 0.31.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/README.md CHANGED
@@ -446,6 +446,7 @@ Long-form task guides are maintained with the Auth source:
446
446
  - [CLI and native applications](https://github.com/Ifkafin/auth/blob/main/apps/developer/docs/sdk/device.md)
447
447
  - [Social ID-token sign-in](https://github.com/Ifkafin/auth/blob/main/apps/developer/docs/sdk/social-sign-in.md)
448
448
  - [Organizations and invitations](https://github.com/Ifkafin/auth/blob/main/apps/developer/docs/sdk/organizations.md)
449
+ - [Organization admission](https://github.com/Ifkafin/auth/blob/main/apps/developer/docs/sdk/organization-admission.md)
449
450
  - [Drive credentials](https://github.com/Ifkafin/auth/blob/main/apps/developer/docs/sdk/drive-credentials.md)
450
451
  - [Errors and recovery](https://github.com/Ifkafin/auth/blob/main/apps/developer/docs/sdk/errors-and-recovery.md)
451
452
 
@@ -454,3 +455,7 @@ These links track current source and can describe a newer SDK version. Check the
454
455
  ### Organization presence authorization candidate
455
456
 
456
457
  The request-scoped server method `authorizeOrganizationPresence(organizationId, { applicationId, userIds }, serviceAssertion, { applicationCredential })` forwards fresh actor, application and registered service proofs. The exact ordered selection contains 1 to 50 Auth User IDs. The supplied application credential remains untrusted proof. Auth checks its signature and exact current actor session. The result binds the actor, organization, application and selected IDs; its observation time is not an authority lease. Your application must enforce its own disclosure and visibility policies. Browser and device clients have no direct service facade. This source candidate requires release and registration qualification before use.
458
+
459
+ ### Organization admission candidate
460
+
461
+ Import `createOrganizationAdmissionAuth`, `createOrganizationAdmissionBillingAuth`, and `createOrganizationAdmissionDirectoryAuth` from `@finueva/auth/server`. These separate clients expose actor setup operations, private billing attestations, and the pending setup directory. Actor operations require a current incoming request and a separate service assertion. Use `organizationAdmissionBodyDigest(operation, input)` and the client's `audience(operation)` when signing each fresh assertion. A pending setup grants no organization membership or Drive authority. This source candidate requires release and hosted qualification before use.
package/dist/server.d.ts CHANGED
@@ -28,6 +28,190 @@ interface FinuevaOrganizationDirectoryAuth {
28
28
  /** Server-only directory. A directory entry identifies an incarnation; it grants no membership or billing authority. */
29
29
  declare function createOrganizationDirectoryAuth(options: OrganizationDirectoryAuthOptions): FinuevaOrganizationDirectoryAuth;
30
30
  //#endregion
31
+ //#region src/organization-admission/types.d.ts
32
+ /** Hidden setup identity. This is not organization membership or admission authority. */
33
+ interface OrganizationAdmissionSetup {
34
+ setupId: string;
35
+ applicationId: string;
36
+ organizationId: string;
37
+ organizationGeneration: string;
38
+ kind: "new" | "existing";
39
+ status: "reserved" | "activating" | "activated" | "recovery_required";
40
+ name: string;
41
+ slug: string;
42
+ createdAt: number;
43
+ activatedAt: number | null;
44
+ displayRevision: number;
45
+ amendable: boolean;
46
+ }
47
+ interface OrganizationAdmission {
48
+ applicationId: string;
49
+ organizationId: string;
50
+ organizationGeneration: string;
51
+ state: "pending" | "active";
52
+ basis: "coverage" | "grandfathered" | null;
53
+ policyRevision: number;
54
+ }
55
+ interface OrganizationAdmissionSetupInput {
56
+ applicationId: string;
57
+ setupId: string;
58
+ }
59
+ interface ReserveOrganizationAdmissionInput {
60
+ applicationId: string;
61
+ idempotencyKey: string;
62
+ target: {
63
+ kind: "new";
64
+ name: string;
65
+ slug: string;
66
+ } | {
67
+ kind: "existing";
68
+ organizationId: string;
69
+ organizationGeneration: string;
70
+ };
71
+ }
72
+ interface AmendOrganizationAdmissionInput extends OrganizationAdmissionSetupInput {
73
+ expectedDisplayRevision: number;
74
+ name: string;
75
+ slug: string;
76
+ }
77
+ interface OrganizationAdmissionPageInput {
78
+ applicationId: string;
79
+ cursor?: string;
80
+ limit?: number;
81
+ }
82
+ interface OrganizationAdmissionPage {
83
+ setups: OrganizationAdmissionSetup[];
84
+ /** Only null proves that this collection is exhausted. */
85
+ nextCursor: string | null;
86
+ }
87
+ interface CurrentOrganizationAdmissionInput {
88
+ applicationId: string;
89
+ organizationId: string;
90
+ organizationGeneration?: string;
91
+ }
92
+ interface OrganizationAdmissionIdentityInput {
93
+ applicationId: string;
94
+ organizationId: string;
95
+ }
96
+ /** Exact current organization incarnation only. This grants neither admission nor membership. */
97
+ interface OrganizationAdmissionIdentity {
98
+ organizationId: string;
99
+ organizationGeneration: string;
100
+ }
101
+ interface OrganizationAdmissionCreator {
102
+ /** Private application-scoped binding. Never expose it in the Ops pending projection. */
103
+ userId: string;
104
+ userGeneration: string;
105
+ }
106
+ interface OrganizationAdmissionBillingSetup extends OrganizationAdmissionSetup {
107
+ creator: OrganizationAdmissionCreator;
108
+ }
109
+ interface OrganizationAdmissionSelection {
110
+ revision: number;
111
+ digest: string;
112
+ planId: string;
113
+ priceId: string;
114
+ seats: number;
115
+ }
116
+ interface AttestOrganizationAdmissionInput extends OrganizationAdmissionSetupInput {
117
+ organizationId: string;
118
+ organizationGeneration: string;
119
+ creator: OrganizationAdmissionCreator;
120
+ selection: OrganizationAdmissionSelection;
121
+ receipt: {
122
+ id: string;
123
+ revision: number;
124
+ source: "paid" | "trial" | "complimentary";
125
+ observedPriceId: string | null;
126
+ observedAt: number;
127
+ validUntil: number;
128
+ };
129
+ }
130
+ interface OrganizationAdmissionReceipt {
131
+ id: string;
132
+ revision: number;
133
+ state: "accepted" | "withdrawn" | "activated";
134
+ }
135
+ interface WithdrawOrganizationAdmissionInput extends OrganizationAdmissionSetupInput {
136
+ selectionDigest: string;
137
+ receiptId: string;
138
+ receiptRevision: number;
139
+ }
140
+ interface FinalizeOrganizationAdmissionInput extends OrganizationAdmissionSetupInput {
141
+ receiptId: string;
142
+ receiptRevision: number;
143
+ }
144
+ interface FinalizedOrganizationAdmission {
145
+ setup: OrganizationAdmissionSetup;
146
+ admission: OrganizationAdmission & {
147
+ state: "active";
148
+ basis: "coverage";
149
+ };
150
+ }
151
+ type OrganizationAdmissionActorOperation = "reserve" | "read" | "list" | "amend" | "finalize";
152
+ type OrganizationAdmissionOperation = OrganizationAdmissionActorOperation | "current" | "identity" | "lookup" | "attest" | "withdraw" | "pending";
153
+ interface OrganizationAdmissionAuthOptions {
154
+ authOrigin: string;
155
+ fetch?: typeof globalThis.fetch;
156
+ timeoutMs?: number;
157
+ }
158
+ /** Request-scoped actor authority, separate from the application service assertion. */
159
+ interface OrganizationAdmissionActorProof {
160
+ serviceAssertion: string;
161
+ request: Request;
162
+ /** Trusted configured application Origin; never derive it from an untrusted header. */
163
+ appOrigin: string;
164
+ }
165
+ interface FinuevaOrganizationAdmissionAuth {
166
+ audience(operation: OrganizationAdmissionActorOperation | "current" | "identity"): string;
167
+ getOrganizationIdentity(input: OrganizationAdmissionIdentityInput, serviceAssertion: string): Promise<OrganizationAdmissionIdentity | null>;
168
+ amendSetup(input: AmendOrganizationAdmissionInput, proof: OrganizationAdmissionActorProof): Promise<OrganizationAdmissionSetup>;
169
+ reserveSetup(input: ReserveOrganizationAdmissionInput, proof: OrganizationAdmissionActorProof): Promise<OrganizationAdmissionSetup>;
170
+ readSetup(input: OrganizationAdmissionSetupInput, proof: OrganizationAdmissionActorProof): Promise<OrganizationAdmissionSetup | null>;
171
+ listSetups(input: OrganizationAdmissionPageInput, proof: OrganizationAdmissionActorProof): Promise<OrganizationAdmissionPage>;
172
+ getCurrentAdmission(input: CurrentOrganizationAdmissionInput, serviceAssertion: string): Promise<OrganizationAdmission | null>;
173
+ finalizeSetup(input: FinalizeOrganizationAdmissionInput, proof: OrganizationAdmissionActorProof): Promise<FinalizedOrganizationAdmission>;
174
+ }
175
+ interface FinuevaOrganizationAdmissionBillingAuth {
176
+ audience(operation: "lookup" | "attest" | "withdraw"): string;
177
+ lookupSetup(input: OrganizationAdmissionSetupInput, serviceAssertion: string): Promise<OrganizationAdmissionBillingSetup | null>;
178
+ attestCoverage(input: AttestOrganizationAdmissionInput, serviceAssertion: string): Promise<{
179
+ setup: OrganizationAdmissionSetup;
180
+ receipt: OrganizationAdmissionReceipt;
181
+ }>;
182
+ withdrawCoverage(input: WithdrawOrganizationAdmissionInput, serviceAssertion: string): Promise<{
183
+ outcome: "withdrawn" | "already_activated";
184
+ setup: OrganizationAdmissionSetup;
185
+ }>;
186
+ }
187
+ interface FinuevaOrganizationAdmissionDirectoryAuth {
188
+ audience(operation: "pending"): string;
189
+ listPendingSetups(input: OrganizationAdmissionPageInput, serviceAssertion: string): Promise<OrganizationAdmissionPage>;
190
+ }
191
+ //#endregion
192
+ //#region src/organization-admission/index.d.ts
193
+ interface OrganizationAdmissionInputs {
194
+ amend: AmendOrganizationAdmissionInput;
195
+ reserve: ReserveOrganizationAdmissionInput;
196
+ read: OrganizationAdmissionSetupInput;
197
+ list: OrganizationAdmissionPageInput;
198
+ current: CurrentOrganizationAdmissionInput;
199
+ identity: OrganizationAdmissionIdentityInput;
200
+ lookup: OrganizationAdmissionSetupInput;
201
+ pending: OrganizationAdmissionPageInput;
202
+ attest: AttestOrganizationAdmissionInput;
203
+ withdraw: WithdrawOrganizationAdmissionInput;
204
+ finalize: FinalizeOrganizationAdmissionInput;
205
+ }
206
+ /** Hash the strict normalized operation input before signing its bodyDigest claim. No authority is created. */
207
+ declare function organizationAdmissionBodyDigest<Operation extends OrganizationAdmissionOperation>(operation: Operation, input: OrganizationAdmissionInputs[Operation]): Promise<string>;
208
+ /** Server-only actor and current-admission client. Each call needs a fresh exact-body service assertion. */
209
+ declare function createOrganizationAdmissionAuth(options: OrganizationAdmissionAuthOptions): FinuevaOrganizationAdmissionAuth;
210
+ /** Server-only billing capability. It never forwards actor session headers. */
211
+ declare function createOrganizationAdmissionBillingAuth(options: OrganizationAdmissionAuthOptions): FinuevaOrganizationAdmissionBillingAuth;
212
+ /** Server-only pending projection. It contains no creator binding and grants no organization authority. */
213
+ declare function createOrganizationAdmissionDirectoryAuth(options: OrganizationAdmissionAuthOptions): FinuevaOrganizationAdmissionDirectoryAuth;
214
+ //#endregion
31
215
  //#region src/product-operations/types.d.ts
32
216
  type AccountProductOperationPhase = "snapshot" | "consume" | "receipt";
33
217
  interface AccountProductOperationProof {
@@ -321,6 +505,73 @@ interface FinuevaUserDirectoryAuth {
321
505
  /** Server-only service assertions. This client has no session authority and performs no automatic retry. */
322
506
  declare function createUserDirectoryAuth(options: UserDirectoryAuthOptions): FinuevaUserDirectoryAuth;
323
507
  //#endregion
508
+ //#region src/organization-role-events/index.d.ts
509
+ type Role = "owner" | "admin" | "member";
510
+ type OrganizationRoleEventReason = "manual_role_change" | "ownership_transferred_out" | "ownership_transferred_in";
511
+ interface OrganizationRoleEventRoles {
512
+ manualRole: Role;
513
+ effectiveRole: Role;
514
+ }
515
+ /** The application-scoped pseudonymous pair of the User Directory. It is not the canonical Auth User ID. */
516
+ interface OrganizationRoleEventUser {
517
+ userId: string;
518
+ userGeneration: string;
519
+ }
520
+ interface OrganizationRoleEvent {
521
+ /** Immutable. A consumer applies each event identifier once. */
522
+ eventId: string;
523
+ /** Decimal commit order within the feed. Gaps are normal. Compare as numbers. */
524
+ sequence: string;
525
+ occurredAt: number;
526
+ organization: {
527
+ id: string;
528
+ generation: string;
529
+ name: string;
530
+ };
531
+ reason: OrganizationRoleEventReason;
532
+ /** Equal on the two events of one ownership transfer. */
533
+ correlationId: string;
534
+ subject: OrganizationRoleEventUser;
535
+ /** Null when the actor can no longer be addressed. */
536
+ actor: OrganizationRoleEventUser | null;
537
+ before: OrganizationRoleEventRoles;
538
+ after: OrganizationRoleEventRoles;
539
+ }
540
+ interface OrganizationRoleEventsInput {
541
+ applicationId: string;
542
+ /** The last checkpoint the consumer stored. Omit it to start at the retained beginning. */
543
+ after?: string;
544
+ limit?: number;
545
+ }
546
+ interface OrganizationRoleEventsPage {
547
+ version: 1;
548
+ applicationId: string;
549
+ events: OrganizationRoleEvent[];
550
+ /** The highest sequence Auth examined. Store it, even when `events` is empty. */
551
+ checkpoint: string;
552
+ /** Only `false` means the feed reached its head. */
553
+ hasMore: boolean;
554
+ }
555
+ interface OrganizationRoleEventsAuthOptions {
556
+ authOrigin: string;
557
+ fetch?: typeof globalThis.fetch;
558
+ timeoutMs?: number;
559
+ }
560
+ interface FinuevaOrganizationRoleEventsAuth {
561
+ listRoleEvents(input: OrganizationRoleEventsInput, assertion: string): Promise<OrganizationRoleEventsPage>;
562
+ }
563
+ /** The stored checkpoint is older than the history Auth retains. Events between it and `earliest` are gone. */
564
+ declare class OrganizationRoleEventCheckpointExpiredError extends AuthError {
565
+ readonly earliest: string;
566
+ constructor(earliest: string);
567
+ }
568
+ /**
569
+ * Server-only service assertions. The client has no session authority and performs no automatic retry.
570
+ * Each page is checked against the request: the application, an ordered and unique event list, and a checkpoint
571
+ * that never moves backwards.
572
+ */
573
+ declare function createOrganizationRoleEventsAuth(options: OrganizationRoleEventsAuthOptions): FinuevaOrganizationRoleEventsAuth;
574
+ //#endregion
324
575
  //#region src/server.d.ts
325
576
  interface ServerAuthOptions {
326
577
  authOrigin: string;
@@ -385,4 +636,4 @@ interface FinuevaServerAuth {
385
636
  }
386
637
  declare function createServerAuth(options: ServerAuthOptions): FinuevaServerAuth;
387
638
  //#endregion
388
- export { type AcceptInvitationInput, type AccountProductOperationAuthOptions, type AccountProductOperationConsumer, type AccountProductOperationInput, type AccountProductOperationPhase, type AccountProductOperationProof, type AccountProductOperationReceipt, type AccountProductOperationSnapshot, type AccountProductOperationSnapshotInput, type AddedOrganizationTeamMember, AuthError, type AuthErrorCode, type AuthErrorStatus, type AuthOrganization, type AuthSession, type AuthUser, type CanceledOrganizationInvitation, type CompleteGoogleAccountRecoveryInput, type CreateOrganizationMemberInvitationInput, type CreatedOrganization, type CreatedOrganizationMemberInvitation, type CreatedOrganizationTeam, type DeclineInvitationInput, type DeletedOrganizationTeam, type DriveCredential, type DriveCredentialInput, type DriveProvisioningAuthOptions, type DriveProvisioningCredential, type DriveRecipient, type DriveRecipientAuthOptions, type FinuevaDriveProvisioningAuth, type FinuevaDriveRecipientAuth, type FinuevaIdentityResolverAuth, type FinuevaMembershipResolverAuth, type FinuevaOrganizationDirectoryAuth, FinuevaServerAuth, type FinuevaUserDirectoryAuth, type GoogleAccountRecovery, type GoogleAccountRecoveryInput, type IdentityResolverAuthOptions, type InvitationAcceptance, type InvitationDecline, type MembershipResolverAuthOptions, type OrganizationApplicationRegistration, type OrganizationDeparture, type OrganizationDirectoryAuthOptions, type OrganizationDirectoryEntry, type OrganizationDirectoryLookupInput, type OrganizationDirectoryPage, type OrganizationDirectorySearchInput, type OrganizationDisplay, type OrganizationInvitation, type OrganizationInvitationPage, type OrganizationMember, type OrganizationMemberApplicationAccess, type OrganizationMemberApplicationAccessInput, type OrganizationMemberAuthority, type OrganizationMemberPage, type OrganizationMemberPageInput, type OrganizationPage, type OrganizationPageInput, type OrganizationPresenceAuthorization, type OrganizationPresenceInput, type OrganizationTeam, type OrganizationTeamDisplay, type OrganizationTeamMemberPage, type OrganizationTeamPage, type OrganizationWorkspaceSelection, type PersonalWorkspaceSelection, type ReceivedOrganizationInvitation, type ReceivedOrganizationInvitationPage, type RegisterOrganizationApplicationInput, type RegisteredOrganizationApplication, type RemovedOrganizationMember, type RemovedOrganizationTeamMember, type ResentOrganizationInvitation, type ResolveDriveRecipientInput, type ResolveIdentityInput, type ResolveMembershipBatchInput, type ResolveMembershipInput, type ResolvedIdentity, type ResolvedMembership, type ResolvedMembershipBatch, type ResolvedMembershipRole, ServerAuthOptions, ServerInvitationAcceptance, ServerSignOutResult, ServerSocialIdTokenSession, type SocialIdTokenInput, type SocialIdTokenProvider, type UpdateOrganizationDisplayInput, type UpdateOrganizationTeamDisplayInput, type UserApiCredential, type UserApiCredentialInput, type UserApiIdentity, type UserApiVerifierOptions, type UserDirectoryAuthOptions, type UserDirectoryBinding, type UserDirectoryEntry, type UserDirectoryListInput, type UserDirectoryLookupInput, type UserDirectoryMember, type UserDirectoryMembersInput, type UserDirectoryMembersPage, type UserDirectoryPage, type UserDirectoryResolveInput, type WorkspaceSelection, createAccountProductOperationAuth, createDriveProvisioningAuth, createDriveRecipientAuth, createIdentityResolverAuth, createMembershipResolverAuth, createOrganizationDirectoryAuth, createServerAuth, createUserApiVerifier, createUserDirectoryAuth };
639
+ export { type AcceptInvitationInput, type AccountProductOperationAuthOptions, type AccountProductOperationConsumer, type AccountProductOperationInput, type AccountProductOperationPhase, type AccountProductOperationProof, type AccountProductOperationReceipt, type AccountProductOperationSnapshot, type AccountProductOperationSnapshotInput, type AddedOrganizationTeamMember, type AmendOrganizationAdmissionInput, type AttestOrganizationAdmissionInput, AuthError, type AuthErrorCode, type AuthErrorStatus, type AuthOrganization, type AuthSession, type AuthUser, type CanceledOrganizationInvitation, type CompleteGoogleAccountRecoveryInput, type CreateOrganizationMemberInvitationInput, type CreatedOrganization, type CreatedOrganizationMemberInvitation, type CreatedOrganizationTeam, type CurrentOrganizationAdmissionInput, type DeclineInvitationInput, type DeletedOrganizationTeam, type DriveCredential, type DriveCredentialInput, type DriveProvisioningAuthOptions, type DriveProvisioningCredential, type DriveRecipient, type DriveRecipientAuthOptions, type FinalizeOrganizationAdmissionInput, type FinalizedOrganizationAdmission, type FinuevaDriveProvisioningAuth, type FinuevaDriveRecipientAuth, type FinuevaIdentityResolverAuth, type FinuevaMembershipResolverAuth, type FinuevaOrganizationAdmissionAuth, type FinuevaOrganizationAdmissionBillingAuth, type FinuevaOrganizationAdmissionDirectoryAuth, type FinuevaOrganizationDirectoryAuth, type FinuevaOrganizationRoleEventsAuth, FinuevaServerAuth, type FinuevaUserDirectoryAuth, type GoogleAccountRecovery, type GoogleAccountRecoveryInput, type IdentityResolverAuthOptions, type InvitationAcceptance, type InvitationDecline, type MembershipResolverAuthOptions, type OrganizationAdmission, type OrganizationAdmissionActorOperation, type OrganizationAdmissionActorProof, type OrganizationAdmissionAuthOptions, type OrganizationAdmissionBillingSetup, type OrganizationAdmissionCreator, type OrganizationAdmissionIdentity, type OrganizationAdmissionIdentityInput, type OrganizationAdmissionInputs, type OrganizationAdmissionOperation, type OrganizationAdmissionPage, type OrganizationAdmissionPageInput, type OrganizationAdmissionReceipt, type OrganizationAdmissionSelection, type OrganizationAdmissionSetup, type OrganizationAdmissionSetupInput, type OrganizationApplicationRegistration, type OrganizationDeparture, type OrganizationDirectoryAuthOptions, type OrganizationDirectoryEntry, type OrganizationDirectoryLookupInput, type OrganizationDirectoryPage, type OrganizationDirectorySearchInput, type OrganizationDisplay, type OrganizationInvitation, type OrganizationInvitationPage, type OrganizationMember, type OrganizationMemberApplicationAccess, type OrganizationMemberApplicationAccessInput, type OrganizationMemberAuthority, type OrganizationMemberPage, type OrganizationMemberPageInput, type OrganizationPage, type OrganizationPageInput, type OrganizationPresenceAuthorization, type OrganizationPresenceInput, type OrganizationRoleEvent, OrganizationRoleEventCheckpointExpiredError, type OrganizationRoleEventReason, type OrganizationRoleEventRoles, type OrganizationRoleEventUser, type OrganizationRoleEventsAuthOptions, type OrganizationRoleEventsInput, type OrganizationRoleEventsPage, type OrganizationTeam, type OrganizationTeamDisplay, type OrganizationTeamMemberPage, type OrganizationTeamPage, type OrganizationWorkspaceSelection, type PersonalWorkspaceSelection, type ReceivedOrganizationInvitation, type ReceivedOrganizationInvitationPage, type RegisterOrganizationApplicationInput, type RegisteredOrganizationApplication, type RemovedOrganizationMember, type RemovedOrganizationTeamMember, type ResentOrganizationInvitation, type ReserveOrganizationAdmissionInput, type ResolveDriveRecipientInput, type ResolveIdentityInput, type ResolveMembershipBatchInput, type ResolveMembershipInput, type ResolvedIdentity, type ResolvedMembership, type ResolvedMembershipBatch, type ResolvedMembershipRole, ServerAuthOptions, ServerInvitationAcceptance, ServerSignOutResult, ServerSocialIdTokenSession, type SocialIdTokenInput, type SocialIdTokenProvider, type UpdateOrganizationDisplayInput, type UpdateOrganizationTeamDisplayInput, type UserApiCredential, type UserApiCredentialInput, type UserApiIdentity, type UserApiVerifierOptions, type UserDirectoryAuthOptions, type UserDirectoryBinding, type UserDirectoryEntry, type UserDirectoryListInput, type UserDirectoryLookupInput, type UserDirectoryMember, type UserDirectoryMembersInput, type UserDirectoryMembersPage, type UserDirectoryPage, type UserDirectoryResolveInput, type WithdrawOrganizationAdmissionInput, type WorkspaceSelection, createAccountProductOperationAuth, createDriveProvisioningAuth, createDriveRecipientAuth, createIdentityResolverAuth, createMembershipResolverAuth, createOrganizationAdmissionAuth, createOrganizationAdmissionBillingAuth, createOrganizationAdmissionDirectoryAuth, createOrganizationDirectoryAuth, createOrganizationRoleEventsAuth, createServerAuth, createUserApiVerifier, createUserDirectoryAuth, organizationAdmissionBodyDigest };
package/dist/server.js CHANGED
@@ -517,7 +517,7 @@ function normalizeWorkspaceSelection(value) {
517
517
  throw new AuthError("invalid_workspace_selection", 422);
518
518
  }
519
519
  function fromAuthorityError(value, fallbackStatus, retryAfter) {
520
- const mapped = mapError(isObject$1(value) && typeof value.code === "string" ? value.code : void 0, fallbackStatus);
520
+ const mapped = mapError$1(isObject$1(value) && typeof value.code === "string" ? value.code : void 0, fallbackStatus);
521
521
  return new AuthError(mapped.code, mapped.status, parseRetryAfter(retryAfter));
522
522
  }
523
523
  function fromAccountAuthorityError(value, status, retryAfter) {
@@ -626,7 +626,7 @@ function fromInvitationAuthorityError(value, status) {
626
626
  function fromInvitationError(error) {
627
627
  return error instanceof AuthError ? error : authorityUnavailable();
628
628
  }
629
- function mapError(code, status) {
629
+ function mapError$1(code, status) {
630
630
  if (code === "authentication_required") return {
631
631
  code,
632
632
  status: 401
@@ -1397,6 +1397,400 @@ function createOrganizationDirectoryAuth(options) {
1397
1397
  };
1398
1398
  }
1399
1399
  //#endregion
1400
+ //#region src/organization-admission/contract.ts
1401
+ const invalid$1 = () => new AuthError("invalid_request", 400);
1402
+ const positive = (value) => typeof value === "number" && Number.isSafeInteger(value) && value > 0 && value < Number.MAX_SAFE_INTEGER;
1403
+ const timestamp$1 = (value) => typeof value === "number" && Number.isSafeInteger(value) && value >= 0 && value <= 864e13;
1404
+ const digest$2 = (value) => typeof value === "string" && /^[a-f0-9]{64}$(?![\s\S])/.test(value);
1405
+ const text = (value) => typeof value === "string" && value.length > 0 && new TextEncoder().encode(value).byteLength <= 255;
1406
+ const slug = (value) => typeof value === "string" && /^[a-z0-9-]{1,128}$(?![\s\S])/.test(value);
1407
+ function setupInput(input, additional = []) {
1408
+ if (!exact$6(input, [
1409
+ "applicationId",
1410
+ "setupId",
1411
+ ...additional
1412
+ ]) || !directoryId(input.applicationId) || !directoryGeneration(input.setupId)) throw invalid$1();
1413
+ }
1414
+ function pageInput$1(input) {
1415
+ if (!record$1(input) || Object.keys(input).some((key) => ![
1416
+ "applicationId",
1417
+ "cursor",
1418
+ "limit"
1419
+ ].includes(key)) || !directoryId(input.applicationId) || input.cursor !== void 0 && (typeof input.cursor !== "string" || input.cursor.length < 1 || input.cursor.length > 2048) || input.limit !== void 0 && (!positive(input.limit) || input.limit > 50)) throw invalid$1();
1420
+ }
1421
+ const setupKeys = [
1422
+ "setupId",
1423
+ "applicationId",
1424
+ "organizationId",
1425
+ "organizationGeneration",
1426
+ "kind",
1427
+ "status",
1428
+ "name",
1429
+ "slug",
1430
+ "createdAt",
1431
+ "activatedAt",
1432
+ "displayRevision",
1433
+ "amendable"
1434
+ ];
1435
+ function setup(value, applicationId, setupId) {
1436
+ if (!exact$6(value, setupKeys) || !directoryGeneration(value.setupId) || setupId !== void 0 && value.setupId !== setupId || value.applicationId !== applicationId || !directoryId(value.organizationId) || !directoryGeneration(value.organizationGeneration) || value.kind !== "new" && value.kind !== "existing" || ![
1437
+ "reserved",
1438
+ "activating",
1439
+ "activated",
1440
+ "recovery_required"
1441
+ ].includes(String(value.status)) || !text(value.name) || !slug(value.slug) || !timestamp$1(value.createdAt) || !positive(value.displayRevision) || typeof value.amendable !== "boolean" || value.amendable && (value.kind !== "new" || value.status === "activated" || value.status === "activating") || value.activatedAt !== null && (!timestamp$1(value.activatedAt) || value.activatedAt < value.createdAt) || value.status === "activated" !== (value.activatedAt !== null)) throw authorityUnavailable();
1442
+ return {
1443
+ setupId: value.setupId,
1444
+ applicationId,
1445
+ organizationId: value.organizationId,
1446
+ organizationGeneration: value.organizationGeneration,
1447
+ kind: value.kind,
1448
+ status: value.status,
1449
+ name: value.name,
1450
+ slug: value.slug,
1451
+ createdAt: value.createdAt,
1452
+ activatedAt: value.activatedAt,
1453
+ displayRevision: value.displayRevision,
1454
+ amendable: value.amendable
1455
+ };
1456
+ }
1457
+ function billingSetup(value, applicationId, setupId) {
1458
+ if (!exact$6(value, [...setupKeys, "creator"]) || !exact$6(value.creator, ["userId", "userGeneration"]) || !directoryGeneration(value.creator.userId) || !directoryGeneration(value.creator.userGeneration)) throw authorityUnavailable();
1459
+ const { creator: _creator, ...projection } = value;
1460
+ return {
1461
+ ...setup(projection, applicationId, setupId),
1462
+ creator: {
1463
+ userId: value.creator.userId,
1464
+ userGeneration: value.creator.userGeneration
1465
+ }
1466
+ };
1467
+ }
1468
+ function page(value, input, pending = false) {
1469
+ if (!exact$6(value, ["setups", "nextCursor"]) || !Array.isArray(value.setups) || value.setups.length > (input.limit ?? 25) || value.nextCursor !== null && (typeof value.nextCursor !== "string" || !value.nextCursor.length || value.nextCursor.length > 2048 || value.nextCursor === input.cursor)) throw authorityUnavailable();
1470
+ const setups = value.setups.map((item) => setup(item, input.applicationId));
1471
+ if (new Set(setups.map((item) => item.setupId)).size !== setups.length || pending && setups.some((item) => item.status === "activated")) throw authorityUnavailable();
1472
+ return {
1473
+ setups,
1474
+ nextCursor: value.nextCursor
1475
+ };
1476
+ }
1477
+ function admission(value, applicationId, organizationId, generation) {
1478
+ if (!exact$6(value, [
1479
+ "applicationId",
1480
+ "organizationId",
1481
+ "organizationGeneration",
1482
+ "state",
1483
+ "basis",
1484
+ "policyRevision"
1485
+ ]) || value.applicationId !== applicationId || value.organizationId !== organizationId || !directoryGeneration(value.organizationGeneration) || generation !== void 0 && value.organizationGeneration !== generation || !positive(value.policyRevision) || value.state !== "pending" && value.state !== "active" || (value.state === "pending" ? value.basis !== null : value.basis !== "coverage" && value.basis !== "grandfathered")) throw authorityUnavailable();
1486
+ return {
1487
+ applicationId,
1488
+ organizationId,
1489
+ organizationGeneration: value.organizationGeneration,
1490
+ state: value.state,
1491
+ basis: value.basis,
1492
+ policyRevision: value.policyRevision
1493
+ };
1494
+ }
1495
+ //#endregion
1496
+ //#region src/organization-admission/transport.ts
1497
+ function actorHeaders(proof) {
1498
+ if (!exact$6(proof, [
1499
+ "serviceAssertion",
1500
+ "request",
1501
+ "appOrigin"
1502
+ ]) || !(proof.request instanceof Request)) throw invalid$1();
1503
+ const authorization = proof.request.headers.get("authorization");
1504
+ if (authorization !== null) {
1505
+ if (new TextEncoder().encode(authorization).byteLength > 16 * 1024 || /[^\x20-\x7e]/.test(authorization) || !/^Bearer [^\s,]+$/i.test(authorization) || /^[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+$/.test(authorization.slice(7))) throw new AuthError("authentication_required", 401);
1506
+ return { authorization };
1507
+ }
1508
+ const cookie = (proof.request.headers.get("cookie") ?? "").split(";").map((entry) => entry.trim()).filter((entry) => {
1509
+ const separator = entry.indexOf("=");
1510
+ const name = entry.slice(0, separator);
1511
+ return separator > 0 && (name.startsWith("better-auth.") || name.startsWith("__Secure-better-auth."));
1512
+ }).join("; ");
1513
+ if (!cookie || new TextEncoder().encode(cookie).byteLength > 16 * 1024) throw new AuthError("authentication_required", 401);
1514
+ const origin = normalizeOrigin(proof.appOrigin, "appOrigin");
1515
+ if (proof.request.headers.get("origin") !== origin) throw new AuthError("request_origin_denied", 403);
1516
+ return {
1517
+ cookie,
1518
+ origin
1519
+ };
1520
+ }
1521
+ function transport(options, operations) {
1522
+ const base = joinURL(normalizeOrigin(options.authOrigin, "authOrigin"), "api/v1/auth/organization-admission");
1523
+ const fetchImpl = options.fetch ?? globalThis.fetch?.bind(globalThis);
1524
+ if (typeof fetchImpl !== "function") throw new TypeError("fetch is required");
1525
+ const timeoutMs = normalizeTimeout(options.timeoutMs);
1526
+ let inFlight = 0;
1527
+ function audience(operation) {
1528
+ if (!operations.includes(operation)) throw invalid$1();
1529
+ return joinURL(base, operation);
1530
+ }
1531
+ async function exchange(operation, body, assertion, actor) {
1532
+ const url = audience(operation);
1533
+ if (typeof assertion !== "string" || assertion.length > 16 * 1024 || !/^[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+$(?![\s\S])/.test(assertion) || new TextEncoder().encode(JSON.stringify(body)).byteLength > 8192) throw invalid$1();
1534
+ const headers = actor ? actorHeaders(actor) : {};
1535
+ if (inFlight >= 4) throw new AuthError("state_conflict", 409);
1536
+ inFlight += 1;
1537
+ const controller = new AbortController();
1538
+ let timer;
1539
+ const deadline = new Promise((_, reject) => {
1540
+ timer = setTimeout(() => {
1541
+ reject(authorityUnavailable());
1542
+ controller.abort();
1543
+ }, timeoutMs);
1544
+ });
1545
+ try {
1546
+ return await Promise.race([requestJson(url, {
1547
+ fetch: fetchImpl,
1548
+ timeoutMs,
1549
+ method: "POST",
1550
+ credentials: "omit",
1551
+ cache: "no-store",
1552
+ signal: controller.signal,
1553
+ maxResponseBytes: 64 * 1024,
1554
+ headers: {
1555
+ ...headers,
1556
+ "x-finueva-service-assertion": assertion,
1557
+ "content-type": "application/json",
1558
+ accept: "application/json"
1559
+ },
1560
+ body,
1561
+ mapError: (_value, status, retryAfter) => {
1562
+ if (status === 400) return invalid$1();
1563
+ if (status === 401) return new AuthError("authentication_required", 401);
1564
+ if (status === 403) return new AuthError("access_denied", 403);
1565
+ if (status === 409) return new AuthError("state_conflict", 409);
1566
+ if (status === 429 && retryAfter !== null && /^(?:[1-9]|[1-5][0-9]|60)$/.test(retryAfter)) return new AuthError("auth_request_rate_limited", 429, Number(retryAfter));
1567
+ return authorityUnavailable();
1568
+ }
1569
+ }).finally(() => {
1570
+ inFlight -= 1;
1571
+ }), deadline]);
1572
+ } finally {
1573
+ clearTimeout(timer);
1574
+ controller.abort();
1575
+ }
1576
+ }
1577
+ return {
1578
+ audience,
1579
+ exchange
1580
+ };
1581
+ }
1582
+ //#endregion
1583
+ //#region src/organization-admission/index.ts
1584
+ function validate(operation, input) {
1585
+ if (operation === "reserve") {
1586
+ if (!exact$6(input, [
1587
+ "applicationId",
1588
+ "idempotencyKey",
1589
+ "target"
1590
+ ]) || !directoryId(input.applicationId) || typeof input.idempotencyKey !== "string" || !/^[A-Za-z0-9_-]{16,128}$(?![\s\S])/.test(input.idempotencyKey) || !record$1(input.target)) throw invalid$1();
1591
+ const target = input.target;
1592
+ if (target.kind === "new" ? !exact$6(target, [
1593
+ "kind",
1594
+ "name",
1595
+ "slug"
1596
+ ]) || !text(target.name) || !slug(target.slug) : target.kind !== "existing" || !exact$6(target, [
1597
+ "kind",
1598
+ "organizationId",
1599
+ "organizationGeneration"
1600
+ ]) || !directoryId(target.organizationId) || !directoryGeneration(target.organizationGeneration)) throw invalid$1();
1601
+ } else if (operation === "list" || operation === "pending") {
1602
+ pageInput$1(input);
1603
+ return {
1604
+ ...input,
1605
+ limit: input.limit ?? 25
1606
+ };
1607
+ } else if (operation === "identity") {
1608
+ if (!exact$6(input, ["applicationId", "organizationId"]) || !directoryId(input.applicationId) || !directoryId(input.organizationId)) throw invalid$1();
1609
+ } else if (operation === "current") {
1610
+ if (!record$1(input) || Object.keys(input).some((key) => ![
1611
+ "applicationId",
1612
+ "organizationId",
1613
+ "organizationGeneration"
1614
+ ].includes(key)) || !directoryId(input.applicationId) || !directoryId(input.organizationId) || input.organizationGeneration !== void 0 && !directoryGeneration(input.organizationGeneration)) throw invalid$1();
1615
+ } else if (operation === "amend") {
1616
+ setupInput(input, [
1617
+ "expectedDisplayRevision",
1618
+ "name",
1619
+ "slug"
1620
+ ]);
1621
+ if (!positive(input.expectedDisplayRevision) || !text(input.name) || !slug(input.slug)) throw invalid$1();
1622
+ } else if (operation === "read" || operation === "lookup") setupInput(input);
1623
+ else if (operation === "finalize" || operation === "withdraw") {
1624
+ setupInput(input, [
1625
+ "receiptId",
1626
+ "receiptRevision",
1627
+ ...operation === "withdraw" ? ["selectionDigest"] : []
1628
+ ]);
1629
+ if (!directoryId(input.receiptId) || !positive(input.receiptRevision) || operation === "withdraw" && !digest$2(input.selectionDigest)) throw invalid$1();
1630
+ } else if (operation === "attest") {
1631
+ setupInput(input, [
1632
+ "organizationId",
1633
+ "organizationGeneration",
1634
+ "creator",
1635
+ "selection",
1636
+ "receipt"
1637
+ ]);
1638
+ const { creator, selection, receipt } = input;
1639
+ if (!directoryId(input.organizationId) || !directoryGeneration(input.organizationGeneration) || !exact$6(creator, ["userId", "userGeneration"]) || !directoryGeneration(creator.userId) || !directoryGeneration(creator.userGeneration) || !exact$6(selection, [
1640
+ "revision",
1641
+ "digest",
1642
+ "planId",
1643
+ "priceId",
1644
+ "seats"
1645
+ ]) || !positive(selection.revision) || !digest$2(selection.digest) || !directoryId(selection.planId) || !directoryId(selection.priceId) || !positive(selection.seats) || selection.seats > 1e4 || !exact$6(receipt, [
1646
+ "id",
1647
+ "revision",
1648
+ "source",
1649
+ "observedPriceId",
1650
+ "observedAt",
1651
+ "validUntil"
1652
+ ]) || !directoryId(receipt.id) || !positive(receipt.revision) || ![
1653
+ "paid",
1654
+ "trial",
1655
+ "complimentary"
1656
+ ].includes(String(receipt.source)) || !timestamp$1(receipt.observedAt) || !timestamp$1(receipt.validUntil) || receipt.validUntil <= receipt.observedAt || receipt.validUntil - receipt.observedAt > 6e4 || (receipt.source === "complimentary" ? receipt.observedPriceId !== null : receipt.observedPriceId !== selection.priceId)) throw invalid$1();
1657
+ } else throw invalid$1();
1658
+ return input;
1659
+ }
1660
+ function canonical(value) {
1661
+ if (Array.isArray(value)) return `[${value.map(canonical).join(",")}]`;
1662
+ if (record$1(value)) return `{${Object.keys(value).filter((key) => value[key] !== void 0).sort().map((key) => `${JSON.stringify(key)}:${canonical(value[key])}`).join(",")}}`;
1663
+ return JSON.stringify(value);
1664
+ }
1665
+ async function organizationAdmissionBodyDigest(operation, input) {
1666
+ const bytes = new TextEncoder().encode(canonical(validate(operation, input)));
1667
+ if (bytes.byteLength > 8192) throw invalid$1();
1668
+ return Array.from(new Uint8Array(await crypto.subtle.digest("SHA-256", bytes)), (byte) => byte.toString(16).padStart(2, "0")).join("");
1669
+ }
1670
+ function createOrganizationAdmissionAuth(options) {
1671
+ const { audience, exchange } = transport(options, [
1672
+ "reserve",
1673
+ "read",
1674
+ "list",
1675
+ "amend",
1676
+ "current",
1677
+ "identity",
1678
+ "finalize"
1679
+ ]);
1680
+ return {
1681
+ audience,
1682
+ async getOrganizationIdentity(input, assertion) {
1683
+ const value = await exchange("identity", validate("identity", input), assertion);
1684
+ if (!exact$6(value, ["organization"])) throw authorityUnavailable();
1685
+ if (value.organization === null) return null;
1686
+ if (!exact$6(value.organization, ["organizationId", "organizationGeneration"]) || value.organization.organizationId !== input.organizationId || !directoryGeneration(value.organization.organizationGeneration)) throw authorityUnavailable();
1687
+ return {
1688
+ organizationId: input.organizationId,
1689
+ organizationGeneration: value.organization.organizationGeneration
1690
+ };
1691
+ },
1692
+ async amendSetup(input, proof) {
1693
+ const value = await exchange("amend", validate("amend", input), proof.serviceAssertion, proof);
1694
+ if (!exact$6(value, ["setup"])) throw authorityUnavailable();
1695
+ const result = setup(value.setup, input.applicationId, input.setupId);
1696
+ if (result.kind !== "new" || result.name !== input.name || result.slug !== input.slug || result.displayRevision !== input.expectedDisplayRevision + 1) throw authorityUnavailable();
1697
+ return result;
1698
+ },
1699
+ async reserveSetup(input, proof) {
1700
+ const body = validate("reserve", input);
1701
+ const value = await exchange("reserve", body, proof.serviceAssertion, proof);
1702
+ if (!exact$6(value, ["setup"])) throw authorityUnavailable();
1703
+ const result = setup(value.setup, input.applicationId);
1704
+ if (result.kind !== input.target.kind || (input.target.kind === "new" ? result.displayRevision === 1 && (result.name !== input.target.name || result.slug !== input.target.slug) : result.organizationId !== input.target.organizationId || result.organizationGeneration !== input.target.organizationGeneration)) throw authorityUnavailable();
1705
+ return result;
1706
+ },
1707
+ async readSetup(input, proof) {
1708
+ const value = await exchange("read", validate("read", input), proof.serviceAssertion, proof);
1709
+ if (!exact$6(value, ["setup"])) throw authorityUnavailable();
1710
+ return value.setup === null ? null : setup(value.setup, input.applicationId, input.setupId);
1711
+ },
1712
+ async listSetups(input, proof) {
1713
+ return page(await exchange("list", validate("list", input), proof.serviceAssertion, proof), input);
1714
+ },
1715
+ async getCurrentAdmission(input, assertion) {
1716
+ const value = await exchange("current", validate("current", input), assertion);
1717
+ if (!exact$6(value, ["admission"])) throw authorityUnavailable();
1718
+ return value.admission === null ? null : admission(value.admission, input.applicationId, input.organizationId, input.organizationGeneration);
1719
+ },
1720
+ async finalizeSetup(input, proof) {
1721
+ const value = await exchange("finalize", validate("finalize", input), proof.serviceAssertion, proof);
1722
+ if (!exact$6(value, ["setup", "admission"])) throw authorityUnavailable();
1723
+ const result = setup(value.setup, input.applicationId, input.setupId);
1724
+ const active = admission(value.admission, input.applicationId, result.organizationId, result.organizationGeneration);
1725
+ if (result.status !== "activated" || active.state !== "active" || active.basis !== "coverage") throw authorityUnavailable();
1726
+ return {
1727
+ setup: result,
1728
+ admission: {
1729
+ ...active,
1730
+ state: "active",
1731
+ basis: "coverage"
1732
+ }
1733
+ };
1734
+ }
1735
+ };
1736
+ }
1737
+ function createOrganizationAdmissionBillingAuth(options) {
1738
+ const { audience, exchange } = transport(options, [
1739
+ "lookup",
1740
+ "attest",
1741
+ "withdraw"
1742
+ ]);
1743
+ return {
1744
+ audience,
1745
+ async lookupSetup(input, assertion) {
1746
+ const value = await exchange("lookup", validate("lookup", input), assertion);
1747
+ if (!exact$6(value, ["setup"])) throw authorityUnavailable();
1748
+ return value.setup === null ? null : billingSetup(value.setup, input.applicationId, input.setupId);
1749
+ },
1750
+ async attestCoverage(input, assertion) {
1751
+ const value = await exchange("attest", validate("attest", input), assertion);
1752
+ if (!exact$6(value, ["setup", "receipt"]) || !exact$6(value.receipt, [
1753
+ "id",
1754
+ "revision",
1755
+ "state"
1756
+ ]) || value.receipt.id !== input.receipt.id || value.receipt.revision !== input.receipt.revision || ![
1757
+ "accepted",
1758
+ "withdrawn",
1759
+ "activated"
1760
+ ].includes(String(value.receipt.state))) throw authorityUnavailable();
1761
+ const result = setup(value.setup, input.applicationId, input.setupId);
1762
+ if (result.organizationId !== input.organizationId || result.organizationGeneration !== input.organizationGeneration || value.receipt.state === "activated" !== (result.status === "activated")) throw authorityUnavailable();
1763
+ return {
1764
+ setup: result,
1765
+ receipt: {
1766
+ id: input.receipt.id,
1767
+ revision: input.receipt.revision,
1768
+ state: value.receipt.state
1769
+ }
1770
+ };
1771
+ },
1772
+ async withdrawCoverage(input, assertion) {
1773
+ const value = await exchange("withdraw", validate("withdraw", input), assertion);
1774
+ if (!exact$6(value, ["setup", "outcome"]) || value.outcome !== "withdrawn" && value.outcome !== "already_activated") throw authorityUnavailable();
1775
+ const result = setup(value.setup, input.applicationId, input.setupId);
1776
+ if (value.outcome === "already_activated" !== (result.status === "activated")) throw authorityUnavailable();
1777
+ return {
1778
+ setup: result,
1779
+ outcome: value.outcome
1780
+ };
1781
+ }
1782
+ };
1783
+ }
1784
+ function createOrganizationAdmissionDirectoryAuth(options) {
1785
+ const { audience, exchange } = transport(options, ["pending"]);
1786
+ return {
1787
+ audience,
1788
+ async listPendingSetups(input, assertion) {
1789
+ return page(await exchange("pending", validate("pending", input), assertion), input, true);
1790
+ }
1791
+ };
1792
+ }
1793
+ //#endregion
1400
1794
  //#region src/product-operations/contract.ts
1401
1795
  const id$2 = /^[A-Za-z0-9_-]{1,128}$(?![\s\S])/;
1402
1796
  const digest$1 = /^[a-f0-9]{64}$(?![\s\S])/;
@@ -3049,7 +3443,7 @@ function createIdentityResolverAuth(options) {
3049
3443
  //#region src/membership-resolution.ts
3050
3444
  const idPattern = /^[A-Za-z0-9_-]{1,128}$(?![\s\S])/;
3051
3445
  const isoPattern = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{1,3})?Z$(?![\s\S])/;
3052
- const roles = [
3446
+ const roles$1 = [
3053
3447
  "admin",
3054
3448
  "member",
3055
3449
  "owner"
@@ -3071,7 +3465,7 @@ function parseMembership(value, organizationId, userId) {
3071
3465
  if (!exact$1(value, ["membership"])) throw authorityUnavailable();
3072
3466
  if (value.membership === null) return null;
3073
3467
  const membership = value.membership;
3074
- if (!exact$1(membership, membershipKeys) || typeof membership.checkedAt !== "string" || !isoPattern.test(membership.checkedAt) || Number.isNaN(Date.parse(membership.checkedAt)) || typeof membership.manualRole !== "string" || !roles.includes(membership.manualRole) || typeof membership.role !== "string" || !roles.includes(membership.role) || typeof membership.memberCount !== "number" || !Number.isSafeInteger(membership.memberCount) || membership.memberCount < 0 || typeof membership.memberId !== "string" || !idPattern.test(membership.memberId) || typeof membership.owner !== "boolean" || membership.organizationId !== organizationId || membership.userId !== userId) throw authorityUnavailable();
3468
+ if (!exact$1(membership, membershipKeys) || typeof membership.checkedAt !== "string" || !isoPattern.test(membership.checkedAt) || Number.isNaN(Date.parse(membership.checkedAt)) || typeof membership.manualRole !== "string" || !roles$1.includes(membership.manualRole) || typeof membership.role !== "string" || !roles$1.includes(membership.role) || typeof membership.memberCount !== "number" || !Number.isSafeInteger(membership.memberCount) || membership.memberCount < 0 || typeof membership.memberId !== "string" || !idPattern.test(membership.memberId) || typeof membership.owner !== "boolean" || membership.organizationId !== organizationId || membership.userId !== userId) throw authorityUnavailable();
3075
3469
  return {
3076
3470
  checkedAt: membership.checkedAt,
3077
3471
  manualRole: membership.manualRole,
@@ -3476,7 +3870,7 @@ function createDriveProvisioningAuth(options) {
3476
3870
  }
3477
3871
  //#endregion
3478
3872
  //#region src/user-directory.ts
3479
- function user(value, applicationId) {
3873
+ function user$1(value, applicationId) {
3480
3874
  if (!exact$6(value, [
3481
3875
  "applicationId",
3482
3876
  "userId",
@@ -3514,7 +3908,7 @@ function nextCursor(value) {
3514
3908
  return value;
3515
3909
  }
3516
3910
  function selectedUser(value, input) {
3517
- const normalized = user(value, input.applicationId);
3911
+ const normalized = user$1(value, input.applicationId);
3518
3912
  if (normalized.userId !== input.userId || normalized.userGeneration !== input.userGeneration) throw authorityUnavailable();
3519
3913
  return normalized;
3520
3914
  }
@@ -3567,7 +3961,7 @@ function createUserDirectoryAuth(options) {
3567
3961
  pageInput(input);
3568
3962
  const value = await exchange("list", input, assertion);
3569
3963
  if (!exact$6(value, ["users", "nextCursor"]) || !Array.isArray(value.users) || value.users.length > (input.limit ?? 50)) throw authorityUnavailable();
3570
- const users = value.users.map((item) => user(item, input.applicationId));
3964
+ const users = value.users.map((item) => user$1(item, input.applicationId));
3571
3965
  if (users.some((item) => item.lifecycle === "deleted") || new Set(users.map((item) => item.userId)).size !== users.length) throw authorityUnavailable();
3572
3966
  return {
3573
3967
  users,
@@ -3596,7 +3990,7 @@ function createUserDirectoryAuth(options) {
3596
3990
  "role",
3597
3991
  "membershipStatus"
3598
3992
  ]) || item.role !== "owner" && item.role !== "admin" && item.role !== "member" || item.membershipStatus !== "active" && item.membershipStatus !== "suspended") throw authorityUnavailable();
3599
- const normalized = user(item.user, input.applicationId);
3993
+ const normalized = user$1(item.user, input.applicationId);
3600
3994
  if (normalized.lifecycle === "deleted") throw authorityUnavailable();
3601
3995
  return {
3602
3996
  user: normalized,
@@ -3617,7 +4011,7 @@ function createUserDirectoryAuth(options) {
3617
4011
  if (!exact$6(input, ["applicationId", "authUserId"]) || !directoryId(input.applicationId) || !directoryId(input.authUserId)) throw new AuthError("invalid_request", 400);
3618
4012
  const value = await exchange("resolve", input, assertion);
3619
4013
  if (!exact$6(value, ["user"])) throw authorityUnavailable();
3620
- const result = value.user === null ? null : user(value.user, input.applicationId);
4014
+ const result = value.user === null ? null : user$1(value.user, input.applicationId);
3621
4015
  if (result?.lifecycle === "deleted") throw authorityUnavailable();
3622
4016
  return result;
3623
4017
  },
@@ -3637,6 +4031,169 @@ function createUserDirectoryAuth(options) {
3637
4031
  };
3638
4032
  }
3639
4033
  //#endregion
4034
+ //#region src/organization-role-events/index.ts
4035
+ var OrganizationRoleEventCheckpointExpiredError = class extends AuthError {
4036
+ earliest;
4037
+ constructor(earliest) {
4038
+ super("state_conflict", 409);
4039
+ this.name = "OrganizationRoleEventCheckpointExpiredError";
4040
+ this.earliest = earliest;
4041
+ }
4042
+ };
4043
+ const checkpointPattern = /^(?:0|[1-9][0-9]{0,15})$(?![\s\S])/;
4044
+ const roles = new Set([
4045
+ "owner",
4046
+ "admin",
4047
+ "member"
4048
+ ]);
4049
+ const reasons = new Set([
4050
+ "manual_role_change",
4051
+ "ownership_transferred_out",
4052
+ "ownership_transferred_in"
4053
+ ]);
4054
+ function checkpoint(value) {
4055
+ return typeof value === "string" && checkpointPattern.test(value) && Number.isSafeInteger(Number(value));
4056
+ }
4057
+ function user(value) {
4058
+ if (!exact$6(value, ["userId", "userGeneration"]) || !directoryGeneration(value.userId) || !directoryGeneration(value.userGeneration)) throw authorityUnavailable();
4059
+ return {
4060
+ userId: value.userId,
4061
+ userGeneration: value.userGeneration
4062
+ };
4063
+ }
4064
+ function roleSet(value) {
4065
+ if (!exact$6(value, ["manualRole", "effectiveRole"]) || !roles.has(value.manualRole) || !roles.has(value.effectiveRole)) throw authorityUnavailable();
4066
+ return {
4067
+ manualRole: value.manualRole,
4068
+ effectiveRole: value.effectiveRole
4069
+ };
4070
+ }
4071
+ function event(value) {
4072
+ if (!exact$6(value, [
4073
+ "eventId",
4074
+ "sequence",
4075
+ "occurredAt",
4076
+ "organization",
4077
+ "reason",
4078
+ "correlationId",
4079
+ "subject",
4080
+ "actor",
4081
+ "before",
4082
+ "after"
4083
+ ]) || typeof value.eventId !== "string" || !/^rle_[a-f0-9]{32}$(?![\s\S])/.test(value.eventId) || !checkpoint(value.sequence) || value.sequence === "0" || !Number.isSafeInteger(value.occurredAt) || value.occurredAt < 0 || typeof value.correlationId !== "string" || !/^[A-Za-z0-9_-]{43}$(?![\s\S])/.test(value.correlationId) || !reasons.has(value.reason) || !exact$6(value.organization, [
4084
+ "id",
4085
+ "generation",
4086
+ "name"
4087
+ ]) || !directoryId(value.organization.id) || !directoryGeneration(value.organization.generation) || typeof value.organization.name !== "string" || value.organization.name.length < 1 || new TextEncoder().encode(value.organization.name).byteLength > 255) throw authorityUnavailable();
4088
+ const organization = value.organization;
4089
+ return {
4090
+ eventId: value.eventId,
4091
+ sequence: value.sequence,
4092
+ occurredAt: value.occurredAt,
4093
+ organization: {
4094
+ id: organization.id,
4095
+ generation: organization.generation,
4096
+ name: organization.name
4097
+ },
4098
+ reason: value.reason,
4099
+ correlationId: value.correlationId,
4100
+ subject: user(value.subject),
4101
+ actor: value.actor === null ? null : user(value.actor),
4102
+ before: roleSet(value.before),
4103
+ after: roleSet(value.after)
4104
+ };
4105
+ }
4106
+ function listInput(input) {
4107
+ if (!record$1(input) || Object.keys(input).some((key) => ![
4108
+ "applicationId",
4109
+ "after",
4110
+ "limit"
4111
+ ].includes(key)) || !directoryId(input.applicationId) || input.after !== void 0 && !checkpoint(input.after) || input.limit !== void 0 && (!Number.isInteger(input.limit) || input.limit < 1 || input.limit > 100)) throw new AuthError("invalid_request", 400);
4112
+ }
4113
+ function mapError(value, status, retryAfter) {
4114
+ if (status === 409 && exact$6(value, [
4115
+ "code",
4116
+ "message",
4117
+ "earliest"
4118
+ ]) && value.code === "CHECKPOINT_EXPIRED" && checkpoint(value.earliest)) return new OrganizationRoleEventCheckpointExpiredError(value.earliest);
4119
+ return fromAuthorityError(value, status, retryAfter);
4120
+ }
4121
+ function createOrganizationRoleEventsAuth(options) {
4122
+ const origin = normalizeOrigin(options.authOrigin, "authOrigin");
4123
+ const fetchImpl = options.fetch ?? globalThis.fetch?.bind(globalThis);
4124
+ if (typeof fetchImpl !== "function") throw new TypeError("fetch is required");
4125
+ const timeoutMs = normalizeTimeout(options.timeoutMs);
4126
+ let inFlight = 0;
4127
+ async function exchange(body, assertion) {
4128
+ if (typeof assertion !== "string" || assertion.length > 16 * 1024 || !/^[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+$(?![\s\S])/.test(assertion)) throw new AuthError("invalid_request", 400);
4129
+ if (inFlight >= 4) throw new AuthError("state_conflict", 409);
4130
+ inFlight += 1;
4131
+ const controller = new AbortController();
4132
+ let timer;
4133
+ const deadline = new Promise((_, reject) => {
4134
+ timer = setTimeout(() => {
4135
+ reject(authorityUnavailable());
4136
+ controller.abort();
4137
+ }, timeoutMs);
4138
+ });
4139
+ try {
4140
+ return await Promise.race([requestJson(joinURL(origin, "api/v1/auth/organization-role-events/list"), {
4141
+ fetch: fetchImpl,
4142
+ timeoutMs,
4143
+ method: "POST",
4144
+ credentials: "omit",
4145
+ cache: "no-store",
4146
+ headers: {
4147
+ "x-finueva-service-assertion": assertion,
4148
+ "content-type": "application/json",
4149
+ accept: "application/json"
4150
+ },
4151
+ body,
4152
+ maxResponseBytes: 256 * 1024,
4153
+ signal: controller.signal,
4154
+ mapError
4155
+ }).finally(() => {
4156
+ inFlight -= 1;
4157
+ }), deadline]);
4158
+ } catch (cause) {
4159
+ if (cause instanceof AuthError) throw cause;
4160
+ throw authorityUnavailable();
4161
+ } finally {
4162
+ clearTimeout(timer);
4163
+ controller.abort();
4164
+ }
4165
+ }
4166
+ return { async listRoleEvents(input, assertion) {
4167
+ listInput(input);
4168
+ const value = await exchange(input, assertion);
4169
+ if (!exact$6(value, [
4170
+ "version",
4171
+ "applicationId",
4172
+ "events",
4173
+ "checkpoint",
4174
+ "hasMore"
4175
+ ]) || value.version !== 1 || value.applicationId !== input.applicationId || !Array.isArray(value.events) || value.events.length > (input.limit ?? 50) || !checkpoint(value.checkpoint) || typeof value.hasMore !== "boolean") throw authorityUnavailable();
4176
+ const events = value.events.map(event);
4177
+ const floor = Number(input.after ?? "0");
4178
+ let previous = floor;
4179
+ const seen = new Set();
4180
+ for (const item of events) {
4181
+ const sequence = Number(item.sequence);
4182
+ if (sequence <= previous || sequence > Number(value.checkpoint) || seen.has(item.eventId)) throw authorityUnavailable();
4183
+ previous = sequence;
4184
+ seen.add(item.eventId);
4185
+ }
4186
+ if (Number(value.checkpoint) < floor || value.hasMore && Number(value.checkpoint) <= floor) throw authorityUnavailable();
4187
+ return {
4188
+ version: 1,
4189
+ applicationId: input.applicationId,
4190
+ events,
4191
+ checkpoint: value.checkpoint,
4192
+ hasMore: value.hasMore
4193
+ };
4194
+ } };
4195
+ }
4196
+ //#endregion
3640
4197
  //#region src/server.ts
3641
4198
  const MAX_AUTHORIZATION_BYTES = 16 * 1024;
3642
4199
  function createServerAuth(options) {
@@ -4197,4 +4754,4 @@ function authAuthorizationHeader(value) {
4197
4754
  return value;
4198
4755
  }
4199
4756
  //#endregion
4200
- export { AuthError, createAccountProductOperationAuth, createDriveProvisioningAuth, createDriveRecipientAuth, createIdentityResolverAuth, createMembershipResolverAuth, createOrganizationDirectoryAuth, createServerAuth, createUserApiVerifier, createUserDirectoryAuth };
4757
+ export { AuthError, OrganizationRoleEventCheckpointExpiredError, createAccountProductOperationAuth, createDriveProvisioningAuth, createDriveRecipientAuth, createIdentityResolverAuth, createMembershipResolverAuth, createOrganizationAdmissionAuth, createOrganizationAdmissionBillingAuth, createOrganizationAdmissionDirectoryAuth, createOrganizationDirectoryAuth, createOrganizationRoleEventsAuth, createServerAuth, createUserApiVerifier, createUserDirectoryAuth, organizationAdmissionBodyDigest };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@finueva/auth",
3
- "version": "0.29.0",
3
+ "version": "0.31.0",
4
4
  "description": "Public browser and server SDK for Finueva Auth",
5
5
  "type": "module",
6
6
  "sideEffects": false,