@chelone/core 0.6.0 → 0.7.0

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 (242) hide show
  1. package/dist/assistant/assistant-session.d.ts +6 -0
  2. package/dist/assistant/assistant-session.js +204 -181
  3. package/dist/assistant/echo-transport.js +26 -29
  4. package/dist/assistant/http-transport.d.ts +10 -0
  5. package/dist/assistant/http-transport.js +98 -0
  6. package/dist/assistant/types.d.ts +1 -7
  7. package/dist/auth/access-control.d.ts +13 -5
  8. package/dist/auth/access-control.js +25 -21
  9. package/dist/auth/auth-options.d.ts +21 -17
  10. package/dist/auth/auth-options.js +80 -48
  11. package/dist/auth/permission-matrix.d.ts +12 -0
  12. package/dist/auth/permission-matrix.js +67 -0
  13. package/dist/auth/types.d.ts +14 -4
  14. package/dist/block-editor/block-document.d.ts +60 -0
  15. package/dist/block-editor/block-document.js +143 -0
  16. package/dist/block-editor/data-blocks.d.ts +63 -0
  17. package/dist/block-editor/data-blocks.js +117 -0
  18. package/dist/chart/chart-data.js +46 -44
  19. package/dist/command-menu/hotkey.js +58 -47
  20. package/dist/command-menu/recents.js +8 -11
  21. package/dist/command-menu/registry.d.ts +9 -5
  22. package/dist/command-menu/registry.js +36 -46
  23. package/dist/controller/calendar-dates.js +82 -113
  24. package/dist/controller/calendar-events.js +93 -88
  25. package/dist/controller/client-list-controller.d.ts +2 -2
  26. package/dist/controller/client-list-controller.js +251 -254
  27. package/dist/controller/data-table-columns.d.ts +2 -0
  28. package/dist/controller/data-table-columns.js +50 -56
  29. package/dist/controller/deep-equal.d.ts +1 -0
  30. package/dist/controller/deep-equal.js +14 -0
  31. package/dist/controller/filter-toggle.js +36 -44
  32. package/dist/controller/in-place-editor.d.ts +42 -0
  33. package/dist/controller/in-place-editor.js +42 -0
  34. package/dist/controller/infinite-list-controller.js +219 -189
  35. package/dist/controller/inspector.d.ts +49 -0
  36. package/dist/controller/inspector.js +64 -0
  37. package/dist/controller/job-monitor.d.ts +3 -4
  38. package/dist/controller/job-monitor.js +37 -47
  39. package/dist/controller/kanban-board.d.ts +2 -3
  40. package/dist/controller/kanban-board.js +43 -24
  41. package/dist/controller/list-controller.d.ts +5 -5
  42. package/dist/controller/list-controller.js +444 -400
  43. package/dist/controller/list-params.js +96 -87
  44. package/dist/controller/pivot-grid.js +89 -95
  45. package/dist/controller/prev-next.d.ts +2 -2
  46. package/dist/controller/prev-next.js +74 -54
  47. package/dist/controller/record-controllers.d.ts +14 -6
  48. package/dist/controller/record-controllers.js +288 -257
  49. package/dist/controller/record-diff.d.ts +21 -0
  50. package/dist/controller/record-diff.js +50 -0
  51. package/dist/controller/record-timeline.js +42 -30
  52. package/dist/controller/record-tree.js +57 -47
  53. package/dist/controller/record-workflow.d.ts +38 -16
  54. package/dist/controller/record-workflow.js +85 -64
  55. package/dist/controller/reference-many-controller.js +198 -192
  56. package/dist/controller/reference-one-controller.d.ts +1 -1
  57. package/dist/controller/reference-one-controller.js +63 -56
  58. package/dist/controller/saved-queries.js +104 -91
  59. package/dist/controller/translate-fallback.js +10 -6
  60. package/dist/csv/export.d.ts +2 -1
  61. package/dist/csv/export.js +43 -40
  62. package/dist/csv/import-controller.js +185 -169
  63. package/dist/csv/match-headers.js +29 -22
  64. package/dist/csv/parse-with.js +60 -54
  65. package/dist/csv/run-import.js +69 -72
  66. package/dist/csv/validate-rows.d.ts +1 -1
  67. package/dist/csv/validate-rows.js +65 -52
  68. package/dist/data/cache-ops.d.ts +5 -4
  69. package/dist/data/cache-ops.js +208 -188
  70. package/dist/data/combine-data-providers.js +25 -23
  71. package/dist/data/data-provider-log.d.ts +45 -0
  72. package/dist/data/data-provider-log.js +93 -0
  73. package/dist/data/errors.js +14 -10
  74. package/dist/data/fake-provider.d.ts +6 -3
  75. package/dist/data/fake-provider.js +129 -114
  76. package/dist/data/fetch-utils.js +61 -44
  77. package/dist/data/filter-branch.d.ts +5 -0
  78. package/dist/data/filter-branch.js +10 -0
  79. package/dist/data/get-many-aggregate.js +84 -76
  80. package/dist/data/http-error.js +17 -12
  81. package/dist/data/keys.js +50 -36
  82. package/dist/data/mutation-options.d.ts +14 -9
  83. package/dist/data/mutation-options.js +93 -109
  84. package/dist/data/query-options.js +73 -68
  85. package/dist/data/remove-empty.d.ts +3 -0
  86. package/dist/data/remove-empty.js +11 -0
  87. package/dist/data/undoable.d.ts +2 -2
  88. package/dist/data/undoable.js +190 -174
  89. package/dist/data/with-lifecycle-callbacks.d.ts +45 -17
  90. package/dist/data/with-lifecycle-callbacks.js +66 -52
  91. package/dist/environment/application-update-store.js +58 -55
  92. package/dist/environment/offline-store.js +21 -21
  93. package/dist/form/array-binding.d.ts +30 -11
  94. package/dist/form/array-binding.js +184 -166
  95. package/dist/form/choice-ids.d.ts +7 -0
  96. package/dist/form/choice-ids.js +11 -0
  97. package/dist/form/choices-controller.d.ts +3 -2
  98. package/dist/form/choices-controller.js +302 -275
  99. package/dist/form/date-format.d.ts +38 -0
  100. package/dist/form/date-format.js +89 -0
  101. package/dist/form/dirty-values.d.ts +2 -2
  102. package/dist/form/dirty-values.js +22 -11
  103. package/dist/form/duration.d.ts +22 -0
  104. package/dist/form/duration.js +49 -0
  105. package/dist/form/edit-create-form.d.ts +12 -5
  106. package/dist/form/edit-create-form.js +243 -188
  107. package/dist/form/event-value.d.ts +6 -0
  108. package/dist/form/event-value.js +17 -0
  109. package/dist/form/field-error.d.ts +14 -0
  110. package/dist/form/field-error.js +28 -0
  111. package/dist/form/field-name.d.ts +20 -0
  112. package/dist/form/field-name.js +6 -0
  113. package/dist/form/filter-form-values.js +63 -49
  114. package/dist/form/form-controller.d.ts +9 -1
  115. package/dist/form/form-controller.js +165 -160
  116. package/dist/form/form-groups.d.ts +4 -3
  117. package/dist/form/form-groups.js +79 -79
  118. package/dist/form/form-handle.d.ts +175 -0
  119. package/dist/form/form-handle.js +68 -0
  120. package/dist/form/input-binding.d.ts +56 -31
  121. package/dist/form/input-binding.js +169 -118
  122. package/dist/form/input-values.d.ts +130 -0
  123. package/dist/form/input-values.js +177 -0
  124. package/dist/form/json-text.js +51 -37
  125. package/dist/form/save-pipeline.d.ts +6 -8
  126. package/dist/form/save-pipeline.js +91 -82
  127. package/dist/form/set-form-values.d.ts +6 -0
  128. package/dist/form/set-form-values.js +10 -0
  129. package/dist/form/source.js +97 -65
  130. package/dist/form/text-of.d.ts +2 -0
  131. package/dist/form/text-of.js +7 -0
  132. package/dist/form/validators.d.ts +58 -19
  133. package/dist/form/validators.js +97 -71
  134. package/dist/geo/bbox.d.ts +5 -4
  135. package/dist/geo/bbox.js +69 -48
  136. package/dist/geo/bounds.d.ts +14 -3
  137. package/dist/geo/bounds.js +98 -68
  138. package/dist/geo/constraints.js +88 -93
  139. package/dist/geo/coordinates.js +31 -23
  140. package/dist/geo/editor.d.ts +13 -13
  141. package/dist/geo/editor.js +176 -153
  142. package/dist/geo/geocoding.d.ts +4 -4
  143. package/dist/geo/geocoding.js +38 -41
  144. package/dist/geo/geojson.d.ts +12 -74
  145. package/dist/geo/geojson.js +52 -40
  146. package/dist/geo/geometry-math.d.ts +4 -4
  147. package/dist/geo/geometry-math.js +100 -93
  148. package/dist/geo/index.d.ts +7 -6
  149. package/dist/geo/map-layers.d.ts +42 -7
  150. package/dist/geo/map-layers.js +88 -62
  151. package/dist/geo/map-style.js +31 -32
  152. package/dist/geo/messages.js +48 -45
  153. package/dist/geo/nominatim.js +88 -80
  154. package/dist/geo/osm-presets.d.ts +4 -3
  155. package/dist/geo/osm-presets.js +108 -86
  156. package/dist/geo/osm-tags.js +14 -12
  157. package/dist/geo/overpass.d.ts +14 -2
  158. package/dist/geo/overpass.js +83 -90
  159. package/dist/geo/shape-value.d.ts +9 -5
  160. package/dist/geo/shape-value.js +169 -146
  161. package/dist/geo/snap-to-roads.d.ts +3 -3
  162. package/dist/geo/snap-to-roads.js +55 -50
  163. package/dist/geo/throttle.js +36 -39
  164. package/dist/guards.d.ts +37 -0
  165. package/dist/guards.js +62 -0
  166. package/dist/i18n/default-messages.js +34 -29
  167. package/dist/i18n/english-messages.js +187 -189
  168. package/dist/i18n/i18n.d.ts +2 -2
  169. package/dist/i18n/i18n.js +47 -60
  170. package/dist/i18n/inflection.d.ts +34 -0
  171. package/dist/i18n/inflection.js +82 -0
  172. package/dist/i18n/messages.d.ts +10 -2
  173. package/dist/i18n/messages.js +17 -4
  174. package/dist/i18n/missing-keys.js +66 -62
  175. package/dist/i18n/translatable.d.ts +16 -1
  176. package/dist/i18n/translatable.js +40 -47
  177. package/dist/index.d.ts +71 -24
  178. package/dist/index.js +40 -288
  179. package/dist/json/deep-equal.d.ts +8 -0
  180. package/dist/json/deep-equal.js +24 -0
  181. package/dist/json/strip-json-comments.js +38 -42
  182. package/dist/noop.d.ts +2 -0
  183. package/dist/noop.js +4 -0
  184. package/dist/notification/error-message.d.ts +2 -0
  185. package/dist/notification/error-message.js +10 -0
  186. package/dist/notification/notification-store.d.ts +3 -2
  187. package/dist/notification/notification-store.js +41 -45
  188. package/dist/onboarding-tour/placement.js +63 -78
  189. package/dist/onboarding-tour/tour-controller.js +46 -54
  190. package/dist/realtime/add-events-for-mutations.js +75 -81
  191. package/dist/realtime/announce-lock.js +16 -13
  192. package/dist/realtime/broadcast-channel-transport.js +65 -59
  193. package/dist/realtime/copy-members.js +22 -14
  194. package/dist/realtime/in-memory-lock-provider.js +40 -48
  195. package/dist/realtime/live.js +95 -101
  196. package/dist/realtime/lock-options.js +16 -16
  197. package/dist/realtime/lock-session.js +91 -78
  198. package/dist/realtime/memory-transport.js +25 -25
  199. package/dist/realtime/presence.js +120 -122
  200. package/dist/realtime/realtime-data-provider.d.ts +10 -0
  201. package/dist/realtime/realtime-data-provider.js +45 -42
  202. package/dist/realtime/reconnect-backoff.js +17 -0
  203. package/dist/realtime/sse-transport.d.ts +31 -0
  204. package/dist/realtime/sse-transport.js +235 -0
  205. package/dist/realtime/status-store.js +23 -28
  206. package/dist/realtime/topic-hub.js +62 -71
  207. package/dist/realtime/topics.js +10 -12
  208. package/dist/realtime/types.js +10 -12
  209. package/dist/realtime/unread-count.js +21 -21
  210. package/dist/realtime/websocket-transport.d.ts +32 -0
  211. package/dist/realtime/websocket-transport.js +306 -0
  212. package/dist/resource/describe-resource.d.ts +2 -0
  213. package/dist/resource/describe-resource.js +232 -219
  214. package/dist/resource/get-at-path.js +29 -14
  215. package/dist/resource/identifier.d.ts +18 -0
  216. package/dist/resource/identifier.js +27 -0
  217. package/dist/resource/record.d.ts +4 -0
  218. package/dist/resource/record.js +10 -0
  219. package/dist/resource/register.d.ts +7 -0
  220. package/dist/resource/registry-store.d.ts +45 -15
  221. package/dist/resource/registry-store.js +67 -60
  222. package/dist/resource/registry.d.ts +10 -0
  223. package/dist/resource/registry.js +8 -4
  224. package/dist/resource/source-path.d.ts +16 -1
  225. package/dist/rich-text/rich-text-extras.d.ts +132 -0
  226. package/dist/rich-text/rich-text-extras.js +179 -0
  227. package/dist/rich-text/rich-text-image.d.ts +124 -0
  228. package/dist/rich-text/rich-text-image.js +163 -0
  229. package/dist/rich-text/rich-text.d.ts +6 -0
  230. package/dist/rich-text/rich-text.js +125 -88
  231. package/dist/router/location.d.ts +22 -4
  232. package/dist/router/location.js +41 -18
  233. package/dist/router/match.js +47 -39
  234. package/dist/router/paths.js +40 -34
  235. package/dist/router/record-from-location.d.ts +1 -1
  236. package/dist/router/record-from-location.js +25 -17
  237. package/dist/store/adapters.js +51 -55
  238. package/dist/store/micro-store.js +57 -59
  239. package/dist/store/shallow-equal.d.ts +12 -0
  240. package/dist/store/shallow-equal.js +20 -0
  241. package/dist/store/store.js +54 -57
  242. package/package.json +13 -11
