@odla-ai/chapter 0.47.6 → 0.47.8

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.
@@ -11,6 +11,8 @@ interface ChapterTierConfig {
11
11
  id: string;
12
12
  name: string;
13
13
  priceCents: number;
14
+ currency?: string;
15
+ interval?: "year" | "month";
14
16
  stripePriceId?: string;
15
17
  blurb?: string;
16
18
  /** Defaults to declaration order when omitted. */
@@ -946,6 +948,10 @@ interface SignupControlTier {
946
948
  available: boolean;
947
949
  sortOrder: number;
948
950
  priceCents: number;
951
+ /** ISO currency; omitted only by pre-field schema-v1 documents. */
952
+ currency?: string;
953
+ /** Recurring interval; omitted only by pre-field schema-v1 documents. */
954
+ interval?: "year" | "month";
949
955
  stripePriceId?: string;
950
956
  blurb?: string;
951
957
  }
@@ -11,6 +11,8 @@ interface ChapterTierConfig {
11
11
  id: string;
12
12
  name: string;
13
13
  priceCents: number;
14
+ currency?: string;
15
+ interval?: "year" | "month";
14
16
  stripePriceId?: string;
15
17
  blurb?: string;
16
18
  /** Defaults to declaration order when omitted. */
@@ -946,6 +948,10 @@ interface SignupControlTier {
946
948
  available: boolean;
947
949
  sortOrder: number;
948
950
  priceCents: number;
951
+ /** ISO currency; omitted only by pre-field schema-v1 documents. */
952
+ currency?: string;
953
+ /** Recurring interval; omitted only by pre-field schema-v1 documents. */
954
+ interval?: "year" | "month";
949
955
  stripePriceId?: string;
950
956
  blurb?: string;
951
957
  }
@@ -316,6 +316,8 @@ function joinConfig(group, paymentsReady, tiers = [], conditions = {}) {
316
316
  name: group.name,
317
317
  standardPriceCents: group.standardPriceCents ?? 0,
318
318
  foundingDiscountCents: group.foundingDiscountCents ?? 0,
319
+ currency: group.currency ?? "usd",
320
+ interval: group.interval ?? "year",
319
321
  tiers: [...tiers],
320
322
  // The browser evaluates the same conditions the server enforces.
321
323
  conditions,
@@ -348,6 +350,8 @@ function resolveTiers(group, rows5 = []) {
348
350
  groupId: String(group.id ?? ""),
349
351
  name: "Membership",
350
352
  priceCents: group.standardPriceCents ?? 0,
353
+ currency: group.currency ?? "usd",
354
+ interval: group.interval ?? "year",
351
355
  ...group.stripePriceId ? { stripePriceId: group.stripePriceId } : {},
352
356
  sortOrder: 0,
353
357
  active: true
@@ -360,11 +364,13 @@ function findTier(tiers, tierId) {
360
364
  if (!tierId) return tiers.length === 1 ? tiers[0] : null;
361
365
  return tiers.find((tier) => tier.id === tierId) ?? null;
362
366
  }
363
- function joinConfigTiers(tiers) {
367
+ function joinConfigTiers(tiers, defaults = {}) {
364
368
  return tiers.map((tier) => ({
365
369
  id: tier.id,
366
370
  name: tier.name,
367
371
  priceCents: tier.priceCents,
372
+ currency: tier.currency ?? defaults.currency ?? "usd",
373
+ interval: tier.interval ?? defaults.interval ?? "year",
368
374
  blurb: tier.blurb ?? "",
369
375
  free: tierIsFree(tier)
370
376
  }));
@@ -377,6 +383,8 @@ function rowToTier(row, groupId) {
377
383
  groupId: String(row.groupId ?? groupId),
378
384
  name: String(row.name ?? ""),
379
385
  priceCents: typeof row.priceCents === "number" ? row.priceCents : 0,
386
+ ...typeof row.currency === "string" && row.currency ? { currency: row.currency } : {},
387
+ ...row.interval === "year" || row.interval === "month" ? { interval: row.interval } : {},
380
388
  ...typeof row.stripePriceId === "string" && row.stripePriceId ? { stripePriceId: row.stripePriceId } : {},
381
389
  ...typeof row.blurb === "string" ? { blurb: row.blurb } : {},
382
390
  sortOrder: typeof row.sortOrder === "number" ? row.sortOrder : 0,
@@ -1491,6 +1499,8 @@ function groupAttrs(document) {
1491
1499
  const firstPaid = [...document.tiers].find((tier) => tier.available && tier.priceCents > 0);
1492
1500
  return {
1493
1501
  ...first4 ? { standardPriceCents: first4.priceCents } : {},
1502
+ currency: first4?.currency ?? "usd",
1503
+ interval: first4?.interval ?? "year",
1494
1504
  foundingDiscountCents: 0,
1495
1505
  ...firstPaid?.stripePriceId ? { stripePriceId: firstPaid.stripePriceId } : {},
1496
1506
  ...document.policy ?? {},
@@ -1524,6 +1534,8 @@ async function materializeSignupControl(db, envelope, previous, receivedAt) {
1524
1534
  groupId: document.target.chapterId,
1525
1535
  name: tier.name,
1526
1536
  priceCents: tier.priceCents,
1537
+ currency: tier.currency ?? "usd",
1538
+ interval: tier.interval ?? "year",
1527
1539
  ...tier.stripePriceId ? { stripePriceId: tier.stripePriceId } : {},
1528
1540
  ...tier.blurb ? { blurb: tier.blurb } : {},
1529
1541
  sortOrder: tier.sortOrder,
@@ -1940,7 +1952,7 @@ var handleMember = async (req, url, env, ctx) => {
1940
1952
  const activeControl = chapter.signupControl ? await loadActiveSignupControl(db, chapter.id, env.ODLA_ENV) : null;
1941
1953
  const application = controlledApplication(chapter.application, activeControl?.document);
1942
1954
  return json({
1943
- ...joinConfig(group, paymentsReady, joinConfigTiers(offered), application.conditions),
1955
+ ...joinConfig(group, paymentsReady, joinConfigTiers(offered, { currency: typeof group.currency === "string" ? group.currency : void 0, interval: group.interval === "month" ? "month" : "year" }), application.conditions),
1944
1956
  fieldContract: chapterFlowFieldContract(chapter, "join", application),
1945
1957
  copy: { ...chapter.copy.join, ...activeControl?.document.application?.copy ?? {} },
1946
1958
  ...activeControl ? { signupControl: {
@@ -2297,7 +2309,7 @@ var ROOT_KEYS2 = /* @__PURE__ */ new Set([
2297
2309
  "theme",
2298
2310
  "giftOffers"
2299
2311
  ]);
2300
- var TIER_KEYS2 = /* @__PURE__ */ new Set(["id", "name", "available", "sortOrder", "priceCents", "stripePriceId", "blurb"]);
2312
+ var TIER_KEYS2 = /* @__PURE__ */ new Set(["id", "name", "available", "sortOrder", "priceCents", "currency", "interval", "stripePriceId", "blurb"]);
2301
2313
  var recordOf = (value) => value !== null && typeof value === "object" && !Array.isArray(value) ? value : null;
2302
2314
  function unknownKeys(value, allowed2, path, errors) {
2303
2315
  for (const key of Object.keys(value)) if (!allowed2.has(key)) errors.push(`${path}.${key} is not supported`);
@@ -2341,6 +2353,12 @@ function tiersOf(value, errors) {
2341
2353
  if (item.available === true && Number(item.priceCents) > 0 && !item.stripePriceId) {
2342
2354
  errors.push(`${path}.stripePriceId is required for an available paid tier`);
2343
2355
  }
2356
+ if (item.currency !== void 0 && (typeof item.currency !== "string" || !/^[a-z]{3}$/.test(item.currency))) {
2357
+ errors.push(`${path}.currency must be a lowercase ISO currency code`);
2358
+ }
2359
+ if (item.interval !== void 0 && item.interval !== "year" && item.interval !== "month") {
2360
+ errors.push(`${path}.interval must be year or month`);
2361
+ }
2344
2362
  const blurb = item.blurb === void 0 ? void 0 : text2(item.blurb, `${path}.blurb`, errors, 4e3);
2345
2363
  return [{
2346
2364
  id,
@@ -2348,6 +2366,8 @@ function tiersOf(value, errors) {
2348
2366
  available: item.available === true,
2349
2367
  sortOrder: Number(item.sortOrder) || 0,
2350
2368
  priceCents: Number(item.priceCents) || 0,
2369
+ ...typeof item.currency === "string" ? { currency: item.currency } : {},
2370
+ ...item.interval === "year" || item.interval === "month" ? { interval: item.interval } : {},
2351
2371
  ...typeof item.stripePriceId === "string" ? { stripePriceId: item.stripePriceId } : {},
2352
2372
  ...blurb ? { blurb } : {}
2353
2373
  }];