@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.
@@ -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, receiver) {
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 === "GET") return receiver;
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, receiver) {
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 === "GET") return receiver;
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 { FUNCTION_HEADER, INSTANCE_HEADER, decodeResponse } from "./shared.js";
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 or codec plugins).
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
- * What a server function import is at runtime on the client: an async
32
- * callable that fetches the server, plus escape hatches for forms and
33
- * custom requests.
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 interface ServerFunctionCallable {
36
- (...args: any[]): Promise<any>;
37
- /** URL invoking this function directly over HTTP (e.g. form `action`s). */
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. Not meant for hand-written code.
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): ServerFunctionCallable;
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;