tinybase 4.2.3 → 4.3.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (158) hide show
  1. package/lib/cjs/persisters/persister-cr-sqlite-wasm.cjs +1 -1
  2. package/lib/cjs/persisters/persister-cr-sqlite-wasm.cjs.gz +0 -0
  3. package/lib/cjs/persisters/persister-expo-sqlite.cjs +1 -1
  4. package/lib/cjs/persisters/persister-expo-sqlite.cjs.gz +0 -0
  5. package/lib/cjs/persisters/persister-partykit-client.cjs +1 -0
  6. package/lib/cjs/persisters/persister-partykit-client.cjs.gz +0 -0
  7. package/lib/cjs/persisters/persister-partykit-server.cjs +1 -0
  8. package/lib/cjs/persisters/persister-partykit-server.cjs.gz +0 -0
  9. package/lib/cjs/persisters/persister-sqlite-wasm.cjs +1 -1
  10. package/lib/cjs/persisters/persister-sqlite-wasm.cjs.gz +0 -0
  11. package/lib/cjs/persisters/persister-sqlite3.cjs +1 -1
  12. package/lib/cjs/persisters/persister-sqlite3.cjs.gz +0 -0
  13. package/lib/cjs/store.cjs +1 -1
  14. package/lib/cjs/store.cjs.gz +0 -0
  15. package/lib/cjs/tinybase.cjs +1 -1
  16. package/lib/cjs/tinybase.cjs.gz +0 -0
  17. package/lib/cjs/tools.cjs +1 -1
  18. package/lib/cjs/tools.cjs.gz +0 -0
  19. package/lib/cjs/ui-react-dom-debug.cjs +1 -1
  20. package/lib/cjs/ui-react-dom-debug.cjs.gz +0 -0
  21. package/lib/cjs/ui-react.cjs +1 -1
  22. package/lib/cjs/ui-react.cjs.gz +0 -0
  23. package/lib/cjs-es6/persisters/persister-cr-sqlite-wasm.cjs +1 -1
  24. package/lib/cjs-es6/persisters/persister-cr-sqlite-wasm.cjs.gz +0 -0
  25. package/lib/cjs-es6/persisters/persister-expo-sqlite.cjs +1 -1
  26. package/lib/cjs-es6/persisters/persister-expo-sqlite.cjs.gz +0 -0
  27. package/lib/cjs-es6/persisters/persister-partykit-client.cjs +1 -0
  28. package/lib/cjs-es6/persisters/persister-partykit-client.cjs.gz +0 -0
  29. package/lib/cjs-es6/persisters/persister-partykit-server.cjs +1 -0
  30. package/lib/cjs-es6/persisters/persister-partykit-server.cjs.gz +0 -0
  31. package/lib/cjs-es6/persisters/persister-sqlite-wasm.cjs +1 -1
  32. package/lib/cjs-es6/persisters/persister-sqlite-wasm.cjs.gz +0 -0
  33. package/lib/cjs-es6/persisters/persister-sqlite3.cjs +1 -1
  34. package/lib/cjs-es6/persisters/persister-sqlite3.cjs.gz +0 -0
  35. package/lib/cjs-es6/store.cjs +1 -1
  36. package/lib/cjs-es6/store.cjs.gz +0 -0
  37. package/lib/cjs-es6/tinybase.cjs +1 -1
  38. package/lib/cjs-es6/tinybase.cjs.gz +0 -0
  39. package/lib/cjs-es6/tools.cjs +1 -1
  40. package/lib/cjs-es6/tools.cjs.gz +0 -0
  41. package/lib/cjs-es6/ui-react-dom-debug.cjs +1 -1
  42. package/lib/cjs-es6/ui-react-dom-debug.cjs.gz +0 -0
  43. package/lib/cjs-es6/ui-react.cjs +1 -1
  44. package/lib/cjs-es6/ui-react.cjs.gz +0 -0
  45. package/lib/debug/persisters/persister-cr-sqlite-wasm.js +10 -7
  46. package/lib/debug/persisters/persister-expo-sqlite.js +10 -7
  47. package/lib/debug/persisters/persister-partykit-client.js +249 -0
  48. package/lib/debug/persisters/persister-partykit-server.js +161 -0
  49. package/lib/debug/persisters/persister-sqlite-wasm.js +10 -7
  50. package/lib/debug/persisters/persister-sqlite3.js +10 -7
  51. package/lib/debug/queries.js +2 -2
  52. package/lib/debug/store.js +3 -3
  53. package/lib/debug/tinybase.js +4 -4
  54. package/lib/debug/tools.js +3 -4
  55. package/lib/debug/ui-react-dom.js +3 -3
  56. package/lib/debug/ui-react.js +1 -1
  57. package/lib/es6/persisters/persister-cr-sqlite-wasm.js +1 -1
  58. package/lib/es6/persisters/persister-cr-sqlite-wasm.js.gz +0 -0
  59. package/lib/es6/persisters/persister-expo-sqlite.js +1 -1
  60. package/lib/es6/persisters/persister-expo-sqlite.js.gz +0 -0
  61. package/lib/es6/persisters/persister-partykit-client.js +1 -0
  62. package/lib/es6/persisters/persister-partykit-client.js.gz +0 -0
  63. package/lib/es6/persisters/persister-partykit-server.js +1 -0
  64. package/lib/es6/persisters/persister-partykit-server.js.gz +0 -0
  65. package/lib/es6/persisters/persister-sqlite-wasm.js +1 -1
  66. package/lib/es6/persisters/persister-sqlite-wasm.js.gz +0 -0
  67. package/lib/es6/persisters/persister-sqlite3.js +1 -1
  68. package/lib/es6/persisters/persister-sqlite3.js.gz +0 -0
  69. package/lib/es6/store.js +1 -1
  70. package/lib/es6/store.js.gz +0 -0
  71. package/lib/es6/tinybase.js +1 -1
  72. package/lib/es6/tinybase.js.gz +0 -0
  73. package/lib/es6/tools.js +1 -1
  74. package/lib/es6/tools.js.gz +0 -0
  75. package/lib/es6/ui-react-dom-debug.js +1 -1
  76. package/lib/es6/ui-react-dom-debug.js.gz +0 -0
  77. package/lib/es6/ui-react.js +1 -1
  78. package/lib/es6/ui-react.js.gz +0 -0
  79. package/lib/persisters/persister-cr-sqlite-wasm.js +1 -1
  80. package/lib/persisters/persister-cr-sqlite-wasm.js.gz +0 -0
  81. package/lib/persisters/persister-expo-sqlite.js +1 -1
  82. package/lib/persisters/persister-expo-sqlite.js.gz +0 -0
  83. package/lib/persisters/persister-partykit-client.js +1 -0
  84. package/lib/persisters/persister-partykit-client.js.gz +0 -0
  85. package/lib/persisters/persister-partykit-server.js +1 -0
  86. package/lib/persisters/persister-partykit-server.js.gz +0 -0
  87. package/lib/persisters/persister-sqlite-wasm.js +1 -1
  88. package/lib/persisters/persister-sqlite-wasm.js.gz +0 -0
  89. package/lib/persisters/persister-sqlite3.js +1 -1
  90. package/lib/persisters/persister-sqlite3.js.gz +0 -0
  91. package/lib/store.js +1 -1
  92. package/lib/store.js.gz +0 -0
  93. package/lib/tinybase.js +1 -1
  94. package/lib/tinybase.js.gz +0 -0
  95. package/lib/tools.js +1 -1
  96. package/lib/tools.js.gz +0 -0
  97. package/lib/types/persisters/persister-cr-sqlite-wasm.d.ts +2 -0
  98. package/lib/types/persisters/persister-expo-sqlite.d.ts +2 -0
  99. package/lib/types/persisters/persister-partykit-client.d.ts +87 -0
  100. package/lib/types/persisters/persister-partykit-server.d.ts +113 -0
  101. package/lib/types/persisters/persister-sqlite-wasm.d.ts +2 -0
  102. package/lib/types/persisters/persister-sqlite3.d.ts +2 -0
  103. package/lib/types/ui-react.d.ts +12 -4
  104. package/lib/types/with-schemas/persisters/persister-cr-sqlite-wasm.d.ts +2 -0
  105. package/lib/types/with-schemas/persisters/persister-expo-sqlite.d.ts +2 -0
  106. package/lib/types/with-schemas/persisters/persister-partykit-client.d.ts +98 -0
  107. package/lib/types/with-schemas/persisters/persister-partykit-server.d.ts +113 -0
  108. package/lib/types/with-schemas/persisters/persister-sqlite-wasm.d.ts +2 -0
  109. package/lib/types/with-schemas/persisters/persister-sqlite3.d.ts +2 -0
  110. package/lib/types/with-schemas/ui-react.d.ts +18 -8
  111. package/lib/ui-react.js +1 -1
  112. package/lib/ui-react.js.gz +0 -0
  113. package/lib/umd/persisters/persister-cr-sqlite-wasm.js +1 -1
  114. package/lib/umd/persisters/persister-cr-sqlite-wasm.js.gz +0 -0
  115. package/lib/umd/persisters/persister-expo-sqlite.js +1 -1
  116. package/lib/umd/persisters/persister-expo-sqlite.js.gz +0 -0
  117. package/lib/umd/persisters/persister-partykit-client.js +1 -0
  118. package/lib/umd/persisters/persister-partykit-client.js.gz +0 -0
  119. package/lib/umd/persisters/persister-partykit-server.js +1 -0
  120. package/lib/umd/persisters/persister-partykit-server.js.gz +0 -0
  121. package/lib/umd/persisters/persister-sqlite-wasm.js +1 -1
  122. package/lib/umd/persisters/persister-sqlite-wasm.js.gz +0 -0
  123. package/lib/umd/persisters/persister-sqlite3.js +1 -1
  124. package/lib/umd/persisters/persister-sqlite3.js.gz +0 -0
  125. package/lib/umd/store.js +1 -1
  126. package/lib/umd/store.js.gz +0 -0
  127. package/lib/umd/tinybase.js +1 -1
  128. package/lib/umd/tinybase.js.gz +0 -0
  129. package/lib/umd/tools.js +1 -1
  130. package/lib/umd/tools.js.gz +0 -0
  131. package/lib/umd/ui-react-dom-debug.js +1 -1
  132. package/lib/umd/ui-react-dom-debug.js.gz +0 -0
  133. package/lib/umd/ui-react.js +1 -1
  134. package/lib/umd/ui-react.js.gz +0 -0
  135. package/lib/umd-es6/persisters/persister-cr-sqlite-wasm.js +1 -1
  136. package/lib/umd-es6/persisters/persister-cr-sqlite-wasm.js.gz +0 -0
  137. package/lib/umd-es6/persisters/persister-expo-sqlite.js +1 -1
  138. package/lib/umd-es6/persisters/persister-expo-sqlite.js.gz +0 -0
  139. package/lib/umd-es6/persisters/persister-partykit-client.js +1 -0
  140. package/lib/umd-es6/persisters/persister-partykit-client.js.gz +0 -0
  141. package/lib/umd-es6/persisters/persister-partykit-server.js +1 -0
  142. package/lib/umd-es6/persisters/persister-partykit-server.js.gz +0 -0
  143. package/lib/umd-es6/persisters/persister-sqlite-wasm.js +1 -1
  144. package/lib/umd-es6/persisters/persister-sqlite-wasm.js.gz +0 -0
  145. package/lib/umd-es6/persisters/persister-sqlite3.js +1 -1
  146. package/lib/umd-es6/persisters/persister-sqlite3.js.gz +0 -0
  147. package/lib/umd-es6/store.js +1 -1
  148. package/lib/umd-es6/store.js.gz +0 -0
  149. package/lib/umd-es6/tinybase.js +1 -1
  150. package/lib/umd-es6/tinybase.js.gz +0 -0
  151. package/lib/umd-es6/tools.js +1 -1
  152. package/lib/umd-es6/tools.js.gz +0 -0
  153. package/lib/umd-es6/ui-react-dom-debug.js +1 -1
  154. package/lib/umd-es6/ui-react-dom-debug.js.gz +0 -0
  155. package/lib/umd-es6/ui-react.js +1 -1
  156. package/lib/umd-es6/ui-react.js.gz +0 -0
  157. package/package.json +23 -13
  158. package/readme.md +13 -13
