@alxia/react-router 0.17.0 → 0.19.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.
Files changed (46) hide show
  1. package/README.md +45 -1
  2. package/dist/chunks/index-3jfeew2y.js.map +1 -1
  3. package/dist/chunks/index-6jf7zpxz.js.map +1 -1
  4. package/dist/chunks/index-9xv2a8et.js.map +1 -1
  5. package/dist/chunks/{index-c3k47yw7.js → index-a45b1582.js} +7 -6
  6. package/dist/chunks/{index-c3k47yw7.js.map → index-a45b1582.js.map} +3 -3
  7. package/dist/chunks/index-kfekhvgr.js.map +1 -1
  8. package/dist/chunks/index-mscfme4r.js +12 -0
  9. package/dist/chunks/index-mscfme4r.js.map +10 -0
  10. package/dist/cli/index.js.map +1 -1
  11. package/dist/entry/index.js.map +1 -1
  12. package/dist/errors/cross-site.d.ts +8 -0
  13. package/dist/errors/cross-site.d.ts.map +1 -0
  14. package/dist/errors/index.js +1 -1
  15. package/dist/errors/index.js.map +1 -1
  16. package/dist/errors/same-site.d.ts.map +1 -1
  17. package/dist/index.js.map +1 -1
  18. package/dist/pwa/index.js.map +1 -1
  19. package/dist/pwa/worker/index.js.map +1 -1
  20. package/dist/session/index.js +1 -1
  21. package/dist/session/index.js.map +1 -1
  22. package/dist/session/react/index.js +17 -6
  23. package/dist/session/react/index.js.map +3 -3
  24. package/dist/session/react/use-link-param.d.ts +12 -2
  25. package/dist/session/react/use-link-param.d.ts.map +1 -1
  26. package/dist/subscription/documents.d.ts +3 -0
  27. package/dist/subscription/documents.d.ts.map +1 -0
  28. package/dist/subscription/index.d.ts +7 -0
  29. package/dist/subscription/index.d.ts.map +1 -0
  30. package/dist/subscription/index.js +360 -0
  31. package/dist/subscription/index.js.map +14 -0
  32. package/dist/subscription/proxy.d.ts +40 -0
  33. package/dist/subscription/proxy.d.ts.map +1 -0
  34. package/dist/subscription/read.d.ts +17 -0
  35. package/dist/subscription/read.d.ts.map +1 -0
  36. package/dist/subscription/refusal.d.ts +11 -0
  37. package/dist/subscription/refusal.d.ts.map +1 -0
  38. package/dist/subscription/relay.d.ts +16 -0
  39. package/dist/subscription/relay.d.ts.map +1 -0
  40. package/dist/vite/index.js.map +1 -1
  41. package/docs/README.md +2 -1
  42. package/docs/guide/session.md +18 -1
  43. package/docs/guide/subscriptions.md +126 -0
  44. package/docs/roadmap.md +10 -2
  45. package/docs/troubleshooting.md +109 -0
  46. package/package.json +9 -3
