@lunora/config 1.0.0-alpha.11 → 1.0.0-alpha.111

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 (89) hide show
  1. package/LICENSE.md +6 -0
  2. package/README.md +2 -2
  3. package/__assets__/package-og.svg +1 -1
  4. package/dist/cloudflare/index.d.mts +661 -0
  5. package/dist/cloudflare/index.d.ts +661 -0
  6. package/dist/cloudflare/index.mjs +1 -0
  7. package/dist/index.d.mts +689 -824
  8. package/dist/index.d.ts +689 -824
  9. package/dist/index.mjs +1 -22
  10. package/dist/packem_shared/ACCENT-CLeV5v0K.mjs +7 -0
  11. package/dist/packem_shared/AGENT_MODE_ENV-B54hVQ_w.mjs +1 -0
  12. package/dist/packem_shared/AGENT_RULES_DIR-hP9TiDNx.mjs +1 -0
  13. package/dist/packem_shared/ALLOW_FORWARDED_ENV-DGdbCDre.mjs +1 -0
  14. package/dist/packem_shared/CLOUDFLARE_DRIVER-DS7cF7Cl.mjs +1 -0
  15. package/dist/packem_shared/DEFAULT_DEPLOY_TARGET-CBoD0Zha.mjs +1 -0
  16. package/dist/packem_shared/DEV_DAEMON_ENV-D9Z83rlU.mjs +4 -0
  17. package/dist/packem_shared/DEV_VARS_EXAMPLE_FILE-BL0hrPx3.mjs +6 -0
  18. package/dist/packem_shared/LINKED_PROJECT_DIR-CMzUvj-1.mjs +2 -0
  19. package/dist/packem_shared/LUNORA_CONFIG_FILE-DoVUD52W.mjs +1 -0
  20. package/dist/packem_shared/LUNORA_EVENT_SOURCE-ZclWASXS.mjs +1 -0
  21. package/dist/packem_shared/LunoraReporter-BnXUqh8t.mjs +6 -0
  22. package/dist/packem_shared/PACKAGE_SECRETS_REGISTRY-BgmvEPA-.mjs +1 -0
  23. package/dist/packem_shared/POLICY_SCAFFOLD_ENDPOINT-CUYWD0Mh.mjs +1 -0
  24. package/dist/packem_shared/REMOTE_ELIGIBLE_KEYS-ws6iE0y-.mjs +1 -0
  25. package/dist/packem_shared/REQUIRED_COMPATIBILITY_DATE-BwmyesjD.mjs +1 -0
  26. package/dist/packem_shared/SCHEMA_EDIT_ENDPOINT-BNB1ogaj.mjs +1 -0
  27. package/dist/packem_shared/SEED_ENDPOINT-BaYShU8q.mjs +1 -0
  28. package/dist/packem_shared/WORKERS_CACHE_MIN_DATE-B1h_wNDN.mjs +1 -0
  29. package/dist/packem_shared/WRANGLER_FILES-Bi_18Pj6.mjs +1 -0
  30. package/dist/packem_shared/applyAdditiveEdit-Cff30cSa.mjs +6 -0
  31. package/dist/packem_shared/assetContentType-DNZyUOuF.mjs +1 -0
  32. package/dist/packem_shared/buildPackageSecretsBlock-DlAPMSwt.mjs +18 -0
  33. package/dist/packem_shared/classifyPolicyEdit-BzC_MfYK.mjs +24 -0
  34. package/dist/packem_shared/collectWranglerSecretVariables-jPUxMC9j.mjs +1 -0
  35. package/dist/packem_shared/createConfirm-7IL0kZyE.mjs +7 -0
  36. package/dist/packem_shared/detectFramework-VTQfCNXy.mjs +1 -0
  37. package/dist/packem_shared/discoverAgentInfo-BJm0QtoI.mjs +1 -0
  38. package/dist/packem_shared/discoverContainerInfo-CYG9j2LY.mjs +1 -0
  39. package/dist/packem_shared/discoverSchemaInfo-C8X9mo-i.mjs +1 -0
  40. package/dist/packem_shared/discoverWorkflowInfo-Bbc0u2gE.mjs +1 -0
  41. package/dist/packem_shared/inferLunoraBindings-tf2nExl_.mjs +1 -0
  42. package/dist/packem_shared/jsonc-edit-BZVpxVA0.mjs +1 -0
  43. package/dist/packem_shared/parseDevVariable-B193_28t.mjs +1 -0
  44. package/dist/packem_shared/parseSchema-BQjgz6bk.mjs +1 -0
  45. package/dist/packem_shared/{policy-scaffold.d-DCmwn7zQ.d.mts → policy-scaffold.d-CFd2FlqG.d.mts} +22 -22
  46. package/dist/packem_shared/{policy-scaffold.d-DCmwn7zQ.d.ts → policy-scaffold.d-CFd2FlqG.d.ts} +22 -22
  47. package/dist/packem_shared/reconcileWranglerBindings-BCwTpuLO.mjs +1 -0
  48. package/dist/packem_shared/reconcileWranglerCompatibilityDate-BXNiEQ7p.mjs +1 -0
  49. package/dist/packem_shared/reconcileWranglerCrons-BmQa_kGL.mjs +1 -0
  50. package/dist/packem_shared/renderStudioHtml-B2AkxcW1.mjs +15 -0
  51. package/dist/packem_shared/schema-info.d-DS0bUsWE.d.mts +375 -0
  52. package/dist/packem_shared/schema-info.d-DS0bUsWE.d.ts +375 -0
  53. package/dist/packem_shared/serveJsonHandler-DQ-Yqa4J.mjs +1 -0
  54. package/dist/packem_shared/streamContainerLogs-BPYBNrWS.mjs +2 -0
  55. package/dist/packem_shared/wranglerToAlchemy-Fh5KfTPB.mjs +6 -0
  56. package/dist/packem_shared/write-atomic-Cdr2oQb-.mjs +1 -0
  57. package/dist/studio-host/index.d.mts +166 -92
  58. package/dist/studio-host/index.d.ts +166 -92
  59. package/dist/studio-host/index.mjs +1 -7
  60. package/package.json +15 -8
  61. package/dist/packem_shared/ACCENT-DW1XJn8i.mjs +0 -40
  62. package/dist/packem_shared/AGENT_RULES_DIR-lcgC08aE.mjs +0 -40
  63. package/dist/packem_shared/DEV_VARS_EXAMPLE_FILE-dJPNTEnK.mjs +0 -37
  64. package/dist/packem_shared/LINKED_PROJECT_DIR-CXwXzV_C.mjs +0 -52
  65. package/dist/packem_shared/LUNORA_CONFIG_FILE-CtcIcB5-.mjs +0 -34
  66. package/dist/packem_shared/LUNORA_EVENT_SOURCE-D2fDeGB6.mjs +0 -86
  67. package/dist/packem_shared/LunoraReporter-Ci-bDCK9.mjs +0 -70
  68. package/dist/packem_shared/PACKAGE_SECRETS_REGISTRY-B8t_SdoZ.mjs +0 -70
  69. package/dist/packem_shared/POLICY_SCAFFOLD_ENDPOINT-CiC2IGKx.mjs +0 -103
  70. package/dist/packem_shared/REMOTE_ELIGIBLE_KEYS-BC7_e9Bz.mjs +0 -105
  71. package/dist/packem_shared/REQUIRED_COMPATIBILITY_DATE-DRSNSOOp.mjs +0 -476
  72. package/dist/packem_shared/SCHEMA_EDIT_ENDPOINT-Df-Wrix-.mjs +0 -99
  73. package/dist/packem_shared/SEED_ENDPOINT-DVCjaGO-.mjs +0 -61
  74. package/dist/packem_shared/WRANGLER_FILES-DwSuC-Kn.mjs +0 -25
  75. package/dist/packem_shared/applyAdditiveEdit-C-snTFEV.mjs +0 -228
  76. package/dist/packem_shared/buildPackageSecretsBlock-DNzNRu7T.mjs +0 -188
  77. package/dist/packem_shared/classifyPolicyEdit-BHeAqF8P.mjs +0 -99
  78. package/dist/packem_shared/createConfirm-fvpdgJ9s.mjs +0 -100
  79. package/dist/packem_shared/detectFramework-Br-BcPBq.mjs +0 -41
  80. package/dist/packem_shared/discoverContainerInfo-BXFs6Wav.mjs +0 -19
  81. package/dist/packem_shared/discoverSchemaInfo-BB-CKlTK.mjs +0 -25
  82. package/dist/packem_shared/discoverWorkflowInfo-CedvR0mn.mjs +0 -19
  83. package/dist/packem_shared/inferLunoraBindings-DIku9mTN.mjs +0 -302
  84. package/dist/packem_shared/loadStudioAssets-Csk5RS4E.mjs +0 -28
  85. package/dist/packem_shared/parseDevVariable-CJiq2IwE.mjs +0 -30
  86. package/dist/packem_shared/parseSchema-DSeyktvG.mjs +0 -107
  87. package/dist/packem_shared/reconcileWranglerBindings-DTHmqTbL.mjs +0 -277
  88. package/dist/packem_shared/renderStudioHtml-449Ysn75.mjs +0 -37
  89. package/dist/packem_shared/serveJsonHandler-B4OLTGLS.mjs +0 -86
