@adobe/data 0.1.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.
Files changed (328) hide show
  1. package/README.md +310 -0
  2. package/assembly/index.d.ts +30 -0
  3. package/assembly/index.js +18 -0
  4. package/assembly/index.wasm +0 -0
  5. package/assembly/index.wasm.map +1 -0
  6. package/assembly-test/assembly.test.d.ts +1 -0
  7. package/assembly-test/assembly.test.js +29 -0
  8. package/assembly-test/assembly.test.js.map +1 -0
  9. package/cache/async-cache.d.ts +15 -0
  10. package/cache/async-cache.js +23 -0
  11. package/cache/async-cache.js.map +1 -0
  12. package/cache/blob-store.d.ts +94 -0
  13. package/cache/blob-store.js +191 -0
  14. package/cache/blob-store.js.map +1 -0
  15. package/cache/blob-store.test.d.ts +1 -0
  16. package/cache/blob-store.test.js +142 -0
  17. package/cache/blob-store.test.js.map +1 -0
  18. package/cache/data-cache.d.ts +38 -0
  19. package/cache/data-cache.js +96 -0
  20. package/cache/data-cache.js.map +1 -0
  21. package/cache/data-cache.test.d.ts +1 -0
  22. package/cache/data-cache.test.js +50 -0
  23. package/cache/data-cache.test.js.map +1 -0
  24. package/cache/expiring-data-cache.d.ts +6 -0
  25. package/cache/expiring-data-cache.js +49 -0
  26. package/cache/expiring-data-cache.js.map +1 -0
  27. package/cache/expiring-data-cache.test.d.ts +1 -0
  28. package/cache/expiring-data-cache.test.js +62 -0
  29. package/cache/expiring-data-cache.test.js.map +1 -0
  30. package/cache/fallback-async-cache.d.ts +7 -0
  31. package/cache/fallback-async-cache.js +22 -0
  32. package/cache/fallback-async-cache.js.map +1 -0
  33. package/cache/functions/bind-functions.d.ts +6 -0
  34. package/cache/functions/bind-functions.js +33 -0
  35. package/cache/functions/bind-functions.js.map +1 -0
  36. package/cache/functions/functions.test.d.ts +1 -0
  37. package/cache/functions/functions.test.js +79 -0
  38. package/cache/functions/functions.test.js.map +1 -0
  39. package/cache/functions/get-cached.d.ts +11 -0
  40. package/cache/functions/get-cached.js +49 -0
  41. package/cache/functions/get-cached.js.map +1 -0
  42. package/cache/functions/get-cached.test.d.ts +1 -0
  43. package/cache/functions/get-cached.test.js +96 -0
  44. package/cache/functions/get-cached.test.js.map +1 -0
  45. package/cache/functions/hashing/blob-to-hash.d.ts +4 -0
  46. package/cache/functions/hashing/blob-to-hash.js +44 -0
  47. package/cache/functions/hashing/blob-to-hash.js.map +1 -0
  48. package/cache/functions/hashing/buffer-to-hash.d.ts +4 -0
  49. package/cache/functions/hashing/buffer-to-hash.js +33 -0
  50. package/cache/functions/hashing/buffer-to-hash.js.map +1 -0
  51. package/cache/functions/hashing/hashing.test.d.ts +1 -0
  52. package/cache/functions/hashing/hashing.test.js +95 -0
  53. package/cache/functions/hashing/hashing.test.js.map +1 -0
  54. package/cache/functions/hashing/index.d.ts +4 -0
  55. package/cache/functions/hashing/index.js +26 -0
  56. package/cache/functions/hashing/index.js.map +1 -0
  57. package/cache/functions/hashing/json-to-hash.d.ts +4 -0
  58. package/cache/functions/hashing/json-to-hash.js +29 -0
  59. package/cache/functions/hashing/json-to-hash.js.map +1 -0
  60. package/cache/functions/hashing/string-to-hash.d.ts +4 -0
  61. package/cache/functions/hashing/string-to-hash.js +37 -0
  62. package/cache/functions/hashing/string-to-hash.js.map +1 -0
  63. package/cache/functions/index.d.ts +5 -0
  64. package/cache/functions/index.js +29 -0
  65. package/cache/functions/index.js.map +1 -0
  66. package/cache/functions/memoize.d.ts +12 -0
  67. package/cache/functions/memoize.js +48 -0
  68. package/cache/functions/memoize.js.map +1 -0
  69. package/cache/functions/omit.d.ts +1 -0
  70. package/cache/functions/omit.js +29 -0
  71. package/cache/functions/omit.js.map +1 -0
  72. package/cache/functions/prevent-parallel-execution.d.ts +7 -0
  73. package/cache/functions/prevent-parallel-execution.js +25 -0
  74. package/cache/functions/prevent-parallel-execution.js.map +1 -0
  75. package/cache/functions/types.d.ts +1 -0
  76. package/cache/functions/types.js +23 -0
  77. package/cache/functions/types.js.map +1 -0
  78. package/cache/get-persistent-cache.d.ts +12 -0
  79. package/cache/get-persistent-cache.js +23 -0
  80. package/cache/get-persistent-cache.js.map +1 -0
  81. package/cache/index.d.ts +3 -0
  82. package/cache/index.js +25 -0
  83. package/cache/index.js.map +1 -0
  84. package/cache/managed-array.d.ts +23 -0
  85. package/cache/managed-array.js +160 -0
  86. package/cache/managed-array.js.map +1 -0
  87. package/cache/managed-async-cache.browser.test.d.ts +1 -0
  88. package/cache/managed-async-cache.browser.test.js +50 -0
  89. package/cache/managed-async-cache.browser.test.js.map +1 -0
  90. package/cache/managed-async-cache.d.ts +4 -0
  91. package/cache/managed-async-cache.js +45 -0
  92. package/cache/managed-async-cache.js.map +1 -0
  93. package/cache/memory-allocator.d.ts +23 -0
  94. package/cache/memory-allocator.js +94 -0
  95. package/cache/memory-allocator.js.map +1 -0
  96. package/cache/memory-async-cache.d.ts +6 -0
  97. package/cache/memory-async-cache.js +23 -0
  98. package/cache/memory-async-cache.js.map +1 -0
  99. package/core/data.d.ts +22 -0
  100. package/core/data.js +52 -0
  101. package/core/data.js.map +1 -0
  102. package/core/data.test.d.ts +1 -0
  103. package/core/data.test.js +48 -0
  104. package/core/data.test.js.map +1 -0
  105. package/core/functions/array-equals.d.ts +1 -0
  106. package/core/functions/array-equals.js +34 -0
  107. package/core/functions/array-equals.js.map +1 -0
  108. package/core/functions/deep-merge.d.ts +31 -0
  109. package/core/functions/deep-merge.js +51 -0
  110. package/core/functions/deep-merge.js.map +1 -0
  111. package/core/functions/deep-merge.test.d.ts +1 -0
  112. package/core/functions/deep-merge.test.js +94 -0
  113. package/core/functions/deep-merge.test.js.map +1 -0
  114. package/core/functions/index.d.ts +4 -0
  115. package/core/functions/index.js +26 -0
  116. package/core/functions/index.js.map +1 -0
  117. package/core/functions/is-async-generator.d.ts +1 -0
  118. package/core/functions/is-async-generator.js +25 -0
  119. package/core/functions/is-async-generator.js.map +1 -0
  120. package/core/functions/is-promise.d.ts +1 -0
  121. package/core/functions/is-promise.js +26 -0
  122. package/core/functions/is-promise.js.map +1 -0
  123. package/core/functions/with-validation.d.ts +5 -0
  124. package/core/functions/with-validation.js +38 -0
  125. package/core/functions/with-validation.js.map +1 -0
  126. package/core/functions/with-validation.test.d.ts +1 -0
  127. package/core/functions/with-validation.test.js +96 -0
  128. package/core/functions/with-validation.test.js.map +1 -0
  129. package/core/index.d.ts +3 -0
  130. package/core/index.js +25 -0
  131. package/core/index.js.map +1 -0
  132. package/core/schema.d.ts +86 -0
  133. package/core/schema.js +33 -0
  134. package/core/schema.js.map +1 -0
  135. package/core/schema.test.d.ts +1 -0
  136. package/core/schema.test.js +16 -0
  137. package/core/schema.test.js.map +1 -0
  138. package/ecs/action-ecs/action-ecs.d.ts +19 -0
  139. package/ecs/action-ecs/action-ecs.js +203 -0
  140. package/ecs/action-ecs/action-ecs.js.map +1 -0
  141. package/ecs/action-ecs/action-ecs.test.d.ts +1 -0
  142. package/ecs/action-ecs/action-ecs.test.js +362 -0
  143. package/ecs/action-ecs/action-ecs.test.js.map +1 -0
  144. package/ecs/action-ecs/action-types.d.ts +106 -0
  145. package/ecs/action-ecs/action-types.js +19 -0
  146. package/ecs/action-ecs/action-types.js.map +1 -0
  147. package/ecs/action-ecs/index.d.ts +2 -0
  148. package/ecs/action-ecs/index.js +23 -0
  149. package/ecs/action-ecs/index.js.map +1 -0
  150. package/ecs/core-ecs/core-ecs-serialization.test.d.ts +1 -0
  151. package/ecs/core-ecs/core-ecs-serialization.test.js +230 -0
  152. package/ecs/core-ecs/core-ecs-serialization.test.js.map +1 -0
  153. package/ecs/core-ecs/core-ecs-types.d.ts +141 -0
  154. package/ecs/core-ecs/core-ecs-types.js +23 -0
  155. package/ecs/core-ecs/core-ecs-types.js.map +1 -0
  156. package/ecs/core-ecs/core-ecs.d.ts +7 -0
  157. package/ecs/core-ecs/core-ecs.js +492 -0
  158. package/ecs/core-ecs/core-ecs.js.map +1 -0
  159. package/ecs/core-ecs/core-ecs.test.d.ts +1 -0
  160. package/ecs/core-ecs/core-ecs.test.js +404 -0
  161. package/ecs/core-ecs/core-ecs.test.js.map +1 -0
  162. package/ecs/core-ecs/index.d.ts +1 -0
  163. package/ecs/core-ecs/index.js +2 -0
  164. package/ecs/core-ecs/index.js.map +1 -0
  165. package/ecs/ecs/ecs-types.d.ts +132 -0
  166. package/ecs/ecs/ecs-types.js +23 -0
  167. package/ecs/ecs/ecs-types.js.map +1 -0
  168. package/ecs/ecs/ecs-where-functions.d.ts +6 -0
  169. package/ecs/ecs/ecs-where-functions.js +91 -0
  170. package/ecs/ecs/ecs-where-functions.js.map +1 -0
  171. package/ecs/ecs/ecs.d.ts +13 -0
  172. package/ecs/ecs/ecs.js +177 -0
  173. package/ecs/ecs/ecs.js.map +1 -0
  174. package/ecs/ecs/ecs.test.d.ts +1 -0
  175. package/ecs/ecs/ecs.test.js +399 -0
  176. package/ecs/ecs/ecs.test.js.map +1 -0
  177. package/ecs/ecs/index.d.ts +3 -0
  178. package/ecs/ecs/index.js +3 -0
  179. package/ecs/ecs/index.js.map +1 -0
  180. package/ecs/index.d.ts +4 -0
  181. package/ecs/index.js +26 -0
  182. package/ecs/index.js.map +1 -0
  183. package/ecs/transaction-ecs/index.d.ts +2 -0
  184. package/ecs/transaction-ecs/index.js +24 -0
  185. package/ecs/transaction-ecs/index.js.map +1 -0
  186. package/ecs/transaction-ecs/transaction-ecs.d.ts +11 -0
  187. package/ecs/transaction-ecs/transaction-ecs.js +184 -0
  188. package/ecs/transaction-ecs/transaction-ecs.js.map +1 -0
  189. package/ecs/transaction-ecs/transaction-ecs.test.d.ts +1 -0
  190. package/ecs/transaction-ecs/transaction-ecs.test.js +599 -0
  191. package/ecs/transaction-ecs/transaction-ecs.test.js.map +1 -0
  192. package/ecs/transaction-ecs/transaction-types.d.ts +135 -0
  193. package/ecs/transaction-ecs/transaction-types.js +2 -0
  194. package/ecs/transaction-ecs/transaction-types.js.map +1 -0
  195. package/ecs/transaction-ecs/transactions.d.ts +5 -0
  196. package/ecs/transaction-ecs/transactions.js +158 -0
  197. package/ecs/transaction-ecs/transactions.js.map +1 -0
  198. package/index.d.ts +1 -0
  199. package/index.js +23 -0
  200. package/index.js.map +1 -0
  201. package/observe/create-observable-event.d.ts +10 -0
  202. package/observe/create-observable-event.js +22 -0
  203. package/observe/create-observable-event.js.map +1 -0
  204. package/observe/create-observable-state.d.ts +7 -0
  205. package/observe/create-observable-state.js +27 -0
  206. package/observe/create-observable-state.js.map +1 -0
  207. package/observe/create-persisted-state.d.ts +11 -0
  208. package/observe/create-persisted-state.js +31 -0
  209. package/observe/create-persisted-state.js.map +1 -0
  210. package/observe/create-persisted-state.test.d.ts +1 -0
  211. package/observe/create-persisted-state.test.js +124 -0
  212. package/observe/create-persisted-state.test.js.map +1 -0
  213. package/observe/from-array.d.ts +5 -0
  214. package/observe/from-array.js +30 -0
  215. package/observe/from-array.js.map +1 -0
  216. package/observe/from-constant.d.ts +5 -0
  217. package/observe/from-constant.js +12 -0
  218. package/observe/from-constant.js.map +1 -0
  219. package/observe/from-element-id.d.ts +7 -0
  220. package/observe/from-element-id.js +70 -0
  221. package/observe/from-element-id.js.map +1 -0
  222. package/observe/from-element-properties-and-events.d.ts +2 -0
  223. package/observe/from-element-properties-and-events.js +18 -0
  224. package/observe/from-element-properties-and-events.js.map +1 -0
  225. package/observe/from-element-property.d.ts +11 -0
  226. package/observe/from-element-property.js +60 -0
  227. package/observe/from-element-property.js.map +1 -0
  228. package/observe/from-promise-with-error.d.ts +7 -0
  229. package/observe/from-promise-with-error.js +27 -0
  230. package/observe/from-promise-with-error.js.map +1 -0
  231. package/observe/from-promise.d.ts +6 -0
  232. package/observe/from-promise.js +22 -0
  233. package/observe/from-promise.js.map +1 -0
  234. package/observe/from-properties.d.ts +10 -0
  235. package/observe/from-properties.js +33 -0
  236. package/observe/from-properties.js.map +1 -0
  237. package/observe/index.d.ts +27 -0
  238. package/observe/index.js +49 -0
  239. package/observe/index.js.map +1 -0
  240. package/observe/observe.test.d.ts +7 -0
  241. package/observe/observe.test.js +417 -0
  242. package/observe/observe.test.js.map +1 -0
  243. package/observe/to-promise.d.ts +8 -0
  244. package/observe/to-promise.js +18 -0
  245. package/observe/to-promise.js.map +1 -0
  246. package/observe/to-properties.d.ts +11 -0
  247. package/observe/to-properties.js +9 -0
  248. package/observe/to-properties.js.map +1 -0
  249. package/observe/types.d.ts +17 -0
  250. package/observe/types.js +2 -0
  251. package/observe/types.js.map +1 -0
  252. package/observe/with-async-map.d.ts +6 -0
  253. package/observe/with-async-map.js +12 -0
  254. package/observe/with-async-map.js.map +1 -0
  255. package/observe/with-cache.d.ts +6 -0
  256. package/observe/with-cache.js +33 -0
  257. package/observe/with-cache.js.map +1 -0
  258. package/observe/with-copy.d.ts +5 -0
  259. package/observe/with-copy.js +10 -0
  260. package/observe/with-copy.js.map +1 -0
  261. package/observe/with-deduplicate-data.d.ts +7 -0
  262. package/observe/with-deduplicate-data.js +18 -0
  263. package/observe/with-deduplicate-data.js.map +1 -0
  264. package/observe/with-deduplicate.d.ts +6 -0
  265. package/observe/with-deduplicate.js +19 -0
  266. package/observe/with-deduplicate.js.map +1 -0
  267. package/observe/with-default.d.ts +6 -0
  268. package/observe/with-default.js +21 -0
  269. package/observe/with-default.js.map +1 -0
  270. package/observe/with-map-data.d.ts +7 -0
  271. package/observe/with-map-data.js +32 -0
  272. package/observe/with-map-data.js.map +1 -0
  273. package/observe/with-map.d.ts +5 -0
  274. package/observe/with-map.js +11 -0
  275. package/observe/with-map.js.map +1 -0
  276. package/observe/with-optional.d.ts +5 -0
  277. package/observe/with-optional.js +20 -0
  278. package/observe/with-optional.js.map +1 -0
  279. package/observe/with-unwrap.d.ts +5 -0
  280. package/observe/with-unwrap.js +26 -0
  281. package/observe/with-unwrap.js.map +1 -0
  282. package/package.json +105 -0
  283. package/perftest/ecs-perf.d.ts +49 -0
  284. package/perftest/ecs-perf.js +230 -0
  285. package/perftest/ecs-perf.js.map +1 -0
  286. package/perftest/helper-functions.d.ts +1 -0
  287. package/perftest/helper-functions.js +31 -0
  288. package/perftest/helper-functions.js.map +1 -0
  289. package/perftest/horizon-perf.d.ts +22 -0
  290. package/perftest/horizon-perf.js +126 -0
  291. package/perftest/horizon-perf.js.map +1 -0
  292. package/perftest/index.d.ts +1 -0
  293. package/perftest/index.js +35 -0
  294. package/perftest/index.js.map +1 -0
  295. package/perftest/perf-test.d.ts +18 -0
  296. package/perftest/perf-test.js +124 -0
  297. package/perftest/perf-test.js.map +1 -0
  298. package/perftest/vanilla-perf.d.ts +38 -0
  299. package/perftest/vanilla-perf.js +128 -0
  300. package/perftest/vanilla-perf.js.map +1 -0
  301. package/schemas/index.d.ts +1 -0
  302. package/schemas/index.js +23 -0
  303. package/schemas/index.js.map +1 -0
  304. package/schemas/schemas.d.ts +45 -0
  305. package/schemas/schemas.js +39 -0
  306. package/schemas/schemas.js.map +1 -0
  307. package/service/add-observable-actions.d.ts +29 -0
  308. package/service/add-observable-actions.js +108 -0
  309. package/service/add-observable-actions.js.map +1 -0
  310. package/service/index.d.ts +4 -0
  311. package/service/index.js +26 -0
  312. package/service/index.js.map +1 -0
  313. package/service/progressive-result.d.ts +96 -0
  314. package/service/progressive-result.js +99 -0
  315. package/service/progressive-result.js.map +1 -0
  316. package/service/sequential-action.d.ts +18 -0
  317. package/service/sequential-action.js +45 -0
  318. package/service/sequential-action.js.map +1 -0
  319. package/service/service.d.ts +4 -0
  320. package/service/service.js +26 -0
  321. package/service/service.js.map +1 -0
  322. package/tsconfig.tsbuildinfo +1 -0
  323. package/types/index.d.ts +1 -0
  324. package/types/index.js +23 -0
  325. package/types/index.js.map +1 -0
  326. package/types/types.d.ts +61 -0
  327. package/types/types.js +27 -0
  328. package/types/types.js.map +1 -0
