@odla-ai/chapter 0.8.0 → 0.9.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
@@ -701,11 +701,22 @@ declare function projectApplicant(deps: ProjectionDeps, applicant: Applicant): P
701
701
  recordId: string;
702
702
  }>;
703
703
 
704
+ /** The outcome of a Clerk provisioning call. `existed` marks the heal case: Clerk
705
+ * rejected it because the account/invitation is already there, which is the end
706
+ * state we wanted anyway. */
707
+ interface ClerkResult {
708
+ ok: boolean;
709
+ status: number;
710
+ existed?: boolean;
711
+ }
704
712
  /** Inputs for a Clerk invitation. */
705
713
  interface ClerkInviteInput {
706
714
  email: string;
707
715
  /** Where the accept-invitation link lands (usually the member area). */
708
716
  redirectUrl?: string;
717
+ /** Written to the invitation's `public_metadata`, so the accepted account
718
+ * carries your own profile fields. */
719
+ publicMetadata?: Record<string, unknown>;
709
720
  }
710
721
  /** Build the Clerk Backend API invitation request (path + JSON body). Pure, so
711
722
  * the wire shape is testable without a network call. */
@@ -713,18 +724,18 @@ declare function clerkInviteRequest(input: ClerkInviteInput): {
713
724
  path: string;
714
725
  body: Record<string, unknown>;
715
726
  };
716
- /** POST the invitation to the Clerk Backend API. `ignore_existing` isn't set, so
717
- * a repeat invite for an already-invited/known email returns non-ok the caller
718
- * swallows that (idempotent-enough for a best-effort apply-time invite). */
719
- declare function createClerkInvitation(secretKey: string, input: ClerkInviteInput, fetchImpl?: typeof fetch): Promise<{
720
- ok: boolean;
721
- status: number;
722
- }>;
727
+ /** POST the invitation to the Clerk Backend API. A repeat invite for an
728
+ * already-invited email heals to `{ ok: true, existed: true }` rather than
729
+ * reporting a failure the caller would have to special-case. */
730
+ declare function createClerkInvitation(secretKey: string, input: ClerkInviteInput, fetchImpl?: typeof fetch): Promise<ClerkResult>;
723
731
  /** Inputs for a server-side Clerk user create. */
724
732
  interface ClerkUserInput {
725
733
  email: string;
726
734
  firstName?: string;
727
735
  lastName?: string;
736
+ /** Written to the user's `public_metadata` — the site's own profile fields
737
+ * (role, tier, whatever the member area reads). */
738
+ publicMetadata?: Record<string, unknown>;
728
739
  }
729
740
  /** Build the Clerk Backend API user-create request. The account is created
730
741
  * passwordless (the member signs in via the site's Clerk flow), so join step 3
@@ -733,12 +744,10 @@ declare function clerkUserRequest(input: ClerkUserInput): {
733
744
  path: string;
734
745
  body: Record<string, unknown>;
735
746
  };
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
- }>;
747
+ /** Create the applicant's Clerk account server-side. A repeat for an email that
748
+ * already has an account heals to `{ ok: true, existed: true }` — the account
749
+ * exists, which is the state apply-time provisioning wanted. */
750
+ declare function createClerkUser(secretKey: string, input: ClerkUserInput, fetchImpl?: typeof fetch): Promise<ClerkResult>;
742
751
 
743
752
  /** An application row, as far as the session cares about it. */
744
753
  interface ApplicationRecord {
@@ -962,4 +971,4 @@ type ApplicationBookingPatch = {
962
971
  * already there (never backward). */
963
972
  declare function applicationBookingUpdate(currentStatus: string, startAt: number, htmlLink?: string | null): ApplicationBookingPatch;
964
973
 
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 };
974
+ 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 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 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
@@ -701,11 +701,22 @@ declare function projectApplicant(deps: ProjectionDeps, applicant: Applicant): P
701
701
  recordId: string;
702
702
  }>;
703
703
 
704
+ /** The outcome of a Clerk provisioning call. `existed` marks the heal case: Clerk
705
+ * rejected it because the account/invitation is already there, which is the end
706
+ * state we wanted anyway. */
707
+ interface ClerkResult {
708
+ ok: boolean;
709
+ status: number;
710
+ existed?: boolean;
711
+ }
704
712
  /** Inputs for a Clerk invitation. */
705
713
  interface ClerkInviteInput {
706
714
  email: string;
707
715
  /** Where the accept-invitation link lands (usually the member area). */
708
716
  redirectUrl?: string;
717
+ /** Written to the invitation's `public_metadata`, so the accepted account
718
+ * carries your own profile fields. */
719
+ publicMetadata?: Record<string, unknown>;
709
720
  }
710
721
  /** Build the Clerk Backend API invitation request (path + JSON body). Pure, so
711
722
  * the wire shape is testable without a network call. */
