@powerhousedao/ph-cli 6.0.2-staging.9 → 6.1.0-staging.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 (32) hide show
  1. package/README.md +32 -30
  2. package/dist/cli.mjs +124 -24
  3. package/dist/cli.mjs.map +1 -1
  4. package/dist/generate-all-WiQQo-Nz.mjs +30 -0
  5. package/dist/generate-all-WiQQo-Nz.mjs.map +1 -0
  6. package/dist/{generate-app-KE0rbE-b.mjs → generate-app-DdmOt6ID.mjs} +15 -5
  7. package/dist/generate-app-DdmOt6ID.mjs.map +1 -0
  8. package/dist/generate-document-model-DQ5PVeIH.mjs +34 -0
  9. package/dist/generate-document-model-DQ5PVeIH.mjs.map +1 -0
  10. package/dist/{generate-editor-DmSzWm3W.mjs → generate-editor-DtzVAs6x.mjs} +15 -5
  11. package/dist/generate-editor-DtzVAs6x.mjs.map +1 -0
  12. package/dist/{generate-processor-B-fChg4W.mjs → generate-processor-FGtN6BVY.mjs} +15 -5
  13. package/dist/generate-processor-FGtN6BVY.mjs.map +1 -0
  14. package/dist/{generate-subgraph-C6dWIQzP.mjs → generate-subgraph-BrzmW_sj.mjs} +15 -5
  15. package/dist/generate-subgraph-BrzmW_sj.mjs.map +1 -0
  16. package/dist/{switchboard-BsdbF-rL.mjs → switchboard-CERuSM8r.mjs} +3 -3
  17. package/dist/{switchboard-BsdbF-rL.mjs.map → switchboard-CERuSM8r.mjs.map} +1 -1
  18. package/dist/switchboard-ChH1PMaE.mjs +4 -0
  19. package/dist/switchboard-reset-1YcJEVqc.mjs +87 -0
  20. package/dist/switchboard-reset-1YcJEVqc.mjs.map +1 -0
  21. package/dist/{vetra-BUcRFup0.mjs → vetra-yCsUKy_u.mjs} +7 -5
  22. package/dist/{vetra-BUcRFup0.mjs.map → vetra-yCsUKy_u.mjs.map} +1 -1
  23. package/package.json +13 -10
  24. package/dist/generate-all-Cj8zjFhN.mjs +0 -15
  25. package/dist/generate-all-Cj8zjFhN.mjs.map +0 -1
  26. package/dist/generate-app-KE0rbE-b.mjs.map +0 -1
  27. package/dist/generate-document-model-Cut44i6D.mjs +0 -24
  28. package/dist/generate-document-model-Cut44i6D.mjs.map +0 -1
  29. package/dist/generate-editor-DmSzWm3W.mjs.map +0 -1
  30. package/dist/generate-processor-B-fChg4W.mjs.map +0 -1
  31. package/dist/generate-subgraph-C6dWIQzP.mjs.map +0 -1
  32. package/dist/switchboard-GTBlxiJZ.mjs +0 -4
package/README.md CHANGED
@@ -97,51 +97,53 @@ ph connect --config-file ./my-config.js
97
97
 
98
98
  ### `ph generate`
99
99
 
100
- Generate code from document models with various options. This command supports multiple generation types including editors, processors, subgraphs, and import scripts.
100
+ `ph generate` is a router; pass a subcommand to generate a specific
101
+ module type. See `ph generate <subcommand> --help` for the full option
102
+ list per subcommand.
101
103
 
102
- #### Options:
104
+ #### Subcommands:
105
+
106
+ - `document-model` (alias `doc`) — generate from a `.phd`/`.json` spec
107
+ - `editor` — generate a document editor
108
+ - `app` — generate a drive app
109
+ - `processor` — generate a reactor processor
110
+ - `subgraph` — generate a GraphQL subgraph
111
+ - `migration-file` — generate migrations for a relational-db processor
112
+ - `all` — re-generate every module in the project
113
+
114
+ Most subcommands share these options:
103
115
 
