@odla-ai/chapter 0.26.1 → 0.27.1
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 +51 -3
- package/dist/{chunk-QBTFQUDL.js → chunk-IOHVFBXH.js} +2 -2
- package/dist/{chunk-OIWCKF2G.js → chunk-JAWTIROV.js} +2 -1
- package/dist/chunk-JAWTIROV.js.map +1 -0
- package/dist/{chunk-4QZEAWQL.js → chunk-L2SA47IO.js} +434 -79
- package/dist/chunk-L2SA47IO.js.map +1 -0
- package/dist/{copy-context-Vof2eTMt.d.ts → copy-context-efEMF_aD.d.ts} +33 -5
- package/dist/index.cjs +90 -6
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +84 -11
- package/dist/index.d.ts +84 -11
- package/dist/index.js +90 -6
- package/dist/index.js.map +1 -1
- package/dist/ui/admin/index.d.ts +12 -3
- package/dist/ui/admin/index.js +6 -2
- package/dist/ui/index.d.ts +2 -2
- package/dist/ui/index.js +7 -3
- package/dist/ui/member/index.d.ts +2 -2
- package/dist/ui/member/index.js +2 -2
- package/dist/worker/index.cjs +424 -16
- package/dist/worker/index.cjs.map +1 -1
- package/dist/worker/index.d.cts +35 -7
- package/dist/worker/index.d.ts +35 -7
- package/dist/worker/index.js +426 -14
- package/dist/worker/index.js.map +1 -1
- package/package.json +1 -1
- package/dist/chunk-4QZEAWQL.js.map +0 -1
- package/dist/chunk-OIWCKF2G.js.map +0 -1
- /package/dist/{chunk-QBTFQUDL.js.map → chunk-IOHVFBXH.js.map} +0 -0
package/dist/index.d.cts
CHANGED
|
@@ -42,7 +42,7 @@ interface ChapterCopy {
|
|
|
42
42
|
admin: {
|
|
43
43
|
auth: TextFields<"checking" | "notAuthorized" | "accountNotAuthorized" | "thisAccount" | "signOut" | "loading" | "signInNotConfigured" | "missingPublishableKey" | "noWorkspaces" | "signInTagline">;
|
|
44
44
|
shell: TextFields<"adminRole" | "adminConsole" | "adminName" | "navigationLabel">;
|
|
45
|
-
workspaces: TextFields<"dashboard" | "overview" | "billing" | "people" | "portfolio" | "settings" | "calendar" | "email" | "chapters" | "formations" | "dealFlow" | "dashboardViewsLabel" | "settingsViewsLabel" | "collectionsLabel" | "portfolioViewsLabel">;
|
|
45
|
+
workspaces: TextFields<"dashboard" | "overview" | "billing" | "people" | "network" | "portfolio" | "settings" | "calendar" | "email" | "chapters" | "formations" | "dealFlow" | "dashboardViewsLabel" | "settingsViewsLabel" | "collectionsLabel" | "portfolioViewsLabel">;
|
|
46
46
|
dashboard: TextFields<"loading" | "loadFailed" | "upcomingCalls" | "callsNeedAttention" | "noUpcomingCalls" | "drift" | "open" | "meet" | "applications" | "newMembers" | "newMembersUnavailable" | "revenueAdded" | "revenue" | "revenueUnavailable" | "pipeline" | "pipelineLabel" | "thisWeek" | "noChange" | "activeMemberships" | "annualRunRate" | "testMode">;
|
|
47
47
|
billing: TextFields<"loading" | "loadFailed" | "notConfigured" | "active" | "annualized" | "renewingSoon" | "pastDue" | "subscriptions" | "testMode" | "truncated" | "name" | "email" | "application" | "subscription" | "cancelling" | "amount" | "renews">;
|
|
48
48
|
availability: TextFields<"loading" | "loadFailed" | "saved" | "title" | "days" | "startHour" | "endHour" | "slotMinutes" | "minNoticeHours" | "windowDays" | "timezone" | "summaryTemplate" | "save"> & {
|
|
@@ -80,11 +80,31 @@ interface ChapterNetworkTarget {
|
|
|
80
80
|
/** Per-record-type field allowlist. If present, omitted types cannot be sent
|
|
81
81
|
* to this target. Without it, package-safe person/company defaults apply. */
|
|
82
82
|
fields?: Record<string, readonly string[]>;
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
83
|
+
/** Record types on which leader admins may deliberately share notes with
|
|
84
|
+
* this follower. Omitted by default: a target never gains write permission
|
|
85
|
+
* merely because its records are browsable. */
|
|
86
|
+
sharedNotes?: readonly string[];
|
|
87
|
+
}
|
|
88
|
+
/** One signed peer allowed to browse a privacy-bounded projection of this
|
|
89
|
+
* site's CRM. The follower owns this allowlist; a leader target declaration
|
|
90
|
+
* cannot widen it. */
|
|
91
|
+
interface ChapterNetworkReader {
|
|
92
|
+
/** Stable app/site slug expected in the signed federation envelope. */
|
|
93
|
+
id: string;
|
|
94
|
+
/** Per-record-type field allowlist. Omitted types and fields never leave
|
|
95
|
+
* this site. Record id, name, stage, and timestamps are bounded metadata. */
|
|
96
|
+
fields: Record<string, readonly string[]>;
|
|
97
|
+
/** Record types on which this reader may append an explicitly shared note.
|
|
98
|
+
* Omitted by default: browse permission never silently grants write access.
|
|
99
|
+
* Shared notes land in the follower CRM activity feed. */
|
|
100
|
+
sharedNotes?: readonly string[];
|
|
101
|
+
}
|
|
102
|
+
/** Leader/follower network configuration. A follower needs no code config to
|
|
103
|
+
* receive pushed records. It must explicitly declare `readers` before any peer
|
|
104
|
+
* can browse its CRM. */
|
|
86
105
|
interface ChapterNetwork {
|
|
87
106
|
targets?: readonly ChapterNetworkTarget[];
|
|
107
|
+
readers?: readonly ChapterNetworkReader[];
|
|
88
108
|
}
|
|
89
109
|
/** Public chapter-formation intake backed by one CRM record type. The host owns
|
|
90
110
|
* the branded form; Chapter owns the bounded, idempotent write contract. */
|
|
@@ -119,10 +139,18 @@ interface ResolvedNetworkTarget {
|
|
|
119
139
|
binding?: string;
|
|
120
140
|
secretName: string;
|
|
121
141
|
fields?: Record<string, readonly string[]>;
|
|
142
|
+
sharedNotes: readonly string[];
|
|
143
|
+
}
|
|
144
|
+
/** A validated follower-owned record projection for one signed reader. */
|
|
145
|
+
interface ResolvedNetworkReader {
|
|
146
|
+
id: string;
|
|
147
|
+
fields: Record<string, readonly string[]>;
|
|
148
|
+
sharedNotes: readonly string[];
|
|
122
149
|
}
|
|
123
150
|
/** Fully-resolved leader network configuration. */
|
|
124
151
|
interface ResolvedNetwork {
|
|
125
152
|
targets: readonly ResolvedNetworkTarget[];
|
|
153
|
+
readers: readonly ResolvedNetworkReader[];
|
|
126
154
|
}
|
|
127
155
|
|
|
128
156
|
/** Which feature profile a site runs. `chapter` is the full public member site
|
|
@@ -405,8 +433,8 @@ interface ChapterConfig {
|
|
|
405
433
|
/** User-visible language for packaged Chapter surfaces. Recursively partial;
|
|
406
434
|
* `defineChapter()` resolves every omitted leaf from the package defaults. */
|
|
407
435
|
copy?: ChapterCopyInput;
|
|
408
|
-
/**
|
|
409
|
-
*
|
|
436
|
+
/** Signed network edges: leader delivery targets and follower-owned,
|
|
437
|
+
* privacy-bounded record readers. Secret values stay in tenant vaults. */
|
|
410
438
|
network?: ChapterNetwork;
|
|
411
439
|
/** Enable a public, host-rendered formation application workflow. */
|
|
412
440
|
formation?: LeaderFormationConfig;
|
|
@@ -589,9 +617,8 @@ interface ChapterIntegrationDescriptor {
|
|
|
589
617
|
}>;
|
|
590
618
|
/** Runbooks that bear on THIS chapter's role, so tooling can point at the
|
|
591
619
|
* right procedure without the operator knowing it exists. A chapter declaring
|
|
592
|
-
* `network.targets` is a leader hub; one
|
|
593
|
-
* and
|
|
594
|
-
* "share records"). */
|
|
620
|
+
* `network.targets` is a leader hub; one with no targets is a follower site
|
|
621
|
+
* (and may declare `network.readers` for bounded CRM browsing). */
|
|
595
622
|
runbooks: ChapterRunbookHints;
|
|
596
623
|
}
|
|
597
624
|
/** Which runbooks apply, and why. */
|
|
@@ -618,7 +645,7 @@ declare function createChapterIntegration(chapter: Chapter, options?: ChapterInt
|
|
|
618
645
|
* read-only super-admin tier (default on for the `"claim"` ladder). A `"claim"`
|
|
619
646
|
* chapter therefore emits the reference namespace set — `applications`,
|
|
620
647
|
* `groups`, `meetings`, `emailLog`, `superAdmins` — with no `admins` table. */
|
|
621
|
-
declare function chapterDb(mode: ChapterMode, auth: ResolvedAuth): {
|
|
648
|
+
declare function chapterDb(mode: ChapterMode, auth: ResolvedAuth, includeNetworkNotes?: boolean): {
|
|
622
649
|
schema: DbSchema;
|
|
623
650
|
rules: DbRules;
|
|
624
651
|
};
|
|
@@ -1070,6 +1097,52 @@ interface NetworkRollup {
|
|
|
1070
1097
|
}>;
|
|
1071
1098
|
targets: NetworkRollupTarget[];
|
|
1072
1099
|
}
|
|
1100
|
+
/** Privacy-bounded CRM record returned by a follower to one configured,
|
|
1101
|
+
* authenticated reader. */
|
|
1102
|
+
interface NetworkRecord {
|
|
1103
|
+
id: string;
|
|
1104
|
+
type: string;
|
|
1105
|
+
name: string;
|
|
1106
|
+
stage?: string;
|
|
1107
|
+
fields: Record<string, unknown>;
|
|
1108
|
+
createdAt: number;
|
|
1109
|
+
updatedAt: number;
|
|
1110
|
+
}
|
|
1111
|
+
/** One bounded, offset-paged follower record window. */
|
|
1112
|
+
interface NetworkRecordPage {
|
|
1113
|
+
version: 1;
|
|
1114
|
+
site: {
|
|
1115
|
+
id: string;
|
|
1116
|
+
name: string;
|
|
1117
|
+
};
|
|
1118
|
+
type: string;
|
|
1119
|
+
records: NetworkRecord[];
|
|
1120
|
+
total: number;
|
|
1121
|
+
limit: number;
|
|
1122
|
+
offset: number;
|
|
1123
|
+
}
|
|
1124
|
+
/** Leader-private note attached to a stable remote record identity. */
|
|
1125
|
+
interface NetworkRecordNote {
|
|
1126
|
+
id: string;
|
|
1127
|
+
targetId: string;
|
|
1128
|
+
recordType: string;
|
|
1129
|
+
recordId: string;
|
|
1130
|
+
body: string;
|
|
1131
|
+
authorId: string;
|
|
1132
|
+
authorEmail?: string;
|
|
1133
|
+
createdAt: number;
|
|
1134
|
+
}
|
|
1135
|
+
/** A note deliberately shared across the federation edge and stored in the
|
|
1136
|
+
* follower CRM activity feed. Unlike NetworkRecordNote, this is visible to
|
|
1137
|
+
* the follower's own CRM admins. */
|
|
1138
|
+
interface NetworkSharedNote {
|
|
1139
|
+
id: string;
|
|
1140
|
+
sourceId: string;
|
|
1141
|
+
recordType: string;
|
|
1142
|
+
recordId: string;
|
|
1143
|
+
body: string;
|
|
1144
|
+
createdAt: number;
|
|
1145
|
+
}
|
|
1073
1146
|
interface NormalizedSharedRecord {
|
|
1074
1147
|
version: 1 | 2;
|
|
1075
1148
|
sourceId: string;
|
|
@@ -1636,4 +1709,4 @@ type ApplicationBookingPatch = {
|
|
|
1636
1709
|
* already there (never backward). */
|
|
1637
1710
|
declare function applicationBookingUpdate(currentStatus: string, startAt: number, htmlLink?: string | null): ApplicationBookingPatch;
|
|
1638
1711
|
|
|
1639
|
-
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 ChapterCopy, type ChapterCopyInput, type ChapterDb, type ChapterEmails, type ChapterIntegrationDescriptor, type ChapterIntegrationOptions, type ChapterMode, type ChapterNetwork, type ChapterNetworkTarget, type ChapterOperations, type ChapterPipeline, type ChapterPolicy, type ChapterPrices, type ChapterRunbookHints, type ChapterScheduling, type ChapterSends, 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 LeaderCrmOptions, type LeaderFormationConfig, type LiveEvent, type MailSender, type MeetingForReconcile, type MeetingRecord, type MeetingReschedulePatch, type MemberApplication, type MemberSession, type NetworkRollup, type NetworkRollupTarget, 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 ResolvedNetworkTarget, type ResolvedOperations, type ResolvedPipeline, type ResolvedScheduling, type ResolvedSends, type RoleChangeContext, type Rule, SCHEDULING_DEFAULTS, type SchedulingErrors, type SecretMode, type SecretStore, type SessionUser, type SharedBusiness, type SharedPerson, type SharedRecord, type SharedRecordV1, type SharedRecordV2, type StripeEvent, type StripeResult, type SubmitResult, type WebhookEvent, applicantProfile, applicationBookingUpdate, applicationSummary, backfillCrm, bookingDecision, brandTokens, bucketSeries, buildGroupSeed, canApprove, canBook, canChangeRole, canTransition, canceledPatch, chapterBrandFromTokens, chapterDb, clampArray, clerkGetUser, clerkGetUserByEmail, clerkIntegration, clerkInviteRequest, clerkListUsers, clerkSetRole, clerkUserRequest, createChapterIntegration, createClerkInvitation, createClerkUser, dashboardMetricData, defaultCrm, defineChapter, emailGroupFrom, endForSlot, findApplicationRef, firstPaymentPatch, formatChapterCopy, formationFields, getVaultSecret, hasDisclaimerAck, introIdempotencyKey, isAdminRole, isAlreadySent, isReconcilable, isSlotAvailable, isValidEmail, joinConfig, leaderCrmConfig, meetingCreateRow, meetingRescheduleUpdate, memberApplication, memberSession, networkSourceTag, normalizeSharedRecord, normalizeWebhookEvent, paymentsReady, personInputFromApp, planDelivery, projectApplicant, projectSharedRecord, reconcileMeetings, refundedPatch, render, renderSummary, renderTemplateBody, renewalPatch, resolveApplication, resolveAuth, resolveChapterCopy, resolveLeaderFormation, resolvePipeline, resolveScheduling, roleFromClaim, sendTemplated, sharedPersonInput, sharedRecordFromCrm, slotWindow, stageIndex, stripeCall, stripeForm, subAnnualCents, submitApplication, subscriptionIdempotencyKey, syncApplicationToCrm, updateClerkUserMetadata, updateClerkUserMetadataByEmail, validateScheduling, verifyStripeSignature, webhookMutationId };
|
|
1712
|
+
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 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 ChapterRunbookHints, type ChapterScheduling, type ChapterSends, 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 LeaderCrmOptions, type LeaderFormationConfig, type LiveEvent, type MailSender, type MeetingForReconcile, type MeetingRecord, type MeetingReschedulePatch, type MemberApplication, type MemberSession, 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 RoleChangeContext, type Rule, SCHEDULING_DEFAULTS, type SchedulingErrors, type SecretMode, type SecretStore, type SessionUser, type SharedBusiness, type SharedPerson, type SharedRecord, type SharedRecordV1, type SharedRecordV2, type StripeEvent, type StripeResult, type SubmitResult, type WebhookEvent, applicantProfile, applicationBookingUpdate, applicationSummary, backfillCrm, bookingDecision, brandTokens, bucketSeries, buildGroupSeed, canApprove, canBook, canChangeRole, canTransition, canceledPatch, chapterBrandFromTokens, chapterDb, clampArray, clerkGetUser, clerkGetUserByEmail, clerkIntegration, clerkInviteRequest, clerkListUsers, clerkSetRole, clerkUserRequest, createChapterIntegration, createClerkInvitation, createClerkUser, dashboardMetricData, defaultCrm, defineChapter, emailGroupFrom, endForSlot, findApplicationRef, firstPaymentPatch, formatChapterCopy, formationFields, getVaultSecret, hasDisclaimerAck, introIdempotencyKey, isAdminRole, isAlreadySent, isReconcilable, isSlotAvailable, isValidEmail, joinConfig, leaderCrmConfig, meetingCreateRow, meetingRescheduleUpdate, memberApplication, memberSession, networkSourceTag, normalizeSharedRecord, normalizeWebhookEvent, paymentsReady, personInputFromApp, planDelivery, projectApplicant, projectSharedRecord, reconcileMeetings, refundedPatch, render, renderSummary, renderTemplateBody, renewalPatch, resolveApplication, resolveAuth, resolveChapterCopy, resolveLeaderFormation, resolvePipeline, resolveScheduling, roleFromClaim, sendTemplated, sharedPersonInput, sharedRecordFromCrm, slotWindow, stageIndex, stripeCall, stripeForm, subAnnualCents, submitApplication, subscriptionIdempotencyKey, syncApplicationToCrm, updateClerkUserMetadata, updateClerkUserMetadataByEmail, validateScheduling, verifyStripeSignature, webhookMutationId };
|
package/dist/index.d.ts
CHANGED
|
@@ -42,7 +42,7 @@ interface ChapterCopy {
|
|
|
42
42
|
admin: {
|
|
43
43
|
auth: TextFields<"checking" | "notAuthorized" | "accountNotAuthorized" | "thisAccount" | "signOut" | "loading" | "signInNotConfigured" | "missingPublishableKey" | "noWorkspaces" | "signInTagline">;
|
|
44
44
|
shell: TextFields<"adminRole" | "adminConsole" | "adminName" | "navigationLabel">;
|
|
45
|
-
workspaces: TextFields<"dashboard" | "overview" | "billing" | "people" | "portfolio" | "settings" | "calendar" | "email" | "chapters" | "formations" | "dealFlow" | "dashboardViewsLabel" | "settingsViewsLabel" | "collectionsLabel" | "portfolioViewsLabel">;
|
|
45
|
+
workspaces: TextFields<"dashboard" | "overview" | "billing" | "people" | "network" | "portfolio" | "settings" | "calendar" | "email" | "chapters" | "formations" | "dealFlow" | "dashboardViewsLabel" | "settingsViewsLabel" | "collectionsLabel" | "portfolioViewsLabel">;
|
|
46
46
|
dashboard: TextFields<"loading" | "loadFailed" | "upcomingCalls" | "callsNeedAttention" | "noUpcomingCalls" | "drift" | "open" | "meet" | "applications" | "newMembers" | "newMembersUnavailable" | "revenueAdded" | "revenue" | "revenueUnavailable" | "pipeline" | "pipelineLabel" | "thisWeek" | "noChange" | "activeMemberships" | "annualRunRate" | "testMode">;
|
|
47
47
|
billing: TextFields<"loading" | "loadFailed" | "notConfigured" | "active" | "annualized" | "renewingSoon" | "pastDue" | "subscriptions" | "testMode" | "truncated" | "name" | "email" | "application" | "subscription" | "cancelling" | "amount" | "renews">;
|
|
48
48
|
availability: TextFields<"loading" | "loadFailed" | "saved" | "title" | "days" | "startHour" | "endHour" | "slotMinutes" | "minNoticeHours" | "windowDays" | "timezone" | "summaryTemplate" | "save"> & {
|
|
@@ -80,11 +80,31 @@ interface ChapterNetworkTarget {
|
|
|
80
80
|
/** Per-record-type field allowlist. If present, omitted types cannot be sent
|
|
81
81
|
* to this target. Without it, package-safe person/company defaults apply. */
|
|
82
82
|
fields?: Record<string, readonly string[]>;
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
83
|
+
/** Record types on which leader admins may deliberately share notes with
|
|
84
|
+
* this follower. Omitted by default: a target never gains write permission
|
|
85
|
+
* merely because its records are browsable. */
|
|
86
|
+
sharedNotes?: readonly string[];
|
|
87
|
+
}
|
|
88
|
+
/** One signed peer allowed to browse a privacy-bounded projection of this
|
|
89
|
+
* site's CRM. The follower owns this allowlist; a leader target declaration
|
|
90
|
+
* cannot widen it. */
|
|
91
|
+
interface ChapterNetworkReader {
|
|
92
|
+
/** Stable app/site slug expected in the signed federation envelope. */
|
|
93
|
+
id: string;
|
|
94
|
+
/** Per-record-type field allowlist. Omitted types and fields never leave
|
|
95
|
+
* this site. Record id, name, stage, and timestamps are bounded metadata. */
|
|
96
|
+
fields: Record<string, readonly string[]>;
|
|
97
|
+
/** Record types on which this reader may append an explicitly shared note.
|
|
98
|
+
* Omitted by default: browse permission never silently grants write access.
|
|
99
|
+
* Shared notes land in the follower CRM activity feed. */
|
|
100
|
+
sharedNotes?: readonly string[];
|
|
101
|
+
}
|
|
102
|
+
/** Leader/follower network configuration. A follower needs no code config to
|
|
103
|
+
* receive pushed records. It must explicitly declare `readers` before any peer
|
|
104
|
+
* can browse its CRM. */
|
|
86
105
|
interface ChapterNetwork {
|
|
87
106
|
targets?: readonly ChapterNetworkTarget[];
|
|
107
|
+
readers?: readonly ChapterNetworkReader[];
|
|
88
108
|
}
|
|
89
109
|
/** Public chapter-formation intake backed by one CRM record type. The host owns
|
|
90
110
|
* the branded form; Chapter owns the bounded, idempotent write contract. */
|
|
@@ -119,10 +139,18 @@ interface ResolvedNetworkTarget {
|
|
|
119
139
|
binding?: string;
|
|
120
140
|
secretName: string;
|
|
121
141
|
fields?: Record<string, readonly string[]>;
|
|
142
|
+
sharedNotes: readonly string[];
|
|
143
|
+
}
|
|
144
|
+
/** A validated follower-owned record projection for one signed reader. */
|
|
145
|
+
interface ResolvedNetworkReader {
|
|
146
|
+
id: string;
|
|
147
|
+
fields: Record<string, readonly string[]>;
|
|
148
|
+
sharedNotes: readonly string[];
|
|
122
149
|
}
|
|
123
150
|
/** Fully-resolved leader network configuration. */
|
|
124
151
|
interface ResolvedNetwork {
|
|
125
152
|
targets: readonly ResolvedNetworkTarget[];
|
|
153
|
+
readers: readonly ResolvedNetworkReader[];
|
|
126
154
|
}
|
|
127
155
|
|
|
128
156
|
/** Which feature profile a site runs. `chapter` is the full public member site
|
|
@@ -405,8 +433,8 @@ interface ChapterConfig {
|
|
|
405
433
|
/** User-visible language for packaged Chapter surfaces. Recursively partial;
|
|
406
434
|
* `defineChapter()` resolves every omitted leaf from the package defaults. */
|
|
407
435
|
copy?: ChapterCopyInput;
|
|
408
|
-
/**
|
|
409
|
-
*
|
|
436
|
+
/** Signed network edges: leader delivery targets and follower-owned,
|
|
437
|
+
* privacy-bounded record readers. Secret values stay in tenant vaults. */
|
|
410
438
|
network?: ChapterNetwork;
|
|
411
439
|
/** Enable a public, host-rendered formation application workflow. */
|
|
412
440
|
formation?: LeaderFormationConfig;
|
|
@@ -589,9 +617,8 @@ interface ChapterIntegrationDescriptor {
|
|
|
589
617
|
}>;
|
|
590
618
|
/** Runbooks that bear on THIS chapter's role, so tooling can point at the
|
|
591
619
|
* right procedure without the operator knowing it exists. A chapter declaring
|
|
592
|
-
* `network.targets` is a leader hub; one
|
|
593
|
-
* and
|
|
594
|
-
* "share records"). */
|
|
620
|
+
* `network.targets` is a leader hub; one with no targets is a follower site
|
|
621
|
+
* (and may declare `network.readers` for bounded CRM browsing). */
|
|
595
622
|
runbooks: ChapterRunbookHints;
|
|
596
623
|
}
|
|
597
624
|
/** Which runbooks apply, and why. */
|
|
@@ -618,7 +645,7 @@ declare function createChapterIntegration(chapter: Chapter, options?: ChapterInt
|
|
|
618
645
|
* read-only super-admin tier (default on for the `"claim"` ladder). A `"claim"`
|
|
619
646
|
* chapter therefore emits the reference namespace set — `applications`,
|
|
620
647
|
* `groups`, `meetings`, `emailLog`, `superAdmins` — with no `admins` table. */
|
|
621
|
-
declare function chapterDb(mode: ChapterMode, auth: ResolvedAuth): {
|
|
648
|
+
declare function chapterDb(mode: ChapterMode, auth: ResolvedAuth, includeNetworkNotes?: boolean): {
|
|
622
649
|
schema: DbSchema;
|
|
623
650
|
rules: DbRules;
|
|
624
651
|
};
|
|
@@ -1070,6 +1097,52 @@ interface NetworkRollup {
|
|
|
1070
1097
|
}>;
|
|
1071
1098
|
targets: NetworkRollupTarget[];
|
|
1072
1099
|
}
|
|
1100
|
+
/** Privacy-bounded CRM record returned by a follower to one configured,
|
|
1101
|
+
* authenticated reader. */
|
|
1102
|
+
interface NetworkRecord {
|
|
1103
|
+
id: string;
|
|
1104
|
+
type: string;
|
|
1105
|
+
name: string;
|
|
1106
|
+
stage?: string;
|
|
1107
|
+
fields: Record<string, unknown>;
|
|
1108
|
+
createdAt: number;
|
|
1109
|
+
updatedAt: number;
|
|
1110
|
+
}
|
|
1111
|
+
/** One bounded, offset-paged follower record window. */
|
|
1112
|
+
interface NetworkRecordPage {
|
|
1113
|
+
version: 1;
|
|
1114
|
+
site: {
|
|
1115
|
+
id: string;
|
|
1116
|
+
name: string;
|
|
1117
|
+
};
|
|
1118
|
+
type: string;
|
|
1119
|
+
records: NetworkRecord[];
|
|
1120
|
+
total: number;
|
|
1121
|
+
limit: number;
|
|
1122
|
+
offset: number;
|
|
1123
|
+
}
|
|
1124
|
+
/** Leader-private note attached to a stable remote record identity. */
|
|
1125
|
+
interface NetworkRecordNote {
|
|
1126
|
+
id: string;
|
|
1127
|
+
targetId: string;
|
|
1128
|
+
recordType: string;
|
|
1129
|
+
recordId: string;
|
|
1130
|
+
body: string;
|
|
1131
|
+
authorId: string;
|
|
1132
|
+
authorEmail?: string;
|
|
1133
|
+
createdAt: number;
|
|
1134
|
+
}
|
|
1135
|
+
/** A note deliberately shared across the federation edge and stored in the
|
|
1136
|
+
* follower CRM activity feed. Unlike NetworkRecordNote, this is visible to
|
|
1137
|
+
* the follower's own CRM admins. */
|
|
1138
|
+
interface NetworkSharedNote {
|
|
1139
|
+
id: string;
|
|
1140
|
+
sourceId: string;
|
|
1141
|
+
recordType: string;
|
|
1142
|
+
recordId: string;
|
|
1143
|
+
body: string;
|
|
1144
|
+
createdAt: number;
|
|
1145
|
+
}
|
|
1073
1146
|
interface NormalizedSharedRecord {
|
|
1074
1147
|
version: 1 | 2;
|
|
1075
1148
|
sourceId: string;
|
|
@@ -1636,4 +1709,4 @@ type ApplicationBookingPatch = {
|
|
|
1636
1709
|
* already there (never backward). */
|
|
1637
1710
|
declare function applicationBookingUpdate(currentStatus: string, startAt: number, htmlLink?: string | null): ApplicationBookingPatch;
|
|
1638
1711
|
|
|
1639
|
-
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 ChapterCopy, type ChapterCopyInput, type ChapterDb, type ChapterEmails, type ChapterIntegrationDescriptor, type ChapterIntegrationOptions, type ChapterMode, type ChapterNetwork, type ChapterNetworkTarget, type ChapterOperations, type ChapterPipeline, type ChapterPolicy, type ChapterPrices, type ChapterRunbookHints, type ChapterScheduling, type ChapterSends, 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 LeaderCrmOptions, type LeaderFormationConfig, type LiveEvent, type MailSender, type MeetingForReconcile, type MeetingRecord, type MeetingReschedulePatch, type MemberApplication, type MemberSession, type NetworkRollup, type NetworkRollupTarget, 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 ResolvedNetworkTarget, type ResolvedOperations, type ResolvedPipeline, type ResolvedScheduling, type ResolvedSends, type RoleChangeContext, type Rule, SCHEDULING_DEFAULTS, type SchedulingErrors, type SecretMode, type SecretStore, type SessionUser, type SharedBusiness, type SharedPerson, type SharedRecord, type SharedRecordV1, type SharedRecordV2, type StripeEvent, type StripeResult, type SubmitResult, type WebhookEvent, applicantProfile, applicationBookingUpdate, applicationSummary, backfillCrm, bookingDecision, brandTokens, bucketSeries, buildGroupSeed, canApprove, canBook, canChangeRole, canTransition, canceledPatch, chapterBrandFromTokens, chapterDb, clampArray, clerkGetUser, clerkGetUserByEmail, clerkIntegration, clerkInviteRequest, clerkListUsers, clerkSetRole, clerkUserRequest, createChapterIntegration, createClerkInvitation, createClerkUser, dashboardMetricData, defaultCrm, defineChapter, emailGroupFrom, endForSlot, findApplicationRef, firstPaymentPatch, formatChapterCopy, formationFields, getVaultSecret, hasDisclaimerAck, introIdempotencyKey, isAdminRole, isAlreadySent, isReconcilable, isSlotAvailable, isValidEmail, joinConfig, leaderCrmConfig, meetingCreateRow, meetingRescheduleUpdate, memberApplication, memberSession, networkSourceTag, normalizeSharedRecord, normalizeWebhookEvent, paymentsReady, personInputFromApp, planDelivery, projectApplicant, projectSharedRecord, reconcileMeetings, refundedPatch, render, renderSummary, renderTemplateBody, renewalPatch, resolveApplication, resolveAuth, resolveChapterCopy, resolveLeaderFormation, resolvePipeline, resolveScheduling, roleFromClaim, sendTemplated, sharedPersonInput, sharedRecordFromCrm, slotWindow, stageIndex, stripeCall, stripeForm, subAnnualCents, submitApplication, subscriptionIdempotencyKey, syncApplicationToCrm, updateClerkUserMetadata, updateClerkUserMetadataByEmail, validateScheduling, verifyStripeSignature, webhookMutationId };
|
|
1712
|
+
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 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 ChapterRunbookHints, type ChapterScheduling, type ChapterSends, 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 LeaderCrmOptions, type LeaderFormationConfig, type LiveEvent, type MailSender, type MeetingForReconcile, type MeetingRecord, type MeetingReschedulePatch, type MemberApplication, type MemberSession, 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 RoleChangeContext, type Rule, SCHEDULING_DEFAULTS, type SchedulingErrors, type SecretMode, type SecretStore, type SessionUser, type SharedBusiness, type SharedPerson, type SharedRecord, type SharedRecordV1, type SharedRecordV2, type StripeEvent, type StripeResult, type SubmitResult, type WebhookEvent, applicantProfile, applicationBookingUpdate, applicationSummary, backfillCrm, bookingDecision, brandTokens, bucketSeries, buildGroupSeed, canApprove, canBook, canChangeRole, canTransition, canceledPatch, chapterBrandFromTokens, chapterDb, clampArray, clerkGetUser, clerkGetUserByEmail, clerkIntegration, clerkInviteRequest, clerkListUsers, clerkSetRole, clerkUserRequest, createChapterIntegration, createClerkInvitation, createClerkUser, dashboardMetricData, defaultCrm, defineChapter, emailGroupFrom, endForSlot, findApplicationRef, firstPaymentPatch, formatChapterCopy, formationFields, getVaultSecret, hasDisclaimerAck, introIdempotencyKey, isAdminRole, isAlreadySent, isReconcilable, isSlotAvailable, isValidEmail, joinConfig, leaderCrmConfig, meetingCreateRow, meetingRescheduleUpdate, memberApplication, memberSession, networkSourceTag, normalizeSharedRecord, normalizeWebhookEvent, paymentsReady, personInputFromApp, planDelivery, projectApplicant, projectSharedRecord, reconcileMeetings, refundedPatch, render, renderSummary, renderTemplateBody, renewalPatch, resolveApplication, resolveAuth, resolveChapterCopy, resolveLeaderFormation, resolvePipeline, resolveScheduling, roleFromClaim, sendTemplated, sharedPersonInput, sharedRecordFromCrm, slotWindow, stageIndex, stripeCall, stripeForm, subAnnualCents, submitApplication, subscriptionIdempotencyKey, syncApplicationToCrm, updateClerkUserMetadata, updateClerkUserMetadataByEmail, validateScheduling, verifyStripeSignature, webhookMutationId };
|
package/dist/index.js
CHANGED
|
@@ -27,6 +27,19 @@ var superAdmins = {
|
|
|
27
27
|
createdAt: attr("number", { indexed: true })
|
|
28
28
|
}
|
|
29
29
|
};
|
|
30
|
+
var networkNotes = {
|
|
31
|
+
attrs: {
|
|
32
|
+
id: id(),
|
|
33
|
+
recordKey: attr("string", { indexed: true }),
|
|
34
|
+
targetId: attr("string", { indexed: true }),
|
|
35
|
+
recordType: attr("string", { indexed: true }),
|
|
36
|
+
recordId: attr("string", { indexed: true }),
|
|
37
|
+
body: attr("string"),
|
|
38
|
+
authorId: attr("string", { indexed: true }),
|
|
39
|
+
authorEmail: attr("string", { optional: true }),
|
|
40
|
+
createdAt: attr("number", { indexed: true })
|
|
41
|
+
}
|
|
42
|
+
};
|
|
30
43
|
var applications = {
|
|
31
44
|
attrs: {
|
|
32
45
|
id: id(),
|
|
@@ -118,7 +131,7 @@ var emailLog = {
|
|
|
118
131
|
sentAt: attr("number", { indexed: true })
|
|
119
132
|
}
|
|
120
133
|
};
|
|
121
|
-
function chapterDb(mode, auth) {
|
|
134
|
+
function chapterDb(mode, auth, includeNetworkNotes = false) {
|
|
122
135
|
const entities = {};
|
|
123
136
|
if (mode === "chapter") {
|
|
124
137
|
entities.applications = applications;
|
|
@@ -128,6 +141,7 @@ function chapterDb(mode, auth) {
|
|
|
128
141
|
}
|
|
129
142
|
if (auth.source === "table") entities.admins = admins;
|
|
130
143
|
if (auth.superAdmins) entities.superAdmins = superAdmins;
|
|
144
|
+
if (includeNetworkNotes) entities.networkNotes = networkNotes;
|
|
131
145
|
const schema = { entities, links: {} };
|
|
132
146
|
const rules = {};
|
|
133
147
|
for (const ns of Object.keys(entities)) {
|
|
@@ -519,6 +533,7 @@ var DEFAULT_ADMIN_COPY = {
|
|
|
519
533
|
overview: "Overview",
|
|
520
534
|
billing: "Billing",
|
|
521
535
|
people: "People",
|
|
536
|
+
network: "Network",
|
|
522
537
|
portfolio: "Portfolio",
|
|
523
538
|
settings: "Settings",
|
|
524
539
|
calendar: "Calendar",
|
|
@@ -880,10 +895,17 @@ function formationFields(crm, formation) {
|
|
|
880
895
|
});
|
|
881
896
|
}
|
|
882
897
|
|
|
883
|
-
// src/config.ts
|
|
898
|
+
// src/config-network.ts
|
|
884
899
|
var SLUG = /^[a-z0-9][a-z0-9-]{1,62}$/;
|
|
885
900
|
var FIELD = /^[a-z][a-zA-Z0-9_]*$/;
|
|
886
901
|
var BINDING = /^[A-Z][A-Z0-9_]{0,127}$/;
|
|
902
|
+
function validateSharedNotes(opts) {
|
|
903
|
+
const duplicate = opts.values.some((type, index) => opts.values.indexOf(type) !== index);
|
|
904
|
+
const invalid = opts.values.some((type) => !FIELD.test(type) || !opts.crm.config.types[type] || (opts.fields ? !opts.fields[type] : false));
|
|
905
|
+
if (duplicate || invalid) {
|
|
906
|
+
throw new Error(`${opts.path}: must contain unique CRM types allowed by fields`);
|
|
907
|
+
}
|
|
908
|
+
}
|
|
887
909
|
function resolveNetwork(config, crm) {
|
|
888
910
|
const seen = /* @__PURE__ */ new Set();
|
|
889
911
|
const targets = [];
|
|
@@ -935,24 +957,81 @@ function resolveNetwork(config, crm) {
|
|
|
935
957
|
`defineChapter.network.targets.${target.id}.binding: must be an uppercase Worker binding identifier`
|
|
936
958
|
);
|
|
937
959
|
}
|
|
960
|
+
const sharedNotes = target.sharedNotes ?? [];
|
|
961
|
+
validateSharedNotes({
|
|
962
|
+
path: `defineChapter.network.targets.${target.id}.sharedNotes`,
|
|
963
|
+
values: sharedNotes,
|
|
964
|
+
crm,
|
|
965
|
+
fields
|
|
966
|
+
});
|
|
938
967
|
targets.push({
|
|
939
968
|
id: target.id,
|
|
940
969
|
name: target.name?.trim() || target.id,
|
|
941
970
|
url: url.origin,
|
|
942
971
|
...binding ? { binding } : {},
|
|
943
972
|
secretName,
|
|
944
|
-
...fields ? { fields } : {}
|
|
973
|
+
...fields ? { fields } : {},
|
|
974
|
+
sharedNotes
|
|
945
975
|
});
|
|
946
976
|
}
|
|
947
|
-
|
|
977
|
+
const readerIds = /* @__PURE__ */ new Set();
|
|
978
|
+
const readers = [];
|
|
979
|
+
for (const reader of config.network?.readers ?? []) {
|
|
980
|
+
if (!SLUG.test(reader.id)) {
|
|
981
|
+
throw new Error(`defineChapter.network.readers.id: must be a lowercase slug \u2014 got ${JSON.stringify(reader.id)}`);
|
|
982
|
+
}
|
|
983
|
+
if (readerIds.has(reader.id)) {
|
|
984
|
+
throw new Error(`defineChapter.network.readers: duplicate reader "${reader.id}"`);
|
|
985
|
+
}
|
|
986
|
+
readerIds.add(reader.id);
|
|
987
|
+
const entries = Object.entries(reader.fields ?? {});
|
|
988
|
+
if (entries.length === 0) {
|
|
989
|
+
throw new Error(`defineChapter.network.readers.${reader.id}.fields: at least one CRM type is required`);
|
|
990
|
+
}
|
|
991
|
+
for (const [type, names] of entries) {
|
|
992
|
+
if (!FIELD.test(type) || names.length === 0 || names.some((name) => !FIELD.test(name))) {
|
|
993
|
+
throw new Error(
|
|
994
|
+
`defineChapter.network.readers.${reader.id}.fields.${type}: type and field names must be non-empty CRM identifiers`
|
|
995
|
+
);
|
|
996
|
+
}
|
|
997
|
+
const def = crm.config.types[type];
|
|
998
|
+
if (!def) {
|
|
999
|
+
throw new Error(`defineChapter.network.readers.${reader.id}.fields: unknown local CRM type "${type}"`);
|
|
1000
|
+
}
|
|
1001
|
+
const unknown = names.filter((field) => !def.fields[field]);
|
|
1002
|
+
if (unknown.length > 0) {
|
|
1003
|
+
throw new Error(
|
|
1004
|
+
`defineChapter.network.readers.${reader.id}.fields.${type}: ${unknown.map((field) => `"${field}"`).join(", ")} not declared on the local CRM type`
|
|
1005
|
+
);
|
|
1006
|
+
}
|
|
1007
|
+
const nameField = def.nameField ?? "name";
|
|
1008
|
+
if (!names.includes(nameField)) {
|
|
1009
|
+
throw new Error(
|
|
1010
|
+
`defineChapter.network.readers.${reader.id}.fields.${type}: must include required name field "${nameField}"`
|
|
1011
|
+
);
|
|
1012
|
+
}
|
|
1013
|
+
}
|
|
1014
|
+
const sharedNotes = reader.sharedNotes ?? [];
|
|
1015
|
+
validateSharedNotes({
|
|
1016
|
+
path: `defineChapter.network.readers.${reader.id}.sharedNotes`,
|
|
1017
|
+
values: sharedNotes,
|
|
1018
|
+
crm,
|
|
1019
|
+
fields: reader.fields
|
|
1020
|
+
});
|
|
1021
|
+
readers.push({ id: reader.id, fields: reader.fields, sharedNotes });
|
|
1022
|
+
}
|
|
1023
|
+
return { targets, readers };
|
|
948
1024
|
}
|
|
1025
|
+
|
|
1026
|
+
// src/config.ts
|
|
1027
|
+
var SLUG2 = /^[a-z0-9][a-z0-9-]{1,62}$/;
|
|
949
1028
|
function isResolvedCrm(x) {
|
|
950
1029
|
return !!x && typeof x === "object" && "prepare" in x && typeof x.prepare === "function";
|
|
951
1030
|
}
|
|
952
1031
|
function defineChapter(config) {
|
|
953
1032
|
if (!config || typeof config !== "object") throw new Error("defineChapter: a config object is required");
|
|
954
1033
|
const { id: id2, name } = config;
|
|
955
|
-
if (typeof id2 !== "string" || !
|
|
1034
|
+
if (typeof id2 !== "string" || !SLUG2.test(id2)) {
|
|
956
1035
|
throw new Error(`defineChapter.id: must be a lowercase slug [a-z0-9-] (2-63 chars) \u2014 got ${JSON.stringify(id2)}`);
|
|
957
1036
|
}
|
|
958
1037
|
if (typeof name !== "string" || name.trim() === "") throw new Error("defineChapter.name: a non-empty name is required");
|
|
@@ -977,7 +1056,7 @@ function defineChapter(config) {
|
|
|
977
1056
|
const copy = resolveChapterCopy(config.copy);
|
|
978
1057
|
const network = resolveNetwork(config, crm);
|
|
979
1058
|
const formation = resolveLeaderFormation(config.formation, crm);
|
|
980
|
-
const { schema, rules } = chapterDb(mode, auth);
|
|
1059
|
+
const { schema, rules } = chapterDb(mode, auth, network.targets.length > 0);
|
|
981
1060
|
const services = config.services ?? ["db", "calendar", "o11y"];
|
|
982
1061
|
const account = config.account ?? "none";
|
|
983
1062
|
if (account !== "invite" && account !== "create" && account !== "none") {
|
|
@@ -1233,6 +1312,11 @@ function createChapterIntegration(chapter, options = {}) {
|
|
|
1233
1312
|
// The snapshot route is deliberately private. A credential-free smoke
|
|
1234
1313
|
// request must prove that the route is mounted and closed.
|
|
1235
1314
|
{ path: "/api/network/snapshot", expectedStatus: 401 },
|
|
1315
|
+
...chapter.network.readers.length > 0 ? [{ path: "/api/network/records", expectedStatus: 401 }] : [],
|
|
1316
|
+
...chapter.network.readers.some((reader) => reader.sharedNotes.length > 0) ? [{
|
|
1317
|
+
path: "/api/network/shared-notes",
|
|
1318
|
+
expectedStatus: 401
|
|
1319
|
+
}] : [],
|
|
1236
1320
|
// Formation metadata is public only when the host explicitly enables
|
|
1237
1321
|
// the bounded intake contract.
|
|
1238
1322
|
...chapter.formation.enabled ? [{ path: "/api/formation/config", expectedStatus: 200 }] : []
|