@odla-ai/chapter 0.48.1 → 0.48.3

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.
@@ -288,7 +288,7 @@ interface LeaderFormationConfig {
288
288
  maxLen?: Record<string, number>;
289
289
  /** Per-string cap when `maxLen` has no field override. Default 4000. */
290
290
  defaultMaxLen?: number;
291
- /** Maximum JSON request size in characters. Default 32768. */
291
+ /** Maximum JSON request size in UTF-8 bytes, enforced while streaming. Default 32768. */
292
292
  bodyCap?: number;
293
293
  }
294
294
  /** Fully resolved formation intake policy. */
@@ -534,7 +534,7 @@ interface ChapterApplication {
534
534
  /** Per-field character cap. Fields not listed use `defaultMaxLen`. */
535
535
  maxLen?: Record<string, number>;
536
536
  defaultMaxLen?: number;
537
- /** Max JSON request body in bytes. Default 32768. */
537
+ /** Max JSON request body in UTF-8 bytes, enforced while streaming. Default 32768. */
538
538
  bodyCap?: number;
539
539
  /** Reject a submit that carries no truthy `disclaimerAck` (400), instead of
540
540
  * writing a row with no consent record. Default `true`. Set `false`
package/dist/index.d.cts CHANGED
@@ -388,7 +388,7 @@ interface LeaderFormationConfig {
388
388
  maxLen?: Record<string, number>;
389
389
  /** Per-string cap when `maxLen` has no field override. Default 4000. */
390
390
  defaultMaxLen?: number;
391
- /** Maximum JSON request size in characters. Default 32768. */
391
+ /** Maximum JSON request size in UTF-8 bytes, enforced while streaming. Default 32768. */
392
392
  bodyCap?: number;
393
393
  }
394
394
  /** Fully resolved formation intake policy. */
@@ -691,7 +691,7 @@ interface ChapterApplication {
691
691
  /** Per-field character cap. Fields not listed use `defaultMaxLen`. */
692
692
  maxLen?: Record<string, number>;
693
693
  defaultMaxLen?: number;
694
- /** Max JSON request body in bytes. Default 32768. */
694
+ /** Max JSON request body in UTF-8 bytes, enforced while streaming. Default 32768. */
695
695
  bodyCap?: number;
696
696
  /** Reject a submit that carries no truthy `disclaimerAck` (400), instead of
697
697
  * writing a row with no consent record. Default `true`. Set `false`
package/dist/index.d.ts CHANGED
@@ -388,7 +388,7 @@ interface LeaderFormationConfig {
388
388
  maxLen?: Record<string, number>;
389
389
  /** Per-string cap when `maxLen` has no field override. Default 4000. */
390
390
  defaultMaxLen?: number;
391
- /** Maximum JSON request size in characters. Default 32768. */
391
+ /** Maximum JSON request size in UTF-8 bytes, enforced while streaming. Default 32768. */
392
392
  bodyCap?: number;
393
393
  }
394
394
  /** Fully resolved formation intake policy. */