@@ -1,63 +1,69 @@
1
1
  import { createTopicHub } from "./topic-hub.js";
2
+ // src/realtime/broadcast-channel-transport.ts
2
3
  function isEnvelope(value) {
3
- if (typeof value !== "object" || value === null) return false;
4
- if (!("topic" in value) || typeof value.topic !== "string") return false;
5
- if (!("event" in value)) return false;
6
- const { event } = value;
7
- return typeof event === "object" && event !== null && "type" in event && typeof event.type === "string";
4
+ if (typeof value !== "object" || value === null) return false;
5
+ if (!("topic" in value) || typeof value.topic !== "string") return false;
6
+ if (!("event" in value)) return false;
7
+ const { event } = value;
8
+ return typeof event === "object" && event !== null && "type" in event && typeof event.type === "string";
8
9
  }
9
- function broadcastChannelTransport({
10
- channel,
11
- onError
12
- }) {
13
- if (typeof BroadcastChannel === "undefined") {
14
- throw new Error(
15
- "broadcastChannelTransport needs the global BroadcastChannel, which this environment does not have."
16
- );
17
- }
18
- const hub = createTopicHub({ onError });
19
- const broadcast = new BroadcastChannel(channel);
20
- let closed = false;
21
- const onMessage = (message) => {
22
- if (!isEnvelope(message.data)) {
23
- hub.report({
24
- kind: "parse_failed",
25
- cause: message.data,
26
- retrying: false
27
- });
28
- return;
29
- }
30
- const { topic, event } = message.data;
31
- hub.dispatch({ payload: void 0, ...event, topic });
32
- };
33
- broadcast.addEventListener("message", onMessage);
34
- return {
35
- subscribe: hub.subscribe,
36
- async publish(topic, event) {
37
- if (closed) {
38
- throw new Error("broadcastChannelTransport is closed");
39
- }
40
- try {
41
- broadcast.postMessage({ topic, event });
42
- } catch (cause) {
43
- hub.report({ kind: "send_failed", topic, cause, retrying: false });
44
- throw cause;
45
- }
46
- hub.dispatch({ ...event, topic });
47
- },
48
- onReconnect: hub.onReconnect,
49
- onStatusChange: hub.onStatusChange,
50
- onError: hub.onError,
51
- getStatus: hub.getStatus,
52
- close() {
53
- if (closed) return;
54
- closed = true;
55
- broadcast.removeEventListener("message", onMessage);
56
- broadcast.close();
57
- hub.setStatus("disconnected");
58
- }
59
- };
10
+ /** Carries realtime events between the tabs of one browser, with no server. */
11
+ function broadcastChannelTransport({ channel, onError }) {
12
+ if (typeof BroadcastChannel === "undefined") throw new Error("broadcastChannelTransport needs the global BroadcastChannel, which this environment does not have.");
13
+ const hub = createTopicHub({ onError });
14
+ const broadcast = new BroadcastChannel(channel);
15
+ let closed = false;
16
+ const onMessage = (message) => {
17
+ if (!isEnvelope(message.data)) {
18
+ hub.report({
19
+ kind: "parse_failed",
20
+ cause: message.data,
21
+ retrying: false
22
+ });
23
+ return;
24
+ }
25
+ const { topic, event } = message.data;
26
+ hub.dispatch({
27
+ payload: void 0,
28
+ ...event,
29
+ topic
30
+ });
31
+ };
32
+ broadcast.addEventListener("message", onMessage);
33
+ return {
34
+ subscribe: hub.subscribe,
35
+ async publish(topic, event) {
36
+ if (closed) throw new Error("broadcastChannelTransport is closed");
37
+ try {
38
+ broadcast.postMessage({
39
+ topic,
40
+ event
41
+ });
42
+ } catch (cause) {
43
+ hub.report({
44
+ kind: "send_failed",
45
+ topic,
46
+ cause,
47
+ retrying: false
48
+ });
49
+ throw cause;
50
+ }
51
+ hub.dispatch({
52
+ ...event,
53
+ topic
54
+ });
55
+ },
56
+ onReconnect: hub.onReconnect,
57
+ onStatusChange: hub.onStatusChange,
58
+ onError: hub.onError,
59
+ getStatus: hub.getStatus,
60
+ close() {
61
+ if (closed) return;
62
+ closed = true;
63
+ broadcast.removeEventListener("message", onMessage);
64
+ broadcast.close();
65
+ hub.setStatus("disconnected");
66
+ }
67
+ };
60
68
  }
61
- export {
62
- broadcastChannelTransport
63
- };
69
+ export { broadcastChannelTransport };
@@ -1,16 +1,24 @@
1
+ // src/realtime/copy-members.ts
2
+ /**
3
+ * A copy of `source` that keeps what a spread drops: methods on the prototype
4
+ * chain of a class instance, bound to `source` so they still see its state.
5
+ */
1
6
  function copyMembers(source) {
2
- const copy = { ...source };
3
- let proto = Object.getPrototypeOf(source);
4
- while (proto && proto !== Object.prototype) {
5
- for (const key of Reflect.ownKeys(proto)) {
6
- if (key === "constructor" || Object.hasOwn(copy, key)) continue;
7
- const { value } = Object.getOwnPropertyDescriptor(proto, key) ?? {};
8
- if (typeof value === "function") copy[key] = value.bind(source);
9
- }
10
- proto = Object.getPrototypeOf(proto);
11
- }
12
- return copy;
7
+ const copy = { ...source };
8
+ let proto = Object.getPrototypeOf(source);
9
+ while (proto && proto !== Object.prototype) {
10
+ for (const key of Reflect.ownKeys(proto)) {
11
+ if (key === "constructor" || Object.hasOwn(copy, key)) continue;
12
+ const { value } = Object.getOwnPropertyDescriptor(proto, key) ?? {};
13
+ if (typeof value === "function") Object.defineProperty(copy, key, {
14
+ value: value.bind(source),
15
+ writable: true,
16
+ enumerable: true,
17
+ configurable: true
18
+ });
19
+ }
20
+ proto = Object.getPrototypeOf(proto);
21
+ }
22
+ return copy;
13
23
  }
14
- export {
15
- copyMembers
16
- };
24
+ export { copyMembers };
@@ -1,51 +1,43 @@
1
1
  import { announceLock } from "./announce-lock.js";
2
2
  import { LockConflictError } from "./types.js";
3
- const storeKey = (resource, id) => JSON.stringify([resource, String(id)]);
4
- function inMemoryLockProvider({
5
- publisher
6
- } = {}) {
7
- const store = /* @__PURE__ */ new Map();
8
- return {
9
- async lock(resource, { id, identity }) {
10
- const key = storeKey(resource, id);
11
- const existing = store.get(key);
12
- if (existing) {
13
- if (String(existing.identity) !== String(identity)) {
14
- throw new LockConflictError(existing);
15
- }
16
- return existing;
17
- }
18
- const lock = {
19
- resource,
20
- recordId: id,
21
- identity,
22
- createdAt: (/* @__PURE__ */ new Date()).toISOString()
23
- };
24
- store.set(key, lock);
25
- await announceLock(publisher, "locked", lock);
26
- return lock;
27
- },
28
- async unlock(resource, { id, identity }) {
29
- const key = storeKey(resource, id);
30
- const existing = store.get(key);
31
- if (!existing) {
32
- throw new Error(`No lock on ${resource}/${String(id)} to release`);
33
- }
34
- if (String(existing.identity) !== String(identity)) {
35
- throw new LockConflictError(existing);
36
- }
37
- store.delete(key);
38
- await announceLock(publisher, "unlocked", existing);
39
- return existing;
40
- },
41
- async getLock(resource, { id }) {
42
- return store.get(storeKey(resource, id)) ?? null;
43
- },
44
- async getLocks(resource) {
45
- return [...store.values()].filter((lock) => lock.resource === resource);
46
- }
47
- };
3
+ // src/realtime/in-memory-lock-provider.ts
4
+ var storeKey = (resource, id) => JSON.stringify([resource, String(id)]);
5
+ /** A `LockProvider` kept in a `Map`, for tests and demos. */
6
+ function inMemoryLockProvider({ publisher } = {}) {
7
+ const store = /* @__PURE__ */ new Map();
8
+ return {
9
+ async lock(resource, { id, identity }) {
10
+ const key = storeKey(resource, id);
11
+ const existing = store.get(key);
12
+ if (existing) {
13
+ if (String(existing.identity) !== String(identity)) throw new LockConflictError(existing);
14
+ return existing;
15
+ }
16
+ const lock = {
17
+ resource,
18
+ recordId: id,
19
+ identity,
20
+ createdAt: (/* @__PURE__ */ new Date()).toISOString()
21
+ };
22
+ store.set(key, lock);
23
+ await announceLock(publisher, "locked", lock);
24
+ return lock;
25
+ },
26
+ async unlock(resource, { id, identity }) {
27
+ const key = storeKey(resource, id);
28
+ const existing = store.get(key);
29
+ if (!existing) throw new Error(`No lock on ${resource}/${String(id)} to release`);
30
+ if (String(existing.identity) !== String(identity)) throw new LockConflictError(existing);
31
+ store.delete(key);
32
+ await announceLock(publisher, "unlocked", existing);
33
+ return existing;
34
+ },
35
+ async getLock(resource, { id }) {
36
+ return store.get(storeKey(resource, id)) ?? null;
37
+ },
38
+ async getLocks(resource) {
39
+ return [...store.values()].filter((lock) => lock.resource === resource);
40
+ }
41
+ };
48
42
  }
49
- export {
50
- inMemoryLockProvider
51
- };
43
+ export { inMemoryLockProvider };
@@ -1,118 +1,112 @@
1
1
  import { lockKey, locksKey, resourceKey } from "../data/keys.js";
2
2
  import { hasUnsettledUndoables, onUndoablesSettled } from "../data/undoable.js";
3
3
  import { assertRealtimeDataProvider } from "./realtime-data-provider.js";
4
- import { recordTopic, resourceTopic, lockTopic, lockResourceTopic } from "./topics.js";
4
+ import { lockResourceTopic, lockTopic, recordTopic, resourceTopic } from "./topics.js";
5
+ // src/realtime/live.ts
5
6
  function subscribeLive(ctx, spec) {
6
- const { dataProvider } = ctx;
7
- assertRealtimeDataProvider(dataProvider, spec.caller);
8
- let stopped = false;
9
- let scheduled = false;
10
- let missed = false;
11
- const schedule = () => {
12
- if (scheduled) return;
13
- scheduled = true;
14
- queueMicrotask(() => {
15
- scheduled = false;
16
- if (!stopped) spec.invalidate();
17
- });
18
- };
19
- let stopWaiting;
20
- const holdForUndoable = () => {
21
- if (stopWaiting) return;
22
- stopWaiting = onUndoablesSettled(() => {
23
- stopWaiting?.();
24
- stopWaiting = void 0;
25
- onEvent();
26
- });
27
- };
28
- const onEvent = () => {
29
- if (stopped) return;
30
- if (spec.holdWhileUndoable && hasUnsettledUndoables()) {
31
- holdForUndoable();
32
- return;
33
- }
34
- if (spec.options?.paused?.()) {
35
- missed = true;
36
- return;
37
- }
38
- schedule();
39
- };
40
- const unsubscribes = spec.topics.map(
41
- (topic) => dataProvider.subscribe(topic, onEvent)
42
- );
43
- if (spec.topics.length > 0 && dataProvider.onReconnect) {
44
- unsubscribes.push(dataProvider.onReconnect(onEvent));
45
- }
46
- return {
47
- stop() {
48
- stopped = true;
49
- stopWaiting?.();
50
- stopWaiting = void 0;
51
- for (const unsubscribe of unsubscribes.splice(0)) unsubscribe();
52
- },
53
- resume() {
54
- if (stopped || !missed) return;
55
- missed = false;
56
- onEvent();
57
- }
58
- };
7
+ const { dataProvider } = ctx;
8
+ assertRealtimeDataProvider(dataProvider, spec.caller);
9
+ let stopped = false;
10
+ let scheduled = false;
11
+ let missed = false;
12
+ const schedule = () => {
13
+ if (scheduled) return;
14
+ scheduled = true;
15
+ queueMicrotask(() => {
16
+ scheduled = false;
17
+ if (!stopped) spec.invalidate();
18
+ });
19
+ };
20
+ let stopWaiting;
21
+ const holdForUndoable = () => {
22
+ if (stopWaiting) return;
23
+ stopWaiting = onUndoablesSettled(() => {
24
+ stopWaiting?.();
25
+ stopWaiting = void 0;
26
+ onEvent();
27
+ });
28
+ };
29
+ const onEvent = () => {
30
+ if (stopped) return;
31
+ if (spec.holdWhileUndoable && hasUnsettledUndoables()) {
32
+ holdForUndoable();
33
+ return;
34
+ }
35
+ if (spec.options?.paused?.()) {
36
+ missed = true;
37
+ return;
38
+ }
39
+ schedule();
40
+ };
41
+ const unsubscribes = spec.topics.map((topic) => dataProvider.subscribe(topic, onEvent));
42
+ if (spec.topics.length > 0 && dataProvider.onReconnect) unsubscribes.push(dataProvider.onReconnect(onEvent));
43
+ return {
44
+ stop() {
45
+ stopped = true;
46
+ stopWaiting?.();
47
+ stopWaiting = void 0;
48
+ for (const unsubscribe of unsubscribes.splice(0)) unsubscribe();
49
+ },
50
+ resume() {
51
+ if (stopped || !missed) return;
52
+ missed = false;
53
+ onEvent();
54
+ }
55
+ };
59
56
  }
57
+ /** Invalidates everything under the resource except lock queries, which have their own subscribers. */
60
58
  function invalidateResource(ctx, resource) {
61
- void ctx.queryClient.invalidateQueries({
62
- queryKey: resourceKey(resource),
63
- predicate: ({ queryKey }) => queryKey[1] !== "getLock" && queryKey[1] !== "getLocks"
64
- });
59
+ ctx.queryClient.invalidateQueries({
60
+ queryKey: resourceKey(resource),
61
+ predicate: ({ queryKey }) => queryKey[1] !== "getLock" && queryKey[1] !== "getLocks"
62
+ });
65
63
  }
64
+ /** Refetches the resource's lists, shows and edits when anything in it changes or the connection comes back. */
66
65
  function subscribeLiveResource(ctx, resource, options) {
67
- return subscribeLive(ctx, {
68
- caller: "subscribeLiveResource",
69
- topics: [resourceTopic(resource)],
70
- invalidate: () => invalidateResource(ctx, resource),
71
- options,
72
- holdWhileUndoable: true
73
- });
66
+ return subscribeLive(ctx, {
67
+ caller: "subscribeLiveResource",
68
+ topics: [resourceTopic(resource)],
69
+ invalidate: () => invalidateResource(ctx, resource),
70
+ options,
71
+ holdWhileUndoable: true
72
+ });
74
73
  }
74
+ /** Like `subscribeLiveResource`, for the events of one record. */
75
75
  function subscribeLiveRecord(ctx, resource, id, options) {
76
- return subscribeLive(ctx, {
77
- caller: "subscribeLiveRecord",
78
- topics: [recordTopic(resource, id)],
79
- invalidate: () => invalidateResource(ctx, resource),
80
- options,
81
- holdWhileUndoable: true
82
- });
76
+ return subscribeLive(ctx, {
77
+ caller: "subscribeLiveRecord",
78
+ topics: [recordTopic(resource, id)],
79
+ invalidate: () => invalidateResource(ctx, resource),
80
+ options,
81
+ holdWhileUndoable: true
82
+ });
83
83
  }
84
+ /** Like `subscribeLiveRecord`, for several records: one invalidation however many of them change. */
84
85
  function subscribeLiveRecords(ctx, resource, ids, options) {
85
- return subscribeLive(ctx, {
86
- caller: "subscribeLiveRecords",
87
- // `1` and `"1"` give the same topic; listen once.
88
- topics: [...new Set(ids.map((id) => recordTopic(resource, id)))],
89
- invalidate: () => invalidateResource(ctx, resource),
90
- options,
91
- holdWhileUndoable: true
92
- });
86
+ return subscribeLive(ctx, {
87
+ caller: "subscribeLiveRecords",
88
+ topics: [...new Set(ids.map((id) => recordTopic(resource, id)))],
89
+ invalidate: () => invalidateResource(ctx, resource),
90
+ options,
91
+ holdWhileUndoable: true
92
+ });
93
93
  }
94
+ /** Refetches one record's lock when it is taken or released. */
94
95
  function subscribeLiveLock(ctx, resource, id) {
95
- return subscribeLive(ctx, {
96
- caller: "subscribeLiveLock",
97
- topics: [lockTopic(resource, id)],
98
- invalidate: () => void ctx.queryClient.invalidateQueries({
99
- queryKey: lockKey(resource, { id })
100
- }),
101
- holdWhileUndoable: false
102
- });
96
+ return subscribeLive(ctx, {
97
+ caller: "subscribeLiveLock",
98
+ topics: [lockTopic(resource, id)],
99
+ invalidate: () => void ctx.queryClient.invalidateQueries({ queryKey: lockKey(resource, { id }) }),
100
+ holdWhileUndoable: false
101
+ });
103
102
  }
103
+ /** Refetches the resource's lock list when any lock is taken or released. */
104
104
  function subscribeLiveLocks(ctx, resource) {
105
- return subscribeLive(ctx, {
106
- caller: "subscribeLiveLocks",
107
- topics: [lockResourceTopic(resource)],
108
- invalidate: () => void ctx.queryClient.invalidateQueries({ queryKey: locksKey(resource) }),
109
- holdWhileUndoable: false
110
- });
105
+ return subscribeLive(ctx, {
106
+ caller: "subscribeLiveLocks",
107
+ topics: [lockResourceTopic(resource)],
108
+ invalidate: () => void ctx.queryClient.invalidateQueries({ queryKey: locksKey(resource) }),
109
+ holdWhileUndoable: false
110
+ });
111
111
  }
112
- export {
113
- subscribeLiveLock,
114
- subscribeLiveLocks,
115
- subscribeLiveRecord,
116
- subscribeLiveRecords,
117
- subscribeLiveResource
118
- };
112
+ export { subscribeLiveLock, subscribeLiveLocks, subscribeLiveRecord, subscribeLiveRecords, subscribeLiveResource };
@@ -1,22 +1,22 @@
1
1
  import { lockKey, locksKey } from "../data/keys.js";
2
2
  import { assertRealtimeDataProvider } from "./realtime-data-provider.js";
3
+ // src/realtime/lock-options.ts
4
+ /** One record's lock, cached under `lockKey`. Resolves to `null` when unlocked. */
3
5
  function getLockOptions(ctx, resource, params) {
4
- const { dataProvider } = ctx;
5
- assertRealtimeDataProvider(dataProvider, "getLockOptions");
6
- return {
7
- queryKey: lockKey(resource, params),
8
- queryFn: () => dataProvider.getLock(resource, params)
9
- };
6
+ const { dataProvider } = ctx;
7
+ assertRealtimeDataProvider(dataProvider, "getLockOptions");
8
+ return {
9
+ queryKey: lockKey(resource, params),
10
+ queryFn: () => dataProvider.getLock(resource, params)
11
+ };
10
12
  }
13
+ /** Every lock held on a resource, cached under `locksKey`. */
11
14
  function getLocksOptions(ctx, resource) {
12
- const { dataProvider } = ctx;
13
- assertRealtimeDataProvider(dataProvider, "getLocksOptions");
14
- return {
15
- queryKey: locksKey(resource),
16
- queryFn: () => dataProvider.getLocks(resource)
17
- };
15
+ const { dataProvider } = ctx;
16
+ assertRealtimeDataProvider(dataProvider, "getLocksOptions");
17
+ return {
18
+ queryKey: locksKey(resource),
19
+ queryFn: () => dataProvider.getLocks(resource)
20
+ };
18
21
  }
19
- export {
20
- getLockOptions,
21
- getLocksOptions
22
- };
22
+ export { getLockOptions, getLocksOptions };