@odla-ai/chapter 0.12.0 → 0.13.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
@@ -833,6 +833,32 @@ declare function clerkUserRequest(input: ClerkUserInput): {
833
833
  * re-application repairs a previously missed create (`refreshed: true`). */
834
834
  declare function createClerkUser(secretKey: string, input: ClerkUserInput, fetchImpl?: typeof fetch): Promise<ClerkResult>;
835
835
 
836
+ /** A Clerk user as chapter's role layer sees it. `role` defaults to the lowest
837
+ * rung when `public_metadata` carries none; `publicMetadata` is returned raw so a
838
+ * site with a custom ladder can re-derive it. */
839
+ interface ClerkUserRecord {
840
+ id: string;
841
+ email?: string;
842
+ role: string;
843
+ publicMetadata: Record<string, unknown>;
844
+ }
845
+ /** Look a Clerk user up by email. `null` when no such user — or when the lookup
846
+ * fails (a role gate treats an unresolvable user as absent, matching the site's
847
+ * own fallback). Role defaults to provisional when unset. */
848
+ declare function clerkGetUserByEmail(secretKey: string, email: string, fetchImpl?: typeof fetch): Promise<ClerkUserRecord | null>;
849
+ /** Fetch a Clerk user by id, for role-change gating. `null` when missing or on a
850
+ * failed lookup. Role defaults to provisional when unset. */
851
+ declare function clerkGetUser(secretKey: string, id: string, fetchImpl?: typeof fetch): Promise<ClerkUserRecord | null>;
852
+ /** List ALL Clerk users with their roles, auto-paginating. A membership community
853
+ * outgrows one page, and a fixed `limit=100` would silently drop members from the
854
+ * admin roster with no error — so this pages (offset in steps of {@link PAGE})
855
+ * until a short page. A page fetch that fails THROWS rather than returning a
856
+ * partial list, so the caller never mistakes a truncated roster for the whole. */
857
+ declare function clerkListUsers(secretKey: string, fetchImpl?: typeof fetch): Promise<ClerkUserRecord[]>;
858
+ /** Write a user's role: a MERGE-PATCH of only `{ role }` on `public_metadata`, so
859
+ * it leaves a separately-written `profile` untouched. Returns whether it stuck. */
860
+ declare function clerkSetRole(secretKey: string, id: string, role: string, fetchImpl?: typeof fetch): Promise<boolean>;
861
+
836
862
  /** An application row, as far as the session cares about it. */
837
863
  interface ApplicationRecord {
838
864
  id: string;
@@ -1071,4 +1097,4 @@ type ApplicationBookingPatch = {
1071
1097
  * already there (never backward). */
1072
1098
  declare function applicationBookingUpdate(currentStatus: string, startAt: number, htmlLink?: string | null): ApplicationBookingPatch;
1073
1099
 
1074
- 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, clampArray, clerkInviteRequest, clerkUserRequest, createChapterIntegration, createClerkInvitation, createClerkUser, defaultCrm, defineChapter, emailGroupFrom, endForSlot, findApplicationRef, firstPaymentPatch, getVaultSecret, hasDisclaimerAck, introIdempotencyKey, isAdminRole, isAlreadySent, isReconcilable, isSlotAvailable, isValidEmail, 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 };
1100
+ 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 ClerkUserRecord, 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, clampArray, clerkGetUser, clerkGetUserByEmail, clerkInviteRequest, clerkListUsers, clerkSetRole, clerkUserRequest, createChapterIntegration, createClerkInvitation, createClerkUser, defaultCrm, defineChapter, emailGroupFrom, endForSlot, findApplicationRef, firstPaymentPatch, getVaultSecret, hasDisclaimerAck, introIdempotencyKey, isAdminRole, isAlreadySent, isReconcilable, isSlotAvailable, isValidEmail, 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
@@ -833,6 +833,32 @@ declare function clerkUserRequest(input: ClerkUserInput): {
833
833
  * re-application repairs a previously missed create (`refreshed: true`). */
834
834
  declare function createClerkUser(secretKey: string, input: ClerkUserInput, fetchImpl?: typeof fetch): Promise<ClerkResult>;
835
835
 
836
+ /** A Clerk user as chapter's role layer sees it. `role` defaults to the lowest
837
+ * rung when `public_metadata` carries none; `publicMetadata` is returned raw so a
838
+ * site with a custom ladder can re-derive it. */
839
+ interface ClerkUserRecord {
840
+ id: string;
841
+ email?: string;
842
+ role: string;
843
+ publicMetadata: Record<string, unknown>;
844
+ }
845
+ /** Look a Clerk user up by email. `null` when no such user — or when the lookup
846
+ * fails (a role gate treats an unresolvable user as absent, matching the site's
847
+ * own fallback). Role defaults to provisional when unset. */
848
+ declare function clerkGetUserByEmail(secretKey: string, email: string, fetchImpl?: typeof fetch): Promise<ClerkUserRecord | null>;
849
+ /** Fetch a Clerk user by id, for role-change gating. `null` when missing or on a
850
+ * failed lookup. Role defaults to provisional when unset. */
851
+ declare function clerkGetUser(secretKey: string, id: string, fetchImpl?: typeof fetch): Promise<ClerkUserRecord | null>;
852
+ /** List ALL Clerk users with their roles, auto-paginating. A membership community
853
+ * outgrows one page, and a fixed `limit=100` would silently drop members from the
854
+ * admin roster with no error — so this pages (offset in steps of {@link PAGE})
855
+ * until a short page. A page fetch that fails THROWS rather than returning a
856
+ * partial list, so the caller never mistakes a truncated roster for the whole. */
857
+ declare function clerkListUsers(secretKey: string, fetchImpl?: typeof fetch): Promise<ClerkUserRecord[]>;
858
+ /** Write a user's role: a MERGE-PATCH of only `{ role }` on `public_metadata`, so
859
+ * it leaves a separately-written `profile` untouched. Returns whether it stuck. */
860
+ declare function clerkSetRole(secretKey: string, id: string, role: string, fetchImpl?: typeof fetch): Promise<boolean>;
861
+
836
862
  /** An application row, as far as the session cares about it. */
837
863
  interface ApplicationRecord {
838
864
  id: string;
@@ -1071,4 +1097,4 @@ type ApplicationBookingPatch = {
1071
1097
  * already there (never backward). */
1072
1098
  declare function applicationBookingUpdate(currentStatus: string, startAt: number, htmlLink?: string | null): ApplicationBookingPatch;
1073
1099
 
1074
- 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, clampArray, clerkInviteRequest, clerkUserRequest, createChapterIntegration, createClerkInvitation, createClerkUser, defaultCrm, defineChapter, emailGroupFrom, endForSlot, findApplicationRef, firstPaymentPatch, getVaultSecret, hasDisclaimerAck, introIdempotencyKey, isAdminRole, isAlreadySent, isReconcilable, isSlotAvailable, isValidEmail, 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 };
1100
+ 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 ClerkUserRecord, 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, clampArray, clerkGetUser, clerkGetUserByEmail, clerkInviteRequest, clerkListUsers, clerkSetRole, clerkUserRequest, createChapterIntegration, createClerkInvitation, createClerkUser, defaultCrm, defineChapter, emailGroupFrom, endForSlot, findApplicationRef, firstPaymentPatch, getVaultSecret, hasDisclaimerAck, introIdempotencyKey, isAdminRole, isAlreadySent, isReconcilable, isSlotAvailable, isValidEmail, 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
@@ -883,6 +883,53 @@ async function createClerkUser(secretKey, input, fetchImpl = fetch) {
883
883
  return { ...healed, refreshed };
884
884
  }
885
885
 
886
+ // src/clerk-roles.ts
887
+ var CLERK_API = "https://api.clerk.com";
888
+ var DEFAULT_ROLE = "provisional";
889
+ var PAGE = 100;
890
+ function toRecord(u) {
891
+ if (typeof u.id !== "string") return null;
892
+ const pm = u.public_metadata ?? {};
893
+ const role = typeof pm.role === "string" && pm.role ? pm.role : DEFAULT_ROLE;
894
+ const email = u.email_addresses?.[0]?.email_address;
895
+ return { id: u.id, email: typeof email === "string" ? email : void 0, role, publicMetadata: pm };
896
+ }
897
+ async function clerkGet(path, secretKey, fetchImpl) {
898
+ const res = await fetchImpl(`${CLERK_API}${path}`, { headers: { authorization: `Bearer ${secretKey}` } });
899
+ if (!res.ok) throw new Error(`clerk GET ${path} \u2192 ${res.status}`);
900
+ return res.json();
901
+ }
902
+ async function clerkGetUserByEmail(secretKey, email, fetchImpl = fetch) {
903
+ const data = await clerkGet(`/v1/users?email_address=${encodeURIComponent(email)}&limit=1`, secretKey, fetchImpl).catch(() => null);
904
+ const user = Array.isArray(data) ? data[0] : void 0;
905
+ return user ? toRecord(user) : null;
906
+ }
907
+ async function clerkGetUser(secretKey, id2, fetchImpl = fetch) {
908
+ const data = await clerkGet(`/v1/users/${encodeURIComponent(id2)}`, secretKey, fetchImpl).catch(() => null);
909
+ return data ? toRecord(data) : null;
910
+ }
911
+ async function clerkListUsers(secretKey, fetchImpl = fetch) {
912
+ const out = [];
913
+ for (let offset = 0; ; offset += PAGE) {
914
+ const data = await clerkGet(`/v1/users?limit=${PAGE}&offset=${offset}`, secretKey, fetchImpl);
915
+ const page = Array.isArray(data) ? data : [];
916
+ for (const u of page) {
917
+ const record = toRecord(u);
918
+ if (record) out.push(record);
919
+ }
920
+ if (page.length < PAGE) break;
921
+ }
922
+ return out;
923
+ }
924
+ async function clerkSetRole(secretKey, id2, role, fetchImpl = fetch) {
925
+ const res = await fetchImpl(`${CLERK_API}/v1/users/${encodeURIComponent(id2)}/metadata`, {
926
+ method: "PATCH",
927
+ headers: { authorization: `Bearer ${secretKey}`, "content-type": "application/json" },
928
+ body: JSON.stringify({ public_metadata: { role } })
929
+ });
930
+ return res.ok;
931
+ }
932
+
886
933
  // src/session.ts
887
934
  function applicationSummary(app) {
888
935
  return {
@@ -1100,7 +1147,11 @@ export {
1100
1147
  canceledPatch,
1101
1148
  chapterDb,
1102
1149
  clampArray,
1150
+ clerkGetUser,
1151
+ clerkGetUserByEmail,
1103
1152
  clerkInviteRequest,
1153
+ clerkListUsers,
1154
+ clerkSetRole,
1104
1155
  clerkUserRequest,
1105
1156
  createChapterIntegration,
1106
1157
  createClerkInvitation,