@solidjs/web 2.0.0-beta.2 → 2.0.0-beta.20
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 +27 -4
- package/dist/dev.cjs +783 -223
- package/dist/dev.js +757 -217
- package/dist/server.cjs +742 -186
- package/dist/server.js +714 -183
- package/dist/web.cjs +772 -196
- package/dist/web.js +746 -190
- package/package.json +193 -38
- package/serialization/dist/serialization.cjs +83 -0
- package/serialization/dist/serialization.js +75 -0
- package/serialization/package.json +20 -0
- package/serialization/types/index.d.ts +139 -0
- package/serialization/types-cjs/index.d.cts +139 -0
- package/serialization/types-cjs/package.json +3 -0
- package/server-functions/dist/client.cjs +370 -0
- package/server-functions/dist/client.js +363 -0
- package/server-functions/dist/server.cjs +542 -0
- package/server-functions/dist/server.js +531 -0
- package/server-functions/package.json +30 -0
- package/storage/package.json +8 -3
- package/storage/types/index.d.ts +26 -0
- package/storage/types-cjs/index.d.cts +28 -0
- package/storage/types-cjs/package.json +3 -0
- package/types/client.d.ts +64 -21
- package/types/core.d.ts +3 -3
- package/types/index.d.ts +156 -24
- package/types/jsx-properties.d.ts +93 -0
- package/types/jsx.d.ts +4135 -1
- package/types/response.d.ts +93 -0
- package/types/serializer.d.ts +139 -0
- package/types/server-functions/client.d.ts +63 -0
- package/types/server-functions/server.d.ts +188 -0
- package/types/server-functions/shared.d.ts +171 -0
- package/types/server-mock.d.ts +89 -0
- package/types/server.d.ts +123 -28
- package/types-cjs/client.d.cts +131 -0
- package/types-cjs/core.d.cts +3 -0
- package/types-cjs/index.d.cts +178 -0
- package/types-cjs/jsx-properties.d.cts +93 -0
- package/types-cjs/jsx.d.cts +4135 -0
- package/types-cjs/package.json +3 -0
- package/types-cjs/response.d.cts +93 -0
- package/types-cjs/serializer.d.cts +139 -0
- package/types-cjs/server-functions/client.d.cts +63 -0
- package/types-cjs/server-functions/server.d.cts +188 -0
- package/types-cjs/server-functions/shared.d.cts +171 -0
- package/types-cjs/server-mock.d.cts +161 -0
- package/types-cjs/server.d.cts +251 -0
- package/storage/types/src/client.d.ts +0 -1
- package/storage/types/src/index.d.ts +0 -46
- package/storage/types/src/server-mock.d.ts +0 -72
- package/storage/types/storage/src/index.d.ts +0 -2
|
@@ -0,0 +1,363 @@
|
|
|
1
|
+
import { fromCrossJSON, Feature, toCrossJSONStream } from 'seroval';
|
|
2
|
+
import { AbortSignalPlugin, CustomEventPlugin, DOMExceptionPlugin, EventPlugin, FormDataPlugin, HeadersPlugin, ReadableStreamPlugin, RequestPlugin, ResponsePlugin, URLSearchParamsPlugin, URLPlugin } from 'seroval-plugins/web';
|
|
3
|
+
|
|
4
|
+
Feature.AggregateError | Feature.BigIntTypedArray;
|
|
5
|
+
const DEFAULT_WEB_PLUGINS = Object.freeze([AbortSignalPlugin,
|
|
6
|
+
CustomEventPlugin, DOMExceptionPlugin, EventPlugin,
|
|
7
|
+
FormDataPlugin, HeadersPlugin, ReadableStreamPlugin, RequestPlugin, ResponsePlugin, URLSearchParamsPlugin, URLPlugin]);
|
|
8
|
+
function resolveSerializerPlugins(customPlugins) {
|
|
9
|
+
return customPlugins ? [...customPlugins, ...DEFAULT_WEB_PLUGINS] : [...DEFAULT_WEB_PLUGINS];
|
|
10
|
+
}
|
|
11
|
+
const JSON_CODEC_DISABLED_FEATURES = Feature.RegExp;
|
|
12
|
+
const JSON_CODEC_DEPTH_LIMIT = 64;
|
|
13
|
+
function resolveCodecOptions({
|
|
14
|
+
plugins,
|
|
15
|
+
disabledFeatures,
|
|
16
|
+
depthLimit
|
|
17
|
+
} = {}) {
|
|
18
|
+
return {
|
|
19
|
+
plugins: resolveSerializerPlugins(plugins),
|
|
20
|
+
disabledFeatures: disabledFeatures === undefined ? JSON_CODEC_DISABLED_FEATURES : disabledFeatures,
|
|
21
|
+
depthLimit: depthLimit === undefined ? JSON_CODEC_DEPTH_LIMIT : depthLimit
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
function serializeJSON(value, {
|
|
25
|
+
onParse,
|
|
26
|
+
onDone,
|
|
27
|
+
onError,
|
|
28
|
+
...codecOptions
|
|
29
|
+
}) {
|
|
30
|
+
return toCrossJSONStream(value, {
|
|
31
|
+
onParse,
|
|
32
|
+
onDone,
|
|
33
|
+
onError,
|
|
34
|
+
...resolveCodecOptions(codecOptions)
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
function createJSONDeserializer(options) {
|
|
38
|
+
const refs = new Map();
|
|
39
|
+
const resolved = resolveCodecOptions(options);
|
|
40
|
+
return function deserializeJSONChunk(node) {
|
|
41
|
+
return fromCrossJSON(node, {
|
|
42
|
+
refs,
|
|
43
|
+
...resolved
|
|
44
|
+
});
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const codecConfig = {
|
|
49
|
+
codec: undefined
|
|
50
|
+
};
|
|
51
|
+
function configureServerFunctionsCodec(codec) {
|
|
52
|
+
codecConfig.codec = codec;
|
|
53
|
+
}
|
|
54
|
+
function getServerFunctionsCodec() {
|
|
55
|
+
return codecConfig.codec;
|
|
56
|
+
}
|
|
57
|
+
const FUNCTION_HEADER = "X-Server-Function-Id";
|
|
58
|
+
const INSTANCE_HEADER = "X-Server-Function-Instance";
|
|
59
|
+
const BODY_FORMAT_HEADER = "X-Server-Function-Format";
|
|
60
|
+
const FILE_FORM_KEY = "__server_function_file__";
|
|
61
|
+
const BodyFormat = {
|
|
62
|
+
Serialized: "0",
|
|
63
|
+
String: "1",
|
|
64
|
+
FormData: "2",
|
|
65
|
+
URLSearchParams: "3",
|
|
66
|
+
Blob: "4",
|
|
67
|
+
File: "5",
|
|
68
|
+
ArrayBuffer: "6",
|
|
69
|
+
Uint8Array: "7"
|
|
70
|
+
};
|
|
71
|
+
function getHeadersAndBody(body) {
|
|
72
|
+
switch (true) {
|
|
73
|
+
case typeof body === "string":
|
|
74
|
+
return {
|
|
75
|
+
headers: {
|
|
76
|
+
"Content-Type": "text/plain",
|
|
77
|
+
[BODY_FORMAT_HEADER]: BodyFormat.String
|
|
78
|
+
},
|
|
79
|
+
body
|
|
80
|
+
};
|
|
81
|
+
case body instanceof FormData:
|
|
82
|
+
return {
|
|
83
|
+
headers: {
|
|
84
|
+
[BODY_FORMAT_HEADER]: BodyFormat.FormData
|
|
85
|
+
},
|
|
86
|
+
body
|
|
87
|
+
};
|
|
88
|
+
case body instanceof URLSearchParams:
|
|
89
|
+
return {
|
|
90
|
+
headers: {
|
|
91
|
+
"Content-Type": "application/x-www-form-urlencoded",
|
|
92
|
+
[BODY_FORMAT_HEADER]: BodyFormat.URLSearchParams
|
|
93
|
+
},
|
|
94
|
+
body
|
|
95
|
+
};
|
|
96
|
+
case typeof File !== "undefined" && body instanceof File:
|
|
97
|
+
{
|
|
98
|
+
const formData = new FormData();
|
|
99
|
+
formData.append(FILE_FORM_KEY, body, body.name);
|
|
100
|
+
return {
|
|
101
|
+
headers: {
|
|
102
|
+
[BODY_FORMAT_HEADER]: BodyFormat.File
|
|
103
|
+
},
|
|
104
|
+
body: formData
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
case body instanceof Blob:
|
|
108
|
+
return {
|
|
109
|
+
headers: {
|
|
110
|
+
[BODY_FORMAT_HEADER]: BodyFormat.Blob
|
|
111
|
+
},
|
|
112
|
+
body
|
|
113
|
+
};
|
|
114
|
+
case body instanceof ArrayBuffer:
|
|
115
|
+
return {
|
|
116
|
+
headers: {
|
|
117
|
+
[BODY_FORMAT_HEADER]: BodyFormat.ArrayBuffer
|
|
118
|
+
},
|
|
119
|
+
body
|
|
120
|
+
};
|
|
121
|
+
case body instanceof Uint8Array:
|
|
122
|
+
return {
|
|
123
|
+
headers: {
|
|
124
|
+
[BODY_FORMAT_HEADER]: BodyFormat.Uint8Array
|
|
125
|
+
},
|
|
126
|
+
body: new Uint8Array(body)
|
|
127
|
+
};
|
|
128
|
+
default:
|
|
129
|
+
return undefined;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
async function extractBody(source, codecOptions) {
|
|
133
|
+
const contentType = source.headers.get("content-type");
|
|
134
|
+
const format = source.headers.get(BODY_FORMAT_HEADER);
|
|
135
|
+
const clone = source.clone();
|
|
136
|
+
switch (true) {
|
|
137
|
+
case format === BodyFormat.Serialized:
|
|
138
|
+
return await deserializeStream(clone, codecOptions);
|
|
139
|
+
case format === BodyFormat.String:
|
|
140
|
+
return await clone.text();
|
|
141
|
+
case format === BodyFormat.File:
|
|
142
|
+
{
|
|
143
|
+
const formData = await clone.formData();
|
|
144
|
+
return formData.get(FILE_FORM_KEY);
|
|
145
|
+
}
|
|
146
|
+
case format === BodyFormat.FormData:
|
|
147
|
+
case contentType && contentType.startsWith("multipart/form-data"):
|
|
148
|
+
return await clone.formData();
|
|
149
|
+
case format === BodyFormat.URLSearchParams:
|
|
150
|
+
case contentType && contentType.startsWith("application/x-www-form-urlencoded"):
|
|
151
|
+
return new URLSearchParams(await clone.text());
|
|
152
|
+
case format === BodyFormat.Blob:
|
|
153
|
+
return await clone.blob();
|
|
154
|
+
case format === BodyFormat.ArrayBuffer:
|
|
155
|
+
return await clone.arrayBuffer();
|
|
156
|
+
case format === BodyFormat.Uint8Array:
|
|
157
|
+
return new Uint8Array(await clone.arrayBuffer());
|
|
158
|
+
}
|
|
159
|
+
return undefined;
|
|
160
|
+
}
|
|
161
|
+
function createChunk(data) {
|
|
162
|
+
const encodeData = new TextEncoder().encode(data);
|
|
163
|
+
const bytes = encodeData.length;
|
|
164
|
+
const baseHex = bytes.toString(16);
|
|
165
|
+
const totalHex = "00000000".substring(0, 8 - baseHex.length) + baseHex;
|
|
166
|
+
const head = new TextEncoder().encode(`;0x${totalHex};`);
|
|
167
|
+
const chunk = new Uint8Array(12 + bytes);
|
|
168
|
+
chunk.set(head);
|
|
169
|
+
chunk.set(encodeData, 12);
|
|
170
|
+
return chunk;
|
|
171
|
+
}
|
|
172
|
+
class ChunkReader {
|
|
173
|
+
constructor(stream) {
|
|
174
|
+
this.reader = stream.getReader();
|
|
175
|
+
this.buffer = new Uint8Array(0);
|
|
176
|
+
this.done = false;
|
|
177
|
+
}
|
|
178
|
+
async readChunk() {
|
|
179
|
+
const chunk = await this.reader.read();
|
|
180
|
+
if (!chunk.done) {
|
|
181
|
+
const newBuffer = new Uint8Array(this.buffer.length + chunk.value.length);
|
|
182
|
+
newBuffer.set(this.buffer);
|
|
183
|
+
newBuffer.set(chunk.value, this.buffer.length);
|
|
184
|
+
this.buffer = newBuffer;
|
|
185
|
+
} else {
|
|
186
|
+
this.done = true;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
async next() {
|
|
190
|
+
if (this.buffer.length === 0) {
|
|
191
|
+
if (this.done) {
|
|
192
|
+
return {
|
|
193
|
+
done: true,
|
|
194
|
+
value: undefined
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
await this.readChunk();
|
|
198
|
+
return await this.next();
|
|
199
|
+
}
|
|
200
|
+
const head = new TextDecoder().decode(this.buffer.subarray(1, 11));
|
|
201
|
+
const bytes = Number.parseInt(head, 16);
|
|
202
|
+
if (Number.isNaN(bytes)) {
|
|
203
|
+
throw new Error("Malformed server function stream.");
|
|
204
|
+
}
|
|
205
|
+
while (bytes > this.buffer.length - 12) {
|
|
206
|
+
if (this.done) {
|
|
207
|
+
throw new Error("Malformed server function stream.");
|
|
208
|
+
}
|
|
209
|
+
await this.readChunk();
|
|
210
|
+
}
|
|
211
|
+
const partial = new TextDecoder().decode(this.buffer.subarray(12, 12 + bytes));
|
|
212
|
+
this.buffer = this.buffer.subarray(12 + bytes);
|
|
213
|
+
return {
|
|
214
|
+
done: false,
|
|
215
|
+
value: partial
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
async drain(interpret) {
|
|
219
|
+
while (true) {
|
|
220
|
+
const result = await this.next();
|
|
221
|
+
if (result.done) {
|
|
222
|
+
break;
|
|
223
|
+
}
|
|
224
|
+
interpret(result.value);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
function serializeStream(value, codecOptions) {
|
|
229
|
+
return new ReadableStream({
|
|
230
|
+
start(controller) {
|
|
231
|
+
serializeJSON(value, {
|
|
232
|
+
...codecOptions,
|
|
233
|
+
onParse(node) {
|
|
234
|
+
controller.enqueue(createChunk(JSON.stringify(node)));
|
|
235
|
+
},
|
|
236
|
+
onDone() {
|
|
237
|
+
controller.close();
|
|
238
|
+
},
|
|
239
|
+
onError(error) {
|
|
240
|
+
controller.error(error);
|
|
241
|
+
}
|
|
242
|
+
});
|
|
243
|
+
}
|
|
244
|
+
});
|
|
245
|
+
}
|
|
246
|
+
async function serializeString(value, codecOptions) {
|
|
247
|
+
const response = new Response(serializeStream(value, codecOptions));
|
|
248
|
+
return await response.text();
|
|
249
|
+
}
|
|
250
|
+
async function deserializeStream(source, codecOptions) {
|
|
251
|
+
if (!source.body) {
|
|
252
|
+
throw new Error("missing body");
|
|
253
|
+
}
|
|
254
|
+
const reader = new ChunkReader(source.body);
|
|
255
|
+
const result = await reader.next();
|
|
256
|
+
if (!result.done) {
|
|
257
|
+
const deserializeChunk = createJSONDeserializer(codecOptions);
|
|
258
|
+
function interpretChunk(chunk) {
|
|
259
|
+
return deserializeChunk(JSON.parse(chunk));
|
|
260
|
+
}
|
|
261
|
+
void reader.drain(interpretChunk);
|
|
262
|
+
return interpretChunk(result.value);
|
|
263
|
+
}
|
|
264
|
+
return undefined;
|
|
265
|
+
}
|
|
266
|
+
async function decodeResponse(response, codecOptions) {
|
|
267
|
+
if (!response.body) return undefined;
|
|
268
|
+
return await extractBody(response, codecOptions === undefined ? codecConfig.codec : codecOptions);
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
const config = {
|
|
272
|
+
endpoint: "/_server"
|
|
273
|
+
};
|
|
274
|
+
function configureServerFunctionsClient({
|
|
275
|
+
endpoint,
|
|
276
|
+
codec
|
|
277
|
+
} = {}) {
|
|
278
|
+
if (endpoint !== undefined) config.endpoint = endpoint;
|
|
279
|
+
if (codec !== undefined) configureServerFunctionsCodec(codec);
|
|
280
|
+
}
|
|
281
|
+
let INSTANCE = 0;
|
|
282
|
+
function createRequest(base, id, instance, options) {
|
|
283
|
+
return fetch(base, {
|
|
284
|
+
method: "POST",
|
|
285
|
+
...options,
|
|
286
|
+
headers: {
|
|
287
|
+
...options.headers,
|
|
288
|
+
[FUNCTION_HEADER]: id,
|
|
289
|
+
[INSTANCE_HEADER]: instance
|
|
290
|
+
}
|
|
291
|
+
});
|
|
292
|
+
}
|
|
293
|
+
async function initializeResponse(base, id, instance, options, args) {
|
|
294
|
+
if (args.length === 0) {
|
|
295
|
+
return createRequest(base, id, instance, options);
|
|
296
|
+
}
|
|
297
|
+
if (args.length === 1) {
|
|
298
|
+
const result = getHeadersAndBody(args[0]);
|
|
299
|
+
if (result) {
|
|
300
|
+
return createRequest(base, id, instance, {
|
|
301
|
+
...options,
|
|
302
|
+
body: result.body,
|
|
303
|
+
headers: {
|
|
304
|
+
...options.headers,
|
|
305
|
+
...result.headers
|
|
306
|
+
}
|
|
307
|
+
});
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
return createRequest(base, id, instance, {
|
|
311
|
+
...options,
|
|
312
|
+
body: await serializeString(args, getServerFunctionsCodec()),
|
|
313
|
+
headers: {
|
|
314
|
+
...options.headers,
|
|
315
|
+
"Content-Type": "text/plain",
|
|
316
|
+
[BODY_FORMAT_HEADER]: BodyFormat.Serialized
|
|
317
|
+
}
|
|
318
|
+
});
|
|
319
|
+
}
|
|
320
|
+
async function fetchServerFunction(base, id, options, args) {
|
|
321
|
+
const instance = `server-function:${INSTANCE++}`;
|
|
322
|
+
const response = await initializeResponse(base, id, instance, options, args);
|
|
323
|
+
if (response.headers.has("Location") || response.headers.has("X-Revalidate") || response.headers.has("X-Single-Flight")) {
|
|
324
|
+
return response;
|
|
325
|
+
}
|
|
326
|
+
const result = await decodeResponse(response.clone());
|
|
327
|
+
if (response.headers.has("X-Server-Function-Error")) {
|
|
328
|
+
throw result;
|
|
329
|
+
}
|
|
330
|
+
return result;
|
|
331
|
+
}
|
|
332
|
+
function createServerReference(id) {
|
|
333
|
+
const fn = (...args) => fetchServerFunction(config.endpoint, id, {}, args);
|
|
334
|
+
return new Proxy(fn, {
|
|
335
|
+
get(target, prop, receiver) {
|
|
336
|
+
if (prop === "url") {
|
|
337
|
+
return `${config.endpoint}?id=${encodeURIComponent(id)}`;
|
|
338
|
+
}
|
|
339
|
+
if (prop === "GET") {
|
|
340
|
+
return receiver.withOptions({
|
|
341
|
+
method: "GET"
|
|
342
|
+
});
|
|
343
|
+
}
|
|
344
|
+
if (prop === "withOptions") {
|
|
345
|
+
const url = `${config.endpoint}?id=${encodeURIComponent(id)}`;
|
|
346
|
+
return options => {
|
|
347
|
+
const wrapped = async (...args) => {
|
|
348
|
+
const encodeArgs = options.method && options.method.toUpperCase() === "GET";
|
|
349
|
+
return fetchServerFunction(encodeArgs ? url + (args.length ? `&args=${encodeURIComponent(await serializeString(args, getServerFunctionsCodec()))}` : "") : config.endpoint, id, options, encodeArgs ? [] : args);
|
|
350
|
+
};
|
|
351
|
+
wrapped.url = url;
|
|
352
|
+
return wrapped;
|
|
353
|
+
};
|
|
354
|
+
}
|
|
355
|
+
return target[prop];
|
|
356
|
+
}
|
|
357
|
+
});
|
|
358
|
+
}
|
|
359
|
+
function registerServerReference() {
|
|
360
|
+
throw new Error("registerServerReference must not be called in the client build");
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
export { FUNCTION_HEADER, INSTANCE_HEADER, configureServerFunctionsClient, createServerReference, decodeResponse, registerServerReference };
|