turbo-stream 2.0.0 → 2.1.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.
package/LICENSE ADDED
@@ -0,0 +1,7 @@
1
+ Copyright (c) 2018-19 [these people](https://github.com/rich-harris/devalue/graphs/contributors)
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4
+
5
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6
+
7
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
package/dist/flatten.d.ts CHANGED
@@ -1,2 +1,2 @@
1
1
  import { type ThisEncode } from "./utils.js";
2
- export declare function flatten(this: ThisEncode, input: unknown): number;
2
+ export declare function flatten(this: ThisEncode, input: unknown): number | [number];
package/dist/flatten.js CHANGED
@@ -6,14 +6,16 @@ function flatten(input) {
6
6
  const { indices } = this;
7
7
  const existing = indices.get(input);
8
8
  if (existing)
9
- return existing;
9
+ return [existing];
10
10
  if (input === undefined)
11
11
  return utils_js_1.UNDEFINED;
12
+ if (input === null)
13
+ return utils_js_1.NULL;
12
14
  if (Number.isNaN(input))
13
15
  return utils_js_1.NAN;
14
- if (input === Infinity)
16
+ if (input === Number.POSITIVE_INFINITY)
15
17
  return utils_js_1.POSITIVE_INFINITY;
16
- if (input === -Infinity)
18
+ if (input === Number.NEGATIVE_INFINITY)
17
19
  return utils_js_1.NEGATIVE_INFINITY;
18
20
  if (input === 0 && 1 / input < 0)
19
21
  return utils_js_1.NEGATIVE_ZERO;
@@ -38,15 +40,16 @@ function stringify(input, index) {
38
40
  case "bigint":
39
41
  str[index] = `["${utils_js_1.TYPE_BIGINT}","${input}"]`;
40
42
  break;
41
- case "symbol":
43
+ case "symbol": {
42
44
  const keyFor = Symbol.keyFor(input);
43
45
  if (!keyFor)
44
46
  throw new Error("Cannot encode symbol unless created with Symbol.for()");
45
47
  str[index] = `["${utils_js_1.TYPE_SYMBOL}",${JSON.stringify(keyFor)}]`;
46
48
  break;
47
- case "object":
49
+ }
50
+ case "object": {
48
51
  if (!input) {
49
- str[index] = "null";
52
+ str[index] = `${utils_js_1.NULL}`;
50
53
  break;
51
54
  }
52
55
  const isArray = Array.isArray(input);
@@ -59,8 +62,9 @@ function stringify(input, index) {
59
62
  const [pluginIdentifier, ...rest] = pluginResult;
60
63
  str[index] = `[${JSON.stringify(pluginIdentifier)}`;
61
64
  if (rest.length > 0) {
62
- str[index] +=
63
- "," + rest.map((v) => flatten.call(this, v)).join(",");
65
+ str[index] += `,${rest
66
+ .map((v) => flatten.call(this, v))
67
+ .join(",")}`;
64
68
  }
65
69
  str[index] += "]";
66
70
  break;
@@ -74,7 +78,7 @@ function stringify(input, index) {
74
78
  result +=
75
79
  (i ? "," : "") +
76
80
  (i in input ? flatten.call(this, input[i]) : utils_js_1.HOLE);
77
- str[index] = result + "]";
81
+ str[index] = `${result}]`;
78
82
  }
79
83
  else if (input instanceof Date) {
80
84
  str[index] = `["${utils_js_1.TYPE_DATE}",${input.getTime()}]`;
@@ -86,14 +90,27 @@ function stringify(input, index) {
86
90
  str[index] = `["${utils_js_1.TYPE_REGEXP}",${JSON.stringify(input.source)},${JSON.stringify(input.flags)}]`;
87
91
  }
88
92
  else if (input instanceof Set) {
89
- str[index] = `["${utils_js_1.TYPE_SET}",${[...input]
90
- .map((val) => flatten.call(this, val))
91
- .join(",")}]`;
93
+ if (input.size > 0) {
94
+ str[index] = `["${utils_js_1.TYPE_SET}",${[...input]
95
+ .map((val) => flatten.call(this, val))
96
+ .join(",")}]`;
97
+ }
98
+ else {
99
+ str[index] = `["${utils_js_1.TYPE_SET}"]`;
100
+ }
92
101
  }
93
102
  else if (input instanceof Map) {
94
- str[index] = `["${utils_js_1.TYPE_MAP}",${[...input]
95
- .flatMap(([k, v]) => [flatten.call(this, k), flatten.call(this, v)])
96
- .join(",")}]`;
103
+ if (input.size > 0) {
104
+ str[index] = `["${utils_js_1.TYPE_MAP}",${[...input]
105
+ .flatMap(([k, v]) => [
106
+ flatten.call(this, k),
107
+ flatten.call(this, v),
108
+ ])
109
+ .join(",")}]`;
110
+ }
111
+ else {
112
+ str[index] = `["${utils_js_1.TYPE_MAP}"]`;
113
+ }
97
114
  }
98
115
  else if (input instanceof Promise) {
99
116
  str[index] = `["${utils_js_1.TYPE_PROMISE}",${index}]`;
@@ -117,6 +134,7 @@ function stringify(input, index) {
117
134
  }
118
135
  }
119
136
  break;
137
+ }
120
138
  default:
121
139
  throw new Error("Cannot encode function or unexpected type");
122
140
  }
@@ -121,6 +121,9 @@ function encode(input, options) {
121
121
  const readable = new ReadableStream({
122
122
  async start(controller) {
123
123
  const id = flatten_js_1.flatten.call(encoder, input);
124
+ if (Array.isArray(id)) {
125
+ throw new Error("This should never happen");
126
+ }
124
127
  if (id < 0) {
125
128
  controller.enqueue(textEncoder.encode(`${id}\n`));
126
129
  }
@@ -136,7 +139,10 @@ function encode(input, options) {
136
139
  seenPromises.add((encoder.deferred[Number(deferredId)] = raceSignal(deferred, encoder.signal)
137
140
  .then((resolved) => {
138
141
  const id = flatten_js_1.flatten.call(encoder, resolved);
139
- if (id < 0) {
142
+ if (Array.isArray(id)) {
143
+ controller.enqueue(textEncoder.encode(`${utils_js_1.TYPE_PROMISE}${deferredId}:[["${utils_js_1.TYPE_PREVIOUS_RESOLVED}",${id[0]}]]\n`));
144
+ }
145
+ else if (id < 0) {
140
146
  controller.enqueue(textEncoder.encode(`${utils_js_1.TYPE_PROMISE}${deferredId}:${id}\n`));
141
147
  }
142
148
  else {
@@ -153,7 +159,10 @@ function encode(input, options) {
153
159
  reason = new Error("An unknown error occurred");
154
160
  }
155
161
  const id = flatten_js_1.flatten.call(encoder, reason);
156
- if (id < 0) {
162
+ if (Array.isArray(id)) {
163
+ controller.enqueue(textEncoder.encode(`${utils_js_1.TYPE_ERROR}${deferredId}:[["${utils_js_1.TYPE_PREVIOUS_RESOLVED}",${id[0]}]]\n`));
164
+ }
165
+ else if (id < 0) {
157
166
  controller.enqueue(textEncoder.encode(`${utils_js_1.TYPE_ERROR}${deferredId}:${id}\n`));
158
167
  }
159
168
  else {
@@ -1,10 +1,11 @@
1
1
  // src/utils.ts
2
2
  var HOLE = -1;
3
3
  var NAN = -2;
4
- var NEGATIVE_INFINITY = -4;
5
- var NEGATIVE_ZERO = -5;
6
- var POSITIVE_INFINITY = -3;
7
- var UNDEFINED = -1;
4
+ var NEGATIVE_INFINITY = -3;
5
+ var NEGATIVE_ZERO = -4;
6
+ var NULL = -5;
7
+ var POSITIVE_INFINITY = -6;
8
+ var UNDEFINED = -7;
8
9
  var TYPE_BIGINT = "B";
9
10
  var TYPE_DATE = "D";
10
11
  var TYPE_ERROR = "E";
@@ -15,6 +16,7 @@ var TYPE_REGEXP = "R";
15
16
  var TYPE_SET = "S";
16
17
  var TYPE_SYMBOL = "Y";
17
18
  var TYPE_URL = "U";
19
+ var TYPE_PREVIOUS_RESOLVED = "Z";
18
20
  var Deferred = class {
19
21
  promise;
20
22
  resolve;
@@ -27,12 +29,12 @@ var Deferred = class {
27
29
  }
28
30
  };
29
31
  function createLineSplittingTransform() {
30
- let decoder = new TextDecoder();
32
+ const decoder = new TextDecoder();
31
33
  let leftover = "";
32
34
  return new TransformStream({
33
35
  transform(chunk, controller) {
34
- let str = decoder.decode(chunk, { stream: true });
35
- let parts = (leftover + str).split("\n");
36
+ const str = decoder.decode(chunk, { stream: true });
37
+ const parts = (leftover + str).split("\n");
36
38
  leftover = parts.pop() || "";
37
39
  for (const part of parts) {
38
40
  controller.enqueue(part);
@@ -51,14 +53,16 @@ function flatten(input) {
51
53
  const { indices } = this;
52
54
  const existing = indices.get(input);
53
55
  if (existing)
54
- return existing;
56
+ return [existing];
55
57
  if (input === void 0)
56
58
  return UNDEFINED;
59
+ if (input === null)
60
+ return NULL;
57
61
  if (Number.isNaN(input))
58
62
  return NAN;
59
- if (input === Infinity)
63
+ if (input === Number.POSITIVE_INFINITY)
60
64
  return POSITIVE_INFINITY;
61
- if (input === -Infinity)
65
+ if (input === Number.NEGATIVE_INFINITY)
62
66
  return NEGATIVE_INFINITY;
63
67
  if (input === 0 && 1 / input < 0)
64
68
  return NEGATIVE_ZERO;
@@ -80,7 +84,7 @@ function stringify(input, index) {
80
84
  case "bigint":
81
85
  str[index] = `["${TYPE_BIGINT}","${input}"]`;
82
86
  break;
83
- case "symbol":
87
+ case "symbol": {
84
88
  const keyFor = Symbol.keyFor(input);
85
89
  if (!keyFor)
86
90
  throw new Error(
@@ -88,9 +92,10 @@ function stringify(input, index) {
88
92
  );
89
93
  str[index] = `["${TYPE_SYMBOL}",${JSON.stringify(keyFor)}]`;
90
94
  break;
91
- case "object":
95
+ }
96
+ case "object": {
92
97
  if (!input) {
93
- str[index] = "null";
98
+ str[index] = `${NULL}`;
94
99
  break;
95
100
  }
96
101
  const isArray = Array.isArray(input);
@@ -103,7 +108,7 @@ function stringify(input, index) {
103
108
  const [pluginIdentifier, ...rest] = pluginResult;
104
109
  str[index] = `[${JSON.stringify(pluginIdentifier)}`;
105
110
  if (rest.length > 0) {
106
- str[index] += "," + rest.map((v) => flatten.call(this, v)).join(",");
111
+ str[index] += `,${rest.map((v) => flatten.call(this, v)).join(",")}`;
107
112
  }
108
113
  str[index] += "]";
109
114
  break;
@@ -115,7 +120,7 @@ function stringify(input, index) {
115
120
  if (isArray) {
116
121
  for (let i = 0; i < input.length; i++)
117
122
  result += (i ? "," : "") + (i in input ? flatten.call(this, input[i]) : HOLE);
118
- str[index] = result + "]";
123
+ str[index] = `${result}]`;
119
124
  } else if (input instanceof Date) {
120
125
  str[index] = `["${TYPE_DATE}",${input.getTime()}]`;
121
126
  } else if (input instanceof URL) {
@@ -125,9 +130,20 @@ function stringify(input, index) {
125
130
  input.source
126
131
  )},${JSON.stringify(input.flags)}]`;
127
132
  } else if (input instanceof Set) {
128
- str[index] = `["${TYPE_SET}",${[...input].map((val) => flatten.call(this, val)).join(",")}]`;
133
+ if (input.size > 0) {
134
+ str[index] = `["${TYPE_SET}",${[...input].map((val) => flatten.call(this, val)).join(",")}]`;
135
+ } else {
136
+ str[index] = `["${TYPE_SET}"]`;
137
+ }
129
138
  } else if (input instanceof Map) {
130
- str[index] = `["${TYPE_MAP}",${[...input].flatMap(([k, v]) => [flatten.call(this, k), flatten.call(this, v)]).join(",")}]`;
139
+ if (input.size > 0) {
140
+ str[index] = `["${TYPE_MAP}",${[...input].flatMap(([k, v]) => [
141
+ flatten.call(this, k),
142
+ flatten.call(this, v)
143
+ ]).join(",")}]`;
144
+ } else {
145
+ str[index] = `["${TYPE_MAP}"]`;
146
+ }
131
147
  } else if (input instanceof Promise) {
132
148
  str[index] = `["${TYPE_PROMISE}",${index}]`;
133
149
  deferred[index] = input;
@@ -146,6 +162,7 @@ function stringify(input, index) {
146
162
  }
147
163
  }
148
164
  break;
165
+ }
149
166
  default:
150
167
  throw new Error("Cannot encode function or unexpected type");
151
168
  }
@@ -174,6 +191,8 @@ function hydrate(index) {
174
191
  switch (index) {
175
192
  case UNDEFINED:
176
193
  return;
194
+ case NULL:
195
+ return null;
177
196
  case NAN:
178
197
  return NaN;
179
198
  case POSITIVE_INFINITY:
@@ -237,6 +256,8 @@ function hydrate(index) {
237
256
  let error = errorType && globalObj && globalObj[errorType] ? new globalObj[errorType](message) : new Error(message);
238
257
  hydrated[index] = error;
239
258
  return error;
259
+ case TYPE_PREVIOUS_RESOLVED:
260
+ return hydrate.call(this, b);
240
261
  default:
241
262
  if (Array.isArray(plugins)) {
242
263
  const args = value.slice(1).map((i) => hydrate.call(this, i));
@@ -379,6 +400,9 @@ function encode(input, options) {
379
400
  const readable = new ReadableStream({
380
401
  async start(controller) {
381
402
  const id = flatten.call(encoder, input);
403
+ if (Array.isArray(id)) {
404
+ throw new Error("This should never happen");
405
+ }
382
406
  if (id < 0) {
383
407
  controller.enqueue(textEncoder.encode(`${id}
384
408
  `));
@@ -401,7 +425,14 @@ function encode(input, options) {
401
425
  ).then(
402
426
  (resolved) => {
403
427
  const id2 = flatten.call(encoder, resolved);
404
- if (id2 < 0) {
428
+ if (Array.isArray(id2)) {
429
+ controller.enqueue(
430
+ textEncoder.encode(
431
+ `${TYPE_PROMISE}${deferredId}:[["${TYPE_PREVIOUS_RESOLVED}",${id2[0]}]]
432
+ `
433
+ )
434
+ );
435
+ } else if (id2 < 0) {
405
436
  controller.enqueue(
406
437
  textEncoder.encode(`${TYPE_PROMISE}${deferredId}:${id2}
407
438
  `)
@@ -422,7 +453,14 @@ function encode(input, options) {
422
453
  reason = new Error("An unknown error occurred");
423
454
  }
424
455
  const id2 = flatten.call(encoder, reason);
425
- if (id2 < 0) {
456
+ if (Array.isArray(id2)) {
457
+ controller.enqueue(
458
+ textEncoder.encode(
459
+ `${TYPE_ERROR}${deferredId}:[["${TYPE_PREVIOUS_RESOLVED}",${id2[0]}]]
460
+ `
461
+ )
462
+ );
463
+ } else if (id2 < 0) {
426
464
  controller.enqueue(
427
465
  textEncoder.encode(`${TYPE_ERROR}${deferredId}:${id2}
428
466
  `)
package/dist/unflatten.js CHANGED
@@ -24,6 +24,8 @@ function hydrate(index) {
24
24
  switch (index) {
25
25
  case utils_js_1.UNDEFINED:
26
26
  return;
27
+ case utils_js_1.NULL:
28
+ return null;
27
29
  case utils_js_1.NAN:
28
30
  return NaN;
29
31
  case utils_js_1.POSITIVE_INFINITY:
@@ -87,6 +89,8 @@ function hydrate(index) {
87
89
  : new Error(message);
88
90
  hydrated[index] = error;
89
91
  return error;
92
+ case utils_js_1.TYPE_PREVIOUS_RESOLVED:
93
+ return hydrate.call(this, b);
90
94
  default:
91
95
  // Run plugins at the end so we have a chance to resolve primitives
92
96
  // without running into a loop
package/dist/utils.d.ts CHANGED
@@ -1,9 +1,10 @@
1
1
  export declare const HOLE = -1;
2
2
  export declare const NAN = -2;
3
- export declare const NEGATIVE_INFINITY = -4;
4
- export declare const NEGATIVE_ZERO = -5;
5
- export declare const POSITIVE_INFINITY = -3;
6
- export declare const UNDEFINED = -1;
3
+ export declare const NEGATIVE_INFINITY = -3;
4
+ export declare const NEGATIVE_ZERO = -4;
5
+ export declare const NULL = -5;
6
+ export declare const POSITIVE_INFINITY = -6;
7
+ export declare const UNDEFINED = -7;
7
8
  export declare const TYPE_BIGINT = "B";
8
9
  export declare const TYPE_DATE = "D";
9
10
  export declare const TYPE_ERROR = "E";
@@ -14,6 +15,7 @@ export declare const TYPE_REGEXP = "R";
14
15
  export declare const TYPE_SET = "S";
15
16
  export declare const TYPE_SYMBOL = "Y";
16
17
  export declare const TYPE_URL = "U";
18
+ export declare const TYPE_PREVIOUS_RESOLVED = "Z";
17
19
  export type DecodePlugin = (type: string, ...data: unknown[]) => {
18
20
  value: unknown;
19
21
  } | false | null | undefined;
package/dist/utils.js CHANGED
@@ -1,12 +1,13 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.createLineSplittingTransform = exports.Deferred = exports.TYPE_URL = exports.TYPE_SYMBOL = exports.TYPE_SET = exports.TYPE_REGEXP = exports.TYPE_PROMISE = exports.TYPE_NULL_OBJECT = exports.TYPE_MAP = exports.TYPE_ERROR = exports.TYPE_DATE = exports.TYPE_BIGINT = exports.UNDEFINED = exports.POSITIVE_INFINITY = exports.NEGATIVE_ZERO = exports.NEGATIVE_INFINITY = exports.NAN = exports.HOLE = void 0;
3
+ exports.createLineSplittingTransform = exports.Deferred = exports.TYPE_PREVIOUS_RESOLVED = exports.TYPE_URL = exports.TYPE_SYMBOL = exports.TYPE_SET = exports.TYPE_REGEXP = exports.TYPE_PROMISE = exports.TYPE_NULL_OBJECT = exports.TYPE_MAP = exports.TYPE_ERROR = exports.TYPE_DATE = exports.TYPE_BIGINT = exports.UNDEFINED = exports.POSITIVE_INFINITY = exports.NULL = exports.NEGATIVE_ZERO = exports.NEGATIVE_INFINITY = exports.NAN = exports.HOLE = void 0;
4
4
  exports.HOLE = -1;
5
5
  exports.NAN = -2;
6
- exports.NEGATIVE_INFINITY = -4;
7
- exports.NEGATIVE_ZERO = -5;
8
- exports.POSITIVE_INFINITY = -3;
9
- exports.UNDEFINED = -1;
6
+ exports.NEGATIVE_INFINITY = -3;
7
+ exports.NEGATIVE_ZERO = -4;
8
+ exports.NULL = -5;
9
+ exports.POSITIVE_INFINITY = -6;
10
+ exports.UNDEFINED = -7;
10
11
  exports.TYPE_BIGINT = "B";
11
12
  exports.TYPE_DATE = "D";
12
13
  exports.TYPE_ERROR = "E";
@@ -17,6 +18,7 @@ exports.TYPE_REGEXP = "R";
17
18
  exports.TYPE_SET = "S";
18
19
  exports.TYPE_SYMBOL = "Y";
19
20
  exports.TYPE_URL = "U";
21
+ exports.TYPE_PREVIOUS_RESOLVED = "Z";
20
22
  class Deferred {
21
23
  promise;
22
24
  resolve;
@@ -30,12 +32,12 @@ class Deferred {
30
32
  }
31
33
  exports.Deferred = Deferred;
32
34
  function createLineSplittingTransform() {
33
- let decoder = new TextDecoder();
35
+ const decoder = new TextDecoder();
34
36
  let leftover = "";
35
37
  return new TransformStream({
36
38
  transform(chunk, controller) {
37
- let str = decoder.decode(chunk, { stream: true });
38
- let parts = (leftover + str).split("\n");
39
+ const str = decoder.decode(chunk, { stream: true });
40
+ const parts = (leftover + str).split("\n");
39
41
  // The last part might be a partial line, so keep it for the next chunk.
40
42
  leftover = parts.pop() || "";
41
43
  for (const part of parts) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "turbo-stream",
3
- "version": "2.0.0",
3
+ "version": "2.1.0",
4
4
  "description": "A streaming data transport format that aims to support built-in features such as Promises, Dates, RegExps, Maps, Sets and more.",
5
5
  "files": [
6
6
  "dist",