@odla-ai/chapter 0.26.0 → 0.26.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.
@@ -1,8 +1,8 @@
1
1
  import * as preact from 'preact';
2
2
  import { ComponentChildren, JSX } from 'preact';
3
3
  import { CrmClient, Crm, CrmRecord } from '@odla-ai/crm';
4
- import { a as Chapter, b as ChapterCopy } from '../../copy-context-CLvhJhrF.js';
5
- export { C as ChapterCopyProvider, u as useChapterCopy } from '../../copy-context-CLvhJhrF.js';
4
+ import { a as Chapter, b as ChapterCopy } from '../../copy-context-Vof2eTMt.js';
5
+ export { C as ChapterCopyProvider, u as useChapterCopy } from '../../copy-context-Vof2eTMt.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, AdminChrome, AdminNote, AdminPage, AdminResource, AdminRouteState, AdminRouteTarget, AdminRouting, AdminSection, AdminSectionContext, AdminWorkspace, AdminWorkspaceNavProps, AvailabilitySectionOptions, BillingSectionOptions, ChapterAdmin, ChapterAdminAuthAdapter, ChapterAdminAuthConfig, ChapterAdminAuthLoadContext, ChapterAdminProps, ChapterAdminUser, CollectionSectionOptions, DashboardSectionOptions, EmailSectionOptions, LeaderNetworkOverview, MeetingsSectionOptions, NetworkShareActions, NetworkShareActionsProps, Panel, PeopleSectionOptions, RecordActions, RecordActionsProps, ThemeWarning, adminFetch, adminRouteFromUrl, adminRouteHref, adminSectionFromUrl, adminSectionHref, applicationLifecycleAdapter, availabilitySection, billingSection, collectionSection, dashboardSection, defaultAdminSections, defaultAdminWorkspaces, emailSection, loadChapterAdminConfig, loadChapterAdminUser, meetingsSection, peopleSection, useAdminResource } from './admin/index.js';
2
- export { C as ChapterCopyProvider, u as useChapterCopy } from '../copy-context-CLvhJhrF.js';
2
+ export { C as ChapterCopyProvider, u as useChapterCopy } from '../copy-context-Vof2eTMt.js';
3
3
  export { ApiFn, BrandStyle, BrandStyleProps, JoinConfig, JoinFlowState, JoinIsland, JoinIslandProps, JoinStepRenderContext, JoinSubmitRenderContext, MemberProvisionalRenderContext, MembersArea, MembersAreaProps, PaymentPriceLines, PaymentStep, PaymentStepProps, RescheduleProps, Rescheduler, Slot, SlotPicker, SlotPickerClasses, SlotPickerProps, dayKey, dayLabel, fmtDate, fmtMoney, fullLabel, groupSlotsByDay, loadJoinResume, timeLabel, tzShort } 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 { b as ChapterCopy, c as ChapterBrand } from '../../copy-context-CLvhJhrF.js';
4
- export { C as ChapterCopyProvider, u as useChapterCopy } from '../../copy-context-CLvhJhrF.js';
3
+ import { b as ChapterCopy, c as ChapterBrand } from '../../copy-context-Vof2eTMt.js';
4
+ export { C as ChapterCopyProvider, u as useChapterCopy } from '../../copy-context-Vof2eTMt.js';
5
5
  import '@odla-ai/crm';
6
6
 
7
7
  /** A bookable slot: a start instant in epoch milliseconds. */
@@ -2637,8 +2637,118 @@ var handleAdminComms = async (req, url, env, ctx) => {
2637
2637
  };
2638
2638
 
2639
2639
  // src/worker-routes-network.ts
2640
+ var import_crm5 = require("@odla-ai/crm");
2641
+ var import_db4 = require("@odla-ai/db");
2642
+
2643
+ // src/worker-network-fetch.ts
2644
+ function targetFetcher(env, target) {
2645
+ if (!target.binding) return null;
2646
+ const candidate = env[target.binding];
2647
+ if (typeof candidate !== "object" || candidate === null || !("fetch" in candidate) || typeof candidate.fetch !== "function") {
2648
+ throw new Error(`service binding "${target.binding}" is unavailable`);
2649
+ }
2650
+ return candidate;
2651
+ }
2652
+ function fetchNetworkTarget(env, target, destination, init) {
2653
+ const binding = targetFetcher(env, target);
2654
+ return binding ? binding.fetch(new Request(destination, init)) : globalThis.fetch(destination, init);
2655
+ }
2656
+
2657
+ // src/worker-network-push.ts
2640
2658
  var import_crm4 = require("@odla-ai/crm");
