@lunora/config 1.0.0-alpha.206 → 1.0.0-alpha.208

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.
@@ -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-CoNU-Q6s.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-DMTyRVyn.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};
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-YpqIPmvK.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-uIPpAmD1.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{readFileSync as w,existsSync as h,readdirSync as L}from"node:fs";import{basename as T,join as b,dirname as O,extname as k}from"node:path";import{discoverSchemaInfo as B}from"./discoverSchemaInfo-Bg2CUZXG.mjs";import{Project as U,Node as p}from"ts-morph";import{COMPOSED_WORKER_ENTRY as W,LUNORA_WORKER_VIRTUAL_ID as q,WORKER_ENTRY_FALLBACKS as F}from"./COMPOSED_WORKER_ENTRY-D8SuPTeb.mjs";import{isCacheEnabled as P,WORKERS_CACHE_MIN_DATE as $}from"./WORKERS_CACHE_MIN_DATE-0k9ABJtF.mjs";import{findWranglerFile as K,readWranglerJsonc as G}from"./WRANGLER_FILES-UNW-xY5u.mjs";const V=new Set(["1","enabled","on","true","yes"]),Y=e=>typeof e=="string"&&V.has(e.trim().toLowerCase()),H=new Set([".cts",".mts",".ts",".tsx"]),Q=(e,s,n)=>{const t=b(s,W);if(h(t))return t;if(e!==q){if(typeof e=="string"&&e.length>0){const i=b(O(n),e);return h(i)&&H.has(k(i))?i:void 0}return F.map(i=>b(s,i)).find(i=>h(i))}},D=(e,s)=>{if(p.isIdentifier(e)){s.add(e.getText());return}if(p.isObjectBindingPattern(e)||p.isArrayBindingPattern(e))for(const n of e.getElements())p.isBindingElement(n)&&D(n.getNameNode(),s)},z=(e,s)=>{let n=!1;for(const t of e.getExportDeclarations())if(!t.isTypeOnly()){if(t.isNamespaceExport()){const i=t.getNamespaceExport();i===void 0?n=!0:s.add(i.getName());continue}for(const i of t.getNamedExports())i.isTypeOnly()||s.add(i.getAliasNode()?.getText()??i.getName())}return n},J=(e,s)=>{for(const n of e.getVariableStatements().filter(t=>t.getExportKeyword()!==void 0))for(const t of n.getDeclarations())D(t.getNameNode(),s);for(const n of[...e.getClasses(),...e.getFunctions(),...e.getEnums()]){const t=n.getExportKeyword()!==void 0&&!n.isDefaultExport()?n.getName():void 0;t!==void 0&&s.add(t)}},X="defineApp",Z=(e,s)=>{const n=new Set;for(const t of e.getImportDeclarations())for(const i of t.getNamedImports())!i.isTypeOnly()&&i.getName()===s&&n.add(i.getAliasNode()?.getText()??i.getName());return n},ee=(e,s)=>{let n=!1;return e.forEachDescendant((t,i)=>{if(!p.isCallExpression(t))return;const a=t.getExpression();p.isIdentifier(a)&&s.has(a.getText())&&(n=!0,i.stop())}),n},se=(e,s,n)=>{const t=Q(e,s,n);if(t===void 0)return;let i;try{i=w(t,"utf8")}catch{return}const a=new U({compilerOptions:{allowJs:!0},skipFileDependencyResolution:!0,skipLoadingLibFiles:!0,useInMemoryFileSystem:!0}),o=a.createSourceFile(T(t),i,{overwrite:!0});if(a.getProgram().compilerObject.getSyntacticDiagnostics(o.compilerNode).length>0)return;const r=new Set,d=z(o,r);return d||J(o,r),{composesApp:ee(o,Z(o,X)),exports:d?void 0:r,path:t}},te=new Set(["_generated","build","coverage","dist","node_modules","out","target"]),ne=new Set([".cts",".mts",".ts",".tsx"]),ie=2e3,ae=".vectors(",oe=e=>{const s=[],n=[];let t;try{t=L(e,{withFileTypes:!0})}catch{return{files:s,subdirectories:n}}for(const i of t)i.isDirectory()?!i.name.startsWith(".")&&!te.has(i.name)&&n.push(b(e,i.name)):ne.has(k(i.name))&&s.push(b(e,i.name));return{files:s,subdirectories:n}},re=e=>{try{return w(e,"utf8").includes(ae)}catch{return!1}},ce=e=>{const s=[e];let n=ie;for(;s.length>0;){const t=s.pop(),{files:i,subdirectories:a}=oe(t);s.push(...a);for(const o of i)if(n-=1,n<0||re(o))return!0}return!1},S="2026-04-07",Qe="web_socket_auto_reply_to_close",A=/^\d{4}-\d{2}-\d{2}$/,j=["containers","d1_databases","durable_objects","kv_namespaces","queues","r2_buckets","secrets_store_secrets","services","tail_consumers","vars","vectorize","workflows"],R=["assets","compatibility_date","exports","logpush","main","migrations","observability","placement"],x=(e,s)=>{if(s===void 0)return{merged:e,unverifiedKeys:[]};const n=e.env?.[s];if(n===void 0){const r=Object.keys(e.env??{}).toSorted((c,l)=>c.localeCompare(l)),d=r.length>0?` (declared: ${r.join(", ")}).`:" (no environments are declared).";return{error:`--env "${s}" names no environment declared in wrangler.jsonc's "env" block${d}`,merged:e,unverifiedKeys:[]}}const t={...e},i=Object.keys(n).filter(r=>r!=="env");for(const r of i)R.includes(r)&&(t[r]=n[r]);for(const r of j)t[r]=n[r];const a=new Set([...j,...R]),o=i.filter(r=>!a.has(r)).map(String);return{merged:t,unverifiedKeys:o}},de=(e,s,n)=>{if(s.length===0)return;const t=e.vectorize??[],i=new Set(t.filter(Boolean).map(a=>a?.index_name));for(const a of s)i.has(a)||n.push(`schema declares vector index "${a}"; wrangler "vectorize" must include a binding with index_name "${a}"`)},le=new Set(["basic","dev","lite","standard","standard-1","standard-2","standard-3","standard-4"]),me={disk_mb:2e4,memory_mib:12288,vcpu:4},ue=(e,s,n)=>{const t=e.instance_type;if(t===void 0)return;if(typeof t=="string"){le.has(t)||n.push(`${s} has unknown instance_type "${t}" — expected lite, basic, standard-1..4, or a custom { vcpu, memory_mib, disk_mb } object`);return}for(const[r,d]of Object.entries(me)){const c=t[r];c!==void 0&&(typeof c!="number"||c<=0||c>d)&&n.push(`${s} custom instance_type ${r} must be a positive number ≤ ${String(d)} (got ${String(c)})`)}const{disk_mb:i,memory_mib:a,vcpu:o}=t;if(typeof o=="number"&&typeof a=="number"&&a<o*3072&&n.push(`${s} custom instance_type needs ≥ 3 GiB (3072 MiB) memory per vCPU (got ${String(a)} MiB for ${String(o)} vCPU)`),typeof a=="number"&&typeof i=="number"){const r=Math.floor(a/1024*2e3);i>r&&n.push(`${s} custom instance_type allows ≤ 2 GB disk per GiB memory (≤ ${String(r)} MB for ${String(a)} MiB memory; got ${String(i)} MB)`)}},ge=(e,s,n)=>{const{boundClasses:t,classKinds:i,errors:a,warnings:o}=n;if(!e||typeof e!="object"||typeof e.class_name!="string"||e.class_name.length===0){a.push(`${s} must have a non-empty "class_name" naming its container-enabled Durable Object class`);return}(typeof e.image!="string"||e.image.length===0)&&a.push(`${s} ("${e.class_name}") must have an "image" — a Dockerfile path or a registry reference`),t.has(e.class_name)||a.push(`${s} class "${e.class_name}" has no matching durable_objects binding — your dev server auto-reconciles this on startup; add { "name": "...", "class_name": "${e.class_name}" } to fix it by hand`);const r=i.get(e.class_name);r!=="sqlite"&&a.push(r==="classic"?`${s} class "${e.class_name}" is registered via "new_classes" but containers require SQLite-backed DOs — move it to "new_sqlite_classes"`:`${s} class "${e.class_name}" is missing from migrations — add a migration entry with "new_sqlite_classes": ["${e.class_name}"]`),ue(e,`${s} ("${e.class_name}")`,a),e.max_instances===void 0&&o.push(`${s} ("${e.class_name}") declares no max_instances — set a cap so a traffic spike can't fan out unbounded container spend`)},m=e=>typeof e=="string"&&e.length>0,g=e=>Array.isArray(e)?e.filter(s=>s!==null&&typeof s=="object"):[],v=e=>Array.isArray(e)?e.filter(s=>m(s)):[],M=e=>{const s=new Map;for(const n of g(e)){for(const t of v(n.new_classes))s.set(t,"classic");for(const t of v(n.new_sqlite_classes))s.set(t,"sqlite");for(const t of g(n.renamed_classes))if(m(t.from)&&m(t.to)){const i=s.get(t.from)??"sqlite";s.delete(t.from),s.set(t.to,i)}for(const t of v(n.deleted_classes))s.delete(t)}return s},fe=e=>new Set(M(e).keys()),be=(e,s)=>{const n=fe(e.migrations);for(const t of g(e.durable_objects?.bindings))t.script_name===void 0&&m(t.class_name)&&!n.has(t.class_name)&&s.push(`durable_objects.bindings declares class "${t.class_name}" but it is missing from migrations — add a migration entry with "new_sqlite_classes": ["${t.class_name}"] (or "new_classes" for a non-SQLite-backed class), or let the dev server auto-reconcile it on the next start`)},pe=(e,s,n)=>{if(e.containers===void 0)return;if(!Array.isArray(e.containers)){s.push("containers must be an array of { class_name, image, ... } entries");return}const t=e.containers;if(t.length===0)return;const i=new Set(g(e.durable_objects?.bindings).map(o=>o.class_name)),a=M(e.migrations);for(const[o,r]of t.entries())ge(r,`containers[${String(o)}]`,{boundClasses:i,classKinds:a,errors:s,warnings:n});e.observability?.enabled!==!0&&n.push('containers are configured but observability is not enabled — container logs will not be captured (add { "observability": { "enabled": true } })')},E=e=>e,y=(e,s,n,t)=>{if(e!==void 0){if(!Array.isArray(e)){t.push(n.arrayMessage);return}for(const[i,a]of E(e).entries()){const o=`${s}[${String(i)}]`;if(!a||typeof a!="object"){t.push(n.objectMessage(o));continue}for(const r of n.fields)m(a[r.field])||t.push(r.message(o))}}},he={arrayMessage:"workflows must be an array of { name, binding, class_name } entries",fields:[{field:"binding",message:e=>`${e} must have a non-empty "binding" naming the Workflow binding (e.g. WORKFLOW_ORDER_PIPELINE)`},{field:"class_name",message:e=>`${e} must have a non-empty "class_name" naming the exported WorkflowEntrypoint class`},{field:"name",message:e=>`${e} must have a non-empty "name" naming the deployed workflow`}],objectMessage:e=>`${e} must be a { name, binding, class_name } object`},ye={arrayMessage:"queues.producers must be an array of { binding, queue } entries",fields:[{field:"binding",message:e=>`${e} must have a non-empty "binding" naming the Queue producer (e.g. QUEUE_EMAIL)`},{field:"queue",message:e=>`${e} must have a non-empty "queue" naming the deployed queue`}],objectMessage:e=>`${e} must be a { binding, queue } object`},_e={arrayMessage:"queues.consumers must be an array of { queue } entries",fields:[{field:"queue",message:e=>`${e} must have a non-empty "queue" naming the consumed queue`}],objectMessage:e=>`${e} must be a { queue } object`},ve=(e,s)=>{if(e.queues!==void 0){if(typeof e.queues!="object"||Array.isArray(e.queues)){s.push("queues must be a { producers, consumers } object");return}y(e.queues.producers,"queues.producers",ye,s),y(e.queues.consumers,"queues.consumers",_e,s)}},Ee={arrayMessage:"secrets_store_secrets must be an array of { binding, store_id, secret_name } entries",fields:["binding","store_id","secret_name"].map(e=>({field:e,message:s=>`${s} must have a non-empty "${e}"`})),objectMessage:e=>`${e} must be a { binding, store_id, secret_name } object`},$e=[{arrayMessage:"kv_namespaces must be an array of { binding, id } entries",bindingMessage:e=>`${e} must have a non-empty "binding" naming the KV namespace binding`,hintField:"id",hintMessage:(e,s)=>`${e} ("${s}") has no "id" — run \`wrangler kv namespace create\` and set the namespace id, or the binding can't resolve`,key:"kv_namespaces"},{arrayMessage:"flagship must be an array of { binding, app_id } entries",bindingMessage:e=>`${e} must have a non-empty "binding" naming the Flagship binding`,hintField:"app_id",hintMessage:(e,s)=>`${e} ("${s}") has no "app_id" — create a Flagship app and set its id, or the binding can't resolve`,key:"flagship"},{arrayMessage:"hyperdrive must be an array of { binding, id } entries",bindingMessage:e=>`${e} must have a non-empty "binding" naming the Hyperdrive binding`,hintField:"id",hintMessage:(e,s)=>`${e} ("${s}") has no "id" — run \`wrangler hyperdrive create\` and set the id, or the binding can't connect`,key:"hyperdrive"},{arrayMessage:"pipelines must be an array of { binding, stream } entries",bindingMessage:e=>`${e} must have a non-empty "binding" naming the Pipelines binding`,hintField:["stream","pipeline"],hintMessage:(e,s)=>`${e} ("${s}") has no "stream" — run \`wrangler pipelines create <name>\` and set the stream name, or the binding can't resolve`,key:"pipelines"},{arrayMessage:"analytics_engine_datasets must be an array of { binding, dataset } entries",bindingMessage:e=>`${e} must have a non-empty "binding" naming the Analytics Engine binding`,hintField:"dataset",hintMessage:(e,s)=>`${e} ("${s}") has no "dataset" — it defaults to the binding name; set it explicitly to avoid drift`,key:"analytics_engine_datasets"}],Se=(e,s,n,t)=>{const i=e[s.key];if(i!==void 0){if(!Array.isArray(i)){n.push(s.arrayMessage);return}for(const[a,o]of E(i).entries()){const r=`${s.key}[${String(a)}]`;if(!o||typeof o!="object"||!m(o.binding)){n.push(s.bindingMessage(r));continue}(typeof s.hintField=="string"?[s.hintField]:s.hintField).some(c=>m(o[c]))||t.push(s.hintMessage(r,o.binding))}}},Ae=[{key:"browser",message:'browser must be an object with a non-empty "binding" (e.g. { "binding": "BROWSER" })'},{key:"images",message:'images must be an object with a non-empty "binding" (e.g. { "binding": "IMAGES" })'}],je=(e,s,n)=>{const t=e[s.key];t!==void 0&&(typeof t!="object"||t===null||Array.isArray(t)||!m(t.binding))&&n.push(s.message)},Re=[{arrayMessage:"services must be an array of { binding, service, entrypoint? } entries",fields:[{field:"binding",message:e=>`${e} must have a non-empty "binding" naming the service binding`},{field:"service",message:e=>`${e} must have a non-empty "service" naming the target Worker`}],key:"services",objectMessage:e=>`${e} must be a { binding, service, entrypoint? } object`},{arrayMessage:"dispatch_namespaces must be an array of { binding, namespace } entries",fields:[{field:"binding",message:e=>`${e} must have a non-empty "binding"`},{field:"namespace",message:e=>`${e} must have a non-empty "namespace" naming the dispatch namespace`}],key:"dispatch_namespaces",objectMessage:e=>`${e} must be a { binding, namespace } object`},{arrayMessage:"mtls_certificates must be an array of { binding, certificate_id } entries",fields:[{field:"binding",message:e=>`${e} must have a non-empty "binding"`},{field:"certificate_id",message:e=>`${e} must have a non-empty "certificate_id" (upload via \`wrangler mtls-certificate upload\`)`}],key:"mtls_certificates",objectMessage:e=>`${e} must be a { binding, certificate_id } object`},{arrayMessage:"r2_buckets must be an array of { binding, bucket_name } entries",fields:[{field:"binding",message:e=>`${e} must have a non-empty "binding" naming the R2 bucket binding`},{field:"bucket_name",message:e=>`${e} must have a non-empty "bucket_name" naming the deployed bucket`}],key:"r2_buckets",objectMessage:e=>`${e} must be a { binding, bucket_name } object`}],Ne=(e,s)=>{const{d1_databases:n}=e;if(n!==void 0){if(!Array.isArray(n)){s.push("d1_databases must be an array of { binding, database_id | database_name } entries");return}for(const[t,i]of E(n).entries()){const a=`d1_databases[${String(t)}]`;if(!i||typeof i!="object"){s.push(`${a} must be a { binding, database_id | database_name } object`);continue}m(i.binding)||s.push(`${a} must have a non-empty "binding" naming the D1 binding`),!m(i.database_id)&&!m(i.database_name)&&s.push(`${a} must have a "database_id" or a "database_name" — run \`wrangler d1 create\` and set one, or the binding can't resolve`)}}},we=(e,s,n)=>{const t=e.send_email;if(t===void 0)return;if(!Array.isArray(t)){s.push("send_email must be an array of { name, destination_address? } entries");return}const i=t;for(const[a,o]of i.entries())(!o||typeof o!="object"||typeof o.name!="string"||o.name.length===0)&&n.push(`send_email[${String(a)}] has no non-empty "name" naming the send-email binding — set one before deploying`)},Oe=(e,s)=>{e.logpush!==void 0&&typeof e.logpush!="boolean"&&s.push('logpush must be a boolean (set "logpush": true to enable Cloudflare Logpush)')},N=new Set(["off","smart","targeted"]),ke=(e,s)=>{const{placement:n}=e;if(n===void 0)return;if(typeof n!="object"||n===null||Array.isArray(n)){s.push('placement must be an object (e.g. { "mode": "smart" })');return}const{mode:t}=n;t!==void 0&&(typeof t!="string"||!N.has(t))&&s.push(`placement.mode must be one of ${[...N].map(i=>`"${i}"`).join(", ")}`)},De=(e,s)=>{const{observability:n}=e;if(n===void 0)return;if(typeof n!="object"||Array.isArray(n)){s.push('observability must be an object (e.g. { "enabled": true, "head_sampling_rate": 1 })');return}const t=(i,a)=>{i!==void 0&&(typeof i!="number"||Number.isNaN(i)||i<0||i>1)&&s.push(`${a} must be a number in [0, 1] (the fraction of requests sampled)`)};t(n.head_sampling_rate,"observability.head_sampling_rate"),n.logs!==void 0&&(typeof n.logs!="object"||Array.isArray(n.logs)?s.push("observability.logs must be an object"):t(n.logs.head_sampling_rate,"observability.logs.head_sampling_rate"))},xe=(e,s)=>{const{cache:n}=e;if(n!==void 0){if(typeof n!="object"||n===null||Array.isArray(n)){s.push('cache must be an object (e.g. { "enabled": true })');return}n.enabled!==void 0&&typeof n.enabled!="boolean"&&s.push("cache.enabled must be a boolean (true or false)")}},Me=(e,s)=>{const{exports:n}=e;if(n!==void 0){if(typeof n!="object"||n===null||Array.isArray(n)){s.push("exports must be an object keyed by entrypoint name");return}for(const[t,i]of Object.entries(n)){if(typeof i!="object"||i===null){s.push(`exports["${t}"] must be an object`);continue}i.type!==void 0&&typeof i.type!="string"&&s.push(`exports["${t}"].type must be a string`),i.cache!==void 0&&(typeof i.cache!="object"||i.cache===null||Array.isArray(i.cache)?s.push(`exports["${t}"].cache must be an object`):i.cache.enabled!==void 0&&typeof i.cache.enabled!="boolean"&&s.push(`exports["${t}"].cache.enabled must be a boolean`))}}},Ie=(e,s)=>{const{assets:n}=e;if(n!==void 0){if(typeof n!="object"||Array.isArray(n)){s.push('assets must be an object (e.g. { "directory": "./dist/client", "binding": "ASSETS" })');return}(typeof n.directory!="string"||n.directory.length===0)&&s.push('assets must declare a non-empty "directory" pointing at the built client output (e.g. "./dist/client")'),n.binding!==void 0&&(typeof n.binding!="string"||n.binding.length===0)&&s.push('assets.binding must be a non-empty string (e.g. "ASSETS")'),n.html_handling!==void 0&&typeof n.html_handling!="string"&&s.push("assets.html_handling must be a string"),n.not_found_handling!==void 0&&typeof n.not_found_handling!="string"&&s.push("assets.not_found_handling must be a string")}},Ce=(e,s)=>{const n=e.tail_consumers;if(n===void 0)return;if(!Array.isArray(n)){s.push("tail_consumers must be an array of { service, environment? } entries");return}const t=n;for(const[i,a]of t.entries())(!a||typeof a!="object"||typeof a.service!="string"||a.service.length===0)&&s.push(`tail_consumers[${String(i)}] must have a non-empty "service" naming the consumer Worker`)},ze=(e,s)=>{const n=e.tail_consumers??[];return n.some(i=>!!i&&i?.service===s.service&&i?.environment===s.environment)?e:{...e,tail_consumers:[...n,s]}},Le=(e,s)=>{const{vars:n}=e;if(!n||typeof n!="object")return;const t=n.LUNORA_ALLOWED_ORIGINS,i=n.LUNORA_CORS_ALLOW_CREDENTIALS,a=typeof t=="string"&&t.split(",").some(r=>r.trim()==="*"),o=Y(i);a&&o&&s.push('vars.LUNORA_ALLOWED_ORIGINS includes a "*" wildcard while vars.LUNORA_CORS_ALLOW_CREDENTIALS is on — browsers reject this combination and it defeats the allowlist; name explicit origins or drop credentials')},_="LUNORA_ORIGIN_URL",Te=(e,s,n)=>{if(!g(e.durable_objects?.bindings).some(o=>o.class_name==="SchedulerDO"&&o.script_name===void 0)||m(e.vars?.[_]))return;const i=s===void 0?"vars":`env.${s}.vars`,a=s===void 0?"":` --env ${s}`;n.push(`durable_objects.bindings declares the SchedulerDO but ${i}.${_} is unset — the DO reads its dispatch origin from its own env and refuses to schedule without it, so every ctx.scheduler.runAfter/runAt fails with ORIGIN_NOT_CONFIGURED. Set ${i}.${_} to the worker's public URL, or \`wrangler secret put ${_}${a}\` (ignore this if it is already set as a secret or in the dashboard).`)},Be=(e,s,n)=>{const{error:t,merged:i,unverifiedKeys:a}=x(e,s);return t!==void 0?{error:t,wrangler:i}:(a.length>0&&n.push(`env.${String(s)} overrides ${a.join(", ")}, which this validator doesn't have a verified inheritance rule for — validated against the TOP-LEVEL value only. Double-check ${a.length===1?"it":"them"} by hand for "${String(s)}".`),{wrangler:i})},I=(e,s,n)=>{const t=[],i=[];if(!e||typeof e!="object")return t.push("wrangler config is not a valid object"),{errors:t,valid:!1,warnings:i};const{error:a,wrangler:o}=Be(e,n,i);if(a!==void 0)return t.push(a),{errors:t,valid:!1,warnings:i};g(o.durable_objects?.bindings).find(l=>l.name==="SHARD"&&l.class_name==="ShardDO")||t.push('durable_objects.bindings must include { "name": "SHARD", "class_name": "ShardDO" } — your dev server auto-reconciles this on startup, or add the binding manually'),be(o,t);const c=o.compatibility_date??"";c&&!A.test(c)?t.push(`compatibility_date must be in YYYY-MM-DD format (got "${c}")`):c<S&&t.push(`compatibility_date must be >= "${S}" (got "${c||"<missing>"}")`),P(o)&&A.test(c)&&c<$&&t.push(`cache.enabled requires compatibility_date >= "${$}" (got "${c||"<missing>"}")`),s?.hasGlobalTable&&(g(o.d1_databases).find(u=>u.binding==="DB")||t.push('schema declares .global() tables; d1_databases must include a binding named "DB" — your dev server auto-reconciles this on startup, or add the binding manually')),Ne(o,t),de(o,s?.vectorIndexNames??[],t),Ce(o,t),pe(o,t,i),y(o.workflows,"workflows",he,t),ve(o,t),y(o.secrets_store_secrets,"secrets_store_secrets",Ee,t);for(const l of $e)Se(o,l,t,i);for(const l of Re)y(o[l.key],l.key,l,t);for(const l of Ae)je(o,l,t);return we(o,t,i),Oe(o,t),ke(o,t),De(o,t),Ie(o,t),xe(o,t),Me(o,t),Le(o,t),Te(o,n,i),{errors:t,valid:t.length===0,warnings:i}},Je=I,C=e=>Array.isArray(e)?e:[],Ue=(e,s,n)=>{const t=[];for(const i of C(e)){const a=i?.image;typeof a!="string"||!(a.startsWith("./")||a.startsWith("../")||a.startsWith("/")||a.includes("Dockerfile"))||h(a.startsWith("/")?a:b(s,a))||t.push(`containers image "${a}" does not exist (resolved relative to ${n}); create the Dockerfile or point image at a registry reference`)}return t},We=(e,s,n)=>s.length===0||!e.composesApp||ce(n)?[]:[`schema declares vector index(es) ${s.map(t=>`"${t}"`).join(", ")} but nothing chains .vectors(...) onto defineApp() (entry: ${e.path}) — \`ctx.vectors\` is then a throwing stub and buildWorkerOptions rejects EVERY request, /_lunora/health included. Add \`.vectors((env) => ({ ${String(s[0])}: env.<BINDING> }))\` to the chain.`],qe=(e,s)=>{const n=s.exports;if(n===void 0)return[];const t=[];for(const a of g(e.durable_objects?.bindings))typeof a.class_name=="string"&&a.class_name.length>0&&a.script_name===void 0&&t.push({className:a.class_name,label:"durable_objects.bindings"});for(const a of C(e.workflows))typeof a?.class_name=="string"&&a.class_name.length>0&&a.script_name===void 0&&t.push({className:a.class_name,label:"workflows"});return t.filter(a=>!n.has(a.className)).map(a=>`${a.label} declares class "${a.className}" but the worker entry (${s.path}) does not export it — wrangler refuses to bundle a Worker whose Durable Object classes are not exported. Re-export it from the module that defines it (\`export { ${a.className} } from "./…";\`), or add it to the app builder's own export (\`export const { ${a.className} } = app;\`).`)},Xe=e=>{const s=e.schemaDir??"lunora",n=K(e.projectRoot);if(!n){const u=`wrangler.jsonc not found in ${e.projectRoot}; create one declaring at least the SHARD durable object binding.`;return{problems:[u],report:{errors:[u],valid:!1,warnings:[]},wranglerPath:void 0}}const{parsed:t}=G(n);if(t===void 0){const u=`failed to parse ${n} as JSONC.`;return{problems:[u],report:{errors:[u],valid:!1,warnings:[]},wranglerPath:n}}const{error:i,merged:a}=x(t,e.environment);if(i!==void 0)return{problems:[i],report:{errors:[i],valid:!1,warnings:[]},wranglerPath:n};const{error:o,info:r}=B(e.projectRoot,s),d=I(t,r,e.environment);o!==void 0&&d.warnings.push(`schema parse failed in ${s}/schema.ts: ${o}`);const c=O(n),l=se(a.main,e.projectRoot,n);d.errors.push(...Ue(a.containers??[],c,n)),l!==void 0&&d.errors.push(...qe(a,l),...We(l,r?.vectorIndexNames??[],e.projectRoot));const f=a.assets?.directory;if(typeof f=="string"&&f.length>0){const u=f.startsWith("/")?f:b(c,f);h(u)||d.warnings.push(`assets.directory "${f}" does not exist yet — it is created by the client build; run the build before deploy`)}return d.valid=d.errors.length===0,{problems:d.errors,report:d,wranglerPath:n}};export{S as REQUIRED_COMPATIBILITY_DATE,Qe as REQUIRED_FLAG,x as mergeWranglerEnvironment,g as objectBindingEntries,v as stringEntries,Je as validateWrangler,I as validateWranglerConfig,Xe as validateWranglerProject,ze as withTailConsumer};
@@ -1 +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-DMTyRVyn.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};
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-uIPpAmD1.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};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lunora/config",
3
- "version": "1.0.0-alpha.206",
3
+ "version": "1.0.0-alpha.208",
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.169",
57
+ "@lunora/codegen": "1.0.0-alpha.171",
58
58
  "@lunora/container": "1.0.0-alpha.48",
