openwrangler 0.0.1 → 0.0.3

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/dist/index.d.mts CHANGED
@@ -4,12 +4,9 @@ interface BindingsConfig {
4
4
  accountId: string;
5
5
  apiToken: string;
6
6
  }
7
- interface Bindings {
8
- r2: R2Bucket;
9
- kv: KVNamespace;
10
- d1: D1Database;
11
- }
12
- declare function getBindings(config: BindingsConfig): Bindings;
7
+ declare function createR2Binding(config: BindingsConfig, bucketName: string): R2Bucket;
8
+ declare function createKVBinding(config: BindingsConfig, namespaceId: string): KVNamespace;
9
+ declare function createD1Binding(config: BindingsConfig, databaseId: string): D1Database;
13
10
 
14
- export { getBindings };
15
- export type { Bindings, BindingsConfig };
11
+ export { createD1Binding, createKVBinding, createR2Binding };
12
+ export type { BindingsConfig };
package/dist/index.d.ts CHANGED
@@ -4,12 +4,9 @@ interface BindingsConfig {
4
4
  accountId: string;
5
5
  apiToken: string;
6
6
  }
7
- interface Bindings {
8
- r2: R2Bucket;
9
- kv: KVNamespace;
10
- d1: D1Database;
11
- }
12
- declare function getBindings(config: BindingsConfig): Bindings;
7
+ declare function createR2Binding(config: BindingsConfig, bucketName: string): R2Bucket;
8
+ declare function createKVBinding(config: BindingsConfig, namespaceId: string): KVNamespace;
9
+ declare function createD1Binding(config: BindingsConfig, databaseId: string): D1Database;
13
10
 
