@rsc-kit/core 0.24.0 → 0.24.1

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.
@@ -1,4 +1,6 @@
1
1
  export declare class ServerValidationError extends Error {
2
+ /** Whichever copy of this module threw it; see KIND. */
3
+ static [Symbol.hasInstance](value: unknown): boolean;
2
4
  readonly errors: Record<string, string[]>;
3
5
  constructor(message: string, errors: Record<string, string[]>);
4
6
  }
@@ -6,19 +8,29 @@ export declare function noteRedirected(location: string): void;
6
8
  /** The redirect the action just performed, if it did - read once. */
7
9
  export declare function redirectedTo(): string | null;
8
10
  export declare class ServerRedirectError extends Error {
11
+ /** Whichever copy of this module threw it; see KIND. */
12
+ static [Symbol.hasInstance](value: unknown): boolean;
9
13
  readonly location: string;
10
14
  constructor(location: string);
11
15
  }
12
16
  export declare class ServerAuthenticationError extends Error {
17
+ /** Whichever copy of this module threw it; see KIND. */
18
+ static [Symbol.hasInstance](value: unknown): boolean;
13
19
  constructor(message?: string);
14
20
  }
15
21
  export declare class ServerAuthorizationError extends Error {
22
+ /** Whichever copy of this module threw it; see KIND. */
23
+ static [Symbol.hasInstance](value: unknown): boolean;
16
24
  constructor(message?: string);
17
25
  }
18
26
  export declare class ServerDumpError extends Error {
27
+ /** Whichever copy of this module threw it; see KIND. */
28
+ static [Symbol.hasInstance](value: unknown): boolean;
19
29
  constructor();
20
30
  }
21
31
  export declare class ServerSessionExpiredError extends Error {
32
+ /** Whichever copy of this module threw it; see KIND. */
33
+ static [Symbol.hasInstance](value: unknown): boolean;
22
34
  constructor(message?: string);
23
35
  }
24
36
  /**
package/dist/js/errors.js CHANGED
@@ -1,8 +1,30 @@
1
+ /**
2
+ * Which of these an error is, readable by every copy of this module.
3
+ *
4
+ * The app's code and the server's are bundled apart, so an app can hold one
5
+ * copy of these classes while the rpc() client throws from another - and
6
+ * instanceof compares classes, so a server component's
7
+ * `error instanceof ServerAuthenticationError` never matched an rpc() that
8
+ * failed because the visitor was signed out. Each instance is marked under a
9
+ * registry symbol both copies share, and instanceof reads the mark.
10
+ */
11
+ const KIND = Symbol.for("rsc-kit.error-kind");
12
+ function mark(error, kind) {
13
+ Object.defineProperty(error, KIND, { value: kind });
14
+ }
15
+ function isKind(value, kind) {
16
+ return typeof value === "object" && value !== null && value[KIND] === kind;
17
+ }
1
18
  export class ServerValidationError extends Error {
19
+ /** Whichever copy of this module threw it; see KIND. */
20
+ static [Symbol.hasInstance](value) {
21
+ return isKind(value, "ServerValidationError");
22
+ }
2
23
  errors;
3
24
  constructor(message, errors) {
4
25
  super(message);
5
26
  this.name = "ServerValidationError";
27
+ mark(this, "ServerValidationError");
6
28
  this.errors = errors;
7
29
  }
8
30
  }
@@ -30,35 +52,60 @@ export function redirectedTo() {
30
52
  return location;
31
53
  }
32
54
  export class ServerRedirectError extends Error {
55
+ /** Whichever copy of this module threw it; see KIND. */
56
+ static [Symbol.hasInstance](value) {
57
+ return isKind(value, "ServerRedirectError");
58
+ }
33
59
  location;
34
60
  constructor(location) {
35
61
  super(`Server action redirected to ${location}`);
36
62
  this.name = "ServerRedirectError";
63
+ mark(this, "ServerRedirectError");
37
64
  this.location = location;
38
65
  }
39
66
  }
40
67
  export class ServerAuthenticationError extends Error {
68
+ /** Whichever copy of this module threw it; see KIND. */
69
+ static [Symbol.hasInstance](value) {
70
+ return isKind(value, "ServerAuthenticationError");
71
+ }
41
72
  constructor(message = "Unauthenticated.") {
42
73
  super(message);
43
74
  this.name = "ServerAuthenticationError";
75
+ mark(this, "ServerAuthenticationError");
44
76
  }
45
77
  }
