everything-dev 1.17.0 → 1.20.0

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 (52) hide show
  1. package/dist/cli/init.cjs +165 -84
  2. package/dist/cli/init.cjs.map +1 -1
  3. package/dist/cli/init.d.cts +14 -2
  4. package/dist/cli/init.d.cts.map +1 -1
  5. package/dist/cli/init.d.mts +14 -2
  6. package/dist/cli/init.d.mts.map +1 -1
  7. package/dist/cli/init.mjs +164 -85
  8. package/dist/cli/init.mjs.map +1 -1
  9. package/dist/cli/prompts.cjs +12 -14
  10. package/dist/cli/prompts.cjs.map +1 -1
  11. package/dist/cli/prompts.mjs +12 -14
  12. package/dist/cli/prompts.mjs.map +1 -1
  13. package/dist/cli/timing.cjs +21 -1
  14. package/dist/cli/timing.cjs.map +1 -1
  15. package/dist/cli/timing.mjs +21 -1
  16. package/dist/cli/timing.mjs.map +1 -1
  17. package/dist/cli/upgrade.cjs +114 -49
  18. package/dist/cli/upgrade.cjs.map +1 -1
  19. package/dist/cli/upgrade.mjs +114 -49
  20. package/dist/cli/upgrade.mjs.map +1 -1
  21. package/dist/contract.cjs +1 -4
  22. package/dist/contract.cjs.map +1 -1
  23. package/dist/contract.d.cts +4 -10
  24. package/dist/contract.d.cts.map +1 -1
  25. package/dist/contract.d.mts +4 -10
  26. package/dist/contract.d.mts.map +1 -1
  27. package/dist/contract.meta.cjs +5 -5
  28. package/dist/contract.meta.cjs.map +1 -1
  29. package/dist/contract.meta.d.cts +9 -9
  30. package/dist/contract.meta.d.mts +9 -9
  31. package/dist/contract.meta.mjs +5 -5
  32. package/dist/contract.meta.mjs.map +1 -1
  33. package/dist/contract.mjs +1 -4
  34. package/dist/contract.mjs.map +1 -1
  35. package/dist/plugin.cjs +83 -119
  36. package/dist/plugin.cjs.map +1 -1
  37. package/dist/plugin.d.cts +3 -6
  38. package/dist/plugin.d.cts.map +1 -1
  39. package/dist/plugin.d.mts +3 -6
  40. package/dist/plugin.d.mts.map +1 -1
  41. package/dist/plugin.mjs +84 -120
  42. package/dist/plugin.mjs.map +1 -1
  43. package/dist/types.d.cts +2 -2
  44. package/dist/types.d.mts +2 -2
  45. package/package.json +5 -5
  46. package/src/cli/init.ts +224 -162
  47. package/src/cli/prompts.ts +17 -22
  48. package/src/cli/timing.ts +27 -0
  49. package/src/cli/upgrade.ts +173 -56
  50. package/src/contract.meta.ts +6 -8
  51. package/src/contract.ts +1 -4
  52. package/src/plugin.ts +189 -209
