@odla-ai/chapter 0.39.1 → 0.40.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 +18 -5
- package/dist/{copy-context-Buz_27Ed.d.ts → copy-context-Dbu9Bbq1.d.ts} +2 -4
- package/dist/index.cjs +40 -20
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +9 -6
- package/dist/index.d.ts +9 -6
- package/dist/index.js +40 -20
- package/dist/index.js.map +1 -1
- package/dist/ui/admin/index.d.ts +2 -2
- package/dist/ui/index.d.ts +1 -1
- package/dist/ui/member/index.d.ts +2 -2
- package/dist/worker/index.cjs +90 -24
- package/dist/worker/index.cjs.map +1 -1
- package/dist/worker/index.d.cts +8 -5
- package/dist/worker/index.d.ts +8 -5
- package/dist/worker/index.js +90 -24
- package/dist/worker/index.js.map +1 -1
- package/package.json +1 -1
- package/runbooks/greenfield.md +21 -4
package/dist/index.d.cts
CHANGED
|
@@ -207,16 +207,14 @@ interface ResolvedMemberContent {
|
|
|
207
207
|
interface ChapterBuilderLibrary {
|
|
208
208
|
/** Keep local admin authoring enabled. Defaults to true. */
|
|
209
209
|
localAuthoring?: boolean;
|
|
210
|
-
/**
|
|
210
|
+
/** Existing Chapter-network peers this app accepts. Hub sources must be
|
|
211
|
+
* configured network targets; a Chapter source must be a configured reader. */
|
|
211
212
|
sources?: readonly {
|
|
212
213
|
sourceId: string;
|
|
213
|
-
/** Vault key holding the dedicated Builder Library edge secret. */
|
|
214
|
-
secretName?: string;
|
|
215
214
|
}[];
|
|
216
215
|
}
|
|
217
216
|
interface ResolvedBuilderLibrarySource {
|
|
218
217
|
sourceId: string;
|
|
219
|
-
secretName: string;
|
|
220
218
|
}
|
|
221
219
|
/** Validated Builder Library settings carried on a resolved Chapter. */
|
|
222
220
|
interface ResolvedBuilderLibrary {
|
|
@@ -796,8 +794,9 @@ declare function resolveSignupControl(input: ChapterSignupControl | undefined):
|
|
|
796
794
|
/** Validate the deliberately separate member-content authoring boundary. */
|
|
797
795
|
declare function resolveMemberContent(input: ChapterMemberContent | undefined): ResolvedMemberContent | null;
|
|
798
796
|
|
|
799
|
-
/** Validate the private Builder Library
|
|
800
|
-
|
|
797
|
+
/** Validate the private Builder Library boundary against Chapter's existing
|
|
798
|
+
* network peers. Builder Library never introduces a second edge credential. */
|
|
799
|
+
declare function resolveBuilderLibrary(mode: ChapterMode, input: ChapterBuilderLibrary | undefined, network?: ResolvedNetwork): ResolvedBuilderLibrary | null;
|
|
801
800
|
|
|
802
801
|
/** Options for {@link leaderCrmConfig}. */
|
|
803
802
|
interface LeaderCrmOptions {
|
|
@@ -1545,6 +1544,8 @@ type WebhookEvent = ({
|
|
|
1545
1544
|
}) & {
|
|
1546
1545
|
appId?: string;
|
|
1547
1546
|
environment?: string;
|
|
1547
|
+
dataEnvironment?: string;
|
|
1548
|
+
runtime?: string;
|
|
1548
1549
|
};
|
|
1549
1550
|
/** Resolve the application reference on a Stripe object: `applicationId` from
|
|
1550
1551
|
* metadata (direct, then subscription_details, then nested
|
|
@@ -1554,6 +1555,8 @@ declare function findApplicationRef(obj: Record<string, unknown>): {
|
|
|
1554
1555
|
customerId?: string;
|
|
1555
1556
|
appId?: string;
|
|
1556
1557
|
environment?: string;
|
|
1558
|
+
dataEnvironment?: string;
|
|
1559
|
+
runtime?: string;
|
|
1557
1560
|
};
|
|
1558
1561
|
/** Normalize a verified Stripe event into a {@link WebhookEvent}. `invoice.paid`
|
|
1559
1562
|
* splits into first_payment vs renewal by `billing_reason`; refunds and
|
package/dist/index.d.ts
CHANGED
|
@@ -207,16 +207,14 @@ interface ResolvedMemberContent {
|
|
|
207
207
|
interface ChapterBuilderLibrary {
|
|
208
208
|
/** Keep local admin authoring enabled. Defaults to true. */
|
|
209
209
|
localAuthoring?: boolean;
|
|
210
|
-
/**
|
|
210
|
+
/** Existing Chapter-network peers this app accepts. Hub sources must be
|
|
211
|
+
* configured network targets; a Chapter source must be a configured reader. */
|
|
211
212
|
sources?: readonly {
|
|
212
213
|
sourceId: string;
|
|
213
|
-
/** Vault key holding the dedicated Builder Library edge secret. */
|
|
214
|
-
secretName?: string;
|
|
215
214
|
}[];
|
|
216
215
|
}
|
|
217
216
|
interface ResolvedBuilderLibrarySource {
|
|
218
217
|
sourceId: string;
|
|
219
|
-
secretName: string;
|
|
220
218
|
}
|
|
221
219
|
/** Validated Builder Library settings carried on a resolved Chapter. */
|
|
222
220
|
interface ResolvedBuilderLibrary {
|
|
@@ -796,8 +794,9 @@ declare function resolveSignupControl(input: ChapterSignupControl | undefined):
|
|
|
796
794
|
/** Validate the deliberately separate member-content authoring boundary. */
|
|
797
795
|
declare function resolveMemberContent(input: ChapterMemberContent | undefined): ResolvedMemberContent | null;
|
|
798
796
|
|
|
799
|
-
/** Validate the private Builder Library
|
|
800
|
-
|
|
797
|
+
/** Validate the private Builder Library boundary against Chapter's existing
|
|
798
|
+
* network peers. Builder Library never introduces a second edge credential. */
|
|
799
|
+
declare function resolveBuilderLibrary(mode: ChapterMode, input: ChapterBuilderLibrary | undefined, network?: ResolvedNetwork): ResolvedBuilderLibrary | null;
|
|
801
800
|
|
|
802
801
|
/** Options for {@link leaderCrmConfig}. */
|
|
803
802
|
interface LeaderCrmOptions {
|
|
@@ -1545,6 +1544,8 @@ type WebhookEvent = ({
|
|
|
1545
1544
|
}) & {
|
|
1546
1545
|
appId?: string;
|
|
1547
1546
|
environment?: string;
|
|
1547
|
+
dataEnvironment?: string;
|
|
1548
|
+
runtime?: string;
|
|
1548
1549
|
};
|
|
1549
1550
|
/** Resolve the application reference on a Stripe object: `applicationId` from
|
|
1550
1551
|
* metadata (direct, then subscription_details, then nested
|
|
@@ -1554,6 +1555,8 @@ declare function findApplicationRef(obj: Record<string, unknown>): {
|
|
|
1554
1555
|
customerId?: string;
|
|
1555
1556
|
appId?: string;
|
|
1556
1557
|
environment?: string;
|
|
1558
|
+
dataEnvironment?: string;
|
|
1559
|
+
runtime?: string;
|
|
1557
1560
|
};
|
|
1558
1561
|
/** Normalize a verified Stripe event into a {@link WebhookEvent}. `invoice.paid`
|
|
1559
1562
|
* splits into first_payment vs renewal by `billing_reason`; refunds and
|
package/dist/index.js
CHANGED
|
@@ -215,6 +215,7 @@ var applicationAttrs = {
|
|
|
215
215
|
tierId: attr("string", { indexed: true, optional: true }),
|
|
216
216
|
stripeCustomerId: attr("string", { indexed: true, optional: true }),
|
|
217
217
|
stripeSubscriptionId: attr("string", { indexed: true, optional: true }),
|
|
218
|
+
stripeRuntime: attr("string", { indexed: true, optional: true }),
|
|
218
219
|
renewalAt: attr("number", { optional: true }),
|
|
219
220
|
disclaimerAckAt: attr("number", { optional: true }),
|
|
220
221
|
refundPolicyAckAt: attr("number", { optional: true }),
|
|
@@ -310,6 +311,7 @@ var giftPurchaseIntentsEntity = { attrs: {
|
|
|
310
311
|
id: id2(),
|
|
311
312
|
chapterId: attr3("string", { indexed: true }),
|
|
312
313
|
environment: attr3("string", { indexed: true }),
|
|
314
|
+
runtime: attr3("string", { optional: true, indexed: true }),
|
|
313
315
|
purchaserType: attr3("string", { indexed: true }),
|
|
314
316
|
purchaserApplicationId: attr3("string", { optional: true, indexed: true }),
|
|
315
317
|
purchaserUserId: attr3("string", { optional: true, indexed: true }),
|
|
@@ -1523,8 +1525,7 @@ function resolveMemberContent(input) {
|
|
|
1523
1525
|
|
|
1524
1526
|
// src/config-builder-library.ts
|
|
1525
1527
|
var SLUG4 = /^[a-z0-9][a-z0-9-]{1,62}$/;
|
|
1526
|
-
|
|
1527
|
-
function resolveBuilderLibrary(mode, input) {
|
|
1528
|
+
function resolveBuilderLibrary(mode, input, network = { targets: [], readers: [] }) {
|
|
1528
1529
|
if (!input) return null;
|
|
1529
1530
|
if (input.sources !== void 0 && !Array.isArray(input.sources)) {
|
|
1530
1531
|
throw new Error("defineChapter.builderLibrary.sources: must be an array");
|
|
@@ -1544,11 +1545,19 @@ function resolveBuilderLibrary(mode, input) {
|
|
|
1544
1545
|
throw new Error(`defineChapter.builderLibrary.sources: duplicate source "${source.sourceId}"`);
|
|
1545
1546
|
}
|
|
1546
1547
|
seen.add(source.sourceId);
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1548
|
+
if ("secretName" in source) {
|
|
1549
|
+
throw new Error(
|
|
1550
|
+
`defineChapter.builderLibrary.sources[${index}].secretName: remove this field; Builder Library reuses the Chapter network edge`
|
|
1551
|
+
);
|
|
1552
|
+
}
|
|
1553
|
+
const networkPeer = mode === "hub" ? network.targets.some((target) => target.id === source.sourceId) : network.readers.some((reader) => reader.id === source.sourceId);
|
|
1554
|
+
if (!networkPeer) {
|
|
1555
|
+
const side = mode === "hub" ? "targets" : "readers";
|
|
1556
|
+
throw new Error(
|
|
1557
|
+
`defineChapter.builderLibrary.sources[${index}]: "${source.sourceId}" must already be configured in network.${side}`
|
|
1558
|
+
);
|
|
1550
1559
|
}
|
|
1551
|
-
return { sourceId: source.sourceId
|
|
1560
|
+
return { sourceId: source.sourceId };
|
|
1552
1561
|
});
|
|
1553
1562
|
return { enabled: true, localAuthoring: input.localAuthoring !== false, sources };
|
|
1554
1563
|
}
|
|
@@ -1587,7 +1596,7 @@ function defineChapter(config) {
|
|
|
1587
1596
|
const network = resolveNetwork(config, crm);
|
|
1588
1597
|
const signupControl = resolveSignupControl(config.signupControl);
|
|
1589
1598
|
const memberContent = resolveMemberContent(config.memberContent);
|
|
1590
|
-
const builderLibrary = resolveBuilderLibrary(mode, config.builderLibrary);
|
|
1599
|
+
const builderLibrary = resolveBuilderLibrary(mode, config.builderLibrary, network);
|
|
1591
1600
|
const formation = resolveLeaderFormation(config.formation, crm);
|
|
1592
1601
|
if (signupControl && mode !== "chapter") {
|
|
1593
1602
|
throw new Error("defineChapter.signupControl: only chapter-mode followers can receive signup control");
|
|
@@ -1911,13 +1920,6 @@ function createChapterIntegration(chapter, options = {}) {
|
|
|
1911
1920
|
...emails?.debugEmail ? { debugEmail: emails.debugEmail } : {}
|
|
1912
1921
|
});
|
|
1913
1922
|
const seeds = [...crmDesc.seeds ?? []];
|
|
1914
|
-
const builderLibrarySecrets = [...new Set(
|
|
1915
|
-
chapter.builderLibrary?.sources.map((source) => source.secretName) ?? []
|
|
1916
|
-
)].map((name) => ({
|
|
1917
|
-
name,
|
|
1918
|
-
description: "Signing secret for private Builder Library delivery from a configured source.",
|
|
1919
|
-
required: true
|
|
1920
|
-
}));
|
|
1921
1923
|
const group = chapter.groupSeed();
|
|
1922
1924
|
if (group) {
|
|
1923
1925
|
seeds.push({ id: "group", ns: "groups", key: { attr: "id", value: chapter.id }, attrs: { ...group, createdAt: now } });
|
|
@@ -1950,7 +1952,7 @@ function createChapterIntegration(chapter, options = {}) {
|
|
|
1950
1952
|
},
|
|
1951
1953
|
rules: { ...crmDesc.rules, ...chapter.rules },
|
|
1952
1954
|
seeds,
|
|
1953
|
-
secrets:
|
|
1955
|
+
secrets: [],
|
|
1954
1956
|
probes: [
|
|
1955
1957
|
...crmDesc.probes ?? [],
|
|
1956
1958
|
// The snapshot route is deliberately private. A credential-free smoke
|
|
@@ -2655,12 +2657,16 @@ function findApplicationRef(obj) {
|
|
|
2655
2657
|
const applicationId = candidates.map(pick).find(Boolean);
|
|
2656
2658
|
const appId = candidates.map((metadata) => typeof metadata.odlaAppId === "string" ? metadata.odlaAppId : void 0).find(Boolean);
|
|
2657
2659
|
const environment = candidates.map((metadata) => typeof metadata.odlaEnvironment === "string" ? metadata.odlaEnvironment : void 0).find(Boolean);
|
|
2660
|
+
const dataEnvironment = candidates.map((metadata) => typeof metadata.odlaDataEnvironment === "string" ? metadata.odlaDataEnvironment : void 0).find(Boolean);
|
|
2661
|
+
const runtime = candidates.map((metadata) => typeof metadata.odlaRuntime === "string" ? metadata.odlaRuntime : void 0).find(Boolean);
|
|
2658
2662
|
const customerId = typeof obj.customer === "string" ? obj.customer : void 0;
|
|
2659
2663
|
return {
|
|
2660
2664
|
...applicationId ? { applicationId } : {},
|
|
2661
2665
|
...customerId ? { customerId } : {},
|
|
2662
2666
|
...appId ? { appId } : {},
|
|
2663
|
-
...environment ? { environment } : {}
|
|
2667
|
+
...environment ? { environment } : {},
|
|
2668
|
+
...dataEnvironment ? { dataEnvironment } : {},
|
|
2669
|
+
...runtime ? { runtime } : {}
|
|
2664
2670
|
};
|
|
2665
2671
|
}
|
|
2666
2672
|
function findGiftRef(obj) {
|
|
@@ -2670,17 +2676,31 @@ function findGiftRef(obj) {
|
|
|
2670
2676
|
const subscription = obj.subscription_details ?? parent?.subscription_details;
|
|
2671
2677
|
const giftIntentId = pick(metaOf(obj)) ?? pick(metaOf(subscription));
|
|
2672
2678
|
const subscriptionId = typeof obj.subscription === "string" ? obj.subscription : typeof subscription?.subscription === "string" ? String(subscription.subscription) : void 0;
|
|
2673
|
-
|
|
2679
|
+
const candidates = [metaOf(obj), metaOf(subscription)];
|
|
2680
|
+
const pickIdentity = (name) => candidates.map((metadata) => typeof metadata[name] === "string" ? String(metadata[name]) : void 0).find(Boolean);
|
|
2681
|
+
const appId = pickIdentity("odlaAppId");
|
|
2682
|
+
const environment = pickIdentity("odlaEnvironment");
|
|
2683
|
+
const dataEnvironment = pickIdentity("odlaDataEnvironment");
|
|
2684
|
+
const runtime = pickIdentity("odlaRuntime");
|
|
2685
|
+
return {
|
|
2686
|
+
...giftIntentId ? { giftIntentId } : {},
|
|
2687
|
+
providerObjectId: subscriptionId ?? String(obj.id ?? ""),
|
|
2688
|
+
...appId ? { appId } : {},
|
|
2689
|
+
...environment ? { environment } : {},
|
|
2690
|
+
...dataEnvironment ? { dataEnvironment } : {},
|
|
2691
|
+
...runtime ? { runtime } : {}
|
|
2692
|
+
};
|
|
2674
2693
|
}
|
|
2675
2694
|
function normalizeWebhookEvent(event) {
|
|
2676
2695
|
const obj = event.data?.object ?? {};
|
|
2677
2696
|
const gift = findGiftRef(obj);
|
|
2678
2697
|
if (gift.giftIntentId) {
|
|
2698
|
+
const { giftIntentId, providerObjectId, ...identity } = gift;
|
|
2679
2699
|
if (event.type === "payment_intent.succeeded" || event.type === "invoice.paid" && obj.billing_reason === "subscription_create") {
|
|
2680
|
-
return { kind: "gift_paid", giftIntentId
|
|
2700
|
+
return { kind: "gift_paid", giftIntentId, providerObjectId, ...identity };
|
|
2681
2701
|
}
|
|
2682
|
-
if (event.type === "charge.refunded") return { kind: "gift_revoked", giftIntentId
|
|
2683
|
-
if (event.type === "customer.subscription.deleted") return { kind: "gift_revoked", giftIntentId
|
|
2702
|
+
if (event.type === "charge.refunded") return { kind: "gift_revoked", giftIntentId, ...identity, reason: "refunded" };
|
|
2703
|
+
if (event.type === "customer.subscription.deleted") return { kind: "gift_revoked", giftIntentId, ...identity, reason: "canceled" };
|
|
2684
2704
|
return { kind: "ignored", type: event.type };
|
|
2685
2705
|
}
|
|
2686
2706
|
const ref = findApplicationRef(obj);
|