meridianjs 0.2.2 → 0.2.4

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.
Files changed (94) hide show
  1. package/CHANGELOG.md +65 -160
  2. package/README.md +560 -93
  3. package/dist/analytics/collector.d.ts +28 -0
  4. package/dist/analytics/collector.d.ts.map +1 -0
  5. package/dist/analytics/collector.js +62 -0
  6. package/dist/analytics/collector.js.map +1 -0
  7. package/dist/analytics/index.d.ts +3 -0
  8. package/dist/analytics/index.d.ts.map +1 -0
  9. package/dist/analytics/index.js +2 -0
  10. package/dist/analytics/index.js.map +1 -0
  11. package/dist/capabilities/index.d.ts +3 -0
  12. package/dist/capabilities/index.d.ts.map +1 -0
  13. package/dist/capabilities/index.js +2 -0
  14. package/dist/capabilities/index.js.map +1 -0
  15. package/dist/capabilities/registry.d.ts +6 -0
  16. package/dist/capabilities/registry.d.ts.map +1 -0
  17. package/dist/capabilities/registry.js +61 -0
  18. package/dist/capabilities/registry.js.map +1 -0
  19. package/dist/core/pipeline.d.ts +3 -1
  20. package/dist/core/pipeline.d.ts.map +1 -1
  21. package/dist/core/pipeline.js +25 -0
  22. package/dist/core/pipeline.js.map +1 -1
  23. package/dist/core/types.d.ts +37 -1
  24. package/dist/core/types.d.ts.map +1 -1
  25. package/dist/core/types.js +4 -2
  26. package/dist/core/types.js.map +1 -1
  27. package/dist/debug/index.d.ts +3 -0
  28. package/dist/debug/index.d.ts.map +1 -0
  29. package/dist/debug/index.js +2 -0
  30. package/dist/debug/index.js.map +1 -0
  31. package/dist/debug/recorder.d.ts +32 -0
  32. package/dist/debug/recorder.d.ts.map +1 -0
  33. package/dist/debug/recorder.js +76 -0
  34. package/dist/debug/recorder.js.map +1 -0
  35. package/dist/generator/cli.d.ts +20 -0
  36. package/dist/generator/cli.d.ts.map +1 -0
  37. package/dist/generator/cli.js +56 -0
  38. package/dist/generator/cli.js.map +1 -0
  39. package/dist/generator/index.d.ts +9 -0
  40. package/dist/generator/index.d.ts.map +1 -0
  41. package/dist/generator/index.js +49 -0
  42. package/dist/generator/index.js.map +1 -0
  43. package/dist/generator/openapi.d.ts +13 -0
  44. package/dist/generator/openapi.d.ts.map +1 -0
  45. package/dist/generator/openapi.js +49 -0
  46. package/dist/generator/openapi.js.map +1 -0
  47. package/dist/generator/templates.d.ts +16 -0
  48. package/dist/generator/templates.d.ts.map +1 -0
  49. package/dist/generator/templates.js +290 -0
  50. package/dist/generator/templates.js.map +1 -0
  51. package/dist/index.d.ts +31 -0
  52. package/dist/index.d.ts.map +1 -1
  53. package/dist/index.js +96 -0
  54. package/dist/index.js.map +1 -1
  55. package/dist/policies/builtin.d.ts +24 -0
  56. package/dist/policies/builtin.d.ts.map +1 -0
  57. package/dist/policies/builtin.js +94 -0
  58. package/dist/policies/builtin.js.map +1 -0
  59. package/dist/policies/index.d.ts +2 -0
  60. package/dist/policies/index.d.ts.map +1 -0
  61. package/dist/policies/index.js +2 -0
  62. package/dist/policies/index.js.map +1 -0
  63. package/dist/public.d.ts +15 -0
  64. package/dist/public.d.ts.map +1 -1
  65. package/dist/public.js +15 -0
  66. package/dist/public.js.map +1 -1
  67. package/dist/schema/index.d.ts +2 -0
  68. package/dist/schema/index.d.ts.map +1 -0
  69. package/dist/schema/index.js +2 -0
  70. package/dist/schema/index.js.map +1 -0
  71. package/dist/schema/monitor.d.ts +10 -0
  72. package/dist/schema/monitor.d.ts.map +1 -0
  73. package/dist/schema/monitor.js +46 -0
  74. package/dist/schema/monitor.js.map +1 -0
  75. package/dist/services/index.d.ts +2 -0
  76. package/dist/services/index.d.ts.map +1 -0
  77. package/dist/services/index.js +2 -0
  78. package/dist/services/index.js.map +1 -0
  79. package/dist/services/service-client.d.ts +34 -0
  80. package/dist/services/service-client.d.ts.map +1 -0
  81. package/dist/services/service-client.js +156 -0
  82. package/dist/services/service-client.js.map +1 -0
  83. package/dist/transactions/index.d.ts +3 -0
  84. package/dist/transactions/index.d.ts.map +1 -0
  85. package/dist/transactions/index.js +2 -0
  86. package/dist/transactions/index.js.map +1 -0
  87. package/dist/transactions/saga.d.ts +22 -0
  88. package/dist/transactions/saga.d.ts.map +1 -0
  89. package/dist/transactions/saga.js +58 -0
  90. package/dist/transactions/saga.js.map +1 -0
  91. package/dist/validation/drift-detector.d.ts.map +1 -1
  92. package/dist/validation/drift-detector.js +17 -8
  93. package/dist/validation/drift-detector.js.map +1 -1
  94. package/package.json +3 -2
