@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.
- package/LICENSE.md +135 -0
- package/README.md +3 -3
- package/dist/cloudflare/index.d.mts +1252 -0
- package/dist/cloudflare/index.d.ts +1252 -0
- package/dist/cloudflare/index.mjs +1 -0
- package/dist/index.d.mts +1048 -917
- package/dist/index.d.ts +1048 -917
- package/dist/index.mjs +1 -23
- package/dist/packem_shared/ACCENT-CotPTfv7.mjs +7 -0
- package/dist/packem_shared/AGENT_MODE_ENV-D8MvSwPE.mjs +1 -0
- package/dist/packem_shared/AGENT_RULES_DIR-HrrbNZPy.mjs +1 -0
- package/dist/packem_shared/ALLOW_FORWARDED_ENV-BUndghJx.mjs +1 -0
- package/dist/packem_shared/BINDING_MANIFEST_VERSION-CfXEYG8e.mjs +1 -0
- package/dist/packem_shared/CLOUDFLARE_CLI_CONFIG_WARNING_ENV-BKMrOuXV.mjs +1 -0
- package/dist/packem_shared/CLOUDFLARE_DRIVER-CULavrYO.mjs +1 -0
- package/dist/packem_shared/CLOUDFLARE_TOOLCHAIN_VERSIONS-DV5E_f_q.mjs +1 -0
- package/dist/packem_shared/CODEGEN_ENV-ZsCxV1kP.mjs +1 -0
- package/dist/packem_shared/COMPOSED_WORKER_ENTRY-Ciiba5g_.mjs +1 -0
- package/dist/packem_shared/DEFAULT_DEPLOY_TARGET-rR7buNQw.mjs +1 -0
- package/dist/packem_shared/DEFAULT_OBSERVABILITY-bN6UkTMx.mjs +1 -0
- package/dist/packem_shared/DEV_BINDINGS_FILE-C0ZN_XlP.mjs +4 -0
- package/dist/packem_shared/DEV_VARS_EXAMPLE_FILE-CqLorAxT.mjs +6 -0
- package/dist/packem_shared/DEV_WORKER_ENV_VALUE-2XFXmRrP.mjs +1 -0
- package/dist/packem_shared/GLOBAL_FETCH_STRICTLY_PUBLIC_FLAG-f8CnJha3.mjs +1 -0
- package/dist/packem_shared/LINKED_PROJECT_DIR-Ba5qPEwo.mjs +2 -0
- package/dist/packem_shared/LUNORA_EVENT_SOURCE-B9ZVohjO.mjs +1 -0
- package/dist/packem_shared/LUNORA_IGNORED_PATHS-U93uPxrW.mjs +19 -0
- package/dist/packem_shared/LUNORA_TAG-CiQM3BkI.mjs +1 -0
- package/dist/packem_shared/LunoraReporter-f277GLNT.mjs +6 -0
- package/dist/packem_shared/PACKAGE_SECRETS_REGISTRY-38Plje8b.mjs +1 -0
- package/dist/packem_shared/POLICY_SCAFFOLD_ENDPOINT-BmJYwAy2.mjs +1 -0
- package/dist/packem_shared/REMOTE_ELIGIBLE_KEYS-PLeh_74E.mjs +1 -0
- package/dist/packem_shared/REQUIRED_COMPATIBILITY_DATE-OLQlG0oj.mjs +1 -0
- package/dist/packem_shared/SCHEMA_EDIT_ENDPOINT-BeTxqCuQ.mjs +1 -0
- package/dist/packem_shared/SEED_ENDPOINT-2B56PN_H.mjs +1 -0
- package/dist/packem_shared/STUDIO_PATH-CSx_psKS.mjs +1 -0
- package/dist/packem_shared/UNEXPORTED_CLASS_MARKER-DwJCN8fX.mjs +1 -0
- package/dist/packem_shared/WORKERS_CACHE_MIN_DATE-0k9ABJtF.mjs +1 -0
- package/dist/packem_shared/WRANGLER_FILES-UNW-xY5u.mjs +1 -0
- package/dist/packem_shared/acceptsConnection-DHhUYGjT.mjs +2 -0
- package/dist/packem_shared/addArgsFor-CYZKhNIo.mjs +1 -0
- package/dist/packem_shared/applyAdditiveEdit-CH0VhMJ2.mjs +6 -0
- package/dist/packem_shared/applyModify-DKP2l6S9.mjs +1 -0
- package/dist/packem_shared/applyStudioAssetCache-DHQEJuuv.mjs +1 -0
- package/dist/packem_shared/assertWranglerSatisfiesSchema-Dd7ZPhw7.mjs +3 -0
- package/dist/packem_shared/assetContentType-CUb5bpbI.mjs +1 -0
- package/dist/packem_shared/buildPackageSecretsBlock-BWV_VxqV.mjs +19 -0
- package/dist/packem_shared/celld-config-D-L6uskI.mjs +3 -0
- package/dist/packem_shared/classifyPolicyEdit-DJi9Fk8G.mjs +24 -0
- package/dist/packem_shared/collectExportGaps-BPuhGH2J.mjs +2 -0
- package/dist/packem_shared/createConfirm-D5mKTMHj.mjs +7 -0
- package/dist/packem_shared/createDiscoveryCache-npJI4uej.mjs +1 -0
- package/dist/packem_shared/describePreservedCrons-C5KPuPy3.mjs +1 -0
- package/dist/packem_shared/describeWithheldWorkersAi-IIxe3TuI.mjs +1 -0
- package/dist/packem_shared/detectFramework-Dfpvu6rD.mjs +1 -0
- package/dist/packem_shared/discover-info-DC2MrAIM.mjs +1 -0
- package/dist/packem_shared/discoverAgentInfo-pqFMJBtJ.mjs +1 -0
- package/dist/packem_shared/discoverContainerInfo-DzXr7Vm3.mjs +1 -0
- package/dist/packem_shared/discoverSchemaInfo-BBRlXZop.mjs +1 -0
- package/dist/packem_shared/discoverWorkflowInfo-zW7Tt0Tn.mjs +1 -0
- package/dist/packem_shared/guards-Buu_E7mP.mjs +1 -0
- package/dist/packem_shared/hasCloudflareCredentials-byvHpEiD.mjs +1 -0
- package/dist/packem_shared/infer-bindings-C1NFOdMi.mjs +1 -0
- package/dist/packem_shared/infer-bindings.d-CFxssIAC.d.mts +480 -0
- package/dist/packem_shared/infer-bindings.d-CFxssIAC.d.ts +480 -0
- package/dist/packem_shared/inferLunoraBindings-Gp_7yyIo.mjs +1 -0
- package/dist/packem_shared/interpretRemote-CcmGeGZ_.mjs +1 -0
- package/dist/packem_shared/lunora-manifest-DuH_Cmyu.mjs +6 -0
- package/dist/packem_shared/materializeServiceDevConfigs-DLUHefD-.mjs +1 -0
- package/dist/packem_shared/mergeWranglerEnvironment-DXiB-HcS.mjs +1 -0
- package/dist/packem_shared/package-secrets-registry-BeheNwsP.mjs +1 -0
- package/dist/packem_shared/parseDevVariable-teAAahVD.mjs +1 -0
- package/dist/packem_shared/parseSchema-D1Wbr1qv.mjs +1 -0
- package/dist/packem_shared/policy-scaffold.d-D2H4_G01.d.mts +86 -0
- package/dist/packem_shared/policy-scaffold.d-D2H4_G01.d.ts +86 -0
- package/dist/packem_shared/process-tree-once-Ou4SfxKM.mjs +1 -0
- package/dist/packem_shared/readProjectDependencies-l3uhUKjo.mjs +1 -0
- package/dist/packem_shared/reconcile-services-DFqH4eMQ.mjs +1 -0
- package/dist/packem_shared/reconcileBindingsSafely-7IJ58Uit.mjs +1 -0
- package/dist/packem_shared/reconcileWranglerCompatibilityDate-hocXEuRA.mjs +1 -0
- package/dist/packem_shared/renderStudioHtml-ByowDtMl.mjs +15 -0
- package/dist/packem_shared/resolveSchemaDirectory-Ca5P6KuP.mjs +1 -0
- package/dist/packem_shared/runPostCodegenHook-Dx3yTsYZ.mjs +1 -0
- package/dist/packem_shared/scanWranglerVariablesForSecrets-BFTVje1q.mjs +1 -0
- package/dist/packem_shared/serveJsonHandler-Dv0EdCb9.mjs +1 -0
- package/dist/packem_shared/startCelldDevSession-BLFsd6jG.mjs +1 -0
- package/dist/packem_shared/streamContainerLogs-0nko1qpv.mjs +2 -0
- package/dist/packem_shared/validate-bindings-CvNBF3U4.mjs +1 -0
- package/dist/packem_shared/withTailConsumer-DngzpJMK.mjs +1 -0
- package/dist/packem_shared/worker-entry-checks-AIASCYl7.mjs +1 -0
- package/dist/packem_shared/wranglerCodegenInputs-CbisphsH.mjs +1 -0
- package/dist/packem_shared/wranglerToAlchemy-CBO2ucRm.mjs +6 -0
- package/dist/packem_shared/write-atomic-CK6VZaPI.mjs +1 -0
- package/dist/studio-host/index.d.mts +314 -110
- package/dist/studio-host/index.d.ts +314 -110
- package/dist/studio-host/index.mjs +1 -7
- package/package.json +16 -7
- package/dist/packem_shared/ACCENT-DW1XJn8i.mjs +0 -40
- package/dist/packem_shared/AGENT_RULES_DIR-lcgC08aE.mjs +0 -40
- package/dist/packem_shared/DEV_VARS_EXAMPLE_FILE-dJPNTEnK.mjs +0 -37
- package/dist/packem_shared/LINKED_PROJECT_DIR-CXwXzV_C.mjs +0 -52
- package/dist/packem_shared/LUNORA_CONFIG_FILE-CtcIcB5-.mjs +0 -34
- package/dist/packem_shared/LUNORA_EVENT_SOURCE-D2fDeGB6.mjs +0 -86
- package/dist/packem_shared/LunoraReporter-Ci-bDCK9.mjs +0 -70
- package/dist/packem_shared/PACKAGE_SECRETS_REGISTRY-B8t_SdoZ.mjs +0 -70
- package/dist/packem_shared/POLICY_SCAFFOLD_ENDPOINT-CiC2IGKx.mjs +0 -103
- package/dist/packem_shared/REMOTE_ELIGIBLE_KEYS-BC7_e9Bz.mjs +0 -105
- package/dist/packem_shared/REQUIRED_COMPATIBILITY_DATE-2YYyWJUq.mjs +0 -561
- package/dist/packem_shared/SCHEMA_EDIT_ENDPOINT-Df-Wrix-.mjs +0 -99
- package/dist/packem_shared/SEED_ENDPOINT-DVCjaGO-.mjs +0 -61
- package/dist/packem_shared/WRANGLER_FILES-DwSuC-Kn.mjs +0 -25
- package/dist/packem_shared/applyAdditiveEdit-C-snTFEV.mjs +0 -228
- package/dist/packem_shared/buildPackageSecretsBlock-DWDKHViT.mjs +0 -243
- package/dist/packem_shared/classifyPolicyEdit-BHeAqF8P.mjs +0 -99
- package/dist/packem_shared/createConfirm-fvpdgJ9s.mjs +0 -100
- package/dist/packem_shared/detectFramework-Br-BcPBq.mjs +0 -41
- package/dist/packem_shared/discoverContainerInfo-BXFs6Wav.mjs +0 -19
- package/dist/packem_shared/discoverSchemaInfo-BB-CKlTK.mjs +0 -25
- package/dist/packem_shared/discoverWorkflowInfo-CedvR0mn.mjs +0 -19
- package/dist/packem_shared/inferLunoraBindings-ByMwG-gH.mjs +0 -352
- package/dist/packem_shared/loadStudioAssets-Csk5RS4E.mjs +0 -28
- package/dist/packem_shared/parseDevVariable-CJiq2IwE.mjs +0 -30
- package/dist/packem_shared/parseSchema-DSeyktvG.mjs +0 -107
- package/dist/packem_shared/policy-scaffold.d-DCmwn7zQ.d.mts +0 -74
- package/dist/packem_shared/policy-scaffold.d-DCmwn7zQ.d.ts +0 -74
- package/dist/packem_shared/reconcileWranglerBindings-Cruwwx1M.mjs +0 -334
- package/dist/packem_shared/renderStudioHtml-449Ysn75.mjs +0 -37
- package/dist/packem_shared/serveJsonHandler-B4OLTGLS.mjs +0 -86
- package/dist/packem_shared/streamContainerLogs-BZ4cOZwH.mjs +0 -157
|
@@ -0,0 +1,1252 @@
|
|
|
1
|
+
import { D as DeployDriver, G as GeneratedClassModule, I as InferredBindings, S as SchemaInfo } from "../packem_shared/infer-bindings.d-CFxssIAC.mjs";
|
|
2
|
+
import { WranglerQueueProducerIR, WranglerVariableIR } from '@lunora/codegen';
|
|
3
|
+
/** Apply one structural jsonc edit and return the rewritten text (a no-op edit returns the input). */
|
|
4
|
+
declare const applyModify: (text: string, path: ReadonlyArray<number | string>, value: unknown) => string;
|
|
5
|
+
/** The project coordinates the validator needs. */
|
|
6
|
+
interface AssertWranglerOptions {
|
|
7
|
+
/** Absolute path to the project root holding `wrangler.jsonc`. */
|
|
8
|
+
projectRoot: string;
|
|
9
|
+
/** The schema directory, relative to `projectRoot` (usually `"lunora"`). */
|
|
10
|
+
schemaDir: string;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Throw unless `wrangler.jsonc` satisfies the schema's binding requirements.
|
|
14
|
+
*
|
|
15
|
+
* Non-blocking validator warnings go to `warn`. `remedy` closes both error
|
|
16
|
+
* messages — the caller's own "and restart the dev server" / "and rebuild" —
|
|
17
|
+
* since that is the only part a reader acts on differently per front-end.
|
|
18
|
+
*
|
|
19
|
+
* Must run AFTER binding provisioning: the bindings this requires are largely the
|
|
20
|
+
* ones Lunora writes itself, so validating first fails the very first build of any
|
|
21
|
+
* project that declares a `.global()` table or a container.
|
|
22
|
+
*/
|
|
23
|
+
declare const assertWranglerSatisfiesSchema: (options: AssertWranglerOptions, warn: (message: string) => void, remedy: string) => void;
|
|
24
|
+
/**
|
|
25
|
+
* Translate a `wrangler.jsonc` into an [Alchemy](https://alchemy.run) program.
|
|
26
|
+
*
|
|
27
|
+
* # Why translate rather than ask for a second config
|
|
28
|
+
*
|
|
29
|
+
* `wrangler.jsonc` is already the source of truth for what an app needs, and
|
|
30
|
+
* Lunora already infers and reconciles it — `inferLunoraBindings` decides that
|
|
31
|
+
* a project needs a shard namespace and a bucket, `reconcileWranglerBindings`
|
|
32
|
+
* writes them. Asking a developer to restate all of that in an
|
|
33
|
+
* `alchemy.run.ts` would give the project two sources of truth that drift, and
|
|
34
|
+
* the drift would surface as a deploy that provisions something the app does
|
|
35
|
+
* not bind.
|
|
36
|
+
*
|
|
37
|
+
* So Alchemy is an implementation detail of `deploy`, not a thing to configure:
|
|
38
|
+
* read the config, emit the program, run it.
|
|
39
|
+
*
|
|
40
|
+
* # Why this emits source rather than calling Alchemy
|
|
41
|
+
*
|
|
42
|
+
* `alchemy@0.93` has thirty dependencies, nine of them Node-shaped —
|
|
43
|
+
* `wrangler`, `miniflare`, `esbuild`, `execa`, `find-process`, `glob`, `open`,
|
|
44
|
+
* `proper-lockfile`, `signal-exit`. `@lunora/config` is imported by
|
|
45
|
+
* `@lunora/vite`, so importing Alchemy here would push that tree into every
|
|
46
|
+
* project that merely wanted to read `lunora.config.*`, and into any bundle
|
|
47
|
+
* targeting workerd — where none of it survives.
|
|
48
|
+
*
|
|
49
|
+
* Emitting text keeps this module pure and dependency-free. Alchemy is invoked
|
|
50
|
+
* as a CLI against the generated file, so it only has to exist on the machine
|
|
51
|
+
* that deploys.
|
|
52
|
+
*
|
|
53
|
+
* # Adoption, not re-creation
|
|
54
|
+
*
|
|
55
|
+
* Every resource is emitted with `adopt: true`. A project translated from an
|
|
56
|
+
* existing `wrangler.jsonc` already *has* its D1 database and its bucket, with
|
|
57
|
+
* data in them. Without adoption Alchemy would treat them as new and try to
|
|
58
|
+
* create alongside — the one outcome a deploy must never have.
|
|
59
|
+
*/
|
|
60
|
+
/** A Durable Object binding as `wrangler.jsonc` spells it. */
|
|
61
|
+
interface WranglerDurableObjectBinding$1 {
|
|
62
|
+
class_name?: string;
|
|
63
|
+
name?: string;
|
|
64
|
+
script_name?: string;
|
|
65
|
+
}
|
|
66
|
+
/** The slice of `wrangler.jsonc` that translates into Alchemy resources. */
|
|
67
|
+
interface WranglerConfigShape {
|
|
68
|
+
compatibility_date?: string;
|
|
69
|
+
compatibility_flags?: ReadonlyArray<string>;
|
|
70
|
+
d1_databases?: ReadonlyArray<{
|
|
71
|
+
binding?: string;
|
|
72
|
+
database_id?: string;
|
|
73
|
+
database_name?: string;
|
|
74
|
+
}>;
|
|
75
|
+
durable_objects?: {
|
|
76
|
+
bindings?: ReadonlyArray<WranglerDurableObjectBinding$1>;
|
|
77
|
+
};
|
|
78
|
+
kv_namespaces?: ReadonlyArray<{
|
|
79
|
+
binding?: string;
|
|
80
|
+
id?: string;
|
|
81
|
+
}>;
|
|
82
|
+
main?: string;
|
|
83
|
+
/** `new_sqlite_classes` marks which DO classes get SQLite storage — Alchemy needs that per namespace. */
|
|
84
|
+
migrations?: ReadonlyArray<{
|
|
85
|
+
new_classes?: ReadonlyArray<string>;
|
|
86
|
+
new_sqlite_classes?: ReadonlyArray<string>;
|
|
87
|
+
}>;
|
|
88
|
+
name?: string;
|
|
89
|
+
/** Only `producers` translate; a `consumers` entry is dropped and reported as `queues.consumers`. */
|
|
90
|
+
queues?: {
|
|
91
|
+
consumers?: ReadonlyArray<{
|
|
92
|
+
queue?: string;
|
|
93
|
+
}>;
|
|
94
|
+
producers?: ReadonlyArray<{
|
|
95
|
+
binding?: string;
|
|
96
|
+
queue?: string;
|
|
97
|
+
}>;
|
|
98
|
+
};
|
|
99
|
+
r2_buckets?: ReadonlyArray<{
|
|
100
|
+
binding?: string;
|
|
101
|
+
bucket_name?: string;
|
|
102
|
+
}>;
|
|
103
|
+
triggers?: {
|
|
104
|
+
crons?: ReadonlyArray<string>;
|
|
105
|
+
};
|
|
106
|
+
vars?: Readonly<Record<string, unknown>>;
|
|
107
|
+
}
|
|
108
|
+
/** What the translation could not carry over, so the caller can say so out loud. */
|
|
109
|
+
interface AlchemyTranslation {
|
|
110
|
+
/** The emitted program source. */
|
|
111
|
+
source: string;
|
|
112
|
+
/**
|
|
113
|
+
* Bindings present in `wrangler.jsonc` that this translation drops.
|
|
114
|
+
*
|
|
115
|
+
* Reported rather than silently omitted: a deploy that quietly loses a
|
|
116
|
+
* Vectorize index produces a worker whose `env.POSTS_SEARCH` is undefined
|
|
117
|
+
* at runtime, and nothing in the build says why.
|
|
118
|
+
*/
|
|
119
|
+
unsupported: ReadonlyArray<string>;
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Translate a parsed `wrangler.jsonc` into an Alchemy program.
|
|
123
|
+
*
|
|
124
|
+
* Pure: it reads nothing and writes nothing, so the caller decides where the
|
|
125
|
+
* source lands and the whole thing stays testable as a string comparison.
|
|
126
|
+
* @param config The parsed `wrangler.jsonc`.
|
|
127
|
+
* @returns the program source, plus whatever could not be carried over.
|
|
128
|
+
*/
|
|
129
|
+
declare const wranglerToAlchemy: (config: WranglerConfigShape) => AlchemyTranslation;
|
|
130
|
+
/** Schema version of the emitted document, so a consumer can gate on shape changes. */
|
|
131
|
+
declare const BINDING_MANIFEST_VERSION = 1;
|
|
132
|
+
/**
|
|
133
|
+
* One resource the built Worker expects to be bound to. `binding` is the name the
|
|
134
|
+
* Worker reads off `env`; the remaining fields are whatever identifies the
|
|
135
|
+
* resource for that type, omitted when the config does not carry them (an id
|
|
136
|
+
* Lunora could not mint is absent here exactly as it is absent from the config).
|
|
137
|
+
*/
|
|
138
|
+
interface BindingRequirement {
|
|
139
|
+
/** The `env` property name the Worker reads. */
|
|
140
|
+
binding: string;
|
|
141
|
+
/**
|
|
142
|
+
* Durable Object / Workflow / Container class the Worker must export. Present
|
|
143
|
+
* for the class-backed binding types, so a deployer can assert the bundle
|
|
144
|
+
* exports it before publishing.
|
|
145
|
+
*/
|
|
146
|
+
className?: string;
|
|
147
|
+
/** Bucket name (`r2`), database name (`d1`), dataset (`analytics_engine`), queue name (`queue`), index (`vectorize`), stream (`pipeline`), namespace (`artifacts`, `ai_search_namespace`), instance (`ai_search`), Worker name (`service`). */
|
|
148
|
+
resource?: string;
|
|
149
|
+
/** Remote resource id, when the config declares one (`d1`, `kv`, `hyperdrive`, `vpc_service`, `vpc_network`). */
|
|
150
|
+
resourceId?: string;
|
|
151
|
+
/** For `durable_object`: whether the class uses SQLite storage (`new_sqlite_classes`). */
|
|
152
|
+
sqlite?: boolean;
|
|
153
|
+
/** The kind of resource, keyed to the wrangler section it came from. */
|
|
154
|
+
type: "ai" | "ai_search" | "ai_search_namespace" | "analytics_engine" | "analytics_sql" | "artifacts" | "assets" | "browser" | "container" | "d1" | "durable_object" | "hyperdrive" | "images" | "kv" | "media" | "pipeline" | "queue_consumer" | "queue_producer" | "r2" | "service" | "stream" | "vectorize" | "vpc_network" | "vpc_service" | "workflow";
|
|
155
|
+
}
|
|
156
|
+
/** The document the `lunora build --emit-bindings` flag writes. */
|
|
157
|
+
interface BindingManifest {
|
|
158
|
+
/** Every resource the Worker expects, sorted by `type` then `binding` so the file is diff-stable. */
|
|
159
|
+
bindings: ReadonlyArray<BindingRequirement>;
|
|
160
|
+
/** `compatibility_date`, when declared. */
|
|
161
|
+
compatibilityDate?: string;
|
|
162
|
+
/** `compatibility_flags`, when declared. */
|
|
163
|
+
compatibilityFlags?: ReadonlyArray<string>;
|
|
164
|
+
/** Cron expressions the Worker must be triggered on (`triggers.crons`). */
|
|
165
|
+
crons: ReadonlyArray<string>;
|
|
166
|
+
/** Worker name from `wrangler.jsonc`. */
|
|
167
|
+
name?: string;
|
|
168
|
+
/**
|
|
169
|
+
* Wrangler sections present in the config that this version does not model,
|
|
170
|
+
* by field name. Empty for a fully-understood config; non-empty is a prompt to
|
|
171
|
+
* extend the collector, and is surfaced to the user rather than silently
|
|
172
|
+
* dropped.
|
|
173
|
+
*/
|
|
174
|
+
unknown: ReadonlyArray<string>;
|
|
175
|
+
/** Names of `vars` entries. Values are deliberately excluded — a manifest is committed and read by CI, and a `vars` entry can hold a value a project would rather not publish. */
|
|
176
|
+
vars: ReadonlyArray<string>;
|
|
177
|
+
/** Schema version — {@link BINDING_MANIFEST_VERSION}. */
|
|
178
|
+
version: number;
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* The wider config this reads. {@link WranglerConfigShape} covers what the
|
|
182
|
+
* Alchemy translation models; a manifest additionally reports the sections that
|
|
183
|
+
* translation lists as unsupported, so those are declared here.
|
|
184
|
+
*/
|
|
185
|
+
interface ManifestConfigShape extends WranglerConfigShape {
|
|
186
|
+
ai?: {
|
|
187
|
+
binding?: string;
|
|
188
|
+
};
|
|
189
|
+
ai_search?: ReadonlyArray<{
|
|
190
|
+
binding?: string;
|
|
191
|
+
instance_name?: string;
|
|
192
|
+
}>;
|
|
193
|
+
ai_search_namespaces?: ReadonlyArray<{
|
|
194
|
+
binding?: string;
|
|
195
|
+
namespace?: string;
|
|
196
|
+
}>;
|
|
197
|
+
/** The Analytics SQL binding — a parameterless `{ binding }`, distinct from `analytics_engine_datasets`. */
|
|
198
|
+
analytics?: {
|
|
199
|
+
binding?: string;
|
|
200
|
+
};
|
|
201
|
+
analytics_engine_datasets?: ReadonlyArray<{
|
|
202
|
+
binding?: string;
|
|
203
|
+
dataset?: string;
|
|
204
|
+
}>;
|
|
205
|
+
artifacts?: ReadonlyArray<{
|
|
206
|
+
binding?: string;
|
|
207
|
+
namespace?: string;
|
|
208
|
+
}>;
|
|
209
|
+
/** Static assets carry a real `binding` the Worker reads (`env.ASSETS`). */
|
|
210
|
+
assets?: {
|
|
211
|
+
binding?: string;
|
|
212
|
+
directory?: string;
|
|
213
|
+
};
|
|
214
|
+
browser?: {
|
|
215
|
+
binding?: string;
|
|
216
|
+
};
|
|
217
|
+
containers?: ReadonlyArray<{
|
|
218
|
+
class_name?: string;
|
|
219
|
+
image?: string;
|
|
220
|
+
max_instances?: number;
|
|
221
|
+
}>;
|
|
222
|
+
/** Top-level exports; only `type: "workflow"` entries map to a binding requirement (see {@link collectWorkflowExports}). */
|
|
223
|
+
exports?: Record<string, {
|
|
224
|
+
name?: string;
|
|
225
|
+
type?: string;
|
|
226
|
+
} | null | undefined>;
|
|
227
|
+
hyperdrive?: ReadonlyArray<{
|
|
228
|
+
binding?: string;
|
|
229
|
+
id?: string;
|
|
230
|
+
}>;
|
|
231
|
+
images?: {
|
|
232
|
+
binding?: string;
|
|
233
|
+
};
|
|
234
|
+
media?: {
|
|
235
|
+
binding?: string;
|
|
236
|
+
};
|
|
237
|
+
/** `pipeline` is wrangler's deprecated spelling of `stream`; both are read. */
|
|
238
|
+
pipelines?: ReadonlyArray<{
|
|
239
|
+
binding?: string;
|
|
240
|
+
pipeline?: string;
|
|
241
|
+
stream?: string;
|
|
242
|
+
}>;
|
|
243
|
+
/** Adds `consumers` — the Alchemy translation models producers only. */
|
|
244
|
+
queues?: {
|
|
245
|
+
consumers?: ReadonlyArray<{
|
|
246
|
+
queue?: string;
|
|
247
|
+
}>;
|
|
248
|
+
producers?: ReadonlyArray<{
|
|
249
|
+
binding?: string;
|
|
250
|
+
queue?: string;
|
|
251
|
+
}>;
|
|
252
|
+
};
|
|
253
|
+
/** Service bindings to sibling Workers; `service` is the Worker name. */
|
|
254
|
+
services?: ReadonlyArray<{
|
|
255
|
+
binding?: string;
|
|
256
|
+
entrypoint?: string;
|
|
257
|
+
service?: string;
|
|
258
|
+
}>;
|
|
259
|
+
stream?: {
|
|
260
|
+
binding?: string;
|
|
261
|
+
};
|
|
262
|
+
vectorize?: ReadonlyArray<{
|
|
263
|
+
binding?: string;
|
|
264
|
+
index_name?: string;
|
|
265
|
+
}>;
|
|
266
|
+
vpc_networks?: ReadonlyArray<{
|
|
267
|
+
binding?: string;
|
|
268
|
+
network_id?: string;
|
|
269
|
+
tunnel_id?: string;
|
|
270
|
+
}>;
|
|
271
|
+
vpc_services?: ReadonlyArray<{
|
|
272
|
+
binding?: string;
|
|
273
|
+
service_id?: string;
|
|
274
|
+
}>;
|
|
275
|
+
workflows?: ReadonlyArray<{
|
|
276
|
+
binding?: string;
|
|
277
|
+
class_name?: string;
|
|
278
|
+
name?: string;
|
|
279
|
+
}>;
|
|
280
|
+
}
|
|
281
|
+
/**
|
|
282
|
+
* Build the manifest for a parsed `wrangler.jsonc`.
|
|
283
|
+
*
|
|
284
|
+
* Pure: reads nothing and writes nothing, so the caller decides where the
|
|
285
|
+
* document lands and the mapping stays testable as a plain object comparison.
|
|
286
|
+
* @param config The parsed, already-reconciled `wrangler.jsonc`.
|
|
287
|
+
* @returns the requirements document.
|
|
288
|
+
*/
|
|
289
|
+
declare const buildBindingManifest: (config: ManifestConfigShape) => BindingManifest;
|
|
290
|
+
/** Env var the once-per-process-tree guard behind {@link warnCloudflareCliConfigOnce} sets. */
|
|
291
|
+
declare const CLOUDFLARE_CLI_CONFIG_WARNING_ENV = "LUNORA_CF_CONFIG_WARNING_SHOWN";
|
|
292
|
+
/** A detected Cloudflare CLI config: what was found, and what to do about it. */
|
|
293
|
+
interface CloudflareCliConfigFinding {
|
|
294
|
+
/** What to do — `cf` resource commands are fine, lifecycle commands are not. Links the tracking issue. */
|
|
295
|
+
fix: string;
|
|
296
|
+
/** One line: which file was found, where, and why it is a problem. */
|
|
297
|
+
message: string;
|
|
298
|
+
}
|
|
299
|
+
/**
|
|
300
|
+
* Detect a Cloudflare CLI config (`cloudflare.config.{ts,mts,js,mjs}`) in
|
|
301
|
+
* `projectRoot`, or `undefined` when there is none. The message names the
|
|
302
|
+
* wrangler config actually present (`wrangler.jsonc` / `wrangler.json`), or says
|
|
303
|
+
* "in the project root" when there is none yet.
|
|
304
|
+
*/
|
|
305
|
+
declare const detectCloudflareCliConfig: (projectRoot: string) => CloudflareCliConfigFinding | undefined;
|
|
306
|
+
/**
|
|
307
|
+
* Warn through `warn` when `projectRoot` holds a Cloudflare CLI config — once
|
|
308
|
+
* per process tree (a rebuild, a dev-server restart, or a child process that
|
|
309
|
+
* inherited the env stays quiet). The guard is read before the filesystem probe,
|
|
310
|
+
* and claimed only when there is something to say. Non-blocking by design: the
|
|
311
|
+
* risk is a separate `cf` lifecycle command, not anything Lunora runs. Returns
|
|
312
|
+
* whether it warned.
|
|
313
|
+
*/
|
|
314
|
+
declare const warnCloudflareCliConfigOnce: (projectRoot: string, warn: (message: string) => void) => boolean;
|
|
315
|
+
/** The Cloudflare deploy driver. */
|
|
316
|
+
declare const CLOUDFLARE_DRIVER: DeployDriver;
|
|
317
|
+
/**
|
|
318
|
+
* The `global_fetch_strictly_public` compatibility flag: every global `fetch` from
|
|
319
|
+
* the Worker goes out to the public internet, never to a private or special-use
|
|
320
|
+
* address. `workersCimdFetch()` from `@lunora/auth/cimd/workers` refuses to build
|
|
321
|
+
* without it, and `lunora doctor` checks for it wherever that transport is imported.
|
|
322
|
+
*/
|
|
323
|
+
declare const GLOBAL_FETCH_STRICTLY_PUBLIC_FLAG = "global_fetch_strictly_public";
|
|
324
|
+
/** Inputs, injectable so tests never read the real home directory or env. */
|
|
325
|
+
interface CloudflareCredentialProbe {
|
|
326
|
+
env?: Record<string, string | undefined>;
|
|
327
|
+
home?: string;
|
|
328
|
+
/** Project whose `.env` files are read; omit to skip them. */
|
|
329
|
+
projectRoot?: string;
|
|
330
|
+
}
|
|
331
|
+
declare const hasCloudflareCredentials: (probe?: CloudflareCredentialProbe) => boolean;
|
|
332
|
+
/** Which kind of temp config a file is, in its name. */
|
|
333
|
+
type DevConfigKind = "dev" | "service";
|
|
334
|
+
/**
|
|
335
|
+
* The binding name to withhold from a logged-out dev session, or `undefined` to keep
|
|
336
|
+
* it. The credential probe runs only when an `ai` binding is declared at all.
|
|
337
|
+
*/
|
|
338
|
+
declare const withheldWorkersAi: (ai: {
|
|
339
|
+
binding?: string;
|
|
340
|
+
} | null | undefined, hasCredentials: () => boolean) => string | undefined;
|
|
341
|
+
/** The one dev warning for a withheld Workers AI binding, shared by `lunora dev` and `@lunora/vite`. */
|
|
342
|
+
declare const describeWithheldWorkersAi: (binding: string) => string;
|
|
343
|
+
/**
|
|
344
|
+
* A container/workflow that is declared (so codegen emits its class) but the
|
|
345
|
+
* worker entry never re-exports — the one wiring step the generators can't always
|
|
346
|
+
* do for the developer. wrangler rejects a `class_name` the deployed worker
|
|
347
|
+
* doesn't export, so a deploy fails late on this; surfacing it as structured data
|
|
348
|
+
* lets the Vite plugin raise it in the dev error overlay (not just the console)
|
|
349
|
+
* the moment the gap appears. The human-readable form is also folded into
|
|
350
|
+
* {@link ReconcileBindingsResult.warnings}.
|
|
351
|
+
*/
|
|
352
|
+
interface ExportGap {
|
|
353
|
+
/** Generated class wrangler needs exported, e.g. `OrderPipelineWorkflow`. */
|
|
354
|
+
className: string;
|
|
355
|
+
/** The `lunora/{agents,containers,workflows}.ts` export name, e.g. `orderPipeline`. */
|
|
356
|
+
exportName: string;
|
|
357
|
+
/** Which declaration is unexported. */
|
|
358
|
+
kind: "agent" | "container" | "workflow";
|
|
359
|
+
/** The `_generated/{module}` to re-export from, e.g. `workflows`. */
|
|
360
|
+
module: GeneratedClassModule;
|
|
361
|
+
}
|
|
362
|
+
interface ReconcileBindingsResult {
|
|
363
|
+
/** Short labels for each binding written (e.g. `"SCHEDULER/SchedulerDO"`). */
|
|
364
|
+
added: string[];
|
|
365
|
+
/** `true` when `wrangler.jsonc` was rewritten. */
|
|
366
|
+
changed: boolean;
|
|
367
|
+
/** What was written to the SvelteKit / Nuxt dev sidecar's own config, when anything was. */
|
|
368
|
+
devConfig?: {
|
|
369
|
+
added: string[];
|
|
370
|
+
path: string;
|
|
371
|
+
updated: string[];
|
|
372
|
+
};
|
|
373
|
+
/**
|
|
374
|
+
* Declared containers/workflows the worker entry doesn't re-export — the
|
|
375
|
+
* structured form of the corresponding `warnings` entries, for the dev error
|
|
376
|
+
* overlay. Empty when every declaration is wired.
|
|
377
|
+
*/
|
|
378
|
+
exportGaps: ExportGap[];
|
|
379
|
+
/** Reason reconciliation was skipped, for logging. */
|
|
380
|
+
reason?: string;
|
|
381
|
+
/**
|
|
382
|
+
* Short labels for each EXISTING entry whose settings were brought in line
|
|
383
|
+
* with its declaration (e.g. `"queues.consumers/receipt-queue (max_retries)"`).
|
|
384
|
+
* Kept apart from `added` so a retune is not logged as a new binding.
|
|
385
|
+
*/
|
|
386
|
+
updated: string[];
|
|
387
|
+
/** Non-fatal hints for capabilities that cannot be auto-provisioned. */
|
|
388
|
+
warnings: string[];
|
|
389
|
+
/** Resolved wrangler path, or `undefined` when none was found. */
|
|
390
|
+
wranglerPath?: string;
|
|
391
|
+
}
|
|
392
|
+
/**
|
|
393
|
+
* The declared-but-not-re-exported containers and workflows, as structured
|
|
394
|
+
* {@link ExportGap}s. The same gaps `collectWarnings` renders into prose — kept
|
|
395
|
+
* here as data so the Vite plugin can raise them in the error overlay with a
|
|
396
|
+
* precise remediation, rather than re-parsing the warning strings.
|
|
397
|
+
*
|
|
398
|
+
* Exported because reconciliation is not the only caller that needs the answer:
|
|
399
|
+
* `lunora codegen` and `lunora doctor` both want the gaps WITHOUT rewriting
|
|
400
|
+
* `wrangler.jsonc`, which is the rest of what {@link reconcileWranglerBindings}
|
|
401
|
+
* does. Deriving them again from `inferred.{containers,workflows,agents}` at each
|
|
402
|
+
* call site is how one kind ends up silently uncovered.
|
|
403
|
+
*/
|
|
404
|
+
declare const collectExportGaps: (inferred: InferredBindings) => ExportGap[];
|
|
405
|
+
/**
|
|
406
|
+
* Reconcile inferred Durable Object / D1 bindings into `wrangler.jsonc`.
|
|
407
|
+
*
|
|
408
|
+
* Writes only when something is missing; returns `changed: false` when the
|
|
409
|
+
* config already satisfies the inferred needs.
|
|
410
|
+
*
|
|
411
|
+
* `environment`, when passed, does NOT change where this provisions — every
|
|
412
|
+
* step below still only ADDS to the TOP-LEVEL config; wrangler's `env.<name>`
|
|
413
|
+
* blocks have no auto-provisioning path today. The one write into the block is
|
|
414
|
+
* {@link reconcileEnvQueues}, which retunes queue consumers the block already
|
|
415
|
+
* declares and adds nothing. Otherwise it is used only to emit an
|
|
416
|
+
* advisory warning, because bindings (`durable_objects`, `d1_databases`, …)
|
|
417
|
+
* are non-inheritable (see `wrangler-environment.ts`'s `NON_INHERITABLE_KEYS`):
|
|
418
|
+
* a `--env production` deploy needs its OWN copy of each one, and silently
|
|
419
|
+
* writing only to the top level would leave that gap unmentioned. Extending
|
|
420
|
+
* the JSONC writer itself to target `env.<name>.*` idempotently for every
|
|
421
|
+
* binding kind here is a separate, larger change (each of the ~10 pipeline
|
|
422
|
+
* steps below reads AND writes the top-level path) that this fix does not
|
|
423
|
+
* attempt — `lunora deploy --env <name>` now VALIDATES the env-scoped view
|
|
424
|
+
* (closing the reported gap), it just doesn't yet auto-provision it.
|
|
425
|
+
*/
|
|
426
|
+
declare const reconcileWranglerBindings: (projectRoot: string, inferred: InferredBindings, { environment, target }?: {
|
|
427
|
+
environment?: string;
|
|
428
|
+
target?: string;
|
|
429
|
+
}) => ReconcileBindingsResult;
|
|
430
|
+
interface ReconcileCompatibilityDateResult {
|
|
431
|
+
/** `true` when `wrangler.jsonc` was rewritten. */
|
|
432
|
+
changed: boolean;
|
|
433
|
+
/** The new date value, or the existing one when unchanged. */
|
|
434
|
+
date: string | undefined;
|
|
435
|
+
/** Human-readable reason when reconciliation was skipped. */
|
|
436
|
+
reason?: string;
|
|
437
|
+
/** Resolved wrangler path, or `undefined` when none was found. */
|
|
438
|
+
wranglerPath?: string;
|
|
439
|
+
}
|
|
440
|
+
/**
|
|
441
|
+
* Reconcile the `compatibility_date` in `wrangler.jsonc` when Workers Cache
|
|
442
|
+
* is enabled but the date is below the minimum required.
|
|
443
|
+
*/
|
|
444
|
+
declare const reconcileWranglerCompatibilityDate: (projectRoot: string) => ReconcileCompatibilityDateResult;
|
|
445
|
+
interface ReconcileResult {
|
|
446
|
+
/** `true` when the wrangler config's `triggers.crons` was rewritten. */
|
|
447
|
+
changed: boolean;
|
|
448
|
+
/**
|
|
449
|
+
* Entries left in `triggers.crons` that this reconciler did not generate and
|
|
450
|
+
* does not own — a hand-written `backupCron` trigger, or anything already
|
|
451
|
+
* there before ownership was first recorded. Non-empty means the array is
|
|
452
|
+
* NOT the codegen-derived set, which is the surprising half of what this
|
|
453
|
+
* does and the one thing worth printing.
|
|
454
|
+
*/
|
|
455
|
+
preserved: string[];
|
|
456
|
+
/** Human-readable reason when reconciliation was skipped (for logging). */
|
|
457
|
+
reason?: string;
|
|
458
|
+
/**
|
|
459
|
+
* Problems with the ownership record itself, for the caller to `warn`. A
|
|
460
|
+
* damaged `lunora.crons` is not fatal — the reconciler degrades to add-only
|
|
461
|
+
* — but the degradation is invisible: the generated cron it wrote last pass
|
|
462
|
+
* is reported back as hand-written and is then kept for good. Silence is
|
|
463
|
+
* what turns a merge conflict into a permanent orphan.
|
|
464
|
+
*/
|
|
465
|
+
warnings: string[];
|
|
466
|
+
/** Resolved wrangler path, or `undefined` when none was found. */
|
|
467
|
+
wranglerPath?: string;
|
|
468
|
+
}
|
|
469
|
+
/**
|
|
470
|
+
* Reconcile the codegen-derived cron schedules into the project's wrangler
|
|
471
|
+
* config `triggers.crons` array, preserving comments and formatting via
|
|
472
|
+
* `jsonc-parser`'s structural edits.
|
|
473
|
+
*
|
|
474
|
+
* **This does not own the whole array.** Two runtime cron surfaces live on
|
|
475
|
+
* `createWorker` rather than in `lunora/crons.ts`: `backupCron` (the nightly
|
|
476
|
+
* NDJSON backup) and `crons` (handlers keyed by expression). Replacing the array
|
|
477
|
+
* wholesale deleted both on the next `lunora deploy` or dev-server schema save,
|
|
478
|
+
* silently — the nightly backup simply stopped. So an entry this reconciler did
|
|
479
|
+
* not generate is the user's, is kept, and is reported in
|
|
480
|
+
* {@link ReconcileResult.preserved}.
|
|
481
|
+
*
|
|
482
|
+
* Codegen now scans the worker entry for both, so the STATIC case arrives in
|
|
483
|
+
* `cronTriggers` like any declared cron — kept because it is generated, and
|
|
484
|
+
* cleared when the entry stops declaring it. What it cannot resolve is the
|
|
485
|
+
* dynamic case, and that case is supported: `.extend((env) => ({ backupCron:
|
|
486
|
+
* env.NIGHTLY_CRON }))` is the documented escape hatch, and its value exists
|
|
487
|
+
* only at runtime. That residue — plus a computed `crons` key, a spread options
|
|
488
|
+
* object, and anything a project put in `triggers.crons` for its own reasons —
|
|
489
|
+
* is what the preserve rule below is for. It is not redundant with discovery; it
|
|
490
|
+
* is the half discovery provably cannot reach.
|
|
491
|
+
*
|
|
492
|
+
* Ownership is recorded in the project's `package.json` under `lunora.crons`,
|
|
493
|
+
* which is why a REMOVED generated cron still gets cleared (it is in the record
|
|
494
|
+
* and no longer in `cronTriggers`) while a hand-written one never is. Three
|
|
495
|
+
* properties pick that location:
|
|
496
|
+
*
|
|
497
|
+
* COMMITTED, so it survives a fresh clone. Gitignored `.lunora/` state does not:
|
|
498
|
+
* a CI-only deploy finds none, and falling back to add-only there leaves a
|
|
499
|
+
* removed cron firing forever.
|
|
500
|
+
*
|
|
501
|
+
* VALID JSON, so `wrangler.json` — a supported config name — behaves exactly like
|
|
502
|
+
* `wrangler.jsonc`. A `//` marker inside the config does not: wrangler tolerates
|
|
503
|
+
* one in either (both go through its JSONC parser), but the project's own
|
|
504
|
+
* `JSON.parse`, its deploy wrapper and its editor's JSON schema validation all
|
|
505
|
+
* break the moment a `.json` grows a comment. Nor can the record be a plain key
|
|
506
|
+
* in the wrangler config — wrangler reports unknown fields ("Unexpected fields
|
|
507
|
+
* found in top-level field") on every command.
|
|
508
|
+
*
|
|
509
|
+
* READ AND WRITTEN AT ONE ADDRESS. A comment has to be found textually on the way
|
|
510
|
+
* in and positioned structurally on the way out, and those are not the same
|
|
511
|
+
* place: a stale duplicate higher in the file was read as the record and deleted
|
|
512
|
+
* the user's backup trigger.
|
|
513
|
+
*
|
|
514
|
+
* The wrangler config is rewritten only when an entry actually moves, so
|
|
515
|
+
* {@link ReconcileResult.changed} means what a `synced N cron trigger(s)` log
|
|
516
|
+
* claims it means.
|
|
517
|
+
*
|
|
518
|
+
* A project with nothing recorded yet — one predating this, or one with no
|
|
519
|
+
* manifest — treats every entry as the user's, which is the safe direction: a
|
|
520
|
+
* wrongly-kept trigger costs one no-op invocation, a wrongly-deleted one
|
|
521
|
+
* silently ends the backups. It becomes precise after a codegen run that still
|
|
522
|
+
* declares the cron; upgrading and deleting a cron in the same change records an
|
|
523
|
+
* empty set, and that orphan is then kept for good.
|
|
524
|
+
*
|
|
525
|
+
* This intentionally writes the SAME `triggers.crons` shape the
|
|
526
|
+
* `@lunora/config` validator accepts, so the wrangler validator never fights the
|
|
527
|
+
* generated value.
|
|
528
|
+
*/
|
|
529
|
+
declare const reconcileWranglerCrons: (projectRoot: string, cronTriggers: ReadonlyArray<string>) => ReconcileResult;
|
|
530
|
+
/**
|
|
531
|
+
* The one log line worth printing for a reconcile that kept entries it does not
|
|
532
|
+
* own, or `undefined` when it owned the whole array. Lives here rather than in
|
|
533
|
+
* each caller because `lunora deploy` and the Vite plugin print it verbatim and
|
|
534
|
+
* had already drifted into two copies of the same sentence.
|
|
535
|
+
*/
|
|
536
|
+
declare const describePreservedCrons: (preserved: ReadonlyArray<string>) => string | undefined;
|
|
537
|
+
/** The project coordinates every reconciler here needs. */
|
|
538
|
+
interface ReconcileProject {
|
|
539
|
+
/** Absolute path to the project root holding `wrangler.jsonc`. */
|
|
540
|
+
projectRoot: string;
|
|
541
|
+
/** The schema directory, relative to `projectRoot` (usually `"lunora"`). */
|
|
542
|
+
schemaDir: string;
|
|
543
|
+
/** The deploy target; wrangler settings only Cloudflare reads are written only for `"cloudflare"` (or when omitted). */
|
|
544
|
+
target?: string;
|
|
545
|
+
}
|
|
546
|
+
/** The two logger methods every reconciler here needs; `info` is optional on Vite's. */
|
|
547
|
+
interface ReconcileLogger {
|
|
548
|
+
info?: (message: string) => void;
|
|
549
|
+
warn: (message: string) => void;
|
|
550
|
+
}
|
|
551
|
+
/**
|
|
552
|
+
* Infer the Cloudflare bindings the project's code implies and reconcile them
|
|
553
|
+
* into `wrangler.jsonc` (Durable Objects, their migration classes, and the
|
|
554
|
+
* `DB` D1 binding for `.global()` schemas). Best-effort and idempotent — runs
|
|
555
|
+
* once at startup so the user never hand-writes binding boilerplate. A failure
|
|
556
|
+
* here must never abort codegen; the wrangler validator reports real problems.
|
|
557
|
+
*
|
|
558
|
+
* `onExportGaps` (dev only) is invoked when a declared container/workflow isn't
|
|
559
|
+
* re-exported by the worker entry, so the caller can raise it in the browser
|
|
560
|
+
* error overlay in addition to the console warning.
|
|
561
|
+
*/
|
|
562
|
+
declare const reconcileBindingsSafely: (options: ReconcileProject, logger: ReconcileLogger, onExportGaps?: (gaps: ReadonlyArray<ExportGap>) => void) => Promise<void>;
|
|
563
|
+
/** Reconcile cron triggers and the compatibility date into `wrangler.jsonc`. */
|
|
564
|
+
declare const reconcileWranglerExtras: (projectRoot: string, cronTriggers: ReadonlyArray<string>, logger: ReconcileLogger) => void;
|
|
565
|
+
/**
|
|
566
|
+
* The wrangler config sections Lunora can safely flip to remote mode in dev,
|
|
567
|
+
* each with the human label used in logs and the structural `shape` the entry
|
|
568
|
+
* lives in.
|
|
569
|
+
*
|
|
570
|
+
* `"array"` is a top-level array of binding objects (`d1_databases`,
|
|
571
|
+
* `kv_namespaces`, `r2_buckets`, `vectorize`, `services`). `"producers"` is
|
|
572
|
+
* `queues.producers[]` — consumers are NOT remoted (their schema has no `remote`
|
|
573
|
+
* field) and the edit path is two levels deep. `"object"` is a single binding
|
|
574
|
+
* object, not an array (`ai`), whose edit path targets the section key directly.
|
|
575
|
+
*
|
|
576
|
+
* Every kind here was confirmed against `wrangler/config-schema.json`: the
|
|
577
|
+
* entry's schema declares a `remote` property. Deliberately omits
|
|
578
|
+
* `durable_objects` (no CF remote-DO mode; shards stay local) and sections whose
|
|
579
|
+
* schema has no `remote` field (`hyperdrive`, `analytics_engine_datasets`,
|
|
580
|
+
* `secrets_store_secrets`, queue consumers, …). Widening further is a one-line
|
|
581
|
+
* table edit.
|
|
582
|
+
*/
|
|
583
|
+
declare const REMOTE_ELIGIBLE_KEYS: {
|
|
584
|
+
readonly ai: {
|
|
585
|
+
readonly label: "AI";
|
|
586
|
+
readonly shape: "object";
|
|
587
|
+
};
|
|
588
|
+
readonly ai_search: {
|
|
589
|
+
readonly label: "AI Search";
|
|
590
|
+
readonly shape: "array";
|
|
591
|
+
};
|
|
592
|
+
readonly ai_search_namespaces: {
|
|
593
|
+
readonly label: "AI Search namespace";
|
|
594
|
+
readonly shape: "array";
|
|
595
|
+
};
|
|
596
|
+
readonly analytics: {
|
|
597
|
+
readonly label: "Analytics SQL";
|
|
598
|
+
readonly shape: "object";
|
|
599
|
+
};
|
|
600
|
+
readonly d1_databases: {
|
|
601
|
+
readonly label: "D1";
|
|
602
|
+
readonly shape: "array";
|
|
603
|
+
};
|
|
604
|
+
readonly kv_namespaces: {
|
|
605
|
+
readonly label: "KV";
|
|
606
|
+
readonly shape: "array";
|
|
607
|
+
};
|
|
608
|
+
readonly queues: {
|
|
609
|
+
readonly label: "Queue";
|
|
610
|
+
readonly shape: "producers";
|
|
611
|
+
};
|
|
612
|
+
readonly r2_buckets: {
|
|
613
|
+
readonly label: "R2";
|
|
614
|
+
readonly shape: "array";
|
|
615
|
+
};
|
|
616
|
+
readonly services: {
|
|
617
|
+
readonly label: "Service";
|
|
618
|
+
readonly shape: "array";
|
|
619
|
+
};
|
|
620
|
+
readonly vectorize: {
|
|
621
|
+
readonly label: "Vectorize";
|
|
622
|
+
readonly shape: "array";
|
|
623
|
+
};
|
|
624
|
+
};
|
|
625
|
+
type RemoteEligibleKey = keyof typeof REMOTE_ELIGIBLE_KEYS;
|
|
626
|
+
/** One binding object as it appears in any eligible section. */
|
|
627
|
+
interface BindingEntry {
|
|
628
|
+
binding?: string;
|
|
629
|
+
remote?: boolean;
|
|
630
|
+
}
|
|
631
|
+
/** One binding entry we mark remote, with enough provenance to log + edit it. */
|
|
632
|
+
interface RemoteBindingPlan {
|
|
633
|
+
/** The binding name as declared in the config (e.g. `"DB"`, `"FILES"`). */
|
|
634
|
+
binding: string;
|
|
635
|
+
/** Short kind label for logging (`"D1"`, `"KV"`, `"R2"`, `"Vectorize"`, …). */
|
|
636
|
+
kind: string;
|
|
637
|
+
/**
|
|
638
|
+
* The jsonc edit path within {@link RemoteBindingPlan.section}, relative to
|
|
639
|
+
* the section key: `[index]` for an `"array"` section, `["producers", index]`
|
|
640
|
+
* for a queue producer, or `[]` for the single-object `ai` section. The
|
|
641
|
+
* materializer prepends the section key and appends `"remote"`.
|
|
642
|
+
*/
|
|
643
|
+
path: ReadonlyArray<number | string>;
|
|
644
|
+
/** The wrangler config key the entry lives under. */
|
|
645
|
+
section: RemoteEligibleKey;
|
|
646
|
+
}
|
|
647
|
+
/** The structural slice of a wrangler config the remote planner reads. */
|
|
648
|
+
interface RemoteWranglerShape {
|
|
649
|
+
ai?: BindingEntry | null;
|
|
650
|
+
ai_search?: ReadonlyArray<BindingEntry | null | undefined>;
|
|
651
|
+
ai_search_namespaces?: ReadonlyArray<BindingEntry | null | undefined>;
|
|
652
|
+
analytics?: BindingEntry | null;
|
|
653
|
+
d1_databases?: ReadonlyArray<BindingEntry | null | undefined>;
|
|
654
|
+
kv_namespaces?: ReadonlyArray<BindingEntry | null | undefined>;
|
|
655
|
+
queues?: {
|
|
656
|
+
producers?: ReadonlyArray<BindingEntry | null | undefined>;
|
|
657
|
+
} | null;
|
|
658
|
+
r2_buckets?: ReadonlyArray<BindingEntry | null | undefined>;
|
|
659
|
+
services?: ReadonlyArray<BindingEntry | null | undefined>;
|
|
660
|
+
vectorize?: ReadonlyArray<BindingEntry | null | undefined>;
|
|
661
|
+
}
|
|
662
|
+
/**
|
|
663
|
+
* Inspect a parsed wrangler config and list every eligible binding that should
|
|
664
|
+
* be flipped to remote mode. Pure — no file-system access, no mutation. An
|
|
665
|
+
* entry already carrying `"remote": true` is still reported (so logging is
|
|
666
|
+
* complete) but the materializer's edit is a harmless no-op for it.
|
|
667
|
+
*/
|
|
668
|
+
declare const planRemoteBindings: (parsed: RemoteWranglerShape) => RemoteBindingPlan[];
|
|
669
|
+
/**
|
|
670
|
+
* Inject `"remote": true` onto each planned binding in the config `text`,
|
|
671
|
+
* comment-preservingly via jsonc edits. Pure string→string; the edits target
|
|
672
|
+
* disjoint entries so applying them sequentially is safe. The edit path is
|
|
673
|
+
* `[section, ...plan.path, "remote"]`, which resolves to the array element, the
|
|
674
|
+
* `queues.producers[i]` entry, or the single `ai` object as the plan demands.
|
|
675
|
+
*/
|
|
676
|
+
declare const injectRemoteFlags: (text: string, plans: ReadonlyArray<RemoteBindingPlan>) => string;
|
|
677
|
+
interface MaterializeDevOptions {
|
|
678
|
+
/** Whether wrangler can authenticate; defaults to a probe of `projectRoot`. */
|
|
679
|
+
hasCredentials?: () => boolean;
|
|
680
|
+
projectRoot: string;
|
|
681
|
+
/** Proxy the eligible bindings to the deployed resources (`--remote` / `LUNORA_REMOTE`). Off, only the logged-out `ai` withholding applies. */
|
|
682
|
+
remote: boolean;
|
|
683
|
+
}
|
|
684
|
+
interface MaterializeDevResult {
|
|
685
|
+
/** Removes the temp config. Always safe to call: idempotent, and a no-op when nothing was written. */
|
|
686
|
+
cleanup: () => void;
|
|
687
|
+
/** The temp config to pass to `wrangler dev --config`, or `undefined` to run the user's file unchanged. */
|
|
688
|
+
configPath?: string;
|
|
689
|
+
/** Why remote mode produced no temp config, for the dev log. Only set when nothing was written. */
|
|
690
|
+
reason?: string;
|
|
691
|
+
/** The bindings flipped to remote, for the dev banner. */
|
|
692
|
+
remoteBindings: RemoteBindingPlan[];
|
|
693
|
+
/** The `ai` binding name left out for lack of Cloudflare credentials, for the dev warning. */
|
|
694
|
+
withheld: string[];
|
|
695
|
+
}
|
|
696
|
+
/**
|
|
697
|
+
* Write the temp wrangler config a dev session runs with: the user's file with any
|
|
698
|
+
* eligible bindings flipped to `"remote": true` (when `remote` is set), and the
|
|
699
|
+
* `ai` binding removed when the session has no Cloudflare login. See `dev-config.ts`
|
|
700
|
+
* for why the `ai` removal exists.
|
|
701
|
+
*
|
|
702
|
+
* The temp file sits beside the source `wrangler.jsonc`, not in an OS temp dir,
|
|
703
|
+
* because wrangler resolves a config's relative `main`/`assets`/`migrations_dir`
|
|
704
|
+
* paths against the config file's own directory. Returns no `configPath` when there
|
|
705
|
+
* is nothing to change, so the caller runs the user's file unchanged.
|
|
706
|
+
*/
|
|
707
|
+
declare const materializeDevWranglerConfig: (options: MaterializeDevOptions) => MaterializeDevResult;
|
|
708
|
+
/**
|
|
709
|
+
* Parse a `LUNORA_REMOTE` env value into the on/off decision. Truthy when set to
|
|
710
|
+
* `"1"` or `"true"` (case-insensitive); anything else — unset, `"0"`, `"false"`,
|
|
711
|
+
* empty — is off. Mirrors the `"1" | "true"` convention used across the runtime.
|
|
712
|
+
*/
|
|
713
|
+
declare const isRemoteEnvEnabled: (value: string | undefined) => boolean;
|
|
714
|
+
/** The three inputs that can switch remote-binding dev on, in precedence order. */
|
|
715
|
+
interface RemoteEnableInputs {
|
|
716
|
+
/**
|
|
717
|
+
* The `remote` preference from `lunora.config.*` (the lowest-priority signal).
|
|
718
|
+
* `undefined` means "no project preference"; an explicit `false` here loses
|
|
719
|
+
* to neither the flag nor the env when those are absent — it just stays off.
|
|
720
|
+
*/
|
|
721
|
+
configPreference?: boolean;
|
|
722
|
+
/** The raw `LUNORA_REMOTE` env value (parsed with {@link isRemoteEnvEnabled}). */
|
|
723
|
+
envValue?: string;
|
|
724
|
+
/** The explicit `--remote` CLI flag — `true` when passed, `undefined`/`false` otherwise. */
|
|
725
|
+
flag?: boolean;
|
|
726
|
+
}
|
|
727
|
+
/**
|
|
728
|
+
* Resolve whether remote-binding dev is on, with a clear precedence:
|
|
729
|
+
*
|
|
730
|
+
* 1. an explicit `--remote` flag (highest — a deliberate per-invocation choice),
|
|
731
|
+
* 2. then `LUNORA_REMOTE` in the environment,
|
|
732
|
+
* 3. then the `remote` key in `lunora.config.*` (lowest — a project default).
|
|
733
|
+
*
|
|
734
|
+
* The flag and env are one-directional (they can only turn remote *on*); only
|
|
735
|
+
* the config preference carries a meaningful `false`, and it applies solely when
|
|
736
|
+
* neither stronger signal is present. So a project that sets `"remote": false`
|
|
737
|
+
* is still overridable per-run by `--remote` or `LUNORA_REMOTE=1`.
|
|
738
|
+
*/
|
|
739
|
+
declare const resolveRemoteEnabled: (inputs: RemoteEnableInputs) => boolean;
|
|
740
|
+
/** The configs to pass as `--config`, in input order, and what was done to them. */
|
|
741
|
+
interface ServiceDevConfigs {
|
|
742
|
+
/** Unlinks every copy written. Idempotent, never throws — a no-op when none was. */
|
|
743
|
+
cleanup: () => void;
|
|
744
|
+
configPaths: string[];
|
|
745
|
+
/** The `ai` binding names left out of a service copy for lack of Cloudflare credentials, for the dev warning. */
|
|
746
|
+
withheld: string[];
|
|
747
|
+
}
|
|
748
|
+
interface ServiceMaterializeOptions {
|
|
749
|
+
/** Whether wrangler can authenticate; defaults to a probe of `projectRoot`. */
|
|
750
|
+
hasCredentials?: () => boolean;
|
|
751
|
+
/** The app's folder, where `wrangler dev` runs and whose `.env` files it reads. */
|
|
752
|
+
projectRoot: string;
|
|
753
|
+
}
|
|
754
|
+
/**
|
|
755
|
+
* Resolve the `--config` path of each service the shared `wrangler dev` session
|
|
756
|
+
* runs, writing a copy only for a service that needs one (see the module doc).
|
|
757
|
+
*/
|
|
758
|
+
declare const materializeServiceDevConfigs: (wranglerPaths: ReadonlyArray<string>, options: ServiceMaterializeOptions) => ServiceDevConfigs;
|
|
759
|
+
/**
|
|
760
|
+
* The Cloudflare toolchain ranges a scaffolded Lunora app declares — the one
|
|
761
|
+
* source for `lunora init`'s overlay. The `templates/*` starters are fetched at
|
|
762
|
+
* runtime and cannot import this, so `tests/vis-templates` asserts that every
|
|
763
|
+
* template declaring one of these packages declares exactly this range.
|
|
764
|
+
*
|
|
765
|
+
* `@cloudflare/workers-types` is on the v5 line: v4 ended at 4.20260702.1, and
|
|
766
|
+
* v5's root entrypoint is the latest runtime (AI Search, Artifacts, Analytics
|
|
767
|
+
* SQL, tracing `setStatus`). `wrangler` >= 4.145.0 accepts the Analytics SQL
|
|
768
|
+
* `analytics` binding that `ctx.analyticsSql` makes `lunora dev` write, and
|
|
769
|
+
* >= 4.142.0 declares and runs Workflows in `exports`, which codegen writes.
|
|
770
|
+
* `@cloudflare/vite-plugin` matches the wrangler it embeds.
|
|
771
|
+
*
|
|
772
|
+
* Bump it together with the `cloudflare` / `vite` catalogs in `pnpm-workspace.yaml`.
|
|
773
|
+
*/
|
|
774
|
+
declare const CLOUDFLARE_TOOLCHAIN_VERSIONS: Readonly<Record<"@cloudflare/vite-plugin" | "@cloudflare/workers-types" | "wrangler", string>>;
|
|
775
|
+
/** The `wrangler.jsonc` shape the validator reads, and the report it returns. */
|
|
776
|
+
interface WranglerDurableObjectBinding {
|
|
777
|
+
class_name?: string;
|
|
778
|
+
name?: string;
|
|
779
|
+
/** Present when the class lives in ANOTHER Worker — then it is that script's to export, not this entry's. */
|
|
780
|
+
script_name?: string;
|
|
781
|
+
}
|
|
782
|
+
/**
|
|
783
|
+
* A `tail_consumers` entry: a Worker that receives this Worker's tail events
|
|
784
|
+
* (logs, exceptions, fetch metadata) for forwarding to an external sink. See
|
|
785
|
+
* `withTailConsumer` for the wiring helper.
|
|
786
|
+
*/
|
|
787
|
+
interface TailConsumer {
|
|
788
|
+
/** Optional Cloudflare environment of the consumer Worker. */
|
|
789
|
+
environment?: string;
|
|
790
|
+
/** Name of the Worker that consumes tail events. */
|
|
791
|
+
service?: string;
|
|
792
|
+
}
|
|
793
|
+
/**
|
|
794
|
+
* `observability.traces` — Workers Traces. `destinations` names OpenTelemetry
|
|
795
|
+
* export destinations configured in the dashboard; `persist: false` exports
|
|
796
|
+
* without also storing in Cloudflare (default `true`).
|
|
797
|
+
* https://developers.cloudflare.com/workers/observability/opentelemetry-export/
|
|
798
|
+
*/
|
|
799
|
+
interface WranglerObservabilityTraces {
|
|
800
|
+
destinations?: ReadonlyArray<string>;
|
|
801
|
+
enabled?: boolean;
|
|
802
|
+
/** Fraction of requests traced, 0–1. */
|
|
803
|
+
head_sampling_rate?: number;
|
|
804
|
+
persist?: boolean;
|
|
805
|
+
}
|
|
806
|
+
/**
|
|
807
|
+
* `observability.logs` — Workers Logs. Same export knobs as traces, plus
|
|
808
|
+
* `invocation_logs` (the per-invocation summary line; default `true`).
|
|
809
|
+
*/
|
|
810
|
+
interface WranglerObservabilityLogs extends WranglerObservabilityTraces {
|
|
811
|
+
invocation_logs?: boolean;
|
|
812
|
+
}
|
|
813
|
+
/** The wrangler `observability` block (Workers Logs + Traces). */
|
|
814
|
+
interface WranglerObservability {
|
|
815
|
+
enabled?: boolean;
|
|
816
|
+
/** Fraction of requests logged, 0–1 (wrangler's default is 1: every request). */
|
|
817
|
+
head_sampling_rate?: number;
|
|
818
|
+
/** Workers Issues — detects and groups production failures. */
|
|
819
|
+
issues?: {
|
|
820
|
+
enabled?: boolean;
|
|
821
|
+
};
|
|
822
|
+
logs?: WranglerObservabilityLogs;
|
|
823
|
+
/** Strip query strings from request URLs in logs and traces (wrangler's default is `false`). */
|
|
824
|
+
redact_query_string?: boolean;
|
|
825
|
+
traces?: WranglerObservabilityTraces;
|
|
826
|
+
}
|
|
827
|
+
/**
|
|
828
|
+
* The `observability` block Lunora writes when a project has none — by
|
|
829
|
+
* `lunora dev`'s binding reconcile and by `lunora init`'s scaffold. Logs on,
|
|
830
|
+
* every request sampled: the right default while an app is small, and what
|
|
831
|
+
* `lunora doctor`'s `observability-full-sampling` advisory then flags once
|
|
832
|
+
* Workers Observability is billed. One constant so the writers and the doctor
|
|
833
|
+
* cannot drift apart.
|
|
834
|
+
*/
|
|
835
|
+
declare const DEFAULT_OBSERVABILITY: Readonly<{
|
|
836
|
+
enabled: true;
|
|
837
|
+
head_sampling_rate: 1;
|
|
838
|
+
}>;
|
|
839
|
+
/** One signal's effective sampling, as {@link resolveObservabilitySampling} resolves it. */
|
|
840
|
+
interface ObservabilitySignalSampling {
|
|
841
|
+
enabled: boolean;
|
|
842
|
+
/** Fraction of requests sampled, 0–1. */
|
|
843
|
+
headSamplingRate: number;
|
|
844
|
+
}
|
|
845
|
+
/**
|
|
846
|
+
* The effective logs / traces sampling an `observability` block deploys with,
|
|
847
|
+
* defaults applied. An absent block is {@link DEFAULT_OBSERVABILITY}, which is
|
|
848
|
+
* what Lunora reconciles it to. Inside a present block, logs are on unless the
|
|
849
|
+
* block (or its `logs` sub-block) turns them off; traces are opt-in
|
|
850
|
+
* (`traces.enabled: true`); and an unset rate is wrangler's own default of 1.
|
|
851
|
+
* `logs.*` overrides the top-level switch and rate.
|
|
852
|
+
*/
|
|
853
|
+
declare const resolveObservabilitySampling: (block: WranglerObservability | undefined) => {
|
|
854
|
+
logs: ObservabilitySignalSampling;
|
|
855
|
+
traces: ObservabilitySignalSampling;
|
|
856
|
+
};
|
|
857
|
+
/** A wrangler `containers[]` entry (parsed from untrusted JSONC). */
|
|
858
|
+
interface WranglerContainerEntry {
|
|
859
|
+
class_name?: string;
|
|
860
|
+
image?: string;
|
|
861
|
+
/** Named images under the `durable_object` scheduling policy. */
|
|
862
|
+
images?: Record<string, {
|
|
863
|
+
build_context?: string;
|
|
864
|
+
build_vars?: Record<string, string>;
|
|
865
|
+
dockerfile?: string;
|
|
866
|
+
image?: string;
|
|
867
|
+
} | null | undefined>;
|
|
868
|
+
instance_type?: string | {
|
|
869
|
+
disk_mb?: number;
|
|
870
|
+
memory_mib?: number;
|
|
871
|
+
vcpu?: number;
|
|
872
|
+
};
|
|
873
|
+
max_instances?: number;
|
|
874
|
+
scheduling_policy?: string;
|
|
875
|
+
}
|
|
876
|
+
/**
|
|
877
|
+
* A wrangler `workflows[]` entry (parsed from untrusted JSONC). Unlike
|
|
878
|
+
* containers, workflows are NOT Durable Objects — the entry stands alone (no
|
|
879
|
+
* `durable_objects` binding, no migration class).
|
|
880
|
+
*/
|
|
881
|
+
interface WranglerWorkflowEntry {
|
|
882
|
+
binding?: string;
|
|
883
|
+
class_name?: string;
|
|
884
|
+
/** `{ success_retention?, error_retention? }` durations; shape-checked by `validateWorkflowSettings`. */
|
|
885
|
+
default_retention?: unknown;
|
|
886
|
+
/** `{ steps? }`; shape-checked by `validateWorkflowSettings`. */
|
|
887
|
+
limits?: unknown;
|
|
888
|
+
name?: string;
|
|
889
|
+
/** Cron strings that each start an instance; shape-checked by `validateWorkflowSettings`. */
|
|
890
|
+
schedules?: unknown;
|
|
891
|
+
/** Present when the class lives in ANOTHER Worker — then it is that script's to export. */
|
|
892
|
+
script_name?: string;
|
|
893
|
+
}
|
|
894
|
+
/** A wrangler `queues.producers[]` entry — a `Queue` binding sending to `queue`. */
|
|
895
|
+
interface WranglerQueueProducer {
|
|
896
|
+
binding?: string;
|
|
897
|
+
delivery_delay?: number;
|
|
898
|
+
queue?: string;
|
|
899
|
+
}
|
|
900
|
+
/** A wrangler `queues.consumers[]` entry — push (worker) or `type: "http_pull"`. */
|
|
901
|
+
interface WranglerQueueConsumer {
|
|
902
|
+
dead_letter_queue?: string;
|
|
903
|
+
max_batch_size?: number;
|
|
904
|
+
max_batch_timeout?: number;
|
|
905
|
+
max_concurrency?: number;
|
|
906
|
+
max_retries?: number;
|
|
907
|
+
queue?: string;
|
|
908
|
+
retry_delay?: number;
|
|
909
|
+
type?: string;
|
|
910
|
+
}
|
|
911
|
+
interface WranglerConfig {
|
|
912
|
+
account_id?: unknown;
|
|
913
|
+
ai?: {
|
|
914
|
+
binding?: unknown;
|
|
915
|
+
} | null;
|
|
916
|
+
ai_search?: ReadonlyArray<{
|
|
917
|
+
binding?: string;
|
|
918
|
+
instance_name?: string;
|
|
919
|
+
remote?: boolean;
|
|
920
|
+
} | null | undefined>;
|
|
921
|
+
ai_search_namespaces?: ReadonlyArray<{
|
|
922
|
+
binding?: string;
|
|
923
|
+
namespace?: string;
|
|
924
|
+
remote?: boolean;
|
|
925
|
+
} | null | undefined>;
|
|
926
|
+
analytics?: {
|
|
927
|
+
binding?: unknown;
|
|
928
|
+
remote?: boolean;
|
|
929
|
+
} | null;
|
|
930
|
+
analytics_engine_datasets?: ReadonlyArray<{
|
|
931
|
+
binding?: string;
|
|
932
|
+
dataset?: string;
|
|
933
|
+
} | null | undefined>;
|
|
934
|
+
artifacts?: ReadonlyArray<{
|
|
935
|
+
binding?: string;
|
|
936
|
+
namespace?: string;
|
|
937
|
+
remote?: boolean;
|
|
938
|
+
} | null | undefined>;
|
|
939
|
+
assets?: {
|
|
940
|
+
binding?: string;
|
|
941
|
+
directory?: string;
|
|
942
|
+
html_handling?: string;
|
|
943
|
+
not_found_handling?: string;
|
|
944
|
+
};
|
|
945
|
+
browser?: {
|
|
946
|
+
binding?: string;
|
|
947
|
+
};
|
|
948
|
+
cache?: {
|
|
949
|
+
enabled?: boolean;
|
|
950
|
+
} | null;
|
|
951
|
+
compatibility_date?: string;
|
|
952
|
+
compatibility_flags?: ReadonlyArray<string>;
|
|
953
|
+
containers?: ReadonlyArray<WranglerContainerEntry | null | undefined>;
|
|
954
|
+
d1_databases?: ReadonlyArray<{
|
|
955
|
+
binding?: string;
|
|
956
|
+
database_id?: string;
|
|
957
|
+
database_name?: string;
|
|
958
|
+
migrations_dir?: string;
|
|
959
|
+
migrations_pattern?: string;
|
|
960
|
+
} | null | undefined>;
|
|
961
|
+
dispatch_namespaces?: ReadonlyArray<{
|
|
962
|
+
binding?: string;
|
|
963
|
+
namespace?: string;
|
|
964
|
+
outbound?: unknown;
|
|
965
|
+
} | null | undefined>;
|
|
966
|
+
durable_objects?: {
|
|
967
|
+
bindings?: ReadonlyArray<WranglerDurableObjectBinding>;
|
|
968
|
+
};
|
|
969
|
+
env?: Record<string, WranglerConfig>;
|
|
970
|
+
exports?: Record<string, {
|
|
971
|
+
cache?: {
|
|
972
|
+
enabled?: boolean;
|
|
973
|
+
} | null;
|
|
974
|
+
default_retention?: unknown;
|
|
975
|
+
limits?: unknown;
|
|
976
|
+
name?: unknown;
|
|
977
|
+
schedules?: unknown;
|
|
978
|
+
type?: string;
|
|
979
|
+
} | null> | null;
|
|
980
|
+
flagship?: ReadonlyArray<{
|
|
981
|
+
app_id?: string;
|
|
982
|
+
binding?: string;
|
|
983
|
+
} | null | undefined>;
|
|
984
|
+
hyperdrive?: ReadonlyArray<{
|
|
985
|
+
binding?: string;
|
|
986
|
+
id?: string;
|
|
987
|
+
localConnectionString?: string;
|
|
988
|
+
} | null | undefined>;
|
|
989
|
+
images?: {
|
|
990
|
+
binding?: string;
|
|
991
|
+
};
|
|
992
|
+
k2?: ReadonlyArray<unknown>;
|
|
993
|
+
kv_namespaces?: ReadonlyArray<{
|
|
994
|
+
binding?: string;
|
|
995
|
+
id?: string;
|
|
996
|
+
} | null | undefined>;
|
|
997
|
+
limits?: {
|
|
998
|
+
cpu_ms?: number;
|
|
999
|
+
};
|
|
1000
|
+
logpush?: boolean;
|
|
1001
|
+
main?: string;
|
|
1002
|
+
media?: {
|
|
1003
|
+
binding?: string;
|
|
1004
|
+
};
|
|
1005
|
+
migrations?: ReadonlyArray<{
|
|
1006
|
+
deleted_classes?: ReadonlyArray<string>;
|
|
1007
|
+
new_classes?: ReadonlyArray<string>;
|
|
1008
|
+
new_sqlite_classes?: ReadonlyArray<string>;
|
|
1009
|
+
renamed_classes?: ReadonlyArray<{
|
|
1010
|
+
from?: string;
|
|
1011
|
+
to?: string;
|
|
1012
|
+
} | null | undefined>;
|
|
1013
|
+
} | null | undefined>;
|
|
1014
|
+
mtls_certificates?: ReadonlyArray<{
|
|
1015
|
+
binding?: string;
|
|
1016
|
+
certificate_id?: string;
|
|
1017
|
+
} | null | undefined>;
|
|
1018
|
+
observability?: WranglerObservability;
|
|
1019
|
+
pipelines?: ReadonlyArray<{
|
|
1020
|
+
binding?: string;
|
|
1021
|
+
pipeline?: string;
|
|
1022
|
+
stream?: string;
|
|
1023
|
+
} | null | undefined>;
|
|
1024
|
+
placement?: {
|
|
1025
|
+
host?: string;
|
|
1026
|
+
hostname?: string;
|
|
1027
|
+
mode?: string;
|
|
1028
|
+
region?: string;
|
|
1029
|
+
};
|
|
1030
|
+
queues?: {
|
|
1031
|
+
consumers?: ReadonlyArray<WranglerQueueConsumer | null | undefined>;
|
|
1032
|
+
producers?: ReadonlyArray<WranglerQueueProducer | null | undefined>;
|
|
1033
|
+
};
|
|
1034
|
+
r2_buckets?: ReadonlyArray<{
|
|
1035
|
+
binding?: string;
|
|
1036
|
+
bucket_name?: string;
|
|
1037
|
+
jurisdiction?: string;
|
|
1038
|
+
} | null | undefined>;
|
|
1039
|
+
secrets?: {
|
|
1040
|
+
required?: unknown;
|
|
1041
|
+
} | null;
|
|
1042
|
+
secrets_store_secrets?: ReadonlyArray<{
|
|
1043
|
+
binding?: string;
|
|
1044
|
+
secret_name?: string;
|
|
1045
|
+
store_id?: string;
|
|
1046
|
+
} | null | undefined>;
|
|
1047
|
+
send_email?: ReadonlyArray<{
|
|
1048
|
+
allowed_destination_addresses?: ReadonlyArray<string>;
|
|
1049
|
+
destination_address?: string;
|
|
1050
|
+
name?: string;
|
|
1051
|
+
} | null | undefined>;
|
|
1052
|
+
services?: ReadonlyArray<{
|
|
1053
|
+
binding?: string;
|
|
1054
|
+
entrypoint?: string;
|
|
1055
|
+
environment?: string;
|
|
1056
|
+
service?: string;
|
|
1057
|
+
} | null | undefined>;
|
|
1058
|
+
stream?: {
|
|
1059
|
+
binding?: string;
|
|
1060
|
+
};
|
|
1061
|
+
tail_consumers?: ReadonlyArray<TailConsumer | null | undefined>;
|
|
1062
|
+
vars?: Record<string, unknown>;
|
|
1063
|
+
vectorize?: ReadonlyArray<{
|
|
1064
|
+
binding?: string;
|
|
1065
|
+
index_name?: string;
|
|
1066
|
+
} | null | undefined>;
|
|
1067
|
+
vpc_networks?: ReadonlyArray<{
|
|
1068
|
+
binding?: string;
|
|
1069
|
+
network_id?: string;
|
|
1070
|
+
remote?: boolean;
|
|
1071
|
+
tunnel_id?: string;
|
|
1072
|
+
} | null | undefined>;
|
|
1073
|
+
vpc_services?: ReadonlyArray<{
|
|
1074
|
+
binding?: string;
|
|
1075
|
+
remote?: boolean;
|
|
1076
|
+
service_id?: string;
|
|
1077
|
+
} | null | undefined>;
|
|
1078
|
+
workflows?: ReadonlyArray<WranglerWorkflowEntry | null | undefined>;
|
|
1079
|
+
}
|
|
1080
|
+
interface WranglerValidationReport {
|
|
1081
|
+
errors: string[];
|
|
1082
|
+
valid: boolean;
|
|
1083
|
+
warnings: string[];
|
|
1084
|
+
}
|
|
1085
|
+
/**
|
|
1086
|
+
* Return a new `WranglerConfig` with `consumer` present in `tail_consumers`,
|
|
1087
|
+
* wiring this Worker to forward its tail events (logs/exceptions) to another
|
|
1088
|
+
* Worker that fans them out to an external sink. Pure and idempotent: an
|
|
1089
|
+
* existing entry with the same `service` + `environment` is left untouched
|
|
1090
|
+
* rather than duplicated, so it is safe to call on every codegen/deploy.
|
|
1091
|
+
*/
|
|
1092
|
+
declare const withTailConsumer: (wrangler: WranglerConfig, consumer: TailConsumer) => WranglerConfig;
|
|
1093
|
+
/**
|
|
1094
|
+
* Single source of truth for "does this wrangler config enable Workers
|
|
1095
|
+
* Cache?" and "what compatibility_date does that require?".
|
|
1096
|
+
*
|
|
1097
|
+
* Before this module, `reconcile-compatibility-date.ts` (auto-bump) and
|
|
1098
|
+
* `wrangler-validator.ts` (validation) each carried their own
|
|
1099
|
+
* `WORKERS_CACHE_MIN_DATE` literal and their own top-level/`exports[]`
|
|
1100
|
+
* cache-enabled walk — two copies of the same fact that could silently drift
|
|
1101
|
+
* apart (a date bumped in one file without the other would either validate a
|
|
1102
|
+
* config the reconciler wouldn't produce, or vice versa).
|
|
1103
|
+
*/
|
|
1104
|
+
/** The `compatibility_date` Workers Cache (`cache.enabled: true`) requires. */
|
|
1105
|
+
declare const WORKERS_CACHE_MIN_DATE = "2026-05-01";
|
|
1106
|
+
/** The subset of a parsed `wrangler.jsonc` the cache-enabled check reads. */
|
|
1107
|
+
interface WranglerCacheShape {
|
|
1108
|
+
cache?: {
|
|
1109
|
+
enabled?: boolean;
|
|
1110
|
+
} | null;
|
|
1111
|
+
exports?: Record<string, {
|
|
1112
|
+
cache?: {
|
|
1113
|
+
enabled?: boolean;
|
|
1114
|
+
} | null;
|
|
1115
|
+
} | null> | null;
|
|
1116
|
+
}
|
|
1117
|
+
/**
|
|
1118
|
+
* Whether Workers Cache is enabled anywhere in a parsed wrangler config — the
|
|
1119
|
+
* top-level `cache.enabled` toggle, or a per-export override in
|
|
1120
|
+
* `exports[name].cache.enabled` (Workers can scope cache per named export).
|
|
1121
|
+
* `undefined`/`null` (an unparsed or absent config) is treated as disabled.
|
|
1122
|
+
*/
|
|
1123
|
+
declare const isCacheEnabled: (parsed: WranglerCacheShape | null | undefined) => boolean;
|
|
1124
|
+
interface WranglerCodegenInputs {
|
|
1125
|
+
/** Every well-formed `queues.producers[]` entry of the top level and each `env.<name>` block. */
|
|
1126
|
+
wranglerQueueProducers: WranglerQueueProducerIR[];
|
|
1127
|
+
/** Top-level `vars` entries that look like plaintext secrets. */
|
|
1128
|
+
wranglerVariables: WranglerVariableIR[];
|
|
1129
|
+
}
|
|
1130
|
+
/** Both inputs are empty when there is no wrangler config or it does not parse. */
|
|
1131
|
+
declare const wranglerCodegenInputs: (projectRoot: string) => WranglerCodegenInputs;
|
|
1132
|
+
interface WranglerEnvironmentMerge {
|
|
1133
|
+
/** Set when `environment` names no `env.<name>` block declared in the config — the caller should treat this as a hard validation failure. */
|
|
1134
|
+
error?: string;
|
|
1135
|
+
/** The env-scoped view: `wrangler` unchanged when `environment` is `undefined`, otherwise merged per {@link NON_INHERITABLE_KEYS} / {@link INHERITABLE_KEYS}. */
|
|
1136
|
+
merged: WranglerConfig;
|
|
1137
|
+
/**
|
|
1138
|
+
* Keys the env block overrides whose inheritance status this validator
|
|
1139
|
+
* cannot verify (not in either table above) — validated against the
|
|
1140
|
+
* TOP-LEVEL value only, per the "do not guess" rule; the override is
|
|
1141
|
+
* silently ignored for validation purposes. The caller logs this ONCE
|
|
1142
|
+
* (not per key) so an unusual `env.<name>` block doesn't spam warnings.
|
|
1143
|
+
*/
|
|
1144
|
+
unverifiedKeys: string[];
|
|
1145
|
+
}
|
|
1146
|
+
/**
|
|
1147
|
+
* Resolve the config view `wrangler deploy --env <environment>` will actually
|
|
1148
|
+
* use. Undefined `environment` returns `wrangler` unchanged — the top-level
|
|
1149
|
+
* config is what a plain `wrangler deploy` reads, same as today.
|
|
1150
|
+
*
|
|
1151
|
+
* Deliberately independent of any other merge in this module: called fresh
|
|
1152
|
+
* from the ORIGINAL `wrangler` each time (see both call sites), so there is
|
|
1153
|
+
* no risk of merging an already-merged config and silently losing the
|
|
1154
|
+
* top-level fallback a second merge pass would no longer have access to.
|
|
1155
|
+
*/
|
|
1156
|
+
declare const mergeWranglerEnvironment: (wrangler: WranglerConfig, environment: string | undefined) => WranglerEnvironmentMerge;
|
|
1157
|
+
/** Candidate wrangler config filenames, in the order every consumer probes them. */
|
|
1158
|
+
declare const WRANGLER_FILES: readonly ["wrangler.jsonc", "wrangler.json"];
|
|
1159
|
+
/** Locate the project's wrangler config, or `undefined` when none exists. */
|
|
1160
|
+
declare const findWranglerFile: (projectRoot: string) => string | undefined;
|
|
1161
|
+
interface ReadWranglerResult<T> {
|
|
1162
|
+
/** Parsed config, or `undefined` when the file was not valid JSONC. */
|
|
1163
|
+
parsed: T | undefined;
|
|
1164
|
+
/** Raw file text — needed for comment-preserving `modify`/`applyEdits`. */
|
|
1165
|
+
text: string;
|
|
1166
|
+
}
|
|
1167
|
+
/**
|
|
1168
|
+
* Read and JSONC-parse a wrangler config file. Returns the raw `text` (for
|
|
1169
|
+
* structural edits) alongside `parsed`, which is `undefined` when the file is
|
|
1170
|
+
* not valid JSONC or does not parse to an object. Allows trailing commas, as
|
|
1171
|
+
* wrangler does.
|
|
1172
|
+
*/
|
|
1173
|
+
declare const readWranglerJsonc: <T = unknown>(wranglerPath: string) => ReadWranglerResult<T>;
|
|
1174
|
+
interface WranglerProjectValidationOptions {
|
|
1175
|
+
/**
|
|
1176
|
+
* Cloudflare environment to validate against `env.<name>` in
|
|
1177
|
+
* wrangler.jsonc. See {@link mergeWranglerEnvironment} for which keys
|
|
1178
|
+
* inherit the top-level value vs must be redeclared per environment.
|
|
1179
|
+
* Omit to validate the top-level config only (unchanged default).
|
|
1180
|
+
*/
|
|
1181
|
+
environment?: string;
|
|
1182
|
+
projectRoot: string;
|
|
1183
|
+
schemaDir?: string;
|
|
1184
|
+
}
|
|
1185
|
+
interface WranglerProjectValidationResult {
|
|
1186
|
+
problems: ReadonlyArray<string>;
|
|
1187
|
+
report: WranglerValidationReport;
|
|
1188
|
+
wranglerPath: string | undefined;
|
|
1189
|
+
}
|
|
1190
|
+
/**
|
|
1191
|
+
* The phrase every unexported-class error carries.
|
|
1192
|
+
*
|
|
1193
|
+
* Exported because it is a CONTRACT, not prose: `lunora doctor` picks these
|
|
1194
|
+
* errors out of the report by substring to raise its own finding, and the
|
|
1195
|
+
* validator's report is a flat `string[]`. Until the report entries carry a
|
|
1196
|
+
* code, a copy-edit here would silently disable that check — so the copy-edit
|
|
1197
|
+
* has to go through this constant.
|
|
1198
|
+
*/
|
|
1199
|
+
declare const UNEXPORTED_CLASS_MARKER = "does not export it";
|
|
1200
|
+
/**
|
|
1201
|
+
* File-system aware variant: reads `wrangler.jsonc`/`wrangler.json` from
|
|
1202
|
+
* the given project root, discovers the schema (if any), and delegates to
|
|
1203
|
+
* `validateWranglerConfig`. Returns the legacy
|
|
1204
|
+
* `{ problems, wranglerPath }` shape plus the structured `report`.
|
|
1205
|
+
*/
|
|
1206
|
+
declare const validateWranglerProject: (options: WranglerProjectValidationOptions) => WranglerProjectValidationResult;
|
|
1207
|
+
/**
|
|
1208
|
+
* Pure scan of a `vars` map for plaintext secrets — the FS-free core, exported for
|
|
1209
|
+
* unit tests. A variable is flagged when, for a **string** value that is neither a
|
|
1210
|
+
* placeholder nor a public/publishable key, EITHER the value matches a known
|
|
1211
|
+
* secret shape (`secretKindOf`) OR the key name strongly implies a secret and the
|
|
1212
|
+
* value is long enough to plausibly be one. `kind` is the matched shape, or
|
|
1213
|
+
* `secret_named_var` for the key-name path.
|
|
1214
|
+
*/
|
|
1215
|
+
declare const scanWranglerVariablesForSecrets: (variables: Record<string, unknown> | undefined, file: string) => WranglerVariableIR[];
|
|
1216
|
+
declare const REQUIRED_COMPATIBILITY_DATE: string;
|
|
1217
|
+
declare const REQUIRED_FLAG: string;
|
|
1218
|
+
/**
|
|
1219
|
+
* Pure validator: given a parsed `WranglerConfig` object and an optional
|
|
1220
|
+
* `SchemaInfo`, produce a structured report. Performs no I/O.
|
|
1221
|
+
*
|
|
1222
|
+
* `environment`, when set, validates the `env.<environment>` view
|
|
1223
|
+
* ({@link mergeWranglerEnvironment}) instead of the top-level config — e.g. a
|
|
1224
|
+
* `durable_objects` binding present only at the top level is a validation
|
|
1225
|
+
* FAILURE for `--env production` if `env.production` doesn't repeat it,
|
|
1226
|
+
* because `durable_objects` is non-inheritable and wrangler will not carry it
|
|
1227
|
+
* over. Omit `environment` to validate the top level only (unchanged default).
|
|
1228
|
+
*/
|
|
1229
|
+
declare const validateWranglerConfig: (wranglerInput: WranglerConfig | undefined, schema?: SchemaInfo, environment?: string) => WranglerValidationReport;
|
|
1230
|
+
/**
|
|
1231
|
+
* Convenience alias matching the original task-spec signature
|
|
1232
|
+
* `validateWrangler(wranglerJson, schema)` returning
|
|
1233
|
+
* `{ valid, errors, warnings }`.
|
|
1234
|
+
*/
|
|
1235
|
+
declare const validateWrangler: typeof validateWranglerConfig;
|
|
1236
|
+
export { type AlchemyTranslation, type AssertWranglerOptions, BINDING_MANIFEST_VERSION, type BindingManifest, type BindingRequirement, CLOUDFLARE_CLI_CONFIG_WARNING_ENV, CLOUDFLARE_DRIVER, CLOUDFLARE_TOOLCHAIN_VERSIONS, type CloudflareCliConfigFinding, type CloudflareCredentialProbe, DEFAULT_OBSERVABILITY, type DevConfigKind, type ExportGap, GLOBAL_FETCH_STRICTLY_PUBLIC_FLAG, type ManifestConfigShape, type MaterializeDevOptions, type MaterializeDevResult, type ObservabilitySignalSampling, REMOTE_ELIGIBLE_KEYS, REQUIRED_COMPATIBILITY_DATE, REQUIRED_FLAG, type ReadWranglerResult, type ReconcileBindingsResult, type ReconcileCompatibilityDateResult, type ReconcileResult as ReconcileCronsResult, type ReconcileProject, type RemoteBindingPlan, type RemoteEnableInputs, type RemoteWranglerShape, type ServiceDevConfigs, type TailConsumer, UNEXPORTED_CLASS_MARKER, WORKERS_CACHE_MIN_DATE, WRANGLER_FILES, type WranglerCacheShape, type WranglerCodegenInputs, type WranglerConfig, type WranglerConfigShape, type WranglerContainerEntry, type WranglerEnvironmentMerge, type WranglerObservability, type WranglerObservabilityLogs, type WranglerObservabilityTraces, type WranglerProjectValidationOptions, type WranglerProjectValidationResult, type WranglerValidationReport, type WranglerWorkflowEntry,
|
|
1237
|
+
/**
|
|
1238
|
+
* `@lunora/config/cloudflare` — the wrangler layer.
|
|
1239
|
+
*
|
|
1240
|
+
* Everything here speaks `wrangler.jsonc`: validating it, reconciling inferred
|
|
1241
|
+
* bindings/crons/compatibility-date into it, resolving remote bindings, and the
|
|
1242
|
+
* `DeployDriver` that ties them together for `--target cloudflare`.
|
|
1243
|
+
*
|
|
1244
|
+
* Split out from the package root so `@lunora/config` itself stays
|
|
1245
|
+
* provider-neutral. The root keeps what any target needs — the `DeployDriver`
|
|
1246
|
+
* contract, the driver registry, project config and target resolution,
|
|
1247
|
+
* `.dev.vars` grammar, binding *inference* — while emission and validation,
|
|
1248
|
+
* which are wrangler-shaped by definition, live behind this subpath.
|
|
1249
|
+
* Plan 114 §5.3 (D6): a package carrying real provider code isolates it behind a
|
|
1250
|
+
* subpath rather than relocating wholesale.
|
|
1251
|
+
*/
|
|
1252
|
+
applyModify, assertWranglerSatisfiesSchema, buildBindingManifest, collectExportGaps, describePreservedCrons, describeWithheldWorkersAi, detectCloudflareCliConfig, findWranglerFile, hasCloudflareCredentials, injectRemoteFlags, isCacheEnabled, isRemoteEnvEnabled, materializeDevWranglerConfig, materializeServiceDevConfigs, mergeWranglerEnvironment, planRemoteBindings, readWranglerJsonc, reconcileBindingsSafely, reconcileWranglerBindings, reconcileWranglerCompatibilityDate, reconcileWranglerCrons, reconcileWranglerExtras, resolveObservabilitySampling, resolveRemoteEnabled, scanWranglerVariablesForSecrets, validateWrangler, validateWranglerConfig, validateWranglerProject, warnCloudflareCliConfigOnce, withTailConsumer, withheldWorkersAi, wranglerCodegenInputs, wranglerToAlchemy };
|