@odla-ai/cli 0.14.0 → 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.
- package/dist/bin.cjs +62 -45
- package/dist/bin.cjs.map +1 -1
- package/dist/bin.js +1 -1
- package/dist/{chunk-3AC74CD2.js → chunk-AN6KZMR5.js} +62 -45
- package/dist/chunk-AN6KZMR5.js.map +1 -0
- package/dist/index.cjs +62 -45
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -2
- package/dist/index.d.ts +3 -2
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/skills/odla/references/co-owners.md +7 -0
- package/dist/chunk-3AC74CD2.js.map +0 -1
package/dist/bin.js
CHANGED
|
@@ -1669,7 +1669,7 @@ function hostedSecurityCredential(value) {
|
|
|
1669
1669
|
// src/security-hosted-github.ts
|
|
1670
1670
|
async function connectGitHubSecuritySource(options) {
|
|
1671
1671
|
const out = options.stdout ?? console;
|
|
1672
|
-
const repository = githubRepositoryName(options.repository);
|
|
1672
|
+
const repository = options.repository === void 0 ? void 0 : githubRepositoryName(options.repository);
|
|
1673
1673
|
const attempt = await requestHostedSecurityJson(
|
|
1674
1674
|
options,
|
|
1675
1675
|
"/registry/github/connect",
|
|
@@ -1678,7 +1678,7 @@ async function connectGitHubSecuritySource(options) {
|
|
|
1678
1678
|
body: JSON.stringify({
|
|
1679
1679
|
appId: hostedIdentifier(options.appId, "appId"),
|
|
1680
1680
|
env: hostedIdentifier(options.env, "env"),
|
|
1681
|
-
repository
|
|
1681
|
+
...repository === void 0 ? {} : { repository }
|
|
1682
1682
|
})
|
|
1683
1683
|
},
|
|
1684
1684
|
"start GitHub connection"
|
|
@@ -5079,7 +5079,7 @@ function assertWranglerConfig(cfg) {
|
|
|
5079
5079
|
}
|
|
5080
5080
|
|
|
5081
5081
|
// src/provision.ts
|
|
5082
|
-
import { createAppsClient, tenantIdFor as
|
|
5082
|
+
import { createAppsClient, tenantIdFor as tenantIdFor3 } from "@odla-ai/apps";
|
|
5083
5083
|
import { putSecret } from "@odla-ai/ai";
|
|
5084
5084
|
import process8 from "process";
|
|
5085
5085
|
|
|
@@ -5232,6 +5232,7 @@ async function safeText3(res) {
|
|
|
5232
5232
|
|
|
5233
5233
|
// src/provision-helpers.ts
|
|
5234
5234
|
import { DEFAULT_SECRET_NAMES } from "@odla-ai/ai";
|
|
5235
|
+
import { tenantIdFor as tenantIdFor2 } from "@odla-ai/apps";
|
|
5235
5236
|
function serviceRank(service) {
|
|
5236
5237
|
if (service === "db") return 0;
|
|
5237
5238
|
if (service === "calendar") return 2;
|
|
@@ -5241,6 +5242,54 @@ function defaultSecretName(provider) {
|
|
|
5241
5242
|
const names = DEFAULT_SECRET_NAMES;
|
|
5242
5243
|
return names[provider] ?? `${provider}_api_key`;
|
|
5243
5244
|
}
|
|
5245
|
+
async function assertTenantAdminAccess(doFetch, cfg, env, token) {
|
|
5246
|
+
const tenantId = tenantIdFor2(cfg.app.id, env);
|
|
5247
|
+
const res = await doFetch(`${cfg.dbEndpoint}/admin/apps/${encodeURIComponent(tenantId)}/entitlements`, {
|
|
5248
|
+
headers: { authorization: `Bearer ${token}` }
|
|
5249
|
+
});
|
|
5250
|
+
if (res.ok || res.status === 404) return;
|
|
5251
|
+
if (res.status === 403) {
|
|
5252
|
+
throw new Error(
|
|
5253
|
+
`${env}: you are not an owner of "${cfg.app.id}" (tenant ${tenantId}) \u2014 nothing was minted or written; ask an existing owner to run "odla-ai app owners add <your-email>", then re-run provision`
|
|
5254
|
+
);
|
|
5255
|
+
}
|
|
5256
|
+
throw new Error(`${env}: tenant access preflight (${tenantId}) failed: ${res.status} ${await safeText4(res)}`);
|
|
5257
|
+
}
|
|
5258
|
+
async function readRegistryApp(cfg, token, doFetch) {
|
|
5259
|
+
const res = await doFetch(`${cfg.platformUrl}/registry/apps/${encodeURIComponent(cfg.app.id)}`, {
|
|
5260
|
+
headers: { authorization: `Bearer ${token}` }
|
|
5261
|
+
});
|
|
5262
|
+
if (res.status === 404) return null;
|
|
5263
|
+
if (!res.ok) return null;
|
|
5264
|
+
const json2 = await res.json();
|
|
5265
|
+
return json2.app ?? null;
|
|
5266
|
+
}
|
|
5267
|
+
async function postJson2(doFetch, url, bearer, body) {
|
|
5268
|
+
const res = await doFetch(url, {
|
|
5269
|
+
method: "POST",
|
|
5270
|
+
headers: { authorization: `Bearer ${bearer}`, "content-type": "application/json" },
|
|
5271
|
+
body: JSON.stringify(body)
|
|
5272
|
+
});
|
|
5273
|
+
if (!res.ok) throw new Error(`${new URL(url).pathname} failed: ${res.status} ${await safeText4(res)}`);
|
|
5274
|
+
}
|
|
5275
|
+
function normalizeClerkConfig(value) {
|
|
5276
|
+
if (!value) return null;
|
|
5277
|
+
if (typeof value === "string") {
|
|
5278
|
+
const publishableKey2 = envValue(value);
|
|
5279
|
+
return publishableKey2 ? { publishableKey: publishableKey2 } : null;
|
|
5280
|
+
}
|
|
5281
|
+
if (typeof value !== "object") return null;
|
|
5282
|
+
const cfg = value;
|
|
5283
|
+
const publishableKey = envValue(cfg.publishableKey);
|
|
5284
|
+
return publishableKey ? { publishableKey, ...cfg.audience ? { audience: cfg.audience } : {}, ...cfg.mode ? { mode: cfg.mode } : {} } : null;
|
|
5285
|
+
}
|
|
5286
|
+
async function safeText4(res) {
|
|
5287
|
+
try {
|
|
5288
|
+
return redactSecrets((await res.text()).slice(0, 500));
|
|
5289
|
+
} catch {
|
|
5290
|
+
return "";
|
|
5291
|
+
}
|
|
5292
|
+
}
|
|
5244
5293
|
|
|
5245
5294
|
// src/provision.ts
|
|
5246
5295
|
async function provision(options) {
|
|
@@ -5320,6 +5369,9 @@ async function provision(options) {
|
|
|
5320
5369
|
await apps.createApp({ name: cfg.app.name, appId: cfg.app.id });
|
|
5321
5370
|
out.log(`app: created ${cfg.app.id}`);
|
|
5322
5371
|
}
|
|
5372
|
+
for (const env of cfg.envs) {
|
|
5373
|
+
await assertTenantAdminAccess(doFetch, cfg, env, token);
|
|
5374
|
+
}
|
|
5323
5375
|
const serviceOrder = [...cfg.services].sort((a, b) => serviceRank(a) - serviceRank(b));
|
|
5324
5376
|
for (const env of cfg.envs) {
|
|
5325
5377
|
for (const service of serviceOrder) {
|
|
@@ -5353,7 +5405,7 @@ async function provision(options) {
|
|
|
5353
5405
|
}
|
|
5354
5406
|
}
|
|
5355
5407
|
for (const env of cfg.envs) {
|
|
5356
|
-
const tenantId =
|
|
5408
|
+
const tenantId = tenantIdFor3(cfg.app.id, env);
|
|
5357
5409
|
credentials = await provisionEnvCredentials({
|
|
5358
5410
|
cfg,
|
|
5359
5411
|
env,
|
|
@@ -5436,45 +5488,10 @@ ${env}: credentials are already saved; retry "odla-ai secrets push --env ${env}$
|
|
|
5436
5488
|
}
|
|
5437
5489
|
}
|
|
5438
5490
|
}
|
|
5439
|
-
async function readRegistryApp(cfg, token, doFetch) {
|
|
5440
|
-
const res = await doFetch(`${cfg.platformUrl}/registry/apps/${encodeURIComponent(cfg.app.id)}`, {
|
|
5441
|
-
headers: { authorization: `Bearer ${token}` }
|
|
5442
|
-
});
|
|
5443
|
-
if (res.status === 404) return null;
|
|
5444
|
-
if (!res.ok) return null;
|
|
5445
|
-
const json2 = await res.json();
|
|
5446
|
-
return json2.app ?? null;
|
|
5447
|
-
}
|
|
5448
|
-
async function postJson2(doFetch, url, bearer, body) {
|
|
5449
|
-
const res = await doFetch(url, {
|
|
5450
|
-
method: "POST",
|
|
5451
|
-
headers: { authorization: `Bearer ${bearer}`, "content-type": "application/json" },
|
|
5452
|
-
body: JSON.stringify(body)
|
|
5453
|
-
});
|
|
5454
|
-
if (!res.ok) throw new Error(`${new URL(url).pathname} failed: ${res.status} ${await safeText4(res)}`);
|
|
5455
|
-
}
|
|
5456
|
-
function normalizeClerkConfig(value) {
|
|
5457
|
-
if (!value) return null;
|
|
5458
|
-
if (typeof value === "string") {
|
|
5459
|
-
const publishableKey2 = envValue(value);
|
|
5460
|
-
return publishableKey2 ? { publishableKey: publishableKey2 } : null;
|
|
5461
|
-
}
|
|
5462
|
-
if (typeof value !== "object") return null;
|
|
5463
|
-
const cfg = value;
|
|
5464
|
-
const publishableKey = envValue(cfg.publishableKey);
|
|
5465
|
-
return publishableKey ? { publishableKey, ...cfg.audience ? { audience: cfg.audience } : {}, ...cfg.mode ? { mode: cfg.mode } : {} } : null;
|
|
5466
|
-
}
|
|
5467
|
-
async function safeText4(res) {
|
|
5468
|
-
try {
|
|
5469
|
-
return redactSecrets((await res.text()).slice(0, 500));
|
|
5470
|
-
} catch {
|
|
5471
|
-
return "";
|
|
5472
|
-
}
|
|
5473
|
-
}
|
|
5474
5491
|
|
|
5475
5492
|
// src/secrets-set.ts
|
|
5476
5493
|
import { putSecret as putSecret2 } from "@odla-ai/ai";
|
|
5477
|
-
import { tenantIdFor as
|
|
5494
|
+
import { tenantIdFor as tenantIdFor4 } from "@odla-ai/apps";
|
|
5478
5495
|
var PROD_ENV_NAMES2 = /* @__PURE__ */ new Set(["prod", "production"]);
|
|
5479
5496
|
async function secretsSet(options) {
|
|
5480
5497
|
const name = (options.name ?? "").trim();
|
|
@@ -5526,7 +5543,7 @@ async function resolveVaultWrite(options) {
|
|
|
5526
5543
|
throw new Error(`refusing to store a secret for "${options.env}" without --yes`);
|
|
5527
5544
|
}
|
|
5528
5545
|
const value = await secretInputValue(options, "secret");
|
|
5529
|
-
return { cfg, tenantId:
|
|
5546
|
+
return { cfg, tenantId: tenantIdFor4(cfg.app.id, options.env), value, doFetch, out };
|
|
5530
5547
|
}
|
|
5531
5548
|
|
|
5532
5549
|
// src/security.ts
|
|
@@ -6966,16 +6983,16 @@ async function githubSecurityCommand(parsed, dependencies) {
|
|
|
6966
6983
|
}
|
|
6967
6984
|
assertArgs(parsed, ["config", "env", "platform", "repo", "email", "open"], 3);
|
|
6968
6985
|
const context = await hostedSecurityContext(parsed, dependencies);
|
|
6969
|
-
const repository = stringOpt(parsed.options.repo) ?? await inferGitHubRepository(process.cwd(), dependencies.readGitOrigin);
|
|
6986
|
+
const repository = stringOpt(parsed.options.repo) ?? await inferGitHubRepository(process.cwd(), dependencies.readGitOrigin).catch(() => void 0);
|
|
6970
6987
|
const connection = await connectGitHubSecuritySource({
|
|
6971
6988
|
...context,
|
|
6972
|
-
repository,
|
|
6989
|
+
...repository === void 0 ? {} : { repository },
|
|
6973
6990
|
open: parsed.options.open !== false,
|
|
6974
6991
|
openInstallUrl: dependencies.openUrl ?? openUrl,
|
|
6975
6992
|
wait: dependencies.pollWait,
|
|
6976
6993
|
stdout: context.stdout
|
|
6977
6994
|
});
|
|
6978
|
-
context.stdout.log(`github: connected ${connection.repository ?? repository} (${connection.sourceId ?? "source pending"})`);
|
|
6995
|
+
context.stdout.log(`github: connected ${connection.repository ?? repository ?? "app repository"} (${connection.sourceId ?? "source pending"})`);
|
|
6979
6996
|
context.stdout.log("github: odla.ai stores the installation; no PAT or GitHub token is written locally");
|
|
6980
6997
|
}
|
|
6981
6998
|
async function listSecuritySources(parsed, dependencies) {
|
|
@@ -7269,4 +7286,4 @@ export {
|
|
|
7269
7286
|
exitCodeFor,
|
|
7270
7287
|
runCli
|
|
7271
7288
|
};
|
|
7272
|
-
//# sourceMappingURL=chunk-
|
|
7289
|
+
//# sourceMappingURL=chunk-AN6KZMR5.js.map
|