@@ -691,7 +691,7 @@ interface ChapterApplication {
691
691
  /** Per-field character cap. Fields not listed use `defaultMaxLen`. */
692
692
  maxLen?: Record<string, number>;
693
693
  defaultMaxLen?: number;
694
- /** Max JSON request body in bytes. Default 32768. */
694
+ /** Max JSON request body in UTF-8 bytes, enforced while streaming. Default 32768. */
695
695
  bodyCap?: number;
696
696
  /** Reject a submit that carries no truthy `disclaimerAck` (400), instead of
697
697
  * writing a row with no consent record. Default `true`. Set `false`
@@ -1,8 +1,8 @@
1
1
  import * as preact from 'preact';
2
2
  import { ComponentChildren, JSX } from 'preact';
3
3
  import { CrmClient, Crm, CrmRecord, FieldType } from '@odla-ai/crm';
4
- import { a as Chapter, b as ChapterCopy, M as MemberContentDocument, E as EffectiveMemberContent, c as MemberContentTierAuthority } from '../../copy-context-BveBZglM.js';
5
- export { C as ChapterCopyProvider, u as useChapterCopy } from '../../copy-context-BveBZglM.js';
4
+ import { a as Chapter, b as ChapterCopy, M as MemberContentDocument, E as EffectiveMemberContent, c as MemberContentTierAuthority } from '../../copy-context-CMupQL9h.js';
5
+ export { C as ChapterCopyProvider, u as useChapterCopy } from '../../copy-context-CMupQL9h.js';
6
6
  import { CrmLifecycleAdapter, CrmWorkspaceMasterContext, CrmWorkspaceRecordContext, RecordPanelTab } from '@odla-ai/crm/ui';
7
7
 
8
8
  /** Normalized public auth configuration consumed by the Clerk gate. */
@@ -1,5 +1,5 @@
1
1
  export { AdminAccountMenuProps, AdminBuilderLibraryData, AdminChrome, AdminMemberContentData, AdminNote, AdminPage, AdminResource, AdminRouteState, AdminRouteTarget, AdminRouting, AdminSection, AdminSectionContext, AdminWorkspace, AdminWorkspaceFrameProps, AdminWorkspaceNavProps, AdmissionGrantsWorkspace, AvailabilitySectionOptions, BillingSectionOptions, BuilderLibraryAdmin, ChapterAdmin, ChapterAdminAuthAdapter, ChapterAdminAuthConfig, ChapterAdminAuthLoadContext, ChapterAdminProps, ChapterAdminUser, CollectionSectionOptions, DashboardSectionOptions, EmailSectionOptions, LeaderAdmissionAction, LeaderAdmissionActionProps, LeaderNetworkOverview, MeetingsSectionOptions, MemberContentAdmin, NetworkRecordEditor, NetworkRecordsWorkspace, NetworkShareActions, NetworkShareActionsProps, Panel, PeopleSectionOptions, RecordActions, RecordActionsProps, ThemeWarning, adminFetch, adminRouteFromUrl, adminRouteHref, adminSectionFromUrl, adminSectionHref, admissionGrantsWorkspace, applicationLifecycleAdapter, availabilitySection, billingSection, builderLibrarySection, collectionSection, dashboardSection, defaultAdminSections, defaultAdminWorkspaces, emailSection, loadChapterAdminConfig, loadChapterAdminUser, meetingsSection, memberContentSection, networkRecordsWorkspace, peopleSection, useAdminResource } from './admin/index.js';
2
- export { C as ChapterCopyProvider, u as useChapterCopy } from '../copy-context-BveBZglM.js';
2
+ export { C as ChapterCopyProvider, u as useChapterCopy } from '../copy-context-CMupQL9h.js';
3
3
  export { ApiFn, BrandStyle, BrandStyleProps, GiftCodeRedeemResult, GiftCodeRedeemer, GiftCodeRedeemerCopy, GiftCodeRedeemerProps, GiftOfferCards, GiftOfferCardsMode, GiftOfferCardsProps, GiftPurchases, GiftPurchasesProps, JoinBookingSimulation, JoinConfig, JoinFlowState, JoinIsland, JoinIslandProps, JoinSimulation, JoinStepRenderContext, JoinSubmitRenderContext, JoinTier, JoinTierRenderContext, MEMBERSHIP_CARD_TOKEN_DEFAULTS, MemberContentArea, MemberContentAreaProps, MemberGifts, MemberProvisionalRenderContext, MembersArea, MembersAreaProps, MembershipCardTokenName, MembershipCards, MembershipCardsMode, MembershipCardsProps, PaymentPriceLines, PaymentStep, PaymentStepProps, PaymentStepSimulation, RescheduleProps, Rescheduler, Slot, SlotPicker, SlotPickerClasses, SlotPickerProps, SubResponse, TierPlaceholder, dayKey, dayLabel, fmtDate, fmtMoney, fullLabel, groupSlotsByDay, loadJoinResume, membershipApplicationHref, tierNeedsPayment, timeLabel, tzShort, useTierSelection } from './member/index.js';
4
4
  import 'preact';
5
5
  import '@odla-ai/crm';
@@ -1,7 +1,7 @@
1
1
  import * as preact from 'preact';
2
2
  import { ComponentChildren, JSX } from 'preact';
3
- import { d as MemberContentProjection, e as MemberContentPageProjection, b as ChapterCopy, f as ChapterBrand } from '../../copy-context-BveBZglM.js';
4
- export { C as ChapterCopyProvider, u as useChapterCopy } from '../../copy-context-BveBZglM.js';
3
+ import { d as MemberContentProjection, e as MemberContentPageProjection, b as ChapterCopy, f as ChapterBrand } from '../../copy-context-CMupQL9h.js';
4
+ export { C as ChapterCopyProvider, u as useChapterCopy } from '../../copy-context-CMupQL9h.js';
5
5
  import { FieldType, FieldConditions } from '@odla-ai/crm';
6
6
 
7
7
  /** A bookable slot: a start instant in epoch milliseconds. */
@@ -3678,6 +3678,47 @@ async function memberSessionApplication(db, chapterId, runtime, identity) {
3678
3678
  ) };
3679
3679
  }
3680
3680
 
