@lunora/config 1.0.0-alpha.253 → 1.0.0-alpha.255
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 +5 -3
- package/dist/cloudflare/index.d.ts +5 -3
- package/dist/cloudflare/index.mjs +1 -1
- package/dist/packem_shared/collectExportGaps-BJw9LdRV.mjs +2 -0
- package/dist/packem_shared/describePreservedCrons-Ci5r2aph.mjs +1 -0
- package/dist/packem_shared/lunora-manifest-V77OcyFC.mjs +6 -0
- package/package.json +3 -3
- package/dist/packem_shared/collectExportGaps-k35UGfxu.mjs +0 -1
- package/dist/packem_shared/describePreservedCrons-Bp5s5u0M.mjs +0 -4
|
@@ -286,9 +286,11 @@ declare const collectExportGaps: (inferred: InferredBindings) => ExportGap[];
|
|
|
286
286
|
* Writes only when something is missing; returns `changed: false` when the
|
|
287
287
|
* config already satisfies the inferred needs.
|
|
288
288
|
*
|
|
289
|
-
* `environment`, when passed, does NOT change where this
|
|
290
|
-
* below still only
|
|
291
|
-
* blocks have no auto-provisioning path today.
|
|
289
|
+
* `environment`, when passed, does NOT change where this provisions — every
|
|
290
|
+
* step below still only ADDS to the TOP-LEVEL config; wrangler's `env.<name>`
|
|
291
|
+
* blocks have no auto-provisioning path today. The one write into the block is
|
|
292
|
+
* {@link reconcileEnvQueues}, which retunes queue consumers the block already
|
|
293
|
+
* declares and adds nothing. Otherwise it is used only to emit an
|
|
292
294
|
* advisory warning, because bindings (`durable_objects`, `d1_databases`, …)
|
|
293
295
|
* are non-inheritable (see `wrangler-validator.ts`'s `NON_INHERITABLE_KEYS`):
|
|
294
296
|
* a `--env production` deploy needs its OWN copy of each one, and silently
|
|
@@ -286,9 +286,11 @@ declare const collectExportGaps: (inferred: InferredBindings) => ExportGap[];
|
|
|
286
286
|
* Writes only when something is missing; returns `changed: false` when the
|
|
287
287
|
* config already satisfies the inferred needs.
|
|
288
288
|
*
|
|
289
|
-
* `environment`, when passed, does NOT change where this
|
|
290
|
-
* below still only
|
|
291
|
-
* blocks have no auto-provisioning path today.
|
|
289
|
+
* `environment`, when passed, does NOT change where this provisions — every
|
|
290
|
+
* step below still only ADDS to the TOP-LEVEL config; wrangler's `env.<name>`
|
|
291
|
+
* blocks have no auto-provisioning path today. The one write into the block is
|
|
292
|
+
* {@link reconcileEnvQueues}, which retunes queue consumers the block already
|
|
293
|
+
* declares and adds nothing. Otherwise it is used only to emit an
|
|
292
294
|
* advisory warning, because bindings (`durable_objects`, `d1_databases`, …)
|
|
293
295
|
* are non-inheritable (see `wrangler-validator.ts`'s `NON_INHERITABLE_KEYS`):
|
|
294
296
|
* a `--env production` deploy needs its OWN copy of each one, and silently
|
|
@@ -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-BJw9LdRV.mjs";import{reconcileWranglerCompatibilityDate as R}from"../packem_shared/reconcileWranglerCompatibilityDate-7OO_xaKR.mjs";import{describePreservedCrons as c,reconcileWranglerCrons as s}from"../packem_shared/describePreservedCrons-Ci5r2aph.mjs";import{REMOTE_ELIGIBLE_KEYS as d,injectRemoteFlags as p,isRemoteEnvEnabled as I,materializeRemoteWranglerConfig as W,planRemoteBindings as _,resolveRemoteEnabled as x}from"../packem_shared/REMOTE_ELIGIBLE_KEYS-D-edJjVY.mjs";import{WORKERS_CACHE_MIN_DATE as A,isCacheEnabled as D}from"../packem_shared/WORKERS_CACHE_MIN_DATE-0k9ABJtF.mjs";import{WRANGLER_FILES as S,findWranglerFile as T,readWranglerJsonc as b}from"../packem_shared/WRANGLER_FILES-UNW-xY5u.mjs";import{collectWranglerSecretVariables as F,scanWranglerVariablesForSecrets as N}from"../packem_shared/collectWranglerSecretVariables-D-usPfT8.mjs";import{wranglerToAlchemy as M}from"../packem_shared/wranglerToAlchemy-SDoS_XY0.mjs";import{REQUIRED_COMPATIBILITY_DATE as G,REQUIRED_FLAG as P,UNEXPORTED_CLASS_MARKER as U,mergeWranglerEnvironment as V,validateWrangler as h,validateWranglerConfig as u,validateWranglerProject as K,withTailConsumer as j}from"../packem_shared/REQUIRED_COMPATIBILITY_DATE-SdRHaUwh.mjs";export{o as BINDING_MANIFEST_VERSION,l as CLOUDFLARE_DRIVER,d as REMOTE_ELIGIBLE_KEYS,G as REQUIRED_COMPATIBILITY_DATE,P as REQUIRED_FLAG,U as UNEXPORTED_CLASS_MARKER,A as WORKERS_CACHE_MIN_DATE,S as WRANGLER_FILES,a as buildBindingManifest,i as collectExportGaps,F as collectWranglerSecretVariables,c as describePreservedCrons,T as findWranglerFile,p as injectRemoteFlags,D as isCacheEnabled,I as isRemoteEnvEnabled,W as materializeRemoteWranglerConfig,V as mergeWranglerEnvironment,_ as planRemoteBindings,b as readWranglerJsonc,E as reconcileWranglerBindings,R as reconcileWranglerCompatibilityDate,s as reconcileWranglerCrons,x as resolveRemoteEnabled,N as scanWranglerVariablesForSecrets,h as validateWrangler,u as validateWranglerConfig,K as validateWranglerProject,j as withTailConsumer,M as wranglerToAlchemy};
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{writeFileSync as T,readFileSync as R}from"node:fs";import{join as M}from"node:path";import{containerBuildTag as W}from"@lunora/container";import{parseTree as L,findNodeAtLocation as Q}from"jsonc-parser";import{DEV_VARS_FILE as K,parseDevVariableEntries as U}from"./DEV_VARS_EXAMPLE_FILE-CqLorAxT.mjs";import{a as x}from"./jsonc-edit-BZgQIdAH.mjs";import{r as Y,a as F}from"./lunora-manifest-V77OcyFC.mjs";import{findWranglerFile as G,readWranglerJsonc as H}from"./WRANGLER_FILES-UNW-xY5u.mjs";import{objectBindingEntries as q,stringEntries as E}from"./REQUIRED_COMPATIBILITY_DATE-SdRHaUwh.mjs";const I="<replace-with-d1-create-id>",J=e=>[["container","containers",e.containers],["workflow","workflows",e.workflows],["agent","agents",e.agents]].flatMap(([s,t,a])=>a.filter(o=>!o.exported).map(({className:o,exportName:c})=>({className:o,exportName:c,kind:s,module:t}))),k="PIPELINES",V=(e,n)=>{const s=e.flagshipBinding!==void 0&&!(n?.flagship??[]).some(o=>o.binding===e.flagshipBinding),t=e.usesPipelines&&!(n?.pipelines??[]).some(o=>o.binding===k);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 "${k}" pipelines binding exists; run 'wrangler pipelines create <name>' and add a 'pipelines' binding ({ binding: "${k}", 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(([o])=>o).map(([,o])=>o)},z=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),N=(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.`),X=(e,n)=>{const s=new Set([...e.workflows,...e.agents].map(t=>t.className));return s.size===0?[]:(n.workflows??[]).flatMap(t=>{const a=t.class_name;return a===void 0||s.has(a)?[]:[`wrangler.jsonc declares workflows[] entry "${a}" 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.`]})},Z=(e,n)=>{if(e.queues.length===0)return[];const s=new Set(e.queues.map(a=>a.name)),t=new Set(e.queues.map(a=>a.bindingName));return[...(n.queues?.consumers??[]).flatMap(a=>{const{queue:o}=a;return o===void 0||s.has(o)?[]:[`wrangler.jsonc subscribes queues.consumers[] to "${o}" 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(a=>{const{binding:o}=a;return o===void 0||t.has(o)?[]:[`wrangler.jsonc declares queues.producers[] binding "${o}" but no defineQueue export declares it — a leftover from a rename. Remove it if it is not hand-wired.`]})]},ee=(e,n)=>[...X(e,n),...Z(e,n)],j=[{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"}],ne=()=>j.map(({keys:e,label:n})=>`${e[0]} + ${e[1]} (${n})`).join(" or "),se=e=>{let n;try{n=R(M(e,K),"utf8")}catch{return!1}const s=new Map(U(n).map(t=>[t.key,t.value]));return j.some(({keys:t})=>t.every(a=>(s.get(a)??"")!==""))},O=(e,n,s)=>{const t=new Set(e.durableObjects.map(d=>d.className)),a=[],o=(s?.r2_buckets?.length??0)>0,c=(s?.d1_databases?.some(d=>d.binding==="DB")??!1)||e.needsD1;return e.usesStorage&&!o&&a.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&&a.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")&&a.push("@lunora/scheduler is used but the worker entry exports no SchedulerDO; export it so the SCHEDULER binding can be provisioned."),a.push(...N("container","containers",e.containers),...N("workflow","workflows",e.workflows),...N("agent","agents",e.agents)),e.containers.length>0&&s?.observability?.enabled===!1&&a.push("containers are declared but observability is explicitly disabled in wrangler.jsonc — container logs will not be captured."),e.usesPayment&&!se(n)&&a.push(`@lunora/payment is used; set one provider's secret pair in .dev.vars — ${ne()}.`),a.push(...z(e),...V(e,s)),s!==void 0&&a.push(...ee(e,s)),a},te=e=>{const n=new Set(q(e).map(t=>t.tag));let s=1;for(;n.has(`v${String(s)}`);)s+=1;return`v${String(s)}`},oe=e=>{const n=new Set;for(const s of q(e)){for(const t of E(s.deleted_classes))n.delete(t);for(const{from:t,to:a}of q(s.renamed_classes))t!==void 0&&n.delete(t),a!==void 0&&n.add(a);for(const t of[...E(s.new_classes),...E(s.new_sqlite_classes)])n.add(t)}return n},ae=(e,n,s)=>{const t=n.durable_objects?.bindings??[],a=new Set(t.map(l=>l.name)),o=s.filter(l=>!a.has(l.binding));let c=e;const d=[];if(o.length>0){const l=[...t,...o.map(b=>({class_name:b.className,name:b.binding}))];c=x(c,["durable_objects","bindings"],l),d.push(...o.map(b=>`${b.binding}/${b.className}`))}const p=n.migrations??[],r=s.map(l=>l.className).filter(l=>!oe(p).has(l));if(r.length>0){const l=[...p,{new_sqlite_classes:r,tag:te(p)}];c=x(c,["migrations"],l)}return{added:d,text:c}},ie=(e,n)=>{const s=n.d1_databases??[];if(s.some(o=>o.binding==="DB"))return{added:[],text:e};const t=typeof n.name=="string"&&n.name.length>0?n.name:"lunora",a=[...s,{binding:"DB",database_id:I,database_name:t}];return{added:["DB (D1)"],text:x(e,["d1_databases"],a)}},$=(e,n,s,t,a)=>{const o=n[s]?.binding;return typeof o=="string"&&o.length>0?{added:[],text:e}:{added:[a],text:x(e,[s],{binding:t})}},re=(e,n)=>(n.analytics_engine_datasets?.length??0)>0?{added:[],text:e}:{added:["ANALYTICS (Analytics Engine)"],text:x(e,["analytics_engine_datasets"],[{binding:"ANALYTICS",dataset:"ANALYTICS"}])},de=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},ce=e=>e.image.kind==="dockerfile"?e.image.dockerfilePath:e.image.kind==="registry"?e.image.reference:W(e.exportName),ue=e=>{const n={class_name:e.className,image:ce(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=de(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},le=(e,n,s)=>{const t=n.containers??[],a=new Set(t.map(d=>d.class_name)),o=s.filter(d=>!a.has(d.className));if(o.length===0)return{added:[],text:e};const c=x(e,["containers"],[...t,...o.map(d=>ue(d))]);return{added:o.map(d=>`containers/${d.className}`),text:c}},ge=(e,n)=>{if(n.observability!==void 0)return{added:[],text:e};const s=x(e,["observability"],{enabled:!0,head_sampling_rate:1});return{added:["observability"],text:s}},B=e=>({binding:e.bindingName,class_name:e.className,name:e.name}),me=(e,n,s,t=[])=>{const a=n.workflows??[],o=new Set(a.map(r=>r.class_name)),c=s.filter(r=>!o.has(r.className)),d=t.filter(r=>!o.has(r.className));if(c.length===0&&d.length===0)return{added:[],text:e};const p=x(e,["workflows"],[...a,...c.map(r=>B(r)),...d.map(r=>B(r))]);return{added:[...c.map(r=>`workflows/${r.className}`),...d.map(r=>`workflows/${r.className}`)],text:p}},pe=[["maxBatchSize","max_batch_size"],["maxBatchTimeout","max_batch_timeout"],["maxRetries","max_retries"],["deadLetterQueue","dead_letter_queue"],["retryDelay","retry_delay"]],D=e=>Object.fromEntries(pe.filter(([n])=>e.tuning[n]!==void 0).map(([n,s])=>[s,e.tuning[n]])),A="queueTuning",be=/^[\t ]*(?:,[\t ]*)?(?:\/\/[^\n\r]*)?\r?\n/u,he=/^[\t ]*,/u,fe=(e,n)=>{const s=L(e),t=s===void 0?void 0:Q(s,[...n])?.parent;if(t?.type==="property"){const a=t.offset+t.length,o=e.lastIndexOf(`
|
|
2
|
+
`,t.offset-1)+1,c=be.exec(e.slice(a));if(c!==null&&e.slice(o,t.offset).trim()===""){const d=t.parent?.children??[],p=d.indexOf(t),r=p===d.length-1&&p>0?d[p-1]:void 0,l=r===void 0?void 0:he.exec(e.slice(r.offset+r.length))??void 0;return(l===void 0||r===void 0?e.slice(0,o):e.slice(0,r.offset+r.length)+e.slice(r.offset+r.length+l[0].length,o))+e.slice(a+c[0].length)}}return x(e,n,void 0)},P=(e,n,s,t,a,o=new Set)=>{const c=s.join("."),d={},p=[],r=[];let l=e;return{entries:n.map((u,f)=>{const g=t(u);if(g===void 0||u.queue===void 0)return u;const v=Object.fromEntries(Object.entries(D(g)).filter(([m])=>!o.has(m))),w=Object.entries(a[u.queue]??{}).filter(([m])=>!Object.hasOwn(v,m)),_=Object.entries(v).filter(([m,i])=>u[m]!==i),y=w.filter(([m,i])=>u[m]===i).map(([m])=>m),S=Object.fromEntries(Object.entries({...u,...v}).filter(([m])=>!y.includes(m)));for(const[m,i]of _)l=x(l,[...s,f,m],i);for(const m of y)l=fe(l,[...s,f,m]);for(const[m,i]of w){const h=u[m];h!==void 0&&h!==i&&r.push(`${c}/${u.queue}: ${m} is no longer declared by defineQueue, but it was changed by hand to ${JSON.stringify(h)} from the declared ${JSON.stringify(i)}, so it was kept. Delete it from wrangler.jsonc if it should go.`)}return(_.length>0||y.length>0)&&p.push(`${c}/${u.queue} (${[..._.map(([m])=>m),...y.map(m=>`removed ${m}`)].join(", ")})`),Object.keys(v).length>0&&(d[u.queue]=v),S}),owned:d,text:l,updated:p,warnings:r}},ve=(e,n,s,t)=>{const a=n.queues??{},o=a.producers??[],c=a.consumers??[],d=new Set(o.map(g=>g.binding)),p=new Set(c.map(g=>g.queue)),r=s.filter(g=>!d.has(g.bindingName)),l=s.filter(g=>!p.has(g.name)),b=P(e,c,["queues","consumers"],g=>s.find(v=>v.name===g.queue),t);let u=b.text;const f={...b.owned};if(r.length>0||l.length>0){const g=[...o,...r.map(w=>({binding:w.bindingName,queue:w.name}))],v=[...b.entries,...l.map(w=>({queue:w.name,...w.mode==="pull"?{type:"http_pull"}:{},...D(w)}))];for(const w of l){const _=D(w);Object.keys(_).length>0&&(f[w.name]=_)}u=x(u,["queues"],{consumers:v,producers:g})}return{added:[...r.map(g=>`queues.producers/${g.bindingName}`),...l.map(g=>`queues.consumers/${g.name}`)],owned:f,text:u,updated:b.updated,warnings:b.warnings}},we=(e,n,s,t,a)=>{const o=n.env?.[t],c=o?.queues?.consumers??[],d=o?.queues?.producers??[],p=u=>{const f=d.find(g=>g.queue===u.queue)?.binding;return f!==void 0?s.find(g=>g.bindingName===f):s.find(g=>g.name===u.queue&&!d.some(v=>v.binding===g.bindingName))},r=P(e,c,["env",t,"queues","consumers"],p,a,new Set(["dead_letter_queue"])),l=c.filter(u=>u.queue!==void 0&&p(u)===void 0).map(u=>`env.${t}.queues.consumers/${String(u.queue)}: no defineQueue export matches it — this block declares no producer mapping one of their bindings to "${String(u.queue)}", and no export is named that — so it was not retuned. A consumer for a queue another worker produces is skipped the same way.`),b=c.flatMap(u=>{const f=p(u)?.tuning.deadLetterQueue;return f===void 0||u.dead_letter_queue!==void 0?[]:[`env.${t}.queues.consumers/${String(u.queue)}: defineQueue declares deadLetterQueue "${f}", but this consumer has no dead_letter_queue, so its exhausted messages are dropped. Queue names differ per environment, so reconcile does not write it here; add it by hand.`]});return{added:[],owned:r.owned,text:r.text,updated:r.updated,warnings:[...r.warnings,...b,...l]}},_e=(e,n)=>{if(e?.lunoraIsForeign===!0)return n.push(`${e.path}: \`lunora\` is not an object, so the queue tuning ownership record cannot be read or written — an option removed from defineQueue stays deployed.`),{};const s=e?.lunora?.[A],t=a=>typeof a=="object"&&a!==null&&!Array.isArray(a);return s===void 0?{}:!t(s)||!Object.values(s).every(a=>t(a)&&Object.values(a).every(o=>t(o)))?(n.push(`${e?.path??"package.json"}: \`lunora.${A}\` is not a map of scope → queue → fields, so it is ignored — an option removed from defineQueue stays deployed until the next pass records it again.`),{}):s},xe=(e,n,s)=>{const t=Object.fromEntries(Object.entries({...n,...s}).filter(([,a])=>Object.keys(a).length>0));F(e,A,Object.keys(t).length===0?void 0:t)},Ae=(e,n,s)=>{const t=G(e),a=J(n);if(!t)return{added:[],changed:!1,exportGaps:a,reason:"wrangler.jsonc not found",updated:[],warnings:O(n,e)};const{parsed:o,text:c}=H(t);if(o===void 0)return{added:[],changed:!1,exportGaps:a,reason:`failed to parse ${t} as JSONC`,updated:[],warnings:O(n,e),wranglerPath:t};const d=O(n,e,o);if(s!==void 0){const i=o.env?.[s]!==void 0;d.push(i?`auto-provisioned bindings are written to the top level of wrangler.jsonc only (queue consumers "env.${s}" already declares are retuned, nothing is added) — "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 p=n.containers.filter(i=>i.exported),r=n.agents.filter(i=>i.exported&&i.voice===!0&&i.voiceBindingName!==void 0&&i.voiceClassName!==void 0),l=[...n.durableObjects,...p.map(i=>({binding:i.bindingName,className:i.className})),...r.map(i=>({binding:i.voiceBindingName,className:i.voiceClassName}))],b=n.workflows.filter(i=>i.exported),u=n.agents.filter(i=>i.exported),f=Y(e),g=_e(f,d),v={},w=[{enabled:!0,run:i=>ae(i,o,l)},{enabled:n.needsD1,run:i=>ie(i,o)},{enabled:n.usesAi,run:i=>$(i,o,"ai","AI","AI (Workers AI)")},{enabled:n.usesBrowser,run:i=>$(i,o,"browser","BROWSER","BROWSER (Browser Rendering)")},{enabled:n.usesImages,run:i=>$(i,o,"images","IMAGES","IMAGES (Cloudflare Images)")},{enabled:n.usesAnalytics,run:i=>re(i,o)},{enabled:!0,run:i=>ge(i,o)},{enabled:p.length>0,run:i=>le(i,o,p)},{enabled:b.length>0||u.length>0,run:i=>me(i,o,b,u)},{enabled:n.queues.length>0,run:i=>{const h=ve(i,o,n.queues,g.queues??{});return v.queues=h.owned,h}},...s===void 0||o.env?.[s]===void 0?[]:[{enabled:n.queues.length>0,run:i=>{const h=`env.${s}.queues`,C=we(i,o,n.queues,s,g[h]??{});return v[h]=C.owned,C}}]];let _=c;const y=[],S=[];for(const i of w){if(!i.enabled)continue;const h=i.run(_);_=h.text,y.push(...h.added),S.push(...h.updated??[]),d.push(...h.warnings??[])}const m=i=>{if(!(f===void 0||Object.keys(v).length===0))try{xe(f,g,v)}catch(h){d.push(`${i?"wrangler.jsonc was updated, but ":""}recording the queue tuning reconcile owns in ${f.path} (lunora.queueTuning) failed: ${h instanceof Error?h.message:String(h)}. Until it is recorded, an option removed from defineQueue stays deployed.`)}};return y.includes("DB (D1)")&&d.push(`wrote a DB binding with a placeholder database_id ("${I}") — run \`wrangler d1 create <name>\` and replace it before deploying.`),_===c?(m(!1),{added:[],changed:!1,exportGaps:a,reason:"bindings already in sync",updated:[],warnings:d,wranglerPath:t}):(T(t,_,"utf8"),m(!0),{added:y,changed:!0,exportGaps:a,updated:S,warnings:d,wranglerPath:t})};export{J as collectExportGaps,Ae as reconcileWranglerBindings};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{writeFileSync as u}from"node:fs";import{modify as y,applyEdits as w}from"jsonc-parser";import{r as m,f as v,a as $}from"./lunora-manifest-V77OcyFC.mjs";import{findWranglerFile as x,readWranglerJsonc as C}from"./WRANGLER_FILES-UNW-xY5u.mjs";const b=(r,n)=>r.length===n.length&&r.every((e,t)=>e===n[t]),j=(r,n)=>{if(r?.lunoraIsForeign===!0)return n.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 e=r?.lunora?.crons;if(e===void 0)return[];if(!Array.isArray(e))return n.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=e.filter(o=>typeof o=="string");return t.length!==e.length&&n.push(`${r?.path??"package.json"}: \`lunora.crons\` dropped ${String(e.length-t.length)} non-string entry(s) — anything it recorded there is now treated as hand-written and will not be cleared.`),t},k=(r,n)=>{$(r,"crons",n.length===0?void 0:[...n])},W=(r,n)=>{const e=x(r);if(!e)return{changed:!1,preserved:[],reason:"wrangler.jsonc not found",warnings:[]};const{parsed:t,text:o}=C(e);if(t===void 0)return{changed:!1,preserved:[],reason:`failed to parse ${e} as JSONC`,warnings:[],wranglerPath:e};const g=Array.isArray(t.triggers?.crons)?t.triggers.crons.filter(i=>typeof i=="string"):[],c=[...n],s=[],d=m(r),p=j(d,s),a=g.filter(i=>!c.includes(i)&&!p.includes(i)),l=[...c,...a],f=()=>{d!==void 0&&k(d,c)};if(b(g,l))return f(),{changed:!1,preserved:a,reason:"triggers.crons already in sync",warnings:s,wranglerPath:e};const h=y(o,["triggers","crons"],l,{formattingOptions:v(o)});return h.length===0?{changed:!1,preserved:a,reason:"no structural edit produced",warnings:s,wranglerPath:e}:(u(e,w(o,h),"utf8"),f(),{changed:!0,preserved:a,warnings:s,wranglerPath:e})},J=r=>r.length===0?void 0:`kept ${String(r.length)} hand-written cron trigger(s): ${r.join(", ")}`;export{J as describePreservedCrons,W as reconcileWranglerCrons};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import{existsSync as O,readFileSync as b,writeFileSync as N}from"node:fs";import{applyEdits as $,modify as S,parseTree as h,findNodeAtLocation as g}from"jsonc-parser";import{join as A}from"node:path";const F=/^([\t ]+)"/mu,J=n=>{const o=F.exec(n)?.[1]??" ";return{eol:n.includes(`\r
|
|
2
|
+
`)?`\r
|
|
3
|
+
`:`
|
|
4
|
+
`,insertSpaces:!o.startsWith(" "),tabSize:o.length}},K=n=>{const o=A(n,"package.json");if(O(o))try{const t=b(o,"utf8"),{lunora:r}=JSON.parse(t),e=typeof r=="object"&&r!==null&&!Array.isArray(r);return{lunora:e?r:void 0,lunoraIsForeign:r!==void 0&&!e,path:o,text:t}}catch{return}},p=n=>JSON.stringify(n,(o,t)=>typeof t=="object"&&t!==null&&!Array.isArray(t)?Object.fromEntries(Object.entries(t).toSorted(([r],[e])=>r.localeCompare(e))):t),j=(n,o,t)=>{const r=J(n),e=r.insertSpaces===!1?" ":" ".repeat(r.tabSize??4),i=r.eol??`
|
|
5
|
+
`,c=e.repeat(o.length),a=JSON.stringify(t,void 0,e).split(`
|
|
6
|
+
`).join(i+c),l=h(n),f=l===void 0?void 0:g(l,[...o]);if(f!==void 0)return n.slice(0,f.offset)+a+n.slice(f.offset+f.length);let s=l;l!==void 0&&o.length>1&&(s=g(l,o.slice(0,-1)));const y=JSON.stringify(o.at(-1));if(s===void 0&&o.length>1)return j(n,o.slice(0,-1),{[o.at(-1)]:t});if(s?.type!=="object")return $(n,S(n,[...o],t,{formattingOptions:r}));const d=s.children?.at(-1);if(d===void 0){const v=`${i}${c}${y}: ${a}${i}${e.repeat(o.length-1)}`;return`${n.slice(0,s.offset+1)}${v}${n.slice(s.offset+s.length-1)}`}const u=d.offset+d.length;return`${n.slice(0,u)},${i}${c}${y}: ${a}${n.slice(u)}`},k=(n,o,t)=>{const r=Object.keys(n.lunora??{}).every(c=>c===o);if(n.lunoraIsForeign||p(n.lunora?.[o])===p(t))return;const e=t===void 0&&r?["lunora"]:["lunora",o],i=t===void 0?$(n.text,S(n.text,e,void 0,{})):j(n.text,e,t);i!==n.text&&N(n.path,i,"utf8")};export{k as a,J as f,K as r};
|
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.255",
|
|
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.
|
|
57
|
+
"@lunora/codegen": "1.0.0-alpha.219",
|
|
58
58
|
"@lunora/container": "1.0.0-alpha.56",
|
|
59
59
|
"@lunora/errors": "1.0.0-alpha.41",
|
|
60
|
-
"@lunora/seed": "1.0.0-alpha.
|
|
60
|
+
"@lunora/seed": "1.0.0-alpha.156",
|
|
61
61
|
"@visulima/colorize": "2.1.1",
|
|
62
62
|
"@visulima/find-ai-runner": "1.0.2",
|
|
63
63
|
"@visulima/package": "5.0.20",
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{writeFileSync as A,readFileSync as O}from"node:fs";import{join as P}from"node:path";import{containerBuildTag as $}from"@lunora/container";import{DEV_VARS_FILE as I,parseDevVariableEntries as R}from"./DEV_VARS_EXAMPLE_FILE-CqLorAxT.mjs";import{a as f}from"./jsonc-edit-BZgQIdAH.mjs";import{findWranglerFile as M,readWranglerJsonc as T}from"./WRANGLER_FILES-UNW-xY5u.mjs";import{objectBindingEntries as k,stringEntries as _}from"./REQUIRED_COMPATIBILITY_DATE-SdRHaUwh.mjs";const C="<replace-with-d1-create-id>",W=e=>[["container","containers",e.containers],["workflow","workflows",e.workflows],["agent","agents",e.agents]].flatMap(([n,a,i])=>i.filter(t=>!t.exported).map(({className:t,exportName:l})=>({className:t,exportName:l,kind:n,module:a}))),x="PIPELINES",q=(e,s)=>{const n=e.flagshipBinding!==void 0&&!(s?.flagship??[]).some(t=>t.binding===e.flagshipBinding),a=e.usesPipelines&&!(s?.pipelines??[]).some(t=>t.binding===x);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."],[a,`ctx.pipelines is used but no "${x}" pipelines binding exists; run 'wrangler pipelines create <name>' and add a 'pipelines' binding ({ binding: "${x}", 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(([t])=>t).map(([,t])=>t)},j=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),y=(e,s,n)=>n.filter(a=>!a.exported).map(a=>`${e} "${a.exportName}" is declared but ${a.className} is not exported by the worker entry; add \`export * from "./lunora/_generated/${s}"\` so its binding can be provisioned.`),K=(e,s)=>{const n=new Set([...e.workflows,...e.agents].map(a=>a.className));return n.size===0?[]:(s.workflows??[]).flatMap(a=>{const i=a.class_name;return i===void 0||n.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,s)=>{if(e.queues.length===0)return[];const n=new Set(e.queues.map(i=>i.name)),a=new Set(e.queues.map(i=>i.bindingName));return[...(s.queues?.consumers??[]).flatMap(i=>{const{queue:t}=i;return t===void 0||n.has(t)?[]:[`wrangler.jsonc subscribes queues.consumers[] to "${t}" 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.`]}),...(s.queues?.producers??[]).flatMap(i=>{const{binding:t}=i;return t===void 0||a.has(t)?[]:[`wrangler.jsonc declares queues.producers[] binding "${t}" but no defineQueue export declares it — a leftover from a rename. Remove it if it is not hand-wired.`]})]},Y=(e,s)=>[...K(e,s),...L(e,s)],B=[{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"}],H=()=>B.map(({keys:e,label:s})=>`${e[0]} + ${e[1]} (${s})`).join(" or "),F=e=>{let s;try{s=O(P(e,I),"utf8")}catch{return!1}const n=new Map(R(s).map(a=>[a.key,a.value]));return B.some(({keys:a})=>a.every(i=>(n.get(i)??"")!==""))},E=(e,s,n)=>{const a=new Set(e.durableObjects.map(r=>r.className)),i=[],t=(n?.r2_buckets?.length??0)>0,l=(n?.d1_databases?.some(r=>r.binding==="DB")??!1)||e.needsD1;return e.usesStorage&&!t&&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&&!a.has("SessionDO")&&!l&&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&&!a.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(...y("container","containers",e.containers),...y("workflow","workflows",e.workflows),...y("agent","agents",e.agents)),e.containers.length>0&&n?.observability?.enabled===!1&&i.push("containers are declared but observability is explicitly disabled in wrangler.jsonc — container logs will not be captured."),e.usesPayment&&!F(s)&&i.push(`@lunora/payment is used; set one provider's secret pair in .dev.vars — ${H()}.`),i.push(...j(e),...q(e,n)),n!==void 0&&i.push(...Y(e,n)),i},G=e=>{const s=new Set(k(e).map(a=>a.tag));let n=1;for(;s.has(`v${String(n)}`);)n+=1;return`v${String(n)}`},U=e=>{const s=new Set;for(const n of k(e)){for(const a of _(n.deleted_classes))s.delete(a);for(const{from:a,to:i}of k(n.renamed_classes))a!==void 0&&s.delete(a),i!==void 0&&s.add(i);for(const a of[..._(n.new_classes),..._(n.new_sqlite_classes)])s.add(a)}return s},Q=(e,s,n)=>{const a=s.durable_objects?.bindings??[],i=new Set(a.map(c=>c.name)),t=n.filter(c=>!i.has(c.binding));let l=e;const r=[];if(t.length>0){const c=[...a,...t.map(b=>({class_name:b.className,name:b.binding}))];l=f(l,["durable_objects","bindings"],c),r.push(...t.map(b=>`${b.binding}/${b.className}`))}const m=s.migrations??[],d=n.map(c=>c.className).filter(c=>!U(m).has(c));if(d.length>0){const c=[...m,{new_sqlite_classes:d,tag:G(m)}];l=f(l,["migrations"],c)}return{added:r,text:l}},V=(e,s)=>{const n=s.d1_databases??[];if(n.some(t=>t.binding==="DB"))return{added:[],text:e};const a=typeof s.name=="string"&&s.name.length>0?s.name:"lunora",i=[...n,{binding:"DB",database_id:C,database_name:a}];return{added:["DB (D1)"],text:f(e,["d1_databases"],i)}},S=(e,s,n,a,i)=>{const t=s[n]?.binding;return typeof t=="string"&&t.length>0?{added:[],text:e}:{added:[i],text:f(e,[n],{binding:a})}},z=(e,s)=>(s.analytics_engine_datasets?.length??0)>0?{added:[],text:e}:{added:["ANALYTICS (Analytics Engine)"],text:f(e,["analytics_engine_datasets"],[{binding:"ANALYTICS",dataset:"ANALYTICS"}])},X=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},J=e=>e.image.kind==="dockerfile"?e.image.dockerfilePath:e.image.kind==="registry"?e.image.reference:$(e.exportName),Z=e=>{const s={class_name:e.className,image:J(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=X(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},ee=(e,s,n)=>{const a=s.containers??[],i=new Set(a.map(r=>r.class_name)),t=n.filter(r=>!i.has(r.className));if(t.length===0)return{added:[],text:e};const l=f(e,["containers"],[...a,...t.map(r=>Z(r))]);return{added:t.map(r=>`containers/${r.className}`),text:l}},se=(e,s)=>{if(s.observability!==void 0)return{added:[],text:e};const n=f(e,["observability"],{enabled:!0,head_sampling_rate:1});return{added:["observability"],text:n}},D=e=>({binding:e.bindingName,class_name:e.className,name:e.name}),ne=(e,s,n,a=[])=>{const i=s.workflows??[],t=new Set(i.map(d=>d.class_name)),l=n.filter(d=>!t.has(d.className)),r=a.filter(d=>!t.has(d.className));if(l.length===0&&r.length===0)return{added:[],text:e};const m=f(e,["workflows"],[...i,...l.map(d=>D(d)),...r.map(d=>D(d))]);return{added:[...l.map(d=>`workflows/${d.className}`),...r.map(d=>`workflows/${d.className}`)],text:m}},te=[["maxBatchSize","max_batch_size"],["maxBatchTimeout","max_batch_timeout"],["maxRetries","max_retries"],["deadLetterQueue","dead_letter_queue"],["retryDelay","retry_delay"]],N=e=>Object.fromEntries(te.filter(([s])=>e.tuning[s]!==void 0).map(([s,n])=>[n,e.tuning[s]])),ae=(e,s,n)=>{const a=s.queues??{},i=a.producers??[],t=a.consumers??[],l=new Set(i.map(g=>g.binding)),r=new Set(t.map(g=>g.queue)),m=n.filter(g=>!l.has(g.bindingName)),d=n.filter(g=>!r.has(g.name));let c=e;const b=[];for(const[g,v]of t.entries()){const u=n.find(p=>p.name===v.queue);if(u===void 0)continue;const h=Object.entries(N(u)).filter(([p,o])=>v[p]!==o);for(const[p,o]of h)c=f(c,["queues","consumers",g,p],o);h.length>0&&b.push(`queues.consumers/${u.name} (${h.map(([p])=>p).join(", ")})`)}if(m.length>0||d.length>0){const g=[...i,...m.map(u=>({binding:u.bindingName,queue:u.name}))],v=[...t.map(u=>{const h=n.find(p=>p.name===u.queue);return h===void 0?u:{...u,...N(h)}}),...d.map(u=>({queue:u.name,...u.mode==="pull"?{type:"http_pull"}:{},...N(u)}))];c=f(c,["queues"],{consumers:v,producers:g})}return{added:[...m.map(g=>`queues.producers/${g.bindingName}`),...d.map(g=>`queues.consumers/${g.name}`)],text:c,updated:b}},ge=(e,s,n)=>{const a=M(e),i=W(s);if(!a)return{added:[],changed:!1,exportGaps:i,reason:"wrangler.jsonc not found",updated:[],warnings:E(s,e)};const{parsed:t,text:l}=T(a);if(t===void 0)return{added:[],changed:!1,exportGaps:i,reason:`failed to parse ${a} as JSONC`,updated:[],warnings:E(s,e),wranglerPath:a};const r=E(s,e,t);if(n!==void 0){const o=t.env?.[n]!==void 0;r.push(o?`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 m=s.containers.filter(o=>o.exported),d=s.agents.filter(o=>o.exported&&o.voice===!0&&o.voiceBindingName!==void 0&&o.voiceClassName!==void 0),c=[...s.durableObjects,...m.map(o=>({binding:o.bindingName,className:o.className})),...d.map(o=>({binding:o.voiceBindingName,className:o.voiceClassName}))],b=s.workflows.filter(o=>o.exported),g=s.agents.filter(o=>o.exported),v=[{enabled:!0,run:o=>Q(o,t,c)},{enabled:s.needsD1,run:o=>V(o,t)},{enabled:s.usesAi,run:o=>S(o,t,"ai","AI","AI (Workers AI)")},{enabled:s.usesBrowser,run:o=>S(o,t,"browser","BROWSER","BROWSER (Browser Rendering)")},{enabled:s.usesImages,run:o=>S(o,t,"images","IMAGES","IMAGES (Cloudflare Images)")},{enabled:s.usesAnalytics,run:o=>z(o,t)},{enabled:!0,run:o=>se(o,t)},{enabled:m.length>0,run:o=>ee(o,t,m)},{enabled:b.length>0||g.length>0,run:o=>ne(o,t,b,g)},{enabled:s.queues.length>0,run:o=>ae(o,t,s.queues)}];let u=l;const h=[],p=[];for(const o of v){if(!o.enabled)continue;const w=o.run(u);u=w.text,h.push(...w.added),p.push(...w.updated??[])}return h.includes("DB (D1)")&&r.push(`wrote a DB binding with a placeholder database_id ("${C}") — run \`wrangler d1 create <name>\` and replace it before deploying.`),u===l?{added:[],changed:!1,exportGaps:i,reason:"bindings already in sync",updated:[],warnings:r,wranglerPath:a}:(A(a,u,"utf8"),{added:h,changed:!0,exportGaps:i,updated:p,warnings:r,wranglerPath:a})};export{W as collectExportGaps,ge as reconcileWranglerBindings};
|
|
@@ -1,4 +0,0 @@
|
|
|
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};
|