@lunora/codegen 1.0.0-alpha.304 → 1.0.0-alpha.306
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.mjs +1 -1
- package/dist/packem_shared/SCHEMA_SNAPSHOT_FILENAME-dqvBdE2E.mjs +11 -0
- package/dist/packem_shared/{emitAgents-D_UUdNe1.mjs → emitAgents-CVN1D17z.mjs} +1 -1
- package/dist/packem_shared/{emitApp-CJe2L06A.mjs → emitApp-BOUdd-2R.mjs} +109 -21
- package/dist/packem_shared/{emitShard-zun44Krh.mjs → emitShard-D_dkDtuY.mjs} +1 -1
- package/dist/packem_shared/{shard-QKj9rp3r.mjs → shard-Av4rUyYS.mjs} +2 -2
- package/dist/packem_shared/{shard-runtime-BX0xmo0P.mjs → shard-runtime-CkTgY8tL.mjs} +1 -1
- package/package.json +3 -3
- package/dist/packem_shared/SCHEMA_SNAPSHOT_FILENAME-B8fjAt1q.mjs +0 -11
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{APP_METHOD_CAPABILITIES as k}from"./CAPABILITY_PROBES-brcmKenl.mjs";import{i as S}from"./schema-BgM8A3XV.mjs";import{G as E}from"./shared-DnCokNcE.mjs";const D={configKey:"vectors",doc:"Wire the Vectorize index map backing `ctx.vectors`.",method:"vectors"},
|
|
1
|
+
import{APP_METHOD_CAPABILITIES as k}from"./CAPABILITY_PROBES-brcmKenl.mjs";import{i as S}from"./schema-BgM8A3XV.mjs";import{G as E}from"./shared-DnCokNcE.mjs";const D={configKey:"vectors",doc:"Wire the Vectorize index map backing `ctx.vectors`.",method:"vectors"},m=e=>[...k.filter(({key:r})=>e.capabilities.has(r)).map(({appMethod:r})=>r),...e.hasVectors?[D]:[]],g=e=>m(e).length>0,v=e=>(e.emailAgents?.length??0)>0,d=e=>e.tables.some(r=>S(r)),R=e=>e.hasScheduler?`
|
|
2
2
|
/** Resolve the \`SchedulerDO\`-backed scheduler for this env; \`undefined\` until the namespace is wired. */
|
|
3
3
|
private resolveScheduler(env: Env): ReturnType<typeof createScheduler> | undefined {
|
|
4
4
|
const namespace = this.schedulerDeclaration?.namespace(env);
|
|
@@ -332,7 +332,7 @@ const buildGlobalCdcApplier =
|
|
|
332
332
|
|
|
333
333
|
return request.changes.length;
|
|
334
334
|
};
|
|
335
|
-
`:"",C=e=>[...e.hasStorage?["/** `.storage(...)` declaration — one bucket (required) plus optional extra named buckets and signed-URL config. Backs `ctx.storage` AND the studio file browser. */\ninterface StorageDeclaration<Env> {\n /** The default R2 bucket binding (the bare `ctx.storage`). */\n bucket: Selector<Env, R2BucketLike>;\n /** Extra named buckets, reached via `ctx.storage.bucket(\"name\")` and the studio's bucket picker. */\n buckets?: Record<string, Selector<Env, R2BucketLike>>;\n /** Public base URL signed/public object URLs resolve against. Omit it and `ctx.storage` in a mutation, action or HTTP handler (and the studio's copy-URL) signs against the origin the request reached the worker on — no per-environment value to ship. Queries get no such fallback (a live query re-runs with no request behind it), so a query that signs URLs needs this set. */\n publicBaseUrl?: Selector<Env, string>;\n /** R2 S3-API credentials (`{ accountId, accessKeyId, secretAccessKey, bucket, jurisdiction? }`) enabling `ctx.storage.getPresignedUrl` — native S3 presigned URLs that hit R2 directly, bypassing the worker. Omit to use only the worker-signed `getSignedUrl` path. */\n s3?: Selector<Env, R2S3Credentials>;\n /** HMAC secret for signed URLs. */\n signingSecret?: Selector<Env, string>;\n}"]:[],...e.hasScheduler?["/** `.scheduler(...)` declaration — the `SchedulerDO` namespace. Backs `ctx.scheduler` AND the studio's scheduled-jobs view. The origin its callbacks dispatch back to is not declared here: the DO reads `env.LUNORA_ORIGIN_URL` at fire time, because a caller-supplied dispatch target would be an SSRF vector. */\ninterface SchedulerDeclaration<Env> {\n /** The `SchedulerDO` namespace binding (typically `env.SCHEDULER`). */\n namespace: Selector<Env, DurableObjectNamespaceLike & ShardNamespaceLike>;\n}"]:[],...e.hasGlobal?["/** `.global(...)` declaration — the D1 binding backing `.global()` tables. Backs cross-tenant `ctx.db` reads/writes AND the studio's global data browser. */\ninterface GlobalDeclaration<Env> {\n /** The D1 binding (typically `env.DB`). */\n d1: Selector<Env, D1DatabaseLike>;\n /** The worker origin used to fan reverse cross-backend relations across shards. Without it, such a relation throws a clear error. */\n origin?: Selector<Env, string>;\n}"]:[],...e.hasHyperdriveGlobal?['/** `.hyperdriveGlobal(...)` declaration — backs `.global({ backend: "hyperdrive" })` tables on a Postgres/MySQL database via Hyperdrive. Stays reactive: the writer is injected as `globalDb` and the broadcast hook drives live queries. */\ninterface HyperdriveGlobalDeclaration<Env> {\n /** The Hyperdrive engine — selects the Postgres or MySQL dialect. */\n engine: HyperdriveEngine;\n /** Build the `SqlExec` from `env` — e.g. `buildPgExec(fromPostgresJs(postgres(env.HYPERDRIVE.connectionString)))`. Cache the driver on the DO instance; rebuild lazily after hibernation. */\n exec: (env: Env) => SqlExec;\n /** The worker origin used to fan reverse cross-backend relations across shards. Without it, such a relation throws a clear error. */\n origin?: Selector<Env, string>;\n}']:[],...e.hasAuth?['/** `.auth(...)` declaration — better-auth options plus the storage the adapter reads. Give it `d1` (the default) or `namespace` (a Durable Object that hosts the auth tables), never both. The builder owns the lazy build + `ensureMigrated` dance and wires `authHandler` / `resolveIdentity` / `authAdmin`. */\ninterface AuthDeclaration<Env> {\n /** The D1 binding the auth SQL adapter is wired over (via `lunoraD1Adapter`). Omit only when using `namespace`. */\n d1?: Selector<Env, unknown>;\n /** Shared secret the worker presents on the object\'s internal session route. REQUIRED with `namespace`: the binding is reachable from any worker bound to it, so the secret — not the binding — is the authorization boundary. Without it identity resolution fails closed. */\n internalSecret?: Selector<Env, string>;\n /** Name of the Durable Object instance holding the auth tables. Defaults to `"auth"`. Set it to run separate auth objects (per deployment, per tenant) off one namespace. */\n objectName?: Selector<Env, string>;\n /** The auth Durable Object namespace — the DO-backed mode. Needed for `@better-auth/scim`, which requires native transactions that D1 has none of. The object owns the auth tables, so `/api/auth/*` and identity resolution both go through it. Typed as `AuthNamespaceLike` because `createDoAuthWiring` resolves through `idFromName` + `get` and has no `getByName` fallback — both members are load-bearing here, and `ShardNamespaceLike` leaves both optional. */\n namespace?: Selector<Env, AuthNamespaceLike>;\n /** Build the better-auth options from `env` (secret, plugins, email/password, …). */\n options: (env: Env) => LunoraAuthOptions;\n}']:[]],O=e=>[...e.hasAccess?[" private accessSelector?: Selector<Env, CreateAccessResolverOptions | undefined>;"]:[]," private adminToken?: Selector<Env, string>;",...e.hasAuth?[" private authDeclaration?: AuthDeclaration<Env>;"]:[]," private cdcEnabled = false;"," private reactiveCacheConfig: boolean | { maxBytes?: number; maxEntries?: number } = false;",' private maxRelationKeysLimit?: ShardConfig["maxRelationKeys"];',' private observabilitySink?: ShardConfig["observability"];',' private relationExistsPushDownMode?: ShardConfig["relationExistsPushDown"];'," private readonly extendFns: ((env: Env, derived: Readonly<WorkerOptions>) => Partial<WorkerOptions>)[] = [];",...e.hasGlobal?[" private globalDeclaration?: GlobalDeclaration<Env>;"]:[],...e.hasHyperdriveGlobal?[" private hyperdriveGlobalDeclaration?: HyperdriveGlobalDeclaration<Env>;"]:[]," private httpRouterApp?: HttpRouterLike;"," private readonly routeMap: Record<string, Route> = {};",...e.hasScheduler?[" private schedulerDeclaration?: SchedulerDeclaration<Env>;"]:[],...
|
|
335
|
+
`:"",C=e=>[...e.hasStorage?["/** `.storage(...)` declaration — one bucket (required) plus optional extra named buckets and signed-URL config. Backs `ctx.storage` AND the studio file browser. */\ninterface StorageDeclaration<Env> {\n /** The default R2 bucket binding (the bare `ctx.storage`). */\n bucket: Selector<Env, R2BucketLike>;\n /** Extra named buckets, reached via `ctx.storage.bucket(\"name\")` and the studio's bucket picker. */\n buckets?: Record<string, Selector<Env, R2BucketLike>>;\n /** Public base URL signed/public object URLs resolve against. Omit it and `ctx.storage` in a mutation, action or HTTP handler (and the studio's copy-URL) signs against the origin the request reached the worker on — no per-environment value to ship. Queries get no such fallback (a live query re-runs with no request behind it), so a query that signs URLs needs this set. */\n publicBaseUrl?: Selector<Env, string>;\n /** R2 S3-API credentials (`{ accountId, accessKeyId, secretAccessKey, bucket, jurisdiction? }`) enabling `ctx.storage.getPresignedUrl` — native S3 presigned URLs that hit R2 directly, bypassing the worker. Omit to use only the worker-signed `getSignedUrl` path. */\n s3?: Selector<Env, R2S3Credentials>;\n /** HMAC secret for signed URLs. */\n signingSecret?: Selector<Env, string>;\n}"]:[],...e.hasScheduler?["/** `.scheduler(...)` declaration — the `SchedulerDO` namespace. Backs `ctx.scheduler` AND the studio's scheduled-jobs view. The origin its callbacks dispatch back to is not declared here: the DO reads `env.LUNORA_ORIGIN_URL` at fire time, because a caller-supplied dispatch target would be an SSRF vector. */\ninterface SchedulerDeclaration<Env> {\n /** The `SchedulerDO` namespace binding (typically `env.SCHEDULER`). */\n namespace: Selector<Env, DurableObjectNamespaceLike & ShardNamespaceLike>;\n}"]:[],...e.hasGlobal?["/** `.global(...)` declaration — the D1 binding backing `.global()` tables. Backs cross-tenant `ctx.db` reads/writes AND the studio's global data browser. */\ninterface GlobalDeclaration<Env> {\n /** The D1 binding (typically `env.DB`). */\n d1: Selector<Env, D1DatabaseLike>;\n /** The worker origin used to fan reverse cross-backend relations across shards. Without it, such a relation throws a clear error. */\n origin?: Selector<Env, string>;\n}"]:[],...e.hasHyperdriveGlobal?['/** `.hyperdriveGlobal(...)` declaration — backs `.global({ backend: "hyperdrive" })` tables on a Postgres/MySQL database via Hyperdrive. Stays reactive: the writer is injected as `globalDb` and the broadcast hook drives live queries. */\ninterface HyperdriveGlobalDeclaration<Env> {\n /** The Hyperdrive engine — selects the Postgres or MySQL dialect. */\n engine: HyperdriveEngine;\n /** Build the `SqlExec` from `env` — e.g. `buildPgExec(fromPostgresJs(postgres(env.HYPERDRIVE.connectionString)))`. Cache the driver on the DO instance; rebuild lazily after hibernation. */\n exec: (env: Env) => SqlExec;\n /** The worker origin used to fan reverse cross-backend relations across shards. Without it, such a relation throws a clear error. */\n origin?: Selector<Env, string>;\n}']:[],...e.hasAuth?['/** `.auth(...)` declaration — better-auth options plus the storage the adapter reads. Give it `d1` (the default) or `namespace` (a Durable Object that hosts the auth tables), never both. The builder owns the lazy build + `ensureMigrated` dance and wires `authHandler` / `resolveIdentity` / `authAdmin`. */\ninterface AuthDeclaration<Env> {\n /** The D1 binding the auth SQL adapter is wired over (via `lunoraD1Adapter`). Omit only when using `namespace`. */\n d1?: Selector<Env, unknown>;\n /** Shared secret the worker presents on the object\'s internal session route. REQUIRED with `namespace`: the binding is reachable from any worker bound to it, so the secret — not the binding — is the authorization boundary. Without it identity resolution fails closed. */\n internalSecret?: Selector<Env, string>;\n /** Name of the Durable Object instance holding the auth tables. Defaults to `"auth"`. Set it to run separate auth objects (per deployment, per tenant) off one namespace. */\n objectName?: Selector<Env, string>;\n /** The auth Durable Object namespace — the DO-backed mode. Needed for `@better-auth/scim`, which requires native transactions that D1 has none of. The object owns the auth tables, so `/api/auth/*` and identity resolution both go through it. Typed as `AuthNamespaceLike` because `createDoAuthWiring` resolves through `idFromName` + `get` and has no `getByName` fallback — both members are load-bearing here, and `ShardNamespaceLike` leaves both optional. */\n namespace?: Selector<Env, AuthNamespaceLike>;\n /** Build the better-auth options from `env` (secret, plugins, email/password, …). */\n options: (env: Env) => LunoraAuthOptions;\n}']:[]],O=e=>[...e.hasAccess?[" private accessSelector?: Selector<Env, CreateAccessResolverOptions | undefined>;"]:[]," private adminToken?: Selector<Env, string>;",...e.hasAuth?[" private authDeclaration?: AuthDeclaration<Env>;"]:[]," private cdcEnabled = false;"," private reactiveCacheConfig: boolean | { maxBytes?: number; maxEntries?: number } = false;",' private maxRelationKeysLimit?: ShardConfig["maxRelationKeys"];',' private observabilitySink?: ShardConfig["observability"];',' private relationExistsPushDownMode?: ShardConfig["relationExistsPushDown"];'," private readonly extendFns: ((env: Env, derived: Readonly<WorkerOptions>) => Partial<WorkerOptions>)[] = [];",...e.hasGlobal?[" private globalDeclaration?: GlobalDeclaration<Env>;"]:[],...e.hasHyperdriveGlobal?[" private hyperdriveGlobalDeclaration?: HyperdriveGlobalDeclaration<Env>;"]:[]," private httpRouterApp?: HttpRouterLike;"," private readonly routeMap: Record<string, Route> = {};",...e.hasScheduler?[" private schedulerDeclaration?: SchedulerDeclaration<Env>;"]:[],...g(e)?[" private readonly shardExtras: Partial<ShardConfig> = {};"]:[],...d(e)?[" private shardRegistrySelector?: Selector<Env, ShardNamespaceLike>;"]:[]," private shardSelector?: Selector<Env, ShardNamespaceLike>;",...e.hasSourcedTables?[' private sourceClientFactory?: NonNullable<ShardConfig["sourceClient"]>;']:[],...e.hasStorage?[" private storageDeclaration?: StorageDeclaration<Env>;"]:[]],T=e=>m(e).map(({configKey:r,doc:t,method:a})=>` /** ${t} */
|
|
336
336
|
public ${a}(factory: (env: Env) => ReturnType<NonNullable<ShardConfig["${r}"]>>): this {
|
|
337
337
|
this.shardExtras.${r} = factory as NonNullable<ShardConfig["${r}"]>;
|
|
338
338
|
|
|
@@ -396,7 +396,7 @@ const buildGlobalCdcApplier =
|
|
|
396
396
|
this.storageDeclaration = declaration;
|
|
397
397
|
|
|
398
398
|
return this;
|
|
399
|
-
}`]:[],...T(e)],
|
|
399
|
+
}`]:[],...T(e)],I=e=>{const r=a=>e.hasScheduler?`
|
|
400
400
|
...(this.schedulerDeclaration ? { scheduler: this.resolveScheduler(env) as unknown as ${a}["scheduler"] } : {}),`:"",t=[" cdc: this.cdcEnabled,"," reactiveCache: this.reactiveCacheConfig,"," ...(this.maxRelationKeysLimit === undefined ? {} : { maxRelationKeys: this.maxRelationKeysLimit }),"," ...(this.observabilitySink === undefined ? {} : { observability: this.observabilitySink }),"," ...(this.relationExistsPushDownMode === undefined ? {} : { relationExistsPushDown: this.relationExistsPushDownMode }),",...e.hasGlobal?[` ...(this.globalDeclaration
|
|
401
401
|
? {
|
|
402
402
|
d1: (rawEnv: Record<string, unknown>, request?: { bookmark?: string; cdc?: boolean; cdcRetentionMs?: number; identity?: Record<string, unknown>; onBookmark?: (bookmark: string | undefined) => void; userId?: string | null }) => {
|
|
@@ -468,13 +468,13 @@ const buildGlobalCdcApplier =
|
|
|
468
468
|
? {
|
|
469
469
|
scheduler: (rawEnv: Record<string, unknown>) => this.resolveScheduler(rawEnv as Env),
|
|
470
470
|
}
|
|
471
|
-
: {}),`]:[],...d(e)?[" ...(this.shardRegistrySelector ? { shardRegistry: (rawEnv: Record<string, unknown>) => this.shardRegistrySelector?.(rawEnv as Env) } : {}),"]:[],...e.hasSourcedTables?[" ...(this.sourceClientFactory === undefined ? {} : { sourceClient: this.sourceClientFactory }),"]:[],...e.hasStorage?[" ...(this.storageDeclaration ? { storage: (rawEnv: Record<string, unknown>, origin?: string) => this.resolveStorage(rawEnv as Env, origin) } : {}),"]:[],...
|
|
471
|
+
: {}),`]:[],...d(e)?[" ...(this.shardRegistrySelector ? { shardRegistry: (rawEnv: Record<string, unknown>) => this.shardRegistrySelector?.(rawEnv as Env) } : {}),"]:[],...e.hasSourcedTables?[" ...(this.sourceClientFactory === undefined ? {} : { sourceClient: this.sourceClientFactory }),"]:[],...e.hasStorage?[" ...(this.storageDeclaration ? { storage: (rawEnv: Record<string, unknown>, origin?: string) => this.resolveStorage(rawEnv as Env, origin) } : {}),"]:[],...g(e)?[" ...this.shardExtras,"]:[]];return t.length>0?`
|
|
472
472
|
${t.join(`
|
|
473
473
|
`)}
|
|
474
|
-
`:""},
|
|
474
|
+
`:""},q=e=>e?['import * as lunoraIdentityContract from "../identity.js";']:[],L=(e,r)=>e?['import type { CreateAccessResolverOptions } from "@lunora/cloudflare-access";',`import { createAccessResolver${r?", composeResolvers":""} } from "@lunora/cloudflare-access";`]:[],j=e=>e?['import { createKvIntrospectorFromEnv } from "@lunora/bindings/kv";']:[],B=e=>e?['import { createVectorAdminIntrospector } from "@lunora/bindings/vectors";']:[],G=e=>e?['import type { D1CtxDbOptions, D1DatabaseLike, D1Exec } from "@lunora/d1";','import { applyCdcChanges, createD1CtxDb, emitD1QueryCost, exportGlobalRows, facetGlobalColumn, importGlobalRows, listGlobalTables, readD1CdcChanges, readGlobalTablePage, retryingExec } from "@lunora/d1";']:[],P=e=>e?['import notifyConfig from "../notify.js";']:[],_=e=>v(e)?['import { dispatchAgentEmail } from "@lunora/agent/inbound";']:[],W=e=>v(e)?['import * as lunoraAgentDefinitions from "../agents.js";']:[],M=e=>{const{hasFramework:r,hasGlobal:t,hasHyperdriveGlobal:a,hasQueue:s,useUmbrella:o}=e,i=o?"lunorash/runtime":"@lunora/runtime",c=["ExecutionContextLike","HttpRouterLike","LunoraWorker","Route","ScheduledControllerLike","ShardNamespaceLike","WorkerOptions",...s?["TriggerTrace"]:[],...t?["GlobalIntrospector"]:[],...e.tables.length>0?["ShardingInfo"]:[],...r?["FrameworkHostHandler"]:[]],l=[...t||a?["createCrossShardRelationCapabilities"]:[],...d(e)?["createDynamicShardRegistry","createQueryCoordinator"]:[],"createWorker",...e.jurisdiction?["declareAppJurisdiction"]:[],"resolveLogArchiveFromEnv",...e.hasAuth?["memoizeIdentity"]:[],...r?["withFrameworkWorker"]:[]].join(", ");return[`import type { ${[...c].toSorted((n,h)=>n.localeCompare(h)).join(", ")} } from "${i}";`,`import { ${l} } from "${i}";`]},H=e=>{const{hasAccess:r,hasAuth:t,hasGlobal:a,hasHyperdriveGlobal:s,hasKvIntrospector:o,hasQueue:i,hasScheduler:c,hasStorage:l,hasWorkflow:n,wantsOpenApi:h,wantsOpenRpc:u}=e;return[...t?['import type { AuthNamespaceLike, LunoraAuth, LunoraAuthOptions } from "@lunora/auth";','import { authDiscoveryPathsFor, createAuth, createAuthAdmin, createAuthAuditReader, createDoAuthWiring, d1Executor, handleAuthDiscoveryRequest, handleAuthRequest, lunoraD1Adapter } from "@lunora/auth";']:[],...L(r,t),...G(a),...s?['import type { HyperdriveEngine } from "@lunora/hyperdrive/global";','import { createHyperdriveGlobalCtxDb } from "@lunora/hyperdrive/global";','import type { SqlCtxDbOptions, SqlExec } from "@lunora/sql-store";']:[],...j(o),...B(e.hasVectors),...c?['import type { DurableObjectNamespaceLike } from "@lunora/scheduler";','import { createScheduler } from "@lunora/scheduler";']:[],...l?['import type { R2BucketLike, R2S3Credentials, Storage } from "@lunora/storage";','import { createBucketStorage, createStorage } from "@lunora/storage";']:[],...n?['import { createWorkflowsRestClient } from "@lunora/workflow";']:[],..._(e),...M(e),"",...q(e.identity),...W(e),...a||s?['import schema from "../schema.js";']:[],...P(e.hasNotify),'import { LUNORA_CRONS } from "./crons.js";','import { LUNORA_FUNCTIONS } from "./functions.js";',...i?['import { createQueueCaptureSink, dispatchQueueBatch, shouldCaptureQueue } from "@lunora/queue";','import { LUNORA_QUEUE_REGISTRY } from "./queues.js";']:[],...e.wantsArchitecture?['import { architecture } from "./architecture.js";']:[],...h?['import { openApiSpec } from "./openapi.js";']:[],...u?['import { openRpcSpec } from "./openrpc.js";']:[],'import { createShardDO } from "./shard.js";',...e.hasVectors?['import { LUNORA_VECTOR_INDEXES } from "./vectors.js";']:[]]},$=e=>e.jurisdiction&&e.jurisdictionPinsAuth===!0?`
|
|
475
475
|
// The schema's jurisdiction pins the auth object like every other DO.
|
|
476
|
-
jurisdiction: ${JSON.stringify(e.jurisdiction)},`:"",
|
|
477
|
-
${e.tables.map(r=>` [${JSON.stringify(r.name)}, ${
|
|
476
|
+
jurisdiction: ${JSON.stringify(e.jurisdiction)},`:"",U=e=>typeof e=="string"?`{ mode: { kind: ${JSON.stringify(e)} } }`:`{ mode: { field: ${JSON.stringify(e.field)}, kind: "shardBy" } }`,F=e=>[...e.tables.length>0?[` const tableSharding = new Map<string, ShardingInfo>([
|
|
477
|
+
${e.tables.map(r=>` [${JSON.stringify(r.name)}, ${U(r.shardMode)}],`).join(`
|
|
478
478
|
`)}
|
|
479
479
|
]);
|
|
480
480
|
|
|
@@ -551,7 +551,7 @@ ${e.tables.map(r=>` [${JSON.stringify(r.name)}, ${M(r.shardMode)}],`)
|
|
|
551
551
|
// Memoised on the declaration: a framework-hosted worker rebuilds these
|
|
552
552
|
// options per request, and \`options(env)\` rebuilds every plugin.
|
|
553
553
|
discoveryPaths: authDiscoveryPathsFor(authDeclaration, env),
|
|
554
|
-
internalSecret: authDeclaration.internalSecret?.(env),${
|
|
554
|
+
internalSecret: authDeclaration.internalSecret?.(env),${$(e)}
|
|
555
555
|
namespace: authNamespace(env),
|
|
556
556
|
objectName: authDeclaration.objectName?.(env),
|
|
557
557
|
});
|
|
@@ -627,6 +627,88 @@ ${e.tables.map(r=>` [${JSON.stringify(r.name)}, ${M(r.shardMode)}],`)
|
|
|
627
627
|
|
|
628
628
|
options.authAdmin = authInstance ? createAuthAdmin(authInstance) : undefined;
|
|
629
629
|
options.authAuditReader = createAuthAuditReader(d1Executor(authD1(env) as never));
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
// Both modes pay a session lookup per request (the auth object hop, or a D1
|
|
633
|
+
// read), and the runtime resolves identity once per RPC and per fan-out leg.
|
|
634
|
+
// Memoise per credential. The default window is the shorter of 60s and
|
|
635
|
+
// better-auth's cookie-cache \`maxAge\`; \`LUNORA_IDENTITY_CACHE_MS\` overrides it, \`0\`
|
|
636
|
+
// disables the cross-request cache. The memoised \`getSession\` result may itself
|
|
637
|
+
// come from better-auth's cookie cache, so the worst case is the two stacked: a
|
|
638
|
+
// revoked session or a changed role can resolve for up to the memo window PLUS the
|
|
639
|
+
// cookie-cache \`maxAge\` (about 120s with the presets).
|
|
640
|
+
//
|
|
641
|
+
// An app that switched the cookie cache OFF (the \`strict\` session preset) asked
|
|
642
|
+
// for fast revocation, so its default is per-request memoisation only; the env var
|
|
643
|
+
// still opts back in. Read from the declared options at runtime, the one place
|
|
644
|
+
// the chosen policy is visible.
|
|
645
|
+
//
|
|
646
|
+
// Built once per \`env\` object and kept for this assembled worker: a framework-hosted
|
|
647
|
+
// worker rebuilds these options on every request, and a fresh memo per build
|
|
648
|
+
// would never hit. A different \`env\` object gets its own memo.
|
|
649
|
+
if (options.resolveIdentity) {
|
|
650
|
+
let memo = identityMemos.get(env);
|
|
651
|
+
|
|
652
|
+
if (!memo) {
|
|
653
|
+
// A wrangler var may be a JSON number (\`0\`) or a string. A blank string is
|
|
654
|
+
// unset, not \`0\` (\`Number("")\` is 0); anything else non-numeric is unset too.
|
|
655
|
+
const identityCacheRaw = (env as { LUNORA_IDENTITY_CACHE_MS?: unknown }).LUNORA_IDENTITY_CACHE_MS;
|
|
656
|
+
let identityCacheMs = Number.NaN;
|
|
657
|
+
|
|
658
|
+
if (typeof identityCacheRaw === "number") {
|
|
659
|
+
identityCacheMs = identityCacheRaw;
|
|
660
|
+
} else if (typeof identityCacheRaw === "string" && identityCacheRaw.trim() !== "") {
|
|
661
|
+
identityCacheMs = Number(identityCacheRaw);
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
// \`options(env)\` is application code. A scheduled, queue or serverQuery event must
|
|
665
|
+
// not fail to construct — and so never run — because that callback throws, so a
|
|
666
|
+
// throw is caught rather than escaping.
|
|
667
|
+
let defaultMs: number;
|
|
668
|
+
|
|
669
|
+
try {
|
|
670
|
+
const cookieCache = authDeclaration?.options(env).session?.cookieCache;
|
|
671
|
+
// better-auth's \`maxAge\` is in SECONDS; createAuth fills 60 when it is unset.
|
|
672
|
+
const cookieCacheSeconds = typeof cookieCache?.maxAge === "number" && cookieCache.maxAge >= 0 ? cookieCache.maxAge : 60;
|
|
673
|
+
|
|
674
|
+
// createAuth fills \`{ enabled: true, maxAge: 60 }\` only when \`cookieCache\` is absent; a partial
|
|
675
|
+
// object without \`enabled: true\` has NO cookie cache, so the memo stays per-request there.
|
|
676
|
+
defaultMs = cookieCache === undefined || cookieCache.enabled === true ? Math.min(60_000, cookieCacheSeconds * 1000) : 0;
|
|
677
|
+
} catch {
|
|
678
|
+
// The policy is unreadable. Fall back to PER-REQUEST memoisation, not the 60s
|
|
679
|
+
// window: a 60s cross-request cache would let a revoked session keep
|
|
680
|
+
// resolving for a minute, which is exactly what the \`strict\` preset turned
|
|
681
|
+
// off. Construction still does not fail, so the event still runs.
|
|
682
|
+
defaultMs = 0;
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
memo = memoizeIdentity(options.resolveIdentity, {
|
|
686
|
+
// better-auth resolves the session from ALL request headers, so the key
|
|
687
|
+
// must cover every header a supported plugin authenticates on: the
|
|
688
|
+
// session cookie, \`Authorization\` (bearer / jwt) and \`x-api-key\` (apiKey).
|
|
689
|
+
cacheKey: (request: Request) => {
|
|
690
|
+
const parts = ["authorization", "cookie", "x-api-key"].map((name) => request.headers.get(name) ?? "");
|
|
691
|
+
|
|
692
|
+
if (parts.every((part) => part === "")) {
|
|
693
|
+
return undefined;
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
const key = parts.join("\\u0000");
|
|
697
|
+
|
|
698
|
+
// The map is bounded in ENTRIES, not in key size, so a client with one
|
|
699
|
+
// valid session could add a junk cookie per request and grow it without
|
|
700
|
+
// bound. Skip the cache for an oversized credential set rather than
|
|
701
|
+
// truncating the key, which could collide with a different credential and
|
|
702
|
+
// hand back the wrong identity.
|
|
703
|
+
return key.length > 4_096 ? undefined : key;
|
|
704
|
+
},
|
|
705
|
+
maxEntries: 2_000,
|
|
706
|
+
ttlMs: Number.isFinite(identityCacheMs) && identityCacheMs >= 0 ? identityCacheMs : defaultMs,
|
|
707
|
+
});
|
|
708
|
+
identityMemos.set(env, memo);
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
options.resolveIdentity = memo;
|
|
630
712
|
}`]:[],...e.hasAccess?[e.hasAuth?` if (this.accessSelector) {
|
|
631
713
|
const accessResolver = createAccessResolver(this.accessSelector(env));
|
|
632
714
|
const fallback = options.resolveIdentity;
|
|
@@ -637,9 +719,15 @@ ${e.tables.map(r=>` [${JSON.stringify(r.name)}, ${M(r.shardMode)}],`)
|
|
|
637
719
|
}`]:[],...e.voiceAgents&&e.voiceAgents.length>0?[` options.voiceAgents = {
|
|
638
720
|
${e.voiceAgents.map(r=>` ${JSON.stringify(r.exportName)}: (env as Record<string, unknown>)[${JSON.stringify(r.bindingName)}] as ShardNamespaceLike,`).join(`
|
|
639
721
|
`)}
|
|
640
|
-
};`]:[]],J=e=>[" cronJobs: LUNORA_CRONS,"," functions: LUNORA_FUNCTIONS,",...e.identity?[` identity: lunoraIdentityContract.${e.identity.exportName},`]:[],...e.jurisdiction?[` jurisdiction: ${JSON.stringify(e.jurisdiction)},`]:[],...e.wantsArchitecture?[" architecture,"]:[],...e.wantsOpenApi?[" openApiSpec,"]:[],...e.wantsOpenRpc?[" openRpcSpec,"]:[],...e.hasQueue?[" queue: (batch: unknown, queueEnv: unknown, _context: ExecutionContextLike, trigger: TriggerTrace): Promise<void> =>"," dispatchQueueBatch(batch as Parameters<typeof dispatchQueueBatch>[0], LUNORA_QUEUE_REGISTRY, {"," capture: shouldCaptureQueue(queueEnv as Record<string, unknown>)",` ? createQueueCaptureSink(queueEnv as Record<string, unknown>${e.jurisdiction?`, { jurisdiction: ${JSON.stringify(e.jurisdiction)} }`:""})`," : undefined,"," env: queueEnv as Record<string, unknown>,"," traceparent: trigger.traceparent,"," }),"]:[]," ...(this.httpRouterApp ? { httpRouter: this.httpRouterApp } : {}),"," routes: this.routeMap,"," shardDO: this.shardSelector?.(env) ?? (undefined as unknown as ShardNamespaceLike),"],K=e=>
|
|
722
|
+
};`]:[]],J=e=>[" cronJobs: LUNORA_CRONS,"," functions: LUNORA_FUNCTIONS,",...e.identity?[` identity: lunoraIdentityContract.${e.identity.exportName},`]:[],...e.jurisdiction?[` jurisdiction: ${JSON.stringify(e.jurisdiction)},`]:[],...e.wantsArchitecture?[" architecture,"]:[],...e.wantsOpenApi?[" openApiSpec,"]:[],...e.wantsOpenRpc?[" openRpcSpec,"]:[],...e.hasQueue?[" queue: (batch: unknown, queueEnv: unknown, _context: ExecutionContextLike, trigger: TriggerTrace): Promise<void> =>"," dispatchQueueBatch(batch as Parameters<typeof dispatchQueueBatch>[0], LUNORA_QUEUE_REGISTRY, {"," capture: shouldCaptureQueue(queueEnv as Record<string, unknown>)",` ? createQueueCaptureSink(queueEnv as Record<string, unknown>${e.jurisdiction?`, { jurisdiction: ${JSON.stringify(e.jurisdiction)} }`:""})`," : undefined,"," env: queueEnv as Record<string, unknown>,"," traceparent: trigger.traceparent,"," }),"]:[]," ...(this.httpRouterApp ? { httpRouter: this.httpRouterApp } : {}),"," routes: this.routeMap,"," shardDO: this.shardSelector?.(env) ?? (undefined as unknown as ShardNamespaceLike),"],K=e=>e?`
|
|
723
|
+
/** The identity memo per \`env\` object, owned by one assembled worker. */
|
|
724
|
+
type IdentityMemoStore = WeakMap<object, ReturnType<typeof memoizeIdentity>>;
|
|
725
|
+
`:"",V=e=>[...e.hasAuth?["AuthDeclaration"]:[],"ComposedApp",...e.hasGlobal?["GlobalDeclaration"]:[],"LunoraConfig",...e.hasScheduler?["SchedulerDeclaration"]:[],"Selector",...e.hasStorage?["StorageDeclaration"]:[]].toSorted((r,t)=>r.localeCompare(t)).join(", "),Z=e=>{const r=(e.hasVectors??!0)&&(e.vectorIndexCount??0)>0,t={...e,hasVectors:r},{hasAuth:a}=t,s=C(t),o=Q(t),i=a?` let auth: LunoraAuth | null = null;
|
|
641
726
|
let authInit: Promise<void> | null = null;
|
|
642
|
-
|
|
727
|
+
// One memo per env for THIS assembled worker: a framework-hosted worker rebuilds its options per
|
|
728
|
+
// request and must reuse it, but a second \`assemble()\` has its own auth closure and must not share.
|
|
729
|
+
const identityMemos: IdentityMemoStore = new WeakMap();
|
|
730
|
+
`:"",c=a?`
|
|
643
731
|
const initAuth = async (env: Env): Promise<void> => {
|
|
644
732
|
if (!this.authDeclaration) {
|
|
645
733
|
return;
|
|
@@ -691,9 +779,9 @@ ${e.voiceAgents.map(r=>` ${JSON.stringify(r.exportName)}: (env as Rec
|
|
|
691
779
|
authInit = null;
|
|
692
780
|
throw error;
|
|
693
781
|
}));
|
|
694
|
-
`:"",
|
|
695
|
-
await ensureAuth(env);`:"",
|
|
696
|
-
host ? withFrameworkWorker(host, (hostEnv) => this.buildWorkerOptions(hostEnv as Env, ${
|
|
782
|
+
`:"",l=a?`
|
|
783
|
+
await ensureAuth(env);`:"",n=a?"() => auth, identityMemos":"() => null",h=a?"getAuth: () => LunoraAuth | null, identityMemos: IdentityMemoStore":"_getAuth: () => null",u=t.hasFramework?` const buildWorker = (env: Env): LunoraWorker =>
|
|
784
|
+
host ? withFrameworkWorker(host, (hostEnv) => this.buildWorkerOptions(hostEnv as Env, ${n})) : createWorker(this.buildWorkerOptions(env, ${n}));`:` const buildWorker = (env: Env): LunoraWorker => createWorker(this.buildWorkerOptions(env, ${n}));`,y=t.hasFramework?"host?: FrameworkHostHandler":"",p=t.emailAgents??[],f=p.length>0?` composed.email = dispatchAgentEmail([
|
|
697
785
|
${p.map(b=>` { agent: lunoraAgentDefinitions.${b.exportName}, className: ${JSON.stringify(b.className)} },`).join(`
|
|
698
786
|
`)}
|
|
699
787
|
]);
|
|
@@ -709,15 +797,15 @@ type Selector<Env, T> = (env: Env) => T | undefined;
|
|
|
709
797
|
|
|
710
798
|
/** The generated \`createShardDO\` config — \`.observability()\`, \`.maxRelationKeys()\` and the long-tail \`.ai()\` / \`.kv()\` / … methods pass straight through to it. */
|
|
711
799
|
type ShardConfig = NonNullable<Parameters<typeof createShardDO>[0]>;
|
|
712
|
-
${t.jurisdiction?`
|
|
800
|
+
${K(a)}${t.jurisdiction?`
|
|
713
801
|
// Module scope, so every isolate loading this script (the worker and each Durable
|
|
714
802
|
// Object class it exports) knows the schema's jurisdiction before a request runs.
|
|
715
803
|
// \`@lunora/mail\` reads it to pin its shard RPC like every other DO path.
|
|
716
804
|
declareAppJurisdiction(${JSON.stringify(t.jurisdiction)});
|
|
717
805
|
`:""}
|
|
718
|
-
${
|
|
806
|
+
${s.join(`
|
|
719
807
|
|
|
720
|
-
`)}${
|
|
808
|
+
`)}${s.length>0?`
|
|
721
809
|
|
|
722
810
|
`:""}/** The composed app: a Cloudflare module worker (\`fetch\` / \`scheduled\` / optional \`email\`) plus the \`ShardDO\` class binding. */
|
|
723
811
|
interface ComposedApp extends LunoraWorker {
|
|
@@ -747,19 +835,19 @@ ${w}
|
|
|
747
835
|
|
|
748
836
|
/** Build the shard DO + compose the worker (standalone or framework-hosted), wrapping the lazy per-isolate singletons + auth init. */
|
|
749
837
|
private assemble(${y}): ComposedApp {
|
|
750
|
-
const ShardDO = createShardDO({${
|
|
838
|
+
const ShardDO = createShardDO({${I(t)}});
|
|
751
839
|
|
|
752
840
|
// Per-isolate singletons: the worker (and auth instance) are expensive to
|
|
753
841
|
// build, so the first request constructs them and every later request on
|
|
754
842
|
// the same isolate reuses them.
|
|
755
843
|
let worker: LunoraWorker | null = null;
|
|
756
|
-
${i}${
|
|
844
|
+
${i}${c}
|
|
757
845
|
${u}
|
|
758
846
|
|
|
759
847
|
const composed: ComposedApp = {
|
|
760
848
|
ShardDO,
|
|
761
849
|
fetch: async (request: Request, rawEnv: unknown, context: ExecutionContextLike): Promise<Response> => {
|
|
762
|
-
const env = rawEnv as Env;${
|
|
850
|
+
const env = rawEnv as Env;${l}
|
|
763
851
|
worker ??= buildWorker(env);
|
|
764
852
|
|
|
765
853
|
return worker.fetch(request, rawEnv, context);
|
|
@@ -863,5 +951,5 @@ interface LunoraConfig<Env extends object = object> {
|
|
|
863
951
|
const defineApp = <Env extends object>(): AppBuilder<Env> => new AppBuilder<Env>();
|
|
864
952
|
|
|
865
953
|
export { AppBuilder, defineApp };
|
|
866
|
-
export type { ${
|
|
867
|
-
`};export{
|
|
954
|
+
export type { ${V(t)} };
|
|
955
|
+
`};export{Z as emitApp};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import"./SCHEMA_SNAPSHOT_VERSION-C0oHwiJZ.mjs";import"./isD1GlobalTable-udvHAAzD.mjs";import"./json-data-Chfs2Cz5.mjs";import{e as d}from"./shard-
|
|
1
|
+
import"./SCHEMA_SNAPSHOT_VERSION-C0oHwiJZ.mjs";import"./isD1GlobalTable-udvHAAzD.mjs";import"./json-data-Chfs2Cz5.mjs";import{e as d}from"./shard-Av4rUyYS.mjs";import"./shard-runtime-CkTgY8tL.mjs";import"./shared-DnCokNcE.mjs";import"./platform-8oj7iXQy.mjs";import"./schema-BgM8A3XV.mjs";export{d as default};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{LunoraError as Rt}from"@lunora/errors";import{serializeSchemaSnapshot as xt,hashSchemaSnapshot as At}from"./SCHEMA_SNAPSHOT_VERSION-C0oHwiJZ.mjs";import{isHyperdriveGlobalTable as Ot,isD1GlobalTable as Dt}from"./isD1GlobalTable-udvHAAzD.mjs";import{r as Tt}from"./json-data-Chfs2Cz5.mjs";import{r as L,e as Et,a as Lt,b as Ct,c as It,d as _t,f as Mt,g as Pt,h as Nt,i as $t,j as qt,k as Ft,l as Ut,m as Bt,n as Wt,o as jt,p as Ht,q as Vt}from"./shard-runtime-
|
|
1
|
+
import{LunoraError as Rt}from"@lunora/errors";import{serializeSchemaSnapshot as xt,hashSchemaSnapshot as At}from"./SCHEMA_SNAPSHOT_VERSION-C0oHwiJZ.mjs";import{isHyperdriveGlobalTable as Ot,isD1GlobalTable as Dt}from"./isD1GlobalTable-udvHAAzD.mjs";import{r as Tt}from"./json-data-Chfs2Cz5.mjs";import{r as L,e as Et,a as Lt,b as Ct,c as It,d as _t,f as Mt,g as Pt,h as Nt,i as $t,j as qt,k as Ft,l as Ut,m as Bt,n as Wt,o as jt,p as Ht,q as Vt}from"./shard-runtime-CkTgY8tL.mjs";import{u as K,i as Kt,G as Gt,d as Qt}from"./shared-DnCokNcE.mjs";import{p as zt}from"./platform-8oj7iXQy.mjs";import{i as Jt}from"./schema-BgM8A3XV.mjs";const h=(n,e)=>`((): (() => ${e}) => { let cached: ${e} | undefined; return () => (cached ??= JSON.parse(${JSON.stringify(JSON.stringify(n))}) as ${e}); })()`,te=["categories","description","facing","level","remediation","title"],Yt=n=>{const e={};return{advisoryRows:n.map(a=>{let r=e[a.name];return r||(r=Object.fromEntries(te.filter(s=>s in a).map(s=>[s,a[s]])),e[a.name]=r),Object.fromEntries(Object.entries(a).filter(([s,d])=>!te.includes(s)||JSON.stringify(d)!==JSON.stringify(r[s])))}),advisoryRules:e}},Xt=` /**
|
|
2
2
|
* The bare writer every admin/maintenance entry point writes through.
|
|
3
3
|
*
|
|
4
4
|
* Admin and maintenance writes go through the SAME reactive-cache hooks as a
|
|
@@ -1069,7 +1069,7 @@ assertShapesDeclareReadPolicies(LUNORA_SHAPES, ${JSON.stringify(r)}, (schema as
|
|
|
1069
1069
|
`:"",sourceClientCacheConst:n?`
|
|
1070
1070
|
const sourceClientCache = new WeakMap<object, Map<string, SourceClientLike>>();
|
|
1071
1071
|
const sourcePollAtCache = new WeakMap<object, Map<string, number>>();
|
|
1072
|
-
`:""}),mr=(n,e)=>{const t=e.length>0,r=n?L("vectorsStub: VectorSearchLike","ctx.vectors: no vectors configured. Pass `vectors` to createShardDO().",["deleteByIds","getByIds","query","upsert","upsertNow"]):"",s=t?` const vectorShardKey = this.currentShardKey();
|
|
1072
|
+
`:""}),mr=(n,e)=>{const t=e.length>0,r=n?L("vectorsStub: VectorSearchLike","ctx.vectors: no vectors configured. Pass `vectors` to createShardDO().",["deleteByIds","getByIds","query","upsert","upsertMany","upsertNow"]):"",s=t?` const vectorShardKey = this.currentShardKey();
|
|
1073
1073
|
`:"",d=t?"namespace: vectorShardKey === ROOT_SHARD_NAME ? undefined : vectorShardKey, ":"",f=`, { ${["deferAfterCommit: (work) => this.deferAfterCommit(work)",...t?["namespace: vectorShardKey === ROOT_SHARD_NAME ? undefined : vectorShardKey",`shardedIndexNames: [${e.map(S=>JSON.stringify(S)).join(", ")}]`]:[]].join(", ")} }`,c=n?`
|
|
1074
1074
|
const vectorSync = this.vectorSync(env);
|
|
1075
1075
|
// Vectorize lives outside this shard's SQLite, so a query whose result
|
|
@@ -115,7 +115,7 @@ const LUNORA_FLAG_KEYS = ${b(e,'ReadonlyArray<{ key: string; type: "boolean" | "
|
|
|
115
115
|
telemetry: { metrics, trace },
|
|
116
116
|
});
|
|
117
117
|
`,configField:`
|
|
118
|
-
ai?: (env: Record<string, unknown>) => AiBindingLike;`,importLines:['import type { AiBindingLike, LunoraAi } from "@lunora/ai";','import { createAi } from "@lunora/ai";'],stub:""}),S=()=>({build:`
|
|
118
|
+
ai?: (env: Record<string, unknown>) => AiBindingLike;`,importLines:['import type { AiBindingLike, LunoraAi } from "@lunora/ai/create";','import { createAi } from "@lunora/ai/create";'],stub:""}),S=()=>({build:`
|
|
119
119
|
const access = accessFacade(identity, userId);
|
|
120
120
|
`,configField:"",importLines:['import { accessFacade } from "@lunora/cloudflare-access/context";'],stub:""}),w=()=>({build:`
|
|
121
121
|
const r2sqlEnv = env as Record<string, unknown>;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lunora/codegen",
|
|
3
|
-
"version": "1.0.0-alpha.
|
|
3
|
+
"version": "1.0.0-alpha.306",
|
|
4
4
|
"description": "Code generator for Lunora: emits _generated/{api,server,dataModel}.ts from your schema",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"cloudflare",
|
|
@@ -46,8 +46,8 @@
|
|
|
46
46
|
"access": "public"
|
|
47
47
|
},
|
|
48
48
|
"dependencies": {
|
|
49
|
-
"@lunora/advisor": "1.0.0-alpha.
|
|
50
|
-
"@lunora/agent": "1.0.0-alpha.
|
|
49
|
+
"@lunora/advisor": "1.0.0-alpha.218",
|
|
50
|
+
"@lunora/agent": "1.0.0-alpha.208",
|
|
51
51
|
"@lunora/container": "1.0.0-alpha.75",
|
|
52
52
|
"@lunora/errors": ">=1.0.0-alpha.51 <2.0.0-0",
|
|
53
53
|
"@lunora/platform": "1.0.0-alpha.64",
|