@@ -0,0 +1,94 @@
1
+ import { type FromSchema } from "../core/schema.js";
2
+ export declare const BlobRefSchema: {
3
+ readonly oneOf: readonly [{
4
+ readonly required: readonly ["remoteBlobRef"];
5
+ readonly properties: {
6
+ readonly remoteBlobRef: {
7
+ readonly type: "string";
8
+ readonly pattern: "http.*";
9
+ };
10
+ };
11
+ readonly additionalProperties: false;
12
+ }, {
13
+ readonly required: readonly ["localBlobRef"];
14
+ readonly properties: {
15
+ readonly localBlobRef: {
16
+ readonly type: "string";
17
+ };
18
+ };
19
+ readonly additionalProperties: false;
20
+ }];
21
+ };
22
+ /**
23
+ * Represents a reference to a blob as a plain JSON object.
24
+ * Do NOT create this type directly.
25
+ * Use the BlobStore to create and manage blob references.
26
+ */
27
+ export type BlobRef = FromSchema<typeof BlobRefSchema>;
28
+ export declare function isBlobRef(value: unknown): value is BlobRef;
29
+ /**
30
+ * Defined as a symbol because we only want it used by internal code like DataCache.
31
+ */
32
+ export declare const hasBlobInternalDoNotUse: unique symbol;
33
+ /**
34
+ * A blob store is a service that can efficiently store blobs across sessions and retrieve them using the browsers Cache api.
35
+ */
36
+ export interface BlobStore {
37
+ /**
38
+ * Stores a blob and returns a reference to it.
39
+ * Blob references are based upon the content and type of the Blob.
40
+ * If an equivalent blob is stored, an equivalent reference will be returned every time.
41
+ */
42
+ getRef(b: Blob | string): Promise<BlobRef>;
43
+ /**
44
+ * Gets a blob from the blob store or null if it is not available.
45
+ */
46
+ getBlob(r: BlobRef | null): Promise<Blob | null>;
47
+ /**
48
+ * Checks if the blob is still available.
49
+ */
50
+ hasBlob(r: BlobRef | null): Promise<boolean>;
51
+ /**
52
+ * Do NOT use this directly, use useBorrowUrl hook instead as it will automatically return the url when the component unmounts.
53
+ */
54
+ borrowUrl(r: BlobRef | null): Promise<string | null>;
55
+ /**
56
+ * Return a url that was previously borrowed from borrowUrl.
57
+ * Failure to do so may result in memory leaking.
58
+ * @param url The url provided by borrowUrl.
59
+ */
60
+ returnUrl(url: string | null): void;
61
+ /**
62
+ * Removes a blob from the store.
63
+ */
64
+ releaseBlob(r: BlobRef): Promise<void>;
65
+ /**
66
+ * Creates a new remote blob ref. The url must start with http.
67
+ * This should only be called if the remote content is persistent and immutable.
68
+ */
69
+ createRemoteBlobRef(url: string): BlobRef;
70
+ /**
71
+ * TEST ONLY: Gets the current borrow count for a blob reference.
72
+ * This should only be used in tests to verify reference counting behavior.
73
+ * @param r The blob reference to check
74
+ * @returns The number of times the blob reference has been borrowed, or 0 if not borrowed
75
+ */
76
+ _testGetBorrowCount(r: BlobRef): number;
77
+ }
78
+ /**
79
+ * Creates a new blob store instance.
80
+ */
81
+ export declare function createBlobStore(): Promise<{
82
+ readonly getRef: (blob: Blob | string) => Promise<BlobRef>;
83
+ readonly getBlob: (r?: BlobRef | null) => Promise<Blob | null>;
84
+ readonly hasBlob: (r: BlobRef) => Promise<boolean>;
85
+ readonly borrowUrl: (r: BlobRef) => Promise<string | null>;
86
+ readonly returnUrl: (url: string | null) => void;
87
+ readonly releaseBlob: (r: BlobRef) => Promise<void>;
88
+ readonly createRemoteBlobRef: (url: string) => BlobRef;
89
+ readonly _testGetBorrowCount: (r: BlobRef) => number;
90
+ }>;
91
+ /**
92
+ * The global blob store that can be used to store and retrieve blobs.
93
+ */
94
+ export declare const blobStore: BlobStore;
@@ -0,0 +1,191 @@
1
+ /*MIT License
2
+
3
+ © Copyright 2025 Adobe. All rights reserved.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.*/
22
+ import { getManagedPersistentCache } from "./get-persistent-cache.js";
23
+ import { blobToHash } from "./functions/hashing/blob-to-hash.js";
24
+ import { preventParallelExecution } from "./functions/prevent-parallel-execution.js";
25
+ const remoteUrlPrefix = "http";
26
+ const RemoteUrlSchema = {
27
+ type: "string",
28
+ pattern: `${remoteUrlPrefix}.*`,
29
+ };
30
+ const RemoteBlobRefSchema = {
31
+ required: ["remoteBlobRef"],
32
+ properties: {
33
+ remoteBlobRef: RemoteUrlSchema,
34
+ },
35
+ additionalProperties: false,
36
+ };
37
+ const LocalBlobRefSchema = {
38
+ required: ["localBlobRef"],
39
+ properties: {
40
+ localBlobRef: { type: "string" },
41
+ },
42
+ additionalProperties: false,
43
+ };
44
+ export const BlobRefSchema = {
45
+ oneOf: [RemoteBlobRefSchema, LocalBlobRefSchema],
46
+ };
47
+ function isRemoteBlobRef(ref) {
48
+ const maybe = ref;
49
+ return typeof maybe?.remoteBlobRef === "string";
50
+ }
51
+ function isLocalBlobRef(ref) {
52
+ const maybe = ref;
53
+ return typeof maybe?.localBlobRef === "string";
54
+ }
55
+ export function isBlobRef(value) {
56
+ return isRemoteBlobRef(value) || isLocalBlobRef(value);
57
+ }
58
+ function isRemoteUrl(url) {
59
+ return url.startsWith(remoteUrlPrefix);
60
+ }
61
+ function toRequest(ref) {
62
+ return new Request(`${window.location.origin}/${ref.localBlobRef}`);
63
+ }
64
+ /**
65
+ * Defined as a symbol because we only want it used by internal code like DataCache.
66
+ */
67
+ export const hasBlobInternalDoNotUse = Symbol("hasBlob");
68
+ /**
69
+ * Creates a new blob store instance.
70
+ */
71
+ export async function createBlobStore() {
72
+ const cache = await getManagedPersistentCache("blobstore", {
73
+ maximumMemoryEntries: 10,
74
+ maximumStorageEntries: 1000,
75
+ });
76
+ // Track borrowed URLs and their reference counts
77
+ const borrowedUrls = new Map();
78
+ // Reverse mapping for O(1) lookup
79
+ const urlToKey = new Map();
80
+ async function getRef(blob) {
81
+ if (typeof blob === "string") {
82
+ // if this is not a remote url, then we can assume it is a data url and fetch the blob from it.
83
+ blob = await (await fetch(blob)).blob();
84
+ }
85
+ const ref = {
86
+ localBlobRef: await blobToHash(blob),
87
+ };
88
+ const request = toRequest(ref);
89
+ const response = new Response(blob);
90
+ await cache.put(request, response);
91
+ return ref;
92
+ }
93
+ async function hasBlob(r) {
94
+ if (isRemoteBlobRef(r)) {
95
+ return true;
96
+ }
97
+ const response = await cache.match(toRequest(r));
98
+ return response !== undefined;
99
+ }
100
+ async function getBlob(r) {
101
+ if (!r) {
102
+ return null;
103
+ }
104
+ const response = await (isRemoteBlobRef(r)
105
+ ? fetch(r.remoteBlobRef)
106
+ : cache.match(toRequest(r)));
107
+ if (!response) {
108
+ return null;
109
+ }
110
+ if (!response.ok) {
111
+ // this should only happen with remote urls. local blob responses are always ok.
112
+ throw new Error(response.statusText);
113
+ }
114
+ return response.blob();
115
+ }
116
+ async function releaseBlob(r) {
117
+ if (isLocalBlobRef(r)) {
118
+ cache.delete(toRequest(r));
119
+ }
120
+ }
121
+ /**
122
+ * prevent parallel execution to avoid race condition in borrowUrl while awaiting getBlob
123
+ */
124
+ const borrowUrlInternalNoIncrement = preventParallelExecution(async (key, r) => {
125
+ if (isRemoteBlobRef(r)) {
126
+ return { url: r.remoteBlobRef, count: 0 };
127
+ }
128
+ const blob = await getBlob(r);
129
+ if (!blob) {
130
+ return null;
131
+ }
132
+ const url = URL.createObjectURL(blob);
133
+ const existing = { url, count: 0 };
134
+ borrowedUrls.set(key, existing);
135
+ urlToKey.set(url, key);
136
+ return existing;
137
+ });
138
+ async function borrowUrl(r) {
139
+ const key = JSON.stringify(r);
140
+ const existing = borrowedUrls.get(key) ?? await borrowUrlInternalNoIncrement(key, r);
141
+ if (!existing) {
142
+ return null;
143
+ }
144
+ existing.count++;
145
+ return existing.url;
146
+ }
147
+ function returnUrl(url) {
148
+ if (!url) {
149
+ return;
150
+ }
151
+ const key = urlToKey.get(url);
152
+ if (key) {
153
+ const entry = borrowedUrls.get(key);
154
+ if (entry) {
155
+ entry.count--;
156
+ if (entry.count <= 0) {
157
+ borrowedUrls.delete(key);
158
+ urlToKey.delete(url);
159
+ if (!isRemoteUrl(url)) {
160
+ URL.revokeObjectURL(url);
161
+ }
162
+ }
163
+ }
164
+ }
165
+ }
166
+ function createRemoteBlobRef(url) {
167
+ if (!isRemoteUrl(url)) {
168
+ throw new Error(`Invalid url, expected to start with (${remoteUrlPrefix}): ${url}`);
169
+ }
170
+ return { remoteBlobRef: url };
171
+ }
172
+ function _testGetBorrowCount(r) {
173
+ const key = JSON.stringify(r);
174
+ return borrowedUrls.get(key)?.count ?? 0;
175
+ }
176
+ return {
177
+ getRef,
178
+ getBlob,
179
+ hasBlob,
180
+ borrowUrl,
181
+ returnUrl,
182
+ releaseBlob,
183
+ createRemoteBlobRef,
184
+ _testGetBorrowCount,
185
+ };
186
+ }
187
+ /**
188
+ * The global blob store that can be used to store and retrieve blobs.
189
+ */
190
+ export const blobStore = await createBlobStore();
191
+ //# sourceMappingURL=blob-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"blob-store.js","sourceRoot":"","sources":["../../src/cache/blob-store.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,142 @@
1
+ /*MIT License
2
+
3
+ © Copyright 2025 Adobe. All rights reserved.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.*/
22
+ import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
23
+ import { createBlobStore } from "./blob-store.js";
24
+ describe("blobStore", () => {
25
+ // Mock URL.createObjectURL and URL.revokeObjectURL
26
+ const mockCreateObjectURL = vi.fn((blob) => `blob:${Math.random()}`);
27
+ const mockRevokeObjectURL = vi.fn();
28
+ let testBlobStore;
29
+ let createdUrl;
30
+ beforeEach(async () => {
31
+ // Setup URL mock functions
32
+ const originalCreateObjectURL = URL.createObjectURL;
33
+ const originalRevokeObjectURL = URL.revokeObjectURL;
34
+ // Ensure we create a non-http URL
35
+ mockCreateObjectURL.mockImplementation((blob) => {
36
+ createdUrl = `blob:${Math.random()}`;
37
+ return createdUrl;
38
+ });
39
+ URL.createObjectURL = mockCreateObjectURL;
40
+ URL.revokeObjectURL = mockRevokeObjectURL;
41
+ // Clear mock call history
42
+ mockCreateObjectURL.mockClear();
43
+ mockRevokeObjectURL.mockClear();
44
+ testBlobStore = await createBlobStore();
45
+ return () => {
46
+ URL.createObjectURL = originalCreateObjectURL;
47
+ URL.revokeObjectURL = originalRevokeObjectURL;
48
+ };
49
+ });
50
+ afterEach(() => {
51
+ // Clean up any remaining borrowed URLs
52
+ mockCreateObjectURL.mockReset();
53
+ mockRevokeObjectURL.mockReset();
54
+ });
55
+ describe("URL reference counting", () => {
56
+ it("should reuse the same URL for multiple borrows of the same blob", async () => {
57
+ // Create a test blob
58
+ const testBlob = new Blob(["test"], { type: "text/plain" });
59
+ const blobRef = await testBlobStore.getRef(testBlob);
60
+ // Borrow the URL multiple times
61
+ const url1 = await testBlobStore.borrowUrl(blobRef);
62
+ const url2 = await testBlobStore.borrowUrl(blobRef);
63
+ const url3 = await testBlobStore.borrowUrl(blobRef);
64
+ expect(url1).toBeTruthy();
65
+ expect(url1).toBe(url2);
66
+ expect(url2).toBe(url3);
67
+ expect(url1).toMatch(/^blob:/); // Verify it's a blob URL
68
+ // createObjectURL should only be called once
69
+ expect(mockCreateObjectURL).toHaveBeenCalledTimes(1);
70
+ // Clean up
71
+ testBlobStore.returnUrl(url1);
72
+ testBlobStore.returnUrl(url2);
73
+ testBlobStore.returnUrl(url3);
74
+ });
75
+ it("should only revoke URL when all references are returned", async () => {
76
+ const testBlob = new Blob(["test"], { type: "text/plain" });
77
+ const blobRef = await testBlobStore.getRef(testBlob);
78
+ // Borrow the URL three times
79
+ const url1 = await testBlobStore.borrowUrl(blobRef);
80
+ const url2 = await testBlobStore.borrowUrl(blobRef);
81
+ const url3 = await testBlobStore.borrowUrl(blobRef);
82
+ expect(url1).toMatch(/^blob:/); // Verify it's a blob URL
83
+ // Return URLs one by one
84
+ testBlobStore.returnUrl(url1);
85
+ expect(mockRevokeObjectURL).not.toHaveBeenCalled();
86
+ testBlobStore.returnUrl(url2);
87
+ expect(mockRevokeObjectURL).not.toHaveBeenCalled();
88
+ testBlobStore.returnUrl(url3);
89
+ expect(mockRevokeObjectURL).toHaveBeenCalledTimes(1);
90
+ expect(mockRevokeObjectURL).toHaveBeenCalledWith(createdUrl);
91
+ });
92
+ it("should handle remote URLs correctly", async () => {
93
+ const remoteRef = testBlobStore.createRemoteBlobRef("http://example.com/image.jpg");
94
+ // Borrow remote URL multiple times
95
+ const url1 = await testBlobStore.borrowUrl(remoteRef);
96
+ const url2 = await testBlobStore.borrowUrl(remoteRef);
97
+ expect(url1).toBe("http://example.com/image.jpg");
98
+ expect(url2).toBe("http://example.com/image.jpg");
99
+ expect(mockCreateObjectURL).not.toHaveBeenCalled();
100
+ // Return URLs
101
+ testBlobStore.returnUrl(url1);
102
+ testBlobStore.returnUrl(url2);
103
+ // Should not revoke remote URLs
104
+ expect(mockRevokeObjectURL).not.toHaveBeenCalled();
105
+ });
106
+ it("should handle null inputs gracefully", async () => {
107
+ const nullUrl = await testBlobStore.borrowUrl(null);
108
+ expect(nullUrl).toBeNull();
109
+ // Should not throw when returning null
110
+ expect(() => testBlobStore.returnUrl(null)).not.toThrow();
111
+ });
112
+ it('demonstrates race condition in borrowUrl', async () => {
113
+ const store = testBlobStore;
114
+ const testBlob = new Blob(['test data'], { type: 'text/plain' });
115
+ const blobRef = await store.getRef(testBlob);
116
+ // Create an artificially delayed getBlob to simulate network latency
117
+ const originalGetBlob = store.getBlob;
118
+ store.getBlob = async (ref) => {
119
+ await new Promise(resolve => setTimeout(resolve, 50)); // Add delay
120
+ return originalGetBlob(ref);
121
+ };
122
+ // Make two parallel borrowUrl calls
123
+ const [url1, url2] = await Promise.all([
124
+ store.borrowUrl(blobRef),
125
+ store.borrowUrl(blobRef)
126
+ ]);
127
+ expect(url1).toBe(url2); // Same URL should be returned
128
+ // Return one of the URLs
129
+ store.returnUrl(url1);
130
+ // Verify that the borrow count is still 1 since we borrowed twice and returned once
131
+ expect(store._testGetBorrowCount(blobRef)).toBe(1);
132
+ // Return the second URL
133
+ store.returnUrl(url2);
134
+ // Verify the borrow count is now 0
135
+ expect(store._testGetBorrowCount(blobRef)).toBe(0);
136
+ // Verify the URL was revoked
137
+ expect(mockRevokeObjectURL).toHaveBeenCalledTimes(1);
138
+ expect(mockRevokeObjectURL).toHaveBeenCalledWith(url1);
139
+ });
140
+ });
141
+ });
142
+ //# sourceMappingURL=blob-store.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"blob-store.test.js","sourceRoot":"","sources":["../../src/cache/blob-store.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,38 @@
1
+ import { type AsyncCache } from "./async-cache.js";
2
+ import { type BlobRef, BlobStore } from "./blob-store.js";
3
+ import { type Data } from "../core/data.js";
4
+ export type DataCacheInternal<K extends Data, V extends Data> = AsyncCache<K, V>;
5
+ /**
6
+ * A persistent cache that stores data with an optional expiration time.
7
+ */
8
+ export interface DataCache<K extends Data, V extends Data> {
9
+ /**
10
+ * Stores a new value within the cache.
11
+ * @param key key to use to store the value
12
+ * @param value the value to store
13
+ * @param maxDuration the time to live relative to the current time
14
+ */
15
+ put(key: K, value: V, options?: {
16
+ maximumDuration: number;
17
+ }): Promise<void>;
18
+ /**
19
+ * Attempts to retrieve a value from the cache.
20
+ * @param key The key previously used to store the value.
21
+ */
22
+ match(key: K): Promise<V | undefined>;
23
+ /**
24
+ * Deletes an item from the cache.
25
+ * @param key The key previously used to store the value.
26
+ */
27
+ delete(key: K): Promise<void>;
28
+ }
29
+ export declare function getBlobRefs(d: Data): Array<BlobRef>;
30
+ export declare function createDataCache<K extends Data, V extends Data>(cache: AsyncCache<Request, Response>): DataCacheInternal<K, V>;
31
+ export declare function createBlobRefAwareDataCache<K extends Data = Data, V extends Data = Data>(baseCache?: DataCacheInternal<K, V>, blobstore?: BlobStore): DataCacheInternal<Data, Data>;
32
+ export declare const dataCache: DataCache<Data, Data>;
33
+ /**
34
+ * Retrieves a namespaced data cache. Calling it multiple times will return an equivalent cache.
35
+ * Values stored within a data cache generally persist across sessions.
36
+ * @param nameSpace A unique string used to isolate values within this cache from other caches.
37
+ */
38
+ export declare function getDataCache<K extends Data, V extends Data>(nameSpace: string): DataCache<K, V>;
@@ -0,0 +1,96 @@
1
+ import { isBlobRef, blobStore } from "./blob-store.js";
2
+ import { getManagedPersistentCache } from "./get-persistent-cache.js";
3
+ import { createExpiringDataCache } from "./expiring-data-cache.js";
4
+ /**
5
+ * Recursively searches arbitrary JSON data and locates any BlobRefs within it.
6
+ */
7
+ function getBlobRefsInternal(d, refs = []) {
8
+ if (d && typeof d === "object") {
9
+ if (isBlobRef(d)) {
10
+ refs.push(d);
11
+ }
12
+ for (const value of Array.isArray(d) ? d : Object.values(d)) {
13
+ getBlobRefsInternal(value, refs);
14
+ }
15
+ }
16
+ return refs;
17
+ }
18
+ export function getBlobRefs(d) {
19
+ return getBlobRefsInternal(d);
20
+ }
21
+ function toRequest(data) {
22
+ return new Request("http://cache.key?" + encodeURI(JSON.stringify(data)));
23
+ }
24
+ async function areAllBlobRefsPresentInBlobStore(blobstore, data) {
25
+ for (const ref of getBlobRefs(data)) {
26
+ // TODO: consider using a batched request to the blobstore or await Promise.all
27
+ if (!(await blobstore.hasBlob(ref))) {
28
+ // a contained blob ref is expired, so the entire data structure is expired
29
+ return false;
30
+ }
31
+ }
32
+ return true;
33
+ }
34
+ export function createDataCache(cache) {
35
+ return {
36
+ async match(k) {
37
+ const response = await cache.match(toRequest(k));
38
+ return response?.json();
39
+ },
40
+ async put(k, v) {
41
+ const blob = new Blob([JSON.stringify(v)], { type: "application/json" });
42
+ await cache.put(toRequest(k), new Response(blob));
43
+ },
44
+ async delete(k) {
45
+ await cache.delete(toRequest(k));
46
+ },
47
+ };
48
+ }
49
+ export function createBlobRefAwareDataCache(baseCache = dataCache, blobstore = blobStore) {
50
+ return {
51
+ ...baseCache,
52
+ async match(k) {
53
+ const result = await baseCache.match(k);
54
+ if (result !== undefined &&
55
+ !(await areAllBlobRefsPresentInBlobStore(blobstore, result))) {
56
+ await baseCache.delete(k);
57
+ return undefined;
58
+ }
59
+ return result;
60
+ },
61
+ };
62
+ }
63
+ const managedPersistentCache = await getManagedPersistentCache("datacache", {
64
+ maximumMemoryEntries: 100,
65
+ maximumStorageEntries: 1000,
66
+ });
67
+ const blobRefAwareDataCache = await createBlobRefAwareDataCache(createDataCache(managedPersistentCache));
68
+ export const dataCache = createExpiringDataCache(blobRefAwareDataCache);
69
+ /**
70
+ * Retrieves a namespaced data cache. Calling it multiple times will return an equivalent cache.
71
+ * Values stored within a data cache generally persist across sessions.
72
+ * @param nameSpace A unique string used to isolate values within this cache from other caches.
73
+ */
74
+ export function getDataCache(nameSpace) {
75
+ return getNamespacedDataCacheInternal(nameSpace, dataCache);
76
+ }
77
+ function getNamespacedDataCacheInternal(name, mainCache = dataCache) {
78
+ if (!name || name.length === 0) {
79
+ throw new Error(`name is required`);
80
+ }
81
+ const getNSKey = (key) => {
82
+ return { name, key };
83
+ };
84
+ return {
85
+ async match(key) {
86
+ return (await mainCache.match(getNSKey(key)));
87
+ },
88
+ async put(key, value, options) {
89
+ await mainCache.put(getNSKey(key), value, options);
90
+ },
91
+ async delete(key) {
92
+ await mainCache.delete(getNSKey(key));
93
+ },
94
+ };
95
+ }
96
+ //# sourceMappingURL=data-cache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"data-cache.js","sourceRoot":"","sources":["../../src/cache/data-cache.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,50 @@
1
+ /*MIT License
2
+
3
+ © Copyright 2025 Adobe. All rights reserved.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.*/
22
+ import { getDataCache } from "./data-cache.js";
23
+ import { beforeAll, describe, expect, it } from "vitest";
24
+ describe("DataCache", () => {
25
+ beforeAll(() => { });
26
+ it("should allow storing and retrieving values in namespaced/versioned caches", async () => {
27
+ // get a namespaced cache
28
+ const cache = await getDataCache("test:v1");
29
+ // create some keys and values to store
30
+ const key = { foo: 1, bar: [{ baz: 12 }] };
31
+ const valueIn = { alpha: "bet", bar: ["a", "b"] };
32
+ // store a key/value pair
33
+ await cache.put(key, valueIn);
34
+ // retrieve the value
35
+ const valueOut = await cache.match(key);
36
+ // output is NOT identical
37
+ expect(valueOut !== valueIn).toBe(true);
38
+ // output IS structurally equal
39
+ expect(valueOut).toEqual(valueIn);
40
+ // output from structurally equivalent key is the same
41
+ expect(await cache.match(JSON.parse(JSON.stringify(key)))).toEqual(valueIn);
42
+ // output from equivalent cache (constructed with same name/version) is the same.
43
+ expect(await (await getDataCache("test:v1")).match(key)).toEqual(valueIn);
44
+ // output from different named cache is undefined
45
+ expect(await (await getDataCache("test2:v1")).match(key)).toEqual(undefined);
46
+ // output from different cache version is undefined
47
+ expect(await (await getDataCache("test:v2")).match(key)).toEqual(undefined);
48
+ });
49
+ });
50
+ //# sourceMappingURL=data-cache.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"data-cache.test.js","sourceRoot":"","sources":["../../src/cache/data-cache.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;WAoBW;AACX,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAEzD,QAAQ,CAAC,WAAW,EAAE,GAAG,EAAE;IACzB,SAAS,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;IACpB,EAAE,CAAC,2EAA2E,EAAE,KAAK,IAAI,EAAE;QACzF,0BAA0B;QAC1B,MAAM,KAAK,GAAG,MAAM,YAAY,CAAC,SAAS,CAAC,CAAC;QAE5C,wCAAwC;QACxC,MAAM,GAAG,GAAG,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC;QAC3C,MAAM,OAAO,GAAG,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,GAAG,EAAE,GAAG,CAAC,EAAE,CAAC;QAElD,0BAA0B;QAC1B,MAAM,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;QAE9B,sBAAsB;QACtB,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAExC,2BAA2B;QAC3B,MAAM,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAExC,gCAAgC;QAChC,MAAM,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;QAElC,uDAAuD;QACvD,MAAM,CAAC,MAAM,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;QAE5E,kFAAkF;QAClF,MAAM,CAAC,MAAM,CAAC,MAAM,YAAY,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;QAE1E,kDAAkD;QAClD,MAAM,CAAC,MAAM,CAAC,MAAM,YAAY,CAAC,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,CAC/D,SAAS,CACV,CAAC;QAEF,oDAAoD;QACpD,MAAM,CAAC,MAAM,CAAC,MAAM,YAAY,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAC9E,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -0,0 +1,6 @@
1
+ import { type Data } from "../core/data.js";
2
+ import { type DataCache, DataCacheInternal } from "./data-cache.js";
3
+ /**
4
+ * Creates a new expiring data cache with the specified underlying cache.
5
+ */
6
+ export declare function createExpiringDataCache<K extends Data, V extends Data>(baseCache: DataCacheInternal<K, V>, getTime?: () => number): DataCache<K, V>;