14
- export { getBindings };
15
- export type { Bindings, BindingsConfig };
11
+ export { createD1Binding, createKVBinding, createR2Binding };
12
+ export type { BindingsConfig };
package/dist/index.mjs CHANGED
@@ -1,18 +1,398 @@
1
- function getBindings(config) {
1
+ class CloudflareAPIClient {
2
+ baseUrl = "https://api.cloudflare.com/client/v4";
3
+ accountId;
4
+ apiToken;
5
+ constructor(accountId, apiToken) {
6
+ this.accountId = accountId;
7
+ this.apiToken = apiToken;
8
+ }
9
+ async request(method, endpoint, body, headers) {
10
+ const url = `${this.baseUrl}${endpoint}`;
11
+ const response = await fetch(url, {
12
+ method,
13
+ headers: {
14
+ "Authorization": `Bearer ${this.apiToken}`,
15
+ "Content-Type": "application/json",
16
+ ...headers
17
+ },
18
+ body: body ? JSON.stringify(body) : void 0
19
+ });
20
+ const data = await response.json();
21
+ if (!response.ok || !data.success) {
22
+ const errorMessage = data.errors?.[0]?.message || `HTTP ${response.status}`;
23
+ throw new Error(`Cloudflare API Error: ${errorMessage}`);
24
+ }
25
+ return data.result;
26
+ }
27
+ async get(endpoint, headers) {
28
+ return this.request("GET", endpoint, void 0, headers);
29
+ }
30
+ async post(endpoint, body, headers) {
31
+ return this.request("POST", endpoint, body, headers);
32
+ }
33
+ async put(endpoint, body, headers) {
34
+ return this.request("PUT", endpoint, body, headers);
35
+ }
36
+ async delete(endpoint, body, headers) {
37
+ return this.request("DELETE", endpoint, body, headers);
38
+ }
39
+ getAccountId() {
40
+ return this.accountId;
41
+ }
42
+ }
43
+
44
+ function createKVBinding$1(client, namespaceId) {
45
+ const baseEndpoint = `/accounts/${client.getAccountId()}/storage/kv/namespaces/${namespaceId}`;
46
+ async function getValue(key, type, cacheTtl) {
47
+ try {
48
+ const url = `${baseEndpoint}/values/${encodeURIComponent(key)}`;
49
+ const headers = {};
50
+ if (cacheTtl !== void 0) {
51
+ headers["Cache-Control"] = `max-age=${cacheTtl}`;
52
+ }
53
+ const response = await fetch(`https://api.cloudflare.com/client/v4${url}`, {
54
+ method: "GET",
55
+ headers: {
56
+ "Authorization": `Bearer ${client.apiToken}`,
57
+ ...headers
58
+ }
59
+ });
60
+ if (response.status === 404) {
61
+ return null;
62
+ }
63
+ if (!response.ok) {
64
+ throw new Error(`KV GET failed: ${response.status}`);
65
+ }
66
+ switch (type) {
67
+ case "json":
68
+ return await response.json();
69
+ case "arrayBuffer":
70
+ return await response.arrayBuffer();
71
+ case "stream":
72
+ return response.body;
73
+ case "text":
74
+ default:
75
+ return await response.text();
76
+ }
77
+ } catch (error) {
78
+ if (error?.message?.includes("404")) {
79
+ return null;
80
+ }
81
+ throw error;
82
+ }
83
+ }
84
+ async function getValueWithMetadata(key, type) {
85
+ try {
86
+ const url = `${baseEndpoint}/values/${encodeURIComponent(key)}`;
87
+ const response = await fetch(`https://api.cloudflare.com/client/v4${url}`, {
88
+ method: "GET",
89
+ headers: {
90
+ "Authorization": `Bearer ${client.apiToken}`
91
+ }
92
+ });
93
+ if (response.status === 404) {
94
+ return { value: null, metadata: null, cacheStatus: null };
95
+ }
96
+ if (!response.ok) {
97
+ throw new Error(`KV GET failed: ${response.status}`);
98
+ }
99
+ const metadata = response.headers.get("cf-kv-metadata");
100
+ const parsedMetadata = metadata ? JSON.parse(metadata) : null;
101
+ let value;
102
+ switch (type) {
103
+ case "json":
104
+ value = await response.json();
105
+ break;
106
+ case "arrayBuffer":
107
+ value = await response.arrayBuffer();
108
+ break;
109
+ case "stream":
110
+ value = response.body;
111
+ break;
112
+ case "text":
113
+ default:
114
+ value = await response.text();
115
+ }
116
+ return {
117
+ value,
118
+ metadata: parsedMetadata,
119
+ cacheStatus: response.headers.get("cf-cache-status")
120
+ };
121
+ } catch (error) {
122
+ if (error?.message?.includes("404")) {
123
+ return { value: null, metadata: null, cacheStatus: null };
124
+ }
125
+ throw error;
126
+ }
127
+ }
128
+ const kvNamespace = {
129
+ async get(key, options) {
130
+ if (Array.isArray(key)) {
131
+ const type2 = typeof options === "string" ? options : options?.type || "text";
132
+ const results = /* @__PURE__ */ new Map();
133
+ for (const k of key) {
134
+ const value = await getValue(k, type2, options?.cacheTtl);
135
+ results.set(k, value);
136
+ }
137
+ return results;
138
+ }
139
+ const type = typeof options === "string" ? options : options?.type;
140
+ return getValue(key, type, options?.cacheTtl);
141
+ },
142
+ async put(key, value, options) {
143
+ const url = `${baseEndpoint}/values/${encodeURIComponent(key)}`;
144
+ const headers = {
145
+ "Authorization": `Bearer ${client.apiToken}`
146
+ };
147
+ let body;
148
+ if (typeof value === "string") {
149
+ body = value;
150
+ } else if (value instanceof ArrayBuffer) {
151
+ body = value;
152
+ } else if (ArrayBuffer.isView(value)) {
153
+ body = value.buffer.slice(value.byteOffset, value.byteOffset + value.byteLength);
154
+ } else if (value instanceof ReadableStream) {
155
+ const reader = value.getReader();
156
+ const chunks = [];
157
+ while (true) {
158
+ const { done, value: chunk } = await reader.read();
159
+ if (done) break;
160
+ chunks.push(chunk);
161
+ }
162
+ const totalLength = chunks.reduce((acc, chunk) => acc + chunk.length, 0);
163
+ const result = new Uint8Array(totalLength);
164
+ let offset = 0;
165
+ for (const chunk of chunks) {
166
+ result.set(chunk, offset);
167
+ offset += chunk.length;
168
+ }
169
+ body = result.buffer;
170
+ } else {
171
+ throw new Error("Unsupported value type");
172
+ }
173
+ const queryParams = new URLSearchParams();
174
+ if (options?.expiration) {
175
+ queryParams.set("expiration", options.expiration.toString());
176
+ }
177
+ if (options?.expirationTtl) {
178
+ queryParams.set("expiration_ttl", options.expirationTtl.toString());
179
+ }
180
+ const queryString = queryParams.toString();
181
+ const fullUrl = queryString ? `${url}?${queryString}` : url;
182
+ const response = await fetch(`https://api.cloudflare.com/client/v4${fullUrl}`, {
183
+ method: "PUT",
184
+ headers,
185
+ body
186
+ });
187
+ if (!response.ok) {
188
+ throw new Error(`KV PUT failed: ${response.status}`);
189
+ }
190
+ },
191
+ async delete(key) {
192
+ const url = `${baseEndpoint}/values/${encodeURIComponent(key)}`;
193
+ const response = await fetch(`https://api.cloudflare.com/client/v4${url}`, {
194
+ method: "DELETE",
195
+ headers: {
196
+ "Authorization": `Bearer ${client.apiToken}`
197
+ }
198
+ });
199
+ if (!response.ok && response.status !== 404) {
200
+ throw new Error(`KV DELETE failed: ${response.status}`);
201
+ }
202
+ },
203
+ async deleteBulk(keys) {
204
+ const keyArray = Array.isArray(keys) ? keys : [keys];
205
+ const url = `${baseEndpoint}/bulk`;
206
+ const response = await fetch(`https://api.cloudflare.com/client/v4${url}`, {
207
+ method: "DELETE",
208
+ headers: {
209
+ "Authorization": `Bearer ${client.apiToken}`,
210
+ "Content-Type": "application/json"
211
+ },
212
+ body: JSON.stringify(keyArray)
213
+ });
214
+ if (!response.ok) {
215
+ throw new Error(`KV DELETE BULK failed: ${response.status}`);
216
+ }
217
+ },
218
+ async list(options) {
219
+ const queryParams = new URLSearchParams();
220
+ if (options?.limit) {
221
+ queryParams.set("limit", options.limit.toString());
222
+ }
223
+ if (options?.prefix) {
224
+ queryParams.set("prefix", options.prefix);
225
+ }
226
+ if (options?.cursor) {
227
+ queryParams.set("cursor", options.cursor);
228
+ }
229
+ const queryString = queryParams.toString();
230
+ const url = queryString ? `${baseEndpoint}/keys?${queryString}` : `${baseEndpoint}/keys`;
231
+ const data = await client.get(url);
232
+ if (data.list_complete) {
233
+ return {
234
+ list_complete: true,
235
+ keys: data.keys.map((k) => ({
236
+ name: k.name,
237
+ expiration: k.expiration,
238
+ metadata: k.metadata
239
+ })),
240
+ cacheStatus: null
241
+ };
242
+ } else {
243
+ return {
244
+ list_complete: false,
245
+ keys: data.keys.map((k) => ({
246
+ name: k.name,
247
+ expiration: k.expiration,
248
+ metadata: k.metadata
249
+ })),
250
+ cursor: data.cursor,
251
+ cacheStatus: null
252
+ };
253
+ }
254
+ },
255
+ async getWithMetadata(key, options) {
256
+ if (Array.isArray(key)) {
257
+ const type2 = typeof options === "string" ? options : options?.type || "text";
258
+ const results = /* @__PURE__ */ new Map();
259
+ for (const k of key) {
260
+ const result = await getValueWithMetadata(k, type2);
261
+ results.set(k, result);
262
+ }
263
+ return results;
264
+ }
265
+ const type = typeof options === "string" ? options : options?.type;
266
+ return getValueWithMetadata(key, type);
267
+ }
268
+ };
269
+ return kvNamespace;
270
+ }
271
+
272
+ class D1PreparedStatementImpl {
273
+ constructor(query, client, databaseId) {
274
+ this.query = query;
275
+ this.client = client;
276
+ this.databaseId = databaseId;
277
+ }
278
+ bindings = [];
279
+ bind(...values) {
280
+ this.bindings = values;
281
+ return this;
282
+ }
283
+ async run() {
284
+ const endpoint = `/accounts/${this.client.getAccountId()}/d1/database/${this.databaseId}/query`;
285
+ const data = await this.client.post(endpoint, {
286
+ sql: this.query,
287
+ params: this.bindings
288
+ });
289
+ const result = data[0];
290
+ return {
291
+ success: result.success,
292
+ results: result.results,
293
+ meta: {
294
+ served_by: result.meta.served_by || "",
295
+ duration: result.meta.duration || 0,
296
+ changes: result.meta.changes || 0,
297
+ last_row_id: result.meta.last_row_id || 0,
298
+ changed_db: result.meta.changed_db || false,
299
+ size_after: result.meta.size_after || 0,
300
+ rows_read: result.meta.rows_read || 0,
301
+ rows_written: result.meta.rows_written || 0
302
+ }
303
+ };
304
+ }
305
+ async all() {
306
+ return this.run();
307
+ }
308
+ async first(colName) {
309
+ const result = await this.run();
310
+ if (!result.results || result.results.length === 0) {
311
+ return null;
312
+ }
313
+ const firstRow = result.results[0];
314
+ if (colName && typeof firstRow === "object" && firstRow !== null) {
315
+ return firstRow[colName] ?? null;
316
+ }
317
+ return firstRow;
318
+ }
319
+ async raw(options) {
320
+ const result = await this.run();
321
+ if (!result.results || result.results.length === 0) {
322
+ return [];
323
+ }
324
+ const raw = result.results.map((row) => {
325
+ if (typeof row === "object" && row !== null) {
326
+ return Object.values(row);
327
+ }
328
+ return row;
329
+ });
330
+ if (options?.columnNames && result.results.length > 0) {
331
+ const firstRow = result.results[0];
332
+ if (typeof firstRow === "object" && firstRow !== null) {
333
+ const columnNames = Object.keys(firstRow);
334
+ return [columnNames, ...raw];
335
+ }
336
+ }
337
+ return raw;
338
+ }
339
+ }
340
+ function createD1Binding$1(client, databaseId) {
2
341
  return {
3
- r2: createR2Binding(),
4
- kv: createKVBinding(),
5
- d1: createD1Binding()
342
+ prepare(query) {
343
+ return new D1PreparedStatementImpl(query, client, databaseId);
344
+ },
345
+ async batch(statements) {
346
+ const endpoint = `/accounts/${client.getAccountId()}/d1/database/${databaseId}/query`;
347
+ const queries = statements.map((stmt) => {
348
+ const impl = stmt;
349
+ return {
350
+ sql: impl.query,
351
+ params: impl.bindings
352
+ };
353
+ });
354
+ const data = await client.post(endpoint, queries);
355
+ return data.map((result) => ({
356
+ success: result.success,
357
+ results: result.results,
358
+ meta: {
359
+ served_by: result.meta.served_by || "",
360
+ duration: result.meta.duration || 0,
361
+ changes: result.meta.changes || 0,
362
+ last_row_id: result.meta.last_row_id || 0,
363
+ changed_db: result.meta.changed_db || false,
364
+ size_after: result.meta.size_after || 0,
365
+ rows_read: result.meta.rows_read || 0,
366
+ rows_written: result.meta.rows_written || 0
367
+ }
368
+ }));
369
+ },
370
+ async exec(query) {
371
+ const endpoint = `/accounts/${client.getAccountId()}/d1/database/${databaseId}/query`;
372
+ const data = await client.post(endpoint, {
373
+ sql: query
374
+ });
375
+ return {
376
+ count: data.length,
377
+ duration: data.reduce((acc, r) => acc + (r.meta.duration || 0), 0)
378
+ };
379
+ },
380
+ dump() {
381
+ throw new Error("D1 dump() is deprecated and not supported");
382
+ }
6
383
  };
7
384
  }
8
- function createR2Binding(config) {
9
- throw new Error("Not implemented");
385
+
386
+ function createR2Binding(config, bucketName) {
387
+ throw new Error("R2 binding not yet implemented. Use KV or D1 instead.");
10
388
  }
11
- function createKVBinding(config) {
12
- throw new Error("Not implemented");
389
+ function createKVBinding(config, namespaceId) {
390
+ const client = new CloudflareAPIClient(config.accountId, config.apiToken);
391
+ return createKVBinding$1(client, namespaceId);
13
392
  }
14
- function createD1Binding(config) {
15
- throw new Error("Not implemented");
393
+ function createD1Binding(config, databaseId) {
394
+ const client = new CloudflareAPIClient(config.accountId, config.apiToken);
395
+ return createD1Binding$1(client, databaseId);
16
396
  }
17
397
 
18
- export { getBindings };
398
+ export { createD1Binding, createKVBinding, createR2Binding };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openwrangler",
3
- "version": "0.0.1",
3
+ "version": "0.0.3",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": {
@@ -13,16 +13,16 @@
13
13
  "files": [
14
14
  "dist"
15
15
  ],
16
- "scripts": {
17
- "dev": "nuxi dev playground",
18
- "build": "unbuild"
19
- },
20
16
  "devDependencies": {
21
- "@binochoi/nitro-cloudflare-dev": "workspace:*",
22
17
  "@cloudflare/workers-types": "^4.20251231.0",
23
18
  "nuxt": "^3.15.0",
24
19
  "typescript": "^5.7.2",
25
20
  "unbuild": "^3.3.1",
26
- "wrangler": "^3.99.0"
21
+ "wrangler": "^3.99.0",
22
+ "@binochoi/nitro-cloudflare-dev": "npm:@bino0216/nitro-cloudflare-dev@0.2.5"
23
+ },
24
+ "scripts": {
25
+ "dev": "nuxi dev playground",
26
+ "build": "unbuild"
27
27
  }
28
- }
28
+ }