@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,7 +1,7 @@
1
1
  'use strict';
2
2
 
3
- var seroval = require('seroval');
4
3
  var solidJs = require('solid-js');
4
+ var seroval = require('seroval');
5
5
  var web = require('seroval-plugins/web');
6
6
 
7
7
  const runWithHydrationScope = (id, fn) => solidJs.runWithOwner(solidJs.createOwner({
@@ -56,6 +56,21 @@ function resolveCodecOptions({
56
56
  depthLimit: depthLimit === undefined ? JSON_CODEC_DEPTH_LIMIT : depthLimit
57
57
  };
58
58
  }
59
+ function serializeJSON(value, {
60
+ onParse,
61
+ onDone,
62
+ onError,
63
+ ...codecOptions
64
+ }) {
65
+ const resolved = resolveCodecOptions(codecOptions);
66
+ return seroval.toCrossJSONStream(value, {
67
+ onParse,
68
+ onDone,
69
+ onError,
70
+ ...resolved,
71
+ disabledFeatures: resolved.disabledFeatures | serializeOnlyDisabledFeatures()
72
+ });
73
+ }
59
74
  function createJSONSerializer({
60
75
  onData,
61
76
  onDone,
@@ -635,6 +650,51 @@ function renderToStream(code, options = {}) {
635
650
  drainTurn = 0;
636
651
  progressed ? queue(attempt) : setTimeout(attempt);
637
652
  };
653
+ let cachedReadable;
654
+ let consumer;
655
+ const claimConsumer = name => {
656
+ if (consumer && consumer !== name) {
657
+ throw new Error(`renderToStream result was already consumed via \`${consumer}\`; cannot also consume it via \`${name}\`. Use exactly one of \`pipe\`, \`pipeTo\`, or \`readable\`.`);
658
+ }
659
+ consumer = name;
660
+ };
661
+ const pipeToImpl = w => {
662
+ let resolve;
663
+ const p = new Promise(r => resolve = r);
664
+ function flush() {
665
+ allSettled(blockingPromises).then(() => {
666
+ scheduleFlush(() => {
667
+ doShell();
668
+ if (!shellCompleted) return flush();
669
+ const encoder = new TextEncoder();
670
+ const writer = w.getWriter();
671
+ let pendingWrites = Promise.resolve();
672
+ writable = {
673
+ end() {
674
+ pendingWrites.then(() => {
675
+ writer.releaseLock();
676
+ w.close().catch(() => {});
677
+ resolve();
678
+ });
679
+ }
680
+ };
681
+ buffer = {
682
+ write(payload) {
683
+ pendingWrites = pendingWrites.then(() => writer.write(encoder.encode(payload))).catch(() => {});
684
+ }
685
+ };
686
+ buffer.write(tmp);
687
+ firstFlushed = true;
688
+ if (completed) {
689
+ dispose();
690
+ writable.end();
691
+ } else flushEnd();
692
+ });
693
+ });
694
+ }
695
+ flush();
696
+ return p;
697
+ };
638
698
  return {
639
699
  then(fn) {
640
700
  function complete() {
@@ -659,6 +719,7 @@ function renderToStream(code, options = {}) {
659
719
  flush();
660
720
  },
661
721
  pipe(w) {
722
+ claimConsumer("pipe");
662
723
  function flush() {
663
724
  allSettled(blockingPromises).then(() => {
664
725
  scheduleFlush(() => {
@@ -677,38 +738,17 @@ function renderToStream(code, options = {}) {
677
738
  flush();
678
739
  },
679
740
  pipeTo(w) {
680
- let resolve;
681
- const p = new Promise(r => resolve = r);
682
- function flush() {
683
- allSettled(blockingPromises).then(() => {
684
- scheduleFlush(() => {
685
- doShell();
686
- if (!shellCompleted) return flush();
687
- const encoder = new TextEncoder();
688
- const writer = w.getWriter();
689
- writable = {
690
- end() {
691
- writer.releaseLock();
692
- w.close().catch(() => {});
693
- resolve();
694
- }
695
- };
696
- buffer = {
697
- write(payload) {
698
- writer.write(encoder.encode(payload)).catch(() => {});
699
- }
700
- };
701
- buffer.write(tmp);
702
- firstFlushed = true;
703
- if (completed) {
704
- dispose();
705
- writable.end();
706
- } else flushEnd();
707
- });
708
- });
741
+ claimConsumer("pipeTo");
742
+ return pipeToImpl(w);
743
+ },
744
+ get readable() {
745
+ claimConsumer("readable");
746
+ if (!cachedReadable) {
747
+ const t = new TransformStream();
748
+ pipeToImpl(t.writable);
749
+ cachedReadable = t.readable;
709
750
  }
710
- flush();
711
- return p;
751
+ return cachedReadable;
712
752
  }
713
753
  };
714
754
  }
@@ -1153,6 +1193,51 @@ function resolveSSRSync(node) {
1153
1193
  throw new Error("This value cannot be rendered synchronously. Are you missing a boundary?");
1154
1194
  }
1155
1195
 
1196
+ function frameAddress(id, args) {
1197
+ return args && args.length ? id + ":" + hashArguments(args) : id;
1198
+ }
1199
+ function hashArguments(args) {
1200
+ let hash = 0;
1201
+ const text = stableString(args);
1202
+ for (let i = 0; i < text.length; i++) {
1203
+ hash = (hash << 5) - hash + text.charCodeAt(i);
1204
+ hash |= 0;
1205
+ }
1206
+ return (hash >>> 0).toString(36);
1207
+ }
1208
+ function stableString(value, seen) {
1209
+ if (value === null || typeof value !== "object") {
1210
+ return typeof value === "bigint" ? value + "n" : String(value);
1211
+ }
1212
+ if (value instanceof Date) return "Date:" + value.getTime();
1213
+ seen || (seen = new Set());
1214
+ if (seen.has(value)) return "~";
1215
+ seen.add(value);
1216
+ if (value instanceof Map) {
1217
+ const entries = [];
1218
+ for (const [k, v] of value) {
1219
+ entries.push(stableString(k, seen) + "=>" + stableString(v, seen));
1220
+ }
1221
+ return "Map{" + entries.sort().join(",") + "}";
1222
+ }
1223
+ if (value instanceof Set) {
1224
+ const members = [];
1225
+ for (const v of value) members.push(stableString(v, seen));
1226
+ return "Set{" + members.sort().join(",") + "}";
1227
+ }
1228
+ if (Array.isArray(value)) {
1229
+ let out = "[";
1230
+ for (let i = 0; i < value.length; i++) out += (i ? "," : "") + stableString(value[i], seen);
1231
+ return out + "]";
1232
+ }
1233
+ const keys = Object.keys(value).sort();
1234
+ let out = "{";
1235
+ for (let i = 0; i < keys.length; i++) {
1236
+ out += (i ? "," : "") + keys[i] + ":" + stableString(value[keys[i]], seen);
1237
+ }
1238
+ return out + "}";
1239
+ }
1240
+ const SINGLE_FLIGHT_HEADER = "X-Single-Flight";
1156
1241
  function createChunk(data) {
1157
1242
  const encodeData = new TextEncoder().encode(data);
1158
1243
  const bytes = encodeData.length;
@@ -1164,16 +1249,138 @@ function createChunk(data) {
1164
1249
  chunk.set(encodeData, 12);
1165
1250
  return chunk;
1166
1251
  }
1252
+ class ChunkReader {
1253
+ constructor(stream) {
1254
+ this.reader = stream.getReader();
1255
+ this.buffer = new Uint8Array(0);
1256
+ this.done = false;
1257
+ }
1258
+ async readChunk() {
1259
+ const chunk = await this.reader.read();
1260
+ if (!chunk.done) {
1261
+ const newBuffer = new Uint8Array(this.buffer.length + chunk.value.length);
1262
+ newBuffer.set(this.buffer);
1263
+ newBuffer.set(chunk.value, this.buffer.length);
1264
+ this.buffer = newBuffer;
1265
+ } else {
1266
+ this.done = true;
1267
+ }
1268
+ }
1269
+ async next() {
1270
+ while (this.buffer.length < 12) {
1271
+ if (this.done) {
1272
+ if (this.buffer.length === 0) return {
1273
+ done: true,
1274
+ value: undefined
1275
+ };
1276
+ throw new Error("Malformed server function stream.");
1277
+ }
1278
+ await this.readChunk();
1279
+ }
1280
+ const head = new TextDecoder().decode(this.buffer.subarray(1, 11));
1281
+ const bytes = Number.parseInt(head, 16);
1282
+ if (Number.isNaN(bytes)) {
1283
+ throw new Error("Malformed server function stream.");
1284
+ }
1285
+ while (bytes > this.buffer.length - 12) {
1286
+ if (this.done) {
1287
+ throw new Error("Malformed server function stream.");
1288
+ }
1289
+ await this.readChunk();
1290
+ }
1291
+ const partial = new TextDecoder().decode(this.buffer.subarray(12, 12 + bytes));
1292
+ this.buffer = this.buffer.subarray(12 + bytes);
1293
+ return {
1294
+ done: false,
1295
+ value: partial
1296
+ };
1297
+ }
1298
+ async drain(interpret) {
1299
+ while (true) {
1300
+ const result = await this.next();
1301
+ if (result.done) {
1302
+ break;
1303
+ }
1304
+ interpret(result.value);
1305
+ }
1306
+ }
1307
+ }
1308
+ function serializeStream(value, codecOptions) {
1309
+ return new ReadableStream({
1310
+ start(controller) {
1311
+ serializeJSON(value, {
1312
+ ...codecOptions,
1313
+ onParse(node) {
1314
+ controller.enqueue(createChunk(JSON.stringify(node)));
1315
+ },
1316
+ onDone() {
1317
+ controller.close();
1318
+ },
1319
+ onError(error) {
1320
+ controller.error(error);
1321
+ }
1322
+ });
1323
+ }
1324
+ });
1325
+ }
1167
1326
 
1168
1327
  const ENVELOPE = Symbol.for("solid.ResponseEnvelope");
1169
1328
  function isResponseEnvelope(value) {
1170
1329
  return !!(value && typeof value === "object" && value[ENVELOPE]);
1171
1330
  }
1172
1331
 
1332
+ const INVOCATIONS = new WeakMap();
1333
+ function getEventServerFunctionInvocation(event) {
1334
+ return event && INVOCATIONS.get(event);
1335
+ }
1336
+
1173
1337
  const FRAME_STREAM_HEADER = "X-Frame-Stream";
1174
1338
  function isFrameStreamResponse(response) {
1175
1339
  return response.headers.has(FRAME_STREAM_HEADER);
1176
1340
  }
1341
+ const SERVER_COMPONENT = /*#__PURE__*/Symbol.for("dom-expressions.server-component");
1342
+ const SERVER_COMPONENT_SOURCE = /*#__PURE__*/Symbol.for("dom-expressions.server-component-source");
1343
+ const SERVER_COMPONENT_ADDRESS = /*#__PURE__*/Symbol.for("dom-expressions.server-component-address");
1344
+ function parseServerComponent(value, ctx) {
1345
+ return {
1346
+ id: ctx.parse(value[SERVER_COMPONENT]),
1347
+ address: ctx.parse(value[SERVER_COMPONENT_ADDRESS])
1348
+ };
1349
+ }
1350
+ const ServerComponentPlugin = /*#__PURE__*/seroval.createPlugin({
1351
+ tag: "dom-expressions/server-component",
1352
+ test(value) {
1353
+ return typeof value === "function" && SERVER_COMPONENT in value;
1354
+ },
1355
+ parse: {
1356
+ sync: parseServerComponent,
1357
+ async async(value, ctx) {
1358
+ return {
1359
+ id: await ctx.parse(value[SERVER_COMPONENT]),
1360
+ address: await ctx.parse(value[SERVER_COMPONENT_ADDRESS])
1361
+ };
1362
+ },
1363
+ stream: parseServerComponent
1364
+ },
1365
+ serialize(node, ctx) {
1366
+ return "self._$SC.r(" + ctx.serialize(node.id) + "," + ctx.serialize(node.address) + ")";
1367
+ },
1368
+ deserialize(node, ctx) {
1369
+ const id = ctx.deserialize(node.id);
1370
+ ctx.deserialize(node.address);
1371
+ return globalThis._$SC.r(id);
1372
+ }
1373
+ });
1374
+ function flightCodec(codec) {
1375
+ const plugins = codec && codec.plugins || [];
1376
+ for (const plugin of plugins) {
1377
+ if (plugin && plugin.tag === "dom-expressions/server-component") return codec;
1378
+ }
1379
+ return {
1380
+ ...codec,
1381
+ plugins: [...plugins, ServerComponentPlugin]
1382
+ };
1383
+ }
1177
1384
 
1178
1385
  function serverOwned(render) {
1179
1386
  return solidJs.NoHydration ? solidJs.NoHydration({
@@ -1182,6 +1389,9 @@ function serverOwned(render) {
1182
1389
  }
1183
1390
  }) : render();
1184
1391
  }
1392
+ function serverComponentScope(render) {
1393
+ return solidJs.runInServerComponentScope ? solidJs.runInServerComponentScope(render) : render();
1394
+ }
1185
1395
  function createFrameSink(emit, frame) {
1186
1396
  const {
1187
1397
  id,
@@ -1363,7 +1573,7 @@ function renderToFrameStream(code, options = {}) {
1363
1573
  function renderServerComponent(component, options = {}) {
1364
1574
  return frameStream((sink, frame) => {
1365
1575
  const props = createSlotProps(sink, frame);
1366
- return () => component(props);
1576
+ return () => serverComponentScope(() => component(props));
1367
1577
  }, options);
1368
1578
  }
1369
1579
  function frameStream(makeCode, options) {
@@ -1556,16 +1766,23 @@ function frameElementOpen(id) {
1556
1766
  }
1557
1767
  const FRAME_ELEMENT_CLOSE = `</${FRAME_TAG}>`;
1558
1768
  function frameTransformDirectResult(value, {
1559
- id
1769
+ id,
1770
+ args
1560
1771
  }) {
1561
1772
  if (typeof value !== "function") return value;
1562
1773
  const component = value;
1563
1774
  const wrapped = props => [{
1564
1775
  t: frameElementOpen(id)
1565
- }, serverOwned(() => component(createDocumentSlotProps(props, id))), {
1776
+ },
1777
+ serverOwned(() => {
1778
+ const slotProps = createDocumentSlotProps(props, id);
1779
+ return serverComponentScope(() => component(slotProps));
1780
+ }), {
1566
1781
  t: FRAME_ELEMENT_CLOSE
1567
1782
  }];
1568
1783
  wrapped[SERVER_COMPONENT] = id;
1784
+ wrapped[SERVER_COMPONENT_SOURCE] = component;
1785
+ wrapped[SERVER_COMPONENT_ADDRESS] = frameAddress(id, args);
1569
1786
  return wrapped;
1570
1787
  }
1571
1788
  function resolveRegionHtml(ctx, node) {
@@ -1582,37 +1799,7 @@ function resolveRegionHtml(ctx, node) {
1582
1799
  return out;
1583
1800
  });
1584
1801
  }
1585
- const SERVER_COMPONENT = /*#__PURE__*/Symbol.for("dom-expressions.server-component");
1586
- const ServerComponentPlugin = /*#__PURE__*/seroval.createPlugin({
1587
- tag: "dom-expressions/server-component",
1588
- test(value) {
1589
- return typeof value === "function" && SERVER_COMPONENT in value;
1590
- },
1591
- parse: {
1592
- sync(value, ctx) {
1593
- return {
1594
- id: ctx.parse(value[SERVER_COMPONENT])
1595
- };
1596
- },
1597
- async async(value, ctx) {
1598
- return {
1599
- id: await ctx.parse(value[SERVER_COMPONENT])
1600
- };
1601
- },
1602
- stream(value, ctx) {
1603
- return {
1604
- id: ctx.parse(value[SERVER_COMPONENT])
1605
- };
1606
- }
1607
- },
1608
- serialize(node, ctx) {
1609
- return "self._$SC.r(" + ctx.serialize(node.id) + ")";
1610
- },
1611
- deserialize(node, ctx) {
1612
- return globalThis._$SC.r(ctx.deserialize(node.id));
1613
- }
1614
- });
1615
- const SERVER_COMPONENT_BOOTSTRAP = "self._$SC={c:{},r(i){return this.c[i]||(this.c[i]=(p)=>self._$SC.impl(i,p))}};";
1802
+ 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))}};";
1616
1803
  function isServerContent(value) {
1617
1804
  if (value && typeof value === "object") {
1618
1805
  if ("t" in value) return true;
@@ -1721,7 +1908,7 @@ function serverComponentResponse(component, options = {}, init = {}) {
1721
1908
  headers
1722
1909
  });
1723
1910
  }
1724
- function frameTransformResult(event, result) {
1911
+ function frameTransformResult(event, result, context) {
1725
1912
  let init;
1726
1913
  if (isResponseEnvelope(result)) {
1727
1914
  const {
@@ -1736,19 +1923,114 @@ function frameTransformResult(event, result) {
1736
1923
  result = value;
1737
1924
  }
1738
1925
  if (typeof result !== "function") return result;
1739
- const meta = event && event.locals && event.locals.serverFunctionMeta;
1926
+ if (context && context.collectsFlight) return init ? {
1927
+ response: init,
1928
+ value: result
1929
+ } : result;
1930
+ const invocation = getEventServerFunctionInvocation(event);
1740
1931
  return serverComponentResponse(result, {
1741
1932
  frame: {
1742
- id: meta && meta.id || ""
1933
+ id: invocation && invocation.id || ""
1743
1934
  }
1744
1935
  }, init);
1745
1936
  }
1937
+ async function frameTransformFlightResult(event, outcome, context) {
1938
+ const {
1939
+ value,
1940
+ data
1941
+ } = outcome;
1942
+ const regions = [];
1943
+ let serialized = data;
1944
+ if (data && typeof data === "object") {
1945
+ serialized = {};
1946
+ const keys = Object.keys(data);
1947
+ const values = await Promise.all(keys.map(key => data[key]));
1948
+ for (let i = 0; i < keys.length; i++) {
1949
+ const entry = values[i];
1950
+ serialized[keys[i]] = entry;
1951
+ if (typeof entry === "function") {
1952
+ regions.push({
1953
+ id: entry[SERVER_COMPONENT_ADDRESS] || keys[i],
1954
+ component: entry[SERVER_COMPONENT_SOURCE] || entry
1955
+ });
1956
+ }
1957
+ }
1958
+ }
1959
+ const invocation = getEventServerFunctionInvocation(event);
1960
+ const primary = typeof value === "function" ? {
1961
+ id: invocation && invocation.id || "",
1962
+ component: value
1963
+ } : undefined;
1964
+ if (!primary && !regions.length) return undefined;
1965
+ return frameFlightResponse({
1966
+ primary,
1967
+ regions,
1968
+ outcome: {
1969
+ value: primary ? undefined : value,
1970
+ data: serialized
1971
+ },
1972
+ codec: context && context.codec
1973
+ });
1974
+ }
1975
+ function frameFlightResponse({
1976
+ primary,
1977
+ regions = [],
1978
+ outcome,
1979
+ codec
1980
+ }, init = {}) {
1981
+ const frames = primary ? [primary, ...regions] : regions;
1982
+ const headers = new Headers(init.headers);
1983
+ headers.set("Content-Type", "application/x-frame-stream");
1984
+ headers.set(FRAME_STREAM_HEADER, primary ? primary.id : "");
1985
+ headers.set("X-Content-Raw", "1");
1986
+ headers.set(SINGLE_FLIGHT_HEADER, "true");
1987
+ const body = new ReadableStream({
1988
+ async start(controller) {
1989
+ const write = chunk => controller.enqueue(createChunk(JSON.stringify(chunk)));
1990
+ try {
1991
+ for (const {
1992
+ id,
1993
+ component
1994
+ } of frames) {
1995
+ await new Promise(resolve => {
1996
+ renderServerComponent(component, {
1997
+ frame: {
1998
+ id,
1999
+ version: 1
2000
+ }
2001
+ }).pipe({
2002
+ write,
2003
+ end: resolve
2004
+ });
2005
+ });
2006
+ }
2007
+ if (outcome) {
2008
+ const reader = new ChunkReader(serializeStream(outcome, flightCodec(codec)));
2009
+ for (let node = await reader.next(); !node.done; node = await reader.next()) {
2010
+ write({
2011
+ type: "outcome",
2012
+ payload: node.value
2013
+ });
2014
+ }
2015
+ }
2016
+ controller.close();
2017
+ } catch (err) {
2018
+ controller.error(err);
2019
+ }
2020
+ }
2021
+ });
2022
+ return new Response(body, {
2023
+ status: init.status || 200,
2024
+ headers
2025
+ });
2026
+ }
1746
2027
 
1747
2028
  exports.FRAME_STREAM_HEADER = FRAME_STREAM_HEADER;
1748
2029
  exports.SERVER_COMPONENT_BOOTSTRAP = SERVER_COMPONENT_BOOTSTRAP;
1749
2030
  exports.ServerComponentPlugin = ServerComponentPlugin;
1750
2031
  exports.createFrameSink = createFrameSink;
1751
2032
  exports.frameTransformDirectResult = frameTransformDirectResult;
2033
+ exports.frameTransformFlightResult = frameTransformFlightResult;
1752
2034
  exports.frameTransformResult = frameTransformResult;
1753
2035
  exports.isFrameStreamResponse = isFrameStreamResponse;
1754
2036
  exports.renderServerComponent = renderServerComponent;