@@ -14,6 +14,7 @@ const ifNotUndefined = (value, then, otherwise) =>
14
14
  isUndefined(value) ? otherwise?.() : then(value);
15
15
  const isString = (thing) => getTypeOf(thing) == STRING;
16
16
  const isArray = (thing) => Array.isArray(thing);
17
+ const slice = (arrayOrString, start, end) => arrayOrString.slice(start, end);
17
18
  const promiseAll = async (promises) => promise.all(promises);
18
19
 
19
20
  const arrayJoin = (array, sep = EMPTY_STRING) => array.join(sep);
@@ -21,7 +22,6 @@ const arrayMap = (array, cb) => array.map(cb);
21
22
  const arrayLength = (array) => array.length;
22
23
  const arrayIsEmpty = (array) => arrayLength(array) == 0;
23
24
  const arrayFilter = (array, cb) => array.filter(cb);
24
- const arraySlice = (array, start, end) => array.slice(start, end);
25
25
  const arrayPush = (array, ...values) => array.push(...values);
26
26
  const arrayShift = (array) => array.shift();
27
27
 
@@ -315,10 +315,13 @@ const upsert = async (
315
315
  ),
316
316
  ) +
317
317
  ')VALUES' +
318
- strRepeat(
319
- `,(?${strRepeat(',?', arrayLength(changingColumnNames))})`,
320
- arrayLength(args) / (arrayLength(changingColumnNames) + 1),
321
- ).substring(1) +
318
+ slice(
319
+ strRepeat(
320
+ `,(?${strRepeat(',?', arrayLength(changingColumnNames))})`,
321
+ arrayLength(args) / (arrayLength(changingColumnNames) + 1),
322
+ ),
323
+ 1,
324
+ ) +
322
325
  'ON CONFLICT(' +
