@solidjs/web 2.0.0-beta.20 → 2.0.0-beta.22
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/dev.cjs +34 -1
- package/dist/dev.js +31 -2
- package/dist/server.cjs +19 -1
- package/dist/server.js +16 -2
- package/dist/web.cjs +34 -1
- package/dist/web.js +31 -2
- package/package.json +3 -3
- package/server-functions/dist/client.cjs +144 -38
- package/server-functions/dist/client.js +136 -39
- package/server-functions/dist/server.cjs +127 -10
- package/server-functions/dist/server.js +119 -11
- package/types/client.d.ts +18 -0
- package/types/jsx.d.ts +17 -2
- package/types/response.d.ts +27 -1
- package/types/server-functions/client.d.ts +104 -19
- package/types/server-functions/server.d.ts +138 -15
- package/types/server-functions/shared.d.ts +200 -0
- package/types/server.d.ts +8 -0
- package/types-cjs/client.d.cts +18 -0
- package/types-cjs/jsx.d.cts +17 -2
- package/types-cjs/response.d.cts +27 -1
- package/types-cjs/server-functions/client.d.cts +104 -19
- package/types-cjs/server-functions/server.d.cts +138 -15
- package/types-cjs/server-functions/shared.d.cts +200 -0
- package/types-cjs/server.d.cts +8 -0
|
@@ -67,9 +67,55 @@ function configureServerFunctionsCodec(codec) {
|
|
|
67
67
|
function getServerFunctionsCodec() {
|
|
68
68
|
return codecConfig.codec;
|
|
69
69
|
}
|
|
70
|
+
function subscribeFlightData(consumer) {
|
|
71
|
+
return () => {
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
const SERVER_FUNCTION_METADATA = Symbol.for("solid.ServerFunctionMetadata");
|
|
75
|
+
function getServerFunctionMetadata(fn) {
|
|
76
|
+
if (typeof fn !== "function") return undefined;
|
|
77
|
+
return fn[SERVER_FUNCTION_METADATA] || undefined;
|
|
78
|
+
}
|
|
79
|
+
function isServerFunction(fn) {
|
|
80
|
+
return typeof fn === "function" && !!fn[SERVER_FUNCTION_METADATA];
|
|
81
|
+
}
|
|
82
|
+
function withMeta(fn, meta) {
|
|
83
|
+
const metadata = getServerFunctionMetadata(fn);
|
|
84
|
+
if (!metadata) {
|
|
85
|
+
throw new Error("withMeta expects a server function reference");
|
|
86
|
+
}
|
|
87
|
+
Object.assign(metadata, meta);
|
|
88
|
+
return fn;
|
|
89
|
+
}
|
|
70
90
|
const FUNCTION_HEADER = "X-Server-Function-Id";
|
|
91
|
+
const ERROR_HEADER = "X-Server-Function-Error";
|
|
92
|
+
const ERROR_HEADER_MARKER = "=?1?";
|
|
93
|
+
const NEEDS_ENCODING = /[^\x20-\x7e\xa0-\xff]/;
|
|
94
|
+
function encodeErrorHeaderValue(value) {
|
|
95
|
+
let stripped = String(value).replace(/[\r\n]+/g, "");
|
|
96
|
+
if (!NEEDS_ENCODING.test(stripped) && !stripped.startsWith(ERROR_HEADER_MARKER) && stripped === stripped.trim()) {
|
|
97
|
+
return stripped;
|
|
98
|
+
}
|
|
99
|
+
if (typeof stripped.toWellFormed === "function") {
|
|
100
|
+
stripped = stripped.toWellFormed();
|
|
101
|
+
} else {
|
|
102
|
+
stripped = stripped.replace(/[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?<![\uD800-\uDBFF])[\uDC00-\uDFFF]/g, "\uFFFD");
|
|
103
|
+
}
|
|
104
|
+
return ERROR_HEADER_MARKER + encodeURIComponent(stripped);
|
|
105
|
+
}
|
|
106
|
+
function decodeErrorHeaderValue(value) {
|
|
107
|
+
if (typeof value !== "string" || !value.startsWith(ERROR_HEADER_MARKER)) {
|
|
108
|
+
return value;
|
|
109
|
+
}
|
|
110
|
+
try {
|
|
111
|
+
return decodeURIComponent(value.slice(ERROR_HEADER_MARKER.length));
|
|
112
|
+
} catch {
|
|
113
|
+
return value;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
71
116
|
const INSTANCE_HEADER = "X-Server-Function-Instance";
|
|
72
117
|
const BODY_FORMAT_HEADER = "X-Server-Function-Format";
|
|
118
|
+
const SINGLE_FLIGHT_HEADER = "X-Single-Flight";
|
|
73
119
|
const FILE_FORM_KEY = "__server_function_file__";
|
|
74
120
|
const BodyFormat = {
|
|
75
121
|
Serialized: "0",
|
|
@@ -282,14 +328,17 @@ async function decodeResponse(response, codecOptions) {
|
|
|
282
328
|
|
|
283
329
|
const config = {
|
|
284
330
|
provideEvent: undefined,
|
|
331
|
+
collectFlightData: undefined,
|
|
285
332
|
endpoint: "/_server"
|
|
286
333
|
};
|
|
287
334
|
function configureServerFunctionsServer({
|
|
288
335
|
provideEvent,
|
|
336
|
+
collectFlightData,
|
|
289
337
|
endpoint,
|
|
290
338
|
codec
|
|
291
339
|
} = {}) {
|
|
292
340
|
if (provideEvent !== undefined) config.provideEvent = provideEvent;
|
|
341
|
+
if (collectFlightData !== undefined) config.collectFlightData = collectFlightData;
|
|
293
342
|
if (endpoint !== undefined) config.endpoint = endpoint;
|
|
294
343
|
if (codec !== undefined) configureServerFunctionsCodec(codec);
|
|
295
344
|
}
|
|
@@ -300,6 +349,7 @@ function provideEvent(event, fn) {
|
|
|
300
349
|
throw new Error("No request event provider. Configure one with configureServerFunctionsServer({ provideEvent }).");
|
|
301
350
|
}
|
|
302
351
|
const REGISTRATIONS = new Map();
|
|
352
|
+
const METHODS = new Map();
|
|
303
353
|
function registerServerFunction(id, callback) {
|
|
304
354
|
REGISTRATIONS.set(id, callback);
|
|
305
355
|
return callback;
|
|
@@ -311,24 +361,30 @@ function getServerFunction(id) {
|
|
|
311
361
|
}
|
|
312
362
|
throw new Error("invalid server function: " + id);
|
|
313
363
|
}
|
|
314
|
-
function registerServerReference(id, fn) {
|
|
364
|
+
function registerServerReference(id, fn, name) {
|
|
315
365
|
registerServerFunction(id, fn);
|
|
316
366
|
return {
|
|
317
367
|
id,
|
|
318
|
-
fn
|
|
368
|
+
fn,
|
|
369
|
+
name
|
|
319
370
|
};
|
|
320
371
|
}
|
|
321
372
|
function createServerReference({
|
|
322
373
|
id,
|
|
323
|
-
fn
|
|
374
|
+
fn,
|
|
375
|
+
name
|
|
324
376
|
}) {
|
|
325
377
|
if (typeof fn !== "function") throw new Error("Export from a 'use server' module must be a function");
|
|
378
|
+
const metadata = name === undefined ? {} : {
|
|
379
|
+
name
|
|
380
|
+
};
|
|
326
381
|
return new Proxy(fn, {
|
|
327
|
-
get(target, prop
|
|
382
|
+
get(target, prop) {
|
|
383
|
+
if (prop === "id") return id;
|
|
328
384
|
if (prop === "url") {
|
|
329
385
|
return `${config.endpoint}?id=${encodeURIComponent(id)}`;
|
|
330
386
|
}
|
|
331
|
-
if (prop ===
|
|
387
|
+
if (prop === SERVER_FUNCTION_METADATA) return metadata;
|
|
332
388
|
return target[prop];
|
|
333
389
|
},
|
|
334
390
|
apply(target, thisArg, args) {
|
|
@@ -347,6 +403,15 @@ function createServerReference({
|
|
|
347
403
|
}
|
|
348
404
|
});
|
|
349
405
|
}
|
|
406
|
+
function GET(fn) {
|
|
407
|
+
if (!isServerFunction(fn) || typeof fn.id !== "string") {
|
|
408
|
+
throw new Error("GET expects a server function reference");
|
|
409
|
+
}
|
|
410
|
+
METHODS.set(fn.id, "GET");
|
|
411
|
+
return withMeta(fn, {
|
|
412
|
+
method: "GET"
|
|
413
|
+
});
|
|
414
|
+
}
|
|
350
415
|
function getServerFunctionMeta() {
|
|
351
416
|
const event = getRequestEvent();
|
|
352
417
|
return event && event.locals.serverFunctionMeta;
|
|
@@ -360,7 +425,8 @@ function resolveFunctionId(request, url) {
|
|
|
360
425
|
}
|
|
361
426
|
async function parseArguments(request, url, instance, codec) {
|
|
362
427
|
const parsed = [];
|
|
363
|
-
|
|
428
|
+
const bodyFormat = request.method === "POST" ? request.headers.get(BODY_FORMAT_HEADER) : null;
|
|
429
|
+
if (!instance || request.method === "GET" || bodyFormat !== BodyFormat.Serialized) {
|
|
364
430
|
const args = url.searchParams.get("args");
|
|
365
431
|
if (args) {
|
|
366
432
|
const result = args.startsWith(";0x") ? await deserializeString(args, codec) : JSON.parse(args);
|
|
@@ -370,15 +436,23 @@ async function parseArguments(request, url, instance, codec) {
|
|
|
370
436
|
}
|
|
371
437
|
}
|
|
372
438
|
if (request.method === "POST" && request.body !== null) {
|
|
373
|
-
const format = request.headers.get(BODY_FORMAT_HEADER);
|
|
374
439
|
const decoded = await extractBody(request.clone(), codec);
|
|
375
|
-
if (
|
|
440
|
+
if (bodyFormat === BodyFormat.Serialized) {
|
|
376
441
|
return decoded;
|
|
377
442
|
}
|
|
378
443
|
parsed.push(decoded);
|
|
379
444
|
}
|
|
380
445
|
return parsed;
|
|
381
446
|
}
|
|
447
|
+
async function foldFlightData(hook, event, headers, outcome) {
|
|
448
|
+
const data = await hook(event, outcome);
|
|
449
|
+
if (data === undefined) return outcome.value;
|
|
450
|
+
headers.set(SINGLE_FLIGHT_HEADER, "true");
|
|
451
|
+
return {
|
|
452
|
+
value: outcome.value,
|
|
453
|
+
data
|
|
454
|
+
};
|
|
455
|
+
}
|
|
382
456
|
function serializedResponse(value, headers, codec) {
|
|
383
457
|
headers.set(BODY_FORMAT_HEADER, BodyFormat.Serialized);
|
|
384
458
|
headers.set("Content-Type", "text/plain");
|
|
@@ -421,11 +495,21 @@ async function handleServerFunctionRequest(request, options = {}) {
|
|
|
421
495
|
status: 404
|
|
422
496
|
});
|
|
423
497
|
}
|
|
498
|
+
if (request.method === "GET" && METHODS.get(functionId) !== "GET") {
|
|
499
|
+
return new Response(process.env.NODE_ENV === "development" ? `Method not allowed for server function: ${functionId}` : null, {
|
|
500
|
+
status: 405,
|
|
501
|
+
headers: {
|
|
502
|
+
Allow: "POST"
|
|
503
|
+
}
|
|
504
|
+
});
|
|
505
|
+
}
|
|
424
506
|
const event = options.createEvent ? options.createEvent(request) : {
|
|
425
507
|
request,
|
|
426
508
|
locals: {}
|
|
427
509
|
};
|
|
428
510
|
const provide = options.provideEvent || provideEvent;
|
|
511
|
+
const flightHook = options.collectFlightData !== undefined ? options.collectFlightData : config.collectFlightData;
|
|
512
|
+
const collectsFlight = !!(flightHook && instance && request.headers.has(SINGLE_FLIGHT_HEADER));
|
|
429
513
|
const parsed = await parseArguments(request, url, instance, codec);
|
|
430
514
|
const headers = new Headers();
|
|
431
515
|
try {
|
|
@@ -442,6 +526,7 @@ async function handleServerFunctionRequest(request, options = {}) {
|
|
|
442
526
|
});
|
|
443
527
|
}
|
|
444
528
|
let status = 200;
|
|
529
|
+
let metadata;
|
|
445
530
|
if (isResponseEnvelope(result)) {
|
|
446
531
|
const {
|
|
447
532
|
response,
|
|
@@ -456,6 +541,7 @@ async function handleServerFunctionRequest(request, options = {}) {
|
|
|
456
541
|
if (response && response.status && (response.status < 300 || response.status >= 400)) {
|
|
457
542
|
status = response.status;
|
|
458
543
|
}
|
|
544
|
+
metadata = response;
|
|
459
545
|
result = value;
|
|
460
546
|
} else if (result instanceof Response) {
|
|
461
547
|
if (result.headers && result.headers.has("X-Content-Raw")) return result;
|
|
@@ -466,11 +552,21 @@ async function handleServerFunctionRequest(request, options = {}) {
|
|
|
466
552
|
if (result.status && (result.status < 300 || result.status >= 400)) {
|
|
467
553
|
status = result.status;
|
|
468
554
|
}
|
|
555
|
+
metadata = result;
|
|
469
556
|
if (result.body == null) {
|
|
470
557
|
result = null;
|
|
471
558
|
}
|
|
472
559
|
}
|
|
473
560
|
}
|
|
561
|
+
if (collectsFlight) {
|
|
562
|
+
result = await foldFlightData(flightHook, event, headers, {
|
|
563
|
+
id: functionId,
|
|
564
|
+
value: result,
|
|
565
|
+
response: metadata,
|
|
566
|
+
request,
|
|
567
|
+
thrown: false
|
|
568
|
+
});
|
|
569
|
+
}
|
|
474
570
|
if (!instance) {
|
|
475
571
|
if (options.handleNoJS) return options.handleNoJS(result, request, parsed);
|
|
476
572
|
if (result instanceof Response) return result;
|
|
@@ -487,6 +583,7 @@ async function handleServerFunctionRequest(request, options = {}) {
|
|
|
487
583
|
});
|
|
488
584
|
}
|
|
489
585
|
let status = 200;
|
|
586
|
+
let metadata;
|
|
490
587
|
if (isResponseEnvelope(x)) {
|
|
491
588
|
const {
|
|
492
589
|
response,
|
|
@@ -498,6 +595,7 @@ async function handleServerFunctionRequest(request, options = {}) {
|
|
|
498
595
|
if (response && response.status && (!instance || response.status < 300 || response.status >= 400)) {
|
|
499
596
|
status = response.status;
|
|
500
597
|
}
|
|
598
|
+
metadata = response;
|
|
501
599
|
x = value;
|
|
502
600
|
} else if (x instanceof Response) {
|
|
503
601
|
if (x.headers) {
|
|
@@ -506,11 +604,21 @@ async function handleServerFunctionRequest(request, options = {}) {
|
|
|
506
604
|
if (x.status && (!instance || x.status < 300 || x.status >= 400)) {
|
|
507
605
|
status = x.status;
|
|
508
606
|
}
|
|
607
|
+
metadata = x;
|
|
509
608
|
if (x.body == null) {
|
|
510
609
|
x = null;
|
|
511
610
|
}
|
|
512
611
|
}
|
|
513
|
-
|
|
612
|
+
if (collectsFlight) {
|
|
613
|
+
x = await foldFlightData(flightHook, event, headers, {
|
|
614
|
+
id: functionId,
|
|
615
|
+
value: x,
|
|
616
|
+
response: metadata,
|
|
617
|
+
request,
|
|
618
|
+
thrown: true
|
|
619
|
+
});
|
|
620
|
+
}
|
|
621
|
+
headers.set(ERROR_HEADER, "true");
|
|
514
622
|
if (!instance) {
|
|
515
623
|
if (options.handleNoJS) return options.handleNoJS(x, request, parsed, true);
|
|
516
624
|
if (x instanceof Response) return x;
|
|
@@ -525,18 +633,27 @@ async function handleServerFunctionRequest(request, options = {}) {
|
|
|
525
633
|
});
|
|
526
634
|
}
|
|
527
635
|
const error = x instanceof Error ? x.message : typeof x === "string" ? x : "true";
|
|
528
|
-
headers.set(
|
|
636
|
+
headers.set(ERROR_HEADER, encodeErrorHeaderValue(error));
|
|
529
637
|
return encodeResult(x, headers, 200, codec);
|
|
530
638
|
}
|
|
531
639
|
}
|
|
532
640
|
|
|
641
|
+
exports.ERROR_HEADER = ERROR_HEADER;
|
|
533
642
|
exports.FUNCTION_HEADER = FUNCTION_HEADER;
|
|
643
|
+
exports.GET = GET;
|
|
534
644
|
exports.INSTANCE_HEADER = INSTANCE_HEADER;
|
|
645
|
+
exports.SINGLE_FLIGHT_HEADER = SINGLE_FLIGHT_HEADER;
|
|
535
646
|
exports.configureServerFunctionsServer = configureServerFunctionsServer;
|
|
536
647
|
exports.createServerReference = createServerReference;
|
|
648
|
+
exports.decodeErrorHeaderValue = decodeErrorHeaderValue;
|
|
537
649
|
exports.decodeResponse = decodeResponse;
|
|
650
|
+
exports.encodeErrorHeaderValue = encodeErrorHeaderValue;
|
|
538
651
|
exports.getServerFunction = getServerFunction;
|
|
539
652
|
exports.getServerFunctionMeta = getServerFunctionMeta;
|
|
653
|
+
exports.getServerFunctionMetadata = getServerFunctionMetadata;
|
|
540
654
|
exports.handleServerFunctionRequest = handleServerFunctionRequest;
|
|
655
|
+
exports.isServerFunction = isServerFunction;
|
|
541
656
|
exports.registerServerFunction = registerServerFunction;
|
|
542
657
|
exports.registerServerReference = registerServerReference;
|
|
658
|
+
exports.subscribeFlightData = subscribeFlightData;
|
|
659
|
+
exports.withMeta = withMeta;
|
|
@@ -65,9 +65,55 @@ function configureServerFunctionsCodec(codec) {
|
|
|
65
65
|
function getServerFunctionsCodec() {
|
|
66
66
|
return codecConfig.codec;
|
|
67
67
|
}
|
|
68
|
+
function subscribeFlightData(consumer) {
|
|
69
|
+
return () => {
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
const SERVER_FUNCTION_METADATA = Symbol.for("solid.ServerFunctionMetadata");
|
|
73
|
+
function getServerFunctionMetadata(fn) {
|
|
74
|
+
if (typeof fn !== "function") return undefined;
|
|
75
|
+
return fn[SERVER_FUNCTION_METADATA] || undefined;
|
|
76
|
+
}
|
|
77
|
+
function isServerFunction(fn) {
|
|
78
|
+
return typeof fn === "function" && !!fn[SERVER_FUNCTION_METADATA];
|
|
79
|
+
}
|
|
80
|
+
function withMeta(fn, meta) {
|
|
81
|
+
const metadata = getServerFunctionMetadata(fn);
|
|
82
|
+
if (!metadata) {
|
|
83
|
+
throw new Error("withMeta expects a server function reference");
|
|
84
|
+
}
|
|
85
|
+
Object.assign(metadata, meta);
|
|
86
|
+
return fn;
|
|
87
|
+
}
|
|
68
88
|
const FUNCTION_HEADER = "X-Server-Function-Id";
|
|
89
|
+
const ERROR_HEADER = "X-Server-Function-Error";
|
|
90
|
+
const ERROR_HEADER_MARKER = "=?1?";
|
|
91
|
+
const NEEDS_ENCODING = /[^\x20-\x7e\xa0-\xff]/;
|
|
92
|
+
function encodeErrorHeaderValue(value) {
|
|
93
|
+
let stripped = String(value).replace(/[\r\n]+/g, "");
|
|
94
|
+
if (!NEEDS_ENCODING.test(stripped) && !stripped.startsWith(ERROR_HEADER_MARKER) && stripped === stripped.trim()) {
|
|
95
|
+
return stripped;
|
|
96
|
+
}
|
|
97
|
+
if (typeof stripped.toWellFormed === "function") {
|
|
98
|
+
stripped = stripped.toWellFormed();
|
|
99
|
+
} else {
|
|
100
|
+
stripped = stripped.replace(/[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?<![\uD800-\uDBFF])[\uDC00-\uDFFF]/g, "\uFFFD");
|
|
101
|
+
}
|
|
102
|
+
return ERROR_HEADER_MARKER + encodeURIComponent(stripped);
|
|
103
|
+
}
|
|
104
|
+
function decodeErrorHeaderValue(value) {
|
|
105
|
+
if (typeof value !== "string" || !value.startsWith(ERROR_HEADER_MARKER)) {
|
|
106
|
+
return value;
|
|
107
|
+
}
|
|
108
|
+
try {
|
|
109
|
+
return decodeURIComponent(value.slice(ERROR_HEADER_MARKER.length));
|
|
110
|
+
} catch {
|
|
111
|
+
return value;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
69
114
|
const INSTANCE_HEADER = "X-Server-Function-Instance";
|
|
70
115
|
const BODY_FORMAT_HEADER = "X-Server-Function-Format";
|
|
116
|
+
const SINGLE_FLIGHT_HEADER = "X-Single-Flight";
|
|
71
117
|
const FILE_FORM_KEY = "__server_function_file__";
|
|
72
118
|
const BodyFormat = {
|
|
73
119
|
Serialized: "0",
|
|
@@ -280,14 +326,17 @@ async function decodeResponse(response, codecOptions) {
|
|
|
280
326
|
|
|
281
327
|
const config = {
|
|
282
328
|
provideEvent: undefined,
|
|
329
|
+
collectFlightData: undefined,
|
|
283
330
|
endpoint: "/_server"
|
|
284
331
|
};
|
|
285
332
|
function configureServerFunctionsServer({
|
|
286
333
|
provideEvent,
|
|
334
|
+
collectFlightData,
|
|
287
335
|
endpoint,
|
|
288
336
|
codec
|
|
289
337
|
} = {}) {
|
|
290
338
|
if (provideEvent !== undefined) config.provideEvent = provideEvent;
|
|
339
|
+
if (collectFlightData !== undefined) config.collectFlightData = collectFlightData;
|
|
291
340
|
if (endpoint !== undefined) config.endpoint = endpoint;
|
|
292
341
|
if (codec !== undefined) configureServerFunctionsCodec(codec);
|
|
293
342
|
}
|
|
@@ -298,6 +347,7 @@ function provideEvent(event, fn) {
|
|
|
298
347
|
throw new Error("No request event provider. Configure one with configureServerFunctionsServer({ provideEvent }).");
|
|
299
348
|
}
|
|
300
349
|
const REGISTRATIONS = new Map();
|
|
350
|
+
const METHODS = new Map();
|
|
301
351
|
function registerServerFunction(id, callback) {
|
|
302
352
|
REGISTRATIONS.set(id, callback);
|
|
303
353
|
return callback;
|
|
@@ -309,24 +359,30 @@ function getServerFunction(id) {
|
|
|
309
359
|
}
|
|
310
360
|
throw new Error("invalid server function: " + id);
|
|
311
361
|
}
|
|
312
|
-
function registerServerReference(id, fn) {
|
|
362
|
+
function registerServerReference(id, fn, name) {
|
|
313
363
|
registerServerFunction(id, fn);
|
|
314
364
|
return {
|
|
315
365
|
id,
|
|
316
|
-
fn
|
|
366
|
+
fn,
|
|
367
|
+
name
|
|
317
368
|
};
|
|
318
369
|
}
|
|
319
370
|
function createServerReference({
|
|
320
371
|
id,
|
|
321
|
-
fn
|
|
372
|
+
fn,
|
|
373
|
+
name
|
|
322
374
|
}) {
|
|
323
375
|
if (typeof fn !== "function") throw new Error("Export from a 'use server' module must be a function");
|
|
376
|
+
const metadata = name === undefined ? {} : {
|
|
377
|
+
name
|
|
378
|
+
};
|
|
324
379
|
return new Proxy(fn, {
|
|
325
|
-
get(target, prop
|
|
380
|
+
get(target, prop) {
|
|
381
|
+
if (prop === "id") return id;
|
|
326
382
|
if (prop === "url") {
|
|
327
383
|
return `${config.endpoint}?id=${encodeURIComponent(id)}`;
|
|
328
384
|
}
|
|
329
|
-
if (prop ===
|
|
385
|
+
if (prop === SERVER_FUNCTION_METADATA) return metadata;
|
|
330
386
|
return target[prop];
|
|
331
387
|
},
|
|
332
388
|
apply(target, thisArg, args) {
|
|
@@ -345,6 +401,15 @@ function createServerReference({
|
|
|
345
401
|
}
|
|
346
402
|
});
|
|
347
403
|
}
|
|
404
|
+
function GET(fn) {
|
|
405
|
+
if (!isServerFunction(fn) || typeof fn.id !== "string") {
|
|
406
|
+
throw new Error("GET expects a server function reference");
|
|
407
|
+
}
|
|
408
|
+
METHODS.set(fn.id, "GET");
|
|
409
|
+
return withMeta(fn, {
|
|
410
|
+
method: "GET"
|
|
411
|
+
});
|
|
412
|
+
}
|
|
348
413
|
function getServerFunctionMeta() {
|
|
349
414
|
const event = getRequestEvent();
|
|
350
415
|
return event && event.locals.serverFunctionMeta;
|
|
@@ -358,7 +423,8 @@ function resolveFunctionId(request, url) {
|
|
|
358
423
|
}
|
|
359
424
|
async function parseArguments(request, url, instance, codec) {
|
|
360
425
|
const parsed = [];
|
|
361
|
-
|
|
426
|
+
const bodyFormat = request.method === "POST" ? request.headers.get(BODY_FORMAT_HEADER) : null;
|
|
427
|
+
if (!instance || request.method === "GET" || bodyFormat !== BodyFormat.Serialized) {
|
|
362
428
|
const args = url.searchParams.get("args");
|
|
363
429
|
if (args) {
|
|
364
430
|
const result = args.startsWith(";0x") ? await deserializeString(args, codec) : JSON.parse(args);
|
|
@@ -368,15 +434,23 @@ async function parseArguments(request, url, instance, codec) {
|
|
|
368
434
|
}
|
|
369
435
|
}
|
|
370
436
|
if (request.method === "POST" && request.body !== null) {
|
|
371
|
-
const format = request.headers.get(BODY_FORMAT_HEADER);
|
|
372
437
|
const decoded = await extractBody(request.clone(), codec);
|
|
373
|
-
if (
|
|
438
|
+
if (bodyFormat === BodyFormat.Serialized) {
|
|
374
439
|
return decoded;
|
|
375
440
|
}
|
|
376
441
|
parsed.push(decoded);
|
|
377
442
|
}
|
|
378
443
|
return parsed;
|
|
379
444
|
}
|
|
445
|
+
async function foldFlightData(hook, event, headers, outcome) {
|
|
446
|
+
const data = await hook(event, outcome);
|
|
447
|
+
if (data === undefined) return outcome.value;
|
|
448
|
+
headers.set(SINGLE_FLIGHT_HEADER, "true");
|
|
449
|
+
return {
|
|
450
|
+
value: outcome.value,
|
|
451
|
+
data
|
|
452
|
+
};
|
|
453
|
+
}
|
|
380
454
|
function serializedResponse(value, headers, codec) {
|
|
381
455
|
headers.set(BODY_FORMAT_HEADER, BodyFormat.Serialized);
|
|
382
456
|
headers.set("Content-Type", "text/plain");
|
|
@@ -419,11 +493,21 @@ async function handleServerFunctionRequest(request, options = {}) {
|
|
|
419
493
|
status: 404
|
|
420
494
|
});
|
|
421
495
|
}
|
|
496
|
+
if (request.method === "GET" && METHODS.get(functionId) !== "GET") {
|
|
497
|
+
return new Response(process.env.NODE_ENV === "development" ? `Method not allowed for server function: ${functionId}` : null, {
|
|
498
|
+
status: 405,
|
|
499
|
+
headers: {
|
|
500
|
+
Allow: "POST"
|
|
501
|
+
}
|
|
502
|
+
});
|
|
503
|
+
}
|
|
422
504
|
const event = options.createEvent ? options.createEvent(request) : {
|
|
423
505
|
request,
|
|
424
506
|
locals: {}
|
|
425
507
|
};
|
|
426
508
|
const provide = options.provideEvent || provideEvent;
|
|
509
|
+
const flightHook = options.collectFlightData !== undefined ? options.collectFlightData : config.collectFlightData;
|
|
510
|
+
const collectsFlight = !!(flightHook && instance && request.headers.has(SINGLE_FLIGHT_HEADER));
|
|
427
511
|
const parsed = await parseArguments(request, url, instance, codec);
|
|
428
512
|
const headers = new Headers();
|
|
429
513
|
try {
|
|
@@ -440,6 +524,7 @@ async function handleServerFunctionRequest(request, options = {}) {
|
|
|
440
524
|
});
|
|
441
525
|
}
|
|
442
526
|
let status = 200;
|
|
527
|
+
let metadata;
|
|
443
528
|
if (isResponseEnvelope(result)) {
|
|
444
529
|
const {
|
|
445
530
|
response,
|
|
@@ -454,6 +539,7 @@ async function handleServerFunctionRequest(request, options = {}) {
|
|
|
454
539
|
if (response && response.status && (response.status < 300 || response.status >= 400)) {
|
|
455
540
|
status = response.status;
|
|
456
541
|
}
|
|
542
|
+
metadata = response;
|
|
457
543
|
result = value;
|
|
458
544
|
} else if (result instanceof Response) {
|
|
459
545
|
if (result.headers && result.headers.has("X-Content-Raw")) return result;
|
|
@@ -464,11 +550,21 @@ async function handleServerFunctionRequest(request, options = {}) {
|
|
|
464
550
|
if (result.status && (result.status < 300 || result.status >= 400)) {
|
|
465
551
|
status = result.status;
|
|
466
552
|
}
|
|
553
|
+
metadata = result;
|
|
467
554
|
if (result.body == null) {
|
|
468
555
|
result = null;
|
|
469
556
|
}
|
|
470
557
|
}
|
|
471
558
|
}
|
|
559
|
+
if (collectsFlight) {
|
|
560
|
+
result = await foldFlightData(flightHook, event, headers, {
|
|
561
|
+
id: functionId,
|
|
562
|
+
value: result,
|
|
563
|
+
response: metadata,
|
|
564
|
+
request,
|
|
565
|
+
thrown: false
|
|
566
|
+
});
|
|
567
|
+
}
|
|
472
568
|
if (!instance) {
|
|
473
569
|
if (options.handleNoJS) return options.handleNoJS(result, request, parsed);
|
|
474
570
|
if (result instanceof Response) return result;
|
|
@@ -485,6 +581,7 @@ async function handleServerFunctionRequest(request, options = {}) {
|
|
|
485
581
|
});
|
|
486
582
|
}
|
|
487
583
|
let status = 200;
|
|
584
|
+
let metadata;
|
|
488
585
|
if (isResponseEnvelope(x)) {
|
|
489
586
|
const {
|
|
490
587
|
response,
|
|
@@ -496,6 +593,7 @@ async function handleServerFunctionRequest(request, options = {}) {
|
|
|
496
593
|
if (response && response.status && (!instance || response.status < 300 || response.status >= 400)) {
|
|
497
594
|
status = response.status;
|
|
498
595
|
}
|
|
596
|
+
metadata = response;
|
|
499
597
|
x = value;
|
|
500
598
|
} else if (x instanceof Response) {
|
|
501
599
|
if (x.headers) {
|
|
@@ -504,11 +602,21 @@ async function handleServerFunctionRequest(request, options = {}) {
|
|
|
504
602
|
if (x.status && (!instance || x.status < 300 || x.status >= 400)) {
|
|
505
603
|
status = x.status;
|
|
506
604
|
}
|
|
605
|
+
metadata = x;
|
|
507
606
|
if (x.body == null) {
|
|
508
607
|
x = null;
|
|
509
608
|
}
|
|
510
609
|
}
|
|
511
|
-
|
|
610
|
+
if (collectsFlight) {
|
|
611
|
+
x = await foldFlightData(flightHook, event, headers, {
|
|
612
|
+
id: functionId,
|
|
613
|
+
value: x,
|
|
614
|
+
response: metadata,
|
|
615
|
+
request,
|
|
616
|
+
thrown: true
|
|
617
|
+
});
|
|
618
|
+
}
|
|
619
|
+
headers.set(ERROR_HEADER, "true");
|
|
512
620
|
if (!instance) {
|
|
513
621
|
if (options.handleNoJS) return options.handleNoJS(x, request, parsed, true);
|
|
514
622
|
if (x instanceof Response) return x;
|
|
@@ -523,9 +631,9 @@ async function handleServerFunctionRequest(request, options = {}) {
|
|
|
523
631
|
});
|
|
524
632
|
}
|
|
525
633
|
const error = x instanceof Error ? x.message : typeof x === "string" ? x : "true";
|
|
526
|
-
headers.set(
|
|
634
|
+
headers.set(ERROR_HEADER, encodeErrorHeaderValue(error));
|
|
527
635
|
return encodeResult(x, headers, 200, codec);
|
|
528
636
|
}
|
|
529
637
|
}
|
|
530
638
|
|
|
531
|
-
export { FUNCTION_HEADER, INSTANCE_HEADER, configureServerFunctionsServer, createServerReference, decodeResponse, getServerFunction, getServerFunctionMeta, handleServerFunctionRequest, registerServerFunction, registerServerReference };
|
|
639
|
+
export { ERROR_HEADER, FUNCTION_HEADER, GET, INSTANCE_HEADER, SINGLE_FLIGHT_HEADER, configureServerFunctionsServer, createServerReference, decodeErrorHeaderValue, decodeResponse, encodeErrorHeaderValue, getServerFunction, getServerFunctionMeta, getServerFunctionMetadata, handleServerFunctionRequest, isServerFunction, registerServerFunction, registerServerReference, subscribeFlightData, withMeta };
|
package/types/client.d.ts
CHANGED
|
@@ -66,6 +66,24 @@ export function assign(
|
|
|
66
66
|
): void;
|
|
67
67
|
export function setAttribute(node: Element, name: string, value: string): void;
|
|
68
68
|
export function setAttributeNS(node: Element, namespace: string, name: string, value: string): void;
|
|
69
|
+
/**
|
|
70
|
+
* Register a consumer for compiler-emitted element claims. Compiled DOM
|
|
71
|
+
* output claims navigation-relevant elements (`a[href]`, `form[action]`) at
|
|
72
|
+
* creation, and compiler-owned writes to `href`/`action` re-invoke the same
|
|
73
|
+
* handlers — so handlers must be idempotent and must check the element's
|
|
74
|
+
* relevance themselves (rechecks can fire for any element whose
|
|
75
|
+
* `href`/`action` is written, e.g. `<link href>`). Handlers run under the
|
|
76
|
+
* reactive owner current at element creation; scope per-element state and
|
|
77
|
+
* cleanup through your own reactive system. Dormant until registered —
|
|
78
|
+
* without a handler the emitted claims are null checks. Returns an
|
|
79
|
+
* unregister function.
|
|
80
|
+
*/
|
|
81
|
+
export function registerElementClaim(handler: (element: Element) => void): () => void;
|
|
82
|
+
/**
|
|
83
|
+
* Claim `node` for registered consumers (see `registerElementClaim`).
|
|
84
|
+
* Emitted by the compiler at element creation; idempotent by contract.
|
|
85
|
+
*/
|
|
86
|
+
export function claimElement<T extends Element>(node: T): T;
|
|
69
87
|
export function className(node: Element, value: JSX.ClassValue, prev?: JSX.ClassValue): void;
|
|
70
88
|
export function setProperty(node: Element, name: string, value: any): void;
|
|
71
89
|
export function setStyleProperty(node: Element, name: string, value: any): void;
|
package/types/jsx.d.ts
CHANGED
|
@@ -1120,7 +1120,7 @@ export namespace JSX {
|
|
|
1120
1120
|
|
|
1121
1121
|
interface AnchorHTMLAttributes<T> extends HTMLAttributes<T> {
|
|
1122
1122
|
download?: string | EnumeratedAcceptsEmpty | RemoveAttribute;
|
|
1123
|
-
href?: string | RemoveAttribute;
|
|
1123
|
+
href?: string | SerializableAttributeValue | RemoveAttribute;
|
|
1124
1124
|
hreflang?: string | RemoveAttribute;
|
|
1125
1125
|
ping?: string | RemoveAttribute;
|
|
1126
1126
|
referrerpolicy?: HTMLReferrerPolicy | RemoveAttribute;
|
|
@@ -1128,6 +1128,21 @@ export namespace JSX {
|
|
|
1128
1128
|
target?: "_self" | "_blank" | "_parent" | "_top" | (string & {}) | RemoveAttribute;
|
|
1129
1129
|
type?: string | RemoveAttribute;
|
|
1130
1130
|
|
|
1131
|
+
// Client-side navigation contract. These attributes are inert markup on
|
|
1132
|
+
// their own — a routing integration that delegates anchor clicks (e.g.
|
|
1133
|
+
// @solidjs/router) reads them off the element at event time. Typed here
|
|
1134
|
+
// so plain `<a>` elements participate without per-router augmentation.
|
|
1135
|
+
/** Marks the anchor as a client-navigation link when the integration requires explicit opt-in. */
|
|
1136
|
+
link?: BooleanAttribute | RemoveAttribute;
|
|
1137
|
+
/** Serialized (JSON) history state pushed alongside the navigation. */
|
|
1138
|
+
state?: string | RemoveAttribute;
|
|
1139
|
+
/** Suppress scroll restoration/reset after the navigation. */
|
|
1140
|
+
noScroll?: BooleanAttribute | RemoveAttribute;
|
|
1141
|
+
/** Replace the current history entry instead of pushing a new one. */
|
|
1142
|
+
replace?: BooleanAttribute | RemoveAttribute;
|
|
1143
|
+
/** Route preload intent; `"false"` disables the integration's default eager preload. */
|
|
1144
|
+
preload?: boolean | "false" | RemoveAttribute;
|
|
1145
|
+
|
|
1131
1146
|
/** @experimental */
|
|
1132
1147
|
attributionsrc?: string | RemoveAttribute;
|
|
1133
1148
|
|
|
@@ -1147,7 +1162,7 @@ export namespace JSX {
|
|
|
1147
1162
|
alt?: string | RemoveAttribute;
|
|
1148
1163
|
coords?: string | RemoveAttribute;
|
|
1149
1164
|
download?: string | EnumeratedAcceptsEmpty | RemoveAttribute;
|
|
1150
|
-
href?: string | RemoveAttribute;
|
|
1165
|
+
href?: string | SerializableAttributeValue | RemoveAttribute;
|
|
1151
1166
|
ping?: string | RemoveAttribute;
|
|
1152
1167
|
referrerpolicy?: HTMLReferrerPolicy | RemoveAttribute;
|
|
1153
1168
|
rel?: string | RemoveAttribute;
|
package/types/response.d.ts
CHANGED
|
@@ -23,6 +23,32 @@ export class ResponseEnvelope<T = unknown> {
|
|
|
23
23
|
*/
|
|
24
24
|
export function isResponseEnvelope(value: unknown): value is ResponseEnvelope;
|
|
25
25
|
|
|
26
|
+
/**
|
|
27
|
+
* Registered-symbol brand (`Symbol.for("solid.Href")`) marking URL-bearing
|
|
28
|
+
* values. Declared `unique symbol` type-side; the runtime value is the
|
|
29
|
+
* registered symbol, so separately bundled copies agree on identity.
|
|
30
|
+
*/
|
|
31
|
+
export declare const HREF: unique symbol;
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* A URL-bearing value: coerces to its URL via `toString()` and carries the
|
|
35
|
+
* `HREF` registered-symbol brand. Integrations mint these (e.g. a router's
|
|
36
|
+
* typed path objects answer the brand from their proxy) and URL-accepting
|
|
37
|
+
* APIs like `redirect()` accept them alongside plain strings. The brand is
|
|
38
|
+
* what makes the type meaningful — every object has `toString()`.
|
|
39
|
+
*/
|
|
40
|
+
export interface Href {
|
|
41
|
+
[HREF]: true;
|
|
42
|
+
toString(): string;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Whether `value` is an `Href`-branded URL-bearing value. Registered-symbol
|
|
47
|
+
* check, so it stays correct across duplicated module instances — same
|
|
48
|
+
* rationale as `isResponseEnvelope`.
|
|
49
|
+
*/
|
|
50
|
+
export function isHref(value: unknown): value is Href;
|
|
51
|
+
|
|
26
52
|
/** `ResponseInit` accepted by the response helpers, plus `revalidate`. */
|
|
27
53
|
export interface ResponseHelperInit extends ResponseInit {
|
|
28
54
|
/**
|
|
@@ -51,7 +77,7 @@ export interface ResponseHelperInit extends ResponseInit {
|
|
|
51
77
|
* }
|
|
52
78
|
* ```
|
|
53
79
|
*/
|
|
54
|
-
export function redirect(url: string, init?: number | ResponseHelperInit): Response;
|
|
80
|
+
export function redirect(url: string | Href, init?: number | ResponseHelperInit): Response;
|
|
55
81
|
|
|
56
82
|
/**
|
|
57
83
|
* Empty response requesting revalidation of the named cache keys — all of
|