turbo-stream 2.0.1 → 2.2.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/dist/flatten.d.ts +1 -1
- package/dist/flatten.js +44 -9
- package/dist/turbo-stream.js +11 -2
- package/dist/turbo-stream.mjs +58 -7
- package/dist/unflatten.js +2 -0
- package/dist/utils.d.ts +1 -0
- package/dist/utils.js +2 -1
- package/package.json +1 -1
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,7 +6,7 @@ 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
12
|
if (input === null)
|
|
@@ -90,14 +90,27 @@ function stringify(input, index) {
|
|
|
90
90
|
str[index] = `["${utils_js_1.TYPE_REGEXP}",${JSON.stringify(input.source)},${JSON.stringify(input.flags)}]`;
|
|
91
91
|
}
|
|
92
92
|
else if (input instanceof Set) {
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
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
|
+
}
|
|
96
101
|
}
|
|
97
102
|
else if (input instanceof Map) {
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
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
|
+
}
|
|
101
114
|
}
|
|
102
115
|
else if (input instanceof Promise) {
|
|
103
116
|
str[index] = `["${utils_js_1.TYPE_PROMISE}",${index}]`;
|
|
@@ -122,8 +135,30 @@ function stringify(input, index) {
|
|
|
122
135
|
}
|
|
123
136
|
break;
|
|
124
137
|
}
|
|
125
|
-
default:
|
|
126
|
-
|
|
138
|
+
default: {
|
|
139
|
+
const isArray = Array.isArray(input);
|
|
140
|
+
let pluginHandled = false;
|
|
141
|
+
if (!isArray && plugins) {
|
|
142
|
+
for (const plugin of plugins) {
|
|
143
|
+
const pluginResult = plugin(input);
|
|
144
|
+
if (Array.isArray(pluginResult)) {
|
|
145
|
+
pluginHandled = true;
|
|
146
|
+
const [pluginIdentifier, ...rest] = pluginResult;
|
|
147
|
+
str[index] = `[${JSON.stringify(pluginIdentifier)}`;
|
|
148
|
+
if (rest.length > 0) {
|
|
149
|
+
str[index] += `,${rest
|
|
150
|
+
.map((v) => flatten.call(this, v))
|
|
151
|
+
.join(",")}`;
|
|
152
|
+
}
|
|
153
|
+
str[index] += "]";
|
|
154
|
+
break;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
if (!pluginHandled) {
|
|
159
|
+
throw new Error("Cannot encode function or unexpected type");
|
|
160
|
+
}
|
|
161
|
+
}
|
|
127
162
|
}
|
|
128
163
|
}
|
|
129
164
|
const objectProtoNames = Object.getOwnPropertyNames(Object.prototype)
|
package/dist/turbo-stream.js
CHANGED
|
@@ -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
|
|
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
|
|
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 {
|
package/dist/turbo-stream.mjs
CHANGED
|
@@ -16,6 +16,7 @@ var TYPE_REGEXP = "R";
|
|
|
16
16
|
var TYPE_SET = "S";
|
|
17
17
|
var TYPE_SYMBOL = "Y";
|
|
18
18
|
var TYPE_URL = "U";
|
|
19
|
+
var TYPE_PREVIOUS_RESOLVED = "Z";
|
|
19
20
|
var Deferred = class {
|
|
20
21
|
promise;
|
|
21
22
|
resolve;
|
|
@@ -52,7 +53,7 @@ function flatten(input) {
|
|
|
52
53
|
const { indices } = this;
|
|
53
54
|
const existing = indices.get(input);
|
|
54
55
|
if (existing)
|
|
55
|
-
return existing;
|
|
56
|
+
return [existing];
|
|
56
57
|
if (input === void 0)
|
|
57
58
|
return UNDEFINED;
|
|
58
59
|
if (input === null)
|
|
@@ -129,9 +130,20 @@ function stringify(input, index) {
|
|
|
129
130
|
input.source
|
|
130
131
|
)},${JSON.stringify(input.flags)}]`;
|
|
131
132
|
} else if (input instanceof Set) {
|
|
132
|
-
|
|
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
|
+
}
|
|
133
138
|
} else if (input instanceof Map) {
|
|
134
|
-
|
|
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
|
+
}
|
|
135
147
|
} else if (input instanceof Promise) {
|
|
136
148
|
str[index] = `["${TYPE_PROMISE}",${index}]`;
|
|
137
149
|
deferred[index] = input;
|
|
@@ -151,8 +163,28 @@ function stringify(input, index) {
|
|
|
151
163
|
}
|
|
152
164
|
break;
|
|
153
165
|
}
|
|
154
|
-
default:
|
|
155
|
-
|
|
166
|
+
default: {
|
|
167
|
+
const isArray = Array.isArray(input);
|
|
168
|
+
let pluginHandled = false;
|
|
169
|
+
if (!isArray && plugins) {
|
|
170
|
+
for (const plugin of plugins) {
|
|
171
|
+
const pluginResult = plugin(input);
|
|
172
|
+
if (Array.isArray(pluginResult)) {
|
|
173
|
+
pluginHandled = true;
|
|
174
|
+
const [pluginIdentifier, ...rest] = pluginResult;
|
|
175
|
+
str[index] = `[${JSON.stringify(pluginIdentifier)}`;
|
|
176
|
+
if (rest.length > 0) {
|
|
177
|
+
str[index] += `,${rest.map((v) => flatten.call(this, v)).join(",")}`;
|
|
178
|
+
}
|
|
179
|
+
str[index] += "]";
|
|
180
|
+
break;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
if (!pluginHandled) {
|
|
185
|
+
throw new Error("Cannot encode function or unexpected type");
|
|
186
|
+
}
|
|
187
|
+
}
|
|
156
188
|
}
|
|
157
189
|
}
|
|
158
190
|
var objectProtoNames = Object.getOwnPropertyNames(Object.prototype).sort().join("\0");
|
|
@@ -244,6 +276,8 @@ function hydrate(index) {
|
|
|
244
276
|
let error = errorType && globalObj && globalObj[errorType] ? new globalObj[errorType](message) : new Error(message);
|
|
245
277
|
hydrated[index] = error;
|
|
246
278
|
return error;
|
|
279
|
+
case TYPE_PREVIOUS_RESOLVED:
|
|
280
|
+
return hydrate.call(this, b);
|
|
247
281
|
default:
|
|
248
282
|
if (Array.isArray(plugins)) {
|
|
249
283
|
const args = value.slice(1).map((i) => hydrate.call(this, i));
|
|
@@ -386,6 +420,9 @@ function encode(input, options) {
|
|
|
386
420
|
const readable = new ReadableStream({
|
|
387
421
|
async start(controller) {
|
|
388
422
|
const id = flatten.call(encoder, input);
|
|
423
|
+
if (Array.isArray(id)) {
|
|
424
|
+
throw new Error("This should never happen");
|
|
425
|
+
}
|
|
389
426
|
if (id < 0) {
|
|
390
427
|
controller.enqueue(textEncoder.encode(`${id}
|
|
391
428
|
`));
|
|
@@ -408,7 +445,14 @@ function encode(input, options) {
|
|
|
408
445
|
).then(
|
|
409
446
|
(resolved) => {
|
|
410
447
|
const id2 = flatten.call(encoder, resolved);
|
|
411
|
-
if (id2
|
|
448
|
+
if (Array.isArray(id2)) {
|
|
449
|
+
controller.enqueue(
|
|
450
|
+
textEncoder.encode(
|
|
451
|
+
`${TYPE_PROMISE}${deferredId}:[["${TYPE_PREVIOUS_RESOLVED}",${id2[0]}]]
|
|
452
|
+
`
|
|
453
|
+
)
|
|
454
|
+
);
|
|
455
|
+
} else if (id2 < 0) {
|
|
412
456
|
controller.enqueue(
|
|
413
457
|
textEncoder.encode(`${TYPE_PROMISE}${deferredId}:${id2}
|
|
414
458
|
`)
|
|
@@ -429,7 +473,14 @@ function encode(input, options) {
|
|
|
429
473
|
reason = new Error("An unknown error occurred");
|
|
430
474
|
}
|
|
431
475
|
const id2 = flatten.call(encoder, reason);
|
|
432
|
-
if (id2
|
|
476
|
+
if (Array.isArray(id2)) {
|
|
477
|
+
controller.enqueue(
|
|
478
|
+
textEncoder.encode(
|
|
479
|
+
`${TYPE_ERROR}${deferredId}:[["${TYPE_PREVIOUS_RESOLVED}",${id2[0]}]]
|
|
480
|
+
`
|
|
481
|
+
)
|
|
482
|
+
);
|
|
483
|
+
} else if (id2 < 0) {
|
|
433
484
|
controller.enqueue(
|
|
434
485
|
textEncoder.encode(`${TYPE_ERROR}${deferredId}:${id2}
|
|
435
486
|
`)
|
package/dist/unflatten.js
CHANGED
|
@@ -89,6 +89,8 @@ function hydrate(index) {
|
|
|
89
89
|
: new Error(message);
|
|
90
90
|
hydrated[index] = error;
|
|
91
91
|
return error;
|
|
92
|
+
case utils_js_1.TYPE_PREVIOUS_RESOLVED:
|
|
93
|
+
return hydrate.call(this, b);
|
|
92
94
|
default:
|
|
93
95
|
// Run plugins at the end so we have a chance to resolve primitives
|
|
94
96
|
// without running into a loop
|
package/dist/utils.d.ts
CHANGED
|
@@ -15,6 +15,7 @@ export declare const TYPE_REGEXP = "R";
|
|
|
15
15
|
export declare const TYPE_SET = "S";
|
|
16
16
|
export declare const TYPE_SYMBOL = "Y";
|
|
17
17
|
export declare const TYPE_URL = "U";
|
|
18
|
+
export declare const TYPE_PREVIOUS_RESOLVED = "Z";
|
|
18
19
|
export type DecodePlugin = (type: string, ...data: unknown[]) => {
|
|
19
20
|
value: unknown;
|
|
20
21
|
} | false | null | undefined;
|
package/dist/utils.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
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.NULL = 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
6
|
exports.NEGATIVE_INFINITY = -3;
|
|
@@ -18,6 +18,7 @@ exports.TYPE_REGEXP = "R";
|
|
|
18
18
|
exports.TYPE_SET = "S";
|
|
19
19
|
exports.TYPE_SYMBOL = "Y";
|
|
20
20
|
exports.TYPE_URL = "U";
|
|
21
|
+
exports.TYPE_PREVIOUS_RESOLVED = "Z";
|
|
21
22
|
class Deferred {
|
|
22
23
|
promise;
|
|
23
24
|
resolve;
|
package/package.json
CHANGED