@revealui/services 0.0.3 → 0.2.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 +22 -0
- package/LICENSE.commercial +112 -0
- package/README.md +177 -0
- package/dist/api/create-checkout-session/index.d.ts +2 -0
- package/dist/api/create-checkout-session/index.d.ts.map +1 -0
- package/dist/api/create-checkout-session/index.js +61 -0
- package/dist/api/create-checkout-session/index.js.map +1 -0
- package/dist/api/create-portal-link/index.d.ts +2 -0
- package/dist/api/create-portal-link/index.d.ts.map +1 -0
- package/dist/api/create-portal-link/index.js +37 -0
- package/dist/api/create-portal-link/index.js.map +1 -0
- package/dist/api/handlers/customer-handlers.d.ts +27 -0
- package/dist/api/handlers/customer-handlers.d.ts.map +1 -0
- package/dist/api/handlers/customer-handlers.js +86 -0
- package/dist/api/handlers/customer-handlers.js.map +1 -0
- package/dist/api/handlers/index.d.ts +18 -0
- package/dist/api/handlers/index.d.ts.map +1 -0
- package/dist/api/handlers/index.js +18 -0
- package/dist/api/handlers/index.js.map +1 -0
- package/dist/api/handlers/invoice-handlers.d.ts +9 -0
- package/dist/api/handlers/invoice-handlers.d.ts.map +1 -0
- package/dist/api/handlers/invoice-handlers.js +52 -0
- package/dist/api/handlers/invoice-handlers.js.map +1 -0
- package/dist/api/handlers/payment-handlers.d.ts +13 -0
- package/dist/api/handlers/payment-handlers.d.ts.map +1 -0
- package/dist/api/handlers/payment-handlers.js +133 -0
- package/dist/api/handlers/payment-handlers.js.map +1 -0
- package/dist/api/handlers/payment-intent.d.ts +21 -0
- package/dist/api/handlers/payment-intent.d.ts.map +1 -0
- package/dist/api/handlers/payment-intent.js +87 -0
- package/dist/api/handlers/payment-intent.js.map +1 -0
- package/dist/api/handlers/product-handlers.d.ts +11 -0
- package/dist/api/handlers/product-handlers.d.ts.map +1 -0
- package/dist/api/handlers/product-handlers.js +43 -0
- package/dist/api/handlers/product-handlers.js.map +1 -0
- package/dist/api/handlers/subscription-handlers.d.ts +17 -0
- package/dist/api/handlers/subscription-handlers.d.ts.map +1 -0
- package/dist/api/handlers/subscription-handlers.js +119 -0
- package/dist/api/handlers/subscription-handlers.js.map +1 -0
- package/dist/api/index.d.ts +8 -0
- package/dist/api/index.d.ts.map +1 -0
- package/dist/api/index.js +8 -0
- package/dist/api/index.js.map +1 -0
- package/dist/api/types/stripe.d.ts +42 -0
- package/dist/api/types/stripe.d.ts.map +1 -0
- package/dist/api/types/stripe.js +72 -0
- package/dist/api/types/stripe.js.map +1 -0
- package/dist/api/update-price/index.d.ts +42 -0
- package/dist/api/update-price/index.d.ts.map +1 -0
- package/dist/api/update-price/index.js +78 -0
- package/dist/api/update-price/index.js.map +1 -0
- package/dist/api/update-product/index.d.ts +44 -0
- package/dist/api/update-product/index.d.ts.map +1 -0
- package/dist/api/update-product/index.js +85 -0
- package/dist/api/update-product/index.js.map +1 -0
- package/dist/api/utils.d.ts +34 -0
- package/dist/api/utils.d.ts.map +1 -0
- package/dist/api/utils.js +66 -0
- package/dist/api/utils.js.map +1 -0
- package/dist/api/webhooks/index.d.ts +12 -0
- package/dist/api/webhooks/index.d.ts.map +1 -0
- package/dist/api/webhooks/index.js +280 -0
- package/dist/api/webhooks/index.js.map +1 -0
- package/dist/client/index.d.ts +11 -0
- package/dist/client/index.d.ts.map +1 -0
- package/dist/client/index.js +12 -0
- package/dist/client/index.js.map +1 -0
- package/dist/index.d.ts +33 -24
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +46 -41
- package/dist/index.js.map +1 -0
- package/dist/revealcoin/__tests__/client.test.d.ts +2 -0
- package/dist/revealcoin/__tests__/client.test.d.ts.map +1 -0
- package/dist/revealcoin/__tests__/client.test.js +207 -0
- package/dist/revealcoin/__tests__/client.test.js.map +1 -0
- package/dist/revealcoin/__tests__/config.test.d.ts +2 -0
- package/dist/revealcoin/__tests__/config.test.d.ts.map +1 -0
- package/dist/revealcoin/__tests__/config.test.js +91 -0
- package/dist/revealcoin/__tests__/config.test.js.map +1 -0
- package/dist/revealcoin/__tests__/oracle.test.d.ts +2 -0
- package/dist/revealcoin/__tests__/oracle.test.d.ts.map +1 -0
- package/dist/revealcoin/__tests__/oracle.test.js +238 -0
- package/dist/revealcoin/__tests__/oracle.test.js.map +1 -0
- package/dist/revealcoin/__tests__/safeguards.test.d.ts +2 -0
- package/dist/revealcoin/__tests__/safeguards.test.d.ts.map +1 -0
- package/dist/revealcoin/__tests__/safeguards.test.js +571 -0
- package/dist/revealcoin/__tests__/safeguards.test.js.map +1 -0
- package/dist/revealcoin/client.d.ts +51 -0
- package/dist/revealcoin/client.d.ts.map +1 -0
- package/dist/revealcoin/client.js +211 -0
- package/dist/revealcoin/client.js.map +1 -0
- package/dist/revealcoin/config.d.ts +32 -0
- package/dist/revealcoin/config.d.ts.map +1 -0
- package/dist/revealcoin/config.js +54 -0
- package/dist/revealcoin/config.js.map +1 -0
- package/dist/revealcoin/index.d.ts +5 -0
- package/dist/revealcoin/index.d.ts.map +1 -0
- package/dist/revealcoin/index.js +5 -0
- package/dist/revealcoin/index.js.map +1 -0
- package/dist/revealcoin/oracle.d.ts +81 -0
- package/dist/revealcoin/oracle.d.ts.map +1 -0
- package/dist/revealcoin/oracle.js +211 -0
- package/dist/revealcoin/oracle.js.map +1 -0
- package/dist/revealcoin/safeguards.d.ts +92 -0
- package/dist/revealcoin/safeguards.d.ts.map +1 -0
- package/dist/revealcoin/safeguards.js +240 -0
- package/dist/revealcoin/safeguards.js.map +1 -0
- package/dist/stripe/db-circuit-breaker.d.ts +47 -0
- package/dist/stripe/db-circuit-breaker.d.ts.map +1 -0
- package/dist/stripe/db-circuit-breaker.js +223 -0
- package/dist/stripe/db-circuit-breaker.js.map +1 -0
- package/dist/stripe/index.d.ts +2 -0
- package/dist/stripe/index.d.ts.map +1 -0
- package/dist/stripe/index.js +2 -0
- package/dist/stripe/index.js.map +1 -0
- package/dist/stripe/stripeClient.d.ts +126 -0
- package/dist/stripe/stripeClient.d.ts.map +1 -0
- package/dist/stripe/stripeClient.js +226 -0
- package/dist/stripe/stripeClient.js.map +1 -0
- package/dist/supabase/index.d.ts +6 -0
- package/dist/supabase/index.d.ts.map +1 -0
- package/dist/supabase/index.js +5 -0
- package/dist/supabase/index.js.map +1 -0
- package/dist/supabase/resilience.d.ts +50 -0
- package/dist/supabase/resilience.d.ts.map +1 -0
- package/dist/supabase/resilience.js +166 -0
- package/dist/supabase/resilience.js.map +1 -0
- package/dist/supabase/types.d.ts +206 -0
- package/dist/supabase/types.d.ts.map +1 -0
- package/dist/supabase/types.js +19 -0
- package/dist/supabase/types.js.map +1 -0
- package/dist/supabase/utils/client.d.ts +4 -0
- package/dist/supabase/utils/client.d.ts.map +1 -0
- package/dist/supabase/utils/client.js +12 -0
- package/dist/supabase/utils/client.js.map +1 -0
- package/dist/supabase/utils/server.d.ts +10 -0
- package/dist/supabase/utils/server.d.ts.map +1 -0
- package/dist/supabase/utils/server.js +49 -0
- package/dist/supabase/utils/server.js.map +1 -0
- package/dist/supabase/utils/web.d.ts +4 -0
- package/dist/supabase/utils/web.d.ts.map +1 -0
- package/dist/supabase/utils/web.js +37 -0
- package/dist/supabase/utils/web.js.map +1 -0
- package/package.json +79 -16
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import Stripe from 'stripe';
|
|
2
|
+
import { DbCircuitBreaker } from './db-circuit-breaker.js';
|
|
3
|
+
/**
|
|
4
|
+
* Get or create Stripe client instance (production use)
|
|
5
|
+
*/
|
|
6
|
+
declare function getStripe(): Stripe;
|
|
7
|
+
/**
|
|
8
|
+
* Factory function to create protected Stripe client with dependency injection
|
|
9
|
+
* @param stripeInstance - Stripe instance to use (for testing) or undefined to use getStripe()
|
|
10
|
+
*/
|
|
11
|
+
declare function createProtectedStripe(stripeInstance?: Stripe): {
|
|
12
|
+
billingPortal: {
|
|
13
|
+
sessions: {
|
|
14
|
+
create: (params: Stripe.BillingPortal.SessionCreateParams, options?: Stripe.RequestOptions) => Promise<Stripe.BillingPortal.Session>;
|
|
15
|
+
};
|
|
16
|
+
};
|
|
17
|
+
customers: {
|
|
18
|
+
create: (params: Stripe.CustomerCreateParams, options?: Stripe.RequestOptions) => Promise<Stripe.Customer>;
|
|
19
|
+
retrieve: (id: string, options?: Stripe.RequestOptions | undefined) => Promise<Stripe.Customer | Stripe.DeletedCustomer>;
|
|
20
|
+
update: (id: string, params?: Stripe.CustomerUpdateParams | undefined, options?: Stripe.RequestOptions | undefined) => Promise<Stripe.Customer>;
|
|
21
|
+
del: (id: string, options?: Stripe.RequestOptions | undefined) => Promise<Stripe.DeletedCustomer>;
|
|
22
|
+
list: (params?: Stripe.CustomerListParams, options?: Stripe.RequestOptions) => Promise<Stripe.ApiList<Stripe.Customer>>;
|
|
23
|
+
};
|
|
24
|
+
paymentIntents: {
|
|
25
|
+
create: (params: Stripe.PaymentIntentCreateParams, options?: Stripe.RequestOptions | undefined) => Promise<Stripe.PaymentIntent>;
|
|
26
|
+
retrieve: (id: string, options?: Stripe.RequestOptions | undefined) => Promise<Stripe.PaymentIntent>;
|
|
27
|
+
update: (id: string, params?: Stripe.PaymentIntentUpdateParams | undefined, options?: Stripe.RequestOptions | undefined) => Promise<Stripe.PaymentIntent>;
|
|
28
|
+
};
|
|
29
|
+
checkout: {
|
|
30
|
+
sessions: {
|
|
31
|
+
create: (params: Stripe.Checkout.SessionCreateParams, options?: Stripe.RequestOptions) => Promise<Stripe.Checkout.Session>;
|
|
32
|
+
retrieve: (id: string, options?: Stripe.RequestOptions | undefined) => Promise<Stripe.Checkout.Session>;
|
|
33
|
+
};
|
|
34
|
+
};
|
|
35
|
+
products: {
|
|
36
|
+
create: (params: Stripe.ProductCreateParams, options?: Stripe.RequestOptions | undefined) => Promise<Stripe.Product>;
|
|
37
|
+
retrieve: (id: string, options?: Stripe.RequestOptions | undefined) => Promise<Stripe.Product>;
|
|
38
|
+
update: (id: string, params?: Stripe.ProductUpdateParams | undefined, options?: Stripe.RequestOptions | undefined) => Promise<Stripe.Product>;
|
|
39
|
+
list: (params?: Stripe.ProductListParams, options?: Stripe.RequestOptions) => Promise<Stripe.ApiList<Stripe.Product>>;
|
|
40
|
+
};
|
|
41
|
+
prices: {
|
|
42
|
+
create: (params: Stripe.PriceCreateParams, options?: Stripe.RequestOptions | undefined) => Promise<Stripe.Price>;
|
|
43
|
+
retrieve: (id: string, options?: Stripe.RequestOptions | undefined) => Promise<Stripe.Price>;
|
|
44
|
+
update: (id: string, params?: Stripe.PriceUpdateParams | undefined, options?: Stripe.RequestOptions | undefined) => Promise<Stripe.Price>;
|
|
45
|
+
list: (params?: Stripe.PriceListParams, options?: Stripe.RequestOptions) => Promise<Stripe.ApiList<Stripe.Price>>;
|
|
46
|
+
};
|
|
47
|
+
subscriptions: {
|
|
48
|
+
list: (options?: Stripe.RequestOptions | undefined) => Promise<Stripe.ApiList<Stripe.Subscription>>;
|
|
49
|
+
retrieve: (id: string, options?: Stripe.RequestOptions | undefined) => Promise<Stripe.Subscription>;
|
|
50
|
+
update: (id: string, params?: Stripe.SubscriptionUpdateParams | undefined, options?: Stripe.RequestOptions | undefined) => Promise<Stripe.Subscription>;
|
|
51
|
+
cancel: (id: string, options?: Stripe.RequestOptions | undefined) => Promise<Stripe.Subscription>;
|
|
52
|
+
};
|
|
53
|
+
readonly webhooks: Stripe["webhooks"];
|
|
54
|
+
readonly balance: Stripe["balance"];
|
|
55
|
+
};
|
|
56
|
+
/**
|
|
57
|
+
* Enhanced Stripe client with circuit breaker and retry protection
|
|
58
|
+
* Uses factory with production Stripe instance for backward compatibility
|
|
59
|
+
*/
|
|
60
|
+
export declare const protectedStripe: {
|
|
61
|
+
billingPortal: {
|
|
62
|
+
sessions: {
|
|
63
|
+
create: (params: Stripe.BillingPortal.SessionCreateParams, options?: Stripe.RequestOptions) => Promise<Stripe.BillingPortal.Session>;
|
|
64
|
+
};
|
|
65
|
+
};
|
|
66
|
+
customers: {
|
|
67
|
+
create: (params: Stripe.CustomerCreateParams, options?: Stripe.RequestOptions) => Promise<Stripe.Customer>;
|
|
68
|
+
retrieve: (id: string, options?: Stripe.RequestOptions | undefined) => Promise<Stripe.Customer | Stripe.DeletedCustomer>;
|
|
69
|
+
update: (id: string, params?: Stripe.CustomerUpdateParams | undefined, options?: Stripe.RequestOptions | undefined) => Promise<Stripe.Customer>;
|
|
70
|
+
del: (id: string, options?: Stripe.RequestOptions | undefined) => Promise<Stripe.DeletedCustomer>;
|
|
71
|
+
list: (params?: Stripe.CustomerListParams, options?: Stripe.RequestOptions) => Promise<Stripe.ApiList<Stripe.Customer>>;
|
|
72
|
+
};
|
|
73
|
+
paymentIntents: {
|
|
74
|
+
create: (params: Stripe.PaymentIntentCreateParams, options?: Stripe.RequestOptions | undefined) => Promise<Stripe.PaymentIntent>;
|
|
75
|
+
retrieve: (id: string, options?: Stripe.RequestOptions | undefined) => Promise<Stripe.PaymentIntent>;
|
|
76
|
+
update: (id: string, params?: Stripe.PaymentIntentUpdateParams | undefined, options?: Stripe.RequestOptions | undefined) => Promise<Stripe.PaymentIntent>;
|
|
77
|
+
};
|
|
78
|
+
checkout: {
|
|
79
|
+
sessions: {
|
|
80
|
+
create: (params: Stripe.Checkout.SessionCreateParams, options?: Stripe.RequestOptions) => Promise<Stripe.Checkout.Session>;
|
|
81
|
+
retrieve: (id: string, options?: Stripe.RequestOptions | undefined) => Promise<Stripe.Checkout.Session>;
|
|
82
|
+
};
|
|
83
|
+
};
|
|
84
|
+
products: {
|
|
85
|
+
create: (params: Stripe.ProductCreateParams, options?: Stripe.RequestOptions | undefined) => Promise<Stripe.Product>;
|
|
86
|
+
retrieve: (id: string, options?: Stripe.RequestOptions | undefined) => Promise<Stripe.Product>;
|
|
87
|
+
update: (id: string, params?: Stripe.ProductUpdateParams | undefined, options?: Stripe.RequestOptions | undefined) => Promise<Stripe.Product>;
|
|
88
|
+
list: (params?: Stripe.ProductListParams, options?: Stripe.RequestOptions) => Promise<Stripe.ApiList<Stripe.Product>>;
|
|
89
|
+
};
|
|
90
|
+
prices: {
|
|
91
|
+
create: (params: Stripe.PriceCreateParams, options?: Stripe.RequestOptions | undefined) => Promise<Stripe.Price>;
|
|
92
|
+
retrieve: (id: string, options?: Stripe.RequestOptions | undefined) => Promise<Stripe.Price>;
|
|
93
|
+
update: (id: string, params?: Stripe.PriceUpdateParams | undefined, options?: Stripe.RequestOptions | undefined) => Promise<Stripe.Price>;
|
|
94
|
+
list: (params?: Stripe.PriceListParams, options?: Stripe.RequestOptions) => Promise<Stripe.ApiList<Stripe.Price>>;
|
|
95
|
+
};
|
|
96
|
+
subscriptions: {
|
|
97
|
+
list: (options?: Stripe.RequestOptions | undefined) => Promise<Stripe.ApiList<Stripe.Subscription>>;
|
|
98
|
+
retrieve: (id: string, options?: Stripe.RequestOptions | undefined) => Promise<Stripe.Subscription>;
|
|
99
|
+
update: (id: string, params?: Stripe.SubscriptionUpdateParams | undefined, options?: Stripe.RequestOptions | undefined) => Promise<Stripe.Subscription>;
|
|
100
|
+
cancel: (id: string, options?: Stripe.RequestOptions | undefined) => Promise<Stripe.Subscription>;
|
|
101
|
+
};
|
|
102
|
+
readonly webhooks: Stripe["webhooks"];
|
|
103
|
+
readonly balance: Stripe["balance"];
|
|
104
|
+
};
|
|
105
|
+
export { getStripe, createProtectedStripe };
|
|
106
|
+
export declare const __dbCircuitBreaker: DbCircuitBreaker;
|
|
107
|
+
export declare const __CIRCUIT_BREAKER_CONFIG: {
|
|
108
|
+
failureThreshold: number;
|
|
109
|
+
resetTimeout: number;
|
|
110
|
+
successThreshold: number;
|
|
111
|
+
};
|
|
112
|
+
export declare const __RETRY_CONFIG: {
|
|
113
|
+
maxAttempts: number;
|
|
114
|
+
backoff: number[];
|
|
115
|
+
timeout: number;
|
|
116
|
+
};
|
|
117
|
+
/**
|
|
118
|
+
* Reset the DB circuit breaker state and clear local cache (test-only).
|
|
119
|
+
*/
|
|
120
|
+
export declare const __resetCircuitBreaker: () => Promise<void>;
|
|
121
|
+
/**
|
|
122
|
+
* Reset the cached Stripe instance (test-only)
|
|
123
|
+
* This allows tests to reset the production Stripe cache
|
|
124
|
+
*/
|
|
125
|
+
export declare const __resetStripe: () => void;
|
|
126
|
+
//# sourceMappingURL=stripeClient.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stripeClient.d.ts","sourceRoot":"","sources":["../../src/stripe/stripeClient.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
// Import config module (ESM)
|
|
2
|
+
// Config uses proxy for lazy loading, so import is safe - validation only happens on property access
|
|
3
|
+
import configModule from '@revealui/config';
|
|
4
|
+
import Stripe from 'stripe';
|
|
5
|
+
import { createLogger } from '@revealui/core/observability/logger';
|
|
6
|
+
import { DbCircuitBreaker } from './db-circuit-breaker.js';
|
|
7
|
+
const logger = createLogger({ service: 'Stripe' });
|
|
8
|
+
// Lazy initialization to handle missing env vars during build
|
|
9
|
+
let _stripe = null;
|
|
10
|
+
/**
|
|
11
|
+
* Get or create Stripe client instance (production use)
|
|
12
|
+
*/
|
|
13
|
+
function getStripe() {
|
|
14
|
+
// Use cached instance if available
|
|
15
|
+
if (_stripe)
|
|
16
|
+
return _stripe;
|
|
17
|
+
// Try to get from config module, fallback to process.env for backward compatibility
|
|
18
|
+
let secretKey;
|
|
19
|
+
try {
|
|
20
|
+
// Accessing config.stripe.secretKey triggers lazy validation via proxy
|
|
21
|
+
// Type assertion needed because Proxy type inference fails for nested properties
|
|
22
|
+
// Config is a Proxy, so we need to access properties directly
|
|
23
|
+
secretKey = configModule.stripe?.secretKey;
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
// Config validation failed or module unavailable - will use process.env fallback
|
|
27
|
+
secretKey = undefined;
|
|
28
|
+
}
|
|
29
|
+
secretKey = secretKey ?? process.env.STRIPE_SECRET_KEY;
|
|
30
|
+
if (!secretKey) {
|
|
31
|
+
throw new Error('STRIPE_SECRET_KEY environment variable is required. Use @revealui/config or set STRIPE_SECRET_KEY.');
|
|
32
|
+
}
|
|
33
|
+
_stripe = new Stripe(secretKey, {
|
|
34
|
+
apiVersion: '2026-01-28.clover',
|
|
35
|
+
});
|
|
36
|
+
return _stripe;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Circuit breaker configuration
|
|
40
|
+
*/
|
|
41
|
+
const CIRCUIT_BREAKER_CONFIG = {
|
|
42
|
+
failureThreshold: 5, // Open circuit after 5 failures
|
|
43
|
+
resetTimeout: 30000, // 30 seconds before half-open
|
|
44
|
+
successThreshold: 2, // Need 2 successes to close from half-open
|
|
45
|
+
};
|
|
46
|
+
/**
|
|
47
|
+
* Retry configuration
|
|
48
|
+
*/
|
|
49
|
+
const RETRY_CONFIG = {
|
|
50
|
+
maxAttempts: 3,
|
|
51
|
+
backoff: [100, 200, 400], // Exponential backoff in milliseconds
|
|
52
|
+
timeout: 10000, // 10 second timeout
|
|
53
|
+
};
|
|
54
|
+
/**
|
|
55
|
+
* Shared DB-backed circuit breaker for all Stripe operations.
|
|
56
|
+
* State is persisted to NeonDB so all API instances share the same view.
|
|
57
|
+
* Local 5-second cache keeps the read path fast.
|
|
58
|
+
*/
|
|
59
|
+
const stripeCircuitBreaker = new DbCircuitBreaker('stripe', {
|
|
60
|
+
failureThreshold: CIRCUIT_BREAKER_CONFIG.failureThreshold,
|
|
61
|
+
successThreshold: CIRCUIT_BREAKER_CONFIG.successThreshold,
|
|
62
|
+
resetTimeout: CIRCUIT_BREAKER_CONFIG.resetTimeout,
|
|
63
|
+
});
|
|
64
|
+
/**
|
|
65
|
+
* Sleep helper for exponential backoff
|
|
66
|
+
*/
|
|
67
|
+
function sleep(ms) {
|
|
68
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Timeout wrapper for promises
|
|
72
|
+
*/
|
|
73
|
+
function withTimeout(promise, timeoutMs) {
|
|
74
|
+
return Promise.race([
|
|
75
|
+
promise,
|
|
76
|
+
new Promise((_, reject) => setTimeout(() => reject(new Error(`Operation timed out after ${timeoutMs}ms`)), timeoutMs)),
|
|
77
|
+
]);
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Factory function to create protected Stripe client with dependency injection
|
|
81
|
+
* @param stripeInstance - Stripe instance to use (for testing) or undefined to use getStripe()
|
|
82
|
+
*/
|
|
83
|
+
function createProtectedStripe(stripeInstance) {
|
|
84
|
+
// Use provided instance or get production instance
|
|
85
|
+
const getStripeInstance = () => {
|
|
86
|
+
return stripeInstance ?? getStripe();
|
|
87
|
+
};
|
|
88
|
+
/**
|
|
89
|
+
* Wrapper for Stripe API calls with circuit breaker and retry logic
|
|
90
|
+
*/
|
|
91
|
+
async function callWithResilience(operation, operationName) {
|
|
92
|
+
// Check circuit breaker state (DB-backed, 5s local cache)
|
|
93
|
+
if (await stripeCircuitBreaker.isOpen()) {
|
|
94
|
+
logger.error(`Stripe circuit breaker is OPEN`, undefined, {
|
|
95
|
+
operation: operationName,
|
|
96
|
+
state: 'open',
|
|
97
|
+
});
|
|
98
|
+
throw new Error('Stripe circuit breaker is OPEN. Service may be unavailable. Please try again later.');
|
|
99
|
+
}
|
|
100
|
+
let lastError;
|
|
101
|
+
// Retry with exponential backoff
|
|
102
|
+
for (let attempt = 0; attempt < RETRY_CONFIG.maxAttempts; attempt++) {
|
|
103
|
+
try {
|
|
104
|
+
// Execute operation with timeout
|
|
105
|
+
const result = await withTimeout(operation(), RETRY_CONFIG.timeout);
|
|
106
|
+
// Success - record it and return
|
|
107
|
+
await stripeCircuitBreaker.recordSuccess();
|
|
108
|
+
return result;
|
|
109
|
+
}
|
|
110
|
+
catch (error) {
|
|
111
|
+
lastError = error;
|
|
112
|
+
// Check if it's a timeout or network error (retryable)
|
|
113
|
+
const isRetryable = error instanceof Error &&
|
|
114
|
+
(error.message.includes('timeout') ||
|
|
115
|
+
error.message.includes('ECONNREFUSED') ||
|
|
116
|
+
error.message.includes('ETIMEDOUT') ||
|
|
117
|
+
error.message.includes('network'));
|
|
118
|
+
// Don't retry non-retryable errors (e.g., validation errors from Stripe)
|
|
119
|
+
if (!isRetryable) {
|
|
120
|
+
await stripeCircuitBreaker.recordFailure();
|
|
121
|
+
logger.error(`Operation ${operationName} failed (non-retryable)`, error instanceof Error ? error : new Error(String(error)), {
|
|
122
|
+
operation: operationName,
|
|
123
|
+
attempt: attempt + 1,
|
|
124
|
+
maxAttempts: RETRY_CONFIG.maxAttempts,
|
|
125
|
+
});
|
|
126
|
+
throw error;
|
|
127
|
+
}
|
|
128
|
+
// Log retryable error
|
|
129
|
+
logger.warn(`Operation ${operationName} failed (retryable), retrying...`, {
|
|
130
|
+
operation: operationName,
|
|
131
|
+
attempt: attempt + 1,
|
|
132
|
+
maxAttempts: RETRY_CONFIG.maxAttempts,
|
|
133
|
+
error: error instanceof Error ? error.message : String(error),
|
|
134
|
+
});
|
|
135
|
+
// If this is the last attempt, don't wait
|
|
136
|
+
if (attempt === RETRY_CONFIG.maxAttempts - 1) {
|
|
137
|
+
break;
|
|
138
|
+
}
|
|
139
|
+
// Exponential backoff
|
|
140
|
+
const backoffMs = RETRY_CONFIG.backoff[attempt] ??
|
|
141
|
+
RETRY_CONFIG.backoff[RETRY_CONFIG.backoff.length - 1] ??
|
|
142
|
+
1000;
|
|
143
|
+
await sleep(backoffMs);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
// All retries failed
|
|
147
|
+
await stripeCircuitBreaker.recordFailure();
|
|
148
|
+
throw lastError instanceof Error
|
|
149
|
+
? new Error(`${operationName} failed after ${RETRY_CONFIG.maxAttempts} attempts: ${lastError.message}`)
|
|
150
|
+
: new Error(`${operationName} failed after ${RETRY_CONFIG.maxAttempts} attempts`);
|
|
151
|
+
}
|
|
152
|
+
// Return protected Stripe client using the provided or production Stripe instance
|
|
153
|
+
return {
|
|
154
|
+
billingPortal: {
|
|
155
|
+
sessions: {
|
|
156
|
+
create: (params, options) => callWithResilience(() => getStripeInstance().billingPortal.sessions.create(params, options), 'billingPortal.sessions.create'),
|
|
157
|
+
},
|
|
158
|
+
},
|
|
159
|
+
customers: {
|
|
160
|
+
create: (params, options) => callWithResilience(() => getStripeInstance().customers.create(params, options), 'customers.create'),
|
|
161
|
+
retrieve: (...args) => callWithResilience(() => getStripeInstance().customers.retrieve(...args), 'customers.retrieve'),
|
|
162
|
+
update: (...args) => callWithResilience(() => getStripeInstance().customers.update(...args), 'customers.update'),
|
|
163
|
+
del: (...args) => callWithResilience(() => getStripeInstance().customers.del(...args), 'customers.del'),
|
|
164
|
+
list: (params, options) => callWithResilience(() => getStripeInstance().customers.list(params, options), 'customers.list'),
|
|
165
|
+
},
|
|
166
|
+
paymentIntents: {
|
|
167
|
+
create: (...args) => callWithResilience(() => getStripeInstance().paymentIntents.create(...args), 'paymentIntents.create'),
|
|
168
|
+
retrieve: (...args) => callWithResilience(() => getStripeInstance().paymentIntents.retrieve(...args), 'paymentIntents.retrieve'),
|
|
169
|
+
update: (...args) => callWithResilience(() => getStripeInstance().paymentIntents.update(...args), 'paymentIntents.update'),
|
|
170
|
+
},
|
|
171
|
+
checkout: {
|
|
172
|
+
sessions: {
|
|
173
|
+
create: (params, options) => callWithResilience(() => getStripeInstance().checkout.sessions.create(params, options), 'checkout.sessions.create'),
|
|
174
|
+
retrieve: (...args) => callWithResilience(() => getStripeInstance().checkout.sessions.retrieve(...args), 'checkout.sessions.retrieve'),
|
|
175
|
+
},
|
|
176
|
+
},
|
|
177
|
+
products: {
|
|
178
|
+
create: (...args) => callWithResilience(() => getStripeInstance().products.create(...args), 'products.create'),
|
|
179
|
+
retrieve: (...args) => callWithResilience(() => getStripeInstance().products.retrieve(...args), 'products.retrieve'),
|
|
180
|
+
update: (...args) => callWithResilience(() => getStripeInstance().products.update(...args), 'products.update'),
|
|
181
|
+
list: (params, options) => callWithResilience(() => getStripeInstance().products.list(params, options), 'products.list'),
|
|
182
|
+
},
|
|
183
|
+
prices: {
|
|
184
|
+
create: (...args) => callWithResilience(() => getStripeInstance().prices.create(...args), 'prices.create'),
|
|
185
|
+
retrieve: (...args) => callWithResilience(() => getStripeInstance().prices.retrieve(...args), 'prices.retrieve'),
|
|
186
|
+
update: (...args) => callWithResilience(() => getStripeInstance().prices.update(...args), 'prices.update'),
|
|
187
|
+
list: (params, options) => callWithResilience(() => getStripeInstance().prices.list(params, options), 'prices.list'),
|
|
188
|
+
},
|
|
189
|
+
subscriptions: {
|
|
190
|
+
list: (...args) => callWithResilience(() => getStripeInstance().subscriptions.list(...args), 'subscriptions.list'),
|
|
191
|
+
retrieve: (...args) => callWithResilience(() => getStripeInstance().subscriptions.retrieve(...args), 'subscriptions.retrieve'),
|
|
192
|
+
update: (...args) => callWithResilience(() => getStripeInstance().subscriptions.update(...args), 'subscriptions.update'),
|
|
193
|
+
cancel: (...args) => callWithResilience(() => getStripeInstance().subscriptions.cancel(...args), 'subscriptions.cancel'),
|
|
194
|
+
},
|
|
195
|
+
get webhooks() {
|
|
196
|
+
return getStripeInstance().webhooks;
|
|
197
|
+
},
|
|
198
|
+
get balance() {
|
|
199
|
+
return getStripeInstance().balance;
|
|
200
|
+
},
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* Enhanced Stripe client with circuit breaker and retry protection
|
|
205
|
+
* Uses factory with production Stripe instance for backward compatibility
|
|
206
|
+
*/
|
|
207
|
+
export const protectedStripe = createProtectedStripe();
|
|
208
|
+
// Export factory for cases where you need explicit initialization control (e.g., testing)
|
|
209
|
+
export { getStripe, createProtectedStripe };
|
|
210
|
+
// Test-only exports (DO NOT USE IN PRODUCTION)
|
|
211
|
+
// These are exported with __ prefix to indicate they are internal and test-only
|
|
212
|
+
export const __dbCircuitBreaker = stripeCircuitBreaker;
|
|
213
|
+
export const __CIRCUIT_BREAKER_CONFIG = CIRCUIT_BREAKER_CONFIG;
|
|
214
|
+
export const __RETRY_CONFIG = RETRY_CONFIG;
|
|
215
|
+
/**
|
|
216
|
+
* Reset the DB circuit breaker state and clear local cache (test-only).
|
|
217
|
+
*/
|
|
218
|
+
export const __resetCircuitBreaker = () => stripeCircuitBreaker.reset();
|
|
219
|
+
/**
|
|
220
|
+
* Reset the cached Stripe instance (test-only)
|
|
221
|
+
* This allows tests to reset the production Stripe cache
|
|
222
|
+
*/
|
|
223
|
+
export const __resetStripe = () => {
|
|
224
|
+
_stripe = null;
|
|
225
|
+
};
|
|
226
|
+
//# sourceMappingURL=stripeClient.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stripeClient.js","sourceRoot":"","sources":["../../src/stripe/stripeClient.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export type { SupabaseClient } from '@supabase/supabase-js';
|
|
2
|
+
export { withSupabaseResilience } from './resilience.js';
|
|
3
|
+
export { default as createBrowserClient } from './utils/client.js';
|
|
4
|
+
export { default as createServerClient } from './utils/server.js';
|
|
5
|
+
export { createServerClientFromRequest } from './utils/web.js';
|
|
6
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/supabase/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAA;AAC3D,OAAO,EAAE,sBAAsB,EAAE,MAAM,iBAAiB,CAAA;AACxD,OAAO,EAAE,OAAO,IAAI,mBAAmB,EAAE,MAAM,mBAAmB,CAAA;AAClE,OAAO,EAAE,OAAO,IAAI,kBAAkB,EAAE,MAAM,mBAAmB,CAAA;AACjE,OAAO,EAAE,6BAA6B,EAAE,MAAM,gBAAgB,CAAA"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { withSupabaseResilience } from './resilience.js';
|
|
2
|
+
export { default as createBrowserClient } from './utils/client.js';
|
|
3
|
+
export { default as createServerClient } from './utils/server.js';
|
|
4
|
+
export { createServerClientFromRequest } from './utils/web.js';
|
|
5
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/supabase/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,sBAAsB,EAAE,MAAM,iBAAiB,CAAA;AACxD,OAAO,EAAE,OAAO,IAAI,mBAAmB,EAAE,MAAM,mBAAmB,CAAA;AAClE,OAAO,EAAE,OAAO,IAAI,kBAAkB,EAAE,MAAM,mBAAmB,CAAA;AACjE,OAAO,EAAE,6BAA6B,EAAE,MAAM,gBAAgB,CAAA"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Supabase Resilience Layer
|
|
3
|
+
*
|
|
4
|
+
* Provides circuit breaker + retry protection for Supabase operations,
|
|
5
|
+
* matching the resilience pattern used in packages/services/src/stripe/stripeClient.ts.
|
|
6
|
+
*
|
|
7
|
+
* NOTE: Circuit breaker state is in-memory (per-instance).
|
|
8
|
+
* TODO: For multi-instance deployments, replace with Redis-backed state.
|
|
9
|
+
* Uses createLogger from @revealui/core. Wire up to alerting when circuit opens.
|
|
10
|
+
*/
|
|
11
|
+
type CircuitState = 'closed' | 'open' | 'half-open';
|
|
12
|
+
interface CircuitBreakerState {
|
|
13
|
+
state: CircuitState;
|
|
14
|
+
failures: number;
|
|
15
|
+
lastFailureTime: number;
|
|
16
|
+
successCount: number;
|
|
17
|
+
}
|
|
18
|
+
declare function getCircuitBreaker(operationName: string): CircuitBreakerState;
|
|
19
|
+
declare function recordFailure(operationName: string): void;
|
|
20
|
+
declare function recordSuccess(operationName: string): void;
|
|
21
|
+
declare function isCircuitOpen(operationName: string): boolean;
|
|
22
|
+
/**
|
|
23
|
+
* Wrap a Supabase operation with circuit breaker + exponential-backoff retry.
|
|
24
|
+
*
|
|
25
|
+
* Usage:
|
|
26
|
+
* ```ts
|
|
27
|
+
* const data = await withSupabaseResilience(
|
|
28
|
+
* () => supabase.from('documents').select('*'),
|
|
29
|
+
* 'documents.select',
|
|
30
|
+
* )
|
|
31
|
+
* ```
|
|
32
|
+
*/
|
|
33
|
+
export declare function withSupabaseResilience<T>(operation: () => Promise<T>, operationName: string): Promise<T>;
|
|
34
|
+
export declare const __supabaseCircuitBreakers: Map<string, CircuitBreakerState>;
|
|
35
|
+
export declare const __supabaseCircuitBreakerConfig: {
|
|
36
|
+
failureThreshold: number;
|
|
37
|
+
resetTimeout: number;
|
|
38
|
+
successThreshold: number;
|
|
39
|
+
};
|
|
40
|
+
export declare const __supabaseRetryConfig: {
|
|
41
|
+
maxAttempts: number;
|
|
42
|
+
backoff: readonly [100, 200, 400];
|
|
43
|
+
timeout: number;
|
|
44
|
+
};
|
|
45
|
+
export declare const __supabaseGetCircuitBreaker: typeof getCircuitBreaker;
|
|
46
|
+
export declare const __supabaseRecordFailure: typeof recordFailure;
|
|
47
|
+
export declare const __supabaseRecordSuccess: typeof recordSuccess;
|
|
48
|
+
export declare const __supabaseIsCircuitOpen: typeof isCircuitOpen;
|
|
49
|
+
export {};
|
|
50
|
+
//# sourceMappingURL=resilience.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resilience.d.ts","sourceRoot":"","sources":["../../src/supabase/resilience.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAUH,KAAK,YAAY,GAAG,QAAQ,GAAG,MAAM,GAAG,WAAW,CAAA;AAEnD,UAAU,mBAAmB;IAC3B,KAAK,EAAE,YAAY,CAAA;IACnB,QAAQ,EAAE,MAAM,CAAA;IAChB,eAAe,EAAE,MAAM,CAAA;IACvB,YAAY,EAAE,MAAM,CAAA;CACrB;AAwBD,iBAAS,iBAAiB,CAAC,aAAa,EAAE,MAAM,GAAG,mBAAmB,CAWrE;AAED,iBAAS,aAAa,CAAC,aAAa,EAAE,MAAM,GAAG,IAAI,CAelD;AAED,iBAAS,aAAa,CAAC,aAAa,EAAE,MAAM,GAAG,IAAI,CAelD;AAED,iBAAS,aAAa,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO,CAgBrD;AAuBD;;;;;;;;;;GAUG;AACH,wBAAsB,sBAAsB,CAAC,CAAC,EAC5C,SAAS,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EAC3B,aAAa,EAAE,MAAM,GACpB,OAAO,CAAC,CAAC,CAAC,CA0DZ;AAGD,eAAO,MAAM,yBAAyB,kCAAkB,CAAA;AACxD,eAAO,MAAM,8BAA8B;;;;CAAyB,CAAA;AACpE,eAAO,MAAM,qBAAqB;;;;CAAe,CAAA;AACjD,eAAO,MAAM,2BAA2B,0BAAoB,CAAA;AAC5D,eAAO,MAAM,uBAAuB,sBAAgB,CAAA;AACpD,eAAO,MAAM,uBAAuB,sBAAgB,CAAA;AACpD,eAAO,MAAM,uBAAuB,sBAAgB,CAAA"}
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Supabase Resilience Layer
|
|
3
|
+
*
|
|
4
|
+
* Provides circuit breaker + retry protection for Supabase operations,
|
|
5
|
+
* matching the resilience pattern used in packages/services/src/stripe/stripeClient.ts.
|
|
6
|
+
*
|
|
7
|
+
* NOTE: Circuit breaker state is in-memory (per-instance).
|
|
8
|
+
* TODO: For multi-instance deployments, replace with Redis-backed state.
|
|
9
|
+
* Uses createLogger from @revealui/core. Wire up to alerting when circuit opens.
|
|
10
|
+
*/
|
|
11
|
+
import { createLogger } from '@revealui/core/observability/logger';
|
|
12
|
+
const logger = createLogger({ service: 'Supabase' });
|
|
13
|
+
// ---------------------------------------------------------------------------
|
|
14
|
+
// Configuration — mirrors Stripe circuit breaker config for consistency
|
|
15
|
+
// ---------------------------------------------------------------------------
|
|
16
|
+
const CIRCUIT_BREAKER_CONFIG = {
|
|
17
|
+
failureThreshold: 5,
|
|
18
|
+
resetTimeout: 30_000,
|
|
19
|
+
successThreshold: 2,
|
|
20
|
+
};
|
|
21
|
+
const RETRY_CONFIG = {
|
|
22
|
+
maxAttempts: 3,
|
|
23
|
+
backoff: [100, 200, 400],
|
|
24
|
+
timeout: 10_000,
|
|
25
|
+
};
|
|
26
|
+
// ---------------------------------------------------------------------------
|
|
27
|
+
// Circuit breaker state store (in-memory)
|
|
28
|
+
// ---------------------------------------------------------------------------
|
|
29
|
+
const circuitBreakers = new Map();
|
|
30
|
+
function getCircuitBreaker(operationName) {
|
|
31
|
+
if (!circuitBreakers.has(operationName)) {
|
|
32
|
+
circuitBreakers.set(operationName, {
|
|
33
|
+
state: 'closed',
|
|
34
|
+
failures: 0,
|
|
35
|
+
lastFailureTime: 0,
|
|
36
|
+
successCount: 0,
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
// biome-ignore lint/style/noNonNullAssertion: just set above
|
|
40
|
+
return circuitBreakers.get(operationName);
|
|
41
|
+
}
|
|
42
|
+
function recordFailure(operationName) {
|
|
43
|
+
const breaker = getCircuitBreaker(operationName);
|
|
44
|
+
breaker.failures++;
|
|
45
|
+
breaker.lastFailureTime = Date.now();
|
|
46
|
+
if (breaker.failures >= CIRCUIT_BREAKER_CONFIG.failureThreshold) {
|
|
47
|
+
if (breaker.state !== 'open') {
|
|
48
|
+
logger.warn(`Circuit breaker OPENED for Supabase:${operationName}`, {
|
|
49
|
+
failures: breaker.failures,
|
|
50
|
+
threshold: CIRCUIT_BREAKER_CONFIG.failureThreshold,
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
breaker.state = 'open';
|
|
54
|
+
breaker.successCount = 0;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
function recordSuccess(operationName) {
|
|
58
|
+
const breaker = getCircuitBreaker(operationName);
|
|
59
|
+
breaker.failures = 0;
|
|
60
|
+
if (breaker.state === 'half-open') {
|
|
61
|
+
breaker.successCount++;
|
|
62
|
+
if (breaker.successCount >= CIRCUIT_BREAKER_CONFIG.successThreshold) {
|
|
63
|
+
logger.info(`Circuit breaker CLOSED for Supabase:${operationName}`);
|
|
64
|
+
breaker.state = 'closed';
|
|
65
|
+
breaker.successCount = 0;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
else if (breaker.state === 'open') {
|
|
69
|
+
breaker.state = 'closed';
|
|
70
|
+
breaker.successCount = 0;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
function isCircuitOpen(operationName) {
|
|
74
|
+
const breaker = getCircuitBreaker(operationName);
|
|
75
|
+
if (breaker.state === 'closed')
|
|
76
|
+
return false;
|
|
77
|
+
if (breaker.state === 'open') {
|
|
78
|
+
const elapsed = Date.now() - breaker.lastFailureTime;
|
|
79
|
+
if (elapsed >= CIRCUIT_BREAKER_CONFIG.resetTimeout) {
|
|
80
|
+
breaker.state = 'half-open';
|
|
81
|
+
breaker.successCount = 0;
|
|
82
|
+
return false;
|
|
83
|
+
}
|
|
84
|
+
return true;
|
|
85
|
+
}
|
|
86
|
+
return false; // half-open: allow one attempt
|
|
87
|
+
}
|
|
88
|
+
// ---------------------------------------------------------------------------
|
|
89
|
+
// Helpers
|
|
90
|
+
// ---------------------------------------------------------------------------
|
|
91
|
+
function sleep(ms) {
|
|
92
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
93
|
+
}
|
|
94
|
+
function withTimeout(promise, ms) {
|
|
95
|
+
return Promise.race([
|
|
96
|
+
promise,
|
|
97
|
+
new Promise((_, reject) => setTimeout(() => reject(new Error(`Supabase operation timed out after ${ms}ms`)), ms)),
|
|
98
|
+
]);
|
|
99
|
+
}
|
|
100
|
+
// ---------------------------------------------------------------------------
|
|
101
|
+
// Public API
|
|
102
|
+
// ---------------------------------------------------------------------------
|
|
103
|
+
/**
|
|
104
|
+
* Wrap a Supabase operation with circuit breaker + exponential-backoff retry.
|
|
105
|
+
*
|
|
106
|
+
* Usage:
|
|
107
|
+
* ```ts
|
|
108
|
+
* const data = await withSupabaseResilience(
|
|
109
|
+
* () => supabase.from('documents').select('*'),
|
|
110
|
+
* 'documents.select',
|
|
111
|
+
* )
|
|
112
|
+
* ```
|
|
113
|
+
*/
|
|
114
|
+
export async function withSupabaseResilience(operation, operationName) {
|
|
115
|
+
if (isCircuitOpen(operationName)) {
|
|
116
|
+
logger.error(`Circuit breaker OPEN for Supabase:${operationName}`, undefined, {
|
|
117
|
+
operation: operationName,
|
|
118
|
+
state: 'open',
|
|
119
|
+
});
|
|
120
|
+
throw new Error(`Circuit breaker is OPEN for Supabase:${operationName}. Service may be unavailable.`);
|
|
121
|
+
}
|
|
122
|
+
let lastError;
|
|
123
|
+
for (let attempt = 0; attempt < RETRY_CONFIG.maxAttempts; attempt++) {
|
|
124
|
+
try {
|
|
125
|
+
const result = await withTimeout(operation(), RETRY_CONFIG.timeout);
|
|
126
|
+
recordSuccess(operationName);
|
|
127
|
+
return result;
|
|
128
|
+
}
|
|
129
|
+
catch (error) {
|
|
130
|
+
lastError = error;
|
|
131
|
+
const isRetryable = error instanceof Error &&
|
|
132
|
+
(error.message.includes('timeout') ||
|
|
133
|
+
error.message.includes('ECONNREFUSED') ||
|
|
134
|
+
error.message.includes('ETIMEDOUT') ||
|
|
135
|
+
error.message.includes('network') ||
|
|
136
|
+
error.message.includes('fetch failed'));
|
|
137
|
+
if (!isRetryable) {
|
|
138
|
+
recordFailure(operationName);
|
|
139
|
+
logger.error(`Supabase:${operationName} failed (non-retryable)`, error instanceof Error ? error : new Error(String(error)), { attempt: attempt + 1 });
|
|
140
|
+
throw error;
|
|
141
|
+
}
|
|
142
|
+
logger.warn(`Supabase:${operationName} failed (retryable), retrying...`, {
|
|
143
|
+
attempt: attempt + 1,
|
|
144
|
+
maxAttempts: RETRY_CONFIG.maxAttempts,
|
|
145
|
+
error: error instanceof Error ? error.message : String(error),
|
|
146
|
+
});
|
|
147
|
+
if (attempt < RETRY_CONFIG.maxAttempts - 1) {
|
|
148
|
+
const backoffMs = RETRY_CONFIG.backoff[attempt] ?? RETRY_CONFIG.backoff.at(-1) ?? 1000;
|
|
149
|
+
await sleep(backoffMs);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
recordFailure(operationName);
|
|
154
|
+
throw lastError instanceof Error
|
|
155
|
+
? new Error(`Supabase:${operationName} failed after ${RETRY_CONFIG.maxAttempts} attempts: ${lastError.message}`)
|
|
156
|
+
: new Error(`Supabase:${operationName} failed after ${RETRY_CONFIG.maxAttempts} attempts`);
|
|
157
|
+
}
|
|
158
|
+
// Test-only exports
|
|
159
|
+
export const __supabaseCircuitBreakers = circuitBreakers;
|
|
160
|
+
export const __supabaseCircuitBreakerConfig = CIRCUIT_BREAKER_CONFIG;
|
|
161
|
+
export const __supabaseRetryConfig = RETRY_CONFIG;
|
|
162
|
+
export const __supabaseGetCircuitBreaker = getCircuitBreaker;
|
|
163
|
+
export const __supabaseRecordFailure = recordFailure;
|
|
164
|
+
export const __supabaseRecordSuccess = recordSuccess;
|
|
165
|
+
export const __supabaseIsCircuitOpen = isCircuitOpen;
|
|
166
|
+
//# sourceMappingURL=resilience.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resilience.js","sourceRoot":"","sources":["../../src/supabase/resilience.ts"],"names":[],"mappings":"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"}
|