tinybase 4.0.0-beta.4 → 4.0.0-beta.5

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 (269) hide show
  1. package/lib/cjs/persisters/persister-automerge.cjs +1 -0
  2. package/lib/cjs/persisters/persister-automerge.cjs.gz +0 -0
  3. package/lib/cjs/persisters/persister-browser.cjs +1 -0
  4. package/lib/cjs/persisters/persister-browser.cjs.gz +0 -0
  5. package/lib/cjs/persisters/persister-cr-sqlite-wasm.cjs +1 -0
  6. package/lib/cjs/persisters/persister-cr-sqlite-wasm.cjs.gz +0 -0
  7. package/lib/cjs/persisters/persister-file.cjs +1 -0
  8. package/lib/cjs/persisters/persister-file.cjs.gz +0 -0
  9. package/lib/cjs/persisters/persister-remote.cjs +1 -0
  10. package/lib/cjs/persisters/persister-remote.cjs.gz +0 -0
  11. package/lib/cjs/persisters/persister-sqlite-wasm.cjs +1 -0
  12. package/lib/cjs/persisters/persister-sqlite-wasm.cjs.gz +0 -0
  13. package/lib/cjs/persisters/persister-sqlite3.cjs +1 -0
  14. package/lib/cjs/persisters/persister-sqlite3.cjs.gz +0 -0
  15. package/lib/cjs/persisters/persister-yjs.cjs +1 -0
  16. package/lib/cjs/persisters/persister-yjs.cjs.gz +0 -0
  17. package/lib/cjs/persisters.cjs +1 -1
  18. package/lib/cjs/persisters.cjs.gz +0 -0
  19. package/lib/cjs/store.cjs +1 -1
  20. package/lib/cjs/store.cjs.gz +0 -0
  21. package/lib/cjs/tinybase.cjs +1 -1
  22. package/lib/cjs/tinybase.cjs.gz +0 -0
  23. package/lib/cjs/tools.cjs +1 -1
  24. package/lib/cjs/tools.cjs.gz +0 -0
  25. package/lib/cjs/ui-react.cjs +1 -1
  26. package/lib/cjs/ui-react.cjs.gz +0 -0
  27. package/lib/cjs-es6/persisters/persister-automerge.cjs +1 -0
  28. package/lib/cjs-es6/persisters/persister-automerge.cjs.gz +0 -0
  29. package/lib/cjs-es6/persisters/persister-browser.cjs +1 -0
  30. package/lib/cjs-es6/persisters/persister-browser.cjs.gz +0 -0
  31. package/lib/cjs-es6/persisters/persister-cr-sqlite-wasm.cjs +1 -0
  32. package/lib/cjs-es6/persisters/persister-cr-sqlite-wasm.cjs.gz +0 -0
  33. package/lib/cjs-es6/persisters/persister-file.cjs +1 -0
  34. package/lib/cjs-es6/persisters/persister-file.cjs.gz +0 -0
  35. package/lib/cjs-es6/persisters/persister-remote.cjs +1 -0
  36. package/lib/cjs-es6/persisters/persister-remote.cjs.gz +0 -0
  37. package/lib/cjs-es6/persisters/persister-sqlite-wasm.cjs +1 -0
  38. package/lib/cjs-es6/persisters/persister-sqlite-wasm.cjs.gz +0 -0
  39. package/lib/cjs-es6/persisters/persister-sqlite3.cjs +1 -0
  40. package/lib/cjs-es6/persisters/persister-sqlite3.cjs.gz +0 -0
  41. package/lib/cjs-es6/persisters/persister-yjs.cjs +1 -0
  42. package/lib/cjs-es6/persisters/persister-yjs.cjs.gz +0 -0
  43. package/lib/cjs-es6/persisters.cjs +1 -1
  44. package/lib/cjs-es6/persisters.cjs.gz +0 -0
  45. package/lib/cjs-es6/store.cjs +1 -1
  46. package/lib/cjs-es6/store.cjs.gz +0 -0
  47. package/lib/cjs-es6/tinybase.cjs +1 -1
  48. package/lib/cjs-es6/tinybase.cjs.gz +0 -0
  49. package/lib/cjs-es6/tools.cjs +1 -1
  50. package/lib/cjs-es6/tools.cjs.gz +0 -0
  51. package/lib/cjs-es6/ui-react.cjs +1 -1
  52. package/lib/cjs-es6/ui-react.cjs.gz +0 -0
  53. package/lib/debug/{persister-automerge.js → persisters/persister-automerge.js} +57 -30
  54. package/lib/debug/{persister-browser.js → persisters/persister-browser.js} +48 -19
  55. package/lib/debug/persisters/persister-cr-sqlite-wasm.js +665 -0
  56. package/lib/debug/{persister-file.js → persisters/persister-file.js} +50 -24
  57. package/lib/debug/{persister-remote.js → persisters/persister-remote.js} +47 -18
  58. package/lib/debug/persisters/persister-sqlite-wasm.js +673 -0
  59. package/lib/debug/persisters/persister-sqlite3.js +676 -0
  60. package/lib/debug/{persister-yjs.js → persisters/persister-yjs.js} +48 -19
  61. package/lib/debug/persisters.js +46 -17
  62. package/lib/debug/store.js +77 -27
  63. package/lib/debug/tinybase.js +120 -43
  64. package/lib/debug/tools.js +121 -27
  65. package/lib/debug/ui-react.js +24 -0
  66. package/lib/es6/persisters/persister-automerge.js +1 -0
  67. package/lib/es6/persisters/persister-automerge.js.gz +0 -0
  68. package/lib/es6/persisters/persister-browser.js +1 -0
  69. package/lib/es6/persisters/persister-browser.js.gz +0 -0
  70. package/lib/es6/persisters/persister-cr-sqlite-wasm.js +1 -0
  71. package/lib/es6/persisters/persister-cr-sqlite-wasm.js.gz +0 -0
  72. package/lib/es6/persisters/persister-file.js +1 -0
  73. package/lib/es6/persisters/persister-file.js.gz +0 -0
  74. package/lib/es6/persisters/persister-remote.js +1 -0
  75. package/lib/es6/persisters/persister-remote.js.gz +0 -0
  76. package/lib/es6/persisters/persister-sqlite-wasm.js +1 -0
  77. package/lib/es6/persisters/persister-sqlite-wasm.js.gz +0 -0
  78. package/lib/es6/persisters/persister-sqlite3.js +1 -0
  79. package/lib/es6/persisters/persister-sqlite3.js.gz +0 -0
  80. package/lib/es6/persisters/persister-yjs.js +1 -0
  81. package/lib/es6/persisters/persister-yjs.js.gz +0 -0
  82. package/lib/es6/persisters.js +1 -1
  83. package/lib/es6/persisters.js.gz +0 -0
  84. package/lib/es6/store.js +1 -1
  85. package/lib/es6/store.js.gz +0 -0
  86. package/lib/es6/tinybase.js +1 -1
  87. package/lib/es6/tinybase.js.gz +0 -0
  88. package/lib/es6/tools.js +1 -1
  89. package/lib/es6/tools.js.gz +0 -0
  90. package/lib/es6/ui-react.js +1 -1
  91. package/lib/es6/ui-react.js.gz +0 -0
  92. package/lib/persisters/persister-automerge.js +1 -0
  93. package/lib/persisters/persister-automerge.js.gz +0 -0
  94. package/lib/persisters/persister-browser.js +1 -0
  95. package/lib/persisters/persister-browser.js.gz +0 -0
  96. package/lib/persisters/persister-cr-sqlite-wasm.js +1 -0
  97. package/lib/persisters/persister-cr-sqlite-wasm.js.gz +0 -0
  98. package/lib/persisters/persister-file.js +1 -0
  99. package/lib/persisters/persister-file.js.gz +0 -0
  100. package/lib/persisters/persister-remote.js +1 -0
  101. package/lib/persisters/persister-remote.js.gz +0 -0
  102. package/lib/persisters/persister-sqlite-wasm.js +1 -0
  103. package/lib/persisters/persister-sqlite-wasm.js.gz +0 -0
  104. package/lib/persisters/persister-sqlite3.js +1 -0
  105. package/lib/persisters/persister-sqlite3.js.gz +0 -0
  106. package/lib/persisters/persister-yjs.js +1 -0
  107. package/lib/persisters/persister-yjs.js.gz +0 -0
  108. package/lib/persisters.js +1 -1
  109. package/lib/persisters.js.gz +0 -0
  110. package/lib/store.js +1 -1
  111. package/lib/store.js.gz +0 -0
  112. package/lib/tinybase.js +1 -1
  113. package/lib/tinybase.js.gz +0 -0
  114. package/lib/tools.js +1 -1
  115. package/lib/tools.js.gz +0 -0
  116. package/lib/types/checkpoints.d.ts +0 -27
  117. package/lib/types/common.d.ts +0 -9
  118. package/lib/types/indexes.d.ts +0 -26
  119. package/lib/types/metrics.d.ts +0 -23
  120. package/lib/types/{persister-automerge.d.ts → persisters/persister-automerge.d.ts} +4 -6
  121. package/lib/types/{persister-browser.d.ts → persisters/persister-browser.d.ts} +2 -5
  122. package/lib/types/persisters/persister-cr-sqlite-wasm.d.ts +95 -0
  123. package/lib/types/{persister-file.d.ts → persisters/persister-file.d.ts} +3 -5
  124. package/lib/types/{persister-remote.d.ts → persisters/persister-remote.d.ts} +2 -4
  125. package/lib/types/persisters/persister-sqlite-wasm.d.ts +102 -0
  126. package/lib/types/persisters/persister-sqlite3.d.ts +109 -0
  127. package/lib/types/{persister-yjs.d.ts → persisters/persister-yjs.d.ts} +4 -6
  128. package/lib/types/persisters.d.ts +517 -27
  129. package/lib/types/queries.d.ts +52 -127
  130. package/lib/types/relationships.d.ts +0 -26
  131. package/lib/types/store.d.ts +347 -196
  132. package/lib/types/tinybase.d.ts +0 -1
  133. package/lib/types/tools.d.ts +15 -28
  134. package/lib/types/ui-react.d.ts +196 -181
  135. package/lib/types/with-schemas/checkpoints.d.ts +5 -32
  136. package/lib/types/with-schemas/common.d.ts +0 -9
  137. package/lib/types/with-schemas/indexes.d.ts +9 -35
  138. package/lib/types/with-schemas/metrics.d.ts +9 -32
  139. package/lib/types/with-schemas/{persister-automerge.d.ts → persisters/persister-automerge.d.ts} +4 -6
  140. package/lib/types/with-schemas/{persister-browser.d.ts → persisters/persister-browser.d.ts} +2 -5
  141. package/lib/types/with-schemas/persisters/persister-cr-sqlite-wasm.d.ts +105 -0
  142. package/lib/types/with-schemas/{persister-file.d.ts → persisters/persister-file.d.ts} +3 -5
  143. package/lib/types/with-schemas/{persister-remote.d.ts → persisters/persister-remote.d.ts} +2 -4
  144. package/lib/types/with-schemas/persisters/persister-sqlite-wasm.d.ts +113 -0
  145. package/lib/types/with-schemas/persisters/persister-sqlite3.d.ts +119 -0
  146. package/lib/types/with-schemas/{persister-yjs.d.ts → persisters/persister-yjs.d.ts} +4 -6
  147. package/lib/types/with-schemas/persisters.d.ts +534 -29
  148. package/lib/types/with-schemas/queries.d.ts +61 -224
  149. package/lib/types/with-schemas/relationships.d.ts +9 -35
  150. package/lib/types/with-schemas/store.d.ts +488 -239
  151. package/lib/types/with-schemas/tinybase.d.ts +0 -1
  152. package/lib/types/with-schemas/tools.d.ts +19 -32
  153. package/lib/types/with-schemas/ui-react.d.ts +221 -186
  154. package/lib/ui-react.js +1 -1
  155. package/lib/ui-react.js.gz +0 -0
  156. package/lib/umd/persisters/persister-automerge.js +1 -0
  157. package/lib/umd/persisters/persister-automerge.js.gz +0 -0
  158. package/lib/umd/persisters/persister-browser.js +1 -0
  159. package/lib/umd/persisters/persister-browser.js.gz +0 -0
  160. package/lib/umd/persisters/persister-cr-sqlite-wasm.js +1 -0
  161. package/lib/umd/persisters/persister-cr-sqlite-wasm.js.gz +0 -0
  162. package/lib/umd/persisters/persister-file.js +1 -0
  163. package/lib/umd/persisters/persister-file.js.gz +0 -0
  164. package/lib/umd/persisters/persister-remote.js +1 -0
  165. package/lib/umd/persisters/persister-remote.js.gz +0 -0
  166. package/lib/umd/persisters/persister-sqlite-wasm.js +1 -0
  167. package/lib/umd/persisters/persister-sqlite-wasm.js.gz +0 -0
  168. package/lib/umd/persisters/persister-sqlite3.js +1 -0
  169. package/lib/umd/persisters/persister-sqlite3.js.gz +0 -0
  170. package/lib/umd/persisters/persister-yjs.js +1 -0
  171. package/lib/umd/persisters/persister-yjs.js.gz +0 -0
  172. package/lib/umd/persisters.js +1 -1
  173. package/lib/umd/persisters.js.gz +0 -0
  174. package/lib/umd/store.js +1 -1
  175. package/lib/umd/store.js.gz +0 -0
  176. package/lib/umd/tinybase.js +1 -1
  177. package/lib/umd/tinybase.js.gz +0 -0
  178. package/lib/umd/tools.js +1 -1
  179. package/lib/umd/tools.js.gz +0 -0
  180. package/lib/umd/ui-react.js +1 -1
  181. package/lib/umd/ui-react.js.gz +0 -0
  182. package/lib/umd-es6/persisters/persister-automerge.js +1 -0
  183. package/lib/umd-es6/persisters/persister-automerge.js.gz +0 -0
  184. package/lib/umd-es6/persisters/persister-browser.js +1 -0
  185. package/lib/umd-es6/persisters/persister-browser.js.gz +0 -0
  186. package/lib/umd-es6/persisters/persister-cr-sqlite-wasm.js +1 -0
  187. package/lib/umd-es6/persisters/persister-cr-sqlite-wasm.js.gz +0 -0
  188. package/lib/umd-es6/persisters/persister-file.js +1 -0
  189. package/lib/umd-es6/persisters/persister-file.js.gz +0 -0
  190. package/lib/umd-es6/persisters/persister-remote.js +1 -0
  191. package/lib/umd-es6/persisters/persister-remote.js.gz +0 -0
  192. package/lib/umd-es6/persisters/persister-sqlite-wasm.js +1 -0
  193. package/lib/umd-es6/persisters/persister-sqlite-wasm.js.gz +0 -0
  194. package/lib/umd-es6/persisters/persister-sqlite3.js +1 -0
  195. package/lib/umd-es6/persisters/persister-sqlite3.js.gz +0 -0
  196. package/lib/umd-es6/persisters/persister-yjs.js +1 -0
  197. package/lib/umd-es6/persisters/persister-yjs.js.gz +0 -0
  198. package/lib/umd-es6/persisters.js +1 -1
  199. package/lib/umd-es6/persisters.js.gz +0 -0
  200. package/lib/umd-es6/store.js +1 -1
  201. package/lib/umd-es6/store.js.gz +0 -0
  202. package/lib/umd-es6/tinybase.js +1 -1
  203. package/lib/umd-es6/tinybase.js.gz +0 -0
  204. package/lib/umd-es6/tools.js +1 -1
  205. package/lib/umd-es6/tools.js.gz +0 -0
  206. package/lib/umd-es6/ui-react.js +1 -1
  207. package/lib/umd-es6/ui-react.js.gz +0 -0
  208. package/package.json +38 -21
  209. package/readme.md +3 -3
  210. package/lib/cjs/persister-automerge.cjs +0 -1
  211. package/lib/cjs/persister-automerge.cjs.gz +0 -0
  212. package/lib/cjs/persister-browser.cjs +0 -1
  213. package/lib/cjs/persister-browser.cjs.gz +0 -0
  214. package/lib/cjs/persister-file.cjs +0 -1
  215. package/lib/cjs/persister-file.cjs.gz +0 -0
  216. package/lib/cjs/persister-remote.cjs +0 -1
  217. package/lib/cjs/persister-remote.cjs.gz +0 -0
  218. package/lib/cjs/persister-yjs.cjs +0 -1
  219. package/lib/cjs/persister-yjs.cjs.gz +0 -0
  220. package/lib/cjs-es6/persister-automerge.cjs +0 -1
  221. package/lib/cjs-es6/persister-automerge.cjs.gz +0 -0
  222. package/lib/cjs-es6/persister-browser.cjs +0 -1
  223. package/lib/cjs-es6/persister-browser.cjs.gz +0 -0
  224. package/lib/cjs-es6/persister-file.cjs +0 -1
  225. package/lib/cjs-es6/persister-file.cjs.gz +0 -0
  226. package/lib/cjs-es6/persister-remote.cjs +0 -1
  227. package/lib/cjs-es6/persister-remote.cjs.gz +0 -0
  228. package/lib/cjs-es6/persister-yjs.cjs +0 -1
  229. package/lib/cjs-es6/persister-yjs.cjs.gz +0 -0
  230. package/lib/es6/persister-automerge.js +0 -1
  231. package/lib/es6/persister-automerge.js.gz +0 -0
  232. package/lib/es6/persister-browser.js +0 -1
  233. package/lib/es6/persister-browser.js.gz +0 -0
  234. package/lib/es6/persister-file.js +0 -1
  235. package/lib/es6/persister-file.js.gz +0 -0
  236. package/lib/es6/persister-remote.js +0 -1
  237. package/lib/es6/persister-remote.js.gz +0 -0
  238. package/lib/es6/persister-yjs.js +0 -1
  239. package/lib/es6/persister-yjs.js.gz +0 -0
  240. package/lib/persister-automerge.js +0 -1
  241. package/lib/persister-automerge.js.gz +0 -0
  242. package/lib/persister-browser.js +0 -1
  243. package/lib/persister-browser.js.gz +0 -0
  244. package/lib/persister-file.js +0 -1
  245. package/lib/persister-file.js.gz +0 -0
  246. package/lib/persister-remote.js +0 -1
  247. package/lib/persister-remote.js.gz +0 -0
  248. package/lib/persister-yjs.js +0 -1
  249. package/lib/persister-yjs.js.gz +0 -0
  250. package/lib/umd/persister-automerge.js +0 -1
  251. package/lib/umd/persister-automerge.js.gz +0 -0
  252. package/lib/umd/persister-browser.js +0 -1
  253. package/lib/umd/persister-browser.js.gz +0 -0
  254. package/lib/umd/persister-file.js +0 -1
  255. package/lib/umd/persister-file.js.gz +0 -0
  256. package/lib/umd/persister-remote.js +0 -1
  257. package/lib/umd/persister-remote.js.gz +0 -0
  258. package/lib/umd/persister-yjs.js +0 -1
  259. package/lib/umd/persister-yjs.js.gz +0 -0
  260. package/lib/umd-es6/persister-automerge.js +0 -1
  261. package/lib/umd-es6/persister-automerge.js.gz +0 -0
  262. package/lib/umd-es6/persister-browser.js +0 -1
  263. package/lib/umd-es6/persister-browser.js.gz +0 -0
  264. package/lib/umd-es6/persister-file.js +0 -1
  265. package/lib/umd-es6/persister-file.js.gz +0 -0
  266. package/lib/umd-es6/persister-remote.js +0 -1
  267. package/lib/umd-es6/persister-remote.js.gz +0 -0
  268. package/lib/umd-es6/persister-yjs.js +0 -1
  269. package/lib/umd-es6/persister-yjs.js.gz +0 -0
