@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,269 @@
|
|
|
1
|
+
// src/schema/payment-transactions.ts
|
|
2
|
+
import { pgTable, uuid, text, numeric, timestamp, jsonb, index, unique } from "drizzle-orm/pg-core";
|
|
3
|
+
var paymentTransactions = pgTable(
|
|
4
|
+
"payment_transactions",
|
|
5
|
+
{
|
|
6
|
+
id: uuid("id").defaultRandom().primaryKey(),
|
|
7
|
+
// Idempotency - prevents duplicate charges
|
|
8
|
+
internal_payment_id: text("internal_payment_id").notNull(),
|
|
9
|
+
idempotency_key: text("idempotency_key"),
|
|
10
|
+
// User association (FK configured at application level)
|
|
11
|
+
user_id: uuid("user_id").notNull(),
|
|
12
|
+
// Transaction classification
|
|
13
|
+
transaction_type: text("transaction_type").$type().notNull(),
|
|
14
|
+
status: text("status").$type().notNull().default("created"),
|
|
15
|
+
// Amounts in smallest currency unit (cents/agorot)
|
|
16
|
+
amount_minor: numeric("amount_minor").notNull(),
|
|
17
|
+
currency: text("currency").notNull().default("USD"),
|
|
18
|
+
// Original amount if currency converted
|
|
19
|
+
original_amount_minor: numeric("original_amount_minor"),
|
|
20
|
+
original_currency: text("original_currency"),
|
|
21
|
+
currency_conversion_rate: numeric("currency_conversion_rate"),
|
|
22
|
+
// Provider information
|
|
23
|
+
provider: text("provider").notNull(),
|
|
24
|
+
// stripe, hyp, cardcom
|
|
25
|
+
provider_transaction_id: text("provider_transaction_id"),
|
|
26
|
+
provider_authorization_code: text("provider_authorization_code"),
|
|
27
|
+
provider_metadata: jsonb("provider_metadata").$type(),
|
|
28
|
+
// Two-phase commit tracking (J5)
|
|
29
|
+
authorized_at: timestamp("authorized_at", { withTimezone: true }),
|
|
30
|
+
captured_at: timestamp("captured_at", { withTimezone: true }),
|
|
31
|
+
voided_at: timestamp("voided_at", { withTimezone: true }),
|
|
32
|
+
capture_deadline: timestamp("capture_deadline", { withTimezone: true }),
|
|
33
|
+
// Refund tracking
|
|
34
|
+
refunded_amount_minor: numeric("refunded_amount_minor").default("0"),
|
|
35
|
+
last_refund_at: timestamp("last_refund_at", { withTimezone: true }),
|
|
36
|
+
// Tax invoice (Israeli requirement)
|
|
37
|
+
tax_invoice_status: text("tax_invoice_status").$type().default("pending"),
|
|
38
|
+
tax_invoice_number: text("tax_invoice_number"),
|
|
39
|
+
tax_invoice_url: text("tax_invoice_url"),
|
|
40
|
+
// Error tracking
|
|
41
|
+
failure_code: text("failure_code"),
|
|
42
|
+
failure_message: text("failure_message"),
|
|
43
|
+
failure_details: jsonb("failure_details"),
|
|
44
|
+
// Application metadata
|
|
45
|
+
description: text("description"),
|
|
46
|
+
metadata: jsonb("metadata").$type(),
|
|
47
|
+
// Timestamps
|
|
48
|
+
created_at: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
|
|
49
|
+
updated_at: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow()
|
|
50
|
+
},
|
|
51
|
+
(table) => ({
|
|
52
|
+
// Performance indexes
|
|
53
|
+
userIdx: index("payment_transactions_user_idx").on(table.user_id),
|
|
54
|
+
statusIdx: index("payment_transactions_status_idx").on(table.status),
|
|
55
|
+
providerIdx: index("payment_transactions_provider_idx").on(table.provider),
|
|
56
|
+
providerTxIdx: index("payment_transactions_provider_tx_idx").on(table.provider_transaction_id),
|
|
57
|
+
createdAtIdx: index("payment_transactions_created_at_idx").on(table.created_at),
|
|
58
|
+
// Unique constraints for idempotency
|
|
59
|
+
internalIdUnique: unique("payment_transactions_internal_id_unique").on(
|
|
60
|
+
table.internal_payment_id
|
|
61
|
+
),
|
|
62
|
+
idempotencyUnique: unique("payment_transactions_idempotency_unique").on(table.idempotency_key)
|
|
63
|
+
})
|
|
64
|
+
);
|
|
65
|
+
|
|
66
|
+
// src/schema/payment-methods.ts
|
|
67
|
+
import { pgTable as pgTable2, uuid as uuid2, text as text2, boolean, timestamp as timestamp2, jsonb as jsonb2, index as index2 } from "drizzle-orm/pg-core";
|
|
68
|
+
var paymentMethods = pgTable2(
|
|
69
|
+
"payment_methods",
|
|
70
|
+
{
|
|
71
|
+
id: uuid2("id").defaultRandom().primaryKey(),
|
|
72
|
+
// User association (FK configured at application level)
|
|
73
|
+
user_id: uuid2("user_id").notNull(),
|
|
74
|
+
// Method type
|
|
75
|
+
type: text2("type").$type().notNull(),
|
|
76
|
+
// Provider information
|
|
77
|
+
provider: text2("provider").notNull(),
|
|
78
|
+
// stripe, hyp, cardcom
|
|
79
|
+
provider_payment_method_id: text2("provider_payment_method_id").notNull(),
|
|
80
|
+
// Card details (tokenized, never full numbers)
|
|
81
|
+
card_brand: text2("card_brand").$type(),
|
|
82
|
+
card_last4: text2("card_last4"),
|
|
83
|
+
card_exp_month: text2("card_exp_month"),
|
|
84
|
+
card_exp_year: text2("card_exp_year"),
|
|
85
|
+
card_bin: text2("card_bin"),
|
|
86
|
+
// First 6-8 digits for routing
|
|
87
|
+
// State
|
|
88
|
+
is_default: boolean("is_default").default(false),
|
|
89
|
+
is_active: boolean("is_active").default(true),
|
|
90
|
+
// Provider-specific data
|
|
91
|
+
provider_metadata: jsonb2("provider_metadata").$type(),
|
|
92
|
+
// Timestamps
|
|
93
|
+
created_at: timestamp2("created_at", { withTimezone: true }).notNull().defaultNow(),
|
|
94
|
+
updated_at: timestamp2("updated_at", { withTimezone: true }).notNull().defaultNow(),
|
|
95
|
+
last_used_at: timestamp2("last_used_at", { withTimezone: true })
|
|
96
|
+
},
|
|
97
|
+
(table) => ({
|
|
98
|
+
// Performance indexes
|
|
99
|
+
userIdx: index2("payment_methods_user_idx").on(table.user_id),
|
|
100
|
+
userDefaultIdx: index2("payment_methods_user_default_idx").on(table.user_id, table.is_default),
|
|
101
|
+
providerIdx: index2("payment_methods_provider_idx").on(table.provider),
|
|
102
|
+
providerMethodIdx: index2("payment_methods_provider_method_idx").on(
|
|
103
|
+
table.provider_payment_method_id
|
|
104
|
+
),
|
|
105
|
+
cardBinIdx: index2("payment_methods_card_bin_idx").on(table.card_bin)
|
|
106
|
+
})
|
|
107
|
+
);
|
|
108
|
+
|
|
109
|
+
// src/schema/webhook-events.ts
|
|
110
|
+
import {
|
|
111
|
+
pgTable as pgTable3,
|
|
112
|
+
uuid as uuid3,
|
|
113
|
+
text as text3,
|
|
114
|
+
timestamp as timestamp3,
|
|
115
|
+
jsonb as jsonb3,
|
|
116
|
+
index as index3,
|
|
117
|
+
unique as unique2
|
|
118
|
+
} from "drizzle-orm/pg-core";
|
|
119
|
+
var paymentWebhookEvents = pgTable3(
|
|
120
|
+
"payment_webhook_events",
|
|
121
|
+
{
|
|
122
|
+
id: uuid3("id").defaultRandom().primaryKey(),
|
|
123
|
+
// Event identification
|
|
124
|
+
provider: text3("provider").notNull(),
|
|
125
|
+
// stripe, hyp, cardcom
|
|
126
|
+
provider_event_id: text3("provider_event_id").notNull(),
|
|
127
|
+
event_type: text3("event_type").notNull(),
|
|
128
|
+
// Processing state
|
|
129
|
+
status: text3("status").$type().notNull().default("pending"),
|
|
130
|
+
attempts: text3("attempts").default("0"),
|
|
131
|
+
last_attempt_at: timestamp3("last_attempt_at", { withTimezone: true }),
|
|
132
|
+
// Linked transaction (if applicable)
|
|
133
|
+
transaction_id: uuid3("transaction_id"),
|
|
134
|
+
// Event payload (store for debugging and retry)
|
|
135
|
+
payload: jsonb3("payload").$type().notNull(),
|
|
136
|
+
signature: text3("signature"),
|
|
137
|
+
// Error tracking
|
|
138
|
+
error_message: text3("error_message"),
|
|
139
|
+
error_details: jsonb3("error_details"),
|
|
140
|
+
// Timestamps
|
|
141
|
+
received_at: timestamp3("received_at", { withTimezone: true }).notNull().defaultNow(),
|
|
142
|
+
processed_at: timestamp3("processed_at", { withTimezone: true }),
|
|
143
|
+
created_at: timestamp3("created_at", { withTimezone: true }).notNull().defaultNow()
|
|
144
|
+
},
|
|
145
|
+
(table) => ({
|
|
146
|
+
// Unique constraint for idempotency
|
|
147
|
+
providerEventUnique: unique2("webhook_events_provider_event_unique").on(
|
|
148
|
+
table.provider,
|
|
149
|
+
table.provider_event_id
|
|
150
|
+
),
|
|
151
|
+
// Performance indexes
|
|
152
|
+
statusIdx: index3("webhook_events_status_idx").on(table.status),
|
|
153
|
+
transactionIdx: index3("webhook_events_transaction_idx").on(
|
|
154
|
+
table.transaction_id
|
|
155
|
+
),
|
|
156
|
+
receivedAtIdx: index3("webhook_events_received_at_idx").on(table.received_at),
|
|
157
|
+
providerIdx: index3("webhook_events_provider_idx").on(table.provider),
|
|
158
|
+
eventTypeIdx: index3("webhook_events_event_type_idx").on(table.event_type)
|
|
159
|
+
})
|
|
160
|
+
);
|
|
161
|
+
|
|
162
|
+
// src/schema/payment-audit-log.ts
|
|
163
|
+
import {
|
|
164
|
+
pgTable as pgTable4,
|
|
165
|
+
uuid as uuid4,
|
|
166
|
+
text as text4,
|
|
167
|
+
timestamp as timestamp4,
|
|
168
|
+
jsonb as jsonb4,
|
|
169
|
+
index as index4
|
|
170
|
+
} from "drizzle-orm/pg-core";
|
|
171
|
+
var paymentAuditLog = pgTable4(
|
|
172
|
+
"payment_audit_log",
|
|
173
|
+
{
|
|
174
|
+
id: uuid4("id").defaultRandom().primaryKey(),
|
|
175
|
+
// What transaction was affected
|
|
176
|
+
transaction_id: uuid4("transaction_id").notNull(),
|
|
177
|
+
// What action occurred
|
|
178
|
+
action: text4("action").$type().notNull(),
|
|
179
|
+
// State before and after
|
|
180
|
+
previous_state: jsonb4("previous_state"),
|
|
181
|
+
new_state: jsonb4("new_state").notNull(),
|
|
182
|
+
// Who/what triggered this change
|
|
183
|
+
triggered_by: text4("triggered_by").$type().notNull(),
|
|
184
|
+
triggered_by_id: uuid4("triggered_by_id"),
|
|
185
|
+
// User ID if applicable
|
|
186
|
+
// Request context
|
|
187
|
+
ip_address: text4("ip_address"),
|
|
188
|
+
user_agent: text4("user_agent"),
|
|
189
|
+
// Correlation for distributed tracing
|
|
190
|
+
correlation_id: text4("correlation_id"),
|
|
191
|
+
// Additional context
|
|
192
|
+
metadata: jsonb4("metadata").$type(),
|
|
193
|
+
// Immutable timestamp (never updated)
|
|
194
|
+
created_at: timestamp4("created_at", { withTimezone: true }).notNull().defaultNow()
|
|
195
|
+
},
|
|
196
|
+
(table) => ({
|
|
197
|
+
// Performance indexes
|
|
198
|
+
transactionIdx: index4("payment_audit_log_transaction_idx").on(
|
|
199
|
+
table.transaction_id
|
|
200
|
+
),
|
|
201
|
+
actionIdx: index4("payment_audit_log_action_idx").on(table.action),
|
|
202
|
+
correlationIdx: index4("payment_audit_log_correlation_idx").on(
|
|
203
|
+
table.correlation_id
|
|
204
|
+
),
|
|
205
|
+
createdAtIdx: index4("payment_audit_log_created_at_idx").on(table.created_at),
|
|
206
|
+
triggeredByIdx: index4("payment_audit_log_triggered_by_idx").on(
|
|
207
|
+
table.triggered_by
|
|
208
|
+
)
|
|
209
|
+
})
|
|
210
|
+
);
|
|
211
|
+
|
|
212
|
+
// src/schema/provider-health.ts
|
|
213
|
+
import {
|
|
214
|
+
pgTable as pgTable5,
|
|
215
|
+
uuid as uuid5,
|
|
216
|
+
text as text5,
|
|
217
|
+
numeric as numeric2,
|
|
218
|
+
timestamp as timestamp5,
|
|
219
|
+
jsonb as jsonb5,
|
|
220
|
+
index as index5,
|
|
221
|
+
unique as unique3
|
|
222
|
+
} from "drizzle-orm/pg-core";
|
|
223
|
+
var providerHealth = pgTable5(
|
|
224
|
+
"payment_provider_health",
|
|
225
|
+
{
|
|
226
|
+
id: uuid5("id").defaultRandom().primaryKey(),
|
|
227
|
+
// Provider identification
|
|
228
|
+
provider: text5("provider").notNull(),
|
|
229
|
+
// stripe, hyp, cardcom
|
|
230
|
+
// Circuit breaker state
|
|
231
|
+
circuit_state: text5("circuit_state").$type().notNull().default("closed"),
|
|
232
|
+
// Failure tracking
|
|
233
|
+
failure_count: text5("failure_count").default("0"),
|
|
234
|
+
success_count: text5("success_count").default("0"),
|
|
235
|
+
last_failure_at: timestamp5("last_failure_at", { withTimezone: true }),
|
|
236
|
+
last_success_at: timestamp5("last_success_at", { withTimezone: true }),
|
|
237
|
+
// Circuit breaker timing
|
|
238
|
+
circuit_opened_at: timestamp5("circuit_opened_at", { withTimezone: true }),
|
|
239
|
+
next_retry_at: timestamp5("next_retry_at", { withTimezone: true }),
|
|
240
|
+
// Performance metrics
|
|
241
|
+
avg_latency_ms: numeric2("avg_latency_ms"),
|
|
242
|
+
error_rate: numeric2("error_rate"),
|
|
243
|
+
// 0-1
|
|
244
|
+
request_count_window: text5("request_count_window").default("0"),
|
|
245
|
+
// Health check results
|
|
246
|
+
last_health_check_at: timestamp5("last_health_check_at", { withTimezone: true }),
|
|
247
|
+
health_check_result: jsonb5("health_check_result").$type(),
|
|
248
|
+
// Timestamps
|
|
249
|
+
created_at: timestamp5("created_at", { withTimezone: true }).notNull().defaultNow(),
|
|
250
|
+
updated_at: timestamp5("updated_at", { withTimezone: true }).notNull().defaultNow()
|
|
251
|
+
},
|
|
252
|
+
(table) => ({
|
|
253
|
+
// One record per provider
|
|
254
|
+
providerUnique: unique3("provider_health_provider_unique").on(table.provider),
|
|
255
|
+
// Performance indexes
|
|
256
|
+
circuitStateIdx: index5("provider_health_circuit_state_idx").on(
|
|
257
|
+
table.circuit_state
|
|
258
|
+
),
|
|
259
|
+
nextRetryIdx: index5("provider_health_next_retry_idx").on(table.next_retry_at)
|
|
260
|
+
})
|
|
261
|
+
);
|
|
262
|
+
export {
|
|
263
|
+
paymentAuditLog,
|
|
264
|
+
paymentMethods,
|
|
265
|
+
paymentTransactions,
|
|
266
|
+
paymentWebhookEvents,
|
|
267
|
+
providerHealth
|
|
268
|
+
};
|
|
269
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/schema/payment-transactions.ts","../../src/schema/payment-methods.ts","../../src/schema/webhook-events.ts","../../src/schema/payment-audit-log.ts","../../src/schema/provider-health.ts"],"sourcesContent":["/**\r\n * PaymentOS - Payment Transactions Schema\r\n *\r\n * Core table for tracking all payment operations.\r\n * Implements Two-Phase Commit (J5) pattern with authorize/capture flow.\r\n *\r\n * Note: User FK is optional and configured via schema-config.ts\r\n */\r\n\r\nimport { pgTable, uuid, text, numeric, timestamp, jsonb, index, unique } from 'drizzle-orm/pg-core'\r\n\r\n// ============================================================================\r\n// Type Definitions\r\n// ============================================================================\r\n\r\n/**\r\n * Payment transaction states (strict state machine)\r\n * @see src/lib/payments/types/state-machine.ts for transition rules\r\n */\r\nexport type PaymentTransactionStatus =\r\n | 'created'\r\n | 'pending_authorization'\r\n | 'authorized'\r\n | 'capturing'\r\n | 'captured'\r\n | 'voided'\r\n | 'failed'\r\n | 'expired'\r\n | 'partially_refunded'\r\n | 'fully_refunded'\r\n\r\n/**\r\n * Payment transaction types\r\n */\r\nexport type PaymentTransactionType =\r\n | 'one_time_purchase'\r\n | 'subscription_initial'\r\n | 'subscription_renewal'\r\n | 'refund'\r\n\r\n/**\r\n * Tax invoice status (Israeli compliance)\r\n */\r\nexport type PaymentTaxInvoiceStatus = 'pending' | 'generated' | 'sent' | 'failed'\r\n\r\n// ============================================================================\r\n// Schema Definition\r\n// ============================================================================\r\n\r\n/**\r\n * Payment transactions table\r\n *\r\n * FK to user table is NOT defined here - it's application-specific.\r\n * The user_id column stores the UUID, but the FK constraint should be\r\n * added via migration if needed for your specific user table.\r\n *\r\n * To add FK constraint, create a migration:\r\n * ```sql\r\n * ALTER TABLE payment_transactions\r\n * ADD CONSTRAINT payment_transactions_user_id_fkey\r\n * FOREIGN KEY (user_id) REFERENCES your_users_table(id) ON DELETE CASCADE;\r\n * ```\r\n */\r\nexport const paymentTransactions = pgTable(\r\n 'payment_transactions',\r\n {\r\n id: uuid('id').defaultRandom().primaryKey(),\r\n\r\n // Idempotency - prevents duplicate charges\r\n internal_payment_id: text('internal_payment_id').notNull(),\r\n idempotency_key: text('idempotency_key'),\r\n\r\n // User association (FK configured at application level)\r\n user_id: uuid('user_id').notNull(),\r\n\r\n // Transaction classification\r\n transaction_type: text('transaction_type').$type<PaymentTransactionType>().notNull(),\r\n status: text('status').$type<PaymentTransactionStatus>().notNull().default('created'),\r\n\r\n // Amounts in smallest currency unit (cents/agorot)\r\n amount_minor: numeric('amount_minor').notNull(),\r\n currency: text('currency').notNull().default('USD'),\r\n\r\n // Original amount if currency converted\r\n original_amount_minor: numeric('original_amount_minor'),\r\n original_currency: text('original_currency'),\r\n currency_conversion_rate: numeric('currency_conversion_rate'),\r\n\r\n // Provider information\r\n provider: text('provider').notNull(), // stripe, hyp, cardcom\r\n provider_transaction_id: text('provider_transaction_id'),\r\n provider_authorization_code: text('provider_authorization_code'),\r\n provider_metadata: jsonb('provider_metadata').$type<Record<string, unknown>>(),\r\n\r\n // Two-phase commit tracking (J5)\r\n authorized_at: timestamp('authorized_at', { withTimezone: true }),\r\n captured_at: timestamp('captured_at', { withTimezone: true }),\r\n voided_at: timestamp('voided_at', { withTimezone: true }),\r\n capture_deadline: timestamp('capture_deadline', { withTimezone: true }),\r\n\r\n // Refund tracking\r\n refunded_amount_minor: numeric('refunded_amount_minor').default('0'),\r\n last_refund_at: timestamp('last_refund_at', { withTimezone: true }),\r\n\r\n // Tax invoice (Israeli requirement)\r\n tax_invoice_status: text('tax_invoice_status')\r\n .$type<PaymentTaxInvoiceStatus>()\r\n .default('pending'),\r\n tax_invoice_number: text('tax_invoice_number'),\r\n tax_invoice_url: text('tax_invoice_url'),\r\n\r\n // Error tracking\r\n failure_code: text('failure_code'),\r\n failure_message: text('failure_message'),\r\n failure_details: jsonb('failure_details'),\r\n\r\n // Application metadata\r\n description: text('description'),\r\n metadata: jsonb('metadata').$type<{\r\n credit_package_id?: string\r\n subscription_plan_id?: string\r\n credits_amount?: number\r\n [key: string]: unknown\r\n }>(),\r\n\r\n // Timestamps\r\n created_at: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),\r\n updated_at: timestamp('updated_at', { withTimezone: true }).notNull().defaultNow(),\r\n },\r\n (table) => ({\r\n // Performance indexes\r\n userIdx: index('payment_transactions_user_idx').on(table.user_id),\r\n statusIdx: index('payment_transactions_status_idx').on(table.status),\r\n providerIdx: index('payment_transactions_provider_idx').on(table.provider),\r\n providerTxIdx: index('payment_transactions_provider_tx_idx').on(table.provider_transaction_id),\r\n createdAtIdx: index('payment_transactions_created_at_idx').on(table.created_at),\r\n // Unique constraints for idempotency\r\n internalIdUnique: unique('payment_transactions_internal_id_unique').on(\r\n table.internal_payment_id\r\n ),\r\n idempotencyUnique: unique('payment_transactions_idempotency_unique').on(table.idempotency_key),\r\n })\r\n)\r\n","/**\r\n * PaymentOS - Payment Methods Schema\r\n *\r\n * Stores tokenized payment methods (PCI-compliant - no full card numbers).\r\n * Used for saved cards and recurring billing.\r\n *\r\n * Note: User FK is optional and configured via schema-config.ts\r\n */\r\n\r\nimport { pgTable, uuid, text, boolean, timestamp, jsonb, index } from 'drizzle-orm/pg-core'\r\n\r\n// ============================================================================\r\n// Type Definitions\r\n// ============================================================================\r\n\r\n/**\r\n * Payment method types\r\n */\r\nexport type PaymentMethodType = 'card' | 'bank_account' | 'paypal'\r\n\r\n/**\r\n * Card brands\r\n */\r\nexport type CardBrandType =\r\n | 'visa'\r\n | 'mastercard'\r\n | 'amex'\r\n | 'discover'\r\n | 'isracard'\r\n | 'diners'\r\n | 'unknown'\r\n\r\n// ============================================================================\r\n// Schema Definition\r\n// ============================================================================\r\n\r\n/**\r\n * Payment methods table\r\n *\r\n * FK to user table is NOT defined here - it's application-specific.\r\n * The user_id column stores the UUID, but the FK constraint should be\r\n * added via migration if needed for your specific user table.\r\n *\r\n * To add FK constraint, create a migration:\r\n * ```sql\r\n * ALTER TABLE payment_methods\r\n * ADD CONSTRAINT payment_methods_user_id_fkey\r\n * FOREIGN KEY (user_id) REFERENCES your_users_table(id) ON DELETE CASCADE;\r\n * ```\r\n */\r\nexport const paymentMethods = pgTable(\r\n 'payment_methods',\r\n {\r\n id: uuid('id').defaultRandom().primaryKey(),\r\n\r\n // User association (FK configured at application level)\r\n user_id: uuid('user_id').notNull(),\r\n\r\n // Method type\r\n type: text('type').$type<PaymentMethodType>().notNull(),\r\n\r\n // Provider information\r\n provider: text('provider').notNull(), // stripe, hyp, cardcom\r\n provider_payment_method_id: text('provider_payment_method_id').notNull(),\r\n\r\n // Card details (tokenized, never full numbers)\r\n card_brand: text('card_brand').$type<CardBrandType>(),\r\n card_last4: text('card_last4'),\r\n card_exp_month: text('card_exp_month'),\r\n card_exp_year: text('card_exp_year'),\r\n card_bin: text('card_bin'), // First 6-8 digits for routing\r\n\r\n // State\r\n is_default: boolean('is_default').default(false),\r\n is_active: boolean('is_active').default(true),\r\n\r\n // Provider-specific data\r\n provider_metadata: jsonb('provider_metadata').$type<Record<string, unknown>>(),\r\n\r\n // Timestamps\r\n created_at: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),\r\n updated_at: timestamp('updated_at', { withTimezone: true }).notNull().defaultNow(),\r\n last_used_at: timestamp('last_used_at', { withTimezone: true }),\r\n },\r\n (table) => ({\r\n // Performance indexes\r\n userIdx: index('payment_methods_user_idx').on(table.user_id),\r\n userDefaultIdx: index('payment_methods_user_default_idx').on(table.user_id, table.is_default),\r\n providerIdx: index('payment_methods_provider_idx').on(table.provider),\r\n providerMethodIdx: index('payment_methods_provider_method_idx').on(\r\n table.provider_payment_method_id\r\n ),\r\n cardBinIdx: index('payment_methods_card_bin_idx').on(table.card_bin),\r\n })\r\n)\r\n","import {\r\n pgTable,\r\n uuid,\r\n text,\r\n timestamp,\r\n jsonb,\r\n index,\r\n unique,\r\n} from 'drizzle-orm/pg-core'\r\n\r\n/**\r\n * Webhook processing status\r\n */\r\nexport type WebhookEventStatus =\r\n | 'pending'\r\n | 'processing'\r\n | 'processed'\r\n | 'failed'\r\n | 'ignored'\r\n\r\n/**\r\n * Payment webhook events table\r\n * Stores all incoming webhooks for idempotent processing.\r\n * Ensures each provider event is processed exactly once.\r\n */\r\nexport const paymentWebhookEvents = pgTable(\r\n 'payment_webhook_events',\r\n {\r\n id: uuid('id').defaultRandom().primaryKey(),\r\n\r\n // Event identification\r\n provider: text('provider').notNull(), // stripe, hyp, cardcom\r\n provider_event_id: text('provider_event_id').notNull(),\r\n event_type: text('event_type').notNull(),\r\n\r\n // Processing state\r\n status: text('status')\r\n .$type<WebhookEventStatus>()\r\n .notNull()\r\n .default('pending'),\r\n attempts: text('attempts').default('0'),\r\n last_attempt_at: timestamp('last_attempt_at', { withTimezone: true }),\r\n\r\n // Linked transaction (if applicable)\r\n transaction_id: uuid('transaction_id'),\r\n\r\n // Event payload (store for debugging and retry)\r\n payload: jsonb('payload').$type<Record<string, unknown>>().notNull(),\r\n signature: text('signature'),\r\n\r\n // Error tracking\r\n error_message: text('error_message'),\r\n error_details: jsonb('error_details'),\r\n\r\n // Timestamps\r\n received_at: timestamp('received_at', { withTimezone: true })\r\n .notNull()\r\n .defaultNow(),\r\n processed_at: timestamp('processed_at', { withTimezone: true }),\r\n created_at: timestamp('created_at', { withTimezone: true })\r\n .notNull()\r\n .defaultNow(),\r\n },\r\n (table) => ({\r\n // Unique constraint for idempotency\r\n providerEventUnique: unique('webhook_events_provider_event_unique').on(\r\n table.provider,\r\n table.provider_event_id\r\n ),\r\n // Performance indexes\r\n statusIdx: index('webhook_events_status_idx').on(table.status),\r\n transactionIdx: index('webhook_events_transaction_idx').on(\r\n table.transaction_id\r\n ),\r\n receivedAtIdx: index('webhook_events_received_at_idx').on(table.received_at),\r\n providerIdx: index('webhook_events_provider_idx').on(table.provider),\r\n eventTypeIdx: index('webhook_events_event_type_idx').on(table.event_type),\r\n })\r\n)\r\n","/**\n * @nehorai/payments-drizzle - Payment Audit Log Schema\n *\n * Immutable audit trail for all payment state changes.\n * Used for debugging, compliance, and dispute resolution.\n */\n\nimport {\n pgTable,\n uuid,\n text,\n timestamp,\n jsonb,\n index,\n} from 'drizzle-orm/pg-core'\n\n// ============================================================================\n// Type Definitions\n// ============================================================================\n\n/**\n * Audit log action types\n */\nexport type AuditLogAction =\n | 'created'\n | 'status_changed'\n | 'authorized'\n | 'captured'\n | 'voided'\n | 'refund_initiated'\n | 'refund_completed'\n | 'webhook_received'\n | 'webhook_processed'\n | 'error_occurred'\n | 'retry_attempted'\n | 'manual_intervention'\n\n/**\n * Who/what triggered the action\n */\nexport type AuditLogTrigger =\n | 'user'\n | 'webhook'\n | 'system'\n | 'admin'\n | 'cron'\n | 'api'\n\n// ============================================================================\n// Schema Definition\n// ============================================================================\n\n/**\n * Payment audit log table\n * Immutable audit trail for all payment state changes.\n * Used for debugging, compliance, and dispute resolution.\n */\nexport const paymentAuditLog = pgTable(\n 'payment_audit_log',\n {\n id: uuid('id').defaultRandom().primaryKey(),\n\n // What transaction was affected\n transaction_id: uuid('transaction_id').notNull(),\n\n // What action occurred\n action: text('action').$type<AuditLogAction>().notNull(),\n\n // State before and after\n previous_state: jsonb('previous_state'),\n new_state: jsonb('new_state').notNull(),\n\n // Who/what triggered this change\n triggered_by: text('triggered_by').$type<AuditLogTrigger>().notNull(),\n triggered_by_id: uuid('triggered_by_id'), // User ID if applicable\n\n // Request context\n ip_address: text('ip_address'),\n user_agent: text('user_agent'),\n\n // Correlation for distributed tracing\n correlation_id: text('correlation_id'),\n\n // Additional context\n metadata: jsonb('metadata').$type<Record<string, unknown>>(),\n\n // Immutable timestamp (never updated)\n created_at: timestamp('created_at', { withTimezone: true })\n .notNull()\n .defaultNow(),\n },\n (table) => ({\n // Performance indexes\n transactionIdx: index('payment_audit_log_transaction_idx').on(\n table.transaction_id\n ),\n actionIdx: index('payment_audit_log_action_idx').on(table.action),\n correlationIdx: index('payment_audit_log_correlation_idx').on(\n table.correlation_id\n ),\n createdAtIdx: index('payment_audit_log_created_at_idx').on(table.created_at),\n triggeredByIdx: index('payment_audit_log_triggered_by_idx').on(\n table.triggered_by\n ),\n })\n)\n","/**\n * @nehorai/payments-drizzle - Provider Health Schema\n *\n * Tracks payment provider health for circuit breaker pattern.\n * Used for intelligent failover when providers experience issues.\n */\n\nimport {\n pgTable,\n uuid,\n text,\n numeric,\n timestamp,\n jsonb,\n index,\n unique,\n} from 'drizzle-orm/pg-core'\n\n// ============================================================================\n// Type Definitions\n// ============================================================================\n\n/**\n * Circuit breaker states\n */\nexport type CircuitBreakerState = 'closed' | 'open' | 'half_open'\n\n// ============================================================================\n// Schema Definition\n// ============================================================================\n\n/**\n * Provider health table\n * Tracks payment provider health for circuit breaker pattern.\n * Used for intelligent failover when providers experience issues.\n */\nexport const providerHealth = pgTable(\n 'payment_provider_health',\n {\n id: uuid('id').defaultRandom().primaryKey(),\n\n // Provider identification\n provider: text('provider').notNull(), // stripe, hyp, cardcom\n\n // Circuit breaker state\n circuit_state: text('circuit_state')\n .$type<CircuitBreakerState>()\n .notNull()\n .default('closed'),\n\n // Failure tracking\n failure_count: text('failure_count').default('0'),\n success_count: text('success_count').default('0'),\n last_failure_at: timestamp('last_failure_at', { withTimezone: true }),\n last_success_at: timestamp('last_success_at', { withTimezone: true }),\n\n // Circuit breaker timing\n circuit_opened_at: timestamp('circuit_opened_at', { withTimezone: true }),\n next_retry_at: timestamp('next_retry_at', { withTimezone: true }),\n\n // Performance metrics\n avg_latency_ms: numeric('avg_latency_ms'),\n error_rate: numeric('error_rate'), // 0-1\n request_count_window: text('request_count_window').default('0'),\n\n // Health check results\n last_health_check_at: timestamp('last_health_check_at', { withTimezone: true }),\n health_check_result: jsonb('health_check_result').$type<{\n healthy: boolean\n latency_ms?: number\n error?: string\n }>(),\n\n // Timestamps\n created_at: timestamp('created_at', { withTimezone: true })\n .notNull()\n .defaultNow(),\n updated_at: timestamp('updated_at', { withTimezone: true })\n .notNull()\n .defaultNow(),\n },\n (table) => ({\n // One record per provider\n providerUnique: unique('provider_health_provider_unique').on(table.provider),\n // Performance indexes\n circuitStateIdx: index('provider_health_circuit_state_idx').on(\n table.circuit_state\n ),\n nextRetryIdx: index('provider_health_next_retry_idx').on(table.next_retry_at),\n })\n)\n"],"mappings":";AASA,SAAS,SAAS,MAAM,MAAM,SAAS,WAAW,OAAO,OAAO,cAAc;AAsDvE,IAAM,sBAAsB;AAAA,EACjC;AAAA,EACA;AAAA,IACE,IAAI,KAAK,IAAI,EAAE,cAAc,EAAE,WAAW;AAAA;AAAA,IAG1C,qBAAqB,KAAK,qBAAqB,EAAE,QAAQ;AAAA,IACzD,iBAAiB,KAAK,iBAAiB;AAAA;AAAA,IAGvC,SAAS,KAAK,SAAS,EAAE,QAAQ;AAAA;AAAA,IAGjC,kBAAkB,KAAK,kBAAkB,EAAE,MAA8B,EAAE,QAAQ;AAAA,IACnF,QAAQ,KAAK,QAAQ,EAAE,MAAgC,EAAE,QAAQ,EAAE,QAAQ,SAAS;AAAA;AAAA,IAGpF,cAAc,QAAQ,cAAc,EAAE,QAAQ;AAAA,IAC9C,UAAU,KAAK,UAAU,EAAE,QAAQ,EAAE,QAAQ,KAAK;AAAA;AAAA,IAGlD,uBAAuB,QAAQ,uBAAuB;AAAA,IACtD,mBAAmB,KAAK,mBAAmB;AAAA,IAC3C,0BAA0B,QAAQ,0BAA0B;AAAA;AAAA,IAG5D,UAAU,KAAK,UAAU,EAAE,QAAQ;AAAA;AAAA,IACnC,yBAAyB,KAAK,yBAAyB;AAAA,IACvD,6BAA6B,KAAK,6BAA6B;AAAA,IAC/D,mBAAmB,MAAM,mBAAmB,EAAE,MAA+B;AAAA;AAAA,IAG7E,eAAe,UAAU,iBAAiB,EAAE,cAAc,KAAK,CAAC;AAAA,IAChE,aAAa,UAAU,eAAe,EAAE,cAAc,KAAK,CAAC;AAAA,IAC5D,WAAW,UAAU,aAAa,EAAE,cAAc,KAAK,CAAC;AAAA,IACxD,kBAAkB,UAAU,oBAAoB,EAAE,cAAc,KAAK,CAAC;AAAA;AAAA,IAGtE,uBAAuB,QAAQ,uBAAuB,EAAE,QAAQ,GAAG;AAAA,IACnE,gBAAgB,UAAU,kBAAkB,EAAE,cAAc,KAAK,CAAC;AAAA;AAAA,IAGlE,oBAAoB,KAAK,oBAAoB,EAC1C,MAA+B,EAC/B,QAAQ,SAAS;AAAA,IACpB,oBAAoB,KAAK,oBAAoB;AAAA,IAC7C,iBAAiB,KAAK,iBAAiB;AAAA;AAAA,IAGvC,cAAc,KAAK,cAAc;AAAA,IACjC,iBAAiB,KAAK,iBAAiB;AAAA,IACvC,iBAAiB,MAAM,iBAAiB;AAAA;AAAA,IAGxC,aAAa,KAAK,aAAa;AAAA,IAC/B,UAAU,MAAM,UAAU,EAAE,MAKzB;AAAA;AAAA,IAGH,YAAY,UAAU,cAAc,EAAE,cAAc,KAAK,CAAC,EAAE,QAAQ,EAAE,WAAW;AAAA,IACjF,YAAY,UAAU,cAAc,EAAE,cAAc,KAAK,CAAC,EAAE,QAAQ,EAAE,WAAW;AAAA,EACnF;AAAA,EACA,CAAC,WAAW;AAAA;AAAA,IAEV,SAAS,MAAM,+BAA+B,EAAE,GAAG,MAAM,OAAO;AAAA,IAChE,WAAW,MAAM,iCAAiC,EAAE,GAAG,MAAM,MAAM;AAAA,IACnE,aAAa,MAAM,mCAAmC,EAAE,GAAG,MAAM,QAAQ;AAAA,IACzE,eAAe,MAAM,sCAAsC,EAAE,GAAG,MAAM,uBAAuB;AAAA,IAC7F,cAAc,MAAM,qCAAqC,EAAE,GAAG,MAAM,UAAU;AAAA;AAAA,IAE9E,kBAAkB,OAAO,yCAAyC,EAAE;AAAA,MAClE,MAAM;AAAA,IACR;AAAA,IACA,mBAAmB,OAAO,yCAAyC,EAAE,GAAG,MAAM,eAAe;AAAA,EAC/F;AACF;;;ACrIA,SAAS,WAAAA,UAAS,QAAAC,OAAM,QAAAC,OAAM,SAAS,aAAAC,YAAW,SAAAC,QAAO,SAAAC,cAAa;AAyC/D,IAAM,iBAAiBL;AAAA,EAC5B;AAAA,EACA;AAAA,IACE,IAAIC,MAAK,IAAI,EAAE,cAAc,EAAE,WAAW;AAAA;AAAA,IAG1C,SAASA,MAAK,SAAS,EAAE,QAAQ;AAAA;AAAA,IAGjC,MAAMC,MAAK,MAAM,EAAE,MAAyB,EAAE,QAAQ;AAAA;AAAA,IAGtD,UAAUA,MAAK,UAAU,EAAE,QAAQ;AAAA;AAAA,IACnC,4BAA4BA,MAAK,4BAA4B,EAAE,QAAQ;AAAA;AAAA,IAGvE,YAAYA,MAAK,YAAY,EAAE,MAAqB;AAAA,IACpD,YAAYA,MAAK,YAAY;AAAA,IAC7B,gBAAgBA,MAAK,gBAAgB;AAAA,IACrC,eAAeA,MAAK,eAAe;AAAA,IACnC,UAAUA,MAAK,UAAU;AAAA;AAAA;AAAA,IAGzB,YAAY,QAAQ,YAAY,EAAE,QAAQ,KAAK;AAAA,IAC/C,WAAW,QAAQ,WAAW,EAAE,QAAQ,IAAI;AAAA;AAAA,IAG5C,mBAAmBE,OAAM,mBAAmB,EAAE,MAA+B;AAAA;AAAA,IAG7E,YAAYD,WAAU,cAAc,EAAE,cAAc,KAAK,CAAC,EAAE,QAAQ,EAAE,WAAW;AAAA,IACjF,YAAYA,WAAU,cAAc,EAAE,cAAc,KAAK,CAAC,EAAE,QAAQ,EAAE,WAAW;AAAA,IACjF,cAAcA,WAAU,gBAAgB,EAAE,cAAc,KAAK,CAAC;AAAA,EAChE;AAAA,EACA,CAAC,WAAW;AAAA;AAAA,IAEV,SAASE,OAAM,0BAA0B,EAAE,GAAG,MAAM,OAAO;AAAA,IAC3D,gBAAgBA,OAAM,kCAAkC,EAAE,GAAG,MAAM,SAAS,MAAM,UAAU;AAAA,IAC5F,aAAaA,OAAM,8BAA8B,EAAE,GAAG,MAAM,QAAQ;AAAA,IACpE,mBAAmBA,OAAM,qCAAqC,EAAE;AAAA,MAC9D,MAAM;AAAA,IACR;AAAA,IACA,YAAYA,OAAM,8BAA8B,EAAE,GAAG,MAAM,QAAQ;AAAA,EACrE;AACF;;;AC9FA;AAAA,EACE,WAAAC;AAAA,EACA,QAAAC;AAAA,EACA,QAAAC;AAAA,EACA,aAAAC;AAAA,EACA,SAAAC;AAAA,EACA,SAAAC;AAAA,EACA,UAAAC;AAAA,OACK;AAiBA,IAAM,uBAAuBN;AAAA,EAClC;AAAA,EACA;AAAA,IACE,IAAIC,MAAK,IAAI,EAAE,cAAc,EAAE,WAAW;AAAA;AAAA,IAG1C,UAAUC,MAAK,UAAU,EAAE,QAAQ;AAAA;AAAA,IACnC,mBAAmBA,MAAK,mBAAmB,EAAE,QAAQ;AAAA,IACrD,YAAYA,MAAK,YAAY,EAAE,QAAQ;AAAA;AAAA,IAGvC,QAAQA,MAAK,QAAQ,EAClB,MAA0B,EAC1B,QAAQ,EACR,QAAQ,SAAS;AAAA,IACpB,UAAUA,MAAK,UAAU,EAAE,QAAQ,GAAG;AAAA,IACtC,iBAAiBC,WAAU,mBAAmB,EAAE,cAAc,KAAK,CAAC;AAAA;AAAA,IAGpE,gBAAgBF,MAAK,gBAAgB;AAAA;AAAA,IAGrC,SAASG,OAAM,SAAS,EAAE,MAA+B,EAAE,QAAQ;AAAA,IACnE,WAAWF,MAAK,WAAW;AAAA;AAAA,IAG3B,eAAeA,MAAK,eAAe;AAAA,IACnC,eAAeE,OAAM,eAAe;AAAA;AAAA,IAGpC,aAAaD,WAAU,eAAe,EAAE,cAAc,KAAK,CAAC,EACzD,QAAQ,EACR,WAAW;AAAA,IACd,cAAcA,WAAU,gBAAgB,EAAE,cAAc,KAAK,CAAC;AAAA,IAC9D,YAAYA,WAAU,cAAc,EAAE,cAAc,KAAK,CAAC,EACvD,QAAQ,EACR,WAAW;AAAA,EAChB;AAAA,EACA,CAAC,WAAW;AAAA;AAAA,IAEV,qBAAqBG,QAAO,sCAAsC,EAAE;AAAA,MAClE,MAAM;AAAA,MACN,MAAM;AAAA,IACR;AAAA;AAAA,IAEA,WAAWD,OAAM,2BAA2B,EAAE,GAAG,MAAM,MAAM;AAAA,IAC7D,gBAAgBA,OAAM,gCAAgC,EAAE;AAAA,MACtD,MAAM;AAAA,IACR;AAAA,IACA,eAAeA,OAAM,gCAAgC,EAAE,GAAG,MAAM,WAAW;AAAA,IAC3E,aAAaA,OAAM,6BAA6B,EAAE,GAAG,MAAM,QAAQ;AAAA,IACnE,cAAcA,OAAM,+BAA+B,EAAE,GAAG,MAAM,UAAU;AAAA,EAC1E;AACF;;;ACvEA;AAAA,EACE,WAAAE;AAAA,EACA,QAAAC;AAAA,EACA,QAAAC;AAAA,EACA,aAAAC;AAAA,EACA,SAAAC;AAAA,EACA,SAAAC;AAAA,OACK;AA2CA,IAAM,kBAAkBL;AAAA,EAC7B;AAAA,EACA;AAAA,IACE,IAAIC,MAAK,IAAI,EAAE,cAAc,EAAE,WAAW;AAAA;AAAA,IAG1C,gBAAgBA,MAAK,gBAAgB,EAAE,QAAQ;AAAA;AAAA,IAG/C,QAAQC,MAAK,QAAQ,EAAE,MAAsB,EAAE,QAAQ;AAAA;AAAA,IAGvD,gBAAgBE,OAAM,gBAAgB;AAAA,IACtC,WAAWA,OAAM,WAAW,EAAE,QAAQ;AAAA;AAAA,IAGtC,cAAcF,MAAK,cAAc,EAAE,MAAuB,EAAE,QAAQ;AAAA,IACpE,iBAAiBD,MAAK,iBAAiB;AAAA;AAAA;AAAA,IAGvC,YAAYC,MAAK,YAAY;AAAA,IAC7B,YAAYA,MAAK,YAAY;AAAA;AAAA,IAG7B,gBAAgBA,MAAK,gBAAgB;AAAA;AAAA,IAGrC,UAAUE,OAAM,UAAU,EAAE,MAA+B;AAAA;AAAA,IAG3D,YAAYD,WAAU,cAAc,EAAE,cAAc,KAAK,CAAC,EACvD,QAAQ,EACR,WAAW;AAAA,EAChB;AAAA,EACA,CAAC,WAAW;AAAA;AAAA,IAEV,gBAAgBE,OAAM,mCAAmC,EAAE;AAAA,MACzD,MAAM;AAAA,IACR;AAAA,IACA,WAAWA,OAAM,8BAA8B,EAAE,GAAG,MAAM,MAAM;AAAA,IAChE,gBAAgBA,OAAM,mCAAmC,EAAE;AAAA,MACzD,MAAM;AAAA,IACR;AAAA,IACA,cAAcA,OAAM,kCAAkC,EAAE,GAAG,MAAM,UAAU;AAAA,IAC3E,gBAAgBA,OAAM,oCAAoC,EAAE;AAAA,MAC1D,MAAM;AAAA,IACR;AAAA,EACF;AACF;;;AClGA;AAAA,EACE,WAAAC;AAAA,EACA,QAAAC;AAAA,EACA,QAAAC;AAAA,EACA,WAAAC;AAAA,EACA,aAAAC;AAAA,EACA,SAAAC;AAAA,EACA,SAAAC;AAAA,EACA,UAAAC;AAAA,OACK;AAoBA,IAAM,iBAAiBP;AAAA,EAC5B;AAAA,EACA;AAAA,IACE,IAAIC,MAAK,IAAI,EAAE,cAAc,EAAE,WAAW;AAAA;AAAA,IAG1C,UAAUC,MAAK,UAAU,EAAE,QAAQ;AAAA;AAAA;AAAA,IAGnC,eAAeA,MAAK,eAAe,EAChC,MAA2B,EAC3B,QAAQ,EACR,QAAQ,QAAQ;AAAA;AAAA,IAGnB,eAAeA,MAAK,eAAe,EAAE,QAAQ,GAAG;AAAA,IAChD,eAAeA,MAAK,eAAe,EAAE,QAAQ,GAAG;AAAA,IAChD,iBAAiBE,WAAU,mBAAmB,EAAE,cAAc,KAAK,CAAC;AAAA,IACpE,iBAAiBA,WAAU,mBAAmB,EAAE,cAAc,KAAK,CAAC;AAAA;AAAA,IAGpE,mBAAmBA,WAAU,qBAAqB,EAAE,cAAc,KAAK,CAAC;AAAA,IACxE,eAAeA,WAAU,iBAAiB,EAAE,cAAc,KAAK,CAAC;AAAA;AAAA,IAGhE,gBAAgBD,SAAQ,gBAAgB;AAAA,IACxC,YAAYA,SAAQ,YAAY;AAAA;AAAA,IAChC,sBAAsBD,MAAK,sBAAsB,EAAE,QAAQ,GAAG;AAAA;AAAA,IAG9D,sBAAsBE,WAAU,wBAAwB,EAAE,cAAc,KAAK,CAAC;AAAA,IAC9E,qBAAqBC,OAAM,qBAAqB,EAAE,MAI/C;AAAA;AAAA,IAGH,YAAYD,WAAU,cAAc,EAAE,cAAc,KAAK,CAAC,EACvD,QAAQ,EACR,WAAW;AAAA,IACd,YAAYA,WAAU,cAAc,EAAE,cAAc,KAAK,CAAC,EACvD,QAAQ,EACR,WAAW;AAAA,EAChB;AAAA,EACA,CAAC,WAAW;AAAA;AAAA,IAEV,gBAAgBG,QAAO,iCAAiC,EAAE,GAAG,MAAM,QAAQ;AAAA;AAAA,IAE3E,iBAAiBD,OAAM,mCAAmC,EAAE;AAAA,MAC1D,MAAM;AAAA,IACR;AAAA,IACA,cAAcA,OAAM,gCAAgC,EAAE,GAAG,MAAM,aAAa;AAAA,EAC9E;AACF;","names":["pgTable","uuid","text","timestamp","jsonb","index","pgTable","uuid","text","timestamp","jsonb","index","unique","pgTable","uuid","text","timestamp","jsonb","index","pgTable","uuid","text","numeric","timestamp","jsonb","index","unique"]}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/storage/index.ts
|
|
21
|
+
var storage_exports = {};
|
|
22
|
+
__export(storage_exports, {
|
|
23
|
+
DrizzleCircuitBreakerStorage: () => DrizzleCircuitBreakerStorage,
|
|
24
|
+
createDrizzleCircuitBreakerStorage: () => createDrizzleCircuitBreakerStorage
|
|
25
|
+
});
|
|
26
|
+
module.exports = __toCommonJS(storage_exports);
|
|
27
|
+
|
|
28
|
+
// src/storage/drizzle-circuit-breaker-storage.ts
|
|
29
|
+
var DrizzleCircuitBreakerStorage = class {
|
|
30
|
+
repo;
|
|
31
|
+
constructor(providerHealthRepository) {
|
|
32
|
+
this.repo = providerHealthRepository;
|
|
33
|
+
}
|
|
34
|
+
async getState(provider) {
|
|
35
|
+
try {
|
|
36
|
+
const health = await this.repo.findByProvider(provider);
|
|
37
|
+
if (!health) return null;
|
|
38
|
+
return this.mapToStateRecord(provider, health);
|
|
39
|
+
} catch (error) {
|
|
40
|
+
console.error(`[DrizzleCircuitBreakerStorage] Failed to get state for ${provider}:`, error);
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
async setState(provider, state) {
|
|
45
|
+
try {
|
|
46
|
+
await this.repo.getOrCreate(provider);
|
|
47
|
+
await this.repo.update(provider, {
|
|
48
|
+
circuitState: state.state,
|
|
49
|
+
failureCount: state.failureCount,
|
|
50
|
+
successCount: state.successCount,
|
|
51
|
+
lastFailureAt: state.lastFailure ?? void 0,
|
|
52
|
+
circuitOpenedAt: state.openedAt ?? void 0,
|
|
53
|
+
nextRetryAt: state.nextRetryAt ?? void 0
|
|
54
|
+
});
|
|
55
|
+
} catch (error) {
|
|
56
|
+
console.error(`[DrizzleCircuitBreakerStorage] Failed to set state for ${provider}:`, error);
|
|
57
|
+
throw error;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
async getAllStates() {
|
|
61
|
+
try {
|
|
62
|
+
const allHealth = await this.repo.findAll();
|
|
63
|
+
const states = /* @__PURE__ */ new Map();
|
|
64
|
+
for (const health of allHealth) {
|
|
65
|
+
const provider = health.provider;
|
|
66
|
+
states.set(provider, this.mapToStateRecord(provider, health));
|
|
67
|
+
}
|
|
68
|
+
return states;
|
|
69
|
+
} catch (error) {
|
|
70
|
+
console.error("[DrizzleCircuitBreakerStorage] Failed to get all states:", error);
|
|
71
|
+
return /* @__PURE__ */ new Map();
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
async deleteState(provider) {
|
|
75
|
+
try {
|
|
76
|
+
await this.repo.resetStats(provider);
|
|
77
|
+
await this.repo.closeCircuit(provider);
|
|
78
|
+
} catch (error) {
|
|
79
|
+
console.error(`[DrizzleCircuitBreakerStorage] Failed to delete state for ${provider}:`, error);
|
|
80
|
+
throw error;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
async getOpenCircuits() {
|
|
84
|
+
try {
|
|
85
|
+
const openHealth = await this.repo.findOpenCircuits();
|
|
86
|
+
return openHealth.map((h) => h.provider);
|
|
87
|
+
} catch (error) {
|
|
88
|
+
console.error("[DrizzleCircuitBreakerStorage] Failed to get open circuits:", error);
|
|
89
|
+
return [];
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
async isHealthy() {
|
|
93
|
+
try {
|
|
94
|
+
await this.repo.findAll();
|
|
95
|
+
return true;
|
|
96
|
+
} catch (error) {
|
|
97
|
+
console.error("[DrizzleCircuitBreakerStorage] Health check failed:", error);
|
|
98
|
+
return false;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
// ==========================================================================
|
|
102
|
+
// Helper Methods
|
|
103
|
+
// ==========================================================================
|
|
104
|
+
mapToStateRecord(provider, health) {
|
|
105
|
+
return {
|
|
106
|
+
provider,
|
|
107
|
+
state: health.circuitState,
|
|
108
|
+
failureCount: health.failureCount,
|
|
109
|
+
successCount: health.successCount,
|
|
110
|
+
lastFailure: health.lastFailureAt,
|
|
111
|
+
openedAt: health.circuitOpenedAt,
|
|
112
|
+
nextRetryAt: health.nextRetryAt
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
};
|
|
116
|
+
function createDrizzleCircuitBreakerStorage(providerHealthRepo) {
|
|
117
|
+
return new DrizzleCircuitBreakerStorage(providerHealthRepo);
|
|
118
|
+
}
|
|
119
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
120
|
+
0 && (module.exports = {
|
|
121
|
+
DrizzleCircuitBreakerStorage,
|
|
122
|
+
createDrizzleCircuitBreakerStorage
|
|
123
|
+
});
|
|
124
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/storage/index.ts","../../src/storage/drizzle-circuit-breaker-storage.ts"],"sourcesContent":["/**\n * @nehorai/payments-drizzle - Storage Exports\n *\n * Database-backed circuit breaker storage implementations.\n */\n\nexport {\n DrizzleCircuitBreakerStorage,\n createDrizzleCircuitBreakerStorage,\n} from './drizzle-circuit-breaker-storage.js'\n","/**\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":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACsCO,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":[]}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { PaymentProvider } from '@nehorai/payments/types';
|
|
2
|
+
import { IProviderHealthRepository } from '@nehorai/payments/repository';
|
|
3
|
+
import { ICircuitBreakerStorage, CircuitBreakerStateRecord } from '@nehorai/payments/services';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* @nehorai/payments-drizzle - Drizzle Circuit Breaker Storage
|
|
7
|
+
*
|
|
8
|
+
* Database-backed storage implementation using the existing provider_health table.
|
|
9
|
+
* Suitable for serverless deployments and multi-instance environments.
|
|
10
|
+
*
|
|
11
|
+
* Benefits:
|
|
12
|
+
* - State persists across deployments
|
|
13
|
+
* - Shared state across multiple instances (serverless-friendly)
|
|
14
|
+
* - Uses existing provider_health table (no migration needed)
|
|
15
|
+
*
|
|
16
|
+
* Usage:
|
|
17
|
+
* ```typescript
|
|
18
|
+
* const repos = createDrizzleRepositories(db);
|
|
19
|
+
* const storage = new DrizzleCircuitBreakerStorage(repos.providerHealth);
|
|
20
|
+
* const circuitBreaker = new CircuitBreaker({ storage });
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Drizzle-based implementation of ICircuitBreakerStorage
|
|
26
|
+
*
|
|
27
|
+
* Uses the existing provider_health table via IProviderHealthRepository.
|
|
28
|
+
* Perfect for serverless environments (Vercel, AWS Lambda) where
|
|
29
|
+
* in-memory state doesn't persist between invocations.
|
|
30
|
+
*/
|
|
31
|
+
declare class DrizzleCircuitBreakerStorage implements ICircuitBreakerStorage {
|
|
32
|
+
private repo;
|
|
33
|
+
constructor(providerHealthRepository: IProviderHealthRepository);
|
|
34
|
+
getState(provider: PaymentProvider): Promise<CircuitBreakerStateRecord | null>;
|
|
35
|
+
setState(provider: PaymentProvider, state: CircuitBreakerStateRecord): Promise<void>;
|
|
36
|
+
getAllStates(): Promise<Map<PaymentProvider, CircuitBreakerStateRecord>>;
|
|
37
|
+
deleteState(provider: PaymentProvider): Promise<void>;
|
|
38
|
+
getOpenCircuits(): Promise<PaymentProvider[]>;
|
|
39
|
+
isHealthy(): Promise<boolean>;
|
|
40
|
+
private mapToStateRecord;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Create a Drizzle-based circuit breaker storage
|
|
44
|
+
*
|
|
45
|
+
* Convenience function for creating storage with a provider health repository.
|
|
46
|
+
*
|
|
47
|
+
* @param providerHealthRepo - The Drizzle provider health repository
|
|
48
|
+
* @returns DrizzleCircuitBreakerStorage instance
|
|
49
|
+
*/
|
|
50
|
+
declare function createDrizzleCircuitBreakerStorage(providerHealthRepo: IProviderHealthRepository): DrizzleCircuitBreakerStorage;
|
|
51
|
+
|
|
52
|
+
export { DrizzleCircuitBreakerStorage, createDrizzleCircuitBreakerStorage };
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { PaymentProvider } from '@nehorai/payments/types';
|
|
2
|
+
import { IProviderHealthRepository } from '@nehorai/payments/repository';
|
|
3
|
+
import { ICircuitBreakerStorage, CircuitBreakerStateRecord } from '@nehorai/payments/services';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* @nehorai/payments-drizzle - Drizzle Circuit Breaker Storage
|
|
7
|
+
*
|
|
8
|
+
* Database-backed storage implementation using the existing provider_health table.
|
|
9
|
+
* Suitable for serverless deployments and multi-instance environments.
|
|
10
|
+
*
|
|
11
|
+
* Benefits:
|
|
12
|
+
* - State persists across deployments
|
|
13
|
+
* - Shared state across multiple instances (serverless-friendly)
|
|
14
|
+
* - Uses existing provider_health table (no migration needed)
|
|
15
|
+
*
|
|
16
|
+
* Usage:
|
|
17
|
+
* ```typescript
|
|
18
|
+
* const repos = createDrizzleRepositories(db);
|
|
19
|
+
* const storage = new DrizzleCircuitBreakerStorage(repos.providerHealth);
|
|
20
|
+
* const circuitBreaker = new CircuitBreaker({ storage });
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Drizzle-based implementation of ICircuitBreakerStorage
|
|
26
|
+
*
|
|
27
|
+
* Uses the existing provider_health table via IProviderHealthRepository.
|
|
28
|
+
* Perfect for serverless environments (Vercel, AWS Lambda) where
|
|
29
|
+
* in-memory state doesn't persist between invocations.
|
|
30
|
+
*/
|
|
31
|
+
declare class DrizzleCircuitBreakerStorage implements ICircuitBreakerStorage {
|
|
32
|
+
private repo;
|
|
33
|
+
constructor(providerHealthRepository: IProviderHealthRepository);
|
|
34
|
+
getState(provider: PaymentProvider): Promise<CircuitBreakerStateRecord | null>;
|
|
35
|
+
setState(provider: PaymentProvider, state: CircuitBreakerStateRecord): Promise<void>;
|
|
36
|
+
getAllStates(): Promise<Map<PaymentProvider, CircuitBreakerStateRecord>>;
|
|
37
|
+
deleteState(provider: PaymentProvider): Promise<void>;
|
|
38
|
+
getOpenCircuits(): Promise<PaymentProvider[]>;
|
|
39
|
+
isHealthy(): Promise<boolean>;
|
|
40
|
+
private mapToStateRecord;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Create a Drizzle-based circuit breaker storage
|
|
44
|
+
*
|
|
45
|
+
* Convenience function for creating storage with a provider health repository.
|
|
46
|
+
*
|
|
47
|
+
* @param providerHealthRepo - The Drizzle provider health repository
|
|
48
|
+
* @returns DrizzleCircuitBreakerStorage instance
|
|
49
|
+
*/
|
|
50
|
+
declare function createDrizzleCircuitBreakerStorage(providerHealthRepo: IProviderHealthRepository): DrizzleCircuitBreakerStorage;
|
|
51
|
+
|
|
52
|
+
export { DrizzleCircuitBreakerStorage, createDrizzleCircuitBreakerStorage };
|