@@ -713,18 +724,18 @@ declare function clerkInviteRequest(input: ClerkInviteInput): {
713
724
  path: string;
714
725
  body: Record<string, unknown>;
715
726
  };
716
- /** POST the invitation to the Clerk Backend API. `ignore_existing` isn't set, so
717
- * a repeat invite for an already-invited/known email returns non-ok the caller
718
- * swallows that (idempotent-enough for a best-effort apply-time invite). */
719
- declare function createClerkInvitation(secretKey: string, input: ClerkInviteInput, fetchImpl?: typeof fetch): Promise<{
720
- ok: boolean;
721
- status: number;
722
- }>;
727
+ /** POST the invitation to the Clerk Backend API. A repeat invite for an
728
+ * already-invited email heals to `{ ok: true, existed: true }` rather than
729
+ * reporting a failure the caller would have to special-case. */
730
+ declare function createClerkInvitation(secretKey: string, input: ClerkInviteInput, fetchImpl?: typeof fetch): Promise<ClerkResult>;
723
731
  /** Inputs for a server-side Clerk user create. */
724
732
  interface ClerkUserInput {
725
733
  email: string;
726
734
  firstName?: string;
727
735
  lastName?: string;
736
+ /** Written to the user's `public_metadata` — the site's own profile fields
737
+ * (role, tier, whatever the member area reads). */
738
+ publicMetadata?: Record<string, unknown>;
728
739
  }
729
740
  /** Build the Clerk Backend API user-create request. The account is created
730
741
  * passwordless (the member signs in via the site's Clerk flow), so join step 3
@@ -733,12 +744,10 @@ declare function clerkUserRequest(input: ClerkUserInput): {
733
744
  path: string;
734
745
  body: Record<string, unknown>;
735
746
  };
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
- }>;
747
+ /** Create the applicant's Clerk account server-side. A repeat for an email that
748
+ * already has an account heals to `{ ok: true, existed: true }` — the account
749
+ * exists, which is the state apply-time provisioning wanted. */
750
+ declare function createClerkUser(secretKey: string, input: ClerkUserInput, fetchImpl?: typeof fetch): Promise<ClerkResult>;
742
751
 
743
752
  /** An application row, as far as the session cares about it. */
744
753
  interface ApplicationRecord {
@@ -962,4 +971,4 @@ type ApplicationBookingPatch = {
962
971
  * already there (never backward). */
963
972
  declare function applicationBookingUpdate(currentStatus: string, startAt: number, htmlLink?: string | null): ApplicationBookingPatch;
964
973
 
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 };
974
+ 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 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 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
@@ -764,13 +764,15 @@ async function projectApplicant(deps, applicant) {
764
764
  }
765
765
 
766
766
  // src/clerk.ts
767
+ var heal = (status) => status === 422 ? { ok: true, status, existed: true } : { ok: false, status };
767
768
  function clerkInviteRequest(input) {
768
769
  return {
769
770
  path: "/v1/invitations",
770
771
  body: {
771
772
  email_address: input.email,
772
773
  notify: true,
773
- ...input.redirectUrl ? { redirect_url: input.redirectUrl } : {}
774
+ ...input.redirectUrl ? { redirect_url: input.redirectUrl } : {},
775
+ ...input.publicMetadata ? { public_metadata: input.publicMetadata } : {}
774
776
  }
775
777
  };
776
778
  }
@@ -781,7 +783,7 @@ async function createClerkInvitation(secretKey, input, fetchImpl = fetch) {
781
783
  headers: { authorization: `Bearer ${secretKey}`, "content-type": "application/json" },
782
784
  body: JSON.stringify(body)
783
785
  });
784
- return { ok: res.ok, status: res.status };
786
+ return res.ok ? { ok: true, status: res.status } : heal(res.status);
785
787
  }
786
788
  function clerkUserRequest(input) {
787
789
  return {
@@ -790,7 +792,8 @@ function clerkUserRequest(input) {
790
792
  email_address: [input.email],
791
793
  skip_password_requirement: true,
792
794
  ...input.firstName ? { first_name: input.firstName } : {},
793
- ...input.lastName ? { last_name: input.lastName } : {}
795
+ ...input.lastName ? { last_name: input.lastName } : {},
796
+ ...input.publicMetadata ? { public_metadata: input.publicMetadata } : {}
794
797
  }
795
798
  };
796
799
  }
@@ -801,7 +804,7 @@ async function createClerkUser(secretKey, input, fetchImpl = fetch) {
801
804
  headers: { authorization: `Bearer ${secretKey}`, "content-type": "application/json" },
802
805
  body: JSON.stringify(body)
803
806
  });
804
- return { ok: res.ok, status: res.status };
807
+ return res.ok ? { ok: true, status: res.status } : heal(res.status);
805
808
  }
806
809
 
807
810
  // src/session.ts