@opengeni/core 2.4.0-canary.1 → 2.5.2-canary.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.
@@ -0,0 +1,369 @@
1
+ import {
2
+ MANAGED_AUTH_ACTOR_EPOCH_HEADER,
3
+ MANAGED_AUTH_SESSION_SET_COOKIE,
4
+ ManagedAuthActorChangeError,
5
+ managedAuthSha256,
6
+ resolveManagedAuthSelectedSession
7
+ } from "./chunk-YGOMUGYS.js";
8
+
9
+ // src/managed-session.ts
10
+ import {
11
+ acquireManagedAuthActorMutationLease,
12
+ getManagedAuthAdoptedSessionSnapshot,
13
+ getManagedAuthSessionSetSnapshot,
14
+ ManagedAuthSessionSetAuthorityError,
15
+ ManagedAuthSessionSetGenerationConflictError,
16
+ releaseManagedAuthActorMutationLease,
17
+ validateManagedAuthActorMutationLease
18
+ } from "@opengeni/db/managed-auth-session-sets";
19
+ import { validateCanonicalHumanSession } from "@opengeni/db/canonical-human-identities";
20
+ import { HTTPException } from "hono/http-exception";
21
+ var ACTOR_MUTATION_LEASE_SECONDS = 15 * 60;
22
+ var ACTOR_MUTATION_LEASE_REFRESH_MS = 5 * 60 * 1e3;
23
+ var ACTOR_MUTATION_HANDLER_DEADLINE_MS = 10 * 60 * 1e3;
24
+ var ACTOR_MUTATION_FATAL_SAFETY_MS = 5e3;
25
+ var productionActorMutationLeaseRuntime = {
26
+ monotonicNow: () => performance.now(),
27
+ schedule: (callback, delayMs) => unrefTimer(setTimeout(callback, delayMs)),
28
+ cancel: (timer) => clearTimeout(timer),
29
+ terminate: () => {
30
+ process.stderr.write("fatal: managed actor mutation outlived its durable lease\n");
31
+ process.exit(1);
32
+ }
33
+ };
34
+ var actorMutationLeaseRuntime = productionActorMutationLeaseRuntime;
35
+ var actorMutationLeaseByRequest = /* @__PURE__ */ new WeakMap();
36
+ var managedActorEpochByRequest = /* @__PURE__ */ new WeakMap();
37
+ var managedActorAdmissionByRequest = /* @__PURE__ */ new WeakMap();
38
+ async function getManagedSession(c, auth, options) {
39
+ const sessionSetMode = options?.sessionSetMode ?? "legacy";
40
+ if (sessionSetMode !== "legacy" && options?.db && options.sessionAdapter) {
41
+ const authority = requestCookie(c.req.raw, MANAGED_AUTH_SESSION_SET_COOKIE);
42
+ if (authority) {
43
+ try {
44
+ const admittedActorEpoch = managedActorEpochByRequest.get(c.req.raw) ?? null;
45
+ const expectedActorEpoch = admittedActorEpoch ?? c.req.header(MANAGED_AUTH_ACTOR_EPOCH_HEADER) ?? null;
46
+ const legacyAmbient = sessionSetMode === "dual" && expectedActorEpoch === null ? await options.sessionAdapter.resolveAmbientSession(c.req.raw.headers) : null;
47
+ const selected = await resolveManagedAuthSelectedSession({
48
+ db: options.db,
49
+ adapter: options.sessionAdapter,
50
+ authority,
51
+ mode: sessionSetMode,
52
+ expectedActorEpoch,
53
+ legacyAmbientSessionId: typeof legacyAmbient?.session?.id === "string" ? legacyAmbient.session.id : null,
54
+ allowRecovery: options.allowIdentityRecovery ?? false
55
+ });
56
+ if (selected) {
57
+ if (admittedActorEpoch === null) {
58
+ c.header(MANAGED_AUTH_ACTOR_EPOCH_HEADER, selected.projection.actorEpoch);
59
+ managedActorEpochByRequest.set(c.req.raw, selected.projection.actorEpoch);
60
+ }
61
+ managedActorAdmissionByRequest.set(c.req.raw, {
62
+ authorityHash: managedAuthSha256(authority),
63
+ actorEpoch: selected.projection.actorEpoch
64
+ });
65
+ }
66
+ if (selected && !selected.session) return null;
67
+ if (selected?.session) {
68
+ let resolvedSession = selected.session;
69
+ if (requestNeedsActorMutationLease(c.req.method)) {
70
+ await ensureActorMutationLease(
71
+ c.req.raw,
72
+ options.db,
73
+ authority,
74
+ selected.projection.actorEpoch
75
+ );
76
+ const selectedSlot = await selectedSlotForAuthority(
77
+ options.db,
78
+ authority,
79
+ sessionSetMode,
80
+ options.allowIdentityRecovery ?? false
81
+ );
82
+ if (!selectedSlot) throw new ManagedAuthActorChangeError();
83
+ const refreshed = await options.sessionAdapter.refreshSelectedSession(selectedSlot);
84
+ if (!refreshed || refreshed.session.id !== selectedSlot.authSessionId || refreshed.user.id !== selectedSlot.authUserId) {
85
+ throw new ManagedAuthActorChangeError();
86
+ }
87
+ resolvedSession = refreshed;
88
+ }
89
+ return resolvedSession;
90
+ }
91
+ return null;
92
+ } catch (error) {
93
+ if (error instanceof ManagedAuthActorChangeError) {
94
+ if (!managedActorEpochByRequest.has(c.req.raw)) {
95
+ c.header("x-opengeni-actor-state", "changed");
96
+ }
97
+ throw new HTTPException(409, { message: error.code, cause: error });
98
+ }
99
+ throw error;
100
+ }
101
+ }
102
+ if (sessionSetMode === "broker") return null;
103
+ const ambient = await options.sessionAdapter.resolveAmbientSession(c.req.raw.headers);
104
+ if (ambient?.session?.id)
105
+ try {
106
+ const adopted = await getManagedAuthAdoptedSessionSnapshot(options.db, ambient.session.id);
107
+ if (adopted) {
108
+ const admittedActorEpoch = managedActorEpochByRequest.get(c.req.raw) ?? null;
109
+ if (adopted.actorEpoch !== "1" || admittedActorEpoch !== null && adopted.actorEpoch !== admittedActorEpoch || !adopted.selected || adopted.selected.authSessionId !== ambient.session.id || adopted.selected.authUserId !== ambient.user.id) {
110
+ throw new ManagedAuthActorChangeError();
111
+ }
112
+ if (admittedActorEpoch === null) {
113
+ c.header(MANAGED_AUTH_ACTOR_EPOCH_HEADER, adopted.actorEpoch);
114
+ managedActorEpochByRequest.set(c.req.raw, adopted.actorEpoch);
115
+ }
116
+ managedActorAdmissionByRequest.set(c.req.raw, {
117
+ authorityHash: adopted.authorityHash,
118
+ actorEpoch: adopted.actorEpoch
119
+ });
120
+ if (requestNeedsActorMutationLease(c.req.method)) {
121
+ await ensureActorMutationLeaseForHash(
122
+ c.req.raw,
123
+ options.db,
124
+ adopted.authorityHash,
125
+ adopted.actorEpoch
126
+ );
127
+ const current = await getManagedAuthAdoptedSessionSnapshot(
128
+ options.db,
129
+ ambient.session.id
130
+ );
131
+ if (current?.authorityHash !== adopted.authorityHash || current.actorEpoch !== adopted.actorEpoch || !current.selected || current.selected.authSessionId !== ambient.session.id) {
132
+ throw new ManagedAuthActorChangeError();
133
+ }
134
+ const refreshed = await options.sessionAdapter.refreshSelectedSession(current.selected);
135
+ if (!refreshed || refreshed.session.id !== ambient.session.id || refreshed.user.id !== ambient.user.id) {
136
+ throw new ManagedAuthActorChangeError();
137
+ }
138
+ return refreshed;
139
+ }
140
+ return ambient;
141
+ }
142
+ } catch (error) {
143
+ if (error instanceof ManagedAuthActorChangeError) {
144
+ if (!managedActorEpochByRequest.has(c.req.raw)) {
145
+ c.header("x-opengeni-actor-state", "changed");
146
+ }
147
+ throw new HTTPException(409, { message: error.code, cause: error });
148
+ }
149
+ throw error;
150
+ }
151
+ }
152
+ const result = await auth.api.getSession({
153
+ headers: c.req.raw.headers,
154
+ returnHeaders: true
155
+ });
156
+ for (const cookie of setCookieHeaders(result.headers)) {
157
+ c.header("set-cookie", cookie, { append: true });
158
+ }
159
+ const session = result.response;
160
+ if (!session?.user || !options?.db) return session;
161
+ const authSessionId = session.session?.id;
162
+ if (typeof authSessionId !== "string") return null;
163
+ const valid = await validateCanonicalHumanSession(options.db, {
164
+ authSessionId,
165
+ authUserId: session.user.id,
166
+ ...options.allowIdentityRecovery === void 0 ? {} : { allowRecovery: options.allowIdentityRecovery }
167
+ });
168
+ return valid ? session : null;
169
+ }
170
+ function getManagedAuthRequestActorEpoch(request) {
171
+ return managedActorEpochByRequest.get(request) ?? null;
172
+ }
173
+ function selectedSlotForAuthority(db, authority, mode, allowRecovery) {
174
+ return getManagedAuthSessionSetSnapshot(db, {
175
+ authorityHash: managedAuthSha256(authority),
176
+ mode,
177
+ includeInternal: true,
178
+ allowRecovery,
179
+ readOnly: true
180
+ }).then((snapshot) => snapshot?.selected ?? null);
181
+ }
182
+ async function releaseManagedAuthRequestActorLease(request) {
183
+ const lease = actorMutationLeaseByRequest.get(request);
184
+ if (!lease) return;
185
+ actorMutationLeaseByRequest.delete(request);
186
+ if (lease.refreshTimer) lease.runtime.cancel(lease.refreshTimer);
187
+ if (lease.deadlineTimer) lease.runtime.cancel(lease.deadlineTimer);
188
+ if (lease.fatalTimer) lease.runtime.cancel(lease.fatalTimer);
189
+ await releaseManagedAuthActorMutationLease(lease.db, {
190
+ authorityHash: lease.authorityHash,
191
+ requestId: lease.requestId
192
+ });
193
+ }
194
+ function getManagedAuthRequestActorAbortSignal(request) {
195
+ return actorMutationLeaseByRequest.get(request)?.abortController.signal ?? null;
196
+ }
197
+ async function validateManagedAuthRequestActorLease(request) {
198
+ const lease = actorMutationLeaseByRequest.get(request);
199
+ if (!lease) return;
200
+ if (lease.actorTransitionApplied) return;
201
+ if (lease.poisoned !== null) {
202
+ throw new ManagedAuthActorLeaseOutcomeUnknownError({
203
+ cause: lease.poisoned
204
+ });
205
+ }
206
+ const valid = await validateManagedAuthActorMutationLease(lease.db, {
207
+ authorityHash: lease.authorityHash,
208
+ actorEpoch: lease.actorEpoch,
209
+ requestId: lease.requestId
210
+ });
211
+ if (!valid) throw new ManagedAuthActorChangeError();
212
+ }
213
+ var ManagedAuthActorLeaseOutcomeUnknownError = class extends Error {
214
+ name = "ManagedAuthActorLeaseOutcomeUnknownError";
215
+ code = "operation_outcome_unknown";
216
+ constructor(options) {
217
+ super("The actor-scoped request outcome is unknown after its durable lease was lost", options);
218
+ }
219
+ };
220
+ function markManagedAuthRequestActorTransitionApplied(request) {
221
+ const lease = actorMutationLeaseByRequest.get(request);
222
+ if (lease) lease.actorTransitionApplied = true;
223
+ }
224
+ function getManagedAuthRequestActorAdmissionStamp(request) {
225
+ return managedActorAdmissionByRequest.get(request) ?? null;
226
+ }
227
+ function getManagedAuthRequestActorLeaseStamp(request) {
228
+ const lease = actorMutationLeaseByRequest.get(request);
229
+ return lease ? {
230
+ authorityHash: lease.authorityHash,
231
+ actorEpoch: lease.actorEpoch,
232
+ requestId: lease.requestId
233
+ } : null;
234
+ }
235
+ function requestNeedsActorMutationLease(method) {
236
+ return method !== "GET" && method !== "HEAD" && method !== "OPTIONS";
237
+ }
238
+ async function ensureActorMutationLease(request, db, authority, actorEpoch) {
239
+ const authorityHash = managedAuthSha256(authority);
240
+ await ensureActorMutationLeaseForHash(request, db, authorityHash, actorEpoch);
241
+ }
242
+ async function ensureActorMutationLeaseForHash(request, db, authorityHash, actorEpoch) {
243
+ const existing = actorMutationLeaseByRequest.get(request);
244
+ if (existing) {
245
+ if (existing.authorityHash !== authorityHash || existing.actorEpoch !== actorEpoch) {
246
+ throw new ManagedAuthActorChangeError();
247
+ }
248
+ return;
249
+ }
250
+ const lease = {
251
+ db,
252
+ authorityHash,
253
+ actorEpoch,
254
+ requestId: crypto.randomUUID(),
255
+ refreshTimer: null,
256
+ deadlineTimer: null,
257
+ fatalTimer: null,
258
+ expiresAt: /* @__PURE__ */ new Date(0),
259
+ localFatalDeadlineMonotonicMs: 0,
260
+ runtime: actorMutationLeaseRuntime,
261
+ abortController: new AbortController(),
262
+ poisoned: null,
263
+ actorTransitionApplied: false
264
+ };
265
+ const acquireStartedAtMonotonicMs = lease.runtime.monotonicNow();
266
+ try {
267
+ lease.expiresAt = await acquireManagedAuthActorMutationLease(db, {
268
+ authorityHash,
269
+ actorEpoch,
270
+ requestId: lease.requestId,
271
+ leaseSeconds: ACTOR_MUTATION_LEASE_SECONDS
272
+ });
273
+ } catch (error) {
274
+ if (error instanceof ManagedAuthSessionSetGenerationConflictError || error instanceof ManagedAuthSessionSetAuthorityError) {
275
+ throw new ManagedAuthActorChangeError();
276
+ }
277
+ throw error;
278
+ }
279
+ lease.localFatalDeadlineMonotonicMs = acquireStartedAtMonotonicMs + ACTOR_MUTATION_LEASE_SECONDS * 1e3 - ACTOR_MUTATION_FATAL_SAFETY_MS;
280
+ actorMutationLeaseByRequest.set(request, lease);
281
+ scheduleActorMutationLeaseRefresh(request, lease);
282
+ lease.deadlineTimer = lease.runtime.schedule(() => {
283
+ poisonActorMutationLease(
284
+ request,
285
+ lease,
286
+ new Error("managed actor mutation handler exceeded its bounded lifetime")
287
+ );
288
+ }, ACTOR_MUTATION_HANDLER_DEADLINE_MS);
289
+ }
290
+ function scheduleActorMutationLeaseRefresh(request, lease) {
291
+ const timer = lease.runtime.schedule(() => {
292
+ if (actorMutationLeaseByRequest.get(request) !== lease) return;
293
+ const refreshStartedAtMonotonicMs = lease.runtime.monotonicNow();
294
+ void acquireManagedAuthActorMutationLease(lease.db, {
295
+ authorityHash: lease.authorityHash,
296
+ actorEpoch: lease.actorEpoch,
297
+ requestId: lease.requestId,
298
+ leaseSeconds: ACTOR_MUTATION_LEASE_SECONDS
299
+ }).then(async (expiresAt) => {
300
+ if (actorMutationLeaseByRequest.get(request) !== lease) {
301
+ await releaseManagedAuthActorMutationLease(lease.db, {
302
+ authorityHash: lease.authorityHash,
303
+ requestId: lease.requestId
304
+ });
305
+ return;
306
+ }
307
+ lease.expiresAt = expiresAt;
308
+ lease.localFatalDeadlineMonotonicMs = refreshStartedAtMonotonicMs + ACTOR_MUTATION_LEASE_SECONDS * 1e3 - ACTOR_MUTATION_FATAL_SAFETY_MS;
309
+ scheduleActorMutationLeaseRefresh(request, lease);
310
+ }).catch((error) => poisonActorMutationLease(request, lease, error));
311
+ }, ACTOR_MUTATION_LEASE_REFRESH_MS);
312
+ lease.refreshTimer = timer;
313
+ }
314
+ function poisonActorMutationLease(request, lease, error) {
315
+ if (actorMutationLeaseByRequest.get(request) !== lease || lease.poisoned !== null) return;
316
+ lease.poisoned = error;
317
+ if (lease.refreshTimer) lease.runtime.cancel(lease.refreshTimer);
318
+ lease.refreshTimer = null;
319
+ lease.abortController.abort(error);
320
+ const fatalAfterMs = Math.max(
321
+ 0,
322
+ lease.localFatalDeadlineMonotonicMs - lease.runtime.monotonicNow()
323
+ );
324
+ lease.fatalTimer = lease.runtime.schedule(() => {
325
+ if (actorMutationLeaseByRequest.get(request) !== lease) return;
326
+ lease.runtime.terminate();
327
+ }, fatalAfterMs);
328
+ }
329
+ function unrefTimer(timer) {
330
+ timer.unref?.();
331
+ return timer;
332
+ }
333
+ function requestCookie(request, name) {
334
+ const header = request.headers.get("cookie");
335
+ if (!header) return null;
336
+ for (const part of header.split(";")) {
337
+ const separator = part.indexOf("=");
338
+ if (separator < 0 || part.slice(0, separator).trim() !== name) continue;
339
+ const value = part.slice(separator + 1).trim();
340
+ if (!value || value.length > 512) return null;
341
+ try {
342
+ return decodeURIComponent(value);
343
+ } catch {
344
+ return null;
345
+ }
346
+ }
347
+ return null;
348
+ }
349
+ function setCookieHeaders(headers) {
350
+ const getSetCookie = headers.getSetCookie;
351
+ if (getSetCookie) {
352
+ return getSetCookie.call(headers);
353
+ }
354
+ const cookie = headers.get("set-cookie");
355
+ return cookie ? [cookie] : [];
356
+ }
357
+
358
+ export {
359
+ getManagedSession,
360
+ getManagedAuthRequestActorEpoch,
361
+ releaseManagedAuthRequestActorLease,
362
+ getManagedAuthRequestActorAbortSignal,
363
+ validateManagedAuthRequestActorLease,
364
+ ManagedAuthActorLeaseOutcomeUnknownError,
365
+ markManagedAuthRequestActorTransitionApplied,
366
+ getManagedAuthRequestActorAdmissionStamp,
367
+ getManagedAuthRequestActorLeaseStamp
368
+ };
369
+ //# sourceMappingURL=chunk-ZVZJTMSV.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/managed-session.ts"],"sourcesContent":["import type { Context } from \"hono\";\nimport type { ManagedAuth } from \"./managed-auth-type\";\nimport type { Database } from \"@opengeni/db\";\nimport {\n acquireManagedAuthActorMutationLease,\n getManagedAuthAdoptedSessionSnapshot,\n getManagedAuthSessionSetSnapshot,\n ManagedAuthSessionSetAuthorityError,\n ManagedAuthSessionSetGenerationConflictError,\n releaseManagedAuthActorMutationLease,\n validateManagedAuthActorMutationLease,\n} from \"@opengeni/db/managed-auth-session-sets\";\nimport { validateCanonicalHumanSession } from \"@opengeni/db/canonical-human-identities\";\nimport type { ManagedAuthSessionSetMode } from \"@opengeni/contracts/managed-auth-session-sets\";\nimport { HTTPException } from \"hono/http-exception\";\nimport {\n MANAGED_AUTH_ACTOR_EPOCH_HEADER,\n MANAGED_AUTH_SESSION_SET_COOKIE,\n ManagedAuthActorChangeError,\n managedAuthSha256,\n resolveManagedAuthSelectedSession,\n type ManagedAuthSessionAdapter,\n} from \"./managed-auth-session-sets\";\n\nconst ACTOR_MUTATION_LEASE_SECONDS = 15 * 60;\nconst ACTOR_MUTATION_LEASE_REFRESH_MS = 5 * 60 * 1_000;\nconst ACTOR_MUTATION_HANDLER_DEADLINE_MS = 10 * 60 * 1_000;\nconst ACTOR_MUTATION_FATAL_SAFETY_MS = 5_000;\ntype ActorMutationLeaseRuntime = {\n monotonicNow: () => number;\n schedule: (callback: () => void, delayMs: number) => ReturnType<typeof setTimeout>;\n cancel: (timer: ReturnType<typeof setTimeout>) => void;\n terminate: () => void;\n};\nconst productionActorMutationLeaseRuntime: ActorMutationLeaseRuntime = {\n monotonicNow: () => performance.now(),\n schedule: (callback, delayMs) => unrefTimer(setTimeout(callback, delayMs)),\n cancel: (timer) => clearTimeout(timer),\n terminate: () => {\n process.stderr.write(\"fatal: managed actor mutation outlived its durable lease\\n\");\n process.exit(1);\n },\n};\nlet actorMutationLeaseRuntime = productionActorMutationLeaseRuntime;\ntype ActorMutationLease = {\n db: Database;\n authorityHash: string;\n actorEpoch: string;\n requestId: string;\n refreshTimer: ReturnType<typeof setTimeout> | null;\n deadlineTimer: ReturnType<typeof setTimeout> | null;\n fatalTimer: ReturnType<typeof setTimeout> | null;\n expiresAt: Date;\n localFatalDeadlineMonotonicMs: number;\n runtime: ActorMutationLeaseRuntime;\n abortController: AbortController;\n poisoned: unknown | null;\n actorTransitionApplied: boolean;\n};\nconst actorMutationLeaseByRequest = new WeakMap<Request, ActorMutationLease>();\nconst managedActorEpochByRequest = new WeakMap<Request, string>();\nconst managedActorAdmissionByRequest = new WeakMap<Request, ManagedAuthActorAdmissionStamp>();\n\n/**\n * Read a Better Auth session without bypassing its sliding-cookie renewal.\n *\n * Better Auth can refresh the durable session while resolving `getSession`.\n * Programmatic callers must explicitly request and forward the returned cookie\n * headers; the HTTP handler does this automatically, but direct API calls do not.\n */\nexport async function getManagedSession(\n c: Context,\n auth: ManagedAuth,\n options?: {\n db?: Database | undefined;\n allowIdentityRecovery?: boolean | undefined;\n sessionSetMode?: ManagedAuthSessionSetMode | undefined;\n sessionAdapter?: ManagedAuthSessionAdapter | null | undefined;\n },\n) {\n const sessionSetMode = options?.sessionSetMode ?? \"legacy\";\n if (sessionSetMode !== \"legacy\" && options?.db && options.sessionAdapter) {\n const authority = requestCookie(c.req.raw, MANAGED_AUTH_SESSION_SET_COOKIE);\n if (authority) {\n try {\n // A long-lived response reuses this exact Request for periodic\n // authorization. Once admitted, the server-owned stamp is the actor\n // fence: a client may omit the header on its initial GET, but a later\n // reauthorization must not follow a newly selected actor.\n const admittedActorEpoch = managedActorEpochByRequest.get(c.req.raw) ?? null;\n const expectedActorEpoch =\n admittedActorEpoch ?? c.req.header(MANAGED_AUTH_ACTOR_EPOCH_HEADER) ?? null;\n const legacyAmbient =\n sessionSetMode === \"dual\" && expectedActorEpoch === null\n ? await options.sessionAdapter.resolveAmbientSession(c.req.raw.headers)\n : null;\n const selected = await resolveManagedAuthSelectedSession({\n db: options.db,\n adapter: options.sessionAdapter,\n authority,\n mode: sessionSetMode,\n expectedActorEpoch,\n legacyAmbientSessionId:\n typeof legacyAmbient?.session?.id === \"string\" ? legacyAmbient.session.id : null,\n allowRecovery: options.allowIdentityRecovery ?? false,\n });\n if (selected) {\n // The actor epoch is both an admission fence and response provenance.\n // A browser must ignore a late finite response after another tab has\n // advanced selection, even when the request itself was read-only.\n if (admittedActorEpoch === null) {\n c.header(MANAGED_AUTH_ACTOR_EPOCH_HEADER, selected.projection.actorEpoch);\n managedActorEpochByRequest.set(c.req.raw, selected.projection.actorEpoch);\n }\n managedActorAdmissionByRequest.set(c.req.raw, {\n authorityHash: managedAuthSha256(authority),\n actorEpoch: selected.projection.actorEpoch,\n });\n }\n if (selected && !selected.session) return null;\n if (selected?.session) {\n let resolvedSession = selected.session;\n if (requestNeedsActorMutationLease(c.req.method)) {\n await ensureActorMutationLease(\n c.req.raw,\n options.db,\n authority,\n selected.projection.actorEpoch,\n );\n const selectedSlot = await selectedSlotForAuthority(\n options.db,\n authority,\n sessionSetMode,\n options.allowIdentityRecovery ?? false,\n );\n if (!selectedSlot) throw new ManagedAuthActorChangeError();\n const refreshed = await options.sessionAdapter.refreshSelectedSession(selectedSlot);\n if (\n !refreshed ||\n refreshed.session.id !== selectedSlot.authSessionId ||\n refreshed.user.id !== selectedSlot.authUserId\n ) {\n throw new ManagedAuthActorChangeError();\n }\n resolvedSession = refreshed;\n }\n return resolvedSession;\n }\n // Once a browser presents a session-set authority it is authoritative.\n // An absent/expired/rekeyed authority must never fall through to an\n // ambient Better Auth cookie in dual mode: that would bypass the actor\n // epoch and mutation-lease fences after another tab transitions.\n return null;\n } catch (error) {\n if (error instanceof ManagedAuthActorChangeError) {\n // Response headers are immutable after an SSE body starts. The\n // original response already carries its actor epoch; reauthorization\n // closes that stream through the thrown conflict instead.\n if (!managedActorEpochByRequest.has(c.req.raw)) {\n c.header(\"x-opengeni-actor-state\", \"changed\");\n }\n throw new HTTPException(409, { message: error.code, cause: error });\n }\n throw error;\n }\n }\n if (sessionSetMode === \"broker\") return null;\n const ambient = await options.sessionAdapter.resolveAmbientSession(c.req.raw.headers);\n if (ambient?.session?.id)\n try {\n const adopted = await getManagedAuthAdoptedSessionSnapshot(options.db, ambient.session.id);\n if (adopted) {\n const admittedActorEpoch = managedActorEpochByRequest.get(c.req.raw) ?? null;\n if (\n adopted.actorEpoch !== \"1\" ||\n (admittedActorEpoch !== null && adopted.actorEpoch !== admittedActorEpoch) ||\n !adopted.selected ||\n adopted.selected.authSessionId !== ambient.session.id ||\n adopted.selected.authUserId !== ambient.user.id\n ) {\n throw new ManagedAuthActorChangeError();\n }\n if (admittedActorEpoch === null) {\n c.header(MANAGED_AUTH_ACTOR_EPOCH_HEADER, adopted.actorEpoch);\n managedActorEpochByRequest.set(c.req.raw, adopted.actorEpoch);\n }\n managedActorAdmissionByRequest.set(c.req.raw, {\n authorityHash: adopted.authorityHash,\n actorEpoch: adopted.actorEpoch,\n });\n if (requestNeedsActorMutationLease(c.req.method)) {\n await ensureActorMutationLeaseForHash(\n c.req.raw,\n options.db,\n adopted.authorityHash,\n adopted.actorEpoch,\n );\n const current = await getManagedAuthAdoptedSessionSnapshot(\n options.db,\n ambient.session.id,\n );\n if (\n current?.authorityHash !== adopted.authorityHash ||\n current.actorEpoch !== adopted.actorEpoch ||\n !current.selected ||\n current.selected.authSessionId !== ambient.session.id\n ) {\n throw new ManagedAuthActorChangeError();\n }\n const refreshed = await options.sessionAdapter.refreshSelectedSession(current.selected);\n if (\n !refreshed ||\n refreshed.session.id !== ambient.session.id ||\n refreshed.user.id !== ambient.user.id\n ) {\n throw new ManagedAuthActorChangeError();\n }\n return refreshed;\n }\n return ambient;\n }\n } catch (error) {\n if (error instanceof ManagedAuthActorChangeError) {\n if (!managedActorEpochByRequest.has(c.req.raw)) {\n c.header(\"x-opengeni-actor-state\", \"changed\");\n }\n throw new HTTPException(409, { message: error.code, cause: error });\n }\n throw error;\n }\n }\n const result = await auth.api.getSession({\n headers: c.req.raw.headers,\n returnHeaders: true,\n });\n\n for (const cookie of setCookieHeaders(result.headers)) {\n c.header(\"set-cookie\", cookie, { append: true });\n }\n\n const session = result.response;\n if (!session?.user || !options?.db) return session;\n const authSessionId = session.session?.id;\n if (typeof authSessionId !== \"string\") return null;\n const valid = await validateCanonicalHumanSession(options.db, {\n authSessionId,\n authUserId: session.user.id,\n ...(options.allowIdentityRecovery === undefined\n ? {}\n : { allowRecovery: options.allowIdentityRecovery }),\n });\n return valid ? session : null;\n}\n\n/** Safe response provenance for a request authenticated through session-set authority. */\nexport function getManagedAuthRequestActorEpoch(request: Request): string | null {\n return managedActorEpochByRequest.get(request) ?? null;\n}\n\nfunction selectedSlotForAuthority(\n db: Database,\n authority: string,\n mode: ManagedAuthSessionSetMode,\n allowRecovery: boolean,\n) {\n return getManagedAuthSessionSetSnapshot(db, {\n authorityHash: managedAuthSha256(authority),\n mode,\n includeInternal: true,\n allowRecovery,\n readOnly: true,\n }).then((snapshot) => snapshot?.selected ?? null);\n}\n\n/** Release the multi-replica actor fence after the outer HTTP handler settles. */\nexport async function releaseManagedAuthRequestActorLease(request: Request): Promise<void> {\n const lease = actorMutationLeaseByRequest.get(request);\n if (!lease) return;\n actorMutationLeaseByRequest.delete(request);\n if (lease.refreshTimer) lease.runtime.cancel(lease.refreshTimer);\n if (lease.deadlineTimer) lease.runtime.cancel(lease.deadlineTimer);\n if (lease.fatalTimer) lease.runtime.cancel(lease.fatalTimer);\n await releaseManagedAuthActorMutationLease(lease.db, {\n authorityHash: lease.authorityHash,\n requestId: lease.requestId,\n });\n}\n\n/** Cooperative cancellation signal for actor-scoped provider/external I/O. */\nexport function getManagedAuthRequestActorAbortSignal(request: Request): AbortSignal | null {\n return actorMutationLeaseByRequest.get(request)?.abortController.signal ?? null;\n}\n\n/** @internal Deterministic lease-clock seam used only by direct lifecycle tests. */\nexport function installManagedAuthActorLeaseRuntimeForTest(\n overrides: Partial<ActorMutationLeaseRuntime>,\n): () => void {\n const previous = actorMutationLeaseRuntime;\n actorMutationLeaseRuntime = {\n ...productionActorMutationLeaseRuntime,\n ...overrides,\n };\n return () => {\n actorMutationLeaseRuntime = previous;\n };\n}\n\n/**\n * Exact post-handler fence. A finite unsafe response is not released unless\n * its request-owned lease is still live at the same actor epoch.\n */\nexport async function validateManagedAuthRequestActorLease(request: Request): Promise<void> {\n const lease = actorMutationLeaseByRequest.get(request);\n if (!lease) return;\n if (lease.actorTransitionApplied) return;\n if (lease.poisoned !== null) {\n throw new ManagedAuthActorLeaseOutcomeUnknownError({\n cause: lease.poisoned,\n });\n }\n const valid = await validateManagedAuthActorMutationLease(lease.db, {\n authorityHash: lease.authorityHash,\n actorEpoch: lease.actorEpoch,\n requestId: lease.requestId,\n });\n if (!valid) throw new ManagedAuthActorChangeError();\n}\n\nexport class ManagedAuthActorLeaseOutcomeUnknownError extends Error {\n readonly name = \"ManagedAuthActorLeaseOutcomeUnknownError\";\n readonly code = \"operation_outcome_unknown\";\n constructor(options?: ErrorOptions) {\n super(\"The actor-scoped request outcome is unknown after its durable lease was lost\", options);\n }\n}\n\n/** A known-applied same-request canonical transition intentionally consumes its lease. */\nexport function markManagedAuthRequestActorTransitionApplied(request: Request): void {\n const lease = actorMutationLeaseByRequest.get(request);\n if (lease) lease.actorTransitionApplied = true;\n}\n\nexport type ManagedAuthActorMutationLeaseStamp = {\n authorityHash: string;\n actorEpoch: string;\n requestId: string;\n};\n\nexport type ManagedAuthActorAdmissionStamp = {\n authorityHash: string;\n actorEpoch: string;\n};\n\n/** Verified server-owned actor evidence available to both reads and mutations. */\nexport function getManagedAuthRequestActorAdmissionStamp(\n request: Request,\n): ManagedAuthActorAdmissionStamp | null {\n return managedActorAdmissionByRequest.get(request) ?? null;\n}\n\n/** Exact request-owned fence passed into a same-transaction actor transition. */\nexport function getManagedAuthRequestActorLeaseStamp(\n request: Request,\n): ManagedAuthActorMutationLeaseStamp | null {\n const lease = actorMutationLeaseByRequest.get(request);\n return lease\n ? {\n authorityHash: lease.authorityHash,\n actorEpoch: lease.actorEpoch,\n requestId: lease.requestId,\n }\n : null;\n}\n\nfunction requestNeedsActorMutationLease(method: string): boolean {\n return method !== \"GET\" && method !== \"HEAD\" && method !== \"OPTIONS\";\n}\n\nasync function ensureActorMutationLease(\n request: Request,\n db: Database,\n authority: string,\n actorEpoch: string,\n): Promise<void> {\n const authorityHash = managedAuthSha256(authority);\n await ensureActorMutationLeaseForHash(request, db, authorityHash, actorEpoch);\n}\n\nasync function ensureActorMutationLeaseForHash(\n request: Request,\n db: Database,\n authorityHash: string,\n actorEpoch: string,\n): Promise<void> {\n const existing = actorMutationLeaseByRequest.get(request);\n if (existing) {\n if (existing.authorityHash !== authorityHash || existing.actorEpoch !== actorEpoch) {\n throw new ManagedAuthActorChangeError();\n }\n return;\n }\n const lease: ActorMutationLease = {\n db,\n authorityHash,\n actorEpoch,\n requestId: crypto.randomUUID(),\n refreshTimer: null,\n deadlineTimer: null,\n fatalTimer: null,\n expiresAt: new Date(0),\n localFatalDeadlineMonotonicMs: 0,\n runtime: actorMutationLeaseRuntime,\n abortController: new AbortController(),\n poisoned: null,\n actorTransitionApplied: false,\n };\n const acquireStartedAtMonotonicMs = lease.runtime.monotonicNow();\n try {\n lease.expiresAt = await acquireManagedAuthActorMutationLease(db, {\n authorityHash,\n actorEpoch,\n requestId: lease.requestId,\n leaseSeconds: ACTOR_MUTATION_LEASE_SECONDS,\n });\n } catch (error) {\n if (\n error instanceof ManagedAuthSessionSetGenerationConflictError ||\n error instanceof ManagedAuthSessionSetAuthorityError\n ) {\n throw new ManagedAuthActorChangeError();\n }\n throw error;\n }\n lease.localFatalDeadlineMonotonicMs =\n acquireStartedAtMonotonicMs +\n ACTOR_MUTATION_LEASE_SECONDS * 1_000 -\n ACTOR_MUTATION_FATAL_SAFETY_MS;\n actorMutationLeaseByRequest.set(request, lease);\n scheduleActorMutationLeaseRefresh(request, lease);\n lease.deadlineTimer = lease.runtime.schedule(() => {\n poisonActorMutationLease(\n request,\n lease,\n new Error(\"managed actor mutation handler exceeded its bounded lifetime\"),\n );\n }, ACTOR_MUTATION_HANDLER_DEADLINE_MS);\n}\n\nfunction scheduleActorMutationLeaseRefresh(request: Request, lease: ActorMutationLease): void {\n const timer = lease.runtime.schedule(() => {\n if (actorMutationLeaseByRequest.get(request) !== lease) return;\n const refreshStartedAtMonotonicMs = lease.runtime.monotonicNow();\n void acquireManagedAuthActorMutationLease(lease.db, {\n authorityHash: lease.authorityHash,\n actorEpoch: lease.actorEpoch,\n requestId: lease.requestId,\n leaseSeconds: ACTOR_MUTATION_LEASE_SECONDS,\n })\n .then(async (expiresAt) => {\n if (actorMutationLeaseByRequest.get(request) !== lease) {\n // Release may have won while this pooled acquire statement was in\n // flight. Converge the just-renewed row immediately; never resurrect\n // a request-owned fence after the outer handler has settled.\n await releaseManagedAuthActorMutationLease(lease.db, {\n authorityHash: lease.authorityHash,\n requestId: lease.requestId,\n });\n return;\n }\n lease.expiresAt = expiresAt;\n lease.localFatalDeadlineMonotonicMs =\n refreshStartedAtMonotonicMs +\n ACTOR_MUTATION_LEASE_SECONDS * 1_000 -\n ACTOR_MUTATION_FATAL_SAFETY_MS;\n scheduleActorMutationLeaseRefresh(request, lease);\n })\n .catch((error) => poisonActorMutationLease(request, lease, error));\n }, ACTOR_MUTATION_LEASE_REFRESH_MS);\n lease.refreshTimer = timer;\n}\n\nfunction poisonActorMutationLease(\n request: Request,\n lease: ActorMutationLease,\n error: unknown,\n): void {\n if (actorMutationLeaseByRequest.get(request) !== lease || lease.poisoned !== null) return;\n lease.poisoned = error;\n if (lease.refreshTimer) lease.runtime.cancel(lease.refreshTimer);\n lease.refreshTimer = null;\n lease.abortController.abort(error);\n const fatalAfterMs = Math.max(\n 0,\n lease.localFatalDeadlineMonotonicMs - lease.runtime.monotonicNow(),\n );\n lease.fatalTimer = lease.runtime.schedule(() => {\n if (actorMutationLeaseByRequest.get(request) !== lease) return;\n // A handler that ignored cooperative cancellation must not outlive the\n // durable fence and resume under a later actor. Terminate this API\n // instance before PostgreSQL can expire the lease; process death is the\n // final multi-replica-safe cancellation boundary.\n lease.runtime.terminate();\n }, fatalAfterMs);\n}\n\nfunction unrefTimer<T extends ReturnType<typeof setTimeout>>(timer: T): T {\n (timer as T & { unref?: () => void }).unref?.();\n return timer;\n}\n\nfunction requestCookie(request: Request, name: string): string | null {\n const header = request.headers.get(\"cookie\");\n if (!header) return null;\n for (const part of header.split(\";\")) {\n const separator = part.indexOf(\"=\");\n if (separator < 0 || part.slice(0, separator).trim() !== name) continue;\n const value = part.slice(separator + 1).trim();\n if (!value || value.length > 512) return null;\n try {\n return decodeURIComponent(value);\n } catch {\n return null;\n }\n }\n return null;\n}\n\nfunction setCookieHeaders(headers: Headers): string[] {\n const getSetCookie = (\n headers as Headers & {\n getSetCookie?: () => string[];\n }\n ).getSetCookie;\n if (getSetCookie) {\n return getSetCookie.call(headers);\n }\n\n const cookie = headers.get(\"set-cookie\");\n return cookie ? [cookie] : [];\n}\n"],"mappings":"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","names":[]}
@@ -6,6 +6,7 @@ import type { EventBus } from "@opengeni/events";
6
6
  import type { Observability } from "@opengeni/observability";
