@odla-ai/chapter 0.40.0 → 0.40.2

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.
@@ -273,6 +273,8 @@ interface ChapterPrices {
273
273
  interface ChapterPolicy {
274
274
  disclaimerText?: string;
275
275
  refundPolicyText?: string;
276
+ /** Plain-language merchant identity shown immediately before payment consent. */
277
+ merchantDisclosureText?: string;
276
278
  trustCopy?: string;
277
279
  commitmentText?: string;
278
280
  normsText?: string;
@@ -877,6 +879,8 @@ interface SignupControlApplication {
877
879
  interface SignupControlPolicy {
878
880
  disclaimerText: string;
879
881
  refundPolicyText: string;
882
+ /** Plain-language merchant identity displayed before payment consent. */
883
+ merchantDisclosureText?: string;
880
884
  trustCopy?: string;
881
885
  commitmentText?: string;
882
886
  normsText?: string;
@@ -273,6 +273,8 @@ interface ChapterPrices {
273
273
  interface ChapterPolicy {
274
274
  disclaimerText?: string;
275
275
  refundPolicyText?: string;
276
+ /** Plain-language merchant identity shown immediately before payment consent. */
277
+ merchantDisclosureText?: string;
276
278
  trustCopy?: string;
277
279
  commitmentText?: string;
278
280
  normsText?: string;
@@ -877,6 +879,8 @@ interface SignupControlApplication {
877
879
  interface SignupControlPolicy {
878
880
  disclaimerText: string;
879
881
  refundPolicyText: string;
882
+ /** Plain-language merchant identity displayed before payment consent. */
883
+ merchantDisclosureText?: string;
880
884
  trustCopy?: string;
881
885
  commitmentText?: string;
882
886
  normsText?: string;
@@ -317,6 +317,7 @@ function joinConfig(group, paymentsReady, tiers = [], conditions = {}) {
317
317
  conditions,
318
318
  disclaimerText: group.disclaimerText ?? "",
319
319
  refundPolicyText: group.refundPolicyText ?? "",
320
+ merchantDisclosureText: group.merchantDisclosureText ?? "",
320
321
  trustCopy: group.trustCopy ?? "",
321
322
  commitmentText: group.commitmentText ?? "",
322
323
  normsText: group.normsText ?? "",
@@ -1647,7 +1648,14 @@ async function createClerkUser(secretKey, input, fetchImpl = fetch) {
1647
1648
  headers: { authorization: `Bearer ${secretKey}`, "content-type": "application/json" },
1648
1649
  body: JSON.stringify(body)
1649
1650
  });
1650
- if (res.ok) return { ok: true, status: res.status };
1651
+ if (res.ok) {
1652
+ const body2 = typeof res.json === "function" ? await res.json().catch(() => null) : null;
1653
+ return {
1654
+ ok: true,
1655
+ status: res.status,
1656
+ ...typeof body2?.id === "string" && body2.id ? { userId: body2.id } : {}
1657
+ };
1658
+ }
1651
1659
  const healed = heal(res.status);
1652
1660
  const repair = input.repairMetadata ?? {
1653
1661
  ...input.publicMetadata !== void 0 ? { publicMetadata: input.publicMetadata } : {},
@@ -1697,6 +1705,34 @@ async function syncApplicantPrivateMetadata(db, chapter, applicationId, fields,
1697
1705
  return false;
1698
1706
  }
1699
1707
  }
1708
+ var AccountProvisioningError = class extends Error {
1709
+ constructor(code, status) {
1710
+ super(code);
1711
+ this.code = code;
1712
+ this.status = status;
1713
+ }
1714
+ code;
1715
+ status;
1716
+ name = "AccountProvisioningError";
1717
+ };
1718
+ async function provisionApplicantForRoute(db, chapter, applicationId, fields) {
1719
+ try {
1720
+ await provisionApplicant(db, chapter, applicationId, fields);
1721
+ return null;
1722
+ } catch (error) {
1723
+ if (!(error instanceof AccountProvisioningError)) throw error;
1724
+ return {
1725
+ status: error.status,
1726
+ body: {
1727
+ error: {
1728
+ code: error.code,
1729
+ message: error.code === "clerk_secret_unavailable" ? "account provisioning credential is unavailable" : "account provisioning failed"
1730
+ },
1731
+ applicationId
1732
+ }
1733
+ };
1734
+ }
1735
+ }
1700
1736
  async function provisionApplicant(db, chapter, applicationId, fields) {
1701
1737
  const email = typeof fields.email === "string" ? fields.email : "";
1702
1738
  if (!email) return;
@@ -1721,9 +1757,9 @@ async function provisionApplicant(db, chapter, applicationId, fields) {
1721
1757
  } catch {
1722
1758
  }
1723
1759
  if (chapter.account === "none") return;
1760
+ const secret = await getVaultSecret(db, "clerk_secret_key");
1761
+ if (!secret) throw new AccountProvisioningError("clerk_secret_unavailable", 503);
1724
1762
  try {
1725
- const secret = await getVaultSecret(db, "clerk_secret_key");
1726
- if (!secret) return;
1727
1763
  const privateMetadata = applicantPrivateMetadata(chapter, applicationId, fields);
1728
1764
  if (chapter.account === "create") {
1729
1765
  const result = await createClerkUser(secret, {
@@ -1736,11 +1772,13 @@ async function provisionApplicant(db, chapter, applicationId, fields) {
1736
1772
  privateMetadata: applicantPrivateMetadata(chapter, applicationId, fields, true)
1737
1773
  }
1738
1774
  });
1739
- if (result.ok && (!result.existed || result.refreshed)) {
1740
- await markPrivateMetadataSynced(db, applicationId);
1775
+ if (!result.ok || result.existed && !result.refreshed) {
1776
+ throw new AccountProvisioningError("clerk_account_provisioning_failed", 502);
1741
1777
  }
1778
+ await markPrivateMetadataSynced(db, applicationId, result.userId);
1742
1779
  } else {
1743
1780
  const result = await createClerkInvitation(secret, { email });
1781
+ if (!result.ok) throw new AccountProvisioningError("clerk_account_provisioning_failed", 502);
1744
1782
  if (result.existed) {
1745
1783
  const refreshed = await updateClerkUserMetadataByEmail(secret, email, {
1746
1784
  publicMetadata: publicProfileRemoval,
@@ -1749,7 +1787,9 @@ async function provisionApplicant(db, chapter, applicationId, fields) {
1749
1787
  if (refreshed) await markPrivateMetadataSynced(db, applicationId);
1750
1788
  }
1751
1789
  }
1752
- } catch {
1790
+ } catch (error) {
1791
+ if (error instanceof AccountProvisioningError) throw error;
1792
+ throw new AccountProvisioningError("clerk_account_provisioning_failed", 502);
1753
1793
  }
1754
1794
  }
1755
1795
  async function notifyAdminOfApplication(db, env, chapterId, applicationId, fields) {
@@ -1973,8 +2013,9 @@ var handleMember = async (req, url, env, ctx) => {
1973
2013
  if (effectiveChapter.sends.adminNotification === "submit") {
1974
2014
  await notifyAdminOfApplication(db, env, chapter.id, result.id, parsed);
1975
2015
  }
1976
- await provisionApplicant(db, effectiveChapter, result.id, parsed);
1977
2016
  }
2017
+ const provisioningFailure = await provisionApplicantForRoute(db, effectiveChapter, result.id, parsed);
2018
+ if (provisioningFailure) return json(provisioningFailure.body, provisioningFailure.status);
1978
2019
  const apps = (await db.query({ applications: { $: { where: { id: result.id }, limit: 1 } } })).applications;
1979
2020
  const canonical2 = Array.isArray(apps) ? apps[0] : void 0;
1980
2021
  const groups = (await db.query({ groups: { $: { where: { id: chapter.id }, limit: 1 } } })).groups;
@@ -2325,7 +2366,14 @@ function policyOf(value, errors) {
2325
2366
  errors.push("document.policy must be an object");
2326
2367
  return void 0;
2327
2368
  }
2328
- const allowed2 = /* @__PURE__ */ new Set(["disclaimerText", "refundPolicyText", "trustCopy", "commitmentText", "normsText"]);
2369
+ const allowed2 = /* @__PURE__ */ new Set([
2370
+ "disclaimerText",
2371
+ "refundPolicyText",
2372
+ "merchantDisclosureText",
2373
+ "trustCopy",
2374
+ "commitmentText",
2375
+ "normsText"
2376
+ ]);
2329
2377
  unknownKeys(input, allowed2, "document.policy", errors);
2330
2378
  const result = {};
2331
2379
  for (const key of allowed2) {
@@ -4162,7 +4210,8 @@ var handleGifts = async (req, url, env, ctx) => {
4162
4210
  return json({
4163
4211
  offers: publicGiftOffers(control3?.document.giftOffers, Date.now()),
4164
4212
  claims: buyerGiftClaims(rows2(found.giftClaims).sort((a, b) => Number(b.createdAt) - Number(a.createdAt)), Date.now()),
4165
- refundPolicyText: typeof group?.refundPolicyText === "string" ? group.refundPolicyText : ""
4213
+ refundPolicyText: typeof group?.refundPolicyText === "string" ? group.refundPolicyText : "",
4214
+ merchantDisclosureText: typeof group?.merchantDisclosureText === "string" ? group.merchantDisclosureText : ""
4166
4215
  });
4167
4216
  }
4168
4217
  if (req.method === "POST" && url.pathname === "/api/gifts/checkout") {