@eide/foir-cli 0.13.1 → 0.14.1

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/dist/cli.js +257 -109
  2. package/package.json +2 -2
package/dist/cli.js CHANGED
@@ -472,6 +472,7 @@ import { HooksService as HooksService2 } from "@eide/foir-proto-ts/hooks/v1/hook
472
472
  import { NotificationsService as NotificationsService2 } from "@eide/foir-proto-ts/notifications/v1/notifications_pb";
473
473
  import { SchedulesService as SchedulesService2 } from "@eide/foir-proto-ts/schedules/v1/schedules_pb";
474
474
  import { AppsService as AppsService2 } from "@eide/foir-proto-ts/apps/v1/apps_service_pb";
475
+ import { SecretsService as SecretsService2 } from "@eide/foir-proto-ts/secrets/v1/secrets_pb";
475
476
 
476
477
  // src/lib/rpc/identity.ts
477
478
  import { create } from "@bufbuild/protobuf";
@@ -1447,21 +1448,12 @@ import {
1447
1448
  ListScheduledPublishesRequestSchema,
1448
1449
  ListDraftVersionsRequestSchema,
1449
1450
  BatchPublishVersionsRequestSchema,
1450
- CreatePublishBatchRequestSchema,
1451
- UpdatePublishBatchRequestSchema,
1452
- CancelPublishBatchRequestSchema,
1453
- RollbackPublishBatchRequestSchema,
1454
- RetryFailedBatchItemsRequestSchema,
1455
- AddItemsToPublishBatchRequestSchema,
1456
- RemoveItemsFromPublishBatchRequestSchema,
1457
- ListPublishBatchesRequestSchema,
1458
- GetPublishBatchRequestSchema,
1459
1451
  GlobalSearchRequestSchema,
1460
1452
  GetEmbeddingStatsRequestSchema,
1461
1453
  GetRecordEmbeddingsRequestSchema,
1462
1454
  FindSimilarRecordsRequestSchema
1463
1455
  } from "@eide/foir-proto-ts/records/v1/records_pb";
