@loadbare/app 0.12.0 → 0.14.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.
- package/dist/build/assemble.d.ts.map +1 -1
- package/dist/build/assemble.js +87 -1
- package/dist/build/assemble.js.map +1 -1
- package/dist/build/cli.js +2 -1
- package/dist/build/cli.js.map +1 -1
- package/dist/build/elements.d.ts +9 -1
- package/dist/build/elements.d.ts.map +1 -1
- package/dist/build/elements.js +50 -0
- package/dist/build/elements.js.map +1 -1
- package/dist/build/origins.d.ts +2 -0
- package/dist/build/origins.d.ts.map +1 -1
- package/dist/build/origins.js +1 -1
- package/dist/build/origins.js.map +1 -1
- package/dist/core/lb-constants.d.ts +34 -1
- package/dist/core/lb-constants.d.ts.map +1 -1
- package/dist/core/lb-constants.js +105 -0
- package/dist/core/lb-constants.js.map +1 -1
- package/dist/core/lb-types.d.ts +74 -18
- package/dist/core/lb-types.d.ts.map +1 -1
- package/dist/core/lb-types.js +74 -11
- package/dist/core/lb-types.js.map +1 -1
- package/dist/hub/lb-apply.d.ts +57 -18
- package/dist/hub/lb-apply.d.ts.map +1 -1
- package/dist/hub/lb-apply.js +661 -63
- package/dist/hub/lb-apply.js.map +1 -1
- package/dist/hub/lb-hub.browser.d.ts.map +1 -1
- package/dist/hub/lb-hub.browser.js +400 -33
- package/dist/hub/lb-hub.browser.js.map +1 -1
- package/dist/server/lb-express.d.ts +19 -7
- package/dist/server/lb-express.d.ts.map +1 -1
- package/dist/server/lb-express.js +62 -26
- package/dist/server/lb-express.js.map +1 -1
- package/dist/server/lb-server.d.ts +80 -11
- package/dist/server/lb-server.d.ts.map +1 -1
- package/dist/server/lb-server.js +185 -33
- package/dist/server/lb-server.js.map +1 -1
- package/docs/TECHREF-1.0.md +584 -111
- package/docs/comparison.md +17 -13
- package/docs/possible-ideas.md +308 -0
- package/docs/reference/chrome.md +7 -1
- package/docs/reference/custom-elements.md +134 -39
- package/docs/reference/data-binding.md +405 -17
- package/docs/reference/page-files.md +101 -19
- package/docs/reference/server.md +24 -0
- package/docs/reference/widgets.md +118 -25
- package/docs/roadmap.md +17 -6
- package/docs/testing.md +21 -10
- package/package.json +2 -3
- package/skills/loadbare-app/SKILL.md +92 -30
- package/skills/loadbare-app/references/TECHREF-1.0.md +584 -111
- package/skills/loadbare-app/references/chrome.md +7 -1
- package/skills/loadbare-app/references/custom-elements.md +134 -39
- package/skills/loadbare-app/references/data-binding.md +405 -17
- package/skills/loadbare-app/references/page-files.md +101 -19
- package/skills/loadbare-app/references/server.md +24 -0
- package/skills/loadbare-app/references/widgets.md +118 -25
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lb-hub.browser.js","sourceRoot":"","sources":["../../hub/lb-hub.browser.ts"],"names":[],"mappings":"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","sourcesContent":["/// <reference lib=\"dom\" />\n\nimport {\n ATTR_COLUMN,\n ATTR_COLUMN_VALUE,\n ATTR_KEY_VALUE,\n ATTR_PAGE,\n ATTR_PAGE_TITLE,\n ATTR_QUERY,\n ATTR_REQUEST,\n ATTR_REQUEST_ERROR,\n ATTR_REQUEST_PENDING,\n ATTR_URL_LINK,\n ATTR_URL_PUSH,\n ATTR_URL_UNKNOWN,\n HUB_TAG_NAME,\n KIND_ROW,\n LB_DONE_EVENT_NAME,\n LB_ENDPOINT,\n LB_EVENT_NAME,\n LB_REQUEST_TIMEOUT_MS,\n LB_RESERVED_PREFIX,\n LIVE_ROW,\n REQUEST_ROW_DELETE,\n REQUEST_ROW_INSERT,\n REQUEST_ROW_UPDATE,\n URL_COLUMN_PAGE_LABEL,\n URL_COLUMN_PAGE_UNKNOWN,\n URL_COLUMN_PATH,\n URL_QUERY,\n} from \"../core/lb-constants.js\";\nimport {\n isRowRequest,\n nextLocation,\n pageNameFor,\n type HubRequest,\n type HubRequestDone,\n type HubResponse,\n type ResponseItem,\n type Row,\n} from \"../core/lb-types.js\";\nimport {\n applyResponse,\n forget,\n isControl,\n isFormAssociated,\n within,\n type Control,\n} from \"./lb-apply.js\";\n\nexport { applyResponse, applyRow } from \"./lb-apply.js\";\n\n/** What each request Loadbare provides cannot be issued without. */\nconst NEEDS: Record<string, readonly (keyof HubRequest)[]> = {\n [REQUEST_ROW_INSERT]: [\"query\", \"values\"],\n [REQUEST_ROW_UPDATE]: [\"query\", \"key\", \"values\"],\n [REQUEST_ROW_DELETE]: [\"query\", \"key\"],\n};\n\n/** The nearest ancestor carrying `lb-query`. An element is not its own. */\nfunction queryOf(el: Element): Element | null {\n return el.parentElement?.closest(`[${ATTR_QUERY}]`) ?? null;\n}\n\n/** The live row an element is, or is in. */\nfunction liveRowOf(el: Element): Element | null {\n return el.closest(LIVE_ROW);\n}\n\n/**\n * The key of the nearest ancestor row, when that row is of `query`: a live\n * row whose query it is, or the element a `row` of it landed on.\n */\nfunction keyFrom(el: Element, query: Element): string | undefined {\n // A live row is its own row; any other element's row is an ancestor.\n const row = el.matches(LIVE_ROW)\n ? el\n : el.parentElement?.closest(`[${ATTR_KEY_VALUE}]`);\n if (!row) return undefined;\n // A live row's key is its outer query's, even when the row names a query\n // of its own. Any other element's key is its own query's.\n const ofQuery = row.matches(LIVE_ROW)\n ? queryOf(row) === query\n : row === query;\n return ofQuery ? (row.getAttribute(ATTR_KEY_VALUE) ?? undefined) : undefined;\n}\n\n/**\n * Every control whose form owner is `form`: HTML's own list, which holds a\n * control nested in the form or joined to it by the `form` attribute, and a\n * form-associated custom element as well as a native control.\n */\nfunction controlsOf(form: HTMLFormElement): Element[] {\n return [...(form.elements as unknown as Iterable<Element>)];\n}\n\n/**\n * The form owner of an element that has one, as HTML reports it on the\n * element's `form` property.\n */\nfunction formOwnerOf(el: Element): HTMLFormElement | null {\n const owner = (el as { form?: unknown }).form;\n return owner && (owner as Element).localName === \"form\"\n ? (owner as HTMLFormElement)\n : null;\n}\n\n/** The group a request gathers from. */\ninterface Group {\n controls: Element[];\n /** Set when the group is a form, so a successful insert resets it. */\n form?: HTMLFormElement;\n /** What the group is: the form or the live row. */\n root: Element;\n}\n\n/**\n * The controls a request gathers — see docs/reference/data-binding.md,\n * \"Gathering\":\n *\n * 1. the element carrying `lb-request` has `lb-column`: it alone;\n * 2. the element is a `<form>`: the controls whose form owner it is;\n * 3. the element is in a live row: the controls in that live row;\n * 4. otherwise: the controls whose form owner is the element's.\n *\n * A control whose nearest `lb-query` is inside the group belongs to a query\n * nested in it, and is skipped.\n */\nfunction groupFor(el: Element): Group | null {\n if (el.hasAttribute(ATTR_COLUMN)) return { controls: [el], root: el };\n if (el.localName === \"form\") {\n const form = el as HTMLFormElement;\n return { controls: controlsOf(form), form, root: form };\n }\n const live = liveRowOf(el);\n if (live) return { controls: within(live, `[${ATTR_COLUMN}]`), root: live };\n const form = formOwnerOf(el);\n if (form) return { controls: controlsOf(form), form, root: form };\n return null;\n}\n\n/** The gathered controls, with their values under their columns. */\nfunction gather(group: Group | null): {\n controls: Control[];\n values: Record<string, string>;\n} {\n const controls: Control[] = [];\n const values: Record<string, string> = {};\n for (const el of group?.controls ?? []) {\n const column = el.getAttribute(ATTR_COLUMN);\n if (column === null || !isControl(el)) continue;\n const nested = queryOf(el);\n if (nested && nested !== group!.root && group!.root.contains(nested)) {\n continue;\n }\n controls.push(el);\n values[column] = el.value;\n }\n return { controls, values };\n}\n\n/** The form each insert gathered from, until its round trip succeeds. */\nconst insertedFrom = new WeakMap<HubRequest, HTMLFormElement>();\n\n/**\n * Complete a request from where its element sits. Every request passes\n * through here, whoever issued it; a field it already carries is its\n * issuer's to decide and is left as it is.\n *\n * False when the request cannot be issued, having said why.\n */\nfunction complete(request: HubRequest | undefined, el: Element): boolean {\n if (!request?.name) {\n console.warn(`lb-hub: a request without a name, ignoring`, request);\n return false;\n }\n const { name } = request;\n if (name.startsWith(LB_RESERVED_PREFIX) && !isRowRequest(name)) {\n console.error(\n `lb-hub: '${name}' begins with '${LB_RESERVED_PREFIX}' but names no ` +\n `request Loadbare provides, ignoring`,\n );\n return false;\n }\n\n const group = groupFor(el);\n const { controls, values } = gather(group);\n if (request.values === undefined && controls.length > 0) {\n request.values = values;\n }\n\n // The request is for the nearest `lb-query` of what it gathered, or of the\n // element itself when it gathered nothing.\n const queries = new Set(controls.map(queryOf));\n if (queries.size > 1) {\n console.error(\n `lb-hub: '${name}' gathered controls of more than one query, not sent`,\n el,\n );\n return false;\n }\n const from = controls[0] ?? el;\n const query = controls.length > 0 ? [...queries][0]! : queryOf(el);\n if (query) {\n request.query ??= query.getAttribute(ATTR_QUERY)!;\n const key = keyFrom(from, query);\n if (key !== undefined) request.key ??= key;\n }\n\n if (name === REQUEST_ROW_INSERT && group?.form) {\n insertedFrom.set(request, group.form);\n }\n\n const needs = NEEDS[name];\n if (needs) {\n const missing = needs.filter(\n (field) =>\n request[field] === undefined ||\n (field === \"values\" && Object.keys(request.values!).length === 0),\n );\n if (missing.length > 0) {\n console.error(\n `lb-hub: '${name}' from <${el.localName}> has no ` +\n `${missing.join(\", \")}, not sent`,\n el,\n );\n return false;\n }\n }\n return true;\n}\n\n/**\n * Commit: dispatch the request an element names, for the hub to complete. A\n * commit on an element whose round trip is in flight is ignored.\n */\nfunction commit(el: Element): void {\n if (el.hasAttribute(ATTR_REQUEST_PENDING)) return;\n const detail: HubRequest = { name: el.getAttribute(ATTR_REQUEST)! };\n el.dispatchEvent(new CustomEvent(LB_EVENT_NAME, { bubbles: true, detail }));\n}\n\n/** A submit button with a form owner commits with its form, never on click. */\nfunction isSubmitButton(el: Element): boolean {\n const type = (el as HTMLInputElement).type as string;\n const submits =\n (el.localName === \"button\" && type === \"submit\") ||\n (el.localName === \"input\" && (type === \"submit\" || type === \"image\"));\n return submits && formOwnerOf(el) !== null;\n}\n\n/**\n * HTML's interactive content: elements a click already means something to.\n * HTML forbids nesting them inside `<a>` or `<button>` so a click means one\n * thing, and the hub draws the same line.\n */\nconst INTERACTIVE = [\n \"a[href]\",\n \"button\",\n \"input:not([type=hidden])\",\n \"select\",\n \"textarea\",\n \"label\",\n \"details\",\n \"iframe\",\n \"embed\",\n \"audio[controls]\",\n \"video[controls]\",\n \"img[usemap]\",\n].join(\", \");\n\n/**\n * Whether a click on `target` is the click of `el`, the element carrying\n * `lb-request` above it: no interactive content lies between them. A click on\n * a control, link or button inside `el` belongs to that element.\n */\nfunction clicks(target: Element, el: Element): boolean {\n for (let node: Element | null = target; node && node !== el;) {\n if (node.matches(INTERACTIVE) || isFormAssociated(node)) return false;\n node = node.parentElement;\n }\n return true;\n}\n\n/** The page file's title, or its stub when it has none. */\nfunction titleOf(template: HTMLTemplateElement | null, page: string): string {\n return template?.getAttribute(ATTR_PAGE_TITLE) || page;\n}\n\n/**\n * The `<template>` a page ships in. The builder guarantees one per stub\n * (build/locations.ts refuses two page files sharing one), so a second match\n * here means the document was assembled by something else.\n */\nfunction pageHostFor(page: string): HTMLTemplateElement | null {\n const hosts: HTMLTemplateElement[] = [];\n for (const el of document.querySelectorAll(`template[${ATTR_PAGE}]`)) {\n if (el.getAttribute(ATTR_PAGE) === page) {\n hosts.push(el as HTMLTemplateElement);\n }\n }\n if (hosts.length > 1) {\n console.error(\n `lb-hub: ${hosts.length} pages carry ${ATTR_PAGE}=\"${page}\", ` +\n `using the first`,\n );\n }\n return hosts[0] ?? null;\n}\n\n/**\n * One round trip against the client-side deadline. Throws on a non-ok\n * response, a network failure or a timeout, so a caller can tell a failed\n * request from an empty answer.\n *\n * The stub names the path below the endpoint and the query string the\n * browser is showing rides after it verbatim, so every round trip reaches\n * the server with the query parms in hand.\n */\nasync function fetchItems(\n page: string,\n request?: HubRequest,\n): Promise<HubResponse> {\n const path = page.split(\"/\").map(encodeURIComponent).join(\"/\");\n const url = `${LB_ENDPOINT}/${path}${location.search}`;\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), LB_REQUEST_TIMEOUT_MS);\n try {\n // An empty body is how the hub asks for the page's queries.\n const res = await fetch(url, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\" },\n body: JSON.stringify(request ?? {}),\n signal: controller.signal,\n });\n if (!res.ok) {\n throw new Error(`lb-hub: server responded ${res.status} for ${url}`);\n }\n return (await res.json()) as HubResponse;\n } finally {\n clearTimeout(timeout);\n }\n}\n\n/** An element's round trip is in flight, or is not. */\nfunction pending(el: Element | undefined, on: boolean): void {\n if (!el) return;\n if (on) {\n el.removeAttribute(ATTR_REQUEST_ERROR);\n el.setAttribute(ATTR_REQUEST_PENDING, \"\");\n el.setAttribute(\"aria-busy\", \"true\");\n } else {\n el.removeAttribute(ATTR_REQUEST_PENDING);\n el.removeAttribute(\"aria-busy\");\n }\n}\n\n/**\n * Tell the element that committed how its request turned out. Raised after\n * everything the request brought back has landed, so a listener sees the\n * page as the answer left it, and `lb-request-pending` is already gone.\n */\nfunction done(\n origin: Element | undefined,\n request: HubRequest,\n landed: ResponseItem[] | Error,\n): void {\n const detail: HubRequestDone =\n landed instanceof Error\n ? { request, items: [], error: landed }\n : { request, items: landed };\n origin?.dispatchEvent(\n new CustomEvent(LB_DONE_EVENT_NAME, { bubbles: true, detail }),\n );\n}\n\n/** What can take focus, before asking whether it can be operated. */\nconst FOCUSABLE =\n `a[href], button, input:not([type=\"hidden\"]), select, textarea, ` +\n `summary, [tabindex]:not([tabindex=\"-1\"]), ` +\n `[contenteditable]:not([contenteditable=\"false\"])`;\n\n/**\n * Focus the first element in `main` the user can operate: not disabled, not\n * in a closed dialog, not inert, not hidden, and one that took the focus\n * when asked. Nothing in a `<template>` is a candidate, so an absent\n * `lb-show` branch is passed over. Focus already in `main` is the user's,\n * and is left where it is.\n */\nfunction focusFirst(main: HTMLElement): void {\n if (main.contains(document.activeElement)) return;\n for (const el of main.querySelectorAll<HTMLElement>(FOCUSABLE)) {\n if (el.matches(\":disabled\")) continue;\n if (el.closest(`dialog:not([open]), [inert], [hidden]`)) continue;\n if (el.checkVisibility?.() === false) continue;\n el.focus();\n if (document.activeElement === el) return;\n }\n}\n\n/**\n * The URL a round trip answers for: its path and its query string. An answer\n * that returns to another is not landed.\n */\nfunction here(): string {\n return location.pathname + location.search;\n}\n\n/** A plain primary click: no other button, no modifier, not yet handled. */\nfunction isPlainClick(e: MouseEvent): boolean {\n return (\n e.button === 0 &&\n !e.defaultPrevented &&\n !e.metaKey &&\n !e.ctrlKey &&\n !e.shiftKey &&\n !e.altKey\n );\n}\n\n/** The URL a row for `lb-url` leads to, by the rule the server follows. */\nfunction nextUrl(row: Row): { url: URL; moved: boolean } {\n const url = new URL(location.href);\n const next = nextLocation(pageNameFor(url.pathname), url.searchParams, row);\n const path = row[URL_COLUMN_PATH];\n if (typeof path === \"string\") url.pathname = path;\n url.search = next.parms.toString();\n return { url, moved: next.moved };\n}\n\n/**\n * The hub is a singleton outside <main>. It survives every page change,\n * so it needs no id to disambiguate it.\n */\nclass LbHub extends HTMLElement {\n private main!: HTMLElement;\n\n /**\n * The stub of the page in <main>. A page declares its own requests, so a\n * request says which page it came from, on the path below the endpoint.\n */\n private page = \"\";\n\n /**\n * Set when a page is entered, and cleared once its queries have landed\n * and focus has gone to its first control. A change of query parm on the\n * same page does not set it: the user is where they chose to be.\n */\n private entering = false;\n\n connectedCallback() {\n this.main = this.querySelector(\"main\")!;\n\n // Completed in the capture phase, on the way down, so every ancestor\n // that sees the request on its way back up sees it whole. A request that\n // cannot be issued is stopped here, before anything sees it at all.\n this.addEventListener(\n LB_EVENT_NAME,\n (e: Event) => {\n const origin = e.target as Element;\n const request = (e as CustomEvent<HubRequest>).detail;\n if (!complete(request, origin)) e.stopPropagation();\n },\n { capture: true },\n );\n\n this.addEventListener(LB_EVENT_NAME, (e: Event) => {\n const request = (e as CustomEvent<HubRequest>).detail;\n // The element that issued the request, not e.currentTarget (the hub\n // itself, since the event bubbles).\n const origin = (e.target as Element | null) ?? undefined;\n if (request.query?.startsWith(LB_RESERVED_PREFIX)) {\n void this.answer(request, origin);\n return;\n }\n void this.send(request, origin);\n });\n\n // A form commits on submit. The submitter's own lb-request replaces the\n // form's, the way `formaction` replaces `action`.\n this.addEventListener(\"submit\", (e: SubmitEvent) => {\n const form = e.target as Element | null;\n if (!form) return;\n const submitter = e.submitter;\n const el = submitter?.hasAttribute(ATTR_REQUEST)\n ? submitter\n : form.hasAttribute(ATTR_REQUEST)\n ? form\n : null;\n if (!el) return;\n e.preventDefault();\n commit(el);\n });\n\n // A reset returns a form's controls to their defaults, so none of them\n // shows what landed any longer. The browser resets the controls; the\n // hub drops its own stamp from the same controls a submit gathers.\n this.addEventListener(\"reset\", (e: Event) => {\n if (e.defaultPrevented) return;\n for (const el of controlsOf(e.target as HTMLFormElement)) {\n el.removeAttribute(ATTR_COLUMN_VALUE);\n }\n });\n\n // A control commits on change.\n this.addEventListener(\"change\", (e: Event) => {\n const el = e.target as Element | null;\n if (!el || !el.hasAttribute(ATTR_REQUEST) || !isControl(el)) return;\n commit(el);\n });\n\n // Anything else commits on click. A form commits on submit, a control on\n // change, and a submit button with its form. A click on interactive\n // content inside the element is that content's own.\n this.addEventListener(\"click\", (e: MouseEvent) => {\n const target = e.target as Element | null;\n const el = target?.closest(`[${ATTR_REQUEST}]`);\n if (!target || !el || !this.contains(el)) return;\n if (el.localName === \"form\" || isControl(el) || isSubmitButton(el)) {\n return;\n }\n if (!clicks(target, el)) return;\n e.preventDefault();\n commit(el);\n });\n\n // A link that opted in. Everything else is a real link, and so is a\n // click that opens a new tab or window. The link's URL is a row for\n // lb-url: its path, its query parms, and every other parm emptied. A\n // link pushes a history entry, as a link does.\n this.addEventListener(\"click\", (e: MouseEvent) => {\n const link = (e.target as Element | null)?.closest(`a[${ATTR_URL_LINK}]`);\n if (!link || !isPlainClick(e)) return;\n e.preventDefault();\n const href = new URL((link as HTMLAnchorElement).href);\n const row: Row = {};\n for (const name of new URLSearchParams(location.search).keys()) {\n row[name] = \"\";\n }\n for (const [name, value] of href.searchParams) row[name] = value;\n row[URL_COLUMN_PATH] = href.pathname;\n this.moveTo(row, true);\n void this.navigate();\n });\n\n addEventListener(\"popstate\", () => void this.navigate());\n\n void this.navigate();\n }\n\n /**\n * Send a request to the server and land its answer. An answer naming\n * `lb-url` moves the URL first; the server has already loaded the page\n * there, in the same round trip.\n */\n private async send(request: HubRequest, origin?: Element): Promise<void> {\n const at = here();\n const items = await this.roundTrip(this.page, request, origin);\n if (items instanceof Error) return done(origin, request, items);\n let landed: ResponseItem[] = [];\n // The server answered for the URL the request was sent from. A user who\n // moved while it was in flight, to another page or to other parms, is\n // looking at something it says nothing about, and on a URL that is not\n // the server's to change. The write still happened.\n if (here() === at) {\n const url = items.find((item) => item.query === URL_QUERY);\n const load = items.filter((item) => item !== url);\n landed = load;\n if (url === undefined) applyResponse(this, load);\n else landed = await this.follow(url, load, origin);\n }\n insertedFrom.get(request)?.reset();\n done(origin, request, landed);\n }\n\n /**\n * One round trip for a page: a request, or with none a page load. The\n * element that issued it carries `lb-request-pending` while it is in\n * flight, and `lb-request-error` when it fails. The error on failure.\n */\n private async roundTrip(\n page: string,\n request: HubRequest | undefined,\n origin: Element | undefined,\n ): Promise<HubResponse | Error> {\n pending(origin, true);\n try {\n return await fetchItems(page, request);\n } catch (err) {\n console.error(`lb-hub: request failed for '${page}'`, err);\n origin?.setAttribute(ATTR_REQUEST_ERROR, \"\");\n return err instanceof Error ? err : new Error(String(err));\n } finally {\n pending(origin, false);\n }\n }\n\n /**\n * Answer a request for a query the hub serves, with no round trip. The\n * hub serves `lb-url`, and updates it.\n */\n private async answer(request: HubRequest, origin?: Element): Promise<void> {\n if (request.query !== URL_QUERY || request.name !== REQUEST_ROW_UPDATE) {\n const message =\n `lb-hub: '${request.name}' for '${request.query}' is not a request ` +\n `the hub answers, ignoring`;\n console.error(message);\n return done(origin, request, new Error(message));\n }\n const pushed = origin?.hasAttribute(ATTR_URL_PUSH) ?? false;\n const moved = this.moveTo(request.values ?? {}, pushed);\n done(origin, request, moved ? await this.navigate(origin) : []);\n }\n\n /**\n * Write a row for `lb-url` into the URL. A new page pushes a history\n * entry, and so does `push`; a change of query parms replaces the entry.\n * False when the URL is already the row's.\n */\n private moveTo(row: Row, push: boolean): boolean {\n const { url, moved } = nextUrl(row);\n if (url.href === location.href) return false;\n if (moved || push) history.pushState(null, \"\", url);\n else history.replaceState(null, \"\", url);\n return true;\n }\n\n /**\n * A server answer named `lb-url`: write the URL, then land the page the\n * server loaded there. A load that did not come back is asked for again,\n * without marking the element that issued the request: its write\n * succeeded, and an error would invite sending it twice.\n *\n * What landed: the `lb-url` item and the load, however it arrived. A load\n * asked for again that fails is not the request's failure.\n */\n private async follow(\n item: ResponseItem,\n load: ResponseItem[],\n origin?: Element,\n ): Promise<ResponseItem[]> {\n this.moveTo(item.row ?? {}, origin?.hasAttribute(ATTR_URL_PUSH) ?? false);\n if (load.length === 0) {\n const again = await this.navigate();\n return again instanceof Error ? [item] : [item, ...again];\n }\n const template = this.arrive();\n if (template) applyResponse(this, load);\n this.entered();\n return template ? [item, ...load] : [item];\n }\n\n /**\n * Load the page at the URL the browser is showing. Every way of arriving\n * comes through here — a cold load, a link, Back, a new query parm — so\n * each is the same page load and a URL always shows the same thing.\n *\n * Entering a page is the one operation that replaces what <main> holds.\n * Staying on it, with only the query parms changed, keeps what it has: the\n * queries re-run and land by key, so rows that come back keep their place.\n *\n * `origin` is the element whose request changed the URL, if one did, and\n * carries the round trip's pending and error state.\n *\n * What landed, or the error when the round trip failed. A load that\n * returns after the URL has moved again lands nothing: the load for where\n * the browser is now is already on its way, and may be here.\n */\n private async navigate(origin?: Element): Promise<ResponseItem[] | Error> {\n const template = this.arrive();\n if (!template) return [];\n const at = here();\n const items = await this.roundTrip(this.page, undefined, origin);\n if (here() !== at) return items instanceof Error ? items : [];\n const landed = items instanceof Error ? [] : items;\n applyResponse(this, landed);\n this.entered();\n return items instanceof Error ? items : landed;\n }\n\n /**\n * A page that was entered has landed its queries, so its first control\n * exists: a row cloned, a branch shown, a picker's options in place.\n */\n private entered(): void {\n if (!this.entering) return;\n this.entering = false;\n focusFirst(this.main);\n }\n\n /**\n * Show the page the path names, and land `lb-url`. Null when no page's\n * stub matches the path.\n */\n private arrive(): HTMLTemplateElement | null {\n const page = pageNameFor(location.pathname);\n const template = pageHostFor(page);\n if (template && page !== this.page) {\n this.page = page;\n // The template is already in the document, so the page's markup goes\n // in before its data arrives rather than leaving <main> empty. What\n // the last page's queries answered goes with it.\n this.main.replaceChildren(template.content.cloneNode(true));\n forget(this);\n this.entering = true;\n }\n this.landUrl(template ? titleOf(template, page) : null);\n // An app that ships `<body hidden>` (docs/reference/chrome.md) stays\n // invisible until there is something coherent to show.\n document.body.hidden = false;\n if (!template) {\n console.error(`lb-hub: no page for '${page}'`);\n const dialog = this.querySelector(`dialog[${ATTR_URL_UNKNOWN}]`);\n if (dialog && !(dialog as HTMLDialogElement).open) {\n (dialog as HTMLDialogElement).showModal();\n }\n }\n return template;\n }\n\n /**\n * The hub's own query: one row, keyed by the path, whose other columns are\n * the query parms.\n *\n * The one exception to landing. A row sets the columns it names and\n * leaves the rest as they were, and a URL names only the parms it carries.\n * So the row also names, as empty, every column an element under\n * `lb-query=\"lb-url\"` shows: a control then shows what the address bar\n * says after Back as well as after a reload, and never a parm the URL has\n * dropped.\n */\n private landUrl(label: string | null): void {\n if (label !== null) document.title = label;\n const scopes = this.querySelectorAll(`[${ATTR_QUERY}=\"${URL_QUERY}\"]`);\n if (scopes.length === 0) return;\n const row: Row = {};\n for (const scope of scopes) {\n for (const el of within(scope, `[${ATTR_COLUMN}]`)) {\n if (el === scope) continue;\n row[el.getAttribute(ATTR_COLUMN)!] = \"\";\n }\n }\n for (const [name, value] of new URLSearchParams(location.search)) {\n row[name] = value;\n }\n row[URL_COLUMN_PATH] = location.pathname;\n row[URL_COLUMN_PAGE_LABEL] = label;\n row[URL_COLUMN_PAGE_UNKNOWN] = label === null;\n applyResponse(this, [\n { query: URL_QUERY, kind: KIND_ROW, key: URL_COLUMN_PATH, row },\n ]);\n }\n}\n\ncustomElements.define(HUB_TAG_NAME, LbHub);\n"]}
|
|
1
|
+
{"version":3,"file":"lb-hub.browser.js","sourceRoot":"","sources":["../../hub/lb-hub.browser.ts"],"names":[],"mappings":"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","sourcesContent":["/// <reference lib=\"dom\" />\n\nimport {\n ATTR_COLUMN,\n ATTR_COLUMN_VALUE,\n ATTR_KEY_VALUE,\n ATTR_PAGE,\n ATTR_PAGE_TITLE,\n ATTR_QUERY,\n ATTR_REQUEST,\n ATTR_REQUEST_ERROR,\n ATTR_REQUEST_PENDING,\n ATTR_REQUEST_REFUSED,\n ATTR_ROW_EDITING,\n ATTR_SELECT,\n ATTR_URL_LINK,\n ATTR_URL_PUSH,\n ATTR_URL_UNKNOWN,\n COMMAND_EDIT,\n COMMAND_NEW,\n COMMAND_RELEASE,\n HUB_TAG_NAME,\n KIND_ROW,\n LB_DONE_EVENT_NAME,\n LB_ENDPOINT,\n LB_EVENT_NAME,\n LB_REFUSAL_STATUS,\n LB_REQUEST_TIMEOUT_MS,\n LB_COMMAND_PREFIX,\n LB_RESERVED_PREFIX,\n LIVE_ROW,\n ORDER_PARM_PREFIX,\n REQUEST_ROW_DELETE,\n REQUEST_ROW_INSERT,\n REQUEST_ROW_UPDATE,\n URL_COLUMN_PAGE_LABEL,\n URL_COLUMN_PAGE_UNKNOWN,\n URL_COLUMN_PATH,\n URL_QUERY,\n} from \"../core/lb-constants.js\";\nimport {\n isRowRequest,\n nextLocation,\n orderParm,\n pageNameFor,\n type GatheredRow,\n type HubRefusal,\n type HubRequest,\n type HubRequestDone,\n type HubResponse,\n type ResponseItem,\n type Row,\n} from \"../core/lb-types.js\";\nimport {\n applyResponse,\n applyRow,\n blankRow,\n controlValue,\n select,\n forget,\n isControl,\n isFormAssociated,\n keptAnswer,\n reland,\n within,\n type Control,\n type LandOptions,\n} from \"./lb-apply.js\";\n\nexport { applyResponse, applyRow } from \"./lb-apply.js\";\n\n/** What each request Loadbare provides cannot be issued without. */\nconst NEEDS: Record<string, readonly (keyof HubRequest)[]> = {\n [REQUEST_ROW_INSERT]: [\"query\", \"values\"],\n [REQUEST_ROW_UPDATE]: [\"query\", \"key\", \"values\"],\n [REQUEST_ROW_DELETE]: [\"query\", \"key\"],\n};\n\n/** The nearest ancestor carrying `lb-query`. An element is not its own. */\nfunction queryOf(el: Element): Element | null {\n return el.parentElement?.closest(`[${ATTR_QUERY}]`) ?? null;\n}\n\n/** The live row an element is, or is in. */\nfunction liveRowOf(el: Element): Element | null {\n return el.closest(LIVE_ROW);\n}\n\n/**\n * The key of the nearest ancestor row, when that row is of `query`: a live\n * row whose query it is, or the element a `row` of it landed on.\n */\nfunction keyFrom(el: Element, query: Element): string | undefined {\n // A live row is its own row; any other element's row is an ancestor.\n const row = el.matches(LIVE_ROW)\n ? el\n : el.parentElement?.closest(`[${ATTR_KEY_VALUE}]`);\n if (!row) return undefined;\n // A live row's key is its outer query's, even when the row names a query\n // of its own. Any other element's key is its own query's.\n const ofQuery = row.matches(LIVE_ROW)\n ? queryOf(row) === query\n : row === query;\n return ofQuery ? (row.getAttribute(ATTR_KEY_VALUE) ?? undefined) : undefined;\n}\n\n/**\n * Every control whose form owner is `form`: HTML's own list, which holds a\n * control nested in the form or joined to it by the `form` attribute, and a\n * form-associated custom element as well as a native control.\n */\nfunction controlsOf(form: HTMLFormElement): Element[] {\n return [...(form.elements as unknown as Iterable<Element>)];\n}\n\n/**\n * The form owner of an element that has one, as HTML reports it on the\n * element's `form` property.\n */\nfunction formOwnerOf(el: Element): HTMLFormElement | null {\n const owner = (el as { form?: unknown }).form;\n return owner && (owner as Element).localName === \"form\"\n ? (owner as HTMLFormElement)\n : null;\n}\n\n/** The group a request gathers from. */\ninterface Group {\n controls: Element[];\n /** Set when the group is a form, so a successful insert resets it. */\n form?: HTMLFormElement;\n /** What the group is: the form or the live row. */\n root: Element;\n}\n\n/**\n * The controls a request gathers — see docs/reference/data-binding.md,\n * \"Gathering\":\n *\n * 1. the element carrying `lb-request` has `lb-column`: it alone;\n * 2. the element is a `<form>`: the controls whose form owner it is;\n * 3. the element is in a live row: the controls in that live row;\n * 4. otherwise: the controls whose form owner is the element's.\n *\n * A control whose nearest `lb-query` is inside the group belongs to a query\n * nested in it, and is skipped.\n */\nfunction groupFor(el: Element): Group | null {\n if (el.hasAttribute(ATTR_COLUMN)) return { controls: [el], root: el };\n if (el.localName === \"form\") {\n const form = el as HTMLFormElement;\n return { controls: controlsOf(form), form, root: form };\n }\n const live = liveRowOf(el);\n if (live) return { controls: within(live, `[${ATTR_COLUMN}]`), root: live };\n const form = formOwnerOf(el);\n if (form) return { controls: controlsOf(form), form, root: form };\n return null;\n}\n\n/**\n * The gathered controls, with their values under their columns.\n *\n * A form also gathers the live rows of a query nested in its own, each with\n * the values of its own controls, under the nested query's name: a master's\n * details, entered beside it. One level only, since a query nested deeper\n * shows the same rows in every row around it, and its keys would repeat. A\n * live row gathers nothing nested.\n */\nfunction gather(group: Group | null): {\n controls: Control[];\n values: Record<string, string>;\n rows: Record<string, GatheredRow[]>;\n nestedControls: Control[];\n /** The element naming the form's own query, when the group is a form. */\n own: Element | null;\n} {\n const controls: Control[] = [];\n const values: Record<string, string> = {};\n const nestedControls: Control[] = [];\n const byQuery = new Map<string, Map<string, Record<string, string>>>();\n const form = group?.form;\n const own = form\n ? form.hasAttribute(ATTR_QUERY)\n ? form\n : queryOf(form)\n : null;\n for (const el of group?.controls ?? []) {\n const column = el.getAttribute(ATTR_COLUMN);\n if (column === null || !isControl(el)) continue;\n const nested = queryOf(el);\n if (nested && nested !== group!.root && group!.root.contains(nested)) {\n const live = liveRowOf(el);\n if (\n own &&\n queryOf(nested) === own &&\n live &&\n queryOf(live) === nested\n ) {\n const name = nested.getAttribute(ATTR_QUERY)!;\n const key = live.getAttribute(ATTR_KEY_VALUE)!;\n const set = byQuery.get(name) ?? new Map();\n byQuery.set(name, set);\n const row = set.get(key) ?? {};\n set.set(key, row);\n row[column] = controlValue(el);\n nestedControls.push(el);\n }\n continue;\n }\n controls.push(el);\n values[column] = controlValue(el);\n }\n const rows: Record<string, GatheredRow[]> = {};\n for (const [name, set] of byQuery) {\n rows[name] = [...set].map(([key, row]) => ({ key, values: row }));\n }\n return { controls, values, rows, nestedControls, own };\n}\n\n/** The controls each request gathered, so a refusal can find them. */\nconst gatheredFrom = new WeakMap<HubRequest, Element[]>();\n\n/** A request's round trip came back refused, with the handler's words. */\nclass RefusedError extends Error {\n constructor(readonly refusal: HubRefusal) {\n super(refusal.message ?? \"refused\");\n this.name = \"RefusedError\";\n }\n}\n\n/**\n * A refusal on show: the controls its request gathered, the controls that\n * carry its messages, and the element that committed, stamped with its\n * message. It stands until the user edits any control the request gathered,\n * since that makes a new question of the next submit.\n */\ninterface Shown {\n gathered: Element[];\n marked: Element[];\n origin: Element | undefined;\n}\n\nconst shown: Shown[] = [];\n\n/** A control that takes a message the way HTML's own do. */\ninterface Validates {\n setCustomValidity(message: string): void;\n reportValidity(): boolean;\n}\n\nfunction validates(el: Element): el is Element & Validates {\n const v = el as Partial<Validates>;\n return (\n typeof v.setCustomValidity === \"function\" &&\n typeof v.reportValidity === \"function\"\n );\n}\n\n/** Take a refusal off show: its messages, and the stamp on its origin. */\nfunction withdraw(refused: Shown): void {\n for (const el of refused.marked) (el as Element & Validates).setCustomValidity(\"\");\n refused.origin?.removeAttribute(ATTR_REQUEST_REFUSED);\n shown.splice(shown.indexOf(refused), 1);\n}\n\n/** Withdraw every refusal whose request gathered `el`, or what holds it. */\nfunction edited(target: Element): void {\n for (const refused of [...shown]) {\n if (refused.gathered.some((c) => c === target || c.contains(target))) {\n withdraw(refused);\n }\n }\n}\n\n/** The form each insert gathered from, until its round trip succeeds. */\nconst insertedFrom = new WeakMap<HubRequest, HTMLFormElement>();\n\n/**\n * Every form a button has pointed, with the live row it is pointed at: null\n * when it was started empty, for an insert.\n */\nconst pointed = new WeakMap<HTMLFormElement, Element | null>();\n\n/** The pointed form each request gathered from, until it succeeds. */\nconst savedFrom = new WeakMap<HubRequest, HTMLFormElement>();\n\n/**\n * The `lb-select` checkboxes showing for a query, under the hub an element\n * is in. One parked by `lb-show` is in template content, out of reach, so\n * only a selection the user can see counts.\n */\nfunction selectorsFor(el: Element, query: string): HTMLInputElement[] {\n const root = el.closest(HUB_TAG_NAME) ?? el.ownerDocument;\n return [...root.querySelectorAll<HTMLInputElement>(`[${ATTR_SELECT}]`)].filter(\n (box) => {\n const live = liveRowOf(box);\n return live !== null && queryOf(live)?.getAttribute(ATTR_QUERY) === query;\n },\n );\n}\n\n/** The keys of the rows a query's showing checkboxes select. */\nfunction selectedKeys(boxes: HTMLInputElement[]): string[] {\n return boxes\n .filter((box) => box.checked)\n .map((box) => liveRowOf(box)!.getAttribute(ATTR_KEY_VALUE)!);\n}\n\n/**\n * Complete a request from where its element sits. Every request passes\n * through here, whoever issued it; a field it already carries is its\n * issuer's to decide and is left as it is.\n *\n * False when the request cannot be issued, having said why, or when it is\n * an update or delete for a row not yet entered, which is not sent.\n */\nfunction complete(request: HubRequest | undefined, el: Element): boolean {\n if (!request?.name) {\n console.warn(`lb-hub: a request without a name, ignoring`, request);\n return false;\n }\n const { name } = request;\n if (name.startsWith(LB_RESERVED_PREFIX) && !isRowRequest(name)) {\n console.error(\n `lb-hub: '${name}' begins with '${LB_RESERVED_PREFIX}' but names no ` +\n `request Loadbare provides, ignoring`,\n );\n return false;\n }\n\n const group = groupFor(el);\n const { controls, values, rows, nestedControls, own } = gather(group);\n gatheredFrom.set(request, [...controls, ...nestedControls]);\n if (request.values === undefined && controls.length > 0) {\n request.values = values;\n }\n // A form's nested rows go with what it writes, and not with a delete. A\n // form of nested rows alone still writes, with no values of its own.\n if (\n request.rows === undefined &&\n Object.keys(rows).length > 0 &&\n name !== REQUEST_ROW_DELETE\n ) {\n request.rows = rows;\n request.values ??= {};\n }\n\n // The request is for the nearest `lb-query` of what it gathered, or of the\n // element itself when it gathered nothing.\n const queries = new Set(controls.map(queryOf));\n if (queries.size > 1) {\n console.error(\n `lb-hub: '${name}' gathered controls of more than one query, not sent`,\n el,\n );\n return false;\n }\n // A form of nested rows alone is for its own query, and keyed by the row\n // landed on it or the row it is pointed at, if any.\n if (controls.length === 0 && nestedControls.length > 0 && own) {\n request.query ??= own.getAttribute(ATTR_QUERY)!;\n const key = own.getAttribute(ATTR_KEY_VALUE);\n if (key !== null) request.key ??= key;\n } else {\n const from = controls[0] ?? el;\n const query = controls.length > 0 ? [...queries][0]! : queryOf(el);\n if (query) {\n request.query ??= query.getAttribute(ATTR_QUERY)!;\n const key = keyFrom(from, query);\n if (key !== undefined) request.key ??= key;\n }\n }\n\n if (name === REQUEST_ROW_INSERT && group?.form) {\n insertedFrom.set(request, group.form);\n }\n if (group?.form && pointed.has(group.form)) {\n savedFrom.set(request, group.form);\n }\n\n // A row not yet entered: its key is empty, from a `row` the server\n // answered with no key yet, or from a form New pointed. It has no key to\n // send, and nothing on record to update or delete, so those two are not\n // sent. That is the row's state, not a mistake, and nothing is reported.\n const unentered = request.key === \"\";\n if (unentered) {\n delete request.key;\n if (name === REQUEST_ROW_UPDATE || name === REQUEST_ROW_DELETE) {\n return false;\n }\n }\n\n // A request that names no one row acts on the rows the user selected,\n // when its query shows checkboxes to select them by. An insert adds a row\n // and selects nothing. With none ticked, an update or a delete has\n // nothing to act on, and is not sent, as for a row not yet entered.\n if (\n request.key === undefined &&\n request.keys === undefined &&\n request.query !== undefined &&\n !unentered &&\n name !== REQUEST_ROW_INSERT\n ) {\n const boxes = selectorsFor(el, request.query);\n if (boxes.length > 0) {\n request.keys = selectedKeys(boxes);\n if (\n request.keys.length === 0 &&\n (name === REQUEST_ROW_UPDATE || name === REQUEST_ROW_DELETE)\n ) {\n return false;\n }\n }\n }\n\n const needs = NEEDS[name];\n if (needs) {\n const missing = needs.filter(\n (field) =>\n (request[field] === undefined &&\n !(field === \"key\" && request.keys !== undefined)) ||\n (field === \"values\" &&\n Object.keys(request.values!).length === 0 &&\n request.rows === undefined),\n );\n if (missing.length > 0) {\n console.error(\n `lb-hub: '${name}' from <${el.localName}> has no ` +\n `${missing.join(\", \")}, not sent`,\n el,\n );\n return false;\n }\n }\n return true;\n}\n\n/**\n * Commit: dispatch the request an element names, for the hub to complete. A\n * commit on an element whose round trip is in flight is ignored.\n */\nfunction commit(el: Element): void {\n if (el.hasAttribute(ATTR_REQUEST_PENDING)) return;\n const detail: HubRequest = { name: el.getAttribute(ATTR_REQUEST)! };\n el.dispatchEvent(new CustomEvent(LB_EVENT_NAME, { bubbles: true, detail }));\n}\n\n/** A submit button with a form owner commits with its form, never on click. */\nfunction isSubmitButton(el: Element): boolean {\n const type = (el as HTMLInputElement).type as string;\n const submits =\n (el.localName === \"button\" && type === \"submit\") ||\n (el.localName === \"input\" && (type === \"submit\" || type === \"image\"));\n return submits && formOwnerOf(el) !== null;\n}\n\n/**\n * HTML's interactive content: elements a click already means something to.\n * HTML forbids nesting them inside `<a>` or `<button>` so a click means one\n * thing, and the hub draws the same line.\n */\nconst INTERACTIVE = [\n \"a[href]\",\n \"button\",\n \"input:not([type=hidden])\",\n \"select\",\n \"textarea\",\n \"label\",\n \"details\",\n \"iframe\",\n \"embed\",\n \"audio[controls]\",\n \"video[controls]\",\n \"img[usemap]\",\n].join(\", \");\n\n/**\n * Whether a click on `target` is the click of `el`, the element carrying\n * `lb-request` above it: no interactive content lies between them. A click on\n * a control, link or button inside `el` belongs to that element.\n */\nfunction clicks(target: Element, el: Element): boolean {\n for (let node: Element | null = target; node && node !== el;) {\n if (node.matches(INTERACTIVE) || isFormAssociated(node)) return false;\n node = node.parentElement;\n }\n return true;\n}\n\n/** The page file's title, or its stub when it has none. */\nfunction titleOf(template: HTMLTemplateElement | null, page: string): string {\n return template?.getAttribute(ATTR_PAGE_TITLE) || page;\n}\n\n/**\n * The `<template>` a page ships in. The builder guarantees one per stub\n * (build/locations.ts refuses two page files sharing one), so a second match\n * here means the document was assembled by something else.\n */\nfunction pageHostFor(page: string): HTMLTemplateElement | null {\n const hosts: HTMLTemplateElement[] = [];\n for (const el of document.querySelectorAll(`template[${ATTR_PAGE}]`)) {\n if (el.getAttribute(ATTR_PAGE) === page) {\n hosts.push(el as HTMLTemplateElement);\n }\n }\n if (hosts.length > 1) {\n console.error(\n `lb-hub: ${hosts.length} pages carry ${ATTR_PAGE}=\"${page}\", ` +\n `using the first`,\n );\n }\n return hosts[0] ?? null;\n}\n\n/**\n * One round trip against the client-side deadline. Throws on a non-ok\n * response, a network failure or a timeout, so a caller can tell a failed\n * request from an empty answer.\n *\n * The stub names the path below the endpoint and the query string the\n * browser is showing rides after it verbatim, so every round trip reaches\n * the server with the query parms in hand.\n */\nasync function fetchItems(\n page: string,\n request?: HubRequest,\n): Promise<HubResponse> {\n const path = page.split(\"/\").map(encodeURIComponent).join(\"/\");\n const url = `${LB_ENDPOINT}/${path}${location.search}`;\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), LB_REQUEST_TIMEOUT_MS);\n try {\n // An empty body is how the hub asks for the page's queries.\n const res = await fetch(url, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\" },\n body: JSON.stringify(request ?? {}),\n signal: controller.signal,\n });\n if (res.status === LB_REFUSAL_STATUS) {\n const body = (await res.json().catch(() => ({}))) as {\n refusal?: HubRefusal;\n };\n throw new RefusedError(body.refusal ?? {});\n }\n if (!res.ok) {\n throw new Error(`lb-hub: server responded ${res.status} for ${url}`);\n }\n return (await res.json()) as HubResponse;\n } finally {\n clearTimeout(timeout);\n }\n}\n\n/** An element's round trip is in flight, or is not. */\nfunction pending(el: Element | undefined, on: boolean): void {\n if (!el) return;\n if (on) {\n el.removeAttribute(ATTR_REQUEST_ERROR);\n el.removeAttribute(ATTR_REQUEST_REFUSED);\n el.setAttribute(ATTR_REQUEST_PENDING, \"\");\n el.setAttribute(\"aria-busy\", \"true\");\n } else {\n el.removeAttribute(ATTR_REQUEST_PENDING);\n el.removeAttribute(\"aria-busy\");\n }\n}\n\n/**\n * Tell the element that committed how its request turned out. Raised after\n * everything the request brought back has landed, so a listener sees the\n * page as the answer left it, and `lb-request-pending` is already gone.\n */\nfunction done(\n origin: Element | undefined,\n request: HubRequest,\n landed: ResponseItem[] | Error,\n): void {\n const detail: HubRequestDone =\n landed instanceof RefusedError\n ? { request, items: [], error: landed, refusal: landed.refusal }\n : landed instanceof Error\n ? { request, items: [], error: landed }\n : { request, items: landed };\n origin?.dispatchEvent(\n new CustomEvent(LB_DONE_EVENT_NAME, { bubbles: true, detail }),\n );\n}\n\n/** What can take focus, before asking whether it can be operated. */\nconst FOCUSABLE =\n `a[href], button, input:not([type=\"hidden\"]), select, textarea, ` +\n `summary, [tabindex]:not([tabindex=\"-1\"]), ` +\n `[contenteditable]:not([contenteditable=\"false\"])`;\n\n/**\n * Focus the first element in `main` the user can operate: not disabled, not\n * in a closed dialog, not inert, not hidden, and one that took the focus\n * when asked. Nothing in a `<template>` is a candidate, so an absent\n * `lb-show` branch is passed over. Focus already in `main` is the user's,\n * and is left where it is.\n */\nfunction focusFirst(main: HTMLElement): void {\n if (main.contains(document.activeElement)) return;\n focusIn(main);\n}\n\n/** Focus the first element in `root` the user can operate. */\nfunction focusIn(root: Element): void {\n for (const el of root.querySelectorAll<HTMLElement>(FOCUSABLE)) {\n if (el.matches(\":disabled\")) continue;\n if (el.closest(`dialog:not([open]), [inert], [hidden]`)) continue;\n if (el.checkVisibility?.() === false) continue;\n el.focus();\n if (document.activeElement === el) return;\n }\n}\n\n/**\n * Empty a form of whatever row it showed: every column it names lands as\n * null, so text and `lb-show` read as no row, and then the form resets, so\n * each control returns to its default.\n */\nfunction clear(form: HTMLFormElement): void {\n pointed.get(form)?.removeAttribute(ATTR_ROW_EDITING);\n applyRow(form, blankRow(form));\n form.reset();\n}\n\n/**\n * Point a form at a row: fill it from the row and key it by the row's key,\n * so gathering sends that key. With no row, the form starts empty and its\n * key is empty, for an insert. A form inside a `<dialog>` opens it.\n */\nfunction point(\n form: HTMLFormElement,\n row: Row | null,\n key: string,\n live: Element | null,\n): void {\n clear(form);\n if (row) applyRow(form, row);\n form.setAttribute(ATTR_KEY_VALUE, key);\n live?.setAttribute(ATTR_ROW_EDITING, \"\");\n pointed.set(form, live);\n const dialog = form.closest(\"dialog\");\n if (dialog && !dialog.open) dialog.showModal();\n focusIn(form);\n}\n\n/**\n * Let a pointed form go: empty it and drop its key. A form inside a\n * `<dialog>` closes it, and the dialog's `close` finds nothing left to do.\n */\nfunction release(form: HTMLFormElement): void {\n if (!pointed.has(form)) return;\n clear(form);\n form.removeAttribute(ATTR_KEY_VALUE);\n pointed.delete(form);\n const dialog = form.closest(\"dialog\");\n if (dialog?.open) dialog.close();\n}\n\n/**\n * The URL a round trip answers for: its path and its query string. An answer\n * that returns to another is not landed.\n */\nfunction here(): string {\n return location.pathname + location.search;\n}\n\n/** A plain primary click: no other button, no modifier, not yet handled. */\nfunction isPlainClick(e: MouseEvent): boolean {\n return (\n e.button === 0 &&\n !e.defaultPrevented &&\n !e.metaKey &&\n !e.ctrlKey &&\n !e.shiftKey &&\n !e.altKey\n );\n}\n\n/** The user's order for a query, from the parm the URL carries for it. */\nfunction orderFor(query: string): string | undefined {\n return new URLSearchParams(location.search).get(orderParm(query)) ?? undefined;\n}\n\n/** How everything the hub lands is landed: placed by the user's order. */\nconst LANDING: LandOptions = { orderFor };\n\n/** The URL a row for `lb-url` leads to, by the rule the server follows. */\nfunction nextUrl(row: Row): { url: URL; moved: boolean } {\n const url = new URL(location.href);\n const next = nextLocation(pageNameFor(url.pathname), url.searchParams, row);\n const path = row[URL_COLUMN_PATH];\n if (typeof path === \"string\") url.pathname = path;\n url.search = next.parms.toString();\n return { url, moved: next.moved };\n}\n\n/**\n * The hub is a singleton outside <main>. It survives every page change,\n * so it needs no id to disambiguate it.\n */\nclass LbHub extends HTMLElement {\n private main!: HTMLElement;\n\n /**\n * The stub of the page in <main>. A page declares its own requests, so a\n * request says which page it came from, on the path below the endpoint.\n */\n private page = \"\";\n\n /**\n * Set when a page is entered, and cleared once its queries have landed\n * and focus has gone to its first control. A change of query parm on the\n * same page does not set it: the user is where they chose to be.\n */\n private entering = false;\n\n connectedCallback() {\n this.main = this.querySelector(\"main\")!;\n\n // Completed in the capture phase, on the way down, so every ancestor\n // that sees the request on its way back up sees it whole. A request that\n // cannot be issued is stopped here, before anything sees it at all.\n this.addEventListener(\n LB_EVENT_NAME,\n (e: Event) => {\n const origin = e.target as Element;\n const request = (e as CustomEvent<HubRequest>).detail;\n if (!complete(request, origin)) e.stopPropagation();\n },\n { capture: true },\n );\n\n this.addEventListener(LB_EVENT_NAME, (e: Event) => {\n const request = (e as CustomEvent<HubRequest>).detail;\n // The element that issued the request, not e.currentTarget (the hub\n // itself, since the event bubbles).\n const origin = (e.target as Element | null) ?? undefined;\n if (request.query?.startsWith(LB_RESERVED_PREFIX)) {\n void this.answer(request, origin);\n return;\n }\n void this.send(request, origin);\n });\n\n // A form commits on submit. The submitter's own lb-request replaces the\n // form's, the way `formaction` replaces `action`.\n this.addEventListener(\"submit\", (e: SubmitEvent) => {\n const form = e.target as Element | null;\n if (!form) return;\n const submitter = e.submitter;\n const el = submitter?.hasAttribute(ATTR_REQUEST)\n ? submitter\n : form.hasAttribute(ATTR_REQUEST)\n ? form\n : null;\n if (!el) return;\n e.preventDefault();\n commit(el);\n });\n\n // A reset returns a form's controls to their defaults, so none of them\n // shows what landed any longer. The browser resets the controls; the\n // hub drops its own stamp from the same controls a submit gathers, and\n // any refusal they were answering.\n this.addEventListener(\"reset\", (e: Event) => {\n if (e.defaultPrevented) return;\n for (const el of controlsOf(e.target as HTMLFormElement)) {\n el.removeAttribute(ATTR_COLUMN_VALUE);\n edited(el);\n }\n });\n\n // An edit to anything a refused request gathered withdraws the refusal.\n // Heard on the way down, so a control's own request on change goes out\n // with its message already gone.\n for (const type of [\"input\", \"change\"]) {\n this.addEventListener(\n type,\n (e: Event) => {\n if (shown.length > 0) edited(e.target as Element);\n },\n { capture: true },\n );\n }\n\n // A selector selects its row, and is no column.\n this.addEventListener(\"change\", (e: Event) => {\n const box = e.target as Element | null;\n if (box?.hasAttribute(ATTR_SELECT)) {\n select(box, (box as HTMLInputElement).checked);\n }\n });\n\n // A control commits on change.\n this.addEventListener(\"change\", (e: Event) => {\n const el = e.target as Element | null;\n if (!el || !el.hasAttribute(ATTR_REQUEST) || !isControl(el)) return;\n commit(el);\n });\n\n // Anything else commits on click. A form commits on submit, a control on\n // change, and a submit button with its form. A click on interactive\n // content inside the element is that content's own.\n this.addEventListener(\"click\", (e: MouseEvent) => {\n const target = e.target as Element | null;\n const el = target?.closest(`[${ATTR_REQUEST}]`);\n if (!target || !el || !this.contains(el)) return;\n if (el.localName === \"form\" || isControl(el) || isSubmitButton(el)) {\n return;\n }\n if (!clicks(target, el)) return;\n e.preventDefault();\n commit(el);\n });\n\n // A link that opted in. Everything else is a real link, and so is a\n // click that opens a new tab or window. The link's URL is a row for\n // lb-url: its path, its query parms, and every other parm emptied. A\n // link pushes a history entry, as a link does.\n this.addEventListener(\"click\", (e: MouseEvent) => {\n const link = (e.target as Element | null)?.closest(`a[${ATTR_URL_LINK}]`);\n if (!link || !isPlainClick(e)) return;\n e.preventDefault();\n const href = new URL((link as HTMLAnchorElement).href);\n const row: Row = {};\n for (const name of new URLSearchParams(location.search).keys()) {\n row[name] = \"\";\n }\n for (const [name, value] of href.searchParams) row[name] = value;\n row[URL_COLUMN_PATH] = href.pathname;\n this.moveTo(row, true);\n void this.navigate();\n });\n\n // A button points a form with HTML's own commandfor and command. The\n // command event goes to the form and does not bubble, so it is heard on\n // the way down.\n this.addEventListener(\n \"command\",\n (e: Event) => {\n const { command, source } = e as Event & {\n command?: string;\n source?: Element | null;\n };\n if (!command?.startsWith(LB_COMMAND_PREFIX)) return;\n const form = e.target as Element;\n if (form.localName !== \"form\" || !form.hasAttribute(ATTR_QUERY)) {\n console.error(\n `lb-hub: '${command}' is for a <form> carrying ${ATTR_QUERY}, ` +\n `not <${form.localName}>, ignoring`,\n form,\n );\n return;\n }\n this.command(command, form as HTMLFormElement, source ?? null);\n },\n { capture: true },\n );\n\n // A dialog closes however HTML closes it — Escape, a close command,\n // `method=\"dialog\"` — and a form pointed inside it lets go.\n this.addEventListener(\n \"close\",\n (e: Event) => {\n const dialog = e.target as Element;\n if (dialog.localName !== \"dialog\") return;\n for (const form of dialog.querySelectorAll(\"form\")) release(form);\n },\n { capture: true },\n );\n\n addEventListener(\"popstate\", () => void this.navigate());\n\n void this.navigate();\n }\n\n /**\n * A command for a form. Edit fills the form from the row the button sits\n * in, as the hub holds it: no round trip, since the user can only edit a\n * row they can see.\n */\n private command(\n command: string,\n form: HTMLFormElement,\n source: Element | null,\n ): void {\n const query = form.getAttribute(ATTR_QUERY)!;\n switch (command) {\n case COMMAND_EDIT: {\n const live = source ? liveRowOf(source) : null;\n if (!live || queryOf(live)?.getAttribute(ATTR_QUERY) !== query) {\n console.error(\n `lb-hub: '${command}' comes from no row of '${query}', ignoring`,\n source,\n );\n return;\n }\n const key = live.getAttribute(ATTR_KEY_VALUE)!;\n const item = keptAnswer(this, query);\n const row = item?.rows?.find((r) => String(r[item.key]) === key);\n if (!row) {\n console.error(\n `lb-hub: the hub holds no row of '${query}' keyed '${key}', ` +\n `ignoring`,\n );\n return;\n }\n point(form, row, key, live);\n return;\n }\n case COMMAND_NEW:\n point(form, null, \"\", null);\n return;\n case COMMAND_RELEASE:\n release(form);\n return;\n default:\n console.error(\n `lb-hub: '${command}' begins with '${LB_COMMAND_PREFIX}' but ` +\n `names no command Loadbare provides, ignoring`,\n );\n }\n }\n\n /**\n * Send a request to the server and land its answer. An answer naming\n * `lb-url` moves the URL first; the server has already loaded the page\n * there, in the same round trip.\n */\n private async send(request: HubRequest, origin?: Element): Promise<void> {\n // Sending again answers the last refusal from here, whatever it said.\n for (const refused of shown.filter((r) => r.origin === origin)) {\n withdraw(refused);\n }\n const at = here();\n const items = await this.roundTrip(this.page, request, origin);\n if (items instanceof RefusedError) this.refused(request, items, origin);\n if (items instanceof Error) return done(origin, request, items);\n let landed: ResponseItem[] = [];\n // The server answered for the URL the request was sent from. A user who\n // moved while it was in flight, to another page or to other parms, is\n // looking at something it says nothing about, and on a URL that is not\n // the server's to change. The write still happened.\n if (here() === at) {\n const url = items.find((item) => item.query === URL_QUERY);\n const load = items.filter((item) => item !== url);\n landed = load;\n if (url === undefined) {\n applyResponse(this, load, { ...LANDING, requested: true });\n }\n else landed = await this.follow(url, load, origin);\n }\n // The selected rows have been acted on, and the selection is done.\n if (request.keys !== undefined && request.query !== undefined) {\n for (const box of selectorsFor(this, request.query)) select(box, false);\n }\n // A pointed form has done what it was pointed for, and lets go.\n const saved = savedFrom.get(request);\n if (saved) release(saved);\n else insertedFrom.get(request)?.reset();\n done(origin, request, landed);\n }\n\n /**\n * Show a refusal. The message for the request as a whole is stamped on the\n * element that committed, for a stylesheet to show. Each column's message\n * goes on the control the request gathered it from, as HTML's own\n * validity, and the first is reported: the browser shows its message\n * there and moves focus to it.\n */\n private refused(\n request: HubRequest,\n { refusal }: RefusedError,\n origin: Element | undefined,\n ): void {\n const gathered = gatheredFrom.get(request) ?? [];\n const marked: Element[] = [];\n for (const [column, message] of Object.entries(refusal.columns ?? {})) {\n const control = gathered.find(\n (c) => c.getAttribute(ATTR_COLUMN) === column,\n );\n if (!control || !validates(control)) {\n console.warn(\n `lb-hub: '${request.name}' was refused for '${column}', but ` +\n `gathered no control there that takes a message`,\n );\n continue;\n }\n control.setCustomValidity(message);\n marked.push(control);\n }\n origin?.setAttribute(ATTR_REQUEST_REFUSED, refusal.message ?? \"\");\n shown.push({ gathered, marked, origin });\n (marked[0] as (Element & Validates) | undefined)?.reportValidity();\n }\n\n /**\n * One round trip for a page: a request, or with none a page load. The\n * element that issued it carries `lb-request-pending` while it is in\n * flight, and `lb-request-error` when it fails. The error on failure.\n */\n private async roundTrip(\n page: string,\n request: HubRequest | undefined,\n origin: Element | undefined,\n ): Promise<HubResponse | Error> {\n pending(origin, true);\n try {\n return await fetchItems(page, request);\n } catch (err) {\n // A refusal is the handler's answer, not a failure: the request's\n // sender shows it, and nothing is reported.\n if (err instanceof RefusedError) return err;\n console.error(`lb-hub: request failed for '${page}'`, err);\n origin?.setAttribute(ATTR_REQUEST_ERROR, \"\");\n return err instanceof Error ? err : new Error(String(err));\n } finally {\n pending(origin, false);\n }\n }\n\n /**\n * Answer a request for a query the hub serves, with no round trip. The\n * hub serves `lb-url`, and updates it.\n */\n private async answer(request: HubRequest, origin?: Element): Promise<void> {\n if (request.query !== URL_QUERY || request.name !== REQUEST_ROW_UPDATE) {\n const message =\n `lb-hub: '${request.name}' for '${request.query}' is not a request ` +\n `the hub answers, ignoring`;\n console.error(message);\n return done(origin, request, new Error(message));\n }\n const pushed = origin?.hasAttribute(ATTR_URL_PUSH) ?? false;\n const was = new URL(location.href);\n if (!this.moveTo(request.values ?? {}, pushed)) {\n return done(origin, request, []);\n }\n if (this.sortHere(was)) return done(origin, request, []);\n done(origin, request, await this.navigate(origin));\n }\n\n /**\n * A change of URL that only changed the user's order for queries the hub\n * sorts itself: the rows are already here, so they are placed again with\n * no round trip. False when anything else changed, or a query whose order\n * changed reads the parm itself, and the page must load.\n */\n private sortHere(was: URL): boolean {\n if (was.pathname !== location.pathname) return false;\n const now = new URLSearchParams(location.search);\n const names = new Set([...was.searchParams.keys(), ...now.keys()]);\n const queries: string[] = [];\n for (const name of names) {\n if (was.searchParams.get(name) === now.get(name)) continue;\n if (!name.startsWith(ORDER_PARM_PREFIX)) return false;\n const query = name.slice(ORDER_PARM_PREFIX.length);\n const item = keptAnswer(this, query);\n if (!item || item.serverSortedByUrl) return false;\n queries.push(query);\n }\n this.arrive();\n for (const query of queries) reland(this, query);\n return true;\n }\n\n /**\n * Write a row for `lb-url` into the URL. A new page pushes a history\n * entry, and so does `push`; a change of query parms replaces the entry.\n * False when the URL is already the row's.\n */\n private moveTo(row: Row, push: boolean): boolean {\n const { url, moved } = nextUrl(row);\n if (url.href === location.href) return false;\n if (moved || push) history.pushState(null, \"\", url);\n else history.replaceState(null, \"\", url);\n return true;\n }\n\n /**\n * A server answer named `lb-url`: write the URL, then land the page the\n * server loaded there. A load that did not come back is asked for again,\n * without marking the element that issued the request: its write\n * succeeded, and an error would invite sending it twice.\n *\n * What landed: the `lb-url` item and the load, however it arrived. A load\n * asked for again that fails is not the request's failure.\n */\n private async follow(\n item: ResponseItem,\n load: ResponseItem[],\n origin?: Element,\n ): Promise<ResponseItem[]> {\n this.moveTo(item.row ?? {}, origin?.hasAttribute(ATTR_URL_PUSH) ?? false);\n if (load.length === 0) {\n const again = await this.navigate();\n return again instanceof Error ? [item] : [item, ...again];\n }\n const template = this.arrive();\n if (template) applyResponse(this, load, LANDING);\n this.entered();\n return template ? [item, ...load] : [item];\n }\n\n /**\n * Load the page at the URL the browser is showing. Every way of arriving\n * comes through here — a cold load, a link, Back, a new query parm — so\n * each is the same page load and a URL always shows the same thing.\n *\n * Entering a page is the one operation that replaces what <main> holds.\n * Staying on it, with only the query parms changed, keeps what it has: the\n * queries re-run and land by key, so rows that come back keep their place.\n *\n * `origin` is the element whose request changed the URL, if one did, and\n * carries the round trip's pending and error state.\n *\n * What landed, or the error when the round trip failed. A load that\n * returns after the URL has moved again lands nothing: the load for where\n * the browser is now is already on its way, and may be here.\n */\n private async navigate(origin?: Element): Promise<ResponseItem[] | Error> {\n const template = this.arrive();\n if (!template) return [];\n const at = here();\n const items = await this.roundTrip(this.page, undefined, origin);\n if (here() !== at) return items instanceof Error ? items : [];\n if (items instanceof Error) {\n this.entered();\n return items;\n }\n // Entering the page moved the URL, as an application restoring what the\n // user last had on screen does: the server loaded the page there.\n const url = items.find((item) => item.query === URL_QUERY);\n if (url) {\n return this.follow(\n url,\n items.filter((item) => item !== url),\n origin,\n );\n }\n applyResponse(this, items, LANDING);\n this.entered();\n return items;\n }\n\n /**\n * A page that was entered has landed its queries, so its first control\n * exists: a row cloned, a branch shown, a picker's options in place.\n */\n private entered(): void {\n if (!this.entering) return;\n this.entering = false;\n focusFirst(this.main);\n }\n\n /**\n * Show the page the path names, and land `lb-url`. Null when no page's\n * stub matches the path.\n */\n private arrive(): HTMLTemplateElement | null {\n const page = pageNameFor(location.pathname);\n const template = pageHostFor(page);\n if (template && page !== this.page) {\n this.page = page;\n // The template is already in the document, so the page's markup goes\n // in before its data arrives rather than leaving <main> empty. What\n // the last page's queries answered goes with it.\n this.main.replaceChildren(template.content.cloneNode(true));\n forget(this);\n this.entering = true;\n }\n this.landUrl(template ? titleOf(template, page) : null);\n // An app that ships `<body hidden>` (docs/reference/chrome.md) stays\n // invisible until there is something coherent to show.\n document.body.hidden = false;\n if (!template) {\n console.error(`lb-hub: no page for '${page}'`);\n const dialog = this.querySelector(`dialog[${ATTR_URL_UNKNOWN}]`);\n if (dialog && !(dialog as HTMLDialogElement).open) {\n (dialog as HTMLDialogElement).showModal();\n }\n }\n return template;\n }\n\n /**\n * The hub's own query: one row, keyed by the path, whose other columns are\n * the query parms.\n *\n * The one exception to landing. A row sets the columns it names and\n * leaves the rest as they were, and a URL names only the parms it carries.\n * So the row also names, as empty, every column an element under\n * `lb-query=\"lb-url\"` shows: a control then shows what the address bar\n * says after Back as well as after a reload, and never a parm the URL has\n * dropped.\n */\n private landUrl(label: string | null): void {\n if (label !== null) document.title = label;\n const scopes = this.querySelectorAll(`[${ATTR_QUERY}=\"${URL_QUERY}\"]`);\n if (scopes.length === 0) return;\n const row: Row = {};\n for (const scope of scopes) {\n for (const el of within(scope, `[${ATTR_COLUMN}]`)) {\n if (el === scope) continue;\n row[el.getAttribute(ATTR_COLUMN)!] = \"\";\n }\n }\n for (const [name, value] of new URLSearchParams(location.search)) {\n row[name] = value;\n }\n row[URL_COLUMN_PATH] = location.pathname;\n row[URL_COLUMN_PAGE_LABEL] = label;\n row[URL_COLUMN_PAGE_UNKNOWN] = label === null;\n applyResponse(\n this,\n [{ query: URL_QUERY, kind: KIND_ROW, key: URL_COLUMN_PATH, row }],\n LANDING,\n );\n }\n}\n\ncustomElements.define(HUB_TAG_NAME, LbHub);\n"]}
|
|
@@ -9,10 +9,12 @@
|
|
|
9
9
|
* One endpoint, and no second:
|
|
10
10
|
*
|
|
11
11
|
* POST /lb/<stub>?<query string>
|
|
12
|
-
* an empty body asks for the page's queries
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
12
|
+
* an empty body asks for the page's queries, or for
|
|
13
|
+
* the page loaded at the new URL its onPageEnter
|
|
14
|
+
* returned; a body carrying a request runs its
|
|
15
|
+
* handler and answers with the refresh set, or with
|
|
16
|
+
* the page loaded at the new URL the handler
|
|
17
|
+
* returned
|
|
16
18
|
*
|
|
17
19
|
* The page rides on the path rather than in the body, which is what lets the
|
|
18
20
|
* operation set stay closed. The query string is the one the browser is
|
|
@@ -21,8 +23,8 @@
|
|
|
21
23
|
* an application's own GET routes never collide with this one and no page
|
|
22
24
|
* name is reserved.
|
|
23
25
|
*/
|
|
24
|
-
import { type Request, type Router } from "express";
|
|
25
|
-
import type
|
|
26
|
+
import express, { type Request, type Router } from "express";
|
|
27
|
+
import { type Hub, type HubContext } from "./lb-server.js";
|
|
26
28
|
/**
|
|
27
29
|
* Building the context is the application's job — it is where an
|
|
28
30
|
* authenticated database handle comes from — so it is injected rather than
|
|
@@ -42,5 +44,15 @@ import type { Hub, HubContext } from "./lb-server.js";
|
|
|
42
44
|
* in a link, and are validated where they are read.
|
|
43
45
|
*/
|
|
44
46
|
export type ContextFor = (req: Request, parms: URLSearchParams) => HubContext;
|
|
45
|
-
|
|
47
|
+
/**
|
|
48
|
+
* The router's options, one key per concern.
|
|
49
|
+
*
|
|
50
|
+
* `json` is handed to `express.json()` untouched, so it takes whatever that
|
|
51
|
+
* takes. The one an application is likely to want is `limit`: the default
|
|
52
|
+
* of 100kb refuses a page that sends a file's text as a value.
|
|
53
|
+
*/
|
|
54
|
+
export interface HubRoutesOptions {
|
|
55
|
+
json?: Parameters<typeof express.json>[0];
|
|
56
|
+
}
|
|
57
|
+
export declare function hubRoutes(hub: Hub, contextFor: ContextFor, options?: HubRoutesOptions): Router;
|
|
46
58
|
//# sourceMappingURL=lb-express.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lb-express.d.ts","sourceRoot":"","sources":["../../server/lb-express.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"lb-express.d.ts","sourceRoot":"","sources":["../../server/lb-express.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH,OAAO,OAAO,EAAE,EAEd,KAAK,OAAO,EAEZ,KAAK,MAAM,EACZ,MAAM,SAAS,CAAC;AAWjB,OAAO,EAAW,KAAK,GAAG,EAAE,KAAK,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAEpE;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,MAAM,UAAU,GAAG,CAAC,GAAG,EAAE,OAAO,EAAE,KAAK,EAAE,eAAe,KAAK,UAAU,CAAC;AAE9E;;;;;;GAMG;AACH,MAAM,WAAW,gBAAgB;IAC/B,IAAI,CAAC,EAAE,UAAU,CAAC,OAAO,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;CAC3C;AAED,wBAAgB,SAAS,CACvB,GAAG,EAAE,GAAG,EACR,UAAU,EAAE,UAAU,EACtB,OAAO,GAAE,gBAAqB,GAC7B,MAAM,CA8IR"}
|
|
@@ -9,10 +9,12 @@
|
|
|
9
9
|
* One endpoint, and no second:
|
|
10
10
|
*
|
|
11
11
|
* POST /lb/<stub>?<query string>
|
|
12
|
-
* an empty body asks for the page's queries
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
12
|
+
* an empty body asks for the page's queries, or for
|
|
13
|
+
* the page loaded at the new URL its onPageEnter
|
|
14
|
+
* returned; a body carrying a request runs its
|
|
15
|
+
* handler and answers with the refresh set, or with
|
|
16
|
+
* the page loaded at the new URL the handler
|
|
17
|
+
* returned
|
|
16
18
|
*
|
|
17
19
|
* The page rides on the path rather than in the body, which is what lets the
|
|
18
20
|
* operation set stay closed. The query string is the one the browser is
|
|
@@ -22,13 +24,14 @@
|
|
|
22
24
|
* name is reserved.
|
|
23
25
|
*/
|
|
24
26
|
import express from "express";
|
|
25
|
-
import { LB_ENDPOINT, URL_QUERY } from "../core/lb-constants.js";
|
|
27
|
+
import { LB_ENDPOINT, LB_REFUSAL_STATUS, URL_QUERY, } from "../core/lb-constants.js";
|
|
26
28
|
import { nextLocation, } from "../core/lb-types.js";
|
|
27
|
-
|
|
29
|
+
import { Refusal } from "./lb-server.js";
|
|
30
|
+
export function hubRoutes(hub, contextFor, options = {}) {
|
|
28
31
|
const router = express.Router();
|
|
29
32
|
// Mounted here rather than on the app so that Hub's need for a parsed
|
|
30
33
|
// body is stated where the routes that need it are.
|
|
31
|
-
router.use(express.json());
|
|
34
|
+
router.use(express.json(options.json));
|
|
32
35
|
router.post(`${LB_ENDPOINT}/*page`, async (req, res) => {
|
|
33
36
|
// A page name may hold a slash, so the path below the endpoint is
|
|
34
37
|
// gathered whole.
|
|
@@ -42,7 +45,15 @@ export function hubRoutes(hub, contextFor) {
|
|
|
42
45
|
// page's queries. A body that carries something but no name is
|
|
43
46
|
// malformed.
|
|
44
47
|
if (request === undefined || Object.keys(request).length === 0) {
|
|
45
|
-
|
|
48
|
+
const items = await hub.dataForPage(page, ctx, { parms });
|
|
49
|
+
const moved = items.find((item) => item.query === URL_QUERY);
|
|
50
|
+
if (moved === undefined) {
|
|
51
|
+
res.json(items);
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
// onPageEnter moved the URL, so the page loads there, and that load
|
|
55
|
+
// does not follow onPageEnter again: no page can move the URL forever.
|
|
56
|
+
res.json(await loadAt(moved, nextLocation(page, parms, moved.row ?? {}), `entering '${page}'`));
|
|
46
57
|
return;
|
|
47
58
|
}
|
|
48
59
|
if (!request.name) {
|
|
@@ -54,11 +65,18 @@ export function hubRoutes(hub, contextFor) {
|
|
|
54
65
|
// "this request is invalid" or hits an unexpected failure — it resolves
|
|
55
66
|
// to a real response rather than an unhandled rejection, so the browser
|
|
56
67
|
// side has something to catch.
|
|
68
|
+
// A refusal carries words the handler wrote for the user, and goes to
|
|
69
|
+
// the browser with them. Anything else thrown is a failure, and goes
|
|
70
|
+
// with nothing, so a stack or a database message never reaches a page.
|
|
57
71
|
let items;
|
|
58
72
|
try {
|
|
59
73
|
items = await hub.runRequest(page, request, ctx);
|
|
60
74
|
}
|
|
61
75
|
catch (err) {
|
|
76
|
+
if (err instanceof Refusal) {
|
|
77
|
+
res.status(LB_REFUSAL_STATUS).json({ refusal: err.refusal });
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
62
80
|
console.error(`loadbare: '${request.name}' threw`, err);
|
|
63
81
|
res.status(500).json([]);
|
|
64
82
|
return;
|
|
@@ -73,29 +91,47 @@ export function hubRoutes(hub, contextFor) {
|
|
|
73
91
|
// here a failure must not read as the request failing, or the user would
|
|
74
92
|
// send it again. The item goes back alone instead, and the hub, writing
|
|
75
93
|
// the URL with nothing to land, loads the page itself.
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
94
|
+
res.json(await loadAt(moved, nextLocation(page, parms, moved.row ?? {}), `'${request.name}'`));
|
|
95
|
+
/**
|
|
96
|
+
* The `lb-url` item and the page loaded where it leads. A load that
|
|
97
|
+
* throws is not the failure of what moved the URL: the item goes back
|
|
98
|
+
* alone, and the hub, writing the URL with nothing to land, loads the
|
|
99
|
+
* page itself.
|
|
100
|
+
*/
|
|
101
|
+
async function loadAt(moved, next, what) {
|
|
102
|
+
try {
|
|
103
|
+
const load = await hub.dataForPage(next.page, contextFor(req, next.parms), { follow: false });
|
|
104
|
+
return [moved, ...load];
|
|
105
|
+
}
|
|
106
|
+
catch (err) {
|
|
107
|
+
console.error(`loadbare: ${what} moved the URL, and loading '${next.page}' ` +
|
|
108
|
+
`there threw`, err);
|
|
109
|
+
return [moved];
|
|
110
|
+
}
|
|
85
111
|
}
|
|
86
112
|
});
|
|
87
|
-
// A body that never parsed is refused like any
|
|
88
|
-
// rather than falling through to the
|
|
89
|
-
// would print a stack and call it a
|
|
90
|
-
// path: express.json() above sees
|
|
91
|
-
//
|
|
113
|
+
// A body that never parsed, or was too large to read, is refused like any
|
|
114
|
+
// other malformed request, rather than falling through to the
|
|
115
|
+
// application's error handler, which would print a stack and call it a
|
|
116
|
+
// server failure. Only for the hub's own path: express.json() above sees
|
|
117
|
+
// every request, and a bad body sent to one of the application's routes is
|
|
118
|
+
// the application's to answer.
|
|
92
119
|
router.use(`${LB_ENDPOINT}/*page`, (err, _req, res, next) => {
|
|
93
|
-
|
|
94
|
-
|
|
120
|
+
const { type, limit } = err;
|
|
121
|
+
if (type === "entity.parse.failed") {
|
|
122
|
+
console.warn(`loadbare: request body is not JSON`);
|
|
123
|
+
res.status(400).json([]);
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
if (type === "entity.too.large") {
|
|
127
|
+
// Named in the log, since nothing in the browser says which limit
|
|
128
|
+
// was hit or where to raise it.
|
|
129
|
+
console.warn(`loadbare: request body is over the limit of ${limit} bytes; ` +
|
|
130
|
+
`raise it with hubRoutes' json.limit option`);
|
|
131
|
+
res.status(413).json([]);
|
|
95
132
|
return;
|
|
96
133
|
}
|
|
97
|
-
|
|
98
|
-
res.status(400).json([]);
|
|
134
|
+
next(err);
|
|
99
135
|
});
|
|
100
136
|
return router;
|
|
101
137
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lb-express.js","sourceRoot":"","sources":["../../server/lb-express.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The Express adapter — the standard hand-off from an Express router to a\n * Hub built by createHub(). Every Hub application wires this same router,\n * which is why it ships from here rather than being copied into each one.\n *\n * Express itself is a peer dependency: nothing outside this file imports it,\n * so an application that hosts Hub some other way never pays for it.\n *\n * One endpoint, and no second:\n *\n * POST /lb/<stub>?<query string>\n * an empty body asks for the page's queries; a body\n * carrying a request runs its handler and answers\n * with the refresh set, or with the page loaded at\n * the new URL the handler returned\n *\n * The page rides on the path rather than in the body, which is what lets the\n * operation set stay closed. The query string is the one the browser is\n * showing, verbatim, and `contextFor` is handed its parms. What a parm means\n * is the application's: nothing here reads one. Every hub call is a POST, so\n * an application's own GET routes never collide with this one and no page\n * name is reserved.\n */\n\nimport express, {\n type NextFunction,\n type Request,\n type Response,\n type Router,\n} from \"express\";\nimport { LB_ENDPOINT, URL_QUERY } from \"../core/lb-constants.js\";\nimport {\n nextLocation,\n type HubRequest,\n type HubResponse,\n} from \"../core/lb-types.js\";\nimport type { Hub, HubContext } from \"./lb-server.js\";\n\n/**\n * Building the context is the application's job — it is where an\n * authenticated database handle comes from — so it is injected rather than\n * assumed. Whatever established identity has already run by the time this\n * router is reached; where that happens is the application's ordering\n * decision, not Hub's.\n *\n * The query parms arrive as `parms`, and are read there rather than off\n * `req.query`. The two agree except after a request that wrote parms: the\n * page is then loaded at the new query string in the same round trip, and\n * this is called a second time for that load, with the same `req` and the\n * new `parms`. So it must be safe to call twice for one request, and a\n * write must be visible to the second context by the time its `run`\n * returns.\n *\n * Parms are user input like any other, typed into an address bar or mailed\n * in a link, and are validated where they are read.\n */\nexport type ContextFor = (req: Request, parms: URLSearchParams) => HubContext;\n\nexport function hubRoutes(hub: Hub, contextFor: ContextFor): Router {\n const router = express.Router();\n\n // Mounted here rather than on the app so that Hub's need for a parsed\n // body is stated where the routes that need it are.\n router.use(express.json());\n\n router.post(`${LB_ENDPOINT}/*page`, async (req, res) => {\n // A page name may hold a slash, so the path below the endpoint is\n // gathered whole.\n const page = (req.params.page as string[]).join(\"/\");\n const request = req.body as HubRequest | undefined;\n // Parsed here rather than taken from req.query, so that the parms a\n // context is built from are the same kind of thing on both calls.\n const parms = new URL(req.originalUrl, \"http://localhost\").searchParams;\n const ctx = contextFor(req, parms);\n\n // No body at all is the page load: the browser is asking for this\n // page's queries. A body that carries something but no name is\n // malformed.\n if (request === undefined || Object.keys(request).length === 0) {\n res.json(await hub.dataForPage(page, ctx));\n return;\n }\n\n if (!request.name) {\n console.warn(`loadbare: request without a name`);\n res.status(400).json([]);\n return;\n }\n\n // A thrown error is how application code (a query, a handler) says\n // \"this request is invalid\" or hits an unexpected failure — it resolves\n // to a real response rather than an unhandled rejection, so the browser\n // side has something to catch.\n let items: HubResponse;\n try {\n items = await hub.runRequest(page, request, ctx);\n } catch (err) {\n console.error(`loadbare: '${request.name}' threw`, err);\n res.status(500).json([]);\n return;\n }\n\n const moved = items.find((item) => item.query === URL_QUERY);\n if (moved === undefined) {\n res.json(items);\n return;\n }\n // The handler returned a new row for lb-url, so the page loads there, as\n // a cold load of the new URL would. The handler has already run: from\n // here a failure must not read as the request failing, or the user would\n // send it again. The item goes back alone instead, and the hub, writing\n // the URL with nothing to land, loads the page itself.\n const { page: next, parms: nextParms } = nextLocation(\n page,\n parms,\n moved.row ?? {},\n );\n try {\n const load = await hub.dataForPage(next, contextFor(req, nextParms));\n res.json([moved, ...load]);\n } catch (err) {\n console.error(\n `loadbare: '${request.name}' moved the URL, and loading ` +\n `'${next}' there threw`,\n err,\n );\n res.json([moved]);\n }\n });\n\n // A body that never parsed is refused like any other malformed request,\n // rather than falling through to the application's error handler, which\n // would print a stack and call it a server failure. Only for the hub's own\n // path: express.json() above sees every request, and a bad body sent to one\n // of the application's routes is the application's to answer.\n router.use(\n `${LB_ENDPOINT}/*page`,\n (err: unknown, _req: Request, res: Response, next: NextFunction) => {\n if ((err as { type?: string }).type !== \"entity.parse.failed\") {\n next(err);\n return;\n }\n console.warn(`loadbare: request body is not JSON`);\n res.status(400).json([]);\n },\n );\n\n return router;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"lb-express.js","sourceRoot":"","sources":["../../server/lb-express.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The Express adapter — the standard hand-off from an Express router to a\n * Hub built by createHub(). Every Hub application wires this same router,\n * which is why it ships from here rather than being copied into each one.\n *\n * Express itself is a peer dependency: nothing outside this file imports it,\n * so an application that hosts Hub some other way never pays for it.\n *\n * One endpoint, and no second:\n *\n * POST /lb/<stub>?<query string>\n * an empty body asks for the page's queries, or for\n * the page loaded at the new URL its onPageEnter\n * returned; a body carrying a request runs its\n * handler and answers with the refresh set, or with\n * the page loaded at the new URL the handler\n * returned\n *\n * The page rides on the path rather than in the body, which is what lets the\n * operation set stay closed. The query string is the one the browser is\n * showing, verbatim, and `contextFor` is handed its parms. What a parm means\n * is the application's: nothing here reads one. Every hub call is a POST, so\n * an application's own GET routes never collide with this one and no page\n * name is reserved.\n */\n\nimport express, {\n type NextFunction,\n type Request,\n type Response,\n type Router,\n} from \"express\";\nimport {\n LB_ENDPOINT,\n LB_REFUSAL_STATUS,\n URL_QUERY,\n} from \"../core/lb-constants.js\";\nimport {\n nextLocation,\n type HubRequest,\n type HubResponse,\n} from \"../core/lb-types.js\";\nimport { Refusal, type Hub, type HubContext } from \"./lb-server.js\";\n\n/**\n * Building the context is the application's job — it is where an\n * authenticated database handle comes from — so it is injected rather than\n * assumed. Whatever established identity has already run by the time this\n * router is reached; where that happens is the application's ordering\n * decision, not Hub's.\n *\n * The query parms arrive as `parms`, and are read there rather than off\n * `req.query`. The two agree except after a request that wrote parms: the\n * page is then loaded at the new query string in the same round trip, and\n * this is called a second time for that load, with the same `req` and the\n * new `parms`. So it must be safe to call twice for one request, and a\n * write must be visible to the second context by the time its `run`\n * returns.\n *\n * Parms are user input like any other, typed into an address bar or mailed\n * in a link, and are validated where they are read.\n */\nexport type ContextFor = (req: Request, parms: URLSearchParams) => HubContext;\n\n/**\n * The router's options, one key per concern.\n *\n * `json` is handed to `express.json()` untouched, so it takes whatever that\n * takes. The one an application is likely to want is `limit`: the default\n * of 100kb refuses a page that sends a file's text as a value.\n */\nexport interface HubRoutesOptions {\n json?: Parameters<typeof express.json>[0];\n}\n\nexport function hubRoutes(\n hub: Hub,\n contextFor: ContextFor,\n options: HubRoutesOptions = {},\n): Router {\n const router = express.Router();\n\n // Mounted here rather than on the app so that Hub's need for a parsed\n // body is stated where the routes that need it are.\n router.use(express.json(options.json));\n\n router.post(`${LB_ENDPOINT}/*page`, async (req, res) => {\n // A page name may hold a slash, so the path below the endpoint is\n // gathered whole.\n const page = (req.params.page as string[]).join(\"/\");\n const request = req.body as HubRequest | undefined;\n // Parsed here rather than taken from req.query, so that the parms a\n // context is built from are the same kind of thing on both calls.\n const parms = new URL(req.originalUrl, \"http://localhost\").searchParams;\n const ctx = contextFor(req, parms);\n\n // No body at all is the page load: the browser is asking for this\n // page's queries. A body that carries something but no name is\n // malformed.\n if (request === undefined || Object.keys(request).length === 0) {\n const items = await hub.dataForPage(page, ctx, { parms });\n const moved = items.find((item) => item.query === URL_QUERY);\n if (moved === undefined) {\n res.json(items);\n return;\n }\n // onPageEnter moved the URL, so the page loads there, and that load\n // does not follow onPageEnter again: no page can move the URL forever.\n res.json(\n await loadAt(\n moved,\n nextLocation(page, parms, moved.row ?? {}),\n `entering '${page}'`,\n ),\n );\n return;\n }\n\n if (!request.name) {\n console.warn(`loadbare: request without a name`);\n res.status(400).json([]);\n return;\n }\n\n // A thrown error is how application code (a query, a handler) says\n // \"this request is invalid\" or hits an unexpected failure — it resolves\n // to a real response rather than an unhandled rejection, so the browser\n // side has something to catch.\n // A refusal carries words the handler wrote for the user, and goes to\n // the browser with them. Anything else thrown is a failure, and goes\n // with nothing, so a stack or a database message never reaches a page.\n let items: HubResponse;\n try {\n items = await hub.runRequest(page, request, ctx);\n } catch (err) {\n if (err instanceof Refusal) {\n res.status(LB_REFUSAL_STATUS).json({ refusal: err.refusal });\n return;\n }\n console.error(`loadbare: '${request.name}' threw`, err);\n res.status(500).json([]);\n return;\n }\n\n const moved = items.find((item) => item.query === URL_QUERY);\n if (moved === undefined) {\n res.json(items);\n return;\n }\n // The handler returned a new row for lb-url, so the page loads there, as\n // a cold load of the new URL would. The handler has already run: from\n // here a failure must not read as the request failing, or the user would\n // send it again. The item goes back alone instead, and the hub, writing\n // the URL with nothing to land, loads the page itself.\n res.json(\n await loadAt(\n moved,\n nextLocation(page, parms, moved.row ?? {}),\n `'${request.name}'`,\n ),\n );\n\n /**\n * The `lb-url` item and the page loaded where it leads. A load that\n * throws is not the failure of what moved the URL: the item goes back\n * alone, and the hub, writing the URL with nothing to land, loads the\n * page itself.\n */\n async function loadAt(\n moved: HubResponse[number],\n next: { page: string; parms: URLSearchParams },\n what: string,\n ): Promise<HubResponse> {\n try {\n const load = await hub.dataForPage(\n next.page,\n contextFor(req, next.parms),\n { follow: false },\n );\n return [moved, ...load];\n } catch (err) {\n console.error(\n `loadbare: ${what} moved the URL, and loading '${next.page}' ` +\n `there threw`,\n err,\n );\n return [moved];\n }\n }\n });\n\n // A body that never parsed, or was too large to read, is refused like any\n // other malformed request, rather than falling through to the\n // application's error handler, which would print a stack and call it a\n // server failure. Only for the hub's own path: express.json() above sees\n // every request, and a bad body sent to one of the application's routes is\n // the application's to answer.\n router.use(\n `${LB_ENDPOINT}/*page`,\n (err: unknown, _req: Request, res: Response, next: NextFunction) => {\n const { type, limit } = err as { type?: string; limit?: number };\n if (type === \"entity.parse.failed\") {\n console.warn(`loadbare: request body is not JSON`);\n res.status(400).json([]);\n return;\n }\n if (type === \"entity.too.large\") {\n // Named in the log, since nothing in the browser says which limit\n // was hit or where to raise it.\n console.warn(\n `loadbare: request body is over the limit of ${limit} bytes; ` +\n `raise it with hubRoutes' json.limit option`,\n );\n res.status(413).json([]);\n return;\n }\n next(err);\n },\n );\n\n return router;\n}\n"]}
|