ctrl-fx 0.1.1 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -6,7 +6,7 @@ import {
6
6
  isNodeGroup,
7
7
  nodeGroup,
8
8
  nodeId
9
- } from "./chunk-NSWOTCDU.js";
9
+ } from "./chunk-EKBLRHWK.js";
10
10
  import {
11
11
  ResponseBody,
12
12
  emptyLocation,
@@ -27,7 +27,7 @@ import {
27
27
  stringToInt,
28
28
  success,
29
29
  taskId
30
- } from "./chunk-KNHJPAIU.js";
30
+ } from "./chunk-OSIRHKDB.js";
31
31
  import {
32
32
  dbVersion,
33
33
  run,
@@ -1132,7 +1132,6 @@ function closestComponentPath(node) {
1132
1132
  }
1133
1133
 
1134
1134
  // src/internal/cmpmgr.ts
1135
- var mountCount = 0;
1136
1135
  function manageComponent(component, mountId, window2, interpreter, styleRegistry) {
1137
1136
  const mountNode = window2.document.getElementById(mountId);
1138
1137
  if (!mountNode) {
@@ -1152,11 +1151,19 @@ function manageComponent(component, mountId, window2, interpreter, styleRegistry
1152
1151
  };
1153
1152
  }
1154
1153
  var ComponentManager = class {
1155
- constructor(component, mountNode, window2, interpreter, styleRegistry, onRootEvent) {
1154
+ constructor(component, mountNode, window2, interpreter, styleRegistry, onRootEvent, alreadyMountedPaths) {
1156
1155
  __publicField(this, "rootCompPath");
1157
1156
  __publicField(this, "components", {});
1158
1157
  __publicField(this, "removedComponents", {});
1158
+ // Mirrors `components` but for view()/fixedView() subtrees, which have no
1159
+ // state of their own but still need stable identity so their onRender
1160
+ // effects don't refire whenever an ancestor element is rebuilt (or, via
1161
+ // alreadyMountedPaths, whenever a fresh ComponentManager remounts them).
1162
+ // Keyed the same way as components: nodeId + enclosing *component* path
1163
+ // (nesting through another view doesn't add a path segment).
1164
+ __publicField(this, "views", {});
1159
1165
  __publicField(this, "addedComponents", []);
1166
+ __publicField(this, "pendingRenderEffects", []);
1160
1167
  __publicField(this, "interpreter");
1161
1168
  __publicField(this, "window");
1162
1169
  __publicField(this, "document");
@@ -1164,11 +1171,19 @@ var ComponentManager = class {
1164
1171
  __publicField(this, "taskRegistry", new TaskRegistry());
1165
1172
  __publicField(this, "styleRegistry");
1166
1173
  __publicField(this, "onRootEvent");
1174
+ // Paths that were already mounted (and had their onRender effects fired)
1175
+ // by some earlier, unrelated ComponentManager instance -- e.g. a prior
1176
+ // `.run()` call in ctrl-fx/testing, which mounts a fresh ComponentManager
1177
+ // each time but wants onRender to still behave as if the component tree
1178
+ // had persisted. Suppresses re-queueing onRender effects for those paths
1179
+ // without affecting real first-time mounts.
1180
+ __publicField(this, "alreadyMountedPaths");
1167
1181
  this.window = window2;
1168
1182
  this.document = this.window.document;
1169
1183
  this.interpreter = interpreter;
1170
1184
  this.styleRegistry = styleRegistry;
1171
1185
  this.onRootEvent = onRootEvent;
1186
+ this.alreadyMountedPaths = alreadyMountedPaths ?? /* @__PURE__ */ new Set();
1172
1187
  this.eventManager = new EventManager(
1173
1188
  this.window,
1174
1189
  (effect, node, onResult) => {
@@ -1178,7 +1193,7 @@ var ComponentManager = class {
1178
1193
  }
1179
1194
  }
1180
1195
  );
1181
- const rootCompPath = componentPath(nodeId(`__root_component:${++mountCount}`));
1196
+ const rootCompPath = componentPath(nodeId("__root_component"));
1182
1197
  this.rootCompPath = rootCompPath;
1183
1198
  const compNode = componentNode(component, rootCompPath.nodeId);
1184
1199
  const root = rootNode(mountNode);
@@ -1200,6 +1215,11 @@ var ComponentManager = class {
1200
1215
  _type: "Uninitialized"
1201
1216
  };
1202
1217
  }
1218
+ /** Paths of components (past their initial render) and views currently mounted. */
1219
+ getMountedPaths() {
1220
+ const componentPaths = Object.entries(this.components).filter(([, node]) => node.state._type === "Ready").map(([path]) => path);
1221
+ return /* @__PURE__ */ new Set([...componentPaths, ...Object.keys(this.views)]);
1222
+ }
1203
1223
  dispatchEffect(effect) {
1204
1224
  this.runEffect(effect, this.rootCompPath, () => {
1205
1225
  });
@@ -1247,11 +1267,19 @@ var ComponentManager = class {
1247
1267
  if (component.state._type === "Ready" && eq(component.state.value, state)) {
1248
1268
  return;
1249
1269
  }
1270
+ const isInitialMount = component.state._type === "Uninitialized";
1271
+ const wasAlreadyMounted = this.alreadyMountedPaths.has(componentPath2.format());
1250
1272
  component.state = { _type: "Ready", value: state };
1251
1273
  const newNodeGroup = component.component.view(
1252
1274
  state,
1253
1275
  component.component.params
1254
1276
  );
1277
+ if (isInitialMount && !wasAlreadyMounted && newNodeGroup.renderEffects.length > 0) {
1278
+ this.pendingRenderEffects.push({
1279
+ path: componentPath2,
1280
+ effects: newNodeGroup.renderEffects
1281
+ });
1282
+ }
1255
1283
  component.containerListeners = newNodeGroup.containerListeners;
1256
1284
  this.eventManager.setContainerListeners(component);
1257
1285
  const oldNodes = component.firstChild;
@@ -1271,6 +1299,11 @@ var ComponentManager = class {
1271
1299
  });
1272
1300
  }
1273
1301
  });
1302
+ const pending = this.pendingRenderEffects.splice(0);
1303
+ pending.forEach(({ path, effects }) => {
1304
+ effects.forEach((effect) => this.runEffect(effect, path, () => {
1305
+ }));
1306
+ });
1274
1307
  }
1275
1308
  compareNodeSequences(oldNodes, newNodes, parent, ancestorComponentPath) {
1276
1309
  const mutNewNodes = [...newNodes];
@@ -1319,6 +1352,11 @@ var ComponentManager = class {
1319
1352
  }
1320
1353
  case "ViewNode": {
1321
1354
  that.eventManager.setContainerListeners(node);
1355
+ const viewPath = componentPath(
1356
+ node.nodeId,
1357
+ ancestorComponentPath2
1358
+ ).format();
1359
+ delete that.views[viewPath];
1322
1360
  return;
1323
1361
  }
1324
1362
  case "ComponentNode": {
@@ -1489,6 +1527,13 @@ var ComponentManager = class {
1489
1527
  return internalElement;
1490
1528
  },
1491
1529
  onView(view) {
1530
+ const viewId = componentPath(view.nodeId, ancestorComponentId).format();
1531
+ const existingView = that.views[viewId];
1532
+ if (existingView) {
1533
+ detach(existingView);
1534
+ that.compareNodes(existingView, view, ancestorComponentId);
1535
+ return existingView;
1536
+ }
1492
1537
  const vNode = viewNode(view);
1493
1538
  const nodeGroup2 = view.nodes(view.params);
1494
1539
  vNode.params = view.params;
@@ -1499,6 +1544,13 @@ var ComponentManager = class {
1499
1544
  );
1500
1545
  });
1501
1546
  that.eventManager.setContainerListeners(vNode);
1547
+ that.views[viewId] = vNode;
1548
+ if (!that.alreadyMountedPaths.has(viewId) && nodeGroup2.renderEffects.length > 0) {
1549
+ that.pendingRenderEffects.push({
1550
+ path: ancestorComponentId,
1551
+ effects: nodeGroup2.renderEffects
1552
+ });
1553
+ }
1502
1554
  return vNode;
1503
1555
  },
1504
1556
  onComponent(comp) {
@@ -1577,6 +1629,12 @@ var ComponentManager = class {
1577
1629
  return registeredComponent;
1578
1630
  }
1579
1631
  }
1632
+ if (typeof newNode !== "string" && newNode._type === "View") {
1633
+ const registeredView = this.views[componentPath(newNode.nodeId, ancestorComponentPath).format()];
1634
+ if (registeredView) {
1635
+ return registeredView;
1636
+ }
1637
+ }
1580
1638
  let next = oldNodes;
1581
1639
  while (next) {
1582
1640
  if (getNodesRelationship(next, newNode) === "same") {
@@ -1811,7 +1869,7 @@ var TestScheduler = class {
1811
1869
  cancel(tskId) {
1812
1870
  this.pending = this.pending.filter((t) => t.taskId !== tskId);
1813
1871
  }
1814
- advance(ms, acc, broadcastReg, window2) {
1872
+ advance(ms, acc, broadcastReg, window2, config) {
1815
1873
  const targetTime = this.virtualNow + ms;
1816
1874
  while (true) {
1817
1875
  const next = this.pending.filter((t) => t.nextFireAtMillis <= targetTime).sort((a, b) => a.nextFireAtMillis - b.nextFireAtMillis)[0];
@@ -1829,7 +1887,8 @@ var TestScheduler = class {
1829
1887
  acc,
1830
1888
  broadcastReg,
1831
1889
  this,
1832
- window2
1890
+ window2,
1891
+ config
1833
1892
  );
1834
1893
  }
1835
1894
  this.virtualNow = targetTime;
@@ -1837,12 +1896,11 @@ var TestScheduler = class {
1837
1896
  };
1838
1897
  var BroadcastChannelRegistry = class {
1839
1898
  constructor() {
1840
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
1841
1899
  __publicField(this, "channels", /* @__PURE__ */ new Map());
1842
1900
  }
1843
- subscribe(channel, handler, tskId) {
1901
+ subscribe(channel, handler, tskId, callbacks) {
1844
1902
  if (!this.channels.has(channel)) this.channels.set(channel, []);
1845
- this.channels.get(channel).push({ handler, taskId: tskId });
1903
+ this.channels.get(channel).push({ handler, taskId: tskId, callbacks });
1846
1904
  }
1847
1905
  unsubscribe(tskId) {
1848
1906
  for (const [ch, subs] of this.channels) {
@@ -1850,27 +1908,22 @@ var BroadcastChannelRegistry = class {
1850
1908
  }
1851
1909
  }
1852
1910
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
1853
- deliver(channel, message, acc, broadcastReg, scheduler, window2) {
1911
+ deliver(channel, message, acc, broadcastReg, scheduler, window2, config) {
1854
1912
  const subs = this.channels.get(channel) ?? [];
1855
1913
  for (const sub of subs) {
1856
1914
  testingInterpreter(
1857
1915
  sub.handler(message),
1858
1916
  {
1917
+ ...sub.callbacks,
1859
1918
  onComplete() {
1860
- },
1861
- onFireEvent() {
1862
- },
1863
- getState() {
1864
- return void 0;
1865
- },
1866
- setState() {
1867
1919
  }
1868
1920
  },
1869
1921
  new TaskRegistry(),
1870
1922
  acc,
1871
1923
  broadcastReg,
1872
1924
  scheduler,
1873
- window2
1925
+ window2,
1926
+ config
1874
1927
  );
1875
1928
  }
1876
1929
  }
@@ -1941,8 +1994,8 @@ function makeTestingInterpreter(initialData, window2, config) {
1941
1994
  return {
1942
1995
  interpreter,
1943
1996
  getData: () => snapshotTestData(acc),
1944
- advanceTime: (ms) => scheduler.advance(ms, acc, broadcastReg, window2),
1945
- fireBroadcast: (channel, message) => broadcastReg.deliver(channel, message, acc, broadcastReg, scheduler, window2)
1997
+ advanceTime: (ms) => scheduler.advance(ms, acc, broadcastReg, window2, config),
1998
+ fireBroadcast: (channel, message) => broadcastReg.deliver(channel, message, acc, broadcastReg, scheduler, window2, config)
1946
1999
  };
1947
2000
  }
1948
2001
  function testingInterpreter(effect, callbacks, taskRegistry, acc, broadcastReg, scheduler, window2, config) {
@@ -2088,7 +2141,7 @@ function testingInterpreter(effect, callbacks, taskRegistry, acc, broadcastReg,
2088
2141
  if (tskIdInput) {
2089
2142
  broadcastReg.unsubscribe(tskIdInput);
2090
2143
  }
2091
- broadcastReg.subscribe(channel, handler, tskId);
2144
+ broadcastReg.subscribe(channel, handler, tskId, callbacks);
2092
2145
  callbacks.onComplete(tskId);
2093
2146
  return;
2094
2147
  }
@@ -2140,7 +2193,22 @@ function testingInterpreter(effect, callbacks, taskRegistry, acc, broadcastReg,
2140
2193
  return;
2141
2194
  }
2142
2195
  case "MakeHttpRequest": {
2143
- callbacks.onComplete(void 0);
2196
+ const request = effect.operation.input;
2197
+ const handler = config?.http.handler ?? (() => {
2198
+ throw new Error("No HTTP handler configured in TestConfig.");
2199
+ });
2200
+ let result;
2201
+ try {
2202
+ result = handler(request, acc.http.interactions);
2203
+ } catch (err) {
2204
+ result = failure({
2205
+ _type: "RequestError",
2206
+ cause: "UnexpectedError",
2207
+ message: err instanceof Error ? err.message : `Unexpected request error: ${err}`
2208
+ });
2209
+ }
2210
+ acc.http.interactions.push({ request, response: result });
2211
+ callbacks.onComplete(result);
2144
2212
  return;
2145
2213
  }
2146
2214
  case "Product": {
@@ -2444,6 +2512,7 @@ var Node = class {
2444
2512
  }
2445
2513
  insertBefore(node) {
2446
2514
  const newNode = typeof node === "string" ? new TextNode(node) : node;
2515
+ newNode.remove();
2447
2516
  if (this.previousSibling) {
2448
2517
  this.previousSibling.nextSibling = newNode;
2449
2518
  newNode.previousSibling = this.previousSibling;
@@ -2459,6 +2528,7 @@ var Node = class {
2459
2528
  }
2460
2529
  insertAfter(node) {
2461
2530
  const newNode = typeof node === "string" ? new TextNode(node) : node;
2531
+ newNode.remove();
2462
2532
  if (this.nextSibling) {
2463
2533
  this.nextSibling.previousSibling = newNode;
2464
2534
  newNode.nextSibling = this.nextSibling;
@@ -2766,19 +2836,26 @@ function makeWindow() {
2766
2836
  return win;
2767
2837
  }
2768
2838
  var TestableComponentImpl = class _TestableComponentImpl {
2769
- constructor(component, state, config, data, dom, window2) {
2839
+ constructor(component, state, config, data, dom, window2, mountedPaths) {
2770
2840
  __publicField(this, "config");
2771
2841
  __publicField(this, "data");
2772
2842
  __publicField(this, "dom");
2773
2843
  __publicField(this, "_component");
2774
2844
  __publicField(this, "state");
2775
2845
  __publicField(this, "_window");
2846
+ // Component paths already mounted by a previous ComponentManager in this
2847
+ // chain of .run() calls. Each .run() mounts a fresh ComponentManager (the
2848
+ // DOM/scheduler/subscriptions don't persist), so without this, onRender
2849
+ // effects would fire again on every chained .run() even though, from the
2850
+ // test's perspective, the component was already mounted.
2851
+ __publicField(this, "_mountedPaths");
2776
2852
  this._component = component;
2777
2853
  this.state = state;
2778
2854
  this.config = config;
2779
2855
  this.data = data;
2780
2856
  this.dom = dom;
2781
2857
  this._window = window2;
2858
+ this._mountedPaths = mountedPaths;
2782
2859
  }
2783
2860
  withConfig(config) {
2784
2861
  return new _TestableComponentImpl(
@@ -2787,7 +2864,8 @@ var TestableComponentImpl = class _TestableComponentImpl {
2787
2864
  config,
2788
2865
  this.data,
2789
2866
  this.dom,
2790
- this._window
2867
+ this._window,
2868
+ this._mountedPaths
2791
2869
  );
2792
2870
  }
2793
2871
  withData(data) {
@@ -2797,7 +2875,8 @@ var TestableComponentImpl = class _TestableComponentImpl {
2797
2875
  this.config,
2798
2876
  data,
2799
2877
  this.dom,
2800
- this._window
2878
+ this._window,
2879
+ this._mountedPaths
2801
2880
  );
2802
2881
  }
2803
2882
  run(...interactions) {
@@ -2818,7 +2897,9 @@ var TestableComponentImpl = class _TestableComponentImpl {
2818
2897
  appNode,
2819
2898
  win,
2820
2899
  interpreter,
2821
- noopStyleRegistry()
2900
+ noopStyleRegistry(),
2901
+ void 0,
2902
+ this._mountedPaths
2822
2903
  );
2823
2904
  for (const interaction of interactions) {
2824
2905
  if ("_type" in interaction) {
@@ -2901,7 +2982,8 @@ var TestableComponentImpl = class _TestableComponentImpl {
2901
2982
  this.config,
2902
2983
  getData(),
2903
2984
  serializeDom(win.document),
2904
- win
2985
+ win,
2986
+ mgr.getMountedPaths()
2905
2987
  );
2906
2988
  }
2907
2989
  find(selector) {
@@ -2956,7 +3038,8 @@ function testableComponent(component, config, data) {
2956
3038
  config,
2957
3039
  getData(),
2958
3040
  serializeDom(win.document),
2959
- win
3041
+ win,
3042
+ mgr.getMountedPaths()
2960
3043
  );
2961
3044
  }
2962
3045
  function parseSelector(selector) {
@@ -3319,6 +3402,7 @@ function makeHttpRequest(request, callback) {
3319
3402
  if (ab) {
3320
3403
  callback(
3321
3404
  success({
3405
+ status: response.status,
3322
3406
  headers: convertHeaders(response.headers),
3323
3407
  body: new ResponseBody(ab)
3324
3408
  })
@@ -2,7 +2,7 @@ import {
2
2
  async,
3
3
  isEffect,
4
4
  pure
5
- } from "./chunk-KNHJPAIU.js";
5
+ } from "./chunk-OSIRHKDB.js";
6
6
 
7
7
  // src/dom/nodeid.ts
8
8
  function nodeId(value) {
@@ -111,6 +111,18 @@ var ResponseBody = class {
111
111
  asBlob() {
112
112
  return new Blob([this.data]);
113
113
  }
114
+ asArrayBuffer() {
115
+ return this.data;
116
+ }
117
+ /** Base64-encodes the response body into a `data:` URI. `mimeType` isn't known to `ResponseBody` itself (it's not `data`, it lives on the response's headers) so the caller must supply it. */
118
+ asDataUri(mimeType) {
119
+ const bytes = new Uint8Array(this.data);
120
+ let binary = "";
121
+ for (let i = 0; i < bytes.length; i++) {
122
+ binary += String.fromCharCode(bytes[i]);
123
+ }
124
+ return `data:${mimeType};base64,${btoa(binary)}`;
125
+ }
114
126
  asJson() {
115
127
  try {
116
128
  return success(new Json(JSON.parse(this.asString())));
@@ -1,2 +1,2 @@
1
- export { aB as A, aC as Abbr, aD as Address, aE as Article, aF as Aside, A as Attr, aG as AttrArg, aH as AttrOrNodeIdArgs, aI as B, aJ as BlockElement, aK as Blockquote, aL as Br, aM as Button, aN as ButtonContent, aO as ChangeData, aP as Circle, aQ as Cite, aR as Code, C as Component, aS as ComponentElement, aT as CustomElement, aU as Dd, aV as Details, aW as Div, aX as Dl, aY as Dt, aZ as Element, a_ as Ellipse, a$ as Em, a as EventActions, b0 as EventListenerResult, b1 as EventOptions, b2 as Fieldset, b3 as Figcaption, b4 as Figure, b5 as FlowContent, b6 as Footer, b7 as Form, b8 as H1, b9 as H2, ba as H3, bb as H4, bc as H5, bd as H6, be as Header, bf as Hr, bg as I, bh as Image, bi as Img, bj as InlineElement, bk as Input, bl as Kbd, bm as KeyData, bn as Label, bo as Li, bp as Line, bq as Main, br as Mark, bs as MouseMoveData, bt as Nav, e as Node, N as NodeGroup, bu as NodeId, bv as NonTextNode, bw as NonVoidElement, bx as Ol, by as Option, bz as P, bA as Path, bB as PhrasingContent, bC as Polygon, bD as Polyline, bE as Pre, bF as Prop, bG as Q, bH as Rect, bI as ReplacedElement, bJ as S, bK as ScrollData, bL as Section, bM as Select, bN as Small, bO as Span, bP as Strong, bQ as Sub, bR as Summary, bS as Sup, bT as Svg, bU as SvgGraphicElement, bV as Table, bW as Tbody, bX as Td, bY as TextState, bZ as Textarea, b_ as Tfoot, b$ as Th, c0 as Thead, c1 as Time, c2 as TouchData, c3 as Tr, c4 as U, c5 as Ul, c6 as Use, c7 as View, c8 as VoidElement, c9 as WheelData, ca as attr, cb as component, cc as cssVars, cd as foldNode, ce as id, cf as makeDom, cg as nodeId, ch as preventDefault, ci as prop, cj as stopPropagation, ck as stopPropagationAndPreventDefault, cl as typeAttr } from '../index-fpCmXVEu.js';
1
+ export { aD as A, aE as Abbr, aF as Address, aG as Article, aH as Aside, A as Attr, aI as AttrArg, aJ as AttrOrNodeIdArgs, aK as B, aL as BlockElement, aM as Blockquote, aN as Br, aO as Button, aP as ButtonContent, aQ as ChangeData, aR as Circle, aS as Cite, aT as Code, C as Component, aU as ComponentElement, aV as CustomElement, aW as Dd, aX as Details, aY as Div, aZ as Dl, a_ as Dt, a$ as Element, b0 as Ellipse, b1 as Em, a as EventActions, b2 as EventListenerResult, b3 as EventOptions, b4 as Fieldset, b5 as Figcaption, b6 as Figure, b7 as FlowContent, b8 as Footer, b9 as Form, ba as H1, bb as H2, bc as H3, bd as H4, be as H5, bf as H6, bg as Header, bh as Hr, bi as I, bj as Image, bk as Img, bl as InlineElement, bm as Input, bn as Kbd, bo as KeyData, bp as Label, bq as Li, br as Line, bs as Main, bt as Mark, bu as MouseMoveData, bv as Nav, e as Node, N as NodeGroup, bw as NodeId, bx as NonTextNode, by as NonVoidElement, bz as Ol, bA as Option, bB as P, bC as Path, bD as PhrasingContent, bE as Polygon, bF as Polyline, bG as Pre, bH as Prop, bI as Q, bJ as Rect, bK as ReplacedElement, bL as S, bM as ScrollData, bN as Section, bO as Select, bP as Small, bQ as Span, bR as Strong, bS as Sub, bT as Summary, bU as Sup, bV as Svg, bW as SvgGraphicElement, bX as Table, bY as Tbody, bZ as Td, b_ as TextState, b$ as Textarea, c0 as Tfoot, c1 as Th, c2 as Thead, c3 as Time, c4 as TouchData, c5 as Tr, c6 as U, c7 as Ul, c8 as Use, c9 as View, ca as VoidElement, cb as WheelData, cc as attr, cd as component, ce as cssVars, cf as foldNode, cg as id, ch as makeDom, ci as nodeId, cj as preventDefault, ck as prop, cl as stopPropagation, cm as stopPropagationAndPreventDefault, cn as typeAttr } from '../index-DeEjNrg-.js';
2
2
  import '../db/index.js';
package/dist/dom/index.js CHANGED
@@ -11,8 +11,8 @@ import {
11
11
  stopPropagation,
12
12
  stopPropagationAndPreventDefault,
13
13
  typeAttr
14
- } from "../chunk-NSWOTCDU.js";
15
- import "../chunk-KNHJPAIU.js";
14
+ } from "../chunk-EKBLRHWK.js";
15
+ import "../chunk-OSIRHKDB.js";
16
16
  import "../chunk-PKBMQBKP.js";
17
17
  export {
18
18
  attr,
package/dist/effects.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- export { f as ClipboardError, g as DecodingError, h as DownloadInput, E as Effect, F as FlatMap, j as Fragment, k as Headers, d as HttpError, H as HttpRequest, b as HttpResponse, I as InternalLocation, J as Json, L as Lens, M as Method, l as Path, Q as QueryParam, c as RequestError, n as ResponseBody, R as Result, o as ResultTransformer, q as Return, r as ScrollElementError, S as ScrollOptions, s as StorageTarget, v as Suspend, T as TaskId, w as alert, x as async, y as cancelTask, z as clearAppBadge, B as clearLocalStorage, G as clearSessionStorage, K as confirm, O as customEffect, V as download, W as fireEvent, X as generateUuid, Y as getLocalStorageItem, Z as getLocation, _ as getNotificationPermission, $ as getRandom, a0 as getSessionStorageItem, a1 as getState, a2 as getTime, a3 as go, a4 as isEffect, a5 as log, a6 as makeEffects, a7 as makeHttpRequest, a8 as mapEvent, a9 as mapState, aa as noop, ab as openDatabase, ac as postBroadcastMessage, ad as product, ae as prompt, af as pure, ag as pushState, ah as readClipboard, ai as removeLocalStorageItem, aj as removeSessionStorageItem, ak as replaceState, al as requestNotificationPermission, am as resultT, an as runDbTransaction, ao as scheduleTask, ap as scrollElement, aq as scrollWindow, ar as setAppBadge, as as setDocumentTitle, at as setLocalStorageItem, au as setSessionStorageItem, av as setTimeout, aw as subscribeToBroadcastChannel, ax as taskId, ay as traverse, az as updateState, aA as writeClipboard } from './index-fpCmXVEu.js';
1
+ export { h as ClipboardError, j as DecodingError, k as DownloadInput, E as Effect, F as FlatMap, l as Fragment, n as Headers, d as HttpError, H as HttpRequest, b as HttpResponse, I as InternalLocation, J as Json, L as Lens, M as Method, o as Path, Q as QueryParam, c as RequestError, f as ResponseBody, R as Result, q as ResultTransformer, r as Return, v as ScrollElementError, S as ScrollOptions, w as StorageTarget, x as Suspend, T as TaskId, y as alert, z as async, B as cancelTask, G as clearAppBadge, K as clearLocalStorage, O as clearSessionStorage, V as confirm, W as customEffect, X as download, Y as fireEvent, Z as generateUuid, _ as getLocalStorageItem, $ as getLocation, a0 as getNotificationPermission, a1 as getRandom, a2 as getSessionStorageItem, a3 as getState, a4 as getTime, a5 as go, a6 as isEffect, a7 as log, a8 as makeEffects, a9 as makeHttpRequest, aa as mapEvent, ab as mapState, ac as noop, ad as openDatabase, ae as postBroadcastMessage, af as product, ag as prompt, ah as pure, ai as pushState, aj as readClipboard, ak as removeLocalStorageItem, al as removeSessionStorageItem, am as replaceState, an as requestNotificationPermission, ao as resultT, ap as runDbTransaction, aq as scheduleTask, ar as scrollElement, as as scrollWindow, at as setAppBadge, au as setDocumentTitle, av as setLocalStorageItem, aw as setSessionStorageItem, ax as setTimeout, ay as subscribeToBroadcastChannel, az as taskId, aA as traverse, aB as updateState, aC as writeClipboard } from './index-DeEjNrg-.js';
2
2
  export { ConstraintError, DbEffect, DbError, DbName, DbSetupEffect, DbVersion, NotFoundError, ObjectStore, UnexpectedError } from './db/index.js';
package/dist/effects.js CHANGED
@@ -52,7 +52,7 @@ import {
52
52
  traverse,
53
53
  updateState,
54
54
  writeClipboard
55
- } from "./chunk-KNHJPAIU.js";
55
+ } from "./chunk-OSIRHKDB.js";
56
56
  import "./chunk-PKBMQBKP.js";
57
57
  export {
58
58
  ResultTransformer,
@@ -69,8 +69,12 @@ type Failure<A, E> = {
69
69
  };
70
70
  /** A value that is either a success (`A`) or a failure (`E`). */
71
71
  type Result<A, E> = Success<A, E> | Failure<A, E>;
72
+ /** Creates a successful Result. */
73
+ declare function success<A, E>(value: A): Result<A, E>;
74
+ /** Creates a failed Result. */
75
+ declare function failure<A, E>(error: E): Result<A, E>;
72
76
 
73
- type Method = 'GET' | 'POST' | 'DELETE' | 'PUT' | 'HEAD' | 'OPTIONS';
77
+ type Method = 'GET' | 'POST' | 'DELETE' | 'PUT' | 'PATCH' | 'HEAD' | 'OPTIONS';
74
78
  type HttpRequest = {
75
79
  readonly uri: string;
76
80
  readonly method: Method;
@@ -81,6 +85,7 @@ type Headers = {
81
85
  [key: string]: string;
82
86
  };
83
87
  type HttpResponse = {
88
+ readonly status: number;
84
89
  readonly headers: Headers;
85
90
  readonly body: ResponseBody;
86
91
  };
@@ -106,6 +111,9 @@ declare class ResponseBody {
106
111
  constructor(data: ArrayBuffer);
107
112
  asString(): string;
108
113
  asBlob(): Blob;
114
+ asArrayBuffer(): ArrayBuffer;
115
+ /** Base64-encodes the response body into a `data:` URI. `mimeType` isn't known to `ResponseBody` itself (it's not `data`, it lives on the response's headers) so the caller must supply it. */
116
+ asDataUri(mimeType: string): string;
109
117
  asJson(): Result<Json, DecodingError>;
110
118
  }
111
119
 
@@ -1377,7 +1385,7 @@ declare function makeDom<State, Event>(): {
1377
1385
  element: (tag: string) => (...attrs: readonly (readonly [string, string] | NodeId)[]) => (...children: readonly FlowContent<State, Event>[]) => CustomElement<State, Event>;
1378
1386
  nodeGroup: (...nodes: Node<State, Event>[]) => NodeGroup<State, Event>;
1379
1387
  _: (...nodes: Node<State, Event>[]) => NodeGroup<State, Event>;
1380
- fixedView: (id: NodeId | string) => (nodes: NodeGroup<State, Event> | Node<State, Event>) => View<State, void, Event>;
1388
+ fixedView: (id: NodeId | string) => (nodes: NodeGroup<State, Event> | Node<State, Event>) => View<State, unknown, Event>;
1381
1389
  };
1382
1390
  /** Pattern-matches over a `Node` value, calling the appropriate case handler and returning its result. */
1383
1391
  declare function foldNode<State, Event, A>(node: Node<State, Event>, cases: {
@@ -1388,4 +1396,4 @@ declare function foldNode<State, Event, A>(node: Node<State, Event>, cases: {
1388
1396
  onView: (view: View<State, unknown, Event>) => A;
1389
1397
  }): A;
1390
1398
 
1391
- export { getRandom as $, type Attr as A, clearLocalStorage as B, type Component as C, type Dimensions as D, type Effect as E, type FlatMap as F, clearSessionStorage as G, type HttpRequest as H, type InternalLocation as I, Json as J, confirm as K, type Lens as L, type Method as M, type NodeGroup as N, customEffect as O, type Permission as P, type QueryParam as Q, type Result as R, type ScrollOptions as S, type TaskId as T, type Uuid as U, download as V, fireEvent as W, generateUuid as X, getLocalStorageItem as Y, getLocation as Z, getNotificationPermission as _, type EventActions as a, type Em as a$, getSessionStorageItem as a0, getState as a1, getTime as a2, go as a3, isEffect as a4, log as a5, makeEffects as a6, makeHttpRequest as a7, mapEvent as a8, mapState as a9, writeClipboard as aA, type A as aB, type Abbr as aC, type Address as aD, type Article as aE, type Aside as aF, type AttrArg as aG, type AttrOrNodeIdArgs as aH, type B as aI, type BlockElement as aJ, type Blockquote as aK, type Br as aL, type Button as aM, type ButtonContent as aN, type ChangeData as aO, type Circle as aP, type Cite as aQ, type Code as aR, type ComponentElement as aS, type CustomElement as aT, type Dd as aU, type Details as aV, type Div as aW, type Dl as aX, type Dt as aY, type Element as aZ, type Ellipse as a_, noop as aa, openDatabase as ab, postBroadcastMessage as ac, product as ad, prompt as ae, pure as af, pushState as ag, readClipboard as ah, removeLocalStorageItem as ai, removeSessionStorageItem as aj, replaceState as ak, requestNotificationPermission as al, resultT as am, runDbTransaction as an, scheduleTask as ao, scrollElement as ap, scrollWindow as aq, setAppBadge as ar, setDocumentTitle as as, setLocalStorageItem as at, setSessionStorageItem as au, setTimeout as av, subscribeToBroadcastChannel as aw, taskId as ax, traverse as ay, updateState as az, type HttpResponse as b, type Th as b$, type EventListenerResult as b0, type EventOptions as b1, type Fieldset as b2, type Figcaption as b3, type Figure as b4, type FlowContent as b5, type Footer as b6, type Form as b7, type H1 as b8, type H2 as b9, type Path as bA, type PhrasingContent as bB, type Polygon as bC, type Polyline as bD, type Pre as bE, type Prop as bF, type Q as bG, type Rect as bH, type ReplacedElement as bI, type S as bJ, type ScrollData as bK, type Section as bL, type Select as bM, type Small as bN, type Span as bO, type Strong as bP, type Sub as bQ, type Summary as bR, type Sup as bS, type Svg as bT, type SvgGraphicElement as bU, type Table as bV, type Tbody as bW, type Td as bX, type TextState as bY, type Textarea as bZ, type Tfoot as b_, type H3 as ba, type H4 as bb, type H5 as bc, type H6 as bd, type Header as be, type Hr as bf, type I as bg, type Image as bh, type Img as bi, type InlineElement as bj, type Input as bk, type Kbd as bl, type KeyData as bm, type Label as bn, type Li as bo, type Line as bp, type Main as bq, type Mark as br, type MouseMoveData as bs, type Nav as bt, type NodeId as bu, type NonTextNode as bv, type NonVoidElement as bw, type Ol as bx, type Option as by, type P as bz, type RequestError as c, type Thead as c0, type Time as c1, type TouchData as c2, type Tr as c3, type U as c4, type Ul as c5, type Use as c6, type View as c7, type VoidElement as c8, type WheelData as c9, attr as ca, component as cb, cssVars as cc, foldNode as cd, id as ce, makeDom as cf, nodeId as cg, preventDefault as ch, prop as ci, stopPropagation as cj, stopPropagationAndPreventDefault as ck, typeAttr as cl, type HttpError as d, type Node as e, type ClipboardError as f, type DecodingError as g, type DownloadInput as h, isState as i, type Fragment as j, type Headers as k, type Path$1 as l, manageApplication as m, ResponseBody as n, ResultTransformer as o, permission as p, type Return as q, type ScrollElementError as r, type StorageTarget as s, toComponent as t, uuidFromString as u, type Suspend as v, alert as w, async as x, cancelTask as y, clearAppBadge as z };
1399
+ export { getLocation as $, type Attr as A, cancelTask as B, type Component as C, type Dimensions as D, type Effect as E, type FlatMap as F, clearAppBadge as G, type HttpRequest as H, type InternalLocation as I, Json as J, clearLocalStorage as K, type Lens as L, type Method as M, type NodeGroup as N, clearSessionStorage as O, type Permission as P, type QueryParam as Q, type Result as R, type ScrollOptions as S, type TaskId as T, type Uuid as U, confirm as V, customEffect as W, download as X, fireEvent as Y, generateUuid as Z, getLocalStorageItem as _, type EventActions as a, type Element as a$, getNotificationPermission as a0, getRandom as a1, getSessionStorageItem as a2, getState as a3, getTime as a4, go as a5, isEffect as a6, log as a7, makeEffects as a8, makeHttpRequest as a9, traverse as aA, updateState as aB, writeClipboard as aC, type A as aD, type Abbr as aE, type Address as aF, type Article as aG, type Aside as aH, type AttrArg as aI, type AttrOrNodeIdArgs as aJ, type B as aK, type BlockElement as aL, type Blockquote as aM, type Br as aN, type Button as aO, type ButtonContent as aP, type ChangeData as aQ, type Circle as aR, type Cite as aS, type Code as aT, type ComponentElement as aU, type CustomElement as aV, type Dd as aW, type Details as aX, type Div as aY, type Dl as aZ, type Dt as a_, mapEvent as aa, mapState as ab, noop as ac, openDatabase as ad, postBroadcastMessage as ae, product as af, prompt as ag, pure as ah, pushState as ai, readClipboard as aj, removeLocalStorageItem as ak, removeSessionStorageItem as al, replaceState as am, requestNotificationPermission as an, resultT as ao, runDbTransaction as ap, scheduleTask as aq, scrollElement as ar, scrollWindow as as, setAppBadge as at, setDocumentTitle as au, setLocalStorageItem as av, setSessionStorageItem as aw, setTimeout as ax, subscribeToBroadcastChannel as ay, taskId as az, type HttpResponse as b, type Textarea as b$, type Ellipse as b0, type Em as b1, type EventListenerResult as b2, type EventOptions as b3, type Fieldset as b4, type Figcaption as b5, type Figure as b6, type FlowContent as b7, type Footer as b8, type Form as b9, type Option as bA, type P as bB, type Path as bC, type PhrasingContent as bD, type Polygon as bE, type Polyline as bF, type Pre as bG, type Prop as bH, type Q as bI, type Rect as bJ, type ReplacedElement as bK, type S as bL, type ScrollData as bM, type Section as bN, type Select as bO, type Small as bP, type Span as bQ, type Strong as bR, type Sub as bS, type Summary as bT, type Sup as bU, type Svg as bV, type SvgGraphicElement as bW, type Table as bX, type Tbody as bY, type Td as bZ, type TextState as b_, type H1 as ba, type H2 as bb, type H3 as bc, type H4 as bd, type H5 as be, type H6 as bf, type Header as bg, type Hr as bh, type I as bi, type Image as bj, type Img as bk, type InlineElement as bl, type Input as bm, type Kbd as bn, type KeyData as bo, type Label as bp, type Li as bq, type Line as br, type Main as bs, type Mark as bt, type MouseMoveData as bu, type Nav as bv, type NodeId as bw, type NonTextNode as bx, type NonVoidElement as by, type Ol as bz, type RequestError as c, type Tfoot as c0, type Th as c1, type Thead as c2, type Time as c3, type TouchData as c4, type Tr as c5, type U as c6, type Ul as c7, type Use as c8, type View as c9, type VoidElement as ca, type WheelData as cb, attr as cc, component as cd, cssVars as ce, foldNode as cf, id as cg, makeDom as ch, nodeId as ci, preventDefault as cj, prop as ck, stopPropagation as cl, stopPropagationAndPreventDefault as cm, typeAttr as cn, type HttpError as d, type Node as e, ResponseBody as f, failure as g, type ClipboardError as h, isState as i, type DecodingError as j, type DownloadInput as k, type Fragment as l, manageApplication as m, type Headers as n, type Path$1 as o, permission as p, ResultTransformer as q, type Return as r, success as s, toComponent as t, uuidFromString as u, type ScrollElementError as v, type StorageTarget as w, type Suspend as x, alert as y, async as z };
package/dist/index.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- export { D as Dimensions, P as Permission, U as Uuid, i as isState, m as manageApplication, p as permission, t as toComponent, u as uuidFromString } from './index-fpCmXVEu.js';
1
+ export { D as Dimensions, P as Permission, U as Uuid, i as isState, m as manageApplication, p as permission, t as toComponent, u as uuidFromString } from './index-DeEjNrg-.js';
2
2
  import './db/index.js';
package/dist/index.js CHANGED
@@ -4,9 +4,9 @@ import {
4
4
  permission,
5
5
  toComponent,
6
6
  uuidFromString
7
- } from "./chunk-DZAR6PTR.js";
8
- import "./chunk-NSWOTCDU.js";
9
- import "./chunk-KNHJPAIU.js";
7
+ } from "./chunk-BDTTV33M.js";
8
+ import "./chunk-EKBLRHWK.js";
9
+ import "./chunk-OSIRHKDB.js";
10
10
  import "./chunk-XICUXW4T.js";
11
11
  import "./chunk-PKBMQBKP.js";
12
12
  export {
package/dist/router.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { I as InternalLocation, E as Effect, a as EventActions } from './index-fpCmXVEu.js';
1
+ import { I as InternalLocation, E as Effect, a as EventActions } from './index-DeEjNrg-.js';
2
2
  import './db/index.js';
3
3
 
4
4
  /** Named path-segment parameters extracted from a matched route. */
package/dist/router.js CHANGED
@@ -2,7 +2,7 @@ import {
2
2
  async,
3
3
  parseInternalLocation,
4
4
  pushState
5
- } from "./chunk-KNHJPAIU.js";
5
+ } from "./chunk-OSIRHKDB.js";
6
6
  import "./chunk-PKBMQBKP.js";
7
7
 
8
8
  // src/router.ts
package/dist/testing.d.ts CHANGED
@@ -1,4 +1,5 @@
1
- import { A as Attr, H as HttpRequest, R as Result, b as HttpResponse, c as RequestError, d as HttpError, I as InternalLocation, S as ScrollOptions, N as NodeGroup, e as Node, E as Effect, C as Component } from './index-fpCmXVEu.js';
1
+ import { A as Attr, H as HttpRequest, R as Result, b as HttpResponse, c as RequestError, d as HttpError, I as InternalLocation, S as ScrollOptions, N as NodeGroup, e as Node, E as Effect, C as Component } from './index-DeEjNrg-.js';
2
+ export { f as ResponseBody, g as failure, s as success } from './index-DeEjNrg-.js';
2
3
  import { KeyPath, JsonValue, DbName, ObjectStore } from './db/index.js';
3
4
 
4
5
  type NonEmptyArray<A> = [A, ...A[]];
@@ -251,4 +252,4 @@ type OneOrMore = {
251
252
  declare function one(selector: string): OneOrMore;
252
253
  type QuerySelector = ExactlyOne | OneOrMore | ZeroOrMore | ZeroOrOne;
253
254
 
254
- export { type AdvanceTime, type AppBadgeOperation, type BroadcastSentRecord, type ClearAppBadge, type Click, type ConfirmInteraction, type DbStoreSnapshot, type DomElement, type DomNode, type DownloadRecord, type ExactlyOne, type FireCustomEvent, HttpError, type HttpHandler, type HttpInteraction, HttpRequest, HttpResponse, type Interaction, InternalLocation, type NonEmptyArray, type OneOrMore, type PromptInteraction, type QuerySelector, type ReceiveBroadcast, RequestError, type SetAppBadge, type Submit, type TestConfig, type TestData, TestDatabaseData, type TestInput, type TestableComponent, type TestableDom, type TextInput, type ZeroOrMore, type ZeroOrOne, advanceTime, appBadgeCount, attr, clearAppBadge, click, defaultTestConfig, fireCustomEvent, newTestData, one, receiveBroadcast, setAppBadge, submit, testApplication, testComponent, textInput };
255
+ export { type AdvanceTime, type AppBadgeOperation, type BroadcastSentRecord, type ClearAppBadge, type Click, type ConfirmInteraction, type DbStoreSnapshot, type DomElement, type DomNode, type DownloadRecord, type ExactlyOne, type FireCustomEvent, HttpError, type HttpHandler, type HttpInteraction, HttpRequest, HttpResponse, type Interaction, InternalLocation, type NonEmptyArray, type OneOrMore, type PromptInteraction, type QuerySelector, type ReceiveBroadcast, RequestError, Result, type SetAppBadge, type Submit, type TestConfig, type TestData, TestDatabaseData, type TestInput, type TestableComponent, type TestableDom, type TextInput, type ZeroOrMore, type ZeroOrOne, advanceTime, appBadgeCount, attr, clearAppBadge, click, defaultTestConfig, fireCustomEvent, newTestData, one, receiveBroadcast, setAppBadge, submit, testApplication, testComponent, textInput };
package/dist/testing.js CHANGED
@@ -15,12 +15,17 @@ import {
15
15
  testApplication,
16
16
  testComponent,
17
17
  textInput
18
- } from "./chunk-DZAR6PTR.js";
19
- import "./chunk-NSWOTCDU.js";
20
- import "./chunk-KNHJPAIU.js";
18
+ } from "./chunk-BDTTV33M.js";
19
+ import "./chunk-EKBLRHWK.js";
20
+ import {
21
+ ResponseBody,
22
+ failure,
23
+ success
24
+ } from "./chunk-OSIRHKDB.js";
21
25
  import "./chunk-XICUXW4T.js";
22
26
  import "./chunk-PKBMQBKP.js";
23
27
  export {
28
+ ResponseBody,
24
29
  TestDatabaseData,
25
30
  advanceTime,
26
31
  appBadgeCount,
@@ -28,12 +33,14 @@ export {
28
33
  clearAppBadge,
29
34
  click,
30
35
  defaultTestConfig,
36
+ failure,
31
37
  fireCustomEvent,
32
38
  newTestData,
33
39
  one,
34
40
  receiveBroadcast,
35
41
  setAppBadge,
36
42
  submit,
43
+ success,
37
44
  testApplication,
38
45
  testComponent,
39
46
  textInput
@@ -1,4 +1,4 @@
1
- import { C as Component } from './index-fpCmXVEu.js';
1
+ import { C as Component } from './index-DeEjNrg-.js';
2
2
  import './db/index.js';
3
3
 
4
4
  /** Options for `defineWebComponent`. */
@@ -2,9 +2,9 @@ import {
2
2
  ComponentManager,
3
3
  domInterpreter,
4
4
  realStyleRegistry
5
- } from "./chunk-DZAR6PTR.js";
6
- import "./chunk-NSWOTCDU.js";
7
- import "./chunk-KNHJPAIU.js";
5
+ } from "./chunk-BDTTV33M.js";
6
+ import "./chunk-EKBLRHWK.js";
7
+ import "./chunk-OSIRHKDB.js";
8
8
  import "./chunk-XICUXW4T.js";
9
9
  import {
10
10
  __publicField
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ctrl-fx",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "description": "A no-dependency, purely functional TypeScript framework for building web applications",
5
5
  "type": "module",
6
6
  "license": "Apache-2.0",