1464
- import { RecordType, BatchStatus } from "@eide/foir-proto-ts/records/v1/records_pb";
1456
+ import { RecordType } from "@eide/foir-proto-ts/records/v1/records_pb";
1465
1457
  function sanitizeData(obj) {
1466
1458
  const result = {};
1467
1459
  for (const [key, value] of Object.entries(obj)) {
@@ -1770,103 +1762,6 @@ function createRecordsMethods(client) {
1770
1762
  publishedCount: resp.publishedCount
1771
1763
  };
1772
1764
  },
1773
- // ── Publish Batches ───────────────────────────────────────
1774
- async createPublishBatch(params) {
1775
- const resp = await client.createPublishBatch(
1776
- create4(CreatePublishBatchRequestSchema, {
1777
- name: params.name,
1778
- versionIds: params.versionIds,
1779
- scheduledAt: params.scheduledAt ? {
1780
- seconds: BigInt(
1781
- Math.floor(params.scheduledAt.getTime() / 1e3)
1782
- ),
1783
- nanos: 0
1784
- } : void 0
1785
- })
1786
- );
1787
- return resp.batch ?? null;
1788
- },
1789
- async updatePublishBatch(params) {
1790
- const resp = await client.updatePublishBatch(
1791
- create4(UpdatePublishBatchRequestSchema, {
1792
- batchId: params.batchId,
1793
- name: params.name,
1794
- scheduledAt: params.scheduledAt ? {
1795
- seconds: BigInt(
1796
- Math.floor(params.scheduledAt.getTime() / 1e3)
1797
- ),
1798
- nanos: 0
1799
- } : void 0
1800
- })
1801
- );
1802
- return resp.batch ?? null;
1803
- },
1804
- async cancelPublishBatch(batchId) {
1805
- const resp = await client.cancelPublishBatch(
1806
- create4(CancelPublishBatchRequestSchema, { batchId })
1807
- );
1808
- return resp.batch ?? null;
1809
- },
1810
- async rollbackPublishBatch(batchId) {
1811
- const resp = await client.rollbackPublishBatch(
1812
- create4(RollbackPublishBatchRequestSchema, { batchId })
1813
- );
1814
- return resp.batch ?? null;
1815
- },
1816
- async retryFailedBatchItems(batchId) {
1817
- const resp = await client.retryFailedBatchItems(
1818
- create4(RetryFailedBatchItemsRequestSchema, { batchId })
1819
- );
1820
- return {
1821
- batch: resp.batch ?? null,
1822
- retriedCount: resp.retriedCount
1823
- };
1824
- },
1825
- async addItemsToPublishBatch(batchId, versionIds) {
1826
- const resp = await client.addItemsToPublishBatch(
1827
- create4(AddItemsToPublishBatchRequestSchema, { batchId, versionIds })
1828
- );
1829
- return resp.batch ?? null;
1830
- },
1831
- async removeItemsFromPublishBatch(batchId, versionIds) {
1832
- const resp = await client.removeItemsFromPublishBatch(
1833
- create4(RemoveItemsFromPublishBatchRequestSchema, {
1834
- batchId,
1835
- versionIds
1836
- })
1837
- );
1838
- return resp.batch ?? null;
1839
- },
1840
- async listPublishBatches(params) {
1841
- const resp = await client.listPublishBatches(
1842
- create4(ListPublishBatchesRequestSchema, {
1843
- status: params?.status,
1844
- from: params?.from ? {
1845
- seconds: BigInt(Math.floor(params.from.getTime() / 1e3)),
1846
- nanos: 0
1847
- } : void 0,
1848
- to: params?.to ? {
1849
- seconds: BigInt(Math.floor(params.to.getTime() / 1e3)),
1850
- nanos: 0
1851
- } : void 0,
1852
- limit: params?.limit ?? 50,
1853
- offset: params?.offset ?? 0
1854
- })
1855
- );
1856
- return {
1857
- items: resp.batches ?? [],
1858
- total: resp.total
1859
- };
1860
- },
1861
- async getPublishBatch(batchId) {
1862
- const resp = await client.getPublishBatch(
1863
- create4(GetPublishBatchRequestSchema, { batchId })
1864
- );
1865
- return {
1866
- batch: resp.batch ?? null,
1867
- versions: resp.versions ?? []
1868
- };
1869
- },
1870
1765
  // ── Search & Embeddings ──────────────────────────────────
1871
1766
  async globalSearch(params) {
1872
1767
  const resp = await client.globalSearch(
@@ -3241,6 +3136,74 @@ function createCronSchedulesMethods(client) {
3241
3136
  };
3242
3137
  }
3243
3138
 
3139
+ // src/lib/rpc/secrets.ts
3140
+ import { create as create14 } from "@bufbuild/protobuf";
3141
+ import {
3142
+ PutSecretRequestSchema,
3143
+ GetSecretRequestSchema,
3144
+ ListSecretsRequestSchema,
3145
+ RotateSecretRequestSchema,
3146
+ DeleteSecretRequestSchema,
3147
+ RestoreSecretRequestSchema,
3148
+ PurgeSoftDeletedRequestSchema,
3149
+ OwnerKind
3150
+ } from "@eide/foir-proto-ts/secrets/v1/secrets_pb";
3151
+ function createSecretsMethods(client) {
3152
+ return {
3153
+ async put(args) {
3154
+ const resp = await client.putSecret(
3155
+ create14(PutSecretRequestSchema, {
3156
+ tenantId: args.tenantId,
3157
+ projectId: args.projectId,
3158
+ ownerKind: args.ownerKind,
3159
+ ownerId: args.ownerId ?? "",
3160
+ label: args.label ?? "",
3161
+ plaintext: args.plaintext
3162
+ })
3163
+ );
3164
+ return resp.ref;
3165
+ },
3166
+ async get(ref, purpose) {
3167
+ return client.getSecret(
3168
+ create14(GetSecretRequestSchema, { ref, purpose: purpose ?? "" })
3169
+ );
3170
+ },
3171
+ async list(args) {
3172
+ const resp = await client.listSecrets(
3173
+ create14(ListSecretsRequestSchema, {
3174
+ tenantId: args.tenantId,
3175
+ projectId: args.projectId,
3176
+ ownerKind: args.ownerKind ?? OwnerKind.UNSPECIFIED,
3177
+ ownerId: args.ownerId ?? "",
3178
+ includeSoftDeleted: args.includeSoftDeleted ?? false
3179
+ })
3180
+ );
3181
+ return resp.secrets;
3182
+ },
3183
+ async rotate(ref, plaintext) {
3184
+ const resp = await client.rotateSecret(
3185
+ create14(RotateSecretRequestSchema, { ref, plaintext })
3186
+ );
3187
+ return resp.newRef;
3188
+ },
3189
+ async delete(ref) {
3190
+ await client.deleteSecret(create14(DeleteSecretRequestSchema, { ref }));
3191
+ },
3192
+ async restore(ref) {
3193
+ await client.restoreSecret(create14(RestoreSecretRequestSchema, { ref }));
3194
+ },
3195
+ async purge(args = {}) {
3196
+ const resp = await client.purgeSoftDeleted(
3197
+ create14(PurgeSoftDeletedRequestSchema, {
3198
+ tenantId: args.tenantId ?? "",
3199
+ projectId: args.projectId ?? ""
3200
+ })
3201
+ );
3202
+ return resp.purgedCount;
3203
+ }
3204
+ };
3205
+ }
3206
+
3244
3207
  // src/lib/client.ts
3245
3208
  async function createPlatformClient(options) {
3246
3209
  const apiUrl = getApiUrl(options);
@@ -3300,7 +3263,8 @@ async function createPlatformClient(options) {
3300
3263
  cronSchedules: createCronSchedulesMethods(
3301
3264
  createRpcClient(SchedulesService2, transport)
3302
3265
  ),
3303
- apps: createAppsMethods(createRpcClient(AppsService2, transport))
3266
+ apps: createAppsMethods(createRpcClient(AppsService2, transport)),
3267
+ secrets: createSecretsMethods(createRpcClient(SecretsService2, transport))
3304
3268
  };
3305
3269
  }
3306
3270
  function createPlatformClientWithHeaders(apiUrl, headers) {
@@ -3336,7 +3300,8 @@ function createPlatformClientWithHeaders(apiUrl, headers) {
3336
3300
  cronSchedules: createCronSchedulesMethods(
3337
3301
  createRpcClient(SchedulesService2, transport)
3338
3302
  ),
3339
- apps: createAppsMethods(createRpcClient(AppsService2, transport))
3303
+ apps: createAppsMethods(createRpcClient(AppsService2, transport)),
3304
+ secrets: createSecretsMethods(createRpcClient(SecretsService2, transport))
3340
3305
  };
3341
3306
  }
3342
3307
  async function getStorageAuth(options) {
@@ -8758,6 +8723,188 @@ function classToLabel(n) {
8758
8723
  }
8759
8724
  }
8760
8725
 
8726
+ // src/commands/secrets.ts
8727
+ import { promises as fs5 } from "fs";
8728
+ function registerSecretsCommands(program2, globalOpts) {
8729
+ const secrets = program2.command("secrets").description("Manage vault secrets");
8730
+ secrets.command("put").description("Store a new secret and print its ref").option("--label <label>", "Optional human-readable label").option("--app <name>", "Owner: app name (defaults to project-owned)").option("--file <path>", "Read plaintext from file (binary-safe)").option("--value <plaintext>", "Plaintext value (string only; prefer --file for binary)").action(
8731
+ withErrorHandler(globalOpts, async (cmdOpts) => {
8732
+ const opts = globalOpts();
8733
+ const resolved = await requireProject2(opts);
8734
+ const plaintext = await readPlaintext(cmdOpts);
8735
+ const client = await createPlatformClient(opts);
8736
+ const ownerKind = cmdOpts.app ? OwnerKind.APP : OwnerKind.PROJECT;
8737
+ const ref = await client.secrets.put({
8738
+ tenantId: resolved.project.tenantId,
8739
+ projectId: resolved.project.id,
8740
+ ownerKind,
8741
+ ownerId: cmdOpts.app,
8742
+ label: cmdOpts.label,
8743
+ plaintext
8744
+ });
8745
+ if (opts.json || opts.jsonl) {
8746
+ formatOutput({ ref }, opts);
8747
+ } else if (opts.quiet) {
8748
+ console.log(ref);
8749
+ } else {
8750
+ success(`Stored secret`);
8751
+ console.log(` ref: ${ref}`);
8752
+ if (cmdOpts.label) console.log(` label: ${cmdOpts.label}`);
8753
+ if (cmdOpts.app) console.log(` app: ${cmdOpts.app}`);
8754
+ }
8755
+ })
8756
+ );
8757
+ secrets.command("list").description("List secrets metadata (no plaintext)").option("--app <name>", "List app-owned secrets for this app").option("--include-soft-deleted", "Include soft-deleted entries").action(
8758
+ withErrorHandler(globalOpts, async (cmdOpts) => {
8759
+ const opts = globalOpts();
8760
+ const resolved = await requireProject2(opts);
8761
+ const client = await createPlatformClient(opts);
8762
+ const ownerKind = cmdOpts.app ? OwnerKind.APP : OwnerKind.PROJECT;
8763
+ const items = await client.secrets.list({
8764
+ tenantId: resolved.project.tenantId,
8765
+ projectId: resolved.project.id,
8766
+ ownerKind,
8767
+ ownerId: typeof cmdOpts.app === "string" ? cmdOpts.app : "",
8768
+ includeSoftDeleted: !!cmdOpts.includeSoftDeleted
8769
+ });
8770
+ if (opts.json || opts.jsonl) {
8771
+ formatOutput(
8772
+ items.map((s) => ({
8773
+ ref: s.ref,
8774
+ label: s.label,
8775
+ ownerKind: ownerKindToString(s.ownerKind),
8776
+ ownerId: s.ownerId,
8777
+ createdAt: tsToString(s.createdAt),
8778
+ lastReadAt: tsToString(s.lastReadAt),
8779
+ softDeletedAt: tsToString(s.softDeletedAt)
8780
+ })),
8781
+ opts
8782
+ );
8783
+ return;
8784
+ }
8785
+ if (items.length === 0) {
8786
+ warn("No secrets found.");
8787
+ return;
8788
+ }
8789
+ for (const s of items) {
8790
+ const owner = s.ownerKind === OwnerKind.APP ? `app:${s.ownerId}` : "project";
8791
+ const deleted = s.softDeletedAt ? " [soft-deleted]" : "";
8792
+ console.log(`${s.ref} ${owner.padEnd(24)} ${s.label ?? ""}${deleted}`);
8793
+ }
8794
+ })
8795
+ );
8796
+ secrets.command("rotate <ref>").description("Replace plaintext for an existing ref; returns new ref").option("--file <path>", "Read plaintext from file (binary-safe)").option("--value <plaintext>", "Plaintext value (string only; prefer --file for binary)").option("--confirm", "Skip confirmation prompt").action(
8797
+ withErrorHandler(globalOpts, async (ref, cmdOpts) => {
8798
+ const opts = globalOpts();
8799
+ const confirmed = await confirmAction(
8800
+ `Rotate secret ${ref}? Every record pointing at it will be updated to the new ref.`,
8801
+ { confirm: !!cmdOpts.confirm }
8802
+ );
8803
+ if (!confirmed) {
8804
+ console.log("Aborted.");
8805
+ return;
8806
+ }
8807
+ const plaintext = await readPlaintext(cmdOpts);
8808
+ const client = await createPlatformClient(opts);
8809
+ const newRef = await client.secrets.rotate(ref, plaintext);
8810
+ if (opts.json || opts.jsonl) {
8811
+ formatOutput({ oldRef: ref, newRef }, opts);
8812
+ } else if (opts.quiet) {
8813
+ console.log(newRef);
8814
+ } else {
8815
+ success(`Rotated`);
8816
+ console.log(` old: ${ref}`);
8817
+ console.log(` new: ${newRef}`);
8818
+ }
8819
+ })
8820
+ );
8821
+ secrets.command("delete <ref>").description("Soft-delete a secret (recoverable until purged)").option("--confirm", "Skip confirmation prompt").action(
8822
+ withErrorHandler(globalOpts, async (ref, cmdOpts) => {
8823
+ const opts = globalOpts();
8824
+ const confirmed = await confirmAction(
8825
+ `Soft-delete secret ${ref}? Refuses if the secret is still referenced.`,
8826
+ { confirm: !!cmdOpts.confirm }
8827
+ );
8828
+ if (!confirmed) {
8829
+ console.log("Aborted.");
8830
+ return;
8831
+ }
8832
+ const client = await createPlatformClient(opts);
8833
+ await client.secrets.delete(ref);
8834
+ success(`Deleted ${ref}`);
8835
+ })
8836
+ );
8837
+ secrets.command("restore <ref>").description("Undo a soft-delete (only valid before purge_after passes)").action(
8838
+ withErrorHandler(globalOpts, async (ref) => {
8839
+ const opts = globalOpts();
8840
+ const client = await createPlatformClient(opts);
8841
+ await client.secrets.restore(ref);
8842
+ success(`Restored ${ref}`);
8843
+ })
8844
+ );
8845
+ secrets.command("purge").description("Drop every soft-deleted secret past its TTL (admin-only)").option("--confirm", "Skip confirmation prompt").action(
8846
+ withErrorHandler(globalOpts, async (cmdOpts) => {
8847
+ const opts = globalOpts();
8848
+ const confirmed = await confirmAction(
8849
+ `Purge soft-deleted secrets? Cannot be undone.`,
8850
+ { confirm: !!cmdOpts.confirm }
8851
+ );
8852
+ if (!confirmed) {
8853
+ console.log("Aborted.");
8854
+ return;
8855
+ }
8856
+ const resolved = await requireProject2(opts);
8857
+ const client = await createPlatformClient(opts);
8858
+ const count = await client.secrets.purge({
8859
+ tenantId: resolved.project.tenantId,
8860
+ projectId: resolved.project.id
8861
+ });
8862
+ success(`Purged ${count} secret(s)`);
8863
+ })
8864
+ );
8865
+ }
8866
+ async function requireProject2(opts) {
8867
+ const resolved = await resolveProjectContext(opts);
8868
+ if (!resolved) {
8869
+ throw new Error(
8870
+ "No project selected. Run `foir select-project` or set FOIR_PROJECT."
8871
+ );
8872
+ }
8873
+ return resolved;
8874
+ }
8875
+ async function readPlaintext(cmdOpts) {
8876
+ const file = typeof cmdOpts.file === "string" ? cmdOpts.file : "";
8877
+ const value = typeof cmdOpts.value === "string" ? cmdOpts.value : "";
8878
+ if (file && value) {
8879
+ throw new Error("Pass either --file or --value, not both.");
8880
+ }
8881
+ if (!file && !value) {
8882
+ throw new Error("One of --file or --value is required.");
8883
+ }
8884
+ if (file) {
8885
+ return fs5.readFile(file);
8886
+ }
8887
+ return new TextEncoder().encode(value);
8888
+ }
8889
+ function ownerKindToString(k) {
8890
+ switch (k) {
8891
+ case OwnerKind.PROJECT:
8892
+ return "project";
8893
+ case OwnerKind.APP:
8894
+ return "app";
8895
+ case OwnerKind.CUSTOMER:
8896
+ return "customer";
8897
+ default:
8898
+ return "";
8899
+ }
8900
+ }
8901
+ function tsToString(t) {
8902
+ if (!t || t.seconds === void 0 && t.nanos === void 0) return "";
8903
+ const seconds = Number(t.seconds ?? 0n);
8904
+ const nanos = t.nanos ?? 0;
8905
+ return new Date(seconds * 1e3 + Math.floor(nanos / 1e6)).toISOString();
8906
+ }
8907
+
8761
8908
  // src/cli.ts
8762
8909
  var __filename = fileURLToPath(import.meta.url);
8763
8910
  var __dirname = dirname4(__filename);
@@ -8807,4 +8954,5 @@ registerNotesCommands(program, getGlobalOpts);
8807
8954
  registerNotificationsCommands(program, getGlobalOpts);
8808
8955
  registerConfigsCommands(program, getGlobalOpts);
8809
8956
  registerAppsCommands(program, getGlobalOpts);
8957
+ registerSecretsCommands(program, getGlobalOpts);
8810
8958
  program.parse();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eide/foir-cli",
3
- "version": "0.13.1",
3
+ "version": "0.14.1",
4
4
  "description": "Universal platform CLI for Foir platform",
5
5
  "type": "module",
6
6
  "publishConfig": {
@@ -50,7 +50,7 @@
50
50
  "@bufbuild/protovalidate": "^1.1.1",
51
51
  "@connectrpc/connect": "^2.0.0",
52
52
  "@connectrpc/connect-node": "^2.0.0",
53
- "@eide/foir-proto-ts": "^0.31.0",
53
+ "@eide/foir-proto-ts": "^0.40.0",
54
54
  "chalk": "^5.3.0",
55
55
  "commander": "^12.1.0",
56
56
  "dotenv": "^16.4.5",