@solidjs/web 2.0.0-beta.28 → 2.0.0-beta.29

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 (43) hide show
  1. package/dist/dev.cjs +40 -2
  2. package/dist/dev.js +39 -4
  3. package/dist/server.cjs +90 -31
  4. package/dist/server.js +89 -33
  5. package/dist/web.cjs +40 -2
  6. package/dist/web.js +39 -4
  7. package/frames/dist/client.cjs +370 -209
  8. package/frames/dist/client.dev.cjs +370 -210
  9. package/frames/dist/client.dev.js +371 -211
  10. package/frames/dist/client.js +371 -210
  11. package/frames/dist/server.cjs +351 -69
  12. package/frames/dist/server.js +351 -70
  13. package/package.json +3 -3
  14. package/server-functions/dist/client.cjs +87 -3
  15. package/server-functions/dist/client.js +80 -4
  16. package/server-functions/dist/server.cjs +52 -17
  17. package/server-functions/dist/server.js +51 -17
  18. package/types/client.d.ts +15 -0
  19. package/types/core.d.ts +1 -1
  20. package/types/frames/client.d.ts +7 -5
  21. package/types/frames/frame-client.d.ts +17 -0
  22. package/types/frames/frame-sink.d.ts +29 -6
  23. package/types/frames/frame-transport.d.ts +76 -12
  24. package/types/frames/server.d.ts +1 -1
  25. package/types/index.d.ts +74 -0
  26. package/types/server-functions/client.d.ts +24 -0
  27. package/types/server-functions/server.d.ts +75 -16
  28. package/types/server-functions/shared.d.ts +9 -0
  29. package/types/server-mock.d.ts +6 -2
  30. package/types/server.d.ts +39 -1
  31. package/types-cjs/client.d.cts +15 -0
  32. package/types-cjs/core.d.cts +1 -1
  33. package/types-cjs/frames/client.d.cts +7 -5
  34. package/types-cjs/frames/frame-client.d.cts +17 -0
  35. package/types-cjs/frames/frame-sink.d.cts +29 -6
  36. package/types-cjs/frames/frame-transport.d.cts +76 -12
  37. package/types-cjs/frames/server.d.cts +1 -1
  38. package/types-cjs/index.d.cts +74 -0
  39. package/types-cjs/server-functions/client.d.cts +24 -0
  40. package/types-cjs/server-functions/server.d.cts +75 -16
  41. package/types-cjs/server-functions/shared.d.cts +9 -0
  42. package/types-cjs/server-mock.d.cts +6 -2
  43. package/types-cjs/server.d.cts +39 -1
@@ -1,5 +1,5 @@
1
+ import { runWithOwner, createOwner, sharedConfig, createRoot, ssrHandleError, getOwner, NoHydration, runInServerComponentScope, Hydration } from 'solid-js';
1
2
  import { toCrossJSONStream, Feature, Serializer, getCrossReferenceHeader, createPlugin } from 'seroval';
2
- import { runWithOwner, createOwner, sharedConfig, createRoot, ssrHandleError, getOwner, NoHydration, Hydration } from 'solid-js';
3
3
  import { AbortSignalPlugin, CustomEventPlugin, DOMExceptionPlugin, EventPlugin, FormDataPlugin, HeadersPlugin, ReadableStreamPlugin, RequestPlugin, ResponsePlugin, URLSearchParamsPlugin, URLPlugin } from 'seroval-plugins/web';
4
4
 
