@happyvertical/smrt-app-runtime 0.60.9 → 0.60.11

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/index.d.ts CHANGED
@@ -14,7 +14,7 @@ import { type DatabaseInterface } from '@happyvertical/sql';
14
14
  import { type LocalMcpTokenStore } from './local-mcp-tokens.js';
15
15
  export * from './application-identity.js';
16
16
  export * from './deployed-runtime.js';
17
- export { DEFAULT_LOCAL_MCP_TOKEN_TTL_SECONDS, type IssuedLocalMcpToken, type IssueLocalMcpTokenInput, isLocalMcpTokenPrincipal, LOCAL_MCP_TOKEN_PREFIX, LOCAL_MCP_TOKEN_PRINCIPAL, LOCAL_MCP_TOKEN_TABLE, type LocalMcpTokenPrincipal, type LocalMcpTokenRecord, type LocalMcpTokenStatus, type LocalMcpTokenStore, MAX_LOCAL_MCP_TOKEN_TTL_SECONDS, } from './local-mcp-tokens.js';
17
+ export { DEFAULT_LOCAL_MCP_TOKEN_TTL_SECONDS, type IssuedLocalMcpToken, type IssueLocalMcpTokenInput, isLocalMcpTokenPrincipal, LOCAL_MCP_TOKEN_PREFIX, LOCAL_MCP_TOKEN_PRINCIPAL, LOCAL_MCP_TOKEN_TABLE, type LocalMcpDesktopCredentialInput, type LocalMcpDesktopOwnerSession, type LocalMcpTokenPrincipal, type LocalMcpTokenRecord, type LocalMcpTokenStatus, type LocalMcpTokenStore, MAX_LOCAL_MCP_TOKEN_TTL_SECONDS, } from './local-mcp-tokens.js';
18
18
  export * from './operation-lock.js';
19
19
  export * from './provider-readiness.js';
20
20
  export * from './runtime-diagnostics.js';
@@ -186,7 +186,7 @@ export interface LocalRuntimeDiagnostics {
186
186
  readonly paidCapabilitiesEnabled: boolean;
187
187
  readonly secretValuesIncluded: false;
188
188
  }
189
- export type LocalRuntimeErrorCode = 'bootstrap_claimed' | 'bootstrap_expired' | 'bootstrap_invalid' | 'bootstrap_unavailable' | 'capability_disabled' | 'invalid_configuration' | 'invalid_scope' | 'migration_failed' | 'owner_tenant_conflict' | 'owner_unavailable' | 'unsafe_public_exposure';
189
+ export type LocalRuntimeErrorCode = 'bootstrap_claimed' | 'bootstrap_expired' | 'bootstrap_invalid' | 'bootstrap_unavailable' | 'capability_disabled' | 'invalid_configuration' | 'invalid_scope' | 'migration_failed' | 'owner_tenant_conflict' | 'owner_identity_conflict' | 'owner_unavailable' | 'unsafe_public_exposure';
190
190
  /**
191
191
  * Fixed, secret-free surface for a failed application migration.
192
192
  *
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -1,2 +1,2 @@
1
- import { A as reclaimStaleRecord, C as findInstalledPackage, D as processExists, E as lockOwnerPid, F as LOCAL_MCP_TOKEN_PRINCIPAL, G as initializeDeployedApplicationRuntime, I as LOCAL_MCP_TOKEN_TABLE, K as isSessionTenantAuthorized, L as MAX_LOCAL_MCP_TOKEN_TTL_SECONDS, M as runtimeConfigurationFingerprint, N as DEFAULT_LOCAL_MCP_TOKEN_TTL_SECONDS, O as withOperationLock, P as LOCAL_MCP_TOKEN_PREFIX, R as isLocalMcpTokenPrincipal, S as createProviderReadinessProbe, T as isStaleOperationLock, U as DeployedRuntimeCleanupError, W as DeployedRuntimeError, _ as MAX_RUNTIME_DIAGNOSTIC_TOOLS, a as openLocalMcpTokenStore, b as projectRuntimeDiagnostics, c as validateApplicationId, d as readActiveWriterLease, f as ONBOARDING_HANDOFF_FILES, g as MAX_RUNTIME_DIAGNOSTIC_ERRORS, h as resolveApplicationStateRoot, i as initializeLocalApplicationRuntime, j as resolveApplicationId, k as RECLAIM_MUTEX_FILE, l as validateLocalDatabaseStorage, m as removeOnboardingHandoff, n as MIGRATION_FAILED_MESSAGE, o as prepareLocalDatabaseStorage, p as prepareApplicationStateRoot, r as encodeApplicationId, s as resolveLocalRuntimePaths, t as LocalRuntimeError, u as acquireWriterLease, v as RUNTIME_DIAGNOSTICS_SCHEMA_VERSION, w as resolveReadinessModule, x as PROVIDER_READINESS_SETTINGS, y as RUNTIME_WORKER_FRESHNESS_SECONDS } from "./chunks/src-DP7SxcSY.js";
1
+ import { A as reclaimStaleRecord, C as findInstalledPackage, D as processExists, E as lockOwnerPid, F as LOCAL_MCP_TOKEN_PRINCIPAL, G as initializeDeployedApplicationRuntime, I as LOCAL_MCP_TOKEN_TABLE, K as isSessionTenantAuthorized, L as MAX_LOCAL_MCP_TOKEN_TTL_SECONDS, M as runtimeConfigurationFingerprint, N as DEFAULT_LOCAL_MCP_TOKEN_TTL_SECONDS, O as withOperationLock, P as LOCAL_MCP_TOKEN_PREFIX, R as isLocalMcpTokenPrincipal, S as createProviderReadinessProbe, T as isStaleOperationLock, U as DeployedRuntimeCleanupError, W as DeployedRuntimeError, _ as MAX_RUNTIME_DIAGNOSTIC_TOOLS, a as openLocalMcpTokenStore, b as projectRuntimeDiagnostics, c as validateApplicationId, d as readActiveWriterLease, f as ONBOARDING_HANDOFF_FILES, g as MAX_RUNTIME_DIAGNOSTIC_ERRORS, h as resolveApplicationStateRoot, i as initializeLocalApplicationRuntime, j as resolveApplicationId, k as RECLAIM_MUTEX_FILE, l as validateLocalDatabaseStorage, m as removeOnboardingHandoff, n as MIGRATION_FAILED_MESSAGE, o as prepareLocalDatabaseStorage, p as prepareApplicationStateRoot, r as encodeApplicationId, s as resolveLocalRuntimePaths, t as LocalRuntimeError, u as acquireWriterLease, v as RUNTIME_DIAGNOSTICS_SCHEMA_VERSION, w as resolveReadinessModule, x as PROVIDER_READINESS_SETTINGS, y as RUNTIME_WORKER_FRESHNESS_SECONDS } from "./chunks/src-DG72tyzB.js";
2
2
  export { DEFAULT_LOCAL_MCP_TOKEN_TTL_SECONDS, DeployedRuntimeCleanupError, DeployedRuntimeError, LOCAL_MCP_TOKEN_PREFIX, LOCAL_MCP_TOKEN_PRINCIPAL, LOCAL_MCP_TOKEN_TABLE, LocalRuntimeError, MAX_LOCAL_MCP_TOKEN_TTL_SECONDS, MAX_RUNTIME_DIAGNOSTIC_ERRORS, MAX_RUNTIME_DIAGNOSTIC_TOOLS, MIGRATION_FAILED_MESSAGE, ONBOARDING_HANDOFF_FILES, PROVIDER_READINESS_SETTINGS, RECLAIM_MUTEX_FILE, RUNTIME_DIAGNOSTICS_SCHEMA_VERSION, RUNTIME_WORKER_FRESHNESS_SECONDS, acquireWriterLease, createProviderReadinessProbe, encodeApplicationId, findInstalledPackage, initializeDeployedApplicationRuntime, initializeLocalApplicationRuntime, isLocalMcpTokenPrincipal, isSessionTenantAuthorized, isStaleOperationLock, lockOwnerPid, openLocalMcpTokenStore, prepareApplicationStateRoot, prepareLocalDatabaseStorage, processExists, projectRuntimeDiagnostics, readActiveWriterLease, reclaimStaleRecord, removeOnboardingHandoff, resolveApplicationId, resolveApplicationStateRoot, resolveLocalRuntimePaths, resolveReadinessModule, runtimeConfigurationFingerprint, validateApplicationId, validateLocalDatabaseStorage, withOperationLock };
@@ -0,0 +1,10 @@
1
+ /** Derive public identifiers from the existing private installation seed. */
2
+ export declare function deriveLocalInstallationIdentity(applicationSecret: string): {
3
+ deviceId: string;
4
+ tenantId: string;
5
+ ownerId: string;
6
+ profileId: string;
7
+ membershipId: string;
8
+ };
9
+ export type LocalInstallationIdentity = ReturnType<typeof deriveLocalInstallationIdentity>;
10
+ //# sourceMappingURL=local-installation-identity.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"local-installation-identity.d.ts","sourceRoot":"","sources":["../src/local-installation-identity.ts"],"names":[],"mappings":"AAaA,6EAA6E;AAC7E,wBAAgB,+BAA+B,CAAC,iBAAiB,EAAE,MAAM;;;;;;EASxE;AAED,MAAM,MAAM,yBAAyB,GAAG,UAAU,CAChD,OAAO,+BAA+B,CACvC,CAAC"}
@@ -87,10 +87,28 @@ export interface LocalMcpTokenPrincipal {
87
87
  }
88
88
  /** True for a principal derived from a verified local MCP token. */
89
89
  export declare function isLocalMcpTokenPrincipal(value: unknown): boolean;
90
+ /** Credential management input for an authenticated desktop owner session. */
91
+ export type LocalMcpDesktopCredentialInput = {
92
+ readonly action: 'put';
93
+ readonly id: string;
94
+ readonly scopes: readonly string[];
95
+ readonly expiresInSeconds: number;
96
+ } | {
97
+ readonly action: 'revoke';
98
+ readonly id: string;
99
+ };
100
+ /** Verified server-side session snapshot, never supplied by the client. */
101
+ export interface LocalMcpDesktopOwnerSession {
102
+ readonly userId: string;
103
+ readonly tenantId: string;
104
+ readonly permissions: readonly string[];
105
+ }
90
106
  /** Owner-scoped local MCP token operations. */
