alchemy 0.34.0 → 0.34.2
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/bin/alchemy.mjs +38018 -3538
- package/bin/alchemy.ts +26 -0
- package/bin/bootstrap-s3.ts +255 -0
- package/lib/aws/index.d.ts +1 -0
- package/lib/aws/index.d.ts.map +1 -1
- package/lib/aws/index.js +1 -0
- package/lib/aws/index.js.map +1 -1
- package/lib/aws/s3-state-store.d.ts +117 -0
- package/lib/aws/s3-state-store.d.ts.map +1 -0
- package/lib/aws/s3-state-store.js +224 -0
- package/lib/aws/s3-state-store.js.map +1 -0
- package/lib/cloudflare/index.d.ts +2 -1
- package/lib/cloudflare/index.d.ts.map +1 -1
- package/lib/cloudflare/index.js +2 -1
- package/lib/cloudflare/index.js.map +1 -1
- package/package.json +2 -1
- package/src/aws/index.ts +1 -0
- package/src/aws/s3-state-store.ts +316 -0
- package/src/cloudflare/index.ts +2 -1
|
@@ -38,8 +38,8 @@ export * from "./r2-rest-state-store.ts";
|
|
|
38
38
|
export * from "./react-router.ts";
|
|
39
39
|
export * from "./redwood.ts";
|
|
40
40
|
export * from "./route.ts";
|
|
41
|
-
export * from "./secret.ts";
|
|
42
41
|
export * from "./secret-key.ts";
|
|
42
|
+
export * from "./secret.ts";
|
|
43
43
|
export * from "./secrets-store.ts";
|
|
44
44
|
export * from "./sveltekit.ts";
|
|
45
45
|
export * from "./tanstack-start.ts";
|
|
@@ -48,6 +48,7 @@ export * from "./vectorize-metadata-index.ts";
|
|
|
48
48
|
export * from "./version-metadata.ts";
|
|
49
49
|
export * from "./vite.ts";
|
|
50
50
|
export * from "./website.ts";
|
|
51
|
+
export * from "./worker-stub.ts";
|
|
51
52
|
export * from "./worker.ts";
|
|
52
53
|
export { Workflow } from "./workflow.ts";
|
|
53
54
|
export * from "./wrangler.json.ts";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/cloudflare/index.ts"],"names":[],"mappings":"AAAA,cAAc,wBAAwB,CAAC;AACvC,cAAc,iBAAiB,CAAC;AAChC,cAAc,iBAAiB,CAAC;AAChC,cAAc,SAAS,CAAC;AACxB,cAAc,uBAAuB,CAAC;AACtC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,UAAU,CAAC;AACzB,cAAc,aAAa,CAAC;AAC5B,cAAc,YAAY,CAAC;AAC3B,cAAc,eAAe,CAAC;AAC9B,cAAc,YAAY,CAAC;AAC3B,cAAc,wBAAwB,CAAC;AACvC,cAAc,aAAa,CAAC;AAC5B,cAAc,sBAAsB,CAAC;AACrC,cAAc,uCAAuC,CAAC;AACtD,cAAc,oBAAoB,CAAC;AACnC,cAAc,eAAe,CAAC;AAC9B,cAAc,kBAAkB,CAAC;AACjC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,yBAAyB,CAAC;AACxC,cAAc,kBAAkB,CAAC;AACjC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,+BAA+B,CAAC;AAC9C,cAAc,oBAAoB,CAAC;AACnC,cAAc,sBAAsB,CAAC;AACrC,cAAc,oBAAoB,CAAC;AACnC,cAAc,iBAAiB,CAAC;AAChC,cAAc,iBAAiB,CAAC;AAChC,cAAc,aAAa,CAAC;AAC5B,cAAc,mBAAmB,CAAC;AAClC,cAAc,WAAW,CAAC;AAC1B,cAAc,wBAAwB,CAAC;AACvC,cAAc,eAAe,CAAC;AAC9B,cAAc,qBAAqB,CAAC;AACpC,cAAc,YAAY,CAAC;AAC3B,cAAc,0BAA0B,CAAC;AACzC,cAAc,mBAAmB,CAAC;AAClC,cAAc,cAAc,CAAC;AAC7B,cAAc,YAAY,CAAC;AAC3B,cAAc,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/cloudflare/index.ts"],"names":[],"mappings":"AAAA,cAAc,wBAAwB,CAAC;AACvC,cAAc,iBAAiB,CAAC;AAChC,cAAc,iBAAiB,CAAC;AAChC,cAAc,SAAS,CAAC;AACxB,cAAc,uBAAuB,CAAC;AACtC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,UAAU,CAAC;AACzB,cAAc,aAAa,CAAC;AAC5B,cAAc,YAAY,CAAC;AAC3B,cAAc,eAAe,CAAC;AAC9B,cAAc,YAAY,CAAC;AAC3B,cAAc,wBAAwB,CAAC;AACvC,cAAc,aAAa,CAAC;AAC5B,cAAc,sBAAsB,CAAC;AACrC,cAAc,uCAAuC,CAAC;AACtD,cAAc,oBAAoB,CAAC;AACnC,cAAc,eAAe,CAAC;AAC9B,cAAc,kBAAkB,CAAC;AACjC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,yBAAyB,CAAC;AACxC,cAAc,kBAAkB,CAAC;AACjC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,+BAA+B,CAAC;AAC9C,cAAc,oBAAoB,CAAC;AACnC,cAAc,sBAAsB,CAAC;AACrC,cAAc,oBAAoB,CAAC;AACnC,cAAc,iBAAiB,CAAC;AAChC,cAAc,iBAAiB,CAAC;AAChC,cAAc,aAAa,CAAC;AAC5B,cAAc,mBAAmB,CAAC;AAClC,cAAc,WAAW,CAAC;AAC1B,cAAc,wBAAwB,CAAC;AACvC,cAAc,eAAe,CAAC;AAC9B,cAAc,qBAAqB,CAAC;AACpC,cAAc,YAAY,CAAC;AAC3B,cAAc,0BAA0B,CAAC;AACzC,cAAc,mBAAmB,CAAC;AAClC,cAAc,cAAc,CAAC;AAC7B,cAAc,YAAY,CAAC;AAC3B,cAAc,iBAAiB,CAAC;AAChC,cAAc,aAAa,CAAC;AAC5B,cAAc,oBAAoB,CAAC;AACnC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,qBAAqB,CAAC;AACpC,cAAc,sBAAsB,CAAC;AACrC,cAAc,+BAA+B,CAAC;AAC9C,cAAc,uBAAuB,CAAC;AACtC,cAAc,WAAW,CAAC;AAC1B,cAAc,cAAc,CAAC;AAC7B,cAAc,kBAAkB,CAAC;AACjC,cAAc,aAAa,CAAC;AAC5B,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,cAAc,oBAAoB,CAAC;AACnC,cAAc,WAAW,CAAC"}
|
package/lib/cloudflare/index.js
CHANGED
|
@@ -38,8 +38,8 @@ export * from "./r2-rest-state-store.js";
|
|
|
38
38
|
export * from "./react-router.js";
|
|
39
39
|
export * from "./redwood.js";
|
|
40
40
|
export * from "./route.js";
|
|
41
|
-
export * from "./secret.js";
|
|
42
41
|
export * from "./secret-key.js";
|
|
42
|
+
export * from "./secret.js";
|
|
43
43
|
export * from "./secrets-store.js";
|
|
44
44
|
export * from "./sveltekit.js";
|
|
45
45
|
export * from "./tanstack-start.js";
|
|
@@ -48,6 +48,7 @@ export * from "./vectorize-metadata-index.js";
|
|
|
48
48
|
export * from "./version-metadata.js";
|
|
49
49
|
export * from "./vite.js";
|
|
50
50
|
export * from "./website.js";
|
|
51
|
+
export * from "./worker-stub.js";
|
|
51
52
|
export * from "./worker.js";
|
|
52
53
|
export { Workflow } from "./workflow.js";
|
|
53
54
|
export * from "./wrangler.json.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cloudflare/index.ts"],"names":[],"mappings":"AAAA,cAAc,wBAAwB,CAAC;AACvC,cAAc,iBAAiB,CAAC;AAChC,cAAc,iBAAiB,CAAC;AAChC,cAAc,SAAS,CAAC;AACxB,cAAc,uBAAuB,CAAC;AACtC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,UAAU,CAAC;AACzB,cAAc,aAAa,CAAC;AAC5B,cAAc,YAAY,CAAC;AAC3B,cAAc,eAAe,CAAC;AAC9B,cAAc,YAAY,CAAC;AAC3B,cAAc,wBAAwB,CAAC;AACvC,cAAc,aAAa,CAAC;AAC5B,cAAc,sBAAsB,CAAC;AACrC,cAAc,uCAAuC,CAAC;AACtD,cAAc,oBAAoB,CAAC;AACnC,cAAc,eAAe,CAAC;AAC9B,cAAc,kBAAkB,CAAC;AACjC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,yBAAyB,CAAC;AACxC,cAAc,kBAAkB,CAAC;AACjC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,+BAA+B,CAAC;AAC9C,cAAc,oBAAoB,CAAC;AACnC,cAAc,sBAAsB,CAAC;AACrC,cAAc,oBAAoB,CAAC;AACnC,cAAc,iBAAiB,CAAC;AAChC,cAAc,iBAAiB,CAAC;AAChC,cAAc,aAAa,CAAC;AAC5B,cAAc,mBAAmB,CAAC;AAClC,cAAc,WAAW,CAAC;AAC1B,cAAc,wBAAwB,CAAC;AACvC,cAAc,eAAe,CAAC;AAC9B,cAAc,qBAAqB,CAAC;AACpC,cAAc,YAAY,CAAC;AAC3B,cAAc,0BAA0B,CAAC;AACzC,cAAc,mBAAmB,CAAC;AAClC,cAAc,cAAc,CAAC;AAC7B,cAAc,YAAY,CAAC;AAC3B,cAAc,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cloudflare/index.ts"],"names":[],"mappings":"AAAA,cAAc,wBAAwB,CAAC;AACvC,cAAc,iBAAiB,CAAC;AAChC,cAAc,iBAAiB,CAAC;AAChC,cAAc,SAAS,CAAC;AACxB,cAAc,uBAAuB,CAAC;AACtC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,UAAU,CAAC;AACzB,cAAc,aAAa,CAAC;AAC5B,cAAc,YAAY,CAAC;AAC3B,cAAc,eAAe,CAAC;AAC9B,cAAc,YAAY,CAAC;AAC3B,cAAc,wBAAwB,CAAC;AACvC,cAAc,aAAa,CAAC;AAC5B,cAAc,sBAAsB,CAAC;AACrC,cAAc,uCAAuC,CAAC;AACtD,cAAc,oBAAoB,CAAC;AACnC,cAAc,eAAe,CAAC;AAC9B,cAAc,kBAAkB,CAAC;AACjC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,yBAAyB,CAAC;AACxC,cAAc,kBAAkB,CAAC;AACjC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,+BAA+B,CAAC;AAC9C,cAAc,oBAAoB,CAAC;AACnC,cAAc,sBAAsB,CAAC;AACrC,cAAc,oBAAoB,CAAC;AACnC,cAAc,iBAAiB,CAAC;AAChC,cAAc,iBAAiB,CAAC;AAChC,cAAc,aAAa,CAAC;AAC5B,cAAc,mBAAmB,CAAC;AAClC,cAAc,WAAW,CAAC;AAC1B,cAAc,wBAAwB,CAAC;AACvC,cAAc,eAAe,CAAC;AAC9B,cAAc,qBAAqB,CAAC;AACpC,cAAc,YAAY,CAAC;AAC3B,cAAc,0BAA0B,CAAC;AACzC,cAAc,mBAAmB,CAAC;AAClC,cAAc,cAAc,CAAC;AAC7B,cAAc,YAAY,CAAC;AAC3B,cAAc,iBAAiB,CAAC;AAChC,cAAc,aAAa,CAAC;AAC5B,cAAc,oBAAoB,CAAC;AACnC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,qBAAqB,CAAC;AACpC,cAAc,sBAAsB,CAAC;AACrC,cAAc,+BAA+B,CAAC;AAC9C,cAAc,uBAAuB,CAAC;AACtC,cAAc,WAAW,CAAC;AAC1B,cAAc,cAAc,CAAC;AAC7B,cAAc,kBAAkB,CAAC;AACjC,cAAc,aAAa,CAAC;AAC5B,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,cAAc,oBAAoB,CAAC;AACnC,cAAc,WAAW,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "alchemy",
|
|
3
|
-
"version": "0.34.
|
|
3
|
+
"version": "0.34.2",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"module": "./lib/index.js",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -158,6 +158,7 @@
|
|
|
158
158
|
"@ai-sdk/anthropic": "^1.1.6",
|
|
159
159
|
"@ai-sdk/openai": "^1.1.9",
|
|
160
160
|
"@asteasolutions/zod-to-openapi": "^7.3.0",
|
|
161
|
+
"@aws-sdk/client-resource-groups-tagging-api": "^3.830.0",
|
|
161
162
|
"@aws-sdk/client-s3": "3.726.1",
|
|
162
163
|
"@biomejs/biome": "^1.9.4",
|
|
163
164
|
"@cloudflare/puppeteer": "^1.0.2",
|
package/src/aws/index.ts
CHANGED
|
@@ -0,0 +1,316 @@
|
|
|
1
|
+
import {
|
|
2
|
+
DeleteObjectCommand,
|
|
3
|
+
GetObjectCommand,
|
|
4
|
+
ListObjectsV2Command,
|
|
5
|
+
NoSuchBucket,
|
|
6
|
+
NoSuchKey,
|
|
7
|
+
PutObjectCommand,
|
|
8
|
+
S3Client,
|
|
9
|
+
} from "@aws-sdk/client-s3";
|
|
10
|
+
import { ResourceScope } from "../resource.ts";
|
|
11
|
+
import type { Scope } from "../scope.ts";
|
|
12
|
+
import { serialize } from "../serde.ts";
|
|
13
|
+
import { deserializeState, type State, type StateStore } from "../state.ts";
|
|
14
|
+
import { ignore } from "../util/ignore.ts";
|
|
15
|
+
import { retry } from "./retry.ts";
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Options for S3StateStore
|
|
19
|
+
*/
|
|
20
|
+
export interface S3StateStoreOptions {
|
|
21
|
+
/**
|
|
22
|
+
* The prefix to use for object keys in the S3 bucket
|
|
23
|
+
* This allows multiple state stores to use the same S3 bucket
|
|
24
|
+
*/
|
|
25
|
+
prefix?: string;
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* The S3 bucket name to use
|
|
29
|
+
* Required - the bucket must already exist
|
|
30
|
+
*/
|
|
31
|
+
bucketName?: string;
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* AWS region for the S3 client
|
|
35
|
+
* If not provided, uses the default AWS region configuration
|
|
36
|
+
*/
|
|
37
|
+
region?: string;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* State store implementation using AWS S3
|
|
42
|
+
* Provides reliable, scalable state storage with eventual consistency
|
|
43
|
+
*/
|
|
44
|
+
export class S3StateStore implements StateStore {
|
|
45
|
+
private client: S3Client;
|
|
46
|
+
private prefix: string;
|
|
47
|
+
private bucketName: string;
|
|
48
|
+
private initialized = false;
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Create a new S3StateStore
|
|
52
|
+
*
|
|
53
|
+
* @param scope The scope this store belongs to
|
|
54
|
+
* @param options Options for the state store
|
|
55
|
+
*/
|
|
56
|
+
constructor(
|
|
57
|
+
public readonly scope: Scope,
|
|
58
|
+
private readonly options: S3StateStoreOptions = {},
|
|
59
|
+
) {
|
|
60
|
+
// Use the scope's chain to build the prefix, similar to how FileSystemStateStore builds its directory
|
|
61
|
+
const scopePath = scope.chain.join("/");
|
|
62
|
+
this.prefix = options.prefix
|
|
63
|
+
? `${options.prefix}${scopePath}/`
|
|
64
|
+
: `alchemy/${scopePath}/`;
|
|
65
|
+
|
|
66
|
+
this.bucketName = options.bucketName ?? "alchemy-state";
|
|
67
|
+
|
|
68
|
+
this.client = new S3Client({
|
|
69
|
+
region: options.region,
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Initialize the S3 client and verify bucket access
|
|
75
|
+
*/
|
|
76
|
+
async init(): Promise<void> {
|
|
77
|
+
if (this.initialized) return;
|
|
78
|
+
|
|
79
|
+
// Verify bucket exists and is accessible
|
|
80
|
+
try {
|
|
81
|
+
await retry(() =>
|
|
82
|
+
this.client.send(
|
|
83
|
+
new ListObjectsV2Command({
|
|
84
|
+
Bucket: this.bucketName,
|
|
85
|
+
MaxKeys: 1,
|
|
86
|
+
}),
|
|
87
|
+
),
|
|
88
|
+
);
|
|
89
|
+
} catch (error: any) {
|
|
90
|
+
if (error.name === NoSuchBucket.name) {
|
|
91
|
+
throw new Error(
|
|
92
|
+
`S3 bucket '${this.bucketName}' does not exist. Please create the bucket first.`,
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
throw error;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
this.initialized = true;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* S3 buckets cannot be deleted programmatically via this method
|
|
103
|
+
*/
|
|
104
|
+
async deinit(): Promise<void> {
|
|
105
|
+
// We don't delete the bucket here, only via explicit resource deletion
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* List all resources in the state store
|
|
110
|
+
*/
|
|
111
|
+
async list(): Promise<string[]> {
|
|
112
|
+
await this.ensureInitialized();
|
|
113
|
+
|
|
114
|
+
const keys: string[] = [];
|
|
115
|
+
let continuationToken: string | undefined;
|
|
116
|
+
|
|
117
|
+
do {
|
|
118
|
+
const response = await retry(() =>
|
|
119
|
+
this.client.send(
|
|
120
|
+
new ListObjectsV2Command({
|
|
121
|
+
Bucket: this.bucketName,
|
|
122
|
+
Prefix: this.prefix,
|
|
123
|
+
ContinuationToken: continuationToken,
|
|
124
|
+
}),
|
|
125
|
+
),
|
|
126
|
+
);
|
|
127
|
+
|
|
128
|
+
if (response.Contents) {
|
|
129
|
+
keys.push(
|
|
130
|
+
...response.Contents.map((obj) => {
|
|
131
|
+
const key = obj.Key!.slice(this.prefix.length);
|
|
132
|
+
return this.convertKeyFromStorage(key);
|
|
133
|
+
}),
|
|
134
|
+
);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
continuationToken = response.NextContinuationToken;
|
|
138
|
+
} while (continuationToken);
|
|
139
|
+
|
|
140
|
+
return keys;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Count the number of items in the state store
|
|
145
|
+
*/
|
|
146
|
+
async count(): Promise<number> {
|
|
147
|
+
const keys = await this.list();
|
|
148
|
+
return keys.length;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Get a state by key
|
|
153
|
+
*
|
|
154
|
+
* @param key The key to look up
|
|
155
|
+
* @returns The state or undefined if not found
|
|
156
|
+
*/
|
|
157
|
+
async get(key: string): Promise<State | undefined> {
|
|
158
|
+
await this.ensureInitialized();
|
|
159
|
+
|
|
160
|
+
try {
|
|
161
|
+
const response = await retry(() =>
|
|
162
|
+
this.client.send(
|
|
163
|
+
new GetObjectCommand({
|
|
164
|
+
Bucket: this.bucketName,
|
|
165
|
+
Key: this.getObjectKey(key),
|
|
166
|
+
}),
|
|
167
|
+
),
|
|
168
|
+
);
|
|
169
|
+
|
|
170
|
+
if (!response.Body) {
|
|
171
|
+
return undefined;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// Read the stream into a string
|
|
175
|
+
const content = await response.Body.transformToString();
|
|
176
|
+
|
|
177
|
+
// Parse and deserialize the state data
|
|
178
|
+
const state = await deserializeState(this.scope, content);
|
|
179
|
+
|
|
180
|
+
// Create a new state object with proper output
|
|
181
|
+
return {
|
|
182
|
+
...state,
|
|
183
|
+
output: {
|
|
184
|
+
...(state.output || {}),
|
|
185
|
+
[ResourceScope]: this.scope,
|
|
186
|
+
},
|
|
187
|
+
};
|
|
188
|
+
} catch (error: any) {
|
|
189
|
+
if (error.name === NoSuchKey.name) {
|
|
190
|
+
return undefined;
|
|
191
|
+
}
|
|
192
|
+
throw error;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* Get multiple states by their keys
|
|
198
|
+
*
|
|
199
|
+
* @param ids Array of keys to fetch
|
|
200
|
+
* @returns Record mapping keys to their states
|
|
201
|
+
*/
|
|
202
|
+
async getBatch(ids: string[]): Promise<Record<string, State>> {
|
|
203
|
+
const result: Record<string, State> = {};
|
|
204
|
+
|
|
205
|
+
// S3 doesn't have a batch get operation, so we need to make multiple requests
|
|
206
|
+
const promises = ids.map(async (id) => {
|
|
207
|
+
const state = await this.get(id);
|
|
208
|
+
if (state) {
|
|
209
|
+
result[id] = state;
|
|
210
|
+
}
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
await Promise.all(promises);
|
|
214
|
+
return result;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* Get all states in the store
|
|
219
|
+
*
|
|
220
|
+
* @returns Record mapping all keys to their states
|
|
221
|
+
*/
|
|
222
|
+
async all(): Promise<Record<string, State>> {
|
|
223
|
+
const keys = await this.list();
|
|
224
|
+
return this.getBatch(keys);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* Set a state for a key
|
|
229
|
+
*
|
|
230
|
+
* @param key The key to set
|
|
231
|
+
* @param value The state to store
|
|
232
|
+
*/
|
|
233
|
+
async set(key: string, value: State): Promise<void> {
|
|
234
|
+
await this.ensureInitialized();
|
|
235
|
+
|
|
236
|
+
const objectKey = this.getObjectKey(key);
|
|
237
|
+
|
|
238
|
+
// Serialize the state to handle cyclic structures
|
|
239
|
+
const serializedData = JSON.stringify(
|
|
240
|
+
await serialize(this.scope, value),
|
|
241
|
+
null,
|
|
242
|
+
2,
|
|
243
|
+
);
|
|
244
|
+
|
|
245
|
+
await retry(() =>
|
|
246
|
+
this.client.send(
|
|
247
|
+
new PutObjectCommand({
|
|
248
|
+
Bucket: this.bucketName,
|
|
249
|
+
Key: objectKey,
|
|
250
|
+
Body: serializedData,
|
|
251
|
+
ContentType: "application/json",
|
|
252
|
+
}),
|
|
253
|
+
),
|
|
254
|
+
);
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
/**
|
|
258
|
+
* Delete a state by key
|
|
259
|
+
*
|
|
260
|
+
* @param key The key to delete
|
|
261
|
+
*/
|
|
262
|
+
async delete(key: string): Promise<void> {
|
|
263
|
+
await this.ensureInitialized();
|
|
264
|
+
|
|
265
|
+
await ignore(NoSuchKey.name, () =>
|
|
266
|
+
retry(() =>
|
|
267
|
+
this.client.send(
|
|
268
|
+
new DeleteObjectCommand({
|
|
269
|
+
Bucket: this.bucketName,
|
|
270
|
+
Key: this.getObjectKey(key),
|
|
271
|
+
}),
|
|
272
|
+
),
|
|
273
|
+
),
|
|
274
|
+
);
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
/**
|
|
278
|
+
* Convert key for storage by replacing slashes with colons
|
|
279
|
+
* since S3 treats slashes as directory separators
|
|
280
|
+
*
|
|
281
|
+
* @param key The original key
|
|
282
|
+
* @returns Key with slashes replaced by colons
|
|
283
|
+
*/
|
|
284
|
+
private convertKeyForStorage(key: string): string {
|
|
285
|
+
return key.replaceAll("/", ":");
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
/**
|
|
289
|
+
* Convert key from storage by replacing colons with slashes
|
|
290
|
+
*
|
|
291
|
+
* @param key The storage key
|
|
292
|
+
* @returns Key with colons replaced by slashes
|
|
293
|
+
*/
|
|
294
|
+
private convertKeyFromStorage(key: string): string {
|
|
295
|
+
return key.replaceAll(":", "/");
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
/**
|
|
299
|
+
* Get the full object key for storage
|
|
300
|
+
*
|
|
301
|
+
* @param key The original key
|
|
302
|
+
* @returns The key with prefix for use in the S3 bucket
|
|
303
|
+
*/
|
|
304
|
+
private getObjectKey(key: string): string {
|
|
305
|
+
return `${this.prefix}${this.convertKeyForStorage(key)}`;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
/**
|
|
309
|
+
* Ensure the store is initialized before operations
|
|
310
|
+
*/
|
|
311
|
+
private async ensureInitialized(): Promise<void> {
|
|
312
|
+
if (!this.initialized) {
|
|
313
|
+
await this.init();
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
}
|
package/src/cloudflare/index.ts
CHANGED
|
@@ -38,8 +38,8 @@ export * from "./r2-rest-state-store.ts";
|
|
|
38
38
|
export * from "./react-router.ts";
|
|
39
39
|
export * from "./redwood.ts";
|
|
40
40
|
export * from "./route.ts";
|
|
41
|
-
export * from "./secret.ts";
|
|
42
41
|
export * from "./secret-key.ts";
|
|
42
|
+
export * from "./secret.ts";
|
|
43
43
|
export * from "./secrets-store.ts";
|
|
44
44
|
export * from "./sveltekit.ts";
|
|
45
45
|
export * from "./tanstack-start.ts";
|
|
@@ -48,6 +48,7 @@ export * from "./vectorize-metadata-index.ts";
|
|
|
48
48
|
export * from "./version-metadata.ts";
|
|
49
49
|
export * from "./vite.ts";
|
|
50
50
|
export * from "./website.ts";
|
|
51
|
+
export * from "./worker-stub.ts";
|
|
51
52
|
export * from "./worker.ts";
|
|
52
53
|
export { Workflow } from "./workflow.ts";
|
|
53
54
|
export * from "./wrangler.json.ts";
|