@lunora/config 1.0.0-alpha.103 → 1.0.0-alpha.104
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/README.md +2 -2
- package/dist/cloudflare/index.d.mts +628 -0
- package/dist/cloudflare/index.d.ts +628 -0
- package/dist/cloudflare/index.mjs +1 -0
- package/dist/index.d.mts +97 -723
- package/dist/index.d.ts +97 -723
- package/dist/index.mjs +1 -1
- package/dist/packem_shared/CLOUDFLARE_DRIVER-DqnWynqM.mjs +1 -0
- package/dist/packem_shared/DEFAULT_DEPLOY_TARGET-DDfyhjj8.mjs +1 -0
- package/dist/packem_shared/LUNORA_CONFIG_FILE-DVkEe5L6.mjs +1 -0
- package/dist/packem_shared/{inferLunoraBindings-B2y-19KL.mjs → inferLunoraBindings-BP-OTizO.mjs} +1 -1
- package/dist/packem_shared/schema-info.d-DS0bUsWE.d.mts +375 -0
- package/dist/packem_shared/schema-info.d-DS0bUsWE.d.ts +375 -0
- package/dist/packem_shared/wranglerToAlchemy-Fh5KfTPB.mjs +6 -0
- package/package.json +7 -3
- package/dist/packem_shared/LUNORA_CONFIG_FILE-3bpx6TZN.mjs +0 -1
package/dist/index.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{AGENT_MODE_ENV as
|
|
1
|
+
import{AGENT_MODE_ENV as t,detectAiAgent as o}from"./packem_shared/AGENT_MODE_ENV-B54hVQ_w.mjs";import{discoverAgentInfo as E}from"./packem_shared/discoverAgentInfo-BJm0QtoI.mjs";import{AGENT_RULES_DIR as _,AGENT_RULES_HINT as s,AGENT_RULES_HINT_ENV as p,LUNORA_SKILL_NAMES as c,ROOT_SKILL_NAME as l,claimAgentRulesHint as n,detectAgentRules as d}from"./packem_shared/AGENT_RULES_DIR-hP9TiDNx.mjs";import{discoverContainerInfo as A}from"./packem_shared/discoverContainerInfo-CYG9j2LY.mjs";import{streamContainerLogs as f}from"./packem_shared/streamContainerLogs-BPYBNrWS.mjs";import{detectFramework as L,readProjectDependencyNames as N}from"./packem_shared/detectFramework-VTQfCNXy.mjs";import{DEV_DAEMON_ENV as T,DEV_HANDOFF_ENV as R,DEV_LOG_FILE as I,DEV_LOG_FILE_ENV as x,DEV_STATE_DIR as V,DEV_STATE_FILE as P,claimDevServerState as g,clearDevServerState as F,isProcessAlive as O,isRecordedProcessCurrent as u,readDevServerState as G,readLiveDevServerState as U,updateDevServerState as C,writeDevServerState as M}from"./packem_shared/DEV_DAEMON_ENV-D9Z83rlU.mjs";import{DEV_VARS_EXAMPLE_FILE as B,DEV_VARS_FILE as b,DEV_VARS_KEY_PATTERN as k,parseDevVariableEntries as w}from"./packem_shared/DEV_VARS_EXAMPLE_FILE-DX6xGbpr.mjs";import{DEFAULT_DEPLOY_TARGET as j,deployTargetIds as h,resolveDeployDriver as H}from"./packem_shared/DEFAULT_DEPLOY_TARGET-DDfyhjj8.mjs";import{inferLunoraBindings as W,packageNamesFromBindings as J}from"./packem_shared/inferLunoraBindings-BP-OTizO.mjs";import{LINKED_PROJECT_DIR as X,LINKED_PROJECT_FILE as z,readLinkedProject as Q,writeLinkedProject as Z}from"./packem_shared/LINKED_PROJECT_DIR-CMzUvj-1.mjs";import{LUNORA_EVENT_SOURCE as ee,formatLunoraEvent as re}from"./packem_shared/LUNORA_EVENT_SOURCE-ZclWASXS.mjs";import{default as oe}from"./packem_shared/LunoraReporter-BnXUqh8t.mjs";import{PACKAGE_SECRETS_REGISTRY as Ee,secretsForPackages as ie}from"./packem_shared/PACKAGE_SECRETS_REGISTRY-BgmvEPA-.mjs";import{LUNORA_CONFIG_FILE as se,interpretRemote as pe,readProjectRemotePreference as ce,readProjectTarget as le,resolveProjectTarget as ne,resolveTargetOrThrow as de}from"./packem_shared/LUNORA_CONFIG_FILE-DVkEe5L6.mjs";import{createConfirm as Ae,isInteractive as Se,promptMultiSelect as fe,promptSelect as De,promptText as Le,promptYesNo as Ne}from"./packem_shared/createConfirm-7IL0kZyE.mjs";import{buildPackageSecretsBlock as Te,ensureDevVariables as Re,ensureDevVarsExample as Ie,fillDevSecrets as xe,generateSecretValue as Ve,isMintableSecretKey as Pe,isPlaceholderValue as ge,planDevSecretsFill as Fe,planDevVariablesAugment as Oe,planDevVariablesScaffold as ue,requiredSecrets as Ge}from"./packem_shared/buildPackageSecretsBlock-BpvaZzQ8.mjs";import{applyAdditiveEdit as Ce,classifyEdit as Me}from"./packem_shared/applyAdditiveEdit-Cff30cSa.mjs";import{parseSchema as Be}from"./packem_shared/parseSchema-BQjgz6bk.mjs";import{classifyPolicyEdit as ke,scaffoldPolicyFile as we,wireRlsIntoProcedure as Ke}from"./packem_shared/classifyPolicyEdit-BzC_MfYK.mjs";import{discoverSchemaInfo as he}from"./packem_shared/discoverSchemaInfo-C8X9mo-i.mjs";import{ACCENT as Ye,BADGES as We,BADGE_COLUMN_WIDTH as Je,LUNA_ART as qe,LUNA_BUNNY as Xe,LUNA_NAME as ze,LUNA_SIGNOFF as Qe,STEP_BADGE_NAMES as Ze,badgeLead as $e,badgeWidth as er,padBadge as rr,paintAnswer as tr,paintBadge as or}from"./packem_shared/ACCENT-CLeV5v0K.mjs";import{discoverWorkflowInfo as Er}from"./packem_shared/discoverWorkflowInfo-Bbc0u2gE.mjs";export{Ye as ACCENT,t as AGENT_MODE_ENV,_ as AGENT_RULES_DIR,s as AGENT_RULES_HINT,p as AGENT_RULES_HINT_ENV,We as BADGES,Je as BADGE_COLUMN_WIDTH,j as DEFAULT_DEPLOY_TARGET,T as DEV_DAEMON_ENV,R as DEV_HANDOFF_ENV,I as DEV_LOG_FILE,x as DEV_LOG_FILE_ENV,V as DEV_STATE_DIR,P as DEV_STATE_FILE,B as DEV_VARS_EXAMPLE_FILE,b as DEV_VARS_FILE,k as DEV_VARS_KEY_PATTERN,X as LINKED_PROJECT_DIR,z as LINKED_PROJECT_FILE,qe as LUNA_ART,Xe as LUNA_BUNNY,ze as LUNA_NAME,Qe as LUNA_SIGNOFF,se as LUNORA_CONFIG_FILE,ee as LUNORA_EVENT_SOURCE,c as LUNORA_SKILL_NAMES,oe as LunoraReporter,Ee as PACKAGE_SECRETS_REGISTRY,l as ROOT_SKILL_NAME,Ze as STEP_BADGE_NAMES,Ce as applyAdditiveEdit,$e as badgeLead,er as badgeWidth,Te as buildPackageSecretsBlock,n as claimAgentRulesHint,g as claimDevServerState,Me as classifyEdit,ke as classifyPolicyEdit,F as clearDevServerState,Ae as createConfirm,h as deployTargetIds,d as detectAgentRules,o as detectAiAgent,L as detectFramework,E as discoverAgentInfo,A as discoverContainerInfo,he as discoverSchemaInfo,Er as discoverWorkflowInfo,Re as ensureDevVariables,Ie as ensureDevVarsExample,xe as fillDevSecrets,re as formatLunoraEvent,Ve as generateSecretValue,W as inferLunoraBindings,pe as interpretRemote,Se as isInteractive,Pe as isMintableSecretKey,ge as isPlaceholderValue,O as isProcessAlive,u as isRecordedProcessCurrent,J as packageNamesFromBindings,rr as padBadge,tr as paintAnswer,or as paintBadge,w as parseDevVariableEntries,Be as parseSchema,Fe as planDevSecretsFill,Oe as planDevVariablesAugment,ue as planDevVariablesScaffold,fe as promptMultiSelect,De as promptSelect,Le as promptText,Ne as promptYesNo,G as readDevServerState,Q as readLinkedProject,U as readLiveDevServerState,N as readProjectDependencyNames,ce as readProjectRemotePreference,le as readProjectTarget,Ge as requiredSecrets,H as resolveDeployDriver,ne as resolveProjectTarget,de as resolveTargetOrThrow,we as scaffoldPolicyFile,ie as secretsForPackages,f as streamContainerLogs,C as updateDevServerState,Ke as wireRlsIntoProcedure,M as writeDevServerState,Z as writeLinkedProject};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{inferLunoraBindings as c}from"./inferLunoraBindings-BP-OTizO.mjs";import{reconcileWranglerBindings as p}from"./reconcileWranglerBindings-CHFT6zqp.mjs";import{reconcileWranglerCompatibilityDate as u}from"./reconcileWranglerCompatibilityDate-BXNiEQ7p.mjs";import{reconcileWranglerCrons as g}from"./reconcileWranglerCrons-BmQa_kGL.mjs";const m=(e,r)=>{const a=e.durableObjects.map(t=>({className:t.className,exported:!0,name:t.binding})),n=e.queues.map(t=>({name:t.name})),s=e.workflows.map(t=>({exported:t.exported,name:t.exportName}));return{containers:e.containers.map(t=>({exported:t.exported,name:t.exportName})),crons:[...r],globalDatabase:e.needsD1,keyValueStore:e.usesKv,objectStorage:e.usesStorage,queues:n,shardNamespaces:a,signals:[...e.signals],workflows:s}},i=(e,r)=>{try{const a=r();return{added:a.added??[],changed:a.changed,configPath:a.wranglerPath,warnings:a.warnings??[]}}catch(a){const n=a instanceof Error?a.message:String(a);return{added:[],changed:!1,warnings:[`${e} skipped: ${n}`]}}},l={deploy:e=>{const r=e.preview===!0?["versions","upload"]:["deploy"];return e.entry!==void 0&&r.push(e.entry),e.environment!==void 0&&r.push("--env",e.environment),e.temporary===!0&&r.push("--temporary"),e.dryRun===!0&&r.push("--dry-run"),e.outDir!==void 0&&r.push("--outdir",e.outDir,"--metafile"),{args:r,tool:"wrangler"}},dev:e=>{const r=["dev"];return e.configPath!==void 0&&r.push("--config",e.configPath),e.environment!==void 0&&r.push("--env",e.environment),r.push(...e.extraArgs??[]),{args:r,tool:"wrangler"}},secretList:e=>{const r=["secret","list","--format","json"];return e.environment!==void 0&&r.push("--env",e.environment),e.temporary===!0&&r.push("--temporary"),{args:r,tool:"wrangler"}},secretPut:e=>{const r=["secret","put",e.key??""];return e.environment!==void 0&&r.push("--env",e.environment),e.temporary===!0&&r.push("--temporary"),{args:r,tool:"wrangler"}},tail:e=>{const r=["tail"];return e.worker!==void 0&&r.push(e.worker),e.environment!==void 0&&r.push("--env",e.environment),e.format!==void 0&&r.push("--format",e.format),e.status!==void 0&&r.push("--status",e.status),e.search!==void 0&&r.push("--search",e.search),e.temporary===!0&&r.push("--temporary"),{args:r,tool:"wrangler"}}},w={id:"cloudflare",infer:async e=>{const r=await c({projectRoot:e.projectRoot});return m(r,e.crons??[])},name:"Cloudflare",provision:async e=>{const r=e.crons??[],a=await(async()=>{try{const o=await c({projectRoot:e.projectRoot});return i("binding inference",()=>p(e.projectRoot,o))}catch(o){const d=o instanceof Error?o.message:String(o);return{added:[],changed:!1,warnings:[`binding inference skipped: ${d}`]}}})(),n=i("compatibility date sync",()=>u(e.projectRoot)),s=i("cron trigger sync",()=>g(e.projectRoot,r)),t=[a,{...n,added:n.changed?["compatibility_date"]:[]},{...s,added:s.changed?[`${String(r.length)} cron trigger(s)`]:[]}];return{added:t.flatMap(o=>o.added),changed:t.some(o=>o.changed),configPath:t.find(o=>o.configPath!==void 0)?.configPath,warnings:t.flatMap(o=>o.warnings)}},toolchain:l};export{w as default};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import t from"./CLOUDFLARE_DRIVER-DqnWynqM.mjs";const a="cloudflare",r={cloudflare:t},l=()=>Object.keys(r).toSorted((e,o)=>e.localeCompare(o)),n=(e=a)=>{const o=r[e];if(o===void 0)throw new Error(`unknown deploy target "${e}" — available targets: ${l().join(", ")}`);return o};export{a as DEFAULT_DEPLOY_TARGET,l as deployTargetIds,n as resolveDeployDriver};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{existsSync as n,readFileSync as s}from"node:fs";import{readProjectTarget as i}from"@lunora/codegen";import{parse as l}from"jsonc-parser";import{DEFAULT_DEPLOY_TARGET as c,resolveDeployDriver as f}from"./DEFAULT_DEPLOY_TARGET-DDfyhjj8.mjs";import{join as m}from"node:path";const p="lunora.json",u=r=>{if(typeof r=="boolean")return r;if(r!==null&&typeof r=="object")return!0},j=r=>{const e=m(r,p);if(!n(e))return;let t;try{t=s(e,"utf8")}catch{return}const a=[],o=l(t,a,{allowTrailingComma:!0});if(!(a.length>0||o===null||typeof o!="object"))return o},E=r=>u(j(r)?.remote),T=r=>i(r),y=(r,e)=>e??T(r)??c,F=(r,e)=>{const t=y(r,e);return f(t),t};export{p as LUNORA_CONFIG_FILE,u as interpretRemote,E as readProjectRemotePreference,T as readProjectTarget,y as resolveProjectTarget,F as resolveTargetOrThrow};
|
package/dist/packem_shared/{inferLunoraBindings-B2y-19KL.mjs → inferLunoraBindings-BP-OTizO.mjs}
RENAMED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{existsSync as d,statSync as O,readFileSync as b,readdirSync as C}from"node:fs";import{init as T,parse as f}from"es-module-lexer";import{discoverAgentInfo as B}from"./discoverAgentInfo-BJm0QtoI.mjs";import{discoverContainerInfo as P}from"./discoverContainerInfo-CYG9j2LY.mjs";import{FLAGS_FILENAME as L,discoverFlags as K,QUEUES_FILENAME as M,discoverQueues as H}from"@lunora/codegen";import{Project as R}from"ts-morph";import{join as c}from"node:path";import{discoverSchemaInfo as q}from"./discoverSchemaInfo-C8X9mo-i.mjs";import{discoverWorkflowInfo as G}from"./discoverWorkflowInfo-Bbc0u2gE.mjs";import{WRANGLER_FILES as W,readWranglerJsonc as X}from"./WRANGLER_FILES-Bi_18Pj6.mjs";const U=(e,r)=>{const t=c(e,r,L);if(!d(t))return{};try{const s=new R({skipAddingFilesFromTsConfig:!0,useInMemoryFileSystem:!1});return{flags:K(s,c(e,r))}}catch(s){return{error:s instanceof Error?s.message:String(s)}}},Q=(e,r)=>{const t=c(e,r,M);if(!d(t))return{queues:[]};try{const s=new R({skipAddingFilesFromTsConfig:!0,useInMemoryFileSystem:!1});return{queues:H(s,c(e,r))}}catch(s){return{error:s instanceof Error?s.message:String(s),queues:[]}}},Y=new Set([".cjs",".cts",".js",".jsx",".mjs",".mts",".ts",".tsx"]),z=new Set([".git",".lunora-cache",".wrangler","_generated","dist","node_modules"]),J=["lunora","src"],V=["src/server/index.ts","src/server/index.tsx","src/index.ts","src/worker.ts"],k={SchedulerDO:"SCHEDULER",SessionDO:"SESSION",ShardDO:"SHARD"},$=Object.keys(k),Z={SchedulerDO:/\btype\s+SchedulerDO\b/,SessionDO:/\btype\s+SessionDO\b/,ShardDO:/\btype\s+ShardDO\b/},ee=/\benv\s*\.\s*DB\b/,re=/\benv\s*\.\s*AI\b/,A=/\bctx\s*\.\s*pipelines\b/,_=/^\s*import\s+type\b/,se=new Set(["@lunora/agent","@lunora/agent/sandbox"]),te=e=>{const r=e.indexOf("{");if(r===-1)return"";const t=e.indexOf("}",r+1);return t===-1?e.slice(r+1):e.slice(r+1,t)},ne=/\btype\s+browserTool\b/,oe=/\bbrowserTool\b/,ae=/import\s+\{[^}]*\bbrowserTool\b[^}]*\}\s+from\s+["']@lunora\/agent(?:\/sandbox)?["']/,ie=e=>{if(_.test(e))return!1;const r=te(e);return oe.test(r)&&!ne.test(r)},ce=e=>{try{const[r]=f(e);return r.some(t=>t.n!==void 0&&se.has(t.n)&&ie(e.slice(t.ss,t.se)))}catch{return ae.test(e)}},g={usesAi:{pattern:/\bfrom\s+["']@lunora\/ai["']/,source:"@lunora/ai"},usesAnalytics:{pattern:/\bfrom\s+["']@lunora\/bindings\/analytics["']/,source:"@lunora/bindings/analytics"},usesAuth:{pattern:/\bfrom\s+["']@lunora\/auth["']/,source:"@lunora/auth"},usesBrowser:{pattern:/\bfrom\s+["']@lunora\/browser["']/,source:"@lunora/browser"},usesHyperdrive:{pattern:/\bfrom\s+["']@lunora\/hyperdrive["']/,source:"@lunora/hyperdrive"},usesImages:{pattern:/\bfrom\s+["']@lunora\/bindings\/images["']/,source:"@lunora/bindings/images"},usesKv:{pattern:/\bfrom\s+["']@lunora\/bindings\/kv["']/,source:"@lunora/bindings/kv"},usesMail:{pattern:/\bfrom\s+["']@lunora\/mail["']/,source:"@lunora/mail"},usesPayment:{pattern:/\bfrom\s+["']@lunora\/payment["']/,source:"@lunora/payment"},usesPipelines:{pattern:A,source:"@lunora/bindings/pipelines"},usesScheduler:{pattern:/\bfrom\s+["']@lunora\/scheduler["']/,source:"@lunora/scheduler"},usesStorage:{pattern:/\bfrom\s+["']@lunora\/storage["']/,source:"@lunora/storage"},usesX402Charge:{pattern:/\bfrom\s+["']@lunora\/x402\/charge["']/,source:"@lunora/x402/charge"},usesX402Pay:{pattern:/\bfrom\s+["']@lunora\/x402\/pay["']/,source:"@lunora/x402/pay"}},p=Object.keys(g),ue="STRIPE_SECRET_KEY + STRIPE_WEBHOOK_SECRET (Stripe) or POLAR_ACCESS_TOKEN + POLAR_WEBHOOK_SECRET (Polar)",I=[...p,"needsD1"],de=()=>{const e={};for(const r of I)e[r]=!1;return e},l=Object.freeze(de()),y=(e,r)=>{const t={};for(const s of I)t[s]=e[s]||r[s];return t},le=e=>{for(const r of p)if(g[r].source===e)return{...l,[r]:!0};return l},pe=e=>{const[r]=f(e);let t=l;for(const s of r){const n=s.n;!n||_.test(e.slice(s.ss,s.se))||(t=y(t,le(n)))}return t},me=e=>{const r={...l};for(const t of p)r[t]=g[t].pattern.test(e);return r},be=e=>{let r;try{r=pe(e)}catch{r=me(e)}return y(r,{...l,needsD1:ee.test(e),usesAi:re.test(e),usesPipelines:A.test(e)})},S=(e,r)=>{let t;try{t=C(e,{withFileTypes:!0})}catch{return}for(const s of t){if(s.isDirectory()){z.has(s.name)||S(c(e,s.name),r);continue}const n=s.name.lastIndexOf(".");n!==-1&&Y.has(s.name.slice(n))&&r.push(c(e,s.name))}},fe=e=>{for(const r of W){const t=c(e,r);if(!d(t))continue;const{parsed:s}=X(t),n=s?.main;if(typeof n=="string"&&d(c(e,n)))return c(e,n);break}for(const r of V){const t=c(e,r);if(d(t))return t}},ge=e=>{const r=b(e,"utf8");let t;try{const[,s]=f(r);t=new Set(s.map(n=>n.n))}catch{t=new Set($.filter(s=>new RegExp(String.raw`\bexport\b[^\n;]*\b${s}\b`).test(r)))}return $.filter(s=>t.has(s)&&!Z[s].test(r)).map(s=>({binding:k[s],className:s}))},j=e=>e.replaceAll(/[$()*+.?[\\\]^{|}]/gu,String.raw`\$&`),he=/(?:^|[\s,{])type$/u,ye=(e,r)=>{const t=r.ls>=0?r.ls:r.s;return he.test(e.slice(0,t).trimEnd())},Se=(e,r)=>{const t=j(r);return new RegExp(String.raw`\bexport\s+type\s+${t}\b`,"u").test(e)||new RegExp(String.raw`\bexport\s+type\s*\{[^}]*\b${t}\b`,"u").test(e)||new RegExp(String.raw`\bexport\s+\{[^}]*\btype\s+${t}\b`,"u").test(e)},w=(e,r,t)=>{if(r.length===0)return[];if(e===void 0)return r.map(o=>({...o,exported:!1}));const s=b(e,"utf8"),n=new RegExp(String.raw`\bexport\s*\*\s*from\s*["'][^"']*_generated\/${t}(?:\.js)?["']`).test(s);let a;try{const[,o]=f(s);a=new Set(o.filter(i=>!ye(s,i)).map(i=>i.n))}catch{a=new Set(r.map(o=>o.className).filter(o=>new RegExp(String.raw`\bexport\b[^\n;]*\b${j(o)}\b`,"u").test(s)&&!Se(s,o)))}return r.map(o=>{const i=n||a.has(o.className);return{...o,exported:i}})},we=(e,r)=>w(e,r,"containers"),xe=(e,r)=>w(e,r,"workflows"),ve=(e,r)=>w(e,r,"agents"),Ee=(e,r)=>q(e,r).info?.hasGlobalTable??!1,Ne=(e,r)=>{let t=l;for(const s of r){const n=c(e,s);if(!d(n)||!O(n).isDirectory())continue;const a=[];S(n,a);for(const o of a)t=y(t,be(b(o,"utf8")))}return t},De=(e,r)=>{const t=c(e,r);if(!d(t)||!O(t).isDirectory())return!1;const s=[];return S(t,s),s.some(n=>ce(b(n,"utf8")))},$e=(e,r,t)=>[...e.map(s=>s.exported?`${s.bindingName}/${s.className} (container "${s.exportName}" declared and exported)`:`hint: container "${s.exportName}" is declared but ${s.className} is not exported by the worker entry — add \`export * from "./lunora/_generated/containers"\``),...r.map(s=>s.exported?`${s.bindingName}/${s.className} (workflow "${s.exportName}" declared and exported)`:`hint: workflow "${s.exportName}" is declared but ${s.className} is not exported by the worker entry — add \`export * from "./lunora/_generated/workflows"\``),...t.map(s=>s.exported?`${s.bindingName}/${s.className} (agent "${s.exportName}" declared and exported)`:`hint: agent "${s.exportName}" is declared but ${s.className} is not exported by the worker entry — add \`export * from "./lunora/_generated/agents"\``)],Oe=(e,r)=>[[e.usesAi,"AI (@lunora/ai imported or env.AI used)"],[e.usesAuth&&!r.has("SessionDO"),"hint: @lunora/auth is imported; its tables are D1-backed by default. For DO-backed auth (what @better-auth/scim needs), pass `namespace` to .auth() and export the generated auth DO class"],[e.usesScheduler&&!r.has("SchedulerDO"),"hint: @lunora/scheduler is imported but no SchedulerDO is exported by the worker entry"],[e.usesStorage,"hint: @lunora/storage is imported; add an r2_buckets binding (bucket binding names are user-defined)"],[e.usesMail,"hint: @lunora/mail is imported; set RESEND_API_KEY in .dev.vars (obtain at https://resend.com/api-keys)"],[e.usesPayment,`hint: @lunora/payment is imported; set the provider secrets in .dev.vars — ${ue}`],[e.usesBrowser,"browser (@lunora/browser imported) — self-describing { binding: BROWSER }"],[e.usesImages,"images (@lunora/bindings/images imported) — self-describing { binding: IMAGES }"],[e.usesAnalytics,"analytics_engine_datasets (@lunora/bindings/analytics imported) — self-describing { binding: ANALYTICS, dataset }"],[e.usesKv,"hint: @lunora/bindings/kv is imported; add a kv_namespaces binding ({ binding, id }) and pass env.<BINDING> to createKv() — the namespace id can't be auto-provisioned"],[e.usesHyperdrive,"hint: @lunora/hyperdrive is imported; run 'wrangler hyperdrive create' and add a 'hyperdrive' binding ({ binding, id }) — the id can't be auto-provisioned"],[e.usesPipelines,"hint: ctx.pipelines is used; run 'wrangler pipelines create <name>' and add a 'pipelines' binding ({ binding, pipeline }) — the pipeline resource can't be auto-provisioned"],[e.usesX402Charge,"hint: @lunora/x402/charge is imported; set the recipient wallet address as a [vars] entry (the var name is yours to choose) and pass it to the charge config — the x402 facilitator settles USDC to that address"],[e.usesX402Pay,"hint: @lunora/x402/pay is imported (ActionCtx-only, spends real funds); add a secrets_store_secrets[] binding for the agent wallet key (name it to match signer.secretName) and pair the pay rail with a spend policy — ctx.secrets reads a Secrets Store binding, not .dev.vars, so the key can't be auto-provisioned"]].filter(([t])=>t).map(([,t])=>t),Re=(e,r,t,s=[],n=[],a=[])=>{const o=new Set(e.map(u=>u.className)),i=e.map(u=>`${u.binding}/${u.className} (exported by worker entry)`);return r&&i.push("DB (.global() table declared)"),i.push(...$e(s,n,a),...Oe(t,o)),i},Le=async e=>{await T;const r=e.schemaDir??"lunora",t=e.scanDirs??J,s=Ne(e.projectRoot,t),n={...s,usesBrowser:s.usesBrowser||De(e.projectRoot,r)},a=fe(e.projectRoot),o=a?ge(a):[],i=n.needsD1||Ee(e.projectRoot,r),u=we(a,P(e.projectRoot,r).containers),x=xe(a,G(e.projectRoot,r).workflows),v=ve(a,B(e.projectRoot,r).agents),F=[...Q(e.projectRoot,r).queues],{flags:m}=U(e.projectRoot,r),h=m?.provider==="flagship"&&m.mode==="binding"?m.bindingName:void 0,E={};for(const D of p)E[D]=n[D];const N=Re(o,i,n,u,x,v);return h!==void 0&&N.push(`hint: lunora/flags.ts uses Flagship in binding mode; add a flagship binding ({ binding: "${h}", app_id }) — the app_id can't be auto-provisioned`),{agents:v,containers:u,durableObjects:o,flagshipBinding:h,needsD1:i,queues:F,signals:N,usesFlags:m!==void 0,workflows:x,...E}},Ke=e=>{const r=[];for(const t of p)e[t]&&r.push(g[t].source);return r};export{Le as inferLunoraBindings,Ke as packageNamesFromBindings};
|
|
1
|
+
import{existsSync as d,statSync as O,readFileSync as b,readdirSync as C}from"node:fs";import{init as T,parse as f}from"es-module-lexer";import{discoverAgentInfo as B}from"./discoverAgentInfo-BJm0QtoI.mjs";import{WRANGLER_FILES as P,readWranglerJsonc as L}from"./WRANGLER_FILES-Bi_18Pj6.mjs";import{discoverContainerInfo as K}from"./discoverContainerInfo-CYG9j2LY.mjs";import{FLAGS_FILENAME as M,discoverFlags as H,QUEUES_FILENAME as q,discoverQueues as G}from"@lunora/codegen";import{Project as R}from"ts-morph";import{join as c}from"node:path";import{discoverSchemaInfo as W}from"./discoverSchemaInfo-C8X9mo-i.mjs";import{discoverWorkflowInfo as X}from"./discoverWorkflowInfo-Bbc0u2gE.mjs";const U=(e,r)=>{const t=c(e,r,M);if(!d(t))return{};try{const s=new R({skipAddingFilesFromTsConfig:!0,useInMemoryFileSystem:!1});return{flags:H(s,c(e,r))}}catch(s){return{error:s instanceof Error?s.message:String(s)}}},Q=(e,r)=>{const t=c(e,r,q);if(!d(t))return{queues:[]};try{const s=new R({skipAddingFilesFromTsConfig:!0,useInMemoryFileSystem:!1});return{queues:G(s,c(e,r))}}catch(s){return{error:s instanceof Error?s.message:String(s),queues:[]}}},Y=new Set([".cjs",".cts",".js",".jsx",".mjs",".mts",".ts",".tsx"]),z=new Set([".git",".lunora-cache",".wrangler","_generated","dist","node_modules"]),J=["lunora","src"],V=["src/server/index.ts","src/server/index.tsx","src/index.ts","src/worker.ts"],k={SchedulerDO:"SCHEDULER",SessionDO:"SESSION",ShardDO:"SHARD"},$=Object.keys(k),Z={SchedulerDO:/\btype\s+SchedulerDO\b/,SessionDO:/\btype\s+SessionDO\b/,ShardDO:/\btype\s+ShardDO\b/},ee=/\benv\s*\.\s*DB\b/,re=/\benv\s*\.\s*AI\b/,A=/\bctx\s*\.\s*pipelines\b/,_=/^\s*import\s+type\b/,se=new Set(["@lunora/agent","@lunora/agent/sandbox"]),te=e=>{const r=e.indexOf("{");if(r===-1)return"";const t=e.indexOf("}",r+1);return t===-1?e.slice(r+1):e.slice(r+1,t)},ne=/\btype\s+browserTool\b/,oe=/\bbrowserTool\b/,ae=/import\s+\{[^}]*\bbrowserTool\b[^}]*\}\s+from\s+["']@lunora\/agent(?:\/sandbox)?["']/,ie=e=>{if(_.test(e))return!1;const r=te(e);return oe.test(r)&&!ne.test(r)},ce=e=>{try{const[r]=f(e);return r.some(t=>t.n!==void 0&&se.has(t.n)&&ie(e.slice(t.ss,t.se)))}catch{return ae.test(e)}},g={usesAi:{pattern:/\bfrom\s+["']@lunora\/ai["']/,source:"@lunora/ai"},usesAnalytics:{pattern:/\bfrom\s+["']@lunora\/bindings\/analytics["']/,source:"@lunora/bindings/analytics"},usesAuth:{pattern:/\bfrom\s+["']@lunora\/auth["']/,source:"@lunora/auth"},usesBrowser:{pattern:/\bfrom\s+["']@lunora\/browser["']/,source:"@lunora/browser"},usesHyperdrive:{pattern:/\bfrom\s+["']@lunora\/hyperdrive["']/,source:"@lunora/hyperdrive"},usesImages:{pattern:/\bfrom\s+["']@lunora\/bindings\/images["']/,source:"@lunora/bindings/images"},usesKv:{pattern:/\bfrom\s+["']@lunora\/bindings\/kv["']/,source:"@lunora/bindings/kv"},usesMail:{pattern:/\bfrom\s+["']@lunora\/mail["']/,source:"@lunora/mail"},usesPayment:{pattern:/\bfrom\s+["']@lunora\/payment["']/,source:"@lunora/payment"},usesPipelines:{pattern:A,source:"@lunora/bindings/pipelines"},usesScheduler:{pattern:/\bfrom\s+["']@lunora\/scheduler["']/,source:"@lunora/scheduler"},usesStorage:{pattern:/\bfrom\s+["']@lunora\/storage["']/,source:"@lunora/storage"},usesX402Charge:{pattern:/\bfrom\s+["']@lunora\/x402\/charge["']/,source:"@lunora/x402/charge"},usesX402Pay:{pattern:/\bfrom\s+["']@lunora\/x402\/pay["']/,source:"@lunora/x402/pay"}},p=Object.keys(g),ue="STRIPE_SECRET_KEY + STRIPE_WEBHOOK_SECRET (Stripe) or POLAR_ACCESS_TOKEN + POLAR_WEBHOOK_SECRET (Polar)",I=[...p,"needsD1"],de=()=>{const e={};for(const r of I)e[r]=!1;return e},l=Object.freeze(de()),y=(e,r)=>{const t={};for(const s of I)t[s]=e[s]||r[s];return t},le=e=>{for(const r of p)if(g[r].source===e)return{...l,[r]:!0};return l},pe=e=>{const[r]=f(e);let t=l;for(const s of r){const n=s.n;!n||_.test(e.slice(s.ss,s.se))||(t=y(t,le(n)))}return t},me=e=>{const r={...l};for(const t of p)r[t]=g[t].pattern.test(e);return r},be=e=>{let r;try{r=pe(e)}catch{r=me(e)}return y(r,{...l,needsD1:ee.test(e),usesAi:re.test(e),usesPipelines:A.test(e)})},S=(e,r)=>{let t;try{t=C(e,{withFileTypes:!0})}catch{return}for(const s of t){if(s.isDirectory()){z.has(s.name)||S(c(e,s.name),r);continue}const n=s.name.lastIndexOf(".");n!==-1&&Y.has(s.name.slice(n))&&r.push(c(e,s.name))}},fe=e=>{for(const r of P){const t=c(e,r);if(!d(t))continue;const{parsed:s}=L(t),n=s?.main;if(typeof n=="string"&&d(c(e,n)))return c(e,n);break}for(const r of V){const t=c(e,r);if(d(t))return t}},ge=e=>{const r=b(e,"utf8");let t;try{const[,s]=f(r);t=new Set(s.map(n=>n.n))}catch{t=new Set($.filter(s=>new RegExp(String.raw`\bexport\b[^\n;]*\b${s}\b`).test(r)))}return $.filter(s=>t.has(s)&&!Z[s].test(r)).map(s=>({binding:k[s],className:s}))},j=e=>e.replaceAll(/[$()*+.?[\\\]^{|}]/gu,String.raw`\$&`),he=/(?:^|[\s,{])type$/u,ye=(e,r)=>{const t=r.ls>=0?r.ls:r.s;return he.test(e.slice(0,t).trimEnd())},Se=(e,r)=>{const t=j(r);return new RegExp(String.raw`\bexport\s+type\s+${t}\b`,"u").test(e)||new RegExp(String.raw`\bexport\s+type\s*\{[^}]*\b${t}\b`,"u").test(e)||new RegExp(String.raw`\bexport\s+\{[^}]*\btype\s+${t}\b`,"u").test(e)},w=(e,r,t)=>{if(r.length===0)return[];if(e===void 0)return r.map(o=>({...o,exported:!1}));const s=b(e,"utf8"),n=new RegExp(String.raw`\bexport\s*\*\s*from\s*["'][^"']*_generated\/${t}(?:\.js)?["']`).test(s);let a;try{const[,o]=f(s);a=new Set(o.filter(i=>!ye(s,i)).map(i=>i.n))}catch{a=new Set(r.map(o=>o.className).filter(o=>new RegExp(String.raw`\bexport\b[^\n;]*\b${j(o)}\b`,"u").test(s)&&!Se(s,o)))}return r.map(o=>{const i=n||a.has(o.className);return{...o,exported:i}})},we=(e,r)=>w(e,r,"containers"),xe=(e,r)=>w(e,r,"workflows"),ve=(e,r)=>w(e,r,"agents"),Ee=(e,r)=>W(e,r).info?.hasGlobalTable??!1,Ne=(e,r)=>{let t=l;for(const s of r){const n=c(e,s);if(!d(n)||!O(n).isDirectory())continue;const a=[];S(n,a);for(const o of a)t=y(t,be(b(o,"utf8")))}return t},De=(e,r)=>{const t=c(e,r);if(!d(t)||!O(t).isDirectory())return!1;const s=[];return S(t,s),s.some(n=>ce(b(n,"utf8")))},$e=(e,r,t)=>[...e.map(s=>s.exported?`${s.bindingName}/${s.className} (container "${s.exportName}" declared and exported)`:`hint: container "${s.exportName}" is declared but ${s.className} is not exported by the worker entry — add \`export * from "./lunora/_generated/containers"\``),...r.map(s=>s.exported?`${s.bindingName}/${s.className} (workflow "${s.exportName}" declared and exported)`:`hint: workflow "${s.exportName}" is declared but ${s.className} is not exported by the worker entry — add \`export * from "./lunora/_generated/workflows"\``),...t.map(s=>s.exported?`${s.bindingName}/${s.className} (agent "${s.exportName}" declared and exported)`:`hint: agent "${s.exportName}" is declared but ${s.className} is not exported by the worker entry — add \`export * from "./lunora/_generated/agents"\``)],Oe=(e,r)=>[[e.usesAi,"AI (@lunora/ai imported or env.AI used)"],[e.usesAuth&&!r.has("SessionDO"),"hint: @lunora/auth is imported; its tables are D1-backed by default. For DO-backed auth (what @better-auth/scim needs), pass `namespace` to .auth() and export the generated auth DO class"],[e.usesScheduler&&!r.has("SchedulerDO"),"hint: @lunora/scheduler is imported but no SchedulerDO is exported by the worker entry"],[e.usesStorage,"hint: @lunora/storage is imported; add an r2_buckets binding (bucket binding names are user-defined)"],[e.usesMail,"hint: @lunora/mail is imported; set RESEND_API_KEY in .dev.vars (obtain at https://resend.com/api-keys)"],[e.usesPayment,`hint: @lunora/payment is imported; set the provider secrets in .dev.vars — ${ue}`],[e.usesBrowser,"browser (@lunora/browser imported) — self-describing { binding: BROWSER }"],[e.usesImages,"images (@lunora/bindings/images imported) — self-describing { binding: IMAGES }"],[e.usesAnalytics,"analytics_engine_datasets (@lunora/bindings/analytics imported) — self-describing { binding: ANALYTICS, dataset }"],[e.usesKv,"hint: @lunora/bindings/kv is imported; add a kv_namespaces binding ({ binding, id }) and pass env.<BINDING> to createKv() — the namespace id can't be auto-provisioned"],[e.usesHyperdrive,"hint: @lunora/hyperdrive is imported; run 'wrangler hyperdrive create' and add a 'hyperdrive' binding ({ binding, id }) — the id can't be auto-provisioned"],[e.usesPipelines,"hint: ctx.pipelines is used; run 'wrangler pipelines create <name>' and add a 'pipelines' binding ({ binding, pipeline }) — the pipeline resource can't be auto-provisioned"],[e.usesX402Charge,"hint: @lunora/x402/charge is imported; set the recipient wallet address as a [vars] entry (the var name is yours to choose) and pass it to the charge config — the x402 facilitator settles USDC to that address"],[e.usesX402Pay,"hint: @lunora/x402/pay is imported (ActionCtx-only, spends real funds); add a secrets_store_secrets[] binding for the agent wallet key (name it to match signer.secretName) and pair the pay rail with a spend policy — ctx.secrets reads a Secrets Store binding, not .dev.vars, so the key can't be auto-provisioned"]].filter(([t])=>t).map(([,t])=>t),Re=(e,r,t,s=[],n=[],a=[])=>{const o=new Set(e.map(u=>u.className)),i=e.map(u=>`${u.binding}/${u.className} (exported by worker entry)`);return r&&i.push("DB (.global() table declared)"),i.push(...$e(s,n,a),...Oe(t,o)),i},Le=async e=>{await T;const r=e.schemaDir??"lunora",t=e.scanDirs??J,s=Ne(e.projectRoot,t),n={...s,usesBrowser:s.usesBrowser||De(e.projectRoot,r)},a=fe(e.projectRoot),o=a?ge(a):[],i=n.needsD1||Ee(e.projectRoot,r),u=we(a,K(e.projectRoot,r).containers),x=xe(a,X(e.projectRoot,r).workflows),v=ve(a,B(e.projectRoot,r).agents),F=[...Q(e.projectRoot,r).queues],{flags:m}=U(e.projectRoot,r),h=m?.provider==="flagship"&&m.mode==="binding"?m.bindingName:void 0,E={};for(const D of p)E[D]=n[D];const N=Re(o,i,n,u,x,v);return h!==void 0&&N.push(`hint: lunora/flags.ts uses Flagship in binding mode; add a flagship binding ({ binding: "${h}", app_id }) — the app_id can't be auto-provisioned`),{agents:v,containers:u,durableObjects:o,flagshipBinding:h,needsD1:i,queues:F,signals:N,usesFlags:m!==void 0,workflows:x,...E}},Ke=e=>{const r=[];for(const t of p)e[t]&&r.push(g[t].source);return r};export{Le as inferLunoraBindings,Ke as packageNamesFromBindings};
|
|
@@ -0,0 +1,375 @@
|
|
|
1
|
+
import { AgentIR, ContainerIR, QueueIR, WorkflowIR } from '@lunora/codegen';
|
|
2
|
+
/**
|
|
3
|
+
* `DeployDriver` — the provider-neutral seam between what an app needs and
|
|
4
|
+
* how a host provides it (plan 114, §5.3).
|
|
5
|
+
*
|
|
6
|
+
* Configuration inference is two jobs welded together today. Deciding that an
|
|
7
|
+
* app needs a shard namespace, a queue, and an object-storage bucket is
|
|
8
|
+
* host-neutral: it falls out of the app's schema and imports, and every target
|
|
9
|
+
* reaches the same conclusion. Writing `durable_objects.bindings[]` into a
|
|
10
|
+
* `wrangler.jsonc` is not — it is one host's encoding of that conclusion.
|
|
11
|
+
*
|
|
12
|
+
* The split here names both halves. {@link ResourceGraph} is the neutral answer
|
|
13
|
+
* to "what does this app need?"; a {@link DeployDriver} turns that graph into
|
|
14
|
+
* one host's configuration and owns the host's toolchain surface. A second
|
|
15
|
+
* target implements the driver rather than forking the inference.
|
|
16
|
+
*
|
|
17
|
+
* Only the Cloudflare driver exists today (`cloudflare-driver.ts`), and it is
|
|
18
|
+
* deliberately thin: it delegates to the same `inferLunoraBindings` /
|
|
19
|
+
* `reconcileWrangler*` functions the CLI called directly before, so routing a
|
|
20
|
+
* command through the driver is behavior-preserving by construction.
|
|
21
|
+
*
|
|
22
|
+
* The second half is the **toolchain surface**: which command a host runs to
|
|
23
|
+
* deploy, serve, tail, or set a secret. A driver only *describes* that command
|
|
24
|
+
* ({@link ToolchainCommand}); it never spawns. The CLI keeps ownership of
|
|
25
|
+
* running it — package-manager resolution (`pnpm exec` / `npx --` / `bun x`)
|
|
26
|
+
* and the injected spawner its tests substitute — so the driver stays free of
|
|
27
|
+
* process concerns and remains trivially testable as a pure function.
|
|
28
|
+
*
|
|
29
|
+
* Each request type below is deliberately neutral: `preview`, `environment`,
|
|
30
|
+
* `temporary` are concepts, not wrangler flags. A second host maps the same
|
|
31
|
+
* request onto its own CLI without the caller changing.
|
|
32
|
+
*/
|
|
33
|
+
/** A durable, single-writer shard namespace (a Durable Object namespace on Cloudflare). */
|
|
34
|
+
interface ShardNamespaceResource {
|
|
35
|
+
/** The implementing class name the host binds to. */
|
|
36
|
+
className: string;
|
|
37
|
+
/** Whether the worker entry re-exports the class — an unexported class cannot be bound. */
|
|
38
|
+
exported: boolean;
|
|
39
|
+
/** The binding name the app reaches it through (e.g. `SHARD`). */
|
|
40
|
+
name: string;
|
|
41
|
+
}
|
|
42
|
+
/** A named resource the app declares and the host must provision (queue, workflow, container). */
|
|
43
|
+
interface NamedResource {
|
|
44
|
+
/** Whether the declaration is re-exported from the worker entry, where that applies. */
|
|
45
|
+
exported?: boolean;
|
|
46
|
+
/** The declared name. */
|
|
47
|
+
name: string;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* The provider-neutral statement of what an app needs, derived from its schema
|
|
51
|
+
* and imports. Every field is a *requirement*, not a host encoding: a driver
|
|
52
|
+
* decides what `objectStorage: true` means for its target.
|
|
53
|
+
*/
|
|
54
|
+
interface ResourceGraph {
|
|
55
|
+
/** Container images the app declares. */
|
|
56
|
+
containers: ReadonlyArray<NamedResource>;
|
|
57
|
+
/** Cron expressions the app schedules. */
|
|
58
|
+
crons: ReadonlyArray<string>;
|
|
59
|
+
/**
|
|
60
|
+
* The app declares a `.global()` table, so it needs a replicated SQL store
|
|
61
|
+
* (D1 on Cloudflare; Aurora/RDS elsewhere).
|
|
62
|
+
*/
|
|
63
|
+
globalDatabase: boolean;
|
|
64
|
+
/** The app reads or writes a key-value store. */
|
|
65
|
+
keyValueStore: boolean;
|
|
66
|
+
/** The app needs object storage (R2 on Cloudflare; S3-compatible elsewhere). */
|
|
67
|
+
objectStorage: boolean;
|
|
68
|
+
/** Queues the app declares. */
|
|
69
|
+
queues: ReadonlyArray<NamedResource>;
|
|
70
|
+
/** Shard namespaces the app needs. */
|
|
71
|
+
shardNamespaces: ReadonlyArray<ShardNamespaceResource>;
|
|
72
|
+
/**
|
|
73
|
+
* Human-readable provenance for each requirement — why inference concluded
|
|
74
|
+
* the app needs it. Surfaced in CLI logs; never load-bearing.
|
|
75
|
+
*/
|
|
76
|
+
signals: ReadonlyArray<string>;
|
|
77
|
+
/** Workflows the app declares. */
|
|
78
|
+
workflows: ReadonlyArray<NamedResource>;
|
|
79
|
+
}
|
|
80
|
+
/** The outcome of writing a {@link ResourceGraph} into a host's configuration. */
|
|
81
|
+
interface ProvisionResult {
|
|
82
|
+
/** Short labels for each resource written, for logging. */
|
|
83
|
+
added: ReadonlyArray<string>;
|
|
84
|
+
/** Whether the host's configuration file was rewritten. */
|
|
85
|
+
changed: boolean;
|
|
86
|
+
/** Resolved configuration path, when the host has one. */
|
|
87
|
+
configPath?: string;
|
|
88
|
+
/** Non-fatal hints for requirements the driver cannot auto-provision. */
|
|
89
|
+
warnings: ReadonlyArray<string>;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* A host CLI invocation, described but not run.
|
|
93
|
+
*
|
|
94
|
+
* `tool` is the binary name only (`"wrangler"`); the caller resolves how to
|
|
95
|
+
* execute it through the project's package manager. Keeping that split means a
|
|
96
|
+
* driver never has to know whether the project uses pnpm, npm, yarn, or bun.
|
|
97
|
+
*/
|
|
98
|
+
interface ToolchainCommand {
|
|
99
|
+
/** Arguments for {@link ToolchainCommand.tool}. */
|
|
100
|
+
args: ReadonlyArray<string>;
|
|
101
|
+
/** The host CLI binary, e.g. `"wrangler"`. */
|
|
102
|
+
tool: string;
|
|
103
|
+
}
|
|
104
|
+
/** Neutral options for a deploy. */
|
|
105
|
+
interface DeployRequest {
|
|
106
|
+
/** Validate and bundle without publishing — nothing ships. */
|
|
107
|
+
dryRun?: boolean;
|
|
108
|
+
/** Deploy this entry file instead of the host config's default (framework composition). */
|
|
109
|
+
entry?: string;
|
|
110
|
+
/** Named deployment environment, when the host supports them. */
|
|
111
|
+
environment?: string;
|
|
112
|
+
/** Write the built bundle (and any build metadata) to this directory. */
|
|
113
|
+
outDir?: string;
|
|
114
|
+
/** Upload a preview/versioned artifact instead of taking production traffic. */
|
|
115
|
+
preview?: boolean;
|
|
116
|
+
/** Deploy to a short-lived, unauthenticated account where the host offers one. */
|
|
117
|
+
temporary?: boolean;
|
|
118
|
+
}
|
|
119
|
+
/** Neutral options for a local dev server. */
|
|
120
|
+
interface DevRequest {
|
|
121
|
+
/** Host config file to run against, when the flow uses a generated one. */
|
|
122
|
+
configPath?: string;
|
|
123
|
+
/** Named environment. */
|
|
124
|
+
environment?: string;
|
|
125
|
+
/** Extra host-specific flags the caller has already resolved. */
|
|
126
|
+
extraArgs?: ReadonlyArray<string>;
|
|
127
|
+
}
|
|
128
|
+
/** Neutral options for tailing live logs. */
|
|
129
|
+
interface TailRequest {
|
|
130
|
+
/** Named environment. */
|
|
131
|
+
environment?: string;
|
|
132
|
+
/** Output format the host tail supports (`"json"`, `"pretty"`, …). */
|
|
133
|
+
format?: string;
|
|
134
|
+
/** Free-text filter. */
|
|
135
|
+
search?: string;
|
|
136
|
+
/** Status filter (`"error"`, `"ok"`, …). */
|
|
137
|
+
status?: string;
|
|
138
|
+
/** Tail a short-lived account's deployment. */
|
|
139
|
+
temporary?: boolean;
|
|
140
|
+
/** Tail a specific deployed worker/service by name, when the host addresses them individually. */
|
|
141
|
+
worker?: string;
|
|
142
|
+
}
|
|
143
|
+
/** Neutral options for reading or writing deployment secrets. */
|
|
144
|
+
interface SecretRequest {
|
|
145
|
+
/** Named environment. */
|
|
146
|
+
environment?: string;
|
|
147
|
+
/** The secret's name — required for `put`, unused for `list`. */
|
|
148
|
+
key?: string;
|
|
149
|
+
/** Operate against a short-lived account. */
|
|
150
|
+
temporary?: boolean;
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* The host's command-line surface. Optional as a whole: a host with no CLI (a
|
|
154
|
+
* hypothetical API-driven target) implements `infer`/`provision` only, and the
|
|
155
|
+
* caller falls back to its own handling.
|
|
156
|
+
*/
|
|
157
|
+
interface DriverToolchain {
|
|
158
|
+
/** The command that deploys the app. */
|
|
159
|
+
deploy: (request: DeployRequest) => ToolchainCommand;
|
|
160
|
+
/** The command that runs a local dev server. */
|
|
161
|
+
dev: (request: DevRequest) => ToolchainCommand;
|
|
162
|
+
/** The command that lists remote secret names. */
|
|
163
|
+
secretList: (request: SecretRequest) => ToolchainCommand;
|
|
164
|
+
/** The command that writes one secret. Its value is passed on stdin, never argv. */
|
|
165
|
+
secretPut: (request: SecretRequest) => ToolchainCommand;
|
|
166
|
+
/** The command that tails live logs. */
|
|
167
|
+
tail: (request: TailRequest) => ToolchainCommand;
|
|
168
|
+
}
|
|
169
|
+
/** Options every driver method receives. */
|
|
170
|
+
interface DriverContext {
|
|
171
|
+
/** Cron expressions codegen discovered, threaded in because they come from the app's code rather than its config. */
|
|
172
|
+
crons?: ReadonlyArray<string>;
|
|
173
|
+
/** Project root containing the `lunora/` directory. */
|
|
174
|
+
projectRoot: string;
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* A deploy target's implementation: report what the app needs, and encode it
|
|
178
|
+
* into that host's configuration.
|
|
179
|
+
*
|
|
180
|
+
* **Why `provision` does not take a {@link ResourceGraph}.** The obvious
|
|
181
|
+
* signature is `provision(graph, context)`, and it is wrong. Writing real host
|
|
182
|
+
* configuration needs the host's own encodings — binding names, DO class
|
|
183
|
+
* wiring, migration tags — which the neutral graph deliberately discards. A
|
|
184
|
+
* driver handed only the graph would have to re-derive them, so passing it
|
|
185
|
+
* would be decorative. `infer` is therefore the *reporting* surface (a portable
|
|
186
|
+
* picture of the app's requirements, for logs, diagnostics, and cross-target
|
|
187
|
+
* comparison) and `provision` is the *doing* surface, which owns its own
|
|
188
|
+
* inference end-to-end.
|
|
189
|
+
*
|
|
190
|
+
* That asymmetry is a genuine finding about this seam, not a shortcut: it says
|
|
191
|
+
* the neutral graph is not a sufficient intermediate representation for config
|
|
192
|
+
* emission. If a future target needs one, the graph must grow a host-extension
|
|
193
|
+
* escape hatch rather than pretend it already carries the detail.
|
|
194
|
+
*/
|
|
195
|
+
interface DeployDriver {
|
|
196
|
+
/** The target id this driver serves (`"cloudflare"`, …) — matches codegen's `target`. */
|
|
197
|
+
readonly id: string;
|
|
198
|
+
/**
|
|
199
|
+
* Read the app and report what it needs, in provider-neutral terms. Pure
|
|
200
|
+
* with respect to the project: it never writes configuration.
|
|
201
|
+
*/
|
|
202
|
+
infer: (context: DriverContext) => Promise<ResourceGraph>;
|
|
203
|
+
/** Human-readable target name, for logs. */
|
|
204
|
+
readonly name: string;
|
|
205
|
+
/**
|
|
206
|
+
* Write the app's requirements into the host's configuration, adding what is
|
|
207
|
+
* missing and leaving existing entries alone. Must be idempotent:
|
|
208
|
+
* provisioning an already-provisioned project reports `changed: false`, and
|
|
209
|
+
* must fold a failed step into a warning rather than throwing.
|
|
210
|
+
*/
|
|
211
|
+
provision: (context: DriverContext) => Promise<ProvisionResult>;
|
|
212
|
+
/**
|
|
213
|
+
* The host's command-line surface, or `undefined` for a host that has none.
|
|
214
|
+
* Pure: these build argv, they never spawn.
|
|
215
|
+
*/
|
|
216
|
+
readonly toolchain?: DriverToolchain;
|
|
217
|
+
}
|
|
218
|
+
interface DurableObjectSpec {
|
|
219
|
+
binding: string;
|
|
220
|
+
className: string;
|
|
221
|
+
}
|
|
222
|
+
/**
|
|
223
|
+
* A `defineContainer` declaration plus whether its generated DO class is
|
|
224
|
+
* exported by the worker entry. Only exported containers are safe to
|
|
225
|
+
* provision — wrangler rejects a `containers[].class_name` (and its Durable
|
|
226
|
+
* Object binding) that the worker doesn't export.
|
|
227
|
+
*/
|
|
228
|
+
interface InferredContainer extends ContainerIR {
|
|
229
|
+
exported: boolean;
|
|
230
|
+
}
|
|
231
|
+
/**
|
|
232
|
+
* A `defineWorkflow` declaration plus whether its generated
|
|
233
|
+
* `WorkflowEntrypoint` class is exported by the worker entry. Only exported
|
|
234
|
+
* workflows are safe to provision — wrangler rejects a `workflows[].class_name`
|
|
235
|
+
* the worker doesn't export. Workflows are NOT Durable Objects, so this never
|
|
236
|
+
* implies a `durable_objects` binding or migration.
|
|
237
|
+
*/
|
|
238
|
+
interface InferredWorkflow extends WorkflowIR {
|
|
239
|
+
exported: boolean;
|
|
240
|
+
}
|
|
241
|
+
/**
|
|
242
|
+
* A `defineAgent` declaration plus whether its generated agent
|
|
243
|
+
* `WorkflowEntrypoint` class (e.g. `SupportAgentWorkflow`) is exported by the
|
|
244
|
+
* worker entry. An agent compiles onto a Cloudflare Workflow, so — exactly like
|
|
245
|
+
* {@link InferredWorkflow} — only exported agents are safe to provision
|
|
246
|
+
* (wrangler rejects a `workflows[].class_name` the worker doesn't export), and
|
|
247
|
+
* an agent is NOT a Durable Object (no `durable_objects` binding or migration).
|
|
248
|
+
*/
|
|
249
|
+
interface InferredAgent extends AgentIR {
|
|
250
|
+
exported: boolean;
|
|
251
|
+
}
|
|
252
|
+
/**
|
|
253
|
+
* A queue declared in `lunora/queues.ts`. Unlike workflows, a queue needs no
|
|
254
|
+
* worker-entry class export (its `queue()` handler rides `createWorker`), so
|
|
255
|
+
* there is no `exported` flag — every declared queue is reconcilable into the
|
|
256
|
+
* wrangler `queues.producers[]` / `queues.consumers[]`.
|
|
257
|
+
*/
|
|
258
|
+
type InferredQueue = QueueIR;
|
|
259
|
+
interface InferredBindings {
|
|
260
|
+
/** Agents declared in `lunora/agents.ts` (exported or not — see {@link InferredAgent.exported}); reconciled into `workflows[]`. */
|
|
261
|
+
agents: InferredAgent[];
|
|
262
|
+
/** Containers declared in `lunora/containers.ts` (exported or not — see {@link InferredContainer.exported}). */
|
|
263
|
+
containers: InferredContainer[];
|
|
264
|
+
/** Durable Objects the worker entry exports → safe to bind. */
|
|
265
|
+
durableObjects: DurableObjectSpec[];
|
|
266
|
+
/**
|
|
267
|
+
* The wrangler `flagship[].binding` name implied by `lunora/flags.ts` when it
|
|
268
|
+
* uses the Flagship provider in binding mode — `undefined` for HTTP-mode
|
|
269
|
+
* Flagship, a custom OpenFeature provider, or no flags. The binding needs an
|
|
270
|
+
* un-mintable `app_id`, so it is reconciled as a hint, not auto-written.
|
|
271
|
+
*/
|
|
272
|
+
flagshipBinding?: string;
|
|
273
|
+
/** Schema declares a `.global()` table → needs the `DB` D1 binding. */
|
|
274
|
+
needsD1: boolean;
|
|
275
|
+
/** Queues declared in `lunora/queues.ts` → reconciled into `queues.producers[]` / `queues.consumers[]`. */
|
|
276
|
+
queues: InferredQueue[];
|
|
277
|
+
/** Human-readable provenance for each inferred binding / hint, for logging. */
|
|
278
|
+
signals: string[];
|
|
279
|
+
/** `@lunora/ai` is imported or `env.AI` is used → needs the `ai` Workers AI binding. */
|
|
280
|
+
usesAi: boolean;
|
|
281
|
+
/** `@lunora/bindings/analytics` is imported → self-describing `analytics_engine_datasets` binding (auto-writeable). */
|
|
282
|
+
usesAnalytics: boolean;
|
|
283
|
+
/** `@lunora/auth` is imported (sessions may be D1- or `SessionDO`-backed). */
|
|
284
|
+
usesAuth: boolean;
|
|
285
|
+
/** `@lunora/browser` is imported → self-describing `browser` binding (auto-writeable). */
|
|
286
|
+
usesBrowser: boolean;
|
|
287
|
+
/** `lunora/flags.ts` declares a feature-flag provider (any OpenFeature provider — Flagship or custom). */
|
|
288
|
+
usesFlags: boolean;
|
|
289
|
+
/** `@lunora/hyperdrive` is imported (binding needs an un-mintable remote `id`; hint-only). */
|
|
290
|
+
usesHyperdrive: boolean;
|
|
291
|
+
/** `@lunora/bindings/images` is imported → self-describing `images` binding (auto-writeable). */
|
|
292
|
+
usesImages: boolean;
|
|
293
|
+
/** `@lunora/bindings/kv` is imported (namespace binding name + id are user-defined; hint-only). */
|
|
294
|
+
usesKv: boolean;
|
|
295
|
+
/** `@lunora/mail` is imported (Resend API key must be set in `.dev.vars`; no binding). */
|
|
296
|
+
usesMail: boolean;
|
|
297
|
+
/** `@lunora/payment` is imported (provider secrets must be set in `.dev.vars`; no binding). */
|
|
298
|
+
usesPayment: boolean;
|
|
299
|
+
/** `ctx.pipelines` is used (binding needs an un-mintable remote pipeline name; hint-only). */
|
|
300
|
+
usesPipelines: boolean;
|
|
301
|
+
/** `@lunora/scheduler` is imported. */
|
|
302
|
+
usesScheduler: boolean;
|
|
303
|
+
/** `@lunora/storage` is imported (R2 bucket binding name is user-defined). */
|
|
304
|
+
usesStorage: boolean;
|
|
305
|
+
/** `@lunora/x402/charge` is imported — the charge rail settles USDC to a recipient address (a public `[vars]` entry, user-named; hint-only). */
|
|
306
|
+
usesX402Charge: boolean;
|
|
307
|
+
/** `@lunora/x402/pay` is imported — the agent-wallet pay rail signs from a Secrets Store binding paired with a spend policy (ActionCtx-only; hint-only). */
|
|
308
|
+
usesX402Pay: boolean;
|
|
309
|
+
/** Workflows declared in `lunora/workflows.ts` (exported or not — see {@link InferredWorkflow.exported}). */
|
|
310
|
+
workflows: InferredWorkflow[];
|
|
311
|
+
}
|
|
312
|
+
interface InferOptions {
|
|
313
|
+
projectRoot: string;
|
|
314
|
+
/** Directories (relative to root) to scan. Defaults to `lunora` + `src`. */
|
|
315
|
+
scanDirs?: ReadonlyArray<string>;
|
|
316
|
+
/** Lunora source directory holding `schema.ts`. Defaults to `lunora`. */
|
|
317
|
+
schemaDir?: string;
|
|
318
|
+
}
|
|
319
|
+
/**
|
|
320
|
+
* Scan a Lunora project and report which Cloudflare bindings its code implies.
|
|
321
|
+
* Read-only: performs no writes. Binding provisioning is driven by the worker
|
|
322
|
+
* entry's Durable Object exports plus the schema's D1 need; capability imports
|
|
323
|
+
* surface as hints.
|
|
324
|
+
*/
|
|
325
|
+
declare const inferLunoraBindings: (options: InferOptions) => Promise<InferredBindings>;
|
|
326
|
+
/**
|
|
327
|
+
* Derive the list of `@lunora/*` package names that are actively used by a
|
|
328
|
+
* project, based on its already-resolved {@link InferredBindings}.
|
|
329
|
+
*
|
|
330
|
+
* This is the canonical bridge between binding inference and the package-aware
|
|
331
|
+
* `.dev.vars.example` scaffolding in `scaffold-dev-variables.ts`. The result is
|
|
332
|
+
* a stable, predictable slice of {@link CAPABILITY_SOURCES} source values,
|
|
333
|
+
* filtered to the flags that are `true` in `bindings` — in CAPABILITY_SOURCES
|
|
334
|
+
* declaration order.
|
|
335
|
+
*/
|
|
336
|
+
declare const packageNamesFromBindings: (bindings: InferredBindings) => string[];
|
|
337
|
+
/** One filterable Vectorize metadata property a schema declares. */
|
|
338
|
+
interface VectorMetadataDeclaration {
|
|
339
|
+
/** The vector index the property belongs to. */
|
|
340
|
+
index: string;
|
|
341
|
+
/**
|
|
342
|
+
* The validator kind behind the column, or `undefined` when the column
|
|
343
|
+
* isn't in the owning table's shape. Callers map it to the Vectorize
|
|
344
|
+
* metadata type; a kind that can't be filtered on is reported, not indexed.
|
|
345
|
+
*/
|
|
346
|
+
kind: string | undefined;
|
|
347
|
+
/** Column mirrored into vector metadata. */
|
|
348
|
+
property: string;
|
|
349
|
+
}
|
|
350
|
+
interface SchemaInfo {
|
|
351
|
+
/** Whether the lunora schema declares any `.global()` table. */
|
|
352
|
+
hasGlobalTable: boolean;
|
|
353
|
+
/** Names of vector indexes declared via `.vectorize()` / `defineVectorIndex()`. */
|
|
354
|
+
vectorIndexNames?: ReadonlyArray<string>;
|
|
355
|
+
/**
|
|
356
|
+
* Metadata properties declared filterable on a vector index. Cloudflare
|
|
357
|
+
* needs an explicit metadata index per property before a `filter` can match
|
|
358
|
+
* anything, so deploy provisions these and doctor reports them.
|
|
359
|
+
*/
|
|
360
|
+
vectorMetadata?: ReadonlyArray<VectorMetadataDeclaration>;
|
|
361
|
+
}
|
|
362
|
+
interface DiscoverSchemaInfoResult {
|
|
363
|
+
/** Parse error message, when the schema exists but could not be analyzed. */
|
|
364
|
+
error?: string;
|
|
365
|
+
/** Schema facts, or `undefined` when no `schema.ts` exists or parsing failed. */
|
|
366
|
+
info: SchemaInfo | undefined;
|
|
367
|
+
}
|
|
368
|
+
/**
|
|
369
|
+
* Discover {@link SchemaInfo} for a project. Returns `{ info: undefined }` when
|
|
370
|
+
* the project declares no `schema.ts` (not an error), or `{ info: undefined,
|
|
371
|
+
* error }` when a present schema could not be parsed — callers decide whether a
|
|
372
|
+
* parse failure is a warning (validator) or simply ignorable (inference).
|
|
373
|
+
*/
|
|
374
|
+
declare const discoverSchemaInfo: (projectRoot: string, schemaDirectory: string) => DiscoverSchemaInfoResult;
|
|
375
|
+
export { DeployDriver as D, InferredBindings as I, NamedResource as N, ProvisionResult as P, ResourceGraph as R, SchemaInfo as S, TailRequest as T, DeployRequest as a, DevRequest as b, DiscoverSchemaInfoResult as c, DriverContext as d, DriverToolchain as e, InferOptions as f, InferredAgent as g, InferredContainer as h, InferredWorkflow as i, SecretRequest as j, ShardNamespaceResource as k, ToolchainCommand as l, discoverSchemaInfo as m, inferLunoraBindings as n, packageNamesFromBindings as p };
|