@eide/foir-cli 0.2.0 → 0.3.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.
package/dist/cli.js CHANGED
@@ -448,7 +448,7 @@ function registerLogoutCommand(program2, globalOpts) {
448
448
  import inquirer from "inquirer";
449
449
 
450
450
  // src/lib/client.ts
451
- import { createClient } from "@connectrpc/connect";
451
+ import { createClient as createRpcClient } from "@connectrpc/connect";
452
452
  import { createConnectTransport } from "@connectrpc/connect-node";
453
453
  import {
454
454
  IdentityService,
@@ -459,15 +459,16 @@ import {
459
459
  ExperimentsService,
460
460
  SettingsService,
461
461
  StorageService
462
- } from "@foir/connect-clients/services";
463
- import { createIdentityMethods } from "@foir/connect-clients/identity";
464
- import { createModelsMethods } from "@foir/connect-clients/models";
465
- import { createRecordsMethods } from "@foir/connect-clients/records";
466
- import { createConfigsMethods } from "@foir/connect-clients/configs";
467
- import { createSegmentsMethods } from "@foir/connect-clients/segments";
468
- import { createExperimentsMethods } from "@foir/connect-clients/experiments";
469
- import { createSettingsMethods } from "@foir/connect-clients/settings";
470
- import { createStorageMethods } from "@foir/connect-clients/storage";
462
+ } from "@eide/foir-connect-clients/services";
463
+ import { createIdentityMethods } from "@eide/foir-connect-clients/identity";
464
+ import { createModelsMethods } from "@eide/foir-connect-clients/models";
465
+ import { createRecordsMethods } from "@eide/foir-connect-clients/records";
466
+ import { createConfigsMethods } from "@eide/foir-connect-clients/configs";
467
+ import { createSegmentsMethods } from "@eide/foir-connect-clients/segments";
468
+ import { createExperimentsMethods } from "@eide/foir-connect-clients/experiments";
469
+ import { createSettingsMethods } from "@eide/foir-connect-clients/settings";
470
+ import { createStorageMethods } from "@eide/foir-connect-clients/storage";
471
+ import { GraphQLClient } from "graphql-request";
471
472
  async function createPlatformClient(options) {
472
473
  const apiUrl = getApiUrl(options);
473
474
  const headers = {};
@@ -503,16 +504,16 @@ async function createPlatformClient(options) {
503
504
  interceptors: [authInterceptor]
504
505
  });
505
506
  return {
506
- identity: createIdentityMethods(createClient(IdentityService, transport)),
507
- models: createModelsMethods(createClient(ModelsService, transport)),
508
- records: createRecordsMethods(createClient(RecordsService, transport)),
509
- configs: createConfigsMethods(createClient(ConfigsService, transport)),
510
- segments: createSegmentsMethods(createClient(SegmentsService, transport)),
507
+ identity: createIdentityMethods(createRpcClient(IdentityService, transport)),
508
+ models: createModelsMethods(createRpcClient(ModelsService, transport)),
509
+ records: createRecordsMethods(createRpcClient(RecordsService, transport)),
510
+ configs: createConfigsMethods(createRpcClient(ConfigsService, transport)),
511
+ segments: createSegmentsMethods(createRpcClient(SegmentsService, transport)),
511
512
  experiments: createExperimentsMethods(
512
- createClient(ExperimentsService, transport)
513
+ createRpcClient(ExperimentsService, transport)
513
514
  ),
514
- settings: createSettingsMethods(createClient(SettingsService, transport)),
515
- storage: createStorageMethods(createClient(StorageService, transport))
515
+ settings: createSettingsMethods(createRpcClient(SettingsService, transport)),
516
+ storage: createStorageMethods(createRpcClient(StorageService, transport))
516
517
  };
517
518
  }
518
519
  function createPlatformClientWithHeaders(apiUrl, headers) {
@@ -528,16 +529,16 @@ function createPlatformClientWithHeaders(apiUrl, headers) {
528
529
  interceptors: [authInterceptor]
529
530
  });
