@nehorai/payments-drizzle 0.1.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/LICENSE +21 -0
- package/dist/index.cjs +1310 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +47 -0
- package/dist/index.d.ts +47 -0
- package/dist/index.js +1289 -0
- package/dist/index.js.map +1 -0
- package/dist/provider-health.drizzle-repository-DfRo4qJ8.d.cts +185 -0
- package/dist/provider-health.drizzle-repository-DfRo4qJ8.d.ts +185 -0
- package/dist/repositories/index.cjs +1190 -0
- package/dist/repositories/index.cjs.map +1 -0
- package/dist/repositories/index.d.cts +16 -0
- package/dist/repositories/index.d.ts +16 -0
- package/dist/repositories/index.js +1177 -0
- package/dist/repositories/index.js.map +1 -0
- package/dist/schema/index.cjs +276 -0
- package/dist/schema/index.cjs.map +1 -0
- package/dist/schema/index.d.cts +1729 -0
- package/dist/schema/index.d.ts +1729 -0
- package/dist/schema/index.js +269 -0
- package/dist/schema/index.js.map +1 -0
- package/dist/storage/index.cjs +124 -0
- package/dist/storage/index.cjs.map +1 -0
- package/dist/storage/index.d.cts +52 -0
- package/dist/storage/index.d.ts +52 -0
- package/dist/storage/index.js +96 -0
- package/dist/storage/index.js.map +1 -0
- package/package.json +53 -0
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
// src/storage/drizzle-circuit-breaker-storage.ts
|
|
2
|
+
var DrizzleCircuitBreakerStorage = class {
|
|
3
|
+
repo;
|
|
4
|
+
constructor(providerHealthRepository) {
|
|
5
|
+
this.repo = providerHealthRepository;
|
|
6
|
+
}
|
|
7
|
+
async getState(provider) {
|
|
8
|
+
try {
|
|
9
|
+
const health = await this.repo.findByProvider(provider);
|
|
10
|
+
if (!health) return null;
|
|
11
|
+
return this.mapToStateRecord(provider, health);
|
|
12
|
+
} catch (error) {
|
|
13
|
+
console.error(`[DrizzleCircuitBreakerStorage] Failed to get state for ${provider}:`, error);
|
|
14
|
+
return null;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
async setState(provider, state) {
|
|
18
|
+
try {
|
|
19
|
+
await this.repo.getOrCreate(provider);
|
|
20
|
+
await this.repo.update(provider, {
|
|
21
|
+
circuitState: state.state,
|
|
22
|
+
failureCount: state.failureCount,
|
|
23
|
+
successCount: state.successCount,
|
|
24
|
+
lastFailureAt: state.lastFailure ?? void 0,
|
|
25
|
+
circuitOpenedAt: state.openedAt ?? void 0,
|
|
26
|
+
nextRetryAt: state.nextRetryAt ?? void 0
|
|
27
|
+
});
|
|
28
|
+
} catch (error) {
|
|
29
|
+
console.error(`[DrizzleCircuitBreakerStorage] Failed to set state for ${provider}:`, error);
|
|
30
|
+
throw error;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
async getAllStates() {
|
|
34
|
+
try {
|
|
35
|
+
const allHealth = await this.repo.findAll();
|
|
36
|
+
const states = /* @__PURE__ */ new Map();
|
|
37
|
+
for (const health of allHealth) {
|
|
38
|
+
const provider = health.provider;
|
|
39
|
+
states.set(provider, this.mapToStateRecord(provider, health));
|
|
40
|
+
}
|
|
41
|
+
return states;
|
|
42
|
+
} catch (error) {
|
|
43
|
+
console.error("[DrizzleCircuitBreakerStorage] Failed to get all states:", error);
|
|
44
|
+
return /* @__PURE__ */ new Map();
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
async deleteState(provider) {
|
|
48
|
+
try {
|
|
49
|
+
await this.repo.resetStats(provider);
|
|
50
|
+
await this.repo.closeCircuit(provider);
|
|
51
|
+
} catch (error) {
|
|
52
|
+
console.error(`[DrizzleCircuitBreakerStorage] Failed to delete state for ${provider}:`, error);
|
|
53
|
+
throw error;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
async getOpenCircuits() {
|
|
57
|
+
try {
|
|
58
|
+
const openHealth = await this.repo.findOpenCircuits();
|
|
59
|
+
return openHealth.map((h) => h.provider);
|
|
60
|
+
} catch (error) {
|
|
61
|
+
console.error("[DrizzleCircuitBreakerStorage] Failed to get open circuits:", error);
|
|
62
|
+
return [];
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
async isHealthy() {
|
|
66
|
+
try {
|
|
67
|
+
await this.repo.findAll();
|
|
68
|
+
return true;
|
|
69
|
+
} catch (error) {
|
|
70
|
+
console.error("[DrizzleCircuitBreakerStorage] Health check failed:", error);
|
|
71
|
+
return false;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
// ==========================================================================
|
|
75
|
+
// Helper Methods
|
|
76
|
+
// ==========================================================================
|
|
77
|
+
mapToStateRecord(provider, health) {
|
|
78
|
+
return {
|
|
79
|
+
provider,
|
|
80
|
+
state: health.circuitState,
|
|
81
|
+
failureCount: health.failureCount,
|
|
82
|
+
successCount: health.successCount,
|
|
83
|
+
lastFailure: health.lastFailureAt,
|
|
84
|
+
openedAt: health.circuitOpenedAt,
|
|
85
|
+
nextRetryAt: health.nextRetryAt
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
function createDrizzleCircuitBreakerStorage(providerHealthRepo) {
|
|
90
|
+
return new DrizzleCircuitBreakerStorage(providerHealthRepo);
|
|
91
|
+
}
|
|
92
|
+
export {
|
|
93
|
+
DrizzleCircuitBreakerStorage,
|
|
94
|
+
createDrizzleCircuitBreakerStorage
|
|
95
|
+
};
|
|
96
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/storage/drizzle-circuit-breaker-storage.ts"],"sourcesContent":["/**\n * @nehorai/payments-drizzle - Drizzle Circuit Breaker Storage\n *\n * Database-backed storage implementation using the existing provider_health table.\n * Suitable for serverless deployments and multi-instance environments.\n *\n * Benefits:\n * - State persists across deployments\n * - Shared state across multiple instances (serverless-friendly)\n * - Uses existing provider_health table (no migration needed)\n *\n * Usage:\n * ```typescript\n * const repos = createDrizzleRepositories(db);\n * const storage = new DrizzleCircuitBreakerStorage(repos.providerHealth);\n * const circuitBreaker = new CircuitBreaker({ storage });\n * ```\n */\n\nimport type { PaymentProvider } from '@nehorai/payments/types'\nimport type { IProviderHealthRepository } from '@nehorai/payments/repository'\nimport type {\n ICircuitBreakerStorage,\n CircuitBreakerStateRecord,\n StoredCircuitState,\n} from '@nehorai/payments/services'\n\n// ============================================================================\n// Drizzle Storage Implementation\n// ============================================================================\n\n/**\n * Drizzle-based implementation of ICircuitBreakerStorage\n *\n * Uses the existing provider_health table via IProviderHealthRepository.\n * Perfect for serverless environments (Vercel, AWS Lambda) where\n * in-memory state doesn't persist between invocations.\n */\nexport class DrizzleCircuitBreakerStorage implements ICircuitBreakerStorage {\n private repo: IProviderHealthRepository\n\n constructor(providerHealthRepository: IProviderHealthRepository) {\n this.repo = providerHealthRepository\n }\n\n async getState(provider: PaymentProvider): Promise<CircuitBreakerStateRecord | null> {\n try {\n const health = await this.repo.findByProvider(provider)\n if (!health) return null\n\n return this.mapToStateRecord(provider, health)\n } catch (error) {\n console.error(`[DrizzleCircuitBreakerStorage] Failed to get state for ${provider}:`, error)\n return null\n }\n }\n\n async setState(provider: PaymentProvider, state: CircuitBreakerStateRecord): Promise<void> {\n try {\n // Ensure record exists\n await this.repo.getOrCreate(provider)\n\n // Update with new state\n await this.repo.update(provider, {\n circuitState: state.state,\n failureCount: state.failureCount,\n successCount: state.successCount,\n lastFailureAt: state.lastFailure ?? undefined,\n circuitOpenedAt: state.openedAt ?? undefined,\n nextRetryAt: state.nextRetryAt ?? undefined,\n })\n } catch (error) {\n console.error(`[DrizzleCircuitBreakerStorage] Failed to set state for ${provider}:`, error)\n throw error\n }\n }\n\n async getAllStates(): Promise<Map<PaymentProvider, CircuitBreakerStateRecord>> {\n try {\n const allHealth = await this.repo.findAll()\n const states = new Map<PaymentProvider, CircuitBreakerStateRecord>()\n\n for (const health of allHealth) {\n const provider = health.provider as PaymentProvider\n states.set(provider, this.mapToStateRecord(provider, health))\n }\n\n return states\n } catch (error) {\n console.error('[DrizzleCircuitBreakerStorage] Failed to get all states:', error)\n return new Map()\n }\n }\n\n async deleteState(provider: PaymentProvider): Promise<void> {\n try {\n await this.repo.resetStats(provider)\n await this.repo.closeCircuit(provider)\n } catch (error) {\n console.error(`[DrizzleCircuitBreakerStorage] Failed to delete state for ${provider}:`, error)\n throw error\n }\n }\n\n async getOpenCircuits(): Promise<PaymentProvider[]> {\n try {\n const openHealth = await this.repo.findOpenCircuits()\n return openHealth.map((h) => h.provider as PaymentProvider)\n } catch (error) {\n console.error('[DrizzleCircuitBreakerStorage] Failed to get open circuits:', error)\n return []\n }\n }\n\n async isHealthy(): Promise<boolean> {\n try {\n // Try a simple read operation to verify database connectivity\n await this.repo.findAll()\n return true\n } catch (error) {\n console.error('[DrizzleCircuitBreakerStorage] Health check failed:', error)\n return false\n }\n }\n\n // ==========================================================================\n // Helper Methods\n // ==========================================================================\n\n private mapToStateRecord(\n provider: PaymentProvider,\n health: {\n circuitState: string\n failureCount: number\n successCount: number\n lastFailureAt: Date | null\n circuitOpenedAt: Date | null\n nextRetryAt: Date | null\n }\n ): CircuitBreakerStateRecord {\n return {\n provider,\n state: health.circuitState as StoredCircuitState,\n failureCount: health.failureCount,\n successCount: health.successCount,\n lastFailure: health.lastFailureAt,\n openedAt: health.circuitOpenedAt,\n nextRetryAt: health.nextRetryAt,\n }\n }\n}\n\n// ============================================================================\n// Factory Helper\n// ============================================================================\n\n/**\n * Create a Drizzle-based circuit breaker storage\n *\n * Convenience function for creating storage with a provider health repository.\n *\n * @param providerHealthRepo - The Drizzle provider health repository\n * @returns DrizzleCircuitBreakerStorage instance\n */\nexport function createDrizzleCircuitBreakerStorage(\n providerHealthRepo: IProviderHealthRepository\n): DrizzleCircuitBreakerStorage {\n return new DrizzleCircuitBreakerStorage(providerHealthRepo)\n}\n"],"mappings":";AAsCO,IAAM,+BAAN,MAAqE;AAAA,EAClE;AAAA,EAER,YAAY,0BAAqD;AAC/D,SAAK,OAAO;AAAA,EACd;AAAA,EAEA,MAAM,SAAS,UAAsE;AACnF,QAAI;AACF,YAAM,SAAS,MAAM,KAAK,KAAK,eAAe,QAAQ;AACtD,UAAI,CAAC,OAAQ,QAAO;AAEpB,aAAO,KAAK,iBAAiB,UAAU,MAAM;AAAA,IAC/C,SAAS,OAAO;AACd,cAAQ,MAAM,0DAA0D,QAAQ,KAAK,KAAK;AAC1F,aAAO;AAAA,IACT;AAAA,EACF;AAAA,EAEA,MAAM,SAAS,UAA2B,OAAiD;AACzF,QAAI;AAEF,YAAM,KAAK,KAAK,YAAY,QAAQ;AAGpC,YAAM,KAAK,KAAK,OAAO,UAAU;AAAA,QAC/B,cAAc,MAAM;AAAA,QACpB,cAAc,MAAM;AAAA,QACpB,cAAc,MAAM;AAAA,QACpB,eAAe,MAAM,eAAe;AAAA,QACpC,iBAAiB,MAAM,YAAY;AAAA,QACnC,aAAa,MAAM,eAAe;AAAA,MACpC,CAAC;AAAA,IACH,SAAS,OAAO;AACd,cAAQ,MAAM,0DAA0D,QAAQ,KAAK,KAAK;AAC1F,YAAM;AAAA,IACR;AAAA,EACF;AAAA,EAEA,MAAM,eAAyE;AAC7E,QAAI;AACF,YAAM,YAAY,MAAM,KAAK,KAAK,QAAQ;AAC1C,YAAM,SAAS,oBAAI,IAAgD;AAEnE,iBAAW,UAAU,WAAW;AAC9B,cAAM,WAAW,OAAO;AACxB,eAAO,IAAI,UAAU,KAAK,iBAAiB,UAAU,MAAM,CAAC;AAAA,MAC9D;AAEA,aAAO;AAAA,IACT,SAAS,OAAO;AACd,cAAQ,MAAM,4DAA4D,KAAK;AAC/E,aAAO,oBAAI,IAAI;AAAA,IACjB;AAAA,EACF;AAAA,EAEA,MAAM,YAAY,UAA0C;AAC1D,QAAI;AACF,YAAM,KAAK,KAAK,WAAW,QAAQ;AACnC,YAAM,KAAK,KAAK,aAAa,QAAQ;AAAA,IACvC,SAAS,OAAO;AACd,cAAQ,MAAM,6DAA6D,QAAQ,KAAK,KAAK;AAC7F,YAAM;AAAA,IACR;AAAA,EACF;AAAA,EAEA,MAAM,kBAA8C;AAClD,QAAI;AACF,YAAM,aAAa,MAAM,KAAK,KAAK,iBAAiB;AACpD,aAAO,WAAW,IAAI,CAAC,MAAM,EAAE,QAA2B;AAAA,IAC5D,SAAS,OAAO;AACd,cAAQ,MAAM,+DAA+D,KAAK;AAClF,aAAO,CAAC;AAAA,IACV;AAAA,EACF;AAAA,EAEA,MAAM,YAA8B;AAClC,QAAI;AAEF,YAAM,KAAK,KAAK,QAAQ;AACxB,aAAO;AAAA,IACT,SAAS,OAAO;AACd,cAAQ,MAAM,uDAAuD,KAAK;AAC1E,aAAO;AAAA,IACT;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAMQ,iBACN,UACA,QAQ2B;AAC3B,WAAO;AAAA,MACL;AAAA,MACA,OAAO,OAAO;AAAA,MACd,cAAc,OAAO;AAAA,MACrB,cAAc,OAAO;AAAA,MACrB,aAAa,OAAO;AAAA,MACpB,UAAU,OAAO;AAAA,MACjB,aAAa,OAAO;AAAA,IACtB;AAAA,EACF;AACF;AAcO,SAAS,mCACd,oBAC8B;AAC9B,SAAO,IAAI,6BAA6B,kBAAkB;AAC5D;","names":[]}
|
package/package.json
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@nehorai/payments-drizzle",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Drizzle ORM adapter for @nehorai/payments",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.cjs",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.js",
|
|
12
|
+
"require": "./dist/index.cjs"
|
|
13
|
+
},
|
|
14
|
+
"./schema": {
|
|
15
|
+
"types": "./dist/schema/index.d.ts",
|
|
16
|
+
"import": "./dist/schema/index.js",
|
|
17
|
+
"require": "./dist/schema/index.cjs"
|
|
18
|
+
},
|
|
19
|
+
"./repositories": {
|
|
20
|
+
"types": "./dist/repositories/index.d.ts",
|
|
21
|
+
"import": "./dist/repositories/index.js",
|
|
22
|
+
"require": "./dist/repositories/index.cjs"
|
|
23
|
+
},
|
|
24
|
+
"./storage": {
|
|
25
|
+
"types": "./dist/storage/index.d.ts",
|
|
26
|
+
"import": "./dist/storage/index.js",
|
|
27
|
+
"require": "./dist/storage/index.cjs"
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
"files": [
|
|
31
|
+
"dist"
|
|
32
|
+
],
|
|
33
|
+
"dependencies": {
|
|
34
|
+
"@nehorai/payments": "0.1.0"
|
|
35
|
+
},
|
|
36
|
+
"peerDependencies": {
|
|
37
|
+
"drizzle-orm": ">=0.30.0"
|
|
38
|
+
},
|
|
39
|
+
"devDependencies": {
|
|
40
|
+
"drizzle-orm": "^0.38.0",
|
|
41
|
+
"@types/pg": "^8.11.0",
|
|
42
|
+
"typescript": "^5.7.3",
|
|
43
|
+
"tsup": "^8.0.0",
|
|
44
|
+
"@types/node": "^22.13.4"
|
|
45
|
+
},
|
|
46
|
+
"license": "MIT",
|
|
47
|
+
"author": "Nehorai Hadad",
|
|
48
|
+
"scripts": {
|
|
49
|
+
"build": "tsup",
|
|
50
|
+
"dev": "tsup --watch",
|
|
51
|
+
"typecheck": "tsc --noEmit"
|
|
52
|
+
}
|
|
53
|
+
}
|