foldkit 0.97.0 → 0.97.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.
@@ -13,7 +13,11 @@ type Hot = NonNullable<ImportMeta['hot']>;
13
13
  *
14
14
  * `dispatch` enqueues a Message into the runtime's message queue; the bridge
15
15
  * uses it to fulfill `RequestDispatchMessage` after decoding the payload
16
- * against `maybeMessageSchema`. When `maybeMessageSchema` is `None`, dispatch
16
+ * against a JSON-canonical derivation of `maybeMessageSchema` (via
17
+ * `Schema.toCodecJson`). The derivation reconstructs runtime values like
18
+ * `Option`, `Date`, `Map`, and `Set` from their JSON-tagged shapes, so
19
+ * application Message Schemas using stdlib types Just Work over dispatch
20
+ * without author-side changes. When `maybeMessageSchema` is `None`, dispatch
17
21
  * requests are rejected with an informative error.
18
22
  *
19
23
  * Production-safe: callers must check `import.meta.hot` is defined before
@@ -1 +1 @@
1
- {"version":3,"file":"webSocketBridge.d.ts","sourceRoot":"","sources":["../../src/devTools/webSocketBridge.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,MAAM,EAIN,MAAM,EAEN,MAAM,IAAI,CAAC,EAGZ,MAAM,QAAQ,CAAA;AA+Bf,OAAO,EAAE,KAAK,aAAa,EAAc,MAAM,YAAY,CAAA;AAQ3D,KAAK,GAAG,GAAG,WAAW,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,CAAA;AAczC;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,oBAAoB,GAC/B,OAAO,aAAa,EACpB,KAAK,GAAG,EACR,UAAU,CAAC,OAAO,EAAE,OAAO,KAAK,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,EACnD,oBAAoB,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,KACnD,MAAM,CAAC,MAAM,CAAC,IAAI,CA+EjB,CAAA"}
1
+ {"version":3,"file":"webSocketBridge.d.ts","sourceRoot":"","sources":["../../src/devTools/webSocketBridge.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,MAAM,EAIN,MAAM,EAEN,MAAM,IAAI,CAAC,EAGZ,MAAM,QAAQ,CAAA;AA+Bf,OAAO,EAAE,KAAK,aAAa,EAAc,MAAM,YAAY,CAAA;AAQ3D,KAAK,GAAG,GAAG,WAAW,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,CAAA;AAczC;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,eAAO,MAAM,oBAAoB,GAC/B,OAAO,aAAa,EACpB,KAAK,GAAG,EACR,UAAU,CAAC,OAAO,EAAE,OAAO,KAAK,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,EACnD,oBAAoB,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,KACnD,MAAM,CAAC,MAAM,CAAC,IAAI,CAiFjB,CAAA"}
@@ -21,7 +21,11 @@ const currentAbsoluteIndex = (entriesLength, startIndex) => (entriesLength === 0
21
21
  *
22
22
  * `dispatch` enqueues a Message into the runtime's message queue; the bridge
23
23
  * uses it to fulfill `RequestDispatchMessage` after decoding the payload
24
- * against `maybeMessageSchema`. When `maybeMessageSchema` is `None`, dispatch
24
+ * against a JSON-canonical derivation of `maybeMessageSchema` (via
25
+ * `Schema.toCodecJson`). The derivation reconstructs runtime values like
26
+ * `Option`, `Date`, `Map`, and `Set` from their JSON-tagged shapes, so
27
+ * application Message Schemas using stdlib types Just Work over dispatch
28
+ * without author-side changes. When `maybeMessageSchema` is `None`, dispatch
25
29
  * requests are rejected with an informative error.
26
30
  *
27
31
  * Production-safe: callers must check `import.meta.hot` is defined before
@@ -30,6 +34,7 @@ const currentAbsoluteIndex = (entriesLength, startIndex) => (entriesLength === 0
30
34
  export const startWebSocketBridge = (store, hot, dispatch, maybeMessageSchema) => Effect.gen(function* () {
31
35
  const connectionId = generateConnectionId();
32
36
  const capturedContext = yield* Effect.context();
37
+ const maybeDispatchSchema = Option.map(maybeMessageSchema, S.toCodecJson);
33
38
  const encodeEventFrame = S.encodeUnknownSync(EventFrame);
34
39
  const encodeResponseFrame = S.encodeUnknownSync(ResponseFrame);
35
40
  const sendEvent = (event) => {
@@ -49,7 +54,7 @@ export const startWebSocketBridge = (store, hot, dispatch, maybeMessageSchema) =
49
54
  }),
50
55
  }));
51
56
  const handleRequest = (id, request) => Effect.gen(function* () {
52
- const response = yield* dispatchRequest(store, dispatch, maybeMessageSchema, request);
57
+ const response = yield* dispatchRequest(store, dispatch, maybeDispatchSchema, request);
53
58
  sendResponse(id, response);
54
59
  });
55
60
  const handleRequestFrame = (frame) => {
@@ -94,7 +99,7 @@ const readModelResponse = (store, index, maybePath, expand) => Effect.gen(functi
94
99
  }).pipe(Effect.catchCause(cause => Effect.succeed(ResponseError({
95
100
  reason: `Failed to read Model at index ${index}: ${Cause.pretty(cause)}`,
96
101
  }))));
97
- const dispatchRequest = (store, dispatch, maybeMessageSchema, request) => Match.value(request).pipe(Match.tagsExhaustive({
102
+ const dispatchRequest = (store, dispatch, maybeDispatchSchema, request) => Match.value(request).pipe(Match.tagsExhaustive({
98
103
  RequestGetModel: ({ maybePath, expand }) => Effect.gen(function* () {
99
104
  const state = yield* SubscriptionRef.get(store.stateRef);
100
105
  const index = currentAbsoluteIndex(state.entries.length, state.startIndex);
@@ -147,12 +152,12 @@ const dispatchRequest = (store, dispatch, maybeMessageSchema, request) => Match.
147
152
  }).pipe(Effect.catchCause(cause => Effect.succeed(ResponseError({
148
153
  reason: `Failed to resume: ${Cause.pretty(cause)}`,
149
154
  })))),
150
- RequestDispatchMessage: ({ message }) => Option.match(maybeMessageSchema, {
155
+ RequestDispatchMessage: ({ message }) => Option.match(maybeDispatchSchema, {
151
156
  onNone: () => Effect.succeed(ResponseError({
152
157
  reason: 'Cannot dispatch: DevToolsConfig.Message not configured. Pass your Message Schema to enable dispatch.',
153
158
  })),
154
- onSome: messageSchema => Effect.gen(function* () {
155
- const decodedMessage = yield* S.decodeUnknownEffect(messageSchema)(message);
159
+ onSome: dispatchSchema => Effect.gen(function* () {
160
+ const decodedMessage = yield* S.decodeUnknownEffect(dispatchSchema)(message);
156
161
  const stateBefore = yield* SubscriptionRef.get(store.stateRef);
157
162
  const acceptedAtIndex = stateBefore.startIndex + stateBefore.entries.length;
158
163
  yield* dispatch(decodedMessage);
@@ -4,11 +4,22 @@ import type { Html } from './index.js';
4
4
  * equal (`===`) to the previous call, the cached VNode is returned without
5
5
  * re-running the view function. Snabbdom's `patchVnode` short-circuits when
6
6
  * it sees the same VNode reference, so both VNode construction and subtree
7
- * diffing are skipped. */
7
+ * diffing are skipped.
8
+ *
9
+ * The cached VNode must be rendered at a single position in the tree.
10
+ * Snabbdom tracks the real DOM through each VNode's mutable `.elm` field
11
+ * and assumes one VNode per position. Rendering the same cached VNode at
12
+ * two positions causes patches to collide and can duplicate or misplace
13
+ * DOM nodes. If the same content needs to appear in multiple positions,
14
+ * create one slot per position. */
8
15
  export declare const createLazy: () => (<Args extends ReadonlyArray<unknown>>(fn: (...args: Args) => Html, args: Args) => Html);
9
16
  /** Creates a keyed memoization map for view functions rendered in a loop. Each
10
17
  * key gets its own independent cache slot. On each render, only entries whose
11
18
  * function reference, dispatch context, or arguments have changed by reference
12
- * are recomputed. */
19
+ * are recomputed.
20
+ *
21
+ * Like `createLazy`, each key's cached VNode must be rendered at a single
22
+ * position in the tree. If the same item needs to appear in multiple
23
+ * positions, create one keyed lazy per position. */
13
24
  export declare const createKeyedLazy: () => (<Args extends ReadonlyArray<unknown>>(key: string, fn: (...args: Args) => Html, args: Args) => Html);
14
25
  //# sourceMappingURL=lazy.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"lazy.d.ts","sourceRoot":"","sources":["../../src/html/lazy.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAA;AAsCtC;;;;;2BAK2B;AAC3B,eAAO,MAAM,UAAU,QAAO,CAAC,CAAC,IAAI,SAAS,aAAa,CAAC,OAAO,CAAC,EACjE,EAAE,EAAE,CAAC,GAAG,IAAI,EAAE,IAAI,KAAK,IAAI,EAC3B,IAAI,EAAE,IAAI,KACP,IAAI,CAUR,CAAA;AAED;;;sBAGsB;AACtB,eAAO,MAAM,eAAe,QAAO,CAAC,CAAC,IAAI,SAAS,aAAa,CAAC,OAAO,CAAC,EACtE,GAAG,EAAE,MAAM,EACX,EAAE,EAAE,CAAC,GAAG,IAAI,EAAE,IAAI,KAAK,IAAI,EAC3B,IAAI,EAAE,IAAI,KACP,IAAI,CAWR,CAAA"}
1
+ {"version":3,"file":"lazy.d.ts","sourceRoot":"","sources":["../../src/html/lazy.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAA;AAsCtC;;;;;;;;;;;;oCAYoC;AACpC,eAAO,MAAM,UAAU,QAAO,CAAC,CAAC,IAAI,SAAS,aAAa,CAAC,OAAO,CAAC,EACjE,EAAE,EAAE,CAAC,GAAG,IAAI,EAAE,IAAI,KAAK,IAAI,EAC3B,IAAI,EAAE,IAAI,KACP,IAAI,CAUR,CAAA;AAED;;;;;;;qDAOqD;AACrD,eAAO,MAAM,eAAe,QAAO,CAAC,CAAC,IAAI,SAAS,aAAa,CAAC,OAAO,CAAC,EACtE,GAAG,EAAE,MAAM,EACX,EAAE,EAAE,CAAC,GAAG,IAAI,EAAE,IAAI,KAAK,IAAI,EAC3B,IAAI,EAAE,IAAI,KACP,IAAI,CAWR,CAAA"}
package/dist/html/lazy.js CHANGED
@@ -19,7 +19,14 @@ const resolveOrCache = (previousEntry, fn, args, onCache) => Effect.gen(function
19
19
  * equal (`===`) to the previous call, the cached VNode is returned without
20
20
  * re-running the view function. Snabbdom's `patchVnode` short-circuits when
21
21
  * it sees the same VNode reference, so both VNode construction and subtree
22
- * diffing are skipped. */
22
+ * diffing are skipped.
23
+ *
24
+ * The cached VNode must be rendered at a single position in the tree.
25
+ * Snabbdom tracks the real DOM through each VNode's mutable `.elm` field
26
+ * and assumes one VNode per position. Rendering the same cached VNode at
27
+ * two positions causes patches to collide and can duplicate or misplace
28
+ * DOM nodes. If the same content needs to appear in multiple positions,
29
+ * create one slot per position. */
23
30
  export const createLazy = () => {
24
31
  let cached;
25
32
  return (fn, args) => resolveOrCache(cached, fn, args, entry => {
@@ -29,7 +36,11 @@ export const createLazy = () => {
29
36
  /** Creates a keyed memoization map for view functions rendered in a loop. Each
30
37
  * key gets its own independent cache slot. On each render, only entries whose
31
38
  * function reference, dispatch context, or arguments have changed by reference
32
- * are recomputed. */
39
+ * are recomputed.
40
+ *
41
+ * Like `createLazy`, each key's cached VNode must be rendered at a single
42
+ * position in the tree. If the same item needs to appear in multiple
43
+ * positions, create one keyed lazy per position. */
33
44
  export const createKeyedLazy = () => {
34
45
  const cache = new Map();
35
46
  return (key, fn, args) => resolveOrCache(cache.get(key), fn, args, entry => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "foldkit",
3
- "version": "0.97.0",
3
+ "version": "0.97.2",
4
4
  "description": "A TypeScript frontend framework, built on Effect and architected like Elm",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",