@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.
@@ -56,9 +56,63 @@ function configureServerFunctionsCodec(codec) {
56
56
  function getServerFunctionsCodec() {
57
57
  return codecConfig.codec;
58
58
  }
59
+ const flightConfig = {
60
+ consumer: undefined
61
+ };
62
+ function subscribeFlightData(consumer) {
63
+ flightConfig.consumer = consumer;
64
+ return () => {
65
+ if (flightConfig.consumer === consumer) flightConfig.consumer = undefined;
66
+ };
67
+ }
68
+ function getFlightDataConsumer() {
69
+ return flightConfig.consumer;
70
+ }
71
+ const SERVER_FUNCTION_METADATA = Symbol.for("solid.ServerFunctionMetadata");
72
+ function getServerFunctionMetadata(fn) {
73
+ if (typeof fn !== "function") return undefined;
74
+ return fn[SERVER_FUNCTION_METADATA] || undefined;
75
+ }
76
+ function isServerFunction(fn) {
77
+ return typeof fn === "function" && !!fn[SERVER_FUNCTION_METADATA];
78
+ }
79
+ function withMeta(fn, meta) {
80
+ const metadata = getServerFunctionMetadata(fn);
81
+ if (!metadata) {
82
+ throw new Error("withMeta expects a server function reference");
83
+ }
84
+ Object.assign(metadata, meta);
85
+ return fn;
86
+ }
59
87
  const FUNCTION_HEADER = "X-Server-Function-Id";
88
+ const ERROR_HEADER = "X-Server-Function-Error";
89
+ const ERROR_HEADER_MARKER = "=?1?";
90
+ const NEEDS_ENCODING = /[^\x20-\x7e\xa0-\xff]/;
91
+ function encodeErrorHeaderValue(value) {
92
+ let stripped = String(value).replace(/[\r\n]+/g, "");
93
+ if (!NEEDS_ENCODING.test(stripped) && !stripped.startsWith(ERROR_HEADER_MARKER) && stripped === stripped.trim()) {
94
+ return stripped;
95
+ }
96
+ if (typeof stripped.toWellFormed === "function") {
97
+ stripped = stripped.toWellFormed();
98
+ } else {
99
+ stripped = stripped.replace(/[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?<![\uD800-\uDBFF])[\uDC00-\uDFFF]/g, "\uFFFD");
100
+ }
101
+ return ERROR_HEADER_MARKER + encodeURIComponent(stripped);
102
+ }
103
+ function decodeErrorHeaderValue(value) {
104
+ if (typeof value !== "string" || !value.startsWith(ERROR_HEADER_MARKER)) {
105
+ return value;
106
+ }
107
+ try {
108
+ return decodeURIComponent(value.slice(ERROR_HEADER_MARKER.length));
109
+ } catch {
110
+ return value;
111
+ }
112
+ }
60
113
  const INSTANCE_HEADER = "X-Server-Function-Instance";
61
114
  const BODY_FORMAT_HEADER = "X-Server-Function-Format";
115
+ const SINGLE_FLIGHT_HEADER = "X-Single-Flight";
62
116
  const FILE_FORM_KEY = "__server_function_file__";
63
117
  const BodyFormat = {
64
118
  Serialized: "0",
@@ -271,30 +325,44 @@ async function decodeResponse(response, codecOptions) {
271
325
  }
272
326
 
273
327
  const config = {
274
- endpoint: "/_server"
328
+ endpoint: "/_server",
329
+ prepareRequest: undefined
275
330
  };
276
331
  function configureServerFunctionsClient({
277
332
  endpoint,
278
- codec
333
+ codec,
334
+ prepareRequest
279
335
  } = {}) {
280
336
  if (endpoint !== undefined) config.endpoint = endpoint;
281
337
  if (codec !== undefined) configureServerFunctionsCodec(codec);
338
+ if (prepareRequest !== undefined) config.prepareRequest = prepareRequest;
282
339
  }
283
340
  let INSTANCE = 0;
284
- function createRequest(base, id, instance, options) {
285
- return fetch(base, {
341
+ async function createRequest(base, id, instance, options, meta) {
342
+ const headers = {
343
+ ...options.headers,
344
+ [FUNCTION_HEADER]: id,
345
+ [INSTANCE_HEADER]: instance
346
+ };
347
+ if (getFlightDataConsumer() && (!options.method || options.method.toUpperCase() !== "GET")) {
348
+ headers[SINGLE_FLIGHT_HEADER] = "true";
349
+ }
350
+ let init = {
286
351
  method: "POST",
287
352
  ...options,
288
- headers: {
289
- ...options.headers,
290
- [FUNCTION_HEADER]: id,
291
- [INSTANCE_HEADER]: instance
292
- }
293
- });
353
+ headers
354
+ };
355
+ if (config.prepareRequest) {
356
+ init = (await config.prepareRequest(init, {
357
+ id,
358
+ meta
359
+ })) || init;
360
+ }
361
+ return fetch(base, init);
294
362
  }
295
- async function initializeResponse(base, id, instance, options, args) {
363
+ async function initializeResponse(base, id, instance, options, args, meta) {
296
364
  if (args.length === 0) {
297
- return createRequest(base, id, instance, options);
365
+ return createRequest(base, id, instance, options, meta);
298
366
  }
299
367
  if (args.length === 1) {
300
368
  const result = getHeadersAndBody(args[0]);
@@ -306,7 +374,7 @@ async function initializeResponse(base, id, instance, options, args) {
306
374
  ...options.headers,
307
375
  ...result.headers
308
376
  }
309
- });
377
+ }, meta);
310
378
  }
311
379
  }
