turbo-stream 0.0.6 → 0.0.8
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/README.md +3 -3
- package/dist/flatten.js +15 -1
- package/dist/turbo-stream.js +39 -8
- package/dist/unflatten.js +20 -1
- package/dist/utils.d.ts +1 -0
- package/dist/utils.js +1 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -18,10 +18,10 @@ npm install turbo-stream
|
|
|
18
18
|
```js
|
|
19
19
|
import { decode, encode } from "turbo-stream";
|
|
20
20
|
|
|
21
|
-
const encodedStream = encode(
|
|
21
|
+
const encodedStream = encode(Promise.resolve(42));
|
|
22
22
|
const decoded = await decode(encodedStream);
|
|
23
|
-
console.log(decoded.value
|
|
24
|
-
console.log(await decoded.value
|
|
23
|
+
console.log(decoded.value); // a Promise
|
|
24
|
+
console.log(await decoded.value); // 42
|
|
25
25
|
await decoded.done; // wait for the stream to finish
|
|
26
26
|
```
|
|
27
27
|
|
package/dist/flatten.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { HOLE, NAN, NEGATIVE_INFINITY, NEGATIVE_ZERO, POSITIVE_INFINITY, TYPE_BIGINT, TYPE_DATE, TYPE_MAP, TYPE_PROMISE, TYPE_REGEXP, TYPE_SET, TYPE_SYMBOL, UNDEFINED, } from "./utils.js";
|
|
1
|
+
import { HOLE, NAN, NEGATIVE_INFINITY, NEGATIVE_ZERO, POSITIVE_INFINITY, TYPE_BIGINT, TYPE_DATE, TYPE_ERROR, TYPE_MAP, TYPE_NULL_OBJECT, TYPE_PROMISE, TYPE_REGEXP, TYPE_SET, TYPE_SYMBOL, UNDEFINED, } from "./utils.js";
|
|
2
2
|
export function flatten(input) {
|
|
3
3
|
const existing = this.indicies.get(input);
|
|
4
4
|
if (existing)
|
|
@@ -67,6 +67,20 @@ function stringify(input, index) {
|
|
|
67
67
|
str[index] = `["${TYPE_PROMISE}",${index}]`;
|
|
68
68
|
this.deferred[index] = input;
|
|
69
69
|
}
|
|
70
|
+
else if (input instanceof Error) {
|
|
71
|
+
str[index] = `["${TYPE_ERROR}",${JSON.stringify(input.message)}`;
|
|
72
|
+
if (input.name !== "Error") {
|
|
73
|
+
str[index] += `,${JSON.stringify(input.name)}`;
|
|
74
|
+
}
|
|
75
|
+
str[index] += "]";
|
|
76
|
+
}
|
|
77
|
+
else if (Object.getPrototypeOf(input) === null) {
|
|
78
|
+
str[index] = `["${TYPE_NULL_OBJECT}"`;
|
|
79
|
+
const parts = [];
|
|
80
|
+
for (const key in input)
|
|
81
|
+
parts.push(`${JSON.stringify(key)}:${flatten.call(this, input[key])}`);
|
|
82
|
+
str[index] += ",{" + parts.join(",") + "}]";
|
|
83
|
+
}
|
|
70
84
|
else if (isPlainObject(input)) {
|
|
71
85
|
const parts = [];
|
|
72
86
|
for (const key in input)
|
package/dist/turbo-stream.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { flatten } from "./flatten.js";
|
|
2
2
|
import { unflatten } from "./unflatten.js";
|
|
3
|
-
import { createLineSplittingTransform, Deferred, TYPE_PROMISE, } from "./utils.js";
|
|
3
|
+
import { createLineSplittingTransform, Deferred, TYPE_PROMISE, TYPE_ERROR, } from "./utils.js";
|
|
4
4
|
export async function decode(readable) {
|
|
5
5
|
const done = new Deferred();
|
|
6
6
|
const reader = readable
|
|
@@ -56,7 +56,7 @@ async function decodeDeferred(reader) {
|
|
|
56
56
|
continue;
|
|
57
57
|
const line = read.value;
|
|
58
58
|
switch (line[0]) {
|
|
59
|
-
case TYPE_PROMISE:
|
|
59
|
+
case TYPE_PROMISE: {
|
|
60
60
|
const colonIndex = line.indexOf(":");
|
|
61
61
|
const deferredId = Number(line.slice(1, colonIndex));
|
|
62
62
|
const deferred = this.deferred[deferredId];
|
|
@@ -74,9 +74,26 @@ async function decodeDeferred(reader) {
|
|
|
74
74
|
const value = unflatten.call(this, jsonLine);
|
|
75
75
|
deferred.resolve(value);
|
|
76
76
|
break;
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
77
|
+
}
|
|
78
|
+
case TYPE_ERROR: {
|
|
79
|
+
const colonIndex = line.indexOf(":");
|
|
80
|
+
const deferredId = Number(line.slice(1, colonIndex));
|
|
81
|
+
const deferred = this.deferred[deferredId];
|
|
82
|
+
if (!deferred) {
|
|
83
|
+
throw new Error(`Deferred ID ${deferredId} not found in stream`);
|
|
84
|
+
}
|
|
85
|
+
const lineData = line.slice(colonIndex + 1);
|
|
86
|
+
let jsonLine;
|
|
87
|
+
try {
|
|
88
|
+
jsonLine = JSON.parse(lineData);
|
|
89
|
+
}
|
|
90
|
+
catch (reason) {
|
|
91
|
+
throw new SyntaxError();
|
|
92
|
+
}
|
|
93
|
+
const value = unflatten.call(this, jsonLine);
|
|
94
|
+
deferred.reject(value);
|
|
95
|
+
break;
|
|
96
|
+
}
|
|
80
97
|
default:
|
|
81
98
|
throw new SyntaxError();
|
|
82
99
|
}
|
|
@@ -94,7 +111,7 @@ export function encode(input) {
|
|
|
94
111
|
let lastSentIndex = 0;
|
|
95
112
|
const readable = new ReadableStream({
|
|
96
113
|
async start(controller) {
|
|
97
|
-
const id = flatten.call(encoder,
|
|
114
|
+
const id = flatten.call(encoder, input);
|
|
98
115
|
if (id < 0) {
|
|
99
116
|
controller.enqueue(textEncoder.encode(`${id}\n`));
|
|
100
117
|
}
|
|
@@ -121,8 +138,22 @@ export function encode(input) {
|
|
|
121
138
|
lastSentIndex = encoder.stringified.length - 1;
|
|
122
139
|
}
|
|
123
140
|
}, (reason) => {
|
|
124
|
-
|
|
125
|
-
|
|
141
|
+
if (!reason ||
|
|
142
|
+
typeof reason !== "object" ||
|
|
143
|
+
!(reason instanceof Error)) {
|
|
144
|
+
reason = new Error("An unknown error occurred");
|
|
145
|
+
}
|
|
146
|
+
const id = flatten.call(encoder, reason);
|
|
147
|
+
if (id < 0) {
|
|
148
|
+
controller.enqueue(textEncoder.encode(`${TYPE_ERROR}${deferredId}:${id}\n`));
|
|
149
|
+
}
|
|
150
|
+
else {
|
|
151
|
+
const values = encoder.stringified
|
|
152
|
+
.slice(lastSentIndex + 1)
|
|
153
|
+
.join(",");
|
|
154
|
+
controller.enqueue(textEncoder.encode(`${TYPE_ERROR}${deferredId}:[${values}]\n`));
|
|
155
|
+
lastSentIndex = encoder.stringified.length - 1;
|
|
156
|
+
}
|
|
126
157
|
})
|
|
127
158
|
.finally(() => {
|
|
128
159
|
delete encoder.deferred[Number(deferredId)];
|
package/dist/unflatten.js
CHANGED
|
@@ -1,4 +1,9 @@
|
|
|
1
|
-
import { Deferred, HOLE, NAN, NEGATIVE_INFINITY, NEGATIVE_ZERO, POSITIVE_INFINITY, TYPE_BIGINT, TYPE_DATE, TYPE_MAP, TYPE_PROMISE, TYPE_REGEXP, TYPE_SET, TYPE_SYMBOL, UNDEFINED, } from "./utils.js";
|
|
1
|
+
import { Deferred, HOLE, NAN, NEGATIVE_INFINITY, NEGATIVE_ZERO, POSITIVE_INFINITY, TYPE_BIGINT, TYPE_DATE, TYPE_MAP, TYPE_PROMISE, TYPE_REGEXP, TYPE_SET, TYPE_SYMBOL, UNDEFINED, TYPE_ERROR, TYPE_NULL_OBJECT, } from "./utils.js";
|
|
2
|
+
const globalObj = (typeof window !== "undefined"
|
|
3
|
+
? window
|
|
4
|
+
: typeof globalThis !== "undefined"
|
|
5
|
+
? globalThis
|
|
6
|
+
: undefined);
|
|
2
7
|
export function unflatten(parsed) {
|
|
3
8
|
if (typeof parsed === "number")
|
|
4
9
|
return hydrate.call(this, parsed);
|
|
@@ -52,6 +57,13 @@ function hydrate(index) {
|
|
|
52
57
|
map.set(hydrate.call(this, value[i]), hydrate.call(this, value[i + 1]));
|
|
53
58
|
}
|
|
54
59
|
return map;
|
|
60
|
+
case TYPE_NULL_OBJECT:
|
|
61
|
+
console.log({ value });
|
|
62
|
+
const obj = Object.create(null);
|
|
63
|
+
hydrated[index] = obj;
|
|
64
|
+
for (const key in value[1])
|
|
65
|
+
obj[key] = hydrate.call(this, value[1][key]);
|
|
66
|
+
return obj;
|
|
55
67
|
case TYPE_PROMISE:
|
|
56
68
|
if (hydrated[value[1]]) {
|
|
57
69
|
return (hydrated[index] = hydrated[value[1]]);
|
|
@@ -61,6 +73,13 @@ function hydrate(index) {
|
|
|
61
73
|
deferred[value[1]] = d;
|
|
62
74
|
return (hydrated[index] = d.promise);
|
|
63
75
|
}
|
|
76
|
+
case TYPE_ERROR:
|
|
77
|
+
const [, message, errorType] = value;
|
|
78
|
+
let error = errorType && globalObj && globalObj[errorType]
|
|
79
|
+
? new globalObj[errorType](message)
|
|
80
|
+
: new Error(message);
|
|
81
|
+
hydrated[index] = error;
|
|
82
|
+
return error;
|
|
64
83
|
default:
|
|
65
84
|
throw new SyntaxError();
|
|
66
85
|
}
|
package/dist/utils.d.ts
CHANGED
|
@@ -12,6 +12,7 @@ export declare const TYPE_REGEXP = "R";
|
|
|
12
12
|
export declare const TYPE_SYMBOL = "Y";
|
|
13
13
|
export declare const TYPE_NULL_OBJECT = "N";
|
|
14
14
|
export declare const TYPE_PROMISE = "P";
|
|
15
|
+
export declare const TYPE_ERROR = "E";
|
|
15
16
|
export interface ThisDecode {
|
|
16
17
|
values: unknown[];
|
|
17
18
|
hydrated: unknown[];
|
package/dist/utils.js
CHANGED
package/package.json
CHANGED