@@ -0,0 +1,661 @@
1
+ import { D as DeployDriver, I as InferredBindings, S as SchemaInfo } from "../packem_shared/schema-info.d-DS0bUsWE.mjs";
2
+ import { WranglerVariableIR } from '@lunora/codegen';
3
+ /** The Cloudflare deploy driver. */
4
+ declare const CLOUDFLARE_DRIVER: DeployDriver;
5
+ /**
6
+ * A container/workflow that is declared (so codegen emits its class) but the
7
+ * worker entry never re-exports — the one wiring step the generators can't always
8
+ * do for the developer. wrangler rejects a `class_name` the deployed worker
9
+ * doesn't export, so a deploy fails late on this; surfacing it as structured data
10
+ * lets the Vite plugin raise it in the dev error overlay (not just the console)
11
+ * the moment the gap appears. The human-readable form is also folded into
12
+ * {@link ReconcileBindingsResult.warnings}.
13
+ */
14
+ interface ExportGap {
15
+ /** Generated class wrangler needs exported, e.g. `OrderPipelineWorkflow`. */
16
+ className: string;
17
+ /** The `lunora/{agents,containers,workflows}.ts` export name, e.g. `orderPipeline`. */
18
+ exportName: string;
19
+ /** Which declaration is unexported. */
20
+ kind: "agent" | "container" | "workflow";
21
+ /** The `_generated/{module}` to re-export from, e.g. `workflows`. */
22
+ module: "agents" | "containers" | "workflows";
23
+ }
24
+ interface ReconcileBindingsResult {
25
+ /** Short labels for each binding written (e.g. `"SCHEDULER/SchedulerDO"`). */
26
+ added: string[];
27
+ /** `true` when `wrangler.jsonc` was rewritten. */
28
+ changed: boolean;
29
+ /**
30
+ * Declared containers/workflows the worker entry doesn't re-export — the
31
+ * structured form of the corresponding `warnings` entries, for the dev error
32
+ * overlay. Empty when every declaration is wired.
33
+ */
34
+ exportGaps: ExportGap[];
35
+ /** Reason reconciliation was skipped, for logging. */
36
+ reason?: string;
37
+ /** Non-fatal hints for capabilities that cannot be auto-provisioned. */
38
+ warnings: string[];
39
+ /** Resolved wrangler path, or `undefined` when none was found. */
40
+ wranglerPath?: string;
41
+ }
42
+ /**
43
+ * Reconcile inferred Durable Object / D1 bindings into `wrangler.jsonc`.
44
+ *
45
+ * Writes only when something is missing; returns `changed: false` when the
46
+ * config already satisfies the inferred needs.
47
+ *
48
+ * `environment`, when passed, does NOT change where this writes — every step
49
+ * below still only touches the TOP-LEVEL config; wrangler's `env.<name>`
50
+ * blocks have no auto-provisioning path today. It is used only to emit an
51
+ * advisory warning, because bindings (`durable_objects`, `d1_databases`, …)
52
+ * are non-inheritable (see `wrangler-validator.ts`'s `NON_INHERITABLE_KEYS`):
53
+ * a `--env production` deploy needs its OWN copy of each one, and silently
54
+ * writing only to the top level would leave that gap unmentioned. Extending
55
+ * the JSONC writer itself to target `env.<name>.*` idempotently for every
56
+ * binding kind here is a separate, larger change (each of the ~10 pipeline
57
+ * steps below reads AND writes the top-level path) that this fix does not
58
+ * attempt — `lunora deploy --env <name>` now VALIDATES the env-scoped view
59
+ * (closing the reported gap), it just doesn't yet auto-provision it.
60
+ */
61
+ declare const reconcileWranglerBindings: (projectRoot: string, inferred: InferredBindings, environment?: string) => ReconcileBindingsResult;
62
+ interface ReconcileCompatibilityDateResult {
63
+ /** `true` when `wrangler.jsonc` was rewritten. */
64
+ changed: boolean;
65
+ /** The new date value, or the existing one when unchanged. */
66
+ date: string | undefined;
67
+ /** Human-readable reason when reconciliation was skipped. */
68
+ reason?: string;
69
+ /** Resolved wrangler path, or `undefined` when none was found. */
70
+ wranglerPath?: string;
71
+ }
72
+ /**
73
+ * Reconcile the `compatibility_date` in `wrangler.jsonc` when Workers Cache
74
+ * is enabled but the date is below the minimum required.
75
+ */
76
+ declare const reconcileWranglerCompatibilityDate: (projectRoot: string) => ReconcileCompatibilityDateResult;
77
+ interface ReconcileResult {
78
+ /** `true` when `wrangler.jsonc` was rewritten. */
79
+ changed: boolean;
80
+ /** Human-readable reason when reconciliation was skipped (for logging). */
81
+ reason?: string;
82
+ /** Resolved wrangler path, or `undefined` when none was found. */
83
+ wranglerPath?: string;
84
+ }
85
+ /**
86
+ * Reconcile the codegen-derived cron schedules into the project's
87
+ * `wrangler.jsonc` `triggers.crons` array, preserving comments and formatting
88
+ * via `jsonc-parser`'s structural edits.
89
+ *
90
+ * When `triggers.crons` already matches `cronTriggers`, nothing is written (so
91
+ * we don't churn the file or trip the dev server's file watcher). When the
92
+ * project declares no crons, a stale non-empty array is cleared so removed
93
+ * crons stop firing.
94
+ *
95
+ * This intentionally writes the SAME `triggers.crons` shape the
96
+ * `@lunora/config` validator accepts, so the wrangler validator never fights
97
+ * the generated value.
98
+ */
99
+ declare const reconcileWranglerCrons: (projectRoot: string, cronTriggers: ReadonlyArray<string>) => ReconcileResult;
100
+ /**
101
+ * The wrangler config sections Lunora can safely flip to remote mode in dev,
102
+ * each with the human label used in logs and the structural `shape` the entry
103
+ * lives in.
104
+ *
105
+ * `"array"` is a top-level array of binding objects (`d1_databases`,
106
+ * `kv_namespaces`, `r2_buckets`, `vectorize`, `services`). `"producers"` is
107
+ * `queues.producers[]` — consumers are NOT remoted (their schema has no `remote`
108
+ * field) and the edit path is two levels deep. `"object"` is a single binding
109
+ * object, not an array (`ai`), whose edit path targets the section key directly.
110
+ *
111
+ * Every kind here was confirmed against `wrangler/config-schema.json`: the
112
+ * entry's schema declares a `remote` property. Deliberately omits
113
+ * `durable_objects` (no CF remote-DO mode; shards stay local) and sections whose
114
+ * schema has no `remote` field (`hyperdrive`, `analytics_engine_datasets`,
115
+ * `secrets_store_secrets`, queue consumers, …). Widening further is a one-line
116
+ * table edit.
117
+ */
118
+ declare const REMOTE_ELIGIBLE_KEYS: {
119
+ readonly ai: {
120
+ readonly label: "AI";
121
+ readonly shape: "object";
122
+ };
123
+ readonly d1_databases: {
124
+ readonly label: "D1";
125
+ readonly shape: "array";
126
+ };
127
+ readonly kv_namespaces: {
128
+ readonly label: "KV";
129
+ readonly shape: "array";
130
+ };
131
+ readonly queues: {
132
+ readonly label: "Queue";
133
+ readonly shape: "producers";
134
+ };
135
+ readonly r2_buckets: {
136
+ readonly label: "R2";
137
+ readonly shape: "array";
138
+ };
139
+ readonly services: {
140
+ readonly label: "Service";
141
+ readonly shape: "array";
142
+ };
143
+ readonly vectorize: {
144
+ readonly label: "Vectorize";
145
+ readonly shape: "array";
146
+ };
147
+ };
148
+ type RemoteEligibleKey = keyof typeof REMOTE_ELIGIBLE_KEYS;
149
+ /** One binding object as it appears in any eligible section. */
150
+ interface BindingEntry {
151
+ binding?: string;
152
+ remote?: boolean;
153
+ }
154
+ /** One binding entry we mark remote, with enough provenance to log + edit it. */
155
+ interface RemoteBindingPlan {
156
+ /** The binding name as declared in the config (e.g. `"DB"`, `"FILES"`). */
157
+ binding: string;
158
+ /** Short kind label for logging (`"D1"`, `"KV"`, `"R2"`, `"Vectorize"`, …). */
159
+ kind: string;
160
+ /**
161
+ * The jsonc edit path within {@link RemoteBindingPlan.section}, relative to
162
+ * the section key: `[index]` for an `"array"` section, `["producers", index]`
163
+ * for a queue producer, or `[]` for the single-object `ai` section. The
164
+ * materializer prepends the section key and appends `"remote"`.
165
+ */
166
+ path: ReadonlyArray<number | string>;
167
+ /** The wrangler config key the entry lives under. */
168
+ section: RemoteEligibleKey;
169
+ }
170
+ /** The structural slice of a wrangler config the remote planner reads. */
171
+ interface RemoteWranglerShape {
172
+ ai?: BindingEntry | null;
173
+ d1_databases?: ReadonlyArray<BindingEntry | null | undefined>;
174
+ kv_namespaces?: ReadonlyArray<BindingEntry | null | undefined>;
175
+ queues?: {
176
+ producers?: ReadonlyArray<BindingEntry | null | undefined>;
177
+ } | null;
178
+ r2_buckets?: ReadonlyArray<BindingEntry | null | undefined>;
179
+ services?: ReadonlyArray<BindingEntry | null | undefined>;
180
+ vectorize?: ReadonlyArray<BindingEntry | null | undefined>;
181
+ }
182
+ /**
183
+ * Inspect a parsed wrangler config and list every eligible binding that should
184
+ * be flipped to remote mode. Pure — no file-system access, no mutation. An
185
+ * entry already carrying `"remote": true` is still reported (so logging is
186
+ * complete) but the materializer's edit is a harmless no-op for it.
187
+ */
188
+ declare const planRemoteBindings: (parsed: RemoteWranglerShape) => RemoteBindingPlan[];
189
+ /**
190
+ * Inject `"remote": true` onto each planned binding in the config `text`,
191
+ * comment-preservingly via jsonc edits. Pure string→string; the edits target
192
+ * disjoint entries so applying them sequentially is safe. The edit path is
193
+ * `[section, ...plan.path, "remote"]`, which resolves to the array element, the
194
+ * `queues.producers[i]` entry, or the single `ai` object as the plan demands.
195
+ */
196
+ declare const injectRemoteFlags: (text: string, plans: ReadonlyArray<RemoteBindingPlan>) => string;
197
+ interface MaterializeOptions {
198
+ /** When `false`, the call is a no-op (returns `enabled: false`). */
199
+ enabled: boolean;
200
+ projectRoot: string;
201
+ }
202
+ interface MaterializeResult {
203
+ /**
204
+ * Removes the generated temp config file. Always present and always safe to
205
+ * call: it is idempotent, a no-op when nothing was written (disabled /
206
+ * fall-through cases), and never throws if the path is already gone. The dev
207
+ * command calls this on every exit path (normal, signal, error).
208
+ */
209
+ cleanup: () => void;
210
+ /**
211
+ * Absolute path to the generated temp config to pass to
212
+ * `wrangler dev --config`. `undefined` when remote mode is disabled, no
213
+ * wrangler config was found, it failed to parse, or it declared no eligible
214
+ * binding (nothing to remote — run plain local dev).
215
+ */
216
+ configPath?: string;
217
+ /** Whether remote mode was requested at all. */
218
+ enabled: boolean;
219
+ /** Why no temp config was produced, for logging (only set when none was). */
220
+ reason?: string;
221
+ /** The bindings flipped to remote, for the dev banner. */
222
+ remoteBindings: RemoteBindingPlan[];
223
+ }
224
+ /**
225
+ * Produce a temporary wrangler config with `"remote": true` on every eligible
226
+ * binding, so `lunora dev` can run `wrangler dev --config &lt;temp>` against the
227
+ * deployed D1/KV/R2 without touching the user's file.
228
+ *
229
+ * The temp file is written as a sibling of the source `wrangler.jsonc` (in the
230
+ * project root), NOT an OS temp dir: wrangler resolves a config's relative paths
231
+ * (`main`, `assets`, `migrations_dir`, …) against the **config file's own
232
+ * directory**, so a temp config in `/tmp` would make wrangler look for
233
+ * `/tmp/src/server.ts` and fail to start the worker. Keeping it beside the real
234
+ * config preserves those relative paths. Returns `configPath: undefined` (with a
235
+ * `reason`) for every fall-through case so the caller degrades to plain local
236
+ * dev instead of failing.
237
+ */
238
+ declare const materializeRemoteWranglerConfig: (options: MaterializeOptions) => MaterializeResult;
239
+ /**
240
+ * Parse a `LUNORA_REMOTE` env value into the on/off decision. Truthy when set to
241
+ * `"1"` or `"true"` (case-insensitive); anything else — unset, `"0"`, `"false"`,
242
+ * empty — is off. Mirrors the `"1" | "true"` convention used across the runtime.
243
+ */
244
+ declare const isRemoteEnvEnabled: (value: string | undefined) => boolean;
245
+ /** The three inputs that can switch remote-binding dev on, in precedence order. */
246
+ interface RemoteEnableInputs {
247
+ /**
248
+ * The `remote` preference from `lunora.json` (the lowest-priority signal).
249
+ * `undefined` means "no project preference"; an explicit `false` here loses
250
+ * to neither the flag nor the env when those are absent — it just stays off.
251
+ */
252
+ configPreference?: boolean;
253
+ /** The raw `LUNORA_REMOTE` env value (parsed with {@link isRemoteEnvEnabled}). */
254
+ envValue?: string;
255
+ /** The explicit `--remote` CLI flag — `true` when passed, `undefined`/`false` otherwise. */
256
+ flag?: boolean;
257
+ }
258
+ /**
259
+ * Resolve whether remote-binding dev is on, with a clear precedence:
260
+ *
261
+ * 1. an explicit `--remote` flag (highest — a deliberate per-invocation choice),
262
+ * 2. then `LUNORA_REMOTE` in the environment,
263
+ * 3. then the `remote` key in `lunora.json` (lowest — a project default).
264
+ *
265
+ * The flag and env are one-directional (they can only turn remote *on*); only
266
+ * the config preference carries a meaningful `false`, and it applies solely when
267
+ * neither stronger signal is present. So a project that sets `"remote": false`
268
+ * is still overridable per-run by `--remote` or `LUNORA_REMOTE=1`.
269
+ */
270
+ declare const resolveRemoteEnabled: (inputs: RemoteEnableInputs) => boolean;
271
+ /**
272
+ * Single source of truth for "does this wrangler config enable Workers
273
+ * Cache?" and "what compatibility_date does that require?".
274
+ *
275
+ * Before this module, `reconcile-compatibility-date.ts` (auto-bump) and
276
+ * `wrangler-validator.ts` (validation) each carried their own
277
+ * `WORKERS_CACHE_MIN_DATE` literal and their own top-level/`exports[]`
278
+ * cache-enabled walk — two copies of the same fact that could silently drift
279
+ * apart (a date bumped in one file without the other would either validate a
280
+ * config the reconciler wouldn't produce, or vice versa).
281
+ */
282
+ /** The `compatibility_date` Workers Cache (`cache.enabled: true`) requires. */
283
+ declare const WORKERS_CACHE_MIN_DATE = "2026-05-01";
284
+ /** The subset of a parsed `wrangler.jsonc` the cache-enabled check reads. */
285
+ interface WranglerCacheShape {
286
+ cache?: {
287
+ enabled?: boolean;
288
+ } | null;
289
+ exports?: Record<string, {
290
+ cache?: {
291
+ enabled?: boolean;
292
+ } | null;
293
+ } | null> | null;
294
+ }
295
+ /**
296
+ * Whether Workers Cache is enabled anywhere in a parsed wrangler config — the
297
+ * top-level `cache.enabled` toggle, or a per-export override in
298
+ * `exports[name].cache.enabled` (Workers can scope cache per named export).
299
+ * `undefined`/`null` (an unparsed or absent config) is treated as disabled.
300
+ */
301
+ declare const isCacheEnabled: (parsed: WranglerCacheShape | null | undefined) => boolean;
302
+ /** Candidate wrangler config filenames, in the order every consumer probes them. */
303
+ declare const WRANGLER_FILES: readonly ["wrangler.jsonc", "wrangler.json"];
304
+ /** Locate the project's wrangler config, or `undefined` when none exists. */
305
+ declare const findWranglerFile: (projectRoot: string) => string | undefined;
306
+ interface ReadWranglerResult<T> {
307
+ /** Parsed config, or `undefined` when the file was not valid JSONC. */
308
+ parsed: T | undefined;
309
+ /** Raw file text — needed for comment-preserving `modify`/`applyEdits`. */
310
+ text: string;
311
+ }
312
+ /**
313
+ * Read and JSONC-parse a wrangler config file. Returns the raw `text` (for
314
+ * structural edits) alongside `parsed`, which is `undefined` when the file is
315
+ * not valid JSONC or does not parse to an object. Allows trailing commas, as
316
+ * wrangler does.
317
+ */
318
+ declare const readWranglerJsonc: <T = unknown>(wranglerPath: string) => ReadWranglerResult<T>;
319
+ /**
320
+ * Pure scan of a `vars` map for plaintext secrets — the FS-free core, exported for
321
+ * unit tests. A variable is flagged when, for a **string** value that is neither a
322
+ * placeholder nor a public/publishable key, EITHER the value matches a known
323
+ * secret shape (`secretKindOf`) OR the key name strongly implies a secret and the
324
+ * value is long enough to plausibly be one. `kind` is the matched shape, or
325
+ * `secret_named_var` for the key-name path.
326
+ */
327
+ declare const scanWranglerVariablesForSecrets: (variables: Record<string, unknown> | undefined, file: string) => WranglerVariableIR[];
328
+ /**
329
+ * Read the project's `wrangler.jsonc` and return its plaintext-secret `vars` as IR
330
+ * for the `plaintext_secret_in_wrangler_vars` lint. Returns `[]` when there is no
331
+ * wrangler config, it doesn't parse, or nothing looks like a secret. Scans the
332
+ * top-level `vars` block (mirroring the existing `validateCorsVariables` scope);
333
+ * per-environment `env.&lt;name>.vars` overrides are out of scope for now.
334
+ */
335
+ declare const collectWranglerSecretVariables: (projectRoot: string) => WranglerVariableIR[];
336
+ /**
337
+ * Translate a `wrangler.jsonc` into an [Alchemy](https://alchemy.run) program.
338
+ *
339
+ * # Why translate rather than ask for a second config
340
+ *
341
+ * `wrangler.jsonc` is already the source of truth for what an app needs, and
342
+ * Lunora already infers and reconciles it — `inferLunoraBindings` decides that
343
+ * a project needs a shard namespace and a bucket, `reconcileWranglerBindings`
344
+ * writes them. Asking a developer to restate all of that in an
345
+ * `alchemy.run.ts` would give the project two sources of truth that drift, and
346
+ * the drift would surface as a deploy that provisions something the app does
347
+ * not bind.
348
+ *
349
+ * So Alchemy is an implementation detail of `deploy`, not a thing to configure:
350
+ * read the config, emit the program, run it.
351
+ *
352
+ * # Why this emits source rather than calling Alchemy
353
+ *
354
+ * `alchemy@0.93` has thirty dependencies, nine of them Node-shaped —
355
+ * `wrangler`, `miniflare`, `esbuild`, `execa`, `find-process`, `glob`, `open`,
356
+ * `proper-lockfile`, `signal-exit`. `@lunora/config` is imported by
357
+ * `@lunora/vite`, so importing Alchemy here would push that tree into every
358
+ * project that merely wanted to read `lunora.json`, and into any bundle
359
+ * targeting workerd — where none of it survives.
360
+ *
361
+ * Emitting text keeps this module pure and dependency-free. Alchemy is invoked
362
+ * as a CLI against the generated file, so it only has to exist on the machine
363
+ * that deploys.
364
+ *
365
+ * # Adoption, not re-creation
366
+ *
367
+ * Every resource is emitted with `adopt: true`. A project translated from an
368
+ * existing `wrangler.jsonc` already *has* its D1 database and its bucket, with
369
+ * data in them. Without adoption Alchemy would treat them as new and try to
370
+ * create alongside — the one outcome a deploy must never have.
371
+ */
372
+ /** A Durable Object binding as `wrangler.jsonc` spells it. */
373
+ interface WranglerDurableObjectBinding$1 {
374
+ class_name?: string;
375
+ name?: string;
376
+ script_name?: string;
377
+ }
378
+ /** The slice of `wrangler.jsonc` that translates into Alchemy resources. */
379
+ interface WranglerConfigShape {
380
+ compatibility_date?: string;
381
+ compatibility_flags?: ReadonlyArray<string>;
382
+ d1_databases?: ReadonlyArray<{
383
+ binding?: string;
384
+ database_id?: string;
385
+ database_name?: string;
386
+ }>;
387
+ durable_objects?: {
388
+ bindings?: ReadonlyArray<WranglerDurableObjectBinding$1>;
389
+ };
390
+ kv_namespaces?: ReadonlyArray<{
391
+ binding?: string;
392
+ id?: string;
393
+ }>;
394
+ main?: string;
395
+ /** `new_sqlite_classes` marks which DO classes get SQLite storage — Alchemy needs that per namespace. */
396
+ migrations?: ReadonlyArray<{
397
+ new_classes?: ReadonlyArray<string>;
398
+ new_sqlite_classes?: ReadonlyArray<string>;
399
+ }>;
400
+ name?: string;
401
+ queues?: {
402
+ producers?: ReadonlyArray<{
403
+ binding?: string;
404
+ queue?: string;
405
+ }>;
406
+ };
407
+ r2_buckets?: ReadonlyArray<{
408
+ binding?: string;
409
+ bucket_name?: string;
410
+ }>;
411
+ triggers?: {
412
+ crons?: ReadonlyArray<string>;
413
+ };
414
+ vars?: Readonly<Record<string, unknown>>;
415
+ }
416
+ /** What the translation could not carry over, so the caller can say so out loud. */
417
+ interface AlchemyTranslation {
418
+ /** The emitted program source. */
419
+ source: string;
420
+ /**
421
+ * Bindings present in `wrangler.jsonc` that this translation drops.
422
+ *
423
+ * Reported rather than silently omitted: a deploy that quietly loses a
424
+ * Vectorize index produces a worker whose `env.POSTS_SEARCH` is undefined
425
+ * at runtime, and nothing in the build says why.
426
+ */
427
+ unsupported: ReadonlyArray<string>;
428
+ }
429
+ /**
430
+ * Translate a parsed `wrangler.jsonc` into an Alchemy program.
431
+ *
432
+ * Pure: it reads nothing and writes nothing, so the caller decides where the
433
+ * source lands and the whole thing stays testable as a string comparison.
434
+ * @param config The parsed `wrangler.jsonc`.
435
+ * @returns the program source, plus whatever could not be carried over.
436
+ */
437
+ declare const wranglerToAlchemy: (config: WranglerConfigShape) => AlchemyTranslation;
438
+ declare const REQUIRED_COMPATIBILITY_DATE: string;
439
+ declare const REQUIRED_FLAG: string;
440
+ interface WranglerDurableObjectBinding {
441
+ class_name?: string;
442
+ name?: string;
443
+ /** Present when the class lives in ANOTHER Worker — then it is that script's to export, not this entry's. */
444
+ script_name?: string;
445
+ }
446
+ /**
447
+ * A `tail_consumers` entry: a Worker that receives this Worker's tail events
448
+ * (logs, exceptions, fetch metadata) for forwarding to an external sink. See
449
+ * `withTailConsumer` for the wiring helper.
450
+ */
451
+ interface TailConsumer {
452
+ /** Optional Cloudflare environment of the consumer Worker. */
453
+ environment?: string;
454
+ /** Name of the Worker that consumes tail events. */
455
+ service?: string;
456
+ }
457
+ /** A wrangler `containers[]` entry (parsed from untrusted JSONC). */
458
+ interface WranglerContainerEntry {
459
+ class_name?: string;
460
+ image?: string;
461
+ instance_type?: string | {
462
+ disk_mb?: number;
463
+ memory_mib?: number;
464
+ vcpu?: number;
465
+ };
466
+ max_instances?: number;
467
+ }
468
+ /**
469
+ * A wrangler `workflows[]` entry (parsed from untrusted JSONC). Unlike
470
+ * containers, workflows are NOT Durable Objects — the entry stands alone (no
471
+ * `durable_objects` binding, no migration class).
472
+ */
473
+ interface WranglerWorkflowEntry {
474
+ binding?: string;
475
+ class_name?: string;
476
+ name?: string;
477
+ /** Present when the class lives in ANOTHER Worker — then it is that script's to export. */
478
+ script_name?: string;
479
+ }
480
+ /** A wrangler `queues.producers[]` entry — a `Queue` binding sending to `queue`. */
481
+ interface WranglerQueueProducer {
482
+ binding?: string;
483
+ delivery_delay?: number;
484
+ queue?: string;
485
+ }
486
+ /** A wrangler `queues.consumers[]` entry — push (worker) or `type: "http_pull"`. */
487
+ interface WranglerQueueConsumer {
488
+ dead_letter_queue?: string;
489
+ max_batch_size?: number;
490
+ max_batch_timeout?: number;
491
+ max_retries?: number;
492
+ queue?: string;
493
+ retry_delay?: number;
494
+ type?: string;
495
+ }
496
+ interface WranglerConfig {
497
+ analytics_engine_datasets?: ReadonlyArray<{
498
+ binding?: string;
499
+ dataset?: string;
500
+ } | null | undefined>;
501
+ assets?: {
502
+ binding?: string;
503
+ directory?: string;
504
+ html_handling?: string;
505
+ not_found_handling?: string;
506
+ };
507
+ browser?: {
508
+ binding?: string;
509
+ };
510
+ cache?: {
511
+ enabled?: boolean;
512
+ } | null;
513
+ compatibility_date?: string;
514
+ compatibility_flags?: ReadonlyArray<string>;
515
+ containers?: ReadonlyArray<WranglerContainerEntry | null | undefined>;
516
+ d1_databases?: ReadonlyArray<{
517
+ binding?: string;
518
+ }>;
519
+ dispatch_namespaces?: ReadonlyArray<{
520
+ binding?: string;
521
+ namespace?: string;
522
+ outbound?: unknown;
523
+ } | null | undefined>;
524
+ durable_objects?: {
525
+ bindings?: ReadonlyArray<WranglerDurableObjectBinding>;
526
+ };
527
+ env?: Record<string, WranglerConfig>;
528
+ exports?: Record<string, {
529
+ cache?: {
530
+ enabled?: boolean;
531
+ } | null;
532
+ type?: string;
533
+ } | null> | null;
534
+ flagship?: ReadonlyArray<{
535
+ app_id?: string;
536
+ binding?: string;
537
+ } | null | undefined>;
538
+ hyperdrive?: ReadonlyArray<{
539
+ binding?: string;
540
+ id?: string;
541
+ localConnectionString?: string;
542
+ } | null | undefined>;
543
+ images?: {
544
+ binding?: string;
545
+ };
546
+ kv_namespaces?: ReadonlyArray<{
547
+ binding?: string;
548
+ id?: string;
549
+ } | null | undefined>;
550
+ logpush?: boolean;
551
+ main?: string;
552
+ migrations?: ReadonlyArray<{
553
+ new_classes?: ReadonlyArray<string>;
554
+ new_sqlite_classes?: ReadonlyArray<string>;
555
+ } | null | undefined>;
556
+ mtls_certificates?: ReadonlyArray<{
557
+ binding?: string;
558
+ certificate_id?: string;
559
+ } | null | undefined>;
560
+ observability?: {
561
+ enabled?: boolean;
562
+ head_sampling_rate?: number;
563
+ logs?: {
564
+ enabled?: boolean;
565
+ head_sampling_rate?: number;
566
+ };
567
+ };
568
+ pipelines?: ReadonlyArray<{
569
+ binding?: string;
570
+ pipeline?: string;
571
+ stream?: string;
572
+ } | null | undefined>;
573
+ placement?: {
574
+ mode?: string;
575
+ };
576
+ queues?: {
577
+ consumers?: ReadonlyArray<WranglerQueueConsumer | null | undefined>;
578
+ producers?: ReadonlyArray<WranglerQueueProducer | null | undefined>;
579
+ };
580
+ r2_buckets?: ReadonlyArray<{
581
+ binding?: string;
582
+ }>;
583
+ secrets_store_secrets?: ReadonlyArray<{
584
+ binding?: string;
585
+ secret_name?: string;
586
+ store_id?: string;
587
+ } | null | undefined>;
588
+ send_email?: ReadonlyArray<{
589
+ allowed_destination_addresses?: ReadonlyArray<string>;
590
+ destination_address?: string;
591
+ name?: string;
592
+ } | null | undefined>;
593
+ services?: ReadonlyArray<{
594
+ binding?: string;
595
+ entrypoint?: string;
596
+ environment?: string;
597
+ service?: string;
598
+ } | null | undefined>;
599
+ tail_consumers?: ReadonlyArray<TailConsumer | null | undefined>;
600
+ vars?: Record<string, unknown>;
601
+ vectorize?: ReadonlyArray<{
602
+ binding?: string;
603
+ index_name?: string;
604
+ } | null | undefined>;
605
+ workflows?: ReadonlyArray<WranglerWorkflowEntry | null | undefined>;
606
+ }
607
+ interface WranglerValidationReport {
608
+ errors: string[];
609
+ valid: boolean;
610
+ warnings: string[];
611
+ }
612
+ /**
613
+ * Return a new `WranglerConfig` with `consumer` present in `tail_consumers`,
614
+ * wiring this Worker to forward its tail events (logs/exceptions) to another
615
+ * Worker that fans them out to an external sink. Pure and idempotent: an
616
+ * existing entry with the same `service` + `environment` is left untouched
617
+ * rather than duplicated, so it is safe to call on every codegen/deploy.
618
+ */
619
+ declare const withTailConsumer: (wrangler: WranglerConfig, consumer: TailConsumer) => WranglerConfig;
620
+ /**
621
+ * Pure validator: given a parsed `WranglerConfig` object and an optional
622
+ * `SchemaInfo`, produce a structured report. Performs no I/O.
623
+ *
624
+ * `environment`, when set, validates the `env.&lt;environment>` view
625
+ * ({@link mergeWranglerEnvironment}) instead of the top-level config — e.g. a
626
+ * `durable_objects` binding present only at the top level is a validation
627
+ * FAILURE for `--env production` if `env.production` doesn't repeat it,
628
+ * because `durable_objects` is non-inheritable and wrangler will not carry it
629
+ * over. Omit `environment` to validate the top level only (unchanged default).
630
+ */
631
+ declare const validateWranglerConfig: (wranglerInput: WranglerConfig | undefined, schema?: SchemaInfo, environment?: string) => WranglerValidationReport;
632
+ /**
633
+ * Convenience alias matching the original task-spec signature
634
+ * `validateWrangler(wranglerJson, schema)` returning
635
+ * `{ valid, errors, warnings }`.
636
+ */
637
+ declare const validateWrangler: typeof validateWranglerConfig;
638
+ interface WranglerProjectValidationOptions {
639
+ /**
640
+ * Cloudflare environment to validate against `env.&lt;name>` in
641
+ * wrangler.jsonc. See {@link mergeWranglerEnvironment} for which keys
642
+ * inherit the top-level value vs must be redeclared per environment.
643
+ * Omit to validate the top-level config only (unchanged default).
644
+ */
645
+ environment?: string;
646
+ projectRoot: string;
647
+ schemaDir?: string;
648
+ }
649
+ interface WranglerProjectValidationResult {
650
+ problems: ReadonlyArray<string>;
651
+ report: WranglerValidationReport;
652
+ wranglerPath: string | undefined;
653
+ }
654
+ /**
655
+ * File-system aware variant: reads `wrangler.jsonc`/`wrangler.json` from
656
+ * the given project root, discovers the schema (if any), and delegates to
657
+ * `validateWranglerConfig`. Returns the legacy
658
+ * `{ problems, wranglerPath }` shape plus the structured `report`.
659
+ */
660
+ declare const validateWranglerProject: (options: WranglerProjectValidationOptions) => WranglerProjectValidationResult;
661
+ export { type AlchemyTranslation, CLOUDFLARE_DRIVER, type ExportGap, type MaterializeOptions, type MaterializeResult, REMOTE_ELIGIBLE_KEYS, REQUIRED_COMPATIBILITY_DATE, REQUIRED_FLAG, type ReadWranglerResult, type ReconcileBindingsResult, type ReconcileCompatibilityDateResult, type ReconcileResult as ReconcileCronsResult, type RemoteBindingPlan, type RemoteEnableInputs, type RemoteWranglerShape, type TailConsumer, WORKERS_CACHE_MIN_DATE, WRANGLER_FILES, type WranglerCacheShape, type WranglerConfig, type WranglerConfigShape, type WranglerContainerEntry, type WranglerProjectValidationOptions, type WranglerProjectValidationResult, type WranglerValidationReport, type WranglerWorkflowEntry, collectWranglerSecretVariables, findWranglerFile, injectRemoteFlags, isCacheEnabled, isRemoteEnvEnabled, materializeRemoteWranglerConfig, planRemoteBindings, readWranglerJsonc, reconcileWranglerBindings, reconcileWranglerCompatibilityDate, reconcileWranglerCrons, resolveRemoteEnabled, scanWranglerVariablesForSecrets, validateWrangler, validateWranglerConfig, validateWranglerProject, withTailConsumer, wranglerToAlchemy };