@odla-ai/chapter 0.10.0 → 0.11.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/README.md +30 -0
- package/dist/index.cjs +24 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +25 -2
- package/dist/index.d.ts +25 -2
- package/dist/index.js +24 -2
- package/dist/index.js.map +1 -1
- package/dist/worker/index.cjs +35 -4
- package/dist/worker/index.cjs.map +1 -1
- package/dist/worker/index.d.cts +7 -0
- package/dist/worker/index.d.ts +7 -0
- package/dist/worker/index.js +35 -4
- package/dist/worker/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -175,6 +175,12 @@ interface ChapterApplication {
|
|
|
175
175
|
defaultMaxLen?: number;
|
|
176
176
|
/** Max JSON request body in bytes. Default 32768. */
|
|
177
177
|
bodyCap?: number;
|
|
178
|
+
/** Reject a submit that carries no truthy `disclaimerAck` (400), instead of
|
|
179
|
+
* writing a row with no consent record. Default `false` for back-compat —
|
|
180
|
+
* but turn it on if the disclaimer is a compliance record: a missing ack is
|
|
181
|
+
* otherwise silent, permanent and unreconstructible. Failure is deterministic
|
|
182
|
+
* and surfaces on the first test submit, not intermittently in production. */
|
|
183
|
+
requireDisclaimerAck?: boolean;
|
|
178
184
|
}
|
|
179
185
|
/** The fully-resolved application config carried on the {@link Chapter}. */
|
|
180
186
|
interface ResolvedApplication {
|
|
@@ -183,6 +189,7 @@ interface ResolvedApplication {
|
|
|
183
189
|
maxLen: Record<string, number>;
|
|
184
190
|
defaultMaxLen: number;
|
|
185
191
|
bodyCap: number;
|
|
192
|
+
requireDisclaimerAck: boolean;
|
|
186
193
|
}
|
|
187
194
|
/** The `defineChapter()` config a site fills in. */
|
|
188
195
|
interface ChapterConfig {
|
|
@@ -625,12 +632,28 @@ declare function canceledPatch(): {
|
|
|
625
632
|
|
|
626
633
|
/** Apply defaults + validate the application config. Throws at import on bad shape. */
|
|
627
634
|
declare function resolveApplication(a: ChapterApplication | undefined): ResolvedApplication;
|
|
628
|
-
/**
|
|
635
|
+
/** Whether a submit body carries a genuine disclaimer acknowledgement. Accepts
|
|
636
|
+
* the boolean an API client sends and the string a plain HTML form posts. */
|
|
637
|
+
declare function hasDisclaimerAck(fields: Record<string, unknown>): boolean;
|
|
638
|
+
/**
|
|
639
|
+
* The applicant profile written to the Clerk account's `public_metadata.profile`:
|
|
640
|
+
* every configured application field Clerk does not already carry natively, plus
|
|
641
|
+
* `focus`. Derived from `application.required`/`optional`, so a site's own field
|
|
642
|
+
* names project without this package knowing them. Pure; returns `undefined` when
|
|
643
|
+
* there is nothing to write.
|
|
644
|
+
*/
|
|
645
|
+
declare function applicantProfile(chapter: Chapter, fields: Record<string, unknown>): Record<string, unknown> | undefined;
|
|
646
|
+
/** A validated submission, or a 400-worthy validation error the route returns.
|
|
647
|
+
* `disclaimerAckAt` reports what THIS request recorded — a number when consent
|
|
648
|
+
* was stamped, `null` when none was supplied. It is always present so a missing
|
|
649
|
+
* consent record is visible in the response rather than silently absent from a
|
|
650
|
+
* row nobody reads until an audit. */
|
|
629
651
|
type SubmitResult = {
|
|
630
652
|
ok: true;
|
|
631
653
|
id: string;
|
|
632
654
|
duplicate: boolean;
|
|
633
655
|
status: string;
|
|
656
|
+
disclaimerAckAt: number | null;
|
|
634
657
|
} | {
|
|
635
658
|
ok: false;
|
|
636
659
|
error: string;
|
|
@@ -1008,4 +1031,4 @@ type ApplicationBookingPatch = {
|
|
|
1008
1031
|
* already there (never backward). */
|
|
1009
1032
|
declare function applicationBookingUpdate(currentStatus: string, startAt: number, htmlLink?: string | null): ApplicationBookingPatch;
|
|
1010
1033
|
|
|
1011
|
-
export { type AccountModel, type AdminNotificationTrigger, type Applicant, type ApplicationBookingPatch, type ApplicationRecord, type ApplicationSummary, type Attr, type AttrType, type Chapter, type ChapterApplication, type ChapterAuth, type ChapterBrand, type ChapterConfig, type ChapterDb, type ChapterEmails, type ChapterIntegrationDescriptor, type ChapterIntegrationOptions, type ChapterMode, type ChapterPipeline, type ChapterPolicy, type ChapterPrices, type ChapterScheduling, type ChapterSends, type ClerkInviteInput, type ClerkResult, type ClerkUserInput, type DbOp, type DbRules, type DbSchema, type DeliveryDecision, type EmailGroup, type EmailTemplate, type EmailTemplateRow, type Entity, type ExistingMeeting, type GuardResult, type JoinConfigGroup, type LiveEvent, type MailSender, type MeetingForReconcile, type MeetingRecord, type MeetingReschedulePatch, type MemberApplication, type MemberSession, type NewMeetingRow, type NotifyDeps, type NotifyInput, type NotifyResult, type PaymentsGroup, type ProjectionDeps, type ReconcileDecision, type ResolvedApplication, type ResolvedAuth, type ResolvedPipeline, type ResolvedScheduling, type ResolvedSends, type RoleChangeContext, type Rule, SCHEDULING_DEFAULTS, type SchedulingErrors, type SecretStore, type SessionUser, type SharedPerson, type StripeEvent, type SubmitResult, type WebhookEvent, applicationBookingUpdate, applicationSummary, bookingDecision, brandTokens, buildGroupSeed, canApprove, canBook, canChangeRole, canTransition, canceledPatch, chapterDb, clerkInviteRequest, clerkUserRequest, createChapterIntegration, createClerkInvitation, createClerkUser, defaultCrm, defineChapter, emailGroupFrom, endForSlot, findApplicationRef, firstPaymentPatch, getVaultSecret, introIdempotencyKey, isAdminRole, isAlreadySent, isReconcilable, isSlotAvailable, joinConfig, meetingCreateRow, meetingRescheduleUpdate, memberApplication, memberSession, normalizeWebhookEvent, paymentsReady, planDelivery, projectApplicant, projectSharedRecord, reconcileMeetings, refundedPatch, render, renderSummary, renderTemplateBody, renewalPatch, resolveApplication, resolveAuth, resolvePipeline, resolveScheduling, roleFromClaim, sendTemplated, sharedPersonInput, slotWindow, stageIndex, stripeForm, submitApplication, subscriptionIdempotencyKey, validateScheduling, verifyStripeSignature, webhookMutationId };
|
|
1034
|
+
export { type AccountModel, type AdminNotificationTrigger, type Applicant, type ApplicationBookingPatch, type ApplicationRecord, type ApplicationSummary, type Attr, type AttrType, type Chapter, type ChapterApplication, type ChapterAuth, type ChapterBrand, type ChapterConfig, type ChapterDb, type ChapterEmails, type ChapterIntegrationDescriptor, type ChapterIntegrationOptions, type ChapterMode, type ChapterPipeline, type ChapterPolicy, type ChapterPrices, type ChapterScheduling, type ChapterSends, type ClerkInviteInput, type ClerkResult, type ClerkUserInput, type DbOp, type DbRules, type DbSchema, type DeliveryDecision, type EmailGroup, type EmailTemplate, type EmailTemplateRow, type Entity, type ExistingMeeting, type GuardResult, type JoinConfigGroup, type LiveEvent, type MailSender, type MeetingForReconcile, type MeetingRecord, type MeetingReschedulePatch, type MemberApplication, type MemberSession, type NewMeetingRow, type NotifyDeps, type NotifyInput, type NotifyResult, type PaymentsGroup, type ProjectionDeps, type ReconcileDecision, type ResolvedApplication, type ResolvedAuth, type ResolvedPipeline, type ResolvedScheduling, type ResolvedSends, type RoleChangeContext, type Rule, SCHEDULING_DEFAULTS, type SchedulingErrors, type SecretStore, type SessionUser, type SharedPerson, type StripeEvent, type SubmitResult, type WebhookEvent, applicantProfile, applicationBookingUpdate, applicationSummary, bookingDecision, brandTokens, buildGroupSeed, canApprove, canBook, canChangeRole, canTransition, canceledPatch, chapterDb, clerkInviteRequest, clerkUserRequest, createChapterIntegration, createClerkInvitation, createClerkUser, defaultCrm, defineChapter, emailGroupFrom, endForSlot, findApplicationRef, firstPaymentPatch, getVaultSecret, hasDisclaimerAck, introIdempotencyKey, isAdminRole, isAlreadySent, isReconcilable, isSlotAvailable, joinConfig, meetingCreateRow, meetingRescheduleUpdate, memberApplication, memberSession, normalizeWebhookEvent, paymentsReady, planDelivery, projectApplicant, projectSharedRecord, reconcileMeetings, refundedPatch, render, renderSummary, renderTemplateBody, renewalPatch, resolveApplication, resolveAuth, resolvePipeline, resolveScheduling, roleFromClaim, sendTemplated, sharedPersonInput, slotWindow, stageIndex, stripeForm, submitApplication, subscriptionIdempotencyKey, validateScheduling, verifyStripeSignature, webhookMutationId };
|
package/dist/index.d.ts
CHANGED
|
@@ -175,6 +175,12 @@ interface ChapterApplication {
|
|
|
175
175
|
defaultMaxLen?: number;
|
|
176
176
|
/** Max JSON request body in bytes. Default 32768. */
|
|
177
177
|
bodyCap?: number;
|
|
178
|
+
/** Reject a submit that carries no truthy `disclaimerAck` (400), instead of
|
|
179
|
+
* writing a row with no consent record. Default `false` for back-compat —
|
|
180
|
+
* but turn it on if the disclaimer is a compliance record: a missing ack is
|
|
181
|
+
* otherwise silent, permanent and unreconstructible. Failure is deterministic
|
|
182
|
+
* and surfaces on the first test submit, not intermittently in production. */
|
|
183
|
+
requireDisclaimerAck?: boolean;
|
|
178
184
|
}
|
|
179
185
|
/** The fully-resolved application config carried on the {@link Chapter}. */
|
|
180
186
|
interface ResolvedApplication {
|
|
@@ -183,6 +189,7 @@ interface ResolvedApplication {
|
|
|
183
189
|
maxLen: Record<string, number>;
|
|
184
190
|
defaultMaxLen: number;
|
|
185
191
|
bodyCap: number;
|
|
192
|
+
requireDisclaimerAck: boolean;
|
|
186
193
|
}
|
|
187
194
|
/** The `defineChapter()` config a site fills in. */
|
|
188
195
|
interface ChapterConfig {
|
|
@@ -625,12 +632,28 @@ declare function canceledPatch(): {
|
|
|
625
632
|
|
|
626
633
|
/** Apply defaults + validate the application config. Throws at import on bad shape. */
|
|
627
634
|
declare function resolveApplication(a: ChapterApplication | undefined): ResolvedApplication;
|
|
628
|
-
/**
|
|
635
|
+
/** Whether a submit body carries a genuine disclaimer acknowledgement. Accepts
|
|
636
|
+
* the boolean an API client sends and the string a plain HTML form posts. */
|
|
637
|
+
declare function hasDisclaimerAck(fields: Record<string, unknown>): boolean;
|
|
638
|
+
/**
|
|
639
|
+
* The applicant profile written to the Clerk account's `public_metadata.profile`:
|
|
640
|
+
* every configured application field Clerk does not already carry natively, plus
|
|
641
|
+
* `focus`. Derived from `application.required`/`optional`, so a site's own field
|
|
642
|
+
* names project without this package knowing them. Pure; returns `undefined` when
|
|
643
|
+
* there is nothing to write.
|
|
644
|
+
*/
|
|
645
|
+
declare function applicantProfile(chapter: Chapter, fields: Record<string, unknown>): Record<string, unknown> | undefined;
|
|
646
|
+
/** A validated submission, or a 400-worthy validation error the route returns.
|
|
647
|
+
* `disclaimerAckAt` reports what THIS request recorded — a number when consent
|
|
648
|
+
* was stamped, `null` when none was supplied. It is always present so a missing
|
|
649
|
+
* consent record is visible in the response rather than silently absent from a
|
|
650
|
+
* row nobody reads until an audit. */
|
|
629
651
|
type SubmitResult = {
|
|
630
652
|
ok: true;
|
|
631
653
|
id: string;
|
|
632
654
|
duplicate: boolean;
|
|
633
655
|
status: string;
|
|
656
|
+
disclaimerAckAt: number | null;
|
|
634
657
|
} | {
|
|
635
658
|
ok: false;
|
|
636
659
|
error: string;
|
|
@@ -1008,4 +1031,4 @@ type ApplicationBookingPatch = {
|
|
|
1008
1031
|
* already there (never backward). */
|
|
1009
1032
|
declare function applicationBookingUpdate(currentStatus: string, startAt: number, htmlLink?: string | null): ApplicationBookingPatch;
|
|
1010
1033
|
|
|
1011
|
-
export { type AccountModel, type AdminNotificationTrigger, type Applicant, type ApplicationBookingPatch, type ApplicationRecord, type ApplicationSummary, type Attr, type AttrType, type Chapter, type ChapterApplication, type ChapterAuth, type ChapterBrand, type ChapterConfig, type ChapterDb, type ChapterEmails, type ChapterIntegrationDescriptor, type ChapterIntegrationOptions, type ChapterMode, type ChapterPipeline, type ChapterPolicy, type ChapterPrices, type ChapterScheduling, type ChapterSends, type ClerkInviteInput, type ClerkResult, type ClerkUserInput, type DbOp, type DbRules, type DbSchema, type DeliveryDecision, type EmailGroup, type EmailTemplate, type EmailTemplateRow, type Entity, type ExistingMeeting, type GuardResult, type JoinConfigGroup, type LiveEvent, type MailSender, type MeetingForReconcile, type MeetingRecord, type MeetingReschedulePatch, type MemberApplication, type MemberSession, type NewMeetingRow, type NotifyDeps, type NotifyInput, type NotifyResult, type PaymentsGroup, type ProjectionDeps, type ReconcileDecision, type ResolvedApplication, type ResolvedAuth, type ResolvedPipeline, type ResolvedScheduling, type ResolvedSends, type RoleChangeContext, type Rule, SCHEDULING_DEFAULTS, type SchedulingErrors, type SecretStore, type SessionUser, type SharedPerson, type StripeEvent, type SubmitResult, type WebhookEvent, applicationBookingUpdate, applicationSummary, bookingDecision, brandTokens, buildGroupSeed, canApprove, canBook, canChangeRole, canTransition, canceledPatch, chapterDb, clerkInviteRequest, clerkUserRequest, createChapterIntegration, createClerkInvitation, createClerkUser, defaultCrm, defineChapter, emailGroupFrom, endForSlot, findApplicationRef, firstPaymentPatch, getVaultSecret, introIdempotencyKey, isAdminRole, isAlreadySent, isReconcilable, isSlotAvailable, joinConfig, meetingCreateRow, meetingRescheduleUpdate, memberApplication, memberSession, normalizeWebhookEvent, paymentsReady, planDelivery, projectApplicant, projectSharedRecord, reconcileMeetings, refundedPatch, render, renderSummary, renderTemplateBody, renewalPatch, resolveApplication, resolveAuth, resolvePipeline, resolveScheduling, roleFromClaim, sendTemplated, sharedPersonInput, slotWindow, stageIndex, stripeForm, submitApplication, subscriptionIdempotencyKey, validateScheduling, verifyStripeSignature, webhookMutationId };
|
|
1034
|
+
export { type AccountModel, type AdminNotificationTrigger, type Applicant, type ApplicationBookingPatch, type ApplicationRecord, type ApplicationSummary, type Attr, type AttrType, type Chapter, type ChapterApplication, type ChapterAuth, type ChapterBrand, type ChapterConfig, type ChapterDb, type ChapterEmails, type ChapterIntegrationDescriptor, type ChapterIntegrationOptions, type ChapterMode, type ChapterPipeline, type ChapterPolicy, type ChapterPrices, type ChapterScheduling, type ChapterSends, type ClerkInviteInput, type ClerkResult, type ClerkUserInput, type DbOp, type DbRules, type DbSchema, type DeliveryDecision, type EmailGroup, type EmailTemplate, type EmailTemplateRow, type Entity, type ExistingMeeting, type GuardResult, type JoinConfigGroup, type LiveEvent, type MailSender, type MeetingForReconcile, type MeetingRecord, type MeetingReschedulePatch, type MemberApplication, type MemberSession, type NewMeetingRow, type NotifyDeps, type NotifyInput, type NotifyResult, type PaymentsGroup, type ProjectionDeps, type ReconcileDecision, type ResolvedApplication, type ResolvedAuth, type ResolvedPipeline, type ResolvedScheduling, type ResolvedSends, type RoleChangeContext, type Rule, SCHEDULING_DEFAULTS, type SchedulingErrors, type SecretStore, type SessionUser, type SharedPerson, type StripeEvent, type SubmitResult, type WebhookEvent, applicantProfile, applicationBookingUpdate, applicationSummary, bookingDecision, brandTokens, buildGroupSeed, canApprove, canBook, canChangeRole, canTransition, canceledPatch, chapterDb, clerkInviteRequest, clerkUserRequest, createChapterIntegration, createClerkInvitation, createClerkUser, defaultCrm, defineChapter, emailGroupFrom, endForSlot, findApplicationRef, firstPaymentPatch, getVaultSecret, hasDisclaimerAck, introIdempotencyKey, isAdminRole, isAlreadySent, isReconcilable, isSlotAvailable, joinConfig, meetingCreateRow, meetingRescheduleUpdate, memberApplication, memberSession, normalizeWebhookEvent, paymentsReady, planDelivery, projectApplicant, projectSharedRecord, reconcileMeetings, refundedPatch, render, renderSummary, renderTemplateBody, renewalPatch, resolveApplication, resolveAuth, resolvePipeline, resolveScheduling, roleFromClaim, sendTemplated, sharedPersonInput, slotWindow, stageIndex, stripeForm, submitApplication, subscriptionIdempotencyKey, validateScheduling, verifyStripeSignature, webhookMutationId };
|
package/dist/index.js
CHANGED
|
@@ -400,9 +400,24 @@ function resolveApplication(a) {
|
|
|
400
400
|
optional,
|
|
401
401
|
maxLen: a?.maxLen ?? {},
|
|
402
402
|
defaultMaxLen: a?.defaultMaxLen ?? 2e3,
|
|
403
|
-
bodyCap: a?.bodyCap ?? 32768
|
|
403
|
+
bodyCap: a?.bodyCap ?? 32768,
|
|
404
|
+
requireDisclaimerAck: a?.requireDisclaimerAck ?? false
|
|
404
405
|
};
|
|
405
406
|
}
|
|
407
|
+
function hasDisclaimerAck(fields) {
|
|
408
|
+
return fields.disclaimerAck === true || fields.disclaimerAck === "true";
|
|
409
|
+
}
|
|
410
|
+
var IDENTITY_FIELDS = /* @__PURE__ */ new Set(["email", "firstName", "lastName"]);
|
|
411
|
+
function applicantProfile(chapter, fields) {
|
|
412
|
+
const profile = {};
|
|
413
|
+
for (const f of [...chapter.application.required, ...chapter.application.optional]) {
|
|
414
|
+
if (IDENTITY_FIELDS.has(f)) continue;
|
|
415
|
+
const v = fields[f];
|
|
416
|
+
if (typeof v === "string" && v.trim() !== "") profile[f] = v.trim();
|
|
417
|
+
}
|
|
418
|
+
if (fields.focus !== void 0) profile.focus = fields.focus;
|
|
419
|
+
return Object.keys(profile).length > 0 ? profile : void 0;
|
|
420
|
+
}
|
|
406
421
|
async function submitApplication(db, chapter, fields, opts) {
|
|
407
422
|
const app = chapter.application;
|
|
408
423
|
for (const f of app.required) {
|
|
@@ -414,6 +429,10 @@ async function submitApplication(db, chapter, fields, opts) {
|
|
|
414
429
|
const cap = app.maxLen[f] ?? app.defaultMaxLen;
|
|
415
430
|
if (typeof v === "string" && v.length > cap) return { ok: false, error: `${f} exceeds ${cap} characters` };
|
|
416
431
|
}
|
|
432
|
+
const acked = hasDisclaimerAck(fields);
|
|
433
|
+
if (app.requireDisclaimerAck && !acked) {
|
|
434
|
+
return { ok: false, error: "disclaimerAck is required" };
|
|
435
|
+
}
|
|
417
436
|
const id2 = opts.newId();
|
|
418
437
|
const row = { id: id2, status: chapter.pipeline.initial, createdAt: opts.now };
|
|
419
438
|
for (const f of [...app.required, ...app.optional]) {
|
|
@@ -421,11 +440,12 @@ async function submitApplication(db, chapter, fields, opts) {
|
|
|
421
440
|
}
|
|
422
441
|
if (fields.focus !== void 0) row.focus = fields.focus;
|
|
423
442
|
if (opts.groupId) row.groupId = opts.groupId;
|
|
443
|
+
if (acked) row.disclaimerAckAt = opts.now;
|
|
424
444
|
const { duplicate } = await db.transact(
|
|
425
445
|
[{ t: "update", ns: "applications", id: id2, attrs: row }],
|
|
426
446
|
opts.submissionId ? { mutationId: `join:${opts.submissionId}` } : void 0
|
|
427
447
|
);
|
|
428
|
-
return { ok: true, id: id2, duplicate, status: chapter.pipeline.initial };
|
|
448
|
+
return { ok: true, id: id2, duplicate, status: chapter.pipeline.initial, disclaimerAckAt: acked ? opts.now : null };
|
|
429
449
|
}
|
|
430
450
|
function joinConfig(group, paymentsReady2) {
|
|
431
451
|
return {
|
|
@@ -1037,6 +1057,7 @@ function applicationBookingUpdate(currentStatus, startAt, htmlLink) {
|
|
|
1037
1057
|
}
|
|
1038
1058
|
export {
|
|
1039
1059
|
SCHEDULING_DEFAULTS,
|
|
1060
|
+
applicantProfile,
|
|
1040
1061
|
applicationBookingUpdate,
|
|
1041
1062
|
applicationSummary,
|
|
1042
1063
|
bookingDecision,
|
|
@@ -1060,6 +1081,7 @@ export {
|
|
|
1060
1081
|
findApplicationRef,
|
|
1061
1082
|
firstPaymentPatch,
|
|
1062
1083
|
getVaultSecret,
|
|
1084
|
+
hasDisclaimerAck,
|
|
1063
1085
|
introIdempotencyKey,
|
|
1064
1086
|
isAdminRole,
|
|
1065
1087
|
isAlreadySent,
|