@finueva/auth 0.25.0 → 0.26.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
@@ -450,3 +450,7 @@ Long-form task guides are maintained with the Auth source:
450
450
  - [Errors and recovery](https://github.com/Ifkafin/auth/blob/main/apps/developer/docs/sdk/errors-and-recovery.md)
451
451
 
452
452
  These links track current source and can describe a newer SDK version. Check the version at the start of the guide. Repository access is required until these guides have a public, versioned documentation deployment.
453
+
454
+ ### Organization presence authorization candidate
455
+
456
+ 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.
package/dist/server.d.ts CHANGED
@@ -59,6 +59,23 @@ declare function createAccountProductOperationAuth(options: AccountProductOperat
59
59
  audience(phase: AccountProductOperationPhase): string;
60
60
  };
61
61
  //#endregion
62
+ //#region src/organization-presence.d.ts
63
+ interface OrganizationPresenceInput {
64
+ applicationId: string;
65
+ userIds: string[];
66
+ }
67
+ interface OrganizationPresenceAuthorization {
68
+ organizationId: string;
69
+ applicationId: string;
70
+ actor: {
71
+ userId: string;
72
+ sessionId: string;
73
+ };
74
+ userIds: string[];
75
+ /** Observation time only. This is not an authority lease or application privacy decision. */
76
+ checkedAt: Date;
77
+ }
78
+ //#endregion
62
79
  //#region src/application-access.d.ts
63
80
  interface OrganizationMemberApplicationAccessInput {
64
81
  applicationId: string;
@@ -232,6 +249,9 @@ interface FinuevaServerAuth {
232
249
  getSession(): Promise<AuthSession | null>;
233
250
  listOrganizations(input?: OrganizationPageInput): Promise<OrganizationPage>;
234
251
  getOrganization(organizationId: string): Promise<AuthOrganization>;
252
+ authorizeOrganizationPresence(organizationId: string, input: OrganizationPresenceInput, serviceAssertion: string, options?: {
253
+ applicationCredential: string;
254
+ }): Promise<OrganizationPresenceAuthorization>;
235
255
  getOrganizationMemberApplicationAccess(organizationId: string, input: OrganizationMemberApplicationAccessInput, serviceAssertion: string, options?: {
236
256
  applicationCredential: string;
237
257
  }): Promise<OrganizationMemberApplicationAccess>;
@@ -266,4 +286,4 @@ interface FinuevaServerAuth {
266
286
  }
267
287
  declare function createServerAuth(options: ServerAuthOptions): FinuevaServerAuth;
268
288
  //#endregion
269
- 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, FinuevaServerAuth, type GoogleAccountRecovery, type GoogleAccountRecoveryInput, type IdentityResolverAuthOptions, type InvitationAcceptance, type InvitationDecline, type MembershipResolverAuthOptions, type OrganizationDeparture, type OrganizationDisplay, type OrganizationInvitation, type OrganizationInvitationPage, type OrganizationMember, type OrganizationMemberApplicationAccess, type OrganizationMemberApplicationAccessInput, type OrganizationMemberAuthority, type OrganizationMemberPage, type OrganizationMemberPageInput, type OrganizationPage, type OrganizationPageInput, type OrganizationTeam, type OrganizationTeamDisplay, type OrganizationTeamMemberPage, type OrganizationTeamPage, type OrganizationWorkspaceSelection, type PersonalWorkspaceSelection, type ReceivedOrganizationInvitation, type ReceivedOrganizationInvitationPage, 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 WorkspaceSelection, createAccountProductOperationAuth, createDriveProvisioningAuth, createDriveRecipientAuth, createIdentityResolverAuth, createMembershipResolverAuth, createServerAuth, createUserApiVerifier };
289
+ 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, FinuevaServerAuth, type GoogleAccountRecovery, type GoogleAccountRecoveryInput, type IdentityResolverAuthOptions, type InvitationAcceptance, type InvitationDecline, type MembershipResolverAuthOptions, type OrganizationDeparture, 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 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 WorkspaceSelection, createAccountProductOperationAuth, createDriveProvisioningAuth, createDriveRecipientAuth, createIdentityResolverAuth, createMembershipResolverAuth, createServerAuth, createUserApiVerifier };
package/dist/server.js CHANGED
@@ -496,7 +496,7 @@ var AuthError = class extends Error {
496
496
  //#endregion
497
497
  //#region src/shared.ts
498
498
  const DRIVE_CREDENTIAL_LIFETIME_SECONDS = 840;
499
- const id$2 = /^[A-Za-z0-9_-]{1,128}$/;
499
+ const id$3 = /^[A-Za-z0-9_-]{1,128}$/;
500
500
  const email = /^[^\s@]+@[^\s@]+$/;
501
501
  const MAX_SOCIAL_ID_TOKEN_BYTES = 16 * 1024;
502
502
  function normalizeEmail(value) {
@@ -606,7 +606,7 @@ function normalizeIdInput(value) {
606
606
  return value;
607
607
  }
608
608
  function normalizeOrganization(value) {
609
- exact$5(value, [
609
+ exact$6(value, [
610
610
  "capabilities",
611
611
  "id",
612
612
  "lifecycle",
@@ -616,7 +616,7 @@ function normalizeOrganization(value) {
616
616
  "slug"
617
617
  ]);
618
618
  if (!isId(value.id) || !boundedString(value.name, 255) || !boundedString(value.slug, 255) || value.lifecycle !== "ordinary" && value.lifecycle !== "managed" || !role(value.role) || !isObject$1(value.capabilities)) throw authorityUnavailable();
619
- exact$5(value.capabilities, [
619
+ exact$6(value.capabilities, [
620
620
  "readInvitations",
621
621
  "readMembers",
622
622
  "readTeams"
@@ -678,7 +678,7 @@ function normalizeOrganizationCreationInput(name, slug, idempotencyKey) {
678
678
  };
679
679
  }
680
680
  function normalizeCreatedOrganization(value) {
681
- exact$5(value, [
681
+ exact$6(value, [
682
682
  "id",
683
683
  "name",
684
684
  "slug"
@@ -698,7 +698,7 @@ function normalizeOrganizationTeamCreationInput(name, idempotencyKey) {
698
698
  };
699
699
  }
700
700
  function normalizeCreatedOrganizationTeam(value) {
701
- exact$5(value, ["id", "name"]);
701
+ exact$6(value, ["id", "name"]);
702
702
  if (!isId(value.id) || !boundedString(value.name, 255)) throw authorityUnavailable();
703
703
  return {
704
704
  id: value.id,
@@ -725,7 +725,7 @@ function normalizeOrganizationMemberInvitationCreationInput(value) {
725
725
  };
726
726
  }
727
727
  function normalizeCreatedOrganizationMemberInvitation(value) {
728
- exact$5(value, ["expiresAt", "id"]);
728
+ exact$6(value, ["expiresAt", "id"]);
729
729
  if (!isId(value.id)) throw authorityUnavailable();
730
730
  return {
731
731
  id: value.id,
@@ -742,7 +742,7 @@ function normalizeOrganizationInvitationAdministrationInput(idempotencyKey) {
742
742
  return { idempotencyKey };
743
743
  }
744
744
  function normalizeCanceledOrganizationInvitation(value) {
745
- exact$5(value, ["status"]);
745
+ exact$6(value, ["status"]);
746
746
  if (value.status !== "canceled") throw authorityUnavailable();
747
747
  return { status: "canceled" };
748
748
  }
@@ -751,12 +751,12 @@ function normalizeOrganizationMembershipRemovalInput(idempotencyKey) {
751
751
  return { idempotencyKey };
752
752
  }
753
753
  function normalizeRemovedOrganizationMember(value) {
754
- exact$5(value, ["status"]);
754
+ exact$6(value, ["status"]);
755
755
  if (value.status !== "removed") throw authorityUnavailable();
756
756
  return { status: "removed" };
757
757
  }
758
758
  function normalizeOrganizationDeparture(value) {
759
- exact$5(value, ["status"]);
759
+ exact$6(value, ["status"]);
760
760
  if (value.status !== "left") throw authorityUnavailable();
761
761
  return { status: "left" };
762
762
  }
@@ -765,22 +765,22 @@ function normalizeOrganizationTeamMembershipInput(idempotencyKey) {
765
765
  return { idempotencyKey };
766
766
  }
767
767
  function normalizeAddedOrganizationTeamMember(value) {
768
- exact$5(value, ["status"]);
768
+ exact$6(value, ["status"]);
769
769
  if (value.status !== "added") throw authorityUnavailable();
770
770
  return { status: "added" };
771
771
  }
772
772
  function normalizeRemovedOrganizationTeamMember(value) {
773
- exact$5(value, ["status"]);
773
+ exact$6(value, ["status"]);
774
774
  if (value.status !== "removed") throw authorityUnavailable();
775
775
  return { status: "removed" };
776
776
  }
777
777
  function normalizeDeletedOrganizationTeam(value) {
778
- exact$5(value, ["status"]);
778
+ exact$6(value, ["status"]);
779
779
  if (value.status !== "deleted") throw authorityUnavailable();
780
780
  return { status: "deleted" };
781
781
  }
782
782
  function normalizeOrganizations(value) {
783
- exact$5(value, ["nextCursor", "organizations"]);
783
+ exact$6(value, ["nextCursor", "organizations"]);
784
784
  if (!Array.isArray(value.organizations) || value.organizations.length > 100) throw authorityUnavailable();
785
785
  return {
786
786
  organizations: unique(value.organizations.map(normalizeOrganization), (item) => item.id),
@@ -788,11 +788,11 @@ function normalizeOrganizations(value) {
788
788
  };
789
789
  }
790
790
  function normalizeOrganizationMembers(value) {
791
- exact$5(value, ["members", "nextCursor"]);
791
+ exact$6(value, ["members", "nextCursor"]);
792
792
  if (!Array.isArray(value.members) || value.members.length > 100) throw authorityUnavailable();
793
793
  return {
794
794
  members: unique(value.members.map((member) => {
795
- exact$5(member, [
795
+ exact$6(member, [
796
796
  "email",
797
797
  "id",
798
798
  "image",
@@ -821,11 +821,11 @@ function normalizeOrganizationMembers(value) {
821
821
  };
822
822
  }
823
823
  function normalizeOrganizationTeams(value) {
824
- exact$5(value, ["nextCursor", "teams"]);
824
+ exact$6(value, ["nextCursor", "teams"]);
825
825
  if (!Array.isArray(value.teams) || value.teams.length > 100) throw authorityUnavailable();
826
826
  return {
827
827
  teams: unique(value.teams.map((team) => {
828
- exact$5(team, [
828
+ exact$6(team, [
829
829
  "category",
830
830
  "createdAt",
831
831
  "id",
@@ -843,7 +843,7 @@ function normalizeOrganizationTeams(value) {
843
843
  };
844
844
  }
845
845
  function normalizeOrganizationTeamMembers(value) {
846
- exact$5(value, ["memberIds", "nextCursor"]);
846
+ exact$6(value, ["memberIds", "nextCursor"]);
847
847
  if (!Array.isArray(value.memberIds) || value.memberIds.length > 100) throw authorityUnavailable();
848
848
  return {
849
849
  memberIds: unique(value.memberIds.map((item) => normalizeResponseId(item)), (item) => item),
@@ -851,7 +851,7 @@ function normalizeOrganizationTeamMembers(value) {
851
851
  };
852
852
  }
853
853
  function normalizeOrganizationInvitation(value) {
854
- exact$5(value, [
854
+ exact$6(value, [
855
855
  "createdAt",
856
856
  "email",
857
857
  "expiresAt",
@@ -862,7 +862,7 @@ function normalizeOrganizationInvitation(value) {
862
862
  "teamIds"
863
863
  ]);
864
864
  if (!isId(value.id) || typeof value.email !== "string" || value.email.length > 320 || !email.test(value.email) || !role(value.role) || value.status !== "pending" || !Array.isArray(value.teamIds) || value.teamIds.length > 100 || !isObject$1(value.inviter)) throw authorityUnavailable();
865
- exact$5(value.inviter, ["membershipId", "name"]);
865
+ exact$6(value.inviter, ["membershipId", "name"]);
866
866
  if (!isId(value.inviter.membershipId) || !boundedString(value.inviter.name, 255)) throw authorityUnavailable();
867
867
  return {
868
868
  id: value.id,
@@ -879,7 +879,7 @@ function normalizeOrganizationInvitation(value) {
879
879
  };
880
880
  }
881
881
  function normalizeOrganizationInvitations(value) {
882
- exact$5(value, ["invitations", "nextCursor"]);
882
+ exact$6(value, ["invitations", "nextCursor"]);
883
883
  if (!Array.isArray(value.invitations) || value.invitations.length > 100) throw authorityUnavailable();
884
884
  return {
885
885
  invitations: unique(value.invitations.map(normalizeOrganizationInvitation), (item) => item.id),
@@ -887,7 +887,7 @@ function normalizeOrganizationInvitations(value) {
887
887
  };
888
888
  }
889
889
  function normalizeReceivedInvitation(value) {
890
- exact$5(value, [
890
+ exact$6(value, [
891
891
  "expiresAt",
892
892
  "id",
893
893
  "inviterName",
@@ -896,7 +896,7 @@ function normalizeReceivedInvitation(value) {
896
896
  "teams"
897
897
  ]);
898
898
  if (!isId(value.id) || !boundedString(value.inviterName, 255) || !role(value.role) || !Array.isArray(value.teams) || value.teams.length > 100 || !isObject$1(value.organization)) throw authorityUnavailable();
899
- exact$5(value.organization, [
899
+ exact$6(value.organization, [
900
900
  "id",
901
901
  "logo",
902
902
  "name",
@@ -913,7 +913,7 @@ function normalizeReceivedInvitation(value) {
913
913
  },
914
914
  role: value.role,
915
915
  teams: unique(value.teams.map((team) => {
916
- exact$5(team, ["id", "name"]);
916
+ exact$6(team, ["id", "name"]);
917
917
  if (!isId(team.id) || !boundedString(team.name, 255)) throw authorityUnavailable();
918
918
  return {
919
919
  id: team.id,
@@ -925,7 +925,7 @@ function normalizeReceivedInvitation(value) {
925
925
  };
926
926
  }
927
927
  function normalizeReceivedInvitations(value) {
928
- exact$5(value, ["invitations", "nextCursor"]);
928
+ exact$6(value, ["invitations", "nextCursor"]);
929
929
  if (!Array.isArray(value.invitations) || value.invitations.length > 100) throw authorityUnavailable();
930
930
  return {
931
931
  invitations: unique(value.invitations.map(normalizeReceivedInvitation), (item) => item.id),
@@ -948,7 +948,7 @@ function normalizeWorkspaceSelection(value) {
948
948
  if (!isObject$1(value)) throw new AuthError("invalid_workspace_selection", 422);
949
949
  const keys = Object.keys(value);
950
950
  if (value.type === "personal" && keys.length === 1 && keys[0] === "type") return { type: "personal" };
951
- if (value.type === "organization" && keys.length === 2 && keys.includes("type") && keys.includes("organizationId") && typeof value.organizationId === "string" && id$2.test(value.organizationId)) return {
951
+ if (value.type === "organization" && keys.length === 2 && keys.includes("type") && keys.includes("organizationId") && typeof value.organizationId === "string" && id$3.test(value.organizationId)) return {
952
952
  type: "organization",
953
953
  organizationId: value.organizationId
954
954
  };
@@ -1015,7 +1015,7 @@ function fromOrganizationMembershipRemovalError(value, status, retryAfter) {
1015
1015
  return fromOrganizationMutationAuthorityError(value, status, retryAfter);
1016
1016
  }
1017
1017
  function normalizeOrganizationMemberAuthority(value, organizationId, memberId) {
1018
- exact$5(value, [
1018
+ exact$6(value, [
1019
1019
  "organizationId",
1020
1020
  "actor",
1021
1021
  "target"
@@ -1033,7 +1033,7 @@ function normalizeOrganizationMemberAuthority(value, organizationId, memberId) {
1033
1033
  };
1034
1034
  }
1035
1035
  function normalizeOrganizationAuthorityMemberOutcome(value, includesStatus = false) {
1036
- exact$5(value, [
1036
+ exact$6(value, [
1037
1037
  "memberId",
1038
1038
  "manualRole",
1039
1039
  "role",
@@ -1124,9 +1124,9 @@ function toDate(value) {
1124
1124
  return result && Number.isFinite(result.getTime()) ? result : void 0;
1125
1125
  }
1126
1126
  function isId(value) {
1127
- return typeof value === "string" && id$2.test(value);
1127
+ return typeof value === "string" && id$3.test(value);
1128
1128
  }
1129
- function exact$5(value, keys) {
1129
+ function exact$6(value, keys) {
1130
1130
  if (!isObject$1(value) || Object.keys(value).sort().join(",") !== [...keys].sort().join(",")) throw authorityUnavailable();
1131
1131
  }
1132
1132
  function boundedString(value, maximum) {
@@ -1253,20 +1253,20 @@ async function readJson(response, maximum = MAX_RESPONSE_BYTES, signal) {
1253
1253
  }
1254
1254
  //#endregion
1255
1255
  //#region src/product-operations/contract.ts
1256
- const id$1 = /^[A-Za-z0-9_-]{1,128}$(?![\s\S])/;
1256
+ const id$2 = /^[A-Za-z0-9_-]{1,128}$(?![\s\S])/;
1257
1257
  const digest$1 = /^[a-f0-9]{64}$(?![\s\S])/;
1258
1258
  const credential = /^[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+$(?![\s\S])/;
1259
- function exact$4(value, keys) {
1259
+ function exact$5(value, keys) {
1260
1260
  return value !== null && typeof value === "object" && !Array.isArray(value) && Object.keys(value).length === keys.length && keys.every((key) => Object.hasOwn(value, key));
1261
1261
  }
1262
1262
  function identifier(value) {
1263
- return typeof value === "string" && id$1.test(value);
1263
+ return typeof value === "string" && id$2.test(value);
1264
1264
  }
1265
1265
  function timestamp(value) {
1266
1266
  return typeof value === "number" && Number.isSafeInteger(value) && value >= 0 && value <= 864e13;
1267
1267
  }
1268
1268
  function operationProof(value) {
1269
- if (!exact$4(value, [
1269
+ if (!exact$5(value, [
1270
1270
  "applicationCredential",
1271
1271
  "serviceAssertion",
1272
1272
  "actorUserId",
@@ -1289,14 +1289,14 @@ function operationProof(value) {
1289
1289
  };
1290
1290
  }
1291
1291
  function snapshotInput(value) {
1292
- if (!exact$4(value, ["applicationId", "participantUserUids"]) || !identifier(value.applicationId) || !Array.isArray(value.participantUserUids) || value.participantUserUids.length < 1 || value.participantUserUids.length > 100 || !value.participantUserUids.every((uid, index, all) => identifier(uid) && (index === 0 || all[index - 1] < uid))) throw new AuthError("invalid_request", 400);
1292
+ if (!exact$5(value, ["applicationId", "participantUserUids"]) || !identifier(value.applicationId) || !Array.isArray(value.participantUserUids) || value.participantUserUids.length < 1 || value.participantUserUids.length > 100 || !value.participantUserUids.every((uid, index, all) => identifier(uid) && (index === 0 || all[index - 1] < uid))) throw new AuthError("invalid_request", 400);
1293
1293
  return {
1294
1294
  applicationId: value.applicationId,
1295
1295
  participantUserUids: [...value.participantUserUids]
1296
1296
  };
1297
1297
  }
1298
1298
  function operationInput(value) {
1299
- if (!exact$4(value, [
1299
+ if (!exact$5(value, [
1300
1300
  "applicationId",
1301
1301
  "snapshotId",
1302
1302
  "operationHash",
@@ -1327,13 +1327,13 @@ function snapshotFields(value) {
1327
1327
  };
1328
1328
  }
1329
1329
  function snapshotOutput(value, participants, proof) {
1330
- if (!exact$4(value, snapshotKeys)) throw authorityUnavailable();
1330
+ if (!exact$5(value, snapshotKeys)) throw authorityUnavailable();
1331
1331
  const result = snapshotFields(value);
1332
1332
  if (!participants.includes(result.actorUserId) || result.actorUserId !== proof.actorUserId || result.actorSessionId !== proof.actorSessionId) throw authorityUnavailable();
1333
1333
  return result;
1334
1334
  }
1335
1335
  function receiptOutput(value, input, proof, phase) {
1336
- if (!exact$4(value, [
1336
+ if (!exact$5(value, [
1337
1337
  ...snapshotKeys,
1338
1338
  "serviceId",
1339
1339
  "applicationId",
@@ -1431,7 +1431,7 @@ function createAccountProductOperationAuth(options) {
1431
1431
  const expected = operationProof(proof);
1432
1432
  const { applicationId, ...body } = validated;
1433
1433
  const value = await exchange("consume", applicationId, body, expected);
1434
- if (!exact$4(value, ["receipt", "replayed"]) || typeof value.replayed !== "boolean") throw authorityUnavailable();
1434
+ if (!exact$5(value, ["receipt", "replayed"]) || typeof value.replayed !== "boolean") throw authorityUnavailable();
1435
1435
  return {
1436
1436
  receipt: receiptOutput(value.receipt, validated, expected, "consume"),
1437
1437
  replayed: value.replayed
@@ -1446,98 +1446,6 @@ function createAccountProductOperationAuth(options) {
1446
1446
  };
1447
1447
  }
1448
1448
  //#endregion
1449
- //#region src/application-access.ts
1450
- const id = /^[A-Za-z0-9_-]{1,128}$(?![\s\S])/;
1451
- function applicationAccessInput(input) {
1452
- if (!input || typeof input.applicationId !== "string" || !id.test(input.applicationId) || !Array.isArray(input.userIds) || input.userIds.length < 1 || input.userIds.length > 50 || input.userIds.some((value) => typeof value !== "string" || !id.test(value)) || new Set(input.userIds).size !== input.userIds.length) throw new TypeError("Application access input is invalid");
1453
- return {
1454
- applicationId: input.applicationId,
1455
- userIds: [...input.userIds]
1456
- };
1457
- }
1458
- function exact$3(value, keys) {
1459
- return !!value && typeof value === "object" && !Array.isArray(value) && Object.keys(value).length === keys.length && keys.every((key) => Object.hasOwn(value, key));
1460
- }
1461
- function normalizeApplicationAccess(value, userIds) {
1462
- const invalid = () => new AuthError("identity_authority_unavailable", 503);
1463
- if (!exact$3(value, ["members"]) || !Array.isArray(value.members) || value.members.length !== userIds.length) throw invalid();
1464
- return { members: value.members.map((member, index) => {
1465
- if (!exact$3(member, [
1466
- "userId",
1467
- "latestAppSessionAdmittedAt",
1468
- "activeAppSessionCount"
1469
- ]) || member.userId !== userIds[index] || typeof member.activeAppSessionCount !== "number" || !Number.isSafeInteger(member.activeAppSessionCount) || member.activeAppSessionCount < 0 || member.latestAppSessionAdmittedAt !== null && (typeof member.latestAppSessionAdmittedAt !== "string" || !/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$(?![\s\S])/.test(member.latestAppSessionAdmittedAt) || Number.isNaN(Date.parse(member.latestAppSessionAdmittedAt)) || new Date(member.latestAppSessionAdmittedAt).toISOString() !== member.latestAppSessionAdmittedAt)) throw invalid();
1470
- return {
1471
- userId: member.userId,
1472
- latestAppSessionAdmittedAt: member.latestAppSessionAdmittedAt,
1473
- activeAppSessionCount: member.activeAppSessionCount
1474
- };
1475
- }) };
1476
- }
1477
- //#endregion
1478
- //#region src/google-recovery.ts
1479
- function object(value) {
1480
- return value !== null && typeof value === "object" && !Array.isArray(value);
1481
- }
1482
- function validTicket(value) {
1483
- return typeof value === "string" && /^[A-Za-z0-9_-]{43}$/.test(value);
1484
- }
1485
- function googleRecoveryInput(value, complete) {
1486
- if (!object(value) || Object.keys(value).sort().join(",") !== (complete ? "idToken,recoveryToken" : "idToken") || !object(value.idToken) || Object.keys(value.idToken).some((key) => key !== "token" && key !== "nonce") || complete && !validTicket(value.recoveryToken)) throw new AuthError("invalid_request", 400);
1487
- const social = normalizeSocialIdTokenInput({
1488
- provider: "google",
1489
- idToken: value.idToken.token,
1490
- signUp: false,
1491
- ...value.idToken.nonce === void 0 ? {} : { nonce: value.idToken.nonce }
1492
- });
1493
- return {
1494
- idToken: {
1495
- token: social.idToken,
1496
- ...social.nonce === void 0 ? {} : { nonce: social.nonce }
1497
- },
1498
- ...complete ? { recoveryToken: value.recoveryToken } : {}
1499
- };
1500
- }
1501
- function normalizeGoogleRecovery(value, now) {
1502
- if (!object(value) || Object.keys(value).sort().join(",") !== "expiresAt,recoveryToken" || !validTicket(value.recoveryToken) || typeof value.expiresAt !== "string") throw authorityUnavailable();
1503
- const expiresAt = Date.parse(value.expiresAt);
1504
- if (!Number.isFinite(expiresAt) || expiresAt <= now || expiresAt > now + 10 * 6e4) throw authorityUnavailable();
1505
- return {
1506
- recoveryToken: value.recoveryToken,
1507
- expiresAt: value.expiresAt
1508
- };
1509
- }
1510
- function normalizeGoogleRecoveryCompletion(value) {
1511
- if (!object(value) || Object.keys(value).join(",") !== "linked" || value.linked !== true) throw authorityUnavailable();
1512
- return { linked: true };
1513
- }
1514
- function fromGoogleRecoveryError(value, status, retryAfter) {
1515
- const code = object(value) ? value.code : void 0;
1516
- if (status === 409 && code === "GOOGLE_RECOVERY_IN_PROGRESS") return new AuthError("google_recovery_in_progress", 409);
1517
- if (status === 409 && code === "GOOGLE_RECOVERY_NOT_REQUIRED") return new AuthError("google_recovery_not_required", 409);
1518
- if (status === 403 && code === "GOOGLE_RECOVERY_EMAIL_VERIFICATION_REQUIRED") return new AuthError("email_verification_required", 403);
1519
- if (status === 400 && code === "GOOGLE_RECOVERY_INVALID") return new AuthError("google_recovery_invalid", 400);
1520
- if (status === 410 && code === "GOOGLE_RECOVERY_EXPIRED") return new AuthError("google_recovery_expired", 410);
1521
- if (status === 403 && code === "GOOGLE_RECOVERY_ACCOUNT_MISMATCH") return new AuthError("google_recovery_account_mismatch", 403);
1522
- if (status === 401 && code === "GOOGLE_RECOVERY_FRESH_SIGN_IN_REQUIRED") return new AuthError("recent_sign_in_required", 401);
1523
- if (code === "GOOGLE_RECOVERY_UNAVAILABLE") return authorityUnavailable();
1524
- return fromAccountAuthorityError(value, status, retryAfter);
1525
- }
1526
- //#endregion
1527
- //#region src/user-api/credential.ts
1528
- function userApiApplication(input) {
1529
- if (!input || typeof input.applicationId !== "string" || !/^[A-Za-z0-9_-]{1,128}$(?![\s\S])/.test(input.applicationId) || input.forceRefresh !== void 0 && typeof input.forceRefresh !== "boolean") throw new TypeError("User API credential input is invalid");
1530
- return input.applicationId;
1531
- }
1532
- function normalizeUserApiCredential(value, startedAt) {
1533
- if (!value || typeof value !== "object" || Array.isArray(value) || !("tokenType" in value) || value.tokenType !== "Bearer" || !("token" in value) || typeof value.token !== "string" || value.token.length + 7 > 16 * 1024 || !/^[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+$/.test(value.token) || !("expiresIn" in value) || typeof value.expiresIn !== "number" || !Number.isInteger(value.expiresIn) || value.expiresIn < 1 || value.expiresIn > 840 || Object.keys(value).sort().join(",") !== "expiresIn,token,tokenType") throw new AuthError("identity_authority_unavailable", 503);
1534
- return {
1535
- tokenType: "Bearer",
1536
- token: value.token,
1537
- expiresAt: new Date(startedAt + value.expiresIn * 1e3)
1538
- };
1539
- }
1540
- //#endregion
1541
1449
  //#region ../../node_modules/.pnpm/jose@6.2.4/node_modules/jose/dist/webapi/lib/buffer_utils.js
1542
1450
  const encoder$1 = new TextEncoder();
1543
1451
  const decoder = new TextDecoder();
@@ -2586,6 +2494,139 @@ function decodeJwt(jwt) {
2586
2494
  return result;
2587
2495
  }
2588
2496
  //#endregion
2497
+ //#region src/organization-presence.ts
2498
+ const id$1 = /^[A-Za-z0-9_-]{1,128}$(?![\s\S])/;
2499
+ function presenceInput(input) {
2500
+ if (!input || typeof input.applicationId !== "string" || !id$1.test(input.applicationId) || !Array.isArray(input.userIds) || input.userIds.length < 1 || input.userIds.length > 50 || input.userIds.some((value) => typeof value !== "string" || !id$1.test(value)) || new Set(input.userIds).size !== input.userIds.length) throw new TypeError("Organization presence selection is invalid");
2501
+ return {
2502
+ applicationId: input.applicationId,
2503
+ userIds: [...input.userIds]
2504
+ };
2505
+ }
2506
+ function presenceProofActor(token, applicationId) {
2507
+ try {
2508
+ const claims = decodeJwt(token);
2509
+ if (typeof claims.sub !== "string" || !id$1.test(claims.sub) || typeof claims.sid !== "string" || !id$1.test(claims.sid) || claims.app !== applicationId) throw new Error("Invalid projection");
2510
+ return {
2511
+ userId: claims.sub,
2512
+ sessionId: claims.sid
2513
+ };
2514
+ } catch {
2515
+ throw new TypeError("Organization presence credential is invalid");
2516
+ }
2517
+ }
2518
+ function exact$4(value, keys) {
2519
+ return !!value && typeof value === "object" && !Array.isArray(value) && Object.keys(value).length === keys.length && keys.every((key) => Object.hasOwn(value, key));
2520
+ }
2521
+ function normalizePresence(value, organizationId, input, actor) {
2522
+ if (!exact$4(value, [
2523
+ "organizationId",
2524
+ "applicationId",
2525
+ "actor",
2526
+ "userIds",
2527
+ "checkedAt"
2528
+ ]) || value.organizationId !== organizationId || value.applicationId !== input.applicationId || !exact$4(value.actor, ["userId", "sessionId"]) || value.actor.userId !== actor.userId || value.actor.sessionId !== actor.sessionId || !Array.isArray(value.userIds) || value.userIds.length !== input.userIds.length || value.userIds.some((userId, index) => userId !== input.userIds[index]) || typeof value.checkedAt !== "string" || !/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$(?![\s\S])/.test(value.checkedAt) || Number.isNaN(Date.parse(value.checkedAt)) || new Date(value.checkedAt).toISOString() !== value.checkedAt) throw new AuthError("identity_authority_unavailable", 503);
2529
+ return {
2530
+ organizationId,
2531
+ applicationId: input.applicationId,
2532
+ actor: { ...actor },
2533
+ userIds: [...input.userIds],
2534
+ checkedAt: new Date(value.checkedAt)
2535
+ };
2536
+ }
2537
+ //#endregion
2538
+ //#region src/application-access.ts
2539
+ const id = /^[A-Za-z0-9_-]{1,128}$(?![\s\S])/;
2540
+ function applicationAccessInput(input) {
2541
+ if (!input || typeof input.applicationId !== "string" || !id.test(input.applicationId) || !Array.isArray(input.userIds) || input.userIds.length < 1 || input.userIds.length > 50 || input.userIds.some((value) => typeof value !== "string" || !id.test(value)) || new Set(input.userIds).size !== input.userIds.length) throw new TypeError("Application access input is invalid");
2542
+ return {
2543
+ applicationId: input.applicationId,
2544
+ userIds: [...input.userIds]
2545
+ };
2546
+ }
2547
+ function exact$3(value, keys) {
2548
+ return !!value && typeof value === "object" && !Array.isArray(value) && Object.keys(value).length === keys.length && keys.every((key) => Object.hasOwn(value, key));
2549
+ }
2550
+ function normalizeApplicationAccess(value, userIds) {
2551
+ const invalid = () => new AuthError("identity_authority_unavailable", 503);
2552
+ if (!exact$3(value, ["members"]) || !Array.isArray(value.members) || value.members.length !== userIds.length) throw invalid();
2553
+ return { members: value.members.map((member, index) => {
2554
+ if (!exact$3(member, [
2555
+ "userId",
2556
+ "latestAppSessionAdmittedAt",
2557
+ "activeAppSessionCount"
2558
+ ]) || member.userId !== userIds[index] || typeof member.activeAppSessionCount !== "number" || !Number.isSafeInteger(member.activeAppSessionCount) || member.activeAppSessionCount < 0 || member.latestAppSessionAdmittedAt !== null && (typeof member.latestAppSessionAdmittedAt !== "string" || !/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$(?![\s\S])/.test(member.latestAppSessionAdmittedAt) || Number.isNaN(Date.parse(member.latestAppSessionAdmittedAt)) || new Date(member.latestAppSessionAdmittedAt).toISOString() !== member.latestAppSessionAdmittedAt)) throw invalid();
2559
+ return {
2560
+ userId: member.userId,
2561
+ latestAppSessionAdmittedAt: member.latestAppSessionAdmittedAt,
2562
+ activeAppSessionCount: member.activeAppSessionCount
2563
+ };
2564
+ }) };
2565
+ }
2566
+ //#endregion
2567
+ //#region src/google-recovery.ts
2568
+ function object(value) {
2569
+ return value !== null && typeof value === "object" && !Array.isArray(value);
2570
+ }
2571
+ function validTicket(value) {
2572
+ return typeof value === "string" && /^[A-Za-z0-9_-]{43}$/.test(value);
2573
+ }
2574
+ function googleRecoveryInput(value, complete) {
2575
+ if (!object(value) || Object.keys(value).sort().join(",") !== (complete ? "idToken,recoveryToken" : "idToken") || !object(value.idToken) || Object.keys(value.idToken).some((key) => key !== "token" && key !== "nonce") || complete && !validTicket(value.recoveryToken)) throw new AuthError("invalid_request", 400);
2576
+ const social = normalizeSocialIdTokenInput({
2577
+ provider: "google",
2578
+ idToken: value.idToken.token,
2579
+ signUp: false,
2580
+ ...value.idToken.nonce === void 0 ? {} : { nonce: value.idToken.nonce }
2581
+ });
2582
+ return {
2583
+ idToken: {
2584
+ token: social.idToken,
2585
+ ...social.nonce === void 0 ? {} : { nonce: social.nonce }
2586
+ },
2587
+ ...complete ? { recoveryToken: value.recoveryToken } : {}
2588
+ };
2589
+ }
2590
+ function normalizeGoogleRecovery(value, now) {
2591
+ if (!object(value) || Object.keys(value).sort().join(",") !== "expiresAt,recoveryToken" || !validTicket(value.recoveryToken) || typeof value.expiresAt !== "string") throw authorityUnavailable();
2592
+ const expiresAt = Date.parse(value.expiresAt);
2593
+ if (!Number.isFinite(expiresAt) || expiresAt <= now || expiresAt > now + 10 * 6e4) throw authorityUnavailable();
2594
+ return {
2595
+ recoveryToken: value.recoveryToken,
2596
+ expiresAt: value.expiresAt
2597
+ };
2598
+ }
2599
+ function normalizeGoogleRecoveryCompletion(value) {
2600
+ if (!object(value) || Object.keys(value).join(",") !== "linked" || value.linked !== true) throw authorityUnavailable();
2601
+ return { linked: true };
2602
+ }
2603
+ function fromGoogleRecoveryError(value, status, retryAfter) {
2604
+ const code = object(value) ? value.code : void 0;
2605
+ if (status === 409 && code === "GOOGLE_RECOVERY_IN_PROGRESS") return new AuthError("google_recovery_in_progress", 409);
2606
+ if (status === 409 && code === "GOOGLE_RECOVERY_NOT_REQUIRED") return new AuthError("google_recovery_not_required", 409);
2607
+ if (status === 403 && code === "GOOGLE_RECOVERY_EMAIL_VERIFICATION_REQUIRED") return new AuthError("email_verification_required", 403);
2608
+ if (status === 400 && code === "GOOGLE_RECOVERY_INVALID") return new AuthError("google_recovery_invalid", 400);
2609
+ if (status === 410 && code === "GOOGLE_RECOVERY_EXPIRED") return new AuthError("google_recovery_expired", 410);
2610
+ if (status === 403 && code === "GOOGLE_RECOVERY_ACCOUNT_MISMATCH") return new AuthError("google_recovery_account_mismatch", 403);
2611
+ if (status === 401 && code === "GOOGLE_RECOVERY_FRESH_SIGN_IN_REQUIRED") return new AuthError("recent_sign_in_required", 401);
2612
+ if (code === "GOOGLE_RECOVERY_UNAVAILABLE") return authorityUnavailable();
2613
+ return fromAccountAuthorityError(value, status, retryAfter);
2614
+ }
2615
+ //#endregion
2616
+ //#region src/user-api/credential.ts
2617
+ function userApiApplication(input) {
2618
+ if (!input || typeof input.applicationId !== "string" || !/^[A-Za-z0-9_-]{1,128}$(?![\s\S])/.test(input.applicationId) || input.forceRefresh !== void 0 && typeof input.forceRefresh !== "boolean") throw new TypeError("User API credential input is invalid");
2619
+ return input.applicationId;
2620
+ }
2621
+ function normalizeUserApiCredential(value, startedAt) {
2622
+ if (!value || typeof value !== "object" || Array.isArray(value) || !("tokenType" in value) || value.tokenType !== "Bearer" || !("token" in value) || typeof value.token !== "string" || value.token.length + 7 > 16 * 1024 || !/^[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+$/.test(value.token) || !("expiresIn" in value) || typeof value.expiresIn !== "number" || !Number.isInteger(value.expiresIn) || value.expiresIn < 1 || value.expiresIn > 840 || Object.keys(value).sort().join(",") !== "expiresIn,token,tokenType") throw new AuthError("identity_authority_unavailable", 503);
2623
+ return {
2624
+ tokenType: "Bearer",
2625
+ token: value.token,
2626
+ expiresAt: new Date(startedAt + value.expiresIn * 1e3)
2627
+ };
2628
+ }
2629
+ //#endregion
2589
2630
  //#region src/user-api/verifier.ts
2590
2631
  const ID = /^[A-Za-z0-9_-]{1,128}$(?![\s\S])/;
2591
2632
  const KID = /^[A-Za-z0-9_-]{43}$(?![\s\S])/;
@@ -3394,6 +3435,46 @@ function createServerAuth(options) {
3394
3435
  getOrganization(organizationId) {
3395
3436
  return organizationRead(normalizeIdInput(organizationId), void 0, normalizeOrganization);
3396
3437
  },
3438
+ async authorizeOrganizationPresence(organizationId, input, serviceAssertion, options) {
3439
+ if (typeof serviceAssertion !== "string" || serviceAssertion.length > 16 * 1024 || !/^[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+$(?![\s\S])/.test(serviceAssertion)) throw new TypeError("Organization presence service assertion is invalid");
3440
+ const organization = normalizeIdInput(organizationId);
3441
+ const body = presenceInput(input);
3442
+ let applicationCredential;
3443
+ if (options !== void 0) {
3444
+ const supplied = options?.applicationCredential;
3445
+ if (typeof supplied !== "string" || supplied.length > 16 * 1024 || !/^[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+$(?![\s\S])/.test(supplied)) throw new TypeError("Organization presence credential is invalid");
3446
+ applicationCredential = supplied;
3447
+ } else {
3448
+ const startedAt = now();
3449
+ applicationCredential = normalizeUserApiCredential(await requestJson(joinURL(authOrigin, "api/v1/auth/user-api-credential"), {
3450
+ fetch: fetchImpl,
3451
+ timeoutMs,
3452
+ method: "POST",
3453
+ credentials,
3454
+ headers: {
3455
+ ...authHeaders(),
3456
+ "content-type": "application/json"
3457
+ },
3458
+ body: { applicationId: body.applicationId }
3459
+ }), startedAt).token;
3460
+ }
3461
+ const actor = presenceProofActor(applicationCredential, body.applicationId);
3462
+ return normalizePresence(await requestJson(joinURL(authOrigin, "api/v1/auth/organizations", organization, "presence/authorize"), {
3463
+ fetch: fetchImpl,
3464
+ timeoutMs,
3465
+ method: "POST",
3466
+ maxResponseBytes: 16 * 1024,
3467
+ credentials,
3468
+ headers: {
3469
+ ...authHeaders(!authorization),
3470
+ "content-type": "application/json",
3471
+ "x-finueva-application-credential": applicationCredential,
3472
+ "x-finueva-service-assertion": serviceAssertion
3473
+ },
3474
+ body,
3475
+ mapError: fromOrganizationReadAuthorityError
3476
+ }), organization, body, actor);
3477
+ },
3397
3478
  async getOrganizationMemberApplicationAccess(organizationId, input, serviceAssertion, options) {
3398
3479
  if (typeof serviceAssertion !== "string" || serviceAssertion.length > 16 * 1024 || !/^[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+$(?![\s\S])/.test(serviceAssertion)) throw new TypeError("Application access service assertion is invalid");
3399
3480
  const organization = normalizeIdInput(organizationId);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@finueva/auth",
3
- "version": "0.25.0",
3
+ "version": "0.26.0",
4
4
  "description": "Public browser and server SDK for Finueva Auth",
5
5
  "type": "module",
6
6
  "sideEffects": false,