tapimo 0.4.1 → 0.4.4

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 (263) hide show
  1. package/README.md +1 -1
  2. package/dist/ApiKey.d.ts +1 -9
  3. package/dist/ApiKey.d.ts.map +1 -1
  4. package/dist/ApiKey.js +2 -3
  5. package/dist/ApiKey.js.map +1 -1
  6. package/dist/ApiKeys.d.ts +53 -27
  7. package/dist/ApiKeys.d.ts.map +1 -1
  8. package/dist/ApiKeys.js +32 -17
  9. package/dist/ApiKeys.js.map +1 -1
  10. package/dist/App.d.ts +1990 -1442
  11. package/dist/App.d.ts.map +1 -1
  12. package/dist/App.js +23 -9
  13. package/dist/App.js.map +1 -1
  14. package/dist/Assets.d.ts +10 -0
  15. package/dist/Assets.d.ts.map +1 -1
  16. package/dist/Assets.js +4 -0
  17. package/dist/Assets.js.map +1 -1
  18. package/dist/Auth.d.ts +2 -1
  19. package/dist/Auth.d.ts.map +1 -1
  20. package/dist/Auth.js +2 -1
  21. package/dist/Auth.js.map +1 -1
  22. package/dist/Scope.d.ts +40 -15
  23. package/dist/Scope.d.ts.map +1 -1
  24. package/dist/Scope.js +44 -13
  25. package/dist/Scope.js.map +1 -1
  26. package/dist/admin/App.d.ts +560 -9
  27. package/dist/admin/App.d.ts.map +1 -1
  28. package/dist/admin/App.js +38 -6
  29. package/dist/admin/App.js.map +1 -1
  30. package/dist/admin/apps/api-keys.d.ts +10 -24
  31. package/dist/admin/apps/api-keys.d.ts.map +1 -1
  32. package/dist/admin/apps/api-keys.js +10 -3
  33. package/dist/admin/apps/api-keys.js.map +1 -1
  34. package/dist/admin/apps/organizations.d.ts +833 -0
  35. package/dist/admin/apps/organizations.d.ts.map +1 -0
  36. package/dist/admin/apps/organizations.js +733 -0
  37. package/dist/admin/apps/organizations.js.map +1 -0
  38. package/dist/admin/apps/scopes.d.ts +8 -0
  39. package/dist/admin/apps/scopes.d.ts.map +1 -1
  40. package/dist/admin/apps/verified-tokens.d.ts +57 -57
  41. package/dist/admin/ui.generated.d.ts +1 -1
  42. package/dist/admin/ui.generated.d.ts.map +1 -1
  43. package/dist/admin/ui.generated.js +53 -13
  44. package/dist/admin/ui.generated.js.map +1 -1
  45. package/dist/analytics/Analytics.d.ts +10 -0
  46. package/dist/analytics/Analytics.d.ts.map +1 -1
  47. package/dist/analytics/Analytics.js +8 -0
  48. package/dist/analytics/Analytics.js.map +1 -1
  49. package/dist/analytics/tables/requestEvents.d.ts +9 -0
  50. package/dist/analytics/tables/requestEvents.d.ts.map +1 -1
  51. package/dist/analytics/tables/requestEvents.js +14 -0
  52. package/dist/analytics/tables/requestEvents.js.map +1 -1
  53. package/dist/apps/data/App.d.ts +1304 -1304
  54. package/dist/apps/data/FundingRouteProviders.d.ts +4 -22
  55. package/dist/apps/data/FundingRouteProviders.d.ts.map +1 -1
  56. package/dist/apps/data/FundingRouteProviders.js +10 -120
  57. package/dist/apps/data/FundingRouteProviders.js.map +1 -1
  58. package/dist/apps/data/routes/activities.d.ts +38 -38
  59. package/dist/apps/data/routes/addresses.d.ts +24 -24
  60. package/dist/apps/data/routes/blocks.d.ts +39 -39
  61. package/dist/apps/data/routes/fee-amm.d.ts +20 -20
  62. package/dist/apps/data/routes/funding.js +7 -7
  63. package/dist/apps/data/routes/funding.js.map +1 -1
  64. package/dist/apps/data/routes/indexer.d.ts +5 -5
  65. package/dist/apps/data/routes/tokenlist.d.ts +12 -12
  66. package/dist/apps/data/routes/verified-tokens.d.ts +36 -36
  67. package/dist/apps/management/App.d.ts +808 -267
  68. package/dist/apps/management/App.d.ts.map +1 -1
  69. package/dist/apps/management/App.js +2 -2
  70. package/dist/apps/management/Billing.d.ts +3 -0
  71. package/dist/apps/management/Billing.d.ts.map +1 -1
  72. package/dist/apps/management/Billing.js +7 -2
  73. package/dist/apps/management/Billing.js.map +1 -1
  74. package/dist/apps/management/routes/api-keys.d.ts +116 -100
  75. package/dist/apps/management/routes/api-keys.d.ts.map +1 -1
  76. package/dist/apps/management/routes/api-keys.js +41 -30
  77. package/dist/apps/management/routes/api-keys.js.map +1 -1
  78. package/dist/apps/management/routes/billing.d.ts +182 -50
  79. package/dist/apps/management/routes/billing.d.ts.map +1 -1
  80. package/dist/apps/management/routes/billing.js +14 -14
  81. package/dist/apps/management/routes/billing.js.map +1 -1
  82. package/dist/apps/management/routes/invitations.d.ts +93 -20
  83. package/dist/apps/management/routes/invitations.d.ts.map +1 -1
  84. package/dist/apps/management/routes/invitations.js +12 -15
  85. package/dist/apps/management/routes/invitations.js.map +1 -1
  86. package/dist/apps/management/routes/members.d.ts +89 -18
  87. package/dist/apps/management/routes/members.d.ts.map +1 -1
  88. package/dist/apps/management/routes/members.js +10 -10
  89. package/dist/apps/management/routes/members.js.map +1 -1
  90. package/dist/apps/management/routes/orgs.d.ts +100 -40
  91. package/dist/apps/management/routes/orgs.d.ts.map +1 -1
  92. package/dist/apps/management/routes/orgs.js +19 -19
  93. package/dist/apps/management/routes/orgs.js.map +1 -1
  94. package/dist/apps/management/routes/projects.d.ts +122 -33
  95. package/dist/apps/management/routes/projects.d.ts.map +1 -1
  96. package/dist/apps/management/routes/projects.js +12 -13
  97. package/dist/apps/management/routes/projects.js.map +1 -1
  98. package/dist/apps/management/routes/scopes.d.ts +4 -18
  99. package/dist/apps/management/routes/scopes.d.ts.map +1 -1
  100. package/dist/apps/management/routes/scopes.js +6 -7
  101. package/dist/apps/management/routes/scopes.js.map +1 -1
  102. package/dist/apps/management/routes/usage.d.ts +63 -19
  103. package/dist/apps/management/routes/usage.d.ts.map +1 -1
  104. package/dist/apps/management/routes/usage.js +9 -10
  105. package/dist/apps/management/routes/usage.js.map +1 -1
  106. package/dist/apps/mcp.d.ts.map +1 -1
  107. package/dist/apps/mcp.js +38 -4
  108. package/dist/apps/mcp.js.map +1 -1
  109. package/dist/apps/relay/App.d.ts +26 -4
  110. package/dist/apps/relay/App.d.ts.map +1 -1
  111. package/dist/apps/relay/App.js +17 -14
  112. package/dist/apps/relay/App.js.map +1 -1
  113. package/dist/cloudflare.d.ts +2 -0
  114. package/dist/cloudflare.d.ts.map +1 -1
  115. package/dist/cloudflare.js +4 -0
  116. package/dist/cloudflare.js.map +1 -1
  117. package/dist/db/Db.d.ts +5 -3
  118. package/dist/db/Db.d.ts.map +1 -1
  119. package/dist/db/Db.js +52 -0
  120. package/dist/db/Db.js.map +1 -1
  121. package/dist/db/Schema.d.ts +13 -0
  122. package/dist/db/Schema.d.ts.map +1 -1
  123. package/dist/db/Schema.js +16 -1
  124. package/dist/db/Schema.js.map +1 -1
  125. package/dist/db/tables/adminAuditLogs.d.ts +27 -0
  126. package/dist/db/tables/adminAuditLogs.d.ts.map +1 -0
  127. package/dist/db/tables/adminAuditLogs.js +19 -0
  128. package/dist/db/tables/adminAuditLogs.js.map +1 -0
  129. package/dist/db/tables/invitations.d.ts +1 -1
  130. package/dist/db/tables/invitations.d.ts.map +1 -1
  131. package/dist/db/tables/memberships.d.ts +32 -4
  132. package/dist/db/tables/memberships.d.ts.map +1 -1
  133. package/dist/db/tables/memberships.js +31 -0
  134. package/dist/db/tables/memberships.js.map +1 -1
  135. package/dist/db/tables/organizations.d.ts +43 -1
  136. package/dist/db/tables/organizations.d.ts.map +1 -1
  137. package/dist/db/tables/organizations.js +103 -0
  138. package/dist/db/tables/organizations.js.map +1 -1
  139. package/dist/db/tables/projects.d.ts +25 -0
  140. package/dist/db/tables/projects.d.ts.map +1 -1
  141. package/dist/db/tables/projects.js +22 -0
  142. package/dist/db/tables/projects.js.map +1 -1
  143. package/dist/db/tables/webhookDeliveries.d.ts +26 -0
  144. package/dist/db/tables/webhookDeliveries.d.ts.map +1 -1
  145. package/dist/db/tables/webhookDeliveries.js +37 -0
  146. package/dist/db/tables/webhookDeliveries.js.map +1 -1
  147. package/dist/internal/Auth.d.ts +46 -40
  148. package/dist/internal/Auth.d.ts.map +1 -1
  149. package/dist/internal/Auth.js +118 -69
  150. package/dist/internal/Auth.js.map +1 -1
  151. package/dist/internal/Cursor.d.ts +1 -1
  152. package/dist/internal/Cursor.d.ts.map +1 -1
  153. package/dist/internal/Cursor.js +4 -0
  154. package/dist/internal/Cursor.js.map +1 -1
  155. package/dist/internal/EdgeCache.d.ts.map +1 -1
  156. package/dist/internal/EdgeCache.js +2 -0
  157. package/dist/internal/EdgeCache.js.map +1 -1
  158. package/dist/internal/Errors.d.ts +6 -0
  159. package/dist/internal/Errors.d.ts.map +1 -0
  160. package/dist/internal/Errors.js +16 -0
  161. package/dist/internal/Errors.js.map +1 -0
  162. package/dist/internal/FundingRoutes.d.ts +15 -43
  163. package/dist/internal/FundingRoutes.d.ts.map +1 -1
  164. package/dist/internal/FundingRoutes.js +8 -17
  165. package/dist/internal/FundingRoutes.js.map +1 -1
  166. package/dist/internal/Log.d.ts +16 -1
  167. package/dist/internal/Log.d.ts.map +1 -1
  168. package/dist/internal/Log.js +5 -3
  169. package/dist/internal/Log.js.map +1 -1
  170. package/dist/internal/Store.d.ts +61 -16
  171. package/dist/internal/Store.d.ts.map +1 -1
  172. package/dist/internal/Store.js +72 -17
  173. package/dist/internal/Store.js.map +1 -1
  174. package/dist/internal/Viem.d.ts +1 -1
  175. package/dist/internal/index.d.ts +27 -0
  176. package/dist/internal/index.d.ts.map +1 -0
  177. package/dist/internal/index.js +27 -0
  178. package/dist/internal/index.js.map +1 -0
  179. package/package.json +8 -3
  180. package/src/ApiKey.ts +2 -3
  181. package/src/ApiKeys.ts +95 -17
  182. package/src/App.test.ts +104 -6
  183. package/src/App.ts +29 -9
  184. package/src/Assets.ts +8 -0
  185. package/src/Auth.test-d.ts +36 -0
  186. package/src/Auth.ts +20 -1
  187. package/src/Client.test-d.ts +17 -17
  188. package/src/Scope.test.ts +34 -0
  189. package/src/Scope.ts +53 -17
  190. package/src/admin/App.test.ts +33 -3
  191. package/src/admin/App.ts +49 -14
  192. package/src/admin/apps/api-keys.ts +10 -3
  193. package/src/admin/apps/organizations.test.ts +455 -0
  194. package/src/admin/apps/organizations.ts +953 -0
  195. package/src/admin/apps/scopes.test.ts +10 -0
  196. package/src/admin/ui/plugin.ts +1 -1
  197. package/src/admin/ui/src/components/MobileProfile.tsx +2 -0
  198. package/src/admin/ui/src/components/ThemeToggle.tsx +20 -0
  199. package/src/admin/ui/src/lib/api-keys.ts +36 -19
  200. package/src/admin/ui/src/lib/config.ts +2 -3
  201. package/src/admin/ui/src/lib/organizations.test.ts +89 -0
  202. package/src/admin/ui/src/lib/organizations.ts +262 -0
  203. package/src/admin/ui/src/lib/query-client.ts +3 -1
  204. package/src/admin/ui/src/lib/theme.ts +57 -0
  205. package/src/admin/ui/src/routeTree.gen.ts +47 -4
  206. package/src/admin/ui/src/routes/__root.tsx +18 -3
  207. package/src/admin/ui/src/routes/api-keys.tsx +52 -7
  208. package/src/admin/ui/src/routes/index.tsx +1 -1
  209. package/src/admin/ui/src/routes/organizations.tsx +158 -0
  210. package/src/admin/ui/src/routes/organizations_.$orgId.tsx +710 -0
  211. package/src/admin/ui/src/start.ts +6 -0
  212. package/src/admin/ui.generated.ts +63 -13
  213. package/src/analytics/Analytics.ts +25 -0
  214. package/src/analytics/tables/requestEvents.ts +33 -0
  215. package/src/apps/composition.test.ts +82 -2
  216. package/src/apps/data/FundingRouteProviders.test.ts +37 -93
  217. package/src/apps/data/FundingRouteProviders.ts +14 -161
  218. package/src/apps/data/routes/funding.test.ts +7 -42
  219. package/src/apps/data/routes/funding.ts +8 -8
  220. package/src/apps/data/routes/indexer.test.ts +2 -2
  221. package/src/apps/data/routes/webhooks.test.ts +2 -2
  222. package/src/apps/management/App.ts +2 -2
  223. package/src/apps/management/Billing.ts +10 -2
  224. package/src/apps/management/routes/api-keys.test.ts +137 -1
  225. package/src/apps/management/routes/api-keys.ts +63 -38
  226. package/src/apps/management/routes/billing.ts +14 -14
  227. package/src/apps/management/routes/invitations.test.ts +102 -1
  228. package/src/apps/management/routes/invitations.ts +13 -15
  229. package/src/apps/management/routes/members.ts +10 -10
  230. package/src/apps/management/routes/orgs.test.ts +78 -16
  231. package/src/apps/management/routes/orgs.ts +21 -20
  232. package/src/apps/management/routes/projects.ts +12 -13
  233. package/src/apps/management/routes/scopes.test.ts +16 -0
  234. package/src/apps/management/routes/scopes.ts +6 -7
  235. package/src/apps/management/routes/usage.ts +9 -14
  236. package/src/apps/mcp.test.ts +72 -7
  237. package/src/apps/mcp.ts +46 -4
  238. package/src/apps/relay/App.test.ts +23 -18
  239. package/src/apps/relay/App.ts +35 -14
  240. package/src/cloudflare.ts +5 -0
  241. package/src/db/Db.ts +59 -3
  242. package/src/db/Schema.ts +20 -1
  243. package/src/db/tables/adminAuditLogs.ts +47 -0
  244. package/src/db/tables/invitations.ts +1 -1
  245. package/src/db/tables/memberships.ts +59 -3
  246. package/src/db/tables/organizations.ts +148 -1
  247. package/src/db/tables/projects.ts +47 -0
  248. package/src/db/tables/webhookDeliveries.ts +83 -0
  249. package/src/internal/Auth.test.ts +571 -23
  250. package/src/internal/Auth.ts +166 -94
  251. package/src/internal/Cursor.test.ts +10 -0
  252. package/src/internal/Cursor.ts +5 -1
  253. package/src/internal/EdgeCache.test.ts +11 -0
  254. package/src/internal/EdgeCache.ts +2 -0
  255. package/src/internal/FundingRoutes.test.ts +8 -8
  256. package/src/internal/FundingRoutes.ts +25 -29
  257. package/src/internal/Log.test.ts +41 -3
  258. package/src/internal/Log.ts +23 -4
  259. package/src/internal/Store.test-d.ts +15 -0
  260. package/src/internal/Store.test.ts +153 -2
  261. package/src/internal/Store.ts +157 -41
  262. package/src/internal/index.test.ts +34 -0
  263. package/src/internal/index.ts +26 -0