5
5
  const runWithHydrationScope = (id, fn) => runWithOwner(createOwner({
@@ -54,6 +54,21 @@ function resolveCodecOptions({
54
54
  depthLimit: depthLimit === undefined ? JSON_CODEC_DEPTH_LIMIT : depthLimit
55
55
  };
56
56
  }
57
+ function serializeJSON(value, {
58
+ onParse,
59
+ onDone,
60
+ onError,
61
+ ...codecOptions
62
+ }) {
63
+ const resolved = resolveCodecOptions(codecOptions);
64
+ return toCrossJSONStream(value, {
65
+ onParse,
66
+ onDone,
67
+ onError,
68
+ ...resolved,
69
+ disabledFeatures: resolved.disabledFeatures | serializeOnlyDisabledFeatures()
70
+ });
71
+ }
57
72
  function createJSONSerializer({
58
73
  onData,
59
74
  onDone,
@@ -633,6 +648,51 @@ function renderToStream(code, options = {}) {
633
648
  drainTurn = 0;
634
649
  progressed ? queue(attempt) : setTimeout(attempt);
635
650
  };
651
+ let cachedReadable;
652
+ let consumer;
653
+ const claimConsumer = name => {
654
+ if (consumer && consumer !== name) {
655
+ throw new Error(`renderToStream result was already consumed via \`${consumer}\`; cannot also consume it via \`${name}\`. Use exactly one of \`pipe\`, \`pipeTo\`, or \`readable\`.`);
656
+ }
657
+ consumer = name;
658
+ };
659
+ const pipeToImpl = w => {
660
+ let resolve;
661
+ const p = new Promise(r => resolve = r);
662
+ function flush() {
663
+ allSettled(blockingPromises).then(() => {
664
+ scheduleFlush(() => {
665
+ doShell();
666
+ if (!shellCompleted) return flush();
667
+ const encoder = new TextEncoder();
668
+ const writer = w.getWriter();
669
+ let pendingWrites = Promise.resolve();
670
+ writable = {
671
+ end() {
672
+ pendingWrites.then(() => {
673
+ writer.releaseLock();
674
+ w.close().catch(() => {});
675
+ resolve();
676
+ });
677
+ }
678
+ };
679
+ buffer = {
680
+ write(payload) {
681
+ pendingWrites = pendingWrites.then(() => writer.write(encoder.encode(payload))).catch(() => {});
682
+ }
683
+ };
684
+ buffer.write(tmp);
685
+ firstFlushed = true;
686
+ if (completed) {
687
+ dispose();
688
+ writable.end();
689
+ } else flushEnd();
690
+ });
691
+ });
692
+ }
693
+ flush();
694
+ return p;
695
+ };
636
696
  return {
637
697
  then(fn) {
638
698
  function complete() {
@@ -657,6 +717,7 @@ function renderToStream(code, options = {}) {
657
717
  flush();
658
718
  },
659
719
  pipe(w) {
720
+ claimConsumer("pipe");
660
721
  function flush() {
661
722
  allSettled(blockingPromises).then(() => {
662
723
  scheduleFlush(() => {
@@ -675,38 +736,17 @@ function renderToStream(code, options = {}) {
675
736
  flush();
676
737
  },
677
738
  pipeTo(w) {
678
- let resolve;
679
- const p = new Promise(r => resolve = r);
680
- function flush() {
681
- allSettled(blockingPromises).then(() => {
682
- scheduleFlush(() => {
683
- doShell();
684
- if (!shellCompleted) return flush();
685
- const encoder = new TextEncoder();
686
- const writer = w.getWriter();
687
- writable = {
688
- end() {
689
- writer.releaseLock();
690
- w.close().catch(() => {});
691
- resolve();
692
- }
693
- };
694
- buffer = {
695
- write(payload) {
696
- writer.write(encoder.encode(payload)).catch(() => {});
697
- }
698
- };
699
- buffer.write(tmp);
700
- firstFlushed = true;
701
- if (completed) {
702
- dispose();
703
- writable.end();
704
- } else flushEnd();
705
- });
706
- });
739
+ claimConsumer("pipeTo");
740
+ return pipeToImpl(w);
741
+ },
742
+ get readable() {
743
+ claimConsumer("readable");
744
+ if (!cachedReadable) {
745
+ const t = new TransformStream();
746
+ pipeToImpl(t.writable);
747
+ cachedReadable = t.readable;
707
748
  }
708
- flush();
709
- return p;
749
+ return cachedReadable;
710
750
  }
711
751
  };
712
752
  }
@@ -1151,6 +1191,51 @@ function resolveSSRSync(node) {
1151
1191
  throw new Error("This value cannot be rendered synchronously. Are you missing a boundary?");
1152
1192
  }
1153
1193
 
1194
+ function frameAddress(id, args) {
1195
+ return args && args.length ? id + ":" + hashArguments(args) : id;
1196
+ }
1197
+ function hashArguments(args) {
1198
+ let hash = 0;
1199
+ const text = stableString(args);
1200
+ for (let i = 0; i < text.length; i++) {
1201
+ hash = (hash << 5) - hash + text.charCodeAt(i);
1202
+ hash |= 0;
1203
+ }
1204
+ return (hash >>> 0).toString(36);
1205
+ }
1206
+ function stableString(value, seen) {
1207
+ if (value === null || typeof value !== "object") {
1208
+ return typeof value === "bigint" ? value + "n" : String(value);
1209
+ }
1210
+ if (value instanceof Date) return "Date:" + value.getTime();
1211
+ seen || (seen = new Set());
1212
+ if (seen.has(value)) return "~";
1213
+ seen.add(value);
1214
+ if (value instanceof Map) {
1215
+ const entries = [];
1216
+ for (const [k, v] of value) {
1217
+ entries.push(stableString(k, seen) + "=>" + stableString(v, seen));
1218
+ }
1219
+ return "Map{" + entries.sort().join(",") + "}";
1220
+ }
1221
+ if (value instanceof Set) {
1222
+ const members = [];
1223
+ for (const v of value) members.push(stableString(v, seen));
1224
+ return "Set{" + members.sort().join(",") + "}";
1225
+ }
1226
+ if (Array.isArray(value)) {
1227
+ let out = "[";
1228
+ for (let i = 0; i < value.length; i++) out += (i ? "," : "") + stableString(value[i], seen);
1229
+ return out + "]";
1230
+ }
1231
+ const keys = Object.keys(value).sort();
1232
+ let out = "{";
1233
+ for (let i = 0; i < keys.length; i++) {
1234
+ out += (i ? "," : "") + keys[i] + ":" + stableString(value[keys[i]], seen);
1235
+ }
1236
+ return out + "}";
1237
+ }
1238
+ const SINGLE_FLIGHT_HEADER = "X-Single-Flight";
1154
1239
  function createChunk(data) {
1155
1240
  const encodeData = new TextEncoder().encode(data);
1156
1241
  const bytes = encodeData.length;
@@ -1162,16 +1247,138 @@ function createChunk(data) {
1162
1247
  chunk.set(encodeData, 12);
1163
1248
  return chunk;
1164
1249
  }
1250
+ class ChunkReader {
1251
+ constructor(stream) {
1252
+ this.reader = stream.getReader();
1253
+ this.buffer = new Uint8Array(0);
1254
+ this.done = false;
1255
+ }
1256
+ async readChunk() {
1257
+ const chunk = await this.reader.read();
1258
+ if (!chunk.done) {
1259
+ const newBuffer = new Uint8Array(this.buffer.length + chunk.value.length);
1260
+ newBuffer.set(this.buffer);
1261
+ newBuffer.set(chunk.value, this.buffer.length);
1262
+ this.buffer = newBuffer;
1263
+ } else {
1264
+ this.done = true;
1265
+ }
1266
+ }
1267
+ async next() {
1268
+ while (this.buffer.length < 12) {
1269
+ if (this.done) {
1270
+ if (this.buffer.length === 0) return {
1271
+ done: true,
1272
+ value: undefined
1273
+ };
1274
+ throw new Error("Malformed server function stream.");
1275
+ }
1276
+ await this.readChunk();
1277
+ }
1278
+ const head = new TextDecoder().decode(this.buffer.subarray(1, 11));
1279
+ const bytes = Number.parseInt(head, 16);
1280
+ if (Number.isNaN(bytes)) {
1281
+ throw new Error("Malformed server function stream.");
1282
+ }
1283
+ while (bytes > this.buffer.length - 12) {
1284
+ if (this.done) {
1285
+ throw new Error("Malformed server function stream.");
1286
+ }
1287
+ await this.readChunk();
1288
+ }
1289
+ const partial = new TextDecoder().decode(this.buffer.subarray(12, 12 + bytes));
1290
+ this.buffer = this.buffer.subarray(12 + bytes);
1291
+ return {
1292
+ done: false,
1293
+ value: partial
1294
+ };
1295
+ }
1296
+ async drain(interpret) {
1297
+ while (true) {
1298
+ const result = await this.next();
1299
+ if (result.done) {
1300
+ break;
1301
+ }
1302
+ interpret(result.value);
1303
+ }
1304
+ }
1305
+ }
1306
+ function serializeStream(value, codecOptions) {
1307
+ return new ReadableStream({
1308
+ start(controller) {
1309
+ serializeJSON(value, {
1310
+ ...codecOptions,
1311
+ onParse(node) {
1312
+ controller.enqueue(createChunk(JSON.stringify(node)));
1313
+ },
1314
+ onDone() {
1315
+ controller.close();
1316
+ },
1317
+ onError(error) {
1318
+ controller.error(error);
1319
+ }
1320
+ });
1321
+ }
1322
+ });
1323
+ }
1165
1324
 
1166
1325
  const ENVELOPE = Symbol.for("solid.ResponseEnvelope");
1167
1326
  function isResponseEnvelope(value) {
1168
1327
  return !!(value && typeof value === "object" && value[ENVELOPE]);
1169
1328
  }
1170
1329
 
1330
+ const INVOCATIONS = new WeakMap();
1331
+ function getEventServerFunctionInvocation(event) {
1332
+ return event && INVOCATIONS.get(event);
1333
+ }
1334
+
1171
1335
  const FRAME_STREAM_HEADER = "X-Frame-Stream";
1172
1336
  function isFrameStreamResponse(response) {
1173
1337
  return response.headers.has(FRAME_STREAM_HEADER);
1174
1338
  }
1339
+ const SERVER_COMPONENT = /*#__PURE__*/Symbol.for("dom-expressions.server-component");
1340
+ const SERVER_COMPONENT_SOURCE = /*#__PURE__*/Symbol.for("dom-expressions.server-component-source");
1341
+ const SERVER_COMPONENT_ADDRESS = /*#__PURE__*/Symbol.for("dom-expressions.server-component-address");
1342
+ function parseServerComponent(value, ctx) {
1343
+ return {
1344
+ id: ctx.parse(value[SERVER_COMPONENT]),
1345
+ address: ctx.parse(value[SERVER_COMPONENT_ADDRESS])
1346
+ };
1347
+ }
1348
+ const ServerComponentPlugin = /*#__PURE__*/createPlugin({
1349
+ tag: "dom-expressions/server-component",
1350
+ test(value) {
1351
+ return typeof value === "function" && SERVER_COMPONENT in value;
1352
+ },
1353
+ parse: {
1354
+ sync: parseServerComponent,
1355
+ async async(value, ctx) {
1356
+ return {
1357
+ id: await ctx.parse(value[SERVER_COMPONENT]),
1358
+ address: await ctx.parse(value[SERVER_COMPONENT_ADDRESS])
1359
+ };
1360
+ },
1361
+ stream: parseServerComponent
1362
+ },
1363
+ serialize(node, ctx) {
1364
+ return "self._$SC.r(" + ctx.serialize(node.id) + "," + ctx.serialize(node.address) + ")";
1365
+ },
1366
+ deserialize(node, ctx) {
1367
+ const id = ctx.deserialize(node.id);
1368
+ ctx.deserialize(node.address);
1369
+ return globalThis._$SC.r(id);
1370
+ }
1371
+ });
1372
+ function flightCodec(codec) {
1373
+ const plugins = codec && codec.plugins || [];
1374
+ for (const plugin of plugins) {
1375
+ if (plugin && plugin.tag === "dom-expressions/server-component") return codec;
1376
+ }
1377
+ return {
1378
+ ...codec,
1379
+ plugins: [...plugins, ServerComponentPlugin]
1380
+ };
1381
+ }
1175
1382
 
1176
1383
  function serverOwned(render) {
1177
1384
  return NoHydration ? NoHydration({
@@ -1180,6 +1387,9 @@ function serverOwned(render) {
1180
1387
  }
1181
1388
  }) : render();
1182
1389
  }
1390
+ function serverComponentScope(render) {
1391
+ return runInServerComponentScope ? runInServerComponentScope(render) : render();
1392
+ }
1183
1393
  function createFrameSink(emit, frame) {
1184
1394
  const {
1185
1395
  id,
@@ -1361,7 +1571,7 @@ function renderToFrameStream(code, options = {}) {
1361
1571
  function renderServerComponent(component, options = {}) {
1362
1572
  return frameStream((sink, frame) => {
1363
1573
  const props = createSlotProps(sink, frame);
1364
- return () => component(props);
1574
+ return () => serverComponentScope(() => component(props));
1365
1575
  }, options);
1366
1576
  }
1367
1577
  function frameStream(makeCode, options) {
@@ -1554,16 +1764,23 @@ function frameElementOpen(id) {
1554
1764
  }
1555
1765
  const FRAME_ELEMENT_CLOSE = `</${FRAME_TAG}>`;
1556
1766
  function frameTransformDirectResult(value, {
1557
- id
1767
+ id,
1768
+ args
1558
1769
  }) {
1559
1770
  if (typeof value !== "function") return value;
1560
1771
  const component = value;
1561
1772
  const wrapped = props => [{
1562
1773
  t: frameElementOpen(id)
1563
- }, serverOwned(() => component(createDocumentSlotProps(props, id))), {
1774
+ },
1775
+ serverOwned(() => {
1776
+ const slotProps = createDocumentSlotProps(props, id);
1777
+ return serverComponentScope(() => component(slotProps));
1778
+ }), {
1564
1779
  t: FRAME_ELEMENT_CLOSE
1565
1780
  }];
1566
1781
  wrapped[SERVER_COMPONENT] = id;
1782
+ wrapped[SERVER_COMPONENT_SOURCE] = component;
1783
+ wrapped[SERVER_COMPONENT_ADDRESS] = frameAddress(id, args);
1567
1784
  return wrapped;
1568
1785
  }
1569
1786
  function resolveRegionHtml(ctx, node) {
@@ -1580,37 +1797,7 @@ function resolveRegionHtml(ctx, node) {
1580
1797
  return out;
1581
1798
  });
1582
1799
  }
1583
- const SERVER_COMPONENT = /*#__PURE__*/Symbol.for("dom-expressions.server-component");
1584
- const ServerComponentPlugin = /*#__PURE__*/createPlugin({
1585
- tag: "dom-expressions/server-component",
1586
- test(value) {
1587
- return typeof value === "function" && SERVER_COMPONENT in value;
1588
- },
1589
- parse: {
1590
- sync(value, ctx) {
1591
- return {
1592
- id: ctx.parse(value[SERVER_COMPONENT])
1593
- };
1594
- },
1595
- async async(value, ctx) {
1596
- return {
1597
- id: await ctx.parse(value[SERVER_COMPONENT])
1598
- };
1599
- },
1600
- stream(value, ctx) {
1601
- return {
1602
- id: ctx.parse(value[SERVER_COMPONENT])
1603
- };
1604
- }
1605
- },
1606
- serialize(node, ctx) {
1607
- return "self._$SC.r(" + ctx.serialize(node.id) + ")";
1608
- },
1609
- deserialize(node, ctx) {
1610
- return globalThis._$SC.r(ctx.deserialize(node.id));
1611
- }
1612
- });
1613
- const SERVER_COMPONENT_BOOTSTRAP = "self._$SC={c:{},r(i){return this.c[i]||(this.c[i]=(p)=>self._$SC.impl(i,p))}};";
1800
+ const SERVER_COMPONENT_BOOTSTRAP = "self._$SC={c:{},a:{},r(i,a){a&&(this.a[a]=i,this.reg&&this.reg(a,i));return this.c[i]||(this.c[i]=(p)=>self._$SC.impl(i,p))}};";
1614
1801
  function isServerContent(value) {
1615
1802
  if (value && typeof value === "object") {
1616
1803
  if ("t" in value) return true;
@@ -1719,7 +1906,7 @@ function serverComponentResponse(component, options = {}, init = {}) {
1719
1906
  headers
1720
1907
  });
1721
1908
  }
1722
- function frameTransformResult(event, result) {
1909
+ function frameTransformResult(event, result, context) {
1723
1910
  let init;
1724
1911
  if (isResponseEnvelope(result)) {
1725
1912
  const {
@@ -1734,12 +1921,106 @@ function frameTransformResult(event, result) {
1734
1921
  result = value;
1735
1922
  }
1736
1923
  if (typeof result !== "function") return result;
1737
- const meta = event && event.locals && event.locals.serverFunctionMeta;
1924
+ if (context && context.collectsFlight) return init ? {
1925
+ response: init,
1926
+ value: result
1927
+ } : result;
1928
+ const invocation = getEventServerFunctionInvocation(event);
1738
1929
  return serverComponentResponse(result, {
1739
1930
  frame: {
1740
- id: meta && meta.id || ""
1931
+ id: invocation && invocation.id || ""
1741
1932
  }
1742
1933
  }, init);
1743
1934
  }
1935
+ async function frameTransformFlightResult(event, outcome, context) {
1936
+ const {
1937
+ value,
1938
+ data
1939
+ } = outcome;
1940
+ const regions = [];
1941
+ let serialized = data;
1942
+ if (data && typeof data === "object") {
1943
+ serialized = {};
1944
+ const keys = Object.keys(data);
1945
+ const values = await Promise.all(keys.map(key => data[key]));
1946
+ for (let i = 0; i < keys.length; i++) {
1947
+ const entry = values[i];
1948
+ serialized[keys[i]] = entry;
1949
+ if (typeof entry === "function") {
1950
+ regions.push({
1951
+ id: entry[SERVER_COMPONENT_ADDRESS] || keys[i],
1952
+ component: entry[SERVER_COMPONENT_SOURCE] || entry
1953
+ });
1954
+ }
1955
+ }
1956
+ }
1957
+ const invocation = getEventServerFunctionInvocation(event);
1958
+ const primary = typeof value === "function" ? {
1959
+ id: invocation && invocation.id || "",
1960
+ component: value
1961
+ } : undefined;
1962
+ if (!primary && !regions.length) return undefined;
1963
+ return frameFlightResponse({
1964
+ primary,
1965
+ regions,
1966
+ outcome: {
1967
+ value: primary ? undefined : value,
1968
+ data: serialized
1969
+ },
1970
+ codec: context && context.codec
1971
+ });
1972
+ }
1973
+ function frameFlightResponse({
1974
+ primary,
1975
+ regions = [],
1976
+ outcome,
1977
+ codec
1978
+ }, init = {}) {
1979
+ const frames = primary ? [primary, ...regions] : regions;
1980
+ const headers = new Headers(init.headers);
1981
+ headers.set("Content-Type", "application/x-frame-stream");
1982
+ headers.set(FRAME_STREAM_HEADER, primary ? primary.id : "");
1983
+ headers.set("X-Content-Raw", "1");
1984
+ headers.set(SINGLE_FLIGHT_HEADER, "true");
1985
+ const body = new ReadableStream({
1986
+ async start(controller) {
1987
+ const write = chunk => controller.enqueue(createChunk(JSON.stringify(chunk)));
1988
+ try {
1989
+ for (const {
1990
+ id,
1991
+ component
1992
+ } of frames) {
1993
+ await new Promise(resolve => {
1994
+ renderServerComponent(component, {
1995
+ frame: {
1996
+ id,
1997
+ version: 1
1998
+ }
1999
+ }).pipe({
2000
+ write,
2001
+ end: resolve
2002
+ });
2003
+ });
2004
+ }
2005
+ if (outcome) {
2006
+ const reader = new ChunkReader(serializeStream(outcome, flightCodec(codec)));
2007
+ for (let node = await reader.next(); !node.done; node = await reader.next()) {
2008
+ write({
2009
+ type: "outcome",
2010
+ payload: node.value
2011
+ });
2012
+ }
2013
+ }
2014
+ controller.close();
2015
+ } catch (err) {
2016
+ controller.error(err);
2017
+ }
2018
+ }
2019
+ });
2020
+ return new Response(body, {
2021
+ status: init.status || 200,
2022
+ headers
2023
+ });
2024
+ }
1744
2025
 
1745
- export { FRAME_STREAM_HEADER, SERVER_COMPONENT_BOOTSTRAP, ServerComponentPlugin, createFrameSink, frameTransformDirectResult, frameTransformResult, isFrameStreamResponse, renderServerComponent, renderToFrameStream, serverComponentResponse };
2026
+ export { FRAME_STREAM_HEADER, SERVER_COMPONENT_BOOTSTRAP, ServerComponentPlugin, createFrameSink, frameTransformDirectResult, frameTransformFlightResult, frameTransformResult, isFrameStreamResponse, renderServerComponent, renderToFrameStream, serverComponentResponse };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@solidjs/web",
3
3
  "description": "Solid's web runtime: client rendering, hydration, SSR, and DOM-specific control flow (Portal, Dynamic).",
4
- "version": "2.0.0-beta.28",
4
+ "version": "2.0.0-beta.29",
5
5
  "author": "Ryan Carniato",
6
6
  "license": "MIT",
7
7
  "homepage": "https://solidjs.com",
@@ -316,10 +316,10 @@
316
316
  "seroval-plugins": "~1.5.4"
317
317
  },
318
318
  "peerDependencies": {
319
- "solid-js": "^2.0.0-beta.28"
319
+ "solid-js": "^2.0.0-beta.29"
320
320
  },
321
321
  "devDependencies": {
322
- "solid-js": "2.0.0-beta.28"
322
+ "solid-js": "2.0.0-beta.29"
323
323
  },
324
324
  "scripts": {
325
325
  "build": "npm-run-all -nl build:clean types:copy-jsx build:js",
@@ -42,6 +42,9 @@ const codecConfig = {
42
42
  function configureServerFunctionsCodec(codec) {
43
43
  codecConfig.codec = codec;
44
44
  }
45
+ function getServerFunctionsCodec() {
46
+ return codecConfig.codec;
47
+ }
45
48
  const flightConfig = {
46
49
  consumer: undefined
47
50
  };
@@ -54,6 +57,50 @@ function subscribeFlightData(consumer) {
54
57
  function getFlightDataConsumer() {
55
58
  return flightConfig.consumer;
56
59
  }
60
+ function frameAddress(id, args) {
61
+ return args && args.length ? id + ":" + hashArguments(args) : id;
62
+ }
63
+ function hashArguments(args) {
64
+ let hash = 0;
65
+ const text = stableString(args);
66
+ for (let i = 0; i < text.length; i++) {
67
+ hash = (hash << 5) - hash + text.charCodeAt(i);
68
+ hash |= 0;
69
+ }
70
+ return (hash >>> 0).toString(36);
71
+ }
72
+ function stableString(value, seen) {
73
+ if (value === null || typeof value !== "object") {
74
+ return typeof value === "bigint" ? value + "n" : String(value);
75
+ }
76
+ if (value instanceof Date) return "Date:" + value.getTime();
77
+ seen || (seen = new Set());
78
+ if (seen.has(value)) return "~";
79
+ seen.add(value);
80
+ if (value instanceof Map) {
81
+ const entries = [];
82
+ for (const [k, v] of value) {
83
+ entries.push(stableString(k, seen) + "=>" + stableString(v, seen));
84
+ }
85
+ return "Map{" + entries.sort().join(",") + "}";
86
+ }
87
+ if (value instanceof Set) {
88
+ const members = [];
89
+ for (const v of value) members.push(stableString(v, seen));
90
+ return "Set{" + members.sort().join(",") + "}";
91
+ }
92
+ if (Array.isArray(value)) {
93
+ let out = "[";
94
+ for (let i = 0; i < value.length; i++) out += (i ? "," : "") + stableString(value[i], seen);
95
+ return out + "]";
96
+ }
97
+ const keys = Object.keys(value).sort();
98
+ let out = "{";
99
+ for (let i = 0; i < keys.length; i++) {
100
+ out += (i ? "," : "") + keys[i] + ":" + stableString(value[keys[i]], seen);
101
+ }
102
+ return out + "}";
103
+ }
57
104
  const SERVER_FUNCTION_METADATA = Symbol.for("solid.ServerFunctionMetadata");
58
105
  function getServerFunctionMetadata(fn) {
59
106
  if (typeof fn !== "function") return undefined;
@@ -211,6 +258,17 @@ async function extractBody(source, codecOptions) {
211
258
  }
212
259
  return undefined;
213
260
  }
261
+ function createChunk(data) {
262
+ const encodeData = new TextEncoder().encode(data);
263
+ const bytes = encodeData.length;
264
+ const baseHex = bytes.toString(16);
265
+ const totalHex = "00000000".substring(0, 8 - baseHex.length) + baseHex;
266
+ const head = new TextEncoder().encode(`;0x${totalHex};`);
267
+ const chunk = new Uint8Array(12 + bytes);
268
+ chunk.set(head);
269
+ chunk.set(encodeData, 12);
270
+ return chunk;
271
+ }
214
272
  class ChunkReader {
215
273
  constructor(stream) {
216
274
  this.reader = stream.getReader();
@@ -391,6 +449,21 @@ async function initializeResponse(base, id, instance, options, args, meta) {
391
449
  }
392
450
  }, meta);
393
451
  }
452
+ if (args.length > 1) {
453
+ const trailing = getHeadersAndBody(args[args.length - 1]);
454
+ const leading = args.slice(0, -1).map(arg => arg === undefined ? null : arg);
455
+ if (trailing && isJSONSafe(leading)) {
456
+ const target = base + (base.includes("?") ? "&" : "?") + "args=" + encodeURIComponent(JSON.stringify(leading));
457
+ return createRequest(target, id, instance, {
458
+ ...options,
459
+ body: trailing.body,
460
+ headers: {
461
+ ...options.headers,
462
+ ...trailing.headers
463
+ }
464
+ }, meta);
465
+ }
466
+ }
394
467
  return createRequest(base, id, instance, {
395
468
  ...options,
396
469
  body: await serializeArguments(args),
@@ -401,7 +474,7 @@ async function initializeResponse(base, id, instance, options, args, meta) {
401
474
  }
402
475
  }, meta);
403
476
  }
404
- async function fetchServerFunction(base, id, options, args, meta) {
477
+ async function fetchServerFunction(base, id, options, args, meta, callArgs = args) {
405
478
  const instance = `server-function:${INSTANCE++}`;
406
479
  const handler = config.responseHandler;
407
480
  const context = handler && handler.capture ? handler.capture({
@@ -413,7 +486,7 @@ async function fetchServerFunction(base, id, options, args, meta) {
413
486
  const handled = handler.handle(response, {
414
487
  id,
415
488
  meta,
416
- args,
489
+ args: callArgs,
417
490
  context
418
491
  });
419
492
  if (handled !== undefined) return handled;
@@ -492,7 +565,7 @@ function GET(fn) {
492
565
  }
493
566
  return fetchServerFunction(base, id, {
494
567
  method: "GET"
495
- }, [], metadata);
568
+ }, [], metadata, args);
496
569
  };
497
570
  wrapped[SERVER_FUNCTION_METADATA] = metadata;
498
571
  wrapped.id = id;
@@ -507,21 +580,32 @@ function GET(fn) {
507
580
  function registerServerReference() {
508
581
  throw new Error("registerServerReference must not be called in the client build");
509
582
  }
583
+ function getServerFunctionInvocation() {
584
+ return undefined;
585
+ }
510
586
 
587
+ exports.ChunkReader = ChunkReader;
511
588
  exports.ERROR_HEADER = ERROR_HEADER;
512
589
  exports.FLASH_COOKIE = FLASH_COOKIE;
513
590
  exports.FUNCTION_HEADER = FUNCTION_HEADER;
514
591
  exports.GET = GET;
515
592
  exports.INSTANCE_HEADER = INSTANCE_HEADER;
593
+ exports.REVALIDATE_HEADER = REVALIDATE_HEADER;
516
594
  exports.SINGLE_FLIGHT_HEADER = SINGLE_FLIGHT_HEADER;
517
595
  exports.clearFlashCookie = clearFlashCookie;
518
596
  exports.configureServerFunctionsClient = configureServerFunctionsClient;
597
+ exports.createChunk = createChunk;
519
598
  exports.createServerReference = createServerReference;
520
599
  exports.decodeErrorHeaderValue = decodeErrorHeaderValue;
521
600
  exports.decodeResponse = decodeResponse;
522
601
  exports.decodeResponsePayload = decodeResponsePayload;
602
+ exports.deserializeStream = deserializeStream;
523
603
  exports.encodeErrorHeaderValue = encodeErrorHeaderValue;
604
+ exports.frameAddress = frameAddress;
605
+ exports.getFlightDataConsumer = getFlightDataConsumer;
606
+ exports.getServerFunctionInvocation = getServerFunctionInvocation;
524
607
  exports.getServerFunctionMetadata = getServerFunctionMetadata;
608
+ exports.getServerFunctionsCodec = getServerFunctionsCodec;
525
609
  exports.hasFlashCookie = hasFlashCookie;
526
610
  exports.isServerFunction = isServerFunction;
527
611
  exports.registerServerReference = registerServerReference;