@shdan/submesh 0.1.0 → 1.0.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 +2 -2
- package/dist/contracts.d.ts +39 -2
- package/dist/contracts.d.ts.map +1 -1
- package/dist/drizzle/ensure-schema.d.ts.map +1 -1
- package/dist/drizzle/ensure-schema.js +12 -0
- package/dist/drizzle/ensure-schema.js.map +1 -1
- package/dist/drizzle/schema.d.ts.map +1 -1
- package/dist/drizzle/schema.js +4 -1
- package/dist/drizzle/schema.js.map +1 -1
- package/dist/drizzle/subject-repository.d.ts.map +1 -1
- package/dist/drizzle/subject-repository.js +7 -3
- package/dist/drizzle/subject-repository.js.map +1 -1
- package/dist/drizzle/summary-repository.d.ts.map +1 -1
- package/dist/drizzle/summary-repository.js +16 -7
- package/dist/drizzle/summary-repository.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/logger.d.ts +27 -0
- package/dist/logger.d.ts.map +1 -1
- package/dist/logger.js +61 -0
- package/dist/logger.js.map +1 -1
- package/dist/plugins/builtin-plugins.d.ts.map +1 -1
- package/dist/plugins/builtin-plugins.js +2 -1
- package/dist/plugins/builtin-plugins.js.map +1 -1
- package/dist/providers/stripe/plugin/stripe-plan-sync.d.ts +4 -0
- package/dist/providers/stripe/plugin/stripe-plan-sync.d.ts.map +1 -0
- package/dist/providers/stripe/plugin/stripe-plan-sync.js +83 -0
- package/dist/providers/stripe/plugin/stripe-plan-sync.js.map +1 -0
- package/dist/providers/stripe/plugin/stripe.d.ts +20 -0
- package/dist/providers/stripe/plugin/stripe.d.ts.map +1 -0
- package/dist/providers/stripe/plugin/stripe.js +238 -0
- package/dist/providers/stripe/plugin/stripe.js.map +1 -0
- package/dist/providers/stripe/security/stripe-signature-verification.d.ts +3 -0
- package/dist/providers/stripe/security/stripe-signature-verification.d.ts.map +1 -0
- package/dist/providers/stripe/security/stripe-signature-verification.js +162 -0
- package/dist/providers/stripe/security/stripe-signature-verification.js.map +1 -0
- package/dist/providers/stripe/services/stripe-subscription-verification-service.d.ts +3 -0
- package/dist/providers/stripe/services/stripe-subscription-verification-service.d.ts.map +1 -0
- package/dist/providers/stripe/services/stripe-subscription-verification-service.js +65 -0
- package/dist/providers/stripe/services/stripe-subscription-verification-service.js.map +1 -0
- package/dist/services/managed-subscription-service.d.ts +2 -1
- package/dist/services/managed-subscription-service.d.ts.map +1 -1
- package/dist/services/managed-subscription-service.js +7 -1
- package/dist/services/managed-subscription-service.js.map +1 -1
- package/dist/services/plan-provisioning-service.d.ts +2 -1
- package/dist/services/plan-provisioning-service.d.ts.map +1 -1
- package/dist/services/plan-provisioning-service.js +16 -1
- package/dist/services/plan-provisioning-service.js.map +1 -1
- package/dist/services/provider-subscription-sync-service.d.ts +2 -1
- package/dist/services/provider-subscription-sync-service.d.ts.map +1 -1
- package/dist/services/provider-subscription-sync-service.js +7 -1
- package/dist/services/provider-subscription-sync-service.js.map +1 -1
- package/dist/services/retry-event-replay.d.ts +4 -0
- package/dist/services/retry-event-replay.d.ts.map +1 -0
- package/dist/services/retry-event-replay.js +53 -0
- package/dist/services/retry-event-replay.js.map +1 -0
- package/dist/services/webhook-ingestion-service.d.ts.map +1 -1
- package/dist/services/webhook-ingestion-service.js +23 -7
- package/dist/services/webhook-ingestion-service.js.map +1 -1
- package/dist/submesh.d.ts +15 -1
- package/dist/submesh.d.ts.map +1 -1
- package/dist/submesh.js +117 -27
- package/dist/submesh.js.map +1 -1
- package/dist/utils/validation.d.ts +6 -0
- package/dist/utils/validation.d.ts.map +1 -1
- package/dist/utils/validation.js +7 -1
- package/dist/utils/validation.js.map +1 -1
- package/drizzle/0001_steady_perf_indexes.sql +8 -0
- package/drizzle/meta/_journal.json +7 -0
- package/package.json +10 -10
- package/LICENSE +0 -21
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stripe.d.ts","sourceRoot":"","sources":["../../../../src/providers/stripe/plugin/stripe.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAEV,kBAAkB,EAEnB,MAAM,qBAAqB,CAAC;AAE7B,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAgRhE,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;CAkCyB,CAAC"}
|
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
import { verifyStripeWebhook } from "../security/stripe-signature-verification.js";
|
|
3
|
+
import { verifyTrustedRelayWebhook } from "../../../security/plugin-webhook-verification.js";
|
|
4
|
+
import { hashPayload } from "../../../plugins/hash-payload.js";
|
|
5
|
+
import { deprovisionStripePlan, provisionStripePlan } from "./stripe-plan-sync.js";
|
|
6
|
+
function asObject(value) {
|
|
7
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
8
|
+
return {};
|
|
9
|
+
}
|
|
10
|
+
return value;
|
|
11
|
+
}
|
|
12
|
+
function getString(value) {
|
|
13
|
+
return typeof value === "string" && value.length > 0 ? value : undefined;
|
|
14
|
+
}
|
|
15
|
+
function getBoolean(value) {
|
|
16
|
+
return typeof value === "boolean" ? value : undefined;
|
|
17
|
+
}
|
|
18
|
+
function getNumericString(value) {
|
|
19
|
+
if (typeof value === "number" && Number.isFinite(value)) {
|
|
20
|
+
return value.toString();
|
|
21
|
+
}
|
|
22
|
+
return getString(value);
|
|
23
|
+
}
|
|
24
|
+
function toStripeDateString(value) {
|
|
25
|
+
const raw = getNumericString(value);
|
|
26
|
+
if (raw) {
|
|
27
|
+
const numeric = Number(raw);
|
|
28
|
+
if (Number.isFinite(numeric)) {
|
|
29
|
+
return raw.length >= 13
|
|
30
|
+
? new Date(numeric).toISOString()
|
|
31
|
+
: new Date(numeric * 1000).toISOString();
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return getString(value) ?? null;
|
|
35
|
+
}
|
|
36
|
+
function isFutureTimestamp(value) {
|
|
37
|
+
if (!value) {
|
|
38
|
+
return false;
|
|
39
|
+
}
|
|
40
|
+
const time = Date.parse(value);
|
|
41
|
+
return Number.isFinite(time) && time > Date.now();
|
|
42
|
+
}
|
|
43
|
+
function normalizeStripeStatus(input) {
|
|
44
|
+
if (input.eventType === "customer.subscription.deleted") {
|
|
45
|
+
return "canceled";
|
|
46
|
+
}
|
|
47
|
+
if (input.eventType === "customer.subscription.paused") {
|
|
48
|
+
return "paused";
|
|
49
|
+
}
|
|
50
|
+
if (input.eventType === "customer.subscription.resumed") {
|
|
51
|
+
return "active";
|
|
52
|
+
}
|
|
53
|
+
if (input.eventType === "customer.subscription.trial_will_end") {
|
|
54
|
+
return "trialing";
|
|
55
|
+
}
|
|
56
|
+
switch (input.status) {
|
|
57
|
+
case "trialing":
|
|
58
|
+
return "trialing";
|
|
59
|
+
case "active":
|
|
60
|
+
return "active";
|
|
61
|
+
case "past_due":
|
|
62
|
+
case "unpaid":
|
|
63
|
+
return "billing_issue";
|
|
64
|
+
case "paused":
|
|
65
|
+
return "paused";
|
|
66
|
+
case "incomplete":
|
|
67
|
+
case "incomplete_expired":
|
|
68
|
+
return "canceled";
|
|
69
|
+
case "canceled":
|
|
70
|
+
return input.cancelAtPeriodEnd && isFutureTimestamp(input.currentPeriodEnd)
|
|
71
|
+
? "active"
|
|
72
|
+
: "canceled";
|
|
73
|
+
default:
|
|
74
|
+
return "active";
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
function parsePayload(body) {
|
|
78
|
+
if (typeof body === "string") {
|
|
79
|
+
return asObject(JSON.parse(body));
|
|
80
|
+
}
|
|
81
|
+
if (body && typeof body === "object" && !Array.isArray(body)) {
|
|
82
|
+
return body;
|
|
83
|
+
}
|
|
84
|
+
throw new Error("Stripe plugin expects a JSON object payload.");
|
|
85
|
+
}
|
|
86
|
+
function resolveExternalProductId(payload, subscription) {
|
|
87
|
+
const items = asObject(subscription.items);
|
|
88
|
+
const data = Array.isArray(items.data)
|
|
89
|
+
? items.data.filter((entry) => Boolean(entry) && typeof entry === "object" && !Array.isArray(entry))
|
|
90
|
+
: [];
|
|
91
|
+
const firstItem = asObject(data[0]);
|
|
92
|
+
const price = asObject(firstItem.price || subscription.price || subscription.plan);
|
|
93
|
+
return (getString(payload.externalProductId) ??
|
|
94
|
+
getString(payload.priceId) ??
|
|
95
|
+
getString(payload.productId) ??
|
|
96
|
+
getString(price.id) ??
|
|
97
|
+
getString(price.product) ??
|
|
98
|
+
getString(asObject(price.product).id));
|
|
99
|
+
}
|
|
100
|
+
function resolveExternalCustomerId(payload, subscription) {
|
|
101
|
+
const customer = subscription.customer;
|
|
102
|
+
return (getString(payload.externalCustomerId) ??
|
|
103
|
+
getString(payload.externalSubjectId) ??
|
|
104
|
+
getString(payload.customerId) ??
|
|
105
|
+
getString(customer) ??
|
|
106
|
+
getString(asObject(customer).id));
|
|
107
|
+
}
|
|
108
|
+
function buildRecord(input) {
|
|
109
|
+
const metadata = asObject(input.subscription.metadata);
|
|
110
|
+
const currentPeriodStart = toStripeDateString(input.subscription.current_period_start) ??
|
|
111
|
+
toStripeDateString(input.payload.currentPeriodStart);
|
|
112
|
+
const currentPeriodEnd = toStripeDateString(input.subscription.current_period_end) ??
|
|
113
|
+
toStripeDateString(input.payload.currentPeriodEnd);
|
|
114
|
+
const cancelAtPeriodEnd = getBoolean(input.subscription.cancel_at_period_end) ?? false;
|
|
115
|
+
const cancelAt = toStripeDateString(input.subscription.cancel_at) ??
|
|
116
|
+
toStripeDateString(input.payload.cancelAt) ??
|
|
117
|
+
(cancelAtPeriodEnd && isFutureTimestamp(currentPeriodEnd) ? currentPeriodEnd : null);
|
|
118
|
+
const externalCustomerId = resolveExternalCustomerId(input.payload, input.subscription);
|
|
119
|
+
return {
|
|
120
|
+
pluginKey: "stripe",
|
|
121
|
+
sourceType: getString(input.payload.sourceType) ?? "stripe",
|
|
122
|
+
sourceRef: input.sourceRef,
|
|
123
|
+
status: normalizeStripeStatus({
|
|
124
|
+
status: getString(input.subscription.status) ?? getString(input.payload.status),
|
|
125
|
+
eventType: input.eventType,
|
|
126
|
+
currentPeriodEnd,
|
|
127
|
+
cancelAtPeriodEnd,
|
|
128
|
+
}),
|
|
129
|
+
subjectId: getString(input.payload.subjectId) ??
|
|
130
|
+
getString(input.payload.userId) ??
|
|
131
|
+
getString(metadata.subjectId) ??
|
|
132
|
+
getString(metadata.userId),
|
|
133
|
+
externalSubjectId: externalCustomerId,
|
|
134
|
+
externalCustomerId,
|
|
135
|
+
planCode: getString(input.payload.planCode) ?? getString(metadata.planCode),
|
|
136
|
+
externalProductId: resolveExternalProductId(input.payload, input.subscription),
|
|
137
|
+
currentPeriodStart,
|
|
138
|
+
currentPeriodEnd,
|
|
139
|
+
trialEndAt: toStripeDateString(input.subscription.trial_end),
|
|
140
|
+
cancelAt,
|
|
141
|
+
metadata: {
|
|
142
|
+
eventType: input.eventType,
|
|
143
|
+
lifecycle: input.eventType.split(".").slice(-1)[0] ?? "updated",
|
|
144
|
+
payload: input.payload,
|
|
145
|
+
subscription: input.subscription,
|
|
146
|
+
},
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
function toNormalizedEvent(payload) {
|
|
150
|
+
const sourceRef = String(payload.sourceRef ?? payload.subscriptionId ?? payload.id ?? randomUUID());
|
|
151
|
+
const record = buildRecord({
|
|
152
|
+
payload,
|
|
153
|
+
subscription: {
|
|
154
|
+
id: sourceRef,
|
|
155
|
+
status: payload.status,
|
|
156
|
+
customer: payload.externalCustomerId ?? payload.externalSubjectId ?? payload.customerId,
|
|
157
|
+
current_period_start: payload.currentPeriodStart,
|
|
158
|
+
current_period_end: payload.currentPeriodEnd,
|
|
159
|
+
trial_end: payload.trialEndAt,
|
|
160
|
+
cancel_at: payload.cancelAt,
|
|
161
|
+
items: {
|
|
162
|
+
data: [
|
|
163
|
+
{
|
|
164
|
+
price: {
|
|
165
|
+
id: payload.priceId ?? payload.externalProductId,
|
|
166
|
+
product: payload.productId,
|
|
167
|
+
},
|
|
168
|
+
},
|
|
169
|
+
],
|
|
170
|
+
},
|
|
171
|
+
metadata: asObject(payload.metadata),
|
|
172
|
+
},
|
|
173
|
+
eventType: getString(payload.eventType) ?? "stripe.subscription.updated",
|
|
174
|
+
sourceRef,
|
|
175
|
+
});
|
|
176
|
+
return {
|
|
177
|
+
eventKey: getString(payload.eventKey) ?? hashPayload(payload),
|
|
178
|
+
eventType: getString(payload.eventType) ?? "stripe.subscription.updated",
|
|
179
|
+
sourceRef,
|
|
180
|
+
records: [record],
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
function toStripeEvent(payload) {
|
|
184
|
+
const eventType = getString(payload.type) ?? "stripe.event";
|
|
185
|
+
const data = asObject(payload.data);
|
|
186
|
+
const object = asObject(data.object);
|
|
187
|
+
if (!eventType.startsWith("customer.subscription.")) {
|
|
188
|
+
return {
|
|
189
|
+
eventKey: getString(payload.id) ?? hashPayload(payload),
|
|
190
|
+
eventType,
|
|
191
|
+
sourceRef: null,
|
|
192
|
+
records: [],
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
const sourceRef = String(object.id ?? payload.id ?? randomUUID());
|
|
196
|
+
const record = buildRecord({
|
|
197
|
+
payload,
|
|
198
|
+
subscription: object,
|
|
199
|
+
eventType,
|
|
200
|
+
sourceRef,
|
|
201
|
+
});
|
|
202
|
+
return {
|
|
203
|
+
eventKey: getString(payload.id) ?? hashPayload(payload),
|
|
204
|
+
eventType,
|
|
205
|
+
sourceRef,
|
|
206
|
+
records: [record],
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
export const stripePlugin = {
|
|
210
|
+
key: "stripe",
|
|
211
|
+
displayName: "Stripe Billing",
|
|
212
|
+
description: "Normalizes Stripe Billing subscription webhook events and syncs verified subscriptions into canonical records.",
|
|
213
|
+
capabilities: ["webhooks", "subscription-sync", "billing"],
|
|
214
|
+
async provisionPlan(input, context) {
|
|
215
|
+
return provisionStripePlan(input, context.config);
|
|
216
|
+
},
|
|
217
|
+
async deprovisionPlan(input, context) {
|
|
218
|
+
return deprovisionStripePlan(input, context.config, context.result);
|
|
219
|
+
},
|
|
220
|
+
async verifyWebhook(envelope, context) {
|
|
221
|
+
const stripeVerification = verifyStripeWebhook(envelope, context.config);
|
|
222
|
+
if (stripeVerification) {
|
|
223
|
+
return stripeVerification;
|
|
224
|
+
}
|
|
225
|
+
return verifyTrustedRelayWebhook(envelope, context.config);
|
|
226
|
+
},
|
|
227
|
+
async parseWebhook(envelope) {
|
|
228
|
+
const payload = parsePayload(envelope.body);
|
|
229
|
+
if (typeof payload.status === "string") {
|
|
230
|
+
return toNormalizedEvent(payload);
|
|
231
|
+
}
|
|
232
|
+
if (typeof payload.type === "string") {
|
|
233
|
+
return toStripeEvent(payload);
|
|
234
|
+
}
|
|
235
|
+
throw new Error("Stripe plugin expects either a normalized payload with status or a Stripe event payload with type.");
|
|
236
|
+
},
|
|
237
|
+
};
|
|
238
|
+
//# sourceMappingURL=stripe.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stripe.js","sourceRoot":"","sources":["../../../../src/providers/stripe/plugin/stripe.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { PluginWebhookEnvelope, PluginWebhookVerification } from "@shdan/submesh-core";
|
|
2
|
+
export declare function verifyStripeWebhook(envelope: PluginWebhookEnvelope, config: Record<string, unknown>): PluginWebhookVerification | undefined;
|
|
3
|
+
//# sourceMappingURL=stripe-signature-verification.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stripe-signature-verification.d.ts","sourceRoot":"","sources":["../../../../src/providers/stripe/security/stripe-signature-verification.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,qBAAqB,EACrB,yBAAyB,EAC1B,MAAM,qBAAqB,CAAC;AA4G7B,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,qBAAqB,EAC/B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC9B,yBAAyB,GAAG,SAAS,CAqFvC"}
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import { createHmac, timingSafeEqual } from "node:crypto";
|
|
2
|
+
const DEFAULT_WEBHOOK_TOLERANCE_SECONDS = 300;
|
|
3
|
+
function readHeader(headers, key) {
|
|
4
|
+
const value = headers[key] ?? headers[key.toLowerCase()];
|
|
5
|
+
return Array.isArray(value) ? value[0] : value;
|
|
6
|
+
}
|
|
7
|
+
function getString(value) {
|
|
8
|
+
return typeof value === "string" && value.length > 0 ? value : undefined;
|
|
9
|
+
}
|
|
10
|
+
function getNumber(value) {
|
|
11
|
+
return typeof value === "number" && Number.isFinite(value) ? value : undefined;
|
|
12
|
+
}
|
|
13
|
+
function hasStripeVerificationConfig(config) {
|
|
14
|
+
return typeof config.stripeWebhookSigningSecret === "string";
|
|
15
|
+
}
|
|
16
|
+
function toRawPayload(envelope) {
|
|
17
|
+
const raw = envelope.rawBody ?? envelope.body;
|
|
18
|
+
if (typeof raw === "string") {
|
|
19
|
+
return raw;
|
|
20
|
+
}
|
|
21
|
+
if (raw instanceof Uint8Array) {
|
|
22
|
+
return Buffer.from(raw).toString("utf8");
|
|
23
|
+
}
|
|
24
|
+
return undefined;
|
|
25
|
+
}
|
|
26
|
+
function safeEqualHex(expectedHex, candidateHex) {
|
|
27
|
+
if (expectedHex.length !== candidateHex.length) {
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
30
|
+
try {
|
|
31
|
+
const expected = Buffer.from(expectedHex, "hex");
|
|
32
|
+
const candidate = Buffer.from(candidateHex, "hex");
|
|
33
|
+
if (expected.length !== candidate.length) {
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
36
|
+
return timingSafeEqual(expected, candidate);
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
return false;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
function parseSignatureHeader(value) {
|
|
43
|
+
const signatures = [];
|
|
44
|
+
let timestamp;
|
|
45
|
+
for (const entry of value.split(",")) {
|
|
46
|
+
const [rawKey, rawValue] = entry.trim().split("=", 2);
|
|
47
|
+
if (!rawKey || !rawValue) {
|
|
48
|
+
continue;
|
|
49
|
+
}
|
|
50
|
+
if (rawKey === "t") {
|
|
51
|
+
const parsed = Number(rawValue);
|
|
52
|
+
if (Number.isFinite(parsed)) {
|
|
53
|
+
timestamp = parsed;
|
|
54
|
+
}
|
|
55
|
+
continue;
|
|
56
|
+
}
|
|
57
|
+
if (rawKey === "v1") {
|
|
58
|
+
signatures.push(rawValue);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
if (!Number.isFinite(timestamp) || signatures.length === 0) {
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
64
|
+
return {
|
|
65
|
+
timestamp: timestamp,
|
|
66
|
+
signatures,
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
function resolveToleranceSeconds(config) {
|
|
70
|
+
const direct = getNumber(config.stripeWebhookToleranceSeconds);
|
|
71
|
+
if (direct !== undefined && direct >= 0) {
|
|
72
|
+
return direct;
|
|
73
|
+
}
|
|
74
|
+
const configured = getString(config.stripeWebhookToleranceSeconds);
|
|
75
|
+
if (configured) {
|
|
76
|
+
const parsed = Number(configured);
|
|
77
|
+
if (Number.isFinite(parsed) && parsed >= 0) {
|
|
78
|
+
return parsed;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return DEFAULT_WEBHOOK_TOLERANCE_SECONDS;
|
|
82
|
+
}
|
|
83
|
+
export function verifyStripeWebhook(envelope, config) {
|
|
84
|
+
if (!hasStripeVerificationConfig(config)) {
|
|
85
|
+
return undefined;
|
|
86
|
+
}
|
|
87
|
+
const secret = getString(config.stripeWebhookSigningSecret);
|
|
88
|
+
if (!secret) {
|
|
89
|
+
return {
|
|
90
|
+
verified: false,
|
|
91
|
+
strategy: "custom",
|
|
92
|
+
metadata: {
|
|
93
|
+
provider: "stripe",
|
|
94
|
+
reason: "missing_signing_secret",
|
|
95
|
+
},
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
const signatureHeader = readHeader(envelope.headers, "stripe-signature");
|
|
99
|
+
if (!signatureHeader) {
|
|
100
|
+
return {
|
|
101
|
+
verified: false,
|
|
102
|
+
strategy: "custom",
|
|
103
|
+
metadata: {
|
|
104
|
+
provider: "stripe",
|
|
105
|
+
reason: "missing_signature_header",
|
|
106
|
+
},
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
const parsed = parseSignatureHeader(signatureHeader);
|
|
110
|
+
if (!parsed) {
|
|
111
|
+
return {
|
|
112
|
+
verified: false,
|
|
113
|
+
strategy: "custom",
|
|
114
|
+
metadata: {
|
|
115
|
+
provider: "stripe",
|
|
116
|
+
reason: "invalid_signature_header",
|
|
117
|
+
},
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
const payload = toRawPayload(envelope);
|
|
121
|
+
if (!payload) {
|
|
122
|
+
return {
|
|
123
|
+
verified: false,
|
|
124
|
+
strategy: "custom",
|
|
125
|
+
metadata: {
|
|
126
|
+
provider: "stripe",
|
|
127
|
+
reason: "missing_raw_body",
|
|
128
|
+
},
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
const toleranceSeconds = resolveToleranceSeconds(config);
|
|
132
|
+
const nowSeconds = Math.floor(Date.now() / 1000);
|
|
133
|
+
if (Math.abs(nowSeconds - parsed.timestamp) > toleranceSeconds) {
|
|
134
|
+
return {
|
|
135
|
+
verified: false,
|
|
136
|
+
strategy: "custom",
|
|
137
|
+
metadata: {
|
|
138
|
+
provider: "stripe",
|
|
139
|
+
reason: "timestamp_out_of_tolerance",
|
|
140
|
+
timestamp: parsed.timestamp,
|
|
141
|
+
},
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
const signedPayload = `${parsed.timestamp}.${payload}`;
|
|
145
|
+
const expected = createHmac("sha256", secret).update(signedPayload).digest("hex");
|
|
146
|
+
const matched = parsed.signatures.some((signature) => safeEqualHex(expected, signature));
|
|
147
|
+
return {
|
|
148
|
+
verified: matched,
|
|
149
|
+
strategy: "custom",
|
|
150
|
+
metadata: matched
|
|
151
|
+
? {
|
|
152
|
+
provider: "stripe",
|
|
153
|
+
timestamp: parsed.timestamp,
|
|
154
|
+
}
|
|
155
|
+
: {
|
|
156
|
+
provider: "stripe",
|
|
157
|
+
reason: "signature_mismatch",
|
|
158
|
+
timestamp: parsed.timestamp,
|
|
159
|
+
},
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
//# sourceMappingURL=stripe-signature-verification.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stripe-signature-verification.js","sourceRoot":"","sources":["../../../../src/providers/stripe/security/stripe-signature-verification.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { VerifiedProviderSubscription, VerifyStripeSubscriptionInput } from "../../../contracts.js";
|
|
2
|
+
export declare function verifyStripeSubscription(input: VerifyStripeSubscriptionInput, config?: Record<string, unknown>): Promise<VerifiedProviderSubscription>;
|
|
3
|
+
//# sourceMappingURL=stripe-subscription-verification-service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stripe-subscription-verification-service.d.ts","sourceRoot":"","sources":["../../../../src/providers/stripe/services/stripe-subscription-verification-service.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,4BAA4B,EAC5B,6BAA6B,EAC9B,MAAM,uBAAuB,CAAC;AAsE/B,wBAAsB,wBAAwB,CAC5C,KAAK,EAAE,6BAA6B,EACpC,MAAM,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,GACnC,OAAO,CAAC,4BAA4B,CAAC,CAoBvC"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { ValidationError } from "../../../errors.js";
|
|
2
|
+
import { stripePlugin } from "../plugin/stripe.js";
|
|
3
|
+
function asObject(value) {
|
|
4
|
+
return value && typeof value === "object" && !Array.isArray(value)
|
|
5
|
+
? value
|
|
6
|
+
: {};
|
|
7
|
+
}
|
|
8
|
+
function getString(value) {
|
|
9
|
+
return typeof value === "string" && value.length > 0 ? value : undefined;
|
|
10
|
+
}
|
|
11
|
+
function resolveApiKey(input, config) {
|
|
12
|
+
const apiKey = input.apiKey ?? getString(config.stripeApiKey);
|
|
13
|
+
if (!apiKey) {
|
|
14
|
+
throw new ValidationError("Stripe subscription verification requires apiKey in the method input or plugin config.stripeApiKey.");
|
|
15
|
+
}
|
|
16
|
+
return apiKey;
|
|
17
|
+
}
|
|
18
|
+
async function parseStripeRecord(body) {
|
|
19
|
+
const parsed = await stripePlugin.parseWebhook?.({
|
|
20
|
+
body,
|
|
21
|
+
headers: {},
|
|
22
|
+
receivedAt: new Date().toISOString(),
|
|
23
|
+
});
|
|
24
|
+
const [event] = Array.isArray(parsed) ? parsed : [parsed];
|
|
25
|
+
const record = event?.records[0];
|
|
26
|
+
if (!record) {
|
|
27
|
+
throw new Error("Stripe verification did not produce a canonical subscription record.");
|
|
28
|
+
}
|
|
29
|
+
return record;
|
|
30
|
+
}
|
|
31
|
+
async function loadStripeSubscription(input, config) {
|
|
32
|
+
const apiKey = resolveApiKey(input, config);
|
|
33
|
+
const url = new URL(`https://api.stripe.com/v1/subscriptions/${encodeURIComponent(input.subscriptionId)}`);
|
|
34
|
+
url.searchParams.append("expand[]", "items.data.price.product");
|
|
35
|
+
const response = await fetch(url, {
|
|
36
|
+
headers: {
|
|
37
|
+
authorization: `Bearer ${apiKey}`,
|
|
38
|
+
},
|
|
39
|
+
});
|
|
40
|
+
if (!response.ok) {
|
|
41
|
+
throw new ValidationError(`Stripe subscription lookup failed for ${input.subscriptionId} with status ${response.status}.`);
|
|
42
|
+
}
|
|
43
|
+
return asObject(await response.json());
|
|
44
|
+
}
|
|
45
|
+
export async function verifyStripeSubscription(input, config = {}) {
|
|
46
|
+
const subscription = await loadStripeSubscription(input, config);
|
|
47
|
+
const raw = {
|
|
48
|
+
id: `stripe.verify:${input.subscriptionId}`,
|
|
49
|
+
type: "customer.subscription.updated",
|
|
50
|
+
subjectId: input.subjectId,
|
|
51
|
+
planCode: input.planCode,
|
|
52
|
+
data: {
|
|
53
|
+
object: subscription,
|
|
54
|
+
},
|
|
55
|
+
};
|
|
56
|
+
const canonical = await parseStripeRecord(raw);
|
|
57
|
+
return {
|
|
58
|
+
provider: "stripe",
|
|
59
|
+
sourceRef: canonical.sourceRef,
|
|
60
|
+
status: canonical.status,
|
|
61
|
+
canonical,
|
|
62
|
+
raw: subscription,
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
//# sourceMappingURL=stripe-subscription-verification-service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stripe-subscription-verification-service.js","sourceRoot":"","sources":["../../../../src/providers/stripe/services/stripe-subscription-verification-service.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { Subscription } from "@shdan/submesh-core";
|
|
2
2
|
import type { CreateManagedSubscriptionInput } from "../contracts.js";
|
|
3
3
|
import type { SubmeshRepositories } from "../repositories/index.js";
|
|
4
|
-
|
|
4
|
+
import type { SubmeshLogger } from "../logger.js";
|
|
5
|
+
export declare function createManagedSubscription(repositories: SubmeshRepositories, input: CreateManagedSubscriptionInput, logger?: SubmeshLogger): Promise<Subscription>;
|
|
5
6
|
//# sourceMappingURL=managed-subscription-service.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"managed-subscription-service.d.ts","sourceRoot":"","sources":["../../src/services/managed-subscription-service.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAExD,OAAO,KAAK,EAAE,8BAA8B,EAAE,MAAM,iBAAiB,CAAC;AAEtE,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAEpE,wBAAsB,yBAAyB,CAC7C,YAAY,EAAE,mBAAmB,EACjC,KAAK,EAAE,8BAA8B,
|
|
1
|
+
{"version":3,"file":"managed-subscription-service.d.ts","sourceRoot":"","sources":["../../src/services/managed-subscription-service.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAExD,OAAO,KAAK,EAAE,8BAA8B,EAAE,MAAM,iBAAiB,CAAC;AAEtE,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAEpE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAGlD,wBAAsB,yBAAyB,CAC7C,YAAY,EAAE,mBAAmB,EACjC,KAAK,EAAE,8BAA8B,EACrC,MAAM,GAAE,aAA0B,GACjC,OAAO,CAAC,YAAY,CAAC,CA4BvB"}
|
|
@@ -1,9 +1,15 @@
|
|
|
1
1
|
import { NotFoundError } from "../errors.js";
|
|
2
|
-
|
|
2
|
+
import { noopLogger } from "../logger.js";
|
|
3
|
+
export async function createManagedSubscription(repositories, input, logger = noopLogger) {
|
|
3
4
|
const plan = await repositories.plans.getByCode(input.planCode);
|
|
4
5
|
if (!plan) {
|
|
5
6
|
throw new NotFoundError(`Plan ${input.planCode} was not found.`);
|
|
6
7
|
}
|
|
8
|
+
logger.info("Creating managed subscription", {
|
|
9
|
+
subjectId: input.subjectId,
|
|
10
|
+
planCode: input.planCode,
|
|
11
|
+
status: input.status,
|
|
12
|
+
});
|
|
7
13
|
return repositories.transaction(async (tx) => {
|
|
8
14
|
await tx.subjects.upsert({ id: input.subjectId });
|
|
9
15
|
return tx.subscriptions.upsert({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"managed-subscription-service.js","sourceRoot":"","sources":["../../src/services/managed-subscription-service.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"managed-subscription-service.js","sourceRoot":"","sources":["../../src/services/managed-subscription-service.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAI7C,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAE1C,MAAM,CAAC,KAAK,UAAU,yBAAyB,CAC7C,YAAiC,EACjC,KAAqC,EACrC,SAAwB,UAAU;IAElC,MAAM,IAAI,GAAG,MAAM,YAAY,CAAC,KAAK,CAAC,SAAS,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;IAChE,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,MAAM,IAAI,aAAa,CAAC,QAAQ,KAAK,CAAC,QAAQ,iBAAiB,CAAC,CAAC;IACnE,CAAC;IAED,MAAM,CAAC,IAAI,CAAC,+BAA+B,EAAE;QAC3C,SAAS,EAAE,KAAK,CAAC,SAAS;QAC1B,QAAQ,EAAE,KAAK,CAAC,QAAQ;QACxB,MAAM,EAAE,KAAK,CAAC,MAAM;KACrB,CAAC,CAAC;IAEH,OAAO,YAAY,CAAC,WAAW,CAAC,KAAK,EAAE,EAAE,EAAE,EAAE;QAC3C,MAAM,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,EAAE,EAAE,KAAK,CAAC,SAAS,EAAE,CAAC,CAAC;QAClD,OAAO,EAAE,CAAC,aAAa,CAAC,MAAM,CAAC;YAC7B,SAAS,EAAE,KAAK,CAAC,SAAS;YAC1B,MAAM,EAAE,IAAI,CAAC,EAAE;YACf,SAAS,EAAE,KAAK,CAAC,SAAS,IAAI,QAAQ;YACtC,UAAU,EAAE,KAAK,CAAC,UAAU,IAAI,QAAQ;YACxC,SAAS,EAAE,KAAK,CAAC,SAAS,IAAI,GAAG,KAAK,CAAC,SAAS,IAAI,IAAI,CAAC,IAAI,EAAE;YAC/D,MAAM,EAAE,KAAK,CAAC,MAAM,IAAI,QAAQ;YAChC,kBAAkB,EAAE,KAAK,CAAC,kBAAkB,IAAI,IAAI;YACpD,gBAAgB,EAAE,KAAK,CAAC,gBAAgB,IAAI,IAAI;YAChD,UAAU,EAAE,KAAK,CAAC,UAAU,IAAI,IAAI;YACpC,QAAQ,EAAE,KAAK,CAAC,QAAQ,IAAI,IAAI;YAChC,QAAQ,EAAE,KAAK,CAAC,QAAQ,IAAI,EAAE;SAC/B,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { CreatePlanInput } from "../contracts.js";
|
|
2
2
|
import type { PluginRegistry } from "../plugins/plugin-registry.js";
|
|
3
3
|
import type { SubmeshRepositories } from "../repositories/index.js";
|
|
4
|
-
|
|
4
|
+
import { SubmeshLogger } from "../logger.js";
|
|
5
|
+
export declare function createPlanWithProvisioning(repositories: SubmeshRepositories, pluginRegistry: PluginRegistry, input: CreatePlanInput, logger?: SubmeshLogger): Promise<import("@shdan/submesh-core").Plan>;
|
|
5
6
|
//# sourceMappingURL=plan-provisioning-service.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plan-provisioning-service.d.ts","sourceRoot":"","sources":["../../src/services/plan-provisioning-service.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,eAAe,EAGhB,MAAM,iBAAiB,CAAC;AAEzB,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC;AACpE,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAoEpE,wBAAsB,0BAA0B,CAC9C,YAAY,EAAE,mBAAmB,EACjC,cAAc,EAAE,cAAc,EAC9B,KAAK,EAAE,eAAe,+
|
|
1
|
+
{"version":3,"file":"plan-provisioning-service.d.ts","sourceRoot":"","sources":["../../src/services/plan-provisioning-service.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,eAAe,EAGhB,MAAM,iBAAiB,CAAC;AAEzB,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC;AACpE,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAoEpE,OAAO,EAAE,aAAa,EAAc,MAAM,cAAc,CAAC;AAEzD,wBAAsB,0BAA0B,CAC9C,YAAY,EAAE,mBAAmB,EACjC,cAAc,EAAE,cAAc,EAC9B,KAAK,EAAE,eAAe,EACtB,MAAM,GAAE,aAA0B,+CA4FnC"}
|
|
@@ -39,8 +39,12 @@ async function rollbackProvisioning(pluginRegistry, input, provisions) {
|
|
|
39
39
|
}
|
|
40
40
|
return failures;
|
|
41
41
|
}
|
|
42
|
-
|
|
42
|
+
import { noopLogger } from "../logger.js";
|
|
43
|
+
export async function createPlanWithProvisioning(repositories, pluginRegistry, input, logger = noopLogger) {
|
|
43
44
|
const provisions = [];
|
|
45
|
+
logger.info("Starting plan creation with provider provisioning", {
|
|
46
|
+
planCode: input.code,
|
|
47
|
+
});
|
|
44
48
|
try {
|
|
45
49
|
const installations = await repositories.pluginInstallations.list();
|
|
46
50
|
for (const installation of installations) {
|
|
@@ -51,6 +55,10 @@ export async function createPlanWithProvisioning(repositories, pluginRegistry, i
|
|
|
51
55
|
if (!plugin?.provisionPlan) {
|
|
52
56
|
continue;
|
|
53
57
|
}
|
|
58
|
+
logger.debug("Triggering plan provisioning for plugin", {
|
|
59
|
+
pluginKey: installation.pluginKey,
|
|
60
|
+
planCode: input.code,
|
|
61
|
+
});
|
|
54
62
|
const result = await plugin.provisionPlan(input, {
|
|
55
63
|
config: installation.config ?? {},
|
|
56
64
|
});
|
|
@@ -80,10 +88,17 @@ export async function createPlanWithProvisioning(repositories, pluginRegistry, i
|
|
|
80
88
|
await tx.catalogMappings.upsert(mapping);
|
|
81
89
|
}
|
|
82
90
|
}
|
|
91
|
+
logger.info("Plan creation with provisioning completed", {
|
|
92
|
+
planCode: input.code,
|
|
93
|
+
});
|
|
83
94
|
return created;
|
|
84
95
|
});
|
|
85
96
|
}
|
|
86
97
|
catch (error) {
|
|
98
|
+
logger.error("Plan creation with provisioning failed", {
|
|
99
|
+
planCode: input.code,
|
|
100
|
+
error,
|
|
101
|
+
});
|
|
87
102
|
const rollbackFailures = await rollbackProvisioning(pluginRegistry, input, provisions);
|
|
88
103
|
if (rollbackFailures.length > 0) {
|
|
89
104
|
const baseMessage = error instanceof Error
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plan-provisioning-service.js","sourceRoot":"","sources":["../../src/services/plan-provisioning-service.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAY/C,SAAS,yBAAyB,CAChC,QAA6C,EAC7C,UAAmC;IAEnC,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC5B,OAAO,QAAQ,IAAI,EAAE,CAAC;IACxB,CAAC;IAED,OAAO;QACL,GAAG,CAAC,QAAQ,IAAI,EAAE,CAAC;QACnB,YAAY,EAAE;YACZ,GAAG,CAAE,QAAQ,EAAE,YAAoD,IAAI,EAAE,CAAC;YAC1E,GAAG,MAAM,CAAC,WAAW,CACnB,UAAU,CAAC,GAAG,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC;gBAC5B,SAAS,CAAC,SAAS;gBACnB;oBACE,QAAQ,EAAE,SAAS,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;wBAC7C,iBAAiB,EAAE,OAAO,CAAC,iBAAiB;wBAC5C,QAAQ,EAAE,OAAO,CAAC,QAAQ,IAAI,EAAE;qBACjC,CAAC,CAAC;oBACH,QAAQ,EAAE,SAAS,CAAC,QAAQ,IAAI,EAAE;iBACnC;aACF,CAAC,CACH;SACF;KACF,CAAC;AACJ,CAAC;AAED,KAAK,UAAU,oBAAoB,CACjC,cAA8B,EAC9B,KAAsB,EACtB,UAAmC;IAEnC,MAAM,QAAQ,GAAa,EAAE,CAAC;IAE9B,KAAK,MAAM,SAAS,IAAI,UAAU,EAAE,CAAC;QACnC,MAAM,MAAM,GAAG,cAAc,CAAC,GAAG,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;QACvD,IAAI,CAAC,MAAM,EAAE,eAAe,EAAE,CAAC;YAC7B,SAAS;QACX,CAAC;QAED,IAAI,CAAC;YACH,MAAM,MAAM,CAAC,eAAe,CAAC,KAAK,EAAE;gBAClC,MAAM,EAAE,SAAS,CAAC,kBAAkB,IAAI,EAAE;gBAC1C,MAAM,EAAE,SAAS,CAAC,MAAM;aACzB,CAAC,CAAC;QACL,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,QAAQ,CAAC,IAAI,CACX,GAAG,SAAS,CAAC,SAAS,KACpB,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,+BAC3C,EAAE,CACH,CAAC;QACJ,CAAC;IACH,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,0BAA0B,CAC9C,YAAiC,EACjC,cAA8B,EAC9B,KAAsB;
|
|
1
|
+
{"version":3,"file":"plan-provisioning-service.js","sourceRoot":"","sources":["../../src/services/plan-provisioning-service.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { CanonicalSubscriptionInput, Subscription } from "@shdan/submesh-core";
|
|
2
2
|
import type { SubmeshRepositories } from "../repositories/index.js";
|
|
3
|
-
|
|
3
|
+
import { SubmeshLogger } from "../logger.js";
|
|
4
|
+
export declare function syncVerifiedProviderSubscription(repositories: SubmeshRepositories, input: CanonicalSubscriptionInput, logger?: SubmeshLogger): Promise<Subscription>;
|
|
4
5
|
//# sourceMappingURL=provider-subscription-sync-service.d.ts.map
|