323
326
  escapeId(rowIdColumnName) +
324
327
  ')DO UPDATE SET' +
@@ -666,7 +669,7 @@ const getDefaultedTabularConfigMap = (
666
669
  ) => {
667
670
  const configMap = mapNew();
668
671
  objMap(configsObj, (configObj, id) => {
669
- const defaultedConfig = arraySlice(
672
+ const defaultedConfig = slice(
670
673
  objValues(
671
674
  objMerge(
672
675
  defaultObj,
@@ -695,7 +698,7 @@ const getConfigStructures = (configOrStoreTableName) => {
695
698
  ];
696
699
  }
697
700
  const {tables: {load = {}, save = {}} = {}, values = {}} = config;
698
- const valuesConfig = arraySlice(
701
+ const valuesConfig = slice(
699
702
  objValues(objMerge(DEFAULT_TABULAR_VALUES_CONFIG, values)),
700
703
  0,
701
704
  objSize(DEFAULT_TABULAR_VALUES_CONFIG),
@@ -14,6 +14,7 @@ const ifNotUndefined = (value, then, otherwise) =>
14
14
  isUndefined(value) ? otherwise?.() : then(value);
15
15
  const isString = (thing) => getTypeOf(thing) == STRING;
16
16
  const isArray = (thing) => Array.isArray(thing);
17
+ const slice = (arrayOrString, start, end) => arrayOrString.slice(start, end);
17
18
  const promiseAll = async (promises) => promise.all(promises);
18
19
 
19
20
  const arrayJoin = (array, sep = EMPTY_STRING) => array.join(sep);
@@ -21,7 +22,6 @@ const arrayMap = (array, cb) => array.map(cb);
21
22
  const arrayLength = (array) => array.length;
22
23
  const arrayIsEmpty = (array) => arrayLength(array) == 0;
23
24
  const arrayFilter = (array, cb) => array.filter(cb);
24
- const arraySlice = (array, start, end) => array.slice(start, end);
25
25
  const arrayPush = (array, ...values) => array.push(...values);
26
26
  const arrayShift = (array) => array.shift();
27
27
 
@@ -315,10 +315,13 @@ const upsert = async (
315
315
  ),
316
316
  ) +
317
317
  ')VALUES' +
318
- strRepeat(
319
- `,(?${strRepeat(',?', arrayLength(changingColumnNames))})`,
320
- arrayLength(args) / (arrayLength(changingColumnNames) + 1),
321
- ).substring(1) +
318
+ slice(
319
+ strRepeat(
320
+ `,(?${strRepeat(',?', arrayLength(changingColumnNames))})`,
321
+ arrayLength(args) / (arrayLength(changingColumnNames) + 1),
322
+ ),
323
+ 1,
324
+ ) +
322
325
  'ON CONFLICT(' +
323
326
  escapeId(rowIdColumnName) +
324
327
  ')DO UPDATE SET' +
@@ -666,7 +669,7 @@ const getDefaultedTabularConfigMap = (
666
669
  ) => {
667
670
  const configMap = mapNew();
668
671
  objMap(configsObj, (configObj, id) => {
669
- const defaultedConfig = arraySlice(
672
+ const defaultedConfig = slice(
670
673
  objValues(
671
674
  objMerge(
672
675
  defaultObj,
@@ -695,7 +698,7 @@ const getConfigStructures = (configOrStoreTableName) => {
695
698
  ];
696
699
  }
697
700
  const {tables: {load = {}, save = {}} = {}, values = {}} = config;
698
- const valuesConfig = arraySlice(
701
+ const valuesConfig = slice(
699
702
  objValues(objMerge(DEFAULT_TABULAR_VALUES_CONFIG, values)),
700
703
  0,
701
704
  objSize(DEFAULT_TABULAR_VALUES_CONFIG),
@@ -0,0 +1,249 @@
1
+ const getTypeOf = (thing) => typeof thing;
2
+ const EMPTY_STRING = '';
3
+ const STRING = getTypeOf(EMPTY_STRING);
4
+
5
+ const isInstanceOf = (thing, cls) => thing instanceof cls;
6
+ const isUndefined = (thing) => thing == void 0;
7
+ const ifNotUndefined = (value, then, otherwise) =>
8
+ isUndefined(value) ? otherwise?.() : then(value);
9
+ const isString = (thing) => getTypeOf(thing) == STRING;
10
+ const slice = (arrayOrString, start, end) => arrayOrString.slice(start, end);
11
+
12
+ const arrayLength = (array) => array.length;
13
+ const arrayPush = (array, ...values) => array.push(...values);
14
+ const arrayShift = (array) => array.shift();
15
+
16
+ const object = Object;
17
+ const objIds = object.keys;
18
+ const objFreeze = object.freeze;
19
+ const isObject = (obj) =>
20
+ isInstanceOf(obj, object) && obj.constructor == object;
21
+ const objSize = (obj) => arrayLength(objIds(obj));
22
+ const objIsEmpty = (obj) => isObject(obj) && objSize(obj) == 0;
23
+
24
+ const jsonString = (obj) =>
25
+ JSON.stringify(obj, (_key, value) =>
26
+ isInstanceOf(value, Map) ? object.fromEntries([...value]) : value,
27
+ );
28
+ const jsonParse = JSON.parse;
29
+
30
+ const SET_CHANGES = 's';
31
+ const STORE_PATH = '/store';
32
+ const PUT = 'PUT';
33
+ const constructMessage = (type, payload) =>
34
+ type + (isString(payload) ? payload : jsonString(payload));
35
+ const deconstructMessage = (message, stringified) => [
36
+ message[0],
37
+ stringified ? jsonParse(slice(message, 1)) : slice(message, 1),
38
+ ];
39
+
40
+ const collHas = (coll, keyOrValue) => coll?.has(keyOrValue) ?? false;
41
+ const collDel = (coll, keyOrValue) => coll?.delete(keyOrValue);
42
+
43
+ const mapNew = (entries) => new Map(entries);
44
+ const mapGet = (map, key) => map?.get(key);
45
+ const mapSet = (map, key, value) =>
46
+ isUndefined(value) ? (collDel(map, key), map) : map?.set(key, value);
47
+ const mapEnsure = (map, key, getDefaultValue) => {
48
+ if (!collHas(map, key)) {
49
+ mapSet(map, key, getDefaultValue());
50
+ }
51
+ return mapGet(map, key);
52
+ };
53
+
54
+ const scheduleRunning = mapNew();
55
+ const scheduleActions = mapNew();
56
+ const createCustomPersister = (
57
+ store,
58
+ getPersisted,
59
+ setPersisted,
60
+ addPersisterListener,
61
+ delPersisterListener,
62
+ onIgnoredError,
63
+ scheduleId = [],
64
+ ) => {
65
+ let listenerId;
66
+ let loadSave = 0;
67
+ let loads = 0;
68
+ let saves = 0;
69
+ let listening = 0;
70
+ let action;
71
+ let listeningHandle;
72
+ mapEnsure(scheduleRunning, scheduleId, () => 0);
73
+ mapEnsure(scheduleActions, scheduleId, () => []);
74
+ const run = async () => {
75
+ /* istanbul ignore else */
76
+ if (!mapGet(scheduleRunning, scheduleId)) {
77
+ mapSet(scheduleRunning, scheduleId, 1);
78
+ while (
79
+ !isUndefined((action = arrayShift(mapGet(scheduleActions, scheduleId))))
80
+ ) {
81
+ try {
82
+ await action();
83
+ } catch (error) {
84
+ /* istanbul ignore next */
85
+ onIgnoredError?.(error);
86
+ }
87
+ }
88
+ mapSet(scheduleRunning, scheduleId, 0);
89
+ }
90
+ };
91
+ const loadLock = async (actions) => {
92
+ /* istanbul ignore else */
93
+ if (loadSave != 2) {
94
+ loadSave = 1;
95
+ {
96
+ loads++;
97
+ }
98
+ await persister.schedule(async () => {
99
+ await actions();
100
+ loadSave = 0;
101
+ });
102
+ }
103
+ return persister;
104
+ };
105
+ const persister = {
106
+ load: async (initialTables, initialValues) =>
107
+ await loadLock(async () => {
108
+ try {
109
+ store.setContent(await getPersisted());
110
+ } catch {
111
+ store.setContent([initialTables, initialValues]);
112
+ }
113
+ }),
114
+ startAutoLoad: async (initialTables = {}, initialValues = {}) => {
115
+ persister.stopAutoLoad();
116
+ await persister.load(initialTables, initialValues);
117
+ listening = 1;
118
+ listeningHandle = addPersisterListener(
119
+ async (getContent, getTransactionChanges) => {
120
+ if (getTransactionChanges) {
121
+ const transactionChanges = getTransactionChanges();
122
+ await loadLock(async () =>
123
+ store.setTransactionChanges(transactionChanges),
124
+ );
125
+ } else {
126
+ await loadLock(async () => {
127
+ try {
128
+ store.setContent(getContent?.() ?? (await getPersisted()));
129
+ } catch (error) {
130
+ onIgnoredError?.(error);
131
+ }
132
+ });
133
+ }
134
+ },
135
+ );
136
+ return persister;
137
+ },
138
+ stopAutoLoad: () => {
139
+ if (listening) {
140
+ delPersisterListener(listeningHandle);
141
+ listeningHandle = void 0;
142
+ listening = 0;
143
+ }
144
+ return persister;
145
+ },
146
+ save: async (getTransactionChanges) => {
147
+ /* istanbul ignore else */
148
+ if (loadSave != 1) {
149
+ loadSave = 2;
150
+ {
151
+ saves++;
152
+ }
153
+ await persister.schedule(async () => {
154
+ try {
155
+ await setPersisted(store.getContent, getTransactionChanges);
156
+ } catch (error) {
157
+ /* istanbul ignore next */
158
+ onIgnoredError?.(error);
159
+ }
160
+ loadSave = 0;
161
+ });
162
+ }
163
+ return persister;
164
+ },
165
+ startAutoSave: async () => {
166
+ await persister.stopAutoSave().save();
167
+ listenerId = store.addDidFinishTransactionListener(
168
+ (_store, getTransactionChanges) => {
169
+ const [tableChanges, valueChanges] = getTransactionChanges();
170
+ if (!objIsEmpty(tableChanges) || !objIsEmpty(valueChanges)) {
171
+ persister.save(() => [tableChanges, valueChanges]);
172
+ }
173
+ },
174
+ );
175
+ return persister;
176
+ },
177
+ stopAutoSave: () => {
178
+ ifNotUndefined(listenerId, store.delListener);
179
+ return persister;
180
+ },
181
+ schedule: async (...actions) => {
182
+ arrayPush(mapGet(scheduleActions, scheduleId), ...actions);
183
+ await run();
184
+ return persister;
185
+ },
186
+ getStore: () => store,
187
+ destroy: () => persister.stopAutoLoad().stopAutoSave(),
188
+ getStats: () => ({loads, saves}),
189
+ };
190
+ return objFreeze(persister);
191
+ };
192
+
193
+ const MESSAGE = 'message';
194
+ const createPartyKitPersister = (
195
+ store,
196
+ connection,
197
+ storeUrlProtocol = 'https',
198
+ onIgnoredError,
199
+ ) => {
200
+ const {host, room} = connection.partySocketOptions;
201
+ const storeUrl =
202
+ storeUrlProtocol +
203
+ '://' +
204
+ host +
205
+ '/parties/' +
206
+ (connection.name ?? 'main') +
207
+ '/' +
208
+ room +
209
+ STORE_PATH;
210
+ const getOrSetStore = async (content) =>
211
+ await (
212
+ await fetch(storeUrl, {
213
+ ...(content ? {method: PUT, body: jsonString(content)} : {}),
214
+ mode: 'cors',
215
+ cache: 'no-store',
216
+ })
217
+ ).json();
218
+ const getPersisted = async () => await getOrSetStore();
219
+ const setPersisted = async (getContent, getTransactionChanges) => {
220
+ if (getTransactionChanges) {
221
+ connection.send(constructMessage(SET_CHANGES, getTransactionChanges()));
222
+ } else {
223
+ await getOrSetStore(getContent());
224
+ }
225
+ };
226
+ const addPersisterListener = (listener) => {
227
+ const messageListener = (event) => {
228
+ const [type, payload] = deconstructMessage(event.data, 1);
229
+ if (type == SET_CHANGES) {
230
+ listener(void 0, () => payload);
231
+ }
232
+ };
233
+ connection.addEventListener(MESSAGE, messageListener);
234
+ return messageListener;
235
+ };
236
+ const delPersisterListener = (messageListener) => {
237
+ connection.removeEventListener(MESSAGE, messageListener);
238
+ };
239
+ return createCustomPersister(
240
+ store,
241
+ getPersisted,
242
+ setPersisted,
243
+ addPersisterListener,
244
+ delPersisterListener,
245
+ onIgnoredError,
246
+ );
247
+ };
248
+
249
+ export {createPartyKitPersister};
@@ -0,0 +1,161 @@
1
+ const getTypeOf = (thing) => typeof thing;
2
+ const EMPTY_STRING = '';
3
+ const STRING = getTypeOf(EMPTY_STRING);
4
+ const T = 't';
5
+ const V = 'v';
6
+
7
+ const promise = Promise;
8
+ const isInstanceOf = (thing, cls) => thing instanceof cls;
9
+ const isUndefined = (thing) => thing == void 0;
10
+ const ifNotUndefined = (value, then, otherwise) =>
11
+ isUndefined(value) ? otherwise?.() : then(value);
12
+ const isString = (thing) => getTypeOf(thing) == STRING;
13
+ const slice = (arrayOrString, start, end) => arrayOrString.slice(start, end);
14
+ const promiseAll = async (promises) => promise.all(promises);
15
+
16
+ const arrayEvery = (array, cb) => array.every(cb);
17
+ const arrayMap = (array, cb) => array.map(cb);
18
+ const arrayLength = (array) => array.length;
19
+ const arrayIsEmpty = (array) => arrayLength(array) == 0;
20
+ const arrayPush = (array, ...values) => array.push(...values);
21
+ const arrayUnshift = (array, ...values) => array.unshift(...values);
22
+
23
+ const object = Object;
24
+ const objNew = (entries = []) => object.fromEntries(entries);
25
+ const objGet = (obj, id) => ifNotUndefined(obj, (obj2) => obj2[id]);
26
+ const objHas = (obj, id) => !isUndefined(objGet(obj, id));
27
+ const objMap = (obj, cb) =>
28
+ arrayMap(object.entries(obj), ([id, value]) => cb(value, id));
29
+ const objEnsure = (obj, id, getDefaultValue) => {
30
+ if (!objHas(obj, id)) {
31
+ obj[id] = getDefaultValue();
32
+ }
33
+ return obj[id];
34
+ };
35
+
36
+ const jsonString = (obj) =>
37
+ JSON.stringify(obj, (_key, value) =>
38
+ isInstanceOf(value, Map) ? object.fromEntries([...value]) : value,
39
+ );
40
+ const jsonParse = JSON.parse;
41
+
42
+ const SET_CHANGES = 's';
43
+ const STORE_PATH = '/store';
44
+ const PUT = 'PUT';
45
+ const constructMessage = (type, payload) =>
46
+ type + (isString(payload) ? payload : jsonString(payload));
47
+ const deconstructMessage = (message, stringified) => [
48
+ message[0],
49
+ stringified ? jsonParse(slice(message, 1)) : slice(message, 1),
50
+ ];
51
+
52
+ const collForEach = (coll, cb) => coll?.forEach(cb);
53
+
54
+ const mapForEach = (map, cb) =>
55
+ collForEach(map, (value, key) => cb(key, value));
56
+
57
+ const HAS_STORE = 'hasStore';
58
+ const CORS_HEADERS = objNew(
59
+ arrayMap(['Origin', 'Methods', 'Headers'], (suffix) => [
60
+ 'Access-Control-Allow-' + suffix,
61
+ '*',
62
+ ]),
63
+ );
64
+ const hasStoreInStorage = async (storage) => await storage.get(HAS_STORE);
65
+ const loadStoreFromStorage = async (storage) => {
66
+ const tables = {};
67
+ const values = {};
68
+ mapForEach(await storage.list(), (key, cellOrValue) => {
69
+ const [type, ids] = deconstructMessage(key);
70
+ if (type == T) {
71
+ const [tableId, rowId, cellId] = jsonParse('[' + ids + ']');
72
+ objEnsure(objEnsure(tables, tableId, objNew), rowId, objNew)[cellId] =
73
+ cellOrValue;
74
+ } else if (type == V) {
75
+ values[ids] = cellOrValue;
76
+ }
77
+ });
78
+ return [tables, values];
79
+ };
80
+ const saveStoreToStorage = async (storage, transactionChanges) => {
81
+ const promises = [storage.put(HAS_STORE, 1)];
82
+ const keyPrefixesToDelete = [];
83
+ objMap(transactionChanges[0], (table, tableId) =>
84
+ isUndefined(table)
85
+ ? arrayUnshift(keyPrefixesToDelete, getStoreStorageKey(T, tableId))
86
+ : objMap(table, (row, rowId) =>
87
+ isUndefined(row)
88
+ ? arrayPush(
89
+ keyPrefixesToDelete,
90
+ getStoreStorageKey(T, tableId, rowId),
91
+ )
92
+ : objMap(row, (cell, cellId) =>
93
+ promiseToSetOrDelStorage(
94
+ promises,
95
+ storage,
96
+ getStoreStorageKey(T, tableId, rowId, cellId),
97
+ cell,
98
+ ),
99
+ ),
100
+ ),
101
+ );
102
+ objMap(transactionChanges[1], (value, valueId) =>
103
+ promiseToSetOrDelStorage(promises, storage, V + valueId, value),
104
+ );
105
+ if (!arrayIsEmpty(keyPrefixesToDelete)) {
106
+ mapForEach(await storage.list(), (key) =>
107
+ arrayEvery(
108
+ keyPrefixesToDelete,
109
+ (keyPrefixToDelete) =>
110
+ !key.startsWith(keyPrefixToDelete) ||
111
+ (promiseToSetOrDelStorage(promises, storage, key) && false),
112
+ ),
113
+ );
114
+ }
115
+ await promiseAll(promises);
116
+ };
117
+ const getStoreStorageKey = (type, ...ids) =>
118
+ type + slice(jsonString(ids), 1, -1);
119
+ const promiseToSetOrDelStorage = (promises, storage, key, value) =>
120
+ arrayPush(
121
+ promises,
122
+ isUndefined(value) ? storage.delete(key) : storage.put(key, value),
123
+ );
124
+ const getResponse = (status, body = null) =>
125
+ new Response(body, {status, headers: CORS_HEADERS});
126
+ class TinyBasePartyKitServer {
127
+ constructor(party) {
128
+ this.party = party;
129
+ }
130
+ async onRequest(request) {
131
+ const storage = this.party.storage;
132
+ if (request.url.endsWith(STORE_PATH)) {
133
+ const hasStore = await hasStoreInStorage(storage);
134
+ const text = await request.text();
135
+ if (request.method == PUT) {
136
+ if (hasStore) {
137
+ return getResponse(205);
138
+ }
139
+ await saveStoreToStorage(this.party.storage, jsonParse(text));
140
+ return getResponse(201);
141
+ }
142
+ return getResponse(
143
+ 200,
144
+ hasStore
145
+ ? jsonString(await loadStoreFromStorage(storage))
146
+ : EMPTY_STRING,
147
+ );
148
+ }
149
+ return getResponse(404);
150
+ }
151
+ async onMessage(message, client) {
152
+ const storage = this.party.storage;
153
+ const [type, payload] = deconstructMessage(message, 1);
154
+ if (type == SET_CHANGES && (await hasStoreInStorage(storage))) {
155
+ await saveStoreToStorage(storage, payload);
156
+ this.party.broadcast(constructMessage(SET_CHANGES, payload), [client.id]);
157
+ }
158
+ }
159
+ }
160
+
161
+ export {TinyBasePartyKitServer};
@@ -14,6 +14,7 @@ const ifNotUndefined = (value, then, otherwise) =>
14
14
  isUndefined(value) ? otherwise?.() : then(value);
15
15
  const isString = (thing) => getTypeOf(thing) == STRING;
16
16
  const isArray = (thing) => Array.isArray(thing);
17
+ const slice = (arrayOrString, start, end) => arrayOrString.slice(start, end);
17
18
  const promiseAll = async (promises) => promise.all(promises);
18
19
 
19
20
  const arrayJoin = (array, sep = EMPTY_STRING) => array.join(sep);
@@ -21,7 +22,6 @@ const arrayMap = (array, cb) => array.map(cb);
21
22
  const arrayLength = (array) => array.length;
22
23
  const arrayIsEmpty = (array) => arrayLength(array) == 0;
23
24
  const arrayFilter = (array, cb) => array.filter(cb);
24
- const arraySlice = (array, start, end) => array.slice(start, end);
25
25
  const arrayPush = (array, ...values) => array.push(...values);
26
26
  const arrayShift = (array) => array.shift();
27
27
 
@@ -315,10 +315,13 @@ const upsert = async (
315
315
  ),
316
316
  ) +
317
317
  ')VALUES' +
318
- strRepeat(
319
- `,(?${strRepeat(',?', arrayLength(changingColumnNames))})`,
320
- arrayLength(args) / (arrayLength(changingColumnNames) + 1),
321
- ).substring(1) +
318
+ slice(
319
+ strRepeat(
320
+ `,(?${strRepeat(',?', arrayLength(changingColumnNames))})`,
321
+ arrayLength(args) / (arrayLength(changingColumnNames) + 1),
322
+ ),
323
+ 1,
324
+ ) +
322
325
  'ON CONFLICT(' +
323
326
  escapeId(rowIdColumnName) +
324
327
  ')DO UPDATE SET' +
@@ -666,7 +669,7 @@ const getDefaultedTabularConfigMap = (
666
669
  ) => {
667
670
  const configMap = mapNew();
668
671
  objMap(configsObj, (configObj, id) => {
669
- const defaultedConfig = arraySlice(
672
+ const defaultedConfig = slice(
670
673
  objValues(
671
674
  objMerge(
672
675
  defaultObj,
@@ -695,7 +698,7 @@ const getConfigStructures = (configOrStoreTableName) => {
695
698
  ];
696
699
  }
697
700
  const {tables: {load = {}, save = {}} = {}, values = {}} = config;
698
- const valuesConfig = arraySlice(
701
+ const valuesConfig = slice(
699
702
  objValues(objMerge(DEFAULT_TABULAR_VALUES_CONFIG, values)),
700
703
  0,
701
704
  objSize(DEFAULT_TABULAR_VALUES_CONFIG),
@@ -14,6 +14,7 @@ const ifNotUndefined = (value, then, otherwise) =>
14
14
  isUndefined(value) ? otherwise?.() : then(value);
15
15
  const isString = (thing) => getTypeOf(thing) == STRING;
16
16
  const isArray = (thing) => Array.isArray(thing);
17
+ const slice = (arrayOrString, start, end) => arrayOrString.slice(start, end);
17
18
  const promiseNew = (resolver) => new promise(resolver);
18
19
  const promiseAll = async (promises) => promise.all(promises);
19
20
 
@@ -22,7 +23,6 @@ const arrayMap = (array, cb) => array.map(cb);
22
23
  const arrayLength = (array) => array.length;
23
24
  const arrayIsEmpty = (array) => arrayLength(array) == 0;
24
25
  const arrayFilter = (array, cb) => array.filter(cb);
25
- const arraySlice = (array, start, end) => array.slice(start, end);
26
26
  const arrayPush = (array, ...values) => array.push(...values);
27
27
  const arrayShift = (array) => array.shift();
28
28
 
@@ -316,10 +316,13 @@ const upsert = async (
316
316
  ),
317
317
  ) +
318
318
  ')VALUES' +
319
- strRepeat(
320
- `,(?${strRepeat(',?', arrayLength(changingColumnNames))})`,
321
- arrayLength(args) / (arrayLength(changingColumnNames) + 1),
322
- ).substring(1) +
319
+ slice(
320
+ strRepeat(
321
+ `,(?${strRepeat(',?', arrayLength(changingColumnNames))})`,
322
+ arrayLength(args) / (arrayLength(changingColumnNames) + 1),
323
+ ),
324
+ 1,
325
+ ) +
323
326
  'ON CONFLICT(' +
324
327
  escapeId(rowIdColumnName) +
325
328
  ')DO UPDATE SET' +
@@ -667,7 +670,7 @@ const getDefaultedTabularConfigMap = (
667
670
  ) => {
668
671
  const configMap = mapNew();
669
672
  objMap(configsObj, (configObj, id) => {
670
- const defaultedConfig = arraySlice(
673
+ const defaultedConfig = slice(
671
674
  objValues(
672
675
  objMerge(
673
676
  defaultObj,
@@ -696,7 +699,7 @@ const getConfigStructures = (configOrStoreTableName) => {
696
699
  ];
697
700
  }
698
701
  const {tables: {load = {}, save = {}} = {}, values = {}} = config;
699
- const valuesConfig = arraySlice(
702
+ const valuesConfig = slice(
700
703
  objValues(objMerge(DEFAULT_TABULAR_VALUES_CONFIG, values)),
701
704
  0,
702
705
  objSize(DEFAULT_TABULAR_VALUES_CONFIG),
@@ -31,7 +31,6 @@ const arraySum = (array) => arrayReduce(array, (i, j) => i + j, 0);
31
31
  const arrayLength = (array) => array.length;
32
32
  const arrayIsEmpty = (array) => arrayLength(array) == 0;
33
33
  const arrayReduce = (array, cb, initial) => array.reduce(cb, initial);
34
- const arraySlice = (array, start, end) => array.slice(start, end);
35
34
  const arrayPush = (array, ...values) => array.push(...values);
36
35
 
37
36
  const mathMax = Math.max;
@@ -43,6 +42,7 @@ const ifNotUndefined = (value, then, otherwise) =>
43
42
  const isTypeStringOrBoolean = (type) => type == STRING || type == BOOLEAN;
44
43
  const isFunction = (thing) => getTypeOf(thing) == FUNCTION;
45
44
  const isArray = (thing) => Array.isArray(thing);
45
+ const slice = (arrayOrString, start, end) => arrayOrString.slice(start, end);
46
46
  const getUndefined = () => void 0;
47
47
 
48
48
  const object = Object;
@@ -794,7 +794,7 @@ const createQueries = getCreateFunction((store) => {
794
794
  );
795
795
  queries[ADD + RESULT + gettable + LISTENER] = (...args) =>
796
796
  resultStore[ADD + gettable + LISTENER](
797
- ...arraySlice(args, 0, argumentCount),
797
+ ...slice(args, 0, argumentCount),
798
798
  (_store, ...listenerArgs) =>
799
799
  args[argumentCount](queries, ...listenerArgs),
800
800
  );
@@ -30,6 +30,7 @@ const ifNotUndefined = (value, then, otherwise) =>
30
30
  const isTypeStringOrBoolean = (type) => type == STRING || type == BOOLEAN;
31
31
  const isFunction = (thing) => getTypeOf(thing) == FUNCTION;
32
32
  const isArray = (thing) => Array.isArray(thing);
33
+ const slice = (arrayOrString, start, end) => arrayOrString.slice(start, end);
33
34
  const test = (regex, subject) => regex.test(subject);
34
35
 
35
36
  const arrayHas = (array, value) => array.includes(value);
@@ -42,7 +43,6 @@ const arrayForEach = (array, cb) => array.forEach(cb);
42
43
  const arrayMap = (array, cb) => array.map(cb);
43
44
  const arrayLength = (array) => array.length;
44
45
  const arrayReduce = (array, cb, initial) => array.reduce(cb, initial);
45
- const arraySlice = (array, start, end) => array.slice(start, end);
46
46
  const arrayPush = (array, ...values) => array.push(...values);
47
47
  const arrayShift = (array) => array.shift();
48
48
 
@@ -935,7 +935,7 @@ const createStore = () => {
935
935
  const getRowIds = (tableId) => mapKeys(mapGet(tablesMap, id(tableId)));
936
936
  const getSortedRowIds = (tableId, cellId, descending, offset = 0, limit) =>
937
937
  arrayMap(
938
- arraySlice(
938
+ slice(
939
939
  arraySort(
940
940
  mapMap(mapGet(tablesMap, id(tableId)), (row, rowId) => [
941
941
  isUndefined(cellId) ? rowId : mapGet(row, id(cellId)),
@@ -1495,7 +1495,7 @@ const createStore = () => {
1495
1495
  addListener(
1496
1496
  args[argumentCount],
1497
1497
  idSetNode[args[argumentCount + 1] ? 1 : 0],
1498
- argumentCount > 0 ? arraySlice(args, 0, argumentCount) : void 0,
1498
+ argumentCount > 0 ? slice(args, 0, argumentCount) : void 0,
1499
1499
  pathGetters,
1500
1500
  extraArgsGetter,
1501
1501
  );