@chelone/core 0.6.0 → 0.9.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 (255) 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 +23 -17
  10. package/dist/auth/auth-options.js +82 -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 +64 -0
  15. package/dist/block-editor/block-document.js +147 -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.d.ts +4 -0
  21. package/dist/command-menu/recents.js +12 -11
  22. package/dist/command-menu/registry.d.ts +9 -5
  23. package/dist/command-menu/registry.js +36 -46
  24. package/dist/controller/calendar-dates.d.ts +12 -0
  25. package/dist/controller/calendar-dates.js +94 -113
  26. package/dist/controller/calendar-events.js +93 -88
  27. package/dist/controller/client-list-controller.d.ts +2 -2
  28. package/dist/controller/client-list-controller.js +251 -254
  29. package/dist/controller/data-table-columns.d.ts +2 -0
  30. package/dist/controller/data-table-columns.js +50 -56
  31. package/dist/controller/deep-equal.d.ts +1 -0
  32. package/dist/controller/deep-equal.js +14 -0
  33. package/dist/controller/filter-toggle.js +36 -44
  34. package/dist/controller/in-place-editor.d.ts +43 -0
  35. package/dist/controller/in-place-editor.js +43 -0
  36. package/dist/controller/infinite-list-controller.js +219 -189
  37. package/dist/controller/inspector.d.ts +55 -0
  38. package/dist/controller/inspector.js +70 -0
  39. package/dist/controller/job-monitor.d.ts +10 -4
  40. package/dist/controller/job-monitor.js +46 -47
  41. package/dist/controller/kanban-board.js +45 -24
  42. package/dist/controller/list-controller.d.ts +8 -5
  43. package/dist/controller/list-controller.js +447 -400
  44. package/dist/controller/list-params.js +96 -87
  45. package/dist/controller/pivot-grid.d.ts +4 -4
  46. package/dist/controller/pivot-grid.js +89 -95
  47. package/dist/controller/prev-next.d.ts +2 -2
  48. package/dist/controller/prev-next.js +74 -54
  49. package/dist/controller/record-controllers.d.ts +14 -6
  50. package/dist/controller/record-controllers.js +288 -257
  51. package/dist/controller/record-diff.d.ts +21 -0
  52. package/dist/controller/record-diff.js +50 -0
  53. package/dist/controller/record-timeline.d.ts +5 -5
  54. package/dist/controller/record-timeline.js +42 -30
  55. package/dist/controller/record-tree.js +57 -47
  56. package/dist/controller/record-workflow.d.ts +38 -16
  57. package/dist/controller/record-workflow.js +85 -64
  58. package/dist/controller/reference-many-controller.d.ts +2 -0
  59. package/dist/controller/reference-many-controller.js +199 -192
  60. package/dist/controller/reference-one-controller.d.ts +1 -1
  61. package/dist/controller/reference-one-controller.js +63 -56
  62. package/dist/controller/saved-queries.js +104 -91
  63. package/dist/controller/translate-fallback.js +10 -6
  64. package/dist/csv/export.d.ts +4 -3
  65. package/dist/csv/export.js +43 -40
  66. package/dist/csv/import-controller.d.ts +4 -0
  67. package/dist/csv/import-controller.js +189 -169
  68. package/dist/csv/match-headers.js +29 -22
  69. package/dist/csv/parse-with.js +60 -54
  70. package/dist/csv/run-import.js +69 -72
  71. package/dist/csv/validate-rows.d.ts +1 -1
  72. package/dist/csv/validate-rows.js +65 -52
  73. package/dist/data/cache-ops.d.ts +5 -4
  74. package/dist/data/cache-ops.js +208 -188
  75. package/dist/data/combine-data-providers.js +25 -23
  76. package/dist/data/data-provider-log.d.ts +45 -0
  77. package/dist/data/data-provider-log.js +93 -0
  78. package/dist/data/errors.js +14 -10
  79. package/dist/data/fake-provider.d.ts +6 -3
  80. package/dist/data/fake-provider.js +135 -114
  81. package/dist/data/fetch-utils.js +61 -44
  82. package/dist/data/filter-branch.d.ts +5 -0
  83. package/dist/data/filter-branch.js +10 -0
  84. package/dist/data/get-many-aggregate.js +84 -76
  85. package/dist/data/http-error.js +17 -12
  86. package/dist/data/keys.js +50 -36
  87. package/dist/data/mutation-options.d.ts +14 -9
  88. package/dist/data/mutation-options.js +93 -109
  89. package/dist/data/query-options.js +73 -68
  90. package/dist/data/remove-empty.d.ts +3 -0
  91. package/dist/data/remove-empty.js +11 -0
  92. package/dist/data/undoable.d.ts +2 -2
  93. package/dist/data/undoable.js +190 -174
  94. package/dist/data/with-lifecycle-callbacks.d.ts +45 -17
  95. package/dist/data/with-lifecycle-callbacks.js +66 -52
  96. package/dist/environment/application-update-store.js +58 -55
  97. package/dist/environment/offline-store.js +21 -21
  98. package/dist/form/array-binding.d.ts +30 -11
  99. package/dist/form/array-binding.js +184 -166
  100. package/dist/form/choice-ids.d.ts +7 -0
  101. package/dist/form/choice-ids.js +11 -0
  102. package/dist/form/choices-controller.d.ts +22 -2
  103. package/dist/form/choices-controller.js +315 -275
  104. package/dist/form/date-format.d.ts +38 -0
  105. package/dist/form/date-format.js +89 -0
  106. package/dist/form/dirty-values.d.ts +2 -2
  107. package/dist/form/dirty-values.js +22 -11
  108. package/dist/form/duration.d.ts +22 -0
  109. package/dist/form/duration.js +49 -0
  110. package/dist/form/edit-create-form.d.ts +12 -5
  111. package/dist/form/edit-create-form.js +243 -188
  112. package/dist/form/event-value.d.ts +6 -0
  113. package/dist/form/event-value.js +17 -0
  114. package/dist/form/field-error.d.ts +14 -0
  115. package/dist/form/field-error.js +28 -0
  116. package/dist/form/field-name.d.ts +20 -0
  117. package/dist/form/field-name.js +6 -0
  118. package/dist/form/filter-form-values.js +63 -49
  119. package/dist/form/form-controller.d.ts +9 -1
  120. package/dist/form/form-controller.js +165 -160
  121. package/dist/form/form-groups.d.ts +4 -3
  122. package/dist/form/form-groups.js +79 -79
  123. package/dist/form/form-handle.d.ts +175 -0
  124. package/dist/form/form-handle.js +68 -0
  125. package/dist/form/input-binding.d.ts +56 -31
  126. package/dist/form/input-binding.js +171 -118
  127. package/dist/form/input-values.d.ts +140 -0
  128. package/dist/form/input-values.js +206 -0
  129. package/dist/form/json-text.d.ts +11 -0
  130. package/dist/form/json-text.js +62 -37
  131. package/dist/form/save-pipeline.d.ts +6 -8
  132. package/dist/form/save-pipeline.js +91 -82
  133. package/dist/form/set-form-values.d.ts +6 -0
  134. package/dist/form/set-form-values.js +10 -0
  135. package/dist/form/source.js +97 -65
  136. package/dist/form/text-of.d.ts +2 -0
  137. package/dist/form/text-of.js +7 -0
  138. package/dist/form/validators.d.ts +58 -19
  139. package/dist/form/validators.js +97 -71
  140. package/dist/geo/bbox.d.ts +5 -4
  141. package/dist/geo/bbox.js +69 -48
  142. package/dist/geo/bounds.d.ts +14 -3
  143. package/dist/geo/bounds.js +98 -68
  144. package/dist/geo/constraints.js +88 -93
  145. package/dist/geo/coordinates.d.ts +10 -0
  146. package/dist/geo/coordinates.js +44 -23
  147. package/dist/geo/editor.d.ts +13 -13
  148. package/dist/geo/editor.js +176 -153
  149. package/dist/geo/geocoding.d.ts +4 -4
  150. package/dist/geo/geocoding.js +38 -41
  151. package/dist/geo/geojson.d.ts +12 -74
  152. package/dist/geo/geojson.js +52 -40
  153. package/dist/geo/geometry-math.d.ts +4 -4
  154. package/dist/geo/geometry-math.js +100 -93
  155. package/dist/geo/index.d.ts +9 -8
  156. package/dist/geo/map-layers.d.ts +42 -7
  157. package/dist/geo/map-layers.js +88 -62
  158. package/dist/geo/map-style.d.ts +12 -0
  159. package/dist/geo/map-style.js +43 -32
  160. package/dist/geo/messages.js +48 -45
  161. package/dist/geo/nominatim.js +88 -80
  162. package/dist/geo/osm-presets.d.ts +4 -3
  163. package/dist/geo/osm-presets.js +108 -86
  164. package/dist/geo/osm-tags.js +14 -12
  165. package/dist/geo/overpass.d.ts +14 -2
  166. package/dist/geo/overpass.js +83 -90
  167. package/dist/geo/shape-value.d.ts +9 -5
  168. package/dist/geo/shape-value.js +169 -146
  169. package/dist/geo/snap-to-roads.d.ts +3 -3
  170. package/dist/geo/snap-to-roads.js +55 -50
  171. package/dist/geo/throttle.js +36 -39
  172. package/dist/guards.d.ts +44 -0
  173. package/dist/guards.js +77 -0
  174. package/dist/i18n/default-messages.js +34 -29
  175. package/dist/i18n/english-messages.d.ts +172 -0
  176. package/dist/i18n/english-messages.js +359 -189
  177. package/dist/i18n/i18n.d.ts +2 -2
  178. package/dist/i18n/i18n.js +47 -60
  179. package/dist/i18n/inflection.d.ts +34 -0
  180. package/dist/i18n/inflection.js +82 -0
  181. package/dist/i18n/messages.d.ts +10 -2
  182. package/dist/i18n/messages.js +17 -4
  183. package/dist/i18n/missing-keys.d.ts +4 -0
  184. package/dist/i18n/missing-keys.js +70 -62
  185. package/dist/i18n/translatable.d.ts +16 -1
  186. package/dist/i18n/translatable.js +40 -47
  187. package/dist/index.d.ts +87 -39
  188. package/dist/index.js +54 -301
  189. package/dist/json/deep-equal.d.ts +8 -0
  190. package/dist/json/deep-equal.js +24 -0
  191. package/dist/json/strip-json-comments.js +38 -42
  192. package/dist/noop.d.ts +2 -0
  193. package/dist/noop.js +4 -0
  194. package/dist/notification/error-message.d.ts +2 -0
  195. package/dist/notification/error-message.js +10 -0
  196. package/dist/notification/notification-store.d.ts +3 -2
  197. package/dist/notification/notification-store.js +41 -45
  198. package/dist/onboarding-tour/placement.d.ts +2 -0
  199. package/dist/onboarding-tour/placement.js +65 -78
  200. package/dist/onboarding-tour/tour-controller.js +46 -54
  201. package/dist/realtime/add-events-for-mutations.js +75 -81
  202. package/dist/realtime/announce-lock.js +16 -13
  203. package/dist/realtime/broadcast-channel-transport.js +65 -59
  204. package/dist/realtime/copy-members.js +22 -14
  205. package/dist/realtime/in-memory-lock-provider.js +40 -48
  206. package/dist/realtime/live.js +95 -101
  207. package/dist/realtime/lock-options.js +16 -16
  208. package/dist/realtime/lock-session.js +91 -78
  209. package/dist/realtime/memory-transport.js +25 -25
  210. package/dist/realtime/presence.js +120 -122
  211. package/dist/realtime/realtime-data-provider.d.ts +10 -0
  212. package/dist/realtime/realtime-data-provider.js +45 -42
  213. package/dist/realtime/reconnect-backoff.js +17 -0
  214. package/dist/realtime/sse-transport.d.ts +31 -0
  215. package/dist/realtime/sse-transport.js +235 -0
  216. package/dist/realtime/status-store.js +23 -28
  217. package/dist/realtime/topic-hub.js +62 -71
  218. package/dist/realtime/topics.js +10 -12
  219. package/dist/realtime/types.js +10 -12
  220. package/dist/realtime/unread-count.js +21 -21
  221. package/dist/realtime/websocket-transport.d.ts +32 -0
  222. package/dist/realtime/websocket-transport.js +306 -0
  223. package/dist/resource/describe-resource.d.ts +2 -0
  224. package/dist/resource/describe-resource.js +247 -219
  225. package/dist/resource/get-at-path.js +29 -14
  226. package/dist/resource/identifier.d.ts +18 -0
  227. package/dist/resource/identifier.js +27 -0
  228. package/dist/resource/record.d.ts +4 -0
  229. package/dist/resource/record.js +10 -0
  230. package/dist/resource/register.d.ts +7 -0
  231. package/dist/resource/registry-store.d.ts +45 -15
  232. package/dist/resource/registry-store.js +67 -60
  233. package/dist/resource/registry.d.ts +10 -0
  234. package/dist/resource/registry.js +8 -4
  235. package/dist/resource/source-path.d.ts +23 -2
  236. package/dist/rich-text/rich-text-extras.d.ts +134 -0
  237. package/dist/rich-text/rich-text-extras.js +181 -0
  238. package/dist/rich-text/rich-text-image.d.ts +124 -0
  239. package/dist/rich-text/rich-text-image.js +163 -0
  240. package/dist/rich-text/rich-text.d.ts +6 -0
  241. package/dist/rich-text/rich-text.js +125 -88
  242. package/dist/router/location.d.ts +24 -4
  243. package/dist/router/location.js +43 -18
  244. package/dist/router/match.js +47 -39
  245. package/dist/router/paths.js +40 -34
  246. package/dist/router/record-from-location.d.ts +1 -1
  247. package/dist/router/record-from-location.js +25 -17
  248. package/dist/store/adapters.js +51 -55
  249. package/dist/store/micro-store.js +57 -59
  250. package/dist/store/shallow-equal.d.ts +12 -0
  251. package/dist/store/shallow-equal.js +20 -0
  252. package/dist/store/store.js +54 -57
  253. package/dist/ui-defaults.d.ts +15 -0
  254. package/dist/ui-defaults.js +17 -0
  255. package/package.json +13 -11