312
380
  return createRequest(base, id, instance, {
@@ -317,54 +385,92 @@ async function initializeResponse(base, id, instance, options, args) {
317
385
  "Content-Type": "text/plain",
318
386
  [BODY_FORMAT_HEADER]: BodyFormat.Serialized
319
387
  }
320
- });
388
+ }, meta);
321
389
  }
322
- async function fetchServerFunction(base, id, options, args) {
390
+ async function fetchServerFunction(base, id, options, args, meta) {
323
391
  const instance = `server-function:${INSTANCE++}`;
324
- const response = await initializeResponse(base, id, instance, options, args);
325
- if (response.headers.has("Location") || response.headers.has("X-Revalidate") || response.headers.has("X-Single-Flight")) {
392
+ const response = await initializeResponse(base, id, instance, options, args, meta);
393
+ if (response.headers.has(SINGLE_FLIGHT_HEADER)) {
394
+ const consumer = getFlightDataConsumer();
395
+ if (consumer) {
396
+ const payload = await decodeResponse(response);
397
+ await consumer(payload.data, {
398
+ response
399
+ });
400
+ if (response.headers.has(ERROR_HEADER) && !response.headers.has("Location") && !response.headers.has("X-Revalidate")) {
401
+ throw payload.value;
402
+ }
403
+ return payload.value;
404
+ }
405
+ }
406
+ if (response.headers.has("Location") || response.headers.has("X-Revalidate") || response.headers.has(SINGLE_FLIGHT_HEADER)) {
326
407
  return response;
327
408
  }
328
409
  const result = await decodeResponse(response.clone());
329
- if (response.headers.has("X-Server-Function-Error")) {
410
+ if (response.headers.has(ERROR_HEADER)) {
330
411
  throw result;
331
412
  }
332
413
  return result;
333
414
  }
334
- function createServerReference(id) {
335
- const fn = (...args) => fetchServerFunction(config.endpoint, id, {}, args);
415
+ function createServerReference(id, name, base) {
416
+ const metadata = name === undefined ? {} : {
417
+ name
418
+ };
419
+ const fn = (...args) => fetchServerFunction(base || config.endpoint, id, {}, args, metadata);
420
+ fn[SERVER_FUNCTION_METADATA] = metadata;
336
421
  return new Proxy(fn, {
337
- get(target, prop, receiver) {
422
+ get(target, prop) {
423
+ if (prop === "id") return id;
338
424
  if (prop === "url") {
339
- return `${config.endpoint}?id=${encodeURIComponent(id)}`;
340
- }
341
- if (prop === "GET") {
342
- return receiver.withOptions({
343
- method: "GET"
344
- });
345
- }
346
- if (prop === "withOptions") {
347
- const url = `${config.endpoint}?id=${encodeURIComponent(id)}`;
348
- return options => {
349
- const wrapped = async (...args) => {
350
- const encodeArgs = options.method && options.method.toUpperCase() === "GET";
351
- return fetchServerFunction(encodeArgs ? url + (args.length ? `&args=${encodeURIComponent(await serializeString(args, getServerFunctionsCodec()))}` : "") : config.endpoint, id, options, encodeArgs ? [] : args);
352
- };
353
- wrapped.url = url;
354
- return wrapped;
355
- };
425
+ return base || `${config.endpoint}?id=${encodeURIComponent(id)}`;
356
426
  }
357
427
  return target[prop];
358
428
  }
359
429
  });
360
430
  }
431
+ function GET(fn) {
432
+ if (!isServerFunction(fn)) {
433
+ throw new Error("GET expects a server function reference");
434
+ }
435
+ const id = fn.id;
436
+ const metadata = {
437
+ ...getServerFunctionMetadata(fn)
438
+ };
439
+ const wrapped = async (...args) => {
440
+ let base = `${config.endpoint}?id=${encodeURIComponent(id)}`;
441
+ if (args.length) {
442
+ base += `&args=${encodeURIComponent(await serializeString(args, getServerFunctionsCodec()))}`;
443
+ }
444
+ return fetchServerFunction(base, id, {
445
+ method: "GET"
446
+ }, [], metadata);
447
+ };
448
+ wrapped[SERVER_FUNCTION_METADATA] = metadata;
449
+ wrapped.id = id;
450
+ Object.defineProperty(wrapped, "url", {
451
+ get: () => `${config.endpoint}?id=${encodeURIComponent(id)}`,
452
+ configurable: true
453
+ });
454
+ return withMeta(wrapped, {
455
+ method: "GET"
456
+ });
457
+ }
361
458
  function registerServerReference() {
362
459
  throw new Error("registerServerReference must not be called in the client build");
363
460
  }
364
461
 
462
+ exports.ERROR_HEADER = ERROR_HEADER;
365
463
  exports.FUNCTION_HEADER = FUNCTION_HEADER;
464
+ exports.GET = GET;
366
465
  exports.INSTANCE_HEADER = INSTANCE_HEADER;
466
+ exports.SINGLE_FLIGHT_HEADER = SINGLE_FLIGHT_HEADER;
367
467
  exports.configureServerFunctionsClient = configureServerFunctionsClient;
368
468
  exports.createServerReference = createServerReference;
469
+ exports.decodeErrorHeaderValue = decodeErrorHeaderValue;
369
470
  exports.decodeResponse = decodeResponse;
471
+ exports.encodeErrorHeaderValue = encodeErrorHeaderValue;
472
+ exports.getServerFunctionMetadata = getServerFunctionMetadata;
473
+ exports.isServerFunction = isServerFunction;
370
474
  exports.registerServerReference = registerServerReference;
475
+ exports.subscribeFlightData = subscribeFlightData;
476
+ exports.withMeta = withMeta;
@@ -54,9 +54,63 @@ function configureServerFunctionsCodec(codec) {
54
54
  function getServerFunctionsCodec() {
55
55
  return codecConfig.codec;
56
56
  }
57
+ const flightConfig = {
58
+ consumer: undefined
59
+ };
60
+ function subscribeFlightData(consumer) {
61
+ flightConfig.consumer = consumer;
62
+ return () => {
63
+ if (flightConfig.consumer === consumer) flightConfig.consumer = undefined;
64
+ };
65
+ }
66
+ function getFlightDataConsumer() {
67
+ return flightConfig.consumer;
68
+ }
69
+ const SERVER_FUNCTION_METADATA = Symbol.for("solid.ServerFunctionMetadata");
70
+ function getServerFunctionMetadata(fn) {
71
+ if (typeof fn !== "function") return undefined;
72
+ return fn[SERVER_FUNCTION_METADATA] || undefined;
73
+ }
74
+ function isServerFunction(fn) {
75
+ return typeof fn === "function" && !!fn[SERVER_FUNCTION_METADATA];
76
+ }
77
+ function withMeta(fn, meta) {
78
+ const metadata = getServerFunctionMetadata(fn);
79
+ if (!metadata) {
80
+ throw new Error("withMeta expects a server function reference");
81
+ }
82
+ Object.assign(metadata, meta);
83
+ return fn;
84
+ }
57
85
  const FUNCTION_HEADER = "X-Server-Function-Id";
86
+ const ERROR_HEADER = "X-Server-Function-Error";
87
+ const ERROR_HEADER_MARKER = "=?1?";
88
+ const NEEDS_ENCODING = /[^\x20-\x7e\xa0-\xff]/;
89
+ function encodeErrorHeaderValue(value) {
90
+ let stripped = String(value).replace(/[\r\n]+/g, "");
91
+ if (!NEEDS_ENCODING.test(stripped) && !stripped.startsWith(ERROR_HEADER_MARKER) && stripped === stripped.trim()) {
92
+ return stripped;
93
+ }
94
+ if (typeof stripped.toWellFormed === "function") {
95
+ stripped = stripped.toWellFormed();
96
+ } else {
97
+ stripped = stripped.replace(/[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?<![\uD800-\uDBFF])[\uDC00-\uDFFF]/g, "\uFFFD");
98
+ }
99
+ return ERROR_HEADER_MARKER + encodeURIComponent(stripped);
100
+ }
101
+ function decodeErrorHeaderValue(value) {
102
+ if (typeof value !== "string" || !value.startsWith(ERROR_HEADER_MARKER)) {
103
+ return value;
104
+ }
105
+ try {
106
+ return decodeURIComponent(value.slice(ERROR_HEADER_MARKER.length));
107
+ } catch {
108
+ return value;
109
+ }
110
+ }
58
111
  const INSTANCE_HEADER = "X-Server-Function-Instance";
59
112
  const BODY_FORMAT_HEADER = "X-Server-Function-Format";
113
+ const SINGLE_FLIGHT_HEADER = "X-Single-Flight";
60
114
  const FILE_FORM_KEY = "__server_function_file__";
61
115
  const BodyFormat = {
62
116
  Serialized: "0",
@@ -269,30 +323,44 @@ async function decodeResponse(response, codecOptions) {
269
323
  }
270
324
 
271
325
  const config = {
272
- endpoint: "/_server"
326
+ endpoint: "/_server",
327
+ prepareRequest: undefined
273
328
  };
274
329
  function configureServerFunctionsClient({
275
330
  endpoint,
276
- codec
331
+ codec,
332
+ prepareRequest
277
333
  } = {}) {
278
334
  if (endpoint !== undefined) config.endpoint = endpoint;
279
335
  if (codec !== undefined) configureServerFunctionsCodec(codec);
336
+ if (prepareRequest !== undefined) config.prepareRequest = prepareRequest;
280
337
  }
281
338
  let INSTANCE = 0;
282
- function createRequest(base, id, instance, options) {
283
- return fetch(base, {
339
+ async function createRequest(base, id, instance, options, meta) {
340
+ const headers = {
341
+ ...options.headers,
342
+ [FUNCTION_HEADER]: id,
343
+ [INSTANCE_HEADER]: instance
344
+ };
345
+ if (getFlightDataConsumer() && (!options.method || options.method.toUpperCase() !== "GET")) {
346
+ headers[SINGLE_FLIGHT_HEADER] = "true";
347
+ }
348
+ let init = {
284
349
  method: "POST",
285
350
  ...options,
286
- headers: {
287
- ...options.headers,
288
- [FUNCTION_HEADER]: id,
289
- [INSTANCE_HEADER]: instance
290
- }
291
- });
351
+ headers
352
+ };
353
+ if (config.prepareRequest) {
354
+ init = (await config.prepareRequest(init, {
355
+ id,
356
+ meta
357
+ })) || init;
358
+ }
359
+ return fetch(base, init);
292
360
  }
293
- async function initializeResponse(base, id, instance, options, args) {
361
+ async function initializeResponse(base, id, instance, options, args, meta) {
294
362
  if (args.length === 0) {
295
- return createRequest(base, id, instance, options);
363
+ return createRequest(base, id, instance, options, meta);
296
364
  }
297
365
  if (args.length === 1) {
298
366
  const result = getHeadersAndBody(args[0]);
@@ -304,7 +372,7 @@ async function initializeResponse(base, id, instance, options, args) {
304
372
  ...options.headers,
305
373
  ...result.headers
306
374
  }
307
- });
375
+ }, meta);
308
376
  }
309
377
  }
310
378
  return createRequest(base, id, instance, {
@@ -315,49 +383,78 @@ async function initializeResponse(base, id, instance, options, args) {
315
383
  "Content-Type": "text/plain",
316
384
  [BODY_FORMAT_HEADER]: BodyFormat.Serialized
317
385
  }
318
- });
386
+ }, meta);
319
387
  }
320
- async function fetchServerFunction(base, id, options, args) {
388
+ async function fetchServerFunction(base, id, options, args, meta) {
321
389
  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")) {
390
+ const response = await initializeResponse(base, id, instance, options, args, meta);
391
+ if (response.headers.has(SINGLE_FLIGHT_HEADER)) {
392
+ const consumer = getFlightDataConsumer();
393
+ if (consumer) {
394
+ const payload = await decodeResponse(response);
395
+ await consumer(payload.data, {
396
+ response
397
+ });
398
+ if (response.headers.has(ERROR_HEADER) && !response.headers.has("Location") && !response.headers.has("X-Revalidate")) {
399
+ throw payload.value;
400
+ }
401
+ return payload.value;
402
+ }
403
+ }
404
+ if (response.headers.has("Location") || response.headers.has("X-Revalidate") || response.headers.has(SINGLE_FLIGHT_HEADER)) {
324
405
  return response;
325
406
  }
326
407
  const result = await decodeResponse(response.clone());
327
- if (response.headers.has("X-Server-Function-Error")) {
408
+ if (response.headers.has(ERROR_HEADER)) {
328
409
  throw result;
329
410
  }
330
411
  return result;
331
412
  }
332
- function createServerReference(id) {
333
- const fn = (...args) => fetchServerFunction(config.endpoint, id, {}, args);
413
+ function createServerReference(id, name, base) {
414
+ const metadata = name === undefined ? {} : {
415
+ name
416
+ };
417
+ const fn = (...args) => fetchServerFunction(base || config.endpoint, id, {}, args, metadata);
418
+ fn[SERVER_FUNCTION_METADATA] = metadata;
334
419
  return new Proxy(fn, {
335
- get(target, prop, receiver) {
420
+ get(target, prop) {
421
+ if (prop === "id") return id;
336
422
  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
- };
423
+ return base || `${config.endpoint}?id=${encodeURIComponent(id)}`;
354
424
  }
355
425
  return target[prop];
356
426
  }
357
427
  });
358
428
  }
429
+ function GET(fn) {
430
+ if (!isServerFunction(fn)) {
431
+ throw new Error("GET expects a server function reference");
432
+ }
433
+ const id = fn.id;
434
+ const metadata = {
435
+ ...getServerFunctionMetadata(fn)
436
+ };
437
+ const wrapped = async (...args) => {
438
+ let base = `${config.endpoint}?id=${encodeURIComponent(id)}`;
439
+ if (args.length) {
440
+ base += `&args=${encodeURIComponent(await serializeString(args, getServerFunctionsCodec()))}`;
441
+ }
442
+ return fetchServerFunction(base, id, {
443
+ method: "GET"
444
+ }, [], metadata);
445
+ };
446
+ wrapped[SERVER_FUNCTION_METADATA] = metadata;
447
+ wrapped.id = id;
448
+ Object.defineProperty(wrapped, "url", {
449
+ get: () => `${config.endpoint}?id=${encodeURIComponent(id)}`,
450
+ configurable: true
451
+ });
452
+ return withMeta(wrapped, {
453
+ method: "GET"
454
+ });
455
+ }
359
456
  function registerServerReference() {
360
457
  throw new Error("registerServerReference must not be called in the client build");
361
458
  }
362
459
 
363
- export { FUNCTION_HEADER, INSTANCE_HEADER, configureServerFunctionsClient, createServerReference, decodeResponse, registerServerReference };
460
+ export { ERROR_HEADER, FUNCTION_HEADER, GET, INSTANCE_HEADER, SINGLE_FLIGHT_HEADER, configureServerFunctionsClient, createServerReference, decodeErrorHeaderValue, decodeResponse, encodeErrorHeaderValue, getServerFunctionMetadata, isServerFunction, registerServerReference, subscribeFlightData, withMeta };