@odla-ai/chapter 0.10.0 → 0.10.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -156,6 +156,18 @@ These bite silently — a smoke test won't catch them:
156
156
  ready), `"none"` skips it — all need `clerk_secret_key` in the tenant vault. A
157
157
  site that wants server-side create must set `account: "create"`; inheriting the
158
158
  default silently changes the model.
159
+ - **What lands on the Clerk account.** Both models write `public_metadata` as
160
+ `{ applicationId, profile }`, where `profile` is every configured
161
+ `application.required`/`optional` field Clerk doesn't already carry natively
162
+ (so *not* email/firstName/lastName), plus `focus`. It follows your field names —
163
+ `applicantProfile(chapter, fields)` is exported if you want to assert the exact
164
+ shape in a test before deleting a local override.
165
+ - **Disclaimer acknowledgement.** A truthy `disclaimerAck` on the submit body
166
+ (boolean or the string a plain form posts) stamps `disclaimerAckAt` from the
167
+ *server* clock; no ack leaves the attr absent, and a client-supplied
168
+ `disclaimerAckAt` is ignored. If your join page collects consent, post the flag —
169
+ an unstamped row is the honest record that nobody acked, so a missing flag
170
+ fails silently in exactly the way a compliance record must not.
159
171
  - **CRM projection points.** chapter projects the person on application submit
160
172
  (`projectApplicant`), not on booking or on webhook status change. If you mirror
161
173
  pipeline stage into the CRM, keep those routes.
package/dist/index.cjs CHANGED
@@ -21,6 +21,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
21
21
  var index_exports = {};
22
22
  __export(index_exports, {
23
23
  SCHEDULING_DEFAULTS: () => SCHEDULING_DEFAULTS,
24
+ applicantProfile: () => applicantProfile,
24
25
  applicationBookingUpdate: () => applicationBookingUpdate,
25
26
  applicationSummary: () => applicationSummary,
26
27
  bookingDecision: () => bookingDecision,
@@ -488,6 +489,17 @@ function resolveApplication(a) {
488
489
  bodyCap: a?.bodyCap ?? 32768
489
490
  };
490
491
  }
492
+ var IDENTITY_FIELDS = /* @__PURE__ */ new Set(["email", "firstName", "lastName"]);
493
+ function applicantProfile(chapter, fields) {
494
+ const profile = {};
495
+ for (const f of [...chapter.application.required, ...chapter.application.optional]) {
496
+ if (IDENTITY_FIELDS.has(f)) continue;
497
+ const v = fields[f];
498
+ if (typeof v === "string" && v.trim() !== "") profile[f] = v.trim();
499
+ }
500
+ if (fields.focus !== void 0) profile.focus = fields.focus;
501
+ return Object.keys(profile).length > 0 ? profile : void 0;
502
+ }
491
503
  async function submitApplication(db, chapter, fields, opts) {
492
504
  const app = chapter.application;
493
505
  for (const f of app.required) {
@@ -506,6 +518,7 @@ async function submitApplication(db, chapter, fields, opts) {
506
518
  }
507
519
  if (fields.focus !== void 0) row.focus = fields.focus;
508
520
  if (opts.groupId) row.groupId = opts.groupId;
521
+ if (fields.disclaimerAck === true || fields.disclaimerAck === "true") row.disclaimerAckAt = opts.now;
509
522
  const { duplicate } = await db.transact(
510
523
  [{ t: "update", ns: "applications", id: id2, attrs: row }],
511
524
  opts.submissionId ? { mutationId: `join:${opts.submissionId}` } : void 0