46
78
  export class ServerAuthorizationError extends Error {
79
+ /** Whichever copy of this module threw it; see KIND. */
80
+ static [Symbol.hasInstance](value) {
81
+ return isKind(value, "ServerAuthorizationError");
82
+ }
47
83
  constructor(message = "This action is unauthorized.") {
48
84
  super(message);
49
85
  this.name = "ServerAuthorizationError";
86
+ mark(this, "ServerAuthorizationError");
50
87
  }
51
88
  }
52
89
  export class ServerDumpError extends Error {
90
+ /** Whichever copy of this module threw it; see KIND. */
91
+ static [Symbol.hasInstance](value) {
92
+ return isKind(value, "ServerDumpError");
93
+ }
53
94
  constructor() {
54
95
  super("Server returned a dump response.");
55
96
  this.name = "ServerDumpError";
97
+ mark(this, "ServerDumpError");
56
98
  }
57
99
  }
58
100
  export class ServerSessionExpiredError extends Error {
101
+ /** Whichever copy of this module threw it; see KIND. */
102
+ static [Symbol.hasInstance](value) {
103
+ return isKind(value, "ServerSessionExpiredError");
104
+ }
59
105
  constructor(message = "Your session has expired. Please refresh the page.") {
60
106
  super(message);
61
107
  this.name = "ServerSessionExpiredError";
108
+ mark(this, "ServerSessionExpiredError");
62
109
  }
63
110
  }