@@ -1,47 +1,43 @@
1
+ // src/notification/notification-store.ts
1
2
  function createNotificationStore() {
2
- let notifications = [];
3
- let nextId = 1;
4
- const subscribers = /* @__PURE__ */ new Set();
5
- const emit = () => {
6
- for (const cb of subscribers) cb();
7
- };
8
- return {
9
- notify(message, options = {}) {
10
- const id = nextId++;
11
- notifications = [
12
- ...notifications,
13
- {
14
- id,
15
- message,
16
- type: options.type ?? "info",
17
- messageArgs: options.messageArgs,
18
- undoable: options.undoable,
19
- autoHideDuration: options.autoHideDuration,
20
- undo: options.undo,
21
- onClose: options.onClose
22
- }
23
- ];
24
- emit();
25
- return id;
26
- },
27
- dismiss(id) {
28
- const next = notifications.filter((n) => n.id !== id);
29
- if (next.length === notifications.length) return;
30
- notifications = next;
31
- emit();
32
- },
33
- clear() {
34
- if (notifications.length === 0) return;
35
- notifications = [];
36
- emit();
37
- },
38
- getSnapshot: () => notifications,
39
- subscribe(callback) {
40
- subscribers.add(callback);
41
- return () => void subscribers.delete(callback);
42
- }
43
- };
3
+ let notifications = [];
4
+ let nextId = 1;
5
+ const subscribers = /* @__PURE__ */ new Set();
6
+ const emit = () => {
7
+ for (const cb of subscribers) cb();
8
+ };
9
+ return {
10
+ notify(message, options = {}) {
11
+ const id = nextId++;
12
+ notifications = [...notifications, {
13
+ id,
14
+ message,
15
+ type: options.type ?? "info",
16
+ messageArgs: options.messageArgs,
17
+ undoable: options.undoable,
18
+ autoHideDuration: options.autoHideDuration,
19
+ undo: options.undo,
20
+ onClose: options.onClose
21
+ }];
22
+ emit();
23
+ return id;
24
+ },
25
+ dismiss(id) {
26
+ const next = notifications.filter((n) => n.id !== id);
27
+ if (next.length === notifications.length) return;
28
+ notifications = next;
29
+ emit();
30
+ },
31
+ clear() {
32
+ if (notifications.length === 0) return;
33
+ notifications = [];
34
+ emit();
35
+ },
36
+ getSnapshot: () => notifications,
37
+ subscribe(callback) {
38
+ subscribers.add(callback);
39
+ return () => void subscribers.delete(callback);
40
+ }
41
+ };
44
42
  }
