foldkit 0.132.0 → 0.134.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 (90) hide show
  1. package/README.md +59 -108
  2. package/dist/canvas/view.d.ts +18 -11
  3. package/dist/canvas/view.d.ts.map +1 -1
  4. package/dist/canvas/view.js +18 -11
  5. package/dist/customElement/index.d.ts +9 -6
  6. package/dist/customElement/index.d.ts.map +1 -1
  7. package/dist/customElement/index.js +14 -3
  8. package/dist/devTools/protocol.d.ts +19 -1
  9. package/dist/devTools/protocol.d.ts.map +1 -1
  10. package/dist/devTools/protocol.js +13 -1
  11. package/dist/devTools/public.d.ts +1 -1
  12. package/dist/devTools/public.d.ts.map +1 -1
  13. package/dist/devTools/public.js +1 -1
  14. package/dist/devTools/store.d.ts +6 -0
  15. package/dist/devTools/store.d.ts.map +1 -1
  16. package/dist/devTools/store.js +7 -1
  17. package/dist/devTools/webSocketBridge.d.ts +7 -0
  18. package/dist/devTools/webSocketBridge.d.ts.map +1 -1
  19. package/dist/devTools/webSocketBridge.js +36 -8
  20. package/dist/html/boundary.d.ts.map +1 -1
  21. package/dist/html/boundary.js +48 -2
  22. package/dist/html/index.d.ts +682 -1643
  23. package/dist/html/index.d.ts.map +1 -1
  24. package/dist/html/index.js +56 -16
  25. package/dist/html/public.d.ts +2 -2
  26. package/dist/html/public.d.ts.map +1 -1
  27. package/dist/html/public.js +1 -1
  28. package/dist/html/runtimeSingleton.d.ts +1 -1
  29. package/dist/html/runtimeSingleton.d.ts.map +1 -1
  30. package/dist/html/runtimeSingleton.js +1 -1
  31. package/dist/html/submodel.d.ts +51 -19
  32. package/dist/html/submodel.d.ts.map +1 -1
  33. package/dist/html/submodel.js +37 -13
  34. package/dist/route/transition.d.ts +35 -29
  35. package/dist/route/transition.d.ts.map +1 -1
  36. package/dist/route/transition.js +36 -30
  37. package/dist/runtime/crashUI.d.ts.map +1 -1
  38. package/dist/runtime/crashUI.js +29 -30
  39. package/dist/runtime/runtime.d.ts +9 -6
  40. package/dist/runtime/runtime.d.ts.map +1 -1
  41. package/dist/runtime/runtime.js +25 -8
  42. package/dist/test/apps/attributes.d.ts +2 -2
  43. package/dist/test/apps/attributes.d.ts.map +1 -1
  44. package/dist/test/apps/attributes.js +1 -3
  45. package/dist/test/apps/bubbling.d.ts +2 -2
  46. package/dist/test/apps/bubbling.d.ts.map +1 -1
  47. package/dist/test/apps/bubbling.js +1 -3
  48. package/dist/test/apps/counter.d.ts +2 -2
  49. package/dist/test/apps/counter.d.ts.map +1 -1
  50. package/dist/test/apps/counter.js +1 -3
  51. package/dist/test/apps/crashOnRender.d.ts +2 -2
  52. package/dist/test/apps/crashOnRender.d.ts.map +1 -1
  53. package/dist/test/apps/crashOnRender.js +1 -3
  54. package/dist/test/apps/drafts.d.ts +2 -2
  55. package/dist/test/apps/drafts.d.ts.map +1 -1
  56. package/dist/test/apps/drafts.js +1 -3
  57. package/dist/test/apps/fileUpload.d.ts +2 -2
  58. package/dist/test/apps/fileUpload.d.ts.map +1 -1
  59. package/dist/test/apps/fileUpload.js +1 -3
  60. package/dist/test/apps/interactions.d.ts +2 -2
  61. package/dist/test/apps/interactions.d.ts.map +1 -1
  62. package/dist/test/apps/interactions.js +1 -3
  63. package/dist/test/apps/keypress.d.ts +2 -2
  64. package/dist/test/apps/keypress.d.ts.map +1 -1
  65. package/dist/test/apps/keypress.js +1 -3
  66. package/dist/test/apps/login.d.ts +2 -2
  67. package/dist/test/apps/login.d.ts.map +1 -1
  68. package/dist/test/apps/login.js +1 -3
  69. package/dist/test/apps/logoutButton.d.ts +2 -2
  70. package/dist/test/apps/logoutButton.d.ts.map +1 -1
  71. package/dist/test/apps/logoutButton.js +1 -3
  72. package/dist/test/apps/mountPanel.d.ts +4 -4
  73. package/dist/test/apps/mountPanel.d.ts.map +1 -1
  74. package/dist/test/apps/mountPanel.js +3 -7
  75. package/dist/test/apps/multiRole.d.ts +2 -2
  76. package/dist/test/apps/multiRole.d.ts.map +1 -1
  77. package/dist/test/apps/multiRole.js +1 -3
  78. package/dist/test/apps/pointer.d.ts +2 -2
  79. package/dist/test/apps/pointer.d.ts.map +1 -1
  80. package/dist/test/apps/pointer.js +1 -3
  81. package/dist/test/apps/resumeUpload.d.ts +2 -2
  82. package/dist/test/apps/resumeUpload.d.ts.map +1 -1
  83. package/dist/test/apps/resumeUpload.js +3 -6
  84. package/dist/test/apps/uploads.d.ts +2 -2
  85. package/dist/test/apps/uploads.d.ts.map +1 -1
  86. package/dist/test/apps/uploads.js +1 -3
  87. package/dist/test/scene.d.ts +3 -3
  88. package/dist/test/scene.d.ts.map +1 -1
  89. package/dist/test/scene.js +2 -2
  90. package/package.json +6 -6