64
111
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/js/errors.ts"],"names":[],"mappings":"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","sourcesContent":["export class ServerValidationError extends Error {\n public readonly errors: Record<string, string[]>;\n\n constructor(message: string, errors: Record<string, string[]>) {\n super(message);\n this.name = \"ServerValidationError\";\n this.errors = errors;\n }\n}\n\n/** An action answered with a location instead of a result. */\n/**\n * The redirect the last action answered with, for the one caller that asks.\n *\n * An action that redirects resolves - the navigation is already under way\n * and the caller has nothing to do - which leaves a form that wants to know\n * whether to say \"saved\" with no way to tell a redirect from a void answer.\n * callServer notes the destination here; <Form> clears it before its action\n * runs and reads it, always, right after its await - so a form only ever sees\n * a redirect its own action made. A note nobody reads (an action called\n * outside a Form) is cleared by the next form's submit instead of being taken\n * for that form's redirect. Nothing else needs to read it.\n */\nlet lastRedirect: string | null = null;\n\nexport function noteRedirected(location: string): void {\n lastRedirect = location;\n}\n\n/** The redirect the action just performed, if it did - read once. */\nexport function redirectedTo(): string | null {\n const location = lastRedirect;\n\n lastRedirect = null;\n\n return location;\n}\n\nexport class ServerRedirectError extends Error {\n public readonly location: string;\n\n constructor(location: string) {\n super(`Server action redirected to ${location}`);\n this.name = \"ServerRedirectError\";\n this.location = location;\n }\n}\n\nexport class ServerAuthenticationError extends Error {\n constructor(message: string = \"Unauthenticated.\") {\n super(message);\n this.name = \"ServerAuthenticationError\";\n }\n}\n\nexport class ServerAuthorizationError extends Error {\n constructor(message: string = \"This action is unauthorized.\") {\n super(message);\n this.name = \"ServerAuthorizationError\";\n }\n}\n\nexport class ServerDumpError extends Error {\n constructor() {\n super(\"Server returned a dump response.\");\n this.name = \"ServerDumpError\";\n }\n}\n\nexport class ServerSessionExpiredError extends Error {\n constructor(message: string = \"Your session has expired. Please refresh the page.\") {\n super(message);\n this.name = \"ServerSessionExpiredError\";\n }\n}\n\n/**\n * Turn a failed server-action response into the error it describes.\n *\n * A server action that does not succeed answers with JSON or a redirect\n * header rather than a Flight stream. Passing one of those to the Flight\n * decoder does not produce the server's message — it produces an internal\n * parser failure (\"enqueueModel is not a function\") or a truncated read\n * (\"Connection closed.\"), which is what reached onError before this existed.\n *\n * Returns without throwing when the response is a stream to be decoded.\n */\nexport async function throwForFailedAction(response: Response): Promise<void> {\n // Before the status: a redirect the action asked for is a 204 with the\n // destination in this header - an ok answer with no Flight in it - and\n // an expired session's is a 401. Read first, the header decides for both.\n // Read after `ok`, the 204 fell through to the Flight decoder with an\n // empty body, and the form waited forever.\n const location = response.headers.get(\"X-RSC-Redirect\");\n\n if (location !== null && location !== \"\") {\n throw new ServerRedirectError(location);\n }\n\n if (response.ok) return;\n\n if (response.status === 422) {\n const payload = (await response.json().catch(() => null)) as\n | { message?: string; errors?: Record<string, string[]> }\n | null;\n\n throw new ServerValidationError(\n payload?.message ?? \"Validation failed\",\n payload?.errors ?? {},\n );\n }\n\n if (response.status === 413) {\n throw new Error(\n \"Server action refused: the request body is larger than the server accepts. \" +\n \"A file upload is the usual cause; the limit is the host's maxActionBody.\",\n );\n }\n\n throw new Error(`Server action failed with ${response.status}`);\n}\n\n/**\n * Reject a payload response that is not one.\n *\n * The page a PPR route serves is a static shell: real HTML, status 200, with\n * its Suspense fallbacks showing. Everything below them arrives in a second\n * request. If that request fails there is nothing on screen to say so — the\n * skeletons simply stay, for ever — and handing the failure body to the Flight\n * decoder reports the decoder's confusion rather than the status.\n */\nexport function throwForFailedPayload(response: Response): void {\n if (response.ok) return;\n\n // A 404 that is a payload is the not-found page, rendered: a url a\n // pattern's shell answered with a 200 and a page that, run for real,\n // found no row - a subcategory under the wrong category. The page is\n // what the visitor should see; refusing it left the shell's content on\n // screen with nothing hydrated behind it, and every tap dead.\n if (isPayload(response)) return;\n\n throw new Error(`RSC payload request failed with ${response.status}`);\n}\n\n/** Whether a response is a Flight payload, whatever its status. */\nexport function isPayload(response: Response): boolean {\n return (response.headers.get(\"Content-Type\") ?? \"\").includes(\"text/x-component\");\n}\n\n/**\n * Announce a failure that nothing else will.\n *\n * Dispatched as well as logged: an app that wants to replace a stuck skeleton\n * with something honest has no other way to find out.\n */\nexport function reportClientFailure(scope: string, error: unknown): void {\n if (typeof window !== \"undefined\") {\n window.dispatchEvent(new CustomEvent(\"rsc-client-error\", { detail: { scope, error } }));\n }\n\n console.error(`[rsc-kit] ${scope}`, error);\n}\n"]}
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/js/errors.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,MAAM,IAAI,GAAG,MAAM,CAAC,GAAG,CAAC,oBAAoB,CAAC,CAAC;AAE9C,SAAS,IAAI,CAAC,KAAY,EAAE,IAAY;IACtC,MAAM,CAAC,cAAc,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;AACtD,CAAC;AAED,SAAS,MAAM,CAAC,KAAc,EAAE,IAAY;IAC1C,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAK,KAAiC,CAAC,IAAI,CAAC,KAAK,IAAI,CAAC;AAC1G,CAAC;AAED,MAAM,OAAO,qBAAsB,SAAQ,KAAK;IAC9C,wDAAwD;IACxD,MAAM,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,KAAc;QACxC,OAAO,MAAM,CAAC,KAAK,EAAE,uBAAuB,CAAC,CAAC;IAChD,CAAC;IAEe,MAAM,CAA2B;IAEjD,YAAY,OAAe,EAAE,MAAgC;QAC3D,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,uBAAuB,CAAC;QACpC,IAAI,CAAC,IAAI,EAAE,uBAAuB,CAAC,CAAC;QACpC,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACvB,CAAC;CACF;AAED,8DAA8D;AAC9D;;;;;;;;;;;GAWG;AACH,IAAI,YAAY,GAAkB,IAAI,CAAC;AAEvC,MAAM,UAAU,cAAc,CAAC,QAAgB;IAC7C,YAAY,GAAG,QAAQ,CAAC;AAC1B,CAAC;AAED,qEAAqE;AACrE,MAAM,UAAU,YAAY;IAC1B,MAAM,QAAQ,GAAG,YAAY,CAAC;IAE9B,YAAY,GAAG,IAAI,CAAC;IAEpB,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,MAAM,OAAO,mBAAoB,SAAQ,KAAK;IAC5C,wDAAwD;IACxD,MAAM,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,KAAc;QACxC,OAAO,MAAM,CAAC,KAAK,EAAE,qBAAqB,CAAC,CAAC;IAC9C,CAAC;IAEe,QAAQ,CAAS;IAEjC,YAAY,QAAgB;QAC1B,KAAK,CAAC,+BAA+B,QAAQ,EAAE,CAAC,CAAC;QACjD,IAAI,CAAC,IAAI,GAAG,qBAAqB,CAAC;QAClC,IAAI,CAAC,IAAI,EAAE,qBAAqB,CAAC,CAAC;QAClC,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;IAC3B,CAAC;CACF;AAED,MAAM,OAAO,yBAA0B,SAAQ,KAAK;IAClD,wDAAwD;IACxD,MAAM,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,KAAc;QACxC,OAAO,MAAM,CAAC,KAAK,EAAE,2BAA2B,CAAC,CAAC;IACpD,CAAC;IAED,YAAY,OAAO,GAAW,kBAAkB;QAC9C,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,2BAA2B,CAAC;QACxC,IAAI,CAAC,IAAI,EAAE,2BAA2B,CAAC,CAAC;IAC1C,CAAC;CACF;AAED,MAAM,OAAO,wBAAyB,SAAQ,KAAK;IACjD,wDAAwD;IACxD,MAAM,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,KAAc;QACxC,OAAO,MAAM,CAAC,KAAK,EAAE,0BAA0B,CAAC,CAAC;IACnD,CAAC;IAED,YAAY,OAAO,GAAW,8BAA8B;QAC1D,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,0BAA0B,CAAC;QACvC,IAAI,CAAC,IAAI,EAAE,0BAA0B,CAAC,CAAC;IACzC,CAAC;CACF;AAED,MAAM,OAAO,eAAgB,SAAQ,KAAK;IACxC,wDAAwD;IACxD,MAAM,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,KAAc;QACxC,OAAO,MAAM,CAAC,KAAK,EAAE,iBAAiB,CAAC,CAAC;IAC1C,CAAC;IAED;QACE,KAAK,CAAC,kCAAkC,CAAC,CAAC;QAC1C,IAAI,CAAC,IAAI,GAAG,iBAAiB,CAAC;QAC9B,IAAI,CAAC,IAAI,EAAE,iBAAiB,CAAC,CAAC;IAChC,CAAC;CACF;AAED,MAAM,OAAO,yBAA0B,SAAQ,KAAK;IAClD,wDAAwD;IACxD,MAAM,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,KAAc;QACxC,OAAO,MAAM,CAAC,KAAK,EAAE,2BAA2B,CAAC,CAAC;IACpD,CAAC;IAED,YAAY,OAAO,GAAW,oDAAoD;QAChF,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,2BAA2B,CAAC;QACxC,IAAI,CAAC,IAAI,EAAE,2BAA2B,CAAC,CAAC;IAC1C,CAAC;CACF;AAED;;;;;;;;;;GAUG;AACH,MAAM,CAAC,KAAK,UAAU,oBAAoB,CAAC,QAAkB;IAC3D,uEAAuE;IACvE,uEAAuE;IACvE,0EAA0E;IAC1E,sEAAsE;IACtE,2CAA2C;IAC3C,MAAM,QAAQ,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC;IAExD,IAAI,QAAQ,KAAK,IAAI,IAAI,QAAQ,KAAK,EAAE,EAAE,CAAC;QACzC,MAAM,IAAI,mBAAmB,CAAC,QAAQ,CAAC,CAAC;IAC1C,CAAC;IAED,IAAI,QAAQ,CAAC,EAAE;QAAE,OAAO;IAExB,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;QAC5B,MAAM,OAAO,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAEhD,CAAC;QAET,MAAM,IAAI,qBAAqB,CAC7B,OAAO,EAAE,OAAO,IAAI,mBAAmB,EACvC,OAAO,EAAE,MAAM,IAAI,EAAE,CACtB,CAAC;IACJ,CAAC;IAED,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;QAC5B,MAAM,IAAI,KAAK,CACb,6EAA6E;YAC3E,0EAA0E,CAC7E,CAAC;IACJ,CAAC;IAED,MAAM,IAAI,KAAK,CAAC,6BAA6B,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;AAClE,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,qBAAqB,CAAC,QAAkB;IACtD,IAAI,QAAQ,CAAC,EAAE;QAAE,OAAO;IAExB,mEAAmE;IACnE,qEAAqE;IACrE,qEAAqE;IACrE,uEAAuE;IACvE,8DAA8D;IAC9D,IAAI,SAAS,CAAC,QAAQ,CAAC;QAAE,OAAO;IAEhC,MAAM,IAAI,KAAK,CAAC,mCAAmC,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;AACxE,CAAC;AAED,mEAAmE;AACnE,MAAM,UAAU,SAAS,CAAC,QAAkB;IAC1C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,IAAI,EAAE,CAAC,CAAC,QAAQ,CAAC,kBAAkB,CAAC,CAAC;AACnF,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,mBAAmB,CAAC,KAAa,EAAE,KAAc;IAC/D,IAAI,OAAO,MAAM,KAAK,WAAW,EAAE,CAAC;QAClC,MAAM,CAAC,aAAa,CAAC,IAAI,WAAW,CAAC,kBAAkB,EAAE,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC,CAAC;IAC1F,CAAC;IAED,OAAO,CAAC,KAAK,CAAC,aAAa,KAAK,EAAE,EAAE,KAAK,CAAC,CAAC;AAC7C,CAAC","sourcesContent":["/**\n * Which of these an error is, readable by every copy of this module.\n *\n * The app's code and the server's are bundled apart, so an app can hold one\n * copy of these classes while the rpc() client throws from another - and\n * instanceof compares classes, so a server component's\n * `error instanceof ServerAuthenticationError` never matched an rpc() that\n * failed because the visitor was signed out. Each instance is marked under a\n * registry symbol both copies share, and instanceof reads the mark.\n */\nconst KIND = Symbol.for(\"rsc-kit.error-kind\");\n\nfunction mark(error: Error, kind: string): void {\n Object.defineProperty(error, KIND, { value: kind });\n}\n\nfunction isKind(value: unknown, kind: string): boolean {\n return typeof value === \"object\" && value !== null && (value as Record<symbol, unknown>)[KIND] === kind;\n}\n\nexport class ServerValidationError extends Error {\n /** Whichever copy of this module threw it; see KIND. */\n static [Symbol.hasInstance](value: unknown): boolean {\n return isKind(value, \"ServerValidationError\");\n }\n\n public readonly errors: Record<string, string[]>;\n\n constructor(message: string, errors: Record<string, string[]>) {\n super(message);\n this.name = \"ServerValidationError\";\n mark(this, \"ServerValidationError\");\n this.errors = errors;\n }\n}\n\n/** An action answered with a location instead of a result. */\n/**\n * The redirect the last action answered with, for the one caller that asks.\n *\n * An action that redirects resolves - the navigation is already under way\n * and the caller has nothing to do - which leaves a form that wants to know\n * whether to say \"saved\" with no way to tell a redirect from a void answer.\n * callServer notes the destination here; <Form> clears it before its action\n * runs and reads it, always, right after its await - so a form only ever sees\n * a redirect its own action made. A note nobody reads (an action called\n * outside a Form) is cleared by the next form's submit instead of being taken\n * for that form's redirect. Nothing else needs to read it.\n */\nlet lastRedirect: string | null = null;\n\nexport function noteRedirected(location: string): void {\n lastRedirect = location;\n}\n\n/** The redirect the action just performed, if it did - read once. */\nexport function redirectedTo(): string | null {\n const location = lastRedirect;\n\n lastRedirect = null;\n\n return location;\n}\n\nexport class ServerRedirectError extends Error {\n /** Whichever copy of this module threw it; see KIND. */\n static [Symbol.hasInstance](value: unknown): boolean {\n return isKind(value, \"ServerRedirectError\");\n }\n\n public readonly location: string;\n\n constructor(location: string) {\n super(`Server action redirected to ${location}`);\n this.name = \"ServerRedirectError\";\n mark(this, \"ServerRedirectError\");\n this.location = location;\n }\n}\n\nexport class ServerAuthenticationError extends Error {\n /** Whichever copy of this module threw it; see KIND. */\n static [Symbol.hasInstance](value: unknown): boolean {\n return isKind(value, \"ServerAuthenticationError\");\n }\n\n constructor(message: string = \"Unauthenticated.\") {\n super(message);\n this.name = \"ServerAuthenticationError\";\n mark(this, \"ServerAuthenticationError\");\n }\n}\n\nexport class ServerAuthorizationError extends Error {\n /** Whichever copy of this module threw it; see KIND. */\n static [Symbol.hasInstance](value: unknown): boolean {\n return isKind(value, \"ServerAuthorizationError\");\n }\n\n constructor(message: string = \"This action is unauthorized.\") {\n super(message);\n this.name = \"ServerAuthorizationError\";\n mark(this, \"ServerAuthorizationError\");\n }\n}\n\nexport class ServerDumpError extends Error {\n /** Whichever copy of this module threw it; see KIND. */\n static [Symbol.hasInstance](value: unknown): boolean {\n return isKind(value, \"ServerDumpError\");\n }\n\n constructor() {\n super(\"Server returned a dump response.\");\n this.name = \"ServerDumpError\";\n mark(this, \"ServerDumpError\");\n }\n}\n\nexport class ServerSessionExpiredError extends Error {\n /** Whichever copy of this module threw it; see KIND. */\n static [Symbol.hasInstance](value: unknown): boolean {\n return isKind(value, \"ServerSessionExpiredError\");\n }\n\n constructor(message: string = \"Your session has expired. Please refresh the page.\") {\n super(message);\n this.name = \"ServerSessionExpiredError\";\n mark(this, \"ServerSessionExpiredError\");\n }\n}\n\n/**\n * Turn a failed server-action response into the error it describes.\n *\n * A server action that does not succeed answers with JSON or a redirect\n * header rather than a Flight stream. Passing one of those to the Flight\n * decoder does not produce the server's message — it produces an internal\n * parser failure (\"enqueueModel is not a function\") or a truncated read\n * (\"Connection closed.\"), which is what reached onError before this existed.\n *\n * Returns without throwing when the response is a stream to be decoded.\n */\nexport async function throwForFailedAction(response: Response): Promise<void> {\n // Before the status: a redirect the action asked for is a 204 with the\n // destination in this header - an ok answer with no Flight in it - and\n // an expired session's is a 401. Read first, the header decides for both.\n // Read after `ok`, the 204 fell through to the Flight decoder with an\n // empty body, and the form waited forever.\n const location = response.headers.get(\"X-RSC-Redirect\");\n\n if (location !== null && location !== \"\") {\n throw new ServerRedirectError(location);\n }\n\n if (response.ok) return;\n\n if (response.status === 422) {\n const payload = (await response.json().catch(() => null)) as\n | { message?: string; errors?: Record<string, string[]> }\n | null;\n\n throw new ServerValidationError(\n payload?.message ?? \"Validation failed\",\n payload?.errors ?? {},\n );\n }\n\n if (response.status === 413) {\n throw new Error(\n \"Server action refused: the request body is larger than the server accepts. \" +\n \"A file upload is the usual cause; the limit is the host's maxActionBody.\",\n );\n }\n\n throw new Error(`Server action failed with ${response.status}`);\n}\n\n/**\n * Reject a payload response that is not one.\n *\n * The page a PPR route serves is a static shell: real HTML, status 200, with\n * its Suspense fallbacks showing. Everything below them arrives in a second\n * request. If that request fails there is nothing on screen to say so — the\n * skeletons simply stay, for ever — and handing the failure body to the Flight\n * decoder reports the decoder's confusion rather than the status.\n */\nexport function throwForFailedPayload(response: Response): void {\n if (response.ok) return;\n\n // A 404 that is a payload is the not-found page, rendered: a url a\n // pattern's shell answered with a 200 and a page that, run for real,\n // found no row - a subcategory under the wrong category. The page is\n // what the visitor should see; refusing it left the shell's content on\n // screen with nothing hydrated behind it, and every tap dead.\n if (isPayload(response)) return;\n\n throw new Error(`RSC payload request failed with ${response.status}`);\n}\n\n/** Whether a response is a Flight payload, whatever its status. */\nexport function isPayload(response: Response): boolean {\n return (response.headers.get(\"Content-Type\") ?? \"\").includes(\"text/x-component\");\n}\n\n/**\n * Announce a failure that nothing else will.\n *\n * Dispatched as well as logged: an app that wants to replace a stuck skeleton\n * with something honest has no other way to find out.\n */\nexport function reportClientFailure(scope: string, error: unknown): void {\n if (typeof window !== \"undefined\") {\n window.dispatchEvent(new CustomEvent(\"rsc-client-error\", { detail: { scope, error } }));\n }\n\n console.error(`[rsc-kit] ${scope}`, error);\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rsc-kit/core",
3
- "version": "0.24.0",
3
+ "version": "0.24.1",
4
4
  "description": "React Server Components as a Vite plugin. Routing, streaming, server actions, typed urls and build-time prerendering — deploy to Bun, Node, Workers, Vercel or Deno.",
5
5
  "license": "MIT",
6
6
  "type": "module",