@opengeni/api-router 1.1.0 → 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.
package/dist/app.js CHANGED
@@ -28,7 +28,7 @@ import {
28
28
  withDefaultEnabledCapabilityMcpTools,
29
29
  workflowIdForSession,
30
30
  workspaceActorContextExempt
31
- } from "./chunk-A4J3LBH6.js";
31
+ } from "./chunk-BAZXDFT2.js";
32
32
  import "./chunk-OGQDXVXY.js";
33
33
  export {
34
34
  API_MAX_REQUEST_BODY_BYTES,
@@ -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,
@@ -15383,8 +15384,8 @@ function boundedState(value) {
15383
15384
  function pkceChallenge(verifier) {
15384
15385
  return createHash4("sha256").update(verifier, "ascii").digest("base64url");
15385
15386
  }
15386
- function opaque(prefix) {
15387
- return `${prefix}${randomBytes5(32).toString("base64url")}`;
15387
+ function opaque(prefix2) {
15388
+ return `${prefix2}${randomBytes5(32).toString("base64url")}`;
15388
15389
  }
15389
15390
  function tokenHash(value) {
15390
15391
  return createHash4("sha256").update(value, "utf8").digest("hex");
@@ -21620,21 +21621,21 @@ function projectScheduledTaskUtf8(value, maxBytes) {
21620
21621
  return { value, originalBytes, deliveredBytes: originalBytes, truncated: false };
21621
21622
  }
21622
21623
  let marker = "";
21623
- let prefix = "";
21624
+ let prefix2 = "";
21624
21625
  let omittedBytes = originalBytes;
21625
21626
  for (let attempt = 0; attempt < 4; attempt += 1) {
21626
21627
  marker = `\u2026[${omittedBytes} UTF-8 bytes omitted]`;
21627
21628
  if (Buffer.byteLength(marker, "utf8") > byteLimit) {
21628
21629
  marker = utf8Prefix2(marker, byteLimit);
21629
- prefix = "";
21630
+ prefix2 = "";
21630
21631
  break;
21631
21632
  }
21632
- prefix = utf8Prefix2(value, byteLimit - Buffer.byteLength(marker, "utf8"));
21633
- const nextOmitted = originalBytes - Buffer.byteLength(prefix, "utf8");
21633
+ prefix2 = utf8Prefix2(value, byteLimit - Buffer.byteLength(marker, "utf8"));
21634
+ const nextOmitted = originalBytes - Buffer.byteLength(prefix2, "utf8");
21634
21635
  if (nextOmitted === omittedBytes) break;
21635
21636
  omittedBytes = nextOmitted;
21636
21637
  }
21637
- const projected = `${prefix}${marker}`;
21638
+ const projected = `${prefix2}${marker}`;
21638
21639
  return {
21639
21640
  value: projected,
21640
21641
  originalBytes,
@@ -25081,8 +25082,8 @@ function sniffSlackReactionImageMime(bytes) {
25081
25082
  return null;
25082
25083
  }
25083
25084
  function hasMarkupPrefix(bytes) {
25084
- const prefix = new TextDecoder("utf-8", { fatal: false }).decode(bytes.subarray(0, Math.min(bytes.byteLength, 256))).replace(/^\uFEFF/u, "").trimStart().toLowerCase();
25085
- 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");
25086
25087
  }
25087
25088
  function isCompletePng(bytes) {
25088
25089
  const signature = [137, 80, 78, 71, 13, 10, 26, 10];
@@ -38568,14 +38569,9 @@ var ACTION_CATALOG = [
38568
38569
  "method": "GET",
38569
38570
  "path": "/v1/organizations/:accountId/insights/calls",
38570
38571
  "request": [],
38571
- "response": []
38572
- },
38573
- {
38574
- "id": "GET /v1/organizations/:accountId/insights/usage",
38575
- "method": "GET",
38576
- "path": "/v1/organizations/:accountId/insights/usage",
38577
- "request": [],
38578
- "response": []
38572
+ "response": [
38573
+ "InsightsCallsResponse"
38574
+ ]
38579
38575
  },
38580
38576
  {
38581
38577
  "id": "GET /v1/organizations/:organizationId/codex/accounts",
@@ -38728,14 +38724,9 @@ var ACTION_CATALOG = [
38728
38724
  "method": "GET",
38729
38725
  "path": "/v1/workspaces/:workspaceId/insights/calls",
38730
38726
  "request": [],
38731
- "response": []
38732
- },
38733
- {
38734
- "id": "GET /v1/workspaces/:workspaceId/insights/usage",
38735
- "method": "GET",
38736
- "path": "/v1/workspaces/:workspaceId/insights/usage",
38737
- "request": [],
38738
- "response": []
38727
+ "response": [
38728
+ "InsightsCallsResponse"
38729
+ ]
38739
38730
  },
38740
38731
  {
38741
38732
  "id": "GET /v1/workspaces/:workspaceId/instruction-policies/:revisionId",
@@ -39296,6 +39287,15 @@ var ACTION_CATALOG = [
39296
39287
  "GetOrganizationCredentialProviderResponse"
39297
39288
  ]
39298
39289
  },
39290
+ {
39291
+ "id": "getOrganizationInsightsUsage",
39292
+ "method": "GET",
39293
+ "path": "/v1/organizations/:accountId/insights/usage",
39294
+ "request": [],
39295
+ "response": [
39296
+ "InsightsUsageResponse"
39297
+ ]
39298
+ },
39299
39299
  {
39300
39300
  "id": "getOrganizationIntegrationCatalog",
39301
39301
  "method": "GET",
@@ -39751,6 +39751,15 @@ var ACTION_CATALOG = [
39751
39751
  "WorkspaceInsightsResponse"
39752
39752
  ]
39753
39753
  },
39754
+ {
39755
+ "id": "getWorkspaceInsightsUsage",
39756
+ "method": "GET",
39757
+ "path": "/v1/workspaces/:workspaceId/insights/usage",
39758
+ "request": [],
39759
+ "response": [
39760
+ "InsightsUsageResponse"
39761
+ ]
39762
+ },
39754
39763
  {
39755
39764
  "id": "getWorkspaceLearningHistory",
39756
39765
  "method": "GET",
@@ -73499,13 +73508,13 @@ function registerCatalogAssetRoutes(app, deps) {
73499
73508
  });
73500
73509
  }
73501
73510
  function catalogAssetKeyFromPath(pathname) {
73502
- const prefix = "/v1/";
73503
- if (!pathname.startsWith(prefix)) {
73511
+ const prefix2 = "/v1/";
73512
+ if (!pathname.startsWith(prefix2)) {
73504
73513
  return null;
73505
73514
  }
73506
73515
  let key;
73507
73516
  try {
73508
- key = decodeURIComponent(pathname.slice(prefix.length));
73517
+ key = decodeURIComponent(pathname.slice(prefix2.length));
73509
73518
  } catch {
73510
73519
  return null;
73511
73520
  }
@@ -82445,8 +82454,8 @@ function registerVariableSetRoutes(app, deps) {
82445
82454
  "/v1/workspaces/:workspaceId/variable-sets",
82446
82455
  "/v1/workspaces/:workspaceId/environments"
82447
82456
  ];
82448
- for (const prefix of prefixes) {
82449
- app.get(`${prefix}`, async (c) => {
82457
+ for (const prefix2 of prefixes) {
82458
+ app.get(`${prefix2}`, async (c) => {
82450
82459
  const workspaceId = c.req.param("workspaceId");
82451
82460
  const grant = await requireAccessGrant20(c, deps, workspaceId);
82452
82461
  requirePermission4(grant, "variable-sets:list");
@@ -82459,14 +82468,14 @@ function registerVariableSetRoutes(app, deps) {
82459
82468
  })
82460
82469
  );
82461
82470
  });
82462
- app.post(`${prefix}`, async (c) => {
82471
+ app.post(`${prefix2}`, async (c) => {
82463
82472
  const workspaceId = c.req.param("workspaceId");
82464
82473
  const authorization = await requireAccessGrantAuthorization15(c, deps, workspaceId);
82465
82474
  const grant = authorization.grant;
82466
82475
  requirePermission4(grant, "variable-sets:write");
82467
82476
  const key = requireVariableSetEncryption2(settings);
82468
82477
  const payload = await parseRequestJson(c, CreateVariableSetRequest);
82469
- if (prefix.endsWith("/environments") && payload.scope !== "workspace") {
82478
+ if (prefix2.endsWith("/environments") && payload.scope !== "workspace") {
82470
82479
  throw new HTTPException61(422, {
82471
82480
  message: "the legacy environments route only creates workspace-scoped variable sets"
82472
82481
  });
@@ -82530,8 +82539,8 @@ function registerVariableSetRoutes(app, deps) {
82530
82539
  });
82531
82540
  return c.json(created, 201);
82532
82541
  });
82533
- if (prefix.endsWith("/variable-sets")) {
82534
- app.post(`${prefix}/resolve-attachments`, async (c) => {
82542
+ if (prefix2.endsWith("/variable-sets")) {
82543
+ app.post(`${prefix2}/resolve-attachments`, async (c) => {
82535
82544
  const workspaceId = c.req.param("workspaceId");
82536
82545
  const grant = await requireAccessGrant20(c, deps, workspaceId);
82537
82546
  requirePermission4(grant, "variable-sets:attach");
@@ -82549,15 +82558,15 @@ function registerVariableSetRoutes(app, deps) {
82549
82558
  return c.json(ResolveVariableSetAttachmentsResponse.parse({ variableSets }));
82550
82559
  });
82551
82560
  }
82552
- app.get(`${prefix}/:variableSetId`, async (c) => {
82561
+ app.get(`${prefix2}/:variableSetId`, async (c) => {
82553
82562
  const workspaceId = c.req.param("workspaceId");
82554
82563
  const grant = await requireAccessGrant20(c, deps, workspaceId);
82555
82564
  requirePermission4(grant, "variable-sets:read");
82556
82565
  requirePermission4(grant, "secrets:list");
82557
82566
  return c.json(await requireVariableSetForApi(db, grant, c.req.param("variableSetId")));
82558
82567
  });
82559
- if (prefix.endsWith("/variable-sets")) {
82560
- app.get(`${prefix}/:variableSetId/variables/:name`, async (c) => {
82568
+ if (prefix2.endsWith("/variable-sets")) {
82569
+ app.get(`${prefix2}/:variableSetId/variables/:name`, async (c) => {
82561
82570
  const workspaceId = c.req.param("workspaceId");
82562
82571
  const grant = await requireAccessGrant20(c, deps, workspaceId);
82563
82572
  requirePermission4(grant, "variable-sets:read");
@@ -82581,7 +82590,7 @@ function registerVariableSetRoutes(app, deps) {
82581
82590
  return c.json(secret);
82582
82591
  });
82583
82592
  }
82584
- app.patch(`${prefix}/:variableSetId`, async (c) => {
82593
+ app.patch(`${prefix2}/:variableSetId`, async (c) => {
82585
82594
  const workspaceId = c.req.param("workspaceId");
82586
82595
  const authorization = await requireAccessGrantAuthorization15(c, deps, workspaceId);
82587
82596
  const grant = authorization.grant;
@@ -82629,7 +82638,7 @@ function registerVariableSetRoutes(app, deps) {
82629
82638
  });
82630
82639
  return c.json(updated);
82631
82640
  });
82632
- app.delete(`${prefix}/:variableSetId`, async (c) => {
82641
+ app.delete(`${prefix2}/:variableSetId`, async (c) => {
82633
82642
  const workspaceId = c.req.param("workspaceId");
82634
82643
  const authorization = await requireAccessGrantAuthorization15(c, deps, workspaceId);
82635
82644
  const grant = authorization.grant;
@@ -82666,7 +82675,7 @@ function registerVariableSetRoutes(app, deps) {
82666
82675
  });
82667
82676
  return c.json({ ok: true });
82668
82677
  });
82669
- app.put(`${prefix}/:variableSetId/variables/:name`, async (c) => {
82678
+ app.put(`${prefix2}/:variableSetId/variables/:name`, async (c) => {
82670
82679
  const workspaceId = c.req.param("workspaceId");
82671
82680
  const authorization = await requireAccessGrantAuthorization15(c, deps, workspaceId);
82672
82681
  const grant = authorization.grant;
@@ -82705,7 +82714,7 @@ function registerVariableSetRoutes(app, deps) {
82705
82714
  });
82706
82715
  return c.json(metadata);
82707
82716
  });
82708
- app.delete(`${prefix}/:variableSetId/variables/:name`, async (c) => {
82717
+ app.delete(`${prefix2}/:variableSetId/variables/:name`, async (c) => {
82709
82718
  const workspaceId = c.req.param("workspaceId");
82710
82719
  const authorization = await requireAccessGrantAuthorization15(c, deps, workspaceId);
82711
82720
  const grant = authorization.grant;
@@ -83021,10 +83030,43 @@ import {
83021
83030
  OrganizationUsageWorkspacePageQuery
83022
83031
  } from "@opengeni/contracts";
83023
83032
  import { OrganizationModelUsageQuery } from "@opengeni/contracts/organization-model-usage";
83024
- 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
83025
83066
  import {
83026
83067
  applyCreditLedgerEntry,
83027
83068
  getBillingBalance,
83069
+ readCreditPromotionPolicy,
83028
83070
  getBillingCustomer,
83029
83071
  getCreditLedgerEntry,
83030
83072
  hasCreditLedgerEntry,
@@ -83034,6 +83076,7 @@ import {
83034
83076
  getOrganizationUsageSummary,
83035
83077
  getOrganizationUsageWorkspacePage,
83036
83078
  withSessionRlsActorContext as withSessionRlsActorContext8,
83079
+ withRlsContext as withRlsContext2,
83037
83080
  getManagedAccount as getManagedAccount2,
83038
83081
  markStripeWebhookProcessed,
83039
83082
  recordStripeWebhookEvent,
@@ -83139,6 +83182,12 @@ function registerBillingRoutes(app, deps) {
83139
83182
  const accountId = requireSelectedAccount(context, body3.accountId, "billing:manage");
83140
83183
  const stripe = stripeClient(deps);
83141
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;
83142
83191
  const amountCents = body3.amountUsd !== void 0 ? usdToCents(body3.amountUsd) : promotion?.amountOffCents ?? null;
83143
83192
  if (amountCents === null) {
83144
83193
  throw new HTTPException64(422, {
@@ -83150,6 +83199,11 @@ function registerBillingRoutes(app, deps) {
83150
83199
  message: "Credits must be between $5 and $10,000."
83151
83200
  });
83152
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
+ }
83153
83207
  const amountMicros = centsToMicros(amountCents);
83154
83208
  const customerId = await getOrCreateStripeCustomer(deps, stripe, context, accountId);
83155
83209
  const idempotencyKey = `checkout:${accountId}:${amountMicros}:${crypto.randomUUID()}`;
@@ -83167,8 +83221,10 @@ function registerBillingRoutes(app, deps) {
83167
83221
  successUrl: body3.successUrl,
83168
83222
  cancelUrl: body3.cancelUrl,
83169
83223
  idempotencyKey,
83224
+ promotionalScope,
83170
83225
  ...promotion ? {
83171
83226
  promotionCodeId: promotion.id,
83227
+ couponId: promotion.couponId,
83172
83228
  fullyDiscounted: promotion.percentOff === 100 || (promotion.amountOffCents ?? 0) >= amountCents
83173
83229
  } : {}
83174
83230
  }),
@@ -83187,7 +83243,8 @@ function registerBillingRoutes(app, deps) {
83187
83243
  CreateCheckoutResponse.parse({
83188
83244
  checkoutSessionId: session.id,
83189
83245
  url: session.url,
83190
- amountUsd: amountCents / 100
83246
+ amountUsd: amountCents / 100,
83247
+ promotionalScope
83191
83248
  })
83192
83249
  );
83193
83250
  });
@@ -83231,6 +83288,7 @@ function registerBillingRoutes(app, deps) {
83231
83288
  state: entry2 ? "granted" : "pending",
83232
83289
  amountMicros: entry2?.amountMicros ?? credit.amountMicros,
83233
83290
  currency: "usd",
83291
+ promotionalScope: creditScopeFromMetadata(session.metadata),
83234
83292
  free: entry2 ? entry2.sourceType === "stripe_checkout_coupon" : isFreeCouponCheckout(session)
83235
83293
  },
83236
83294
  balance: entry2 ? await getBillingBalance(deps.db, accountId) : null
@@ -83330,7 +83388,7 @@ function stripeCheckoutSessionCreateParams(input) {
83330
83388
  return {
83331
83389
  mode: "payment",
83332
83390
  // Stripe takes either a code field on its page or one discount up front.
83333
- ...input.promotionCodeId ? { discounts: [{ promotion_code: input.promotionCodeId }] } : { allow_promotion_codes: true },
83391
+ ...input.promotionCodeId ? { discounts: [{ promotion_code: input.promotionCodeId }] } : { allow_promotion_codes: false },
83334
83392
  customer: input.customerId,
83335
83393
  customer_update: {
83336
83394
  address: "auto",
@@ -83359,6 +83417,8 @@ function stripeCheckoutSessionCreateParams(input) {
83359
83417
  }
83360
83418
  ],
83361
83419
  metadata: {
83420
+ ...creditScopeMetadata(input.promotionalScope),
83421
+ ...input.couponId ? { opengeni_credit_offer_id: input.couponId } : {},
83362
83422
  opengeni_account_id: input.accountId,
83363
83423
  opengeni_credit_amount_usd: (input.amountCents / 100).toFixed(2),
83364
83424
  opengeni_credit_micros: String(input.amountMicros),
@@ -83500,6 +83560,10 @@ async function grantCheckoutSessionCredits(deps, session, source) {
83500
83560
  }
83501
83561
  const credit = decision.credit;
83502
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
+ }
83503
83567
  if (!await getManagedAccount2(deps.db, credit.accountId)) {
83504
83568
  console.info(
83505
83569
  "[api] stripe webhook ignored a checkout session for an account not in this deployment",
@@ -83526,10 +83590,13 @@ async function grantCheckoutSessionCredits(deps, session, source) {
83526
83590
  accountId: credit.accountId,
83527
83591
  type: freeCouponCheckout ? "grant" : "credit_topup",
83528
83592
  amountMicros: credit.amountMicros,
83593
+ eligibleModelIds: promotionalScope?.eligibleModelIds,
83529
83594
  sourceType: freeCouponCheckout ? "stripe_checkout_coupon" : "stripe_checkout_session",
83530
83595
  sourceId: session.id,
83531
83596
  idempotencyKey: credit.idempotencyKey,
83532
83597
  metadata: {
83598
+ ...promotionalScope ? { creditOfferLabel: promotionalScope.label } : {},
83599
+ creditOfferId: session.metadata?.opengeni_credit_offer_id ?? null,
83533
83600
  stripeEventId: source.stripeEventId,
83534
83601
  stripePaymentIntentId: typeof session.payment_intent === "string" ? session.payment_intent : session.payment_intent?.id ?? null,
83535
83602
  stripePackageId: credit.packageId,
@@ -83555,7 +83622,12 @@ async function resolveCheckoutPromotionCode(stripe, code) {
83555
83622
  throw new HTTPException64(422, { message: "That code isn't valid or has expired." });
83556
83623
  }
83557
83624
  const amountOffCents = coupon.amount_off && coupon.currency === "usd" ? coupon.amount_off : coupon.currency_options?.usd?.amount_off ?? null;
83558
- 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
+ };
83559
83631
  }
83560
83632
  async function mirrorPaymentIntentCustomer(deps, event) {
83561
83633
  const intent = event.data.object;
@@ -83637,18 +83709,26 @@ async function releaseDisputedCredits(deps, stripe, event) {
83637
83709
  return;
83638
83710
  }
83639
83711
  const holdIdempotencyKey = `stripe:dispute_hold:${dispute.id}`;
83640
- if (!await hasCreditLedgerEntry(deps.db, accountId, holdIdempotencyKey)) {
83641
- return;
83642
- }
83643
83712
  const debitMicros = await creditAdjustmentMicros(deps, metadata, dispute.amount);
83644
- await applyCreditLedgerEntry(deps.db, {
83645
- accountId,
83646
- type: "credit_dispute_release",
83647
- amountMicros: debitMicros,
83648
- sourceType: "stripe_dispute",
83649
- sourceId: dispute.id,
83650
- idempotencyKey: `stripe:dispute_release:${dispute.id}`,
83651
- 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
+ });
83652
83732
  });
83653
83733
  }
83654
83734
  async function creditAdjustmentMicros(deps, metadata, amountCents) {
@@ -91702,9 +91782,9 @@ async function requireGitHubManageGrant(c, deps, workspaceId, expectedState) {
91702
91782
  }
91703
91783
  }
91704
91784
  function allCookieValues(c, name) {
91705
- const prefix = `${name}=`;
91706
- return (c.req.header("cookie") ?? "").split(";").map((part) => part.trim()).filter((part) => part.startsWith(prefix)).map((part) => {
91707
- 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);
91708
91788
  try {
91709
91789
  return decodeURIComponent(raw);
91710
91790
  } catch {
@@ -96472,12 +96552,12 @@ function requireStateCookie(c, state) {
96472
96552
  }
96473
96553
  }
96474
96554
  function allCookieValues2(c, name) {
96475
- const prefix = `${name}=`;
96476
- 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) => {
96477
96557
  try {
96478
- return decodeURIComponent(part.slice(prefix.length));
96558
+ return decodeURIComponent(part.slice(prefix2.length));
96479
96559
  } catch {
96480
- return part.slice(prefix.length);
96560
+ return part.slice(prefix2.length);
96481
96561
  }
96482
96562
  });
96483
96563
  }
@@ -100099,9 +100179,9 @@ function openGeniRealtimeInstructions(additional) {
100099
100179
  const trimmed = additional?.trim();
100100
100180
  if (!trimmed) return OPENGENI_REALTIME_BASE_INSTRUCTIONS;
100101
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";
100102
- const prefix = `${OPENGENI_REALTIME_BASE_INSTRUCTIONS}${heading}`;
100103
- const remaining = REALTIME_INSTRUCTIONS_MAX_BYTES - Buffer.byteLength(prefix, "utf8");
100104
- 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))}`;
100105
100185
  }
100106
100186
  function takeUtf8Head(value, maximumBytes) {
100107
100187
  if (Buffer.byteLength(value, "utf8") <= maximumBytes) return value;
@@ -106311,6 +106391,8 @@ import {
106311
106391
  import { loadWorkspaceCodexModelAvailability } from "@opengeni/core";
106312
106392
  import {
106313
106393
  allWorkspacePermissions,
106394
+ getBillingBalance as getBillingBalance2,
106395
+ spendableCreditMicros,
106314
106396
  createWorkspace,
106315
106397
  ensureWorkspaceByExternalIdentity,
106316
106398
  findWorkspaceByExternalIdentity as findWorkspaceByExternalIdentity2,
@@ -106905,25 +106987,31 @@ function registerWorkspaceRoutes(app, deps) {
106905
106987
  organizationOpenRouterCustomModels: organizationProviders.openrouter.models
106906
106988
  });
106907
106989
  const workspaceSettings = workspace?.settings ?? {};
106990
+ const creditBalance = deps.settings.billingMode === "stripe" ? await getBillingBalance2(deps.db, grant.accountId) : void 0;
106908
106991
  const defaultSelection = await resolveDefaultSessionModelForSelections(deps.db, {
106909
106992
  settings: workspaceCatalogSettings,
106910
106993
  accountId: grant.accountId,
106911
106994
  workspaceSettings,
106912
106995
  selections
106913
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
+ }
106914
107013
  c.header("cache-control", "private, no-store");
106915
- return c.json(
106916
- WorkspaceModelCatalogResponse2.parse(
106917
- projectWorkspaceModelCatalog(selections, {
106918
- defaultSelection,
106919
- creditsSelection: creditsDefaultSessionModel({
106920
- settings: workspaceCatalogSettings,
106921
- selections,
106922
- workspaceSettings
106923
- })
106924
- })
106925
- )
106926
- );
107014
+ return c.json(WorkspaceModelCatalogResponse2.parse(catalog));
106927
107015
  });
106928
107016
  app.get("/v1/workspaces/:workspaceId/gateway-custom-models", async (c) => {
106929
107017
  const workspaceId = c.req.param("workspaceId");
@@ -111974,7 +112062,7 @@ import {
111974
112062
  hasEditableArtifactSessionLink as hasEditableArtifactSessionLink2,
111975
112063
  hasWorkspaceArtifactSessionLink,
111976
112064
  transactionallyAuthorizeEditableArtifactActor,
111977
- withRlsContext as withRlsContext2
112065
+ withRlsContext as withRlsContext3
111978
112066
  } from "@opengeni/db";
111979
112067
  import { HTTPException as HTTPException106 } from "hono/http-exception";
111980
112068
  import { z as z54 } from "zod";
@@ -112005,7 +112093,7 @@ function registerSessionArtifactAssociationRoutes(app, deps) {
112005
112093
  const linked = kind === "editable" ? await hasEditableArtifactSessionLink2(deps.db, scope, sessionId, artifactId2) : await hasWorkspaceArtifactSessionLink(deps.db, workspaceId, sessionId, artifactId2);
112006
112094
  if (!linked) throw new HTTPException106(404, { message: "Artifact association not found" });
112007
112095
  if (kind === "editable") {
112008
- const decision = await withRlsContext2(
112096
+ const decision = await withRlsContext3(
112009
112097
  deps.db,
112010
112098
  scope,
112011
112099
  (tx) => transactionallyAuthorizeEditableArtifactActor(tx, {
@@ -113138,8 +113226,8 @@ function setTransactionCookie(context, deps, transactionId, transactionSecret) {
113138
113226
  }
113139
113227
  function requireTransactionSecret(context, transactionId) {
113140
113228
  const value = getCookie(context, MANAGED_AUTH_LOGIN_TRANSACTION_COOKIE);
113141
- const prefix = `${transactionId}.`;
113142
- 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;
113143
113231
  if (!secret || !/^[A-Za-z0-9_-]{43}$/.test(secret)) {
113144
113232
  throw managedAuthApiError(401, "invalid_transaction");
113145
113233
  }
@@ -113739,6 +113827,7 @@ function registerCanonicalHumanIdentityRoutes(app, deps) {
113739
113827
  }
113740
113828
 
113741
113829
  // src/routes/organization-memberships.ts
113830
+ import { signupCreditModelIds } from "@opengeni/config";
113742
113831
  import {
113743
113832
  lookupExternalIdentityForRequest,
113744
113833
  cancelExternalWorkspaceMemberGrantForRequest,
@@ -113985,6 +114074,7 @@ function registerOrganizationMembershipRoutes(app, deps) {
113985
114074
  subjectId,
113986
114075
  subjectLabel: session.user.email || session.user.name,
113987
114076
  ...payload,
114077
+ trialCreditModelIds: signupCreditModelIds(deps.settings),
113988
114078
  trialCreditsEnabled: deps.settings.productAccessMode === "managed" && deps.settings.verifiedSignupTrialCreditsEnabled
113989
114079
  })
113990
114080
  ),
@@ -115156,6 +115246,7 @@ function registerOrganizationRecoveryRoutes(app, deps, services = productionServ
115156
115246
  }
115157
115247
 
115158
115248
  // src/routes/managed-onboarding.ts
115249
+ import { signupCreditModelIds as signupCreditModelIds2 } from "@opengeni/config";
115159
115250
  import {
115160
115251
  CompleteSelfServiceOrganizationSetupRequest,
115161
115252
  CompleteSelfServiceOrganizationSetupResponse,
@@ -115216,6 +115307,7 @@ function registerManagedOnboardingRoutes(app, deps, options = {}) {
115216
115307
  organizationName,
115217
115308
  operationId: parsed.data.operationId,
115218
115309
  requestFingerprint,
115310
+ trialCreditModelIds: signupCreditModelIds2(deps.settings),
115219
115311
  trialCreditsEnabled: deps.settings.productAccessMode === "managed" && deps.settings.verifiedSignupTrialCreditsEnabled
115220
115312
  })
115221
115313
  );
@@ -116531,14 +116623,14 @@ function resolveSlackWorkspaceRoute(input) {
116531
116623
  source: "thread"
116532
116624
  };
116533
116625
  }
116534
- const prefix = AUTHORED_BY_INVOKER.has(input.entry.triggerKind) ? parseSlackWorkspacePrefix(splitSlackLeadingMention(input.entry.text, input.botUserId).rest) : null;
116535
- if (prefix) {
116536
- 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);
116537
116629
  if (named === "ambiguous" || !named) {
116538
116630
  return {
116539
116631
  kind: "denied",
116540
116632
  reason: "no_access_to_named",
116541
- requested: prefix.requested,
116633
+ requested: prefix2.requested,
116542
116634
  candidates
116543
116635
  };
116544
116636
  }
@@ -122415,10 +122507,10 @@ function createAppComposition(deps) {
122415
122507
  const workspaceId = c.req.param("workspaceId");
122416
122508
  const grant = await requireAccessGrant53(c, routeDeps, workspaceId);
122417
122509
  const url = new URL(c.req.url);
122418
- const prefix = `/v1/workspaces/${workspaceId}/codemode/sdk`;
122510
+ const prefix2 = `/v1/workspaces/${workspaceId}/codemode/sdk`;
122419
122511
  let forwarded;
122420
122512
  try {
122421
- const path = url.pathname.slice(prefix.length) + url.search;
122513
+ const path = url.pathname.slice(prefix2.length) + url.search;
122422
122514
  forwarded = await codemodeSessionRequest(routeDeps, grant, c.req.raw, path, (session) => {
122423
122515
  assertConfiguredCodemodeSessionProxyPath(session, path, c.req.method);
122424
122516
  const proxyTools = configuredCodemodeSessionProxyTools(routeDeps.settings, session);
@@ -124045,4 +124137,4 @@ export {
124045
124137
  withDefaultEnabledCapabilityMcpTools,
124046
124138
  workflowIdForSession4 as workflowIdForSession
124047
124139
  };
124048
- //# sourceMappingURL=chunk-A4J3LBH6.js.map
124140
+ //# sourceMappingURL=chunk-BAZXDFT2.js.map