pub const RPC_JS: &str = "// The client half of the boundary the compiler derived.\n//\n// Nothing here decides anything. Which endpoints exist, what they are\n// called and what they take is settled by the tier split (spec \u{a7}17.2);\n// this file only moves the bytes and keeps the `Remote of T` variant\n// honest while they are in flight.\n\nimport { signal, effect } from \'./signal.js\';\nimport { stringify, decode } from \'./wire.js\';\n\nconst LOADING = { tag: \'Loading\', fields: [] };\n\nfunction ready(value) {\n return { tag: \'Ready\', fields: [value] };\n}\n\n/**\n * The closed set of `Failed` codes, mirrored in `zdc-types`\'s\n * `FailureCode` (crates/zdc-types/src/failure.rs) and pinned against it by\n * a test. Three, not four: `Malformed` was specified and dropped, because\n * a code a server selects by choosing what it writes into a body is a bit\n * of channel at a public label.\n *\n * These are the arms of the built-in `choice` called `Code`, so each\n * string below is a variant *tag* rather than a value a program compares\n * text against. The pinning test reads them off that choice, so it fails\n * if this object and the language\'s arms ever name different sets.\n *\n * `code` is public by construction, and this is the construction: every\n * one of these is decided by *this file\'s* control flow. `Unreachable`\n * means no response object came back at all; `Timeout` means the deadline\n * below fired, which is our own `setTimeout` and our own boolean;\n * `Rejected` means a response object came back and the status line or the\n * decoder rejected it. None of them is read out of the response body, and\n * none of them is read out of an error\'s text.\n */\nconst CODES = Object.freeze({\n UNREACHABLE: \'Unreachable\',\n TIMEOUT: \'Timeout\',\n REJECTED: \'Rejected\',\n});\n\n/**\n * A failure the transport classified. Nothing else constructs one.\n *\n * The code travels on the *object*, chosen at the throw site, so nothing\n * downstream has to parse a message to recover it \u{2014} which is the only way\n * a server\'s bytes could have reached the field.\n */\nclass TransportFailure extends Error {\n constructor(code, message) {\n super(message);\n this.name = \'TransportFailure\';\n this.zdCode = code;\n }\n}\n\n/**\n * Which code a rejection carries.\n *\n * A transport this runtime did not write \u{2014} a test\'s, or a host page\'s \u{2014}\n * rejects with whatever it likes. An abort is a `Timeout` because that is\n * what an abort of an RPC is; anything else is `Unreachable`, because no\n * answer was obtained and the runtime has no evidence of one. The message\n * is never consulted.\n */\nfunction codeOf(error) {\n if (error instanceof TransportFailure) return error.zdCode;\n const name = error && error.name;\n if (name === \'AbortError\' || name === \'TimeoutError\') return CODES.TIMEOUT;\n return CODES.UNREACHABLE;\n}\n\n/**\n * The `Failed` payload: two fields at two labels.\n *\n * `message` is host text and carries \u{a7}14G.1.3(d)\'s join \u{2014} as secret as\n * whatever the endpoint read. `code` is the runtime\'s own verdict on the\n * transport and is `public`. The compiler enforces the difference; this\n * file\'s job is to make the second one true.\n *\n * `code` is a value of `Code`, a built-in `choice`, so it travels in the\n * same shape every other variant does \u{2014} `{ tag, fields }`, as `variant()`\n * in `dom.js` builds and as `whenInto` dispatches on. It was a bare\n * string until `Code` became a type, and a bare string is what let\n * `error.code is \"Timout\"` compile.\n */\nfunction failed(error) {\n return {\n tag: \'Failed\',\n fields: [\n {\n message: String(error && error.message ? error.message : error),\n code: { tag: codeOf(error), fields: [] },\n },\n ],\n };\n}\n\n/**\n * A `server` or `durable` signal read from the browser.\n *\n * Returns a getter of `Remote of T`, which is exactly what \u{a7}5.2 says the\n * read yields: the network is in the value because the network is there,\n * and the caller cannot reach the value without eliminating the variant.\n *\n * `inputs` are the getters for the endpoint\'s parameters, in the wire\n * order the manifest records. Reading them inside the effect is what\n * makes the call re-run when \u{2014} and only when \u{2014} one of them changes.\n */\nexport function remote(name, inputs) {\n return remoteCell(name, inputs)[0];\n}\n\n/**\n * The same cell, with the two handles live sync needs.\n *\n * Returns `[read, apply, refetch]`:\n *\n * - `read` is the getter `remote` returns.\n * - `apply(value)` writes a value straight in, for an update the server\n * *pushed*. Without it a second window would have to re-fetch on every\n * announcement, which is the round trip \u{a7}17.2.5 fatal 4\'s `LiveValue`\n * edge exists to avoid.\n * - `refetch()` re-runs the call, for a `resync` \u{2014} the case where the\n * server cannot prove it has the whole tail a client missed and the\n * only honest answer is to ask again.\n *\n * Both bump the generation counter, so a push that lands while a request\n * is in flight is not overwritten by that request\'s late answer.\n */\nexport function remoteCell(name, inputs) {\n const [read, write] = signal(LOADING);\n // Generation-guarded: typing `ab` and having the first response land\n // last must not overwrite the newer result.\n let generation = 0;\n let latest = () => {};\n\n effect(() => {\n const args = inputs.map((input) => input());\n latest = () => start(args);\n start(args);\n });\n\n function start(args) {\n const mine = ++generation;\n write(LOADING);\n invoke(name, args).then(\n (value) => {\n if (mine === generation) write(ready(value));\n },\n (error) => {\n if (mine === generation) write(failed(error));\n },\n );\n }\n\n function apply(value) {\n // Claims the generation, so an older request landing later is ignored:\n // a pushed value is newer than anything already on the wire.\n generation += 1;\n write(ready(value));\n }\n\n function refetch() {\n latest();\n }\n\n return [read, apply, refetch];\n}\n\n/**\n * A cross-region write: the browser asks the server to perform it.\n *\n * The right-hand side and every index were evaluated in the browser and\n * are shipped as arguments; only the place resolution and the store\n * operator run on the other side (spec \u{a7}17.2.7\'s command rule).\n *\n * Returns a promise, and generated handlers `await` it. That is not a\n * convenience: a discarded promise means the handler cannot order two\n * writes, cannot see either fail, and half-applies in silence.\n *\n * **Generated handlers no longer call this.** One write per request is one\n * store operation per request, and a handler with three of them can\n * half-apply however carefully each one is awaited. `atomic` replaced it.\n * The export stays because it is the one-write shape of the same request\n * and a host page or a test may want it.\n */\nexport function call(name, ...args) {\n return invoke(name, args);\n}\n\n/** The reserved name the batch is posted to. `~` cannot appear in a ZD\n * identifier, so it can never collide with an endpoint. */\nexport const ATOMIC = \'~atomic\';\n\n/**\n * Every durable write one handler asked for, as one transaction.\n *\n * `commands` is `[[endpoint, args], ...]` in source order, which is the\n * list the generated handler accumulated in `$tx`. The server runs all of\n * them and commits them in a single store transaction, so they all land or\n * none does \u{2014} and a failure part way through leaves the store as it was\n * rather than half-written.\n *\n * The list can be built in the browser at all because \u{a7}17.2.7\'s Command\n * rule evaluated every right-hand side and index here, so by the time this\n * is called the whole transaction is decided and nothing in it depends on\n * reading the server\'s state. That is what lets the server use a\n * non-interactive atomic batch, which is the only kind Deno KV and\n * DynamoDB have.\n *\n * An empty list is not a request. A handler whose only write sits inside\n * an `if` that did not fire has nothing to commit, and a round trip to say\n * so would be a request per click on every conditional write in a program.\n */\nexport function atomic(commands) {\n if (!commands || commands.length === 0) return Promise.resolve(null);\n return invoke(ATOMIC, commands);\n}\n\n/**\n * Where a write\'s failure goes.\n *\n * A generated handler wraps its awaited writes in `try`/`catch` and calls\n * this. It exists because the alternative is an unhandled rejection: the\n * DOM layer invokes a listener and discards what it returns, so an async\n * handler that rejects produces \u{2014} at best \u{2014} a console entry nobody reads,\n * and at worst nothing at all.\n *\n * This is deliberately not \"show the user an error\". The language has no\n * global error surface, and inventing one here would be a UI decision made\n * in the runtime. What it guarantees is that the failure is *reachable*:\n * the default reports it through the platform\'s own channel, and an\n * application \u{2014} or a test \u{2014} can replace the sink.\n */\nlet failureSink = defaultFailureSink;\n\n// Named `reportFailure` and not `failed`: `failed` is already the private\n// constructor for the `Failed` variant three lines from the top of this\n// file, and a second declaration of that name silently replaces it \u{2014} so\n// `write(failed(error))` would store `undefined` and the page would sit in\n// `Loading` for ever. That is exactly the bug this whole sink exists to\n// prevent, arriving through the fix for it.\nexport function reportFailure(error) {\n failureSink(error);\n}\n\n/** Replace the failure sink. Used by tests, and by a host page that has\n * somewhere better to put it than the console. */\nexport function setFailureSink(next) {\n failureSink = next || defaultFailureSink;\n}\n\nfunction defaultFailureSink(error) {\n // `reportError` is the platform\'s own \"this went wrong and nobody caught\n // it\" channel \u{2014} it reaches `window.onerror` and error-reporting services\n // the way a genuinely uncaught exception would. `console.error` is the\n // fallback for runtimes that predate it.\n if (typeof reportError === \'function\') {\n reportError(error);\n } else if (typeof console !== \'undefined\' && console.error) {\n console.error(error);\n }\n}\n\n/** Which endpoint URL a name maps to. One place, so the shape is one decision. */\nexport function endpointUrl(name) {\n return `/_zd/${encodeURIComponent(name)}`;\n}\n\nlet transport = defaultTransport;\n\n/** Replace the transport. Used by tests, which record calls rather than make them. */\nexport function setTransport(next) {\n transport = next || defaultTransport;\n}\n\nfunction invoke(name, args) {\n try {\n return Promise.resolve(transport(name, args));\n } catch (error) {\n return Promise.reject(error);\n }\n}\n\n/**\n * How long a call may take before the runtime stops waiting.\n *\n * A deadline is what makes `Timeout` a thing this file decides rather\n * than a thing it reports. Without one, a stalled server is\n * indistinguishable from a slow one for ever, and the arm never fires.\n */\nconst DEADLINE_MS = 30000;\n\n/** A cancellable deadline, or a no-op where the platform has no timers. */\nfunction startDeadline() {\n const has = typeof AbortController === \'function\' && typeof setTimeout === \'function\';\n if (!has) return { signal: undefined, cancel: () => {}, expired: () => false };\n const controller = new AbortController();\n let fired = false;\n const timer = setTimeout(() => {\n fired = true;\n controller.abort();\n }, DEADLINE_MS);\n return {\n signal: controller.signal,\n cancel: () => clearTimeout(timer),\n // Read from our own variable and not from the abort reason, so that\n // nothing on the wire participates in the answer.\n expired: () => fired,\n };\n}\n\nasync function defaultTransport(name, args) {\n const deadline = startDeadline();\n let response;\n try {\n response = await fetch(endpointUrl(name), {\n method: \'POST\',\n headers: { \'content-type\': \'application/json\' },\n // `stringify`, never `JSON.stringify`: a `Map of K to V` is a\n // JavaScript `Map`, and `JSON.stringify` turns one into `{}` without\n // saying so. See `wire.js`.\n body: stringify(args),\n signal: deadline.signal,\n });\n } catch (error) {\n // No response object: nothing was received, so nothing the server\n // could have sent chose this. Which of the two codes it is comes from\n // `deadline.expired()`, this file\'s own boolean.\n throw deadline.expired()\n ? new TransportFailure(CODES.TIMEOUT, `${name} did not answer within ${DEADLINE_MS}ms`)\n : new TransportFailure(CODES.UNREACHABLE, `${name} could not be reached: ${error}`);\n } finally {\n deadline.cancel();\n }\n if (!response.ok) {\n // The body carries why. A `Remote of T` renders that text, so losing\n // it here would turn \"`GREETING_API_KEY` is not set\" into \"500\".\n // It goes into `message`, which is labelled; the *code* comes from\n // the status line, which is not part of the body.\n throw new TransportFailure(CODES.REJECTED, await reason(response, name));\n }\n try {\n return decode(await response.json());\n } catch (error) {\n // A 2xx the decoder could not read. `Rejected` again, deliberately:\n // it is the same code a non-2xx status line produces, so choosing\n // what to write into a 200 body distinguishes nothing that the status\n // line cannot already distinguish on its own. That equality is what\n // keeps the body out of `code`.\n throw new TransportFailure(CODES.REJECTED, `${name} answered with something unreadable: ${error}`);\n }\n}\n\nasync function reason(response, name) {\n try {\n const body = await response.json();\n if (body && typeof body.error === \'string\') return body.error;\n } catch (error) {\n // Not JSON. Fall through to the status, which is all there is.\n }\n return `${name} failed with ${response.status}`;\n}\n";Expand description
The client half of the derived boundary: $remote and $call.
A bundle links against this only when the split found a crossing, so a client-only program still ships nothing it does not use (ยง16.3.1).