@calo-design/cli 0.13.3 → 0.13.5

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.
Files changed (2) hide show
  1. package/bin/backend.js +32 -4
  2. package/package.json +1 -1
package/bin/backend.js CHANGED
@@ -104,6 +104,30 @@ function recipesDir(root) {
104
104
 
105
105
  const listRecipes = (dir) => fs.readdirSync(dir).filter((r) => fs.existsSync(path.join(dir, r, "recipe.json")));
106
106
 
107
+ // Which resources a worker/ dir needs, inferred from the bindings its code references
108
+ // (env.DB → d1, env.KV → kv, env.BUCKET → r2). Used on the reconnect/fork path where
109
+ // there's no recipe.json to read — a fork of ANY recipe provisions the right resources,
110
+ // not just d1. Scans worker source (skips migrations/); migrations also imply d1.
111
+ function inferResources(workerDir) {
112
+ const kinds = new Set();
113
+ const scan = (d) => {
114
+ for (const e of fs.readdirSync(d, { withFileTypes: true })) {
115
+ const p = path.join(d, e.name);
116
+ if (e.isDirectory()) {
117
+ if (e.name === "migrations") kinds.add("d1");
118
+ else scan(p);
119
+ } else if (/\.(js|ts|mjs)$/.test(e.name)) {
120
+ const src = fs.readFileSync(p, "utf8");
121
+ if (/\benv\.DB\b/.test(src)) kinds.add("d1");
122
+ if (/\benv\.KV\b/.test(src)) kinds.add("kv");
123
+ if (/\benv\.BUCKET\b/.test(src)) kinds.add("r2");
124
+ }
125
+ }
126
+ };
127
+ try { scan(workerDir); } catch {}
128
+ return [...kinds];
129
+ }
130
+
107
131
  // --- verbs ----------------------------------------------------------------------------
108
132
 
109
133
  // Scaffold (recipe → worker/) + provision + write backend.json + glue. One command in
@@ -137,8 +161,10 @@ async function cmdInit(args) {
137
161
  } else {
138
162
  log(c.dim(`worker/ already exists — ${existing ? "re-checking provisioning" : "reconnecting it to a provisioned backend"}`));
139
163
  recipe = recipe || (existing && existing.recipe) || undefined;
140
- // Infer the resource need from the code we have: migrations D1.
141
- if (fs.existsSync(path.join(workerDir, "migrations"))) recipeResources = ["d1"];
164
+ // Infer resource needs from what the worker code actually BINDS env.DB (d1),
165
+ // env.KV (kv), env.BUCKET (r2) so a fork of any recipe (or a hand-written worker)
166
+ // provisions the right resources. (Migrations imply d1 too, as a belt.)
167
+ recipeResources = inferResources(workerDir);
142
168
  }
143
169
 
144
170
  // Provision. When we hold no backend.json we always ask for a key: for a brand-new
@@ -166,9 +192,11 @@ async function cmdInit(args) {
166
192
  warn("app key was re-minted for this reconnect — run `calo-design backend deploy` to activate it");
167
193
  }
168
194
 
169
- // Glue: the one sanctioned way app code reaches the backend.
195
+ // Glue: the one sanctioned way app code reaches the backend. Always generated —
196
+ // Expo Router projects that only use app/ still get src/backend.ts.
170
197
  const glue = path.join(root, "src", "backend.ts");
171
- if (fs.existsSync(path.join(root, "src")) && !fs.existsSync(glue)) {
198
+ if (!fs.existsSync(glue)) {
199
+ fs.mkdirSync(path.join(root, "src"), { recursive: true });
172
200
  fs.writeFileSync(
173
201
  glue,
174
202
  `// Generated by \`calo-design backend init\` — app code talks to this prototype's\n` +
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@calo-design/cli",
3
- "version": "0.13.3",
3
+ "version": "0.13.5",
4
4
  "description": "One-line setup for Calo design tooling: logs in with your Calo email and installs the calo-design skill + design-system packages. No GitHub account needed.",
5
5
  "bin": {
6
6
  "calo-design": "bin/cli.js"