@lunora/config 1.0.0-alpha.196 → 1.0.0-alpha.197
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cloudflare/index.d.mts +71 -11
- package/dist/cloudflare/index.d.ts +71 -11
- package/dist/cloudflare/index.mjs +1 -1
- package/dist/packem_shared/collectExportGaps-Diin6M0h.mjs +1 -0
- package/dist/packem_shared/describePreservedCrons-Bp5s5u0M.mjs +4 -0
- package/package.json +5 -5
- package/dist/packem_shared/collectExportGaps-BtNtwL7x.mjs +0 -1
- package/dist/packem_shared/reconcileWranglerCrons-COMb6ICf.mjs +0 -1
|
@@ -310,28 +310,88 @@ interface ReconcileCompatibilityDateResult {
|
|
|
310
310
|
*/
|
|
311
311
|
declare const reconcileWranglerCompatibilityDate: (projectRoot: string) => ReconcileCompatibilityDateResult;
|
|
312
312
|
interface ReconcileResult {
|
|
313
|
-
/** `true` when `
|
|
313
|
+
/** `true` when the wrangler config's `triggers.crons` was rewritten. */
|
|
314
314
|
changed: boolean;
|
|
315
|
+
/**
|
|
316
|
+
* Entries left in `triggers.crons` that this reconciler did not generate and
|
|
317
|
+
* does not own — a hand-written `backupCron` trigger, or anything already
|
|
318
|
+
* there before ownership was first recorded. Non-empty means the array is
|
|
319
|
+
* NOT the codegen-derived set, which is the surprising half of what this
|
|
320
|
+
* does and the one thing worth printing.
|
|
321
|
+
*/
|
|
322
|
+
preserved: string[];
|
|
315
323
|
/** Human-readable reason when reconciliation was skipped (for logging). */
|
|
316
324
|
reason?: string;
|
|
325
|
+
/**
|
|
326
|
+
* Problems with the ownership record itself, for the caller to `warn`. A
|
|
327
|
+
* damaged `lunora.crons` is not fatal — the reconciler degrades to add-only
|
|
328
|
+
* — but the degradation is invisible: the generated cron it wrote last pass
|
|
329
|
+
* is reported back as hand-written and is then kept for good. Silence is
|
|
330
|
+
* what turns a merge conflict into a permanent orphan.
|
|
331
|
+
*/
|
|
332
|
+
warnings: string[];
|
|
317
333
|
/** Resolved wrangler path, or `undefined` when none was found. */
|
|
318
334
|
wranglerPath?: string;
|
|
319
335
|
}
|
|
320
336
|
/**
|
|
321
|
-
* Reconcile the codegen-derived cron schedules into the project's
|
|
322
|
-
*
|
|
323
|
-
*
|
|
337
|
+
* Reconcile the codegen-derived cron schedules into the project's wrangler
|
|
338
|
+
* config `triggers.crons` array, preserving comments and formatting via
|
|
339
|
+
* `jsonc-parser`'s structural edits.
|
|
340
|
+
*
|
|
341
|
+
* **This does not own the whole array.** Two runtime cron surfaces are invisible
|
|
342
|
+
* to codegen and are documented as needing a hand-written `triggers.crons` entry:
|
|
343
|
+
* `createWorker({ backupCron })` (the nightly NDJSON backup) and
|
|
344
|
+
* `createWorker({ crons })` (handlers keyed by expression). Replacing the array
|
|
345
|
+
* wholesale deleted both on the next `lunora deploy` or dev-server schema save,
|
|
346
|
+
* silently — the nightly backup simply stopped. So an entry this reconciler did
|
|
347
|
+
* not generate is the user's, is kept, and is reported in
|
|
348
|
+
* {@link ReconcileResult.preserved}.
|
|
324
349
|
*
|
|
325
|
-
*
|
|
326
|
-
*
|
|
327
|
-
*
|
|
328
|
-
*
|
|
350
|
+
* Ownership is recorded in the project's `package.json` under `lunora.crons`,
|
|
351
|
+
* which is why a REMOVED generated cron still gets cleared (it is in the record
|
|
352
|
+
* and no longer in `cronTriggers`) while a hand-written one never is. Three
|
|
353
|
+
* properties pick that location:
|
|
354
|
+
*
|
|
355
|
+
* COMMITTED, so it survives a fresh clone. Gitignored `.lunora/` state does not:
|
|
356
|
+
* a CI-only deploy finds none, and falling back to add-only there leaves a
|
|
357
|
+
* removed cron firing forever.
|
|
358
|
+
*
|
|
359
|
+
* VALID JSON, so `wrangler.json` — a supported config name — behaves exactly like
|
|
360
|
+
* `wrangler.jsonc`. A `//` marker inside the config does not: wrangler tolerates
|
|
361
|
+
* one in either (both go through its JSONC parser), but the project's own
|
|
362
|
+
* `JSON.parse`, its deploy wrapper and its editor's JSON schema validation all
|
|
363
|
+
* break the moment a `.json` grows a comment. Nor can the record be a plain key
|
|
364
|
+
* in the wrangler config — wrangler reports unknown fields ("Unexpected fields
|
|
365
|
+
* found in top-level field") on every command.
|
|
366
|
+
*
|
|
367
|
+
* READ AND WRITTEN AT ONE ADDRESS. A comment has to be found textually on the way
|
|
368
|
+
* in and positioned structurally on the way out, and those are not the same
|
|
369
|
+
* place: a stale duplicate higher in the file was read as the record and deleted
|
|
370
|
+
* the user's backup trigger.
|
|
371
|
+
*
|
|
372
|
+
* The wrangler config is rewritten only when an entry actually moves, so
|
|
373
|
+
* {@link ReconcileResult.changed} means what a `synced N cron trigger(s)` log
|
|
374
|
+
* claims it means.
|
|
375
|
+
*
|
|
376
|
+
* A project with nothing recorded yet — one predating this, or one with no
|
|
377
|
+
* manifest — treats every entry as the user's, which is the safe direction: a
|
|
378
|
+
* wrongly-kept trigger costs one no-op invocation, a wrongly-deleted one
|
|
379
|
+
* silently ends the backups. It becomes precise after a codegen run that still
|
|
380
|
+
* declares the cron; upgrading and deleting a cron in the same change records an
|
|
381
|
+
* empty set, and that orphan is then kept for good.
|
|
329
382
|
*
|
|
330
383
|
* This intentionally writes the SAME `triggers.crons` shape the
|
|
331
|
-
* `@lunora/config` validator accepts, so the wrangler validator never fights
|
|
332
|
-
*
|
|
384
|
+
* `@lunora/config` validator accepts, so the wrangler validator never fights the
|
|
385
|
+
* generated value.
|
|
333
386
|
*/
|
|
334
387
|
declare const reconcileWranglerCrons: (projectRoot: string, cronTriggers: ReadonlyArray<string>) => ReconcileResult;
|
|
388
|
+
/**
|
|
389
|
+
* The one log line worth printing for a reconcile that kept entries it does not
|
|
390
|
+
* own, or `undefined` when it owned the whole array. Lives here rather than in
|
|
391
|
+
* each caller because `lunora deploy` and the Vite plugin print it verbatim and
|
|
392
|
+
* had already drifted into two copies of the same sentence.
|
|
393
|
+
*/
|
|
394
|
+
declare const describePreservedCrons: (preserved: ReadonlyArray<string>) => string | undefined;
|
|
335
395
|
/**
|
|
336
396
|
* The wrangler config sections Lunora can safely flip to remote mode in dev,
|
|
337
397
|
* each with the human label used in logs and the structural `shape` the entry
|
|
@@ -875,4 +935,4 @@ type BindingRequirement, CLOUDFLARE_DRIVER, type ExportGap,
|
|
|
875
935
|
* Plan 114 §5.3 (D6): a package carrying real provider code isolates it behind a
|
|
876
936
|
* subpath rather than relocating wholesale.
|
|
877
937
|
*/
|
|
878
|
-
type ManifestConfigShape, 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 WranglerEnvironmentMerge, type WranglerProjectValidationOptions, type WranglerProjectValidationResult, type WranglerValidationReport, type WranglerWorkflowEntry, buildBindingManifest, collectExportGaps, collectWranglerSecretVariables, findWranglerFile, injectRemoteFlags, isCacheEnabled, isRemoteEnvEnabled, materializeRemoteWranglerConfig, mergeWranglerEnvironment, planRemoteBindings, readWranglerJsonc, reconcileWranglerBindings, reconcileWranglerCompatibilityDate, reconcileWranglerCrons, resolveRemoteEnabled, scanWranglerVariablesForSecrets, validateWrangler, validateWranglerConfig, validateWranglerProject, withTailConsumer, wranglerToAlchemy };
|
|
938
|
+
type ManifestConfigShape, 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 WranglerEnvironmentMerge, type WranglerProjectValidationOptions, type WranglerProjectValidationResult, type WranglerValidationReport, type WranglerWorkflowEntry, buildBindingManifest, collectExportGaps, collectWranglerSecretVariables, describePreservedCrons, findWranglerFile, injectRemoteFlags, isCacheEnabled, isRemoteEnvEnabled, materializeRemoteWranglerConfig, mergeWranglerEnvironment, planRemoteBindings, readWranglerJsonc, reconcileWranglerBindings, reconcileWranglerCompatibilityDate, reconcileWranglerCrons, resolveRemoteEnabled, scanWranglerVariablesForSecrets, validateWrangler, validateWranglerConfig, validateWranglerProject, withTailConsumer, wranglerToAlchemy };
|
|
@@ -310,28 +310,88 @@ interface ReconcileCompatibilityDateResult {
|
|
|
310
310
|
*/
|
|
311
311
|
declare const reconcileWranglerCompatibilityDate: (projectRoot: string) => ReconcileCompatibilityDateResult;
|
|
312
312
|
interface ReconcileResult {
|
|
313
|
-
/** `true` when `
|
|
313
|
+
/** `true` when the wrangler config's `triggers.crons` was rewritten. */
|
|
314
314
|
changed: boolean;
|
|
315
|
+
/**
|
|
316
|
+
* Entries left in `triggers.crons` that this reconciler did not generate and
|
|
317
|
+
* does not own — a hand-written `backupCron` trigger, or anything already
|
|
318
|
+
* there before ownership was first recorded. Non-empty means the array is
|
|
319
|
+
* NOT the codegen-derived set, which is the surprising half of what this
|
|
320
|
+
* does and the one thing worth printing.
|
|
321
|
+
*/
|
|
322
|
+
preserved: string[];
|
|
315
323
|
/** Human-readable reason when reconciliation was skipped (for logging). */
|
|
316
324
|
reason?: string;
|
|
325
|
+
/**
|
|
326
|
+
* Problems with the ownership record itself, for the caller to `warn`. A
|
|
327
|
+
* damaged `lunora.crons` is not fatal — the reconciler degrades to add-only
|
|
328
|
+
* — but the degradation is invisible: the generated cron it wrote last pass
|
|
329
|
+
* is reported back as hand-written and is then kept for good. Silence is
|
|
330
|
+
* what turns a merge conflict into a permanent orphan.
|
|
331
|
+
*/
|
|
332
|
+
warnings: string[];
|
|
317
333
|
/** Resolved wrangler path, or `undefined` when none was found. */
|
|
318
334
|
wranglerPath?: string;
|
|
319
335
|
}
|
|
320
336
|
/**
|
|
321
|
-
* Reconcile the codegen-derived cron schedules into the project's
|
|
322
|
-
*
|
|
323
|
-
*
|
|
337
|
+
* Reconcile the codegen-derived cron schedules into the project's wrangler
|
|
338
|
+
* config `triggers.crons` array, preserving comments and formatting via
|
|
339
|
+
* `jsonc-parser`'s structural edits.
|
|
340
|
+
*
|
|
341
|
+
* **This does not own the whole array.** Two runtime cron surfaces are invisible
|
|
342
|
+
* to codegen and are documented as needing a hand-written `triggers.crons` entry:
|
|
343
|
+
* `createWorker({ backupCron })` (the nightly NDJSON backup) and
|
|
344
|
+
* `createWorker({ crons })` (handlers keyed by expression). Replacing the array
|
|
345
|
+
* wholesale deleted both on the next `lunora deploy` or dev-server schema save,
|
|
346
|
+
* silently — the nightly backup simply stopped. So an entry this reconciler did
|
|
347
|
+
* not generate is the user's, is kept, and is reported in
|
|
348
|
+
* {@link ReconcileResult.preserved}.
|
|
324
349
|
*
|
|
325
|
-
*
|
|
326
|
-
*
|
|
327
|
-
*
|
|
328
|
-
*
|
|
350
|
+
* Ownership is recorded in the project's `package.json` under `lunora.crons`,
|
|
351
|
+
* which is why a REMOVED generated cron still gets cleared (it is in the record
|
|
352
|
+
* and no longer in `cronTriggers`) while a hand-written one never is. Three
|
|
353
|
+
* properties pick that location:
|
|
354
|
+
*
|
|
355
|
+
* COMMITTED, so it survives a fresh clone. Gitignored `.lunora/` state does not:
|
|
356
|
+
* a CI-only deploy finds none, and falling back to add-only there leaves a
|
|
357
|
+
* removed cron firing forever.
|
|
358
|
+
*
|
|
359
|
+
* VALID JSON, so `wrangler.json` — a supported config name — behaves exactly like
|
|
360
|
+
* `wrangler.jsonc`. A `//` marker inside the config does not: wrangler tolerates
|
|
361
|
+
* one in either (both go through its JSONC parser), but the project's own
|
|
362
|
+
* `JSON.parse`, its deploy wrapper and its editor's JSON schema validation all
|
|
363
|
+
* break the moment a `.json` grows a comment. Nor can the record be a plain key
|
|
364
|
+
* in the wrangler config — wrangler reports unknown fields ("Unexpected fields
|
|
365
|
+
* found in top-level field") on every command.
|
|
366
|
+
*
|
|
367
|
+
* READ AND WRITTEN AT ONE ADDRESS. A comment has to be found textually on the way
|
|
368
|
+
* in and positioned structurally on the way out, and those are not the same
|
|
369
|
+
* place: a stale duplicate higher in the file was read as the record and deleted
|
|
370
|
+
* the user's backup trigger.
|
|
371
|
+
*
|
|
372
|
+
* The wrangler config is rewritten only when an entry actually moves, so
|
|
373
|
+
* {@link ReconcileResult.changed} means what a `synced N cron trigger(s)` log
|
|
374
|
+
* claims it means.
|
|
375
|
+
*
|
|
376
|
+
* A project with nothing recorded yet — one predating this, or one with no
|
|
377
|
+
* manifest — treats every entry as the user's, which is the safe direction: a
|
|
378
|
+
* wrongly-kept trigger costs one no-op invocation, a wrongly-deleted one
|
|
379
|
+
* silently ends the backups. It becomes precise after a codegen run that still
|
|
380
|
+
* declares the cron; upgrading and deleting a cron in the same change records an
|
|
381
|
+
* empty set, and that orphan is then kept for good.
|
|
329
382
|
*
|
|
330
383
|
* This intentionally writes the SAME `triggers.crons` shape the
|
|
331
|
-
* `@lunora/config` validator accepts, so the wrangler validator never fights
|
|
332
|
-
*
|
|
384
|
+
* `@lunora/config` validator accepts, so the wrangler validator never fights the
|
|
385
|
+
* generated value.
|
|
333
386
|
*/
|
|
334
387
|
declare const reconcileWranglerCrons: (projectRoot: string, cronTriggers: ReadonlyArray<string>) => ReconcileResult;
|
|
388
|
+
/**
|
|
389
|
+
* The one log line worth printing for a reconcile that kept entries it does not
|
|
390
|
+
* own, or `undefined` when it owned the whole array. Lives here rather than in
|
|
391
|
+
* each caller because `lunora deploy` and the Vite plugin print it verbatim and
|
|
392
|
+
* had already drifted into two copies of the same sentence.
|
|
393
|
+
*/
|
|
394
|
+
declare const describePreservedCrons: (preserved: ReadonlyArray<string>) => string | undefined;
|
|
335
395
|
/**
|
|
336
396
|
* The wrangler config sections Lunora can safely flip to remote mode in dev,
|
|
337
397
|
* each with the human label used in logs and the structural `shape` the entry
|
|
@@ -875,4 +935,4 @@ type BindingRequirement, CLOUDFLARE_DRIVER, type ExportGap,
|
|
|
875
935
|
* Plan 114 §5.3 (D6): a package carrying real provider code isolates it behind a
|
|
876
936
|
* subpath rather than relocating wholesale.
|
|
877
937
|
*/
|
|
878
|
-
type ManifestConfigShape, 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 WranglerEnvironmentMerge, type WranglerProjectValidationOptions, type WranglerProjectValidationResult, type WranglerValidationReport, type WranglerWorkflowEntry, buildBindingManifest, collectExportGaps, collectWranglerSecretVariables, findWranglerFile, injectRemoteFlags, isCacheEnabled, isRemoteEnvEnabled, materializeRemoteWranglerConfig, mergeWranglerEnvironment, planRemoteBindings, readWranglerJsonc, reconcileWranglerBindings, reconcileWranglerCompatibilityDate, reconcileWranglerCrons, resolveRemoteEnabled, scanWranglerVariablesForSecrets, validateWrangler, validateWranglerConfig, validateWranglerProject, withTailConsumer, wranglerToAlchemy };
|
|
938
|
+
type ManifestConfigShape, 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 WranglerEnvironmentMerge, type WranglerProjectValidationOptions, type WranglerProjectValidationResult, type WranglerValidationReport, type WranglerWorkflowEntry, buildBindingManifest, collectExportGaps, collectWranglerSecretVariables, describePreservedCrons, findWranglerFile, injectRemoteFlags, isCacheEnabled, isRemoteEnvEnabled, materializeRemoteWranglerConfig, mergeWranglerEnvironment, planRemoteBindings, readWranglerJsonc, reconcileWranglerBindings, reconcileWranglerCompatibilityDate, reconcileWranglerCrons, resolveRemoteEnabled, scanWranglerVariablesForSecrets, validateWrangler, validateWranglerConfig, validateWranglerProject, withTailConsumer, wranglerToAlchemy };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{BINDING_MANIFEST_VERSION as o,buildBindingManifest as a}from"../packem_shared/BINDING_MANIFEST_VERSION-B8dwEKLn.mjs";import{default as l}from"../packem_shared/CLOUDFLARE_DRIVER-Ci9oJMYb.mjs";import{collectExportGaps as i,reconcileWranglerBindings as E}from"../packem_shared/collectExportGaps-
|
|
1
|
+
import{BINDING_MANIFEST_VERSION as o,buildBindingManifest as a}from"../packem_shared/BINDING_MANIFEST_VERSION-B8dwEKLn.mjs";import{default as l}from"../packem_shared/CLOUDFLARE_DRIVER-Ci9oJMYb.mjs";import{collectExportGaps as i,reconcileWranglerBindings as E}from"../packem_shared/collectExportGaps-Diin6M0h.mjs";import{reconcileWranglerCompatibilityDate as g}from"../packem_shared/reconcileWranglerCompatibilityDate-7OO_xaKR.mjs";import{describePreservedCrons as s,reconcileWranglerCrons as R}from"../packem_shared/describePreservedCrons-Bp5s5u0M.mjs";import{REMOTE_ELIGIBLE_KEYS as d,injectRemoteFlags as p,isRemoteEnvEnabled as I,materializeRemoteWranglerConfig as W,planRemoteBindings as x,resolveRemoteEnabled as _}from"../packem_shared/REMOTE_ELIGIBLE_KEYS-D-edJjVY.mjs";import{WORKERS_CACHE_MIN_DATE as A,isCacheEnabled as b}from"../packem_shared/WORKERS_CACHE_MIN_DATE-0k9ABJtF.mjs";import{WRANGLER_FILES as L,findWranglerFile as T,readWranglerJsonc as v}from"../packem_shared/WRANGLER_FILES-UNW-xY5u.mjs";import{collectWranglerSecretVariables as S,scanWranglerVariablesForSecrets as B}from"../packem_shared/collectWranglerSecretVariables-D-usPfT8.mjs";import{wranglerToAlchemy as G}from"../packem_shared/wranglerToAlchemy-SDoS_XY0.mjs";import{REQUIRED_COMPATIBILITY_DATE as O,REQUIRED_FLAG as V,mergeWranglerEnvironment as h,validateWrangler as u,validateWranglerConfig as P,validateWranglerProject as U,withTailConsumer as j}from"../packem_shared/REQUIRED_COMPATIBILITY_DATE-vJI8hq20.mjs";export{o as BINDING_MANIFEST_VERSION,l as CLOUDFLARE_DRIVER,d as REMOTE_ELIGIBLE_KEYS,O as REQUIRED_COMPATIBILITY_DATE,V as REQUIRED_FLAG,A as WORKERS_CACHE_MIN_DATE,L as WRANGLER_FILES,a as buildBindingManifest,i as collectExportGaps,S as collectWranglerSecretVariables,s as describePreservedCrons,T as findWranglerFile,p as injectRemoteFlags,b as isCacheEnabled,I as isRemoteEnvEnabled,W as materializeRemoteWranglerConfig,h as mergeWranglerEnvironment,x as planRemoteBindings,v as readWranglerJsonc,E as reconcileWranglerBindings,g as reconcileWranglerCompatibilityDate,R as reconcileWranglerCrons,_ as resolveRemoteEnabled,B as scanWranglerVariablesForSecrets,u as validateWrangler,P as validateWranglerConfig,U as validateWranglerProject,j as withTailConsumer,G as wranglerToAlchemy};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{writeFileSync as B,readFileSync as C}from"node:fs";import{join as A}from"node:path";import{containerBuildTag as P}from"@lunora/container";import{DEV_VARS_FILE as O,parseDevVariableEntries as I}from"./DEV_VARS_EXAMPLE_FILE-CqLorAxT.mjs";import{a as b}from"./jsonc-edit-BZgQIdAH.mjs";import{findWranglerFile as $,readWranglerJsonc as R}from"./WRANGLER_FILES-UNW-xY5u.mjs";import{objectBindingEntries as S,stringEntries as v}from"./REQUIRED_COMPATIBILITY_DATE-vJI8hq20.mjs";const k="<replace-with-d1-create-id>",M=e=>[["container","containers",e.containers],["workflow","workflows",e.workflows],["agent","agents",e.agents]].flatMap(([s,t,i])=>i.filter(a=>!a.exported).map(({className:a,exportName:c})=>({className:a,exportName:c,kind:s,module:t}))),w="PIPELINES",T=(e,n)=>{const s=e.flagshipBinding!==void 0&&!(n?.flagship??[]).some(a=>a.binding===e.flagshipBinding),t=e.usesPipelines&&!(n?.pipelines??[]).some(a=>a.binding===w);return[[e.usesKv&&(n?.kv_namespaces?.length??0)===0,"@lunora/bindings/kv is used but no kv_namespaces binding exists; add a kv_namespaces entry ({ binding, id }) and pass env.<BINDING> to createKv() — the namespace id can't be auto-provisioned."],[e.usesHyperdrive&&(n?.hyperdrive?.length??0)===0,"@lunora/hyperdrive is used but no hyperdrive binding exists; run 'wrangler hyperdrive create' and add a 'hyperdrive' binding ({ binding, id }) — the id can't be auto-provisioned."],[t,`ctx.pipelines is used but no "${w}" pipelines binding exists; run 'wrangler pipelines create <name>' and add a 'pipelines' binding ({ binding: "${w}", pipeline }) — codegen resolves this one name, and the pipeline resource can't be auto-provisioned.`],[s,`lunora/flags.ts uses Flagship in binding mode but no flagship binding "${e.flagshipBinding??""}" exists; add a flagship entry ({ binding: "${e.flagshipBinding??""}", app_id }) — the app_id can't be auto-provisioned.`]].filter(([a])=>a).map(([,a])=>a)},W=e=>[[e.usesX402Charge,"@lunora/x402/charge is used; set the recipient wallet address as a [vars] entry (the var name is your choice) and pass it to the charge config — the x402 facilitator settles USDC to that address."],[e.usesX402Pay,"@lunora/x402/pay is used (ActionCtx-only, spends real funds); add a secrets_store_secrets[] binding holding the agent wallet key (binding name == signer.secretName) and pair the pay rail with a spend policy — ctx.secrets reads a Secrets Store binding, not .dev.vars."]].filter(([s])=>s).map(([,s])=>s),_=(e,n,s)=>s.filter(t=>!t.exported).map(t=>`${e} "${t.exportName}" is declared but ${t.className} is not exported by the worker entry; add \`export * from "./lunora/_generated/${n}"\` so its binding can be provisioned.`),K=(e,n)=>{const s=new Set([...e.workflows,...e.agents].map(t=>t.className));return s.size===0?[]:(n.workflows??[]).flatMap(t=>{const i=t.class_name;return i===void 0||s.has(i)?[]:[`wrangler.jsonc declares workflows[] entry "${i}" but no defineWorkflow/defineAgent export generates that class — a leftover from a rename will fail the deploy (wrangler rejects a class_name the worker does not export). Remove it if it is not hand-wired.`]})},L=(e,n)=>{if(e.queues.length===0)return[];const s=new Set(e.queues.map(i=>i.name)),t=new Set(e.queues.map(i=>i.bindingName));return[...(n.queues?.consumers??[]).flatMap(i=>{const{queue:a}=i;return a===void 0||s.has(a)?[]:[`wrangler.jsonc subscribes queues.consumers[] to "${a}" but no defineQueue export declares that queue — a leftover from a rename keeps delivering batches this worker has no handler for (they retry to exhaustion, then drop or dead-letter). Remove it if it is not hand-wired.`]}),...(n.queues?.producers??[]).flatMap(i=>{const{binding:a}=i;return a===void 0||t.has(a)?[]:[`wrangler.jsonc declares queues.producers[] binding "${a}" but no defineQueue export declares it — a leftover from a rename. Remove it if it is not hand-wired.`]})]},j=(e,n)=>[...K(e,n),...L(e,n)],D=[{keys:["STRIPE_SECRET_KEY","STRIPE_WEBHOOK_SECRET"],label:"Stripe"},{keys:["POLAR_ACCESS_TOKEN","POLAR_WEBHOOK_SECRET"],label:"Polar"},{keys:["CREEM_API_KEY","CREEM_WEBHOOK_SECRET"],label:"Creem"},{keys:["AUTUMN_SECRET_KEY","AUTUMN_WEBHOOK_SECRET"],label:"Autumn"},{keys:["DODO_PAYMENTS_API_KEY","DODO_PAYMENTS_WEBHOOK_KEY"],label:"Dodo Payments"}],Y=()=>D.map(({keys:e,label:n})=>`${e[0]} + ${e[1]} (${n})`).join(" or "),q=e=>{let n;try{n=C(A(e,O),"utf8")}catch{return!1}const s=new Map(I(n).map(t=>[t.key,t.value]));return D.some(({keys:t})=>t.every(i=>(s.get(i)??"")!==""))},x=(e,n,s)=>{const t=new Set(e.durableObjects.map(d=>d.className)),i=[],a=(s?.r2_buckets?.length??0)>0,c=(s?.d1_databases?.some(d=>d.binding==="DB")??!1)||e.needsD1;return e.usesStorage&&!a&&i.push("@lunora/storage is used but R2 bucket bindings have user-defined names; add an r2_buckets entry and pass env.<BINDING> to createStorage()."),e.usesAuth&&!t.has("SessionDO")&&!c&&i.push("@lunora/auth is used but the worker entry exports no SessionDO; sessions are D1-backed, or export SessionDO to enable DO-backed sessions."),e.usesScheduler&&!t.has("SchedulerDO")&&i.push("@lunora/scheduler is used but the worker entry exports no SchedulerDO; export it so the SCHEDULER binding can be provisioned."),i.push(..._("container","containers",e.containers),..._("workflow","workflows",e.workflows),..._("agent","agents",e.agents)),e.containers.length>0&&s?.observability?.enabled===!1&&i.push("containers are declared but observability is explicitly disabled in wrangler.jsonc — container logs will not be captured."),e.usesPayment&&!q(n)&&i.push(`@lunora/payment is used; set one provider's secret pair in .dev.vars — ${Y()}.`),i.push(...W(e),...T(e,s)),s!==void 0&&i.push(...j(e,s)),i},H=e=>{const n=new Set(S(e).map(t=>t.tag));let s=1;for(;n.has(`v${String(s)}`);)s+=1;return`v${String(s)}`},F=e=>{const n=new Set;for(const s of S(e)){for(const t of v(s.deleted_classes))n.delete(t);for(const{from:t,to:i}of S(s.renamed_classes))t!==void 0&&n.delete(t),i!==void 0&&n.add(i);for(const t of[...v(s.new_classes),...v(s.new_sqlite_classes)])n.add(t)}return n},G=(e,n,s)=>{const t=n.durable_objects?.bindings??[],i=new Set(t.map(u=>u.name)),a=s.filter(u=>!i.has(u.binding));let c=e;const d=[];if(a.length>0){const u=[...t,...a.map(p=>({class_name:p.className,name:p.binding}))];c=b(c,["durable_objects","bindings"],u),d.push(...a.map(p=>`${p.binding}/${p.className}`))}const g=n.migrations??[],l=s.map(u=>u.className).filter(u=>!F(g).has(u));if(l.length>0){const u=[...g,{new_sqlite_classes:l,tag:H(g)}];c=b(c,["migrations"],u)}return{added:d,text:c}},Q=(e,n)=>{const s=n.d1_databases??[];if(s.some(a=>a.binding==="DB"))return{added:[],text:e};const t=typeof n.name=="string"&&n.name.length>0?n.name:"lunora",i=[...s,{binding:"DB",database_id:k,database_name:t}];return{added:["DB (D1)"],text:b(e,["d1_databases"],i)}},y=(e,n,s,t,i)=>{const a=n[s]?.binding;return typeof a=="string"&&a.length>0?{added:[],text:e}:{added:[i],text:b(e,[s],{binding:t})}},U=(e,n)=>(n.analytics_engine_datasets?.length??0)>0?{added:[],text:e}:{added:["ANALYTICS (Analytics Engine)"],text:b(e,["analytics_engine_datasets"],[{binding:"ANALYTICS",dataset:"ANALYTICS"}])},z=e=>{if(typeof e=="string")return e;const n={};return e.diskMb!==void 0&&(n.disk_mb=e.diskMb),e.memoryMib!==void 0&&(n.memory_mib=e.memoryMib),e.vcpu!==void 0&&(n.vcpu=e.vcpu),n},V=e=>e.image.kind==="dockerfile"?e.image.dockerfilePath:e.image.kind==="registry"?e.image.reference:P(e.exportName),X=e=>{const n={class_name:e.className,image:V(e)};return e.image.kind==="dockerfile"&&(n.image_build_context=e.image.buildContext),e.buildArgs!==void 0&&e.image.kind!=="registry"&&(n.image_vars=e.buildArgs),e.instanceType!==void 0&&(n.instance_type=z(e.instanceType)),e.maxInstances!==void 0&&(n.max_instances=e.maxInstances),e.name!==void 0&&(n.name=e.name),e.rollout?.stepPercentage!==void 0&&(n.rollout_step_percentage=e.rollout.stepPercentage),e.rollout?.gracePeriodSeconds!==void 0&&(n.rollout_active_grace_period=e.rollout.gracePeriodSeconds),n},J=(e,n,s)=>{const t=n.containers??[],i=new Set(t.map(d=>d.class_name)),a=s.filter(d=>!i.has(d.className));if(a.length===0)return{added:[],text:e};const c=b(e,["containers"],[...t,...a.map(d=>X(d))]);return{added:a.map(d=>`containers/${d.className}`),text:c}},Z=(e,n)=>{if(n.observability!==void 0)return{added:[],text:e};const s=b(e,["observability"],{enabled:!0,head_sampling_rate:1});return{added:["observability"],text:s}},N=e=>({binding:e.bindingName,class_name:e.className,name:e.name}),ee=(e,n,s,t=[])=>{const i=n.workflows??[],a=new Set(i.map(l=>l.class_name)),c=s.filter(l=>!a.has(l.className)),d=t.filter(l=>!a.has(l.className));if(c.length===0&&d.length===0)return{added:[],text:e};const g=b(e,["workflows"],[...i,...c.map(l=>N(l)),...d.map(l=>N(l))]);return{added:[...c.map(l=>`workflows/${l.className}`),...d.map(l=>`workflows/${l.className}`)],text:g}},ne=(e,n,s)=>{const t=n.queues??{},i=t.producers??[],a=t.consumers??[],c=new Set(i.map(r=>r.binding)),d=new Set(a.map(r=>r.queue)),g=s.filter(r=>!c.has(r.bindingName)),l=s.filter(r=>!d.has(r.name));if(g.length===0&&l.length===0)return{added:[],text:e};const u=[...i,...g.map(r=>({binding:r.bindingName,queue:r.name}))],p=[...a,...l.map(r=>{const m={queue:r.name};return r.mode==="pull"&&(m.type="http_pull"),r.tuning.maxBatchSize!==void 0&&(m.max_batch_size=r.tuning.maxBatchSize),r.tuning.maxBatchTimeout!==void 0&&(m.max_batch_timeout=r.tuning.maxBatchTimeout),r.tuning.maxRetries!==void 0&&(m.max_retries=r.tuning.maxRetries),r.tuning.deadLetterQueue!==void 0&&(m.dead_letter_queue=r.tuning.deadLetterQueue),r.tuning.retryDelay!==void 0&&(m.retry_delay=r.tuning.retryDelay),m})],h=b(e,["queues"],{consumers:p,producers:u});return{added:[...g.map(r=>`queues.producers/${r.bindingName}`),...l.map(r=>`queues.consumers/${r.name}`)],text:h}},le=(e,n,s)=>{const t=$(e),i=M(n);if(!t)return{added:[],changed:!1,exportGaps:i,reason:"wrangler.jsonc not found",warnings:x(n,e)};const{parsed:a,text:c}=R(t);if(a===void 0)return{added:[],changed:!1,exportGaps:i,reason:`failed to parse ${t} as JSONC`,warnings:x(n,e),wranglerPath:t};const d=x(n,e,a);if(s!==void 0){const o=a.env?.[s]!==void 0;d.push(o?`auto-provisioned bindings are written to the top level of wrangler.jsonc only — "env.${s}" has its own (non-inheritable) bindings and must be reconciled by hand; \`lunora deploy --env ${s}\` now validates them, so a gap here will be reported at deploy time.`:`--env "${s}" was requested but wrangler.jsonc declares no "env.${s}" block — auto-provisioned bindings are written to the top level only and will not apply to that environment.`)}const g=n.containers.filter(o=>o.exported),l=n.agents.filter(o=>o.exported&&o.voice===!0&&o.voiceBindingName!==void 0&&o.voiceClassName!==void 0),u=[...n.durableObjects,...g.map(o=>({binding:o.bindingName,className:o.className})),...l.map(o=>({binding:o.voiceBindingName,className:o.voiceClassName}))],p=n.workflows.filter(o=>o.exported),h=n.agents.filter(o=>o.exported),r=[{enabled:!0,run:o=>G(o,a,u)},{enabled:n.needsD1,run:o=>Q(o,a)},{enabled:n.usesAi,run:o=>y(o,a,"ai","AI","AI (Workers AI)")},{enabled:n.usesBrowser,run:o=>y(o,a,"browser","BROWSER","BROWSER (Browser Rendering)")},{enabled:n.usesImages,run:o=>y(o,a,"images","IMAGES","IMAGES (Cloudflare Images)")},{enabled:n.usesAnalytics,run:o=>U(o,a)},{enabled:!0,run:o=>Z(o,a)},{enabled:g.length>0,run:o=>J(o,a,g)},{enabled:p.length>0||h.length>0,run:o=>ee(o,a,p,h)},{enabled:n.queues.length>0,run:o=>ne(o,a,n.queues)}];let m=c;const f=[];for(const o of r){if(!o.enabled)continue;const E=o.run(m);m=E.text,f.push(...E.added)}return f.includes("DB (D1)")&&d.push(`wrote a DB binding with a placeholder database_id ("${k}") — run \`wrangler d1 create <name>\` and replace it before deploying.`),m===c?{added:[],changed:!1,exportGaps:i,reason:"bindings already in sync",warnings:d,wranglerPath:t}:(B(t,m,"utf8"),{added:f,changed:!0,exportGaps:i,warnings:d,wranglerPath:t})};export{M as collectExportGaps,le as reconcileWranglerBindings};
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import{writeFileSync as p,existsSync as x,readFileSync as j}from"node:fs";import{modify as f,applyEdits as y}from"jsonc-parser";import{findWranglerFile as S,readWranglerJsonc as b}from"./WRANGLER_FILES-UNW-xY5u.mjs";import{join as m}from"node:path";const F=(r,e)=>r.length===e.length&&r.every((n,t)=>n===e[t]),O=/^([\t ]+)"/mu,w=r=>{const e=O.exec(r)?.[1]??" ";return{eol:r.includes(`\r
|
|
2
|
+
`)?`\r
|
|
3
|
+
`:`
|
|
4
|
+
`,insertSpaces:!e.startsWith(" "),tabSize:e.length}},$=r=>{const e=m(r,"package.json");if(x(e))try{const n=j(e,"utf8"),{lunora:t}=JSON.parse(n),o=typeof t=="object"&&t!==null&&!Array.isArray(t);return{lunora:o?t:void 0,lunoraIsForeign:t!==void 0&&!o,path:e,text:n}}catch{return}},k=(r,e)=>{if(r?.lunoraIsForeign===!0)return e.push(`${r.path}: \`lunora\` is not an object, so the cron ownership record cannot be read or written — a removed cron will keep firing.`),[];const n=r?.lunora?.crons;if(n===void 0)return[];if(!Array.isArray(n))return e.push(`${r?.path??"package.json"}: \`lunora.crons\` is not an array of cron expressions — the crons it recorded are now treated as hand-written and will not be cleared.`),[];const t=n.filter(o=>typeof o=="string");return t.length!==n.length&&e.push(`${r?.path??"package.json"}: \`lunora.crons\` dropped ${String(n.length-t.length)} non-string entry(s) — anything it recorded there is now treated as hand-written and will not be cleared.`),t},A=(r,e)=>{const n=e.length===0,t=Object.keys(r.lunora??{}).every(a=>a==="crons");if(r.lunoraIsForeign)return;const o=n&&t?["lunora"]:["lunora","crons"],i=f(r.text,o,n?void 0:[...e],{formattingOptions:w(r.text)});if(i.length===0)return;const s=y(r.text,i);s!==r.text&&p(r.path,s,"utf8")},J=(r,e)=>{const n=S(r);if(!n)return{changed:!1,preserved:[],reason:"wrangler.jsonc not found",warnings:[]};const{parsed:t,text:o}=b(n);if(t===void 0)return{changed:!1,preserved:[],reason:`failed to parse ${n} as JSONC`,warnings:[],wranglerPath:n};const i=Array.isArray(t.triggers?.crons)?t.triggers.crons.filter(d=>typeof d=="string"):[],s=[...e],a=[],l=$(r),v=k(l,a),c=i.filter(d=>!s.includes(d)&&!v.includes(d)),g=[...s,...c],u=()=>{l!==void 0&&A(l,s)};if(F(i,g))return u(),{changed:!1,preserved:c,reason:"triggers.crons already in sync",warnings:a,wranglerPath:n};const h=f(o,["triggers","crons"],g,{formattingOptions:w(o)});return h.length===0?{changed:!1,preserved:c,reason:"no structural edit produced",warnings:a,wranglerPath:n}:(p(n,y(o,h),"utf8"),u(),{changed:!0,preserved:c,warnings:a,wranglerPath:n})},M=r=>r.length===0?void 0:`kept ${String(r.length)} hand-written cron trigger(s): ${r.join(", ")}`;export{M as describePreservedCrons,J as reconcileWranglerCrons};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lunora/config",
|
|
3
|
-
"version": "1.0.0-alpha.
|
|
3
|
+
"version": "1.0.0-alpha.197",
|
|
4
4
|
"description": "Internal shared CLI + Vite config layer for Lunora: wrangler.jsonc validation, binding inference, and .dev.vars scaffolding",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"bindings",
|
|
@@ -54,10 +54,10 @@
|
|
|
54
54
|
"access": "public"
|
|
55
55
|
},
|
|
56
56
|
"dependencies": {
|
|
57
|
-
"@lunora/codegen": "1.0.0-alpha.
|
|
58
|
-
"@lunora/container": "1.0.0-alpha.
|
|
59
|
-
"@lunora/errors": "1.0.0-alpha.
|
|
60
|
-
"@lunora/seed": "1.0.0-alpha.
|
|
57
|
+
"@lunora/codegen": "1.0.0-alpha.161",
|
|
58
|
+
"@lunora/container": "1.0.0-alpha.47",
|
|
59
|
+
"@lunora/errors": "1.0.0-alpha.34",
|
|
60
|
+
"@lunora/seed": "1.0.0-alpha.111",
|
|
61
61
|
"@visulima/colorize": "2.1.1",
|
|
62
62
|
"@visulima/find-ai-runner": "1.0.1",
|
|
63
63
|
"@visulima/package": "5.0.12",
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{writeFileSync as B,readFileSync as C}from"node:fs";import{join as A}from"node:path";import{containerBuildTag as P}from"@lunora/container";import{DEV_VARS_FILE as O,parseDevVariableEntries as I}from"./DEV_VARS_EXAMPLE_FILE-CqLorAxT.mjs";import{a as b}from"./jsonc-edit-BZgQIdAH.mjs";import{findWranglerFile as $,readWranglerJsonc as R}from"./WRANGLER_FILES-UNW-xY5u.mjs";import{objectBindingEntries as E,stringEntries as v}from"./REQUIRED_COMPATIBILITY_DATE-vJI8hq20.mjs";const k="<replace-with-d1-create-id>",T=e=>[["container","containers",e.containers],["workflow","workflows",e.workflows],["agent","agents",e.agents]].flatMap(([n,t,o])=>o.filter(a=>!a.exported).map(({className:a,exportName:c})=>({className:a,exportName:c,kind:n,module:t}))),_="PIPELINES",M=(e,s)=>{const n=e.flagshipBinding!==void 0&&!(s?.flagship??[]).some(a=>a.binding===e.flagshipBinding),t=e.usesPipelines&&!(s?.pipelines??[]).some(a=>a.binding===_);return[[e.usesKv&&(s?.kv_namespaces?.length??0)===0,"@lunora/bindings/kv is used but no kv_namespaces binding exists; add a kv_namespaces entry ({ binding, id }) and pass env.<BINDING> to createKv() — the namespace id can't be auto-provisioned."],[e.usesHyperdrive&&(s?.hyperdrive?.length??0)===0,"@lunora/hyperdrive is used but no hyperdrive binding exists; run 'wrangler hyperdrive create' and add a 'hyperdrive' binding ({ binding, id }) — the id can't be auto-provisioned."],[t,`ctx.pipelines is used but no "${_}" pipelines binding exists; run 'wrangler pipelines create <name>' and add a 'pipelines' binding ({ binding: "${_}", pipeline }) — codegen resolves this one name, and the pipeline resource can't be auto-provisioned.`],[n,`lunora/flags.ts uses Flagship in binding mode but no flagship binding "${e.flagshipBinding??""}" exists; add a flagship entry ({ binding: "${e.flagshipBinding??""}", app_id }) — the app_id can't be auto-provisioned.`]].filter(([a])=>a).map(([,a])=>a)},W=e=>[[e.usesX402Charge,"@lunora/x402/charge is used; set the recipient wallet address as a [vars] entry (the var name is your choice) and pass it to the charge config — the x402 facilitator settles USDC to that address."],[e.usesX402Pay,"@lunora/x402/pay is used (ActionCtx-only, spends real funds); add a secrets_store_secrets[] binding holding the agent wallet key (binding name == signer.secretName) and pair the pay rail with a spend policy — ctx.secrets reads a Secrets Store binding, not .dev.vars."]].filter(([n])=>n).map(([,n])=>n),x=(e,s,n)=>n.filter(t=>!t.exported).map(t=>`${e} "${t.exportName}" is declared but ${t.className} is not exported by the worker entry; add \`export * from "./lunora/_generated/${s}"\` so its binding can be provisioned.`),D=[{keys:["STRIPE_SECRET_KEY","STRIPE_WEBHOOK_SECRET"],label:"Stripe"},{keys:["POLAR_ACCESS_TOKEN","POLAR_WEBHOOK_SECRET"],label:"Polar"},{keys:["CREEM_API_KEY","CREEM_WEBHOOK_SECRET"],label:"Creem"},{keys:["AUTUMN_SECRET_KEY","AUTUMN_WEBHOOK_SECRET"],label:"Autumn"},{keys:["DODO_PAYMENTS_API_KEY","DODO_PAYMENTS_WEBHOOK_KEY"],label:"Dodo Payments"}],K=()=>D.map(({keys:e,label:s})=>`${e[0]} + ${e[1]} (${s})`).join(" or "),L=e=>{let s;try{s=C(A(e,O),"utf8")}catch{return!1}const n=new Map(I(s).map(t=>[t.key,t.value]));return D.some(({keys:t})=>t.every(o=>(n.get(o)??"")!==""))},y=(e,s,n)=>{const t=new Set(e.durableObjects.map(d=>d.className)),o=[],a=(n?.r2_buckets?.length??0)>0,c=(n?.d1_databases?.some(d=>d.binding==="DB")??!1)||e.needsD1;return e.usesStorage&&!a&&o.push("@lunora/storage is used but R2 bucket bindings have user-defined names; add an r2_buckets entry and pass env.<BINDING> to createStorage()."),e.usesAuth&&!t.has("SessionDO")&&!c&&o.push("@lunora/auth is used but the worker entry exports no SessionDO; sessions are D1-backed, or export SessionDO to enable DO-backed sessions."),e.usesScheduler&&!t.has("SchedulerDO")&&o.push("@lunora/scheduler is used but the worker entry exports no SchedulerDO; export it so the SCHEDULER binding can be provisioned."),o.push(...x("container","containers",e.containers),...x("workflow","workflows",e.workflows),...x("agent","agents",e.agents)),e.containers.length>0&&n?.observability?.enabled===!1&&o.push("containers are declared but observability is explicitly disabled in wrangler.jsonc — container logs will not be captured."),e.usesPayment&&!L(s)&&o.push(`@lunora/payment is used; set one provider's secret pair in .dev.vars — ${K()}.`),o.push(...W(e),...M(e,n)),o},Y=e=>{const s=new Set(E(e).map(t=>t.tag));let n=1;for(;s.has(`v${String(n)}`);)n+=1;return`v${String(n)}`},H=e=>{const s=new Set;for(const n of E(e)){for(const t of v(n.deleted_classes))s.delete(t);for(const{from:t,to:o}of E(n.renamed_classes))t!==void 0&&s.delete(t),o!==void 0&&s.add(o);for(const t of[...v(n.new_classes),...v(n.new_sqlite_classes)])s.add(t)}return s},j=(e,s,n)=>{const t=s.durable_objects?.bindings??[],o=new Set(t.map(g=>g.name)),a=n.filter(g=>!o.has(g.binding));let c=e;const d=[];if(a.length>0){const g=[...t,...a.map(p=>({class_name:p.className,name:p.binding}))];c=b(c,["durable_objects","bindings"],g),d.push(...a.map(p=>`${p.binding}/${p.className}`))}const u=s.migrations??[],l=n.map(g=>g.className).filter(g=>!H(u).has(g));if(l.length>0){const g=[...u,{new_sqlite_classes:l,tag:Y(u)}];c=b(c,["migrations"],g)}return{added:d,text:c}},F=(e,s)=>{const n=s.d1_databases??[];if(n.some(a=>a.binding==="DB"))return{added:[],text:e};const t=typeof s.name=="string"&&s.name.length>0?s.name:"lunora",o=[...n,{binding:"DB",database_id:k,database_name:t}];return{added:["DB (D1)"],text:b(e,["d1_databases"],o)}},w=(e,s,n,t,o)=>{const a=s[n]?.binding;return typeof a=="string"&&a.length>0?{added:[],text:e}:{added:[o],text:b(e,[n],{binding:t})}},G=(e,s)=>(s.analytics_engine_datasets?.length??0)>0?{added:[],text:e}:{added:["ANALYTICS (Analytics Engine)"],text:b(e,["analytics_engine_datasets"],[{binding:"ANALYTICS",dataset:"ANALYTICS"}])},U=e=>{if(typeof e=="string")return e;const s={};return e.diskMb!==void 0&&(s.disk_mb=e.diskMb),e.memoryMib!==void 0&&(s.memory_mib=e.memoryMib),e.vcpu!==void 0&&(s.vcpu=e.vcpu),s},V=e=>e.image.kind==="dockerfile"?e.image.dockerfilePath:e.image.kind==="registry"?e.image.reference:P(e.exportName),z=e=>{const s={class_name:e.className,image:V(e)};return e.image.kind==="dockerfile"&&(s.image_build_context=e.image.buildContext),e.buildArgs!==void 0&&e.image.kind!=="registry"&&(s.image_vars=e.buildArgs),e.instanceType!==void 0&&(s.instance_type=U(e.instanceType)),e.maxInstances!==void 0&&(s.max_instances=e.maxInstances),e.name!==void 0&&(s.name=e.name),e.rollout?.stepPercentage!==void 0&&(s.rollout_step_percentage=e.rollout.stepPercentage),e.rollout?.gracePeriodSeconds!==void 0&&(s.rollout_active_grace_period=e.rollout.gracePeriodSeconds),s},Q=(e,s,n)=>{const t=s.containers??[],o=new Set(t.map(d=>d.class_name)),a=n.filter(d=>!o.has(d.className));if(a.length===0)return{added:[],text:e};const c=b(e,["containers"],[...t,...a.map(d=>z(d))]);return{added:a.map(d=>`containers/${d.className}`),text:c}},X=(e,s)=>{if(s.observability!==void 0)return{added:[],text:e};const n=b(e,["observability"],{enabled:!0,head_sampling_rate:1});return{added:["observability"],text:n}},N=e=>({binding:e.bindingName,class_name:e.className,name:e.name}),J=(e,s,n,t=[])=>{const o=s.workflows??[],a=new Set(o.map(l=>l.class_name)),c=n.filter(l=>!a.has(l.className)),d=t.filter(l=>!a.has(l.className));if(c.length===0&&d.length===0)return{added:[],text:e};const u=b(e,["workflows"],[...o,...c.map(l=>N(l)),...d.map(l=>N(l))]);return{added:[...c.map(l=>`workflows/${l.className}`),...d.map(l=>`workflows/${l.className}`)],text:u}},q=(e,s,n)=>{const t=s.queues??{},o=t.producers??[],a=t.consumers??[],c=new Set(o.map(r=>r.binding)),d=new Set(a.map(r=>r.queue)),u=n.filter(r=>!c.has(r.bindingName)),l=n.filter(r=>!d.has(r.name));if(u.length===0&&l.length===0)return{added:[],text:e};const g=[...o,...u.map(r=>({binding:r.bindingName,queue:r.name}))],p=[...a,...l.map(r=>{const m={queue:r.name};return r.mode==="pull"&&(m.type="http_pull"),r.tuning.maxBatchSize!==void 0&&(m.max_batch_size=r.tuning.maxBatchSize),r.tuning.maxBatchTimeout!==void 0&&(m.max_batch_timeout=r.tuning.maxBatchTimeout),r.tuning.maxRetries!==void 0&&(m.max_retries=r.tuning.maxRetries),r.tuning.deadLetterQueue!==void 0&&(m.dead_letter_queue=r.tuning.deadLetterQueue),r.tuning.retryDelay!==void 0&&(m.retry_delay=r.tuning.retryDelay),m})],h=b(e,["queues"],{consumers:p,producers:g});return{added:[...u.map(r=>`queues.producers/${r.bindingName}`),...l.map(r=>`queues.consumers/${r.name}`)],text:h}},oe=(e,s,n)=>{const t=$(e),o=T(s);if(!t)return{added:[],changed:!1,exportGaps:o,reason:"wrangler.jsonc not found",warnings:y(s,e)};const{parsed:a,text:c}=R(t);if(a===void 0)return{added:[],changed:!1,exportGaps:o,reason:`failed to parse ${t} as JSONC`,warnings:y(s,e),wranglerPath:t};const d=y(s,e,a);if(n!==void 0){const i=a.env?.[n]!==void 0;d.push(i?`auto-provisioned bindings are written to the top level of wrangler.jsonc only — "env.${n}" has its own (non-inheritable) bindings and must be reconciled by hand; \`lunora deploy --env ${n}\` now validates them, so a gap here will be reported at deploy time.`:`--env "${n}" was requested but wrangler.jsonc declares no "env.${n}" block — auto-provisioned bindings are written to the top level only and will not apply to that environment.`)}const u=s.containers.filter(i=>i.exported),l=s.agents.filter(i=>i.exported&&i.voice===!0&&i.voiceBindingName!==void 0&&i.voiceClassName!==void 0),g=[...s.durableObjects,...u.map(i=>({binding:i.bindingName,className:i.className})),...l.map(i=>({binding:i.voiceBindingName,className:i.voiceClassName}))],p=s.workflows.filter(i=>i.exported),h=s.agents.filter(i=>i.exported),r=[{enabled:!0,run:i=>j(i,a,g)},{enabled:s.needsD1,run:i=>F(i,a)},{enabled:s.usesAi,run:i=>w(i,a,"ai","AI","AI (Workers AI)")},{enabled:s.usesBrowser,run:i=>w(i,a,"browser","BROWSER","BROWSER (Browser Rendering)")},{enabled:s.usesImages,run:i=>w(i,a,"images","IMAGES","IMAGES (Cloudflare Images)")},{enabled:s.usesAnalytics,run:i=>G(i,a)},{enabled:!0,run:i=>X(i,a)},{enabled:u.length>0,run:i=>Q(i,a,u)},{enabled:p.length>0||h.length>0,run:i=>J(i,a,p,h)},{enabled:s.queues.length>0,run:i=>q(i,a,s.queues)}];let m=c;const f=[];for(const i of r){if(!i.enabled)continue;const S=i.run(m);m=S.text,f.push(...S.added)}return f.includes("DB (D1)")&&d.push(`wrote a DB binding with a placeholder database_id ("${k}") — run \`wrangler d1 create <name>\` and replace it before deploying.`),m===c?{added:[],changed:!1,exportGaps:o,reason:"bindings already in sync",warnings:d,wranglerPath:t}:(B(t,m,"utf8"),{added:f,changed:!0,exportGaps:o,warnings:d,wranglerPath:t})};export{T as collectExportGaps,oe as reconcileWranglerBindings};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{writeFileSync as g}from"node:fs";import{modify as c,applyEdits as l}from"jsonc-parser";import{findWranglerFile as f,readWranglerJsonc as d}from"./WRANGLER_FILES-UNW-xY5u.mjs";const p=(t,e)=>t.length===e.length&&t.every((r,n)=>r===e[n]),y=(t,e)=>{const r=f(t);if(!r)return{changed:!1,reason:"wrangler.jsonc not found"};const{parsed:n,text:s}=d(r);if(n===void 0)return{changed:!1,reason:`failed to parse ${r} as JSONC`,wranglerPath:r};const a=Array.isArray(n.triggers?.crons)?n.triggers.crons.filter(i=>typeof i=="string"):[];if(p(a,e))return{changed:!1,reason:"triggers.crons already in sync",wranglerPath:r};const o=c(s,["triggers","crons"],[...e],{formattingOptions:{insertSpaces:!0,tabSize:4}});return o.length===0?{changed:!1,reason:"no structural edit produced",wranglerPath:r}:(g(r,l(s,o),"utf8"),{changed:!0,wranglerPath:r})};export{y as reconcileWranglerCrons};
|