59
59
  "@lunora/errors": "1.0.0-alpha.35",
60
- "@lunora/seed": "1.0.0-alpha.117",
60
+ "@lunora/seed": "1.0.0-alpha.119",
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{existsSync as f,readFileSync as L}from"node:fs";import{dirname as k,join as b,basename as I,extname as C}from"node:path";import{Project as B,Node as h}from"ts-morph";import{COMPOSED_WORKER_ENTRY as T,LUNORA_WORKER_VIRTUAL_ID as U,WORKER_ENTRY_FALLBACKS as W}from"./COMPOSED_WORKER_ENTRY-D8SuPTeb.mjs";import{discoverSchemaInfo as q}from"./discoverSchemaInfo-Bg2CUZXG.mjs";import{isCacheEnabled as F,WORKERS_CACHE_MIN_DATE as $}from"./WORKERS_CACHE_MIN_DATE-0k9ABJtF.mjs";import{findWranglerFile as K,readWranglerJsonc as P}from"./WRANGLER_FILES-UNW-xY5u.mjs";const G=new Set(["1","enabled","on","true","yes"]),V=e=>typeof e=="string"&&G.has(e.trim().toLowerCase()),E="2026-04-07",Be="web_socket_auto_reply_to_close",S=/^\d{4}-\d{2}-\d{2}$/,j=["containers","d1_databases","durable_objects","kv_namespaces","queues","r2_buckets","secrets_store_secrets","services","tail_consumers","vars","vectorize","workflows"],A=["assets","compatibility_date","exports","logpush","main","migrations","observability","placement"],w=(e,s)=>{if(s===void 0)return{merged:e,unverifiedKeys:[]};const n=e.env?.[s];if(n===void 0){const r=Object.keys(e.env??{}).toSorted((d,l)=>d.localeCompare(l)),c=r.length>0?` (declared: ${r.join(", ")}).`:" (no environments are declared).";return{error:`--env "${s}" names no environment declared in wrangler.jsonc's "env" block${c}`,merged:e,unverifiedKeys:[]}}const t={...e},i=Object.keys(n).filter(r=>r!=="env");for(const r of i)A.includes(r)&&(t[r]=n[r]);for(const r of j)t[r]=n[r];const a=new Set([...j,...A]),o=i.filter(r=>!a.has(r)).map(String);return{merged:t,unverifiedKeys:o}},Y=(e,s,n)=>{if(s.length===0)return;const t=e.vectorize??[],i=new Set(t.filter(Boolean).map(a=>a?.index_name));for(const a of s)i.has(a)||n.push(`schema declares vector index "${a}"; wrangler "vectorize" must include a binding with index_name "${a}"`)},H=new Set(["basic","dev","lite","standard","standard-1","standard-2","standard-3","standard-4"]),Q={disk_mb:2e4,memory_mib:12288,vcpu:4},z=(e,s,n)=>{const t=e.instance_type;if(t===void 0)return;if(typeof t=="string"){H.has(t)||n.push(`${s} has unknown instance_type "${t}" — expected lite, basic, standard-1..4, or a custom { vcpu, memory_mib, disk_mb } object`);return}for(const[r,c]of Object.entries(Q)){const d=t[r];d!==void 0&&(typeof d!="number"||d<=0||d>c)&&n.push(`${s} custom instance_type ${r} must be a positive number ≤ ${String(c)} (got ${String(d)})`)}const{disk_mb:i,memory_mib:a,vcpu:o}=t;if(typeof o=="number"&&typeof a=="number"&&a<o*3072&&n.push(`${s} custom instance_type needs ≥ 3 GiB (3072 MiB) memory per vCPU (got ${String(a)} MiB for ${String(o)} vCPU)`),typeof a=="number"&&typeof i=="number"){const r=Math.floor(a/1024*2e3);i>r&&n.push(`${s} custom instance_type allows ≤ 2 GB disk per GiB memory (≤ ${String(r)} MB for ${String(a)} MiB memory; got ${String(i)} MB)`)}},J=(e,s,n)=>{const{boundClasses:t,classKinds:i,errors:a,warnings:o}=n;if(!e||typeof e!="object"||typeof e.class_name!="string"||e.class_name.length===0){a.push(`${s} must have a non-empty "class_name" naming its container-enabled Durable Object class`);return}(typeof e.image!="string"||e.image.length===0)&&a.push(`${s} ("${e.class_name}") must have an "image" — a Dockerfile path or a registry reference`),t.has(e.class_name)||a.push(`${s} class "${e.class_name}" has no matching durable_objects binding — your dev server auto-reconciles this on startup; add { "name": "...", "class_name": "${e.class_name}" } to fix it by hand`);const r=i.get(e.class_name);r!=="sqlite"&&a.push(r==="classic"?`${s} class "${e.class_name}" is registered via "new_classes" but containers require SQLite-backed DOs — move it to "new_sqlite_classes"`:`${s} class "${e.class_name}" is missing from migrations — add a migration entry with "new_sqlite_classes": ["${e.class_name}"]`),z(e,`${s} ("${e.class_name}")`,a),e.max_instances===void 0&&o.push(`${s} ("${e.class_name}") declares no max_instances — set a cap so a traffic spike can't fan out unbounded container spend`)},m=e=>typeof e=="string"&&e.length>0,g=e=>Array.isArray(e)?e.filter(s=>s!==null&&typeof s=="object"):[],_=e=>Array.isArray(e)?e.filter(s=>m(s)):[],O=e=>{const s=new Map;for(const n of g(e)){for(const t of _(n.new_classes))s.set(t,"classic");for(const t of _(n.new_sqlite_classes))s.set(t,"sqlite");for(const t of g(n.renamed_classes))if(m(t.from)&&m(t.to)){const i=s.get(t.from)??"sqlite";s.delete(t.from),s.set(t.to,i)}for(const t of _(n.deleted_classes))s.delete(t)}return s},X=e=>new Set(O(e).keys()),Z=(e,s)=>{const n=X(e.migrations);for(const t of g(e.durable_objects?.bindings))t.script_name===void 0&&m(t.class_name)&&!n.has(t.class_name)&&s.push(`durable_objects.bindings declares class "${t.class_name}" but it is missing from migrations — add a migration entry with "new_sqlite_classes": ["${t.class_name}"] (or "new_classes" for a non-SQLite-backed class), or let the dev server auto-reconcile it on the next start`)},ee=(e,s,n)=>{if(e.containers===void 0)return;if(!Array.isArray(e.containers)){s.push("containers must be an array of { class_name, image, ... } entries");return}const t=e.containers;if(t.length===0)return;const i=new Set(g(e.durable_objects?.bindings).map(o=>o.class_name)),a=O(e.migrations);for(const[o,r]of t.entries())J(r,`containers[${String(o)}]`,{boundClasses:i,classKinds:a,errors:s,warnings:n});e.observability?.enabled!==!0&&n.push('containers are configured but observability is not enabled — container logs will not be captured (add { "observability": { "enabled": true } })')},v=e=>e,p=(e,s,n,t)=>{if(e!==void 0){if(!Array.isArray(e)){t.push(n.arrayMessage);return}for(const[i,a]of v(e).entries()){const o=`${s}[${String(i)}]`;if(!a||typeof a!="object"){t.push(n.objectMessage(o));continue}for(const r of n.fields)m(a[r.field])||t.push(r.message(o))}}},se={arrayMessage:"workflows must be an array of { name, binding, class_name } entries",fields:[{field:"binding",message:e=>`${e} must have a non-empty "binding" naming the Workflow binding (e.g. WORKFLOW_ORDER_PIPELINE)`},{field:"class_name",message:e=>`${e} must have a non-empty "class_name" naming the exported WorkflowEntrypoint class`},{field:"name",message:e=>`${e} must have a non-empty "name" naming the deployed workflow`}],objectMessage:e=>`${e} must be a { name, binding, class_name } object`},te={arrayMessage:"queues.producers must be an array of { binding, queue } entries",fields:[{field:"binding",message:e=>`${e} must have a non-empty "binding" naming the Queue producer (e.g. QUEUE_EMAIL)`},{field:"queue",message:e=>`${e} must have a non-empty "queue" naming the deployed queue`}],objectMessage:e=>`${e} must be a { binding, queue } object`},ne={arrayMessage:"queues.consumers must be an array of { queue } entries",fields:[{field:"queue",message:e=>`${e} must have a non-empty "queue" naming the consumed queue`}],objectMessage:e=>`${e} must be a { queue } object`},ie=(e,s)=>{if(e.queues!==void 0){if(typeof e.queues!="object"||Array.isArray(e.queues)){s.push("queues must be a { producers, consumers } object");return}p(e.queues.producers,"queues.producers",te,s),p(e.queues.consumers,"queues.consumers",ne,s)}},ae={arrayMessage:"secrets_store_secrets must be an array of { binding, store_id, secret_name } entries",fields:["binding","store_id","secret_name"].map(e=>({field:e,message:s=>`${s} must have a non-empty "${e}"`})),objectMessage:e=>`${e} must be a { binding, store_id, secret_name } object`},oe=[{arrayMessage:"kv_namespaces must be an array of { binding, id } entries",bindingMessage:e=>`${e} must have a non-empty "binding" naming the KV namespace binding`,hintField:"id",hintMessage:(e,s)=>`${e} ("${s}") has no "id" — run \`wrangler kv namespace create\` and set the namespace id, or the binding can't resolve`,key:"kv_namespaces"},{arrayMessage:"flagship must be an array of { binding, app_id } entries",bindingMessage:e=>`${e} must have a non-empty "binding" naming the Flagship binding`,hintField:"app_id",hintMessage:(e,s)=>`${e} ("${s}") has no "app_id" — create a Flagship app and set its id, or the binding can't resolve`,key:"flagship"},{arrayMessage:"hyperdrive must be an array of { binding, id } entries",bindingMessage:e=>`${e} must have a non-empty "binding" naming the Hyperdrive binding`,hintField:"id",hintMessage:(e,s)=>`${e} ("${s}") has no "id" — run \`wrangler hyperdrive create\` and set the id, or the binding can't connect`,key:"hyperdrive"},{arrayMessage:"pipelines must be an array of { binding, stream } entries",bindingMessage:e=>`${e} must have a non-empty "binding" naming the Pipelines binding`,hintField:["stream","pipeline"],hintMessage:(e,s)=>`${e} ("${s}") has no "stream" — run \`wrangler pipelines create <name>\` and set the stream name, or the binding can't resolve`,key:"pipelines"},{arrayMessage:"analytics_engine_datasets must be an array of { binding, dataset } entries",bindingMessage:e=>`${e} must have a non-empty "binding" naming the Analytics Engine binding`,hintField:"dataset",hintMessage:(e,s)=>`${e} ("${s}") has no "dataset" — it defaults to the binding name; set it explicitly to avoid drift`,key:"analytics_engine_datasets"}],re=(e,s,n,t)=>{const i=e[s.key];if(i!==void 0){if(!Array.isArray(i)){n.push(s.arrayMessage);return}for(const[a,o]of v(i).entries()){const r=`${s.key}[${String(a)}]`;if(!o||typeof o!="object"||!m(o.binding)){n.push(s.bindingMessage(r));continue}(typeof s.hintField=="string"?[s.hintField]:s.hintField).some(d=>m(o[d]))||t.push(s.hintMessage(r,o.binding))}}},ce=[{key:"browser",message:'browser must be an object with a non-empty "binding" (e.g. { "binding": "BROWSER" })'},{key:"images",message:'images must be an object with a non-empty "binding" (e.g. { "binding": "IMAGES" })'}],de=(e,s,n)=>{const t=e[s.key];t!==void 0&&(typeof t!="object"||t===null||Array.isArray(t)||!m(t.binding))&&n.push(s.message)},le=[{arrayMessage:"services must be an array of { binding, service, entrypoint? } entries",fields:[{field:"binding",message:e=>`${e} must have a non-empty "binding" naming the service binding`},{field:"service",message:e=>`${e} must have a non-empty "service" naming the target Worker`}],key:"services",objectMessage:e=>`${e} must be a { binding, service, entrypoint? } object`},{arrayMessage:"dispatch_namespaces must be an array of { binding, namespace } entries",fields:[{field:"binding",message:e=>`${e} must have a non-empty "binding"`},{field:"namespace",message:e=>`${e} must have a non-empty "namespace" naming the dispatch namespace`}],key:"dispatch_namespaces",objectMessage:e=>`${e} must be a { binding, namespace } object`},{arrayMessage:"mtls_certificates must be an array of { binding, certificate_id } entries",fields:[{field:"binding",message:e=>`${e} must have a non-empty "binding"`},{field:"certificate_id",message:e=>`${e} must have a non-empty "certificate_id" (upload via \`wrangler mtls-certificate upload\`)`}],key:"mtls_certificates",objectMessage:e=>`${e} must be a { binding, certificate_id } object`},{arrayMessage:"r2_buckets must be an array of { binding, bucket_name } entries",fields:[{field:"binding",message:e=>`${e} must have a non-empty "binding" naming the R2 bucket binding`},{field:"bucket_name",message:e=>`${e} must have a non-empty "bucket_name" naming the deployed bucket`}],key:"r2_buckets",objectMessage:e=>`${e} must be a { binding, bucket_name } object`}],me=(e,s)=>{const{d1_databases:n}=e;if(n!==void 0){if(!Array.isArray(n)){s.push("d1_databases must be an array of { binding, database_id | database_name } entries");return}for(const[t,i]of v(n).entries()){const a=`d1_databases[${String(t)}]`;if(!i||typeof i!="object"){s.push(`${a} must be a { binding, database_id | database_name } object`);continue}m(i.binding)||s.push(`${a} must have a non-empty "binding" naming the D1 binding`),!m(i.database_id)&&!m(i.database_name)&&s.push(`${a} must have a "database_id" or a "database_name" — run \`wrangler d1 create\` and set one, or the binding can't resolve`)}}},ue=(e,s,n)=>{const t=e.send_email;if(t===void 0)return;if(!Array.isArray(t)){s.push("send_email must be an array of { name, destination_address? } entries");return}const i=t;for(const[a,o]of i.entries())(!o||typeof o!="object"||typeof o.name!="string"||o.name.length===0)&&n.push(`send_email[${String(a)}] has no non-empty "name" naming the send-email binding — set one before deploying`)},ge=(e,s)=>{e.logpush!==void 0&&typeof e.logpush!="boolean"&&s.push('logpush must be a boolean (set "logpush": true to enable Cloudflare Logpush)')},R=new Set(["off","smart","targeted"]),fe=(e,s)=>{const{placement:n}=e;if(n===void 0)return;if(typeof n!="object"||n===null||Array.isArray(n)){s.push('placement must be an object (e.g. { "mode": "smart" })');return}const{mode:t}=n;t!==void 0&&(typeof t!="string"||!R.has(t))&&s.push(`placement.mode must be one of ${[...R].map(i=>`"${i}"`).join(", ")}`)},be=(e,s)=>{const{observability:n}=e;if(n===void 0)return;if(typeof n!="object"||Array.isArray(n)){s.push('observability must be an object (e.g. { "enabled": true, "head_sampling_rate": 1 })');return}const t=(i,a)=>{i!==void 0&&(typeof i!="number"||Number.isNaN(i)||i<0||i>1)&&s.push(`${a} must be a number in [0, 1] (the fraction of requests sampled)`)};t(n.head_sampling_rate,"observability.head_sampling_rate"),n.logs!==void 0&&(typeof n.logs!="object"||Array.isArray(n.logs)?s.push("observability.logs must be an object"):t(n.logs.head_sampling_rate,"observability.logs.head_sampling_rate"))},pe=(e,s)=>{const{cache:n}=e;if(n!==void 0){if(typeof n!="object"||n===null||Array.isArray(n)){s.push('cache must be an object (e.g. { "enabled": true })');return}n.enabled!==void 0&&typeof n.enabled!="boolean"&&s.push("cache.enabled must be a boolean (true or false)")}},he=(e,s)=>{const{exports:n}=e;if(n!==void 0){if(typeof n!="object"||n===null||Array.isArray(n)){s.push("exports must be an object keyed by entrypoint name");return}for(const[t,i]of Object.entries(n)){if(typeof i!="object"||i===null){s.push(`exports["${t}"] must be an object`);continue}i.type!==void 0&&typeof i.type!="string"&&s.push(`exports["${t}"].type must be a string`),i.cache!==void 0&&(typeof i.cache!="object"||i.cache===null||Array.isArray(i.cache)?s.push(`exports["${t}"].cache must be an object`):i.cache.enabled!==void 0&&typeof i.cache.enabled!="boolean"&&s.push(`exports["${t}"].cache.enabled must be a boolean`))}}},ye=(e,s)=>{const{assets:n}=e;if(n!==void 0){if(typeof n!="object"||Array.isArray(n)){s.push('assets must be an object (e.g. { "directory": "./dist/client", "binding": "ASSETS" })');return}(typeof n.directory!="string"||n.directory.length===0)&&s.push('assets must declare a non-empty "directory" pointing at the built client output (e.g. "./dist/client")'),n.binding!==void 0&&(typeof n.binding!="string"||n.binding.length===0)&&s.push('assets.binding must be a non-empty string (e.g. "ASSETS")'),n.html_handling!==void 0&&typeof n.html_handling!="string"&&s.push("assets.html_handling must be a string"),n.not_found_handling!==void 0&&typeof n.not_found_handling!="string"&&s.push("assets.not_found_handling must be a string")}},_e=(e,s)=>{const n=e.tail_consumers;if(n===void 0)return;if(!Array.isArray(n)){s.push("tail_consumers must be an array of { service, environment? } entries");return}const t=n;for(const[i,a]of t.entries())(!a||typeof a!="object"||typeof a.service!="string"||a.service.length===0)&&s.push(`tail_consumers[${String(i)}] must have a non-empty "service" naming the consumer Worker`)},Te=(e,s)=>{const n=e.tail_consumers??[];return n.some(i=>!!i&&i?.service===s.service&&i?.environment===s.environment)?e:{...e,tail_consumers:[...n,s]}},ve=(e,s)=>{const{vars:n}=e;if(!n||typeof n!="object")return;const t=n.LUNORA_ALLOWED_ORIGINS,i=n.LUNORA_CORS_ALLOW_CREDENTIALS,a=typeof t=="string"&&t.split(",").some(r=>r.trim()==="*"),o=V(i);a&&o&&s.push('vars.LUNORA_ALLOWED_ORIGINS includes a "*" wildcard while vars.LUNORA_CORS_ALLOW_CREDENTIALS is on — browsers reject this combination and it defeats the allowlist; name explicit origins or drop credentials')},y="LUNORA_ORIGIN_URL",$e=(e,s,n)=>{if(!g(e.durable_objects?.bindings).some(o=>o.class_name==="SchedulerDO"&&o.script_name===void 0)||m(e.vars?.[y]))return;const i=s===void 0?"vars":`env.${s}.vars`,a=s===void 0?"":` --env ${s}`;n.push(`durable_objects.bindings declares the SchedulerDO but ${i}.${y} is unset — the DO reads its dispatch origin from its own env and refuses to schedule without it, so every ctx.scheduler.runAfter/runAt fails with ORIGIN_NOT_CONFIGURED. Set ${i}.${y} to the worker's public URL, or \`wrangler secret put ${y}${a}\` (ignore this if it is already set as a secret or in the dashboard).`)},Ee=(e,s,n)=>{const{error:t,merged:i,unverifiedKeys:a}=w(e,s);return t!==void 0?{error:t,wrangler:i}:(a.length>0&&n.push(`env.${String(s)} overrides ${a.join(", ")}, which this validator doesn't have a verified inheritance rule for — validated against the TOP-LEVEL value only. Double-check ${a.length===1?"it":"them"} by hand for "${String(s)}".`),{wrangler:i})},N=(e,s,n)=>{const t=[],i=[];if(!e||typeof e!="object")return t.push("wrangler config is not a valid object"),{errors:t,valid:!1,warnings:i};const{error:a,wrangler:o}=Ee(e,n,i);if(a!==void 0)return t.push(a),{errors:t,valid:!1,warnings:i};g(o.durable_objects?.bindings).find(l=>l.name==="SHARD"&&l.class_name==="ShardDO")||t.push('durable_objects.bindings must include { "name": "SHARD", "class_name": "ShardDO" } — your dev server auto-reconciles this on startup, or add the binding manually'),Z(o,t);const d=o.compatibility_date??"";d&&!S.test(d)?t.push(`compatibility_date must be in YYYY-MM-DD format (got "${d}")`):d<E&&t.push(`compatibility_date must be >= "${E}" (got "${d||"<missing>"}")`),F(o)&&S.test(d)&&d<$&&t.push(`cache.enabled requires compatibility_date >= "${$}" (got "${d||"<missing>"}")`),s?.hasGlobalTable&&(g(o.d1_databases).find(x=>x.binding==="DB")||t.push('schema declares .global() tables; d1_databases must include a binding named "DB" — your dev server auto-reconciles this on startup, or add the binding manually')),me(o,t),Y(o,s?.vectorIndexNames??[],t),_e(o,t),ee(o,t,i),p(o.workflows,"workflows",se,t),ie(o,t),p(o.secrets_store_secrets,"secrets_store_secrets",ae,t);for(const l of oe)re(o,l,t,i);for(const l of le)p(o[l.key],l.key,l,t);for(const l of ce)de(o,l,t);return ue(o,t,i),ge(o,t),fe(o,t),be(o,t),ye(o,t),pe(o,t),he(o,t),ve(o,t),$e(o,n,i),{errors:t,valid:t.length===0,warnings:i}},Ue=N,M=e=>Array.isArray(e)?e:[],Se=(e,s,n)=>{const t=[];for(const i of M(e)){const a=i?.image;typeof a!="string"||!(a.startsWith("./")||a.startsWith("../")||a.startsWith("/")||a.includes("Dockerfile"))||f(a.startsWith("/")?a:b(s,a))||t.push(`containers image "${a}" does not exist (resolved relative to ${n}); create the Dockerfile or point image at a registry reference`)}return t},je=new Set([".cts",".mts",".ts",".tsx"]),Ae=(e,s,n)=>{const t=b(s,T);if(f(t))return t;if(e!==U){if(typeof e=="string"&&e.length>0){const i=b(k(n),e);return f(i)&&je.has(C(i))?i:void 0}return W.map(i=>b(s,i)).find(i=>f(i))}},D=(e,s)=>{if(h.isIdentifier(e)){s.add(e.getText());return}if(h.isObjectBindingPattern(e)||h.isArrayBindingPattern(e))for(const n of e.getElements())h.isBindingElement(n)&&D(n.getNameNode(),s)},Re=(e,s)=>{let n=!1;for(const t of e.getExportDeclarations())if(!t.isTypeOnly()){if(t.isNamespaceExport()){const i=t.getNamespaceExport();i===void 0?n=!0:s.add(i.getName());continue}for(const i of t.getNamedExports())i.isTypeOnly()||s.add(i.getAliasNode()?.getText()??i.getName())}return n},ke=(e,s)=>{for(const n of e.getVariableStatements().filter(t=>t.getExportKeyword()!==void 0))for(const t of n.getDeclarations())D(t.getNameNode(),s);for(const n of[...e.getClasses(),...e.getFunctions(),...e.getEnums()]){const t=n.getExportKeyword()!==void 0&&!n.isDefaultExport()?n.getName():void 0;t!==void 0&&s.add(t)}},we=(e,s)=>{const n=new B({compilerOptions:{allowJs:!0},skipFileDependencyResolution:!0,skipLoadingLibFiles:!0,useInMemoryFileSystem:!0}),t=n.createSourceFile(e,s,{overwrite:!0});if(n.getProgram().compilerObject.getSyntacticDiagnostics(t.compilerNode).length>0)return;const i=new Set;if(!Re(t,i))return ke(t,i),i},Oe=(e,s,n)=>{const t=Ae(e.main,s,n);if(t===void 0)return[];let i;try{i=L(t,"utf8")}catch{return[]}const a=we(I(t),i);if(a===void 0)return[];const o=[];for(const c of g(e.durable_objects?.bindings))typeof c.class_name=="string"&&c.class_name.length>0&&c.script_name===void 0&&o.push({className:c.class_name,label:"durable_objects.bindings"});for(const c of M(e.workflows))typeof c?.class_name=="string"&&c.class_name.length>0&&c.script_name===void 0&&o.push({className:c.class_name,label:"workflows"});return o.filter(c=>!a.has(c.className)).map(c=>`${c.label} declares class "${c.className}" but the worker entry (${t}) does not export it — wrangler refuses to bundle a Worker whose Durable Object classes are not exported. Re-export it from the module that defines it (\`export { ${c.className} } from "./…";\`), or add it to the app builder's own export (\`export const { ${c.className} } = app;\`).`)},We=e=>{const s=e.schemaDir??"lunora",n=K(e.projectRoot);if(!n){const u=`wrangler.jsonc not found in ${e.projectRoot}; create one declaring at least the SHARD durable object binding.`;return{problems:[u],report:{errors:[u],valid:!1,warnings:[]},wranglerPath:void 0}}const{parsed:t}=P(n);if(t===void 0){const u=`failed to parse ${n} as JSONC.`;return{problems:[u],report:{errors:[u],valid:!1,warnings:[]},wranglerPath:n}}const{error:i,merged:a}=w(t,e.environment);if(i!==void 0)return{problems:[i],report:{errors:[i],valid:!1,warnings:[]},wranglerPath:n};const{error:o,info:r}=q(e.projectRoot,s),c=N(t,r,e.environment);o!==void 0&&c.warnings.push(`schema parse failed in ${s}/schema.ts: ${o}`);const d=k(n);c.errors.push(...Se(a.containers??[],d,n),...Oe(a,e.projectRoot,n));const l=a.assets?.directory;if(typeof l=="string"&&l.length>0){const u=l.startsWith("/")?l:b(d,l);f(u)||c.warnings.push(`assets.directory "${l}" does not exist yet — it is created by the client build; run the build before deploy`)}return c.valid=c.errors.length===0,{problems:c.errors,report:c,wranglerPath:n}};export{E as REQUIRED_COMPATIBILITY_DATE,Be as REQUIRED_FLAG,w as mergeWranglerEnvironment,g as objectBindingEntries,_ as stringEntries,Ue as validateWrangler,N as validateWranglerConfig,We as validateWranglerProject,Te as withTailConsumer};