@happyvertical/smrt-app-runtime 0.57.8 → 0.57.10

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,570 @@
1
+ import { B as deepFrozenPlainCopy, G as initializeDeployedApplicationRuntime, H as resolveBoundMembershipPermissions, K as isSessionTenantAuthorized, M as runtimeConfigurationFingerprint, R as isLocalMcpTokenPrincipal, V as ownValue, b as projectRuntimeDiagnostics, c as validateApplicationId, h as resolveApplicationStateRoot, i as initializeLocalApplicationRuntime, j as resolveApplicationId, p as prepareApplicationStateRoot, s as resolveLocalRuntimePaths, u as acquireWriterLease, z as PlainDataError } from "./chunks/src-C98Cqurb.js";
2
+ import { n as normalizeTenantSelection, t as createSubdomainTenantSelector } from "./chunks/tenancy-BzdIxH2M.js";
3
+ import { loadConfig, resolveEffectiveApplicationRuntime } from "@happyvertical/smrt-config";
4
+ import { OidcIdentityCollection } from "@happyvertical/smrt-profiles";
5
+ import { enableTenancy, getCurrentTenant, isTenancyEnabled, withSystemContext } from "@happyvertical/smrt-tenancy";
6
+ import { MembershipCollection, PermissionResolver, SessionService, UserCollection, UserStatus, getCurrentSessionPermissionContext, getRequestScopedDatabase, withPrincipalPermissionContext, withSessionPermissionContext } from "@happyvertical/smrt-users";
7
+ import { getDatabase } from "@happyvertical/sql";
8
+ import { ObjectRegistry } from "@happyvertical/smrt-core";
9
+ //#region src/sveltekit/runtime.ts
10
+ var DEFAULT_SESSION_TTL_SECONDS = 10080 * 60;
11
+ function createSmrtSvelteKitRuntime(options = {}) {
12
+ return composeSmrtSvelteKitRuntime(options, {});
13
+ }
14
+ function composeSmrtSvelteKitRuntime(options, seams) {
15
+ const env = options.env ?? process.env;
16
+ const sourceRoot = options.sourceRoot ?? process.cwd();
17
+ const dataDirectory = options.dataDirectory ?? env.SMRT_DATA_DIR;
18
+ const initializeLocal = seams.initializeLocal ?? initializeLocalApplicationRuntime;
19
+ const initializeDeployed = seams.initializeDeployed ?? initializeDeployedApplicationRuntime;
20
+ if (options.enableTenancy !== false && !isTenancyEnabled()) enableTenancy();
21
+ let appId;
22
+ const applicationId = () => {
23
+ appId ??= options.appId ? validateApplicationId(options.appId) : resolveApplicationId({
24
+ sourceRoot,
25
+ explicitId: env.SMRT_APP_ID
26
+ });
27
+ return appId;
28
+ };
29
+ let resolved;
30
+ let resolvedPromise;
31
+ const resolvedRuntime = () => {
32
+ resolvedPromise ??= (async () => {
33
+ const value = typeof options.runtime === "function" ? await options.runtime() : options.runtime ?? await (seams.loadRuntime ?? loadConfiguredRuntime)();
34
+ resolved = value;
35
+ return value;
36
+ })().catch((error) => {
37
+ resolvedPromise = void 0;
38
+ throw error;
39
+ });
40
+ return resolvedPromise;
41
+ };
42
+ const requireResolved = () => {
43
+ if (!resolved) throw new Error("The SMRT application runtime is not resolved yet; await init() first.");
44
+ return resolved;
45
+ };
46
+ const baseDatabaseConfig = () => {
47
+ const runtime = requireResolved();
48
+ if (runtime.profile === "local") {
49
+ const paths = resolveLocalRuntimePaths({
50
+ appId: applicationId(),
51
+ dataDirectory,
52
+ sourceRoot,
53
+ env
54
+ });
55
+ return {
56
+ type: "sqlite",
57
+ url: paths.database,
58
+ secureFile: {
59
+ driver: "node:sqlite",
60
+ custody: "trusted-parent",
61
+ root: paths.root
62
+ }
63
+ };
64
+ }
65
+ const databaseUrl = env.DATABASE_URL;
66
+ if (!databaseUrl) throw new Error(`${runtime.profile} requires DATABASE_URL.`);
67
+ return {
68
+ type: "postgres",
69
+ url: databaseUrl
70
+ };
71
+ };
72
+ const baseClassOptions = (className) => {
73
+ const defaults = { db: baseDatabaseConfig() };
74
+ const override = options.classOverrides?.[className];
75
+ return override ? {
76
+ ...defaults,
77
+ ...override
78
+ } : defaults;
79
+ };
80
+ const rlsRequestDatabase = () => {
81
+ if (getCurrentSessionPermissionContext()?.postgresRls !== true) return void 0;
82
+ return getRequestScopedDatabase() ?? void 0;
83
+ };
84
+ const databaseConfig = () => rlsRequestDatabase() ?? baseDatabaseConfig();
85
+ const classOptions = (className) => {
86
+ const base = baseClassOptions(className);
87
+ if (options.classOverrides?.[className]?.db !== void 0) return base;
88
+ const requestDb = rlsRequestDatabase();
89
+ return requestDb ? {
90
+ ...base,
91
+ db: requestDb
92
+ } : base;
93
+ };
94
+ const getCollection = (className) => ObjectRegistry.getCollection(className, classOptions(className));
95
+ const writerLease = options.acquireWriterLease === false ? void 0 : options.acquireWriterLease ?? ((context) => defaultWriterLease(context, env));
96
+ let localPromise;
97
+ let localLease;
98
+ const localRuntime = async () => {
99
+ const runtime = await resolvedRuntime();
100
+ if (runtime.profile !== "local") throw new Error("Owner bootstrap is available only in the local profile.");
101
+ if (localPromise) return localPromise;
102
+ const bindHost = options.bindHost || env.HOST || (env.NODE_ENV === "development" ? "127.0.0.1" : null);
103
+ if (!bindHost) throw new Error("Local production startup requires an explicit loopback HOST; use pnpm app:start.");
104
+ const id = applicationId();
105
+ localLease ??= writerLease?.({
106
+ appId: id,
107
+ dataDirectory,
108
+ sourceRoot
109
+ });
110
+ localPromise = initializeLocal({
111
+ appId: id,
112
+ dataDirectory,
113
+ sourceRoot,
114
+ env,
115
+ bindHost,
116
+ providers: {
117
+ database: runtime.providers.database,
118
+ authentication: runtime.providers.authentication,
119
+ tenancy: runtime.providers.tenancy,
120
+ assets: runtime.providers.assets,
121
+ secrets: runtime.providers.secrets,
122
+ jobs: runtime.providers.jobs,
123
+ network: runtime.providers.network
124
+ },
125
+ backgroundJobs: options.backgroundJobs ?? env.SMRT_BACKGROUND_JOBS === "true",
126
+ paidCapabilities: options.paidCapabilities,
127
+ bootstrapTtlSeconds: options.bootstrapTtlSeconds,
128
+ sessionTtlSeconds: options.sessionTtlSeconds,
129
+ ownerTenant: options.ownerTenant,
130
+ passwordPolicy: options.passwordPolicy,
131
+ prepareDatabase: options.prepareDatabase,
132
+ now: options.now
133
+ }).then(({ runtime: initialized, bootstrap }) => {
134
+ if (bootstrap) try {
135
+ options.onBootstrapInvitation?.(bootstrap, { bindHost });
136
+ } catch {}
137
+ return initialized;
138
+ }).catch((error) => {
139
+ localLease?.release();
140
+ localLease = void 0;
141
+ localPromise = void 0;
142
+ throw error;
143
+ });
144
+ return localPromise;
145
+ };
146
+ let deployedPromise;
147
+ const deployedRuntime = async () => {
148
+ const runtime = await resolvedRuntime();
149
+ if (runtime.profile === "local") throw new Error("deployed_runtime_unavailable");
150
+ const profile = runtime.profile;
151
+ const databaseUrl = env.DATABASE_URL;
152
+ if (!databaseUrl) throw new Error(`${profile} requires DATABASE_URL.`);
153
+ const authenticationProvider = runtime.providers.authentication.provider;
154
+ if (authenticationProvider === "owner-bootstrap") throw new Error("Deployed profiles require public authentication.");
155
+ const readiness = options.providerReadiness;
156
+ if (!readiness) throw new Error(`${profile} requires providerReadiness probes for authentication, assets, and secrets.`);
157
+ deployedPromise ??= initializeDeployed({
158
+ profile,
159
+ providers: {
160
+ database: runtime.providers.database,
161
+ authentication: runtime.providers.authentication,
162
+ tenancy: runtime.providers.tenancy,
163
+ assets: runtime.providers.assets,
164
+ secrets: runtime.providers.secrets,
165
+ jobs: runtime.providers.jobs,
166
+ network: runtime.providers.network
167
+ },
168
+ database: {
169
+ engine: "postgres",
170
+ connect: () => getDatabase({
171
+ type: "postgres",
172
+ url: databaseUrl
173
+ }),
174
+ close: async (db) => {
175
+ await db.close?.();
176
+ }
177
+ },
178
+ authentication: {
179
+ provider: authenticationProvider,
180
+ readiness: readiness("authentication", {
181
+ profile,
182
+ provider: authenticationProvider
183
+ })
184
+ },
185
+ assets: {
186
+ provider: runtime.providers.assets.provider,
187
+ readiness: readiness("assets", {
188
+ profile,
189
+ provider: runtime.providers.assets.provider
190
+ })
191
+ },
192
+ secrets: {
193
+ provider: runtime.providers.secrets.provider,
194
+ readiness: readiness("secrets", {
195
+ profile,
196
+ provider: runtime.providers.secrets.provider
197
+ })
198
+ },
199
+ prepareDatabase: options.prepareDatabase
200
+ });
201
+ return deployedPromise;
202
+ };
203
+ const ready = async () => {
204
+ if ((await resolvedRuntime()).profile === "local") {
205
+ await localRuntime();
206
+ return;
207
+ }
208
+ await deployedRuntime();
209
+ };
210
+ const configurationFingerprint = () => runtimeConfigurationFingerprint(requireResolved(), env);
211
+ const health = async () => {
212
+ await ready();
213
+ const runtime = requireResolved();
214
+ const publicHealth = {
215
+ schemaVersion: 1,
216
+ status: "ready",
217
+ profile: runtime.profile
218
+ };
219
+ return runtime.profile === "local" ? {
220
+ ...publicHealth,
221
+ application: applicationId(),
222
+ instance: env.SMRT_PROCESS_INSTANCE || null,
223
+ configuration: configurationFingerprint()
224
+ } : publicHealth;
225
+ };
226
+ const readDiagnostics = async (diagnosticsOptions) => {
227
+ await ready();
228
+ const runtime = requireResolved();
229
+ const schema = {
230
+ status: diagnosticsOptions.schemaStatus ?? "unknown",
231
+ migrations: diagnosticsOptions.migrationStatus ?? "unknown"
232
+ };
233
+ if (runtime.profile === "local") {
234
+ const diagnostics = await (await localRuntime()).diagnostics();
235
+ return projectRuntimeDiagnostics({
236
+ profile: "local",
237
+ health: "healthy",
238
+ schema,
239
+ capabilities: {
240
+ "asset-storage": "available",
241
+ authentication: "available",
242
+ "background-jobs": diagnostics.jobs.backgroundEnabled ? "available" : "disabled",
243
+ database: "available",
244
+ "paid-capabilities": diagnostics.paidCapabilitiesEnabled ? "available" : "disabled",
245
+ "secret-storage": "available"
246
+ },
247
+ toolNames: diagnosticsOptions.toolNames,
248
+ worker: {
249
+ topology: diagnostics.jobs.topology,
250
+ required: diagnostics.jobs.backgroundEnabled,
251
+ heartbeatAt: diagnosticsOptions.workerHeartbeatAt
252
+ },
253
+ recentErrors: diagnosticsOptions.recentErrors,
254
+ observedAt: diagnosticsOptions.observedAt
255
+ });
256
+ }
257
+ const deployed = await deployedPromise;
258
+ if (!deployed) throw new Error("deployed_runtime_unavailable");
259
+ const readiness = await deployed.readiness();
260
+ const componentStatus = (component) => readiness.components[component].status === "ready" ? "available" : "unavailable";
261
+ return projectRuntimeDiagnostics({
262
+ profile: runtime.profile,
263
+ health: deployed.health().status === "healthy" ? readiness.status === "ready" ? "healthy" : "degraded" : "stopped",
264
+ schema,
265
+ capabilities: {
266
+ "asset-storage": componentStatus("assets"),
267
+ authentication: componentStatus("authentication"),
268
+ "background-jobs": "available",
269
+ database: componentStatus("database"),
270
+ "paid-capabilities": "unknown",
271
+ "secret-storage": componentStatus("secrets")
272
+ },
273
+ toolNames: diagnosticsOptions.toolNames,
274
+ worker: {
275
+ topology: deployed.resolvedRuntime.providers.jobs.topology,
276
+ required: true,
277
+ heartbeatAt: diagnosticsOptions.workerHeartbeatAt
278
+ },
279
+ recentErrors: diagnosticsOptions.recentErrors,
280
+ observedAt: diagnosticsOptions.observedAt
281
+ });
282
+ };
283
+ const selectTenant = options.selectTenant ?? createSubdomainTenantSelector({
284
+ baseDomain: options.tenantBaseDomain ?? env.TENANT_BASE_DOMAIN,
285
+ classOptions: () => baseClassOptions("Tenant")
286
+ });
287
+ const readinessHandle = async ({ event, resolve }) => {
288
+ await ready();
289
+ return resolve(event);
290
+ };
291
+ const tenantSelectionHandle = async ({ event, resolve }) => {
292
+ const locals = runtimeLocals(event.locals);
293
+ const selection = normalizeTenantSelection(await selectTenant({
294
+ url: event.url,
295
+ request: event.request
296
+ }));
297
+ locals.selectedTenantId = selection.tenantId;
298
+ locals.selectedTenantSlug = selection.tenantSlug;
299
+ return resolve(event);
300
+ };
301
+ const sessionCookieName = options.session?.cookieName ?? "sid";
302
+ const sessionSkipPaths = options.session?.skipPaths ?? [];
303
+ const sessionServiceOptions = () => ({
304
+ ...baseClassOptions("Session"),
305
+ ...options.session,
306
+ defaultTTL: options.session?.ttl ?? DEFAULT_SESSION_TTL_SECONDS,
307
+ autoExtend: options.session?.autoExtend ?? false
308
+ });
309
+ const postgresRls = () => requireResolved().providers.tenancy.isolation === "database-rls" ? true : options.session?.postgresRls;
310
+ let permissionResolverPromise;
311
+ const permissionResolver = () => {
312
+ permissionResolverPromise ??= PermissionResolver.create(baseClassOptions("Permission")).catch((error) => {
313
+ permissionResolverPromise = void 0;
314
+ throw error;
315
+ });
316
+ return permissionResolverPromise;
317
+ };
318
+ const runAsPrincipal = async (principal, fn) => {
319
+ if (!principal || typeof principal !== "object") throw new Error("A bound principal is required.");
320
+ const snapshot = snapshotBoundPrincipal(principal);
321
+ const tokenDerived = isLocalMcpTokenPrincipal(snapshot);
322
+ const userId = ownValue(snapshot, "id");
323
+ const tenantId = ownValue(snapshot, "tenantId");
324
+ const snapshotScopes = ownValue(snapshot, "scopes");
325
+ const requestedTenantBinding = ownValue(snapshot, "tenantBinding");
326
+ const requestedScopes = snapshotScopes === void 0 ? void 0 : Object.freeze([...snapshotScopes]);
327
+ if (requestedScopes !== void 0 && !requestedScopes.every((scope) => typeof scope === "string")) throw new Error("A bound principal has malformed scopes.");
328
+ if (typeof userId !== "string" || userId.length === 0) throw new Error("A bound principal requires a user id.");
329
+ if (typeof tenantId !== "string" || tenantId.length === 0) throw new Error("A bound principal requires a tenant.");
330
+ if (tokenDerived && requestedTenantBinding !== void 0 && requestedTenantBinding !== "direct") throw new Error("A local MCP token principal binds only through its direct membership.");
331
+ const binding = tokenDerived ? "direct" : requestedTenantBinding ?? "direct-or-inherited";
332
+ if (binding !== "direct" && binding !== "direct-or-inherited") throw new Error("Unknown tenant binding mode for a bound principal.");
333
+ const resolved2 = await resolveBoundMembershipPermissions({
334
+ memberships: await MembershipCollection.create(baseClassOptions("Membership")),
335
+ resolver: await permissionResolver(),
336
+ userId,
337
+ tenantId,
338
+ binding
339
+ });
340
+ if (!resolved2) throw new Error(binding === "direct" ? "The bound principal has no active direct membership in its tenant." : "The bound principal has no authorized membership in its tenant.");
341
+ const cap = requestedScopes ? new Set(requestedScopes) : void 0;
342
+ const permissions = [...resolved2.permissions].filter((permission) => !cap || cap.has(permission));
343
+ return withPrincipalPermissionContext({
344
+ ...baseClassOptions("Session"),
345
+ userId,
346
+ tenantId,
347
+ permissions,
348
+ enterTenantContext: true,
349
+ postgresRls: postgresRls()
350
+ }, () => fn(Object.freeze(Object.assign(/* @__PURE__ */ Object.create(null), snapshot, {
351
+ id: userId,
352
+ tenantId,
353
+ tenantBinding: binding,
354
+ scopes: Object.freeze([...permissions])
355
+ }))));
356
+ };
357
+ const verifyLocalMcpToken = async (token) => {
358
+ if ((await resolvedRuntime()).profile !== "local") return null;
359
+ return await (await localRuntime()).mcpTokens?.verify(token) ?? null;
360
+ };
361
+ const resolveMcpPrincipal = async (identity) => {
362
+ if ((await resolvedRuntime()).profile === "local") return null;
363
+ if (!identity || typeof identity !== "object") return null;
364
+ const issuer = ownValue(identity, "issuer");
365
+ const subject = ownValue(identity, "subject");
366
+ if (typeof issuer !== "string" || issuer.length === 0 || typeof subject !== "string" || subject.length === 0) return null;
367
+ return withSystemContext(async () => {
368
+ const identities = await OidcIdentityCollection.create(baseClassOptions("OidcIdentity"));
369
+ let linked;
370
+ try {
371
+ linked = await identities.findBySubject(issuer, subject);
372
+ } catch {
373
+ return null;
374
+ }
375
+ if (!linked?.profileId) return null;
376
+ const owners = await (await UserCollection.create(baseClassOptions("User"))).list({
377
+ where: { profileId: linked.profileId },
378
+ limit: 2
379
+ });
380
+ const user = owners.length === 1 ? owners[0] : void 0;
381
+ if (typeof user?.id !== "string" || user.id.length === 0 || user.status !== UserStatus.ACTIVE) return null;
382
+ const memberships = await MembershipCollection.create(baseClassOptions("Membership"));
383
+ const tenants = new Set((await memberships.findActiveByUser(user.id)).map((membership) => membership.tenantId).filter((tenantId2) => typeof tenantId2 === "string" && tenantId2.length > 0));
384
+ if (tenants.size !== 1) return null;
385
+ const [tenantId] = tenants;
386
+ return Object.freeze({
387
+ id: user.id,
388
+ tenantId,
389
+ kind: "human",
390
+ tenantBinding: "direct"
391
+ });
392
+ });
393
+ };
394
+ let sessionServicePromise;
395
+ const sessionService = () => {
396
+ sessionServicePromise ??= (async () => {
397
+ const service = new TenantAuthorizingSessionService(sessionServiceOptions(), requireResolved().providers.tenancy.context === "required");
398
+ await service.initialize();
399
+ return service;
400
+ })().catch((error) => {
401
+ sessionServicePromise = void 0;
402
+ throw error;
403
+ });
404
+ return sessionServicePromise;
405
+ };
406
+ const sessionStep = async ({ event, resolve }) => {
407
+ const locals = runtimeLocals(event.locals);
408
+ clearSessionLocals(locals);
409
+ const rls = postgresRls();
410
+ const skipped = sessionSkipPaths.some((path) => event.url.pathname.startsWith(path));
411
+ if (skipped && !rls) return resolve(event);
412
+ const sessionId = skipped ? void 0 : event.cookies.get(sessionCookieName);
413
+ if (!sessionId && !rls) return resolve(event);
414
+ let resolveEntered = false;
415
+ let downstream;
416
+ try {
417
+ const service = await sessionService();
418
+ return await withSessionPermissionContext({
419
+ ...sessionServiceOptions(),
420
+ enterTenantContext: true,
421
+ postgresRls: rls,
422
+ sessionId: sessionId ?? null,
423
+ sessionService: service
424
+ }, async (context) => {
425
+ if (context.session) {
426
+ locals.user = context.user;
427
+ locals.membership = context.membership ?? null;
428
+ locals.permissions = context.permissions;
429
+ locals.tenantId = context.tenantId;
430
+ locals.sessionId = context.sessionId;
431
+ locals.authMethod = context.session.authMethod ?? null;
432
+ locals.sessionParent = context.session.parent ?? null;
433
+ if (context.tenantId) verifiedSessionTenants.set(locals, context.tenantId);
434
+ }
435
+ resolveEntered = true;
436
+ try {
437
+ return await resolve(event);
438
+ } catch (error) {
439
+ downstream = { error };
440
+ throw error;
441
+ }
442
+ });
443
+ } catch (error) {
444
+ if (downstream) throw downstream.error;
445
+ if (resolveEntered) throw error;
446
+ clearSessionLocals(locals);
447
+ return new Response("Internal Server Error", { status: 500 });
448
+ }
449
+ };
450
+ const sessionCookie = Object.freeze({
451
+ name: options.session?.cookieName ?? "sid",
452
+ path: options.session?.cookiePath ?? "/",
453
+ ...options.session?.cookieDomain ? { domain: options.session.cookieDomain } : {},
454
+ sameSite: options.session?.cookieSameSite ?? "lax",
455
+ ...options.session?.cookieSecure !== void 0 ? { secure: options.session.cookieSecure } : {},
456
+ maxAgeSeconds: options.sessionTtlSeconds ?? DEFAULT_SESSION_TTL_SECONDS
457
+ });
458
+ const init = () => ready();
459
+ return Object.freeze({
460
+ handle: composeHandles(readinessHandle, tenantSelectionHandle, sessionStep, authorizedTenantLocalsHandle),
461
+ init,
462
+ sessionCookie,
463
+ resolvedRuntime,
464
+ ready,
465
+ applicationId,
466
+ applicationStateRoot: () => resolveApplicationStateRoot({
467
+ appId: applicationId(),
468
+ dataDirectory,
469
+ sourceRoot
470
+ }),
471
+ configurationFingerprint,
472
+ databaseConfig,
473
+ classOptions,
474
+ getCollection,
475
+ runAsPrincipal,
476
+ verifyLocalMcpToken,
477
+ resolveMcpPrincipal,
478
+ localRuntime,
479
+ deployedRuntime,
480
+ health,
481
+ readDiagnostics
482
+ });
483
+ }
484
+ function defaultWriterLease(context, env = process.env) {
485
+ return acquireWriterLease(prepareApplicationStateRoot({
486
+ appId: context.appId,
487
+ dataDirectory: context.dataDirectory,
488
+ sourceRoot: context.sourceRoot
489
+ }), { operationInstance: env.SMRT_OPERATION_INSTANCE });
490
+ }
491
+ var verifiedSessionTenants = /* @__PURE__ */ new WeakMap();
492
+ var TenantAuthorizingSessionService = class extends SessionService {
493
+ tenantRequired;
494
+ constructor(options, tenantRequired) {
495
+ super(options);
496
+ this.tenantRequired = tenantRequired;
497
+ }
498
+ async loadSessionContext(sessionId) {
499
+ const context = await super.loadSessionContext(sessionId);
500
+ if (!context) return null;
501
+ if (typeof context.tenantId === "string" && context.tenantId.length > 0) return isSessionTenantAuthorized(context) ? context : null;
502
+ return this.tenantRequired ? null : context;
503
+ }
504
+ };
505
+ function clearSessionLocals(locals) {
506
+ locals.user = null;
507
+ locals.membership = null;
508
+ locals.permissions = [];
509
+ locals.tenantId = null;
510
+ locals.sessionId = null;
511
+ locals.authMethod = null;
512
+ locals.sessionParent = null;
513
+ locals.tenantContext = void 0;
514
+ verifiedSessionTenants.delete(locals);
515
+ }
516
+ var authorizedTenantLocalsHandle = async ({ event, resolve }) => {
517
+ const locals = runtimeLocals(event.locals);
518
+ const activeContext = getCurrentTenant();
519
+ if (locals.user && locals.tenantId && verifiedSessionTenants.get(locals) === locals.tenantId && activeContext?.tenantId === locals.tenantId) locals.tenantContext = activeContext;
520
+ return resolve(event);
521
+ };
522
+ function composeHandles(...handles) {
523
+ return ({ event, resolve }) => {
524
+ const run = (index, current, resolveOptions) => {
525
+ const next = handles[index];
526
+ if (!next) return resolve(current, resolveOptions);
527
+ return next({
528
+ event: current,
529
+ resolve: (nextEvent, nextOptions) => run(index + 1, nextEvent, nextOptions ?? resolveOptions)
530
+ });
531
+ };
532
+ return run(0, event);
533
+ };
534
+ }
535
+ function runtimeLocals(locals) {
536
+ return locals;
537
+ }
538
+ async function loadConfiguredRuntime() {
539
+ return resolveEffectiveApplicationRuntime(await loadConfig());
540
+ }
541
+ function snapshotBoundPrincipal(principal) {
542
+ if (!principal || typeof principal !== "object" || Array.isArray(principal)) throw new Error("A bound principal is required.");
543
+ let snapshot;
544
+ try {
545
+ snapshot = deepFrozenPlainCopy(principal);
546
+ } catch (error) {
547
+ if (error instanceof PlainDataError) throw new Error(`A bound principal ${error.message}.`);
548
+ throw error;
549
+ }
550
+ for (const key of [
551
+ "id",
552
+ "tenantId",
553
+ "kind",
554
+ "tenantBinding"
555
+ ]) {
556
+ const value = ownValue(snapshot, key);
557
+ if (value !== void 0 && typeof value !== "string") throw new Error(`A bound principal has a malformed ${key}.`);
558
+ }
559
+ for (const key of ["scopes", "roles"]) {
560
+ const value = ownValue(snapshot, key);
561
+ if (value !== void 0 && (!Array.isArray(value) || !value.every((entry) => typeof entry === "string"))) throw new Error(`A bound principal has malformed ${key}.`);
562
+ }
563
+ const allowCrossTenant = ownValue(snapshot, "allowCrossTenant");
564
+ if (allowCrossTenant !== void 0 && typeof allowCrossTenant !== "boolean") throw new Error("A bound principal has a malformed allowCrossTenant.");
565
+ return snapshot;
566
+ }
567
+ //#endregion
568
+ export { authorizedTenantLocalsHandle, composeHandles, composeSmrtSvelteKitRuntime, createSmrtSvelteKitRuntime, defaultWriterLease };
569
+
570
+ //# sourceMappingURL=sveltekit-runtime.js.map