@eide/foir-cli 0.3.2 → 0.4.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
@@ -2,7 +2,7 @@
2
2
 
3
3
  // src/cli.ts
4
4
  import { config } from "dotenv";
5
- import { resolve as resolve6, dirname as dirname4 } from "path";
5
+ import { resolve as resolve7, dirname as dirname4 } from "path";
6
6
  import { fileURLToPath } from "url";
7
7
  import { createRequire } from "module";
8
8
  import { Command } from "commander";
@@ -300,13 +300,13 @@ function withErrorHandler(optsFn, fn) {
300
300
  // src/commands/login.ts
301
301
  async function findAvailablePort(start, end) {
302
302
  for (let port = start; port <= end; port++) {
303
- const available = await new Promise((resolve7) => {
303
+ const available = await new Promise((resolve8) => {
304
304
  const server = http.createServer();
305
305
  server.listen(port, () => {
306
306
  server.close();
307
- resolve7(true);
307
+ resolve8(true);
308
308
  });
309
- server.on("error", () => resolve7(false));
309
+ server.on("error", () => resolve8(false));
310
310
  });
311
311
  if (available) return port;
312
312
  }
@@ -344,7 +344,7 @@ async function loginAction(globalOpts) {
344
344
  const state = crypto.randomBytes(16).toString("hex");
345
345
  const port = await findAvailablePort(9876, 9900);
346
346
  const redirectUri = `http://localhost:${port}/callback`;
347
- const authCode = await new Promise((resolve7, reject) => {
347
+ const authCode = await new Promise((resolve8, reject) => {
348
348
  let timeoutId;
349
349
  const server = http.createServer((req, res) => {
350
350
  const url = new URL(req.url, `http://localhost:${port}`);
@@ -383,7 +383,7 @@ async function loginAction(globalOpts) {
383
383
  );
384
384
  server.closeAllConnections();
385
385
  server.close();
386
- resolve7(code);
386
+ resolve8(code);
387
387
  }
388
388
  });
389
389
  server.listen(port);
@@ -1860,7 +1860,14 @@ function createConfigsMethods(client) {
1860
1860
  configData
1861
1861
  })
1862
1862
  );
1863
- return resp.config ?? null;
1863
+ const config2 = resp.config ?? null;
1864
+ if (!config2) return null;
1865
+ return {
1866
+ ...config2,
1867
+ summary: resp.summary ?? null,
1868
+ provisionedApiKeys: resp.provisionedApiKeys ?? [],
1869
+ webhookSecret: resp.webhookSecret ?? null
1870
+ };
1864
1871
  },
1865
1872
  async deleteConfig(id) {
1866
1873
  const resp = await client.deleteConfig(
@@ -2905,12 +2912,9 @@ function registerSelectProjectCommand(program2, globalOpts) {
2905
2912
  selectedProject = projects.find((p) => p.id === projectId);
2906
2913
  }
2907
2914
  console.log("\nProvisioning API key for CLI access...");
2908
- const projectClient = createPlatformClientWithHeaders(apiUrl, {
2909
- Authorization: `Bearer ${credentials.accessToken}`,
2910
- "x-tenant-id": selectedProject.tenantId,
2911
- "x-project-id": selectedProject.id
2912
- });
2913
- const { apiKey, apiKeyId } = await provisionApiKey(projectClient);
2915
+ await client.identity.switchTenant(selectedProject.tenantId);
2916
+ await client.identity.switchProject(selectedProject.id);
2917
+ const { apiKey, apiKeyId } = await provisionApiKey(client);
2914
2918
  await writeProjectContext(
2915
2919
  {
2916
2920
  id: selectedProject.id,
@@ -4229,7 +4233,7 @@ Edit the files, then run:
4229
4233
 
4230
4234
  // src/commands/push.ts
4231
4235
  import chalk6 from "chalk";
4232
- import { existsSync as existsSync4 } from "fs";
4236
+ import { existsSync as existsSync4, readFileSync, writeFileSync as writeFileSync2 } from "fs";
4233
4237
  import { resolve as resolve4 } from "path";
4234
4238
  var CONFIG_FILE_NAMES = [
4235
4239
  "foir.config.ts",
@@ -4244,8 +4248,25 @@ function discoverConfigFile() {
4244
4248
  }
4245
4249
  return null;
4246
4250
  }
4251
+ function writeEnvVar(envPath, key, value) {
4252
+ let content = "";
4253
+ if (existsSync4(envPath)) {
4254
+ content = readFileSync(envPath, "utf-8");
4255
+ const regex = new RegExp(`^${key}=`, "m");
4256
+ if (regex.test(content)) {
4257
+ return false;
4258
+ }
4259
+ }
4260
+ if (content && !content.endsWith("\n")) {
4261
+ content += "\n";
4262
+ }
4263
+ content += `${key}=${value}
4264
+ `;
4265
+ writeFileSync2(envPath, content, "utf-8");
4266
+ return true;
4267
+ }
4247
4268
  function registerPushCommand(program2, globalOpts) {
4248
- program2.command("push").description("Push foir.config.ts to the platform").option("--config <path>", "Path to config file (default: auto-discover)").option("--force", "Force reinstall (delete and recreate)", false).action(
4269
+ program2.command("push").description("Push foir.config.ts to the platform").option("--config <path>", "Path to config file (default: auto-discover)").option("--force", "Force reinstall (delete and recreate)", false).option("--env <path>", "Path to .env file (default: .env)").action(
4249
4270
  withErrorHandler(
4250
4271
  globalOpts,
4251
4272
  async (opts) => {
@@ -4282,18 +4303,203 @@ function registerPushCommand(program2, globalOpts) {
4282
4303
  );
4283
4304
  }
4284
4305
  console.log();
4285
- console.log(chalk6.green("Config applied successfully."));
4286
- console.log();
4306
+ console.log(chalk6.green("\u2713 Config applied successfully"));
4287
4307
  console.log(` Config ID: ${chalk6.cyan(result.id)}`);
4288
4308
  console.log(` Config Key: ${chalk6.cyan(result.key)}`);
4309
+ const summary = result.summary;
4310
+ if (summary) {
4311
+ console.log();
4312
+ const lines = [];
4313
+ if (summary.modelsCreated || summary.modelsUpdated) {
4314
+ lines.push(
4315
+ ` Models: ${summary.modelsCreated ?? 0} created, ${summary.modelsUpdated ?? 0} updated`
4316
+ );
4317
+ }
4318
+ if (summary.operationsCreated || summary.operationsUpdated) {
4319
+ lines.push(
4320
+ ` Operations: ${summary.operationsCreated ?? 0} created, ${summary.operationsUpdated ?? 0} updated`
4321
+ );
4322
+ }
4323
+ if (summary.hooksCreated || summary.hooksUpdated) {
4324
+ lines.push(
4325
+ ` Hooks: ${summary.hooksCreated ?? 0} created, ${summary.hooksUpdated ?? 0} updated`
4326
+ );
4327
+ }
4328
+ if (summary.segmentsCreated || summary.segmentsUpdated) {
4329
+ lines.push(
4330
+ ` Segments: ${summary.segmentsCreated ?? 0} created, ${summary.segmentsUpdated ?? 0} updated`
4331
+ );
4332
+ }
4333
+ if (summary.schedulesCreated || summary.schedulesUpdated) {
4334
+ lines.push(
4335
+ ` Schedules: ${summary.schedulesCreated ?? 0} created, ${summary.schedulesUpdated ?? 0} updated`
4336
+ );
4337
+ }
4338
+ if (summary.authProvidersCreated || summary.authProvidersUpdated) {
4339
+ lines.push(
4340
+ ` Auth: ${summary.authProvidersCreated ?? 0} created, ${summary.authProvidersUpdated ?? 0} updated`
4341
+ );
4342
+ }
4343
+ if (summary.resourcesDeleted) {
4344
+ lines.push(
4345
+ ` Cleaned up: ${summary.resourcesDeleted} orphaned resource(s)`
4346
+ );
4347
+ }
4348
+ if (lines.length > 0) {
4349
+ for (const line of lines) {
4350
+ console.log(line);
4351
+ }
4352
+ }
4353
+ }
4354
+ const envPath = resolve4(opts.env ?? ".env");
4355
+ const r = result;
4356
+ const provisionedKeys = r.provisionedApiKeys;
4357
+ const webhookSecret = r.webhookSecret;
4358
+ const envWrites = [];
4359
+ if (provisionedKeys && provisionedKeys.length > 0) {
4360
+ for (const pk of provisionedKeys) {
4361
+ envWrites.push({
4362
+ key: pk.envVar,
4363
+ value: pk.rawKey,
4364
+ label: `${pk.name} (${pk.keyType})`
4365
+ });
4366
+ }
4367
+ }
4368
+ if (webhookSecret) {
4369
+ envWrites.push({
4370
+ key: "FOIR_WEBHOOK_SECRET",
4371
+ value: webhookSecret,
4372
+ label: "Webhook signing secret"
4373
+ });
4374
+ }
4375
+ if (envWrites.length > 0) {
4376
+ console.log();
4377
+ for (const { key, value, label } of envWrites) {
4378
+ const written = writeEnvVar(envPath, key, value);
4379
+ if (written) {
4380
+ console.log(
4381
+ chalk6.green(`\u2713 ${label}`) + chalk6.dim(` \u2192 ${key} written to ${envPath}`)
4382
+ );
4383
+ } else {
4384
+ console.log(
4385
+ chalk6.dim(` ${label}: ${key} already exists in ${envPath}, skipped`)
4386
+ );
4387
+ }
4388
+ }
4389
+ }
4289
4390
  console.log();
4290
4391
  }
4291
4392
  )
4292
4393
  );
4293
4394
  }
4294
4395
 
4295
- // src/commands/remove.ts
4396
+ // src/commands/pull.ts
4296
4397
  import chalk7 from "chalk";
4398
+ import { existsSync as existsSync5, writeFileSync as writeFileSync3 } from "fs";
4399
+ import { resolve as resolve5 } from "path";
4400
+ import prettier from "prettier";
4401
+ var DEFAULT_OUTPUT = "foir.config.ts";
4402
+ function registerPullCommand(program2, globalOpts) {
4403
+ program2.command("pull").description("Export platform config to foir.config.ts").option("--key <configKey>", "Config key to export").option("--out <path>", `Output file (default: ${DEFAULT_OUTPUT})`).option("--force", "Overwrite existing file without prompting", false).action(
4404
+ withErrorHandler(
4405
+ globalOpts,
4406
+ async (opts) => {
4407
+ const client = await createPlatformClient(globalOpts());
4408
+ let configKey = opts.key;
4409
+ if (!configKey) {
4410
+ const { configs } = await client.configs.listConfigs({ limit: 50 });
4411
+ if (!configs || configs.length === 0) {
4412
+ throw new Error(
4413
+ "No configs found in this project. Push one first with `foir push`."
4414
+ );
4415
+ }
4416
+ if (configs.length === 1) {
4417
+ configKey = configs[0].key;
4418
+ } else {
4419
+ console.log("Available configs:");
4420
+ for (const c of configs) {
4421
+ console.log(` ${chalk7.cyan(c.key)} \u2014 ${c.name}`);
4422
+ }
4423
+ throw new Error(
4424
+ "Multiple configs found. Use --key <configKey> to specify which one to export."
4425
+ );
4426
+ }
4427
+ }
4428
+ console.log(chalk7.dim(`Fetching config "${configKey}"...`));
4429
+ const config2 = await client.configs.getConfigByKey(configKey);
4430
+ if (!config2) {
4431
+ throw new Error(`Config "${configKey}" not found.`);
4432
+ }
4433
+ const configData = config2.config;
4434
+ if (!configData) {
4435
+ throw new Error(
4436
+ `Config "${configKey}" has no config data. It may have been created via the admin UI without a manifest.`
4437
+ );
4438
+ }
4439
+ const manifest = {
4440
+ key: config2.key,
4441
+ name: config2.name,
4442
+ ...config2.configType && config2.configType !== "custom" ? { configType: config2.configType } : {},
4443
+ ...config2.direction ? { direction: config2.direction } : {},
4444
+ ...config2.description ? { description: config2.description } : {},
4445
+ ...config2.connectionDomain ? { operationBaseUrl: config2.connectionDomain } : {},
4446
+ ...configData
4447
+ };
4448
+ delete manifest.force;
4449
+ const jsonContent = JSON.stringify(manifest, null, 2);
4450
+ const tsContent = `/**
4451
+ * ${manifest.name} \u2014 Foir Config
4452
+ *
4453
+ * Exported from platform via \`foir pull\`.
4454
+ * Push changes back with \`foir push\`.
4455
+ */
4456
+
4457
+ import { defineConfig } from '@eide/foir-cli/configs';
4458
+
4459
+ export default defineConfig(${jsonContent});
4460
+ `;
4461
+ let formatted;
4462
+ try {
4463
+ formatted = await prettier.format(tsContent, {
4464
+ parser: "typescript",
4465
+ singleQuote: true,
4466
+ trailingComma: "all"
4467
+ });
4468
+ } catch {
4469
+ formatted = tsContent;
4470
+ }
4471
+ const outPath = resolve5(opts.out ?? DEFAULT_OUTPUT);
4472
+ if (existsSync5(outPath) && !opts.force) {
4473
+ throw new Error(
4474
+ `${outPath} already exists. Use --force to overwrite.`
4475
+ );
4476
+ }
4477
+ writeFileSync3(outPath, formatted, "utf-8");
4478
+ console.log(chalk7.green(`\u2713 Exported to ${outPath}`));
4479
+ const models = configData.models ?? [];
4480
+ const operations = configData.operations ?? [];
4481
+ const hooks = configData.hooks ?? [];
4482
+ const segments = configData.segments ?? [];
4483
+ const schedules = configData.schedules ?? [];
4484
+ const authProviders = configData.authProviders ?? [];
4485
+ const parts = [];
4486
+ if (models.length > 0) parts.push(`${models.length} model(s)`);
4487
+ if (operations.length > 0) parts.push(`${operations.length} operation(s)`);
4488
+ if (hooks.length > 0) parts.push(`${hooks.length} hook(s)`);
4489
+ if (segments.length > 0) parts.push(`${segments.length} segment(s)`);
4490
+ if (schedules.length > 0) parts.push(`${schedules.length} schedule(s)`);
4491
+ if (authProviders.length > 0) parts.push(`${authProviders.length} auth provider(s)`);
4492
+ if (configData.customerProfileSchema) parts.push("customer profile schema");
4493
+ if (parts.length > 0) {
4494
+ console.log(chalk7.dim(` Contains: ${parts.join(", ")}`));
4495
+ }
4496
+ }
4497
+ )
4498
+ );
4499
+ }
4500
+
4501
+ // src/commands/remove.ts
4502
+ import chalk8 from "chalk";
4297
4503
  import inquirer5 from "inquirer";
4298
4504
  function registerRemoveCommand(program2, globalOpts) {
4299
4505
  program2.command("remove <key>").description("Remove a config and all its provisioned resources").option("--force", "Skip confirmation prompt", false).action(
@@ -4315,13 +4521,13 @@ function registerRemoveCommand(program2, globalOpts) {
4315
4521
  }
4316
4522
  ]);
4317
4523
  if (!confirmed) {
4318
- console.log(chalk7.dim("Cancelled."));
4524
+ console.log(chalk8.dim("Cancelled."));
4319
4525
  return;
4320
4526
  }
4321
4527
  }
4322
4528
  await client.configs.deleteConfig(config2.id);
4323
4529
  console.log(
4324
- chalk7.green(`Removed config "${config2.name}" (${config2.key}).`)
4530
+ chalk8.green(`Removed config "${config2.name}" (${config2.key}).`)
4325
4531
  );
4326
4532
  }
4327
4533
  )
@@ -4329,7 +4535,7 @@ function registerRemoveCommand(program2, globalOpts) {
4329
4535
  }
4330
4536
 
4331
4537
  // src/commands/profiles.ts
4332
- import chalk8 from "chalk";
4538
+ import chalk9 from "chalk";
4333
4539
  function registerProfilesCommand(program2, globalOpts) {
4334
4540
  const profiles = program2.command("profiles").description("Manage named project profiles");
4335
4541
  profiles.command("list").description("List all saved project profiles").action(
@@ -4489,7 +4695,7 @@ function registerProfilesCommand(program2, globalOpts) {
4489
4695
  if (opts.json || opts.jsonl) {
4490
4696
  formatOutput({ deleted: name }, opts);
4491
4697
  } else {
4492
- console.log(chalk8.green(`Deleted profile "${name}".`));
4698
+ console.log(chalk9.green(`Deleted profile "${name}".`));
4493
4699
  }
4494
4700
  }
4495
4701
  )
@@ -4498,8 +4704,8 @@ function registerProfilesCommand(program2, globalOpts) {
4498
4704
 
4499
4705
  // src/commands/register-commands.ts
4500
4706
  import { readdirSync } from "fs";
4501
- import { resolve as resolve5 } from "path";
4502
- import chalk9 from "chalk";
4707
+ import { resolve as resolve6 } from "path";
4708
+ import chalk10 from "chalk";
4503
4709
 
4504
4710
  // src/command-registry/command-map.ts
4505
4711
  var COMMANDS = [
@@ -6297,7 +6503,7 @@ function buildDispatchTable() {
6297
6503
  unregisterConfig: async (v, c) => await c.configs.deleteConfig(str(v.id)),
6298
6504
  triggerConfigSync: async (v, _c) => {
6299
6505
  console.log(
6300
- chalk9.yellow(
6506
+ chalk10.yellow(
6301
6507
  `Config sync trigger for ${str(v.configId)} is not yet available via ConnectRPC.`
6302
6508
  )
6303
6509
  );
@@ -6467,11 +6673,11 @@ function registerDynamicCommands(program2, globalOpts) {
6467
6673
  variables.limit = flags.limit;
6468
6674
  }
6469
6675
  if (flags.dir && entry.acceptsInput) {
6470
- const dirPath = resolve5(String(flags.dir));
6676
+ const dirPath = resolve6(String(flags.dir));
6471
6677
  const files = readdirSync(dirPath).filter((f) => /\.(json|ts|js|mjs)$/.test(f)).sort();
6472
6678
  if (files.length === 0) {
6473
6679
  console.error(
6474
- chalk9.yellow(`No .json/.ts/.js files found in ${dirPath}`)
6680
+ chalk10.yellow(`No .json/.ts/.js files found in ${dirPath}`)
6475
6681
  );
6476
6682
  return;
6477
6683
  }
@@ -6479,7 +6685,7 @@ function registerDynamicCommands(program2, globalOpts) {
6479
6685
  let updated = 0;
6480
6686
  let failed = 0;
6481
6687
  for (const file of files) {
6482
- const filePath = resolve5(dirPath, file);
6688
+ const filePath = resolve6(dirPath, file);
6483
6689
  const fileData = await parseInputData({ file: filePath });
6484
6690
  const argName = entry.inputArgName ?? "input";
6485
6691
  const fileVars = { ...variables, [argName]: fileData };
@@ -6514,19 +6720,19 @@ function registerDynamicCommands(program2, globalOpts) {
6514
6720
  } catch (updateErr) {
6515
6721
  failed++;
6516
6722
  const msg2 = updateErr instanceof Error ? updateErr.message : String(updateErr);
6517
- console.error(chalk9.red(`\u2717 ${label}:`), msg2);
6723
+ console.error(chalk10.red(`\u2717 ${label}:`), msg2);
6518
6724
  continue;
6519
6725
  }
6520
6726
  }
6521
6727
  failed++;
6522
6728
  const msg = err instanceof Error ? err.message : String(err);
6523
- console.error(chalk9.red(`\u2717 ${label}:`), msg);
6729
+ console.error(chalk10.red(`\u2717 ${label}:`), msg);
6524
6730
  }
6525
6731
  }
6526
6732
  if (!(opts.json || opts.jsonl || opts.quiet)) {
6527
6733
  console.log("");
6528
6734
  console.log(
6529
- chalk9.bold(
6735
+ chalk10.bold(
6530
6736
  `Done: ${created} created${updated ? `, ${updated} updated` : ""}${failed ? `, ${failed} failed` : ""}`
6531
6737
  )
6532
6738
  );
@@ -6687,7 +6893,7 @@ function registerDynamicCommands(program2, globalOpts) {
6687
6893
  }
6688
6894
  } else if (!(opts.json || opts.jsonl || opts.quiet)) {
6689
6895
  console.error(
6690
- chalk9.yellow(
6896
+ chalk10.yellow(
6691
6897
  "Could not auto-publish: no version found in response"
6692
6898
  )
6693
6899
  );
@@ -6702,7 +6908,7 @@ function registerDynamicCommands(program2, globalOpts) {
6702
6908
  // src/cli.ts
6703
6909
  var __filename = fileURLToPath(import.meta.url);
6704
6910
  var __dirname = dirname4(__filename);
6705
- config({ path: resolve6(__dirname, "../.env.local") });
6911
+ config({ path: resolve7(__dirname, "../.env.local") });
6706
6912
  var require2 = createRequire(import.meta.url);
6707
6913
  var { version } = require2("../package.json");
6708
6914
  var program = new Command();
@@ -6725,6 +6931,7 @@ registerProfilesCommand(program, getGlobalOpts);
6725
6931
  registerMediaCommands(program, getGlobalOpts);
6726
6932
  registerSearchCommands(program, getGlobalOpts);
6727
6933
  registerPushCommand(program, getGlobalOpts);
6934
+ registerPullCommand(program, getGlobalOpts);
6728
6935
  registerRemoveCommand(program, getGlobalOpts);
6729
6936
  registerCreateConfigCommand(program, getGlobalOpts);
6730
6937
  registerInitCommands(program, getGlobalOpts);
@@ -98,6 +98,16 @@ interface ApplyConfigHookInput {
98
98
  expression?: Record<string, unknown>;
99
99
  hooks?: ApplyConfigHookInput[];
100
100
  }
101
+ interface ApplyConfigApiKeyInput {
102
+ /** Name for this API key (e.g. "Tilly iOS", "Tilly BFF"). */
103
+ name: string;
104
+ /** Key type: 'public' for client apps, 'secret' for BFF/server. */
105
+ keyType: 'public' | 'secret';
106
+ /** Environment variable name to write the key to in .env (e.g. "FOIR_PUBLIC_KEY"). */
107
+ envVar: string;
108
+ /** Optional scopes to restrict the key. */
109
+ scopes?: Record<string, unknown>;
110
+ }
101
111
  interface ApplyConfigInput {
102
112
  key: string;
103
113
  name: string;
@@ -110,6 +120,7 @@ interface ApplyConfigInput {
110
120
  hooks?: ApplyConfigHookInput[];
111
121
  authProviders?: ApplyConfigAuthProviderInput[];
112
122
  placements?: ApplyConfigPlacementInput[];
123
+ apiKeys?: ApplyConfigApiKeyInput[];
113
124
  [key: string]: unknown;
114
125
  }
115
126
  /** Define a complete config manifest. */
@@ -133,4 +144,4 @@ declare function defineHook(hook: ApplyConfigHookInput): ApplyConfigHookInput;
133
144
  /** Define an editor placement (sidebar or main-editor tab). */
134
145
  declare function definePlacement(placement: ApplyConfigPlacementInput): ApplyConfigPlacementInput;
135
146
 
136
- export { type ApplyConfigAuthProviderInput, type ApplyConfigHookInput, type ApplyConfigInput, type ApplyConfigModelInput, type ApplyConfigOperationInput, type ApplyConfigPlacementInput, type ApplyConfigScheduleInput, type ApplyConfigSegmentInput, type FieldDefinitionInput, defineAuthProvider, defineConfig, defineExtension, defineField, defineHook, defineModel, defineOperation, definePlacement, defineSchedule, defineSegment };
147
+ export { type ApplyConfigApiKeyInput, type ApplyConfigAuthProviderInput, type ApplyConfigHookInput, type ApplyConfigInput, type ApplyConfigModelInput, type ApplyConfigOperationInput, type ApplyConfigPlacementInput, type ApplyConfigScheduleInput, type ApplyConfigSegmentInput, type FieldDefinitionInput, defineAuthProvider, defineConfig, defineExtension, defineField, defineHook, defineModel, defineOperation, definePlacement, defineSchedule, defineSegment };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eide/foir-cli",
3
- "version": "0.3.2",
3
+ "version": "0.4.0",
4
4
  "description": "Universal platform CLI for Foir platform",
5
5
  "type": "module",
6
6
  "publishConfig": {
@@ -49,7 +49,7 @@
49
49
  "@bufbuild/protobuf": "^2.0.0",
50
50
  "@connectrpc/connect": "^2.0.0",
51
51
  "@connectrpc/connect-node": "^2.0.0",
52
- "@eide/foir-proto-ts": "^0.1.0",
52
+ "@eide/foir-proto-ts": "^0.3.1",
53
53
  "chalk": "^5.3.0",
54
54
  "commander": "^12.1.0",
55
55
  "dotenv": "^16.4.5",