package/README.md CHANGED
@@ -2,147 +2,477 @@
2
2
 
3
3
  # Meridian
4
4
 
5
- **One SDK. Every API. Zero inconsistency.**
5
+ **Integration Reliability SDK**
6
+
7
+ *One interface. Every provider. Built for production.*
6
8
 
7
9
  [![npm version](https://img.shields.io/npm/v/meridianjs?color=0070f3&label=npm)](https://www.npmjs.com/package/meridianjs)
8
10
  [![npm downloads](https://img.shields.io/npm/dm/meridianjs?color=0070f3)](https://www.npmjs.com/package/meridianjs)
9
11
  [![License: MIT](https://img.shields.io/badge/license-MIT-green)](LICENSE.md)
10
12
  [![TypeScript](https://img.shields.io/badge/TypeScript-5.5-blue?logo=typescript&logoColor=white)](https://www.typescriptlang.org/)
11
- [![Tests](https://img.shields.io/badge/tests-1489%20passing-brightgreen)](https://vitest.dev)
13
+ [![Version](https://img.shields.io/badge/version-0.2.4-blue)](CHANGELOG.md)
14
+ [![Tests](https://img.shields.io/badge/tests-1568%20passing-brightgreen)](https://vitest.dev)
12
15
  [![Adapters](https://img.shields.io/badge/adapters-39-blueviolet)](#provider-status-matrix)
13
16
 
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.
15
-
16
17
  </div>
17
18
 
18
19
  ---
19
20
 
21
+ Your application integrates with Stripe, OpenAI, Razorpay, Twilio — and a dozen more.
22
+
23
+ Each one fails differently. Each one changes silently. Each one has a different error shape, pagination strategy, and rate limit header.
24
+
25
+ **Meridian sits between your application and every provider.**
26
+
27
+ It normalizes the differences, absorbs the failures, and makes providers swappable without touching your application code.
28
+
29
+ ```
30
+ Your Application
31
+
32
+
33
+ Meridian
34
+ ┌────┼─────┐
35
+ ▼ ▼ ▼
36
+ Stripe OpenAI Razorpay ··· 39 providers
37
+ ```
38
+
39
+ When OpenAI goes down, Meridian routes to Anthropic. When Stripe rate-limits you, Meridian backs off and retries. When a provider silently renames a field, Meridian tells you before it breaks production.
40
+
41
+ Zero runtime dependencies. Node.js 18+.
42
+
43
+ ---
44
+
45
+ ## The Killer Feature: Providers Become Replaceable
46
+
47
+ Your application stops naming vendors. Meridian routes, fails over, and recovers — automatically.
48
+
49
+ ```typescript
50
+ import { Meridian } from "meridianjs";
51
+
52
+ const meridian = await Meridian.create({
53
+ localUnsafe: true,
54
+ providers: {
55
+ openai: { auth: { apiKey: process.env.OPENAI_API_KEY } },
56
+ anthropic: { auth: { apiKey: process.env.ANTHROPIC_API_KEY } },
57
+ gemini: { auth: { apiKey: process.env.GEMINI_API_KEY } },
58
+ },
59
+ services: {
60
+ // Your app calls "llm". It never touches "openai" or "anthropic".
61
+ llm: {
62
+ providers: ["openai", "anthropic", "gemini"],
63
+ strategy: "failover",
64
+ },
65
+ },
66
+ });
67
+
68
+ // OpenAI outage? Anthropic takes over. No code change. No redeployment.
69
+ const result = await meridian.service("llm")!.post("/v1/chat/completions", {
70
+ body: { messages: [{ role: "user", content: "Hello" }] },
71
+ });
72
+
73
+ console.log(result.meta.provider); // "openai" or "anthropic" — whoever answered
74
+ console.log(result.meta.trace.retries); // 0, 1, 2 — what it took to get a response
75
+ console.log(result.meta.trace.latency); // ms end-to-end
76
+ ```
77
+
78
+ This works across payments, messaging, KYC, logistics — any category where multiple providers exist.
79
+
80
+ ---
81
+
20
82
  ## Install
21
83
 
22
84
  ```bash
23
85
  npm install meridianjs
24
86
  ```
25
87
 
26
- Requires **Node.js ≥ 18**. Zero runtime dependencies.
88
+ ---
89
+
90
+ ## What Meridian Owns
91
+
92
+ | Problem | Without Meridian | With Meridian |
93
+ |---|---|---|
94
+ | Error handling | Different shape per provider | `MeridianError` — always `category`, `retryable`, `retryAfter` |
95
+ | Rate limits | Parse headers manually per provider | `meta.rateLimit` — always normalized |
96
+ | Pagination | Different cursor/offset/link per provider | `meta.pagination` — always normalized |
97
+ | Retries | Roll your own | Exponential backoff with jitter, idempotency-safe |
98
+ | Circuit breaking | Roll your own | Automatic, per-provider |
99
+ | Provider outage | Your app breaks | Automatic failover to next provider |
100
+ | Request tracing | Nothing | `meta.trace` — latency, retries, circuit state |
101
+ | API drift | Silent production breaks | `meridian.schema.check()` — detect before it breaks |
27
102
 
28
103
  ---
29
104
 
30
- ## Quick Start
105
+ ## Service Abstraction & Failover
31
106
 
32
- ```typescript
33
- import { Meridian } from "meridianjs";
107
+ Your application stops knowing which vendor it uses. If OpenAI goes down, Anthropic takes over. No code changes, no deployment.
34
108
 
109
+ ```typescript
35
110
  const meridian = await Meridian.create({
111
+ localUnsafe: true,
36
112
  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
- },
113
+ openai: { auth: { apiKey: process.env.OPENAI_API_KEY } },
114
+ anthropic: { auth: { apiKey: process.env.ANTHROPIC_API_KEY } },
115
+ gemini: { auth: { apiKey: process.env.GEMINI_API_KEY } },
116
+ },
117
+ services: {
118
+ llm: {
119
+ providers: ["openai", "anthropic", "gemini"],
120
+ strategy: "failover", // try in order, advance on network/rate/provider errors
121
+ },
122
+ payments: {
123
+ providers: ["stripe", "razorpay"],
124
+ strategy: "highest-success-rate", // always routes to healthiest provider
125
+ },
126
+ cheapLlm: {
127
+ providers: ["openai", "anthropic", "gemini"],
128
+ strategy: "cheapest",
129
+ costs: { openai: 0.03, anthropic: 0.01, gemini: 0.02 }, // per 1K tokens
43
130
  },
44
131
  },
45
132
  });
46
133
 
47
- // Same API for every provider
48
- const { data, meta } = await meridian.provider("stripe").get("/v1/customers");
134
+ // Your application never touches provider names again
135
+ const result = await meridian.service("llm")!.post("/v1/chat/completions", {
136
+ body: { model: "gpt-4o", messages: [{ role: "user", content: "Hello" }] },
137
+ });
138
+ ```
139
+
140
+ **Routing strategies:**
141
+
142
+ | Strategy | Behaviour |
143
+ |---|---|
144
+ | `"failover"` | Try providers in order. Advance on `rate_limit`, `network`, or `provider` errors. |
145
+ | `"round-robin"` | Distribute requests evenly across all providers. |
146
+ | `"lowest-latency"` | Route to the fastest provider. Self-calibrates using EWMA over `meta.trace.latency`. |
147
+ | `"cheapest"` | Route to the cheapest provider. Fails over in ascending cost order. |
148
+ | `"highest-success-rate"` | Route to the provider with the best live success rate from `meridian.analytics()`. |
149
+
150
+ ---
151
+
152
+ ## Request Trace
153
+
154
+ Every response carries operational telemetry — no configuration needed:
49
155
 
50
- console.log(meta.provider); // "stripe"
51
- console.log(meta.rateLimit.remaining); // always normalized
52
- console.log(meta.pagination.hasNext); // always normalized
156
+ ```typescript
157
+ const result = await meridian.provider("stripe").get("/v1/customers");
158
+
159
+ console.log(result.meta.trace);
160
+ // {
161
+ // retries: 2,
162
+ // latency: 341, // ms end-to-end including retries
163
+ // circuitBreaker: "CLOSED",
164
+ // rateLimitRemaining: 91
165
+ // }
166
+ ```
167
+
168
+ ---
169
+
170
+ ## Analytics & Health
171
+
172
+ ```typescript
173
+ // After some traffic has flowed through:
174
+ console.log(meridian.analytics());
175
+ // {
176
+ // stripe: { requests: 12431, errors: 37, errorRate: "0.3%", avgLatency: 240, p95Latency: 480 },
177
+ // razorpay: { requests: 8111, errors: 146, errorRate: "1.8%", avgLatency: 410, p95Latency: 820 },
178
+ // openai: { requests: 4200, errors: 50, errorRate: "1.2%", avgLatency: 780, p95Latency: 1500 }
179
+ // }
180
+
181
+ console.log(meridian.health());
182
+ // {
183
+ // stripe: { status: "healthy", successRate: "99.7%", avgLatency: 240, circuitBreaker: "CLOSED" },
184
+ // razorpay: { status: "degraded", successRate: "98.2%", avgLatency: 410, circuitBreaker: "CLOSED" },
185
+ // openai: { status: "down", successRate: "88.1%", avgLatency: 780, circuitBreaker: "OPEN" }
186
+ // }
53
187
  ```
54
188
 
55
- Switch providers your app code doesn't change.
189
+ Health thresholds: `>= 99%` healthy, `>= 95%` → degraded, `< 95%` → down. Circuit breaker state overrides: `OPEN` → down, `HALF_OPEN` → at least degraded.
56
190
 
57
191
  ---
58
192
 
59
- ## What It Does
193
+ ## Debug Recording & Replay
194
+
195
+ Record production requests. Replay failures locally.
196
+
197
+ ```typescript
198
+ meridian.debug.enable();
199
+
200
+ // Run your application...
201
+
202
+ const recordings = meridian.debug.recordings();
203
+ // [
204
+ // {
205
+ // requestId: "abc-123",
206
+ // provider: "stripe",
207
+ // endpoint: "/v1/charges",
208
+ // method: "POST",
209
+ // statusCode: 200,
210
+ // duration: 241,
211
+ // trace: { retries: 0, latency: 241, circuitBreaker: "CLOSED", rateLimitRemaining: 99 },
212
+ // options: { method: "POST", body: { amount: 1000, currency: "usd" } }
213
+ // }
214
+ // ]
215
+
216
+ // Replay a specific request with identical options:
217
+ const fresh = await meridian.replay("abc-123");
218
+
219
+ meridian.debug.disable();
220
+ meridian.debug.clear();
221
+ ```
222
+
223
+ ---
60
224
 
61
- | Feature | Description |
225
+ ## Policy Engine
226
+
227
+ Block requests before they leave your application. Enforce compliance rules at the SDK layer.
228
+
229
+ ```typescript
230
+ import { Meridian, blockPII, allowedProviders, readOnly, customPolicy } from "meridianjs";
231
+
232
+ const meridian = await Meridian.create({
233
+ localUnsafe: true,
234
+ providers: { openai: { auth: { apiKey: "..." } } },
235
+ policies: [
236
+ // Block PII (credit cards, SSNs, emails, Aadhaar, PAN) from reaching OpenAI
237
+ blockPII(["openai"]),
238
+
239
+ // Only allow these providers to be used
240
+ allowedProviders(["openai", "stripe"]),
241
+
242
+ // No write operations to GitHub in this service
243
+ readOnly(["github"]),
244
+
245
+ // Custom policy with your own logic
246
+ customPolicy("require-tenant-id", (ctx) =>
247
+ ctx.body && typeof ctx.body === "object" && "tenantId" in ctx.body
248
+ ? { allow: true }
249
+ : { allow: false, reason: "tenantId is required in all requests" }
250
+ ),
251
+ ],
252
+ });
253
+ ```
254
+
255
+ A blocked request throws `MeridianError` with `category: "validation"` containing the policy name and reason. Policies run before the request leaves the process — no network round-trip wasted.
256
+
257
+ **Built-in policies:**
258
+
259
+ | Function | Description |
62
260
  |---|---|
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) |
261
+ | `blockPII(providers?)` | Detects and blocks credit cards, SSNs, emails, phone numbers, Aadhaar, PAN |
262
+ | `allowedProviders(list)` | Only allow requests to the specified providers |
263
+ | `blockedProviders(list)` | Block requests to the specified providers entirely |
264
+ | `readOnly(providers?)` | Block POST, PUT, PATCH, DELETE |
265
+ | `customPolicy(name, fn)` | Define any rule as a function |
73
266
 
74
267
  ---
75
268
 
76
- ## Provider Status Matrix
269
+ ## Multi-Provider Transactions
270
+
271
+ Coordinate operations across multiple providers. If any step fails, compensating rollbacks run automatically in reverse order.
272
+
273
+ ```typescript
274
+ import { Meridian } from "meridianjs";
275
+
276
+ const stripe = meridian.provider("stripe")!;
277
+ const sendgrid = meridian.provider("sendgrid")!;
278
+ const hubspot = meridian.provider("hubspot")!;
279
+
280
+ const result = await meridian.transaction([
281
+ {
282
+ name: "charge",
283
+ execute: async () =>
284
+ stripe.post("/v1/charges", { body: { amount: 2000, currency: "usd", source: "tok_visa" } }),
285
+ rollback: async (r) =>
286
+ stripe.post(`/v1/charges/${(r.data as any).id}/refund`),
287
+ },
288
+ {
289
+ name: "email",
290
+ execute: async () =>
291
+ sendgrid.post("/v3/mail/send", { body: { to: "user@example.com", subject: "Receipt" } }),
292
+ // no rollback — can't unsend an email
293
+ },
294
+ {
295
+ name: "crm",
296
+ execute: async () =>
297
+ hubspot.post("/crm/v3/objects/contacts", { body: { properties: { email: "user@example.com" } } }),
298
+ rollback: async (r) =>
299
+ hubspot.delete(`/crm/v3/objects/contacts/${(r.data as any).id}`),
300
+ },
301
+ ]);
302
+
303
+ // { succeeded: ["charge", "email", "crm"], rolledBack: [], results: {...} }
304
+ ```
305
+
306
+ If `crm` fails: charge is refunded, `email` has no rollback (skipped), and `TransactionError` is thrown with `failed`, `succeeded`, `rolledBack`, `rollbackErrors`, and partial `results`.
307
+
308
+ ---
309
+
310
+ ## Schema Drift Detection
311
+
312
+ Snapshot API response schemas and get alerted when providers silently rename or remove fields.
313
+
314
+ ```typescript
315
+ // Baseline today's response:
316
+ const customers = await meridian.provider("stripe")!.get("/v1/customers");
317
+ await meridian.schema.snapshot("stripe", "/v1/customers", customers.data);
318
+
319
+ // Run again tomorrow (or in CI):
320
+ const latest = await meridian.provider("stripe")!.get("/v1/customers");
321
+ const drifts = await meridian.schema.check("stripe", "/v1/customers", latest.data);
322
+
323
+ if (drifts.length > 0) {
324
+ console.error("Stripe API drift detected:");
325
+ for (const d of drifts) {
326
+ console.error(` ${d.severity} ${d.type}: field "${d.field}" changed from ${d.oldValue} → ${d.newValue}`);
327
+ }
328
+ }
329
+ // ERROR FIELD_REMOVED: field "customer_name" changed from "string" → undefined
330
+ // WARNING REQUIRED_REMOVED: field "name" changed from true → false
331
+ ```
332
+
333
+ Schemas are stored by default in `.meridian/schemas/` (file system). Configure a custom `SchemaStorage` for cloud storage or databases.
334
+
335
+ ---
336
+
337
+ ## Provider Capability Registry
338
+
339
+ Discover what each provider supports. Build capability-driven routing.
340
+
341
+ ```typescript
342
+ meridian.providers();
343
+ // [
344
+ // { name: "openai", capabilities: ["chat", "completions", "embeddings", "streaming", "vision", ...] },
345
+ // { name: "stripe", capabilities: ["payments", "subscriptions", "refunds", "invoices", ...] },
346
+ // { name: "razorpay", capabilities: ["payments", "upi", "subscriptions", "refunds", ...] },
347
+ // ]
348
+
349
+ meridian.findProviders({ capability: "streaming" });
350
+ // [{ name: "openai", ... }, { name: "anthropic", ... }, { name: "gemini", ... }, { name: "mistral", ... }]
77
351
 
78
- Every adapter in Meridian is held to the **same** contract — adapters are just data sources, so the guarantees Meridian makes (error normalization, retry semantics, rate-limit parsing, pagination, request shaping) must hold identically across all of them. A single, provider-agnostic suite (`runProviderContract`) runs **19 invariants against every registered adapter** in CI, so a provider is only listed here if it upholds the full contract.
352
+ meridian.findProviders({ capability: "kyc" });
353
+ // [{ name: "hyperverge", ... }, { name: "digio", ... }, { name: "karza", ... }, { name: "idfy", ... }]
354
+
355
+ meridian.findProviders({ capability: "upi" });
356
+ // [{ name: "razorpay", ... }, { name: "phonepe", ... }, { name: "cashfree", ... }, { name: "setu", ... }]
357
+ ```
358
+
359
+ Custom adapters can declare additional capabilities via the optional `capabilities(): string[]` method.
360
+
361
+ ---
362
+
363
+ ## Adapter Generator
364
+
365
+ Scaffold a new provider adapter in under a minute.
79
366
 
80
367
  ```bash
81
- npm run test:contracts # run the contract against all 39 adapters
82
- npm run test:contracts stripe # focus a single provider
368
+ # From a description:
369
+ npx meridian generate --provider acme --base-url https://api.acme.com --auth bearer
370
+
371
+ # From an OpenAPI 3.x spec:
372
+ npx meridian generate --provider acme --openapi ./acme-openapi.json
83
373
  ```
84
374
 
85
- | Provider | Category | Contract Tests | Status |
86
- |:---|:---|:---:|:---:|
87
- | **Adyen** | Payments | 19/19 Passed | ✅ Production-Ready |
88
- | **Anthropic** | AI / LLM | 19/19 Passed | ✅ Production-Ready |
89
- | **Apollo.io** | CRM / Sales | 19/19 Passed | ✅ Production-Ready |
90
- | **Auth0** | Auth / Identity | 19/19 Passed | ✅ Production-Ready |
91
- | **Braintree** | Payments | 19/19 Passed | Production-Ready |
92
- | **Cashfree** | Payments | 19/19 Passed | ✅ Production-Ready |
93
- | **Checkout.com** | Payments | 19/19 Passed | ✅ Production-Ready |
94
- | **Cleartax** | Tax / Compliance | 19/19 Passed | ✅ Production-Ready |
95
- | **Cohere** | AI / LLM | 19/19 Passed | ✅ Production-Ready |
96
- | **Decentro** | Banking / Fintech | 19/19 Passed | ✅ Production-Ready |
97
- | **Delhivery** | Logistics | 19/19 Passed | ✅ Production-Ready |
98
- | **Digio** | eSign / KYC | 19/19 Passed | ✅ Production-Ready |
99
- | **Exotel** | Communications | 19/19 Passed | Production-Ready |
100
- | **Google Gemini** | AI / LLM | 19/19 Passed | ✅ Production-Ready |
101
- | **Gupshup** | Communications | 19/19 Passed | Production-Ready |
102
- | **GitHub** | Developer Tools | 19/19 Passed | ✅ Production-Ready |
103
- | **HubSpot** | CRM | 19/19 Passed | ✅ Production-Ready |
104
- | **HyperVerge** | KYC / Identity | 19/19 Passed | ✅ Production-Ready |
105
- | **IDfy** | KYC / Identity | 19/19 Passed | ✅ Production-Ready |
106
- | **Juspay** | Payments | 19/19 Passed | ✅ Production-Ready |
107
- | **Karza** | KYC / Verification | 19/19 Passed | ✅ Production-Ready |
108
- | **Klarna** | Payments | 19/19 Passed | ✅ Production-Ready |
109
- | **Mailgun** | Communications | 19/19 Passed | ✅ Production-Ready |
110
- | **MapMyIndia** | Maps / Geo | 19/19 Passed | ✅ Production-Ready |
111
- | **Mistral** | AI / LLM | 19/19 Passed | ✅ Production-Ready |
112
- | **Mollie** | Payments | 19/19 Passed | ✅ Production-Ready |
113
- | **MSG91** | Communications | 19/19 Passed | ✅ Production-Ready |
114
- | **OpenAI** | AI / LLM | 19/19 Passed | ✅ Production-Ready |
115
- | **PayU** | Payments | 19/19 Passed | ✅ Production-Ready |
116
- | **Perfios** | Financial Data | 19/19 Passed | ✅ Production-Ready |
117
- | **PhonePe** | Payments | 19/19 Passed | ✅ Production-Ready |
118
- | **Razorpay** | Payments | 19/19 Passed | ✅ Production-Ready |
119
- | **SendGrid** | Communications | 19/19 Passed | ✅ Production-Ready |
120
- | **Setu** | Banking / UPI | 19/19 Passed | ✅ Production-Ready |
121
- | **Shiprocket** | Logistics | 19/19 Passed | ✅ Production-Ready |
122
- | **Stripe** | Payments | 19/19 Passed | ✅ Production-Ready |
123
- | **Supabase** | Database / Auth | 19/19 Passed | ✅ Production-Ready |
124
- | **Twilio** | Communications | 19/19 Passed | ✅ Production-Ready |
125
- | **Vonage** | Communications | 19/19 Passed | ✅ Production-Ready |
375
+ Generates four files in `src/providers/acme/`:
376
+
377
+ | File | Contents |
378
+ |---|---|
379
+ | `adapter.ts` | Full working adapter with auth, error mapping, rate-limit header parsing |
380
+ | `adapter.test.ts` | 8 tests that pass immediately |
381
+ | `pagination.ts` | Cursor pagination stub with TODO comments |
382
+ | `index.ts` | Barrel export |
383
+
384
+ **Options:**
385
+
386
+ | Flag | Description | Default |
387
+ |---|---|---|
388
+ | `--provider` | Provider name (required) | |
389
+ | `--openapi` | Path to OpenAPI 3.x JSON file | |
390
+ | `--base-url` | API base URL | `https://api.<name>.com` |
391
+ | `--auth` | Auth type: `apiKey`, `bearer`, `basic`, `oauth2` | `apiKey` |
392
+ | `--output` | Output directory | `src/providers/<name>/` |
126
393
 
127
394
  ---
128
395
 
129
396
  ## Error Handling
130
397
 
131
- Every error has the same shape — no more `try/catch` archaeology per provider:
398
+ Every provider error has the same shape — no more per-provider archaeology:
132
399
 
133
400
  ```typescript
134
401
  try {
135
- const result = await meridian.provider("stripe").post("/v1/charges", { body });
402
+ const result = await meridian.provider("stripe")!.post("/v1/charges", { body });
136
403
  } catch (err) {
137
404
  if (err instanceof MeridianError) {
138
405
  err.category; // "auth" | "rate_limit" | "validation" | "network" | "provider"
139
- err.retryable; // boolean
140
- err.retryAfter; // Date | undefined
406
+ err.code; // "AUTH_FAILED" | "RATE_LIMITED" | "BAD_REQUEST" | "UPSTREAM_5XX" | ...
407
+ err.retryable; // boolean safe to retry?
408
+ err.retryAfter; // Date | undefined — when to retry
141
409
  err.provider; // "stripe"
410
+ err.requestId; // for support tickets
411
+ }
412
+ }
413
+ ```
414
+
415
+ ---
416
+
417
+ ## Circuit Breaker
418
+
419
+ Each provider has its own circuit breaker. Opens after repeated failures, probes with a single request after a timeout, closes on success.
420
+
421
+ ```typescript
422
+ const status = meridian.getCircuitStatus("stripe");
423
+ // {
424
+ // state: "CLOSED", // "CLOSED" | "OPEN" | "HALF_OPEN"
425
+ // failures: 0,
426
+ // successes: 12,
427
+ // lastFailure: null,
428
+ // nextAttempt: null
429
+ // }
430
+ ```
431
+
432
+ ---
433
+
434
+ ## Pagination
435
+
436
+ ```typescript
437
+ for await (const page of meridian.provider("stripe")!.paginate("/v1/customers")) {
438
+ console.log(page.meta.pagination);
439
+ // { hasNext: true, cursor: "cu_next123", total: 4200 }
440
+ for (const customer of page.data as Customer[]) {
441
+ process(customer);
142
442
  }
143
443
  }
144
444
  ```
145
445
 
446
+ Works identically for cursor, offset, and link-header pagination — the adapter handles the translation.
447
+
448
+ ---
449
+
450
+ ## Streaming
451
+
452
+ ```typescript
453
+ for await (const chunk of meridian.provider("openai")!.stream("/v1/chat/completions", {
454
+ body: { model: "gpt-4o", messages: [{ role: "user", content: "Hello" }], stream: true },
455
+ })) {
456
+ process.stdout.write(chunk.data as string);
457
+ }
458
+ ```
459
+
460
+ Supported: OpenAI, Anthropic, Gemini, Mistral, Cohere.
461
+
462
+ ---
463
+
464
+ ## Batch Requests
465
+
466
+ ```typescript
467
+ const results = await meridian.provider("stripe")!.batch([
468
+ { method: "GET", endpoint: "/v1/customers/cu_1" },
469
+ { method: "GET", endpoint: "/v1/customers/cu_2" },
470
+ { method: "GET", endpoint: "/v1/customers/cu_3" },
471
+ ], 5); // max 5 concurrent
472
+
473
+ // Results always in input order. Errors are MeridianError, never thrown.
474
+ ```
475
+
146
476
  ---
147
477
 
148
478
  ## Webhook Verification
@@ -158,31 +488,168 @@ const valid = adapter.verifyWebhook(
158
488
  );
159
489
  ```
160
490
 
161
- Works identically for Razorpay, Cashfree, Braintree, Twilio, Adyen, and more.
491
+ Timing-safe HMAC verification available on Stripe, Razorpay, Cashfree, Braintree, Twilio, Adyen, and more.
162
492
 
163
493
  ---
164
494
 
165
- ## Batch Requests
495
+ ## Configuration Reference
166
496
 
167
497
  ```typescript
168
- const results = await meridian.provider("stripe").batch([
169
- { method: "GET", endpoint: "/v1/customers/cu_1" },
170
- { method: "GET", endpoint: "/v1/customers/cu_2" },
171
- { method: "GET", endpoint: "/v1/customers/cu_3" },
172
- ], 5); // max 5 concurrent
498
+ const meridian = await Meridian.create({
499
+ // Required: either localUnsafe:true or stateStorage
500
+ localUnsafe: true, // dev only — warns on startup
501
+
502
+ // Per-provider configuration
503
+ providers: {
504
+ stripe: {
505
+ auth: { apiKey: "sk_live_..." }, // or token, username/password, clientId/Secret
506
+ baseUrl: "https://api.stripe.com", // override base URL
507
+ retry: { maxRetries: 3, baseDelay: 1000, maxDelay: 30000, jitter: true },
508
+ circuitBreaker: { failureThreshold: 5, timeout: 60000, errorThresholdPercentage: 50 },
509
+ rateLimit: { tokensPerSecond: 10, maxTokens: 100, adaptiveBackoff: true },
510
+ },
511
+ },
512
+
513
+ // Service abstraction — group providers behind a logical name
514
+ services: {
515
+ llm: { providers: ["openai", "anthropic"], strategy: "failover" },
516
+ },
517
+
518
+ // Default settings applied to all providers
519
+ defaults: {
520
+ timeout: 30000,
521
+ retry: { maxRetries: 2 },
522
+ circuitBreaker: { failureThreshold: 5 },
523
+ },
524
+
525
+ // Policy engine
526
+ policies: [blockPII(["openai"]), readOnly(["github"])],
527
+
528
+ // Observability (any number of adapters)
529
+ observability: [new ConsoleObservability(), new PrometheusObservability()],
530
+
531
+ // Distributed state (required for multi-instance deployments)
532
+ mode: "distributed",
533
+ stateStorage: new RedisStateStorage(redisClient),
534
+
535
+ // Schema validation & drift detection
536
+ schemaValidation: {
537
+ enabled: true,
538
+ storage: new FileSystemSchemaStorage(".meridian/schemas"),
539
+ onDrift: (drifts) => alerting.notify(drifts),
540
+ },
541
+
542
+ // Compliance
543
+ compliance: {
544
+ piiRedaction: true, // redacts Aadhaar, PAN, bank accounts from logs
545
+ indiaMode: true, // DPDPA-compliant redaction
546
+ auditLog: true,
547
+ },
548
+
549
+ // Idempotency
550
+ idempotency: {
551
+ defaultLevel: IdempotencyLevel.SAFE,
552
+ autoGenerateKeys: true,
553
+ },
554
+ });
555
+ ```
556
+
557
+ ---
173
558
 
174
- // Results are always in input order; errors are MeridianError, never thrown
559
+ ## Provider Status Matrix
560
+
561
+ Every adapter passes a 19-invariant contract test suite before being listed. Run the suite yourself:
562
+
563
+ ```bash
564
+ npm run test:contracts # all 39 adapters
565
+ npm run test:contracts stripe # single provider
175
566
  ```
176
567
 
177
- ## Support & Contact
568
+ | Provider | Category | Contract | Status |
569
+ |:---|:---|:---:|:---:|
570
+ | **Adyen** | Payments | 19/19 | ✅ |
571
+ | **Anthropic** | AI / LLM | 19/19 | ✅ |
572
+ | **Apollo.io** | CRM / Sales | 19/19 | ✅ |
573
+ | **Auth0** | Auth / Identity | 19/19 | ✅ |
574
+ | **Braintree** | Payments | 19/19 | ✅ |
575
+ | **Cashfree** | Payments | 19/19 | ✅ |
576
+ | **Checkout.com** | Payments | 19/19 | ✅ |
577
+ | **Cleartax** | Tax / Compliance | 19/19 | ✅ |
578
+ | **Cohere** | AI / LLM | 19/19 | ✅ |
579
+ | **Decentro** | Banking / Fintech | 19/19 | ✅ |
580
+ | **Delhivery** | Logistics | 19/19 | ✅ |
581
+ | **Digio** | eSign / KYC | 19/19 | ✅ |
582
+ | **Exotel** | Communications | 19/19 | ✅ |
583
+ | **Google Gemini** | AI / LLM | 19/19 | ✅ |
584
+ | **GitHub** | Developer Tools | 19/19 | ✅ |
585
+ | **Gupshup** | Communications | 19/19 | ✅ |
586
+ | **HubSpot** | CRM | 19/19 | ✅ |
587
+ | **HyperVerge** | KYC / Identity | 19/19 | ✅ |
588
+ | **IDfy** | KYC / Identity | 19/19 | ✅ |
589
+ | **Juspay** | Payments | 19/19 | ✅ |
590
+ | **Karza** | KYC / Verification | 19/19 | ✅ |
591
+ | **Klarna** | Payments | 19/19 | ✅ |
592
+ | **Mailgun** | Communications | 19/19 | ✅ |
593
+ | **MapMyIndia** | Maps / Geo | 19/19 | ✅ |
594
+ | **Mistral** | AI / LLM | 19/19 | ✅ |
595
+ | **Mollie** | Payments | 19/19 | ✅ |
596
+ | **MSG91** | Communications | 19/19 | ✅ |
597
+ | **OpenAI** | AI / LLM | 19/19 | ✅ |
598
+ | **PayU** | Payments | 19/19 | ✅ |
599
+ | **Perfios** | Financial Data | 19/19 | ✅ |
600
+ | **PhonePe** | Payments | 19/19 | ✅ |
601
+ | **Razorpay** | Payments | 19/19 | ✅ |
602
+ | **SendGrid** | Communications | 19/19 | ✅ |
603
+ | **Setu** | Banking / UPI | 19/19 | ✅ |
604
+ | **Shiprocket** | Logistics | 19/19 | ✅ |
605
+ | **Stripe** | Payments | 19/19 | ✅ |
606
+ | **Supabase** | Database / Auth | 19/19 | ✅ |
607
+ | **Twilio** | Communications | 19/19 | ✅ |
608
+ | **Vonage** | Communications | 19/19 | ✅ |
609
+
610
+ ---
611
+
612
+ ## Adding a Provider
613
+
614
+ Fastest path: use the generator.
615
+
616
+ ```bash
617
+ npx meridian generate --provider myprovider --openapi ./myprovider-openapi.json
618
+ ```
619
+
620
+ Manual path: implement `ProviderAdapter` and register it:
621
+
622
+ ```typescript
623
+ import type { ProviderAdapter } from "meridianjs";
624
+
625
+ class MyAdapter implements ProviderAdapter {
626
+ buildRequest(input) { ... }
627
+ parseResponse(raw) { ... }
628
+ parseError(raw) { ... }
629
+ authStrategy(cfg) { ... }
630
+ rateLimitPolicy(h) { ... }
631
+ paginationStrategy(){ ... }
632
+ getIdempotencyConfig() { ... }
633
+ }
634
+
635
+ await meridian.registerProvider("myprovider", new MyAdapter(), {
636
+ auth: { apiKey: process.env.MY_API_KEY },
637
+ });
638
+ ```
639
+
640
+ ---
641
+
642
+ ## Contributing
178
643
 
179
- If you encounter any issues or have questions, please reach out directly at [raghav.verma.work@gmail.com](mailto:raghav.verma.work@gmail.com).
644
+ 1. Fork feature branch PR
645
+ 2. Every new adapter requires: `adapter.ts`, `adapter.test.ts`, `pagination.ts`, `index.ts`
646
+ 3. All existing contract tests must continue to pass: `npm test`
647
+ 4. The adapter generator produces a correct starting point: `npx meridian generate --provider yourprovider`
180
648
 
181
649
  ---
182
650
 
183
651
  ## Links
184
652
 
185
- - [GitHub](https://github.com/Raghaverma/Meridianjs)
186
653
  - [Changelog](CHANGELOG.md)
187
- - [Roadmap](ROADMAP.md)
188
654
  - [License: MIT](LICENSE.md)
655
+ - [npm](https://www.npmjs.com/package/meridianjs)