@@ -1,9 +1,52 @@
1
1
  import { Json } from 'ox'
2
2
 
3
+ /** Key-to-value map used by typed stores. */
4
+ export type StoreItemMap = Record<string, unknown>
5
+
6
+ /** Result of an atomic store update. */
7
+ export type Change<value, result> =
8
+ | {
9
+ /** Leaves the value unchanged. */
10
+ op: 'noop'
11
+ /** Value returned by the update. */
12
+ result: result
13
+ }
14
+ | {
15
+ /** Replaces the stored value. */
16
+ op: 'set'
17
+ /** Value returned by the update. */
18
+ result: result
19
+ /** New stored value. */
20
+ value: value
21
+ }
22
+ | {
23
+ /** Deletes the stored value. */
24
+ op: 'delete'
25
+ /** Value returned by the update. */
26
+ result: result
27
+ }
28
+
29
+ /** Typed store with atomic read-modify-write support. */
30
+ export type AtomicStore<itemMap extends StoreItemMap = StoreItemMap> = {
31
+ /** Deletes a key. */
32
+ delete<key extends keyof itemMap & string>(key: key): Promise<void>
33
+ /** Gets a typed value. */
34
+ get<key extends keyof itemMap & string>(key: key): Promise<itemMap[key] | null>
35
+ /** Writes a typed value. */
36
+ put<key extends keyof itemMap & string>(key: key, value: itemMap[key]): Promise<void>
37
+ /** Atomically updates a typed value. */
38
+ update<key extends keyof itemMap & string, result>(
39
+ key: key,
40
+ fn: (current: itemMap[key] | null) => Change<itemMap[key], result>,
41
+ ): Promise<result>
42
+ }
43
+
3
44
  /** Minimal string store contract used by Tempo API internals. */
