@palbase/backend 17.2.0 → 17.4.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-IBIME7N2.js → chunk-AAN642N5.js} +16 -1
- package/dist/{chunk-IBIME7N2.js.map → chunk-AAN642N5.js.map} +1 -1
- package/dist/db/index.cjs +15 -0
- package/dist/db/index.cjs.map +1 -1
- package/dist/db/index.d.cts +1 -1
- package/dist/db/index.d.ts +1 -1
- package/dist/db/index.js +1 -1
- package/dist/{index-D6mRh4yq.d.cts → index-BA_oFAz9.d.cts} +18 -0
- package/dist/{index-J1tnAnFj.d.ts → index-VLrU7rSW.d.ts} +18 -0
- package/dist/index.cjs +15 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -1
- package/dist/test/index.cjs +4 -0
- package/dist/test/index.cjs.map +1 -1
- package/dist/test/index.d.cts +24 -1
- package/dist/test/index.d.ts +24 -1
- package/dist/test/index.js +4 -0
- package/dist/test/index.js.map +1 -1
- 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/tx-plan.ts","../src/errors.ts","../src/purchases/errors.ts","../src/purchases/registry.ts","../src/purchases/subject.ts","../src/purchases/decorators.ts","../src/purchases/keys-gen.ts","../src/db/policy.ts","../src/db/schema.ts","../src/db/extensions.ts","../src/db/columns.ts","../src/db/raw.ts","../src/db/typed-db.ts","../src/db/env-gen.ts","../src/config/storage.ts","../src/config/egress.ts","../src/config/notifications.ts","../src/config/test-users.ts","../src/config/flags.ts","../src/decorators/registry.ts","../src/decorators/controller.ts","../src/decorators/methods.ts","../src/decorators/upload.ts","../src/decorators/params.ts","../src/middleware.ts","../src/error-registry.ts","../src/decorators/webhook.ts","../src/job.ts","../src/decorators/job.ts","../src/resource.ts","../src/hooks.ts"],"sourcesContent":["export type {\n PBRequest,\n ClientInfo,\n RateLimitConfig,\n DBClient,\n DBOps,\n FileContext,\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 Log,\n Notifications,\n Flags,\n Realtime,\n Purchases,\n __setRuntime,\n __runWithRuntime,\n __requestALS,\n __getRuntime,\n} from \"./runtime.js\";\nexport type { RuntimeServices, RequestStore } from \"./runtime.js\";\n// Purchases: entitlement gate + metered spend, at the decorator level.\nexport { RequireEntitlement, Spend } from \"./purchases/decorators.js\";\nexport type { PurchasesService, LimitState, SpendOptions, StoreEnv } from \"./purchases/service.js\";\nexport type { EntitlementKey, LimitKey } from \"./purchases/keys.js\";\n// The codegen twin of makeEnvDts — emits the project's `palbase-purchases.d.ts`.\nexport { makePurchasesDts } from \"./purchases/keys-gen.js\";\nexport type { PurchasesManifest } from \"./purchases/keys-gen.js\";\n// Per-route purchases metadata, read by the OpenAPI step to declare 403/429.\nexport { entitlementFor, spendFor } from \"./purchases/registry.js\";\nexport type { SpendMeta } from \"./purchases/registry.js\";\nexport type {\n PalbaseAuthClient,\n PalbaseStorageClient,\n PalbaseBucketClient,\n PalbaseRealtimeClient,\n PalbaseFunctionsClient,\n PalbaseInvokeOptions,\n PalbaseFlagsClient,\n PalbaseFlagsServiceClient,\n PalbaseFlagContext,\n PalbaseFlagVariant,\n PalbaseFlag,\n PalbaseFlagValue,\n PalbaseFlagSource,\n PalbaseSetOverrideResult,\n PalbaseSetOverridesResult,\n PalbaseClearOverrideResult,\n PalbaseClearAllOverridesResult,\n PalbaseBatchOverrideOperation,\n PalbaseBatchSetOverridesResult,\n PalbaseNotificationsClient,\n PalbasePushClient,\n PalbaseEmailClient,\n PalbaseSmsClient,\n PalbaseInboxClient,\n PalbasePreferencesClient,\n PalbaseAnalyticsClient,\n PalbaseAnalyticsQueryNamespace,\n PalbaseAnalyticsManagementNamespace,\n PalbaseLinksClient,\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 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} 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, bigint, numeric, boolean, timestamp, jsonb, enumType } from \"./db/columns.js\";\nexport type { ColumnBuilder, ColumnDef, ColumnType, OnDeleteAction } from \"./db/columns.js\";\nexport { raw } from \"./db/raw.js\";\nexport type { RawConstraintDef } from \"./db/raw.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 EnvTypedTable,\n EnvTables,\n TxPlan,\n TxTables,\n} from \"./db/typed-db.js\";\n// Transaction plans: the `tx.tables.*` operation surface, its handles, and the\n// expressions a plan may write. `Database.transaction()` is on `Database`.\nexport { inc, dec, now, TxRefError, TxPlanError } from \"./db/tx-plan.js\";\nexport type {\n Ref,\n TxRow,\n TxRows,\n TxTable,\n TxPlanHandle,\n Materialized,\n TxNow,\n TxColumnExpr,\n TxInsertValue,\n TxSetValue,\n TxInsertShape,\n TxSetShape,\n TxWhere,\n TxSelectOptions,\n TxPlanBody,\n TxPlanResponse,\n TxPlanOpResult,\n TxPlanRejection,\n TxWireOp,\n TxWireRef,\n TxWireExpr,\n TxWireGuard,\n TxWireValue,\n} from \"./db/tx-plan.js\";\nexport type { Tables, TableTypes } from \"./db/env.js\";\nexport { makeEnvDts } from \"./db/env-gen.js\";\n// Module config-as-code DSLs (sibling of defineSchema). config/storage.ts\n// default-exports defineStorage(...); the deploy evals + applies the buckets.\nexport { defineStorage, bucket, parseFileSizeLimit, STORAGE_CONFIG_KIND } from \"./config/storage.js\";\nexport type { BucketDef, BucketOptions, ImageVariant, StorageConfig, StorageInput } from \"./config/storage.js\";\nexport {\n defineEgress,\n EGRESS_CONFIG_KIND,\n EGRESS_TIMEOUT_DEFAULT_MS,\n EGRESS_TIMEOUT_MAX_MS,\n EGRESS_TIMEOUT_MIN_MS,\n} from \"./config/egress.js\";\nexport type { EgressConfig, EgressInput } from \"./config/egress.js\";\n// config/notifications.ts default-exports defineNotifications(...); the deploy\n// evals + applies the providers (non-secret fields here, cert/key secrets bound\n// by convention to reserved PB_NOTIFICATIONS_* env vars resolved at deploy).\nexport {\n defineNotifications,\n buildProvider,\n extractVariables,\n reservedSecretKey,\n PROVIDER_CATALOG,\n NOTIFICATIONS_CONFIG_KIND,\n RESERVED_SECRET_PREFIX,\n DEFAULT_TEMPLATE_LOCALE,\n} from \"./config/notifications.js\";\nexport type {\n NotificationsConfig,\n NotificationsInput,\n ProviderDef,\n ProviderName,\n ProviderOptions,\n ProviderCatalogEntry,\n ApnsOptions,\n FcmOptions,\n SendgridOptions,\n SesOptions,\n SmtpOptions,\n AcsOptions,\n TwilioOptions,\n TemplatesInput,\n TemplatesConfig,\n EmailTemplateOptions,\n EmailTemplateContent,\n EmailTemplateDef,\n SmsTemplateOptions,\n SmsTemplateContent,\n SmsTemplateDef,\n} from \"./config/notifications.js\";\n// config/flags.ts default-exports defineFlags(...); the deploy evals + UPSERTS\n// the declared flag DEFINITIONS into PalFlags (upsert-only, never auto-deleted).\n// The simplest module config — pure declarative data, no secrets.\n// config/test-users.ts default-exports defineTestUsers(...); the deploy evals it\n// and hands the JSON to Studio's single apply engine (mint + seed). A fixture\n// (email+password given) is materialized create-if-missing; a template (no\n// credentials) is only registered for Studio/CLI to mint from.\nexport { defineTestUsers, testUser, TEST_USERS_CONFIG_KIND } from \"./config/test-users.js\";\nexport type {\n OwnedTablesOf,\n Seed,\n SeedFor,\n SeedJson,\n SeedRowFor,\n TableGraph,\n TestUserDef,\n TestUserOptions,\n TestUsersConfig,\n TestUsersInput,\n} from \"./config/test-users.js\";\nexport { defineFlags, flag, FLAGS_CONFIG_KIND } from \"./config/flags.js\";\nexport type {\n FlagDef,\n FlagJsonObject,\n FlagJsonValue,\n FlagOptions,\n FlagsConfig,\n FlagsInput,\n FlagType,\n FlagValue,\n} from \"./config/flags.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, Query } from \"./decorators/methods.js\";\nexport { Upload, validateUploadAgainstStorage } from \"./decorators/upload.js\";\nexport type { UploadConfig } from \"./decorators/upload.js\";\n// `UploadedObject` is exported from upload.js, where BOTH the `@UploadedObject()`\n// decorator value AND the `UploadedObject` type are declared. One module → one\n// export name carries both — authors write `@UploadedObject()` (value) and\n// `: UploadedObject` (type) with a single imported name.\nexport { UploadedObject } from \"./decorators/upload.js\";\nexport {\n Body,\n QueryParams,\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, ThrowDescriptor, RouteMeta, ParamMeta, ParamKind } from \"./decorators/registry.js\";\n// recordThrows is the stager-injected carrier for inferred throw descriptors\n// (the recordReturn twin) — public so the injected IIFE in a deployed bundle\n// can call it via `require(\"@palbase/backend\").recordThrows(...)`.\nexport { recordThrows } from \"./decorators/registry.js\";\n// getRoutes reads a controller's RouteMeta[] straight from the registry — the\n// isolate runtime enumerates routes with it instead of the worker.js raw-Symbol\n// fallback (the ROUTES symbol stays, both fallbacks keep reading it).\nexport { getRoutes } 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, VerifiedDevice, 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\";\n// Typed project errors — defineError returns an HttpError subclass and\n// self-registers {code, status, dataSchema} in the project-global error\n// registry (the OpenAPI spec twins join `RouteMeta.throws` against it).\nexport { defineError, getErrorRegistry } from \"./error-registry.js\";\nexport type { RegisteredError, DefinedError, DefinedErrorWithData } from \"./error-registry.js\";\nexport type { JobMeta } from \"./job.js\";\nexport type { WebhookProvider, WebhookMeta, WebhookRequest } from \"./webhook.js\";\n// Webhooks and jobs are classes: `@Webhook`/`@On` for inbound webhooks,\n// `@Job` for cron. Both take their name from their file — see decorators/*.\nexport { getWebhookConfig, On, Webhook } from \"./decorators/webhook.js\";\nexport type { ResolvedWebhook, SignatureSpec, WebhookEventHandler, WebhookOptions } from \"./decorators/webhook.js\";\nexport { getJobConfig, Job } from \"./decorators/job.js\";\nexport type { JobOptions, ResolvedJob } from \"./decorators/job.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 CacheClient,\n Logger,\n PalbaseDocsClient,\n} from \"./endpoint.js\";\nimport type {\n PalbaseStorageClient,\n PalbaseNotificationsClient,\n PalbaseFlagsClient,\n PalbaseFlagsServiceClient,\n PalbaseFlagContext,\n PalbaseFlagVariant,\n PalbaseFlag,\n PalbaseFlagValue,\n PalbaseSetOverrideResult,\n PalbaseRealtimeClient,\n} from \"./clients.js\";\nimport type { PalbaseResult } from \"./endpoint.js\";\nimport type {\n EnvTypedDatabase,\n EnvServiceDatabase,\n EnvTables,\n TxPlan,\n TxTables,\n} from \"./db/typed-db.js\";\nimport type { Materialized } from \"./db/tx-plan.js\";\nimport { TxPlanBuilder, runTxPlan } from \"./db/tx-plan.js\";\nimport type { PurchasesService } from \"./purchases/service.js\";\n\n/** The set of live clients the runtime injects per request scope.\n *\n * Realtime is BROADCAST-ONLY here (a stateless handler can push an event but\n * cannot hold a subscription socket — `subscribe()` lives on the client SDK).\n *\n * EXCLUDED on purpose: Functions, Links, Analytics, Auth. They are not\n * exposed as backend handler singletons (auth lives on the client SDK; the rest\n * are out of scope for backend endpoints). */\nexport interface RuntimeServices {\n Database: DBClient;\n Documents: PalbaseDocsClient;\n Storage: PalbaseStorageClient;\n Cache: CacheClient;\n Log: Logger;\n Notifications: PalbaseNotificationsClient;\n Flags: PalbaseFlagsClient;\n Realtime: PalbaseRealtimeClient;\n Purchases: PurchasesService;\n}\n\n/**\n * The per-request ALS box.\n *\n * `runtime` is the service bundle. `userId` is the request's authenticated user\n * id, written by the runtime immediately after it assembles the request object\n * (worker.js: `requestALS.getStore().userId = pbReq.user?.id || null`) and\n * `null` on an anonymous request. It was already being written there for the\n * Flags client's auto-bind; declaring it here makes the existing contract typed\n * instead of implicit, which is what lets `currentSubjectId()` read a\n * server-owned identity rather than trusting anything the caller sent.\n */\nexport interface RequestStore {\n runtime: RuntimeServices;\n userId?: string | null;\n /** This request's id (`req_…`), written by the runtime. Used as the spend\n * idempotency scope when the caller supplied no `Idempotency-Key`. */\n requestId?: string;\n /** The caller's `Idempotency-Key` header, or `null` when absent. What makes a\n * client's retry replay its first result instead of charging twice. */\n idempotencyKey?: string | null;\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<RequestStore>();\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 the top-level `Database`. Each\n * `tables.<name>` access returns a small object that forwards the five CRUD ops\n * to the underlying client using `name` as the string table identifier. The\n * shapes are typed against the generated `palbase-env.d.ts` (`EnvTables`); at\n * runtime they are 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: () => DBOps): 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>(\n fn: (tx: TxPlan) => T extends Promise<unknown> ? never : T,\n ): Promise<Materialized<T>> {\n // A FRESH builder per call: it holds this transaction's ops and its error\n // slot table, and the runtime serves concurrent requests on one event loop.\n // A shared builder would splice one request's writes into another's plan.\n const builder = new TxPlanBuilder();\n return runTxPlan(raw, makeTxTablesAccessor(builder), builder, fn) as Promise<\n Materialized<T>\n >;\n },\n });\n}\n\n/**\n * The transaction twin of {@link makeTablesAccessor}: `tables.<name>` yields the\n * table's PLAN operations, recorded into `builder` instead of sent one by one.\n *\n * Same Proxy shape and same reason for the single narrowing — TS cannot infer a\n * mapped type through a Proxy, so the cast names what the trap returns.\n */\nfunction makeTxTablesAccessor(builder: TxPlanBuilder): TxTables {\n const tablesProxy = new Proxy(\n {},\n {\n get(_t, prop: string | symbol) {\n if (typeof prop !== \"string\") return undefined;\n return builder.table(prop);\n },\n },\n );\n return tablesProxy as TxTables;\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\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/**\n * Palstore purchases (entitlements + quota/credit spend).\n *\n * Reached by handlers through the `@RequireEntitlement` / `@Spend` decorators\n * rather than called directly in the common case; exposed as a singleton for\n * the cases the decorators deliberately do not cover (a dynamic spend count,\n * which must run BEFORE the billable side-effect).\n */\nexport const Purchases: PurchasesService = makeServiceProxy(\"Purchases\");\n\n/**\n * The raw runtime Flags client for the current request scope. Carries the\n * default-surface reads + `setOverride` AND the runtime's `asService()` sibling\n * (the br-pod's `buildFlagsClient` returns both). The default `Flags` singleton\n * below forwards reads + `setOverride` through here; `Flags.asService()`\n * forwards to this client's own `asService()`.\n */\nconst rawFlags: PalbaseFlagsClient = makeServiceProxy(\"Flags\");\n\n/**\n * Feature flags.\n *\n * Mirrors the `Database` / `Database.asService()` model. The default surface is\n * RLS-equivalent for flags: reads resolve against the CURRENT request user and\n * `Flags.setOverride(key, value)` writes an override for that same signed-in\n * user (no userId argument, no admin power). Cross-user admin writes\n * (`setOverrideForUser`, …) live behind `Flags.asService()` — explicit and\n * greppable, just like `Database.asService()`.\n *\n * @example\n * import { Flags } from \"@palbase/backend\";\n *\n * if (await Flags.isEnabled(\"new_checkout\")) { ... } // current user\n * await Flags.setOverride(\"new_checkout\", true); // current user\n * await Flags.asService().setOverrideForUser(\"u_9\", \"x\", true); // cross-user\n */\nexport const Flags: PalbaseFlagsClient = Object.assign(\n {\n isEnabled(\n flagName: string,\n context?: PalbaseFlagContext,\n ): Promise<PalbaseResult<boolean>> {\n return rawFlags.isEnabled(flagName, context);\n },\n getVariant(\n flagName: string,\n context?: PalbaseFlagContext,\n ): Promise<PalbaseResult<PalbaseFlagVariant>> {\n return rawFlags.getVariant(flagName, context);\n },\n getAll(context?: PalbaseFlagContext): Promise<PalbaseResult<PalbaseFlag[]>> {\n return rawFlags.getAll(context);\n },\n setOverride(\n key: string,\n value: PalbaseFlagValue,\n ): Promise<PalbaseResult<PalbaseSetOverrideResult>> {\n return rawFlags.setOverride(key, value);\n },\n },\n {\n /**\n * Lazily resolve the runtime's cross-user sibling on each call. We do NOT\n * cache it: `rawFlags.asService()` reads the CURRENT request scope through\n * the runtime proxy, so caching would leak one request's sibling into\n * another concurrent request. Mirrors `Database.asService()`.\n */\n asService(): PalbaseFlagsServiceClient {\n return rawFlags.asService();\n },\n },\n);\n\n/**\n * The Realtime broadcast singleton for the current request scope. Backend-side\n * Realtime is BROADCAST-ONLY (a stateless handler can push but not subscribe —\n * `subscribe()` lives on the client SDK's `pb.realtime`). Fire-and-forget:\n * `broadcast` resolves once accepted (or with an `error`), never blocking the\n * handler on subscribers.\n *\n * @example\n * import { Realtime } from \"@palbase/backend\";\n *\n * await Realtime.broadcast(\"room:42\", \"message\", { text, from: user.id });\n */\nexport const Realtime: PalbaseRealtimeClient = makeServiceProxy(\"Realtime\");\n","/**\n * tx-plan.ts — `Database.transaction()` as a PLAN, not a pinned session.\n *\n * A transaction used to be a conversation: BEGIN, then one network round trip\n * per operation, then COMMIT. Each of those round trips cost ~4 ms and, because\n * the pooler runs in transaction mode, an open transaction pinned a Postgres\n * backend for the whole conversation. A 121-operation statement upload pinned\n * one backend for ~490 ms.\n *\n * So the callback no longer TALKS to the database. It DESCRIBES what should\n * happen; the description is serialised and sent once; the broker runs the whole\n * thing inside one transaction and answers once. Committing on return and\n * rolling back on throw is unchanged — that is the only property tenant code\n * actually asked for.\n *\n * The consequences, stated plainly, because they are the whole design:\n *\n * - The callback is SYNCHRONOUS. There is nothing to await: no statement has\n * run yet when it returns. `async` on the callback and `await` inside it are\n * both compile errors (see {@link TxPlan} and {@link NotAwaitable}).\n * - `insert()` does not hand back a row, it hands back {@link TxRows}. Reading\n * a field requires `.expectOne(err)` first, which makes \"what if the row\n * isn't there\" a question you cannot route around: it is the argument.\n * - A field read from a row is a {@link Ref} — a PROMISE OF A VALUE THE SERVER\n * WILL PRODUCE, not the value. It can be written into a later operation and\n * it can be returned from the callback (it is substituted for the real value\n * before `transaction()` resolves). It cannot be branched on. See the\n * \"Truthiness\" note below — this is the sharp edge of the whole design.\n * - Control flow that needs a real value must move OUT of the callback: read\n * before the transaction, or express the condition as a guard\n * (`updateWhere({ id, accepted_at: null }, …).expectOne(new Conflict(…))`)\n * which the server evaluates and which rolls the whole plan back.\n *\n * # Truthiness — the hole this file CANNOT close\n *\n * JavaScript does not let a Proxy trap truthiness. `if (ref)` takes the true\n * branch, always, for every Ref, and no `get` handler ever runs. `tsc` is silent\n * because a Ref is a perfectly good object. So:\n *\n * const pot = tx.tables.pots.select({ id }, { limit: 1 }).expectOne(e);\n * if (!pot.balance) { … } // ← ALWAYS false. Silently wrong data.\n *\n * What this file does close: coercion (`Symbol.toPrimitive`/`valueOf`/\n * `toString`), awaiting (`then` is a callable member with a non-thenable\n * signature, which is a *compile* error), serialisation (`toJSON`), and nesting\n * a Ref inside a literal value where the server would store it as data. What it\n * cannot close is a bare truthiness test. The real defence is the build-time\n * static analysis (`tx_analysis.js`, phase P4); until that ships, this hole is\n * open and this comment is the only warning.\n *\n * # Wire contract\n *\n * The JSON this file emits is consumed by\n * `modules/backend/internal/management/tx_program.go`. That decoder rejects\n * unknown fields at every level, so an op carries EXACTLY the fields its kind\n * takes. Everything here that looks like a needless restriction is one of the\n * server's rules made visible early:\n *\n * - `$ref` only points BACKWARDS, and only at an op statically known to yield\n * at most one row (insert, or a `one`/`atMost 1` guard, or `select limit 1`).\n * `.expectOne()` is what this file uses to satisfy that, always.\n * - `$expr` is a closed set: `inc`/`dec` (update only — they read the column's\n * current value) and `now()`.\n * - `update`/`delete` require a `where`; `insert` refuses one.\n * - `insertMany` rows must all set the same columns.\n * - ≤1000 ops, ≤5000 rows per insertMany, ≤8 MiB of JSON.\n *\n * Column keys are emitted SORTED, so the same callback always produces byte-\n * identical JSON. That is what lets the Go decoder be locked to golden files\n * this SDK emits (`testdata/tx_plan_golden/`).\n */\n\n// ---------------------------------------------------------------------------\n// Errors\n// ---------------------------------------------------------------------------\n\n/**\n * A plan handle was used as if it were a value: awaited, coerced to a string or\n * number, serialised, or nested inside another value.\n *\n * Thrown while the callback is still BUILDING the plan, so nothing has been sent\n * and nothing has been written.\n */\nexport class TxRefError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"TxRefError\";\n }\n}\n\n/**\n * The plan the callback described cannot be sent: it breaks a rule the server\n * would reject, and rejecting it here names the line that wrote it instead of\n * returning a 400 about an op index.\n */\nexport class TxPlanError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"TxPlanError\";\n }\n}\n\n// ---------------------------------------------------------------------------\n// Wire types — mirror tx_program.go's decoder exactly.\n// ---------------------------------------------------------------------------\n\n/** A backwards reference to an earlier op's single-row result. */\nexport interface TxWireRef {\n $ref: { op: number; field: string };\n}\n\n/** A call from the server's closed function set. */\nexport interface TxWireExpr {\n $expr: { fn: \"inc\" | \"dec\"; by: number } | { fn: \"now\" };\n}\n\n/** One value in a `values`/`set`/`where` map: a literal, a `$ref` or a `$expr`. */\nexport type TxWireValue = TxWireRef | TxWireExpr | unknown;\n\n/** The tenant's declared expectation about an op's row count. `slot` indexes the\n * client-side error table — the error OBJECT never travels. */\nexport interface TxWireGuard {\n kind: \"one\" | \"none\" | \"atLeast\" | \"atMost\";\n n: number;\n slot: number;\n}\n\n/** One operation in the wire plan. Fields are omitted, never null: the decoder\n * rejects a field that does not belong to the op's kind. */\nexport interface TxWireOp {\n op: \"insert\" | \"insertMany\" | \"update\" | \"delete\" | \"select\";\n table: string;\n values?: Record<string, TxWireValue>;\n rows?: Record<string, TxWireValue>[];\n set?: Record<string, TxWireValue>;\n where?: Record<string, TxWireValue>;\n limit?: number;\n lock?: \"update\";\n guard?: TxWireGuard;\n}\n\n/** The request body of `POST /internal-api/db/tx`. */\nexport interface TxPlanBody {\n ops: TxWireOp[];\n}\n\n/** One op's outcome, positionally matched to the plan's ops. */\nexport interface TxPlanOpResult {\n rows: Record<string, unknown>[];\n rows_affected: number;\n}\n\n/** The response body of `POST /internal-api/db/tx`. */\nexport interface TxPlanResponse {\n results: TxPlanOpResult[];\n}\n\n/**\n * The fields the runtime must copy from the broker's error envelope onto the\n * rejection it throws out of {@link DBClient.txPlan}.\n *\n * `slot` is the whole point: on a guard failure the server answers with the\n * INDEX of the expectation that did not hold, never with an error message of its\n * own, and this SDK maps that index back to the `Error` the callback handed to\n * `.expectOne(…)`. Without `slot` a guard failure degrades to a generic 409.\n */\nexport interface TxPlanRejection {\n status?: number;\n /** `tx_plan_invalid` | `tx_guard_failed` | `tx_ref_unresolved` | a pg class. */\n error_code?: string;\n /** Present only for `tx_guard_failed`: the client-side error table index. */\n slot?: number;\n /** Present on a database error: which op failed. */\n op?: number;\n}\n\n// ---------------------------------------------------------------------------\n// Handle types\n// ---------------------------------------------------------------------------\n\ndeclare const refBrand: unique symbol;\ndeclare const rowBrand: unique symbol;\ndeclare const rowsBrand: unique symbol;\n\n/**\n * Makes a handle a compile error to `await`.\n *\n * `then` is declared as a CALLABLE member whose signature is not `PromiseLike`,\n * which is precisely the shape TypeScript rejects: `await handle` is TS1320 and\n * `async () => handle` is TS1058. A non-callable `then` would not do it — the\n * compiler simply ignores those.\n */\nexport interface NotAwaitable {\n /** Not a promise. Nothing here has run yet; there is nothing to await. */\n then(doNotAwaitAPlanHandle: \"a transaction plan is built synchronously\"): never;\n}\n\n/**\n * A value the SERVER will produce, standing in for a column of a row this plan\n * writes or reads.\n *\n * Legal uses: write it into a later operation's `values`/`set`/`where`, or\n * return it from the callback (it is replaced by the real value before\n * `transaction()` resolves).\n *\n * Illegal, and caught: `await`, `String(ref)`, `` `${ref}` ``, `ref + 1`,\n * `JSON.stringify(ref)`, burying it inside a jsonb object.\n *\n * Illegal, and NOT caught: `if (ref)`. See the truthiness note at the top.\n */\nexport interface Ref<T> extends NotAwaitable {\n readonly [refBrand]: T;\n}\n\n/** The brand carried by a single-row handle, and the seam `Materialized` reads\n * to turn `return st` into the whole row. */\nexport interface TxRowHandle<Row> extends NotAwaitable {\n readonly [rowBrand]: Row;\n}\n\n/**\n * A row this plan is known to produce exactly one of. Every property is a\n * {@link Ref}; returning the handle itself yields the whole row.\n *\n * Only `.expectOne(err)` produces one — which is the design: a row you can read\n * fields from is a row whose absence you have already answered for.\n */\nexport type TxRow<Row> = { readonly [K in keyof Row]: Ref<Row[K]> } & TxRowHandle<Row>;\n\n/**\n * The result of one operation, before any expectation is declared about it.\n *\n * Deliberately not a row and not a list: an operation's row count is not known\n * until the server runs it, so the only thing that can be said about it here is\n * an EXPECTATION. Declaring one is also the only way to get a readable row.\n *\n * At most one expectation per operation — the wire carries one guard per op, and\n * a second call throws rather than silently dropping the first.\n */\nexport interface TxRows<Row> extends NotAwaitable {\n readonly [rowsBrand]: Row;\n /**\n * Require exactly one row, and read it. On any other count the server rolls\n * the whole transaction back and this `error` is thrown to the caller.\n *\n * This is the only way to reach a row's fields, and the only shape a `$ref`\n * may point at.\n */\n expectOne(error: Error): TxRow<Row>;\n /** Require zero rows (e.g. \"this membership must not already exist\"). */\n expectNone(error: Error): void;\n /** Require at least `n` rows. */\n expectAtLeast(n: number, error: Error): void;\n /** Require at most `n` rows. */\n expectAtMost(n: number, error: Error): void;\n}\n\n/** `now()` — the server's clock, usable wherever a value is. */\nexport interface TxNow extends NotAwaitable {\n readonly $expr: { fn: \"now\" };\n}\n\n/** `inc(n)` / `dec(n)` — read the column's CURRENT value and write it back\n * changed. Only meaningful in an update's `set`, which is where the types allow\n * it and where the server allows it. */\nexport interface TxColumnExpr extends NotAwaitable {\n readonly $expr: { fn: \"inc\" | \"dec\"; by: number };\n}\n\n/**\n * Resolve a callback's return type against what actually comes back: every\n * {@link Ref} becomes its value, every {@link TxRow} becomes its row, and\n * anything else keeps its shape.\n *\n * A {@link TxRows} resolves to an explanatory string type rather than a row\n * list: it has no single answer to give, and saying so in the type is louder\n * than a runtime throw.\n */\nexport type Materialized<T> = T extends Ref<infer U>\n ? U\n : T extends TxRowHandle<infer R>\n ? R\n : T extends TxRows<unknown>\n ? \"a TxRows cannot leave the transaction callback — read a row with .expectOne(err) first\"\n : T extends Date\n ? T\n : T extends object\n ? { [K in keyof T]: Materialized<T[K]> }\n : T;\n\n// ---------------------------------------------------------------------------\n// Author-facing value types\n// ---------------------------------------------------------------------------\n\n/** A value written by an INSERT: a literal, an earlier row's field, or `now()`.\n * `inc`/`dec` are absent on purpose — they read a current value, and an inserted\n * row has none. */\nexport type TxInsertValue<V> = V | Ref<V> | TxNow;\n\n/** A value written by an UPDATE's `set`: everything an insert takes, plus the\n * read-modify-write expressions. */\nexport type TxSetValue<V> = V | Ref<V> | TxNow | TxColumnExpr;\n\n/** An insert payload: the table's insert shape, with refs and `now()` allowed. */\nexport type TxInsertShape<Insert> = { [K in keyof Insert]: TxInsertValue<Insert[K]> };\n\n/** An update's `set`: any subset of the insert shape, with expressions allowed. */\nexport type TxSetShape<Insert> = { [K in keyof Insert]?: TxSetValue<Insert[K]> };\n\n/**\n * A filter. Every entry is an equality test and they are AND-ed; a `null`\n * becomes `IS NULL`, which is what makes `{ accepted_at: null }` a usable\n * \"not yet accepted\" guard rather than a clause that matches nothing.\n */\nexport type TxWhere<Row> = { [K in keyof Row]?: Row[K] | Ref<Row[K]> };\n\n/** Options for a plan `select`. */\nexport interface TxSelectOptions {\n /** Cap the rows read. */\n limit?: number;\n /** Take a real `FOR UPDATE` row lock for the rest of the transaction. */\n lock?: \"update\";\n}\n\n/** One table, as the plan sees it. */\nexport interface TxTable<Row, Insert> {\n /** Insert one row. Returns a handle — call `.expectOne(err)` to read fields. */\n insert(values: TxInsertShape<Insert>): TxRows<Row>;\n /**\n * Insert many rows in ONE statement. Every row must set the same columns\n * (a row that omits one would silently take the column's default).\n *\n * An empty list writes nothing and sends nothing.\n */\n insertMany(rows: readonly TxInsertShape<Insert>[]): TxRows<Row>;\n /**\n * Update every row matching `where`. The filter comes first because it is the\n * dangerous half: an update whose `where` you got wrong rewrites rows you\n * never looked at. The server refuses an update with no `where` at all.\n */\n updateWhere(where: TxWhere<Row>, set: TxSetShape<Insert>): TxRows<Row>;\n /** Delete every row matching `where`. The server refuses an unfiltered delete. */\n deleteWhere(where: TxWhere<Row>): TxRows<Row>;\n /** Read rows, optionally locking them for the rest of the transaction. */\n select(where?: TxWhere<Row>, options?: TxSelectOptions): TxRows<Row>;\n}\n\n/**\n * The handle a transaction callback receives.\n *\n * It carries tables and nothing else: no `query`, no `findById`, no `asService`.\n * A read whose value the plan does not write belongs OUTSIDE the transaction,\n * where it costs one round trip and can be branched on like an ordinary value.\n */\nexport interface TxPlanHandle<TTables> {\n tables: TTables;\n}\n\n// ---------------------------------------------------------------------------\n// Runtime — expressions\n// ---------------------------------------------------------------------------\n\n/** Internal marker read by the serialiser. */\nconst EXPR = Symbol.for(\"palbase.tx.expr\");\nconst REF = Symbol.for(\"palbase.tx.ref\");\nconst ROW = Symbol.for(\"palbase.tx.row\");\nconst ROWS = Symbol.for(\"palbase.tx.rows\");\n\ninterface RefDescriptor {\n op: number;\n field: string;\n}\n\n/** Property reads that must not silently produce a value on a plan handle.\n * `then` is the one that matters for correctness (it makes `await` a compile\n * error AND stops a handle from being adopted by a promise); the rest turn a\n * silent wrong answer — `\"[object Object]\"`, `NaN`, `{}` — into a thrown one. */\nconst TRAPPED_PROPS: readonly (string | symbol)[] = [\n \"then\",\n \"valueOf\",\n \"toString\",\n \"toJSON\",\n Symbol.toPrimitive,\n];\n\nfunction trap(prop: string | symbol, what: string, hint: string): never {\n const name = typeof prop === \"symbol\" ? prop.description ?? String(prop) : prop;\n throw new TxRefError(\n `${what} was used as a value (via \\`${name}\\`). Nothing in a transaction ` +\n `callback has run yet, so there is no value to read. ${hint}`,\n );\n}\n\n/** The server's `now()`. */\nexport function now(): TxNow {\n return makeExpr({ fn: \"now\" }) as TxNow;\n}\n\n/** Add `by` to the column's current value. Only valid in an update's `set`. */\nexport function inc(by: number): TxColumnExpr {\n assertFiniteNumber(by, \"inc\");\n return makeExpr({ fn: \"inc\", by }) as TxColumnExpr;\n}\n\n/** Subtract `by` from the column's current value. Only valid in an update's `set`. */\nexport function dec(by: number): TxColumnExpr {\n assertFiniteNumber(by, \"dec\");\n return makeExpr({ fn: \"dec\", by }) as TxColumnExpr;\n}\n\nfunction assertFiniteNumber(by: number, fn: string): void {\n if (typeof by !== \"number\" || !Number.isFinite(by)) {\n // JSON has no NaN/Infinity: they would serialise to `null` and the server\n // would reject the plan with an unhelpful decode error.\n throw new TxPlanError(`${fn}() needs a finite number, got ${String(by)}`);\n }\n}\n\nfunction makeExpr(expr: TxWireExpr[\"$expr\"]): unknown {\n return new Proxy(\n { [EXPR]: expr } as Record<string | symbol, unknown>,\n {\n get(target, prop) {\n if (prop === EXPR) return target[EXPR];\n if (TRAPPED_PROPS.includes(prop)) {\n trap(prop, \"A plan expression\", \"Write it into an operation instead.\");\n }\n return undefined;\n },\n },\n );\n}\n\n// ---------------------------------------------------------------------------\n// Runtime — refs and row handles\n// ---------------------------------------------------------------------------\n\nfunction makeRef(op: number, field: string): unknown {\n const target: Record<string | symbol, unknown> = { [REF]: { op, field } satisfies RefDescriptor };\n return new Proxy(target, {\n get(t, prop) {\n if (prop === REF) return t[REF];\n if (TRAPPED_PROPS.includes(prop)) {\n trap(\n prop,\n `\\`${field}\\` of a row this transaction has not written yet`,\n \"Pass it to another operation in the same plan, or return it from the \" +\n \"callback and read it after `transaction()` resolves.\",\n );\n }\n return undefined;\n },\n });\n}\n\nfunction makeRowHandle(op: number): unknown {\n const target: Record<string | symbol, unknown> = { [ROW]: op };\n return new Proxy(target, {\n get(t, prop) {\n if (prop === ROW) return t[ROW];\n if (TRAPPED_PROPS.includes(prop)) {\n trap(\n prop,\n \"A row this transaction has not written yet\",\n \"Read one of its columns to reference it, or return the row from the \" +\n \"callback and read it after `transaction()` resolves.\",\n );\n }\n if (typeof prop === \"symbol\") return undefined;\n return makeRef(op, prop);\n },\n });\n}\n\nfunction refDescriptor(v: unknown): RefDescriptor | null {\n if (typeof v !== \"object\" || v === null) return null;\n const d = (v as Record<symbol, unknown>)[REF];\n return isRefDescriptor(d) ? d : null;\n}\n\nfunction isRefDescriptor(d: unknown): d is RefDescriptor {\n return (\n typeof d === \"object\" &&\n d !== null &&\n typeof (d as RefDescriptor).op === \"number\" &&\n typeof (d as RefDescriptor).field === \"string\"\n );\n}\n\nfunction rowOpIndex(v: unknown): number | null {\n if (typeof v !== \"object\" || v === null) return null;\n const op = (v as Record<symbol, unknown>)[ROW];\n return typeof op === \"number\" ? op : null;\n}\n\nfunction exprOf(v: unknown): TxWireExpr[\"$expr\"] | null {\n if (typeof v !== \"object\" || v === null) return null;\n const e = (v as Record<symbol, unknown>)[EXPR];\n return typeof e === \"object\" && e !== null ? (e as TxWireExpr[\"$expr\"]) : null;\n}\n\nfunction isRowsHandle(v: unknown): boolean {\n return typeof v === \"object\" && v !== null && (v as Record<symbol, unknown>)[ROWS] !== undefined;\n}\n\n// ---------------------------------------------------------------------------\n// Runtime — value encoding\n// ---------------------------------------------------------------------------\n\n/**\n * Encode one value of a `values`/`set`/`where` map.\n *\n * The nesting check is not defensive tidiness. The server treats `$ref` as a\n * tagged value only at the TOP of a column's value; a ref buried inside a jsonb\n * payload is just data, and would be stored as the literal object\n * `{\"$ref\":{...}}` — a write that succeeds, commits, and is wrong. So a nested\n * handle is a hard error here, where the line that wrote it is still on the\n * stack.\n */\nfunction encodeValue(value: unknown, column: string, allowColumnExpr: boolean): TxWireValue {\n const ref = refDescriptor(value);\n if (ref) return { $ref: { op: ref.op, field: ref.field } } satisfies TxWireRef;\n\n const expr = exprOf(value);\n if (expr) {\n if (expr.fn !== \"now\" && !allowColumnExpr) {\n throw new TxPlanError(\n `\\`${column}\\`: ${expr.fn}() reads the column's current value, so it is ` +\n `only valid in updateWhere(where, set).`,\n );\n }\n return { $expr: expr } satisfies TxWireExpr;\n }\n\n if (rowOpIndex(value) !== null) {\n throw new TxPlanError(\n `\\`${column}\\`: a row handle is not a value. Read the column you meant ` +\n `(e.g. \\`row.id\\`).`,\n );\n }\n if (isRowsHandle(value)) {\n throw new TxPlanError(\n `\\`${column}\\`: an operation result is not a value. Declare an expectation ` +\n `first (\\`.expectOne(err)\\`) and read a column from the row.`,\n );\n }\n\n assertNoNestedHandles(value, column);\n return value;\n}\n\nfunction assertNoNestedHandles(value: unknown, column: string): void {\n if (typeof value !== \"object\" || value === null) return;\n if (value instanceof Date) return;\n if (refDescriptor(value) || exprOf(value) || rowOpIndex(value) !== null || isRowsHandle(value)) {\n throw new TxPlanError(\n `\\`${column}\\`: a plan handle is nested inside a value. The server would ` +\n `store it as literal JSON, not resolve it. Put the reference directly in ` +\n `the column.`,\n );\n }\n if (Array.isArray(value)) {\n for (const item of value) assertNoNestedHandles(item, column);\n return;\n }\n for (const item of Object.values(value as Record<string, unknown>)) {\n assertNoNestedHandles(item, column);\n }\n}\n\n/**\n * Encode a column map, dropping `undefined` and emitting keys SORTED.\n *\n * Sorting is what makes the same callback produce byte-identical JSON every\n * time, which is what lets the Go decoder be locked to goldens this SDK emits.\n * Dropping `undefined` mirrors what `JSON.stringify` would do anyway, but does\n * it where the resulting column list is still checkable.\n */\nfunction encodeMap(\n map: Record<string, unknown>,\n allowColumnExpr: boolean,\n): Record<string, TxWireValue> {\n const out: Record<string, TxWireValue> = {};\n for (const key of Object.keys(map).sort()) {\n const value = map[key];\n if (value === undefined) continue;\n out[key] = encodeValue(value, key, allowColumnExpr);\n }\n return out;\n}\n\n// ---------------------------------------------------------------------------\n// Runtime — the builder\n// ---------------------------------------------------------------------------\n\n/** How many rows an op can produce, as far as the CLIENT can tell before it\n * runs. Only the empty `insertMany` is knowable, and knowing it is what lets a\n * doomed expectation fail on the line that declared it. */\nconst SKIPPED_OP = -1;\n\nclass TxRowsImpl<Row> implements TxRows<Row> {\n // Present so `isRowsHandle` recognises the object; never read for its value.\n readonly [ROWS] = true;\n // Phantom: the type brand that stops a bare object passing as a TxRows. Never\n // present at run time, which is what `declare` says.\n declare readonly [rowsBrand]: Row;\n private guarded = false;\n\n constructor(\n private readonly builder: TxPlanBuilder,\n private readonly opIndex: number,\n private readonly what: string,\n ) {}\n\n // The type-level `await` guard made real: TS rejects `await rows` at compile\n // time, and reaching this means someone called `.then(...)` by hand.\n then(): never {\n throw new TxRefError(\n `${this.what} cannot be awaited: a transaction callback builds a plan, it ` +\n `does not run statements. Remove the \\`await\\`.`,\n );\n }\n\n expectOne(error: Error): TxRow<Row> {\n this.declareGuard(\"one\", 1, error);\n if (this.opIndex === SKIPPED_OP) throw error;\n return makeRowHandle(this.opIndex) as TxRow<Row>;\n }\n\n expectNone(error: Error): void {\n this.declareGuard(\"none\", 0, error);\n }\n\n expectAtLeast(n: number, error: Error): void {\n assertGuardCount(n, \"expectAtLeast\");\n this.declareGuard(\"atLeast\", n, error);\n if (this.opIndex === SKIPPED_OP && n > 0) throw error;\n }\n\n expectAtMost(n: number, error: Error): void {\n assertGuardCount(n, \"expectAtMost\");\n this.declareGuard(\"atMost\", n, error);\n }\n\n private declareGuard(kind: TxWireGuard[\"kind\"], n: number, error: Error): void {\n if (!(error instanceof Error)) {\n // The error object is the ONLY thing that describes this failure to the\n // caller — the server sends back an index, never a message.\n throw new TxPlanError(\n `${this.what}: an expectation needs the Error to throw when it does not ` +\n `hold (e.g. \\`.expect…(new Conflict(\"already accepted\"))\\`).`,\n );\n }\n if (this.guarded) {\n throw new TxPlanError(\n `${this.what} already has an expectation. One operation carries one ` +\n `expectation; declare the second one on its own operation.`,\n );\n }\n this.guarded = true;\n if (this.opIndex === SKIPPED_OP) return;\n this.builder.attachGuard(this.opIndex, kind, n, error);\n }\n}\n\nfunction assertGuardCount(n: number, fn: string): void {\n if (!Number.isInteger(n) || n < 0) {\n throw new TxPlanError(`${fn}(n) needs a non-negative integer, got ${String(n)}`);\n }\n}\n\n/** Bounds mirrored from tx_program.go so an over-sized plan is named here rather\n * than rejected as an opaque 400 after it has crossed the network. */\nconst MAX_OPS = 1000;\nconst MAX_ROWS = 5000;\n\n/**\n * Accumulates ops and the client-side error table while the callback runs.\n *\n * Exported for the runtime and for tests that need the serialised plan without\n * a server; author code never sees it.\n */\nexport class TxPlanBuilder {\n private readonly ops: TxWireOp[] = [];\n /** Errors handed to expectations, indexed by the `slot` the server echoes. */\n private readonly slots: Error[] = [];\n\n /** The table surface handed to the callback. Untyped here; the public\n * `transaction()` signatures put the schema types on top. */\n table(name: string): TxTable<Record<string, unknown>, Record<string, unknown>> {\n return {\n insert: (values) => {\n const encoded = encodeMap(values as Record<string, unknown>, false);\n if (Object.keys(encoded).length === 0) {\n throw new TxPlanError(`${name}.insert() needs at least one column`);\n }\n return this.push({ op: \"insert\", table: name, values: encoded }, `${name}.insert()`);\n },\n\n insertMany: (rows) => {\n if (rows.length === 0) {\n // Nothing to write. Emitting an op would be a guaranteed 400 (the\n // server requires rows), and refusing outright would punish the\n // ordinary \"filtered every candidate out\" case.\n return new TxRowsImpl(this, SKIPPED_OP, `${name}.insertMany()`);\n }\n if (rows.length > MAX_ROWS) {\n throw new TxPlanError(\n `${name}.insertMany() has ${rows.length} rows; the limit is ${MAX_ROWS}. ` +\n `Split the write across requests.`,\n );\n }\n const encoded = rows.map((row) => encodeMap(row as Record<string, unknown>, false));\n assertUniformRows(encoded, name);\n return this.push({ op: \"insertMany\", table: name, rows: encoded }, `${name}.insertMany()`);\n },\n\n updateWhere: (where, set) => {\n const encodedWhere = encodeMap(where as Record<string, unknown>, false);\n const encodedSet = encodeMap(set as Record<string, unknown>, true);\n if (Object.keys(encodedWhere).length === 0) {\n throw new TxPlanError(\n `${name}.updateWhere() needs a filter. An update with no filter ` +\n `rewrites the whole table.`,\n );\n }\n if (Object.keys(encodedSet).length === 0) {\n throw new TxPlanError(`${name}.updateWhere() needs at least one column to set`);\n }\n return this.push(\n { op: \"update\", table: name, set: encodedSet, where: encodedWhere },\n `${name}.updateWhere()`,\n );\n },\n\n deleteWhere: (where) => {\n const encodedWhere = encodeMap(where as Record<string, unknown>, false);\n if (Object.keys(encodedWhere).length === 0) {\n throw new TxPlanError(\n `${name}.deleteWhere() needs a filter. A delete with no filter empties ` +\n `the table.`,\n );\n }\n return this.push(\n { op: \"delete\", table: name, where: encodedWhere },\n `${name}.deleteWhere()`,\n );\n },\n\n select: (where, options) => {\n const op: TxWireOp = { op: \"select\", table: name };\n const encodedWhere = encodeMap((where ?? {}) as Record<string, unknown>, false);\n if (Object.keys(encodedWhere).length > 0) op.where = encodedWhere;\n if (options?.limit !== undefined) {\n if (!Number.isInteger(options.limit) || options.limit < 0) {\n throw new TxPlanError(\n `${name}.select(): limit needs a non-negative integer, got ${String(options.limit)}`,\n );\n }\n op.limit = options.limit;\n }\n if (options?.lock !== undefined) op.lock = options.lock;\n return this.push(op, `${name}.select()`);\n },\n };\n }\n\n private push(op: TxWireOp, what: string): TxRows<Record<string, unknown>> {\n if (this.ops.length >= MAX_OPS) {\n throw new TxPlanError(\n `this transaction has ${MAX_OPS} operations, which is the limit. Use ` +\n `insertMany() for bulk writes, or split the work across requests.`,\n );\n }\n const index = this.ops.length;\n this.ops.push(op);\n return new TxRowsImpl(this, index, what);\n }\n\n /** Attach an expectation to an op and record its error in the slot table. */\n attachGuard(opIndex: number, kind: TxWireGuard[\"kind\"], n: number, error: Error): void {\n const op = this.ops[opIndex];\n // Unreachable: the index came from `push`. A loud failure beats a silently\n // unguarded write if that ever stops being true.\n if (!op) throw new TxPlanError(`internal: expectation on unknown operation ${opIndex}`);\n const slot = this.slots.length;\n this.slots.push(error);\n op.guard = { kind, n, slot };\n }\n\n /** The serialisable plan. Empty when the callback described no writes. */\n body(): TxPlanBody {\n return { ops: this.ops };\n }\n\n /** The error the server's `slot` selects, or `null` when it names one this\n * plan never declared (a server/client disagreement, not a tenant error). */\n errorForSlot(slot: number): Error | null {\n return this.slots[slot] ?? null;\n }\n}\n\nfunction assertUniformRows(rows: Record<string, TxWireValue>[], table: string): void {\n const first = rows[0];\n if (!first) return;\n const want = Object.keys(first);\n const wantKey = want.join(\",\");\n for (let i = 1; i < rows.length; i++) {\n const got = Object.keys(rows[i] as Record<string, TxWireValue>);\n if (got.join(\",\") !== wantKey) {\n // One statement, one column list. A ragged row would take the DB default\n // for the column it omitted — a write that succeeds and is wrong.\n throw new TxPlanError(\n `${table}.insertMany(): every row must set the same columns. Row 0 sets ` +\n `[${want.join(\", \")}] but row ${i} sets [${got.join(\", \")}]. ` +\n `(A property set to \\`undefined\\` counts as absent — use \\`null\\`.)`,\n );\n }\n }\n}\n\n// ---------------------------------------------------------------------------\n// Runtime — materialisation\n// ---------------------------------------------------------------------------\n\n/**\n * Replace every handle in the callback's return value with what the server\n * actually produced.\n *\n * Walks arrays and PLAIN objects only. Class instances (a Date, a Zod schema, a\n * domain object) are returned untouched — recursing into them would rebuild them\n * as bare objects, and nothing inside one can be a handle that this SDK created.\n */\nexport function materializeResult(value: unknown, results: TxPlanOpResult[]): unknown {\n const ref = refDescriptor(value);\n if (ref) {\n const row = rowOf(results, ref.op, `\\`${ref.field}\\``);\n if (!(ref.field in row)) {\n throw new TxPlanError(\n `the transaction's operation ${ref.op} returned no column \\`${ref.field}\\`.`,\n );\n }\n return row[ref.field];\n }\n\n const rowOp = rowOpIndex(value);\n if (rowOp !== null) return rowOf(results, rowOp, \"a row\");\n\n if (isRowsHandle(value)) {\n throw new TxPlanError(\n \"an operation result cannot be returned from a transaction callback: its \" +\n \"row count is not known until the plan runs. Declare an expectation \" +\n \"(`.expectOne(err)`) and return the row, or a column of it.\",\n );\n }\n\n if (Array.isArray(value)) return value.map((item) => materializeResult(item, results));\n\n if (isPlainObject(value)) {\n const out: Record<string, unknown> = {};\n for (const [key, item] of Object.entries(value)) out[key] = materializeResult(item, results);\n return out;\n }\n\n return value;\n}\n\nfunction rowOf(results: TxPlanOpResult[], opIndex: number, what: string): Record<string, unknown> {\n const result = results[opIndex];\n if (!result) {\n throw new TxPlanError(\n `the transaction returned no result for operation ${opIndex}, so ${what} ` +\n `cannot be read.`,\n );\n }\n const row = result.rows[0];\n if (!row) {\n // Unreachable through the public API: a handle only exists behind an\n // `expectOne`, and the server rolls back rather than answering 200 with a\n // guard unmet. Loud, because the alternative is `undefined` in tenant data.\n throw new TxPlanError(\n `the transaction's operation ${opIndex} returned no row, so ${what} cannot ` +\n `be read.`,\n );\n }\n return row;\n}\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n if (typeof value !== \"object\" || value === null) return false;\n const proto: unknown = Object.getPrototypeOf(value);\n return proto === Object.prototype || proto === null;\n}\n\n// ---------------------------------------------------------------------------\n// Runtime — the driver\n// ---------------------------------------------------------------------------\n\n/** What {@link runTxPlan} needs from the runtime: one call, one transaction. */\nexport interface TxPlanTransport {\n txPlan(plan: TxPlanBody): Promise<TxPlanResponse>;\n}\n\n/**\n * Build the plan, send it, and resolve the callback's return value.\n *\n * A callback that throws never reaches the network: there is nothing to roll\n * back because nothing was sent. A callback that describes no writes also skips\n * the round trip entirely.\n *\n * The RETURN type is `unknown` here on purpose. `Materialized<T>` is a compile-\n * time rewrite of the callback's return type, and it belongs on the public\n * `transaction()` signatures where `T` is inferred from the author's callback;\n * threading it through this driver as well would mean inferring `T` twice, from\n * two different positions, and reconciling them. The public wrappers narrow\n * once, at the seam where the value types were erased anyway.\n */\nexport async function runTxPlan<TTables>(\n transport: TxPlanTransport,\n tables: TTables,\n builder: TxPlanBuilder,\n fn: (tx: TxPlanHandle<TTables>) => unknown,\n): Promise<unknown> {\n const returned = fn({ tables });\n const body = builder.body();\n if (body.ops.length === 0) {\n return materializeResult(returned, []);\n }\n\n let response: TxPlanResponse;\n try {\n response = await transport.txPlan(body);\n } catch (err) {\n throw translateRejection(err, builder);\n }\n return materializeResult(returned, response.results);\n}\n\n/**\n * Turn the broker's rejection back into the tenant's own error.\n *\n * The server never sees the `Error` an expectation was given — only its slot\n * index — so this is the only place the intended error can be produced. A\n * rejection this SDK does not recognise passes through untouched: inventing an\n * error for it would hide the real failure.\n */\nfunction translateRejection(err: unknown, builder: TxPlanBuilder): unknown {\n if (typeof err !== \"object\" || err === null) return err;\n const rejection = err as TxPlanRejection;\n if (rejection.error_code !== \"tx_guard_failed\" || typeof rejection.slot !== \"number\") {\n return err;\n }\n return builder.errorForSlot(rejection.slot) ?? err;\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/**\n * 400 — the request was malformed or failed validation. Carries a fixed typed\n * payload: `new BadRequest({ fields: [{ field: \"email\", message: \"invalid\" }] })`.\n * The shape is declared once in the SDK so codegen surfaces `error.data.fields`\n * typed on the client.\n */\nexport class BadRequest extends NamedHttpError {\n public declare readonly data: BadRequestData;\n constructor(data: BadRequestData, message?: string) {\n super(400, \"bad_request\", \"BadRequest\", message, undefined, 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/** A single field-level validation failure carried by {@link BadRequest}. */\nexport interface FieldError {\n /** The offending field's name (dotted path for nested fields). */\n field: string;\n /** Human-readable reason the field failed. */\n message: string;\n}\n\n/** The fixed, typed payload {@link BadRequest} ships. */\nexport interface BadRequestData {\n /** The fields that failed validation. */\n fields: FieldError[];\n}\n\n/** The fixed, typed payload {@link TooManyRequests} ships. */\nexport interface TooManyRequestsData {\n /** Seconds the caller should wait before retrying. */\n retryAfter: number;\n}\n\n/**\n * 429 — the caller has exceeded the rate limit. Carries a fixed typed payload:\n * `new TooManyRequests({ retryAfter: 30 })`. The shape is declared once in the\n * SDK (error-registry pre-seed) so codegen surfaces `error.data.retryAfter`\n * typed on the client — no per-project definition needed.\n */\nexport class TooManyRequests extends NamedHttpError {\n public declare readonly data: TooManyRequestsData;\n constructor(data: TooManyRequestsData, message?: string) {\n super(429, \"too_many_requests\", \"TooManyRequests\", message, undefined, data);\n }\n}\n","/**\n * Map palstore's thrown errors onto palbase's wire envelope.\n *\n * This mapping is REQUIRED, not cosmetic: the runtime only serializes a throw\n * that carries `{ status: number, error: string }` (worker.js's HttpError\n * catch). A palstore error carries `{ status, code }` — no `error` — so an\n * unmapped `QuotaExceededError` would leave the handler as a 500 and the client\n * would see \"internal error\" for a perfectly ordinary exhausted quota.\n *\n * The detection is STRUCTURAL (`code` + `status`) rather than `instanceof`,\n * because `@palbase/backend` deliberately has no dependency on\n * `@palstore/purchases` — see purchases/service.ts for why.\n */\n\nimport { HttpError, PalError } from \"../errors.js\";\n\n/** The shape every `PalstoreError` subclass presents: a stable snake_case wire\n * code plus the HTTP status it stands for. */\ninterface PalstoreErrorLike {\n code: string;\n status: number;\n message: string;\n}\n\nfunction asPalstoreError(err: unknown): PalstoreErrorLike | null {\n if (!(err instanceof Error)) return null;\n const e = err as Error & { code?: unknown; status?: unknown };\n if (typeof e.code !== \"string\" || typeof e.status !== \"number\") return null;\n return { code: e.code, status: e.status, message: e.message };\n}\n\n/**\n * Translate a purchases failure into an `HttpError`, or return the error\n * untouched when it is not one.\n *\n * Anything unrecognised is rethrown VERBATIM — a transport failure, a bug, a\n * 500 from palstore — because turning an unknown fault into a tidy 403/429\n * would tell the client \"you lack access\" when the truth is \"we are broken\",\n * and would hide the outage from whoever is on call.\n */\nexport function toHttpError(err: unknown): unknown {\n // Already a palbase error (e.g. the 401 from subject resolution): leave it.\n if (err instanceof HttpError) return err;\n\n const p = asPalstoreError(err);\n if (!p) return err;\n\n switch (p.code) {\n case \"entitlement_required\": {\n const entitlement = (err as { entitlement?: unknown }).entitlement ?? null;\n return new PalError(403, \"entitlement_required\", p.message, { entitlement });\n }\n case \"quota_exceeded\":\n case \"credit_insufficient\": {\n // The LimitState/CreditState rides on `data` so a client can render the\n // real ceiling and reset time instead of guessing a retry delay. This is\n // why the 429 is NOT palbase's `TooManyRequests`: that class fixes its\n // payload to `{ retryAfter }`, which is rate-limiting's shape, not a\n // quota's — and squeezing a LimitState through it would drop `max`,\n // `used` and `remaining`, the three fields a paywall needs.\n const state = (err as { state?: unknown }).state;\n return new PalError(429, p.code, p.message, state);\n }\n default:\n return err;\n }\n}\n\n/** Run `fn`, translating any purchases failure on the way out. */\nexport async function mappingPurchaseErrors<T>(fn: () => Promise<T>): Promise<T> {\n try {\n return await fn();\n } catch (err) {\n throw toHttpError(err);\n }\n}\n","/**\n * Per-method purchases metadata, stored on the controller class the same way\n * `decorators/registry.ts` stores routes: a symbol-keyed static, plain data, no\n * `reflect-metadata`.\n *\n * Its only consumer is the OpenAPI step, which needs to know that a route is\n * gated (declare 403) or metered (declare 429) so the iOS client codegen emits\n * TYPED errors instead of a bare status number. Enforcement does NOT read this\n * — the decorators wrap the method directly — so a stale registry can never\n * cause a missed gate.\n */\n\nimport type { EntitlementKey, LimitKey } from \"./keys.js\";\n\nconst ENTITLEMENTS: unique symbol = Symbol.for(\"palbase.backend.purchases.entitlements\");\nconst SPENDS: unique symbol = Symbol.for(\"palbase.backend.purchases.spends\");\n\n/** What `@Spend` recorded for one method. */\nexport interface SpendMeta {\n key: LimitKey;\n count: number;\n}\n\ninterface PurchasesCarrier {\n [ENTITLEMENTS]?: Record<string, EntitlementKey>;\n [SPENDS]?: Record<string, SpendMeta>;\n}\n\n/** Resolve a decorated target (prototype or constructor) to the constructor\n * that owns the metadata, mirroring `carrierOf` in decorators/registry.ts. */\nfunction carrierOf(target: object): PurchasesCarrier {\n return (\n typeof target === \"function\"\n ? (target as unknown as PurchasesCarrier)\n : (((target as { constructor?: unknown }).constructor ?? target) as PurchasesCarrier)\n );\n}\n\n/** Own (not inherited) slot, so a subclass never mutates its base's metadata. */\nfunction own<K extends typeof ENTITLEMENTS | typeof SPENDS>(\n carrier: PurchasesCarrier,\n slot: K,\n): NonNullable<PurchasesCarrier[K]> {\n if (!Object.prototype.hasOwnProperty.call(carrier, slot)) {\n carrier[slot] = {} as never;\n }\n return carrier[slot] as NonNullable<PurchasesCarrier[K]>;\n}\n\nexport function recordEntitlement(target: object, fnName: string, key: EntitlementKey): void {\n own(carrierOf(target), ENTITLEMENTS)[fnName] = key;\n}\n\nexport function recordSpend(target: object, fnName: string, meta: SpendMeta): void {\n own(carrierOf(target), SPENDS)[fnName] = meta;\n}\n\n/** The entitlement `fnName` is gated on, or undefined when it is not gated. */\nexport function entitlementFor(ctor: object, fnName: string): EntitlementKey | undefined {\n return carrierOf(ctor)[ENTITLEMENTS]?.[fnName];\n}\n\n/** What `fnName` spends, or undefined when it spends nothing. */\nexport function spendFor(ctor: object, fnName: string): SpendMeta | undefined {\n return carrierOf(ctor)[SPENDS]?.[fnName];\n}\n","/**\n * subject.ts — the ONLY place a purchases subject is resolved.\n *\n * The subject is derived from the SERVER-OWNED authenticated user on the\n * request context. It is never a decorator argument, never a body field, never\n * a header. A caller who could name their own subject could read someone\n * else's entitlements or spend someone else's quota, so the surface simply\n * offers no way to say it — `currentSubjectId()` takes no parameters.\n */\n\nimport { Purchases, __requestALS, type RequestStore } from \"../runtime.js\";\nimport { Unauthorized } from \"../errors.js\";\nimport type { StoreEnv } from \"./service.js\";\n\n/**\n * Per-request memo, keyed on the ALS box (one object per request, collected\n * with it). Both decorators on one route need the subject; resolving it twice\n * would double the round-trip to palstore for no gain. Kept here rather than as\n * a field on `RequestStore` so the core request type stays free of purchases\n * concerns.\n *\n * The PROMISE is memoized, not the resolved value, so two decorators that race\n * (or any concurrent caller) share one in-flight resolution instead of firing\n * two and keeping the loser.\n */\nconst subjectByRequest = new WeakMap<RequestStore, Promise<string>>();\n\n/**\n * The store environment subjects resolve against. Sandbox purchases are\n * isolated from production ones all the way down the palstore schema, so this\n * is a DEPLOYMENT fact, not a per-request one — a request cannot select it.\n * Defaults to production: a project that forgets to set it gets the strict\n * environment, never a sandbox subject that would accept test purchases.\n */\nfunction storeEnv(): StoreEnv {\n return process.env.PALSTORE_STORE_ENV === \"sandbox\" ? \"sandbox\" : \"production\";\n}\n\n/**\n * Resolve the palstore subject for the request in scope.\n *\n * Throws 401 when the request carries no authenticated user — and does so\n * BEFORE any call to palstore, so an anonymous request never mints a subject.\n */\nexport async function currentSubjectId(): Promise<string> {\n // Async, so every failure is a rejection — a Promise-returning function that\n // sometimes throws synchronously is a footgun for `.catch()`-only callers.\n // The body runs to the memo write before its first await, so two concurrent\n // callers still share one resolution.\n const store = __requestALS.getStore();\n if (!store) {\n throw new Error(\n \"Purchases decorators used outside a request scope. @RequireEntitlement/@Spend \" +\n \"resolve the subject from the request's authenticated user, so they only work \" +\n \"inside an endpoint handler.\",\n );\n }\n\n const memoized = subjectByRequest.get(store);\n if (memoized) return memoized;\n\n const userId = store.userId;\n if (!userId) {\n throw new Unauthorized(\n \"This endpoint requires an authenticated user: purchases entitlements and quota \" +\n \"are per-user, and the subject is resolved from the request's identity.\",\n );\n }\n\n const resolving = Purchases.resolveSubject({ userRef: userId, storeEnv: storeEnv() }).then(\n (r) => r.subjectId,\n );\n // ponytail: a failed resolution is NOT memoized — cache the promise, then drop\n // it on rejection so the next request-scoped caller retries instead of\n // inheriting a permanently poisoned subject for the life of the request.\n subjectByRequest.set(store, resolving);\n resolving.catch(() => subjectByRequest.delete(store));\n return resolving;\n}\n","/**\n * `@RequireEntitlement` and `@Spend` — access and metering at the decorator\n * level, so a controller method says what it costs instead of wiring it.\n *\n * TWO decorators, deliberately, because not every subscription is limit-based.\n * Most products just say \"pro users may call this\" and consume nothing; a\n * zero-count spend would express that badly and run the whole reserve/commit\n * machine for no reason.\n *\n * @RequireEntitlement('pro') pure gate → 403, consumes nothing\n * @Spend('bookCreate') consumption → 429 when exhausted\n *\n * ORDER IS FIXED, and not by where you wrote them. Both decorators record\n * metadata and share ONE installed wrapper that always runs the entitlement\n * gate before it reserves quota. Reserving for someone who is about to get a\n * 403 is wasted work and a race window, so the source order of the two\n * decorators cannot introduce it.\n */\n\nimport { Purchases, __requestALS } from \"../runtime.js\";\nimport { toHttpError } from \"./errors.js\";\nimport type { EntitlementKey, LimitKey } from \"./keys.js\";\nimport { entitlementFor, recordEntitlement, recordSpend, spendFor } from \"./registry.js\";\nimport { currentSubjectId } from \"./subject.js\";\n\n/** Marks a method whose purchases wrapper is already installed, so applying\n * both decorators wraps once rather than nesting two half-pipelines. */\nconst WRAPPED: unique symbol = Symbol.for(\"palbase.backend.purchases.wrapped\");\n\ntype Wrapped = ((...args: unknown[]) => unknown) & { [WRAPPED]?: true };\n\ntype MethodDecorator = (\n target: object,\n propertyKey: string | symbol,\n descriptor: PropertyDescriptor,\n) => void;\n\n/**\n * The idempotency key for this request's spend.\n *\n * palstore requires one (§9 scopes idempotency by `(project_ref, subject_id,\n * operation, idempotency_key)`) and refuses a call without it rather than\n * running it non-idempotently. The caller's `Idempotency-Key` header is the\n * honest source — it is what makes a client's RETRY replay the first result\n * instead of charging twice. With no header we fall back to the request id,\n * which still satisfies the server and still makes the two decorators on one\n * request share a scope, but cannot deduplicate across a retry the client\n * never labelled.\n *\n * Suffixed with the limit key so two different `@Spend`s reached in one request\n * are separate operations rather than a self-collision.\n */\nfunction idempotencyKeyFor(key: LimitKey): string {\n const store = __requestALS.getStore();\n const base = store?.idempotencyKey || store?.requestId;\n if (!base) {\n throw new Error(\n \"@Spend needs a request-scoped idempotency key, and the runtime supplied neither an \" +\n \"Idempotency-Key header nor a request id. Spending without one would let a retried \" +\n \"request charge the user twice.\",\n );\n }\n return `${base}:${key}`;\n}\n\n/**\n * Install the single purchases wrapper on a method, if it is not there yet.\n *\n * The wrapper reads the registry at CALL time, so whichever decorator happens\n * to be applied first still yields the same fixed pipeline.\n */\nfunction ensureWrapper(target: object, fnName: string, descriptor: PropertyDescriptor): void {\n const original = descriptor.value as Wrapped | undefined;\n if (typeof original !== \"function\") {\n throw new Error(\n `@RequireEntitlement/@Spend can only decorate a method; \"${fnName}\" is not one.`,\n );\n }\n if (original[WRAPPED]) return;\n\n const wrapper = async function (this: unknown, ...args: unknown[]): Promise<unknown> {\n const ctor = (this as { constructor: object }).constructor;\n const entitlement = entitlementFor(ctor, fnName);\n const spend = spendFor(ctor, fnName);\n\n // One resolution per request, shared by both decorators (subject.ts memoizes).\n let subjectId: string;\n try {\n subjectId = await currentSubjectId();\n } catch (err) {\n throw toHttpError(err);\n }\n\n // GATE FIRST — always, regardless of decoration order.\n if (entitlement !== undefined) {\n try {\n await Purchases.require(subjectId, entitlement);\n } catch (err) {\n throw toHttpError(err);\n }\n }\n\n if (spend === undefined) {\n return original.apply(this, args);\n }\n\n // `withSpend` reserves, runs, then commits on success / cancels on throw,\n // always rethrowing the handler's own error. We track that error by\n // identity so the mapping below never reshapes a tenant's exception into a\n // purchases one on its way out.\n let handlerFailure: { err: unknown } | undefined;\n try {\n return await Purchases.withSpend(\n subjectId,\n spend.key,\n { count: spend.count, idempotencyKey: idempotencyKeyFor(spend.key) },\n async () => {\n try {\n return await original.apply(this, args);\n } catch (err) {\n handlerFailure = { err };\n throw err;\n }\n },\n );\n } catch (err) {\n if (handlerFailure !== undefined && handlerFailure.err === err) throw err;\n throw toHttpError(err);\n }\n } as Wrapped;\n\n wrapper[WRAPPED] = true;\n descriptor.value = wrapper;\n}\n\n/**\n * Require an active entitlement. Answers 403 `entitlement_required` when it is\n * absent and consumes nothing.\n *\n * The key is a member of the generated `EntitlementKey` union, so a typo is a\n * compile error rather than a gate that silently never matches.\n */\nexport function RequireEntitlement(key: EntitlementKey): MethodDecorator {\n return function (target, propertyKey, descriptor) {\n const fnName = String(propertyKey);\n recordEntitlement(target, fnName, key);\n ensureWrapper(target, fnName, descriptor);\n };\n}\n\n/**\n * Consume one unit of a limit or credit for the request's subject.\n *\n * Reserves before the handler runs and commits only if it returns; a throw\n * cancels the hold, so a user is never charged for work that did not complete.\n * Answers 429 `quota_exceeded` (carrying the `LimitState`) when exhausted.\n *\n * The count is fixed at 1. A DYNAMIC amount is deliberately not expressible\n * here: it has to be decided inside the handler and spent BEFORE the billable\n * side-effect, which is an explicit `Purchases.withSpend(...)` call, not a\n * decorator.\n */\nexport function Spend(key: LimitKey): MethodDecorator {\n return function (target, propertyKey, descriptor) {\n const fnName = String(propertyKey);\n recordSpend(target, fnName, { key, count: 1 });\n ensureWrapper(target, fnName, descriptor);\n };\n}\n","/**\n * keys-gen.ts — generate the `palbase-purchases.d.ts` text from a catalog\n * manifest.\n *\n * The twin of `db/env-gen.ts`: the CLI / deploy pipeline calls\n * {@link makePurchasesDts} with the project's catalog revision and writes the\n * result to `palbase-purchases.d.ts` at the project root. That file augments\n * the `@palbase/backend/purchases` `Entitlements` / `Limits` interfaces, so\n * `@RequireEntitlement(...)` and `@Spend(...)` accept the project's real keys\n * and nothing else.\n *\n * Same catalog, two languages: this is the TypeScript half of what swiftgen\n * already emits for iOS. Neither side is hand-maintained, so the two cannot\n * drift from each other or from the manifest the server validated.\n *\n * The emitted file ends in `export {};` — same as `makeEnvDts`. Without it the\n * `.d.ts` is a global script, and `declare module \"…\"` there DECLARES an\n * ambient module (shadowing the real one, so every key silently becomes\n * invalid) instead of AUGMENTING it.\n */\n\n/** A catalog entry that may be tombstoned. */\ninterface Removable {\n removed?: boolean;\n}\n\n/**\n * The slice of `pur_catalogs.manifest` this generator reads. Deliberately\n * partial and permissive: the server already validated the manifest (its models\n * are `extra=\"forbid\"`), so re-checking here would be a second, weaker copy of\n * that authority.\n */\nexport interface PurchasesManifest {\n limits?: Record<string, Removable>;\n credits?: Record<string, Removable>;\n entitlements?: Record<string, Removable>;\n}\n\n/** Live keys, sorted, with tombstones dropped.\n *\n * `removed: true` is the catalog's tombstone: the key still exists so historical\n * receipts resolve, but it must NOT be offered to new code. Emitting it would\n * let a handler compile against a limit the project has retired. */\nfunction liveKeys(entries: Record<string, Removable> | undefined): string[] {\n return Object.entries(entries ?? {})\n .filter(([, def]) => def?.removed !== true)\n .map(([key]) => key)\n .sort();\n}\n\n/** A bare identifier stays bare; anything else is quoted. */\nfunction memberName(key: string): string {\n return /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(key) ? key : JSON.stringify(key);\n}\n\nfunction members(keys: string[]): string {\n if (keys.length === 0) return \"\";\n return `\\n${keys.map((k) => ` ${memberName(k)}: true;`).join(\"\\n\")}\\n `;\n}\n\n/**\n * Render the project's `palbase-purchases.d.ts`.\n *\n * `Limits` carries BOTH limits and credits: `@Spend` consumes either, and the\n * server answers both with a 429 (`quota_exceeded` / `credit_insufficient`), so\n * splitting them into two unions would make the author pick the right decorator\n * for a distinction the spend path does not make.\n */\nexport function makePurchasesDts(manifest: PurchasesManifest): string {\n const entitlements = liveKeys(manifest.entitlements);\n const limits = liveKeys({ ...manifest.limits, ...manifest.credits });\n\n return `// palbase-purchases.d.ts — GENERATED by @palbase/backend. Do not edit.\n// Source: the project's palstore catalog revision.\n\ndeclare module \"@palbase/backend/purchases\" {\n interface Entitlements {${members(entitlements)}}\n\n interface Limits {${members(limits)}}\n}\n\nexport {};\n`;\n}\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\";\nimport type { RawConstraintDef } from \"./raw.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. **Defaults to\n * `true`**, and is forced on when `policies` is non-empty. A table with RLS\n * and no policies is deny-all, which is the starting state: nothing reads it\n * until a policy says who may. Set `rls: false` only for a genuinely public\n * table — it is an explicit opt-out that a reviewer can grep for, not\n * something you get by forgetting.\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 /** Composite/named primary key (ordered column names). Omit for single-column inline .primaryKey(). */\n primaryKey?: string[];\n /** Named multi-column UNIQUE constraints. */\n unique?: { name: string; columns: string[] }[];\n /** Named raw-SQL DDL objects (EXCLUDE, triggers, views) that the typed DSL cannot express. */\n raw?: RawConstraintDef[];\n /**\n * Named first-class CHECK constraints. Diffed by NAME with a BODY compare:\n * a changed `expr` (after pg normalization) recreates the constraint\n * (DROP + ADD). `expr` is trusted SQL emitted verbatim (like policy USING),\n * `name` is identifier-validated.\n */\n checks?: { name: string; expr: string }[];\n /**\n * Plain (non-unique) btree indexes over an ordered column list, emitted as\n * standalone `CREATE INDEX [IF NOT EXISTS] name ON table (col1, col2)`\n * statements (NOT a table clause — a separate migration statement category).\n * Structural compare by NAME (no expression normalization). `name` and each\n * column are identifier-validated by the Go differ.\n *\n * Scope: columns-only plain btree. Partial (`where`) and expression indexes\n * are a deliberate follow-up — modelling them needs the same raw-SQL\n * normalization round-trip CHECK uses (Task 10), so they are NOT in this\n * type yet to avoid a half-working partial-index path.\n */\n indexes?: { name: string; columns: string[] }[];\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 `true`/`[]`).\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 primaryKey?: string[];\n unique?: { name: string; columns: string[] }[];\n /** Named raw-SQL DDL objects emitted verbatim on deploy. Tracked by name. */\n raw?: RawConstraintDef[];\n /** Named first-class CHECK constraints. Diffed by name + (normalized) body. */\n checks?: { name: string; expr: string }[];\n /** Plain btree indexes (columns-only), emitted as standalone CREATE INDEX. Diffed by name. */\n indexes?: { name: string; columns: string[] }[];\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 **`true`**, `policies` to `[]`. A table\n * that declares neither is therefore deny-all — nothing reads it until a policy\n * says who may, which is the safe starting point rather than a bug. Declare\n * `rls: false` for a genuinely public table; that is an explicit, greppable\n * statement of intent instead of an omission. When `policies` is non-empty,\n * `rls` is forced on (ENABLE + FORCE) regardless of the declared flag — a table\n * with policies must have RLS enabled or the 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 // Fail closed. RLS is on unless the schema explicitly says `rls: false`, and\n // policies force it on regardless — a policy on a table without RLS enabled\n // is inert, so declaring both is a contradiction that resolves towards the\n // safe reading.\n //\n // This defaulted to `false` until 2026-08-07, which meant a table nobody\n // thought about had no row-level security while `typed-db.ts` documented the\n // default `Database.*` path as RLS-enforced. Both cannot be true, and the\n // live proof settled which one was not: user B read user A's row in full\n // through the typed client, while the same request against a table declaring\n // `rls: true` returned 0 of 165 rows\n // (docs/superpowers/uat/2026-08-07-rls-fail-open-proof.md). With no policies\n // this is deny-all, so an unconsidered table now returns nothing instead of\n // returning everything to everyone.\n const rls = policies.length > 0 || table.rls !== false;\n const tableDef: TableDef<T[typeof name][\"columns\"]> = {\n name: name as string,\n columns: table.columns,\n rls,\n policies,\n };\n if (table.primaryKey !== undefined) tableDef.primaryKey = table.primaryKey;\n if (table.unique !== undefined) tableDef.unique = table.unique;\n if (table.raw !== undefined && table.raw.length > 0) tableDef.raw = table.raw.slice();\n if (table.checks !== undefined && table.checks.length > 0) tableDef.checks = table.checks.slice();\n if (table.indexes !== undefined && table.indexes.length > 0) tableDef.indexes = table.indexes.slice();\n tables[name] = tableDef;\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 // Indexing & constraints\n \"btree_gist\", // GiST operator classes for scalar types — needed for EXCLUDE\n // constraints that mix \"=\" with a range/&& overlap (e.g. no-double-booking).\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/**\n * The ON DELETE actions permitted on a foreign key to the built-in auth users\n * (`auth.users`). Both let a user's rows be removed (`cascade`) or detached\n * (`set null`) when the account is erased; `restrict` / `no action` would BLOCK\n * erasure and are therefore excluded. This is the CLIENT-SIDE mirror of the\n * server's auth-FK deletion policy — the server (validateAuthUserFK) is the real\n * boundary, this narrows the type so the common mistake is caught at compile time.\n */\nexport type AuthUserOnDelete = Extract<OnDeleteAction, 'cascade' | 'set null'>;\n\n/** Column type identifiers. */\nexport type ColumnType =\n | 'uuid'\n | 'text'\n | 'integer'\n | 'bigint'\n | 'numeric'\n | 'boolean'\n | 'timestamp'\n | 'jsonb'\n | '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 unique?: boolean;\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;\ndeclare const __colPayload: 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 * P — jsonb payload shape (unknown unless jsonb<T>() supplied one)\n *\n * All five params have defaults so bare `ColumnBuilder` (no args) still\n * satisfies `Record<string, ColumnBuilder>` in schema.ts without modification.\n *\n * The five `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 P = 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 declare readonly [__colPayload]: P;\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, P> {\n this._def.primaryKey = true;\n return new ColumnBuilder<K, N, D, E, P>(this._def.type as K, this._def);\n }\n\n /** Mark this column as NOT NULL (default). */\n notNull(): ColumnBuilder<K, false, D, E, P> {\n this._def.nullable = false;\n return new ColumnBuilder<K, false, D, E, P>(this._def.type as K, this._def);\n }\n\n /** Allow NULL values. */\n nullable(): ColumnBuilder<K, true, D, E, P> {\n this._def.nullable = true;\n return new ColumnBuilder<K, true, D, E, P>(this._def.type as K, this._def);\n }\n\n /** Set a default value. */\n default(value: unknown): ColumnBuilder<K, N, true, E, P> {\n this._def.defaultValue = value;\n return new ColumnBuilder<K, N, true, E, P>(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, P> {\n this._def.defaultRandom = true;\n return new ColumnBuilder<K, N, true, E, P>(this._def.type as K, this._def);\n }\n\n /** Timestamp: default to now(). */\n defaultNow(): ColumnBuilder<K, N, true, E, P> {\n this._def.defaultNow = true;\n return new ColumnBuilder<K, N, true, E, P>(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, P> {\n this._def.references = { table, column };\n return new ColumnBuilder<K, N, D, E, P>(this._def.type as K, this._def);\n }\n\n /**\n * Add a real DB-level foreign key to the built-in auth users\n * (`REFERENCES auth.users(id)`), so a column like `user_id` gets true\n * database cascade/integrity instead of app-layer-only. Sugar for\n * `.references(\"auth.users\", \"id\")`.\n *\n * `auth.users` lives in the SAME tenant database (palauth-owned), so this is\n * a genuine cross-schema integrity constraint scoped to THIS tenant's users.\n * The referenced `auth.users.id` is `text` (palauth ids are `usr_<uuid>`), so\n * the referencing column must be `text()` too.\n *\n * ON DELETE is REQUIRED here and may only be `cascade` or `set null`: an\n * account-erasure request must never be blocked by a lingering FK, so\n * `restrict` / `no action` are not accepted (they don't type-check). Example:\n * `text().notNull().referencesAuthUser(\"cascade\")`, or\n * `text().nullable().referencesAuthUser(\"set null\")`. The server\n * (validateAuthUserFK) enforces this — and the remaining rules the type can't\n * express (referencing column is text, `set null` needs a nullable column) —\n * as the real boundary; this signature is the compile-time DX mirror.\n */\n referencesAuthUser(onDelete: AuthUserOnDelete): ColumnBuilder<K, N, D, E, P> {\n this._def.references = { table: 'auth.users', column: 'id' };\n this._def.onDeleteAction = onDelete;\n return new ColumnBuilder<K, N, D, E, P>(this._def.type as K, this._def);\n }\n\n /**\n * Add a real DB-level foreign key to the canonical, server-minted installation\n * anchor (`REFERENCES auth.installations(id)`) — the app-scoped verified-device\n * root (`ins_...`). Sugar for `.references(\"auth.installations\", \"id\")`.\n *\n * An installation is an APP INSTALL, not a user: this FK is NOT user ownership.\n * A user-owned row STILL needs its own `.referencesAuthUser(...)` FK so account\n * erasure removes it — an installation reference alone does not tie a row to a\n * user's deletion. Use this only for install-scoped state (device prefs, push\n * routing, …), alongside a separate auth-user FK where the row is user-owned.\n *\n * `auth.installations` lives in the SAME tenant DB (palauth-owned); its `id` is\n * `text` (`ins_<uuid>`), so the referencing column must be `text()` too. ON\n * DELETE is REQUIRED and may only be `cascade` or `set null` (same allowed set\n * as an auth-user FK): an installation revoke / orphan cleanup must never be\n * blocked by a lingering FK. The server (validateAuthAnchorFK) is the real\n * boundary; this signature is the compile-time DX mirror.\n */\n referencesInstallation(onDelete: AuthUserOnDelete): ColumnBuilder<K, N, D, E, P> {\n this._def.references = { table: 'auth.installations', column: 'id' };\n this._def.onDeleteAction = onDelete;\n return new ColumnBuilder<K, N, D, E, P>(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, P> {\n this._def.onDeleteAction = action;\n return new ColumnBuilder<K, N, D, E, P>(this._def.type as K, this._def);\n }\n\n /** Add a single-column UNIQUE constraint. */\n unique(): ColumnBuilder<K, N, D, E, P> {\n this._def.unique = true;\n return new ColumnBuilder<K, N, D, E, P>(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\" | \"bigint\" | \"numeric\" → string (or string | null when N = true)\n * Note: bigint/numeric surface as string — JS number loses precision past 2^53,\n * and pgx/PostgREST serialize int8/numeric as strings. App code uses\n * BigInt(row.amount) for bigint, or a decimal lib for numeric.\n * - \"integer\" → number\n * - \"boolean\" → boolean\n * - \"jsonb\" → P (the dev-supplied payload shape from jsonb<T>(), else unknown)\n * - \"enum\" → E (the union of literal values)\n */\nexport type ColValue<C> =\n C extends ColumnBuilder<'uuid' | 'text' | 'timestamp' | 'bigint' | 'numeric', infer N, infer _D, infer _E, infer _P>\n ? N extends true\n ? string | null\n : string\n : C extends ColumnBuilder<'integer', infer N, infer _D, infer _E, infer _P>\n ? N extends true\n ? number | null\n : number\n : C extends ColumnBuilder<'boolean', infer N, infer _D, infer _E, infer _P>\n ? N extends true\n ? boolean | null\n : boolean\n : C extends ColumnBuilder<'jsonb', infer N, infer _D, infer _E, infer P>\n ? N extends true\n ? P | null\n : P\n : C extends ColumnBuilder<'enum', infer N, infer _D, infer E, infer _P>\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. Emits int4 (max ~2.1B). */\nexport function integer(): ColumnBuilder<'integer', false, false, never> {\n return new ColumnBuilder('integer');\n}\n\n/**\n * Create a BIGINT column (Postgres int8, max ~9.2×10^18).\n * Surfaces as `string` in row/insert types — JS number loses precision past 2^53\n * and pgx/PostgREST serialize int8 as a JSON string. Use BigInt(row.column) in app code.\n */\nexport function bigint(): ColumnBuilder<'bigint', false, false, never> {\n return new ColumnBuilder('bigint');\n}\n\n/**\n * Create a NUMERIC column (Postgres `numeric`/`decimal`, arbitrary precision).\n * For exact fractional values (money with cents as a decimal, rates, weights)\n * where int4/int8 don't fit. Surfaces as `string` in row/insert types — JS\n * number can't hold arbitrary-precision decimals without rounding, and\n * pgx/PostgREST serialize numeric as a JSON string. Parse with a decimal lib\n * (or BigInt for scaled integers) in app code.\n */\nexport function numeric(): ColumnBuilder<'numeric', false, false, never> {\n return new ColumnBuilder('numeric');\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/**\n * Create a JSONB column. Pass a payload type to make the generated row/insert\n * type concrete instead of `unknown`:\n *\n * tags: jsonb<string[]>() // row.tags: string[]\n * meta: jsonb<{ tier: string }>() // row.meta: { tier: string }\n * raw: jsonb() // row.raw: unknown (back-compat)\n *\n * The runtime accepts a plain JS object/array directly (no JSON.stringify); the\n * generic only refines the TYPE the env codegen emits.\n */\nexport function jsonb<T = unknown>(): ColumnBuilder<'jsonb', false, false, never, T> {\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 * A named raw-SQL DDL object declared in db/schema.ts for anything the typed DSL\n * cannot express (EXCLUDE, CHECK, partial/expression indexes, triggers, views).\n * The deploy emits `up` verbatim on the privileged DDL connection — same trust\n * posture as policy().using(). Tracked by NAME (not by diffing the body), so a\n * changed body needs a new name or an explicit drop+add.\n */\nexport interface RawConstraintDef {\n name: string;\n up: string;\n down?: string;\n}\n\nexport function raw(name: string, up: string, opts?: { down?: string }): RawConstraintDef {\n return { name, up, ...(opts?.down != null ? { down: opts.down } : {}) };\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, DBOps } from \"../endpoint.js\";\nimport type { Materialized, TxPlanHandle, TxTable } from \"./tx-plan.js\";\nimport { TxPlanBuilder, runTxPlan } from \"./tx-plan.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 /** Run a transaction plan. See {@link EnvTypedDatabase.transaction}. */\n transaction<T>(\n fn: (tx: TypedTx<S>) => T extends Promise<unknown> ? never : T,\n ): Promise<Materialized<T>>;\n}\n\n/** The plan-building handle a `TypedDB<S>` transaction callback receives: the\n * schema's tables, expressed as plan operations rather than awaited calls. */\nexport type TypedTx<S extends SchemaDef> = TxPlanHandle<{\n [K in keyof S[\"tables\"]]: TxTable<RowShape<S[\"tables\"][K]>, InsertShape<S[\"tables\"][K]>>;\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 `DBOps` (the six string-keyed ops) because this only\n * ever calls those — never `txPlan`, which builds its own operations rather than\n * delegating to these.\n */\nfunction makeTypedTable<T extends TableDef<Record<string, ColumnBuilder>>>(\n name: string,\n raw: DBOps,\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 for the direct ops — all calls\n * delegate to `raw` with the table name as a plain string.\n *\n * `transaction` does NOT delegate to a per-op client: the callback describes a\n * plan against a fresh {@link TxPlanBuilder}, and the whole plan travels in one\n * `raw.txPlan` call. The schema is used only for its table NAMES; the values\n * are typed by `S` at compile time and are plain strings at run time.\n *\n * The `as` casts are single structural narrowings from a dynamically-built\n * object to the precise mapped type (TS cannot infer the mapped-type result\n * through `Object.keys` iteration) — see the module-level doc comment.\n */\nexport function makeTypedDB<S extends SchemaDef>(\n schema: S,\n raw: DBClient,\n): TypedDB<S> {\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, raw);\n }\n }\n\n const result = {\n tables,\n transaction<T>(\n fn: (tx: TypedTx<S>) => T extends Promise<unknown> ? never : T,\n ): Promise<Materialized<T>> {\n const builder = new TxPlanBuilder();\n const planTables: Record<string, unknown> = {};\n for (const key of Object.keys(schema.tables)) {\n const tableDef = schema.tables[key];\n if (tableDef !== undefined) planTables[key] = builder.table(tableDef.name);\n }\n // Two narrowings at the same seam: the plan tables are built by NAME, so\n // TS cannot see the mapped type through the loop, and the driver erases\n // the callback's return type (see runTxPlan's doc). Both are the erasure\n // this facade exists to undo.\n return runTxPlan(\n raw,\n planTables as TypedTx<S>[\"tables\"],\n builder,\n fn,\n ) as Promise<Materialized<T>>;\n },\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/** The project's tables as PLAN operations, keyed by the env `Tables`\n * interface. The transaction twin of {@link EnvTables}. */\nexport type TxTables = {\n [K in keyof Tables]: TxTable<Tables[K][\"row\"], Tables[K][\"insert\"]>;\n};\n\n/**\n * The handle a `Database.transaction(…)` callback receives.\n *\n * Tables only — no `query`, no `findById`, no `asService`. A read whose value\n * the plan does not write belongs outside the transaction, where it costs one\n * round trip and is an ordinary value you can branch on.\n */\nexport type TxPlan = TxPlanHandle<TxTables>;\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, \"txPlan\" | \"asService\"> {\n tables: EnvTables;\n transaction<T>(fn: (tx: TxPlan) => T extends Promise<unknown> ? never : T): Promise<Materialized<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` that runs a whole plan in one request, and `asService()` for\n * the explicit RLS-bypass sibling.\n *\n * The low-level `txPlan` op is deliberately NOT re-exposed here: `transaction`\n * is the surface, and a hand-built plan would bypass the ref/guard machinery\n * that makes one safe to write.\n */\nexport interface EnvTypedDatabase extends Omit<DBClient, \"txPlan\" | \"asService\"> {\n tables: EnvTables;\n /**\n * Run a transaction. The callback DESCRIBES the operations; the whole\n * description travels in one request and the broker runs it inside a single\n * transaction — committing when it finishes, rolling back on any failure.\n *\n * The callback is SYNCHRONOUS: nothing has run when it returns, so there is\n * nothing to await. `async` on it and `await` inside it are compile errors.\n * Values a later operation needs are {@link Ref}s, written straight into the\n * next operation; values the CALLER needs are returned and substituted before\n * this promise resolves.\n *\n * @example\n * const { statementId } = await Database.transaction((tx) => {\n * const st = tx.tables.statements\n * .insert({ household_id: hid, file_sha256: sha, status: \"reviewing\" })\n * .expectOne(new Internal(\"statement insert failed\"));\n *\n * tx.tables.statement_lines.insertMany(\n * lines.map((l) => ({ statement_id: st.id, category: resolveCategory(l) })),\n * );\n *\n * return { statementId: st.id };\n * });\n */\n transaction<T>(fn: (tx: TxPlan) => T extends Promise<unknown> ? never : T): Promise<Materialized<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 db types` / 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 // Both are exact-precision in Postgres and lossy as a JSON number, so the\n // database proxy serializes them as strings — measured: 9007199254740993\n // used to arrive as ...992 and 41.00821234567890123 as 41.0082123456789.\n // numeric had no case at all and fell through to `unknown`, which typed\n // every numeric column out of existence.\n case \"bigint\":\n case \"numeric\":\n return \"string\";\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/** The table a foreign key must target for its column to be the OWNER column —\n * what `.referencesAuthUser(...)` writes into `ColumnDef.references.table`. */\nconst AUTH_USERS_TABLE = \"auth.users\";\n\n/**\n * The table's owner column: the one that foreign-keys `auth.users`, i.e. the\n * column a row is \"owned by\". Declared in `db/schema.ts` via\n * `.referencesAuthUser(...)` — we read the declaration rather than parsing the\n * RLS policy body, because the FK IS the ownership statement.\n *\n * When several columns reference `auth.users` (e.g. `user_id` and `created_by`)\n * the FIRST in declaration order wins — deterministic, and the remaining ones\n * stay ordinary writable columns.\n */\nfunction ownerColumnOf(table: TableDef): string | null {\n for (const [col, builder] of Object.entries(table.columns)) {\n if (builder._def.references?.table === AUTH_USERS_TABLE) return col;\n }\n return null;\n}\n\n/** One FK edge: `child.column` points at the parent table this edge hangs off. */\ntype ChildEdge = { child: string; column: string };\n\n/**\n * Collect the raw parent → children FK edges across the schema.\n *\n * Only edges between tables IN this schema participate — a reference to\n * `auth.users` / `auth.installations` (or any table the project doesn't\n * declare) has no parent bucket and is skipped. Self-FKs are skipped outright.\n *\n * A child that references the same parent through TWO columns is recorded once,\n * on the first column in declaration order: `children` maps a child table to a\n * single FK column, and the second FK stays an ordinary writable column.\n */\nfunction buildChildEdges(schema: SchemaDef): Map<string, ChildEdge[]> {\n const edges = new Map<string, ChildEdge[]>();\n for (const name of Object.keys(schema.tables)) edges.set(name, []);\n\n for (const childName of Object.keys(schema.tables)) {\n const table = schema.tables[childName];\n if (table === undefined) continue;\n for (const [col, builder] of Object.entries(table.columns)) {\n const ref = builder._def.references;\n if (ref === undefined) continue;\n if (ref.table === childName) continue; // self-FK\n const bucket = edges.get(ref.table);\n if (bucket === undefined) continue; // targets a table outside this schema\n if (bucket.some((e) => e.child === childName)) continue; // already linked\n bucket.push({ child: childName, column: col });\n }\n }\n return edges;\n}\n\n/**\n * Drop cycle back-edges from the FK graph.\n *\n * `children` feeds a RECURSIVE type in the seed/fixture DSL\n * (`SeedRow<T>` expands each child's own `children`). A cycle — `lists → todos`\n * plus `todos → lists` through a second FK — would make that type infinite\n * (\"Type instantiation is excessively deep\"). So we walk the graph depth-first\n * in declaration order and drop any edge pointing back at a table currently on\n * the DFS stack. Cross-edges into an already-FINISHED subtree are KEPT: they\n * re-expand a finite subtree, which terminates.\n *\n * Declaration order makes the choice of which edge to drop deterministic (the\n * generated .d.ts is golden-tested).\n */\nfunction pruneCycles(raw: Map<string, ChildEdge[]>): Map<string, ChildEdge[]> {\n const pruned = new Map<string, ChildEdge[]>();\n for (const table of raw.keys()) pruned.set(table, []);\n const state = new Map<string, \"visiting\" | \"done\">();\n\n function visit(table: string): void {\n state.set(table, \"visiting\");\n for (const edge of raw.get(table) ?? []) {\n if (state.get(edge.child) === \"visiting\") continue; // back-edge → drop\n pruned.get(table)?.push(edge);\n if (state.get(edge.child) === undefined) visit(edge.child);\n }\n state.set(table, \"done\");\n }\n\n for (const table of raw.keys()) {\n if (state.get(table) === undefined) visit(table);\n }\n return pruned;\n}\n\n/** Emit the `row` / `insert` / `owner` / `children` blocks for one table at the\n * given base indentation. */\nfunction tableBlock(table: TableDef, children: ChildEdge[], 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 const owner = ownerColumnOf(table);\n const childEntries = children\n .map((e) => `${JSON.stringify(e.child)}: ${JSON.stringify(e.column)}`)\n .join(\"; \");\n return [\n `${indent}${table.name}: {`,\n `${indent} row: {`,\n ...rowLines,\n `${indent} };`,\n `${indent} insert: {`,\n ...insertLines,\n `${indent} };`,\n `${indent} owner: ${owner === null ? \"null\" : JSON.stringify(owner)};`,\n `${indent} children: {${childEntries === \"\" ? \"\" : ` ${childEntries} `}};`,\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 children = pruneCycles(buildChildEdges(schema));\n const blocks = tableNames.map((name) =>\n tableBlock(schema.tables[name]!, children.get(name) ?? [], \" \"),\n );\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 db types\\` / 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","/**\n * storage.ts — the storage-buckets config-as-code DSL.\n *\n * `defineStorage({ buckets })` is the first MODULE config-as-code surface (the\n * sibling of `db/schema.ts`'s `defineSchema`). A `config/storage.ts` file\n * default-exports a `defineStorage(...)` result; on deploy the br-pod evaluates\n * it to JSON and reconciles the declared buckets against the tenant's live\n * buckets via the Storage admin API (create missing, update changed; never\n * auto-delete — dropping a bucket is destructive and warned only).\n *\n * Buckets are DECLARATIVE: name + access + size/mime limits. The FILES inside a\n * bucket are runtime state (uploaded via the SDK), never in git.\n *\n * @example\n * import { defineStorage, bucket } from \"@palbase/backend\";\n *\n * export default defineStorage({\n * buckets: {\n * avatars: bucket({\n * public: true,\n * fileSizeLimit: \"5MB\",\n * allowedMimeTypes: [\"image/png\", \"image/jpeg\", \"image/webp\"],\n * }),\n * invoices: bucket({\n * public: false,\n * fileSizeLimit: \"20MB\",\n * allowedMimeTypes: [\"application/pdf\"],\n * }),\n * },\n * });\n *\n * The returned value is the EXACT JSON shape the runtime's generic config\n * extractor (`config_extract.js`) emits and the Go apply step parses:\n * { __config: \"storage\", buckets: { avatars: { public, fileSizeLimit, allowedMimeTypes }, ... } }\n * `fileSizeLimit` is always normalized to a number of bytes (or null when\n * omitted, meaning \"no limit\"); the apply step maps it to the Storage API's\n * `file_size_limit` field. `allowedMimeTypes` is the allowlist or null (any).\n */\n\n/** The discriminant written under `__config` so the eval/apply can tell which\n * module config a `config/*.ts` file describes. Storage is `\"storage\"`. */\nexport const STORAGE_CONFIG_KIND = \"storage\" as const;\n\n/**\n * The author-facing options for a single bucket.\n *\n * - `public`: when true the bucket is served without a signed URL. Defaults to\n * `false` (private — signed URLs only).\n * - `fileSizeLimit`: the per-object upload cap. Accepts a human string\n * (`\"5MB\"`, `\"20MB\"`, `\"1GB\"`) or a bare number of BYTES. Omit for no limit.\n * - `allowedMimeTypes`: an allowlist of MIME types accepted on upload. Omit to\n * allow any type. Each entry must look like `type/subtype` (e.g. `image/png`,\n * `application/pdf`, or a wildcard `image/*`).\n */\nexport interface BucketOptions {\n public?: boolean;\n fileSizeLimit?: string | number;\n allowedMimeTypes?: string[];\n variants?: Record<string, ImageVariant>;\n}\n\n/**\n * One named rendition of an uploaded image — the same three knobs\n * `getPublicUrl(path, ...)` takes, given a name so the size lives with the\n * bucket instead of being retyped at every call site.\n *\n * At least one of `width` / `height` must be set (a variant that resizes\n * nothing and converts nothing is a typo, not a variant).\n */\nexport interface ImageVariant {\n width?: number;\n height?: number;\n format?: \"webp\" | \"avif\" | \"jpeg\" | \"png\";\n}\n\nconst VARIANT_FORMATS = [\"webp\", \"avif\", \"jpeg\", \"png\"] as const;\n\n/**\n * Validate + normalize a bucket's `variants` map.\n *\n * Renditions are produced ON REQUEST by the image-transform route and cached —\n * declaring one stores nothing extra and costs nothing until it is fetched,\n * which is why adding a size later needs no backfill of objects already\n * uploaded.\n */\nfunction normalizeVariants(\n input: Record<string, ImageVariant>,\n): Record<string, ImageVariant> {\n if (input === null || typeof input !== \"object\" || Array.isArray(input)) {\n throw new Error(\"bucket variants must be an object of { <name>: { width?, height?, format? } }\");\n }\n const out: Record<string, ImageVariant> = {};\n for (const [name, spec] of Object.entries(input)) {\n // The name becomes part of a URL/response key, so keep it boring.\n if (!/^[a-z0-9][a-z0-9_-]*$/i.test(name)) {\n throw new Error(\n `bucket variant name \"${name}\" must be alphanumeric with optional - or _ (e.g. \"thumb\", \"card_2x\")`,\n );\n }\n if (spec === null || typeof spec !== \"object\" || Array.isArray(spec)) {\n throw new Error(`bucket variant \"${name}\" must be an object like { width: 100, height: 100 }`);\n }\n for (const dim of [\"width\", \"height\"] as const) {\n const value = spec[dim];\n if (value === undefined) continue;\n if (typeof value !== \"number\" || !Number.isInteger(value) || value <= 0) {\n throw new Error(`bucket variant \"${name}\" ${dim} must be a positive integer, got ${String(value)}`);\n }\n }\n if (spec.width === undefined && spec.height === undefined) {\n throw new Error(`bucket variant \"${name}\" must set width and/or height`);\n }\n if (spec.format !== undefined && !VARIANT_FORMATS.includes(spec.format)) {\n throw new Error(\n `bucket variant \"${name}\" format must be one of ${VARIANT_FORMATS.join(\", \")}, got \"${String(spec.format)}\"`,\n );\n }\n out[name] = {\n ...(spec.width !== undefined ? { width: spec.width } : {}),\n ...(spec.height !== undefined ? { height: spec.height } : {}),\n ...(spec.format !== undefined ? { format: spec.format } : {}),\n };\n }\n return out;\n}\n\n/**\n * The compiled, serializable bucket definition — the EXACT shape emitted to\n * JSON and consumed by the Go apply step.\n *\n * - `public`: always present (defaulted to `false`).\n * - `fileSizeLimit`: bytes as a number, or `null` for \"no limit\".\n * - `allowedMimeTypes`: the MIME allowlist, or `null` for \"any type\".\n */\nexport interface BucketDef {\n public: boolean;\n fileSizeLimit: number | null;\n allowedMimeTypes: string[] | null;\n /** Named renditions, or `null` when none are declared. Rendered on request by\n * the image-transform route and cached — nothing extra is stored. */\n variants: Record<string, ImageVariant> | null;\n}\n\n/** A storage config definition: the discriminant + a map of bucket name →\n * {@link BucketDef}. This is the value `defineStorage` returns and the runtime\n * config extractor serializes. */\nexport interface StorageConfig {\n __config: typeof STORAGE_CONFIG_KIND;\n buckets: Record<string, BucketDef>;\n}\n\n/** The author-facing input to `defineStorage`: a `buckets` map whose keys are\n * the bucket names and whose values are `bucket({...})` builders. */\nexport interface StorageInput {\n buckets: Record<string, BucketDef>;\n}\n\n// Powers of 1024 (binary, IEC). Storage's `file_size_limit` string parser\n// (the `bytes` npm lib, used by Supabase Storage) treats \"MB\"/\"GB\" as binary\n// multiples, so \"5MB\" = 5 * 1024 * 1024. We match that exactly so the limit a\n// user declares is the limit the bucket enforces.\nconst UNIT_BYTES: Record<string, number> = {\n b: 1,\n kb: 1024,\n mb: 1024 ** 2,\n gb: 1024 ** 3,\n tb: 1024 ** 4,\n};\n\n/**\n * Parse a `fileSizeLimit` into a number of bytes.\n *\n * - A bare number is taken as bytes verbatim (must be a non-negative integer).\n * - A string is `<number><unit>` (e.g. `\"5MB\"`, `\"1.5GB\"`, `\"500kb\"`); the unit\n * is case-insensitive and optional (a bare numeric string = bytes). Binary\n * units (1 MB = 1024 squared bytes) to match the Storage module's parser.\n *\n * Throws on a negative value, a non-finite number, or an unrecognized unit so a\n * bad limit fails at config-author time, not silently at deploy.\n */\nexport function parseFileSizeLimit(input: string | number): number {\n if (typeof input === \"number\") {\n if (!Number.isFinite(input) || input < 0 || !Number.isInteger(input)) {\n throw new Error(\n `bucket fileSizeLimit must be a non-negative integer number of bytes, got ${input}`,\n );\n }\n return input;\n }\n\n const trimmed = input.trim();\n // <number><optional-unit>, e.g. \"5MB\", \"1.5 gb\", \"1024\", \"500kb\".\n const match = /^(\\d+(?:\\.\\d+)?)\\s*([a-zA-Z]+)?$/.exec(trimmed);\n if (!match) {\n throw new Error(\n `bucket fileSizeLimit string must be \"<number><unit>\" like \"5MB\" or \"1GB\", got \"${input}\"`,\n );\n }\n const value = Number.parseFloat(match[1]!);\n const unit = (match[2] ?? \"b\").toLowerCase();\n const multiplier = UNIT_BYTES[unit];\n if (multiplier === undefined) {\n throw new Error(\n `bucket fileSizeLimit has an unknown unit \"${match[2]}\" — use B, KB, MB, GB, or TB (e.g. \"5MB\")`,\n );\n }\n const bytes = value * multiplier;\n if (!Number.isFinite(bytes) || bytes < 0) {\n throw new Error(`bucket fileSizeLimit resolved to an invalid byte count: ${bytes}`);\n }\n // Round to a whole byte — a fractional byte is meaningless to the Storage API.\n return Math.round(bytes);\n}\n\n// A loose MIME-type shape check: `type/subtype`, where each side is a token of\n// alphanumerics plus the usual punctuation, and the subtype may be a wildcard\n// `*`. This is intentionally permissive (not an IANA allowlist) but rejects the\n// obvious typos (\"image\", \"imagepng\", \" \").\nconst MIME_RE = /^[a-zA-Z0-9][a-zA-Z0-9!#$&^_.+-]*\\/(?:\\*|[a-zA-Z0-9][a-zA-Z0-9!#$&^_.+-]*)$/;\n\n/**\n * Define a single bucket. The bucket NAME is supplied by the key in\n * `defineStorage({ buckets: { <name>: bucket({...}) } })`, so `bucket()` takes\n * only the options.\n *\n * Validates eagerly (at config-author time):\n * - `fileSizeLimit` parses to a valid non-negative byte count.\n * - each `allowedMimeTypes` entry is a `type/subtype` MIME string.\n *\n * Returns a normalized {@link BucketDef}: `public` defaulted to `false`,\n * `fileSizeLimit` as bytes-or-null, `allowedMimeTypes` deduped-or-null.\n */\nexport function bucket(opts: BucketOptions = {}): BucketDef {\n const fileSizeLimit =\n opts.fileSizeLimit === undefined ? null : parseFileSizeLimit(opts.fileSizeLimit);\n\n let allowedMimeTypes: string[] | null = null;\n if (opts.allowedMimeTypes !== undefined) {\n if (!Array.isArray(opts.allowedMimeTypes)) {\n throw new Error(\"bucket allowedMimeTypes must be an array of MIME-type strings\");\n }\n for (const mime of opts.allowedMimeTypes) {\n if (typeof mime !== \"string\" || !MIME_RE.test(mime.trim())) {\n throw new Error(\n `bucket allowedMimeTypes entry \"${mime}\" is not a valid MIME type (expected \"type/subtype\", e.g. \"image/png\")`,\n );\n }\n }\n // Dedupe + trim. An empty array means \"explicitly no types\" — keep it as []\n // rather than null so the apply step can distinguish \"any\" (null) from a\n // caller that passed [].\n allowedMimeTypes = [...new Set(opts.allowedMimeTypes.map((m) => m.trim()))];\n }\n\n return {\n public: opts.public ?? false,\n fileSizeLimit,\n allowedMimeTypes,\n variants: opts.variants === undefined ? null : normalizeVariants(opts.variants),\n };\n}\n\n/**\n * Define the storage config for a project. The bucket NAME comes from each\n * object key (authors never repeat the name). Returns the discriminated\n * {@link StorageConfig} the runtime config extractor serializes and the Go\n * apply step reconciles.\n *\n * @example\n * export default defineStorage({\n * buckets: { avatars: bucket({ public: true, fileSizeLimit: \"5MB\" }) },\n * });\n */\nexport function defineStorage(input: StorageInput): StorageConfig {\n if (input === null || typeof input !== \"object\" || typeof input.buckets !== \"object\") {\n throw new Error(\"defineStorage expects { buckets: { <name>: bucket({...}) } }\");\n }\n const buckets: Record<string, BucketDef> = {};\n for (const name of Object.keys(input.buckets)) {\n if (name.length === 0) {\n throw new Error(\"bucket name must be a non-empty string\");\n }\n const def = input.buckets[name];\n if (def === undefined) continue;\n buckets[name] = def;\n }\n return { __config: STORAGE_CONFIG_KIND, buckets };\n}\n","/**\n * egress.ts — the tenant outbound-HTTP allowlist config-as-code DSL.\n *\n * `defineEgress({ hosts, timeoutMs })` declares the external hosts a backend may\n * fetch(), and how long a single call may take. config/egress.ts default-exports\n * it; the deploy evals it to JSON (SchemaExtractor.EvaluateConfigFile →\n * config_extract.js) and bakes both into the artifact manifest → the isolate\n * loader → Tenant.egressAllow / Tenant.egressTimeoutMs. The tenantFetch\n * capability rejects any host NOT on the list. NO config/egress.ts (or an empty\n * list) ⇒ the backend has NO outbound network — fail-closed.\n *\n * @example\n * // config/egress.ts\n * import { defineEgress } from \"@palbase/backend\";\n * export default defineEgress({\n * hosts: [\"api.openai.com\"],\n * timeoutMs: 90_000, // a slow LLM call; default 30_000\n * });\n *\n * Each host is a bare hostname (no scheme/port/path/wildcard). A leading dot,\n * `.example.com`, also covers subdomains (Squid dstdomain semantics). Egress is\n * https-only on :443; the deploy REJECTS a malformed / IP-literal / internal host\n * (fail-closed — a security allowlist is never best-effort).\n *\n * `timeoutMs` is a CEILING, not a grant: the call still ends when the INVOCATION\n * ends. A job may run up to its own `@Job({ timeout })` (max 300s), while a\n * request is additionally bounded by the gateway. Setting 300_000 on a route\n * whose request dies earlier buys nothing — size it to the caller.\n *\n * Response bodies are BUFFERED whole (5 MB cap) before your fetch() resolves, so\n * a streaming/SSE upstream gives you no partial output and no earlier\n * first-byte: the entire stream must complete inside `timeoutMs`.\n *\n * Emits: { __config: \"egress\", hosts: [...], timeoutMs?: number }\n */\n\n/** The discriminant written under `__config` so the deploy eval knows the kind. */\nexport const EGRESS_CONFIG_KIND = \"egress\" as const;\n\n/**\n * Bounds on `timeoutMs`, duplicated (deliberately) in the deploy's\n * ParseEgressConfig. This copy shapes the authoring error; that one is\n * authoritative and fail-closed. They must agree — a value this accepts and the\n * deploy rejects is a broken deploy the author cannot see coming.\n */\nexport const EGRESS_TIMEOUT_MIN_MS = 1_000;\nexport const EGRESS_TIMEOUT_MAX_MS = 300_000;\n/** Applied when `timeoutMs` is omitted. Also spelled in the isolate capability. */\nexport const EGRESS_TIMEOUT_DEFAULT_MS = 30_000;\n\n/** The author-facing input to defineEgress. */\nexport interface EgressInput {\n hosts: string[];\n /**\n * Per-call ceiling for an outbound fetch, in milliseconds.\n * 1_000..300_000; omitted ⇒ 30_000.\n */\n timeoutMs?: number;\n}\n\n/** The evaluated config/egress.ts default export (what the deploy reads). */\nexport interface EgressConfig {\n __config: typeof EGRESS_CONFIG_KIND;\n hosts: string[];\n timeoutMs?: number;\n}\n\n/**\n * Declare the backend's outbound-HTTP allowlist. Client-side this only shapes +\n * validates the list; the authoritative fail-closed validation runs at deploy.\n */\nexport function defineEgress(input: EgressInput): EgressConfig {\n if (input === null || typeof input !== \"object\" || !Array.isArray(input.hosts)) {\n throw new Error(\"defineEgress expects { hosts: string[] }\");\n }\n const hosts: string[] = [];\n for (const h of input.hosts) {\n if (typeof h !== \"string\" || h.trim().length === 0) {\n throw new Error(\"defineEgress: every host must be a non-empty string\");\n }\n hosts.push(h.trim().toLowerCase());\n }\n if (input.timeoutMs === undefined) {\n return { __config: EGRESS_CONFIG_KIND, hosts };\n }\n const timeoutMs = input.timeoutMs;\n if (typeof timeoutMs !== \"number\" || !Number.isInteger(timeoutMs)) {\n throw new Error(\"defineEgress: timeoutMs must be an integer number of milliseconds\");\n }\n if (timeoutMs < EGRESS_TIMEOUT_MIN_MS || timeoutMs > EGRESS_TIMEOUT_MAX_MS) {\n throw new Error(\n `defineEgress: timeoutMs must be between ${EGRESS_TIMEOUT_MIN_MS} and ${EGRESS_TIMEOUT_MAX_MS} (got ${timeoutMs})`,\n );\n }\n return { __config: EGRESS_CONFIG_KIND, hosts, timeoutMs };\n}\n","/**\n * notifications.ts — the notification-providers config-as-code DSL.\n *\n * `defineNotifications({ push, email, sms })` is the second MODULE config-as-code\n * surface (the sibling of `config/storage.ts`'s `defineStorage`). A\n * `config/notifications.ts` file default-exports a `defineNotifications(...)`\n * result; on deploy the br-pod evaluates it to JSON and reconciles the declared\n * providers against the tenant's live providers via the PalNotify admin API\n * (create missing; never auto-delete — dropping a provider is destructive and\n * warned only).\n *\n * SECRETS ARE NEVER IN THE FILE. Each provider's NON-SECRET fields (team id, key\n * id, bundle id, region, host, port, from address, account sid, …) are literals\n * in the config. Each provider's SECRET material (the APNs .p8 key, the FCM\n * service-account JSON, an api_key, an auth token, the SMTP/ACS password, …) is\n * NOT a field here — it is bound BY CONVENTION to a RESERVED encrypted env var\n * and resolved at deploy from control-pg. The env-key convention is:\n *\n * PB_NOTIFICATIONS_<PROVIDER>_<FIELD> (UPPER_SNAKE_CASE)\n *\n * e.g. `PB_NOTIFICATIONS_APNS_P8`, `PB_NOTIFICATIONS_FCM_SERVICE_ACCOUNT`,\n * `PB_NOTIFICATIONS_TWILIO_AUTH_TOKEN`. The `PB_` namespace is reserved (the CLI\n * refuses a hand-set `palbase secret set PB_*`); the CLI's `palbase notifications\n * add <provider>` derives the key and uploads the secret for you, so an author\n * never types either the secret or the env-key name into git.\n *\n * @example\n * import { defineNotifications } from \"@palbase/backend\";\n *\n * export default defineNotifications({\n * push: {\n * apns: { enabled: true, teamId: \"ABCDE12345\", keyId: \"KEY1234567\", bundleId: \"com.acme.app\" },\n * fcm: { enabled: true },\n * },\n * email: {\n * sendgrid: { enabled: true, fromDomain: \"mail.acme.com\" },\n * },\n * sms: {\n * twilio: { enabled: true, accountSid: \"ACxxxxxxxx\", messagingServiceSid: \"MGxxxxxxxx\" },\n * },\n * });\n *\n * The returned value is the EXACT JSON shape the runtime's generic config\n * extractor (`config_extract.js`) emits and the Go apply step parses:\n * { __config: \"notifications\", push: {...}, email: {...}, sms: {...} }\n * Only ENABLED providers carry their non-secret fields; a disabled (or absent)\n * provider serializes as `{ enabled: false }` so the apply step skips it.\n */\n\n/** The `__config` discriminant the eval/apply reads to confirm a config/*.ts is\n * a notifications config. Notifications is `\"notifications\"`. */\nexport const NOTIFICATIONS_CONFIG_KIND = \"notifications\" as const;\n\n/** The reserved env-var prefix that backs provider secrets. A `palbase secret\n * set` of a key under this prefix is REFUSED by the CLI (it is managed by\n * `palbase notifications add`). Both the CLI and the br-pod apply step derive a\n * provider's secret env key as `${RESERVED_SECRET_PREFIX}_<PROVIDER>_<FIELD>`. */\nexport const RESERVED_SECRET_PREFIX = \"PB_NOTIFICATIONS\" as const;\n\n// ────────────────────────────────────────────────────────────────────────────\n// Provider catalog — the SINGLE SOURCE of which providers exist + their fields.\n//\n// Ported from platform/studio/src/server/trpc/routers/notifications.ts (the\n// per-provider credential zod schemas). Here the fields are split into:\n// • nonSecret: literals that live in config/notifications.ts (this file).\n// • secret: the field name(s) bound to a reserved env var (NOT in config).\n// The Go apply step + the CLI both mirror this catalog, so adding a provider is\n// a three-line change kept in lockstep across the SDK / runtime / CLI.\n// ────────────────────────────────────────────────────────────────────────────\n\n/** One provider's catalog entry: which non-secret fields are required, which are\n * optional, and which secret field-name(s) bind to reserved env vars. */\nexport interface ProviderCatalogEntry {\n /** The channel this provider serves (`push` | `email` | `sms`). */\n readonly channel: \"push\" | \"email\" | \"sms\";\n /** Non-secret config fields the author MUST supply (validated eagerly). */\n readonly required: readonly string[];\n /** Non-secret config fields the author MAY supply. */\n readonly optional: readonly string[];\n /** Secret field name(s) — each backed by `PB_NOTIFICATIONS_<PROVIDER>_<FIELD>`\n * (FIELD is the UPPER_SNAKE of the name here). NOT a config field. */\n readonly secrets: readonly string[];\n}\n\n/**\n * The provider catalog: provider key → fields. The non-secret field names are\n * the camelCase keys an author writes in `config/notifications.ts`; the secret\n * names are the snake-ish tokens that become the reserved env-var suffix.\n *\n * apns: team_id / key_id / bundle_id (+ optional is_production); secret = p8.\n * fcm: no non-secret fields; secret = service_account (the full JSON).\n * sendgrid: from_domain; secret = api_key.\n * ses: region / from_domain / access_key_id; secret = secret_access_key.\n * smtp: host / port / from_email (+ optional username, use_starttls); secret = password.\n * acs: from_email (+ optional from_name); secret = connection_string.\n * twilio: account_sid + (from_number OR messaging_service_sid); secret = auth_token.\n */\nexport const PROVIDER_CATALOG = {\n apns: {\n channel: \"push\",\n required: [\"teamId\", \"keyId\", \"bundleId\"],\n optional: [\"isProduction\"],\n secrets: [\"p8\"],\n },\n fcm: {\n channel: \"push\",\n required: [],\n optional: [],\n secrets: [\"serviceAccount\"],\n },\n sendgrid: {\n channel: \"email\",\n required: [\"fromDomain\"],\n optional: [],\n secrets: [\"apiKey\"],\n },\n ses: {\n channel: \"email\",\n required: [\"region\", \"accessKeyId\", \"fromDomain\"],\n optional: [],\n secrets: [\"secretAccessKey\"],\n },\n smtp: {\n channel: \"email\",\n required: [\"host\", \"port\", \"fromEmail\"],\n optional: [\"username\", \"useStarttls\"],\n secrets: [\"password\"],\n },\n acs: {\n channel: \"email\",\n required: [\"fromEmail\"],\n optional: [\"fromName\"],\n secrets: [\"connectionString\"],\n },\n twilio: {\n channel: \"sms\",\n // account_sid required; one of from_number / messaging_service_sid required\n // (enforced by the refine in buildProvider, not by the flat `required` list).\n required: [\"accountSid\"],\n optional: [\"fromNumber\", \"messagingServiceSid\"],\n secrets: [\"authToken\"],\n },\n} as const satisfies Record<string, ProviderCatalogEntry>;\n\n/** A provider key (`\"apns\" | \"fcm\" | \"sendgrid\" | …`). */\nexport type ProviderName = keyof typeof PROVIDER_CATALOG;\n\n// ── author-facing per-provider option types (non-secret fields only) ─────────\n\n/** APNs (Apple Push) — non-secret fields. The `.p8` key is the reserved secret\n * `PB_NOTIFICATIONS_APNS_P8` (uploaded via `palbase notifications add apns`). */\nexport interface ApnsOptions {\n enabled?: boolean;\n teamId: string;\n keyId: string;\n bundleId: string;\n /** APNs production gateway vs sandbox. Defaults to true (production). */\n isProduction?: boolean;\n}\n\n/** FCM (Firebase Cloud Messaging) — no non-secret fields; the service-account\n * JSON is the reserved secret `PB_NOTIFICATIONS_FCM_SERVICE_ACCOUNT`. */\nexport interface FcmOptions {\n enabled?: boolean;\n}\n\n/** SendGrid email — non-secret `fromDomain`; api_key is the reserved secret. */\nexport interface SendgridOptions {\n enabled?: boolean;\n fromDomain: string;\n}\n\n/** Amazon SES email — secret_access_key is the reserved secret. */\nexport interface SesOptions {\n enabled?: boolean;\n region: string;\n accessKeyId: string;\n fromDomain: string;\n}\n\n/** SMTP email — password is the reserved secret. */\nexport interface SmtpOptions {\n enabled?: boolean;\n host: string;\n port: number;\n fromEmail: string;\n username?: string;\n useStarttls?: boolean;\n}\n\n/** Azure Communication Services email — connection_string is the reserved secret. */\nexport interface AcsOptions {\n enabled?: boolean;\n fromEmail: string;\n fromName?: string;\n}\n\n/** Twilio SMS — auth_token is the reserved secret. Exactly one of `fromNumber`\n * or `messagingServiceSid` must be supplied. */\nexport interface TwilioOptions {\n enabled?: boolean;\n accountSid: string;\n fromNumber?: string;\n messagingServiceSid?: string;\n}\n\n/** The union of every provider's author-facing options. `buildProvider` accepts\n * this so each provider's typed options pass without a cast. */\nexport type ProviderOptions =\n | ApnsOptions\n | FcmOptions\n | SendgridOptions\n | SesOptions\n | SmtpOptions\n | AcsOptions\n | TwilioOptions;\n\n// ── templates ───────────────────────────────────────────────────────────────\n//\n// Templates are the OTHER half of config-as-code notifications. A provider says\n// *how* mail leaves; a template says *what* it says. Before this existed the\n// only way to create one was a live API call or a click in Studio — so the thing\n// your code sends by slug lived outside your repo, outside review, and outside\n// the deploy that depends on it. `Notifications.email.send({ templateSlug })`\n// would 404 on a fresh environment until somebody remembered to re-create it by\n// hand.\n\n/** The default locale a template row lands on when the author names none. Must\n * match PalNotify's `model.DefaultLocale`. */\nexport const DEFAULT_TEMPLATE_LOCALE = \"en\" as const;\n\n/** One locale's email content. */\nexport interface EmailTemplateContent {\n /** Subject line. Handlebars placeholders (`{{name}}`) are rendered at send. */\n subject: string;\n /** HTML body. */\n html: string;\n /** Plain-text body. Omit and the server derives one from `html` at render. */\n text?: string;\n /**\n * Variables the sender MUST supply. Omit and they are DERIVED from the\n * `{{placeholders}}` in this locale's content — see {@link extractVariables}.\n * Supply explicitly to make a placeholder optional (leave it out of the list)\n * or to require something a conditional references.\n */\n variables?: readonly string[];\n}\n\n/** An email template: base content, plus optional per-locale overrides. */\nexport interface EmailTemplateOptions extends EmailTemplateContent {\n /** Locale of the base content. Defaults to `\"en\"`. */\n locale?: string;\n /** Additional locales, keyed by BCP47 short tag (`tr`, `de`, …). */\n locales?: Record<string, EmailTemplateContent>;\n}\n\n/** One locale's SMS content. */\nexport interface SmsTemplateContent {\n /** Message body. Handlebars placeholders are rendered at send. */\n body: string;\n /** Variables the sender must supply. Derived from `body` when omitted. */\n variables?: readonly string[];\n}\n\n/** An SMS template: base content, plus optional per-locale overrides. */\nexport interface SmsTemplateOptions extends SmsTemplateContent {\n /** Locale of the base content. Defaults to `\"en\"`. */\n locale?: string;\n /** Additional locales, keyed by BCP47 short tag. */\n locales?: Record<string, SmsTemplateContent>;\n}\n\n/** Author-facing templates block: slug → template. */\nexport interface TemplatesInput {\n email?: Record<string, EmailTemplateOptions>;\n sms?: Record<string, SmsTemplateOptions>;\n}\n\n/** A compiled email-template row — one (slug, locale) pair, in the snake_case\n * wire shape PalNotify's templates API takes. */\nexport interface EmailTemplateDef {\n slug: string;\n locale: string;\n subject: string;\n html_body: string;\n text_body?: string;\n variables: string[];\n}\n\n/** A compiled SMS-template row — one (slug, locale) pair. */\nexport interface SmsTemplateDef {\n slug: string;\n locale: string;\n body: string;\n variables: string[];\n}\n\n/** The compiled templates block: flat, per-channel row lists. Flat rows (rather\n * than a nested locale map) are what the apply step iterates — one row is one\n * upsert against the (slug, locale) unique key. */\nexport interface TemplatesConfig {\n email: EmailTemplateDef[];\n sms: SmsTemplateDef[];\n}\n\n/**\n * Pull the variable names out of Handlebars content.\n *\n * Only PLAIN mustaches count: `{{name}}` and `{{{name}}}`. Deliberately skipped:\n * - block/section/partial/comment tokens (`{{#if}}`, `{{/if}}`, `{{else}}`,\n * `{{> partial}}`, `{{! comment}}`) — structure, not data the sender passes;\n * - helper calls (`{{formatDate at}}`) — the first token is a helper name;\n * - `this` and `@index`-style frame references.\n *\n * A dotted path contributes its ROOT (`{{user.name}}` → `user`), because that is\n * what the sender actually has to hand over.\n *\n * The list is what the server ENFORCES as required at render time, so keeping it\n * to the unambiguous cases is the point: an over-eager derivation would turn an\n * optional conditional into a mandatory argument and 400 real sends.\n */\nexport function extractVariables(...sources: (string | undefined)[]): string[] {\n const found = new Set<string>();\n for (const src of sources) {\n if (!src) continue;\n for (const match of src.matchAll(/\\{\\{\\{?\\s*([^{}]+?)\\s*\\}?\\}\\}/g)) {\n const token = (match[1] ?? \"\").trim();\n if (token === \"\" || \"#/^!>&\".includes(token.charAt(0)) || token === \"else\") continue;\n if (/\\s/.test(token)) continue; // helper invocation\n const root = token.split(\".\")[0] ?? \"\";\n if (root === \"\" || root === \"this\" || root.startsWith(\"@\")) continue;\n found.add(root);\n }\n }\n return [...found].sort();\n}\n\n/** Compile one email template into its per-locale rows. */\nfunction buildEmailTemplate(slug: string, opts: EmailTemplateOptions): EmailTemplateDef[] {\n const row = (locale: string, c: EmailTemplateContent): EmailTemplateDef => {\n if (!c.subject) throw new Error(`notifications: email template \"${slug}\" (${locale}) needs a subject`);\n if (!c.html) throw new Error(`notifications: email template \"${slug}\" (${locale}) needs an html body`);\n const def: EmailTemplateDef = {\n slug,\n locale,\n subject: c.subject,\n html_body: c.html,\n variables: c.variables ? [...c.variables] : extractVariables(c.subject, c.html, c.text),\n };\n if (c.text !== undefined) def.text_body = c.text;\n return def;\n };\n\n const rows = [row(opts.locale ?? DEFAULT_TEMPLATE_LOCALE, opts)];\n for (const [locale, content] of Object.entries(opts.locales ?? {})) {\n rows.push(row(locale, content));\n }\n return rows;\n}\n\n/** Compile one SMS template into its per-locale rows. */\nfunction buildSmsTemplate(slug: string, opts: SmsTemplateOptions): SmsTemplateDef[] {\n const row = (locale: string, c: SmsTemplateContent): SmsTemplateDef => {\n if (!c.body) throw new Error(`notifications: sms template \"${slug}\" (${locale}) needs a body`);\n return {\n slug,\n locale,\n body: c.body,\n variables: c.variables ? [...c.variables] : extractVariables(c.body),\n };\n };\n\n const rows = [row(opts.locale ?? DEFAULT_TEMPLATE_LOCALE, opts)];\n for (const [locale, content] of Object.entries(opts.locales ?? {})) {\n rows.push(row(locale, content));\n }\n return rows;\n}\n\n/** Compile the whole templates block, rejecting a duplicated (slug, locale). */\nfunction buildTemplates(input: TemplatesInput): TemplatesConfig {\n const out: TemplatesConfig = { email: [], sms: [] };\n const seen = new Set<string>();\n const claim = (channel: string, slug: string, locale: string) => {\n const key = `${channel}/${slug}/${locale}`;\n if (seen.has(key)) {\n throw new Error(`notifications: ${channel} template \"${slug}\" declares locale \"${locale}\" twice`);\n }\n seen.add(key);\n };\n\n for (const [slug, opts] of Object.entries(input.email ?? {})) {\n for (const row of buildEmailTemplate(slug, opts)) {\n claim(\"email\", row.slug, row.locale);\n out.email.push(row);\n }\n }\n for (const [slug, opts] of Object.entries(input.sms ?? {})) {\n for (const row of buildSmsTemplate(slug, opts)) {\n claim(\"sms\", row.slug, row.locale);\n out.sms.push(row);\n }\n }\n return out;\n}\n\n/** The author-facing input to `defineNotifications`. Every provider + every\n * channel is optional — declare only what you use. */\nexport interface NotificationsInput {\n push?: {\n apns?: ApnsOptions;\n fcm?: FcmOptions;\n };\n email?: {\n sendgrid?: SendgridOptions;\n ses?: SesOptions;\n smtp?: SmtpOptions;\n acs?: AcsOptions;\n };\n sms?: {\n twilio?: TwilioOptions;\n };\n /** Email + SMS templates, keyed by slug. Applied on every deploy. */\n templates?: TemplatesInput;\n}\n\n// ── compiled (serializable) provider defs — the EXACT JSON the apply parses ──\n\n/** A compiled provider def. `enabled` is always present; the remaining keys are\n * the provider's non-secret fields (verbatim from the catalog). A disabled\n * provider is `{ enabled: false }` with no other fields. */\nexport type ProviderDef = { enabled: boolean } & Record<string, unknown>;\n\n/** The compiled notifications config — the discriminant + per-channel maps of\n * provider name → {@link ProviderDef}. This is what `defineNotifications`\n * returns and the runtime extractor serializes. */\nexport interface NotificationsConfig {\n __config: typeof NOTIFICATIONS_CONFIG_KIND;\n push: Record<string, ProviderDef>;\n email: Record<string, ProviderDef>;\n sms: Record<string, ProviderDef>;\n templates: TemplatesConfig;\n}\n\n// ── validation + compilation ────────────────────────────────────────────────\n\n/**\n * Compile + validate one provider's author options into a {@link ProviderDef}.\n *\n * - A provider with `enabled === false` (or omitted) compiles to `{ enabled:\n * false }` and its required fields are NOT enforced (you can declare a disabled\n * provider as a placeholder without filling it in).\n * - An ENABLED provider must supply every `required` non-secret field from the\n * catalog; a missing one throws at config-author time (not silently at deploy).\n * - Only the catalog's non-secret fields (required + optional) are copied into\n * the def — an unknown extra key is ignored (it would have no effect on the\n * live provider). Secrets are never read here.\n */\nexport function buildProvider(name: ProviderName, opts: ProviderOptions): ProviderDef {\n const entry = PROVIDER_CATALOG[name];\n // A fresh, index-signature-bearing copy so catalog-driven field reads are\n // typed without a cast (the author-facing option interfaces are closed).\n const src: Record<string, unknown> = { ...opts };\n const enabled = src.enabled === undefined ? false : Boolean(src.enabled);\n if (!enabled) {\n return { enabled: false };\n }\n\n const def: ProviderDef = { enabled: true };\n\n for (const field of entry.required) {\n const value = src[field];\n if (value === undefined || value === null || value === \"\") {\n throw new Error(\n `notifications: provider \"${name}\" is enabled but missing required field \"${field}\"`,\n );\n }\n def[field] = value;\n }\n for (const field of entry.optional) {\n if (src[field] !== undefined) {\n def[field] = src[field];\n }\n }\n\n // Twilio: exactly one of fromNumber / messagingServiceSid is required (mirrors\n // the studio router's refine + the module's ValidateTwilioConfig).\n if (name === \"twilio\") {\n const hasFrom = Boolean(def.fromNumber);\n const hasMsg = Boolean(def.messagingServiceSid);\n if (!hasFrom && !hasMsg) {\n throw new Error(\n 'notifications: provider \"twilio\" requires one of \"fromNumber\" or \"messagingServiceSid\"',\n );\n }\n }\n\n return def;\n}\n\n/**\n * Define the notification-provider config for a project. Returns the\n * discriminated {@link NotificationsConfig} the runtime config extractor\n * serializes and the Go apply step reconciles. Validates eagerly: an enabled\n * provider missing a required non-secret field throws here (config-author time),\n * not at deploy.\n *\n * @example\n * export default defineNotifications({\n * push: { apns: { enabled: true, teamId: \"T\", keyId: \"K\", bundleId: \"com.x\" } },\n * });\n */\nexport function defineNotifications(input: NotificationsInput): NotificationsConfig {\n if (input === null || typeof input !== \"object\") {\n throw new Error(\"defineNotifications expects { push?, email?, sms? }\");\n }\n\n const config: NotificationsConfig = {\n __config: NOTIFICATIONS_CONFIG_KIND,\n push: {},\n email: {},\n sms: {},\n templates: buildTemplates(input.templates ?? {}),\n };\n\n const push = input.push ?? {};\n if (push.apns !== undefined) config.push.apns = buildProvider(\"apns\", push.apns);\n if (push.fcm !== undefined) config.push.fcm = buildProvider(\"fcm\", push.fcm);\n\n const email = input.email ?? {};\n if (email.sendgrid !== undefined) config.email.sendgrid = buildProvider(\"sendgrid\", email.sendgrid);\n if (email.ses !== undefined) config.email.ses = buildProvider(\"ses\", email.ses);\n if (email.smtp !== undefined) config.email.smtp = buildProvider(\"smtp\", email.smtp);\n if (email.acs !== undefined) config.email.acs = buildProvider(\"acs\", email.acs);\n\n const sms = input.sms ?? {};\n if (sms.twilio !== undefined) config.sms.twilio = buildProvider(\"twilio\", sms.twilio);\n\n return config;\n}\n\n/**\n * Derive the RESERVED env-var key that backs a provider's secret field, e.g.\n * `reservedSecretKey(\"apns\", \"p8\")` → `\"PB_NOTIFICATIONS_APNS_P8\"`. The CLI uses\n * this to upload the secret and the br-pod apply step uses the same derivation\n * to resolve it — they never hand-type the key, so they cannot drift.\n */\nexport function reservedSecretKey(provider: ProviderName, secretField: string): string {\n return `${RESERVED_SECRET_PREFIX}_${camelToUpperSnake(provider)}_${camelToUpperSnake(secretField)}`;\n}\n\n/** camelCase → UPPER_SNAKE_CASE (`serviceAccount` → `SERVICE_ACCOUNT`). */\nfunction camelToUpperSnake(s: string): string {\n return s.replace(/([a-z0-9])([A-Z])/g, \"$1_$2\").toUpperCase();\n}\n","/**\n * test-users.ts — the test-user fixtures config-as-code DSL.\n *\n * `defineTestUsers({ users })` is a MODULE config-as-code surface (a sibling of\n * `config/storage.ts`'s `defineStorage` and `config/flags.ts`'s `defineFlags`).\n * A `config/test-users.ts` file default-exports a `defineTestUsers(...)` result;\n * on deploy the runtime evaluates it to JSON and hands it to Studio, which owns\n * the single apply engine (mint + seed). Studio, the CLI and the deploy all go\n * through that one engine — there is no second interpreter of this JSON.\n *\n * TWO SHAPES, ONE DSL:\n *\n * - `email` GIVEN → a FIXTURE. Deploy materializes it create-if-missing, so\n * the app can always be signed into with the same credentials. Deliberately\n * NOT applied to a production Environment (the password lives in git).\n * - `email` OMITTED → a TEMPLATE. Deploy creates nothing; Studio and the CLI\n * mint as many fresh instances from it as you want (random credentials).\n *\n * Every minted user is an `is_test` user: excluded from MAU/billing, carrying\n * `test: true` in its token, and refused by the Test Data write path if it ever\n * turns out not to be one.\n *\n * @example\n * import { defineTestUsers, testUser } from \"@palbase/backend\";\n *\n * export default defineTestUsers({\n * users: {\n * demo: testUser({\n * email: \"demo@test.local\",\n * password: \"demo-password-1234\",\n * seed: {\n * profiles: [{ display_name: \"Demo\", tier: \"pro\" }],\n * lists: [\n * { title: \"Groceries\", todos: [{ title: \"Milk\" }, { title: \"Eggs\", done: true }] },\n * ],\n * },\n * }),\n * heavy_user: testUser({ seed: { lists: [{ title: \"L\", todos: [{ title: \"t\" }] }] } }),\n * },\n * });\n *\n * The returned value is the EXACT JSON shape the runtime's generic config\n * extractor emits and the apply engine consumes:\n * { __config: \"test-users\", users: { <name>: { email, password, seed } } }\n * `email` / `password` are the string or `null`; `seed` is `{}` when omitted.\n */\n\nimport type { TableTypes, Tables } from \"../db/env.js\";\n\n/** The `__config` discriminant the eval/apply reads to confirm a config/*.ts is\n * a test-users config. */\nexport const TEST_USERS_CONFIG_KIND = \"test-users\" as const;\n\n// ── Types derived from db/schema.ts ──────────────────────────────────────────\n//\n// `palbase-env.d.ts` (generated by makeEnvDts on every `palbase db types` and\n// on deploy) augments the `Tables` interface with, per table:\n// `row`, `insert`, `owner` (the auth.users FK column, or null) and `children`\n// (tables that FK this one, mapped to their FK column). Those last two are what\n// let the seed shape below be fully derived — the author never writes an owner\n// or a foreign key, because the apply engine fills both.\n\n/**\n * A table graph in the shape the env `Tables` interface carries. The\n * derivations below are parameterized over it (rather than reading the global\n * `Tables` directly) so they can be type-tested against a fixture graph without\n * augmenting the global interface — augmentation is program-wide and would leak\n * into every other type test.\n *\n * The `Record<keyof G, …>` constraint is deliberate: a plain\n * `Record<string, TableTypes>` would reject the `Tables` INTERFACE, which has\n * no index signature.\n */\nexport type TableGraph = Record<string, TableTypes>;\n\n/** The user-rooted tables of `G` — the ones a test user owns rows in directly. */\nexport type OwnedTablesOf<G extends Record<keyof G, TableTypes>> = {\n [T in keyof G]: G[T][\"owner\"] extends string ? T : never;\n}[keyof G];\n\n/**\n * One authored seed row for table `T` of graph `G`.\n *\n * Starts from the table's INSERT shape and removes the two columns the engine\n * owns: the owner column (set to the minted user) and `Via` — the FK column\n * this row hangs off its parent by, when the row is nested under one. What\n * remains is extended with the table's children, each an optional array of\n * their own seed rows.\n *\n * Recursion terminates because `makeEnvDts` drops self-FKs and cycle\n * back-edges when it emits `children`.\n *\n * Name collision note: if a table has a COLUMN whose name equals a CHILD\n * table's name, the intersection makes that key unusable (its type collapses).\n * That is a schema-naming problem the author sees at compile time; the apply\n * engine resolves the same ambiguity live in favour of the column, because it\n * introspects the real table.\n */\nexport type SeedRowFor<\n G extends Record<keyof G, TableTypes>,\n T extends keyof G,\n Via extends string = never,\n> = Omit<G[T][\"insert\"], (G[T][\"owner\"] & string) | Via> & {\n [C in keyof G[T][\"children\"]]?: Array<\n SeedRowFor<G, C & keyof G, G[T][\"children\"][C] & string>\n >;\n};\n\n/** The typed seed over graph `G`: top-level keys are user-rooted tables only;\n * everything else is reached by nesting under its parent. */\nexport type SeedFor<G extends Record<keyof G, TableTypes>> = {\n [T in OwnedTablesOf<G>]?: Array<SeedRowFor<G, T>>;\n};\n\n/** The serialized seed — what travels as JSON and what the engine receives. */\nexport type SeedJson = Record<string, Array<Record<string, unknown>>>;\n\n/**\n * The author-facing seed type. Falls back to the loose shape when `Tables` is\n * still empty (no `db/schema.ts`, or `palbase-env.d.ts` not generated yet) so\n * an unseeded project gets a usable DSL instead of an inscrutable `{}` error.\n */\nexport type Seed = [keyof Tables] extends [never] ? SeedJson : SeedFor<Tables>;\n\n// ── Author-facing options / compiled defs ────────────────────────────────────\n\n/**\n * The options for one declared test user.\n *\n * - `email` / `password`: supply BOTH to make this a fixture with stable\n * credentials (deploy materializes it, the app signs in with them), or\n * NEITHER to make it a template the server generates credentials for.\n * - `seed`: the user's data tree, derived from `db/schema.ts`. Top-level keys\n * are user-rooted tables; FK children nest inside their parent's rows.\n */\nexport interface TestUserOptions {\n email?: string;\n password?: string;\n /**\n * A verified phone for this fixture, E.164 (`+905551112233`). Requires\n * {@link TestUserOptions.otp}: nothing can receive an SMS at a fabricated\n * number, so a phone fixture without a knowable code is one no test could\n * ever sign in as.\n */\n phone?: string;\n /**\n * The fixed code this fixture's phone accepts. Honoured ONLY for the\n * `is_test` user it belongs to — the real rail is untouched, and no\n * verification is ever sent (or billed) for a fixture.\n */\n otp?: string;\n seed?: Seed;\n}\n\n/** The compiled, serializable test-user definition — the EXACT shape emitted to\n * JSON and consumed by the apply engine. */\nexport interface TestUserDef {\n /** Fixed login e-mail (fixture), or `null` when the server should generate one. */\n email: string | null;\n /** Fixed password (fixture), or `null` when the server should generate one. */\n password: string | null;\n /** Verified phone in E.164, or `null` for an e-mail-only fixture. */\n phone: string | null;\n /** The code that phone accepts, or `null` when there is no phone. */\n otp: string | null;\n /** The user's data tree; `{}` when nothing is seeded. */\n seed: SeedJson;\n}\n\n/** A test-users config: the discriminant + the declared users by name. */\nexport interface TestUsersConfig {\n __config: typeof TEST_USERS_CONFIG_KIND;\n users: Record<string, TestUserDef>;\n}\n\n/** The author-facing input to `defineTestUsers`. */\nexport interface TestUsersInput {\n users: Record<string, TestUserDef>;\n}\n\n// Template names ride into control-pg as the scenario name and into the CLI as\n// `--template <name>`; keep them to the same key vocabulary flags use.\nconst TEST_USER_NAME_RE = /^[a-zA-Z][a-zA-Z0-9_]*$/;\n\n// Deliberately permissive: the real address validation is palauth's. This only\n// catches the obvious typo at config-author time.\nconst EMAIL_RE = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/;\n\n// E.164: a leading + and 1..15 digits, first digit non-zero. Same shape palauth\n// validates with; this only catches the obvious authoring typo early.\nconst E164_RE = /^\\+[1-9]\\d{1,14}$/;\n\n// The fixed code is what a test types, so it must match what the UI accepts:\n// palauth mints 6-digit OTPs and the phone screens are 6-box.\nconst OTP_LENGTH = 6;\nconst OTP_RE = /^\\d{6}$/;\n\n/**\n * Minimum fixture password length.\n *\n * NOT palauth's 15-character single-factor floor: an `is_test` user is a\n * disposable harness identity excluded from MAU, and palauth applies neither\n * the length policy nor the HIBP check to the credentials it mints for one. We\n * still refuse an empty or one-character password so a typo can't produce a\n * fixture nobody can reason about.\n */\nconst MIN_PASSWORD_LENGTH = 8;\n\n/** True for a plain `{...}` object (not null, not an array). */\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\n/**\n * Structurally validate a seed and return its serializable form.\n *\n * Deliberately SHALLOW on meaning: we check that the seed is\n * `{ <table>: [ {...}, ... ] }` with non-empty arrays of plain objects, and\n * stop there. Whether a key inside a row is a COLUMN or a CHILD TABLE is\n * resolved by the apply engine against the LIVE schema — it introspects the\n * real table, so it is the only side that can tell them apart (and a jsonb\n * column may legitimately hold an array, which a deeper structural rule here\n * would misread as a nested child).\n */\nfunction normalizeSeed(seed: unknown, userName: string): SeedJson {\n if (seed === undefined) return {};\n if (!isPlainObject(seed)) {\n throw new Error(`testUser ${JSON.stringify(userName)}: seed must be { <table>: [ {...} ] }`);\n }\n const out: SeedJson = {};\n for (const [table, rows] of Object.entries(seed)) {\n if (!Array.isArray(rows)) {\n throw new Error(\n `testUser ${JSON.stringify(userName)}: seed.${table} must be an array of rows`,\n );\n }\n if (rows.length === 0) {\n throw new Error(\n `testUser ${JSON.stringify(userName)}: seed.${table} is empty — remove it or add a row`,\n );\n }\n for (const row of rows) {\n if (!isPlainObject(row)) {\n throw new Error(\n `testUser ${JSON.stringify(userName)}: every row in seed.${table} must be an object`,\n );\n }\n }\n out[table] = rows as Array<Record<string, unknown>>;\n }\n return out;\n}\n\n/**\n * Define a single test user. The NAME is supplied by the object key in\n * `defineTestUsers({ users: { <name>: testUser({...}) } })`, so `testUser()`\n * takes only the options.\n *\n * Validates eagerly (at config-author time):\n * - `email` and `password` are supplied together or not at all — half a\n * credential pair would silently degrade a fixture into a template.\n * - `email` looks like an address; `password` is at least\n * {@link MIN_PASSWORD_LENGTH} characters.\n * - `seed` is structurally `{ <table>: [ {...}, ... ] }` with non-empty arrays.\n *\n * The user NAME is validated by `defineTestUsers`, which is where it is known.\n */\nexport function testUser(opts: TestUserOptions = {}): TestUserDef {\n if (!isPlainObject(opts)) {\n throw new Error(\"testUser() expects { email?, password?, phone?, otp?, seed? }\");\n }\n const hasEmail = opts.email !== undefined;\n const hasPassword = opts.password !== undefined;\n if (hasEmail !== hasPassword) {\n throw new Error(\n \"testUser() needs email AND password together (a fixture with stable credentials) or neither (a template the server generates credentials for)\",\n );\n }\n\n let email: string | null = null;\n let password: string | null = null;\n if (hasEmail) {\n if (typeof opts.email !== \"string\" || !EMAIL_RE.test(opts.email)) {\n throw new Error(`testUser email ${JSON.stringify(opts.email)} is not a valid address`);\n }\n if (typeof opts.password !== \"string\" || opts.password.length < MIN_PASSWORD_LENGTH) {\n throw new Error(\n `testUser password must be at least ${MIN_PASSWORD_LENGTH} characters (got ${\n typeof opts.password === \"string\" ? opts.password.length : 0\n })`,\n );\n }\n email = opts.email;\n password = opts.password;\n }\n\n // A phone needs its code and vice versa. Refused here, at authoring time,\n // rather than at deploy: a phone fixture with no knowable code provisions\n // fine and then fails as a test hanging on an SMS that can never arrive.\n const hasPhone = opts.phone !== undefined;\n const hasOTP = opts.otp !== undefined;\n if (hasPhone !== hasOTP) {\n throw new Error(\n \"testUser() needs phone AND otp together — nothing can receive an SMS at a fabricated number, so a phone fixture without its fixed code can never be signed in as\",\n );\n }\n\n let phone: string | null = null;\n let otp: string | null = null;\n if (hasPhone) {\n if (typeof opts.phone !== \"string\" || !E164_RE.test(opts.phone)) {\n throw new Error(\n `testUser phone ${JSON.stringify(opts.phone)} must be E.164, e.g. \"+905551112233\"`,\n );\n }\n if (typeof opts.otp !== \"string\" || !OTP_RE.test(opts.otp)) {\n throw new Error(\n `testUser otp ${JSON.stringify(opts.otp)} must be ${OTP_LENGTH} digits`,\n );\n }\n phone = opts.phone;\n otp = opts.otp;\n }\n\n // The user name is not known here (it is the object key in defineTestUsers),\n // so seed errors are labelled with the e-mail when there is one.\n return { email, password, phone, otp, seed: normalizeSeed(opts.seed, email ?? \"<template>\") };\n}\n\n/**\n * Define a project's test users. The user NAME comes from each object key\n * (authors never repeat it). Returns the discriminated {@link TestUsersConfig}\n * the runtime config extractor serializes and the apply engine consumes.\n *\n * Validates eagerly:\n * - each name matches `^[a-zA-Z][a-zA-Z0-9_]*$` (the CLI's `--template <name>`\n * and control-pg's scenario name share this vocabulary).\n * - no two fixtures declare the SAME e-mail — they would race to\n * create-if-missing the one account and the second would silently adopt the\n * first one's data tree.\n *\n * @example\n * export default defineTestUsers({\n * users: { demo: testUser({ email: \"demo@test.local\", password: \"demo-password-1234\" }) },\n * });\n */\nexport function defineTestUsers(input: TestUsersInput): TestUsersConfig {\n if (!isPlainObject(input) || !isPlainObject(input.users)) {\n throw new Error(\"defineTestUsers expects { users: { <name>: testUser({...}) } }\");\n }\n const users: Record<string, TestUserDef> = {};\n const emails = new Map<string, string>();\n for (const name of Object.keys(input.users)) {\n if (!TEST_USER_NAME_RE.test(name)) {\n throw new Error(\n `test user name ${JSON.stringify(name)} is invalid — must start with a letter and contain only letters, digits, and underscores`,\n );\n }\n const def = input.users[name];\n if (def === undefined) continue;\n if (def.email !== null) {\n const lower = def.email.toLowerCase();\n const already = emails.get(lower);\n if (already !== undefined) {\n throw new Error(\n `test users ${JSON.stringify(already)} and ${JSON.stringify(name)} declare the same e-mail ${JSON.stringify(def.email)}`,\n );\n }\n emails.set(lower, name);\n }\n users[name] = def;\n }\n return { __config: TEST_USERS_CONFIG_KIND, users };\n}\n","/**\n * flags.ts — the feature-flag-definitions config-as-code DSL.\n *\n * `defineFlags({ flags })` is the third MODULE config-as-code surface (a sibling\n * of `config/storage.ts`'s `defineStorage` and `config/notifications.ts`'s\n * `defineNotifications`). A `config/flags.ts` file default-exports a\n * `defineFlags(...)` result; on deploy the br-pod evaluates it to JSON and\n * UPSERTS the declared flag DEFINITIONS into PalFlags (the user-flags module's\n * system-flags admin API) — create-or-update, idempotent. A live flag NOT in\n * config is NEVER auto-deleted (an orphan flag is harmless; upsert-only).\n *\n * Flags are DECLARATIVE: a flag is a typed project-wide DEFAULT (its key, type,\n * default value, an optional description, and — for string flags — an optional\n * list of allowed `variants`). The VALUE of a flag for a specific USER (a\n * per-user override / A-B assignment) is runtime state set via the SDK, NEVER in\n * git. `variants` here is part of the DEFINITION (the allowed values a string\n * flag may take), not a per-user assignment.\n *\n * NO SECRETS. Unlike notifications, a flag carries no credentials — this is the\n * simplest module config (pure declarative data).\n *\n * @example\n * import { defineFlags, flag } from \"@palbase/backend\";\n *\n * export default defineFlags({\n * flags: {\n * new_dashboard: flag({ type: \"boolean\", default: false, description: \"Roll out the new dashboard\" }),\n * max_uploads: flag({ type: \"number\", default: 10 }),\n * theme: flag({ type: \"string\", default: \"light\", variants: [\"light\", \"dark\", \"system\"] }),\n * limits: flag({ type: \"json\", default: { daily: 10, burst: 50 } }),\n * },\n * });\n *\n * The returned value is the EXACT JSON shape the runtime's generic config\n * extractor (`config_extract.js`) emits and the Go apply step parses:\n * { __config: \"flags\", flags: { <key>: { type, default, variants, description }, ... } }\n * `variants` is the allowed-values list for a string flag, or `null` (any\n * string). `description` is the doc string, or `null`. The apply step maps the\n * author-facing `type` to PalFlags' `value_type`: \"boolean\" → \"bool\" and\n * \"json\" → \"object\"; \"number\"/\"string\" pass through.\n */\n\n/** The `__config` discriminant the eval/apply reads to confirm a config/*.ts is\n * a flags config. Flags is `\"flags\"`. */\nexport const FLAGS_CONFIG_KIND = \"flags\" as const;\n\n/**\n * A flag's type. The author-facing vocabulary is `\"boolean\" | \"number\" |\n * \"string\" | \"json\"`; the apply step maps it to PalFlags' `value_type` enum —\n * `\"boolean\"` → `\"bool\"`, `\"json\"` → `\"object\"`, the other two pass through. The\n * SDK keeps the JS-natural names so the DSL reads cleanly.\n *\n * `\"json\"` is a structured (object) flag. It is named for what an author types —\n * a JSON object literal — and matches the `--type json` the CLI's per-user\n * override commands already use for this same server type.\n */\nexport type FlagType = \"boolean\" | \"number\" | \"string\" | \"json\";\n\n/** Any value expressible in JSON — what may appear INSIDE a `\"json\"` flag's default. */\nexport type FlagJsonValue = boolean | number | string | null | FlagJsonValue[] | { [key: string]: FlagJsonValue };\n\n/**\n * The default of a `\"json\"` flag: a JSON OBJECT. Not an array and not a scalar —\n * PalFlags' `object` value type accepts a JSON object at the top level only\n * (`validate.ValidateValueTypeMatch`), and it caps nesting depth at 3.\n */\nexport type FlagJsonObject = { [key: string]: FlagJsonValue };\n\n/** The runtime JSON value a flag's `default` may hold (matches {@link FlagType}). */\nexport type FlagValue = boolean | number | string | FlagJsonObject;\n\n/**\n * The author-facing options for a single flag — a UNION keyed on `type`, so\n * `default` is checked against the declared type at compile time and `variants`\n * is only accepted where it means something.\n *\n * - `type`: the flag's type — `\"boolean\" | \"number\" | \"string\" | \"json\"`.\n * - `default`: the project-wide default value. MUST match `type` (a `number`\n * default with `type: \"boolean\"` is a type error, and throws at runtime).\n * - `variants`: ONLY valid for `type: \"string\"` — the allowed values the string\n * flag may take (a DEFINITION, not a per-user assignment). When given, the\n * `default` MUST be one of the variants. Supplying `variants` on any other\n * type is a type error, and throws at runtime. (PalFlags rejects variants for\n * every non-string `value_type`, so accepting them here would only produce a\n * config the server refuses.)\n * - `description`: an optional human description of what the flag controls.\n */\nexport type FlagOptions =\n | {\n type: \"boolean\";\n default: boolean;\n variants?: never;\n conditions?: FlagCondition<boolean>[];\n description?: string;\n }\n | {\n type: \"number\";\n default: number;\n variants?: never;\n conditions?: FlagCondition<number>[];\n description?: string;\n }\n | {\n type: \"string\";\n default: string;\n variants?: string[];\n conditions?: FlagCondition<string>[];\n description?: string;\n }\n | {\n type: \"json\";\n default: FlagJsonObject;\n variants?: never;\n conditions?: FlagCondition<FlagJsonObject>[];\n description?: string;\n };\n\n/**\n * One targeting branch: the value this flag resolves to when `when` matches the\n * caller's client context. Branch ORDER is priority — the first match wins, and\n * a flag with no matching branch falls back to its `default`.\n *\n * `when` is a small expression over what the client declares about itself:\n *\n * ```\n * client.platform == 'ios' && client.app_version >= '2.0.0'\n * client.locale startsWith 'tr'\n * client.platform in ['ios', 'android']\n * ```\n *\n * Those are CLAIMS, not proof — the server treats them as attacker-controlled.\n * They select WHICH value a caller sees, never WHETHER they may see it, so a\n * condition must not be the thing standing between a user and something paid.\n */\n/**\n * The variables the server exposes. Mirrors `declaredVars` in\n * `modules/user-flags/internal/conditions/conditions.go`; the server rejects\n * anything it does not know, so the worst a stale copy here does is offer too\n * little.\n *\n * `client.*` is what the SDK reports about the caller. `percentile` and\n * `server.now` are DERIVED server-side and cannot be moved by a lying client,\n * which is what makes a rollout or a time window mean anything.\n */\ntype StringVar = \"client.platform\" | \"client.locale\";\ntype SemverVar = \"client.app_version\" | \"client.os_version\";\n\ntype EqualityOp = \"==\" | \"!=\";\n/** Ordering only where order exists — a platform string has none. */\ntype OrderedOp = EqualityOp | \"<\" | \"<=\" | \">\" | \">=\";\ntype TextOp = EqualityOp | \"startsWith\" | \"endsWith\" | \"contains\";\n\n/** A single-quoted literal. Quoting is the mistake people make most. */\ntype Quoted = `'${string}'`;\n\ntype Comparison =\n | `${StringVar} ${TextOp} ${Quoted}`\n | `${StringVar} in [${string}]`\n | `${SemverVar} ${OrderedOp} ${Quoted}`\n // Bare number: quoting it would make the server compare a string and the\n // rule would silently never match.\n | `percentile ${OrderedOp} ${number}`\n | `server.now ${OrderedOp} ${Quoted}`;\n\n/**\n * One expression: a comparison, optionally chained with `&&` / `||`, or a\n * parenthesised group.\n *\n * ONE level, and the limit is TypeScript's, not a preference. Unrolling a second\n * level produced `TS2590: union type too complex`, and the failure mode there is\n * the worst possible one: the checker gives up and the type silently degrades to\n * `string`, so NOTHING is checked while the code still compiles. Measured, not\n * assumed — the two-level version accepted `client.app_verison` without\n * complaint.\n *\n * So the FIRST term is fully checked and the rest of a chain is not. That is\n * where the mistakes are: a rule is usually one comparison, and a typo in the\n * first one is the common case. A typo after an `&&` still reaches the server,\n * which parses the real grammar and rejects it.\n *\n * A group's contents go unchecked for the same reason.\n */\nexport type FlagConditionExpression =\n | Comparison\n | `${Comparison} && ${string}`\n | `${Comparison} || ${string}`\n | `(${string})`;\n\nexport interface FlagCondition<V> {\n when: FlagConditionExpression;\n value: V;\n}\n\n/**\n * The COMPILED shape of a condition — the JSON actually emitted and parsed by\n * the Go apply step.\n *\n * `when` widens back to `string` here on purpose. The narrow type is an\n * authoring aid; once the expression has been trimmed and serialised it is just\n * text on the wire, and keeping the template-literal type would force a cast on\n * every string operation without checking anything the author had not already\n * been checked on.\n */\nexport interface CompiledFlagCondition<V> {\n when: string;\n value: V;\n}\n\n/**\n * The compiled, serializable flag definition — the EXACT shape emitted to JSON\n * and consumed by the Go apply step.\n *\n * - `type`: the author-facing type verbatim (`\"boolean\" | \"number\" | \"string\" |\n * \"json\"`) — the apply step maps it to PalFlags' `value_type`.\n * - `default`: the default value (matches `type`).\n * - `variants`: the allowed-values list for a string flag, or `null` (any).\n * - `description`: the doc string, or `null`.\n */\nexport interface FlagDef {\n type: FlagType;\n default: FlagValue;\n variants: string[] | null;\n /** Ordered targeting branches, or `null` when the flag is unconditional. */\n conditions: CompiledFlagCondition<FlagValue>[] | null;\n description: string | null;\n}\n\n/** A flags config definition: the discriminant + a map of flag key →\n * {@link FlagDef}. This is the value `defineFlags` returns and the runtime\n * config extractor serializes. */\nexport interface FlagsConfig {\n __config: typeof FLAGS_CONFIG_KIND;\n flags: Record<string, FlagDef>;\n}\n\n/** The author-facing input to `defineFlags`: a `flags` map whose keys are the\n * flag keys and whose values are `flag({...})` builders. */\nexport interface FlagsInput {\n flags: Record<string, FlagDef>;\n}\n\n// Flag keys mirror PalFlags' system-flag key rule (validate.keyNameRe): a\n// letter, then letters / digits / underscores. We validate eagerly so a key the\n// CLI/SDK accepts is a key PalFlags accepts (the apply step never has to reject).\nconst FLAG_KEY_RE = /^[a-zA-Z][a-zA-Z0-9_]*$/;\n\n/** Reports whether `value` matches the declared {@link FlagType}. */\nfunction valueMatchesType(type: FlagType, value: FlagValue): boolean {\n switch (type) {\n case \"boolean\":\n return typeof value === \"boolean\";\n case \"number\":\n // A finite number only — NaN / Infinity are not serializable as JSON.\n return typeof value === \"number\" && Number.isFinite(value);\n case \"string\":\n return typeof value === \"string\";\n case \"json\":\n // A plain JSON OBJECT — not null, not an array. PalFlags' `object` value\n // type decodes to map[string]any and rejects anything else, so an array or\n // a bare scalar default must fail here rather than at deploy time.\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n }\n}\n\n/**\n * Define a single flag. The flag KEY is supplied by the object key in\n * `defineFlags({ flags: { <key>: flag({...}) } })`, so `flag()` takes only the\n * options.\n *\n * Validates eagerly (at config-author time):\n * - `type` is one of `\"boolean\" | \"number\" | \"string\" | \"json\"`.\n * - `default` matches `type` (e.g. a `number` default with `type: \"boolean\"`\n * throws; a `\"json\"` default must be a plain object, not an array or scalar).\n * - `variants` is ONLY allowed for a string flag (variants on any other type\n * throws); each entry is a non-empty string; the `default` must be one of the\n * variants.\n *\n * Returns a normalized {@link FlagDef}: `variants` deduped-or-null,\n * `description` trimmed-or-null.\n */\nexport function flag(opts: FlagOptions): FlagDef {\n if (opts === null || typeof opts !== \"object\") {\n throw new Error(\"flag() expects { type, default, variants?, description? }\");\n }\n const { type } = opts;\n if (type !== \"boolean\" && type !== \"number\" && type !== \"string\" && type !== \"json\") {\n throw new Error(`flag type must be \"boolean\", \"number\", \"string\", or \"json\", got ${JSON.stringify(type)}`);\n }\n if (!valueMatchesType(type, opts.default)) {\n throw new Error(\n `flag default ${JSON.stringify(opts.default)} does not match type \"${type}\"`,\n );\n }\n\n let variants: string[] | null = null;\n if (opts.variants !== undefined) {\n if (opts.type !== \"string\") {\n throw new Error(`flag variants are only valid for type \"string\" (got type \"${type}\")`);\n }\n if (!Array.isArray(opts.variants)) {\n throw new Error(\"flag variants must be an array of strings\");\n }\n for (const v of opts.variants) {\n if (typeof v !== \"string\" || v.length === 0) {\n throw new Error(`flag variant ${JSON.stringify(v)} must be a non-empty string`);\n }\n }\n // Dedupe while preserving first-seen order. An empty array is meaningless\n // (no value would be allowed) — reject it rather than silently widening.\n variants = [...new Set(opts.variants)];\n if (variants.length === 0) {\n throw new Error(\"flag variants must be a non-empty list when supplied\");\n }\n // `opts` narrowed to the string member above, so `default` is a string.\n if (!variants.includes(opts.default)) {\n throw new Error(\n `flag default ${JSON.stringify(opts.default)} is not one of its variants [${variants\n .map((v) => JSON.stringify(v))\n .join(\", \")}]`,\n );\n }\n }\n\n let conditions: CompiledFlagCondition<FlagValue>[] | null = null;\n if (opts.conditions !== undefined) {\n if (!Array.isArray(opts.conditions)) {\n throw new Error(\"flag conditions must be an array of { when, value }\");\n }\n const compiled: CompiledFlagCondition<FlagValue>[] = [];\n for (const [i, branch] of opts.conditions.entries()) {\n if (branch === null || typeof branch !== \"object\") {\n throw new Error(`flag condition ${i} must be an object { when, value }`);\n }\n if (typeof branch.when !== \"string\" || branch.when.trim().length === 0) {\n throw new Error(`flag condition ${i} needs a non-empty \"when\" expression`);\n }\n // Every branch has to satisfy exactly what the default satisfies: a flag\n // must not be able to resolve, through any door, to a value it would have\n // rejected as its own default.\n if (!valueMatchesType(type, branch.value as FlagValue)) {\n throw new Error(\n `flag condition ${i} value ${JSON.stringify(branch.value)} does not match type \"${type}\"`,\n );\n }\n if (variants !== null && !variants.includes(branch.value as string)) {\n throw new Error(\n `flag condition ${i} value ${JSON.stringify(branch.value)} is not one of its variants [${variants\n .map((v) => JSON.stringify(v))\n .join(\", \")}]`,\n );\n }\n compiled.push({ when: branch.when.trim(), value: branch.value as FlagValue });\n }\n conditions = compiled.length > 0 ? compiled : null;\n }\n\n let description: string | null = null;\n if (opts.description !== undefined) {\n if (typeof opts.description !== \"string\") {\n throw new Error(\"flag description must be a string\");\n }\n const trimmed = opts.description.trim();\n description = trimmed.length > 0 ? trimmed : null;\n }\n\n return {\n type,\n default: opts.default,\n variants,\n conditions,\n description,\n };\n}\n\n/**\n * Define the feature-flag definitions for a project. The flag KEY comes from\n * each object key (authors never repeat the key). Returns the discriminated\n * {@link FlagsConfig} the runtime config extractor serializes and the Go apply\n * step UPSERTS into PalFlags.\n *\n * @example\n * export default defineFlags({\n * flags: { dark_mode: flag({ type: \"boolean\", default: false }) },\n * });\n */\nexport function defineFlags(input: FlagsInput): FlagsConfig {\n if (input === null || typeof input !== \"object\" || typeof input.flags !== \"object\") {\n throw new Error(\"defineFlags expects { flags: { <key>: flag({...}) } }\");\n }\n const flags: Record<string, FlagDef> = {};\n for (const key of Object.keys(input.flags)) {\n if (!FLAG_KEY_RE.test(key)) {\n throw new Error(\n `flag key ${JSON.stringify(key)} is invalid — must start with a letter and contain only letters, digits, and underscores`,\n );\n }\n const def = input.flags[key];\n if (def === undefined) continue;\n flags[key] = def;\n }\n return { __config: FLAGS_CONFIG_KIND, flags };\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 { UploadConfig } from \"./upload.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\" | \"QUERY\";\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 /** Direct-storage upload config — present ONLY on `@Upload` routes (the\n * `@Get`/`@Post`/… decorators never set it). Its presence is what MARKS a\n * route as an upload route through the whole pipeline (registry → flatten →\n * openapi → codegen). The bytes go client→storage directly; the method body\n * runs as the completion handler. See {@link UploadConfig} (decorators/upload.ts). */\n uploadConfig?: UploadConfig;\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 // `@UploadedObject()` — injects the uploaded object (completion input) on an\n // `@Upload` route. No schema (the shape is the fixed UploadedObject type).\n | \"uploadedObject\";\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 inferred throw site: the error CLASS name (e.g. \"TodoLocked\") and its\n * wire code (e.g. \"todo_locked\"). `status`, `hasData`, and the data JSON schema\n * are NOT carried here — they resolve from the error registry by `code` at\n * extract/openapi time (single source of truth). */\nexport interface ThrowDescriptor {\n name: string;\n code: 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 /** Error classes this route can throw, if inferred. Derived from the method\n * body + service call graph by the deploy stager's throw analysis and written\n * here via `recordThrows` (a generated top-level IIFE injected per controller,\n * the `recordReturn` twin), not by an author-written decorator. */\n throws?: ThrowDescriptor[];\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/** Symbol the per-method buffered throw descriptors are stored under while a\n * class's registry is being populated. The stager-injected `recordThrows` 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 `recordThrows`\n * writes through if the route already exists). Buffering on BOTH sides means a\n * fully-formed route entry always carries its throw descriptors — a raw-symbol\n * reader (the runtime) never has to re-merge. */\nconst THROWS_BUFFER: unique symbol = Symbol.for(\"palbase.backend.throwsBuffer\");\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 [THROWS_BUFFER]?: Record<string, ThrowDescriptor[]>;\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 // Same drain for buffered throw descriptors (the recordThrows-ran-first\n // ordering) — the route entry is complete the moment it's created.\n const throwsBuffer = carrier[THROWS_BUFFER];\n if (throwsBuffer && throwsBuffer[fnName] !== undefined) {\n route.throws = throwsBuffer[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/** Attach the inferred throw descriptors to the route for `fnName` (called by\n * the stager-injected IIFE that carries the throw analysis result — the\n * `recordReturn` twin). If the route does not exist yet, the descriptors are\n * buffered (THROWS_BUFFER) and drained into the route by `recordRoute` when the\n * method decorator runs. */\nexport function recordThrows(target: object, fnName: string, throws: ThrowDescriptor[]): 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.throws = throws;\n return;\n }\n if (!Object.prototype.hasOwnProperty.call(carrier, THROWS_BUFFER)) {\n carrier[THROWS_BUFFER] = {};\n }\n const throwsBuffer = carrier[THROWS_BUFFER];\n if (throwsBuffer) throwsBuffer[fnName] = throws;\n}\n\n/** Read the route metadata for a controller class (the deploy/dispatch entry\n * point). Applies any buffered return schemas + throw descriptors (for the\n * recordReturn/recordThrows-runs-before orderings) and returns a defensive copy\n * 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 const throwsBuffer = carrier[THROWS_BUFFER];\n if (throwsBuffer) {\n for (const route of routes) {\n const buffered = throwsBuffer[route.fnName];\n if (buffered && route.throws === undefined) {\n route.throws = buffered;\n }\n }\n }\n return routes.map((r) => ({\n ...r,\n params: r.params.slice(),\n ...(r.throws !== undefined ? { throws: r.throws.slice() } : {}),\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\";\nimport { getRoutes } from \"./registry.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/** The one path segment the platform owns. The isolate matches\n * `^/webhooks/([^/]+)$` on the raw request path BEFORE controller dispatch, so\n * anything a controller resolves to under it answers `404 webhook_not_found`\n * and never runs. */\nconst RESERVED_FIRST_SEGMENT = \"webhooks\";\n\n/**\n * Throw if `path` resolves under the reserved segment. Segments are compared the\n * way the isolate compares them — `split(\"/\").filter(Boolean)` — NOT by string\n * prefix, because empty segments collapse there: `@Controller(\"/\")` +\n * `@Post(\"/webhooks/x\")` composes to `//webhooks/x`, which the isolate serves as\n * `/webhooks/x`. A prefix check reads that as safe; the segment check does not.\n * `/webhooksy` stays allowed for the same reason — it is a different segment.\n *\n * Every verb is refused, not just the POST the isolate currently intercepts: the\n * reservation is of the URL namespace, so a `@Get(\"/webhooks/x\")` that happens\n * to work today would be silently shadowed the moment the isolate's method gate\n * widens. Refusing at build is recoverable; discovering it as a 404 is not.\n */\nfunction assertNotReserved(path: string, subject: string): void {\n const [first] = path.split(\"/\").filter(Boolean);\n if (first === RESERVED_FIRST_SEGMENT) {\n throw new Error(\n `${subject} resolves under the reserved /${RESERVED_FIRST_SEGMENT} path — ` +\n \"inbound webhooks are served there and would shadow this route\",\n );\n }\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(\\@QueryParams(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 // /webhooks/* belongs to the platform: the isolate matches the inbound\n // webhook route before controller dispatch, so a controller mounted here\n // would never receive a request. Silent shadowing is the failure mode this\n // whole change exists to remove, so refuse it at build.\n //\n // The COMPOSED path is what gets shadowed, not the base path. `@Controller(\"\")`\n // and `@Controller(\"/\")` both pass a base-path-only check while a\n // `@Post(\"/webhooks/stripe\")` inside them resolves to exactly the path the\n // isolate intercepts. Method decorators run BEFORE the class decorator (TS\n // evaluates members first), so every route this class declares is already in\n // the registry here — which is why the composed check can live at this one\n // seam instead of on the dispatch read path. The `@Controller(\"\") +\n // @Post(\"/webhooks/stripe\")` test is the lock on that ordering: if it ever\n // stopped holding, that test goes red.\n assertNotReserved(basePath, `@Controller(\"${basePath}\")`);\n for (const route of getRoutes(ctor)) {\n assertNotReserved(\n `${basePath}${route.subpath}`,\n `@${route.method}(\"${route.subpath}\") in @Controller(\"${basePath}\")`,\n );\n }\n\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","// Method decorators: `@Get` / `@Post` / `@Put` / `@Patch` / `@Delete` /\n// `@Query` declare a 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` — and it is PUBLIC API, not authoring sugar: the runtime\n * derives the operationId as `<controllerName>.<fnName>` (the dotted namespace\n * the SDKs expose as `pb.todos.list()`), so renaming this method renames every\n * client call. The flat verb+path id is only the fallback for routes with no\n * controller metadata. See openapi/discover.ts. */\nfunction makeMethodDecorator(method: HttpMethodUpper) {\n return function (subpath: string, options: RouteOptions = {}): MethodDecorator {\n // Runtime guard for stale pre-9.0.0 code: `@Query(zodSchema)` used to be\n // the query-string PARAM decorator. Applied against this SDK it would\n // silently record a garbage route (schema-as-subpath) and fail the deploy\n // with a baffling self-conflict — fail loud and name the migration instead.\n if (typeof subpath !== \"string\") {\n throw new Error(\n `@${method[0]}${method.slice(1).toLowerCase()}(subpath) expects a string subpath, got ${typeof subpath}.` +\n (method === \"QUERY\"\n ? \" If this is a zod schema on a method parameter: the query-string param decorator was renamed @QueryParams(schema) in @palbase/backend 9.0.0.\"\n : \"\"),\n );\n }\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/** `@Query(subpath, options?)` — declare an HTTP QUERY route (RFC 10008):\n * safe + idempotent like GET, body-carrying like POST. Input rides `@Body`. */\nexport const Query = makeMethodDecorator(\"QUERY\");\n","// `@Upload` — the single-method direct-storage upload decorator, and its\n// `@UploadedObject` parameter companion + `UploadConfig`/`UploadedObject` types.\n//\n// Unlike `@Get`/`@Post`/… (where bytes flow THROUGH the br-pod), an `@Upload`\n// route never sees the file bytes: the client uploads DIRECTLY to storage via a\n// signed URL the br-pod mints in an authorize pre-flight. The decorated method\n// body is the COMPLETION handler — it runs once, after storage confirms the\n// object landed (via an HMAC-signed completion webhook), and returns the typed\n// result the client awaits. There is exactly one method: it is BOTH the\n// authorize gate (its uploadConfig drives the guard + signed-URL pinning) AND\n// the completion handler (its body).\n//\n// On the wire the authorize pre-flight is a POST; what marks a route as an\n// upload route through the whole pipeline (registry → flatten → openapi →\n// codegen) is the PRESENCE of `uploadConfig` on the route — never a special HTTP\n// verb. The `@Get`/`@Post`/… decorators never set it.\nimport { recordRoute, recordParam } from \"./registry.js\";\nimport type { RouteOptions } from \"./registry.js\";\nimport type { StorageConfig } from \"../config/storage.js\";\n\n/** A legacy method decorator (`experimentalDecorators`): `(prototype, name,\n * descriptor)`. */\ntype MethodDecorator = (\n target: object,\n propertyKey: string | symbol,\n descriptor: PropertyDescriptor,\n) => void;\n\n/** A legacy parameter decorator: `(prototype, name, paramIndex)`. */\ntype ParameterDecorator = (\n target: object,\n propertyKey: string | symbol,\n parameterIndex: number,\n) => void;\n\n/**\n * Direct-storage upload settings for an `@Upload` route. The br-pod validates an\n * authorize request against these (size/type), then mints a signed upload URL\n * that PINS the limits so storage itself rejects an over-limit / wrong-type PUT\n * — the client cannot exceed what it declared.\n */\nexport interface UploadConfig {\n /**\n * Target bucket NAME. MUST exist in `config/storage.ts` `defineStorage(...)`.\n *\n * The bucket is the SINGLE SOURCE OF TRUTH for the size limit + MIME allowlist:\n * `bucket({ fileSizeLimit, allowedMimeTypes })`. Storage enforces those at the\n * actual PUT (the only guard a client cannot skip), so `@Upload` deliberately\n * does NOT take its own `maxSize`/`allowedTypes` — duplicating them here would\n * let a route declare a tighter limit than its bucket that storage would not\n * enforce (a real bypass: declare 10 bytes at authorize, then PUT up to the\n * bucket ceiling straight at the signed URL). One bucket, one limit, enforced.\n */\n bucket: string;\n /**\n * SERVER-side object key template. The client NEVER chooses the path. Tokens:\n * `{userId}` (authenticated user id), `{uploadId}` (server-minted), and\n * `{filename}` (the client-declared filename, sanitized). e.g.\n * `\"{userId}/{uploadId}-{filename}\"`.\n */\n pathTemplate: string;\n}\n\n/**\n * The uploaded object, injected into an `@Upload` method body by\n * `@UploadedObject()` once storage confirms the upload. Bytes are NOT present\n * (they went straight to storage) — this is the metadata the completion handler\n * persists.\n */\nexport interface UploadedObject {\n /** Server-minted id correlating authorize ↔ completion (idempotency key). */\n uploadId: string;\n /** Final object key in the bucket (rendered from `pathTemplate`). */\n path: string;\n /** Bucket the object landed in. */\n bucket: string;\n /** Object size in bytes, as reported by storage. */\n size: number;\n /** Object MIME type, as reported by storage. */\n contentType: string;\n}\n\n/**\n * `@Upload(subpath, config)` — declare a direct-storage upload route. The method\n * body is the completion handler; `config.uploadConfig` drives the authorize\n * guard + signed-URL pinning.\n *\n * @example\n * @Upload(\"/\", { bucket: \"docs\", pathTemplate: \"{userId}/{uploadId}-{filename}\" })\n * async upload(@UploadedObject() obj: UploadedObject, @User() user): Promise<DocResult> { ... }\n * // The size limit + MIME allowlist come from the \"docs\" bucket in\n * // config/storage.ts — storage enforces them at the PUT.\n */\nexport function Upload(\n subpath: string,\n config: UploadConfig & Pick<RouteOptions, \"auth\" | \"rateLimit\">,\n): MethodDecorator {\n const { auth, rateLimit, ...uploadConfig } = config;\n validateUploadConfigShape(uploadConfig);\n const options: RouteOptions = {\n uploadConfig,\n ...(auth !== undefined ? { auth } : {}),\n ...(rateLimit !== undefined ? { rateLimit } : {}),\n };\n return function (target, propertyKey) {\n // On the wire the authorize pre-flight is a POST; `uploadConfig` is what\n // marks this as an upload route downstream.\n recordRoute(target, String(propertyKey), \"POST\", subpath, options);\n };\n}\n\n/**\n * `@UploadedObject()` — inject the uploaded object (`: UploadedObject`) into an\n * `@Upload` method body (the completion input). Only valid on an `@Upload`\n * route; the bytes are NOT present (they went directly to storage), this is the\n * confirmed object's metadata.\n *\n * Co-located with the {@link UploadedObject} TYPE so a single exported name\n * `UploadedObject` carries BOTH the decorator value and the type annotation.\n */\nexport function UploadedObject(): ParameterDecorator {\n return function (target, propertyKey, parameterIndex) {\n recordParam(target, String(propertyKey), {\n index: parameterIndex,\n kind: \"uploadedObject\",\n });\n };\n}\n\n/**\n * Shape-validate an UploadConfig at decoration time (author-time failure beats a\n * silent deploy bug). Does NOT cross-check against the storage config — that is\n * `validateUploadAgainstStorage`, run at flatten/deploy time when the storage\n * config is available.\n */\nexport function validateUploadConfigShape(c: UploadConfig): void {\n if (c === null || typeof c !== \"object\") {\n throw new Error(\"@Upload config must be an object { bucket, pathTemplate, ... }\");\n }\n if (typeof c.bucket !== \"string\" || c.bucket.length === 0) {\n throw new Error(\"@Upload config.bucket must be a non-empty bucket name\");\n }\n if (typeof c.pathTemplate !== \"string\" || c.pathTemplate.length === 0) {\n throw new Error(\"@Upload config.pathTemplate must be a non-empty key template\");\n }\n}\n\n/**\n * Cross-check one `@Upload` route's uploadConfig against the project's\n * {@link StorageConfig}: the named bucket MUST exist in `defineStorage(...)`.\n * Throws a precise error so a typo fails at deploy, not at the first user upload.\n *\n * That is the ONLY cross-check: the size limit + MIME allowlist live on the\n * bucket (`bucket({ fileSizeLimit, allowedMimeTypes })`) and are enforced by\n * storage at the PUT. `@Upload` carries no `maxSize`/`allowedTypes` of its own,\n * so there is nothing to compare — one bucket, one limit, no drift.\n *\n * `routeLabel` is used only for error messages (e.g. `docs.upload`).\n */\nexport function validateUploadAgainstStorage(\n uploadConfig: UploadConfig,\n storage: StorageConfig,\n routeLabel: string,\n): void {\n const def = storage.buckets[uploadConfig.bucket];\n if (def === undefined) {\n const known = Object.keys(storage.buckets);\n throw new Error(\n `@Upload route ${routeLabel} targets bucket \"${uploadConfig.bucket}\" which is not declared in defineStorage(...). ` +\n (known.length ? `Known buckets: ${known.join(\", \")}.` : \"No buckets are declared.\"),\n );\n }\n}\n","// Parameter decorators: `@Body` / `@QueryParams` / `@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/** `@QueryParams(schema)` — inject the parsed query params, validated against\n * `schema`. */\nexport function QueryParams(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\n// NOTE: `@UploadedObject()` lives in decorators/upload.ts (co-located with the\n// `UploadedObject` TYPE) so a single exported name carries both the value (the\n// decorator) and the type — TS can only merge value+type under one export name\n// when both are declared in the SAME module.\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 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","// defineError — project-defined typed error classes + the module-global error\n// registry the OpenAPI spec twins join against.\n//\n// `defineError(code, status, dataSchema?)` returns an `HttpError` subclass whose\n// constructor is typed by the zod schema (`new TodoLocked({ retryAfter: 30 })`).\n// Each call self-registers `{ code, status, className, dataSchema }` in a\n// registry anchored on `globalThis` under `Symbol.for(...)` — mirroring the\n// ROUTES pattern — so the deploy bundle's registrations land on the single SDK\n// instance the extractor `require()`s. The registry is pre-seeded with the named\n// built-in classes (`NotFound`, `Conflict`, …) so throw inference can resolve\n// ad-hoc `throw new NotFound(...)` sites by their canonical wire codes.\n//\n// Duplicate code with a DIFFERENT shape (status OR converted data schema) is a\n// hard error at registration time (deploy fails loudly — error codes are\n// project-unique); structurally-identical re-registration is idempotent (each\n// controller BUNDLE carries its own copy of a shared models/errors.ts, so the\n// same defineError line legitimately runs once per bundle in one process).\nimport {\n OpenAPIRegistry,\n OpenApiGeneratorV31,\n extendZodWithOpenApi,\n} from \"@asteasolutions/zod-to-openapi\";\nimport { z, type ZodTypeAny } from \"zod\";\nimport { HttpError } from \"./errors.js\";\n\nextendZodWithOpenApi(z);\n\n/** One registered error: the wire code, HTTP status, the class name the\n * analyzer sees, the optional data payload schema, and whether it is one of the\n * pre-seeded built-in named classes. */\nexport interface RegisteredError {\n code: string;\n status: number;\n className: string;\n dataSchema?: ZodTypeAny;\n /** JSON.stringify of the converted JSON schema — equal digest ⇔ the spec\n * twins would emit an identical `data` schema for this error. */\n dataDigest?: string;\n builtin: boolean;\n}\n\n/** The cross-module-instance registry anchor (the pinned contract symbol). */\nconst ERROR_REGISTRY: unique symbol = Symbol.for(\"palbase.backend.errorRegistry\");\n\ninterface RegistryCarrier {\n [ERROR_REGISTRY]?: Map<string, RegisteredError>;\n}\n\n/** Get (creating + pre-seeding if absent) the project-global error registry,\n * keyed by wire code. Anchored on `globalThis` so every copy of the SDK in a\n * process shares the one registry. */\n/** The fixed data schemas the built-in named errors ship. Declared HERE (not in\n * errors.ts, which stays zod-free) because this is where the registry converts\n * them to JSON-schema for the spec — keying codegen's typed `error.data`. Only\n * the errors that semantically carry a payload have a schema; the rest are\n * data-less. `.int()` is preserved so the wire/codegen sees an integer. */\nconst BUILTIN_DATA_SCHEMAS: Record<string, ZodTypeAny> = {\n bad_request: z.object({\n fields: z.array(z.object({ field: z.string(), message: z.string() })),\n }),\n too_many_requests: z.object({ retryAfter: z.number().int() }),\n // Purchases (@RequireEntitlement / @Spend). Their payloads are what make a\n // paywall renderable on the client: WHICH entitlement was missing, and for a\n // spend the real ceiling and reset time rather than a guessed retry delay.\n entitlement_required: z.object({ entitlement: z.string().nullable() }),\n quota_exceeded: z.object({\n key: z.string(),\n scope: z.string(),\n window: z.string(),\n used: z.number().int(),\n reserved: z.number().int(),\n max: z.number().int(),\n remaining: z.number().int(),\n resetAt: z.string(),\n }),\n credit_insufficient: z.object({\n key: z.string(),\n balance: z.number().int(),\n reserved: z.number().int(),\n remaining: z.number().int(),\n }),\n};\n\nexport function getErrorRegistry(): Map<string, RegisteredError> {\n const g = globalThis as RegistryCarrier;\n if (!g[ERROR_REGISTRY]) {\n const m = new Map<string, RegisteredError>();\n for (const [code, status, className] of [\n [\"bad_request\", 400, \"BadRequest\"],\n [\"unauthorized\", 401, \"Unauthorized\"],\n [\"forbidden\", 403, \"Forbidden\"],\n [\"not_found\", 404, \"NotFound\"],\n [\"conflict\", 409, \"Conflict\"],\n [\"too_many_requests\", 429, \"TooManyRequests\"],\n // Thrown by the purchases decorators, so they are pre-seeded like the\n // other built-ins: a project never declares them, but every gated or\n // metered route must surface them as TYPED errors on the client.\n [\"entitlement_required\", 403, \"EntitlementRequired\"],\n [\"quota_exceeded\", 429, \"QuotaExceeded\"],\n [\"credit_insufficient\", 429, \"CreditInsufficient\"],\n ] as const) {\n const dataSchema = BUILTIN_DATA_SCHEMAS[code];\n m.set(code, {\n code,\n status,\n className,\n builtin: true,\n ...(dataSchema ? { dataSchema, dataDigest: digestOf(code, dataSchema) } : {}),\n });\n }\n g[ERROR_REGISTRY] = m;\n }\n return g[ERROR_REGISTRY];\n}\n\n/** Class returned for schema-bearing errors: ctor(data, message?). */\nexport interface DefinedErrorWithData<S extends ZodTypeAny> {\n new (data: z.input<S>, message?: string): HttpError;\n readonly code: string;\n readonly status: number;\n}\n\n/** Class returned for schema-less errors: ctor(message?). */\nexport interface DefinedError {\n new (message?: string): HttpError;\n readonly code: string;\n readonly status: number;\n}\n\n/**\n * Define a project error class. MUST be called with literal args (string\n * literal `code`, numeric literal `status`) at module top level — the deploy\n * stager's static analyzer reads those literals to resolve throw sites.\n *\n * @example\n * // models/todos/errors.ts\n * export const TodoLocked = defineError(\"todo_locked\", 409, z.object({ retryAfter: z.number() }));\n * // services/todo.service.ts\n * throw new TodoLocked({ retryAfter: 30 });\n */\nexport function defineError<S extends ZodTypeAny>(\n code: string,\n status: number,\n dataSchema: S,\n): DefinedErrorWithData<S>;\nexport function defineError(code: string, status: number): DefinedError;\nexport function defineError(code: string, status: number, dataSchema?: ZodTypeAny): unknown {\n if (!Number.isInteger(status) || status < 400 || status > 599) {\n throw new Error(\n `defineError: status for \"${code}\" must be a 4xx/5xx integer, got ${status} — ` +\n `error responses must not clobber success responses in the project spec.`,\n );\n }\n const registry = getErrorRegistry();\n const existing = registry.get(code);\n const className = defaultClassName(code);\n const dataDigest = dataSchema ? digestOf(code, dataSchema) : undefined;\n if (existing) {\n const sameShape =\n existing.status === status && !existing.builtin && existing.dataDigest === dataDigest;\n if (!sameShape) {\n throw new Error(\n `defineError: duplicate error code \"${code}\" with a different shape ` +\n `(existing: status ${existing.status}${existing.builtin ? \", built-in\" : \"\"}` +\n `${existing.status === status && !existing.builtin ? \", different data schema\" : \"\"}). ` +\n `Error codes are project-unique.`,\n );\n }\n }\n // Local factories so the class-constructor closures capture a NON-optional\n // schema binding (narrowing does not flow into closures created in a branch).\n const makeWithData = (schema: ZodTypeAny) =>\n class extends HttpError {\n static readonly code = code;\n static readonly status = status;\n constructor(data: unknown, message?: string) {\n super(status, code, message ?? humanize(code), schema.parse(data));\n this.name = className;\n }\n };\n const makeWithoutData = () =>\n class extends HttpError {\n static readonly code = code;\n static readonly status = status;\n constructor(message?: string) {\n super(status, code, message ?? humanize(code));\n this.name = className;\n }\n };\n const cls = dataSchema ? makeWithData(dataSchema) : makeWithoutData();\n Object.defineProperty(cls, \"name\", { value: className });\n registry.set(code, {\n code,\n status,\n className,\n builtin: false,\n ...(dataSchema ? { dataSchema } : {}),\n ...(dataDigest !== undefined ? { dataDigest } : {}),\n });\n return cls;\n}\n\n/** Convert a data schema through the SAME library the spec twins use and\n * return its JSON-schema digest (the duplicate-shape comparison key). Doubles\n * as the self-containment guard: a schema carrying `.openapi(refId)` metadata\n * (top-level or nested) converts to `$ref` pointers into components the\n * project spec never emits — a dangling ref every spec consumer would choke\n * on — so it is rejected here, at the definition site, with a fixable message. */\nfunction digestOf(code: string, dataSchema: ZodTypeAny): string {\n const TMP_REF = \"__PalbaseErrorDataDigest\";\n const tmpRegistry = new OpenAPIRegistry();\n // Wrap the schema as a property — exactly how the envelope embeds it — so a\n // TOP-LEVEL .openapi(refId) is not masked by the registration refId and\n // surfaces as the same $ref the real emission would produce.\n tmpRegistry.register(TMP_REF, z.object({ data: dataSchema }).openapi(TMP_REF));\n const generated = new OpenApiGeneratorV31(tmpRegistry.definitions).generateComponents();\n const out = generated.components?.schemas?.[TMP_REF];\n const digest = JSON.stringify(out ?? null);\n if (digest.includes('\"$ref\"')) {\n throw new Error(\n `defineError: dataSchema for \"${code}\" carries .openapi(refId) metadata — ` +\n `it would emit dangling $ref pointers in the project spec. ` +\n `Use a plain zod schema (z.object({...})) without .openapi(...).`,\n );\n }\n return digest;\n}\n\n/** \"todo_locked\" → \"TodoLocked\" (used as Error.name; the source class NAME the\n * analyzer sees is whatever the user assigned the const to — they should match\n * by convention, and the descriptor carries the analyzed const name anyway). */\nfunction defaultClassName(code: string): string {\n return code\n .split(\"_\")\n .map((p) => p.charAt(0).toUpperCase() + p.slice(1))\n .join(\"\");\n}\n\n/** \"todo_locked\" → \"Todo locked\" — the default human-readable message. */\nfunction humanize(code: string): string {\n const s = code.replace(/_/g, \" \");\n return s.charAt(0).toUpperCase() + s.slice(1);\n}\n","// @Webhook / @On — the inbound-webhook half of the decorator surface.\n//\n// Mirrors decorators/controller.ts exactly: symbol-keyed, non-enumerable\n// metadata on the constructor plus a `__palbase` discriminant, read back by a\n// resolver. The resolver is the ONLY translation point — it returns the shape\n// the runtime already consumes, so the isolate's dispatch and the signature\n// engine's cross-binding golden are untouched by the authoring change.\nimport type { WebhookMeta, WebhookProvider } from \"../webhook.js\";\n\n/** A signature scheme spelled out, for a service with no preset. The presets\n * (`provider`) are named configurations of this same shape. */\nexport interface SignatureSpec {\n /** Header carrying the signature. */\n header: string;\n /** Stripped before comparison (e.g. `sha256=`). Omit when absent. */\n prefix?: string;\n algo: \"hmac-sha256\" | \"hmac-sha1\";\n encoding: \"hex\" | \"base64\";\n /** What the HMAC covers. Exactly two placeholders: `{body}` and `{ts}`.\n * Everything else is literal. `{ts}` requires `timestampHeader` and brings\n * the five-minute replay window with it. */\n signs: string;\n timestampHeader?: string;\n}\n\nexport interface WebhookOptions {\n provider?: WebhookProvider;\n signature?: SignatureSpec;\n /** Env-var REFERENCE for the signing secret — the platform never holds it. */\n secret: { env: string };\n}\n\nexport type WebhookEventHandler = (event: unknown, meta: WebhookMeta) => Promise<void>;\n\nexport interface ResolvedWebhook {\n provider?: WebhookProvider;\n signature?: SignatureSpec;\n secret: { env: string };\n events: Record<string, WebhookEventHandler>;\n}\n\nexport const WEBHOOK_META: unique symbol = Symbol.for(\"palbase.backend.webhookMeta\");\nexport const WEBHOOK_EVENTS: unique symbol = Symbol.for(\"palbase.backend.webhookEvents\");\n\ninterface EventEntry {\n event: string;\n fnName: string;\n}\n\ninterface WebhookCarrier {\n __palbase?: \"webhook\";\n [WEBHOOK_META]?: WebhookOptions;\n [WEBHOOK_EVENTS]?: EventEntry[];\n}\n\nfunction carrierOf(ctor: object): WebhookCarrier {\n return ctor as WebhookCarrier;\n}\n\n/** Mark a class as an inbound webhook. The mount name is the FILE name — there\n * is deliberately no `name` option, because the file name IS the public URL. */\nexport function Webhook(options: WebhookOptions) {\n return function <T extends abstract new (...args: never[]) => object>(ctor: T): T {\n const carrier = carrierOf(ctor);\n Object.defineProperty(carrier, WEBHOOK_META, {\n value: options,\n enumerable: false,\n configurable: true,\n writable: false,\n });\n Object.defineProperty(carrier, \"__palbase\", {\n value: \"webhook\",\n enumerable: false,\n configurable: true,\n writable: false,\n });\n return ctor;\n };\n}\n\n/** Bind a method to one event name. Any string is valid: presets provide\n * autocomplete, never a constraint, because we do not carry provider catalogs. */\nexport function On(event: string) {\n return function (target: object, fnName: string | symbol): void {\n // Method decorators receive the PROTOTYPE; metadata belongs on the ctor.\n const carrier = carrierOf((target as { constructor: object }).constructor);\n const existing = carrier[WEBHOOK_EVENTS];\n const entries: EventEntry[] = existing ? [...existing] : [];\n entries.push({ event, fnName: String(fnName) });\n Object.defineProperty(carrier, WEBHOOK_EVENTS, {\n value: entries,\n enumerable: false,\n configurable: true,\n writable: false,\n });\n };\n}\n\n/** Read a decorated class back as the resolved config the runtime consumes.\n * Every misuse throws HERE, at build time, rather than becoming a webhook that\n * answers 200 and does nothing. */\nexport function getWebhookConfig(ctor: object): ResolvedWebhook {\n const carrier = carrierOf(ctor);\n const meta = carrier[WEBHOOK_META];\n const entries = carrier[WEBHOOK_EVENTS] ?? [];\n\n if (!meta) {\n throw new Error(\n `@On used on a class that is not decorated with @Webhook (${(ctor as { name?: string }).name ?? \"anonymous\"})`,\n );\n }\n if (!meta.provider && !meta.signature) {\n throw new Error(\n \"@Webhook requires either a `provider` preset or an explicit `signature` — \" +\n \"an endpoint with no verification would accept forged deliveries\",\n );\n }\n // EITHER, not both. The isolate picks `provider` when both are present and\n // never looks at `signature`, so a tenant that wrote both gets deliveries\n // verified against a scheme they did not choose — silently, and with no way to\n // tell from the outside which one ran. Ambiguity about WHICH signature check\n // guards an endpoint is not something to resolve by precedence.\n if (meta.provider && meta.signature) {\n throw new Error(\n \"@Webhook declares BOTH a `provider` preset and an explicit `signature` — \" +\n \"these are alternatives; keep the one that describes the sender, because only `provider` would be used\",\n );\n }\n if (meta.signature) {\n const sig = meta.signature;\n // Mirrors Go's NewTemplateVerifier (internal/webhook/verify.go). Both sides\n // reject the same specs; this one rejects at build, which is the only place\n // a tenant can still act on it.\n if (!sig.header) {\n throw new Error(\"@Webhook signature requires `header` — the header the signature arrives in\");\n }\n if (sig.algo !== \"hmac-sha256\" && sig.algo !== \"hmac-sha1\") {\n throw new Error(`@Webhook signature has an unsupported algo \"${sig.algo}\"`);\n }\n if (sig.encoding !== \"hex\" && sig.encoding !== \"base64\") {\n throw new Error(`@Webhook signature has an unsupported encoding \"${sig.encoding}\"`);\n }\n if (!sig.signs?.includes(\"{body}\")) {\n throw new Error(\"@Webhook signature `signs` must contain {body} — signing a constant is not a signature\");\n }\n if (sig.signs.includes(\"{ts}\") && !sig.timestampHeader) {\n throw new Error(\"@Webhook signature uses {ts} but declares no `timestampHeader` to read it from\");\n }\n }\n if (!meta.secret?.env) {\n throw new Error(\"@Webhook requires `secret: { env: \\\"VAR_NAME\\\" }`\");\n }\n if (entries.length === 0) {\n throw new Error(\"@Webhook requires at least one @On handler\");\n }\n\n const instance = new (ctor as new () => Record<string, WebhookEventHandler>)();\n // Object.create(null), not {} — event names are free-form, so `@On(\"constructor\")`\n // and `@On(\"toString\")` are legal. A plain literal inherits those keys from\n // Object.prototype, and the duplicate check below would reject the FIRST and\n // only handler for them as a redeclaration.\n const events: Record<string, WebhookEventHandler> = Object.create(null) as Record<string, WebhookEventHandler>;\n for (const entry of entries) {\n if (Object.prototype.hasOwnProperty.call(events, entry.event)) {\n throw new Error(`@On(\"${entry.event}\") declared twice on the same webhook`);\n }\n events[entry.event] = (event, metaArg) =>\n (instance[entry.fnName] as WebhookEventHandler).call(instance, event, metaArg);\n }\n\n return {\n ...(meta.provider ? { provider: meta.provider } : {}),\n ...(meta.signature ? { signature: meta.signature } : {}),\n secret: meta.secret,\n events,\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 /** Environment-scoped env vars. */\n env: Record<string, string>;\n /** The globally unique Environment runtime identifier. */\n environmentId: string;\n}\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 */\nexport function 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","// @Job — the cron half of the decorator surface. Same metadata mechanism as\n// @Webhook/@Controller. The job's NAME is not here on purpose: it is the file\n// name, which is also what the Temporal schedule id is built from. Two names\n// with nothing reconciling them is what this replaces.\nimport type { JobMeta } from \"../job.js\";\nimport { validateCronExpression } from \"../job.js\";\n\nexport interface JobOptions {\n /** Cron expression, five fields (e.g. \"0 3 * * *\"). */\n schedule: string;\n /** Execution timeout in seconds. Defaults to 30, ceiling 300 (sandbox limit). */\n timeout?: number;\n}\n\nexport interface ResolvedJob {\n schedule: string;\n timeout: number;\n handler: (meta: JobMeta) => Promise<void>;\n}\n\nconst DEFAULT_TIMEOUT_SECONDS = 30;\nconst MAX_TIMEOUT_SECONDS = 300;\n\nexport const JOB_META: unique symbol = Symbol.for(\"palbase.backend.jobMeta\");\n\ninterface JobCarrier {\n __palbase?: \"job\";\n [JOB_META]?: JobOptions;\n}\n\nexport function Job(options: JobOptions) {\n return function <T extends abstract new (...args: never[]) => object>(ctor: T): T {\n const carrier = ctor as unknown as JobCarrier;\n Object.defineProperty(carrier, JOB_META, {\n value: options,\n enumerable: false,\n configurable: true,\n writable: false,\n });\n Object.defineProperty(carrier, \"__palbase\", {\n value: \"job\",\n enumerable: false,\n configurable: true,\n writable: false,\n });\n return ctor;\n };\n}\n\nexport function getJobConfig(ctor: object): ResolvedJob {\n const meta = (ctor as JobCarrier)[JOB_META];\n if (!meta) {\n throw new Error(\n `getJobConfig on a class with no @Job decorator (${(ctor as { name?: string }).name ?? \"anonymous\"})`,\n );\n }\n if (!meta.schedule || meta.schedule.trim() === \"\") {\n throw new Error(\"@Job requires a `schedule` cron expression\");\n }\n const cronError = validateCronExpression(meta.schedule);\n if (cronError) {\n throw new Error(`@Job has an invalid cron schedule: ${cronError}`);\n }\n\n const timeout = meta.timeout ?? DEFAULT_TIMEOUT_SECONDS;\n if (!Number.isInteger(timeout) || timeout <= 0) {\n throw new Error(\"@Job `timeout` must be a positive whole number of seconds\");\n }\n if (timeout > MAX_TIMEOUT_SECONDS) {\n throw new Error(`@Job \\`timeout\\` exceeds the ${MAX_TIMEOUT_SECONDS}s sandbox ceiling`);\n }\n\n const instance = new (ctor as new () => { run?: (meta: JobMeta) => Promise<void> })();\n if (typeof instance.run !== \"function\") {\n throw new Error(\"@Job class must declare an async run() method\");\n }\n const run = instance.run.bind(instance);\n\n return { schedule: meta.schedule, timeout, handler: run };\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 /** Environment-scoped env vars. */\n env: Record<string, string>;\n /** The globally unique Environment runtime identifier. */\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":["raw","raw","bucket","raw","isPlainObject","carrierOf","carrierOf","auth","storage","registry","carrierOf","import_zod"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/runtime.ts","../src/db/tx-plan.ts","../src/errors.ts","../src/purchases/errors.ts","../src/purchases/registry.ts","../src/purchases/subject.ts","../src/purchases/decorators.ts","../src/purchases/keys-gen.ts","../src/db/policy.ts","../src/db/schema.ts","../src/db/extensions.ts","../src/db/columns.ts","../src/db/raw.ts","../src/db/typed-db.ts","../src/db/env-gen.ts","../src/config/storage.ts","../src/config/egress.ts","../src/config/notifications.ts","../src/config/test-users.ts","../src/config/flags.ts","../src/decorators/registry.ts","../src/decorators/controller.ts","../src/decorators/methods.ts","../src/decorators/upload.ts","../src/decorators/params.ts","../src/middleware.ts","../src/error-registry.ts","../src/decorators/webhook.ts","../src/job.ts","../src/decorators/job.ts","../src/resource.ts","../src/hooks.ts"],"sourcesContent":["export type {\n PBRequest,\n ClientInfo,\n RateLimitConfig,\n DBClient,\n DBOps,\n FileContext,\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 Log,\n Notifications,\n Flags,\n Realtime,\n Purchases,\n __setRuntime,\n __runWithRuntime,\n __requestALS,\n __getRuntime,\n} from \"./runtime.js\";\nexport type { RuntimeServices, RequestStore } from \"./runtime.js\";\n// Purchases: entitlement gate + metered spend, at the decorator level.\nexport { RequireEntitlement, Spend } from \"./purchases/decorators.js\";\nexport type { PurchasesService, LimitState, SpendOptions, StoreEnv } from \"./purchases/service.js\";\nexport type { EntitlementKey, LimitKey } from \"./purchases/keys.js\";\n// The codegen twin of makeEnvDts — emits the project's `palbase-purchases.d.ts`.\nexport { makePurchasesDts } from \"./purchases/keys-gen.js\";\nexport type { PurchasesManifest } from \"./purchases/keys-gen.js\";\n// Per-route purchases metadata, read by the OpenAPI step to declare 403/429.\nexport { entitlementFor, spendFor } from \"./purchases/registry.js\";\nexport type { SpendMeta } from \"./purchases/registry.js\";\nexport type {\n PalbaseAuthClient,\n PalbaseStorageClient,\n PalbaseBucketClient,\n PalbaseRealtimeClient,\n PalbaseFunctionsClient,\n PalbaseInvokeOptions,\n PalbaseFlagsClient,\n PalbaseFlagsServiceClient,\n PalbaseFlagContext,\n PalbaseFlagVariant,\n PalbaseFlag,\n PalbaseFlagValue,\n PalbaseFlagSource,\n PalbaseSetOverrideResult,\n PalbaseSetOverridesResult,\n PalbaseClearOverrideResult,\n PalbaseClearAllOverridesResult,\n PalbaseBatchOverrideOperation,\n PalbaseBatchSetOverridesResult,\n PalbaseNotificationsClient,\n PalbasePushClient,\n PalbaseEmailClient,\n PalbaseSmsClient,\n PalbaseInboxClient,\n PalbasePreferencesClient,\n PalbaseAnalyticsClient,\n PalbaseAnalyticsQueryNamespace,\n PalbaseAnalyticsManagementNamespace,\n PalbaseLinksClient,\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 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} 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, bigint, numeric, boolean, timestamp, jsonb, enumType } from \"./db/columns.js\";\nexport type { ColumnBuilder, ColumnDef, ColumnType, OnDeleteAction } from \"./db/columns.js\";\nexport { raw } from \"./db/raw.js\";\nexport type { RawConstraintDef } from \"./db/raw.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 EnvTypedTable,\n EnvTables,\n TxPlan,\n TxTables,\n} from \"./db/typed-db.js\";\n// Transaction plans: the `tx.tables.*` operation surface, its handles, and the\n// expressions a plan may write. `Database.transaction()` is on `Database`.\nexport { inc, dec, now, TxRefError, TxPlanError } from \"./db/tx-plan.js\";\nexport type {\n Ref,\n TxRow,\n TxRows,\n TxTable,\n TxPlanHandle,\n Materialized,\n TxNow,\n TxColumnExpr,\n TxInsertValue,\n TxSetValue,\n TxInsertShape,\n TxSetShape,\n TxWhere,\n TxSelectOptions,\n TxPlanBody,\n TxPlanResponse,\n TxPlanOpResult,\n TxPlanRejection,\n TxWireOp,\n TxWireRef,\n TxWireExpr,\n TxWireGuard,\n TxWireValue,\n} from \"./db/tx-plan.js\";\nexport type { Tables, TableTypes } from \"./db/env.js\";\nexport { makeEnvDts } from \"./db/env-gen.js\";\n// Module config-as-code DSLs (sibling of defineSchema). config/storage.ts\n// default-exports defineStorage(...); the deploy evals + applies the buckets.\nexport { defineStorage, bucket, parseFileSizeLimit, STORAGE_CONFIG_KIND } from \"./config/storage.js\";\nexport type { BucketDef, BucketOptions, ImageVariant, StorageConfig, StorageInput } from \"./config/storage.js\";\nexport {\n defineEgress,\n EGRESS_CONFIG_KIND,\n EGRESS_TIMEOUT_DEFAULT_MS,\n EGRESS_TIMEOUT_MAX_MS,\n EGRESS_TIMEOUT_MIN_MS,\n} from \"./config/egress.js\";\nexport type { EgressConfig, EgressInput } from \"./config/egress.js\";\n// config/notifications.ts default-exports defineNotifications(...); the deploy\n// evals + applies the providers (non-secret fields here, cert/key secrets bound\n// by convention to reserved PB_NOTIFICATIONS_* env vars resolved at deploy).\nexport {\n defineNotifications,\n buildProvider,\n extractVariables,\n reservedSecretKey,\n PROVIDER_CATALOG,\n NOTIFICATIONS_CONFIG_KIND,\n RESERVED_SECRET_PREFIX,\n DEFAULT_TEMPLATE_LOCALE,\n} from \"./config/notifications.js\";\nexport type {\n NotificationsConfig,\n NotificationsInput,\n ProviderDef,\n ProviderName,\n ProviderOptions,\n ProviderCatalogEntry,\n ApnsOptions,\n FcmOptions,\n SendgridOptions,\n SesOptions,\n SmtpOptions,\n AcsOptions,\n TwilioOptions,\n TemplatesInput,\n TemplatesConfig,\n EmailTemplateOptions,\n EmailTemplateContent,\n EmailTemplateDef,\n SmsTemplateOptions,\n SmsTemplateContent,\n SmsTemplateDef,\n} from \"./config/notifications.js\";\n// config/flags.ts default-exports defineFlags(...); the deploy evals + UPSERTS\n// the declared flag DEFINITIONS into PalFlags (upsert-only, never auto-deleted).\n// The simplest module config — pure declarative data, no secrets.\n// config/test-users.ts default-exports defineTestUsers(...); the deploy evals it\n// and hands the JSON to Studio's single apply engine (mint + seed). A fixture\n// (email+password given) is materialized create-if-missing; a template (no\n// credentials) is only registered for Studio/CLI to mint from.\nexport { defineTestUsers, testUser, TEST_USERS_CONFIG_KIND } from \"./config/test-users.js\";\nexport type {\n OwnedTablesOf,\n Seed,\n SeedFor,\n SeedJson,\n SeedRowFor,\n TableGraph,\n TestUserDef,\n TestUserOptions,\n TestUsersConfig,\n TestUsersInput,\n} from \"./config/test-users.js\";\nexport { defineFlags, flag, FLAGS_CONFIG_KIND } from \"./config/flags.js\";\nexport type {\n FlagDef,\n FlagJsonObject,\n FlagJsonValue,\n FlagOptions,\n FlagsConfig,\n FlagsInput,\n FlagType,\n FlagValue,\n} from \"./config/flags.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, Query } from \"./decorators/methods.js\";\nexport { Upload, validateUploadAgainstStorage } from \"./decorators/upload.js\";\nexport type { UploadConfig } from \"./decorators/upload.js\";\n// `UploadedObject` is exported from upload.js, where BOTH the `@UploadedObject()`\n// decorator value AND the `UploadedObject` type are declared. One module → one\n// export name carries both — authors write `@UploadedObject()` (value) and\n// `: UploadedObject` (type) with a single imported name.\nexport { UploadedObject } from \"./decorators/upload.js\";\nexport {\n Body,\n QueryParams,\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, ThrowDescriptor, RouteMeta, ParamMeta, ParamKind } from \"./decorators/registry.js\";\n// recordThrows is the stager-injected carrier for inferred throw descriptors\n// (the recordReturn twin) — public so the injected IIFE in a deployed bundle\n// can call it via `require(\"@palbase/backend\").recordThrows(...)`.\nexport { recordThrows } from \"./decorators/registry.js\";\n// getRoutes reads a controller's RouteMeta[] straight from the registry — the\n// isolate runtime enumerates routes with it instead of the worker.js raw-Symbol\n// fallback (the ROUTES symbol stays, both fallbacks keep reading it).\nexport { getRoutes } 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, VerifiedDevice, 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\";\n// Typed project errors — defineError returns an HttpError subclass and\n// self-registers {code, status, dataSchema} in the project-global error\n// registry (the OpenAPI spec twins join `RouteMeta.throws` against it).\nexport { defineError, getErrorRegistry } from \"./error-registry.js\";\nexport type { RegisteredError, DefinedError, DefinedErrorWithData } from \"./error-registry.js\";\nexport type { JobMeta } from \"./job.js\";\nexport type { WebhookProvider, WebhookMeta, WebhookRequest } from \"./webhook.js\";\n// Webhooks and jobs are classes: `@Webhook`/`@On` for inbound webhooks,\n// `@Job` for cron. Both take their name from their file — see decorators/*.\nexport { getWebhookConfig, On, Webhook } from \"./decorators/webhook.js\";\nexport type { ResolvedWebhook, SignatureSpec, WebhookEventHandler, WebhookOptions } from \"./decorators/webhook.js\";\nexport { getJobConfig, Job } from \"./decorators/job.js\";\nexport type { JobOptions, ResolvedJob } from \"./decorators/job.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 CacheClient,\n Logger,\n PalbaseDocsClient,\n} from \"./endpoint.js\";\nimport type {\n PalbaseStorageClient,\n PalbaseNotificationsClient,\n PalbaseFlagsClient,\n PalbaseFlagsServiceClient,\n PalbaseFlagContext,\n PalbaseFlagVariant,\n PalbaseFlag,\n PalbaseFlagValue,\n PalbaseSetOverrideResult,\n PalbaseRealtimeClient,\n} from \"./clients.js\";\nimport type { PalbaseResult } from \"./endpoint.js\";\nimport type {\n EnvTypedDatabase,\n EnvServiceDatabase,\n EnvTables,\n TxPlan,\n TxTables,\n} from \"./db/typed-db.js\";\nimport type { Materialized } from \"./db/tx-plan.js\";\nimport { TxPlanBuilder, runTxPlan } from \"./db/tx-plan.js\";\nimport type { PurchasesService } from \"./purchases/service.js\";\n\n/** The set of live clients the runtime injects per request scope.\n *\n * Realtime is BROADCAST-ONLY here (a stateless handler can push an event but\n * cannot hold a subscription socket — `subscribe()` lives on the client SDK).\n *\n * EXCLUDED on purpose: Functions, Links, Analytics, Auth. They are not\n * exposed as backend handler singletons (auth lives on the client SDK; the rest\n * are out of scope for backend endpoints). */\nexport interface RuntimeServices {\n Database: DBClient;\n Documents: PalbaseDocsClient;\n Storage: PalbaseStorageClient;\n Cache: CacheClient;\n Log: Logger;\n Notifications: PalbaseNotificationsClient;\n Flags: PalbaseFlagsClient;\n Realtime: PalbaseRealtimeClient;\n Purchases: PurchasesService;\n}\n\n/**\n * The per-request ALS box.\n *\n * `runtime` is the service bundle. `userId` is the request's authenticated user\n * id, written by the runtime immediately after it assembles the request object\n * (worker.js: `requestALS.getStore().userId = pbReq.user?.id || null`) and\n * `null` on an anonymous request. It was already being written there for the\n * Flags client's auto-bind; declaring it here makes the existing contract typed\n * instead of implicit, which is what lets `currentSubjectId()` read a\n * server-owned identity rather than trusting anything the caller sent.\n */\nexport interface RequestStore {\n runtime: RuntimeServices;\n userId?: string | null;\n /** This request's id (`req_…`), written by the runtime. Used as the spend\n * idempotency scope when the caller supplied no `Idempotency-Key`. */\n requestId?: string;\n /** The caller's `Idempotency-Key` header, or `null` when absent. What makes a\n * client's retry replay its first result instead of charging twice. */\n idempotencyKey?: string | null;\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<RequestStore>();\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 the top-level `Database`. Each\n * `tables.<name>` access returns a small object that forwards the five CRUD ops\n * to the underlying client using `name` as the string table identifier. The\n * shapes are typed against the generated `palbase-env.d.ts` (`EnvTables`); at\n * runtime they are 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: () => DBOps): 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>(\n fn: (tx: TxPlan) => T extends Promise<unknown> ? never : T,\n ): Promise<Materialized<T>> {\n // A FRESH builder per call: it holds this transaction's ops and its error\n // slot table, and the runtime serves concurrent requests on one event loop.\n // A shared builder would splice one request's writes into another's plan.\n const builder = new TxPlanBuilder();\n return runTxPlan(raw, makeTxTablesAccessor(builder), builder, fn) as Promise<\n Materialized<T>\n >;\n },\n });\n}\n\n/**\n * The transaction twin of {@link makeTablesAccessor}: `tables.<name>` yields the\n * table's PLAN operations, recorded into `builder` instead of sent one by one.\n *\n * Same Proxy shape and same reason for the single narrowing — TS cannot infer a\n * mapped type through a Proxy, so the cast names what the trap returns.\n */\nfunction makeTxTablesAccessor(builder: TxPlanBuilder): TxTables {\n const tablesProxy = new Proxy(\n {},\n {\n get(_t, prop: string | symbol) {\n if (typeof prop !== \"string\") return undefined;\n return builder.table(prop);\n },\n },\n );\n return tablesProxy as TxTables;\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\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/**\n * Palstore purchases (entitlements + quota/credit spend).\n *\n * Reached by handlers through the `@RequireEntitlement` / `@Spend` decorators\n * rather than called directly in the common case; exposed as a singleton for\n * the cases the decorators deliberately do not cover (a dynamic spend count,\n * which must run BEFORE the billable side-effect).\n */\nexport const Purchases: PurchasesService = makeServiceProxy(\"Purchases\");\n\n/**\n * The raw runtime Flags client for the current request scope. Carries the\n * default-surface reads + `setOverride` AND the runtime's `asService()` sibling\n * (the br-pod's `buildFlagsClient` returns both). The default `Flags` singleton\n * below forwards reads + `setOverride` through here; `Flags.asService()`\n * forwards to this client's own `asService()`.\n */\nconst rawFlags: PalbaseFlagsClient = makeServiceProxy(\"Flags\");\n\n/**\n * Feature flags.\n *\n * Mirrors the `Database` / `Database.asService()` model. The default surface is\n * RLS-equivalent for flags: reads resolve against the CURRENT request user and\n * `Flags.setOverride(key, value)` writes an override for that same signed-in\n * user (no userId argument, no admin power). Cross-user admin writes\n * (`setOverrideForUser`, …) live behind `Flags.asService()` — explicit and\n * greppable, just like `Database.asService()`.\n *\n * @example\n * import { Flags } from \"@palbase/backend\";\n *\n * if (await Flags.isEnabled(\"new_checkout\")) { ... } // current user\n * await Flags.setOverride(\"new_checkout\", true); // current user\n * await Flags.asService().setOverrideForUser(\"u_9\", \"x\", true); // cross-user\n */\nexport const Flags: PalbaseFlagsClient = Object.assign(\n {\n isEnabled(\n flagName: string,\n context?: PalbaseFlagContext,\n ): Promise<PalbaseResult<boolean>> {\n return rawFlags.isEnabled(flagName, context);\n },\n getVariant(\n flagName: string,\n context?: PalbaseFlagContext,\n ): Promise<PalbaseResult<PalbaseFlagVariant>> {\n return rawFlags.getVariant(flagName, context);\n },\n getAll(context?: PalbaseFlagContext): Promise<PalbaseResult<PalbaseFlag[]>> {\n return rawFlags.getAll(context);\n },\n setOverride(\n key: string,\n value: PalbaseFlagValue,\n ): Promise<PalbaseResult<PalbaseSetOverrideResult>> {\n return rawFlags.setOverride(key, value);\n },\n },\n {\n /**\n * Lazily resolve the runtime's cross-user sibling on each call. We do NOT\n * cache it: `rawFlags.asService()` reads the CURRENT request scope through\n * the runtime proxy, so caching would leak one request's sibling into\n * another concurrent request. Mirrors `Database.asService()`.\n */\n asService(): PalbaseFlagsServiceClient {\n return rawFlags.asService();\n },\n },\n);\n\n/**\n * The Realtime broadcast singleton for the current request scope. Backend-side\n * Realtime is BROADCAST-ONLY (a stateless handler can push but not subscribe —\n * `subscribe()` lives on the client SDK's `pb.realtime`). Fire-and-forget:\n * `broadcast` resolves once accepted (or with an `error`), never blocking the\n * handler on subscribers.\n *\n * @example\n * import { Realtime } from \"@palbase/backend\";\n *\n * await Realtime.broadcast(\"room:42\", \"message\", { text, from: user.id });\n */\nexport const Realtime: PalbaseRealtimeClient = makeServiceProxy(\"Realtime\");\n","/**\n * tx-plan.ts — `Database.transaction()` as a PLAN, not a pinned session.\n *\n * A transaction used to be a conversation: BEGIN, then one network round trip\n * per operation, then COMMIT. Each of those round trips cost ~4 ms and, because\n * the pooler runs in transaction mode, an open transaction pinned a Postgres\n * backend for the whole conversation. A 121-operation statement upload pinned\n * one backend for ~490 ms.\n *\n * So the callback no longer TALKS to the database. It DESCRIBES what should\n * happen; the description is serialised and sent once; the broker runs the whole\n * thing inside one transaction and answers once. Committing on return and\n * rolling back on throw is unchanged — that is the only property tenant code\n * actually asked for.\n *\n * The consequences, stated plainly, because they are the whole design:\n *\n * - The callback is SYNCHRONOUS. There is nothing to await: no statement has\n * run yet when it returns. `async` on the callback and `await` inside it are\n * both compile errors (see {@link TxPlan} and {@link NotAwaitable}).\n * - `insert()` does not hand back a row, it hands back {@link TxRows}. Reading\n * a field requires `.expectOne(err)` first, which makes \"what if the row\n * isn't there\" a question you cannot route around: it is the argument.\n * - A field read from a row is a {@link Ref} — a PROMISE OF A VALUE THE SERVER\n * WILL PRODUCE, not the value. It can be written into a later operation and\n * it can be returned from the callback (it is substituted for the real value\n * before `transaction()` resolves). It cannot be branched on. See the\n * \"Truthiness\" note below — this is the sharp edge of the whole design.\n * - Control flow that needs a real value must move OUT of the callback: read\n * before the transaction, or express the condition as a guard\n * (`updateWhere({ id, accepted_at: null }, …).expectOne(new Conflict(…))`)\n * which the server evaluates and which rolls the whole plan back.\n *\n * # Truthiness — the hole this file CANNOT close\n *\n * JavaScript does not let a Proxy trap truthiness. `if (ref)` takes the true\n * branch, always, for every Ref, and no `get` handler ever runs. `tsc` is silent\n * because a Ref is a perfectly good object. So:\n *\n * const pot = tx.tables.pots.select({ id }, { limit: 1 }).expectOne(e);\n * if (!pot.balance) { … } // ← ALWAYS false. Silently wrong data.\n *\n * What this file does close: coercion (`Symbol.toPrimitive`/`valueOf`/\n * `toString`), awaiting (`then` is a callable member with a non-thenable\n * signature, which is a *compile* error), serialisation (`toJSON`), and nesting\n * a Ref inside a literal value where the server would store it as data. What it\n * cannot close is a bare truthiness test. The real defence is the build-time\n * static analysis (`tx_analysis.js`, phase P4); until that ships, this hole is\n * open and this comment is the only warning.\n *\n * # Wire contract\n *\n * The JSON this file emits is consumed by\n * `modules/backend/internal/management/tx_program.go`. That decoder rejects\n * unknown fields at every level, so an op carries EXACTLY the fields its kind\n * takes. Everything here that looks like a needless restriction is one of the\n * server's rules made visible early:\n *\n * - `$ref` only points BACKWARDS, and only at an op statically known to yield\n * at most one row (insert, or a `one`/`atMost 1` guard, or `select limit 1`).\n * `.expectOne()` is what this file uses to satisfy that, always.\n * - `$expr` is a closed set: `inc`/`dec` (update only — they read the column's\n * current value) and `now()`.\n * - `update`/`delete` require a `where`; `insert` refuses one.\n * - `insertMany` rows must all set the same columns.\n * - ≤1000 ops, ≤5000 rows per insertMany, ≤8 MiB of JSON.\n *\n * Column keys are emitted SORTED, so the same callback always produces byte-\n * identical JSON. That is what lets the Go decoder be locked to golden files\n * this SDK emits (`testdata/tx_plan_golden/`).\n */\n\n// ---------------------------------------------------------------------------\n// Errors\n// ---------------------------------------------------------------------------\n\n/**\n * A plan handle was used as if it were a value: awaited, coerced to a string or\n * number, serialised, or nested inside another value.\n *\n * Thrown while the callback is still BUILDING the plan, so nothing has been sent\n * and nothing has been written.\n */\nexport class TxRefError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"TxRefError\";\n }\n}\n\n/**\n * The plan the callback described cannot be sent: it breaks a rule the server\n * would reject, and rejecting it here names the line that wrote it instead of\n * returning a 400 about an op index.\n */\nexport class TxPlanError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"TxPlanError\";\n }\n}\n\n// ---------------------------------------------------------------------------\n// Wire types — mirror tx_program.go's decoder exactly.\n// ---------------------------------------------------------------------------\n\n/** A backwards reference to an earlier op's single-row result. */\nexport interface TxWireRef {\n $ref: { op: number; field: string };\n}\n\n/** A call from the server's closed function set. */\nexport interface TxWireExpr {\n $expr: { fn: \"inc\" | \"dec\"; by: number } | { fn: \"now\" };\n}\n\n/** One value in a `values`/`set`/`where` map: a literal, a `$ref` or a `$expr`. */\nexport type TxWireValue = TxWireRef | TxWireExpr | unknown;\n\n/** The tenant's declared expectation about an op's row count. `slot` indexes the\n * client-side error table — the error OBJECT never travels. */\nexport interface TxWireGuard {\n kind: \"one\" | \"none\" | \"atLeast\" | \"atMost\";\n n: number;\n slot: number;\n}\n\n/** One operation in the wire plan. Fields are omitted, never null: the decoder\n * rejects a field that does not belong to the op's kind. */\nexport interface TxWireOp {\n op: \"insert\" | \"insertMany\" | \"update\" | \"delete\" | \"select\";\n table: string;\n values?: Record<string, TxWireValue>;\n rows?: Record<string, TxWireValue>[];\n set?: Record<string, TxWireValue>;\n where?: Record<string, TxWireValue>;\n limit?: number;\n lock?: \"update\";\n guard?: TxWireGuard;\n}\n\n/** The request body of `POST /internal-api/db/tx`. */\nexport interface TxPlanBody {\n ops: TxWireOp[];\n}\n\n/** One op's outcome, positionally matched to the plan's ops. */\nexport interface TxPlanOpResult {\n rows: Record<string, unknown>[];\n rows_affected: number;\n}\n\n/** The response body of `POST /internal-api/db/tx`. */\nexport interface TxPlanResponse {\n results: TxPlanOpResult[];\n}\n\n/**\n * The fields the runtime must copy from the broker's error envelope onto the\n * rejection it throws out of {@link DBClient.txPlan}.\n *\n * `slot` is the whole point: on a guard failure the server answers with the\n * INDEX of the expectation that did not hold, never with an error message of its\n * own, and this SDK maps that index back to the `Error` the callback handed to\n * `.expectOne(…)`. Without `slot` a guard failure degrades to a generic 409.\n */\nexport interface TxPlanRejection {\n status?: number;\n /** `tx_plan_invalid` | `tx_guard_failed` | `tx_ref_unresolved` | a pg class. */\n error_code?: string;\n /** Present only for `tx_guard_failed`: the client-side error table index. */\n slot?: number;\n /** Present on a database error: which op failed. */\n op?: number;\n}\n\n// ---------------------------------------------------------------------------\n// Handle types\n// ---------------------------------------------------------------------------\n\ndeclare const refBrand: unique symbol;\ndeclare const rowBrand: unique symbol;\ndeclare const rowsBrand: unique symbol;\n\n/**\n * Makes a handle a compile error to `await`.\n *\n * `then` is declared as a CALLABLE member whose signature is not `PromiseLike`,\n * which is precisely the shape TypeScript rejects: `await handle` is TS1320 and\n * `async () => handle` is TS1058. A non-callable `then` would not do it — the\n * compiler simply ignores those.\n */\nexport interface NotAwaitable {\n /** Not a promise. Nothing here has run yet; there is nothing to await. */\n then(doNotAwaitAPlanHandle: \"a transaction plan is built synchronously\"): never;\n}\n\n/**\n * A value the SERVER will produce, standing in for a column of a row this plan\n * writes or reads.\n *\n * Legal uses: write it into a later operation's `values`/`set`/`where`, or\n * return it from the callback (it is replaced by the real value before\n * `transaction()` resolves).\n *\n * Illegal, and caught: `await`, `String(ref)`, `` `${ref}` ``, `ref + 1`,\n * `JSON.stringify(ref)`, burying it inside a jsonb object.\n *\n * Illegal, and NOT caught: `if (ref)`. See the truthiness note at the top.\n */\nexport interface Ref<T> extends NotAwaitable {\n readonly [refBrand]: T;\n}\n\n/** The brand carried by a single-row handle, and the seam `Materialized` reads\n * to turn `return st` into the whole row. */\nexport interface TxRowHandle<Row> extends NotAwaitable {\n readonly [rowBrand]: Row;\n}\n\n/**\n * A row this plan is known to produce exactly one of. Every property is a\n * {@link Ref}; returning the handle itself yields the whole row.\n *\n * Only `.expectOne(err)` produces one — which is the design: a row you can read\n * fields from is a row whose absence you have already answered for.\n */\nexport type TxRow<Row> = { readonly [K in keyof Row]: Ref<Row[K]> } & TxRowHandle<Row>;\n\n/**\n * The result of one operation, before any expectation is declared about it.\n *\n * Deliberately not a row and not a list: an operation's row count is not known\n * until the server runs it, so the only thing that can be said about it here is\n * an EXPECTATION. Declaring one is also the only way to get a readable row.\n *\n * At most one expectation per operation — the wire carries one guard per op, and\n * a second call throws rather than silently dropping the first.\n */\nexport interface TxRows<Row> extends NotAwaitable {\n readonly [rowsBrand]: Row;\n /**\n * Require exactly one row, and read it. On any other count the server rolls\n * the whole transaction back and this `error` is thrown to the caller.\n *\n * This is the only way to reach a row's fields, and the only shape a `$ref`\n * may point at.\n */\n expectOne(error: Error): TxRow<Row>;\n /** Require zero rows (e.g. \"this membership must not already exist\"). */\n expectNone(error: Error): void;\n /** Require at least `n` rows. */\n expectAtLeast(n: number, error: Error): void;\n /** Require at most `n` rows. */\n expectAtMost(n: number, error: Error): void;\n}\n\n/** `now()` — the server's clock, usable wherever a value is. */\nexport interface TxNow extends NotAwaitable {\n readonly $expr: { fn: \"now\" };\n}\n\n/** `inc(n)` / `dec(n)` — read the column's CURRENT value and write it back\n * changed. Only meaningful in an update's `set`, which is where the types allow\n * it and where the server allows it. */\nexport interface TxColumnExpr extends NotAwaitable {\n readonly $expr: { fn: \"inc\" | \"dec\"; by: number };\n}\n\n/**\n * Resolve a callback's return type against what actually comes back: every\n * {@link Ref} becomes its value, every {@link TxRow} becomes its row, and\n * anything else keeps its shape.\n *\n * A {@link TxRows} resolves to an explanatory string type rather than a row\n * list: it has no single answer to give, and saying so in the type is louder\n * than a runtime throw.\n */\nexport type Materialized<T> = T extends Ref<infer U>\n ? U\n : T extends TxRowHandle<infer R>\n ? R\n : T extends TxRows<unknown>\n ? \"a TxRows cannot leave the transaction callback — read a row with .expectOne(err) first\"\n : T extends Date\n ? T\n : T extends object\n ? { [K in keyof T]: Materialized<T[K]> }\n : T;\n\n// ---------------------------------------------------------------------------\n// Author-facing value types\n// ---------------------------------------------------------------------------\n\n/** A value written by an INSERT: a literal, an earlier row's field, or `now()`.\n * `inc`/`dec` are absent on purpose — they read a current value, and an inserted\n * row has none. */\nexport type TxInsertValue<V> = V | Ref<V> | TxNow;\n\n/** A value written by an UPDATE's `set`: everything an insert takes, plus the\n * read-modify-write expressions. */\nexport type TxSetValue<V> = V | Ref<V> | TxNow | TxColumnExpr;\n\n/** An insert payload: the table's insert shape, with refs and `now()` allowed. */\nexport type TxInsertShape<Insert> = { [K in keyof Insert]: TxInsertValue<Insert[K]> };\n\n/** An update's `set`: any subset of the insert shape, with expressions allowed. */\nexport type TxSetShape<Insert> = { [K in keyof Insert]?: TxSetValue<Insert[K]> };\n\n/**\n * A filter. Every entry is an equality test and they are AND-ed; a `null`\n * becomes `IS NULL`, which is what makes `{ accepted_at: null }` a usable\n * \"not yet accepted\" guard rather than a clause that matches nothing.\n */\nexport type TxWhere<Row> = { [K in keyof Row]?: Row[K] | Ref<Row[K]> };\n\n/** Options for a plan `select`. */\nexport interface TxSelectOptions {\n /** Cap the rows read. */\n limit?: number;\n /** Take a real `FOR UPDATE` row lock for the rest of the transaction. */\n lock?: \"update\";\n}\n\n/** One table, as the plan sees it. */\nexport interface TxTable<Row, Insert> {\n /** Insert one row. Returns a handle — call `.expectOne(err)` to read fields. */\n insert(values: TxInsertShape<Insert>): TxRows<Row>;\n /**\n * Insert many rows in ONE statement. Every row must set the same columns\n * (a row that omits one would silently take the column's default).\n *\n * An empty list writes nothing and sends nothing.\n */\n insertMany(rows: readonly TxInsertShape<Insert>[]): TxRows<Row>;\n /**\n * Update every row matching `where`. The filter comes first because it is the\n * dangerous half: an update whose `where` you got wrong rewrites rows you\n * never looked at. The server refuses an update with no `where` at all.\n */\n updateWhere(where: TxWhere<Row>, set: TxSetShape<Insert>): TxRows<Row>;\n /** Delete every row matching `where`. The server refuses an unfiltered delete. */\n deleteWhere(where: TxWhere<Row>): TxRows<Row>;\n /** Read rows, optionally locking them for the rest of the transaction. */\n select(where?: TxWhere<Row>, options?: TxSelectOptions): TxRows<Row>;\n}\n\n/**\n * The handle a transaction callback receives.\n *\n * It carries tables and nothing else: no `query`, no `findById`, no `asService`.\n * A read whose value the plan does not write belongs OUTSIDE the transaction,\n * where it costs one round trip and can be branched on like an ordinary value.\n */\nexport interface TxPlanHandle<TTables> {\n tables: TTables;\n}\n\n// ---------------------------------------------------------------------------\n// Runtime — expressions\n// ---------------------------------------------------------------------------\n\n/** Internal marker read by the serialiser. */\nconst EXPR = Symbol.for(\"palbase.tx.expr\");\nconst REF = Symbol.for(\"palbase.tx.ref\");\nconst ROW = Symbol.for(\"palbase.tx.row\");\nconst ROWS = Symbol.for(\"palbase.tx.rows\");\n\ninterface RefDescriptor {\n op: number;\n field: string;\n}\n\n/** Property reads that must not silently produce a value on a plan handle.\n * `then` is the one that matters for correctness (it makes `await` a compile\n * error AND stops a handle from being adopted by a promise); the rest turn a\n * silent wrong answer — `\"[object Object]\"`, `NaN`, `{}` — into a thrown one. */\nconst TRAPPED_PROPS: readonly (string | symbol)[] = [\n \"then\",\n \"valueOf\",\n \"toString\",\n \"toJSON\",\n Symbol.toPrimitive,\n];\n\nfunction trap(prop: string | symbol, what: string, hint: string): never {\n const name = typeof prop === \"symbol\" ? prop.description ?? String(prop) : prop;\n throw new TxRefError(\n `${what} was used as a value (via \\`${name}\\`). Nothing in a transaction ` +\n `callback has run yet, so there is no value to read. ${hint}`,\n );\n}\n\n/** The server's `now()`. */\nexport function now(): TxNow {\n return makeExpr({ fn: \"now\" }) as TxNow;\n}\n\n/** Add `by` to the column's current value. Only valid in an update's `set`. */\nexport function inc(by: number): TxColumnExpr {\n assertFiniteNumber(by, \"inc\");\n return makeExpr({ fn: \"inc\", by }) as TxColumnExpr;\n}\n\n/** Subtract `by` from the column's current value. Only valid in an update's `set`. */\nexport function dec(by: number): TxColumnExpr {\n assertFiniteNumber(by, \"dec\");\n return makeExpr({ fn: \"dec\", by }) as TxColumnExpr;\n}\n\nfunction assertFiniteNumber(by: number, fn: string): void {\n if (typeof by !== \"number\" || !Number.isFinite(by)) {\n // JSON has no NaN/Infinity: they would serialise to `null` and the server\n // would reject the plan with an unhelpful decode error.\n throw new TxPlanError(`${fn}() needs a finite number, got ${String(by)}`);\n }\n}\n\nfunction makeExpr(expr: TxWireExpr[\"$expr\"]): unknown {\n return new Proxy(\n { [EXPR]: expr } as Record<string | symbol, unknown>,\n {\n get(target, prop) {\n if (prop === EXPR) return target[EXPR];\n if (TRAPPED_PROPS.includes(prop)) {\n trap(prop, \"A plan expression\", \"Write it into an operation instead.\");\n }\n return undefined;\n },\n },\n );\n}\n\n// ---------------------------------------------------------------------------\n// Runtime — refs and row handles\n// ---------------------------------------------------------------------------\n\nfunction makeRef(op: number, field: string): unknown {\n const target: Record<string | symbol, unknown> = { [REF]: { op, field } satisfies RefDescriptor };\n return new Proxy(target, {\n get(t, prop) {\n if (prop === REF) return t[REF];\n if (TRAPPED_PROPS.includes(prop)) {\n trap(\n prop,\n `\\`${field}\\` of a row this transaction has not written yet`,\n \"Pass it to another operation in the same plan, or return it from the \" +\n \"callback and read it after `transaction()` resolves.\",\n );\n }\n return undefined;\n },\n });\n}\n\nfunction makeRowHandle(op: number): unknown {\n const target: Record<string | symbol, unknown> = { [ROW]: op };\n return new Proxy(target, {\n get(t, prop) {\n if (prop === ROW) return t[ROW];\n if (TRAPPED_PROPS.includes(prop)) {\n trap(\n prop,\n \"A row this transaction has not written yet\",\n \"Read one of its columns to reference it, or return the row from the \" +\n \"callback and read it after `transaction()` resolves.\",\n );\n }\n if (typeof prop === \"symbol\") return undefined;\n return makeRef(op, prop);\n },\n });\n}\n\nfunction refDescriptor(v: unknown): RefDescriptor | null {\n if (typeof v !== \"object\" || v === null) return null;\n const d = (v as Record<symbol, unknown>)[REF];\n return isRefDescriptor(d) ? d : null;\n}\n\nfunction isRefDescriptor(d: unknown): d is RefDescriptor {\n return (\n typeof d === \"object\" &&\n d !== null &&\n typeof (d as RefDescriptor).op === \"number\" &&\n typeof (d as RefDescriptor).field === \"string\"\n );\n}\n\nfunction rowOpIndex(v: unknown): number | null {\n if (typeof v !== \"object\" || v === null) return null;\n const op = (v as Record<symbol, unknown>)[ROW];\n return typeof op === \"number\" ? op : null;\n}\n\nfunction exprOf(v: unknown): TxWireExpr[\"$expr\"] | null {\n if (typeof v !== \"object\" || v === null) return null;\n const e = (v as Record<symbol, unknown>)[EXPR];\n return typeof e === \"object\" && e !== null ? (e as TxWireExpr[\"$expr\"]) : null;\n}\n\nfunction isRowsHandle(v: unknown): boolean {\n return typeof v === \"object\" && v !== null && (v as Record<symbol, unknown>)[ROWS] !== undefined;\n}\n\n// ---------------------------------------------------------------------------\n// Runtime — value encoding\n// ---------------------------------------------------------------------------\n\n/**\n * Encode one value of a `values`/`set`/`where` map.\n *\n * The nesting check is not defensive tidiness. The server treats `$ref` as a\n * tagged value only at the TOP of a column's value; a ref buried inside a jsonb\n * payload is just data, and would be stored as the literal object\n * `{\"$ref\":{...}}` — a write that succeeds, commits, and is wrong. So a nested\n * handle is a hard error here, where the line that wrote it is still on the\n * stack.\n */\nfunction encodeValue(value: unknown, column: string, allowColumnExpr: boolean): TxWireValue {\n const ref = refDescriptor(value);\n if (ref) return { $ref: { op: ref.op, field: ref.field } } satisfies TxWireRef;\n\n const expr = exprOf(value);\n if (expr) {\n if (expr.fn !== \"now\" && !allowColumnExpr) {\n throw new TxPlanError(\n `\\`${column}\\`: ${expr.fn}() reads the column's current value, so it is ` +\n `only valid in updateWhere(where, set).`,\n );\n }\n return { $expr: expr } satisfies TxWireExpr;\n }\n\n if (rowOpIndex(value) !== null) {\n throw new TxPlanError(\n `\\`${column}\\`: a row handle is not a value. Read the column you meant ` +\n `(e.g. \\`row.id\\`).`,\n );\n }\n if (isRowsHandle(value)) {\n throw new TxPlanError(\n `\\`${column}\\`: an operation result is not a value. Declare an expectation ` +\n `first (\\`.expectOne(err)\\`) and read a column from the row.`,\n );\n }\n\n assertNoNestedHandles(value, column);\n return value;\n}\n\nfunction assertNoNestedHandles(value: unknown, column: string): void {\n if (typeof value !== \"object\" || value === null) return;\n if (value instanceof Date) return;\n if (refDescriptor(value) || exprOf(value) || rowOpIndex(value) !== null || isRowsHandle(value)) {\n throw new TxPlanError(\n `\\`${column}\\`: a plan handle is nested inside a value. The server would ` +\n `store it as literal JSON, not resolve it. Put the reference directly in ` +\n `the column.`,\n );\n }\n if (Array.isArray(value)) {\n for (const item of value) assertNoNestedHandles(item, column);\n return;\n }\n for (const item of Object.values(value as Record<string, unknown>)) {\n assertNoNestedHandles(item, column);\n }\n}\n\n/**\n * Encode a column map, dropping `undefined` and emitting keys SORTED.\n *\n * Sorting is what makes the same callback produce byte-identical JSON every\n * time, which is what lets the Go decoder be locked to goldens this SDK emits.\n * Dropping `undefined` mirrors what `JSON.stringify` would do anyway, but does\n * it where the resulting column list is still checkable.\n */\nfunction encodeMap(\n map: Record<string, unknown>,\n allowColumnExpr: boolean,\n): Record<string, TxWireValue> {\n const out: Record<string, TxWireValue> = {};\n for (const key of Object.keys(map).sort()) {\n const value = map[key];\n if (value === undefined) continue;\n out[key] = encodeValue(value, key, allowColumnExpr);\n }\n return out;\n}\n\n// ---------------------------------------------------------------------------\n// Runtime — the builder\n// ---------------------------------------------------------------------------\n\n/** How many rows an op can produce, as far as the CLIENT can tell before it\n * runs. Only the empty `insertMany` is knowable, and knowing it is what lets a\n * doomed expectation fail on the line that declared it. */\nconst SKIPPED_OP = -1;\n\nclass TxRowsImpl<Row> implements TxRows<Row> {\n // Present so `isRowsHandle` recognises the object; never read for its value.\n readonly [ROWS] = true;\n // Phantom: the type brand that stops a bare object passing as a TxRows. Never\n // present at run time, which is what `declare` says.\n declare readonly [rowsBrand]: Row;\n private guarded = false;\n\n constructor(\n private readonly builder: TxPlanBuilder,\n private readonly opIndex: number,\n private readonly what: string,\n ) {}\n\n // The type-level `await` guard made real: TS rejects `await rows` at compile\n // time, and reaching this means someone called `.then(...)` by hand.\n then(): never {\n throw new TxRefError(\n `${this.what} cannot be awaited: a transaction callback builds a plan, it ` +\n `does not run statements. Remove the \\`await\\`.`,\n );\n }\n\n expectOne(error: Error): TxRow<Row> {\n this.declareGuard(\"one\", 1, error);\n if (this.opIndex === SKIPPED_OP) throw error;\n return makeRowHandle(this.opIndex) as TxRow<Row>;\n }\n\n expectNone(error: Error): void {\n this.declareGuard(\"none\", 0, error);\n }\n\n expectAtLeast(n: number, error: Error): void {\n assertGuardCount(n, \"expectAtLeast\");\n this.declareGuard(\"atLeast\", n, error);\n if (this.opIndex === SKIPPED_OP && n > 0) throw error;\n }\n\n expectAtMost(n: number, error: Error): void {\n assertGuardCount(n, \"expectAtMost\");\n this.declareGuard(\"atMost\", n, error);\n }\n\n private declareGuard(kind: TxWireGuard[\"kind\"], n: number, error: Error): void {\n if (!(error instanceof Error)) {\n // The error object is the ONLY thing that describes this failure to the\n // caller — the server sends back an index, never a message.\n throw new TxPlanError(\n `${this.what}: an expectation needs the Error to throw when it does not ` +\n `hold (e.g. \\`.expect…(new Conflict(\"already accepted\"))\\`).`,\n );\n }\n if (this.guarded) {\n throw new TxPlanError(\n `${this.what} already has an expectation. One operation carries one ` +\n `expectation; declare the second one on its own operation.`,\n );\n }\n this.guarded = true;\n if (this.opIndex === SKIPPED_OP) return;\n this.builder.attachGuard(this.opIndex, kind, n, error);\n }\n}\n\nfunction assertGuardCount(n: number, fn: string): void {\n if (!Number.isInteger(n) || n < 0) {\n throw new TxPlanError(`${fn}(n) needs a non-negative integer, got ${String(n)}`);\n }\n}\n\n/** Bounds mirrored from tx_program.go so an over-sized plan is named here rather\n * than rejected as an opaque 400 after it has crossed the network. */\nconst MAX_OPS = 1000;\nconst MAX_ROWS = 5000;\n\n/**\n * Accumulates ops and the client-side error table while the callback runs.\n *\n * Exported for the runtime and for tests that need the serialised plan without\n * a server; author code never sees it.\n */\nexport class TxPlanBuilder {\n private readonly ops: TxWireOp[] = [];\n /** Errors handed to expectations, indexed by the `slot` the server echoes. */\n private readonly slots: Error[] = [];\n\n /** The table surface handed to the callback. Untyped here; the public\n * `transaction()` signatures put the schema types on top. */\n table(name: string): TxTable<Record<string, unknown>, Record<string, unknown>> {\n return {\n insert: (values) => {\n const encoded = encodeMap(values as Record<string, unknown>, false);\n if (Object.keys(encoded).length === 0) {\n throw new TxPlanError(`${name}.insert() needs at least one column`);\n }\n return this.push({ op: \"insert\", table: name, values: encoded }, `${name}.insert()`);\n },\n\n insertMany: (rows) => {\n if (rows.length === 0) {\n // Nothing to write. Emitting an op would be a guaranteed 400 (the\n // server requires rows), and refusing outright would punish the\n // ordinary \"filtered every candidate out\" case.\n return new TxRowsImpl(this, SKIPPED_OP, `${name}.insertMany()`);\n }\n if (rows.length > MAX_ROWS) {\n throw new TxPlanError(\n `${name}.insertMany() has ${rows.length} rows; the limit is ${MAX_ROWS}. ` +\n `Split the write across requests.`,\n );\n }\n const encoded = rows.map((row) => encodeMap(row as Record<string, unknown>, false));\n assertUniformRows(encoded, name);\n return this.push({ op: \"insertMany\", table: name, rows: encoded }, `${name}.insertMany()`);\n },\n\n updateWhere: (where, set) => {\n const encodedWhere = encodeMap(where as Record<string, unknown>, false);\n const encodedSet = encodeMap(set as Record<string, unknown>, true);\n if (Object.keys(encodedWhere).length === 0) {\n throw new TxPlanError(\n `${name}.updateWhere() needs a filter. An update with no filter ` +\n `rewrites the whole table.`,\n );\n }\n if (Object.keys(encodedSet).length === 0) {\n throw new TxPlanError(`${name}.updateWhere() needs at least one column to set`);\n }\n return this.push(\n { op: \"update\", table: name, set: encodedSet, where: encodedWhere },\n `${name}.updateWhere()`,\n );\n },\n\n deleteWhere: (where) => {\n const encodedWhere = encodeMap(where as Record<string, unknown>, false);\n if (Object.keys(encodedWhere).length === 0) {\n throw new TxPlanError(\n `${name}.deleteWhere() needs a filter. A delete with no filter empties ` +\n `the table.`,\n );\n }\n return this.push(\n { op: \"delete\", table: name, where: encodedWhere },\n `${name}.deleteWhere()`,\n );\n },\n\n select: (where, options) => {\n const op: TxWireOp = { op: \"select\", table: name };\n const encodedWhere = encodeMap((where ?? {}) as Record<string, unknown>, false);\n if (Object.keys(encodedWhere).length > 0) op.where = encodedWhere;\n if (options?.limit !== undefined) {\n if (!Number.isInteger(options.limit) || options.limit < 0) {\n throw new TxPlanError(\n `${name}.select(): limit needs a non-negative integer, got ${String(options.limit)}`,\n );\n }\n op.limit = options.limit;\n }\n if (options?.lock !== undefined) op.lock = options.lock;\n return this.push(op, `${name}.select()`);\n },\n };\n }\n\n private push(op: TxWireOp, what: string): TxRows<Record<string, unknown>> {\n if (this.ops.length >= MAX_OPS) {\n throw new TxPlanError(\n `this transaction has ${MAX_OPS} operations, which is the limit. Use ` +\n `insertMany() for bulk writes, or split the work across requests.`,\n );\n }\n const index = this.ops.length;\n this.ops.push(op);\n return new TxRowsImpl(this, index, what);\n }\n\n /** Attach an expectation to an op and record its error in the slot table. */\n attachGuard(opIndex: number, kind: TxWireGuard[\"kind\"], n: number, error: Error): void {\n const op = this.ops[opIndex];\n // Unreachable: the index came from `push`. A loud failure beats a silently\n // unguarded write if that ever stops being true.\n if (!op) throw new TxPlanError(`internal: expectation on unknown operation ${opIndex}`);\n const slot = this.slots.length;\n this.slots.push(error);\n op.guard = { kind, n, slot };\n }\n\n /** The serialisable plan. Empty when the callback described no writes. */\n body(): TxPlanBody {\n return { ops: this.ops };\n }\n\n /** The error the server's `slot` selects, or `null` when it names one this\n * plan never declared (a server/client disagreement, not a tenant error). */\n errorForSlot(slot: number): Error | null {\n return this.slots[slot] ?? null;\n }\n}\n\nfunction assertUniformRows(rows: Record<string, TxWireValue>[], table: string): void {\n const first = rows[0];\n if (!first) return;\n const want = Object.keys(first);\n const wantKey = want.join(\",\");\n for (let i = 1; i < rows.length; i++) {\n const got = Object.keys(rows[i] as Record<string, TxWireValue>);\n if (got.join(\",\") !== wantKey) {\n // One statement, one column list. A ragged row would take the DB default\n // for the column it omitted — a write that succeeds and is wrong.\n throw new TxPlanError(\n `${table}.insertMany(): every row must set the same columns. Row 0 sets ` +\n `[${want.join(\", \")}] but row ${i} sets [${got.join(\", \")}]. ` +\n `(A property set to \\`undefined\\` counts as absent — use \\`null\\`.)`,\n );\n }\n }\n}\n\n// ---------------------------------------------------------------------------\n// Runtime — materialisation\n// ---------------------------------------------------------------------------\n\n/**\n * Replace every handle in the callback's return value with what the server\n * actually produced.\n *\n * Walks arrays and PLAIN objects only. Class instances (a Date, a Zod schema, a\n * domain object) are returned untouched — recursing into them would rebuild them\n * as bare objects, and nothing inside one can be a handle that this SDK created.\n */\nexport function materializeResult(value: unknown, results: TxPlanOpResult[]): unknown {\n const ref = refDescriptor(value);\n if (ref) {\n const row = rowOf(results, ref.op, `\\`${ref.field}\\``);\n if (!(ref.field in row)) {\n throw new TxPlanError(\n `the transaction's operation ${ref.op} returned no column \\`${ref.field}\\`.`,\n );\n }\n return row[ref.field];\n }\n\n const rowOp = rowOpIndex(value);\n if (rowOp !== null) return rowOf(results, rowOp, \"a row\");\n\n if (isRowsHandle(value)) {\n throw new TxPlanError(\n \"an operation result cannot be returned from a transaction callback: its \" +\n \"row count is not known until the plan runs. Declare an expectation \" +\n \"(`.expectOne(err)`) and return the row, or a column of it.\",\n );\n }\n\n if (Array.isArray(value)) return value.map((item) => materializeResult(item, results));\n\n if (isPlainObject(value)) {\n const out: Record<string, unknown> = {};\n for (const [key, item] of Object.entries(value)) out[key] = materializeResult(item, results);\n return out;\n }\n\n return value;\n}\n\nfunction rowOf(results: TxPlanOpResult[], opIndex: number, what: string): Record<string, unknown> {\n const result = results[opIndex];\n if (!result) {\n throw new TxPlanError(\n `the transaction returned no result for operation ${opIndex}, so ${what} ` +\n `cannot be read.`,\n );\n }\n const row = result.rows[0];\n if (!row) {\n // Unreachable through the public API: a handle only exists behind an\n // `expectOne`, and the server rolls back rather than answering 200 with a\n // guard unmet. Loud, because the alternative is `undefined` in tenant data.\n throw new TxPlanError(\n `the transaction's operation ${opIndex} returned no row, so ${what} cannot ` +\n `be read.`,\n );\n }\n return row;\n}\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n if (typeof value !== \"object\" || value === null) return false;\n const proto: unknown = Object.getPrototypeOf(value);\n return proto === Object.prototype || proto === null;\n}\n\n// ---------------------------------------------------------------------------\n// Runtime — the driver\n// ---------------------------------------------------------------------------\n\n/** What {@link runTxPlan} needs from the runtime: one call, one transaction. */\nexport interface TxPlanTransport {\n txPlan(plan: TxPlanBody): Promise<TxPlanResponse>;\n}\n\n/**\n * Build the plan, send it, and resolve the callback's return value.\n *\n * A callback that throws never reaches the network: there is nothing to roll\n * back because nothing was sent. A callback that describes no writes also skips\n * the round trip entirely.\n *\n * The RETURN type is `unknown` here on purpose. `Materialized<T>` is a compile-\n * time rewrite of the callback's return type, and it belongs on the public\n * `transaction()` signatures where `T` is inferred from the author's callback;\n * threading it through this driver as well would mean inferring `T` twice, from\n * two different positions, and reconciling them. The public wrappers narrow\n * once, at the seam where the value types were erased anyway.\n */\nexport async function runTxPlan<TTables>(\n transport: TxPlanTransport,\n tables: TTables,\n builder: TxPlanBuilder,\n fn: (tx: TxPlanHandle<TTables>) => unknown,\n): Promise<unknown> {\n const returned = fn({ tables });\n const body = builder.body();\n if (body.ops.length === 0) {\n return materializeResult(returned, []);\n }\n\n let response: TxPlanResponse;\n try {\n response = await transport.txPlan(body);\n } catch (err) {\n throw translateRejection(err, builder);\n }\n return materializeResult(returned, response.results);\n}\n\n/**\n * Turn the broker's rejection back into the tenant's own error.\n *\n * The server never sees the `Error` an expectation was given — only its slot\n * index — so this is the only place the intended error can be produced. A\n * rejection this SDK does not recognise passes through untouched: inventing an\n * error for it would hide the real failure.\n */\nfunction translateRejection(err: unknown, builder: TxPlanBuilder): unknown {\n if (typeof err !== \"object\" || err === null) return err;\n const rejection = err as TxPlanRejection;\n if (rejection.error_code !== \"tx_guard_failed\" || typeof rejection.slot !== \"number\") {\n return err;\n }\n return builder.errorForSlot(rejection.slot) ?? err;\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/**\n * 400 — the request was malformed or failed validation. Carries a fixed typed\n * payload: `new BadRequest({ fields: [{ field: \"email\", message: \"invalid\" }] })`.\n * The shape is declared once in the SDK so codegen surfaces `error.data.fields`\n * typed on the client.\n */\nexport class BadRequest extends NamedHttpError {\n public declare readonly data: BadRequestData;\n constructor(data: BadRequestData, message?: string) {\n super(400, \"bad_request\", \"BadRequest\", message, undefined, 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/** A single field-level validation failure carried by {@link BadRequest}. */\nexport interface FieldError {\n /** The offending field's name (dotted path for nested fields). */\n field: string;\n /** Human-readable reason the field failed. */\n message: string;\n}\n\n/** The fixed, typed payload {@link BadRequest} ships. */\nexport interface BadRequestData {\n /** The fields that failed validation. */\n fields: FieldError[];\n}\n\n/** The fixed, typed payload {@link TooManyRequests} ships. */\nexport interface TooManyRequestsData {\n /** Seconds the caller should wait before retrying. */\n retryAfter: number;\n}\n\n/**\n * 429 — the caller has exceeded the rate limit. Carries a fixed typed payload:\n * `new TooManyRequests({ retryAfter: 30 })`. The shape is declared once in the\n * SDK (error-registry pre-seed) so codegen surfaces `error.data.retryAfter`\n * typed on the client — no per-project definition needed.\n */\nexport class TooManyRequests extends NamedHttpError {\n public declare readonly data: TooManyRequestsData;\n constructor(data: TooManyRequestsData, message?: string) {\n super(429, \"too_many_requests\", \"TooManyRequests\", message, undefined, data);\n }\n}\n","/**\n * Map palstore's thrown errors onto palbase's wire envelope.\n *\n * This mapping is REQUIRED, not cosmetic: the runtime only serializes a throw\n * that carries `{ status: number, error: string }` (worker.js's HttpError\n * catch). A palstore error carries `{ status, code }` — no `error` — so an\n * unmapped `QuotaExceededError` would leave the handler as a 500 and the client\n * would see \"internal error\" for a perfectly ordinary exhausted quota.\n *\n * The detection is STRUCTURAL (`code` + `status`) rather than `instanceof`,\n * because `@palbase/backend` deliberately has no dependency on\n * `@palstore/purchases` — see purchases/service.ts for why.\n */\n\nimport { HttpError, PalError } from \"../errors.js\";\n\n/** The shape every `PalstoreError` subclass presents: a stable snake_case wire\n * code plus the HTTP status it stands for. */\ninterface PalstoreErrorLike {\n code: string;\n status: number;\n message: string;\n}\n\nfunction asPalstoreError(err: unknown): PalstoreErrorLike | null {\n if (!(err instanceof Error)) return null;\n const e = err as Error & { code?: unknown; status?: unknown };\n if (typeof e.code !== \"string\" || typeof e.status !== \"number\") return null;\n return { code: e.code, status: e.status, message: e.message };\n}\n\n/**\n * Translate a purchases failure into an `HttpError`, or return the error\n * untouched when it is not one.\n *\n * Anything unrecognised is rethrown VERBATIM — a transport failure, a bug, a\n * 500 from palstore — because turning an unknown fault into a tidy 403/429\n * would tell the client \"you lack access\" when the truth is \"we are broken\",\n * and would hide the outage from whoever is on call.\n */\nexport function toHttpError(err: unknown): unknown {\n // Already a palbase error (e.g. the 401 from subject resolution): leave it.\n if (err instanceof HttpError) return err;\n\n const p = asPalstoreError(err);\n if (!p) return err;\n\n switch (p.code) {\n case \"entitlement_required\": {\n const entitlement = (err as { entitlement?: unknown }).entitlement ?? null;\n return new PalError(403, \"entitlement_required\", p.message, { entitlement });\n }\n case \"quota_exceeded\":\n case \"credit_insufficient\": {\n // The LimitState/CreditState rides on `data` so a client can render the\n // real ceiling and reset time instead of guessing a retry delay. This is\n // why the 429 is NOT palbase's `TooManyRequests`: that class fixes its\n // payload to `{ retryAfter }`, which is rate-limiting's shape, not a\n // quota's — and squeezing a LimitState through it would drop `max`,\n // `used` and `remaining`, the three fields a paywall needs.\n const state = (err as { state?: unknown }).state;\n return new PalError(429, p.code, p.message, state);\n }\n default:\n return err;\n }\n}\n\n/** Run `fn`, translating any purchases failure on the way out. */\nexport async function mappingPurchaseErrors<T>(fn: () => Promise<T>): Promise<T> {\n try {\n return await fn();\n } catch (err) {\n throw toHttpError(err);\n }\n}\n","/**\n * Per-method purchases metadata, stored on the controller class the same way\n * `decorators/registry.ts` stores routes: a symbol-keyed static, plain data, no\n * `reflect-metadata`.\n *\n * Its only consumer is the OpenAPI step, which needs to know that a route is\n * gated (declare 403) or metered (declare 429) so the iOS client codegen emits\n * TYPED errors instead of a bare status number. Enforcement does NOT read this\n * — the decorators wrap the method directly — so a stale registry can never\n * cause a missed gate.\n */\n\nimport type { EntitlementKey, LimitKey } from \"./keys.js\";\n\nconst ENTITLEMENTS: unique symbol = Symbol.for(\"palbase.backend.purchases.entitlements\");\nconst SPENDS: unique symbol = Symbol.for(\"palbase.backend.purchases.spends\");\n\n/** What `@Spend` recorded for one method. */\nexport interface SpendMeta {\n key: LimitKey;\n count: number;\n}\n\ninterface PurchasesCarrier {\n [ENTITLEMENTS]?: Record<string, EntitlementKey>;\n [SPENDS]?: Record<string, SpendMeta>;\n}\n\n/** Resolve a decorated target (prototype or constructor) to the constructor\n * that owns the metadata, mirroring `carrierOf` in decorators/registry.ts. */\nfunction carrierOf(target: object): PurchasesCarrier {\n return (\n typeof target === \"function\"\n ? (target as unknown as PurchasesCarrier)\n : (((target as { constructor?: unknown }).constructor ?? target) as PurchasesCarrier)\n );\n}\n\n/** Own (not inherited) slot, so a subclass never mutates its base's metadata. */\nfunction own<K extends typeof ENTITLEMENTS | typeof SPENDS>(\n carrier: PurchasesCarrier,\n slot: K,\n): NonNullable<PurchasesCarrier[K]> {\n if (!Object.prototype.hasOwnProperty.call(carrier, slot)) {\n carrier[slot] = {} as never;\n }\n return carrier[slot] as NonNullable<PurchasesCarrier[K]>;\n}\n\nexport function recordEntitlement(target: object, fnName: string, key: EntitlementKey): void {\n own(carrierOf(target), ENTITLEMENTS)[fnName] = key;\n}\n\nexport function recordSpend(target: object, fnName: string, meta: SpendMeta): void {\n own(carrierOf(target), SPENDS)[fnName] = meta;\n}\n\n/** The entitlement `fnName` is gated on, or undefined when it is not gated. */\nexport function entitlementFor(ctor: object, fnName: string): EntitlementKey | undefined {\n return carrierOf(ctor)[ENTITLEMENTS]?.[fnName];\n}\n\n/** What `fnName` spends, or undefined when it spends nothing. */\nexport function spendFor(ctor: object, fnName: string): SpendMeta | undefined {\n return carrierOf(ctor)[SPENDS]?.[fnName];\n}\n","/**\n * subject.ts — the ONLY place a purchases subject is resolved.\n *\n * The subject is derived from the SERVER-OWNED authenticated user on the\n * request context. It is never a decorator argument, never a body field, never\n * a header. A caller who could name their own subject could read someone\n * else's entitlements or spend someone else's quota, so the surface simply\n * offers no way to say it — `currentSubjectId()` takes no parameters.\n */\n\nimport { Purchases, __requestALS, type RequestStore } from \"../runtime.js\";\nimport { Unauthorized } from \"../errors.js\";\nimport type { StoreEnv } from \"./service.js\";\n\n/**\n * Per-request memo, keyed on the ALS box (one object per request, collected\n * with it). Both decorators on one route need the subject; resolving it twice\n * would double the round-trip to palstore for no gain. Kept here rather than as\n * a field on `RequestStore` so the core request type stays free of purchases\n * concerns.\n *\n * The PROMISE is memoized, not the resolved value, so two decorators that race\n * (or any concurrent caller) share one in-flight resolution instead of firing\n * two and keeping the loser.\n */\nconst subjectByRequest = new WeakMap<RequestStore, Promise<string>>();\n\n/**\n * The store environment subjects resolve against. Sandbox purchases are\n * isolated from production ones all the way down the palstore schema, so this\n * is a DEPLOYMENT fact, not a per-request one — a request cannot select it.\n * Defaults to production: a project that forgets to set it gets the strict\n * environment, never a sandbox subject that would accept test purchases.\n */\nfunction storeEnv(): StoreEnv {\n return process.env.PALSTORE_STORE_ENV === \"sandbox\" ? \"sandbox\" : \"production\";\n}\n\n/**\n * Resolve the palstore subject for the request in scope.\n *\n * Throws 401 when the request carries no authenticated user — and does so\n * BEFORE any call to palstore, so an anonymous request never mints a subject.\n */\nexport async function currentSubjectId(): Promise<string> {\n // Async, so every failure is a rejection — a Promise-returning function that\n // sometimes throws synchronously is a footgun for `.catch()`-only callers.\n // The body runs to the memo write before its first await, so two concurrent\n // callers still share one resolution.\n const store = __requestALS.getStore();\n if (!store) {\n throw new Error(\n \"Purchases decorators used outside a request scope. @RequireEntitlement/@Spend \" +\n \"resolve the subject from the request's authenticated user, so they only work \" +\n \"inside an endpoint handler.\",\n );\n }\n\n const memoized = subjectByRequest.get(store);\n if (memoized) return memoized;\n\n const userId = store.userId;\n if (!userId) {\n throw new Unauthorized(\n \"This endpoint requires an authenticated user: purchases entitlements and quota \" +\n \"are per-user, and the subject is resolved from the request's identity.\",\n );\n }\n\n const resolving = Purchases.resolveSubject({ userRef: userId, storeEnv: storeEnv() }).then(\n (r) => r.subjectId,\n );\n // ponytail: a failed resolution is NOT memoized — cache the promise, then drop\n // it on rejection so the next request-scoped caller retries instead of\n // inheriting a permanently poisoned subject for the life of the request.\n subjectByRequest.set(store, resolving);\n resolving.catch(() => subjectByRequest.delete(store));\n return resolving;\n}\n","/**\n * `@RequireEntitlement` and `@Spend` — access and metering at the decorator\n * level, so a controller method says what it costs instead of wiring it.\n *\n * TWO decorators, deliberately, because not every subscription is limit-based.\n * Most products just say \"pro users may call this\" and consume nothing; a\n * zero-count spend would express that badly and run the whole reserve/commit\n * machine for no reason.\n *\n * @RequireEntitlement('pro') pure gate → 403, consumes nothing\n * @Spend('bookCreate') consumption → 429 when exhausted\n *\n * ORDER IS FIXED, and not by where you wrote them. Both decorators record\n * metadata and share ONE installed wrapper that always runs the entitlement\n * gate before it reserves quota. Reserving for someone who is about to get a\n * 403 is wasted work and a race window, so the source order of the two\n * decorators cannot introduce it.\n */\n\nimport { Purchases, __requestALS } from \"../runtime.js\";\nimport { toHttpError } from \"./errors.js\";\nimport type { EntitlementKey, LimitKey } from \"./keys.js\";\nimport { entitlementFor, recordEntitlement, recordSpend, spendFor } from \"./registry.js\";\nimport { currentSubjectId } from \"./subject.js\";\n\n/** Marks a method whose purchases wrapper is already installed, so applying\n * both decorators wraps once rather than nesting two half-pipelines. */\nconst WRAPPED: unique symbol = Symbol.for(\"palbase.backend.purchases.wrapped\");\n\ntype Wrapped = ((...args: unknown[]) => unknown) & { [WRAPPED]?: true };\n\ntype MethodDecorator = (\n target: object,\n propertyKey: string | symbol,\n descriptor: PropertyDescriptor,\n) => void;\n\n/**\n * The idempotency key for this request's spend.\n *\n * palstore requires one (§9 scopes idempotency by `(project_ref, subject_id,\n * operation, idempotency_key)`) and refuses a call without it rather than\n * running it non-idempotently. The caller's `Idempotency-Key` header is the\n * honest source — it is what makes a client's RETRY replay the first result\n * instead of charging twice. With no header we fall back to the request id,\n * which still satisfies the server and still makes the two decorators on one\n * request share a scope, but cannot deduplicate across a retry the client\n * never labelled.\n *\n * Suffixed with the limit key so two different `@Spend`s reached in one request\n * are separate operations rather than a self-collision.\n */\nfunction idempotencyKeyFor(key: LimitKey): string {\n const store = __requestALS.getStore();\n const base = store?.idempotencyKey || store?.requestId;\n if (!base) {\n throw new Error(\n \"@Spend needs a request-scoped idempotency key, and the runtime supplied neither an \" +\n \"Idempotency-Key header nor a request id. Spending without one would let a retried \" +\n \"request charge the user twice.\",\n );\n }\n return `${base}:${key}`;\n}\n\n/**\n * Install the single purchases wrapper on a method, if it is not there yet.\n *\n * The wrapper reads the registry at CALL time, so whichever decorator happens\n * to be applied first still yields the same fixed pipeline.\n */\nfunction ensureWrapper(target: object, fnName: string, descriptor: PropertyDescriptor): void {\n const original = descriptor.value as Wrapped | undefined;\n if (typeof original !== \"function\") {\n throw new Error(\n `@RequireEntitlement/@Spend can only decorate a method; \"${fnName}\" is not one.`,\n );\n }\n if (original[WRAPPED]) return;\n\n const wrapper = async function (this: unknown, ...args: unknown[]): Promise<unknown> {\n const ctor = (this as { constructor: object }).constructor;\n const entitlement = entitlementFor(ctor, fnName);\n const spend = spendFor(ctor, fnName);\n\n // One resolution per request, shared by both decorators (subject.ts memoizes).\n let subjectId: string;\n try {\n subjectId = await currentSubjectId();\n } catch (err) {\n throw toHttpError(err);\n }\n\n // GATE FIRST — always, regardless of decoration order.\n if (entitlement !== undefined) {\n try {\n await Purchases.require(subjectId, entitlement);\n } catch (err) {\n throw toHttpError(err);\n }\n }\n\n if (spend === undefined) {\n return original.apply(this, args);\n }\n\n // `withSpend` reserves, runs, then commits on success / cancels on throw,\n // always rethrowing the handler's own error. We track that error by\n // identity so the mapping below never reshapes a tenant's exception into a\n // purchases one on its way out.\n let handlerFailure: { err: unknown } | undefined;\n try {\n return await Purchases.withSpend(\n subjectId,\n spend.key,\n { count: spend.count, idempotencyKey: idempotencyKeyFor(spend.key) },\n async () => {\n try {\n return await original.apply(this, args);\n } catch (err) {\n handlerFailure = { err };\n throw err;\n }\n },\n );\n } catch (err) {\n if (handlerFailure !== undefined && handlerFailure.err === err) throw err;\n throw toHttpError(err);\n }\n } as Wrapped;\n\n wrapper[WRAPPED] = true;\n descriptor.value = wrapper;\n}\n\n/**\n * Require an active entitlement. Answers 403 `entitlement_required` when it is\n * absent and consumes nothing.\n *\n * The key is a member of the generated `EntitlementKey` union, so a typo is a\n * compile error rather than a gate that silently never matches.\n */\nexport function RequireEntitlement(key: EntitlementKey): MethodDecorator {\n return function (target, propertyKey, descriptor) {\n const fnName = String(propertyKey);\n recordEntitlement(target, fnName, key);\n ensureWrapper(target, fnName, descriptor);\n };\n}\n\n/**\n * Consume one unit of a limit or credit for the request's subject.\n *\n * Reserves before the handler runs and commits only if it returns; a throw\n * cancels the hold, so a user is never charged for work that did not complete.\n * Answers 429 `quota_exceeded` (carrying the `LimitState`) when exhausted.\n *\n * The count is fixed at 1. A DYNAMIC amount is deliberately not expressible\n * here: it has to be decided inside the handler and spent BEFORE the billable\n * side-effect, which is an explicit `Purchases.withSpend(...)` call, not a\n * decorator.\n */\nexport function Spend(key: LimitKey): MethodDecorator {\n return function (target, propertyKey, descriptor) {\n const fnName = String(propertyKey);\n recordSpend(target, fnName, { key, count: 1 });\n ensureWrapper(target, fnName, descriptor);\n };\n}\n","/**\n * keys-gen.ts — generate the `palbase-purchases.d.ts` text from a catalog\n * manifest.\n *\n * The twin of `db/env-gen.ts`: the CLI / deploy pipeline calls\n * {@link makePurchasesDts} with the project's catalog revision and writes the\n * result to `palbase-purchases.d.ts` at the project root. That file augments\n * the `@palbase/backend/purchases` `Entitlements` / `Limits` interfaces, so\n * `@RequireEntitlement(...)` and `@Spend(...)` accept the project's real keys\n * and nothing else.\n *\n * Same catalog, two languages: this is the TypeScript half of what swiftgen\n * already emits for iOS. Neither side is hand-maintained, so the two cannot\n * drift from each other or from the manifest the server validated.\n *\n * The emitted file ends in `export {};` — same as `makeEnvDts`. Without it the\n * `.d.ts` is a global script, and `declare module \"…\"` there DECLARES an\n * ambient module (shadowing the real one, so every key silently becomes\n * invalid) instead of AUGMENTING it.\n */\n\n/** A catalog entry that may be tombstoned. */\ninterface Removable {\n removed?: boolean;\n}\n\n/**\n * The slice of `pur_catalogs.manifest` this generator reads. Deliberately\n * partial and permissive: the server already validated the manifest (its models\n * are `extra=\"forbid\"`), so re-checking here would be a second, weaker copy of\n * that authority.\n */\nexport interface PurchasesManifest {\n limits?: Record<string, Removable>;\n credits?: Record<string, Removable>;\n entitlements?: Record<string, Removable>;\n}\n\n/** Live keys, sorted, with tombstones dropped.\n *\n * `removed: true` is the catalog's tombstone: the key still exists so historical\n * receipts resolve, but it must NOT be offered to new code. Emitting it would\n * let a handler compile against a limit the project has retired. */\nfunction liveKeys(entries: Record<string, Removable> | undefined): string[] {\n return Object.entries(entries ?? {})\n .filter(([, def]) => def?.removed !== true)\n .map(([key]) => key)\n .sort();\n}\n\n/** A bare identifier stays bare; anything else is quoted. */\nfunction memberName(key: string): string {\n return /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(key) ? key : JSON.stringify(key);\n}\n\nfunction members(keys: string[]): string {\n if (keys.length === 0) return \"\";\n return `\\n${keys.map((k) => ` ${memberName(k)}: true;`).join(\"\\n\")}\\n `;\n}\n\n/**\n * Render the project's `palbase-purchases.d.ts`.\n *\n * `Limits` carries BOTH limits and credits: `@Spend` consumes either, and the\n * server answers both with a 429 (`quota_exceeded` / `credit_insufficient`), so\n * splitting them into two unions would make the author pick the right decorator\n * for a distinction the spend path does not make.\n */\nexport function makePurchasesDts(manifest: PurchasesManifest): string {\n const entitlements = liveKeys(manifest.entitlements);\n const limits = liveKeys({ ...manifest.limits, ...manifest.credits });\n\n return `// palbase-purchases.d.ts — GENERATED by @palbase/backend. Do not edit.\n// Source: the project's palstore catalog revision.\n\ndeclare module \"@palbase/backend/purchases\" {\n interface Entitlements {${members(entitlements)}}\n\n interface Limits {${members(limits)}}\n}\n\nexport {};\n`;\n}\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\";\nimport type { RawConstraintDef } from \"./raw.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. **Defaults to\n * `true`**, and is forced on when `policies` is non-empty. A table with RLS\n * and no policies is deny-all, which is the starting state: nothing reads it\n * until a policy says who may. Set `rls: false` only for a genuinely public\n * table — it is an explicit opt-out that a reviewer can grep for, not\n * something you get by forgetting.\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 /** Composite/named primary key (ordered column names). Omit for single-column inline .primaryKey(). */\n primaryKey?: string[];\n /** Named multi-column UNIQUE constraints. */\n unique?: { name: string; columns: string[] }[];\n /** Named raw-SQL DDL objects (EXCLUDE, triggers, views) that the typed DSL cannot express. */\n raw?: RawConstraintDef[];\n /**\n * Named first-class CHECK constraints. Diffed by NAME with a BODY compare:\n * a changed `expr` (after pg normalization) recreates the constraint\n * (DROP + ADD). `expr` is trusted SQL emitted verbatim (like policy USING),\n * `name` is identifier-validated.\n */\n checks?: { name: string; expr: string }[];\n /**\n * Plain (non-unique) btree indexes over an ordered column list, emitted as\n * standalone `CREATE INDEX [IF NOT EXISTS] name ON table (col1, col2)`\n * statements (NOT a table clause — a separate migration statement category).\n * Structural compare by NAME (no expression normalization). `name` and each\n * column are identifier-validated by the Go differ.\n *\n * Scope: columns-only plain btree. Partial (`where`) and expression indexes\n * are a deliberate follow-up — modelling them needs the same raw-SQL\n * normalization round-trip CHECK uses (Task 10), so they are NOT in this\n * type yet to avoid a half-working partial-index path.\n */\n indexes?: { name: string; columns: string[] }[];\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 `true`/`[]`).\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 primaryKey?: string[];\n unique?: { name: string; columns: string[] }[];\n /** Named raw-SQL DDL objects emitted verbatim on deploy. Tracked by name. */\n raw?: RawConstraintDef[];\n /** Named first-class CHECK constraints. Diffed by name + (normalized) body. */\n checks?: { name: string; expr: string }[];\n /** Plain btree indexes (columns-only), emitted as standalone CREATE INDEX. Diffed by name. */\n indexes?: { name: string; columns: string[] }[];\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 **`true`**, `policies` to `[]`. A table\n * that declares neither is therefore deny-all — nothing reads it until a policy\n * says who may, which is the safe starting point rather than a bug. Declare\n * `rls: false` for a genuinely public table; that is an explicit, greppable\n * statement of intent instead of an omission. When `policies` is non-empty,\n * `rls` is forced on (ENABLE + FORCE) regardless of the declared flag — a table\n * with policies must have RLS enabled or the 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 // Fail closed. RLS is on unless the schema explicitly says `rls: false`, and\n // policies force it on regardless — a policy on a table without RLS enabled\n // is inert, so declaring both is a contradiction that resolves towards the\n // safe reading.\n //\n // This defaulted to `false` until 2026-08-07, which meant a table nobody\n // thought about had no row-level security while `typed-db.ts` documented the\n // default `Database.*` path as RLS-enforced. Both cannot be true, and the\n // live proof settled which one was not: user B read user A's row in full\n // through the typed client, while the same request against a table declaring\n // `rls: true` returned 0 of 165 rows\n // (docs/superpowers/uat/2026-08-07-rls-fail-open-proof.md). With no policies\n // this is deny-all, so an unconsidered table now returns nothing instead of\n // returning everything to everyone.\n const rls = policies.length > 0 || table.rls !== false;\n const tableDef: TableDef<T[typeof name][\"columns\"]> = {\n name: name as string,\n columns: table.columns,\n rls,\n policies,\n };\n if (table.primaryKey !== undefined) tableDef.primaryKey = table.primaryKey;\n if (table.unique !== undefined) tableDef.unique = table.unique;\n if (table.raw !== undefined && table.raw.length > 0) tableDef.raw = table.raw.slice();\n if (table.checks !== undefined && table.checks.length > 0) tableDef.checks = table.checks.slice();\n if (table.indexes !== undefined && table.indexes.length > 0) tableDef.indexes = table.indexes.slice();\n tables[name] = tableDef;\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 // Indexing & constraints\n \"btree_gist\", // GiST operator classes for scalar types — needed for EXCLUDE\n // constraints that mix \"=\" with a range/&& overlap (e.g. no-double-booking).\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/**\n * The ON DELETE actions permitted on a foreign key to the built-in auth users\n * (`auth.users`). Both let a user's rows be removed (`cascade`) or detached\n * (`set null`) when the account is erased; `restrict` / `no action` would BLOCK\n * erasure and are therefore excluded. This is the CLIENT-SIDE mirror of the\n * server's auth-FK deletion policy — the server (validateAuthUserFK) is the real\n * boundary, this narrows the type so the common mistake is caught at compile time.\n */\nexport type AuthUserOnDelete = Extract<OnDeleteAction, 'cascade' | 'set null'>;\n\n/** Column type identifiers. */\nexport type ColumnType =\n | 'uuid'\n | 'text'\n | 'integer'\n | 'bigint'\n | 'numeric'\n | 'boolean'\n | 'timestamp'\n | 'jsonb'\n | '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 /**\n * The name this column used to have. A diff cannot tell a rename from a drop and\n * an add — both leave one name gone and another present — so the intent has to be\n * declared. Without it, renaming a column loses its data.\n */\n renamedFrom?: string;\n onDeleteAction?: OnDeleteAction;\n enumName?: string;\n enumValues?: string[];\n unique?: boolean;\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;\ndeclare const __colPayload: 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 * P — jsonb payload shape (unknown unless jsonb<T>() supplied one)\n *\n * All five params have defaults so bare `ColumnBuilder` (no args) still\n * satisfies `Record<string, ColumnBuilder>` in schema.ts without modification.\n *\n * The five `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 P = 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 declare readonly [__colPayload]: P;\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, P> {\n this._def.primaryKey = true;\n return new ColumnBuilder<K, N, D, E, P>(this._def.type as K, this._def);\n }\n\n /** Mark this column as NOT NULL (default). */\n notNull(): ColumnBuilder<K, false, D, E, P> {\n this._def.nullable = false;\n return new ColumnBuilder<K, false, D, E, P>(this._def.type as K, this._def);\n }\n\n /** Allow NULL values. */\n nullable(): ColumnBuilder<K, true, D, E, P> {\n this._def.nullable = true;\n return new ColumnBuilder<K, true, D, E, P>(this._def.type as K, this._def);\n }\n\n /** Set a default value. */\n default(value: unknown): ColumnBuilder<K, N, true, E, P> {\n this._def.defaultValue = value;\n return new ColumnBuilder<K, N, true, E, P>(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, P> {\n this._def.defaultRandom = true;\n return new ColumnBuilder<K, N, true, E, P>(this._def.type as K, this._def);\n }\n\n /** Timestamp: default to now(). */\n defaultNow(): ColumnBuilder<K, N, true, E, P> {\n this._def.defaultNow = true;\n return new ColumnBuilder<K, N, true, E, P>(this._def.type as K, this._def);\n }\n\n /** Add a foreign key reference. */\n /**\n * Declares that this column used to be called `previous`.\n *\n * A schema diff sees one name gone and another present; it cannot know whether\n * you renamed a column or dropped one and added another, and the two are very\n * different — the second loses every value. Saying so here turns the plan into\n * `ALTER TABLE … RENAME COLUMN` instead.\n *\n * Once the rename has been applied the annotation is inert (the old name is no\n * longer there to rename), so it can be deleted at your leisure.\n */\n renamedFrom(previous: string): ColumnBuilder<K, N, D, E, P> {\n this._def.renamedFrom = previous;\n return this as unknown as ColumnBuilder<K, N, D, E, P>;\n }\n\n references(table: string, column: string): ColumnBuilder<K, N, D, E, P> {\n this._def.references = { table, column };\n return new ColumnBuilder<K, N, D, E, P>(this._def.type as K, this._def);\n }\n\n /**\n * Add a real DB-level foreign key to the built-in auth users\n * (`REFERENCES auth.users(id)`), so a column like `user_id` gets true\n * database cascade/integrity instead of app-layer-only. Sugar for\n * `.references(\"auth.users\", \"id\")`.\n *\n * `auth.users` lives in the SAME tenant database (palauth-owned), so this is\n * a genuine cross-schema integrity constraint scoped to THIS tenant's users.\n * The referenced `auth.users.id` is `text` (palauth ids are `usr_<uuid>`), so\n * the referencing column must be `text()` too.\n *\n * ON DELETE is REQUIRED here and may only be `cascade` or `set null`: an\n * account-erasure request must never be blocked by a lingering FK, so\n * `restrict` / `no action` are not accepted (they don't type-check). Example:\n * `text().notNull().referencesAuthUser(\"cascade\")`, or\n * `text().nullable().referencesAuthUser(\"set null\")`. The server\n * (validateAuthUserFK) enforces this — and the remaining rules the type can't\n * express (referencing column is text, `set null` needs a nullable column) —\n * as the real boundary; this signature is the compile-time DX mirror.\n */\n referencesAuthUser(onDelete: AuthUserOnDelete): ColumnBuilder<K, N, D, E, P> {\n this._def.references = { table: 'auth.users', column: 'id' };\n this._def.onDeleteAction = onDelete;\n return new ColumnBuilder<K, N, D, E, P>(this._def.type as K, this._def);\n }\n\n /**\n * Add a real DB-level foreign key to the canonical, server-minted installation\n * anchor (`REFERENCES auth.installations(id)`) — the app-scoped verified-device\n * root (`ins_...`). Sugar for `.references(\"auth.installations\", \"id\")`.\n *\n * An installation is an APP INSTALL, not a user: this FK is NOT user ownership.\n * A user-owned row STILL needs its own `.referencesAuthUser(...)` FK so account\n * erasure removes it — an installation reference alone does not tie a row to a\n * user's deletion. Use this only for install-scoped state (device prefs, push\n * routing, …), alongside a separate auth-user FK where the row is user-owned.\n *\n * `auth.installations` lives in the SAME tenant DB (palauth-owned); its `id` is\n * `text` (`ins_<uuid>`), so the referencing column must be `text()` too. ON\n * DELETE is REQUIRED and may only be `cascade` or `set null` (same allowed set\n * as an auth-user FK): an installation revoke / orphan cleanup must never be\n * blocked by a lingering FK. The server (validateAuthAnchorFK) is the real\n * boundary; this signature is the compile-time DX mirror.\n */\n referencesInstallation(onDelete: AuthUserOnDelete): ColumnBuilder<K, N, D, E, P> {\n this._def.references = { table: 'auth.installations', column: 'id' };\n this._def.onDeleteAction = onDelete;\n return new ColumnBuilder<K, N, D, E, P>(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, P> {\n this._def.onDeleteAction = action;\n return new ColumnBuilder<K, N, D, E, P>(this._def.type as K, this._def);\n }\n\n /** Add a single-column UNIQUE constraint. */\n unique(): ColumnBuilder<K, N, D, E, P> {\n this._def.unique = true;\n return new ColumnBuilder<K, N, D, E, P>(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\" | \"bigint\" | \"numeric\" → string (or string | null when N = true)\n * Note: bigint/numeric surface as string — JS number loses precision past 2^53,\n * and pgx/PostgREST serialize int8/numeric as strings. App code uses\n * BigInt(row.amount) for bigint, or a decimal lib for numeric.\n * - \"integer\" → number\n * - \"boolean\" → boolean\n * - \"jsonb\" → P (the dev-supplied payload shape from jsonb<T>(), else unknown)\n * - \"enum\" → E (the union of literal values)\n */\nexport type ColValue<C> =\n C extends ColumnBuilder<'uuid' | 'text' | 'timestamp' | 'bigint' | 'numeric', infer N, infer _D, infer _E, infer _P>\n ? N extends true\n ? string | null\n : string\n : C extends ColumnBuilder<'integer', infer N, infer _D, infer _E, infer _P>\n ? N extends true\n ? number | null\n : number\n : C extends ColumnBuilder<'boolean', infer N, infer _D, infer _E, infer _P>\n ? N extends true\n ? boolean | null\n : boolean\n : C extends ColumnBuilder<'jsonb', infer N, infer _D, infer _E, infer P>\n ? N extends true\n ? P | null\n : P\n : C extends ColumnBuilder<'enum', infer N, infer _D, infer E, infer _P>\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. Emits int4 (max ~2.1B). */\nexport function integer(): ColumnBuilder<'integer', false, false, never> {\n return new ColumnBuilder('integer');\n}\n\n/**\n * Create a BIGINT column (Postgres int8, max ~9.2×10^18).\n * Surfaces as `string` in row/insert types — JS number loses precision past 2^53\n * and pgx/PostgREST serialize int8 as a JSON string. Use BigInt(row.column) in app code.\n */\nexport function bigint(): ColumnBuilder<'bigint', false, false, never> {\n return new ColumnBuilder('bigint');\n}\n\n/**\n * Create a NUMERIC column (Postgres `numeric`/`decimal`, arbitrary precision).\n * For exact fractional values (money with cents as a decimal, rates, weights)\n * where int4/int8 don't fit. Surfaces as `string` in row/insert types — JS\n * number can't hold arbitrary-precision decimals without rounding, and\n * pgx/PostgREST serialize numeric as a JSON string. Parse with a decimal lib\n * (or BigInt for scaled integers) in app code.\n */\nexport function numeric(): ColumnBuilder<'numeric', false, false, never> {\n return new ColumnBuilder('numeric');\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/**\n * Create a JSONB column. Pass a payload type to make the generated row/insert\n * type concrete instead of `unknown`:\n *\n * tags: jsonb<string[]>() // row.tags: string[]\n * meta: jsonb<{ tier: string }>() // row.meta: { tier: string }\n * raw: jsonb() // row.raw: unknown (back-compat)\n *\n * The runtime accepts a plain JS object/array directly (no JSON.stringify); the\n * generic only refines the TYPE the env codegen emits.\n */\nexport function jsonb<T = unknown>(): ColumnBuilder<'jsonb', false, false, never, T> {\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 * A named raw-SQL DDL object declared in db/schema.ts for anything the typed DSL\n * cannot express (EXCLUDE, CHECK, partial/expression indexes, triggers, views).\n * The deploy emits `up` verbatim on the privileged DDL connection — same trust\n * posture as policy().using(). Tracked by NAME (not by diffing the body), so a\n * changed body needs a new name or an explicit drop+add.\n */\nexport interface RawConstraintDef {\n name: string;\n up: string;\n down?: string;\n}\n\nexport function raw(name: string, up: string, opts?: { down?: string }): RawConstraintDef {\n return { name, up, ...(opts?.down != null ? { down: opts.down } : {}) };\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, DBOps } from \"../endpoint.js\";\nimport type { Materialized, TxPlanHandle, TxTable } from \"./tx-plan.js\";\nimport { TxPlanBuilder, runTxPlan } from \"./tx-plan.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 /** Run a transaction plan. See {@link EnvTypedDatabase.transaction}. */\n transaction<T>(\n fn: (tx: TypedTx<S>) => T extends Promise<unknown> ? never : T,\n ): Promise<Materialized<T>>;\n}\n\n/** The plan-building handle a `TypedDB<S>` transaction callback receives: the\n * schema's tables, expressed as plan operations rather than awaited calls. */\nexport type TypedTx<S extends SchemaDef> = TxPlanHandle<{\n [K in keyof S[\"tables\"]]: TxTable<RowShape<S[\"tables\"][K]>, InsertShape<S[\"tables\"][K]>>;\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 `DBOps` (the six string-keyed ops) because this only\n * ever calls those — never `txPlan`, which builds its own operations rather than\n * delegating to these.\n */\nfunction makeTypedTable<T extends TableDef<Record<string, ColumnBuilder>>>(\n name: string,\n raw: DBOps,\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 for the direct ops — all calls\n * delegate to `raw` with the table name as a plain string.\n *\n * `transaction` does NOT delegate to a per-op client: the callback describes a\n * plan against a fresh {@link TxPlanBuilder}, and the whole plan travels in one\n * `raw.txPlan` call. The schema is used only for its table NAMES; the values\n * are typed by `S` at compile time and are plain strings at run time.\n *\n * The `as` casts are single structural narrowings from a dynamically-built\n * object to the precise mapped type (TS cannot infer the mapped-type result\n * through `Object.keys` iteration) — see the module-level doc comment.\n */\nexport function makeTypedDB<S extends SchemaDef>(\n schema: S,\n raw: DBClient,\n): TypedDB<S> {\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, raw);\n }\n }\n\n const result = {\n tables,\n transaction<T>(\n fn: (tx: TypedTx<S>) => T extends Promise<unknown> ? never : T,\n ): Promise<Materialized<T>> {\n const builder = new TxPlanBuilder();\n const planTables: Record<string, unknown> = {};\n for (const key of Object.keys(schema.tables)) {\n const tableDef = schema.tables[key];\n if (tableDef !== undefined) planTables[key] = builder.table(tableDef.name);\n }\n // Two narrowings at the same seam: the plan tables are built by NAME, so\n // TS cannot see the mapped type through the loop, and the driver erases\n // the callback's return type (see runTxPlan's doc). Both are the erasure\n // this facade exists to undo.\n return runTxPlan(\n raw,\n planTables as TypedTx<S>[\"tables\"],\n builder,\n fn,\n ) as Promise<Materialized<T>>;\n },\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/** The project's tables as PLAN operations, keyed by the env `Tables`\n * interface. The transaction twin of {@link EnvTables}. */\nexport type TxTables = {\n [K in keyof Tables]: TxTable<Tables[K][\"row\"], Tables[K][\"insert\"]>;\n};\n\n/**\n * The handle a `Database.transaction(…)` callback receives.\n *\n * Tables only — no `query`, no `findById`, no `asService`. A read whose value\n * the plan does not write belongs outside the transaction, where it costs one\n * round trip and is an ordinary value you can branch on.\n */\nexport type TxPlan = TxPlanHandle<TxTables>;\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, \"txPlan\" | \"asService\"> {\n tables: EnvTables;\n transaction<T>(fn: (tx: TxPlan) => T extends Promise<unknown> ? never : T): Promise<Materialized<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` that runs a whole plan in one request, and `asService()` for\n * the explicit RLS-bypass sibling.\n *\n * The low-level `txPlan` op is deliberately NOT re-exposed here: `transaction`\n * is the surface, and a hand-built plan would bypass the ref/guard machinery\n * that makes one safe to write.\n */\nexport interface EnvTypedDatabase extends Omit<DBClient, \"txPlan\" | \"asService\"> {\n tables: EnvTables;\n /**\n * Run a transaction. The callback DESCRIBES the operations; the whole\n * description travels in one request and the broker runs it inside a single\n * transaction — committing when it finishes, rolling back on any failure.\n *\n * The callback is SYNCHRONOUS: nothing has run when it returns, so there is\n * nothing to await. `async` on it and `await` inside it are compile errors.\n * Values a later operation needs are {@link Ref}s, written straight into the\n * next operation; values the CALLER needs are returned and substituted before\n * this promise resolves.\n *\n * @example\n * const { statementId } = await Database.transaction((tx) => {\n * const st = tx.tables.statements\n * .insert({ household_id: hid, file_sha256: sha, status: \"reviewing\" })\n * .expectOne(new Internal(\"statement insert failed\"));\n *\n * tx.tables.statement_lines.insertMany(\n * lines.map((l) => ({ statement_id: st.id, category: resolveCategory(l) })),\n * );\n *\n * return { statementId: st.id };\n * });\n */\n transaction<T>(fn: (tx: TxPlan) => T extends Promise<unknown> ? never : T): Promise<Materialized<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 db types` / 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 // Both are exact-precision in Postgres and lossy as a JSON number, so the\n // database proxy serializes them as strings — measured: 9007199254740993\n // used to arrive as ...992 and 41.00821234567890123 as 41.0082123456789.\n // numeric had no case at all and fell through to `unknown`, which typed\n // every numeric column out of existence.\n case \"bigint\":\n case \"numeric\":\n return \"string\";\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/** The table a foreign key must target for its column to be the OWNER column —\n * what `.referencesAuthUser(...)` writes into `ColumnDef.references.table`. */\nconst AUTH_USERS_TABLE = \"auth.users\";\n\n/**\n * The table's owner column: the one that foreign-keys `auth.users`, i.e. the\n * column a row is \"owned by\". Declared in `db/schema.ts` via\n * `.referencesAuthUser(...)` — we read the declaration rather than parsing the\n * RLS policy body, because the FK IS the ownership statement.\n *\n * When several columns reference `auth.users` (e.g. `user_id` and `created_by`)\n * the FIRST in declaration order wins — deterministic, and the remaining ones\n * stay ordinary writable columns.\n */\nfunction ownerColumnOf(table: TableDef): string | null {\n for (const [col, builder] of Object.entries(table.columns)) {\n if (builder._def.references?.table === AUTH_USERS_TABLE) return col;\n }\n return null;\n}\n\n/** One FK edge: `child.column` points at the parent table this edge hangs off. */\ntype ChildEdge = { child: string; column: string };\n\n/**\n * Collect the raw parent → children FK edges across the schema.\n *\n * Only edges between tables IN this schema participate — a reference to\n * `auth.users` / `auth.installations` (or any table the project doesn't\n * declare) has no parent bucket and is skipped. Self-FKs are skipped outright.\n *\n * A child that references the same parent through TWO columns is recorded once,\n * on the first column in declaration order: `children` maps a child table to a\n * single FK column, and the second FK stays an ordinary writable column.\n */\nfunction buildChildEdges(schema: SchemaDef): Map<string, ChildEdge[]> {\n const edges = new Map<string, ChildEdge[]>();\n for (const name of Object.keys(schema.tables)) edges.set(name, []);\n\n for (const childName of Object.keys(schema.tables)) {\n const table = schema.tables[childName];\n if (table === undefined) continue;\n for (const [col, builder] of Object.entries(table.columns)) {\n const ref = builder._def.references;\n if (ref === undefined) continue;\n if (ref.table === childName) continue; // self-FK\n const bucket = edges.get(ref.table);\n if (bucket === undefined) continue; // targets a table outside this schema\n if (bucket.some((e) => e.child === childName)) continue; // already linked\n bucket.push({ child: childName, column: col });\n }\n }\n return edges;\n}\n\n/**\n * Drop cycle back-edges from the FK graph.\n *\n * `children` feeds a RECURSIVE type in the seed/fixture DSL\n * (`SeedRow<T>` expands each child's own `children`). A cycle — `lists → todos`\n * plus `todos → lists` through a second FK — would make that type infinite\n * (\"Type instantiation is excessively deep\"). So we walk the graph depth-first\n * in declaration order and drop any edge pointing back at a table currently on\n * the DFS stack. Cross-edges into an already-FINISHED subtree are KEPT: they\n * re-expand a finite subtree, which terminates.\n *\n * Declaration order makes the choice of which edge to drop deterministic (the\n * generated .d.ts is golden-tested).\n */\nfunction pruneCycles(raw: Map<string, ChildEdge[]>): Map<string, ChildEdge[]> {\n const pruned = new Map<string, ChildEdge[]>();\n for (const table of raw.keys()) pruned.set(table, []);\n const state = new Map<string, \"visiting\" | \"done\">();\n\n function visit(table: string): void {\n state.set(table, \"visiting\");\n for (const edge of raw.get(table) ?? []) {\n if (state.get(edge.child) === \"visiting\") continue; // back-edge → drop\n pruned.get(table)?.push(edge);\n if (state.get(edge.child) === undefined) visit(edge.child);\n }\n state.set(table, \"done\");\n }\n\n for (const table of raw.keys()) {\n if (state.get(table) === undefined) visit(table);\n }\n return pruned;\n}\n\n/** Emit the `row` / `insert` / `owner` / `children` blocks for one table at the\n * given base indentation. */\nfunction tableBlock(table: TableDef, children: ChildEdge[], 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 const owner = ownerColumnOf(table);\n const childEntries = children\n .map((e) => `${JSON.stringify(e.child)}: ${JSON.stringify(e.column)}`)\n .join(\"; \");\n return [\n `${indent}${table.name}: {`,\n `${indent} row: {`,\n ...rowLines,\n `${indent} };`,\n `${indent} insert: {`,\n ...insertLines,\n `${indent} };`,\n `${indent} owner: ${owner === null ? \"null\" : JSON.stringify(owner)};`,\n `${indent} children: {${childEntries === \"\" ? \"\" : ` ${childEntries} `}};`,\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 children = pruneCycles(buildChildEdges(schema));\n const blocks = tableNames.map((name) =>\n tableBlock(schema.tables[name]!, children.get(name) ?? [], \" \"),\n );\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 db types\\` / 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","/**\n * storage.ts — the storage-buckets config-as-code DSL.\n *\n * `defineStorage({ buckets })` is the first MODULE config-as-code surface (the\n * sibling of `db/schema.ts`'s `defineSchema`). A `config/storage.ts` file\n * default-exports a `defineStorage(...)` result; on deploy the br-pod evaluates\n * it to JSON and reconciles the declared buckets against the tenant's live\n * buckets via the Storage admin API (create missing, update changed; never\n * auto-delete — dropping a bucket is destructive and warned only).\n *\n * Buckets are DECLARATIVE: name + access + size/mime limits. The FILES inside a\n * bucket are runtime state (uploaded via the SDK), never in git.\n *\n * @example\n * import { defineStorage, bucket } from \"@palbase/backend\";\n *\n * export default defineStorage({\n * buckets: {\n * avatars: bucket({\n * public: true,\n * fileSizeLimit: \"5MB\",\n * allowedMimeTypes: [\"image/png\", \"image/jpeg\", \"image/webp\"],\n * }),\n * invoices: bucket({\n * public: false,\n * fileSizeLimit: \"20MB\",\n * allowedMimeTypes: [\"application/pdf\"],\n * }),\n * },\n * });\n *\n * The returned value is the EXACT JSON shape the runtime's generic config\n * extractor (`config_extract.js`) emits and the Go apply step parses:\n * { __config: \"storage\", buckets: { avatars: { public, fileSizeLimit, allowedMimeTypes }, ... } }\n * `fileSizeLimit` is always normalized to a number of bytes (or null when\n * omitted, meaning \"no limit\"); the apply step maps it to the Storage API's\n * `file_size_limit` field. `allowedMimeTypes` is the allowlist or null (any).\n */\n\n/** The discriminant written under `__config` so the eval/apply can tell which\n * module config a `config/*.ts` file describes. Storage is `\"storage\"`. */\nexport const STORAGE_CONFIG_KIND = \"storage\" as const;\n\n/**\n * The author-facing options for a single bucket.\n *\n * - `public`: when true the bucket is served without a signed URL. Defaults to\n * `false` (private — signed URLs only).\n * - `fileSizeLimit`: the per-object upload cap. Accepts a human string\n * (`\"5MB\"`, `\"20MB\"`, `\"1GB\"`) or a bare number of BYTES. Omit for no limit.\n * - `allowedMimeTypes`: an allowlist of MIME types accepted on upload. Omit to\n * allow any type. Each entry must look like `type/subtype` (e.g. `image/png`,\n * `application/pdf`, or a wildcard `image/*`).\n */\nexport interface BucketOptions {\n public?: boolean;\n fileSizeLimit?: string | number;\n allowedMimeTypes?: string[];\n variants?: Record<string, ImageVariant>;\n}\n\n/**\n * One named rendition of an uploaded image — the same three knobs\n * `getPublicUrl(path, ...)` takes, given a name so the size lives with the\n * bucket instead of being retyped at every call site.\n *\n * At least one of `width` / `height` must be set (a variant that resizes\n * nothing and converts nothing is a typo, not a variant).\n */\nexport interface ImageVariant {\n width?: number;\n height?: number;\n format?: \"webp\" | \"avif\" | \"jpeg\" | \"png\";\n}\n\nconst VARIANT_FORMATS = [\"webp\", \"avif\", \"jpeg\", \"png\"] as const;\n\n/**\n * Validate + normalize a bucket's `variants` map.\n *\n * Renditions are produced ON REQUEST by the image-transform route and cached —\n * declaring one stores nothing extra and costs nothing until it is fetched,\n * which is why adding a size later needs no backfill of objects already\n * uploaded.\n */\nfunction normalizeVariants(\n input: Record<string, ImageVariant>,\n): Record<string, ImageVariant> {\n if (input === null || typeof input !== \"object\" || Array.isArray(input)) {\n throw new Error(\"bucket variants must be an object of { <name>: { width?, height?, format? } }\");\n }\n const out: Record<string, ImageVariant> = {};\n for (const [name, spec] of Object.entries(input)) {\n // The name becomes part of a URL/response key, so keep it boring.\n if (!/^[a-z0-9][a-z0-9_-]*$/i.test(name)) {\n throw new Error(\n `bucket variant name \"${name}\" must be alphanumeric with optional - or _ (e.g. \"thumb\", \"card_2x\")`,\n );\n }\n if (spec === null || typeof spec !== \"object\" || Array.isArray(spec)) {\n throw new Error(`bucket variant \"${name}\" must be an object like { width: 100, height: 100 }`);\n }\n for (const dim of [\"width\", \"height\"] as const) {\n const value = spec[dim];\n if (value === undefined) continue;\n if (typeof value !== \"number\" || !Number.isInteger(value) || value <= 0) {\n throw new Error(`bucket variant \"${name}\" ${dim} must be a positive integer, got ${String(value)}`);\n }\n }\n if (spec.width === undefined && spec.height === undefined) {\n throw new Error(`bucket variant \"${name}\" must set width and/or height`);\n }\n if (spec.format !== undefined && !VARIANT_FORMATS.includes(spec.format)) {\n throw new Error(\n `bucket variant \"${name}\" format must be one of ${VARIANT_FORMATS.join(\", \")}, got \"${String(spec.format)}\"`,\n );\n }\n out[name] = {\n ...(spec.width !== undefined ? { width: spec.width } : {}),\n ...(spec.height !== undefined ? { height: spec.height } : {}),\n ...(spec.format !== undefined ? { format: spec.format } : {}),\n };\n }\n return out;\n}\n\n/**\n * The compiled, serializable bucket definition — the EXACT shape emitted to\n * JSON and consumed by the Go apply step.\n *\n * - `public`: always present (defaulted to `false`).\n * - `fileSizeLimit`: bytes as a number, or `null` for \"no limit\".\n * - `allowedMimeTypes`: the MIME allowlist, or `null` for \"any type\".\n */\nexport interface BucketDef {\n public: boolean;\n fileSizeLimit: number | null;\n allowedMimeTypes: string[] | null;\n /** Named renditions, or `null` when none are declared. Rendered on request by\n * the image-transform route and cached — nothing extra is stored. */\n variants: Record<string, ImageVariant> | null;\n}\n\n/** A storage config definition: the discriminant + a map of bucket name →\n * {@link BucketDef}. This is the value `defineStorage` returns and the runtime\n * config extractor serializes. */\nexport interface StorageConfig {\n __config: typeof STORAGE_CONFIG_KIND;\n buckets: Record<string, BucketDef>;\n}\n\n/** The author-facing input to `defineStorage`: a `buckets` map whose keys are\n * the bucket names and whose values are `bucket({...})` builders. */\nexport interface StorageInput {\n buckets: Record<string, BucketDef>;\n}\n\n// Powers of 1024 (binary, IEC). Storage's `file_size_limit` string parser\n// (the `bytes` npm lib, used by Supabase Storage) treats \"MB\"/\"GB\" as binary\n// multiples, so \"5MB\" = 5 * 1024 * 1024. We match that exactly so the limit a\n// user declares is the limit the bucket enforces.\nconst UNIT_BYTES: Record<string, number> = {\n b: 1,\n kb: 1024,\n mb: 1024 ** 2,\n gb: 1024 ** 3,\n tb: 1024 ** 4,\n};\n\n/**\n * Parse a `fileSizeLimit` into a number of bytes.\n *\n * - A bare number is taken as bytes verbatim (must be a non-negative integer).\n * - A string is `<number><unit>` (e.g. `\"5MB\"`, `\"1.5GB\"`, `\"500kb\"`); the unit\n * is case-insensitive and optional (a bare numeric string = bytes). Binary\n * units (1 MB = 1024 squared bytes) to match the Storage module's parser.\n *\n * Throws on a negative value, a non-finite number, or an unrecognized unit so a\n * bad limit fails at config-author time, not silently at deploy.\n */\nexport function parseFileSizeLimit(input: string | number): number {\n if (typeof input === \"number\") {\n if (!Number.isFinite(input) || input < 0 || !Number.isInteger(input)) {\n throw new Error(\n `bucket fileSizeLimit must be a non-negative integer number of bytes, got ${input}`,\n );\n }\n return input;\n }\n\n const trimmed = input.trim();\n // <number><optional-unit>, e.g. \"5MB\", \"1.5 gb\", \"1024\", \"500kb\".\n const match = /^(\\d+(?:\\.\\d+)?)\\s*([a-zA-Z]+)?$/.exec(trimmed);\n if (!match) {\n throw new Error(\n `bucket fileSizeLimit string must be \"<number><unit>\" like \"5MB\" or \"1GB\", got \"${input}\"`,\n );\n }\n const value = Number.parseFloat(match[1]!);\n const unit = (match[2] ?? \"b\").toLowerCase();\n const multiplier = UNIT_BYTES[unit];\n if (multiplier === undefined) {\n throw new Error(\n `bucket fileSizeLimit has an unknown unit \"${match[2]}\" — use B, KB, MB, GB, or TB (e.g. \"5MB\")`,\n );\n }\n const bytes = value * multiplier;\n if (!Number.isFinite(bytes) || bytes < 0) {\n throw new Error(`bucket fileSizeLimit resolved to an invalid byte count: ${bytes}`);\n }\n // Round to a whole byte — a fractional byte is meaningless to the Storage API.\n return Math.round(bytes);\n}\n\n// A loose MIME-type shape check: `type/subtype`, where each side is a token of\n// alphanumerics plus the usual punctuation, and the subtype may be a wildcard\n// `*`. This is intentionally permissive (not an IANA allowlist) but rejects the\n// obvious typos (\"image\", \"imagepng\", \" \").\nconst MIME_RE = /^[a-zA-Z0-9][a-zA-Z0-9!#$&^_.+-]*\\/(?:\\*|[a-zA-Z0-9][a-zA-Z0-9!#$&^_.+-]*)$/;\n\n/**\n * Define a single bucket. The bucket NAME is supplied by the key in\n * `defineStorage({ buckets: { <name>: bucket({...}) } })`, so `bucket()` takes\n * only the options.\n *\n * Validates eagerly (at config-author time):\n * - `fileSizeLimit` parses to a valid non-negative byte count.\n * - each `allowedMimeTypes` entry is a `type/subtype` MIME string.\n *\n * Returns a normalized {@link BucketDef}: `public` defaulted to `false`,\n * `fileSizeLimit` as bytes-or-null, `allowedMimeTypes` deduped-or-null.\n */\nexport function bucket(opts: BucketOptions = {}): BucketDef {\n const fileSizeLimit =\n opts.fileSizeLimit === undefined ? null : parseFileSizeLimit(opts.fileSizeLimit);\n\n let allowedMimeTypes: string[] | null = null;\n if (opts.allowedMimeTypes !== undefined) {\n if (!Array.isArray(opts.allowedMimeTypes)) {\n throw new Error(\"bucket allowedMimeTypes must be an array of MIME-type strings\");\n }\n for (const mime of opts.allowedMimeTypes) {\n if (typeof mime !== \"string\" || !MIME_RE.test(mime.trim())) {\n throw new Error(\n `bucket allowedMimeTypes entry \"${mime}\" is not a valid MIME type (expected \"type/subtype\", e.g. \"image/png\")`,\n );\n }\n }\n // Dedupe + trim. An empty array means \"explicitly no types\" — keep it as []\n // rather than null so the apply step can distinguish \"any\" (null) from a\n // caller that passed [].\n allowedMimeTypes = [...new Set(opts.allowedMimeTypes.map((m) => m.trim()))];\n }\n\n return {\n public: opts.public ?? false,\n fileSizeLimit,\n allowedMimeTypes,\n variants: opts.variants === undefined ? null : normalizeVariants(opts.variants),\n };\n}\n\n/**\n * Define the storage config for a project. The bucket NAME comes from each\n * object key (authors never repeat the name). Returns the discriminated\n * {@link StorageConfig} the runtime config extractor serializes and the Go\n * apply step reconciles.\n *\n * @example\n * export default defineStorage({\n * buckets: { avatars: bucket({ public: true, fileSizeLimit: \"5MB\" }) },\n * });\n */\nexport function defineStorage(input: StorageInput): StorageConfig {\n if (input === null || typeof input !== \"object\" || typeof input.buckets !== \"object\") {\n throw new Error(\"defineStorage expects { buckets: { <name>: bucket({...}) } }\");\n }\n const buckets: Record<string, BucketDef> = {};\n for (const name of Object.keys(input.buckets)) {\n if (name.length === 0) {\n throw new Error(\"bucket name must be a non-empty string\");\n }\n const def = input.buckets[name];\n if (def === undefined) continue;\n buckets[name] = def;\n }\n return { __config: STORAGE_CONFIG_KIND, buckets };\n}\n","/**\n * egress.ts — the tenant outbound-HTTP allowlist config-as-code DSL.\n *\n * `defineEgress({ hosts, timeoutMs })` declares the external hosts a backend may\n * fetch(), and how long a single call may take. config/egress.ts default-exports\n * it; the deploy evals it to JSON (SchemaExtractor.EvaluateConfigFile →\n * config_extract.js) and bakes both into the artifact manifest → the isolate\n * loader → Tenant.egressAllow / Tenant.egressTimeoutMs. The tenantFetch\n * capability rejects any host NOT on the list. NO config/egress.ts (or an empty\n * list) ⇒ the backend has NO outbound network — fail-closed.\n *\n * @example\n * // config/egress.ts\n * import { defineEgress } from \"@palbase/backend\";\n * export default defineEgress({\n * hosts: [\"api.openai.com\"],\n * timeoutMs: 90_000, // a slow LLM call; default 30_000\n * });\n *\n * Each host is a bare hostname (no scheme/port/path/wildcard). A leading dot,\n * `.example.com`, also covers subdomains (Squid dstdomain semantics). Egress is\n * https-only on :443; the deploy REJECTS a malformed / IP-literal / internal host\n * (fail-closed — a security allowlist is never best-effort).\n *\n * `timeoutMs` is a CEILING, not a grant: the call still ends when the INVOCATION\n * ends. A job may run up to its own `@Job({ timeout })` (max 300s), while a\n * request is additionally bounded by the gateway. Setting 300_000 on a route\n * whose request dies earlier buys nothing — size it to the caller.\n *\n * Response bodies are BUFFERED whole (5 MB cap) before your fetch() resolves, so\n * a streaming/SSE upstream gives you no partial output and no earlier\n * first-byte: the entire stream must complete inside `timeoutMs`.\n *\n * Emits: { __config: \"egress\", hosts: [...], timeoutMs?: number }\n */\n\n/** The discriminant written under `__config` so the deploy eval knows the kind. */\nexport const EGRESS_CONFIG_KIND = \"egress\" as const;\n\n/**\n * Bounds on `timeoutMs`, duplicated (deliberately) in the deploy's\n * ParseEgressConfig. This copy shapes the authoring error; that one is\n * authoritative and fail-closed. They must agree — a value this accepts and the\n * deploy rejects is a broken deploy the author cannot see coming.\n */\nexport const EGRESS_TIMEOUT_MIN_MS = 1_000;\nexport const EGRESS_TIMEOUT_MAX_MS = 300_000;\n/** Applied when `timeoutMs` is omitted. Also spelled in the isolate capability. */\nexport const EGRESS_TIMEOUT_DEFAULT_MS = 30_000;\n\n/** The author-facing input to defineEgress. */\nexport interface EgressInput {\n hosts: string[];\n /**\n * Per-call ceiling for an outbound fetch, in milliseconds.\n * 1_000..300_000; omitted ⇒ 30_000.\n */\n timeoutMs?: number;\n}\n\n/** The evaluated config/egress.ts default export (what the deploy reads). */\nexport interface EgressConfig {\n __config: typeof EGRESS_CONFIG_KIND;\n hosts: string[];\n timeoutMs?: number;\n}\n\n/**\n * Declare the backend's outbound-HTTP allowlist. Client-side this only shapes +\n * validates the list; the authoritative fail-closed validation runs at deploy.\n */\nexport function defineEgress(input: EgressInput): EgressConfig {\n if (input === null || typeof input !== \"object\" || !Array.isArray(input.hosts)) {\n throw new Error(\"defineEgress expects { hosts: string[] }\");\n }\n const hosts: string[] = [];\n for (const h of input.hosts) {\n if (typeof h !== \"string\" || h.trim().length === 0) {\n throw new Error(\"defineEgress: every host must be a non-empty string\");\n }\n hosts.push(h.trim().toLowerCase());\n }\n if (input.timeoutMs === undefined) {\n return { __config: EGRESS_CONFIG_KIND, hosts };\n }\n const timeoutMs = input.timeoutMs;\n if (typeof timeoutMs !== \"number\" || !Number.isInteger(timeoutMs)) {\n throw new Error(\"defineEgress: timeoutMs must be an integer number of milliseconds\");\n }\n if (timeoutMs < EGRESS_TIMEOUT_MIN_MS || timeoutMs > EGRESS_TIMEOUT_MAX_MS) {\n throw new Error(\n `defineEgress: timeoutMs must be between ${EGRESS_TIMEOUT_MIN_MS} and ${EGRESS_TIMEOUT_MAX_MS} (got ${timeoutMs})`,\n );\n }\n return { __config: EGRESS_CONFIG_KIND, hosts, timeoutMs };\n}\n","/**\n * notifications.ts — the notification-providers config-as-code DSL.\n *\n * `defineNotifications({ push, email, sms })` is the second MODULE config-as-code\n * surface (the sibling of `config/storage.ts`'s `defineStorage`). A\n * `config/notifications.ts` file default-exports a `defineNotifications(...)`\n * result; on deploy the br-pod evaluates it to JSON and reconciles the declared\n * providers against the tenant's live providers via the PalNotify admin API\n * (create missing; never auto-delete — dropping a provider is destructive and\n * warned only).\n *\n * SECRETS ARE NEVER IN THE FILE. Each provider's NON-SECRET fields (team id, key\n * id, bundle id, region, host, port, from address, account sid, …) are literals\n * in the config. Each provider's SECRET material (the APNs .p8 key, the FCM\n * service-account JSON, an api_key, an auth token, the SMTP/ACS password, …) is\n * NOT a field here — it is bound BY CONVENTION to a RESERVED encrypted env var\n * and resolved at deploy from control-pg. The env-key convention is:\n *\n * PB_NOTIFICATIONS_<PROVIDER>_<FIELD> (UPPER_SNAKE_CASE)\n *\n * e.g. `PB_NOTIFICATIONS_APNS_P8`, `PB_NOTIFICATIONS_FCM_SERVICE_ACCOUNT`,\n * `PB_NOTIFICATIONS_TWILIO_AUTH_TOKEN`. The `PB_` namespace is reserved (the CLI\n * refuses a hand-set `palbase secret set PB_*`); the CLI's `palbase notifications\n * add <provider>` derives the key and uploads the secret for you, so an author\n * never types either the secret or the env-key name into git.\n *\n * @example\n * import { defineNotifications } from \"@palbase/backend\";\n *\n * export default defineNotifications({\n * push: {\n * apns: { enabled: true, teamId: \"ABCDE12345\", keyId: \"KEY1234567\", bundleId: \"com.acme.app\" },\n * fcm: { enabled: true },\n * },\n * email: {\n * sendgrid: { enabled: true, fromDomain: \"mail.acme.com\" },\n * },\n * sms: {\n * twilio: { enabled: true, accountSid: \"ACxxxxxxxx\", messagingServiceSid: \"MGxxxxxxxx\" },\n * },\n * });\n *\n * The returned value is the EXACT JSON shape the runtime's generic config\n * extractor (`config_extract.js`) emits and the Go apply step parses:\n * { __config: \"notifications\", push: {...}, email: {...}, sms: {...} }\n * Only ENABLED providers carry their non-secret fields; a disabled (or absent)\n * provider serializes as `{ enabled: false }` so the apply step skips it.\n */\n\n/** The `__config` discriminant the eval/apply reads to confirm a config/*.ts is\n * a notifications config. Notifications is `\"notifications\"`. */\nexport const NOTIFICATIONS_CONFIG_KIND = \"notifications\" as const;\n\n/** The reserved env-var prefix that backs provider secrets. A `palbase secret\n * set` of a key under this prefix is REFUSED by the CLI (it is managed by\n * `palbase notifications add`). Both the CLI and the br-pod apply step derive a\n * provider's secret env key as `${RESERVED_SECRET_PREFIX}_<PROVIDER>_<FIELD>`. */\nexport const RESERVED_SECRET_PREFIX = \"PB_NOTIFICATIONS\" as const;\n\n// ────────────────────────────────────────────────────────────────────────────\n// Provider catalog — the SINGLE SOURCE of which providers exist + their fields.\n//\n// Ported from platform/studio/src/server/trpc/routers/notifications.ts (the\n// per-provider credential zod schemas). Here the fields are split into:\n// • nonSecret: literals that live in config/notifications.ts (this file).\n// • secret: the field name(s) bound to a reserved env var (NOT in config).\n// The Go apply step + the CLI both mirror this catalog, so adding a provider is\n// a three-line change kept in lockstep across the SDK / runtime / CLI.\n// ────────────────────────────────────────────────────────────────────────────\n\n/** One provider's catalog entry: which non-secret fields are required, which are\n * optional, and which secret field-name(s) bind to reserved env vars. */\nexport interface ProviderCatalogEntry {\n /** The channel this provider serves (`push` | `email` | `sms`). */\n readonly channel: \"push\" | \"email\" | \"sms\";\n /** Non-secret config fields the author MUST supply (validated eagerly). */\n readonly required: readonly string[];\n /** Non-secret config fields the author MAY supply. */\n readonly optional: readonly string[];\n /** Secret field name(s) — each backed by `PB_NOTIFICATIONS_<PROVIDER>_<FIELD>`\n * (FIELD is the UPPER_SNAKE of the name here). NOT a config field. */\n readonly secrets: readonly string[];\n}\n\n/**\n * The provider catalog: provider key → fields. The non-secret field names are\n * the camelCase keys an author writes in `config/notifications.ts`; the secret\n * names are the snake-ish tokens that become the reserved env-var suffix.\n *\n * apns: team_id / key_id / bundle_id (+ optional is_production); secret = p8.\n * fcm: no non-secret fields; secret = service_account (the full JSON).\n * sendgrid: from_domain; secret = api_key.\n * ses: region / from_domain / access_key_id; secret = secret_access_key.\n * smtp: host / port / from_email (+ optional username, use_starttls); secret = password.\n * acs: from_email (+ optional from_name); secret = connection_string.\n * twilio: account_sid + (from_number OR messaging_service_sid); secret = auth_token.\n */\nexport const PROVIDER_CATALOG = {\n apns: {\n channel: \"push\",\n required: [\"teamId\", \"keyId\", \"bundleId\"],\n optional: [\"isProduction\"],\n secrets: [\"p8\"],\n },\n fcm: {\n channel: \"push\",\n required: [],\n optional: [],\n secrets: [\"serviceAccount\"],\n },\n sendgrid: {\n channel: \"email\",\n required: [\"fromDomain\"],\n optional: [],\n secrets: [\"apiKey\"],\n },\n ses: {\n channel: \"email\",\n required: [\"region\", \"accessKeyId\", \"fromDomain\"],\n optional: [],\n secrets: [\"secretAccessKey\"],\n },\n smtp: {\n channel: \"email\",\n required: [\"host\", \"port\", \"fromEmail\"],\n optional: [\"username\", \"useStarttls\"],\n secrets: [\"password\"],\n },\n acs: {\n channel: \"email\",\n required: [\"fromEmail\"],\n optional: [\"fromName\"],\n secrets: [\"connectionString\"],\n },\n twilio: {\n channel: \"sms\",\n // account_sid required; one of from_number / messaging_service_sid required\n // (enforced by the refine in buildProvider, not by the flat `required` list).\n required: [\"accountSid\"],\n optional: [\"fromNumber\", \"messagingServiceSid\"],\n secrets: [\"authToken\"],\n },\n} as const satisfies Record<string, ProviderCatalogEntry>;\n\n/** A provider key (`\"apns\" | \"fcm\" | \"sendgrid\" | …`). */\nexport type ProviderName = keyof typeof PROVIDER_CATALOG;\n\n// ── author-facing per-provider option types (non-secret fields only) ─────────\n\n/** APNs (Apple Push) — non-secret fields. The `.p8` key is the reserved secret\n * `PB_NOTIFICATIONS_APNS_P8` (uploaded via `palbase notifications add apns`). */\nexport interface ApnsOptions {\n enabled?: boolean;\n teamId: string;\n keyId: string;\n bundleId: string;\n /** APNs production gateway vs sandbox. Defaults to true (production). */\n isProduction?: boolean;\n}\n\n/** FCM (Firebase Cloud Messaging) — no non-secret fields; the service-account\n * JSON is the reserved secret `PB_NOTIFICATIONS_FCM_SERVICE_ACCOUNT`. */\nexport interface FcmOptions {\n enabled?: boolean;\n}\n\n/** SendGrid email — non-secret `fromDomain`; api_key is the reserved secret. */\nexport interface SendgridOptions {\n enabled?: boolean;\n fromDomain: string;\n}\n\n/** Amazon SES email — secret_access_key is the reserved secret. */\nexport interface SesOptions {\n enabled?: boolean;\n region: string;\n accessKeyId: string;\n fromDomain: string;\n}\n\n/** SMTP email — password is the reserved secret. */\nexport interface SmtpOptions {\n enabled?: boolean;\n host: string;\n port: number;\n fromEmail: string;\n username?: string;\n useStarttls?: boolean;\n}\n\n/** Azure Communication Services email — connection_string is the reserved secret. */\nexport interface AcsOptions {\n enabled?: boolean;\n fromEmail: string;\n fromName?: string;\n}\n\n/** Twilio SMS — auth_token is the reserved secret. Exactly one of `fromNumber`\n * or `messagingServiceSid` must be supplied. */\nexport interface TwilioOptions {\n enabled?: boolean;\n accountSid: string;\n fromNumber?: string;\n messagingServiceSid?: string;\n}\n\n/** The union of every provider's author-facing options. `buildProvider` accepts\n * this so each provider's typed options pass without a cast. */\nexport type ProviderOptions =\n | ApnsOptions\n | FcmOptions\n | SendgridOptions\n | SesOptions\n | SmtpOptions\n | AcsOptions\n | TwilioOptions;\n\n// ── templates ───────────────────────────────────────────────────────────────\n//\n// Templates are the OTHER half of config-as-code notifications. A provider says\n// *how* mail leaves; a template says *what* it says. Before this existed the\n// only way to create one was a live API call or a click in Studio — so the thing\n// your code sends by slug lived outside your repo, outside review, and outside\n// the deploy that depends on it. `Notifications.email.send({ templateSlug })`\n// would 404 on a fresh environment until somebody remembered to re-create it by\n// hand.\n\n/** The default locale a template row lands on when the author names none. Must\n * match PalNotify's `model.DefaultLocale`. */\nexport const DEFAULT_TEMPLATE_LOCALE = \"en\" as const;\n\n/** One locale's email content. */\nexport interface EmailTemplateContent {\n /** Subject line. Handlebars placeholders (`{{name}}`) are rendered at send. */\n subject: string;\n /** HTML body. */\n html: string;\n /** Plain-text body. Omit and the server derives one from `html` at render. */\n text?: string;\n /**\n * Variables the sender MUST supply. Omit and they are DERIVED from the\n * `{{placeholders}}` in this locale's content — see {@link extractVariables}.\n * Supply explicitly to make a placeholder optional (leave it out of the list)\n * or to require something a conditional references.\n */\n variables?: readonly string[];\n}\n\n/** An email template: base content, plus optional per-locale overrides. */\nexport interface EmailTemplateOptions extends EmailTemplateContent {\n /** Locale of the base content. Defaults to `\"en\"`. */\n locale?: string;\n /** Additional locales, keyed by BCP47 short tag (`tr`, `de`, …). */\n locales?: Record<string, EmailTemplateContent>;\n}\n\n/** One locale's SMS content. */\nexport interface SmsTemplateContent {\n /** Message body. Handlebars placeholders are rendered at send. */\n body: string;\n /** Variables the sender must supply. Derived from `body` when omitted. */\n variables?: readonly string[];\n}\n\n/** An SMS template: base content, plus optional per-locale overrides. */\nexport interface SmsTemplateOptions extends SmsTemplateContent {\n /** Locale of the base content. Defaults to `\"en\"`. */\n locale?: string;\n /** Additional locales, keyed by BCP47 short tag. */\n locales?: Record<string, SmsTemplateContent>;\n}\n\n/** Author-facing templates block: slug → template. */\nexport interface TemplatesInput {\n email?: Record<string, EmailTemplateOptions>;\n sms?: Record<string, SmsTemplateOptions>;\n}\n\n/** A compiled email-template row — one (slug, locale) pair, in the snake_case\n * wire shape PalNotify's templates API takes. */\nexport interface EmailTemplateDef {\n slug: string;\n locale: string;\n subject: string;\n html_body: string;\n text_body?: string;\n variables: string[];\n}\n\n/** A compiled SMS-template row — one (slug, locale) pair. */\nexport interface SmsTemplateDef {\n slug: string;\n locale: string;\n body: string;\n variables: string[];\n}\n\n/** The compiled templates block: flat, per-channel row lists. Flat rows (rather\n * than a nested locale map) are what the apply step iterates — one row is one\n * upsert against the (slug, locale) unique key. */\nexport interface TemplatesConfig {\n email: EmailTemplateDef[];\n sms: SmsTemplateDef[];\n}\n\n/**\n * Pull the variable names out of Handlebars content.\n *\n * Only PLAIN mustaches count: `{{name}}` and `{{{name}}}`. Deliberately skipped:\n * - block/section/partial/comment tokens (`{{#if}}`, `{{/if}}`, `{{else}}`,\n * `{{> partial}}`, `{{! comment}}`) — structure, not data the sender passes;\n * - helper calls (`{{formatDate at}}`) — the first token is a helper name;\n * - `this` and `@index`-style frame references.\n *\n * A dotted path contributes its ROOT (`{{user.name}}` → `user`), because that is\n * what the sender actually has to hand over.\n *\n * The list is what the server ENFORCES as required at render time, so keeping it\n * to the unambiguous cases is the point: an over-eager derivation would turn an\n * optional conditional into a mandatory argument and 400 real sends.\n */\nexport function extractVariables(...sources: (string | undefined)[]): string[] {\n const found = new Set<string>();\n for (const src of sources) {\n if (!src) continue;\n for (const match of src.matchAll(/\\{\\{\\{?\\s*([^{}]+?)\\s*\\}?\\}\\}/g)) {\n const token = (match[1] ?? \"\").trim();\n if (token === \"\" || \"#/^!>&\".includes(token.charAt(0)) || token === \"else\") continue;\n if (/\\s/.test(token)) continue; // helper invocation\n const root = token.split(\".\")[0] ?? \"\";\n if (root === \"\" || root === \"this\" || root.startsWith(\"@\")) continue;\n found.add(root);\n }\n }\n return [...found].sort();\n}\n\n/** Compile one email template into its per-locale rows. */\nfunction buildEmailTemplate(slug: string, opts: EmailTemplateOptions): EmailTemplateDef[] {\n const row = (locale: string, c: EmailTemplateContent): EmailTemplateDef => {\n if (!c.subject) throw new Error(`notifications: email template \"${slug}\" (${locale}) needs a subject`);\n if (!c.html) throw new Error(`notifications: email template \"${slug}\" (${locale}) needs an html body`);\n const def: EmailTemplateDef = {\n slug,\n locale,\n subject: c.subject,\n html_body: c.html,\n variables: c.variables ? [...c.variables] : extractVariables(c.subject, c.html, c.text),\n };\n if (c.text !== undefined) def.text_body = c.text;\n return def;\n };\n\n const rows = [row(opts.locale ?? DEFAULT_TEMPLATE_LOCALE, opts)];\n for (const [locale, content] of Object.entries(opts.locales ?? {})) {\n rows.push(row(locale, content));\n }\n return rows;\n}\n\n/** Compile one SMS template into its per-locale rows. */\nfunction buildSmsTemplate(slug: string, opts: SmsTemplateOptions): SmsTemplateDef[] {\n const row = (locale: string, c: SmsTemplateContent): SmsTemplateDef => {\n if (!c.body) throw new Error(`notifications: sms template \"${slug}\" (${locale}) needs a body`);\n return {\n slug,\n locale,\n body: c.body,\n variables: c.variables ? [...c.variables] : extractVariables(c.body),\n };\n };\n\n const rows = [row(opts.locale ?? DEFAULT_TEMPLATE_LOCALE, opts)];\n for (const [locale, content] of Object.entries(opts.locales ?? {})) {\n rows.push(row(locale, content));\n }\n return rows;\n}\n\n/** Compile the whole templates block, rejecting a duplicated (slug, locale). */\nfunction buildTemplates(input: TemplatesInput): TemplatesConfig {\n const out: TemplatesConfig = { email: [], sms: [] };\n const seen = new Set<string>();\n const claim = (channel: string, slug: string, locale: string) => {\n const key = `${channel}/${slug}/${locale}`;\n if (seen.has(key)) {\n throw new Error(`notifications: ${channel} template \"${slug}\" declares locale \"${locale}\" twice`);\n }\n seen.add(key);\n };\n\n for (const [slug, opts] of Object.entries(input.email ?? {})) {\n for (const row of buildEmailTemplate(slug, opts)) {\n claim(\"email\", row.slug, row.locale);\n out.email.push(row);\n }\n }\n for (const [slug, opts] of Object.entries(input.sms ?? {})) {\n for (const row of buildSmsTemplate(slug, opts)) {\n claim(\"sms\", row.slug, row.locale);\n out.sms.push(row);\n }\n }\n return out;\n}\n\n/** The author-facing input to `defineNotifications`. Every provider + every\n * channel is optional — declare only what you use. */\nexport interface NotificationsInput {\n push?: {\n apns?: ApnsOptions;\n fcm?: FcmOptions;\n };\n email?: {\n sendgrid?: SendgridOptions;\n ses?: SesOptions;\n smtp?: SmtpOptions;\n acs?: AcsOptions;\n };\n sms?: {\n twilio?: TwilioOptions;\n };\n /** Email + SMS templates, keyed by slug. Applied on every deploy. */\n templates?: TemplatesInput;\n}\n\n// ── compiled (serializable) provider defs — the EXACT JSON the apply parses ──\n\n/** A compiled provider def. `enabled` is always present; the remaining keys are\n * the provider's non-secret fields (verbatim from the catalog). A disabled\n * provider is `{ enabled: false }` with no other fields. */\nexport type ProviderDef = { enabled: boolean } & Record<string, unknown>;\n\n/** The compiled notifications config — the discriminant + per-channel maps of\n * provider name → {@link ProviderDef}. This is what `defineNotifications`\n * returns and the runtime extractor serializes. */\nexport interface NotificationsConfig {\n __config: typeof NOTIFICATIONS_CONFIG_KIND;\n push: Record<string, ProviderDef>;\n email: Record<string, ProviderDef>;\n sms: Record<string, ProviderDef>;\n templates: TemplatesConfig;\n}\n\n// ── validation + compilation ────────────────────────────────────────────────\n\n/**\n * Compile + validate one provider's author options into a {@link ProviderDef}.\n *\n * - A provider with `enabled === false` (or omitted) compiles to `{ enabled:\n * false }` and its required fields are NOT enforced (you can declare a disabled\n * provider as a placeholder without filling it in).\n * - An ENABLED provider must supply every `required` non-secret field from the\n * catalog; a missing one throws at config-author time (not silently at deploy).\n * - Only the catalog's non-secret fields (required + optional) are copied into\n * the def — an unknown extra key is ignored (it would have no effect on the\n * live provider). Secrets are never read here.\n */\nexport function buildProvider(name: ProviderName, opts: ProviderOptions): ProviderDef {\n const entry = PROVIDER_CATALOG[name];\n // A fresh, index-signature-bearing copy so catalog-driven field reads are\n // typed without a cast (the author-facing option interfaces are closed).\n const src: Record<string, unknown> = { ...opts };\n const enabled = src.enabled === undefined ? false : Boolean(src.enabled);\n if (!enabled) {\n return { enabled: false };\n }\n\n const def: ProviderDef = { enabled: true };\n\n for (const field of entry.required) {\n const value = src[field];\n if (value === undefined || value === null || value === \"\") {\n throw new Error(\n `notifications: provider \"${name}\" is enabled but missing required field \"${field}\"`,\n );\n }\n def[field] = value;\n }\n for (const field of entry.optional) {\n if (src[field] !== undefined) {\n def[field] = src[field];\n }\n }\n\n // Twilio: exactly one of fromNumber / messagingServiceSid is required (mirrors\n // the studio router's refine + the module's ValidateTwilioConfig).\n if (name === \"twilio\") {\n const hasFrom = Boolean(def.fromNumber);\n const hasMsg = Boolean(def.messagingServiceSid);\n if (!hasFrom && !hasMsg) {\n throw new Error(\n 'notifications: provider \"twilio\" requires one of \"fromNumber\" or \"messagingServiceSid\"',\n );\n }\n }\n\n return def;\n}\n\n/**\n * Define the notification-provider config for a project. Returns the\n * discriminated {@link NotificationsConfig} the runtime config extractor\n * serializes and the Go apply step reconciles. Validates eagerly: an enabled\n * provider missing a required non-secret field throws here (config-author time),\n * not at deploy.\n *\n * @example\n * export default defineNotifications({\n * push: { apns: { enabled: true, teamId: \"T\", keyId: \"K\", bundleId: \"com.x\" } },\n * });\n */\nexport function defineNotifications(input: NotificationsInput): NotificationsConfig {\n if (input === null || typeof input !== \"object\") {\n throw new Error(\"defineNotifications expects { push?, email?, sms? }\");\n }\n\n const config: NotificationsConfig = {\n __config: NOTIFICATIONS_CONFIG_KIND,\n push: {},\n email: {},\n sms: {},\n templates: buildTemplates(input.templates ?? {}),\n };\n\n const push = input.push ?? {};\n if (push.apns !== undefined) config.push.apns = buildProvider(\"apns\", push.apns);\n if (push.fcm !== undefined) config.push.fcm = buildProvider(\"fcm\", push.fcm);\n\n const email = input.email ?? {};\n if (email.sendgrid !== undefined) config.email.sendgrid = buildProvider(\"sendgrid\", email.sendgrid);\n if (email.ses !== undefined) config.email.ses = buildProvider(\"ses\", email.ses);\n if (email.smtp !== undefined) config.email.smtp = buildProvider(\"smtp\", email.smtp);\n if (email.acs !== undefined) config.email.acs = buildProvider(\"acs\", email.acs);\n\n const sms = input.sms ?? {};\n if (sms.twilio !== undefined) config.sms.twilio = buildProvider(\"twilio\", sms.twilio);\n\n return config;\n}\n\n/**\n * Derive the RESERVED env-var key that backs a provider's secret field, e.g.\n * `reservedSecretKey(\"apns\", \"p8\")` → `\"PB_NOTIFICATIONS_APNS_P8\"`. The CLI uses\n * this to upload the secret and the br-pod apply step uses the same derivation\n * to resolve it — they never hand-type the key, so they cannot drift.\n */\nexport function reservedSecretKey(provider: ProviderName, secretField: string): string {\n return `${RESERVED_SECRET_PREFIX}_${camelToUpperSnake(provider)}_${camelToUpperSnake(secretField)}`;\n}\n\n/** camelCase → UPPER_SNAKE_CASE (`serviceAccount` → `SERVICE_ACCOUNT`). */\nfunction camelToUpperSnake(s: string): string {\n return s.replace(/([a-z0-9])([A-Z])/g, \"$1_$2\").toUpperCase();\n}\n","/**\n * test-users.ts — the test-user fixtures config-as-code DSL.\n *\n * `defineTestUsers({ users })` is a MODULE config-as-code surface (a sibling of\n * `config/storage.ts`'s `defineStorage` and `config/flags.ts`'s `defineFlags`).\n * A `config/test-users.ts` file default-exports a `defineTestUsers(...)` result;\n * on deploy the runtime evaluates it to JSON and hands it to Studio, which owns\n * the single apply engine (mint + seed). Studio, the CLI and the deploy all go\n * through that one engine — there is no second interpreter of this JSON.\n *\n * TWO SHAPES, ONE DSL:\n *\n * - `email` GIVEN → a FIXTURE. Deploy materializes it create-if-missing, so\n * the app can always be signed into with the same credentials. Deliberately\n * NOT applied to a production Environment (the password lives in git).\n * - `email` OMITTED → a TEMPLATE. Deploy creates nothing; Studio and the CLI\n * mint as many fresh instances from it as you want (random credentials).\n *\n * Every minted user is an `is_test` user: excluded from MAU/billing, carrying\n * `test: true` in its token, and refused by the Test Data write path if it ever\n * turns out not to be one.\n *\n * @example\n * import { defineTestUsers, testUser } from \"@palbase/backend\";\n *\n * export default defineTestUsers({\n * users: {\n * demo: testUser({\n * email: \"demo@test.local\",\n * password: \"demo-password-1234\",\n * seed: {\n * profiles: [{ display_name: \"Demo\", tier: \"pro\" }],\n * lists: [\n * { title: \"Groceries\", todos: [{ title: \"Milk\" }, { title: \"Eggs\", done: true }] },\n * ],\n * },\n * }),\n * heavy_user: testUser({ seed: { lists: [{ title: \"L\", todos: [{ title: \"t\" }] }] } }),\n * },\n * });\n *\n * The returned value is the EXACT JSON shape the runtime's generic config\n * extractor emits and the apply engine consumes:\n * { __config: \"test-users\", users: { <name>: { email, password, seed } } }\n * `email` / `password` are the string or `null`; `seed` is `{}` when omitted.\n */\n\nimport type { TableTypes, Tables } from \"../db/env.js\";\n\n/** The `__config` discriminant the eval/apply reads to confirm a config/*.ts is\n * a test-users config. */\nexport const TEST_USERS_CONFIG_KIND = \"test-users\" as const;\n\n// ── Types derived from db/schema.ts ──────────────────────────────────────────\n//\n// `palbase-env.d.ts` (generated by makeEnvDts on every `palbase db types` and\n// on deploy) augments the `Tables` interface with, per table:\n// `row`, `insert`, `owner` (the auth.users FK column, or null) and `children`\n// (tables that FK this one, mapped to their FK column). Those last two are what\n// let the seed shape below be fully derived — the author never writes an owner\n// or a foreign key, because the apply engine fills both.\n\n/**\n * A table graph in the shape the env `Tables` interface carries. The\n * derivations below are parameterized over it (rather than reading the global\n * `Tables` directly) so they can be type-tested against a fixture graph without\n * augmenting the global interface — augmentation is program-wide and would leak\n * into every other type test.\n *\n * The `Record<keyof G, …>` constraint is deliberate: a plain\n * `Record<string, TableTypes>` would reject the `Tables` INTERFACE, which has\n * no index signature.\n */\nexport type TableGraph = Record<string, TableTypes>;\n\n/** The user-rooted tables of `G` — the ones a test user owns rows in directly. */\nexport type OwnedTablesOf<G extends Record<keyof G, TableTypes>> = {\n [T in keyof G]: G[T][\"owner\"] extends string ? T : never;\n}[keyof G];\n\n/**\n * One authored seed row for table `T` of graph `G`.\n *\n * Starts from the table's INSERT shape and removes the two columns the engine\n * owns: the owner column (set to the minted user) and `Via` — the FK column\n * this row hangs off its parent by, when the row is nested under one. What\n * remains is extended with the table's children, each an optional array of\n * their own seed rows.\n *\n * Recursion terminates because `makeEnvDts` drops self-FKs and cycle\n * back-edges when it emits `children`.\n *\n * Name collision note: if a table has a COLUMN whose name equals a CHILD\n * table's name, the intersection makes that key unusable (its type collapses).\n * That is a schema-naming problem the author sees at compile time; the apply\n * engine resolves the same ambiguity live in favour of the column, because it\n * introspects the real table.\n */\nexport type SeedRowFor<\n G extends Record<keyof G, TableTypes>,\n T extends keyof G,\n Via extends string = never,\n> = Omit<G[T][\"insert\"], (G[T][\"owner\"] & string) | Via> & {\n [C in keyof G[T][\"children\"]]?: Array<\n SeedRowFor<G, C & keyof G, G[T][\"children\"][C] & string>\n >;\n};\n\n/** The typed seed over graph `G`: top-level keys are user-rooted tables only;\n * everything else is reached by nesting under its parent. */\nexport type SeedFor<G extends Record<keyof G, TableTypes>> = {\n [T in OwnedTablesOf<G>]?: Array<SeedRowFor<G, T>>;\n};\n\n/** The serialized seed — what travels as JSON and what the engine receives. */\nexport type SeedJson = Record<string, Array<Record<string, unknown>>>;\n\n/**\n * The author-facing seed type. Falls back to the loose shape when `Tables` is\n * still empty (no `db/schema.ts`, or `palbase-env.d.ts` not generated yet) so\n * an unseeded project gets a usable DSL instead of an inscrutable `{}` error.\n */\nexport type Seed = [keyof Tables] extends [never] ? SeedJson : SeedFor<Tables>;\n\n// ── Author-facing options / compiled defs ────────────────────────────────────\n\n/**\n * The options for one declared test user.\n *\n * - `email` / `password`: supply BOTH to make this a fixture with stable\n * credentials (deploy materializes it, the app signs in with them), or\n * NEITHER to make it a template the server generates credentials for.\n * - `seed`: the user's data tree, derived from `db/schema.ts`. Top-level keys\n * are user-rooted tables; FK children nest inside their parent's rows.\n */\nexport interface TestUserOptions {\n email?: string;\n password?: string;\n /**\n * A verified phone for this fixture, E.164 (`+905551112233`). Requires\n * {@link TestUserOptions.otp}: nothing can receive an SMS at a fabricated\n * number, so a phone fixture without a knowable code is one no test could\n * ever sign in as.\n */\n phone?: string;\n /**\n * The fixed code this fixture's phone accepts. Honoured ONLY for the\n * `is_test` user it belongs to — the real rail is untouched, and no\n * verification is ever sent (or billed) for a fixture.\n */\n otp?: string;\n seed?: Seed;\n}\n\n/** The compiled, serializable test-user definition — the EXACT shape emitted to\n * JSON and consumed by the apply engine. */\nexport interface TestUserDef {\n /** Fixed login e-mail (fixture), or `null` when the server should generate one. */\n email: string | null;\n /** Fixed password (fixture), or `null` when the server should generate one. */\n password: string | null;\n /** Verified phone in E.164, or `null` for an e-mail-only fixture. */\n phone: string | null;\n /** The code that phone accepts, or `null` when there is no phone. */\n otp: string | null;\n /** The user's data tree; `{}` when nothing is seeded. */\n seed: SeedJson;\n}\n\n/** A test-users config: the discriminant + the declared users by name. */\nexport interface TestUsersConfig {\n __config: typeof TEST_USERS_CONFIG_KIND;\n users: Record<string, TestUserDef>;\n}\n\n/** The author-facing input to `defineTestUsers`. */\nexport interface TestUsersInput {\n users: Record<string, TestUserDef>;\n}\n\n// Template names ride into control-pg as the scenario name and into the CLI as\n// `--template <name>`; keep them to the same key vocabulary flags use.\nconst TEST_USER_NAME_RE = /^[a-zA-Z][a-zA-Z0-9_]*$/;\n\n// Deliberately permissive: the real address validation is palauth's. This only\n// catches the obvious typo at config-author time.\nconst EMAIL_RE = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/;\n\n// E.164: a leading + and 1..15 digits, first digit non-zero. Same shape palauth\n// validates with; this only catches the obvious authoring typo early.\nconst E164_RE = /^\\+[1-9]\\d{1,14}$/;\n\n// The fixed code is what a test types, so it must match what the UI accepts:\n// palauth mints 6-digit OTPs and the phone screens are 6-box.\nconst OTP_LENGTH = 6;\nconst OTP_RE = /^\\d{6}$/;\n\n/**\n * Minimum fixture password length.\n *\n * NOT palauth's 15-character single-factor floor: an `is_test` user is a\n * disposable harness identity excluded from MAU, and palauth applies neither\n * the length policy nor the HIBP check to the credentials it mints for one. We\n * still refuse an empty or one-character password so a typo can't produce a\n * fixture nobody can reason about.\n */\nconst MIN_PASSWORD_LENGTH = 8;\n\n/** True for a plain `{...}` object (not null, not an array). */\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\n/**\n * Structurally validate a seed and return its serializable form.\n *\n * Deliberately SHALLOW on meaning: we check that the seed is\n * `{ <table>: [ {...}, ... ] }` with non-empty arrays of plain objects, and\n * stop there. Whether a key inside a row is a COLUMN or a CHILD TABLE is\n * resolved by the apply engine against the LIVE schema — it introspects the\n * real table, so it is the only side that can tell them apart (and a jsonb\n * column may legitimately hold an array, which a deeper structural rule here\n * would misread as a nested child).\n */\nfunction normalizeSeed(seed: unknown, userName: string): SeedJson {\n if (seed === undefined) return {};\n if (!isPlainObject(seed)) {\n throw new Error(`testUser ${JSON.stringify(userName)}: seed must be { <table>: [ {...} ] }`);\n }\n const out: SeedJson = {};\n for (const [table, rows] of Object.entries(seed)) {\n if (!Array.isArray(rows)) {\n throw new Error(\n `testUser ${JSON.stringify(userName)}: seed.${table} must be an array of rows`,\n );\n }\n if (rows.length === 0) {\n throw new Error(\n `testUser ${JSON.stringify(userName)}: seed.${table} is empty — remove it or add a row`,\n );\n }\n for (const row of rows) {\n if (!isPlainObject(row)) {\n throw new Error(\n `testUser ${JSON.stringify(userName)}: every row in seed.${table} must be an object`,\n );\n }\n }\n out[table] = rows as Array<Record<string, unknown>>;\n }\n return out;\n}\n\n/**\n * Define a single test user. The NAME is supplied by the object key in\n * `defineTestUsers({ users: { <name>: testUser({...}) } })`, so `testUser()`\n * takes only the options.\n *\n * Validates eagerly (at config-author time):\n * - `email` and `password` are supplied together or not at all — half a\n * credential pair would silently degrade a fixture into a template.\n * - `email` looks like an address; `password` is at least\n * {@link MIN_PASSWORD_LENGTH} characters.\n * - `seed` is structurally `{ <table>: [ {...}, ... ] }` with non-empty arrays.\n *\n * The user NAME is validated by `defineTestUsers`, which is where it is known.\n */\nexport function testUser(opts: TestUserOptions = {}): TestUserDef {\n if (!isPlainObject(opts)) {\n throw new Error(\"testUser() expects { email?, password?, phone?, otp?, seed? }\");\n }\n const hasEmail = opts.email !== undefined;\n const hasPassword = opts.password !== undefined;\n if (hasEmail !== hasPassword) {\n throw new Error(\n \"testUser() needs email AND password together (a fixture with stable credentials) or neither (a template the server generates credentials for)\",\n );\n }\n\n let email: string | null = null;\n let password: string | null = null;\n if (hasEmail) {\n if (typeof opts.email !== \"string\" || !EMAIL_RE.test(opts.email)) {\n throw new Error(`testUser email ${JSON.stringify(opts.email)} is not a valid address`);\n }\n if (typeof opts.password !== \"string\" || opts.password.length < MIN_PASSWORD_LENGTH) {\n throw new Error(\n `testUser password must be at least ${MIN_PASSWORD_LENGTH} characters (got ${\n typeof opts.password === \"string\" ? opts.password.length : 0\n })`,\n );\n }\n email = opts.email;\n password = opts.password;\n }\n\n // A phone needs its code and vice versa. Refused here, at authoring time,\n // rather than at deploy: a phone fixture with no knowable code provisions\n // fine and then fails as a test hanging on an SMS that can never arrive.\n const hasPhone = opts.phone !== undefined;\n const hasOTP = opts.otp !== undefined;\n if (hasPhone !== hasOTP) {\n throw new Error(\n \"testUser() needs phone AND otp together — nothing can receive an SMS at a fabricated number, so a phone fixture without its fixed code can never be signed in as\",\n );\n }\n\n let phone: string | null = null;\n let otp: string | null = null;\n if (hasPhone) {\n if (typeof opts.phone !== \"string\" || !E164_RE.test(opts.phone)) {\n throw new Error(\n `testUser phone ${JSON.stringify(opts.phone)} must be E.164, e.g. \"+905551112233\"`,\n );\n }\n if (typeof opts.otp !== \"string\" || !OTP_RE.test(opts.otp)) {\n throw new Error(\n `testUser otp ${JSON.stringify(opts.otp)} must be ${OTP_LENGTH} digits`,\n );\n }\n phone = opts.phone;\n otp = opts.otp;\n }\n\n // The user name is not known here (it is the object key in defineTestUsers),\n // so seed errors are labelled with the e-mail when there is one.\n return { email, password, phone, otp, seed: normalizeSeed(opts.seed, email ?? \"<template>\") };\n}\n\n/**\n * Define a project's test users. The user NAME comes from each object key\n * (authors never repeat it). Returns the discriminated {@link TestUsersConfig}\n * the runtime config extractor serializes and the apply engine consumes.\n *\n * Validates eagerly:\n * - each name matches `^[a-zA-Z][a-zA-Z0-9_]*$` (the CLI's `--template <name>`\n * and control-pg's scenario name share this vocabulary).\n * - no two fixtures declare the SAME e-mail — they would race to\n * create-if-missing the one account and the second would silently adopt the\n * first one's data tree.\n *\n * @example\n * export default defineTestUsers({\n * users: { demo: testUser({ email: \"demo@test.local\", password: \"demo-password-1234\" }) },\n * });\n */\nexport function defineTestUsers(input: TestUsersInput): TestUsersConfig {\n if (!isPlainObject(input) || !isPlainObject(input.users)) {\n throw new Error(\"defineTestUsers expects { users: { <name>: testUser({...}) } }\");\n }\n const users: Record<string, TestUserDef> = {};\n const emails = new Map<string, string>();\n for (const name of Object.keys(input.users)) {\n if (!TEST_USER_NAME_RE.test(name)) {\n throw new Error(\n `test user name ${JSON.stringify(name)} is invalid — must start with a letter and contain only letters, digits, and underscores`,\n );\n }\n const def = input.users[name];\n if (def === undefined) continue;\n if (def.email !== null) {\n const lower = def.email.toLowerCase();\n const already = emails.get(lower);\n if (already !== undefined) {\n throw new Error(\n `test users ${JSON.stringify(already)} and ${JSON.stringify(name)} declare the same e-mail ${JSON.stringify(def.email)}`,\n );\n }\n emails.set(lower, name);\n }\n users[name] = def;\n }\n return { __config: TEST_USERS_CONFIG_KIND, users };\n}\n","/**\n * flags.ts — the feature-flag-definitions config-as-code DSL.\n *\n * `defineFlags({ flags })` is the third MODULE config-as-code surface (a sibling\n * of `config/storage.ts`'s `defineStorage` and `config/notifications.ts`'s\n * `defineNotifications`). A `config/flags.ts` file default-exports a\n * `defineFlags(...)` result; on deploy the br-pod evaluates it to JSON and\n * UPSERTS the declared flag DEFINITIONS into PalFlags (the user-flags module's\n * system-flags admin API) — create-or-update, idempotent. A live flag NOT in\n * config is NEVER auto-deleted (an orphan flag is harmless; upsert-only).\n *\n * Flags are DECLARATIVE: a flag is a typed project-wide DEFAULT (its key, type,\n * default value, an optional description, and — for string flags — an optional\n * list of allowed `variants`). The VALUE of a flag for a specific USER (a\n * per-user override / A-B assignment) is runtime state set via the SDK, NEVER in\n * git. `variants` here is part of the DEFINITION (the allowed values a string\n * flag may take), not a per-user assignment.\n *\n * NO SECRETS. Unlike notifications, a flag carries no credentials — this is the\n * simplest module config (pure declarative data).\n *\n * @example\n * import { defineFlags, flag } from \"@palbase/backend\";\n *\n * export default defineFlags({\n * flags: {\n * new_dashboard: flag({ type: \"boolean\", default: false, description: \"Roll out the new dashboard\" }),\n * max_uploads: flag({ type: \"number\", default: 10 }),\n * theme: flag({ type: \"string\", default: \"light\", variants: [\"light\", \"dark\", \"system\"] }),\n * limits: flag({ type: \"json\", default: { daily: 10, burst: 50 } }),\n * },\n * });\n *\n * The returned value is the EXACT JSON shape the runtime's generic config\n * extractor (`config_extract.js`) emits and the Go apply step parses:\n * { __config: \"flags\", flags: { <key>: { type, default, variants, description }, ... } }\n * `variants` is the allowed-values list for a string flag, or `null` (any\n * string). `description` is the doc string, or `null`. The apply step maps the\n * author-facing `type` to PalFlags' `value_type`: \"boolean\" → \"bool\" and\n * \"json\" → \"object\"; \"number\"/\"string\" pass through.\n */\n\n/** The `__config` discriminant the eval/apply reads to confirm a config/*.ts is\n * a flags config. Flags is `\"flags\"`. */\nexport const FLAGS_CONFIG_KIND = \"flags\" as const;\n\n/**\n * A flag's type. The author-facing vocabulary is `\"boolean\" | \"number\" |\n * \"string\" | \"json\"`; the apply step maps it to PalFlags' `value_type` enum —\n * `\"boolean\"` → `\"bool\"`, `\"json\"` → `\"object\"`, the other two pass through. The\n * SDK keeps the JS-natural names so the DSL reads cleanly.\n *\n * `\"json\"` is a structured (object) flag. It is named for what an author types —\n * a JSON object literal — and matches the `--type json` the CLI's per-user\n * override commands already use for this same server type.\n */\nexport type FlagType = \"boolean\" | \"number\" | \"string\" | \"json\";\n\n/** Any value expressible in JSON — what may appear INSIDE a `\"json\"` flag's default. */\nexport type FlagJsonValue = boolean | number | string | null | FlagJsonValue[] | { [key: string]: FlagJsonValue };\n\n/**\n * The default of a `\"json\"` flag: a JSON OBJECT. Not an array and not a scalar —\n * PalFlags' `object` value type accepts a JSON object at the top level only\n * (`validate.ValidateValueTypeMatch`), and it caps nesting depth at 3.\n */\nexport type FlagJsonObject = { [key: string]: FlagJsonValue };\n\n/** The runtime JSON value a flag's `default` may hold (matches {@link FlagType}). */\nexport type FlagValue = boolean | number | string | FlagJsonObject;\n\n/**\n * The author-facing options for a single flag — a UNION keyed on `type`, so\n * `default` is checked against the declared type at compile time and `variants`\n * is only accepted where it means something.\n *\n * - `type`: the flag's type — `\"boolean\" | \"number\" | \"string\" | \"json\"`.\n * - `default`: the project-wide default value. MUST match `type` (a `number`\n * default with `type: \"boolean\"` is a type error, and throws at runtime).\n * - `variants`: ONLY valid for `type: \"string\"` — the allowed values the string\n * flag may take (a DEFINITION, not a per-user assignment). When given, the\n * `default` MUST be one of the variants. Supplying `variants` on any other\n * type is a type error, and throws at runtime. (PalFlags rejects variants for\n * every non-string `value_type`, so accepting them here would only produce a\n * config the server refuses.)\n * - `description`: an optional human description of what the flag controls.\n */\nexport type FlagOptions =\n | {\n type: \"boolean\";\n default: boolean;\n variants?: never;\n conditions?: FlagCondition<boolean>[];\n description?: string;\n }\n | {\n type: \"number\";\n default: number;\n variants?: never;\n conditions?: FlagCondition<number>[];\n description?: string;\n }\n | {\n type: \"string\";\n default: string;\n variants?: string[];\n conditions?: FlagCondition<string>[];\n description?: string;\n }\n | {\n type: \"json\";\n default: FlagJsonObject;\n variants?: never;\n conditions?: FlagCondition<FlagJsonObject>[];\n description?: string;\n };\n\n/**\n * One targeting branch: the value this flag resolves to when `when` matches the\n * caller's client context. Branch ORDER is priority — the first match wins, and\n * a flag with no matching branch falls back to its `default`.\n *\n * `when` is a small expression over what the client declares about itself:\n *\n * ```\n * client.platform == 'ios' && client.app_version >= '2.0.0'\n * client.locale startsWith 'tr'\n * client.platform in ['ios', 'android']\n * ```\n *\n * Those are CLAIMS, not proof — the server treats them as attacker-controlled.\n * They select WHICH value a caller sees, never WHETHER they may see it, so a\n * condition must not be the thing standing between a user and something paid.\n */\n/**\n * The variables the server exposes. Mirrors `declaredVars` in\n * `modules/user-flags/internal/conditions/conditions.go`; the server rejects\n * anything it does not know, so the worst a stale copy here does is offer too\n * little.\n *\n * `client.*` is what the SDK reports about the caller. `percentile` and\n * `server.now` are DERIVED server-side and cannot be moved by a lying client,\n * which is what makes a rollout or a time window mean anything.\n */\ntype StringVar = \"client.platform\" | \"client.locale\";\ntype SemverVar = \"client.app_version\" | \"client.os_version\";\n\ntype EqualityOp = \"==\" | \"!=\";\n/** Ordering only where order exists — a platform string has none. */\ntype OrderedOp = EqualityOp | \"<\" | \"<=\" | \">\" | \">=\";\ntype TextOp = EqualityOp | \"startsWith\" | \"endsWith\" | \"contains\";\n\n/** A single-quoted literal. Quoting is the mistake people make most. */\ntype Quoted = `'${string}'`;\n\ntype Comparison =\n | `${StringVar} ${TextOp} ${Quoted}`\n | `${StringVar} in [${string}]`\n | `${SemverVar} ${OrderedOp} ${Quoted}`\n // Bare number: quoting it would make the server compare a string and the\n // rule would silently never match.\n | `percentile ${OrderedOp} ${number}`\n | `server.now ${OrderedOp} ${Quoted}`;\n\n/**\n * One expression: a comparison, optionally chained with `&&` / `||`, or a\n * parenthesised group.\n *\n * ONE level, and the limit is TypeScript's, not a preference. Unrolling a second\n * level produced `TS2590: union type too complex`, and the failure mode there is\n * the worst possible one: the checker gives up and the type silently degrades to\n * `string`, so NOTHING is checked while the code still compiles. Measured, not\n * assumed — the two-level version accepted `client.app_verison` without\n * complaint.\n *\n * So the FIRST term is fully checked and the rest of a chain is not. That is\n * where the mistakes are: a rule is usually one comparison, and a typo in the\n * first one is the common case. A typo after an `&&` still reaches the server,\n * which parses the real grammar and rejects it.\n *\n * A group's contents go unchecked for the same reason.\n */\nexport type FlagConditionExpression =\n | Comparison\n | `${Comparison} && ${string}`\n | `${Comparison} || ${string}`\n | `(${string})`;\n\nexport interface FlagCondition<V> {\n when: FlagConditionExpression;\n value: V;\n}\n\n/**\n * The COMPILED shape of a condition — the JSON actually emitted and parsed by\n * the Go apply step.\n *\n * `when` widens back to `string` here on purpose. The narrow type is an\n * authoring aid; once the expression has been trimmed and serialised it is just\n * text on the wire, and keeping the template-literal type would force a cast on\n * every string operation without checking anything the author had not already\n * been checked on.\n */\nexport interface CompiledFlagCondition<V> {\n when: string;\n value: V;\n}\n\n/**\n * The compiled, serializable flag definition — the EXACT shape emitted to JSON\n * and consumed by the Go apply step.\n *\n * - `type`: the author-facing type verbatim (`\"boolean\" | \"number\" | \"string\" |\n * \"json\"`) — the apply step maps it to PalFlags' `value_type`.\n * - `default`: the default value (matches `type`).\n * - `variants`: the allowed-values list for a string flag, or `null` (any).\n * - `description`: the doc string, or `null`.\n */\nexport interface FlagDef {\n type: FlagType;\n default: FlagValue;\n variants: string[] | null;\n /** Ordered targeting branches, or `null` when the flag is unconditional. */\n conditions: CompiledFlagCondition<FlagValue>[] | null;\n description: string | null;\n}\n\n/** A flags config definition: the discriminant + a map of flag key →\n * {@link FlagDef}. This is the value `defineFlags` returns and the runtime\n * config extractor serializes. */\nexport interface FlagsConfig {\n __config: typeof FLAGS_CONFIG_KIND;\n flags: Record<string, FlagDef>;\n}\n\n/** The author-facing input to `defineFlags`: a `flags` map whose keys are the\n * flag keys and whose values are `flag({...})` builders. */\nexport interface FlagsInput {\n flags: Record<string, FlagDef>;\n}\n\n// Flag keys mirror PalFlags' system-flag key rule (validate.keyNameRe): a\n// letter, then letters / digits / underscores. We validate eagerly so a key the\n// CLI/SDK accepts is a key PalFlags accepts (the apply step never has to reject).\nconst FLAG_KEY_RE = /^[a-zA-Z][a-zA-Z0-9_]*$/;\n\n/** Reports whether `value` matches the declared {@link FlagType}. */\nfunction valueMatchesType(type: FlagType, value: FlagValue): boolean {\n switch (type) {\n case \"boolean\":\n return typeof value === \"boolean\";\n case \"number\":\n // A finite number only — NaN / Infinity are not serializable as JSON.\n return typeof value === \"number\" && Number.isFinite(value);\n case \"string\":\n return typeof value === \"string\";\n case \"json\":\n // A plain JSON OBJECT — not null, not an array. PalFlags' `object` value\n // type decodes to map[string]any and rejects anything else, so an array or\n // a bare scalar default must fail here rather than at deploy time.\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n }\n}\n\n/**\n * Define a single flag. The flag KEY is supplied by the object key in\n * `defineFlags({ flags: { <key>: flag({...}) } })`, so `flag()` takes only the\n * options.\n *\n * Validates eagerly (at config-author time):\n * - `type` is one of `\"boolean\" | \"number\" | \"string\" | \"json\"`.\n * - `default` matches `type` (e.g. a `number` default with `type: \"boolean\"`\n * throws; a `\"json\"` default must be a plain object, not an array or scalar).\n * - `variants` is ONLY allowed for a string flag (variants on any other type\n * throws); each entry is a non-empty string; the `default` must be one of the\n * variants.\n *\n * Returns a normalized {@link FlagDef}: `variants` deduped-or-null,\n * `description` trimmed-or-null.\n */\nexport function flag(opts: FlagOptions): FlagDef {\n if (opts === null || typeof opts !== \"object\") {\n throw new Error(\"flag() expects { type, default, variants?, description? }\");\n }\n const { type } = opts;\n if (type !== \"boolean\" && type !== \"number\" && type !== \"string\" && type !== \"json\") {\n throw new Error(`flag type must be \"boolean\", \"number\", \"string\", or \"json\", got ${JSON.stringify(type)}`);\n }\n if (!valueMatchesType(type, opts.default)) {\n throw new Error(\n `flag default ${JSON.stringify(opts.default)} does not match type \"${type}\"`,\n );\n }\n\n let variants: string[] | null = null;\n if (opts.variants !== undefined) {\n if (opts.type !== \"string\") {\n throw new Error(`flag variants are only valid for type \"string\" (got type \"${type}\")`);\n }\n if (!Array.isArray(opts.variants)) {\n throw new Error(\"flag variants must be an array of strings\");\n }\n for (const v of opts.variants) {\n if (typeof v !== \"string\" || v.length === 0) {\n throw new Error(`flag variant ${JSON.stringify(v)} must be a non-empty string`);\n }\n }\n // Dedupe while preserving first-seen order. An empty array is meaningless\n // (no value would be allowed) — reject it rather than silently widening.\n variants = [...new Set(opts.variants)];\n if (variants.length === 0) {\n throw new Error(\"flag variants must be a non-empty list when supplied\");\n }\n // `opts` narrowed to the string member above, so `default` is a string.\n if (!variants.includes(opts.default)) {\n throw new Error(\n `flag default ${JSON.stringify(opts.default)} is not one of its variants [${variants\n .map((v) => JSON.stringify(v))\n .join(\", \")}]`,\n );\n }\n }\n\n let conditions: CompiledFlagCondition<FlagValue>[] | null = null;\n if (opts.conditions !== undefined) {\n if (!Array.isArray(opts.conditions)) {\n throw new Error(\"flag conditions must be an array of { when, value }\");\n }\n const compiled: CompiledFlagCondition<FlagValue>[] = [];\n for (const [i, branch] of opts.conditions.entries()) {\n if (branch === null || typeof branch !== \"object\") {\n throw new Error(`flag condition ${i} must be an object { when, value }`);\n }\n if (typeof branch.when !== \"string\" || branch.when.trim().length === 0) {\n throw new Error(`flag condition ${i} needs a non-empty \"when\" expression`);\n }\n // Every branch has to satisfy exactly what the default satisfies: a flag\n // must not be able to resolve, through any door, to a value it would have\n // rejected as its own default.\n if (!valueMatchesType(type, branch.value as FlagValue)) {\n throw new Error(\n `flag condition ${i} value ${JSON.stringify(branch.value)} does not match type \"${type}\"`,\n );\n }\n if (variants !== null && !variants.includes(branch.value as string)) {\n throw new Error(\n `flag condition ${i} value ${JSON.stringify(branch.value)} is not one of its variants [${variants\n .map((v) => JSON.stringify(v))\n .join(\", \")}]`,\n );\n }\n compiled.push({ when: branch.when.trim(), value: branch.value as FlagValue });\n }\n conditions = compiled.length > 0 ? compiled : null;\n }\n\n let description: string | null = null;\n if (opts.description !== undefined) {\n if (typeof opts.description !== \"string\") {\n throw new Error(\"flag description must be a string\");\n }\n const trimmed = opts.description.trim();\n description = trimmed.length > 0 ? trimmed : null;\n }\n\n return {\n type,\n default: opts.default,\n variants,\n conditions,\n description,\n };\n}\n\n/**\n * Define the feature-flag definitions for a project. The flag KEY comes from\n * each object key (authors never repeat the key). Returns the discriminated\n * {@link FlagsConfig} the runtime config extractor serializes and the Go apply\n * step UPSERTS into PalFlags.\n *\n * @example\n * export default defineFlags({\n * flags: { dark_mode: flag({ type: \"boolean\", default: false }) },\n * });\n */\nexport function defineFlags(input: FlagsInput): FlagsConfig {\n if (input === null || typeof input !== \"object\" || typeof input.flags !== \"object\") {\n throw new Error(\"defineFlags expects { flags: { <key>: flag({...}) } }\");\n }\n const flags: Record<string, FlagDef> = {};\n for (const key of Object.keys(input.flags)) {\n if (!FLAG_KEY_RE.test(key)) {\n throw new Error(\n `flag key ${JSON.stringify(key)} is invalid — must start with a letter and contain only letters, digits, and underscores`,\n );\n }\n const def = input.flags[key];\n if (def === undefined) continue;\n flags[key] = def;\n }\n return { __config: FLAGS_CONFIG_KIND, flags };\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 { UploadConfig } from \"./upload.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\" | \"QUERY\";\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 /** Direct-storage upload config — present ONLY on `@Upload` routes (the\n * `@Get`/`@Post`/… decorators never set it). Its presence is what MARKS a\n * route as an upload route through the whole pipeline (registry → flatten →\n * openapi → codegen). The bytes go client→storage directly; the method body\n * runs as the completion handler. See {@link UploadConfig} (decorators/upload.ts). */\n uploadConfig?: UploadConfig;\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 // `@UploadedObject()` — injects the uploaded object (completion input) on an\n // `@Upload` route. No schema (the shape is the fixed UploadedObject type).\n | \"uploadedObject\";\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 inferred throw site: the error CLASS name (e.g. \"TodoLocked\") and its\n * wire code (e.g. \"todo_locked\"). `status`, `hasData`, and the data JSON schema\n * are NOT carried here — they resolve from the error registry by `code` at\n * extract/openapi time (single source of truth). */\nexport interface ThrowDescriptor {\n name: string;\n code: 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 /** Error classes this route can throw, if inferred. Derived from the method\n * body + service call graph by the deploy stager's throw analysis and written\n * here via `recordThrows` (a generated top-level IIFE injected per controller,\n * the `recordReturn` twin), not by an author-written decorator. */\n throws?: ThrowDescriptor[];\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/** Symbol the per-method buffered throw descriptors are stored under while a\n * class's registry is being populated. The stager-injected `recordThrows` 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 `recordThrows`\n * writes through if the route already exists). Buffering on BOTH sides means a\n * fully-formed route entry always carries its throw descriptors — a raw-symbol\n * reader (the runtime) never has to re-merge. */\nconst THROWS_BUFFER: unique symbol = Symbol.for(\"palbase.backend.throwsBuffer\");\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 [THROWS_BUFFER]?: Record<string, ThrowDescriptor[]>;\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 // Same drain for buffered throw descriptors (the recordThrows-ran-first\n // ordering) — the route entry is complete the moment it's created.\n const throwsBuffer = carrier[THROWS_BUFFER];\n if (throwsBuffer && throwsBuffer[fnName] !== undefined) {\n route.throws = throwsBuffer[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/** Attach the inferred throw descriptors to the route for `fnName` (called by\n * the stager-injected IIFE that carries the throw analysis result — the\n * `recordReturn` twin). If the route does not exist yet, the descriptors are\n * buffered (THROWS_BUFFER) and drained into the route by `recordRoute` when the\n * method decorator runs. */\nexport function recordThrows(target: object, fnName: string, throws: ThrowDescriptor[]): 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.throws = throws;\n return;\n }\n if (!Object.prototype.hasOwnProperty.call(carrier, THROWS_BUFFER)) {\n carrier[THROWS_BUFFER] = {};\n }\n const throwsBuffer = carrier[THROWS_BUFFER];\n if (throwsBuffer) throwsBuffer[fnName] = throws;\n}\n\n/** Read the route metadata for a controller class (the deploy/dispatch entry\n * point). Applies any buffered return schemas + throw descriptors (for the\n * recordReturn/recordThrows-runs-before orderings) and returns a defensive copy\n * 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 const throwsBuffer = carrier[THROWS_BUFFER];\n if (throwsBuffer) {\n for (const route of routes) {\n const buffered = throwsBuffer[route.fnName];\n if (buffered && route.throws === undefined) {\n route.throws = buffered;\n }\n }\n }\n return routes.map((r) => ({\n ...r,\n params: r.params.slice(),\n ...(r.throws !== undefined ? { throws: r.throws.slice() } : {}),\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\";\nimport { getRoutes } from \"./registry.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/** The one path segment the platform owns. The isolate matches\n * `^/webhooks/([^/]+)$` on the raw request path BEFORE controller dispatch, so\n * anything a controller resolves to under it answers `404 webhook_not_found`\n * and never runs. */\nconst RESERVED_FIRST_SEGMENT = \"webhooks\";\n\n/**\n * Throw if `path` resolves under the reserved segment. Segments are compared the\n * way the isolate compares them — `split(\"/\").filter(Boolean)` — NOT by string\n * prefix, because empty segments collapse there: `@Controller(\"/\")` +\n * `@Post(\"/webhooks/x\")` composes to `//webhooks/x`, which the isolate serves as\n * `/webhooks/x`. A prefix check reads that as safe; the segment check does not.\n * `/webhooksy` stays allowed for the same reason — it is a different segment.\n *\n * Every verb is refused, not just the POST the isolate currently intercepts: the\n * reservation is of the URL namespace, so a `@Get(\"/webhooks/x\")` that happens\n * to work today would be silently shadowed the moment the isolate's method gate\n * widens. Refusing at build is recoverable; discovering it as a 404 is not.\n */\nfunction assertNotReserved(path: string, subject: string): void {\n const [first] = path.split(\"/\").filter(Boolean);\n if (first === RESERVED_FIRST_SEGMENT) {\n throw new Error(\n `${subject} resolves under the reserved /${RESERVED_FIRST_SEGMENT} path — ` +\n \"inbound webhooks are served there and would shadow this route\",\n );\n }\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(\\@QueryParams(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 // /webhooks/* belongs to the platform: the isolate matches the inbound\n // webhook route before controller dispatch, so a controller mounted here\n // would never receive a request. Silent shadowing is the failure mode this\n // whole change exists to remove, so refuse it at build.\n //\n // The COMPOSED path is what gets shadowed, not the base path. `@Controller(\"\")`\n // and `@Controller(\"/\")` both pass a base-path-only check while a\n // `@Post(\"/webhooks/stripe\")` inside them resolves to exactly the path the\n // isolate intercepts. Method decorators run BEFORE the class decorator (TS\n // evaluates members first), so every route this class declares is already in\n // the registry here — which is why the composed check can live at this one\n // seam instead of on the dispatch read path. The `@Controller(\"\") +\n // @Post(\"/webhooks/stripe\")` test is the lock on that ordering: if it ever\n // stopped holding, that test goes red.\n assertNotReserved(basePath, `@Controller(\"${basePath}\")`);\n for (const route of getRoutes(ctor)) {\n assertNotReserved(\n `${basePath}${route.subpath}`,\n `@${route.method}(\"${route.subpath}\") in @Controller(\"${basePath}\")`,\n );\n }\n\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","// Method decorators: `@Get` / `@Post` / `@Put` / `@Patch` / `@Delete` /\n// `@Query` declare a 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` — and it is PUBLIC API, not authoring sugar: the runtime\n * derives the operationId as `<controllerName>.<fnName>` (the dotted namespace\n * the SDKs expose as `pb.todos.list()`), so renaming this method renames every\n * client call. The flat verb+path id is only the fallback for routes with no\n * controller metadata. See openapi/discover.ts. */\nfunction makeMethodDecorator(method: HttpMethodUpper) {\n return function (subpath: string, options: RouteOptions = {}): MethodDecorator {\n // Runtime guard for stale pre-9.0.0 code: `@Query(zodSchema)` used to be\n // the query-string PARAM decorator. Applied against this SDK it would\n // silently record a garbage route (schema-as-subpath) and fail the deploy\n // with a baffling self-conflict — fail loud and name the migration instead.\n if (typeof subpath !== \"string\") {\n throw new Error(\n `@${method[0]}${method.slice(1).toLowerCase()}(subpath) expects a string subpath, got ${typeof subpath}.` +\n (method === \"QUERY\"\n ? \" If this is a zod schema on a method parameter: the query-string param decorator was renamed @QueryParams(schema) in @palbase/backend 9.0.0.\"\n : \"\"),\n );\n }\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/** `@Query(subpath, options?)` — declare an HTTP QUERY route (RFC 10008):\n * safe + idempotent like GET, body-carrying like POST. Input rides `@Body`. */\nexport const Query = makeMethodDecorator(\"QUERY\");\n","// `@Upload` — the single-method direct-storage upload decorator, and its\n// `@UploadedObject` parameter companion + `UploadConfig`/`UploadedObject` types.\n//\n// Unlike `@Get`/`@Post`/… (where bytes flow THROUGH the br-pod), an `@Upload`\n// route never sees the file bytes: the client uploads DIRECTLY to storage via a\n// signed URL the br-pod mints in an authorize pre-flight. The decorated method\n// body is the COMPLETION handler — it runs once, after storage confirms the\n// object landed (via an HMAC-signed completion webhook), and returns the typed\n// result the client awaits. There is exactly one method: it is BOTH the\n// authorize gate (its uploadConfig drives the guard + signed-URL pinning) AND\n// the completion handler (its body).\n//\n// On the wire the authorize pre-flight is a POST; what marks a route as an\n// upload route through the whole pipeline (registry → flatten → openapi →\n// codegen) is the PRESENCE of `uploadConfig` on the route — never a special HTTP\n// verb. The `@Get`/`@Post`/… decorators never set it.\nimport { recordRoute, recordParam } from \"./registry.js\";\nimport type { RouteOptions } from \"./registry.js\";\nimport type { StorageConfig } from \"../config/storage.js\";\n\n/** A legacy method decorator (`experimentalDecorators`): `(prototype, name,\n * descriptor)`. */\ntype MethodDecorator = (\n target: object,\n propertyKey: string | symbol,\n descriptor: PropertyDescriptor,\n) => void;\n\n/** A legacy parameter decorator: `(prototype, name, paramIndex)`. */\ntype ParameterDecorator = (\n target: object,\n propertyKey: string | symbol,\n parameterIndex: number,\n) => void;\n\n/**\n * Direct-storage upload settings for an `@Upload` route. The br-pod validates an\n * authorize request against these (size/type), then mints a signed upload URL\n * that PINS the limits so storage itself rejects an over-limit / wrong-type PUT\n * — the client cannot exceed what it declared.\n */\nexport interface UploadConfig {\n /**\n * Target bucket NAME. MUST exist in `config/storage.ts` `defineStorage(...)`.\n *\n * The bucket is the SINGLE SOURCE OF TRUTH for the size limit + MIME allowlist:\n * `bucket({ fileSizeLimit, allowedMimeTypes })`. Storage enforces those at the\n * actual PUT (the only guard a client cannot skip), so `@Upload` deliberately\n * does NOT take its own `maxSize`/`allowedTypes` — duplicating them here would\n * let a route declare a tighter limit than its bucket that storage would not\n * enforce (a real bypass: declare 10 bytes at authorize, then PUT up to the\n * bucket ceiling straight at the signed URL). One bucket, one limit, enforced.\n */\n bucket: string;\n /**\n * SERVER-side object key template. The client NEVER chooses the path. Tokens:\n * `{userId}` (authenticated user id), `{uploadId}` (server-minted), and\n * `{filename}` (the client-declared filename, sanitized). e.g.\n * `\"{userId}/{uploadId}-{filename}\"`.\n */\n pathTemplate: string;\n}\n\n/**\n * The uploaded object, injected into an `@Upload` method body by\n * `@UploadedObject()` once storage confirms the upload. Bytes are NOT present\n * (they went straight to storage) — this is the metadata the completion handler\n * persists.\n */\nexport interface UploadedObject {\n /** Server-minted id correlating authorize ↔ completion (idempotency key). */\n uploadId: string;\n /** Final object key in the bucket (rendered from `pathTemplate`). */\n path: string;\n /** Bucket the object landed in. */\n bucket: string;\n /** Object size in bytes, as reported by storage. */\n size: number;\n /** Object MIME type, as reported by storage. */\n contentType: string;\n}\n\n/**\n * `@Upload(subpath, config)` — declare a direct-storage upload route. The method\n * body is the completion handler; `config.uploadConfig` drives the authorize\n * guard + signed-URL pinning.\n *\n * @example\n * @Upload(\"/\", { bucket: \"docs\", pathTemplate: \"{userId}/{uploadId}-{filename}\" })\n * async upload(@UploadedObject() obj: UploadedObject, @User() user): Promise<DocResult> { ... }\n * // The size limit + MIME allowlist come from the \"docs\" bucket in\n * // config/storage.ts — storage enforces them at the PUT.\n */\nexport function Upload(\n subpath: string,\n config: UploadConfig & Pick<RouteOptions, \"auth\" | \"rateLimit\">,\n): MethodDecorator {\n const { auth, rateLimit, ...uploadConfig } = config;\n validateUploadConfigShape(uploadConfig);\n const options: RouteOptions = {\n uploadConfig,\n ...(auth !== undefined ? { auth } : {}),\n ...(rateLimit !== undefined ? { rateLimit } : {}),\n };\n return function (target, propertyKey) {\n // On the wire the authorize pre-flight is a POST; `uploadConfig` is what\n // marks this as an upload route downstream.\n recordRoute(target, String(propertyKey), \"POST\", subpath, options);\n };\n}\n\n/**\n * `@UploadedObject()` — inject the uploaded object (`: UploadedObject`) into an\n * `@Upload` method body (the completion input). Only valid on an `@Upload`\n * route; the bytes are NOT present (they went directly to storage), this is the\n * confirmed object's metadata.\n *\n * Co-located with the {@link UploadedObject} TYPE so a single exported name\n * `UploadedObject` carries BOTH the decorator value and the type annotation.\n */\nexport function UploadedObject(): ParameterDecorator {\n return function (target, propertyKey, parameterIndex) {\n recordParam(target, String(propertyKey), {\n index: parameterIndex,\n kind: \"uploadedObject\",\n });\n };\n}\n\n/**\n * Shape-validate an UploadConfig at decoration time (author-time failure beats a\n * silent deploy bug). Does NOT cross-check against the storage config — that is\n * `validateUploadAgainstStorage`, run at flatten/deploy time when the storage\n * config is available.\n */\nexport function validateUploadConfigShape(c: UploadConfig): void {\n if (c === null || typeof c !== \"object\") {\n throw new Error(\"@Upload config must be an object { bucket, pathTemplate, ... }\");\n }\n if (typeof c.bucket !== \"string\" || c.bucket.length === 0) {\n throw new Error(\"@Upload config.bucket must be a non-empty bucket name\");\n }\n if (typeof c.pathTemplate !== \"string\" || c.pathTemplate.length === 0) {\n throw new Error(\"@Upload config.pathTemplate must be a non-empty key template\");\n }\n}\n\n/**\n * Cross-check one `@Upload` route's uploadConfig against the project's\n * {@link StorageConfig}: the named bucket MUST exist in `defineStorage(...)`.\n * Throws a precise error so a typo fails at deploy, not at the first user upload.\n *\n * That is the ONLY cross-check: the size limit + MIME allowlist live on the\n * bucket (`bucket({ fileSizeLimit, allowedMimeTypes })`) and are enforced by\n * storage at the PUT. `@Upload` carries no `maxSize`/`allowedTypes` of its own,\n * so there is nothing to compare — one bucket, one limit, no drift.\n *\n * `routeLabel` is used only for error messages (e.g. `docs.upload`).\n */\nexport function validateUploadAgainstStorage(\n uploadConfig: UploadConfig,\n storage: StorageConfig,\n routeLabel: string,\n): void {\n const def = storage.buckets[uploadConfig.bucket];\n if (def === undefined) {\n const known = Object.keys(storage.buckets);\n throw new Error(\n `@Upload route ${routeLabel} targets bucket \"${uploadConfig.bucket}\" which is not declared in defineStorage(...). ` +\n (known.length ? `Known buckets: ${known.join(\", \")}.` : \"No buckets are declared.\"),\n );\n }\n}\n","// Parameter decorators: `@Body` / `@QueryParams` / `@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/** `@QueryParams(schema)` — inject the parsed query params, validated against\n * `schema`. */\nexport function QueryParams(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\n// NOTE: `@UploadedObject()` lives in decorators/upload.ts (co-located with the\n// `UploadedObject` TYPE) so a single exported name carries both the value (the\n// decorator) and the type — TS can only merge value+type under one export name\n// when both are declared in the SAME module.\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 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","// defineError — project-defined typed error classes + the module-global error\n// registry the OpenAPI spec twins join against.\n//\n// `defineError(code, status, dataSchema?)` returns an `HttpError` subclass whose\n// constructor is typed by the zod schema (`new TodoLocked({ retryAfter: 30 })`).\n// Each call self-registers `{ code, status, className, dataSchema }` in a\n// registry anchored on `globalThis` under `Symbol.for(...)` — mirroring the\n// ROUTES pattern — so the deploy bundle's registrations land on the single SDK\n// instance the extractor `require()`s. The registry is pre-seeded with the named\n// built-in classes (`NotFound`, `Conflict`, …) so throw inference can resolve\n// ad-hoc `throw new NotFound(...)` sites by their canonical wire codes.\n//\n// Duplicate code with a DIFFERENT shape (status OR converted data schema) is a\n// hard error at registration time (deploy fails loudly — error codes are\n// project-unique); structurally-identical re-registration is idempotent (each\n// controller BUNDLE carries its own copy of a shared models/errors.ts, so the\n// same defineError line legitimately runs once per bundle in one process).\nimport {\n OpenAPIRegistry,\n OpenApiGeneratorV31,\n extendZodWithOpenApi,\n} from \"@asteasolutions/zod-to-openapi\";\nimport { z, type ZodTypeAny } from \"zod\";\nimport { HttpError } from \"./errors.js\";\n\nextendZodWithOpenApi(z);\n\n/** One registered error: the wire code, HTTP status, the class name the\n * analyzer sees, the optional data payload schema, and whether it is one of the\n * pre-seeded built-in named classes. */\nexport interface RegisteredError {\n code: string;\n status: number;\n className: string;\n dataSchema?: ZodTypeAny;\n /** JSON.stringify of the converted JSON schema — equal digest ⇔ the spec\n * twins would emit an identical `data` schema for this error. */\n dataDigest?: string;\n builtin: boolean;\n}\n\n/** The cross-module-instance registry anchor (the pinned contract symbol). */\nconst ERROR_REGISTRY: unique symbol = Symbol.for(\"palbase.backend.errorRegistry\");\n\ninterface RegistryCarrier {\n [ERROR_REGISTRY]?: Map<string, RegisteredError>;\n}\n\n/** Get (creating + pre-seeding if absent) the project-global error registry,\n * keyed by wire code. Anchored on `globalThis` so every copy of the SDK in a\n * process shares the one registry. */\n/** The fixed data schemas the built-in named errors ship. Declared HERE (not in\n * errors.ts, which stays zod-free) because this is where the registry converts\n * them to JSON-schema for the spec — keying codegen's typed `error.data`. Only\n * the errors that semantically carry a payload have a schema; the rest are\n * data-less. `.int()` is preserved so the wire/codegen sees an integer. */\nconst BUILTIN_DATA_SCHEMAS: Record<string, ZodTypeAny> = {\n bad_request: z.object({\n fields: z.array(z.object({ field: z.string(), message: z.string() })),\n }),\n too_many_requests: z.object({ retryAfter: z.number().int() }),\n // Purchases (@RequireEntitlement / @Spend). Their payloads are what make a\n // paywall renderable on the client: WHICH entitlement was missing, and for a\n // spend the real ceiling and reset time rather than a guessed retry delay.\n entitlement_required: z.object({ entitlement: z.string().nullable() }),\n quota_exceeded: z.object({\n key: z.string(),\n scope: z.string(),\n window: z.string(),\n used: z.number().int(),\n reserved: z.number().int(),\n max: z.number().int(),\n remaining: z.number().int(),\n resetAt: z.string(),\n }),\n credit_insufficient: z.object({\n key: z.string(),\n balance: z.number().int(),\n reserved: z.number().int(),\n remaining: z.number().int(),\n }),\n};\n\nexport function getErrorRegistry(): Map<string, RegisteredError> {\n const g = globalThis as RegistryCarrier;\n if (!g[ERROR_REGISTRY]) {\n const m = new Map<string, RegisteredError>();\n for (const [code, status, className] of [\n [\"bad_request\", 400, \"BadRequest\"],\n [\"unauthorized\", 401, \"Unauthorized\"],\n [\"forbidden\", 403, \"Forbidden\"],\n [\"not_found\", 404, \"NotFound\"],\n [\"conflict\", 409, \"Conflict\"],\n [\"too_many_requests\", 429, \"TooManyRequests\"],\n // Thrown by the purchases decorators, so they are pre-seeded like the\n // other built-ins: a project never declares them, but every gated or\n // metered route must surface them as TYPED errors on the client.\n [\"entitlement_required\", 403, \"EntitlementRequired\"],\n [\"quota_exceeded\", 429, \"QuotaExceeded\"],\n [\"credit_insufficient\", 429, \"CreditInsufficient\"],\n ] as const) {\n const dataSchema = BUILTIN_DATA_SCHEMAS[code];\n m.set(code, {\n code,\n status,\n className,\n builtin: true,\n ...(dataSchema ? { dataSchema, dataDigest: digestOf(code, dataSchema) } : {}),\n });\n }\n g[ERROR_REGISTRY] = m;\n }\n return g[ERROR_REGISTRY];\n}\n\n/** Class returned for schema-bearing errors: ctor(data, message?). */\nexport interface DefinedErrorWithData<S extends ZodTypeAny> {\n new (data: z.input<S>, message?: string): HttpError;\n readonly code: string;\n readonly status: number;\n}\n\n/** Class returned for schema-less errors: ctor(message?). */\nexport interface DefinedError {\n new (message?: string): HttpError;\n readonly code: string;\n readonly status: number;\n}\n\n/**\n * Define a project error class. MUST be called with literal args (string\n * literal `code`, numeric literal `status`) at module top level — the deploy\n * stager's static analyzer reads those literals to resolve throw sites.\n *\n * @example\n * // models/todos/errors.ts\n * export const TodoLocked = defineError(\"todo_locked\", 409, z.object({ retryAfter: z.number() }));\n * // services/todo.service.ts\n * throw new TodoLocked({ retryAfter: 30 });\n */\nexport function defineError<S extends ZodTypeAny>(\n code: string,\n status: number,\n dataSchema: S,\n): DefinedErrorWithData<S>;\nexport function defineError(code: string, status: number): DefinedError;\nexport function defineError(code: string, status: number, dataSchema?: ZodTypeAny): unknown {\n if (!Number.isInteger(status) || status < 400 || status > 599) {\n throw new Error(\n `defineError: status for \"${code}\" must be a 4xx/5xx integer, got ${status} — ` +\n `error responses must not clobber success responses in the project spec.`,\n );\n }\n const registry = getErrorRegistry();\n const existing = registry.get(code);\n const className = defaultClassName(code);\n const dataDigest = dataSchema ? digestOf(code, dataSchema) : undefined;\n if (existing) {\n const sameShape =\n existing.status === status && !existing.builtin && existing.dataDigest === dataDigest;\n if (!sameShape) {\n throw new Error(\n `defineError: duplicate error code \"${code}\" with a different shape ` +\n `(existing: status ${existing.status}${existing.builtin ? \", built-in\" : \"\"}` +\n `${existing.status === status && !existing.builtin ? \", different data schema\" : \"\"}). ` +\n `Error codes are project-unique.`,\n );\n }\n }\n // Local factories so the class-constructor closures capture a NON-optional\n // schema binding (narrowing does not flow into closures created in a branch).\n const makeWithData = (schema: ZodTypeAny) =>\n class extends HttpError {\n static readonly code = code;\n static readonly status = status;\n constructor(data: unknown, message?: string) {\n super(status, code, message ?? humanize(code), schema.parse(data));\n this.name = className;\n }\n };\n const makeWithoutData = () =>\n class extends HttpError {\n static readonly code = code;\n static readonly status = status;\n constructor(message?: string) {\n super(status, code, message ?? humanize(code));\n this.name = className;\n }\n };\n const cls = dataSchema ? makeWithData(dataSchema) : makeWithoutData();\n Object.defineProperty(cls, \"name\", { value: className });\n registry.set(code, {\n code,\n status,\n className,\n builtin: false,\n ...(dataSchema ? { dataSchema } : {}),\n ...(dataDigest !== undefined ? { dataDigest } : {}),\n });\n return cls;\n}\n\n/** Convert a data schema through the SAME library the spec twins use and\n * return its JSON-schema digest (the duplicate-shape comparison key). Doubles\n * as the self-containment guard: a schema carrying `.openapi(refId)` metadata\n * (top-level or nested) converts to `$ref` pointers into components the\n * project spec never emits — a dangling ref every spec consumer would choke\n * on — so it is rejected here, at the definition site, with a fixable message. */\nfunction digestOf(code: string, dataSchema: ZodTypeAny): string {\n const TMP_REF = \"__PalbaseErrorDataDigest\";\n const tmpRegistry = new OpenAPIRegistry();\n // Wrap the schema as a property — exactly how the envelope embeds it — so a\n // TOP-LEVEL .openapi(refId) is not masked by the registration refId and\n // surfaces as the same $ref the real emission would produce.\n tmpRegistry.register(TMP_REF, z.object({ data: dataSchema }).openapi(TMP_REF));\n const generated = new OpenApiGeneratorV31(tmpRegistry.definitions).generateComponents();\n const out = generated.components?.schemas?.[TMP_REF];\n const digest = JSON.stringify(out ?? null);\n if (digest.includes('\"$ref\"')) {\n throw new Error(\n `defineError: dataSchema for \"${code}\" carries .openapi(refId) metadata — ` +\n `it would emit dangling $ref pointers in the project spec. ` +\n `Use a plain zod schema (z.object({...})) without .openapi(...).`,\n );\n }\n return digest;\n}\n\n/** \"todo_locked\" → \"TodoLocked\" (used as Error.name; the source class NAME the\n * analyzer sees is whatever the user assigned the const to — they should match\n * by convention, and the descriptor carries the analyzed const name anyway). */\nfunction defaultClassName(code: string): string {\n return code\n .split(\"_\")\n .map((p) => p.charAt(0).toUpperCase() + p.slice(1))\n .join(\"\");\n}\n\n/** \"todo_locked\" → \"Todo locked\" — the default human-readable message. */\nfunction humanize(code: string): string {\n const s = code.replace(/_/g, \" \");\n return s.charAt(0).toUpperCase() + s.slice(1);\n}\n","// @Webhook / @On — the inbound-webhook half of the decorator surface.\n//\n// Mirrors decorators/controller.ts exactly: symbol-keyed, non-enumerable\n// metadata on the constructor plus a `__palbase` discriminant, read back by a\n// resolver. The resolver is the ONLY translation point — it returns the shape\n// the runtime already consumes, so the isolate's dispatch and the signature\n// engine's cross-binding golden are untouched by the authoring change.\nimport type { WebhookMeta, WebhookProvider } from \"../webhook.js\";\n\n/** A signature scheme spelled out, for a service with no preset. The presets\n * (`provider`) are named configurations of this same shape. */\nexport interface SignatureSpec {\n /** Header carrying the signature. */\n header: string;\n /** Stripped before comparison (e.g. `sha256=`). Omit when absent. */\n prefix?: string;\n algo: \"hmac-sha256\" | \"hmac-sha1\";\n encoding: \"hex\" | \"base64\";\n /** What the HMAC covers. Exactly two placeholders: `{body}` and `{ts}`.\n * Everything else is literal. `{ts}` requires `timestampHeader` and brings\n * the five-minute replay window with it. */\n signs: string;\n timestampHeader?: string;\n}\n\nexport interface WebhookOptions {\n provider?: WebhookProvider;\n signature?: SignatureSpec;\n /** Env-var REFERENCE for the signing secret — the platform never holds it. */\n secret: { env: string };\n}\n\nexport type WebhookEventHandler = (event: unknown, meta: WebhookMeta) => Promise<void>;\n\nexport interface ResolvedWebhook {\n provider?: WebhookProvider;\n signature?: SignatureSpec;\n secret: { env: string };\n events: Record<string, WebhookEventHandler>;\n}\n\nexport const WEBHOOK_META: unique symbol = Symbol.for(\"palbase.backend.webhookMeta\");\nexport const WEBHOOK_EVENTS: unique symbol = Symbol.for(\"palbase.backend.webhookEvents\");\n\ninterface EventEntry {\n event: string;\n fnName: string;\n}\n\ninterface WebhookCarrier {\n __palbase?: \"webhook\";\n [WEBHOOK_META]?: WebhookOptions;\n [WEBHOOK_EVENTS]?: EventEntry[];\n}\n\nfunction carrierOf(ctor: object): WebhookCarrier {\n return ctor as WebhookCarrier;\n}\n\n/** Mark a class as an inbound webhook. The mount name is the FILE name — there\n * is deliberately no `name` option, because the file name IS the public URL. */\nexport function Webhook(options: WebhookOptions) {\n return function <T extends abstract new (...args: never[]) => object>(ctor: T): T {\n const carrier = carrierOf(ctor);\n Object.defineProperty(carrier, WEBHOOK_META, {\n value: options,\n enumerable: false,\n configurable: true,\n writable: false,\n });\n Object.defineProperty(carrier, \"__palbase\", {\n value: \"webhook\",\n enumerable: false,\n configurable: true,\n writable: false,\n });\n return ctor;\n };\n}\n\n/** Bind a method to one event name. Any string is valid: presets provide\n * autocomplete, never a constraint, because we do not carry provider catalogs. */\nexport function On(event: string) {\n return function (target: object, fnName: string | symbol): void {\n // Method decorators receive the PROTOTYPE; metadata belongs on the ctor.\n const carrier = carrierOf((target as { constructor: object }).constructor);\n const existing = carrier[WEBHOOK_EVENTS];\n const entries: EventEntry[] = existing ? [...existing] : [];\n entries.push({ event, fnName: String(fnName) });\n Object.defineProperty(carrier, WEBHOOK_EVENTS, {\n value: entries,\n enumerable: false,\n configurable: true,\n writable: false,\n });\n };\n}\n\n/** Read a decorated class back as the resolved config the runtime consumes.\n * Every misuse throws HERE, at build time, rather than becoming a webhook that\n * answers 200 and does nothing. */\nexport function getWebhookConfig(ctor: object): ResolvedWebhook {\n const carrier = carrierOf(ctor);\n const meta = carrier[WEBHOOK_META];\n const entries = carrier[WEBHOOK_EVENTS] ?? [];\n\n if (!meta) {\n throw new Error(\n `@On used on a class that is not decorated with @Webhook (${(ctor as { name?: string }).name ?? \"anonymous\"})`,\n );\n }\n if (!meta.provider && !meta.signature) {\n throw new Error(\n \"@Webhook requires either a `provider` preset or an explicit `signature` — \" +\n \"an endpoint with no verification would accept forged deliveries\",\n );\n }\n // EITHER, not both. The isolate picks `provider` when both are present and\n // never looks at `signature`, so a tenant that wrote both gets deliveries\n // verified against a scheme they did not choose — silently, and with no way to\n // tell from the outside which one ran. Ambiguity about WHICH signature check\n // guards an endpoint is not something to resolve by precedence.\n if (meta.provider && meta.signature) {\n throw new Error(\n \"@Webhook declares BOTH a `provider` preset and an explicit `signature` — \" +\n \"these are alternatives; keep the one that describes the sender, because only `provider` would be used\",\n );\n }\n if (meta.signature) {\n const sig = meta.signature;\n // Mirrors Go's NewTemplateVerifier (internal/webhook/verify.go). Both sides\n // reject the same specs; this one rejects at build, which is the only place\n // a tenant can still act on it.\n if (!sig.header) {\n throw new Error(\"@Webhook signature requires `header` — the header the signature arrives in\");\n }\n if (sig.algo !== \"hmac-sha256\" && sig.algo !== \"hmac-sha1\") {\n throw new Error(`@Webhook signature has an unsupported algo \"${sig.algo}\"`);\n }\n if (sig.encoding !== \"hex\" && sig.encoding !== \"base64\") {\n throw new Error(`@Webhook signature has an unsupported encoding \"${sig.encoding}\"`);\n }\n if (!sig.signs?.includes(\"{body}\")) {\n throw new Error(\"@Webhook signature `signs` must contain {body} — signing a constant is not a signature\");\n }\n if (sig.signs.includes(\"{ts}\") && !sig.timestampHeader) {\n throw new Error(\"@Webhook signature uses {ts} but declares no `timestampHeader` to read it from\");\n }\n }\n if (!meta.secret?.env) {\n throw new Error(\"@Webhook requires `secret: { env: \\\"VAR_NAME\\\" }`\");\n }\n if (entries.length === 0) {\n throw new Error(\"@Webhook requires at least one @On handler\");\n }\n\n const instance = new (ctor as new () => Record<string, WebhookEventHandler>)();\n // Object.create(null), not {} — event names are free-form, so `@On(\"constructor\")`\n // and `@On(\"toString\")` are legal. A plain literal inherits those keys from\n // Object.prototype, and the duplicate check below would reject the FIRST and\n // only handler for them as a redeclaration.\n const events: Record<string, WebhookEventHandler> = Object.create(null) as Record<string, WebhookEventHandler>;\n for (const entry of entries) {\n if (Object.prototype.hasOwnProperty.call(events, entry.event)) {\n throw new Error(`@On(\"${entry.event}\") declared twice on the same webhook`);\n }\n events[entry.event] = (event, metaArg) =>\n (instance[entry.fnName] as WebhookEventHandler).call(instance, event, metaArg);\n }\n\n return {\n ...(meta.provider ? { provider: meta.provider } : {}),\n ...(meta.signature ? { signature: meta.signature } : {}),\n secret: meta.secret,\n events,\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 /** Environment-scoped env vars. */\n env: Record<string, string>;\n /** The globally unique Environment runtime identifier. */\n environmentId: string;\n}\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 */\nexport function 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","// @Job — the cron half of the decorator surface. Same metadata mechanism as\n// @Webhook/@Controller. The job's NAME is not here on purpose: it is the file\n// name, which is also what the Temporal schedule id is built from. Two names\n// with nothing reconciling them is what this replaces.\nimport type { JobMeta } from \"../job.js\";\nimport { validateCronExpression } from \"../job.js\";\n\nexport interface JobOptions {\n /** Cron expression, five fields (e.g. \"0 3 * * *\"). */\n schedule: string;\n /** Execution timeout in seconds. Defaults to 30, ceiling 300 (sandbox limit). */\n timeout?: number;\n}\n\nexport interface ResolvedJob {\n schedule: string;\n timeout: number;\n handler: (meta: JobMeta) => Promise<void>;\n}\n\nconst DEFAULT_TIMEOUT_SECONDS = 30;\nconst MAX_TIMEOUT_SECONDS = 300;\n\nexport const JOB_META: unique symbol = Symbol.for(\"palbase.backend.jobMeta\");\n\ninterface JobCarrier {\n __palbase?: \"job\";\n [JOB_META]?: JobOptions;\n}\n\nexport function Job(options: JobOptions) {\n return function <T extends abstract new (...args: never[]) => object>(ctor: T): T {\n const carrier = ctor as unknown as JobCarrier;\n Object.defineProperty(carrier, JOB_META, {\n value: options,\n enumerable: false,\n configurable: true,\n writable: false,\n });\n Object.defineProperty(carrier, \"__palbase\", {\n value: \"job\",\n enumerable: false,\n configurable: true,\n writable: false,\n });\n return ctor;\n };\n}\n\nexport function getJobConfig(ctor: object): ResolvedJob {\n const meta = (ctor as JobCarrier)[JOB_META];\n if (!meta) {\n throw new Error(\n `getJobConfig on a class with no @Job decorator (${(ctor as { name?: string }).name ?? \"anonymous\"})`,\n );\n }\n if (!meta.schedule || meta.schedule.trim() === \"\") {\n throw new Error(\"@Job requires a `schedule` cron expression\");\n }\n const cronError = validateCronExpression(meta.schedule);\n if (cronError) {\n throw new Error(`@Job has an invalid cron schedule: ${cronError}`);\n }\n\n const timeout = meta.timeout ?? DEFAULT_TIMEOUT_SECONDS;\n if (!Number.isInteger(timeout) || timeout <= 0) {\n throw new Error(\"@Job `timeout` must be a positive whole number of seconds\");\n }\n if (timeout > MAX_TIMEOUT_SECONDS) {\n throw new Error(`@Job \\`timeout\\` exceeds the ${MAX_TIMEOUT_SECONDS}s sandbox ceiling`);\n }\n\n const instance = new (ctor as new () => { run?: (meta: JobMeta) => Promise<void> })();\n if (typeof instance.run !== \"function\") {\n throw new Error(\"@Job class must declare an async run() method\");\n }\n const run = instance.run.bind(instance);\n\n return { schedule: meta.schedule, timeout, handler: run };\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 /** Environment-scoped env vars. */\n env: Record<string, string>;\n /** The globally unique Environment runtime identifier. */\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":["raw","raw","bucket","raw","isPlainObject","carrierOf","carrierOf","auth","storage","registry","carrierOf","import_zod"]}
|