@opengeni/api-router 1.0.2 → 1.2.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.
@@ -3803,8 +3803,8 @@ async function sendIntegrationEndpointTest(input) {
3803
3803
  // src/routes/workspace-integrations.ts
3804
3804
  import { HTTPException as HTTPException14 } from "hono/http-exception";
3805
3805
  import { z as z10 } from "zod";
3806
- function newIntegrationSecret(prefix) {
3807
- return `${prefix}_${randomBytes2(32).toString("base64url")}`;
3806
+ function newIntegrationSecret(prefix2) {
3807
+ return `${prefix2}_${randomBytes2(32).toString("base64url")}`;
3808
3808
  }
3809
3809
  function iso(value) {
3810
3810
  return value ? value.toISOString() : null;
@@ -4378,13 +4378,13 @@ function registerApiKeyRoutes(app, deps) {
4378
4378
  quantity: 1
4379
4379
  });
4380
4380
  const token = generateApiKeyToken();
4381
- const prefix = token.slice(0, 14);
4381
+ const prefix2 = token.slice(0, 14);
4382
4382
  const apiKey = await createApiKey(deps.db, {
4383
4383
  accountId: grant.accountId,
4384
4384
  workspaceId: grant.workspaceId,
4385
4385
  name: body3.name,
4386
4386
  description: body3.description ?? null,
4387
- prefix,
4387
+ prefix: prefix2,
4388
4388
  keyHash: await sha256Hex(token),
4389
4389
  permissions,
4390
4390
  expiresAt: body3.expiresAt ? new Date(body3.expiresAt) : null
@@ -5843,6 +5843,7 @@ function projectClientModel(model) {
5843
5843
  id: model.id,
5844
5844
  label: model.label,
5845
5845
  ...model.shortLabel ? { shortLabel: model.shortLabel } : {},
5846
+ ...model.logoUrl ? { logoUrl: model.logoUrl } : {},
5846
5847
  ...publicProvider,
5847
5848
  ...source === void 0 ? {} : { source },
5848
5849
  api: model.api,
@@ -9756,6 +9757,7 @@ import {
9756
9757
  setSessionChannel
9757
9758
  } from "@opengeni/db";
9758
9759
  import { createHash as createHash15, randomUUID as randomUUID5 } from "crypto";
9760
+ import { assertGoalResumeAllowed } from "@opengeni/core";
9759
9761
 
9760
9762
  // src/sandbox/enrollment.ts
9761
9763
  import { createPublicKey, randomBytes as randomBytes3, verify } from "crypto";
@@ -14802,7 +14804,7 @@ var PKCE_CHALLENGE = /^[A-Za-z0-9_-]{43}$/u;
14802
14804
  var WORKSPACE_MCP_PATH = /^\/v1\/workspaces\/([0-9a-f-]{36})\/mcp(?:\/(docs|files))?$/u;
14803
14805
  var ORGANIZATION_MCP_PATH = "/v1/mcp";
14804
14806
  function registerMcpOAuthRoutes(app, deps) {
14805
- app.get("/.well-known/oauth-authorization-server", (c) => {
14807
+ const authorizationServerMetadata = (c) => {
14806
14808
  requireMcpOAuthEnabled(deps);
14807
14809
  const issuer = mcpOAuthIssuer(deps);
14808
14810
  c.header("cache-control", "public, max-age=300");
@@ -14820,7 +14822,9 @@ function registerMcpOAuthRoutes(app, deps) {
14820
14822
  authorization_response_iss_parameter_supported: true
14821
14823
  })
14822
14824
  );
14823
- });
14825
+ };
14826
+ app.get("/.well-known/oauth-authorization-server", authorizationServerMetadata);
14827
+ app.get("/.well-known/oauth-authorization-server/*", authorizationServerMetadata);
14824
14828
  app.get("/.well-known/oauth-protected-resource/*", (c) => {
14825
14829
  requireMcpOAuthEnabled(deps);
14826
14830
  const pathname = new URL(c.req.url).pathname.replace(
@@ -15242,7 +15246,7 @@ function mcpOAuthConsentToolIdentities(catalog) {
15242
15246
  return catalog.entries.map((entry2) => entry2.identity);
15243
15247
  }
15244
15248
  function isMcpOAuthPublicProtocolPath(pathname) {
15245
- return pathname === "/.well-known/oauth-authorization-server" || pathname.startsWith("/.well-known/oauth-protected-resource/") || pathname === "/oauth/register" || pathname === "/oauth/authorize" || pathname === "/oauth/token";
15249
+ return pathname === "/.well-known/oauth-authorization-server" || pathname.startsWith("/.well-known/oauth-authorization-server/") || pathname.startsWith("/.well-known/oauth-protected-resource/") || pathname === "/oauth/register" || pathname === "/oauth/authorize" || pathname === "/oauth/token";
15246
15250
  }
15247
15251
  function mcpOAuthAuthenticateHeader(deps, pathname) {
15248
15252
  return `Bearer resource_metadata="${mcpOAuthIssuer(deps)}/.well-known/oauth-protected-resource${pathname}", scope="${MCP_OAUTH_SCOPE}"`;
@@ -15380,8 +15384,8 @@ function boundedState(value) {
15380
15384
  function pkceChallenge(verifier) {
15381
15385
  return createHash4("sha256").update(verifier, "ascii").digest("base64url");
15382
15386
  }
15383
- function opaque(prefix) {
15384
- return `${prefix}${randomBytes5(32).toString("base64url")}`;
15387
+ function opaque(prefix2) {
15388
+ return `${prefix2}${randomBytes5(32).toString("base64url")}`;
15385
15389
  }
15386
15390
  function tokenHash(value) {
15387
15391
  return createHash4("sha256").update(value, "utf8").digest("hex");
@@ -21617,21 +21621,21 @@ function projectScheduledTaskUtf8(value, maxBytes) {
21617
21621
  return { value, originalBytes, deliveredBytes: originalBytes, truncated: false };
21618
21622
  }
21619
21623
  let marker = "";
21620
- let prefix = "";
21624
+ let prefix2 = "";
21621
21625
  let omittedBytes = originalBytes;
21622
21626
  for (let attempt = 0; attempt < 4; attempt += 1) {
21623
21627
  marker = `\u2026[${omittedBytes} UTF-8 bytes omitted]`;
21624
21628
  if (Buffer.byteLength(marker, "utf8") > byteLimit) {
21625
21629
  marker = utf8Prefix2(marker, byteLimit);
21626
- prefix = "";
21630
+ prefix2 = "";
21627
21631
  break;
21628
21632
  }
21629
- prefix = utf8Prefix2(value, byteLimit - Buffer.byteLength(marker, "utf8"));
21630
- const nextOmitted = originalBytes - Buffer.byteLength(prefix, "utf8");
21633
+ prefix2 = utf8Prefix2(value, byteLimit - Buffer.byteLength(marker, "utf8"));
21634
+ const nextOmitted = originalBytes - Buffer.byteLength(prefix2, "utf8");
21631
21635
  if (nextOmitted === omittedBytes) break;
21632
21636
  omittedBytes = nextOmitted;
21633
21637
  }
21634
- const projected = `${prefix}${marker}`;
21638
+ const projected = `${prefix2}${marker}`;
21635
21639
  return {
21636
21640
  value: projected,
21637
21641
  originalBytes,
@@ -25078,8 +25082,8 @@ function sniffSlackReactionImageMime(bytes) {
25078
25082
  return null;
25079
25083
  }
25080
25084
  function hasMarkupPrefix(bytes) {
25081
- const prefix = new TextDecoder("utf-8", { fatal: false }).decode(bytes.subarray(0, Math.min(bytes.byteLength, 256))).replace(/^\uFEFF/u, "").trimStart().toLowerCase();
25082
- return prefix.startsWith("<svg") || prefix.startsWith("<html") || prefix.startsWith("<!doctype") || prefix.startsWith("<?xml");
25085
+ const prefix2 = new TextDecoder("utf-8", { fatal: false }).decode(bytes.subarray(0, Math.min(bytes.byteLength, 256))).replace(/^\uFEFF/u, "").trimStart().toLowerCase();
25086
+ return prefix2.startsWith("<svg") || prefix2.startsWith("<html") || prefix2.startsWith("<!doctype") || prefix2.startsWith("<?xml");
25083
25087
  }
25084
25088
  function isCompletePng(bytes) {
25085
25089
  const signature = [137, 80, 78, 71, 13, 10, 26, 10];
@@ -33429,6 +33433,7 @@ function registerGoalTools(server, deps, grant, sessionId, json2) {
33429
33433
  sessionId,
33430
33434
  {
33431
33435
  status: "active",
33436
+ beforeResume: (tx, session, causalTurn) => assertGoalResumeAllowed({ ...deps, db: tx }, session, causalTurn),
33432
33437
  event: { type: "goal.resumed", actor: "agent" }
33433
33438
  }
33434
33439
  );
@@ -38564,14 +38569,9 @@ var ACTION_CATALOG = [
38564
38569
  "method": "GET",
38565
38570
  "path": "/v1/organizations/:accountId/insights/calls",
38566
38571
  "request": [],
38567
- "response": []
38568
- },
38569
- {
38570
- "id": "GET /v1/organizations/:accountId/insights/usage",
38571
- "method": "GET",
38572
- "path": "/v1/organizations/:accountId/insights/usage",
38573
- "request": [],
38574
- "response": []
38572
+ "response": [
38573
+ "InsightsCallsResponse"
38574
+ ]
38575
38575
  },
38576
38576
  {
38577
38577
  "id": "GET /v1/organizations/:organizationId/codex/accounts",
@@ -38724,14 +38724,9 @@ var ACTION_CATALOG = [
38724
38724
  "method": "GET",
38725
38725
  "path": "/v1/workspaces/:workspaceId/insights/calls",
38726
38726
  "request": [],
38727
- "response": []
38728
- },
38729
- {
38730
- "id": "GET /v1/workspaces/:workspaceId/insights/usage",
38731
- "method": "GET",
38732
- "path": "/v1/workspaces/:workspaceId/insights/usage",
38733
- "request": [],
38734
- "response": []
38727
+ "response": [
38728
+ "InsightsCallsResponse"
38729
+ ]
38735
38730
  },
38736
38731
  {
38737
38732
  "id": "GET /v1/workspaces/:workspaceId/instruction-policies/:revisionId",
@@ -39292,6 +39287,15 @@ var ACTION_CATALOG = [
39292
39287
  "GetOrganizationCredentialProviderResponse"
39293
39288
  ]
39294
39289
  },
39290
+ {
39291
+ "id": "getOrganizationInsightsUsage",
39292
+ "method": "GET",
39293
+ "path": "/v1/organizations/:accountId/insights/usage",
39294
+ "request": [],
39295
+ "response": [
39296
+ "InsightsUsageResponse"
39297
+ ]
39298
+ },
39295
39299
  {
39296
39300
  "id": "getOrganizationIntegrationCatalog",
39297
39301
  "method": "GET",
@@ -39747,6 +39751,15 @@ var ACTION_CATALOG = [
39747
39751
  "WorkspaceInsightsResponse"
39748
39752
  ]
39749
39753
  },
39754
+ {
39755
+ "id": "getWorkspaceInsightsUsage",
39756
+ "method": "GET",
39757
+ "path": "/v1/workspaces/:workspaceId/insights/usage",
39758
+ "request": [],
39759
+ "response": [
39760
+ "InsightsUsageResponse"
39761
+ ]
39762
+ },
39750
39763
  {
39751
39764
  "id": "getWorkspaceLearningHistory",
39752
39765
  "method": "GET",
@@ -42907,6 +42920,17 @@ var ACTION_CATALOG = [
42907
42920
  "PrReviewAppRegistration"
42908
42921
  ]
42909
42922
  },
42923
+ {
42924
+ "id": "updateArtifactPin",
42925
+ "method": "PUT",
42926
+ "path": "/v1/workspaces/:workspaceId/artifact-catalog/:kind/:artifactId/pin",
42927
+ "request": [
42928
+ "ArtifactCatalogKind"
42929
+ ],
42930
+ "response": [
42931
+ "ArtifactPinResponse"
42932
+ ]
42933
+ },
42910
42934
  {
42911
42935
  "id": "updateBrowserIdentity",
42912
42936
  "method": "PATCH",
@@ -73484,13 +73508,13 @@ function registerCatalogAssetRoutes(app, deps) {
73484
73508
  });
73485
73509
  }
73486
73510
  function catalogAssetKeyFromPath(pathname) {
73487
- const prefix = "/v1/";
73488
- if (!pathname.startsWith(prefix)) {
73511
+ const prefix2 = "/v1/";
73512
+ if (!pathname.startsWith(prefix2)) {
73489
73513
  return null;
73490
73514
  }
73491
73515
  let key;
73492
73516
  try {
73493
- key = decodeURIComponent(pathname.slice(prefix.length));
73517
+ key = decodeURIComponent(pathname.slice(prefix2.length));
73494
73518
  } catch {
73495
73519
  return null;
73496
73520
  }
@@ -82430,8 +82454,8 @@ function registerVariableSetRoutes(app, deps) {
82430
82454
  "/v1/workspaces/:workspaceId/variable-sets",
82431
82455
  "/v1/workspaces/:workspaceId/environments"
82432
82456
  ];
82433
- for (const prefix of prefixes) {
82434
- app.get(`${prefix}`, async (c) => {
82457
+ for (const prefix2 of prefixes) {
82458
+ app.get(`${prefix2}`, async (c) => {
82435
82459
  const workspaceId = c.req.param("workspaceId");
82436
82460
  const grant = await requireAccessGrant20(c, deps, workspaceId);
82437
82461
  requirePermission4(grant, "variable-sets:list");
@@ -82444,14 +82468,14 @@ function registerVariableSetRoutes(app, deps) {
82444
82468
  })
82445
82469
  );
82446
82470
  });
82447
- app.post(`${prefix}`, async (c) => {
82471
+ app.post(`${prefix2}`, async (c) => {
82448
82472
  const workspaceId = c.req.param("workspaceId");
82449
82473
  const authorization = await requireAccessGrantAuthorization15(c, deps, workspaceId);
82450
82474
  const grant = authorization.grant;
82451
82475
  requirePermission4(grant, "variable-sets:write");
82452
82476
  const key = requireVariableSetEncryption2(settings);
82453
82477
  const payload = await parseRequestJson(c, CreateVariableSetRequest);
82454
- if (prefix.endsWith("/environments") && payload.scope !== "workspace") {
82478
+ if (prefix2.endsWith("/environments") && payload.scope !== "workspace") {
82455
82479
  throw new HTTPException61(422, {
82456
82480
  message: "the legacy environments route only creates workspace-scoped variable sets"
82457
82481
  });
@@ -82515,8 +82539,8 @@ function registerVariableSetRoutes(app, deps) {
82515
82539
  });
82516
82540
  return c.json(created, 201);
82517
82541
  });
82518
- if (prefix.endsWith("/variable-sets")) {
82519
- app.post(`${prefix}/resolve-attachments`, async (c) => {
82542
+ if (prefix2.endsWith("/variable-sets")) {
82543
+ app.post(`${prefix2}/resolve-attachments`, async (c) => {
82520
82544
  const workspaceId = c.req.param("workspaceId");
82521
82545
  const grant = await requireAccessGrant20(c, deps, workspaceId);
82522
82546
  requirePermission4(grant, "variable-sets:attach");
@@ -82534,15 +82558,15 @@ function registerVariableSetRoutes(app, deps) {
82534
82558
  return c.json(ResolveVariableSetAttachmentsResponse.parse({ variableSets }));
82535
82559
  });
82536
82560
  }
82537
- app.get(`${prefix}/:variableSetId`, async (c) => {
82561
+ app.get(`${prefix2}/:variableSetId`, async (c) => {
82538
82562
  const workspaceId = c.req.param("workspaceId");
82539
82563
  const grant = await requireAccessGrant20(c, deps, workspaceId);
82540
82564
  requirePermission4(grant, "variable-sets:read");
82541
82565
  requirePermission4(grant, "secrets:list");
82542
82566
  return c.json(await requireVariableSetForApi(db, grant, c.req.param("variableSetId")));
82543
82567
  });
82544
- if (prefix.endsWith("/variable-sets")) {
82545
- app.get(`${prefix}/:variableSetId/variables/:name`, async (c) => {
82568
+ if (prefix2.endsWith("/variable-sets")) {
82569
+ app.get(`${prefix2}/:variableSetId/variables/:name`, async (c) => {
82546
82570
  const workspaceId = c.req.param("workspaceId");
82547
82571
  const grant = await requireAccessGrant20(c, deps, workspaceId);
82548
82572
  requirePermission4(grant, "variable-sets:read");
@@ -82566,7 +82590,7 @@ function registerVariableSetRoutes(app, deps) {
82566
82590
  return c.json(secret);
82567
82591
  });
82568
82592
  }
82569
- app.patch(`${prefix}/:variableSetId`, async (c) => {
82593
+ app.patch(`${prefix2}/:variableSetId`, async (c) => {
82570
82594
  const workspaceId = c.req.param("workspaceId");
82571
82595
  const authorization = await requireAccessGrantAuthorization15(c, deps, workspaceId);
82572
82596
  const grant = authorization.grant;
@@ -82614,7 +82638,7 @@ function registerVariableSetRoutes(app, deps) {
82614
82638
  });
82615
82639
  return c.json(updated);
82616
82640
  });
82617
- app.delete(`${prefix}/:variableSetId`, async (c) => {
82641
+ app.delete(`${prefix2}/:variableSetId`, async (c) => {
82618
82642
  const workspaceId = c.req.param("workspaceId");
82619
82643
  const authorization = await requireAccessGrantAuthorization15(c, deps, workspaceId);
82620
82644
  const grant = authorization.grant;
@@ -82651,7 +82675,7 @@ function registerVariableSetRoutes(app, deps) {
82651
82675
  });
82652
82676
  return c.json({ ok: true });
82653
82677
  });
82654
- app.put(`${prefix}/:variableSetId/variables/:name`, async (c) => {
82678
+ app.put(`${prefix2}/:variableSetId/variables/:name`, async (c) => {
82655
82679
  const workspaceId = c.req.param("workspaceId");
82656
82680
  const authorization = await requireAccessGrantAuthorization15(c, deps, workspaceId);
82657
82681
  const grant = authorization.grant;
@@ -82690,7 +82714,7 @@ function registerVariableSetRoutes(app, deps) {
82690
82714
  });
82691
82715
  return c.json(metadata);
82692
82716
  });
82693
- app.delete(`${prefix}/:variableSetId/variables/:name`, async (c) => {
82717
+ app.delete(`${prefix2}/:variableSetId/variables/:name`, async (c) => {
82694
82718
  const workspaceId = c.req.param("workspaceId");
82695
82719
  const authorization = await requireAccessGrantAuthorization15(c, deps, workspaceId);
82696
82720
  const grant = authorization.grant;
@@ -83006,10 +83030,43 @@ import {
83006
83030
  OrganizationUsageWorkspacePageQuery
83007
83031
  } from "@opengeni/contracts";
83008
83032
  import { OrganizationModelUsageQuery } from "@opengeni/contracts/organization-model-usage";
83009
- import { configuredEntitlements } from "@opengeni/config";
83033
+ import { configuredEntitlements, promotionalCreditScope } from "@opengeni/config";
83034
+
83035
+ // src/credit-promotion-snapshot.ts
83036
+ import { PromotionalCreditScope } from "@opengeni/contracts";
83037
+ var prefix = "opengeni_credit_scope_";
83038
+ var countKey = `${prefix}v1`;
83039
+ function creditScopeMetadata(scope) {
83040
+ if (!scope) return {};
83041
+ const encoded = JSON.stringify(PromotionalCreditScope.parse(scope));
83042
+ const chunks = encoded.match(/[\s\S]{1,400}/g);
83043
+ if (chunks.length > 24)
83044
+ throw new Error("Promotional credit policy exceeds checkout metadata limits");
83045
+ return Object.fromEntries([
83046
+ [countKey, String(chunks.length)],
83047
+ ...chunks.map((chunk, index) => [`${prefix}${index}`, chunk])
83048
+ ]);
83049
+ }
83050
+ function creditScopeFromMetadata(metadata) {
83051
+ if (!metadata || !Object.keys(metadata).some((key) => key.startsWith(prefix))) return void 0;
83052
+ const count = Number(metadata[countKey]);
83053
+ if (!Number.isInteger(count) || count < 1 || count > 24) {
83054
+ throw new Error("Invalid promotional credit snapshot");
83055
+ }
83056
+ let encoded = "";
83057
+ for (let index = 0; index < count; index++) {
83058
+ const chunk = metadata[`${prefix}${index}`];
83059
+ if (!chunk) throw new Error("Incomplete promotional credit snapshot");
83060
+ encoded += chunk;
83061
+ }
83062
+ return PromotionalCreditScope.parse(JSON.parse(encoded));
83063
+ }
83064
+
83065
+ // src/routes/billing.ts
83010
83066
  import {
83011
83067
  applyCreditLedgerEntry,
83012
83068
  getBillingBalance,
83069
+ readCreditPromotionPolicy,
83013
83070
  getBillingCustomer,
83014
83071
  getCreditLedgerEntry,
83015
83072
  hasCreditLedgerEntry,
@@ -83019,6 +83076,7 @@ import {
83019
83076
  getOrganizationUsageSummary,
83020
83077
  getOrganizationUsageWorkspacePage,
83021
83078
  withSessionRlsActorContext as withSessionRlsActorContext8,
83079
+ withRlsContext as withRlsContext2,
83022
83080
  getManagedAccount as getManagedAccount2,
83023
83081
  markStripeWebhookProcessed,
83024
83082
  recordStripeWebhookEvent,
@@ -83124,6 +83182,12 @@ function registerBillingRoutes(app, deps) {
83124
83182
  const accountId = requireSelectedAccount(context, body3.accountId, "billing:manage");
83125
83183
  const stripe = stripeClient(deps);
83126
83184
  const promotion = body3.promotionCode ? await resolveCheckoutPromotionCode(stripe, body3.promotionCode) : null;
83185
+ const promotionalScope = promotion ? promotionalCreditScope(
83186
+ {
83187
+ creditPromotionPolicy: await readCreditPromotionPolicy(deps.db) ?? deps.settings.creditPromotionPolicy
83188
+ },
83189
+ promotion.couponId
83190
+ ) : void 0;
83127
83191
  const amountCents = body3.amountUsd !== void 0 ? usdToCents(body3.amountUsd) : promotion?.amountOffCents ?? null;
83128
83192
  if (amountCents === null) {
83129
83193
  throw new HTTPException64(422, {
@@ -83135,6 +83199,11 @@ function registerBillingRoutes(app, deps) {
83135
83199
  message: "Credits must be between $5 and $10,000."
83136
83200
  });
83137
83201
  }
83202
+ if (promotionalScope && (!promotion?.amountOffCents || amountCents !== promotion.amountOffCents)) {
83203
+ throw new HTTPException64(422, {
83204
+ message: "Redeem this offer for its exact credit amount. Buy additional credits separately."
83205
+ });
83206
+ }
83138
83207
  const amountMicros = centsToMicros(amountCents);
83139
83208
  const customerId = await getOrCreateStripeCustomer(deps, stripe, context, accountId);
83140
83209
  const idempotencyKey = `checkout:${accountId}:${amountMicros}:${crypto.randomUUID()}`;
@@ -83152,8 +83221,10 @@ function registerBillingRoutes(app, deps) {
83152
83221
  successUrl: body3.successUrl,
83153
83222
  cancelUrl: body3.cancelUrl,
83154
83223
  idempotencyKey,
83224
+ promotionalScope,
83155
83225
  ...promotion ? {
83156
83226
  promotionCodeId: promotion.id,
83227
+ couponId: promotion.couponId,
83157
83228
  fullyDiscounted: promotion.percentOff === 100 || (promotion.amountOffCents ?? 0) >= amountCents
83158
83229
  } : {}
83159
83230
  }),
@@ -83172,7 +83243,8 @@ function registerBillingRoutes(app, deps) {
83172
83243
  CreateCheckoutResponse.parse({
83173
83244
  checkoutSessionId: session.id,
83174
83245
  url: session.url,
83175
- amountUsd: amountCents / 100
83246
+ amountUsd: amountCents / 100,
83247
+ promotionalScope
83176
83248
  })
83177
83249
  );
83178
83250
  });
@@ -83216,6 +83288,7 @@ function registerBillingRoutes(app, deps) {
83216
83288
  state: entry2 ? "granted" : "pending",
83217
83289
  amountMicros: entry2?.amountMicros ?? credit.amountMicros,
83218
83290
  currency: "usd",
83291
+ promotionalScope: creditScopeFromMetadata(session.metadata),
83219
83292
  free: entry2 ? entry2.sourceType === "stripe_checkout_coupon" : isFreeCouponCheckout(session)
83220
83293
  },
83221
83294
  balance: entry2 ? await getBillingBalance(deps.db, accountId) : null
@@ -83315,7 +83388,7 @@ function stripeCheckoutSessionCreateParams(input) {
83315
83388
  return {
83316
83389
  mode: "payment",
83317
83390
  // Stripe takes either a code field on its page or one discount up front.
83318
- ...input.promotionCodeId ? { discounts: [{ promotion_code: input.promotionCodeId }] } : { allow_promotion_codes: true },
83391
+ ...input.promotionCodeId ? { discounts: [{ promotion_code: input.promotionCodeId }] } : { allow_promotion_codes: false },
83319
83392
  customer: input.customerId,
83320
83393
  customer_update: {
83321
83394
  address: "auto",
@@ -83344,6 +83417,8 @@ function stripeCheckoutSessionCreateParams(input) {
83344
83417
  }
83345
83418
  ],
83346
83419
  metadata: {
83420
+ ...creditScopeMetadata(input.promotionalScope),
83421
+ ...input.couponId ? { opengeni_credit_offer_id: input.couponId } : {},
83347
83422
  opengeni_account_id: input.accountId,
83348
83423
  opengeni_credit_amount_usd: (input.amountCents / 100).toFixed(2),
83349
83424
  opengeni_credit_micros: String(input.amountMicros),
@@ -83485,6 +83560,10 @@ async function grantCheckoutSessionCredits(deps, session, source) {
83485
83560
  }
83486
83561
  const credit = decision.credit;
83487
83562
  const freeCouponCheckout = isFreeCouponCheckout(session);
83563
+ const promotionalScope = creditScopeFromMetadata(session.metadata);
83564
+ if (promotionalScope && !freeCouponCheckout) {
83565
+ throw new Error("Scoped promotional credits require a fully discounted checkout");
83566
+ }
83488
83567
  if (!await getManagedAccount2(deps.db, credit.accountId)) {
83489
83568
  console.info(
83490
83569
  "[api] stripe webhook ignored a checkout session for an account not in this deployment",
@@ -83511,10 +83590,13 @@ async function grantCheckoutSessionCredits(deps, session, source) {
83511
83590
  accountId: credit.accountId,
83512
83591
  type: freeCouponCheckout ? "grant" : "credit_topup",
83513
83592
  amountMicros: credit.amountMicros,
83593
+ eligibleModelIds: promotionalScope?.eligibleModelIds,
83514
83594
  sourceType: freeCouponCheckout ? "stripe_checkout_coupon" : "stripe_checkout_session",
83515
83595
  sourceId: session.id,
83516
83596
  idempotencyKey: credit.idempotencyKey,
83517
83597
  metadata: {
83598
+ ...promotionalScope ? { creditOfferLabel: promotionalScope.label } : {},
83599
+ creditOfferId: session.metadata?.opengeni_credit_offer_id ?? null,
83518
83600
  stripeEventId: source.stripeEventId,
83519
83601
  stripePaymentIntentId: typeof session.payment_intent === "string" ? session.payment_intent : session.payment_intent?.id ?? null,
83520
83602
  stripePackageId: credit.packageId,
@@ -83540,7 +83622,12 @@ async function resolveCheckoutPromotionCode(stripe, code) {
83540
83622
  throw new HTTPException64(422, { message: "That code isn't valid or has expired." });
83541
83623
  }
83542
83624
  const amountOffCents = coupon.amount_off && coupon.currency === "usd" ? coupon.amount_off : coupon.currency_options?.usd?.amount_off ?? null;
83543
- return { id: promotionCode.id, amountOffCents, percentOff: coupon.percent_off ?? null };
83625
+ return {
83626
+ id: promotionCode.id,
83627
+ couponId: coupon.id,
83628
+ amountOffCents,
83629
+ percentOff: coupon.percent_off ?? null
83630
+ };
83544
83631
  }
83545
83632
  async function mirrorPaymentIntentCustomer(deps, event) {
83546
83633
  const intent = event.data.object;
@@ -83622,18 +83709,26 @@ async function releaseDisputedCredits(deps, stripe, event) {
83622
83709
  return;
83623
83710
  }
83624
83711
  const holdIdempotencyKey = `stripe:dispute_hold:${dispute.id}`;
83625
- if (!await hasCreditLedgerEntry(deps.db, accountId, holdIdempotencyKey)) {
83626
- return;
83627
- }
83628
83712
  const debitMicros = await creditAdjustmentMicros(deps, metadata, dispute.amount);
83629
- await applyCreditLedgerEntry(deps.db, {
83630
- accountId,
83631
- type: "credit_dispute_release",
83632
- amountMicros: debitMicros,
83633
- sourceType: "stripe_dispute",
83634
- sourceId: dispute.id,
83635
- idempotencyKey: `stripe:dispute_release:${dispute.id}`,
83636
- metadata: { stripeDisputeId: dispute.id, stripeEventType: event.type }
83713
+ await withRlsContext2(deps.db, { accountId }, async (tx) => {
83714
+ await applyCreditLedgerEntry(tx, {
83715
+ accountId,
83716
+ type: "credit_dispute_hold",
83717
+ amountMicros: -debitMicros,
83718
+ sourceType: "stripe_dispute",
83719
+ sourceId: dispute.id,
83720
+ idempotencyKey: holdIdempotencyKey,
83721
+ metadata: { stripeDisputeId: dispute.id, stripeEventType: event.type }
83722
+ });
83723
+ await applyCreditLedgerEntry(tx, {
83724
+ accountId,
83725
+ type: "credit_dispute_release",
83726
+ amountMicros: debitMicros,
83727
+ sourceType: "stripe_dispute",
83728
+ sourceId: dispute.id,
83729
+ idempotencyKey: `stripe:dispute_release:${dispute.id}`,
83730
+ metadata: { stripeDisputeId: dispute.id, stripeEventType: event.type }
83731
+ });
83637
83732
  });
83638
83733
  }
83639
83734
  async function creditAdjustmentMicros(deps, metadata, amountCents) {
@@ -91687,9 +91782,9 @@ async function requireGitHubManageGrant(c, deps, workspaceId, expectedState) {
91687
91782
  }
91688
91783
  }
91689
91784
  function allCookieValues(c, name) {
91690
- const prefix = `${name}=`;
91691
- return (c.req.header("cookie") ?? "").split(";").map((part) => part.trim()).filter((part) => part.startsWith(prefix)).map((part) => {
91692
- const raw = part.slice(prefix.length);
91785
+ const prefix2 = `${name}=`;
91786
+ return (c.req.header("cookie") ?? "").split(";").map((part) => part.trim()).filter((part) => part.startsWith(prefix2)).map((part) => {
91787
+ const raw = part.slice(prefix2.length);
91693
91788
  try {
91694
91789
  return decodeURIComponent(raw);
91695
91790
  } catch {
@@ -96457,12 +96552,12 @@ function requireStateCookie(c, state) {
96457
96552
  }
96458
96553
  }
96459
96554
  function allCookieValues2(c, name) {
96460
- const prefix = `${name}=`;
96461
- return (c.req.header("cookie") ?? "").split(";").map((part) => part.trim()).filter((part) => part.startsWith(prefix)).map((part) => {
96555
+ const prefix2 = `${name}=`;
96556
+ return (c.req.header("cookie") ?? "").split(";").map((part) => part.trim()).filter((part) => part.startsWith(prefix2)).map((part) => {
96462
96557
  try {
96463
- return decodeURIComponent(part.slice(prefix.length));
96558
+ return decodeURIComponent(part.slice(prefix2.length));
96464
96559
  } catch {
96465
- return part.slice(prefix.length);
96560
+ return part.slice(prefix2.length);
96466
96561
  }
96467
96562
  });
96468
96563
  }
@@ -99677,6 +99772,7 @@ function registerScheduledTaskRoutes(app, deps) {
99677
99772
 
99678
99773
  // src/routes/sessions.ts
99679
99774
  import { getRetainedProviderCommand } from "@opengeni/db/retained-provider-commands";
99775
+ import { assertGoalResumeAllowed as assertGoalResumeAllowed2, GoalResumeBlockedError } from "@opengeni/core";
99680
99776
  import { UnsupportedLatencyModeError } from "@opengeni/config";
99681
99777
  import { searchSessionMessagesForSubject, SessionMessageSearchCursorError } from "@opengeni/db";
99682
99778
  import { listSessionEventSlices } from "@opengeni/db/session-event-slices";
@@ -100083,9 +100179,9 @@ function openGeniRealtimeInstructions(additional) {
100083
100179
  const trimmed = additional?.trim();
100084
100180
  if (!trimmed) return OPENGENI_REALTIME_BASE_INSTRUCTIONS;
100085
100181
  const heading = "\n\n## Additional realtime guidance\nFollow the guidance below for this conversation unless it conflicts with the operating, delegation, safety, permission, or context-handling rules above.\n";
100086
- const prefix = `${OPENGENI_REALTIME_BASE_INSTRUCTIONS}${heading}`;
100087
- const remaining = REALTIME_INSTRUCTIONS_MAX_BYTES - Buffer.byteLength(prefix, "utf8");
100088
- return `${prefix}${takeUtf8Head(trimmed, Math.max(0, remaining))}`;
100182
+ const prefix2 = `${OPENGENI_REALTIME_BASE_INSTRUCTIONS}${heading}`;
100183
+ const remaining = REALTIME_INSTRUCTIONS_MAX_BYTES - Buffer.byteLength(prefix2, "utf8");
100184
+ return `${prefix2}${takeUtf8Head(trimmed, Math.max(0, remaining))}`;
100089
100185
  }
100090
100186
  function takeUtf8Head(value, maximumBytes) {
100091
100187
  if (Buffer.byteLength(value, "utf8") <= maximumBytes) return value;
@@ -103151,6 +103247,14 @@ function registerSessionRoutes(app, deps) {
103151
103247
  sessionId,
103152
103248
  {
103153
103249
  status: "active",
103250
+ beforeResume: (tx, session, causalTurn) => assertGoalResumeAllowed2({ ...deps, db: tx }, session, causalTurn).catch(
103251
+ (error) => {
103252
+ if (error instanceof GoalResumeBlockedError) {
103253
+ throw new HTTPException88(422, { message: error.message, cause: error });
103254
+ }
103255
+ throw error;
103256
+ }
103257
+ ),
103154
103258
  event: { type: "goal.resumed", actor: "api" }
103155
103259
  }
103156
103260
  );
@@ -105149,7 +105253,7 @@ function sessionTenancyHttpError(error) {
105149
105253
  if (error instanceof SessionTenancyNotActivatedError) {
105150
105254
  return new ApiHttpError(409, {
105151
105255
  code: "conflict",
105152
- message: "Session tenancy is not activated for this organization.",
105256
+ message: "Only-me chats are not enabled for this organization.",
105153
105257
  retryable: false,
105154
105258
  details: { reason: "not_activated" }
105155
105259
  });
@@ -106287,6 +106391,8 @@ import {
106287
106391
  import { loadWorkspaceCodexModelAvailability } from "@opengeni/core";
106288
106392
  import {
106289
106393
  allWorkspacePermissions,
106394
+ getBillingBalance as getBillingBalance2,
106395
+ spendableCreditMicros,
106290
106396
  createWorkspace,
106291
106397
  ensureWorkspaceByExternalIdentity,
106292
106398
  findWorkspaceByExternalIdentity as findWorkspaceByExternalIdentity2,
@@ -106881,25 +106987,31 @@ function registerWorkspaceRoutes(app, deps) {
106881
106987
  organizationOpenRouterCustomModels: organizationProviders.openrouter.models
106882
106988
  });
106883
106989
  const workspaceSettings = workspace?.settings ?? {};
106990
+ const creditBalance = deps.settings.billingMode === "stripe" ? await getBillingBalance2(deps.db, grant.accountId) : void 0;
106884
106991
  const defaultSelection = await resolveDefaultSessionModelForSelections(deps.db, {
106885
106992
  settings: workspaceCatalogSettings,
106886
106993
  accountId: grant.accountId,
106887
106994
  workspaceSettings,
106888
106995
  selections
106889
106996
  });
106997
+ const catalog = projectWorkspaceModelCatalog(selections, {
106998
+ defaultSelection,
106999
+ creditsSelection: creditsDefaultSessionModel({
107000
+ settings: workspaceCatalogSettings,
107001
+ selections,
107002
+ workspaceSettings
107003
+ })
107004
+ });
107005
+ if (creditBalance) {
107006
+ for (const model of catalog.models) {
107007
+ if (model.cost !== "credits") continue;
107008
+ model.creditFunding = creditBalance.promotionalCredits?.some(
107009
+ (credit) => credit.remainingMicros > 0 && credit.eligibleModelIds.includes(model.id)
107010
+ ) ? "promotional" : spendableCreditMicros(creditBalance, model.id) > 0 ? "general" : "unavailable";
107011
+ }
107012
+ }
106890
107013
  c.header("cache-control", "private, no-store");
106891
- return c.json(
106892
- WorkspaceModelCatalogResponse2.parse(
106893
- projectWorkspaceModelCatalog(selections, {
106894
- defaultSelection,
106895
- creditsSelection: creditsDefaultSessionModel({
106896
- settings: workspaceCatalogSettings,
106897
- selections,
106898
- workspaceSettings
106899
- })
106900
- })
106901
- )
106902
- );
107014
+ return c.json(WorkspaceModelCatalogResponse2.parse(catalog));
106903
107015
  });
106904
107016
  app.get("/v1/workspaces/:workspaceId/gateway-custom-models", async (c) => {
106905
107017
  const workspaceId = c.req.param("workspaceId");
@@ -110062,6 +110174,8 @@ import {
110062
110174
  ArtifactCatalogKind as ArtifactCatalogKind2,
110063
110175
  ArtifactCatalogListQuery,
110064
110176
  ArtifactCatalogListResponse,
110177
+ ArtifactPinResponse,
110178
+ UpdateArtifactPinRequest,
110065
110179
  retainedArtifactReferenceFromFile as retainedArtifactReferenceFromFile3,
110066
110180
  retainedGeneratedImageReferenceFromFile as retainedGeneratedImageReferenceFromFile2
110067
110181
  } from "@opengeni/contracts";
@@ -110082,9 +110196,12 @@ import {
110082
110196
  getGeneratedImageArtifact as getGeneratedImageArtifact2,
110083
110197
  getSessionAuthorityProjection as getSessionAuthorityProjection3,
110084
110198
  listArtifactCatalogCandidates,
110199
+ nestedPostgresSqlState as nestedPostgresSqlState14,
110200
+ updateArtifactPin,
110085
110201
  withSessionRlsActorContext as withSessionRlsActorContext9
110086
110202
  } from "@opengeni/db";
110087
110203
  import { HTTPException as HTTPException102 } from "hono/http-exception";
110204
+ import { z as z53 } from "zod";
110088
110205
 
110089
110206
  // src/artifact-catalog-cursor.ts
110090
110207
  import { createCipheriv as createCipheriv2, createDecipheriv as createDecipheriv2, createHash as createHash29, randomBytes as randomBytes12 } from "crypto";
@@ -110098,7 +110215,8 @@ var Cursor = z52.object({
110098
110215
  after: z52.object({
110099
110216
  key: z52.string().max(4096),
110100
110217
  kind: ArtifactCatalogKind,
110101
- id: z52.string().min(1).max(128)
110218
+ id: z52.string().min(1).max(128),
110219
+ pinned: z52.boolean().optional()
110102
110220
  }).strict()
110103
110221
  }).strict();
110104
110222
  function artifactCatalogCursorCodec(secret, binding) {
@@ -110146,9 +110264,82 @@ var iso2 = (value) => new Date(value).toISOString();
110146
110264
  var position = (row) => ({
110147
110265
  key: row.sort_key,
110148
110266
  kind: row.kind,
110149
- id: row.id
110267
+ id: row.id,
110268
+ pinned: row.pinned ?? false
110150
110269
  });
110151
110270
  function registerArtifactCatalogRoutes(app, deps) {
110271
+ app.put("/v1/workspaces/:workspaceId/artifact-catalog/:kind/:artifactId/pin", async (context) => {
110272
+ const workspaceId = context.req.param("workspaceId");
110273
+ const authorization = await requireAccessGrantAuthorization36(
110274
+ context,
110275
+ deps,
110276
+ workspaceId,
110277
+ "artifacts:publish"
110278
+ );
110279
+ const grant = authorization.grant;
110280
+ if (!hasPermission27(grant.permissions, "artifacts:publish"))
110281
+ throw new HTTPException102(403, { message: "Artifact publish access required" });
110282
+ const kind = ArtifactCatalogKind2.safeParse(context.req.param("kind"));
110283
+ const body3 = UpdateArtifactPinRequest.safeParse(await context.req.json().catch(() => null));
110284
+ const requestedId = context.req.param("artifactId");
110285
+ if (!kind.success || !body3.success || !(editableKinds.has(kind.data) ? /^[0-9a-f]{32}$/.test(requestedId) : z53.string().uuid().safeParse(requestedId).success))
110286
+ throw new HTTPException102(422, { message: "Invalid artifact pin request" });
110287
+ const artifactId2 = editableKinds.has(kind.data) ? requestedId : requestedId.toLowerCase();
110288
+ const fileKind = kind.data === "file" || kind.data === "image";
110289
+ if (!hasPermission27(grant.permissions, fileKind ? "files:read" : "artifacts:read"))
110290
+ throw new HTTPException102(403, { message: "Artifact read access required" });
110291
+ const actor = fileKind ? await fileOwnerContextForAccess5(deps, authorization, "files:read") : { subjectId: grant.subjectId, privateFileOwnerSubjectId: null };
110292
+ context.header("cache-control", "private, no-store");
110293
+ return withSessionRlsActorContext9(actor, async () => {
110294
+ if (editableKinds.has(kind.data)) {
110295
+ if (!deps.editableArtifacts)
110296
+ throw new HTTPException102(503, { message: "Editable artifacts are unavailable" });
110297
+ try {
110298
+ const scope = editableArtifactScope2({ accountId: grant.accountId, workspaceId });
110299
+ const artifact = await deps.editableArtifacts.readArtifact({
110300
+ scope,
110301
+ actor: editableArtifactActorForGrant(grant, "0000000000000001"),
110302
+ artifactId: editableArtifactId3(artifactId2)
110303
+ });
110304
+ if (artifact.scope.accountId !== scope.accountId || artifact.scope.workspaceId !== scope.workspaceId || artifact.id !== artifactId2 || artifact.modality !== kind.data)
110305
+ throw new HTTPException102(404, { message: "Artifact not found" });
110306
+ } catch (error) {
110307
+ if (isInvisibleListCandidate(error))
110308
+ throw new HTTPException102(404, { message: "Artifact not found" });
110309
+ throw editableArtifactHttpError(error);
110310
+ }
110311
+ }
110312
+ if (fileKind) {
110313
+ const subjectId = await fileAuthoritySubjectIdForGrant(deps, grant);
110314
+ const [file] = await getFilesForSubject3(deps.db, {
110315
+ accountId: grant.accountId,
110316
+ workspaceId,
110317
+ subjectId,
110318
+ fileIds: [artifactId2]
110319
+ });
110320
+ if (!file || file.status !== "ready")
110321
+ throw new HTTPException102(404, { message: "Artifact not found" });
110322
+ }
110323
+ try {
110324
+ await updateArtifactPin(
110325
+ deps.db,
110326
+ { accountId: grant.accountId, workspaceId },
110327
+ {
110328
+ kind: kind.data,
110329
+ artifactId: artifactId2,
110330
+ pinned: body3.data.pinned
110331
+ }
110332
+ );
110333
+ } catch (error) {
110334
+ if (nestedPostgresSqlState14(error) === "42501")
110335
+ throw new HTTPException102(404, { message: "Artifact not found" });
110336
+ throw error;
110337
+ }
110338
+ return context.json(
110339
+ ArtifactPinResponse.parse({ kind: kind.data, artifactId: artifactId2, pinned: body3.data.pinned })
110340
+ );
110341
+ });
110342
+ });
110152
110343
  app.get("/v1/workspaces/:workspaceId/artifact-catalog", async (context) => {
110153
110344
  const workspaceId = context.req.param("workspaceId");
110154
110345
  const authorization = await requireAccessGrantAuthorization36(context, deps, workspaceId);
@@ -110282,7 +110473,8 @@ async function projectCandidate(deps, grant, row, fileSubject) {
110282
110473
  title: row.title,
110283
110474
  status: row.status,
110284
110475
  createdAt: iso2(row.created_at),
110285
- updatedAt: iso2(row.updated_at)
110476
+ updatedAt: iso2(row.updated_at),
110477
+ ...row.pinned !== void 0 ? { pinned: row.pinned } : {}
110286
110478
  };
110287
110479
  if (row.version_id) item.versionId = row.version_id;
110288
110480
  if (editableKinds.has(row.kind)) {
@@ -111870,12 +112062,12 @@ import {
111870
112062
  hasEditableArtifactSessionLink as hasEditableArtifactSessionLink2,
111871
112063
  hasWorkspaceArtifactSessionLink,
111872
112064
  transactionallyAuthorizeEditableArtifactActor,
111873
- withRlsContext as withRlsContext2
112065
+ withRlsContext as withRlsContext3
111874
112066
  } from "@opengeni/db";
111875
112067
  import { HTTPException as HTTPException106 } from "hono/http-exception";
111876
- import { z as z53 } from "zod";
111877
- var SessionId2 = z53.string().uuid();
111878
- var EditableArtifactId = z53.string().regex(/^(?!0{32}$)[0-9a-f]{32}$/u);
112068
+ import { z as z54 } from "zod";
112069
+ var SessionId2 = z54.string().uuid();
112070
+ var EditableArtifactId = z54.string().regex(/^(?!0{32}$)[0-9a-f]{32}$/u);
111879
112071
  function registerSessionArtifactAssociationRoutes(app, deps) {
111880
112072
  app.get(
111881
112073
  "/v1/workspaces/:workspaceId/sessions/:sessionId/artifact-associations/:artifactId",
@@ -111901,7 +112093,7 @@ function registerSessionArtifactAssociationRoutes(app, deps) {
111901
112093
  const linked = kind === "editable" ? await hasEditableArtifactSessionLink2(deps.db, scope, sessionId, artifactId2) : await hasWorkspaceArtifactSessionLink(deps.db, workspaceId, sessionId, artifactId2);
111902
112094
  if (!linked) throw new HTTPException106(404, { message: "Artifact association not found" });
111903
112095
  if (kind === "editable") {
111904
- const decision = await withRlsContext2(
112096
+ const decision = await withRlsContext3(
111905
112097
  deps.db,
111906
112098
  scope,
111907
112099
  (tx) => transactionallyAuthorizeEditableArtifactActor(tx, {
@@ -112099,7 +112291,7 @@ import {
112099
112291
  getCanonicalHumanIdentityProjection as getCanonicalHumanIdentityProjection3
112100
112292
  } from "@opengeni/db/canonical-human-identities";
112101
112293
  import { HTTPException as HTTPException110 } from "hono/http-exception";
112102
- import { z as z56 } from "zod";
112294
+ import { z as z57 } from "zod";
112103
112295
 
112104
112296
  // src/routes/managed-sign-in-methods.ts
112105
112297
  import {
@@ -112123,7 +112315,7 @@ import { getManagedAuthSessionSetSnapshot as getManagedAuthSessionSetSnapshot2 }
112123
112315
  import { getCanonicalHumanIdentityProjection as getCanonicalHumanIdentityProjection2 } from "@opengeni/db/canonical-human-identities";
112124
112316
  import { getCookie as getCookie2 } from "hono/cookie";
112125
112317
  import { HTTPException as HTTPException109 } from "hono/http-exception";
112126
- import { z as z55 } from "zod";
112318
+ import { z as z56 } from "zod";
112127
112319
 
112128
112320
  // src/routes/managed-auth-session-sets.ts
112129
112321
  import { assertManagedUserAdmission as assertManagedUserAdmission2, getManagedSession as getManagedSession3 } from "@opengeni/core";
@@ -112189,12 +112381,12 @@ import {
112189
112381
  import { ensureManagedAccessForUser as ensureManagedAccessForUser2, getSession as getSession10 } from "@opengeni/db";
112190
112382
  import { deleteCookie as deleteCookie3, getCookie, setCookie as setCookie3 } from "hono/cookie";
112191
112383
  import { HTTPException as HTTPException108 } from "hono/http-exception";
112192
- import { z as z54 } from "zod";
112193
- var ManagedAuthSocialStartReceipt = z54.object({
112194
- version: z54.literal(1),
112195
- requestDigest: z54.string().regex(/^[0-9a-f]{64}$/u),
112196
- url: z54.string().url().max(4096),
112197
- stateCookie: z54.string().min(1).max(4096)
112384
+ import { z as z55 } from "zod";
112385
+ var ManagedAuthSocialStartReceipt = z55.object({
112386
+ version: z55.literal(1),
112387
+ requestDigest: z55.string().regex(/^[0-9a-f]{64}$/u),
112388
+ url: z55.string().url().max(4096),
112389
+ stateCookie: z55.string().min(1).max(4096)
112198
112390
  }).strict();
112199
112391
  function registerManagedAuthSessionSetRoutes(app, deps) {
112200
112392
  const noStore = async (context, next) => {
@@ -113034,8 +113226,8 @@ function setTransactionCookie(context, deps, transactionId, transactionSecret) {
113034
113226
  }
113035
113227
  function requireTransactionSecret(context, transactionId) {
113036
113228
  const value = getCookie(context, MANAGED_AUTH_LOGIN_TRANSACTION_COOKIE);
113037
- const prefix = `${transactionId}.`;
113038
- const secret = value?.startsWith(prefix) ? value.slice(prefix.length) : null;
113229
+ const prefix2 = `${transactionId}.`;
113230
+ const secret = value?.startsWith(prefix2) ? value.slice(prefix2.length) : null;
113039
113231
  if (!secret || !/^[A-Za-z0-9_-]{43}$/.test(secret)) {
113040
113232
  throw managedAuthApiError(401, "invalid_transaction");
113041
113233
  }
@@ -113130,23 +113322,23 @@ function setCookieHeaders(headers) {
113130
113322
  }
113131
113323
 
113132
113324
  // src/routes/managed-sign-in-methods.ts
113133
- var ConnectState = z55.object({
113134
- opengeniSignInMethod: z55.object({
113135
- intentId: z55.string().uuid(),
113136
- provider: z55.enum(["google", "github"])
113325
+ var ConnectState = z56.object({
113326
+ opengeniSignInMethod: z56.object({
113327
+ intentId: z56.string().uuid(),
113328
+ provider: z56.enum(["google", "github"])
113137
113329
  }),
113138
- link: z55.object({ userId: z55.string().min(1), email: z55.string().email() }),
113139
- callbackURL: z55.string().url(),
113140
- errorURL: z55.string().url()
113330
+ link: z56.object({ userId: z56.string().min(1), email: z56.string().email() }),
113331
+ callbackURL: z56.string().url(),
113332
+ errorURL: z56.string().url()
113141
113333
  });
113142
- var ConnectIntent = z55.object({
113143
- authUserId: z55.string().min(1),
113144
- authSessionId: z55.string().min(1),
113145
- expectedIdentityId: z55.string().uuid(),
113146
- actorFence: z55.object({
113147
- authorityHash: z55.string().regex(/^[0-9a-f]{64}$/),
113148
- actorEpoch: z55.string().regex(/^[1-9][0-9]*$/),
113149
- requestId: z55.string().uuid()
113334
+ var ConnectIntent = z56.object({
113335
+ authUserId: z56.string().min(1),
113336
+ authSessionId: z56.string().min(1),
113337
+ expectedIdentityId: z56.string().uuid(),
113338
+ actorFence: z56.object({
113339
+ authorityHash: z56.string().regex(/^[0-9a-f]{64}$/),
113340
+ actorEpoch: z56.string().regex(/^[1-9][0-9]*$/),
113341
+ requestId: z56.string().uuid()
113150
113342
  }).optional()
113151
113343
  });
113152
113344
  async function rows(deps, query) {
@@ -113466,7 +113658,7 @@ async function handleManagedSignInConnectCallback(context, deps, provider) {
113466
113658
 
113467
113659
  // src/routes/canonical-human-identities.ts
113468
113660
  import { managedAuthSecretRequestDigest as managedAuthSecretRequestDigest3 } from "@opengeni/core/managed-auth-session-sets";
113469
- var BindingId = z56.string().uuid();
113661
+ var BindingId = z57.string().uuid();
113470
113662
  async function requestIdentity(context, deps) {
113471
113663
  return await requireCanonicalHumanRequestIdentity2(context, {
113472
113664
  db: deps.db,
@@ -113635,6 +113827,7 @@ function registerCanonicalHumanIdentityRoutes(app, deps) {
113635
113827
  }
113636
113828
 
113637
113829
  // src/routes/organization-memberships.ts
113830
+ import { signupCreditModelIds } from "@opengeni/config";
113638
113831
  import {
113639
113832
  lookupExternalIdentityForRequest,
113640
113833
  cancelExternalWorkspaceMemberGrantForRequest,
@@ -113702,7 +113895,7 @@ import {
113702
113895
  listOrganizationAdministrationMembers,
113703
113896
  listOrganizationInvitations,
113704
113897
  listSelfOrganizationInvitations,
113705
- nestedPostgresSqlState as nestedPostgresSqlState14,
113898
+ nestedPostgresSqlState as nestedPostgresSqlState15,
113706
113899
  prepareOrganizationUserSetupDelivery,
113707
113900
  revokeOrganizationInvitation,
113708
113901
  settleOrganizationUserSetupDelivery,
@@ -113716,11 +113909,11 @@ import {
113716
113909
  updateOrganizationRetentionPolicy
113717
113910
  } from "@opengeni/db";
113718
113911
  import { HTTPException as HTTPException111 } from "hono/http-exception";
113719
- import { z as z57 } from "zod";
113720
- var OrganizationId2 = z57.string().uuid();
113721
- var WorkspaceId = z57.string().uuid();
113722
- var MembershipId = z57.string().uuid();
113723
- var InvitationId = z57.string().uuid();
113912
+ import { z as z58 } from "zod";
113913
+ var OrganizationId2 = z58.string().uuid();
113914
+ var WorkspaceId = z58.string().uuid();
113915
+ var MembershipId = z58.string().uuid();
113916
+ var InvitationId = z58.string().uuid();
113724
113917
  async function requirePrivateSessionAdministrator(context, deps, organizationId2) {
113725
113918
  const agent = agentActingAsPerson(
113726
113919
  context,
@@ -113819,7 +114012,7 @@ function parseId(schema, value, label) {
113819
114012
  return parsed.data;
113820
114013
  }
113821
114014
  function rethrowMembershipError(error, resourceLimitMessage) {
113822
- const sqlState = nestedPostgresSqlState14(error);
114015
+ const sqlState = nestedPostgresSqlState15(error);
113823
114016
  if (sqlState === "54000" && resourceLimitMessage) {
113824
114017
  throw new HTTPException111(409, {
113825
114018
  message: resourceLimitMessage
@@ -113881,6 +114074,7 @@ function registerOrganizationMembershipRoutes(app, deps) {
113881
114074
  subjectId,
113882
114075
  subjectLabel: session.user.email || session.user.name,
113883
114076
  ...payload,
114077
+ trialCreditModelIds: signupCreditModelIds(deps.settings),
113884
114078
  trialCreditsEnabled: deps.settings.productAccessMode === "managed" && deps.settings.verifiedSignupTrialCreditsEnabled
113885
114079
  })
113886
114080
  ),
@@ -113924,7 +114118,7 @@ function registerOrganizationMembershipRoutes(app, deps) {
113924
114118
  })
113925
114119
  );
113926
114120
  } catch (error) {
113927
- if (nestedPostgresSqlState14(error) === "42501") {
114121
+ if (nestedPostgresSqlState15(error) === "42501") {
113928
114122
  throw new HTTPException111(403, {
113929
114123
  message: "organization membership is not active"
113930
114124
  });
@@ -114232,11 +114426,6 @@ function registerOrganizationMembershipRoutes(app, deps) {
114232
114426
  )
114233
114427
  );
114234
114428
  } catch (error) {
114235
- if (nestedPostgresSqlState14(error) === "55000") {
114236
- throw new HTTPException111(409, {
114237
- message: "private-session readiness is not activated for this organization"
114238
- });
114239
- }
114240
114429
  rethrowMembershipError(error);
114241
114430
  }
114242
114431
  });
@@ -114584,13 +114773,13 @@ import {
114584
114773
  SessionListCursorExpiredError as SessionListCursorExpiredError2
114585
114774
  } from "@opengeni/db";
114586
114775
  import { HTTPException as HTTPException112 } from "hono/http-exception";
114587
- import { z as z58 } from "zod";
114776
+ import { z as z59 } from "zod";
114588
114777
  var ORGANIZATION_SESSION_LIST_MAX_WORKSPACE_READS = 25;
114589
- var OrganizationId3 = z58.string().uuid();
114590
- var OrganizationSessionListCursorEnvelope = z58.object({
114591
- workspaceId: z58.string().uuid(),
114592
- cursor: z58.string().min(1).nullable(),
114593
- pinnedOffset: z58.number().int().nonnegative().max(1e4).optional()
114778
+ var OrganizationId3 = z59.string().uuid();
114779
+ var OrganizationSessionListCursorEnvelope = z59.object({
114780
+ workspaceId: z59.string().uuid(),
114781
+ cursor: z59.string().min(1).nullable(),
114782
+ pinnedOffset: z59.number().int().nonnegative().max(1e4).optional()
114594
114783
  }).strict();
114595
114784
  function encodeOrganizationSessionListCursor(cursor) {
114596
114785
  return Buffer.from(JSON.stringify(cursor)).toString("base64url");
@@ -114818,9 +115007,9 @@ import {
114818
115007
  startOrganizationRecoveryOperation
114819
115008
  } from "@opengeni/db";
114820
115009
  import { HTTPException as HTTPException113 } from "hono/http-exception";
114821
- import { z as z59 } from "zod";
114822
- var OrganizationId4 = z59.string().uuid();
114823
- var RecoveryOperationId = z59.string().uuid();
115010
+ import { z as z60 } from "zod";
115011
+ var OrganizationId4 = z60.string().uuid();
115012
+ var RecoveryOperationId = z60.string().uuid();
114824
115013
  var productionServices = {
114825
115014
  requireCanonicalHumanRequestIdentity: requireCanonicalHumanRequestIdentity3,
114826
115015
  getManagedAuthRequestActorAdmissionStamp,
@@ -115057,6 +115246,7 @@ function registerOrganizationRecoveryRoutes(app, deps, services = productionServ
115057
115246
  }
115058
115247
 
115059
115248
  // src/routes/managed-onboarding.ts
115249
+ import { signupCreditModelIds as signupCreditModelIds2 } from "@opengeni/config";
115060
115250
  import {
115061
115251
  CompleteSelfServiceOrganizationSetupRequest,
115062
115252
  CompleteSelfServiceOrganizationSetupResponse,
@@ -115071,7 +115261,7 @@ import {
115071
115261
  completeSelfServiceOrganizationSetup,
115072
115262
  completeOrganizationUserSetup,
115073
115263
  getSelfServiceOrganizationOnboardingState,
115074
- nestedPostgresSqlState as nestedPostgresSqlState15,
115264
+ nestedPostgresSqlState as nestedPostgresSqlState16,
115075
115265
  preflightOrganizationUserSetup,
115076
115266
  previewOrganizationUserSetup,
115077
115267
  recordOrganizationSignupUseCase
@@ -115117,6 +115307,7 @@ function registerManagedOnboardingRoutes(app, deps, options = {}) {
115117
115307
  organizationName,
115118
115308
  operationId: parsed.data.operationId,
115119
115309
  requestFingerprint,
115310
+ trialCreditModelIds: signupCreditModelIds2(deps.settings),
115120
115311
  trialCreditsEnabled: deps.settings.productAccessMode === "managed" && deps.settings.verifiedSignupTrialCreditsEnabled
115121
115312
  })
115122
115313
  );
@@ -115128,14 +115319,14 @@ function registerManagedOnboardingRoutes(app, deps, options = {}) {
115128
115319
  useCase: parsed.data.useCase
115129
115320
  }).catch((error) => {
115130
115321
  console.warn("[api] could not record the signup use case", {
115131
- sqlState: nestedPostgresSqlState15(error) ?? null
115322
+ sqlState: nestedPostgresSqlState16(error) ?? null
115132
115323
  });
115133
115324
  });
115134
115325
  }
115135
115326
  return context.json(completed);
115136
115327
  } catch (error) {
115137
115328
  recordOrganizationSetupOutcome(deps.observability, "failed");
115138
- const sqlState = nestedPostgresSqlState15(error);
115329
+ const sqlState = nestedPostgresSqlState16(error);
115139
115330
  if (sqlState === "22023") {
115140
115331
  throw new HTTPException114(422, {
115141
115332
  message: "invalid organization setup request"
@@ -115215,7 +115406,7 @@ function registerManagedOnboardingRoutes(app, deps, options = {}) {
115215
115406
  )
115216
115407
  );
115217
115408
  } catch (error) {
115218
- const sqlState = nestedPostgresSqlState15(error);
115409
+ const sqlState = nestedPostgresSqlState16(error);
115219
115410
  if (sqlState === "22023") {
115220
115411
  throw new HTTPException114(422, {
115221
115412
  message: "invalid account setup request"
@@ -115336,9 +115527,9 @@ import {
115336
115527
  SessionAuthorizationUnavailableError as SessionAuthorizationUnavailableError15,
115337
115528
  SessionTenancyManagedHumanRequiredError as SessionTenancyManagedHumanRequiredError3
115338
115529
  } from "@opengeni/core";
115339
- import { nestedPostgresSqlState as nestedPostgresSqlState16, SessionTenancyNotActivatedError as SessionTenancyNotActivatedError3 } from "@opengeni/db";
115530
+ import { nestedPostgresSqlState as nestedPostgresSqlState17, SessionTenancyNotActivatedError as SessionTenancyNotActivatedError3 } from "@opengeni/db";
115340
115531
  import { HTTPException as HTTPException115 } from "hono/http-exception";
115341
- import { z as z60 } from "zod";
115532
+ import { z as z61 } from "zod";
115342
115533
  async function body2(context, schema) {
115343
115534
  const parsed = schema.safeParse(await context.req.json().catch(() => null));
115344
115535
  if (!parsed.success) throw new HTTPException115(422, { message: "invalid user-resource request" });
@@ -115351,10 +115542,10 @@ function lifecycleError(error) {
115351
115542
  if (error instanceof SessionAuthorizationUnavailableError15) {
115352
115543
  throw new HTTPException115(503, { message: "session authorization unavailable" });
115353
115544
  }
115354
- if (nestedPostgresSqlState16(error) === "42501") {
115545
+ if (nestedPostgresSqlState17(error) === "42501") {
115355
115546
  throw new HTTPException115(403, { message: "user-resource authority denied" });
115356
115547
  }
115357
- if (nestedPostgresSqlState16(error) === "22023") {
115548
+ if (nestedPostgresSqlState17(error) === "22023") {
115358
115549
  throw new HTTPException115(422, { message: "invalid user-resource request" });
115359
115550
  }
115360
115551
  throw error;
@@ -115395,7 +115586,7 @@ function registerUserResourceAuthorityRoutes(app, deps) {
115395
115586
  });
115396
115587
  app.post(`${base}/:authorityId/grants`, async (context) => {
115397
115588
  const workspaceId = context.req.param("workspaceId");
115398
- const authorityId = z60.string().uuid().safeParse(context.req.param("authorityId"));
115589
+ const authorityId = z61.string().uuid().safeParse(context.req.param("authorityId"));
115399
115590
  if (!authorityId.success) throw new HTTPException115(422, { message: "invalid authority id" });
115400
115591
  const request = await body2(context, IssueUserResourceGrantRequest);
115401
115592
  const access = await requireAccessGrantAuthorization39(
@@ -115425,7 +115616,7 @@ function registerUserResourceAuthorityRoutes(app, deps) {
115425
115616
  app.delete(`${base}/grants/:grantId`, async (context) => {
115426
115617
  const query = RevokeUserResourceGrantQuery.safeParse({ scope: context.req.query("scope") });
115427
115618
  if (!query.success) throw new HTTPException115(422, { message: "explicit scope=user required" });
115428
- const grantId = z60.string().uuid().safeParse(context.req.param("grantId"));
115619
+ const grantId = z61.string().uuid().safeParse(context.req.param("grantId"));
115429
115620
  if (!grantId.success) throw new HTTPException115(422, { message: "invalid grant id" });
115430
115621
  const workspaceId = context.req.param("workspaceId");
115431
115622
  const access = await requireAccessGrantAuthorization39(
@@ -116432,14 +116623,14 @@ function resolveSlackWorkspaceRoute(input) {
116432
116623
  source: "thread"
116433
116624
  };
116434
116625
  }
116435
- const prefix = AUTHORED_BY_INVOKER.has(input.entry.triggerKind) ? parseSlackWorkspacePrefix(splitSlackLeadingMention(input.entry.text, input.botUserId).rest) : null;
116436
- if (prefix) {
116437
- const named = matchCandidate(candidates, prefix.requested);
116626
+ const prefix2 = AUTHORED_BY_INVOKER.has(input.entry.triggerKind) ? parseSlackWorkspacePrefix(splitSlackLeadingMention(input.entry.text, input.botUserId).rest) : null;
116627
+ if (prefix2) {
116628
+ const named = matchCandidate(candidates, prefix2.requested);
116438
116629
  if (named === "ambiguous" || !named) {
116439
116630
  return {
116440
116631
  kind: "denied",
116441
116632
  reason: "no_access_to_named",
116442
- requested: prefix.requested,
116633
+ requested: prefix2.requested,
116443
116634
  candidates
116444
116635
  };
116445
116636
  }
@@ -122068,7 +122259,8 @@ function createAppComposition(deps) {
122068
122259
  await next();
122069
122260
  return;
122070
122261
  }
122071
- const grant = await requireAccessGrant53(c, routeDeps, workspaceId);
122262
+ const permission = c.req.method === "PUT" && /^\/v1\/workspaces\/[^/]+\/artifact-catalog\/[^/]+\/[^/]+\/pin$/.test(c.req.path) ? "artifacts:publish" : void 0;
122263
+ const grant = await requireAccessGrant53(c, routeDeps, workspaceId, permission);
122072
122264
  await withAccessGrantSessionRlsContext(routeDeps, grant, next);
122073
122265
  });
122074
122266
  app.all("/v1/workspaces/:workspaceId/mcp", async (c) => {
@@ -122315,10 +122507,10 @@ function createAppComposition(deps) {
122315
122507
  const workspaceId = c.req.param("workspaceId");
122316
122508
  const grant = await requireAccessGrant53(c, routeDeps, workspaceId);
122317
122509
  const url = new URL(c.req.url);
122318
- const prefix = `/v1/workspaces/${workspaceId}/codemode/sdk`;
122510
+ const prefix2 = `/v1/workspaces/${workspaceId}/codemode/sdk`;
122319
122511
  let forwarded;
122320
122512
  try {
122321
- const path = url.pathname.slice(prefix.length) + url.search;
122513
+ const path = url.pathname.slice(prefix2.length) + url.search;
122322
122514
  forwarded = await codemodeSessionRequest(routeDeps, grant, c.req.raw, path, (session) => {
122323
122515
  assertConfiguredCodemodeSessionProxyPath(session, path, c.req.method);
122324
122516
  const proxyTools = configuredCodemodeSessionProxyTools(routeDeps.settings, session);
@@ -122938,7 +123130,7 @@ async function withTimeout(promise, timeoutMs) {
122938
123130
  }
122939
123131
  var routeLabelPatterns = [
122940
123132
  {
122941
- pattern: /^\/\.well-known\/oauth-authorization-server$/,
123133
+ pattern: /^\/\.well-known\/oauth-authorization-server(?:\/.*)?$/,
122942
123134
  label: "/.well-known/oauth-authorization-server"
122943
123135
  },
122944
123136
  {
@@ -123945,4 +124137,4 @@ export {
123945
124137
  withDefaultEnabledCapabilityMcpTools,
123946
124138
  workflowIdForSession4 as workflowIdForSession
123947
124139
  };
123948
- //# sourceMappingURL=chunk-6TZ5LG3O.js.map
124140
+ //# sourceMappingURL=chunk-BAZXDFT2.js.map