7
7
  import type { createObjectStorage } from "@opengeni/storage";
8
8
  import type { ManagedAuth } from "./managed-auth-type.js";
9
+ import type { ManagedAuthSessionAdapter } from "./managed-auth-session-sets.js";
9
10
  import type { ApiSandboxClient, ResumeBoxByIdInput, ResumedSandboxSession } from "./sandbox-types.js";
10
11
  import type { TranscriptionSegmenter, TranscriptionService } from "./transcription.js";
11
12
  import type { EditableArtifactApplicationPort } from "./editable-artifact-live.js";
@@ -162,6 +163,8 @@ export type AppDependencies = {
162
163
  */
163
164
  sessionAuthorization?: SessionAuthorizationPort | null;
164
165
  managedAuth?: ManagedAuth | null;
166
+ /** Provider-neutral browser login-slot adapter; required by dual/broker managed auth. */
167
+ managedAuthSessionAdapter?: ManagedAuthSessionAdapter | null;
165
168
  /** Injectable managed-email transport; standalone API defaults to Resend or local capture. */
166
169
  managedEmailTransport?: ManagedEmailTransport;
167
170
  /** Injectable Codex HTTP transport for deterministic API/provider tests. */
@@ -213,6 +213,8 @@ export declare function postUserMessageTurn(input: {
213
213
  annotations?: TimelineAnnotation[];
214
214
  modelContext?: string | null;
215
215
  resources: ResourceRef[];
216
+ /** Actor-owned resources used only for the exact durable-draft fence. */
217
+ composerDraftResources?: ResourceRef[];
216
218
  model?: string | null;
217
219
  reasoningEffort?: Settings["openaiReasoningEffort"] | null;
218
220
  latencyMode?: "standard" | "priority" | "fast" | null;
@@ -272,6 +274,8 @@ export declare function acceptSessionUserMessageWithOutcome(deps: AcceptSessionU
272
274
  annotations?: SubmittedTimelineAnnotation[];
273
275
  modelContext?: string | null;
274
276
  resources?: ResourceRef[];
277
+ /** Actor-owned resources used only for the exact durable-draft fence. */
278
+ composerDraftResources?: ResourceRef[];
275
279
  model?: string | null;
276
280
  reasoningEffort?: ReasoningEffort | null;
277
281
  latencyMode?: "standard" | "priority" | "fast" | null;
package/dist/index.d.ts CHANGED
@@ -2,7 +2,7 @@ export * from "./dependencies.js";
2
2
  export * from "./workflow-wake-contract.js";
3
3
  export * from "./sandbox-types.js";
4
4
  export * from "./managed-auth-type.js";
5
- export * from "./managed-session.js";
5
+ export { getManagedAuthRequestActorAbortSignal, getManagedAuthRequestActorAdmissionStamp, getManagedAuthRequestActorEpoch, getManagedAuthRequestActorLeaseStamp, getManagedSession, ManagedAuthActorLeaseOutcomeUnknownError, markManagedAuthRequestActorTransitionApplied, releaseManagedAuthRequestActorLease, validateManagedAuthRequestActorLease, type ManagedAuthActorAdmissionStamp, type ManagedAuthActorMutationLeaseStamp, } from "./managed-session.js";
6
6
  export * from "./transcription.js";
7
7
  export * from "./sandbox/fleet.js";
8
8
  export * from "./sandbox/routing.js";
@@ -42,6 +42,7 @@ export * from "./domain/video-generation.js";
42
42
  export * from "./domain/video-generation-capabilities.js";
43
43
  export * from "./domain/organization-membership-lifecycle.js";
44
44
  export * from "./application/new-session-drafts.js";
45
+ export * from "./application/composer-submit.js";
45
46
  export * from "./application/session-commands.js";
46
47
  export * from "./application/session-tenancy.js";
47
48
  export * from "./application/user-resource-grants.js";