@@ -45,6 +45,12 @@ export type Bridge = Readonly<{
45
45
  * when no Messages have been recorded yet.
46
46
  */
47
47
  export declare const latestEntryIndex: (state: StoreState) => number;
48
+ /**
49
+ * The absolute index the next recorded entry will land at. `recordMessage`
50
+ * assigns indices from this formula, so dispatch predictions derived from it
51
+ * match where entries are actually recorded.
52
+ */
53
+ export declare const nextEntryIndex: (state: StoreState) => number;
48
54
  /**
49
55
  * Options for `createDevToolsStore`.
50
56
  *
@@ -1 +1 @@
1
- {"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/devTools/store.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/devTools/store.ts"],"names":[],"mappings":"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"}
@@ -91,6 +91,12 @@ export const latestEntryIndex = (state) => Array.match(state.entries, {
91
91
  onEmpty: () => INIT_INDEX,
92
92
  onNonEmpty: entries => state.startIndex + entries.length - 1,
93
93
  });
94
+ /**
95
+ * The absolute index the next recorded entry will land at. `recordMessage`
96
+ * assigns indices from this formula, so dispatch predictions derived from it
97
+ * match where entries are actually recorded.
98
+ */
99
+ export const nextEntryIndex = (state) => state.startIndex + state.entries.length;
94
100
  export const createDevToolsStore = (bridge, options = {}) => Effect.gen(function* () {
95
101
  const maxEntries = options.maxEntries ?? DEFAULT_MAX_ENTRIES;
96
102
  const keyframeInterval = options.keyframeInterval ?? DEFAULT_KEYFRAME_INTERVAL;
@@ -135,7 +141,7 @@ export const createDevToolsStore = (bridge, options = {}) => Effect.gen(function
135
141
  maybeLatestModel: () => Option.some(model),
136
142
  }));
137
143
  const recordMessage = (message, modelBeforeUpdate, modelAfterUpdate, commands, isModelChanged) => SubscriptionRef.update(stateRef, state => {
138
- const absoluteIndex = state.startIndex + state.entries.length;
144
+ const absoluteIndex = nextEntryIndex(state);
139
145
  const diff = isModelChanged
140
146
  ? computeDiff(modelBeforeUpdate, modelAfterUpdate)
141
147
  : emptyDiff;
@@ -1,4 +1,5 @@
1
1
  import { Effect, Option, Schema as S, Scope } from 'effect';
2
+ import { type Request, type Response } from './protocol.js';
2
3
  import { type DevToolsStore } from './store.js';
3
4
  type Hot = NonNullable<ImportMeta['hot']>;
4
5
  /**
@@ -33,5 +34,11 @@ type Hot = NonNullable<ImportMeta['hot']>;
33
34
  * invoking this. The function assumes a live HMR connection.
34
35
  */
35
36
  export declare const startWebSocketBridge: (store: DevToolsStore, hot: Hot, dispatch: (message: unknown) => Effect.Effect<void>, maybeMessageSchema: Option.Option<S.Codec<any, any>>) => Effect.Effect<void, never, Scope.Scope>;
37
+ /**
38
+ * Fulfill one bridge Request against the DevTools store. `startWebSocketBridge`
39
+ * wires this to the HMR request channel; exported so tests can drive request
40
+ * handling without a live HMR connection.
41
+ */
42
+ export declare const dispatchRequest: (store: DevToolsStore, dispatch: (message: unknown) => Effect.Effect<void>, maybeDispatchSchema: Option.Option<S.Codec<any, any>>, maybeJsonSchemaDocument: Option.Option<unknown>, request: Request) => Effect.Effect<Response>;
36
43
  export {};
37
44
  //# sourceMappingURL=webSocketBridge.d.ts.map
@@ -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,EACX,KAAK,EAGN,MAAM,QAAQ,CAAA;AAwDf,OAAO,EACL,KAAK,aAAa,EAInB,MAAM,YAAY,CAAA;AAQnB,KAAK,GAAG,GAAG,WAAW,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,CAAA;AAuBzC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;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,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,CAkGrC,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,EACX,KAAK,EAGN,MAAM,QAAQ,CAAA;AAcf,OAAO,EAYL,KAAK,OAAO,EAEZ,KAAK,QAAQ,EAiBd,MAAM,eAAe,CAAA;AAatB,OAAO,EACL,KAAK,aAAa,EAKnB,MAAM,YAAY,CAAA;AAQnB,KAAK,GAAG,GAAG,WAAW,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,CAAA;AAuBzC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;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,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,CAkGrC,CAAA;AAsIJ;;;;GAIG;AACH,eAAO,MAAM,eAAe,GAC1B,OAAO,aAAa,EACpB,UAAU,CAAC,OAAO,EAAE,OAAO,KAAK,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,EACnD,qBAAqB,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,EACrD,yBAAyB,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,EAC/C,SAAS,OAAO,KACf,MAAM,CAAC,MAAM,CAAC,QAAQ,CA4UtB,CAAA"}
@@ -1,10 +1,10 @@
1
1
  import { Array, Cause, Effect, Exit, HashMap, Match, Option, Order, Schema as S, SubscriptionRef, pipe, } from 'effect';
2
2
  import { OptionExt } from '../effectExtensions/index.js';
3
3
  import { collectMatchingEntries, countEntriesByTag, findUnanchoredPattern, formatIndexNotReadable, isIndexReadable, matchesAnyPathPattern, pageMatchingEntries, pathOrder, readSummarizedValueAt, } from './historyQuery.js';
4
- import { DiffValueAbsent, DiffValuePresent, EventConnected, EventDisconnected, EventFrame, KeyframeInfo, MessageSchemaDocumentResult, MessageSchemaIndexResult, RequestFrame, ResponseDispatched, ResponseError, ResponseFrame, ResponseInit, ResponseKeyframes, ResponseMessage, ResponseMessageCounts, ResponseMessageSchema, ResponseMessages, ResponseModel, ResponseModelDiff, ResponseReplayed, ResponseResumed, ResponseRuntimeState, RuntimeInfo, } from './protocol.js';
4
+ import { DiffValueAbsent, DiffValuePresent, EventConnected, EventDisconnected, EventFrame, KeyframeInfo, MAX_DISPATCH_BATCH_SIZE, MessageSchemaDocumentResult, MessageSchemaIndexResult, RequestFrame, ResponseDispatched, ResponseDispatchedBatch, ResponseError, ResponseFrame, ResponseInit, ResponseKeyframes, ResponseMessage, ResponseMessageCounts, ResponseMessageSchema, ResponseMessages, ResponseModel, ResponseModelDiff, ResponseReplayed, ResponseResumed, ResponseRuntimeState, RuntimeInfo, } from './protocol.js';
5
5
  import { diagnoseVariantPath, indexMessageSchemaDocument, narrowToVariant, splitVariantPath, } from './schemaSummarize.js';
6
6
  import { toInspectableValue, toSerializedCommand, toSerializedEntry, toSerializedMount, } from './serialize.js';
7
- import { INIT_INDEX, computeDiff, latestEntryIndex, } from './store.js';
7
+ import { INIT_INDEX, computeDiff, latestEntryIndex, nextEntryIndex, } from './store.js';
8
8
  import { formatPathNotFound, resolvePath, summarizeValue, } from './summarize.js';
9
9
  const REQUEST_CHANNEL = 'foldkit:devTools:request';
10
10
  const RESPONSE_CHANNEL = 'foldkit:devTools:response';
@@ -175,7 +175,16 @@ const formatUnknownVariantError = (document, variantPath) => {
175
175
  },
176
176
  });
177
177
  };
