pub const SHELL: &str = "// The trait-independent half of a web-rpc Javascript endpoint. This file is embedded verbatim\n// at the top of every module rendered by `web_rpc::js::endpoint!`, ahead of the generated\n// schemas, method tables and class. It has no imports and no top-level side effects.\n//\n// The generated part is data: every type reachable from the traits becomes a schema value\n// (see `Codec`), and every method becomes an entry in a method table. This half interprets\n// them.\n\nconst MASK_64 = 0xffffffffffffffffn;\nconst MASK_128 = 0xffffffffffffffffffffffffffffffffn;\n\n// `MessageHeader`, by declaration order.\nconst REQUEST = 0;\nconst ABORT = 1;\nconst RESPONSE = 2;\nconst STREAM_ITEM = 3;\nconst STREAM_END = 4;\n\n// `WireArg`, by declaration order.\nconst WIRE_JS = 0;\nconst WIRE_BYTES = 1;\nconst WIRE_NONE = 2;\nconst WIRE_SOME = 3;\nconst WIRE_OK = 4;\nconst WIRE_ERR = 5;\n\nconst textEncoder = new TextEncoder();\nconst textDecoder = new TextDecoder(\"utf-8\", { fatal: true });\n\n/** A growable postcard writer. */\nexport class Writer {\n constructor() {\n this.buffer = new Uint8Array(64);\n this.length = 0;\n this.view = new DataView(this.buffer.buffer);\n }\n\n reserve(extra) {\n if (this.length + extra <= this.buffer.length) return;\n let capacity = this.buffer.length * 2;\n while (capacity < this.length + extra) capacity *= 2;\n const grown = new Uint8Array(capacity);\n grown.set(this.buffer.subarray(0, this.length));\n this.buffer = grown;\n this.view = new DataView(this.buffer.buffer);\n }\n\n /** The bytes written so far, in a buffer of exactly that length. */\n take() {\n return this.buffer.slice(0, this.length);\n }\n\n u8(value) {\n this.reserve(1);\n this.buffer[this.length++] = value & 0xff;\n }\n\n i8(value) {\n this.u8(value < 0 ? value + 256 : value);\n }\n\n bool(value) {\n this.u8(value ? 1 : 0);\n }\n\n varint32(value) {\n let rest = value >>> 0;\n while (rest >= 0x80) {\n this.u8((rest & 0x7f) | 0x80);\n rest = rest >>> 7;\n }\n this.u8(rest);\n }\n\n zigzag32(value) {\n this.varint32(((value << 1) ^ (value >> 31)) >>> 0);\n }\n\n varintBig(value, mask) {\n let rest = BigInt(value) & mask;\n while (rest >= 0x80n) {\n this.u8(Number(rest & 0x7fn) | 0x80);\n rest >>= 7n;\n }\n this.u8(Number(rest));\n }\n\n varint64(value) {\n this.varintBig(value, MASK_64);\n }\n\n zigzag64(value) {\n const wide = BigInt(value);\n this.varintBig((wide << 1n) ^ (wide >> 63n), MASK_64);\n }\n\n varint128(value) {\n this.varintBig(value, MASK_128);\n }\n\n zigzag128(value) {\n const wide = BigInt(value);\n this.varintBig((wide << 1n) ^ (wide >> 127n), MASK_128);\n }\n\n f32(value) {\n this.reserve(4);\n this.view.setFloat32(this.length, value, true);\n this.length += 4;\n }\n\n f64(value) {\n this.reserve(8);\n this.view.setFloat64(this.length, value, true);\n this.length += 8;\n }\n\n /** A length-prefixed run of bytes, from a `Uint8Array`, any other view, or an `ArrayBuffer`. */\n bytes(value) {\n const view = ArrayBuffer.isView(value)\n ? new Uint8Array(value.buffer, value.byteOffset, value.byteLength)\n : new Uint8Array(value);\n this.varint32(view.length);\n this.reserve(view.length);\n this.buffer.set(view, this.length);\n this.length += view.length;\n }\n\n string(value) {\n this.bytes(textEncoder.encode(value));\n }\n}\n\n/** A postcard reader over a byte view. */\nexport class Reader {\n constructor(view) {\n this.buffer = view;\n this.position = 0;\n this.view = new DataView(view.buffer, view.byteOffset, view.byteLength);\n }\n\n u8() {\n if (this.position >= this.buffer.length) {\n throw new RangeError(\"web-rpc: message ended mid-value\");\n }\n return this.buffer[this.position++];\n }\n\n i8() {\n const byte = this.u8();\n return byte > 127 ? byte - 256 : byte;\n }\n\n bool() {\n return this.u8() !== 0;\n }\n\n varint32() {\n let value = 0;\n let shift = 0;\n for (;;) {\n const byte = this.u8();\n value += (byte & 0x7f) * 2 ** shift;\n if ((byte & 0x80) === 0) break;\n shift += 7;\n }\n return value >>> 0;\n }\n\n zigzag32() {\n const value = this.varint32();\n return (value >>> 1) ^ -(value & 1);\n }\n\n varintBig() {\n let value = 0n;\n let shift = 0n;\n for (;;) {\n const byte = this.u8();\n value |= BigInt(byte & 0x7f) << shift;\n if ((byte & 0x80) === 0) break;\n shift += 7n;\n }\n return value;\n }\n\n varint64() {\n return this.varintBig() & MASK_64;\n }\n\n zigzag64() {\n const value = this.varintBig() & MASK_64;\n return BigInt.asIntN(64, (value >> 1n) ^ -(value & 1n));\n }\n\n varint128() {\n return this.varintBig() & MASK_128;\n }\n\n zigzag128() {\n const value = this.varintBig() & MASK_128;\n return BigInt.asIntN(128, (value >> 1n) ^ -(value & 1n));\n }\n\n f32() {\n const value = this.view.getFloat32(this.position, true);\n this.position += 4;\n return value;\n }\n\n f64() {\n const value = this.view.getFloat64(this.position, true);\n this.position += 8;\n return value;\n }\n\n bytes() {\n const length = this.varint32();\n if (this.position + length > this.buffer.length) {\n throw new RangeError(\"web-rpc: message ended mid-value\");\n }\n const slice = this.buffer.subarray(this.position, this.position + length);\n this.position += length;\n return slice;\n }\n\n string() {\n return textDecoder.decode(this.bytes());\n }\n\n /** A reader over the next length-prefixed run of bytes. */\n sub() {\n return new Reader(this.bytes());\n }\n}\n\n/** The `Writer` and `Reader` method that carries each primitive schema. */\nconst PRIMITIVES = {\n bool: \"bool\",\n u8: \"u8\",\n i8: \"i8\",\n u16: \"varint32\",\n u32: \"varint32\",\n i16: \"zigzag32\",\n i32: \"zigzag32\",\n u64: \"varint64\",\n i64: \"zigzag64\",\n u128: \"varint128\",\n i128: \"zigzag128\",\n f32: \"f32\",\n f64: \"f64\",\n char: \"string\",\n string: \"string\",\n bytes: \"bytes\",\n};\n\nfunction isUnitOnly(variants) {\n return variants.every(([, variant]) => variant === \"unit\");\n}\n\nfunction expectTag(actual, expected, what) {\n if (actual !== expected) {\n throw new TypeError(`web-rpc: expected ${what}, found wire tag ${actual}`);\n }\n}\n\n/**\n * Postcard and `WireArg` codecs driven by schema values.\n *\n * A schema is either a string naming a primitive, or an object with a `kind`:\n *\n * \"bool\" \"u8\" \"i8\" \"u16\" \"i16\" \"u32\" \"i32\" \"u64\" \"i64\" \"u128\" \"i128\"\n * \"f32\" \"f64\" \"char\" \"string\" \"bytes\" \"unit\"\n * { kind: \"option\", inner } `undefined` or `null` is `None`\n * { kind: \"seq\", inner } an array, or a `Uint8Array` when `inner` is \"u8\"\n * { kind: \"tuple\", items } an array of fixed length\n * { kind: \"map\", key, value } a `Map`\n * { kind: \"struct\", fields } `fields` is `[[name, schema], ...]`\n * { kind: \"enum\", variants } `variants` is `[[name, variant], ...]`\n * { kind: \"ref\", name } a schema declared under `name` in the table given to the\n * constructor\n *\n * A variant is \"unit\", `{ kind: \"newtype\", inner }`, or a tuple or struct schema. An enum\n * whose variants are all unit is a string; any other enum is `{ tag: name, value }`, or\n * `{ tag: name, ...fields }` for a struct variant.\n *\n * A wire description says how one argument or return value crosses the channel:\n *\n * { kind: \"js\", transfer } a Javascript value in the message, transferred if asked\n * { kind: \"postcard\", schema } postcard bytes behind a tag and a length\n * { kind: \"inline\", schema } postcard bytes with no tag and no length\n * { kind: \"option\", inner }\n * { kind: \"result\", ok, err } `{ tag: \"Ok\", value }` or `{ tag: \"Err\", value }`\n */\nexport class Codec {\n constructor(schemas) {\n this.schemas = schemas;\n }\n\n encode(schema, writer, value) {\n if (typeof schema === \"string\") {\n if (schema === \"unit\") return;\n const method = PRIMITIVES[schema];\n if (!method) throw new TypeError(`web-rpc: unknown schema ${schema}`);\n writer[method](value);\n return;\n }\n switch (schema.kind) {\n case \"ref\":\n this.encode(this.schemas[schema.name], writer, value);\n return;\n case \"option\":\n if (value === undefined || value === null) {\n writer.u8(0);\n } else {\n writer.u8(1);\n this.encode(schema.inner, writer, value);\n }\n return;\n case \"seq\":\n if (schema.inner === \"u8\") {\n writer.bytes(value);\n return;\n }\n writer.varint32(value.length);\n for (const item of value) this.encode(schema.inner, writer, item);\n return;\n case \"tuple\":\n schema.items.forEach((item, index) => this.encode(item, writer, value[index]));\n return;\n case \"map\":\n writer.varint32(value.size);\n for (const [key, item] of value) {\n this.encode(schema.key, writer, key);\n this.encode(schema.value, writer, item);\n }\n return;\n case \"struct\":\n for (const [name, field] of schema.fields) this.encode(field, writer, value[name]);\n return;\n case \"enum\":\n this.encodeEnum(schema, writer, value);\n return;\n default:\n throw new TypeError(`web-rpc: unknown schema kind ${schema.kind}`);\n }\n }\n\n encodeEnum(schema, writer, value) {\n const tag = isUnitOnly(schema.variants) ? value : value.tag;\n const index = schema.variants.findIndex(([name]) => name === tag);\n if (index < 0) throw new TypeError(`web-rpc: unknown variant ${tag}`);\n writer.varint32(index);\n const variant = schema.variants[index][1];\n if (variant === \"unit\") return;\n switch (variant.kind) {\n case \"newtype\":\n this.encode(variant.inner, writer, value.value);\n return;\n case \"tuple\":\n this.encode(variant, writer, value.value);\n return;\n case \"struct\":\n this.encode(variant, writer, value);\n return;\n default:\n throw new TypeError(`web-rpc: unknown variant kind ${variant.kind}`);\n }\n }\n\n decode(schema, reader) {\n if (typeof schema === \"string\") {\n if (schema === \"unit\") return undefined;\n const method = PRIMITIVES[schema];\n if (!method) throw new TypeError(`web-rpc: unknown schema ${schema}`);\n return reader[method]();\n }\n switch (schema.kind) {\n case \"ref\":\n return this.decode(this.schemas[schema.name], reader);\n case \"option\":\n return reader.u8() === 0 ? undefined : this.decode(schema.inner, reader);\n case \"seq\": {\n if (schema.inner === \"u8\") return reader.bytes();\n const length = reader.varint32();\n const items = [];\n for (let index = 0; index < length; index += 1) {\n items.push(this.decode(schema.inner, reader));\n }\n return items;\n }\n case \"tuple\":\n return schema.items.map((item) => this.decode(item, reader));\n case \"map\": {\n const length = reader.varint32();\n const map = new Map();\n for (let index = 0; index < length; index += 1) {\n const key = this.decode(schema.key, reader);\n map.set(key, this.decode(schema.value, reader));\n }\n return map;\n }\n case \"struct\": {\n const object = {};\n for (const [name, field] of schema.fields) object[name] = this.decode(field, reader);\n return object;\n }\n case \"enum\":\n return this.decodeEnum(schema, reader);\n default:\n throw new TypeError(`web-rpc: unknown schema kind ${schema.kind}`);\n }\n }\n\n decodeEnum(schema, reader) {\n const index = reader.varint32();\n const entry = schema.variants[index];\n if (!entry) throw new RangeError(`web-rpc: unknown variant index ${index}`);\n const [tag, variant] = entry;\n if (variant === \"unit\") return isUnitOnly(schema.variants) ? tag : { tag };\n switch (variant.kind) {\n case \"newtype\":\n return { tag, value: this.decode(variant.inner, reader) };\n case \"tuple\":\n return { tag, value: this.decode(variant, reader) };\n case \"struct\":\n return { tag, ...this.decode(variant, reader) };\n default:\n throw new TypeError(`web-rpc: unknown variant kind ${variant.kind}`);\n }\n }\n\n encodeWire(description, writer, value, jsValues, transferList) {\n switch (description.kind) {\n case \"js\":\n writer.varint32(WIRE_JS);\n jsValues.push(value);\n if (description.transfer) transferList.push(value);\n return;\n case \"postcard\": {\n writer.varint32(WIRE_BYTES);\n const inner = new Writer();\n this.encode(description.schema, inner, value);\n writer.bytes(inner.take());\n return;\n }\n case \"inline\":\n this.encode(description.schema, writer, value);\n return;\n case \"option\":\n if (value === undefined || value === null) {\n writer.varint32(WIRE_NONE);\n } else {\n writer.varint32(WIRE_SOME);\n this.encodeWire(description.inner, writer, value, jsValues, transferList);\n }\n return;\n case \"result\":\n if (value && value.tag === \"Ok\") {\n writer.varint32(WIRE_OK);\n this.encodeWire(description.ok, writer, value.value, jsValues, transferList);\n } else if (value && value.tag === \"Err\") {\n writer.varint32(WIRE_ERR);\n this.encodeWire(description.err, writer, value.value, jsValues, transferList);\n } else {\n throw new TypeError(\'web-rpc: expected { tag: \"Ok\" } or { tag: \"Err\" }\');\n }\n return;\n default:\n throw new TypeError(`web-rpc: unknown wire kind ${description.kind}`);\n }\n }\n\n decodeWire(description, reader, jsValues) {\n if (description.kind === \"inline\") return this.decode(description.schema, reader);\n const tag = reader.varint32();\n switch (description.kind) {\n case \"js\":\n expectTag(tag, WIRE_JS, \"a Javascript value\");\n return jsValues.shift();\n case \"postcard\":\n expectTag(tag, WIRE_BYTES, \"postcard bytes\");\n return this.decode(description.schema, reader.sub());\n case \"option\":\n if (tag === WIRE_NONE) return undefined;\n expectTag(tag, WIRE_SOME, \"an option\");\n return this.decodeWire(description.inner, reader, jsValues);\n case \"result\":\n if (tag === WIRE_OK) {\n return { tag: \"Ok\", value: this.decodeWire(description.ok, reader, jsValues) };\n }\n expectTag(tag, WIRE_ERR, \"a result\");\n return { tag: \"Err\", value: this.decodeWire(description.err, reader, jsValues) };\n default:\n throw new TypeError(`web-rpc: unknown wire kind ${description.kind}`);\n }\n }\n}\n\n/** True when a method\'s promise resolves the `Ok` payload and rejects with the `Err`. */\nfunction isFallible(method) {\n return method.kind === \"value\" && method.returns.kind === \"result\";\n}\n\n/**\n * A `Worker`, `MessagePort` or `DedicatedWorkerGlobalScope`, wrapped so that the endpoint has\n * one way to post and one way to listen.\n *\n * The transport is used, never owned: nothing here creates it, terminates it, or calls\n * `start()` on a `MessagePort`. An unstarted port delivers nothing to these listeners.\n */\nclass Transport {\n constructor(target) {\n if (\n !target ||\n typeof target.postMessage !== \"function\" ||\n typeof target.addEventListener !== \"function\"\n ) {\n throw new TypeError(\"web-rpc: endpoint must be a Worker, MessagePort or worker scope\");\n }\n this.target = target;\n this.listeners = [];\n }\n\n post(message, transferList) {\n this.target.postMessage(message, transferList);\n }\n\n on(type, handler) {\n this.target.addEventListener(type, handler);\n this.listeners.push([type, handler]);\n }\n\n detach() {\n for (const [type, handler] of this.listeners) {\n this.target.removeEventListener(type, handler);\n }\n this.listeners = [];\n }\n}\n\nfunction abortError(message) {\n const error = new Error(message);\n error.name = \"AbortError\";\n return error;\n}\n\n/** An `Error` becomes its message; anything else is encoded as thrown. */\nfunction reduceThrown(thrown) {\n return thrown instanceof Error ? thrown.message : thrown;\n}\n\n/**\n * The base class of every generated endpoint.\n *\n * `methods` describes the trait this endpoint calls and `handlers` the trait it implements.\n * Each entry is `{ name, kind, args, returns }`, where `kind` is \"value\", \"notify\" or\n * \"stream\", `args` is a list of wire descriptions, and `returns` is the wire description of\n * the response or stream item, or null for a notification. An entry\'s position is the\n * method\'s index on the wire.\n */\nclass Endpoint {\n constructor(options, className, codec, methods, handlers) {\n const { endpoint, handlers: implementation } = options ?? {};\n if (!endpoint) {\n throw new TypeError(`${className}: options.endpoint is required`);\n }\n if (handlers.length > 0) {\n if (!implementation || typeof implementation !== \"object\") {\n throw new TypeError(`${className}: options.handlers is required`);\n }\n const missing = handlers\n .filter((handler) => typeof implementation[handler.name] !== \"function\")\n .map((handler) => handler.name);\n if (missing.length > 0) {\n throw new TypeError(`${className}: missing handlers: ${missing.join(\", \")}`);\n }\n }\n\n this._className = className;\n this._codec = codec;\n this._methods = methods;\n this._handlers = handlers;\n this._implementation = implementation;\n this._transport = new Transport(endpoint);\n this._sequence = 0;\n this._pendingRequests = new Map();\n this._openStreams = new Map();\n this._runningIterators = new Map();\n this._inflightRequests = new Set();\n this._ready = false;\n this._failure = null;\n this._closed = false;\n this._queuedSends = [];\n this._inbox = [];\n\n this._transport.on(\"message\", (event) => this._onMessage(event.data));\n this._transport.on(\"messageerror\", () =>\n this._fail(new Error(`${className}: a message could not be deserialized`)),\n );\n this._transport.on(\"error\", (event) =>\n this._fail(\n new Error(`${className}: the transport failed to start: ${event.message ?? event.type}`),\n ),\n );\n\n this._poll = setInterval(() => {\n if (!this._ready && !this._closed && !this._failure) this._transport.post(null, []);\n }, 10);\n this._transport.post(null, []);\n }\n\n // -- handshake and transport -------------------------------------------------\n\n _onMessage(data) {\n if (this._closed) return;\n if (!Array.isArray(data)) {\n // Handshake: the peer is listening. Answer once so it sees us too.\n if (!this._ready) {\n this._ready = true;\n clearInterval(this._poll);\n this._transport.post(null, []);\n const queued = this._queuedSends;\n this._queuedSends = [];\n for (const send of queued) send();\n const inbox = this._inbox;\n this._inbox = [];\n for (const message of inbox) this._dispatch(message);\n }\n return;\n }\n if (!this._ready) {\n this._inbox.push(data);\n return;\n }\n this._dispatch(data);\n }\n\n _fail(error) {\n if (this._failure || this._closed) return;\n this._failure = error;\n clearInterval(this._poll);\n for (const pending of this._pendingRequests.values()) pending.reject(error);\n this._pendingRequests.clear();\n for (const stream of this._openStreams.values()) stream.rejectDone(error);\n this._openStreams.clear();\n this._queuedSends = [];\n }\n\n /** Post `[header, payload?, ...jsValues]`, or queue it until the handshake completes. */\n _send(kind, sequence, payload, jsValues, transferList) {\n if (this._closed) return;\n const send = () => {\n const header = new Writer();\n header.varint32(kind);\n header.varint32(sequence);\n const headerBytes = header.take();\n const message = [headerBytes.buffer];\n const transfer = [headerBytes.buffer];\n if (payload) {\n const payloadBytes = payload.take();\n message.push(payloadBytes.buffer);\n transfer.push(payloadBytes.buffer);\n }\n this._transport.post(message.concat(jsValues), transfer.concat(transferList));\n };\n if (this._ready) send();\n else this._queuedSends.push(send);\n }\n\n _encodeCall(index, args) {\n const method = this._methods[index];\n const payload = new Writer();\n const jsValues = [];\n const transferList = [];\n payload.varint32(index);\n method.args.forEach((description, position) => {\n this._codec.encodeWire(description, payload, args[position], jsValues, transferList);\n });\n return { payload, jsValues, transferList };\n }\n\n _decodeReturn(index, method, payload, jsValues) {\n const actual = payload.varint32();\n if (actual !== index) {\n throw new TypeError(`${this._className}: response is for another method`);\n }\n return this._codec.decodeWire(method.returns, payload, jsValues);\n }\n\n // -- calling the other side --------------------------------------------------\n\n _request(index, args) {\n const method = this._methods[index];\n const sequence = this._sequence++;\n let settle;\n const promise = new Promise((resolve, reject) => {\n settle = { resolve, reject };\n });\n if (this._closed) {\n settle.reject(abortError(`${this._className}: endpoint closed`));\n } else if (this._failure) {\n settle.reject(this._failure);\n } else {\n const { payload, jsValues, transferList } = this._encodeCall(index, args);\n this._pendingRequests.set(sequence, { ...settle, index, method });\n this._send(REQUEST, sequence, payload, jsValues, transferList);\n }\n promise.abort = () => {\n if (!this._pendingRequests.has(sequence)) return;\n this._pendingRequests.delete(sequence);\n this._send(ABORT, sequence, null, [], []);\n settle.reject(abortError(`${this._className}: request aborted`));\n };\n return promise;\n }\n\n _notify(index, args) {\n if (this._closed || this._failure) return;\n const { payload, jsValues, transferList } = this._encodeCall(index, args);\n this._send(REQUEST, this._sequence++, payload, jsValues, transferList);\n }\n\n _stream(index, args, callback) {\n if (typeof callback !== \"function\") {\n throw new TypeError(`${this._className}: a streaming method needs a callback`);\n }\n const method = this._methods[index];\n const sequence = this._sequence++;\n let resolveDone;\n let rejectDone;\n const done = new Promise((resolve, reject) => {\n resolveDone = resolve;\n rejectDone = reject;\n });\n if (this._closed || this._failure) {\n rejectDone(this._failure ?? abortError(`${this._className}: endpoint closed`));\n return { close() {}, done };\n }\n const state = {\n index,\n method,\n callback,\n queue: Promise.resolve(),\n resolveDone,\n rejectDone,\n closed: false,\n };\n this._openStreams.set(sequence, state);\n const { payload, jsValues, transferList } = this._encodeCall(index, args);\n this._send(REQUEST, sequence, payload, jsValues, transferList);\n return {\n close: () => {\n if (state.closed) return;\n state.closed = true;\n this._send(ABORT, sequence, null, [], []);\n },\n done,\n };\n }\n\n /** Detach listeners, reject pending requests and close open streams. */\n close() {\n if (this._closed) return;\n this._closed = true;\n clearInterval(this._poll);\n this._transport.detach();\n const error = abortError(`${this._className}: endpoint closed`);\n for (const pending of this._pendingRequests.values()) pending.reject(error);\n this._pendingRequests.clear();\n for (const stream of this._openStreams.values()) {\n stream.queue.then(stream.resolveDone, stream.resolveDone);\n }\n this._openStreams.clear();\n for (const iterator of this._runningIterators.values()) {\n if (typeof iterator.return === \"function\") iterator.return();\n }\n this._runningIterators.clear();\n this._inflightRequests.clear();\n this._queuedSends = [];\n }\n\n // -- inbound -----------------------------------------------------------------\n\n _dispatch(message) {\n const slots = message.slice();\n const header = new Reader(new Uint8Array(slots.shift()));\n const kind = header.varint32();\n const sequence = header.varint32();\n switch (kind) {\n case RESPONSE: {\n const payload = new Reader(new Uint8Array(slots.shift()));\n const pending = this._pendingRequests.get(sequence);\n if (!pending) return;\n this._pendingRequests.delete(sequence);\n try {\n const value = this._decodeReturn(pending.index, pending.method, payload, slots);\n if (!isFallible(pending.method)) pending.resolve(value);\n else if (value.tag === \"Ok\") pending.resolve(value.value);\n else pending.reject(value.value);\n } catch (error) {\n pending.reject(error);\n }\n return;\n }\n case STREAM_ITEM: {\n const payload = new Reader(new Uint8Array(slots.shift()));\n const state = this._openStreams.get(sequence);\n if (!state) return;\n let item;\n try {\n item = this._decodeReturn(state.index, state.method, payload, slots);\n } catch (error) {\n this._openStreams.delete(sequence);\n state.rejectDone(error);\n return;\n }\n state.queue = state.queue.then(() => state.callback(item));\n return;\n }\n case STREAM_END: {\n const state = this._openStreams.get(sequence);\n if (!state) return;\n this._openStreams.delete(sequence);\n state.queue.then(state.resolveDone, state.rejectDone);\n return;\n }\n case REQUEST: {\n const payload = new Reader(new Uint8Array(slots.shift()));\n this._onRequest(sequence, payload, slots);\n return;\n }\n case ABORT: {\n this._inflightRequests.delete(sequence);\n const iterator = this._runningIterators.get(sequence);\n if (iterator) {\n this._runningIterators.delete(sequence);\n if (typeof iterator.return === \"function\") iterator.return();\n }\n return;\n }\n default:\n console.error(`${this._className}: unknown message kind ${kind}`);\n }\n }\n\n _onRequest(sequence, payload, slots) {\n let index;\n let handler;\n let args;\n try {\n index = payload.varint32();\n handler = this._handlers[index];\n if (!handler) throw new RangeError(`unknown method index ${index}`);\n args = handler.args.map((description) =>\n this._codec.decodeWire(description, payload, slots),\n );\n } catch (error) {\n console.error(`${this._className}: could not decode an inbound request:`, error);\n return;\n }\n const implementation = this._implementation[handler.name];\n if (handler.kind === \"notify\") {\n try {\n implementation.apply(this._implementation, args);\n } catch (error) {\n console.error(`${this._className}: ${handler.name} threw:`, error);\n }\n return;\n }\n if (handler.kind === \"stream\") {\n this._runStream(sequence, index, handler, implementation, args);\n return;\n }\n this._inflightRequests.add(sequence);\n Promise.resolve()\n .then(() => implementation.apply(this._implementation, args))\n .then(\n (value) => {\n if (!this._inflightRequests.delete(sequence)) return;\n // A handler returns the `Ok` payload.\n const returned = isFallible(handler) ? { tag: \"Ok\", value } : value;\n this._respond(sequence, index, handler, returned);\n },\n (error) => {\n if (!this._inflightRequests.delete(sequence)) return;\n if (isFallible(handler)) {\n this._respond(sequence, index, handler, { tag: \"Err\", value: reduceThrown(error) });\n } else {\n console.error(`${this._className}: ${handler.name} threw:`, error);\n }\n },\n );\n }\n\n _encodeReturn(index, handler, value) {\n const payload = new Writer();\n const jsValues = [];\n const transferList = [];\n payload.varint32(index);\n this._codec.encodeWire(handler.returns, payload, value, jsValues, transferList);\n return { payload, jsValues, transferList };\n }\n\n _respond(sequence, index, handler, value) {\n let encoded;\n try {\n encoded = this._encodeReturn(index, handler, value);\n } catch (error) {\n console.error(`${this._className}: could not encode the result of ${handler.name}:`, error);\n return;\n }\n this._send(RESPONSE, sequence, encoded.payload, encoded.jsValues, encoded.transferList);\n }\n\n /**\n * Drive one inbound streaming call.\n *\n * An `Abort` arrives as a message event, so it is only observed between event loop turns: a\n * producer that never awaits a macrotask runs to completion whatever the caller does.\n */\n _runStream(sequence, index, handler, implementation, args) {\n let iterator;\n try {\n const iterable = implementation.apply(this._implementation, args);\n iterator =\n typeof iterable[Symbol.asyncIterator] === \"function\"\n ? iterable[Symbol.asyncIterator]()\n : iterable[Symbol.iterator]();\n } catch (error) {\n console.error(`${this._className}: ${handler.name} threw:`, error);\n this._send(STREAM_END, sequence, null, [], []);\n return;\n }\n this._runningIterators.set(sequence, iterator);\n (async () => {\n try {\n for (;;) {\n const step = await iterator.next();\n if (step.done) break;\n if (!this._runningIterators.has(sequence)) break;\n const encoded = this._encodeReturn(index, handler, step.value);\n this._send(STREAM_ITEM, sequence, encoded.payload, encoded.jsValues, encoded.transferList);\n }\n } catch (error) {\n console.error(`${this._className}: ${handler.name} threw:`, error);\n } finally {\n this._runningIterators.delete(sequence);\n this._send(STREAM_END, sequence, null, [], []);\n }\n })();\n }\n}\n";Expand description
The trait-independent part of every generated endpoint, emitted ahead of the rendered schemas, method tables and class.