@rsc-kit/core 0.24.3 → 0.26.0

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 +1 @@
1
- {"version":3,"file":"conformance.js","sourceRoot":"","sources":["../src/conformance.ts"],"names":[],"mappings":"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","sourcesContent":["#!/usr/bin/env node\n// The contract every backend adapter keeps, as a suite it runs against itself.\n//\n// A backend answers rpc(), actions and guards over one endpoint, and every\n// difference between how it and the engine read that wire is a bug in an\n// app that nobody wrote: a nil slice arriving as null where the type said a\n// list, a timestamp the type called unknown, a refusal that did not come out\n// as the error a page checks for. Each was found by an app, one at a time.\n// This finds them before an adapter ships.\n//\n// The adapter registers the Conformance.* functions described in CASES, in\n// its own language, the way an app would write them; this calls them through\n// the real client and checks what arrives. Where the adapter's manifest types\n// a function, every value it sends is checked against that type too.\n//\n// rsc-kit-conformance --endpoint http://127.0.0.1:8080/__rsc/host-call \\\n// --secret test-secret --manifest rsc-host.json\n//\n// The test host's hostReply passes the same suite (conformance.test.ts), so\n// a page test faking the backend fakes what a real adapter does.\n\nimport { readFileSync } from 'node:fs'\nimport { argv, exit, stderr, stdout } from 'node:process'\nimport { pathToFileURL } from 'node:url'\nimport { httpHostCalls } from './hostCalls.js'\nimport { isNotFoundSignal } from './notFound.js'\nimport { withRedirect } from './redirect.js'\nimport { withRequest } from './request.js'\nimport { ServerAuthenticationError, ServerAuthorizationError } from './js/errors.js'\n\ntype Schema = Record<string, unknown>\n\n/** A host-call client: the real one in a run, the test host's in core's own test. */\nexport type ConformanceCall = (name: string, ...args: unknown[]) => Promise<unknown>\n\nexport interface ConformanceOptions {\n /** The adapter's host-call endpoint, e.g. http://127.0.0.1:8080/__rsc/host-call. */\n endpoint: string\n /** The secret the adapter checks. */\n secret: string\n /** The adapter's rsc-host.json, parsed or as a path: its types are checked against what arrives. */\n manifest?: string | { functions?: string[]; types?: Record<string, { result?: Schema }>; defs?: Record<string, Schema> }\n /** For a test: the fetch the client uses. */\n fetch?: typeof fetch\n}\n\nexport interface ConformanceResult {\n case: string\n ok: boolean\n /** What went wrong, when it did. */\n detail?: string\n}\n\n/**\n * What the adapter registers, and what each must do. Names are fixed; how\n * they are written is the adapter's - the point is that they are written the\n * way an app's would be, with the adapter's ordinary API.\n */\nexport const CASES = {\n 'Conformance.echo': 'Return its one argument unchanged: any JSON value, nested.',\n 'Conformance.emptyList': 'Return an empty list of objects, the way the language makes \"no rows\" (Go: a nil slice).',\n 'Conformance.time': \"Return the instant 2026-01-02T03:04:05Z as the language's own time value.\",\n 'Conformance.noTime': \"Return an absent time: a nil pointer, a null Carbon, typed as a time or nothing.\",\n 'Conformance.unauthenticated': 'Refuse as not signed in, the way the framework does.',\n 'Conformance.unauthorized': 'Refuse as signed in but not allowed.',\n 'Conformance.notFound': \"Refuse as not found (404), the way the framework does: Go's Refuse(404), Laravel's abort(404).\",\n 'Conformance.refuse': 'Refuse with status 429 and the message \"Slow down.\"',\n 'Conformance.invalid': 'Refuse the input: a validation error on the field \"name\".',\n 'Conformance.redirect': 'Send the visitor to /login.',\n 'Conformance.revalidate': 'Mark the region \"orders\" stale, and return \"ok\".',\n 'Conformance.fail': 'Fail unexpectedly: an ordinary error, not a refusal.',\n 'Conformance.authorization': \"Return the request's Authorization header, as the renderer forwarded it.\",\n '__rsc.middleware': 'Guards: \"conformance-allow\" passes; \"conformance-deny\" refuses; a name with no guard refuses.',\n} as const\n\nconst INSTANT = Date.parse('2026-01-02T03:04:05Z')\n\nconst ECHOES: unknown[] = [null, 0, -1.5, 'héllo ✓ \"quoted\"', [1, 'a', null], { a: { b: [true, false] }, c: '' }]\n\n/**\n * Run the suite against a client. Every case runs; none stops another.\n *\n * `revalidated` is where the client records what each call marked stale -\n * its onRevalidate - so the revalidation case can read it.\n */\nexport async function conformance(\n call: ConformanceCall,\n options: { revalidated: string[][]; manifest?: ConformanceOptions['manifest']; wrongSecret?: ConformanceCall },\n): Promise<ConformanceResult[]> {\n const { revalidated, manifest, wrongSecret } = options\n const results: ConformanceResult[] = []\n const types = typeof manifest === 'string' ? JSON.parse(readFileSync(manifest, 'utf-8')) : manifest\n\n const check = async (name: string, run: () => Promise<void>) => {\n try {\n await run()\n results.push({ case: name, ok: true })\n } catch (error) {\n results.push({ case: name, ok: false, detail: error instanceof Error ? error.message : String(error) })\n }\n }\n\n const expect = (ok: boolean, detail: string) => {\n if (!ok) throw new Error(detail)\n }\n\n const rejection = async (run: () => Promise<unknown>): Promise<unknown> => {\n try {\n const value = await run()\n\n throw new Error('answered ' + JSON.stringify(value) + ' instead of refusing')\n } catch (error) {\n return error\n }\n }\n\n /** The value against the type the adapter's manifest declares, when it declares one. */\n const typed = (name: string, value: unknown) => {\n const schema = types?.types?.[name]?.result\n\n if (!schema) return\n\n const problem = conformsTo(value, schema, types?.defs ?? {}, 'result')\n\n expect(problem === null, `the manifest types ${name}'s result, and what arrived does not fit it: ${problem}`)\n }\n\n await check('the manifest lists every Conformance function', async () => {\n if (!types) return\n\n const missing = Object.keys(CASES).filter((n) => !n.startsWith('__') && !types.functions?.includes(n))\n\n expect(missing.length === 0, 'not in functions: ' + missing.join(', '))\n })\n\n await check('a value of any JSON shape comes back unchanged', async () => {\n for (const value of ECHOES) {\n const back = await call('Conformance.echo', value)\n\n expect(JSON.stringify(back) === JSON.stringify(value), `sent ${JSON.stringify(value)}, got ${JSON.stringify(back)}`)\n }\n })\n\n await check('\"no rows\" is an empty list, never null', async () => {\n const value = await call('Conformance.emptyList')\n\n expect(Array.isArray(value) && value.length === 0, 'got ' + JSON.stringify(value))\n typed('Conformance.emptyList', value)\n })\n\n await check('a time is an ISO 8601 string of the same instant', async () => {\n const value = await call('Conformance.time')\n\n expect(typeof value === 'string' && Date.parse(value) === INSTANT, 'got ' + JSON.stringify(value))\n typed('Conformance.time', value)\n })\n\n await check('an absent time is null', async () => {\n const value = await call('Conformance.noTime')\n\n expect(value === null, 'got ' + JSON.stringify(value))\n typed('Conformance.noTime', value)\n })\n\n await check('not signed in is the engine\\'s ServerAuthenticationError', async () => {\n const error = await rejection(() => call('Conformance.unauthenticated'))\n\n expect(error instanceof ServerAuthenticationError, 'got ' + String(error))\n })\n\n await check('not allowed is the engine\\'s ServerAuthorizationError', async () => {\n const error = await rejection(() => call('Conformance.unauthorized'))\n\n expect(error instanceof ServerAuthorizationError, 'got ' + String(error))\n })\n\n await check('not found is the engine\\'s notFound()', async () => {\n const error = await rejection(() => call('Conformance.notFound'))\n\n expect(isNotFoundSignal(error), 'got ' + String(error))\n })\n\n await check('a refusal keeps its status and its message', async () => {\n const error = (await rejection(() => call('Conformance.refuse'))) as Error & { refusalStatus?: number }\n\n expect(error.refusalStatus === 429, 'status ' + String(error.refusalStatus))\n expect(String(error.message).includes('Slow down.'), 'message ' + JSON.stringify(error.message))\n })\n\n await check('refused input names its field', async () => {\n const error = (await rejection(() => call('Conformance.invalid'))) as { errors?: Record<string, string[]> }\n\n expect(Array.isArray(error.errors?.name) && error.errors.name.length > 0, 'errors ' + JSON.stringify(error.errors))\n })\n\n await check('a redirect is the engine\\'s redirect, to where it said', async () => {\n const taken = await withRedirect(async (seen) => {\n await rejection(() => call('Conformance.redirect'))\n\n return seen()\n })\n\n expect(taken?.location === '/login', 'redirect ' + JSON.stringify(taken))\n expect(taken!.status >= 300 && taken!.status < 400, 'status ' + taken?.status)\n })\n\n await check('a revalidation rides with the result', async () => {\n const value = await call('Conformance.revalidate')\n\n expect(value === 'ok', 'got ' + JSON.stringify(value))\n expect(revalidated.some((r) => r.includes('orders')), 'revalidated ' + JSON.stringify(revalidated))\n })\n\n await check('an unexpected failure is an error, not a refusal', async () => {\n const error = (await rejection(() => call('Conformance.fail'))) as Error & { refusalStatus?: number }\n\n expect(\n error instanceof Error && !(error instanceof ServerAuthenticationError) && !(error instanceof ServerAuthorizationError) && !error.refusalStatus && !isNotFoundSignal(error),\n 'got ' + String(error),\n )\n })\n\n await check('the visitor\\'s Authorization header is forwarded', async () => {\n const value = await withRequest(new Request('https://app.test/', { headers: { authorization: 'Bearer conformance' } }), () =>\n call('Conformance.authorization'),\n )\n\n expect(value === 'Bearer conformance', 'got ' + JSON.stringify(value))\n })\n\n await check('calls in one batch are each answered, a refusal only its own', async () => {\n const [a, b, c] = await Promise.allSettled([\n call('Conformance.echo', 1),\n call('Conformance.unauthenticated'),\n call('Conformance.echo', 2),\n ])\n\n expect(a.status === 'fulfilled' && a.value === 1, 'first ' + JSON.stringify(a))\n expect(b.status === 'rejected' && b.reason instanceof ServerAuthenticationError, 'second ' + String((b as PromiseRejectedResult).reason))\n expect(c.status === 'fulfilled' && c.value === 2, 'third ' + JSON.stringify(c))\n })\n\n await check('a guard that passes answers true', async () => {\n const value = await call('__rsc.middleware', ['conformance-allow'])\n\n expect(value === true, 'got ' + JSON.stringify(value))\n })\n\n await check('a guard that refuses refuses', async () => {\n const value = await call('__rsc.middleware', ['conformance-deny']).catch((e: unknown) => e)\n\n expect(value !== true, 'it answered true')\n })\n\n await check('a guard nobody registered refuses: fail closed', async () => {\n const value = await call('__rsc.middleware', ['conformance-nobody-registered-this']).catch((e: unknown) => e)\n\n expect(value !== true, 'it answered true')\n })\n\n if (wrongSecret) {\n await check('a call with the wrong secret is refused', async () => {\n const value = await wrongSecret('Conformance.echo', 'should not run').catch((e: unknown) => e)\n\n expect(value !== 'should not run', 'it ran')\n })\n }\n\n return results\n}\n\n/** Run the suite against an adapter's endpoint. */\nexport async function runConformance(options: ConformanceOptions): Promise<ConformanceResult[]> {\n const revalidated: string[][] = []\n const client = (secret: string) =>\n httpHostCalls({\n endpoint: options.endpoint,\n secret,\n fetch: options.fetch,\n onRevalidate: (targets) => revalidated.push(targets),\n })\n\n return await conformance(client(options.secret), {\n revalidated,\n manifest: options.manifest,\n wrongSecret: client(options.secret + '-wrong'),\n })\n}\n\n/**\n * Whether a value fits the JSON Schema subset the manifest uses. Null when it\n * does; otherwise where and why it does not.\n */\nexport function conformsTo(value: unknown, schema: Schema, defs: Record<string, Schema>, at: string): string | null {\n if (!schema || Object.keys(schema).length === 0) return null\n\n const ref = schema.$ref\n\n if (typeof ref === 'string' && ref.startsWith('#/defs/')) {\n const target = defs[ref.slice(7)]\n\n return target ? conformsTo(value, target, defs, at) : `${at}: ${ref} is not in defs`\n }\n\n if (Array.isArray(schema.anyOf)) {\n const fits = (schema.anyOf as Schema[]).some((s) => conformsTo(value, s, defs, at) === null)\n\n return fits ? null : `${at}: ${JSON.stringify(value)} is none of ${JSON.stringify(schema.anyOf)}`\n }\n\n if (Array.isArray(schema.enum)) {\n return (schema.enum as unknown[]).includes(value) ? null : `${at}: ${JSON.stringify(value)} is not one of ${JSON.stringify(schema.enum)}`\n }\n\n const kind = Array.isArray(value) ? 'array' : value === null ? 'null' : typeof value\n\n switch (schema.type) {\n case 'string':\n if (kind !== 'string') return `${at}: expected a string, got ${JSON.stringify(value)}`\n if (schema.format === 'date-time' && Number.isNaN(Date.parse(value as string))) return `${at}: ${JSON.stringify(value)} is not a date-time`\n return null\n case 'integer':\n return Number.isInteger(value) ? null : `${at}: expected an integer, got ${JSON.stringify(value)}`\n case 'number':\n return kind === 'number' ? null : `${at}: expected a number, got ${JSON.stringify(value)}`\n case 'boolean':\n return kind === 'boolean' ? null : `${at}: expected a boolean, got ${JSON.stringify(value)}`\n case 'null':\n return value === null ? null : `${at}: expected null, got ${JSON.stringify(value)}`\n case 'array': {\n if (kind !== 'array') return `${at}: expected an array, got ${JSON.stringify(value)}`\n for (const [i, item] of (value as unknown[]).entries()) {\n const problem = conformsTo(item, schema.items as Schema, defs, `${at}[${i}]`)\n if (problem) return problem\n }\n return null\n }\n case 'object': {\n if (kind !== 'object') return `${at}: expected an object, got ${JSON.stringify(value)}`\n const object = value as Record<string, unknown>\n const properties = (schema.properties ?? {}) as Record<string, Schema>\n for (const name of (schema.required as string[] | undefined) ?? []) {\n if (!(name in object)) return `${at}.${name}: required, and missing`\n }\n for (const [name, s] of Object.entries(properties)) {\n if (name in object) {\n const problem = conformsTo(object[name], s, defs, `${at}.${name}`)\n if (problem) return problem\n }\n }\n const extra = schema.additionalProperties as Schema | undefined\n if (extra && !schema.properties) {\n for (const [name, item] of Object.entries(object)) {\n const problem = conformsTo(item, extra, defs, `${at}.${name}`)\n if (problem) return problem\n }\n }\n return null\n }\n default:\n return null\n }\n}\n\n/** Print a result table, and say whether the adapter conforms. */\nexport function report(results: ConformanceResult[]): boolean {\n for (const r of results) {\n stdout.write(` ${r.ok ? '✓' : '✗'} ${r.case}${r.ok ? '' : '\\n ' + r.detail}\\n`)\n }\n\n const failed = results.filter((r) => !r.ok).length\n\n stdout.write(failed === 0 ? `\\n conforms: ${results.length} cases\\n` : `\\n ${failed} of ${results.length} cases failed\\n`)\n\n return failed === 0\n}\n\n// Run as a command, not when imported.\nif (import.meta.url === pathToFileURL(argv[1] ?? '').href || argv[1]?.endsWith('rsc-kit-conformance')) {\n const flag = (name: string) => {\n const at = argv.indexOf('--' + name)\n\n return at === -1 ? undefined : argv[at + 1]\n }\n\n const endpoint = flag('endpoint')\n const secret = flag('secret')\n\n if (!endpoint || !secret) {\n stderr.write('usage: rsc-kit-conformance --endpoint <url> --secret <secret> [--manifest rsc-host.json]\\n')\n exit(2)\n }\n\n runConformance({ endpoint, secret, manifest: flag('manifest') })\n .then((results) => exit(report(results) ? 0 : 1))\n .catch((error: unknown) => {\n stderr.write('rsc-kit-conformance: ' + (error instanceof Error ? error.message : String(error)) + '\\n')\n exit(1)\n })\n}\n"]}
1
+ {"version":3,"file":"conformance.js","sourceRoot":"","sources":["../src/conformance.ts"],"names":[],"mappings":"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","sourcesContent":["#!/usr/bin/env node\n// The contract every backend adapter keeps, as a suite it runs against itself.\n//\n// A backend answers rpc(), actions and guards over one endpoint, and every\n// difference between how it and the engine read that wire is a bug in an\n// app that nobody wrote: a nil slice arriving as null where the type said a\n// list, a timestamp the type called unknown, a refusal that did not come out\n// as the error a page checks for. Each was found by an app, one at a time.\n// This finds them before an adapter ships.\n//\n// The adapter registers the Conformance.* functions described in CASES, in\n// its own language, the way an app would write them; this calls them through\n// the real client and checks what arrives. Where the adapter's manifest types\n// a function, every value it sends is checked against that type too.\n//\n// rsc-kit-conformance --endpoint http://127.0.0.1:8080/__rsc/host-call \\\n// --secret test-secret --manifest rsc-host.json\n//\n// The test host's hostReply passes the same suite (conformance.test.ts), so\n// a page test faking the backend fakes what a real adapter does.\n\nimport { readFileSync } from 'node:fs'\nimport { argv, exit, stderr, stdout } from 'node:process'\nimport { pathToFileURL } from 'node:url'\nimport { httpHostCalls } from './hostCalls.js'\nimport { isNotFoundSignal } from './notFound.js'\nimport { withRedirect } from './redirect.js'\nimport { withRequest } from './request.js'\nimport { ServerAuthenticationError, ServerAuthorizationError } from './js/errors.js'\n\ntype Schema = Record<string, unknown>\n\n/** A host-call client: the real one in a run, the test host's in core's own test. */\nexport type ConformanceCall = (name: string, ...args: unknown[]) => Promise<unknown>\n\nexport interface ConformanceOptions {\n /** The adapter's host-call endpoint, e.g. http://127.0.0.1:8080/__rsc/host-call. */\n endpoint: string\n /** The secret the adapter checks. */\n secret: string\n /** The adapter's rsc-host.json, parsed or as a path: its types are checked against what arrives. */\n manifest?: string | { functions?: string[]; types?: Record<string, { result?: Schema }>; defs?: Record<string, Schema> }\n /** For a test: the fetch the client uses. */\n fetch?: typeof fetch\n}\n\nexport interface ConformanceResult {\n case: string\n ok: boolean\n /** What went wrong, when it did. */\n detail?: string\n}\n\n/**\n * What the adapter registers, and what each must do. Names are fixed; how\n * they are written is the adapter's - the point is that they are written the\n * way an app's would be, with the adapter's ordinary API.\n */\nexport const CASES = {\n 'Conformance.echo': 'Return its one argument unchanged: any JSON value, nested.',\n 'Conformance.emptyList': 'Return an empty list of objects, the way the language makes \"no rows\" (Go: a nil slice).',\n 'Conformance.time': \"Return the instant 2026-01-02T03:04:05Z as the language's own time value.\",\n 'Conformance.noTime': \"Return an absent time: a nil pointer, a null Carbon, typed as a time or nothing.\",\n 'Conformance.unauthenticated': 'Refuse as not signed in, the way the framework does.',\n 'Conformance.unauthorized': 'Refuse as signed in but not allowed.',\n 'Conformance.notFound': \"Refuse as not found (404), the way the framework does: Go's Refuse(404), Laravel's abort(404).\",\n 'Conformance.refuse': 'Refuse with status 429 and the message \"Slow down.\"',\n 'Conformance.invalid': 'Refuse the input: a validation error on the field \"name\".',\n 'Conformance.redirect': 'Send the visitor to /login.',\n 'Conformance.revalidate': 'Mark the region \"orders\" stale, and return \"ok\".',\n 'Conformance.fail': 'Fail unexpectedly: an ordinary error, not a refusal.',\n 'Conformance.authorization': \"Return the request's Authorization header, as the renderer forwarded it.\",\n '__rsc.middleware': 'Guards: \"conformance-allow\" passes; \"conformance-deny\" refuses; a name with no guard refuses.',\n 'Conformance.change': 'Say the name \"conformance:changed\" changed, the way the adapter does from a webhook, and return \"ok\".',\n '__rsc.changed':\n 'Given { since: { name: version }, wait }: answer { versions } with every name whose version differs from since now. ' +\n 'A name never changed is at 0. May hold the call up to wait ms for one to differ; may answer at once.',\n} as const\n\nconst INSTANT = Date.parse('2026-01-02T03:04:05Z')\n\nconst ECHOES: unknown[] = [null, 0, -1.5, 'héllo ✓ \"quoted\"', [1, 'a', null], { a: { b: [true, false] }, c: '' }]\n\n/**\n * Run the suite against a client. Every case runs; none stops another.\n *\n * `revalidated` is where the client records what each call marked stale -\n * its onRevalidate - so the revalidation case can read it.\n */\nexport async function conformance(\n call: ConformanceCall,\n options: { revalidated: string[][]; manifest?: ConformanceOptions['manifest']; wrongSecret?: ConformanceCall },\n): Promise<ConformanceResult[]> {\n const { revalidated, manifest, wrongSecret } = options\n const results: ConformanceResult[] = []\n const types = typeof manifest === 'string' ? JSON.parse(readFileSync(manifest, 'utf-8')) : manifest\n\n const check = async (name: string, run: () => Promise<void>) => {\n try {\n await run()\n results.push({ case: name, ok: true })\n } catch (error) {\n results.push({ case: name, ok: false, detail: error instanceof Error ? error.message : String(error) })\n }\n }\n\n const expect = (ok: boolean, detail: string) => {\n if (!ok) throw new Error(detail)\n }\n\n const rejection = async (run: () => Promise<unknown>): Promise<unknown> => {\n try {\n const value = await run()\n\n throw new Error('answered ' + JSON.stringify(value) + ' instead of refusing')\n } catch (error) {\n return error\n }\n }\n\n /** The value against the type the adapter's manifest declares, when it declares one. */\n const typed = (name: string, value: unknown) => {\n const schema = types?.types?.[name]?.result\n\n if (!schema) return\n\n const problem = conformsTo(value, schema, types?.defs ?? {}, 'result')\n\n expect(problem === null, `the manifest types ${name}'s result, and what arrived does not fit it: ${problem}`)\n }\n\n await check('the manifest lists every Conformance function', async () => {\n if (!types) return\n\n const missing = Object.keys(CASES).filter((n) => !n.startsWith('__') && !types.functions?.includes(n))\n\n expect(missing.length === 0, 'not in functions: ' + missing.join(', '))\n })\n\n await check('a value of any JSON shape comes back unchanged', async () => {\n for (const value of ECHOES) {\n const back = await call('Conformance.echo', value)\n\n expect(JSON.stringify(back) === JSON.stringify(value), `sent ${JSON.stringify(value)}, got ${JSON.stringify(back)}`)\n }\n })\n\n await check('\"no rows\" is an empty list, never null', async () => {\n const value = await call('Conformance.emptyList')\n\n expect(Array.isArray(value) && value.length === 0, 'got ' + JSON.stringify(value))\n typed('Conformance.emptyList', value)\n })\n\n await check('a time is an ISO 8601 string of the same instant', async () => {\n const value = await call('Conformance.time')\n\n expect(typeof value === 'string' && Date.parse(value) === INSTANT, 'got ' + JSON.stringify(value))\n typed('Conformance.time', value)\n })\n\n await check('an absent time is null', async () => {\n const value = await call('Conformance.noTime')\n\n expect(value === null, 'got ' + JSON.stringify(value))\n typed('Conformance.noTime', value)\n })\n\n await check('not signed in is the engine\\'s ServerAuthenticationError', async () => {\n const error = await rejection(() => call('Conformance.unauthenticated'))\n\n expect(error instanceof ServerAuthenticationError, 'got ' + String(error))\n })\n\n await check('not allowed is the engine\\'s ServerAuthorizationError', async () => {\n const error = await rejection(() => call('Conformance.unauthorized'))\n\n expect(error instanceof ServerAuthorizationError, 'got ' + String(error))\n })\n\n await check('not found is the engine\\'s notFound()', async () => {\n const error = await rejection(() => call('Conformance.notFound'))\n\n expect(isNotFoundSignal(error), 'got ' + String(error))\n })\n\n await check('a refusal keeps its status and its message', async () => {\n const error = (await rejection(() => call('Conformance.refuse'))) as Error & { refusalStatus?: number }\n\n expect(error.refusalStatus === 429, 'status ' + String(error.refusalStatus))\n expect(String(error.message).includes('Slow down.'), 'message ' + JSON.stringify(error.message))\n })\n\n await check('refused input names its field', async () => {\n const error = (await rejection(() => call('Conformance.invalid'))) as { errors?: Record<string, string[]> }\n\n expect(Array.isArray(error.errors?.name) && error.errors.name.length > 0, 'errors ' + JSON.stringify(error.errors))\n })\n\n await check('a redirect is the engine\\'s redirect, to where it said', async () => {\n const taken = await withRedirect(async (seen) => {\n await rejection(() => call('Conformance.redirect'))\n\n return seen()\n })\n\n expect(taken?.location === '/login', 'redirect ' + JSON.stringify(taken))\n expect(taken!.status >= 300 && taken!.status < 400, 'status ' + taken?.status)\n })\n\n await check('a revalidation rides with the result', async () => {\n const value = await call('Conformance.revalidate')\n\n expect(value === 'ok', 'got ' + JSON.stringify(value))\n expect(revalidated.some((r) => r.includes('orders')), 'revalidated ' + JSON.stringify(revalidated))\n })\n\n await check('an unexpected failure is an error, not a refusal', async () => {\n const error = (await rejection(() => call('Conformance.fail'))) as Error & { refusalStatus?: number }\n\n expect(\n error instanceof Error && !(error instanceof ServerAuthenticationError) && !(error instanceof ServerAuthorizationError) && !error.refusalStatus && !isNotFoundSignal(error),\n 'got ' + String(error),\n )\n })\n\n await check('the visitor\\'s Authorization header is forwarded', async () => {\n const value = await withRequest(new Request('https://app.test/', { headers: { authorization: 'Bearer conformance' } }), () =>\n call('Conformance.authorization'),\n )\n\n expect(value === 'Bearer conformance', 'got ' + JSON.stringify(value))\n })\n\n await check('calls in one batch are each answered, a refusal only its own', async () => {\n const [a, b, c] = await Promise.allSettled([\n call('Conformance.echo', 1),\n call('Conformance.unauthenticated'),\n call('Conformance.echo', 2),\n ])\n\n expect(a.status === 'fulfilled' && a.value === 1, 'first ' + JSON.stringify(a))\n expect(b.status === 'rejected' && b.reason instanceof ServerAuthenticationError, 'second ' + String((b as PromiseRejectedResult).reason))\n expect(c.status === 'fulfilled' && c.value === 2, 'third ' + JSON.stringify(c))\n })\n\n await check('a guard that passes answers true', async () => {\n const value = await call('__rsc.middleware', ['conformance-allow'])\n\n expect(value === true, 'got ' + JSON.stringify(value))\n })\n\n await check('a guard that refuses refuses', async () => {\n const value = await call('__rsc.middleware', ['conformance-deny']).catch((e: unknown) => e)\n\n expect(value !== true, 'it answered true')\n })\n\n await check('a guard nobody registered refuses: fail closed', async () => {\n const value = await call('__rsc.middleware', ['conformance-nobody-registered-this']).catch((e: unknown) => e)\n\n expect(value !== true, 'it answered true')\n })\n\n const versionsOf = async (query: { since: Record<string, number>; wait?: number }) => {\n const answer = (await call('__rsc.changed', query)) as { versions?: Record<string, number> } | null\n\n expect(typeof answer?.versions === 'object' && answer.versions !== null, 'got ' + JSON.stringify(answer))\n\n return answer!.versions!\n }\n\n await check('a name nobody changed is at version 0, and unchanged from 0', async () => {\n const all = await versionsOf({ since: { 'conformance:never': -1 } })\n\n expect(all['conformance:never'] === 0, 'from -1: ' + JSON.stringify(all))\n\n const none = await versionsOf({ since: { 'conformance:never': 0 } })\n\n expect(Object.keys(none).length === 0, 'from 0: ' + JSON.stringify(none))\n })\n\n await check('saying a name changed moves its version', async () => {\n const before = (await versionsOf({ since: { 'conformance:changed': -1 } }))['conformance:changed'] ?? 0\n const value = await call('Conformance.change')\n\n expect(value === 'ok', 'got ' + JSON.stringify(value))\n\n const moved = await versionsOf({ since: { 'conformance:changed': before } })\n\n expect(typeof moved['conformance:changed'] === 'number' && moved['conformance:changed'] !== before, 'from ' + before + ': ' + JSON.stringify(moved))\n })\n\n await check('waiting for a name to change is bounded by wait', async () => {\n const started = Date.now()\n const none = await versionsOf({ since: { 'conformance:never': 0 }, wait: 300 })\n const took = Date.now() - started\n\n expect(Object.keys(none).length === 0, 'got ' + JSON.stringify(none))\n expect(took < 3_000, 'took ' + took + 'ms')\n })\n\n if (wrongSecret) {\n await check('a call with the wrong secret is refused', async () => {\n const value = await wrongSecret('Conformance.echo', 'should not run').catch((e: unknown) => e)\n\n expect(value !== 'should not run', 'it ran')\n })\n }\n\n return results\n}\n\n/** Run the suite against an adapter's endpoint. */\nexport async function runConformance(options: ConformanceOptions): Promise<ConformanceResult[]> {\n const revalidated: string[][] = []\n const client = (secret: string) =>\n httpHostCalls({\n endpoint: options.endpoint,\n secret,\n fetch: options.fetch,\n onRevalidate: (targets) => revalidated.push(targets),\n })\n\n return await conformance(client(options.secret), {\n revalidated,\n manifest: options.manifest,\n wrongSecret: client(options.secret + '-wrong'),\n })\n}\n\n/**\n * Whether a value fits the JSON Schema subset the manifest uses. Null when it\n * does; otherwise where and why it does not.\n */\nexport function conformsTo(value: unknown, schema: Schema, defs: Record<string, Schema>, at: string): string | null {\n if (!schema || Object.keys(schema).length === 0) return null\n\n const ref = schema.$ref\n\n if (typeof ref === 'string' && ref.startsWith('#/defs/')) {\n const target = defs[ref.slice(7)]\n\n return target ? conformsTo(value, target, defs, at) : `${at}: ${ref} is not in defs`\n }\n\n if (Array.isArray(schema.anyOf)) {\n const fits = (schema.anyOf as Schema[]).some((s) => conformsTo(value, s, defs, at) === null)\n\n return fits ? null : `${at}: ${JSON.stringify(value)} is none of ${JSON.stringify(schema.anyOf)}`\n }\n\n if (Array.isArray(schema.enum)) {\n return (schema.enum as unknown[]).includes(value) ? null : `${at}: ${JSON.stringify(value)} is not one of ${JSON.stringify(schema.enum)}`\n }\n\n const kind = Array.isArray(value) ? 'array' : value === null ? 'null' : typeof value\n\n switch (schema.type) {\n case 'string':\n if (kind !== 'string') return `${at}: expected a string, got ${JSON.stringify(value)}`\n if (schema.format === 'date-time' && Number.isNaN(Date.parse(value as string))) return `${at}: ${JSON.stringify(value)} is not a date-time`\n return null\n case 'integer':\n return Number.isInteger(value) ? null : `${at}: expected an integer, got ${JSON.stringify(value)}`\n case 'number':\n return kind === 'number' ? null : `${at}: expected a number, got ${JSON.stringify(value)}`\n case 'boolean':\n return kind === 'boolean' ? null : `${at}: expected a boolean, got ${JSON.stringify(value)}`\n case 'null':\n return value === null ? null : `${at}: expected null, got ${JSON.stringify(value)}`\n case 'array': {\n if (kind !== 'array') return `${at}: expected an array, got ${JSON.stringify(value)}`\n for (const [i, item] of (value as unknown[]).entries()) {\n const problem = conformsTo(item, schema.items as Schema, defs, `${at}[${i}]`)\n if (problem) return problem\n }\n return null\n }\n case 'object': {\n if (kind !== 'object') return `${at}: expected an object, got ${JSON.stringify(value)}`\n const object = value as Record<string, unknown>\n const properties = (schema.properties ?? {}) as Record<string, Schema>\n for (const name of (schema.required as string[] | undefined) ?? []) {\n if (!(name in object)) return `${at}.${name}: required, and missing`\n }\n for (const [name, s] of Object.entries(properties)) {\n if (name in object) {\n const problem = conformsTo(object[name], s, defs, `${at}.${name}`)\n if (problem) return problem\n }\n }\n const extra = schema.additionalProperties as Schema | undefined\n if (extra && !schema.properties) {\n for (const [name, item] of Object.entries(object)) {\n const problem = conformsTo(item, extra, defs, `${at}.${name}`)\n if (problem) return problem\n }\n }\n return null\n }\n default:\n return null\n }\n}\n\n/** Print a result table, and say whether the adapter conforms. */\nexport function report(results: ConformanceResult[]): boolean {\n for (const r of results) {\n stdout.write(` ${r.ok ? '✓' : '✗'} ${r.case}${r.ok ? '' : '\\n ' + r.detail}\\n`)\n }\n\n const failed = results.filter((r) => !r.ok).length\n\n stdout.write(failed === 0 ? `\\n conforms: ${results.length} cases\\n` : `\\n ${failed} of ${results.length} cases failed\\n`)\n\n return failed === 0\n}\n\n// Run as a command, not when imported.\nif (import.meta.url === pathToFileURL(argv[1] ?? '').href || argv[1]?.endsWith('rsc-kit-conformance')) {\n const flag = (name: string) => {\n const at = argv.indexOf('--' + name)\n\n return at === -1 ? undefined : argv[at + 1]\n }\n\n const endpoint = flag('endpoint')\n const secret = flag('secret')\n\n if (!endpoint || !secret) {\n stderr.write('usage: rsc-kit-conformance --endpoint <url> --secret <secret> [--manifest rsc-host.json]\\n')\n exit(2)\n }\n\n runConformance({ endpoint, secret, manifest: flag('manifest') })\n .then((results) => exit(report(results) ? 0 : 1))\n .catch((error: unknown) => {\n stderr.write('rsc-kit-conformance: ' + (error instanceof Error ? error.message : String(error)) + '\\n')\n exit(1)\n })\n}\n"]}
package/dist/events.d.ts CHANGED
@@ -27,11 +27,11 @@ export interface EventsInput<P = Record<string, string>> {
27
27
  request: Request;
28
28
  }
