@lunora/codegen 1.0.0-alpha.30 → 1.0.0-alpha.32
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 +23 -0
- package/dist/index.d.ts +23 -0
- package/dist/index.mjs +5 -5
- package/dist/packem_shared/GENERATED_HEADER-CLwPlCQe.mjs +3 -0
- package/dist/packem_shared/{OPENRPC_VERSION-u5SqDDGk.mjs → OPENRPC_VERSION-4YIeMkOI.mjs} +1 -1
- package/dist/packem_shared/{SCHEMA_SNAPSHOT_FILENAME-Cpfn80SH.mjs → SCHEMA_SNAPSHOT_FILENAME-OBXQBJV0.mjs} +104 -65
- package/dist/packem_shared/{buildOpenApiDocument-AgKWmlry.mjs → buildOpenApiDocument-bp1pYSV6.mjs} +1 -1
- package/dist/packem_shared/{GENERATED_HEADER-f6nMvllu.mjs → emit-CBwEvCXQ.mjs} +212 -35
- package/dist/packem_shared/{emitApp-DKt3rPtr.mjs → emitApp-nQ2oC-8G.mjs} +19 -26
- package/package.json +3 -3
package/dist/index.d.mts
CHANGED
|
@@ -287,6 +287,18 @@ interface IdentityIR {
|
|
|
287
287
|
exportName: string;
|
|
288
288
|
}
|
|
289
289
|
/**
|
|
290
|
+
* The single `defineEnv({...})` contract discovered in `lunora/env.ts`. Like
|
|
291
|
+
* {@link IdentityIR}, only the export binding is lifted — the emitted
|
|
292
|
+
* `_generated/server.ts` recovers the validated shape from the declaration
|
|
293
|
+
* itself (`ReturnType` over the accessor's `typeof`), and the generated ShardDO
|
|
294
|
+
* applies the same accessor to the worker `env` at ctx-build time to populate
|
|
295
|
+
* `ctx.env`. Exactly one per app; absent ⇒ generated output is byte-identical.
|
|
296
|
+
*/
|
|
297
|
+
interface EnvIR {
|
|
298
|
+
/** Export binding name — the namespace member `_generated/server.ts` reads via `typeof`. */
|
|
299
|
+
exportName: string;
|
|
300
|
+
}
|
|
301
|
+
/**
|
|
290
302
|
* A `defineMutator({...})` declaration discovered in `lunora/mutators.ts`
|
|
291
303
|
* (local-first sync engine, Phase 7). The emitted registry registers the
|
|
292
304
|
* authoritative `server` impl into the DO's `LUNORA_FUNCTIONS` table (so
|
|
@@ -1851,6 +1863,13 @@ declare const emitCollections: (shapes: ReadonlyArray<ShapeIR>, hasDatabase: boo
|
|
|
1851
1863
|
interface EmitServerOptions {
|
|
1852
1864
|
containers?: ReadonlyArray<ContainerIR>;
|
|
1853
1865
|
/**
|
|
1866
|
+
* The single `defineEnv(...)` contract declared in `lunora/env.ts`. When
|
|
1867
|
+
* present, `ctx.env` is typed as the validated `InferEnv` shape (recovered
|
|
1868
|
+
* via `ReturnType` over the accessor's `typeof`). `undefined` leaves `ctx.env`
|
|
1869
|
+
* the base optional binding record — byte-identical to today.
|
|
1870
|
+
*/
|
|
1871
|
+
env?: EnvIR;
|
|
1872
|
+
/**
|
|
1854
1873
|
* A `lunora/` source reads `ctx.access` — wires the verified Cloudflare Access
|
|
1855
1874
|
* facade (`@lunora/cloudflare-access/context`) onto every ctx. Distinct from
|
|
1856
1875
|
* `emitApp`'s `hasAccess` (which gates the worker's `.access()` resolveIdentity
|
|
@@ -1894,6 +1913,7 @@ interface EmitServerOptions {
|
|
|
1894
1913
|
}
|
|
1895
1914
|
declare const emitServer: ({
|
|
1896
1915
|
containers,
|
|
1916
|
+
env,
|
|
1897
1917
|
hasAccessFacade,
|
|
1898
1918
|
hasAi,
|
|
1899
1919
|
hasAnalytics,
|
|
@@ -1951,6 +1971,8 @@ declare const emitWorkflows: (workflows: ReadonlyArray<WorkflowIR>) => string;
|
|
|
1951
1971
|
interface EmitShardOptions {
|
|
1952
1972
|
advisories?: ReadonlyArray<Finding>;
|
|
1953
1973
|
containers?: ReadonlyArray<ContainerIR>;
|
|
1974
|
+
/** The single `defineEnv(...)` contract declared in `lunora/env.ts` — applies the accessor to the worker `env` to populate `ctx.env`. */
|
|
1975
|
+
env?: EnvIR;
|
|
1954
1976
|
/** Statically-discovered `ctx.flags.<type>("key")` reads — the studio Flags page + reactive evaluation iterate these. */
|
|
1955
1977
|
flagKeys?: ReadonlyArray<{
|
|
1956
1978
|
key: string;
|
|
@@ -1994,6 +2016,7 @@ interface EmitShardOptions {
|
|
|
1994
2016
|
declare const emitShard: ({
|
|
1995
2017
|
advisories,
|
|
1996
2018
|
containers,
|
|
2019
|
+
env,
|
|
1997
2020
|
flagKeys,
|
|
1998
2021
|
hasAccessFacade,
|
|
1999
2022
|
hasAi,
|
package/dist/index.d.ts
CHANGED
|
@@ -287,6 +287,18 @@ interface IdentityIR {
|
|
|
287
287
|
exportName: string;
|
|
288
288
|
}
|
|
289
289
|
/**
|
|
290
|
+
* The single `defineEnv({...})` contract discovered in `lunora/env.ts`. Like
|
|
291
|
+
* {@link IdentityIR}, only the export binding is lifted — the emitted
|
|
292
|
+
* `_generated/server.ts` recovers the validated shape from the declaration
|
|
293
|
+
* itself (`ReturnType` over the accessor's `typeof`), and the generated ShardDO
|
|
294
|
+
* applies the same accessor to the worker `env` at ctx-build time to populate
|
|
295
|
+
* `ctx.env`. Exactly one per app; absent ⇒ generated output is byte-identical.
|
|
296
|
+
*/
|
|
297
|
+
interface EnvIR {
|
|
298
|
+
/** Export binding name — the namespace member `_generated/server.ts` reads via `typeof`. */
|
|
299
|
+
exportName: string;
|
|
300
|
+
}
|
|
301
|
+
/**
|
|
290
302
|
* A `defineMutator({...})` declaration discovered in `lunora/mutators.ts`
|
|
291
303
|
* (local-first sync engine, Phase 7). The emitted registry registers the
|
|
292
304
|
* authoritative `server` impl into the DO's `LUNORA_FUNCTIONS` table (so
|
|
@@ -1851,6 +1863,13 @@ declare const emitCollections: (shapes: ReadonlyArray<ShapeIR>, hasDatabase: boo
|
|
|
1851
1863
|
interface EmitServerOptions {
|
|
1852
1864
|
containers?: ReadonlyArray<ContainerIR>;
|
|
1853
1865
|
/**
|
|
1866
|
+
* The single `defineEnv(...)` contract declared in `lunora/env.ts`. When
|
|
1867
|
+
* present, `ctx.env` is typed as the validated `InferEnv` shape (recovered
|
|
1868
|
+
* via `ReturnType` over the accessor's `typeof`). `undefined` leaves `ctx.env`
|
|
1869
|
+
* the base optional binding record — byte-identical to today.
|
|
1870
|
+
*/
|
|
1871
|
+
env?: EnvIR;
|
|
1872
|
+
/**
|
|
1854
1873
|
* A `lunora/` source reads `ctx.access` — wires the verified Cloudflare Access
|
|
1855
1874
|
* facade (`@lunora/cloudflare-access/context`) onto every ctx. Distinct from
|
|
1856
1875
|
* `emitApp`'s `hasAccess` (which gates the worker's `.access()` resolveIdentity
|
|
@@ -1894,6 +1913,7 @@ interface EmitServerOptions {
|
|
|
1894
1913
|
}
|
|
1895
1914
|
declare const emitServer: ({
|
|
1896
1915
|
containers,
|
|
1916
|
+
env,
|
|
1897
1917
|
hasAccessFacade,
|
|
1898
1918
|
hasAi,
|
|
1899
1919
|
hasAnalytics,
|
|
@@ -1951,6 +1971,8 @@ declare const emitWorkflows: (workflows: ReadonlyArray<WorkflowIR>) => string;
|
|
|
1951
1971
|
interface EmitShardOptions {
|
|
1952
1972
|
advisories?: ReadonlyArray<Finding>;
|
|
1953
1973
|
containers?: ReadonlyArray<ContainerIR>;
|
|
1974
|
+
/** The single `defineEnv(...)` contract declared in `lunora/env.ts` — applies the accessor to the worker `env` to populate `ctx.env`. */
|
|
1975
|
+
env?: EnvIR;
|
|
1954
1976
|
/** Statically-discovered `ctx.flags.<type>("key")` reads — the studio Flags page + reactive evaluation iterate these. */
|
|
1955
1977
|
flagKeys?: ReadonlyArray<{
|
|
1956
1978
|
key: string;
|
|
@@ -1994,6 +2016,7 @@ interface EmitShardOptions {
|
|
|
1994
2016
|
declare const emitShard: ({
|
|
1995
2017
|
advisories,
|
|
1996
2018
|
containers,
|
|
2019
|
+
env,
|
|
1997
2020
|
flagKeys,
|
|
1998
2021
|
hasAccessFacade,
|
|
1999
2022
|
hasAi,
|
package/dist/index.mjs
CHANGED
|
@@ -19,11 +19,11 @@ export { default as discoverSchema } from './packem_shared/discoverSchema-CeXJWV
|
|
|
19
19
|
export { SHAPES_FILENAME, discoverShapes } from './packem_shared/SHAPES_FILENAME-DOhPGi-6.mjs';
|
|
20
20
|
export { default as discoverStorageRulesMetadata } from './packem_shared/discoverStorageRulesMetadata-CFHByjIl.mjs';
|
|
21
21
|
export { WORKFLOWS_FILENAME, discoverWorkflows } from './packem_shared/WORKFLOWS_FILENAME-CCC_42o3.mjs';
|
|
22
|
-
export { GENERATED_HEADER, emitApi, emitCollections, emitContainers, emitCrons, emitDataModel, emitDrizzleSchema, emitFunctions, emitServer, emitShard, emitVectors, emitWorkflows, emitWranglerCronTriggers } from './packem_shared/
|
|
23
|
-
export { emitApp } from './packem_shared/emitApp-
|
|
24
|
-
export { buildOpenApiDocument, emitOpenApi, emitOpenApiModule } from './packem_shared/buildOpenApiDocument-
|
|
25
|
-
export { OPENRPC_VERSION, buildOpenRpcDocument, emitOpenRpc, emitOpenRpcModule } from './packem_shared/OPENRPC_VERSION-
|
|
26
|
-
export { SCHEMA_SNAPSHOT_FILENAME, createCodegenProject, refreshCodegenProject, runCodegen } from './packem_shared/SCHEMA_SNAPSHOT_FILENAME-
|
|
22
|
+
export { G as GENERATED_HEADER, e as emitApi, a as emitCollections, b as emitContainers, c as emitCrons, d as emitDataModel, f as emitDrizzleSchema, g as emitFunctions, h as emitServer, i as emitShard, j as emitVectors, k as emitWorkflows, l as emitWranglerCronTriggers } from './packem_shared/emit-CBwEvCXQ.mjs';
|
|
23
|
+
export { emitApp } from './packem_shared/emitApp-nQ2oC-8G.mjs';
|
|
24
|
+
export { buildOpenApiDocument, emitOpenApi, emitOpenApiModule } from './packem_shared/buildOpenApiDocument-bp1pYSV6.mjs';
|
|
25
|
+
export { OPENRPC_VERSION, buildOpenRpcDocument, emitOpenRpc, emitOpenRpcModule } from './packem_shared/OPENRPC_VERSION-4YIeMkOI.mjs';
|
|
26
|
+
export { SCHEMA_SNAPSHOT_FILENAME, createCodegenProject, refreshCodegenProject, runCodegen } from './packem_shared/SCHEMA_SNAPSHOT_FILENAME-OBXQBJV0.mjs';
|
|
27
27
|
export { SCHEMA_SNAPSHOT_VERSION, SchemaSnapshotParseError, buildSchemaSnapshot, diffSchemaSnapshots, evaluateSchemaDrift, parseSchemaSnapshot, serializeSchemaSnapshot } from './packem_shared/SCHEMA_SNAPSHOT_VERSION-D0ARY6rL.mjs';
|
|
28
28
|
export { schemaFromIr } from './packem_shared/schemaFromIr-DTYsLBaA.mjs';
|
|
29
29
|
export { LUNORA_ERROR_CODES, validatorIrToJsonSchema } from './packem_shared/LUNORA_ERROR_CODES-CySpQPD3.mjs';
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import '@lunora/errors';
|
|
2
|
+
export { G as GENERATED_HEADER, m as buildStorageColumns, e as emitApi, a as emitCollections, b as emitContainers, c as emitCrons, d as emitDataModel, f as emitDrizzleSchema, g as emitFunctions, n as emitQueues, o as emitSeed, h as emitServer, i as emitShard, j as emitVectors, k as emitWorkflows, l as emitWranglerCronTriggers } from './emit-CBwEvCXQ.mjs';
|
|
3
|
+
import './paths-BRd6JHuF.mjs';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { GENERATED_HEADER } from './
|
|
1
|
+
import { G as GENERATED_HEADER } from './emit-CBwEvCXQ.mjs';
|
|
2
2
|
import { s as sanitizeNamespace } from './paths-BRd6JHuF.mjs';
|
|
3
3
|
import { argsObjectSchema, LUNORA_ERROR_CODES } from './LUNORA_ERROR_CODES-CySpQPD3.mjs';
|
|
4
4
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { existsSync, readFileSync, mkdirSync, writeFileSync } from 'node:fs';
|
|
1
|
+
import { existsSync, readFileSync, mkdirSync, writeFileSync, rmSync } from 'node:fs';
|
|
2
2
|
import { join, dirname } from 'node:path';
|
|
3
3
|
import { performance } from 'node:perf_hooks';
|
|
4
4
|
import { LunoraError } from '@lunora/errors';
|
|
@@ -8,9 +8,10 @@ import { listLunoraSourceFiles, lunoraRelativePath, classifyProcedureCall, inlin
|
|
|
8
8
|
import discoverAuthApiCalls from './discoverAuthApiCalls-URDoTADN.mjs';
|
|
9
9
|
import { discoverContainers } from './CONTAINERS_FILENAME-DjpXMqhp.mjs';
|
|
10
10
|
import discoverCrons from './discoverCrons-DdZOeroL.mjs';
|
|
11
|
+
import { diagnosticAt } from './CodegenDiagnosticError-DyQ5FwkM.mjs';
|
|
12
|
+
import { C as CAPABILITIES, m as buildStorageColumns, d as emitDataModel, e as emitApi, h as emitServer, g as emitFunctions, i as emitShard, a as emitCollections, b as emitContainers, k as emitWorkflows, n as emitQueues, c as emitCrons, j as emitVectors, f as emitDrizzleSchema, o as emitSeed, l as emitWranglerCronTriggers } from './emit-CBwEvCXQ.mjs';
|
|
11
13
|
import { discoverFlagKeys } from './FLAGS_FILENAME-BjpS5w08.mjs';
|
|
12
14
|
import discoverHttpRoutes from './discoverHttpRoutes-CcwP-Rkr.mjs';
|
|
13
|
-
import { diagnosticAt } from './CodegenDiagnosticError-DyQ5FwkM.mjs';
|
|
14
15
|
import discoverInserts from './discoverInserts-BpFhM32L.mjs';
|
|
15
16
|
import discoverMaskProcedures, { discoverMaskStrategies, discoverMaskMetadata } from './discoverMaskProcedures-DT-v8wvj.mjs';
|
|
16
17
|
import discoverMigrations from './discoverMigrations-cG1idBVM.mjs';
|
|
@@ -26,10 +27,9 @@ import { discoverShapes } from './SHAPES_FILENAME-DOhPGi-6.mjs';
|
|
|
26
27
|
import discoverStorageRulesMetadata from './discoverStorageRulesMetadata-CFHByjIl.mjs';
|
|
27
28
|
import { e as enclosingExportName$2 } from './discover-ast-CT6BgBr4.mjs';
|
|
28
29
|
import { discoverWorkflows } from './WORKFLOWS_FILENAME-CCC_42o3.mjs';
|
|
29
|
-
import {
|
|
30
|
-
import {
|
|
31
|
-
import {
|
|
32
|
-
import { buildOpenRpcDocument, emitOpenRpcModule } from './OPENRPC_VERSION-u5SqDDGk.mjs';
|
|
30
|
+
import { emitApp } from './emitApp-nQ2oC-8G.mjs';
|
|
31
|
+
import { buildOpenApiDocument, emitOpenApiModule } from './buildOpenApiDocument-bp1pYSV6.mjs';
|
|
32
|
+
import { buildOpenRpcDocument, emitOpenRpcModule } from './OPENRPC_VERSION-4YIeMkOI.mjs';
|
|
33
33
|
import { buildSchemaSnapshot, serializeSchemaSnapshot } from './SCHEMA_SNAPSHOT_VERSION-D0ARY6rL.mjs';
|
|
34
34
|
|
|
35
35
|
const HTTP_VERBS$1 = /* @__PURE__ */ new Set(["delete", "get", "head", "options", "patch", "post", "put"]);
|
|
@@ -878,6 +878,89 @@ const discoverContainerOverrides = (project, lunoraDirectory) => {
|
|
|
878
878
|
return rows;
|
|
879
879
|
};
|
|
880
880
|
|
|
881
|
+
const ENV_FILENAME = "env.ts";
|
|
882
|
+
const ENV_MODULE_SPECIFIERS = /* @__PURE__ */ new Set(["@lunora/server", "lunorash/server"]);
|
|
883
|
+
const isDefineEnv = (identifier) => {
|
|
884
|
+
const symbol = identifier.getSymbol();
|
|
885
|
+
if (!symbol) {
|
|
886
|
+
return identifier.getText() === "defineEnv";
|
|
887
|
+
}
|
|
888
|
+
for (const declaration of symbol.getDeclarations()) {
|
|
889
|
+
if (!Node.isImportSpecifier(declaration)) {
|
|
890
|
+
continue;
|
|
891
|
+
}
|
|
892
|
+
if (!ENV_MODULE_SPECIFIERS.has(declaration.getImportDeclaration().getModuleSpecifierValue())) {
|
|
893
|
+
return false;
|
|
894
|
+
}
|
|
895
|
+
return declaration.getNameNode().getText() === "defineEnv";
|
|
896
|
+
}
|
|
897
|
+
return false;
|
|
898
|
+
};
|
|
899
|
+
const isEnvNamespaceImport = (identifier) => {
|
|
900
|
+
const symbol = identifier.getSymbol();
|
|
901
|
+
if (!symbol) {
|
|
902
|
+
return false;
|
|
903
|
+
}
|
|
904
|
+
for (const declaration of symbol.getDeclarations()) {
|
|
905
|
+
if (!Node.isNamespaceImport(declaration)) {
|
|
906
|
+
continue;
|
|
907
|
+
}
|
|
908
|
+
const importDeclaration = declaration.getFirstAncestorByKind(SyntaxKind.ImportDeclaration);
|
|
909
|
+
return importDeclaration !== void 0 && ENV_MODULE_SPECIFIERS.has(importDeclaration.getModuleSpecifierValue());
|
|
910
|
+
}
|
|
911
|
+
return false;
|
|
912
|
+
};
|
|
913
|
+
const isDefineEnvCallee = (callee) => {
|
|
914
|
+
if (Node.isIdentifier(callee)) {
|
|
915
|
+
return isDefineEnv(callee);
|
|
916
|
+
}
|
|
917
|
+
if (Node.isPropertyAccessExpression(callee)) {
|
|
918
|
+
const object = callee.getExpression();
|
|
919
|
+
return callee.getName() === "defineEnv" && Node.isIdentifier(object) && isEnvNamespaceImport(object);
|
|
920
|
+
}
|
|
921
|
+
return false;
|
|
922
|
+
};
|
|
923
|
+
const environmentsFromSource = (source) => {
|
|
924
|
+
const environments = [];
|
|
925
|
+
for (const declaration of source.getVariableDeclarations()) {
|
|
926
|
+
if (!declaration.isExported()) {
|
|
927
|
+
continue;
|
|
928
|
+
}
|
|
929
|
+
const initializer = declaration.getInitializer();
|
|
930
|
+
if (initializer?.getKind() !== SyntaxKind.CallExpression) {
|
|
931
|
+
continue;
|
|
932
|
+
}
|
|
933
|
+
const callExpression = initializer;
|
|
934
|
+
if (!isDefineEnvCallee(callExpression.getExpression())) {
|
|
935
|
+
continue;
|
|
936
|
+
}
|
|
937
|
+
const nameNode = declaration.getNameNode();
|
|
938
|
+
if (!Node.isIdentifier(nameNode)) {
|
|
939
|
+
throw diagnosticAt(nameNode, "defineEnv exports must be plain named exports (no destructuring)");
|
|
940
|
+
}
|
|
941
|
+
environments.push({ exportName: nameNode.getText() });
|
|
942
|
+
}
|
|
943
|
+
return environments;
|
|
944
|
+
};
|
|
945
|
+
const discoverEnv = (project, lunoraDirectory) => {
|
|
946
|
+
const envPath = join(lunoraDirectory, ENV_FILENAME);
|
|
947
|
+
if (!existsSync(envPath)) {
|
|
948
|
+
return void 0;
|
|
949
|
+
}
|
|
950
|
+
const source = project.getSourceFile(envPath) ?? project.addSourceFileAtPath(envPath);
|
|
951
|
+
const environments = environmentsFromSource(source);
|
|
952
|
+
if (environments.length === 0) {
|
|
953
|
+
return void 0;
|
|
954
|
+
}
|
|
955
|
+
if (environments.length > 1) {
|
|
956
|
+
throw diagnosticAt(
|
|
957
|
+
source,
|
|
958
|
+
`lunora/env.ts declares ${environments.length.toString()} defineEnv() contracts (${environments.map((env) => env.exportName).join(", ")}); exactly one is allowed`
|
|
959
|
+
);
|
|
960
|
+
}
|
|
961
|
+
return environments[0];
|
|
962
|
+
};
|
|
963
|
+
|
|
881
964
|
const OPTIONS_ARGUMENT_INDEX$1 = /* @__PURE__ */ new Map([
|
|
882
965
|
["dbRateLimit", 2],
|
|
883
966
|
["rateLimit", 2],
|
|
@@ -932,35 +1015,6 @@ const discoverFailOpenGuards = (project, lunoraDirectory) => {
|
|
|
932
1015
|
return guards;
|
|
933
1016
|
};
|
|
934
1017
|
|
|
935
|
-
const PROBES = {
|
|
936
|
-
// The middleware (`accessContext()` / `accessRoles()`) imports the `/context`
|
|
937
|
-
// and `/roles` subpaths, NOT the bare `@lunora/cloudflare-access` specifier —
|
|
938
|
-
// so the per-procedure middleware never trips the global `ctx.access` wiring.
|
|
939
|
-
// A handler reading `ctx.access` is the signal that wires it onto every ctx.
|
|
940
|
-
access: { contextProperty: "access", moduleSpecifier: "@lunora/cloudflare-access" },
|
|
941
|
-
ai: { contextProperty: "ai", moduleSpecifier: "@lunora/ai" },
|
|
942
|
-
analytics: { contextProperty: "analytics", moduleSpecifier: "@lunora/bindings/analytics" },
|
|
943
|
-
browser: { contextProperty: "browser", moduleSpecifier: "@lunora/browser" },
|
|
944
|
-
// `lunora/containers.ts` imports `defineContainer` from `@lunora/container`,
|
|
945
|
-
// and handlers reach live instances via `ctx.containers` — either signals the
|
|
946
|
-
// app wires containers, so the studio should show the Containers page.
|
|
947
|
-
container: { contextProperty: "containers", moduleSpecifier: "@lunora/container" },
|
|
948
|
-
flags: { contextProperty: "flags", moduleSpecifier: "@lunora/flags" },
|
|
949
|
-
hyperdrive: { contextProperty: "sql", moduleSpecifier: "@lunora/hyperdrive" },
|
|
950
|
-
images: { contextProperty: "images", moduleSpecifier: "@lunora/bindings/images" },
|
|
951
|
-
kv: { contextProperty: "kv", moduleSpecifier: "@lunora/bindings/kv" },
|
|
952
|
-
mail: { moduleSpecifier: "@lunora/mail" },
|
|
953
|
-
payments: { contextProperty: "payments", moduleSpecifier: "@lunora/payment" },
|
|
954
|
-
// Pipelines is its own `@lunora/bindings/pipelines` subpath (distinct from
|
|
955
|
-
// `/analytics`), so a real import is a clean signal that won't be flipped by a
|
|
956
|
-
// plain analytics import; `ctx.pipelines` reads flip it too.
|
|
957
|
-
pipelines: { contextProperty: "pipelines", moduleSpecifier: "@lunora/bindings/pipelines" },
|
|
958
|
-
r2sql: { contextProperty: "r2sql", moduleSpecifier: "@lunora/bindings/r2sql" },
|
|
959
|
-
scheduler: { contextProperty: "scheduler", moduleSpecifier: "@lunora/scheduler" },
|
|
960
|
-
storage: { contextProperty: "storage", moduleSpecifier: "@lunora/storage" },
|
|
961
|
-
vectors: { contextProperty: "vectors", moduleSpecifier: "@lunora/bindings/vectors" },
|
|
962
|
-
workflows: { contextProperty: "workflows", moduleSpecifier: "@lunora/workflow" }
|
|
963
|
-
};
|
|
964
1018
|
const contextPropertiesRead = (sourceFile) => {
|
|
965
1019
|
const reachesContext = (receiver) => Node.isIdentifier(receiver) && receiver.getText() === "ctx";
|
|
966
1020
|
const names = /* @__PURE__ */ new Set();
|
|
@@ -985,44 +1039,24 @@ const contextPropertiesRead = (sourceFile) => {
|
|
|
985
1039
|
return names;
|
|
986
1040
|
};
|
|
987
1041
|
const discoverFeatureUsage = (project, lunoraDirectory) => {
|
|
988
|
-
const usage =
|
|
989
|
-
access: false,
|
|
990
|
-
ai: false,
|
|
991
|
-
analytics: false,
|
|
992
|
-
browser: false,
|
|
993
|
-
container: false,
|
|
994
|
-
flags: false,
|
|
995
|
-
hyperdrive: false,
|
|
996
|
-
images: false,
|
|
997
|
-
kv: false,
|
|
998
|
-
mail: false,
|
|
999
|
-
payments: false,
|
|
1000
|
-
pipelines: false,
|
|
1001
|
-
r2sql: false,
|
|
1002
|
-
scheduler: false,
|
|
1003
|
-
storage: false,
|
|
1004
|
-
vectors: false,
|
|
1005
|
-
workflows: false
|
|
1006
|
-
};
|
|
1007
|
-
const keys = Object.keys(PROBES);
|
|
1042
|
+
const usage = Object.fromEntries(CAPABILITIES.map((capability) => [capability.key, false]));
|
|
1008
1043
|
for (const filePath of listLunoraSourceFiles(lunoraDirectory)) {
|
|
1009
1044
|
const sourceFile = project.getSourceFile(filePath) ?? project.addSourceFileAtPath(filePath);
|
|
1010
1045
|
const importSpecifiers = new Set(sourceFile.getImportDeclarations().map((declaration) => declaration.getModuleSpecifierValue()));
|
|
1011
1046
|
const contextProperties = contextPropertiesRead(sourceFile);
|
|
1012
|
-
for (const
|
|
1013
|
-
if (usage[key]) {
|
|
1047
|
+
for (const capability of CAPABILITIES) {
|
|
1048
|
+
if (usage[capability.key]) {
|
|
1014
1049
|
continue;
|
|
1015
1050
|
}
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
usage[key] = true;
|
|
1051
|
+
if (importSpecifiers.has(capability.moduleSpecifier)) {
|
|
1052
|
+
usage[capability.key] = true;
|
|
1019
1053
|
continue;
|
|
1020
1054
|
}
|
|
1021
|
-
if (
|
|
1022
|
-
usage[key] = true;
|
|
1055
|
+
if (capability.contextProperty !== void 0 && contextProperties.has(capability.contextProperty)) {
|
|
1056
|
+
usage[capability.key] = true;
|
|
1023
1057
|
}
|
|
1024
1058
|
}
|
|
1025
|
-
if (
|
|
1059
|
+
if (CAPABILITIES.every((capability) => usage[capability.key])) {
|
|
1026
1060
|
break;
|
|
1027
1061
|
}
|
|
1028
1062
|
}
|
|
@@ -3134,9 +3168,11 @@ const writeIfChanged = (filePath, content) => {
|
|
|
3134
3168
|
writeFileSync(filePath, content, "utf8");
|
|
3135
3169
|
};
|
|
3136
3170
|
const writeIfPresent = (filePath, content) => {
|
|
3137
|
-
if (content
|
|
3138
|
-
|
|
3171
|
+
if (content === "") {
|
|
3172
|
+
rmSync(filePath, { force: true });
|
|
3173
|
+
return;
|
|
3139
3174
|
}
|
|
3175
|
+
writeIfChanged(filePath, content);
|
|
3140
3176
|
};
|
|
3141
3177
|
const readProjectVersion = (projectRoot) => {
|
|
3142
3178
|
const manifestPath = join(projectRoot, "package.json");
|
|
@@ -3210,6 +3246,7 @@ const runCodegen = (options) => {
|
|
|
3210
3246
|
const shapes = discoverShapes(project, lunoraDirectory);
|
|
3211
3247
|
const mutators = discoverMutators(project, lunoraDirectory);
|
|
3212
3248
|
const identity = discoverIdentity(project, lunoraDirectory);
|
|
3249
|
+
const env = discoverEnv(project, lunoraDirectory);
|
|
3213
3250
|
const workflows = discoverWorkflows(project, lunoraDirectory);
|
|
3214
3251
|
const queues = discoverQueues(project, lunoraDirectory);
|
|
3215
3252
|
const crons = discoverCrons(project, lunoraDirectory, workflows);
|
|
@@ -3296,6 +3333,7 @@ const runCodegen = (options) => {
|
|
|
3296
3333
|
const apiContent = emitApi(functions, workflows, useUmbrella);
|
|
3297
3334
|
const serverContent = emitServer({
|
|
3298
3335
|
containers,
|
|
3336
|
+
env,
|
|
3299
3337
|
hasAccessFacade,
|
|
3300
3338
|
hasAi,
|
|
3301
3339
|
hasAnalytics,
|
|
@@ -3318,6 +3356,7 @@ const runCodegen = (options) => {
|
|
|
3318
3356
|
const shardContent = emitShard({
|
|
3319
3357
|
advisories,
|
|
3320
3358
|
containers,
|
|
3359
|
+
env,
|
|
3321
3360
|
flagKeys,
|
|
3322
3361
|
hasAccessFacade,
|
|
3323
3362
|
hasAi,
|
package/dist/packem_shared/{buildOpenApiDocument-AgKWmlry.mjs → buildOpenApiDocument-bp1pYSV6.mjs}
RENAMED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { GENERATED_HEADER } from './
|
|
1
|
+
import { G as GENERATED_HEADER } from './emit-CBwEvCXQ.mjs';
|
|
2
2
|
import { s as sanitizeNamespace } from './paths-BRd6JHuF.mjs';
|
|
3
3
|
import { LUNORA_ERROR_CODES, objectSchema, argsObjectSchema, validatorIrToJsonSchema } from './LUNORA_ERROR_CODES-CySpQPD3.mjs';
|
|
4
4
|
|
|
@@ -1,6 +1,170 @@
|
|
|
1
1
|
import { LunoraError } from '@lunora/errors';
|
|
2
2
|
import { s as sanitizeNamespace } from './paths-BRd6JHuF.mjs';
|
|
3
3
|
|
|
4
|
+
const CAPABILITY_ROWS = [
|
|
5
|
+
// The middleware (`accessContext()` / `accessRoles()`) imports the `/context`
|
|
6
|
+
// and `/roles` subpaths, NOT the bare `@lunora/cloudflare-access` specifier —
|
|
7
|
+
// so the per-procedure middleware never trips the global `ctx.access` wiring.
|
|
8
|
+
// A handler reading `ctx.access` is the signal that wires it onto every ctx.
|
|
9
|
+
// `access` has a synchronous facade type, so its ctx field stays bespoke in
|
|
10
|
+
// `emit.ts` (no `serverCtxField` here).
|
|
11
|
+
{ contextProperty: "access", key: "access", moduleSpecifier: "@lunora/cloudflare-access" },
|
|
12
|
+
{
|
|
13
|
+
appMethod: { configKey: "ai", doc: "Override the Workers AI binding backing `ctx.ai` (defaults to `env.AI`).", method: "ai" },
|
|
14
|
+
contextProperty: "ai",
|
|
15
|
+
key: "ai",
|
|
16
|
+
moduleSpecifier: "@lunora/ai"
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
appMethod: {
|
|
20
|
+
configKey: "analytics",
|
|
21
|
+
doc: "Override the Analytics Engine dataset backing `ctx.analytics` (defaults to `env.ANALYTICS`).",
|
|
22
|
+
method: "analytics"
|
|
23
|
+
},
|
|
24
|
+
contextProperty: "analytics",
|
|
25
|
+
key: "analytics",
|
|
26
|
+
moduleSpecifier: "@lunora/bindings/analytics",
|
|
27
|
+
// `ctx.analytics` — Analytics Engine write helper. EVERY ctx: a write-only,
|
|
28
|
+
// fire-and-forget side effect, not a determinism hazard for reads.
|
|
29
|
+
serverCtxField: {
|
|
30
|
+
field: `
|
|
31
|
+
/** Analytics Engine telemetry sink. Fire-and-forget and sampled; do not read it back in-handler. */
|
|
32
|
+
readonly analytics: import("@lunora/bindings/analytics").AnalyticsClient;`,
|
|
33
|
+
tier: "every"
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
appMethod: {
|
|
38
|
+
configKey: "browser",
|
|
39
|
+
doc: "Override the Browser Rendering binding backing `ctx.browser` (defaults to `env.BROWSER`).",
|
|
40
|
+
method: "browser"
|
|
41
|
+
},
|
|
42
|
+
contextProperty: "browser",
|
|
43
|
+
key: "browser",
|
|
44
|
+
moduleSpecifier: "@lunora/browser",
|
|
45
|
+
// `ctx.browser` — Browser Rendering. ActionCtx ONLY: non-deterministic network I/O.
|
|
46
|
+
serverCtxField: {
|
|
47
|
+
field: `
|
|
48
|
+
/** Browser Rendering (screenshots/PDF/scrape). Non-deterministic — available only in actions. */
|
|
49
|
+
readonly browser: import("@lunora/browser").Browser;`,
|
|
50
|
+
tier: "action"
|
|
51
|
+
}
|
|
52
|
+
},
|
|
53
|
+
// `lunora/containers.ts` imports `defineContainer` from `@lunora/container`,
|
|
54
|
+
// and handlers reach live instances via `ctx.containers` — either signals the
|
|
55
|
+
// app wires containers, so the studio should show the Containers page. The ctx
|
|
56
|
+
// field is a per-declaration emitter (kept bespoke), so no `serverCtxField`.
|
|
57
|
+
{ contextProperty: "containers", key: "container", moduleSpecifier: "@lunora/container" },
|
|
58
|
+
// `ctx.flags` — OpenFeature. Umbrella-aware specifier + its own provider
|
|
59
|
+
// client, so both the ctx field and the shard fragment stay bespoke.
|
|
60
|
+
{ contextProperty: "flags", key: "flags", moduleSpecifier: "@lunora/flags" },
|
|
61
|
+
{
|
|
62
|
+
appMethod: {
|
|
63
|
+
configKey: "sql",
|
|
64
|
+
doc: "Wire the Hyperdrive SQL client backing `ctx.sql` — build it with `createHyperdrive` + `fromPostgresJs`/`fromNodePg`/`fromMysql2`.",
|
|
65
|
+
method: "hyperdrive"
|
|
66
|
+
},
|
|
67
|
+
contextProperty: "sql",
|
|
68
|
+
key: "hyperdrive",
|
|
69
|
+
moduleSpecifier: "@lunora/hyperdrive",
|
|
70
|
+
// `ctx.sql` — Hyperdrive (external Postgres/MySQL). ActionCtx ONLY: external,
|
|
71
|
+
// non-deterministic I/O whose writes are invisible to Lunora live queries.
|
|
72
|
+
serverCtxField: {
|
|
73
|
+
field: `
|
|
74
|
+
/**
|
|
75
|
+
* External database access via Hyperdrive. Non-deterministic — available only in actions. Writes here are NOT tracked by Lunora live queries; subscriptions will not re-run on external DB changes.
|
|
76
|
+
*/
|
|
77
|
+
readonly sql: import("@lunora/hyperdrive").SqlClient;`,
|
|
78
|
+
tier: "action"
|
|
79
|
+
}
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
appMethod: { configKey: "images", doc: "Override the Images binding backing `ctx.images` (defaults to `env.IMAGES`).", method: "images" },
|
|
83
|
+
contextProperty: "images",
|
|
84
|
+
key: "images",
|
|
85
|
+
moduleSpecifier: "@lunora/bindings/images",
|
|
86
|
+
// `ctx.images` — Cloudflare Images binding transforms. ActionCtx ONLY: non-deterministic compute/network I/O.
|
|
87
|
+
serverCtxField: {
|
|
88
|
+
field: `
|
|
89
|
+
/** Cloudflare Images transforms (resize/format/optimize). Non-deterministic — available only in actions. */
|
|
90
|
+
readonly images: import("@lunora/bindings/images").Images;`,
|
|
91
|
+
tier: "action"
|
|
92
|
+
}
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
appMethod: { configKey: "kv", doc: "Override the Workers KV binding backing `ctx.kv` (defaults to `env.KV`).", method: "kv" },
|
|
96
|
+
contextProperty: "kv",
|
|
97
|
+
key: "kv",
|
|
98
|
+
moduleSpecifier: "@lunora/bindings/kv",
|
|
99
|
+
// `ctx.kv` — Workers KV. Typed on EVERY ctx (a KV read is allowed in a
|
|
100
|
+
// deterministic read path the way `ctx.db` is; the binding is user-named).
|
|
101
|
+
serverCtxField: { field: `
|
|
102
|
+
readonly kv: import("@lunora/bindings/kv").Kv;`, tier: "every" }
|
|
103
|
+
},
|
|
104
|
+
// `mail` is import-only — no `ctx.mail` helper (mail is reached through its own
|
|
105
|
+
// client), so only a `@lunora/mail` import flips it.
|
|
106
|
+
{ key: "mail", moduleSpecifier: "@lunora/mail" },
|
|
107
|
+
{
|
|
108
|
+
appMethod: { configKey: "payment", doc: "Wire the payment options backing `ctx.payments`.", method: "payment" },
|
|
109
|
+
contextProperty: "payments",
|
|
110
|
+
key: "payments",
|
|
111
|
+
moduleSpecifier: "@lunora/payment"
|
|
112
|
+
},
|
|
113
|
+
// Pipelines is its own `@lunora/bindings/pipelines` subpath (distinct from
|
|
114
|
+
// `/analytics`), so a real import is a clean signal that won't be flipped by a
|
|
115
|
+
// plain analytics import; `ctx.pipelines` reads flip it too.
|
|
116
|
+
{
|
|
117
|
+
contextProperty: "pipelines",
|
|
118
|
+
key: "pipelines",
|
|
119
|
+
moduleSpecifier: "@lunora/bindings/pipelines",
|
|
120
|
+
// `ctx.pipelines` — Pipelines (R2-backed) ingestion sink. ActionCtx ONLY
|
|
121
|
+
// (write-only fire-and-forget, but external I/O — kept off query/mutation).
|
|
122
|
+
serverCtxField: {
|
|
123
|
+
field: `
|
|
124
|
+
/** Pipelines ingestion sink (durable, R2-backed). Fire-and-forget and batched; do not read it back in-handler. */
|
|
125
|
+
readonly pipelines: import("@lunora/bindings/pipelines").PipelineClient;`,
|
|
126
|
+
tier: "action"
|
|
127
|
+
}
|
|
128
|
+
},
|
|
129
|
+
{
|
|
130
|
+
appMethod: {
|
|
131
|
+
configKey: "r2sql",
|
|
132
|
+
doc: "Wire the R2 SQL client backing `ctx.r2sql` — build it with `createR2Sql({ accountId, apiToken, bucket })` (defaults to env `R2_SQL_TOKEN` / `R2_SQL_ACCOUNT_ID` / `R2_SQL_BUCKET`).",
|
|
133
|
+
method: "r2sql"
|
|
134
|
+
},
|
|
135
|
+
contextProperty: "r2sql",
|
|
136
|
+
key: "r2sql",
|
|
137
|
+
moduleSpecifier: "@lunora/bindings/r2sql",
|
|
138
|
+
// `ctx.r2sql` — R2 SQL (serverless query engine over Apache Iceberg tables).
|
|
139
|
+
// ActionCtx ONLY: external REST I/O, non-deterministic, and non-reactive
|
|
140
|
+
// (reads are not tracked by Lunora live queries).
|
|
141
|
+
serverCtxField: {
|
|
142
|
+
field: `
|
|
143
|
+
/**
|
|
144
|
+
* R2 SQL over Apache Iceberg tables (window functions, DISTINCT, set operations). Non-deterministic — available only in actions. Reads here are NOT tracked by Lunora live queries.
|
|
145
|
+
*/
|
|
146
|
+
readonly r2sql: import("@lunora/bindings/r2sql").R2SqlClient;`,
|
|
147
|
+
tier: "action"
|
|
148
|
+
}
|
|
149
|
+
},
|
|
150
|
+
{ contextProperty: "scheduler", key: "scheduler", moduleSpecifier: "@lunora/scheduler" },
|
|
151
|
+
{ contextProperty: "storage", key: "storage", moduleSpecifier: "@lunora/storage" },
|
|
152
|
+
{
|
|
153
|
+
appMethod: { configKey: "vectors", doc: "Wire the Vectorize index map backing `ctx.vectors`.", method: "vectors" },
|
|
154
|
+
contextProperty: "vectors",
|
|
155
|
+
key: "vectors",
|
|
156
|
+
moduleSpecifier: "@lunora/bindings/vectors"
|
|
157
|
+
},
|
|
158
|
+
{ contextProperty: "workflows", key: "workflows", moduleSpecifier: "@lunora/workflow" }
|
|
159
|
+
];
|
|
160
|
+
const CAPABILITIES = CAPABILITY_ROWS;
|
|
161
|
+
const SERVER_CTX_FIELDS = new Map(
|
|
162
|
+
CAPABILITIES.flatMap((capability) => capability.serverCtxField ? [[capability.key, capability.serverCtxField]] : [])
|
|
163
|
+
);
|
|
164
|
+
const APP_METHOD_CAPABILITIES = CAPABILITY_ROWS.flatMap(
|
|
165
|
+
(capability) => "appMethod" in capability ? [{ appMethod: capability.appMethod, key: capability.key }] : []
|
|
166
|
+
);
|
|
167
|
+
|
|
4
168
|
const LITERAL_VALUE_RE = /^(?:"[^"\\]*"|'[^'\\]*'|-?\d+(?:\.\d+)?|true|false|null)$/u;
|
|
5
169
|
|
|
6
170
|
const PASS_THROUGH_KINDS = /* @__PURE__ */ new Set(["any", "bigint", "boolean", "date", "id", "null", "number", "storage", "string", "timestamp"]);
|
|
@@ -755,6 +919,7 @@ const buildStorageBucketNames = (schema, ruleBuckets = []) => {
|
|
|
755
919
|
};
|
|
756
920
|
const emitServer = ({
|
|
757
921
|
containers = [],
|
|
922
|
+
env,
|
|
758
923
|
hasAccessFacade = false,
|
|
759
924
|
hasAi = false,
|
|
760
925
|
hasAnalytics = false,
|
|
@@ -827,36 +992,20 @@ ${envBindingFields}` : ""}
|
|
|
827
992
|
|
|
828
993
|
/** Alias for {@link CloudflareBindings} — the typed shape of \`env\`. */
|
|
829
994
|
export type Env = CloudflareBindings;`;
|
|
830
|
-
const
|
|
831
|
-
|
|
995
|
+
const serverCapabilityField = (key, enabled) => enabled ? SERVER_CTX_FIELDS.get(key)?.field ?? "" : "";
|
|
996
|
+
const kvContextField = serverCapabilityField("kv", hasKv);
|
|
997
|
+
const analyticsContextField = serverCapabilityField("analytics", hasAnalytics);
|
|
998
|
+
const hyperdriveActionField = serverCapabilityField("hyperdrive", hasHyperdrive);
|
|
999
|
+
const browserActionField = serverCapabilityField("browser", hasBrowser);
|
|
1000
|
+
const imagesActionField = serverCapabilityField("images", hasImages);
|
|
1001
|
+
const pipelinesActionField = serverCapabilityField("pipelines", hasPipelines);
|
|
1002
|
+
const r2sqlActionField = serverCapabilityField("r2sql", hasR2sql);
|
|
832
1003
|
const accessContextField = hasAccessFacade ? `
|
|
833
1004
|
/** Verified Cloudflare Access identity — a synchronous facade over the resolved claims (email / groups / hasGroup / claims). Anonymous when no Access token is present. */
|
|
834
1005
|
readonly access: import("@lunora/cloudflare-access/context").AccessFacade;` : "";
|
|
835
1006
|
const flagsContextField = hasFlags ? `
|
|
836
1007
|
/** Feature-flag evaluation (OpenFeature). Reads are memoized per request; evaluations never throw — a provider error resolves to the supplied default. */
|
|
837
1008
|
readonly flags: import("${base.flags}").LunoraFlags;` : "";
|
|
838
|
-
const hyperdriveActionField = hasHyperdrive ? `
|
|
839
|
-
/**
|
|
840
|
-
* External database access via Hyperdrive. Non-deterministic — available only in actions. Writes here are NOT tracked by Lunora live queries; subscriptions will not re-run on external DB changes.
|
|
841
|
-
*/
|
|
842
|
-
readonly sql: import("@lunora/hyperdrive").SqlClient;` : "";
|
|
843
|
-
const browserActionField = hasBrowser ? `
|
|
844
|
-
/** Browser Rendering (screenshots/PDF/scrape). Non-deterministic — available only in actions. */
|
|
845
|
-
readonly browser: import("@lunora/browser").Browser;` : "";
|
|
846
|
-
const imagesActionField = hasImages ? `
|
|
847
|
-
/** Cloudflare Images transforms (resize/format/optimize). Non-deterministic — available only in actions. */
|
|
848
|
-
readonly images: import("@lunora/bindings/images").Images;` : "";
|
|
849
|
-
const analyticsContextField = hasAnalytics ? `
|
|
850
|
-
/** Analytics Engine telemetry sink. Fire-and-forget and sampled; do not read it back in-handler. */
|
|
851
|
-
readonly analytics: import("@lunora/bindings/analytics").AnalyticsClient;` : "";
|
|
852
|
-
const pipelinesActionField = hasPipelines ? `
|
|
853
|
-
/** Pipelines ingestion sink (durable, R2-backed). Fire-and-forget and batched; do not read it back in-handler. */
|
|
854
|
-
readonly pipelines: import("@lunora/bindings/pipelines").PipelineClient;` : "";
|
|
855
|
-
const r2sqlActionField = hasR2sql ? `
|
|
856
|
-
/**
|
|
857
|
-
* R2 SQL over Apache Iceberg tables (window functions, DISTINCT, set operations). Non-deterministic — available only in actions. Reads here are NOT tracked by Lunora live queries.
|
|
858
|
-
*/
|
|
859
|
-
readonly r2sql: import("@lunora/bindings/r2sql").R2SqlClient;` : "";
|
|
860
1009
|
const hasWorkflows = workflows.length > 0;
|
|
861
1010
|
const workflowsTypeImport = hasWorkflows ? `import type { WorkflowHandle } from "@lunora/workflow";
|
|
862
1011
|
import type * as lunoraWorkflowDefinitions from "../workflows.js";
|
|
@@ -906,6 +1055,16 @@ type NarrowedAuth = Omit<QueryCtxBase["auth"], "getIdentity"> & { getIdentity: (
|
|
|
906
1055
|
const authContextField = identity ? `
|
|
907
1056
|
readonly auth: NarrowedAuth;` : "";
|
|
908
1057
|
const policyIdentityArgument = identity ? ", Identity" : "";
|
|
1058
|
+
const envTypeImport = env ? `import type * as lunoraEnvContract from "../env.js";
|
|
1059
|
+
` : "";
|
|
1060
|
+
const envTypeBlock = env ? `
|
|
1061
|
+
|
|
1062
|
+
/** This app's declared env contract (\`defineEnv\` in \`lunora/env.ts\`) — the validated, coercion-aware shape of \`ctx.env\`. */
|
|
1063
|
+
export type LunoraEnv = ReturnType<typeof lunoraEnvContract.${env.exportName}>;` : "";
|
|
1064
|
+
const envOmit = env ? ` | "env"` : "";
|
|
1065
|
+
const envContextField = env ? `
|
|
1066
|
+
/** Validated, typed environment declared by \`defineEnv\` in \`lunora/env.ts\` — parsed & coercion-aware config values (\`ctx.env.STRIPE_KEY\`); a missing or invalid value throws at read time. */
|
|
1067
|
+
readonly env: LunoraEnv;` : "";
|
|
909
1068
|
const server = `${GENERATED_HEADER}import { createPolicyDsl, initLunora, v as vBase } from "${base.server}";
|
|
910
1069
|
import type {
|
|
911
1070
|
ActionBuilder,
|
|
@@ -927,11 +1086,11 @@ import type {
|
|
|
927
1086
|
} from "${base.server}";
|
|
928
1087
|
|
|
929
1088
|
import type { DataModel, DatabaseReaderFacade, DatabaseWriterFacade, Doc, Id as IdOfTable, OrmReader, OrmWriter, Relations, TableName } from "./dataModel.js";
|
|
930
|
-
${aiTypeImport}${paymentsTypeImport}${containersTypeImport}${workflowsTypeImport}${queuesTypeImport}${identityTypeImport}
|
|
1089
|
+
${aiTypeImport}${paymentsTypeImport}${containersTypeImport}${workflowsTypeImport}${queuesTypeImport}${identityTypeImport}${envTypeImport}
|
|
931
1090
|
export type { DataModel, Doc, Id, TableName } from "./dataModel.js";
|
|
932
1091
|
|
|
933
1092
|
/** Storage buckets this schema declares (\`v.storage("name")\`), narrowing \`ctx.storage.bucket(name)\`. */
|
|
934
|
-
export type StorageBucketName = ${storageBucketUnion};${envBlock}${workflowsTypeBlock}${queuesTypeBlock}${identityTypeBlock}
|
|
1093
|
+
export type StorageBucketName = ${storageBucketUnion};${envBlock}${workflowsTypeBlock}${queuesTypeBlock}${identityTypeBlock}${envTypeBlock}
|
|
935
1094
|
|
|
936
1095
|
/**
|
|
937
1096
|
* Project-typed contexts. The base contexts from \`@lunora/server\` are
|
|
@@ -960,22 +1119,22 @@ type TypedTableQuery = (<T extends TableName>(table: T) => TableReader<Doc<T>>)
|
|
|
960
1119
|
*/
|
|
961
1120
|
type TypedTableGet = <T extends TableName>(id: IdOfTable<T>) => Promise<Doc<T> | null>;
|
|
962
1121
|
|
|
963
|
-
export interface QueryCtx extends Omit<QueryCtxBase, "db" | "storage"${authOmit}> {
|
|
1122
|
+
export interface QueryCtx extends Omit<QueryCtxBase, "db" | "storage"${authOmit}${envOmit}> {
|
|
964
1123
|
readonly db: Omit<DatabaseReader, "query" | "get"> & DatabaseReaderFacade & { query: TypedTableQuery; get: TypedTableGet };
|
|
965
1124
|
readonly orm: OrmReader;
|
|
966
|
-
readonly storage: ReadOnlyStorage<StorageBucketName>;${accessContextField}${kvContextField}${flagsContextField}${analyticsContextField}${authContextField}
|
|
1125
|
+
readonly storage: ReadOnlyStorage<StorageBucketName>;${accessContextField}${kvContextField}${flagsContextField}${analyticsContextField}${envContextField}${authContextField}
|
|
967
1126
|
}
|
|
968
1127
|
|
|
969
|
-
export interface MutationCtx extends Omit<MutationCtxBase, "db" | "storage"${workflowsOmit}${authOmit}> {
|
|
1128
|
+
export interface MutationCtx extends Omit<MutationCtxBase, "db" | "storage"${workflowsOmit}${authOmit}${envOmit}> {
|
|
970
1129
|
readonly db: Omit<DatabaseWriter, "query" | "get"> & DatabaseWriterFacade & { query: TypedTableQuery; get: TypedTableGet };
|
|
971
1130
|
readonly orm: OrmWriter;
|
|
972
|
-
readonly storage: ReadOnlyStorage<StorageBucketName>;${accessContextField}${kvContextField}${flagsContextField}${analyticsContextField}${workflowsContextField}${queuesContextField}${authContextField}
|
|
1131
|
+
readonly storage: ReadOnlyStorage<StorageBucketName>;${accessContextField}${kvContextField}${flagsContextField}${analyticsContextField}${envContextField}${workflowsContextField}${queuesContextField}${authContextField}
|
|
973
1132
|
}
|
|
974
1133
|
|
|
975
|
-
export interface ActionCtx extends Omit<ActionCtxBase, "db" | "storage"${workflowsOmit}${authOmit}> {
|
|
1134
|
+
export interface ActionCtx extends Omit<ActionCtxBase, "db" | "storage"${workflowsOmit}${authOmit}${envOmit}> {
|
|
976
1135
|
readonly db: Omit<DatabaseWriter, "query" | "get"> & DatabaseWriterFacade & { query: TypedTableQuery; get: TypedTableGet };
|
|
977
1136
|
readonly orm: OrmWriter;
|
|
978
|
-
readonly storage: StorageBase<StorageBucketName>;${accessContextField}${aiActionField}${paymentsActionField}${containersActionField}${kvContextField}${flagsContextField}${hyperdriveActionField}${browserActionField}${imagesActionField}${analyticsContextField}${pipelinesActionField}${r2sqlActionField}${workflowsContextField}${queuesContextField}${authContextField}
|
|
1137
|
+
readonly storage: StorageBase<StorageBucketName>;${accessContextField}${aiActionField}${paymentsActionField}${containersActionField}${kvContextField}${flagsContextField}${hyperdriveActionField}${browserActionField}${imagesActionField}${analyticsContextField}${pipelinesActionField}${r2sqlActionField}${envContextField}${workflowsContextField}${queuesContextField}${authContextField}
|
|
979
1138
|
}
|
|
980
1139
|
|
|
981
1140
|
/**
|
|
@@ -1386,6 +1545,21 @@ const emitFlagsFragments = (hasFlags, flagsSpecifier) => {
|
|
|
1386
1545
|
stub: ""
|
|
1387
1546
|
};
|
|
1388
1547
|
};
|
|
1548
|
+
const emitEnvFragments = (env) => {
|
|
1549
|
+
if (!env) {
|
|
1550
|
+
return EMPTY_HELPER_FRAGMENTS;
|
|
1551
|
+
}
|
|
1552
|
+
return {
|
|
1553
|
+
build: `
|
|
1554
|
+
const envConfig = lunoraEnvContract.${env.exportName}(env);
|
|
1555
|
+
`,
|
|
1556
|
+
configField: "",
|
|
1557
|
+
contextField: `
|
|
1558
|
+
env: envConfig,`,
|
|
1559
|
+
importLines: [`import * as lunoraEnvContract from "../env.js";`],
|
|
1560
|
+
stub: ""
|
|
1561
|
+
};
|
|
1562
|
+
};
|
|
1389
1563
|
const emitAccessFragments = (hasAccessFacade) => {
|
|
1390
1564
|
if (!hasAccessFacade) {
|
|
1391
1565
|
return EMPTY_HELPER_FRAGMENTS;
|
|
@@ -1996,6 +2170,7 @@ const buildDoTypeImports = (hasVectors, hasWorkflows, hasQueues, hasFlags) => [
|
|
|
1996
2170
|
const emitShard = ({
|
|
1997
2171
|
advisories = [],
|
|
1998
2172
|
containers = [],
|
|
2173
|
+
env,
|
|
1999
2174
|
flagKeys = [],
|
|
2000
2175
|
hasAccessFacade = false,
|
|
2001
2176
|
hasAi = false,
|
|
@@ -2027,6 +2202,7 @@ const emitShard = ({
|
|
|
2027
2202
|
const kvFragments = emitKvFragments(hasKv);
|
|
2028
2203
|
const flagsFragments = emitFlagsFragments(hasFlags, base.flags);
|
|
2029
2204
|
const flagsOverrides = emitFlagsOverrides(flagKeys, hasFlags, base.flags);
|
|
2205
|
+
const envFragments = emitEnvFragments(env);
|
|
2030
2206
|
const analyticsFragments = emitAnalyticsFragments(hasAnalytics);
|
|
2031
2207
|
const imagesFragments = emitImagesFragments(hasImages);
|
|
2032
2208
|
const hyperdriveFragments = emitHyperdriveFragments(hasHyperdrive);
|
|
@@ -2181,6 +2357,7 @@ const LUNORA_RLS_READ_REGISTRY = buildRlsReadRegistry(Object.values(LUNORA_FUNCT
|
|
|
2181
2357
|
...accessFragments.importLines,
|
|
2182
2358
|
...kvFragments.importLines,
|
|
2183
2359
|
...flagsFragments.importLines,
|
|
2360
|
+
...envFragments.importLines,
|
|
2184
2361
|
...analyticsFragments.importLines,
|
|
2185
2362
|
...imagesFragments.importLines,
|
|
2186
2363
|
...hyperdriveFragments.importLines,
|
|
@@ -2476,8 +2653,8 @@ ${schema.tables.map(
|
|
|
2476
2653
|
const secretsBuild = `
|
|
2477
2654
|
const secrets = createSecrets(env);
|
|
2478
2655
|
`;
|
|
2479
|
-
const everyContextBuild = `${accessFragments.build}${kvFragments.build}${flagsFragments.build}${analyticsFragments.build}${secretsBuild}`;
|
|
2480
|
-
const everyContextField = `${accessFragments.contextField}${kvFragments.contextField}${flagsFragments.contextField}${analyticsFragments.contextField}
|
|
2656
|
+
const everyContextBuild = `${accessFragments.build}${kvFragments.build}${flagsFragments.build}${analyticsFragments.build}${envFragments.build}${secretsBuild}`;
|
|
2657
|
+
const everyContextField = `${accessFragments.contextField}${kvFragments.contextField}${flagsFragments.contextField}${analyticsFragments.contextField}${envFragments.contextField}
|
|
2481
2658
|
secrets,`;
|
|
2482
2659
|
const actionOnlyHasAny = hasImages || hasHyperdrive || hasBrowser || hasR2sql || hasPipelines;
|
|
2483
2660
|
const actionOnlyBlock = actionOnlyHasAny ? `
|
|
@@ -3271,4 +3448,4 @@ const emitWranglerCronTriggers = (crons) => {
|
|
|
3271
3448
|
return triggers;
|
|
3272
3449
|
};
|
|
3273
3450
|
|
|
3274
|
-
export {
|
|
3451
|
+
export { APP_METHOD_CAPABILITIES as A, CAPABILITIES as C, GENERATED_HEADER as G, emitCollections as a, emitContainers as b, emitCrons as c, emitDataModel as d, emitApi as e, emitDrizzleSchema as f, emitFunctions as g, emitServer as h, emitShard as i, emitVectors as j, emitWorkflows as k, emitWranglerCronTriggers as l, buildStorageColumns as m, emitQueues as n, emitSeed as o };
|
|
@@ -1,26 +1,9 @@
|
|
|
1
|
-
import { GENERATED_HEADER } from './
|
|
2
|
-
|
|
3
|
-
const
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
[
|
|
8
|
-
"hasHyperdrive",
|
|
9
|
-
"hyperdrive",
|
|
10
|
-
"sql",
|
|
11
|
-
"Wire the Hyperdrive SQL client backing `ctx.sql` — build it with `createHyperdrive` + `fromPostgresJs`/`fromNodePg`/`fromMysql2`."
|
|
12
|
-
],
|
|
13
|
-
["hasImages", "images", "images", "Override the Images binding backing `ctx.images` (defaults to `env.IMAGES`)."],
|
|
14
|
-
["hasKv", "kv", "kv", "Override the Workers KV binding backing `ctx.kv` (defaults to `env.KV`)."],
|
|
15
|
-
["hasPayments", "payment", "payment", "Wire the payment options backing `ctx.payments`."],
|
|
16
|
-
[
|
|
17
|
-
"hasR2sql",
|
|
18
|
-
"r2sql",
|
|
19
|
-
"r2sql",
|
|
20
|
-
"Wire the R2 SQL client backing `ctx.r2sql` — build it with `createR2Sql({ accountId, apiToken, bucket })` (defaults to env `R2_SQL_TOKEN` / `R2_SQL_ACCOUNT_ID` / `R2_SQL_BUCKET`)."
|
|
21
|
-
],
|
|
22
|
-
["hasVectors", "vectors", "vectors", "Wire the Vectorize index map backing `ctx.vectors`."]
|
|
23
|
-
];
|
|
1
|
+
import { A as APP_METHOD_CAPABILITIES, G as GENERATED_HEADER } from './emit-CBwEvCXQ.mjs';
|
|
2
|
+
|
|
3
|
+
const hasFlagKey = (key) => `has${key.charAt(0).toUpperCase()}${key.slice(1)}`;
|
|
4
|
+
const LONG_TAIL = APP_METHOD_CAPABILITIES.map(
|
|
5
|
+
({ appMethod, key }) => [hasFlagKey(key), appMethod.method, appMethod.configKey, appMethod.doc]
|
|
6
|
+
);
|
|
24
7
|
const hasAnyLongTail = (options) => LONG_TAIL.some(([flag]) => options[flag]);
|
|
25
8
|
const buildIdentityImports = (identity) => identity ? [`import * as lunoraIdentityContract from "../identity.js";`] : [];
|
|
26
9
|
const buildAccessImports = (hasAccess, hasAuth) => hasAccess ? [
|
|
@@ -83,7 +66,10 @@ const buildImportLines = (options) => {
|
|
|
83
66
|
...hasGlobal || hasHyperdriveGlobal ? [`import schema from "../schema.js";`] : [],
|
|
84
67
|
`import { LUNORA_CRONS } from "./crons.js";`,
|
|
85
68
|
`import { LUNORA_FUNCTIONS } from "./functions.js";`,
|
|
86
|
-
...hasQueue ? [
|
|
69
|
+
...hasQueue ? [
|
|
70
|
+
`import { createQueueCaptureSink, dispatchQueueBatch, shouldCaptureQueue } from "@lunora/queue";`,
|
|
71
|
+
`import { LUNORA_QUEUE_REGISTRY } from "./queues.js";`
|
|
72
|
+
] : [],
|
|
87
73
|
...wantsOpenApi ? [`import { openApiSpec } from "./openapi.js";`] : [],
|
|
88
74
|
...wantsOpenRpc ? [`import { openRpcSpec } from "./openrpc.js";`] : [],
|
|
89
75
|
`import { createShardDO } from "./shard.js";`
|
|
@@ -416,10 +402,17 @@ const buildBaseWorkerOptions = (options) => [
|
|
|
416
402
|
// The push-consumer handler backing the worker's `queue(batch, …)` entry:
|
|
417
403
|
// routes each delivered batch to its `defineQueue` handler. Built from
|
|
418
404
|
// `@lunora/queue` here (keeping the runtime decoupled) and wired only when the
|
|
419
|
-
// app declares push queues in `lunora/queues.ts`.
|
|
405
|
+
// app declares push queues in `lunora/queues.ts`. In a dev environment (or with
|
|
406
|
+
// `LUNORA_QUEUE_CAPTURE`), every consumed message is recorded into the studio's
|
|
407
|
+
// Queues log via the root shard's `recordQueueMessage` admin RPC.
|
|
420
408
|
...options.hasQueue ? [
|
|
421
409
|
` queue: (batch: unknown, queueEnv: unknown, _context: ExecutionContextLike): Promise<void> =>`,
|
|
422
|
-
` dispatchQueueBatch(batch as Parameters<typeof dispatchQueueBatch>[0], LUNORA_QUEUE_REGISTRY, {
|
|
410
|
+
` dispatchQueueBatch(batch as Parameters<typeof dispatchQueueBatch>[0], LUNORA_QUEUE_REGISTRY, {`,
|
|
411
|
+
` capture: shouldCaptureQueue(queueEnv as Record<string, unknown>)`,
|
|
412
|
+
` ? createQueueCaptureSink(queueEnv as Record<string, unknown>${options.jurisdiction ? `, { jurisdiction: ${JSON.stringify(options.jurisdiction)} }` : ""})`,
|
|
413
|
+
` : undefined,`,
|
|
414
|
+
` env: queueEnv as Record<string, unknown>,`,
|
|
415
|
+
` }),`
|
|
423
416
|
] : [],
|
|
424
417
|
` routes: this.routeMap,`,
|
|
425
418
|
` shardDO: this.shardSelector?.(env) ?? (undefined as unknown as ShardNamespaceLike),`
|
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.32",
|
|
4
4
|
"description": "Code generator for Lunora: emits _generated/{api,server,dataModel}.ts from your schema",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"cloudflare",
|
|
@@ -46,10 +46,10 @@
|
|
|
46
46
|
"access": "public"
|
|
47
47
|
},
|
|
48
48
|
"dependencies": {
|
|
49
|
-
"@lunora/advisor": "1.0.0-alpha.
|
|
49
|
+
"@lunora/advisor": "1.0.0-alpha.18",
|
|
50
50
|
"@lunora/container": "1.0.0-alpha.6",
|
|
51
51
|
"@lunora/errors": "1.0.0-alpha.1",
|
|
52
|
-
"@lunora/queue": "1.0.0-alpha.
|
|
52
|
+
"@lunora/queue": "1.0.0-alpha.4",
|
|
53
53
|
"@lunora/scheduler": "1.0.0-alpha.5",
|
|
54
54
|
"@lunora/values": "1.0.0-alpha.4",
|
|
55
55
|
"@lunora/workflow": "1.0.0-alpha.6",
|