91
107
  export interface LocalMcpTokenStore {
92
108
  /** Mint a token bound to the local owner's user and tenant. */
93
109
  issue(input: IssueLocalMcpTokenInput): Promise<IssuedLocalMcpToken>;
110
+ /** Manage one desktop slot as the sole active local owner. */
111
+ manageDesktopCredential?(session: LocalMcpDesktopOwnerSession, input: LocalMcpDesktopCredentialInput): Promise<IssuedLocalMcpToken | 'revoked' | 'slot_unavailable'>;
94
112
  /** Every stored token, newest first, without token values or hashes. */
95
113
  list(): Promise<LocalMcpTokenRecord[]>;
96
114
  /** Revoke a token by id. Repeating it is a no-op. Unknown ids throw. */
@@ -109,7 +127,7 @@ export interface LocalMcpTokenStoreDependencies {
109
127
  readonly readSecret: () => Promise<string>;
110
128
  readonly now: () => Date;
111
129
  /** The active local owner, or `null` before owner setup. */
112
- readonly findOwner: (db: DatabaseInterface) => Promise<{
130
+ readonly findOwner: (db: DatabaseInterface, requireUnique?: boolean) => Promise<{
113
131
  userId: string;
114
132
  tenantId: string;
115
133
  } | null>;
@@ -1 +1 @@
1
- {"version":3,"file":"local-mcp-tokens.d.ts","sourceRoot":"","sources":["../src/local-mcp-tokens.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"local-mcp-tokens.d.ts","sourceRoot":"","sources":["../src/local-mcp-tokens.ts"],"names":[],"mappings":"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"}
@@ -2,7 +2,7 @@
2
2
  "version": "1.0.0",
3
3
  "timestamp": 0,
4
4
  "packageName": "@happyvertical/smrt-app-runtime",
5
- "packageVersion": "0.60.9",
5
+ "packageVersion": "0.60.11",
6
6
  "objects": {},
7
7
  "moduleType": "smrt",
8
8
  "smrtDependencies": [
@@ -3,13 +3,14 @@
3
3
  "sensitiveFieldsExcluded": true,
4
4
  "generatedAt": "1970-01-01T00:00:00.000Z",
5
5
  "packageName": "@happyvertical/smrt-app-runtime",
6
- "packageVersion": "0.60.9",
6
+ "packageVersion": "0.60.11",
7
7
  "sourceManifestPath": "dist/manifest.json",
8
8
  "agentDocPath": "AGENTS.md",
9
9
  "sourceHashes": {
10
- "manifest": "25cfef69426cbfbc4334f62df02a2b272bfde02fe409b2726567f8e18bdbd535",
11
- "packageJson": "b94d5b2d4ee89c47fe87ea32615b58e453dd351f06434f9fe11e4ba1be310d75",
12
- "agents": "4650832b5cfbae9cb4d4b92b222d1830b2fcab57320dc322a6df6ff6649d5af8"
10
+ "manifest": "80d704127a1e182ff0096b16e9dd4885d488d3b72aed58d1631e353e972aa1c8",
11
+ "packageJson": "e139a2a34d873c3fe5fe93e94654962fa87be0d9e24865a5a6189e60f1ef57ce",
12
+ "agents": "dd8582810666f6fbeccf1ca862f443400c163d16ff94e887bddc9fdca6927b01",
13
+ "moduleDoc:README.md": "cdd3fc6895ccdeb44f972378d0242e8cb9bdd881f18d94ae3349c8a6dd3ce893"
13
14
  },
14
15
  "exports": [
15
16
  ".",
@@ -67,5 +68,12 @@
67
68
  "polymorphicAssociations": 0,
68
69
  "uuidColumns": 0
69
70
  },
70
- "agentDoc": "# @happyvertical/smrt-app-runtime\n\nApplication infrastructure composition for the validated runtime profiles in\n`@happyvertical/smrt-config`.\n\n## Local profile\n\n- `validateApplicationId()` is the canonical strict validator for explicit app\n IDs. `encodeApplicationId()` derives a length-bounded, collision-resistant\n ID from package names; generated operational surfaces must share these APIs.\n- `initializeLocalApplicationRuntime()` owns user data paths, SQLite tuning,\n local application-secret creation, and the single-use owner bootstrap flow.\n- SQLite is acquired through `@happyvertical/sql`'s explicit\n `{ driver: 'node:sqlite', custody: 'trusted-parent' }` boundary after the\n runtime establishes its user-owned mode-0700 data root.\n- The initialization lease lives beside the data root\n (`<parent>/.smrt-lease-<key>/initialization.sqlite`, #3877), then the legacy\n `/tmp/.smrt-<uid>/<key>` lease, which older releases take alone: secure when\n its ancestry is trusted, else lock-only (owner check on unmapped ancestors\n relaxed, nothing written; skipped only if its directory cannot be created\n and no lock file exists). It is required (secure) when the parent cannot hold\n a lease. Legacy candidates, deduplicated and in this order: the in-namespace\n uid, then that uid mapped through `/proc/self/uid_map` (identity when absent;\n unparseable/non-covering fails closed); ownership checks still use the\n in-namespace uid. The beside-data lease taken first keeps that order\n deadlock-free. Only the in-namespace candidate (when it differs) is skipped\n if its root is an existing real directory owned by another uid. Acquire in that order; never make the\n lease location configurable per process — every process sharing a data root\n must derive the same lease.\n- Application migrations are explicit through `prepareDatabase`; runtime never\n creates application model tables implicitly. A rejected `prepareDatabase` is\n normalized into `LocalRuntimeError` with the stable `migration_failed` code\n and the fixed recovery message `MIGRATION_FAILED_MESSAGE` (\"run pnpm\n app:setup and inspect the private migration logs\"). The caller's error text\n is never surfaced — it is retained only as a non-enumerable `cause` for\n private logs — and the same application root stays retryable.\n- Standalone migration commands must call `prepareLocalDatabaseStorage()`\n before opening SQLite so custody is established without creating schema or\n bootstrap records.\n- Read-only/copy/import operator commands must call\n `validateLocalDatabaseStorage()` before opening SQLite; it verifies the\n app-bound marker, source separation, real path chain, ownership, and mode\n without creating or repairing storage.\n- Owner bootstrap creates normal `Person`, `User`, `Tenant`, owner `Role` /\n `Membership`, and `Session` records in one transaction. `ownerTenant`\n selects the tenant slug (default `default`); because `Tenant` upserts on\n slug, the claim must look the slug up first and fail closed\n (`owner_tenant_conflict`) rather than save over it. `adoptExisting` adopts\n only an active root tenant with zero memberships (#3032).\n- Bootstrap is loopback-only. Only an HMAC of the short-lived token is stored.\n A token that cannot claim fails a read-only preflight before role/catalog\n seeding (#3323); the claim transaction's conditional UPDATE stays the\n authority for single use, expiry, and concurrency.\n- Local MCP tokens (`mcpTokens`, `openLocalMcpTokenStore`, `smrt app token`):\n owner-bound, scoped, expiring (default 30 d, max 365 d), revocable. Only a\n domain-separated HMAC (application secret) is stored, in the runtime-owned\n `_smrt_local_mcp_tokens` system table (created like the bootstrap table;\n never application schema). Issue refuses scopes the owner lacks; verify\n returns token scopes ∩ live permissions and `null` for anything else.\n- Bearer binding is explicit (`tenantBinding`, set by the auth adapter;\n `direct-membership.ts`): `direct` (local tokens, default hosted resolver)\n needs an active direct membership in exactly the tenant; the default\n `direct-or-inherited` (hosted app mappings) applies\n `isSessionTenantAuthorized`'s rule. The direct row, when present, is pinned\n into `PermissionResolver`, so inheritance never substitutes for it.\n `verify()` principals (and their `scopes` arrays) are frozen;\n `runAsPrincipal` takes a validated, deep-frozen, null-prototype copy of\n the principal before any await (`plain-data.ts`: own data only; poison\n keys `__proto__`/`constructor`/`prototype`, accessors, inherited or\n non-plain data, sparse arrays and functions rejected), authorizes from it,\n and hands `fn` that snapshot. Token `issue()` input is read the same way.\n They carry\n `tenantBinding: 'direct'` and the\n `LOCAL_MCP_TOKEN_PRINCIPAL` brand; `runAsPrincipal` rejects a copy that\n widens the binding, so the two public APIs compose safely.\n Never log or return the token outside `issue()`. The operator store opens an\n uncached connection and takes no writer lease (revocation is per request).\n- Background jobs and application-defined paid capabilities are default-off.\n- The embedded runner reuses `TaskRunner`; it is not a second job contract.\n\n## Deployed profiles\n\n- `initializeDeployedApplicationRuntime()` composes only `self-hosted` and\n `cloud`; it rejects local initialization and provider/binding mismatches.\n- Provider bindings own credentials, vendor clients, and readiness checks.\n Runtime diagnostics contain selectors and status only.\n- The database binding must expose a provider-owned `close` callback before\n `connect` can run. The runtime owns that cleanup boundary and runs the\n application's explicit, idempotent `prepareDatabase` hook.\n- A failed startup cleanup throws `DeployedRuntimeCleanupError`; callers retain\n and retry its idempotent `retryCleanup()` boundary until it succeeds.\n- Public authentication, asset storage, and secret bindings are mandatory and\n readiness-checked before startup succeeds.\n- `createTaskWorker()` and `createScheduleWorker()` initialize the normal jobs\n package runners against the shared PostgreSQL database. They are intended for\n separate processes; the web process does not start them automatically. A\n task worker polls `default` plus `SCHEDULED_JOB_QUEUE` (`agents`, where\n `ScheduleRunner` enqueues) unless `queues` is passed (#3141). The\n worker process must import the app's compiled registration\n (`.smrt/runtime/register.js`, #3117) first; runners resolve `objectType`\n through the registry and never load application source themselves.\n- `close()` drains in-flight readiness/session/worker initialization and\n serialized runner start/stop operations, stops every runner returned by the\n runtime, and then closes PostgreSQL. Returned runners must not be restarted\n after runtime shutdown begins.\n- A tracked operation may await a re-entrant `close()` request without\n deadlocking; external `close()` callers still await complete cleanup.\n- `health()` is process liveness. `readiness()` probes database/auth/assets/\n secrets; it does not claim that an external worker fleet is running.\n- Database-provider readiness is additive; a PostgreSQL-specific server-version\n probe always gates startup and live readiness.\n- Cloud must keep required tenant context and must never introduce a root or\n unscoped tenant fallback. RLS remains an explicit deployment/migration choice.\n\n## SvelteKit entry (`./sveltekit`)\n\n- Server-only subpath; `@sveltejs/kit` is an optional peer and is externalized\n in `vite.config.ts` (kit recognizes `redirect`/`fail` by class identity).\n Consumer apps use core's `smrt()` preset to bundle the Kit-facing entry into\n their SSR output and dedupe Kit; `./sveltekit-runtime` and the root stay external\n to preserve native dependency loading. The implementation subpath is for\n build composition; apps keep importing `./sveltekit`.\n Package-build externalization alone does not preserve class identity through adapter-node's final production bundle.\n The root entry must never import kit or Svelte.\n- Without a `runtime` option the profile comes from smrt-config's\n `resolveEffectiveApplicationRuntime(await loadConfig())`, the same rule as\n `smrt app` (#3446): no block → `local`; `null`/`false`/`0`/`''` fail closed.\n- `createSmrtSvelteKitRuntime()` order is fixed: readiness gate → URL tenant\n selection (`locals.selectedTenant*`, never tenant context, headers ignored) →\n verified session (tenant context entered only when\n `isSessionTenantAuthorized()` accepts it, else unauthenticated; never via\n `createSessionHandler`, which re-runs `resolve` on downstream errors) →\n publish `locals.tenantContext` only for that verified tenant.\n- `database-rls` isolation forces `postgresRls: true`, including on\n `skipPaths` (anonymous principal). `resolve` runs at most once;\n session-layer failure before it is a 500 with cleared locals.\n- In an RLS request `classOptions()`/`databaseConfig()` return the\n transaction-bound request db (class `db` overrides win). Anything that\n outlives a request (session service, tenant selector) must use the base\n config, never these.\n- The local writer lease defaults to `defaultWriterLease()` (root\n `acquireWriterLease` over `prepareApplicationStateRoot`, presenting\n `SMRT_OPERATION_INSTANCE`); `acquireWriterLease` replaces it, `false` opts\n out, deployed profiles never take it. Provider readiness stays injected:\n apps pass `createProviderReadinessProbe`; deployed startup fails closed\n without `providerReadiness`.\n- `getCollection()` builds from `classOptions()` on every call (RLS request db\n inside a request); each generated route's embedded prelude imports the\n app's `smrt.ts` and reaches it through core's\n `createGeneratedCollectionAccess()` (a legacy accessor export wins,\n deprecated for one release).\n- Owner setup removes the `smrt app` onboarding hand-off files by default,\n immediately after the claim commits (before cookie serialization or hooks);\n `onOwnerClaimed` is for additional cleanup and\n `removeOnboardingHandoff: false` is the explicit opt-out.\n- `createSessionLayoutLoad()` adds `session.user` (`{ id, email, name? }`\n copied from `locals.user`, else `null`). `createSignOutHandler(runtime)` is\n the `POST` handler for `src/routes/sign-out/+server.ts`: 405 for other\n methods, 403 unless `Sec-Fetch-Site: same-origin` or `Origin` equals the\n request origin, then `destroySessionCookie` with the runtime's cookie\n name/path/domain (cookie cleared even if the session row is gone); 204, or\n 303 to `/` when the request accepts HTML.\n- Owner setup re-checks loopback peer and loopback URL host per request and\n returns only fixed `{ code, message }` failures.\n- `verifyLocalMcpToken` (local only) and `resolveMcpPrincipal` (hosted only:\n issuer/subject → `oidc_identities` → exactly one active user with exactly\n one active direct membership, else `null`) are the runtime's MCP credential\n bindings; pass the runtime as `mountMcpAppRoute({ runtime })` (or\n `createHostedMcpResourceAuth({ runtime })`).\n Token claims never select a tenant.\n- `resolveApplicationId()` / `runtimeConfigurationFingerprint()` must stay\n byte-compatible with process managers (golden vectors in tests).\n\n## Operator state (root entry)\n\n- One owner for the state shared by the web process and `smrt app`\n (`@happyvertical/smrt-cli/app` re-exports these): `resolveApplicationStateRoot`\n / `prepareApplicationStateRoot` (private app-bound mode-0700 root and\n marker), `withOperationLock` (`operation.lock`), `acquireWriterLease` /\n `readActiveWriterLease` (`writer.lease`), `reclaimStaleRecord`, and\n `createProviderReadinessProbe` (`SMRT_*_READINESS_MODULE`, resolved from the\n app root with Node's own ESM rules). File names, record formats, and\n messages are a cross-process contract; never change them unilaterally.\n- Tests that hook `node:fs` interleavings must live in this package: from a\n consumer the package is an externalized dependency a mock cannot reach.\n\n## Public runtime diagnostics\n\n- `projectRuntimeDiagnostics()` is the only public diagnostic projection. It\n constructs the schema-version-1 allowlist and never serializes the private\n local or deployed diagnostics objects.\n- The allowlist is limited to active profile/coarse health, schema and\n migration readiness, six fixed capability statuses, a sorted/capped public\n tool inventory plus digest, explicit operational topology differences,\n coarse worker heartbeat state, and eight stable code/timestamp errors.\n- Callers supply an explicit clock and worker-heartbeat seam. A missing\n heartbeat is `unknown`; web-process liveness never proves worker liveness.\n- Error ingestion maps unknown codes to `runtime_error`, truncates timestamps\n to the minute, and ignores messages, stacks, logs, records, and nested state.\n- Authentication and diagnostics-read authorization belong before every call\n to the projector or its runtime probes.\n\n## Invariants\n\n- Never expose application-secret bytes or bootstrap token hashes in diagnostics.\n- Never include migration or provider error text in a local or deployed startup\n error message; migration driver text is a likely credential carrier.\n- Never include provider error text, URLs, tokens, or credentials in deployed\n errors, diagnostics, health, or readiness payloads.\n- Keep local data, assets, database, and secrets outside the source tree.\n- Do not reach into collection/database private fields. Add an upstream public\n API if composition cannot be expressed through exported surfaces.\n- Keep profile selection out of domain models, generated APIs, MCP/WebMCP\n surfaces, effects, approvals, and authorization records.\n\n## Validation\n\nBuild first: `sveltekit-production.test.ts` copies the published `dist` entry\nand exercises the final adapter-node HTTP handler in a separate process.\n\n```bash\npnpm --filter @happyvertical/smrt-app-runtime build\npnpm --filter @happyvertical/smrt-app-runtime test\npnpm --filter @happyvertical/smrt-app-runtime typecheck\n```\n"
71
+ "agentDoc": "# @happyvertical/smrt-app-runtime\n\nApplication infrastructure composition for the validated runtime profiles in\n`@happyvertical/smrt-config`.\n\n## Local profile\n\n- `validateApplicationId()` is the canonical strict validator for explicit app\n IDs. `encodeApplicationId()` derives a length-bounded, collision-resistant\n ID from package names; generated operational surfaces must share these APIs.\n- `initializeLocalApplicationRuntime()` owns user data paths, SQLite tuning,\n local application-secret creation, and the single-use owner bootstrap flow.\n- SQLite is acquired through `@happyvertical/sql`'s explicit\n `{ driver: 'node:sqlite', custody: 'trusted-parent' }` boundary after the\n runtime establishes its user-owned mode-0700 data root.\n- The initialization lease lives beside the data root\n (`<parent>/.smrt-lease-<key>/initialization.sqlite`, #3877), then the legacy\n `/tmp/.smrt-<uid>/<key>` lease, which older releases take alone: secure when\n its ancestry is trusted, else lock-only (owner check on unmapped ancestors\n relaxed, nothing written; skipped only if its directory cannot be created\n and no lock file exists). It is required (secure) when the parent cannot hold\n a lease. Legacy candidates, deduplicated and in this order: the in-namespace\n uid, then that uid mapped through `/proc/self/uid_map` (identity when absent;\n unparseable/non-covering fails closed); ownership checks still use the\n in-namespace uid. The beside-data lease taken first keeps that order\n deadlock-free. Only the in-namespace candidate (when it differs) is skipped\n if its root is an existing real directory owned by another uid. Acquire in that order; never make the\n lease location configurable per process — every process sharing a data root\n must derive the same lease.\n- Application migrations are explicit through `prepareDatabase`; runtime never\n creates application model tables implicitly. A rejected `prepareDatabase` is\n normalized into `LocalRuntimeError` with the stable `migration_failed` code\n and the fixed recovery message `MIGRATION_FAILED_MESSAGE` (\"run pnpm\n app:setup and inspect the private migration logs\"). The caller's error text\n is never surfaced — it is retained only as a non-enumerable `cause` for\n private logs — and the same application root stays retryable.\n- Standalone migration commands must call `prepareLocalDatabaseStorage()`\n before opening SQLite so custody is established without creating schema or\n bootstrap records.\n- Read-only/copy/import operator commands must call\n `validateLocalDatabaseStorage()` before opening SQLite; it verifies the\n app-bound marker, source separation, real path chain, ownership, and mode\n without creating or repairing storage.\n- Owner bootstrap creates normal `Person`, `User`, `Tenant`, owner `Role` /\n `Membership`, and `Session` records in one transaction. `ownerTenant`\n selects the tenant slug (default `default`); because `Tenant` upserts on\n slug, the claim must look the slug up first and fail closed\n (`owner_tenant_conflict`) rather than save over it. `adoptExisting` adopts\n only an active root tenant with zero memberships (#3032). Fresh tenant\n creation uses `TenantService` with the local ownership policy and a trusted\n reserved identity. Default tenant and owner graph IDs derive from the\n protected per-install application secret. Preserve that file when restoring\n the same installation.\n- Bootstrap is loopback-only. Only an HMAC of the short-lived token is stored.\n A token that cannot claim fails a read-only preflight before role/catalog\n seeding (#3323); the claim transaction's conditional UPDATE stays the\n authority for single use, expiry, and concurrency.\n- Local MCP tokens (`mcpTokens`, `openLocalMcpTokenStore`, `smrt app token`):\n owner-bound, scoped, expiring (default 30 d, max 365 d), revocable. Only a\n domain-separated HMAC (application secret) is stored, in the runtime-owned\n `_smrt_local_mcp_tokens` system table (created like the bootstrap table;\n never application schema). Issue refuses scopes the owner lacks; verify\n returns token scopes ∩ live permissions and `null` for anything else.\n- Bearer binding is explicit (`tenantBinding`, set by the auth adapter;\n `direct-membership.ts`): `direct` (local tokens, default hosted resolver)\n needs an active direct membership in exactly the tenant; the default\n `direct-or-inherited` (hosted app mappings) applies\n `isSessionTenantAuthorized`'s rule. The direct row, when present, is pinned\n into `PermissionResolver`, so inheritance never substitutes for it.\n `verify()` principals (and their `scopes` arrays) are frozen;\n `runAsPrincipal` takes a validated, deep-frozen, null-prototype copy of\n the principal before any await (`plain-data.ts`: own data only; poison\n keys `__proto__`/`constructor`/`prototype`, accessors, inherited or\n non-plain data, sparse arrays and functions rejected), authorizes from it,\n and hands `fn` that snapshot. Token `issue()` input is read the same way.\n They carry\n `tenantBinding: 'direct'` and the\n `LOCAL_MCP_TOKEN_PRINCIPAL` brand; `runAsPrincipal` rejects a copy that\n widens the binding, so the two public APIs compose safely.\n Return bearer material only to the issuing operator or the authenticated\n desktop credential response. The opt-in `createLocalMcpCredentialHandler`\n requires a direct loopback peer, matching Host and exact Origin, and the sole\n active owner's first-class session. Desktop slots use a disjoint ID namespace,\n atomic hash replacement and terminal revocation. See the desktop protocol in\n [README.md](README.md). The operator store opens an\n uncached connection and takes no writer lease (revocation is per request).\n- Background jobs and application-defined paid capabilities are default-off.\n- The embedded runner reuses `TaskRunner`; it is not a second job contract.\n\n## Deployed profiles\n\n- `initializeDeployedApplicationRuntime()` composes only `self-hosted` and\n `cloud`; it rejects local initialization and provider/binding mismatches.\n- Provider bindings own credentials, vendor clients, and readiness checks.\n Runtime diagnostics contain selectors and status only.\n- The database binding must expose a provider-owned `close` callback before\n `connect` can run. The runtime owns that cleanup boundary and runs the\n application's explicit, idempotent `prepareDatabase` hook.\n- A failed startup cleanup throws `DeployedRuntimeCleanupError`; callers retain\n and retry its idempotent `retryCleanup()` boundary until it succeeds.\n- Public authentication, asset storage, and secret bindings are mandatory and\n readiness-checked before startup succeeds.\n- `createTaskWorker()` and `createScheduleWorker()` initialize the normal jobs\n package runners against the shared PostgreSQL database. They are intended for\n separate processes; the web process does not start them automatically. A\n task worker polls `default` plus `SCHEDULED_JOB_QUEUE` (`agents`, where\n `ScheduleRunner` enqueues) unless `queues` is passed (#3141). The\n worker process must import the app's compiled registration\n (`.smrt/runtime/register.js`, #3117) first; runners resolve `objectType`\n through the registry and never load application source themselves.\n- `close()` drains in-flight readiness/session/worker initialization and\n serialized runner start/stop operations, stops every runner returned by the\n runtime, and then closes PostgreSQL. Returned runners must not be restarted\n after runtime shutdown begins.\n- A tracked operation may await a re-entrant `close()` request without\n deadlocking; external `close()` callers still await complete cleanup.\n- `health()` is process liveness. `readiness()` probes database/auth/assets/\n secrets; it does not claim that an external worker fleet is running.\n- Database-provider readiness is additive; a PostgreSQL-specific server-version\n probe always gates startup and live readiness.\n- Cloud must keep required tenant context and must never introduce a root or\n unscoped tenant fallback. RLS remains an explicit deployment/migration choice.\n\n## SvelteKit entry (`./sveltekit`)\n\n- Server-only subpath; `@sveltejs/kit` is an optional peer and is externalized\n in `vite.config.ts` (kit recognizes `redirect`/`fail` by class identity).\n Consumer apps use core's `smrt()` preset to bundle the Kit-facing entry into\n their SSR output and dedupe Kit; `./sveltekit-runtime` and the root stay external\n to preserve native dependency loading. The implementation subpath is for\n build composition; apps keep importing `./sveltekit`.\n Package-build externalization alone does not preserve class identity through adapter-node's final production bundle.\n The root entry must never import kit or Svelte.\n- Without a `runtime` option the profile comes from smrt-config's\n `resolveEffectiveApplicationRuntime(await loadConfig())`, the same rule as\n `smrt app` (#3446): no block → `local`; `null`/`false`/`0`/`''` fail closed.\n- `createSmrtSvelteKitRuntime()` order is fixed: readiness gate → URL tenant\n selection (`locals.selectedTenant*`, never tenant context, headers ignored) →\n verified session (tenant context entered only when\n `isSessionTenantAuthorized()` accepts it, else unauthenticated; never via\n `createSessionHandler`, which re-runs `resolve` on downstream errors) →\n publish `locals.tenantContext` only for that verified tenant.\n- `database-rls` isolation forces `postgresRls: true`, including on\n `skipPaths` (anonymous principal). `resolve` runs at most once;\n session-layer failure before it is a 500 with cleared locals.\n- In an RLS request `classOptions()`/`databaseConfig()` return the\n transaction-bound request db (class `db` overrides win). Anything that\n outlives a request (session service, tenant selector) must use the base\n config, never these.\n- The local writer lease defaults to `defaultWriterLease()` (root\n `acquireWriterLease` over `prepareApplicationStateRoot`, presenting\n `SMRT_OPERATION_INSTANCE`); `acquireWriterLease` replaces it, `false` opts\n out, deployed profiles never take it. Provider readiness stays injected:\n apps pass `createProviderReadinessProbe`; deployed startup fails closed\n without `providerReadiness`.\n- `getCollection()` builds from `classOptions()` on every call (RLS request db\n inside a request); each generated route's embedded prelude imports the\n app's `smrt.ts` and reaches it through core's\n `createGeneratedCollectionAccess()` (a legacy accessor export wins,\n deprecated for one release).\n- Owner setup removes the `smrt app` onboarding hand-off files by default,\n immediately after the claim commits (before cookie serialization or hooks);\n `onOwnerClaimed` is for additional cleanup and\n `removeOnboardingHandoff: false` is the explicit opt-out.\n- `createSessionLayoutLoad()` adds `session.user` (`{ id, email, name? }`\n copied from `locals.user`, else `null`). `createSignOutHandler(runtime)` is\n the `POST` handler for `src/routes/sign-out/+server.ts`: 405 for other\n methods, 403 unless `Sec-Fetch-Site: same-origin` or `Origin` equals the\n request origin, then `destroySessionCookie` with the runtime's cookie\n name/path/domain (cookie cleared even if the session row is gone); 204, or\n 303 to `/` when the request accepts HTML.\n- Owner setup re-checks loopback peer and loopback URL host per request and\n returns only fixed `{ code, message }` failures.\n- `verifyLocalMcpToken` (local only) and `resolveMcpPrincipal` (hosted only:\n issuer/subject → `oidc_identities` → exactly one active user with exactly\n one active direct membership, else `null`) are the runtime's MCP credential\n bindings; pass the runtime as `mountMcpAppRoute({ runtime })` (or\n `createHostedMcpResourceAuth({ runtime })`).\n Token claims never select a tenant.\n- `resolveApplicationId()` / `runtimeConfigurationFingerprint()` must stay\n byte-compatible with process managers (golden vectors in tests).\n\n## Operator state (root entry)\n\n- One owner for the state shared by the web process and `smrt app`\n (`@happyvertical/smrt-cli/app` re-exports these): `resolveApplicationStateRoot`\n / `prepareApplicationStateRoot` (private app-bound mode-0700 root and\n marker), `withOperationLock` (`operation.lock`), `acquireWriterLease` /\n `readActiveWriterLease` (`writer.lease`), `reclaimStaleRecord`, and\n `createProviderReadinessProbe` (`SMRT_*_READINESS_MODULE`, resolved from the\n app root with Node's own ESM rules). File names, record formats, and\n messages are a cross-process contract; never change them unilaterally.\n- Tests that hook `node:fs` interleavings must live in this package: from a\n consumer the package is an externalized dependency a mock cannot reach.\n\n## Public runtime diagnostics\n\n- `projectRuntimeDiagnostics()` is the only public diagnostic projection. It\n constructs the schema-version-1 allowlist and never serializes the private\n local or deployed diagnostics objects.\n- The allowlist is limited to active profile/coarse health, schema and\n migration readiness, six fixed capability statuses, a sorted/capped public\n tool inventory plus digest, explicit operational topology differences,\n coarse worker heartbeat state, and eight stable code/timestamp errors.\n- Callers supply an explicit clock and worker-heartbeat seam. A missing\n heartbeat is `unknown`; web-process liveness never proves worker liveness.\n- Error ingestion maps unknown codes to `runtime_error`, truncates timestamps\n to the minute, and ignores messages, stacks, logs, records, and nested state.\n- Authentication and diagnostics-read authorization belong before every call\n to the projector or its runtime probes.\n\n## Invariants\n\n- Never expose application-secret bytes or bootstrap token hashes in diagnostics.\n- Never include migration or provider error text in a local or deployed startup\n error message; migration driver text is a likely credential carrier.\n- Never include provider error text, URLs, tokens, or credentials in deployed\n errors, diagnostics, health, or readiness payloads.\n- Keep local data, assets, database, and secrets outside the source tree.\n- Do not reach into collection/database private fields. Add an upstream public\n API if composition cannot be expressed through exported surfaces.\n- Keep profile selection out of domain models, generated APIs, MCP/WebMCP\n surfaces, effects, approvals, and authorization records.\n\n## Validation\n\nBuild first: `sveltekit-production.test.ts` copies the published `dist` entry\nand exercises the final adapter-node HTTP handler in a separate process.\n\n```bash\npnpm --filter @happyvertical/smrt-app-runtime build\npnpm --filter @happyvertical/smrt-app-runtime test\npnpm --filter @happyvertical/smrt-app-runtime typecheck\n```\n",
72
+ "moduleDocs": [
73
+ {
74
+ "path": "README.md",
75
+ "module": "README",
76
+ "content": "# @happyvertical/smrt-app-runtime\n\nReusable infrastructure composition for s-m-r-t applications. The package\nimplements the validated profiles from `@happyvertical/smrt-config` without\nforking domain objects, generated surfaces, effects, approvals, or job calls.\n\n## Private local applications\n\n```ts\nimport {\n initializeLocalApplicationRuntime,\n} from '@happyvertical/smrt-app-runtime';\n\nconst { runtime, bootstrap, diagnostics } =\n await initializeLocalApplicationRuntime({\n appId: 'my-app',\n sourceRoot: process.cwd(),\n prepareDatabase: runApplicationMigrations,\n });\n\n// Show bootstrap.token only in the loopback onboarding URL. The plaintext is\n// returned once and only its HMAC is persisted.\n```\n\nApplication migrations run through the explicit `prepareDatabase` hook while\nthe runtime holds the root lease. A rejected migration is normalized into a\n`LocalRuntimeError` with the stable `migration_failed` code and the fixed,\nsecret-free message exported as `MIGRATION_FAILED_MESSAGE`: \"The application\nmigration step failed; run pnpm app:setup and inspect the private migration\nlogs.\" The migration driver's own text — a likely carrier of a connection\nstring, credential, path, or environment value — is never surfaced; it is kept\nas a non-enumerable `cause` for private logs. Startup releases the database\nhandle and the initialization lease, so the same application root and data\ndirectory remain retryable once the migration is fixed.\n\nThe path resolver selects the current user's OS application-data directory\n(`~/Library/Application Support` on macOS, `%LOCALAPPDATA%` on Windows, or\n`$XDG_DATA_HOME` / `~/.local/share` on Linux). Secure initialization currently\nrequires Node to expose nonzero `O_NOFOLLOW` and `O_DIRECTORY` filesystem\nflags; it fails closed on platforms without that custody support and therefore\ndoes not yet claim Windows runtime support. The data root contains a mode-0600\nSQLite database, a user-owned asset directory, and generated mode-0600\napplication secret material. The root must be a dedicated application\ndirectory: placing it inside the source checkout or choosing an ancestor is\nrefused, as is choosing the user home itself or the filesystem root. An\nexplicitly configured root that already exists must already be\nowned by the current user with mode `0700`; initialization rejects it without\nchanging permissions or creating artifacts when that custody proof fails.\nAn empty root is claimed with an app-specific, empty mode-0600 marker. A\npopulated root is accepted only with that valid marker, so selecting an\nunrelated private directory fails without changing its contents. A pending\nmarker makes the claim crash-recoverable while the database is first acquired;\nit is promoted atomically after the released SQL custody boundary verifies the\ncomplete ancestor/root chain, including macOS ACLs. Failed custody removes the\npending claim and every directory only when they were created by that attempt;\nan inherited pending claim and its database remain authoritative for retry.\nInitializers for the same data root are serialized across processes by an\nexclusive transaction in a dedicated SQLite lock database under a private,\nroot-keyed custody directory kept beside the data it protects:\n`<parent of the data root>/.smrt-lease-<key>/initialization.sqlite`. That\nparent has already passed the custody preflight and is the one location every\nprocess sharing the data directory sees, so the lease also works inside a user\nnamespace (agent sandboxes, rootless containers) where `/tmp` reads as owned by\nthe overflow uid. The historical per-user `/tmp/.smrt-<uid>/<key>` lease is\nstill taken afterwards, so a process running an older release (which takes\nonly that lease) stays excluded. When `/tmp` fails the ancestry owner check\nbecause its owner is unmapped, the legacy lease is taken lock-only: the lock\nfile is never written, every ancestor must still be a real directory that is\nnot group/world writable unless sticky, and the lock directories and file must\nbe current-user-owned and private. A held legacy lease therefore makes the new\nprocess wait (and fail closed after two minutes). Inside a user namespace that\nremaps the uid (for example `unshare -Ur`, where host uid 1000 reads as 0), the\nlegacy lease is taken for both the in-namespace uid (`/tmp/.smrt-0`, what an\nolder release inside the namespace locks) and, in that order, the uid's mapping\nin `/proc/self/uid_map` (`/tmp/.smrt-<host uid>`, what an older host process\nlocks); identical paths are taken once, so a host process takes the single\nlease it always did. Every new process takes the beside-data lease first, which\nis what keeps the fixed legacy order deadlock-free. When the in-namespace uid\ndiffers from its mapping and its `/tmp/.smrt-<uid>` root already exists as a\nreal directory owned by someone else (under `unshare -Ur`, host root's\n`/tmp/.smrt-0` reads as the overflow uid), that one candidate is skipped: no\nprocess in the namespace can hold a lease beneath a root it does not own. A\nsymlink there, and any problem with the mapped candidate, still fails closed.\nA map that\ncannot be read, parsed, or does not cover the current uid fails closed. Only\none namespace level is visible, so a doubly nested remap is not translated\npast its parent. The residual rule: when the\nlegacy lock directory cannot be created at all (`/tmp` not writable or\nread-only in that view) and no legacy lock file exists, the legacy lease is\nskipped. When the data root's parent is not writable by the current user (or is\nread-only) the secure `/tmp` lease is required instead, as before. The\nreleased `@happyvertical/sql`\ntrusted-parent boundary validates each lease directory, its ancestors, and the lock\nleaf for ownership, write permissions, static links, and macOS ACLs before it\nopens the lock database. Atomic SQLite locking elects one owner without deleting\nor replacing a pathname, so there is no stale-file ABA window and no PID or\nclock lease. Process or worker death releases the kernel lock automatically. A\nread-only path, custody, and ownership-marker preflight rejects an obviously\ninvalid application root before creating its lock-registry entry; the complete\nchecks run again under the lease before application-root mutation. The lease\ncovers storage acquisition, secret publication, SQLite tuning,\napplication migrations, and bootstrap construction. Contenders wait up to two\nminutes for that complete sequence, so normal migrations can finish without\noverlap. Marker or temporary-secret cleanup therefore cannot race another\nactive initializer.\nEvery existing path component is opened without following symbolic links and\nchecked against its canonical path before descendants or secret bytes are\nwritten. The runtime then acquires SQLite through `@happyvertical/sql`'s\nexplicit `node:sqlite` trusted-parent custody boundary, rooted at the mode-0700\napplication data directory. Unsupported runtimes or platforms and unsafe\nownership, permissions, ACLs, or path components fail closed. The local\n`runtime.databaseConfig()` and default `runtime.classOptions()` retain that\nsame driver, custody, and root configuration when application collections open\nanother connection; an explicit per-class database override still wins.\n\nThe application secret is published by atomically linking a fully written,\nsynced mode-0600 temporary file into place. Concurrent installers validate and\nreuse the one winning value; an incomplete or malformed existing secret is\nrejected rather than overwritten, and stale interrupted temporary files are\nremoved after a complete value is durably available.\n\nThe custody boundary prevents static link traversal and mutation by other OS\nprincipals while the application retains control of that directory. Hostile\ncode already running as the same user is outside this boundary; isolating\nsame-account processes requires an OS sandbox and a descriptor-relative SQLite\nVFS.\n\nOwner onboarding binds to `127.0.0.1` by default and accepts only loopback IP\nliterals (`127.0.0.0/8` or `::1`), avoiding hostname-resolution ambiguity.\nThe first valid claim creates a tenant-bound `Person`, `User`, default `Tenant`,\nowner `Role` / `Membership`, and server-side `Session` atomically. The owner\nPerson belongs to the actual created or adopted tenant; its shared profile type\nremains global. Startup and setup are idempotent; replayed, expired, or\nconcurrent claims fail closed.\n`ownerTenant: { slug, name, adoptExisting }` (also accepted by the SvelteKit\nruntime) selects the bootstrap tenant; the default is a new tenant with slug\n`default`. The default tenant, owner User, owner Person, and owner Membership\nhave separate UUIDv8 identifiers derived with domain-separated HMAC-SHA256\nfrom the installation's private `secrets/application.secret`. Independent\ninstalls of the same app get distinct identities and share the global built-in\nrole IDs. Restarts reuse the same installation identities. Treat\n`secrets/application.secret` as installation identity material. Preserve it\nwith the database in protected backups and during a restore or move of the\nsame installation. Deleting, replacing, or rotating the file changes the\nderived identities and invalidates existing bootstrap and local MCP tokens.\nKeep only one active installation for a given secret. A copied data root\nretains the same owner, tenant, and writer IDs, and the runtime currently has\nno way to detect that copy. Start independent installations with a fresh data\nroot.\n\nThe invitation and active owner membership authorize the owner. The same\nseed derives a separate writer UUID. The local runtime binds it to the\ndatabase so local edits to tracked rows identify this installation, including\nafter a restart.\n\nA tenant with the selected slug causes `owner_tenant_conflict`, unless\n`adoptExisting: true` explicitly allows adopting an active root tenant with\nzero memberships of any status. An adopted tenant keeps its id and name.\nThe claim rejects an unrelated row using the reserved tenant UUID and an\naccount using the owner UUID or the claimed email. The owner Person and\nMembership also use strict inserts. A failed claim rolls back\nand leaves the invitation claimable.\nAuthenticated session TTLs are configured in whole seconds with a minimum of\none second, and invalid values are rejected before filesystem mutation.\n\nBackground jobs and application-defined paid capabilities remain disabled until\nexplicitly enabled. With embedded job topology, `createEmbeddedJobRunner()`\nreturns the normal s-m-r-t `TaskRunner`, so the application keeps one enqueue\nand execution contract without requiring a separate worker service.\n\n### Local desktop MCP credentials\n\nA desktop product can mount this opt-in SvelteKit route in\n`src/routes/api/local/mcp-credentials/+server.ts`.\n\n```ts\nimport { createLocalMcpCredentialHandler } from '@happyvertical/smrt-app-runtime/sveltekit';\nimport { runtime } from '$lib/server/smrt';\n\nexport const POST = createLocalMcpCredentialHandler(runtime);\n```\n\nServe it on the desktop app's direct loopback listener, with the adapter's\nsocket peer address and request Host. Keep forwarded address, host, and\nprotocol configuration unset. Set adapter-node's\n`ORIGIN` to the actual desktop URL, such as `http://127.0.0.1:4678`, because\nadapter-node otherwise assumes HTTPS. The handler checks the socket peer,\nloopback URL host, matching Host and exact Origin. When the browser\nsends `Sec-Fetch-Site`, it must be `same-origin`. Call the endpoint from the\napp's signed-in, same-origin desktop webview using its normal session cookie.\nThe session must use local bootstrap, password or passkey authentication,\nhave a direct active membership, and match the sole active system Owner\nmembership of the installation. Device, layered and permission-capped sessions\nare rejected.\n\nSend a JSON POST with an opaque lowercase UUIDv4 `id` generated by the\ndesktop app, a nonempty array of permission slugs, and an explicit integer\nlifetime from 60 to 31,536,000 seconds.\n\n```json\n{\n \"action\": \"put\",\n \"id\": \"2c70f518-b95a-445b-a75e-8126ae7c032a\",\n \"scopes\": [\"notes.read\"],\n \"expiresInSeconds\": 3600\n}\n```\n\nThe first PUT creates the slot. A later POST with the same `action: \"put\"`\nreplaces its bearer, scopes and expiry atomically. Scopes must be held by\nboth the live owner and the authenticated session. Successful replies carry\n`{ id, token, scopes, expiresAt }` in a private `Cache-Control: no-store`\nresponse. Pass the bearer directly to native credential handling for the MCP\nbridge. Keep it out of arguments, URLs, logs, browser storage, and generated\nplugin artifacts. The installation secret stays on the server, and the\ndatabase stores only the bearer HMAC.\n\nPersist the non-secret slot ID before the first request and serialize actions\nper slot. A failed write preserves the previous credential. If the outcome is\nunknown or the response is lost, repeat PUT with the same ID. Each successful\nwrite produces a fresh credential, and only the latest committed write\nverifies. A retry therefore recovers the slot without leaving an extra active\ncredential.\n\nSend `{ \"action\": \"revoke\", \"id\": \"<slot-id>\" }` with an unrestricted owner\nsession to disconnect. Repeating it returns `{ \"status\": \"revoked\" }`.\nRevocation is permanent for the slot even if a PUT was delayed or no PUT\ncompleted, so use a new UUID to reconnect. The operator CLI can list or\nrevoke the stored UUIDv8 record. Desktop slots and manual CLI token IDs are\nseparate namespaces.\n\nFailures carry a fixed `code` and no credentials. A revoked slot returns\n`409 slot_unavailable`; validation failures return `400 invalid_request`\nor `400 invalid_scope`; requests failing the trust checks return\n`403 forbidden`. Deployed profiles return `404 unavailable` to requests\nthat reach the profile check.\n\n## SvelteKit entry\n\n`@happyvertical/smrt-app-runtime/sveltekit` composes the profile runtime,\ntenant selection, the signed session, and authorized-tenant locals so an app's\nserver hooks are a few lines. `@sveltejs/kit` is an optional peer dependency;\nthe root entry never imports it.\n\n```ts\n// src/hooks.server.ts\nimport { createSmrtSvelteKitRuntime } from '@happyvertical/smrt-app-runtime/sveltekit';\n\nexport const runtime = createSmrtSvelteKitRuntime({\n prepareDatabase: runApplicationMigrations, // optional, idempotent\n});\nexport const { handle, init } = runtime;\n```\n\n```ts\n// src/app.d.ts\nimport type { SmrtRuntimeLocals } from '@happyvertical/smrt-app-runtime/sveltekit';\ndeclare global {\n namespace App {\n interface Locals extends SmrtRuntimeLocals {}\n }\n}\n```\n\n`init` is the fail-closed startup gate (local runtime or deployed bindings) and\n`handle` waits for it, then runs, in order: URL tenant selection into\n`locals.selectedTenant*` (never tenant context; tenant headers are ignored),\nthe signed session, and publication of `locals.tenantContext` only when the\nactive context matches the verified session tenant. A session's tenant is\naccepted only for an active direct membership or a legitimately inherited\none (`isSessionTenantAuthorized()`, the same rule deployed `restoreSession()`\napplies); otherwise the request is unauthenticated (no user, permissions,\ntenant, or tenant context). `database-rls` isolation always runs the request\nRLS transaction (`session.postgresRls` cannot disable it); a\n`session.skipPaths` prefix skips session loading only and still runs inside\nthat transaction as an anonymous principal. During such a request\n`runtime.classOptions()` / `runtime.databaseConfig()` return the\ntransaction-bound request database (unless the class has its own `db`\noverride), so call them per request and never retain the result. Downstream code runs\nat most once: its error propagates unchanged, and a session-layer failure\nbefore it returns 500 with no authenticated locals. Defaults read `SMRT_APP_ID`, `SMRT_DATA_DIR`, `HOST`, `DATABASE_URL`,\n`TENANT_BASE_DOMAIN`, and `SMRT_BACKGROUND_JOBS`; `smrt.config` `runtime`\nselects the profile (local when absent; a present `null`/`false`/`0`/`''`\nfails closed, as in `smrt app`). Deployed profiles additionally require\n`providerReadiness` probes and fail closed without them. In the local profile\nthe runtime holds the single-writer lease shared with `smrt app` operations by\ndefault (`defaultWriterLease()`: `writer.lease` under\n`prepareApplicationStateRoot()`, presenting `SMRT_OPERATION_INSTANCE`); pass\n`acquireWriterLease` to replace it or `acquireWriterLease: false` to hold none.\nOptional hooks: `onBootstrapInvitation` (present a newly issued setup token),\n`selectTenant`, `session`, and `classOverrides`.\n`runtime.getCollection(className)` returns the registered collection built\nfrom `runtime.classOptions(className)` on that call. Each generated `/api/*`\nroute embeds a prelude that imports the app's `src/lib/server/smrt.ts` and\nresolves collections through its exported `runtime` (core's\n`createGeneratedCollectionAccess()`), so an app's `smrt.ts` is only the\nruntime and its options. A legacy `getCollection`/`getSmrtConfig` export there\nstill takes precedence for one release, with a deprecation warning.\n\nMountable routes:\n\n```ts\n// src/routes/api/_runtime/health/+server.ts\nexport const GET = createRuntimeHealthHandler(runtime);\n// src/routes/api/_runtime/diagnostics/+server.ts\nexport const GET = createRuntimeDiagnosticsHandler({ runtime, toolNames });\n// src/routes/setup/+page.server.ts\nexport const { load, actions } = createOwnerSetupPage(runtime);\n// src/routes/+layout.server.ts\nexport const load = createSessionLayoutLoad();\n// src/routes/sign-out/+server.ts\nexport const POST = createSignOutHandler(runtime);\n```\n\n`createSessionLayoutLoad()` returns `session.user` (`{ id, email, name? }` or\n`null`). `createSignOutHandler` accepts only same-origin `POST` (405 / 403\notherwise), destroys the session, clears the cookie, and answers 204 (303 to\n`/` for HTML form posts).\n\nDiagnostics authorize (owner role or `runtime_diagnostics.read` on an active,\nsession-matching membership) before reading the runtime and return only stable\n`{ schemaVersion: 1, error: { code } }` failures. Owner setup is local-only and\nre-checks on every request that both the peer address and the URL host are\nloopback; its `default` action reads `token`, `name`, `email`, and optional `password` and\n`tenantName`, sets the session cookie, and redirects 303, or returns\n`fail(status, { code, message })` with `setup_disabled` (404),\n`setup_unavailable` (403), `setup_invalid_input` (400), `setup_invalid`\n(400), or `setup_conflict` (409, the `ownerTenant` slug already exists). Claim error text is never returned. After the claim commits, the\nruntime removes the `smrt app setup` / `recover` hand-off files\n(`ONBOARDING_HANDOFF_FILES`: `onboarding.json`, `onboarding-launch.html`) from\n`runtime.applicationStateRoot()`, so `pnpm app:open` stops offering the spent\ninvitation; failed claims leave them untouched. `onOwnerClaimed` remains for\nextra app cleanup and `removeOnboardingHandoff: false` opts out.\n\nPassword-based applications should pass `{ requirePassword: true }` to\n`createOwnerSetupPage` and include a password field in their setup form. The\npassword is stored in the owner-claim transaction; a rejected password leaves\nthe token available for retry. Existing bootstrap consumers may omit it.\nUse one server-only `PasswordPolicyOptions` value for bootstrap and sign-in,\nincluding any pepper, length constraints, or custom rejection hook:\n\n```typescript\nconst passwordPolicy = { pepper: serverSecrets.passwordPepper, minLength: 16 };\nconst runtime = createSmrtSvelteKitRuntime({ passwordPolicy });\nconst passwords = await PasswordCredentialService.create({\n ...runtime.classOptions('User'),\n password: passwordPolicy,\n});\n```\n\n`initializeLocalApplicationRuntime` accepts the same `passwordPolicy` option.\nIt is never taken from form data or included in diagnostics. Bootstrap uses the\npolicy on its transaction-bound service, and registers password-management\npermissions before seeding the owner's grants.\n\n`resolveApplicationId()` and `runtimeConfigurationFingerprint()` (root entry)\nare the canonical app ID and secret-free configuration fingerprint shared by\nthe web health route and process managers.\n\nThe root entry also owns the operator state shared with `smrt app`:\n`prepareApplicationStateRoot()` (private, app-bound state directory),\n`withOperationLock()`, `acquireWriterLease()` / `readActiveWriterLease()`,\nand `createProviderReadinessProbe()`. The SvelteKit runtime takes the writer\nlease itself; a SvelteKit app passes only the readiness probe and its own\noptions, without depending on the CLI:\n\n```ts\n// src/lib/server/smrt.ts\nimport { createProviderReadinessProbe } from '@happyvertical/smrt-app-runtime';\nimport { createSmrtSvelteKitRuntime } from '@happyvertical/smrt-app-runtime/sveltekit';\n\nexport const runtime = createSmrtSvelteKitRuntime({\n providerReadiness: createProviderReadinessProbe,\n});\n```\n\n## Self-hosted and cloud applications\n\nThe deployed initializer validates the selected profile against concrete,\nprovider-owned bindings. Database URLs, OIDC credentials, storage keys, and\nsecret-manager identifiers stay inside those adapters and are never copied into\nthe runtime snapshot.\n\n```ts\nimport {\n initializeDeployedApplicationRuntime,\n} from '@happyvertical/smrt-app-runtime';\nimport { getDatabase } from '@happyvertical/sql';\n\nconst initialized = await initializeDeployedApplicationRuntime({\n profile: 'self-hosted',\n database: {\n engine: 'postgres',\n connect: () => getDatabase({\n type: 'postgres',\n url: requirePrivateSetting('DATABASE_URL'),\n }),\n close: async (db) => {\n await db.close?.();\n },\n },\n authentication: {\n provider: 'oidc',\n readiness: () => oidcProvider.assertReady(),\n },\n assets: {\n provider: 's3-compatible',\n readiness: () => assetProvider.assertReady(),\n },\n secrets: {\n provider: 'environment',\n readiness: () => secretProvider.assertReady(),\n },\n prepareDatabase: runApplicationMigrations,\n});\n```\n\nStartup validates every binding, including the provider-owned database cleanup\nboundary, before opening a connection. A missing public-auth or secret binding,\na selector mismatch, an unavailable provider, a failed\nPostgreSQL probe, or a failed migration rejects startup. Provider failures are\nreported with stable component codes and omit the underlying provider message\nso credentials cannot leak into HTTP or orchestration payloads.\nA custom database readiness callback is additive; the runtime always runs its\nown PostgreSQL-specific server-version probe before startup or readiness can\nsucceed.\nIf cleanup after a startup failure also fails,\n`DeployedRuntimeCleanupError.retryCleanup()` retains the redacted, idempotent\nownership path until the provider closes successfully.\n\n`health()` reports process liveness. `readiness()` rechecks PostgreSQL,\nauthentication, assets, and secrets and returns only `ready` / `not-ready`\ncomponent states. `diagnostics()` reports the resolved profile, explicit\nprovider selectors, tenancy posture, and worker topology without secret values.\n\nJob producers keep using `SmrtObject.bg()` / `background().enqueue()` in every\nprofile. Deployed worker entry points initialize the ordinary runners against\nthe same PostgreSQL database. A worker is a separate Node process, so it must\nfirst import the application's compiled object registration —\n`.smrt/runtime/register.js`, produced by a SvelteKit `smrtPlugin()` build — or\nany job targeting an application object fails with `Unknown object type`:\n\n```ts\nawait import('./.smrt/runtime/register.js');\n\nconst taskWorker = await initialized.createTaskWorker({ concurrency: 8 });\nawait taskWorker.start();\n\n// Run this in a separate schedule-worker process, not beside the web server.\nconst scheduleWorker = await initialized.createScheduleWorker();\nawait scheduleWorker.start();\n```\n\n`initialized.close()` drains in-flight readiness/session/worker initialization\nand serialized runner start/stop operations, stops every runner returned by\nthis runtime, and only then closes PostgreSQL.\nCallers may stop a runner earlier, but must not restart a returned runner after\nits runtime has begun shutdown; lifecycle-gated `start()` calls then reject.\nAn awaited `close()` request made from inside a tracked provider or worker\noperation acknowledges shutdown so that operation can unwind; callers outside\nthe operation continue to await complete worker and database cleanup.\n\nSelf-hosted deployments may select OIDC, magic-link, or password authentication, explicit\nsingle- or multi-tenancy, local or S3-compatible assets, and environment,\nlocal-file, or external secrets. Cloud requires hosted identity, PostgreSQL,\nmulti-tenancy with required tenant context, managed/external secrets,\nmanaged/S3-compatible object storage, public TLS, and scalable workers. Cloud\nmay select application isolation instead of PostgreSQL RLS, but it can never\nenable an unscoped/root-tenant fallback.\n\nThe application runtime does not provision databases, buckets, identity\nproviders, secret managers, worker fleets, TLS, billing, or a hosted control\nplane. Those remain operator/managed-platform responsibilities. Enabling the\n`database-rls` selector also requires the deployment migration to apply the\ndocumented s-m-r-t PostgreSQL policies; the selector does not grant or mutate\ndatabase privileges at runtime.\n"
77
+ }
78
+ ]
71
79
  }
@@ -0,0 +1,56 @@
1
+ ---
2
+ type: "Component"
3
+ title: "@happyvertical/smrt-app-runtime"
4
+ description: "Validated local, self-hosted, and cloud runtime composition for s-m-r-t applications"
5
+ status: "stable"
6
+ generated:
7
+ by: "smrt/scripts/generate-knowledge-okf.ts"
8
+ at: "2026-11-06T02:36:23Z"
9
+ audience: "internal"
10
+ evidence_level: "manifest-described"
11
+ source_revision: "sha256:11ea4a4fc9a78d6668f2fc0a457f8172779678b1b0d408b61a2290c52eb35c8b"
12
+ sources:
13
+ - id: "manifest"
14
+ resource: "https://github.com/happyvertical/smrt/blob/main/packages/app-runtime/package.json"
15
+ title: "@happyvertical/smrt-app-runtime package manifest"
16
+ - id: "agents"
17
+ resource: "https://github.com/happyvertical/smrt/blob/main/packages/app-runtime/AGENTS.md"
18
+ title: "@happyvertical/smrt-app-runtime packages/app-runtime/AGENTS.md"
19
+ - id: "agents-2"
20
+ resource: "https://github.com/happyvertical/smrt/blob/main/packages/app-runtime/README.md"
21
+ title: "@happyvertical/smrt-app-runtime packages/app-runtime/README.md"
22
+ ---
23
+
24
+ # @happyvertical/smrt-app-runtime
25
+
26
+ ## Package
27
+
28
+ - Directory: `packages/app-runtime`
29
+ - Private: no
30
+ - Object source: `domain-artifact`
31
+ - Evidence level: `manifest-described`
32
+
33
+ ## Documentation
34
+
35
+ - `packages/app-runtime/AGENTS.md`
36
+ - `packages/app-runtime/README.md`
37
+
38
+ ## Framework dependencies
39
+
40
+ - [smrt-config](/components/smrt-config.md)
41
+ - [smrt-core](/components/smrt-core.md)
42
+ - [smrt-jobs](/components/smrt-jobs.md)
43
+ - [smrt-profiles](/components/smrt-profiles.md)
44
+ - [smrt-tenancy](/components/smrt-tenancy.md)
45
+ - [smrt-users](/components/smrt-users.md)
46
+ - [smrt-vitest](/components/smrt-vitest.md)
47
+
48
+ ## SDK dependencies
49
+
50
+ - `@happyvertical/sql`
51
+
52
+ ## Exports
53
+
54
+ - `.`
55
+ - `./sveltekit`
56
+ - `./sveltekit-runtime`
@@ -15,6 +15,7 @@
15
15
  */
16
16
  export { type ApplicationRuntimeDiagnosticsOptions, authorizedTenantLocalsHandle, composeHandles, createSmrtSvelteKitRuntime, defaultWriterLease, type ProviderReadinessComponent, type ProviderReadinessFactory, type RuntimeHealthBody, type SmrtRuntimeBoundPrincipal, type SmrtRuntimeBoundPrincipalSnapshot, type SmrtRuntimeDeepReadonly, type SmrtRuntimeLocals, type SmrtRuntimeMcpIdentity, type SmrtRuntimeMcpPrincipalMapping, type SmrtRuntimeSessionCookie, type SmrtRuntimeSessionOptions, type SmrtSvelteKitRuntime, type SmrtSvelteKitRuntimeOptions, type TenantBindingMode, type WriterLease, type WriterLeaseContext, } from '@happyvertical/smrt-app-runtime/sveltekit-runtime';
17
17
  export { createRuntimeDiagnosticsHandler, createRuntimeHealthHandler, createSessionLayoutLoad, type DiagnosticsPrincipalLocals, RUNTIME_DIAGNOSTICS_READ_PERMISSION, type RuntimeDiagnosticsHandlerOptions, type SessionLayoutData, type SessionLayoutUser, } from './handlers.js';
18
+ export { createLocalMcpCredentialHandler } from './local-mcp-credentials.js';
18
19
  export { createOwnerSetupPage, DEFAULT_OWNER_SETUP_MESSAGES, isLoopbackAddress, isLoopbackHostname, isLoopbackRequest, OWNER_SETUP_FIELDS, type OwnerSetupActionEvent, type OwnerSetupErrorCode, type OwnerSetupEvent, type OwnerSetupFailure, type OwnerSetupLinkState, type OwnerSetupPage, type OwnerSetupPageData, type OwnerSetupPageOptions, } from './owner-setup.js';
19
20
  export { createSignOutHandler } from './sign-out.js';
20
21
  export { createSubdomainTenantSelector, normalizeTenantSelection, type SubdomainTenantSelectorOptions, selectTenantSlug, type TenantSelection, type TenantSelectionEvent, type TenantSelector, } from './tenancy.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/sveltekit/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EACL,KAAK,oCAAoC,EACzC,4BAA4B,EAC5B,cAAc,EACd,0BAA0B,EAC1B,kBAAkB,EAClB,KAAK,0BAA0B,EAC/B,KAAK,wBAAwB,EAC7B,KAAK,iBAAiB,EACtB,KAAK,yBAAyB,EAC9B,KAAK,iCAAiC,EACtC,KAAK,uBAAuB,EAC5B,KAAK,iBAAiB,EACtB,KAAK,sBAAsB,EAC3B,KAAK,8BAA8B,EACnC,KAAK,wBAAwB,EAC7B,KAAK,yBAAyB,EAC9B,KAAK,oBAAoB,EACzB,KAAK,2BAA2B,EAChC,KAAK,iBAAiB,EACtB,KAAK,WAAW,EAChB,KAAK,kBAAkB,GACxB,MAAM,mDAAmD,CAAC;AAC3D,OAAO,EACL,+BAA+B,EAC/B,0BAA0B,EAC1B,uBAAuB,EACvB,KAAK,0BAA0B,EAC/B,mCAAmC,EACnC,KAAK,gCAAgC,EACrC,KAAK,iBAAiB,EACtB,KAAK,iBAAiB,GACvB,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,oBAAoB,EACpB,4BAA4B,EAC5B,iBAAiB,EACjB,kBAAkB,EAClB,iBAAiB,EACjB,kBAAkB,EAClB,KAAK,qBAAqB,EAC1B,KAAK,mBAAmB,EACxB,KAAK,eAAe,EACpB,KAAK,iBAAiB,EACtB,KAAK,mBAAmB,EACxB,KAAK,cAAc,EACnB,KAAK,kBAAkB,EACvB,KAAK,qBAAqB,GAC3B,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;AACrD,OAAO,EACL,6BAA6B,EAC7B,wBAAwB,EACxB,KAAK,8BAA8B,EACnC,gBAAgB,EAChB,KAAK,eAAe,EACpB,KAAK,oBAAoB,EACzB,KAAK,cAAc,GACpB,MAAM,cAAc,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/sveltekit/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EACL,KAAK,oCAAoC,EACzC,4BAA4B,EAC5B,cAAc,EACd,0BAA0B,EAC1B,kBAAkB,EAClB,KAAK,0BAA0B,EAC/B,KAAK,wBAAwB,EAC7B,KAAK,iBAAiB,EACtB,KAAK,yBAAyB,EAC9B,KAAK,iCAAiC,EACtC,KAAK,uBAAuB,EAC5B,KAAK,iBAAiB,EACtB,KAAK,sBAAsB,EAC3B,KAAK,8BAA8B,EACnC,KAAK,wBAAwB,EAC7B,KAAK,yBAAyB,EAC9B,KAAK,oBAAoB,EACzB,KAAK,2BAA2B,EAChC,KAAK,iBAAiB,EACtB,KAAK,WAAW,EAChB,KAAK,kBAAkB,GACxB,MAAM,mDAAmD,CAAC;AAC3D,OAAO,EACL,+BAA+B,EAC/B,0BAA0B,EAC1B,uBAAuB,EACvB,KAAK,0BAA0B,EAC/B,mCAAmC,EACnC,KAAK,gCAAgC,EACrC,KAAK,iBAAiB,EACtB,KAAK,iBAAiB,GACvB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,+BAA+B,EAAE,MAAM,4BAA4B,CAAC;AAC7E,OAAO,EACL,oBAAoB,EACpB,4BAA4B,EAC5B,iBAAiB,EACjB,kBAAkB,EAClB,iBAAiB,EACjB,kBAAkB,EAClB,KAAK,qBAAqB,EAC1B,KAAK,mBAAmB,EACxB,KAAK,eAAe,EACpB,KAAK,iBAAiB,EACtB,KAAK,mBAAmB,EACxB,KAAK,cAAc,EACnB,KAAK,kBAAkB,EACvB,KAAK,qBAAqB,GAC3B,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;AACrD,OAAO,EACL,6BAA6B,EAC7B,wBAAwB,EACxB,KAAK,8BAA8B,EACnC,gBAAgB,EAChB,KAAK,eAAe,EACpB,KAAK,oBAAoB,EACzB,KAAK,cAAc,GACpB,MAAM,cAAc,CAAC"}
@@ -0,0 +1,10 @@
1
+ import type { SmrtSvelteKitRuntime } from '@happyvertical/smrt-app-runtime/sveltekit-runtime';
2
+ import type { RequestEvent } from '@sveltejs/kit';
3
+ type CredentialEvent = Pick<RequestEvent, 'request' | 'url' | 'getClientAddress' | 'cookies'>;
4
+ /**
5
+ * Opt-in POST endpoint for the local desktop owner. Mount only on a direct
6
+ * loopback listener, with no proxy-derived client address or origin headers.
7
+ */
8
+ export declare function createLocalMcpCredentialHandler(runtime: Pick<SmrtSvelteKitRuntime, 'resolvedRuntime' | 'localRuntime' | 'sessionCookie'>): (event: CredentialEvent) => Promise<Response>;
9
+ export {};
10
+ //# sourceMappingURL=local-mcp-credentials.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"local-mcp-credentials.d.ts","sourceRoot":"","sources":["../../src/sveltekit/local-mcp-credentials.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,mDAAmD,CAAC;AAC9F,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAKlD,KAAK,eAAe,GAAG,IAAI,CACzB,YAAY,EACZ,SAAS,GAAG,KAAK,GAAG,kBAAkB,GAAG,SAAS,CACnD,CAAC;AA6CF;;;GAGG;AACH,wBAAgB,+BAA+B,CAC7C,OAAO,EAAE,IAAI,CACX,oBAAoB,EACpB,iBAAiB,GAAG,cAAc,GAAG,eAAe,CACrD,GACA,CAAC,KAAK,EAAE,eAAe,KAAK,OAAO,CAAC,QAAQ,CAAC,CAyG/C"}
@@ -1 +1 @@
1
- {"version":3,"file":"owner-setup.d.ts","sourceRoot":"","sources":["../../src/sveltekit/owner-setup.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"owner-setup.d.ts","sourceRoot":"","sources":["../../src/sveltekit/owner-setup.ts"],"names":[],"mappings":"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"}
@@ -1,11 +1,11 @@
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-DP7SxcSY.js";
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-DG72tyzB.js";
2
2
  import { n as normalizeTenantSelection, t as createSubdomainTenantSelector } from "./chunks/tenancy-BzdIxH2M.js";
3
3
  import { loadConfig, resolveEffectiveApplicationRuntime } from "@happyvertical/smrt-config";
4
+ import { ObjectRegistry } from "@happyvertical/smrt-core";
4
5
  import { OidcIdentityCollection } from "@happyvertical/smrt-profiles";
5
6
  import { enableTenancy, getCurrentTenant, isTenancyEnabled, withSystemContext } from "@happyvertical/smrt-tenancy";
6
7
  import { MembershipCollection, PermissionResolver, SessionService, UserCollection, UserStatus, getCurrentSessionPermissionContext, getRequestScopedDatabase, withPrincipalPermissionContext, withSessionPermissionContext } from "@happyvertical/smrt-users";
7
8
  import { getDatabase } from "@happyvertical/sql";
8
- import { ObjectRegistry } from "@happyvertical/smrt-core";
9
9
  //#region src/sveltekit/runtime.ts
10
10
  var DEFAULT_SESSION_TTL_SECONDS = 10080 * 60;
11
11
  function createSmrtSvelteKitRuntime(options = {}) {
package/dist/sveltekit.js CHANGED
@@ -179,7 +179,7 @@ function createOwnerSetupPage(runtime, options = {}) {
179
179
  ipAddress: event.getClientAddress()
180
180
  });
181
181
  } catch (error) {
182
- if (error instanceof LocalRuntimeError && error.code === "owner_tenant_conflict") return failure(409, "setup_conflict");
182
+ if (error instanceof LocalRuntimeError && (error.code === "owner_tenant_conflict" || error.code === "owner_identity_conflict")) return failure(409, "setup_conflict");
183
183
  return failure(400, "setup_invalid");
184
184
  }
185
185
  if (options.removeOnboardingHandoff !== false && runtime.applicationStateRoot) try {
@@ -226,6 +226,101 @@ function isLoopbackHostname(hostname) {
226
226
  return host === "localhost" || isLoopbackAddress(host);
227
227
  }
228
228
  //#endregion
229
+ //#region src/sveltekit/local-mcp-credentials.ts
230
+ var MAX_REQUEST_BYTES = 12 * 1024;
231
+ function reply(status, body) {
232
+ return Response.json(body, {
233
+ status,
234
+ headers: {
235
+ "Cache-Control": "no-store",
236
+ "X-Content-Type-Options": "nosniff",
237
+ "Referrer-Policy": "no-referrer",
238
+ ...status === 405 ? { Allow: "POST" } : {}
239
+ }
240
+ });
241
+ }
242
+ async function readPayload(request) {
243
+ const reader = request.body?.getReader();
244
+ if (!reader) return null;
245
+ const decoder = new TextDecoder("utf-8", { fatal: true });
246
+ let bytes = 0;
247
+ let json = "";
248
+ try {
249
+ for (;;) {
250
+ const chunk = await reader.read();
251
+ if (chunk.done) break;
252
+ bytes += chunk.value.byteLength;
253
+ if (bytes > MAX_REQUEST_BYTES) {
254
+ reader.cancel().catch(() => {});
255
+ return null;
256
+ }
257
+ json += decoder.decode(chunk.value, { stream: true });
258
+ }
259
+ const data = JSON.parse(json + decoder.decode());
260
+ if (data === null || typeof data !== "object" || Array.isArray(data)) return null;
261
+ return data;
262
+ } catch {
263
+ return null;
264
+ } finally {
265
+ reader.releaseLock();
266
+ }
267
+ }
268
+ function createLocalMcpCredentialHandler(runtime) {
269
+ return async (event) => {
270
+ try {
271
+ const { request, url } = event;
272
+ if (request.method !== "POST") return reply(405, { code: "method_not_allowed" });
273
+ const fetchSite = request.headers.get("sec-fetch-site");
274
+ if (!isLoopbackRequest(event) || url.protocol !== "http:" && url.protocol !== "https:" || request.headers.get("host") !== url.host || request.headers.get("origin") !== url.origin || fetchSite !== null && fetchSite !== "same-origin") return reply(403, { code: "forbidden" });
275
+ if ((await runtime.resolvedRuntime()).profile !== "local") return reply(404, { code: "unavailable" });
276
+ const sessionId = event.cookies.get(runtime.sessionCookie.name);
277
+ if (!sessionId) return reply(403, { code: "forbidden" });
278
+ const local = await runtime.localRuntime();
279
+ const store = local.mcpTokens;
280
+ if (!store?.manageDesktopCredential) return reply(404, { code: "unavailable" });
281
+ const session = await local.restoreSession(sessionId);
282
+ if (!session?.user.id || !session.tenantId || !session.membership?.isActive() || session.parent || session.permissionCeiling !== null || ![
283
+ "local-bootstrap",
284
+ "password",
285
+ "passkey"
286
+ ].includes(session.authMethod ?? "")) return reply(403, { code: "forbidden" });
287
+ if ((request.headers.get("content-type")?.split(";", 1)[0])?.trim().toLowerCase() !== "application/json") return reply(415, { code: "unsupported_media_type" });
288
+ const data = await readPayload(request);
289
+ if (!data || typeof data.id !== "string") return reply(400, { code: "invalid_request" });
290
+ const actor = {
291
+ userId: session.user.id,
292
+ tenantId: session.tenantId,
293
+ permissions: session.permissions
294
+ };
295
+ if (data.action === "revoke" && Object.keys(data).length === 2) return await store.manageDesktopCredential(actor, {
296
+ action: "revoke",
297
+ id: data.id
298
+ }) === "revoked" ? reply(200, { status: "revoked" }) : reply(409, { code: "slot_unavailable" });
299
+ if (data.action !== "put" || Object.keys(data).length !== 4 || !Array.isArray(data.scopes) || typeof data.expiresInSeconds !== "number") return reply(400, { code: "invalid_request" });
300
+ const issued = await store.manageDesktopCredential(actor, {
301
+ action: "put",
302
+ id: data.id,
303
+ scopes: data.scopes,
304
+ expiresInSeconds: data.expiresInSeconds
305
+ });
306
+ if (typeof issued === "string") return reply(409, { code: "slot_unavailable" });
307
+ return reply(200, {
308
+ id: data.id,
309
+ token: issued.token,
310
+ scopes: issued.scopes,
311
+ expiresAt: issued.expiresAt
312
+ });
313
+ } catch (error) {
314
+ if (error instanceof LocalRuntimeError) {
315
+ if (error.code === "owner_unavailable") return reply(403, { code: "forbidden" });
316
+ if (error.code === "invalid_scope") return reply(400, { code: "invalid_scope" });
317
+ if (error.code === "invalid_configuration") return reply(400, { code: "invalid_request" });
318
+ }
319
+ return reply(500, { code: "credential_operation_failed" });
320
+ }
321
+ };
322
+ }
323
+ //#endregion
229
324
  //#region src/sveltekit/sign-out.ts
230
325
  function isSameOriginRequest(request, url) {
231
326
  const site = request.headers.get("sec-fetch-site");
@@ -260,6 +355,6 @@ function createSignOutHandler(runtime) {
260
355
  };
261
356
  }
262
357
  //#endregion
263
- export { DEFAULT_OWNER_SETUP_MESSAGES, OWNER_SETUP_FIELDS, RUNTIME_DIAGNOSTICS_READ_PERMISSION, authorizedTenantLocalsHandle, composeHandles, createOwnerSetupPage, createRuntimeDiagnosticsHandler, createRuntimeHealthHandler, createSessionLayoutLoad, createSignOutHandler, createSmrtSvelteKitRuntime, createSubdomainTenantSelector, defaultWriterLease, isLoopbackAddress, isLoopbackHostname, isLoopbackRequest, normalizeTenantSelection, selectTenantSlug };
358
+ export { DEFAULT_OWNER_SETUP_MESSAGES, OWNER_SETUP_FIELDS, RUNTIME_DIAGNOSTICS_READ_PERMISSION, authorizedTenantLocalsHandle, composeHandles, createLocalMcpCredentialHandler, createOwnerSetupPage, createRuntimeDiagnosticsHandler, createRuntimeHealthHandler, createSessionLayoutLoad, createSignOutHandler, createSmrtSvelteKitRuntime, createSubdomainTenantSelector, defaultWriterLease, isLoopbackAddress, isLoopbackHostname, isLoopbackRequest, normalizeTenantSelection, selectTenantSlug };
264
359
 
265
360
  //# sourceMappingURL=sveltekit.js.map