meridianjs 0.2.0 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +80 -462
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,47 +1,29 @@
|
|
|
1
|
-
|
|
2
1
|
<div align="center">
|
|
3
|
-
Meridian
|
|
4
2
|
|
|
5
|
-
|
|
3
|
+
# Meridian
|
|
6
4
|
|
|
7
|
-
|
|
5
|
+
**One SDK. Every API. Zero inconsistency.**
|
|
8
6
|
|
|
9
7
|
[](https://www.npmjs.com/package/meridianjs)
|
|
10
8
|
[](https://www.npmjs.com/package/meridianjs)
|
|
11
9
|
[](LICENSE.md)
|
|
12
10
|
[](https://www.typescriptlang.org/)
|
|
13
|
-
[](#provider-coverage)
|
|
11
|
+
[](https://vitest.dev)
|
|
12
|
+
[](#providers)
|
|
16
13
|
|
|
17
|
-
|
|
14
|
+
A TypeScript-first SDK that gives every third-party API the same interface — normalized errors, rate limits, pagination, and response shapes, regardless of provider.
|
|
18
15
|
|
|
19
16
|
</div>
|
|
20
17
|
|
|
21
|
-
## Problem Statement
|
|
22
|
-
|
|
23
|
-
Applications integrating multiple third-party APIs face inconsistent response formats, error structures, rate limit behaviors, and pagination strategies. This fragmentation requires provider-specific error handling, retry logic, and data transformation code that is difficult to maintain and test.
|
|
24
|
-
|
|
25
|
-
Meridian provides a single abstraction layer that normalizes these differences, allowing applications to interact with any provider through a consistent interface while maintaining type safety and resilience patterns.
|
|
26
|
-
|
|
27
|
-
```typescript
|
|
28
|
-
// Same interface. Every provider. Always.
|
|
29
|
-
const { data, meta } = await meridian.provider("razorpay").get("/v1/payments/pay_123");
|
|
30
|
-
console.log(meta.rateLimit.remaining); // normalized from any provider
|
|
31
|
-
console.log(meta.provider); // "razorpay"
|
|
32
|
-
```
|
|
33
|
-
|
|
34
|
-
If Razorpay changes their error format tomorrow, you don't change a line of your code.
|
|
35
|
-
|
|
36
18
|
---
|
|
37
19
|
|
|
38
|
-
##
|
|
20
|
+
## Install
|
|
39
21
|
|
|
40
22
|
```bash
|
|
41
23
|
npm install meridianjs
|
|
42
24
|
```
|
|
43
25
|
|
|
44
|
-
|
|
26
|
+
Requires **Node.js ≥ 18**. Zero runtime dependencies.
|
|
45
27
|
|
|
46
28
|
---
|
|
47
29
|
|
|
@@ -51,487 +33,123 @@ npm install meridianjs
|
|
|
51
33
|
import { Meridian } from "meridianjs";
|
|
52
34
|
|
|
53
35
|
const meridian = await Meridian.create({
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
36
|
+
providers: {
|
|
37
|
+
stripe: { auth: { apiKey: process.env.STRIPE_SECRET_KEY } },
|
|
38
|
+
razorpay: {
|
|
39
|
+
auth: {
|
|
40
|
+
username: process.env.RAZORPAY_KEY_ID,
|
|
41
|
+
password: process.env.RAZORPAY_KEY_SECRET,
|
|
42
|
+
},
|
|
59
43
|
},
|
|
60
44
|
},
|
|
61
|
-
github: {
|
|
62
|
-
auth: { token: process.env.GITHUB_TOKEN },
|
|
63
|
-
},
|
|
64
45
|
});
|
|
65
46
|
|
|
66
|
-
//
|
|
67
|
-
const
|
|
68
|
-
body: { amount: 50000, currency: "INR" },
|
|
69
|
-
});
|
|
47
|
+
// Same API for every provider
|
|
48
|
+
const { data, meta } = await meridian.provider("stripe").get("/v1/customers");
|
|
70
49
|
|
|
71
|
-
//
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
}
|
|
50
|
+
console.log(meta.provider); // "stripe"
|
|
51
|
+
console.log(meta.rateLimit.remaining); // always normalized
|
|
52
|
+
console.log(meta.pagination.hasNext); // always normalized
|
|
75
53
|
```
|
|
76
54
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
```typescript
|
|
80
|
-
{
|
|
81
|
-
data: T,
|
|
82
|
-
meta: {
|
|
83
|
-
provider: string,
|
|
84
|
-
requestId: string,
|
|
85
|
-
rateLimit: { limit: number, remaining: number, reset: Date },
|
|
86
|
-
pagination?: { hasNext: boolean, cursor?: string },
|
|
87
|
-
warnings: string[],
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
```
|
|
91
|
-
|
|
92
|
-
---
|
|
93
|
-
|
|
94
|
-
## Provider Coverage
|
|
95
|
-
|
|
96
|
-
31 adapters, fully implemented and contract-tested (661 tests).
|
|
97
|
-
|
|
98
|
-
### Global
|
|
99
|
-
|
|
100
|
-
| Provider | Category | Auth |
|
|
101
|
-
| --- | --- | --- |
|
|
102
|
-
| **GitHub** | Developer Tools | Bearer token |
|
|
103
|
-
| **Anthropic** | AI / LLM | `x-api-key` header |
|
|
104
|
-
| **OpenAI** | AI / LLM | Bearer token |
|
|
105
|
-
| **Stripe** | Payments | Basic (`key:`) · ✅ webhook |
|
|
106
|
-
| **Twilio** | Communications | Basic (`SID:AuthToken`) · ✅ webhook |
|
|
107
|
-
| **SendGrid** | Communications | Bearer token · ✅ webhook |
|
|
108
|
-
| **Mailgun** | Communications | Basic (`api:key`) · ✅ webhook |
|
|
109
|
-
| **Vonage** | Communications | Query parameter (`api_key:api_secret`) · ✅ webhook |
|
|
110
|
-
| **Adyen** | Payments | Basic (`apiKey:`) · ✅ webhook |
|
|
111
|
-
| **Google Gemini** | AI / LLM | Bearer token / `x-goog-api-key` |
|
|
112
|
-
| **Auth0** | Auth / Identity | Bearer token |
|
|
113
|
-
| **HubSpot** | CRM | Bearer token |
|
|
114
|
-
| **Supabase** | Databases | Bearer token / `apikey` |
|
|
115
|
-
|
|
116
|
-
### India — Payments
|
|
117
|
-
|
|
118
|
-
| Provider | Auth | Webhook |
|
|
119
|
-
| --- | --- | --- |
|
|
120
|
-
| **Razorpay** | Basic (`key_id:key_secret`) | ✅ HMAC-SHA256 |
|
|
121
|
-
| **Cashfree** | `x-client-id` + `x-client-secret` | ✅ HMAC-SHA256 |
|
|
122
|
-
| **PayU** | Basic (`key:salt`) | ✅ HMAC-SHA512 |
|
|
123
|
-
| **Juspay** | Basic (`apiKey:`) | ✅ HMAC-SHA256 |
|
|
124
|
-
|
|
125
|
-
### India — Communications
|
|
126
|
-
|
|
127
|
-
| Provider | Auth | Key Endpoints |
|
|
128
|
-
| --- | --- | --- |
|
|
129
|
-
| **MSG91** | `authkey` header | SMS, OTP, WhatsApp, Email · ✅ webhook |
|
|
130
|
-
| **Exotel** | Basic (`SID:APIKey`) | Calls, SMS, Virtual Numbers · ✅ webhook |
|
|
131
|
-
| **Gupshup** | `apikey` header | WhatsApp Business, SMS · ✅ webhook |
|
|
132
|
-
|
|
133
|
-
### India — Banking / Fintech
|
|
134
|
-
|
|
135
|
-
| Provider | Auth | Key Endpoints |
|
|
136
|
-
| --- | --- | --- |
|
|
137
|
-
| **Setu** | Bearer token | AA consent, UPI, BBPS |
|
|
138
|
-
| **Decentro** | `clientId\|clientSecret\|moduleSecret` | KYC, UPI, Virtual Accounts |
|
|
139
|
-
| **Perfios** | `x-api-key` header | Bank statement analysis, ITR |
|
|
140
|
-
|
|
141
|
-
### India — Logistics
|
|
142
|
-
|
|
143
|
-
| Provider | Auth | Key Endpoints |
|
|
144
|
-
| --- | --- | --- |
|
|
145
|
-
| **Shiprocket** | Bearer JWT | Orders, Shipments, Tracking, NDR |
|
|
146
|
-
| **Delhivery** | Bearer token | Waybills, Tracking, COD |
|
|
147
|
-
|
|
148
|
-
### India — KYC / Identity / eSign
|
|
149
|
-
|
|
150
|
-
| Provider | Auth | Key Endpoints |
|
|
151
|
-
| --- | --- | --- |
|
|
152
|
-
| **HyperVerge** | `appId\|appKey` headers | Face match, Liveness, OCR |
|
|
153
|
-
| **Digio** | Basic (`clientId:clientSecret`) | eSign, eStamp, Documents |
|
|
154
|
-
| **Karza** | `x-karza-key` header | PAN, GST, Bank verify, ITR |
|
|
155
|
-
| **IDfy** | `api-key` + `account-id` headers | Identity checks, Background verify |
|
|
156
|
-
|
|
157
|
-
### India — Tax / Compliance / Maps
|
|
158
|
-
|
|
159
|
-
| Provider | Auth | Key Endpoints |
|
|
160
|
-
| --- | --- | --- |
|
|
161
|
-
| **Cleartax** | `x-cleartax-auth-token` | GST filing, e-invoicing, IRN |
|
|
162
|
-
| **MapMyIndia** | Bearer token | Geocode, Directions, Places |
|
|
163
|
-
|
|
164
|
-
> **Planned next:** BillDesk, Freshworks, Signzy — see [ROADMAP.md](ROADMAP.md)
|
|
55
|
+
Switch providers — your app code doesn't change.
|
|
165
56
|
|
|
166
57
|
---
|
|
167
58
|
|
|
168
|
-
##
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
CB["⚡ Circuit Breaker\nClosed / Open / Half-open"]
|
|
183
|
-
IK["🔑 Idempotency Resolver\nSAFE / CONDITIONAL / IDEMPOTENT"]
|
|
184
|
-
RT["🔄 Retry Strategy\nExp. backoff + jitter"]
|
|
185
|
-
AU["🔐 Auth Strategy\nauthStrategy(config)"]
|
|
186
|
-
BQ["🔧 Build Request\nbuildRequest(input)"]
|
|
187
|
-
RL --> CB --> IK --> RT --> AU --> BQ
|
|
188
|
-
end
|
|
189
|
-
|
|
190
|
-
subgraph Adapters["Provider Adapters (22)"]
|
|
191
|
-
direction LR
|
|
192
|
-
PAY["💳 Payments\nRazorpay · Cashfree · PayU · Juspay · Stripe"]
|
|
193
|
-
COM["📱 Communications\nMSG91 · Exotel · Gupshup"]
|
|
194
|
-
FIN["🏦 Banking / Fintech\nSetu · Decentro · Perfios"]
|
|
195
|
-
LOG["📦 Logistics\nShiprocket · Delhivery"]
|
|
196
|
-
KYC["🪪 KYC / Identity\nHyperVerge · Digio · Karza · IDfy"]
|
|
197
|
-
TAX["🧾 Tax / Maps\nCleartax · MapMyIndia"]
|
|
198
|
-
GLB["🌐 Global\nGitHub · OpenAI · Anthropic"]
|
|
199
|
-
end
|
|
200
|
-
|
|
201
|
-
OBS["📊 Observability\nlogRequest · logResponse · logError · recordMetric"]
|
|
202
|
-
STATE[("💾 State Storage\nCircuit breaker · Rate limiter\nRedis / In-memory")]
|
|
203
|
-
end
|
|
204
|
-
|
|
205
|
-
EXT[["🌍 External APIs"]]
|
|
206
|
-
RES(["✅ NormalizedResponse<T>\n{ data, meta: { provider, rateLimit, pagination } }"])
|
|
207
|
-
ERR(["❌ MeridianError\n{ category, retryable, status, provider }"])
|
|
208
|
-
|
|
209
|
-
App --> RL
|
|
210
|
-
BQ --> Adapters
|
|
211
|
-
Adapters -->|fetch| EXT
|
|
212
|
-
EXT -->|raw response| Adapters
|
|
213
|
-
Adapters -->|parseResponse| RES
|
|
214
|
-
Adapters -->|parseError| ERR
|
|
215
|
-
Pipeline <-->|log + metrics| OBS
|
|
216
|
-
CB <-->|read/write| STATE
|
|
217
|
-
RL <-->|read/write| STATE
|
|
218
|
-
```
|
|
219
|
-
|
|
220
|
-
### Pipeline Stages
|
|
221
|
-
|
|
222
|
-
```text
|
|
223
|
-
Your Code
|
|
224
|
-
│
|
|
225
|
-
▼
|
|
226
|
-
┌───────────────────────────────────────────────────────────────────┐
|
|
227
|
-
│ Request Pipeline │
|
|
228
|
-
│ │
|
|
229
|
-
│ ① Rate Limiter ② Circuit Breaker ③ Idempotency │
|
|
230
|
-
│ ┌─────────────┐ ┌───────────────┐ ┌─────────────┐ │
|
|
231
|
-
│ │ Token bucket│ │ CLOSED │ │ Resolve or │ │
|
|
232
|
-
│ │ Adaptive │────────►│ OPEN │─────►│ generate │ │
|
|
233
|
-
│ │ backoff │ │ HALF_OPEN │ │ key │ │
|
|
234
|
-
│ └─────────────┘ └───────────────┘ └─────────────┘ │
|
|
235
|
-
│ │ │
|
|
236
|
-
│ ④ Retry Strategy ⑤ Auth Strategy ⑥ Build Request │
|
|
237
|
-
│ ┌─────────────┐ ┌───────────────┐ ┌──────────────────┐ │
|
|
238
|
-
│ │ Exp backoff │ │ authStrategy()│ │ buildRequest() │ │
|
|
239
|
-
│ │ + jitter │◄────────│ → AuthToken │ │ URL · headers │ │
|
|
240
|
-
│ │ retryable? │ └───────────────┘ │ body · auth │ │
|
|
241
|
-
│ └─────────────┘ └──────────────────┘ │
|
|
242
|
-
└──────────────────────────────────────────────────┬────────────────┘
|
|
243
|
-
│
|
|
244
|
-
┌──────────▼───────────┐
|
|
245
|
-
│ Provider Adapter │
|
|
246
|
-
│ buildRequest() │
|
|
247
|
-
│ parseResponse() │
|
|
248
|
-
│ parseError() │
|
|
249
|
-
│ rateLimitPolicy() │
|
|
250
|
-
│ paginationStrategy()│
|
|
251
|
-
└──────────┬───────────┘
|
|
252
|
-
│ fetch()
|
|
253
|
-
▼
|
|
254
|
-
External API
|
|
255
|
-
│
|
|
256
|
-
┌────────────────┴────────────────┐
|
|
257
|
-
▼ ▼
|
|
258
|
-
NormalizedResponse<T> MeridianError
|
|
259
|
-
{ data, meta: { { category,
|
|
260
|
-
provider, requestId, retryable,
|
|
261
|
-
rateLimit, pagination } } provider, status }
|
|
262
|
-
```
|
|
263
|
-
|
|
264
|
-
### Multi-Provider Isolation
|
|
265
|
-
|
|
266
|
-
```text
|
|
267
|
-
┌──────────────────────────────────────────────────────────────────┐
|
|
268
|
-
│ Meridian Instance │
|
|
269
|
-
│ │
|
|
270
|
-
│ provider("razorpay") ──► [ CB ] [ RL ] ──► RazorpayAdapter │
|
|
271
|
-
│ provider("cashfree") ──► [ CB ] [ RL ] ──► CashfreeAdapter │
|
|
272
|
-
│ provider("karza") ──► [ CB ] [ RL ] ──► KarzaAdapter │
|
|
273
|
-
│ provider("shiprocket") ──► [ CB ] [ RL ] ──► ShiprocketAdapter │
|
|
274
|
-
│ provider("github") ──► [ CB ] [ RL ] ──► GitHubAdapter │
|
|
275
|
-
│ │
|
|
276
|
-
│ CB = Circuit Breaker (independent per provider) │
|
|
277
|
-
│ RL = Rate Limiter (independent per provider) │
|
|
278
|
-
│ │
|
|
279
|
-
│ One provider tripping its circuit breaker never affects others. │
|
|
280
|
-
└──────────────────────────────────────────────────────────────────┘
|
|
281
|
-
│ │
|
|
282
|
-
▼ ▼
|
|
283
|
-
StateStorage (Redis) Observability Adapters
|
|
284
|
-
circuit breaker state Console / OTel / Prometheus
|
|
285
|
-
rate limiter state logs · metrics · traces
|
|
286
|
-
```
|
|
59
|
+
## What It Does
|
|
60
|
+
|
|
61
|
+
| Feature | Description |
|
|
62
|
+
|---|---|
|
|
63
|
+
| **Normalized responses** | Every provider returns `{ data, meta }` with consistent shape |
|
|
64
|
+
| **Typed errors** | `MeridianError` with `category`, `retryable`, `retryAfter` — always |
|
|
65
|
+
| **Auto-retry** | Exponential backoff with jitter on 429s and 5xx errors |
|
|
66
|
+
| **Circuit breaker** | Opens automatically on repeated failures, closes after cooldown |
|
|
67
|
+
| **Rate limit awareness** | Tracks limits from response headers, delays before hitting 429 |
|
|
68
|
+
| **Pagination** | Unified `meta.pagination` across cursor, offset, and link-based strategies |
|
|
69
|
+
| **Webhook verification** | Timing-safe HMAC verification on every payment/comms adapter |
|
|
70
|
+
| **Streaming** | SSE streaming for OpenAI, Anthropic, Mistral, Cohere |
|
|
71
|
+
| **Batch requests** | Fan-out with concurrency control via `.batch()` |
|
|
72
|
+
| **India Compliance** | DPDPA-compliant PII redaction (Aadhaar, PAN, UPI VPA, bank accounts) |
|
|
287
73
|
|
|
288
74
|
---
|
|
289
75
|
|
|
290
|
-
##
|
|
76
|
+
## Providers
|
|
291
77
|
|
|
292
|
-
###
|
|
78
|
+
### 🇮🇳 Indian Ecosystem (17 adapters)
|
|
293
79
|
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
},
|
|
303
|
-
},
|
|
304
|
-
},
|
|
305
|
-
});
|
|
80
|
+
| Category | Providers |
|
|
81
|
+
|---|---|
|
|
82
|
+
| Payments | Razorpay, Cashfree, PayU, Juspay, PhonePe |
|
|
83
|
+
| Banking / UPI | Setu, Decentro |
|
|
84
|
+
| Communications | MSG91, Exotel, Gupshup |
|
|
85
|
+
| Logistics | Shiprocket, Delhivery |
|
|
86
|
+
| KYC / Identity | HyperVerge, Digio, Karza, IDfy |
|
|
87
|
+
| Tax / Maps | Cleartax, MapMyIndia, Perfios |
|
|
306
88
|
|
|
307
|
-
|
|
308
|
-
body: {
|
|
309
|
-
order_amount: 100.00,
|
|
310
|
-
order_currency: "INR",
|
|
311
|
-
customer_details: { customer_id: "user_123", customer_phone: "9999999999" },
|
|
312
|
-
},
|
|
313
|
-
idempotencyKey: "order-xyz-123",
|
|
314
|
-
});
|
|
315
|
-
```
|
|
89
|
+
### 🌐 International (19 adapters)
|
|
316
90
|
|
|
317
|
-
|
|
91
|
+
| Category | Providers |
|
|
92
|
+
|---|---|
|
|
93
|
+
| Payments | Stripe, Adyen, Braintree, Checkout.com, Mollie, Klarna |
|
|
94
|
+
| Communications | Twilio, SendGrid, Mailgun, Vonage |
|
|
95
|
+
| AI / LLM | OpenAI, Anthropic, Google Gemini, Cohere, Mistral |
|
|
96
|
+
| CRM / Dev Tools | HubSpot, Auth0, Supabase, GitHub |
|
|
318
97
|
|
|
319
|
-
|
|
320
|
-
const result = await meridian.provider("karza").post("/v3/pan/verify", {
|
|
321
|
-
body: { pan: "ABCDE1234F", consent: "Y" },
|
|
322
|
-
});
|
|
323
|
-
```
|
|
324
|
-
|
|
325
|
-
### Webhook Verification
|
|
326
|
-
|
|
327
|
-
```typescript
|
|
328
|
-
import { CashfreeAdapter, PayuAdapter } from "meridianjs";
|
|
329
|
-
|
|
330
|
-
// Cashfree — HMAC-SHA256, base64
|
|
331
|
-
const cfAdapter = new CashfreeAdapter();
|
|
332
|
-
const isValid = cfAdapter.verifyWebhook(
|
|
333
|
-
req.rawBody,
|
|
334
|
-
req.headers["x-webhook-signature"],
|
|
335
|
-
process.env.CASHFREE_WEBHOOK_SECRET
|
|
336
|
-
);
|
|
98
|
+
---
|
|
337
99
|
|
|
338
|
-
|
|
339
|
-
const payuAdapter = new PayuAdapter();
|
|
340
|
-
const isValid = payuAdapter.verifyWebhook(
|
|
341
|
-
req.rawBody,
|
|
342
|
-
req.headers["x-verify"],
|
|
343
|
-
process.env.PAYU_SALT
|
|
344
|
-
);
|
|
345
|
-
```
|
|
100
|
+
## Error Handling
|
|
346
101
|
|
|
347
|
-
|
|
102
|
+
Every error has the same shape — no more `try/catch` archaeology per provider:
|
|
348
103
|
|
|
349
104
|
```typescript
|
|
350
|
-
import { MeridianError } from "meridianjs";
|
|
351
|
-
|
|
352
105
|
try {
|
|
353
|
-
const result = await meridian.provider("
|
|
106
|
+
const result = await meridian.provider("stripe").post("/v1/charges", { body });
|
|
354
107
|
} catch (err) {
|
|
355
108
|
if (err instanceof MeridianError) {
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
break;
|
|
361
|
-
case "validation": // bad request — fix the payload
|
|
362
|
-
break;
|
|
363
|
-
case "provider": // upstream 5xx — safe to retry (err.retryable === true)
|
|
364
|
-
break;
|
|
365
|
-
case "network": // connection issue — safe to retry
|
|
366
|
-
break;
|
|
367
|
-
}
|
|
109
|
+
err.category; // "auth" | "rate_limit" | "validation" | "network" | "provider"
|
|
110
|
+
err.retryable; // boolean
|
|
111
|
+
err.retryAfter; // Date | undefined
|
|
112
|
+
err.provider; // "stripe"
|
|
368
113
|
}
|
|
369
114
|
}
|
|
370
115
|
```
|
|
371
116
|
|
|
372
117
|
---
|
|
373
118
|
|
|
374
|
-
##
|
|
375
|
-
|
|
376
|
-
### Local Development
|
|
377
|
-
|
|
378
|
-
```typescript
|
|
379
|
-
const meridian = await Meridian.create({
|
|
380
|
-
localUnsafe: true, // in-memory — fine for dev, never for production
|
|
381
|
-
razorpay: { auth: { ... } },
|
|
382
|
-
});
|
|
383
|
-
```
|
|
384
|
-
|
|
385
|
-
### Production (Serverless / Distributed)
|
|
119
|
+
## Webhook Verification
|
|
386
120
|
|
|
387
121
|
```typescript
|
|
388
|
-
import {
|
|
122
|
+
import { StripeAdapter } from "meridianjs";
|
|
389
123
|
|
|
390
|
-
const
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
124
|
+
const adapter = new StripeAdapter();
|
|
125
|
+
const valid = adapter.verifyWebhook(
|
|
126
|
+
req.rawBody,
|
|
127
|
+
req.headers["stripe-signature"],
|
|
128
|
+
process.env.STRIPE_WEBHOOK_SECRET,
|
|
129
|
+
);
|
|
395
130
|
```
|
|
396
131
|
|
|
397
|
-
|
|
132
|
+
Works identically for Razorpay, Cashfree, Braintree, Twilio, Adyen, and more.
|
|
398
133
|
|
|
399
134
|
---
|
|
400
135
|
|
|
401
|
-
##
|
|
402
|
-
|
|
403
|
-
| Guarantee | Behaviour |
|
|
404
|
-
| --- | --- |
|
|
405
|
-
| **Fail-fast init** | All methods throw if called before `Meridian.create()` resolves |
|
|
406
|
-
| **Fail-closed state** | `distributed` mode requires `StateStorage` — startup fails without it |
|
|
407
|
-
| **Secret redaction** | `authorization`, `cookie`, `token`, `apiKey` auto-redacted in all logs, errors, and metrics |
|
|
408
|
-
| **No silent degradation** | Invalid configs fail at startup; adapter validation failures are explicit |
|
|
409
|
-
| **Pagination safety** | Cycle detection + 1000-page hard limit prevent infinite loops |
|
|
410
|
-
|
|
411
|
-
---
|
|
412
|
-
|
|
413
|
-
## Public API
|
|
414
|
-
|
|
415
|
-
### `Meridian.create(config)`
|
|
416
|
-
|
|
417
|
-
```typescript
|
|
418
|
-
const meridian = await Meridian.create({
|
|
419
|
-
razorpay: { auth: { username: "...", password: "..." } },
|
|
420
|
-
github: { auth: { token: "..." } },
|
|
421
|
-
|
|
422
|
-
defaults: {
|
|
423
|
-
retry: { maxRetries: 3, baseDelay: 100, maxDelay: 5000, jitter: true },
|
|
424
|
-
circuitBreaker: { failureThreshold: 5, timeout: 30000 },
|
|
425
|
-
rateLimit: { tokensPerSecond: 10, maxTokens: 100 },
|
|
426
|
-
timeout: 10000,
|
|
427
|
-
},
|
|
428
|
-
|
|
429
|
-
observability: new ConsoleObservability(),
|
|
430
|
-
compliance: { piiRedaction: true, auditLog: true },
|
|
431
|
-
mode: "distributed",
|
|
432
|
-
stateStorage: new RedisStateStorage(client),
|
|
433
|
-
});
|
|
434
|
-
```
|
|
435
|
-
|
|
436
|
-
### Provider Client
|
|
437
|
-
|
|
438
|
-
```typescript
|
|
439
|
-
const client = meridian.provider("razorpay");
|
|
440
|
-
|
|
441
|
-
client.get<T>(endpoint, options?) // GET
|
|
442
|
-
client.post<T>(endpoint, options?) // POST
|
|
443
|
-
client.put<T>(endpoint, options?) // PUT
|
|
444
|
-
client.patch<T>(endpoint, options?) // PATCH
|
|
445
|
-
client.delete<T>(endpoint, options?) // DELETE
|
|
446
|
-
client.paginate<T>(endpoint, options?) // AsyncGenerator — auto-follows cursors
|
|
447
|
-
```
|
|
448
|
-
|
|
449
|
-
### `MeridianError`
|
|
136
|
+
## Batch Requests
|
|
450
137
|
|
|
451
138
|
```typescript
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
error.retryAfter // Date — present on rate_limit errors
|
|
458
|
-
error.metadata // sanitized provider context
|
|
459
|
-
```
|
|
460
|
-
|
|
461
|
-
---
|
|
462
|
-
|
|
463
|
-
## Agent Proxy
|
|
464
|
-
|
|
465
|
-
Meridian ships a built-in HTTP proxy for AI agents and LLM runtimes — rate limiting, circuit breaking, and secret redaction apply automatically to every request.
|
|
466
|
-
|
|
467
|
-
```bash
|
|
468
|
-
export RAZORPAY_KEY_ID="rzp_live_..." RAZORPAY_KEY_SECRET="..."
|
|
469
|
-
export GITHUB_TOKEN="ghp_..."
|
|
470
|
-
export STRIPE_SECRET_KEY="sk_live_..."
|
|
139
|
+
const results = await meridian.provider("stripe").batch([
|
|
140
|
+
{ method: "GET", endpoint: "/v1/customers/cu_1" },
|
|
141
|
+
{ method: "GET", endpoint: "/v1/customers/cu_2" },
|
|
142
|
+
{ method: "GET", endpoint: "/v1/customers/cu_3" },
|
|
143
|
+
], 5); // max 5 concurrent
|
|
471
144
|
|
|
472
|
-
|
|
473
|
-
npx boundary-proxy 8080 # custom port
|
|
474
|
-
```
|
|
475
|
-
|
|
476
|
-
Route pattern: `http://localhost:4242/<provider>/<endpoint>`
|
|
477
|
-
|
|
478
|
-
```text
|
|
479
|
-
GET /github/repos/octocat/Hello-World → api.github.com
|
|
480
|
-
POST /razorpay/v1/orders → api.razorpay.com
|
|
481
|
-
GET /anthropic/v1/messages → api.anthropic.com
|
|
145
|
+
// Results are always in input order; errors are MeridianError, never thrown
|
|
482
146
|
```
|
|
483
147
|
|
|
484
148
|
---
|
|
485
149
|
|
|
486
|
-
##
|
|
487
|
-
|
|
488
|
-
**v0.1.3** — 22 adapters, 565 tests, zero TypeScript errors. Core pipeline stable. API surface settled — all additions are additive and non-breaking.
|
|
489
|
-
|
|
490
|
-
| Milestone | Status |
|
|
491
|
-
| --- | --- |
|
|
492
|
-
| Core pipeline (rate limit, circuit breaker, retry, idempotency) | ✅ Stable |
|
|
493
|
-
| 22 provider adapters (global + Indian ecosystem) | ✅ Stable |
|
|
494
|
-
| Contract test coverage for all adapters | ✅ 565 tests |
|
|
495
|
-
| Webhook verification (Cashfree, PayU, Decentro, Shiprocket) | ✅ Partial |
|
|
496
|
-
| Webhook verification on all remaining adapters | 🔄 Next |
|
|
497
|
-
| Twilio + SendGrid | 📋 v0.2 |
|
|
498
|
-
| Streaming support (OpenAI / Anthropic SSE) | 📋 v0.4 |
|
|
499
|
-
| Mock adapter for testing | 📋 v0.4 |
|
|
500
|
-
| India Compliance Mode (DPDPA) | 📋 v0.5 |
|
|
501
|
-
|
|
502
|
-
See [ROADMAP.md](ROADMAP.md) for the full plan and version targets.
|
|
503
|
-
|
|
504
|
-
---
|
|
505
|
-
|
|
506
|
-
## Non-Goals
|
|
507
|
-
|
|
508
|
-
- UI components or dashboards
|
|
509
|
-
- API mocking / stubbing (planned v0.4)
|
|
510
|
-
- Request recording or replay
|
|
511
|
-
- GraphQL (planned v1)
|
|
512
|
-
- Multi-region routing
|
|
513
|
-
- Built-in caching (layer it on top)
|
|
514
|
-
|
|
515
|
-
---
|
|
516
|
-
|
|
517
|
-
## Contributing
|
|
518
|
-
|
|
519
|
-
```bash
|
|
520
|
-
git clone https://github.com/Raghaverma/meridianjs
|
|
521
|
-
npm install
|
|
522
|
-
npm test # 565 tests
|
|
523
|
-
npm run typecheck # zero errors
|
|
524
|
-
npm run lint
|
|
525
|
-
```
|
|
526
|
-
|
|
527
|
-
See [CONTRIBUTING.md](CONTRIBUTING.md) for the adapter-building guide, error mapping rules, and PR checklist.
|
|
528
|
-
|
|
529
|
-
---
|
|
530
|
-
|
|
531
|
-
## License
|
|
532
|
-
|
|
533
|
-
MIT — see [LICENSE.md](LICENSE.md).
|
|
534
|
-
|
|
535
|
-
---
|
|
150
|
+
## Links
|
|
536
151
|
|
|
537
|
-
|
|
152
|
+
- [GitHub](https://github.com/Raghaverma/Meridianjs)
|
|
153
|
+
- [Changelog](CHANGELOG.md)
|
|
154
|
+
- [Roadmap](ROADMAP.md)
|
|
155
|
+
- [License: MIT](LICENSE.md)
|
package/package.json
CHANGED