alchemy 0.24.0 → 0.24.1
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/lib/aws/function.d.ts.map +1 -1
- package/lib/aws/function.js +1 -4
- package/lib/aws/function.js.map +1 -1
- package/lib/cloudflare/bindings.d.ts +3 -3
- package/lib/cloudflare/bindings.d.ts.map +1 -1
- package/lib/cloudflare/bindings.js.map +1 -1
- package/lib/cloudflare/bound.d.ts +3 -3
- package/lib/cloudflare/bound.d.ts.map +1 -1
- package/lib/cloudflare/do-state-store/index.d.ts +2 -0
- package/lib/cloudflare/do-state-store/index.d.ts.map +1 -0
- package/lib/cloudflare/do-state-store/index.js +2 -0
- package/lib/cloudflare/do-state-store/index.js.map +1 -0
- package/lib/cloudflare/do-state-store/internal.d.ts +19 -0
- package/lib/cloudflare/do-state-store/internal.d.ts.map +1 -0
- package/lib/cloudflare/do-state-store/internal.js +163 -0
- package/lib/cloudflare/do-state-store/internal.js.map +1 -0
- package/lib/cloudflare/do-state-store/store.d.ts +59 -0
- package/lib/cloudflare/do-state-store/store.d.ts.map +1 -0
- package/lib/cloudflare/do-state-store/store.js +120 -0
- package/lib/cloudflare/do-state-store/store.js.map +1 -0
- package/lib/cloudflare/do-state-store/types.d.ts +82 -0
- package/lib/cloudflare/do-state-store/types.d.ts.map +1 -0
- package/lib/cloudflare/do-state-store/types.js +1 -0
- package/lib/cloudflare/do-state-store/types.js.map +1 -0
- package/lib/cloudflare/do-state-store/worker.d.ts +27 -0
- package/lib/cloudflare/do-state-store/worker.d.ts.map +1 -0
- package/lib/cloudflare/do-state-store/worker.js +170 -0
- package/lib/cloudflare/do-state-store/worker.js.map +1 -0
- package/lib/cloudflare/index.d.ts +1 -0
- package/lib/cloudflare/index.d.ts.map +1 -1
- package/lib/cloudflare/index.js +1 -0
- package/lib/cloudflare/index.js.map +1 -1
- package/lib/cloudflare/pipeline.js +1 -1
- package/lib/cloudflare/pipeline.js.map +1 -1
- package/lib/cloudflare/queue-consumer.d.ts +14 -1
- package/lib/cloudflare/queue-consumer.d.ts.map +1 -1
- package/lib/cloudflare/queue-consumer.js +17 -0
- package/lib/cloudflare/queue-consumer.js.map +1 -1
- package/lib/cloudflare/website.d.ts +30 -1
- package/lib/cloudflare/website.d.ts.map +1 -1
- package/lib/cloudflare/website.js +8 -5
- package/lib/cloudflare/website.js.map +1 -1
- package/lib/cloudflare/worker-metadata.js +1 -1
- package/lib/cloudflare/worker-metadata.js.map +1 -1
- package/lib/cloudflare/worker.d.ts +40 -1
- package/lib/cloudflare/worker.d.ts.map +1 -1
- package/lib/cloudflare/worker.js +40 -38
- package/lib/cloudflare/worker.js.map +1 -1
- package/lib/cloudflare/wrangler.json.js +1 -1
- package/lib/cloudflare/wrangler.json.js.map +1 -1
- package/lib/fs/file-system-state-store.d.ts +3 -1
- package/lib/fs/file-system-state-store.d.ts.map +1 -1
- package/lib/fs/file-system-state-store.js +2 -2
- package/lib/fs/file-system-state-store.js.map +1 -1
- package/lib/stripe/card.d.ts +171 -0
- package/lib/stripe/card.d.ts.map +1 -0
- package/lib/stripe/card.js +148 -0
- package/lib/stripe/card.js.map +1 -0
- package/lib/stripe/client.d.ts +9 -0
- package/lib/stripe/client.d.ts.map +1 -0
- package/lib/stripe/client.js +94 -0
- package/lib/stripe/client.js.map +1 -0
- package/lib/stripe/coupon.d.ts +135 -0
- package/lib/stripe/coupon.d.ts.map +1 -0
- package/lib/stripe/coupon.js +161 -0
- package/lib/stripe/coupon.js.map +1 -0
- package/lib/stripe/customer.d.ts +269 -0
- package/lib/stripe/customer.d.ts.map +1 -0
- package/lib/stripe/customer.js +289 -0
- package/lib/stripe/customer.js.map +1 -0
- package/lib/stripe/entitlements-feature.d.ts +84 -0
- package/lib/stripe/entitlements-feature.d.ts.map +1 -0
- package/lib/stripe/entitlements-feature.js +102 -0
- package/lib/stripe/entitlements-feature.js.map +1 -0
- package/lib/stripe/file.d.ts +143 -0
- package/lib/stripe/file.d.ts.map +1 -0
- package/lib/stripe/file.js +97 -0
- package/lib/stripe/file.js.map +1 -0
- package/lib/stripe/index.d.ts +11 -0
- package/lib/stripe/index.d.ts.map +1 -1
- package/lib/stripe/index.js +11 -0
- package/lib/stripe/index.js.map +1 -1
- package/lib/stripe/meter.d.ts +10 -1
- package/lib/stripe/meter.d.ts.map +1 -1
- package/lib/stripe/meter.js +13 -7
- package/lib/stripe/meter.js.map +1 -1
- package/lib/stripe/portal-configuration.d.ts +286 -0
- package/lib/stripe/portal-configuration.d.ts.map +1 -0
- package/lib/stripe/portal-configuration.js +320 -0
- package/lib/stripe/portal-configuration.js.map +1 -0
- package/lib/stripe/price.d.ts +10 -1
- package/lib/stripe/price.d.ts.map +1 -1
- package/lib/stripe/price.js +34 -13
- package/lib/stripe/price.js.map +1 -1
- package/lib/stripe/product-feature.d.ts +76 -0
- package/lib/stripe/product-feature.d.ts.map +1 -0
- package/lib/stripe/product-feature.js +74 -0
- package/lib/stripe/product-feature.js.map +1 -0
- package/lib/stripe/product.d.ts +10 -1
- package/lib/stripe/product.d.ts.map +1 -1
- package/lib/stripe/product.js +33 -14
- package/lib/stripe/product.js.map +1 -1
- package/lib/stripe/promotion-code.d.ts +138 -0
- package/lib/stripe/promotion-code.d.ts.map +1 -0
- package/lib/stripe/promotion-code.js +150 -0
- package/lib/stripe/promotion-code.js.map +1 -0
- package/lib/stripe/shipping-rate.d.ts +188 -0
- package/lib/stripe/shipping-rate.d.ts.map +1 -0
- package/lib/stripe/shipping-rate.js +198 -0
- package/lib/stripe/shipping-rate.js.map +1 -0
- package/lib/stripe/tax-rate.d.ts +130 -0
- package/lib/stripe/tax-rate.d.ts.map +1 -0
- package/lib/stripe/tax-rate.js +126 -0
- package/lib/stripe/tax-rate.js.map +1 -0
- package/lib/stripe/webhook.d.ts +10 -1
- package/lib/stripe/webhook.d.ts.map +1 -1
- package/lib/stripe/webhook.js +59 -14
- package/lib/stripe/webhook.js.map +1 -1
- package/lib/test/bun.d.ts.map +1 -1
- package/lib/test/bun.js +2 -6
- package/lib/test/bun.js.map +1 -1
- package/lib/test/vitest.d.ts.map +1 -1
- package/lib/test/vitest.js +3 -7
- package/lib/test/vitest.js.map +1 -1
- package/lib/util/retry.d.ts +1 -1
- package/lib/util/retry.d.ts.map +1 -1
- package/lib/util/retry.js.map +1 -1
- package/package.json +2 -1
- package/src/aws/function.ts +3 -6
- package/src/cloudflare/bindings.ts +3 -2
- package/src/cloudflare/bound.ts +3 -3
- package/src/cloudflare/do-state-store/index.ts +1 -0
- package/src/cloudflare/do-state-store/internal.ts +215 -0
- package/src/cloudflare/do-state-store/store.ts +188 -0
- package/src/cloudflare/do-state-store/types.ts +74 -0
- package/src/cloudflare/do-state-store/worker.ts +199 -0
- package/src/cloudflare/index.ts +1 -0
- package/src/cloudflare/pipeline.ts +1 -1
- package/src/cloudflare/queue-consumer.ts +59 -1
- package/src/cloudflare/website.ts +38 -6
- package/src/cloudflare/worker-metadata.ts +1 -1
- package/src/cloudflare/worker.ts +66 -46
- package/src/cloudflare/wrangler.json.ts +1 -1
- package/src/fs/file-system-state-store.ts +7 -2
- package/src/stripe/card.ts +320 -0
- package/src/stripe/client.ts +145 -0
- package/src/stripe/coupon.ts +280 -0
- package/src/stripe/customer.ts +528 -0
- package/src/stripe/entitlements-feature.ts +169 -0
- package/src/stripe/file.ts +219 -0
- package/src/stripe/index.ts +11 -0
- package/src/stripe/meter.ts +23 -7
- package/src/stripe/portal-configuration.ts +609 -0
- package/src/stripe/price.ts +47 -14
- package/src/stripe/product-feature.ts +150 -0
- package/src/stripe/product.ts +48 -15
- package/src/stripe/promotion-code.ts +268 -0
- package/src/stripe/shipping-rate.ts +362 -0
- package/src/stripe/tax-rate.ts +218 -0
- package/src/stripe/webhook.ts +82 -15
- package/src/test/bun.ts +2 -7
- package/src/test/vitest.ts +3 -8
- package/src/util/retry.ts +1 -1
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
type CloudflareApi,
|
|
7
7
|
type CloudflareApiOptions,
|
|
8
8
|
} from "./api.ts";
|
|
9
|
-
import type {
|
|
9
|
+
import type { Queue, QueueResource } from "./queue.ts";
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
12
|
* Settings for configuring a Queue Consumer
|
|
@@ -450,3 +450,61 @@ export async function listQueueConsumers(
|
|
|
450
450
|
: undefined,
|
|
451
451
|
}));
|
|
452
452
|
}
|
|
453
|
+
|
|
454
|
+
export async function listQueueConsumersForWorker(
|
|
455
|
+
api: CloudflareApi,
|
|
456
|
+
workerName: string,
|
|
457
|
+
) {
|
|
458
|
+
const response = await api.get(
|
|
459
|
+
`/accounts/${api.accountId}/workers/scripts/${workerName}/queue-consumers?perPage=100`,
|
|
460
|
+
);
|
|
461
|
+
|
|
462
|
+
if (response.status === 404) {
|
|
463
|
+
return [];
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
if (!response.ok) {
|
|
467
|
+
return await handleApiError(
|
|
468
|
+
response,
|
|
469
|
+
"list",
|
|
470
|
+
"QueueConsumer",
|
|
471
|
+
`for worker ${workerName}`,
|
|
472
|
+
);
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
const data = (await response.json()) as {
|
|
476
|
+
result: Array<{
|
|
477
|
+
script: string;
|
|
478
|
+
settings?: {
|
|
479
|
+
batch_size?: number;
|
|
480
|
+
max_retries?: number;
|
|
481
|
+
max_wait_time_ms?: number;
|
|
482
|
+
retry_delay?: number;
|
|
483
|
+
dead_letter_queue?: string;
|
|
484
|
+
};
|
|
485
|
+
type: string;
|
|
486
|
+
queue_name: string;
|
|
487
|
+
queue_id: string;
|
|
488
|
+
consumer_id: string;
|
|
489
|
+
created_on: string;
|
|
490
|
+
}>;
|
|
491
|
+
success: boolean;
|
|
492
|
+
errors: any[] | null;
|
|
493
|
+
messages: any[] | null;
|
|
494
|
+
result_info: {
|
|
495
|
+
page: number;
|
|
496
|
+
per_page: number;
|
|
497
|
+
count: number;
|
|
498
|
+
total_count: number;
|
|
499
|
+
total_pages: number;
|
|
500
|
+
};
|
|
501
|
+
};
|
|
502
|
+
|
|
503
|
+
return data.result.map((consumer) => ({
|
|
504
|
+
queueName: consumer.queue_name,
|
|
505
|
+
queueId: consumer.queue_id,
|
|
506
|
+
consumerId: consumer.consumer_id,
|
|
507
|
+
createdOn: consumer.created_on,
|
|
508
|
+
settings: consumer.settings,
|
|
509
|
+
}));
|
|
510
|
+
}
|
|
@@ -15,8 +15,37 @@ export interface WebsiteProps<B extends Bindings>
|
|
|
15
15
|
extends Omit<WorkerProps<B>, "name" | "assets" | "entrypoint"> {
|
|
16
16
|
/**
|
|
17
17
|
* The command to run to build the site
|
|
18
|
+
*
|
|
19
|
+
* If one is not provided, the build is assumed to have already happened.
|
|
20
|
+
*/
|
|
21
|
+
command?: string;
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Whether to memoize the command (only re-run if the command changes)
|
|
25
|
+
*
|
|
26
|
+
* When set to `true`, the command will only be re-executed if the command string changes.
|
|
27
|
+
*
|
|
28
|
+
* When set to an object with `patterns`, the command will be re-executed if either:
|
|
29
|
+
* 1. The command string changes, or
|
|
30
|
+
* 2. The contents of any files matching the glob patterns change
|
|
31
|
+
*
|
|
32
|
+
* ⚠️ **Important Note**: When using memoization with build commands, the build outputs
|
|
33
|
+
* will not be produced if the command is memoized. This is because the command is not
|
|
34
|
+
* actually executed when memoized. Consider disabling memoization in CI environments:
|
|
35
|
+
*
|
|
36
|
+
* @example
|
|
37
|
+
* // Disable memoization in CI to ensure build outputs are always produced
|
|
38
|
+
* await Website("my-website", {
|
|
39
|
+
* command: "vite build",
|
|
40
|
+
* memoize: process.env.CI ? false : {
|
|
41
|
+
* patterns: ["./src/**"]
|
|
42
|
+
* }
|
|
43
|
+
* });
|
|
44
|
+
*
|
|
45
|
+
* @default false
|
|
18
46
|
*/
|
|
19
|
-
|
|
47
|
+
memoize?: boolean | { patterns: string[] };
|
|
48
|
+
|
|
20
49
|
/**
|
|
21
50
|
* The name of the worker
|
|
22
51
|
*
|
|
@@ -128,11 +157,14 @@ export default {
|
|
|
128
157
|
});
|
|
129
158
|
}
|
|
130
159
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
160
|
+
if (props.command) {
|
|
161
|
+
await Exec("build", {
|
|
162
|
+
cwd,
|
|
163
|
+
command: props.command,
|
|
164
|
+
env: props.env,
|
|
165
|
+
memoize: props.memoize,
|
|
166
|
+
});
|
|
167
|
+
}
|
|
136
168
|
|
|
137
169
|
return (await Worker("worker", {
|
|
138
170
|
...workerProps,
|
|
@@ -361,7 +361,7 @@ export async function prepareWorkerMetadata<B extends Bindings>(
|
|
|
361
361
|
meta.bindings.push({
|
|
362
362
|
type: "service",
|
|
363
363
|
name: bindingName,
|
|
364
|
-
service: binding.name,
|
|
364
|
+
service: "service" in binding ? binding.service : binding.name,
|
|
365
365
|
});
|
|
366
366
|
} else if (binding.type === "durable_object_namespace") {
|
|
367
367
|
meta.bindings.push({
|
package/src/cloudflare/worker.ts
CHANGED
|
@@ -23,6 +23,7 @@ import {
|
|
|
23
23
|
type Binding,
|
|
24
24
|
type Bindings,
|
|
25
25
|
Json,
|
|
26
|
+
type WorkerBindingService,
|
|
26
27
|
type WorkerBindingSpec,
|
|
27
28
|
} from "./bindings.ts";
|
|
28
29
|
import type { Bound } from "./bound.ts";
|
|
@@ -46,7 +47,7 @@ import { isPipeline } from "./pipeline.ts";
|
|
|
46
47
|
import {
|
|
47
48
|
QueueConsumer,
|
|
48
49
|
deleteQueueConsumer,
|
|
49
|
-
|
|
50
|
+
listQueueConsumersForWorker,
|
|
50
51
|
} from "./queue-consumer.ts";
|
|
51
52
|
import { type QueueResource, isQueue } from "./queue.ts";
|
|
52
53
|
import { isVectorizeIndex } from "./vectorize-index.ts";
|
|
@@ -384,6 +385,56 @@ export type Worker<
|
|
|
384
385
|
compatibilityFlags: string[];
|
|
385
386
|
};
|
|
386
387
|
|
|
388
|
+
/**
|
|
389
|
+
* Represents a reference to a Cloudflare Worker service.
|
|
390
|
+
*
|
|
391
|
+
* @template RPC - The type of the worker's RPC entrypoint, defaults to Rpc.WorkerEntrypointBranded.
|
|
392
|
+
*
|
|
393
|
+
* This interface extends all properties of WorkerBindingService except for "name".
|
|
394
|
+
* It also includes an optional __rpc__ property for type branding.
|
|
395
|
+
*/
|
|
396
|
+
export type WorkerRef<
|
|
397
|
+
RPC extends Rpc.WorkerEntrypointBranded = Rpc.WorkerEntrypointBranded,
|
|
398
|
+
> = Omit<WorkerBindingService, "name"> & {
|
|
399
|
+
/**
|
|
400
|
+
* Optional type branding for the worker's RPC entrypoint.
|
|
401
|
+
*/
|
|
402
|
+
__rpc__?: RPC;
|
|
403
|
+
};
|
|
404
|
+
|
|
405
|
+
/**
|
|
406
|
+
* Creates a reference to a Cloudflare Worker service.
|
|
407
|
+
*
|
|
408
|
+
* @example
|
|
409
|
+
* // Create a reference to a Cloudflare Worker service:
|
|
410
|
+
* const ref = WorkerRef({
|
|
411
|
+
* service: "my-worker",
|
|
412
|
+
* environment: "production",
|
|
413
|
+
* namespace: "main"
|
|
414
|
+
* });
|
|
415
|
+
*
|
|
416
|
+
* // Optionally, you can specify only the service:
|
|
417
|
+
* const ref2 = WorkerRef({ service: "my-worker" });
|
|
418
|
+
*
|
|
419
|
+
* // You can also specify the RPC type for stronger typing:
|
|
420
|
+
* interface MyWorkerRPC extends Rpc.WorkerEntrypointBranded {
|
|
421
|
+
* myMethod(arg: string): Promise<number>;
|
|
422
|
+
* }
|
|
423
|
+
* const typedRef = WorkerRef<MyWorkerRPC>({ service: "my-worker" });
|
|
424
|
+
*/
|
|
425
|
+
export function WorkerRef<
|
|
426
|
+
RPC extends Rpc.WorkerEntrypointBranded = Rpc.WorkerEntrypointBranded,
|
|
427
|
+
>(options?: {
|
|
428
|
+
service: string;
|
|
429
|
+
environment?: string;
|
|
430
|
+
namespace?: string;
|
|
431
|
+
}): WorkerRef<RPC> {
|
|
432
|
+
return {
|
|
433
|
+
...options,
|
|
434
|
+
type: "service",
|
|
435
|
+
} as WorkerRef<RPC>;
|
|
436
|
+
}
|
|
437
|
+
|
|
387
438
|
/**
|
|
388
439
|
* A Cloudflare Worker is a serverless function that can be deployed to the Cloudflare network.
|
|
389
440
|
*
|
|
@@ -869,7 +920,7 @@ export const _Worker = Resource(
|
|
|
869
920
|
|
|
870
921
|
if (this.phase === "delete") {
|
|
871
922
|
// Delete any queue consumers attached to this worker first
|
|
872
|
-
await deleteQueueConsumers(
|
|
923
|
+
await deleteQueueConsumers(api, workerName);
|
|
873
924
|
|
|
874
925
|
// @ts-ignore
|
|
875
926
|
await uploadWorkerScript({
|
|
@@ -879,7 +930,7 @@ export const _Worker = Resource(
|
|
|
879
930
|
script:
|
|
880
931
|
props.format === "cjs"
|
|
881
932
|
? "addEventListener('fetch', event => { event.respondWith(new Response('hello world')); });"
|
|
882
|
-
: "export default { fetch(request) { return new Response('hello world'); } }",
|
|
933
|
+
: "export default { fetch(request) { return new Response('hello world'); }, queue: () => {} }",
|
|
883
934
|
bindings: {} as B,
|
|
884
935
|
// we are writing a stub worker (to remove binding/event source dependencies)
|
|
885
936
|
// queue consumers will no longer exist by this point
|
|
@@ -1074,7 +1125,14 @@ export async function putWorker(
|
|
|
1074
1125
|
|
|
1075
1126
|
return formData;
|
|
1076
1127
|
},
|
|
1077
|
-
(err) =>
|
|
1128
|
+
(err) =>
|
|
1129
|
+
err.status === 404 ||
|
|
1130
|
+
err.status === 500 ||
|
|
1131
|
+
err.status === 503 ||
|
|
1132
|
+
// this is a tranient error that cloudflare throws randomly
|
|
1133
|
+
(err instanceof CloudflareApiError &&
|
|
1134
|
+
err.status === 400 &&
|
|
1135
|
+
err.message.match(/binding.*failed to generate/)),
|
|
1078
1136
|
10,
|
|
1079
1137
|
100,
|
|
1080
1138
|
);
|
|
@@ -1248,53 +1306,15 @@ async function getWorkerBindings(api: CloudflareApi, workerName: string) {
|
|
|
1248
1306
|
* @param api CloudflareApi instance
|
|
1249
1307
|
* @param workerName Name of the worker script
|
|
1250
1308
|
*/
|
|
1251
|
-
async function deleteQueueConsumers
|
|
1252
|
-
ctx: Context<Worker<B>>,
|
|
1309
|
+
async function deleteQueueConsumers(
|
|
1253
1310
|
api: CloudflareApi,
|
|
1254
1311
|
workerName: string,
|
|
1255
1312
|
): Promise<void> {
|
|
1256
|
-
const
|
|
1257
|
-
|
|
1258
|
-
// Extract queue IDs from event sources
|
|
1259
|
-
const queueIds = eventSources.flatMap((eventSource) => {
|
|
1260
|
-
if (isQueue(eventSource)) {
|
|
1261
|
-
return [eventSource.id];
|
|
1262
|
-
}
|
|
1263
|
-
if (isQueueEventSource(eventSource)) {
|
|
1264
|
-
return [eventSource.queue.id];
|
|
1265
|
-
}
|
|
1266
|
-
return [];
|
|
1267
|
-
});
|
|
1313
|
+
const consumers = await listQueueConsumersForWorker(api, workerName);
|
|
1268
1314
|
|
|
1269
|
-
// Process each queue associated with this worker
|
|
1270
1315
|
await Promise.all(
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
// List all consumers for this queue
|
|
1274
|
-
const consumers = await listQueueConsumers(api, queueId);
|
|
1275
|
-
|
|
1276
|
-
// Filter consumers by worker name
|
|
1277
|
-
const workerConsumers = consumers.filter(
|
|
1278
|
-
(consumer) => consumer.scriptName === workerName,
|
|
1279
|
-
);
|
|
1280
|
-
|
|
1281
|
-
// Delete all consumers for this worker in parallel
|
|
1282
|
-
await Promise.all(
|
|
1283
|
-
workerConsumers.map(async (consumer) => {
|
|
1284
|
-
console.log(
|
|
1285
|
-
`Deleting queue consumer ${consumer.id} for worker ${workerName}`,
|
|
1286
|
-
);
|
|
1287
|
-
// Use the deleteQueueConsumer function from queue-consumer.ts
|
|
1288
|
-
await deleteQueueConsumer(api, consumer.queueId, consumer.id);
|
|
1289
|
-
}),
|
|
1290
|
-
);
|
|
1291
|
-
} catch (err) {
|
|
1292
|
-
if (err instanceof CloudflareApiError && err.status === 404) {
|
|
1293
|
-
// this is OK
|
|
1294
|
-
} else {
|
|
1295
|
-
throw err;
|
|
1296
|
-
}
|
|
1297
|
-
}
|
|
1316
|
+
consumers.map(async (consumer) => {
|
|
1317
|
+
await deleteQueueConsumer(api, consumer.queueId, consumer.consumerId);
|
|
1298
1318
|
}),
|
|
1299
1319
|
);
|
|
1300
1320
|
}
|
|
@@ -447,7 +447,7 @@ function processBindings(
|
|
|
447
447
|
// Service binding
|
|
448
448
|
services.push({
|
|
449
449
|
binding: bindingName,
|
|
450
|
-
service: binding.name,
|
|
450
|
+
service: "name" in binding ? binding.name : binding.service,
|
|
451
451
|
});
|
|
452
452
|
} else if (binding.type === "kv_namespace") {
|
|
453
453
|
// KV Namespace binding
|
|
@@ -11,8 +11,13 @@ const stateRootDir = path.join(process.cwd(), ".alchemy");
|
|
|
11
11
|
export class FileSystemStateStore implements StateStore {
|
|
12
12
|
public readonly dir: string;
|
|
13
13
|
private initialized = false;
|
|
14
|
-
constructor(
|
|
15
|
-
|
|
14
|
+
constructor(
|
|
15
|
+
public readonly scope: Scope,
|
|
16
|
+
options?: {
|
|
17
|
+
rootDir?: string;
|
|
18
|
+
},
|
|
19
|
+
) {
|
|
20
|
+
this.dir = path.join(options?.rootDir ?? stateRootDir, ...scope.chain);
|
|
16
21
|
}
|
|
17
22
|
|
|
18
23
|
async init(): Promise<void> {
|
|
@@ -0,0 +1,320 @@
|
|
|
1
|
+
import type Stripe from "stripe";
|
|
2
|
+
import type { Context } from "../context.ts";
|
|
3
|
+
import { Resource } from "../resource.ts";
|
|
4
|
+
import type { Secret } from "../secret.ts";
|
|
5
|
+
import {
|
|
6
|
+
createStripeClient,
|
|
7
|
+
handleStripeDeleteError,
|
|
8
|
+
isStripeConflictError,
|
|
9
|
+
} from "./client.ts";
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Properties for creating a Stripe card
|
|
13
|
+
*/
|
|
14
|
+
export interface CardProps {
|
|
15
|
+
/**
|
|
16
|
+
* The ID of the customer to attach the card to
|
|
17
|
+
*/
|
|
18
|
+
customer: string;
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* A token or source to attach to the customer
|
|
22
|
+
*/
|
|
23
|
+
source?: string;
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* The card number, as a string without any separators
|
|
27
|
+
*/
|
|
28
|
+
number?: string;
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Two-digit number representing the card's expiration month
|
|
32
|
+
*/
|
|
33
|
+
expMonth?: number;
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Four-digit number representing the card's expiration year
|
|
37
|
+
*/
|
|
38
|
+
expYear?: number;
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Card security code
|
|
42
|
+
*/
|
|
43
|
+
cvc?: string;
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Cardholder's full name
|
|
47
|
+
*/
|
|
48
|
+
name?: string;
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* City/District/Suburb/Town/Village
|
|
52
|
+
*/
|
|
53
|
+
addressCity?: string;
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Billing address country, if provided when creating card
|
|
57
|
+
*/
|
|
58
|
+
addressCountry?: string;
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Address line 1 (Street address/PO Box/Company name)
|
|
62
|
+
*/
|
|
63
|
+
addressLine1?: string;
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Address line 2 (Apartment/Suite/Unit/Building)
|
|
67
|
+
*/
|
|
68
|
+
addressLine2?: string;
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* State/County/Province/Region
|
|
72
|
+
*/
|
|
73
|
+
addressState?: string;
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* ZIP or postal code
|
|
77
|
+
*/
|
|
78
|
+
addressZip?: string;
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Required when adding a card to an account (not applicable to customers or recipients)
|
|
82
|
+
*/
|
|
83
|
+
currency?: string;
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Only applicable on accounts (not customers or recipients)
|
|
87
|
+
*/
|
|
88
|
+
defaultForCurrency?: boolean;
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Set of key-value pairs that you can attach to an object
|
|
92
|
+
*/
|
|
93
|
+
metadata?: Record<string, string>;
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* API key to use (overrides environment variable)
|
|
97
|
+
*/
|
|
98
|
+
apiKey?: Secret;
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* If true, adopt existing resource if creation fails due to conflict
|
|
102
|
+
*/
|
|
103
|
+
adopt?: boolean;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Output from the Stripe card
|
|
108
|
+
*/
|
|
109
|
+
export interface Card extends Resource<"stripe::Card">, CardProps {
|
|
110
|
+
/**
|
|
111
|
+
* The ID of the card
|
|
112
|
+
*/
|
|
113
|
+
id: string;
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* String representing the object's type
|
|
117
|
+
*/
|
|
118
|
+
object: "card";
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Card brand (Visa, American Express, MasterCard, Discover, JCB, Diners Club, or Unknown)
|
|
122
|
+
*/
|
|
123
|
+
brand: string;
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Two-letter ISO code representing the country of the card
|
|
127
|
+
*/
|
|
128
|
+
country?: string;
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* The last four digits of the device account number
|
|
132
|
+
*/
|
|
133
|
+
dynamicLast4?: string;
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Uniquely identifies this particular card number
|
|
137
|
+
*/
|
|
138
|
+
fingerprint?: string;
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Card funding type (credit, debit, prepaid, or unknown)
|
|
142
|
+
*/
|
|
143
|
+
funding: string;
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* The last four digits of the card
|
|
147
|
+
*/
|
|
148
|
+
last4: string;
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* If the card number is tokenized, this is the method that was used
|
|
152
|
+
*/
|
|
153
|
+
tokenizationMethod?: string;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Create and manage Stripe cards attached to customers
|
|
158
|
+
*
|
|
159
|
+
* @example
|
|
160
|
+
* // Create a card using raw card details
|
|
161
|
+
* const customerCard = await Card("customer-card", {
|
|
162
|
+
* customer: "cus_xyz123",
|
|
163
|
+
* number: "4242424242424242",
|
|
164
|
+
* expMonth: 12,
|
|
165
|
+
* expYear: 2025,
|
|
166
|
+
* cvc: "123",
|
|
167
|
+
* name: "John Doe",
|
|
168
|
+
* addressLine1: "123 Main St",
|
|
169
|
+
* addressCity: "San Francisco",
|
|
170
|
+
* addressState: "CA",
|
|
171
|
+
* addressZip: "94105",
|
|
172
|
+
* addressCountry: "US"
|
|
173
|
+
* });
|
|
174
|
+
*
|
|
175
|
+
* @example
|
|
176
|
+
* // Create a card using a token
|
|
177
|
+
* const tokenCard = await Card("token-card", {
|
|
178
|
+
* customer: "cus_xyz123",
|
|
179
|
+
* source: "tok_visa",
|
|
180
|
+
* metadata: {
|
|
181
|
+
* type: "primary",
|
|
182
|
+
* source: "mobile_app"
|
|
183
|
+
* }
|
|
184
|
+
* });
|
|
185
|
+
*
|
|
186
|
+
* @example
|
|
187
|
+
* // Create a card for international customer
|
|
188
|
+
* const internationalCard = await Card("international-card", {
|
|
189
|
+
* customer: "cus_international456",
|
|
190
|
+
* number: "4000000000000002",
|
|
191
|
+
* expMonth: 6,
|
|
192
|
+
* expYear: 2026,
|
|
193
|
+
* name: "Maria Garcia",
|
|
194
|
+
* addressLine1: "Calle Principal 123",
|
|
195
|
+
* addressCity: "Madrid",
|
|
196
|
+
* addressCountry: "ES",
|
|
197
|
+
* addressZip: "28001",
|
|
198
|
+
* metadata: {
|
|
199
|
+
* region: "europe",
|
|
200
|
+
* currency_preference: "eur"
|
|
201
|
+
* }
|
|
202
|
+
* });
|
|
203
|
+
*/
|
|
204
|
+
export const Card = Resource(
|
|
205
|
+
"stripe::Card",
|
|
206
|
+
async function (
|
|
207
|
+
this: Context<Card>,
|
|
208
|
+
_id: string,
|
|
209
|
+
props: CardProps,
|
|
210
|
+
): Promise<Card> {
|
|
211
|
+
const stripe = createStripeClient({ apiKey: props.apiKey });
|
|
212
|
+
|
|
213
|
+
if (this.phase === "delete") {
|
|
214
|
+
try {
|
|
215
|
+
if (this.output?.id && this.output?.customer) {
|
|
216
|
+
await stripe.customers.deleteSource(
|
|
217
|
+
this.output.customer,
|
|
218
|
+
this.output.id,
|
|
219
|
+
);
|
|
220
|
+
}
|
|
221
|
+
} catch (error) {
|
|
222
|
+
handleStripeDeleteError(error, "Card", this.output?.id);
|
|
223
|
+
}
|
|
224
|
+
return this.destroy();
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
try {
|
|
228
|
+
let card: Stripe.Card;
|
|
229
|
+
|
|
230
|
+
if (this.phase === "update" && this.output?.id) {
|
|
231
|
+
const updateParams = {
|
|
232
|
+
name: props.name,
|
|
233
|
+
address_city: props.addressCity,
|
|
234
|
+
address_country: props.addressCountry,
|
|
235
|
+
address_line1: props.addressLine1,
|
|
236
|
+
address_line2: props.addressLine2,
|
|
237
|
+
address_state: props.addressState,
|
|
238
|
+
address_zip: props.addressZip,
|
|
239
|
+
exp_month: props.expMonth?.toString(),
|
|
240
|
+
exp_year: props.expYear?.toString(),
|
|
241
|
+
metadata: props.metadata,
|
|
242
|
+
};
|
|
243
|
+
|
|
244
|
+
card = (await stripe.customers.updateSource(
|
|
245
|
+
props.customer,
|
|
246
|
+
this.output.id,
|
|
247
|
+
updateParams,
|
|
248
|
+
)) as Stripe.Card;
|
|
249
|
+
} else {
|
|
250
|
+
const createParams: any = {
|
|
251
|
+
metadata: props.metadata,
|
|
252
|
+
};
|
|
253
|
+
|
|
254
|
+
if (props.source) {
|
|
255
|
+
createParams.source = props.source;
|
|
256
|
+
} else if (props.number) {
|
|
257
|
+
createParams.source = {
|
|
258
|
+
object: "card",
|
|
259
|
+
number: props.number,
|
|
260
|
+
exp_month: props.expMonth,
|
|
261
|
+
exp_year: props.expYear,
|
|
262
|
+
cvc: props.cvc,
|
|
263
|
+
name: props.name,
|
|
264
|
+
address_city: props.addressCity,
|
|
265
|
+
address_country: props.addressCountry,
|
|
266
|
+
address_line1: props.addressLine1,
|
|
267
|
+
address_line2: props.addressLine2,
|
|
268
|
+
address_state: props.addressState,
|
|
269
|
+
address_zip: props.addressZip,
|
|
270
|
+
currency: props.currency,
|
|
271
|
+
default_for_currency: props.defaultForCurrency,
|
|
272
|
+
};
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
try {
|
|
276
|
+
card = (await stripe.customers.createSource(
|
|
277
|
+
props.customer,
|
|
278
|
+
createParams,
|
|
279
|
+
)) as Stripe.Card;
|
|
280
|
+
} catch (error) {
|
|
281
|
+
if (isStripeConflictError(error) && props.adopt) {
|
|
282
|
+
throw new Error(
|
|
283
|
+
"Card adoption is not supported - cards cannot be uniquely identified for adoption",
|
|
284
|
+
);
|
|
285
|
+
} else {
|
|
286
|
+
throw error;
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
return this({
|
|
292
|
+
id: card.id,
|
|
293
|
+
object: card.object,
|
|
294
|
+
customer: props.customer,
|
|
295
|
+
brand: card.brand,
|
|
296
|
+
country: card.country || undefined,
|
|
297
|
+
dynamicLast4: card.dynamic_last4 || undefined,
|
|
298
|
+
expMonth: card.exp_month,
|
|
299
|
+
expYear: card.exp_year,
|
|
300
|
+
fingerprint: card.fingerprint || undefined,
|
|
301
|
+
funding: card.funding,
|
|
302
|
+
last4: card.last4,
|
|
303
|
+
name: card.name || undefined,
|
|
304
|
+
addressCity: card.address_city || undefined,
|
|
305
|
+
addressCountry: card.address_country || undefined,
|
|
306
|
+
addressLine1: card.address_line1 || undefined,
|
|
307
|
+
addressLine2: card.address_line2 || undefined,
|
|
308
|
+
addressState: card.address_state || undefined,
|
|
309
|
+
addressZip: card.address_zip || undefined,
|
|
310
|
+
currency: card.currency || undefined,
|
|
311
|
+
defaultForCurrency: card.default_for_currency || undefined,
|
|
312
|
+
metadata: card.metadata || undefined,
|
|
313
|
+
tokenizationMethod: card.tokenization_method || undefined,
|
|
314
|
+
});
|
|
315
|
+
} catch (error) {
|
|
316
|
+
console.error("Error creating/updating card:", error);
|
|
317
|
+
throw error;
|
|
318
|
+
}
|
|
319
|
+
},
|
|
320
|
+
);
|