104
- - `-i, --interactive`: Run the command in interactive mode
105
- - `--editors <type>`: Path to the editors directory
106
- - `-e, --editor <type>`: Editor Name
107
- - `--file <path>`: File path to document model
108
- - `--processors <type>`: Path to the processors directory
109
- - `-p, --processor <type>`: Processor Name
110
- - `--processor-type <type>`: Processor Type (relationalDb/analytics)
111
- - `-s, --subgraph <type>`: Subgraph Name
112
- - `--document-models <type>`: Path to the document models directory
113
- - `--document-types <type>`: Supported document types by the editor
114
- - `-is, --import-script <type>`: Import Script Name
115
- - `-sf, --skip-format`: Skip formatting the generated code
116
- - `-w, --watch`: Watch the generated code
117
- - `-d, --drive-editor <name>`: Generate a drive editor with the specified name
116
+ - `-d, --document <path>`: Path to a document-model spec (`.phd` or `.json`)
117
+ - `--dir <dir>`: Existing module directory to re-generate
118
+ - `-a, --all`: Re-generate every existing module of this type
119
+ - `-x, --extract`: (document-model only) Write a `powerhouse/document-model` spec for each existing model into `specs/document-models/`
118
120
 
119
121
  #### Examples:
120
122
 
121
123
  ```bash
122
- # Generate code from a specific file
123
- ph generate path/to/model.json
124
+ # Generate a document model from a spec file
125
+ ph generate document-model --document path/to/model.phd
124
126
 
125
- # Generate in interactive mode
126
- ph generate -i
127
+ # Re-generate all existing document models in the project
128
+ ph generate document-model --all
127
129
 
128
- # Generate a drive editor
129
- ph generate --drive-editor myEditor
130
+ # Generate an editor for a given document type
131
+ ph generate editor --name myEditor --document-type powerhouse/todo
130
132
 
131
- # Generate an editor with specific document types
132
- ph generate --editor myEditor --document-types "type1,type2"
133
+ # Generate a drive app
134
+ ph generate app --name myApp
133
135
 
134
136
  # Generate a processor
135
- ph generate --processor myProcessor --processor-type relationalDb
137
+ ph generate processor --name myProcessor --processor-type relationalDb
136
138
 
137
139
  # Generate a subgraph
138
- ph generate --subgraph mySubgraph --file path/to/model.json
140
+ ph generate subgraph --name mySubgraph
139
141
 
140
- # Generate an import script
141
- ph generate --import-script myImportScript
142
+ # Generate migration files for a relational-db processor
143
+ ph generate migration-file --processor myProcessor
142
144
 
143
- # Watch mode for continuous generation
144
- ph generate --watch
145
+ # Re-generate everything in the project
146
+ ph generate all
145
147
  ```
146
148
 
147
149
  ### `ph install` (or `ph add`, `ph i`)
package/dist/cli.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="91bfc73b-b8bb-5fb3-9600-c96d09217bb4")}catch(e){}}();
3
+ !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="a2e67adb-542b-5e92-bbfc-4656437ba4d7")}catch(e){}}();
4
4
  import { initCliTelemetry } from "@powerhousedao/shared/clis/telemetry";
5
5
  import { assertNodeVersion } from "@powerhousedao/shared/clis/utils";
6
6
  import { array, boolean, command, flag, multioption, oneOf, option, optional, run, string, subcommands } from "cmd-ts";
@@ -12,9 +12,10 @@ import { PROCESSOR_APPS } from "@powerhousedao/shared/processors";
12
12
  import { execSync } from "child_process";
13
13
  import { execSync as execSync$1 } from "node:child_process";
14
14
  import { createInterface } from "node:readline/promises";
15
+ import { bold, yellow } from "colorette";
15
16
  //#region src/get-version.ts
16
17
  function getVersion() {
17
- return "6.0.2-staging.9";
18
+ return "6.1.0-staging.0";
18
19
  }
19
20
  //#endregion
20
21
  //#region src/utils/constants.ts