@@ -0,0 +1,14 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/subscription/documents.ts", "../src/subscription/refusal.ts", "../src/subscription/read.ts", "../src/subscription/relay.ts", "../src/subscription/proxy.ts"],
4
+ "sourcesContent": [
5
+ "/**\n * Checks, when the proxy is created, that each document the server holds\n * defines `subscription <key>` and nothing else. The documents are the app's\n * own text, never a client's, so a plain scan is enough to catch a mistake (a\n * mutation listed, a name that does not match its key); it is not a parser and\n * guards nothing against hostile input.\n */\nfunction stripped(document: string): string {\n\treturn document\n\t\t.replace(/\"\"\"[\\s\\S]*?\"\"\"/g, ' ')\n\t\t.replace(/\"(?:\\\\.|[^\"\\\\\\n])*\"/g, ' ')\n\t\t.replace(/#[^\\n\\r]*/g, ' ');\n}\n\n/** The top-level definitions of `document`: `[keyword, name]`, `{` for a shorthand query. */\nfunction definitions(document: string): Array<[string, string | undefined]> {\n\tconst found: Array<[string, string | undefined]> = [];\n\tlet depth = 0;\n\tlet open: string | undefined;\n\tlet skipping = false;\n\tfor (const m of stripped(document).matchAll(/[{}()]|[A-Za-z_]\\w*/g)) {\n\t\tconst t = m[0];\n\t\tif (t === '(') depth++;\n\t\telse if (t === ')') depth--;\n\t\telse if (t === '{') {\n\t\t\tif (depth === 0 && !skipping) {\n\t\t\t\tif (open !== undefined) {\n\t\t\t\t\tfound.push([open, undefined]);\n\t\t\t\t\topen = undefined;\n\t\t\t\t} else found.push(['{', undefined]);\n\t\t\t}\n\t\t\tif (depth === 0) skipping = false;\n\t\t\tdepth++;\n\t\t} else if (t === '}') depth--;\n\t\telse if (depth === 0) {\n\t\t\tif (open !== undefined && !skipping) {\n\t\t\t\tfound.push([open, t]);\n\t\t\t\topen = undefined;\n\t\t\t\tskipping = true;\n\t\t\t} else if (t === 'fragment') skipping = true;\n\t\t\telse if (t === 'query' || t === 'mutation' || t === 'subscription')\n\t\t\t\topen = t;\n\t\t}\n\t}\n\treturn found;\n}\n\n/** Throws a worded `TypeError` for a document that is not exactly `subscription <name>`. */\nexport function checkDocuments(allow: Readonly<Record<string, string>>): void {\n\tfor (const [name, document] of Object.entries(allow)) {\n\t\tconst operations = definitions(document).filter(\n\t\t\t([kind]) => kind !== 'fragment',\n\t\t);\n\t\tconst ok =\n\t\t\toperations.length === 1 &&\n\t\t\toperations[0]?.[0] === 'subscription' &&\n\t\t\toperations[0]?.[1] === name;\n\t\tif (!ok)\n\t\t\tthrow new TypeError(\n\t\t\t\t`createSubscriptionProxy(): allow[${JSON.stringify(name)}] must define exactly one operation, \\`subscription ${name}\\`; its document defines ${\n\t\t\t\t\toperations.length === 0\n\t\t\t\t\t\t? 'none'\n\t\t\t\t\t\t: operations.map(([k, n]) => `${k}${n ? ` ${n}` : ''}`).join(', ')\n\t\t\t\t}. Fragments are allowed.`,\n\t\t\t);\n\t}\n}\n",
6
+ "/** An answer the proxy gives itself, as GraphQL-shaped JSON a client can read. */\nexport class Refusal extends Error {\n\tconstructor(\n\t\treadonly status: number,\n\t\tmessage: string,\n\t\treadonly code: string,\n\t) {\n\t\tsuper(message);\n\t\tthis.name = 'Refusal';\n\t}\n}\n\nexport function problem(\n\tstatus: number,\n\tmessage: string,\n\tcode: string,\n\textra: Record<string, unknown> = {},\n\theaders: HeadersInit = {},\n): Response {\n\treturn new Response(\n\t\tJSON.stringify({\n\t\t\terrors: [{ message, extensions: { code, ...extra } }],\n\t\t\t...extra,\n\t\t}),\n\t\t{\n\t\t\tstatus,\n\t\t\theaders: {\n\t\t\t\t'content-type': 'application/json',\n\t\t\t\t'cache-control': 'no-store',\n\t\t\t\t...headers,\n\t\t\t},\n\t\t},\n\t);\n}\n\nexport const refusalResponse = (refusal: Refusal): Response =>\n\tproblem(refusal.status, refusal.message, refusal.code);\n\nfunction retryAfterOf(upstream: Response, body: unknown): number | undefined {\n\tconst header = Number(upstream.headers.get('retry-after'));\n\tif (Number.isFinite(header) && header > 0) return Math.ceil(header);\n\tconst seconds = (value: unknown): number | undefined =>\n\t\ttypeof value === 'number' && Number.isFinite(value) && value > 0\n\t\t\t? Math.ceil(value)\n\t\t\t: undefined;\n\tif (typeof body !== 'object' || body === null) return undefined;\n\tconst top = body as { retryAfter?: unknown; errors?: unknown };\n\tconst first = Array.isArray(top.errors)\n\t\t? (top.errors[0] as { extensions?: { retryAfter?: unknown } } | undefined)\n\t\t: undefined;\n\treturn seconds(top.retryAfter) ?? seconds(first?.extensions?.retryAfter);\n}\n\n/** What a non-2xx upstream answer becomes: a 429 with `retryAfter`, a 502 for a 5xx, any other 4xx as it came. */\nexport async function refusedUpstream(upstream: Response): Promise<Response> {\n\tconst text = await upstream.text().catch(() => '');\n\tif (upstream.status === 429) {\n\t\tlet body: unknown;\n\t\ttry {\n\t\t\tbody = JSON.parse(text);\n\t\t} catch {}\n\t\tconst retryAfter = retryAfterOf(upstream, body);\n\t\treturn problem(\n\t\t\t429,\n\t\t\t'Too many requests.',\n\t\t\t'RATE_LIMITED',\n\t\t\tretryAfter === undefined ? {} : { retryAfter },\n\t\t\tretryAfter === undefined ? {} : { 'retry-after': String(retryAfter) },\n\t\t);\n\t}\n\tif (upstream.status >= 500)\n\t\treturn problem(502, 'The API is unavailable.', 'UPSTREAM_ERROR');\n\treturn new Response(text, {\n\t\tstatus: upstream.status,\n\t\theaders: {\n\t\t\t'content-type':\n\t\t\t\tupstream.headers.get('content-type') ?? 'application/json',\n\t\t\t'cache-control': 'no-store',\n\t\t},\n\t});\n}\n",
7
+ "import { Refusal } from './refusal';\n\n/** The most a body, a query string or the variables may weigh, in bytes. */\nexport const LIMITS = {\n\tbody: 64 * 1024,\n\tqueryString: 16 * 1024,\n\tvariables: 16 * 1024,\n} as const;\n\nexport interface Asked {\n\treadonly operationName: string;\n\treadonly variables?: Record<string, unknown>;\n}\n\nconst TOO_LARGE = () =>\n\tnew Refusal(400, 'The request is too large.', 'BAD_REQUEST');\nconst NOT_JSON = () =>\n\tnew Refusal(400, 'The request is not valid JSON.', 'BAD_REQUEST');\n\nfunction record(value: unknown): Record<string, unknown> | undefined {\n\treturn typeof value === 'object' && value !== null && !Array.isArray(value)\n\t\t? (value as Record<string, unknown>)\n\t\t: undefined;\n}\n\n/** The body as text, refused past `limit` bytes: `content-length` first, then a cap on what is read. */\nasync function textOf(request: Request, limit: number): Promise<string> {\n\tconst declared = Number(request.headers.get('content-length'));\n\tif (Number.isFinite(declared) && declared > limit) throw TOO_LARGE();\n\tif (request.body === null) return '';\n\tconst reader = request.body.getReader();\n\tconst chunks: Uint8Array[] = [];\n\tlet size = 0;\n\tfor (;;) {\n\t\tconst { done, value } = await reader.read();\n\t\tif (done) break;\n\t\tsize += value.byteLength;\n\t\tif (size > limit) {\n\t\t\tvoid reader.cancel().catch(() => {});\n\t\t\tthrow TOO_LARGE();\n\t\t}\n\t\tchunks.push(value);\n\t}\n\treturn new TextDecoder().decode(Buffer.concat(chunks));\n}\n\nfunction parse(text: string): unknown {\n\ttry {\n\t\treturn JSON.parse(text);\n\t} catch {\n\t\tthrow NOT_JSON();\n\t}\n}\n\n/**\n * What a client asks for: an `operationName` and its `variables`, from a\n * GET's search params or a POST's JSON body. Any `query` or `extensions` it\n * sends (graphql-sse always sends a `query`) is ignored.\n */\nexport async function readAsked(request: Request): Promise<Asked> {\n\tlet raw: Record<string, unknown> | undefined;\n\tif (request.method === 'GET') {\n\t\tconst url = new URL(request.url);\n\t\tif (url.search.length > LIMITS.queryString) throw TOO_LARGE();\n\t\tconst variables = url.searchParams.get('variables');\n\t\traw = {\n\t\t\toperationName: url.searchParams.get('operationName') ?? undefined,\n\t\t\tvariables: variables ? parse(variables) : undefined,\n\t\t};\n\t} else {\n\t\tconst type = (request.headers.get('content-type') ?? '')\n\t\t\t.split(';')[0]\n\t\t\t?.trim()\n\t\t\t.toLowerCase();\n\t\tif (type !== 'application/json')\n\t\t\tthrow new Refusal(\n\t\t\t\t415,\n\t\t\t\t'Send the request as application/json.',\n\t\t\t\t'UNSUPPORTED_MEDIA_TYPE',\n\t\t\t);\n\t\traw = record(parse(await textOf(request, LIMITS.body)));\n\t\tif (raw === undefined)\n\t\t\tthrow new Refusal(\n\t\t\t\t400,\n\t\t\t\t'The request must be a JSON object.',\n\t\t\t\t'BAD_REQUEST',\n\t\t\t);\n\t}\n\tconst { operationName, variables } = raw;\n\tif (operationName === undefined)\n\t\tthrow new Refusal(400, 'Send an \"operationName\".', 'BAD_REQUEST');\n\tif (typeof operationName !== 'string')\n\t\tthrow new Refusal(400, '\"operationName\" must be a string.', 'BAD_REQUEST');\n\tif (variables !== undefined) {\n\t\tif (record(variables) === undefined)\n\t\t\tthrow new Refusal(400, '\"variables\" must be an object.', 'BAD_REQUEST');\n\t\tif (JSON.stringify(variables).length > LIMITS.variables) throw TOO_LARGE();\n\t}\n\treturn {\n\t\toperationName,\n\t\t...(variables === undefined\n\t\t\t? {}\n\t\t\t: { variables: variables as Record<string, unknown> }),\n\t};\n}\n",
8
+ "/** The most one event may weigh before the stream is cut, in characters. */\nexport const MAX_EVENT = 1024 * 1024;\n\nconst encoder = new TextEncoder();\nconst decoder = new TextDecoder();\n\nexport const SSE_HEADERS = {\n\t'content-type': 'text/event-stream; charset=utf-8',\n\t'cache-control': 'no-store, no-transform',\n\t'x-accel-buffering': 'no',\n};\n\nconst FAILED =\n\t'event: next\\ndata: {\"errors\":[{\"message\":\"The API stream failed.\",\"extensions\":{\"code\":\"UPSTREAM_ERROR\"}}]}\\n\\nevent: complete\\ndata:\\n\\n';\n\n/**\n * Relays whole events (a heartbeat never lands inside one) until the upstream\n * ends or the client leaves. The stream is pulled: upstream is read only when\n * the client has taken what was queued, so a slow client holds the upstream\n * back instead of growing a buffer, and a heartbeat is skipped while one is\n * waiting.\n */\nexport function relay(\n\tupstream: Response,\n\tabort: AbortController,\n\theartbeatMs: number,\n): Response {\n\tconst reader = (upstream.body as ReadableStream<Uint8Array>).getReader();\n\tlet timer: ReturnType<typeof setInterval> | undefined;\n\tlet buffer = '';\n\tconst stop = (): void => {\n\t\tif (timer !== undefined) clearInterval(timer);\n\t\ttimer = undefined;\n\t};\n\tconst stream = new ReadableStream<Uint8Array>(\n\t\t{\n\t\t\tstart(controller) {\n\t\t\t\tif (heartbeatMs > 0)\n\t\t\t\t\ttimer = setInterval(() => {\n\t\t\t\t\t\tif ((controller.desiredSize ?? 0) > 0)\n\t\t\t\t\t\t\tcontroller.enqueue(encoder.encode(':\\n\\n'));\n\t\t\t\t\t}, heartbeatMs);\n\t\t\t},\n\t\t\tasync pull(controller) {\n\t\t\t\ttry {\n\t\t\t\t\tfor (;;) {\n\t\t\t\t\t\tconst { done, value } = await reader.read();\n\t\t\t\t\t\tif (done) {\n\t\t\t\t\t\t\tstop();\n\t\t\t\t\t\t\tif (buffer.trim() !== '')\n\t\t\t\t\t\t\t\tcontroller.enqueue(encoder.encode(`${buffer}\\n\\n`));\n\t\t\t\t\t\t\tcontroller.close();\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbuffer += decoder\n\t\t\t\t\t\t\t.decode(value, { stream: true })\n\t\t\t\t\t\t\t.replace(/\\r\\n?/g, '\\n');\n\t\t\t\t\t\tconst cut = buffer.lastIndexOf('\\n\\n');\n\t\t\t\t\t\tif (cut !== -1) {\n\t\t\t\t\t\t\tcontroller.enqueue(encoder.encode(buffer.slice(0, cut + 2)));\n\t\t\t\t\t\t\tbuffer = buffer.slice(cut + 2);\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (buffer.length > MAX_EVENT) throw new Error('event too large');\n\t\t\t\t\t}\n\t\t\t\t} catch {\n\t\t\t\t\tstop();\n\t\t\t\t\tif (abort.signal.aborted) return;\n\t\t\t\t\tabort.abort();\n\t\t\t\t\tcontroller.enqueue(encoder.encode(FAILED));\n\t\t\t\t\tcontroller.close();\n\t\t\t\t}\n\t\t\t},\n\t\t\tcancel() {\n\t\t\t\tstop();\n\t\t\t\tabort.abort();\n\t\t\t\tvoid reader.cancel().catch(() => {});\n\t\t\t},\n\t\t},\n\t\t{ highWaterMark: 1 },\n\t);\n\treturn new Response(stream, { status: 200, headers: SSE_HEADERS });\n}\n",
9
+ "import { isCrossSite } from '../errors/cross-site';\nimport { checkDocuments } from './documents';\nimport { readAsked } from './read';\nimport { problem, Refusal, refusalResponse, refusedUpstream } from './refusal';\nimport { relay } from './relay';\n\ntype HeaderValues = Record<string, string | null | undefined> | Headers;\n\nexport interface SubscriptionProxyOptions {\n\t/** The API's GraphQL endpoint, which serves subscriptions over SSE. */\n\treadonly endpoint: string | URL;\n\t/**\n\t * The operations the browser may start: each name with the document the\n\t * proxy sends upstream for it. The client names an operation and sends\n\t * variables; its own `query` and `extensions` are ignored, so nothing it\n\t * writes reaches the API. A name that is not a key is a 403.\n\t */\n\treadonly allow: Readonly<Record<string, string>>;\n\t/** The session's token, from the request: `(request) => cookies.token(request)`. Empty is a 401. */\n\treadonly getToken: (\n\t\trequest: Request,\n\t) => string | null | undefined | Promise<string | null | undefined>;\n\t/** Extra upstream headers (client name, proxy secret, `X-Forwarded-For`, `Accept-Language`), fixed or built per request. A `null` or `undefined` value is left out. */\n\treadonly headers?:\n\t\t| HeaderValues\n\t\t| ((request: Request) => HeaderValues | Promise<HeaderValues>);\n\t/** The app's own origin for the cross-site check, as `jsonActions` takes it; the request's own by default. */\n\treadonly origin?: string | (() => string | undefined);\n\t/** A comment line sent this often so a proxy or Bun's `idleTimeout` keeps the stream open. 15000 by default; `0` turns it off. */\n\treadonly heartbeatMs?: number;\n\t/** The `fetch` used upstream. The global one by default. */\n\treadonly fetch?: (request: Request) => Promise<Response>;\n}\n\nexport interface SubscriptionProxy {\n\t/** A GET: graphql-sse's distinct connections mode, the operation in the search params. */\n\tloader(args: { request: Request }): Promise<Response>;\n\t/** A POST: the operation in a JSON body. */\n\taction(args: { request: Request }): Promise<Response>;\n}\n\ninterface Config {\n\treadonly endpoint: URL;\n\treadonly documents: ReadonlyMap<string, string>;\n\treadonly options: SubscriptionProxyOptions;\n\treadonly origin: () => string | undefined;\n\treadonly heartbeatMs: number;\n\treadonly upstreamFetch: (request: Request) => Promise<Response>;\n}\n\nconst UNSAFE = /[\\r\\n\\0]/;\n\nasync function upstreamHeaders(\n\tconfig: Config,\n\trequest: Request,\n\ttoken: string,\n): Promise<Headers> {\n\tconst { headers } = config.options;\n\tconst extra =\n\t\ttypeof headers === 'function' ? await headers(request) : headers;\n\tconst out = new Headers();\n\tfor (const [name, value] of extra instanceof Headers\n\t\t? extra.entries()\n\t\t: Object.entries(extra ?? {}))\n\t\tif (value !== null && value !== undefined) out.set(name, value);\n\tout.set('content-type', 'application/json');\n\tout.set('accept', 'text/event-stream');\n\tout.set('authorization', `Bearer ${token}`);\n\treturn out;\n}\n\nasync function handle(config: Config, request: Request): Promise<Response> {\n\tif (isCrossSite(request, config.origin()))\n\t\treturn problem(403, 'Cross-site request refused.', 'FORBIDDEN');\n\tconst token = await config.options.getToken(request);\n\tif (!token || UNSAFE.test(token))\n\t\treturn problem(401, 'Sign in to continue.', 'UNAUTHENTICATED');\n\n\tlet asked: Awaited<ReturnType<typeof readAsked>>;\n\ttry {\n\t\tasked = await readAsked(request);\n\t} catch (error) {\n\t\tif (error instanceof Refusal) return refusalResponse(error);\n\t\treturn problem(400, 'The request body could not be read.', 'BAD_REQUEST');\n\t}\n\tconst query = config.documents.get(asked.operationName);\n\tif (query === undefined)\n\t\treturn problem(403, 'This operation is not allowed.', 'FORBIDDEN');\n\n\tlet headers: Headers;\n\ttry {\n\t\theaders = await upstreamHeaders(config, request, token);\n\t} catch {\n\t\treturn problem(\n\t\t\t500,\n\t\t\t\"The proxy's upstream headers are not valid (a name or a value no header can hold).\",\n\t\t\t'PROXY_MISCONFIGURED',\n\t\t);\n\t}\n\n\tconst abort = new AbortController();\n\tif (request.signal.aborted) abort.abort();\n\telse\n\t\trequest.signal.addEventListener('abort', () => abort.abort(), {\n\t\t\tonce: true,\n\t\t});\n\tlet upstream: Response;\n\ttry {\n\t\tupstream = await config.upstreamFetch(\n\t\t\tnew Request(config.endpoint, {\n\t\t\t\tmethod: 'POST',\n\t\t\t\theaders,\n\t\t\t\tbody: JSON.stringify({\n\t\t\t\t\tquery,\n\t\t\t\t\toperationName: asked.operationName,\n\t\t\t\t\t...(asked.variables === undefined\n\t\t\t\t\t\t? {}\n\t\t\t\t\t\t: { variables: asked.variables }),\n\t\t\t\t}),\n\t\t\t\tsignal: abort.signal,\n\t\t\t}),\n\t\t);\n\t} catch {\n\t\treturn problem(502, 'The API is unreachable.', 'UPSTREAM_ERROR');\n\t}\n\tconst streaming =\n\t\tupstream.ok &&\n\t\tupstream.body !== null &&\n\t\t(upstream.headers.get('content-type') ?? '').startsWith(\n\t\t\t'text/event-stream',\n\t\t);\n\tif (streaming) return relay(upstream, abort, config.heartbeatMs);\n\tif (upstream.ok) {\n\t\tabort.abort();\n\t\treturn problem(\n\t\t\t502,\n\t\t\t'The API did not answer with an event stream.',\n\t\t\t'UPSTREAM_ERROR',\n\t\t);\n\t}\n\tconst refused = await refusedUpstream(upstream);\n\tabort.abort();\n\treturn refused;\n}\n\nfunction only(\n\tmethod: string,\n\trun: (request: Request) => Promise<Response>,\n): (args: { request: Request }) => Promise<Response> {\n\treturn async ({ request }) =>\n\t\trequest.method === method\n\t\t\t? run(request)\n\t\t\t: problem(\n\t\t\t\t\t405,\n\t\t\t\t\t`Use ${method}.`,\n\t\t\t\t\t'METHOD_NOT_ALLOWED',\n\t\t\t\t\t{},\n\t\t\t\t\t{ allow: method },\n\t\t\t\t);\n}\n\n/**\n * A resource route that exposes GraphQL subscriptions to the browser without\n * giving it the API's token or a way to write its own document. See the\n * subscription guide.\n */\nexport function createSubscriptionProxy(\n\toptions: SubscriptionProxyOptions,\n): SubscriptionProxy {\n\tcheckDocuments(options.allow);\n\tconst config: Config = {\n\t\tendpoint: new URL(options.endpoint),\n\t\tdocuments: new Map(Object.entries(options.allow)),\n\t\toptions,\n\t\torigin: () =>\n\t\t\ttypeof options.origin === 'function' ? options.origin() : options.origin,\n\t\theartbeatMs: options.heartbeatMs ?? 15000,\n\t\tupstreamFetch: options.fetch ?? ((request) => fetch(request)),\n\t};\n\treturn {\n\t\tloader: only('GET', (request) => handle(config, request)),\n\t\taction: only('POST', (request) => handle(config, request)),\n\t};\n}\n"
10
+ ],
11
+ "mappings": ";;;;;AAOA,SAAS,QAAQ,CAAC,UAA0B;AAAA,EAC3C,OAAO,SACL,QAAQ,mBAAmB,GAAG,EAC9B,QAAQ,wBAAwB,GAAG,EACnC,QAAQ,cAAc,GAAG;AAAA;AAI5B,SAAS,WAAW,CAAC,UAAuD;AAAA,EAC3E,MAAM,QAA6C,CAAC;AAAA,EACpD,IAAI,QAAQ;AAAA,EACZ,IAAI;AAAA,EACJ,IAAI,WAAW;AAAA,EACf,WAAW,KAAK,SAAS,QAAQ,EAAE,SAAS,sBAAsB,GAAG;AAAA,IACpE,MAAM,IAAI,EAAE;AAAA,IACZ,IAAI,MAAM;AAAA,MAAK;AAAA,IACf,KAAK,IAAI,MAAM;AAAA,MAAK;AAAA,IACpB,KAAK,IAAI,MAAM,KAAK;AAAA,MACnB,IAAI,UAAU,KAAK,CAAC,UAAU;AAAA,QAC7B,IAAI,SAAS,WAAW;AAAA,UACvB,MAAM,KAAK,CAAC,MAAM,SAAS,CAAC;AAAA,UAC5B,OAAO;AAAA,QACR,EAAE;AAAA,UAAK,MAAM,KAAK,CAAC,KAAK,SAAS,CAAC;AAAA,MACnC;AAAA,MACA,IAAI,UAAU;AAAA,QAAG,WAAW;AAAA,MAC5B;AAAA,IACD,EAAE,KAAK,IAAI,MAAM;AAAA,MAAK;AAAA,IACtB,KAAK,IAAI,UAAU,GAAG;AAAA,MACrB,IAAI,SAAS,aAAa,CAAC,UAAU;AAAA,QACpC,MAAM,KAAK,CAAC,MAAM,CAAC,CAAC;AAAA,QACpB,OAAO;AAAA,QACP,WAAW;AAAA,MACZ,EAAE,KAAK,IAAI,MAAM;AAAA,QAAY,WAAW;AAAA,MACxC,KAAK,IAAI,MAAM,WAAW,MAAM,cAAc,MAAM;AAAA,QACnD,OAAO;AAAA,IACT;AAAA,EACD;AAAA,EACA,OAAO;AAAA;AAID,SAAS,cAAc,CAAC,OAA+C;AAAA,EAC7E,YAAY,MAAM,aAAa,OAAO,QAAQ,KAAK,GAAG;AAAA,IACrD,MAAM,aAAa,YAAY,QAAQ,EAAE,OACxC,EAAE,UAAU,SAAS,UACtB;AAAA,IACA,MAAM,KACL,WAAW,WAAW,KACtB,WAAW,KAAK,OAAO,kBACvB,WAAW,KAAK,OAAO;AAAA,IACxB,IAAI,CAAC;AAAA,MACJ,MAAM,IAAI,UACT,oCAAoC,KAAK,UAAU,IAAI,wDAAwD,gCAC9G,WAAW,WAAW,IACnB,SACA,WAAW,IAAI,EAAE,GAAG,OAAO,GAAG,IAAI,IAAI,IAAI,MAAM,IAAI,EAAE,KAAK,IAAI,2BAEpE;AAAA,EACF;AAAA;;;AChEM,MAAM,gBAAgB,MAAM;AAAA,EAExB;AAAA,EAEA;AAAA,EAHV,WAAW,CACD,QACT,SACS,MACR;AAAA,IACD,MAAM,OAAO;AAAA,IAJJ;AAAA,IAEA;AAAA,IAGT,KAAK,OAAO;AAAA;AAEd;AAEO,SAAS,OAAO,CACtB,QACA,SACA,MACA,QAAiC,CAAC,GAClC,UAAuB,CAAC,GACb;AAAA,EACX,OAAO,IAAI,SACV,KAAK,UAAU;AAAA,IACd,QAAQ,CAAC,EAAE,SAAS,YAAY,EAAE,SAAS,MAAM,EAAE,CAAC;AAAA,OACjD;AAAA,EACJ,CAAC,GACD;AAAA,IACC;AAAA,IACA,SAAS;AAAA,MACR,gBAAgB;AAAA,MAChB,iBAAiB;AAAA,SACd;AAAA,IACJ;AAAA,EACD,CACD;AAAA;AAGM,IAAM,kBAAkB,CAAC,YAC/B,QAAQ,QAAQ,QAAQ,QAAQ,SAAS,QAAQ,IAAI;AAEtD,SAAS,YAAY,CAAC,UAAoB,MAAmC;AAAA,EAC5E,MAAM,SAAS,OAAO,SAAS,QAAQ,IAAI,aAAa,CAAC;AAAA,EACzD,IAAI,OAAO,SAAS,MAAM,KAAK,SAAS;AAAA,IAAG,OAAO,KAAK,KAAK,MAAM;AAAA,EAClE,MAAM,UAAU,CAAC,UAChB,OAAO,UAAU,YAAY,OAAO,SAAS,KAAK,KAAK,QAAQ,IAC5D,KAAK,KAAK,KAAK,IACf;AAAA,EACJ,IAAI,OAAO,SAAS,YAAY,SAAS;AAAA,IAAM;AAAA,EAC/C,MAAM,MAAM;AAAA,EACZ,MAAM,QAAQ,MAAM,QAAQ,IAAI,MAAM,IAClC,IAAI,OAAO,KACZ;AAAA,EACH,OAAO,QAAQ,IAAI,UAAU,KAAK,QAAQ,OAAO,YAAY,UAAU;AAAA;AAIjE,eAAe,eAAe,CAAC,UAAuC;AAAA,EAC5E,MAAM,OAAO,MAAM,SAAS,KAAK,EAAE,MAAM,MAAM,EAAE;AAAA,EACjD,IAAI,SAAS,WAAW,KAAK;AAAA,IAC5B,IAAI;AAAA,IACJ,IAAI;AAAA,MACH,OAAO,KAAK,MAAM,IAAI;AAAA,MACrB,MAAM;AAAA,IACR,MAAM,aAAa,aAAa,UAAU,IAAI;AAAA,IAC9C,OAAO,QACN,KACA,sBACA,gBACA,eAAe,YAAY,CAAC,IAAI,EAAE,WAAW,GAC7C,eAAe,YAAY,CAAC,IAAI,EAAE,eAAe,OAAO,UAAU,EAAE,CACrE;AAAA,EACD;AAAA,EACA,IAAI,SAAS,UAAU;AAAA,IACtB,OAAO,QAAQ,KAAK,2BAA2B,gBAAgB;AAAA,EAChE,OAAO,IAAI,SAAS,MAAM;AAAA,IACzB,QAAQ,SAAS;AAAA,IACjB,SAAS;AAAA,MACR,gBACC,SAAS,QAAQ,IAAI,cAAc,KAAK;AAAA,MACzC,iBAAiB;AAAA,IAClB;AAAA,EACD,CAAC;AAAA;;;AC5EK,IAAM,SAAS;AAAA,EACrB,MAAM,KAAK;AAAA,EACX,aAAa,KAAK;AAAA,EAClB,WAAW,KAAK;AACjB;AAOA,IAAM,YAAY,MACjB,IAAI,QAAQ,KAAK,6BAA6B,aAAa;AAC5D,IAAM,WAAW,MAChB,IAAI,QAAQ,KAAK,kCAAkC,aAAa;AAEjE,SAAS,MAAM,CAAC,OAAqD;AAAA,EACpE,OAAO,OAAO,UAAU,YAAY,UAAU,QAAQ,CAAC,MAAM,QAAQ,KAAK,IACtE,QACD;AAAA;AAIJ,eAAe,MAAM,CAAC,SAAkB,OAAgC;AAAA,EACvE,MAAM,WAAW,OAAO,QAAQ,QAAQ,IAAI,gBAAgB,CAAC;AAAA,EAC7D,IAAI,OAAO,SAAS,QAAQ,KAAK,WAAW;AAAA,IAAO,MAAM,UAAU;AAAA,EACnE,IAAI,QAAQ,SAAS;AAAA,IAAM,OAAO;AAAA,EAClC,MAAM,SAAS,QAAQ,KAAK,UAAU;AAAA,EACtC,MAAM,SAAuB,CAAC;AAAA,EAC9B,IAAI,OAAO;AAAA,EACX,UAAS;AAAA,IACR,QAAQ,MAAM,UAAU,MAAM,OAAO,KAAK;AAAA,IAC1C,IAAI;AAAA,MAAM;AAAA,IACV,QAAQ,MAAM;AAAA,IACd,IAAI,OAAO,OAAO;AAAA,MACZ,OAAO,OAAO,EAAE,MAAM,MAAM,EAAE;AAAA,MACnC,MAAM,UAAU;AAAA,IACjB;AAAA,IACA,OAAO,KAAK,KAAK;AAAA,EAClB;AAAA,EACA,OAAO,IAAI,YAAY,EAAE,OAAO,OAAO,OAAO,MAAM,CAAC;AAAA;AAGtD,SAAS,KAAK,CAAC,MAAuB;AAAA,EACrC,IAAI;AAAA,IACH,OAAO,KAAK,MAAM,IAAI;AAAA,IACrB,MAAM;AAAA,IACP,MAAM,SAAS;AAAA;AAAA;AASV,eAAe,SAAS,CAAC,SAAkC;AAAA,EACjE,IAAI;AAAA,EACJ,IAAI,QAAQ,WAAW,OAAO;AAAA,IAC7B,MAAM,MAAM,IAAI,IAAI,QAAQ,GAAG;AAAA,IAC/B,IAAI,IAAI,OAAO,SAAS,OAAO;AAAA,MAAa,MAAM,UAAU;AAAA,IAC5D,MAAM,YAAY,IAAI,aAAa,IAAI,WAAW;AAAA,IAClD,MAAM;AAAA,MACL,eAAe,IAAI,aAAa,IAAI,eAAe,KAAK;AAAA,MACxD,WAAW,YAAY,MAAM,SAAS,IAAI;AAAA,IAC3C;AAAA,EACD,EAAE,KAAK;AAAA,IACN,MAAM,QAAQ,QAAQ,QAAQ,IAAI,cAAc,KAAK,IACnD,MAAM,GAAG,EAAE,IACV,KAAK,EACN,YAAY;AAAA,IACd,IAAI,SAAS;AAAA,MACZ,MAAM,IAAI,QACT,KACA,yCACA,wBACD;AAAA,IACD,MAAM,OAAO,MAAM,MAAM,OAAO,SAAS,OAAO,IAAI,CAAC,CAAC;AAAA,IACtD,IAAI,QAAQ;AAAA,MACX,MAAM,IAAI,QACT,KACA,sCACA,aACD;AAAA;AAAA,EAEF,QAAQ,eAAe,cAAc;AAAA,EACrC,IAAI,kBAAkB;AAAA,IACrB,MAAM,IAAI,QAAQ,KAAK,4BAA4B,aAAa;AAAA,EACjE,IAAI,OAAO,kBAAkB;AAAA,IAC5B,MAAM,IAAI,QAAQ,KAAK,qCAAqC,aAAa;AAAA,EAC1E,IAAI,cAAc,WAAW;AAAA,IAC5B,IAAI,OAAO,SAAS,MAAM;AAAA,MACzB,MAAM,IAAI,QAAQ,KAAK,kCAAkC,aAAa;AAAA,IACvE,IAAI,KAAK,UAAU,SAAS,EAAE,SAAS,OAAO;AAAA,MAAW,MAAM,UAAU;AAAA,EAC1E;AAAA,EACA,OAAO;AAAA,IACN;AAAA,OACI,cAAc,YACf,CAAC,IACD,EAAE,UAAgD;AAAA,EACtD;AAAA;;;ACtGM,IAAM,YAAY,OAAO;AAEhC,IAAM,UAAU,IAAI;AACpB,IAAM,UAAU,IAAI;AAEb,IAAM,cAAc;AAAA,EAC1B,gBAAgB;AAAA,EAChB,iBAAiB;AAAA,EACjB,qBAAqB;AACtB;AAEA,IAAM,SACL;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AASM,SAAS,KAAK,CACpB,UACA,OACA,aACW;AAAA,EACX,MAAM,SAAU,SAAS,KAAoC,UAAU;AAAA,EACvE,IAAI;AAAA,EACJ,IAAI,SAAS;AAAA,EACb,MAAM,OAAO,MAAY;AAAA,IACxB,IAAI,UAAU;AAAA,MAAW,cAAc,KAAK;AAAA,IAC5C,QAAQ;AAAA;AAAA,EAET,MAAM,SAAS,IAAI,eAClB;AAAA,IACC,KAAK,CAAC,YAAY;AAAA,MACjB,IAAI,cAAc;AAAA,QACjB,QAAQ,YAAY,MAAM;AAAA,UACzB,KAAK,WAAW,eAAe,KAAK;AAAA,YACnC,WAAW,QAAQ,QAAQ,OAAO;AAAA;AAAA,CAAO,CAAC;AAAA,WACzC,WAAW;AAAA;AAAA,UAEV,IAAI,CAAC,YAAY;AAAA,MACtB,IAAI;AAAA,QACH,UAAS;AAAA,UACR,QAAQ,MAAM,UAAU,MAAM,OAAO,KAAK;AAAA,UAC1C,IAAI,MAAM;AAAA,YACT,KAAK;AAAA,YACL,IAAI,OAAO,KAAK,MAAM;AAAA,cACrB,WAAW,QAAQ,QAAQ,OAAO,GAAG;AAAA;AAAA,CAAY,CAAC;AAAA,YACnD,WAAW,MAAM;AAAA,YACjB;AAAA,UACD;AAAA,UACA,UAAU,QACR,OAAO,OAAO,EAAE,QAAQ,KAAK,CAAC,EAC9B,QAAQ,UAAU;AAAA,CAAI;AAAA,UACxB,MAAM,MAAM,OAAO,YAAY;AAAA;AAAA,CAAM;AAAA,UACrC,IAAI,QAAQ,IAAI;AAAA,YACf,WAAW,QAAQ,QAAQ,OAAO,OAAO,MAAM,GAAG,MAAM,CAAC,CAAC,CAAC;AAAA,YAC3D,SAAS,OAAO,MAAM,MAAM,CAAC;AAAA,YAC7B;AAAA,UACD;AAAA,UACA,IAAI,OAAO,SAAS;AAAA,YAAW,MAAM,IAAI,MAAM,iBAAiB;AAAA,QACjE;AAAA,QACC,MAAM;AAAA,QACP,KAAK;AAAA,QACL,IAAI,MAAM,OAAO;AAAA,UAAS;AAAA,QAC1B,MAAM,MAAM;AAAA,QACZ,WAAW,QAAQ,QAAQ,OAAO,MAAM,CAAC;AAAA,QACzC,WAAW,MAAM;AAAA;AAAA;AAAA,IAGnB,MAAM,GAAG;AAAA,MACR,KAAK;AAAA,MACL,MAAM,MAAM;AAAA,MACP,OAAO,OAAO,EAAE,MAAM,MAAM,EAAE;AAAA;AAAA,EAErC,GACA,EAAE,eAAe,EAAE,CACpB;AAAA,EACA,OAAO,IAAI,SAAS,QAAQ,EAAE,QAAQ,KAAK,SAAS,YAAY,CAAC;AAAA;;;AC/BlE,IAAM,SAAS;AAEf,eAAe,eAAe,CAC7B,QACA,SACA,OACmB;AAAA,EACnB,QAAQ,YAAY,OAAO;AAAA,EAC3B,MAAM,QACL,OAAO,YAAY,aAAa,MAAM,QAAQ,OAAO,IAAI;AAAA,EAC1D,MAAM,MAAM,IAAI;AAAA,EAChB,YAAY,MAAM,UAAU,iBAAiB,UAC1C,MAAM,QAAQ,IACd,OAAO,QAAQ,SAAS,CAAC,CAAC;AAAA,IAC5B,IAAI,UAAU,QAAQ,UAAU;AAAA,MAAW,IAAI,IAAI,MAAM,KAAK;AAAA,EAC/D,IAAI,IAAI,gBAAgB,kBAAkB;AAAA,EAC1C,IAAI,IAAI,UAAU,mBAAmB;AAAA,EACrC,IAAI,IAAI,iBAAiB,UAAU,OAAO;AAAA,EAC1C,OAAO;AAAA;AAGR,eAAe,MAAM,CAAC,QAAgB,SAAqC;AAAA,EAC1E,IAAI,YAAY,SAAS,OAAO,OAAO,CAAC;AAAA,IACvC,OAAO,QAAQ,KAAK,+BAA+B,WAAW;AAAA,EAC/D,MAAM,QAAQ,MAAM,OAAO,QAAQ,SAAS,OAAO;AAAA,EACnD,IAAI,CAAC,SAAS,OAAO,KAAK,KAAK;AAAA,IAC9B,OAAO,QAAQ,KAAK,wBAAwB,iBAAiB;AAAA,EAE9D,IAAI;AAAA,EACJ,IAAI;AAAA,IACH,QAAQ,MAAM,UAAU,OAAO;AAAA,IAC9B,OAAO,OAAO;AAAA,IACf,IAAI,iBAAiB;AAAA,MAAS,OAAO,gBAAgB,KAAK;AAAA,IAC1D,OAAO,QAAQ,KAAK,uCAAuC,aAAa;AAAA;AAAA,EAEzE,MAAM,QAAQ,OAAO,UAAU,IAAI,MAAM,aAAa;AAAA,EACtD,IAAI,UAAU;AAAA,IACb,OAAO,QAAQ,KAAK,kCAAkC,WAAW;AAAA,EAElE,IAAI;AAAA,EACJ,IAAI;AAAA,IACH,UAAU,MAAM,gBAAgB,QAAQ,SAAS,KAAK;AAAA,IACrD,MAAM;AAAA,IACP,OAAO,QACN,KACA,sFACA,qBACD;AAAA;AAAA,EAGD,MAAM,QAAQ,IAAI;AAAA,EAClB,IAAI,QAAQ,OAAO;AAAA,IAAS,MAAM,MAAM;AAAA,EACxC;AAAA,IACC,QAAQ,OAAO,iBAAiB,SAAS,MAAM,MAAM,MAAM,GAAG;AAAA,MAC7D,MAAM;AAAA,IACP,CAAC;AAAA,EACF,IAAI;AAAA,EACJ,IAAI;AAAA,IACH,WAAW,MAAM,OAAO,cACvB,IAAI,QAAQ,OAAO,UAAU;AAAA,MAC5B,QAAQ;AAAA,MACR;AAAA,MACA,MAAM,KAAK,UAAU;AAAA,QACpB;AAAA,QACA,eAAe,MAAM;AAAA,WACjB,MAAM,cAAc,YACrB,CAAC,IACD,EAAE,WAAW,MAAM,UAAU;AAAA,MACjC,CAAC;AAAA,MACD,QAAQ,MAAM;AAAA,IACf,CAAC,CACF;AAAA,IACC,MAAM;AAAA,IACP,OAAO,QAAQ,KAAK,2BAA2B,gBAAgB;AAAA;AAAA,EAEhE,MAAM,YACL,SAAS,MACT,SAAS,SAAS,SACjB,SAAS,QAAQ,IAAI,cAAc,KAAK,IAAI,WAC5C,mBACD;AAAA,EACD,IAAI;AAAA,IAAW,OAAO,MAAM,UAAU,OAAO,OAAO,WAAW;AAAA,EAC/D,IAAI,SAAS,IAAI;AAAA,IAChB,MAAM,MAAM;AAAA,IACZ,OAAO,QACN,KACA,gDACA,gBACD;AAAA,EACD;AAAA,EACA,MAAM,UAAU,MAAM,gBAAgB,QAAQ;AAAA,EAC9C,MAAM,MAAM;AAAA,EACZ,OAAO;AAAA;AAGR,SAAS,IAAI,CACZ,QACA,KACoD;AAAA,EACpD,OAAO,SAAS,cACf,QAAQ,WAAW,SAChB,IAAI,OAAO,IACX,QACA,KACA,OAAO,WACP,sBACA,CAAC,GACD,EAAE,OAAO,OAAO,CACjB;AAAA;AAQG,SAAS,uBAAuB,CACtC,SACoB;AAAA,EACpB,eAAe,QAAQ,KAAK;AAAA,EAC5B,MAAM,SAAiB;AAAA,IACtB,UAAU,IAAI,IAAI,QAAQ,QAAQ;AAAA,IAClC,WAAW,IAAI,IAAI,OAAO,QAAQ,QAAQ,KAAK,CAAC;AAAA,IAChD;AAAA,IACA,QAAQ,MACP,OAAO,QAAQ,WAAW,aAAa,QAAQ,OAAO,IAAI,QAAQ;AAAA,IACnE,aAAa,QAAQ,eAAe;AAAA,IACpC,eAAe,QAAQ,UAAU,CAAC,YAAY,MAAM,OAAO;AAAA,EAC5D;AAAA,EACA,OAAO;AAAA,IACN,QAAQ,KAAK,OAAO,CAAC,YAAY,OAAO,QAAQ,OAAO,CAAC;AAAA,IACxD,QAAQ,KAAK,QAAQ,CAAC,YAAY,OAAO,QAAQ,OAAO,CAAC;AAAA,EAC1D;AAAA;",
12
+ "debugId": "943D148BD34D8EDC64756E2164756E21",
13
+ "names": []
14
+ }
@@ -0,0 +1,40 @@
1
+ type HeaderValues = Record<string, string | null | undefined> | Headers;
2
+ export interface SubscriptionProxyOptions {
3
+ /** The API's GraphQL endpoint, which serves subscriptions over SSE. */
4
+ readonly endpoint: string | URL;
5
+ /**
6
+ * The operations the browser may start: each name with the document the
7
+ * proxy sends upstream for it. The client names an operation and sends
8
+ * variables; its own `query` and `extensions` are ignored, so nothing it
9
+ * writes reaches the API. A name that is not a key is a 403.
10
+ */
11
+ readonly allow: Readonly<Record<string, string>>;
12
+ /** The session's token, from the request: `(request) => cookies.token(request)`. Empty is a 401. */
13
+ readonly getToken: (request: Request) => string | null | undefined | Promise<string | null | undefined>;
14
+ /** Extra upstream headers (client name, proxy secret, `X-Forwarded-For`, `Accept-Language`), fixed or built per request. A `null` or `undefined` value is left out. */
15
+ readonly headers?: HeaderValues | ((request: Request) => HeaderValues | Promise<HeaderValues>);
16
+ /** The app's own origin for the cross-site check, as `jsonActions` takes it; the request's own by default. */
17
+ readonly origin?: string | (() => string | undefined);
18
+ /** A comment line sent this often so a proxy or Bun's `idleTimeout` keeps the stream open. 15000 by default; `0` turns it off. */
19
+ readonly heartbeatMs?: number;
20
+ /** The `fetch` used upstream. The global one by default. */
21
+ readonly fetch?: (request: Request) => Promise<Response>;
22
+ }
23
+ export interface SubscriptionProxy {
24
+ /** A GET: graphql-sse's distinct connections mode, the operation in the search params. */
25
+ loader(args: {
26
+ request: Request;
27
+ }): Promise<Response>;
28
+ /** A POST: the operation in a JSON body. */
29
+ action(args: {
30
+ request: Request;
31
+ }): Promise<Response>;
32
+ }
33
+ /**
34
+ * A resource route that exposes GraphQL subscriptions to the browser without
35
+ * giving it the API's token or a way to write its own document. See the
36
+ * subscription guide.
37
+ */
38
+ export declare function createSubscriptionProxy(options: SubscriptionProxyOptions): SubscriptionProxy;
39
+ export {};
40
+ //# sourceMappingURL=proxy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"proxy.d.ts","sourceRoot":"","sources":["../../src/subscription/proxy.ts"],"names":[],"mappings":"AAMA,KAAK,YAAY,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC,GAAG,OAAO,CAAC;AAExE,MAAM,WAAW,wBAAwB;IACxC,uEAAuE;IACvE,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,GAAG,CAAC;IAChC;;;;;OAKG;IACH,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IACjD,oGAAoG;IACpG,QAAQ,CAAC,QAAQ,EAAE,CAClB,OAAO,EAAE,OAAO,KACZ,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC,CAAC;IACpE,uKAAuK;IACvK,QAAQ,CAAC,OAAO,CAAC,EACd,YAAY,GACZ,CAAC,CAAC,OAAO,EAAE,OAAO,KAAK,YAAY,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC;IAChE,8GAA8G;IAC9G,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,CAAC,MAAM,MAAM,GAAG,SAAS,CAAC,CAAC;IACtD,kIAAkI;IAClI,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,4DAA4D;IAC5D,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;CACzD;AAED,MAAM,WAAW,iBAAiB;IACjC,0FAA0F;IAC1F,MAAM,CAAC,IAAI,EAAE;QAAE,OAAO,EAAE,OAAO,CAAA;KAAE,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;IACtD,4CAA4C;IAC5C,MAAM,CAAC,IAAI,EAAE;QAAE,OAAO,EAAE,OAAO,CAAA;KAAE,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;CACtD;AA0HD;;;;GAIG;AACH,wBAAgB,uBAAuB,CACtC,OAAO,EAAE,wBAAwB,GAC/B,iBAAiB,CAenB"}
@@ -0,0 +1,17 @@
1
+ /** The most a body, a query string or the variables may weigh, in bytes. */
2
+ export declare const LIMITS: {
3
+ readonly body: number;
4
+ readonly queryString: number;
5
+ readonly variables: number;
6
+ };
7
+ export interface Asked {
8
+ readonly operationName: string;
9
+ readonly variables?: Record<string, unknown>;
10
+ }
11
+ /**
12
+ * What a client asks for: an `operationName` and its `variables`, from a
13
+ * GET's search params or a POST's JSON body. Any `query` or `extensions` it
14
+ * sends (graphql-sse always sends a `query`) is ignored.
15
+ */
16
+ export declare function readAsked(request: Request): Promise<Asked>;
17
+ //# sourceMappingURL=read.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"read.d.ts","sourceRoot":"","sources":["../../src/subscription/read.ts"],"names":[],"mappings":"AAEA,4EAA4E;AAC5E,eAAO,MAAM,MAAM;;;;CAIT,CAAC;AAEX,MAAM,WAAW,KAAK;IACrB,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC7C;AA0CD;;;;GAIG;AACH,wBAAsB,SAAS,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC,CA6ChE"}
@@ -0,0 +1,11 @@
1
+ /** An answer the proxy gives itself, as GraphQL-shaped JSON a client can read. */
2
+ export declare class Refusal extends Error {
3
+ readonly status: number;
4
+ readonly code: string;
5
+ constructor(status: number, message: string, code: string);
6
+ }
7
+ export declare function problem(status: number, message: string, code: string, extra?: Record<string, unknown>, headers?: HeadersInit): Response;
8
+ export declare const refusalResponse: (refusal: Refusal) => Response;
9
+ /** What a non-2xx upstream answer becomes: a 429 with `retryAfter`, a 502 for a 5xx, any other 4xx as it came. */
10
+ export declare function refusedUpstream(upstream: Response): Promise<Response>;
11
+ //# sourceMappingURL=refusal.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"refusal.d.ts","sourceRoot":"","sources":["../../src/subscription/refusal.ts"],"names":[],"mappings":"AAAA,kFAAkF;AAClF,qBAAa,OAAQ,SAAQ,KAAK;IAEhC,QAAQ,CAAC,MAAM,EAAE,MAAM;IAEvB,QAAQ,CAAC,IAAI,EAAE,MAAM;gBAFZ,MAAM,EAAE,MAAM,EACvB,OAAO,EAAE,MAAM,EACN,IAAI,EAAE,MAAM;CAKtB;AAED,wBAAgB,OAAO,CACtB,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EACZ,KAAK,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,EACnC,OAAO,GAAE,WAAgB,GACvB,QAAQ,CAeV;AAED,eAAO,MAAM,eAAe,GAAI,SAAS,OAAO,KAAG,QACI,CAAC;AAiBxD,kHAAkH;AAClH,wBAAsB,eAAe,CAAC,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC,CA0B3E"}
@@ -0,0 +1,16 @@
1
+ /** The most one event may weigh before the stream is cut, in characters. */
2
+ export declare const MAX_EVENT: number;
3
+ export declare const SSE_HEADERS: {
4
+ 'content-type': string;
5
+ 'cache-control': string;
6
+ 'x-accel-buffering': string;
7
+ };
8
+ /**
9
+ * Relays whole events (a heartbeat never lands inside one) until the upstream
10
+ * ends or the client leaves. The stream is pulled: upstream is read only when
11
+ * the client has taken what was queued, so a slow client holds the upstream
12
+ * back instead of growing a buffer, and a heartbeat is skipped while one is
13
+ * waiting.
14
+ */
15
+ export declare function relay(upstream: Response, abort: AbortController, heartbeatMs: number): Response;
16
+ //# sourceMappingURL=relay.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"relay.d.ts","sourceRoot":"","sources":["../../src/subscription/relay.ts"],"names":[],"mappings":"AAAA,4EAA4E;AAC5E,eAAO,MAAM,SAAS,QAAc,CAAC;AAKrC,eAAO,MAAM,WAAW;;;;CAIvB,CAAC;AAKF;;;;;;GAMG;AACH,wBAAgB,KAAK,CACpB,QAAQ,EAAE,QAAQ,EAClB,KAAK,EAAE,eAAe,EACtB,WAAW,EAAE,MAAM,GACjB,QAAQ,CAwDV"}
@@ -14,7 +14,7 @@
14
14
  "import { NAME } from './entry';\n\n/**\n * Refuses, with what to do, a dev or preview server running on Node. The\n * React Router CLI's `#!/usr/bin/env node` runs it on Node whenever a node\n * is installed, even from `bun run dev`, and alxia's server then fails on\n * its first request with `ReferenceError: Bun is not defined`.\n */\nexport function requireBun(\n\tcommand: string,\n\thint = `bun --bun ${command}`,\n\tonBun = (globalThis as { Bun?: unknown }).Bun !== undefined,\n\treason = \"and alxia's server runs on Bun\",\n): void {\n\tif (onBun) return;\n\tthrow new Error(\n\t\t`${NAME}: ${command} is running on Node, ${reason}. Add a bunfig.toml beside package.json with \"[run]\" and \"bun = true\", so bun run starts it on Bun, or run it as ${hint}.`,\n\t);\n}\n",
