@hookflo/tern 1.0.6 → 2.0.2-experimental.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 +204 -71
- package/dist/adapters/cloudflare.d.ts +11 -0
- package/dist/adapters/cloudflare.js +25 -0
- package/dist/adapters/express.d.ts +18 -0
- package/dist/adapters/express.js +23 -0
- package/dist/adapters/index.d.ts +4 -0
- package/dist/adapters/index.js +12 -0
- package/dist/adapters/nextjs.d.ts +10 -0
- package/dist/adapters/nextjs.js +20 -0
- package/dist/adapters/shared.d.ts +13 -0
- package/dist/adapters/shared.js +67 -0
- package/dist/cloudflare.d.ts +2 -0
- package/dist/cloudflare.js +5 -0
- package/dist/express.d.ts +2 -0
- package/dist/express.js +5 -0
- package/dist/index.d.ts +8 -4
- package/dist/index.js +66 -14
- package/dist/nextjs.d.ts +2 -0
- package/dist/nextjs.js +5 -0
- package/dist/normalization/index.d.ts +20 -0
- package/dist/normalization/index.js +78 -0
- package/dist/normalization/providers/payment/paypal.d.ts +2 -0
- package/dist/normalization/providers/payment/paypal.js +12 -0
- package/dist/normalization/providers/payment/razorpay.d.ts +2 -0
- package/dist/normalization/providers/payment/razorpay.js +13 -0
- package/dist/normalization/providers/payment/stripe.d.ts +2 -0
- package/dist/normalization/providers/payment/stripe.js +13 -0
- package/dist/normalization/providers/registry.d.ts +5 -0
- package/dist/normalization/providers/registry.js +23 -0
- package/dist/normalization/simple.d.ts +4 -0
- package/dist/normalization/simple.js +138 -0
- package/dist/normalization/storage/interface.d.ts +13 -0
- package/dist/normalization/storage/interface.js +2 -0
- package/dist/normalization/storage/memory.d.ts +12 -0
- package/dist/normalization/storage/memory.js +39 -0
- package/dist/normalization/templates/base/auth.d.ts +2 -0
- package/dist/normalization/templates/base/auth.js +22 -0
- package/dist/normalization/templates/base/ecommerce.d.ts +2 -0
- package/dist/normalization/templates/base/ecommerce.js +25 -0
- package/dist/normalization/templates/base/payment.d.ts +2 -0
- package/dist/normalization/templates/base/payment.js +25 -0
- package/dist/normalization/templates/registry.d.ts +6 -0
- package/dist/normalization/templates/registry.js +22 -0
- package/dist/normalization/transformer/engine.d.ts +11 -0
- package/dist/normalization/transformer/engine.js +86 -0
- package/dist/normalization/transformer/validator.d.ts +12 -0
- package/dist/normalization/transformer/validator.js +56 -0
- package/dist/normalization/types.d.ts +79 -0
- package/dist/normalization/types.js +2 -0
- package/dist/platforms/algorithms.d.ts +1 -1
- package/dist/platforms/algorithms.js +103 -89
- package/dist/test.js +98 -2
- package/dist/types.d.ts +73 -3
- package/dist/types.js +1 -0
- package/dist/verifiers/algorithms.d.ts +2 -2
- package/dist/verifiers/algorithms.js +66 -62
- package/dist/verifiers/base.d.ts +1 -1
- package/dist/verifiers/custom-algorithms.d.ts +2 -2
- package/dist/verifiers/custom-algorithms.js +11 -8
- package/package.json +22 -2
package/dist/index.js
CHANGED
|
@@ -14,22 +14,25 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
14
14
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
15
|
};
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
-
exports.createCustomVerifier = exports.createAlgorithmVerifier = exports.validateSignatureConfig = exports.getPlatformsUsingAlgorithm = exports.platformUsesAlgorithm = exports.getPlatformAlgorithmConfig = exports.WebhookVerificationService = void 0;
|
|
17
|
+
exports.getPlatformsByCategory = exports.getPlatformNormalizationCategory = exports.normalizePayload = exports.createCustomVerifier = exports.createAlgorithmVerifier = exports.validateSignatureConfig = exports.getPlatformsUsingAlgorithm = exports.platformUsesAlgorithm = exports.getPlatformAlgorithmConfig = exports.WebhookVerificationService = void 0;
|
|
18
18
|
const algorithms_1 = require("./verifiers/algorithms");
|
|
19
19
|
const custom_algorithms_1 = require("./verifiers/custom-algorithms");
|
|
20
20
|
const algorithms_2 = require("./platforms/algorithms");
|
|
21
|
+
const simple_1 = require("./normalization/simple");
|
|
21
22
|
class WebhookVerificationService {
|
|
22
23
|
static async verify(request, config) {
|
|
23
24
|
const verifier = this.getVerifier(config);
|
|
24
|
-
const result = await verifier.verify(request);
|
|
25
|
+
const result = await verifier.verify(request.clone());
|
|
25
26
|
// Ensure the platform is set correctly in the result
|
|
26
27
|
if (result.isValid) {
|
|
27
28
|
result.platform = config.platform;
|
|
29
|
+
if (config.normalize) {
|
|
30
|
+
result.payload = (0, simple_1.normalizePayload)(config.platform, result.payload, config.normalize);
|
|
31
|
+
}
|
|
28
32
|
}
|
|
29
33
|
return result;
|
|
30
34
|
}
|
|
31
35
|
static getVerifier(config) {
|
|
32
|
-
const platform = config.platform.toLowerCase();
|
|
33
36
|
// If a custom signature config is provided, use the new algorithm-based framework
|
|
34
37
|
if (config.signatureConfig) {
|
|
35
38
|
return this.createAlgorithmBasedVerifier(config);
|
|
@@ -50,9 +53,8 @@ class WebhookVerificationService {
|
|
|
50
53
|
return (0, algorithms_1.createAlgorithmVerifier)(secret, signatureConfig, config.platform, toleranceInSeconds);
|
|
51
54
|
}
|
|
52
55
|
static getLegacyVerifier(config) {
|
|
53
|
-
const platform = config.platform.toLowerCase();
|
|
54
56
|
// For legacy support, we'll use the algorithm-based approach
|
|
55
|
-
const platformConfig = (0, algorithms_2.getPlatformAlgorithmConfig)(platform);
|
|
57
|
+
const platformConfig = (0, algorithms_2.getPlatformAlgorithmConfig)(config.platform);
|
|
56
58
|
const configWithSignature = {
|
|
57
59
|
...config,
|
|
58
60
|
signatureConfig: platformConfig.signatureConfig,
|
|
@@ -60,30 +62,72 @@ class WebhookVerificationService {
|
|
|
60
62
|
return this.createAlgorithmBasedVerifier(configWithSignature);
|
|
61
63
|
}
|
|
62
64
|
// New method to create verifier using platform algorithm config
|
|
63
|
-
static async verifyWithPlatformConfig(request, platform, secret, toleranceInSeconds = 300) {
|
|
65
|
+
static async verifyWithPlatformConfig(request, platform, secret, toleranceInSeconds = 300, normalize = false) {
|
|
64
66
|
const platformConfig = (0, algorithms_2.getPlatformAlgorithmConfig)(platform);
|
|
65
67
|
const config = {
|
|
66
68
|
platform,
|
|
67
69
|
secret,
|
|
68
70
|
toleranceInSeconds,
|
|
69
71
|
signatureConfig: platformConfig.signatureConfig,
|
|
72
|
+
normalize,
|
|
70
73
|
};
|
|
71
|
-
return
|
|
74
|
+
return this.verify(request, config);
|
|
75
|
+
}
|
|
76
|
+
static async verifyAny(request, secrets, toleranceInSeconds = 300, normalize = false) {
|
|
77
|
+
const requestClone = request.clone();
|
|
78
|
+
const detectedPlatform = this.detectPlatform(requestClone);
|
|
79
|
+
if (detectedPlatform !== 'unknown' && secrets[detectedPlatform]) {
|
|
80
|
+
return this.verifyWithPlatformConfig(requestClone, detectedPlatform, secrets[detectedPlatform], toleranceInSeconds, normalize);
|
|
81
|
+
}
|
|
82
|
+
for (const [platform, secret] of Object.entries(secrets)) {
|
|
83
|
+
if (!secret) {
|
|
84
|
+
continue;
|
|
85
|
+
}
|
|
86
|
+
const result = await this.verifyWithPlatformConfig(requestClone, platform.toLowerCase(), secret, toleranceInSeconds, normalize);
|
|
87
|
+
if (result.isValid) {
|
|
88
|
+
return result;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
return {
|
|
92
|
+
isValid: false,
|
|
93
|
+
error: 'Unable to verify webhook with provided platform secrets',
|
|
94
|
+
errorCode: 'VERIFICATION_ERROR',
|
|
95
|
+
platform: detectedPlatform,
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
static detectPlatform(request) {
|
|
99
|
+
const headers = request.headers;
|
|
100
|
+
if (headers.has('stripe-signature'))
|
|
101
|
+
return 'stripe';
|
|
102
|
+
if (headers.has('x-hub-signature-256'))
|
|
103
|
+
return 'github';
|
|
104
|
+
if (headers.has('svix-signature'))
|
|
105
|
+
return 'clerk';
|
|
106
|
+
if (headers.has('webhook-signature'))
|
|
107
|
+
return 'dodopayments';
|
|
108
|
+
if (headers.has('x-gitlab-token'))
|
|
109
|
+
return 'gitlab';
|
|
110
|
+
if (headers.has('x-polar-signature'))
|
|
111
|
+
return 'polar';
|
|
112
|
+
if (headers.has('x-shopify-hmac-sha256'))
|
|
113
|
+
return 'shopify';
|
|
114
|
+
if (headers.has('x-vercel-signature'))
|
|
115
|
+
return 'vercel';
|
|
116
|
+
if (headers.has('x-webhook-token') && headers.has('x-webhook-id'))
|
|
117
|
+
return 'supabase';
|
|
118
|
+
return 'unknown';
|
|
72
119
|
}
|
|
73
120
|
// Helper method to get all platforms using a specific algorithm
|
|
74
121
|
static getPlatformsUsingAlgorithm(algorithm) {
|
|
75
|
-
|
|
76
|
-
return getPlatformsUsingAlgorithm(algorithm);
|
|
122
|
+
return (0, algorithms_2.getPlatformsUsingAlgorithm)(algorithm);
|
|
77
123
|
}
|
|
78
124
|
// Helper method to check if a platform uses a specific algorithm
|
|
79
125
|
static platformUsesAlgorithm(platform, algorithm) {
|
|
80
|
-
|
|
81
|
-
return platformUsesAlgorithm(platform, algorithm);
|
|
126
|
+
return (0, algorithms_2.platformUsesAlgorithm)(platform, algorithm);
|
|
82
127
|
}
|
|
83
128
|
// Helper method to validate signature config
|
|
84
129
|
static validateSignatureConfig(config) {
|
|
85
|
-
|
|
86
|
-
return validateSignatureConfig(config);
|
|
130
|
+
return (0, algorithms_2.validateSignatureConfig)(config);
|
|
87
131
|
}
|
|
88
132
|
// Simple token-based verification for platforms like Supabase
|
|
89
133
|
static async verifyTokenBased(request, webhookId, webhookToken) {
|
|
@@ -94,6 +138,7 @@ class WebhookVerificationService {
|
|
|
94
138
|
return {
|
|
95
139
|
isValid: false,
|
|
96
140
|
error: 'Missing required headers: x-webhook-id and x-webhook-token',
|
|
141
|
+
errorCode: 'MISSING_TOKEN',
|
|
97
142
|
platform: 'custom',
|
|
98
143
|
};
|
|
99
144
|
}
|
|
@@ -103,6 +148,7 @@ class WebhookVerificationService {
|
|
|
103
148
|
return {
|
|
104
149
|
isValid: false,
|
|
105
150
|
error: 'Invalid webhook ID or token',
|
|
151
|
+
errorCode: 'INVALID_TOKEN',
|
|
106
152
|
platform: 'custom',
|
|
107
153
|
};
|
|
108
154
|
}
|
|
@@ -117,7 +163,7 @@ class WebhookVerificationService {
|
|
|
117
163
|
return {
|
|
118
164
|
isValid: true,
|
|
119
165
|
platform: 'custom',
|
|
120
|
-
payload,
|
|
166
|
+
payload: payload,
|
|
121
167
|
metadata: {
|
|
122
168
|
id: idHeader,
|
|
123
169
|
algorithm: 'token-based',
|
|
@@ -128,6 +174,7 @@ class WebhookVerificationService {
|
|
|
128
174
|
return {
|
|
129
175
|
isValid: false,
|
|
130
176
|
error: `Token-based verification error: ${error.message}`,
|
|
177
|
+
errorCode: 'VERIFICATION_ERROR',
|
|
131
178
|
platform: 'custom',
|
|
132
179
|
};
|
|
133
180
|
}
|
|
@@ -144,4 +191,9 @@ var algorithms_4 = require("./verifiers/algorithms");
|
|
|
144
191
|
Object.defineProperty(exports, "createAlgorithmVerifier", { enumerable: true, get: function () { return algorithms_4.createAlgorithmVerifier; } });
|
|
145
192
|
var custom_algorithms_2 = require("./verifiers/custom-algorithms");
|
|
146
193
|
Object.defineProperty(exports, "createCustomVerifier", { enumerable: true, get: function () { return custom_algorithms_2.createCustomVerifier; } });
|
|
194
|
+
var simple_2 = require("./normalization/simple");
|
|
195
|
+
Object.defineProperty(exports, "normalizePayload", { enumerable: true, get: function () { return simple_2.normalizePayload; } });
|
|
196
|
+
Object.defineProperty(exports, "getPlatformNormalizationCategory", { enumerable: true, get: function () { return simple_2.getPlatformNormalizationCategory; } });
|
|
197
|
+
Object.defineProperty(exports, "getPlatformsByCategory", { enumerable: true, get: function () { return simple_2.getPlatformsByCategory; } });
|
|
198
|
+
__exportStar(require("./adapters"), exports);
|
|
147
199
|
exports.default = WebhookVerificationService;
|
package/dist/nextjs.d.ts
ADDED
package/dist/nextjs.js
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createWebhookHandler = void 0;
|
|
4
|
+
var nextjs_1 = require("./adapters/nextjs");
|
|
5
|
+
Object.defineProperty(exports, "createWebhookHandler", { enumerable: true, get: function () { return nextjs_1.createWebhookHandler; } });
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { BaseTemplate, CreateSchemaInput, NormalizedResult, ProviderInfo, TemplateCategory, TransformParams, UpdateSchemaInput, UserSchema } from './types';
|
|
2
|
+
import { StorageAdapter } from './storage/interface';
|
|
3
|
+
export declare class Normalizer {
|
|
4
|
+
private readonly storage;
|
|
5
|
+
private engine;
|
|
6
|
+
constructor(storage?: StorageAdapter);
|
|
7
|
+
getBaseTemplates(): Promise<BaseTemplate[]>;
|
|
8
|
+
getProviders(category?: TemplateCategory): Promise<ProviderInfo[]>;
|
|
9
|
+
createSchema(input: CreateSchemaInput): Promise<UserSchema>;
|
|
10
|
+
updateSchema(schemaId: string, updates: UpdateSchemaInput): Promise<void>;
|
|
11
|
+
getSchema(id: string): Promise<UserSchema | null>;
|
|
12
|
+
transform(params: TransformParams): Promise<NormalizedResult>;
|
|
13
|
+
validateSchema(schema: UserSchema): Promise<{
|
|
14
|
+
valid: boolean;
|
|
15
|
+
errors: string[];
|
|
16
|
+
}>;
|
|
17
|
+
}
|
|
18
|
+
export * from './types';
|
|
19
|
+
export * from './storage/interface';
|
|
20
|
+
export { InMemoryStorageAdapter } from './storage/memory';
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
exports.InMemoryStorageAdapter = exports.Normalizer = void 0;
|
|
18
|
+
const registry_1 = require("./providers/registry");
|
|
19
|
+
const registry_2 = require("./templates/registry");
|
|
20
|
+
const memory_1 = require("./storage/memory");
|
|
21
|
+
const engine_1 = require("./transformer/engine");
|
|
22
|
+
const validator_1 = require("./transformer/validator");
|
|
23
|
+
class Normalizer {
|
|
24
|
+
constructor(storage = new memory_1.InMemoryStorageAdapter()) {
|
|
25
|
+
this.storage = storage;
|
|
26
|
+
this.engine = new engine_1.NormalizationEngine(storage, new validator_1.SchemaValidator());
|
|
27
|
+
}
|
|
28
|
+
async getBaseTemplates() {
|
|
29
|
+
return this.storage.listBaseTemplates();
|
|
30
|
+
}
|
|
31
|
+
async getProviders(category) {
|
|
32
|
+
return registry_1.providerRegistry.list(category);
|
|
33
|
+
}
|
|
34
|
+
async createSchema(input) {
|
|
35
|
+
const schema = {
|
|
36
|
+
id: generateId(),
|
|
37
|
+
userId: input.userId,
|
|
38
|
+
baseTemplateId: input.baseTemplateId,
|
|
39
|
+
category: input.category,
|
|
40
|
+
fields: input.fields,
|
|
41
|
+
providerMappings: input.providerMappings,
|
|
42
|
+
createdAt: new Date(),
|
|
43
|
+
updatedAt: new Date(),
|
|
44
|
+
};
|
|
45
|
+
await this.storage.saveSchema(schema);
|
|
46
|
+
return schema;
|
|
47
|
+
}
|
|
48
|
+
async updateSchema(schemaId, updates) {
|
|
49
|
+
await this.storage.updateSchema(schemaId, updates);
|
|
50
|
+
}
|
|
51
|
+
async getSchema(id) {
|
|
52
|
+
return this.storage.getSchema(id);
|
|
53
|
+
}
|
|
54
|
+
async transform(params) {
|
|
55
|
+
return this.engine.transform(params);
|
|
56
|
+
}
|
|
57
|
+
async validateSchema(schema) {
|
|
58
|
+
const base = (await this.storage.getBaseTemplate(schema.baseTemplateId))
|
|
59
|
+
?? registry_2.templateRegistry.getById(schema.baseTemplateId);
|
|
60
|
+
if (!base) {
|
|
61
|
+
return {
|
|
62
|
+
valid: false,
|
|
63
|
+
errors: [`Base template not found: ${schema.baseTemplateId}`],
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
const validator = new validator_1.SchemaValidator();
|
|
67
|
+
return validator.validateSchema(schema, base);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
exports.Normalizer = Normalizer;
|
|
71
|
+
function generateId() {
|
|
72
|
+
// Simple non-crypto unique ID generator for framework default
|
|
73
|
+
return (`sch_${Math.random().toString(36).slice(2, 10)}${Date.now().toString(36)}`);
|
|
74
|
+
}
|
|
75
|
+
__exportStar(require("./types"), exports);
|
|
76
|
+
__exportStar(require("./storage/interface"), exports);
|
|
77
|
+
var memory_2 = require("./storage/memory");
|
|
78
|
+
Object.defineProperty(exports, "InMemoryStorageAdapter", { enumerable: true, get: function () { return memory_2.InMemoryStorageAdapter; } });
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.paypalDefaultMapping = void 0;
|
|
4
|
+
exports.paypalDefaultMapping = {
|
|
5
|
+
provider: 'paypal',
|
|
6
|
+
fieldMappings: [
|
|
7
|
+
{ schemaFieldId: 'event_type', providerPath: 'event_type' },
|
|
8
|
+
{ schemaFieldId: 'amount', providerPath: 'resource.amount.value', transform: 'toNumber' },
|
|
9
|
+
{ schemaFieldId: 'currency', providerPath: 'resource.amount.currency_code', transform: 'toUpperCase' },
|
|
10
|
+
{ schemaFieldId: 'transaction_id', providerPath: 'resource.id' },
|
|
11
|
+
],
|
|
12
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.razorpayDefaultMapping = void 0;
|
|
4
|
+
exports.razorpayDefaultMapping = {
|
|
5
|
+
provider: 'razorpay',
|
|
6
|
+
fieldMappings: [
|
|
7
|
+
{ schemaFieldId: 'event_type', providerPath: 'event' },
|
|
8
|
+
{ schemaFieldId: 'amount', providerPath: 'payload.payment.entity.amount' },
|
|
9
|
+
{ schemaFieldId: 'currency', providerPath: 'payload.payment.entity.currency', transform: 'toUpperCase' },
|
|
10
|
+
{ schemaFieldId: 'transaction_id', providerPath: 'payload.payment.entity.id' },
|
|
11
|
+
{ schemaFieldId: 'customer_id', providerPath: 'payload.payment.entity.contact' },
|
|
12
|
+
],
|
|
13
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.stripeDefaultMapping = void 0;
|
|
4
|
+
exports.stripeDefaultMapping = {
|
|
5
|
+
provider: 'stripe',
|
|
6
|
+
fieldMappings: [
|
|
7
|
+
{ schemaFieldId: 'event_type', providerPath: 'type' },
|
|
8
|
+
{ schemaFieldId: 'amount', providerPath: 'data.object.amount_received' },
|
|
9
|
+
{ schemaFieldId: 'currency', providerPath: 'data.object.currency', transform: 'toUpperCase' },
|
|
10
|
+
{ schemaFieldId: 'transaction_id', providerPath: 'data.object.id' },
|
|
11
|
+
{ schemaFieldId: 'customer_id', providerPath: 'data.object.customer' },
|
|
12
|
+
],
|
|
13
|
+
};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.providerRegistry = void 0;
|
|
4
|
+
const providers = [
|
|
5
|
+
{ id: 'stripe', name: 'Stripe', category: 'payment' },
|
|
6
|
+
{ id: 'razorpay', name: 'Razorpay', category: 'payment' },
|
|
7
|
+
{ id: 'paypal', name: 'PayPal', category: 'payment' },
|
|
8
|
+
{ id: 'clerk', name: 'Clerk', category: 'auth' },
|
|
9
|
+
{ id: 'auth0', name: 'Auth0', category: 'auth' },
|
|
10
|
+
{ id: 'supabase', name: 'Supabase', category: 'auth' },
|
|
11
|
+
{ id: 'shopify', name: 'Shopify', category: 'ecommerce' },
|
|
12
|
+
{ id: 'woocommerce', name: 'WooCommerce', category: 'ecommerce' },
|
|
13
|
+
];
|
|
14
|
+
exports.providerRegistry = {
|
|
15
|
+
list(category) {
|
|
16
|
+
if (!category)
|
|
17
|
+
return providers;
|
|
18
|
+
return providers.filter((p) => p.category === category);
|
|
19
|
+
},
|
|
20
|
+
getById(id) {
|
|
21
|
+
return providers.find((p) => p.id === id);
|
|
22
|
+
},
|
|
23
|
+
};
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { AnyNormalizedWebhook, NormalizeOptions, NormalizationCategory, WebhookPlatform } from '../types';
|
|
2
|
+
export declare function getPlatformNormalizationCategory(platform: WebhookPlatform): NormalizationCategory | null;
|
|
3
|
+
export declare function getPlatformsByCategory(category: NormalizationCategory): WebhookPlatform[];
|
|
4
|
+
export declare function normalizePayload(platform: WebhookPlatform, payload: any, normalize?: boolean | NormalizeOptions): AnyNormalizedWebhook | unknown;
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getPlatformNormalizationCategory = getPlatformNormalizationCategory;
|
|
4
|
+
exports.getPlatformsByCategory = getPlatformsByCategory;
|
|
5
|
+
exports.normalizePayload = normalizePayload;
|
|
6
|
+
function readPath(payload, path) {
|
|
7
|
+
return path.split('.').reduce((acc, key) => {
|
|
8
|
+
if (acc === undefined || acc === null) {
|
|
9
|
+
return undefined;
|
|
10
|
+
}
|
|
11
|
+
return acc[key];
|
|
12
|
+
}, payload);
|
|
13
|
+
}
|
|
14
|
+
const platformNormalizers = {
|
|
15
|
+
stripe: {
|
|
16
|
+
platform: 'stripe',
|
|
17
|
+
category: 'payment',
|
|
18
|
+
normalize: (payload) => ({
|
|
19
|
+
category: 'payment',
|
|
20
|
+
event: readPath(payload, 'type') === 'payment_intent.succeeded'
|
|
21
|
+
? 'payment.succeeded'
|
|
22
|
+
: 'payment.unknown',
|
|
23
|
+
amount: readPath(payload, 'data.object.amount_received')
|
|
24
|
+
?? readPath(payload, 'data.object.amount'),
|
|
25
|
+
currency: String(readPath(payload, 'data.object.currency') ?? '').toUpperCase() || undefined,
|
|
26
|
+
customer_id: readPath(payload, 'data.object.customer'),
|
|
27
|
+
transaction_id: readPath(payload, 'data.object.id'),
|
|
28
|
+
metadata: {},
|
|
29
|
+
occurred_at: new Date().toISOString(),
|
|
30
|
+
}),
|
|
31
|
+
},
|
|
32
|
+
polar: {
|
|
33
|
+
platform: 'polar',
|
|
34
|
+
category: 'payment',
|
|
35
|
+
normalize: (payload) => ({
|
|
36
|
+
category: 'payment',
|
|
37
|
+
event: readPath(payload, 'event') === 'payment.completed'
|
|
38
|
+
? 'payment.succeeded'
|
|
39
|
+
: 'payment.unknown',
|
|
40
|
+
amount: readPath(payload, 'payload.amount_cents'),
|
|
41
|
+
currency: String(readPath(payload, 'payload.currency_code') ?? '').toUpperCase() || undefined,
|
|
42
|
+
customer_id: readPath(payload, 'payload.customer_id'),
|
|
43
|
+
transaction_id: readPath(payload, 'payload.transaction_id'),
|
|
44
|
+
metadata: {},
|
|
45
|
+
occurred_at: new Date().toISOString(),
|
|
46
|
+
}),
|
|
47
|
+
},
|
|
48
|
+
clerk: {
|
|
49
|
+
platform: 'clerk',
|
|
50
|
+
category: 'auth',
|
|
51
|
+
normalize: (payload) => ({
|
|
52
|
+
category: 'auth',
|
|
53
|
+
event: readPath(payload, 'type') || 'auth.unknown',
|
|
54
|
+
user_id: readPath(payload, 'data.id'),
|
|
55
|
+
email: readPath(payload, 'data.email_addresses.0.email_address'),
|
|
56
|
+
metadata: {},
|
|
57
|
+
occurred_at: new Date().toISOString(),
|
|
58
|
+
}),
|
|
59
|
+
},
|
|
60
|
+
supabase: {
|
|
61
|
+
platform: 'supabase',
|
|
62
|
+
category: 'auth',
|
|
63
|
+
normalize: (payload) => ({
|
|
64
|
+
category: 'auth',
|
|
65
|
+
event: readPath(payload, 'type') || readPath(payload, 'event') || 'auth.unknown',
|
|
66
|
+
user_id: readPath(payload, 'record.id') || readPath(payload, 'id'),
|
|
67
|
+
email: readPath(payload, 'record.email') || readPath(payload, 'email'),
|
|
68
|
+
metadata: {},
|
|
69
|
+
occurred_at: new Date().toISOString(),
|
|
70
|
+
}),
|
|
71
|
+
},
|
|
72
|
+
vercel: {
|
|
73
|
+
platform: 'vercel',
|
|
74
|
+
category: 'infrastructure',
|
|
75
|
+
normalize: (payload) => ({
|
|
76
|
+
category: 'infrastructure',
|
|
77
|
+
event: readPath(payload, 'type') || 'deployment.unknown',
|
|
78
|
+
project_id: readPath(payload, 'payload.project.id'),
|
|
79
|
+
deployment_id: readPath(payload, 'payload.deployment.id'),
|
|
80
|
+
status: 'unknown',
|
|
81
|
+
metadata: {},
|
|
82
|
+
occurred_at: new Date().toISOString(),
|
|
83
|
+
}),
|
|
84
|
+
},
|
|
85
|
+
};
|
|
86
|
+
function getPlatformNormalizationCategory(platform) {
|
|
87
|
+
return platformNormalizers[platform]?.category || null;
|
|
88
|
+
}
|
|
89
|
+
function getPlatformsByCategory(category) {
|
|
90
|
+
return Object.values(platformNormalizers)
|
|
91
|
+
.filter((spec) => !!spec)
|
|
92
|
+
.filter((spec) => spec.category === category)
|
|
93
|
+
.map((spec) => spec.platform);
|
|
94
|
+
}
|
|
95
|
+
function resolveNormalizeOptions(normalize) {
|
|
96
|
+
if (typeof normalize === 'boolean') {
|
|
97
|
+
return {
|
|
98
|
+
enabled: normalize,
|
|
99
|
+
category: undefined,
|
|
100
|
+
includeRaw: true,
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
return {
|
|
104
|
+
enabled: normalize?.enabled ?? true,
|
|
105
|
+
category: normalize?.category,
|
|
106
|
+
includeRaw: normalize?.includeRaw ?? true,
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
function buildUnknownNormalizedPayload(platform, payload, category, includeRaw, warning) {
|
|
110
|
+
return {
|
|
111
|
+
category: category || 'infrastructure',
|
|
112
|
+
event: payload?.type ?? payload?.event ?? 'unknown',
|
|
113
|
+
_platform: platform,
|
|
114
|
+
_raw: includeRaw ? payload : undefined,
|
|
115
|
+
warning,
|
|
116
|
+
occurred_at: new Date().toISOString(),
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
function normalizePayload(platform, payload, normalize) {
|
|
120
|
+
const options = resolveNormalizeOptions(normalize);
|
|
121
|
+
if (!options.enabled) {
|
|
122
|
+
return payload;
|
|
123
|
+
}
|
|
124
|
+
const spec = platformNormalizers[platform];
|
|
125
|
+
const inferredCategory = spec?.category;
|
|
126
|
+
if (!spec) {
|
|
127
|
+
return buildUnknownNormalizedPayload(platform, payload, options.category, options.includeRaw);
|
|
128
|
+
}
|
|
129
|
+
if (options.category && options.category !== inferredCategory) {
|
|
130
|
+
return buildUnknownNormalizedPayload(platform, payload, inferredCategory, options.includeRaw, `Requested normalization category '${options.category}' does not match platform category '${inferredCategory}'`);
|
|
131
|
+
}
|
|
132
|
+
const normalized = spec.normalize(payload);
|
|
133
|
+
return {
|
|
134
|
+
...normalized,
|
|
135
|
+
_platform: platform,
|
|
136
|
+
_raw: options.includeRaw ? payload : undefined,
|
|
137
|
+
};
|
|
138
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { BaseTemplate, UpdateSchemaInput, UserSchema } from '../types';
|
|
2
|
+
export interface StorageAdapter {
|
|
3
|
+
saveSchema(schema: UserSchema): Promise<void>;
|
|
4
|
+
getSchema(id: string): Promise<UserSchema | null>;
|
|
5
|
+
updateSchema(id: string, updates: UpdateSchemaInput): Promise<void>;
|
|
6
|
+
deleteSchema(id: string): Promise<void>;
|
|
7
|
+
listSchemas(userId: string): Promise<UserSchema[]>;
|
|
8
|
+
getBaseTemplate(id: string): Promise<BaseTemplate | null>;
|
|
9
|
+
listBaseTemplates(): Promise<BaseTemplate[]>;
|
|
10
|
+
}
|
|
11
|
+
export interface NormalizationStorageOptions {
|
|
12
|
+
adapter: StorageAdapter;
|
|
13
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { BaseTemplate, UpdateSchemaInput, UserSchema } from '../types';
|
|
2
|
+
import { StorageAdapter } from './interface';
|
|
3
|
+
export declare class InMemoryStorageAdapter implements StorageAdapter {
|
|
4
|
+
private schemas;
|
|
5
|
+
saveSchema(schema: UserSchema): Promise<void>;
|
|
6
|
+
getSchema(id: string): Promise<UserSchema | null>;
|
|
7
|
+
updateSchema(id: string, updates: UpdateSchemaInput): Promise<void>;
|
|
8
|
+
deleteSchema(id: string): Promise<void>;
|
|
9
|
+
listSchemas(userId: string): Promise<UserSchema[]>;
|
|
10
|
+
getBaseTemplate(id: string): Promise<BaseTemplate | null>;
|
|
11
|
+
listBaseTemplates(): Promise<BaseTemplate[]>;
|
|
12
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.InMemoryStorageAdapter = void 0;
|
|
4
|
+
const registry_1 = require("../templates/registry");
|
|
5
|
+
class InMemoryStorageAdapter {
|
|
6
|
+
constructor() {
|
|
7
|
+
this.schemas = new Map();
|
|
8
|
+
}
|
|
9
|
+
async saveSchema(schema) {
|
|
10
|
+
this.schemas.set(schema.id, schema);
|
|
11
|
+
}
|
|
12
|
+
async getSchema(id) {
|
|
13
|
+
return this.schemas.get(id) ?? null;
|
|
14
|
+
}
|
|
15
|
+
async updateSchema(id, updates) {
|
|
16
|
+
const existing = this.schemas.get(id);
|
|
17
|
+
if (!existing)
|
|
18
|
+
return;
|
|
19
|
+
const updated = {
|
|
20
|
+
...existing,
|
|
21
|
+
...updates,
|
|
22
|
+
updatedAt: new Date(),
|
|
23
|
+
};
|
|
24
|
+
this.schemas.set(id, updated);
|
|
25
|
+
}
|
|
26
|
+
async deleteSchema(id) {
|
|
27
|
+
this.schemas.delete(id);
|
|
28
|
+
}
|
|
29
|
+
async listSchemas(userId) {
|
|
30
|
+
return Array.from(this.schemas.values()).filter((s) => s.userId === userId);
|
|
31
|
+
}
|
|
32
|
+
async getBaseTemplate(id) {
|
|
33
|
+
return registry_1.templateRegistry.getById(id) ?? null;
|
|
34
|
+
}
|
|
35
|
+
async listBaseTemplates() {
|
|
36
|
+
return registry_1.templateRegistry.listAll();
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
exports.InMemoryStorageAdapter = InMemoryStorageAdapter;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.authBaseTemplate = void 0;
|
|
4
|
+
exports.authBaseTemplate = {
|
|
5
|
+
id: 'auth_v1',
|
|
6
|
+
category: 'auth',
|
|
7
|
+
version: '1.0.0',
|
|
8
|
+
fields: [
|
|
9
|
+
{
|
|
10
|
+
id: 'event_type', name: 'event_type', type: 'string', required: true,
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
id: 'user_id', name: 'user_id', type: 'string', required: true,
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
id: 'email', name: 'email', type: 'string', required: false,
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
id: 'status', name: 'status', type: 'string', required: true,
|
|
20
|
+
},
|
|
21
|
+
],
|
|
22
|
+
};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ecommerceBaseTemplate = void 0;
|
|
4
|
+
exports.ecommerceBaseTemplate = {
|
|
5
|
+
id: 'ecommerce_v1',
|
|
6
|
+
category: 'ecommerce',
|
|
7
|
+
version: '1.0.0',
|
|
8
|
+
fields: [
|
|
9
|
+
{
|
|
10
|
+
id: 'event_type', name: 'event_type', type: 'string', required: true,
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
id: 'order_id', name: 'order_id', type: 'string', required: true,
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
id: 'total', name: 'total', type: 'number', required: true,
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
id: 'currency', name: 'currency', type: 'string', required: true,
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
id: 'customer_id', name: 'customer_id', type: 'string', required: false,
|
|
23
|
+
},
|
|
24
|
+
],
|
|
25
|
+
};
|