@odla-ai/chapter 0.42.3 → 0.42.4

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.js CHANGED
@@ -2032,8 +2032,8 @@ function tierPayable(tier, group, hasSecretKey) {
2032
2032
  function byOrder(a, b) {
2033
2033
  return a.sortOrder - b.sortOrder || a.id.localeCompare(b.id);
2034
2034
  }
2035
- function resolveTiers(group, rows2 = []) {
2036
- const stored = rows2.filter((tier) => tier.active);
2035
+ function resolveTiers(group, rows3 = []) {
2036
+ const stored = rows3.filter((tier) => tier.active);
2037
2037
  if (stored.length) return [...stored].sort(byOrder);
2038
2038
  return [{
2039
2039
  id: "standard",
@@ -4066,15 +4066,15 @@ function rowToTier(row, groupId) {
4066
4066
  }
4067
4067
  async function loadTiers(db, group) {
4068
4068
  const groupId = String(group.id ?? "");
4069
- let rows2;
4069
+ let rows3;
4070
4070
  try {
4071
- rows2 = (await db.query({
4071
+ rows3 = (await db.query({
4072
4072
  tiers: { $: { where: { groupId }, order: { sortOrder: "asc" }, limit: 100 } }
4073
4073
  })).tiers;
4074
4074
  } catch {
4075
- rows2 = void 0;
4075
+ rows3 = void 0;
4076
4076
  }
4077
- const list = Array.isArray(rows2) ? rows2.map((row) => rowToTier(row, groupId)) : [];
4077
+ const list = Array.isArray(rows3) ? rows3.map((row) => rowToTier(row, groupId)) : [];
4078
4078
  return resolveTiers(group, list);
4079
4079
  }
4080
4080
  async function loadOfferableTiers(db, group, hasSecretKey) {
@@ -4774,6 +4774,448 @@ async function exportChapterPromotion(input) {
4774
4774
  ]
4775
4775
  };
4776
4776
  }
4777
+
4778
+ // src/member-system-authority.ts
4779
+ var rows2 = (group) => group.fields.map((id4) => ({ ...group, id: id4 }));
4780
+ var MEMBER_SYSTEM_AUTHORITY_MATRIX = [
4781
+ ...rows2({
4782
+ scope: "network",
4783
+ writer: "network_person",
4784
+ projections: ["bnf_admin", "chapter_admin", "member_self_service"],
4785
+ sensitivity: "pii",
4786
+ memberAccess: "edit",
4787
+ fields: [
4788
+ "person.legalName",
4789
+ "person.preferredName",
4790
+ "person.namePronunciation",
4791
+ "person.pronouns",
4792
+ "person.displayLegalName",
4793
+ "person.primaryEmail",
4794
+ "person.secondaryEmails",
4795
+ "person.phone",
4796
+ "person.linkedinUrl",
4797
+ "person.photo",
4798
+ "person.homeAddress",
4799
+ "person.fulfillmentFit",
4800
+ "person.fulfillmentSize"
4801
+ ]
4802
+ }),
4803
+ ...rows2({
4804
+ scope: "network",
4805
+ writer: "network_person",
4806
+ projections: ["bnf_admin", "chapter_admin", "member_self_service"],
4807
+ sensitivity: "ordinary",
4808
+ memberAccess: "edit",
4809
+ fields: [
4810
+ "person.title",
4811
+ "person.company",
4812
+ "person.companyObservedAt",
4813
+ "person.region",
4814
+ "person.whyText",
4815
+ "person.whyTokens",
4816
+ "person.skillsOffered",
4817
+ "person.openToRequests",
4818
+ "person.directoryPhotoConsent"
4819
+ ]
4820
+ }),
4821
+ ...rows2({
4822
+ scope: "network",
4823
+ writer: "network_person",
4824
+ projections: ["bnf_admin", "chapter_admin"],
4825
+ sensitivity: "restricted",
4826
+ memberAccess: "none",
4827
+ fields: [
4828
+ "person.linkedinMemberId",
4829
+ "person.identityClaims",
4830
+ "person.aliases",
4831
+ "person.mergeHistory",
4832
+ "person.introducedByPersonId",
4833
+ "person.introducedAt",
4834
+ "person.firstTouch",
4835
+ "person.globalSuppression",
4836
+ "person.deceasedAt",
4837
+ "person.archivedAt"
4838
+ ]
4839
+ }),
4840
+ ...rows2({
4841
+ scope: "network",
4842
+ writer: "network_person",
4843
+ projections: ["bnf_admin", "chapter_admin", "member_self_service"],
4844
+ sensitivity: "sensitive",
4845
+ memberAccess: "edit",
4846
+ fields: ["person.accreditationSelfCertification", "person.accreditationCategory", "person.accreditationExpiresAt"]
4847
+ }),
4848
+ ...rows2({
4849
+ scope: "network",
4850
+ writer: "network_person",
4851
+ projections: ["bnf_admin", "chapter_admin", "member_self_service"],
4852
+ sensitivity: "restricted",
4853
+ memberAccess: "read",
4854
+ fields: ["person.acknowledgements"]
4855
+ }),
4856
+ ...rows2({
4857
+ scope: "provider",
4858
+ writer: "clerk",
4859
+ projections: ["clerk_identity", "bnf_admin", "chapter_admin"],
4860
+ sensitivity: "restricted",
4861
+ memberAccess: "none",
4862
+ fields: ["identity.clerkUserIds", "identity.clerkEmailVerification"]
4863
+ }),
4864
+ ...rows2({
4865
+ scope: "chapter",
4866
+ writer: "chapter_journey",
4867
+ projections: ["chapter_admin", "chapter_crm", "bnf_admin"],
4868
+ sensitivity: "ordinary",
4869
+ memberAccess: "none",
4870
+ fields: [
4871
+ "journey.chapterId",
4872
+ "journey.stage",
4873
+ "journey.stageEnteredAt",
4874
+ "journey.stageHistory",
4875
+ "journey.ending",
4876
+ "journey.endingReason",
4877
+ "journey.source",
4878
+ "journey.entryChapterId",
4879
+ "journey.route",
4880
+ "journey.flags",
4881
+ "journey.applicationStartedAt",
4882
+ "journey.appliedAt",
4883
+ "journey.paidAt",
4884
+ "journey.callBookedAt",
4885
+ "journey.metAt",
4886
+ "journey.approvedAt",
4887
+ "journey.onboardedAt",
4888
+ "journey.firstLoginAt",
4889
+ "journey.firstDealAt"
4890
+ ]
4891
+ }),
4892
+ ...rows2({
4893
+ scope: "chapter",
4894
+ writer: "chapter_journey",
4895
+ projections: ["chapter_admin", "chapter_crm"],
4896
+ sensitivity: "sensitive",
4897
+ memberAccess: "none",
4898
+ fields: [
4899
+ "journey.relationshipOwnerId",
4900
+ "journey.lastContactAt",
4901
+ "journey.nextAction",
4902
+ "journey.owes",
4903
+ "journey.asks",
4904
+ "journey.preparation",
4905
+ "journey.notes"
4906
+ ]
4907
+ }),
4908
+ ...rows2({
4909
+ scope: "chapter",
4910
+ writer: "chapter_journey",
4911
+ projections: ["chapter_admin", "chapter_crm", "member_self_service"],
4912
+ sensitivity: "ordinary",
4913
+ memberAccess: "edit",
4914
+ fields: ["journey.dealFlowConsent", "journey.directoryConsent", "journey.emailConsent", "journey.smsConsent"]
4915
+ }),
4916
+ ...rows2({
4917
+ scope: "chapter",
4918
+ writer: "chapter_journey",
4919
+ projections: ["chapter_admin", "bnf_admin", "member_self_service"],
4920
+ sensitivity: "ordinary",
4921
+ memberAccess: "read",
4922
+ fields: ["journey.memberNumber"]
4923
+ }),
4924
+ ...rows2({
4925
+ scope: "network",
4926
+ writer: "network_membership",
4927
+ projections: ["bnf_admin", "chapter_admin", "member_self_service"],
4928
+ sensitivity: "ordinary",
4929
+ memberAccess: "read",
4930
+ fields: [
4931
+ "membership.chapterId",
4932
+ "membership.journeyId",
4933
+ "membership.termStartsAt",
4934
+ "membership.termEndsAt",
4935
+ "membership.tier",
4936
+ "membership.status",
4937
+ "membership.joinedAt",
4938
+ "membership.autoRenews",
4939
+ "membership.renewalAt",
4940
+ "membership.cancelsAt",
4941
+ "membership.graceEndsAt",
4942
+ "membership.foundingCohort",
4943
+ "membership.offeringPolicyVersion",
4944
+ "membership.discountPolicyVersion"
4945
+ ]
4946
+ }),
4947
+ ...rows2({
4948
+ scope: "network",
4949
+ writer: "network_commercial_projection",
4950
+ projections: ["bnf_admin", "chapter_admin"],
4951
+ sensitivity: "restricted",
4952
+ memberAccess: "none",
4953
+ fields: [
4954
+ "membership.stripeCustomerId",
4955
+ "membership.stripeSubscriptionId",
4956
+ "membership.stripePriceId",
4957
+ "membership.lastInvoiceId",
4958
+ "membership.paymentOutcome",
4959
+ "membership.refundOutcome"
4960
+ ]
4961
+ }),
4962
+ ...rows2({
4963
+ scope: "network",
4964
+ writer: "network_discount_policy",
4965
+ projections: ["bnf_admin", "chapter_admin", "stripe_billing"],
4966
+ sensitivity: "ordinary",
4967
+ memberAccess: "none",
4968
+ fields: [
4969
+ "discountPolicy.chapterId",
4970
+ "discountPolicy.version",
4971
+ "discountPolicy.eligibleOfferingIds",
4972
+ "discountPolicy.percentOff",
4973
+ "discountPolicy.amountOff",
4974
+ "discountPolicy.activatesOn",
4975
+ "discountPolicy.invoiceCount",
4976
+ "discountPolicy.expiresAt",
4977
+ "discountPolicy.stackingOrder",
4978
+ "discountPolicy.status"
4979
+ ]
4980
+ }),
4981
+ ...rows2({
4982
+ scope: "network",
4983
+ writer: "network_entitlement",
4984
+ projections: ["bnf_admin", "chapter_admin", "member_self_service", "stripe_billing"],
4985
+ sensitivity: "ordinary",
4986
+ memberAccess: "read",
4987
+ fields: [
4988
+ "entitlement.membershipId",
4989
+ "entitlement.kind",
4990
+ "entitlement.priceCents",
4991
+ "entitlement.currency",
4992
+ "entitlement.payerPersonId",
4993
+ "entitlement.purchasedAt",
4994
+ "entitlement.termEndsAt",
4995
+ "entitlement.renewsWithMembership",
4996
+ "entitlement.status"
4997
+ ]
4998
+ }),
4999
+ ...rows2({
5000
+ scope: "network",
5001
+ writer: "network_seat",
5002
+ projections: ["bnf_admin", "chapter_admin", "member_self_service"],
5003
+ sensitivity: "pii",
5004
+ memberAccess: "read",
5005
+ fields: [
5006
+ "seat.membershipId",
5007
+ "seat.entitlementId",
5008
+ "seat.personId",
5009
+ "seat.recipientName",
5010
+ "seat.recipientEmail",
5011
+ "seat.role",
5012
+ "seat.status",
5013
+ "seat.acceptanceExpiresAt",
5014
+ "seat.acceptedAt",
5015
+ "seat.activatedAt",
5016
+ "seat.refundedAt"
5017
+ ]
5018
+ }),
5019
+ ...rows2({
5020
+ scope: "network",
5021
+ writer: "network_referral_ledger",
5022
+ projections: ["bnf_admin", "chapter_admin", "member_self_service"],
5023
+ sensitivity: "ordinary",
5024
+ memberAccess: "read",
5025
+ fields: [
5026
+ "referral.referrerPersonId",
5027
+ "referral.referredPersonId",
5028
+ "referral.qualifiedMembershipId",
5029
+ "referral.creditCents",
5030
+ "referral.status",
5031
+ "referral.appliedInvoiceId",
5032
+ "referral.carryForwardCents",
5033
+ "referral.adjustmentOf"
5034
+ ]
5035
+ }),
5036
+ ...rows2({
5037
+ scope: "network",
5038
+ writer: "network_investment_ledger",
5039
+ projections: ["bnf_admin", "chapter_admin", "member_self_service"],
5040
+ sensitivity: "restricted",
5041
+ memberAccess: "read",
5042
+ fields: [
5043
+ "investment.personId",
5044
+ "investment.chapterId",
5045
+ "investment.season",
5046
+ "investment.purpose",
5047
+ "investment.targetCount",
5048
+ "investment.status",
5049
+ "investment.amountCents",
5050
+ "investment.closedAt",
5051
+ "investment.sourceReference"
5052
+ ]
5053
+ }),
5054
+ ...rows2({
5055
+ scope: "provider",
5056
+ writer: "stripe",
5057
+ projections: ["stripe_billing", "bnf_admin", "chapter_admin"],
5058
+ sensitivity: "restricted",
5059
+ memberAccess: "none",
5060
+ fields: [
5061
+ "commercial.charge",
5062
+ "commercial.invoice",
5063
+ "commercial.refund",
5064
+ "commercial.providerSubscription",
5065
+ "commercial.paymentMethod"
5066
+ ]
5067
+ })
5068
+ ];
5069
+ var MEMBER_SELF_EDITABLE_FIELDS = new Set(
5070
+ MEMBER_SYSTEM_AUTHORITY_MATRIX.filter((row) => row.memberAccess === "edit").map((row) => row.id)
5071
+ );
5072
+ var MEMBER_SELF_READABLE_FIELDS = new Set(
5073
+ MEMBER_SYSTEM_AUTHORITY_MATRIX.filter((row) => row.memberAccess !== "none").map((row) => row.id)
5074
+ );
5075
+ function projectMemberSelf(record4) {
5076
+ return Object.fromEntries(Object.entries(record4).filter(([field]) => MEMBER_SELF_READABLE_FIELDS.has(field)));
5077
+ }
5078
+ function classifyMemberSystemWrite(intent) {
5079
+ if (intent.actor === "bnf") return "reject_bnf_surface";
5080
+ const authority = MEMBER_SYSTEM_AUTHORITY_MATRIX.find((row) => row.id === intent.field);
5081
+ if (!authority) return "reject_unknown_field";
5082
+ if (authority.writer !== intent.actor) return "reject_wrong_writer";
5083
+ if (intent.expectedRevision !== intent.actualRevision) return "reject_stale_revision";
5084
+ return "apply";
5085
+ }
5086
+ function validateMemberSystemAuthority(matrix = MEMBER_SYSTEM_AUTHORITY_MATRIX) {
5087
+ const errors = [];
5088
+ const ids = /* @__PURE__ */ new Set();
5089
+ for (const row of matrix) {
5090
+ if (!row.id || !row.id.includes(".")) errors.push(`invalid field id "${row.id}"`);
5091
+ if (ids.has(row.id)) errors.push(`duplicate field authority "${row.id}"`);
5092
+ ids.add(row.id);
5093
+ if (row.memberAccess !== "none" && !row.projections.includes("member_self_service")) {
5094
+ errors.push(`${row.id} grants member access without a member_self_service projection`);
5095
+ }
5096
+ if (row.id.startsWith("person.") && (row.scope !== "network" || row.writer !== "network_person")) {
5097
+ errors.push(`${row.id} must be network_person authority`);
5098
+ }
5099
+ if (row.id.startsWith("journey.") && (row.scope !== "chapter" || row.writer !== "chapter_journey")) {
5100
+ errors.push(`${row.id} must be chapter_journey authority`);
5101
+ }
5102
+ }
5103
+ return { ok: errors.length === 0, errors };
5104
+ }
5105
+
5106
+ // src/member-system-contract.ts
5107
+ var MEMBER_SYSTEM_CONTRACT_VERSION = 1;
5108
+ var JOURNEY_STAGES = [
5109
+ "identified",
5110
+ "researched",
5111
+ "outreach",
5112
+ "in_conversation",
5113
+ "invited_or_requested",
5114
+ "application_started",
5115
+ "applied",
5116
+ "paid_awaiting_conversation",
5117
+ "ready_to_book",
5118
+ "booked",
5119
+ "met",
5120
+ "approved",
5121
+ "onboarded",
5122
+ "active",
5123
+ "first_deal"
5124
+ ];
5125
+ var JOURNEY_ENDINGS = ["passed", "declined", "withdrew", "lapsed"];
5126
+ var REQUIRED_NOTICE_KINDS = [
5127
+ "payment_receipt",
5128
+ "refund_confirmation",
5129
+ "security_alert",
5130
+ "legal_notice",
5131
+ "membership_status",
5132
+ "renewal_notice",
5133
+ "cancellation_confirmation"
5134
+ ];
5135
+ function memberSystemAvailability(input) {
5136
+ if (!input.odlaReachable) {
5137
+ return {
5138
+ bnfAdministration: false,
5139
+ chapterWorkflow: false,
5140
+ memberSelfService: false,
5141
+ newApplication: false,
5142
+ newCheckout: false,
5143
+ providerRenewalsMayContinue: true,
5144
+ reason: "odla_unavailable"
5145
+ };
5146
+ }
5147
+ return {
5148
+ bnfAdministration: input.bnfFrontendReachable,
5149
+ chapterWorkflow: true,
5150
+ memberSelfService: true,
5151
+ newApplication: true,
5152
+ newCheckout: true,
5153
+ providerRenewalsMayContinue: true,
5154
+ ...!input.bnfFrontendReachable ? { reason: "bnf_frontend_unavailable" } : {}
5155
+ };
5156
+ }
5157
+ function classifyMemberStripeEvent(identity, target, hasProvenLegacyLocalLink) {
5158
+ const keys = ["appId", "environment", "dataEnvironment", "runtime", "chapterId"];
5159
+ const supplied = keys.filter((key) => identity[key] !== void 0);
5160
+ if (supplied.some((key) => identity[key] !== target[key])) return "ignore_sibling";
5161
+ if (supplied.length === keys.length) return "apply";
5162
+ return hasProvenLegacyLocalLink ? "apply_legacy" : "quarantine_unmatched";
5163
+ }
5164
+ function planMemberSystemEventReplay(events) {
5165
+ const seen = /* @__PURE__ */ new Map();
5166
+ const plan = { accepted: [], replayed: [], collisions: [] };
5167
+ for (const event of events) {
5168
+ const digest = seen.get(event.id);
5169
+ if (digest === void 0) {
5170
+ seen.set(event.id, event.digest);
5171
+ plan.accepted.push(event.id);
5172
+ } else if (digest === event.digest) plan.replayed.push(event.id);
5173
+ else plan.collisions.push(event.id);
5174
+ }
5175
+ return plan;
5176
+ }
5177
+ var MEMBER_SYSTEM_RECOVERY_OBJECTIVES = {
5178
+ failClosedWithinMs: 0,
5179
+ replayProjectionWithinMinutes: 15,
5180
+ providerEventsRemainReplayable: true,
5181
+ requireHumanReviewForCollision: true
5182
+ };
5183
+ function planMemberSystemMigration(rows3) {
5184
+ const plan = { importIds: [], fixtureIds: [], rejectedIds: [] };
5185
+ for (const row of rows3) {
5186
+ if (row.source === "synthetic_fixture" && !row.isRealPerson) plan.fixtureIds.push(row.id);
5187
+ else if (row.source === "external_reimport" && row.isRealPerson && row.provenance) plan.importIds.push(row.id);
5188
+ else plan.rejectedIds.push(row.id);
5189
+ }
5190
+ return plan;
5191
+ }
5192
+ function memberSystemRollbackPlan() {
5193
+ return {
5194
+ stopNetworkWrites: true,
5195
+ disableBnfMemberMutations: true,
5196
+ keepChapterProductionReads: true,
5197
+ keepStripeBillingAuthority: true,
5198
+ deleteProviderObjects: false,
5199
+ reverseProviderPayments: false,
5200
+ reconciliationRequired: true
5201
+ };
5202
+ }
5203
+ var SILVER_SALT_P0_FIXTURE = {
5204
+ sourceInventory: { applications: 36, meetings: 7, emails: 49, realPeople: 0 },
5205
+ application: { id: "fixture_application_001", personId: "fixture_person_001", migrates: false },
5206
+ crm: { recordId: "fixture_crm_001", email: "fixture.member@example.invalid", migrates: false },
5207
+ clerk: { userId: "user_fixture_001", verifiedEmail: "fixture.member@example.invalid", migrates: false },
5208
+ stripe: {
5209
+ customerId: "cus_fixture_001",
5210
+ subscriptionId: "sub_fixture_001",
5211
+ productId: "prod_fixture_001",
5212
+ priceId: "price_fixture_001",
5213
+ eventId: "evt_fixture_001",
5214
+ migrates: false
5215
+ },
5216
+ unmatchedStripeEvent: { id: "evt_fixture_unmatched", disposition: "quarantine_unmatched" },
5217
+ legacyStripeEvent: { id: "evt_fixture_legacy", requiresProvenLocalLink: true }
5218
+ };
4777
5219
  export {
4778
5220
  ADMISSION_GRANTS_PATH,
4779
5221
  ADMISSION_GRANTS_SCHEMA_VERSION,
@@ -4787,16 +5229,25 @@ export {
4787
5229
  DEFAULT_CHAPTER_COPY,
4788
5230
  DEFAULT_SHARE_FIELDS,
4789
5231
  GIFT_OFFER_CATALOG_VERSION,
5232
+ JOURNEY_ENDINGS,
5233
+ JOURNEY_STAGES,
4790
5234
  MAX_GIFT_OFFERS,
4791
5235
  MEMBERSHIP_PAGE_RENDERER,
4792
5236
  MEMBER_CONTENT_CONTROL_PATH,
4793
5237
  MEMBER_CONTENT_PATH,
4794
5238
  MEMBER_CONTENT_SCHEMA_VERSION,
5239
+ MEMBER_SELF_EDITABLE_FIELDS,
5240
+ MEMBER_SELF_READABLE_FIELDS,
5241
+ MEMBER_SYSTEM_AUTHORITY_MATRIX,
5242
+ MEMBER_SYSTEM_CONTRACT_VERSION,
5243
+ MEMBER_SYSTEM_RECOVERY_OBJECTIVES,
5244
+ REQUIRED_NOTICE_KINDS,
4795
5245
  SCHEDULING_DEFAULTS,
4796
5246
  SIGNUP_CONTROL_PATH,
4797
5247
  SIGNUP_CONTROL_SCHEMA_VERSION,
4798
5248
  SIGNUP_CONTROL_THEME_MARKER,
4799
5249
  SIGNUP_CONTROL_THEME_STYLE_ID,
5250
+ SILVER_SALT_P0_FIXTURE,
4800
5251
  applicantProfile,
4801
5252
  applicationBookingUpdate,
4802
5253
  applicationFlowFields,
@@ -4823,6 +5274,8 @@ export {
4823
5274
  chapterDb,
4824
5275
  chapterFlowFieldContract,
4825
5276
  clampArray,
5277
+ classifyMemberStripeEvent,
5278
+ classifyMemberSystemWrite,
4826
5279
  clerkGetUser,
4827
5280
  clerkGetUserByEmail,
4828
5281
  clerkIntegration,
@@ -4876,6 +5329,8 @@ export {
4876
5329
  memberContentDigest,
4877
5330
  memberContentDocument,
4878
5331
  memberSession,
5332
+ memberSystemAvailability,
5333
+ memberSystemRollbackPlan,
4879
5334
  membershipPageDocument,
4880
5335
  membershipTierPresentationFromMarkdown,
4881
5336
  networkSourceTag,
@@ -4887,9 +5342,12 @@ export {
4887
5342
  paymentsReady,
4888
5343
  personInputFromApp,
4889
5344
  planDelivery,
5345
+ planMemberSystemEventReplay,
5346
+ planMemberSystemMigration,
4890
5347
  projectApplicant,
4891
5348
  projectBuilderLibraryDelivery,
4892
5349
  projectMemberContent,
5350
+ projectMemberSelf,
4893
5351
  projectSharedRecord,
4894
5352
  promoteBuilderLibraryResource,
4895
5353
  publicGiftOffers,
@@ -4932,6 +5390,7 @@ export {
4932
5390
  validateBuilderLibraryDocument,
4933
5391
  validateGiftOfferCatalog,
4934
5392
  validateMemberContentDocument,
5393
+ validateMemberSystemAuthority,
4935
5394
  validateMembershipPageDocument,
4936
5395
  validateScheduling,
4937
5396
  validateSignupControlDocument,