4
45
  export type Store = {
5
46
  /** Deletes a key. */
6
47
  delete(key: string): Promise<void>
48
+ /** Deletes a key only when its value matches `expected`. */
49
+ deleteIf?: ((key: string, expected: null | string) => Promise<boolean>) | undefined
7
50
  /** Gets a string value. Returns `null` for missing or expired keys. */
8
51
  get(key: string): Promise<null | string>
9
52
  /**
@@ -77,6 +120,9 @@ export namespace Store {
77
120
  */
78
121
  export type State = Store & { type: 'state' }
79
122
 
123
+ /** Authoritative string state that also supports typed atomic operations. */
124
+ export type AtomicState<itemMap extends StoreItemMap = StoreItemMap> = AtomicStore<itemMap> & State
125
+
80
126
  /**
81
127
  * Wraps store operations into a {@link Store}, defaulting to an authoritative
82
128
  * {@link State} store. Omit `type` for the common authoritative case; pass
@@ -136,7 +182,7 @@ export async function update(
136
182
  fn: (current: null | string) => string,
137
183
  options: update.Options = {},
138
184
  ): Promise<string> {
139
- const { attempts = 8, ...put } = options
185
+ const { attempts = updateAttempts, ...put } = options
140
186
 
141
187
  if (!store.swap) {
142
188
  const next = fn(await store.get(key))
@@ -152,6 +198,8 @@ export async function update(
152
198
  throw new UpdateContentionError(key, attempts)
153
199
  }
154
200
 
201
+ const updateAttempts = 8
202
+
155
203
  export declare namespace update {
156
204
  /** Options for {@link update}. */
157
205
  type Options = Store.PutOptions & {
@@ -187,6 +235,11 @@ export function memory(options: memory.Options = {}): State {
187
235
  async delete(key) {
188
236
  cells.delete(key)
189
237
  },
238
+ async deleteIf(key, expected) {
239
+ if ((read(key)?.value ?? null) !== expected) return false
240
+ cells.delete(key)
241
+ return true
242
+ },
190
243
  async get(key) {
191
244
  return read(key)?.value ?? null
192
245
  },
@@ -347,21 +400,26 @@ export declare namespace cloudflareKv {
347
400
  }
348
401
  }
349
402
 
350
- export function durableObject(storage: durableObject.Storage): State
403
+ /** Creates typed atomic state over namespace RPC, or raw object storage state. */
404
+ export function durableObject(namespace: durableObject.Namespace): durableObject.ReturnValue
351
405
  export function durableObject(
352
406
  namespace: durableObject.Namespace,
353
407
  options: durableObject.Options,
354
- ): State
355
- /** Creates a store backed by Cloudflare Durable Object storage or namespace RPC. */
408
+ ): durableObject.ReturnValue
409
+ export function durableObject<const itemMap extends StoreItemMap>(
410
+ namespace: durableObject.Namespace,
411
+ ): AtomicState<itemMap>
412
+ export function durableObject<const itemMap extends StoreItemMap>(
413
+ namespace: durableObject.Namespace,
414
+ options: durableObject.Options,
415
+ ): AtomicState<itemMap>
416
+ export function durableObject(storage: durableObject.Storage): State
356
417
  export function durableObject(
357
418
  target: durableObject.Namespace | durableObject.Storage,
358
- options?: durableObject.Options,
359
- ): State {
360
- if (durableObjectNamespace(target)) {
361
- const name = options?.name
362
- if (name === undefined) throw new TypeError('Durable Object name is required')
363
- return durableObjectStub(target, name)
364
- }
419
+ options: durableObject.Options = {},
420
+ ): durableObject.ReturnValue | State {
421
+ if (durableObjectNamespace(target))
422
+ return durableObjectStub(target, options.name ?? ((key) => key))
365
423
  return durableObjectStorage(target)
366
424
  }
367
425
 
@@ -370,6 +428,13 @@ function durableObjectStorage(storage: durableObject.Storage): State {
370
428
  async delete(key) {
371
429
  await storage.delete(key)
372
430
  },
431
+ // Storage input gates prevent writes between comparison and deletion.
432
+ async deleteIf(key, expected) {
433
+ const current = (await durableObjectRead(storage, key, await storage.get(key)))?.value ?? null
434
+ if (current !== expected) return false
435
+ await storage.delete(key)
436
+ return true
437
+ },
373
438
  async get(key) {
374
439
  return (await durableObjectRead(storage, key, await storage.get(key)))?.value ?? null
375
440
  },
@@ -408,6 +473,19 @@ function durableObjectStorage(storage: durableObject.Storage): State {
408
473
  }
409
474
 
410
475
  export declare namespace durableObject {
476
+ /** Durable Object state assignable to any typed item map. */
477
+ type ReturnValue = State & {
478
+ /** Gets a contextually typed value. */
479
+ get<value = unknown>(key: string): Promise<value | null>
480
+ /** Writes a typed value. */
481
+ put<value>(key: string, value: value, options?: Store.PutOptions): Promise<void>
482
+ /** Atomically updates a contextually typed value. */
483
+ update<value, result>(
484
+ key: string,
485
+ fn: (current: value | null) => Change<value, result>,
486
+ ): Promise<result>
487
+ }
488
+
411
489
  /** Minimal Durable Object namespace shape used by this adapter. */
412
490
  type Namespace = {
413
491
  /** Gets the Durable Object stub for a stable object name. */
@@ -416,13 +494,8 @@ export declare namespace durableObject {
416
494
 
417
495
  /** Options for creating a store from a Durable Object namespace. */
418
496
  type Options = {
419
- /**
420
- * Durable Object name. A static string pins one object holding every key
421
- * (enumerable via `list`). A resolver function shards keys across objects
422
- * (`name(key)` per operation) so each key's object is created near the
423
- * traffic that uses it — sharded stores cannot `list`.
424
- */
425
- name: string | ((key: string) => string)
497
+ /** Static pins all keys; a resolver shards them; omission shards by key. */
498
+ name?: string | ((key: string) => string) | undefined
426
499
  }
427
500
 
428
501
  /** Minimal Cloudflare Durable Object storage shape used by this adapter. */
@@ -440,14 +513,10 @@ export declare namespace durableObject {
440
513
  put<value>(key: string, value: value): Promise<void>
441
514
  }
442
515
 
443
- /**
444
- * Minimal Durable Object RPC stub shape used by this adapter just the store
445
- * operations (no `type` discriminant, which an RPC stub doesn't carry).
446
- * `increment` and `swap` are required: the stub mirrors the
447
- * `tapimo/cloudflare` `DurableObject` class, whose RPC surface implements
448
- * them.
449
- */
450
- type Stub = Omit<Store, 'increment' | 'swap' | 'type'> & {
516
+ /** RPC store operations used by the namespace adapter. */
517
+ type Stub = Omit<Store, 'deleteIf' | 'increment' | 'swap' | 'type'> & {
518
+ /** Atomically deletes a matching value inside the object. */
519
+ deleteIf(key: string, expected: null | string): Promise<boolean>
451
520
  /** Atomically increments an integer counter inside the object. */
452
521
  increment(key: string, options?: Store.PutOptions): Promise<number>
453
522
  /** Atomically compares-and-swaps a value inside the object. */
@@ -533,40 +602,58 @@ function durableObjectNamespace(
533
602
  function durableObjectStub(
534
603
  namespace: durableObject.Namespace,
535
604
  name: string | ((key: string) => string),
536
- ): State {
605
+ ): durableObject.ReturnValue {
537
606
  // Durable Object stubs are request-scoped I/O objects in Workers, so
538
607
  // resolve the stub inside each store operation instead of caching it.
539
608
  const stub = (key: string) => namespace.getByName(typeof name === 'function' ? name(key) : name)
540
609
 
541
- return from({
542
- async delete(key) {
610
+ return {
611
+ async delete(key: string) {
543
612
  await durableObjectRetry(() => stub(key).delete(key))
544
613
  },
545
- async get(key) {
546
- return durableObjectRetry(() => stub(key).get(key))
614
+ async deleteIf(key: string, expected: null | string) {
615
+ const encoded = expected === null ? null : durableObjectEncode(expected)
616
+ return stub(key).deleteIf(key, encoded)
617
+ },
618
+ async get(key: string) {
619
+ return durableObjectDecode(await durableObjectRetry(() => stub(key).get(key)))
547
620
  },
548
621
  // Native RPC increment: the read-modify-write runs inside the object
549
622
  // (one round trip, atomic) instead of the get + put fallback (two).
550
- async increment(key, options) {
623
+ async increment(key: string, options?: Store.PutOptions) {
551
624
  return durableObjectRetry(() => stub(key).increment(key, options))
552
625
  },
553
- async list(options) {
626
+ async list(options?: Parameters<Store['list']>[0]) {
554
627
  // A sharded store scatters keys across objects, so no single object can
555
628
  // enumerate them.
556
629
  if (typeof name === 'function')
557
630
  throw new TypeError('cannot list a sharded Durable Object store')
558
631
  return durableObjectRetry(() => stub('').list(options))
559
632
  },
560
- async put(key, value, options) {
561
- await durableObjectRetry(() => stub(key).put(key, value, options))
633
+ async put(key: string, value: unknown, options?: Store.PutOptions) {
634
+ await durableObjectRetry(() => stub(key).put(key, durableObjectEncode(value), options))
562
635
  },
563
- // Native RPC swap: the compare-and-write runs inside the object. A lost
564
- // response retried after a successful write compares stale and returns
565
- // false, which optimistic callers already handle as contention.
566
- async swap(key, expected, next, options) {
567
- return durableObjectRetry(() => stub(key).swap(key, expected, next, options))
636
+ async swap(key: string, expected: null | string, next: string, options?: Store.PutOptions) {
637
+ const encoded = expected === null ? null : durableObjectEncode(expected)
638
+ return stub(key).swap(key, encoded, durableObjectEncode(next), options)
568
639
  },
569
- })
640
+ type: 'state' as const,
641
+ async update<result>(key: string, fn: (current: unknown) => Change<unknown, result>) {
642
+ for (let attempt = 0; attempt < updateAttempts; attempt++) {
643
+ const current = await durableObjectRetry(() => stub(key).get(key))
644
+ const change = fn(durableObjectDecode(current))
645
+ if (change.op === 'noop') return change.result
646
+
647
+ // Retrying an ambiguous CAS can apply the transform twice.
648
+ const changed =
649
+ change.op === 'set'
650
+ ? await stub(key).swap(key, current, durableObjectEncode(change.value))
651
+ : await stub(key).deleteIf(key, current)
652
+ if (changed) return change.result
653
+ }
654
+ throw new UpdateContentionError(key, updateAttempts)
655
+ },
656
+ } as durableObject.ReturnValue
570
657
  }
571
658
 
572
659
  /**
@@ -588,6 +675,26 @@ async function durableObjectRetry<value>(call: () => Promise<value>): Promise<va
588
675
  }
589
676
  }
590
677
 
678
+ const durableObjectCodecRoot = 'tempo-api:store:json:'
679
+ const durableObjectCodecVersion = 'v1'
680
+ const durableObjectCodecPrefix = `${durableObjectCodecRoot}${durableObjectCodecVersion}:`
681
+
682
+ function durableObjectEncode(value: unknown): string {
683
+ if (typeof value === 'string' && !value.startsWith(durableObjectCodecRoot)) return value
684
+ const encoded = Json.stringify(value)
685
+ if (encoded === undefined) throw new TypeError('Durable Object store value is not serializable')
686
+ return `${durableObjectCodecPrefix}${encoded}`
687
+ }
688
+
689
+ function durableObjectDecode(value: null | string): unknown {
690
+ if (value === null || !value.startsWith(durableObjectCodecRoot)) return value
691
+ if (!value.startsWith(durableObjectCodecPrefix)) {
692
+ const [version] = value.slice(durableObjectCodecRoot.length).split(':')
693
+ throw new DurableObjectCodecError(version)
694
+ }
695
+ return Json.parse(value.slice(durableObjectCodecPrefix.length))
696
+ }
697
+
591
698
  function cloudflareKvExpirationTtl(ttl: number | undefined) {
592
699
  if (ttl === undefined) return undefined
593
700
  if (ttl <= 0) return 0
@@ -649,3 +756,12 @@ export class UpdateContentionError extends Error {
649
756
  super(`Store update on "${key}" lost ${attempts} compare-and-swap attempts.`)
650
757
  }
651
758
  }
759
+
760
+ /** Thrown when Durable Object state uses an unsupported codec. */
761
+ export class DurableObjectCodecError extends Error {
762
+ override name = 'Store.DurableObjectCodecError'
763
+
764
+ constructor(version: unknown) {
765
+ super(`Unsupported Durable Object store codec version: ${String(version)}`)
766
+ }
767
+ }
@@ -0,0 +1,34 @@
1
+ import * as Internal from './index.js'
2
+
3
+ test('exports internal modules', () => {
4
+ expect(Object.keys(Internal)).toMatchInlineSnapshot(`
5
+ [
6
+ "Auth",
7
+ "Cache",
8
+ "Cursor",
9
+ "EdgeCache",
10
+ "Errors",
11
+ "Fees",
12
+ "FundingRoutes",
13
+ "Id",
14
+ "Log",
15
+ "MetricSink",
16
+ "Mpp",
17
+ "OpenApi",
18
+ "Path",
19
+ "RateLimit",
20
+ "Response",
21
+ "RpcSchema",
22
+ "Schema",
23
+ "Store",
24
+ "Tidx",
25
+ "Timing",
26
+ "Ttl",
27
+ "Value",
28
+ "VerifiedTokens",
29
+ "Viem",
30
+ "WebhookDestination",
31
+ "Webhooks",
32
+ ]
33
+ `)
34
+ })
@@ -0,0 +1,26 @@
1
+ export * as Auth from './Auth.js'
2
+ export * as Cache from './Cache.js'
3
+ export * as Cursor from './Cursor.js'
4
+ export * as EdgeCache from './EdgeCache.js'
5
+ export * as Errors from './Errors.js'
6
+ export * as Fees from './Fees.js'
7
+ export * as FundingRoutes from './FundingRoutes.js'
8
+ export * as Id from './Id.js'
9
+ export * as Log from './Log.js'
10
+ export * as MetricSink from './MetricSink.js'
11
+ export * as Mpp from './Mpp.js'
12
+ export * as OpenApi from './OpenApi.js'
13
+ export * as Path from './Path.js'
14
+ export * as RateLimit from './RateLimit.js'
15
+ export * as Response from './Response.js'
16
+ export * as RpcSchema from './RpcSchema.js'
17
+ export * as Schema from './Schema.js'
18
+ export * as Store from './Store.js'
19
+ export * as Tidx from './Tidx.js'
20
+ export * as Timing from './Timing.js'
21
+ export * as Ttl from './Ttl.js'
22
+ export * as Value from './Value.js'
23
+ export * as VerifiedTokens from './VerifiedTokens.js'
24
+ export * as Viem from './Viem.js'
25
+ export * as WebhookDestination from './WebhookDestination.js'
26
+ export * as Webhooks from './Webhooks.js'