@@ -4,22 +4,28 @@
4
4
  * underlying storage types.
5
5
  *
6
6
  * Several entry points are provided (in separately installed modules), each of
7
- * which returns a new Persister object that can load and save a Store:
7
+ * which returns a new Persister object that can load and save a Store. Between
8
+ * them, these allow you to store your TinyBase data locally, remotely, to
9
+ * SQLite databases, and across synchronization boundaries with CRDT frameworks.
8
10
  *
9
- * - The createSessionPersister function (in the persister-browser module)
10
- * returns a Persister that uses the browser's session storage.
11
- * - The createLocalPersister function (in the persister-browser module) returns
12
- * a Persister that uses the browser's local storage.
13
- * - The createRemotePersister function (in the persister-remote module) returns
14
- * a Persister that uses a remote server.
15
- * - The createFilePersister function (in the persister-file module) returns a
16
- * Persister that uses a local file (in an appropriate environment).
11
+ * |Module|Function|Storage|
12
+ * |-|-|-|
13
+ * |persister-browser|createSessionPersister|Browser session storage|
14
+ * |persister-browser|createLocalPersister|Browser local storage|
15
+ * |persister-remote|createRemotePersister|Remote server|
16
+ * |persister-file|createFilePersister|Local file (where possible)|
17
+ * |persister-sqlite3|createSqlite3Persister|SQLite in Node, via [sqlite3](https://github.com/TryGhost/node-sqlite3)|
18
+ * |persister-sqlite-wasm|createSqliteWasmPersister|SQLite in a browser, via [sqlite-wasm](https://github.com/tomayac/sqlite-wasm)|
19
+ * |persister-cr-sqlite-wasm|createCrSqliteWasmPersister|SQLite CRDTs, via [cr-sqlite-wasm](https://github.com/vlcn-io/cr-sqlite)|
20
+ * |persister-yjs|createYjsPersister|Yjs CRDTs, via [yjs](https://github.com/yjs/yjs)|
21
+ * |persister-automerge|createSqliteWasmPersister|Automerge CRDTs, via [automerge-repo](https://github.com/automerge/automerge-repo)|
17
22
  *
18
23
  * Since persistence requirements can be different for every app, the
19
24
  * createCustomPersister function in this module can also be used to easily
20
25
  * create a fully customized way to save and load Store data.
21
- *
22
26
  * @see Persisting Data guide
27
+ * @see Database Persistence guide
28
+ * @see Synchronizing Data guide
23
29
  * @see Countries demo
24
30
  * @see Todo App demos
25
31
  * @see Drawing demo
@@ -30,10 +36,12 @@
30
36
  import {
31
37
  GetTransactionChanges,
32
38
  OptionalSchemas,
39
+ OptionalTablesSchema,
33
40
  Store,
34
41
  Tables,
35
42
  Values,
36
43
  } from './store.d';
44
+ import {TableIdFromSchema} from './internal/store';
37
45
 
38
46
  /**
39
47
  * The PersisterStats type describes the number of times a Persister object has
@@ -41,7 +49,6 @@ import {
41
49
  *
42
50
  * A PersisterStats object is returned from the getStats method, and is only
43
51
  * populated in a debug build.
44
- *
45
52
  * @category Development
46
53
  */
47
54
  export type PersisterStats = {
@@ -73,18 +80,476 @@ export type PersisterStats = {
73
80
  * function _is_ available, that will be used to make a wholesale change to the
74
81
  * Store. If neither are present, the content will be loaded from the
75
82
  * Persister's load method.
76
- *
77
83
  * @param getContent An optional function that, if provided, returns an array of
78
84
  * Store content and can be used to immediately wholesale update the Store.
79
85
  * @param getTransactionChanges An optional function that, if provided, returns
80
86
  * a TransactionChanges object and can be used to immediately incrementally
81
87
  * update the Store.
88
+ * @category Creation
89
+ * @since v4.0.0
82
90
  */
83
91
  export type PersisterListener<Schemas extends OptionalSchemas> = (
84
92
  getContent?: () => [Tables<Schemas[0], true>, Values<Schemas[1], true>],
85
93
  getTransactionChanges?: GetTransactionChanges<Schemas>,
86
94
  ) => void;
87
95
 
96
+ /**
97
+ * The DatabasePersisterConfig type describes the configuration of a
98
+ * database-oriented Persister, such as those for SQLite.
99
+ *
100
+ * This has schema-based typing. The following is a simplified representation:
101
+ *
102
+ * ```ts override
103
+ * DpcJson | DpcTabular;
104
+ * ```
105
+ *
106
+ * There are two modes for persisting a Store with a database:
107
+ *
108
+ * - A JSON serialization of the whole Store, which is stored in a single row of
109
+ * a table (normally called `tinybase`) within the database. This is
110
+ * configured by providing a DpcJson object.
111
+ * - A tabular mapping of Table Ids to database table names (and vice-versa).
112
+ * Values are stored in a separate special table (normally called
113
+ * `tinybase_values`). This is configured by providing a DpcTabular object.
114
+ *
115
+ * Please see the DpcJson and DpcTabular type documentation for more detail on
116
+ * each. If not specified otherwise, JSON serialization will be used for
117
+ * persistence.
118
+ *
119
+ * Changes made to the database (outside of this Persister) are picked up
120
+ * immediately if they are made via the same connection or library that it is
121
+ * using. If the database is being changed by another client, the Persister
122
+ * needs to poll for changes. Hence both configuration types also contain an
123
+ * `autoLoadIntervalSeconds` property which indicates how often it should do
124
+ * that. This defaults to 1 second.
125
+ *
126
+ * Note that all the nested types within this type have a 'Dpc' prefix, short
127
+ * for 'DatabasePersisterConfig'.
128
+ * @example
129
+ * When applied to a database Persister, this DatabasePersisterConfig will load
130
+ * and save a JSON serialization from and to a table called `my_tinybase`,
131
+ * polling the database every 2 seconds. See DpcJson for more details on these
132
+ * settings.
133
+ *
134
+ * ```js
135
+ * const databasePersisterConfig: DatabasePersisterConfig = {
136
+ * mode: 'json',
137
+ * storeTableName: 'my_tinybase',
138
+ * autoLoadIntervalSeconds: 2,
139
+ * };
140
+ * ```
141
+ * @example
142
+ * When applied to a database Persister, this DatabasePersisterConfig will load
143
+ * and save tabular data from and to tables specified in the `load` and `save`
144
+ * mappings. See DpcTabular for more details on these settings.
145
+ *
146
+ * ```js
147
+ * const databasePersisterConfig: DatabasePersisterConfig = {
148
+ * mode: 'tabular',
149
+ * tables: {
150
+ * load: {petsInDb: 'pets', speciesInDb: 'species'},
151
+ * save: {pets: 'petsInDb', species: 'speciesInDb'},
152
+ * },
153
+ * };
154
+ * ```
155
+ * @category Configuration
156
+ * @since v4.0.0
157
+ */
158
+ export type DatabasePersisterConfig<Schemas extends OptionalSchemas> =
159
+ | DpcJson
160
+ | DpcTabular<Schemas[0]>;
161
+
162
+ /**
163
+ * The DpcJson type describes the configuration of a database-oriented Persister
164
+ * operating in serialized JSON mode.
165
+ *
166
+ * The only setting is the `storeTableName` property, which indicates the name
167
+ * of a table in the database which will be used to serialize the Store content
168
+ * into. It defaults to `tinybase`.
169
+ *
170
+ * That table in the database will be given two columns: a primary key column
171
+ * called `_id`, and one called `store`. The Persister will place a single row
172
+ * in this table with `_` in the `_id` column, and the JSON serialization in the
173
+ * `store` column, something like:
174
+ *
175
+ * ```
176
+ * > SELECT * FROM tinybase;
177
+ * +-----+-----------------------------------------------------+
178
+ * | _id | store |
179
+ * +-----+-----------------------------------------------------+
180
+ * | _ | [{"pets":{"fido":{"species":"dog"}}},{"open":true}] |
181
+ * +-----+-----------------------------------------------------+
182
+ * ```
183
+ *
184
+ * The 'Dpc' prefix indicates that this type is used within the
185
+ * DatabasePersisterConfig type.
186
+ * @example
187
+ * When applied to a database Persister, this DatabasePersisterConfig will load
188
+ * and save a JSON serialization from and to a table called `tinybase_json`.
189
+ *
190
+ * ```js
191
+ * const databasePersisterConfig: DatabasePersisterConfig = {
192
+ * mode: 'json',
193
+ * storeTableName: 'tinybase_json',
194
+ * };
195
+ * ```
196
+ * @category Configuration
197
+ * @since v4.0.0
198
+ */
199
+ export type DpcJson = {
200
+ /**
201
+ * The mode to be used for persisting the Store to the database, in this case
202
+ * JSON serialization. See the DpcTabular type for the alternative tabular
203
+ * mapping mode.
204
+ */
205
+ mode: 'json';
206
+ /**
207
+ * An optional string which indicates the name of a table in the database
208
+ * which will be used to serialize the Store content into. It defaults to
209
+ * `tinybase`.
210
+ */
211
+ storeTableName?: string;
212
+ /**
213
+ * How often the Persister should poll the database for any changes made to it
214
+ * by other clients, defaulting to 1 second.
215
+ */
216
+ autoLoadIntervalSeconds?: number;
217
+ };
218
+
219
+ /**
220
+ * The DpcTabular type describes the configuration of a database-oriented
221
+ * Persister that is operating in tabular mapping mode.
222
+ *
223
+ * It is important to note that both the tabular mapping in ('save') and out
224
+ * ('load') of an underlying database are disabled by default. This is to ensure
225
+ * that if you pass in an existing populated database you don't run the
226
+ * immediate risk of corrupting or losing all your data.
227
+ *
228
+ * This configuration therefore takes a `tables` property object (with child
229
+ * `load` and `save` property objects) and a `values` property object. These
230
+ * indicate how you want to load and save Tables and Values respectively. At
231
+ * least one of these two properties are required for the Persister to do
232
+ * anything!
233
+ *
234
+ * Note that if you are planning to both load from and save to a database, it is
235
+ * important to make sure that the load and save table mappings are symmetrical.
236
+ * For example:
237
+ *
238
+ * ```js
239
+ * const databasePersisterConfig: DatabasePersisterConfig = {
240
+ * mode: 'tabular',
241
+ * tables: {
242
+ * load: {petsInDb: 'pets', speciesInDb: 'species'},
243
+ * save: {pets: 'petsInDb', species: 'speciesInDb'},
244
+ * },
245
+ * };
246
+ * ```
247
+ *
248
+ * See the documentation for the DpcTabularLoad, DpcTabularSave, and
249
+ * DpcTabularValues types for more details on how to configure the tabular
250
+ * mapping mode.
251
+ *
252
+ * The 'Dpc' prefix indicates that this type is used within the
253
+ * DatabasePersisterConfig type.
254
+ * @example
255
+ * When applied to a database Persister, this DatabasePersisterConfig will load
256
+ * and save Tables data from and to tables specified in the `load` and `save`
257
+ * mappings, and Values data from and to a table called `my_tinybase_values`.
258
+ *
259
+ * ```js
260
+ * const databasePersisterConfig: DatabasePersisterConfig = {
261
+ * mode: 'tabular',
262
+ * tables: {
263
+ * load: {petsInDb: 'pets', speciesInDb: 'species'},
264
+ * save: {pets: 'petsInDb', species: 'speciesInDb'},
265
+ * },
266
+ * values: {
267
+ * load: true,
268
+ * save: true,
269
+ * tableName: 'my_tinybase_values',
270
+ * },
271
+ * };
272
+ * ```
273
+ * @category Configuration
274
+ * @since v4.0.0
275
+ */
276
+ export type DpcTabular<Schema extends OptionalTablesSchema> = {
277
+ /**
278
+ * The mode to be used for persisting the Store to the database, in this case
279
+ * tabular mapping. See the DpcJson type for the alternative JSON
280
+ * serialization mode.
281
+ */
282
+ mode: 'tabular';
283
+ /**
284
+ * The settings for how the Store Tables are mapped to and from the database.
285
+ */
286
+ tables?: {
287
+ /**
288
+ * The settings for how the database tables are mapped into the Store Tables
289
+ * when loading.
290
+ */
291
+ load?: DpcTabularLoad<Schema>;
292
+ /**
293
+ * The settings for how the Store Tables are mapped out to the database
294
+ * tables when saving.
295
+ */
296
+ save?: DpcTabularSave<Schema>;
297
+ };
298
+ /**
299
+ * The settings for how the Store Values are mapped to and from the database.
300
+ */
301
+ values?: DpcTabularValues;
302
+ /**
303
+ * How often the Persister should poll the database for any changes made to it
304
+ * by other clients, defaulting to 1 second.
305
+ */
306
+ autoLoadIntervalSeconds?: number;
307
+ };
308
+
309
+ /**
310
+ * The DpcTabularLoad type describes the configuration for loading Tables in a
311
+ * database-oriented Persister that is operating in tabular mode.
312
+ *
313
+ * It is an object where each key is a name of a database table, and the value
314
+ * is a child configuration object for how that table should be loaded into the
315
+ * Store. The properties of the child configuration object are:
316
+ *
317
+ * ||Type|Description|
318
+ * |-|-|-|
319
+ * |`tableId`|Id|The Id of the Store Table into which data from this database table should be loaded.|
320
+ * |`rowIdColumnName?`|string|The optional name of the column in the database table that will be used as the Row Ids in the Store Table, defaulting to '_id'.|
321
+ *
322
+ * As a shortcut, if you do not need to specify a custom `rowIdColumnName`, you
323
+ * can simply provide the Id of the Store Table instead of the whole object.
324
+ *
325
+ * The 'Dpc' prefix indicates that this type is used within the
326
+ * DatabasePersisterConfig type.
327
+ * @example
328
+ * When applied to a database Persister, this DatabasePersisterConfig will load
329
+ * the data of two database tables (called 'petsInDb' and 'speciesInDb') into
330
+ * two Store Tables (called 'pets' and 'species'). One has a column for the Row
331
+ * Id called 'id' and the other defaults it to '_id'.
332
+ *
333
+ * ```js
334
+ * const databasePersisterConfig: DatabasePersisterConfig = {
335
+ * mode: 'tabular',
336
+ * tables: {
337
+ * load: {
338
+ * petsInDb: {tableId: 'pets', rowIdColumnName: 'id'},
339
+ * speciesInDb: 'species',
340
+ * },
341
+ * },
342
+ * };
343
+ * ```
344
+ *
345
+ * Imagine database tables that look like this:
346
+ *
347
+ * ```
348
+ * > SELECT * FROM petsInDb;
349
+ * +-------+---------+-------+
350
+ * | id | species | color |
351
+ * +-------+---------+-------+
352
+ * | fido | dog | brown |
353
+ * | felix | cat | black |
354
+ * +-------+---------+-------+
355
+ *
356
+ * > SELECT * FROM speciesInDb;
357
+ * +------+-------+
358
+ * | _id | price |
359
+ * +------+-------+
360
+ * | dog | 5 |
361
+ * | cat | 4 |
362
+ * +------+-------+
363
+ * ```
364
+ *
365
+ * With the configuration above, this will load into a Store with Tables that
366
+ * look like this:
367
+ *
368
+ * ```json
369
+ * {
370
+ * "pets": {
371
+ * "fido": {"species": "dog", "color": "brown"},
372
+ * "felix": {"species": "cat", "color": "black"},
373
+ * },
374
+ * "species": {
375
+ * "dog": {"price": 5},
376
+ * "cat": {"price": 4},
377
+ * },
378
+ * }
379
+ * ```
380
+ * @category Configuration
381
+ * @since v4.0.0
382
+ */
383
+ export type DpcTabularLoad<Schema extends OptionalTablesSchema> = {
384
+ [tableName: string]:
385
+ | {
386
+ /**
387
+ * The Id of the Store Table into which data from this database table
388
+ * should be loaded.
389
+ */
390
+ tableId: TableIdFromSchema<Schema>;
391
+ /**
392
+ * The optional name of the column in the database table that will be
393
+ * used as the Row Ids in the Store Table, defaulting to '_id'.
394
+ */
395
+ rowIdColumnName?: string;
396
+ }
397
+ | TableIdFromSchema<Schema>;
398
+ };
399
+
400
+ /**
401
+ * The DpcTabularSave type describes the configuration for saving Tables in a
402
+ * database-oriented Persister that is operating in tabular mode.
403
+ *
404
+ * It is an object where each key is an Id of a Store Table, and the value is a
405
+ * child configuration object for how that Table should be saved out to the
406
+ * database. The properties of the child configuration object are:
407
+ *
408
+ * ||Type|Description|
409
+ * |-|-|-|
410
+ * |`tableName`|string|The name of the database table out to which the Store Table should be saved.|
411
+ * |`rowIdColumnName?`|string|The optional name of the column in the database table that will be used to save the Row Ids from the Store Table, defaulting to '_id'.|
412
+ * |`deleteEmptyColumns?`|boolean|Whether columns in the database table will be removed if they are empty in the Store Table, defaulting to false.|
413
+ * |`deleteEmptyTable?`|boolean|Whether tables in the database will be removed if the Store Table is empty, defaulting to false.|
414
+ *
415
+ * As a shortcut, if you do not need to specify a custom `rowIdColumnName`, or
416
+ * enable the `deleteEmptyColumns` or `deleteEmptyTable` settings, you can
417
+ * simply provide the name of the database table instead of the whole object.
418
+ *
419
+ * The 'Dpc' prefix indicates that this type is used within the
420
+ * DatabasePersisterConfig type.
421
+ * @example
422
+ * When applied to a database Persister, this DatabasePersisterConfig will save
423
+ * the data of two Store Tables (called 'pets' and 'species') into two database
424
+ * tables (called 'petsInDb' and 'speciesInDb'). One has a column for the Row
425
+ * Id called 'id' and will delete columns and the whole table if empty, the
426
+ * other defaults to '_id' and will not delete columns or the whole table if
427
+ * empty.
428
+ *
429
+ * ```js
430
+ * const databasePersisterConfig: DatabasePersisterConfig = {
431
+ * mode: 'tabular',
432
+ * tables: {
433
+ * save: {
434
+ * pets: {
435
+ * tableName: 'petsInDb',
436
+ * deleteEmptyColumns: true,
437
+ * deleteEmptyTable: true,
438
+ * },
439
+ * species: 'speciesInDb',
440
+ * },
441
+ * },
442
+ * };
443
+ * ```
444
+ *
445
+ * Imagine a Store with Tables that look like this:
446
+ *
447
+ * ```json
448
+ * {
449
+ * "pets": {
450
+ * "fido": {"species": "dog", "color": "brown"},
451
+ * "felix": {"species": "cat", "color": "black"},
452
+ * },
453
+ * "species": {
454
+ * "dog": {"price": 5},
455
+ * "cat": {"price": 4},
456
+ * },
457
+ * }
458
+ * ```
459
+ *
460
+ * With the configuration above, this will save out to a database with tables
461
+ * that look like this:
462
+ *
463
+ * ```
464
+ * > SELECT * FROM petsInDb;
465
+ * +-------+---------+-------+
466
+ * | id | species | color |
467
+ * +-------+---------+-------+
468
+ * | fido | dog | brown |
469
+ * | felix | cat | black |
470
+ * +-------+---------+-------+
471
+ *
472
+ * > SELECT * FROM speciesInDb;
473
+ * +------+-------+
474
+ * | _id | price |
475
+ * +------+-------+
476
+ * | dog | 5 |
477
+ * | cat | 4 |
478
+ * +------+-------+
479
+ * ```
480
+ * @category Configuration
481
+ * @since v4.0.0
482
+ */
483
+ export type DpcTabularSave<Schema extends OptionalTablesSchema> = {
484
+ [TableId in TableIdFromSchema<Schema>]:
485
+ | {
486
+ /**
487
+ * The name of the database table out to which the Store Table should be
488
+ * saved.
489
+ */
490
+ tableName: string;
491
+ /**
492
+ * The optional name of the column in the database table that will be
493
+ * used to save the Row Ids from the Store Table, defaulting to '_id'.
494
+ */
495
+ rowIdColumnName?: string;
496
+ /**
497
+ * Whether columns in the database table will be removed if they are
498
+ * empty in the Store Table, defaulting to false.
499
+ */
500
+ deleteEmptyColumns?: boolean;
501
+ /**
502
+ * Whether tables in the database will be removed if the Store Table
503
+ * is empty, defaulting to false.
504
+ */
505
+ deleteEmptyTable?: boolean;
506
+ }
507
+ | string;
508
+ };
509
+
510
+ /**
511
+ * The DpcTabularValues type describes the configuration for handling Values in
512
+ * a database-oriented Persister that is operating in tabular mode.
513
+ *
514
+ * Note that both loading and saving of Values from and to the database are
515
+ * disabled by default.
516
+ *
517
+ * The 'Dpc' prefix indicates that this type is used within the
518
+ * DatabasePersisterConfig type.
519
+ * @example
520
+ * When applied to a database Persister, this DatabasePersisterConfig will load
521
+ * and save the data of a Store's Values into a database
522
+ * table called 'my_tinybase_values'.
523
+ *
524
+ * ```js
525
+ * const databasePersisterConfig: DatabasePersisterConfig = {
526
+ * mode: 'tabular',
527
+ * values: {
528
+ * load: true,
529
+ * save: true,
530
+ * tableName: 'my_tinybase_values',
531
+ * },
532
+ * };
533
+ * ```
534
+ * @category Configuration
535
+ * @since v4.0.0
536
+ */
537
+ export type DpcTabularValues = {
538
+ /**
539
+ * Whether Store Values will be loaded from a database table.
540
+ */
541
+ load?: boolean;
542
+ /**
543
+ * Whether Store Values will be saved to a database table.
544
+ */
545
+ save?: boolean;
546
+ /**
547
+ * The optional name of the database table from and to which the Store Table
548
+ * should be loaded or saved, defaulting to `tinybase_values`.
549
+ */
550
+ tableName?: string;
551
+ };
552
+
88
553
  /**
89
554
  * A Persister object lets you save and load Store data to and from different
90
555
  * locations, or underlying storage types.
@@ -128,7 +593,6 @@ export type PersisterListener<Schemas extends OptionalSchemas> = (
128
593
  * persistence strategy to understand the opportunity for data loss (in the case
129
594
  * of trying to save data to a server under poor network conditions, for
130
595
  * example).
131
- *
132
596
  * @example
133
597
  * This example creates a Store, persists it to the browser's session storage as
134
598
  * a JSON string, changes the persisted data, updates the Store from it, and
@@ -201,7 +665,6 @@ export interface Persister<in out Schemas extends OptionalSchemas> {
201
665
  * machine or a filesystem. Even for those storage types that are synchronous
202
666
  * (like browser storage) it is still recommended that you `await` calls to
203
667
  * this method or handle the return type natively as a Promise.
204
- *
205
668
  * @param initialTables An optional Tables object used when the underlying
206
669
  * storage has not previously been populated.
207
670
  * @param initialValues An optional Values object used when the underlying
@@ -281,7 +744,6 @@ export interface Persister<in out Schemas extends OptionalSchemas> {
281
744
  * the asynchronous load method. Even for those storage types that are
282
745
  * synchronous (like browser storage) it is still recommended that you `await`
283
746
  * calls to this method or handle the return type natively as a Promise.
284
- *
285
747
  * @param initialTables An optional Tables object used when the underlying
286
748
  * storage has not previously been populated.
287
749
  * @param initialValues An optional Values object used when the underlying
@@ -332,7 +794,6 @@ export interface Persister<in out Schemas extends OptionalSchemas> {
332
794
  *
333
795
  * If the Persister is not currently set to automatically load, this method
334
796
  * has no effect.
335
- *
336
797
  * @returns A reference to the Persister object.
337
798
  * @example
338
799
  * This example creates an empty Store, and starts automatically loading data
@@ -385,7 +846,6 @@ export interface Persister<in out Schemas extends OptionalSchemas> {
385
846
  * machine or a filesystem. Even for those storage types that are synchronous
386
847
  * (like browser storage) it is still recommended that you `await` calls to
387
848
  * this method or handle the return type natively as a Promise.
388
- *
389
849
  * @returns A Promise containing a reference to the Persister object.
390
850
  * @example
391
851
  * This example creates a Store with some data, and saves into the browser's
@@ -424,7 +884,6 @@ export interface Persister<in out Schemas extends OptionalSchemas> {
424
884
  * the asynchronous save method. Even for those storage types that are
425
885
  * synchronous (like browser storage) it is still recommended that you `await`
426
886
  * calls to this method or handle the return type natively as a Promise.
427
- *
428
887
  * @returns A Promise containing a reference to the Persister object.
429
888
  * @example
430
889
  * This example creates a Store with some data, and saves into the browser's
@@ -462,7 +921,6 @@ export interface Persister<in out Schemas extends OptionalSchemas> {
462
921
  *
463
922
  * If the Persister is not currently set to automatically save, this method
464
923
  * has no effect.
465
- *
466
924
  * @returns A reference to the Persister object.
467
925
  * @example
468
926
  * This example creates a Store with some data, and saves into the browser's
@@ -495,20 +953,68 @@ export interface Persister<in out Schemas extends OptionalSchemas> {
495
953
  stopAutoSave(): Persister<Schemas>;
496
954
 
497
955
  /**
498
- * The getStore method returns a reference to the underlying Store that is
499
- * backing this Persister object.
956
+ * The schedule method allows you to queue up a series of asynchronous actions
957
+ * that must run in sequence during persistence.
500
958
  *
501
959
  * This has schema-based typing. The following is a simplified representation:
502
960
  *
503
961
  * ```ts override
504
- * getStore(): Store;
962
+ * schedule(...actions: Promise<any>[]): Promise<Persister>;
505
963
  * ```
506
964
  *
965
+ * For example, a database Persister may need to ensure that multiple
966
+ * asynchronous tasks to check and update the database schema are completed
967
+ * before data is written to it. Therefore it's most likely you will be using
968
+ * this method inside your `setPersisted` implementation.
969
+ *
970
+ * Call this method to add a single asynchronous action, or a sequence of them
971
+ * in one call. This will also start to run the first task in the queue (which
972
+ * once complete will then run the next, and so on), and so this method itself
973
+ * is also asynchronous and returns a promise of the Persister.
974
+ * @returns A reference to the Persister object.
975
+ * @example
976
+ * This example creates a custom Persister object against a newly-created
977
+ * Store and then sequences two tasks in order to update its data on a
978
+ * hypothetical remote system.
979
+ *
980
+ * ```js yolo
981
+ * const store = createStore();
982
+ * const persister = createCustomPersister(
983
+ * store,
984
+ * async () => {
985
+ * // getPersisted
986
+ * return await getDataFromRemoteSystem();
987
+ * },
988
+ * async (getContent) => {
989
+ * // setPersisted
990
+ * await persister.schedule(
991
+ * async () => await checkRemoteSystemIsReady(),
992
+ * async () => await sendDataToRemoteSystem(getContent()),
993
+ * );
994
+ * },
995
+ * (listener) => setInterval(listener, 1000),
996
+ * (interval) => clearInterval(interval),
997
+ * );
998
+ * ```
999
+ * @category Lifecycle
1000
+ * @since v4.0.0
1001
+ */
1002
+ schedule(...actions: Promise<any>[]): Promise<Persister<Schemas>>;
1003
+
1004
+ /**
1005
+ * The getStore method returns a reference to the underlying Store that is
1006
+ * backing this Persister object.
507
1007
  * @returns A reference to the Store.
508
1008
  * @example
509
1009
  * This example creates a Persister object against a newly-created Store and
510
1010
  * then gets its reference in order to update its data.
511
1011
  *
1012
+ * This has schema-based typing. The following is a simplified representation:
1013
+ *
1014
+ * ```ts override
1015
+ * getStore(): Store;
1016
+ * ```
1017
+ *
512
1018
  * ```js
513
1019
  * const persister = createSessionPersister(createStore(), 'pets');
514
1020
  * await persister.startAutoSave();
@@ -538,7 +1044,6 @@ export interface Persister<in out Schemas extends OptionalSchemas> {
538
1044
  * the underlying Store and storage are removed and it can be correctly
539
1045
  * garbage collected. It is equivalent to running the stopAutoLoad method and
540
1046
  * the stopAutoSave method in succession.
541
- *
542
1047
  * @example
543
1048
  * This example creates a Store, associates a Persister object with it (that
544
1049
  * registers a TablesListener with the underlying Store), and then destroys it
@@ -572,7 +1077,6 @@ export interface Persister<in out Schemas extends OptionalSchemas> {
572
1077
  * return an empty object. The method is intended to be used during
573
1078
  * development to ensure your persistence layer is acting as expected, for
574
1079
  * example.
575
- *
576
1080
  * @returns A PersisterStats object containing Persister load and save
577
1081
  * statistics.
578
1082
  * @example
@@ -643,7 +1147,6 @@ export interface Persister<in out Schemas extends OptionalSchemas> {
643
1147
  * function must return the content (or nothing) rather than JSON.
644
1148
  * `startListeningToPersisted` has been renamed `addPersisterListener`, and
645
1149
  * `stopListeningToPersisted` has been renamed `delPersisterListener`.
646
- *
647
1150
  * @param store The Store to persist.
648
1151
  * @param getPersisted An asynchronous function which will fetch content from
649
1152
  * the persistence layer (or `undefined` if not present).
@@ -670,11 +1173,13 @@ export interface Persister<in out Schemas extends OptionalSchemas> {
670
1173
  * const persister = createCustomPersister(
671
1174
  * store,
672
1175
  * async () => {
673
- * try {
674
- * return JSON.parse(storeJson);
675
- * } catch {}
1176
+ * // getPersisted
1177
+ * return JSON.parse(storeJson);
1178
+ * },
1179
+ * async (getContent) => {
1180
+ * // setPersisted
1181
+ * storeJson = JSON.stringify(getContent());
676
1182
  * },
677
- * async (getContent) => (storeJson = JSON.stringify(getContent())),
678
1183
  * (listener) => setInterval(listener, 1000),
679
1184
  * (interval) => clearInterval(interval),
680
1185
  * );