@happyvertical/smrt-app-runtime 0.57.7 → 0.57.9

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/dist/sveltekit.js CHANGED
@@ -1,11 +1,8 @@
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, m as removeOnboardingHandoff, p as prepareApplicationStateRoot, s as resolveLocalRuntimePaths, t as LocalRuntimeError, u as acquireWriterLease, z as PlainDataError } from "./chunks/src-DeNO6bG_.js";
2
- import { loadConfig, resolveEffectiveApplicationRuntime } from "@happyvertical/smrt-config";
3
- import { OidcIdentityCollection } from "@happyvertical/smrt-profiles";
4
- import { enableTenancy, getCurrentTenant, isTenancyEnabled, withSystemContext } from "@happyvertical/smrt-tenancy";
5
- import { MembershipCollection, PermissionResolver, RoleCollection, SessionService, TenantCollection, TenantStatus, UserCollection, UserStatus, getCurrentSessionPermissionContext, getRequestScopedDatabase, withPrincipalPermissionContext, withSessionPermissionContext } from "@happyvertical/smrt-users";
6
- import { getDatabase } from "@happyvertical/sql";
1
+ import { n as normalizeTenantSelection, r as selectTenantSlug, t as createSubdomainTenantSelector } from "./chunks/tenancy-BzdIxH2M.js";
2
+ import { RoleCollection, getRequestScopedDatabase } from "@happyvertical/smrt-users";
3
+ import { authorizedTenantLocalsHandle, composeHandles, createSmrtSvelteKitRuntime, defaultWriterLease } from "@happyvertical/smrt-app-runtime/sveltekit-runtime";
7
4
  import { fail, json, redirect } from "@sveltejs/kit";
8
- import { ObjectRegistry } from "@happyvertical/smrt-core";
5
+ import { LocalRuntimeError, removeOnboardingHandoff } from "@happyvertical/smrt-app-runtime";
9
6
  import { destroySessionCookie } from "@happyvertical/smrt-users/sveltekit";
10
7
  //#region src/sveltekit/handlers.ts
11
8
  var RUNTIME_DIAGNOSTICS_READ_PERMISSION = "runtime_diagnostics.read";
@@ -99,6 +96,7 @@ var OWNER_SETUP_FIELDS = Object.freeze({
99
96
  token: "token",
100
97
  name: "name",
101
98
  email: "email",
99
+ password: "password",
102
100
  tenantName: "tenantName"
103
101
  });