530
531
  return {
531
- identity: createIdentityMethods(createClient(IdentityService, transport)),
532
- models: createModelsMethods(createClient(ModelsService, transport)),
533
- records: createRecordsMethods(createClient(RecordsService, transport)),
534
- configs: createConfigsMethods(createClient(ConfigsService, transport)),
535
- segments: createSegmentsMethods(createClient(SegmentsService, transport)),
532
+ identity: createIdentityMethods(createRpcClient(IdentityService, transport)),
533
+ models: createModelsMethods(createRpcClient(ModelsService, transport)),
534
+ records: createRecordsMethods(createRpcClient(RecordsService, transport)),
535
+ configs: createConfigsMethods(createRpcClient(ConfigsService, transport)),
536
+ segments: createSegmentsMethods(createRpcClient(SegmentsService, transport)),
536
537
  experiments: createExperimentsMethods(
537
- createClient(ExperimentsService, transport)
538
+ createRpcClient(ExperimentsService, transport)
538
539
  ),
539
- settings: createSettingsMethods(createClient(SettingsService, transport)),
540
- storage: createStorageMethods(createClient(StorageService, transport))
540
+ settings: createSettingsMethods(createRpcClient(SettingsService, transport)),
541
+ storage: createStorageMethods(createRpcClient(StorageService, transport))
541
542
  };
542
543
  }
