tempo.ts 0.6.2 → 0.7.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.
Files changed (91) hide show
  1. package/CHANGELOG.md +134 -0
  2. package/README.md +6 -2
  3. package/dist/ox/Transaction.js +1 -1
  4. package/dist/ox/Transaction.js.map +1 -1
  5. package/dist/server/Handler.d.ts +346 -0
  6. package/dist/server/Handler.d.ts.map +1 -0
  7. package/dist/server/Handler.js +441 -0
  8. package/dist/server/Handler.js.map +1 -0
  9. package/dist/server/Kv.d.ts +16 -0
  10. package/dist/server/Kv.d.ts.map +1 -0
  11. package/dist/server/Kv.js +25 -0
  12. package/dist/server/Kv.js.map +1 -0
  13. package/dist/server/index.d.ts +3 -0
  14. package/dist/server/index.d.ts.map +1 -0
  15. package/dist/server/index.js +3 -0
  16. package/dist/server/index.js.map +1 -0
  17. package/dist/server/internal/requestListener.d.ts +124 -0
  18. package/dist/server/internal/requestListener.d.ts.map +1 -0
  19. package/dist/server/internal/requestListener.js +174 -0
  20. package/dist/server/internal/requestListener.js.map +1 -0
  21. package/dist/viem/Actions/amm.d.ts +9 -41
  22. package/dist/viem/Actions/amm.d.ts.map +1 -1
  23. package/dist/viem/Actions/amm.js +15 -26
  24. package/dist/viem/Actions/amm.js.map +1 -1
  25. package/dist/viem/Actions/reward.d.ts +0 -1067
  26. package/dist/viem/Actions/reward.d.ts.map +1 -1
  27. package/dist/viem/Actions/reward.js +4 -212
  28. package/dist/viem/Actions/reward.js.map +1 -1
  29. package/dist/viem/Decorator.d.ts +0 -263
  30. package/dist/viem/Decorator.d.ts.map +1 -1
  31. package/dist/viem/Decorator.js +0 -10
  32. package/dist/viem/Decorator.js.map +1 -1
  33. package/dist/viem/Storage.d.ts +23 -0
  34. package/dist/viem/Storage.d.ts.map +1 -0
  35. package/dist/viem/Storage.js +47 -0
  36. package/dist/viem/Storage.js.map +1 -0
  37. package/dist/viem/Transport.d.ts +10 -1
  38. package/dist/viem/Transport.d.ts.map +1 -1
  39. package/dist/viem/Transport.js +22 -3
  40. package/dist/viem/Transport.js.map +1 -1
  41. package/dist/viem/internal/utils.d.ts +6 -0
  42. package/dist/viem/internal/utils.d.ts.map +1 -1
  43. package/dist/viem/internal/utils.js +24 -0
  44. package/dist/viem/internal/utils.js.map +1 -1
  45. package/dist/wagmi/Actions/reward.d.ts +0 -110
  46. package/dist/wagmi/Actions/reward.d.ts.map +1 -1
  47. package/dist/wagmi/Actions/reward.js +0 -121
  48. package/dist/wagmi/Actions/reward.js.map +1 -1
  49. package/dist/wagmi/Connector.d.ts +6 -17
  50. package/dist/wagmi/Connector.d.ts.map +1 -1
  51. package/dist/wagmi/Connector.js +17 -43
  52. package/dist/wagmi/Connector.js.map +1 -1
  53. package/dist/wagmi/Hooks/reward.d.ts +0 -88
  54. package/dist/wagmi/Hooks/reward.d.ts.map +1 -1
  55. package/dist/wagmi/Hooks/reward.js +0 -103
  56. package/dist/wagmi/Hooks/reward.js.map +1 -1
  57. package/dist/wagmi/KeyManager.d.ts +57 -0
  58. package/dist/wagmi/KeyManager.d.ts.map +1 -0
  59. package/dist/wagmi/KeyManager.js +101 -0
  60. package/dist/wagmi/KeyManager.js.map +1 -0
  61. package/dist/wagmi/index.d.ts +1 -0
  62. package/dist/wagmi/index.d.ts.map +1 -1
  63. package/dist/wagmi/index.js +1 -0
  64. package/dist/wagmi/index.js.map +1 -1
  65. package/package.json +8 -2
  66. package/src/ox/Transaction.ts +1 -1
  67. package/src/ox/e2e.test.ts +7 -0
  68. package/src/server/Handler.test.ts +566 -0
  69. package/src/server/Handler.ts +577 -0
  70. package/src/server/Kv.ts +40 -0
  71. package/src/server/index.ts +2 -0
  72. package/src/server/internal/requestListener.ts +285 -0
  73. package/src/viem/Actions/amm.test.ts +10 -284
  74. package/src/viem/Actions/amm.ts +32 -40
  75. package/src/viem/Actions/reward.test.ts +4 -212
  76. package/src/viem/Actions/reward.ts +4 -291
  77. package/src/viem/Decorator.ts +0 -294
  78. package/src/viem/Storage.ts +88 -0
  79. package/src/viem/Transport.ts +40 -2
  80. package/src/viem/e2e.test.ts +106 -3
  81. package/src/viem/internal/utils.ts +21 -0
  82. package/src/wagmi/Actions/amm.test.ts +7 -85
  83. package/src/wagmi/Actions/reward.test.ts +0 -99
  84. package/src/wagmi/Actions/reward.ts +0 -203
  85. package/src/wagmi/Connector.test.ts +4 -1
  86. package/src/wagmi/Connector.ts +24 -58
  87. package/src/wagmi/Hooks/amm.test.ts +8 -200
  88. package/src/wagmi/Hooks/reward.test.ts +1 -142
  89. package/src/wagmi/Hooks/reward.ts +0 -196
  90. package/src/wagmi/KeyManager.ts +159 -0
  91. package/src/wagmi/index.ts +1 -0