3681
+ // src/bounded-request-text.ts
3682
+ async function readBoundedRequestText(req, maxBytes) {
3683
+ if (!Number.isSafeInteger(maxBytes) || maxBytes < 0) throw new TypeError("invalid request body cap");
3684
+ const reader = req.body?.getReader();
3685
+ const cancel = () => {
3686
+ void reader?.cancel().catch(() => {
3687
+ });
3688
+ };
3689
+ const invalid2 = () => json({ error: "invalid JSON body" }, 400);
3690
+ let complete = false;
3691
+ req.signal.addEventListener("abort", cancel, { once: true });
3692
+ try {
3693
+ if (req.signal.aborted) return invalid2();
3694
+ const declared = req.headers.get("content-length");
3695
+ if (declared && /^\d+$/.test(declared) && Number(declared) > maxBytes) {
3696
+ return json({ error: "request body too large" }, 413);
3697
+ }
3698
+ if (!reader) return "";
3699
+ const decoder = new TextDecoder();
3700
+ let bytes = 0;
3701
+ let text6 = "";
3702
+ for (; ; ) {
3703
+ const { done, value } = await reader.read();
3704
+ if (req.signal.aborted) return invalid2();
3705
+ if (done) {
3706
+ complete = true;
3707
+ return text6 + decoder.decode();
3708
+ }
3709
+ bytes += value.byteLength;
3710
+ if (bytes > maxBytes) return json({ error: "request body too large" }, 413);
3711
+ text6 += decoder.decode(value, { stream: true });
3712
+ }
3713
+ } catch {
3714
+ return invalid2();
3715
+ } finally {
3716
+ req.signal.removeEventListener("abort", cancel);
3717
+ if (!complete) cancel();
3718
+ reader?.releaseLock();
3719
+ }
3720
+ }
3721
+
3681
3722
  // src/clerk.ts
3682
3723
  async function rejectedCreate(res) {
3683
3724
  const body = typeof res.json === "function" ? await res.json().catch(() => null) : null;
@@ -4096,8 +4137,8 @@ var handleMember = async (req, url, env, ctx) => {
4096
4137
  return resumeJoin(url, env, ctx);
4097
4138
  }
4098
4139
  if (req.method === "POST" && url.pathname === "/api/applications") {
4099
- const raw2 = await req.text();
4100
- if (raw2.length > chapter.application.bodyCap) return json({ error: "request body too large" }, 413);
4140
+ const raw2 = await readBoundedRequestText(req, chapter.application.bodyCap);
4141
+ if (raw2 instanceof Response) return raw2;
4101
4142
  let parsed;
4102
4143
  try {
4103
4144
  parsed = JSON.parse(raw2);
@@ -6992,8 +7033,8 @@ async function firstRow2(db, ns, q) {
6992
7033
  async function startSubscription(req, env, ctx) {
6993
7034
  let body;
6994
7035
  try {
6995
- const raw2 = await req.text();
6996
- if (raw2.length > ctx.chapter.application.bodyCap) return json({ error: "request body too large" }, 413);
7036
+ const raw2 = await readBoundedRequestText(req, ctx.chapter.application.bodyCap);
7037
+ if (raw2 instanceof Response) return raw2;
6997
7038
  body = JSON.parse(raw2);
6998
7039
  if (!body || typeof body !== "object" || Array.isArray(body)) throw new TypeError("body");
6999
7040
  } catch {
@@ -9333,6 +9374,9 @@ var handleAdminNetworkPush = async (req, url, env, ctx) => {
9333
9374
  if (req.method !== "POST" || url.pathname !== "/api/admin/network/push") return null;
9334
9375
  const got = await gate6(req, env, ctx);
9335
9376
  if ("response" in got) return got.response;
9377
+ if (!await networkWriteAllowed(req, got.db, got.user, ctx)) {
9378
+ return json({ error: "super-admin required", code: "super_admin_required" }, 403);
9379
+ }
9336
9380
  let body;
9337
9381
  try {
9338
9382
  body = await req.json();
@@ -11855,8 +11899,8 @@ var handleFormation = async (req, url, env, ctx) => {
11855
11899
  });
11856
11900
  }
11857
11901
  if (req.method !== "POST" || url.pathname !== "/api/formation/applications") return null;
11858
- const raw2 = await req.text();
11859
- if (raw2.length > formation.bodyCap) return json({ error: "request body too large" }, 413);
11902
+ const raw2 = await readBoundedRequestText(req, formation.bodyCap);
11903
+ if (raw2 instanceof Response) return raw2;
11860
11904
  let body;
11861
11905
  try {
11862
11906
  body = JSON.parse(raw2);