543
544
  async function getStorageAuth(options) {
@@ -872,7 +873,7 @@ function registerWhoamiCommand(program2, globalOpts) {
872
873
  import { promises as fs2 } from "fs";
873
874
  import { basename } from "path";
874
875
  import chalk3 from "chalk";
875
- import { createStorageClient } from "@foir/connect-clients/storage";
876
+ import { createStorageClient } from "@eide/foir-connect-clients/storage";
876
877
 
877
878
  // src/lib/input.ts
878
879
  import inquirer2 from "inquirer";
@@ -966,7 +967,7 @@ function guessMimeType(filename) {
966
967
  function getStorageUrl() {
967
968
  return process.env.FOIR_STORAGE_URL ?? "https://storage.foir.dev";
968
969
  }
969
- function createClient2(getToken) {
970
+ function createClient(getToken) {
970
971
  return createStorageClient({
971
972
  baseUrl: getStorageUrl(),
972
973
  getAuthToken: getToken
@@ -980,7 +981,7 @@ function registerMediaCommands(program2, globalOpts) {
980
981
  async (filepath, flags) => {
981
982
  const opts = globalOpts();
982
983
  const { getToken } = await getStorageAuth(opts);
983
- const storage = createClient2(getToken);
984
+ const storage = createClient(getToken);
984
985
  const fileBuffer = await fs2.readFile(filepath);
985
986
  const filename = basename(filepath);
986
987
  const mimeType = guessMimeType(filename);
@@ -1021,7 +1022,7 @@ function registerMediaCommands(program2, globalOpts) {
1021
1022
  async (flags) => {
1022
1023
  const opts = globalOpts();
1023
1024
  const { getToken } = await getStorageAuth(opts);
1024
- const storage = createClient2(getToken);
1025
+ const storage = createClient(getToken);
1025
1026
  const result = await storage.listFiles({
1026
1027
  folder: flags.folder,
1027
1028
  mimeType: flags["mime-type"] ?? flags.mimeType,
@@ -1063,7 +1064,7 @@ function registerMediaCommands(program2, globalOpts) {
1063
1064
  withErrorHandler(globalOpts, async (id) => {
1064
1065
  const opts = globalOpts();
1065
1066
  const { getToken } = await getStorageAuth(opts);
1066
- const storage = createClient2(getToken);
1067
+ const storage = createClient(getToken);
1067
1068
  const file = await storage.getFile(id);
1068
1069
  formatOutput(file, opts);
1069
1070
  })
@@ -1072,7 +1073,7 @@ function registerMediaCommands(program2, globalOpts) {
1072
1073
  withErrorHandler(globalOpts, async () => {
1073
1074
  const opts = globalOpts();
1074
1075
  const { getToken } = await getStorageAuth(opts);
1075
- const storage = createClient2(getToken);
1076
+ const storage = createClient(getToken);
1076
1077
  const usage = await storage.getStorageUsage();
1077
1078
  if (opts.json || opts.jsonl) {
1078
1079
  formatOutput(usage, opts);
@@ -1091,7 +1092,7 @@ function registerMediaCommands(program2, globalOpts) {
1091
1092
  async (id, flags) => {
1092
1093
  const opts = globalOpts();
1093
1094
  const { getToken } = await getStorageAuth(opts);
1094
- const storage = createClient2(getToken);
1095
+ const storage = createClient(getToken);
1095
1096
  const file = await storage.updateFile({
1096
1097
  id,
1097
1098
  filename: flags.filename,
@@ -1112,7 +1113,7 @@ function registerMediaCommands(program2, globalOpts) {
1112
1113
  async (id, flags) => {
1113
1114
  const opts = globalOpts();
1114
1115
  const { getToken } = await getStorageAuth(opts);
1115
- const storage = createClient2(getToken);
1116
+ const storage = createClient(getToken);
1116
1117
  const file = await storage.updateFileMetadata({
1117
1118
  id,
1118
1119
  altText: flags.altText ?? flags["alt-text"],
@@ -1140,7 +1141,7 @@ function registerMediaCommands(program2, globalOpts) {
1140
1141
  return;
1141
1142
  }
1142
1143
  const { getToken } = await getStorageAuth(opts);
1143
- const storage = createClient2(getToken);
1144
+ const storage = createClient(getToken);
1144
1145
  if (flags.permanent) {
1145
1146
  await storage.permanentlyDeleteFile(id);
1146
1147
  success("Permanently deleted file");
@@ -1155,7 +1156,7 @@ function registerMediaCommands(program2, globalOpts) {
1155
1156
  withErrorHandler(globalOpts, async (id) => {
1156
1157
  const opts = globalOpts();
1157
1158
  const { getToken } = await getStorageAuth(opts);
1158
- const storage = createClient2(getToken);
1159
+ const storage = createClient(getToken);
1159
1160
  const file = await storage.restoreFile(id);
1160
1161
  if (opts.json || opts.jsonl) {
1161
1162
  formatOutput(file, opts);
@@ -2258,7 +2259,7 @@ import { readdirSync } from "fs";
2258
2259
  import { resolve as resolve5 } from "path";
2259
2260
  import chalk9 from "chalk";
2260
2261
 
2261
- // ../command-registry/src/command-map.ts
2262
+ // src/command-registry/command-map.ts
2262
2263
  var COMMANDS = [
2263
2264
  // =========================================================================
2264
2265
  // MODELS
@@ -2433,6 +2434,15 @@ var COMMANDS = [
2433
2434
  scalarResult: true,
2434
2435
  successMessage: "Unpublished record"
2435
2436
  },
2437
+ {
2438
+ group: "records",
2439
+ name: "cancel-schedule",
2440
+ description: "Cancel a scheduled publish or unpublish",
2441
+ operation: "cancelScheduledRecordPublish",
2442
+ operationType: "mutation",
2443
+ positionalArgs: [{ name: "versionId", graphqlArg: "versionId", description: "Version ID" }],
2444
+ successMessage: "Cancelled scheduled publish for version {versionId}"
2445
+ },
2436
2446
  {
2437
2447
  group: "records",
2438
2448
  name: "duplicate",
@@ -2489,6 +2499,104 @@ var COMMANDS = [
2489
2499
  successMessage: "Created variant"
2490
2500
  },
2491
2501
  // =========================================================================
2502
+ // ROLLOUTS
2503
+ // =========================================================================
2504
+ {
2505
+ group: "rollouts",
2506
+ name: "list",
2507
+ description: "List rollouts",
2508
+ operation: "listPublishBatches",
2509
+ operationType: "query",
2510
+ columns: [
2511
+ { key: "id", header: "ID", width: 28 },
2512
+ { key: "name", header: "Name", width: 24 },
2513
+ { key: "status", header: "Status", width: 16 },
2514
+ { key: "itemCount", header: "Items", width: 6 },
2515
+ { key: "completedCount", header: "Done", width: 6 },
2516
+ { key: "scheduledAt", header: "Scheduled", width: 12, format: "timeAgo" },
2517
+ { key: "createdAt", header: "Created", width: 12, format: "timeAgo" }
2518
+ ]
2519
+ },
2520
+ {
2521
+ group: "rollouts",
2522
+ name: "get",
2523
+ description: "Get a rollout",
2524
+ operation: "getPublishBatch",
2525
+ operationType: "query",
2526
+ positionalArgs: [{ name: "id", graphqlArg: "id", description: "Rollout ID" }]
2527
+ },
2528
+ {
2529
+ group: "rollouts",
2530
+ name: "create",
2531
+ description: "Create a rollout",
2532
+ operation: "createPublishBatch",
2533
+ operationType: "mutation",
2534
+ acceptsInput: true,
2535
+ successMessage: "Created rollout {name}"
2536
+ },
2537
+ {
2538
+ group: "rollouts",
2539
+ name: "update",
2540
+ description: "Update a rollout",
2541
+ operation: "updatePublishBatch",
2542
+ operationType: "mutation",
2543
+ positionalArgs: [{ name: "id", graphqlArg: "id", description: "Rollout ID" }],
2544
+ acceptsInput: true,
2545
+ successMessage: "Updated rollout"
2546
+ },
2547
+ {
2548
+ group: "rollouts",
2549
+ name: "cancel",
2550
+ description: "Cancel a rollout",
2551
+ operation: "cancelPublishBatch",
2552
+ operationType: "mutation",
2553
+ positionalArgs: [{ name: "id", graphqlArg: "id", description: "Rollout ID" }],
2554
+ requiresConfirmation: true,
2555
+ scalarResult: true,
2556
+ successMessage: "Cancelled rollout"
2557
+ },
2558
+ {
2559
+ group: "rollouts",
2560
+ name: "rollback",
2561
+ description: "Rollback a completed rollout",
2562
+ operation: "rollbackPublishBatch",
2563
+ operationType: "mutation",
2564
+ positionalArgs: [{ name: "id", graphqlArg: "id", description: "Rollout ID" }],
2565
+ requiresConfirmation: true,
2566
+ scalarResult: true,
2567
+ successMessage: "Rolled back rollout"
2568
+ },
2569
+ {
2570
+ group: "rollouts",
2571
+ name: "retry",
2572
+ description: "Retry failed items in a rollout",
2573
+ operation: "retryFailedBatchItems",
2574
+ operationType: "mutation",
2575
+ positionalArgs: [{ name: "id", graphqlArg: "id", description: "Rollout ID" }],
2576
+ scalarResult: true,
2577
+ successMessage: "Retrying failed items in rollout"
2578
+ },
2579
+ {
2580
+ group: "rollouts",
2581
+ name: "add-items",
2582
+ description: "Add version IDs to a rollout",
2583
+ operation: "addItemsToPublishBatch",
2584
+ operationType: "mutation",
2585
+ positionalArgs: [{ name: "id", graphqlArg: "id", description: "Rollout ID" }],
2586
+ acceptsInput: true,
2587
+ successMessage: "Added items to rollout"
2588
+ },
2589
+ {
2590
+ group: "rollouts",
2591
+ name: "remove-items",
2592
+ description: "Remove version IDs from a rollout",
2593
+ operation: "removeItemsFromPublishBatch",
2594
+ operationType: "mutation",
2595
+ positionalArgs: [{ name: "id", graphqlArg: "id", description: "Rollout ID" }],
2596
+ acceptsInput: true,
2597
+ successMessage: "Removed items from rollout"
2598
+ },
2599
+ // =========================================================================
2492
2600
  // LOCALES
2493
2601
  // =========================================================================
2494
2602
  {
@@ -3197,6 +3305,7 @@ var COMMANDS = [
3197
3305
  description: "List hook deliveries",
3198
3306
  operation: "hookDeliveries",
3199
3307
  operationType: "query",
3308
+ positionalArgs: [{ name: "hookId", graphqlArg: "hookId", description: "Hook ID" }],
3200
3309
  columns: [
3201
3310
  { key: "id", header: "ID", width: 28 },
3202
3311
  { key: "event", header: "Event", width: 16 },
@@ -3600,8 +3709,19 @@ var COMMANDS = [
3600
3709
  }
3601
3710
  ];
3602
3711
 
3712
+ // src/command-registry/schema-engine.ts
3713
+ import {
3714
+ buildSchema,
3715
+ isObjectType,
3716
+ isInputObjectType,
3717
+ isListType,
3718
+ isNonNullType,
3719
+ isScalarType,
3720
+ isEnumType
3721
+ } from "graphql";
3722
+
3603
3723
  // src/commands/register-commands.ts
3604
- import { RecordType } from "@foir/connect-clients/records";
3724
+ import { RecordType } from "@eide/foir-connect-clients/records";
3605
3725
  function buildDispatchTable() {
3606
3726
  return {
3607
3727
  // ── Models ──────────────────────────────────────────────────
@@ -40,7 +40,8 @@ interface ApplyConfigOperationInput {
40
40
  name: string;
41
41
  description?: string;
42
42
  category?: string;
43
- handler?: string;
43
+ /** HTTP endpoint URL that the platform calls when this operation is triggered. */
44
+ endpoint?: string;
44
45
  config?: Record<string, unknown>;
45
46
  isActive?: boolean;
46
47
  }
@@ -78,8 +79,17 @@ interface ApplyConfigPlacementInput {
78
79
  modelKeys?: string[];
79
80
  }
80
81
  interface ApplyConfigHookInput {
82
+ /** Unique key for this hook. */
83
+ key?: string;
84
+ /** Display name. */
85
+ name?: string;
86
+ /** Lifecycle event that triggers this hook. */
81
87
  event: string;
82
- type: string;
88
+ /** Key of the operation to execute. */
89
+ operationKey?: string;
90
+ /** Filter to scope the hook (e.g., `{ modelKey: 'redirect' }`). */
91
+ filter?: Record<string, unknown>;
92
+ type?: string;
83
93
  url?: string;
84
94
  method?: string;
85
95
  async?: boolean;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eide/foir-cli",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "Universal platform CLI for Foir platform",
5
5
  "type": "module",
6
6
  "publishConfig": {
@@ -49,19 +49,23 @@
49
49
  "@bufbuild/protobuf": "^2.0.0",
50
50
  "@connectrpc/connect": "^2.0.0",
51
51
  "@connectrpc/connect-node": "^2.0.0",
52
- "@foir/connect-clients": "workspace:*",
52
+ "@eide/foir-connect-clients": "0.2.2",
53
53
  "chalk": "^5.3.0",
54
54
  "commander": "^12.1.0",
55
55
  "dotenv": "^16.4.5",
56
+ "graphql": "^16.13.2",
57
+ "graphql-request": "^7.4.0",
56
58
  "inquirer": "^9.2.12",
57
59
  "open": "^10.1.0",
58
60
  "ora": "^8.1.1",
59
61
  "prettier": "^3.4.2"
60
62
  },
61
63
  "devDependencies": {
62
- "@eide/command-registry": "workspace:*",
63
64
  "@types/inquirer": "^9.0.7",
64
65
  "@types/node": "^22.5.0",
66
+ "@typescript-eslint/eslint-plugin": "^8.58.0",
67
+ "@typescript-eslint/parser": "^8.58.0",
68
+ "eslint": "^10.1.0",
65
69
  "tsup": "^8.5.1",
66
70
  "tsx": "^4.20.0",
67
71
  "typescript": "5.9.2",
@@ -72,7 +76,7 @@
72
76
  },
73
77
  "repository": {
74
78
  "type": "git",
75
- "url": "https://github.com/eidestudio/foir.git",
76
- "directory": "packages/cli"
77
- }
78
- }
79
+ "url": "https://github.com/eidestudio/foir-cli.git"
80
+ },
81
+ "packageManager": "pnpm@9.15.4"
82
+ }