@@ -0,0 +1,577 @@
1
+ import { createRouter, type Router } from '@remix-run/fetch-router'
2
+ import { RpcRequest, RpcResponse } from 'ox'
3
+ import * as Base64 from 'ox/Base64'
4
+ import * as Hex from 'ox/Hex'
5
+ import type * as WebAuthnP256 from 'ox/WebAuthnP256'
6
+ import { type Chain, type Client, createClient, type Transport } from 'viem'
7
+ import type { LocalAccount } from 'viem/accounts'
8
+ import { signTransaction } from 'viem/actions'
9
+ import type { OneOf } from '../internal/types.js'
10
+ import { formatTransaction } from '../viem/Formatters.js'
11
+ import * as Transaction from '../viem/Transaction.js'
12
+ import * as RequestListener from './internal/requestListener.js'
13
+ import type * as Kv from './Kv.js'
14
+
15
+ export type Handler = Router & {
16
+ listener: (req: any, res: any) => void
17
+ }
18
+
19
+ /**
20
+ * Instantiates a new request handler.
21
+ *
22
+ * @param options - constructor options
23
+ * @returns Handler instance
24
+ */
25
+ export function from(): Handler {
26
+ const router = createRouter()
27
+ return {
28
+ ...router,
29
+ listener: RequestListener.fromFetchHandler((request) => {
30
+ return router.fetch(request)
31
+ }),
32
+ }
33
+ }
34
+
35
+ /**
36
+ * Defines a Key Manager request handler.
37
+ *
38
+ * @example
39
+ * ### Cloudflare Worker
40
+ *
41
+ * ```ts
42
+ * import { env } from 'cloudflare:workers'
43
+ * import { Handler } from 'tempo.ts/server'
44
+ *
45
+ * export default {
46
+ * fetch(request) {
47
+ * return Handler.keyManager({
48
+ * kv: Kv.cloudflare(env.KEY_STORE),
49
+ * }).fetch(request)
50
+ * }
51
+ * }
52
+ * ```
53
+ *
54
+ * @example
55
+ * ### Next.js
56
+ *
57
+ * ```ts
58
+ * import { Handler } from 'tempo.ts/server'
59
+ *
60
+ * const handler = Handler.keyManager({
61
+ * kv: Kv.memory(),
62
+ * })
63
+ *
64
+ * export GET = handler.fetch
65
+ * export POST = handler.fetch
66
+ * ```
67
+ *
68
+ * @example
69
+ * ### Hono
70
+ *
71
+ * ```ts
72
+ * import { Handler } from 'tempo.ts/server'
73
+ *
74
+ * const handler = Handler.keyManager({
75
+ * kv: Kv.memory(),
76
+ * })
77
+ *
78
+ * const app = new Hono()
79
+ * app.all('*', handler)
80
+ *
81
+ * export default app
82
+ * ```
83
+ *
84
+ * @example
85
+ * ### Node.js
86
+ *
87
+ * ```ts
88
+ * import { Handler } from 'tempo.ts/server'
89
+ *
90
+ * const handler = Handler.keyManager({
91
+ * kv: Kv.memory(),
92
+ * })
93
+ *
94
+ * const server = createServer(handler.listener)
95
+ * server.listen(3000)
96
+ * ```
97
+ *
98
+ * @example
99
+ * ### Bun
100
+ *
101
+ * ```ts
102
+ * import { Handler } from 'tempo.ts/server'
103
+ *
104
+ * const handler = Handler.keyManager({
105
+ * kv: Kv.memory(),
106
+ * })
107
+ *
108
+ * Bun.serve(handler)
109
+ * ```
110
+ *
111
+ * @example
112
+ * ### Deno
113
+ *
114
+ * ```ts
115
+ * import { Handler } from 'tempo.ts/server'
116
+ *
117
+ * const handler = Handler.keyManager({
118
+ * kv: Kv.memory(),
119
+ * })
120
+ *
121
+ * Deno.serve(handler)
122
+ * ```
123
+ *
124
+ * @example
125
+ * ### Express
126
+ *
127
+ * ```ts
128
+ * import { Handler } from 'tempo.ts/server'
129
+ *
130
+ * const handler = Handler.keyManager({
131
+ * kv: Kv.memory(),
132
+ * })
133
+ *
134
+ * const app = express()
135
+ * app.use(handler.listener)
136
+ * app.listen(3000)
137
+ * ```
138
+ *
139
+ * @param options - Options.
140
+ * @returns Request handler.
141
+ */
142
+ export function keyManager(options: keyManager.Options) {
143
+ const { kv } = options
144
+
145
+ const path = options.path ?? ''
146
+
147
+ const rp = (() => {
148
+ if (typeof options.rp === 'string')
149
+ return { id: options.rp, name: options.rp }
150
+ if (options.rp)
151
+ return {
152
+ id: options.rp.id,
153
+ name: options.rp.name ?? options.rp.id,
154
+ }
155
+ return undefined
156
+ })()
157
+
158
+ const router = from()
159
+
160
+ // Get challenge for WebAuthn credential creation
161
+ router.get(`${path}/challenge`, async () => {
162
+ // Generate a random challenge
163
+ const challenge = Hex.random(32)
164
+
165
+ // Store challenge in KV with 5 minute expiration
166
+ await kv.set(`challenge:${challenge}`, '1')
167
+
168
+ return Response.json({
169
+ challenge,
170
+ ...(rp ? { rp } : {}),
171
+ } satisfies keyManager.ChallengeResponse)
172
+ })
173
+
174
+ // Get public key for a credential
175
+ router.get(`${path}/:id`, async ({ params }) => {
176
+ const { id } = params
177
+
178
+ const publicKey = await kv.get<Hex.Hex>(`credential:${id}`)
179
+
180
+ if (!publicKey) return new Response('Credential not found', { status: 404 })
181
+
182
+ return Response.json({
183
+ publicKey,
184
+ })
185
+ })
186
+
187
+ // Set public key for a credential
188
+ router.post(`${path}/:id`, async ({ params, request }) => {
189
+ const { id } = params
190
+ const { credential, publicKey } = (await request.json()) as any
191
+
192
+ if (!credential)
193
+ return Response.json({ error: 'Missing `credential`' }, { status: 400 })
194
+ if (!publicKey)
195
+ return Response.json({ error: 'Missing `publicKey`' }, { status: 400 })
196
+
197
+ // Decode and verify clientDataJSON
198
+ const clientDataJSON = JSON.parse(
199
+ Base64.toString(credential.response.clientDataJSON as unknown as string),
200
+ )
201
+
202
+ // Verify challenge
203
+ const challenge = Base64.toHex(clientDataJSON.challenge)
204
+
205
+ if (!(await kv.get<string>(`challenge:${challenge}`)))
206
+ return Response.json(
207
+ { error: 'Invalid or expired `challenge`' },
208
+ { status: 400 },
209
+ )
210
+
211
+ // Verify type
212
+ if (clientDataJSON.type !== 'webauthn.create')
213
+ return Response.json(
214
+ { error: 'Invalid `clientDataJSON.type`' },
215
+ { status: 400 },
216
+ )
217
+
218
+ // Verify origin
219
+ if (
220
+ rp?.id &&
221
+ !rp.id.includes('localhost') &&
222
+ clientDataJSON.origin !== new URL(`https://${rp.id}`).origin
223
+ )
224
+ return Response.json(
225
+ { error: 'Invalid `clientDataJSON.origin`' },
226
+ { status: 400 },
227
+ )
228
+
229
+ // Parse authenticatorData
230
+ const authenticatorData = Base64.toBytes(
231
+ (credential.response as any).authenticatorData,
232
+ )
233
+
234
+ // Parse flags (byte 32)
235
+ const flags = authenticatorData[32]
236
+ if (!flags)
237
+ return Response.json(
238
+ { error: 'Invalid `authenticatorData`' },
239
+ { status: 400 },
240
+ )
241
+
242
+ // Check User Present (UP) flag (bit 0)
243
+ const userPresent = (flags & 0x01) !== 0
244
+ if (!userPresent)
245
+ return Response.json({ error: 'User not present' }, { status: 400 })
246
+
247
+ // Consume the challenge (delete it so it can't be reused)
248
+ await kv.delete(`challenge:${challenge}`)
249
+
250
+ // Store the public key
251
+ await kv.set(`credential:${id}`, publicKey)
252
+
253
+ return new Response(null, { status: 204 })
254
+ })
255
+
256
+ return router
257
+ }
258
+
259
+ export declare namespace keyManager {
260
+ export type Options = {
261
+ /** The KV store to use for key management. */
262
+ kv: Kv.Kv
263
+ /** The path to use for the handler. */
264
+ path?: string | undefined
265
+ /** The RP to use for WebAuthn. */
266
+ rp?:
267
+ | string
268
+ | {
269
+ id: string
270
+ name?: string | undefined
271
+ }
272
+ | undefined
273
+ }
274
+
275
+ export type ChallengeResponse = {
276
+ challenge: Hex.Hex
277
+ rp?:
278
+ | {
279
+ id: string
280
+ name: string
281
+ }
282
+ | undefined
283
+ }
284
+
285
+ export type GetPublicKeyParameters = {
286
+ credential: WebAuthnP256.P256Credential['raw']
287
+ }
288
+
289
+ export type SetPublicKeyParameters = {
290
+ credential: WebAuthnP256.P256Credential['raw']
291
+ publicKey: Hex.Hex
292
+ }
293
+ }
294
+
295
+ /**
296
+ * Instantiates a fee payer service request handler that can be used to
297
+ * sponsor the fee for user transactions.
298
+ *
299
+ * @example
300
+ * ### Cloudflare Worker
301
+ *
302
+ * ```ts
303
+ * import { createClient, http } from 'viem'
304
+ * import { privateKeyToAccount } from 'viem/accounts'
305
+ * import { tempo } from 'tempo.ts/chains'
306
+ * import { Handler } from 'tempo.ts/server'
307
+ *
308
+ * const client = createClient({
309
+ * chain: tempo({ feeToken: '0x20c0000000000000000000000000000000000001' }),
310
+ * transport: http(),
311
+ * })
312
+ *
313
+ * export default {
314
+ * fetch(request) {
315
+ * return Handler.feePayer({
316
+ * account: privateKeyToAccount('0x...'),
317
+ * client,
318
+ * }).fetch(request)
319
+ * }
320
+ * }
321
+ * ```
322
+ *
323
+ * @example
324
+ * ### Next.js
325
+ *
326
+ * ```ts
327
+ * import { createClient, http } from 'viem'
328
+ * import { privateKeyToAccount } from 'viem/accounts'
329
+ * import { tempo } from 'tempo.ts/chains'
330
+ * import { Handler } from 'tempo.ts/server'
331
+ *
332
+ * const client = createClient({
333
+ * chain: tempo({ feeToken: '0x20c0000000000000000000000000000000000001' }),
334
+ * transport: http(),
335
+ * })
336
+ *
337
+ * const handler = Handler.feePayer({
338
+ * account: privateKeyToAccount('0x...'),
339
+ * client,
340
+ * })
341
+ *
342
+ * export GET = handler.fetch
343
+ * export POST = handler.fetch
344
+ * ```
345
+ *
346
+ * @example
347
+ * ### Hono
348
+ *
349
+ * ```ts
350
+ * import { createClient, http } from 'viem'
351
+ * import { privateKeyToAccount } from 'viem/accounts'
352
+ * import { tempo } from 'tempo.ts/chains'
353
+ * import { Handler } from 'tempo.ts/server'
354
+ *
355
+ * const client = createClient({
356
+ * chain: tempo({ feeToken: '0x20c0000000000000000000000000000000000001' }),
357
+ * transport: http(),
358
+ * })
359
+ *
360
+ * const handler = Handler.feePayer({
361
+ * account: privateKeyToAccount('0x...'),
362
+ * client,
363
+ * })
364
+ *
365
+ * const app = new Hono()
366
+ * app.all('*', handler)
367
+ *
368
+ * export default app
369
+ * ```
370
+ *
371
+ * @example
372
+ * ### Node.js
373
+ *
374
+ * ```ts
375
+ * import { createClient, http } from 'viem'
376
+ * import { privateKeyToAccount } from 'viem/accounts'
377
+ * import { tempo } from 'tempo.ts/chains'
378
+ * import { Handler } from 'tempo.ts/server'
379
+ *
380
+ * const client = createClient({
381
+ * chain: tempo({ feeToken: '0x20c0000000000000000000000000000000000001' }),
382
+ * transport: http(),
383
+ * })
384
+ *
385
+ * const handler = Handler.feePayer({
386
+ * account: privateKeyToAccount('0x...'),
387
+ * client,
388
+ * })
389
+ *
390
+ * const server = createServer(handler.listener)
391
+ * server.listen(3000)
392
+ * ```
393
+ *
394
+ * @example
395
+ * ### Bun
396
+ *
397
+ * ```ts
398
+ * import { createClient, http } from 'viem'
399
+ * import { privateKeyToAccount } from 'viem/accounts'
400
+ * import { tempo } from 'tempo.ts/chains'
401
+ * import { Handler } from 'tempo.ts/server'
402
+ *
403
+ * const client = createClient({
404
+ * account: privateKeyToAccount('0x...'),
405
+ * chain: tempo({
406
+ * feeToken: '0x20c0000000000000000000000000000000000001',
407
+ * }),
408
+ * transport: http(),
409
+ * })
410
+ *
411
+ * const handler = Handler.feePayer({
412
+ * account: privateKeyToAccount('0x...'),
413
+ * client,
414
+ * })
415
+ *
416
+ * Bun.serve(handler)
417
+ * ```
418
+ *
419
+ * @example
420
+ * ### Deno
421
+ *
422
+ * ```ts
423
+ * import { createClient, http } from 'viem'
424
+ * import { privateKeyToAccount } from 'viem/accounts'
425
+ * import { tempo } from 'tempo.ts/chains'
426
+ * import { Handler } from 'tempo.ts/server'
427
+ *
428
+ * const client = createClient({
429
+ * chain: tempo({ feeToken: '0x20c0000000000000000000000000000000000001' }),
430
+ * transport: http(),
431
+ * })
432
+ *
433
+ * const handler = Handler.feePayer({
434
+ * account: privateKeyToAccount('0x...'),
435
+ * client,
436
+ * })
437
+ *
438
+ * Deno.serve(handler)
439
+ * ```
440
+ *
441
+ * @example
442
+ * ### Express
443
+ *
444
+ * ```ts
445
+ * import { createClient, http } from 'viem'
446
+ * import { privateKeyToAccount } from 'viem/accounts'
447
+ * import { tempo } from 'tempo.ts/chains'
448
+ * import { Handler } from 'tempo.ts/server'
449
+ *
450
+ * const client = createClient({
451
+ * chain: tempo({ feeToken: '0x20c0000000000000000000000000000000000001' }),
452
+ * transport: http(),
453
+ * })
454
+ *
455
+ * const handler = Handler.feePayer({
456
+ * account: privateKeyToAccount('0x...'),
457
+ * client,
458
+ * })
459
+ *
460
+ * const app = express()
461
+ * app.use(handler.listener)
462
+ * app.listen(3000)
463
+ * ```
464
+ *
465
+ * @param options - Options.
466
+ * @returns Request handler.
467
+ */
468
+ export function feePayer(options: feePayer.Options) {
469
+ const { account, onRequest, path = '/' } = options
470
+
471
+ const client = (() => {
472
+ if ('client' in options) return options.client!
473
+ if ('chain' in options && 'transport' in options)
474
+ return createClient({
475
+ chain: options.chain,
476
+ transport: options.transport,
477
+ })
478
+ throw new Error('No client or chain provided')
479
+ })()
480
+
481
+ const router = from()
482
+
483
+ router.post(path, async ({ request: req }) => {
484
+ const request = RpcRequest.from((await req.json()) as any)
485
+
486
+ await onRequest?.(request)
487
+
488
+ if (request.method === 'eth_signTransaction') {
489
+ const transactionRequest = formatTransaction(request.params?.[0] as never)
490
+
491
+ const serializedTransaction = await signTransaction(client, {
492
+ ...transactionRequest,
493
+ account,
494
+ // @ts-expect-error
495
+ feePayer: account,
496
+ })
497
+
498
+ return Response.json(
499
+ RpcResponse.from({ result: serializedTransaction }, { request }),
500
+ )
501
+ }
502
+
503
+ if ((request as any).method === 'eth_signRawTransaction') {
504
+ const serialized = request.params?.[0] as `0x76${string}`
505
+ const transaction = Transaction.deserialize(serialized)
506
+
507
+ const serializedTransaction = await signTransaction(client, {
508
+ ...transaction,
509
+ account,
510
+ // @ts-expect-error
511
+ feePayer: account,
512
+ })
513
+
514
+ return Response.json(
515
+ RpcResponse.from({ result: serializedTransaction }, { request }),
516
+ )
517
+ }
518
+
519
+ if (
520
+ request.method === 'eth_sendRawTransaction' ||
521
+ request.method === 'eth_sendRawTransactionSync'
522
+ ) {
523
+ const serialized = request.params?.[0] as `0x76${string}`
524
+ const transaction = Transaction.deserialize(serialized)
525
+
526
+ const serializedTransaction = await signTransaction(client, {
527
+ ...transaction,
528
+ account,
529
+ // @ts-expect-error
530
+ feePayer: account,
531
+ })
532
+
533
+ const result = await client.request({
534
+ method: request.method,
535
+ params: [serializedTransaction],
536
+ })
537
+
538
+ return Response.json(RpcResponse.from({ result }, { request }))
539
+ }
540
+
541
+ return Response.json(
542
+ RpcResponse.from(
543
+ {
544
+ error: new RpcResponse.MethodNotSupportedError({
545
+ message: `Method not supported: ${request.method}`,
546
+ }),
547
+ },
548
+ { request },
549
+ ),
550
+ { status: 400 },
551
+ )
552
+ })
553
+
554
+ return router
555
+ }
556
+
557
+ export declare namespace feePayer {
558
+ export type Options = {
559
+ /** Account to use as the fee payer. */
560
+ account: LocalAccount
561
+ /** Function to call before handling the request. */
562
+ onRequest?: (request: RpcRequest.RpcRequest) => Promise<void>
563
+ /** Path to use for the handler. */
564
+ path?: string | undefined
565
+ } & OneOf<
566
+ | {
567
+ /** Client to use. */
568
+ client: Client
569
+ }
570
+ | {
571
+ /** Chain to use. */
572
+ chain: Chain
573
+ /** Transport to use. */
574
+ transport: Transport
575
+ }
576
+ >
577
+ }
@@ -0,0 +1,40 @@
1
+ export type Kv = {
2
+ get: <value = unknown>(key: string) => Promise<value>
3
+ set: (key: string, value: unknown) => Promise<void>
4
+ delete: (key: string) => Promise<void>
5
+ }
6
+
7
+ export function from<kv extends Kv>(kv: kv): kv {
8
+ return kv
9
+ }
10
+
11
+ export function cloudflare(kv: cloudflare.Parameters): Kv {
12
+ return from({
13
+ delete: kv.delete.bind(kv),
14
+ get: kv.get.bind(kv),
15
+ set: kv.put.bind(kv),
16
+ })
17
+ }
18
+
19
+ export declare namespace cloudflare {
20
+ export type Parameters = {
21
+ get: <value = unknown>(key: string) => Promise<value>
22
+ put: (key: string, value: any) => Promise<void>
23
+ delete: (key: string) => Promise<void>
24
+ }
25
+ }
26
+
27
+ export function memory(): Kv {
28
+ const store = new Map<string, unknown>()
29
+ return from({
30
+ async delete(key) {
31
+ Promise.resolve(store.delete(key))
32
+ },
33
+ async get(key) {
34
+ return store.get(key) as any
35
+ },
36
+ async set(key, value) {
37
+ store.set(key, value)
38
+ },
39
+ })
40
+ }
@@ -0,0 +1,2 @@
1
+ export * as Handler from './Handler.js'
2
+ export * as Kv from './Kv.js'