@solidjs/web 2.0.0-beta.20 → 2.0.0-beta.21
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 +7 -0
- package/dist/dev.js +7 -0
- package/dist/web.cjs +7 -0
- package/dist/web.js +7 -0
- package/package.json +3 -3
- package/server-functions/dist/client.cjs +114 -36
- package/server-functions/dist/client.js +109 -37
- package/server-functions/dist/server.cjs +95 -5
- package/server-functions/dist/server.js +90 -6
- package/types/server-functions/client.d.ts +93 -19
- package/types/server-functions/server.d.ts +134 -15
- package/types/server-functions/shared.d.ts +171 -0
- package/types-cjs/server-functions/client.d.cts +93 -19
- package/types-cjs/server-functions/server.d.cts +134 -15
- package/types-cjs/server-functions/shared.d.cts +171 -0
|
@@ -67,9 +67,30 @@ 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";
|
|
71
91
|
const INSTANCE_HEADER = "X-Server-Function-Instance";
|
|
72
92
|
const BODY_FORMAT_HEADER = "X-Server-Function-Format";
|
|
93
|
+
const SINGLE_FLIGHT_HEADER = "X-Single-Flight";
|
|
73
94
|
const FILE_FORM_KEY = "__server_function_file__";
|
|
74
95
|
const BodyFormat = {
|
|
75
96
|
Serialized: "0",
|
|
@@ -282,14 +303,17 @@ async function decodeResponse(response, codecOptions) {
|
|
|
282
303
|
|
|
283
304
|
const config = {
|
|
284
305
|
provideEvent: undefined,
|
|
306
|
+
collectFlightData: undefined,
|
|
285
307
|
endpoint: "/_server"
|
|
286
308
|
};
|
|
287
309
|
function configureServerFunctionsServer({
|
|
288
310
|
provideEvent,
|
|
311
|
+
collectFlightData,
|
|
289
312
|
endpoint,
|
|
290
313
|
codec
|
|
291
314
|
} = {}) {
|
|
292
315
|
if (provideEvent !== undefined) config.provideEvent = provideEvent;
|
|
316
|
+
if (collectFlightData !== undefined) config.collectFlightData = collectFlightData;
|
|
293
317
|
if (endpoint !== undefined) config.endpoint = endpoint;
|
|
294
318
|
if (codec !== undefined) configureServerFunctionsCodec(codec);
|
|
295
319
|
}
|
|
@@ -300,6 +324,7 @@ function provideEvent(event, fn) {
|
|
|
300
324
|
throw new Error("No request event provider. Configure one with configureServerFunctionsServer({ provideEvent }).");
|
|
301
325
|
}
|
|
302
326
|
const REGISTRATIONS = new Map();
|
|
327
|
+
const METHODS = new Map();
|
|
303
328
|
function registerServerFunction(id, callback) {
|
|
304
329
|
REGISTRATIONS.set(id, callback);
|
|
305
330
|
return callback;
|
|
@@ -311,24 +336,30 @@ function getServerFunction(id) {
|
|
|
311
336
|
}
|
|
312
337
|
throw new Error("invalid server function: " + id);
|
|
313
338
|
}
|
|
314
|
-
function registerServerReference(id, fn) {
|
|
339
|
+
function registerServerReference(id, fn, name) {
|
|
315
340
|
registerServerFunction(id, fn);
|
|
316
341
|
return {
|
|
317
342
|
id,
|
|
318
|
-
fn
|
|
343
|
+
fn,
|
|
344
|
+
name
|
|
319
345
|
};
|
|
320
346
|
}
|
|
321
347
|
function createServerReference({
|
|
322
348
|
id,
|
|
323
|
-
fn
|
|
349
|
+
fn,
|
|
350
|
+
name
|
|
324
351
|
}) {
|
|
325
352
|
if (typeof fn !== "function") throw new Error("Export from a 'use server' module must be a function");
|
|
353
|
+
const metadata = name === undefined ? {} : {
|
|
354
|
+
name
|
|
355
|
+
};
|
|
326
356
|
return new Proxy(fn, {
|
|
327
|
-
get(target, prop
|
|
357
|
+
get(target, prop) {
|
|
358
|
+
if (prop === "id") return id;
|
|
328
359
|
if (prop === "url") {
|
|
329
360
|
return `${config.endpoint}?id=${encodeURIComponent(id)}`;
|
|
330
361
|
}
|
|
331
|
-
if (prop ===
|
|
362
|
+
if (prop === SERVER_FUNCTION_METADATA) return metadata;
|
|
332
363
|
return target[prop];
|
|
333
364
|
},
|
|
334
365
|
apply(target, thisArg, args) {
|
|
@@ -347,6 +378,15 @@ function createServerReference({
|
|
|
347
378
|
}
|
|
348
379
|
});
|
|
349
380
|
}
|
|
381
|
+
function GET(fn) {
|
|
382
|
+
if (!isServerFunction(fn) || typeof fn.id !== "string") {
|
|
383
|
+
throw new Error("GET expects a server function reference");
|
|
384
|
+
}
|
|
385
|
+
METHODS.set(fn.id, "GET");
|
|
386
|
+
return withMeta(fn, {
|
|
387
|
+
method: "GET"
|
|
388
|
+
});
|
|
389
|
+
}
|
|
350
390
|
function getServerFunctionMeta() {
|
|
351
391
|
const event = getRequestEvent();
|
|
352
392
|
return event && event.locals.serverFunctionMeta;
|
|
@@ -379,6 +419,15 @@ async function parseArguments(request, url, instance, codec) {
|
|
|
379
419
|
}
|
|
380
420
|
return parsed;
|
|
381
421
|
}
|
|
422
|
+
async function foldFlightData(hook, event, headers, outcome) {
|
|
423
|
+
const data = await hook(event, outcome);
|
|
424
|
+
if (data === undefined) return outcome.value;
|
|
425
|
+
headers.set(SINGLE_FLIGHT_HEADER, "true");
|
|
426
|
+
return {
|
|
427
|
+
value: outcome.value,
|
|
428
|
+
data
|
|
429
|
+
};
|
|
430
|
+
}
|
|
382
431
|
function serializedResponse(value, headers, codec) {
|
|
383
432
|
headers.set(BODY_FORMAT_HEADER, BodyFormat.Serialized);
|
|
384
433
|
headers.set("Content-Type", "text/plain");
|
|
@@ -421,11 +470,22 @@ async function handleServerFunctionRequest(request, options = {}) {
|
|
|
421
470
|
status: 404
|
|
422
471
|
});
|
|
423
472
|
}
|
|
473
|
+
const allowedMethod = METHODS.get(functionId) || "POST";
|
|
474
|
+
if (request.method === "GET" !== (allowedMethod === "GET")) {
|
|
475
|
+
return new Response(process.env.NODE_ENV === "development" ? `Method not allowed for server function: ${functionId}` : null, {
|
|
476
|
+
status: 405,
|
|
477
|
+
headers: {
|
|
478
|
+
Allow: allowedMethod
|
|
479
|
+
}
|
|
480
|
+
});
|
|
481
|
+
}
|
|
424
482
|
const event = options.createEvent ? options.createEvent(request) : {
|
|
425
483
|
request,
|
|
426
484
|
locals: {}
|
|
427
485
|
};
|
|
428
486
|
const provide = options.provideEvent || provideEvent;
|
|
487
|
+
const flightHook = options.collectFlightData !== undefined ? options.collectFlightData : config.collectFlightData;
|
|
488
|
+
const collectsFlight = !!(flightHook && instance && request.headers.has(SINGLE_FLIGHT_HEADER));
|
|
429
489
|
const parsed = await parseArguments(request, url, instance, codec);
|
|
430
490
|
const headers = new Headers();
|
|
431
491
|
try {
|
|
@@ -442,6 +502,7 @@ async function handleServerFunctionRequest(request, options = {}) {
|
|
|
442
502
|
});
|
|
443
503
|
}
|
|
444
504
|
let status = 200;
|
|
505
|
+
let metadata;
|
|
445
506
|
if (isResponseEnvelope(result)) {
|
|
446
507
|
const {
|
|
447
508
|
response,
|
|
@@ -456,6 +517,7 @@ async function handleServerFunctionRequest(request, options = {}) {
|
|
|
456
517
|
if (response && response.status && (response.status < 300 || response.status >= 400)) {
|
|
457
518
|
status = response.status;
|
|
458
519
|
}
|
|
520
|
+
metadata = response;
|
|
459
521
|
result = value;
|
|
460
522
|
} else if (result instanceof Response) {
|
|
461
523
|
if (result.headers && result.headers.has("X-Content-Raw")) return result;
|
|
@@ -466,11 +528,21 @@ async function handleServerFunctionRequest(request, options = {}) {
|
|
|
466
528
|
if (result.status && (result.status < 300 || result.status >= 400)) {
|
|
467
529
|
status = result.status;
|
|
468
530
|
}
|
|
531
|
+
metadata = result;
|
|
469
532
|
if (result.body == null) {
|
|
470
533
|
result = null;
|
|
471
534
|
}
|
|
472
535
|
}
|
|
473
536
|
}
|
|
537
|
+
if (collectsFlight) {
|
|
538
|
+
result = await foldFlightData(flightHook, event, headers, {
|
|
539
|
+
id: functionId,
|
|
540
|
+
value: result,
|
|
541
|
+
response: metadata,
|
|
542
|
+
request,
|
|
543
|
+
thrown: false
|
|
544
|
+
});
|
|
545
|
+
}
|
|
474
546
|
if (!instance) {
|
|
475
547
|
if (options.handleNoJS) return options.handleNoJS(result, request, parsed);
|
|
476
548
|
if (result instanceof Response) return result;
|
|
@@ -487,6 +559,7 @@ async function handleServerFunctionRequest(request, options = {}) {
|
|
|
487
559
|
});
|
|
488
560
|
}
|
|
489
561
|
let status = 200;
|
|
562
|
+
let metadata;
|
|
490
563
|
if (isResponseEnvelope(x)) {
|
|
491
564
|
const {
|
|
492
565
|
response,
|
|
@@ -498,6 +571,7 @@ async function handleServerFunctionRequest(request, options = {}) {
|
|
|
498
571
|
if (response && response.status && (!instance || response.status < 300 || response.status >= 400)) {
|
|
499
572
|
status = response.status;
|
|
500
573
|
}
|
|
574
|
+
metadata = response;
|
|
501
575
|
x = value;
|
|
502
576
|
} else if (x instanceof Response) {
|
|
503
577
|
if (x.headers) {
|
|
@@ -506,10 +580,20 @@ async function handleServerFunctionRequest(request, options = {}) {
|
|
|
506
580
|
if (x.status && (!instance || x.status < 300 || x.status >= 400)) {
|
|
507
581
|
status = x.status;
|
|
508
582
|
}
|
|
583
|
+
metadata = x;
|
|
509
584
|
if (x.body == null) {
|
|
510
585
|
x = null;
|
|
511
586
|
}
|
|
512
587
|
}
|
|
588
|
+
if (collectsFlight) {
|
|
589
|
+
x = await foldFlightData(flightHook, event, headers, {
|
|
590
|
+
id: functionId,
|
|
591
|
+
value: x,
|
|
592
|
+
response: metadata,
|
|
593
|
+
request,
|
|
594
|
+
thrown: true
|
|
595
|
+
});
|
|
596
|
+
}
|
|
513
597
|
headers.set("X-Server-Function-Error", "true");
|
|
514
598
|
if (!instance) {
|
|
515
599
|
if (options.handleNoJS) return options.handleNoJS(x, request, parsed, true);
|
|
@@ -531,12 +615,18 @@ async function handleServerFunctionRequest(request, options = {}) {
|
|
|
531
615
|
}
|
|
532
616
|
|
|
533
617
|
exports.FUNCTION_HEADER = FUNCTION_HEADER;
|
|
618
|
+
exports.GET = GET;
|
|
534
619
|
exports.INSTANCE_HEADER = INSTANCE_HEADER;
|
|
620
|
+
exports.SINGLE_FLIGHT_HEADER = SINGLE_FLIGHT_HEADER;
|
|
535
621
|
exports.configureServerFunctionsServer = configureServerFunctionsServer;
|
|
536
622
|
exports.createServerReference = createServerReference;
|
|
537
623
|
exports.decodeResponse = decodeResponse;
|
|
538
624
|
exports.getServerFunction = getServerFunction;
|
|
539
625
|
exports.getServerFunctionMeta = getServerFunctionMeta;
|
|
626
|
+
exports.getServerFunctionMetadata = getServerFunctionMetadata;
|
|
540
627
|
exports.handleServerFunctionRequest = handleServerFunctionRequest;
|
|
628
|
+
exports.isServerFunction = isServerFunction;
|
|
541
629
|
exports.registerServerFunction = registerServerFunction;
|
|
542
630
|
exports.registerServerReference = registerServerReference;
|
|
631
|
+
exports.subscribeFlightData = subscribeFlightData;
|
|
632
|
+
exports.withMeta = withMeta;
|
|
@@ -65,9 +65,30 @@ 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";
|
|
69
89
|
const INSTANCE_HEADER = "X-Server-Function-Instance";
|
|
70
90
|
const BODY_FORMAT_HEADER = "X-Server-Function-Format";
|
|
91
|
+
const SINGLE_FLIGHT_HEADER = "X-Single-Flight";
|
|
71
92
|
const FILE_FORM_KEY = "__server_function_file__";
|
|
72
93
|
const BodyFormat = {
|
|
73
94
|
Serialized: "0",
|
|
@@ -280,14 +301,17 @@ async function decodeResponse(response, codecOptions) {
|
|
|
280
301
|
|
|
281
302
|
const config = {
|
|
282
303
|
provideEvent: undefined,
|
|
304
|
+
collectFlightData: undefined,
|
|
283
305
|
endpoint: "/_server"
|
|
284
306
|
};
|
|
285
307
|
function configureServerFunctionsServer({
|
|
286
308
|
provideEvent,
|
|
309
|
+
collectFlightData,
|
|
287
310
|
endpoint,
|
|
288
311
|
codec
|
|
289
312
|
} = {}) {
|
|
290
313
|
if (provideEvent !== undefined) config.provideEvent = provideEvent;
|
|
314
|
+
if (collectFlightData !== undefined) config.collectFlightData = collectFlightData;
|
|
291
315
|
if (endpoint !== undefined) config.endpoint = endpoint;
|
|
292
316
|
if (codec !== undefined) configureServerFunctionsCodec(codec);
|
|
293
317
|
}
|
|
@@ -298,6 +322,7 @@ function provideEvent(event, fn) {
|
|
|
298
322
|
throw new Error("No request event provider. Configure one with configureServerFunctionsServer({ provideEvent }).");
|
|
299
323
|
}
|
|
300
324
|
const REGISTRATIONS = new Map();
|
|
325
|
+
const METHODS = new Map();
|
|
301
326
|
function registerServerFunction(id, callback) {
|
|
302
327
|
REGISTRATIONS.set(id, callback);
|
|
303
328
|
return callback;
|
|
@@ -309,24 +334,30 @@ function getServerFunction(id) {
|
|
|
309
334
|
}
|
|
310
335
|
throw new Error("invalid server function: " + id);
|
|
311
336
|
}
|
|
312
|
-
function registerServerReference(id, fn) {
|
|
337
|
+
function registerServerReference(id, fn, name) {
|
|
313
338
|
registerServerFunction(id, fn);
|
|
314
339
|
return {
|
|
315
340
|
id,
|
|
316
|
-
fn
|
|
341
|
+
fn,
|
|
342
|
+
name
|
|
317
343
|
};
|
|
318
344
|
}
|
|
319
345
|
function createServerReference({
|
|
320
346
|
id,
|
|
321
|
-
fn
|
|
347
|
+
fn,
|
|
348
|
+
name
|
|
322
349
|
}) {
|
|
323
350
|
if (typeof fn !== "function") throw new Error("Export from a 'use server' module must be a function");
|
|
351
|
+
const metadata = name === undefined ? {} : {
|
|
352
|
+
name
|
|
353
|
+
};
|
|
324
354
|
return new Proxy(fn, {
|
|
325
|
-
get(target, prop
|
|
355
|
+
get(target, prop) {
|
|
356
|
+
if (prop === "id") return id;
|
|
326
357
|
if (prop === "url") {
|
|
327
358
|
return `${config.endpoint}?id=${encodeURIComponent(id)}`;
|
|
328
359
|
}
|
|
329
|
-
if (prop ===
|
|
360
|
+
if (prop === SERVER_FUNCTION_METADATA) return metadata;
|
|
330
361
|
return target[prop];
|
|
331
362
|
},
|
|
332
363
|
apply(target, thisArg, args) {
|
|
@@ -345,6 +376,15 @@ function createServerReference({
|
|
|
345
376
|
}
|
|
346
377
|
});
|
|
347
378
|
}
|
|
379
|
+
function GET(fn) {
|
|
380
|
+
if (!isServerFunction(fn) || typeof fn.id !== "string") {
|
|
381
|
+
throw new Error("GET expects a server function reference");
|
|
382
|
+
}
|
|
383
|
+
METHODS.set(fn.id, "GET");
|
|
384
|
+
return withMeta(fn, {
|
|
385
|
+
method: "GET"
|
|
386
|
+
});
|
|
387
|
+
}
|
|
348
388
|
function getServerFunctionMeta() {
|
|
349
389
|
const event = getRequestEvent();
|
|
350
390
|
return event && event.locals.serverFunctionMeta;
|
|
@@ -377,6 +417,15 @@ async function parseArguments(request, url, instance, codec) {
|
|
|
377
417
|
}
|
|
378
418
|
return parsed;
|
|
379
419
|
}
|
|
420
|
+
async function foldFlightData(hook, event, headers, outcome) {
|
|
421
|
+
const data = await hook(event, outcome);
|
|
422
|
+
if (data === undefined) return outcome.value;
|
|
423
|
+
headers.set(SINGLE_FLIGHT_HEADER, "true");
|
|
424
|
+
return {
|
|
425
|
+
value: outcome.value,
|
|
426
|
+
data
|
|
427
|
+
};
|
|
428
|
+
}
|
|
380
429
|
function serializedResponse(value, headers, codec) {
|
|
381
430
|
headers.set(BODY_FORMAT_HEADER, BodyFormat.Serialized);
|
|
382
431
|
headers.set("Content-Type", "text/plain");
|
|
@@ -419,11 +468,22 @@ async function handleServerFunctionRequest(request, options = {}) {
|
|
|
419
468
|
status: 404
|
|
420
469
|
});
|
|
421
470
|
}
|
|
471
|
+
const allowedMethod = METHODS.get(functionId) || "POST";
|
|
472
|
+
if (request.method === "GET" !== (allowedMethod === "GET")) {
|
|
473
|
+
return new Response(process.env.NODE_ENV === "development" ? `Method not allowed for server function: ${functionId}` : null, {
|
|
474
|
+
status: 405,
|
|
475
|
+
headers: {
|
|
476
|
+
Allow: allowedMethod
|
|
477
|
+
}
|
|
478
|
+
});
|
|
479
|
+
}
|
|
422
480
|
const event = options.createEvent ? options.createEvent(request) : {
|
|
423
481
|
request,
|
|
424
482
|
locals: {}
|
|
425
483
|
};
|
|
426
484
|
const provide = options.provideEvent || provideEvent;
|
|
485
|
+
const flightHook = options.collectFlightData !== undefined ? options.collectFlightData : config.collectFlightData;
|
|
486
|
+
const collectsFlight = !!(flightHook && instance && request.headers.has(SINGLE_FLIGHT_HEADER));
|
|
427
487
|
const parsed = await parseArguments(request, url, instance, codec);
|
|
428
488
|
const headers = new Headers();
|
|
429
489
|
try {
|
|
@@ -440,6 +500,7 @@ async function handleServerFunctionRequest(request, options = {}) {
|
|
|
440
500
|
});
|
|
441
501
|
}
|
|
442
502
|
let status = 200;
|
|
503
|
+
let metadata;
|
|
443
504
|
if (isResponseEnvelope(result)) {
|
|
444
505
|
const {
|
|
445
506
|
response,
|
|
@@ -454,6 +515,7 @@ async function handleServerFunctionRequest(request, options = {}) {
|
|
|
454
515
|
if (response && response.status && (response.status < 300 || response.status >= 400)) {
|
|
455
516
|
status = response.status;
|
|
456
517
|
}
|
|
518
|
+
metadata = response;
|
|
457
519
|
result = value;
|
|
458
520
|
} else if (result instanceof Response) {
|
|
459
521
|
if (result.headers && result.headers.has("X-Content-Raw")) return result;
|
|
@@ -464,11 +526,21 @@ async function handleServerFunctionRequest(request, options = {}) {
|
|
|
464
526
|
if (result.status && (result.status < 300 || result.status >= 400)) {
|
|
465
527
|
status = result.status;
|
|
466
528
|
}
|
|
529
|
+
metadata = result;
|
|
467
530
|
if (result.body == null) {
|
|
468
531
|
result = null;
|
|
469
532
|
}
|
|
470
533
|
}
|
|
471
534
|
}
|
|
535
|
+
if (collectsFlight) {
|
|
536
|
+
result = await foldFlightData(flightHook, event, headers, {
|
|
537
|
+
id: functionId,
|
|
538
|
+
value: result,
|
|
539
|
+
response: metadata,
|
|
540
|
+
request,
|
|
541
|
+
thrown: false
|
|
542
|
+
});
|
|
543
|
+
}
|
|
472
544
|
if (!instance) {
|
|
473
545
|
if (options.handleNoJS) return options.handleNoJS(result, request, parsed);
|
|
474
546
|
if (result instanceof Response) return result;
|
|
@@ -485,6 +557,7 @@ async function handleServerFunctionRequest(request, options = {}) {
|
|
|
485
557
|
});
|
|
486
558
|
}
|
|
487
559
|
let status = 200;
|
|
560
|
+
let metadata;
|
|
488
561
|
if (isResponseEnvelope(x)) {
|
|
489
562
|
const {
|
|
490
563
|
response,
|
|
@@ -496,6 +569,7 @@ async function handleServerFunctionRequest(request, options = {}) {
|
|
|
496
569
|
if (response && response.status && (!instance || response.status < 300 || response.status >= 400)) {
|
|
497
570
|
status = response.status;
|
|
498
571
|
}
|
|
572
|
+
metadata = response;
|
|
499
573
|
x = value;
|
|
500
574
|
} else if (x instanceof Response) {
|
|
501
575
|
if (x.headers) {
|
|
@@ -504,10 +578,20 @@ async function handleServerFunctionRequest(request, options = {}) {
|
|
|
504
578
|
if (x.status && (!instance || x.status < 300 || x.status >= 400)) {
|
|
505
579
|
status = x.status;
|
|
506
580
|
}
|
|
581
|
+
metadata = x;
|
|
507
582
|
if (x.body == null) {
|
|
508
583
|
x = null;
|
|
509
584
|
}
|
|
510
585
|
}
|
|
586
|
+
if (collectsFlight) {
|
|
587
|
+
x = await foldFlightData(flightHook, event, headers, {
|
|
588
|
+
id: functionId,
|
|
589
|
+
value: x,
|
|
590
|
+
response: metadata,
|
|
591
|
+
request,
|
|
592
|
+
thrown: true
|
|
593
|
+
});
|
|
594
|
+
}
|
|
511
595
|
headers.set("X-Server-Function-Error", "true");
|
|
512
596
|
if (!instance) {
|
|
513
597
|
if (options.handleNoJS) return options.handleNoJS(x, request, parsed, true);
|
|
@@ -528,4 +612,4 @@ async function handleServerFunctionRequest(request, options = {}) {
|
|
|
528
612
|
}
|
|
529
613
|
}
|
|
530
614
|
|
|
531
|
-
export { FUNCTION_HEADER, INSTANCE_HEADER, configureServerFunctionsServer, createServerReference, decodeResponse, getServerFunction, getServerFunctionMeta, handleServerFunctionRequest, registerServerFunction, registerServerReference };
|
|
615
|
+
export { FUNCTION_HEADER, GET, INSTANCE_HEADER, SINGLE_FLIGHT_HEADER, configureServerFunctionsServer, createServerReference, decodeResponse, getServerFunction, getServerFunctionMeta, getServerFunctionMetadata, handleServerFunctionRequest, isServerFunction, registerServerFunction, registerServerReference, subscribeFlightData, withMeta };
|
|
@@ -1,6 +1,48 @@
|
|
|
1
1
|
import { JSONCodecOptions } from "../serializer.js";
|
|
2
|
+
import { ServerFunction, ServerFunctionMetadata } from "./shared.js";
|
|
2
3
|
|
|
3
|
-
export {
|
|
4
|
+
export {
|
|
5
|
+
FUNCTION_HEADER,
|
|
6
|
+
INSTANCE_HEADER,
|
|
7
|
+
SINGLE_FLIGHT_HEADER,
|
|
8
|
+
decodeResponse,
|
|
9
|
+
getServerFunctionMetadata,
|
|
10
|
+
isServerFunction,
|
|
11
|
+
subscribeFlightData,
|
|
12
|
+
withMeta
|
|
13
|
+
} from "./shared.js";
|
|
14
|
+
export type {
|
|
15
|
+
FlightDataConsumer,
|
|
16
|
+
FlightDataContext,
|
|
17
|
+
ServerFunction,
|
|
18
|
+
ServerFunctionMetadata,
|
|
19
|
+
SingleFlightPayload
|
|
20
|
+
} from "./shared.js";
|
|
21
|
+
|
|
22
|
+
/** The context `prepareRequest` receives alongside the outgoing RequestInit. */
|
|
23
|
+
export interface PrepareRequestContext {
|
|
24
|
+
/** The build-stable id of the function being called. */
|
|
25
|
+
id: string;
|
|
26
|
+
/**
|
|
27
|
+
* The reference's declaration metadata (e.g. `method: "GET"` for
|
|
28
|
+
* `GET(fn)` references). Plain references carry an empty object.
|
|
29
|
+
*/
|
|
30
|
+
meta: ServerFunctionMetadata | undefined;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Client-side session-dynamic transport hook: runs before every
|
|
35
|
+
* server-function fetch. Return (or mutate and return) the RequestInit the
|
|
36
|
+
* transport will use — the hook sees the final init, transport headers
|
|
37
|
+
* included. The motivating case is dynamic credentials that rotate during
|
|
38
|
+
* a session and apply uniformly to every call (OAuth bearer tokens); it is
|
|
39
|
+
* the client-side symmetric of the server handler hooks. Single hook, not
|
|
40
|
+
* a chain — compose by wrapping functions in userland.
|
|
41
|
+
*/
|
|
42
|
+
export type PrepareRequestHook = (
|
|
43
|
+
init: RequestInit,
|
|
44
|
+
context: PrepareRequestContext
|
|
45
|
+
) => RequestInit | Promise<RequestInit>;
|
|
4
46
|
|
|
5
47
|
/** Options for `configureServerFunctionsClient`. */
|
|
6
48
|
export interface ServerFunctionsClientConfig {
|
|
@@ -18,40 +60,72 @@ export interface ServerFunctionsClientConfig {
|
|
|
18
60
|
* `decodeResponse` sees them too.
|
|
19
61
|
*/
|
|
20
62
|
codec?: JSONCodecOptions;
|
|
63
|
+
/**
|
|
64
|
+
* Runs before every server-function fetch. Return (or mutate and return)
|
|
65
|
+
* the RequestInit the transport will use; `context.meta` is the
|
|
66
|
+
* reference's declaration metadata (e.g. method). For session-dynamic
|
|
67
|
+
* cross-cutting concerns — bearer tokens, tracing headers:
|
|
68
|
+
*
|
|
69
|
+
* ```ts
|
|
70
|
+
* configureServerFunctionsClient({
|
|
71
|
+
* prepareRequest(init) {
|
|
72
|
+
* return {
|
|
73
|
+
* ...init,
|
|
74
|
+
* headers: { ...init.headers, Authorization: `Bearer ${session.token()}` }
|
|
75
|
+
* };
|
|
76
|
+
* }
|
|
77
|
+
* });
|
|
78
|
+
* ```
|
|
79
|
+
*/
|
|
80
|
+
prepareRequest?: PrepareRequestHook;
|
|
21
81
|
}
|
|
22
82
|
|
|
23
83
|
/**
|
|
24
84
|
* Configures the client transport. Call once, before any server function is
|
|
25
85
|
* invoked — typically in the client entry, next to `hydrate()`. Only needed
|
|
26
|
-
* when deviating from the defaults (custom endpoint
|
|
86
|
+
* when deviating from the defaults (custom endpoint, codec plugins, or a
|
|
87
|
+
* `prepareRequest` hook).
|
|
27
88
|
*/
|
|
28
89
|
export function configureServerFunctionsClient(config?: ServerFunctionsClientConfig): void;
|
|
29
90
|
|
|
30
91
|
/**
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
92
|
+
* Declares a server function callable over HTTP GET: calls to the returned
|
|
93
|
+
* reference go out as GET requests with the arguments codec-encoded in the
|
|
94
|
+
* query string — cacheable by HTTP infrastructure. Cache headers flow
|
|
95
|
+
* through the handler's header forwarding
|
|
96
|
+
* (`respond(data, { headers: { "cache-control": "max-age=60" } })`).
|
|
97
|
+
*
|
|
98
|
+
* The declaration rides the metadata channel
|
|
99
|
+
* (`getServerFunctionMetadata(fn)?.method === "GET"`) for routers and
|
|
100
|
+
* integrations to detect, and the server enforces it: GET-declared
|
|
101
|
+
* functions accept GET requests (and only GET), everything else answers
|
|
102
|
+
* 405. Server-side the wrapper is identity-flavored — SSR calls stay
|
|
103
|
+
* in-process.
|
|
104
|
+
*
|
|
105
|
+
* Wrap the reference at its declaration; the compiler round-trips the call
|
|
106
|
+
* in both builds:
|
|
107
|
+
*
|
|
108
|
+
* ```ts
|
|
109
|
+
* export const getUser = GET(async (id: string) => {
|
|
110
|
+
* "use server";
|
|
111
|
+
* return db.users.find(id);
|
|
112
|
+
* });
|
|
113
|
+
* ```
|
|
34
114
|
*/
|
|
35
|
-
export
|
|
36
|
-
(...args:
|
|
37
|
-
|
|
38
|
-
url: string;
|
|
39
|
-
/**
|
|
40
|
-
* Variant issuing GET requests with the arguments encoded in the query
|
|
41
|
-
* string — cacheable by HTTP infrastructure.
|
|
42
|
-
*/
|
|
43
|
-
GET: ServerFunctionCallable;
|
|
44
|
-
/** Variant applying a custom RequestInit to every call (headers etc.). */
|
|
45
|
-
withOptions(options: RequestInit): ServerFunctionCallable;
|
|
46
|
-
}
|
|
115
|
+
export function GET<A extends readonly any[], R>(
|
|
116
|
+
fn: (...args: A) => R
|
|
117
|
+
): ServerFunction<A, Awaited<R>>;
|
|
47
118
|
|
|
48
119
|
/**
|
|
49
120
|
* Compiler ABI — emitted by compiled `"use server"` client output where a
|
|
50
121
|
* server function was referenced; produces the fetch-backed callable for
|
|
51
|
-
* the function's build-stable id.
|
|
122
|
+
* the function's build-stable id. Development builds pass the function's
|
|
123
|
+
* source name as the trailing argument (dev-only metadata seeded on the
|
|
124
|
+
* metadata channel; never emitted in production). Not meant for
|
|
125
|
+
* hand-written code.
|
|
52
126
|
* @internal
|
|
53
127
|
*/
|
|
54
|
-
export function createServerReference(id: string):
|
|
128
|
+
export function createServerReference(id: string, name?: string): ServerFunction;
|
|
55
129
|
|
|
56
130
|
/**
|
|
57
131
|
* Compiler ABI — only ever referenced by server-mode compiler output;
|