@lunora/config 1.0.0-alpha.35 → 1.0.0-alpha.351

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.
Files changed (129) hide show
  1. package/LICENSE.md +135 -0
  2. package/README.md +3 -3
  3. package/dist/cloudflare/index.d.mts +1252 -0
  4. package/dist/cloudflare/index.d.ts +1252 -0
  5. package/dist/cloudflare/index.mjs +1 -0
  6. package/dist/index.d.mts +1048 -917
  7. package/dist/index.d.ts +1048 -917
  8. package/dist/index.mjs +1 -23
  9. package/dist/packem_shared/ACCENT-CotPTfv7.mjs +7 -0
  10. package/dist/packem_shared/AGENT_MODE_ENV-D8MvSwPE.mjs +1 -0
  11. package/dist/packem_shared/AGENT_RULES_DIR-HrrbNZPy.mjs +1 -0
  12. package/dist/packem_shared/ALLOW_FORWARDED_ENV-BUndghJx.mjs +1 -0
  13. package/dist/packem_shared/BINDING_MANIFEST_VERSION-CfXEYG8e.mjs +1 -0
  14. package/dist/packem_shared/CLOUDFLARE_CLI_CONFIG_WARNING_ENV-BKMrOuXV.mjs +1 -0
  15. package/dist/packem_shared/CLOUDFLARE_DRIVER-CULavrYO.mjs +1 -0
  16. package/dist/packem_shared/CLOUDFLARE_TOOLCHAIN_VERSIONS-DV5E_f_q.mjs +1 -0
  17. package/dist/packem_shared/CODEGEN_ENV-ZsCxV1kP.mjs +1 -0
  18. package/dist/packem_shared/COMPOSED_WORKER_ENTRY-Ciiba5g_.mjs +1 -0
  19. package/dist/packem_shared/DEFAULT_DEPLOY_TARGET-rR7buNQw.mjs +1 -0
  20. package/dist/packem_shared/DEFAULT_OBSERVABILITY-bN6UkTMx.mjs +1 -0
  21. package/dist/packem_shared/DEV_BINDINGS_FILE-C0ZN_XlP.mjs +4 -0
  22. package/dist/packem_shared/DEV_VARS_EXAMPLE_FILE-CqLorAxT.mjs +6 -0
  23. package/dist/packem_shared/DEV_WORKER_ENV_VALUE-2XFXmRrP.mjs +1 -0
  24. package/dist/packem_shared/GLOBAL_FETCH_STRICTLY_PUBLIC_FLAG-f8CnJha3.mjs +1 -0
  25. package/dist/packem_shared/LINKED_PROJECT_DIR-Ba5qPEwo.mjs +2 -0
  26. package/dist/packem_shared/LUNORA_EVENT_SOURCE-B9ZVohjO.mjs +1 -0
  27. package/dist/packem_shared/LUNORA_IGNORED_PATHS-U93uPxrW.mjs +19 -0
  28. package/dist/packem_shared/LUNORA_TAG-CiQM3BkI.mjs +1 -0
  29. package/dist/packem_shared/LunoraReporter-f277GLNT.mjs +6 -0
  30. package/dist/packem_shared/PACKAGE_SECRETS_REGISTRY-38Plje8b.mjs +1 -0
  31. package/dist/packem_shared/POLICY_SCAFFOLD_ENDPOINT-BmJYwAy2.mjs +1 -0
  32. package/dist/packem_shared/REMOTE_ELIGIBLE_KEYS-PLeh_74E.mjs +1 -0
  33. package/dist/packem_shared/REQUIRED_COMPATIBILITY_DATE-OLQlG0oj.mjs +1 -0
  34. package/dist/packem_shared/SCHEMA_EDIT_ENDPOINT-BeTxqCuQ.mjs +1 -0
  35. package/dist/packem_shared/SEED_ENDPOINT-2B56PN_H.mjs +1 -0
  36. package/dist/packem_shared/STUDIO_PATH-CSx_psKS.mjs +1 -0
  37. package/dist/packem_shared/UNEXPORTED_CLASS_MARKER-DwJCN8fX.mjs +1 -0
  38. package/dist/packem_shared/WORKERS_CACHE_MIN_DATE-0k9ABJtF.mjs +1 -0
  39. package/dist/packem_shared/WRANGLER_FILES-UNW-xY5u.mjs +1 -0
  40. package/dist/packem_shared/acceptsConnection-DHhUYGjT.mjs +2 -0
  41. package/dist/packem_shared/addArgsFor-CYZKhNIo.mjs +1 -0
  42. package/dist/packem_shared/applyAdditiveEdit-CH0VhMJ2.mjs +6 -0
  43. package/dist/packem_shared/applyModify-DKP2l6S9.mjs +1 -0
  44. package/dist/packem_shared/applyStudioAssetCache-DHQEJuuv.mjs +1 -0
  45. package/dist/packem_shared/assertWranglerSatisfiesSchema-Dd7ZPhw7.mjs +3 -0
  46. package/dist/packem_shared/assetContentType-CUb5bpbI.mjs +1 -0
  47. package/dist/packem_shared/buildPackageSecretsBlock-BWV_VxqV.mjs +19 -0
  48. package/dist/packem_shared/celld-config-D-L6uskI.mjs +3 -0
  49. package/dist/packem_shared/classifyPolicyEdit-DJi9Fk8G.mjs +24 -0
  50. package/dist/packem_shared/collectExportGaps-BPuhGH2J.mjs +2 -0
  51. package/dist/packem_shared/createConfirm-D5mKTMHj.mjs +7 -0
  52. package/dist/packem_shared/createDiscoveryCache-npJI4uej.mjs +1 -0
  53. package/dist/packem_shared/describePreservedCrons-C5KPuPy3.mjs +1 -0
  54. package/dist/packem_shared/describeWithheldWorkersAi-IIxe3TuI.mjs +1 -0
  55. package/dist/packem_shared/detectFramework-Dfpvu6rD.mjs +1 -0
  56. package/dist/packem_shared/discover-info-DC2MrAIM.mjs +1 -0
  57. package/dist/packem_shared/discoverAgentInfo-pqFMJBtJ.mjs +1 -0
  58. package/dist/packem_shared/discoverContainerInfo-DzXr7Vm3.mjs +1 -0
  59. package/dist/packem_shared/discoverSchemaInfo-BBRlXZop.mjs +1 -0
  60. package/dist/packem_shared/discoverWorkflowInfo-zW7Tt0Tn.mjs +1 -0
  61. package/dist/packem_shared/guards-Buu_E7mP.mjs +1 -0
  62. package/dist/packem_shared/hasCloudflareCredentials-byvHpEiD.mjs +1 -0
  63. package/dist/packem_shared/infer-bindings-C1NFOdMi.mjs +1 -0
  64. package/dist/packem_shared/infer-bindings.d-CFxssIAC.d.mts +480 -0
  65. package/dist/packem_shared/infer-bindings.d-CFxssIAC.d.ts +480 -0
  66. package/dist/packem_shared/inferLunoraBindings-Gp_7yyIo.mjs +1 -0
  67. package/dist/packem_shared/interpretRemote-CcmGeGZ_.mjs +1 -0
  68. package/dist/packem_shared/lunora-manifest-DuH_Cmyu.mjs +6 -0
  69. package/dist/packem_shared/materializeServiceDevConfigs-DLUHefD-.mjs +1 -0
  70. package/dist/packem_shared/mergeWranglerEnvironment-DXiB-HcS.mjs +1 -0
  71. package/dist/packem_shared/package-secrets-registry-BeheNwsP.mjs +1 -0
  72. package/dist/packem_shared/parseDevVariable-teAAahVD.mjs +1 -0
  73. package/dist/packem_shared/parseSchema-D1Wbr1qv.mjs +1 -0
  74. package/dist/packem_shared/policy-scaffold.d-D2H4_G01.d.mts +86 -0
  75. package/dist/packem_shared/policy-scaffold.d-D2H4_G01.d.ts +86 -0
  76. package/dist/packem_shared/process-tree-once-Ou4SfxKM.mjs +1 -0
  77. package/dist/packem_shared/readProjectDependencies-l3uhUKjo.mjs +1 -0
  78. package/dist/packem_shared/reconcile-services-DFqH4eMQ.mjs +1 -0
  79. package/dist/packem_shared/reconcileBindingsSafely-7IJ58Uit.mjs +1 -0
  80. package/dist/packem_shared/reconcileWranglerCompatibilityDate-hocXEuRA.mjs +1 -0
  81. package/dist/packem_shared/renderStudioHtml-ByowDtMl.mjs +15 -0
  82. package/dist/packem_shared/resolveSchemaDirectory-Ca5P6KuP.mjs +1 -0
  83. package/dist/packem_shared/runPostCodegenHook-Dx3yTsYZ.mjs +1 -0
  84. package/dist/packem_shared/scanWranglerVariablesForSecrets-BFTVje1q.mjs +1 -0
  85. package/dist/packem_shared/serveJsonHandler-Dv0EdCb9.mjs +1 -0
  86. package/dist/packem_shared/startCelldDevSession-BLFsd6jG.mjs +1 -0
  87. package/dist/packem_shared/streamContainerLogs-0nko1qpv.mjs +2 -0
  88. package/dist/packem_shared/validate-bindings-CvNBF3U4.mjs +1 -0
  89. package/dist/packem_shared/withTailConsumer-DngzpJMK.mjs +1 -0
  90. package/dist/packem_shared/worker-entry-checks-AIASCYl7.mjs +1 -0
  91. package/dist/packem_shared/wranglerCodegenInputs-CbisphsH.mjs +1 -0
  92. package/dist/packem_shared/wranglerToAlchemy-CBO2ucRm.mjs +6 -0
  93. package/dist/packem_shared/write-atomic-CK6VZaPI.mjs +1 -0
  94. package/dist/studio-host/index.d.mts +314 -110
  95. package/dist/studio-host/index.d.ts +314 -110
  96. package/dist/studio-host/index.mjs +1 -7
  97. package/package.json +16 -7
  98. package/dist/packem_shared/ACCENT-DW1XJn8i.mjs +0 -40
  99. package/dist/packem_shared/AGENT_RULES_DIR-lcgC08aE.mjs +0 -40
  100. package/dist/packem_shared/DEV_VARS_EXAMPLE_FILE-dJPNTEnK.mjs +0 -37
  101. package/dist/packem_shared/LINKED_PROJECT_DIR-CXwXzV_C.mjs +0 -52
  102. package/dist/packem_shared/LUNORA_CONFIG_FILE-CtcIcB5-.mjs +0 -34
  103. package/dist/packem_shared/LUNORA_EVENT_SOURCE-D2fDeGB6.mjs +0 -86
  104. package/dist/packem_shared/LunoraReporter-Ci-bDCK9.mjs +0 -70
  105. package/dist/packem_shared/PACKAGE_SECRETS_REGISTRY-B8t_SdoZ.mjs +0 -70
  106. package/dist/packem_shared/POLICY_SCAFFOLD_ENDPOINT-CiC2IGKx.mjs +0 -103
  107. package/dist/packem_shared/REMOTE_ELIGIBLE_KEYS-BC7_e9Bz.mjs +0 -105
  108. package/dist/packem_shared/REQUIRED_COMPATIBILITY_DATE-2YYyWJUq.mjs +0 -561
  109. package/dist/packem_shared/SCHEMA_EDIT_ENDPOINT-Df-Wrix-.mjs +0 -99
  110. package/dist/packem_shared/SEED_ENDPOINT-DVCjaGO-.mjs +0 -61
  111. package/dist/packem_shared/WRANGLER_FILES-DwSuC-Kn.mjs +0 -25
  112. package/dist/packem_shared/applyAdditiveEdit-C-snTFEV.mjs +0 -228
  113. package/dist/packem_shared/buildPackageSecretsBlock-DWDKHViT.mjs +0 -243
  114. package/dist/packem_shared/classifyPolicyEdit-BHeAqF8P.mjs +0 -99
  115. package/dist/packem_shared/createConfirm-fvpdgJ9s.mjs +0 -100
  116. package/dist/packem_shared/detectFramework-Br-BcPBq.mjs +0 -41
  117. package/dist/packem_shared/discoverContainerInfo-BXFs6Wav.mjs +0 -19
  118. package/dist/packem_shared/discoverSchemaInfo-BB-CKlTK.mjs +0 -25
  119. package/dist/packem_shared/discoverWorkflowInfo-CedvR0mn.mjs +0 -19
  120. package/dist/packem_shared/inferLunoraBindings-ByMwG-gH.mjs +0 -352
  121. package/dist/packem_shared/loadStudioAssets-Csk5RS4E.mjs +0 -28
  122. package/dist/packem_shared/parseDevVariable-CJiq2IwE.mjs +0 -30
  123. package/dist/packem_shared/parseSchema-DSeyktvG.mjs +0 -107
  124. package/dist/packem_shared/policy-scaffold.d-DCmwn7zQ.d.mts +0 -74
  125. package/dist/packem_shared/policy-scaffold.d-DCmwn7zQ.d.ts +0 -74
  126. package/dist/packem_shared/reconcileWranglerBindings-Cruwwx1M.mjs +0 -334
  127. package/dist/packem_shared/renderStudioHtml-449Ysn75.mjs +0 -37
  128. package/dist/packem_shared/serveJsonHandler-B4OLTGLS.mjs +0 -86
  129. package/dist/packem_shared/streamContainerLogs-BZ4cOZwH.mjs +0 -157
