turbo-stream 2.2.3 → 2.4.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.js CHANGED
@@ -26,14 +26,15 @@ function flatten(input) {
26
26
  }
27
27
  exports.flatten = flatten;
28
28
  function stringify(input, index) {
29
- const { deferred, plugins } = this;
29
+ const { deferred, plugins, postPlugins } = this;
30
30
  const str = this.stringified;
31
31
  const stack = [[input, index]];
32
32
  while (stack.length > 0) {
33
33
  const [input, index] = stack.pop();
34
34
  const partsForObj = (obj) => Object.keys(obj)
35
- .map((k) => `"${flatten.call(this, k)}":${flatten.call(this, obj[k])}`)
35
+ .map((k) => `"_${flatten.call(this, k)}":${flatten.call(this, obj[k])}`)
36
36
  .join(",");
37
+ let error = null;
37
38
  switch (typeof input) {
38
39
  case "boolean":
39
40
  case "number":
@@ -45,9 +46,12 @@ function stringify(input, index) {
45
46
  break;
46
47
  case "symbol": {
47
48
  const keyFor = Symbol.keyFor(input);
48
- if (!keyFor)
49
- throw new Error("Cannot encode symbol unless created with Symbol.for()");
50
- str[index] = `["${utils_js_1.TYPE_SYMBOL}",${JSON.stringify(keyFor)}]`;
49
+ if (!keyFor) {
50
+ error = new Error("Cannot encode symbol unless created with Symbol.for()");
51
+ }
52
+ else {
53
+ str[index] = `["${utils_js_1.TYPE_SYMBOL}",${JSON.stringify(keyFor)}]`;
54
+ }
51
55
  break;
52
56
  }
53
57
  case "object": {
@@ -133,7 +137,7 @@ function stringify(input, index) {
133
137
  str[index] = `{${partsForObj(input)}}`;
134
138
  }
135
139
  else {
136
- throw new Error("Cannot encode object with prototype");
140
+ error = new Error("Cannot encode object with prototype");
137
141
  }
138
142
  }
139
143
  break;
@@ -159,10 +163,33 @@ function stringify(input, index) {
159
163
  }
160
164
  }
161
165
  if (!pluginHandled) {
162
- throw new Error("Cannot encode function or unexpected type");
166
+ error = new Error("Cannot encode function or unexpected type");
163
167
  }
164
168
  }
165
169
  }
170
+ if (error) {
171
+ let pluginHandled = false;
172
+ if (postPlugins) {
173
+ for (const plugin of postPlugins) {
174
+ const pluginResult = plugin(input);
175
+ if (Array.isArray(pluginResult)) {
176
+ pluginHandled = true;
177
+ const [pluginIdentifier, ...rest] = pluginResult;
178
+ str[index] = `[${JSON.stringify(pluginIdentifier)}`;
179
+ if (rest.length > 0) {
180
+ str[index] += `,${rest
181
+ .map((v) => flatten.call(this, v))
182
+ .join(",")}`;
183
+ }
184
+ str[index] += "]";
185
+ break;
186
+ }
187
+ }
188
+ }
189
+ if (!pluginHandled) {
190
+ throw error;
191
+ }
192
+ }
166
193
  }
167
194
  }
168
195
  const objectProtoNames = Object.getOwnPropertyNames(Object.prototype)
@@ -8,5 +8,6 @@ export declare function decode(readable: ReadableStream<Uint8Array>, options?: {
8
8
  }>;
9
9
  export declare function encode(input: unknown, options?: {
10
10
  plugins?: EncodePlugin[];
11
+ postPlugins?: EncodePlugin[];
11
12
  signal?: AbortSignal;
12
13
  }): ReadableStream<Uint8Array>;
@@ -107,13 +107,14 @@ async function decodeDeferred(reader) {
107
107
  }
108
108
  }