45
- export {
46
- createNotificationStore
47
- };
43
+ export { createNotificationStore };
@@ -1,3 +1,5 @@
1
+ /** How often an open tour re-measures its target and card, in milliseconds. */
2
+ export declare const REMEASURE_MS = 250;
1
3
  /** A box in viewport pixels. The adapters measure it; core touches no DOM. */
2
4
  export interface TourRect {
3
5
  top: number;
@@ -1,82 +1,69 @@
1
- const SIDES = ["bottom", "top", "right", "left"];
2
- const OPPOSITE = {
3
- top: "bottom",
4
- bottom: "top",
5
- left: "right",
6
- right: "left"
1
+ // src/onboarding-tour/placement.ts
2
+ /** How often an open tour re-measures its target and card, in milliseconds. */
3
+ var REMEASURE_MS = 250;
4
+ var SIDES = [
5
+ "bottom",
6
+ "top",
7
+ "right",
8
+ "left"
9
+ ];
10
+ var OPPOSITE = {
11
+ top: "bottom",
12
+ bottom: "top",
13
+ left: "right",
14
+ right: "left"
7
15
  };
8
- function placeTourCard({
9
- target,
10
- card,
11
- viewport,
12
- placement,
13
- margin = 12
14
- }) {
15
- if (!target) {
16
- return {
17
- top: (viewport.height - card.height) / 2,
18
- left: (viewport.width - card.width) / 2,
19
- side: placement === "auto" ? "bottom" : placement
20
- };
21
- }
22
- const room = {
23
- top: target.top,
24
- bottom: viewport.height - (target.top + target.height),
25
- left: target.left,
26
- right: viewport.width - (target.left + target.width)
27
- };
28
- const needed = (side2) => (side2 === "top" || side2 === "bottom" ? card.height : card.width) + margin * 2;
29
- const fits = (side2) => room[side2] >= needed(side2);
30
- let side;
31
- if (placement === "auto") {
32
- const roomiest = (candidates) => candidates.reduce(
33
- (best, next) => room[next] > room[best] ? next : best
34
- );
35
- const fitting = SIDES.filter(fits);
36
- side = roomiest(fitting.length > 0 ? fitting : SIDES);
37
- } else {
38
- side = !fits(placement) && fits(OPPOSITE[placement]) ? OPPOSITE[placement] : placement;
39
- }
40
- const centreX = target.left + target.width / 2 - card.width / 2;
41
- const centreY = target.top + target.height / 2 - card.height / 2;
42
- let top;
43
- let left;
44
- switch (side) {
45
- case "bottom":
46
- top = target.top + target.height + margin;
47
- left = centreX;
48
- break;
49
- case "top":
50
- top = target.top - margin - card.height;
51
- left = centreX;
52
- break;
53
- case "right":
54
- top = centreY;
55
- left = target.left + target.width + margin;
56
- break;
57
- case "left":
58
- top = centreY;
59
- left = target.left - margin - card.width;
60
- break;
61
- }
62
- return {
63
- top: Math.max(
64
- margin,
65
- Math.min(top, viewport.height - card.height - margin)
66
- ),
67
- left: Math.max(
68
- margin,
69
- Math.min(left, viewport.width - card.width - margin)
70
- ),
71
- side
72
- };
16
+ function placeTourCard({ target, card, viewport, placement, margin = 12 }) {
17
+ if (!target) return {
18
+ top: (viewport.height - card.height) / 2,
19
+ left: (viewport.width - card.width) / 2,
20
+ side: placement === "auto" ? "bottom" : placement
21
+ };
22
+ const room = {
23
+ top: target.top,
24
+ bottom: viewport.height - (target.top + target.height),
25
+ left: target.left,
26
+ right: viewport.width - (target.left + target.width)
27
+ };
28
+ const needed = (side) => (side === "top" || side === "bottom" ? card.height : card.width) + margin * 2;
29
+ const fits = (side) => room[side] >= needed(side);
30
+ let side;
31
+ if (placement === "auto") {
32
+ const roomiest = (candidates) => candidates.reduce((best, next) => room[next] > room[best] ? next : best);
33
+ const fitting = SIDES.filter(fits);
34
+ side = roomiest(fitting.length > 0 ? fitting : SIDES);
35
+ } else side = !fits(placement) && fits(OPPOSITE[placement]) ? OPPOSITE[placement] : placement;
36
+ const centreX = target.left + target.width / 2 - card.width / 2;
37
+ const centreY = target.top + target.height / 2 - card.height / 2;
38
+ let top;
39
+ let left;
40
+ switch (side) {
41
+ case "bottom":
42
+ top = target.top + target.height + margin;
43
+ left = centreX;
44
+ break;
45
+ case "top":
46
+ top = target.top - margin - card.height;
47
+ left = centreX;
48
+ break;
49
+ case "right":
50
+ top = centreY;
51
+ left = target.left + target.width + margin;
52
+ break;
53
+ case "left":
54
+ top = centreY;
55
+ left = target.left - margin - card.width;
56
+ }
57
+ return {
58
+ top: Math.max(margin, Math.min(top, viewport.height - card.height - margin)),
59
+ left: Math.max(margin, Math.min(left, viewport.width - card.width - margin)),
60
+ side
61
+ };
73
62
  }
63
+ /** A CSS `clip-path` that fills the page except the target's rect. */
74
64
  function tourSpotlightPath(target) {
75
- const right = target.left + target.width;
76
- const bottom = target.top + target.height;
77
- return `polygon(0% 0%, 0% 100%, ${target.left}px 100%, ${target.left}px ${target.top}px, ${right}px ${target.top}px, ${right}px ${bottom}px, ${target.left}px ${bottom}px, ${target.left}px 100%, 100% 100%, 100% 0%)`;
65
+ const right = target.left + target.width;
66
+ const bottom = target.top + target.height;
67
+ return `polygon(0% 0%, 0% 100%, ${target.left}px 100%, ${target.left}px ${target.top}px, ${right}px ${target.top}px, ${right}px ${bottom}px, ${target.left}px ${bottom}px, ${target.left}px 100%, 100% 100%, 100% 0%)`;
78
68
  }
79
- export {
80
- placeTourCard,
81
- tourSpotlightPath
82
- };
69
+ export { REMEASURE_MS, placeTourCard, tourSpotlightPath };
@@ -1,58 +1,50 @@
1
1
  import { createMicroStore } from "../store/micro-store.js";
2
+ // src/onboarding-tour/tour-controller.ts
3
+ /** Where the onboarding tour keeps its done flag in a `CheloneStore`. */
2
4
  function onboardingTourKey(id) {
3
- return `onboarding-tour.${id}.completed`;
5
+ return `onboarding-tour.${id}.completed`;
4
6
  }
5
- function createTourController({
6
- id,
7
- stepCount,
8
- store,
9
- autoStart = true,
10
- onComplete
11
- }) {
12
- const key = onboardingTourKey(id);
13
- const isDone = () => store.getItem(key) === true;
14
- const micro = createMicroStore(
15
- { active: false, index: 0 },
16
- {
17
- // The store is only watched while someone is subscribed, so an unmounted
18
- // tour does not reopen when its flag is cleared.
19
- onSubscribed() {
20
- const openIfDue = () => {
21
- if (autoStart && !isDone() && !micro.getSnapshot().active) start();
22
- };
23
- openIfDue();
24
- return store.subscribe(key, openIfDue);
25
- }
26
- }
27
- );
28
- function start() {
29
- if (stepCount < 1) return;
30
- micro.setState({ active: true, index: 0 });
31
- }
32
- function end(reason) {
33
- if (!micro.getSnapshot().active) return;
34
- micro.setState({ active: false });
35
- store.setItem(key, true);
36
- onComplete?.(reason);
37
- }
38
- return {
39
- ...micro,
40
- start,
41
- next() {
42
- const { active, index } = micro.getSnapshot();
43
- if (!active) return;
44
- if (index >= stepCount - 1) end("finished");
45
- else micro.setState({ index: index + 1 });
46
- },
47
- back() {
48
- const { active, index } = micro.getSnapshot();
49
- if (active && index > 0) micro.setState({ index: index - 1 });
50
- },
51
- skip: () => end("skipped"),
52
- finish: () => end("finished")
53
- };
7
+ function createTourController({ id, stepCount, store, autoStart = true, onComplete }) {
8
+ const key = onboardingTourKey(id);
9
+ const isDone = () => store.getItem(key) === true;
10
+ const micro = createMicroStore({
11
+ active: false,
12
+ index: 0
13
+ }, { onSubscribed() {
14
+ const openIfDue = () => {
15
+ if (autoStart && !isDone() && !micro.getSnapshot().active) start();
16
+ };
17
+ openIfDue();
18
+ return store.subscribe(key, openIfDue);
19
+ } });
20
+ function start() {
21
+ if (stepCount < 1) return;
22
+ micro.setState({
23
+ active: true,
24
+ index: 0
25
+ });
26
+ }
27
+ function end(reason) {
28
+ if (!micro.getSnapshot().active) return;
29
+ micro.setState({ active: false });
30
+ store.setItem(key, true);
31
+ onComplete?.(reason);
32
+ }
33
+ return {
34
+ ...micro,
35
+ start,
36
+ next() {
37
+ const { active, index } = micro.getSnapshot();
38
+ if (!active) return;
39
+ if (index >= stepCount - 1) end("finished");
40
+ else micro.setState({ index: index + 1 });
41
+ },
42
+ back() {
43
+ const { active, index } = micro.getSnapshot();
44
+ if (active && index > 0) micro.setState({ index: index - 1 });
45
+ },
46
+ skip: () => end("skipped"),
47
+ finish: () => end("finished")
48
+ };
54
49
  }
55
- export {
56
- createTourController,
57
- onboardingTourKey
58
- };
50
+ export { createTourController, onboardingTourKey };
@@ -1,85 +1,79 @@
1
1
  import { copyMembers } from "./copy-members.js";
2
2
  import { recordTopic, resourceTopic } from "./topics.js";
3
+ // src/realtime/add-events-for-mutations.ts
4
+ /**
5
+ * Publishes after each successful write, so other clients can refresh. The
6
+ * result waits for the publishes to settle but never fails because of them;
7
+ * a rejected publish goes to `onError`. Returns the type it was given, so a
8
+ * `RealtimeDataProvider` stays one.
9
+ */
3
10
  function addEventsForMutations(base, publisher, { onError } = {}) {
4
- const publishAll = async (events) => {
5
- await Promise.all(
6
- events.map(async ([topic, event]) => {
7
- try {
8
- await publisher.publish(topic, event);
9
- } catch (error) {
10
- try {
11
- onError?.(error);
12
- } catch {
13
- }
14
- }
15
- })
16
- );
17
- };
18
- const manyEvents = (type, resource, ids) => [
19
- [resourceTopic(resource), { type, payload: { ids } }],
20
- ...ids.map(
21
- (id) => [
22
- recordTopic(resource, id),
23
- { type, payload: { id } }
24
- ]
25
- )
26
- ];
27
- const wrapped = {
28
- ...copyMembers(base),
29
- create: async (resource, params) => {
30
- const result = await base.create(resource, params);
31
- await publishAll([
32
- [
33
- resourceTopic(resource),
34
- { type: "created", payload: { ids: [result.data.id] } }
35
- ]
36
- ]);
37
- return result;
38
- },
39
- update: async (resource, params) => {
40
- const result = await base.update(resource, params);
41
- await publishAll([
42
- [
43
- recordTopic(resource, params.id),
44
- { type: "updated", payload: { id: params.id, data: result.data } }
45
- ],
46
- [
47
- resourceTopic(resource),
48
- { type: "updated", payload: { ids: [params.id] } }
49
- ]
50
- ]);
51
- return result;
52
- },
53
- delete: async (resource, params) => {
54
- const result = await base.delete(resource, params);
55
- await publishAll([
56
- [
57
- recordTopic(resource, params.id),
58
- {
59
- type: "deleted",
60
- payload: { id: params.id, previousData: result.data }
61
- }
62
- ],
63
- [
64
- resourceTopic(resource),
65
- { type: "deleted", payload: { ids: [params.id] } }
66
- ]
67
- ]);
68
- return result;
69
- },
70
- updateMany: async (resource, params) => {
71
- const result = await base.updateMany(resource, params);
72
- await publishAll(manyEvents("updated", resource, result.data));
73
- return result;
74
- },
75
- deleteMany: async (resource, params) => {
76
- const result = await base.deleteMany(resource, params);
77
- await publishAll(manyEvents("deleted", resource, result.data));
78
- return result;
79
- }
80
- };
81
- return wrapped;
11
+ const publishAll = async (events) => {
12
+ await Promise.all(events.map(async ([topic, event]) => {
13
+ try {
14
+ await publisher.publish(topic, event);
15
+ } catch (error) {
16
+ try {
17
+ onError?.(error);
18
+ } catch {}
19
+ }
20
+ }));
21
+ };
22
+ const manyEvents = (type, resource, ids) => [[resourceTopic(resource), {
23
+ type,
24
+ payload: { ids }
25
+ }], ...ids.map((id) => [recordTopic(resource, id), {
26
+ type,
27
+ payload: { id }
28
+ }])];
29
+ return {
30
+ ...copyMembers(base),
31
+ create: async (resource, params) => {
32
+ const result = await base.create(resource, params);
33
+ await publishAll([[resourceTopic(resource), {
34
+ type: "created",
35
+ payload: { ids: [result.data.id] }
36
+ }]]);
37
+ return result;
38
+ },
39
+ update: async (resource, params) => {
40
+ const result = await base.update(resource, params);
41
+ await publishAll([[recordTopic(resource, params.id), {
42
+ type: "updated",
43
+ payload: {
44
+ id: params.id,
45
+ data: result.data
46
+ }
47
+ }], [resourceTopic(resource), {
48
+ type: "updated",
49
+ payload: { ids: [params.id] }
50
+ }]]);
51
+ return result;
52
+ },
53
+ delete: async (resource, params) => {
54
+ const result = await base.delete(resource, params);
55
+ await publishAll([[recordTopic(resource, params.id), {
56
+ type: "deleted",
57
+ payload: {
58
+ id: params.id,
59
+ previousData: result.data
60
+ }
61
+ }], [resourceTopic(resource), {
62
+ type: "deleted",
63
+ payload: { ids: [params.id] }
64
+ }]]);
65
+ return result;
66
+ },
67
+ updateMany: async (resource, params) => {
68
+ const result = await base.updateMany(resource, params);
69
+ await publishAll(manyEvents("updated", resource, result.data));
70
+ return result;
71
+ },
72
+ deleteMany: async (resource, params) => {
73
+ const result = await base.deleteMany(resource, params);
74
+ await publishAll(manyEvents("deleted", resource, result.data));
75
+ return result;
76
+ }
77
+ };
82
78
  }
83
- export {
84
- addEventsForMutations
85
- };
79
+ export { addEventsForMutations };
@@ -1,15 +1,18 @@
1
- import { lockTopic, lockResourceTopic } from "./topics.js";
1
+ import { lockResourceTopic, lockTopic } from "./topics.js";
2
+ // src/realtime/announce-lock.ts
3
+ /**
4
+ * Tells a publisher of a lock or an unlock, on the record's and the
5
+ * resource's topic. A failed publish is swallowed: the lock is already taken
6
+ * or released, so a failed announcement must not report it as failed.
7
+ */
2
8
  async function announceLock(publisher, type, lock) {
3
- if (!publisher) return;
4
- const event = { type, payload: lock };
5
- try {
6
- await Promise.all([
7
- publisher.publish(lockTopic(lock.resource, lock.recordId), event),
8
- publisher.publish(lockResourceTopic(lock.resource), event)
9
- ]);
10
- } catch {
11
- }
9
+ if (!publisher) return;
10
+ const event = {
11
+ type,
12
+ payload: lock
13
+ };
14
+ try {
15
+ await Promise.all([publisher.publish(lockTopic(lock.resource, lock.recordId), event), publisher.publish(lockResourceTopic(lock.resource), event)]);
16
+ } catch {}
12
17
  }
13
- export {
14
- announceLock
15
- };
18
+ export { announceLock };