@autumnsgrove/groveengine 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/README.md +163 -0
- package/dist/auth/jwt.d.ts +14 -0
- package/dist/auth/jwt.js +109 -0
- package/dist/auth/session.d.ts +42 -0
- package/dist/auth/session.js +105 -0
- package/dist/components/admin/GutterManager.svelte +910 -0
- package/dist/components/admin/GutterManager.svelte.d.ts +15 -0
- package/dist/components/admin/MarkdownEditor.svelte +3114 -0
- package/dist/components/admin/MarkdownEditor.svelte.d.ts +43 -0
- package/dist/components/custom/CollapsibleSection.svelte +74 -0
- package/dist/components/custom/CollapsibleSection.svelte.d.ts +15 -0
- package/dist/components/custom/ContentWithGutter.svelte +646 -0
- package/dist/components/custom/ContentWithGutter.svelte.d.ts +19 -0
- package/dist/components/custom/GutterItem.svelte +201 -0
- package/dist/components/custom/GutterItem.svelte.d.ts +11 -0
- package/dist/components/custom/LeftGutter.svelte +271 -0
- package/dist/components/custom/LeftGutter.svelte.d.ts +17 -0
- package/dist/components/custom/MobileTOC.svelte +273 -0
- package/dist/components/custom/MobileTOC.svelte.d.ts +11 -0
- package/dist/components/custom/TableOfContents.svelte +163 -0
- package/dist/components/custom/TableOfContents.svelte.d.ts +11 -0
- package/dist/components/gallery/ImageGallery.svelte +681 -0
- package/dist/components/gallery/ImageGallery.svelte.d.ts +11 -0
- package/dist/components/gallery/Lightbox.svelte +107 -0
- package/dist/components/gallery/Lightbox.svelte.d.ts +19 -0
- package/dist/components/gallery/LightboxCaption.svelte +25 -0
- package/dist/components/gallery/LightboxCaption.svelte.d.ts +11 -0
- package/dist/components/gallery/ZoomableImage.svelte +163 -0
- package/dist/components/gallery/ZoomableImage.svelte.d.ts +17 -0
- package/dist/components/ui/Accordion.svelte +74 -0
- package/dist/components/ui/Accordion.svelte.d.ts +42 -0
- package/dist/components/ui/Badge.svelte +48 -0
- package/dist/components/ui/Badge.svelte.d.ts +26 -0
- package/dist/components/ui/Button.svelte +74 -0
- package/dist/components/ui/Button.svelte.d.ts +34 -0
- package/dist/components/ui/Card.svelte +102 -0
- package/dist/components/ui/Card.svelte.d.ts +46 -0
- package/dist/components/ui/Dialog.svelte +91 -0
- package/dist/components/ui/Dialog.svelte.d.ts +43 -0
- package/dist/components/ui/Input.svelte +81 -0
- package/dist/components/ui/Input.svelte.d.ts +35 -0
- package/dist/components/ui/Select.svelte +69 -0
- package/dist/components/ui/Select.svelte.d.ts +36 -0
- package/dist/components/ui/Sheet.svelte +98 -0
- package/dist/components/ui/Sheet.svelte.d.ts +45 -0
- package/dist/components/ui/Skeleton.svelte +31 -0
- package/dist/components/ui/Skeleton.svelte.d.ts +26 -0
- package/dist/components/ui/Table.svelte +59 -0
- package/dist/components/ui/Table.svelte.d.ts +44 -0
- package/dist/components/ui/Tabs.svelte +76 -0
- package/dist/components/ui/Tabs.svelte.d.ts +41 -0
- package/dist/components/ui/Textarea.svelte +81 -0
- package/dist/components/ui/Textarea.svelte.d.ts +35 -0
- package/dist/components/ui/Toast.svelte +18 -0
- package/dist/components/ui/Toast.svelte.d.ts +7 -0
- package/dist/components/ui/accordion/accordion-content.svelte +24 -0
- package/dist/components/ui/accordion/accordion-content.svelte.d.ts +4 -0
- package/dist/components/ui/accordion/accordion-item.svelte +12 -0
- package/dist/components/ui/accordion/accordion-item.svelte.d.ts +4 -0
- package/dist/components/ui/accordion/accordion-trigger.svelte +29 -0
- package/dist/components/ui/accordion/accordion-trigger.svelte.d.ts +7 -0
- package/dist/components/ui/accordion/index.d.ts +6 -0
- package/dist/components/ui/accordion/index.js +8 -0
- package/dist/components/ui/badge/badge.svelte +50 -0
- package/dist/components/ui/badge/badge.svelte.d.ts +60 -0
- package/dist/components/ui/badge/index.d.ts +2 -0
- package/dist/components/ui/badge/index.js +2 -0
- package/dist/components/ui/button/button.svelte +82 -0
- package/dist/components/ui/button/button.svelte.d.ts +132 -0
- package/dist/components/ui/button/index.d.ts +2 -0
- package/dist/components/ui/button/index.js +4 -0
- package/dist/components/ui/card/card-content.svelte +16 -0
- package/dist/components/ui/card/card-content.svelte.d.ts +5 -0
- package/dist/components/ui/card/card-description.svelte +16 -0
- package/dist/components/ui/card/card-description.svelte.d.ts +5 -0
- package/dist/components/ui/card/card-footer.svelte +16 -0
- package/dist/components/ui/card/card-footer.svelte.d.ts +5 -0
- package/dist/components/ui/card/card-header.svelte +16 -0
- package/dist/components/ui/card/card-header.svelte.d.ts +5 -0
- package/dist/components/ui/card/card-title.svelte +25 -0
- package/dist/components/ui/card/card-title.svelte.d.ts +8 -0
- package/dist/components/ui/card/card.svelte +20 -0
- package/dist/components/ui/card/card.svelte.d.ts +5 -0
- package/dist/components/ui/card/index.d.ts +7 -0
- package/dist/components/ui/card/index.js +9 -0
- package/dist/components/ui/dialog/dialog-content.svelte +38 -0
- package/dist/components/ui/dialog/dialog-content.svelte.d.ts +9 -0
- package/dist/components/ui/dialog/dialog-description.svelte +16 -0
- package/dist/components/ui/dialog/dialog-description.svelte.d.ts +4 -0
- package/dist/components/ui/dialog/dialog-footer.svelte +20 -0
- package/dist/components/ui/dialog/dialog-footer.svelte.d.ts +5 -0
- package/dist/components/ui/dialog/dialog-header.svelte +20 -0
- package/dist/components/ui/dialog/dialog-header.svelte.d.ts +5 -0
- package/dist/components/ui/dialog/dialog-overlay.svelte +19 -0
- package/dist/components/ui/dialog/dialog-overlay.svelte.d.ts +4 -0
- package/dist/components/ui/dialog/dialog-title.svelte +16 -0
- package/dist/components/ui/dialog/dialog-title.svelte.d.ts +4 -0
- package/dist/components/ui/dialog/index.d.ts +12 -0
- package/dist/components/ui/dialog/index.js +14 -0
- package/dist/components/ui/index.d.ts +26 -0
- package/dist/components/ui/index.js +29 -0
- package/dist/components/ui/input/index.d.ts +2 -0
- package/dist/components/ui/input/index.js +4 -0
- package/dist/components/ui/input/input.svelte +46 -0
- package/dist/components/ui/input/input.svelte.d.ts +13 -0
- package/dist/components/ui/select/index.d.ts +11 -0
- package/dist/components/ui/select/index.js +13 -0
- package/dist/components/ui/select/select-content.svelte +39 -0
- package/dist/components/ui/select/select-content.svelte.d.ts +7 -0
- package/dist/components/ui/select/select-group-heading.svelte +16 -0
- package/dist/components/ui/select/select-group-heading.svelte.d.ts +4 -0
- package/dist/components/ui/select/select-item.svelte +37 -0
- package/dist/components/ui/select/select-item.svelte.d.ts +4 -0
- package/dist/components/ui/select/select-scroll-down-button.svelte +19 -0
- package/dist/components/ui/select/select-scroll-down-button.svelte.d.ts +4 -0
- package/dist/components/ui/select/select-scroll-up-button.svelte +19 -0
- package/dist/components/ui/select/select-scroll-up-button.svelte.d.ts +4 -0
- package/dist/components/ui/select/select-separator.svelte +13 -0
- package/dist/components/ui/select/select-separator.svelte.d.ts +4 -0
- package/dist/components/ui/select/select-trigger.svelte +24 -0
- package/dist/components/ui/select/select-trigger.svelte.d.ts +4 -0
- package/dist/components/ui/separator/index.d.ts +2 -0
- package/dist/components/ui/separator/index.js +4 -0
- package/dist/components/ui/separator/separator.svelte +22 -0
- package/dist/components/ui/separator/separator.svelte.d.ts +4 -0
- package/dist/components/ui/sheet/index.d.ts +12 -0
- package/dist/components/ui/sheet/index.js +14 -0
- package/dist/components/ui/sheet/sheet-content.svelte +53 -0
- package/dist/components/ui/sheet/sheet-content.svelte.d.ts +62 -0
- package/dist/components/ui/sheet/sheet-description.svelte +16 -0
- package/dist/components/ui/sheet/sheet-description.svelte.d.ts +4 -0
- package/dist/components/ui/sheet/sheet-footer.svelte +20 -0
- package/dist/components/ui/sheet/sheet-footer.svelte.d.ts +5 -0
- package/dist/components/ui/sheet/sheet-header.svelte +20 -0
- package/dist/components/ui/sheet/sheet-header.svelte.d.ts +5 -0
- package/dist/components/ui/sheet/sheet-overlay.svelte +21 -0
- package/dist/components/ui/sheet/sheet-overlay.svelte.d.ts +6 -0
- package/dist/components/ui/sheet/sheet-title.svelte +16 -0
- package/dist/components/ui/sheet/sheet-title.svelte.d.ts +4 -0
- package/dist/components/ui/skeleton/index.d.ts +2 -0
- package/dist/components/ui/skeleton/index.js +4 -0
- package/dist/components/ui/skeleton/skeleton.svelte +17 -0
- package/dist/components/ui/skeleton/skeleton.svelte.d.ts +5 -0
- package/dist/components/ui/table/index.d.ts +9 -0
- package/dist/components/ui/table/index.js +11 -0
- package/dist/components/ui/table/table-body.svelte +16 -0
- package/dist/components/ui/table/table-body.svelte.d.ts +5 -0
- package/dist/components/ui/table/table-caption.svelte +16 -0
- package/dist/components/ui/table/table-caption.svelte.d.ts +5 -0
- package/dist/components/ui/table/table-cell.svelte +20 -0
- package/dist/components/ui/table/table-cell.svelte.d.ts +5 -0
- package/dist/components/ui/table/table-footer.svelte +16 -0
- package/dist/components/ui/table/table-footer.svelte.d.ts +5 -0
- package/dist/components/ui/table/table-head.svelte +23 -0
- package/dist/components/ui/table/table-head.svelte.d.ts +5 -0
- package/dist/components/ui/table/table-header.svelte +16 -0
- package/dist/components/ui/table/table-header.svelte.d.ts +5 -0
- package/dist/components/ui/table/table-row.svelte +23 -0
- package/dist/components/ui/table/table-row.svelte.d.ts +5 -0
- package/dist/components/ui/table/table.svelte +18 -0
- package/dist/components/ui/table/table.svelte.d.ts +5 -0
- package/dist/components/ui/tabs/index.d.ts +6 -0
- package/dist/components/ui/tabs/index.js +8 -0
- package/dist/components/ui/tabs/tabs-content.svelte +19 -0
- package/dist/components/ui/tabs/tabs-content.svelte.d.ts +4 -0
- package/dist/components/ui/tabs/tabs-list.svelte +19 -0
- package/dist/components/ui/tabs/tabs-list.svelte.d.ts +4 -0
- package/dist/components/ui/tabs/tabs-trigger.svelte +19 -0
- package/dist/components/ui/tabs/tabs-trigger.svelte.d.ts +4 -0
- package/dist/components/ui/textarea/index.d.ts +2 -0
- package/dist/components/ui/textarea/index.js +4 -0
- package/dist/components/ui/textarea/textarea.svelte +24 -0
- package/dist/components/ui/textarea/textarea.svelte.d.ts +6 -0
- package/dist/components/ui/toast.d.ts +86 -0
- package/dist/components/ui/toast.js +99 -0
- package/dist/db/schema.sql +238 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.js +20 -0
- package/dist/payments/index.d.ts +33 -0
- package/dist/payments/index.js +47 -0
- package/dist/payments/shop.d.ts +165 -0
- package/dist/payments/shop.js +588 -0
- package/dist/payments/stripe/client.d.ts +231 -0
- package/dist/payments/stripe/client.js +198 -0
- package/dist/payments/stripe/index.d.ts +18 -0
- package/dist/payments/stripe/index.js +17 -0
- package/dist/payments/stripe/provider.d.ts +50 -0
- package/dist/payments/stripe/provider.js +530 -0
- package/dist/payments/types.d.ts +355 -0
- package/dist/payments/types.js +7 -0
- package/dist/server/logger.d.ts +53 -0
- package/dist/server/logger.js +252 -0
- package/dist/styles/content.css +514 -0
- package/dist/styles/tokens.css +175 -0
- package/dist/utils/api.d.ts +20 -0
- package/dist/utils/api.js +109 -0
- package/dist/utils/cn.d.ts +15 -0
- package/dist/utils/cn.js +18 -0
- package/dist/utils/csrf.d.ts +22 -0
- package/dist/utils/csrf.js +72 -0
- package/dist/utils/debounce.d.ts +7 -0
- package/dist/utils/debounce.js +14 -0
- package/dist/utils/gallery.d.ts +66 -0
- package/dist/utils/gallery.js +181 -0
- package/dist/utils/gutter.d.ts +54 -0
- package/dist/utils/gutter.js +169 -0
- package/dist/utils/imageProcessor.d.ts +58 -0
- package/dist/utils/imageProcessor.js +205 -0
- package/dist/utils/json.d.ts +17 -0
- package/dist/utils/json.js +26 -0
- package/dist/utils/markdown.d.ts +101 -0
- package/dist/utils/markdown.js +947 -0
- package/dist/utils/sanitize.d.ts +25 -0
- package/dist/utils/sanitize.js +127 -0
- package/dist/utils/validation.d.ts +46 -0
- package/dist/utils/validation.js +169 -0
- package/dist/utils.d.ts +5 -0
- package/dist/utils.js +5 -0
- package/package.json +129 -0
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Stripe API Client for Cloudflare Workers
|
|
3
|
+
*
|
|
4
|
+
* A lightweight, fetch-based Stripe client that works in edge environments.
|
|
5
|
+
* Does not depend on the Node.js Stripe SDK.
|
|
6
|
+
*/
|
|
7
|
+
export interface StripeClientConfig {
|
|
8
|
+
secretKey: string;
|
|
9
|
+
apiVersion?: string;
|
|
10
|
+
}
|
|
11
|
+
export interface StripeRequestOptions {
|
|
12
|
+
method?: 'GET' | 'POST' | 'DELETE';
|
|
13
|
+
params?: Record<string, unknown>;
|
|
14
|
+
idempotencyKey?: string;
|
|
15
|
+
stripeAccount?: string;
|
|
16
|
+
}
|
|
17
|
+
export interface StripeError {
|
|
18
|
+
type: string;
|
|
19
|
+
code?: string;
|
|
20
|
+
message: string;
|
|
21
|
+
param?: string;
|
|
22
|
+
decline_code?: string;
|
|
23
|
+
}
|
|
24
|
+
export declare class StripeAPIError extends Error {
|
|
25
|
+
readonly type: string;
|
|
26
|
+
readonly code?: string;
|
|
27
|
+
readonly param?: string;
|
|
28
|
+
readonly statusCode: number;
|
|
29
|
+
constructor(error: StripeError, statusCode: number);
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Stripe API Client
|
|
33
|
+
*
|
|
34
|
+
* Usage:
|
|
35
|
+
* ```ts
|
|
36
|
+
* const stripe = new StripeClient({ secretKey: 'sk_test_...' });
|
|
37
|
+
* const session = await stripe.request('checkout/sessions', {
|
|
38
|
+
* method: 'POST',
|
|
39
|
+
* params: { mode: 'payment', ... }
|
|
40
|
+
* });
|
|
41
|
+
* ```
|
|
42
|
+
*/
|
|
43
|
+
export declare class StripeClient {
|
|
44
|
+
private readonly secretKey;
|
|
45
|
+
private readonly apiVersion;
|
|
46
|
+
constructor(config: StripeClientConfig);
|
|
47
|
+
/**
|
|
48
|
+
* Make a request to the Stripe API
|
|
49
|
+
*/
|
|
50
|
+
request<T>(endpoint: string, options?: StripeRequestOptions): Promise<T>;
|
|
51
|
+
/**
|
|
52
|
+
* Encode parameters for application/x-www-form-urlencoded
|
|
53
|
+
* Handles nested objects and arrays
|
|
54
|
+
*/
|
|
55
|
+
private encodeParams;
|
|
56
|
+
/**
|
|
57
|
+
* Append params to URLSearchParams for GET requests
|
|
58
|
+
*/
|
|
59
|
+
private appendSearchParams;
|
|
60
|
+
/**
|
|
61
|
+
* Verify a webhook signature
|
|
62
|
+
*
|
|
63
|
+
* @param payload - Raw request body as string
|
|
64
|
+
* @param signature - Stripe-Signature header value
|
|
65
|
+
* @param secret - Webhook signing secret
|
|
66
|
+
* @param tolerance - Max age of event in seconds (default 300)
|
|
67
|
+
*/
|
|
68
|
+
verifyWebhookSignature(payload: string, signature: string, secret: string, tolerance?: number): Promise<{
|
|
69
|
+
valid: boolean;
|
|
70
|
+
event?: unknown;
|
|
71
|
+
error?: string;
|
|
72
|
+
}>;
|
|
73
|
+
/**
|
|
74
|
+
* Constant-time string comparison to prevent timing attacks
|
|
75
|
+
*/
|
|
76
|
+
private secureCompare;
|
|
77
|
+
}
|
|
78
|
+
export interface StripeProduct {
|
|
79
|
+
id: string;
|
|
80
|
+
object: 'product';
|
|
81
|
+
active: boolean;
|
|
82
|
+
name: string;
|
|
83
|
+
description?: string;
|
|
84
|
+
images: string[];
|
|
85
|
+
metadata: Record<string, string>;
|
|
86
|
+
default_price?: string;
|
|
87
|
+
created: number;
|
|
88
|
+
updated: number;
|
|
89
|
+
}
|
|
90
|
+
export interface StripePrice {
|
|
91
|
+
id: string;
|
|
92
|
+
object: 'price';
|
|
93
|
+
active: boolean;
|
|
94
|
+
product: string;
|
|
95
|
+
currency: string;
|
|
96
|
+
unit_amount: number;
|
|
97
|
+
type: 'one_time' | 'recurring';
|
|
98
|
+
recurring?: {
|
|
99
|
+
interval: 'day' | 'week' | 'month' | 'year';
|
|
100
|
+
interval_count: number;
|
|
101
|
+
};
|
|
102
|
+
metadata: Record<string, string>;
|
|
103
|
+
created: number;
|
|
104
|
+
}
|
|
105
|
+
export interface StripeCheckoutSession {
|
|
106
|
+
id: string;
|
|
107
|
+
object: 'checkout.session';
|
|
108
|
+
url: string;
|
|
109
|
+
status: 'open' | 'complete' | 'expired';
|
|
110
|
+
mode: 'payment' | 'subscription' | 'setup';
|
|
111
|
+
customer?: string;
|
|
112
|
+
customer_email?: string;
|
|
113
|
+
amount_total: number;
|
|
114
|
+
currency: string;
|
|
115
|
+
payment_status: 'unpaid' | 'paid' | 'no_payment_required';
|
|
116
|
+
payment_intent?: string;
|
|
117
|
+
subscription?: string;
|
|
118
|
+
metadata: Record<string, string>;
|
|
119
|
+
expires_at: number;
|
|
120
|
+
client_reference_id?: string;
|
|
121
|
+
}
|
|
122
|
+
export interface StripeCustomer {
|
|
123
|
+
id: string;
|
|
124
|
+
object: 'customer';
|
|
125
|
+
email?: string;
|
|
126
|
+
name?: string;
|
|
127
|
+
phone?: string;
|
|
128
|
+
address?: StripeAddress;
|
|
129
|
+
metadata: Record<string, string>;
|
|
130
|
+
created: number;
|
|
131
|
+
}
|
|
132
|
+
export interface StripeAddress {
|
|
133
|
+
line1?: string;
|
|
134
|
+
line2?: string;
|
|
135
|
+
city?: string;
|
|
136
|
+
state?: string;
|
|
137
|
+
postal_code?: string;
|
|
138
|
+
country?: string;
|
|
139
|
+
}
|
|
140
|
+
export interface StripePaymentIntent {
|
|
141
|
+
id: string;
|
|
142
|
+
object: 'payment_intent';
|
|
143
|
+
amount: number;
|
|
144
|
+
currency: string;
|
|
145
|
+
status: 'requires_payment_method' | 'requires_confirmation' | 'requires_action' | 'processing' | 'requires_capture' | 'canceled' | 'succeeded';
|
|
146
|
+
customer?: string;
|
|
147
|
+
metadata: Record<string, string>;
|
|
148
|
+
latest_charge?: string;
|
|
149
|
+
created: number;
|
|
150
|
+
}
|
|
151
|
+
export interface StripeSubscription {
|
|
152
|
+
id: string;
|
|
153
|
+
object: 'subscription';
|
|
154
|
+
status: 'incomplete' | 'incomplete_expired' | 'trialing' | 'active' | 'past_due' | 'canceled' | 'unpaid' | 'paused';
|
|
155
|
+
customer: string;
|
|
156
|
+
items: {
|
|
157
|
+
data: Array<{
|
|
158
|
+
id: string;
|
|
159
|
+
price: StripePrice;
|
|
160
|
+
quantity: number;
|
|
161
|
+
}>;
|
|
162
|
+
};
|
|
163
|
+
current_period_start: number;
|
|
164
|
+
current_period_end: number;
|
|
165
|
+
cancel_at_period_end: boolean;
|
|
166
|
+
canceled_at?: number;
|
|
167
|
+
trial_start?: number;
|
|
168
|
+
trial_end?: number;
|
|
169
|
+
metadata: Record<string, string>;
|
|
170
|
+
created: number;
|
|
171
|
+
}
|
|
172
|
+
export interface StripeRefund {
|
|
173
|
+
id: string;
|
|
174
|
+
object: 'refund';
|
|
175
|
+
amount: number;
|
|
176
|
+
currency: string;
|
|
177
|
+
status: 'pending' | 'succeeded' | 'failed' | 'canceled';
|
|
178
|
+
payment_intent?: string;
|
|
179
|
+
reason?: 'duplicate' | 'fraudulent' | 'requested_by_customer';
|
|
180
|
+
metadata: Record<string, string>;
|
|
181
|
+
created: number;
|
|
182
|
+
}
|
|
183
|
+
export interface StripeAccount {
|
|
184
|
+
id: string;
|
|
185
|
+
object: 'account';
|
|
186
|
+
type: 'standard' | 'express' | 'custom';
|
|
187
|
+
email?: string;
|
|
188
|
+
country?: string;
|
|
189
|
+
default_currency?: string;
|
|
190
|
+
charges_enabled: boolean;
|
|
191
|
+
payouts_enabled: boolean;
|
|
192
|
+
details_submitted: boolean;
|
|
193
|
+
capabilities?: Record<string, 'active' | 'inactive' | 'pending'>;
|
|
194
|
+
requirements?: {
|
|
195
|
+
currently_due: string[];
|
|
196
|
+
eventually_due: string[];
|
|
197
|
+
past_due: string[];
|
|
198
|
+
};
|
|
199
|
+
created: number;
|
|
200
|
+
}
|
|
201
|
+
export interface StripeAccountLink {
|
|
202
|
+
object: 'account_link';
|
|
203
|
+
url: string;
|
|
204
|
+
expires_at: number;
|
|
205
|
+
created: number;
|
|
206
|
+
}
|
|
207
|
+
export interface StripeLoginLink {
|
|
208
|
+
object: 'login_link';
|
|
209
|
+
url: string;
|
|
210
|
+
created: number;
|
|
211
|
+
}
|
|
212
|
+
export interface StripeBillingPortalSession {
|
|
213
|
+
id: string;
|
|
214
|
+
object: 'billing_portal.session';
|
|
215
|
+
url: string;
|
|
216
|
+
customer: string;
|
|
217
|
+
return_url: string;
|
|
218
|
+
created: number;
|
|
219
|
+
}
|
|
220
|
+
export interface StripeEvent {
|
|
221
|
+
id: string;
|
|
222
|
+
object: 'event';
|
|
223
|
+
type: string;
|
|
224
|
+
data: {
|
|
225
|
+
object: unknown;
|
|
226
|
+
previous_attributes?: Record<string, unknown>;
|
|
227
|
+
};
|
|
228
|
+
account?: string;
|
|
229
|
+
created: number;
|
|
230
|
+
livemode: boolean;
|
|
231
|
+
}
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Stripe API Client for Cloudflare Workers
|
|
3
|
+
*
|
|
4
|
+
* A lightweight, fetch-based Stripe client that works in edge environments.
|
|
5
|
+
* Does not depend on the Node.js Stripe SDK.
|
|
6
|
+
*/
|
|
7
|
+
const STRIPE_API_VERSION = '2024-11-20.acacia';
|
|
8
|
+
const STRIPE_API_BASE = 'https://api.stripe.com/v1';
|
|
9
|
+
export class StripeAPIError extends Error {
|
|
10
|
+
type;
|
|
11
|
+
code;
|
|
12
|
+
param;
|
|
13
|
+
statusCode;
|
|
14
|
+
constructor(error, statusCode) {
|
|
15
|
+
super(error.message);
|
|
16
|
+
this.name = 'StripeAPIError';
|
|
17
|
+
this.type = error.type;
|
|
18
|
+
this.code = error.code;
|
|
19
|
+
this.param = error.param;
|
|
20
|
+
this.statusCode = statusCode;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Stripe API Client
|
|
25
|
+
*
|
|
26
|
+
* Usage:
|
|
27
|
+
* ```ts
|
|
28
|
+
* const stripe = new StripeClient({ secretKey: 'sk_test_...' });
|
|
29
|
+
* const session = await stripe.request('checkout/sessions', {
|
|
30
|
+
* method: 'POST',
|
|
31
|
+
* params: { mode: 'payment', ... }
|
|
32
|
+
* });
|
|
33
|
+
* ```
|
|
34
|
+
*/
|
|
35
|
+
export class StripeClient {
|
|
36
|
+
secretKey;
|
|
37
|
+
apiVersion;
|
|
38
|
+
constructor(config) {
|
|
39
|
+
this.secretKey = config.secretKey;
|
|
40
|
+
this.apiVersion = config.apiVersion || STRIPE_API_VERSION;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Make a request to the Stripe API
|
|
44
|
+
*/
|
|
45
|
+
async request(endpoint, options = {}) {
|
|
46
|
+
const { method = 'GET', params, idempotencyKey, stripeAccount } = options;
|
|
47
|
+
const url = new URL(`${STRIPE_API_BASE}/${endpoint}`);
|
|
48
|
+
// For GET requests, append params as query string
|
|
49
|
+
if (method === 'GET' && params) {
|
|
50
|
+
this.appendSearchParams(url.searchParams, params);
|
|
51
|
+
}
|
|
52
|
+
const headers = {
|
|
53
|
+
'Authorization': `Bearer ${this.secretKey}`,
|
|
54
|
+
'Stripe-Version': this.apiVersion,
|
|
55
|
+
};
|
|
56
|
+
// For POST requests, encode params as form data
|
|
57
|
+
let body;
|
|
58
|
+
if (method === 'POST' && params) {
|
|
59
|
+
headers['Content-Type'] = 'application/x-www-form-urlencoded';
|
|
60
|
+
body = this.encodeParams(params);
|
|
61
|
+
}
|
|
62
|
+
// Idempotency key for POST requests
|
|
63
|
+
if (idempotencyKey) {
|
|
64
|
+
headers['Idempotency-Key'] = idempotencyKey;
|
|
65
|
+
}
|
|
66
|
+
// Stripe Connect: make request on behalf of connected account
|
|
67
|
+
if (stripeAccount) {
|
|
68
|
+
headers['Stripe-Account'] = stripeAccount;
|
|
69
|
+
}
|
|
70
|
+
const response = await fetch(url.toString(), {
|
|
71
|
+
method,
|
|
72
|
+
headers,
|
|
73
|
+
body,
|
|
74
|
+
});
|
|
75
|
+
const data = await response.json();
|
|
76
|
+
if (!response.ok) {
|
|
77
|
+
throw new StripeAPIError(data.error || { type: 'api_error', message: 'Unknown error' }, response.status);
|
|
78
|
+
}
|
|
79
|
+
return data;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Encode parameters for application/x-www-form-urlencoded
|
|
83
|
+
* Handles nested objects and arrays
|
|
84
|
+
*/
|
|
85
|
+
encodeParams(params, prefix = '') {
|
|
86
|
+
const parts = [];
|
|
87
|
+
for (const [key, value] of Object.entries(params)) {
|
|
88
|
+
if (value === undefined || value === null)
|
|
89
|
+
continue;
|
|
90
|
+
const fullKey = prefix ? `${prefix}[${key}]` : key;
|
|
91
|
+
if (Array.isArray(value)) {
|
|
92
|
+
value.forEach((item, index) => {
|
|
93
|
+
if (typeof item === 'object' && item !== null) {
|
|
94
|
+
parts.push(this.encodeParams(item, `${fullKey}[${index}]`));
|
|
95
|
+
}
|
|
96
|
+
else {
|
|
97
|
+
parts.push(`${encodeURIComponent(`${fullKey}[${index}]`)}=${encodeURIComponent(String(item))}`);
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
else if (typeof value === 'object') {
|
|
102
|
+
parts.push(this.encodeParams(value, fullKey));
|
|
103
|
+
}
|
|
104
|
+
else {
|
|
105
|
+
parts.push(`${encodeURIComponent(fullKey)}=${encodeURIComponent(String(value))}`);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
return parts.filter(Boolean).join('&');
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Append params to URLSearchParams for GET requests
|
|
112
|
+
*/
|
|
113
|
+
appendSearchParams(searchParams, params, prefix = '') {
|
|
114
|
+
for (const [key, value] of Object.entries(params)) {
|
|
115
|
+
if (value === undefined || value === null)
|
|
116
|
+
continue;
|
|
117
|
+
const fullKey = prefix ? `${prefix}[${key}]` : key;
|
|
118
|
+
if (Array.isArray(value)) {
|
|
119
|
+
value.forEach((item, index) => {
|
|
120
|
+
if (typeof item === 'object' && item !== null) {
|
|
121
|
+
this.appendSearchParams(searchParams, item, `${fullKey}[${index}]`);
|
|
122
|
+
}
|
|
123
|
+
else {
|
|
124
|
+
searchParams.append(`${fullKey}[${index}]`, String(item));
|
|
125
|
+
}
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
else if (typeof value === 'object') {
|
|
129
|
+
this.appendSearchParams(searchParams, value, fullKey);
|
|
130
|
+
}
|
|
131
|
+
else {
|
|
132
|
+
searchParams.append(fullKey, String(value));
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Verify a webhook signature
|
|
138
|
+
*
|
|
139
|
+
* @param payload - Raw request body as string
|
|
140
|
+
* @param signature - Stripe-Signature header value
|
|
141
|
+
* @param secret - Webhook signing secret
|
|
142
|
+
* @param tolerance - Max age of event in seconds (default 300)
|
|
143
|
+
*/
|
|
144
|
+
async verifyWebhookSignature(payload, signature, secret, tolerance = 300) {
|
|
145
|
+
try {
|
|
146
|
+
// Parse the signature header
|
|
147
|
+
const parts = signature.split(',').reduce((acc, part) => {
|
|
148
|
+
const [key, value] = part.split('=');
|
|
149
|
+
if (key && value) {
|
|
150
|
+
acc[key] = value;
|
|
151
|
+
}
|
|
152
|
+
return acc;
|
|
153
|
+
}, {});
|
|
154
|
+
const timestamp = parts['t'];
|
|
155
|
+
const v1Signature = parts['v1'];
|
|
156
|
+
if (!timestamp || !v1Signature) {
|
|
157
|
+
return { valid: false, error: 'Invalid signature format' };
|
|
158
|
+
}
|
|
159
|
+
// Check timestamp tolerance
|
|
160
|
+
const timestampSeconds = parseInt(timestamp, 10);
|
|
161
|
+
const now = Math.floor(Date.now() / 1000);
|
|
162
|
+
if (now - timestampSeconds > tolerance) {
|
|
163
|
+
return { valid: false, error: 'Webhook timestamp too old' };
|
|
164
|
+
}
|
|
165
|
+
// Compute expected signature
|
|
166
|
+
const signedPayload = `${timestamp}.${payload}`;
|
|
167
|
+
const encoder = new TextEncoder();
|
|
168
|
+
const key = await crypto.subtle.importKey('raw', encoder.encode(secret), { name: 'HMAC', hash: 'SHA-256' }, false, ['sign']);
|
|
169
|
+
const signatureBytes = await crypto.subtle.sign('HMAC', key, encoder.encode(signedPayload));
|
|
170
|
+
const expectedSignature = Array.from(new Uint8Array(signatureBytes))
|
|
171
|
+
.map(b => b.toString(16).padStart(2, '0'))
|
|
172
|
+
.join('');
|
|
173
|
+
// Constant-time comparison
|
|
174
|
+
if (!this.secureCompare(expectedSignature, v1Signature)) {
|
|
175
|
+
return { valid: false, error: 'Signature mismatch' };
|
|
176
|
+
}
|
|
177
|
+
// Parse and return the event
|
|
178
|
+
const event = JSON.parse(payload);
|
|
179
|
+
return { valid: true, event };
|
|
180
|
+
}
|
|
181
|
+
catch (err) {
|
|
182
|
+
return { valid: false, error: `Verification failed: ${err}` };
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* Constant-time string comparison to prevent timing attacks
|
|
187
|
+
*/
|
|
188
|
+
secureCompare(a, b) {
|
|
189
|
+
if (a.length !== b.length) {
|
|
190
|
+
return false;
|
|
191
|
+
}
|
|
192
|
+
let result = 0;
|
|
193
|
+
for (let i = 0; i < a.length; i++) {
|
|
194
|
+
result |= a.charCodeAt(i) ^ b.charCodeAt(i);
|
|
195
|
+
}
|
|
196
|
+
return result === 0;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Stripe Payment Provider
|
|
3
|
+
*
|
|
4
|
+
* @example
|
|
5
|
+
* ```ts
|
|
6
|
+
* import { createStripeProvider } from './';
|
|
7
|
+
*
|
|
8
|
+
* const stripe = createStripeProvider({
|
|
9
|
+
* secretKey: platform.env.STRIPE_SECRET_KEY,
|
|
10
|
+
* webhookSecret: platform.env.STRIPE_WEBHOOK_SECRET,
|
|
11
|
+
* });
|
|
12
|
+
*
|
|
13
|
+
* const session = await stripe.createCheckoutSession(items, options, resolveVariant);
|
|
14
|
+
* ```
|
|
15
|
+
*/
|
|
16
|
+
export { StripeClient, StripeAPIError } from './client.js';
|
|
17
|
+
export { StripeProvider, createStripeProvider } from './provider.js';
|
|
18
|
+
export type { StripeClientConfig, StripeRequestOptions, StripeError, StripeProduct, StripePrice, StripeCheckoutSession, StripeCustomer, StripeAddress, StripePaymentIntent, StripeSubscription, StripeRefund, StripeAccount, StripeAccountLink, StripeLoginLink, StripeBillingPortalSession, StripeEvent, } from './client.js';
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Stripe Payment Provider
|
|
3
|
+
*
|
|
4
|
+
* @example
|
|
5
|
+
* ```ts
|
|
6
|
+
* import { createStripeProvider } from './';
|
|
7
|
+
*
|
|
8
|
+
* const stripe = createStripeProvider({
|
|
9
|
+
* secretKey: platform.env.STRIPE_SECRET_KEY,
|
|
10
|
+
* webhookSecret: platform.env.STRIPE_WEBHOOK_SECRET,
|
|
11
|
+
* });
|
|
12
|
+
*
|
|
13
|
+
* const session = await stripe.createCheckoutSession(items, options, resolveVariant);
|
|
14
|
+
* ```
|
|
15
|
+
*/
|
|
16
|
+
export { StripeClient, StripeAPIError } from './client.js';
|
|
17
|
+
export { StripeProvider, createStripeProvider } from './provider.js';
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Stripe Payment Provider Implementation
|
|
3
|
+
*
|
|
4
|
+
* Implements the PaymentProvider interface using Stripe's API.
|
|
5
|
+
* Supports Stripe Connect for marketplace functionality.
|
|
6
|
+
*/
|
|
7
|
+
import type { PaymentProvider, PaymentProviderConfig, ProductBase, ProductVariant, CartItem, CheckoutOptions, CheckoutSession, PaymentStatus, RefundRequest, RefundResult, Subscription, Customer, WebhookResult, ConnectAccount, ConnectOnboardingOptions, ConnectOnboardingResult } from '../types.js';
|
|
8
|
+
export declare class StripeProvider implements PaymentProvider {
|
|
9
|
+
readonly name = "stripe";
|
|
10
|
+
private readonly client;
|
|
11
|
+
private readonly webhookSecret?;
|
|
12
|
+
private readonly connectWebhookSecret?;
|
|
13
|
+
constructor(config: PaymentProviderConfig);
|
|
14
|
+
syncProduct(product: ProductBase): Promise<{
|
|
15
|
+
providerProductId: string;
|
|
16
|
+
}>;
|
|
17
|
+
syncPrice(variant: ProductVariant, providerProductId: string): Promise<{
|
|
18
|
+
providerPriceId: string;
|
|
19
|
+
}>;
|
|
20
|
+
archiveProduct(providerProductId: string): Promise<void>;
|
|
21
|
+
createCheckoutSession(items: CartItem[], options: CheckoutOptions, resolveVariant: (variantId: string) => Promise<ProductVariant | null>): Promise<CheckoutSession>;
|
|
22
|
+
getCheckoutSession(sessionId: string): Promise<CheckoutSession | null>;
|
|
23
|
+
private mapCheckoutSession;
|
|
24
|
+
getPaymentStatus(providerPaymentId: string): Promise<PaymentStatus>;
|
|
25
|
+
refund(request: RefundRequest, providerPaymentId: string): Promise<RefundResult>;
|
|
26
|
+
getSubscription(providerSubscriptionId: string): Promise<Subscription | null>;
|
|
27
|
+
cancelSubscription(providerSubscriptionId: string, cancelImmediately?: boolean): Promise<void>;
|
|
28
|
+
resumeSubscription(providerSubscriptionId: string): Promise<void>;
|
|
29
|
+
private mapSubscription;
|
|
30
|
+
syncCustomer(customer: Partial<Customer>): Promise<{
|
|
31
|
+
providerCustomerId: string;
|
|
32
|
+
}>;
|
|
33
|
+
getCustomer(providerCustomerId: string): Promise<Customer | null>;
|
|
34
|
+
createBillingPortalSession(providerCustomerId: string, returnUrl: string): Promise<{
|
|
35
|
+
url: string;
|
|
36
|
+
}>;
|
|
37
|
+
handleWebhook(request: Request): Promise<WebhookResult>;
|
|
38
|
+
private mapEventType;
|
|
39
|
+
createConnectAccount(options: ConnectOnboardingOptions): Promise<ConnectOnboardingResult>;
|
|
40
|
+
getConnectAccount(providerAccountId: string): Promise<ConnectAccount | null>;
|
|
41
|
+
createConnectAccountLink(providerAccountId: string, options: Pick<ConnectOnboardingOptions, 'returnUrl' | 'refreshUrl'>): Promise<{
|
|
42
|
+
url: string;
|
|
43
|
+
expiresAt?: Date;
|
|
44
|
+
}>;
|
|
45
|
+
createConnectLoginLink(providerAccountId: string): Promise<{
|
|
46
|
+
url: string;
|
|
47
|
+
}>;
|
|
48
|
+
private mapConnectAccount;
|
|
49
|
+
}
|
|
50
|
+
export declare function createStripeProvider(config: PaymentProviderConfig): StripeProvider;
|