@@ -0,0 +1,480 @@
1
+ import { SchemaIR, AgentIR, ContainerIR, QueueIR, ServiceBindingIR, WorkflowIR } from '@lunora/codegen';
2
+ /**
3
+ * `DeployDriver` — the provider-neutral seam between a Lunora command and the
4
+ * host CLI that carries it out (plan 114, §5.3).
5
+ *
6
+ * The seam is the **toolchain surface**: which command a host runs to deploy,
7
+ * serve, tail, or set a secret. A driver only *describes* that command
8
+ * ({@link ToolchainCommand}); it never spawns. The CLI keeps ownership of
9
+ * running it — package-manager resolution (`pnpm exec` / `npx --` / `bun x`)
10
+ * and the injected spawner its tests substitute — so the driver stays free of
11
+ * process concerns and remains trivially testable as a pure function.
12
+ *
13
+ * Each request type below is deliberately neutral: `preview`, `environment`,
14
+ * `temporary` are concepts, not wrangler flags. A second host maps the same
15
+ * request onto its own CLI without the caller changing.
16
+ *
17
+ * Three drivers are registered: Cloudflare (`cloudflare/cloudflare-driver.ts`)
18
+ * and celld (`celld/celld-driver.ts`), which ship toolchains, and Node
19
+ * (`node/node-driver.ts`), which has none — it is a codegen target, and
20
+ * `lunora deploy` / `lunora dev` refuse it at selection.
21
+ *
22
+ * **What this seam deliberately does NOT carry: configuration inference.** It
23
+ * used to, through an `infer`/`provision` pair over a provider-neutral
24
+ * `ResourceGraph`. Nothing ever called either one — every consumer reads
25
+ * `.toolchain` or just validates the target — and the arm rotted in place: the
26
+ * Node driver was *only* `infer` + `provision`, so its report of what that
27
+ * target cannot serve (containers, undispatched crons) could not reach an
28
+ * operator however wrong the app was. The reason it never got wired is worth
29
+ * keeping: writing real host configuration needs the host's own encodings —
30
+ * binding names, DO class wiring, migration tags — which a neutral graph
31
+ * necessarily discards, so `provision` re-derived them anyway and the graph was
32
+ * decorative. A second target that needs to share inference should grow the
33
+ * seam back with a caller attached, and with an encoding escape hatch.
34
+ */
35
+ /**
36
+ * A host CLI invocation, described but not run.
37
+ *
38
+ * `tool` is the binary name only (`"wrangler"`); the caller resolves how to
39
+ * execute it through the project's package manager (see `toolchainExecArgs`).
40
+ * Keeping that split means a driver never has to know whether the project uses
41
+ * pnpm, npm, yarn, or bun.
42
+ */
43
+ interface ToolchainCommand {
44
+ /** Arguments for {@link ToolchainCommand.tool}. */
45
+ args: ReadonlyArray<string>;
46
+ /**
47
+ * The tool is a standalone binary installed on `PATH`, not a project
48
+ * dependency: run it directly. Going through the package manager would be
49
+ * wrong for it — `npx --` / `bun x` fetch an npm package of the same name
50
+ * when none is installed locally, which for a non-npm binary is somebody
51
+ * else's code.
52
+ */
53
+ onPath?: boolean;
54
+ /** The host CLI binary, e.g. `"wrangler"`. */
55
+ tool: string;
56
+ }
57
+ /** Neutral options for a deploy. */
58
+ interface DeployRequest {
59
+ /** Host config file to deploy, when the flow uses a projected one (see {@link DeployDriver.projectConfig}). */
60
+ configPath?: string;
61
+ /** Validate and bundle without publishing — nothing ships. */
62
+ dryRun?: boolean;
63
+ /** Deploy this entry file instead of the host config's default (framework composition). */
64
+ entry?: string;
65
+ /** Named deployment environment, when the host supports them. */
66
+ environment?: string;
67
+ /** Write the built bundle (and any build metadata) to this directory. */
68
+ outDir?: string;
69
+ /** Upload a preview/versioned artifact instead of taking production traffic. */
70
+ preview?: boolean;
71
+ /** Deploy to a short-lived, unauthenticated account where the host offers one. */
72
+ temporary?: boolean;
73
+ }
74
+ /** Neutral options for a local dev server. */
75
+ interface DevRequest {
76
+ /** Host config file to run against, when the flow uses a generated one. */
77
+ configPath?: string;
78
+ /** Named environment. */
79
+ environment?: string;
80
+ /** Extra host-specific flags the caller has already resolved. */
81
+ extraArgs?: ReadonlyArray<string>;
82
+ }
83
+ /** Neutral options for tailing live logs. */
84
+ interface TailRequest {
85
+ /** Named environment. */
86
+ environment?: string;
87
+ /** Output format the host tail supports (`"json"`, `"pretty"`, …). */
88
+ format?: string;
89
+ /** Free-text filter. */
90
+ search?: string;
91
+ /** Status filter (`"error"`, `"ok"`, …). */
92
+ status?: string;
93
+ /** Tail a short-lived account's deployment. */
94
+ temporary?: boolean;
95
+ /** Tail a specific deployed worker/service by name, when the host addresses them individually. */
96
+ worker?: string;
97
+ }
98
+ /** Neutral options for reading or writing deployment secrets. */
99
+ interface SecretRequest {
100
+ /** Named environment. */
101
+ environment?: string;
102
+ /** The secret's name — required for `put`, unused for `list`. */
103
+ key?: string;
104
+ /** Operate against a short-lived account. */
105
+ temporary?: boolean;
106
+ }
107
+ /**
108
+ * The host's command-line surface. Optional as a whole: a host with no vendor
109
+ * CLI (the Node target; a hypothetical API-driven one) declares none, and
110
+ * `isRunnableTarget` refuses it for the commands that would have to shell out.
111
+ *
112
+ * `deploy` and `dev` are what make a target runnable. The secret and tail
113
+ * commands are optional on their own, because a runnable host can simply not
114
+ * have them — celld keeps configuration in plain `vars` and has no log tail —
115
+ * and the commands that need one say so rather than guessing a substitute.
116
+ */
117
+ interface DriverToolchain {
118
+ /** The command that deploys the app. */
119
+ deploy: (request: DeployRequest) => ToolchainCommand;
120
+ /** The command that runs a local dev server. */
121
+ dev: (request: DevRequest) => ToolchainCommand;
122
+ /**
123
+ * Where `lunora dev` runs the worker. `"workerd"`: `wrangler dev`, or the
124
+ * Vite plugin's `@cloudflare/vite-plugin`, whichever flavor the project
125
+ * picks. `"own"`: the host's dev server ({@link DriverToolchain.dev}) on
126
+ * the projected config, always the standalone flavor — neither Vite nor a
127
+ * framework sidecar can serve the worker on that runtime.
128
+ */
129
+ readonly devServer: "own" | "workerd";
130
+ /**
131
+ * Whether `lunora deploy` builds and pushes container images itself
132
+ * (railpack, into the host's registry) before `deploy`. `false` when the
133
+ * host CLI builds each image from its Dockerfile during the deploy.
134
+ */
135
+ readonly prebuildsContainerImages: boolean;
136
+ /** The command that writes many secrets in one call, as a JSON object of name to value on stdin. Optional: hosts without it get one `secretPut` per key. */
137
+ secretBulk?: (request: SecretRequest) => ToolchainCommand;
138
+ /** The command that lists remote secret names, when the host has a secret store. */
139
+ secretList?: (request: SecretRequest) => ToolchainCommand;
140
+ /** The command that writes one secret, when the host has a secret store. Its value is passed on stdin, never argv. */
141
+ secretPut?: (request: SecretRequest) => ToolchainCommand;
142
+ /** The command that tails live logs, when the host has one. */
143
+ tail?: (request: TailRequest) => ToolchainCommand;
144
+ }
145
+ /** What a {@link DeployDriver.projectConfig} projection is for — a dev server may need a different source than a deploy. */
146
+ type ProjectionPurpose = "deploy" | "dev";
147
+ /**
148
+ * The result of {@link DeployDriver.projectConfig}: a plan, not yet on disk.
149
+ * The caller validates the request it is for (the toolchain's argv builder
150
+ * refuses unsupported options), then calls `write` — so a refused command
151
+ * changes nothing.
152
+ */
153
+ interface ProjectedConfig {
154
+ /** Where the projection goes, to pass as the request's `configPath`. */
155
+ configPath: string;
156
+ /** Every key removed, as a dotted path (`observability`, `containers[0].rollout_step_percentage`). */
157
+ dropped: ReadonlyArray<string>;
158
+ /** Write the projection (and any build-artifact cleanup it planned). */
159
+ write: () => void;
160
+ }
161
+ /** A deploy target's implementation: an identity the registry resolves, and the host CLI surface (if any) behind it. */
162
+ interface DeployDriver {
163
+ /** The target id this driver serves (`"cloudflare"`, …) — matches codegen's `target`. */
164
+ readonly id: string;
165
+ /** Human-readable target name, for logs. */
166
+ readonly name: string;
167
+ /**
168
+ * Rewrite the project's wrangler config into the form this host's CLI
169
+ * accepts, and return the file to hand `deploy`/`dev` as `configPath`.
170
+ * Absent when the host reads the project's config as-is (Cloudflare).
171
+ *
172
+ * Needed because Lunora's reconcilers and templates write Cloudflare-only
173
+ * keys (`observability`, `limits`, …) that a Workers-compatible host with a
174
+ * strict config reader refuses outright. `dropped` names what was removed,
175
+ * so the caller can say so instead of silently deploying less than the
176
+ * config describes.
177
+ */
178
+ readonly projectConfig?: (projectRoot: string, purpose: ProjectionPurpose) => ProjectedConfig;
179
+ /**
180
+ * The host's command-line surface, or `undefined` for a host that has none.
181
+ * Pure: these build argv, they never spawn.
182
+ */
183
+ readonly toolchain?: DriverToolchain;
184
+ }
185
+ /**
186
+ * An invocation-scoped memo for project discovery. A CLI command creates one,
187
+ * threads it through every `discover*` / `inferLunoraBindings` call it makes,
188
+ * and clears it after anything rewrites the sources discovery reads (codegen).
189
+ * Deliberately not module-level: tests and long-lived processes never see a
190
+ * stale result.
191
+ */
192
+ interface DiscoveryCache {
193
+ /** Drop every memoised result. */
194
+ clear: () => void;
195
+ /** Return the result memoised under `key`, computing it on first use. */
196
+ memo: <T>(key: string, compute: () => T) => T;
197
+ }
198
+ declare const createDiscoveryCache: () => DiscoveryCache;
199
+ /** One filterable Vectorize metadata property a schema declares. */
200
+ interface VectorMetadataDeclaration {
201
+ /** The vector index the property belongs to. */
202
+ index: string;
203
+ /**
204
+ * The validator kind behind the column, with `v.optional(...)` and a
205
+ * nullable union unwrapped (metadata columns are usually optional), or
206
+ * `undefined` when the column isn't in the owning table's shape. Callers map it to the Vectorize
207
+ * metadata type; a kind that can't be filtered on is reported, not indexed.
208
+ */
209
+ kind: string | undefined;
210
+ /** Column mirrored into vector metadata. */
211
+ property: string;
212
+ }
213
+ interface SchemaInfo {
214
+ /**
215
+ * Whether the schema declares a **D1-backed** `.global()` table — the only
216
+ * flavour that needs the `DB` binding and the app's `.global({ d1 })` chain.
217
+ * A `.global({ backend: "hyperdrive" })` table needs neither, and counting it
218
+ * here demanded a D1 database of a project that has none.
219
+ */
220
+ hasD1GlobalTable: boolean;
221
+ /** Whether the schema declares a `.global({ backend: "hyperdrive" })` table — needs the app's `.hyperdriveGlobal(...)` chain instead. Required, not optional: the only producer always knows the answer, and `?` made every consumer read a two-valued fact as three-valued. */
222
+ hasHyperdriveGlobalTable: boolean;
223
+ /**
224
+ * Data-residency jurisdiction declared via `defineSchema(...).jurisdiction("…")`.
225
+ * It pins the app's Durable Objects only; KV namespaces and R2 buckets carry
226
+ * their own jurisdiction, set when they are created.
227
+ */
228
+ jurisdiction?: SchemaIR["jurisdiction"];
229
+ /** Names of vector indexes declared via `.vectorize()` / `defineVectorIndex()`. */
230
+ vectorIndexNames?: ReadonlyArray<string>;
231
+ /**
232
+ * Metadata properties declared filterable on a vector index. Cloudflare
233
+ * needs an explicit metadata index per property before a `filter` can match
234
+ * anything, so deploy provisions these and doctor reports them.
235
+ */
236
+ vectorMetadata?: ReadonlyArray<VectorMetadataDeclaration>;
237
+ }
238
+ interface DiscoverSchemaInfoResult {
239
+ /** Parse error message, when the schema exists but could not be analyzed. */
240
+ error?: string;
241
+ /** Schema facts, or `undefined` when no `schema.ts` exists or parsing failed. */
242
+ info: SchemaInfo | undefined;
243
+ }
244
+ /** Discover the schema facts, memoised on `cache` when one is given. */
245
+ declare const discoverSchemaInfo: (projectRoot: string, schemaDirectory: string, cache?: DiscoveryCache) => DiscoverSchemaInfoResult;
246
+ interface DurableObjectSpec {
247
+ binding: string;
248
+ className: string;
249
+ }
250
+ /**
251
+ * Canonical Durable Object class → binding name. wrangler requires the worker
252
+ * to export a class of this exact name, so detection keys on the class name.
253
+ */
254
+ declare const DURABLE_OBJECT_BINDINGS: {
255
+ readonly LunoraDO: "SHARD";
256
+ readonly SchedulerDO: "SCHEDULER";
257
+ readonly SessionDO: "SESSION";
258
+ readonly ShardDO: "SHARD";
259
+ readonly ShardRegistryDO: "SHARD_REGISTRY";
260
+ };
261
+ type DurableObjectClass = keyof typeof DURABLE_OBJECT_BINDINGS;
262
+ /**
263
+ * The `_generated/` modules that hold a generated Durable Object / Workflow
264
+ * class — one per class kind a project can declare. wrangler validates every
265
+ * `class_name` against the worker's exports, so this is the set a worker entry
266
+ * re-exports (and the set the composed class-A entry star-re-exports for the
267
+ * kinds the project has).
268
+ *
269
+ * Owned here because four places need it and they must not drift:
270
+ * `@lunora/vite` emits one star re-export per entry, the wrangler validator
271
+ * DECIDES the composed entry's exports from it, `reconcile-bindings` types its
272
+ * export-gap `module` field on it, and this module's own `detectClassExports`
273
+ * probes the same names.
274
+ *
275
+ * `scheduler` carries no `define*` declarations of its own — codegen writes it
276
+ * off `hasScheduler` purely so the composed class-A entry has a `SchedulerDO`
277
+ * to forward. Its presence is therefore the ONLY signal the plugin and the
278
+ * validator need, and it is the same signal that decides whether the builder
279
+ * has a `.scheduler()` method at all. `@lunora/vite` depends on `@lunora/config`, so config
280
+ * owning it is the direction the dependency graph allows.
281
+ */
282
+ declare const GENERATED_CLASS_MODULES: readonly ["agents", "containers", "scheduler", "shardRegistry", "workflows"];
283
+ /** One {@link GENERATED_CLASS_MODULES} entry. */
284
+ type GeneratedClassModule = (typeof GENERATED_CLASS_MODULES)[number];
285
+ /**
286
+ * The framework Durable Object each class module forwards, for the modules that
287
+ * carry one: codegen writes them off the same signal that gives the builder the
288
+ * matching method, so the module's existence means the composed entry exports
289
+ * the class.
290
+ */
291
+ declare const GENERATED_MODULE_DURABLE_OBJECTS: Partial<Record<GeneratedClassModule, DurableObjectClass>>;
292
+ /** The `_generated/` module codegen writes when `lunora.config` opts in to the merge. */
293
+ declare const MERGED_DURABLE_OBJECTS_MODULE: "durableObjects";
294
+ /**
295
+ * Whether the project merges its Durable Objects: codegen wrote the merge
296
+ * module. The one test the composed entry, binding inference and the export
297
+ * validator all ask — the same "module existence is the signal" rule the
298
+ * scheduler and registry modules follow.
299
+ */
300
+ declare const isMergedProject: (generatedDirectory: string) => boolean;
301
+ /** Whether `module` holds a class the merged class hosts — imported into it, never re-exported. */
302
+ declare const isMergedRoleModule: (module: string) => boolean;
303
+ /**
304
+ * The class-B composed entry. `lunora deploy` passes this file to wrangler as
305
+ * the positional script whenever it exists, overriding `wrangler.main` — so it
306
+ * is what actually gets bundled and what wrangler checks its DO/Workflow
307
+ * bindings against. `main` in a class-B project names the framework adapter's
308
+ * build output (`.svelte-kit/cloudflare/_worker.js`, `dist/_worker.js`), which
309
+ * exists after `vite build` and exports only the SSR fetch handler. Lexing that
310
+ * instead read every declared class as unexported: nothing provisioned, plus a
311
+ * "add `export * from …`" warning the user cannot silence.
312
+ *
313
+ * Exported, not documented-as-duplicated: the CLI's `resolveComposedWorkerEntry`
314
+ * imports this constant, so the deploy's positional entry and the file this
315
+ * module lexes for exported classes cannot drift apart.
316
+ */
317
+ declare const COMPOSED_WORKER_ENTRY = "src/worker.ts";
318
+ /**
319
+ * A `defineContainer` declaration plus whether its generated DO class is
320
+ * exported by the worker entry. Only exported containers are safe to
321
+ * provision — wrangler rejects a `containers[].class_name` (and its Durable
322
+ * Object binding) that the worker doesn't export.
323
+ */
324
+ type InferredContainer = ContainerIR & {
325
+ exported: boolean;
326
+ };
327
+ /**
328
+ * A `defineWorkflow` declaration plus whether its generated
329
+ * `WorkflowEntrypoint` class is exported by the worker entry. Only exported
330
+ * workflows are safe to provision — wrangler rejects an `exports.<Class>`
331
+ * workflow the worker doesn't export. Workflows are NOT Durable Objects, so this never
332
+ * implies a `durable_objects` binding or migration.
333
+ */
334
+ interface InferredWorkflow extends WorkflowIR {
335
+ exported: boolean;
336
+ }
337
+ /**
338
+ * A `defineAgent` declaration plus whether its generated agent
339
+ * `WorkflowEntrypoint` class (e.g. `SupportAgentWorkflow`) is exported by the
340
+ * worker entry. An agent compiles onto a Cloudflare Workflow, so — exactly like
341
+ * {@link InferredWorkflow} — only exported agents are safe to provision
342
+ * (wrangler rejects an `exports.<Class>` workflow the worker doesn't export), and
343
+ * an agent is NOT a Durable Object (no `durable_objects` binding or migration).
344
+ */
345
+ interface InferredAgent extends AgentIR {
346
+ exported: boolean;
347
+ }
348
+ /**
349
+ * A queue declared in `lunora/queues.ts`. Unlike workflows, a queue needs no
350
+ * worker-entry class export (its `queue()` handler rides `createWorker`), so
351
+ * there is no `exported` flag — every declared queue is reconcilable into the
352
+ * wrangler `queues.producers[]` / `queues.consumers[]`.
353
+ */
354
+ type InferredQueue = QueueIR;
355
+ interface InferredBindings {
356
+ /** Agents declared in `lunora/agents.ts` (exported or not — see {@link InferredAgent.exported}); reconciled into wrangler `exports`. */
357
+ agents: InferredAgent[];
358
+ /** Containers declared in `lunora/containers.ts` (exported or not — see {@link InferredContainer.exported}). */
359
+ containers: InferredContainer[];
360
+ /** Durable Objects the worker entry exports → safe to bind. */
361
+ durableObjects: DurableObjectSpec[];
362
+ /**
363
+ * The wrangler `flagship[].binding` name implied by `lunora/flags.ts` when it
364
+ * uses the Flagship provider in binding mode — `undefined` for HTTP-mode
365
+ * Flagship, a custom OpenFeature provider, or no flags. The binding needs an
366
+ * un-mintable `app_id`, so it is reconciled as a hint, not auto-written.
367
+ */
368
+ flagshipBinding?: string;
369
+ /**
370
+ * The schema's `.jurisdiction("…")`, when it declares one. Read by the binding
371
+ * hints whose resource takes its residency at creation (Artifacts), so the
372
+ * hint can name the jurisdiction to create it in.
373
+ */
374
+ jurisdiction?: SchemaInfo["jurisdiction"];
375
+ /** Schema declares a `.global()` table → needs the `DB` D1 binding. */
376
+ needsD1: boolean;
377
+ /** Queues declared in `lunora/queues.ts` → reconciled into `queues.producers[]` / `queues.consumers[]`. */
378
+ queues: InferredQueue[];
379
+ /**
380
+ * Sibling Workers declared in `lunora.config` `services` → reconciled into
381
+ * `services[]` (plan 457). `undefined` when the declaration is unreadable, so
382
+ * reconcile leaves every entry alone rather than removing the owned ones.
383
+ */
384
+ services: ServiceBindingIR[] | undefined;
385
+ /** Human-readable provenance for each inferred binding / hint, for logging. */
386
+ signals: string[];
387
+ /** `@lunora/ai` is imported, `ctx.ai` read, or `env.AI` used → needs the `ai` Workers AI binding. */
388
+ usesAi: boolean;
389
+ /** `@lunora/bindings/ai-search` is value-imported or `ctx.aiSearch` read → self-describing `ai_search_namespaces` binding (`AI_SEARCH` on namespace `default`; auto-writeable). */
390
+ usesAiSearch: boolean;
391
+ /** `@lunora/bindings/analytics` is imported or `ctx.analytics` read → self-describing `analytics_engine_datasets` binding (auto-writeable). */
392
+ usesAnalytics: boolean;
393
+ /** `@lunora/bindings/analytics-sql` is value-imported or `ctx.analyticsSql` read → self-describing `analytics` binding (`{ binding: ANALYTICS_SQL }`; auto-writeable, wrangler >= 4.145.0). */
394
+ usesAnalyticsSql: boolean;
395
+ /**
396
+ * `ctx.artifacts` is read or `@lunora/bindings/artifacts` value-imported.
397
+ * Hint-only: the first repo `create()` against a missing namespace creates it
398
+ * UNRESTRICTED, and a namespace's jurisdiction can never change after that,
399
+ * so Lunora never writes the binding for you.
400
+ */
401
+ usesArtifacts: boolean;
402
+ /** `@lunora/auth` is imported (sessions may be D1- or `SessionDO`-backed). */
403
+ usesAuth: boolean;
404
+ /** `@lunora/browser` is imported or `ctx.browser` read → self-describing `browser` binding (auto-writeable). */
405
+ usesBrowser: boolean;
406
+ /** `@lunora/auth/cimd/workers` is imported → needs the `global_fetch_strictly_public` compatibility flag (no binding; `lunora doctor` checks it). */
407
+ usesCimdWorkers: boolean;
408
+ /** `lunora/flags.ts` declares a feature-flag provider (any OpenFeature provider — Flagship or custom). */
409
+ usesFlags: boolean;
410
+ /** `@lunora/hyperdrive` is imported or `ctx.sql` read (binding needs an un-mintable remote `id`; hint-only). */
411
+ usesHyperdrive: boolean;
412
+ /** `@lunora/bindings/images` is imported or `ctx.images` read → self-describing `images` binding (auto-writeable). */
413
+ usesImages: boolean;
414
+ /** `@lunora/bindings/kv` is imported or `ctx.kv` read (namespace binding name + id are user-defined; hint-only). */
415
+ usesKv: boolean;
416
+ /** `@lunora/mail` is imported (Resend API key must be set in `.dev.vars`; no binding). No `ctx.mail` helper exists, so only the import counts. */
417
+ usesMail: boolean;
418
+ /** `@lunora/notify` is imported or `ctx.notify` read (no binding; channel secrets ride `usesNotifyFcm` / `usesNotifyWebPush`). */
419
+ usesNotify: boolean;
420
+ /** `lunora/notify.ts` configures the `fcm` channel → the `FCM_*` secrets in `.dev.vars`. */
421
+ usesNotifyFcm: boolean;
422
+ /** `lunora/notify.ts` configures the `webPush` channel → the `VAPID_*` secrets in `.dev.vars`. */
423
+ usesNotifyWebPush: boolean;
424
+ /** `@lunora/payment/autumn` is imported → the Autumn secrets in `.dev.vars` (no binding). */
425
+ usesPaymentAutumn: boolean;
426
+ /** `@lunora/payment/creem` is imported → the Creem secrets in `.dev.vars` (no binding). */
427
+ usesPaymentCreem: boolean;
428
+ /** `@lunora/payment/dodopayments` is imported → the Dodo Payments secrets in `.dev.vars` (no binding). */
429
+ usesPaymentDodopayments: boolean;
430
+ /** `@lunora/payment/polar` is imported → the Polar secrets in `.dev.vars` (no binding). */
431
+ usesPaymentPolar: boolean;
432
+ /** `@lunora/payment` is imported or `ctx.payments` read (provider secrets must be set in `.dev.vars`; no binding). */
433
+ usesPayments: boolean;
434
+ /** `@lunora/payment/stripe` is imported → the Stripe secrets in `.dev.vars` (no binding). */
435
+ usesPaymentStripe: boolean;
436
+ /** `@lunora/bindings/pipelines` is value-imported or `ctx.pipelines` read (binding needs an un-mintable remote pipeline name; hint-only). */
437
+ usesPipelines: boolean;
438
+ /** `@lunora/bindings/r2sql` is value-imported or `ctx.r2sql` read (needs the `R2_SQL_*` secrets in `.dev.vars`; no binding). */
439
+ usesR2sql: boolean;
440
+ /** `@lunora/scheduler` is imported or `ctx.scheduler` read. */
441
+ usesScheduler: boolean;
442
+ /** `@lunora/storage` is imported or `ctx.storage` read under `lunora/` (R2 bucket binding name is user-defined). */
443
+ usesStorage: boolean;
444
+ /** `jsCodeTool` is imported from `@lunora/agent` in `lunora/` → self-describing `worker_loaders` binding (`LOADER`). */
445
+ usesWorkerLoader: boolean;
446
+ /** `@lunora/x402/pay` is imported or `ctx.x402` read — the agent-wallet pay rail signs from a Secrets Store binding paired with a spend policy (ActionCtx-only; hint-only). */
447
+ usesX402: boolean;
448
+ /** `@lunora/x402/charge` is imported — the charge rail settles USDC to a recipient address (a public `[vars]` entry, user-named; hint-only). */
449
+ usesX402Charge: boolean;
450
+ /** Workflows declared in `lunora/workflows.ts` (exported or not — see {@link InferredWorkflow.exported}). */
451
+ workflows: InferredWorkflow[];
452
+ }
453
+ interface InferOptions {
454
+ /** Memoises the source scans, so one CLI invocation parses the project once. */
455
+ cache?: DiscoveryCache;
456
+ projectRoot: string;
457
+ /** Directories (relative to root) to scan. Defaults to `lunora` + `src`. */
458
+ scanDirs?: ReadonlyArray<string>;
459
+ /** Lunora source directory holding `schema.ts`. Defaults to `lunora`. */
460
+ schemaDir?: string;
461
+ }
462
+ /**
463
+ * Scan a Lunora project and report which Cloudflare bindings its code implies.
464
+ * Read-only: performs no writes. Binding provisioning is driven by the worker
465
+ * entry's Durable Object exports plus the schema's D1 need; capability imports
466
+ * surface as hints.
467
+ */
468
+ declare const inferLunoraBindings: (options: InferOptions) => Promise<InferredBindings>;
469
+ /**
470
+ * The secret sources a project uses — the {@link PACKAGE_SECRETS_REGISTRY} keys
471
+ * whose secrets it needs, derived from its already-resolved {@link InferredBindings}.
472
+ *
473
+ * This is the canonical bridge between binding inference and the
474
+ * `.dev.vars.example` scaffolding in `scaffold-dev-variables.ts`. The result is
475
+ * {@link FLAG_PACKAGES}' sources whose flag is `true` in `bindings` — in
476
+ * flag-name order — followed by the configured `@lunora/notify` channels
477
+ * ({@link NOTIFY_CHANNEL_SECRETS}), keeping only sources that carry secrets.
478
+ */
479
+ declare const secretSourcesFromBindings: (bindings: InferredBindings) => string[];
480
+ export { COMPOSED_WORKER_ENTRY as C, DeployDriver as D, GeneratedClassModule as G, InferredBindings as I, MERGED_DURABLE_OBJECTS_MODULE as M, ProjectionPurpose as P, SchemaInfo as S, ToolchainCommand as T, DiscoveryCache as a, DURABLE_OBJECT_BINDINGS as b, DeployRequest as c, DevRequest as d, DiscoverSchemaInfoResult as e, DriverToolchain as f, GENERATED_CLASS_MODULES as g, GENERATED_MODULE_DURABLE_OBJECTS as h, InferOptions as i, InferredAgent as j, InferredContainer as k, InferredWorkflow as l, ProjectedConfig as m, SecretRequest as n, TailRequest as o, createDiscoveryCache as p, discoverSchemaInfo as q, inferLunoraBindings as r, isMergedProject as s, isMergedRoleModule as t, secretSourcesFromBindings as u };
@@ -0,0 +1 @@
1
+ import"./discoverAgentInfo-pqFMJBtJ.mjs";import{i as c,s as d}from"./infer-bindings-C1NFOdMi.mjs";import"./discoverContainerInfo-DzXr7Vm3.mjs";import"./DEV_VARS_EXAMPLE_FILE-CqLorAxT.mjs";import"./discover-info-DC2MrAIM.mjs";import"./package-secrets-registry-BeheNwsP.mjs";import"./discoverSchemaInfo-BBRlXZop.mjs";import"./COMPOSED_WORKER_ENTRY-Ciiba5g_.mjs";import"./discoverWorkflowInfo-zW7Tt0Tn.mjs";export{c as inferLunoraBindings,d as secretSourcesFromBindings};
@@ -0,0 +1 @@
1
+ import{readProjectConfigLiterals as o,readProjectTarget as n}from"@lunora/codegen";import{DEFAULT_DEPLOY_TARGET as c,resolveDeployDriver as a}from"./DEFAULT_DEPLOY_TARGET-rR7buNQw.mjs";const s=e=>{if(typeof e=="boolean")return e;if(e!==null&&typeof e=="object")return!0},g=e=>s(o(e).remote),i=e=>n(e),T=(e,r)=>r??i(e)??c,j=(e,r)=>{const t=T(e,r);return a(t),t};export{s as interpretRemote,g as readProjectRemotePreference,i as readProjectTarget,T as resolveProjectTarget,j as resolveTargetOrThrow};
@@ -0,0 +1,6 @@
1
+ import{readFileSync as b,writeFileSync as v}from"node:fs";import{applyEdits as $,modify as S,parseTree as N,findNodeAtLocation as g}from"jsonc-parser";import{join as h}from"node:path";const A=/^([\t ]+)"/mu,F=n=>{const o=A.exec(n)?.[1]??" ";return{eol:n.includes(`\r
2
+ `)?`\r
3
+ `:`
4
+ `,insertSpaces:!o.startsWith(" "),tabSize:o.length}},I=n=>{const o=h(n,"package.json");try{const t=b(o,"utf8"),{lunora:r}=JSON.parse(t),e=typeof r=="object"&&r!==null&&!Array.isArray(r);return{lunora:e?r:void 0,lunoraIsForeign:r!==void 0&&!e,path:o,text:t}}catch{return}},p=n=>JSON.stringify(n,(o,t)=>typeof t=="object"&&t!==null&&!Array.isArray(t)?Object.fromEntries(Object.entries(t).toSorted(([r],[e])=>r.localeCompare(e))):t),j=(n,o,t)=>{const r=F(n),e=r.insertSpaces===!1?" ":" ".repeat(r.tabSize??4),i=r.eol??`
5
+ `,c=e.repeat(o.length),f=JSON.stringify(t,void 0,e).split(`
6
+ `).join(i+c),l=N(n),a=l===void 0?void 0:g(l,[...o]);if(a!==void 0)return n.slice(0,a.offset)+f+n.slice(a.offset+a.length);let s=l;l!==void 0&&o.length>1&&(s=g(l,o.slice(0,-1)));const y=JSON.stringify(o.at(-1));if(s===void 0&&o.length>1)return j(n,o.slice(0,-1),{[o.at(-1)]:t});if(s?.type!=="object")return $(n,S(n,[...o],t,{formattingOptions:r}));const d=s.children?.at(-1);if(d===void 0){const O=`${i}${c}${y}: ${f}${i}${e.repeat(o.length-1)}`;return`${n.slice(0,s.offset+1)}${O}${n.slice(s.offset+s.length-1)}`}const u=d.offset+d.length;return`${n.slice(0,u)},${i}${c}${y}: ${f}${n.slice(u)}`},K=(n,o,t)=>{const r=Object.keys(n.lunora??{}).every(c=>c===o);if(n.lunoraIsForeign||p(n.lunora?.[o])===p(t))return;const e=t===void 0&&r?["lunora"]:["lunora",o],i=t===void 0?$(n.text,S(n.text,e,void 0,{})):j(n.text,e,t);i!==n.text&&v(n.path,i,"utf8")};export{K as a,p as c,F as f,I as r};
@@ -0,0 +1 @@
1
+ import{isAbsolute as f,dirname as p,resolve as m}from"node:path";import{applyModify as l}from"./applyModify-DKP2l6S9.mjs";import{hasCloudflareCredentials as h}from"./hasCloudflareCredentials-byvHpEiD.mjs";import{withheldWorkersAi as u,writeDevConfig as v}from"./describeWithheldWorkersAi-IIxe3TuI.mjs";import{readWranglerJsonc as w}from"./WRANGLER_FILES-UNW-xY5u.mjs";const g=(t,r)=>{const{parsed:e,text:n}=w(t),o=e?.build,c=u(e?.ai,r.hasCredentials??(()=>h({projectRoot:r.projectRoot}))),d=typeof o?.command=="string"&&o.command!==""&&!(typeof o.cwd=="string"&&f(o.cwd));if(!d&&c===void 0)return{configPath:t};const s=p(t);let i=n;c!==void 0&&(i=l(i,["ai"],void 0)),d&&(i=l(i,["build","cwd"],m(s,typeof o.cwd=="string"?o.cwd:".")));const a=v(s,"service",i);return{cleanup:a.cleanup,configPath:a.configPath,withheld:c}},j=(t,r)=>{const e=t.map(o=>g(o,r)),n=e.flatMap(o=>o.cleanup===void 0?[]:[o.cleanup]);return{cleanup:()=>{for(const o of n)o()},configPaths:e.map(o=>o.configPath),withheld:e.flatMap(o=>o.withheld===void 0?[]:[o.withheld])}};export{j as materializeServiceDevConfigs};
@@ -0,0 +1 @@
1
+ const c=["ai_search","ai_search_namespaces","analytics","artifacts","containers","d1_databases","durable_objects","k2","kv_namespaces","queues","r2_buckets","secrets","secrets_store_secrets","services","tail_consumers","vars","vectorize","workflows"],i=["assets","compatibility_date","compatibility_flags","exports","logpush","main","migrations","observability","placement"],m=(s,n)=>{if(n===void 0)return{merged:s,unverifiedKeys:[]};const t=s.env?.[n];if(t===void 0){const e=Object.keys(s.env??{}).toSorted((v,f)=>v.localeCompare(f)),l=e.length>0?` (declared: ${e.join(", ")}).`:" (no environments are declared).";return{error:`--env "${n}" names no environment declared in wrangler.jsonc's "env" block${l}`,merged:s,unverifiedKeys:[]}}const o={...s},r=Object.keys(t).filter(e=>e!=="env");for(const e of r)i.includes(e)&&(o[e]=t[e]);for(const e of c)o[e]=t[e];const a=new Set([...c,...i]),d=r.filter(e=>!a.has(e)).map(String);return{merged:o,unverifiedKeys:d}};export{c as NON_INHERITABLE_KEYS,m as mergeWranglerEnvironment};
@@ -0,0 +1 @@
1
+ const t=e=>e.endsWith("S")?e.slice(0,-1):e,r=e=>e.replaceAll(/([a-z\d])([A-Z])/gu,"$1_$2").toUpperCase().split(/[_-]+/u).filter(s=>s.length>0),n=new Set(["CREDENTIAL","DSN","PASSPHRASE","PASSWD","PASSWORD","SECRET","TOKEN"]),c=["ACCESS_KEY","API_KEY","ENCRYPTION_KEY","PRIVATE_KEY","SIGNING_KEY"],p=new RegExp(`(?:${[...n,...c.map(e=>e.replaceAll("_",""))].join("|")})S?$`,"iu"),i=e=>r(e).some(s=>s==="PUBLIC"||s==="PUBLISHABLE"),d=e=>{if(i(e))return!1;const s=r(e);if(s.some(o=>n.has(t(o))))return!0;const a=t(s.join("_"));return c.some(o=>a===o||a.endsWith(`_${o}`))||p.test(e)},h=[{description:"Bearer token the local Lunora Studio uses to call the worker's admin endpoints (data browser, schema edits) in dev. Generate with: openssl rand -hex 32",docsUrl:"https://lunora.sh/docs/packages/studio",key:"LUNORA_ADMIN_TOKEN",placeholderValue:"replace-with-openssl-rand-hex-32"}],u=["BETTER_AUTH_SECRET","STORAGE_SIGNING_SECRET"],l={"@lunora/auth":[{description:"32-byte random secret used to sign sessions and tokens. Generate with: openssl rand -hex 32",docsUrl:"https://lunora.sh/docs/packages/auth#secrets",key:"AUTH_SECRET",placeholderValue:"replace-with-openssl-rand-hex-32"},{description:"Public base URL of your worker (used by better-auth for redirects and cookie domain). For local dev this is typically http://localhost:8787",docsUrl:"https://lunora.sh/docs/packages/auth#secrets",key:"AUTH_URL",placeholderValue:"http://localhost:8787"}],"@lunora/bindings/r2sql":[{description:"Cloudflare API token with R2 SQL read access, for `ctx.r2sql`. Create at https://dash.cloudflare.com/profile/api-tokens with the R2 SQL permission.",docsUrl:"https://lunora.sh/docs/packages/bindings#r2-sql",key:"R2_SQL_TOKEN",placeholderValue:"<your-r2-sql-api-token>"},{description:"Cloudflare account id the R2 SQL queries run against. Falls back to CLOUDFLARE_ACCOUNT_ID when unset.",docsUrl:"https://lunora.sh/docs/packages/bindings#r2-sql",key:"R2_SQL_ACCOUNT_ID",placeholderValue:"<your-cloudflare-account-id>"},{description:"Name of the R2 bucket holding the Iceberg tables `ctx.r2sql` queries.",docsUrl:"https://lunora.sh/docs/packages/bindings#r2-sql",key:"R2_SQL_BUCKET",placeholderValue:"<your-r2-sql-bucket>"}],"@lunora/mail":[{description:"Resend API key for sending transactional email via @lunora/mail. Obtain at https://resend.com/api-keys",docsUrl:"https://lunora.sh/docs/packages/mail#secrets",key:"RESEND_API_KEY",placeholderValue:"<your-resend-api-key>"}],"@lunora/notify:fcm":[{description:"Firebase project id for FCM (HTTP v1) push. Found in the Firebase console project settings.",docsUrl:"https://lunora.sh/docs/packages/notify#fcm",key:"FCM_PROJECT_ID",placeholderValue:"<your-firebase-project-id>"},{description:"OAuth2 access token for FCM (HTTP v1). Convenient for dev but expires — in production supply a getAccessToken() in defineNotify instead. Obtain via the Google Cloud SDK / a service account.",docsUrl:"https://lunora.sh/docs/packages/notify#fcm",key:"FCM_ACCESS_TOKEN",placeholderValue:"<your-fcm-access-token>"}],"@lunora/notify:webPush":[{description:"Public VAPID key (base64url) for Web Push. Generate a keypair once with: npx web-push generate-vapid-keys — the public key is also shipped to the browser to subscribe.",docsUrl:"https://lunora.sh/docs/packages/notify#web-push",key:"VAPID_PUBLIC_KEY",placeholderValue:"<your-vapid-public-key>"},{description:"Private VAPID key (base64url) for Web Push — the application-server signing key. Generate with: npx web-push generate-vapid-keys",docsUrl:"https://lunora.sh/docs/packages/notify#web-push",key:"VAPID_PRIVATE_KEY",placeholderValue:"<your-vapid-private-key>"},{description:"VAPID `sub` contact — a mailto: or https: URL identifying the application server (e.g. mailto:you@example.com).",docsUrl:"https://lunora.sh/docs/packages/notify#web-push",key:"VAPID_SUBJECT",placeholderValue:"mailto:you@example.com"}],"@lunora/payment/autumn":[{description:"Autumn secret key (am_sk_…) for the Autumn payment adapter. Obtain at https://app.useautumn.com/dev",docsUrl:"https://lunora.sh/docs/packages/payment#autumn",key:"AUTUMN_SECRET_KEY",placeholderValue:"<your-autumn-secret-key>"},{description:"Autumn webhook signing secret for verifying Standard Webhooks event payloads. Obtain from your Autumn dashboard webhook settings.",docsUrl:"https://lunora.sh/docs/packages/payment#autumn",key:"AUTUMN_WEBHOOK_SECRET",placeholderValue:"<your-autumn-webhook-secret>"}],"@lunora/payment/creem":[{description:"Creem API key for the Creem payment adapter. Obtain at https://www.creem.io/dashboard/developers",docsUrl:"https://lunora.sh/docs/packages/payment#creem",key:"CREEM_API_KEY",placeholderValue:"<your-creem-api-key>"},{description:"Creem webhook signing secret for verifying the creem-signature header. Obtain from your Creem dashboard webhook settings.",docsUrl:"https://lunora.sh/docs/packages/payment#creem",key:"CREEM_WEBHOOK_SECRET",placeholderValue:"<your-creem-webhook-secret>"}],"@lunora/payment/dodopayments":[{description:"Dodo Payments API key (bearer token) for the Dodo Payments adapter. Obtain at https://app.dodopayments.com/developer/api-keys",docsUrl:"https://lunora.sh/docs/packages/payment#dodo-payments",key:"DODO_PAYMENTS_API_KEY",placeholderValue:"<your-dodo-payments-api-key>"},{description:"Dodo Payments webhook signing secret (whsec_…) for verifying event payloads. Obtain at https://app.dodopayments.com/developer/webhooks",docsUrl:"https://lunora.sh/docs/packages/payment#dodo-payments",key:"DODO_PAYMENTS_WEBHOOK_KEY",placeholderValue:"<your-dodo-payments-webhook-secret>"}],"@lunora/payment/polar":[{description:"Polar access token for the Polar payment adapter. Obtain at https://polar.sh/settings/tokens",docsUrl:"https://lunora.sh/docs/packages/payment#polar",key:"POLAR_ACCESS_TOKEN",placeholderValue:"<your-polar-access-token>"},{description:"Polar webhook secret for verifying event payloads from Polar. Obtain at https://polar.sh/settings/webhooks",docsUrl:"https://lunora.sh/docs/packages/payment#polar",key:"POLAR_WEBHOOK_SECRET",placeholderValue:"<your-polar-webhook-secret>"}],"@lunora/payment/stripe":[{description:"Stripe secret key (sk_test_…). Required when using the Stripe adapter. Obtain at https://dashboard.stripe.com/apikeys",docsUrl:"https://lunora.sh/docs/packages/payment#stripe",key:"STRIPE_SECRET_KEY",placeholderValue:"<your-stripe-secret-key>"},{description:"Stripe webhook signing secret (whsec_…) for verifying event payloads. Obtain at https://dashboard.stripe.com/webhooks",docsUrl:"https://lunora.sh/docs/packages/payment#stripe",key:"STRIPE_WEBHOOK_SECRET",placeholderValue:"<your-stripe-webhook-secret>"}]},y=new Set([...u,...[...h,...Object.values(l).flat()].filter(e=>d(e.key)&&!e.placeholderValue.startsWith("<")).map(e=>e.key)]),k=e=>{const s=[];for(const a of e){const o=l[a];o!==void 0&&s.push(...o)}return s};export{h as C,y as M,l as P,d as a,i,k as s};
@@ -0,0 +1 @@
1
+ import{readFileSync as n}from"node:fs";import{join as s}from"node:path";import{parseDevVariableEntries as i}from"./DEV_VARS_EXAMPLE_FILE-CqLorAxT.mjs";const a=(o,r)=>{const e=i(o).find(t=>t.key===r);return e===void 0||e.value===""?void 0:e.value},d=o=>{let r;try{r=a(n(s(o,".dev.vars"),"utf8"),"LUNORA_ADMIN_TOKEN")}catch{r=void 0}const e=process.env.LUNORA_ADMIN_TOKEN;return typeof e=="string"&&e!==""&&e!==r&&console.warn("[lunora] LUNORA_ADMIN_TOKEN is exported in this shell but differs from .dev.vars — the local worker only verifies the .dev.vars token, so the studio uses that one."),r};export{a as parseDevVariable,d as resolveAdminToken};
@@ -0,0 +1 @@
1
+ import{Project as m,SyntaxKind as n}from"ts-morph";const f=/^v\s*\.\s*optional\s*\(/u,x=/\.shardBy\(\s*["']([^"']+)["']\s*\)/u,T=/\.global\(\s*(?:\{[^{}]*\}\s*)?\)/u,p=/["']/gu,u=e=>{const t=e.getDescendantsOfKind(n.CallExpression);return e.getKind()===n.CallExpression&&t.push(e.asKindOrThrow(n.CallExpression)),t},A=e=>f.test(e.trim()),h=e=>e?.getKind()!==n.ArrayLiteralExpression?[]:e.asKindOrThrow(n.ArrayLiteralExpression).getElements().filter(t=>t.getKind()===n.StringLiteral).map(t=>t.asKindOrThrow(n.StringLiteral).getLiteralText()),E=e=>{if(e?.getKind()!==n.ObjectLiteralExpression)return!1;const t=e.asKindOrThrow(n.ObjectLiteralExpression).getProperty("unique");return t?.getKind()===n.PropertyAssignment&&t.getInitializer()?.getText()==="true"},K=e=>{const t=e.getExpression();if(t.getKind()!==n.PropertyAccessExpression||t.asKindOrThrow(n.PropertyAccessExpression).getName()!=="index")return;const[r,a,s]=e.getArguments();if(r?.getKind()===n.StringLiteral)return{fields:h(a),name:r.asKindOrThrow(n.StringLiteral).getLiteralText(),unique:E(s)}},O=e=>{const t=e.getInitializer();if(t===void 0)return[];const r=[];for(const a of u(t)){const s=K(a);s!==void 0&&r.push(s)}return r},y=e=>{const t=[],r=e.getInitializer(),s=(r===void 0?void 0:u(r).find(l=>l.getExpression().getText()==="defineTable"))?.getArguments()[0];if(s?.getKind()!==n.ObjectLiteralExpression)return t;for(const l of s.getProperties()){if(l.getKind()!==n.PropertyAssignment)continue;const i=l,o=i.getName().replaceAll(p,""),c=i.getInitializer()?.getText()??"";t.push({name:o,optional:A(c),validator:c})}return t},P=e=>{const r=new m({compilerOptions:{allowJs:!0},useInMemoryFileSystem:!0}).createSourceFile("schema.ts",e,{overwrite:!0}),a=r.getDescendantsOfKind(n.CallExpression).find(i=>i.getExpression().getText()==="defineSchema");if(a===void 0)return{ok:!1,reason:r.getImportDeclarations().some(o=>o.getNamedImports().some(c=>c.getName()==="defineSchema"&&c.getAliasNode()!==void 0))?"aliased-define-schema":"no-define-schema"};const s=a.getArguments()[0];if(s?.getKind()!==n.ObjectLiteralExpression)return{ok:!1,reason:"non-object-argument"};const l=[];for(const i of s.getProperties()){if(i.getKind()!==n.PropertyAssignment)continue;const o=i,c=o.getName().replaceAll(p,""),g=o.getInitializer()?.getText()??"",d=x.exec(g);l.push({columns:y(o),global:T.test(g),indexes:O(o),name:c,...d?.[1]===void 0?{}:{shardBy:d[1]}})}return{ok:!0,tables:l}};export{u as collectCalls,P as parseSchema};
@@ -0,0 +1,86 @@
1
+ /**
2
+ * The server-module specifier to scaffold into a project's own source:
3
+ * `lunorash/server` when the project depends on the umbrella, `@lunora/server`
4
+ * when it installs the granular packages. Same detection codegen and the Vite
5
+ * compose plugin use, so a scaffolded file imports what the emitted code does.
6
+ */
7
+ declare const resolveServerModule: (projectRoot: string) => string;
8
+ /** Scaffold a new policy/role/permission stub file under `lunora/`. */
9
+ interface ScaffoldPolicyEdit {
10
+ readonly kind: "scaffoldPolicy";
11
+ /**
12
+ * Base name for the generated file and its exported policy-set identifier,
13
+ * e.g. `invoices` → `lunora/invoices.policies.ts` exporting `invoicesPolicies`.
14
+ */
15
+ readonly name: string;
16
+ /** Logical table the scaffolded policy guards (used in the stub body). */
17
+ readonly table: string;
18
+ }
19
+ /** Append `.use(rls(<policies>))` to an existing procedure's builder chain. */
20
+ interface WireRlsEdit {
21
+ /** Exported procedure name to wire, e.g. `listInvoices`. */
22
+ readonly exportName: string;
23
+ readonly kind: "wireRls";
24
+ /** Identifier of the policy set passed to `rls(...)`, e.g. `invoicesPolicies`. */
25
+ readonly policies: string;
26
+ }
27
+ /** Additive scaffolder edits — the only requests the scaffolder applies. */
28
+ type AdditivePolicyEdit = ScaffoldPolicyEdit | WireRlsEdit;
29
+ /**
30
+ * Destructive scaffolder requests — never applied. Rewriting an existing `when`
31
+ * body changes evaluation semantics silently, so it is refused (STOP condition
32
+ * in plan 025); carried as data so the editor can describe the request.
33
+ */
34
+ interface DestructivePolicyEdit {
35
+ readonly exportName?: string;
36
+ readonly kind: "rewritePolicyWhen";
37
+ readonly table?: string;
38
+ }
39
+ /** Any request the scaffolder can receive. */
40
+ type PolicyEdit = AdditivePolicyEdit | DestructivePolicyEdit;
41
+ /**
42
+ * Classify a scaffolder request. Additive requests ({@link AdditivePolicyEdit})
43
+ * apply directly; everything else (rewriting an existing predicate) changes
44
+ * evaluation semantics and is destructive.
45
+ */
46
+ declare const classifyPolicyEdit: (edit: PolicyEdit) => "additive" | "destructive";
47
+ /** Failure reasons a scaffolder request can report. */
48
+ type PolicyScaffoldFailureReason = "already-wired" | "destructive" | "invalid-identifier" | "unknown-procedure" | "unsupported-procedure-shape";
49
+ /** Tagged result of generating a stub file. */
50
+ type ScaffoldFileResult = {
51
+ fileName: string;
52
+ ok: true;
53
+ source: string;
54
+ } | {
55
+ ok: false;
56
+ reason: PolicyScaffoldFailureReason;
57
+ };
58
+ /** Tagged result of wiring a procedure. */
59
+ type WireResult = {
60
+ ok: false;
61
+ reason: PolicyScaffoldFailureReason;
62
+ } | {
63
+ ok: true;
64
+ text: string;
65
+ };
66
+ /**
67
+ * Generate the source of a new policy/role/permission stub file. The `when`
68
+ * predicate is a `() => false` skeleton with a TODO — the scaffolder never
69
+ * authors real logic, the developer fills it in. Pure (no I/O); the handler
70
+ * writes the returned source and refuses to overwrite an existing file.
71
+ *
72
+ * `serverModule` is the specifier the PROJECT can resolve the builders from
73
+ * (see {@link resolveServerModule}) — an umbrella-only install has no
74
+ * `@lunora/server` on disk, so hard-coding it would scaffold a file that
75
+ * cannot be bundled.
76
+ */
77
+ declare const scaffoldPolicyFile: (edit: ScaffoldPolicyEdit, serverModule: string) => ScaffoldFileResult;
78
+ /**
79
+ * Append `.use(rls(<policies>))` to a procedure's builder chain, preserving the
80
+ * terminal `.query(handler)` (and its handler body) byte-for-byte. Only the
81
+ * **builder** form can be wired; the bare-factory form (`query({ handler })`)
82
+ * has no chain and is reported `unsupported-procedure-shape` so the editor can
83
+ * tell the developer to convert it rather than silently rewriting their code.
84
+ */
85
+ declare const wireRlsIntoProcedure: (source: string, edit: WireRlsEdit, serverModule: string) => WireResult;
86
+ export { AdditivePolicyEdit as A, DestructivePolicyEdit as D, PolicyEdit as P, ScaffoldPolicyEdit as S, WireRlsEdit as W, PolicyScaffoldFailureReason as a, ScaffoldFileResult as b, WireResult as c, classifyPolicyEdit as d, resolveServerModule as r, scaffoldPolicyFile as s, wireRlsIntoProcedure as w };