2641
2659
  var import_db3 = require("@odla-ai/db");
2660
+ async function pushNetworkRecord(db, env, ctx, target, record) {
2661
+ const secret = await getVaultSecret(db, target.secretName);
2662
+ const crmDeps3 = {
2663
+ crm: ctx.chapter.crm,
2664
+ db,
2665
+ now: () => Date.now(),
2666
+ newId: () => crypto.randomUUID()
2667
+ };
2668
+ if (!secret) {
2669
+ const error = `vault secret "${target.secretName}" is missing`;
2670
+ await (0, import_crm4.recordDeliveryAttempt)(crmDeps3, {
2671
+ recordId: record.id,
2672
+ targetId: target.id,
2673
+ status: "failed",
2674
+ payloadVersion: 2,
2675
+ error
2676
+ });
2677
+ return { id: target.id, name: target.name, ok: false, error };
2678
+ }
2679
+ let payload;
2680
+ try {
2681
+ payload = sharedRecordFromCrm(ctx.chapter.crm, record, target, ctx.chapter.id);
2682
+ } catch (err) {
2683
+ return {
2684
+ id: target.id,
2685
+ name: target.name,
2686
+ ok: false,
2687
+ error: err instanceof Error ? err.message : "record is not shareable"
2688
+ };
2689
+ }
2690
+ const payloadBody = JSON.stringify(payload);
2691
+ const destination = new URL("/api/network/shared", target.url);
2692
+ try {
2693
+ const signed = await (0, import_db3.signFederatedRequest)({
2694
+ secret,
2695
+ sender: ctx.chapter.id,
2696
+ method: "POST",
2697
+ url: destination,
2698
+ body: payloadBody
2699
+ });
2700
+ const res = await fetchNetworkTarget(env, target, destination, {
2701
+ method: "POST",
2702
+ headers: { ...signed, "content-type": "application/json" },
2703
+ body: payloadBody,
2704
+ signal: AbortSignal.timeout(1e4)
2705
+ });
2706
+ const responseBody = await res.json().catch(() => ({}));
2707
+ if (!res.ok) {
2708
+ const error = responseBody.error ?? "follower rejected the record";
2709
+ await (0, import_crm4.recordDeliveryAttempt)(crmDeps3, {
2710
+ recordId: record.id,
2711
+ targetId: target.id,
2712
+ status: "failed",
2713
+ payloadVersion: 2,
2714
+ error
2715
+ });
2716
+ return {
2717
+ id: target.id,
2718
+ name: target.name,
2719
+ ok: false,
2720
+ status: res.status,
2721
+ error
2722
+ };
2723
+ }
2724
+ await (0, import_crm4.recordDeliveryAttempt)(crmDeps3, {
2725
+ recordId: record.id,
2726
+ targetId: target.id,
2727
+ status: "delivered",
2728
+ payloadVersion: 2,
2729
+ ...responseBody.recordId ? { remoteRecordId: responseBody.recordId } : {}
2730
+ });
2731
+ return {
2732
+ id: target.id,
2733
+ name: target.name,
2734
+ ok: true,
2735
+ status: res.status,
2736
+ recordId: responseBody.recordId
2737
+ };
2738
+ } catch (err) {
2739
+ const error = err instanceof Error ? err.message : "delivery failed";
2740
+ await (0, import_crm4.recordDeliveryAttempt)(crmDeps3, {
2741
+ recordId: record.id,
2742
+ targetId: target.id,
2743
+ status: "failed",
2744
+ payloadVersion: 2,
2745
+ error
2746
+ });
2747
+ return { id: target.id, name: target.name, ok: false, error };
2748
+ }
2749
+ }
2750
+
2751
+ // src/worker-routes-network.ts
2642
2752
  async function gate4(req, env, ctx) {
2643
2753
  const db = ctx.makeDb(env);
2644
2754
  const user = await ctx.verifyUser(req, env);
@@ -2664,10 +2774,10 @@ var handleNetworkSnapshot = async (req, url, env, ctx) => {
2664
2774
  const db = ctx.makeDb(env);
2665
2775
  const secret = await getVaultSecret(db, "network_share_secret");
2666
2776
  if (!secret) return json({ error: "unauthorized" }, 401);
2667
- const verified = await (0, import_db3.verifyFederatedRequest)(req, { secret });
2777
+ const verified = await (0, import_db4.verifyFederatedRequest)(req, { secret });
2668
2778
  if (!verified.ok) return json({ error: "unauthorized", reason: verified.reason }, 401);
2669
2779
  const types = await Promise.all(
2670
- Object.keys(ctx.chapter.crm.config.types).map((type) => (0, import_crm4.typeSummary)({ crm: ctx.chapter.crm, db }, type))
2780
+ Object.keys(ctx.chapter.crm.config.types).map((type) => (0, import_crm5.typeSummary)({ crm: ctx.chapter.crm, db }, type))
2671
2781
  );
2672
2782
  const snapshot = {
2673
2783
  version: 1,
@@ -2677,18 +2787,21 @@ var handleNetworkSnapshot = async (req, url, env, ctx) => {
2677
2787
  };
2678
2788
  return json(snapshot);
2679
2789
  };
2680
- async function snapshotOne(db, ctx, target) {
2790
+ async function snapshotOne(db, env, ctx, target) {
2681
2791
  const secret = await getVaultSecret(db, target.secretName);
2682
2792
  if (!secret) return { id: target.id, name: target.name, url: target.url, available: false, error: "edge secret is missing" };
2683
2793
  const destination = new URL("/api/network/snapshot", target.url);
2684
2794
  try {
2685
- const headers = await (0, import_db3.signFederatedRequest)({
2795
+ const headers = await (0, import_db4.signFederatedRequest)({
2686
2796
  secret,
2687
2797
  sender: ctx.chapter.id,
2688
2798
  method: "GET",
2689
2799
  url: destination
2690
2800
  });
2691
- const response = await fetch(destination, { headers, signal: AbortSignal.timeout(1e4) });
2801
+ const response = await fetchNetworkTarget(env, target, destination, {
2802
+ headers,
2803
+ signal: AbortSignal.timeout(1e4)
2804
+ });
2692
2805
  const body = await response.json().catch(() => null);
2693
2806
  if (!response.ok || !body || !("version" in body) || body.version !== 1 || !("site" in body) || body.site.id !== target.id || !Array.isArray(body.types)) {
2694
2807
  const upstream = body && "error" in body && typeof body.error === "string" ? body.error : void 0;
@@ -2723,7 +2836,7 @@ var handleAdminNetworkRollup = async (req, url, env, ctx) => {
2723
2836
  const got = await gate4(req, env, ctx);
2724
2837
  if ("response" in got) return got.response;
2725
2838
  const targets = await Promise.all(
2726
- ctx.chapter.network.targets.map((target) => snapshotOne(got.db, ctx, target))
2839
+ ctx.chapter.network.targets.map((target) => snapshotOne(got.db, env, ctx, target))
2727
2840
  );
2728
2841
  const byType = /* @__PURE__ */ new Map();
2729
2842
  for (const target of targets) {
@@ -2745,74 +2858,6 @@ var handleAdminNetworkRollup = async (req, url, env, ctx) => {
2745
2858
  };
2746
2859
  return json(rollup);
2747
2860
  };
2748
- async function pushOne(db, ctx, target, record) {
2749
- const secret = await getVaultSecret(db, target.secretName);
2750
- const crmDeps3 = { crm: ctx.chapter.crm, db, now: () => Date.now(), newId: () => crypto.randomUUID() };
2751
- if (!secret) {
2752
- const error = `vault secret "${target.secretName}" is missing`;
2753
- await (0, import_crm4.recordDeliveryAttempt)(crmDeps3, {
2754
- recordId: record.id,
2755
- targetId: target.id,
2756
- status: "failed",
2757
- payloadVersion: 2,
2758
- error
2759
- });
2760
- return { id: target.id, name: target.name, ok: false, error };
2761
- }
2762
- let payload;
2763
- try {
2764
- payload = sharedRecordFromCrm(ctx.chapter.crm, record, target, ctx.chapter.id);
2765
- } catch (err) {
2766
- return { id: target.id, name: target.name, ok: false, error: err instanceof Error ? err.message : "record is not shareable" };
2767
- }
2768
- const payloadBody = JSON.stringify(payload);
2769
- const destination = new URL("/api/network/shared", target.url);
2770
- try {
2771
- const signed = await (0, import_db3.signFederatedRequest)({
2772
- secret,
2773
- sender: ctx.chapter.id,
2774
- method: "POST",
2775
- url: destination,
2776
- body: payloadBody
2777
- });
2778
- const res = await fetch(destination, {
2779
- method: "POST",
2780
- headers: { ...signed, "content-type": "application/json" },
2781
- body: payloadBody,
2782
- signal: AbortSignal.timeout(1e4)
2783
- });
2784
- const responseBody = await res.json().catch(() => ({}));
2785
- if (!res.ok) {
2786
- const error = responseBody.error ?? "follower rejected the record";
2787
- await (0, import_crm4.recordDeliveryAttempt)(crmDeps3, {
2788
- recordId: record.id,
2789
- targetId: target.id,
2790
- status: "failed",
2791
- payloadVersion: 2,
2792
- error
2793
- });
2794
- return { id: target.id, name: target.name, ok: false, status: res.status, error };
2795
- }
2796
- await (0, import_crm4.recordDeliveryAttempt)(crmDeps3, {
2797
- recordId: record.id,
2798
- targetId: target.id,
2799
- status: "delivered",
2800
- payloadVersion: 2,
2801
- ...responseBody.recordId ? { remoteRecordId: responseBody.recordId } : {}
2802
- });
2803
- return { id: target.id, name: target.name, ok: true, status: res.status, recordId: responseBody.recordId };
2804
- } catch (err) {
2805
- const error = err instanceof Error ? err.message : "delivery failed";
2806
- await (0, import_crm4.recordDeliveryAttempt)(crmDeps3, {
2807
- recordId: record.id,
2808
- targetId: target.id,
2809
- status: "failed",
2810
- payloadVersion: 2,
2811
- error
2812
- });
2813
- return { id: target.id, name: target.name, ok: false, error };
2814
- }
2815
- }
2816
2861
  var handleAdminNetworkPush = async (req, url, env, ctx) => {
2817
2862
  if (req.method !== "POST" || url.pathname !== "/api/admin/network/push") return null;
2818
2863
  const got = await gate4(req, env, ctx);
@@ -2830,16 +2875,16 @@ var handleAdminNetworkPush = async (req, url, env, ctx) => {
2830
2875
  if (requested.size !== body.targetIds.length) return json({ error: "targetIds must contain unique strings" }, 400);
2831
2876
  const targets = ctx.chapter.network.targets.filter((target) => requested.has(target.id));
2832
2877
  if (targets.length !== requested.size) return json({ error: "one or more targetIds are not configured" }, 400);
2833
- const record = await (0, import_crm4.getRecord)({ crm: ctx.chapter.crm, db: got.db }, body.recordId);
2878
+ const record = await (0, import_crm5.getRecord)({ crm: ctx.chapter.crm, db: got.db }, body.recordId);
2834
2879
  if (!record) return json({ error: "record not found" }, 404);
2835
2880
  const results = await Promise.all(
2836
- targets.map((target) => pushOne(got.db, ctx, target, record))
2881
+ targets.map((target) => pushNetworkRecord(got.db, env, ctx, target, record))
2837
2882
  );
2838
2883
  return json({ ok: results.every((result) => result.ok), results });
2839
2884
  };
2840
2885
 
2841
2886
  // src/worker-routes-formation.ts
2842
- var import_crm5 = require("@odla-ai/crm");
2887
+ var import_crm6 = require("@odla-ai/crm");
2843
2888
 
2844
2889
  // src/formation.ts
2845
2890
  function formationFields(crm, formation) {
@@ -2905,7 +2950,7 @@ var handleFormation = async (req, url, env, ctx) => {
2905
2950
  const db = ctx.makeDb(env);
2906
2951
  const id = submissionId ? await applicationIdForSubmission(`formation:${ctx.chapter.id}:${submissionId}`) : crypto.randomUUID();
2907
2952
  try {
2908
- const created = await (0, import_crm5.createRecord)(
2953
+ const created = await (0, import_crm6.createRecord)(
2909
2954
  {
2910
2955
  crm: ctx.chapter.crm,
2911
2956
  db,