15
15
  "/**\n * The service worker, built by `alxia()` once React Router has built the\n * client: `app/service-worker.ts` is the opt-in, as `app/server.ts` is.\n */\nimport { existsSync } from 'node:fs';\nimport { basename, isAbsolute, join, resolve } from 'node:path';\nimport type { ResolvedConfig } from 'vite';\nimport { type BuildWorkerOptions, buildWorker } from '../pwa/build';\nimport { contextOf } from './config';\nimport { NAME } from './entry';\nimport type { AlxiaOptions } from './index';\nimport { requireBun } from './runtime';\n\n/** `buildWorker()`'s options but where: the plugin knows the root, the client build and, by default, the file. */\nexport type AlxiaWorkerOptions = Omit<\n\tBuildWorkerOptions,\n\t'root' | 'client' | 'file'\n> & { readonly file?: string };\n\n/**\n * The worker's source, absolute, or `undefined` when there is none to\n * build: `worker: false`, or no `app/service-worker.ts` and no named file.\n * Throws when a named file does not exist.\n */\nexport function workerFile(\n\toption: AlxiaOptions['worker'],\n\tconfig: ResolvedConfig,\n): string | undefined {\n\tif (option === false) return undefined;\n\tconst named = typeof option === 'string' ? option : option?.file;\n\tif (named !== undefined) {\n\t\tconst file = isAbsolute(named) ? named : resolve(config.root, named);\n\t\tif (!existsSync(file)) {\n\t\t\tthrow new Error(\n\t\t\t\t`${NAME}: the worker ${named} does not exist. Create it, or leave worker out to build app/service-worker.ts when it exists.`,\n\t\t\t);\n\t\t}\n\t\treturn file;\n\t}\n\tconst file = join(contextOf(config).appDirectory, 'service-worker.ts');\n\treturn existsSync(file) ? file : undefined;\n}\n\nconst MB = (bytes: number) => (bytes / 1024 / 1024).toFixed(2);\nconst KB = (bytes: number) => (bytes / 1024).toFixed(1);\n\n/** Builds the worker into `build/client`, if the app has one. */\nexport async function buildAppWorker(\n\tconfig: ResolvedConfig,\n\toption: AlxiaOptions['worker'],\n): Promise<void> {\n\tconst file = workerFile(option, config);\n\tif (file === undefined) return;\n\trequireBun(\n\t\t'react-router build with a service worker',\n\t\t'bun --bun react-router build',\n\t\tundefined,\n\t\t'and the worker is bundled by Bun.build',\n\t);\n\tconst rest = typeof option === 'object' ? option : {};\n\tconst built = await buildWorker({\n\t\t...rest,\n\t\tfile,\n\t\troot: config.root,\n\t\tclient: join(contextOf(config).buildDirectory, 'client'),\n\t}).catch((error: unknown) => {\n\t\tthrow new Error(`${NAME}: ${(error as Error).message}`, { cause: error });\n\t});\n\tconfig.logger.info(\n\t\t`✓ ${basename(built.file)}: ${built.precache.length} files precached (${MB(built.precacheBytes)} MB), worker ${KB(built.bytes)} kB`,\n\t);\n}\n"
