svelte-effect-runtime 4.2.0 → 4.2.2
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/chunks/{server-NeyeDSax.js → server-BNxq-pUH.js} +29 -14
- package/.dist/chunks/server-BNxq-pUH.js.map +1 -0
- package/.dist/chunks/{transform-C0jW8Qta.js → transform-CASuYezS.js} +89 -23
- package/.dist/chunks/transform-CASuYezS.js.map +1 -0
- package/.dist/internal/remote-server.js +1 -1
- package/.dist/markup/transform/expressions.d.ts +8 -0
- package/.dist/markup/transform.js +1 -1
- package/.dist/remote/diagnostics.d.ts +17 -1
- package/.dist/remote/server.d.ts +3 -3
- package/.dist/remote/server.js +1 -1
- package/.dist/runtime/transform.js +9 -3
- package/.dist/runtime/transform.js.map +1 -1
- package/.dist/server.js +4 -4
- package/.dist/server.js.map +1 -1
- package/package.json +1 -1
- package/.dist/chunks/server-NeyeDSax.js.map +0 -1
- package/.dist/chunks/transform-C0jW8Qta.js.map +0 -1
|
@@ -36,14 +36,15 @@ const remedies = {
|
|
|
36
36
|
* @param context - Optional request detail for the log header.
|
|
37
37
|
* @param report - Sink for the rendered report; defaults to `console.error`.
|
|
38
38
|
*/
|
|
39
|
-
function report_opaque_remote_failure(reason, cause, value,
|
|
39
|
+
function report_opaque_remote_failure(reason, cause, value, resolve_context, report = default_reporter) {
|
|
40
40
|
/**
|
|
41
|
-
* Reporting runs before SvelteKit's error helper, and the failure
|
|
42
|
-
* describes
|
|
43
|
-
* the
|
|
41
|
+
* Reporting runs before SvelteKit's error helper, and both the failure and
|
|
42
|
+
* the request it describes are arbitrary values SER does not own. Resolve
|
|
43
|
+
* the context in here so a request event that refuses a property cannot
|
|
44
|
+
* replace the 500 the handler owes the client.
|
|
44
45
|
*/
|
|
45
46
|
try {
|
|
46
|
-
report(render_opaque_remote_failure(reason, cause, value,
|
|
47
|
+
report(render_opaque_remote_failure(reason, cause, value, resolve_context?.()));
|
|
47
48
|
} catch {}
|
|
48
49
|
}
|
|
49
50
|
/**
|
|
@@ -274,18 +275,18 @@ const is_tagged_form_error = Schema.is(Schema.Struct({ _tag: Schema.Literal("For
|
|
|
274
275
|
const request_event_context_error_start = "Can only read the current request event inside functions invoked during `handle`";
|
|
275
276
|
const request_store_context_error = "Could not get the request store.";
|
|
276
277
|
/** Maps a remote Effect exit into the control flow expected by SvelteKit. */
|
|
277
|
-
async function run_remote_effect(effect, runtime, invalid, error,
|
|
278
|
+
async function run_remote_effect(effect, runtime, invalid, error, resolve_context) {
|
|
278
279
|
const exit = await runtime.runPromise(Effect.exit(effect));
|
|
279
280
|
if (Exit.isSuccess(exit)) return exit.value;
|
|
280
|
-
throw_remote_cause(exit.cause, invalid, error,
|
|
281
|
+
throw_remote_cause(exit.cause, invalid, error, resolve_context);
|
|
281
282
|
}
|
|
282
283
|
/** Applies a classified remote Cause decision to SvelteKit's server helpers. */
|
|
283
|
-
function throw_remote_cause(cause, invalid, error,
|
|
284
|
+
function throw_remote_cause(cause, invalid, error, resolve_context, report) {
|
|
284
285
|
const resolution = classify_remote_cause(cause);
|
|
285
286
|
switch (resolution._tag) {
|
|
286
287
|
case "SvelteKitControlFlow": throw resolution.value;
|
|
287
288
|
case "InterruptOnly":
|
|
288
|
-
report_opaque_remote_failure("interrupted", resolution.cause, void 0,
|
|
289
|
+
report_opaque_remote_failure("interrupted", resolution.cause, void 0, resolve_context, report);
|
|
289
290
|
throw Cause.squash(resolution.cause);
|
|
290
291
|
case "FormInvalid": invalid(...resolution.issues);
|
|
291
292
|
case "RemoteFailure": {
|
|
@@ -294,7 +295,7 @@ function throw_remote_cause(cause, invalid, error, context, report) {
|
|
|
294
295
|
* The client only receives a generic 500 for a failure SER could not
|
|
295
296
|
* encode, so the original error is reported here or lost entirely.
|
|
296
297
|
*/
|
|
297
|
-
if (resolution.opaque) report_opaque_remote_failure(resolution.opaque.reason, cause, resolution.opaque.value,
|
|
298
|
+
if (resolution.opaque) report_opaque_remote_failure(resolution.opaque.reason, cause, resolution.opaque.value, resolve_context, report);
|
|
298
299
|
error(500, envelope);
|
|
299
300
|
}
|
|
300
301
|
}
|
|
@@ -312,15 +313,29 @@ function throw_remote_cause(cause, invalid, error, context, report) {
|
|
|
312
313
|
* @returns Request detail for opaque failure reports.
|
|
313
314
|
*/
|
|
314
315
|
function to_remote_failure_context(event) {
|
|
315
|
-
const method = event.request?.method;
|
|
316
|
-
const route = event.route?.id ?? void 0;
|
|
317
|
-
const url = event.url?.pathname;
|
|
316
|
+
const method = read_event_detail(() => event.request?.method);
|
|
317
|
+
const route = read_event_detail(() => event.route?.id ?? void 0);
|
|
318
|
+
const url = read_event_detail(() => event.url?.pathname);
|
|
318
319
|
return {
|
|
319
320
|
...method ? { method } : {},
|
|
320
321
|
...route ? { route } : {},
|
|
321
322
|
...url ? { url } : {}
|
|
322
323
|
};
|
|
323
324
|
}
|
|
325
|
+
/**
|
|
326
|
+
* Reads one request detail, tolerating an event that refuses it.
|
|
327
|
+
*
|
|
328
|
+
* SvelteKit restricts which parts of a request a remote function may observe,
|
|
329
|
+
* and the set has changed across releases. A diagnostic must never be the
|
|
330
|
+
* reason a handler cannot answer, so an unavailable detail is simply omitted.
|
|
331
|
+
*/
|
|
332
|
+
function read_event_detail(read) {
|
|
333
|
+
try {
|
|
334
|
+
return read();
|
|
335
|
+
} catch {
|
|
336
|
+
return;
|
|
337
|
+
}
|
|
338
|
+
}
|
|
324
339
|
function throw_form_error(issues, invalid) {
|
|
325
340
|
invalid(...issues);
|
|
326
341
|
}
|
|
@@ -336,4 +351,4 @@ function is_sveltekit_remote_context_error(err) {
|
|
|
336
351
|
//#endregion
|
|
337
352
|
export { to_remote_failure_context as a, throw_remote_cause as i, run_remote_effect as n, encode_remote_failure as o, throw_form_error as r, normalize_remote_helper_error as t };
|
|
338
353
|
|
|
339
|
-
//# sourceMappingURL=server-
|
|
354
|
+
//# sourceMappingURL=server-BNxq-pUH.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server-BNxq-pUH.js","names":[],"sources":["../../../modules/svelte-effect-runtime/src/remote/diagnostics.ts","../../../modules/svelte-effect-runtime/src/remote/cause-codec.ts","../../../modules/svelte-effect-runtime/src/remote/server.ts"],"sourcesContent":["import { Cause } from \"effect\";\n\n/**\n * Why a remote failure reached the client without its original detail.\n *\n * @example\n * ```ts\n * const reason: OpaqueRemoteFailureReason = \"untagged\";\n * ```\n *\n * @since 4.2.0\n */\nexport type OpaqueRemoteFailureReason = \"untagged\" | \"unserializable\" | \"unknown\" | \"interrupted\";\n\n/**\n * Request detail attached to an opaque remote failure report so the log line\n * points at the handler that produced it.\n *\n * @example\n * ```ts\n * const context: RemoteFailureContext = { method: \"POST\", url: \"/checkout\" };\n * ```\n *\n * @since 4.2.0\n */\nexport type RemoteFailureContext = {\n\treadonly method?: string;\n\treadonly route?: string;\n\treadonly url?: string;\n};\n\n/**\n * Defers building a {@link RemoteFailureContext} until a report is actually\n * rendered.\n *\n * The context describes a request SER never otherwise inspects, so resolving\n * it eagerly would read request-event properties on every remote call to\n * describe the few that fail.\n *\n * @example\n * ```ts\n * const resolve: ResolveRemoteFailureContext = () => ({ url: event.url.pathname });\n * ```\n *\n * @since 4.2.1\n */\nexport type ResolveRemoteFailureContext = () => RemoteFailureContext | undefined;\n\ntype Reporter = (message: string) => void;\n\nconst explanations: Readonly<Record<OpaqueRemoteFailureReason, string>> = {\n\tuntagged:\n\t\t\"the failure has no string `_tag`, so it cannot be told apart from an arbitrary object on the wire\",\n\tunserializable:\n\t\t\"the failure could not be serialized, even after being reduced to its own enumerable properties\",\n\tunknown: \"the cause carries no failure reason, so there was nothing to serialize\",\n\tinterrupted: \"the handler's fiber was interrupted before it produced a result\",\n};\n\nconst remedies: Readonly<Record<OpaqueRemoteFailureReason, string>> = {\n\tuntagged:\n\t\t\"Fail with a tagged error (`Data.TaggedError` or `Schema.TaggedError`) so SER can carry it to the client.\",\n\tunserializable:\n\t\t\"Remove non-transportable values (functions, class instances, cycles) from the error, or map it to a tagged error first.\",\n\tunknown:\n\t\t\"Check for a defect thrown outside the Effect error channel; the original value is shown above.\",\n\tinterrupted:\n\t\t\"An interrupt usually means the runtime was disposed mid-request, for example when the dev server restarted while this request was in flight.\",\n};\n\n/**\n * Reports a remote failure that had to be replaced with an opaque envelope.\n *\n * SER cannot send an unrecognized failure to the browser, so the client only\n * ever sees a generic 500. Without this report the original error would be\n * lost entirely, which is the difference between a debuggable failure and a\n * silent one.\n *\n * @example\n * ```ts\n * report_opaque_remote_failure(\"untagged\", cause, value, { url: \"/checkout\" });\n * ```\n *\n * @since 4.2.0\n * @param reason - Why the failure could not be transported.\n * @param cause - Full Effect cause behind the failure.\n * @param value - The original failure value, when one was found.\n * @param context - Optional request detail for the log header.\n * @param report - Sink for the rendered report; defaults to `console.error`.\n */\nexport function report_opaque_remote_failure(\n\treason: OpaqueRemoteFailureReason,\n\tcause: Cause.Cause<unknown>,\n\tvalue: unknown,\n\tresolve_context?: ResolveRemoteFailureContext,\n\treport: Reporter = default_reporter,\n): void {\n\t/**\n\t * Reporting runs before SvelteKit's error helper, and both the failure and\n\t * the request it describes are arbitrary values SER does not own. Resolve\n\t * the context in here so a request event that refuses a property cannot\n\t * replace the 500 the handler owes the client.\n\t */\n\ttry {\n\t\treport(render_opaque_remote_failure(reason, cause, value, resolve_context?.()));\n\t} catch {\n\t\t/** A diagnostic is never worth failing the request over. */\n\t}\n}\n\n/**\n * Renders the report emitted by {@link report_opaque_remote_failure}.\n *\n * @example\n * ```ts\n * const message = render_opaque_remote_failure(\"untagged\", cause, value);\n * ```\n *\n * @since 4.2.0\n * @param reason - Why the failure could not be transported.\n * @param cause - Full Effect cause behind the failure.\n * @param value - The original failure value, when one was found.\n * @param context - Optional request detail for the log header.\n * @returns The multi-line report.\n */\nexport function render_opaque_remote_failure(\n\treason: OpaqueRemoteFailureReason,\n\tcause: Cause.Cause<unknown>,\n\tvalue: unknown,\n\tcontext?: RemoteFailureContext,\n): string {\n\tconst request = render_request(context);\n\tconst lines = [\n\t\t\"[svelte-effect-runtime] A remote handler failed with an error that could not be sent to the client.\",\n\t\t` Reason: ${explanations[reason]}.`,\n\t];\n\n\tif (request) {\n\t\tlines.push(` Request: ${request}`);\n\t}\n\n\tif (reason !== \"interrupted\") {\n\t\tlines.push(` Failure: ${inspect_failure(value)}`);\n\t}\n\n\tlines.push(\" Cause:\", indent(pretty_cause(cause)), ` Fix: ${remedies[reason]}`);\n\n\treturn lines.join(\"\\n\");\n}\n\nfunction render_request(context?: RemoteFailureContext): string | undefined {\n\tif (!context) {\n\t\treturn undefined;\n\t}\n\n\tconst target = context.url ?? context.route;\n\tconst parts = [context.method, target].filter(Boolean);\n\tconst names_route = Boolean(context.route && context.url && context.route !== context.url);\n\tconst route = names_route ? ` (route ${context.route})` : \"\";\n\n\tif (parts.length === 0) {\n\t\treturn undefined;\n\t}\n\n\treturn `${parts.join(\" \")}${route}`;\n}\n\nfunction pretty_cause(cause: Cause.Cause<unknown>): string {\n\ttry {\n\t\treturn Cause.pretty(cause);\n\t} catch {\n\t\treturn String(cause);\n\t}\n}\n\n/**\n * Renders the failure value itself. Errors keep their stack because that is\n * the only part of an untagged failure that identifies its source.\n */\nfunction inspect_failure(value: unknown): string {\n\tif (value === undefined) {\n\t\treturn \"(none)\";\n\t}\n\n\tif (value instanceof globalThis.Error) {\n\t\treturn value.stack ?? `${value.name}: ${value.message}`;\n\t}\n\n\tif (typeof value !== \"object\" || value === null) {\n\t\treturn describe_primitive(value);\n\t}\n\n\ttry {\n\t\treturn JSON.stringify(value, undefined, 2) ?? describe_object(value);\n\t} catch {\n\t\treturn describe_object(value);\n\t}\n}\n\n/** A primitive can still carry a throwing `Symbol.toPrimitive`. */\nfunction describe_primitive(value: unknown): string {\n\ttry {\n\t\treturn String(value);\n\t} catch {\n\t\treturn typeof value;\n\t}\n}\n\n/**\n * Falls back through conversions an object can subvert. A null-prototype or\n * hostile object may throw from `toString` and lack `Object.prototype`, so the\n * last resort must not touch the value at all.\n */\nfunction describe_object(value: object): string {\n\ttry {\n\t\treturn String(value);\n\t} catch {\n\t\t/** Fall through to a conversion the value cannot override. */\n\t}\n\n\ttry {\n\t\treturn Object.prototype.toString.call(value);\n\t} catch {\n\t\treturn \"[unrenderable failure]\";\n\t}\n}\n\nfunction indent(value: string): string {\n\treturn value\n\t\t.split(\"\\n\")\n\t\t.map((line) => ` ${line}`)\n\t\t.join(\"\\n\");\n}\n\nfunction default_reporter(message: string): void {\n\tconsole.error(message);\n}\n","import type { OpaqueRemoteFailureReason } from \"$/remote/diagnostics.ts\";\nimport { isHttpError, isRedirect, isValidationError } from \"@sveltejs/kit\";\nimport { is_form_error, type FormIssue } from \"$/remote/shared.ts\";\nimport { Cause, Schema } from \"effect\";\nimport { stringify } from \"devalue\";\n\n/**\n * Records that a failure lost its detail on the way to the client, so callers\n * can report the original error instead of dropping it silently.\n *\n * @example\n * ```ts\n * const diagnostic: OpaqueRemoteFailure = { reason: \"untagged\", value: err };\n * ```\n *\n * @since 4.2.0\n */\nexport type OpaqueRemoteFailure = {\n\treadonly reason: OpaqueRemoteFailureReason;\n\treadonly value: unknown;\n};\n\ntype EncodedRemoteFailure = {\n\treadonly encoded: string;\n\treadonly opaque?: OpaqueRemoteFailure;\n};\n\nexport type RemoteCauseResolution =\n\t| {\n\t\t\treadonly _tag: \"SvelteKitControlFlow\";\n\t\t\treadonly value: unknown;\n\t }\n\t| {\n\t\t\treadonly _tag: \"InterruptOnly\";\n\t\t\treadonly cause: Cause.Cause<unknown>;\n\t }\n\t| {\n\t\t\treadonly _tag: \"FormInvalid\";\n\t\t\treadonly issues: readonly FormIssue[];\n\t }\n\t| {\n\t\t\treadonly _tag: \"RemoteFailure\";\n\t\t\treadonly encoded: string;\n\t\t\treadonly opaque?: OpaqueRemoteFailure;\n\t };\n\n/** Preserves SvelteKit control flow before classifying transportable Effect failures. */\nexport function classify_remote_cause(cause: Cause.Cause<unknown>): RemoteCauseResolution {\n\tconst control_flow = find_sveltekit_control_flow(cause);\n\n\tif (control_flow !== undefined) {\n\t\treturn {\n\t\t\t_tag: \"SvelteKitControlFlow\",\n\t\t\tvalue: control_flow,\n\t\t};\n\t}\n\n\tif (Cause.hasInterruptsOnly(cause)) {\n\t\treturn {\n\t\t\t_tag: \"InterruptOnly\",\n\t\t\tcause,\n\t\t};\n\t}\n\n\tconst form_error_issues = find_form_error_issues(cause);\n\n\tif (form_error_issues !== undefined) {\n\t\treturn {\n\t\t\t_tag: \"FormInvalid\",\n\t\t\tissues: form_error_issues,\n\t\t};\n\t}\n\n\tconst failure = encode_remote_failure_detailed(cause);\n\n\treturn {\n\t\t_tag: \"RemoteFailure\",\n\t\tencoded: failure.encoded,\n\t\t...(failure.opaque ? { opaque: failure.opaque } : {}),\n\t};\n}\n\n/** Encodes a remote failure into the transport ABI shared with generated clients. */\nexport function encode_remote_failure(cause: Cause.Cause<unknown>): string {\n\treturn encode_remote_failure_detailed(cause).encoded;\n}\n\n/**\n * Encodes a remote failure and reports whether its detail survived encoding.\n *\n * @example\n * ```ts\n * const { encoded, opaque } = encode_remote_failure_detailed(cause);\n * ```\n *\n * @since 4.2.0\n * @param cause - Cause carrying the handler's failure.\n * @returns The encoded payload and, when detail was lost, why.\n */\nexport function encode_remote_failure_detailed(cause: Cause.Cause<unknown>): EncodedRemoteFailure {\n\tfor (const reason of cause.reasons) {\n\t\tif (!Cause.isFailReason(reason)) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst tagged = has_public_remote_failure_tag(reason.error);\n\n\t\tif (!tagged) {\n\t\t\treturn {\n\t\t\t\tencoded: stringify_unknown_remote_failure(),\n\t\t\t\topaque: { reason: \"untagged\", value: reason.error },\n\t\t\t};\n\t\t}\n\n\t\tconst failure = to_serializable_public_failure(reason.error);\n\t\tconst encoded = failure === undefined ? undefined : stringify_failure(failure);\n\n\t\tif (encoded !== undefined) {\n\t\t\treturn { encoded };\n\t\t}\n\n\t\treturn {\n\t\t\tencoded: stringify_unknown_remote_failure(),\n\t\t\topaque: { reason: \"unserializable\", value: reason.error },\n\t\t};\n\t}\n\n\treturn {\n\t\tencoded: stringify_unknown_remote_failure(),\n\t\topaque: { reason: \"unknown\", value: find_defect(cause) },\n\t};\n}\n\n/** Surfaces a defect so an unencodable cause still names something concrete. */\nfunction find_defect(cause: Cause.Cause<unknown>): unknown {\n\tfor (const reason of cause.reasons) {\n\t\tif (Cause.isDieReason(reason)) {\n\t\t\treturn reason.defect;\n\t\t}\n\t}\n\n\treturn undefined;\n}\n\nfunction find_sveltekit_control_flow(cause: Cause.Cause<unknown>): unknown | undefined {\n\tfor (const reason of cause.reasons) {\n\t\tif (!Cause.isDieReason(reason)) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (is_sveltekit_control_flow(reason.defect)) {\n\t\t\treturn reason.defect;\n\t\t}\n\t}\n\n\treturn undefined;\n}\n\nfunction find_form_error_issues(cause: Cause.Cause<unknown>): readonly FormIssue[] | undefined {\n\tfor (const reason of cause.reasons) {\n\t\tif (!Cause.isFailReason(reason)) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst issues = get_form_error_issues(reason.error);\n\n\t\tif (issues !== undefined) {\n\t\t\treturn issues;\n\t\t}\n\t}\n\n\treturn undefined;\n}\n\nfunction get_form_error_issues(value: unknown): readonly FormIssue[] | undefined {\n\tif (is_form_error(value)) {\n\t\treturn value.issues;\n\t}\n\n\treturn is_tagged_form_error(value) ? [] : undefined;\n}\n\nfunction is_sveltekit_control_flow(value: unknown): boolean {\n\treturn isRedirect(value) || isHttpError(value) || isValidationError(value);\n}\n\nfunction stringify_failure(value: unknown): string | undefined {\n\ttry {\n\t\treturn stringify(value);\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n\nfunction to_serializable_public_failure(value: unknown, seen = new WeakSet<object>()): unknown {\n\tif (typeof value === \"function\" || typeof value === \"symbol\") {\n\t\treturn undefined;\n\t}\n\n\tif (!is_object_like(value)) {\n\t\treturn value;\n\t}\n\n\tif (stringify_failure(value) !== undefined) {\n\t\treturn value;\n\t}\n\n\tif (is_internal_object(value)) {\n\t\treturn undefined;\n\t}\n\n\tif (seen.has(value)) {\n\t\treturn undefined;\n\t}\n\n\tseen.add(value);\n\n\tconst serializable = Array.isArray(value)\n\t\t? value.map((item) => to_serializable_public_failure(item, seen))\n\t\t: to_plain_record(value, seen);\n\n\tseen.delete(value);\n\n\treturn serializable;\n}\n\nfunction to_plain_record(value: object, seen: WeakSet<object>): Record<string, unknown> {\n\tconst descriptors = Object.getOwnPropertyDescriptors(value);\n\tconst record: Record<string, unknown> = {};\n\n\tfor (const [key, descriptor] of Object.entries(descriptors)) {\n\t\tif (key === \"stack\" || !(\"value\" in descriptor)) {\n\t\t\tcontinue;\n\t\t}\n\n\t\trecord[key] = to_serializable_public_failure(descriptor.value, seen);\n\t}\n\n\tif (value instanceof Error && !(\"message\" in record)) {\n\t\trecord.message = value.message;\n\t}\n\n\treturn record;\n}\n\nfunction is_object_like(value: unknown): value is object {\n\treturn typeof value === \"object\" && value !== null;\n}\n\nfunction has_public_remote_failure_tag(value: unknown): boolean {\n\treturn is_object_like(value) && typeof (value as { _tag?: unknown })._tag === \"string\";\n}\n\nfunction is_internal_object(value: object): boolean {\n\treturn (\n\t\t!Array.isArray(value) && !is_plain_record(value) && !has_public_remote_failure_tag(value)\n\t);\n}\n\nfunction is_plain_record(value: object): boolean {\n\tconst prototype = Object.getPrototypeOf(value);\n\n\treturn prototype === Object.prototype || prototype === null;\n}\n\nfunction create_unknown_remote_failure(): { readonly message: string } {\n\treturn { message: \"[UNKNOWN_REMOTE_FAILURE]: Unknown error\" };\n}\n\nfunction stringify_unknown_remote_failure(): string {\n\treturn stringify(create_unknown_remote_failure());\n}\n\nconst is_tagged_form_error = Schema.is(\n\tSchema.Struct({\n\t\t_tag: Schema.Literal(\"FormError\"),\n\t}),\n);\n","import { create_serialized_remote_failure_envelope } from \"$/remote/shared.ts\";\nimport { report_opaque_remote_failure } from \"$/remote/diagnostics.ts\";\nimport { RemoteHelperContextError, RemoteHelperError } from \"$/errors.ts\";\nimport type { RemoteFailureContext, ResolveRemoteFailureContext } from \"$/remote/diagnostics.ts\";\nimport { classify_remote_cause } from \"$/remote/cause-codec.ts\";\nimport type { FormIssue } from \"$/remote/shared.ts\";\nimport { Cause, Effect, Exit } from \"effect\";\n\ntype SvelteInvalid = (...issues: readonly (FormIssue | string)[]) => never;\n\ntype SvelteError = (status: number, body: unknown) => never;\n\nconst request_event_context_error_start =\n\t\"Can only read the current request event inside functions invoked during `handle`\";\n\nconst request_store_context_error = \"Could not get the request store.\";\n\nexport { encode_remote_failure } from \"$/remote/cause-codec.ts\";\n\n/** Maps a remote Effect exit into the control flow expected by SvelteKit. */\nexport async function run_remote_effect<A>(\n\teffect: Effect.Effect<A, unknown, unknown>,\n\truntime: {\n\t\trunPromise: (e: Effect.Effect<unknown, unknown, unknown>) => Promise<unknown>;\n\t},\n\tinvalid: SvelteInvalid,\n\terror: SvelteError,\n\tresolve_context?: ResolveRemoteFailureContext,\n): Promise<A> {\n\tconst exit: Exit.Exit<A, unknown> = (await runtime.runPromise(\n\t\tEffect.exit(effect) as Effect.Effect<unknown, unknown, unknown>,\n\t)) as Exit.Exit<A, unknown>;\n\n\tif (Exit.isSuccess(exit)) {\n\t\treturn exit.value;\n\t}\n\n\tthrow_remote_cause(exit.cause, invalid, error, resolve_context);\n}\n\n/** Applies a classified remote Cause decision to SvelteKit's server helpers. */\nexport function throw_remote_cause(\n\tcause: Cause.Cause<unknown>,\n\tinvalid: SvelteInvalid,\n\terror: SvelteError,\n\tresolve_context?: ResolveRemoteFailureContext,\n\treport?: (message: string) => void,\n): never {\n\tconst resolution = classify_remote_cause(cause);\n\n\tswitch (resolution._tag) {\n\t\tcase \"SvelteKitControlFlow\": {\n\t\t\tthrow resolution.value;\n\t\t}\n\t\tcase \"InterruptOnly\": {\n\t\t\treport_opaque_remote_failure(\n\t\t\t\t\"interrupted\",\n\t\t\t\tresolution.cause,\n\t\t\t\tundefined,\n\t\t\t\tresolve_context,\n\t\t\t\treport,\n\t\t\t);\n\n\t\t\tthrow Cause.squash(resolution.cause);\n\t\t}\n\t\tcase \"FormInvalid\": {\n\t\t\tinvalid(...resolution.issues);\n\t\t}\n\t\tcase \"RemoteFailure\": {\n\t\t\tconst envelope = create_serialized_remote_failure_envelope(resolution.encoded);\n\n\t\t\t/**\n\t\t\t * The client only receives a generic 500 for a failure SER could not\n\t\t\t * encode, so the original error is reported here or lost entirely.\n\t\t\t */\n\t\t\tif (resolution.opaque) {\n\t\t\t\treport_opaque_remote_failure(\n\t\t\t\t\tresolution.opaque.reason,\n\t\t\t\t\tcause,\n\t\t\t\t\tresolution.opaque.value,\n\t\t\t\t\tresolve_context,\n\t\t\t\t\treport,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\terror(500, envelope);\n\t\t}\n\t}\n}\n\n/**\n * Describes the request a remote failure occurred in.\n *\n * @example\n * ```ts\n * const context = to_remote_failure_context(event);\n * ```\n *\n * @since 4.2.0\n * @param event - Request event the handler ran under.\n * @returns Request detail for opaque failure reports.\n */\nexport function to_remote_failure_context(event: {\n\treadonly request?: { readonly method?: string };\n\treadonly route?: { readonly id?: string | null };\n\treadonly url?: { readonly pathname?: string };\n}): RemoteFailureContext {\n\tconst method = read_event_detail(() => event.request?.method);\n\tconst route = read_event_detail(() => event.route?.id ?? undefined);\n\tconst url = read_event_detail(() => event.url?.pathname);\n\n\treturn {\n\t\t...(method ? { method } : {}),\n\t\t...(route ? { route } : {}),\n\t\t...(url ? { url } : {}),\n\t};\n}\n\n/**\n * Reads one request detail, tolerating an event that refuses it.\n *\n * SvelteKit restricts which parts of a request a remote function may observe,\n * and the set has changed across releases. A diagnostic must never be the\n * reason a handler cannot answer, so an unavailable detail is simply omitted.\n */\nfunction read_event_detail(read: () => string | undefined): string | undefined {\n\ttry {\n\t\treturn read();\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n\nexport function throw_form_error(issues: readonly FormIssue[], invalid: SvelteInvalid): never {\n\tinvalid(...issues);\n}\n\n/** Rebrands SvelteKit context failures with the remote helper that triggered them. */\nexport function normalize_remote_helper_error(err: unknown, helper_name: string): Error {\n\tif (is_sveltekit_remote_context_error(err)) {\n\t\treturn new RemoteHelperContextError(helper_name);\n\t}\n\n\treturn err instanceof Error ? err : new RemoteHelperError(err);\n}\n\nfunction is_sveltekit_remote_context_error(err: unknown): err is Error {\n\tif (!(err instanceof Error)) {\n\t\treturn false;\n\t}\n\n\treturn (\n\t\terr.message.startsWith(request_event_context_error_start) ||\n\t\terr.message === request_store_context_error\n\t);\n}\n"],"mappings":"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"}
|
|
@@ -648,30 +648,33 @@ function is_record(value) {
|
|
|
648
648
|
}
|
|
649
649
|
//#endregion
|
|
650
650
|
//#region src/markup/transform/expressions.ts
|
|
651
|
+
const callback_prefix = "const __SER___callback = ";
|
|
652
|
+
/**
|
|
653
|
+
* Splits a callback expression into its parameter list and body.
|
|
654
|
+
*
|
|
655
|
+
* The split is syntactic rather than textual: locating the body by searching
|
|
656
|
+
* for `=>` finds the first arrow anywhere in the string, including one nested
|
|
657
|
+
* inside the callback's own body, which silently truncates the body and hides
|
|
658
|
+
* whatever it contained.
|
|
659
|
+
*/
|
|
651
660
|
function strip_arrow_function(expr) {
|
|
652
|
-
const
|
|
653
|
-
if (
|
|
661
|
+
const callback = parse_callback_expression(expr);
|
|
662
|
+
if (!callback) return {
|
|
654
663
|
params: "()",
|
|
655
664
|
body: expr,
|
|
656
665
|
body_start: 0,
|
|
657
666
|
body_end: expr.length
|
|
658
667
|
};
|
|
659
|
-
const
|
|
660
|
-
const
|
|
661
|
-
const
|
|
662
|
-
|
|
663
|
-
let
|
|
664
|
-
let
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
}
|
|
670
|
-
const body_leading_ws = body.length - body.trimStart().length;
|
|
671
|
-
const body_trailing_ws = body.length - body.trimEnd().length;
|
|
672
|
-
body_start += body_leading_ws;
|
|
673
|
-
body_end -= body_trailing_ws;
|
|
674
|
-
body = body.trim();
|
|
668
|
+
const offset = 25;
|
|
669
|
+
const parameters = callback.parameters;
|
|
670
|
+
const params = `(${expr.slice(parameters.pos - offset, parameters.end - offset).trim()})`;
|
|
671
|
+
const is_block = ts.isBlock(callback.body);
|
|
672
|
+
let body_start = callback.body.getStart() - offset + (is_block ? 1 : 0);
|
|
673
|
+
let body_end = callback.body.end - offset - (is_block ? 1 : 0);
|
|
674
|
+
const raw = expr.slice(body_start, body_end);
|
|
675
|
+
body_start += raw.length - raw.trimStart().length;
|
|
676
|
+
body_end -= raw.length - raw.trimEnd().length;
|
|
677
|
+
let body = raw.trim();
|
|
675
678
|
if (body.endsWith(";")) {
|
|
676
679
|
body = body.slice(0, -1);
|
|
677
680
|
body_end -= 1;
|
|
@@ -683,6 +686,13 @@ function strip_arrow_function(expr) {
|
|
|
683
686
|
body_end
|
|
684
687
|
};
|
|
685
688
|
}
|
|
689
|
+
function parse_callback_expression(expr) {
|
|
690
|
+
const stmt = ts.createSourceFile("callback.ts", callback_prefix + expr, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS).statements[0];
|
|
691
|
+
if (!stmt || !ts.isVariableStatement(stmt)) return;
|
|
692
|
+
const initializer = stmt.declarationList.declarations[0]?.initializer;
|
|
693
|
+
if (initializer === void 0 || !(ts.isArrowFunction(initializer) || ts.isFunctionExpression(initializer))) return;
|
|
694
|
+
return initializer;
|
|
695
|
+
}
|
|
686
696
|
function is_callback_function_expression(expr) {
|
|
687
697
|
const wrapped = `const __SER___callback = ${expr};`;
|
|
688
698
|
const stmt = ts.createSourceFile("callback.ts", wrapped, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS).statements[0];
|
|
@@ -721,11 +731,56 @@ function collect_free_identifiers(expr_text) {
|
|
|
721
731
|
return ids;
|
|
722
732
|
}
|
|
723
733
|
function visit_ids(node, locals, seen, ids) {
|
|
724
|
-
if (ts.
|
|
734
|
+
if (ts.isFunctionLike(node)) {
|
|
725
735
|
const scoped = new Set(locals);
|
|
726
|
-
if (ts.isFunctionDeclaration(node) && node.name) scoped.add(node.name.text);
|
|
736
|
+
if ((ts.isFunctionDeclaration(node) || ts.isFunctionExpression(node)) && node.name !== void 0) scoped.add(node.name.text);
|
|
737
|
+
/**
|
|
738
|
+
* A computed member name is evaluated in the enclosing scope, so it stays
|
|
739
|
+
* a dependency even though the member itself introduces a new scope.
|
|
740
|
+
*/
|
|
741
|
+
if ("name" in node && node.name !== void 0 && ts.isComputedPropertyName(node.name)) visit_ids(node.name.expression, locals, seen, ids);
|
|
727
742
|
for (const parameter of node.parameters) add_binding_names(parameter.name, scoped);
|
|
728
|
-
|
|
743
|
+
/**
|
|
744
|
+
* Defaults are evaluated in parameter scope: they can reference the values
|
|
745
|
+
* this expression depends on, so skipping them drops a dependency and the
|
|
746
|
+
* effect silently stops re-running.
|
|
747
|
+
*/
|
|
748
|
+
for (const parameter of node.parameters) if (parameter.initializer) visit_ids(parameter.initializer, scoped, seen, ids);
|
|
749
|
+
if ("body" in node && node.body) visit_ids(node.body, scoped, seen, ids);
|
|
750
|
+
return;
|
|
751
|
+
}
|
|
752
|
+
/** A block-scoped declaration must not leak into the enclosing scope. */
|
|
753
|
+
if (ts.isBlock(node) || ts.isCaseBlock(node)) {
|
|
754
|
+
const scoped = new Set(locals);
|
|
755
|
+
node.forEachChild((child) => visit_ids(child, scoped, seen, ids));
|
|
756
|
+
return;
|
|
757
|
+
}
|
|
758
|
+
/**
|
|
759
|
+
* The iterable is evaluated before the loop binding exists, so it has to be
|
|
760
|
+
* walked in the enclosing scope. Binding first would silently swallow a
|
|
761
|
+
* dependency that happens to share the loop variable's name.
|
|
762
|
+
*/
|
|
763
|
+
if (ts.isForOfStatement(node) || ts.isForInStatement(node)) {
|
|
764
|
+
const scoped = new Set(locals);
|
|
765
|
+
visit_ids(node.expression, locals, seen, ids);
|
|
766
|
+
visit_ids(node.initializer, scoped, seen, ids);
|
|
767
|
+
visit_ids(node.statement, scoped, seen, ids);
|
|
768
|
+
return;
|
|
769
|
+
}
|
|
770
|
+
if (ts.isForStatement(node)) {
|
|
771
|
+
const scoped = new Set(locals);
|
|
772
|
+
for (const part of [
|
|
773
|
+
node.initializer,
|
|
774
|
+
node.condition,
|
|
775
|
+
node.incrementor
|
|
776
|
+
]) if (part) visit_ids(part, scoped, seen, ids);
|
|
777
|
+
visit_ids(node.statement, scoped, seen, ids);
|
|
778
|
+
return;
|
|
779
|
+
}
|
|
780
|
+
if (ts.isCatchClause(node)) {
|
|
781
|
+
const scoped = new Set(locals);
|
|
782
|
+
if (node.variableDeclaration) visit_ids(node.variableDeclaration, scoped, seen, ids);
|
|
783
|
+
visit_ids(node.block, scoped, seen, ids);
|
|
729
784
|
return;
|
|
730
785
|
}
|
|
731
786
|
if (ts.isVariableDeclaration(node)) {
|
|
@@ -735,6 +790,12 @@ function visit_ids(node, locals, seen, ids) {
|
|
|
735
790
|
}
|
|
736
791
|
if (ts.isTypeReferenceNode(node)) return;
|
|
737
792
|
if (ts.isIdentifier(node)) {
|
|
793
|
+
/**
|
|
794
|
+
* Statement text reaches this collector through an expression-shaped
|
|
795
|
+
* wrapper, so parser error recovery can synthesise a nameless identifier.
|
|
796
|
+
* Emitting it produces a bare `;` in the generated dependency reads.
|
|
797
|
+
*/
|
|
798
|
+
if (node.text === "") return;
|
|
738
799
|
if (node.text === "yield" || node.text === "undefined" || node.text === "null" || node.text === "true" || node.text === "false" || node.text === "this") return;
|
|
739
800
|
if (is_property_access_name(node)) return;
|
|
740
801
|
if (!locals.has(node.text) && !seen.has(node.text)) {
|
|
@@ -779,9 +840,14 @@ function is_yield_star_expression$1(node) {
|
|
|
779
840
|
if (ts.isYieldExpression(node)) return node.asteriskToken !== void 0;
|
|
780
841
|
return ts.isBinaryExpression(node) && node.operatorToken.kind === ts.SyntaxKind.AsteriskToken && ts.isIdentifier(node.left) && node.left.text === "yield";
|
|
781
842
|
}
|
|
843
|
+
/**
|
|
844
|
+
* Declaration names are not references. Emitting one as a dependency makes the
|
|
845
|
+
* generated code read an identifier that was never declared, which fails at
|
|
846
|
+
* runtime rather than merely re-running too often.
|
|
847
|
+
*/
|
|
782
848
|
function is_property_access_name(node) {
|
|
783
849
|
const parent = node.parent;
|
|
784
|
-
return ts.isPropertyAccessExpression(parent) && parent.name === node || ts.isPropertyAssignment(parent) && parent.name === node || ts.isBindingElement(parent) && parent.propertyName === node || ts.isImportSpecifier(parent) || ts.isExportSpecifier(parent);
|
|
850
|
+
return ts.isPropertyAccessExpression(parent) && parent.name === node || ts.isPropertyAssignment(parent) && parent.name === node || ts.isPropertyDeclaration(parent) && parent.name === node || ts.isClassDeclaration(parent) && parent.name === node || ts.isClassExpression(parent) && parent.name === node || ts.isBindingElement(parent) && parent.propertyName === node || ts.isImportSpecifier(parent) || ts.isExportSpecifier(parent);
|
|
785
851
|
}
|
|
786
852
|
//#endregion
|
|
787
853
|
//#region src/markup/transform/effect-callbacks.ts
|
|
@@ -1594,4 +1660,4 @@ function transform_markup_effect(content, filename, options = {}) {
|
|
|
1594
1660
|
//#endregion
|
|
1595
1661
|
export { slice_start as a, find_yield_star_node as c, collect_top_level_binding_names as d, has_local_import_binding as f, slice as i, is_yield_star_expression as l, validate_rune_yield_usage as n, collect_yield_star_nodes as o, make_imports as p, create_source_map as r, contains_top_level_await as s, transform_markup_effect as t, collect_free_identifiers as u };
|
|
1596
1662
|
|
|
1597
|
-
//# sourceMappingURL=transform-
|
|
1663
|
+
//# sourceMappingURL=transform-CASuYezS.js.map
|