@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.js CHANGED
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  exitCodeFor,
4
4
  runCli
5
- } from "./chunk-3AC74CD2.js";
5
+ } from "./chunk-AN6KZMR5.js";
6
6
 
7
7
  // src/bin.ts
8
8
  runCli().catch((err) => {
@@ -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 tenantIdFor2 } from "@odla-ai/apps";
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 = tenantIdFor2(cfg.app.id, env);
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 tenantIdFor3 } from "@odla-ai/apps";
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: tenantIdFor3(cfg.app.id, options.env), value, doFetch, out };
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-3AC74CD2.js.map
7289
+ //# sourceMappingURL=chunk-AN6KZMR5.js.map