178
- const dispatchRequest = (store, dispatch, maybeDispatchSchema, maybeJsonSchemaDocument, request) => Match.value(request).pipe(Match.tagsExhaustive({
178
+ const missingMessageSchemaResponse = ResponseError({
179
+ reason: 'Cannot dispatch: DevToolsConfig.Message not configured. Pass your Message Schema to enable dispatch.',
180
+ });
181
+ const formatInvalidMessageReason = (error, message) => `${error instanceof Error ? error.message : String(error)}\n\nReceived (typeof ${typeof message}): ${JSON.stringify(message)}`;
182
+ /**
183
+ * Fulfill one bridge Request against the DevTools store. `startWebSocketBridge`
184
+ * wires this to the HMR request channel; exported so tests can drive request
185
+ * handling without a live HMR connection.
186
+ */
187
+ export const dispatchRequest = (store, dispatch, maybeDispatchSchema, maybeJsonSchemaDocument, request) => Match.value(request).pipe(Match.tagsExhaustive({
179
188
  RequestGetModel: ({ maybePath, expand }) => Effect.gen(function* () {
180
189
  const state = yield* SubscriptionRef.get(store.stateRef);
181
190
  const index = latestEntryIndex(state);
@@ -297,19 +306,38 @@ const dispatchRequest = (store, dispatch, maybeDispatchSchema, maybeJsonSchemaDo
297
306
  reason: `Failed to resume: ${Cause.pretty(cause)}`,
298
307
  })))),
299
308
  RequestDispatchMessage: ({ message }) => Option.match(maybeDispatchSchema, {
300
- onNone: () => Effect.succeed(ResponseError({
301
- reason: 'Cannot dispatch: DevToolsConfig.Message not configured. Pass your Message Schema to enable dispatch.',
302
- })),
309
+ onNone: () => Effect.succeed(missingMessageSchemaResponse),
303
310
  onSome: dispatchSchema => Effect.gen(function* () {
304
311
  const decodedMessage = yield* S.decodeUnknownEffect(dispatchSchema)(message);
305
312
  const stateBefore = yield* SubscriptionRef.get(store.stateRef);
306
- const acceptedAtIndex = stateBefore.startIndex + stateBefore.entries.length;
313
+ const acceptedAtIndex = nextEntryIndex(stateBefore);
307
314
  yield* dispatch(decodedMessage);
308
315
  return ResponseDispatched({ acceptedAtIndex });
309
316
  }).pipe(Effect.catch(error => Effect.succeed(ResponseError({
310
- reason: `Invalid Message: ${error instanceof Error ? error.message : String(error)}\n\nReceived (typeof ${typeof message}): ${JSON.stringify(message)}`,
317
+ reason: `Invalid Message: ${formatInvalidMessageReason(error, message)}`,
311
318
  })))),
312
319
  }),
320
+ RequestDispatchMessages: ({ messages }) => {
321
+ if (messages.length > MAX_DISPATCH_BATCH_SIZE) {
322
+ return Effect.succeed(ResponseError({
323
+ reason: `Batch too large: ${messages.length} Messages exceeds the limit of ${MAX_DISPATCH_BATCH_SIZE}. No Messages from the batch were dispatched.`,
324
+ }));
325
+ }
326
+ return Option.match(maybeDispatchSchema, {
327
+ onNone: () => Effect.succeed(missingMessageSchemaResponse),
328
+ onSome: dispatchSchema => Effect.gen(function* () {
329
+ const decodeMessage = S.decodeUnknownEffect(dispatchSchema);
330
+ const decodedMessages = yield* Effect.forEach(messages, (message, position) => Effect.mapError(decodeMessage(message), error => new Error(`Invalid Message at zero-based batch position ${position}: ${formatInvalidMessageReason(error, message)}\n\nNo Messages from the batch were dispatched.`)));
331
+ const stateBefore = yield* SubscriptionRef.get(store.stateRef);
332
+ const firstAcceptedIndex = nextEntryIndex(stateBefore);
333
+ yield* Effect.forEach(decodedMessages, dispatch);
334
+ const acceptedAtIndices = Array.map(decodedMessages, (_decodedMessage, offset) => firstAcceptedIndex + offset);
335
+ return ResponseDispatchedBatch({ acceptedAtIndices });
336
+ }).pipe(Effect.catch(error => Effect.succeed(ResponseError({
337
+ reason: error instanceof Error ? error.message : String(error),
338
+ })))),
339
+ });
340
+ },
313
341
  RequestGetMessageSchema: ({ maybeVariantTag }) => Effect.succeed(buildMessageSchemaResponse(maybeJsonSchemaDocument, maybeVariantTag)),
314
342
  RequestListRuntimes: () => Effect.succeed(ResponseError({
315
343
  reason: 'RequestListRuntimes is plugin-handled and should not reach the runtime bridge',
@@ -1 +1 @@
1
- {"version":3,"file":"boundary.d.ts","sourceRoot":"","sources":["../../src/html/boundary.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAA;AAEzD,wDAAwD;AACxD,MAAM,MAAM,cAAc,GAAG,QAAQ,CAAC;IACpC,eAAe,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAAA;CAC/C,CAAC,CAAA;AAEF;;;;eAIe;AACf,MAAM,MAAM,UAAU,GAAG,MAAM,CAAA;AAI/B,eAAO,MAAM,aAAa,EAAE,UAAe,CAAA;AAE3C,eAAO,MAAM,eAAe,GAC1B,QAAQ,UAAU,EAClB,SAAS,MAAM,KACd,UAUF,CAAA;AAKD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;aAwCa;AACb,MAAM,MAAM,gBAAgB,GAAG;IAC7B,QAAQ,CAAC,KAAK,EAAE,GAAG,CAAC,UAAU,EAAE,cAAc,CAAC,CAAA;IAC/C,QAAQ,CAAC,kBAAkB,EAAE,OAAO,CAClC,YAAY,EACZ,GAAG,CAAC,UAAU,EAAE,YAAY,CAAC,CAC9B,CAAA;IACD,QAAQ,CAAC,cAAc,EAAE,GAAG,CAAC,UAAU,EAAE,MAAM,CAAC,CAAA;IAChD,QAAQ,CAAC,iBAAiB,EAAE,KAAK,CAAC,GAAG,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC,CAAA;IAI1D,QAAQ,CAAC,UAAU,EAAE,GAAG,CAAC,MAAM,CAAC,CAAA;CACjC,CAAA;AAED,eAAO,MAAM,sBAAsB,QAAO,gBAMxC,CAAA;AAqBF,eAAO,MAAM,oBAAoB,GAC/B,UAAU,gBAAgB,EAC1B,YAAY,UAAU,EACtB,YAAY,cAAc,KACzB,IA6BF,CAAA;AAED;;;;wCAIwC;AACxC,eAAO,MAAM,iBAAiB,GAC5B,UAAU,gBAAgB,KACzB,GAAG,CAAC,UAAU,EAAE,MAAM,CAIxB,CAAA;AAED;;yCAEyC;AACzC,eAAO,MAAM,eAAe,GAAI,UAAU,gBAAgB,KAAG,IAQ5D,CAAA;AAED;;;;;;;4CAO4C;AAC5C,eAAO,MAAM,kBAAkB,GAC7B,UAAU,gBAAgB,EAC1B,YAAY,WAAW,CAAC,UAAU,EAAE,MAAM,CAAC,KAC1C,IAWF,CAAA;AAED;;;;;;;;;gBASgB;AAChB,eAAO,MAAM,sBAAsB,GACjC,UAAU,gBAAgB,EAC1B,YAAY,UAAU,KACrB,IAEF,CAAA;AA8CD;;;;;;;;;;;;mFAYmF;AACnF,eAAO,MAAM,4BAA4B,GACvC,UAAU,gBAAgB,EAC1B,eAAe,YAAY,EAC3B,YAAY,UAAU,EACtB,SAAS,OAAO,KACf,CAAC,MAAM,IAAI,CAqBb,CAAA;AAED;;;;;;;8EAO8E;AAC9E,eAAO,MAAM,eAAe,GAC1B,UAAU,gBAAgB,EAC1B,YAAY,UAAU,KACrB,aAAa,CAAC,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAiB7C,CAAA;AAED,eAAO,MAAM,2BAA2B,GACtC,UAAU,gBAAgB,EAC1B,eAAe,YAAY,EAC3B,YAAY,UAAU,KACrB,YAkBF,CAAA;AAED;;;;;;;;;;iEAUiE;AACjE,eAAO,MAAM,WAAW,GAAI,UAAU,gBAAgB,KAAG,IAGxD,CAAA"}
1
+ {"version":3,"file":"boundary.d.ts","sourceRoot":"","sources":["../../src/html/boundary.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAA;AAEzD,wDAAwD;AACxD,MAAM,MAAM,cAAc,GAAG,QAAQ,CAAC;IACpC,eAAe,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAAA;CAC/C,CAAC,CAAA;AAEF;;;;eAIe;AACf,MAAM,MAAM,UAAU,GAAG,MAAM,CAAA;AAI/B,eAAO,MAAM,aAAa,EAAE,UAAe,CAAA;AAE3C,eAAO,MAAM,eAAe,GAC1B,QAAQ,UAAU,EAClB,SAAS,MAAM,KACd,UAUF,CAAA;AAKD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;aAwCa;AACb,MAAM,MAAM,gBAAgB,GAAG;IAC7B,QAAQ,CAAC,KAAK,EAAE,GAAG,CAAC,UAAU,EAAE,cAAc,CAAC,CAAA;IAC/C,QAAQ,CAAC,kBAAkB,EAAE,OAAO,CAClC,YAAY,EACZ,GAAG,CAAC,UAAU,EAAE,YAAY,CAAC,CAC9B,CAAA;IACD,QAAQ,CAAC,cAAc,EAAE,GAAG,CAAC,UAAU,EAAE,MAAM,CAAC,CAAA;IAChD,QAAQ,CAAC,iBAAiB,EAAE,KAAK,CAAC,GAAG,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC,CAAA;IAI1D,QAAQ,CAAC,UAAU,EAAE,GAAG,CAAC,MAAM,CAAC,CAAA;CACjC,CAAA;AAED,eAAO,MAAM,sBAAsB,QAAO,gBAMxC,CAAA;AAqBF,eAAO,MAAM,oBAAoB,GAC/B,UAAU,gBAAgB,EAC1B,YAAY,UAAU,EACtB,YAAY,cAAc,KACzB,IA6BF,CAAA;AAED;;;;wCAIwC;AACxC,eAAO,MAAM,iBAAiB,GAC5B,UAAU,gBAAgB,KACzB,GAAG,CAAC,UAAU,EAAE,MAAM,CAIxB,CAAA;AAED;;yCAEyC;AACzC,eAAO,MAAM,eAAe,GAAI,UAAU,gBAAgB,KAAG,IAQ5D,CAAA;AAED;;;;;;;4CAO4C;AAC5C,eAAO,MAAM,kBAAkB,GAC7B,UAAU,gBAAgB,EAC1B,YAAY,WAAW,CAAC,UAAU,EAAE,MAAM,CAAC,KAC1C,IAWF,CAAA;AAED;;;;;;;;;gBASgB;AAChB,eAAO,MAAM,sBAAsB,GACjC,UAAU,gBAAgB,EAC1B,YAAY,UAAU,KACrB,IAEF,CAAA;AAmGD;;;;;;;;;;;;mFAYmF;AACnF,eAAO,MAAM,4BAA4B,GACvC,UAAU,gBAAgB,EAC1B,eAAe,YAAY,EAC3B,YAAY,UAAU,EACtB,SAAS,OAAO,KACf,CAAC,MAAM,IAAI,CAqBb,CAAA;AAED;;;;;;;8EAO8E;AAC9E,eAAO,MAAM,eAAe,GAC1B,UAAU,gBAAgB,EAC1B,YAAY,UAAU,KACrB,aAAa,CAAC,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAiB7C,CAAA;AAED,eAAO,MAAM,2BAA2B,GACtC,UAAU,gBAAgB,EAC1B,eAAe,YAAY,EAC3B,YAAY,UAAU,KACrB,YAkBF,CAAA;AAED;;;;;;;;;;iEAUiE;AACjE,eAAO,MAAM,WAAW,GAAI,UAAU,gBAAgB,KAAG,IAGxD,CAAA"}
@@ -114,6 +114,52 @@ export const markSeenForLazyHit = (registry, trackedIds) => {
114
114
  export const deregisterBoundaryWrap = (registry, boundaryId) => {
115
115
  registry.wraps.delete(boundaryId);
116
116
  };
117
+ // NOTE: reading `_tag` can itself throw, through a getter or a Proxy trap. This
118
+ // runs while reporting another failure, so an escape here would replace the
119
+ // error being described with an unrelated one.
120
+ const describeMessage = (message) => {
121
+ try {
122
+ if (typeof message === 'object' && message !== null && '_tag' in message) {
123
+ const tag = Reflect.get(message, '_tag');
124
+ if (typeof tag === 'string') {
125
+ return `\`${tag}\``;
126
+ }
127
+ }
128
+ }
129
+ catch {
130
+ return 'the Message';
131
+ }
132
+ return 'the Message';
133
+ };
134
+ /** Applies one boundary's `toParentMessage`, translating a rejection into an
135
+ * error that names the cause.
136
+ *
137
+ * A wrapper Message is normally a Schema constructor, so handing it a Message
138
+ * outside the child's union throws a Schema error naming both shapes and
139
+ * nothing else. That error is accurate and nearly undiagnosable: it fires
140
+ * inside a DOM listener, the app keeps rendering, and reading it requires
141
+ * already knowing that a boundary sits between the handler and `update`. The
142
+ * overwhelmingly common cause is a shared view helper that built an app-level
143
+ * Message inside a Submodel's view, where the dispatcher is chosen by the
144
+ * current render frame rather than by the Message's type. */
145
+ const liftAcrossBoundary = (descriptor, boundaryId, message) => {
146
+ try {
147
+ return descriptor.toParentMessage(message);
148
+ }
149
+ catch (cause) {
150
+ throw new Error(`Foldkit: a Message dispatched from inside Submodel boundary ` +
151
+ `"${boundaryId}" could not be lifted into its parent's Message type. ` +
152
+ `Its \`toParentMessage\` rejected ${describeMessage(message)}, which ` +
153
+ `means that Message is not part of the Submodel's own Message union. ` +
154
+ `The usual cause is a shared view helper building an app-level Message ` +
155
+ `inside a Submodel's view: a handler's dispatcher is chosen by where ` +
156
+ `the element is built, not by the Message it carries, so the boundary ` +
157
+ `tried to wrap a Message the Submodel does not own. Either move the ` +
158
+ `Message into the Submodel's union, or have the parent supply the ` +
159
+ `element through a \`viewInputs\` slot callback so it is built in the ` +
160
+ `parent's boundary.`, { cause });
161
+ }
162
+ };
117
163
  /** Applies the wrapping chain for `boundaryId` from innermost to
118
164
  * outermost, then dispatches the fully-wrapped message via
119
165
  * `outerDispatch`. Called at event-fire time by the dispatcher closure
@@ -146,7 +192,7 @@ const dispatchAcrossBoundary = (registry, outerDispatch, boundaryId, message) =>
146
192
  `one instance (a bundler split foldkit and @foldkit/ui), so the ` +
147
193
  `wrap was registered in one copy and read from another.`);
148
194
  }
149
- wrapped = descriptor.toParentMessage(wrapped);
195
+ wrapped = liftAcrossBoundary(descriptor, ancestorBoundary, wrapped);
150
196
  }
151
197
  outerDispatch(wrapped);
152
198
  };
@@ -178,7 +224,7 @@ export const resolveBoundaryDispatchThunk = (registry, outerDispatch, boundaryId
178
224
  `OnUnmount message. The Submodel's wrap was absent from the registry ` +
179
225
  `at resolve time, which should not happen during a live render.`);
180
226
  }
181
- wrapped = descriptor.toParentMessage(wrapped);
227
+ wrapped = liftAcrossBoundary(descriptor, ancestorBoundary, wrapped);
182
228
  }
183
229
  const rootMessage = wrapped;
184
230
  return () => outerDispatch(rootMessage);