16
16
  ],
17
- "mappings": "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",
17
+ "mappings": "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",
18
18
  "debugId": "7F0E7AC67885D01F64756E2164756E21",
19
19
  "names": []
20
20
  }
package/docs/README.md CHANGED
@@ -3,7 +3,7 @@
3
3
  The [package README](../README.md) is the short version. This folder is
4
4
  the long one: the setup, the Vite plugin and its default server, the build for Bun,
5
5
  customising the server, the typed context, the client's files, making the app
6
- installable and usable offline, wording an API's refusals, and what to do with each message.
6
+ installable and usable offline, wording an API's refusals, the BFF session, a GraphQL subscription relayed to the browser (`/subscription`), and what to do with each message.
7
7
 
8
8
  | Page | Read it when |
9
9
  | --- | --- |
@@ -20,6 +20,7 @@ installable and usable offline, wording an API's refusals, and what to do with e
20
20
  | [Installable and offline](guide/pwa.md) | making the app installable and usable offline: the subpaths of `@alxia/react-router/pwa`, the service worker (`startWorker`, `/pwa/worker`), its build by `alxia()` or `buildWorker` (`/pwa/build`), its contract and cache names, which requests the worker caches and which responses it stores, the precache list read from a build, or clearing the caches at sign-out |
21
21
  | [An API's refusals](guide/errors.md) | wording a GraphQL API's refusals for the pages: recognising an `ApiError`, the request id, the page a request is for, the catalogue store, the form checks in the API's words, the provider, and the loaders, the error page and the actions that answer with it, the JSON actions with their CSRF check and fetcher hook, calling the API from a loader (`apiCallFailure`), and keeping the catalogue fresh (`@alxia/react-router/errors`) |
22
22
  | [A BFF session](guide/session.md) | redirecting after sign-in to a page of the site and nowhere else, the sign-in pages' paths, the session's cookies, the sign-in flow (where an answer lands, a refused code, the viewer, sign-out; `@alxia/react-router/session`), the pages a mail's link opens (a magic link, a password reset: `authLinks`), the page's hooks (sign-out, a mail link's parameter, a one-code field; `@alxia/react-router/session/react`), and the step-up's state and the props it gives the UI (`@alxia/react-router/session/model`) |
23
+ | [Subscriptions for a BFF](guide/subscriptions.md) | showing a GraphQL subscription in the browser without giving it the API's token or a way to write a document: a resource route with a map of operation names to the server's documents, the same-site check, the bearer from the session, extra upstream headers, a heartbeat, abort propagation, size limits and a 429 passed through with `retryAfter` (`@alxia/react-router/subscription`) |
23
24
  | [Troubleshooting](troubleshooting.md) | something went wrong and you have the message, or a page streams, hydrates or reads its context unlike you expected |
24
25
  | [Roadmap](roadmap.md) | wondering what is coming, and what is not planned |
25
26
 
@@ -992,7 +992,7 @@ const { signOut } = useSignOut({
992
992
  ### `useLinkParam`
993
993
 
994
994
  Reads the query parameter a mail's link carries, once: the first render's value
995
- is kept for the page's life. With `drop: true` the parameter is then removed
995
+ is kept for the page's life (unless `live: true`, below). With `drop: true` the parameter is then removed
996
996
  from the address bar (`history.replaceState`, keeping the history state and the
997
997
  hash), so a token is not left in the history, a bookmark or a screenshot. It is
998
998
  `null` when the parameter is absent or empty.
@@ -1017,6 +1017,23 @@ The router's own location is not updated by `replaceState`: a loader or
1017
1017
  `useSearchParams` elsewhere still sees the token until the next navigation.
1018
1018
  Read it with the hook once, and pass it down.
1019
1019
 
1020
+ #### `live: true`: a parameter set after the page mounted
1021
+
1022
+ By default the value is read once. A route that stays mounted while an action
1023
+ redirects back to it with a new parameter (`/settings` to
1024
+ `/settings?state=linked`) never sees it. `live: true` follows the URL: the
1025
+ value is the parameter of the current location, and each new location is read
1026
+ again.
1027
+
1028
+ ```tsx
1029
+ const state = useLinkParam('state', { live: true }); // 'linked' | 'invalid' | null
1030
+ ```
1031
+
1032
+ With `drop: true` too, the value is kept after the address bar loses the
1033
+ parameter, until a location carries a new one: a navigation that has no such
1034
+ parameter does not clear it, since the drop removed it. Without `drop` the
1035
+ value is exactly the current location's parameter, `null` when it is gone.
1036
+
1020
1037
  ### `useCodeField` and `useOnRefusal`
1021
1038
 
1022
1039
  A form that asks for one code (an authenticator app's, a recovery code) and
@@ -0,0 +1,126 @@
1
+ # Subscriptions for a BFF
2
+
3
+ This page is for a React Router app that is the backend of its own pages (a
4
+ BFF) and wants to show a GraphQL subscription in the browser: a room's
5
+ events, a chat, a live counter. The browser must not hold the API's token and
6
+ must not be able to send the API a document of its own, so the app exposes
7
+ **one resource route** that checks the user's session, looks the operation up
8
+ in a list the server holds, and relays the API's server-sent events.
9
+
10
+ `@alxia/react-router/subscription` is that route. It imports nothing (web APIs only), so it adds no peer.
11
+
12
+ ## Expose a subscription
13
+
14
+ `allow` maps each operation name to the **document the server sends for it**.
15
+ Build the map from your codegen's documents, so the text is the one your
16
+ client was generated from:
17
+
18
+ ```ts
19
+ // app/routes/events.ts: a resource route, served at /events
20
+ import { createSubscriptionProxy } from '@alxia/react-router/subscription';
21
+ import { print } from 'graphql';
22
+ import { ChatMessagesDocument, RoomEventsDocument } from '../generated/graphql';
23
+ import { cookies } from '../session.server';
24
+
25
+ const events = createSubscriptionProxy({
26
+ endpoint: 'https://api.example.com/graphql',
27
+ allow: {
28
+ RoomEvents: print(RoomEventsDocument), // a TypedDocumentNode
29
+ ChatMessages: print(ChatMessagesDocument),
30
+ // or the document string codegen exports, or a literal
31
+ },
32
+ getToken: (request) => cookies.token(request),
33
+ headers: (request) => ({
34
+ 'x-client-name': 'my-bff',
35
+ 'x-proxy-secret': process.env.PROXY_SECRET,
36
+ 'x-forwarded-for': request.headers.get('x-forwarded-for'),
37
+ 'accept-language': request.headers.get('accept-language'),
38
+ }),
39
+ });
40
+
41
+ export const loader = events.loader; // GET: operationName and variables in the query string
42
+ export const action = events.action; // POST: the same in a JSON body
43
+ ```
44
+
45
+ ```ts
46
+ // app/routes.ts
47
+ import { route, type RouteConfig } from '@react-router/dev/routes';
48
+
49
+ export default [route('events', 'routes/events.ts')] satisfies RouteConfig;
50
+ ```
51
+
52
+ The browser talks to `/events` with a client that speaks GraphQL over SSE in
53
+ its distinct connections mode, such as `graphql-sse`. It names the operation
54
+ and sends its variables; the `query` it sends, as `graphql-sse` always does,
55
+ is **ignored**:
56
+
57
+ ```ts
58
+ import { createClient } from 'graphql-sse';
59
+
60
+ const client = createClient({ url: '/events', singleConnection: false });
61
+
62
+ const dispose = client.subscribe(
63
+ {
64
+ query: 'subscription RoomEvents($id: ID!) { roomEvents(id: $id) { id kind } }',
65
+ operationName: 'RoomEvents',
66
+ variables: { id: roomId },
67
+ },
68
+ { next: show, error: report, complete: () => {} },
69
+ );
70
+ ```
71
+
72
+ `graphql-sse` sends a POST by default and a GET for `method: 'GET'`; both
73
+ work, each through the matching export.
74
+
75
+ ## What the proxy does
76
+
77
+ | Step | Rule |
78
+ | --- | --- |
79
+ | Same site | Both methods run the rule of `jsonActions`: an `Origin` that is not the app's own, or a `Sec-Fetch-Site` other than `same-origin` or `none`, is a **403** (`origin` sets the app's origin; the request's own by default). It reads headers only. A POST must be `application/json`, else **415**. |
80
+ | Session | `getToken(request)` gives the token, read on the server from the HttpOnly cookie. Empty, `null`, `undefined` or a token holding a line break is a **401**; nothing goes upstream. |
81
+ | Request | The client's `operationName` and `variables` are read. A body that cannot be read (the client left) is a **400**; a body past 64 KiB (`Content-Length` first, then the bytes read), a query string past 16 KiB or `variables` past 16 KiB is a **400**, as is malformed input. Its `query` and `extensions` are ignored. |
82
+ | Allow-list | Each document of `allow` must define `subscription <key>` and no other operation (fragments are fine), or `createSubscriptionProxy` throws a `TypeError` when it is created. `operationName` must be a key of `allow`, else **403**. The proxy sends **its own document** for it, with the client's variables: no document, fragment, extension or persisted id of the client's reaches the API. |
83
+ | Upstream request | A `POST` to `endpoint` with `Accept: text/event-stream`, `Authorization: Bearer <token>` and your `headers`. The browser's own headers and cookies are never forwarded. A header name or value no header can hold (a line break) is a worded **500**. |
84
+ | Relay | Whole events are relayed in order, as the client takes them: a slow client holds the upstream back instead of growing a buffer, and a heartbeat is skipped while one is waiting. A heartbeat comment (`:`) goes out every `heartbeatMs` (15000 by default, `0` turns it off), never inside an event. An event of more than 1 MiB with no end cuts the stream with an `UPSTREAM_ERROR`. |
85
+ | End | The upstream's `complete`, or the end of its stream, closes the client's stream. A stream that breaks sends a `next` with an `UPSTREAM_ERROR` and a `complete`. |
86
+ | Abort | When the browser closes the request, the upstream request is aborted: no subscription is left running. A request that is already aborted never starts one. |
87
+ | Rate limit | An upstream **429** is passed through with `Retry-After` and `retryAfter` in the body (`{ "retryAfter": 12, "errors": [{ "extensions": { "code": "RATE_LIMITED", "retryAfter": 12 } }] }`), read from the upstream's header or body. The proxy never retries. |
88
+ | Other failures | An upstream 5xx, an unreachable API or an answer that is not an event stream is a **502** (`UPSTREAM_ERROR`); an upstream 4xx such as a 401 passes through. |
89
+
90
+ The stream is answered with `Content-Type: text/event-stream`,
91
+ `Cache-Control: no-store, no-transform` and `X-Accel-Buffering: no`, so no
92
+ adapter or reverse proxy needs to buffer it.
93
+
94
+ ## Options
95
+
96
+ | Option | |
97
+ | --- | --- |
98
+ | `endpoint` | the API's GraphQL URL (required) |
99
+ | `allow` | operation name to the document sent upstream (required); each document must define `subscription <name>`, that operation alone, checked when the proxy is created |
100
+ | `getToken(request)` | the session's token, sync or async (required) |
101
+ | `headers` | a record, `Headers`, or `(request) => record`; a `null` or `undefined` value is left out |
102
+ | `origin` | the app's origin for the same-site check, a string or a getter; the request's own by default |
103
+ | `heartbeatMs` | 15000 |
104
+ | `fetch` | the `fetch` used upstream (the global one); useful in specs |
105
+
106
+ ## Keep the stream alive
107
+
108
+ Bun closes an idle connection after `idleTimeout` seconds (10 by default).
109
+ The heartbeat covers it as long as `heartbeatMs` is shorter, and so is a proxy's
110
+ read timeout. Behind nginx, keep `proxy_buffering off` for the route (the
111
+ `X-Accel-Buffering: no` header does it per response).
112
+
113
+ ## Cross-site requests
114
+
115
+ Both methods refuse a request from another site (the rule above), and the
116
+ session cookie should stay `SameSite=Lax` (`sessionCookies` does it). The
117
+ allow-list is what the browser may start; because the documents are the
118
+ server's, it cannot start anything else, a mutation included. The route does
119
+ not stop a signed-in user from starting an allowed subscription as often as
120
+ they like: rate-limit it (`@alxia/rate-limit`) if the API does not.
121
+
122
+ ## Testing
123
+
124
+ Give the proxy a fake API through `fetch`, or start a `Bun.serve` that
125
+ answers with an event stream, and call `events.action({ request })`; the
126
+ answer is a plain `Response`.
package/docs/roadmap.md CHANGED
@@ -8,12 +8,20 @@ number on it. Every release, with each change it made, is in
8
8
  ## Now
9
9
 
10
10
  - **`@alxia/react-router/session/react`: the page's hooks around the session
11
- flows.** `useSignOut`, `useLinkParam` (a mail link's parameter, read once and
12
- optionally dropped from the address bar) and `useCodeField` /
11
+ flows.** `useSignOut`, `useLinkParam` (a mail link's parameter, read once and optionally dropped
12
+ from the address bar, or with `live: true` following the URL) and `useCodeField` /
13
13
  `useOnRefusal` (a one-code field that clears and refocuses on each refusal),
14
14
  so an app stops carrying its own copies. See the
15
15
  [session guide](guide/session.md#the-pages-hooks).
16
16
 
17
+ - **`@alxia/react-router/subscription`: GraphQL subscriptions for the
18
+ browser of a BFF.** `createSubscriptionProxy` gives a resource route's
19
+ `loader` and `action` that relay a subscription over SSE: the server holds
20
+ each allowed document, the bearer comes from the session, the route refuses
21
+ cross-site requests, keeps the stream alive with a heartbeat, aborts the
22
+ upstream with the client and passes a 429 on with `retryAfter`. See the
23
+ [subscriptions guide](guide/subscriptions.md).
24
+
17
25
  ## Next
18
26
 
19
27
  Nothing planned.
@@ -2714,3 +2714,112 @@ import { TOKEN_PAGE_HEADERS } from '@alxia/react-router/session';
2714
2714
 
2715
2715
  export const headers = () => TOKEN_PAGE_HEADERS;
2716
2716
  ```
2717
+
2718
+ ### A subscription answers 401
2719
+
2720
+ `{"errors":[{"message":"Sign in to continue.","extensions":{"code":"UNAUTHENTICATED"}}]}`
2721
+
2722
+ **Why:** `getToken(request)` returned `null`, `undefined`, `''` or a token with a
2723
+ line break: the browser sent no session cookie (signed out, expired, or a
2724
+ cross-site request with a `SameSite=Lax` cookie), or `getToken` reads another
2725
+ cookie than the one the sign-in wrote.
2726
+
2727
+ **Fix:** return the token the loaders use, and send the cookie with the request
2728
+ (`credentials: 'include'` for a cross-origin client):
2729
+
2730
+ ```ts
2731
+ getToken: (request) => cookies.token(request),
2732
+ ```
2733
+
2734
+ ### A subscription answers 403 `This operation is not allowed.`
2735
+
2736
+ **Why:** `operationName` is not a key of `allow`. The proxy runs only the
2737
+ documents the server holds; a `query` the client sends is ignored.
2738
+
2739
+ **Fix:** list the name with its document, and send that name:
2740
+
2741
+ ```ts
2742
+ createSubscriptionProxy({ endpoint, allow: { RoomEvents: document }, getToken });
2743
+ ```
2744
+
2745
+ ### A subscription answers 403 `Cross-site request refused.`
2746
+
2747
+ **Why:** the request's `Origin` is not the app's own, or its `Sec-Fetch-Site` is
2748
+ `cross-site`, or `same-site` (another subdomain of the same site: only `same-origin` and `none` pass). Behind a TLS-terminating proxy
2749
+ the request's own origin can read `http://`.
2750
+
2751
+ **Fix:** call the route from the app's own pages, or give the proxy the public
2752
+ origin:
2753
+
2754
+ ```ts
2755
+ createSubscriptionProxy({ endpoint, allow, getToken, origin: 'https://app.example.com' });
2756
+ ```
2757
+
2758
+ ### A subscription answers 415 `Send the request as application/json.`
2759
+
2760
+ **Why:** a POST with another `Content-Type`, or none.
2761
+
2762
+ **Fix:** send `Content-Type: application/json` (`graphql-sse` does), or use GET.
2763
+
2764
+ ### A subscription answers 400 `The request is too large.`
2765
+
2766
+ **Why:** the body is over 64 KiB, the query string over 16 KiB, or `variables`
2767
+ over 16 KiB.
2768
+
2769
+ **Fix:** send less in `variables`; a document does not belong in the request,
2770
+ the server holds it.
2771
+
2772
+ ### A subscription answers 400 `The request is not valid JSON.`
2773
+
2774
+ **Why:** the POST body, or the `variables` parameter of a GET, is not JSON.
2775
+
2776
+ **Fix:** send `JSON.stringify({ operationName, variables })`, and `variables`
2777
+ JSON-encoded in a GET.
2778
+
2779
+ ### A subscription answers 400 `The request must be a JSON object.`, `Send an "operationName".`, `"operationName" must be a string.` or `"variables" must be an object.`
2780
+
2781
+ **Why:** the body is an array or a scalar, `operationName` is missing or not a
2782
+ string, or `variables` is not an object.
2783
+
2784
+ **Fix:** send `{ "operationName": "RoomEvents", "variables": { … } }`.
2785
+
2786
+ ### A subscription answers 500 `The proxy's upstream headers are not valid …`
2787
+
2788
+ **Why:** a value of `headers` (a forwarded `Accept-Language`, a secret from the
2789
+ environment) holds a line break, or a name is not a header name.
2790
+
2791
+ **Fix:** trim or validate the value before it goes in `headers`.
2792
+
2793
+ ### A subscription answers 429 with `retryAfter`
2794
+
2795
+ The API's rate limit answered. The proxy passes it on and never retries.
2796
+
2797
+ **Fix:** have the client wait `Retry-After` seconds (also `retryAfter` in the
2798
+ body) before it subscribes again.
2799
+
2800
+ ### A subscription answers 502
2801
+
2802
+ **Why:** the API is unreachable, answered 5xx, or answered something that is
2803
+ not `text/event-stream` (a proxy in front of it, or a wrong `endpoint`).
2804
+
2805
+ **Fix:** post the document to the `endpoint` by hand with the same headers; it
2806
+ must answer with `Content-Type: text/event-stream`.
2807
+
2808
+ ### The stream ends with `The API stream failed.`
2809
+
2810
+ **Why:** the upstream stream broke, or sent an event of more than 1 MiB with
2811
+ no blank line ending it.
2812
+
2813
+ **Fix:** read the API's logs; a subscription's events are small and end with a
2814
+ blank line.
2815
+
2816
+ ### Events arrive in bursts, or the stream closes after a few seconds
2817
+
2818
+ **Why:** a proxy or CDN between the app and the browser buffers the response,
2819
+ or closes an idle connection (Bun's `idleTimeout`, a load balancer's timeout)
2820
+ because `heartbeatMs` is longer than it.
2821
+
2822
+ **Fix:** keep `heartbeatMs` shorter than the shortest idle timeout on the
2823
+ path, turn response buffering off for the route (nginx `proxy_buffering off`;
2824
+ the route already sends `X-Accel-Buffering: no`), and do not compress the
2825
+ route's responses.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@alxia/react-router",
3
- "version": "0.17.0",
4
- "description": "alxia as the server of a React Router framework app: server rendering behind the app's hooks, loaders reading its typed context, the client's assets served; the code with no UI an installable app shares (`/pwa`), its hooks (`/pwa/react`), `noCache` for the worker's script (`/pwa/server`), the service worker on Workbox (`/pwa/worker`) and its build (`/pwa/build`), an API's refusals worded for the page (`/errors`), the BFF session: cookies, sign-in, step-up and mail links (`/session`), its page hooks (`/session/react`) and what it shares with the page (`/session/model`), the page's CSP nonce and inline boot scripts (`/document`) and a streaming `entry.server` (`/entry`)",
3
+ "version": "0.19.0",
4
+ "description": "alxia as the server of a React Router framework app: server rendering behind the app's hooks, loaders reading its typed context, the client's assets served; the code with no UI an installable app shares (`/pwa`), its hooks (`/pwa/react`), `noCache` for the worker's script (`/pwa/server`), the service worker on Workbox (`/pwa/worker`) and its build (`/pwa/build`), an API's refusals worded for the page (`/errors`), the BFF session: cookies, sign-in, step-up and mail links (`/session`), its page hooks (`/session/react`) and what it shares with the page (`/session/model`), a GraphQL subscription relayed to the browser over SSE (`/subscription`), the page's CSP nonce and inline boot scripts (`/document`) and a streaming `entry.server` (`/entry`)",
5
5
  "license": "MIT",
6
6
  "type": "module",
7
7
  "main": "./dist/index.js",
@@ -82,6 +82,11 @@
82
82
  "import": "./dist/session/model/index.js",
83
83
  "default": "./dist/session/model/index.js"
84
84
  },
85
+ "./subscription": {
86
+ "types": "./dist/subscription/index.d.ts",
87
+ "import": "./dist/subscription/index.js",
88
+ "default": "./dist/subscription/index.js"
89
+ },
85
90
  "./package.json": "./package.json"
86
91
  },
87
92
  "repository": {
@@ -109,6 +114,7 @@
109
114
  "src/session/model/index.ts",
110
115
  "src/session/index.ts",
111
116
  "src/session/react/index.ts",
117
+ "src/subscription/index.ts",
112
118
  "src/document/index.ts",
113
119
  "src/entry/index.ts",
114
120
  "src/pwa/worker/index.ts",
@@ -123,7 +129,7 @@
123
129
  "@nxgt/graphql-client": "^0.4.0",
124
130
  "@nxgt/janus": "^0.29.0",
125
131
  "@react-router/dev": "^8.5.0",
126
- "@types/bun": "^1.4.2",
132
+ "@types/bun": "^1.4.4",
127
133
  "@types/react": "^19.3.0",
128
134
  "@types/react-dom": "^19.3.0",
129
135
  "graphql": "^17.0.2",