@@ -167,10 +168,14 @@ NOTE: You must run \`ph connect build\` first
167
168
  const generateAllCmd = command({
168
169
  name: "all",
169
170
  description: "Re-generate all modules in the current project",
170
- args: {},
171
- handler: async () => {
172
- const { startGenerateAll } = await import("./generate-all-Cj8zjFhN.mjs");
173
- await startGenerateAll(process.cwd());
171
+ args: { extract: flag({
172
+ long: "extract",
173
+ short: "x",
174
+ description: "Instead of generating code, write a spec for every module into specs/ (one-shot migration to documents-as-source-of-truth)"
175
+ }) },
176
+ handler: async (args) => {
177
+ const { startGenerateAll } = await import("./generate-all-WiQQo-Nz.mjs");
178
+ await startGenerateAll(args, process.cwd());
174
179
  process.exit(0);
175
180
  }
176
181
  });
@@ -192,10 +197,15 @@ const generateAppCmd = command({
192
197
  short: "t",
193
198
  description: "The document types allowed by the new app"
194
199
  }),
200
+ document: option({
201
+ type: optional(File),
202
+ long: "document",
203
+ short: "d",
204
+ description: "Path to a powerhouse/app spec file (.phd or .json) to drive codegen"
205
+ }),
195
206
  dir: option({
196
207
  type: optional(Directory),
197
208
  long: "dir",
198
- short: "d",
199
209
  description: "Name of the directory of an existing app to re-generate"
200
210
  }),
201
211
  disableDragAndDrop: flag({
@@ -210,10 +220,15 @@ const generateAppCmd = command({
210
220
  short: "a",
211
221
  description: "Re-generate all existing apps in the current project"
212
222
  }),
223
+ extract: flag({
224
+ long: "extract",
225
+ short: "x",
226
+ description: "Write a powerhouse/app spec for each existing drive app into specs/apps/"
227
+ }),
213
228
  ...debugArgs
214
229
  },
215
230
  handler: async (args) => {
216
- const { startGenerateApp } = await import("./generate-app-KE0rbE-b.mjs");
231
+ const { startGenerateApp } = await import("./generate-app-DdmOt6ID.mjs");
217
232
  await startGenerateApp(args, process.cwd());
218
233
  process.exit(0);
219
234
  }
@@ -225,16 +240,15 @@ const generateDocumentModelCmd = command({
225
240
  aliases: ["doc"],
226
241
  description: "Generate a document model",
227
242
  args: {
228
- file: option({
243
+ document: option({
229
244
  type: optional(File),
230
- long: "file",
231
- short: "f",
232
- description: "Path to the file to generate the document model from"
245
+ long: "document",
246
+ short: "d",
247
+ description: "Path to a document model spec (.phd or .json) to generate from"
233
248
  }),
234
249
  dir: option({
235
250
  type: optional(Directory),
236
251
  long: "dir",
237
- short: "d",
238
252
  description: "Name of the directory of an existing document model to re-generate"
239
253
  }),
240
254
  all: flag({
@@ -242,10 +256,15 @@ const generateDocumentModelCmd = command({
242
256
  short: "a",
243
257
  description: "Re-generate all existing document models in the current project"
244
258
  }),
259
+ extract: flag({
260
+ long: "extract",
261
+ short: "x",
262
+ description: "Write a powerhouse/document-model spec for each existing document model into specs/document-models/"
263
+ }),
245
264
  ...debugArgs
246
265
  },
247
266
  handler: async (args) => {
248
- const { startGenerateDocumentModel } = await import("./generate-document-model-Cut44i6D.mjs");
267
+ const { startGenerateDocumentModel } = await import("./generate-document-model-DQ5PVeIH.mjs");
249
268
  await startGenerateDocumentModel(args, process.cwd());
250
269
  process.exit(0);
251
270
  }
@@ -268,10 +287,15 @@ const generateEditorCmd = command({
268
287
  short: "t",
269
288
  description: "The document type for the new editor"
270
289
  }),
290
+ document: option({
291
+ type: optional(File),
292
+ long: "document",
293
+ short: "d",
294
+ description: "Path to a powerhouse/document-editor spec file (.phd or .json) to drive codegen"
295
+ }),
271
296
  dir: option({
272
297
  type: optional(Directory),
273
298
  long: "dir",
274
- short: "d",
275
299
  description: "Name of the directory of an existing editor to re-generate"
276
300
  }),
277
301
  all: flag({
@@ -279,10 +303,15 @@ const generateEditorCmd = command({
279
303
  short: "a",
280
304
  description: "Re-generate all existing editors in the current project"
281
305
  }),
306
+ extract: flag({
307
+ long: "extract",
308
+ short: "x",
309
+ description: "Write a powerhouse/document-editor spec for each existing editor into specs/editors/"
310
+ }),
282
311
  ...debugArgs
283
312
  },
284
313
  handler: async (args) => {
285
- const { startGenerateEditor } = await import("./generate-editor-DmSzWm3W.mjs");
314
+ const { startGenerateEditor } = await import("./generate-editor-DtzVAs6x.mjs");
286
315
  await startGenerateEditor(args, process.cwd());
287
316
  process.exit(0);
288
317
  }
@@ -353,10 +382,15 @@ const generateProcessorCmd = command({
353
382
  defaultValue: () => ["switchboard", "connect"],
354
383
  defaultValueIsSerializable: true
355
384
  }),
385
+ document: option({
386
+ type: optional(File),
387
+ long: "document",
388
+ short: "d",
389
+ description: "Path to a powerhouse/processor spec file (.phd or .json) to drive codegen"
390
+ }),
356
391
  dir: option({
357
392
  type: optional(Directory),
358
393
  long: "dir",
359
- short: "d",
360
394
  description: "Name of the directory of an existing processor to re-generate"
361
395
  }),
362
396
  all: flag({
@@ -364,10 +398,15 @@ const generateProcessorCmd = command({
364
398
  short: "a",
365
399
  description: "Re-generate all existing processors in the current project"
366
400
  }),
401
+ extract: flag({
402
+ long: "extract",
403
+ short: "x",
404
+ description: "Write a powerhouse/processor spec for each existing processor into specs/processors/"
405
+ }),
367
406
  ...debugArgs
368
407
  },
369
408
  handler: async (args) => {
370
- const { startGenerateProcessor } = await import("./generate-processor-B-fChg4W.mjs");
409
+ const { startGenerateProcessor } = await import("./generate-processor-FGtN6BVY.mjs");
371
410
  await startGenerateProcessor(args, process.cwd());
372
411
  process.exit(0);
373
412
  }
@@ -384,10 +423,15 @@ const generateSubgraphCmd = command({
384
423
  short: "n",
385
424
  description: "The name of the subgraph to generate"
386
425
  }),
426
+ document: option({
427
+ type: optional(File),
428
+ long: "document",
429
+ short: "d",
430
+ description: "Path to a powerhouse/subgraph spec file (.phd or .json) to drive codegen"
431
+ }),
387
432
  dir: option({
388
433
  type: optional(Directory),
389
434
  long: "dir",
390
- short: "d",
391
435
  description: "Name of the directory of an existing subgraph to re-generate"
392
436
  }),
393
437
  all: flag({
@@ -395,10 +439,15 @@ const generateSubgraphCmd = command({
395
439
  short: "a",
396
440
  description: "Re-generate all existing subgraphs in the current project"
397
441
  }),
442
+ extract: flag({
443
+ long: "extract",
444
+ short: "x",
445
+ description: "Write a powerhouse/subgraph spec for each existing subgraph into specs/subgraphs/"
446
+ }),
398
447
  ...debugArgs
399
448
  },
400
449
  handler: async (args) => {
401
- const { startGenerateSubgraph } = await import("./generate-subgraph-C6dWIQzP.mjs");
450
+ const { startGenerateSubgraph } = await import("./generate-subgraph-BrzmW_sj.mjs");
402
451
  await startGenerateSubgraph(args, process.cwd());
403
452
  process.exit(0);
404
453
  }
@@ -878,8 +927,16 @@ This command:
878
927
  args: switchboardArgs,
879
928
  handler: async (args) => {
880
929
  if (args.debug) console.log(args);
881
- const { basePath, dbPath, migrate, migrateStatus } = args;
930
+ const { basePath, dbPath, migrate, migrateStatus, reset, yes } = args;
882
931
  if (basePath) process.env.BASE_PATH = basePath;
932
+ if (reset) {
933
+ const { resetSwitchboardDatabase } = await import("./switchboard-reset-1YcJEVqc.mjs");
934
+ await resetSwitchboardDatabase({
935
+ dbPath,
936
+ yes
937
+ });
938
+ process.exit(0);
939
+ }
883
940
  if (migrate || migrateStatus) {
884
941
  const { runSwitchboardMigrations } = await import("./switchboard-migrate-BumRp7rC.mjs");
885
942
  await runSwitchboardMigrations({
@@ -888,7 +945,7 @@ This command:
888
945
  });
889
946
  process.exit(0);
890
947
  }
891
- const { startSwitchboard } = await import("./switchboard-GTBlxiJZ.mjs");
948
+ const { startSwitchboard } = await import("./switchboard-ChH1PMaE.mjs");
892
949
  const { defaultDriveUrl, renown } = await startSwitchboard(args);
893
950
  console.log(" ➜ Switchboard:", defaultDriveUrl);
894
951
  if (renown) console.log(" ➜ Identity:", renown.did);
@@ -1065,7 +1122,7 @@ This command:
1065
1122
  args: vetraArgs,
1066
1123
  handler: async (args) => {
1067
1124
  if (args.debug) console.log(args);
1068
- const { startVetra } = await import("./vetra-BUcRFup0.mjs");
1125
+ const { startVetra } = await import("./vetra-yCsUKy_u.mjs");
1069
1126
  await startVetra(args);
1070
1127
  }
1071
1128
  }),
@@ -1091,6 +1148,48 @@ const phCli = subcommands({
1091
1148
  cmds: phCliCommands
1092
1149
  });
1093
1150
  //#endregion
1151
+ //#region src/utils/db-error-hint.ts
1152
+ const UNRECOVERABLE_DB_PATTERNS = [
1153
+ /Database migration failed:/i,
1154
+ /Migration .* failed/i,
1155
+ /relation "[^"]+" already exists/i,
1156
+ /column "[^"]+" does not exist/i,
1157
+ /schema "reactor" does not exist/i,
1158
+ /Unsupported PGLite data dir/i,
1159
+ /PG_VERSION/i
1160
+ ];
1161
+ function collectMessages(err) {
1162
+ const messages = [];
1163
+ let current = err;
1164
+ const seen = /* @__PURE__ */ new Set();
1165
+ while (current && !seen.has(current)) {
1166
+ seen.add(current);
1167
+ if (current instanceof Error) {
1168
+ messages.push(current.message);
1169
+ current = current.cause;
1170
+ } else {
1171
+ messages.push(String(current));
1172
+ break;
1173
+ }
1174
+ }
1175
+ return messages;
1176
+ }
1177
+ function isUnrecoverableDbError(err) {
1178
+ return collectMessages(err).some((msg) => UNRECOVERABLE_DB_PATTERNS.some((re) => re.test(msg)));
1179
+ }
1180
+ function printDbRecoveryHint(err) {
1181
+ const offending = collectMessages(err).find((msg) => UNRECOVERABLE_DB_PATTERNS.some((re) => re.test(msg)));
1182
+ console.error("");
1183
+ console.error(yellow(bold("Switchboard hit an unrecoverable database error.")));
1184
+ if (offending) console.error(yellow(` ${offending}`));
1185
+ console.error("");
1186
+ console.error(yellow("If this is a local PGlite store, you can reset it with:"));
1187
+ console.error(yellow(" ph switchboard --reset"));
1188
+ console.error(yellow("This is destructive: it wipes the local .ph/reactor-storage and .ph/read-storage directories."));
1189
+ console.error(yellow("For Postgres-backed deployments (PH_REACTOR_DATABASE_URL / DATABASE_URL), reset the database manually instead."));
1190
+ console.error("");
1191
+ }
1192
+ //#endregion
1094
1193
  //#region src/cli.ts
1095
1194
  let sentryClient = void 0;
1096
1195
  const COMMANDS_WITH_SUBCOMMANDS = new Set(["connect", "vetra"]);
@@ -1137,6 +1236,7 @@ await main().catch(async (error) => {
1137
1236
  if (isDebug) throw error;
1138
1237
  if (error instanceof Error) {
1139
1238
  console.error(error.message);
1239
+ if (isUnrecoverableDbError(error)) printDbRecoveryHint(error);
1140
1240
  process.exit(1);
1141
1241
  } else throw error;
1142
1242
  });
@@ -1144,4 +1244,4 @@ await main().catch(async (error) => {
1144
1244
  export {};
1145
1245
 
1146
1246
  //# sourceMappingURL=cli.mjs.map
1147
- //# debugId=91bfc73b-b8bb-5fb3-9600-c96d09217bb4
1247
+ //# debugId=a2e67adb-542b-5e92-bbfc-4656437ba4d7