@@ -155,34 +155,82 @@ function migrateRootConfigTargets(config: Record<string, unknown>): boolean {
155
155
  function migratePluginProviderConfig(config: Record<string, unknown>, pluginKey: string): boolean {
156
156
  let changed = false;
157
157
  if (!config.plugins || typeof config.plugins !== "object") {
158
- config.plugins = {};
159
- changed = true;
158
+ return false;
160
159
  }
161
160
 
162
161
  const plugins = config.plugins as Record<string, unknown>;
163
- if (!plugins[pluginKey] || typeof plugins[pluginKey] !== "object") {
164
- plugins[pluginKey] = { name: pluginKey };
162
+ const entry = plugins[pluginKey];
163
+ if (!entry || typeof entry !== "object") return false;
164
+
165
+ const pluginEntry = entry as Record<string, unknown>;
166
+
167
+ if ("name" in pluginEntry) {
168
+ delete pluginEntry.name;
165
169
  changed = true;
166
170
  }
167
171
 
168
- const pluginEntry = plugins[pluginKey] as Record<string, unknown>;
169
- if (typeof pluginEntry.name !== "string" || pluginEntry.name.length === 0) {
170
- pluginEntry.name = pluginKey;
172
+ if (typeof pluginEntry.development === "string" && pluginEntry.development.startsWith("local:")) {
173
+ if ("extends" in pluginEntry) {
174
+ delete pluginEntry.extends;
175
+ changed = true;
176
+ }
177
+ }
178
+
179
+ changed = rewriteExtendsTarget(pluginEntry, `plugins.${pluginKey}`) || changed;
180
+
181
+ return changed;
182
+ }
183
+
184
+ function mergePluginConfigIntoRoot(
185
+ rootConfig: Record<string, unknown>,
186
+ pluginKey: string,
187
+ pluginConfig: Record<string, unknown>,
188
+ ): boolean {
189
+ let changed = false;
190
+
191
+ if (!rootConfig.plugins || typeof rootConfig.plugins !== "object") {
192
+ rootConfig.plugins = {};
193
+ changed = true;
194
+ }
195
+ const plugins = rootConfig.plugins as Record<string, unknown>;
196
+ if (!plugins[pluginKey] || typeof plugins[pluginKey] !== "object") {
197
+ plugins[pluginKey] = {};
171
198
  changed = true;
172
199
  }
173
200
 
174
- const app =
175
- config.app && typeof config.app === "object"
176
- ? (config.app as Record<string, unknown>)
177
- : undefined;
178
- const apiEntry =
179
- app?.api && typeof app.api === "object" ? (app.api as Record<string, unknown>) : undefined;
201
+ const entry = plugins[pluginKey] as Record<string, unknown>;
202
+
203
+ const pluginData = extractPluginEntry(pluginConfig, pluginKey);
180
204
 
181
- if (apiEntry) {
205
+ const apiData = getApiEntry(pluginConfig);
206
+
207
+ if (pluginData) {
208
+ for (const key of [
209
+ "secrets",
210
+ "variables",
211
+ "routes",
212
+ "sidebar",
213
+ "production",
214
+ "integrity",
215
+ "proxy",
216
+ ] as const) {
217
+ if (pluginData[key] !== undefined && entry[key] === undefined) {
218
+ entry[key] = pluginData[key];
219
+ changed = true;
220
+ }
221
+ }
222
+
223
+ if (typeof pluginData.development === "string" && pluginData.development.startsWith("local:")) {
224
+ pluginData.development = `local:plugins/${pluginKey}`;
225
+ }
226
+ if (entry.development === undefined && pluginData.development !== undefined) {
227
+ entry.development = pluginData.development;
228
+ changed = true;
229
+ }
230
+ }
231
+
232
+ if (apiData) {
182
233
  for (const key of [
183
- "extends",
184
- "name",
185
- "development",
186
234
  "production",
187
235
  "integrity",
188
236
  "proxy",
@@ -191,39 +239,94 @@ function migratePluginProviderConfig(config: Record<string, unknown>, pluginKey:
191
239
  "sidebar",
192
240
  "routes",
193
241
  ] as const) {
194
- if (pluginEntry[key] === undefined && apiEntry[key] !== undefined) {
195
- pluginEntry[key] = apiEntry[key];
242
+ if (apiData[key] !== undefined && entry[key] === undefined) {
243
+ entry[key] = apiData[key];
196
244
  changed = true;
197
245
  }
198
246
  }
247
+ }
199
248
 
200
- delete app!.api;
201
- changed = true;
202
- if (Object.keys(app!).length === 0) {
203
- delete config.app;
249
+ if ("extends" in entry) {
250
+ const extendsStr = typeof entry.extends === "string" ? entry.extends : undefined;
251
+ if (!extendsStr || extendsStr.includes(`#plugins.${pluginKey}`)) {
252
+ delete entry.extends;
253
+ changed = true;
204
254
  }
205
255
  }
206
256
 
207
- if (config.sidebar !== undefined && pluginEntry.sidebar === undefined) {
208
- pluginEntry.sidebar = config.sidebar;
257
+ if ("name" in entry) {
258
+ delete entry.name;
209
259
  changed = true;
210
260
  }
211
- if (config.routes !== undefined && pluginEntry.routes === undefined) {
212
- pluginEntry.routes = config.routes;
213
- changed = true;
261
+
262
+ if (configHasTopLevelFields(pluginConfig, pluginKey)) {
263
+ if (entry.routes === undefined && Array.isArray(pluginConfig.routes)) {
264
+ entry.routes = pluginConfig.routes;
265
+ changed = true;
266
+ }
267
+ if (entry.sidebar === undefined && Array.isArray(pluginConfig.sidebar)) {
268
+ entry.sidebar = pluginConfig.sidebar;
269
+ changed = true;
270
+ }
271
+ const api = getApiEntry(pluginConfig);
272
+ if (api) {
273
+ if (entry.routes === undefined && Array.isArray(api.routes)) {
274
+ entry.routes = api.routes;
275
+ changed = true;
276
+ }
277
+ if (entry.sidebar === undefined && Array.isArray(api.sidebar)) {
278
+ entry.sidebar = api.sidebar;
279
+ changed = true;
280
+ }
281
+ }
214
282
  }
215
- if (config.sidebar !== undefined) {
216
- delete config.sidebar;
217
- changed = true;
283
+
284
+ return changed;
285
+ }
286
+
287
+ function extractPluginEntry(
288
+ pluginConfig: Record<string, unknown>,
289
+ pluginKey: string,
290
+ ): Record<string, unknown> | null {
291
+ if (
292
+ pluginConfig.plugins &&
293
+ typeof pluginConfig.plugins === "object" &&
294
+ (pluginConfig.plugins as Record<string, unknown>)[pluginKey] &&
295
+ typeof (pluginConfig.plugins as Record<string, unknown>)[pluginKey] === "object"
296
+ ) {
297
+ return (pluginConfig.plugins as Record<string, unknown>)[pluginKey] as Record<string, unknown>;
218
298
  }
219
- if (config.routes !== undefined) {
220
- delete config.routes;
221
- changed = true;
299
+
300
+ const fallback: Record<string, unknown> = {};
301
+ if (pluginConfig.sidebar !== undefined) {
302
+ fallback.sidebar = pluginConfig.sidebar;
303
+ }
304
+ if (pluginConfig.routes !== undefined) {
305
+ fallback.routes = pluginConfig.routes;
306
+ }
307
+ if (Object.keys(fallback).length > 0) {
308
+ return fallback;
222
309
  }
223
310
 
224
- changed = rewriteExtendsTarget(pluginEntry, `plugins.${pluginKey}`) || changed;
311
+ return null;
312
+ }
225
313
 
226
- return changed;
314
+ function configHasTopLevelFields(
315
+ pluginConfig: Record<string, unknown>,
316
+ _pluginKey: string,
317
+ ): boolean {
318
+ return (
319
+ (pluginConfig.routes !== undefined && Array.isArray(pluginConfig.routes)) ||
320
+ (pluginConfig.sidebar !== undefined && Array.isArray(pluginConfig.sidebar)) ||
321
+ getApiEntry(pluginConfig) !== null
322
+ );
323
+ }
324
+
325
+ function getApiEntry(pluginConfig: Record<string, unknown>): Record<string, unknown> | null {
326
+ if (!pluginConfig.app || typeof pluginConfig.app !== "object") return null;
327
+ const app = pluginConfig.app as Record<string, unknown>;
328
+ if (!app.api || typeof app.api !== "object") return null;
329
+ return app.api as Record<string, unknown>;
227
330
  }
228
331
 
229
332
  export async function migrateBosConfigFiles(projectDir: string): Promise<string[]> {
@@ -232,30 +335,44 @@ export async function migrateBosConfigFiles(projectDir: string): Promise<string[
232
335
 
233
336
  if (existsSync(rootConfigPath)) {
234
337
  const rootConfig = JSON.parse(readFileSync(rootConfigPath, "utf-8")) as Record<string, unknown>;
235
- if (migrateRootConfigTargets(rootConfig)) {
236
- await saveBosConfig(projectDir, rootConfig);
237
- migrated.push("bos.config.json");
238
- }
239
- }
338
+ let rootChanged = migrateRootConfigTargets(rootConfig);
240
339
 
241
- const pluginConfigPaths = await glob("plugins/*/bos.config.json", {
242
- cwd: projectDir,
243
- nodir: true,
244
- dot: false,
245
- absolute: false,
246
- });
340
+ const pluginConfigPaths = await glob("plugins/*/bos.config.json", {
341
+ cwd: projectDir,
342
+ nodir: true,
343
+ dot: false,
344
+ absolute: false,
345
+ });
346
+
347
+ for (const relativePath of pluginConfigPaths) {
348
+ const match = relativePath.match(/^plugins\/([^/]+)\/bos\.config\.json$/);
349
+ const pluginKey = match?.[1];
350
+ if (!pluginKey) continue;
351
+
352
+ const filePath = join(projectDir, relativePath);
353
+ try {
354
+ const pluginConfig = JSON.parse(readFileSync(filePath, "utf-8")) as Record<string, unknown>;
355
+ rootChanged = mergePluginConfigIntoRoot(rootConfig, pluginKey, pluginConfig) || rootChanged;
356
+ } catch {}
247
357
 
248
- for (const relativePath of pluginConfigPaths) {
249
- const match = relativePath.match(/^plugins\/([^/]+)\/bos\.config\.json$/);
250
- const pluginKey = match?.[1];
251
- if (!pluginKey) continue;
358
+ try {
359
+ rmSync(filePath);
360
+ migrated.push(relativePath);
361
+ } catch {}
362
+ }
252
363
 
253
- const filePath = join(projectDir, relativePath);
254
- const pluginConfig = JSON.parse(readFileSync(filePath, "utf-8")) as Record<string, unknown>;
255
- if (!migratePluginProviderConfig(pluginConfig, pluginKey)) continue;
364
+ if (rootConfig.plugins && typeof rootConfig.plugins === "object") {
365
+ for (const pluginKey of Object.keys(rootConfig.plugins as Record<string, unknown>)) {
366
+ rootChanged = migratePluginProviderConfig(rootConfig, pluginKey) || rootChanged;
367
+ }
368
+ }
256
369
 
257
- writeFileSync(filePath, `${JSON.stringify(pluginConfig, null, 2)}\n`);
258
- migrated.push(relativePath);
370
+ if (rootChanged || migrated.length > 0) {
371
+ await saveBosConfig(projectDir, rootConfig);
372
+ if (!migrated.includes("bos.config.json")) {
373
+ migrated.push("bos.config.json");
374
+ }
375
+ }
259
376
  }
260
377
 
261
378
  return migrated;
@@ -79,22 +79,20 @@ export const cliCommandMeta = {
79
79
  },
80
80
  init: {
81
81
  commandPath: ["init"],
82
- summary: "Scaffold a new project from a bos template",
82
+ summary: "Scaffold a new project by extending a deployed app or template",
83
83
  interactive: true,
84
84
  fields: {
85
85
  domain: {
86
86
  positional: true,
87
- description: "New project domain (e.g. ironclaw.everything.dev)",
87
+ description: "New project domain (e.g. myapp.everything.dev)",
88
88
  },
89
- account: { description: "New project NEAR account (auto-derived from domain)" },
90
- extendsAccount: {
91
- description: "Parent NEAR account to extend from (defaults to dev.everything.near)",
92
- },
93
- extendsGateway: {
94
- description: "Parent gateway to extend from (defaults to everything.dev)",
89
+ extends: {
90
+ description: "Parent to extend from (e.g. bos://account/gateway or account/gateway)",
95
91
  },
92
+ account: { description: "New project NEAR account (auto-derived from extends)" },
96
93
  directory: { description: "Target directory (auto-derived from domain)" },
97
94
  source: { description: "Local source dir (skips GitHub download)" },
95
+ plugins: { description: "Comma-separated plugin keys to include" },
98
96
  withHost: { description: "Include host/ in template output" },
99
97
  noInteractive: { description: "Skip prompts, use flags only" },
100
98
  noInstall: { description: "Skip bun install" },
package/src/contract.ts CHANGED
@@ -144,8 +144,6 @@ export const KeyPublishResultSchema = z.object({
144
144
 
145
145
  export const InitOptionsSchema = z.object({
146
146
  extends: z.string().optional(),
147
- extendsAccount: z.string().optional(),
148
- extendsGateway: z.string().optional(),
149
147
  directory: z.string().optional(),
150
148
  account: z.string().optional(),
151
149
  domain: z.string().optional(),
@@ -164,8 +162,7 @@ export const PhaseTimingSchema = z.object({
164
162
  export const InitResultSchema = z.object({
165
163
  status: z.enum(["initialized", "error"]),
166
164
  directory: z.string(),
167
- extendsAccount: z.string(),
168
- extendsGateway: z.string(),
165
+ extendsRef: z.string(),
169
166
  account: z.string().optional(),
170
167
  domain: z.string().optional(),
171
168
  extends: z.string(),