109
109
  function encode(input, options) {
110
- const { plugins, signal } = options ?? {};
110
+ const { plugins, postPlugins, signal } = options ?? {};
111
111
  const encoder = {
112
112
  deferred: {},
113
113
  index: 0,
114
114
  indices: new Map(),
115
115
  stringified: [],
116
116
  plugins,
117
+ postPlugins,
117
118
  signal,
118
119
  };
119
120
  const textEncoder = new TextEncoder();
@@ -72,12 +72,13 @@ function flatten(input) {
72
72
  return index;
73
73
  }
74
74
  function stringify(input, index) {
75
- const { deferred, plugins } = this;
75
+ const { deferred, plugins, postPlugins } = this;
76
76
  const str = this.stringified;
77
77
  const stack = [[input, index]];
78
78
  while (stack.length > 0) {
79
79
  const [input2, index2] = stack.pop();
80
- const partsForObj = (obj) => Object.keys(obj).map((k) => `"${flatten.call(this, k)}":${flatten.call(this, obj[k])}`).join(",");
80
+ const partsForObj = (obj) => Object.keys(obj).map((k) => `"_${flatten.call(this, k)}":${flatten.call(this, obj[k])}`).join(",");
81
+ let error = null;
81
82
  switch (typeof input2) {
82
83
  case "boolean":
83
84
  case "number":
@@ -89,11 +90,13 @@ function stringify(input, index) {
89
90
  break;
90
91
  case "symbol": {
91
92
  const keyFor = Symbol.keyFor(input2);
92
- if (!keyFor)
93
- throw new Error(
93
+ if (!keyFor) {
94
+ error = new Error(
94
95
  "Cannot encode symbol unless created with Symbol.for()"
95
96
  );
96
- str[index2] = `["${TYPE_SYMBOL}",${JSON.stringify(keyFor)}]`;
97
+ } else {
98
+ str[index2] = `["${TYPE_SYMBOL}",${JSON.stringify(keyFor)}]`;
99
+ }
97
100
  break;
98
101
  }
99
102
  case "object": {
@@ -161,7 +164,7 @@ function stringify(input, index) {
161
164
  } else if (isPlainObject(input2)) {
162
165
  str[index2] = `{${partsForObj(input2)}}`;
163
166
  } else {
164
- throw new Error("Cannot encode object with prototype");
167
+ error = new Error("Cannot encode object with prototype");
165
168
  }
166
169
  }
167
170
  break;
@@ -185,9 +188,30 @@ function stringify(input, index) {
185
188
  }
186
189
  }
187
190
  if (!pluginHandled) {
188
- throw new Error("Cannot encode function or unexpected type");
191
+ error = new Error("Cannot encode function or unexpected type");
192
+ }
193
+ }
194
+ }
195
+ if (error) {
196
+ let pluginHandled = false;
197
+ if (postPlugins) {
198
+ for (const plugin of postPlugins) {
199
+ const pluginResult = plugin(input2);
200
+ if (Array.isArray(pluginResult)) {
201
+ pluginHandled = true;
202
+ const [pluginIdentifier, ...rest] = pluginResult;
203
+ str[index2] = `[${JSON.stringify(pluginIdentifier)}`;
204
+ if (rest.length > 0) {
205
+ str[index2] += `,${rest.map((v) => flatten.call(this, v)).join(",")}`;
206
+ }
207
+ str[index2] += "]";
208
+ break;
209
+ }
189
210
  }
190
211
  }
212
+ if (!pluginHandled) {
213
+ throw error;
214
+ }
191
215
  }
192
216
  }
193
217
  }
@@ -313,7 +337,7 @@ function hydrate(index) {
313
337
  case TYPE_NULL_OBJECT:
314
338
  const obj = /* @__PURE__ */ Object.create(null);
315
339
  hydrated[index2] = obj;
316
- for (const key in b) {
340
+ for (const key of Object.keys(b).reverse()) {
317
341
  const r = [];
318
342
  stack.push([
319
343
  b[key],
@@ -322,7 +346,7 @@ function hydrate(index) {
322
346
  }
323
347
  ]);
324
348
  stack.push([
325
- Number(key),
349
+ Number(key.slice(1)),
326
350
  (k) => {
327
351
  r[0] = k;
328
352
  }
@@ -398,7 +422,7 @@ function hydrate(index) {
398
422
  } else {
399
423
  const object = {};
400
424
  hydrated[index2] = object;
401
- for (const key in value) {
425
+ for (const key of Object.keys(value).reverse()) {
402
426
  const r = [];
403
427
  stack.push([
404
428
  value[key],
@@ -407,7 +431,7 @@ function hydrate(index) {
407
431
  }
408
432
  ]);
409
433
  stack.push([
410
- Number(key),
434
+ Number(key.slice(1)),
411
435
  (k) => {
412
436
  r[0] = k;
413
437
  }
@@ -520,13 +544,14 @@ async function decodeDeferred(reader) {
520
544
  }
521
545
  }
522
546
  function encode(input, options) {
523
- const { plugins, signal } = options ?? {};
547
+ const { plugins, postPlugins, signal } = options ?? {};
524
548
  const encoder = {
525
549
  deferred: {},
526
550
  index: 0,
527
551
  indices: /* @__PURE__ */ new Map(),
528
552
  stringified: [],
529
553
  plugins,
554
+ postPlugins,
530
555
  signal
531
556
  };
532
557
  const textEncoder = new TextEncoder();
package/dist/unflatten.js CHANGED
@@ -122,7 +122,7 @@ function hydrate(index) {
122
122
  case utils_js_1.TYPE_NULL_OBJECT:
123
123
  const obj = Object.create(null);
124
124
  hydrated[index] = obj;
125
- for (const key in b) {
125
+ for (const key of Object.keys(b).reverse()) {
126
126
  const r = [];
127
127
  stack.push([
128
128
  b[key],
@@ -131,7 +131,7 @@ function hydrate(index) {
131
131
  },
132
132
  ]);
133
133
  stack.push([
134
- Number(key),
134
+ Number(key.slice(1)),
135
135
  (k) => {
136
136
  r[0] = k;
137
137
  },
@@ -214,7 +214,7 @@ function hydrate(index) {
214
214
  else {
215
215
  const object = {};
216
216
  hydrated[index] = object;
217
- for (const key in value) {
217
+ for (const key of Object.keys(value).reverse()) {
218
218
  const r = [];
219
219
  stack.push([
220
220
  value[key],
@@ -223,7 +223,7 @@ function hydrate(index) {
223
223
  },
224
224
  ]);
225
225
  stack.push([
226
- Number(key),
226
+ Number(key.slice(1)),
227
227
  (k) => {
228
228
  r[0] = k;
229
229
  },
package/dist/utils.d.ts CHANGED
@@ -32,6 +32,7 @@ export interface ThisEncode {
32
32
  stringified: string[];
33
33
  deferred: Record<number, Promise<unknown>>;
34
34
  plugins?: EncodePlugin[];
35
+ postPlugins?: EncodePlugin[];
35
36
  signal?: AbortSignal;
36
37
  }
37
38
  export declare class Deferred<T = unknown> {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "turbo-stream",
3
- "version": "2.2.3",
3
+ "version": "2.4.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",
@@ -18,7 +18,7 @@
18
18
  "./package.json": "./package.json"
19
19
  },
20
20
  "scripts": {
21
- "build": "pnpm build:esm && pnpm build:cjs",
21
+ "build": "pnpm build:esm && pnpm build:cjs && cp ./dist/turbo-stream.mjs ./viewer/scripts/turbo-stream.js",
22
22
  "build:cjs": "tsc --outDir dist --project tsconfig.lib.json",
23
23
  "build:esm": "esbuild --bundle --platform=node --target=node16 --format=esm --outfile=dist/turbo-stream.mjs src/turbo-stream.ts",
24
24
  "test": "node --no-warnings --loader tsm --enable-source-maps --test-reporter tap --test src/*.spec.ts",