@palbase/backend 4.0.0 → 5.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-EG7TTYHY.js → chunk-2N4YNN6F.js} +1 -1
- package/dist/{chunk-EG7TTYHY.js.map → chunk-2N4YNN6F.js.map} +1 -1
- package/dist/db/index.cjs.map +1 -1
- package/dist/db/index.d.cts +2 -2
- package/dist/db/index.d.ts +2 -2
- package/dist/db/index.js +1 -1
- package/dist/{endpoint-2d_DpASt.d.cts → endpoint-BEHjfvFH.d.cts} +7 -1
- package/dist/{endpoint-2d_DpASt.d.ts → endpoint-BEHjfvFH.d.ts} +7 -1
- package/dist/{index-DZW9CjiY.d.ts → index-BTVdhfsb.d.ts} +9 -3
- package/dist/{index-DzRFS3Tl.d.cts → index-mr3Co63T.d.cts} +9 -3
- package/dist/index.cjs +7 -22
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +5 -17
- package/dist/index.d.ts +5 -17
- package/dist/index.js +8 -22
- package/dist/index.js.map +1 -1
- package/dist/test/index.d.cts +1 -1
- package/dist/test/index.d.ts +1 -1
- package/docs/README.md +201 -3
- package/docs/endpoints.md +20 -8
- package/docs/getting-started.md +45 -11
- package/docs/llms-full.txt +349 -103
- package/docs/llms.txt +1 -1
- package/docs/migrations.md +75 -73
- package/docs/routing.md +6 -6
- package/docs/schema.md +3 -2
- package/docs/services.md +2 -3
- package/package.json +1 -1
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/runtime.ts","../src/db/policy.ts","../src/db/schema.ts","../src/db/extensions.ts","../src/db/columns.ts","../src/db/typed-db.ts","../src/db/env-gen.ts","../src/decorators/controller.ts","../src/decorators/registry.ts","../src/decorators/methods.ts","../src/decorators/params.ts","../src/middleware.ts","../src/errors.ts","../src/worker.ts","../src/job.ts","../src/webhook.ts","../src/resource.ts","../src/hooks.ts"],"sourcesContent":["export type {\n PBRequest,\n ClientInfo,\n RateLimitConfig,\n DBClient,\n DBOps,\n TxClient,\n FileContext,\n QueueClient,\n Logger,\n CacheClient,\n PalbaseDocsClient,\n PalbaseCollectionRef,\n PalbaseDocumentRef,\n PalbaseDocumentSnapshot,\n PalbaseQuerySnapshot,\n PalbaseWhereOperator,\n PalbaseResult,\n Middleware,\n ErrorDef,\n ErrorMap,\n ErrorThrowers,\n} from \"./endpoint.js\";\nexport {\n Database,\n Documents,\n Storage,\n Cache,\n Queue,\n Log,\n Notifications,\n Flags,\n __setRuntime,\n __runWithRuntime,\n __requestALS,\n __getRuntime,\n} from \"./runtime.js\";\nexport type { RuntimeServices } from \"./runtime.js\";\nexport type {\n PalbaseAuthClient,\n PalbaseStorageClient,\n PalbaseBucketClient,\n PalbaseRealtimeClient,\n PalbaseRealtimeChannel,\n PalbaseRealtimeMessage,\n PalbaseFunctionsClient,\n PalbaseInvokeOptions,\n PalbaseFlagsClient,\n PalbaseFlagContext,\n PalbaseFlagVariant,\n PalbaseFlag,\n PalbaseNotificationsClient,\n PalbasePushClient,\n PalbaseEmailClient,\n PalbaseSmsClient,\n PalbaseInboxClient,\n PalbasePreferencesClient,\n PalbaseAnalyticsClient,\n PalbaseAnalyticsQueryNamespace,\n PalbaseAnalyticsManagementNamespace,\n PalbaseLinksClient,\n PalbaseCmsClient,\n // Shared local types\n PalbaseUser,\n PalbaseSession,\n PalbaseDeviceInfo,\n PalbaseAttestAndroidParams,\n PalbaseAttestAndroidResult,\n PalbaseAttestiOSParams,\n PalbaseAttestiOSResult,\n PalbaseBindDeviceParams,\n PalbaseVerifyRequestSignatureParams,\n PalbaseFileObject,\n PalbaseSignedUrlResponse,\n PalbasePublicUrlResponse,\n PalbaseUploadOptions,\n PalbaseTransformOptions,\n PalbaseListOptions,\n PalbasePushSendParams,\n PalbasePushSendResponse,\n PalbaseEmailSendParams,\n PalbaseEmailSendResponse,\n PalbaseSmsSendParams,\n PalbaseSmsSendResponse,\n PalbaseInboxSendParams,\n PalbaseInboxSendResponse,\n PalbaseInboxMessage,\n PalbaseInboxListOptions,\n PalbaseInboxListResult,\n PalbasePreferences,\n PalbaseRegisterDeviceParams,\n PalbaseDeviceTokenView,\n PalbaseMultiChannelResponse,\n PalbaseAnalyticsProperties,\n PalbaseIdentifyTraits,\n PalbaseCountQueryInput,\n PalbaseCountResult,\n PalbaseEventsQueryInput,\n PalbaseEventsResult,\n PalbaseUsersQueryInput,\n PalbaseUsersResult,\n PalbaseFunnelQueryInput,\n PalbaseFunnelResult,\n PalbaseRetentionQueryInput,\n PalbaseRetentionResult,\n PalbaseCohortQueryInput,\n PalbaseCohortResult,\n PalbaseOverviewResult,\n PalbaseEventNamesResult,\n PalbaseUserDetailResult,\n PalbaseCreateLinkParams,\n PalbaseUpdateLinkParams,\n PalbaseLink,\n PalbaseLinkDetails,\n PalbaseLinkAnalytics,\n PalbaseQrCodeOptions,\n PalbaseMatchParams,\n PalbaseInitialLink,\n PalbaseListLinksOptions,\n PalbaseListLinksResult,\n PalbaseCmsFindOptions,\n PalbaseCmsFindOneOptions,\n} from \"./clients.js\";\nexport { defineSchema } from \"./db/schema.js\";\nexport type { SchemaDef, TableDef, TableInput, ColumnMap, SchemaInput } from \"./db/schema.js\";\nexport { policy, PolicyBuilder } from \"./db/policy.js\";\nexport type { PolicyDef, PolicyCommand, PolicyMode } from \"./db/policy.js\";\nexport { PALBASE_EXTENSIONS, EXTENSION_DEPENDENCIES, isPalbaseExtension } from \"./db/extensions.js\";\nexport type { PalbaseExtension } from \"./db/extensions.js\";\nexport { uuid, text, integer, boolean, timestamp, jsonb, enumType } from \"./db/columns.js\";\nexport type { ColumnBuilder, ColumnDef, ColumnType, OnDeleteAction } from \"./db/columns.js\";\nexport { makeTypedDB } from \"./db/typed-db.js\";\nexport type {\n TypedDB,\n TypedTx,\n TypedTable,\n InsertShape,\n RowShape,\n EnvTypedDatabase,\n EnvServiceDatabase,\n EnvTypedTx,\n EnvTypedTable,\n EnvTables,\n} from \"./db/typed-db.js\";\nexport type { Tables, TableTypes } from \"./db/env.js\";\nexport { makeEnvDts } from \"./db/env-gen.js\";\n// Class-controller decorator model (replaces defineController/defineHandler/route).\nexport { Controller } from \"./decorators/controller.js\";\nexport type { ControllerOptions } from \"./decorators/controller.js\";\nexport { Get, Post, Put, Patch, Delete, Returns } from \"./decorators/methods.js\";\nexport {\n Body,\n Query,\n Headers,\n Param,\n User,\n OptionalUser,\n Client,\n RequestId,\n TraceId,\n Req,\n} from \"./decorators/params.js\";\nexport type { RouteOptions, HttpMethodUpper } from \"./decorators/registry.js\";\nexport { defineMiddleware } from \"./middleware.js\";\nexport type { MiddlewareContext, MiddlewareHandler } from \"./middleware.js\";\n// The authenticated-user TYPE is exported as `UserT` (not `User`) because the\n// value name `User` is the @User() parameter decorator (exported above). A\n// controller annotates `@User() user: UserT` — decorator for the value\n// position, `UserT` for the type. (NestJS-style: same name as the decorator\n// would collide in the value+type namespaces.)\nexport type { User as UserT, HttpMethod, AuthConfig } from \"./types.js\";\nexport {\n HttpError,\n PalError,\n BadRequest,\n Unauthorized,\n Forbidden,\n NotFound,\n Conflict,\n TooManyRequests,\n} from \"./errors.js\";\nexport { defineWorker } from \"./worker.js\";\nexport type {\n WorkerConfig,\n ResolvedWorkerConfig,\n WorkerMeta,\n BackoffStrategy,\n} from \"./worker.js\";\nexport { defineJob } from \"./job.js\";\nexport type { JobConfig, ResolvedJobConfig, JobMeta } from \"./job.js\";\nexport { defineWebhook } from \"./webhook.js\";\nexport type {\n WebhookProvider,\n WebhookMeta,\n EnvSecretRef,\n ProviderWebhookConfig,\n CustomWebhookConfig,\n ResolvedProviderWebhook,\n ResolvedCustomWebhook,\n ResolvedWebhookConfig,\n WebhookEventHandler,\n WebhookRequest,\n ProviderEventMap,\n} from \"./webhook.js\";\nexport {\n Resource,\n __registerResource,\n __runResourceBoot,\n __shutdownResources,\n} from \"./resource.js\";\nexport type { ResourceEnv } from \"./resource.js\";\nexport { auth, storage, documents } from \"./hooks.js\";\nexport type {\n HookMeta,\n HookHandler,\n ResolvedHook,\n UserCreatedEvent,\n SignInEvent,\n SignOutEvent,\n PasswordResetEvent,\n FileUploadedEvent,\n FileDeletedEvent,\n DocumentCreatedEvent,\n DocumentUpdatedEvent,\n DocumentDeletedEvent,\n} from \"./hooks.js\";\nexport { z } from \"zod\";\n","/**\n * runtime.ts — request-scoped service singletons.\n *\n * The backend SDK no longer threads a `ctx` god-object through every handler.\n * Instead, controller methods import PascalCase service singletons directly:\n *\n * import { Controller, Post, Body, Database } from \"@palbase/backend\";\n *\n * \\@Controller(\"/todos\")\n * export default class TodosController {\n * \\@Post(\"\") create(\\@Body(CreateTodoBody) body: CreateTodoBody): unknown {\n * return Database.insert(\"todos\", { title: body.title });\n * }\n * }\n *\n * The singletons are thin Proxies. Every property access forwards to the live\n * client for the CURRENT request scope, resolved through {@link __getRuntime}.\n *\n * # Request-scope resolution (persistent app-server)\n *\n * The runtime is a long-running Node process that serves many concurrent\n * requests on one event loop (NOT a fresh subprocess per request). A single\n * module-global slot would let one in-flight request's services bleed into\n * another's. So the services are carried in an {@link AsyncLocalStorage} store\n * ({@link __requestALS}) that the runtime sets per request with\n * {@link __runWithRuntime}; every async continuation of that request reads its\n * own store. `__getRuntime` reads the ALS store first; the module-global slot\n * (set by {@link __setRuntime}) is only a fallback for callers that run OUTSIDE\n * an ALS scope (dev-server, unit tests, the legacy single-shot path). Because\n * each `br-<ref>` pod is single-tenant, there is no cross-tenant leakage; the\n * ALS store is what prevents cross-REQUEST leakage within the shared process.\n *\n * The seam that makes `import { Database } from \"@palbase/backend\"` resolve to\n * the runtime-injected client: `@palbase/backend` is marked esbuild-EXTERNAL\n * when the tenant bundle is built, and the package is installed globally in the\n * pod (NODE_PATH=/usr/local/lib/node_modules). So worker.js's\n * `require('@palbase/backend')` and the bundle's `import` resolve to ONE shared\n * module instance — the ALS store and `__setRuntime` slot on that instance are\n * visible to the singletons the bundle imported.\n */\n\nimport { AsyncLocalStorage } from \"node:async_hooks\";\n\nimport type {\n DBClient,\n DBOps,\n TxClient,\n CacheClient,\n QueueClient,\n Logger,\n PalbaseDocsClient,\n} from \"./endpoint.js\";\nimport type {\n PalbaseStorageClient,\n PalbaseNotificationsClient,\n PalbaseFlagsClient,\n} from \"./clients.js\";\nimport type {\n EnvTypedDatabase,\n EnvServiceDatabase,\n EnvTypedTx,\n EnvTables,\n} from \"./db/typed-db.js\";\n\n/** The set of live clients the runtime injects per request scope.\n *\n * EXCLUDED on purpose: Realtime, Functions, CMS, Links, Analytics, Auth. They\n * are not exposed as backend handler singletons (auth lives on the client SDK;\n * the rest are out of scope for backend endpoints). */\nexport interface RuntimeServices {\n Database: DBClient;\n Documents: PalbaseDocsClient;\n Storage: PalbaseStorageClient;\n Cache: CacheClient;\n Queue: QueueClient;\n Log: Logger;\n Notifications: PalbaseNotificationsClient;\n Flags: PalbaseFlagsClient;\n}\n\n/**\n * Per-request store. The persistent runtime runs each request inside\n * {@link __runWithRuntime}, so every async continuation of that request reads\n * its OWN `runtime` (and any other request-scoped fields the runtime adds).\n *\n * Exported with a `__` prefix so the runtime (worker.js) shares the SAME ALS\n * instance across the one module instance — two ALS instances would silently\n * not see each other's stores. NOT part of the public author-facing API.\n */\nexport const __requestALS = new AsyncLocalStorage<{ runtime: RuntimeServices }>();\n\n/** Process-global fallback slot. Used only OUTSIDE an ALS scope (dev-server,\n * unit tests, legacy single-shot worker). Inside the persistent server every\n * request runs in {@link __requestALS}, which takes precedence. */\nlet runtime: RuntimeServices | null = null;\n\n/** Install the live clients in the process-global fallback slot.\n *\n * Persistent-server requests should use {@link __runWithRuntime} instead; this\n * remains for dev-server / tests / the legacy single-shot path that run without\n * an ALS scope. NOT part of the public author-facing API. */\nexport function __setRuntime(services: RuntimeServices): void {\n runtime = services;\n}\n\n/** Run `fn` with `services` bound as the request-scoped runtime.\n *\n * The persistent worker calls this once per request so concurrent requests\n * never share a services slot. NOT part of the public author-facing API. */\nexport function __runWithRuntime<T>(services: RuntimeServices, fn: () => T): T {\n return __requestALS.run({ runtime: services }, fn);\n}\n\n/** Read the live clients, throwing if accessed outside a request scope.\n *\n * Resolves the ALS store first (persistent server, per-request), then the\n * process-global fallback (dev-server / tests). NOT part of the public\n * author-facing API — used by the runtime and the singleton Proxies. */\nexport function __getRuntime(): RuntimeServices {\n const scoped = __requestALS.getStore();\n if (scoped) return scoped.runtime;\n if (runtime === null) {\n throw new Error(\n \"Palbase services accessed outside a request scope. The Database/Documents/… \" +\n \"singletons are only available inside an endpoint handler (or after the \" +\n \"runtime has called __runWithRuntime / __setRuntime).\",\n );\n }\n return runtime;\n}\n\n/**\n * Build a Proxy singleton that forwards every property access to the live\n * client named `key` on the current runtime.\n *\n * The single `as RuntimeServices[K]` is the only contained cast in the surface:\n * `Reflect.get` on a typed object returns `unknown` for a `string | symbol`\n * key, but `prop` is constrained to keys of the client interface at the call\n * sites (the exported singletons are typed below), so the forward is sound.\n */\nfunction makeServiceProxy<K extends keyof RuntimeServices>(key: K): RuntimeServices[K] {\n const handler: ProxyHandler<RuntimeServices[K]> = {\n get(_target, prop, receiver) {\n const client = __getRuntime()[key];\n const value = Reflect.get(client as object, prop, receiver) as unknown;\n // Bind methods to their owning client so `this` stays correct when the\n // author destructures or calls `Database.query(...)`.\n return typeof value === \"function\" ? value.bind(client) : value;\n },\n };\n // The Proxy target is irrelevant (all access goes through `get`); the cast\n // names the surface type the singleton presents to authors.\n return new Proxy({} as RuntimeServices[K], handler);\n}\n\n/**\n * Build the `.tables` accessor for an op-bearing client (the top-level\n * `Database` or a transaction-scoped `tx`). Each `tables.<name>` access\n * returns a small object that forwards the five CRUD ops to the underlying\n * client using `name` as the string table identifier. The shapes are typed\n * against the generated `palbase-env.d.ts` (`EnvTables`); at runtime they are\n * plain string-keyed calls, so no schema value is needed here.\n *\n * Returns `EnvTables` — TS cannot infer the mapped type through the Proxy, so\n * a single structural narrowing names the surface (the proxy returns a\n * correctly-shaped accessor for whatever string member is read).\n */\nfunction makeTablesAccessor(ops: () => TxClient): EnvTables {\n const tablesProxy = new Proxy(\n {},\n {\n get(_t, prop: string | symbol) {\n if (typeof prop !== \"string\") return undefined;\n const name = prop;\n return {\n insert: (data: Record<string, unknown>) => ops().insert(name, data),\n update: (id: string, data: Record<string, unknown>) => ops().update(name, id, data),\n delete: (id: string) => ops().delete(name, id),\n findById: (id: string) => ops().findById(name, id),\n findMany: (query?: Record<string, unknown>) => ops().findMany(name, query),\n };\n },\n },\n );\n return tablesProxy as EnvTables;\n}\n\n/** The raw string-keyed `DBClient` for the current request scope. */\nconst rawDatabase: DBClient = makeServiceProxy(\"Database\");\n\n/**\n * Wrap a raw `DBClient` into the typed `{ ...ops, tables, transaction }`\n * surface. The five string ops forward straight through; `tables` is the\n * env-typed accessor; `transaction` yields typed tables. Reused for both the\n * default (RLS-enforced) `Database` and the `asService()` sibling — each is\n * fed its own raw client (the default proxy vs `rawDatabase.asService()`).\n *\n * The `satisfies` pins the op surface so a missing/renamed op is a compile\n * error; the assembled object carries `tables`/`transaction` alongside.\n */\nfunction makeTypedSurface(raw: Omit<DBClient, \"asService\">): EnvServiceDatabase {\n const ops = {\n query: (sql: string, params?: unknown[]) => raw.query(sql, params),\n insert: (table: string, data: Record<string, unknown>) => raw.insert(table, data),\n update: (table: string, id: string, data: Record<string, unknown>) =>\n raw.update(table, id, data),\n delete: (table: string, id: string) => raw.delete(table, id),\n findById: (table: string, id: string) => raw.findById(table, id),\n findMany: (table: string, query?: Record<string, unknown>) => raw.findMany(table, query),\n } satisfies DBOps;\n return Object.assign(ops, {\n tables: makeTablesAccessor(() => raw),\n transaction<T>(fn: (tx: EnvTypedTx) => Promise<T>): Promise<T> {\n return raw.transaction((rawTx) => fn({ tables: makeTablesAccessor(() => rawTx) }));\n },\n });\n}\n\n/**\n * The project's own Postgres (pgx, schema `env_<envId>`).\n *\n * Typed by default: `Database.tables.<name>.insert({...})` is typed against\n * the project's generated `palbase-env.d.ts` with NO import and NO generic.\n * The raw string ops (`query`/`insert`/`update`/`delete`/`findById`/`findMany`)\n * are also available for dynamic table names and read-only SQL.\n *\n * RLS is enforced by default (the runtime runs each op as `authenticated` with\n * the verified user's claims). To bypass RLS, call `Database.asService()` —\n * explicit and greppable — which runs as the `service_role` (BYPASSRLS).\n *\n * @example\n * import { Database } from \"@palbase/backend\";\n *\n * const todo = await Database.tables.todos.insert({ title: req.input.title });\n * todo.id; // string ✓\n * const rows = await Database.query(\"SELECT id FROM todos WHERE done = $1\", [false]);\n * const all = await Database.asService().tables.todos.findMany({}); // RLS bypass\n */\nexport const Database: EnvTypedDatabase = Object.assign(makeTypedSurface(rawDatabase), {\n /**\n * Lazily resolve the runtime's service-role sibling on each call. We do NOT\n * cache it: `rawDatabase.asService()` reads the CURRENT request scope through\n * the runtime proxy, and the per-request runtime injects a service client\n * bound to that request's identity headers — caching would leak one request's\n * sibling into another concurrent request.\n */\n asService(): EnvServiceDatabase {\n return makeTypedSurface(rawDatabase.asService());\n },\n});\n\n/** Firestore-like document client (PalDocs). */\nexport const Documents: PalbaseDocsClient = makeServiceProxy(\"Documents\");\n\n/** Object storage client (buckets, signed URLs). */\nexport const Storage: PalbaseStorageClient = makeServiceProxy(\"Storage\");\n\n/** JSON-typed cache (get/set/incr/getOrSet). */\nexport const Cache: CacheClient = makeServiceProxy(\"Cache\");\n\n/** Background job queue. */\nexport const Queue: QueueClient = makeServiceProxy(\"Queue\");\n\n/** Structured logger. */\nexport const Log: Logger = makeServiceProxy(\"Log\");\n\n/** Push / email / SMS / in-app notifications. */\nexport const Notifications: PalbaseNotificationsClient = makeServiceProxy(\"Notifications\");\n\n/** Feature flags. */\nexport const Flags: PalbaseFlagsClient = makeServiceProxy(\"Flags\");\n","/**\n * policy.ts — the RLS policy authoring DSL.\n *\n * `policy(name)` returns a fluent builder that mirrors the `ColumnBuilder`\n * style in columns.ts: each chainable method mutates the underlying\n * definition and returns the builder so calls compose. The terminal value is\n * a plain {@link PolicyDef} — the exact JSON shape the runtime's\n * `schema_extract.js` reads off the bundled module and the Go side parses into\n * `PolicyJSON` (CONTRACT-POLICY).\n *\n * @example\n * import { policy } from \"@palbase/backend\";\n *\n * policy(\"owner_select\")\n * .for(\"select\")\n * .to(\"authenticated\")\n * .using(\"owner = (select auth.uid())\");\n */\n\n/** The SQL command a policy applies to. `\"all\"` covers SELECT/INSERT/UPDATE/DELETE. */\nexport type PolicyCommand = \"all\" | \"select\" | \"insert\" | \"update\" | \"delete\";\n\n/** Whether a policy is permissive (OR-combined, the default) or restrictive\n * (AND-combined). Mirrors Postgres `CREATE POLICY ... AS PERMISSIVE|RESTRICTIVE`. */\nexport type PolicyMode = \"permissive\" | \"restrictive\";\n\n/**\n * The compiled, serializable policy definition — the EXACT shape consumed by\n * `schema_extract.js` → Go `PolicyJSON` (CONTRACT-POLICY).\n *\n * - `roles`: the DB roles this policy applies to (`TO` clause). An empty array\n * means the policy applies to PUBLIC (all roles) — the Postgres default.\n * - `using`: the `USING (...)` row-visibility expression, or `null` when none.\n * - `withCheck`: the `WITH CHECK (...)` write-validation expression, or `null`.\n * - `permissive`: `true` for `AS PERMISSIVE` (default), `false` for restrictive.\n */\nexport interface PolicyDef {\n name: string;\n command: PolicyCommand;\n roles: string[];\n using: string | null;\n withCheck: string | null;\n permissive: boolean;\n}\n\n/**\n * Fluent RLS policy builder.\n *\n * Defaults (documented, applied at construction):\n * - `command`: `\"all\"` — applies to every SQL command unless `.for(...)` narrows it.\n * - `roles`: `[\"authenticated\"]` — the common case is \"rule applies to signed-in\n * users\". Call `.to(...)` to override; pass `.to()` with no roles (or never\n * call it after a reset) to target PUBLIC.\n * - `using` / `withCheck`: `null` — no row filter / write check until set.\n * - `permissive`: `true` — `AS PERMISSIVE` (policies OR together).\n *\n * Each method mutates `_def` in place and returns `this`, so the chain is a\n * single builder instance (no per-call allocation, like a tagged-template\n * compile target). The terminal `PolicyDef` is read directly off `_def` by\n * `schema_extract.js`.\n */\nexport class PolicyBuilder {\n readonly _def: PolicyDef;\n\n constructor(name: string) {\n this._def = {\n name,\n command: \"all\",\n roles: [\"authenticated\"],\n using: null,\n withCheck: null,\n permissive: true,\n };\n }\n\n /** Restrict the policy to a single SQL command (default `\"all\"`). */\n for(command: PolicyCommand): this {\n this._def.command = command;\n return this;\n }\n\n /**\n * Set the DB roles the policy applies to (the `TO` clause), replacing any\n * previously-set roles. Call with no arguments to target PUBLIC (all roles).\n *\n * @example\n * policy(\"p\").to(\"authenticated\")\n * policy(\"p\").to(\"authenticated\", \"service_role\")\n * policy(\"p\").to() // PUBLIC\n */\n to(...roles: string[]): this {\n this._def.roles = roles;\n return this;\n }\n\n /** Set the `USING (...)` row-visibility expression (raw SQL). */\n using(sqlExpr: string): this {\n this._def.using = sqlExpr;\n return this;\n }\n\n /** Set the `WITH CHECK (...)` write-validation expression (raw SQL). */\n withCheck(sqlExpr: string): this {\n this._def.withCheck = sqlExpr;\n return this;\n }\n\n /** Set the policy mode: `\"permissive\"` (default, OR-combined) or\n * `\"restrictive\"` (AND-combined). */\n as(mode: PolicyMode): this {\n this._def.permissive = mode === \"permissive\";\n return this;\n }\n}\n\n/**\n * Start authoring an RLS policy. Returns a {@link PolicyBuilder}; the resulting\n * `PolicyBuilder` is accepted directly in a table's `policies: [...]` array\n * (its `_def` is read at schema-extract time).\n *\n * @param name The policy name. Palbase reconciliation keys policies by\n * `(table, name)`, so names must be unique per table.\n */\nexport function policy(name: string): PolicyBuilder {\n return new PolicyBuilder(name);\n}\n","import type { ColumnBuilder } from \"./columns.js\";\nimport { PolicyBuilder } from \"./policy.js\";\nimport type { PolicyDef } from \"./policy.js\";\nimport type { PalbaseExtension } from \"./extensions.js\";\n\n/**\n * A map of column builders keyed by column name — the value you write under\n * the `columns` key of `defineSchema({ tables: { <name>: { columns } } })`.\n *\n * The default `Record<string, ColumnBuilder>` keeps bare references compiling\n * without a type argument.\n */\nexport type ColumnMap = Record<string, ColumnBuilder>;\n\n/**\n * The author-facing value written under each table key:\n * `{ columns, rls?, policies? }`.\n *\n * - `columns`: the column map (required).\n * - `rls`: enable + FORCE row-level security on this table. Implied when\n * `policies` is non-empty; set it explicitly to enable RLS with no policies\n * yet (deny-all — useful only as an intermediate step).\n * - `policies`: the RLS policies for this table, authored with `policy(name)`.\n * Each entry may be a {@link PolicyBuilder} (the normal `policy(...)` chain)\n * or a raw {@link PolicyDef} object.\n *\n * The `C` type parameter preserves the precise per-column phantom types so the\n * typed `Database.tables.*` surface keeps inferring insert/row shapes.\n */\nexport interface TableInput<C extends ColumnMap = ColumnMap> {\n columns: C;\n rls?: boolean;\n policies?: (PolicyBuilder | PolicyDef)[];\n}\n\n/**\n * A table definition — the runtime value the Go runtime's `schema_extract.js`\n * reads. It keys tables by `tableDef.name`, reads `tableDef.columns` for the\n * column DDL, and `tableDef.rls` + `tableDef.policies` for RLS.\n *\n * `defineSchema` derives `name` from the object key, so authors never repeat\n * the table name. `rls`/`policies` are always present after normalization\n * (defaulted to `false`/`[]`).\n *\n * The `C` type parameter preserves the precise per-column phantom types so that\n * downstream mapped types (InsertShape, RowShape) can discriminate on them.\n */\nexport interface TableDef<C extends ColumnMap = ColumnMap> {\n name: string;\n columns: C;\n rls: boolean;\n policies: PolicyDef[];\n}\n\n/**\n * A schema definition containing multiple tables, keyed by table name.\n *\n * The `T` type parameter preserves the exact `TableDef<...>` type for each\n * table so that `SchemaDef[\"tables\"][\"rooms\"]` resolves to the precise\n * `TableDef<{ id: ColumnBuilder<'uuid', false, true, never>; ... }>`.\n */\nexport interface SchemaDef<\n T extends Record<string, TableDef> = Record<string, TableDef>,\n> {\n tables: T;\n /** Postgres extensions to install on deploy. Normalized to `[]` when absent. */\n extensions: PalbaseExtension[];\n}\n\n/** The author-facing input to `defineSchema` — a `tables` map whose keys are\n * the table names and whose values are `{ columns, rls?, policies? }`, plus an\n * optional `extensions` allowlist. */\nexport interface SchemaInput<\n T extends Record<string, TableInput> = Record<string, TableInput>,\n> {\n tables: T;\n /**\n * Postgres extensions to enable for this project, e.g. `[\"vector\"]`.\n * Config-as-code: installed by the deploy (CREATE EXTENSION … SCHEMA\n * extensions) with the privileged deploy connection. The type is an\n * allowlist union, so unsupported names fail typecheck.\n */\n extensions?: PalbaseExtension[];\n}\n\n/** Map the author's `{ tables: { <name>: { columns } } }` input to the\n * `{ tables: { <name>: TableDef<columns> } }` runtime/type shape, threading the\n * per-table column map `T[K][\"columns\"]` so column-level inference survives. */\ntype TablesFromInput<T extends Record<string, TableInput>> = {\n [K in keyof T]: TableDef<T[K][\"columns\"]>;\n};\n\n/** Normalize a single `policies` entry into a plain `PolicyDef` (read off a\n * `PolicyBuilder._def`, or passed through when already a `PolicyDef`). */\nfunction toPolicyDef(p: PolicyBuilder | PolicyDef): PolicyDef {\n return p instanceof PolicyBuilder ? p._def : p;\n}\n\n/**\n * Define a schema. The table NAME comes from the object key. Each table value\n * is `{ columns, rls?, policies? }`:\n *\n * export default defineSchema({\n * tables: {\n * todos: {\n * columns: {\n * id: uuid().primaryKey().defaultRandom(),\n * owner: text().notNull(),\n * title: text().notNull(),\n * },\n * rls: true,\n * policies: [\n * policy(\"owner_all\").for(\"all\").to(\"authenticated\")\n * .using(\"owner = (select auth.uid())\")\n * .withCheck(\"owner = (select auth.uid())\"),\n * ],\n * },\n * },\n * });\n *\n * The returned value is\n * `{ tables: { todos: { name, columns, rls, policies } } }` — the exact shape\n * the runtime schema extractor parses. Per-column phantom types are preserved\n * so `Database.tables.todos.insert({...})` stays typed.\n *\n * RLS normalization: `rls` defaults to `false`, `policies` to `[]`. When\n * `policies` is non-empty, `rls` is forced on (ENABLE + FORCE) regardless of\n * the declared `rls` flag — a table with policies must have RLS enabled or the\n * policies would be inert.\n */\nexport function defineSchema<T extends Record<string, TableInput>>(\n input: SchemaInput<T>,\n): SchemaDef<TablesFromInput<T>> {\n const tables = {} as TablesFromInput<T>;\n for (const name of Object.keys(input.tables) as (keyof T)[]) {\n const table = input.tables[name];\n // `noUncheckedIndexedAccess` widens the index access to `… | undefined`,\n // but `name` comes straight from `Object.keys(input.tables)`, so the entry\n // always exists. Guard to narrow without a cast.\n if (table === undefined) continue;\n const policies = (table.policies ?? []).map(toPolicyDef);\n // A table with policies must have RLS enabled, otherwise the policies are\n // inert. Enabling RLS without policies (deny-all) is allowed explicitly.\n const rls = table.rls === true || policies.length > 0;\n tables[name] = {\n name: name as string,\n columns: table.columns,\n rls,\n policies,\n };\n }\n // Dedupe + normalize extensions (order-independent; deploy resolves deps).\n const extensions = [...new Set(input.extensions ?? [])];\n return { tables, extensions };\n}\n","/**\n * Postgres extensions a Palbase project can enable from its schema.\n *\n * Extensions are config-as-code: declare them in `defineSchema({ extensions })`\n * and the deploy installs them (CREATE EXTENSION … SCHEMA extensions) using the\n * deploy path's privileged connection. They are NOT toggled live from Studio —\n * CREATE EXTENSION requires a superuser role that only the deploy path holds.\n *\n * The list is an allowlist (a string-literal union) so editors autocomplete the\n * supported names and a typo fails typecheck. It is intentionally extensible:\n * add a name here (+ confirm the base image ships it) to support more.\n */\nexport const PALBASE_EXTENSIONS = [\n // Search & text\n \"vector\", // pgvector: AI embeddings + vector similarity search (semantic search / RAG).\n // NB: the Postgres extension is named \"vector\", not \"pgvector\" — declare \"vector\".\n \"pg_trgm\", // trigram fuzzy / typo-tolerant text search\n \"unaccent\", // accent-insensitive text search\n \"citext\", // case-insensitive text type\n // Geospatial / location\n \"postgis\", // geospatial types + queries (maps, \"near me\")\n \"cube\", // multi-dimensional cubes (dependency of earthdistance)\n \"earthdistance\", // great-circle distance (needs cube)\n // Data types & structures\n \"hstore\", // key/value pairs in a single column\n \"ltree\", // hierarchical tree-structured labels\n // Scheduling\n \"pg_cron\", // schedule jobs inside the database\n // Crypto / ids (also installed by default; listable for explicitness)\n \"pgcrypto\", // cryptographic functions (hashing, encryption)\n \"uuid-ossp\", // UUID generation functions\n] as const;\n\n/** A Postgres extension supported by Palbase (allowlist union). */\nexport type PalbaseExtension = (typeof PALBASE_EXTENSIONS)[number];\n\n/**\n * Extensions that depend on another extension. The deploy installs\n * dependencies first; declaring `earthdistance` without `cube` still works\n * because the deploy resolves the order, but listing both is clearer.\n */\nexport const EXTENSION_DEPENDENCIES: Partial<Record<PalbaseExtension, PalbaseExtension[]>> = {\n earthdistance: [\"cube\"],\n};\n\n/** Runtime guard: is `name` a supported Palbase extension? */\nexport function isPalbaseExtension(name: string): name is PalbaseExtension {\n return (PALBASE_EXTENSIONS as readonly string[]).includes(name);\n}\n","/** On delete action for foreign key references. */\nexport type OnDeleteAction = 'cascade' | 'set null' | 'restrict' | 'no action';\n\n/** Column type identifiers. */\nexport type ColumnType = 'uuid' | 'text' | 'integer' | 'boolean' | 'timestamp' | 'jsonb' | 'enum';\n\n/** Base column definition shared by all column types. */\nexport interface ColumnDef {\n type: ColumnType;\n nullable: boolean;\n primaryKey: boolean;\n defaultValue?: unknown;\n defaultRandom?: boolean;\n defaultNow?: boolean;\n references?: { table: string; column: string };\n onDeleteAction?: OnDeleteAction;\n enumName?: string;\n enumValues?: string[];\n}\n\n// Phantom brand symbols — never have runtime values; exist only to force\n// TypeScript's structural type system to distinguish ColumnBuilder instances\n// with different type-param combinations. Without these, TS sees all\n// ColumnBuilder<K,...> as structurally identical and the first branch of\n// ColValue matches everything.\ndeclare const __colKind: unique symbol;\ndeclare const __colNullable: unique symbol;\ndeclare const __colHasDefault: unique symbol;\ndeclare const __colEnumValues: unique symbol;\n\n/**\n * Fluent column builder with phantom type params:\n * K — ColumnType literal (e.g. \"text\", \"integer\")\n * N — boolean: true when nullable() has been called last (false = NOT NULL)\n * D — boolean: true when a default has been set\n * E — enum value union (never for non-enum columns)\n *\n * All four params have defaults so bare `ColumnBuilder` (no args) still\n * satisfies `Record<string, ColumnBuilder>` in schema.ts without modification.\n *\n * The four `declare readonly` brand fields carry the phantom types into the\n * structural shape so that conditional types like ColValue<C> can discriminate\n * on K without requiring runtime values on those fields.\n */\nexport class ColumnBuilder<\n K extends ColumnType = ColumnType,\n N extends boolean = boolean,\n D extends boolean = boolean,\n E = unknown,\n> {\n // These fields exist only in the type layer (declared, never initialised at\n // runtime — TypeScript allows declared class members without an initializer\n // in strict mode as long as they're never read at runtime).\n declare readonly [__colKind]: K;\n declare readonly [__colNullable]: N;\n declare readonly [__colHasDefault]: D;\n declare readonly [__colEnumValues]: E;\n\n readonly _def: ColumnDef;\n\n constructor(type: K, existingDef?: ColumnDef) {\n this._def = existingDef ?? {\n type,\n nullable: false,\n primaryKey: false,\n };\n }\n\n /** Mark this column as the primary key. */\n primaryKey(): ColumnBuilder<K, N, D, E> {\n this._def.primaryKey = true;\n return new ColumnBuilder<K, N, D, E>(this._def.type as K, this._def);\n }\n\n /** Mark this column as NOT NULL (default). */\n notNull(): ColumnBuilder<K, false, D, E> {\n this._def.nullable = false;\n return new ColumnBuilder<K, false, D, E>(this._def.type as K, this._def);\n }\n\n /** Allow NULL values. */\n nullable(): ColumnBuilder<K, true, D, E> {\n this._def.nullable = true;\n return new ColumnBuilder<K, true, D, E>(this._def.type as K, this._def);\n }\n\n /** Set a default value. */\n default(value: unknown): ColumnBuilder<K, N, true, E> {\n this._def.defaultValue = value;\n return new ColumnBuilder<K, N, true, E>(this._def.type as K, this._def);\n }\n\n /** UUID: generate a random default (gen_random_uuid()). */\n defaultRandom(): ColumnBuilder<K, N, true, E> {\n this._def.defaultRandom = true;\n return new ColumnBuilder<K, N, true, E>(this._def.type as K, this._def);\n }\n\n /** Timestamp: default to now(). */\n defaultNow(): ColumnBuilder<K, N, true, E> {\n this._def.defaultNow = true;\n return new ColumnBuilder<K, N, true, E>(this._def.type as K, this._def);\n }\n\n /** Add a foreign key reference. */\n references(table: string, column: string): ColumnBuilder<K, N, D, E> {\n this._def.references = { table, column };\n return new ColumnBuilder<K, N, D, E>(this._def.type as K, this._def);\n }\n\n /** Set the ON DELETE action for a foreign key reference. */\n onDelete(action: OnDeleteAction): ColumnBuilder<K, N, D, E> {\n this._def.onDeleteAction = action;\n return new ColumnBuilder<K, N, D, E>(this._def.type as K, this._def);\n }\n}\n\n// ---------------------------------------------------------------------------\n// Type extractors — imported by Task 2 to derive insert/row shapes.\n// ---------------------------------------------------------------------------\n\n/**\n * Extracts the TypeScript value type for a column, respecting nullability.\n * - \"uuid\" | \"text\" | \"timestamp\" → string (or string | null when N = true)\n * - \"integer\" → number\n * - \"boolean\" → boolean\n * - \"jsonb\" → unknown (opaque JSON)\n * - \"enum\" → E (the union of literal values)\n */\nexport type ColValue<C> =\n C extends ColumnBuilder<'uuid' | 'text' | 'timestamp', infer N, infer _D, infer _E>\n ? N extends true\n ? string | null\n : string\n : C extends ColumnBuilder<'integer', infer N, infer _D, infer _E>\n ? N extends true\n ? number | null\n : number\n : C extends ColumnBuilder<'boolean', infer N, infer _D, infer _E>\n ? N extends true\n ? boolean | null\n : boolean\n : C extends ColumnBuilder<'jsonb', infer _N, infer _D, infer _E>\n ? unknown\n : C extends ColumnBuilder<'enum', infer N, infer _D, infer E>\n ? N extends true\n ? E | null\n : E\n : never;\n\n/**\n * True when a column is optional on INSERT:\n * - nullable columns (N = true) — the DB allows NULL so the field may be omitted\n * - columns with a default (D = true) — the DB fills in the value when absent\n */\nexport type ColIsOptionalOnInsert<C> =\n C extends ColumnBuilder<infer _K, true, infer _D, infer _E>\n ? true\n : C extends ColumnBuilder<infer _K, infer _N, true, infer _E>\n ? true\n : false;\n\n// ---------------------------------------------------------------------------\n// Factory functions\n// ---------------------------------------------------------------------------\n\n/** Create a UUID column. */\nexport function uuid(): ColumnBuilder<'uuid', false, false, never> {\n return new ColumnBuilder('uuid');\n}\n\n/** Create a TEXT column. */\nexport function text(): ColumnBuilder<'text', false, false, never> {\n return new ColumnBuilder('text');\n}\n\n/** Create an INTEGER column. */\nexport function integer(): ColumnBuilder<'integer', false, false, never> {\n return new ColumnBuilder('integer');\n}\n\n/** Create a BOOLEAN column. */\nexport function boolean(): ColumnBuilder<'boolean', false, false, never> {\n return new ColumnBuilder('boolean');\n}\n\n/** Create a TIMESTAMP column. */\nexport function timestamp(): ColumnBuilder<'timestamp', false, false, never> {\n return new ColumnBuilder('timestamp');\n}\n\n/** Create a JSONB column. */\nexport function jsonb(): ColumnBuilder<'jsonb', false, false, never> {\n return new ColumnBuilder('jsonb');\n}\n\n/**\n * Create an ENUM column.\n * @param name The PostgreSQL enum type name (used in DDL).\n * @param values A readonly tuple of valid string values — kept `const` so the\n * union `V[number]` is as narrow as possible.\n */\nexport function enumType<const V extends readonly string[]>(\n name: string,\n values: V,\n): ColumnBuilder<'enum', false, false, V[number]> {\n const builder = new ColumnBuilder<'enum', false, false, V[number]>('enum');\n builder._def.enumName = name;\n builder._def.enumValues = [...values];\n return builder;\n}\n","/**\n * typed-db.ts — Task 2: TypedDB schema-derived insert/row shapes.\n *\n * Derives INSERT and full-row TypeScript types from a `defineSchema()` result\n * and wraps the untyped runtime `DBClient` with a typed facade.\n *\n * No value-any. No `as unknown as X`. The two narrow `as` casts in\n * `makeTypedTable` are safe because:\n * - `data as Record<string, unknown>`: InsertShape<T> maps string keys to\n * typed values; all value types are subsets of `unknown`, so the cast is\n * structurally sound.\n * - `result as RowShape<T>`: The runtime DBClient returns `Record<string,\n * unknown>` which is the erased form of the typed row; we're narrowing back\n * to the precise shape that the schema declared.\n * Both casts are narrowing only (not widening) and correctness is guaranteed\n * by the schema the caller provides.\n */\n\nimport type { ColValue, ColIsOptionalOnInsert, ColumnBuilder } from \"./columns.js\";\nimport type { TableDef, SchemaDef } from \"./schema.js\";\nimport type { Tables, TableTypes } from \"./env.js\";\nimport type { DBClient, TxClient } from \"../endpoint.js\";\n\n// ---------------------------------------------------------------------------\n// Key discriminators — split a column map into required vs optional keys.\n// ---------------------------------------------------------------------------\n\n/** Keys of C whose columns are required on INSERT (not nullable, no default). */\ntype RequiredKeys<C> = {\n [K in keyof C]: ColIsOptionalOnInsert<C[K]> extends true ? never : K;\n}[keyof C];\n\n/** Keys of C whose columns are optional on INSERT (nullable or has a default). */\ntype OptionalKeys<C> = {\n [K in keyof C]: ColIsOptionalOnInsert<C[K]> extends true ? K : never;\n}[keyof C];\n\n// ---------------------------------------------------------------------------\n// Public shape types — exported so callers can reference them directly.\n// ---------------------------------------------------------------------------\n\n/**\n * The TypeScript type for an INSERT payload for table `T`.\n * - Required: columns that are NOT NULL and have no DB-level default.\n * - Optional: columns that are nullable or carry a default.\n *\n * When all columns are optional, `RequiredKeys<C>` resolves to `never` and\n * the first part becomes `{}`, which is a neutral element for `&`.\n */\nexport type InsertShape<T extends TableDef> = {\n [K in RequiredKeys<T[\"columns\"]>]: ColValue<T[\"columns\"][K]>;\n} & {\n [K in OptionalKeys<T[\"columns\"]>]?: ColValue<T[\"columns\"][K]>;\n};\n\n/**\n * The TypeScript type for a full row returned by the DB for table `T`.\n * Every column is present; nullable columns resolve to `T | null`.\n */\nexport type RowShape<T extends TableDef> = {\n [K in keyof T[\"columns\"]]: ColValue<T[\"columns\"][K]>;\n};\n\n// ---------------------------------------------------------------------------\n// TypedTable + TypedDB interfaces.\n// ---------------------------------------------------------------------------\n\n/** A typed table accessor that mirrors the runtime DBClient surface. */\nexport interface TypedTable<T extends TableDef> {\n insert(data: InsertShape<T>): Promise<RowShape<T>>;\n update(id: string, data: Partial<InsertShape<T>>): Promise<RowShape<T>>;\n delete(id: string): Promise<void>;\n findById(id: string): Promise<RowShape<T> | null>;\n findMany(query?: Partial<RowShape<T>>): Promise<RowShape<T>[]>;\n}\n\n/** A typed DB facade covering all tables declared in schema `S`. */\nexport interface TypedDB<S extends SchemaDef> {\n tables: {\n [K in keyof S[\"tables\"]]: TypedTable<S[\"tables\"][K]>;\n };\n transaction<T>(fn: (tx: TypedTx<S>) => Promise<T>): Promise<T>;\n}\n\n/** Transaction-scoped typed facade: same typed tables, no nested transaction. */\nexport interface TypedTx<S extends SchemaDef> {\n tables: {\n [K in keyof S[\"tables\"]]: TypedTable<S[\"tables\"][K]>;\n };\n}\n\n// ---------------------------------------------------------------------------\n// Runtime factory.\n// ---------------------------------------------------------------------------\n\n/**\n * Builds a typed table accessor that delegates every call to `raw` using the\n * runtime table name string. Two narrow `as` casts bridge the mapped-type\n * shapes to/from `Record<string, unknown>` — see module-level doc comment.\n *\n * The `raw` param is typed `TxClient` (the op surface shared by `DBClient` and\n * the transaction-scoped client) because this only ever calls the five\n * insert/update/delete/findById/findMany ops — never `transaction`. This lets\n * the same factory wrap both the top-level db and a tx without any cast.\n */\nfunction makeTypedTable<T extends TableDef<Record<string, ColumnBuilder>>>(\n name: string,\n raw: TxClient,\n): TypedTable<T> {\n return {\n insert: (data: InsertShape<T>) =>\n raw.insert(name, data as Record<string, unknown>) as Promise<RowShape<T>>,\n\n update: (id: string, data: Partial<InsertShape<T>>) =>\n raw.update(name, id, data as Record<string, unknown>) as Promise<RowShape<T>>,\n\n delete: (id: string) => raw.delete(name, id),\n\n findById: (id: string) =>\n raw.findById(name, id) as Promise<RowShape<T> | null>,\n\n findMany: (query?: Partial<RowShape<T>>) =>\n raw.findMany(name, query as Record<string, unknown> | undefined) as Promise<RowShape<T>[]>,\n };\n}\n\n/**\n * Wraps a raw `DBClient` with the type-safe `TypedDB<S>` facade derived from\n * the provided schema. No behavior change — all calls delegate to `raw` with\n * the table name as a plain string.\n *\n * `buildTables` is the reusable factory that wraps any op-bearing client\n * (`TxClient` — the surface shared by `DBClient` and the transaction-scoped\n * client) into the typed tables map. It is used both for the top-level db\n * (wrapping `raw`) and inside `transaction`, where it wraps the raw `TxClient`\n * the runtime yields so the callback sees the same typed `.tables` API.\n *\n * `transaction` delegates straight to `raw.transaction`; the two narrow\n * `as TypedTx<S>` / `as TypedDB<S>` casts are single structural narrowings\n * from the dynamically-built tables object to the precise mapped type (TS\n * cannot infer through `Object.keys` iteration) — see module-level doc comment.\n */\nexport function makeTypedDB<S extends SchemaDef>(\n schema: S,\n raw: DBClient,\n): TypedDB<S> {\n function buildTables(client: TxClient): Record<string, TypedTable<TableDef>> {\n const tables = {} as Record<string, TypedTable<TableDef>>;\n for (const key of Object.keys(schema.tables)) {\n const tableDef = schema.tables[key];\n if (tableDef !== undefined) {\n tables[key] = makeTypedTable(tableDef.name, client);\n }\n }\n return tables;\n }\n\n const result = {\n tables: buildTables(raw),\n transaction: <T>(fn: (tx: TypedTx<S>) => Promise<T>): Promise<T> =>\n raw.transaction((rawTx) => fn({ tables: buildTables(rawTx) } as TypedTx<S>)),\n };\n\n // Narrow cast: `result.tables` is structurally identical to\n // TypedDB<S>[\"tables\"] — each key maps to a TypedTable for the matching\n // TableDef. TS cannot infer the mapped-type result through Object.keys\n // iteration, so a single `as` bridges the gap.\n return result as TypedDB<S>;\n}\n\n// ---------------------------------------------------------------------------\n// Env-augmentation-driven typed surface — the typed-by-default `Database`.\n//\n// These types read the globally-augmented `Tables` interface from\n// `@palbase/backend/env` (filled by the generated `palbase-env.d.ts`). They\n// back `Database.tables.<name>` so handler code is typed with no import and no\n// generic (C5). They DELIBERATELY do not reference `ColumnBuilder` — the env\n// `Tables` interface carries flat `row`/`insert` object types.\n// ---------------------------------------------------------------------------\n\n/** A typed table accessor derived from one env `Tables` entry's flat shapes. */\nexport interface EnvTypedTable<T extends TableTypes> {\n insert(data: T[\"insert\"]): Promise<T[\"row\"]>;\n update(id: string, data: Partial<T[\"insert\"]>): Promise<T[\"row\"]>;\n delete(id: string): Promise<void>;\n findById(id: string): Promise<T[\"row\"] | null>;\n findMany(query?: Partial<T[\"row\"]>): Promise<T[\"row\"][]>;\n}\n\n/** The `tables` map exposed on `Database`/`tx`, keyed by the env `Tables`\n * interface. When no schema is declared `Tables` is empty, so `tables` is an\n * empty object — accessing `.tables.foo` is then a compile error (no member). */\nexport type EnvTables = {\n [K in keyof Tables]: EnvTypedTable<Tables[K]>;\n};\n\n/** Transaction-scoped typed facade for the env-augmented surface: same typed\n * tables, no nested transaction. */\nexport interface EnvTypedTx {\n tables: EnvTables;\n}\n\n/**\n * The RLS-bypass sibling returned by `Database.asService()`. Same typed surface\n * as {@link EnvTypedDatabase} — `tables`, the raw string ops, and a typed\n * `transaction` — but it does NOT re-expose `asService` (no double-bypass).\n * Every op it performs runs as the `service_role` (BYPASSRLS).\n */\nexport interface EnvServiceDatabase extends Omit<DBClient, \"transaction\" | \"asService\"> {\n tables: EnvTables;\n transaction<T>(fn: (tx: EnvTypedTx) => Promise<T>): Promise<T>;\n}\n\n/**\n * The typed-by-default Database surface: the raw string-keyed `DBClient` ops\n * PLUS a `tables` map typed against the project's generated `palbase-env.d.ts`,\n * a `transaction` whose callback receives the typed tables, and `asService()`\n * for the explicit RLS-bypass sibling.\n *\n * `transaction` is declared here (overriding `DBClient[\"transaction\"]`) so the\n * `tx` the callback receives carries the typed `.tables` API. `asService` is\n * re-typed to return the typed {@link EnvServiceDatabase} sibling.\n */\nexport interface EnvTypedDatabase extends Omit<DBClient, \"transaction\" | \"asService\"> {\n tables: EnvTables;\n transaction<T>(fn: (tx: EnvTypedTx) => Promise<T>): Promise<T>;\n /**\n * Return a sibling that bypasses RLS by running as the `service_role`. Use\n * sparingly and explicitly — the default `Database.*` path is RLS-enforced.\n *\n * @example\n * const all = await Database.asService().tables.todos.findMany({});\n * const rows = await Database.asService().query(\"SELECT * FROM todos\");\n */\n asService(): EnvServiceDatabase;\n}\n","/**\n * env-gen.ts — generate the `palbase-env.d.ts` text from a `defineSchema()`\n * result.\n *\n * The CLI (`palbase serve` / codegen) and the deploy pipeline call\n * {@link makeEnvDts} with the project's schema and write the returned string to\n * `palbase-env.d.ts` at the project root. That file AUGMENTS the\n * `@palbase/backend/env` `Tables` interface (controlled global augmentation,\n * C5) so `Database.tables.<name>` is typed with no import and no generic.\n *\n * The output is FLAT: each table gets a `{ row: {...}; insert: {...} }` entry\n * with plain TypeScript object types. The phantom `ColumnBuilder<...>` type\n * NEVER appears in the generated `.d.ts` — that type only lives at authoring\n * time inside `db/schema.ts`.\n */\n\nimport type { ColumnDef } from \"./columns.js\";\nimport type { SchemaDef, TableDef } from \"./schema.js\";\n\n/** The TypeScript value type for a column, ignoring nullability (added by the\n * caller). Mirrors the `ColValue` mapped type in columns.ts exactly. */\nfunction baseTsType(def: ColumnDef): string {\n switch (def.type) {\n case \"uuid\":\n case \"text\":\n case \"timestamp\":\n return \"string\";\n case \"integer\":\n return \"number\";\n case \"boolean\":\n return \"boolean\";\n case \"jsonb\":\n return \"unknown\";\n case \"enum\": {\n const values = def.enumValues ?? [];\n if (values.length === 0) return \"string\";\n return values.map((v) => JSON.stringify(v)).join(\" | \");\n }\n default:\n return \"unknown\";\n }\n}\n\n/** The full row type for a column: base type, `| null` when nullable. */\nfunction rowType(def: ColumnDef): string {\n const base = baseTsType(def);\n return def.nullable ? `${base} | null` : base;\n}\n\n/** True when a column may be omitted on INSERT — nullable OR has any default.\n * Mirrors `ColIsOptionalOnInsert` in columns.ts. */\nfunction optionalOnInsert(def: ColumnDef): boolean {\n return (\n def.nullable === true ||\n def.defaultRandom === true ||\n def.defaultNow === true ||\n def.defaultValue !== undefined\n );\n}\n\n/** Emit the `row: {...}` and `insert: {...}` blocks for one table at the given\n * base indentation. */\nfunction tableBlock(table: TableDef, indent: string): string {\n const cols = Object.entries(table.columns);\n const rowLines = cols.map(([col, builder]) => {\n return `${indent} ${col}: ${rowType(builder._def)};`;\n });\n const insertLines = cols.map(([col, builder]) => {\n const def = builder._def;\n const opt = optionalOnInsert(def) ? \"?\" : \"\";\n return `${indent} ${col}${opt}: ${rowType(def)};`;\n });\n return [\n `${indent}${table.name}: {`,\n `${indent} row: {`,\n ...rowLines,\n `${indent} };`,\n `${indent} insert: {`,\n ...insertLines,\n `${indent} };`,\n `${indent}};`,\n ].join(\"\\n\");\n}\n\n/**\n * Generate the full `palbase-env.d.ts` text for a schema.\n *\n * @example\n * import { makeEnvDts } from \"@palbase/backend\";\n * import schema from \"./db/schema.js\";\n * writeFileSync(\"palbase-env.d.ts\", makeEnvDts(schema));\n */\nexport function makeEnvDts(schema: SchemaDef): string {\n const tableNames = Object.keys(schema.tables);\n const blocks = tableNames.map((name) => tableBlock(schema.tables[name]!, \" \"));\n const body = blocks.length > 0 ? `\\n${blocks.join(\"\\n\")}\\n ` : \"\";\n return `// AUTO-GENERATED by @palbase/backend — DO NOT EDIT.\n// Regenerated from db/schema.ts on every \\`palbase serve\\` / deploy.\n// Augments the @palbase/backend/env \\`Tables\\` interface so \\`Database.tables.*\\`\n// is typed with no import and no generic.\n\ndeclare module \"@palbase/backend/env\" {\n interface Tables {${body}}\n}\n\nexport {};\n`;\n}\n","// `@Controller(basePath, options?)` — the class decorator that marks a class as\n// a Palbase backend controller. It stamps a non-enumerable `__palbase`\n// discriminant + the resolved controller metadata onto the class so the\n// deploy/dispatch pipeline (and `isController`/`resolveController`) can detect\n// and read it without `reflect-metadata`.\nimport type { AuthSpec } from \"../endpoint.js\";\n\n/** The controller metadata stamped onto a `@Controller`-decorated class. The\n * default export of a `controllers/*.controller.ts` file resolves to this via\n * {@link resolveController}. */\nexport interface ControllerMeta {\n /** Discriminant the runtime + tooling read. */\n readonly __palbase: \"controller\";\n /** The base path every route in this controller mounts under (e.g. \"/todos\"). */\n basePath: string;\n /** Controller-level default auth, applied to routes that don't set their own\n * (`@Get(\"/x\", { auth })` overrides this). `undefined` ⇒ secure-by-default. */\n defaultAuth?: AuthSpec;\n}\n\n/** Options accepted by `@Controller`. */\nexport interface ControllerOptions {\n /** Default auth for ALL routes in this controller (route-level overrides). */\n auth?: AuthSpec;\n}\n\n/** Symbol the controller metadata is stamped under. Symbol-keyed (not a string\n * property) so it never collides with an authored member and stays off the\n * structural surface. */\nexport const CONTROLLER_META: unique symbol = Symbol.for(\"palbase.backend.controllerMeta\");\n\n/** A class carrying the stamped controller metadata + discriminant. */\ninterface ControllerCarrier {\n __palbase?: \"controller\";\n [CONTROLLER_META]?: ControllerMeta;\n}\n\n/**\n * Mark a class as a Palbase backend controller. `basePath` is the mount path\n * for every route the class declares; `options.auth` sets the controller-level\n * default auth (a route's own `auth` overrides it; absent ⇒ secure-by-default).\n *\n * @example\n * \\@Controller(\"/todos\", { auth: false })\n * export class TodosController {\n * \\@Get(\"\") list(\\@Query(ListTodosQuery) q: ListTodosQuery): TodoSchema[] { … }\n * }\n */\nexport function Controller(basePath: string, options: ControllerOptions = {}) {\n return function <T extends abstract new (...args: never[]) => object>(ctor: T): T {\n const carrier = ctor as unknown as ControllerCarrier;\n const meta: ControllerMeta = {\n __palbase: \"controller\",\n basePath,\n ...(options.auth !== undefined ? { defaultAuth: options.auth } : {}),\n };\n // Non-enumerable so it doesn't leak onto instances / structural checks.\n Object.defineProperty(carrier, CONTROLLER_META, {\n value: meta,\n enumerable: false,\n configurable: true,\n writable: false,\n });\n // The bare `__palbase` discriminant is the cheap detection marker the\n // runtime/extractor checks; keep it readable but non-enumerable.\n Object.defineProperty(carrier, \"__palbase\", {\n value: \"controller\",\n enumerable: false,\n configurable: true,\n writable: false,\n });\n return ctor;\n };\n}\n\n/** True when `value` is a `@Controller`-decorated class (cheap discriminant\n * check). Accepts the class constructor (the default export of a controller\n * file). */\nexport function isController(value: unknown): boolean {\n if (typeof value !== \"function\" && (typeof value !== \"object\" || value === null)) {\n return false;\n }\n const carrier = value as ControllerCarrier;\n return carrier.__palbase === \"controller\" && carrier[CONTROLLER_META] !== undefined;\n}\n\n/** Read the resolved controller metadata off a `@Controller`-decorated class.\n * Throws if the class was not decorated — callers should gate with\n * {@link isController} first (the loader does). */\nexport function resolveController(ctor: unknown): ControllerMeta {\n if (typeof ctor !== \"function\" && (typeof ctor !== \"object\" || ctor === null)) {\n throw new TypeError(\"resolveController: value is not a class\");\n }\n const meta = (ctor as ControllerCarrier)[CONTROLLER_META];\n if (!meta) {\n throw new TypeError(\n \"resolveController: class is not a @Controller — every controller file must `export default` a @Controller-decorated class\",\n );\n }\n return meta;\n}\n","// The decorator registry — the single plain-data store the method + parameter\n// decorators write into, and the deploy/dispatch pipeline reads back. No\n// `reflect-metadata`, no `emitDecoratorMetadata`: the registry is built from the\n// decorator arguments + the parameter INDEX that esbuild/tsc preserve for legacy\n// parameter decorators (verified — see the design spec §0/§4.1).\n//\n// A controller class carries its route metadata on a symbol-keyed static\n// property (`ROUTES`). `@Get`/`@Post`/… append a {@link RouteMeta} entry;\n// `@Body`/`@User`/… append a {@link ParamMeta} entry onto the route for the\n// method they decorate. Because parameter decorators run BEFORE the method\n// decorator for the same member (TS evaluates innermost-first, params before the\n// method), the route entry may not exist yet when a param decorator fires — so\n// param metadata is buffered per method name and merged when the method\n// decorator creates the route entry.\nimport type { AuthSpec, RateLimitConfig } from \"../endpoint.js\";\nimport type { ZodTypeAny } from \"zod\";\n\n/** The HTTP verbs a route may declare, upper-cased (the runtime router +\n * OpenAPI lower-case on their own). */\nexport type HttpMethodUpper = \"GET\" | \"POST\" | \"PUT\" | \"PATCH\" | \"DELETE\";\n\n/** Route-level options accepted by the method decorators (`@Get`/`@Post`/…). */\nexport interface RouteOptions {\n /** OVERRIDES the controller-level default auth for this one route. */\n auth?: AuthSpec;\n /** Per-route rate limit. */\n rateLimit?: RateLimitConfig;\n}\n\n/** The kind of value a parameter decorator injects. Drives both dispatch\n * (which request slice to inject) and codegen (which OpenAPI parameter source a\n * schema-bearing kind maps to). */\nexport type ParamKind =\n | \"body\"\n | \"query\"\n | \"param\"\n | \"headers\"\n | \"user\"\n | \"optionalUser\"\n | \"client\"\n | \"requestId\"\n | \"traceId\"\n | \"req\";\n\n/** One parameter decorator's recorded metadata. `index` is the parameter\n * position esbuild/tsc preserve; `schema` is present for the schema-bearing\n * kinds (`body`/`query`/`headers`); `name` is the path-param name for `param`. */\nexport interface ParamMeta {\n index: number;\n kind: ParamKind;\n /** Zod schema for `body`/`query`/`headers` (validation + codegen source). */\n schema?: ZodTypeAny;\n /** Path-param name for `@Param(\"id\")`. */\n name?: string;\n}\n\n/** One route's recorded metadata: the verb + subpath + method name + options,\n * the ordered parameter metas, and the resolved return schema (set by\n * `@Returns`). */\nexport interface RouteMeta {\n method: HttpMethodUpper;\n subpath: string;\n fnName: string;\n options: RouteOptions;\n params: ParamMeta[];\n /** Response schema declared via `@Returns(schema)`, if any. */\n returnSchema?: ZodTypeAny;\n}\n\n/** Symbol the route metadata list is stored under on a controller class. Using\n * a symbol (not a string key) keeps it off the public structural surface and\n * avoids any chance of an authored property collision. */\nexport const ROUTES: unique symbol = Symbol.for(\"palbase.backend.routes\");\n\n/** Symbol the per-method buffered parameter metas are stored under while a class\n * is being decorated. Parameter decorators fire before the method decorator, so\n * they buffer here keyed by method name; the method decorator drains the buffer\n * into the route entry it creates. */\nconst PARAM_BUFFER: unique symbol = Symbol.for(\"palbase.backend.paramBuffer\");\n\n/** A class constructor carrying the symbol-keyed registry slots. We type the\n * registry-bearing class as this so the decorators can read/write the slots\n * without `any` — a plain `Function` does not carry index signatures. */\ninterface RegistryCarrier {\n [ROUTES]?: RouteMeta[];\n [PARAM_BUFFER]?: Record<string, ParamMeta[]>;\n}\n\n/** Coerce a decorated target (class constructor or its prototype) into the\n * registry carrier that owns the slots. Method/param decorators receive the\n * PROTOTYPE as their target; the class decorator receives the constructor. We\n * always anchor the registry on the CONSTRUCTOR so `getRoutes(ctor)` finds it. */\nfunction carrierOf(target: object): RegistryCarrier {\n // For instance-member decorators, `target` is the prototype; its `.constructor`\n // is the class. For a static member or the class decorator, `target` is the\n // constructor already. Resolve to the constructor either way.\n const ctor =\n typeof target === \"function\"\n ? (target as unknown as RegistryCarrier)\n : (((target as { constructor?: unknown }).constructor ??\n target) as unknown as RegistryCarrier);\n return ctor;\n}\n\n/** Get (creating if absent) the own route list for a class constructor. Own —\n * not inherited — so a subclass does not mutate its base's routes. */\nfunction ownRoutes(carrier: RegistryCarrier): RouteMeta[] {\n if (!Object.prototype.hasOwnProperty.call(carrier, ROUTES)) {\n carrier[ROUTES] = [];\n }\n return carrier[ROUTES] as RouteMeta[];\n}\n\n/** Get (creating if absent) the own per-method param buffer for a class. */\nfunction ownParamBuffer(carrier: RegistryCarrier): Record<string, ParamMeta[]> {\n if (!Object.prototype.hasOwnProperty.call(carrier, PARAM_BUFFER)) {\n carrier[PARAM_BUFFER] = {};\n }\n return carrier[PARAM_BUFFER] as Record<string, ParamMeta[]>;\n}\n\n/** Record a route (called by the method decorators). Drains any parameter\n * metas already buffered for `fnName` into the new route entry, then sorts them\n * by parameter index so dispatch can inject positionally. */\nexport function recordRoute(\n target: object,\n fnName: string,\n method: HttpMethodUpper,\n subpath: string,\n options: RouteOptions,\n): void {\n const carrier = carrierOf(target);\n const routes = ownRoutes(carrier);\n const buffer = ownParamBuffer(carrier);\n const params = (buffer[fnName] ?? []).slice().sort((a, b) => a.index - b.index);\n routes.push({ method, subpath, fnName, options, params });\n}\n\n/** Record one parameter decorator (called by `@Body`/`@User`/…). Buffers per\n * method name; the method decorator merges the buffer into the route entry. If\n * the route already exists (method decorator ran first — TS does evaluate the\n * method decorator AFTER its parameter decorators, but we stay order-robust),\n * the meta is also appended directly so neither ordering loses it. */\nexport function recordParam(target: object, fnName: string, meta: ParamMeta): void {\n const carrier = carrierOf(target);\n const buffer = ownParamBuffer(carrier);\n (buffer[fnName] ??= []).push(meta);\n\n // Order-robust: if the route already exists, merge in place + keep sorted.\n const routes = carrier[ROUTES];\n if (routes) {\n const route = routes.find((r) => r.fnName === fnName);\n if (route) {\n route.params.push(meta);\n route.params.sort((a, b) => a.index - b.index);\n }\n }\n}\n\n/** Attach a return schema to the route for `fnName` (called by `@Returns`). If\n * the route does not exist yet, the schema is buffered and applied when the\n * method decorator creates the route. */\nconst RETURN_BUFFER: unique symbol = Symbol.for(\"palbase.backend.returnBuffer\");\ninterface ReturnCarrier extends RegistryCarrier {\n [RETURN_BUFFER]?: Record<string, ZodTypeAny>;\n}\n\nexport function recordReturn(target: object, fnName: string, schema: ZodTypeAny): void {\n const carrier = carrierOf(target) as ReturnCarrier;\n const routes = carrier[ROUTES];\n const route = routes?.find((r) => r.fnName === fnName);\n if (route) {\n route.returnSchema = schema;\n return;\n }\n if (!Object.prototype.hasOwnProperty.call(carrier, RETURN_BUFFER)) {\n carrier[RETURN_BUFFER] = {};\n }\n (carrier[RETURN_BUFFER] as Record<string, ZodTypeAny>)[fnName] = schema;\n}\n\n/** Read the route metadata for a controller class (the deploy/dispatch entry\n * point). Applies any buffered return schemas (for the `@Returns` runs-before\n * ordering) and returns a defensive copy so callers cannot mutate the registry.\n */\nexport function getRoutes(ctor: object): RouteMeta[] {\n const carrier = carrierOf(ctor) as ReturnCarrier;\n const routes = carrier[ROUTES] ?? [];\n const returnBuffer = carrier[RETURN_BUFFER];\n if (returnBuffer) {\n for (const route of routes) {\n const buffered = returnBuffer[route.fnName];\n if (buffered && route.returnSchema === undefined) {\n route.returnSchema = buffered;\n }\n }\n }\n return routes.map((r) => ({ ...r, params: r.params.slice() }));\n}\n","// Method decorators: `@Get` / `@Post` / `@Put` / `@Patch` / `@Delete` declare a\n// route (verb + subpath + options) on a controller method, and `@Returns`\n// attaches the response zod schema. These are LEGACY method decorators\n// (`experimentalDecorators`), receiving `(prototype, methodName, descriptor)`.\n// They write into the per-class registry (registry.ts).\nimport type { ZodTypeAny } from \"zod\";\nimport {\n recordRoute,\n recordReturn,\n type HttpMethodUpper,\n type RouteOptions,\n} from \"./registry.js\";\n\n/** A legacy method decorator. */\ntype MethodDecorator = (\n target: object,\n propertyKey: string | symbol,\n descriptor: PropertyDescriptor,\n) => void;\n\n/** Build a method decorator for one HTTP verb. The decorated method's name is\n * the route `fnName` (authoring sugar — the operationId is derived flat from\n * method+path by the runtime, not from this name). */\nfunction makeMethodDecorator(method: HttpMethodUpper) {\n return function (subpath: string, options: RouteOptions = {}): MethodDecorator {\n return function (target, propertyKey) {\n recordRoute(target, String(propertyKey), method, subpath, options);\n };\n };\n}\n\n/** `@Get(subpath, options?)` — declare a GET route. */\nexport const Get = makeMethodDecorator(\"GET\");\n/** `@Post(subpath, options?)` — declare a POST route. */\nexport const Post = makeMethodDecorator(\"POST\");\n/** `@Put(subpath, options?)` — declare a PUT route. */\nexport const Put = makeMethodDecorator(\"PUT\");\n/** `@Patch(subpath, options?)` — declare a PATCH route. */\nexport const Patch = makeMethodDecorator(\"PATCH\");\n/** `@Delete(subpath, options?)` — declare a DELETE route. */\nexport const Delete = makeMethodDecorator(\"DELETE\");\n\n/**\n * `@Returns(schema)` — declare the route's success-response zod schema. The\n * method's return TYPE drives compile-time checking; `@Returns` supplies the\n * matching zod VALUE the OpenAPI generator reads for the 200 response. Optional:\n * a `void` method (no response body) omits it.\n *\n * @example\n * \\@Get(\"/{id}\")\n * \\@Returns(TodoSchema)\n * getOne(\\@Param(\"id\") id: string): TodoSchema { … }\n */\nexport function Returns(schema: ZodTypeAny): MethodDecorator {\n return function (target, propertyKey) {\n recordReturn(target, String(propertyKey), schema);\n };\n}\n","// Parameter decorators: `@Body` / `@Query` / `@Param` / `@Headers` / `@User` /\n// `@OptionalUser` / `@Client` / `@RequestId` / `@TraceId` / `@Req`. Each records\n// `{ index, kind, schema?, name? }` into the per-class registry for the method\n// it decorates. These are LEGACY parameter decorators\n// (`experimentalDecorators`), receiving `(prototype, methodName, paramIndex)` —\n// esbuild/tsc preserve the param index at runtime (verified, design §0), which\n// is how dispatch injects positionally. No type reflection\n// (`emitDecoratorMetadata`) is used: validation comes from the zod schema, the\n// type annotation the developer writes is purely for autocomplete.\nimport type { ZodTypeAny } from \"zod\";\nimport { recordParam, type ParamKind } from \"./registry.js\";\n\n/** A legacy parameter decorator. */\ntype ParameterDecorator = (\n target: object,\n propertyKey: string | symbol,\n parameterIndex: number,\n) => void;\n\n/** Build a parameter decorator that records the given kind (+ optional schema /\n * name) at the decorated parameter's index. */\nfunction makeParamDecorator(\n kind: ParamKind,\n extra?: { schema?: ZodTypeAny; name?: string },\n): ParameterDecorator {\n return function (target, propertyKey, parameterIndex) {\n recordParam(target, String(propertyKey), {\n index: parameterIndex,\n kind,\n ...(extra?.schema !== undefined ? { schema: extra.schema } : {}),\n ...(extra?.name !== undefined ? { name: extra.name } : {}),\n });\n };\n}\n\n/** `@Body(schema)` — inject the request body, validated against `schema`. The\n * developer writes `: T` (= `z.infer<schema>`, same name) for autocomplete. */\nexport function Body(schema: ZodTypeAny): ParameterDecorator {\n return makeParamDecorator(\"body\", { schema });\n}\n\n/** `@Query(schema)` — inject the parsed query params, validated against\n * `schema`. */\nexport function Query(schema: ZodTypeAny): ParameterDecorator {\n return makeParamDecorator(\"query\", { schema });\n}\n\n/** `@Headers(schema?)` — inject the request headers (lowercase keys). With a\n * schema, headers are validated + the codegen emits header parameters. */\nexport function Headers(schema?: ZodTypeAny): ParameterDecorator {\n return makeParamDecorator(\"headers\", schema !== undefined ? { schema } : undefined);\n}\n\n/** `@Param(\"id\")` — inject one matched path param by name. */\nexport function Param(name: string): ParameterDecorator {\n return makeParamDecorator(\"param\", { name });\n}\n\n/** `@User()` — inject the authenticated user (`: User`, non-null for an\n * effective-required route). The runtime resolves the effective auth. */\nexport function User(): ParameterDecorator {\n return makeParamDecorator(\"user\");\n}\n\n/** `@OptionalUser()` — inject the user as `User | null` (for routes whose\n * effective auth is `false` / `{ required: false }`). */\nexport function OptionalUser(): ParameterDecorator {\n return makeParamDecorator(\"optionalUser\");\n}\n\n/** `@Client()` — inject the parsed calling-client metadata (`: ClientInfo`). */\nexport function Client(): ParameterDecorator {\n return makeParamDecorator(\"client\");\n}\n\n/** `@RequestId()` — inject the per-request id (`: string`). */\nexport function RequestId(): ParameterDecorator {\n return makeParamDecorator(\"requestId\");\n}\n\n/** `@TraceId()` — inject the W3C trace id (`: string`). */\nexport function TraceId(): ParameterDecorator {\n return makeParamDecorator(\"traceId\");\n}\n\n/** `@Req()` — inject the raw request object (escape hatch, `: PBRequest`). */\nexport function Req(): ParameterDecorator {\n return makeParamDecorator(\"req\");\n}\n","import type { DBClient, Logger, CacheClient, PalbaseModuleClients } from \"./endpoint.js\";\nimport type { User } from \"./types.js\";\n\n/** Middleware context — subset of EndpointContext without input (not yet validated). */\nexport interface MiddlewareContext extends PalbaseModuleClients {\n params: Record<string, string>;\n query: Record<string, string>;\n headers: Record<string, string>;\n user: User | null;\n db: DBClient;\n env: Record<string, string>;\n log: Logger;\n cache: CacheClient;\n requestId: string;\n projectId: string;\n environmentId: string;\n}\n\n/** Middleware function signature — receives context and next function. */\nexport type MiddlewareHandler = (\n ctx: MiddlewareContext,\n next: () => Promise<void>,\n) => Promise<void>;\n\n/**\n * Define a middleware function for use in the middleware/ directory or\n * as endpoint-specific middleware.\n *\n * Middleware runs before the handler. Call `next()` to pass control\n * to the next middleware or handler. If `next()` is not called, the\n * handler will not execute.\n *\n * Errors thrown in middleware are caught by the pipeline and returned\n * as error responses.\n */\nexport function defineMiddleware(fn: MiddlewareHandler): MiddlewareHandler {\n return fn;\n}\n","/** HTTP error with structured error response format.\n *\n * The base class for the throwable error classes (`PalError`, `Conflict`,\n * `NotFound`, …). Construct one directly with `throw new HttpError(404,\n * \"todo_not_found\", \"No such todo\")`, or throw a named subclass\n * (`throw new NotFound(\"todo not found\")`). The runtime catches any `HttpError`\n * and emits the standard envelope; on the wire (and to iOS) it surfaces as\n * `BackendError.server(code, status, message, requestId)`.\n *\n * The optional `data` field carries a structured payload alongside the\n * standard envelope — for errors that need to ship extra context\n * (e.g. `new Conflict(\"locked\", \"title_locked\", { retryAfter: 30 })`). It rides\n * through to the iOS typed enum's associated value.\n */\nexport class HttpError extends Error {\n public readonly status: number;\n public readonly error: string;\n public readonly errorDescription: string;\n public readonly data?: unknown;\n\n constructor(status: number, error: string, errorDescription: string, data?: unknown) {\n super(errorDescription);\n this.name = \"HttpError\";\n this.status = status;\n this.error = error;\n this.errorDescription = errorDescription;\n if (data !== undefined) {\n this.data = data;\n }\n }\n\n /**\n * Serialize to the standard Palbase error response format.\n * The `requestId` is injected by the runtime layer from the request context.\n * When called without arguments (e.g. JSON.stringify), request_id is omitted.\n * When `data` is set, it is appended as a strict-superset field.\n */\n toJSON(requestId?: string): {\n error: string;\n error_description: string;\n status: number;\n request_id?: string;\n data?: unknown;\n } {\n const result: {\n error: string;\n error_description: string;\n status: number;\n request_id?: string;\n data?: unknown;\n } = {\n error: this.error,\n error_description: this.errorDescription,\n status: this.status,\n };\n if (requestId) {\n result.request_id = requestId;\n }\n if (this.data !== undefined) {\n result.data = this.data;\n }\n return result;\n }\n}\n\n/**\n * Throw with a custom HTTP status + wire code. The general-purpose escape hatch\n * when none of the named classes (`Conflict`/`NotFound`/…) fits.\n *\n * @example\n * throw new PalError(418, \"teapot\", \"I'm a teapot\");\n */\nexport class PalError extends HttpError {\n constructor(status: number, code: string, description: string, data?: unknown) {\n super(status, code, description, data);\n this.name = \"PalError\";\n }\n}\n\n/** Base for the named status classes. Each subclass fixes its HTTP status; the\n * `code` defaults to the class's canonical wire code (overridable), and the\n * `message` defaults to a human-readable label (overridable). */\nabstract class NamedHttpError extends HttpError {\n protected constructor(\n status: number,\n defaultCode: string,\n name: string,\n message?: string,\n code?: string,\n data?: unknown,\n ) {\n super(status, code ?? defaultCode, message ?? defaultMessage(name), data);\n this.name = name;\n }\n}\n\n/** Derive a default human-readable message from a class name\n * (\"NotFound\" → \"Not found\", \"TooManyRequests\" → \"Too many requests\"). */\nfunction defaultMessage(name: string): string {\n const spaced = name.replace(/([a-z0-9])([A-Z])/g, \"$1 $2\");\n return spaced.charAt(0).toUpperCase() + spaced.slice(1).toLowerCase();\n}\n\n/** 400 — the request was malformed or failed validation. */\nexport class BadRequest extends NamedHttpError {\n constructor(message?: string, code?: string, data?: unknown) {\n super(400, \"bad_request\", \"BadRequest\", message, code, data);\n }\n}\n\n/** 401 — the caller is not authenticated. */\nexport class Unauthorized extends NamedHttpError {\n constructor(message?: string, code?: string, data?: unknown) {\n super(401, \"unauthorized\", \"Unauthorized\", message, code, data);\n }\n}\n\n/** 403 — the caller is authenticated but not allowed. */\nexport class Forbidden extends NamedHttpError {\n constructor(message?: string, code?: string, data?: unknown) {\n super(403, \"forbidden\", \"Forbidden\", message, code, data);\n }\n}\n\n/** 404 — the requested resource does not exist. */\nexport class NotFound extends NamedHttpError {\n constructor(message?: string, code?: string, data?: unknown) {\n super(404, \"not_found\", \"NotFound\", message, code, data);\n }\n}\n\n/** 409 — the request conflicts with the current state. */\nexport class Conflict extends NamedHttpError {\n constructor(message?: string, code?: string, data?: unknown) {\n super(409, \"conflict\", \"Conflict\", message, code, data);\n }\n}\n\n/** 429 — the caller has exceeded the rate limit. */\nexport class TooManyRequests extends NamedHttpError {\n constructor(message?: string, code?: string, data?: unknown) {\n super(429, \"too_many_requests\", \"TooManyRequests\", message, code, data);\n }\n}\n","import type { User } from \"./types.js\";\n\n/** Non-service, per-invocation data for background worker handlers.\n * Services (Database, Log, …) are imported as singletons, not passed here. */\nexport interface WorkerMeta {\n /** Branch-scoped env vars. */\n env: Record<string, string>;\n /** The user that enqueued the job, if any (background jobs are usually system-initiated). */\n user: User | null;\n /** Per-invocation id for correlation. */\n requestId: string;\n projectId: string;\n environmentId: string;\n}\n\n/** Backoff strategy for worker retries. */\nexport type BackoffStrategy = \"exponential\" | \"linear\" | \"fixed\";\n\n/** Configuration for a background worker. */\nexport interface WorkerConfig<TPayload = unknown> {\n /** Worker name — must be unique across the project. */\n name: string;\n /** Maximum number of retries before sending to dead letter queue. Defaults to 3. */\n retry?: number;\n /** Execution timeout in seconds. Defaults to 30. */\n timeout?: number;\n /** Backoff strategy between retries. Defaults to \"exponential\". */\n backoff?: BackoffStrategy;\n /** Handler function that processes the job payload. */\n handler: (\n payload: TPayload,\n meta: WorkerMeta,\n ) => Promise<void>;\n}\n\n/** Resolved worker configuration with defaults applied. */\nexport interface ResolvedWorkerConfig<TPayload = unknown> {\n name: string;\n retry: number;\n timeout: number;\n backoff: BackoffStrategy;\n handler: (\n payload: TPayload,\n meta: WorkerMeta,\n ) => Promise<void>;\n}\n\n/** Valid worker name pattern: alphanumeric, underscore, hyphen only.\n * Prevents Redis key injection via colons or path separators. */\nconst VALID_WORKER_NAME = /^[a-zA-Z0-9_-]+$/;\n\n/** Default values for worker configuration. */\nconst WORKER_DEFAULTS = {\n retry: 3,\n timeout: 30,\n backoff: \"exponential\" as BackoffStrategy,\n} as const;\n\n/**\n * Define a background worker that processes jobs from the queue.\n *\n * Workers are placed in the `workers/` directory and auto-discovered at deploy time.\n *\n * @example\n * ```ts\n * export default defineWorker({\n * name: \"send-email\",\n * retry: 5,\n * timeout: 60,\n * backoff: \"exponential\",\n * handler: async (payload: { to: string; subject: string }, meta) => {\n * await sendEmail(payload.to, payload.subject);\n * },\n * });\n * ```\n */\nexport function defineWorker<TPayload = unknown>(\n config: WorkerConfig<TPayload>,\n): ResolvedWorkerConfig<TPayload> {\n if (!config.name || config.name.trim() === \"\") {\n throw new Error(\"Worker name is required\");\n }\n\n if (!VALID_WORKER_NAME.test(config.name)) {\n throw new Error(\n `Invalid worker name \"${config.name}\": must match [a-zA-Z0-9_-]+`,\n );\n }\n\n if (config.retry !== undefined && (config.retry < 0 || !Number.isInteger(config.retry))) {\n throw new Error(\"Worker retry must be a non-negative integer\");\n }\n\n if (config.timeout !== undefined && config.timeout <= 0) {\n throw new Error(\"Worker timeout must be a positive number\");\n }\n\n if (\n config.backoff !== undefined &&\n ![\"exponential\", \"linear\", \"fixed\"].includes(config.backoff)\n ) {\n throw new Error(`Invalid backoff strategy: ${config.backoff}`);\n }\n\n return {\n name: config.name,\n retry: config.retry ?? WORKER_DEFAULTS.retry,\n timeout: config.timeout ?? WORKER_DEFAULTS.timeout,\n backoff: config.backoff ?? WORKER_DEFAULTS.backoff,\n handler: config.handler,\n };\n}\n","/** Non-service, per-invocation data for job handlers.\n * Services (Database, Log, …) are imported as singletons, not passed here. */\nexport interface JobMeta {\n /** Branch-scoped env vars. */\n env: Record<string, string>;\n projectId: string;\n environmentId: string;\n}\n\n/** Configuration for defining a scheduled job. */\nexport interface JobConfig {\n /** Unique job name — alphanumeric, underscore, hyphen only. */\n name: string;\n /** Cron expression (e.g., \"0 3 * * *\"). */\n schedule: string;\n /** Execution timeout in seconds. Defaults to 30. */\n timeout?: number;\n /** Job handler function. */\n handler: (meta: JobMeta) => Promise<void>;\n}\n\n/** Resolved job configuration with defaults applied. */\nexport interface ResolvedJobConfig {\n name: string;\n schedule: string;\n timeout: number;\n handler: (meta: JobMeta) => Promise<void>;\n}\n\n/** Valid job name pattern: alphanumeric, underscore, hyphen only. */\nconst VALID_JOB_NAME = /^[a-zA-Z0-9_-]+$/;\n\n/** Maximum allowed timeout in seconds (5 minutes, matching sandbox limits). */\nconst MAX_TIMEOUT_SECONDS = 300;\n\n/** Default values for job configuration. */\nconst JOB_DEFAULTS = {\n timeout: 30,\n} as const;\n\n/**\n * Cron expression validation.\n * Supports standard 5-field cron: minute hour day-of-month month day-of-week.\n * Each field allows: number, *, ranges (1-5), steps (star/2), lists (1,3,5).\n */\nfunction validateCronExpression(expression: string): string | null {\n const trimmed = expression.trim();\n if (trimmed === \"\") {\n return \"Cron expression is required\";\n }\n\n const parts = trimmed.split(/\\s+/);\n if (parts.length !== 5) {\n return `Invalid cron expression \"${trimmed}\": expected 5 fields (minute hour day month weekday), got ${parts.length}`;\n }\n\n const fieldNames = [\"minute\", \"hour\", \"day of month\", \"month\", \"day of week\"];\n const fieldRanges: [number, number][] = [\n [0, 59],\n [0, 23],\n [1, 31],\n [1, 12],\n [0, 7],\n ];\n\n for (let i = 0; i < 5; i++) {\n const field = parts[i]!;\n const name = fieldNames[i]!;\n const [min, max] = fieldRanges[i]!;\n\n const error = validateCronField(field, name, min, max);\n if (error !== null) {\n return error;\n }\n }\n\n return null;\n}\n\nfunction validateCronField(\n field: string,\n name: string,\n min: number,\n max: number,\n): string | null {\n // Split by comma for lists\n const listParts = field.split(\",\");\n for (const part of listParts) {\n // Check for step: */2, 1-5/2\n const stepParts = part.split(\"/\");\n if (stepParts.length > 2) {\n return `Invalid ${name} field: \"${field}\"`;\n }\n\n const base = stepParts[0]!;\n const step = stepParts[1];\n\n if (step !== undefined) {\n const stepNum = Number(step);\n if (!Number.isInteger(stepNum) || stepNum < 1) {\n return `Invalid step value in ${name} field: \"${field}\"`;\n }\n }\n\n if (base === \"*\") {\n continue;\n }\n\n // Check for range: 1-5\n if (base.includes(\"-\")) {\n const rangeParts = base.split(\"-\");\n if (rangeParts.length !== 2) {\n return `Invalid range in ${name} field: \"${field}\"`;\n }\n const rangeStart = Number(rangeParts[0]);\n const rangeEnd = Number(rangeParts[1]);\n if (\n !Number.isInteger(rangeStart) ||\n !Number.isInteger(rangeEnd) ||\n rangeStart < min ||\n rangeEnd > max ||\n rangeStart > rangeEnd\n ) {\n return `Invalid range in ${name} field: \"${field}\"`;\n }\n continue;\n }\n\n // Single number\n const num = Number(base);\n if (!Number.isInteger(num) || num < min || num > max) {\n return `Invalid value in ${name} field: \"${field}\"`;\n }\n }\n\n return null;\n}\n\n/**\n * Define a scheduled cron job.\n *\n * Jobs are placed in the `jobs/` directory and auto-discovered at deploy time.\n *\n * @example\n * ```ts\n * export default defineJob({\n * name: \"cleanup-expired\",\n * schedule: \"0 3 * * *\", // every day at 3 AM\n * timeout: 60,\n * handler: async (meta) => {\n * await Database.delete(\"sessions\", \"expired < NOW()\");\n * Log.info(\"Cleaned up expired sessions\");\n * },\n * });\n * ```\n */\nexport function defineJob(config: JobConfig): ResolvedJobConfig {\n if (!config.name || config.name.trim() === \"\") {\n throw new Error(\"Job name is required\");\n }\n\n if (!VALID_JOB_NAME.test(config.name)) {\n throw new Error(\n `Invalid job name \"${config.name}\": must match [a-zA-Z0-9_-]+`,\n );\n }\n\n if (!config.schedule || config.schedule.trim() === \"\") {\n throw new Error(\"Job schedule is required\");\n }\n\n const cronError = validateCronExpression(config.schedule);\n if (cronError !== null) {\n throw new Error(cronError);\n }\n\n if (!config.handler) {\n throw new Error(\"Job handler is required\");\n }\n\n if (config.timeout !== undefined && config.timeout <= 0) {\n throw new Error(\"Job timeout must be a positive number\");\n }\n\n if (config.timeout !== undefined && !Number.isInteger(config.timeout)) {\n throw new Error(\"Job timeout must be an integer\");\n }\n\n if (config.timeout !== undefined && config.timeout > MAX_TIMEOUT_SECONDS) {\n throw new Error(\n `Job timeout ${config.timeout}s exceeds maximum ${MAX_TIMEOUT_SECONDS}s`,\n );\n }\n\n return {\n name: config.name,\n schedule: config.schedule.trim(),\n timeout: config.timeout ?? JOB_DEFAULTS.timeout,\n handler: config.handler,\n };\n}\n","/** Supported webhook provider types. */\nexport type WebhookProvider =\n | \"stripe\"\n | \"github\"\n | \"twilio\"\n | \"sendgrid\"\n | \"slack\"\n | \"discord\"\n | \"livekit\";\n\n/** Non-service, per-invocation data for webhook handlers.\n * Services (Database, Log, …) are imported as singletons, not passed here. */\nexport interface WebhookMeta {\n /** Branch-scoped env vars. */\n env: Record<string, string>;\n /** Per-invocation id for correlation. */\n requestId: string;\n projectId: string;\n environmentId: string;\n}\n\n/** Secret reference — resolves from environment variables at runtime. */\nexport interface EnvSecretRef {\n env: string;\n}\n\n/** Provider-specific event maps for type-safe event handlers. */\nexport interface ProviderEventMap {\n stripe: {\n \"checkout.session.completed\": Record<string, unknown>;\n \"payment_intent.succeeded\": Record<string, unknown>;\n \"payment_intent.payment_failed\": Record<string, unknown>;\n \"customer.subscription.created\": Record<string, unknown>;\n \"customer.subscription.updated\": Record<string, unknown>;\n \"customer.subscription.deleted\": Record<string, unknown>;\n \"invoice.paid\": Record<string, unknown>;\n \"invoice.payment_failed\": Record<string, unknown>;\n [key: string]: Record<string, unknown>;\n };\n github: {\n push: Record<string, unknown>;\n pull_request: Record<string, unknown>;\n issues: Record<string, unknown>;\n \"pull_request.opened\": Record<string, unknown>;\n \"pull_request.closed\": Record<string, unknown>;\n \"pull_request.merged\": Record<string, unknown>;\n [key: string]: Record<string, unknown>;\n };\n twilio: {\n \"message.received\": Record<string, unknown>;\n \"message.sent\": Record<string, unknown>;\n \"call.completed\": Record<string, unknown>;\n [key: string]: Record<string, unknown>;\n };\n sendgrid: {\n delivered: Record<string, unknown>;\n bounce: Record<string, unknown>;\n open: Record<string, unknown>;\n click: Record<string, unknown>;\n [key: string]: Record<string, unknown>;\n };\n slack: {\n url_verification: Record<string, unknown>;\n event_callback: Record<string, unknown>;\n [key: string]: Record<string, unknown>;\n };\n discord: {\n PING: Record<string, unknown>;\n MESSAGE_CREATE: Record<string, unknown>;\n INTERACTION_CREATE: Record<string, unknown>;\n [key: string]: Record<string, unknown>;\n };\n livekit: {\n \"room.started\": Record<string, unknown>;\n \"room.finished\": Record<string, unknown>;\n \"participant.joined\": Record<string, unknown>;\n \"participant.left\": Record<string, unknown>;\n [key: string]: Record<string, unknown>;\n };\n}\n\n/** Event handler function type. */\nexport type WebhookEventHandler<TEvent = Record<string, unknown>> = (\n event: TEvent,\n meta: WebhookMeta,\n) => Promise<void>;\n\n/** Provider-based webhook configuration. */\nexport interface ProviderWebhookConfig<P extends WebhookProvider = WebhookProvider> {\n provider: P;\n secret: EnvSecretRef;\n events: {\n [K in keyof ProviderEventMap[P]]?: WebhookEventHandler<ProviderEventMap[P][K]>;\n };\n}\n\n/** Incoming request representation for custom verify functions. */\nexport interface WebhookRequest {\n headers: Record<string, string>;\n body: string;\n method: string;\n url: string;\n}\n\n/** Custom webhook configuration. */\nexport interface CustomWebhookConfig {\n path: string;\n verify?: (req: WebhookRequest) => Promise<boolean> | boolean;\n handler: (payload: Record<string, unknown>, meta: WebhookMeta) => Promise<void>;\n}\n\n/** Resolved provider webhook (internal). */\nexport interface ResolvedProviderWebhook<P extends WebhookProvider = WebhookProvider> {\n type: \"provider\";\n provider: P;\n secret: EnvSecretRef;\n events: Record<string, WebhookEventHandler>;\n}\n\n/** Resolved custom webhook (internal). */\nexport interface ResolvedCustomWebhook {\n type: \"custom\";\n path: string;\n verify?: (req: WebhookRequest) => Promise<boolean> | boolean;\n handler: (payload: Record<string, unknown>, meta: WebhookMeta) => Promise<void>;\n}\n\n/** Union of resolved webhook types. */\nexport type ResolvedWebhookConfig = ResolvedProviderWebhook | ResolvedCustomWebhook;\n\n/** Valid webhook path pattern: starts with /, alphanumeric + hyphen + slash. */\nconst VALID_WEBHOOK_PATH = /^\\/[a-zA-Z0-9/_-]+$/;\n\n/**\n * Define a provider-based webhook.\n *\n * @example\n * ```ts\n * export default defineWebhook({\n * provider: \"stripe\",\n * secret: { env: \"STRIPE_WEBHOOK_SECRET\" },\n * events: {\n * \"checkout.session.completed\": async (event, meta) => {\n * await Database.insert(\"orders\", { status: \"paid\" });\n * },\n * },\n * });\n * ```\n */\nexport function defineWebhook<P extends WebhookProvider>(\n config: ProviderWebhookConfig<P>,\n): ResolvedProviderWebhook<P>;\n\n/**\n * Define a custom webhook with optional verification.\n *\n * @example\n * ```ts\n * export default defineWebhook({\n * path: \"/webhooks/livekit\",\n * verify: async (req) => req.headers[\"x-api-key\"] === \"secret\",\n * handler: async (payload, meta) => {\n * Log.info(\"Received webhook\", payload);\n * },\n * });\n * ```\n */\nexport function defineWebhook(config: CustomWebhookConfig): ResolvedCustomWebhook;\n\nexport function defineWebhook(\n config: ProviderWebhookConfig | CustomWebhookConfig,\n): ResolvedWebhookConfig {\n if (\"provider\" in config) {\n return validateProviderWebhook(config);\n }\n return validateCustomWebhook(config);\n}\n\nfunction validateProviderWebhook<P extends WebhookProvider>(\n config: ProviderWebhookConfig<P>,\n): ResolvedProviderWebhook<P> {\n if (!config.provider) {\n throw new Error(\"Webhook provider is required\");\n }\n\n const validProviders: WebhookProvider[] = [\n \"stripe\", \"github\", \"twilio\", \"sendgrid\", \"slack\", \"discord\", \"livekit\",\n ];\n if (!validProviders.includes(config.provider)) {\n throw new Error(\n `Invalid webhook provider \"${config.provider}\": must be one of ${validProviders.join(\", \")}`,\n );\n }\n\n if (!config.secret) {\n throw new Error(\"Webhook secret is required (use { env: \\\"SECRET_NAME\\\" })\");\n }\n\n if (typeof config.secret.env !== \"string\" || config.secret.env.trim() === \"\") {\n throw new Error(\"Webhook secret env name must be a non-empty string\");\n }\n\n if (!config.events || Object.keys(config.events).length === 0) {\n throw new Error(\"At least one event handler is required\");\n }\n\n for (const [eventName, handler] of Object.entries(config.events)) {\n if (typeof handler !== \"function\") {\n throw new Error(`Event handler for \"${eventName}\" must be a function`);\n }\n }\n\n return {\n type: \"provider\",\n provider: config.provider,\n secret: config.secret,\n events: config.events as Record<string, WebhookEventHandler>,\n };\n}\n\nfunction validateCustomWebhook(config: CustomWebhookConfig): ResolvedCustomWebhook {\n if (!config.path || config.path.trim() === \"\") {\n throw new Error(\"Webhook path is required\");\n }\n\n if (!VALID_WEBHOOK_PATH.test(config.path)) {\n throw new Error(\n `Invalid webhook path \"${config.path}\": must start with / and contain only alphanumeric, hyphen, underscore, slash`,\n );\n }\n\n if (!config.handler) {\n throw new Error(\"Webhook handler is required\");\n }\n\n if (typeof config.handler !== \"function\") {\n throw new Error(\"Webhook handler must be a function\");\n }\n\n if (config.verify !== undefined && typeof config.verify !== \"function\") {\n throw new Error(\"Webhook verify must be a function\");\n }\n\n return {\n type: \"custom\",\n path: config.path,\n verify: config.verify,\n handler: config.handler,\n };\n}\n","/**\n * resource.ts — external connections as lifecycle-managed classes.\n *\n * A `Resource` subclass models one external connection (a pooled datastore, a\n * stateless API client, or a per-user factory). The framework discovers each\n * instance, calls `init(env)` ONCE at boot with the declared secret subset, and\n * `shutdown()` (reverse order) on SIGTERM. On top of that lifecycle the author\n * exposes their own clean facade methods.\n *\n * // resources/neo4j.ts\n * import { Resource } from \"@palbase/backend\";\n * import neo4j, { type Driver, type Session } from \"neo4j-driver\";\n *\n * export class Neo4jResource extends Resource {\n * static secrets = [\"NEO4J_URL\", \"NEO4J_USER\", \"NEO4J_PASSWORD\"] as const;\n * private driver!: Driver;\n * async init(env: { NEO4J_URL: string; NEO4J_USER: string; NEO4J_PASSWORD: string }) {\n * this.driver = neo4j.driver(env.NEO4J_URL, neo4j.auth.basic(env.NEO4J_USER, env.NEO4J_PASSWORD));\n * }\n * async shutdown() { await this.driver.close(); }\n * session(): Session { return this.driver.session(); }\n * }\n * export const neo4j = new Neo4jResource(); // framework finds + manages it\n *\n * # Boot scope (NOT request-ALS)\n *\n * Resources are instantiated once at process boot. This is deliberately NOT the\n * per-request {@link AsyncLocalStorage} scope used for `Database`/`Cache`/… — a\n * connection pool must outlive a single request. The runtime discovers\n * resources from the project's `resources/` directory, registers each via\n * {@link __registerResource}, then calls {@link __runResourceBoot} before\n * serving and {@link __shutdownResources} on SIGTERM. Discovery is a runtime\n * concern; the SDK provides the base class + registry + boot/shutdown hooks.\n */\n\n/** Map a declared `secrets` tuple to the `init(env)` argument type — a record\n * over the secret names, each `string`. An empty tuple maps to an empty\n * record. */\nexport type ResourceEnv<Secrets extends readonly string[]> = {\n [K in Secrets[number]]: string;\n};\n\n/**\n * Base class for external connections.\n *\n * - `static secrets` — OPTIONAL readonly tuple of env-var names this resource\n * needs. Drives (a) the `env` type passed to `init` and (b) the\n * missing-secret check at boot (deploy fails naming the absent secret).\n * - `init(env)` — called ONCE at boot with the declared secret subset. May be\n * sync (`void`) or async (`Promise<void>`).\n * - `shutdown()` — OPTIONAL drain hook, called on SIGTERM in reverse boot\n * order.\n *\n * @example\n * import { Resource } from \"@palbase/backend\";\n * import { Client } from \"@googlemaps/google-maps-services-js\";\n *\n * export class GoogleResource extends Resource {\n * static secrets = [\"GOOGLE_MAPS_KEY\"] as const;\n * private client = new Client();\n * private key = \"\";\n * init(env: { GOOGLE_MAPS_KEY: string }) { this.key = env.GOOGLE_MAPS_KEY; }\n * }\n * export const google = new GoogleResource();\n */\nexport abstract class Resource {\n /** The env-var names this resource needs. Optional; omit for none. */\n static secrets?: readonly string[];\n\n /** Set up the connection from the declared secrets. Called once at boot. */\n abstract init(env: Record<string, string>): void | Promise<void>;\n\n /** Drain/close the connection on SIGTERM. Optional. */\n shutdown?(): void | Promise<void>;\n}\n\n/** A value carrying an optional readonly `secrets` tuple — the constructor side\n * of a Resource subclass. Narrowed from `unknown` via {@link hasSecrets}. */\ninterface WithSecrets {\n secrets?: readonly string[];\n}\n\n/** Guard: does this value carry a `secrets` array (the static on a Resource\n * subclass)? Lets us read `secrets` off `resource.constructor` (typed\n * `Function`) without a cast — narrows from `unknown` instead. */\nfunction hasSecrets(value: unknown): value is WithSecrets {\n if (typeof value !== \"object\" && typeof value !== \"function\") return false;\n const secrets = (value as { secrets?: unknown }).secrets;\n return secrets === undefined || Array.isArray(secrets);\n}\n\n/** A registered resource plus whether its `init` has already run. The\n * `booted` flag makes {@link __runResourceBoot} idempotent (re-running boot,\n * e.g. across a re-entrant deploy path, never re-inits). */\ninterface RegistryEntry {\n resource: Resource;\n booted: boolean;\n}\n\n/** Module-level boot registry. Single per process (the br-pod is\n * single-project). Order is registration order; shutdown reverses it. */\nconst registry: RegistryEntry[] = [];\n\n/**\n * Register a resource instance with the boot registry. The runtime calls this\n * for each instance discovered under the project's `resources/` directory.\n * NOT part of the public author-facing API (prefixed `__`).\n */\nexport function __registerResource(resource: Resource): void {\n registry.push({ resource, booted: false });\n}\n\n/** Read the declared `secrets` tuple off a resource instance's constructor. */\nfunction declaredSecrets(resource: Resource): readonly string[] {\n const ctor: unknown = resource.constructor;\n return hasSecrets(ctor) ? (ctor.secrets ?? []) : [];\n}\n\n/**\n * Boot every registered resource that has not yet been booted: resolve its\n * declared secret subset from `envMap`, then await its `init(env)`. Idempotent\n * — an already-booted resource is skipped. Throws (failing deploy/boot) when a\n * declared secret is absent, naming the missing secret. NOT part of the public\n * author-facing API.\n */\nexport async function __runResourceBoot(envMap: Record<string, string>): Promise<void> {\n for (const entry of registry) {\n if (entry.booted) continue;\n const secrets = declaredSecrets(entry.resource);\n const env: Record<string, string> = {};\n for (const name of secrets) {\n const value = envMap[name];\n if (value === undefined) {\n throw new Error(\n `Resource ${entry.resource.constructor.name} requires secret \"${name}\" but it is not set. ` +\n `Set it with \\`palbase secret set ${name} ...\\` (or in Studio) and redeploy.`,\n );\n }\n env[name] = value;\n }\n await entry.resource.init(env);\n entry.booted = true;\n }\n}\n\n/**\n * Shut down every booted resource in REVERSE registration order, awaiting each\n * `shutdown()` (a no-op when undefined). Clears the registry afterwards so a\n * second call is a no-op. NOT part of the public author-facing API.\n */\nexport async function __shutdownResources(): Promise<void> {\n for (let i = registry.length - 1; i >= 0; i -= 1) {\n const entry = registry[i]!;\n if (entry.booted && entry.resource.shutdown) {\n await entry.resource.shutdown();\n }\n }\n registry.length = 0;\n}\n\n/** Clear the registry without running shutdown. TEST-only helper so each test\n * starts from a clean registry. NOT part of the public author-facing API. */\nexport function __resetResources(): void {\n registry.length = 0;\n}\n","/** Non-service, per-invocation data for hook handlers.\n * Services (Database, Log, …) are imported as singletons, not passed here. */\nexport interface HookMeta {\n /** Branch-scoped env vars. */\n env: Record<string, string>;\n projectId: string;\n environmentId: string;\n}\n\n// --- Auth Event Payloads ---\n\n/** Payload for auth.onUserCreated hook. */\nexport interface UserCreatedEvent {\n user: {\n id: string;\n /** User's email, if they signed up with one (absent for phone-only users). */\n email?: string;\n role: string;\n metadata: Record<string, unknown>;\n createdAt: string;\n };\n}\n\n/** Payload for auth.onSignIn hook. */\nexport interface SignInEvent {\n user: {\n id: string;\n /** User's email, if they have one (absent for phone-only users). */\n email?: string;\n role: string;\n };\n provider: string;\n timestamp: string;\n}\n\n/** Payload for auth.onSignOut hook. */\nexport interface SignOutEvent {\n user: {\n id: string;\n /** User's email, if they have one (absent for phone-only users). */\n email?: string;\n };\n timestamp: string;\n}\n\n/** Payload for auth.onPasswordReset hook.\n * Password reset is inherently email-based, so `email` is always present here\n * (a phone-only passwordless user cannot trigger this event). */\nexport interface PasswordResetEvent {\n user: {\n id: string;\n email: string;\n };\n timestamp: string;\n}\n\n// --- Storage Event Payloads ---\n\n/** Payload for storage.onFileUploaded hook. */\nexport interface FileUploadedEvent {\n file: {\n id: string;\n name: string;\n bucket: string;\n path: string;\n size: number;\n contentType: string;\n };\n}\n\n/** Payload for storage.onFileDeleted hook. */\nexport interface FileDeletedEvent {\n file: {\n id: string;\n name: string;\n bucket: string;\n path: string;\n };\n}\n\n// --- Documents Event Payloads ---\n\n/** Payload for documents.onDocumentCreated hook. */\nexport interface DocumentCreatedEvent {\n document: {\n id: string;\n collection: string;\n data: Record<string, unknown>;\n };\n}\n\n/** Payload for documents.onDocumentUpdated hook. */\nexport interface DocumentUpdatedEvent {\n document: {\n id: string;\n collection: string;\n data: Record<string, unknown>;\n previousData: Record<string, unknown>;\n };\n}\n\n/** Payload for documents.onDocumentDeleted hook. */\nexport interface DocumentDeletedEvent {\n document: {\n id: string;\n collection: string;\n data: Record<string, unknown>;\n };\n}\n\n// --- Hook Handler Types ---\n\nexport type HookHandler<TEvent> = (event: TEvent, meta: HookMeta) => Promise<void>;\n\n/** Resolved hook configuration (internal). */\nexport interface ResolvedHook<TEvent = unknown> {\n module: string;\n event: string;\n handler: HookHandler<TEvent>;\n}\n\n// --- Auth Hooks ---\n\nexport const auth = {\n onUserCreated(handler: HookHandler<UserCreatedEvent>): ResolvedHook<UserCreatedEvent> {\n return { module: \"auth\", event: \"user.created\", handler };\n },\n\n onSignIn(handler: HookHandler<SignInEvent>): ResolvedHook<SignInEvent> {\n return { module: \"auth\", event: \"user.sign_in\", handler };\n },\n\n onSignOut(handler: HookHandler<SignOutEvent>): ResolvedHook<SignOutEvent> {\n return { module: \"auth\", event: \"user.sign_out\", handler };\n },\n\n onPasswordReset(handler: HookHandler<PasswordResetEvent>): ResolvedHook<PasswordResetEvent> {\n return { module: \"auth\", event: \"user.password_reset\", handler };\n },\n};\n\n// --- Storage Hooks ---\n\nexport const storage = {\n onFileUploaded(handler: HookHandler<FileUploadedEvent>): ResolvedHook<FileUploadedEvent> {\n return { module: \"storage\", event: \"file.uploaded\", handler };\n },\n\n onFileDeleted(handler: HookHandler<FileDeletedEvent>): ResolvedHook<FileDeletedEvent> {\n return { module: \"storage\", event: \"file.deleted\", handler };\n },\n};\n\n// --- Documents Hooks ---\n\nexport const documents = {\n onDocumentCreated(handler: HookHandler<DocumentCreatedEvent>): ResolvedHook<DocumentCreatedEvent> {\n return { module: \"documents\", event: \"document.created\", handler };\n },\n\n onDocumentUpdated(handler: HookHandler<DocumentUpdatedEvent>): ResolvedHook<DocumentUpdatedEvent> {\n return { module: \"documents\", event: \"document.updated\", handler };\n },\n\n onDocumentDeleted(handler: HookHandler<DocumentDeletedEvent>): ResolvedHook<DocumentDeletedEvent> {\n return { module: \"documents\", event: \"document.deleted\", handler };\n },\n};\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/runtime.ts","../src/db/policy.ts","../src/db/schema.ts","../src/db/extensions.ts","../src/db/columns.ts","../src/db/typed-db.ts","../src/db/env-gen.ts","../src/decorators/controller.ts","../src/decorators/registry.ts","../src/decorators/methods.ts","../src/decorators/params.ts","../src/middleware.ts","../src/errors.ts","../src/worker.ts","../src/job.ts","../src/webhook.ts","../src/resource.ts","../src/hooks.ts"],"sourcesContent":["export type {\n PBRequest,\n ClientInfo,\n RateLimitConfig,\n DBClient,\n DBOps,\n TxClient,\n FileContext,\n QueueClient,\n Logger,\n CacheClient,\n PalbaseDocsClient,\n PalbaseCollectionRef,\n PalbaseDocumentRef,\n PalbaseDocumentSnapshot,\n PalbaseQuerySnapshot,\n PalbaseWhereOperator,\n PalbaseResult,\n Middleware,\n ErrorDef,\n ErrorMap,\n ErrorThrowers,\n} from \"./endpoint.js\";\nexport {\n Database,\n Documents,\n Storage,\n Cache,\n Queue,\n Log,\n Notifications,\n Flags,\n __setRuntime,\n __runWithRuntime,\n __requestALS,\n __getRuntime,\n} from \"./runtime.js\";\nexport type { RuntimeServices } from \"./runtime.js\";\nexport type {\n PalbaseAuthClient,\n PalbaseStorageClient,\n PalbaseBucketClient,\n PalbaseRealtimeClient,\n PalbaseRealtimeChannel,\n PalbaseRealtimeMessage,\n PalbaseFunctionsClient,\n PalbaseInvokeOptions,\n PalbaseFlagsClient,\n PalbaseFlagContext,\n PalbaseFlagVariant,\n PalbaseFlag,\n PalbaseNotificationsClient,\n PalbasePushClient,\n PalbaseEmailClient,\n PalbaseSmsClient,\n PalbaseInboxClient,\n PalbasePreferencesClient,\n PalbaseAnalyticsClient,\n PalbaseAnalyticsQueryNamespace,\n PalbaseAnalyticsManagementNamespace,\n PalbaseLinksClient,\n PalbaseCmsClient,\n // Shared local types\n PalbaseUser,\n PalbaseSession,\n PalbaseDeviceInfo,\n PalbaseAttestAndroidParams,\n PalbaseAttestAndroidResult,\n PalbaseAttestiOSParams,\n PalbaseAttestiOSResult,\n PalbaseBindDeviceParams,\n PalbaseVerifyRequestSignatureParams,\n PalbaseFileObject,\n PalbaseSignedUrlResponse,\n PalbasePublicUrlResponse,\n PalbaseUploadOptions,\n PalbaseTransformOptions,\n PalbaseListOptions,\n PalbasePushSendParams,\n PalbasePushSendResponse,\n PalbaseEmailSendParams,\n PalbaseEmailSendResponse,\n PalbaseSmsSendParams,\n PalbaseSmsSendResponse,\n PalbaseInboxSendParams,\n PalbaseInboxSendResponse,\n PalbaseInboxMessage,\n PalbaseInboxListOptions,\n PalbaseInboxListResult,\n PalbasePreferences,\n PalbaseRegisterDeviceParams,\n PalbaseDeviceTokenView,\n PalbaseMultiChannelResponse,\n PalbaseAnalyticsProperties,\n PalbaseIdentifyTraits,\n PalbaseCountQueryInput,\n PalbaseCountResult,\n PalbaseEventsQueryInput,\n PalbaseEventsResult,\n PalbaseUsersQueryInput,\n PalbaseUsersResult,\n PalbaseFunnelQueryInput,\n PalbaseFunnelResult,\n PalbaseRetentionQueryInput,\n PalbaseRetentionResult,\n PalbaseCohortQueryInput,\n PalbaseCohortResult,\n PalbaseOverviewResult,\n PalbaseEventNamesResult,\n PalbaseUserDetailResult,\n PalbaseCreateLinkParams,\n PalbaseUpdateLinkParams,\n PalbaseLink,\n PalbaseLinkDetails,\n PalbaseLinkAnalytics,\n PalbaseQrCodeOptions,\n PalbaseMatchParams,\n PalbaseInitialLink,\n PalbaseListLinksOptions,\n PalbaseListLinksResult,\n PalbaseCmsFindOptions,\n PalbaseCmsFindOneOptions,\n} from \"./clients.js\";\nexport { defineSchema } from \"./db/schema.js\";\nexport type { SchemaDef, TableDef, TableInput, ColumnMap, SchemaInput } from \"./db/schema.js\";\nexport { policy, PolicyBuilder } from \"./db/policy.js\";\nexport type { PolicyDef, PolicyCommand, PolicyMode } from \"./db/policy.js\";\nexport { PALBASE_EXTENSIONS, EXTENSION_DEPENDENCIES, isPalbaseExtension } from \"./db/extensions.js\";\nexport type { PalbaseExtension } from \"./db/extensions.js\";\nexport { uuid, text, integer, boolean, timestamp, jsonb, enumType } from \"./db/columns.js\";\nexport type { ColumnBuilder, ColumnDef, ColumnType, OnDeleteAction } from \"./db/columns.js\";\nexport { makeTypedDB } from \"./db/typed-db.js\";\nexport type {\n TypedDB,\n TypedTx,\n TypedTable,\n InsertShape,\n RowShape,\n EnvTypedDatabase,\n EnvServiceDatabase,\n EnvTypedTx,\n EnvTypedTable,\n EnvTables,\n} from \"./db/typed-db.js\";\nexport type { Tables, TableTypes } from \"./db/env.js\";\nexport { makeEnvDts } from \"./db/env-gen.js\";\n// Class-controller decorator model (replaces defineController/defineHandler/route).\nexport { Controller } from \"./decorators/controller.js\";\nexport type { ControllerOptions } from \"./decorators/controller.js\";\nexport { Get, Post, Put, Patch, Delete } from \"./decorators/methods.js\";\nexport {\n Body,\n Query,\n Headers,\n Param,\n User,\n OptionalUser,\n Client,\n RequestId,\n TraceId,\n Req,\n} from \"./decorators/params.js\";\nexport type { RouteOptions, HttpMethodUpper } from \"./decorators/registry.js\";\nexport { defineMiddleware } from \"./middleware.js\";\nexport type { MiddlewareContext, MiddlewareHandler } from \"./middleware.js\";\n// The authenticated-user TYPE is exported as `UserT` (not `User`) because the\n// value name `User` is the @User() parameter decorator (exported above). A\n// controller annotates `@User() user: UserT` — decorator for the value\n// position, `UserT` for the type. (NestJS-style: same name as the decorator\n// would collide in the value+type namespaces.)\nexport type { User as UserT, HttpMethod, AuthConfig } from \"./types.js\";\nexport {\n HttpError,\n PalError,\n BadRequest,\n Unauthorized,\n Forbidden,\n NotFound,\n Conflict,\n TooManyRequests,\n} from \"./errors.js\";\nexport { defineWorker } from \"./worker.js\";\nexport type {\n WorkerConfig,\n ResolvedWorkerConfig,\n WorkerMeta,\n BackoffStrategy,\n} from \"./worker.js\";\nexport { defineJob } from \"./job.js\";\nexport type { JobConfig, ResolvedJobConfig, JobMeta } from \"./job.js\";\nexport { defineWebhook } from \"./webhook.js\";\nexport type {\n WebhookProvider,\n WebhookMeta,\n EnvSecretRef,\n ProviderWebhookConfig,\n CustomWebhookConfig,\n ResolvedProviderWebhook,\n ResolvedCustomWebhook,\n ResolvedWebhookConfig,\n WebhookEventHandler,\n WebhookRequest,\n ProviderEventMap,\n} from \"./webhook.js\";\nexport {\n Resource,\n __registerResource,\n __runResourceBoot,\n __shutdownResources,\n} from \"./resource.js\";\nexport type { ResourceEnv } from \"./resource.js\";\nexport { auth, storage, documents } from \"./hooks.js\";\nexport type {\n HookMeta,\n HookHandler,\n ResolvedHook,\n UserCreatedEvent,\n SignInEvent,\n SignOutEvent,\n PasswordResetEvent,\n FileUploadedEvent,\n FileDeletedEvent,\n DocumentCreatedEvent,\n DocumentUpdatedEvent,\n DocumentDeletedEvent,\n} from \"./hooks.js\";\nexport { z } from \"zod\";\n","/**\n * runtime.ts — request-scoped service singletons.\n *\n * The backend SDK no longer threads a `ctx` god-object through every handler.\n * Instead, controller methods import PascalCase service singletons directly:\n *\n * import { Controller, Post, Body, Database } from \"@palbase/backend\";\n *\n * \\@Controller(\"/todos\")\n * export default class TodosController {\n * \\@Post(\"\") create(\\@Body(CreateTodoBody) body: CreateTodoBody): unknown {\n * return Database.insert(\"todos\", { title: body.title });\n * }\n * }\n *\n * The singletons are thin Proxies. Every property access forwards to the live\n * client for the CURRENT request scope, resolved through {@link __getRuntime}.\n *\n * # Request-scope resolution (persistent app-server)\n *\n * The runtime is a long-running Node process that serves many concurrent\n * requests on one event loop (NOT a fresh subprocess per request). A single\n * module-global slot would let one in-flight request's services bleed into\n * another's. So the services are carried in an {@link AsyncLocalStorage} store\n * ({@link __requestALS}) that the runtime sets per request with\n * {@link __runWithRuntime}; every async continuation of that request reads its\n * own store. `__getRuntime` reads the ALS store first; the module-global slot\n * (set by {@link __setRuntime}) is only a fallback for callers that run OUTSIDE\n * an ALS scope (dev-server, unit tests, the legacy single-shot path). Because\n * each `br-<ref>` pod is single-tenant, there is no cross-tenant leakage; the\n * ALS store is what prevents cross-REQUEST leakage within the shared process.\n *\n * The seam that makes `import { Database } from \"@palbase/backend\"` resolve to\n * the runtime-injected client: `@palbase/backend` is marked esbuild-EXTERNAL\n * when the tenant bundle is built, and the package is installed globally in the\n * pod (NODE_PATH=/usr/local/lib/node_modules). So worker.js's\n * `require('@palbase/backend')` and the bundle's `import` resolve to ONE shared\n * module instance — the ALS store and `__setRuntime` slot on that instance are\n * visible to the singletons the bundle imported.\n */\n\nimport { AsyncLocalStorage } from \"node:async_hooks\";\n\nimport type {\n DBClient,\n DBOps,\n TxClient,\n CacheClient,\n QueueClient,\n Logger,\n PalbaseDocsClient,\n} from \"./endpoint.js\";\nimport type {\n PalbaseStorageClient,\n PalbaseNotificationsClient,\n PalbaseFlagsClient,\n} from \"./clients.js\";\nimport type {\n EnvTypedDatabase,\n EnvServiceDatabase,\n EnvTypedTx,\n EnvTables,\n} from \"./db/typed-db.js\";\n\n/** The set of live clients the runtime injects per request scope.\n *\n * EXCLUDED on purpose: Realtime, Functions, CMS, Links, Analytics, Auth. They\n * are not exposed as backend handler singletons (auth lives on the client SDK;\n * the rest are out of scope for backend endpoints). */\nexport interface RuntimeServices {\n Database: DBClient;\n Documents: PalbaseDocsClient;\n Storage: PalbaseStorageClient;\n Cache: CacheClient;\n Queue: QueueClient;\n Log: Logger;\n Notifications: PalbaseNotificationsClient;\n Flags: PalbaseFlagsClient;\n}\n\n/**\n * Per-request store. The persistent runtime runs each request inside\n * {@link __runWithRuntime}, so every async continuation of that request reads\n * its OWN `runtime` (and any other request-scoped fields the runtime adds).\n *\n * Exported with a `__` prefix so the runtime (worker.js) shares the SAME ALS\n * instance across the one module instance — two ALS instances would silently\n * not see each other's stores. NOT part of the public author-facing API.\n */\nexport const __requestALS = new AsyncLocalStorage<{ runtime: RuntimeServices }>();\n\n/** Process-global fallback slot. Used only OUTSIDE an ALS scope (dev-server,\n * unit tests, legacy single-shot worker). Inside the persistent server every\n * request runs in {@link __requestALS}, which takes precedence. */\nlet runtime: RuntimeServices | null = null;\n\n/** Install the live clients in the process-global fallback slot.\n *\n * Persistent-server requests should use {@link __runWithRuntime} instead; this\n * remains for dev-server / tests / the legacy single-shot path that run without\n * an ALS scope. NOT part of the public author-facing API. */\nexport function __setRuntime(services: RuntimeServices): void {\n runtime = services;\n}\n\n/** Run `fn` with `services` bound as the request-scoped runtime.\n *\n * The persistent worker calls this once per request so concurrent requests\n * never share a services slot. NOT part of the public author-facing API. */\nexport function __runWithRuntime<T>(services: RuntimeServices, fn: () => T): T {\n return __requestALS.run({ runtime: services }, fn);\n}\n\n/** Read the live clients, throwing if accessed outside a request scope.\n *\n * Resolves the ALS store first (persistent server, per-request), then the\n * process-global fallback (dev-server / tests). NOT part of the public\n * author-facing API — used by the runtime and the singleton Proxies. */\nexport function __getRuntime(): RuntimeServices {\n const scoped = __requestALS.getStore();\n if (scoped) return scoped.runtime;\n if (runtime === null) {\n throw new Error(\n \"Palbase services accessed outside a request scope. The Database/Documents/… \" +\n \"singletons are only available inside an endpoint handler (or after the \" +\n \"runtime has called __runWithRuntime / __setRuntime).\",\n );\n }\n return runtime;\n}\n\n/**\n * Build a Proxy singleton that forwards every property access to the live\n * client named `key` on the current runtime.\n *\n * The single `as RuntimeServices[K]` is the only contained cast in the surface:\n * `Reflect.get` on a typed object returns `unknown` for a `string | symbol`\n * key, but `prop` is constrained to keys of the client interface at the call\n * sites (the exported singletons are typed below), so the forward is sound.\n */\nfunction makeServiceProxy<K extends keyof RuntimeServices>(key: K): RuntimeServices[K] {\n const handler: ProxyHandler<RuntimeServices[K]> = {\n get(_target, prop, receiver) {\n const client = __getRuntime()[key];\n const value = Reflect.get(client as object, prop, receiver) as unknown;\n // Bind methods to their owning client so `this` stays correct when the\n // author destructures or calls `Database.query(...)`.\n return typeof value === \"function\" ? value.bind(client) : value;\n },\n };\n // The Proxy target is irrelevant (all access goes through `get`); the cast\n // names the surface type the singleton presents to authors.\n return new Proxy({} as RuntimeServices[K], handler);\n}\n\n/**\n * Build the `.tables` accessor for an op-bearing client (the top-level\n * `Database` or a transaction-scoped `tx`). Each `tables.<name>` access\n * returns a small object that forwards the five CRUD ops to the underlying\n * client using `name` as the string table identifier. The shapes are typed\n * against the generated `palbase-env.d.ts` (`EnvTables`); at runtime they are\n * plain string-keyed calls, so no schema value is needed here.\n *\n * Returns `EnvTables` — TS cannot infer the mapped type through the Proxy, so\n * a single structural narrowing names the surface (the proxy returns a\n * correctly-shaped accessor for whatever string member is read).\n */\nfunction makeTablesAccessor(ops: () => TxClient): EnvTables {\n const tablesProxy = new Proxy(\n {},\n {\n get(_t, prop: string | symbol) {\n if (typeof prop !== \"string\") return undefined;\n const name = prop;\n return {\n insert: (data: Record<string, unknown>) => ops().insert(name, data),\n update: (id: string, data: Record<string, unknown>) => ops().update(name, id, data),\n delete: (id: string) => ops().delete(name, id),\n findById: (id: string) => ops().findById(name, id),\n findMany: (query?: Record<string, unknown>) => ops().findMany(name, query),\n };\n },\n },\n );\n return tablesProxy as EnvTables;\n}\n\n/** The raw string-keyed `DBClient` for the current request scope. */\nconst rawDatabase: DBClient = makeServiceProxy(\"Database\");\n\n/**\n * Wrap a raw `DBClient` into the typed `{ ...ops, tables, transaction }`\n * surface. The five string ops forward straight through; `tables` is the\n * env-typed accessor; `transaction` yields typed tables. Reused for both the\n * default (RLS-enforced) `Database` and the `asService()` sibling — each is\n * fed its own raw client (the default proxy vs `rawDatabase.asService()`).\n *\n * The `satisfies` pins the op surface so a missing/renamed op is a compile\n * error; the assembled object carries `tables`/`transaction` alongside.\n */\nfunction makeTypedSurface(raw: Omit<DBClient, \"asService\">): EnvServiceDatabase {\n const ops = {\n query: (sql: string, params?: unknown[]) => raw.query(sql, params),\n insert: (table: string, data: Record<string, unknown>) => raw.insert(table, data),\n update: (table: string, id: string, data: Record<string, unknown>) =>\n raw.update(table, id, data),\n delete: (table: string, id: string) => raw.delete(table, id),\n findById: (table: string, id: string) => raw.findById(table, id),\n findMany: (table: string, query?: Record<string, unknown>) => raw.findMany(table, query),\n } satisfies DBOps;\n return Object.assign(ops, {\n tables: makeTablesAccessor(() => raw),\n transaction<T>(fn: (tx: EnvTypedTx) => Promise<T>): Promise<T> {\n return raw.transaction((rawTx) => fn({ tables: makeTablesAccessor(() => rawTx) }));\n },\n });\n}\n\n/**\n * The project's own Postgres (pgx, schema `env_<envId>`).\n *\n * Typed by default: `Database.tables.<name>.insert({...})` is typed against\n * the project's generated `palbase-env.d.ts` with NO import and NO generic.\n * The raw string ops (`query`/`insert`/`update`/`delete`/`findById`/`findMany`)\n * are also available for dynamic table names and read-only SQL.\n *\n * RLS is enforced by default (the runtime runs each op as `authenticated` with\n * the verified user's claims). To bypass RLS, call `Database.asService()` —\n * explicit and greppable — which runs as the `service_role` (BYPASSRLS).\n *\n * @example\n * import { Database } from \"@palbase/backend\";\n *\n * const todo = await Database.tables.todos.insert({ title: req.input.title });\n * todo.id; // string ✓\n * const rows = await Database.query(\"SELECT id FROM todos WHERE done = $1\", [false]);\n * const all = await Database.asService().tables.todos.findMany({}); // RLS bypass\n */\nexport const Database: EnvTypedDatabase = Object.assign(makeTypedSurface(rawDatabase), {\n /**\n * Lazily resolve the runtime's service-role sibling on each call. We do NOT\n * cache it: `rawDatabase.asService()` reads the CURRENT request scope through\n * the runtime proxy, and the per-request runtime injects a service client\n * bound to that request's identity headers — caching would leak one request's\n * sibling into another concurrent request.\n */\n asService(): EnvServiceDatabase {\n return makeTypedSurface(rawDatabase.asService());\n },\n});\n\n/** Firestore-like document client (PalDocs). */\nexport const Documents: PalbaseDocsClient = makeServiceProxy(\"Documents\");\n\n/** Object storage client (buckets, signed URLs). */\nexport const Storage: PalbaseStorageClient = makeServiceProxy(\"Storage\");\n\n/** JSON-typed cache (get/set/incr/getOrSet). */\nexport const Cache: CacheClient = makeServiceProxy(\"Cache\");\n\n/** Background job queue. */\nexport const Queue: QueueClient = makeServiceProxy(\"Queue\");\n\n/** Structured logger. */\nexport const Log: Logger = makeServiceProxy(\"Log\");\n\n/** Push / email / SMS / in-app notifications. */\nexport const Notifications: PalbaseNotificationsClient = makeServiceProxy(\"Notifications\");\n\n/** Feature flags. */\nexport const Flags: PalbaseFlagsClient = makeServiceProxy(\"Flags\");\n","/**\n * policy.ts — the RLS policy authoring DSL.\n *\n * `policy(name)` returns a fluent builder that mirrors the `ColumnBuilder`\n * style in columns.ts: each chainable method mutates the underlying\n * definition and returns the builder so calls compose. The terminal value is\n * a plain {@link PolicyDef} — the exact JSON shape the runtime's\n * `schema_extract.js` reads off the bundled module and the Go side parses into\n * `PolicyJSON` (CONTRACT-POLICY).\n *\n * @example\n * import { policy } from \"@palbase/backend\";\n *\n * policy(\"owner_select\")\n * .for(\"select\")\n * .to(\"authenticated\")\n * .using(\"owner = (select auth.uid())\");\n */\n\n/** The SQL command a policy applies to. `\"all\"` covers SELECT/INSERT/UPDATE/DELETE. */\nexport type PolicyCommand = \"all\" | \"select\" | \"insert\" | \"update\" | \"delete\";\n\n/** Whether a policy is permissive (OR-combined, the default) or restrictive\n * (AND-combined). Mirrors Postgres `CREATE POLICY ... AS PERMISSIVE|RESTRICTIVE`. */\nexport type PolicyMode = \"permissive\" | \"restrictive\";\n\n/**\n * The compiled, serializable policy definition — the EXACT shape consumed by\n * `schema_extract.js` → Go `PolicyJSON` (CONTRACT-POLICY).\n *\n * - `roles`: the DB roles this policy applies to (`TO` clause). An empty array\n * means the policy applies to PUBLIC (all roles) — the Postgres default.\n * - `using`: the `USING (...)` row-visibility expression, or `null` when none.\n * - `withCheck`: the `WITH CHECK (...)` write-validation expression, or `null`.\n * - `permissive`: `true` for `AS PERMISSIVE` (default), `false` for restrictive.\n */\nexport interface PolicyDef {\n name: string;\n command: PolicyCommand;\n roles: string[];\n using: string | null;\n withCheck: string | null;\n permissive: boolean;\n}\n\n/**\n * Fluent RLS policy builder.\n *\n * Defaults (documented, applied at construction):\n * - `command`: `\"all\"` — applies to every SQL command unless `.for(...)` narrows it.\n * - `roles`: `[\"authenticated\"]` — the common case is \"rule applies to signed-in\n * users\". Call `.to(...)` to override; pass `.to()` with no roles (or never\n * call it after a reset) to target PUBLIC.\n * - `using` / `withCheck`: `null` — no row filter / write check until set.\n * - `permissive`: `true` — `AS PERMISSIVE` (policies OR together).\n *\n * Each method mutates `_def` in place and returns `this`, so the chain is a\n * single builder instance (no per-call allocation, like a tagged-template\n * compile target). The terminal `PolicyDef` is read directly off `_def` by\n * `schema_extract.js`.\n */\nexport class PolicyBuilder {\n readonly _def: PolicyDef;\n\n constructor(name: string) {\n this._def = {\n name,\n command: \"all\",\n roles: [\"authenticated\"],\n using: null,\n withCheck: null,\n permissive: true,\n };\n }\n\n /** Restrict the policy to a single SQL command (default `\"all\"`). */\n for(command: PolicyCommand): this {\n this._def.command = command;\n return this;\n }\n\n /**\n * Set the DB roles the policy applies to (the `TO` clause), replacing any\n * previously-set roles. Call with no arguments to target PUBLIC (all roles).\n *\n * @example\n * policy(\"p\").to(\"authenticated\")\n * policy(\"p\").to(\"authenticated\", \"service_role\")\n * policy(\"p\").to() // PUBLIC\n */\n to(...roles: string[]): this {\n this._def.roles = roles;\n return this;\n }\n\n /** Set the `USING (...)` row-visibility expression (raw SQL). */\n using(sqlExpr: string): this {\n this._def.using = sqlExpr;\n return this;\n }\n\n /** Set the `WITH CHECK (...)` write-validation expression (raw SQL). */\n withCheck(sqlExpr: string): this {\n this._def.withCheck = sqlExpr;\n return this;\n }\n\n /** Set the policy mode: `\"permissive\"` (default, OR-combined) or\n * `\"restrictive\"` (AND-combined). */\n as(mode: PolicyMode): this {\n this._def.permissive = mode === \"permissive\";\n return this;\n }\n}\n\n/**\n * Start authoring an RLS policy. Returns a {@link PolicyBuilder}; the resulting\n * `PolicyBuilder` is accepted directly in a table's `policies: [...]` array\n * (its `_def` is read at schema-extract time).\n *\n * @param name The policy name. Palbase reconciliation keys policies by\n * `(table, name)`, so names must be unique per table.\n */\nexport function policy(name: string): PolicyBuilder {\n return new PolicyBuilder(name);\n}\n","import type { ColumnBuilder } from \"./columns.js\";\nimport { PolicyBuilder } from \"./policy.js\";\nimport type { PolicyDef } from \"./policy.js\";\nimport type { PalbaseExtension } from \"./extensions.js\";\n\n/**\n * A map of column builders keyed by column name — the value you write under\n * the `columns` key of `defineSchema({ tables: { <name>: { columns } } })`.\n *\n * The default `Record<string, ColumnBuilder>` keeps bare references compiling\n * without a type argument.\n */\nexport type ColumnMap = Record<string, ColumnBuilder>;\n\n/**\n * The author-facing value written under each table key:\n * `{ columns, rls?, policies? }`.\n *\n * - `columns`: the column map (required).\n * - `rls`: enable + FORCE row-level security on this table. Implied when\n * `policies` is non-empty; set it explicitly to enable RLS with no policies\n * yet (deny-all — useful only as an intermediate step).\n * - `policies`: the RLS policies for this table, authored with `policy(name)`.\n * Each entry may be a {@link PolicyBuilder} (the normal `policy(...)` chain)\n * or a raw {@link PolicyDef} object.\n *\n * The `C` type parameter preserves the precise per-column phantom types so the\n * typed `Database.tables.*` surface keeps inferring insert/row shapes.\n */\nexport interface TableInput<C extends ColumnMap = ColumnMap> {\n columns: C;\n rls?: boolean;\n policies?: (PolicyBuilder | PolicyDef)[];\n}\n\n/**\n * A table definition — the runtime value the Go runtime's `schema_extract.js`\n * reads. It keys tables by `tableDef.name`, reads `tableDef.columns` for the\n * column DDL, and `tableDef.rls` + `tableDef.policies` for RLS.\n *\n * `defineSchema` derives `name` from the object key, so authors never repeat\n * the table name. `rls`/`policies` are always present after normalization\n * (defaulted to `false`/`[]`).\n *\n * The `C` type parameter preserves the precise per-column phantom types so that\n * downstream mapped types (InsertShape, RowShape) can discriminate on them.\n */\nexport interface TableDef<C extends ColumnMap = ColumnMap> {\n name: string;\n columns: C;\n rls: boolean;\n policies: PolicyDef[];\n}\n\n/**\n * A schema definition containing multiple tables, keyed by table name.\n *\n * The `T` type parameter preserves the exact `TableDef<...>` type for each\n * table so that `SchemaDef[\"tables\"][\"rooms\"]` resolves to the precise\n * `TableDef<{ id: ColumnBuilder<'uuid', false, true, never>; ... }>`.\n */\nexport interface SchemaDef<\n T extends Record<string, TableDef> = Record<string, TableDef>,\n> {\n tables: T;\n /** Postgres extensions to install on deploy. Normalized to `[]` when absent. */\n extensions: PalbaseExtension[];\n}\n\n/** The author-facing input to `defineSchema` — a `tables` map whose keys are\n * the table names and whose values are `{ columns, rls?, policies? }`, plus an\n * optional `extensions` allowlist. */\nexport interface SchemaInput<\n T extends Record<string, TableInput> = Record<string, TableInput>,\n> {\n tables: T;\n /**\n * Postgres extensions to enable for this project, e.g. `[\"vector\"]`.\n * Config-as-code: installed by the deploy (CREATE EXTENSION … SCHEMA\n * extensions) with the privileged deploy connection. The type is an\n * allowlist union, so unsupported names fail typecheck.\n */\n extensions?: PalbaseExtension[];\n}\n\n/** Map the author's `{ tables: { <name>: { columns } } }` input to the\n * `{ tables: { <name>: TableDef<columns> } }` runtime/type shape, threading the\n * per-table column map `T[K][\"columns\"]` so column-level inference survives. */\ntype TablesFromInput<T extends Record<string, TableInput>> = {\n [K in keyof T]: TableDef<T[K][\"columns\"]>;\n};\n\n/** Normalize a single `policies` entry into a plain `PolicyDef` (read off a\n * `PolicyBuilder._def`, or passed through when already a `PolicyDef`). */\nfunction toPolicyDef(p: PolicyBuilder | PolicyDef): PolicyDef {\n return p instanceof PolicyBuilder ? p._def : p;\n}\n\n/**\n * Define a schema. The table NAME comes from the object key. Each table value\n * is `{ columns, rls?, policies? }`:\n *\n * export default defineSchema({\n * tables: {\n * todos: {\n * columns: {\n * id: uuid().primaryKey().defaultRandom(),\n * owner: text().notNull(),\n * title: text().notNull(),\n * },\n * rls: true,\n * policies: [\n * policy(\"owner_all\").for(\"all\").to(\"authenticated\")\n * .using(\"owner = (select auth.uid())\")\n * .withCheck(\"owner = (select auth.uid())\"),\n * ],\n * },\n * },\n * });\n *\n * The returned value is\n * `{ tables: { todos: { name, columns, rls, policies } } }` — the exact shape\n * the runtime schema extractor parses. Per-column phantom types are preserved\n * so `Database.tables.todos.insert({...})` stays typed.\n *\n * RLS normalization: `rls` defaults to `false`, `policies` to `[]`. When\n * `policies` is non-empty, `rls` is forced on (ENABLE + FORCE) regardless of\n * the declared `rls` flag — a table with policies must have RLS enabled or the\n * policies would be inert.\n */\nexport function defineSchema<T extends Record<string, TableInput>>(\n input: SchemaInput<T>,\n): SchemaDef<TablesFromInput<T>> {\n const tables = {} as TablesFromInput<T>;\n for (const name of Object.keys(input.tables) as (keyof T)[]) {\n const table = input.tables[name];\n // `noUncheckedIndexedAccess` widens the index access to `… | undefined`,\n // but `name` comes straight from `Object.keys(input.tables)`, so the entry\n // always exists. Guard to narrow without a cast.\n if (table === undefined) continue;\n const policies = (table.policies ?? []).map(toPolicyDef);\n // A table with policies must have RLS enabled, otherwise the policies are\n // inert. Enabling RLS without policies (deny-all) is allowed explicitly.\n const rls = table.rls === true || policies.length > 0;\n tables[name] = {\n name: name as string,\n columns: table.columns,\n rls,\n policies,\n };\n }\n // Dedupe + normalize extensions (order-independent; deploy resolves deps).\n const extensions = [...new Set(input.extensions ?? [])];\n return { tables, extensions };\n}\n","/**\n * Postgres extensions a Palbase project can enable from its schema.\n *\n * Extensions are config-as-code: declare them in `defineSchema({ extensions })`\n * and the deploy installs them (CREATE EXTENSION … SCHEMA extensions) using the\n * deploy path's privileged connection. They are NOT toggled live from Studio —\n * CREATE EXTENSION requires a superuser role that only the deploy path holds.\n *\n * The list is an allowlist (a string-literal union) so editors autocomplete the\n * supported names and a typo fails typecheck. It is intentionally extensible:\n * add a name here (+ confirm the base image ships it) to support more.\n */\nexport const PALBASE_EXTENSIONS = [\n // Search & text\n \"vector\", // pgvector: AI embeddings + vector similarity search (semantic search / RAG).\n // NB: the Postgres extension is named \"vector\", not \"pgvector\" — declare \"vector\".\n \"pg_trgm\", // trigram fuzzy / typo-tolerant text search\n \"unaccent\", // accent-insensitive text search\n \"citext\", // case-insensitive text type\n // Geospatial / location\n \"postgis\", // geospatial types + queries (maps, \"near me\")\n \"cube\", // multi-dimensional cubes (dependency of earthdistance)\n \"earthdistance\", // great-circle distance (needs cube)\n // Data types & structures\n \"hstore\", // key/value pairs in a single column\n \"ltree\", // hierarchical tree-structured labels\n // Scheduling\n \"pg_cron\", // schedule jobs inside the database\n // Crypto / ids (also installed by default; listable for explicitness)\n \"pgcrypto\", // cryptographic functions (hashing, encryption)\n \"uuid-ossp\", // UUID generation functions\n] as const;\n\n/** A Postgres extension supported by Palbase (allowlist union). */\nexport type PalbaseExtension = (typeof PALBASE_EXTENSIONS)[number];\n\n/**\n * Extensions that depend on another extension. The deploy installs\n * dependencies first; declaring `earthdistance` without `cube` still works\n * because the deploy resolves the order, but listing both is clearer.\n */\nexport const EXTENSION_DEPENDENCIES: Partial<Record<PalbaseExtension, PalbaseExtension[]>> = {\n earthdistance: [\"cube\"],\n};\n\n/** Runtime guard: is `name` a supported Palbase extension? */\nexport function isPalbaseExtension(name: string): name is PalbaseExtension {\n return (PALBASE_EXTENSIONS as readonly string[]).includes(name);\n}\n","/** On delete action for foreign key references. */\nexport type OnDeleteAction = 'cascade' | 'set null' | 'restrict' | 'no action';\n\n/** Column type identifiers. */\nexport type ColumnType = 'uuid' | 'text' | 'integer' | 'boolean' | 'timestamp' | 'jsonb' | 'enum';\n\n/** Base column definition shared by all column types. */\nexport interface ColumnDef {\n type: ColumnType;\n nullable: boolean;\n primaryKey: boolean;\n defaultValue?: unknown;\n defaultRandom?: boolean;\n defaultNow?: boolean;\n references?: { table: string; column: string };\n onDeleteAction?: OnDeleteAction;\n enumName?: string;\n enumValues?: string[];\n}\n\n// Phantom brand symbols — never have runtime values; exist only to force\n// TypeScript's structural type system to distinguish ColumnBuilder instances\n// with different type-param combinations. Without these, TS sees all\n// ColumnBuilder<K,...> as structurally identical and the first branch of\n// ColValue matches everything.\ndeclare const __colKind: unique symbol;\ndeclare const __colNullable: unique symbol;\ndeclare const __colHasDefault: unique symbol;\ndeclare const __colEnumValues: unique symbol;\n\n/**\n * Fluent column builder with phantom type params:\n * K — ColumnType literal (e.g. \"text\", \"integer\")\n * N — boolean: true when nullable() has been called last (false = NOT NULL)\n * D — boolean: true when a default has been set\n * E — enum value union (never for non-enum columns)\n *\n * All four params have defaults so bare `ColumnBuilder` (no args) still\n * satisfies `Record<string, ColumnBuilder>` in schema.ts without modification.\n *\n * The four `declare readonly` brand fields carry the phantom types into the\n * structural shape so that conditional types like ColValue<C> can discriminate\n * on K without requiring runtime values on those fields.\n */\nexport class ColumnBuilder<\n K extends ColumnType = ColumnType,\n N extends boolean = boolean,\n D extends boolean = boolean,\n E = unknown,\n> {\n // These fields exist only in the type layer (declared, never initialised at\n // runtime — TypeScript allows declared class members without an initializer\n // in strict mode as long as they're never read at runtime).\n declare readonly [__colKind]: K;\n declare readonly [__colNullable]: N;\n declare readonly [__colHasDefault]: D;\n declare readonly [__colEnumValues]: E;\n\n readonly _def: ColumnDef;\n\n constructor(type: K, existingDef?: ColumnDef) {\n this._def = existingDef ?? {\n type,\n nullable: false,\n primaryKey: false,\n };\n }\n\n /** Mark this column as the primary key. */\n primaryKey(): ColumnBuilder<K, N, D, E> {\n this._def.primaryKey = true;\n return new ColumnBuilder<K, N, D, E>(this._def.type as K, this._def);\n }\n\n /** Mark this column as NOT NULL (default). */\n notNull(): ColumnBuilder<K, false, D, E> {\n this._def.nullable = false;\n return new ColumnBuilder<K, false, D, E>(this._def.type as K, this._def);\n }\n\n /** Allow NULL values. */\n nullable(): ColumnBuilder<K, true, D, E> {\n this._def.nullable = true;\n return new ColumnBuilder<K, true, D, E>(this._def.type as K, this._def);\n }\n\n /** Set a default value. */\n default(value: unknown): ColumnBuilder<K, N, true, E> {\n this._def.defaultValue = value;\n return new ColumnBuilder<K, N, true, E>(this._def.type as K, this._def);\n }\n\n /** UUID: generate a random default (gen_random_uuid()). */\n defaultRandom(): ColumnBuilder<K, N, true, E> {\n this._def.defaultRandom = true;\n return new ColumnBuilder<K, N, true, E>(this._def.type as K, this._def);\n }\n\n /** Timestamp: default to now(). */\n defaultNow(): ColumnBuilder<K, N, true, E> {\n this._def.defaultNow = true;\n return new ColumnBuilder<K, N, true, E>(this._def.type as K, this._def);\n }\n\n /** Add a foreign key reference. */\n references(table: string, column: string): ColumnBuilder<K, N, D, E> {\n this._def.references = { table, column };\n return new ColumnBuilder<K, N, D, E>(this._def.type as K, this._def);\n }\n\n /** Set the ON DELETE action for a foreign key reference. */\n onDelete(action: OnDeleteAction): ColumnBuilder<K, N, D, E> {\n this._def.onDeleteAction = action;\n return new ColumnBuilder<K, N, D, E>(this._def.type as K, this._def);\n }\n}\n\n// ---------------------------------------------------------------------------\n// Type extractors — imported by Task 2 to derive insert/row shapes.\n// ---------------------------------------------------------------------------\n\n/**\n * Extracts the TypeScript value type for a column, respecting nullability.\n * - \"uuid\" | \"text\" | \"timestamp\" → string (or string | null when N = true)\n * - \"integer\" → number\n * - \"boolean\" → boolean\n * - \"jsonb\" → unknown (opaque JSON)\n * - \"enum\" → E (the union of literal values)\n */\nexport type ColValue<C> =\n C extends ColumnBuilder<'uuid' | 'text' | 'timestamp', infer N, infer _D, infer _E>\n ? N extends true\n ? string | null\n : string\n : C extends ColumnBuilder<'integer', infer N, infer _D, infer _E>\n ? N extends true\n ? number | null\n : number\n : C extends ColumnBuilder<'boolean', infer N, infer _D, infer _E>\n ? N extends true\n ? boolean | null\n : boolean\n : C extends ColumnBuilder<'jsonb', infer _N, infer _D, infer _E>\n ? unknown\n : C extends ColumnBuilder<'enum', infer N, infer _D, infer E>\n ? N extends true\n ? E | null\n : E\n : never;\n\n/**\n * True when a column is optional on INSERT:\n * - nullable columns (N = true) — the DB allows NULL so the field may be omitted\n * - columns with a default (D = true) — the DB fills in the value when absent\n */\nexport type ColIsOptionalOnInsert<C> =\n C extends ColumnBuilder<infer _K, true, infer _D, infer _E>\n ? true\n : C extends ColumnBuilder<infer _K, infer _N, true, infer _E>\n ? true\n : false;\n\n// ---------------------------------------------------------------------------\n// Factory functions\n// ---------------------------------------------------------------------------\n\n/** Create a UUID column. */\nexport function uuid(): ColumnBuilder<'uuid', false, false, never> {\n return new ColumnBuilder('uuid');\n}\n\n/** Create a TEXT column. */\nexport function text(): ColumnBuilder<'text', false, false, never> {\n return new ColumnBuilder('text');\n}\n\n/** Create an INTEGER column. */\nexport function integer(): ColumnBuilder<'integer', false, false, never> {\n return new ColumnBuilder('integer');\n}\n\n/** Create a BOOLEAN column. */\nexport function boolean(): ColumnBuilder<'boolean', false, false, never> {\n return new ColumnBuilder('boolean');\n}\n\n/** Create a TIMESTAMP column. */\nexport function timestamp(): ColumnBuilder<'timestamp', false, false, never> {\n return new ColumnBuilder('timestamp');\n}\n\n/** Create a JSONB column. */\nexport function jsonb(): ColumnBuilder<'jsonb', false, false, never> {\n return new ColumnBuilder('jsonb');\n}\n\n/**\n * Create an ENUM column.\n * @param name The PostgreSQL enum type name (used in DDL).\n * @param values A readonly tuple of valid string values — kept `const` so the\n * union `V[number]` is as narrow as possible.\n */\nexport function enumType<const V extends readonly string[]>(\n name: string,\n values: V,\n): ColumnBuilder<'enum', false, false, V[number]> {\n const builder = new ColumnBuilder<'enum', false, false, V[number]>('enum');\n builder._def.enumName = name;\n builder._def.enumValues = [...values];\n return builder;\n}\n","/**\n * typed-db.ts — Task 2: TypedDB schema-derived insert/row shapes.\n *\n * Derives INSERT and full-row TypeScript types from a `defineSchema()` result\n * and wraps the untyped runtime `DBClient` with a typed facade.\n *\n * No value-any. No `as unknown as X`. The two narrow `as` casts in\n * `makeTypedTable` are safe because:\n * - `data as Record<string, unknown>`: InsertShape<T> maps string keys to\n * typed values; all value types are subsets of `unknown`, so the cast is\n * structurally sound.\n * - `result as RowShape<T>`: The runtime DBClient returns `Record<string,\n * unknown>` which is the erased form of the typed row; we're narrowing back\n * to the precise shape that the schema declared.\n * Both casts are narrowing only (not widening) and correctness is guaranteed\n * by the schema the caller provides.\n */\n\nimport type { ColValue, ColIsOptionalOnInsert, ColumnBuilder } from \"./columns.js\";\nimport type { TableDef, SchemaDef } from \"./schema.js\";\nimport type { Tables, TableTypes } from \"./env.js\";\nimport type { DBClient, TxClient } from \"../endpoint.js\";\n\n// ---------------------------------------------------------------------------\n// Key discriminators — split a column map into required vs optional keys.\n// ---------------------------------------------------------------------------\n\n/** Keys of C whose columns are required on INSERT (not nullable, no default). */\ntype RequiredKeys<C> = {\n [K in keyof C]: ColIsOptionalOnInsert<C[K]> extends true ? never : K;\n}[keyof C];\n\n/** Keys of C whose columns are optional on INSERT (nullable or has a default). */\ntype OptionalKeys<C> = {\n [K in keyof C]: ColIsOptionalOnInsert<C[K]> extends true ? K : never;\n}[keyof C];\n\n// ---------------------------------------------------------------------------\n// Public shape types — exported so callers can reference them directly.\n// ---------------------------------------------------------------------------\n\n/**\n * The TypeScript type for an INSERT payload for table `T`.\n * - Required: columns that are NOT NULL and have no DB-level default.\n * - Optional: columns that are nullable or carry a default.\n *\n * When all columns are optional, `RequiredKeys<C>` resolves to `never` and\n * the first part becomes `{}`, which is a neutral element for `&`.\n */\nexport type InsertShape<T extends TableDef> = {\n [K in RequiredKeys<T[\"columns\"]>]: ColValue<T[\"columns\"][K]>;\n} & {\n [K in OptionalKeys<T[\"columns\"]>]?: ColValue<T[\"columns\"][K]>;\n};\n\n/**\n * The TypeScript type for a full row returned by the DB for table `T`.\n * Every column is present; nullable columns resolve to `T | null`.\n */\nexport type RowShape<T extends TableDef> = {\n [K in keyof T[\"columns\"]]: ColValue<T[\"columns\"][K]>;\n};\n\n// ---------------------------------------------------------------------------\n// TypedTable + TypedDB interfaces.\n// ---------------------------------------------------------------------------\n\n/** A typed table accessor that mirrors the runtime DBClient surface. */\nexport interface TypedTable<T extends TableDef> {\n insert(data: InsertShape<T>): Promise<RowShape<T>>;\n /** Update the row by id; resolves to the updated row, or `null` if no row\n * matched (absent or RLS-hidden) — an idempotent outcome, mirroring\n * `findById`. The runtime returns a null row rather than throwing. */\n update(id: string, data: Partial<InsertShape<T>>): Promise<RowShape<T> | null>;\n delete(id: string): Promise<void>;\n findById(id: string): Promise<RowShape<T> | null>;\n findMany(query?: Partial<RowShape<T>>): Promise<RowShape<T>[]>;\n}\n\n/** A typed DB facade covering all tables declared in schema `S`. */\nexport interface TypedDB<S extends SchemaDef> {\n tables: {\n [K in keyof S[\"tables\"]]: TypedTable<S[\"tables\"][K]>;\n };\n transaction<T>(fn: (tx: TypedTx<S>) => Promise<T>): Promise<T>;\n}\n\n/** Transaction-scoped typed facade: same typed tables, no nested transaction. */\nexport interface TypedTx<S extends SchemaDef> {\n tables: {\n [K in keyof S[\"tables\"]]: TypedTable<S[\"tables\"][K]>;\n };\n}\n\n// ---------------------------------------------------------------------------\n// Runtime factory.\n// ---------------------------------------------------------------------------\n\n/**\n * Builds a typed table accessor that delegates every call to `raw` using the\n * runtime table name string. Two narrow `as` casts bridge the mapped-type\n * shapes to/from `Record<string, unknown>` — see module-level doc comment.\n *\n * The `raw` param is typed `TxClient` (the op surface shared by `DBClient` and\n * the transaction-scoped client) because this only ever calls the five\n * insert/update/delete/findById/findMany ops — never `transaction`. This lets\n * the same factory wrap both the top-level db and a tx without any cast.\n */\nfunction makeTypedTable<T extends TableDef<Record<string, ColumnBuilder>>>(\n name: string,\n raw: TxClient,\n): TypedTable<T> {\n return {\n insert: (data: InsertShape<T>) =>\n raw.insert(name, data as Record<string, unknown>) as Promise<RowShape<T>>,\n\n update: (id: string, data: Partial<InsertShape<T>>) =>\n raw.update(name, id, data as Record<string, unknown>) as Promise<RowShape<T> | null>,\n\n delete: (id: string) => raw.delete(name, id),\n\n findById: (id: string) =>\n raw.findById(name, id) as Promise<RowShape<T> | null>,\n\n findMany: (query?: Partial<RowShape<T>>) =>\n raw.findMany(name, query as Record<string, unknown> | undefined) as Promise<RowShape<T>[]>,\n };\n}\n\n/**\n * Wraps a raw `DBClient` with the type-safe `TypedDB<S>` facade derived from\n * the provided schema. No behavior change — all calls delegate to `raw` with\n * the table name as a plain string.\n *\n * `buildTables` is the reusable factory that wraps any op-bearing client\n * (`TxClient` — the surface shared by `DBClient` and the transaction-scoped\n * client) into the typed tables map. It is used both for the top-level db\n * (wrapping `raw`) and inside `transaction`, where it wraps the raw `TxClient`\n * the runtime yields so the callback sees the same typed `.tables` API.\n *\n * `transaction` delegates straight to `raw.transaction`; the two narrow\n * `as TypedTx<S>` / `as TypedDB<S>` casts are single structural narrowings\n * from the dynamically-built tables object to the precise mapped type (TS\n * cannot infer through `Object.keys` iteration) — see module-level doc comment.\n */\nexport function makeTypedDB<S extends SchemaDef>(\n schema: S,\n raw: DBClient,\n): TypedDB<S> {\n function buildTables(client: TxClient): Record<string, TypedTable<TableDef>> {\n const tables = {} as Record<string, TypedTable<TableDef>>;\n for (const key of Object.keys(schema.tables)) {\n const tableDef = schema.tables[key];\n if (tableDef !== undefined) {\n tables[key] = makeTypedTable(tableDef.name, client);\n }\n }\n return tables;\n }\n\n const result = {\n tables: buildTables(raw),\n transaction: <T>(fn: (tx: TypedTx<S>) => Promise<T>): Promise<T> =>\n raw.transaction((rawTx) => fn({ tables: buildTables(rawTx) } as TypedTx<S>)),\n };\n\n // Narrow cast: `result.tables` is structurally identical to\n // TypedDB<S>[\"tables\"] — each key maps to a TypedTable for the matching\n // TableDef. TS cannot infer the mapped-type result through Object.keys\n // iteration, so a single `as` bridges the gap.\n return result as TypedDB<S>;\n}\n\n// ---------------------------------------------------------------------------\n// Env-augmentation-driven typed surface — the typed-by-default `Database`.\n//\n// These types read the globally-augmented `Tables` interface from\n// `@palbase/backend/env` (filled by the generated `palbase-env.d.ts`). They\n// back `Database.tables.<name>` so handler code is typed with no import and no\n// generic (C5). They DELIBERATELY do not reference `ColumnBuilder` — the env\n// `Tables` interface carries flat `row`/`insert` object types.\n// ---------------------------------------------------------------------------\n\n/** A typed table accessor derived from one env `Tables` entry's flat shapes. */\nexport interface EnvTypedTable<T extends TableTypes> {\n insert(data: T[\"insert\"]): Promise<T[\"row\"]>;\n /** Update the row by id; resolves to the updated row, or `null` if no row\n * matched (absent or RLS-hidden) — an idempotent outcome, mirroring\n * `findById`. The runtime returns a null row rather than throwing. */\n update(id: string, data: Partial<T[\"insert\"]>): Promise<T[\"row\"] | null>;\n delete(id: string): Promise<void>;\n findById(id: string): Promise<T[\"row\"] | null>;\n findMany(query?: Partial<T[\"row\"]>): Promise<T[\"row\"][]>;\n}\n\n/** The `tables` map exposed on `Database`/`tx`, keyed by the env `Tables`\n * interface. When no schema is declared `Tables` is empty, so `tables` is an\n * empty object — accessing `.tables.foo` is then a compile error (no member). */\nexport type EnvTables = {\n [K in keyof Tables]: EnvTypedTable<Tables[K]>;\n};\n\n/** Transaction-scoped typed facade for the env-augmented surface: same typed\n * tables, no nested transaction. */\nexport interface EnvTypedTx {\n tables: EnvTables;\n}\n\n/**\n * The RLS-bypass sibling returned by `Database.asService()`. Same typed surface\n * as {@link EnvTypedDatabase} — `tables`, the raw string ops, and a typed\n * `transaction` — but it does NOT re-expose `asService` (no double-bypass).\n * Every op it performs runs as the `service_role` (BYPASSRLS).\n */\nexport interface EnvServiceDatabase extends Omit<DBClient, \"transaction\" | \"asService\"> {\n tables: EnvTables;\n transaction<T>(fn: (tx: EnvTypedTx) => Promise<T>): Promise<T>;\n}\n\n/**\n * The typed-by-default Database surface: the raw string-keyed `DBClient` ops\n * PLUS a `tables` map typed against the project's generated `palbase-env.d.ts`,\n * a `transaction` whose callback receives the typed tables, and `asService()`\n * for the explicit RLS-bypass sibling.\n *\n * `transaction` is declared here (overriding `DBClient[\"transaction\"]`) so the\n * `tx` the callback receives carries the typed `.tables` API. `asService` is\n * re-typed to return the typed {@link EnvServiceDatabase} sibling.\n */\nexport interface EnvTypedDatabase extends Omit<DBClient, \"transaction\" | \"asService\"> {\n tables: EnvTables;\n transaction<T>(fn: (tx: EnvTypedTx) => Promise<T>): Promise<T>;\n /**\n * Return a sibling that bypasses RLS by running as the `service_role`. Use\n * sparingly and explicitly — the default `Database.*` path is RLS-enforced.\n *\n * @example\n * const all = await Database.asService().tables.todos.findMany({});\n * const rows = await Database.asService().query(\"SELECT * FROM todos\");\n */\n asService(): EnvServiceDatabase;\n}\n","/**\n * env-gen.ts — generate the `palbase-env.d.ts` text from a `defineSchema()`\n * result.\n *\n * The CLI (`palbase serve` / codegen) and the deploy pipeline call\n * {@link makeEnvDts} with the project's schema and write the returned string to\n * `palbase-env.d.ts` at the project root. That file AUGMENTS the\n * `@palbase/backend/env` `Tables` interface (controlled global augmentation,\n * C5) so `Database.tables.<name>` is typed with no import and no generic.\n *\n * The output is FLAT: each table gets a `{ row: {...}; insert: {...} }` entry\n * with plain TypeScript object types. The phantom `ColumnBuilder<...>` type\n * NEVER appears in the generated `.d.ts` — that type only lives at authoring\n * time inside `db/schema.ts`.\n */\n\nimport type { ColumnDef } from \"./columns.js\";\nimport type { SchemaDef, TableDef } from \"./schema.js\";\n\n/** The TypeScript value type for a column, ignoring nullability (added by the\n * caller). Mirrors the `ColValue` mapped type in columns.ts exactly. */\nfunction baseTsType(def: ColumnDef): string {\n switch (def.type) {\n case \"uuid\":\n case \"text\":\n case \"timestamp\":\n return \"string\";\n case \"integer\":\n return \"number\";\n case \"boolean\":\n return \"boolean\";\n case \"jsonb\":\n return \"unknown\";\n case \"enum\": {\n const values = def.enumValues ?? [];\n if (values.length === 0) return \"string\";\n return values.map((v) => JSON.stringify(v)).join(\" | \");\n }\n default:\n return \"unknown\";\n }\n}\n\n/** The full row type for a column: base type, `| null` when nullable. */\nfunction rowType(def: ColumnDef): string {\n const base = baseTsType(def);\n return def.nullable ? `${base} | null` : base;\n}\n\n/** True when a column may be omitted on INSERT — nullable OR has any default.\n * Mirrors `ColIsOptionalOnInsert` in columns.ts. */\nfunction optionalOnInsert(def: ColumnDef): boolean {\n return (\n def.nullable === true ||\n def.defaultRandom === true ||\n def.defaultNow === true ||\n def.defaultValue !== undefined\n );\n}\n\n/** Emit the `row: {...}` and `insert: {...}` blocks for one table at the given\n * base indentation. */\nfunction tableBlock(table: TableDef, indent: string): string {\n const cols = Object.entries(table.columns);\n const rowLines = cols.map(([col, builder]) => {\n return `${indent} ${col}: ${rowType(builder._def)};`;\n });\n const insertLines = cols.map(([col, builder]) => {\n const def = builder._def;\n const opt = optionalOnInsert(def) ? \"?\" : \"\";\n return `${indent} ${col}${opt}: ${rowType(def)};`;\n });\n return [\n `${indent}${table.name}: {`,\n `${indent} row: {`,\n ...rowLines,\n `${indent} };`,\n `${indent} insert: {`,\n ...insertLines,\n `${indent} };`,\n `${indent}};`,\n ].join(\"\\n\");\n}\n\n/**\n * Generate the full `palbase-env.d.ts` text for a schema.\n *\n * @example\n * import { makeEnvDts } from \"@palbase/backend\";\n * import schema from \"./db/schema.js\";\n * writeFileSync(\"palbase-env.d.ts\", makeEnvDts(schema));\n */\nexport function makeEnvDts(schema: SchemaDef): string {\n const tableNames = Object.keys(schema.tables);\n const blocks = tableNames.map((name) => tableBlock(schema.tables[name]!, \" \"));\n const body = blocks.length > 0 ? `\\n${blocks.join(\"\\n\")}\\n ` : \"\";\n return `// AUTO-GENERATED by @palbase/backend — DO NOT EDIT.\n// Regenerated from db/schema.ts on every \\`palbase serve\\` / deploy.\n// Augments the @palbase/backend/env \\`Tables\\` interface so \\`Database.tables.*\\`\n// is typed with no import and no generic.\n\ndeclare module \"@palbase/backend/env\" {\n interface Tables {${body}}\n}\n\nexport {};\n`;\n}\n","// `@Controller(basePath, options?)` — the class decorator that marks a class as\n// a Palbase backend controller. It stamps a non-enumerable `__palbase`\n// discriminant + the resolved controller metadata onto the class so the\n// deploy/dispatch pipeline (and `isController`/`resolveController`) can detect\n// and read it without `reflect-metadata`.\nimport type { AuthSpec } from \"../endpoint.js\";\n\n/** The controller metadata stamped onto a `@Controller`-decorated class. The\n * default export of a `controllers/*.controller.ts` file resolves to this via\n * {@link resolveController}. */\nexport interface ControllerMeta {\n /** Discriminant the runtime + tooling read. */\n readonly __palbase: \"controller\";\n /** The base path every route in this controller mounts under (e.g. \"/todos\"). */\n basePath: string;\n /** Controller-level default auth, applied to routes that don't set their own\n * (`@Get(\"/x\", { auth })` overrides this). `undefined` ⇒ secure-by-default. */\n defaultAuth?: AuthSpec;\n}\n\n/** Options accepted by `@Controller`. */\nexport interface ControllerOptions {\n /** Default auth for ALL routes in this controller (route-level overrides). */\n auth?: AuthSpec;\n}\n\n/** Symbol the controller metadata is stamped under. Symbol-keyed (not a string\n * property) so it never collides with an authored member and stays off the\n * structural surface. */\nexport const CONTROLLER_META: unique symbol = Symbol.for(\"palbase.backend.controllerMeta\");\n\n/** A class carrying the stamped controller metadata + discriminant. */\ninterface ControllerCarrier {\n __palbase?: \"controller\";\n [CONTROLLER_META]?: ControllerMeta;\n}\n\n/**\n * Mark a class as a Palbase backend controller. `basePath` is the mount path\n * for every route the class declares; `options.auth` sets the controller-level\n * default auth (a route's own `auth` overrides it; absent ⇒ secure-by-default).\n *\n * @example\n * \\@Controller(\"/todos\", { auth: false })\n * export class TodosController {\n * \\@Get(\"\") list(\\@Query(ListTodosQuery) q: ListTodosQuery): TodoSchema[] { … }\n * }\n */\nexport function Controller(basePath: string, options: ControllerOptions = {}) {\n return function <T extends abstract new (...args: never[]) => object>(ctor: T): T {\n const carrier = ctor as unknown as ControllerCarrier;\n const meta: ControllerMeta = {\n __palbase: \"controller\",\n basePath,\n ...(options.auth !== undefined ? { defaultAuth: options.auth } : {}),\n };\n // Non-enumerable so it doesn't leak onto instances / structural checks.\n Object.defineProperty(carrier, CONTROLLER_META, {\n value: meta,\n enumerable: false,\n configurable: true,\n writable: false,\n });\n // The bare `__palbase` discriminant is the cheap detection marker the\n // runtime/extractor checks; keep it readable but non-enumerable.\n Object.defineProperty(carrier, \"__palbase\", {\n value: \"controller\",\n enumerable: false,\n configurable: true,\n writable: false,\n });\n return ctor;\n };\n}\n\n/** True when `value` is a `@Controller`-decorated class (cheap discriminant\n * check). Accepts the class constructor (the default export of a controller\n * file). */\nexport function isController(value: unknown): boolean {\n if (typeof value !== \"function\" && (typeof value !== \"object\" || value === null)) {\n return false;\n }\n const carrier = value as ControllerCarrier;\n return carrier.__palbase === \"controller\" && carrier[CONTROLLER_META] !== undefined;\n}\n\n/** Read the resolved controller metadata off a `@Controller`-decorated class.\n * Throws if the class was not decorated — callers should gate with\n * {@link isController} first (the loader does). */\nexport function resolveController(ctor: unknown): ControllerMeta {\n if (typeof ctor !== \"function\" && (typeof ctor !== \"object\" || ctor === null)) {\n throw new TypeError(\"resolveController: value is not a class\");\n }\n const meta = (ctor as ControllerCarrier)[CONTROLLER_META];\n if (!meta) {\n throw new TypeError(\n \"resolveController: class is not a @Controller — every controller file must `export default` a @Controller-decorated class\",\n );\n }\n return meta;\n}\n","// The decorator registry — the single plain-data store the method + parameter\n// decorators write into, and the deploy/dispatch pipeline reads back. No\n// `reflect-metadata`, no `emitDecoratorMetadata`: the registry is built from the\n// decorator arguments + the parameter INDEX that esbuild/tsc preserve for legacy\n// parameter decorators (verified — see the design spec §0/§4.1).\n//\n// A controller class carries its route metadata on a symbol-keyed static\n// property (`ROUTES`). `@Get`/`@Post`/… append a {@link RouteMeta} entry;\n// `@Body`/`@User`/… append a {@link ParamMeta} entry onto the route for the\n// method they decorate. Because parameter decorators run BEFORE the method\n// decorator for the same member (TS evaluates innermost-first, params before the\n// method), the route entry may not exist yet when a param decorator fires — so\n// param metadata is buffered per method name and merged when the method\n// decorator creates the route entry.\nimport type { AuthSpec, RateLimitConfig } from \"../endpoint.js\";\nimport type { ZodTypeAny } from \"zod\";\n\n/** The HTTP verbs a route may declare, upper-cased (the runtime router +\n * OpenAPI lower-case on their own). */\nexport type HttpMethodUpper = \"GET\" | \"POST\" | \"PUT\" | \"PATCH\" | \"DELETE\";\n\n/** Route-level options accepted by the method decorators (`@Get`/`@Post`/…). */\nexport interface RouteOptions {\n /** OVERRIDES the controller-level default auth for this one route. */\n auth?: AuthSpec;\n /** Per-route rate limit. */\n rateLimit?: RateLimitConfig;\n}\n\n/** The kind of value a parameter decorator injects. Drives both dispatch\n * (which request slice to inject) and codegen (which OpenAPI parameter source a\n * schema-bearing kind maps to). */\nexport type ParamKind =\n | \"body\"\n | \"query\"\n | \"param\"\n | \"headers\"\n | \"user\"\n | \"optionalUser\"\n | \"client\"\n | \"requestId\"\n | \"traceId\"\n | \"req\";\n\n/** One parameter decorator's recorded metadata. `index` is the parameter\n * position esbuild/tsc preserve; `schema` is present for the schema-bearing\n * kinds (`body`/`query`/`headers`); `name` is the path-param name for `param`. */\nexport interface ParamMeta {\n index: number;\n kind: ParamKind;\n /** Zod schema for `body`/`query`/`headers` (validation + codegen source). */\n schema?: ZodTypeAny;\n /** Path-param name for `@Param(\"id\")`. */\n name?: string;\n}\n\n/** One route's recorded metadata: the verb + subpath + method name + options,\n * the ordered parameter metas, and the resolved return schema (injected by the\n * codegen step — see `returnSchema`). */\nexport interface RouteMeta {\n method: HttpMethodUpper;\n subpath: string;\n fnName: string;\n options: RouteOptions;\n params: ParamMeta[];\n /** Response schema for the route, if any. Derived from the method's RETURN\n * TYPE by codegen and written here via `recordReturn` (a generated top-level\n * IIFE injected per controller), not by an author-written decorator. */\n returnSchema?: ZodTypeAny;\n}\n\n/** Symbol the route metadata list is stored under on a controller class. Using\n * a symbol (not a string key) keeps it off the public structural surface and\n * avoids any chance of an authored property collision. */\nexport const ROUTES: unique symbol = Symbol.for(\"palbase.backend.routes\");\n\n/** Symbol the per-method buffered parameter metas are stored under while a class\n * is being decorated. Parameter decorators fire before the method decorator, so\n * they buffer here keyed by method name; the method decorator drains the buffer\n * into the route entry it creates. */\nconst PARAM_BUFFER: unique symbol = Symbol.for(\"palbase.backend.paramBuffer\");\n\n/** Symbol the per-method buffered return-type schemas are stored under while a\n * class's registry is being populated. The codegen-injected `recordReturn` call\n * can fire before OR after the method decorator; it buffers here keyed by method\n * name and `recordRoute` drains it into the route entry (and `recordReturn`\n * writes through if the route already exists). Buffering on BOTH sides means a\n * fully-formed route entry always carries its return schema — a raw-symbol\n * reader (the runtime) never has to re-merge. */\nconst RETURN_BUFFER: unique symbol = Symbol.for(\"palbase.backend.returnBuffer\");\n\n/** A class constructor carrying the symbol-keyed registry slots. We type the\n * registry-bearing class as this so the decorators can read/write the slots\n * without `any` — a plain `Function` does not carry index signatures. */\ninterface RegistryCarrier {\n [ROUTES]?: RouteMeta[];\n [PARAM_BUFFER]?: Record<string, ParamMeta[]>;\n [RETURN_BUFFER]?: Record<string, ZodTypeAny>;\n}\n\n/** Coerce a decorated target (class constructor or its prototype) into the\n * registry carrier that owns the slots. Method/param decorators receive the\n * PROTOTYPE as their target; the class decorator receives the constructor. We\n * always anchor the registry on the CONSTRUCTOR so `getRoutes(ctor)` finds it. */\nfunction carrierOf(target: object): RegistryCarrier {\n // For instance-member decorators, `target` is the prototype; its `.constructor`\n // is the class. For a static member or the class decorator, `target` is the\n // constructor already. Resolve to the constructor either way.\n const ctor =\n typeof target === \"function\"\n ? (target as unknown as RegistryCarrier)\n : (((target as { constructor?: unknown }).constructor ??\n target) as unknown as RegistryCarrier);\n return ctor;\n}\n\n/** Get (creating if absent) the own route list for a class constructor. Own —\n * not inherited — so a subclass does not mutate its base's routes. */\nfunction ownRoutes(carrier: RegistryCarrier): RouteMeta[] {\n if (!Object.prototype.hasOwnProperty.call(carrier, ROUTES)) {\n carrier[ROUTES] = [];\n }\n return carrier[ROUTES] as RouteMeta[];\n}\n\n/** Get (creating if absent) the own per-method param buffer for a class. */\nfunction ownParamBuffer(carrier: RegistryCarrier): Record<string, ParamMeta[]> {\n if (!Object.prototype.hasOwnProperty.call(carrier, PARAM_BUFFER)) {\n carrier[PARAM_BUFFER] = {};\n }\n return carrier[PARAM_BUFFER] as Record<string, ParamMeta[]>;\n}\n\n/** Record a route (called by the method decorators). Drains any parameter\n * metas already buffered for `fnName` into the new route entry, then sorts them\n * by parameter index so dispatch can inject positionally. */\nexport function recordRoute(\n target: object,\n fnName: string,\n method: HttpMethodUpper,\n subpath: string,\n options: RouteOptions,\n): void {\n const carrier = carrierOf(target);\n const routes = ownRoutes(carrier);\n const buffer = ownParamBuffer(carrier);\n const params = (buffer[fnName] ?? []).slice().sort((a, b) => a.index - b.index);\n const route: RouteMeta = { method, subpath, fnName, options, params };\n // Drain a buffered return schema (the recordReturn-ran-first ordering) so the\n // route entry is complete the moment it's created — a raw-symbol consumer\n // (the runtime extractor/worker) sees the return schema without re-merging.\n const returnBuffer = carrier[RETURN_BUFFER];\n if (returnBuffer && returnBuffer[fnName] !== undefined) {\n route.returnSchema = returnBuffer[fnName];\n }\n routes.push(route);\n}\n\n/** Record one parameter decorator (called by `@Body`/`@User`/…). Buffers per\n * method name; the method decorator merges the buffer into the route entry. If\n * the route already exists (method decorator ran first — TS does evaluate the\n * method decorator AFTER its parameter decorators, but we stay order-robust),\n * the meta is also appended directly so neither ordering loses it. */\nexport function recordParam(target: object, fnName: string, meta: ParamMeta): void {\n const carrier = carrierOf(target);\n const buffer = ownParamBuffer(carrier);\n (buffer[fnName] ??= []).push(meta);\n\n // Order-robust: if the route already exists, merge in place + keep sorted.\n const routes = carrier[ROUTES];\n if (routes) {\n const route = routes.find((r) => r.fnName === fnName);\n if (route) {\n route.params.push(meta);\n route.params.sort((a, b) => a.index - b.index);\n }\n }\n}\n\n/** Attach a return schema to the route for `fnName` (called by the codegen\n * injection that reads the method's return type). If the route does not exist\n * yet, the schema is buffered (RETURN_BUFFER) and drained into the route by\n * `recordRoute` when the method decorator runs. */\nexport function recordReturn(target: object, fnName: string, schema: ZodTypeAny): void {\n const carrier = carrierOf(target);\n const routes = carrier[ROUTES];\n const route = routes?.find((r) => r.fnName === fnName);\n if (route) {\n route.returnSchema = schema;\n return;\n }\n if (!Object.prototype.hasOwnProperty.call(carrier, RETURN_BUFFER)) {\n carrier[RETURN_BUFFER] = {};\n }\n const returnBuffer = carrier[RETURN_BUFFER];\n if (returnBuffer) returnBuffer[fnName] = schema;\n}\n\n/** Read the route metadata for a controller class (the deploy/dispatch entry\n * point). Applies any buffered return schemas (for the recordReturn-runs-before\n * ordering) and returns a defensive copy so callers cannot mutate the registry.\n */\nexport function getRoutes(ctor: object): RouteMeta[] {\n const carrier = carrierOf(ctor);\n const routes = carrier[ROUTES] ?? [];\n const returnBuffer = carrier[RETURN_BUFFER];\n if (returnBuffer) {\n for (const route of routes) {\n const buffered = returnBuffer[route.fnName];\n if (buffered && route.returnSchema === undefined) {\n route.returnSchema = buffered;\n }\n }\n }\n return routes.map((r) => ({ ...r, params: r.params.slice() }));\n}\n","// Method decorators: `@Get` / `@Post` / `@Put` / `@Patch` / `@Delete` declare a\n// route (verb + subpath + options) on a controller method. These are LEGACY\n// method decorators (`experimentalDecorators`), receiving\n// `(prototype, methodName, descriptor)`. They write into the per-class registry\n// (registry.ts). The success-response schema is NOT declared here: it is derived\n// from the method's RETURN TYPE by a codegen step and injected onto the route at\n// runtime via `recordReturn` (registry.ts).\nimport {\n recordRoute,\n type HttpMethodUpper,\n type RouteOptions,\n} from \"./registry.js\";\n\n/** A legacy method decorator. */\ntype MethodDecorator = (\n target: object,\n propertyKey: string | symbol,\n descriptor: PropertyDescriptor,\n) => void;\n\n/** Build a method decorator for one HTTP verb. The decorated method's name is\n * the route `fnName` (authoring sugar — the operationId is derived flat from\n * method+path by the runtime, not from this name). */\nfunction makeMethodDecorator(method: HttpMethodUpper) {\n return function (subpath: string, options: RouteOptions = {}): MethodDecorator {\n return function (target, propertyKey) {\n recordRoute(target, String(propertyKey), method, subpath, options);\n };\n };\n}\n\n/** `@Get(subpath, options?)` — declare a GET route. */\nexport const Get = makeMethodDecorator(\"GET\");\n/** `@Post(subpath, options?)` — declare a POST route. */\nexport const Post = makeMethodDecorator(\"POST\");\n/** `@Put(subpath, options?)` — declare a PUT route. */\nexport const Put = makeMethodDecorator(\"PUT\");\n/** `@Patch(subpath, options?)` — declare a PATCH route. */\nexport const Patch = makeMethodDecorator(\"PATCH\");\n/** `@Delete(subpath, options?)` — declare a DELETE route. */\nexport const Delete = makeMethodDecorator(\"DELETE\");\n","// Parameter decorators: `@Body` / `@Query` / `@Param` / `@Headers` / `@User` /\n// `@OptionalUser` / `@Client` / `@RequestId` / `@TraceId` / `@Req`. Each records\n// `{ index, kind, schema?, name? }` into the per-class registry for the method\n// it decorates. These are LEGACY parameter decorators\n// (`experimentalDecorators`), receiving `(prototype, methodName, paramIndex)` —\n// esbuild/tsc preserve the param index at runtime (verified, design §0), which\n// is how dispatch injects positionally. No type reflection\n// (`emitDecoratorMetadata`) is used: validation comes from the zod schema, the\n// type annotation the developer writes is purely for autocomplete.\nimport type { ZodTypeAny } from \"zod\";\nimport { recordParam, type ParamKind } from \"./registry.js\";\n\n/** A legacy parameter decorator. */\ntype ParameterDecorator = (\n target: object,\n propertyKey: string | symbol,\n parameterIndex: number,\n) => void;\n\n/** Build a parameter decorator that records the given kind (+ optional schema /\n * name) at the decorated parameter's index. */\nfunction makeParamDecorator(\n kind: ParamKind,\n extra?: { schema?: ZodTypeAny; name?: string },\n): ParameterDecorator {\n return function (target, propertyKey, parameterIndex) {\n recordParam(target, String(propertyKey), {\n index: parameterIndex,\n kind,\n ...(extra?.schema !== undefined ? { schema: extra.schema } : {}),\n ...(extra?.name !== undefined ? { name: extra.name } : {}),\n });\n };\n}\n\n/** `@Body(schema)` — inject the request body, validated against `schema`. The\n * developer writes `: T` (= `z.infer<schema>`, same name) for autocomplete. */\nexport function Body(schema: ZodTypeAny): ParameterDecorator {\n return makeParamDecorator(\"body\", { schema });\n}\n\n/** `@Query(schema)` — inject the parsed query params, validated against\n * `schema`. */\nexport function Query(schema: ZodTypeAny): ParameterDecorator {\n return makeParamDecorator(\"query\", { schema });\n}\n\n/** `@Headers(schema?)` — inject the request headers (lowercase keys). With a\n * schema, headers are validated + the codegen emits header parameters. */\nexport function Headers(schema?: ZodTypeAny): ParameterDecorator {\n return makeParamDecorator(\"headers\", schema !== undefined ? { schema } : undefined);\n}\n\n/** `@Param(\"id\")` — inject one matched path param by name. */\nexport function Param(name: string): ParameterDecorator {\n return makeParamDecorator(\"param\", { name });\n}\n\n/** `@User()` — inject the authenticated user (`: User`, non-null for an\n * effective-required route). The runtime resolves the effective auth. */\nexport function User(): ParameterDecorator {\n return makeParamDecorator(\"user\");\n}\n\n/** `@OptionalUser()` — inject the user as `User | null` (for routes whose\n * effective auth is `false` / `{ required: false }`). */\nexport function OptionalUser(): ParameterDecorator {\n return makeParamDecorator(\"optionalUser\");\n}\n\n/** `@Client()` — inject the parsed calling-client metadata (`: ClientInfo`). */\nexport function Client(): ParameterDecorator {\n return makeParamDecorator(\"client\");\n}\n\n/** `@RequestId()` — inject the per-request id (`: string`). */\nexport function RequestId(): ParameterDecorator {\n return makeParamDecorator(\"requestId\");\n}\n\n/** `@TraceId()` — inject the W3C trace id (`: string`). */\nexport function TraceId(): ParameterDecorator {\n return makeParamDecorator(\"traceId\");\n}\n\n/** `@Req()` — inject the raw request object (escape hatch, `: PBRequest`). */\nexport function Req(): ParameterDecorator {\n return makeParamDecorator(\"req\");\n}\n","import type { DBClient, Logger, CacheClient, PalbaseModuleClients } from \"./endpoint.js\";\nimport type { User } from \"./types.js\";\n\n/** Middleware context — subset of EndpointContext without input (not yet validated). */\nexport interface MiddlewareContext extends PalbaseModuleClients {\n params: Record<string, string>;\n query: Record<string, string>;\n headers: Record<string, string>;\n user: User | null;\n db: DBClient;\n env: Record<string, string>;\n log: Logger;\n cache: CacheClient;\n requestId: string;\n projectId: string;\n environmentId: string;\n}\n\n/** Middleware function signature — receives context and next function. */\nexport type MiddlewareHandler = (\n ctx: MiddlewareContext,\n next: () => Promise<void>,\n) => Promise<void>;\n\n/**\n * Define a middleware function for use in the middleware/ directory or\n * as endpoint-specific middleware.\n *\n * Middleware runs before the handler. Call `next()` to pass control\n * to the next middleware or handler. If `next()` is not called, the\n * handler will not execute.\n *\n * Errors thrown in middleware are caught by the pipeline and returned\n * as error responses.\n */\nexport function defineMiddleware(fn: MiddlewareHandler): MiddlewareHandler {\n return fn;\n}\n","/** HTTP error with structured error response format.\n *\n * The base class for the throwable error classes (`PalError`, `Conflict`,\n * `NotFound`, …). Construct one directly with `throw new HttpError(404,\n * \"todo_not_found\", \"No such todo\")`, or throw a named subclass\n * (`throw new NotFound(\"todo not found\")`). The runtime catches any `HttpError`\n * and emits the standard envelope; on the wire (and to iOS) it surfaces as\n * `BackendError.server(code, status, message, requestId)`.\n *\n * The optional `data` field carries a structured payload alongside the\n * standard envelope — for errors that need to ship extra context\n * (e.g. `new Conflict(\"locked\", \"title_locked\", { retryAfter: 30 })`). It rides\n * through to the iOS typed enum's associated value.\n */\nexport class HttpError extends Error {\n public readonly status: number;\n public readonly error: string;\n public readonly errorDescription: string;\n public readonly data?: unknown;\n\n constructor(status: number, error: string, errorDescription: string, data?: unknown) {\n super(errorDescription);\n this.name = \"HttpError\";\n this.status = status;\n this.error = error;\n this.errorDescription = errorDescription;\n if (data !== undefined) {\n this.data = data;\n }\n }\n\n /**\n * Serialize to the standard Palbase error response format.\n * The `requestId` is injected by the runtime layer from the request context.\n * When called without arguments (e.g. JSON.stringify), request_id is omitted.\n * When `data` is set, it is appended as a strict-superset field.\n */\n toJSON(requestId?: string): {\n error: string;\n error_description: string;\n status: number;\n request_id?: string;\n data?: unknown;\n } {\n const result: {\n error: string;\n error_description: string;\n status: number;\n request_id?: string;\n data?: unknown;\n } = {\n error: this.error,\n error_description: this.errorDescription,\n status: this.status,\n };\n if (requestId) {\n result.request_id = requestId;\n }\n if (this.data !== undefined) {\n result.data = this.data;\n }\n return result;\n }\n}\n\n/**\n * Throw with a custom HTTP status + wire code. The general-purpose escape hatch\n * when none of the named classes (`Conflict`/`NotFound`/…) fits.\n *\n * @example\n * throw new PalError(418, \"teapot\", \"I'm a teapot\");\n */\nexport class PalError extends HttpError {\n constructor(status: number, code: string, description: string, data?: unknown) {\n super(status, code, description, data);\n this.name = \"PalError\";\n }\n}\n\n/** Base for the named status classes. Each subclass fixes its HTTP status; the\n * `code` defaults to the class's canonical wire code (overridable), and the\n * `message` defaults to a human-readable label (overridable). */\nabstract class NamedHttpError extends HttpError {\n protected constructor(\n status: number,\n defaultCode: string,\n name: string,\n message?: string,\n code?: string,\n data?: unknown,\n ) {\n super(status, code ?? defaultCode, message ?? defaultMessage(name), data);\n this.name = name;\n }\n}\n\n/** Derive a default human-readable message from a class name\n * (\"NotFound\" → \"Not found\", \"TooManyRequests\" → \"Too many requests\"). */\nfunction defaultMessage(name: string): string {\n const spaced = name.replace(/([a-z0-9])([A-Z])/g, \"$1 $2\");\n return spaced.charAt(0).toUpperCase() + spaced.slice(1).toLowerCase();\n}\n\n/** 400 — the request was malformed or failed validation. */\nexport class BadRequest extends NamedHttpError {\n constructor(message?: string, code?: string, data?: unknown) {\n super(400, \"bad_request\", \"BadRequest\", message, code, data);\n }\n}\n\n/** 401 — the caller is not authenticated. */\nexport class Unauthorized extends NamedHttpError {\n constructor(message?: string, code?: string, data?: unknown) {\n super(401, \"unauthorized\", \"Unauthorized\", message, code, data);\n }\n}\n\n/** 403 — the caller is authenticated but not allowed. */\nexport class Forbidden extends NamedHttpError {\n constructor(message?: string, code?: string, data?: unknown) {\n super(403, \"forbidden\", \"Forbidden\", message, code, data);\n }\n}\n\n/** 404 — the requested resource does not exist. */\nexport class NotFound extends NamedHttpError {\n constructor(message?: string, code?: string, data?: unknown) {\n super(404, \"not_found\", \"NotFound\", message, code, data);\n }\n}\n\n/** 409 — the request conflicts with the current state. */\nexport class Conflict extends NamedHttpError {\n constructor(message?: string, code?: string, data?: unknown) {\n super(409, \"conflict\", \"Conflict\", message, code, data);\n }\n}\n\n/** 429 — the caller has exceeded the rate limit. */\nexport class TooManyRequests extends NamedHttpError {\n constructor(message?: string, code?: string, data?: unknown) {\n super(429, \"too_many_requests\", \"TooManyRequests\", message, code, data);\n }\n}\n","import type { User } from \"./types.js\";\n\n/** Non-service, per-invocation data for background worker handlers.\n * Services (Database, Log, …) are imported as singletons, not passed here. */\nexport interface WorkerMeta {\n /** Branch-scoped env vars. */\n env: Record<string, string>;\n /** The user that enqueued the job, if any (background jobs are usually system-initiated). */\n user: User | null;\n /** Per-invocation id for correlation. */\n requestId: string;\n projectId: string;\n environmentId: string;\n}\n\n/** Backoff strategy for worker retries. */\nexport type BackoffStrategy = \"exponential\" | \"linear\" | \"fixed\";\n\n/** Configuration for a background worker. */\nexport interface WorkerConfig<TPayload = unknown> {\n /** Worker name — must be unique across the project. */\n name: string;\n /** Maximum number of retries before sending to dead letter queue. Defaults to 3. */\n retry?: number;\n /** Execution timeout in seconds. Defaults to 30. */\n timeout?: number;\n /** Backoff strategy between retries. Defaults to \"exponential\". */\n backoff?: BackoffStrategy;\n /** Handler function that processes the job payload. */\n handler: (\n payload: TPayload,\n meta: WorkerMeta,\n ) => Promise<void>;\n}\n\n/** Resolved worker configuration with defaults applied. */\nexport interface ResolvedWorkerConfig<TPayload = unknown> {\n name: string;\n retry: number;\n timeout: number;\n backoff: BackoffStrategy;\n handler: (\n payload: TPayload,\n meta: WorkerMeta,\n ) => Promise<void>;\n}\n\n/** Valid worker name pattern: alphanumeric, underscore, hyphen only.\n * Prevents Redis key injection via colons or path separators. */\nconst VALID_WORKER_NAME = /^[a-zA-Z0-9_-]+$/;\n\n/** Default values for worker configuration. */\nconst WORKER_DEFAULTS = {\n retry: 3,\n timeout: 30,\n backoff: \"exponential\" as BackoffStrategy,\n} as const;\n\n/**\n * Define a background worker that processes jobs from the queue.\n *\n * Workers are placed in the `workers/` directory and auto-discovered at deploy time.\n *\n * @example\n * ```ts\n * export default defineWorker({\n * name: \"send-email\",\n * retry: 5,\n * timeout: 60,\n * backoff: \"exponential\",\n * handler: async (payload: { to: string; subject: string }, meta) => {\n * await sendEmail(payload.to, payload.subject);\n * },\n * });\n * ```\n */\nexport function defineWorker<TPayload = unknown>(\n config: WorkerConfig<TPayload>,\n): ResolvedWorkerConfig<TPayload> {\n if (!config.name || config.name.trim() === \"\") {\n throw new Error(\"Worker name is required\");\n }\n\n if (!VALID_WORKER_NAME.test(config.name)) {\n throw new Error(\n `Invalid worker name \"${config.name}\": must match [a-zA-Z0-9_-]+`,\n );\n }\n\n if (config.retry !== undefined && (config.retry < 0 || !Number.isInteger(config.retry))) {\n throw new Error(\"Worker retry must be a non-negative integer\");\n }\n\n if (config.timeout !== undefined && config.timeout <= 0) {\n throw new Error(\"Worker timeout must be a positive number\");\n }\n\n if (\n config.backoff !== undefined &&\n ![\"exponential\", \"linear\", \"fixed\"].includes(config.backoff)\n ) {\n throw new Error(`Invalid backoff strategy: ${config.backoff}`);\n }\n\n return {\n name: config.name,\n retry: config.retry ?? WORKER_DEFAULTS.retry,\n timeout: config.timeout ?? WORKER_DEFAULTS.timeout,\n backoff: config.backoff ?? WORKER_DEFAULTS.backoff,\n handler: config.handler,\n };\n}\n","/** Non-service, per-invocation data for job handlers.\n * Services (Database, Log, …) are imported as singletons, not passed here. */\nexport interface JobMeta {\n /** Branch-scoped env vars. */\n env: Record<string, string>;\n projectId: string;\n environmentId: string;\n}\n\n/** Configuration for defining a scheduled job. */\nexport interface JobConfig {\n /** Unique job name — alphanumeric, underscore, hyphen only. */\n name: string;\n /** Cron expression (e.g., \"0 3 * * *\"). */\n schedule: string;\n /** Execution timeout in seconds. Defaults to 30. */\n timeout?: number;\n /** Job handler function. */\n handler: (meta: JobMeta) => Promise<void>;\n}\n\n/** Resolved job configuration with defaults applied. */\nexport interface ResolvedJobConfig {\n name: string;\n schedule: string;\n timeout: number;\n handler: (meta: JobMeta) => Promise<void>;\n}\n\n/** Valid job name pattern: alphanumeric, underscore, hyphen only. */\nconst VALID_JOB_NAME = /^[a-zA-Z0-9_-]+$/;\n\n/** Maximum allowed timeout in seconds (5 minutes, matching sandbox limits). */\nconst MAX_TIMEOUT_SECONDS = 300;\n\n/** Default values for job configuration. */\nconst JOB_DEFAULTS = {\n timeout: 30,\n} as const;\n\n/**\n * Cron expression validation.\n * Supports standard 5-field cron: minute hour day-of-month month day-of-week.\n * Each field allows: number, *, ranges (1-5), steps (star/2), lists (1,3,5).\n */\nfunction validateCronExpression(expression: string): string | null {\n const trimmed = expression.trim();\n if (trimmed === \"\") {\n return \"Cron expression is required\";\n }\n\n const parts = trimmed.split(/\\s+/);\n if (parts.length !== 5) {\n return `Invalid cron expression \"${trimmed}\": expected 5 fields (minute hour day month weekday), got ${parts.length}`;\n }\n\n const fieldNames = [\"minute\", \"hour\", \"day of month\", \"month\", \"day of week\"];\n const fieldRanges: [number, number][] = [\n [0, 59],\n [0, 23],\n [1, 31],\n [1, 12],\n [0, 7],\n ];\n\n for (let i = 0; i < 5; i++) {\n const field = parts[i]!;\n const name = fieldNames[i]!;\n const [min, max] = fieldRanges[i]!;\n\n const error = validateCronField(field, name, min, max);\n if (error !== null) {\n return error;\n }\n }\n\n return null;\n}\n\nfunction validateCronField(\n field: string,\n name: string,\n min: number,\n max: number,\n): string | null {\n // Split by comma for lists\n const listParts = field.split(\",\");\n for (const part of listParts) {\n // Check for step: */2, 1-5/2\n const stepParts = part.split(\"/\");\n if (stepParts.length > 2) {\n return `Invalid ${name} field: \"${field}\"`;\n }\n\n const base = stepParts[0]!;\n const step = stepParts[1];\n\n if (step !== undefined) {\n const stepNum = Number(step);\n if (!Number.isInteger(stepNum) || stepNum < 1) {\n return `Invalid step value in ${name} field: \"${field}\"`;\n }\n }\n\n if (base === \"*\") {\n continue;\n }\n\n // Check for range: 1-5\n if (base.includes(\"-\")) {\n const rangeParts = base.split(\"-\");\n if (rangeParts.length !== 2) {\n return `Invalid range in ${name} field: \"${field}\"`;\n }\n const rangeStart = Number(rangeParts[0]);\n const rangeEnd = Number(rangeParts[1]);\n if (\n !Number.isInteger(rangeStart) ||\n !Number.isInteger(rangeEnd) ||\n rangeStart < min ||\n rangeEnd > max ||\n rangeStart > rangeEnd\n ) {\n return `Invalid range in ${name} field: \"${field}\"`;\n }\n continue;\n }\n\n // Single number\n const num = Number(base);\n if (!Number.isInteger(num) || num < min || num > max) {\n return `Invalid value in ${name} field: \"${field}\"`;\n }\n }\n\n return null;\n}\n\n/**\n * Define a scheduled cron job.\n *\n * Jobs are placed in the `jobs/` directory and auto-discovered at deploy time.\n *\n * @example\n * ```ts\n * export default defineJob({\n * name: \"cleanup-expired\",\n * schedule: \"0 3 * * *\", // every day at 3 AM\n * timeout: 60,\n * handler: async (meta) => {\n * await Database.delete(\"sessions\", \"expired < NOW()\");\n * Log.info(\"Cleaned up expired sessions\");\n * },\n * });\n * ```\n */\nexport function defineJob(config: JobConfig): ResolvedJobConfig {\n if (!config.name || config.name.trim() === \"\") {\n throw new Error(\"Job name is required\");\n }\n\n if (!VALID_JOB_NAME.test(config.name)) {\n throw new Error(\n `Invalid job name \"${config.name}\": must match [a-zA-Z0-9_-]+`,\n );\n }\n\n if (!config.schedule || config.schedule.trim() === \"\") {\n throw new Error(\"Job schedule is required\");\n }\n\n const cronError = validateCronExpression(config.schedule);\n if (cronError !== null) {\n throw new Error(cronError);\n }\n\n if (!config.handler) {\n throw new Error(\"Job handler is required\");\n }\n\n if (config.timeout !== undefined && config.timeout <= 0) {\n throw new Error(\"Job timeout must be a positive number\");\n }\n\n if (config.timeout !== undefined && !Number.isInteger(config.timeout)) {\n throw new Error(\"Job timeout must be an integer\");\n }\n\n if (config.timeout !== undefined && config.timeout > MAX_TIMEOUT_SECONDS) {\n throw new Error(\n `Job timeout ${config.timeout}s exceeds maximum ${MAX_TIMEOUT_SECONDS}s`,\n );\n }\n\n return {\n name: config.name,\n schedule: config.schedule.trim(),\n timeout: config.timeout ?? JOB_DEFAULTS.timeout,\n handler: config.handler,\n };\n}\n","/** Supported webhook provider types. */\nexport type WebhookProvider =\n | \"stripe\"\n | \"github\"\n | \"twilio\"\n | \"sendgrid\"\n | \"slack\"\n | \"discord\"\n | \"livekit\";\n\n/** Non-service, per-invocation data for webhook handlers.\n * Services (Database, Log, …) are imported as singletons, not passed here. */\nexport interface WebhookMeta {\n /** Branch-scoped env vars. */\n env: Record<string, string>;\n /** Per-invocation id for correlation. */\n requestId: string;\n projectId: string;\n environmentId: string;\n}\n\n/** Secret reference — resolves from environment variables at runtime. */\nexport interface EnvSecretRef {\n env: string;\n}\n\n/** Provider-specific event maps for type-safe event handlers. */\nexport interface ProviderEventMap {\n stripe: {\n \"checkout.session.completed\": Record<string, unknown>;\n \"payment_intent.succeeded\": Record<string, unknown>;\n \"payment_intent.payment_failed\": Record<string, unknown>;\n \"customer.subscription.created\": Record<string, unknown>;\n \"customer.subscription.updated\": Record<string, unknown>;\n \"customer.subscription.deleted\": Record<string, unknown>;\n \"invoice.paid\": Record<string, unknown>;\n \"invoice.payment_failed\": Record<string, unknown>;\n [key: string]: Record<string, unknown>;\n };\n github: {\n push: Record<string, unknown>;\n pull_request: Record<string, unknown>;\n issues: Record<string, unknown>;\n \"pull_request.opened\": Record<string, unknown>;\n \"pull_request.closed\": Record<string, unknown>;\n \"pull_request.merged\": Record<string, unknown>;\n [key: string]: Record<string, unknown>;\n };\n twilio: {\n \"message.received\": Record<string, unknown>;\n \"message.sent\": Record<string, unknown>;\n \"call.completed\": Record<string, unknown>;\n [key: string]: Record<string, unknown>;\n };\n sendgrid: {\n delivered: Record<string, unknown>;\n bounce: Record<string, unknown>;\n open: Record<string, unknown>;\n click: Record<string, unknown>;\n [key: string]: Record<string, unknown>;\n };\n slack: {\n url_verification: Record<string, unknown>;\n event_callback: Record<string, unknown>;\n [key: string]: Record<string, unknown>;\n };\n discord: {\n PING: Record<string, unknown>;\n MESSAGE_CREATE: Record<string, unknown>;\n INTERACTION_CREATE: Record<string, unknown>;\n [key: string]: Record<string, unknown>;\n };\n livekit: {\n \"room.started\": Record<string, unknown>;\n \"room.finished\": Record<string, unknown>;\n \"participant.joined\": Record<string, unknown>;\n \"participant.left\": Record<string, unknown>;\n [key: string]: Record<string, unknown>;\n };\n}\n\n/** Event handler function type. */\nexport type WebhookEventHandler<TEvent = Record<string, unknown>> = (\n event: TEvent,\n meta: WebhookMeta,\n) => Promise<void>;\n\n/** Provider-based webhook configuration. */\nexport interface ProviderWebhookConfig<P extends WebhookProvider = WebhookProvider> {\n provider: P;\n secret: EnvSecretRef;\n events: {\n [K in keyof ProviderEventMap[P]]?: WebhookEventHandler<ProviderEventMap[P][K]>;\n };\n}\n\n/** Incoming request representation for custom verify functions. */\nexport interface WebhookRequest {\n headers: Record<string, string>;\n body: string;\n method: string;\n url: string;\n}\n\n/** Custom webhook configuration. */\nexport interface CustomWebhookConfig {\n path: string;\n verify?: (req: WebhookRequest) => Promise<boolean> | boolean;\n handler: (payload: Record<string, unknown>, meta: WebhookMeta) => Promise<void>;\n}\n\n/** Resolved provider webhook (internal). */\nexport interface ResolvedProviderWebhook<P extends WebhookProvider = WebhookProvider> {\n type: \"provider\";\n provider: P;\n secret: EnvSecretRef;\n events: Record<string, WebhookEventHandler>;\n}\n\n/** Resolved custom webhook (internal). */\nexport interface ResolvedCustomWebhook {\n type: \"custom\";\n path: string;\n verify?: (req: WebhookRequest) => Promise<boolean> | boolean;\n handler: (payload: Record<string, unknown>, meta: WebhookMeta) => Promise<void>;\n}\n\n/** Union of resolved webhook types. */\nexport type ResolvedWebhookConfig = ResolvedProviderWebhook | ResolvedCustomWebhook;\n\n/** Valid webhook path pattern: starts with /, alphanumeric + hyphen + slash. */\nconst VALID_WEBHOOK_PATH = /^\\/[a-zA-Z0-9/_-]+$/;\n\n/**\n * Define a provider-based webhook.\n *\n * @example\n * ```ts\n * export default defineWebhook({\n * provider: \"stripe\",\n * secret: { env: \"STRIPE_WEBHOOK_SECRET\" },\n * events: {\n * \"checkout.session.completed\": async (event, meta) => {\n * await Database.insert(\"orders\", { status: \"paid\" });\n * },\n * },\n * });\n * ```\n */\nexport function defineWebhook<P extends WebhookProvider>(\n config: ProviderWebhookConfig<P>,\n): ResolvedProviderWebhook<P>;\n\n/**\n * Define a custom webhook with optional verification.\n *\n * @example\n * ```ts\n * export default defineWebhook({\n * path: \"/webhooks/livekit\",\n * verify: async (req) => req.headers[\"x-api-key\"] === \"secret\",\n * handler: async (payload, meta) => {\n * Log.info(\"Received webhook\", payload);\n * },\n * });\n * ```\n */\nexport function defineWebhook(config: CustomWebhookConfig): ResolvedCustomWebhook;\n\nexport function defineWebhook(\n config: ProviderWebhookConfig | CustomWebhookConfig,\n): ResolvedWebhookConfig {\n if (\"provider\" in config) {\n return validateProviderWebhook(config);\n }\n return validateCustomWebhook(config);\n}\n\nfunction validateProviderWebhook<P extends WebhookProvider>(\n config: ProviderWebhookConfig<P>,\n): ResolvedProviderWebhook<P> {\n if (!config.provider) {\n throw new Error(\"Webhook provider is required\");\n }\n\n const validProviders: WebhookProvider[] = [\n \"stripe\", \"github\", \"twilio\", \"sendgrid\", \"slack\", \"discord\", \"livekit\",\n ];\n if (!validProviders.includes(config.provider)) {\n throw new Error(\n `Invalid webhook provider \"${config.provider}\": must be one of ${validProviders.join(\", \")}`,\n );\n }\n\n if (!config.secret) {\n throw new Error(\"Webhook secret is required (use { env: \\\"SECRET_NAME\\\" })\");\n }\n\n if (typeof config.secret.env !== \"string\" || config.secret.env.trim() === \"\") {\n throw new Error(\"Webhook secret env name must be a non-empty string\");\n }\n\n if (!config.events || Object.keys(config.events).length === 0) {\n throw new Error(\"At least one event handler is required\");\n }\n\n for (const [eventName, handler] of Object.entries(config.events)) {\n if (typeof handler !== \"function\") {\n throw new Error(`Event handler for \"${eventName}\" must be a function`);\n }\n }\n\n return {\n type: \"provider\",\n provider: config.provider,\n secret: config.secret,\n events: config.events as Record<string, WebhookEventHandler>,\n };\n}\n\nfunction validateCustomWebhook(config: CustomWebhookConfig): ResolvedCustomWebhook {\n if (!config.path || config.path.trim() === \"\") {\n throw new Error(\"Webhook path is required\");\n }\n\n if (!VALID_WEBHOOK_PATH.test(config.path)) {\n throw new Error(\n `Invalid webhook path \"${config.path}\": must start with / and contain only alphanumeric, hyphen, underscore, slash`,\n );\n }\n\n if (!config.handler) {\n throw new Error(\"Webhook handler is required\");\n }\n\n if (typeof config.handler !== \"function\") {\n throw new Error(\"Webhook handler must be a function\");\n }\n\n if (config.verify !== undefined && typeof config.verify !== \"function\") {\n throw new Error(\"Webhook verify must be a function\");\n }\n\n return {\n type: \"custom\",\n path: config.path,\n verify: config.verify,\n handler: config.handler,\n };\n}\n","/**\n * resource.ts — external connections as lifecycle-managed classes.\n *\n * A `Resource` subclass models one external connection (a pooled datastore, a\n * stateless API client, or a per-user factory). The framework discovers each\n * instance, calls `init(env)` ONCE at boot with the declared secret subset, and\n * `shutdown()` (reverse order) on SIGTERM. On top of that lifecycle the author\n * exposes their own clean facade methods.\n *\n * // resources/neo4j.ts\n * import { Resource } from \"@palbase/backend\";\n * import neo4j, { type Driver, type Session } from \"neo4j-driver\";\n *\n * export class Neo4jResource extends Resource {\n * static secrets = [\"NEO4J_URL\", \"NEO4J_USER\", \"NEO4J_PASSWORD\"] as const;\n * private driver!: Driver;\n * async init(env: { NEO4J_URL: string; NEO4J_USER: string; NEO4J_PASSWORD: string }) {\n * this.driver = neo4j.driver(env.NEO4J_URL, neo4j.auth.basic(env.NEO4J_USER, env.NEO4J_PASSWORD));\n * }\n * async shutdown() { await this.driver.close(); }\n * session(): Session { return this.driver.session(); }\n * }\n * export const neo4j = new Neo4jResource(); // framework finds + manages it\n *\n * # Boot scope (NOT request-ALS)\n *\n * Resources are instantiated once at process boot. This is deliberately NOT the\n * per-request {@link AsyncLocalStorage} scope used for `Database`/`Cache`/… — a\n * connection pool must outlive a single request. The runtime discovers\n * resources from the project's `resources/` directory, registers each via\n * {@link __registerResource}, then calls {@link __runResourceBoot} before\n * serving and {@link __shutdownResources} on SIGTERM. Discovery is a runtime\n * concern; the SDK provides the base class + registry + boot/shutdown hooks.\n */\n\n/** Map a declared `secrets` tuple to the `init(env)` argument type — a record\n * over the secret names, each `string`. An empty tuple maps to an empty\n * record. */\nexport type ResourceEnv<Secrets extends readonly string[]> = {\n [K in Secrets[number]]: string;\n};\n\n/**\n * Base class for external connections.\n *\n * - `static secrets` — OPTIONAL readonly tuple of env-var names this resource\n * needs. Drives (a) the `env` type passed to `init` and (b) the\n * missing-secret check at boot (deploy fails naming the absent secret).\n * - `init(env)` — called ONCE at boot with the declared secret subset. May be\n * sync (`void`) or async (`Promise<void>`).\n * - `shutdown()` — OPTIONAL drain hook, called on SIGTERM in reverse boot\n * order.\n *\n * @example\n * import { Resource } from \"@palbase/backend\";\n * import { Client } from \"@googlemaps/google-maps-services-js\";\n *\n * export class GoogleResource extends Resource {\n * static secrets = [\"GOOGLE_MAPS_KEY\"] as const;\n * private client = new Client();\n * private key = \"\";\n * init(env: { GOOGLE_MAPS_KEY: string }) { this.key = env.GOOGLE_MAPS_KEY; }\n * }\n * export const google = new GoogleResource();\n */\nexport abstract class Resource {\n /** The env-var names this resource needs. Optional; omit for none. */\n static secrets?: readonly string[];\n\n /** Set up the connection from the declared secrets. Called once at boot. */\n abstract init(env: Record<string, string>): void | Promise<void>;\n\n /** Drain/close the connection on SIGTERM. Optional. */\n shutdown?(): void | Promise<void>;\n}\n\n/** A value carrying an optional readonly `secrets` tuple — the constructor side\n * of a Resource subclass. Narrowed from `unknown` via {@link hasSecrets}. */\ninterface WithSecrets {\n secrets?: readonly string[];\n}\n\n/** Guard: does this value carry a `secrets` array (the static on a Resource\n * subclass)? Lets us read `secrets` off `resource.constructor` (typed\n * `Function`) without a cast — narrows from `unknown` instead. */\nfunction hasSecrets(value: unknown): value is WithSecrets {\n if (typeof value !== \"object\" && typeof value !== \"function\") return false;\n const secrets = (value as { secrets?: unknown }).secrets;\n return secrets === undefined || Array.isArray(secrets);\n}\n\n/** A registered resource plus whether its `init` has already run. The\n * `booted` flag makes {@link __runResourceBoot} idempotent (re-running boot,\n * e.g. across a re-entrant deploy path, never re-inits). */\ninterface RegistryEntry {\n resource: Resource;\n booted: boolean;\n}\n\n/** Module-level boot registry. Single per process (the br-pod is\n * single-project). Order is registration order; shutdown reverses it. */\nconst registry: RegistryEntry[] = [];\n\n/**\n * Register a resource instance with the boot registry. The runtime calls this\n * for each instance discovered under the project's `resources/` directory.\n * NOT part of the public author-facing API (prefixed `__`).\n */\nexport function __registerResource(resource: Resource): void {\n registry.push({ resource, booted: false });\n}\n\n/** Read the declared `secrets` tuple off a resource instance's constructor. */\nfunction declaredSecrets(resource: Resource): readonly string[] {\n const ctor: unknown = resource.constructor;\n return hasSecrets(ctor) ? (ctor.secrets ?? []) : [];\n}\n\n/**\n * Boot every registered resource that has not yet been booted: resolve its\n * declared secret subset from `envMap`, then await its `init(env)`. Idempotent\n * — an already-booted resource is skipped. Throws (failing deploy/boot) when a\n * declared secret is absent, naming the missing secret. NOT part of the public\n * author-facing API.\n */\nexport async function __runResourceBoot(envMap: Record<string, string>): Promise<void> {\n for (const entry of registry) {\n if (entry.booted) continue;\n const secrets = declaredSecrets(entry.resource);\n const env: Record<string, string> = {};\n for (const name of secrets) {\n const value = envMap[name];\n if (value === undefined) {\n throw new Error(\n `Resource ${entry.resource.constructor.name} requires secret \"${name}\" but it is not set. ` +\n `Set it with \\`palbase secret set ${name} ...\\` (or in Studio) and redeploy.`,\n );\n }\n env[name] = value;\n }\n await entry.resource.init(env);\n entry.booted = true;\n }\n}\n\n/**\n * Shut down every booted resource in REVERSE registration order, awaiting each\n * `shutdown()` (a no-op when undefined). Clears the registry afterwards so a\n * second call is a no-op. NOT part of the public author-facing API.\n */\nexport async function __shutdownResources(): Promise<void> {\n for (let i = registry.length - 1; i >= 0; i -= 1) {\n const entry = registry[i]!;\n if (entry.booted && entry.resource.shutdown) {\n await entry.resource.shutdown();\n }\n }\n registry.length = 0;\n}\n\n/** Clear the registry without running shutdown. TEST-only helper so each test\n * starts from a clean registry. NOT part of the public author-facing API. */\nexport function __resetResources(): void {\n registry.length = 0;\n}\n","/** Non-service, per-invocation data for hook handlers.\n * Services (Database, Log, …) are imported as singletons, not passed here. */\nexport interface HookMeta {\n /** Branch-scoped env vars. */\n env: Record<string, string>;\n projectId: string;\n environmentId: string;\n}\n\n// --- Auth Event Payloads ---\n\n/** Payload for auth.onUserCreated hook. */\nexport interface UserCreatedEvent {\n user: {\n id: string;\n /** User's email, if they signed up with one (absent for phone-only users). */\n email?: string;\n role: string;\n metadata: Record<string, unknown>;\n createdAt: string;\n };\n}\n\n/** Payload for auth.onSignIn hook. */\nexport interface SignInEvent {\n user: {\n id: string;\n /** User's email, if they have one (absent for phone-only users). */\n email?: string;\n role: string;\n };\n provider: string;\n timestamp: string;\n}\n\n/** Payload for auth.onSignOut hook. */\nexport interface SignOutEvent {\n user: {\n id: string;\n /** User's email, if they have one (absent for phone-only users). */\n email?: string;\n };\n timestamp: string;\n}\n\n/** Payload for auth.onPasswordReset hook.\n * Password reset is inherently email-based, so `email` is always present here\n * (a phone-only passwordless user cannot trigger this event). */\nexport interface PasswordResetEvent {\n user: {\n id: string;\n email: string;\n };\n timestamp: string;\n}\n\n// --- Storage Event Payloads ---\n\n/** Payload for storage.onFileUploaded hook. */\nexport interface FileUploadedEvent {\n file: {\n id: string;\n name: string;\n bucket: string;\n path: string;\n size: number;\n contentType: string;\n };\n}\n\n/** Payload for storage.onFileDeleted hook. */\nexport interface FileDeletedEvent {\n file: {\n id: string;\n name: string;\n bucket: string;\n path: string;\n };\n}\n\n// --- Documents Event Payloads ---\n\n/** Payload for documents.onDocumentCreated hook. */\nexport interface DocumentCreatedEvent {\n document: {\n id: string;\n collection: string;\n data: Record<string, unknown>;\n };\n}\n\n/** Payload for documents.onDocumentUpdated hook. */\nexport interface DocumentUpdatedEvent {\n document: {\n id: string;\n collection: string;\n data: Record<string, unknown>;\n previousData: Record<string, unknown>;\n };\n}\n\n/** Payload for documents.onDocumentDeleted hook. */\nexport interface DocumentDeletedEvent {\n document: {\n id: string;\n collection: string;\n data: Record<string, unknown>;\n };\n}\n\n// --- Hook Handler Types ---\n\nexport type HookHandler<TEvent> = (event: TEvent, meta: HookMeta) => Promise<void>;\n\n/** Resolved hook configuration (internal). */\nexport interface ResolvedHook<TEvent = unknown> {\n module: string;\n event: string;\n handler: HookHandler<TEvent>;\n}\n\n// --- Auth Hooks ---\n\nexport const auth = {\n onUserCreated(handler: HookHandler<UserCreatedEvent>): ResolvedHook<UserCreatedEvent> {\n return { module: \"auth\", event: \"user.created\", handler };\n },\n\n onSignIn(handler: HookHandler<SignInEvent>): ResolvedHook<SignInEvent> {\n return { module: \"auth\", event: \"user.sign_in\", handler };\n },\n\n onSignOut(handler: HookHandler<SignOutEvent>): ResolvedHook<SignOutEvent> {\n return { module: \"auth\", event: \"user.sign_out\", handler };\n },\n\n onPasswordReset(handler: HookHandler<PasswordResetEvent>): ResolvedHook<PasswordResetEvent> {\n return { module: \"auth\", event: \"user.password_reset\", handler };\n },\n};\n\n// --- Storage Hooks ---\n\nexport const storage = {\n onFileUploaded(handler: HookHandler<FileUploadedEvent>): ResolvedHook<FileUploadedEvent> {\n return { module: \"storage\", event: \"file.uploaded\", handler };\n },\n\n onFileDeleted(handler: HookHandler<FileDeletedEvent>): ResolvedHook<FileDeletedEvent> {\n return { module: \"storage\", event: \"file.deleted\", handler };\n },\n};\n\n// --- Documents Hooks ---\n\nexport const documents = {\n onDocumentCreated(handler: HookHandler<DocumentCreatedEvent>): ResolvedHook<DocumentCreatedEvent> {\n return { module: \"documents\", event: \"document.created\", handler };\n },\n\n onDocumentUpdated(handler: HookHandler<DocumentUpdatedEvent>): ResolvedHook<DocumentUpdatedEvent> {\n return { module: \"documents\", event: \"document.updated\", handler };\n },\n\n onDocumentDeleted(handler: HookHandler<DocumentDeletedEvent>): ResolvedHook<DocumentDeletedEvent> {\n return { module: \"documents\", event: \"document.deleted\", handler };\n },\n};\n"],"mappings":"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","names":[]}
|