104
102
  var DEFAULT_OWNER_SETUP_MESSAGES = Object.freeze({
@@ -165,8 +163,9 @@ function createOwnerSetupPage(runtime, options = {}) {
165
163
  const token = field(OWNER_SETUP_FIELDS.token);
166
164
  const name = field(OWNER_SETUP_FIELDS.name);
167
165
  const email = field(OWNER_SETUP_FIELDS.email);
166
+ const password = field(OWNER_SETUP_FIELDS.password);
168
167
  const tenantName = field(OWNER_SETUP_FIELDS.tenantName).trim();
169
- if (!token || !name.trim() || !email.includes("@")) return failure(400, "setup_invalid_input");
168
+ if (!token || !name.trim() || !email.includes("@") || options.requirePassword && !password) return failure(400, "setup_invalid_input");
170
169
  const local = await runtime.localRuntime();
171
170
  let result;
172
171
  try {
@@ -174,6 +173,7 @@ function createOwnerSetupPage(runtime, options = {}) {
174
173
  token,
175
174
  name,
176
175
  email,
176
+ password,
177
177
  ...tenantName ? { tenantName } : {},
178
178
  userAgent: event.request.headers.get("user-agent") || void 0,
179
179
  ipAddress: event.getClientAddress()
@@ -226,623 +226,6 @@ function isLoopbackHostname(hostname) {
226
226
  return host === "localhost" || isLoopbackAddress(host);
227
227
  }
228
228
  //#endregion
229
- //#region src/sveltekit/tenancy.ts
230
- var ROOT_LIKE_HOSTS = /* @__PURE__ */ new Set([
231
- "localhost",
232
- "127.0.0.1",
233
- "::1",
234
- "[::1]"
235
- ]);
236
- var RESERVED_SUBDOMAINS = /* @__PURE__ */ new Set([
237
- "www",
238
- "api",
239
- "app",
240
- "admin"
241
- ]);
242
- var NO_SELECTION = Object.freeze({
243
- tenantId: null,
244
- tenantSlug: null
245
- });
246
- function selectTenantSlug(url, baseDomain = process.env.TENANT_BASE_DOMAIN) {
247
- const hostname = url.hostname.toLowerCase();
248
- if (ROOT_LIKE_HOSTS.has(hostname) || hostname.startsWith("[") || /^\d{1,3}(\.\d{1,3}){3}$/.test(hostname)) return null;
249
- const normalizedBase = baseDomain?.trim().toLowerCase().replace(/^\.+|\.+$/g, "");
250
- let candidate;
251
- if (normalizedBase) {
252
- if (hostname === normalizedBase) return null;
253
- const suffix = `.${normalizedBase}`;
254
- if (!hostname.endsWith(suffix)) return null;
255
- candidate = hostname.slice(0, -suffix.length).split(".")[0];
256
- } else {
257
- const labels = hostname.split(".");
258
- if (labels.length < 3) return null;
259
- candidate = labels[0];
260
- }
261
- return candidate && !RESERVED_SUBDOMAINS.has(candidate) ? candidate : null;
262
- }
263
- function isMissingTenantTable(error) {
264
- if (!(error instanceof Error)) return false;
265
- return error.code === "42P01" || error.message.includes("relation \"tenants\" does not exist") || error.message.includes("no such table: tenants");
266
- }
267
- function createSubdomainTenantSelector(options) {
268
- return async (event) => {
269
- const tenantSlug = selectTenantSlug(event.url, options.baseDomain);
270
- if (!tenantSlug) return NO_SELECTION;
271
- let tenantId;
272
- try {
273
- const tenant = await (await TenantCollection.create(options.classOptions())).findBySlug(tenantSlug);
274
- tenantId = tenant?.status === TenantStatus.ACTIVE ? tenant.id ?? null : null;
275
- } catch (error) {
276
- if (!isMissingTenantTable(error)) throw error;
277
- tenantId = null;
278
- }
279
- return {
280
- tenantId,
281
- tenantSlug
282
- };
283
- };
284
- }
285
- function normalizeTenantSelection(selection) {
286
- return {
287
- tenantId: typeof selection?.tenantId === "string" && selection.tenantId ? selection.tenantId : null,
288
- tenantSlug: typeof selection?.tenantSlug === "string" && selection.tenantSlug ? selection.tenantSlug : null
289
- };
290
- }
291
- //#endregion
292
- //#region src/sveltekit/runtime.ts
293
- var DEFAULT_SESSION_TTL_SECONDS = 10080 * 60;
294
- function createSmrtSvelteKitRuntime(options = {}) {
295
- return composeSmrtSvelteKitRuntime(options, {});
296
- }
297
- function composeSmrtSvelteKitRuntime(options, seams) {
298
- const env = options.env ?? process.env;
299
- const sourceRoot = options.sourceRoot ?? process.cwd();
300
- const dataDirectory = options.dataDirectory ?? env.SMRT_DATA_DIR;
301
- const initializeLocal = seams.initializeLocal ?? initializeLocalApplicationRuntime;
302
- const initializeDeployed = seams.initializeDeployed ?? initializeDeployedApplicationRuntime;
303
- if (options.enableTenancy !== false && !isTenancyEnabled()) enableTenancy();
304
- let appId;
305
- const applicationId = () => {
306
- appId ??= options.appId ? validateApplicationId(options.appId) : resolveApplicationId({
307
- sourceRoot,
308
- explicitId: env.SMRT_APP_ID
309
- });
310
- return appId;
311
- };
312
- let resolved;
313
- let resolvedPromise;
314
- const resolvedRuntime = () => {
315
- resolvedPromise ??= (async () => {
316
- const value = typeof options.runtime === "function" ? await options.runtime() : options.runtime ?? await (seams.loadRuntime ?? loadConfiguredRuntime)();
317
- resolved = value;
318
- return value;
319
- })().catch((error) => {
320
- resolvedPromise = void 0;
321
- throw error;
322
- });
323
- return resolvedPromise;
324
- };
325
- const requireResolved = () => {
326
- if (!resolved) throw new Error("The SMRT application runtime is not resolved yet; await init() first.");
327
- return resolved;
328
- };
329
- const baseDatabaseConfig = () => {
330
- const runtime = requireResolved();
331
- if (runtime.profile === "local") {
332
- const paths = resolveLocalRuntimePaths({
333
- appId: applicationId(),
334
- dataDirectory,
335
- sourceRoot,
336
- env
337
- });
338
- return {
339
- type: "sqlite",
340
- url: paths.database,
341
- secureFile: {
342
- driver: "node:sqlite",
343
- custody: "trusted-parent",
344
- root: paths.root
345
- }
346
- };
347
- }
348
- const databaseUrl = env.DATABASE_URL;
349
- if (!databaseUrl) throw new Error(`${runtime.profile} requires DATABASE_URL.`);
350
- return {
351
- type: "postgres",
352
- url: databaseUrl
353
- };
354
- };
355
- const baseClassOptions = (className) => {
356
- const defaults = { db: baseDatabaseConfig() };
357
- const override = options.classOverrides?.[className];
358
- return override ? {
359
- ...defaults,
360
- ...override
361
- } : defaults;
362
- };
363
- const rlsRequestDatabase = () => {
364
- if (getCurrentSessionPermissionContext()?.postgresRls !== true) return void 0;
365
- return getRequestScopedDatabase() ?? void 0;
366
- };
367
- const databaseConfig = () => rlsRequestDatabase() ?? baseDatabaseConfig();
368
- const classOptions = (className) => {
369
- const base = baseClassOptions(className);
370
- if (options.classOverrides?.[className]?.db !== void 0) return base;
371
- const requestDb = rlsRequestDatabase();
372
- return requestDb ? {
373
- ...base,
374
- db: requestDb
375
- } : base;
376
- };
377
- const getCollection = (className) => ObjectRegistry.getCollection(className, classOptions(className));
378
- const writerLease = options.acquireWriterLease === false ? void 0 : options.acquireWriterLease ?? ((context) => defaultWriterLease(context, env));
379
- let localPromise;
380
- let localLease;
381
- const localRuntime = async () => {
382
- const runtime = await resolvedRuntime();
383
- if (runtime.profile !== "local") throw new Error("Owner bootstrap is available only in the local profile.");
384
- if (localPromise) return localPromise;
385
- const bindHost = options.bindHost || env.HOST || (env.NODE_ENV === "development" ? "127.0.0.1" : null);
386
- if (!bindHost) throw new Error("Local production startup requires an explicit loopback HOST; use pnpm app:start.");
387
- const id = applicationId();
388
- localLease ??= writerLease?.({
389
- appId: id,
390
- dataDirectory,
391
- sourceRoot
392
- });
393
- localPromise = initializeLocal({
394
- appId: id,
395
- dataDirectory,
396
- sourceRoot,
397
- env,
398
- bindHost,
399
- providers: {
400
- database: runtime.providers.database,
401
- authentication: runtime.providers.authentication,
402
- tenancy: runtime.providers.tenancy,
403
- assets: runtime.providers.assets,
404
- secrets: runtime.providers.secrets,
405
- jobs: runtime.providers.jobs,
406
- network: runtime.providers.network
407
- },
408
- backgroundJobs: options.backgroundJobs ?? env.SMRT_BACKGROUND_JOBS === "true",
409
- paidCapabilities: options.paidCapabilities,
410
- bootstrapTtlSeconds: options.bootstrapTtlSeconds,
411
- sessionTtlSeconds: options.sessionTtlSeconds,
412
- ownerTenant: options.ownerTenant,
413
- prepareDatabase: options.prepareDatabase,
414
- now: options.now
415
- }).then(({ runtime: initialized, bootstrap }) => {
416
- if (bootstrap) try {
417
- options.onBootstrapInvitation?.(bootstrap, { bindHost });
418
- } catch {}
419
- return initialized;
420
- }).catch((error) => {
421
- localLease?.release();
422
- localLease = void 0;
423
- localPromise = void 0;
424
- throw error;
425
- });
426
- return localPromise;
427
- };
428
- let deployedPromise;
429
- const deployedRuntime = async () => {
430
- const runtime = await resolvedRuntime();
431
- if (runtime.profile === "local") throw new Error("deployed_runtime_unavailable");
432
- const profile = runtime.profile;
433
- const databaseUrl = env.DATABASE_URL;
434
- if (!databaseUrl) throw new Error(`${profile} requires DATABASE_URL.`);
435
- const authenticationProvider = runtime.providers.authentication.provider;
436
- if (authenticationProvider === "owner-bootstrap") throw new Error("Deployed profiles require public authentication.");
437
- const readiness = options.providerReadiness;
438
- if (!readiness) throw new Error(`${profile} requires providerReadiness probes for authentication, assets, and secrets.`);
439
- deployedPromise ??= initializeDeployed({
440
- profile,
441
- providers: {
442
- database: runtime.providers.database,
443
- authentication: runtime.providers.authentication,
444
- tenancy: runtime.providers.tenancy,
445
- assets: runtime.providers.assets,
446
- secrets: runtime.providers.secrets,
447
- jobs: runtime.providers.jobs,
448
- network: runtime.providers.network
449
- },
450
- database: {
451
- engine: "postgres",
452
- connect: () => getDatabase({
453
- type: "postgres",
454
- url: databaseUrl
455
- }),
456
- close: async (db) => {
457
- await db.close?.();
458
- }
459
- },
460
- authentication: {
461
- provider: authenticationProvider,
462
- readiness: readiness("authentication", {
463
- profile,
464
- provider: authenticationProvider
465
- })
466
- },
467
- assets: {
468
- provider: runtime.providers.assets.provider,
469
- readiness: readiness("assets", {
470
- profile,
471
- provider: runtime.providers.assets.provider
472
- })
473
- },
474
- secrets: {
475
- provider: runtime.providers.secrets.provider,
476
- readiness: readiness("secrets", {
477
- profile,
478
- provider: runtime.providers.secrets.provider
479
- })
480
- },
481
- prepareDatabase: options.prepareDatabase
482
- });
483
- return deployedPromise;
484
- };
485
- const ready = async () => {
486
- if ((await resolvedRuntime()).profile === "local") {
487
- await localRuntime();
488
- return;
489
- }
490
- await deployedRuntime();
491
- };
492
- const configurationFingerprint = () => runtimeConfigurationFingerprint(requireResolved(), env);
493
- const health = async () => {
494
- await ready();
495
- const runtime = requireResolved();
496
- const publicHealth = {
497
- schemaVersion: 1,
498
- status: "ready",
499
- profile: runtime.profile
500
- };
501
- return runtime.profile === "local" ? {
502
- ...publicHealth,
503
- application: applicationId(),
504
- instance: env.SMRT_PROCESS_INSTANCE || null,
505
- configuration: configurationFingerprint()
506
- } : publicHealth;
507
- };
508
- const readDiagnostics = async (diagnosticsOptions) => {
509
- await ready();
510
- const runtime = requireResolved();
511
- const schema = {
512
- status: diagnosticsOptions.schemaStatus ?? "unknown",
513
- migrations: diagnosticsOptions.migrationStatus ?? "unknown"
514
- };
515
- if (runtime.profile === "local") {
516
- const diagnostics = await (await localRuntime()).diagnostics();
517
- return projectRuntimeDiagnostics({
518
- profile: "local",
519
- health: "healthy",
520
- schema,
521
- capabilities: {
522
- "asset-storage": "available",
523
- authentication: "available",
524
- "background-jobs": diagnostics.jobs.backgroundEnabled ? "available" : "disabled",
525
- database: "available",
526
- "paid-capabilities": diagnostics.paidCapabilitiesEnabled ? "available" : "disabled",
527
- "secret-storage": "available"
528
- },
529
- toolNames: diagnosticsOptions.toolNames,
530
- worker: {
531
- topology: diagnostics.jobs.topology,
532
- required: diagnostics.jobs.backgroundEnabled,
533
- heartbeatAt: diagnosticsOptions.workerHeartbeatAt
534
- },
535
- recentErrors: diagnosticsOptions.recentErrors,
536
- observedAt: diagnosticsOptions.observedAt
537
- });
538
- }
539
- const deployed = await deployedPromise;
540
- if (!deployed) throw new Error("deployed_runtime_unavailable");
541
- const readiness = await deployed.readiness();
542
- const componentStatus = (component) => readiness.components[component].status === "ready" ? "available" : "unavailable";
543
- return projectRuntimeDiagnostics({
544
- profile: runtime.profile,
545
- health: deployed.health().status === "healthy" ? readiness.status === "ready" ? "healthy" : "degraded" : "stopped",
546
- schema,
547
- capabilities: {
548
- "asset-storage": componentStatus("assets"),
549
- authentication: componentStatus("authentication"),
550
- "background-jobs": "available",
551
- database: componentStatus("database"),
552
- "paid-capabilities": "unknown",
553
- "secret-storage": componentStatus("secrets")
554
- },
555
- toolNames: diagnosticsOptions.toolNames,
556
- worker: {
557
- topology: deployed.resolvedRuntime.providers.jobs.topology,
558
- required: true,
559
- heartbeatAt: diagnosticsOptions.workerHeartbeatAt
560
- },
561
- recentErrors: diagnosticsOptions.recentErrors,
562
- observedAt: diagnosticsOptions.observedAt
563
- });
564
- };
565
- const selectTenant = options.selectTenant ?? createSubdomainTenantSelector({
566
- baseDomain: options.tenantBaseDomain ?? env.TENANT_BASE_DOMAIN,
567
- classOptions: () => baseClassOptions("Tenant")
568
- });
569
- const readinessHandle = async ({ event, resolve }) => {
570
- await ready();
571
- return resolve(event);
572
- };
573
- const tenantSelectionHandle = async ({ event, resolve }) => {
574
- const locals = runtimeLocals(event.locals);
575
- const selection = normalizeTenantSelection(await selectTenant({
576
- url: event.url,
577
- request: event.request
578
- }));
579
- locals.selectedTenantId = selection.tenantId;
580
- locals.selectedTenantSlug = selection.tenantSlug;
581
- return resolve(event);
582
- };
583
- const sessionCookieName = options.session?.cookieName ?? "sid";
584
- const sessionSkipPaths = options.session?.skipPaths ?? [];
585
- const sessionServiceOptions = () => ({
586
- ...baseClassOptions("Session"),
587
- ...options.session,
588
- defaultTTL: options.session?.ttl ?? DEFAULT_SESSION_TTL_SECONDS,
589
- autoExtend: options.session?.autoExtend ?? false
590
- });
591
- const postgresRls = () => requireResolved().providers.tenancy.isolation === "database-rls" ? true : options.session?.postgresRls;
592
- let permissionResolverPromise;
593
- const permissionResolver = () => {
594
- permissionResolverPromise ??= PermissionResolver.create(baseClassOptions("Permission")).catch((error) => {
595
- permissionResolverPromise = void 0;
596
- throw error;
597
- });
598
- return permissionResolverPromise;
599
- };
600
- const runAsPrincipal = async (principal, fn) => {
601
- if (!principal || typeof principal !== "object") throw new Error("A bound principal is required.");
602
- const snapshot = snapshotBoundPrincipal(principal);
603
- const tokenDerived = isLocalMcpTokenPrincipal(snapshot);
604
- const userId = ownValue(snapshot, "id");
605
- const tenantId = ownValue(snapshot, "tenantId");
606
- const snapshotScopes = ownValue(snapshot, "scopes");
607
- const requestedTenantBinding = ownValue(snapshot, "tenantBinding");
608
- const requestedScopes = snapshotScopes === void 0 ? void 0 : Object.freeze([...snapshotScopes]);
609
- if (requestedScopes !== void 0 && !requestedScopes.every((scope) => typeof scope === "string")) throw new Error("A bound principal has malformed scopes.");
610
- if (typeof userId !== "string" || userId.length === 0) throw new Error("A bound principal requires a user id.");
611
- if (typeof tenantId !== "string" || tenantId.length === 0) throw new Error("A bound principal requires a tenant.");
612
- if (tokenDerived && requestedTenantBinding !== void 0 && requestedTenantBinding !== "direct") throw new Error("A local MCP token principal binds only through its direct membership.");
613
- const binding = tokenDerived ? "direct" : requestedTenantBinding ?? "direct-or-inherited";
614
- if (binding !== "direct" && binding !== "direct-or-inherited") throw new Error("Unknown tenant binding mode for a bound principal.");
615
- const resolved2 = await resolveBoundMembershipPermissions({
616
- memberships: await MembershipCollection.create(baseClassOptions("Membership")),
617
- resolver: await permissionResolver(),
618
- userId,
619
- tenantId,
620
- binding
621
- });
622
- 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.");
623
- const cap = requestedScopes ? new Set(requestedScopes) : void 0;
624
- const permissions = [...resolved2.permissions].filter((permission) => !cap || cap.has(permission));
625
- return withPrincipalPermissionContext({
626
- ...baseClassOptions("Session"),
627
- userId,
628
- tenantId,
629
- permissions,
630
- enterTenantContext: true,
631
- postgresRls: postgresRls()
632
- }, () => fn(Object.freeze(Object.assign(/* @__PURE__ */ Object.create(null), snapshot, {
633
- id: userId,
634
- tenantId,
635
- tenantBinding: binding,
636
- scopes: Object.freeze([...permissions])
637
- }))));
638
- };
639
- const verifyLocalMcpToken = async (token) => {
640
- if ((await resolvedRuntime()).profile !== "local") return null;
641
- return await (await localRuntime()).mcpTokens?.verify(token) ?? null;
642
- };
643
- const resolveMcpPrincipal = async (identity) => {
644
- if ((await resolvedRuntime()).profile === "local") return null;
645
- if (!identity || typeof identity !== "object") return null;
646
- const issuer = ownValue(identity, "issuer");
647
- const subject = ownValue(identity, "subject");
648
- if (typeof issuer !== "string" || issuer.length === 0 || typeof subject !== "string" || subject.length === 0) return null;
649
- return withSystemContext(async () => {
650
- const identities = await OidcIdentityCollection.create(baseClassOptions("OidcIdentity"));
651
- let linked;
652
- try {
653
- linked = await identities.findBySubject(issuer, subject);
654
- } catch {
655
- return null;
656
- }
657
- if (!linked?.profileId) return null;
658
- const owners = await (await UserCollection.create(baseClassOptions("User"))).list({
659
- where: { profileId: linked.profileId },
660
- limit: 2
661
- });
662
- const user = owners.length === 1 ? owners[0] : void 0;
663
- if (typeof user?.id !== "string" || user.id.length === 0 || user.status !== UserStatus.ACTIVE) return null;
664
- const memberships = await MembershipCollection.create(baseClassOptions("Membership"));
665
- const tenants = new Set((await memberships.findActiveByUser(user.id)).map((membership) => membership.tenantId).filter((tenantId2) => typeof tenantId2 === "string" && tenantId2.length > 0));
666
- if (tenants.size !== 1) return null;
667
- const [tenantId] = tenants;
668
- return Object.freeze({
669
- id: user.id,
670
- tenantId,
671
- kind: "human",
672
- tenantBinding: "direct"
673
- });
674
- });
675
- };
676
- let sessionServicePromise;
677
- const sessionService = () => {
678
- sessionServicePromise ??= (async () => {
679
- const service = new TenantAuthorizingSessionService(sessionServiceOptions(), requireResolved().providers.tenancy.context === "required");
680
- await service.initialize();
681
- return service;
682
- })().catch((error) => {
683
- sessionServicePromise = void 0;
684
- throw error;
685
- });
686
- return sessionServicePromise;
687
- };
688
- const sessionStep = async ({ event, resolve }) => {
689
- const locals = runtimeLocals(event.locals);
690
- clearSessionLocals(locals);
691
- const rls = postgresRls();
692
- const skipped = sessionSkipPaths.some((path) => event.url.pathname.startsWith(path));
693
- if (skipped && !rls) return resolve(event);
694
- const sessionId = skipped ? void 0 : event.cookies.get(sessionCookieName);
695
- if (!sessionId && !rls) return resolve(event);
696
- let resolveEntered = false;
697
- let downstream;
698
- try {
699
- const service = await sessionService();
700
- return await withSessionPermissionContext({
701
- ...sessionServiceOptions(),
702
- enterTenantContext: true,
703
- postgresRls: rls,
704
- sessionId: sessionId ?? null,
705
- sessionService: service
706
- }, async (context) => {
707
- if (context.session) {
708
- locals.user = context.user;
709
- locals.membership = context.membership ?? null;
710
- locals.permissions = context.permissions;
711
- locals.tenantId = context.tenantId;
712
- locals.sessionId = context.sessionId;
713
- if (context.tenantId) verifiedSessionTenants.set(locals, context.tenantId);
714
- }
715
- resolveEntered = true;
716
- try {
717
- return await resolve(event);
718
- } catch (error) {
719
- downstream = { error };
720
- throw error;
721
- }
722
- });
723
- } catch (error) {
724
- if (downstream) throw downstream.error;
725
- if (resolveEntered) throw error;
726
- clearSessionLocals(locals);
727
- return new Response("Internal Server Error", { status: 500 });
728
- }
729
- };
730
- const sessionCookie = Object.freeze({
731
- name: options.session?.cookieName ?? "sid",
732
- path: options.session?.cookiePath ?? "/",
733
- ...options.session?.cookieDomain ? { domain: options.session.cookieDomain } : {},
734
- sameSite: options.session?.cookieSameSite ?? "lax",
735
- ...options.session?.cookieSecure !== void 0 ? { secure: options.session.cookieSecure } : {},
736
- maxAgeSeconds: options.sessionTtlSeconds ?? DEFAULT_SESSION_TTL_SECONDS
737
- });
738
- const init = () => ready();
739
- return Object.freeze({
740
- handle: composeHandles(readinessHandle, tenantSelectionHandle, sessionStep, authorizedTenantLocalsHandle),
741
- init,
742
- sessionCookie,
743
- resolvedRuntime,
744
- ready,
745
- applicationId,
746
- applicationStateRoot: () => resolveApplicationStateRoot({
747
- appId: applicationId(),
748
- dataDirectory,
749
- sourceRoot
750
- }),
751
- configurationFingerprint,
752
- databaseConfig,
753
- classOptions,
754
- getCollection,
755
- runAsPrincipal,
756
- verifyLocalMcpToken,
757
- resolveMcpPrincipal,
758
- localRuntime,
759
- deployedRuntime,
760
- health,
761
- readDiagnostics
762
- });
763
- }
764
- function defaultWriterLease(context, env = process.env) {
765
- return acquireWriterLease(prepareApplicationStateRoot({
766
- appId: context.appId,
767
- dataDirectory: context.dataDirectory,
768
- sourceRoot: context.sourceRoot
769
- }), { operationInstance: env.SMRT_OPERATION_INSTANCE });
770
- }
771
- var verifiedSessionTenants = /* @__PURE__ */ new WeakMap();
772
- var TenantAuthorizingSessionService = class extends SessionService {
773
- tenantRequired;
774
- constructor(options, tenantRequired) {
775
- super(options);
776
- this.tenantRequired = tenantRequired;
777
- }
778
- async loadSessionContext(sessionId) {
779
- const context = await super.loadSessionContext(sessionId);
780
- if (!context) return null;
781
- if (typeof context.tenantId === "string" && context.tenantId.length > 0) return isSessionTenantAuthorized(context) ? context : null;
782
- return this.tenantRequired ? null : context;
783
- }
784
- };
785
- function clearSessionLocals(locals) {
786
- locals.user = null;
787
- locals.membership = null;
788
- locals.permissions = [];
789
- locals.tenantId = null;
790
- locals.sessionId = null;
791
- locals.tenantContext = void 0;
792
- verifiedSessionTenants.delete(locals);
793
- }
794
- var authorizedTenantLocalsHandle = async ({ event, resolve }) => {
795
- const locals = runtimeLocals(event.locals);
796
- const activeContext = getCurrentTenant();
797
- if (locals.user && locals.tenantId && verifiedSessionTenants.get(locals) === locals.tenantId && activeContext?.tenantId === locals.tenantId) locals.tenantContext = activeContext;
798
- return resolve(event);
799
- };
800
- function composeHandles(...handles) {
801
- return ({ event, resolve }) => {
802
- const run = (index, current, resolveOptions) => {
803
- const next = handles[index];
804
- if (!next) return resolve(current, resolveOptions);
805
- return next({
806
- event: current,
807
- resolve: (nextEvent, nextOptions) => run(index + 1, nextEvent, nextOptions ?? resolveOptions)
808
- });
809
- };
810
- return run(0, event);
811
- };
812
- }
813
- function runtimeLocals(locals) {
814
- return locals;
815
- }
816
- async function loadConfiguredRuntime() {
817
- return resolveEffectiveApplicationRuntime(await loadConfig());
818
- }
819
- function snapshotBoundPrincipal(principal) {
820
- if (!principal || typeof principal !== "object" || Array.isArray(principal)) throw new Error("A bound principal is required.");
821
- let snapshot;
822
- try {
823
- snapshot = deepFrozenPlainCopy(principal);
824
- } catch (error) {
825
- if (error instanceof PlainDataError) throw new Error(`A bound principal ${error.message}.`);
826
- throw error;
827
- }
828
- for (const key of [
829
- "id",
830
- "tenantId",
831
- "kind",
832
- "tenantBinding"
833
- ]) {
834
- const value = ownValue(snapshot, key);
835
- if (value !== void 0 && typeof value !== "string") throw new Error(`A bound principal has a malformed ${key}.`);
836
- }
837
- for (const key of ["scopes", "roles"]) {
838
- const value = ownValue(snapshot, key);
839
- if (value !== void 0 && (!Array.isArray(value) || !value.every((entry) => typeof entry === "string"))) throw new Error(`A bound principal has malformed ${key}.`);
840
- }
841
- const allowCrossTenant = ownValue(snapshot, "allowCrossTenant");
842
- if (allowCrossTenant !== void 0 && typeof allowCrossTenant !== "boolean") throw new Error("A bound principal has a malformed allowCrossTenant.");
843
- return snapshot;
844
- }
845
- //#endregion
846
229
  //#region src/sveltekit/sign-out.ts
847
230
  function isSameOriginRequest(request, url) {
848
231
  const site = request.headers.get("sec-fetch-site");