@odla-ai/chapter 0.33.2 → 0.35.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 +83 -2
- package/dist/index.cjs +217 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +80 -6
- package/dist/index.d.ts +80 -6
- package/dist/index.js +219 -3
- package/dist/index.js.map +1 -1
- package/dist/worker/index.cjs +160 -10
- package/dist/worker/index.cjs.map +1 -1
- package/dist/worker/index.d.cts +99 -1
- package/dist/worker/index.d.ts +99 -1
- package/dist/worker/index.js +160 -10
- package/dist/worker/index.js.map +1 -1
- package/package.json +3 -1
package/dist/index.d.cts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { CrmConfig, Crm, FieldConditions, TypeDef, FieldDef, TypeSummary, CrmRecord } from '@odla-ai/crm';
|
|
2
2
|
import { StripeRequestResult } from '@odla-ai/stripe';
|
|
3
3
|
export { stripeForm, verifyStripeSignature } from '@odla-ai/stripe';
|
|
4
|
+
import { PromotionAdapterResult } from '@odla-ai/promotion';
|
|
4
5
|
|
|
5
6
|
/** One membership tier a chapter offers. `priceCents: 0` means free. */
|
|
6
7
|
interface ChapterTier {
|
|
@@ -300,16 +301,26 @@ interface ChapterPolicy {
|
|
|
300
301
|
type ChapterMode = "chapter" | "hub";
|
|
301
302
|
/** One odla-db transaction op — the wire shape both the real admin client and a
|
|
302
303
|
* test double (`FakeDb`) accept. Built as a plain object, never via a `tx` proxy. */
|
|
303
|
-
|
|
304
|
+
type DbOp<Id extends string | {
|
|
304
305
|
ns: string;
|
|
305
306
|
attr: string;
|
|
306
307
|
value: string | number | boolean;
|
|
307
|
-
} = string> {
|
|
308
|
-
t: "update" | "merge"
|
|
308
|
+
} = string> = {
|
|
309
|
+
t: "update" | "merge";
|
|
309
310
|
ns: string;
|
|
310
311
|
id: Id;
|
|
311
|
-
attrs
|
|
312
|
-
}
|
|
312
|
+
attrs: Record<string, unknown>;
|
|
313
|
+
} | {
|
|
314
|
+
t: "retract";
|
|
315
|
+
ns: string;
|
|
316
|
+
id: Id;
|
|
317
|
+
attrs: string[];
|
|
318
|
+
} | {
|
|
319
|
+
t: "delete";
|
|
320
|
+
ns: string;
|
|
321
|
+
id: Id;
|
|
322
|
+
attrs?: undefined;
|
|
323
|
+
};
|
|
313
324
|
/** The structural view of the odla-db admin client the worker builds and the
|
|
314
325
|
* member routes consume — so route logic is testable against an in-memory fake. */
|
|
315
326
|
interface ChapterDb {
|
|
@@ -2057,6 +2068,59 @@ declare function createSignupControlEnvelope(document: SignupControlDocument): P
|
|
|
2057
2068
|
/** Validate and normalize one complete desired signup state. */
|
|
2058
2069
|
declare function validateSignupControlDocument(input: unknown): SignupControlValidation;
|
|
2059
2070
|
|
|
2071
|
+
/** Stable marker a static document can place where managed signup tokens belong. */
|
|
2072
|
+
declare const SIGNUP_CONTROL_THEME_MARKER: "<!--odla:signup-control-theme-->";
|
|
2073
|
+
/** Stable id shared by the server renderer and browser hydration helper. */
|
|
2074
|
+
declare const SIGNUP_CONTROL_THEME_STYLE_ID: "odla-signup-control-theme";
|
|
2075
|
+
/** The active revision shape exposed by `GET /api/join-config`. */
|
|
2076
|
+
interface SignupControlThemeRevision {
|
|
2077
|
+
revision: number;
|
|
2078
|
+
digest: string;
|
|
2079
|
+
theme?: SignupControlTheme;
|
|
2080
|
+
}
|
|
2081
|
+
/** Identity shared by initial HTML, response caching, and client hydration. */
|
|
2082
|
+
interface SignupControlThemeMetadata {
|
|
2083
|
+
source: "active" | "bootstrap";
|
|
2084
|
+
revision: number | null;
|
|
2085
|
+
digest: string | null;
|
|
2086
|
+
/** Include this value in any host-owned cache key for transformed HTML. */
|
|
2087
|
+
cacheKey: string;
|
|
2088
|
+
}
|
|
2089
|
+
/** A validated style block ready to place in an HTML head. */
|
|
2090
|
+
interface SignupControlThemeHead {
|
|
2091
|
+
css: string;
|
|
2092
|
+
head: string;
|
|
2093
|
+
metadata: SignupControlThemeMetadata;
|
|
2094
|
+
}
|
|
2095
|
+
/** Minimal DOM surface required by {@link hydrateSignupControlTheme}. */
|
|
2096
|
+
interface SignupControlThemeStyleTarget {
|
|
2097
|
+
textContent: string | null;
|
|
2098
|
+
getAttribute(name: string): string | null;
|
|
2099
|
+
setAttribute(name: string, value: string): void;
|
|
2100
|
+
removeAttribute(name: string): void;
|
|
2101
|
+
}
|
|
2102
|
+
/** Host-owned fallback inputs shared by server rendering and hydration. */
|
|
2103
|
+
interface SignupControlThemeOptions {
|
|
2104
|
+
/** Local site-owned tokens used only when no active managed revision exists. */
|
|
2105
|
+
bootstrapTokens?: Readonly<Record<string, string | number>>;
|
|
2106
|
+
}
|
|
2107
|
+
/**
|
|
2108
|
+
* Render validated signup-control tokens for the initial HTML head. Passing
|
|
2109
|
+
* `null` emits the deterministic local bootstrap state; it never performs I/O.
|
|
2110
|
+
*/
|
|
2111
|
+
declare function renderSignupControlThemeHead(revision: SignupControlThemeRevision | null, options?: SignupControlThemeOptions): SignupControlThemeHead;
|
|
2112
|
+
/**
|
|
2113
|
+
* Replace the stable marker (preferred), an earlier Chapter style block, or the
|
|
2114
|
+
* closing head tag. The returned HTML always contains exactly one managed block.
|
|
2115
|
+
*/
|
|
2116
|
+
declare function injectSignupControlThemeHead(html: string, rendered: SignupControlThemeHead, marker?: string): string;
|
|
2117
|
+
/**
|
|
2118
|
+
* Apply a newly fetched revision to the server-rendered style element. When the
|
|
2119
|
+
* revision and digest already match, this performs no writes and returns false,
|
|
2120
|
+
* so hydration cannot cause a visual token change.
|
|
2121
|
+
*/
|
|
2122
|
+
declare function hydrateSignupControlTheme(target: SignupControlThemeStyleTarget, revision: SignupControlThemeRevision | null, options?: SignupControlThemeOptions): boolean;
|
|
2123
|
+
|
|
2060
2124
|
/** A presentation overlay parsed from the constrained membership Markdown convention. */
|
|
2061
2125
|
type MembershipTierMarkdownResult = {
|
|
2062
2126
|
ok: true;
|
|
@@ -2080,4 +2144,14 @@ declare function applyMembershipTierMarkdown(presentation: MembershipTierPresent
|
|
|
2080
2144
|
/** Apply constrained membership Markdown or fail closed with actionable errors. */
|
|
2081
2145
|
declare function membershipTierPresentationFromMarkdown(presentation: MembershipTierPresentation, source: string): MembershipTierPresentation;
|
|
2082
2146
|
|
|
2083
|
-
|
|
2147
|
+
/** Stable adapter identity bound into Chapter artifact provenance. */
|
|
2148
|
+
declare const CHAPTER_PROMOTION_ADAPTER = "@odla-ai/chapter/v1";
|
|
2149
|
+
/** One exact, digest-verified signup-control revision to export. */
|
|
2150
|
+
interface ChapterPromotionInput {
|
|
2151
|
+
document: SignupControlDocument;
|
|
2152
|
+
digest: string;
|
|
2153
|
+
}
|
|
2154
|
+
/** Export the provider-independent pieces of one exact active signup revision. */
|
|
2155
|
+
declare function exportChapterPromotion(input: ChapterPromotionInput): Promise<PromotionAdapterResult>;
|
|
2156
|
+
|
|
2157
|
+
export { type AccountModel, type AdminNotificationTrigger, type Applicant, type ApplicationBookingPatch, type ApplicationRecord, type ApplicationSummary, type Attr, type AttrType, CHAPTER_PROMOTION_ADAPTER, type Chapter, type ChapterApplication, type ChapterAuth, type ChapterBrand, type ChapterConfig, type ChapterCopy, type ChapterCopyInput, type ChapterDb, type ChapterEmails, type ChapterIntegrationDescriptor, type ChapterIntegrationOptions, type ChapterMode, type ChapterNetwork, type ChapterNetworkReader, type ChapterNetworkTarget, type ChapterOperations, type ChapterPipeline, type ChapterPolicy, type ChapterPrices, type ChapterPromotionInput, type ChapterRunbookHints, type ChapterScheduling, type ChapterSends, type ChapterSignupControl, type ChapterTier, type ChapterTierConfig, type ClerkInviteInput, type ClerkMetadataInput, type ClerkResult, type ClerkUserInput, type ClerkUserRecord, type CompiledChapterBrandTokens, DEFAULT_CHAPTER_COPY, DEFAULT_SHARE_FIELDS, type DashboardMetricData, type DashboardMetricSeries, type DbOp, type DbRules, type DbSchema, type DeliveryDecision, type EmailGroup, type EmailTemplate, type EmailTemplateRow, type Entity, type ExistingMeeting, type GuardResult, type IntegrationDescriptor, type IntegrationProvision, type IntegrationSecret, type IntegrationSetting, type IntegrationSync, type JoinConfigGroup, type JoinConfigTier, type LeaderCrmOptions, type LeaderFormationConfig, type LiveEvent, MEMBERSHIP_PAGE_RENDERER, type MailSender, type MeetingForReconcile, type MeetingRecord, type MeetingReschedulePatch, type MemberApplication, type MemberSession, type MembershipPageDocument, type MembershipPageValidationOptions, type MembershipPageValidationResult, type MembershipTierAuthority, type MembershipTierCallout, type MembershipTierCapacity, type MembershipTierMarkdownResult, type MembershipTierPresentation, type MembershipTierVariant, type NetworkRecord, type NetworkRecordNote, type NetworkRecordPage, type NetworkRollup, type NetworkRollupTarget, type NetworkSharedNote, type NetworkSnapshot, type NewMeetingRow, type NotifyDeps, type NotifyInput, type NotifyResult, type PaymentsGroup, type ProjectionDeps, type ReconcileDecision, type ResolvedApplication, type ResolvedAuth, type ResolvedLeaderFormation, type ResolvedNetwork, type ResolvedNetworkReader, type ResolvedNetworkTarget, type ResolvedOperations, type ResolvedPipeline, type ResolvedScheduling, type ResolvedSends, type ResolvedSignupControl, type RoleChangeContext, type Rule, SCHEDULING_DEFAULTS, SIGNUP_CONTROL_PATH, SIGNUP_CONTROL_SCHEMA_VERSION, SIGNUP_CONTROL_THEME_MARKER, SIGNUP_CONTROL_THEME_STYLE_ID, type SchedulingErrors, type SecretMode, type SecretStore, type SessionUser, type SharedBusiness, type SharedPerson, type SharedRecord, type SharedRecordV1, type SharedRecordV2, type SignupControlApplication, type SignupControlDocument, type SignupControlEnvelope, type SignupControlPolicy, type SignupControlReceipt, type SignupControlRejection, type SignupControlTheme, type SignupControlThemeHead, type SignupControlThemeMetadata, type SignupControlThemeOptions, type SignupControlThemeRevision, type SignupControlThemeStyleTarget, type SignupControlTier, type SignupControlValidation, type StripeEvent, type StripeResult, type SubmitResult, type TierGroup, type TierGroupRow, type WebhookEvent, applicantProfile, applicationBookingUpdate, applicationSummary, applyMembershipTierMarkdown, backfillCrm, bookingDecision, brandTokens, bucketSeries, buildGroupSeed, buildTierSeeds, canApprove, canBook, canChangeRole, canTransition, canceledPatch, canonicalSignupControl, chapterBrandFromTokens, chapterDb, clampArray, clerkGetUser, clerkGetUserByEmail, clerkIntegration, clerkInviteRequest, clerkListUsers, clerkSetRole, clerkUserRequest, createChapterIntegration, createClerkInvitation, createClerkUser, createSignupControlEnvelope, dashboardMetricData, defaultCrm, defineChapter, emailGroupFrom, endForSlot, exportChapterPromotion, findApplicationRef, findTier, firstPaymentPatch, formatChapterCopy, formationFields, getVaultSecret, hasDisclaimerAck, hydrateSignupControlTheme, injectSignupControlThemeHead, introIdempotencyKey, isAdminRole, isAlreadySent, isReconcilable, isSlotAvailable, isValidEmail, joinConfig, joinConfigTiers, leaderCrmConfig, loadOfferableTiers, loadTiers, meetingCreateRow, meetingRescheduleUpdate, memberApplication, memberSession, membershipPageDocument, membershipTierPresentationFromMarkdown, networkSourceTag, normalizeSharedRecord, normalizeWebhookEvent, offerableTiers, paymentsReady, personInputFromApp, planDelivery, projectApplicant, projectSharedRecord, reconcileMeetings, refundedPatch, render, renderSignupControlThemeHead, renderSummary, renderTemplateBody, renewalPatch, resolveApplication, resolveAuth, resolveChapterCopy, resolveLeaderFormation, resolvePipeline, resolveScheduling, resolveSignupControl, resolveTiers, roleFromClaim, sendTemplated, sharedPersonInput, sharedRecordFromCrm, signupControlDigest, slotWindow, stageIndex, stripeCall, subAnnualCents, submitApplication, subscriptionIdempotencyKey, syncApplicationToCrm, tierIsFree, tierPayable, updateClerkUserMetadata, updateClerkUserMetadataByEmail, validateMembershipPageDocument, validateScheduling, validateSignupControlDocument, webhookMutationId };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { CrmConfig, Crm, FieldConditions, TypeDef, FieldDef, TypeSummary, CrmRecord } from '@odla-ai/crm';
|
|
2
2
|
import { StripeRequestResult } from '@odla-ai/stripe';
|
|
3
3
|
export { stripeForm, verifyStripeSignature } from '@odla-ai/stripe';
|
|
4
|
+
import { PromotionAdapterResult } from '@odla-ai/promotion';
|
|
4
5
|
|
|
5
6
|
/** One membership tier a chapter offers. `priceCents: 0` means free. */
|
|
6
7
|
interface ChapterTier {
|
|
@@ -300,16 +301,26 @@ interface ChapterPolicy {
|
|
|
300
301
|
type ChapterMode = "chapter" | "hub";
|
|
301
302
|
/** One odla-db transaction op — the wire shape both the real admin client and a
|
|
302
303
|
* test double (`FakeDb`) accept. Built as a plain object, never via a `tx` proxy. */
|
|
303
|
-
|
|
304
|
+
type DbOp<Id extends string | {
|
|
304
305
|
ns: string;
|
|
305
306
|
attr: string;
|
|
306
307
|
value: string | number | boolean;
|
|
307
|
-
} = string> {
|
|
308
|
-
t: "update" | "merge"
|
|
308
|
+
} = string> = {
|
|
309
|
+
t: "update" | "merge";
|
|
309
310
|
ns: string;
|
|
310
311
|
id: Id;
|
|
311
|
-
attrs
|
|
312
|
-
}
|
|
312
|
+
attrs: Record<string, unknown>;
|
|
313
|
+
} | {
|
|
314
|
+
t: "retract";
|
|
315
|
+
ns: string;
|
|
316
|
+
id: Id;
|
|
317
|
+
attrs: string[];
|
|
318
|
+
} | {
|
|
319
|
+
t: "delete";
|
|
320
|
+
ns: string;
|
|
321
|
+
id: Id;
|
|
322
|
+
attrs?: undefined;
|
|
323
|
+
};
|
|
313
324
|
/** The structural view of the odla-db admin client the worker builds and the
|
|
314
325
|
* member routes consume — so route logic is testable against an in-memory fake. */
|
|
315
326
|
interface ChapterDb {
|
|
@@ -2057,6 +2068,59 @@ declare function createSignupControlEnvelope(document: SignupControlDocument): P
|
|
|
2057
2068
|
/** Validate and normalize one complete desired signup state. */
|
|
2058
2069
|
declare function validateSignupControlDocument(input: unknown): SignupControlValidation;
|
|
2059
2070
|
|
|
2071
|
+
/** Stable marker a static document can place where managed signup tokens belong. */
|
|
2072
|
+
declare const SIGNUP_CONTROL_THEME_MARKER: "<!--odla:signup-control-theme-->";
|
|
2073
|
+
/** Stable id shared by the server renderer and browser hydration helper. */
|
|
2074
|
+
declare const SIGNUP_CONTROL_THEME_STYLE_ID: "odla-signup-control-theme";
|
|
2075
|
+
/** The active revision shape exposed by `GET /api/join-config`. */
|
|
2076
|
+
interface SignupControlThemeRevision {
|
|
2077
|
+
revision: number;
|
|
2078
|
+
digest: string;
|
|
2079
|
+
theme?: SignupControlTheme;
|
|
2080
|
+
}
|
|
2081
|
+
/** Identity shared by initial HTML, response caching, and client hydration. */
|
|
2082
|
+
interface SignupControlThemeMetadata {
|
|
2083
|
+
source: "active" | "bootstrap";
|
|
2084
|
+
revision: number | null;
|
|
2085
|
+
digest: string | null;
|
|
2086
|
+
/** Include this value in any host-owned cache key for transformed HTML. */
|
|
2087
|
+
cacheKey: string;
|
|
2088
|
+
}
|
|
2089
|
+
/** A validated style block ready to place in an HTML head. */
|
|
2090
|
+
interface SignupControlThemeHead {
|
|
2091
|
+
css: string;
|
|
2092
|
+
head: string;
|
|
2093
|
+
metadata: SignupControlThemeMetadata;
|
|
2094
|
+
}
|
|
2095
|
+
/** Minimal DOM surface required by {@link hydrateSignupControlTheme}. */
|
|
2096
|
+
interface SignupControlThemeStyleTarget {
|
|
2097
|
+
textContent: string | null;
|
|
2098
|
+
getAttribute(name: string): string | null;
|
|
2099
|
+
setAttribute(name: string, value: string): void;
|
|
2100
|
+
removeAttribute(name: string): void;
|
|
2101
|
+
}
|
|
2102
|
+
/** Host-owned fallback inputs shared by server rendering and hydration. */
|
|
2103
|
+
interface SignupControlThemeOptions {
|
|
2104
|
+
/** Local site-owned tokens used only when no active managed revision exists. */
|
|
2105
|
+
bootstrapTokens?: Readonly<Record<string, string | number>>;
|
|
2106
|
+
}
|
|
2107
|
+
/**
|
|
2108
|
+
* Render validated signup-control tokens for the initial HTML head. Passing
|
|
2109
|
+
* `null` emits the deterministic local bootstrap state; it never performs I/O.
|
|
2110
|
+
*/
|
|
2111
|
+
declare function renderSignupControlThemeHead(revision: SignupControlThemeRevision | null, options?: SignupControlThemeOptions): SignupControlThemeHead;
|
|
2112
|
+
/**
|
|
2113
|
+
* Replace the stable marker (preferred), an earlier Chapter style block, or the
|
|
2114
|
+
* closing head tag. The returned HTML always contains exactly one managed block.
|
|
2115
|
+
*/
|
|
2116
|
+
declare function injectSignupControlThemeHead(html: string, rendered: SignupControlThemeHead, marker?: string): string;
|
|
2117
|
+
/**
|
|
2118
|
+
* Apply a newly fetched revision to the server-rendered style element. When the
|
|
2119
|
+
* revision and digest already match, this performs no writes and returns false,
|
|
2120
|
+
* so hydration cannot cause a visual token change.
|
|
2121
|
+
*/
|
|
2122
|
+
declare function hydrateSignupControlTheme(target: SignupControlThemeStyleTarget, revision: SignupControlThemeRevision | null, options?: SignupControlThemeOptions): boolean;
|
|
2123
|
+
|
|
2060
2124
|
/** A presentation overlay parsed from the constrained membership Markdown convention. */
|
|
2061
2125
|
type MembershipTierMarkdownResult = {
|
|
2062
2126
|
ok: true;
|
|
@@ -2080,4 +2144,14 @@ declare function applyMembershipTierMarkdown(presentation: MembershipTierPresent
|
|
|
2080
2144
|
/** Apply constrained membership Markdown or fail closed with actionable errors. */
|
|
2081
2145
|
declare function membershipTierPresentationFromMarkdown(presentation: MembershipTierPresentation, source: string): MembershipTierPresentation;
|
|
2082
2146
|
|
|
2083
|
-
|
|
2147
|
+
/** Stable adapter identity bound into Chapter artifact provenance. */
|
|
2148
|
+
declare const CHAPTER_PROMOTION_ADAPTER = "@odla-ai/chapter/v1";
|
|
2149
|
+
/** One exact, digest-verified signup-control revision to export. */
|
|
2150
|
+
interface ChapterPromotionInput {
|
|
2151
|
+
document: SignupControlDocument;
|
|
2152
|
+
digest: string;
|
|
2153
|
+
}
|
|
2154
|
+
/** Export the provider-independent pieces of one exact active signup revision. */
|
|
2155
|
+
declare function exportChapterPromotion(input: ChapterPromotionInput): Promise<PromotionAdapterResult>;
|
|
2156
|
+
|
|
2157
|
+
export { type AccountModel, type AdminNotificationTrigger, type Applicant, type ApplicationBookingPatch, type ApplicationRecord, type ApplicationSummary, type Attr, type AttrType, CHAPTER_PROMOTION_ADAPTER, type Chapter, type ChapterApplication, type ChapterAuth, type ChapterBrand, type ChapterConfig, type ChapterCopy, type ChapterCopyInput, type ChapterDb, type ChapterEmails, type ChapterIntegrationDescriptor, type ChapterIntegrationOptions, type ChapterMode, type ChapterNetwork, type ChapterNetworkReader, type ChapterNetworkTarget, type ChapterOperations, type ChapterPipeline, type ChapterPolicy, type ChapterPrices, type ChapterPromotionInput, type ChapterRunbookHints, type ChapterScheduling, type ChapterSends, type ChapterSignupControl, type ChapterTier, type ChapterTierConfig, type ClerkInviteInput, type ClerkMetadataInput, type ClerkResult, type ClerkUserInput, type ClerkUserRecord, type CompiledChapterBrandTokens, DEFAULT_CHAPTER_COPY, DEFAULT_SHARE_FIELDS, type DashboardMetricData, type DashboardMetricSeries, type DbOp, type DbRules, type DbSchema, type DeliveryDecision, type EmailGroup, type EmailTemplate, type EmailTemplateRow, type Entity, type ExistingMeeting, type GuardResult, type IntegrationDescriptor, type IntegrationProvision, type IntegrationSecret, type IntegrationSetting, type IntegrationSync, type JoinConfigGroup, type JoinConfigTier, type LeaderCrmOptions, type LeaderFormationConfig, type LiveEvent, MEMBERSHIP_PAGE_RENDERER, type MailSender, type MeetingForReconcile, type MeetingRecord, type MeetingReschedulePatch, type MemberApplication, type MemberSession, type MembershipPageDocument, type MembershipPageValidationOptions, type MembershipPageValidationResult, type MembershipTierAuthority, type MembershipTierCallout, type MembershipTierCapacity, type MembershipTierMarkdownResult, type MembershipTierPresentation, type MembershipTierVariant, type NetworkRecord, type NetworkRecordNote, type NetworkRecordPage, type NetworkRollup, type NetworkRollupTarget, type NetworkSharedNote, type NetworkSnapshot, type NewMeetingRow, type NotifyDeps, type NotifyInput, type NotifyResult, type PaymentsGroup, type ProjectionDeps, type ReconcileDecision, type ResolvedApplication, type ResolvedAuth, type ResolvedLeaderFormation, type ResolvedNetwork, type ResolvedNetworkReader, type ResolvedNetworkTarget, type ResolvedOperations, type ResolvedPipeline, type ResolvedScheduling, type ResolvedSends, type ResolvedSignupControl, type RoleChangeContext, type Rule, SCHEDULING_DEFAULTS, SIGNUP_CONTROL_PATH, SIGNUP_CONTROL_SCHEMA_VERSION, SIGNUP_CONTROL_THEME_MARKER, SIGNUP_CONTROL_THEME_STYLE_ID, type SchedulingErrors, type SecretMode, type SecretStore, type SessionUser, type SharedBusiness, type SharedPerson, type SharedRecord, type SharedRecordV1, type SharedRecordV2, type SignupControlApplication, type SignupControlDocument, type SignupControlEnvelope, type SignupControlPolicy, type SignupControlReceipt, type SignupControlRejection, type SignupControlTheme, type SignupControlThemeHead, type SignupControlThemeMetadata, type SignupControlThemeOptions, type SignupControlThemeRevision, type SignupControlThemeStyleTarget, type SignupControlTier, type SignupControlValidation, type StripeEvent, type StripeResult, type SubmitResult, type TierGroup, type TierGroupRow, type WebhookEvent, applicantProfile, applicationBookingUpdate, applicationSummary, applyMembershipTierMarkdown, backfillCrm, bookingDecision, brandTokens, bucketSeries, buildGroupSeed, buildTierSeeds, canApprove, canBook, canChangeRole, canTransition, canceledPatch, canonicalSignupControl, chapterBrandFromTokens, chapterDb, clampArray, clerkGetUser, clerkGetUserByEmail, clerkIntegration, clerkInviteRequest, clerkListUsers, clerkSetRole, clerkUserRequest, createChapterIntegration, createClerkInvitation, createClerkUser, createSignupControlEnvelope, dashboardMetricData, defaultCrm, defineChapter, emailGroupFrom, endForSlot, exportChapterPromotion, findApplicationRef, findTier, firstPaymentPatch, formatChapterCopy, formationFields, getVaultSecret, hasDisclaimerAck, hydrateSignupControlTheme, injectSignupControlThemeHead, introIdempotencyKey, isAdminRole, isAlreadySent, isReconcilable, isSlotAvailable, isValidEmail, joinConfig, joinConfigTiers, leaderCrmConfig, loadOfferableTiers, loadTiers, meetingCreateRow, meetingRescheduleUpdate, memberApplication, memberSession, membershipPageDocument, membershipTierPresentationFromMarkdown, networkSourceTag, normalizeSharedRecord, normalizeWebhookEvent, offerableTiers, paymentsReady, personInputFromApp, planDelivery, projectApplicant, projectSharedRecord, reconcileMeetings, refundedPatch, render, renderSignupControlThemeHead, renderSummary, renderTemplateBody, renewalPatch, resolveApplication, resolveAuth, resolveChapterCopy, resolveLeaderFormation, resolvePipeline, resolveScheduling, resolveSignupControl, resolveTiers, roleFromClaim, sendTemplated, sharedPersonInput, sharedRecordFromCrm, signupControlDigest, slotWindow, stageIndex, stripeCall, subAnnualCents, submitApplication, subscriptionIdempotencyKey, syncApplicationToCrm, tierIsFree, tierPayable, updateClerkUserMetadata, updateClerkUserMetadataByEmail, validateMembershipPageDocument, validateScheduling, validateSignupControlDocument, webhookMutationId };
|
package/dist/index.js
CHANGED
|
@@ -2894,12 +2894,18 @@ function themeOf(value, errors) {
|
|
|
2894
2894
|
}
|
|
2895
2895
|
unknownKeys(input, /* @__PURE__ */ new Set(["tokens"]), "document.theme", errors);
|
|
2896
2896
|
if (Object.keys(tokens).length > 256) errors.push("document.theme.tokens supports at most 256 entries");
|
|
2897
|
+
let serializedLength = 0;
|
|
2897
2898
|
for (const [key, token] of Object.entries(tokens)) {
|
|
2898
|
-
if (!/^--[a-z0-9-]{
|
|
2899
|
-
|
|
2900
|
-
|
|
2899
|
+
if (!/^--ui-[a-z0-9][a-z0-9-]{0,94}$/.test(key)) {
|
|
2900
|
+
errors.push(`document.theme.tokens.${key} must be an allowlisted --ui-* custom property`);
|
|
2901
|
+
}
|
|
2902
|
+
const rendered = String(token).trim();
|
|
2903
|
+
serializedLength += key.length + rendered.length + 4;
|
|
2904
|
+
if (typeof token !== "string" && typeof token !== "number" || typeof token === "number" && !Number.isFinite(token) || !rendered || rendered.length > 1e3 || /[\u0000-\u001f\u007f\\<>{};]|\/\*|\*\/|(?:^|[^a-z])(?:url|expression)\s*\(|@import/i.test(rendered)) {
|
|
2905
|
+
errors.push(`document.theme.tokens.${key} must be a bounded breakout-safe CSS value`);
|
|
2901
2906
|
}
|
|
2902
2907
|
}
|
|
2908
|
+
if (serializedLength > 65536) errors.push("document.theme.tokens exceeds the serialized size bound");
|
|
2903
2909
|
return { tokens };
|
|
2904
2910
|
}
|
|
2905
2911
|
function validateSignupControlDocument(input) {
|
|
@@ -2951,6 +2957,116 @@ function validateSignupControlDocument(input) {
|
|
|
2951
2957
|
} };
|
|
2952
2958
|
}
|
|
2953
2959
|
|
|
2960
|
+
// src/signup-control-theme.ts
|
|
2961
|
+
var SIGNUP_CONTROL_THEME_MARKER = "<!--odla:signup-control-theme-->";
|
|
2962
|
+
var SIGNUP_CONTROL_THEME_STYLE_ID = "odla-signup-control-theme";
|
|
2963
|
+
var TOKEN_NAME = /^--ui-[a-z0-9][a-z0-9-]{0,94}$/;
|
|
2964
|
+
var DIGEST = /^sha256:[0-9a-f]{64}$/;
|
|
2965
|
+
var UNSAFE_VALUE = /[\u0000-\u001f\u007f\\<>{};]|\/\*|\*\/|(?:^|[^a-z])(?:url|expression)\s*\(|@import/i;
|
|
2966
|
+
var MAX_TOKENS = 256;
|
|
2967
|
+
var MAX_VALUE_LENGTH = 1e3;
|
|
2968
|
+
var MAX_SERIALIZED_LENGTH = 65536;
|
|
2969
|
+
function validatedTokens(input) {
|
|
2970
|
+
const entries = Object.entries(input ?? {});
|
|
2971
|
+
if (entries.length > MAX_TOKENS) {
|
|
2972
|
+
throw new TypeError(`signup-control theme supports at most ${MAX_TOKENS} tokens`);
|
|
2973
|
+
}
|
|
2974
|
+
const tokens = {};
|
|
2975
|
+
let serializedLength = 0;
|
|
2976
|
+
for (const [name, raw] of entries.sort(([left], [right]) => left.localeCompare(right))) {
|
|
2977
|
+
if (!TOKEN_NAME.test(name)) {
|
|
2978
|
+
throw new TypeError(`signup-control theme token "${name}" must be an allowlisted --ui-* property`);
|
|
2979
|
+
}
|
|
2980
|
+
if (typeof raw !== "string" && typeof raw !== "number" || typeof raw === "number" && !Number.isFinite(raw)) {
|
|
2981
|
+
throw new TypeError(`signup-control theme token "${name}" must be a finite string or number`);
|
|
2982
|
+
}
|
|
2983
|
+
const value = String(raw).trim();
|
|
2984
|
+
if (!value || value.length > MAX_VALUE_LENGTH || UNSAFE_VALUE.test(value)) {
|
|
2985
|
+
throw new TypeError(`signup-control theme token "${name}" has an unsafe or oversized value`);
|
|
2986
|
+
}
|
|
2987
|
+
serializedLength += name.length + value.length + 4;
|
|
2988
|
+
if (serializedLength > MAX_SERIALIZED_LENGTH) {
|
|
2989
|
+
throw new TypeError("signup-control theme exceeds the serialized size bound");
|
|
2990
|
+
}
|
|
2991
|
+
tokens[name] = value;
|
|
2992
|
+
}
|
|
2993
|
+
return tokens;
|
|
2994
|
+
}
|
|
2995
|
+
function cssFor(tokens) {
|
|
2996
|
+
const declarations = Object.entries(tokens).map(([name, value]) => ` ${name}: ${value};`);
|
|
2997
|
+
return declarations.length ? `:root {
|
|
2998
|
+
${declarations.join("\n")}
|
|
2999
|
+
}` : "";
|
|
3000
|
+
}
|
|
3001
|
+
function stateFor(revision, options) {
|
|
3002
|
+
if (!revision) {
|
|
3003
|
+
return {
|
|
3004
|
+
css: cssFor(validatedTokens(options.bootstrapTokens)),
|
|
3005
|
+
metadata: { source: "bootstrap", revision: null, digest: null, cacheKey: "signup-control:bootstrap" }
|
|
3006
|
+
};
|
|
3007
|
+
}
|
|
3008
|
+
if (!Number.isSafeInteger(revision.revision) || revision.revision < 1 || !DIGEST.test(revision.digest)) {
|
|
3009
|
+
throw new TypeError("signup-control theme revision metadata is invalid");
|
|
3010
|
+
}
|
|
3011
|
+
return {
|
|
3012
|
+
css: cssFor(validatedTokens(revision.theme?.tokens)),
|
|
3013
|
+
metadata: {
|
|
3014
|
+
source: "active",
|
|
3015
|
+
revision: revision.revision,
|
|
3016
|
+
digest: revision.digest,
|
|
3017
|
+
cacheKey: `signup-control:${revision.digest}`
|
|
3018
|
+
}
|
|
3019
|
+
};
|
|
3020
|
+
}
|
|
3021
|
+
function attributes(metadata) {
|
|
3022
|
+
return [
|
|
3023
|
+
`id="${SIGNUP_CONTROL_THEME_STYLE_ID}"`,
|
|
3024
|
+
`data-signup-control-source="${metadata.source}"`,
|
|
3025
|
+
`data-signup-control-cache-key="${metadata.cacheKey}"`,
|
|
3026
|
+
...metadata.revision === null ? [] : [`data-signup-control-revision="${metadata.revision}"`],
|
|
3027
|
+
...metadata.digest === null ? [] : [`data-signup-control-digest="${metadata.digest}"`]
|
|
3028
|
+
].join(" ");
|
|
3029
|
+
}
|
|
3030
|
+
function renderSignupControlThemeHead(revision, options = {}) {
|
|
3031
|
+
const { css, metadata } = stateFor(revision, options);
|
|
3032
|
+
return { css, metadata, head: `<style ${attributes(metadata)}>${css}</style>` };
|
|
3033
|
+
}
|
|
3034
|
+
function injectSignupControlThemeHead(html, rendered, marker = SIGNUP_CONTROL_THEME_MARKER) {
|
|
3035
|
+
const existing = /<style\b(?=[^>]*\bid\s*=\s*["']odla-signup-control-theme["'])[^>]*>[\s\S]*?<\/style>/gi;
|
|
3036
|
+
const existingBlocks = html.match(existing) ?? [];
|
|
3037
|
+
if (existingBlocks.length > 1) {
|
|
3038
|
+
throw new TypeError("signup-control theme style block must appear at most once");
|
|
3039
|
+
}
|
|
3040
|
+
if (existingBlocks.length === 1) return html.replace(existing, rendered.head);
|
|
3041
|
+
const markerIndex = html.indexOf(marker);
|
|
3042
|
+
if (markerIndex >= 0) {
|
|
3043
|
+
if (html.indexOf(marker, markerIndex + marker.length) >= 0) {
|
|
3044
|
+
throw new TypeError("signup-control theme marker must appear exactly once");
|
|
3045
|
+
}
|
|
3046
|
+
return `${html.slice(0, markerIndex)}${rendered.head}${html.slice(markerIndex + marker.length)}`;
|
|
3047
|
+
}
|
|
3048
|
+
const closingHead = html.search(/<\/head\s*>/i);
|
|
3049
|
+
if (closingHead < 0) throw new TypeError("signup-control theme requires an HTML head");
|
|
3050
|
+
return `${html.slice(0, closingHead)}${rendered.head}${html.slice(closingHead)}`;
|
|
3051
|
+
}
|
|
3052
|
+
function hydrateSignupControlTheme(target, revision, options = {}) {
|
|
3053
|
+
const next = stateFor(revision, options);
|
|
3054
|
+
const currentSource = target.getAttribute("data-signup-control-source");
|
|
3055
|
+
const currentRevision = target.getAttribute("data-signup-control-revision");
|
|
3056
|
+
const currentDigest = target.getAttribute("data-signup-control-digest");
|
|
3057
|
+
if (currentSource === next.metadata.source && currentRevision === (next.metadata.revision === null ? null : String(next.metadata.revision)) && currentDigest === next.metadata.digest) {
|
|
3058
|
+
return false;
|
|
3059
|
+
}
|
|
3060
|
+
target.textContent = next.css;
|
|
3061
|
+
target.setAttribute("data-signup-control-source", next.metadata.source);
|
|
3062
|
+
target.setAttribute("data-signup-control-cache-key", next.metadata.cacheKey);
|
|
3063
|
+
if (next.metadata.revision === null) target.removeAttribute("data-signup-control-revision");
|
|
3064
|
+
else target.setAttribute("data-signup-control-revision", String(next.metadata.revision));
|
|
3065
|
+
if (next.metadata.digest === null) target.removeAttribute("data-signup-control-digest");
|
|
3066
|
+
else target.setAttribute("data-signup-control-digest", next.metadata.digest);
|
|
3067
|
+
return true;
|
|
3068
|
+
}
|
|
3069
|
+
|
|
2954
3070
|
// src/membership-markdown.ts
|
|
2955
3071
|
var MAX_BENEFITS2 = 24;
|
|
2956
3072
|
var MAX_MARKDOWN2 = 65536;
|
|
@@ -3070,13 +3186,109 @@ function membershipTierPresentationFromMarkdown(presentation, source) {
|
|
|
3070
3186
|
if (!result.ok) throw new TypeError(`Invalid membership Markdown: ${result.errors.join("; ")}`);
|
|
3071
3187
|
return result.value;
|
|
3072
3188
|
}
|
|
3189
|
+
|
|
3190
|
+
// src/promotion.ts
|
|
3191
|
+
import {
|
|
3192
|
+
canonicalPromotionValue
|
|
3193
|
+
} from "@odla-ai/promotion";
|
|
3194
|
+
var CHAPTER_PROMOTION_ADAPTER = "@odla-ai/chapter/v1";
|
|
3195
|
+
var exclusions = (chapterId, paidTierIds) => [
|
|
3196
|
+
{
|
|
3197
|
+
kind: "chapter.providers",
|
|
3198
|
+
id: chapterId,
|
|
3199
|
+
reason: "provider_identity",
|
|
3200
|
+
paths: [
|
|
3201
|
+
...paidTierIds.map((id2) => `tiers[${id2}].stripePriceId`),
|
|
3202
|
+
"groups.stripePublishableKey",
|
|
3203
|
+
"applications.stripeCustomerId",
|
|
3204
|
+
"applications.stripeSubscriptionId",
|
|
3205
|
+
"meetings.googleEventId"
|
|
3206
|
+
],
|
|
3207
|
+
detail: "Stripe, Clerk, and Google identities are resolved independently in each target environment."
|
|
3208
|
+
},
|
|
3209
|
+
{
|
|
3210
|
+
kind: "chapter.runtime",
|
|
3211
|
+
id: chapterId,
|
|
3212
|
+
reason: "runtime_state",
|
|
3213
|
+
paths: ["applications.*", "meetings.*", "emailLog.*", "crm_*.*"],
|
|
3214
|
+
detail: "Applicants, meetings, messages, and CRM rows are operational state, not managed signup content."
|
|
3215
|
+
},
|
|
3216
|
+
{
|
|
3217
|
+
kind: "chapter.access",
|
|
3218
|
+
id: chapterId,
|
|
3219
|
+
reason: "personal_data",
|
|
3220
|
+
paths: ["admins.*", "superAdmins.*", "networkNotes.*"],
|
|
3221
|
+
detail: "People, access lists, and private network notes remain local to the target environment."
|
|
3222
|
+
},
|
|
3223
|
+
{
|
|
3224
|
+
kind: "chapter.history",
|
|
3225
|
+
id: chapterId,
|
|
3226
|
+
reason: "authority_history",
|
|
3227
|
+
paths: ["signupControls[active=false]", "signupControls.*At", "signupControls.environment"],
|
|
3228
|
+
detail: "The source retains immutable delivery history; only selected published content is exported."
|
|
3229
|
+
}
|
|
3230
|
+
];
|
|
3231
|
+
async function exportChapterPromotion(input) {
|
|
3232
|
+
if (!/^sha256:[0-9a-f]{64}$/.test(input.digest)) throw new TypeError("chapter promotion digest is invalid");
|
|
3233
|
+
const checked = validateSignupControlDocument(input.document);
|
|
3234
|
+
if (!checked.ok) throw new TypeError(checked.errors.join("; "));
|
|
3235
|
+
const document = checked.value;
|
|
3236
|
+
if (await signupControlDigest(document) !== input.digest) throw new TypeError("chapter promotion digest does not match its document");
|
|
3237
|
+
const revision = `chapter:${document.target.chapterId}:${document.revision}`;
|
|
3238
|
+
const promotionProvenance = {
|
|
3239
|
+
adapter: CHAPTER_PROMOTION_ADAPTER,
|
|
3240
|
+
sourceIds: [`signup-control:${document.revision}`, document.source.appId, document.target.chapterId].sort(),
|
|
3241
|
+
receiptDigests: [input.digest]
|
|
3242
|
+
};
|
|
3243
|
+
const artifact = (kind, id2, content) => ({
|
|
3244
|
+
kind,
|
|
3245
|
+
id: id2,
|
|
3246
|
+
sourceRevision: revision,
|
|
3247
|
+
provenance: promotionProvenance,
|
|
3248
|
+
content: canonicalPromotionValue(content)
|
|
3249
|
+
});
|
|
3250
|
+
const chapterId = document.target.chapterId;
|
|
3251
|
+
const artifacts = [
|
|
3252
|
+
artifact("chapter.catalog", chapterId, {
|
|
3253
|
+
chapterId,
|
|
3254
|
+
tiers: document.tiers.map(({ stripePriceId: _providerId, ...tier }) => tier)
|
|
3255
|
+
}),
|
|
3256
|
+
artifact("chapter.membership-page", chapterId, document.membershipPage),
|
|
3257
|
+
...document.application ? [artifact("chapter.application", chapterId, document.application)] : [],
|
|
3258
|
+
...document.policy ? [artifact("chapter.policy", chapterId, document.policy)] : [],
|
|
3259
|
+
...document.scheduling ? [artifact("chapter.scheduling", chapterId, document.scheduling)] : [],
|
|
3260
|
+
...document.theme ? [artifact("chapter.theme", chapterId, document.theme)] : []
|
|
3261
|
+
];
|
|
3262
|
+
return {
|
|
3263
|
+
adapter: CHAPTER_PROMOTION_ADAPTER,
|
|
3264
|
+
artifacts,
|
|
3265
|
+
exclusions: exclusions(chapterId, document.tiers.filter((tier) => tier.stripePriceId).map((tier) => tier.id)),
|
|
3266
|
+
preconditions: [
|
|
3267
|
+
{
|
|
3268
|
+
code: "chapter.signup-control.schema",
|
|
3269
|
+
path: "services.chapter.signupControl.schemaVersion",
|
|
3270
|
+
expected: document.schemaVersion,
|
|
3271
|
+
detail: "The target must support this Chapter signup-control document version."
|
|
3272
|
+
},
|
|
3273
|
+
{
|
|
3274
|
+
code: "chapter.identity",
|
|
3275
|
+
path: "app.appId",
|
|
3276
|
+
expected: chapterId,
|
|
3277
|
+
detail: "Chapter content can only target the chapter named by the signed source revision."
|
|
3278
|
+
}
|
|
3279
|
+
]
|
|
3280
|
+
};
|
|
3281
|
+
}
|
|
3073
3282
|
export {
|
|
3283
|
+
CHAPTER_PROMOTION_ADAPTER,
|
|
3074
3284
|
DEFAULT_CHAPTER_COPY,
|
|
3075
3285
|
DEFAULT_SHARE_FIELDS,
|
|
3076
3286
|
MEMBERSHIP_PAGE_RENDERER,
|
|
3077
3287
|
SCHEDULING_DEFAULTS,
|
|
3078
3288
|
SIGNUP_CONTROL_PATH,
|
|
3079
3289
|
SIGNUP_CONTROL_SCHEMA_VERSION,
|
|
3290
|
+
SIGNUP_CONTROL_THEME_MARKER,
|
|
3291
|
+
SIGNUP_CONTROL_THEME_STYLE_ID,
|
|
3080
3292
|
applicantProfile,
|
|
3081
3293
|
applicationBookingUpdate,
|
|
3082
3294
|
applicationSummary,
|
|
@@ -3112,6 +3324,7 @@ export {
|
|
|
3112
3324
|
defineChapter,
|
|
3113
3325
|
emailGroupFrom,
|
|
3114
3326
|
endForSlot,
|
|
3327
|
+
exportChapterPromotion,
|
|
3115
3328
|
findApplicationRef,
|
|
3116
3329
|
findTier,
|
|
3117
3330
|
firstPaymentPatch,
|
|
@@ -3119,6 +3332,8 @@ export {
|
|
|
3119
3332
|
formationFields,
|
|
3120
3333
|
getVaultSecret,
|
|
3121
3334
|
hasDisclaimerAck,
|
|
3335
|
+
hydrateSignupControlTheme,
|
|
3336
|
+
injectSignupControlThemeHead,
|
|
3122
3337
|
introIdempotencyKey,
|
|
3123
3338
|
isAdminRole,
|
|
3124
3339
|
isAlreadySent,
|
|
@@ -3148,6 +3363,7 @@ export {
|
|
|
3148
3363
|
reconcileMeetings,
|
|
3149
3364
|
refundedPatch,
|
|
3150
3365
|
render,
|
|
3366
|
+
renderSignupControlThemeHead,
|
|
3151
3367
|
renderSummary,
|
|
3152
3368
|
renderTemplateBody,
|
|
3153
3369
|
renewalPatch,
|