@tearleads/client-sdk 0.1.105 → 0.1.107
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/Tearleads.js +5 -3
- package/Tearleads.js.map +1 -1
- package/client/blobs/index.d.ts +4 -0
- package/client/blobs/index.js +26 -7
- package/client/blobs/index.js.map +1 -1
- package/client/identity/index.d.ts +11 -2
- package/client/identity/index.js +80 -72
- package/client/identity/index.js.map +1 -1
- package/client/organizations/index.js +5 -2
- package/client/organizations/index.js.map +1 -1
- package/client/organizations/organizationMemberships.js +26 -18
- package/client/organizations/organizationMemberships.js.map +1 -1
- package/client/organizations/organizationReadModels.d.ts +9 -4
- package/client/organizations/organizationReadModels.js +20 -9
- package/client/organizations/organizationReadModels.js.map +1 -1
- package/client/session/index.js +6 -3
- package/client/session/index.js.map +1 -1
- package/client/session/sessionTypes.d.ts +1 -1
- package/client/session/sessionTypes.js.map +1 -1
- package/index.js +1 -1
- package/index.js.map +1 -1
- package/internal/api-client/ApiClient.d.ts +7 -0
- package/internal/crypto/organizationLeaveRequest.d.ts +1 -1
- package/internal/crypto/organizationLeaveRequest.js +9 -2
- package/internal/crypto/organizationLeaveRequest.js.map +1 -1
- package/internal/validators/operation/organizationMemberships.d.ts +7 -0
- package/internal/validators/operation/organizations.d.ts +56 -0
- package/internal/validators/response/organization.d.ts +91 -0
- package/internal/validators/response/organizationReadModel.d.ts +70 -0
- package/internal/validators/util/index.d.ts +1 -1
- package/internal/validators/util/index.js.map +1 -1
- package/internal/validators/util/organizationLeaveRequest.d.ts +25 -2
- package/internal/validators/util/organizationLeaveRequest.js +19 -3
- package/internal/validators/util/organizationLeaveRequest.js.map +1 -1
- package/package.json +1 -1
- package/workflows/organizations/memberships/leaveRequest.d.ts +6 -2
- package/workflows/organizations/memberships/leaveRequest.js +20 -5
- package/workflows/organizations/memberships/leaveRequest.js.map +1 -1
- package/workflows/organizations/memberships/leaveRequestMembersEvidence.js +80 -0
- package/workflows/organizations/memberships/leaveRequestMembersEvidence.js.map +1 -0
- package/workflows/organizations/memberships/leaveRequestMembership.d.ts +24 -0
- package/workflows/organizations/memberships/leaveRequestMembership.js +65 -0
- package/workflows/organizations/memberships/leaveRequestMembership.js.map +1 -0
- package/workflows/organizations/memberships/leaveRequestVerification.d.ts +15 -7
- package/workflows/organizations/memberships/leaveRequestVerification.js +18 -11
- package/workflows/organizations/memberships/leaveRequestVerification.js.map +1 -1
package/Tearleads.js
CHANGED
|
@@ -80,15 +80,17 @@ export class Tearleads {
|
|
|
80
80
|
this.network = new Network(options.online);
|
|
81
81
|
this.syncBillingGate = new SyncBillingGate();
|
|
82
82
|
let session = null;
|
|
83
|
-
this.identity = createIdentity(options.identity,
|
|
84
|
-
|
|
83
|
+
this.identity = createIdentity(options.identity, this.blobs, this.log, {
|
|
84
|
+
assertReadyForGeneration: () => {
|
|
85
85
|
if (this.database.status !== "ready") {
|
|
86
86
|
throw new Error("identity.generate requires a ready SQLite database.");
|
|
87
87
|
}
|
|
88
|
+
},
|
|
89
|
+
bootstrapLocalRootContainer: async (isCurrent) => {
|
|
88
90
|
if (!session) {
|
|
89
91
|
throw new Error("identity.generate requires an initialized session.");
|
|
90
92
|
}
|
|
91
|
-
return session.bootstrapLocalRootContainer();
|
|
93
|
+
return session.bootstrapLocalRootContainer(isCurrent);
|
|
92
94
|
},
|
|
93
95
|
getUserId: () => session?.userId ?? null,
|
|
94
96
|
});
|
package/Tearleads.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Tearleads.js","sourceRoot":"","sources":["Tearleads.ts"],"names":[],"mappings":"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","sourcesContent":["import { ApiClient, ApiRequestMetrics } from \"@tearleads/api-client\";\nimport { Blobs } from \"./client/blobs\";\nimport {\n type ContainerContents,\n createContainerContents,\n} from \"./client/containerContents\";\nimport { createDeviceFirst, type DeviceFirst } from \"./client/deviceFirst\";\nimport { createDocuments, type Documents } from \"./client/documents\";\nimport { logErrorToConsole } from \"./client/host/logger\";\nimport { createIdentity, type Identity } from \"./client/identity\";\nimport {\n createUserIdentities,\n type UserIdentities,\n} from \"./client/identity/userIdentities\";\nimport {\n createOrganizations,\n type Organizations,\n} from \"./client/organizations\";\nimport { createRoot, type Root, rootRuntimeOf } from \"./client/root\";\nimport { ApiVersion } from \"./client/runtime/apiVersion\";\nimport { Database } from \"./client/runtime/database\";\nimport { Events } from \"./client/runtime/events\";\nimport { Network } from \"./client/runtime/network\";\nimport { SyncBillingGate } from \"./client/runtime/syncBillingGate\";\nimport {\n createRuntime,\n type InternalRuntime,\n type Runtime,\n} from \"./client/runtime/workflowRuntime\";\nimport {\n createSecurityIncidentService,\n type SecurityIncidents,\n} from \"./client/securityIncidents\";\nimport { createSession } from \"./client/session\";\nimport type { Session } from \"./client/session/sessionTypes\";\nimport {\n type DocumentProjectorRegistry,\n resolveDocumentProjectorRegistry,\n} from \"./data/documents/documentKinds\";\nimport { createVerifiedManifestCitations } from \"./data/persistence/verifiedManifestBundlePersistence\";\nimport { createDomainScope, type DomainScope } from \"./data/shared/domainScope\";\nimport type { SecurityIncidentReporter } from \"./data/shared/securityIncidents\";\nimport { disposeDomainSyncCoordinator } from \"./data/sync/syncCoordinator\";\nimport { resolveIdentityTrustDomain } from \"./data/trustedUserIdentity\";\nimport type { TearleadsOptions } from \"./TearleadsOptions\";\n\nexport class Tearleads {\n readonly apiVersion = new ApiVersion();\n readonly apiRequests: ApiRequestMetrics;\n readonly blobs: Blobs;\n readonly database: Database;\n readonly deviceFirst: DeviceFirst;\n readonly documents: Documents;\n readonly events: Events;\n readonly containerContents: ContainerContents;\n readonly identity: Identity;\n readonly network: Network;\n readonly organizations: Organizations;\n readonly root: Root;\n readonly runtime: Runtime;\n readonly securityIncidents: SecurityIncidents;\n readonly session: Session;\n readonly syncBillingGate: SyncBillingGate;\n readonly userIdentities: UserIdentities;\n\n private readonly apiClient: ApiClient;\n private readonly documentProjectors: DocumentProjectorRegistry;\n private readonly disposeSecurityIncidents: () => void;\n private retirePrincipalHistoryProtection = () => {};\n // Tracks the storage/identity pair that owns domain-scoped runtime state.\n private domainScopeKey: string | null = null;\n // Recreated when the storage database or signing identity changes.\n private domainScopeValue: DomainScope = createDomainScope();\n private readonly logErrorHandler: (\n message: string | Error,\n cause?: unknown,\n ) => void;\n private readonly logHandler: (message: string) => void;\n private autoIdentityProvisioned = false;\n private autoIdentityProvisioningPromise: Promise<void> | null = null;\n private expiredSessionLoginPromise: Promise<boolean> | null = null;\n // Rebound to the workflow runtime once it exists; the session is created first.\n private pinLocalUserIdentity: InternalRuntime[\"pinLocalUserIdentity\"] =\n async () => {\n throw new Error(\"Trusted user identity runtime is not initialized\");\n };\n private primeProvisionedPrincipalHistory: InternalRuntime[\"primeProvisionedPrincipalHistory\"] =\n async () => undefined;\n private boundUserId: InternalRuntime[\"boundUserId\"] = async () => {\n throw new Error(\"Trusted user identity runtime is not initialized\");\n };\n\n constructor(options: TearleadsOptions = {}) {\n const apiBaseUrl = options.apiBaseUrl ?? \"\";\n this.apiRequests = options.apiRequestMetrics ?? new ApiRequestMetrics();\n this.apiClient = this.createApiClient(apiBaseUrl);\n this.blobs = new Blobs(options.blobStore, options.blobStoreFactory);\n this.database = new Database(options.database);\n this.documentProjectors = resolveDocumentProjectorRegistry(\n options.documentProjectors,\n );\n this.events = new Events(options.events, () =>\n this.apiClient.clearWriterProjectionCaches(),\n );\n this.logHandler = options.logger?.log ?? (() => undefined);\n this.logErrorHandler = options.logger?.logError ?? logErrorToConsole;\n const identityTrustDomain = resolveIdentityTrustDomain({\n apiBaseUrl,\n identityTrustDomain: options.identityTrustDomain,\n });\n const security = this.createSecurityIncidents(identityTrustDomain, options);\n this.securityIncidents = security.incidents;\n this.disposeSecurityIncidents = security.dispose;\n this.network = new Network(options.online);\n this.syncBillingGate = new SyncBillingGate();\n let session: Session | null = null;\n this.identity = createIdentity(\n options.identity,\n (signingFingerprint) =>\n this.blobs.updateIdentityNamespace(signingFingerprint),\n this.log,\n {\n bootstrapLocalRootContainer: async () => {\n if (this.database.status !== \"ready\") {\n throw new Error(\n \"identity.generate requires a ready SQLite database.\",\n );\n }\n if (!session) {\n throw new Error(\n \"identity.generate requires an initialized session.\",\n );\n }\n\n return session.bootstrapLocalRootContainer();\n },\n getUserId: () => session?.userId ?? null,\n },\n );\n session = this.createClientSession(options, security.report);\n this.session = session;\n const runtime = this.createWorkflowRuntime(\n identityTrustDomain,\n options,\n security.report,\n );\n this.bindTrustedIdentityRuntime(runtime);\n this.runtime = runtime.publicRuntime;\n this.documents = createDocuments({\n getDefaultContainerId: () => this.session.containerId,\n runtime,\n });\n this.containerContents = createContainerContents(runtime);\n this.deviceFirst = createDeviceFirst(runtime, this.containerContents);\n this.organizations = createOrganizations(\n runtime,\n this.containerContents,\n () => this.deviceFirst.open().reconciler,\n );\n this.root = createRoot(rootRuntimeOf(runtime, this.session));\n this.userIdentities = createUserIdentities({\n getOrganizationId: () => this.session.organizationId,\n reportSecurityIncident: security.report,\n identityLinks: runtime.identityLinks,\n log: this.log,\n resolveTrustedUserIdentity: (userId) =>\n runtime.workflowInput().resolveTrustedUserIdentity(userId),\n });\n\n this.configureApiClientCallbacks();\n\n if (options.identityProvisioning === \"auto\") {\n this.startAutomaticIdentityProvisioning();\n }\n }\n\n /** Durable incident records in this database, reported to the host's listener. */\n private createSecurityIncidents(\n trustDomain: string | null,\n options: TearleadsOptions,\n ) {\n return createSecurityIncidentService({\n database: this.database,\n logError: this.logError,\n onIncident: options.onSecurityIncident,\n trustDomain,\n });\n }\n\n /** Trust callbacks reach the workflow runtime, which is created later. */\n private createClientSession(\n options: TearleadsOptions,\n reportSecurityIncident: SecurityIncidentReporter,\n ): Session {\n return createSession({\n api: this.apiClient,\n database: this.database,\n documentProjectors: this.documentProjectors,\n identity: this.identity,\n log: this.log,\n logError: this.logError,\n boundUserIdForSigningKey: (signingKeyFingerprint) =>\n this.boundUserId(signingKeyFingerprint),\n onUserIdentityAvailable: (userId, candidate) =>\n this.pinLocalUserIdentity(userId, candidate),\n primeProvisionedPrincipalHistory: (input) =>\n this.primeProvisionedPrincipalHistory(input),\n provisionedSystemContainers: options.provisionedSystemContainers,\n reportSecurityIncident,\n });\n }\n\n private createApiClient(apiBaseUrl: string): ApiClient {\n return new ApiClient(apiBaseUrl, {\n metrics: this.apiRequests,\n getIdentity: () => this.identity.signingFingerprint,\n });\n }\n\n /** Rebinds the session's trust callbacks once the runtime exists. */\n private bindTrustedIdentityRuntime(runtime: InternalRuntime): void {\n this.retirePrincipalHistoryProtection =\n runtime.retirePrincipalHistoryProtection;\n this.pinLocalUserIdentity = (userId, candidate) =>\n runtime.pinLocalUserIdentity(userId, candidate);\n this.primeProvisionedPrincipalHistory =\n runtime.primeProvisionedPrincipalHistory;\n this.boundUserId = (signingKeyFingerprint) =>\n runtime.boundUserId(signingKeyFingerprint);\n }\n\n private configureApiClientCallbacks(): void {\n // Projection reads cite bundles this identity's database already verified.\n this.apiClient.setVerifiedManifestCitations(\n createVerifiedManifestCitations(() => this.database.execSql),\n );\n this.apiClient.setOnError((message) => this.logError(message));\n // An authoritative host source owns connectivity. Without one, request\n // outcomes remain reachability hints. Browser and native app bindings both\n // install authoritative sources so a backend outage cannot stop retries.\n this.apiClient.setOnNetworkError(() =>\n this.network.reportReachability(false),\n );\n this.apiClient.setOnNetworkSuccess(() =>\n this.network.reportReachability(true),\n );\n this.apiClient.setOnApiVersion((version) =>\n this.apiVersion.observe(version),\n );\n this.apiClient.setOnSessionExpired(() => this.loginAfterSessionExpired());\n this.apiClient.setOnPaymentRequired((organizationId) =>\n this.syncBillingGate.notifyPaymentRequired(organizationId),\n );\n }\n\n private createWorkflowRuntime(\n identityTrustDomain: string | null,\n options: TearleadsOptions,\n reportSecurityIncident: SecurityIncidentReporter,\n ): InternalRuntime {\n return createRuntime({\n api: this.apiClient,\n blobs: this.blobs,\n database: this.database,\n documentProjectors: this.documentProjectors,\n events: this.events,\n getDomainScope: () => this.domainScope,\n identity: this.identity,\n identityTrustDomain,\n log: this.log,\n logError: this.logError,\n network: this.network,\n peerScope: options.peerScope ?? null,\n principalHistoryKeyProvider: options.principalHistoryKeyProvider,\n principalMutationTimeoutMs: options.principalMutationTimeoutMs,\n reportSecurityIncident,\n session: this.session,\n syncBillingGate: this.syncBillingGate,\n });\n }\n\n log = (message: string): void => {\n this.logHandler(message);\n };\n\n // Preserve the host's return value so best-effort callers can also catch\n // rejected promises from async loggers accepted by the void callback type.\n logError = (message: string | Error, cause?: unknown): void =>\n this.logErrorHandler(message, cause);\n\n /**\n * A single-use ticket to authenticate the server-events websocket handshake\n * (which cannot carry the bearer header): the one login returned for the\n * first connect of that session, otherwise a freshly minted one. Returns\n * null when no session is active. The caller appends it to the websocket URL.\n */\n requestWebSocketTicket(): Promise<string | null> {\n return this.apiClient.requestWebSocketTicket();\n }\n\n get domainScope(): DomainScope {\n const nextScopeKey = JSON.stringify([\n this.database.id,\n this.identity.signingFingerprint,\n ]);\n if (this.domainScopeKey !== nextScopeKey) {\n this.domainScopeKey = nextScopeKey;\n this.domainScopeValue = createDomainScope();\n }\n\n return this.domainScopeValue;\n }\n\n /**\n * Tear down background work for the active domain scope: stop the reconciler\n * and force-stop the sync coordinator pump, then drop the coordinator from\n * its registry. Hosts call this from unmount/cleanup so a pump cannot outlive\n * the React tree that created it. A later access for the same scope rebuilds\n * fresh state.\n */\n dispose(): void {\n const domainScope = this.domainScope;\n this.disposeSecurityIncidents();\n this.retirePrincipalHistoryProtection();\n this.deviceFirst.dispose();\n disposeDomainSyncCoordinator(domainScope);\n }\n\n private loginAfterSessionExpired(): Promise<boolean> {\n if (!this.session.authToken || !this.identity.signingKeyPair) {\n this.session.logout();\n return Promise.resolve(false);\n }\n\n // The API client replays requests the expired session sent, so a login is\n // their renewal only when the loaded keys authenticate that known user.\n const expiredUserId = this.session.userId;\n this.expiredSessionLoginPromise ??= this.session\n .login()\n .then(\n (renewed) =>\n renewed &&\n expiredUserId !== null &&\n this.session.userId === expiredUserId,\n )\n .finally(() => {\n this.expiredSessionLoginPromise = null;\n });\n return this.expiredSessionLoginPromise;\n }\n\n private startAutomaticIdentityProvisioning(): void {\n let unsubscribe: (() => void) | null = null;\n const stopProvisioningListener = () => {\n unsubscribe?.();\n unsubscribe = null;\n };\n const maybeProvisionIdentity = () => {\n if (this.autoIdentityProvisioned || this.identity.signingKeyPair) {\n stopProvisioningListener();\n return;\n }\n\n if (\n this.autoIdentityProvisioningPromise ||\n this.database.status !== \"ready\"\n ) {\n return;\n }\n\n this.autoIdentityProvisioningPromise = this.identity\n .generate()\n .then(() => {\n this.autoIdentityProvisioned = true;\n stopProvisioningListener();\n })\n .catch((error: unknown) => {\n try {\n this.logError(\"Automatic identity provisioning failed\", error);\n } catch {\n // Keep background provisioning failures from surfacing as unhandled rejections.\n }\n })\n .finally(() => {\n this.autoIdentityProvisioningPromise = null;\n });\n };\n\n unsubscribe = this.database.subscribe(maybeProvisionIdentity);\n void Promise.resolve().then(maybeProvisionIdentity);\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"Tearleads.js","sourceRoot":"","sources":["Tearleads.ts"],"names":[],"mappings":"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","sourcesContent":["import { ApiClient, ApiRequestMetrics } from \"@tearleads/api-client\";\nimport { Blobs } from \"./client/blobs\";\nimport {\n type ContainerContents,\n createContainerContents,\n} from \"./client/containerContents\";\nimport { createDeviceFirst, type DeviceFirst } from \"./client/deviceFirst\";\nimport { createDocuments, type Documents } from \"./client/documents\";\nimport { logErrorToConsole } from \"./client/host/logger\";\nimport { createIdentity, type Identity } from \"./client/identity\";\nimport {\n createUserIdentities,\n type UserIdentities,\n} from \"./client/identity/userIdentities\";\nimport {\n createOrganizations,\n type Organizations,\n} from \"./client/organizations\";\nimport { createRoot, type Root, rootRuntimeOf } from \"./client/root\";\nimport { ApiVersion } from \"./client/runtime/apiVersion\";\nimport { Database } from \"./client/runtime/database\";\nimport { Events } from \"./client/runtime/events\";\nimport { Network } from \"./client/runtime/network\";\nimport { SyncBillingGate } from \"./client/runtime/syncBillingGate\";\nimport {\n createRuntime,\n type InternalRuntime,\n type Runtime,\n} from \"./client/runtime/workflowRuntime\";\nimport {\n createSecurityIncidentService,\n type SecurityIncidents,\n} from \"./client/securityIncidents\";\nimport { createSession } from \"./client/session\";\nimport type { Session } from \"./client/session/sessionTypes\";\nimport {\n type DocumentProjectorRegistry,\n resolveDocumentProjectorRegistry,\n} from \"./data/documents/documentKinds\";\nimport { createVerifiedManifestCitations } from \"./data/persistence/verifiedManifestBundlePersistence\";\nimport { createDomainScope, type DomainScope } from \"./data/shared/domainScope\";\nimport type { SecurityIncidentReporter } from \"./data/shared/securityIncidents\";\nimport { disposeDomainSyncCoordinator } from \"./data/sync/syncCoordinator\";\nimport { resolveIdentityTrustDomain } from \"./data/trustedUserIdentity\";\nimport type { TearleadsOptions } from \"./TearleadsOptions\";\n\nexport class Tearleads {\n readonly apiVersion = new ApiVersion();\n readonly apiRequests: ApiRequestMetrics;\n readonly blobs: Blobs;\n readonly database: Database;\n readonly deviceFirst: DeviceFirst;\n readonly documents: Documents;\n readonly events: Events;\n readonly containerContents: ContainerContents;\n readonly identity: Identity;\n readonly network: Network;\n readonly organizations: Organizations;\n readonly root: Root;\n readonly runtime: Runtime;\n readonly securityIncidents: SecurityIncidents;\n readonly session: Session;\n readonly syncBillingGate: SyncBillingGate;\n readonly userIdentities: UserIdentities;\n\n private readonly apiClient: ApiClient;\n private readonly documentProjectors: DocumentProjectorRegistry;\n private readonly disposeSecurityIncidents: () => void;\n private retirePrincipalHistoryProtection = () => {};\n // Tracks the storage/identity pair that owns domain-scoped runtime state.\n private domainScopeKey: string | null = null;\n // Recreated when the storage database or signing identity changes.\n private domainScopeValue: DomainScope = createDomainScope();\n private readonly logErrorHandler: (\n message: string | Error,\n cause?: unknown,\n ) => void;\n private readonly logHandler: (message: string) => void;\n private autoIdentityProvisioned = false;\n private autoIdentityProvisioningPromise: Promise<void> | null = null;\n private expiredSessionLoginPromise: Promise<boolean> | null = null;\n // Rebound to the workflow runtime once it exists; the session is created first.\n private pinLocalUserIdentity: InternalRuntime[\"pinLocalUserIdentity\"] =\n async () => {\n throw new Error(\"Trusted user identity runtime is not initialized\");\n };\n private primeProvisionedPrincipalHistory: InternalRuntime[\"primeProvisionedPrincipalHistory\"] =\n async () => undefined;\n private boundUserId: InternalRuntime[\"boundUserId\"] = async () => {\n throw new Error(\"Trusted user identity runtime is not initialized\");\n };\n\n constructor(options: TearleadsOptions = {}) {\n const apiBaseUrl = options.apiBaseUrl ?? \"\";\n this.apiRequests = options.apiRequestMetrics ?? new ApiRequestMetrics();\n this.apiClient = this.createApiClient(apiBaseUrl);\n this.blobs = new Blobs(options.blobStore, options.blobStoreFactory);\n this.database = new Database(options.database);\n this.documentProjectors = resolveDocumentProjectorRegistry(\n options.documentProjectors,\n );\n this.events = new Events(options.events, () =>\n this.apiClient.clearWriterProjectionCaches(),\n );\n this.logHandler = options.logger?.log ?? (() => undefined);\n this.logErrorHandler = options.logger?.logError ?? logErrorToConsole;\n const identityTrustDomain = resolveIdentityTrustDomain({\n apiBaseUrl,\n identityTrustDomain: options.identityTrustDomain,\n });\n const security = this.createSecurityIncidents(identityTrustDomain, options);\n this.securityIncidents = security.incidents;\n this.disposeSecurityIncidents = security.dispose;\n this.network = new Network(options.online);\n this.syncBillingGate = new SyncBillingGate();\n let session: Session | null = null;\n this.identity = createIdentity(options.identity, this.blobs, this.log, {\n assertReadyForGeneration: () => {\n if (this.database.status !== \"ready\") {\n throw new Error(\n \"identity.generate requires a ready SQLite database.\",\n );\n }\n },\n bootstrapLocalRootContainer: async (isCurrent) => {\n if (!session) {\n throw new Error(\"identity.generate requires an initialized session.\");\n }\n\n return session.bootstrapLocalRootContainer(isCurrent);\n },\n getUserId: () => session?.userId ?? null,\n });\n session = this.createClientSession(options, security.report);\n this.session = session;\n const runtime = this.createWorkflowRuntime(\n identityTrustDomain,\n options,\n security.report,\n );\n this.bindTrustedIdentityRuntime(runtime);\n this.runtime = runtime.publicRuntime;\n this.documents = createDocuments({\n getDefaultContainerId: () => this.session.containerId,\n runtime,\n });\n this.containerContents = createContainerContents(runtime);\n this.deviceFirst = createDeviceFirst(runtime, this.containerContents);\n this.organizations = createOrganizations(\n runtime,\n this.containerContents,\n () => this.deviceFirst.open().reconciler,\n );\n this.root = createRoot(rootRuntimeOf(runtime, this.session));\n this.userIdentities = createUserIdentities({\n getOrganizationId: () => this.session.organizationId,\n reportSecurityIncident: security.report,\n identityLinks: runtime.identityLinks,\n log: this.log,\n resolveTrustedUserIdentity: (userId) =>\n runtime.workflowInput().resolveTrustedUserIdentity(userId),\n });\n\n this.configureApiClientCallbacks();\n\n if (options.identityProvisioning === \"auto\") {\n this.startAutomaticIdentityProvisioning();\n }\n }\n\n /** Durable incident records in this database, reported to the host's listener. */\n private createSecurityIncidents(\n trustDomain: string | null,\n options: TearleadsOptions,\n ) {\n return createSecurityIncidentService({\n database: this.database,\n logError: this.logError,\n onIncident: options.onSecurityIncident,\n trustDomain,\n });\n }\n\n /** Trust callbacks reach the workflow runtime, which is created later. */\n private createClientSession(\n options: TearleadsOptions,\n reportSecurityIncident: SecurityIncidentReporter,\n ): Session {\n return createSession({\n api: this.apiClient,\n database: this.database,\n documentProjectors: this.documentProjectors,\n identity: this.identity,\n log: this.log,\n logError: this.logError,\n boundUserIdForSigningKey: (signingKeyFingerprint) =>\n this.boundUserId(signingKeyFingerprint),\n onUserIdentityAvailable: (userId, candidate) =>\n this.pinLocalUserIdentity(userId, candidate),\n primeProvisionedPrincipalHistory: (input) =>\n this.primeProvisionedPrincipalHistory(input),\n provisionedSystemContainers: options.provisionedSystemContainers,\n reportSecurityIncident,\n });\n }\n\n private createApiClient(apiBaseUrl: string): ApiClient {\n return new ApiClient(apiBaseUrl, {\n metrics: this.apiRequests,\n getIdentity: () => this.identity.signingFingerprint,\n });\n }\n\n /** Rebinds the session's trust callbacks once the runtime exists. */\n private bindTrustedIdentityRuntime(runtime: InternalRuntime): void {\n this.retirePrincipalHistoryProtection =\n runtime.retirePrincipalHistoryProtection;\n this.pinLocalUserIdentity = (userId, candidate) =>\n runtime.pinLocalUserIdentity(userId, candidate);\n this.primeProvisionedPrincipalHistory =\n runtime.primeProvisionedPrincipalHistory;\n this.boundUserId = (signingKeyFingerprint) =>\n runtime.boundUserId(signingKeyFingerprint);\n }\n\n private configureApiClientCallbacks(): void {\n // Projection reads cite bundles this identity's database already verified.\n this.apiClient.setVerifiedManifestCitations(\n createVerifiedManifestCitations(() => this.database.execSql),\n );\n this.apiClient.setOnError((message) => this.logError(message));\n // An authoritative host source owns connectivity. Without one, request\n // outcomes remain reachability hints. Browser and native app bindings both\n // install authoritative sources so a backend outage cannot stop retries.\n this.apiClient.setOnNetworkError(() =>\n this.network.reportReachability(false),\n );\n this.apiClient.setOnNetworkSuccess(() =>\n this.network.reportReachability(true),\n );\n this.apiClient.setOnApiVersion((version) =>\n this.apiVersion.observe(version),\n );\n this.apiClient.setOnSessionExpired(() => this.loginAfterSessionExpired());\n this.apiClient.setOnPaymentRequired((organizationId) =>\n this.syncBillingGate.notifyPaymentRequired(organizationId),\n );\n }\n\n private createWorkflowRuntime(\n identityTrustDomain: string | null,\n options: TearleadsOptions,\n reportSecurityIncident: SecurityIncidentReporter,\n ): InternalRuntime {\n return createRuntime({\n api: this.apiClient,\n blobs: this.blobs,\n database: this.database,\n documentProjectors: this.documentProjectors,\n events: this.events,\n getDomainScope: () => this.domainScope,\n identity: this.identity,\n identityTrustDomain,\n log: this.log,\n logError: this.logError,\n network: this.network,\n peerScope: options.peerScope ?? null,\n principalHistoryKeyProvider: options.principalHistoryKeyProvider,\n principalMutationTimeoutMs: options.principalMutationTimeoutMs,\n reportSecurityIncident,\n session: this.session,\n syncBillingGate: this.syncBillingGate,\n });\n }\n\n log = (message: string): void => {\n this.logHandler(message);\n };\n\n // Preserve the host's return value so best-effort callers can also catch\n // rejected promises from async loggers accepted by the void callback type.\n logError = (message: string | Error, cause?: unknown): void =>\n this.logErrorHandler(message, cause);\n\n /**\n * A single-use ticket to authenticate the server-events websocket handshake\n * (which cannot carry the bearer header): the one login returned for the\n * first connect of that session, otherwise a freshly minted one. Returns\n * null when no session is active. The caller appends it to the websocket URL.\n */\n requestWebSocketTicket(): Promise<string | null> {\n return this.apiClient.requestWebSocketTicket();\n }\n\n get domainScope(): DomainScope {\n const nextScopeKey = JSON.stringify([\n this.database.id,\n this.identity.signingFingerprint,\n ]);\n if (this.domainScopeKey !== nextScopeKey) {\n this.domainScopeKey = nextScopeKey;\n this.domainScopeValue = createDomainScope();\n }\n\n return this.domainScopeValue;\n }\n\n /**\n * Tear down background work for the active domain scope: stop the reconciler\n * and force-stop the sync coordinator pump, then drop the coordinator from\n * its registry. Hosts call this from unmount/cleanup so a pump cannot outlive\n * the React tree that created it. A later access for the same scope rebuilds\n * fresh state.\n */\n dispose(): void {\n const domainScope = this.domainScope;\n this.disposeSecurityIncidents();\n this.retirePrincipalHistoryProtection();\n this.deviceFirst.dispose();\n disposeDomainSyncCoordinator(domainScope);\n }\n\n private loginAfterSessionExpired(): Promise<boolean> {\n if (!this.session.authToken || !this.identity.signingKeyPair) {\n this.session.logout();\n return Promise.resolve(false);\n }\n\n // The API client replays requests the expired session sent, so a login is\n // their renewal only when the loaded keys authenticate that known user.\n const expiredUserId = this.session.userId;\n this.expiredSessionLoginPromise ??= this.session\n .login()\n .then(\n (renewed) =>\n renewed &&\n expiredUserId !== null &&\n this.session.userId === expiredUserId,\n )\n .finally(() => {\n this.expiredSessionLoginPromise = null;\n });\n return this.expiredSessionLoginPromise;\n }\n\n private startAutomaticIdentityProvisioning(): void {\n let unsubscribe: (() => void) | null = null;\n const stopProvisioningListener = () => {\n unsubscribe?.();\n unsubscribe = null;\n };\n const maybeProvisionIdentity = () => {\n if (this.autoIdentityProvisioned || this.identity.signingKeyPair) {\n stopProvisioningListener();\n return;\n }\n\n if (\n this.autoIdentityProvisioningPromise ||\n this.database.status !== \"ready\"\n ) {\n return;\n }\n\n this.autoIdentityProvisioningPromise = this.identity\n .generate()\n .then(() => {\n this.autoIdentityProvisioned = true;\n stopProvisioningListener();\n })\n .catch((error: unknown) => {\n try {\n this.logError(\"Automatic identity provisioning failed\", error);\n } catch {\n // Keep background provisioning failures from surfacing as unhandled rejections.\n }\n })\n .finally(() => {\n this.autoIdentityProvisioningPromise = null;\n });\n };\n\n unsubscribe = this.database.subscribe(maybeProvisionIdentity);\n void Promise.resolve().then(maybeProvisionIdentity);\n }\n}\n"]}
|
package/client/blobs/index.d.ts
CHANGED
|
@@ -1,13 +1,17 @@
|
|
|
1
1
|
import type { BlobStore } from "../../data/blobs/blobContracts.js";
|
|
2
|
+
import type { PreparedIdentityChange } from "../identity/index.js";
|
|
2
3
|
export type BlobStoreFactory = (namespace: string) => BlobStore;
|
|
3
4
|
export declare class Blobs {
|
|
4
5
|
private readonly ephemeralStore;
|
|
5
6
|
private identityScoped;
|
|
6
7
|
private readonly createIdentityStore;
|
|
7
8
|
private storeValue;
|
|
9
|
+
private revision;
|
|
8
10
|
constructor(store?: BlobStore | undefined, createIdentityStore?: BlobStoreFactory);
|
|
9
11
|
get store(): BlobStore;
|
|
10
12
|
useEphemeralStore(): void;
|
|
11
13
|
useIdentityNamespace(signingFingerprint: string): void;
|
|
12
14
|
updateIdentityNamespace(signingFingerprint: string | null): void;
|
|
15
|
+
/** @internal Prepare storage for the identity service; hosts use namespace methods. */
|
|
16
|
+
prepareIdentityChange(signingFingerprint: string | null): PreparedIdentityChange;
|
|
13
17
|
}
|
package/client/blobs/index.js
CHANGED
|
@@ -5,6 +5,8 @@ export class Blobs {
|
|
|
5
5
|
identityScoped = false;
|
|
6
6
|
createIdentityStore;
|
|
7
7
|
storeValue;
|
|
8
|
+
// Only explicit host switches invalidate prepared identity storage.
|
|
9
|
+
revision = 0;
|
|
8
10
|
constructor(store, createIdentityStore = createBlobStore) {
|
|
9
11
|
this.createIdentityStore = createIdentityStore;
|
|
10
12
|
this.storeValue = store ?? this.ephemeralStore;
|
|
@@ -13,21 +15,38 @@ export class Blobs {
|
|
|
13
15
|
return this.storeValue;
|
|
14
16
|
}
|
|
15
17
|
useEphemeralStore() {
|
|
18
|
+
this.revision += 1;
|
|
16
19
|
this.identityScoped = false;
|
|
17
20
|
this.storeValue = this.ephemeralStore;
|
|
18
21
|
}
|
|
19
22
|
useIdentityNamespace(signingFingerprint) {
|
|
23
|
+
const store = this.createIdentityStore(signingFingerprint);
|
|
24
|
+
this.revision += 1;
|
|
20
25
|
this.identityScoped = true;
|
|
21
|
-
this.storeValue =
|
|
26
|
+
this.storeValue = store;
|
|
22
27
|
}
|
|
23
28
|
updateIdentityNamespace(signingFingerprint) {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
29
|
+
const prepared = this.prepareIdentityChange(signingFingerprint);
|
|
30
|
+
this.revision += 1;
|
|
31
|
+
prepared.commit();
|
|
32
|
+
}
|
|
33
|
+
/** @internal Prepare storage for the identity service; hosts use namespace methods. */
|
|
34
|
+
prepareIdentityChange(signingFingerprint) {
|
|
35
|
+
const revision = this.revision;
|
|
36
|
+
const isCurrent = () => this.revision === revision;
|
|
37
|
+
if (!this.identityScoped && this.storeValue !== this.ephemeralStore) {
|
|
38
|
+
return { isCurrent, commit: () => undefined };
|
|
30
39
|
}
|
|
40
|
+
const store = signingFingerprint
|
|
41
|
+
? this.createIdentityStore(signingFingerprint)
|
|
42
|
+
: this.ephemeralStore;
|
|
43
|
+
return {
|
|
44
|
+
isCurrent,
|
|
45
|
+
commit: () => {
|
|
46
|
+
this.identityScoped = signingFingerprint !== null;
|
|
47
|
+
this.storeValue = store;
|
|
48
|
+
},
|
|
49
|
+
};
|
|
31
50
|
}
|
|
32
51
|
}
|
|
33
52
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,MAAM,kCAAkC,CAAC;AACnE,OAAO,EAAE,qBAAqB,EAAE,MAAM,kCAAkC,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,MAAM,kCAAkC,CAAC;AACnE,OAAO,EAAE,qBAAqB,EAAE,MAAM,kCAAkC,CAAC;AAKzE,MAAM,OAAO,KAAK;IACC,cAAc,GAAG,qBAAqB,EAAE,CAAC;IAClD,cAAc,GAAG,KAAK,CAAC;IACd,mBAAmB,CAAmB;IAC/C,UAAU,CAAY;IAC9B,oEAAoE;IAC5D,QAAQ,GAAG,CAAC,CAAC;IAErB,YACE,KAA6B,EAC7B,sBAAwC,eAAe;QAEvD,IAAI,CAAC,mBAAmB,GAAG,mBAAmB,CAAC;QAC/C,IAAI,CAAC,UAAU,GAAG,KAAK,IAAI,IAAI,CAAC,cAAc,CAAC;IACjD,CAAC;IAED,IAAI,KAAK;QACP,OAAO,IAAI,CAAC,UAAU,CAAC;IACzB,CAAC;IAED,iBAAiB;QACf,IAAI,CAAC,QAAQ,IAAI,CAAC,CAAC;QACnB,IAAI,CAAC,cAAc,GAAG,KAAK,CAAC;QAC5B,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,cAAc,CAAC;IACxC,CAAC;IAED,oBAAoB,CAAC,kBAA0B;QAC7C,MAAM,KAAK,GAAG,IAAI,CAAC,mBAAmB,CAAC,kBAAkB,CAAC,CAAC;QAC3D,IAAI,CAAC,QAAQ,IAAI,CAAC,CAAC;QACnB,IAAI,CAAC,cAAc,GAAG,IAAI,CAAC;QAC3B,IAAI,CAAC,UAAU,GAAG,KAAK,CAAC;IAC1B,CAAC;IAED,uBAAuB,CAAC,kBAAiC;QACvD,MAAM,QAAQ,GAAG,IAAI,CAAC,qBAAqB,CAAC,kBAAkB,CAAC,CAAC;QAChE,IAAI,CAAC,QAAQ,IAAI,CAAC,CAAC;QACnB,QAAQ,CAAC,MAAM,EAAE,CAAC;IACpB,CAAC;IAED,uFAAuF;IACvF,qBAAqB,CACnB,kBAAiC;QAEjC,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC;QAC/B,MAAM,SAAS,GAAG,GAAG,EAAE,CAAC,IAAI,CAAC,QAAQ,KAAK,QAAQ,CAAC;QACnD,IAAI,CAAC,IAAI,CAAC,cAAc,IAAI,IAAI,CAAC,UAAU,KAAK,IAAI,CAAC,cAAc,EAAE,CAAC;YACpE,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,SAAS,EAAE,CAAC;QAChD,CAAC;QACD,MAAM,KAAK,GAAG,kBAAkB;YAC9B,CAAC,CAAC,IAAI,CAAC,mBAAmB,CAAC,kBAAkB,CAAC;YAC9C,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC;QACxB,OAAO;YACL,SAAS;YACT,MAAM,EAAE,GAAG,EAAE;gBACX,IAAI,CAAC,cAAc,GAAG,kBAAkB,KAAK,IAAI,CAAC;gBAClD,IAAI,CAAC,UAAU,GAAG,KAAK,CAAC;YAC1B,CAAC;SACF,CAAC;IACJ,CAAC;CACF","sourcesContent":["import type { BlobStore } from \"../../data/blobs/blobContracts\";\nimport { createBlobStore } from \"../../data/blobs/createBlobStore\";\nimport { createMemoryBlobStore } from \"../../data/blobs/memoryBlobStore\";\nimport type { PreparedIdentityChange } from \"../identity\";\n\nexport type BlobStoreFactory = (namespace: string) => BlobStore;\n\nexport class Blobs {\n private readonly ephemeralStore = createMemoryBlobStore();\n private identityScoped = false;\n private readonly createIdentityStore: BlobStoreFactory;\n private storeValue: BlobStore;\n // Only explicit host switches invalidate prepared identity storage.\n private revision = 0;\n\n constructor(\n store?: BlobStore | undefined,\n createIdentityStore: BlobStoreFactory = createBlobStore,\n ) {\n this.createIdentityStore = createIdentityStore;\n this.storeValue = store ?? this.ephemeralStore;\n }\n\n get store(): BlobStore {\n return this.storeValue;\n }\n\n useEphemeralStore(): void {\n this.revision += 1;\n this.identityScoped = false;\n this.storeValue = this.ephemeralStore;\n }\n\n useIdentityNamespace(signingFingerprint: string): void {\n const store = this.createIdentityStore(signingFingerprint);\n this.revision += 1;\n this.identityScoped = true;\n this.storeValue = store;\n }\n\n updateIdentityNamespace(signingFingerprint: string | null): void {\n const prepared = this.prepareIdentityChange(signingFingerprint);\n this.revision += 1;\n prepared.commit();\n }\n\n /** @internal Prepare storage for the identity service; hosts use namespace methods. */\n prepareIdentityChange(\n signingFingerprint: string | null,\n ): PreparedIdentityChange {\n const revision = this.revision;\n const isCurrent = () => this.revision === revision;\n if (!this.identityScoped && this.storeValue !== this.ephemeralStore) {\n return { isCurrent, commit: () => undefined };\n }\n const store = signingFingerprint\n ? this.createIdentityStore(signingFingerprint)\n : this.ephemeralStore;\n return {\n isCurrent,\n commit: () => {\n this.identityScoped = signingFingerprint !== null;\n this.storeValue = store;\n },\n };\n }\n}\n"]}
|
|
@@ -40,11 +40,20 @@ export interface Identity {
|
|
|
40
40
|
subscribe(listener: IdentityListener): () => void;
|
|
41
41
|
}
|
|
42
42
|
interface IdentityRuntimeHooks {
|
|
43
|
-
|
|
43
|
+
assertReadyForGeneration?: (() => void) | undefined;
|
|
44
|
+
bootstrapLocalRootContainer?: ((isCurrent: () => boolean) => Promise<{
|
|
44
45
|
containerId: string;
|
|
45
46
|
created: boolean;
|
|
46
47
|
}>) | undefined;
|
|
47
48
|
getUserId?: (() => string | null) | undefined;
|
|
48
49
|
}
|
|
49
|
-
export
|
|
50
|
+
export interface PreparedIdentityChange {
|
|
51
|
+
isCurrent(): boolean;
|
|
52
|
+
commit(): void;
|
|
53
|
+
}
|
|
54
|
+
/** Blobs prepares a store; tests use a no-op. Commit only assigns prepared state. */
|
|
55
|
+
interface IdentityChangePreparation {
|
|
56
|
+
prepareIdentityChange(signingFingerprint: string | null): PreparedIdentityChange;
|
|
57
|
+
}
|
|
58
|
+
export declare function createIdentity(options: IdentityOptions | undefined, identityChanges: IdentityChangePreparation, log: (message: string) => void, runtimeHooks?: IdentityRuntimeHooks): Identity;
|
|
50
59
|
export {};
|
package/client/identity/index.js
CHANGED
|
@@ -2,66 +2,71 @@ import { createIdentitySeedPhrase, generateIdentityKeyPairsFromSeedPhrase, toFin
|
|
|
2
2
|
import { errorMessage } from "../../data/shared/errorMessage.js";
|
|
3
3
|
import { createListenerSet } from "../runtime/listenerSet.js";
|
|
4
4
|
import { createIdentityKeyPackage, parseIdentityKeyPackage, } from "./keyPackage.js";
|
|
5
|
-
export function createIdentity(options = {},
|
|
6
|
-
return new IdentityService(options,
|
|
5
|
+
export function createIdentity(options = {}, identityChanges, log, runtimeHooks = {}) {
|
|
6
|
+
return new IdentityService(options, identityChanges, log, runtimeHooks);
|
|
7
7
|
}
|
|
8
8
|
class IdentityService {
|
|
9
|
-
|
|
9
|
+
identityChanges;
|
|
10
10
|
log;
|
|
11
11
|
runtimeHooks;
|
|
12
|
-
encapsulationKeyPairValue;
|
|
13
12
|
listeners = createListenerSet();
|
|
14
|
-
seedPhraseValue;
|
|
15
|
-
signingFingerprintValue;
|
|
16
|
-
signingKeyPairValue;
|
|
17
13
|
snapshotValue;
|
|
18
|
-
|
|
19
|
-
|
|
14
|
+
changeRevision = 0;
|
|
15
|
+
constructor(options = {}, identityChanges, log, runtimeHooks) {
|
|
16
|
+
this.identityChanges = identityChanges;
|
|
20
17
|
this.log = log;
|
|
21
18
|
this.runtimeHooks = runtimeHooks;
|
|
22
|
-
this.
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
19
|
+
this.snapshotValue = {
|
|
20
|
+
encapsulationKeyPair: options.encapsulationKeyPair ?? null,
|
|
21
|
+
seedPhrase: options.seedPhrase ?? null,
|
|
22
|
+
signingFingerprint: options.signingFingerprint ?? null,
|
|
23
|
+
signingKeyPair: options.signingKeyPair ?? null,
|
|
24
|
+
};
|
|
25
|
+
this.identityChanges
|
|
26
|
+
.prepareIdentityChange(this.signingFingerprint)
|
|
27
|
+
.commit();
|
|
28
28
|
}
|
|
29
29
|
get encapsulationKeyPair() {
|
|
30
|
-
return this.
|
|
30
|
+
return this.snapshotValue.encapsulationKeyPair;
|
|
31
31
|
}
|
|
32
32
|
get seedPhrase() {
|
|
33
|
-
return this.
|
|
33
|
+
return this.snapshotValue.seedPhrase;
|
|
34
34
|
}
|
|
35
35
|
get signingFingerprint() {
|
|
36
|
-
return this.
|
|
36
|
+
return this.snapshotValue.signingFingerprint;
|
|
37
37
|
}
|
|
38
38
|
get signingKeyPair() {
|
|
39
|
-
return this.
|
|
39
|
+
return this.snapshotValue.signingKeyPair;
|
|
40
40
|
}
|
|
41
41
|
get snapshot() {
|
|
42
42
|
return this.snapshotValue;
|
|
43
43
|
}
|
|
44
44
|
destroy() {
|
|
45
|
-
|
|
46
|
-
this.
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
45
|
+
const revision = ++this.changeRevision;
|
|
46
|
+
this.publishSnapshot({
|
|
47
|
+
encapsulationKeyPair: null,
|
|
48
|
+
seedPhrase: null,
|
|
49
|
+
signingFingerprint: null,
|
|
50
|
+
signingKeyPair: null,
|
|
51
|
+
}, revision);
|
|
50
52
|
this.log("Key pair destroyed");
|
|
51
53
|
}
|
|
52
54
|
exportKeyPackage() {
|
|
53
55
|
return createIdentityKeyPackage(this.snapshot);
|
|
54
56
|
}
|
|
55
57
|
async generate() {
|
|
58
|
+
this.runtimeHooks.assertReadyForGeneration?.();
|
|
59
|
+
const revision = ++this.changeRevision;
|
|
56
60
|
const seedPhrase = createIdentitySeedPhrase();
|
|
57
61
|
const { encapsulationKeyPair, signingKeyPair } = generateIdentityKeyPairsFromSeedPhrase(seedPhrase);
|
|
58
62
|
const signingFingerprint = await toFingerprint(signingKeyPair.signingPublicKey);
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
this.
|
|
62
|
-
|
|
63
|
-
this.
|
|
64
|
-
this.
|
|
63
|
+
// Factory failures must happen before persisting or selecting a local root.
|
|
64
|
+
// Root failures leave the prepared store inactive and the identity unchanged.
|
|
65
|
+
this.assertCurrent(revision);
|
|
66
|
+
const prepared = this.identityChanges.prepareIdentityChange(signingFingerprint);
|
|
67
|
+
this.assertCurrent(revision, prepared);
|
|
68
|
+
const generationContext = await this.createGenerationContext(() => this.changeRevision === revision && prepared.isCurrent());
|
|
69
|
+
this.publishSnapshot({ signingKeyPair, encapsulationKeyPair, seedPhrase, signingFingerprint }, revision, prepared);
|
|
65
70
|
this.log("Key pair generated");
|
|
66
71
|
return {
|
|
67
72
|
...this.snapshot,
|
|
@@ -69,70 +74,65 @@ class IdentityService {
|
|
|
69
74
|
};
|
|
70
75
|
}
|
|
71
76
|
async importKeyPackage(keyPackage) {
|
|
77
|
+
const revision = ++this.changeRevision;
|
|
72
78
|
const parsed = await parseIdentityKeyPackage(keyPackage);
|
|
73
|
-
this.
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
79
|
+
this.publishSnapshot({
|
|
80
|
+
encapsulationKeyPair: parsed.encapsulationKeyPair,
|
|
81
|
+
seedPhrase: parsed.package.seedPhrase ?? null,
|
|
82
|
+
signingKeyPair: parsed.signingKeyPair,
|
|
83
|
+
signingFingerprint: parsed.package.signingFingerprint,
|
|
84
|
+
}, revision);
|
|
78
85
|
this.log("Key package imported");
|
|
79
86
|
return this.snapshot;
|
|
80
87
|
}
|
|
81
88
|
async importSeedPhrase(seedPhrase) {
|
|
89
|
+
const revision = ++this.changeRevision;
|
|
82
90
|
const derived = generateIdentityKeyPairsFromSeedPhrase(seedPhrase);
|
|
83
|
-
|
|
84
|
-
this.
|
|
85
|
-
this.signingKeyPairValue = derived.signingKeyPair;
|
|
86
|
-
this.signingFingerprintValue = await toFingerprint(derived.signingKeyPair.signingPublicKey);
|
|
87
|
-
this.publishSnapshot();
|
|
91
|
+
const signingFingerprint = await toFingerprint(derived.signingKeyPair.signingPublicKey);
|
|
92
|
+
this.publishSnapshot({ ...derived, signingFingerprint }, revision);
|
|
88
93
|
this.log("Seed phrase imported");
|
|
89
94
|
return this.snapshot;
|
|
90
95
|
}
|
|
91
96
|
requireSigningKeyPair(operation = "This operation") {
|
|
92
|
-
if (!this.
|
|
97
|
+
if (!this.signingKeyPair) {
|
|
93
98
|
throw new Error(`${operation} requires a signing key pair.`);
|
|
94
99
|
}
|
|
95
|
-
return this.
|
|
100
|
+
return this.signingKeyPair;
|
|
96
101
|
}
|
|
97
102
|
async refreshSigningFingerprint() {
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
103
|
+
const revision = this.changeRevision;
|
|
104
|
+
const snapshot = this.snapshot;
|
|
105
|
+
const signingFingerprint = snapshot.signingKeyPair
|
|
106
|
+
? await toFingerprint(snapshot.signingKeyPair.signingPublicKey)
|
|
107
|
+
: null;
|
|
108
|
+
if (this.changeRevision !== revision || this.snapshot !== snapshot) {
|
|
109
|
+
return this.signingFingerprint;
|
|
102
110
|
}
|
|
103
|
-
this.
|
|
104
|
-
|
|
105
|
-
return this.signingFingerprintValue;
|
|
111
|
+
this.publishSnapshot({ ...snapshot, signingFingerprint }, revision);
|
|
112
|
+
return signingFingerprint;
|
|
106
113
|
}
|
|
107
114
|
async setKeyPairs(options) {
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
115
|
+
const revision = ++this.changeRevision;
|
|
116
|
+
const signingFingerprint = options.signingFingerprint ||
|
|
117
|
+
(options.signingKeyPair
|
|
118
|
+
? await toFingerprint(options.signingKeyPair.signingPublicKey)
|
|
119
|
+
: null);
|
|
120
|
+
this.publishSnapshot({
|
|
121
|
+
encapsulationKeyPair: options.encapsulationKeyPair,
|
|
122
|
+
seedPhrase: options.seedPhrase ?? null,
|
|
123
|
+
signingKeyPair: options.signingKeyPair,
|
|
124
|
+
signingFingerprint,
|
|
125
|
+
}, revision);
|
|
118
126
|
return this.snapshot;
|
|
119
127
|
}
|
|
120
128
|
subscribe = (listener) => this.listeners.subscribe(listener);
|
|
121
|
-
|
|
122
|
-
return {
|
|
123
|
-
encapsulationKeyPair: this.encapsulationKeyPairValue,
|
|
124
|
-
seedPhrase: this.seedPhraseValue,
|
|
125
|
-
signingFingerprint: this.signingFingerprintValue,
|
|
126
|
-
signingKeyPair: this.signingKeyPairValue,
|
|
127
|
-
};
|
|
128
|
-
}
|
|
129
|
-
async createGenerationContext() {
|
|
129
|
+
async createGenerationContext(isCurrent) {
|
|
130
130
|
try {
|
|
131
131
|
const bootstrapLocalRootContainer = this.runtimeHooks.bootstrapLocalRootContainer;
|
|
132
132
|
if (!bootstrapLocalRootContainer) {
|
|
133
133
|
throw new Error("identity.generate requires local root container bootstrap.");
|
|
134
134
|
}
|
|
135
|
-
const rootContainer = await bootstrapLocalRootContainer();
|
|
135
|
+
const rootContainer = await bootstrapLocalRootContainer(isCurrent);
|
|
136
136
|
return {
|
|
137
137
|
rootContainerCreated: rootContainer.created,
|
|
138
138
|
rootContainerId: rootContainer.containerId,
|
|
@@ -145,8 +145,8 @@ class IdentityService {
|
|
|
145
145
|
throw error;
|
|
146
146
|
}
|
|
147
147
|
}
|
|
148
|
-
publishSnapshot() {
|
|
149
|
-
|
|
148
|
+
publishSnapshot(nextSnapshot, revision, prepared) {
|
|
149
|
+
this.assertCurrent(revision, prepared);
|
|
150
150
|
const previousSnapshot = this.snapshotValue;
|
|
151
151
|
if (previousSnapshot.encapsulationKeyPair ===
|
|
152
152
|
nextSnapshot.encapsulationKeyPair &&
|
|
@@ -155,9 +155,17 @@ class IdentityService {
|
|
|
155
155
|
previousSnapshot.signingKeyPair === nextSnapshot.signingKeyPair) {
|
|
156
156
|
return;
|
|
157
157
|
}
|
|
158
|
+
const change = prepared ??
|
|
159
|
+
this.identityChanges.prepareIdentityChange(nextSnapshot.signingFingerprint);
|
|
160
|
+
this.assertCurrent(revision, change);
|
|
161
|
+
change.commit();
|
|
158
162
|
this.snapshotValue = nextSnapshot;
|
|
159
|
-
this.onIdentityChanged(nextSnapshot.signingFingerprint);
|
|
160
163
|
this.listeners.notify();
|
|
161
164
|
}
|
|
165
|
+
assertCurrent(revision, prepared) {
|
|
166
|
+
if (this.changeRevision !== revision || prepared?.isCurrent() === false) {
|
|
167
|
+
throw new Error("Identity change was superseded.");
|
|
168
|
+
}
|
|
169
|
+
}
|
|
162
170
|
}
|
|
163
171
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n createIdentitySeedPhrase,\n type EncapsulationKeyPair,\n generateIdentityKeyPairsFromSeedPhrase,\n type SigningKeyPair,\n toFingerprint,\n} from \"@tearleads/crypto\";\nimport { errorMessage } from \"../../data/shared/errorMessage\";\nimport { createListenerSet } from \"../runtime/listenerSet\";\nimport {\n createIdentityKeyPackage,\n type IdentityKeyPackage,\n parseIdentityKeyPackage,\n} from \"./keyPackage\";\n\nexport interface IdentityOptions {\n encapsulationKeyPair?: EncapsulationKeyPair | null | undefined;\n seedPhrase?: string | null | undefined;\n signingFingerprint?: string | null | undefined;\n signingKeyPair?: SigningKeyPair | null | undefined;\n}\n\nexport interface IdentitySnapshot {\n encapsulationKeyPair: EncapsulationKeyPair | null;\n seedPhrase: string | null;\n signingFingerprint: string | null;\n signingKeyPair: SigningKeyPair | null;\n}\n\nexport interface IdentityGenerationResult extends IdentitySnapshot {\n rootContainerCreated: boolean;\n rootContainerId: string;\n userId: string | null;\n}\n\nexport type IdentityListener = () => void;\n\nexport interface Identity {\n readonly encapsulationKeyPair: EncapsulationKeyPair | null;\n readonly seedPhrase: string | null;\n readonly signingFingerprint: string | null;\n readonly signingKeyPair: SigningKeyPair | null;\n readonly snapshot: IdentitySnapshot;\n destroy(): void;\n exportKeyPackage(): Promise<IdentityKeyPackage>;\n generate(): Promise<IdentityGenerationResult>;\n importKeyPackage(keyPackage: unknown): Promise<IdentitySnapshot>;\n importSeedPhrase(seedPhrase: string): Promise<IdentitySnapshot>;\n requireSigningKeyPair(operation?: string): SigningKeyPair;\n refreshSigningFingerprint(): Promise<string | null>;\n setKeyPairs(options: {\n encapsulationKeyPair: EncapsulationKeyPair | null;\n seedPhrase?: string | null | undefined;\n signingFingerprint?: string | null | undefined;\n signingKeyPair: SigningKeyPair | null;\n }): Promise<IdentitySnapshot>;\n subscribe(listener: IdentityListener): () => void;\n}\n\ninterface IdentityGenerationContext {\n rootContainerCreated: boolean;\n rootContainerId: string;\n userId: string | null;\n}\n\ninterface IdentityRuntimeHooks {\n bootstrapLocalRootContainer?:\n | (() => Promise<{ containerId: string; created: boolean }>)\n | undefined;\n getUserId?: (() => string | null) | undefined;\n}\n\nexport function createIdentity(\n options: IdentityOptions = {},\n onIdentityChanged: (signingFingerprint: string | null) => void,\n log: (message: string) => void,\n runtimeHooks: IdentityRuntimeHooks = {},\n): Identity {\n return new IdentityService(options, onIdentityChanged, log, runtimeHooks);\n}\n\nclass IdentityService implements Identity {\n private encapsulationKeyPairValue: EncapsulationKeyPair | null;\n private readonly listeners = createListenerSet();\n private seedPhraseValue: string | null;\n private signingFingerprintValue: string | null;\n private signingKeyPairValue: SigningKeyPair | null;\n private snapshotValue: IdentitySnapshot;\n\n constructor(\n options: IdentityOptions = {},\n private readonly onIdentityChanged: (\n signingFingerprint: string | null,\n ) => void,\n private readonly log: (message: string) => void,\n private readonly runtimeHooks: IdentityRuntimeHooks,\n ) {\n this.encapsulationKeyPairValue = options.encapsulationKeyPair ?? null;\n this.seedPhraseValue = options.seedPhrase ?? null;\n this.signingFingerprintValue = options.signingFingerprint ?? null;\n this.signingKeyPairValue = options.signingKeyPair ?? null;\n this.snapshotValue = this.createSnapshot();\n this.onIdentityChanged(this.signingFingerprintValue);\n }\n\n get encapsulationKeyPair(): EncapsulationKeyPair | null {\n return this.encapsulationKeyPairValue;\n }\n\n get seedPhrase(): string | null {\n return this.seedPhraseValue;\n }\n\n get signingFingerprint(): string | null {\n return this.signingFingerprintValue;\n }\n\n get signingKeyPair(): SigningKeyPair | null {\n return this.signingKeyPairValue;\n }\n\n get snapshot(): IdentitySnapshot {\n return this.snapshotValue;\n }\n\n destroy(): void {\n this.encapsulationKeyPairValue = null;\n this.seedPhraseValue = null;\n this.signingFingerprintValue = null;\n this.signingKeyPairValue = null;\n this.publishSnapshot();\n this.log(\"Key pair destroyed\");\n }\n\n exportKeyPackage(): Promise<IdentityKeyPackage> {\n return createIdentityKeyPackage(this.snapshot);\n }\n\n async generate(): Promise<IdentityGenerationResult> {\n const seedPhrase = createIdentitySeedPhrase();\n const { encapsulationKeyPair, signingKeyPair } =\n generateIdentityKeyPairsFromSeedPhrase(seedPhrase);\n const signingFingerprint = await toFingerprint(\n signingKeyPair.signingPublicKey,\n );\n const generationContext = await this.createGenerationContext();\n\n this.signingKeyPairValue = signingKeyPair;\n this.encapsulationKeyPairValue = encapsulationKeyPair;\n this.seedPhraseValue = seedPhrase;\n this.signingFingerprintValue = signingFingerprint;\n this.publishSnapshot();\n this.log(\"Key pair generated\");\n return {\n ...this.snapshot,\n ...generationContext,\n };\n }\n\n async importKeyPackage(keyPackage: unknown): Promise<IdentitySnapshot> {\n const parsed = await parseIdentityKeyPackage(keyPackage);\n this.encapsulationKeyPairValue = parsed.encapsulationKeyPair;\n this.seedPhraseValue = parsed.package.seedPhrase ?? null;\n this.signingKeyPairValue = parsed.signingKeyPair;\n this.signingFingerprintValue = parsed.package.signingFingerprint;\n this.publishSnapshot();\n this.log(\"Key package imported\");\n return this.snapshot;\n }\n\n async importSeedPhrase(seedPhrase: string): Promise<IdentitySnapshot> {\n const derived = generateIdentityKeyPairsFromSeedPhrase(seedPhrase);\n this.encapsulationKeyPairValue = derived.encapsulationKeyPair;\n this.seedPhraseValue = derived.seedPhrase;\n this.signingKeyPairValue = derived.signingKeyPair;\n this.signingFingerprintValue = await toFingerprint(\n derived.signingKeyPair.signingPublicKey,\n );\n this.publishSnapshot();\n this.log(\"Seed phrase imported\");\n return this.snapshot;\n }\n\n requireSigningKeyPair(operation = \"This operation\"): SigningKeyPair {\n if (!this.signingKeyPairValue) {\n throw new Error(`${operation} requires a signing key pair.`);\n }\n\n return this.signingKeyPairValue;\n }\n\n async refreshSigningFingerprint(): Promise<string | null> {\n if (!this.signingKeyPairValue) {\n this.signingFingerprintValue = null;\n this.publishSnapshot();\n return null;\n }\n\n this.signingFingerprintValue = await toFingerprint(\n this.signingKeyPairValue.signingPublicKey,\n );\n this.publishSnapshot();\n return this.signingFingerprintValue;\n }\n\n async setKeyPairs(options: {\n encapsulationKeyPair: EncapsulationKeyPair | null;\n seedPhrase?: string | null | undefined;\n signingFingerprint?: string | null | undefined;\n signingKeyPair: SigningKeyPair | null;\n }): Promise<IdentitySnapshot> {\n this.encapsulationKeyPairValue = options.encapsulationKeyPair;\n this.seedPhraseValue = options.seedPhrase ?? null;\n this.signingKeyPairValue = options.signingKeyPair;\n this.signingFingerprintValue = options.signingFingerprint ?? null;\n\n if (!this.signingFingerprintValue) {\n await this.refreshSigningFingerprint();\n } else {\n this.publishSnapshot();\n }\n\n return this.snapshot;\n }\n\n subscribe = (listener: IdentityListener): (() => void) =>\n this.listeners.subscribe(listener);\n\n private createSnapshot(): IdentitySnapshot {\n return {\n encapsulationKeyPair: this.encapsulationKeyPairValue,\n seedPhrase: this.seedPhraseValue,\n signingFingerprint: this.signingFingerprintValue,\n signingKeyPair: this.signingKeyPairValue,\n };\n }\n\n private async createGenerationContext(): Promise<IdentityGenerationContext> {\n try {\n const bootstrapLocalRootContainer =\n this.runtimeHooks.bootstrapLocalRootContainer;\n if (!bootstrapLocalRootContainer) {\n throw new Error(\n \"identity.generate requires local root container bootstrap.\",\n );\n }\n\n const rootContainer = await bootstrapLocalRootContainer();\n\n return {\n rootContainerCreated: rootContainer.created,\n rootContainerId: rootContainer.containerId,\n userId: this.runtimeHooks.getUserId?.() ?? null,\n };\n } catch (error: unknown) {\n const message = errorMessage(error);\n this.log(`Root container bootstrap failed: ${message}`);\n throw error;\n }\n }\n\n private publishSnapshot(): void {\n const nextSnapshot = this.createSnapshot();\n const previousSnapshot = this.snapshotValue;\n if (\n previousSnapshot.encapsulationKeyPair ===\n nextSnapshot.encapsulationKeyPair &&\n previousSnapshot.seedPhrase === nextSnapshot.seedPhrase &&\n previousSnapshot.signingFingerprint === nextSnapshot.signingFingerprint &&\n previousSnapshot.signingKeyPair === nextSnapshot.signingKeyPair\n ) {\n return;\n }\n\n this.snapshotValue = nextSnapshot;\n this.onIdentityChanged(nextSnapshot.signingFingerprint);\n this.listeners.notify();\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n createIdentitySeedPhrase,\n type EncapsulationKeyPair,\n generateIdentityKeyPairsFromSeedPhrase,\n type SigningKeyPair,\n toFingerprint,\n} from \"@tearleads/crypto\";\nimport { errorMessage } from \"../../data/shared/errorMessage\";\nimport { createListenerSet } from \"../runtime/listenerSet\";\nimport {\n createIdentityKeyPackage,\n type IdentityKeyPackage,\n parseIdentityKeyPackage,\n} from \"./keyPackage\";\n\nexport interface IdentityOptions {\n encapsulationKeyPair?: EncapsulationKeyPair | null | undefined;\n seedPhrase?: string | null | undefined;\n signingFingerprint?: string | null | undefined;\n signingKeyPair?: SigningKeyPair | null | undefined;\n}\n\nexport interface IdentitySnapshot {\n encapsulationKeyPair: EncapsulationKeyPair | null;\n seedPhrase: string | null;\n signingFingerprint: string | null;\n signingKeyPair: SigningKeyPair | null;\n}\n\nexport interface IdentityGenerationResult extends IdentitySnapshot {\n rootContainerCreated: boolean;\n rootContainerId: string;\n userId: string | null;\n}\n\nexport type IdentityListener = () => void;\n\nexport interface Identity {\n readonly encapsulationKeyPair: EncapsulationKeyPair | null;\n readonly seedPhrase: string | null;\n readonly signingFingerprint: string | null;\n readonly signingKeyPair: SigningKeyPair | null;\n readonly snapshot: IdentitySnapshot;\n destroy(): void;\n exportKeyPackage(): Promise<IdentityKeyPackage>;\n generate(): Promise<IdentityGenerationResult>;\n importKeyPackage(keyPackage: unknown): Promise<IdentitySnapshot>;\n importSeedPhrase(seedPhrase: string): Promise<IdentitySnapshot>;\n requireSigningKeyPair(operation?: string): SigningKeyPair;\n refreshSigningFingerprint(): Promise<string | null>;\n setKeyPairs(options: {\n encapsulationKeyPair: EncapsulationKeyPair | null;\n seedPhrase?: string | null | undefined;\n signingFingerprint?: string | null | undefined;\n signingKeyPair: SigningKeyPair | null;\n }): Promise<IdentitySnapshot>;\n subscribe(listener: IdentityListener): () => void;\n}\n\ninterface IdentityGenerationContext {\n rootContainerCreated: boolean;\n rootContainerId: string;\n userId: string | null;\n}\n\ninterface IdentityRuntimeHooks {\n assertReadyForGeneration?: (() => void) | undefined;\n bootstrapLocalRootContainer?:\n | ((\n isCurrent: () => boolean,\n ) => Promise<{ containerId: string; created: boolean }>)\n | undefined;\n getUserId?: (() => string | null) | undefined;\n}\n\nexport interface PreparedIdentityChange {\n isCurrent(): boolean;\n commit(): void;\n}\n\n/** Blobs prepares a store; tests use a no-op. Commit only assigns prepared state. */\ninterface IdentityChangePreparation {\n prepareIdentityChange(\n signingFingerprint: string | null,\n ): PreparedIdentityChange;\n}\n\nexport function createIdentity(\n options: IdentityOptions = {},\n identityChanges: IdentityChangePreparation,\n log: (message: string) => void,\n runtimeHooks: IdentityRuntimeHooks = {},\n): Identity {\n return new IdentityService(options, identityChanges, log, runtimeHooks);\n}\n\nclass IdentityService implements Identity {\n private readonly listeners = createListenerSet();\n private snapshotValue: IdentitySnapshot;\n private changeRevision = 0;\n\n constructor(\n options: IdentityOptions = {},\n private readonly identityChanges: IdentityChangePreparation,\n private readonly log: (message: string) => void,\n private readonly runtimeHooks: IdentityRuntimeHooks,\n ) {\n this.snapshotValue = {\n encapsulationKeyPair: options.encapsulationKeyPair ?? null,\n seedPhrase: options.seedPhrase ?? null,\n signingFingerprint: options.signingFingerprint ?? null,\n signingKeyPair: options.signingKeyPair ?? null,\n };\n this.identityChanges\n .prepareIdentityChange(this.signingFingerprint)\n .commit();\n }\n\n get encapsulationKeyPair(): EncapsulationKeyPair | null {\n return this.snapshotValue.encapsulationKeyPair;\n }\n\n get seedPhrase(): string | null {\n return this.snapshotValue.seedPhrase;\n }\n\n get signingFingerprint(): string | null {\n return this.snapshotValue.signingFingerprint;\n }\n\n get signingKeyPair(): SigningKeyPair | null {\n return this.snapshotValue.signingKeyPair;\n }\n\n get snapshot(): IdentitySnapshot {\n return this.snapshotValue;\n }\n\n destroy(): void {\n const revision = ++this.changeRevision;\n this.publishSnapshot(\n {\n encapsulationKeyPair: null,\n seedPhrase: null,\n signingFingerprint: null,\n signingKeyPair: null,\n },\n revision,\n );\n this.log(\"Key pair destroyed\");\n }\n\n exportKeyPackage(): Promise<IdentityKeyPackage> {\n return createIdentityKeyPackage(this.snapshot);\n }\n\n async generate(): Promise<IdentityGenerationResult> {\n this.runtimeHooks.assertReadyForGeneration?.();\n const revision = ++this.changeRevision;\n const seedPhrase = createIdentitySeedPhrase();\n const { encapsulationKeyPair, signingKeyPair } =\n generateIdentityKeyPairsFromSeedPhrase(seedPhrase);\n const signingFingerprint = await toFingerprint(\n signingKeyPair.signingPublicKey,\n );\n // Factory failures must happen before persisting or selecting a local root.\n // Root failures leave the prepared store inactive and the identity unchanged.\n this.assertCurrent(revision);\n const prepared =\n this.identityChanges.prepareIdentityChange(signingFingerprint);\n this.assertCurrent(revision, prepared);\n const generationContext = await this.createGenerationContext(\n () => this.changeRevision === revision && prepared.isCurrent(),\n );\n this.publishSnapshot(\n { signingKeyPair, encapsulationKeyPair, seedPhrase, signingFingerprint },\n revision,\n prepared,\n );\n this.log(\"Key pair generated\");\n return {\n ...this.snapshot,\n ...generationContext,\n };\n }\n\n async importKeyPackage(keyPackage: unknown): Promise<IdentitySnapshot> {\n const revision = ++this.changeRevision;\n const parsed = await parseIdentityKeyPackage(keyPackage);\n this.publishSnapshot(\n {\n encapsulationKeyPair: parsed.encapsulationKeyPair,\n seedPhrase: parsed.package.seedPhrase ?? null,\n signingKeyPair: parsed.signingKeyPair,\n signingFingerprint: parsed.package.signingFingerprint,\n },\n revision,\n );\n this.log(\"Key package imported\");\n return this.snapshot;\n }\n\n async importSeedPhrase(seedPhrase: string): Promise<IdentitySnapshot> {\n const revision = ++this.changeRevision;\n const derived = generateIdentityKeyPairsFromSeedPhrase(seedPhrase);\n const signingFingerprint = await toFingerprint(\n derived.signingKeyPair.signingPublicKey,\n );\n this.publishSnapshot({ ...derived, signingFingerprint }, revision);\n this.log(\"Seed phrase imported\");\n return this.snapshot;\n }\n\n requireSigningKeyPair(operation = \"This operation\"): SigningKeyPair {\n if (!this.signingKeyPair) {\n throw new Error(`${operation} requires a signing key pair.`);\n }\n\n return this.signingKeyPair;\n }\n\n async refreshSigningFingerprint(): Promise<string | null> {\n const revision = this.changeRevision;\n const snapshot = this.snapshot;\n const signingFingerprint = snapshot.signingKeyPair\n ? await toFingerprint(snapshot.signingKeyPair.signingPublicKey)\n : null;\n if (this.changeRevision !== revision || this.snapshot !== snapshot) {\n return this.signingFingerprint;\n }\n this.publishSnapshot({ ...snapshot, signingFingerprint }, revision);\n return signingFingerprint;\n }\n\n async setKeyPairs(options: {\n encapsulationKeyPair: EncapsulationKeyPair | null;\n seedPhrase?: string | null | undefined;\n signingFingerprint?: string | null | undefined;\n signingKeyPair: SigningKeyPair | null;\n }): Promise<IdentitySnapshot> {\n const revision = ++this.changeRevision;\n const signingFingerprint =\n options.signingFingerprint ||\n (options.signingKeyPair\n ? await toFingerprint(options.signingKeyPair.signingPublicKey)\n : null);\n this.publishSnapshot(\n {\n encapsulationKeyPair: options.encapsulationKeyPair,\n seedPhrase: options.seedPhrase ?? null,\n signingKeyPair: options.signingKeyPair,\n signingFingerprint,\n },\n revision,\n );\n\n return this.snapshot;\n }\n\n subscribe = (listener: IdentityListener): (() => void) =>\n this.listeners.subscribe(listener);\n\n private async createGenerationContext(\n isCurrent: () => boolean,\n ): Promise<IdentityGenerationContext> {\n try {\n const bootstrapLocalRootContainer =\n this.runtimeHooks.bootstrapLocalRootContainer;\n if (!bootstrapLocalRootContainer) {\n throw new Error(\n \"identity.generate requires local root container bootstrap.\",\n );\n }\n\n const rootContainer = await bootstrapLocalRootContainer(isCurrent);\n\n return {\n rootContainerCreated: rootContainer.created,\n rootContainerId: rootContainer.containerId,\n userId: this.runtimeHooks.getUserId?.() ?? null,\n };\n } catch (error: unknown) {\n const message = errorMessage(error);\n this.log(`Root container bootstrap failed: ${message}`);\n throw error;\n }\n }\n\n private publishSnapshot(\n nextSnapshot: IdentitySnapshot,\n revision: number,\n prepared?: PreparedIdentityChange,\n ): void {\n this.assertCurrent(revision, prepared);\n const previousSnapshot = this.snapshotValue;\n if (\n previousSnapshot.encapsulationKeyPair ===\n nextSnapshot.encapsulationKeyPair &&\n previousSnapshot.seedPhrase === nextSnapshot.seedPhrase &&\n previousSnapshot.signingFingerprint === nextSnapshot.signingFingerprint &&\n previousSnapshot.signingKeyPair === nextSnapshot.signingKeyPair\n ) {\n return;\n }\n\n const change =\n prepared ??\n this.identityChanges.prepareIdentityChange(\n nextSnapshot.signingFingerprint,\n );\n this.assertCurrent(revision, change);\n change.commit();\n this.snapshotValue = nextSnapshot;\n this.listeners.notify();\n }\n\n private assertCurrent(\n revision: number,\n prepared?: PreparedIdentityChange,\n ): void {\n if (this.changeRevision !== revision || prepared?.isCurrent() === false) {\n throw new Error(\"Identity change was superseded.\");\n }\n }\n}\n"]}
|
|
@@ -3,7 +3,7 @@ import { cancelStripeSubscription, checkNativePurchaseEligibility, claimNativeOr
|
|
|
3
3
|
import { createOrganizationDataUsageCoordinator, } from "./organizationDataUsage.js";
|
|
4
4
|
import { loadOrganizationGroupPresentationDetails } from "./organizationGroupPresentation.js";
|
|
5
5
|
import { createOrganizationMemberships, } from "./organizationMemberships.js";
|
|
6
|
-
import { createOrganizationReadModelCoordinator,
|
|
6
|
+
import { createOrganizationReadModelCoordinator, leaveRequestVerifier, } from "./organizationReadModels.js";
|
|
7
7
|
import { authenticatedOrganizationId, runForOrganization, } from "./organizationWorkflowRuntime.js";
|
|
8
8
|
import { abandonPendingOrganizationPolicyMutation, discardUnreadableOrganizationPolicyMutation, readPendingOrganizationPolicyMutation, retryPendingOrganizationPolicyMutation, } from "./principalMutationRecovery.js";
|
|
9
9
|
import { currentOrganizationMutation } from "./principalMutationScope.js";
|
|
@@ -185,7 +185,10 @@ class OrganizationsService {
|
|
|
185
185
|
// Callers store this response as directory state, so its leave request
|
|
186
186
|
// passes the same check as one read from the read model.
|
|
187
187
|
return (user &&
|
|
188
|
-
withVerifiedDirectoryUser(organizationId, user,
|
|
188
|
+
withVerifiedDirectoryUser(organizationId, user, leaveRequestVerifier(this.runtimeService, runtime, {
|
|
189
|
+
organizationId,
|
|
190
|
+
userId: runtime.auth.userId ?? "",
|
|
191
|
+
})));
|
|
189
192
|
}
|
|
190
193
|
updateProfile(profileDocumentId) {
|
|
191
194
|
const runtime = this.runtimeService.workflowInput();
|