@eide/foir-cli 0.7.0 → 0.9.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 +35 -34
- package/dist/lib/config-helpers.d.ts +1 -1
- package/package.json +2 -2
package/dist/cli.js
CHANGED
|
@@ -2955,7 +2955,7 @@ function createOperationsMethods(client) {
|
|
|
2955
2955
|
allowedRoles: params.allowedRoles ?? [],
|
|
2956
2956
|
precondition: params.precondition,
|
|
2957
2957
|
configId: params.configId,
|
|
2958
|
-
|
|
2958
|
+
supportsAsync: params.supportsAsync,
|
|
2959
2959
|
callbackTtlSeconds: params.callbackTtlSeconds
|
|
2960
2960
|
})
|
|
2961
2961
|
);
|
|
@@ -2976,7 +2976,7 @@ function createOperationsMethods(client) {
|
|
|
2976
2976
|
callbackTimeoutRetryPolicy: params.callbackTimeoutRetryPolicy,
|
|
2977
2977
|
precondition: params.precondition,
|
|
2978
2978
|
isActive: params.isActive,
|
|
2979
|
-
|
|
2979
|
+
supportsAsync: params.supportsAsync,
|
|
2980
2980
|
callbackTtlSeconds: params.callbackTtlSeconds
|
|
2981
2981
|
})
|
|
2982
2982
|
);
|
|
@@ -4880,7 +4880,7 @@ import { resolve as resolve4 } from "path";
|
|
|
4880
4880
|
function zeroCounts() {
|
|
4881
4881
|
return { created: 0, updated: 0, deleted: 0 };
|
|
4882
4882
|
}
|
|
4883
|
-
async function reconcileConfig(client, configId, manifest) {
|
|
4883
|
+
async function reconcileConfig(client, configId, manifest, options = {}) {
|
|
4884
4884
|
const summary = {
|
|
4885
4885
|
models: zeroCounts(),
|
|
4886
4886
|
operations: zeroCounts(),
|
|
@@ -4901,7 +4901,13 @@ async function reconcileConfig(client, configId, manifest) {
|
|
|
4901
4901
|
await reconcileAuthProviders(client, manifest.authProviders ?? [], summary);
|
|
4902
4902
|
await reconcilePlacements(client, configId, manifest.placements ?? [], summary);
|
|
4903
4903
|
await reconcileProfileSchema(client, manifest, summary);
|
|
4904
|
-
await reconcileApiKeys(
|
|
4904
|
+
await reconcileApiKeys(
|
|
4905
|
+
client,
|
|
4906
|
+
manifest.key,
|
|
4907
|
+
manifest.apiKeys ?? [],
|
|
4908
|
+
summary,
|
|
4909
|
+
options.rotateKeys ?? false
|
|
4910
|
+
);
|
|
4905
4911
|
return summary;
|
|
4906
4912
|
}
|
|
4907
4913
|
async function reconcileModels(client, configId, models, summary) {
|
|
@@ -4973,8 +4979,8 @@ async function reconcileOperations(client, configId, operations, operationBaseUr
|
|
|
4973
4979
|
}
|
|
4974
4980
|
const ex = existingByKey.get(op.key);
|
|
4975
4981
|
const endpoint = resolveEndpoint(op.endpoint, operationBaseUrl);
|
|
4976
|
-
const
|
|
4977
|
-
if (
|
|
4982
|
+
const supportsAsync = op.mode === "async";
|
|
4983
|
+
if (supportsAsync && op.timeoutMs && op.timeoutMs > 1e4) {
|
|
4978
4984
|
console.warn(
|
|
4979
4985
|
`\u26A0 operation "${op.key}": mode=async but timeoutMs=${op.timeoutMs} \u2014 ack should return in <10s; long timeouts mask slow extensions`
|
|
4980
4986
|
);
|
|
@@ -4994,7 +5000,7 @@ async function reconcileOperations(client, configId, operations, operationBaseUr
|
|
|
4994
5000
|
callbackTimeoutRetryPolicy: op.callbackTimeoutRetryPolicy ?? empty,
|
|
4995
5001
|
precondition: op.precondition ?? empty,
|
|
4996
5002
|
isActive: op.isActive,
|
|
4997
|
-
|
|
5003
|
+
supportsAsync,
|
|
4998
5004
|
callbackTtlSeconds: op.callbackTtlSeconds
|
|
4999
5005
|
});
|
|
5000
5006
|
summary.operations.updated++;
|
|
@@ -5015,7 +5021,7 @@ async function reconcileOperations(client, configId, operations, operationBaseUr
|
|
|
5015
5021
|
allowedRoles: op.allowedRoles,
|
|
5016
5022
|
precondition: op.precondition,
|
|
5017
5023
|
configId,
|
|
5018
|
-
|
|
5024
|
+
supportsAsync,
|
|
5019
5025
|
callbackTtlSeconds: op.callbackTtlSeconds
|
|
5020
5026
|
});
|
|
5021
5027
|
summary.operations.created++;
|
|
@@ -5242,7 +5248,7 @@ async function reconcileProfileSchema(client, manifest, summary) {
|
|
|
5242
5248
|
});
|
|
5243
5249
|
summary.profileSchemaUpdated = true;
|
|
5244
5250
|
}
|
|
5245
|
-
async function reconcileApiKeys(client, configKey, apiKeys, summary) {
|
|
5251
|
+
async function reconcileApiKeys(client, configKey, apiKeys, summary, rotateKeys) {
|
|
5246
5252
|
if (apiKeys.length === 0) return;
|
|
5247
5253
|
const existing = await client.identity.listApiKeys({ limit: 200 });
|
|
5248
5254
|
const existingByName = new Map(
|
|
@@ -5264,8 +5270,10 @@ async function reconcileApiKeys(client, configKey, apiKeys, summary) {
|
|
|
5264
5270
|
updateScopes: true
|
|
5265
5271
|
});
|
|
5266
5272
|
}
|
|
5267
|
-
|
|
5268
|
-
|
|
5273
|
+
if (rotateKeys) {
|
|
5274
|
+
const rotated = await client.identity.rotateApiKey(existingKey.id);
|
|
5275
|
+
rawKey = rotated?.apiKey?.rawKey;
|
|
5276
|
+
}
|
|
5269
5277
|
} else {
|
|
5270
5278
|
const result = await client.identity.createApiKey({
|
|
5271
5279
|
name: key.name,
|
|
@@ -5603,23 +5611,6 @@ function syncEnvVar(envPath, key, value) {
|
|
|
5603
5611
|
`, "utf-8");
|
|
5604
5612
|
return "written";
|
|
5605
5613
|
}
|
|
5606
|
-
function writeEnvVar(envPath, key, value) {
|
|
5607
|
-
let content = "";
|
|
5608
|
-
if (existsSync4(envPath)) {
|
|
5609
|
-
content = readFileSync(envPath, "utf-8");
|
|
5610
|
-
const regex = new RegExp(`^${key}=`, "m");
|
|
5611
|
-
if (regex.test(content)) {
|
|
5612
|
-
return false;
|
|
5613
|
-
}
|
|
5614
|
-
}
|
|
5615
|
-
if (content && !content.endsWith("\n")) {
|
|
5616
|
-
content += "\n";
|
|
5617
|
-
}
|
|
5618
|
-
content += `${key}=${value}
|
|
5619
|
-
`;
|
|
5620
|
-
writeFileSync2(envPath, content, "utf-8");
|
|
5621
|
-
return true;
|
|
5622
|
-
}
|
|
5623
5614
|
function printSummary(summary) {
|
|
5624
5615
|
const lines = [];
|
|
5625
5616
|
const fmt = (label, c) => {
|
|
@@ -5645,7 +5636,11 @@ function printSummary(summary) {
|
|
|
5645
5636
|
}
|
|
5646
5637
|
}
|
|
5647
5638
|
function registerPushCommand(program2, globalOpts) {
|
|
5648
|
-
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(
|
|
5639
|
+
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(
|
|
5640
|
+
"--rotate-keys",
|
|
5641
|
+
"Rotate existing API keys and rewrite their values in .env",
|
|
5642
|
+
false
|
|
5643
|
+
).option("--env <path>", "Path to .env file (default: .env)").action(
|
|
5649
5644
|
withErrorHandler(
|
|
5650
5645
|
globalOpts,
|
|
5651
5646
|
async (opts) => {
|
|
@@ -5685,7 +5680,9 @@ function registerPushCommand(program2, globalOpts) {
|
|
|
5685
5680
|
}
|
|
5686
5681
|
const configId = applyResult.id;
|
|
5687
5682
|
console.log(chalk6.dim("Reconciling resources..."));
|
|
5688
|
-
const summary = await reconcileConfig(client, configId, config2
|
|
5683
|
+
const summary = await reconcileConfig(client, configId, config2, {
|
|
5684
|
+
rotateKeys: opts.rotateKeys ?? false
|
|
5685
|
+
});
|
|
5689
5686
|
console.log();
|
|
5690
5687
|
console.log(chalk6.green("\u2713 Config applied successfully"));
|
|
5691
5688
|
console.log(` Config ID: ${chalk6.cyan(configId)}`);
|
|
@@ -5724,14 +5721,18 @@ function registerPushCommand(program2, globalOpts) {
|
|
|
5724
5721
|
if (envWrites.length > 0) {
|
|
5725
5722
|
console.log();
|
|
5726
5723
|
for (const { key, value, label } of envWrites) {
|
|
5727
|
-
const
|
|
5728
|
-
if (
|
|
5724
|
+
const result = syncEnvVar(envPath, key, value);
|
|
5725
|
+
if (result === "unchanged") {
|
|
5729
5726
|
console.log(
|
|
5730
|
-
chalk6.
|
|
5727
|
+
chalk6.dim(` ${label}: ${key} already up to date in ${envPath}, skipped`)
|
|
5728
|
+
);
|
|
5729
|
+
} else if (result === "replaced") {
|
|
5730
|
+
console.log(
|
|
5731
|
+
chalk6.yellow(`\u27F3 ${label}`) + chalk6.dim(` \u2192 ${key} updated in ${envPath}`)
|
|
5731
5732
|
);
|
|
5732
5733
|
} else {
|
|
5733
5734
|
console.log(
|
|
5734
|
-
chalk6.
|
|
5735
|
+
chalk6.green(`\u2713 ${label}`) + chalk6.dim(` \u2192 ${key} written to ${envPath}`)
|
|
5735
5736
|
);
|
|
5736
5737
|
}
|
|
5737
5738
|
}
|
|
@@ -112,7 +112,7 @@ interface ApplyConfigOperationInput {
|
|
|
112
112
|
* in 2026-04 — every ASYNC dispatch now carries a scoped callback token
|
|
113
113
|
* and the platform tracks the execution to terminal state.
|
|
114
114
|
*
|
|
115
|
-
* Default: `sync`. The CLI maps this to `
|
|
115
|
+
* Default: `sync`. The CLI maps this to `supportsAsync` on the
|
|
116
116
|
* platform Operation row — the operation can still be dispatched in SYNC
|
|
117
117
|
* mode at runtime when callers want a blocking call.
|
|
118
118
|
*/
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@eide/foir-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.0",
|
|
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.
|
|
53
|
+
"@eide/foir-proto-ts": "^0.17.0",
|
|
54
54
|
"chalk": "^5.3.0",
|
|
55
55
|
"commander": "^12.1.0",
|
|
56
56
|
"dotenv": "^16.4.5",
|