@trdrs/quickcharts 4.0.0 → 5.0.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/CHANGELOG.md +106 -0
- package/README.md +325 -79
- package/dist/adapters/rest.d.ts +4 -4
- package/dist/adapters/rest.js +1 -1
- package/dist/adapters/rest.js.map +1 -1
- package/dist/ar-TG26ZCCE.js +1322 -0
- package/dist/ar-TG26ZCCE.js.map +1 -0
- package/dist/{assets-Gg-UquDA.d.ts → assets-DF3nozNV.d.ts} +167 -18
- package/dist/ca_ES-WJWH5BXU.js +1322 -0
- package/dist/ca_ES-WJWH5BXU.js.map +1 -0
- package/dist/{chunk-D3S26ARP.js → chunk-EXJAJZTN.js} +1 -1
- package/dist/chunk-EXJAJZTN.js.map +1 -0
- package/dist/{chunk-C4MEVUNK.js → chunk-Q3DCXQDW.js} +992 -284
- package/dist/chunk-Q3DCXQDW.js.map +1 -0
- package/dist/de-SUDTTPQ3.js +1322 -0
- package/dist/de-SUDTTPQ3.js.map +1 -0
- package/dist/drawings.d.ts +18 -7
- package/dist/drawings.js +7 -1
- package/dist/es-FOBXUK2X.js +1322 -0
- package/dist/es-FOBXUK2X.js.map +1 -0
- package/dist/feature-manifest.json +105 -9
- package/dist/fr-7KQC4IJH.js +1322 -0
- package/dist/fr-7KQC4IJH.js.map +1 -0
- package/dist/he_IL-2T6XBA6D.js +1322 -0
- package/dist/he_IL-2T6XBA6D.js.map +1 -0
- package/dist/id_ID-SI25N57C.js +1322 -0
- package/dist/id_ID-SI25N57C.js.map +1 -0
- package/dist/index.d.ts +952 -176
- package/dist/index.js +11905 -7472
- package/dist/index.js.map +1 -1
- package/dist/it-PMSTWZDL.js +1322 -0
- package/dist/it-PMSTWZDL.js.map +1 -0
- package/dist/ja-PABDRAXV.js +1322 -0
- package/dist/ja-PABDRAXV.js.map +1 -0
- package/dist/ko-JHRYYFCV.js +1322 -0
- package/dist/ko-JHRYYFCV.js.map +1 -0
- package/dist/ms_MY-U4EE5Q4V.js +1322 -0
- package/dist/ms_MY-U4EE5Q4V.js.map +1 -0
- package/dist/pl-4HCG3T3J.js +1322 -0
- package/dist/pl-4HCG3T3J.js.map +1 -0
- package/dist/pt-6LTNN653.js +1322 -0
- package/dist/pt-6LTNN653.js.map +1 -0
- package/dist/quickcharts.css +627 -208
- package/dist/{resources-Le6flcEn.d.ts → resources-XglhzzW0.d.ts} +5 -3
- package/dist/rest-openapi.json +16 -11
- package/dist/ru-LFHCSDBV.js +1322 -0
- package/dist/ru-LFHCSDBV.js.map +1 -0
- package/dist/sv-4XVUXYK6.js +1322 -0
- package/dist/sv-4XVUXYK6.js.map +1 -0
- package/dist/{symbols-6V22WaRX.d.ts → symbols-DdHLHQFC.d.ts} +77 -8
- package/dist/symbols.d.ts +1 -1
- package/dist/th-WM2PVA24.js +1322 -0
- package/dist/th-WM2PVA24.js.map +1 -0
- package/dist/theme-manifest.json +105 -21
- package/dist/tr-HMAZXSJM.js +1322 -0
- package/dist/tr-HMAZXSJM.js.map +1 -0
- package/dist/vi-ITFBV5B7.js +1322 -0
- package/dist/vi-ITFBV5B7.js.map +1 -0
- package/dist/zh-ZGU2RI7K.js +1322 -0
- package/dist/zh-ZGU2RI7K.js.map +1 -0
- package/dist/zh_TW-PNINSQ6F.js +1322 -0
- package/dist/zh_TW-PNINSQ6F.js.map +1 -0
- package/package.json +1 -1
- package/dist/ar-FXZ5QJUR.js +0 -1178
- package/dist/ar-FXZ5QJUR.js.map +0 -1
- package/dist/ca_ES-3WVKFBIF.js +0 -1178
- package/dist/ca_ES-3WVKFBIF.js.map +0 -1
- package/dist/chunk-C4MEVUNK.js.map +0 -1
- package/dist/chunk-D3S26ARP.js.map +0 -1
- package/dist/de-V72Q3OI7.js +0 -1178
- package/dist/de-V72Q3OI7.js.map +0 -1
- package/dist/es-CNQ3OJ6E.js +0 -1178
- package/dist/es-CNQ3OJ6E.js.map +0 -1
- package/dist/fr-5WQBCGR4.js +0 -1178
- package/dist/fr-5WQBCGR4.js.map +0 -1
- package/dist/he_IL-WXKA77UE.js +0 -1178
- package/dist/he_IL-WXKA77UE.js.map +0 -1
- package/dist/id_ID-XPBAYSWK.js +0 -1178
- package/dist/id_ID-XPBAYSWK.js.map +0 -1
- package/dist/it-DR2EBNWX.js +0 -1178
- package/dist/it-DR2EBNWX.js.map +0 -1
- package/dist/ja-URB2CPXO.js +0 -1178
- package/dist/ja-URB2CPXO.js.map +0 -1
- package/dist/ko-OE47NYVP.js +0 -1178
- package/dist/ko-OE47NYVP.js.map +0 -1
- package/dist/ms_MY-BKCFRK2K.js +0 -1178
- package/dist/ms_MY-BKCFRK2K.js.map +0 -1
- package/dist/pl-3IKQRG3Y.js +0 -1178
- package/dist/pl-3IKQRG3Y.js.map +0 -1
- package/dist/pt-PZHV5EZE.js +0 -1178
- package/dist/pt-PZHV5EZE.js.map +0 -1
- package/dist/ru-BAL6RQUV.js +0 -1178
- package/dist/ru-BAL6RQUV.js.map +0 -1
- package/dist/sv-Y6GBGDHM.js +0 -1178
- package/dist/sv-Y6GBGDHM.js.map +0 -1
- package/dist/th-MAMLMZKU.js +0 -1178
- package/dist/th-MAMLMZKU.js.map +0 -1
- package/dist/tr-3LQHINUZ.js +0 -1178
- package/dist/tr-3LQHINUZ.js.map +0 -1
- package/dist/vi-GR4PSDKP.js +0 -1178
- package/dist/vi-GR4PSDKP.js.map +0 -1
- package/dist/zh-2RJ5VNAI.js +0 -1178
- package/dist/zh-2RJ5VNAI.js.map +0 -1
- package/dist/zh_TW-XEBSACHU.js +0 -1178
- package/dist/zh_TW-XEBSACHU.js.map +0 -1
package/dist/adapters/rest.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { C as ChartSaveLoadAdapter } from '../resources-
|
|
1
|
+
import { C as ChartSaveLoadAdapter } from '../resources-XglhzzW0.js';
|
|
2
2
|
|
|
3
|
-
/** The
|
|
4
|
-
type RestTemplateKind = 'indicator' | 'drawing' | 'palette';
|
|
5
|
-
/** Which collection a request addresses. Templates are
|
|
3
|
+
/** The four template collections. */
|
|
4
|
+
type RestTemplateKind = 'indicator' | 'drawing' | 'palette' | 'chart';
|
|
5
|
+
/** Which collection a request addresses. Templates are four collections rather than one, so the
|
|
6
6
|
* kind is part of the address rather than a field inside it. */
|
|
7
7
|
type RestCollection = {
|
|
8
8
|
family: 'charts' | 'layouts' | 'drawings';
|
package/dist/adapters/rest.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/adapters/rest/wire.ts","../../src/adapters/rest/index.ts"],"sourcesContent":["// THE PUBLIC REST WIRE CONTRACT for saved chart resources: the paths, the payloads and the\n// conditional-write rule a service implements so that `createRestSaveLoadAdapter` can drive it.\n//\n// This module is the contract's one source. The types below are what a service's handlers return\n// and what `./index` reads back; the path helpers are what it asks for. `./openapi` renders the\n// same facts as an OpenAPI document, which the build writes to `dist/rest-openapi.json`, so the\n// schema a service author reads and the requests the adapter makes cannot drift apart.\n//\n// Four rules the contract enforces:\n// - Every path is RELATIVE to a base URL the host owns. Nothing here names an origin, a service,\n// a credential or a header a host has not asked for.\n// - Identity and version travel in the BODY: every row carries a stable `id` and an opaque\n// `revision`. A reader quotes the revision it read back in `If-Match` on its next write, and a\n// service compares it for equality alone. Minting it as an ETag value, a counter or a content\n// hash is the service's choice.\n// - A write against a revision the service has moved past is 409 with the ref that stands now,\n// never a silent overwrite. An unknown id is 404. A conditional route reached with no\n// `If-Match` is 428.\n// - Bodies the chart writes are OPAQUE text to the service. It stores and returns `content`\n// without parsing it, so a chart's formats stay the chart's own.\nimport type { DrawingResourceContext } from '../../drawings/document'\n\n/** The contract's own version, which the published OpenAPI document carries as its `info.version`.\n * A later shape arrives as a later number rather than as a widened old one. */\nexport const REST_WIRE_VERSION = 2\n\n/** The three template collections. */\nexport type RestTemplateKind = 'indicator' | 'drawing' | 'palette'\n\nexport const REST_TEMPLATE_KINDS: readonly RestTemplateKind[] = ['indicator', 'drawing', 'palette']\n\n/** Which collection a request addresses. Templates are three collections rather than one, so the\n * kind is part of the address rather than a field inside it. */\nexport type RestCollection = { family: 'charts' | 'layouts' | 'drawings' } | { family: 'templates'; kind: RestTemplateKind }\n\n/** The header a conditional write states its revision in. */\nexport const REST_IF_MATCH_HEADER = 'if-match'\n\n/** The statuses the contract gives meaning to. Anything else is a failure the adapter raises. */\nexport const REST_STATUS = {\n /** The id is unknown, deleted, or another principal's. */\n notFound: 404,\n /** The quoted revision is not the one that stands; the body carries the one that is. */\n conflict: 409,\n /** A conditional route was reached with no `If-Match`. The adapter always sends one. */\n revisionRequired: 428,\n} as const\n\n/** A row's identity plus the exact version a reader saw. */\nexport interface RestResourceRef {\n id: string\n /** Opaque: compared for equality, never parsed or ordered. */\n revision: string\n}\n\n/** A listing: metadata only, so a picker paints without fetching content. `items` is the same key\n * in every family, so one reader serves all four. */\nexport interface RestListResponse<Meta> {\n items: Meta[]\n}\n\n/** A read: the ref the document stands at, and the document. */\nexport interface RestLoadResponse<Body> extends RestResourceRef {\n body: Body\n}\n\n/** A create, update or delete that landed: the ref the service now holds (for a delete, the one it\n * removed), and the listing row the write produced where the service computes one. */\nexport interface RestWriteResponse<Meta> extends RestResourceRef {\n meta?: Meta\n}\n\n/** The 409 body: the ref that stands now, so the caller reloads it and re-decides. */\nexport interface RestConflictBody {\n error: 'conflict'\n current: RestResourceRef\n}\n\n/** The 404 body. */\nexport interface RestNotFoundBody {\n error: 'not_found'\n}\n\n/** The 428 body. */\nexport interface RestRevisionRequiredBody {\n error: 'revision_required'\n}\n\n/** A saved chart's listing row. `updatedAt` is ms since epoch, stamped by the service. */\nexport interface RestChartMeta extends RestResourceRef {\n name: string\n symbol: string\n timeframe: string\n updatedAt: number\n}\n\n/** A saved chart. `content` is the chart's serialized state, opaque to the service. */\nexport interface RestChartBody {\n name: string\n symbol: string\n timeframe: string\n content: string\n}\n\n/** A saved multi-chart layout's listing row. `symbol` and `timeframe` are the active chart's when the\n * layout was last saved; a service that does not keep them leaves them out. */\nexport interface RestLayoutMeta extends RestResourceRef {\n name: string\n symbol?: string\n timeframe?: string\n updatedAt: number\n}\n\nexport interface RestLayoutBody {\n name: string\n symbol?: string\n timeframe?: string\n content: string\n}\n\n/** A drawings document's listing row. One context holds at most one document, so the collection\n * answers zero rows or one. */\nexport interface RestDrawingsMeta extends RestResourceRef {\n updatedAt: number\n}\n\n/** A drawings document, as the service stores it: the document's own JSON, as opaque text. */\nexport interface RestDrawingsBody {\n content: string\n}\n\n/** A template's listing row. `tool` scopes a drawing template to its tool; indicator and palette\n * templates carry none. */\nexport interface RestTemplateMeta extends RestResourceRef {\n name: string\n tool?: string\n updatedAt: number\n}\n\nexport interface RestTemplateBody {\n name: string\n tool?: string\n content: string\n}\n\n/** A collection's path, relative to the host's base URL. */\nexport function restCollectionPath(collection: RestCollection): string {\n return collection.family === 'templates' ? `/templates/${encodeURIComponent(collection.kind)}` : `/${collection.family}`\n}\n\n/** One row's path, relative to the host's base URL. */\nexport function restItemPath(collection: RestCollection, id: string): string {\n return `${restCollectionPath(collection)}/${encodeURIComponent(id)}`\n}\n\n/** The drawing-resource context as one opaque token for the `context` query parameter. Each part is\n * percent-encoded before the join, with the dot separator itself encoded (percent-encoding leaves an\n * unreserved dot alone), so no layout or chart id can spell another context's token, and the kind\n * leads, so a symbol-global document and a layout-shared one never collide. The service\n * keys rows by it and never parses it. */\nexport function restDrawingContextToken(context: DrawingResourceContext): string {\n const parts: string[] = [String(context.version), context.kind]\n if (context.kind === 'chart-local') parts.push(context.layoutId, context.chartId)\n else if (context.kind === 'layout-shared') parts.push(context.layoutId)\n return parts.map((part) => encodeURIComponent(part).replace(/\\./g, '%2E')).join('.')\n}\n\n/** The drawings collection's query: the symbol it belongs to, and the context token. Both are\n * required, because a drawings collection with no context would name every document at once. */\nexport function restDrawingsQuery(context: DrawingResourceContext): string {\n return `symbol=${encodeURIComponent(context.symbol)}&context=${encodeURIComponent(restDrawingContextToken(context))}`\n}","// `@trdrs/quickcharts/adapters/rest` — the optional save/load adapter over the public wire contract in\n// `./wire`.\n//\n// It is a SEPARATE entrypoint because the chart makes no network request of its own. A consumer who\n// never imports this module ships none of it, and a consumer who does hands it two things: where\n// its service lives, and how to reach it.\n//\n// createRestSaveLoadAdapter({ baseUrl, request })\n//\n// `request` is the whole transport. `globalThis.fetch` fits it, and so does a host's own wrapper\n// around one. That is the point: authorization, cookies, CORS, tenancy, retries, timeouts and\n// telemetry are decisions with consequences the chart cannot weigh, so this module holds no\n// credential, no token store, no header policy, no retry and no default origin. The only headers it\n// sets are the two the contract itself needs: the media type of a body it is sending, and the\n// revision a conditional write is quoting.\n//\n// Every refusal the contract defines becomes the core port's typed outcome: 404 is `not-found` (and\n// a null from a load), 409 is `conflict` carrying the ref that stands. Everything else is a\n// `RestSaveLoadError` the caller can inspect and decide about, because a transport failure is not a\n// resource outcome and answering one as an empty list or a missing row would be a lie the next save\n// acts on. An aborted call rejects with the contract's `AbortError`, and nothing lands.\nimport { DRAWING_DOCUMENT_VERSION, drawingContextKey, parseDrawingDocument, type DrawingResourceContext, type DrawingsBody } from '../../drawings/document'\nimport {\n ResourceAbortError,\n type ChartBody,\n type ChartMeta,\n type ChartSaveLoadAdapter,\n type DrawingsMeta,\n type LayoutBody,\n type LayoutMeta,\n type ResourceRef,\n type ResourceStore,\n type TemplateBody,\n type TemplateKind,\n type TemplateMeta,\n type WriteOutcome,\n} from '../../resources'\nimport {\n REST_IF_MATCH_HEADER,\n REST_STATUS,\n restCollectionPath,\n restDrawingsQuery,\n restItemPath,\n type RestChartBody,\n type RestChartMeta,\n type RestCollection,\n type RestConflictBody,\n type RestDrawingsBody,\n type RestDrawingsMeta,\n type RestLayoutBody,\n type RestLayoutMeta,\n type RestListResponse,\n type RestLoadResponse,\n type RestResourceRef,\n type RestTemplateBody,\n type RestTemplateMeta,\n type RestWriteResponse,\n} from './wire'\n\n/** The wire contract, as types a service implementer writes their handlers against. They are what\n * the adapter sends and reads, so a service typed by them and an adapter driving it cannot drift.\n * The paths, the statuses and the schema document are in `./wire` and `dist/rest-openapi.json`. */\nexport type {\n RestChartBody,\n RestChartMeta,\n RestCollection,\n RestConflictBody,\n RestDrawingsBody,\n RestDrawingsMeta,\n RestLayoutBody,\n RestLayoutMeta,\n RestListResponse,\n RestLoadResponse,\n RestNotFoundBody,\n RestResourceRef,\n RestRevisionRequiredBody,\n RestTemplateBody,\n RestTemplateKind,\n RestTemplateMeta,\n RestWriteResponse,\n} from './wire'\n\n/** What the adapter asks a request function to do. Deliberately the subset of `RequestInit` the\n * contract needs, so a host implementing this by hand implements four fields rather than thirty,\n * and a plain `fetch` accepts it unchanged. */\nexport interface RestRequestInit {\n method: string\n headers: Record<string, string>\n /** The JSON payload, on a create and an update; absent on a read and a delete. */\n body?: string\n signal?: AbortSignal\n}\n\n/** What the adapter reads back. The subset of a `Response` the contract needs, so a host may return\n * a real `Response` or its own object of the same shape. */\nexport interface RestResponse {\n readonly status: number\n text(): Promise<string>\n}\n\n/** The host's transport. `fetch` satisfies it; so does a wrapper that adds the host's authorization,\n * its base headers, its retries or its telemetry. The adapter calls it and reads what it answers,\n * and does nothing else with the network. */\nexport type RestRequest = (url: string, init: RestRequestInit) => Promise<RestResponse>\n\nexport interface RestSaveLoadOptions {\n /** Where the host mounts the wire contract's routes. Every path is appended to it, so an origin,\n * a path prefix, or a bare path are all fine. There is no default: the chart does not know where\n * a host's service lives, and guessing would be a request nobody asked for. */\n baseUrl: string\n /** How a request is made. Required, for the same reason. */\n request: RestRequest\n}\n\n/** A request the service answered in a way the contract does not define: a status with no meaning\n * here (`http`), or a body that is not the shape the route promises (`invalid-payload`). It carries\n * what the caller needs to decide: which request, and what came back. */\nexport class RestSaveLoadError extends Error {\n override readonly name = 'RestSaveLoadError'\n readonly reason: 'http' | 'invalid-payload'\n readonly status: number\n readonly method: string\n readonly url: string\n constructor(init: { reason: 'http' | 'invalid-payload'; status: number; method: string; url: string; detail: string }) {\n super(`${init.method} ${init.url}: ${init.detail}`)\n this.reason = init.reason\n this.status = init.status\n this.method = init.method\n this.url = init.url\n }\n}\n\nconst isRecord = (value: unknown): value is Record<string, unknown> => typeof value === 'object' && value !== null\n\n/** A ref the service stated, or null when it stated something else. Both fields are required and\n * both are strings: a numeric revision that arrived as a number is not this contract's ref, and\n * reading one loosely is how a client starts comparing revisions it cannot compare. */\nconst refOf = (value: unknown): ResourceRef | null => {\n if (!isRecord(value)) return null\n const { id, revision } = value as Partial<RestResourceRef>\n return typeof id === 'string' && id !== '' && typeof revision === 'string' ? { id, revision } : null\n}\n\n/** A layout's listing facts, carried only where they were stated: a service that keeps none answers\n * rows without them, and a row without them is a row the listing names by its time instead. */\nconst listingFacts = (from: { symbol?: string; timeframe?: string }): { symbol?: string; timeframe?: string } => ({\n ...(typeof from.symbol === 'string' ? { symbol: from.symbol } : {}),\n ...(typeof from.timeframe === 'string' ? { timeframe: from.timeframe } : {}),\n})\n\n/** The base URL with no trailing slash, so `${base}/charts` never doubles one. */\nconst trimBase = (baseUrl: string): string => baseUrl.replace(/\\/+$/, '')\n\nexport function createRestSaveLoadAdapter(options: RestSaveLoadOptions): ChartSaveLoadAdapter {\n const base = trimBase(options.baseUrl)\n const request = options.request\n\n /** One call: the abort check, the two contract headers, the host's request, and the status and\n * text it answered. Reading the status is each verb's own job, because what a 404 means differs\n * between a load (nothing there) and an update (the row is gone). */\n async function call(deps: { method: string; path: string; body?: unknown; ref?: ResourceRef; signal?: AbortSignal }): Promise<{ status: number; text: string }> {\n if (deps.signal?.aborted) throw new ResourceAbortError()\n const url = `${base}${deps.path}`\n const headers: Record<string, string> = {}\n if (deps.body !== undefined) headers['content-type'] = 'application/json'\n if (deps.ref) headers[REST_IF_MATCH_HEADER] = deps.ref.revision\n const init: RestRequestInit = { method: deps.method, headers }\n if (deps.body !== undefined) init.body = JSON.stringify(deps.body)\n if (deps.signal) init.signal = deps.signal\n const response = await request(url, init)\n const text = await response.text()\n return { status: response.status, text }\n }\n\n /** The JSON a 2xx carried, held to being an object. A body that is not one is the route's promise\n * broken, which is a failure to report rather than an empty answer to act on. */\n function payload(method: string, url: string, answer: { status: number; text: string }): Record<string, unknown> {\n let parsed: unknown = null\n try {\n parsed = answer.text === '' ? null : JSON.parse(answer.text)\n } catch {\n parsed = null\n }\n if (!isRecord(parsed))\n throw new RestSaveLoadError({ reason: 'invalid-payload', status: answer.status, method, url, detail: 'the response is not a JSON object' })\n return parsed\n }\n\n /** A non-2xx the caller did not name: raised with its status, so a host can tell a 401 from a 503\n * and decide (sign in again, back off, tell the viewer) rather than see an empty chart. */\n const httpError = (method: string, url: string, status: number): RestSaveLoadError =>\n new RestSaveLoadError({ reason: 'http', status, method, url, detail: `unexpected status ${status}` })\n\n /** One family over one collection. `metaOf` and `bodyOf` read the wire rows; `wireOf` writes the\n * body. The five verbs share the transport and the refusal mapping. */\n function store<Meta, Body, WireMeta, WireBody>(deps: {\n collection: RestCollection\n /** The collection's query, for a family whose collection is scoped (drawings). */\n query?: string\n metaOf: (row: WireMeta) => Meta\n bodyOf: (wire: WireBody, answer: { status: number; text: string }, url: string) => Body\n wireOf: (body: Body) => WireBody\n }): ResourceStore<Meta, Body> {\n const collectionPath = deps.query ? `${restCollectionPath(deps.collection)}?${deps.query}` : restCollectionPath(deps.collection)\n const itemPath = (id: string): string => restItemPath(deps.collection, id)\n\n /** A write's answer as the port's outcome: the ref it landed at, the ref that beat it, or the\n * absence it found. */\n const written = <T>(method: string, path: string, answer: { status: number; text: string }, carriesMeta: boolean): WriteOutcome<T> => {\n const url = `${base}${path}`\n if (answer.status === REST_STATUS.notFound) return { kind: 'not-found' }\n if (answer.status === REST_STATUS.conflict) {\n const conflict = payload(method, url, answer) as Partial<RestConflictBody>\n const current = refOf(conflict.current)\n if (!current) throw new RestSaveLoadError({ reason: 'invalid-payload', status: answer.status, method, url, detail: 'the conflict states no current ref' })\n return { kind: 'conflict', current }\n }\n if (answer.status < 200 || answer.status >= 300) throw httpError(method, url, answer.status)\n const body = payload(method, url, answer) as Partial<RestWriteResponse<WireMeta>>\n const ref = refOf(body)\n if (!ref) throw new RestSaveLoadError({ reason: 'invalid-payload', status: answer.status, method, url, detail: 'the write states no ref' })\n const outcome: WriteOutcome<T> = { kind: 'ok', ref }\n // A delete answers a ref alone; only a create or an update carries the stored row's meta.\n if (carriesMeta && body.meta !== undefined) outcome.value = deps.metaOf(body.meta) as unknown as T\n return outcome\n }\n\n return {\n async list(signal) {\n const answer = await call({ method: 'GET', path: collectionPath, signal })\n const url = `${base}${collectionPath}`\n if (answer.status < 200 || answer.status >= 300) throw httpError('GET', url, answer.status)\n const body = payload('GET', url, answer) as Partial<RestListResponse<WireMeta>>\n if (!Array.isArray(body.items)) throw new RestSaveLoadError({ reason: 'invalid-payload', status: answer.status, method: 'GET', url, detail: 'the listing states no items array' })\n return body.items.map(deps.metaOf)\n },\n async load(id, signal) {\n const path = itemPath(id)\n const url = `${base}${path}`\n const answer = await call({ method: 'GET', path, signal })\n if (answer.status === REST_STATUS.notFound) return null\n if (answer.status < 200 || answer.status >= 300) throw httpError('GET', url, answer.status)\n const body = payload('GET', url, answer) as Partial<RestLoadResponse<WireBody>>\n const ref = refOf(body)\n if (!ref || body.body === undefined || !isRecord(body.body))\n throw new RestSaveLoadError({ reason: 'invalid-payload', status: answer.status, method: 'GET', url, detail: 'the read states no ref and body' })\n return { ref, body: deps.bodyOf(body.body, answer, url) }\n },\n async create(body, signal) {\n const answer = await call({ method: 'POST', path: collectionPath, body: deps.wireOf(body), signal })\n return written<Meta>('POST', collectionPath, answer, true)\n },\n async update(ref, body, signal) {\n const path = itemPath(ref.id)\n const answer = await call({ method: 'PUT', path, body: deps.wireOf(body), ref, signal })\n return written<Meta>('PUT', path, answer, true)\n },\n async remove(ref, signal) {\n const path = itemPath(ref.id)\n const answer = await call({ method: 'DELETE', path, ref, signal })\n return written<void>('DELETE', path, answer, false)\n },\n }\n }\n\n const drawingStores = new Map<string, ResourceStore<DrawingsMeta, DrawingsBody>>()\n const templateStores = new Map<TemplateKind, ResourceStore<TemplateMeta, TemplateBody>>()\n\n return {\n charts: store<ChartMeta, ChartBody, RestChartMeta, RestChartBody>({\n collection: { family: 'charts' },\n metaOf: (r) => ({ id: r.id, revision: r.revision, name: r.name, symbol: r.symbol, timeframe: r.timeframe, updatedAt: r.updatedAt }),\n bodyOf: (w) => ({ name: w.name, symbol: w.symbol, timeframe: w.timeframe, content: w.content }),\n wireOf: (b) => ({ name: b.name, symbol: b.symbol, timeframe: b.timeframe, content: b.content }),\n }),\n layouts: store<LayoutMeta, LayoutBody, RestLayoutMeta, RestLayoutBody>({\n collection: { family: 'layouts' },\n metaOf: (r) => ({ id: r.id, revision: r.revision, name: r.name, ...listingFacts(r), updatedAt: r.updatedAt }),\n bodyOf: (w) => ({ name: w.name, ...listingFacts(w), content: w.content }),\n wireOf: (b) => ({ name: b.name, ...listingFacts(b), content: b.content }),\n }),\n drawings(context: DrawingResourceContext) {\n const key = drawingContextKey(context)\n let held = drawingStores.get(key)\n if (!held) {\n held = store<DrawingsMeta, DrawingsBody, RestDrawingsMeta, RestDrawingsBody>({\n collection: { family: 'drawings' },\n query: restDrawingsQuery(context),\n metaOf: (r) => ({ id: r.id, revision: r.revision, updatedAt: r.updatedAt }),\n // The document is the one body the chart itself reads, so this is where a stored row is\n // proved to be a document FOR THIS CONTEXT before the chart sees one. A row that is not\n // is refused rather than read as an empty document: an empty read is followed by a save,\n // and that save would replace the row it misread.\n bodyOf: (w, answer, url) => documentOf(w.content, context, answer.status, url),\n wireOf: (b) => ({ content: JSON.stringify(b) }),\n })\n drawingStores.set(key, held)\n }\n return held\n },\n templates(kind: TemplateKind) {\n let held = templateStores.get(kind)\n if (!held) {\n held = store<TemplateMeta, TemplateBody, RestTemplateMeta, RestTemplateBody>({\n collection: { family: 'templates', kind },\n metaOf: (r) => ({ id: r.id, revision: r.revision, name: r.name, ...(r.tool === undefined ? {} : { tool: r.tool }), updatedAt: r.updatedAt }),\n bodyOf: (w) => ({ name: w.name, ...(w.tool === undefined ? {} : { tool: w.tool }), content: w.content }),\n wireOf: (b) => ({ name: b.name, ...(b.tool === undefined ? {} : { tool: b.tool }), content: b.content }),\n })\n templateStores.set(kind, held)\n }\n return held\n },\n }\n}\n\n/** The stored text as this context's document, or a refusal. `parseDrawingDocument` is total and\n * answers an empty document for anything it cannot read, so the two cases it cannot distinguish\n * are separated here first: text that is not a document at all, and a document written for another\n * context. */\nfunction documentOf(content: string, context: DrawingResourceContext, status: number, url: string): DrawingsBody {\n const refuse = (detail: string): RestSaveLoadError => new RestSaveLoadError({ reason: 'invalid-payload', status, method: 'GET', url, detail })\n let raw: unknown = null\n try {\n raw = JSON.parse(content)\n } catch {\n throw refuse('the stored drawings row is not JSON')\n }\n if (!isRecord(raw)) throw refuse('the stored drawings row is not a drawings document')\n if (raw.version !== DRAWING_DOCUMENT_VERSION) throw refuse(`the stored drawings row is not a version-${String(DRAWING_DOCUMENT_VERSION)} document`)\n if (isRecord(raw.context) && drawingContextKey(raw.context as unknown as DrawingResourceContext) !== drawingContextKey(context))\n throw refuse('the stored drawings row is another context\\'s document')\n return parseDrawingDocument(raw, context)\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/adapters/rest/wire.ts","../../src/adapters/rest/index.ts"],"sourcesContent":["// THE PUBLIC REST WIRE CONTRACT for saved chart resources: the paths, the payloads and the\n// conditional-write rule a service implements so that `createRestSaveLoadAdapter` can drive it.\n//\n// This module is the contract's one source. The types below are what a service's handlers return\n// and what `./index` reads back; the path helpers are what it asks for. `./openapi` renders the\n// same facts as an OpenAPI document, which the build writes to `dist/rest-openapi.json`, so the\n// schema a service author reads and the requests the adapter makes cannot drift apart.\n//\n// Four rules the contract enforces:\n// - Every path is RELATIVE to a base URL the host owns. Nothing here names an origin, a service,\n// a credential or a header a host has not asked for.\n// - Identity and version travel in the BODY: every row carries a stable `id` and an opaque\n// `revision`. A reader quotes the revision it read back in `If-Match` on its next write, and a\n// service compares it for equality alone. Minting it as an ETag value, a counter or a content\n// hash is the service's choice.\n// - A write against a revision the service has moved past is 409 with the ref that stands now,\n// never a silent overwrite. An unknown id is 404. A conditional route reached with no\n// `If-Match` is 428.\n// - Bodies the chart writes are OPAQUE text to the service. It stores and returns `content`\n// without parsing it, so a chart's formats stay the chart's own.\nimport type { DrawingResourceContext } from '../../drawings/document'\n\n/** The contract's own version, which the published OpenAPI document carries as its `info.version`.\n * A later shape arrives as a later number rather than as a widened old one. */\nexport const REST_WIRE_VERSION = 3\n\n/** The four template collections. */\nexport type RestTemplateKind = 'indicator' | 'drawing' | 'palette' | 'chart'\n\nexport const REST_TEMPLATE_KINDS: readonly RestTemplateKind[] = ['indicator', 'drawing', 'palette', 'chart']\n\n/** Which collection a request addresses. Templates are four collections rather than one, so the\n * kind is part of the address rather than a field inside it. */\nexport type RestCollection = { family: 'charts' | 'layouts' | 'drawings' } | { family: 'templates'; kind: RestTemplateKind }\n\n/** The header a conditional write states its revision in. */\nexport const REST_IF_MATCH_HEADER = 'if-match'\n\n/** The statuses the contract gives meaning to. Anything else is a failure the adapter raises. */\nexport const REST_STATUS = {\n /** The id is unknown, deleted, or another principal's. */\n notFound: 404,\n /** The quoted revision is not the one that stands; the body carries the one that is. */\n conflict: 409,\n /** A conditional route was reached with no `If-Match`. The adapter always sends one. */\n revisionRequired: 428,\n} as const\n\n/** A row's identity plus the exact version a reader saw. */\nexport interface RestResourceRef {\n id: string\n /** Opaque: compared for equality, never parsed or ordered. */\n revision: string\n}\n\n/** A listing: metadata only, so a picker paints without fetching content. `items` is the same key\n * in every family, so one reader serves all four. */\nexport interface RestListResponse<Meta> {\n items: Meta[]\n}\n\n/** A read: the ref the document stands at, and the document. */\nexport interface RestLoadResponse<Body> extends RestResourceRef {\n body: Body\n}\n\n/** A create, update or delete that landed: the ref the service now holds (for a delete, the one it\n * removed), and the listing row the write produced where the service computes one. */\nexport interface RestWriteResponse<Meta> extends RestResourceRef {\n meta?: Meta\n}\n\n/** The 409 body: the ref that stands now, so the caller reloads it and re-decides. */\nexport interface RestConflictBody {\n error: 'conflict'\n current: RestResourceRef\n}\n\n/** The 404 body. */\nexport interface RestNotFoundBody {\n error: 'not_found'\n}\n\n/** The 428 body. */\nexport interface RestRevisionRequiredBody {\n error: 'revision_required'\n}\n\n/** A saved chart's listing row. `updatedAt` is ms since epoch, stamped by the service. */\nexport interface RestChartMeta extends RestResourceRef {\n name: string\n symbol: string\n timeframe: string\n updatedAt: number\n}\n\n/** A saved chart. `content` is the chart's serialized state, opaque to the service. */\nexport interface RestChartBody {\n name: string\n symbol: string\n timeframe: string\n content: string\n}\n\n/** A saved multi-chart layout's listing row. `symbol` and `timeframe` are the active chart's when the\n * layout was last saved; a service that does not keep them leaves them out. */\nexport interface RestLayoutMeta extends RestResourceRef {\n name: string\n symbol?: string\n timeframe?: string\n updatedAt: number\n}\n\nexport interface RestLayoutBody {\n name: string\n symbol?: string\n timeframe?: string\n content: string\n}\n\n/** A drawings document's listing row. One context holds at most one document, so the collection\n * answers zero rows or one. */\nexport interface RestDrawingsMeta extends RestResourceRef {\n updatedAt: number\n}\n\n/** A drawings document, as the service stores it: the document's own JSON, as opaque text. */\nexport interface RestDrawingsBody {\n content: string\n}\n\n/** A template's listing row. `tool` scopes a drawing template to its tool; indicator and palette\n * templates carry none. */\nexport interface RestTemplateMeta extends RestResourceRef {\n name: string\n tool?: string\n updatedAt: number\n}\n\nexport interface RestTemplateBody {\n name: string\n tool?: string\n content: string\n}\n\n/** A collection's path, relative to the host's base URL. */\nexport function restCollectionPath(collection: RestCollection): string {\n return collection.family === 'templates' ? `/templates/${encodeURIComponent(collection.kind)}` : `/${collection.family}`\n}\n\n/** One row's path, relative to the host's base URL. */\nexport function restItemPath(collection: RestCollection, id: string): string {\n return `${restCollectionPath(collection)}/${encodeURIComponent(id)}`\n}\n\n/** The drawing-resource context as one opaque token for the `context` query parameter. Each part is\n * percent-encoded before the join, with the dot separator itself encoded (percent-encoding leaves an\n * unreserved dot alone), so no layout or chart id can spell another context's token, and the kind\n * leads, so a symbol-global document and a layout-shared one never collide. The service\n * keys rows by it and never parses it. */\nexport function restDrawingContextToken(context: DrawingResourceContext): string {\n const parts: string[] = [String(context.version), context.kind]\n if (context.kind === 'chart-local') parts.push(context.layoutId, context.chartId)\n else if (context.kind === 'layout-shared') parts.push(context.layoutId)\n return parts.map((part) => encodeURIComponent(part).replace(/\\./g, '%2E')).join('.')\n}\n\n/** The drawings collection's query: the symbol it belongs to, and the context token. Both are\n * required, because a drawings collection with no context would name every document at once. */\nexport function restDrawingsQuery(context: DrawingResourceContext): string {\n return `symbol=${encodeURIComponent(context.symbol)}&context=${encodeURIComponent(restDrawingContextToken(context))}`\n}","// `@trdrs/quickcharts/adapters/rest` — the optional save/load adapter over the public wire contract in\n// `./wire`.\n//\n// It is a SEPARATE entrypoint because the chart makes no network request of its own. A consumer who\n// never imports this module ships none of it, and a consumer who does hands it two things: where\n// its service lives, and how to reach it.\n//\n// createRestSaveLoadAdapter({ baseUrl, request })\n//\n// `request` is the whole transport. `globalThis.fetch` fits it, and so does a host's own wrapper\n// around one. That is the point: authorization, cookies, CORS, tenancy, retries, timeouts and\n// telemetry are decisions with consequences the chart cannot weigh, so this module holds no\n// credential, no token store, no header policy, no retry and no default origin. The only headers it\n// sets are the two the contract itself needs: the media type of a body it is sending, and the\n// revision a conditional write is quoting.\n//\n// Every refusal the contract defines becomes the core port's typed outcome: 404 is `not-found` (and\n// a null from a load), 409 is `conflict` carrying the ref that stands. Everything else is a\n// `RestSaveLoadError` the caller can inspect and decide about, because a transport failure is not a\n// resource outcome and answering one as an empty list or a missing row would be a lie the next save\n// acts on. An aborted call rejects with the contract's `AbortError`, and nothing lands.\nimport { DRAWING_DOCUMENT_VERSION, drawingContextKey, parseDrawingDocument, type DrawingResourceContext, type DrawingsBody } from '../../drawings/document'\nimport {\n ResourceAbortError,\n type ChartBody,\n type ChartMeta,\n type ChartSaveLoadAdapter,\n type DrawingsMeta,\n type LayoutBody,\n type LayoutMeta,\n type ResourceRef,\n type ResourceStore,\n type TemplateBody,\n type TemplateKind,\n type TemplateMeta,\n type WriteOutcome,\n} from '../../resources'\nimport {\n REST_IF_MATCH_HEADER,\n REST_STATUS,\n restCollectionPath,\n restDrawingsQuery,\n restItemPath,\n type RestChartBody,\n type RestChartMeta,\n type RestCollection,\n type RestConflictBody,\n type RestDrawingsBody,\n type RestDrawingsMeta,\n type RestLayoutBody,\n type RestLayoutMeta,\n type RestListResponse,\n type RestLoadResponse,\n type RestResourceRef,\n type RestTemplateBody,\n type RestTemplateMeta,\n type RestWriteResponse,\n} from './wire'\n\n/** The wire contract, as types a service implementer writes their handlers against. They are what\n * the adapter sends and reads, so a service typed by them and an adapter driving it cannot drift.\n * The paths, the statuses and the schema document are in `./wire` and `dist/rest-openapi.json`. */\nexport type {\n RestChartBody,\n RestChartMeta,\n RestCollection,\n RestConflictBody,\n RestDrawingsBody,\n RestDrawingsMeta,\n RestLayoutBody,\n RestLayoutMeta,\n RestListResponse,\n RestLoadResponse,\n RestNotFoundBody,\n RestResourceRef,\n RestRevisionRequiredBody,\n RestTemplateBody,\n RestTemplateKind,\n RestTemplateMeta,\n RestWriteResponse,\n} from './wire'\n\n/** What the adapter asks a request function to do. Deliberately the subset of `RequestInit` the\n * contract needs, so a host implementing this by hand implements four fields rather than thirty,\n * and a plain `fetch` accepts it unchanged. */\nexport interface RestRequestInit {\n method: string\n headers: Record<string, string>\n /** The JSON payload, on a create and an update; absent on a read and a delete. */\n body?: string\n signal?: AbortSignal\n}\n\n/** What the adapter reads back. The subset of a `Response` the contract needs, so a host may return\n * a real `Response` or its own object of the same shape. */\nexport interface RestResponse {\n readonly status: number\n text(): Promise<string>\n}\n\n/** The host's transport. `fetch` satisfies it; so does a wrapper that adds the host's authorization,\n * its base headers, its retries or its telemetry. The adapter calls it and reads what it answers,\n * and does nothing else with the network. */\nexport type RestRequest = (url: string, init: RestRequestInit) => Promise<RestResponse>\n\nexport interface RestSaveLoadOptions {\n /** Where the host mounts the wire contract's routes. Every path is appended to it, so an origin,\n * a path prefix, or a bare path are all fine. There is no default: the chart does not know where\n * a host's service lives, and guessing would be a request nobody asked for. */\n baseUrl: string\n /** How a request is made. Required, for the same reason. */\n request: RestRequest\n}\n\n/** A request the service answered in a way the contract does not define: a status with no meaning\n * here (`http`), or a body that is not the shape the route promises (`invalid-payload`). It carries\n * what the caller needs to decide: which request, and what came back. */\nexport class RestSaveLoadError extends Error {\n override readonly name = 'RestSaveLoadError'\n readonly reason: 'http' | 'invalid-payload'\n readonly status: number\n readonly method: string\n readonly url: string\n constructor(init: { reason: 'http' | 'invalid-payload'; status: number; method: string; url: string; detail: string }) {\n super(`${init.method} ${init.url}: ${init.detail}`)\n this.reason = init.reason\n this.status = init.status\n this.method = init.method\n this.url = init.url\n }\n}\n\nconst isRecord = (value: unknown): value is Record<string, unknown> => typeof value === 'object' && value !== null\n\n/** A ref the service stated, or null when it stated something else. Both fields are required and\n * both are strings: a numeric revision that arrived as a number is not this contract's ref, and\n * reading one loosely is how a client starts comparing revisions it cannot compare. */\nconst refOf = (value: unknown): ResourceRef | null => {\n if (!isRecord(value)) return null\n const { id, revision } = value as Partial<RestResourceRef>\n return typeof id === 'string' && id !== '' && typeof revision === 'string' ? { id, revision } : null\n}\n\n/** A layout's listing facts, carried only where they were stated: a service that keeps none answers\n * rows without them, and a row without them is a row the listing names by its time instead. */\nconst listingFacts = (from: { symbol?: string; timeframe?: string }): { symbol?: string; timeframe?: string } => ({\n ...(typeof from.symbol === 'string' ? { symbol: from.symbol } : {}),\n ...(typeof from.timeframe === 'string' ? { timeframe: from.timeframe } : {}),\n})\n\n/** The base URL with no trailing slash, so `${base}/charts` never doubles one. */\nconst trimBase = (baseUrl: string): string => baseUrl.replace(/\\/+$/, '')\n\nexport function createRestSaveLoadAdapter(options: RestSaveLoadOptions): ChartSaveLoadAdapter {\n const base = trimBase(options.baseUrl)\n const request = options.request\n\n /** One call: the abort check, the two contract headers, the host's request, and the status and\n * text it answered. Reading the status is each verb's own job, because what a 404 means differs\n * between a load (nothing there) and an update (the row is gone). */\n async function call(deps: { method: string; path: string; body?: unknown; ref?: ResourceRef; signal?: AbortSignal }): Promise<{ status: number; text: string }> {\n if (deps.signal?.aborted) throw new ResourceAbortError()\n const url = `${base}${deps.path}`\n const headers: Record<string, string> = {}\n if (deps.body !== undefined) headers['content-type'] = 'application/json'\n if (deps.ref) headers[REST_IF_MATCH_HEADER] = deps.ref.revision\n const init: RestRequestInit = { method: deps.method, headers }\n if (deps.body !== undefined) init.body = JSON.stringify(deps.body)\n if (deps.signal) init.signal = deps.signal\n const response = await request(url, init)\n const text = await response.text()\n return { status: response.status, text }\n }\n\n /** The JSON a 2xx carried, held to being an object. A body that is not one is the route's promise\n * broken, which is a failure to report rather than an empty answer to act on. */\n function payload(method: string, url: string, answer: { status: number; text: string }): Record<string, unknown> {\n let parsed: unknown = null\n try {\n parsed = answer.text === '' ? null : JSON.parse(answer.text)\n } catch {\n parsed = null\n }\n if (!isRecord(parsed))\n throw new RestSaveLoadError({ reason: 'invalid-payload', status: answer.status, method, url, detail: 'the response is not a JSON object' })\n return parsed\n }\n\n /** A non-2xx the caller did not name: raised with its status, so a host can tell a 401 from a 503\n * and decide (sign in again, back off, tell the viewer) rather than see an empty chart. */\n const httpError = (method: string, url: string, status: number): RestSaveLoadError =>\n new RestSaveLoadError({ reason: 'http', status, method, url, detail: `unexpected status ${status}` })\n\n /** One family over one collection. `metaOf` and `bodyOf` read the wire rows; `wireOf` writes the\n * body. The five verbs share the transport and the refusal mapping. */\n function store<Meta, Body, WireMeta, WireBody>(deps: {\n collection: RestCollection\n /** The collection's query, for a family whose collection is scoped (drawings). */\n query?: string\n metaOf: (row: WireMeta) => Meta\n bodyOf: (wire: WireBody, answer: { status: number; text: string }, url: string) => Body\n wireOf: (body: Body) => WireBody\n }): ResourceStore<Meta, Body> {\n const collectionPath = deps.query ? `${restCollectionPath(deps.collection)}?${deps.query}` : restCollectionPath(deps.collection)\n const itemPath = (id: string): string => restItemPath(deps.collection, id)\n\n /** A write's answer as the port's outcome: the ref it landed at, the ref that beat it, or the\n * absence it found. */\n const written = <T>(method: string, path: string, answer: { status: number; text: string }, carriesMeta: boolean): WriteOutcome<T> => {\n const url = `${base}${path}`\n if (answer.status === REST_STATUS.notFound) return { kind: 'not-found' }\n if (answer.status === REST_STATUS.conflict) {\n const conflict = payload(method, url, answer) as Partial<RestConflictBody>\n const current = refOf(conflict.current)\n if (!current) throw new RestSaveLoadError({ reason: 'invalid-payload', status: answer.status, method, url, detail: 'the conflict states no current ref' })\n return { kind: 'conflict', current }\n }\n if (answer.status < 200 || answer.status >= 300) throw httpError(method, url, answer.status)\n const body = payload(method, url, answer) as Partial<RestWriteResponse<WireMeta>>\n const ref = refOf(body)\n if (!ref) throw new RestSaveLoadError({ reason: 'invalid-payload', status: answer.status, method, url, detail: 'the write states no ref' })\n const outcome: WriteOutcome<T> = { kind: 'ok', ref }\n // A delete answers a ref alone; only a create or an update carries the stored row's meta.\n if (carriesMeta && body.meta !== undefined) outcome.value = deps.metaOf(body.meta) as unknown as T\n return outcome\n }\n\n return {\n async list(signal) {\n const answer = await call({ method: 'GET', path: collectionPath, signal })\n const url = `${base}${collectionPath}`\n if (answer.status < 200 || answer.status >= 300) throw httpError('GET', url, answer.status)\n const body = payload('GET', url, answer) as Partial<RestListResponse<WireMeta>>\n if (!Array.isArray(body.items)) throw new RestSaveLoadError({ reason: 'invalid-payload', status: answer.status, method: 'GET', url, detail: 'the listing states no items array' })\n return body.items.map(deps.metaOf)\n },\n async load(id, signal) {\n const path = itemPath(id)\n const url = `${base}${path}`\n const answer = await call({ method: 'GET', path, signal })\n if (answer.status === REST_STATUS.notFound) return null\n if (answer.status < 200 || answer.status >= 300) throw httpError('GET', url, answer.status)\n const body = payload('GET', url, answer) as Partial<RestLoadResponse<WireBody>>\n const ref = refOf(body)\n if (!ref || body.body === undefined || !isRecord(body.body))\n throw new RestSaveLoadError({ reason: 'invalid-payload', status: answer.status, method: 'GET', url, detail: 'the read states no ref and body' })\n return { ref, body: deps.bodyOf(body.body, answer, url) }\n },\n async create(body, signal) {\n const answer = await call({ method: 'POST', path: collectionPath, body: deps.wireOf(body), signal })\n return written<Meta>('POST', collectionPath, answer, true)\n },\n async update(ref, body, signal) {\n const path = itemPath(ref.id)\n const answer = await call({ method: 'PUT', path, body: deps.wireOf(body), ref, signal })\n return written<Meta>('PUT', path, answer, true)\n },\n async remove(ref, signal) {\n const path = itemPath(ref.id)\n const answer = await call({ method: 'DELETE', path, ref, signal })\n return written<void>('DELETE', path, answer, false)\n },\n }\n }\n\n const drawingStores = new Map<string, ResourceStore<DrawingsMeta, DrawingsBody>>()\n const templateStores = new Map<TemplateKind, ResourceStore<TemplateMeta, TemplateBody>>()\n\n return {\n charts: store<ChartMeta, ChartBody, RestChartMeta, RestChartBody>({\n collection: { family: 'charts' },\n metaOf: (r) => ({ id: r.id, revision: r.revision, name: r.name, symbol: r.symbol, timeframe: r.timeframe, updatedAt: r.updatedAt }),\n bodyOf: (w) => ({ name: w.name, symbol: w.symbol, timeframe: w.timeframe, content: w.content }),\n wireOf: (b) => ({ name: b.name, symbol: b.symbol, timeframe: b.timeframe, content: b.content }),\n }),\n layouts: store<LayoutMeta, LayoutBody, RestLayoutMeta, RestLayoutBody>({\n collection: { family: 'layouts' },\n metaOf: (r) => ({ id: r.id, revision: r.revision, name: r.name, ...listingFacts(r), updatedAt: r.updatedAt }),\n bodyOf: (w) => ({ name: w.name, ...listingFacts(w), content: w.content }),\n wireOf: (b) => ({ name: b.name, ...listingFacts(b), content: b.content }),\n }),\n drawings(context: DrawingResourceContext) {\n const key = drawingContextKey(context)\n let held = drawingStores.get(key)\n if (!held) {\n held = store<DrawingsMeta, DrawingsBody, RestDrawingsMeta, RestDrawingsBody>({\n collection: { family: 'drawings' },\n query: restDrawingsQuery(context),\n metaOf: (r) => ({ id: r.id, revision: r.revision, updatedAt: r.updatedAt }),\n // The document is the one body the chart itself reads, so this is where a stored row is\n // proved to be a document FOR THIS CONTEXT before the chart sees one. A row that is not\n // is refused rather than read as an empty document: an empty read is followed by a save,\n // and that save would replace the row it misread.\n bodyOf: (w, answer, url) => documentOf(w.content, context, answer.status, url),\n wireOf: (b) => ({ content: JSON.stringify(b) }),\n })\n drawingStores.set(key, held)\n }\n return held\n },\n templates(kind: TemplateKind) {\n let held = templateStores.get(kind)\n if (!held) {\n held = store<TemplateMeta, TemplateBody, RestTemplateMeta, RestTemplateBody>({\n collection: { family: 'templates', kind },\n metaOf: (r) => ({ id: r.id, revision: r.revision, name: r.name, ...(r.tool === undefined ? {} : { tool: r.tool }), updatedAt: r.updatedAt }),\n bodyOf: (w) => ({ name: w.name, ...(w.tool === undefined ? {} : { tool: w.tool }), content: w.content }),\n wireOf: (b) => ({ name: b.name, ...(b.tool === undefined ? {} : { tool: b.tool }), content: b.content }),\n })\n templateStores.set(kind, held)\n }\n return held\n },\n }\n}\n\n/** The stored text as this context's document, or a refusal. `parseDrawingDocument` is total and\n * answers an empty document for anything it cannot read, so the two cases it cannot distinguish\n * are separated here first: text that is not a document at all, and a document written for another\n * context. */\nfunction documentOf(content: string, context: DrawingResourceContext, status: number, url: string): DrawingsBody {\n const refuse = (detail: string): RestSaveLoadError => new RestSaveLoadError({ reason: 'invalid-payload', status, method: 'GET', url, detail })\n let raw: unknown = null\n try {\n raw = JSON.parse(content)\n } catch {\n throw refuse('the stored drawings row is not JSON')\n }\n if (!isRecord(raw)) throw refuse('the stored drawings row is not a drawings document')\n if (raw.version !== DRAWING_DOCUMENT_VERSION) throw refuse(`the stored drawings row is not a version-${String(DRAWING_DOCUMENT_VERSION)} document`)\n if (isRecord(raw.context) && drawingContextKey(raw.context as unknown as DrawingResourceContext) !== drawingContextKey(context))\n throw refuse('the stored drawings row is another context\\'s document')\n return parseDrawingDocument(raw, context)\n}\n"],"mappings":"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","names":[]}
|