@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/worker/index.d.cts
CHANGED
|
@@ -117,16 +117,14 @@ interface ResolvedMemberContent {
|
|
|
117
117
|
interface ChapterBuilderLibrary {
|
|
118
118
|
/** Keep local admin authoring enabled. Defaults to true. */
|
|
119
119
|
localAuthoring?: boolean;
|
|
120
|
-
/**
|
|
120
|
+
/** Existing Chapter-network peers this app accepts. Hub sources must be
|
|
121
|
+
* configured network targets; a Chapter source must be a configured reader. */
|
|
121
122
|
sources?: readonly {
|
|
122
123
|
sourceId: string;
|
|
123
|
-
/** Vault key holding the dedicated Builder Library edge secret. */
|
|
124
|
-
secretName?: string;
|
|
125
124
|
}[];
|
|
126
125
|
}
|
|
127
126
|
interface ResolvedBuilderLibrarySource {
|
|
128
127
|
sourceId: string;
|
|
129
|
-
secretName: string;
|
|
130
128
|
}
|
|
131
129
|
/** Validated Builder Library settings carried on a resolved Chapter. */
|
|
132
130
|
interface ResolvedBuilderLibrary {
|
|
@@ -716,6 +714,9 @@ interface ChapterEnv {
|
|
|
716
714
|
* reads fail closed when it is absent or stale. */
|
|
717
715
|
ODLA_APP_INCARNATION?: string;
|
|
718
716
|
ODLA_ENV: string;
|
|
717
|
+
/** Immutable developer-runtime identity. Omitted by legacy deployments whose
|
|
718
|
+
* runtime and data environment are the same. */
|
|
719
|
+
ODLA_RUNTIME?: string;
|
|
719
720
|
ODLA_API_KEY: string;
|
|
720
721
|
SEND_EMAIL?: {
|
|
721
722
|
send(payload: EmailPayload): Promise<{
|
|
@@ -1123,13 +1124,15 @@ interface BuilderLibraryReceipt {
|
|
|
1123
1124
|
|
|
1124
1125
|
/** Inputs for one signed Builder Library peer delivery. */
|
|
1125
1126
|
interface BuilderLibraryDeliveryOptions {
|
|
1127
|
+
/** Existing Chapter-network share secret for this parent/chapter edge. */
|
|
1126
1128
|
secret: string;
|
|
1127
1129
|
sender: string;
|
|
1128
1130
|
targetUrl: string | URL;
|
|
1129
1131
|
envelope: BuilderLibraryEnvelope;
|
|
1130
1132
|
fetch?: typeof globalThis.fetch;
|
|
1131
1133
|
}
|
|
1132
|
-
/** Deliver one exact Builder Library revision over
|
|
1134
|
+
/** Deliver one exact Builder Library revision over the existing signed Chapter
|
|
1135
|
+
* network edge. No Builder-specific credential is created. */
|
|
1133
1136
|
declare function deliverBuilderLibrary(options: BuilderLibraryDeliveryOptions): Promise<BuilderLibraryReceipt>;
|
|
1134
1137
|
|
|
1135
1138
|
/** Current wire version for parent-authored admission decisions. */
|
package/dist/worker/index.d.ts
CHANGED
|
@@ -117,16 +117,14 @@ interface ResolvedMemberContent {
|
|
|
117
117
|
interface ChapterBuilderLibrary {
|
|
118
118
|
/** Keep local admin authoring enabled. Defaults to true. */
|
|
119
119
|
localAuthoring?: boolean;
|
|
120
|
-
/**
|
|
120
|
+
/** Existing Chapter-network peers this app accepts. Hub sources must be
|
|
121
|
+
* configured network targets; a Chapter source must be a configured reader. */
|
|
121
122
|
sources?: readonly {
|
|
122
123
|
sourceId: string;
|
|
123
|
-
/** Vault key holding the dedicated Builder Library edge secret. */
|
|
124
|
-
secretName?: string;
|
|
125
124
|
}[];
|
|
126
125
|
}
|
|
127
126
|
interface ResolvedBuilderLibrarySource {
|
|
128
127
|
sourceId: string;
|
|
129
|
-
secretName: string;
|
|
130
128
|
}
|
|
131
129
|
/** Validated Builder Library settings carried on a resolved Chapter. */
|
|
132
130
|
interface ResolvedBuilderLibrary {
|
|
@@ -716,6 +714,9 @@ interface ChapterEnv {
|
|
|
716
714
|
* reads fail closed when it is absent or stale. */
|
|
717
715
|
ODLA_APP_INCARNATION?: string;
|
|
718
716
|
ODLA_ENV: string;
|
|
717
|
+
/** Immutable developer-runtime identity. Omitted by legacy deployments whose
|
|
718
|
+
* runtime and data environment are the same. */
|
|
719
|
+
ODLA_RUNTIME?: string;
|
|
719
720
|
ODLA_API_KEY: string;
|
|
720
721
|
SEND_EMAIL?: {
|
|
721
722
|
send(payload: EmailPayload): Promise<{
|
|
@@ -1123,13 +1124,15 @@ interface BuilderLibraryReceipt {
|
|
|
1123
1124
|
|
|
1124
1125
|
/** Inputs for one signed Builder Library peer delivery. */
|
|
1125
1126
|
interface BuilderLibraryDeliveryOptions {
|
|
1127
|
+
/** Existing Chapter-network share secret for this parent/chapter edge. */
|
|
1126
1128
|
secret: string;
|
|
1127
1129
|
sender: string;
|
|
1128
1130
|
targetUrl: string | URL;
|
|
1129
1131
|
envelope: BuilderLibraryEnvelope;
|
|
1130
1132
|
fetch?: typeof globalThis.fetch;
|
|
1131
1133
|
}
|
|
1132
|
-
/** Deliver one exact Builder Library revision over
|
|
1134
|
+
/** Deliver one exact Builder Library revision over the existing signed Chapter
|
|
1135
|
+
* network edge. No Builder-specific credential is created. */
|
|
1133
1136
|
declare function deliverBuilderLibrary(options: BuilderLibraryDeliveryOptions): Promise<BuilderLibraryReceipt>;
|
|
1134
1137
|
|
|
1135
1138
|
/** Current wire version for parent-authored admission decisions. */
|
package/dist/worker/index.js
CHANGED
|
@@ -3354,12 +3354,16 @@ function findApplicationRef(obj) {
|
|
|
3354
3354
|
const applicationId = candidates.map(pick).find(Boolean);
|
|
3355
3355
|
const appId = candidates.map((metadata) => typeof metadata.odlaAppId === "string" ? metadata.odlaAppId : void 0).find(Boolean);
|
|
3356
3356
|
const environment = candidates.map((metadata) => typeof metadata.odlaEnvironment === "string" ? metadata.odlaEnvironment : void 0).find(Boolean);
|
|
3357
|
+
const dataEnvironment = candidates.map((metadata) => typeof metadata.odlaDataEnvironment === "string" ? metadata.odlaDataEnvironment : void 0).find(Boolean);
|
|
3358
|
+
const runtime = candidates.map((metadata) => typeof metadata.odlaRuntime === "string" ? metadata.odlaRuntime : void 0).find(Boolean);
|
|
3357
3359
|
const customerId = typeof obj.customer === "string" ? obj.customer : void 0;
|
|
3358
3360
|
return {
|
|
3359
3361
|
...applicationId ? { applicationId } : {},
|
|
3360
3362
|
...customerId ? { customerId } : {},
|
|
3361
3363
|
...appId ? { appId } : {},
|
|
3362
|
-
...environment ? { environment } : {}
|
|
3364
|
+
...environment ? { environment } : {},
|
|
3365
|
+
...dataEnvironment ? { dataEnvironment } : {},
|
|
3366
|
+
...runtime ? { runtime } : {}
|
|
3363
3367
|
};
|
|
3364
3368
|
}
|
|
3365
3369
|
function findGiftRef(obj) {
|
|
@@ -3369,17 +3373,31 @@ function findGiftRef(obj) {
|
|
|
3369
3373
|
const subscription = obj.subscription_details ?? parent?.subscription_details;
|
|
3370
3374
|
const giftIntentId = pick(metaOf(obj)) ?? pick(metaOf(subscription));
|
|
3371
3375
|
const subscriptionId = typeof obj.subscription === "string" ? obj.subscription : typeof subscription?.subscription === "string" ? String(subscription.subscription) : void 0;
|
|
3372
|
-
|
|
3376
|
+
const candidates = [metaOf(obj), metaOf(subscription)];
|
|
3377
|
+
const pickIdentity = (name) => candidates.map((metadata) => typeof metadata[name] === "string" ? String(metadata[name]) : void 0).find(Boolean);
|
|
3378
|
+
const appId = pickIdentity("odlaAppId");
|
|
3379
|
+
const environment = pickIdentity("odlaEnvironment");
|
|
3380
|
+
const dataEnvironment = pickIdentity("odlaDataEnvironment");
|
|
3381
|
+
const runtime = pickIdentity("odlaRuntime");
|
|
3382
|
+
return {
|
|
3383
|
+
...giftIntentId ? { giftIntentId } : {},
|
|
3384
|
+
providerObjectId: subscriptionId ?? String(obj.id ?? ""),
|
|
3385
|
+
...appId ? { appId } : {},
|
|
3386
|
+
...environment ? { environment } : {},
|
|
3387
|
+
...dataEnvironment ? { dataEnvironment } : {},
|
|
3388
|
+
...runtime ? { runtime } : {}
|
|
3389
|
+
};
|
|
3373
3390
|
}
|
|
3374
3391
|
function normalizeWebhookEvent(event) {
|
|
3375
3392
|
const obj = event.data?.object ?? {};
|
|
3376
3393
|
const gift = findGiftRef(obj);
|
|
3377
3394
|
if (gift.giftIntentId) {
|
|
3395
|
+
const { giftIntentId, providerObjectId, ...identity } = gift;
|
|
3378
3396
|
if (event.type === "payment_intent.succeeded" || event.type === "invoice.paid" && obj.billing_reason === "subscription_create") {
|
|
3379
|
-
return { kind: "gift_paid", giftIntentId
|
|
3397
|
+
return { kind: "gift_paid", giftIntentId, providerObjectId, ...identity };
|
|
3380
3398
|
}
|
|
3381
|
-
if (event.type === "charge.refunded") return { kind: "gift_revoked", giftIntentId
|
|
3382
|
-
if (event.type === "customer.subscription.deleted") return { kind: "gift_revoked", giftIntentId
|
|
3399
|
+
if (event.type === "charge.refunded") return { kind: "gift_revoked", giftIntentId, ...identity, reason: "refunded" };
|
|
3400
|
+
if (event.type === "customer.subscription.deleted") return { kind: "gift_revoked", giftIntentId, ...identity, reason: "canceled" };
|
|
3383
3401
|
return { kind: "ignored", type: event.type };
|
|
3384
3402
|
}
|
|
3385
3403
|
const ref = findApplicationRef(obj);
|
|
@@ -3456,7 +3474,9 @@ function createStripeProvider(config) {
|
|
|
3456
3474
|
groupId: input.groupId,
|
|
3457
3475
|
email: input.email,
|
|
3458
3476
|
odlaAppId: input.appId,
|
|
3459
|
-
odlaEnvironment: input.environment
|
|
3477
|
+
odlaEnvironment: input.environment,
|
|
3478
|
+
odlaDataEnvironment: input.environment,
|
|
3479
|
+
...input.runtime ? { odlaRuntime: input.runtime } : {}
|
|
3460
3480
|
};
|
|
3461
3481
|
let customerId = input.existingCustomerId;
|
|
3462
3482
|
if (!customerId) {
|
|
@@ -3744,12 +3764,16 @@ var clientSecret = (value) => {
|
|
|
3744
3764
|
const nested = confirmation?.client_secret ?? intent?.client_secret;
|
|
3745
3765
|
return typeof nested === "string" && nested ? nested : null;
|
|
3746
3766
|
};
|
|
3747
|
-
async function startGiftProviderCheckout(secretKey, intent, email, existingCustomerId) {
|
|
3767
|
+
async function startGiftProviderCheckout(secretKey, intent, email, existingCustomerId, runtime) {
|
|
3748
3768
|
const offer = intent.offerSnapshot;
|
|
3749
3769
|
const metadata = {
|
|
3750
3770
|
giftIntentId: intent.id,
|
|
3751
3771
|
chapterId: intent.chapterId,
|
|
3752
3772
|
environment: intent.environment,
|
|
3773
|
+
odlaAppId: intent.chapterId,
|
|
3774
|
+
odlaEnvironment: intent.environment,
|
|
3775
|
+
odlaDataEnvironment: intent.environment,
|
|
3776
|
+
...runtime ? { odlaRuntime: runtime } : {},
|
|
3753
3777
|
offerId: intent.offerId
|
|
3754
3778
|
};
|
|
3755
3779
|
let customerId = existingCustomerId;
|
|
@@ -3799,6 +3823,7 @@ async function startGiftIntent(db, input) {
|
|
|
3799
3823
|
id: input.id,
|
|
3800
3824
|
chapterId: input.chapterId,
|
|
3801
3825
|
environment: input.environment,
|
|
3826
|
+
...input.runtime ? { runtime: input.runtime } : {},
|
|
3802
3827
|
purchaserType: input.purchaserType,
|
|
3803
3828
|
purchaserEmailNormalized: input.purchaserEmailNormalized,
|
|
3804
3829
|
...input.purchaserApplicationId ? { purchaserApplicationId: input.purchaserApplicationId } : {},
|
|
@@ -3818,7 +3843,7 @@ async function startGiftIntent(db, input) {
|
|
|
3818
3843
|
stored = write.duplicate ? first2((await db.query({ giftPurchaseIntents: { $: { where: { id: input.id }, limit: 1 } } })).giftPurchaseIntents) : attrs;
|
|
3819
3844
|
if (!write.duplicate) giftCode = prepared.code;
|
|
3820
3845
|
}
|
|
3821
|
-
if (!stored || stored.chapterId !== input.chapterId || stored.environment !== input.environment || stored.offerId !== input.offer.id || stored.purchaserEmailNormalized !== input.purchaserEmailNormalized) {
|
|
3846
|
+
if (!stored || stored.chapterId !== input.chapterId || stored.environment !== input.environment || stored.runtime !== input.runtime || stored.offerId !== input.offer.id || stored.purchaserEmailNormalized !== input.purchaserEmailNormalized) {
|
|
3822
3847
|
throw new Error("gift purchase intent does not match this checkout");
|
|
3823
3848
|
}
|
|
3824
3849
|
if (stored.status === "paid") throw new Error("gift purchase is already paid");
|
|
@@ -3826,7 +3851,8 @@ async function startGiftIntent(db, input) {
|
|
|
3826
3851
|
input.stripeSecret,
|
|
3827
3852
|
stored,
|
|
3828
3853
|
input.purchaserEmail,
|
|
3829
|
-
typeof stored.providerCustomerId === "string" ? stored.providerCustomerId : input.existingCustomerId
|
|
3854
|
+
typeof stored.providerCustomerId === "string" ? stored.providerCustomerId : input.existingCustomerId,
|
|
3855
|
+
input.runtime
|
|
3830
3856
|
);
|
|
3831
3857
|
await db.transact([{ t: "update", ns: "giftPurchaseIntents", id: input.id, attrs: {
|
|
3832
3858
|
status: "checkout_ready",
|
|
@@ -3845,18 +3871,29 @@ async function startGiftIntent(db, input) {
|
|
|
3845
3871
|
};
|
|
3846
3872
|
}
|
|
3847
3873
|
|
|
3874
|
+
// src/stripe-runtime.ts
|
|
3875
|
+
function stripeWebhookSecretName(runtime) {
|
|
3876
|
+
if (!runtime) return "stripe_webhook_secret";
|
|
3877
|
+
if (!/^[a-z0-9]{2,12}$/.test(runtime) || runtime === "prod" || runtime === "production") {
|
|
3878
|
+
throw new Error("ODLA_RUNTIME is invalid");
|
|
3879
|
+
}
|
|
3880
|
+
return `stripe_webhook_secret__${runtime}`;
|
|
3881
|
+
}
|
|
3882
|
+
|
|
3883
|
+
// src/payments-route-support.ts
|
|
3884
|
+
var paymentErrorCode = (error) => error && typeof error === "object" && typeof error.code === "string" ? error.code : "unknown";
|
|
3885
|
+
function paymentLineItems(group) {
|
|
3886
|
+
const standard = Number(group.standardPriceCents ?? 0);
|
|
3887
|
+
const discount = Number(group.foundingDiscountCents ?? 0);
|
|
3888
|
+
return { standardCents: standard, discountCents: discount, dueTodayCents: standard - discount };
|
|
3889
|
+
}
|
|
3890
|
+
|
|
3848
3891
|
// src/worker-routes-payments.ts
|
|
3849
|
-
var codeOf = (err) => err && typeof err === "object" && typeof err.code === "string" ? err.code : "unknown";
|
|
3850
3892
|
async function firstRow2(db, ns, q) {
|
|
3851
3893
|
const res = await db.query({ [ns]: { $: q } });
|
|
3852
3894
|
const rows4 = res[ns];
|
|
3853
3895
|
return Array.isArray(rows4) ? rows4[0] : void 0;
|
|
3854
3896
|
}
|
|
3855
|
-
function lineItems(group) {
|
|
3856
|
-
const standard = Number(group.standardPriceCents ?? 0);
|
|
3857
|
-
const discount = Number(group.foundingDiscountCents ?? 0);
|
|
3858
|
-
return { standardCents: standard, discountCents: discount, dueTodayCents: standard - discount };
|
|
3859
|
-
}
|
|
3860
3897
|
async function findApplication(db, event) {
|
|
3861
3898
|
if ("applicationId" in event && event.applicationId) {
|
|
3862
3899
|
return firstRow2(db, "applications", { where: { id: event.applicationId }, limit: 1 });
|
|
@@ -3947,6 +3984,7 @@ async function startSubscription(req, env, ctx) {
|
|
|
3947
3984
|
chapterId: ctx.chapter.id,
|
|
3948
3985
|
environment: env.ODLA_ENV,
|
|
3949
3986
|
offer,
|
|
3987
|
+
...env.ODLA_RUNTIME ? { runtime: env.ODLA_RUNTIME } : {},
|
|
3950
3988
|
purchaserType: "application",
|
|
3951
3989
|
purchaserEmail: String(app.email ?? ""),
|
|
3952
3990
|
purchaserEmailNormalized: normalizeChapterEmail(String(app.email ?? "")),
|
|
@@ -3979,6 +4017,7 @@ async function startSubscription(req, env, ctx) {
|
|
|
3979
4017
|
result = await provider.createSubscription({
|
|
3980
4018
|
appId: env.ODLA_APP_ID,
|
|
3981
4019
|
environment: env.ODLA_ENV,
|
|
4020
|
+
...env.ODLA_RUNTIME ? { runtime: env.ODLA_RUNTIME } : {},
|
|
3982
4021
|
applicationId,
|
|
3983
4022
|
groupId: String(group.id),
|
|
3984
4023
|
email: String(app.email ?? ""),
|
|
@@ -3987,29 +4026,35 @@ async function startSubscription(req, env, ctx) {
|
|
|
3987
4026
|
existingCustomerId: typeof app.stripeCustomerId === "string" ? app.stripeCustomerId : void 0
|
|
3988
4027
|
});
|
|
3989
4028
|
} catch (err) {
|
|
3990
|
-
return json({ error: "payment setup failed", code:
|
|
4029
|
+
return json({ error: "payment setup failed", code: paymentErrorCode(err) }, 502);
|
|
3991
4030
|
}
|
|
3992
4031
|
await db.transact([
|
|
3993
4032
|
{
|
|
3994
4033
|
t: "update",
|
|
3995
4034
|
ns: "applications",
|
|
3996
4035
|
id: applicationId,
|
|
3997
|
-
attrs: {
|
|
4036
|
+
attrs: {
|
|
4037
|
+
stripeCustomerId: result.customerId,
|
|
4038
|
+
stripeSubscriptionId: result.subscriptionId,
|
|
4039
|
+
...env.ODLA_RUNTIME ? { stripeRuntime: env.ODLA_RUNTIME } : {},
|
|
4040
|
+
refundPolicyAckAt: Date.now()
|
|
4041
|
+
}
|
|
3998
4042
|
}
|
|
3999
4043
|
]);
|
|
4000
|
-
return json({ clientSecret: result.clientSecret, publishableKey: group.stripePublishableKey ?? null, lineItems:
|
|
4044
|
+
return json({ clientSecret: result.clientSecret, publishableKey: group.stripePublishableKey ?? null, lineItems: paymentLineItems(group) });
|
|
4001
4045
|
}
|
|
4002
4046
|
async function ingestWebhook(req, env, ctx) {
|
|
4003
4047
|
const db = ctx.makeDb(env);
|
|
4004
|
-
const webhookSecret = await getVaultSecret(db,
|
|
4048
|
+
const webhookSecret = await getVaultSecret(db, stripeWebhookSecretName(env.ODLA_RUNTIME));
|
|
4005
4049
|
if (!webhookSecret) return json({ error: "webhook not configured" }, 503);
|
|
4006
4050
|
const rawBody = await req.text();
|
|
4007
4051
|
const ingest = await createStripeProvider({ webhookSecret }).ingestWebhook(rawBody, req.headers.get("stripe-signature") ?? "");
|
|
4008
4052
|
if (!ingest.ok) return json({ error: "invalid signature" }, 400);
|
|
4009
4053
|
const { eventId, event } = ingest;
|
|
4010
4054
|
if (event.kind === "ignored") return json({ ok: true, ignored: event.type });
|
|
4011
|
-
const identifiedEnvironment = event.appId !== void 0 || event.environment !== void 0;
|
|
4012
|
-
|
|
4055
|
+
const identifiedEnvironment = event.appId !== void 0 || event.environment !== void 0 || event.dataEnvironment !== void 0 || event.runtime !== void 0;
|
|
4056
|
+
const eventDataEnvironment = event.dataEnvironment ?? event.environment;
|
|
4057
|
+
if (env.ODLA_APP_ID && identifiedEnvironment && (event.appId !== env.ODLA_APP_ID || eventDataEnvironment !== env.ODLA_ENV || event.runtime !== void 0 && event.runtime !== env.ODLA_RUNTIME)) {
|
|
4013
4058
|
return json({ ok: true, matched: false });
|
|
4014
4059
|
}
|
|
4015
4060
|
if (event.kind === "gift_paid" || event.kind === "gift_revoked") {
|
|
@@ -4017,6 +4062,9 @@ async function ingestWebhook(req, env, ctx) {
|
|
|
4017
4062
|
if (!intent || intent.chapterId !== ctx.chapter.id || intent.environment !== env.ODLA_ENV) {
|
|
4018
4063
|
return json({ ok: true, matched: false });
|
|
4019
4064
|
}
|
|
4065
|
+
if (event.runtime === void 0 && typeof intent.runtime === "string" && intent.runtime !== env.ODLA_RUNTIME) {
|
|
4066
|
+
return json({ ok: true, matched: false });
|
|
4067
|
+
}
|
|
4020
4068
|
if (event.kind === "gift_paid") {
|
|
4021
4069
|
if (intent.providerObjectId !== event.providerObjectId) return json({ ok: true, matched: false });
|
|
4022
4070
|
if (intent.status === "refunded" || intent.status === "canceled") return json({ ok: true, matched: false });
|
|
@@ -4040,6 +4088,9 @@ async function ingestWebhook(req, env, ctx) {
|
|
|
4040
4088
|
}
|
|
4041
4089
|
const app = await findApplication(db, event);
|
|
4042
4090
|
if (!app) return json({ ok: true, matched: false });
|
|
4091
|
+
if (event.runtime === void 0 && typeof app.stripeRuntime === "string" && app.stripeRuntime !== env.ODLA_RUNTIME) {
|
|
4092
|
+
return json({ ok: true, matched: false });
|
|
4093
|
+
}
|
|
4043
4094
|
const patch = webhookPatch(event, String(app.status ?? ""));
|
|
4044
4095
|
let next = app;
|
|
4045
4096
|
if (Object.keys(patch).length) {
|
|
@@ -4142,6 +4193,7 @@ var handleGifts = async (req, url, env, ctx) => {
|
|
|
4142
4193
|
offer,
|
|
4143
4194
|
purchaserType: "member",
|
|
4144
4195
|
purchaserEmail: user.email,
|
|
4196
|
+
...env.ODLA_RUNTIME ? { runtime: env.ODLA_RUNTIME } : {},
|
|
4145
4197
|
purchaserEmailNormalized: emailNormalized,
|
|
4146
4198
|
purchaserUserId: user.userId,
|
|
4147
4199
|
...typeof app?.stripeCustomerId === "string" ? { existingCustomerId: app.stripeCustomerId } : {},
|
|
@@ -6074,9 +6126,23 @@ async function saveLocalBuilderLibrary(db, document, environment, expectedRevisi
|
|
|
6074
6126
|
|
|
6075
6127
|
// src/worker-routes-builder-library.ts
|
|
6076
6128
|
var BODY_CAP2 = 1e6;
|
|
6077
|
-
async function verifySource(req, db,
|
|
6129
|
+
async function verifySource(req, db, ctx) {
|
|
6130
|
+
const sources = ctx.chapter.builderLibrary?.sources ?? [];
|
|
6131
|
+
if (ctx.chapter.mode === "chapter") {
|
|
6132
|
+
const secret = await getVaultSecret(db, "network_share_secret");
|
|
6133
|
+
if (!secret) return null;
|
|
6134
|
+
const verified = await verifyFederatedRequest8(req, {
|
|
6135
|
+
secret,
|
|
6136
|
+
senders: sources.map((source2) => source2.sourceId)
|
|
6137
|
+
});
|
|
6138
|
+
if (!verified.ok) return null;
|
|
6139
|
+
const source = sources.find((candidate) => candidate.sourceId === verified.sender);
|
|
6140
|
+
return source ? { source, body: verified.body } : null;
|
|
6141
|
+
}
|
|
6078
6142
|
for (const source of sources) {
|
|
6079
|
-
const
|
|
6143
|
+
const target = ctx.chapter.network.targets.find((candidate) => candidate.id === source.sourceId);
|
|
6144
|
+
if (!target) continue;
|
|
6145
|
+
const secret = await getVaultSecret(db, target.secretName);
|
|
6080
6146
|
if (!secret) continue;
|
|
6081
6147
|
const verified = await verifyFederatedRequest8(req.clone(), { secret, senders: [source.sourceId] });
|
|
6082
6148
|
if (verified.ok) return { source, body: verified.body };
|
|
@@ -6088,7 +6154,7 @@ var handleBuilderLibraryControl = async (req, url, env, ctx) => {
|
|
|
6088
6154
|
const settings = ctx.chapter.builderLibrary;
|
|
6089
6155
|
if (!settings) return json({ error: "not found" }, 404);
|
|
6090
6156
|
const db = ctx.makeDb(env);
|
|
6091
|
-
const verified = await verifySource(req, db,
|
|
6157
|
+
const verified = await verifySource(req, db, ctx);
|
|
6092
6158
|
if (!verified) return json({ error: "unauthorized" }, 401);
|
|
6093
6159
|
let input;
|
|
6094
6160
|
try {
|