29
29
  /** A message with a name or an id, for a client that listens by name or resumes. Made by `named()`. */
30
- export interface NamedEvent {
30
+ export interface NamedEvent<E extends string = string, D = unknown> {
31
31
  readonly [NAMED]: true;
32
- event?: string;
32
+ event?: E;
33
33
  id?: string;
34
- data: unknown;
34
+ data: D;
35
35
  }
36
36
  declare const NAMED: unique symbol;
37
37
  /**
@@ -41,17 +41,33 @@ declare const NAMED: unique symbol;
41
41
  * have a `data` key is still data, and the generator's own type stays the
42
42
  * type of what it yields.
43
43
  */
44
- export declare function named<D>(event: string, data: D, options?: {
44
+ export declare function named<const E extends string, D>(event: E, data: D, options?: {
45
45
  id?: string;
46
- }): NamedEvent;
46
+ }): NamedEvent<E, D>;
47
47
  /** How often a comment goes out on an idle stream, so a proxy keeps it open. */
48
48
  export declare const KEEPALIVE_MS = 15000;
49
49
  /** One message, framed. */
50
50
  export declare function frame(value: unknown): string;
51
- export declare function events<P = Record<string, string>, T = unknown>(produce: (input: EventsInput<P>) => AsyncIterable<T | NamedEvent>, options?: {
52
- keepaliveMs?: number;
53
- }): (request: Request, input: {
51
+ /**
52
+ * What `events()` returns: a GET handler that also says, as a type only, what
53
+ * its generator yields. Nothing reads `~events` at runtime; the build records
54
+ * it per url, which is how `useEvents('/api/orders/42/events')` types a
55
+ * message without being told - and stops compiling when the route changes
56
+ * what it sends.
57
+ */
58
+ export type EventsRoute<P = Record<string, string>, Y = unknown> = ((request: Request, input: {
54
59
  params: Promise<P>;
55
60
  searchParams: Promise<URLSearchParams>;
56
- }) => Response;
61
+ }) => Response) & {
62
+ readonly "~events"?: {
63
+ yields: Y;
64
+ };
65
+ };
66
+ /** The unnamed messages among a stream's yields: what `useEvents` receives without `event`. */
67
+ export type MessageOf<Y> = Exclude<Y, NamedEvent<string, unknown>>;
68
+ /** The data of the messages named `E`. A name computed at runtime matches any. */
69
+ export type NamedMessageOf<Y, E extends string> = Y extends NamedEvent<infer N, infer D> ? (E extends N ? D : never) : never;
70
+ export declare function events<P = Record<string, string>, Y = unknown>(produce: (input: EventsInput<P>) => AsyncIterable<Y>, options?: {
71
+ keepaliveMs?: number;
72
+ }): EventsRoute<P, Y>;
57
73
  export {};
@@ -1 +1 @@
1
- {"version":3,"file":"events.js","sourceRoot":"","sources":["../src/events.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * A route that streams: server-sent events from an async generator.\n *\n * // app/api/orders/[id]/events/route.ts\n * export const GET = events(async function* ({ params, signal }) {\n * for await (const status of orderStatus((await params).id, { signal })) {\n * yield { status }\n * }\n * })\n *\n * An ordinary route.ts, so it lives beside its pages, runs the middleware.ts\n * above it and takes the same params. What this adds is the framing - one\n * `data:` line per yield, JSON - a keepalive comment every fifteen seconds\n * so a proxy does not drop an idle stream, the headers a stream needs, and\n * an end to the generator when the browser goes away, which is what `signal`\n * is for. `useEvents` on the client reads it.\n *\n * Not a query. A query answers once and is cacheable; a stream answers for\n * as long as the tab is open and is not. A server component cannot await a\n * stream, so it has no place in the payload either.\n */\n\nexport interface EventsInput<P = Record<string, string>> {\n params: Promise<P>;\n searchParams: Promise<URLSearchParams>;\n /** Aborted when the browser disconnects. Pass it on, or check `aborted`. */\n signal: AbortSignal;\n request: Request;\n}\n\n/** A message with a name or an id, for a client that listens by name or resumes. Made by `named()`. */\nexport interface NamedEvent {\n readonly [NAMED]: true;\n event?: string;\n id?: string;\n data: unknown;\n}\n\nconst NAMED = Symbol.for(\"@rsc-kit/core.named-event\");\n\n/**\n * A message with a name or an id: `yield named('paid', order)`, or\n * `named('paid', order, { id: order.id })` for one a client can resume from.\n * Built by a function rather than by shape, so a message that happens to\n * have a `data` key is still data, and the generator's own type stays the\n * type of what it yields.\n */\nexport function named<D>(\n event: string,\n data: D,\n options: { id?: string } = {},\n): NamedEvent {\n return { [NAMED]: true, event, id: options.id, data };\n}\n\n/** How often a comment goes out on an idle stream, so a proxy keeps it open. */\nexport const KEEPALIVE_MS = 15_000;\n\nfunction isNamed(value: unknown): value is NamedEvent {\n return (\n typeof value === \"object\" &&\n value !== null &&\n (value as { [NAMED]?: true })[NAMED] === true\n );\n}\n\n/** One message, framed. */\nexport function frame(value: unknown): string {\n const named = isNamed(value) ? value : null;\n const lines: string[] = [];\n\n if (named?.event) lines.push(`event: ${named.event}`);\n if (named?.id) lines.push(`id: ${named.id}`);\n lines.push(`data: ${JSON.stringify(named ? named.data : value)}`);\n\n return lines.join(\"\\n\") + \"\\n\\n\";\n}\n\nexport function events<P = Record<string, string>, T = unknown>(\n produce: (input: EventsInput<P>) => AsyncIterable<T | NamedEvent>,\n options: { keepaliveMs?: number } = {},\n): (\n request: Request,\n input: { params: Promise<P>; searchParams: Promise<URLSearchParams> },\n) => Response {\n const keepaliveMs = options.keepaliveMs ?? KEEPALIVE_MS;\n\n return (request, input) => {\n const controller = new AbortController();\n const encoder = new TextEncoder();\n\n request.signal.addEventListener(\"abort\", () => controller.abort(), {\n once: true,\n });\n\n const stream = new ReadableStream<Uint8Array>({\n async start(sink) {\n // The retry hint first, so a browser that loses the connection waits\n // a moment rather than hammering.\n sink.enqueue(encoder.encode(\"retry: 1000\\n\\n\"));\n\n const keepalive = setInterval(() => {\n try {\n sink.enqueue(encoder.encode(\": keepalive\\n\\n\"));\n } catch {\n // Closed between the check and the write; the loop below ends it.\n }\n }, keepaliveMs);\n\n try {\n for await (const value of produce({\n ...input,\n signal: controller.signal,\n request,\n })) {\n if (controller.signal.aborted) break;\n\n sink.enqueue(encoder.encode(frame(value)));\n }\n } catch (error) {\n if (!controller.signal.aborted) sink.error(error);\n } finally {\n clearInterval(keepalive);\n\n if (!controller.signal.aborted) {\n try {\n sink.close();\n } catch {\n // Already closed by the consumer.\n }\n }\n }\n },\n cancel() {\n controller.abort();\n },\n });\n\n return new Response(stream, {\n headers: {\n \"Content-Type\": \"text/event-stream; charset=utf-8\",\n \"Cache-Control\": \"no-store\",\n // Nginx buffers by default, which turns a stream into one late burst.\n \"X-Accel-Buffering\": \"no\",\n },\n });\n };\n}\n"]}
1
+ {"version":3,"file":"events.js","sourceRoot":"","sources":["../src/events.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * A route that streams: server-sent events from an async generator.\n *\n * // app/api/orders/[id]/events/route.ts\n * export const GET = events(async function* ({ params, signal }) {\n * for await (const status of orderStatus((await params).id, { signal })) {\n * yield { status }\n * }\n * })\n *\n * An ordinary route.ts, so it lives beside its pages, runs the middleware.ts\n * above it and takes the same params. What this adds is the framing - one\n * `data:` line per yield, JSON - a keepalive comment every fifteen seconds\n * so a proxy does not drop an idle stream, the headers a stream needs, and\n * an end to the generator when the browser goes away, which is what `signal`\n * is for. `useEvents` on the client reads it.\n *\n * Not a query. A query answers once and is cacheable; a stream answers for\n * as long as the tab is open and is not. A server component cannot await a\n * stream, so it has no place in the payload either.\n */\n\nexport interface EventsInput<P = Record<string, string>> {\n params: Promise<P>;\n searchParams: Promise<URLSearchParams>;\n /** Aborted when the browser disconnects. Pass it on, or check `aborted`. */\n signal: AbortSignal;\n request: Request;\n}\n\n/** A message with a name or an id, for a client that listens by name or resumes. Made by `named()`. */\nexport interface NamedEvent<E extends string = string, D = unknown> {\n readonly [NAMED]: true;\n event?: E;\n id?: string;\n data: D;\n}\n\nconst NAMED = Symbol.for(\"@rsc-kit/core.named-event\");\n\n/**\n * A message with a name or an id: `yield named('paid', order)`, or\n * `named('paid', order, { id: order.id })` for one a client can resume from.\n * Built by a function rather than by shape, so a message that happens to\n * have a `data` key is still data, and the generator's own type stays the\n * type of what it yields.\n */\nexport function named<const E extends string, D>(\n event: E,\n data: D,\n options: { id?: string } = {},\n): NamedEvent<E, D> {\n return { [NAMED]: true, event, id: options.id, data };\n}\n\n/** How often a comment goes out on an idle stream, so a proxy keeps it open. */\nexport const KEEPALIVE_MS = 15_000;\n\nfunction isNamed(value: unknown): value is NamedEvent {\n return (\n typeof value === \"object\" &&\n value !== null &&\n (value as { [NAMED]?: true })[NAMED] === true\n );\n}\n\n/** One message, framed. */\nexport function frame(value: unknown): string {\n const named = isNamed(value) ? value : null;\n const lines: string[] = [];\n\n if (named?.event) lines.push(`event: ${named.event}`);\n if (named?.id) lines.push(`id: ${named.id}`);\n lines.push(`data: ${JSON.stringify(named ? named.data : value)}`);\n\n return lines.join(\"\\n\") + \"\\n\\n\";\n}\n\n/**\n * What `events()` returns: a GET handler that also says, as a type only, what\n * its generator yields. Nothing reads `~events` at runtime; the build records\n * it per url, which is how `useEvents('/api/orders/42/events')` types a\n * message without being told - and stops compiling when the route changes\n * what it sends.\n */\nexport type EventsRoute<P = Record<string, string>, Y = unknown> = ((\n request: Request,\n input: { params: Promise<P>; searchParams: Promise<URLSearchParams> },\n) => Response) & { readonly \"~events\"?: { yields: Y } };\n\n/** The unnamed messages among a stream's yields: what `useEvents` receives without `event`. */\nexport type MessageOf<Y> = Exclude<Y, NamedEvent<string, unknown>>;\n\n/** The data of the messages named `E`. A name computed at runtime matches any. */\nexport type NamedMessageOf<Y, E extends string> =\n Y extends NamedEvent<infer N, infer D> ? (E extends N ? D : never) : never;\n\nexport function events<P = Record<string, string>, Y = unknown>(\n produce: (input: EventsInput<P>) => AsyncIterable<Y>,\n options: { keepaliveMs?: number } = {},\n): EventsRoute<P, Y> {\n const keepaliveMs = options.keepaliveMs ?? KEEPALIVE_MS;\n\n return (\n request: Request,\n input: { params: Promise<P>; searchParams: Promise<URLSearchParams> },\n ) => {\n const controller = new AbortController();\n const encoder = new TextEncoder();\n\n request.signal.addEventListener(\"abort\", () => controller.abort(), {\n once: true,\n });\n\n const stream = new ReadableStream<Uint8Array>({\n async start(sink) {\n // The retry hint first, so a browser that loses the connection waits\n // a moment rather than hammering.\n sink.enqueue(encoder.encode(\"retry: 1000\\n\\n\"));\n\n const keepalive = setInterval(() => {\n try {\n sink.enqueue(encoder.encode(\": keepalive\\n\\n\"));\n } catch {\n // Closed between the check and the write; the loop below ends it.\n }\n }, keepaliveMs);\n\n try {\n for await (const value of produce({\n ...input,\n signal: controller.signal,\n request,\n })) {\n if (controller.signal.aborted) break;\n\n sink.enqueue(encoder.encode(frame(value)));\n }\n } catch (error) {\n if (!controller.signal.aborted) sink.error(error);\n } finally {\n clearInterval(keepalive);\n\n if (!controller.signal.aborted) {\n try {\n sink.close();\n } catch {\n // Already closed by the consumer.\n }\n }\n }\n },\n cancel() {\n controller.abort();\n },\n });\n\n return new Response(stream, {\n headers: {\n \"Content-Type\": \"text/event-stream; charset=utf-8\",\n \"Cache-Control\": \"no-store\",\n // Nginx buffers by default, which turns a stream into one late burst.\n \"X-Accel-Buffering\": \"no\",\n },\n });\n };\n}\n"]}
package/dist/headers.d.ts CHANGED
@@ -68,6 +68,8 @@ export declare const HEADER: {
68
68
  readonly pprShellPath: '/_rsc/ppr-shell';
69
69
  /** Finish a shell an edge cache is already serving. */
70
70
  readonly pprResumePath: '/_rsc/ppr-resume';
71
+ /** The stream a tab hears on when a name its page refreshes on has changed. */
72
+ readonly changesPath: '/_rsc/changes';
71
73
  };
72
74
  /** Flight payload. */
73
75
  export declare const FLIGHT_TYPE = "text/x-component; charset=utf-8";
package/dist/headers.js CHANGED
@@ -77,6 +77,8 @@ export const HEADER = {
77
77
  pprShellPath: '/_rsc/ppr-shell',
78
78
  /** Finish a shell an edge cache is already serving. */
79
79
  pprResumePath: '/_rsc/ppr-resume',
80
+ /** The stream a tab hears on when a name its page refreshes on has changed. */
81
+ changesPath: '/_rsc/changes',
80
82
  };
81
83
  /** Flight payload. */
82
84
  export const FLIGHT_TYPE = 'text/x-component; charset=utf-8';
@@ -1 +1 @@
1
- {"version":3,"file":"headers.js","sourceRoot":"","sources":["../src/headers.ts"],"names":[],"mappings":"AAAA,2DAA2D;AAC3D,EAAE;AACF,0EAA0E;AAC1E,sEAAsE;AACtE,wEAAwE;AACxE,2EAA2E;AAC3E,gCAAgC;AAChC,EAAE;AACF,gFAAgF;AAEhF,MAAM,CAAC,MAAM,MAAM,GAAG;IACpB;;;OAGG;IACH,GAAG,EAAE,OAAO;IAEZ,iFAAiF;IACjF,QAAQ,EAAE,gBAAgB;IAE1B,kEAAkE;IAClE,YAAY,EAAE,qBAAqB;IAEnC,wCAAwC;IACxC,OAAO,EAAE,eAAe;IAExB,gFAAgF;IAChF,OAAO,EAAE,eAAe;IAExB,uDAAuD;IACvD,SAAS,EAAE,iBAAiB;IAE5B,gDAAgD;IAChD,OAAO,EAAE,eAAe;IAExB,uEAAuE;IACvE,UAAU,EAAE,kBAAkB;IAE9B,0CAA0C;IAC1C,MAAM,EAAE,cAAc;IAEtB;;;;;;;OAOG;IACH,QAAQ,EAAE,gBAAgB;IAE1B;;;;;;OAMG;IACH,WAAW,EAAE,oBAAoB;IAEjC;;;;;OAKG;IACH,UAAU,EAAE,cAAc;IAC1B;;;;;;;;;OASG;IACH;;;;;;;OAOG;IACH,KAAK,EAAE,aAAa;IAEpB,SAAS,EAAE,aAAa;IACxB,mEAAmE;IACnE,YAAY,EAAE,iBAAiB;IAC/B,uDAAuD;IACvD,aAAa,EAAE,kBAAkB;CACzB,CAAA;AAEV,sBAAsB;AACtB,MAAM,CAAC,MAAM,WAAW,GAAG,iCAAiC,CAAA;AAE5D,2BAA2B;AAC3B,MAAM,CAAC,MAAM,SAAS,GAAG,0BAA0B,CAAA;AAEnD;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG;IACzB,MAAM,CAAC,GAAG;IACV,MAAM,CAAC,QAAQ;IACf,MAAM,CAAC,UAAU;IACjB,MAAM,CAAC,SAAS;IAChB,MAAM,CAAC,OAAO;CACf,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;AAEZ;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,UAAU,GAAG,mBAAmB,CAAA;AAE7C;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,UAAU,GAAG,oCAAoC,CAAA;AAE9D;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG,qCAAqC,CAAA","sourcesContent":["// The wire protocol, as names rather than string literals.\n//\n// A host writing these out by hand is how they drift. Two of them are not\n// negotiable at all — the client sends them or asks for them at fixed\n// addresses, and a host that spells one differently fails silently: the\n// request falls through, the decoder never runs, and a button does nothing\n// with no error on either side.\n//\n// PROTOCOL.md describes what each one means. This is the same list, importable.\n\nexport const HEADER = {\n /**\n * Present on a request for a Flight payload rather than the document. One\n * url serves both, which is why every answer must Vary on it.\n */\n rsc: 'X-RSC',\n\n /** The layout chain the client has mounted, outermost first, comma-separated. */\n segments: 'X-RSC-Segments',\n\n /** The boundary the answer replaces. 0 means a whole document. */\n segmentDepth: 'X-RSC-Segment-Depth',\n\n /** The chain to send back next time. */\n layouts: 'X-RSC-Layouts',\n\n /** Identifies the build, so a client can notice it is talking to an old one. */\n version: 'X-RSC-Version',\n\n /** The slot an intercepted navigation is targeting. */\n intercept: 'X-RSC-Intercept',\n\n /** Where the navigation or action came from. */\n referer: 'X-RSC-Referer',\n\n /** One named region of the current page to render and return alone. */\n revalidate: 'X-RSC-Revalidate',\n\n /** The server reference being invoked. */\n action: 'X-RSC-Action',\n\n /**\n * Go here instead.\n *\n * Used for a redirect the client has to perform itself: a failed action, and\n * a navigation whose render redirected. Never a 3xx for those — `fetch`\n * follows one transparently, so the client would get the destination's HTML\n * where it expected a Flight payload and decode it as one.\n */\n redirect: 'X-RSC-Redirect',\n\n /**\n * The body's real type.\n *\n * The body itself goes out as application/octet-stream so a host that parses\n * multipart cannot consume it before the action does — reading Content-Type\n * instead leaves an upload undecodable.\n */\n contentType: 'X-RSC-Content-Type',\n\n /**\n * Where the browser posts server actions.\n *\n * Not a convention this can choose: the client runtime posts here\n * unconditionally.\n */\n actionPath: '/_rsc/action',\n /**\n * Where the browser reads queries.\n *\n * A GET, and that is the whole point of it being a separate address: a POST\n * is cacheable by nothing, so a read routed through the action endpoint can\n * never be kept by an HTTP cache, a CDN or a service worker. Only functions\n * declared with `query()` are reachable here — the endpoint checks the mark\n * before invoking anything, because otherwise this address would run any\n * registered action over GET.\n */\n /**\n * Sent on every read, and required by the query endpoint.\n *\n * A GET with no unusual header is a simple request, so any page could\n * trigger one with an <img> and the visitor's cookies would ride along.\n * This header is not CORS-safelisted, so the browser preflights it — the\n * same thing that makes a POST carrying X-RSC-Action safe.\n */\n query: 'X-RSC-Query',\n\n queryPath: '/_rsc/query',\n /** Build-time shell for a PPR route, for an edge cache to hold. */\n pprShellPath: '/_rsc/ppr-shell',\n /** Finish a shell an edge cache is already serving. */\n pprResumePath: '/_rsc/ppr-resume',\n} as const\n\n/** Flight payload. */\nexport const FLIGHT_TYPE = 'text/x-component; charset=utf-8'\n\n/** A rendered document. */\nexport const HTML_TYPE = 'text/html; charset=utf-8'\n\n/**\n * Every request header that changes what a response body contains.\n *\n * One url answers with a whole document, a partial payload, a named region or\n * an interceptor depending on these — so a cache keyed on the url alone, or on\n * `X-RSC` alone, will hand one client another's answer. They are materially\n * different bodies, not variations in presentation.\n */\nexport const VARY_ON_RSC = [\n HEADER.rsc,\n HEADER.segments,\n HEADER.revalidate,\n HEADER.intercept,\n HEADER.referer,\n].join(', ')\n\n/**\n * What a response says about being stored, when it must not be.\n *\n * `Vary` alone is not enough on the platform this targets. Cloudflare ignores\n * `Vary` for everything except `Accept-Encoding`, and this package ships a\n * Workers story as a headline feature — so one url answering with a document,\n * a Flight payload, a segment and an interceptor, keyed only on the url, hands\n * one visitor another's body. Anything narrowed by a request header, and\n * anything behind a guard, says outright that it is not to be stored.\n */\nexport const PER_CLIENT = 'private, no-store'\n\n/**\n * And what a frozen, unguarded page says.\n *\n * Explicit rather than absent: with no directive at all, whether an\n * intermediary stores it comes down to that intermediary's heuristics, which\n * is not a decision this package should be leaving to chance in either\n * direction.\n */\nexport const REVALIDATE = 'public, max-age=0, must-revalidate'\n\n/**\n * And what a page rendered for one request says.\n *\n * It may have read the visitor's cookies, and nothing in the headers - which\n * leave before the render has finished - can know whether it did. So a shared\n * cache may not keep it; the visitor's own browser may, and must ask again.\n */\nexport const PER_REQUEST = 'private, max-age=0, must-revalidate'\n"]}
1
+ {"version":3,"file":"headers.js","sourceRoot":"","sources":["../src/headers.ts"],"names":[],"mappings":"AAAA,2DAA2D;AAC3D,EAAE;AACF,0EAA0E;AAC1E,sEAAsE;AACtE,wEAAwE;AACxE,2EAA2E;AAC3E,gCAAgC;AAChC,EAAE;AACF,gFAAgF;AAEhF,MAAM,CAAC,MAAM,MAAM,GAAG;IACpB;;;OAGG;IACH,GAAG,EAAE,OAAO;IAEZ,iFAAiF;IACjF,QAAQ,EAAE,gBAAgB;IAE1B,kEAAkE;IAClE,YAAY,EAAE,qBAAqB;IAEnC,wCAAwC;IACxC,OAAO,EAAE,eAAe;IAExB,gFAAgF;IAChF,OAAO,EAAE,eAAe;IAExB,uDAAuD;IACvD,SAAS,EAAE,iBAAiB;IAE5B,gDAAgD;IAChD,OAAO,EAAE,eAAe;IAExB,uEAAuE;IACvE,UAAU,EAAE,kBAAkB;IAE9B,0CAA0C;IAC1C,MAAM,EAAE,cAAc;IAEtB;;;;;;;OAOG;IACH,QAAQ,EAAE,gBAAgB;IAE1B;;;;;;OAMG;IACH,WAAW,EAAE,oBAAoB;IAEjC;;;;;OAKG;IACH,UAAU,EAAE,cAAc;IAC1B;;;;;;;;;OASG;IACH;;;;;;;OAOG;IACH,KAAK,EAAE,aAAa;IAEpB,SAAS,EAAE,aAAa;IACxB,mEAAmE;IACnE,YAAY,EAAE,iBAAiB;IAC/B,uDAAuD;IACvD,aAAa,EAAE,kBAAkB;IACjC,+EAA+E;IAC/E,WAAW,EAAE,eAAe;CACpB,CAAA;AAEV,sBAAsB;AACtB,MAAM,CAAC,MAAM,WAAW,GAAG,iCAAiC,CAAA;AAE5D,2BAA2B;AAC3B,MAAM,CAAC,MAAM,SAAS,GAAG,0BAA0B,CAAA;AAEnD;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG;IACzB,MAAM,CAAC,GAAG;IACV,MAAM,CAAC,QAAQ;IACf,MAAM,CAAC,UAAU;IACjB,MAAM,CAAC,SAAS;IAChB,MAAM,CAAC,OAAO;CACf,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;AAEZ;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,UAAU,GAAG,mBAAmB,CAAA;AAE7C;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,UAAU,GAAG,oCAAoC,CAAA;AAE9D;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG,qCAAqC,CAAA","sourcesContent":["// The wire protocol, as names rather than string literals.\n//\n// A host writing these out by hand is how they drift. Two of them are not\n// negotiable at all — the client sends them or asks for them at fixed\n// addresses, and a host that spells one differently fails silently: the\n// request falls through, the decoder never runs, and a button does nothing\n// with no error on either side.\n//\n// PROTOCOL.md describes what each one means. This is the same list, importable.\n\nexport const HEADER = {\n /**\n * Present on a request for a Flight payload rather than the document. One\n * url serves both, which is why every answer must Vary on it.\n */\n rsc: 'X-RSC',\n\n /** The layout chain the client has mounted, outermost first, comma-separated. */\n segments: 'X-RSC-Segments',\n\n /** The boundary the answer replaces. 0 means a whole document. */\n segmentDepth: 'X-RSC-Segment-Depth',\n\n /** The chain to send back next time. */\n layouts: 'X-RSC-Layouts',\n\n /** Identifies the build, so a client can notice it is talking to an old one. */\n version: 'X-RSC-Version',\n\n /** The slot an intercepted navigation is targeting. */\n intercept: 'X-RSC-Intercept',\n\n /** Where the navigation or action came from. */\n referer: 'X-RSC-Referer',\n\n /** One named region of the current page to render and return alone. */\n revalidate: 'X-RSC-Revalidate',\n\n /** The server reference being invoked. */\n action: 'X-RSC-Action',\n\n /**\n * Go here instead.\n *\n * Used for a redirect the client has to perform itself: a failed action, and\n * a navigation whose render redirected. Never a 3xx for those — `fetch`\n * follows one transparently, so the client would get the destination's HTML\n * where it expected a Flight payload and decode it as one.\n */\n redirect: 'X-RSC-Redirect',\n\n /**\n * The body's real type.\n *\n * The body itself goes out as application/octet-stream so a host that parses\n * multipart cannot consume it before the action does — reading Content-Type\n * instead leaves an upload undecodable.\n */\n contentType: 'X-RSC-Content-Type',\n\n /**\n * Where the browser posts server actions.\n *\n * Not a convention this can choose: the client runtime posts here\n * unconditionally.\n */\n actionPath: '/_rsc/action',\n /**\n * Where the browser reads queries.\n *\n * A GET, and that is the whole point of it being a separate address: a POST\n * is cacheable by nothing, so a read routed through the action endpoint can\n * never be kept by an HTTP cache, a CDN or a service worker. Only functions\n * declared with `query()` are reachable here — the endpoint checks the mark\n * before invoking anything, because otherwise this address would run any\n * registered action over GET.\n */\n /**\n * Sent on every read, and required by the query endpoint.\n *\n * A GET with no unusual header is a simple request, so any page could\n * trigger one with an <img> and the visitor's cookies would ride along.\n * This header is not CORS-safelisted, so the browser preflights it — the\n * same thing that makes a POST carrying X-RSC-Action safe.\n */\n query: 'X-RSC-Query',\n\n queryPath: '/_rsc/query',\n /** Build-time shell for a PPR route, for an edge cache to hold. */\n pprShellPath: '/_rsc/ppr-shell',\n /** Finish a shell an edge cache is already serving. */\n pprResumePath: '/_rsc/ppr-resume',\n /** The stream a tab hears on when a name its page refreshes on has changed. */\n changesPath: '/_rsc/changes',\n} as const\n\n/** Flight payload. */\nexport const FLIGHT_TYPE = 'text/x-component; charset=utf-8'\n\n/** A rendered document. */\nexport const HTML_TYPE = 'text/html; charset=utf-8'\n\n/**\n * Every request header that changes what a response body contains.\n *\n * One url answers with a whole document, a partial payload, a named region or\n * an interceptor depending on these — so a cache keyed on the url alone, or on\n * `X-RSC` alone, will hand one client another's answer. They are materially\n * different bodies, not variations in presentation.\n */\nexport const VARY_ON_RSC = [\n HEADER.rsc,\n HEADER.segments,\n HEADER.revalidate,\n HEADER.intercept,\n HEADER.referer,\n].join(', ')\n\n/**\n * What a response says about being stored, when it must not be.\n *\n * `Vary` alone is not enough on the platform this targets. Cloudflare ignores\n * `Vary` for everything except `Accept-Encoding`, and this package ships a\n * Workers story as a headline feature — so one url answering with a document,\n * a Flight payload, a segment and an interceptor, keyed only on the url, hands\n * one visitor another's body. Anything narrowed by a request header, and\n * anything behind a guard, says outright that it is not to be stored.\n */\nexport const PER_CLIENT = 'private, no-store'\n\n/**\n * And what a frozen, unguarded page says.\n *\n * Explicit rather than absent: with no directive at all, whether an\n * intermediary stores it comes down to that intermediary's heuristics, which\n * is not a decision this package should be leaving to chance in either\n * direction.\n */\nexport const REVALIDATE = 'public, max-age=0, must-revalidate'\n\n/**\n * And what a page rendered for one request says.\n *\n * It may have read the visitor's cookies, and nothing in the headers - which\n * leave before the render has finished - can know whether it did. So a shared\n * cache may not keep it; the visitor's own browser may, and must ask again.\n */\nexport const PER_REQUEST = 'private, max-age=0, must-revalidate'\n"]}
package/dist/host.js CHANGED
@@ -66,6 +66,7 @@ export { redirect } from "./redirect.js";
66
66
  export { matchIntercept, matchRoute, sharedDepth } from "./routing.js";
67
67
  import { FLIGHT_TYPE, HEADER, HTML_TYPE, PER_CLIENT, PER_REQUEST, REVALIDATE, VARY_ON_RSC, } from "./headers.js";
68
68
  import { ServerAuthenticationError, ServerAuthorizationError, } from "./js/errors.js";
69
+ import { changes } from "./changed.js";
69
70
  /**
70
71
  * The answer to a redirect that was decided before anything was written.
71
72
  *
@@ -186,12 +187,15 @@ function refusalStatus(error) {
186
187
  return 401;
187
188
  if (name === "ServerAuthorizationError")
188
189
  return 403;
189
- // A status the host chose — a throttle's 429, a policy's 403 — carried on
190
- // the error by the transport. Bounded to refusals: a host answering 500
191
- // should not be able to make this look like a client's fault, and one
192
- // answering 200 should not turn a failed render into a success.
190
+ // A status the host chose — a throttle's 429, a policy's 403, a 503 while
191
+ // a dependency is down or the app is in maintenance — carried on the error
192
+ // by the transport. Only a deliberate refusal carries one (Go's Refuse,
193
+ // Laravel's abort); a crash never does, so a 5xx here was meant, and
194
+ // collapsing a 503 to a 500 tells a client to give up rather than come
195
+ // back. Bounded to errors: a host answering 200 or 3xx should not turn a
196
+ // failed render into a success or a redirect with no Location.
193
197
  const carried = error?.refusalStatus;
194
- if (typeof carried === "number" && carried >= 400 && carried <= 499)
198
+ if (typeof carried === "number" && carried >= 400 && carried <= 599)
195
199
  return carried;
196
200
  return null;
197
201
  }
@@ -721,6 +725,12 @@ export function createRscHandler(options) {
721
725
  }
722
726
  return await handleQuery(request, url);
723
727
  }
728
+ // A tab waiting to hear that a name its page refreshes on has changed.
729
+ // Signed names are its own authorization: the render that handed them
730
+ // out ran under the page's guards.
731
+ if (request.method === "GET" && url.pathname === HEADER.changesPath) {
732
+ return await changes(request);
733
+ }
724
734
  // The two halves an edge cache needs: hand it a shell it may keep, and
725
735
  // finish that shell for a visitor it cannot answer for itself.
726
736
  if (options.prerendered && url.pathname === HEADER.pprShellPath) {