@odla-ai/chapter 0.7.0 → 0.8.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/index.d.cts CHANGED
@@ -210,7 +210,14 @@ interface ChapterConfig {
210
210
  auth?: ChapterAuth;
211
211
  /** odla services (db implied). Default `["db","calendar","o11y"]`. */
212
212
  services?: readonly string[];
213
- }
213
+ /** Apply-time account provisioning: `"invite"` (default) mints a Clerk
214
+ * invitation, `"create"` makes the account server-side (so join can say the
215
+ * account is ready), `"none"` skips it. Any of these needs a `clerk_secret_key`
216
+ * vault secret to act. */
217
+ account?: AccountModel;
218
+ }
219
+ /** Apply-time Clerk account provisioning model. */
220
+ type AccountModel = "invite" | "create" | "none";
214
221
  /** The resolved engine `defineChapter()` returns. */
215
222
  interface Chapter {
216
223
  config: ChapterConfig;
@@ -230,6 +237,8 @@ interface Chapter {
230
237
  schema: DbSchema;
231
238
  rules: DbRules;
232
239
  services: readonly string[];
240
+ /** Resolved apply-time account provisioning model (default `"invite"`). */
241
+ account: AccountModel;
233
242
  /** The seed `groups` row derived from config (chapter mode), else `null`. */
234
243
  groupSeed(): Record<string, unknown> | null;
235
244
  }
@@ -711,6 +720,25 @@ declare function createClerkInvitation(secretKey: string, input: ClerkInviteInpu
711
720
  ok: boolean;
712
721
  status: number;
713
722
  }>;
723
+ /** Inputs for a server-side Clerk user create. */
724
+ interface ClerkUserInput {
725
+ email: string;
726
+ firstName?: string;
727
+ lastName?: string;
728
+ }
729
+ /** Build the Clerk Backend API user-create request. The account is created
730
+ * passwordless (the member signs in via the site's Clerk flow), so join step 3
731
+ * can say the account is ready — the "create" alternative to an invitation. */
732
+ declare function clerkUserRequest(input: ClerkUserInput): {
733
+ path: string;
734
+ body: Record<string, unknown>;
735
+ };
736
+ /** Create the applicant's Clerk account server-side. A repeat for a known email
737
+ * returns non-ok; the caller swallows it (best-effort at apply time). */
738
+ declare function createClerkUser(secretKey: string, input: ClerkUserInput, fetchImpl?: typeof fetch): Promise<{
739
+ ok: boolean;
740
+ status: number;
741
+ }>;
714
742
 
715
743
  /** An application row, as far as the session cares about it. */
716
744
  interface ApplicationRecord {
@@ -934,4 +962,4 @@ type ApplicationBookingPatch = {
934
962
  * already there (never backward). */
935
963
  declare function applicationBookingUpdate(currentStatus: string, startAt: number, htmlLink?: string | null): ApplicationBookingPatch;
936
964
 
937
- export { 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 ClerkInviteInput, 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 RoleChangeContext, type Rule, SCHEDULING_DEFAULTS, type SecretStore, type SessionUser, type SharedPerson, type StripeEvent, type SubmitResult, type WebhookEvent, applicationBookingUpdate, applicationSummary, bookingDecision, brandTokens, buildGroupSeed, canApprove, canBook, canChangeRole, canTransition, canceledPatch, chapterDb, clerkInviteRequest, createChapterIntegration, createClerkInvitation, 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, verifyStripeSignature, webhookMutationId };
965
+ export { type AccountModel, 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 ClerkInviteInput, 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 RoleChangeContext, type Rule, SCHEDULING_DEFAULTS, 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, verifyStripeSignature, webhookMutationId };
package/dist/index.d.ts CHANGED
@@ -210,7 +210,14 @@ interface ChapterConfig {
210
210
  auth?: ChapterAuth;
211
211
  /** odla services (db implied). Default `["db","calendar","o11y"]`. */
212
212
  services?: readonly string[];
213
- }
213
+ /** Apply-time account provisioning: `"invite"` (default) mints a Clerk
214
+ * invitation, `"create"` makes the account server-side (so join can say the
215
+ * account is ready), `"none"` skips it. Any of these needs a `clerk_secret_key`
216
+ * vault secret to act. */
217
+ account?: AccountModel;
218
+ }
219
+ /** Apply-time Clerk account provisioning model. */
220
+ type AccountModel = "invite" | "create" | "none";
214
221
  /** The resolved engine `defineChapter()` returns. */
215
222
  interface Chapter {
216
223
  config: ChapterConfig;
@@ -230,6 +237,8 @@ interface Chapter {
230
237
  schema: DbSchema;
231
238
  rules: DbRules;
232
239
  services: readonly string[];
240
+ /** Resolved apply-time account provisioning model (default `"invite"`). */
241
+ account: AccountModel;
233
242
  /** The seed `groups` row derived from config (chapter mode), else `null`. */
234
243
  groupSeed(): Record<string, unknown> | null;
235
244
  }
@@ -711,6 +720,25 @@ declare function createClerkInvitation(secretKey: string, input: ClerkInviteInpu
711
720
  ok: boolean;
712
721
  status: number;
713
722
  }>;
723
+ /** Inputs for a server-side Clerk user create. */
724
+ interface ClerkUserInput {
725
+ email: string;
726
+ firstName?: string;
727
+ lastName?: string;
728
+ }
729
+ /** Build the Clerk Backend API user-create request. The account is created
730
+ * passwordless (the member signs in via the site's Clerk flow), so join step 3
731
+ * can say the account is ready — the "create" alternative to an invitation. */
732
+ declare function clerkUserRequest(input: ClerkUserInput): {
733
+ path: string;
734
+ body: Record<string, unknown>;
735
+ };
736
+ /** Create the applicant's Clerk account server-side. A repeat for a known email
737
+ * returns non-ok; the caller swallows it (best-effort at apply time). */
738
+ declare function createClerkUser(secretKey: string, input: ClerkUserInput, fetchImpl?: typeof fetch): Promise<{
739
+ ok: boolean;
740
+ status: number;
741
+ }>;
714
742
 
715
743
  /** An application row, as far as the session cares about it. */
716
744
  interface ApplicationRecord {
@@ -934,4 +962,4 @@ type ApplicationBookingPatch = {
934
962
  * already there (never backward). */
935
963
  declare function applicationBookingUpdate(currentStatus: string, startAt: number, htmlLink?: string | null): ApplicationBookingPatch;
936
964
 
937
- export { 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 ClerkInviteInput, 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 RoleChangeContext, type Rule, SCHEDULING_DEFAULTS, type SecretStore, type SessionUser, type SharedPerson, type StripeEvent, type SubmitResult, type WebhookEvent, applicationBookingUpdate, applicationSummary, bookingDecision, brandTokens, buildGroupSeed, canApprove, canBook, canChangeRole, canTransition, canceledPatch, chapterDb, clerkInviteRequest, createChapterIntegration, createClerkInvitation, 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, verifyStripeSignature, webhookMutationId };
965
+ export { type AccountModel, 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 ClerkInviteInput, 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 RoleChangeContext, type Rule, SCHEDULING_DEFAULTS, 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, verifyStripeSignature, webhookMutationId };
package/dist/index.js CHANGED
@@ -226,7 +226,7 @@ Warmly,
226
226
  ${name}`;
227
227
  return {
228
228
  adminNotification: {
229
- subject: `New application \u2014 {{firstName}} {{lastName}}`,
229
+ subject: `New application: {{firstName}} {{lastName}}`,
230
230
  text: `A new application came in for ${name}.
231
231
 
232
232
  Name: {{firstName}} {{lastName}}
@@ -245,7 +245,7 @@ Your membership payment is confirmed. We'll be in touch to schedule your intro c
245
245
  Looking forward to our call at {{meetingTime}}. {{meetingLink}}${sign}`
246
246
  },
247
247
  onboardingInvite: {
248
- subject: `You're in \u2014 ${name}`,
248
+ subject: `You're in, ${name}`,
249
249
  text: `Hi {{firstName}},
250
250
 
251
251
  Welcome to ${name}. Your member area is here: {{membersUrl}}${sign}`
@@ -470,6 +470,10 @@ function defineChapter(config) {
470
470
  const application = resolveApplication(config.application);
471
471
  const { schema, rules } = chapterDb(mode, auth);
472
472
  const services = config.services ?? ["db", "calendar", "o11y"];
473
+ const account = config.account ?? "invite";
474
+ if (account !== "invite" && account !== "create" && account !== "none") {
475
+ throw new Error(`defineChapter.account: must be "invite", "create", or "none" \u2014 got "${String(account)}"`);
476
+ }
473
477
  const chapter = {
474
478
  config,
475
479
  id: id2,
@@ -482,6 +486,7 @@ function defineChapter(config) {
482
486
  schema,
483
487
  rules,
484
488
  services,
489
+ account,
485
490
  groupSeed: () => mode === "chapter" ? buildGroupSeed(config) : null
486
491
  };
487
492
  if (config.url !== void 0) chapter.url = config.url;
@@ -508,7 +513,7 @@ function createChapterIntegration(chapter, options = {}) {
508
513
  }
509
514
  return {
510
515
  id: "chapter",
511
- title: `Chapter \u2014 ${chapter.name}`,
516
+ title: `Chapter: ${chapter.name}`,
512
517
  npm: "@odla-ai/chapter",
513
518
  schema: {
514
519
  entities: { ...crmDesc.schema.entities, ...chapter.schema.entities },
@@ -778,6 +783,26 @@ async function createClerkInvitation(secretKey, input, fetchImpl = fetch) {
778
783
  });
779
784
  return { ok: res.ok, status: res.status };
780
785
  }
786
+ function clerkUserRequest(input) {
787
+ return {
788
+ path: "/v1/users",
789
+ body: {
790
+ email_address: [input.email],
791
+ skip_password_requirement: true,
792
+ ...input.firstName ? { first_name: input.firstName } : {},
793
+ ...input.lastName ? { last_name: input.lastName } : {}
794
+ }
795
+ };
796
+ }
797
+ async function createClerkUser(secretKey, input, fetchImpl = fetch) {
798
+ const { path, body } = clerkUserRequest(input);
799
+ const res = await fetchImpl(`https://api.clerk.com${path}`, {
800
+ method: "POST",
801
+ headers: { authorization: `Bearer ${secretKey}`, "content-type": "application/json" },
802
+ body: JSON.stringify(body)
803
+ });
804
+ return { ok: res.ok, status: res.status };
805
+ }
781
806
 
782
807
  // src/session.ts
783
808
  function applicationSummary(app) {
@@ -980,8 +1005,10 @@ export {
980
1005
  canceledPatch,
981
1006
  chapterDb,
982
1007
  clerkInviteRequest,
1008
+ clerkUserRequest,
983
1009
  createChapterIntegration,
984
1010
  createClerkInvitation,
1011
+ createClerkUser,
985
1012
  defaultCrm,
986
1013
  defineChapter,
987
1014
  emailGroupFrom,