- commit
- 6db79938d313540bb615716d4c3456b3d74a0b13
- parent
- 856a5b4f345b27d0f56914ef852533332d6e7371
- author
- Dami <dami.etoile@gmail.com>
@@ -0,0 +1,40 @@
1+import { readFile } from 'node:fs/promises'2+import { resolve } from 'node:path'3+4+const fixtureDirectory = resolve(import.meta.dirname, '../../ci/tests/diagrams')5+const fixtures = {6+ bytefield: 'bytefield.bf',7+ nomnoml: 'pirate.nomnoml',8+ vega: 'bar-chart.vega',9+ vegalite: 'discretizing-scale.vlite',10+ wavedrom: 'wavedrom.json5',11+}12+13+async function smoke([engine, filename]) {14+ const source = await readFile(resolve(fixtureDirectory, filename), 'utf8')15+ const endpoint = `https://${engine}.render.diagram.zip/v1/svg`16+ const response = await fetch(endpoint, {17+ method: 'POST',18+ headers: { Accept: 'image/svg+xml', 'Content-Type': 'application/json' },19+ body: JSON.stringify({20+ source,21+ format: 'svg',22+ options: {},23+ metadata: { title: '', description: '' },24+ presentation: { background: '', padding: 0, frame: false },25+ }),26+ })27+ const body = await response.text()28+ if (!response.ok) throw new Error(`${engine}: HTTP ${response.status}: ${body.slice(0, 240)}`)29+ if (!/<svg[\s>]/i.test(body)) throw new Error(`${engine}: response is not SVG`)30+ if (response.headers.get('X-Diagram-Unit') !== engine) throw new Error(`${engine}: unit identity header is missing`)31+ const pipeline = response.headers.get('X-Diagram-Pipeline')32+ if (engine === 'vegalite' ? pipeline !== 'vegalite,vega' : pipeline !== engine) {33+ throw new Error(`${engine}: unexpected pipeline ${pipeline}`)34+ }35+ return `${engine.padEnd(10)} ${response.headers.get('X-Diagram-Cache')?.padEnd(4)} ${body.length} bytes`36+}37+38+const results = await Promise.all(Object.entries(fixtures).map(smoke))39+for (const result of results) console.log(result)40+console.log(`${results.length}/${results.length} independent renderer units returned SVG`)@@ -1,156 +1,23 @@
1-import renderBytefield from 'bytefield-svg'2-import JSON5 from 'json5'3-import { renderSvg as renderNomnoml } from 'nomnoml'4-import { s as serializeOnml } from 'onml'5-import { parse as parseVega, View as VegaView, type Loader as VegaLoader, type Spec as VegaSpec } from 'vega'6-import { expressionInterpreter } from 'vega-interpreter'7-import { compile as compileVegaLite, type TopLevelSpec as VegaLiteSpec } from 'vega-lite'8-import { renderAny as renderWavedrom } from 'wavedrom'9-import darkSkins from 'wavedrom/skins/dark.js'10-import defaultSkins from 'wavedrom/skins/default.js'11-import lowkeySkins from 'wavedrom/skins/lowkey.js'12-import narrowSkins from 'wavedrom/skins/narrow.js'13-import narrowerSkins from 'wavedrom/skins/narrower.js'14-import narrowererSkins from 'wavedrom/skins/narrowerer.js'15-import { RenderError } from '../errors'16-import type { EngineId, RendererAdapter, RenderRequest, RenderResult } from '../types'17-18-type EdgeEngineId = 'bytefield' | 'nomnoml' | 'vega' | 'vegalite' | 'wavedrom'19-20-const versions: Record<EdgeEngineId, string> = {21- bytefield: 'bytefield-svg@1.11.0',22- nomnoml: 'nomnoml@1.7.0',23- vega: 'vega@6.3.1',24- vegalite: 'vega-lite@6.4.3',25- wavedrom: 'wavedrom@3.6.2',26-}27-28-const waveSkins = {29- dark: darkSkins.dark,30- default: defaultSkins.default,31- lowkey: lowkeySkins.lowkey,32- narrow: narrowSkins.narrow,33- narrower: narrowerSkins.narrower,34- narrowerer: narrowererSkins.narrowerer,35-}36-function result(id: EdgeEngineId, body: string): RenderResult {37- if (typeof body !== 'string' || body.trim() === '') {38- throw new RenderError(422, 'empty_render', `The ${id} renderer returned no SVG.`)39- }40- return { body, contentType: 'image/svg+xml', engineVersion: versions[id], runtime: 'edge-js' }41-}42-43-function parsedSpecification(source: string): unknown {44- const parsed: unknown = JSON.parse(source)45- if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) {46- throw new RenderError(422, 'render_failed', 'Vega source must be a JSON object.')47- }48- return parsed49-}50-51-function isVegaSpec(value: unknown): value is VegaSpec {52- return typeof value === 'object' && value !== null && !Array.isArray(value)53-}54-55-function isVegaLiteSpec(value: unknown): value is VegaLiteSpec {56- if (typeof value !== 'object' || value === null || Array.isArray(value)) return false57- const specification = value as Record<string, unknown>58- return ['mark', 'layer', 'facet', 'repeat', 'concat', 'hconcat', 'vconcat'].some(name => name in specification)59-}60-61-function containsUrl(value: unknown): boolean {62- const pending: unknown[] = [value]63- let visited = 064- while (pending.length > 0) {65- const current = pending.pop()66- if (++visited > 100_000) throw new RenderError(413, 'render_too_large', 'Vega specification is too complex.')67- if (Array.isArray(current)) {68- pending.push(...current)69- continue70- }71- if (typeof current !== 'object' || current === null) continue72- for (const [name, nested] of Object.entries(current)) {73- if (name.toLowerCase() === 'url' && nested !== undefined && nested !== null && nested !== '') return true74- pending.push(nested)75- }76- }77- return false78-}79-80-const disabledVegaLoader: VegaLoader = {81- load: async () => { throw new Error('External Vega data loading is disabled.') },82- http: async () => { throw new Error('External Vega HTTP loading is disabled.') },83- file: async () => { throw new Error('External Vega file loading is disabled.') },84- sanitize: async uri => ({ href: uri }),85-}86-87-async function renderVega(id: 'vega' | 'vegalite', source: string): Promise<string> {88- const input = parsedSpecification(source)89- if (containsUrl(input)) {90- throw new RenderError(422, 'unsafe_include', 'URL-backed Vega data and images are disabled; embed data as values.')91- }92- let specification: VegaSpec93- if (id === 'vegalite') {94- if (!isVegaLiteSpec(input)) throw new RenderError(422, 'render_failed', 'Vega-Lite source has no top-level view specification.')95- specification = compileVegaLite(input).spec96- } else {97- if (!isVegaSpec(input)) throw new RenderError(422, 'render_failed', 'Vega source must be a JSON object.')98- specification = input99- }100- const view = new VegaView(parseVega(specification, undefined, { ast: true }), {101- expr: expressionInterpreter,102- loader: disabledVegaLoader,103- renderer: 'none',104- })105- try {106- return await view.toSVG()107- } finally {108- view.finalize()109- }110-}111-112-async function renderEdge(id: EdgeEngineId, request: RenderRequest, signal: AbortSignal): Promise<RenderResult> {113- if (signal.aborted) throw signal.reason114- try {115- switch (id) {116- case 'nomnoml':117- return result(id, renderNomnoml(request.source))118- case 'bytefield':119- return result(id, renderBytefield(request.source))120- case 'vega':121- case 'vegalite':122- return result(id, await renderVega(id, request.source))123- case 'wavedrom': {124- const specification: unknown = JSON5.parse(request.source)125- const skin = request.options.skin126- if (skin !== undefined && !(skin in waveSkins)) {127- throw new RenderError(400, 'invalid_options', `Unknown WaveDrom skin: ${skin}.`)128- }129- if (skin !== undefined && typeof specification === 'object' && specification !== null) {130- const currentConfig = 'config' in specification && typeof specification.config === 'object' && specification.config !== null131- ? specification.config132- : {}133- Object.assign(specification, { config: { ...currentConfig, skin } })134- }135- return result(id, serializeOnml(renderWavedrom(0, specification, waveSkins)))136- }137- }138- } catch (error) {139- if (error instanceof RenderError) throw error140- const message = error instanceof Error ? error.message : String(error)141- throw new RenderError(422, 'render_failed', message.slice(0, 500) || `The ${id} renderer could not render this source.`)142- }1+import type { EngineId, RendererAdapter } from '../types'2+import { bytefieldAdapter } from './edge/bytefield'3+import { nomnomlAdapter } from './edge/nomnoml'4+import { vegaAdapter } from './edge/vega'5+import { vegaliteAdapter } from './edge/vegalite'6+import { wavedromAdapter } from './edge/wavedrom'7+import type { EdgeEngineId } from './edge/types'8+9+const adapters: Record<EdgeEngineId, RendererAdapter> = {10+ bytefield: bytefieldAdapter,11+ nomnoml: nomnomlAdapter,12+ vega: vegaAdapter,13+ vegalite: vegaliteAdapter,14+ wavedrom: wavedromAdapter,14315 }14416 14517 export function isEdgeEngine(id: EngineId): id is EdgeEngineId {146- return id in versions18+ return id in adapters14719 }14820 14921 export function edgeAdapter(id: EdgeEngineId): RendererAdapter {150- return {151- id,152- runtime: 'edge-js',153- version: versions[id],154- render: (request, signal) => renderEdge(id, request, signal),155- }22+ return adapters[id]15623 }@@ -0,0 +1,19 @@
1+import renderBytefield from 'bytefield-svg'2+import type { RendererAdapter } from '../../types'3+import { edgeFailure, edgeResult } from './types'4+5+const VERSION = 'bytefield-svg@1.11.0'6+7+export const bytefieldAdapter: RendererAdapter = {8+ id: 'bytefield',9+ runtime: 'edge-js',10+ version: VERSION,11+ render(request, signal) {12+ if (signal.aborted) throw signal.reason13+ try {14+ return Promise.resolve(edgeResult('bytefield', VERSION, renderBytefield(request.source)))15+ } catch (error) {16+ return edgeFailure('bytefield', error)17+ }18+ },19+}@@ -0,0 +1,19 @@
1+import { renderSvg } from 'nomnoml'2+import type { RendererAdapter } from '../../types'3+import { edgeFailure, edgeResult } from './types'4+5+const VERSION = 'nomnoml@1.7.0'6+7+export const nomnomlAdapter: RendererAdapter = {8+ id: 'nomnoml',9+ runtime: 'edge-js',10+ version: VERSION,11+ render(request, signal) {12+ if (signal.aborted) throw signal.reason13+ try {14+ return Promise.resolve(edgeResult('nomnoml', VERSION, renderSvg(request.source)))15+ } catch (error) {16+ return edgeFailure('nomnoml', error)17+ }18+ },19+}@@ -0,0 +1,17 @@
1+import { RenderError } from '../../errors'2+import type { RenderResult } from '../../types'3+4+export type EdgeEngineId = 'bytefield' | 'nomnoml' | 'vega' | 'vegalite' | 'wavedrom'5+6+export function edgeResult(id: EdgeEngineId, version: string, body: string): RenderResult {7+ if (typeof body !== 'string' || body.trim() === '') {8+ throw new RenderError(422, 'empty_render', `The ${id} renderer returned no SVG.`)9+ }10+ return { body, contentType: 'image/svg+xml', engineVersion: version, runtime: 'edge-js' }11+}12+13+export function edgeFailure(id: EdgeEngineId, error: unknown): never {14+ if (error instanceof RenderError) throw error15+ const message = error instanceof Error ? error.message : String(error)16+ throw new RenderError(422, 'render_failed', message.slice(0, 500) || `The ${id} renderer could not render this source.`)17+}@@ -0,0 +1,49 @@
1+import { parse, View, type Loader, type Spec } from 'vega'2+import { expressionInterpreter } from 'vega-interpreter'3+4+const disabledLoader: Loader = {5+ load: async () => { throw new Error('External Vega data loading is disabled.') },6+ http: async () => { throw new Error('External Vega HTTP loading is disabled.') },7+ file: async () => { throw new Error('External Vega file loading is disabled.') },8+ sanitize: async uri => ({ href: uri }),9+}10+11+export function parsedSpecification(source: string): Record<string, unknown> {12+ const parsed: unknown = JSON.parse(source)13+ if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) {14+ throw new Error('Vega source must be a JSON object.')15+ }16+ return parsed as Record<string, unknown>17+}18+19+export function containsUrl(value: unknown): boolean {20+ const pending: unknown[] = [value]21+ let visited = 022+ while (pending.length > 0) {23+ const current = pending.pop()24+ if (++visited > 100_000) throw new Error('Vega specification is too complex.')25+ if (Array.isArray(current)) {26+ pending.push(...current)27+ continue28+ }29+ if (typeof current !== 'object' || current === null) continue30+ for (const [name, nested] of Object.entries(current)) {31+ if (name.toLowerCase() === 'url' && nested !== undefined && nested !== null && nested !== '') return true32+ pending.push(nested)33+ }34+ }35+ return false36+}37+38+export async function renderVegaSpecification(specification: Spec): Promise<string> {39+ const view = new View(parse(specification, undefined, { ast: true }), {40+ expr: expressionInterpreter,41+ loader: disabledLoader,42+ renderer: 'none',43+ })44+ try {45+ return await view.toSVG()46+ } finally {47+ view.finalize()48+ }49+}@@ -0,0 +1,25 @@
1+import type { Spec } from 'vega'2+import { RenderError } from '../../errors'3+import type { RendererAdapter } from '../../types'4+import { containsUrl, parsedSpecification, renderVegaSpecification } from './vega-common'5+import { edgeFailure, edgeResult } from './types'6+7+const VERSION = 'vega@6.3.1'8+9+export const vegaAdapter: RendererAdapter = {10+ id: 'vega',11+ runtime: 'edge-js',12+ version: VERSION,13+ async render(request, signal) {14+ if (signal.aborted) throw signal.reason15+ try {16+ const specification = parsedSpecification(request.source)17+ if (containsUrl(specification)) {18+ throw new RenderError(422, 'unsafe_include', 'URL-backed Vega data and images are disabled; embed data as values.')19+ }20+ return edgeResult('vega', VERSION, await renderVegaSpecification(specification as Spec))21+ } catch (error) {22+ return edgeFailure('vega', error)23+ }24+ },25+}@@ -0,0 +1,30 @@
1+import { compile, type TopLevelSpec } from 'vega-lite'2+import { RenderError } from '../../errors'3+import type { RendererAdapter } from '../../types'4+import { containsUrl, parsedSpecification, renderVegaSpecification } from './vega-common'5+import { edgeFailure, edgeResult } from './types'6+7+const VERSION = 'vega-lite@6.4.3'8+9+const viewKeys = ['mark', 'layer', 'facet', 'repeat', 'concat', 'hconcat', 'vconcat']10+11+export const vegaliteAdapter: RendererAdapter = {12+ id: 'vegalite',13+ runtime: 'edge-js',14+ version: VERSION,15+ async render(request, signal) {16+ if (signal.aborted) throw signal.reason17+ try {18+ const input = parsedSpecification(request.source)19+ if (!viewKeys.some(name => name in input)) {20+ throw new RenderError(422, 'render_failed', 'Vega-Lite source has no top-level view specification.')21+ }22+ if (containsUrl(input)) {23+ throw new RenderError(422, 'unsafe_include', 'URL-backed Vega data and images are disabled; embed data as values.')24+ }25+ return edgeResult('vegalite', VERSION, await renderVegaSpecification(compile(input as unknown as TopLevelSpec).spec))26+ } catch (error) {27+ return edgeFailure('vegalite', error)28+ }29+ },30+}@@ -0,0 +1,48 @@
1+import JSON5 from 'json5'2+import { s as serializeOnml } from 'onml'3+import { renderAny } from 'wavedrom'4+import darkSkins from 'wavedrom/skins/dark.js'5+import defaultSkins from 'wavedrom/skins/default.js'6+import lowkeySkins from 'wavedrom/skins/lowkey.js'7+import narrowSkins from 'wavedrom/skins/narrow.js'8+import narrowerSkins from 'wavedrom/skins/narrower.js'9+import narrowererSkins from 'wavedrom/skins/narrowerer.js'10+import { RenderError } from '../../errors'11+import type { RendererAdapter } from '../../types'12+import { edgeFailure, edgeResult } from './types'13+14+const VERSION = 'wavedrom@3.6.2'15+16+const skins = {17+ dark: darkSkins.dark,18+ default: defaultSkins.default,19+ lowkey: lowkeySkins.lowkey,20+ narrow: narrowSkins.narrow,21+ narrower: narrowerSkins.narrower,22+ narrowerer: narrowererSkins.narrowerer,23+}24+25+export const wavedromAdapter: RendererAdapter = {26+ id: 'wavedrom',27+ runtime: 'edge-js',28+ version: VERSION,29+ render(request, signal) {30+ if (signal.aborted) throw signal.reason31+ try {32+ const specification: unknown = JSON5.parse(request.source)33+ const skin = request.options.skin34+ if (skin !== undefined && !(skin in skins)) {35+ throw new RenderError(400, 'invalid_options', `Unknown WaveDrom skin: ${skin}.`)36+ }37+ if (skin !== undefined && typeof specification === 'object' && specification !== null) {38+ const currentConfig = 'config' in specification && typeof specification.config === 'object' && specification.config !== null39+ ? specification.config40+ : {}41+ Object.assign(specification, { config: { ...currentConfig, skin } })42+ }43+ return Promise.resolve(edgeResult('wavedrom', VERSION, serializeOnml(renderAny(0, specification, skins))))44+ } catch (error) {45+ return edgeFailure('wavedrom', error)46+ }47+ },48+}@@ -0,0 +1,139 @@
1+import { RenderError, RequestError } from './errors'2+import { sanitizeAndDecorateSvg } from './svg'3+import type { EngineId, RendererAdapter, RenderRequest } from './types'4+import { parseUnitRenderRequest } from './validation'5+6+const CACHE_MAX_AGE = 1_8007+8+export interface RendererUnitDescriptor {9+ readonly id: EngineId10+ readonly kind: 'render' | 'translate' | 'compatibility'11+ readonly adapter: RendererAdapter12+ readonly pipeline?: readonly EngineId[]13+ readonly knownLosses?: readonly string[]14+}15+16+interface RendererUnitEnv {17+ RENDERER_BUILD: string18+}19+20+function json(value: unknown, init: ResponseInit = {}): Response {21+ const headers = new Headers(init.headers)22+ headers.set('Content-Type', 'application/json; charset=utf-8')23+ headers.set('Cache-Control', 'no-store')24+ headers.set('Access-Control-Allow-Origin', '*')25+ return Response.json(value, { ...init, headers })26+}27+28+function errorResponse(error: unknown): Response {29+ if (error instanceof RequestError || error instanceof RenderError) {30+ return json({ error: { code: error.code, message: error.message } }, { status: error.status })31+ }32+ return json({ error: { code: 'internal_error', message: 'The diagram could not be rendered.' } }, { status: 500 })33+}34+35+function canonicalRequest(request: RenderRequest): string {36+ const options = Object.fromEntries(Object.entries(request.options).sort(([left], [right]) => left.localeCompare(right)))37+ return JSON.stringify({ ...request, options })38+}39+40+function base64Url(bytes: Uint8Array): string {41+ let binary = ''42+ for (const byte of bytes) binary += String.fromCharCode(byte)43+ return btoa(binary).replaceAll('+', '-').replaceAll('/', '_').replace(/=+$/, '')44+}45+46+async function cacheRequestFor(request: RenderRequest, build: string): Promise<Request> {47+ const digest = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(canonicalRequest(request)))48+ return new Request(`https://diagramzip-unit-cache.invalid/${encodeURIComponent(request.engine)}/${encodeURIComponent(build)}/${base64Url(new Uint8Array(digest))}`)49+}50+51+function responseWithCacheStatus(response: Response, status: 'HIT' | 'MISS'): Response {52+ const headers = new Headers(response.headers)53+ headers.set('X-Diagram-Cache', status)54+ return new Response(response.body, { status: response.status, statusText: response.statusText, headers })55+}56+57+async function render(58+ descriptor: RendererUnitDescriptor,59+ request: RenderRequest,60+ build: string,61+ signal: AbortSignal,62+): Promise<Response> {63+ const rendered = await descriptor.adapter.render(request, signal)64+ if (signal.aborted) throw signal.reason65+ const body = sanitizeAndDecorateSvg(rendered.body, request.metadata, request.presentation, descriptor.id)66+ return new Response(body, {67+ headers: {68+ 'Access-Control-Allow-Origin': '*',69+ 'Cache-Control': `public, max-age=${CACHE_MAX_AGE}`,70+ 'Content-Security-Policy': "default-src 'none'; style-src 'unsafe-inline'; sandbox",71+ 'Content-Type': 'image/svg+xml; charset=utf-8',72+ 'X-Content-Type-Options': 'nosniff',73+ 'X-Diagram-Engine': descriptor.id,74+ 'X-Diagram-Engine-Version': rendered.engineVersion,75+ 'X-Diagram-Renderer': rendered.runtime,76+ 'X-Diagram-Unit': descriptor.id,77+ 'X-Diagram-Pipeline': [descriptor.id, ...(descriptor.pipeline ?? [])].join(','),78+ 'X-Renderer-Build': build,79+ },80+ })81+}82+83+function capabilities(descriptor: RendererUnitDescriptor, build: string): Response {84+ return json({85+ id: descriptor.id,86+ kind: descriptor.kind,87+ format: 'svg',88+ runtime: descriptor.adapter.runtime,89+ version: descriptor.adapter.version,90+ build,91+ pipeline: [descriptor.id, ...(descriptor.pipeline ?? [])],92+ knownLosses: descriptor.knownLosses ?? [],93+ }, { headers: { 'Cache-Control': 'public, max-age=300' } })94+}95+96+export function createRendererUnit(descriptor: RendererUnitDescriptor): ExportedHandler<RendererUnitEnv> {97+ if (descriptor.adapter.id !== descriptor.id) throw new Error('Renderer unit adapter identity does not match its unit identity.')98+99+ return {100+ async fetch(request, env, ctx): Promise<Response> {101+ const url = new URL(request.url)102+ if (request.method === 'OPTIONS') {103+ return new Response(null, {104+ status: 204,105+ headers: {106+ 'Access-Control-Allow-Headers': 'Accept, Content-Type',107+ 'Access-Control-Allow-Methods': 'GET, POST, OPTIONS',108+ 'Access-Control-Allow-Origin': '*',109+ 'Access-Control-Max-Age': '86400',110+ },111+ })112+ }113+ try {114+ if (request.method === 'GET' && url.pathname === '/v1/health') return json({ ok: true, id: descriptor.id })115+ if (request.method === 'GET' && url.pathname === '/v1/capabilities') return capabilities(descriptor, env.RENDERER_BUILD)116+ if (request.method !== 'POST' || url.pathname !== '/v1/svg') {117+ return json({ error: { code: 'not_found', message: 'Route not found.' } }, { status: 404 })118+ }119+ const input = await parseUnitRenderRequest(request, descriptor.id)120+ const cacheKey = await cacheRequestFor(input, env.RENDERER_BUILD)121+ const cached = await caches.default.match(cacheKey)122+ if (cached !== undefined) return responseWithCacheStatus(cached, 'HIT')123+ const response = await render(descriptor, input, env.RENDERER_BUILD, request.signal)124+ ctx.waitUntil(caches.default.put(cacheKey, response.clone()))125+ return responseWithCacheStatus(response, 'MISS')126+ } catch (error) {127+ if (!(error instanceof RequestError || error instanceof RenderError)) {128+ console.error(JSON.stringify({129+ message: 'unhandled renderer unit error',130+ unit: descriptor.id,131+ error: error instanceof Error ? error.message : String(error),132+ path: url.pathname,133+ }))134+ }135+ return errorResponse(error)136+ }137+ },138+ }139+}@@ -0,0 +1,9 @@
1+import { vegaAdapter } from '../adapters/edge/vega'2+import { createRendererUnit } from '../unit'3+4+export default createRendererUnit({5+ id: 'vega',6+ kind: 'render',7+ adapter: vegaAdapter,8+ knownLosses: ['URL-backed data and images are rejected; data must be embedded as values.', 'Only SVG is in the rendering contract.'],9+})@@ -0,0 +1,10 @@
1+import { vegaliteAdapter } from '../adapters/edge/vegalite'2+import { createRendererUnit } from '../unit'3+4+export default createRendererUnit({5+ id: 'vegalite',6+ kind: 'translate',7+ adapter: vegaliteAdapter,8+ pipeline: ['vega'],9+ knownLosses: ['URL-backed data and images are rejected; data must be embedded as values.', 'Only SVG is in the rendering contract.'],10+})@@ -0,0 +1,9 @@
1+import { wavedromAdapter } from '../adapters/edge/wavedrom'2+import { createRendererUnit } from '../unit'3+4+export default createRendererUnit({5+ id: 'wavedrom',6+ kind: 'render',7+ adapter: wavedromAdapter,8+ knownLosses: ['Only the six bundled Kroki skins are accepted.', 'Only SVG is in the rendering contract.'],9+})@@ -1,5 +1,5 @@
11 import { RequestError } from './errors'2-import { isEngineId, type RenderMetadata, type RenderPresentation, type RenderRequest } from './types'2+import { isEngineId, type EngineId, type RenderMetadata, type RenderPresentation, type RenderRequest } from './types'33 44 const MAX_REQUEST_BYTES = 1_048_57655 const MAX_SOURCE_LENGTH = 524_288@@ -101,7 +101,7 @@ function presentationValue(value: unknown): RenderPresentation {
101101 return { background, padding: Number(padding), frame }102102 }103103 104-export async function parseRenderRequest(request: Request): Promise<RenderRequest> {104+async function renderInput(request: Request): Promise<Record<string, unknown>> {105105 if (!request.headers.get('Content-Type')?.toLowerCase().startsWith('application/json')) {106106 throw new RequestError(415, 'unsupported_media_type', 'Render requests must use application/json.')107107 }@@ -112,9 +112,10 @@ export async function parseRenderRequest(request: Request): Promise<RenderReques
112112 if (error instanceof RequestError) throw error113113 throw new RequestError(400, 'invalid_json', 'Render request is not valid JSON.')114114 }115- const input = objectValue(value, 'request')116- const engine = boundedString(input.engine, 'engine', 32)117- if (!isEngineId(engine)) throw new RequestError(400, 'unknown_engine', `Unknown diagram engine: ${engine}.`)115+ return objectValue(value, 'request')116+}117+118+function parsedRequest(input: Record<string, unknown>, engine: EngineId): RenderRequest {118119 const source = boundedString(input.source, 'source', MAX_SOURCE_LENGTH)119120 if (source.trim() === '') throw new RequestError(400, 'empty_source', 'Diagram source cannot be empty.')120121 if (input.format !== undefined && input.format !== 'svg') {@@ -129,3 +130,18 @@ export async function parseRenderRequest(request: Request): Promise<RenderReques
129130 presentation: presentationValue(input.presentation),130131 }131132 }133+134+export async function parseRenderRequest(request: Request): Promise<RenderRequest> {135+ const input = await renderInput(request)136+ const engine = boundedString(input.engine, 'engine', 32)137+ if (!isEngineId(engine)) throw new RequestError(400, 'unknown_engine', `Unknown diagram engine: ${engine}.`)138+ return parsedRequest(input, engine)139+}140+141+export async function parseUnitRenderRequest(request: Request, engine: EngineId): Promise<RenderRequest> {142+ const input = await renderInput(request)143+ if (input.engine !== undefined) {144+ throw new RequestError(400, 'invalid_request', 'Renderer unit requests must not select an engine.')145+ }146+ return parsedRequest(input, engine)147+}@@ -0,0 +1,63 @@
1+import { describe, expect, it } from 'vitest'2+import { createRendererUnit } from '../src/unit'3+import type { RendererAdapter } from '../src/types'4+5+const adapter: RendererAdapter = {6+ id: 'vegalite',7+ runtime: 'edge-js',8+ version: 'test@1',9+ async render() {10+ return {11+ body: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 10"><text x="1" y="8">ok</text></svg>',12+ contentType: 'image/svg+xml',13+ engineVersion: 'test@1',14+ runtime: 'edge-js',15+ }16+ },17+}18+19+const unit = createRendererUnit({ id: 'vegalite', kind: 'translate', adapter, pipeline: ['vega'] })20+const fetchUnit = unit.fetch!21+const env = { RENDERER_BUILD: 'unit-test' }22+const context = {23+ waitUntil() {},24+ passThroughOnException() {},25+ props: {},26+} as unknown as ExecutionContext27+28+function request(body: unknown): Parameters<typeof fetchUnit>[0] {29+ return new Request('https://vegalite.render.diagram.zip/v1/svg', {30+ method: 'POST',31+ headers: { 'Content-Type': 'application/json' },32+ body: JSON.stringify(body),33+ }) as Parameters<typeof fetchUnit>[0]34+}35+36+describe('renderer unit protocol', () => {37+ it('assigns its own engine and exposes the explicit translation pipeline', async () => {38+ const response = await fetchUnit(request({ source: '{"mark":"point"}' }), env, context)39+ expect(response.status).toBe(200)40+ expect(response.headers.get('X-Diagram-Unit')).toBe('vegalite')41+ expect(response.headers.get('X-Diagram-Pipeline')).toBe('vegalite,vega')42+ expect(await response.text()).toContain('<text x="1" y="8">ok</text>')43+ })44+45+ it('rejects attempts to select a different engine inside a unit', async () => {46+ const response = await fetchUnit(request({ engine: 'mermaid', source: 'flowchart LR' }), env, context)47+ expect(response.status).toBe(400)48+ await expect(response.json()).resolves.toMatchObject({ error: { code: 'invalid_request' } })49+ })50+51+ it('describes only itself and its declared downstream unit', async () => {52+ const response = await fetchUnit(53+ new Request('https://vegalite.render.diagram.zip/v1/capabilities') as Parameters<typeof fetchUnit>[0],54+ env,55+ context,56+ )57+ await expect(response.json()).resolves.toMatchObject({58+ id: 'vegalite',59+ kind: 'translate',60+ pipeline: ['vegalite', 'vega'],61+ })62+ })63+})@@ -0,0 +1,10 @@
1+{2+ "$schema": "../node_modules/wrangler/config-schema.json",3+ "name": "diagramzip-render-bytefield",4+ "main": "../src/units/bytefield.ts",5+ "compatibility_date": "2026-08-20",6+ "compatibility_flags": ["nodejs_compat"],7+ "observability": { "enabled": true, "logs": { "head_sampling_rate": 1 } },8+ "vars": { "RENDERER_BUILD": "bytefield-svg-1.11.0-unit-1" },9+ "routes": [{ "pattern": "bytefield.render.diagram.zip", "custom_domain": true }]10+}@@ -0,0 +1,10 @@
1+{2+ "$schema": "../node_modules/wrangler/config-schema.json",3+ "name": "diagramzip-render-nomnoml",4+ "main": "../src/units/nomnoml.ts",5+ "compatibility_date": "2026-08-20",6+ "compatibility_flags": ["nodejs_compat"],7+ "observability": { "enabled": true, "logs": { "head_sampling_rate": 1 } },8+ "vars": { "RENDERER_BUILD": "nomnoml-1.7.0-unit-1" },9+ "routes": [{ "pattern": "nomnoml.render.diagram.zip", "custom_domain": true }]10+}@@ -0,0 +1,10 @@
1+{2+ "$schema": "../node_modules/wrangler/config-schema.json",3+ "name": "diagramzip-render-vega",4+ "main": "../src/units/vega.ts",5+ "compatibility_date": "2026-08-20",6+ "compatibility_flags": ["nodejs_compat"],7+ "observability": { "enabled": true, "logs": { "head_sampling_rate": 1 } },8+ "vars": { "RENDERER_BUILD": "vega-6.3.1-unit-1" },9+ "routes": [{ "pattern": "vega.render.diagram.zip", "custom_domain": true }]10+}@@ -0,0 +1,10 @@
1+{2+ "$schema": "../node_modules/wrangler/config-schema.json",3+ "name": "diagramzip-render-vegalite",4+ "main": "../src/units/vegalite.ts",5+ "compatibility_date": "2026-08-20",6+ "compatibility_flags": ["nodejs_compat"],7+ "observability": { "enabled": true, "logs": { "head_sampling_rate": 1 } },8+ "vars": { "RENDERER_BUILD": "vegalite-6.4.3-vega-6.3.1-unit-1" },9+ "routes": [{ "pattern": "vegalite.render.diagram.zip", "custom_domain": true }]10+}@@ -0,0 +1,10 @@
1+{2+ "$schema": "../node_modules/wrangler/config-schema.json",3+ "name": "diagramzip-render-wavedrom",4+ "main": "../src/units/wavedrom.ts",5+ "compatibility_date": "2026-08-20",6+ "compatibility_flags": ["nodejs_compat"],7+ "observability": { "enabled": true, "logs": { "head_sampling_rate": 1 } },8+ "vars": { "RENDERER_BUILD": "wavedrom-3.6.2-unit-1" },9+ "routes": [{ "pattern": "wavedrom.render.diagram.zip", "custom_domain": true }]10+}@@ -1,8 +1,13 @@
11 const CHANNEL = 'diagram.zip:renderer:v1'2-const FRAME_URL = '/diagram.zip/renderer-frame.html?v=2'32 const RENDER_TIMEOUT = 20_00043 5-export const CLIENT_RENDERER_IDS = Object.freeze(['mermaid', 'bpmn'])4+export const CLIENT_RENDERERS = Object.freeze({5+ mermaid: Object.freeze({ frameUrl: '/diagram.zip/renderer-frame.html?v=2' }),6+ bpmn: Object.freeze({ frameUrl: '/diagram.zip/renderer-frame.html?v=2' }),7+ excalidraw: Object.freeze({ frameUrl: 'https://excalidraw.render.diagram.zip/index.html?v=3' }),8+})9+10+export const CLIENT_RENDERER_IDS = Object.freeze(Object.keys(CLIENT_RENDERERS))611 712 function abortError(reason) {813 if (reason?.name === 'AbortError') return reason@@ -10,7 +15,7 @@ function abortError(reason) {
1015 }1116 1217 export class RendererFrame {13- constructor({ documentObject = document, windowObject = window, frameUrl = FRAME_URL } = {}) {18+ constructor({ documentObject = document, windowObject = window, frameUrl } = {}) {1419 this.document = documentObject1520 this.window = windowObject1621 this.frameUrl = frameUrl@@ -108,14 +113,19 @@ export class RendererFrame {
108113 }109114 }110115 111-let sharedFrame116+const frames = new Map()112117 113118 export function clientAdapterFor(engine) {114- if (!CLIENT_RENDERER_IDS.includes(engine)) return null115- sharedFrame ??= new RendererFrame()119+ const renderer = CLIENT_RENDERERS[engine]120+ if (!renderer) return null121+ let frame = frames.get(renderer.frameUrl)122+ if (!frame) {123+ frame = new RendererFrame({ frameUrl: renderer.frameUrl })124+ frames.set(renderer.frameUrl, frame)125+ }116126 return {117127 id: engine,118128 runtime: 'client',119- render: ({ source }, signal) => sharedFrame.render(engine, source, signal),129+ render: ({ source }, signal) => frame.render(engine, source, signal),120130 }121131 }@@ -1,5 +1,6 @@
11 import { clientAdapterFor } from './client-renderers.js'22 import { sanitizeAndDecorateSvg } from './client-svg.js'3+import { httpRendererUnitFor } from './renderer-units.js'34 45 function clamp(value, minimum, maximum) {56 return Math.min(Math.max(value, minimum), maximum)@@ -120,15 +121,47 @@ export class PreviewController {
120121 }121122 122123 async renderThroughGateway({ type, source, options, meta, presentation }, signal) {123- const response = await fetch('/render/v1/svg', {124+ const unitEndpoint = httpRendererUnitFor(type)125+ if (unitEndpoint) {126+ try {127+ const response = await this.renderRequest(128+ unitEndpoint,129+ { source, format: 'svg', options, metadata: meta, presentation },130+ signal,131+ )132+ if (response.ok || response.status < 500) return await this.renderResponse(response)133+ await response.body?.cancel()134+ } catch (error) {135+ if (error.name === 'AbortError') throw error136+ }137+ }138+139+ const response = await this.renderRequest('/render/v1/svg', {140+ engine: type,141+ source,142+ format: 'svg',143+ options,144+ metadata: meta,145+ presentation,146+ }, signal)147+ return this.renderResponse(response)148+ }149+150+ renderRequest(endpoint, body, signal) {151+ return fetch(endpoint, {124152 method: 'POST',125153 headers: { Accept: 'image/svg+xml', 'Content-Type': 'application/json' },126- body: JSON.stringify({ engine: type, source, format: 'svg', options, metadata: meta, presentation }),154+ body: JSON.stringify(body),127155 signal,128156 })157+ }158+159+ async renderResponse(response) {129160 if (!response.ok) throw new Error(await this.errorMessage(response))130161 this.status.dataset.cache = response.headers.get('X-Diagram-Cache')?.toLowerCase() ?? 'miss'131- this.status.dataset.renderer = response.headers.get('X-Diagram-Renderer')?.toLowerCase() ?? 'gateway'162+ this.status.dataset.renderer = response.headers.get('X-Diagram-Unit')?.toLowerCase()163+ ?? response.headers.get('X-Diagram-Renderer')?.toLowerCase()164+ ?? 'gateway'132165 return response.text()133166 }134167 @@ -0,0 +1,11 @@
1+export const HTTP_RENDERER_UNITS = Object.freeze({2+ bytefield: 'https://bytefield.render.diagram.zip/v1/svg',3+ nomnoml: 'https://nomnoml.render.diagram.zip/v1/svg',4+ vega: 'https://vega.render.diagram.zip/v1/svg',5+ vegalite: 'https://vegalite.render.diagram.zip/v1/svg',6+ wavedrom: 'https://wavedrom.render.diagram.zip/v1/svg',7+})8+9+export function httpRendererUnitFor(engine) {10+ return HTTP_RENDERER_UNITS[engine] ?? null11+}@@ -1,6 +1,6 @@
11 import assert from 'node:assert/strict'22 import test from 'node:test'3-import { CLIENT_RENDERER_IDS, RendererFrame, clientAdapterFor } from '../src/client-renderers.js'3+import { CLIENT_RENDERERS, CLIENT_RENDERER_IDS, RendererFrame, clientAdapterFor } from '../src/client-renderers.js'44 55 const CHANNEL = 'diagram.zip:renderer:v1'66 @@ -30,7 +30,8 @@ function fakeBrowser() {
3030 }3131 3232 test('registers the first client-native renderer cohort', () => {33- assert.deepEqual(CLIENT_RENDERER_IDS, ['mermaid', 'bpmn'])33+ assert.deepEqual(CLIENT_RENDERER_IDS, ['mermaid', 'bpmn', 'excalidraw'])34+ assert.equal(CLIENT_RENDERERS.excalidraw.frameUrl, 'https://excalidraw.render.diagram.zip/index.html?v=3')3435 assert.equal(clientAdapterFor('graphviz'), null)3536 })3637 @@ -0,0 +1,16 @@
1+import assert from 'node:assert/strict'2+import test from 'node:test'3+import { HTTP_RENDERER_UNITS, httpRendererUnitFor } from '../src/renderer-units.js'4+5+test('gives each Worker-native renderer its own origin', () => {6+ assert.deepEqual(Object.keys(HTTP_RENDERER_UNITS), ['bytefield', 'nomnoml', 'vega', 'vegalite', 'wavedrom'])7+ for (const [engine, endpoint] of Object.entries(HTTP_RENDERER_UNITS)) {8+ assert.equal(new URL(endpoint).hostname, `${engine}.render.diagram.zip`)9+ assert.equal(new URL(endpoint).pathname, '/v1/svg')10+ }11+})12+13+test('does not route compatibility renderers through an unrelated unit', () => {14+ assert.equal(httpRendererUnitFor('bytefield'), 'https://bytefield.render.diagram.zip/v1/svg')15+ assert.equal(httpRendererUnitFor('plantuml'), null)16+})@@ -0,0 +1,15 @@
1+/*2+ Access-Control-Allow-Origin: *3+ Cross-Origin-Resource-Policy: cross-origin4+ Referrer-Policy: no-referrer5+ X-Content-Type-Options: nosniff6+7+/index.html8+ Cache-Control: public, max-age=300, no-transform9+ Content-Security-Policy: default-src 'none'; script-src https://excalidraw.render.diagram.zip; style-src 'unsafe-inline'; img-src data: blob:; font-src https://excalidraw.render.diagram.zip data:; connect-src https://excalidraw.render.diagram.zip; worker-src 'none'; frame-src 'none'; base-uri 'none'; form-action 'none'10+11+/frame-v3.js12+ Cache-Control: public, max-age=31536000, immutable13+14+/fonts/*15+ Cache-Control: public, max-age=31536000, immutable@@ -0,0 +1,58 @@
1+const CHANNEL = 'diagram.zip:renderer:v1'2+const ENGINE = 'excalidraw'3+const VERSION = '@excalidraw/excalidraw@0.18.1'4+const MAX_SOURCE_LENGTH = 524_2885+6+// The frame has an opaque origin because diagram.zip omits allow-same-origin.7+// Resolve font files against the document URL rather than location.origin.8+window.EXCALIDRAW_ASSET_PATH = new URL('/', window.location.href).href9+const library = import('@excalidraw/excalidraw')10+11+let queue = Promise.resolve()12+13+function sceneFrom(source) {14+ if (typeof source !== 'string' || source.length > MAX_SOURCE_LENGTH) {15+ throw new Error('Excalidraw source must be a JSON string no larger than 512 KiB.')16+ }17+ const scene = JSON.parse(source)18+ if (typeof scene !== 'object' || scene === null || Array.isArray(scene)) {19+ throw new Error('Excalidraw source must be a JSON object.')20+ }21+ return scene22+}23+24+window.addEventListener('message', event => {25+ const message = event.data26+ if (27+ event.source !== parent28+ || message?.channel !== CHANNEL29+ || message?.type !== 'render'30+ || message?.engine !== ENGINE31+ || typeof message?.requestId !== 'string'32+ ) return33+34+ queue = queue.then(async () => {35+ try {36+ const { exportToSvg } = await library37+ const svg = await exportToSvg(sceneFrom(message.source))38+ parent.postMessage({39+ channel: CHANNEL,40+ type: 'result',41+ requestId: message.requestId,42+ ok: true,43+ svg: svg.outerHTML,44+ version: VERSION,45+ }, '*')46+ } catch (error) {47+ parent.postMessage({48+ channel: CHANNEL,49+ type: 'result',50+ requestId: message.requestId,51+ ok: false,52+ error: error instanceof Error ? error.message.slice(0, 500) : 'Excalidraw rendering failed.',53+ }, '*')54+ }55+ })56+})57+58+parent.postMessage({ channel: CHANNEL, type: 'ready', engine: ENGINE, version: VERSION }, '*')@@ -0,0 +1,14 @@
1+2+<html lang="en">3+ <head>4+ <meta charset="UTF-8">5+ <meta6+ http-equiv="Content-Security-Policy"7+ content="default-src 'none'; script-src https://excalidraw.render.diagram.zip; style-src 'unsafe-inline'; img-src data: blob:; font-src https://excalidraw.render.diagram.zip data:; connect-src https://excalidraw.render.diagram.zip; worker-src 'none'; frame-src 'none'; base-uri 'none'; form-action 'none'"8+ >9+ <title>Excalidraw renderer</title>10+ </head>11+ <body>12+ <script src="/frame-v3.js"></script>13+ </body>14+</html>@@ -0,0 +1,34 @@
1+const CAPABILITIES = Object.freeze({2+ id: 'excalidraw',3+ kind: 'render',4+ format: 'svg',5+ runtime: 'client',6+ version: '@excalidraw/excalidraw@0.18.1',7+ build: 'excalidraw-0.18.1-client-unit-1',8+ pipeline: ['excalidraw'],9+ frame: '/index.html?v=3',10+ knownLosses: [11+ 'External resources are blocked; image data must be embedded in the scene.',12+ 'Font subsetting is disabled by the sandbox policy, so exports embed the complete self-hosted font.',13+ ],14+})15+16+function json(value, init = {}) {17+ const headers = new Headers(init.headers)18+ headers.set('Access-Control-Allow-Origin', '*')19+ headers.set('Cache-Control', 'public, max-age=300')20+ headers.set('Content-Type', 'application/json; charset=utf-8')21+ return Response.json(value, { ...init, headers })22+}23+24+export default {25+ fetch(request, env) {26+ const url = new URL(request.url)27+ if (request.method === 'GET' && url.pathname === '/v1/health') return json({ ok: true, id: CAPABILITIES.id })28+ if (request.method === 'GET' && url.pathname === '/v1/capabilities') return json(CAPABILITIES)29+ if (url.pathname.startsWith('/v1/')) {30+ return json({ error: { code: 'not_found', message: 'Route not found.' } }, { status: 404 })31+ }32+ return env.ASSETS.fetch(request)33+ },34+}@@ -8,6 +8,8 @@
88 "scripts": {99 "prestart": "cp -r ./node_modules/@excalidraw/excalidraw/dist/prod/fonts ./assets/",1010 "build": "npx esbuild ./assets/index.js --bundle --minify --outfile=./assets/index.bundle.js",11+ "build:diagramzip-unit": "node ./scripts/build-diagramzip-unit.mjs",12+ "deploy:diagramzip-unit": "../diagramzip-render/node_modules/.bin/wrangler deploy --config wrangler.diagramzip.jsonc",1113 "start": "node src/index.js",1214 "test": "echo \"Error: no test specified\" && exit 1",1315 "lint": "biome check src"@@ -0,0 +1,24 @@
1+import { cp, mkdir, rm } from 'node:fs/promises'2+import { build } from 'esbuild'3+4+const output = new URL('../diagramzip-unit-dist/', import.meta.url)5+const packageAssets = new URL('../node_modules/@excalidraw/excalidraw/dist/prod/fonts/', import.meta.url)6+7+await rm(output, { recursive: true, force: true })8+await mkdir(output, { recursive: true })9+await Promise.all([10+ cp(new URL('../diagramzip-unit/index.html', import.meta.url), new URL('index.html', output)),11+ cp(new URL('../diagramzip-unit/_headers', import.meta.url), new URL('_headers', output)),12+ cp(packageAssets, new URL('fonts/', output), { recursive: true }),13+])14+15+await build({16+ entryPoints: [new URL('../diagramzip-unit/frame.js', import.meta.url).pathname],17+ bundle: true,18+ minify: true,19+ format: 'iife',20+ platform: 'browser',21+ outfile: new URL('frame-v3.js', output).pathname,22+ sourcemap: false,23+ treeShaking: true,24+})@@ -0,0 +1,22 @@
1+{2+ "$schema": "../diagramzip-render/node_modules/wrangler/config-schema.json",3+ "name": "diagramzip-render-excalidraw",4+ "main": "./diagramzip-unit/worker.js",5+ "compatibility_date": "2026-08-20",6+ "assets": {7+ "directory": "./diagramzip-unit-dist",8+ "binding": "ASSETS",9+ "html_handling": "none",10+ "not_found_handling": "none",11+ "run_worker_first": ["/v1/*"]12+ },13+ "observability": {14+ "enabled": true15+ },16+ "routes": [17+ {18+ "pattern": "excalidraw.render.diagram.zip",19+ "custom_domain": true20+ }21+ ]22+}@@ -1640,11 +1640,11 @@ Rel(bob, tandem, "Completes tasks")
16401640 +--------+--------+16411641 | Shared Tasks |16421642 | {s} |1643- +-----------------+`,d2:Cx,nwdiag:Ax,packetdiag:jx,rackdiag:Nx,bpmn:xx.replaceAll(`Examine Situation`,`Bob Agent tests Tandem`).replaceAll(`Things OK?`,`Tests pass?`).replaceAll(`Notification Sent`,`Alice and Bob share tasks`).replaceAll(`Error Propagated`,`Alice Agent revises flow`).replaceAll(`Klaus`,`Alice`).replaceAll(`Walter`,`Bob`),bytefield:Sx,dbml:wx,diagramsnet:Tx,erd:Ex,excalidraw:Dx,goat:Ox,nomnoml:kx,pikchr:Mx,svgbob:Px,symbolator:Fx,tikz:Ix,umlet:Lx,vega:Rx,vegalite:zx,wavedrom:Bx,wireviz:Vx},uC={plantuml:[`Tandem task sync`,`Alice and Bob coordinate shared tasks through their agents.`],mermaid:[`Shared task flow`,`A compact view of ideas moving through the Tandem team.`],graphviz:[`Tandem collaboration graph`,`People and agents converge on one synchronized task list.`],d2:[`Connection styles`,`D2 connection, arrowhead, shape, and animation syntax.`],c4plantuml:[`Tandem system context`,`The people and software systems surrounding Tandem.`],blockdiag:[`Tandem block flow`,`A block-oriented view of the shared task workflow.`],seqdiag:[`Tandem task sequence`,`A task moves from Alice to Bob and back through Tandem.`],actdiag:[`Tandem delivery activities`,`Work crosses Alice, Alice Agent, and Bob Agent lanes.`],nwdiag:[`Network layout`,`A sample network topology and its connected address ranges.`],packetdiag:[`TCP packet structure`,`The bit-level layout of a TCP packet header.`],rackdiag:[`Rack layout`,`A sample equipment rack rendered from rackdiag syntax.`],bpmn:[`Agent-assisted review`,`A BPMN review flow that branches on test results.`],bytefield:[`Byte field layout`,`A compact byte-oriented protocol field example.`],dbml:[`Database schema`,`Tables and relationships expressed with DBML.`],diagramsnet:[`Venn diagram`,`An overlapping-set example imported from diagrams.net.`],ditaa:[`Tandem ASCII architecture`,`An ASCII sketch becomes a rendered system diagram.`],erd:[`Data model`,`Entities and relationships in a small relational schema.`],excalidraw:[`Venn sketch`,`A hand-drawn overlapping-set diagram.`],goat:[`Component shapes`,`GoAT exercises boxes, connectors, curves, and symbols.`],nomnoml:[`Pirate class diagram`,`A playful class diagram demonstrating Nomnoml syntax.`],pikchr:[`Cardinal points`,`A diamond marks north, east, south, and west.`],structurizr:[`Tandem landscape`,`A software landscape linking people, agents, and Tandem.`],svgbob:[`Cloud network`,`An ASCII cloud connects clients and services.`],symbolator:[`Hardware component`,`A component symbol generated from interface declarations.`],tikz:[`Periodic table`,`A color-coded periodic table rendered with TikZ.`],umlet:[`UML example`,`A UMLet document rendered directly from its XML form.`],vega:[`Bar chart`,`A declarative bar chart expressed with Vega.`],vegalite:[`Discretizing scale`,`A Vega-Lite example comparing discretized values.`],wavedrom:[`Timing diagram`,`Digital signals and timing relationships rendered by WaveDrom.`],wireviz:[`Wiring harness`,`Connections, cables, and pins described with WireViz.`]};function dC(e){return lC[e]??oC}function fC(e){let t=mx.findIndex(t=>t.id===e),[n,r]=uC[e]??[`Diagram example`,`A diagram.zip catalog example.`];return{type:e,source:dC(e),options:{},...Ux(Math.max(t,0),{title:n,description:r})}}function pC(e,t,n,r,i){return e.set(t,{...r,type:t}),e.get(n)??i(n)}var mC=`/api/v1`,hC=/^[A-Za-z0-9_-]{16}$/,gC=/^[A-Za-z0-9_-]{43}$/;function _C(e){let t=``;for(let n of e)t+=String.fromCharCode(n);return btoa(t).replaceAll(`+`,`-`).replaceAll(`/`,`_`).replace(/=+$/,``)}function vC(){return _C(crypto.getRandomValues(new Uint8Array(32)))}function yC(e){return e.match(/^\/d\/([A-Za-z0-9_-]{16})\/?$/)?.[1]??null}function bC(e,t){if(!hC.test(t))throw Error(`Invalid diagram alias.`);return new URL(`/d/${t}`,e).toString()}function xC(e,t,n){if(!gC.test(n))throw Error(`Invalid write capability.`);let r=new URL(bC(e,t));return r.hash=`w=${n}`,r.toString()}function SC(e,t,n=`svg`){if(!hC.test(t))throw Error(`Invalid diagram alias.`);if(n!==`svg`&&n!==`png`)throw Error(`Invalid render format.`);return new URL(`${mC}/aliases/${t}/renders/${n}`,e).toString()}function CC(e){return e.match(/^#w=([A-Za-z0-9_-]{43})$/)?.[1]??null}var wC=class extends Error{constructor(e,{status:t,code:n}={}){super(e),this.status=t,this.code=n}};function TC(e){if(!e||typeof e!=`object`||typeof e.type!=`string`||typeof e.source!=`string`)throw Error(`Invalid diagram state.`);return{mode:`open`,diagram:{type:e.type,source:e.source,options:e.options??{},presentation:cC(e.presentation)},metadata:sC(e.meta)}}function EC(e){if(!e||typeof e!=`object`||!hC.test(e.aliasId)||!gC.test(e.contentId)||!gC.test(e.renderId)||!Number.isSafeInteger(e.revision)||e.mode!==`open`&&e.mode!==`locked`)throw new wC(`The persistence service returned an invalid response.`,{code:`invalid_response`});let t={aliasId:e.aliasId,contentId:e.contentId,renderId:e.renderId,revision:e.revision,mode:e.mode,createdAt:e.createdAt,updatedAt:e.updatedAt};if(e.mode===`locked`){if(!e.encryptedContent||!e.encryptedMetadata||!e.keyEnvelope)throw new wC(`The persistence service returned an invalid locked diagram.`,{code:`invalid_response`});return{...t,encryptedContent:e.encryptedContent,encryptedMetadata:e.encryptedMetadata,keyEnvelope:e.keyEnvelope}}if(!e.diagram||typeof e.diagram!=`object`)throw new wC(`The persistence service returned an invalid open diagram.`,{code:`invalid_response`});return{...t,state:{type:e.diagram.type,source:e.diagram.source,options:e.diagram.options??{},presentation:cC(e.diagram.presentation),meta:sC(e.metadata)}}}var DC=class{constructor({fetchImpl:e=globalThis.fetch,origin:t=globalThis.location?.origin??`http://localhost`,apiPrefix:n=mC}={}){this.fetch=(...t)=>e(...t),this.origin=t,this.apiPrefix=n.replace(/\/$/,``)}url(e=``){return new URL(`${this.apiPrefix}/aliases${e}`,this.origin)}async request(e,t){let n=await this.fetch(e,t),r=await n.json().catch(()=>null);if(!n.ok)throw new wC(r?.error?.message||`Persistence request failed with HTTP ${n.status}.`,{status:n.status,code:r?.error?.code});return EC(r)}async errorFor(e){let t=await e.json().catch(()=>null);return new wC(t?.error?.message||`Persistence request failed with HTTP ${e.status}.`,{status:e.status,code:t?.error?.code})}async createPayload(e){let t=vC();return{...await this.request(this.url(),{method:`POST`,headers:{Authorization:`Bearer ${t}`,"Content-Type":`application/json`},body:JSON.stringify(e)}),writeCapability:t}}createAlias(e){return this.createPayload(TC(e))}createLockedAlias(e){if(e?.mode!==`locked`)throw Error(`Invalid locked diagram payload.`);return this.createPayload(e)}getAlias(e){if(!hC.test(e))throw Error(`Invalid diagram alias.`);return this.request(this.url(`/${e}`),{headers:{Accept:`application/json`}})}updatePayload(e,t,n,r){if(!hC.test(e))throw Error(`Invalid diagram alias.`);if(!Number.isSafeInteger(n)||n<1)throw Error(`Invalid alias revision.`);if(!gC.test(r))throw Error(`Invalid write capability.`);return this.request(this.url(`/${e}`),{method:`PUT`,headers:{Accept:`application/json`,Authorization:`Bearer ${r}`,"Content-Type":`application/json`,"If-Match":`"${n}"`},body:JSON.stringify(t)})}updateAlias(e,t,n,r){return this.updatePayload(e,TC(t),n,r)}updateLockedAlias(e,t,n,r){if(t?.mode!==`locked`)throw Error(`Invalid locked diagram payload.`);return this.updatePayload(e,t,n,r)}async uploadRender({aliasId:e,renderId:t,revision:n,writeCapability:r,format:i,mode:a,render:o}){if(!hC.test(e))throw Error(`Invalid diagram alias.`);if(!gC.test(t))throw Error(`Invalid render ID.`);if(!Number.isSafeInteger(n)||n<1)throw Error(`Invalid alias revision.`);if(!gC.test(r))throw Error(`Invalid write capability.`);if(i!==`svg`&&i!==`png`)throw Error(`Invalid render format.`);if(a!==`open`&&a!==`locked`)throw Error(`Invalid diagram mode.`);let s=a===`locked`?`application/json`:i===`svg`?`image/svg+xml`:`image/png`,c=a===`locked`?JSON.stringify(o):o,l=await this.fetch(this.url(`/${e}/renders/${i}`),{method:`PUT`,headers:{Authorization:`Bearer ${r}`,"Content-Type":s,"If-Match":`"${n}"`,"X-Render-Id":t},body:c});if(!l.ok)throw await this.errorFor(l)}async getEncryptedRender(e,t){if(!hC.test(e))throw Error(`Invalid diagram alias.`);if(t!==`svg`&&t!==`png`)throw Error(`Invalid render format.`);let n=this.url(`/${e}/renders/${t}`);n.searchParams.set(`encrypted`,`1`);let r=await this.fetch(n,{headers:{Accept:`application/json`}});if(!r.ok)throw await this.errorFor(r);return r.json()}},OC=6e5,kC=new TextEncoder,AC=new TextDecoder,jC=kC.encode(`diagram.zip:content:v1`),MC=kC.encode(`diagram.zip:metadata:v1`),NC=kC.encode(`diagram.zip:bundle-key:v1`);function PC(e){if(e!==`svg`&&e!==`png`)throw Error(`Invalid render format.`);return kC.encode(`diagram.zip:render:${e}:v1`)}function FC(e){let t=``,n=32768;for(let r=0;r<e.length;r+=n)t+=String.fromCharCode(...e.subarray(r,r+n));return btoa(t).replaceAll(`+`,`-`).replaceAll(`/`,`_`).replace(/=+$/,``)}function IC(e){if(typeof e!=`string`||!/^[A-Za-z0-9_-]+$/.test(e))throw Error(`Invalid encrypted diagram.`);let t=e.replaceAll(`-`,`+`).replaceAll(`_`,`/`),n=t+`=`.repeat((4-t.length%4)%4),r=atob(n),i=Uint8Array.from(r,e=>e.charCodeAt(0));if(FC(i)!==e)throw Error(`Invalid encrypted diagram.`);return i}function LC(e){return crypto.getRandomValues(new Uint8Array(e))}async function RC(e,t){if(!(e instanceof Uint8Array)||e.byteLength!==32)throw Error(`Invalid diagram key.`);return crypto.subtle.importKey(`raw`,e,{name:`AES-GCM`},!1,t)}async function zC(e,{iterations:t,salt:n}){if(typeof e!=`string`)throw Error(`Password is required.`);let r=await crypto.subtle.importKey(`raw`,kC.encode(e),`PBKDF2`,!1,[`deriveKey`]);return crypto.subtle.deriveKey({name:`PBKDF2`,hash:`SHA-256`,iterations:t,salt:n},r,{name:`AES-GCM`,length:256},!1,[`encrypt`,`decrypt`])}async function BC(e,t,n){let r=LC(12),i=await crypto.subtle.encrypt({name:`AES-GCM`,iv:r,additionalData:n,tagLength:128},t,e);return{v:1,alg:`A256GCM`,iv:FC(r),ciphertext:FC(new Uint8Array(i))}}async function VC(e,t,n){if(!e||e.v!==1||e.alg!==`A256GCM`)throw Error(`Invalid encrypted diagram.`);let r=IC(e.iv);if(r.byteLength!==12)throw Error(`Invalid encrypted diagram.`);let i=IC(e.ciphertext);if(i.byteLength<16)throw Error(`Invalid encrypted diagram.`);return new Uint8Array(await crypto.subtle.decrypt({name:`AES-GCM`,iv:r,additionalData:n,tagLength:128},t,i))}async function HC(e,t,n){return BC(kC.encode(JSON.stringify(e)),t,n)}async function UC(e,t,n){return JSON.parse(AC.decode(await VC(e,t,n)))}function WC(e,t){if(!e||typeof e!=`object`||!bx(e.type)||typeof e.source!=`string`||!e.options||typeof e.options!=`object`||Array.isArray(e.options))throw Error(`Invalid encrypted diagram.`);return{type:e.type,source:e.source,options:e.options,presentation:cC(e.presentation),meta:sC(t)}}async function GC(e,t){if(typeof t!=`string`||t.length<8)throw Error(`Password must be at least 8 characters.`);let n=LC(16),r={name:`PBKDF2`,hash:`SHA-256`,iterations:OC,salt:FC(n)};return{v:1,kdf:r,wrap:await BC(e,await zC(t,{iterations:r.iterations,salt:n}),NC)}}async function KC(e,t){if(!e||e.v!==1||e.kdf?.name!==`PBKDF2`||e.kdf.hash!==`SHA-256`||!Number.isInteger(e.kdf.iterations)||e.kdf.iterations<1e5||e.kdf.iterations>5e6)throw Error(`Invalid encrypted diagram.`);let n=IC(e.kdf.salt);if(n.byteLength!==16)throw Error(`Invalid encrypted diagram.`);let r=await zC(t,{iterations:e.kdf.iterations,salt:n}),i=await VC(e.wrap,r,NC);if(i.byteLength!==32)throw Error(`Invalid encrypted diagram.`);return i}async function qC(e,t,n){let r=WC({type:e.type,source:e.source,options:e.options??{},presentation:e.presentation},e.meta),i=await RC(t,[`encrypt`]);return{mode:`locked`,encryptedContent:await HC({type:r.type,source:r.source,options:r.options,presentation:r.presentation},i,jC),encryptedMetadata:await HC(r.meta,i,MC),keyEnvelope:n}}async function JC(e,t){let n=LC(32);return{bundleKey:n,payload:await qC(e,n,await GC(n,t))}}async function YC(e,t){if(!e||e.mode!==`locked`)throw Error(`Invalid encrypted diagram.`);try{let n=await KC(e.keyEnvelope,t),r=await RC(n,[`decrypt`]),[i,a]=await Promise.all([UC(e.encryptedContent,r,jC),UC(e.encryptedMetadata,r,MC)]);return{bundleKey:n,state:WC(i,a)}}catch{throw Error(`Wrong password or damaged diagram.`)}}async function XC(e,t,n){if(!(e instanceof Blob))throw Error(`Invalid rendered image.`);let r=await RC(t,[`encrypt`]);return BC(new Uint8Array(await e.arrayBuffer()),r,PC(n))}var ZC=`diagram.zip:renderer:v1`,QC=`/diagram.zip/renderer-frame.html?v=2`,$C=2e4,ew=Object.freeze([`mermaid`,`bpmn`]);function tw(e){return e?.name===`AbortError`?e:new DOMException(`Render superseded.`,`AbortError`)}var nw=class{constructor({documentObject:e=document,windowObject:t=window,frameUrl:n=QC}={}){this.document=e,this.window=t,this.frameUrl=n,this.frame=null,this.ready=null,this.resolveReady=null,this.rejectReady=null,this.sequence=0,this.pending=new Map,this.handleMessage=e=>this.receive(e),this.window.addEventListener(`message`,this.handleMessage)}ensureFrame(){if(this.frame)return this.ready;let e=this.document.createElement(`iframe`);return e.title=`Diagram renderer`,e.setAttribute(`sandbox`,`allow-scripts`),e.setAttribute(`aria-hidden`,`true`),e.tabIndex=-1,Object.assign(e.style,{position:`fixed`,left:`-200vw`,top:`0`,width:`1280px`,height:`800px`,border:`0`,pointerEvents:`none`,visibility:`hidden`}),this.ready=new Promise((e,t)=>{this.resolveReady=e,this.rejectReady=t}),e.addEventListener(`error`,()=>this.rejectReady?.(Error(`The client renderer could not be loaded.`)),{once:!0}),e.src=this.frameUrl,this.frame=e,this.document.body.append(e),this.ready}receive(e){if(!this.frame||e.source!==this.frame.contentWindow||e.data?.channel!==ZC)return;if(e.data.type===`ready`){this.resolveReady?.(),this.resolveReady=null,this.rejectReady=null;return}if(e.data.type!==`result`)return;let t=this.pending.get(e.data.requestId);t&&(this.pending.delete(e.data.requestId),t.finish(),e.data.ok&&typeof e.data.svg==`string`?t.resolve({body:e.data.svg,version:e.data.version,runtime:`client`}):t.reject(Error(e.data.error||`Client rendering failed.`)))}async render(e,t,n){let r;try{await Promise.race([this.ensureFrame(),new Promise((e,t)=>{r=setTimeout(()=>t(Error(`The client renderer timed out while loading.`)),$C)})])}finally{clearTimeout(r)}if(n.aborted)throw tw(n.reason);let i=`${Date.now().toString(36)}-${++this.sequence}`;return new Promise((r,a)=>{let o=setTimeout(()=>{this.pending.delete(i),n.removeEventListener(`abort`,s),a(Error(`The client renderer timed out.`))},$C),s=()=>{this.pending.delete(i),clearTimeout(o),a(tw(n.reason))};n.addEventListener(`abort`,s,{once:!0}),this.pending.set(i,{resolve:r,reject:a,finish:()=>{clearTimeout(o),n.removeEventListener(`abort`,s)}}),this.frame.contentWindow.postMessage({channel:ZC,type:`render`,requestId:i,engine:e,source:t},`*`)})}},rw;function iw(e){return ew.includes(e)?(rw??=new nw,{id:e,runtime:`client`,render:({source:t},n)=>rw.render(e,t,n)}):null}var aw=e((e=>{Object.defineProperty(e,"__esModule",{value:!0}),e.CHAR=` 1643+ +-----------------+`,d2:Cx,nwdiag:Ax,packetdiag:jx,rackdiag:Nx,bpmn:xx.replaceAll(`Examine Situation`,`Bob Agent tests Tandem`).replaceAll(`Things OK?`,`Tests pass?`).replaceAll(`Notification Sent`,`Alice and Bob share tasks`).replaceAll(`Error Propagated`,`Alice Agent revises flow`).replaceAll(`Klaus`,`Alice`).replaceAll(`Walter`,`Bob`),bytefield:Sx,dbml:wx,diagramsnet:Tx,erd:Ex,excalidraw:Dx,goat:Ox,nomnoml:kx,pikchr:Mx,svgbob:Px,symbolator:Fx,tikz:Ix,umlet:Lx,vega:Rx,vegalite:zx,wavedrom:Bx,wireviz:Vx},uC={plantuml:[`Tandem task sync`,`Alice and Bob coordinate shared tasks through their agents.`],mermaid:[`Shared task flow`,`A compact view of ideas moving through the Tandem team.`],graphviz:[`Tandem collaboration graph`,`People and agents converge on one synchronized task list.`],d2:[`Connection styles`,`D2 connection, arrowhead, shape, and animation syntax.`],c4plantuml:[`Tandem system context`,`The people and software systems surrounding Tandem.`],blockdiag:[`Tandem block flow`,`A block-oriented view of the shared task workflow.`],seqdiag:[`Tandem task sequence`,`A task moves from Alice to Bob and back through Tandem.`],actdiag:[`Tandem delivery activities`,`Work crosses Alice, Alice Agent, and Bob Agent lanes.`],nwdiag:[`Network layout`,`A sample network topology and its connected address ranges.`],packetdiag:[`TCP packet structure`,`The bit-level layout of a TCP packet header.`],rackdiag:[`Rack layout`,`A sample equipment rack rendered from rackdiag syntax.`],bpmn:[`Agent-assisted review`,`A BPMN review flow that branches on test results.`],bytefield:[`Byte field layout`,`A compact byte-oriented protocol field example.`],dbml:[`Database schema`,`Tables and relationships expressed with DBML.`],diagramsnet:[`Venn diagram`,`An overlapping-set example imported from diagrams.net.`],ditaa:[`Tandem ASCII architecture`,`An ASCII sketch becomes a rendered system diagram.`],erd:[`Data model`,`Entities and relationships in a small relational schema.`],excalidraw:[`Venn sketch`,`A hand-drawn overlapping-set diagram.`],goat:[`Component shapes`,`GoAT exercises boxes, connectors, curves, and symbols.`],nomnoml:[`Pirate class diagram`,`A playful class diagram demonstrating Nomnoml syntax.`],pikchr:[`Cardinal points`,`A diamond marks north, east, south, and west.`],structurizr:[`Tandem landscape`,`A software landscape linking people, agents, and Tandem.`],svgbob:[`Cloud network`,`An ASCII cloud connects clients and services.`],symbolator:[`Hardware component`,`A component symbol generated from interface declarations.`],tikz:[`Periodic table`,`A color-coded periodic table rendered with TikZ.`],umlet:[`UML example`,`A UMLet document rendered directly from its XML form.`],vega:[`Bar chart`,`A declarative bar chart expressed with Vega.`],vegalite:[`Discretizing scale`,`A Vega-Lite example comparing discretized values.`],wavedrom:[`Timing diagram`,`Digital signals and timing relationships rendered by WaveDrom.`],wireviz:[`Wiring harness`,`Connections, cables, and pins described with WireViz.`]};function dC(e){return lC[e]??oC}function fC(e){let t=mx.findIndex(t=>t.id===e),[n,r]=uC[e]??[`Diagram example`,`A diagram.zip catalog example.`];return{type:e,source:dC(e),options:{},...Ux(Math.max(t,0),{title:n,description:r})}}function pC(e,t,n,r,i){return e.set(t,{...r,type:t}),e.get(n)??i(n)}var mC=`/api/v1`,hC=/^[A-Za-z0-9_-]{16}$/,gC=/^[A-Za-z0-9_-]{43}$/;function _C(e){let t=``;for(let n of e)t+=String.fromCharCode(n);return btoa(t).replaceAll(`+`,`-`).replaceAll(`/`,`_`).replace(/=+$/,``)}function vC(){return _C(crypto.getRandomValues(new Uint8Array(32)))}function yC(e){return e.match(/^\/d\/([A-Za-z0-9_-]{16})\/?$/)?.[1]??null}function bC(e,t){if(!hC.test(t))throw Error(`Invalid diagram alias.`);return new URL(`/d/${t}`,e).toString()}function xC(e,t,n){if(!gC.test(n))throw Error(`Invalid write capability.`);let r=new URL(bC(e,t));return r.hash=`w=${n}`,r.toString()}function SC(e,t,n=`svg`){if(!hC.test(t))throw Error(`Invalid diagram alias.`);if(n!==`svg`&&n!==`png`)throw Error(`Invalid render format.`);return new URL(`${mC}/aliases/${t}/renders/${n}`,e).toString()}function CC(e){return e.match(/^#w=([A-Za-z0-9_-]{43})$/)?.[1]??null}var wC=class extends Error{constructor(e,{status:t,code:n}={}){super(e),this.status=t,this.code=n}};function TC(e){if(!e||typeof e!=`object`||typeof e.type!=`string`||typeof e.source!=`string`)throw Error(`Invalid diagram state.`);return{mode:`open`,diagram:{type:e.type,source:e.source,options:e.options??{},presentation:cC(e.presentation)},metadata:sC(e.meta)}}function EC(e){if(!e||typeof e!=`object`||!hC.test(e.aliasId)||!gC.test(e.contentId)||!gC.test(e.renderId)||!Number.isSafeInteger(e.revision)||e.mode!==`open`&&e.mode!==`locked`)throw new wC(`The persistence service returned an invalid response.`,{code:`invalid_response`});let t={aliasId:e.aliasId,contentId:e.contentId,renderId:e.renderId,revision:e.revision,mode:e.mode,createdAt:e.createdAt,updatedAt:e.updatedAt};if(e.mode===`locked`){if(!e.encryptedContent||!e.encryptedMetadata||!e.keyEnvelope)throw new wC(`The persistence service returned an invalid locked diagram.`,{code:`invalid_response`});return{...t,encryptedContent:e.encryptedContent,encryptedMetadata:e.encryptedMetadata,keyEnvelope:e.keyEnvelope}}if(!e.diagram||typeof e.diagram!=`object`)throw new wC(`The persistence service returned an invalid open diagram.`,{code:`invalid_response`});return{...t,state:{type:e.diagram.type,source:e.diagram.source,options:e.diagram.options??{},presentation:cC(e.diagram.presentation),meta:sC(e.metadata)}}}var DC=class{constructor({fetchImpl:e=globalThis.fetch,origin:t=globalThis.location?.origin??`http://localhost`,apiPrefix:n=mC}={}){this.fetch=(...t)=>e(...t),this.origin=t,this.apiPrefix=n.replace(/\/$/,``)}url(e=``){return new URL(`${this.apiPrefix}/aliases${e}`,this.origin)}async request(e,t){let n=await this.fetch(e,t),r=await n.json().catch(()=>null);if(!n.ok)throw new wC(r?.error?.message||`Persistence request failed with HTTP ${n.status}.`,{status:n.status,code:r?.error?.code});return EC(r)}async errorFor(e){let t=await e.json().catch(()=>null);return new wC(t?.error?.message||`Persistence request failed with HTTP ${e.status}.`,{status:e.status,code:t?.error?.code})}async createPayload(e){let t=vC();return{...await this.request(this.url(),{method:`POST`,headers:{Authorization:`Bearer ${t}`,"Content-Type":`application/json`},body:JSON.stringify(e)}),writeCapability:t}}createAlias(e){return this.createPayload(TC(e))}createLockedAlias(e){if(e?.mode!==`locked`)throw Error(`Invalid locked diagram payload.`);return this.createPayload(e)}getAlias(e){if(!hC.test(e))throw Error(`Invalid diagram alias.`);return this.request(this.url(`/${e}`),{headers:{Accept:`application/json`}})}updatePayload(e,t,n,r){if(!hC.test(e))throw Error(`Invalid diagram alias.`);if(!Number.isSafeInteger(n)||n<1)throw Error(`Invalid alias revision.`);if(!gC.test(r))throw Error(`Invalid write capability.`);return this.request(this.url(`/${e}`),{method:`PUT`,headers:{Accept:`application/json`,Authorization:`Bearer ${r}`,"Content-Type":`application/json`,"If-Match":`"${n}"`},body:JSON.stringify(t)})}updateAlias(e,t,n,r){return this.updatePayload(e,TC(t),n,r)}updateLockedAlias(e,t,n,r){if(t?.mode!==`locked`)throw Error(`Invalid locked diagram payload.`);return this.updatePayload(e,t,n,r)}async uploadRender({aliasId:e,renderId:t,revision:n,writeCapability:r,format:i,mode:a,render:o}){if(!hC.test(e))throw Error(`Invalid diagram alias.`);if(!gC.test(t))throw Error(`Invalid render ID.`);if(!Number.isSafeInteger(n)||n<1)throw Error(`Invalid alias revision.`);if(!gC.test(r))throw Error(`Invalid write capability.`);if(i!==`svg`&&i!==`png`)throw Error(`Invalid render format.`);if(a!==`open`&&a!==`locked`)throw Error(`Invalid diagram mode.`);let s=a===`locked`?`application/json`:i===`svg`?`image/svg+xml`:`image/png`,c=a===`locked`?JSON.stringify(o):o,l=await this.fetch(this.url(`/${e}/renders/${i}`),{method:`PUT`,headers:{Authorization:`Bearer ${r}`,"Content-Type":s,"If-Match":`"${n}"`,"X-Render-Id":t},body:c});if(!l.ok)throw await this.errorFor(l)}async getEncryptedRender(e,t){if(!hC.test(e))throw Error(`Invalid diagram alias.`);if(t!==`svg`&&t!==`png`)throw Error(`Invalid render format.`);let n=this.url(`/${e}/renders/${t}`);n.searchParams.set(`encrypted`,`1`);let r=await this.fetch(n,{headers:{Accept:`application/json`}});if(!r.ok)throw await this.errorFor(r);return r.json()}},OC=6e5,kC=new TextEncoder,AC=new TextDecoder,jC=kC.encode(`diagram.zip:content:v1`),MC=kC.encode(`diagram.zip:metadata:v1`),NC=kC.encode(`diagram.zip:bundle-key:v1`);function PC(e){if(e!==`svg`&&e!==`png`)throw Error(`Invalid render format.`);return kC.encode(`diagram.zip:render:${e}:v1`)}function FC(e){let t=``,n=32768;for(let r=0;r<e.length;r+=n)t+=String.fromCharCode(...e.subarray(r,r+n));return btoa(t).replaceAll(`+`,`-`).replaceAll(`/`,`_`).replace(/=+$/,``)}function IC(e){if(typeof e!=`string`||!/^[A-Za-z0-9_-]+$/.test(e))throw Error(`Invalid encrypted diagram.`);let t=e.replaceAll(`-`,`+`).replaceAll(`_`,`/`),n=t+`=`.repeat((4-t.length%4)%4),r=atob(n),i=Uint8Array.from(r,e=>e.charCodeAt(0));if(FC(i)!==e)throw Error(`Invalid encrypted diagram.`);return i}function LC(e){return crypto.getRandomValues(new Uint8Array(e))}async function RC(e,t){if(!(e instanceof Uint8Array)||e.byteLength!==32)throw Error(`Invalid diagram key.`);return crypto.subtle.importKey(`raw`,e,{name:`AES-GCM`},!1,t)}async function zC(e,{iterations:t,salt:n}){if(typeof e!=`string`)throw Error(`Password is required.`);let r=await crypto.subtle.importKey(`raw`,kC.encode(e),`PBKDF2`,!1,[`deriveKey`]);return crypto.subtle.deriveKey({name:`PBKDF2`,hash:`SHA-256`,iterations:t,salt:n},r,{name:`AES-GCM`,length:256},!1,[`encrypt`,`decrypt`])}async function BC(e,t,n){let r=LC(12),i=await crypto.subtle.encrypt({name:`AES-GCM`,iv:r,additionalData:n,tagLength:128},t,e);return{v:1,alg:`A256GCM`,iv:FC(r),ciphertext:FC(new Uint8Array(i))}}async function VC(e,t,n){if(!e||e.v!==1||e.alg!==`A256GCM`)throw Error(`Invalid encrypted diagram.`);let r=IC(e.iv);if(r.byteLength!==12)throw Error(`Invalid encrypted diagram.`);let i=IC(e.ciphertext);if(i.byteLength<16)throw Error(`Invalid encrypted diagram.`);return new Uint8Array(await crypto.subtle.decrypt({name:`AES-GCM`,iv:r,additionalData:n,tagLength:128},t,i))}async function HC(e,t,n){return BC(kC.encode(JSON.stringify(e)),t,n)}async function UC(e,t,n){return JSON.parse(AC.decode(await VC(e,t,n)))}function WC(e,t){if(!e||typeof e!=`object`||!bx(e.type)||typeof e.source!=`string`||!e.options||typeof e.options!=`object`||Array.isArray(e.options))throw Error(`Invalid encrypted diagram.`);return{type:e.type,source:e.source,options:e.options,presentation:cC(e.presentation),meta:sC(t)}}async function GC(e,t){if(typeof t!=`string`||t.length<8)throw Error(`Password must be at least 8 characters.`);let n=LC(16),r={name:`PBKDF2`,hash:`SHA-256`,iterations:OC,salt:FC(n)};return{v:1,kdf:r,wrap:await BC(e,await zC(t,{iterations:r.iterations,salt:n}),NC)}}async function KC(e,t){if(!e||e.v!==1||e.kdf?.name!==`PBKDF2`||e.kdf.hash!==`SHA-256`||!Number.isInteger(e.kdf.iterations)||e.kdf.iterations<1e5||e.kdf.iterations>5e6)throw Error(`Invalid encrypted diagram.`);let n=IC(e.kdf.salt);if(n.byteLength!==16)throw Error(`Invalid encrypted diagram.`);let r=await zC(t,{iterations:e.kdf.iterations,salt:n}),i=await VC(e.wrap,r,NC);if(i.byteLength!==32)throw Error(`Invalid encrypted diagram.`);return i}async function qC(e,t,n){let r=WC({type:e.type,source:e.source,options:e.options??{},presentation:e.presentation},e.meta),i=await RC(t,[`encrypt`]);return{mode:`locked`,encryptedContent:await HC({type:r.type,source:r.source,options:r.options,presentation:r.presentation},i,jC),encryptedMetadata:await HC(r.meta,i,MC),keyEnvelope:n}}async function JC(e,t){let n=LC(32);return{bundleKey:n,payload:await qC(e,n,await GC(n,t))}}async function YC(e,t){if(!e||e.mode!==`locked`)throw Error(`Invalid encrypted diagram.`);try{let n=await KC(e.keyEnvelope,t),r=await RC(n,[`decrypt`]),[i,a]=await Promise.all([UC(e.encryptedContent,r,jC),UC(e.encryptedMetadata,r,MC)]);return{bundleKey:n,state:WC(i,a)}}catch{throw Error(`Wrong password or damaged diagram.`)}}async function XC(e,t,n){if(!(e instanceof Blob))throw Error(`Invalid rendered image.`);let r=await RC(t,[`encrypt`]);return BC(new Uint8Array(await e.arrayBuffer()),r,PC(n))}var ZC=`diagram.zip:renderer:v1`,QC=2e4,$C=Object.freeze({mermaid:Object.freeze({frameUrl:`/diagram.zip/renderer-frame.html?v=2`}),bpmn:Object.freeze({frameUrl:`/diagram.zip/renderer-frame.html?v=2`}),excalidraw:Object.freeze({frameUrl:`https://excalidraw.render.diagram.zip/index.html?v=3`})});Object.freeze(Object.keys($C));function ew(e){return e?.name===`AbortError`?e:new DOMException(`Render superseded.`,`AbortError`)}var tw=class{constructor({documentObject:e=document,windowObject:t=window,frameUrl:n}={}){this.document=e,this.window=t,this.frameUrl=n,this.frame=null,this.ready=null,this.resolveReady=null,this.rejectReady=null,this.sequence=0,this.pending=new Map,this.handleMessage=e=>this.receive(e),this.window.addEventListener(`message`,this.handleMessage)}ensureFrame(){if(this.frame)return this.ready;let e=this.document.createElement(`iframe`);return e.title=`Diagram renderer`,e.setAttribute(`sandbox`,`allow-scripts`),e.setAttribute(`aria-hidden`,`true`),e.tabIndex=-1,Object.assign(e.style,{position:`fixed`,left:`-200vw`,top:`0`,width:`1280px`,height:`800px`,border:`0`,pointerEvents:`none`,visibility:`hidden`}),this.ready=new Promise((e,t)=>{this.resolveReady=e,this.rejectReady=t}),e.addEventListener(`error`,()=>this.rejectReady?.(Error(`The client renderer could not be loaded.`)),{once:!0}),e.src=this.frameUrl,this.frame=e,this.document.body.append(e),this.ready}receive(e){if(!this.frame||e.source!==this.frame.contentWindow||e.data?.channel!==ZC)return;if(e.data.type===`ready`){this.resolveReady?.(),this.resolveReady=null,this.rejectReady=null;return}if(e.data.type!==`result`)return;let t=this.pending.get(e.data.requestId);t&&(this.pending.delete(e.data.requestId),t.finish(),e.data.ok&&typeof e.data.svg==`string`?t.resolve({body:e.data.svg,version:e.data.version,runtime:`client`}):t.reject(Error(e.data.error||`Client rendering failed.`)))}async render(e,t,n){let r;try{await Promise.race([this.ensureFrame(),new Promise((e,t)=>{r=setTimeout(()=>t(Error(`The client renderer timed out while loading.`)),QC)})])}finally{clearTimeout(r)}if(n.aborted)throw ew(n.reason);let i=`${Date.now().toString(36)}-${++this.sequence}`;return new Promise((r,a)=>{let o=setTimeout(()=>{this.pending.delete(i),n.removeEventListener(`abort`,s),a(Error(`The client renderer timed out.`))},QC),s=()=>{this.pending.delete(i),clearTimeout(o),a(ew(n.reason))};n.addEventListener(`abort`,s,{once:!0}),this.pending.set(i,{resolve:r,reject:a,finish:()=>{clearTimeout(o),n.removeEventListener(`abort`,s)}}),this.frame.contentWindow.postMessage({channel:ZC,type:`render`,requestId:i,engine:e,source:t},`*`)})}},nw=new Map;function rw(e){let t=$C[e];if(!t)return null;let n=nw.get(t.frameUrl);return n||(n=new tw({frameUrl:t.frameUrl}),nw.set(t.frameUrl,n)),{id:e,runtime:`client`,render:({source:t},r)=>n.render(e,t,r)}}var iw=e((e=>{Object.defineProperty(e,"__esModule",{value:!0}),e.CHAR=` 16441644 \r --�𐀀-`,e.S=` \r1645-`,e.NAME_START_CHAR=`:A-Z_a-zÀ-ÖØ-öø-˿Ͱ-ͽͿ-⁰-Ⰰ-、-豈-﷏ﷰ-�𐀀-`,e.NAME_CHAR=`-`+e.NAME_START_CHAR+`.0-9·̀-ͯ‿-⁀`,e.CHAR_RE=RegExp(`^[`+e.CHAR+`]$`,`u`),e.S_RE=RegExp(`^[`+e.S+`]+$`,`u`),e.NAME_START_CHAR_RE=RegExp(`^[`+e.NAME_START_CHAR+`]$`,`u`),e.NAME_CHAR_RE=RegExp(`^[`+e.NAME_CHAR+`]$`,`u`),e.NAME_RE=RegExp(`^[`+e.NAME_START_CHAR+`][`+e.NAME_CHAR+`]*$`,`u`),e.NMTOKEN_RE=RegExp(`^[`+e.NAME_CHAR+`]+$`,`u`);var t=9,n=10,r=13,i=32;e.S_LIST=[i,n,r,t];function a(e){return e>=i&&e<=55295||e===n||e===r||e===t||e>=57344&&e<=65533||e>=65536&&e<=1114111}e.isChar=a;function o(e){return e===i||e===n||e===r||e===t}e.isS=o;function s(e){return e>=65&&e<=90||e>=97&&e<=122||e===58||e===95||e===8204||e===8205||e>=192&&e<=214||e>=216&&e<=246||e>=248&&e<=767||e>=880&&e<=893||e>=895&&e<=8191||e>=8304&&e<=8591||e>=11264&&e<=12271||e>=12289&&e<=55295||e>=63744&&e<=64975||e>=65008&&e<=65533||e>=65536&&e<=983039}e.isNameStartChar=s;function c(e){return s(e)||e>=48&&e<=57||e===45||e===46||e===183||e>=768&&e<=879||e>=8255&&e<=8256}e.isNameChar=c})),ow=e((e=>{Object.defineProperty(e,"__esModule",{value:!0}),e.CHAR=`--�𐀀-`,e.RESTRICTED_CHAR=`-\b\v\f---`,e.S=` \r1646-`,e.NAME_START_CHAR=`:A-Z_a-zÀ-ÖØ-öø-˿Ͱ-ͽͿ-⁰-Ⰰ-、-豈-﷏ﷰ-�𐀀-`,e.NAME_CHAR=`-`+e.NAME_START_CHAR+`.0-9·̀-ͯ‿-⁀`,e.CHAR_RE=RegExp(`^[`+e.CHAR+`]$`,`u`),e.RESTRICTED_CHAR_RE=RegExp(`^[`+e.RESTRICTED_CHAR+`]$`,`u`),e.S_RE=RegExp(`^[`+e.S+`]+$`,`u`),e.NAME_START_CHAR_RE=RegExp(`^[`+e.NAME_START_CHAR+`]$`,`u`),e.NAME_CHAR_RE=RegExp(`^[`+e.NAME_CHAR+`]$`,`u`),e.NAME_RE=RegExp(`^[`+e.NAME_START_CHAR+`][`+e.NAME_CHAR+`]*$`,`u`),e.NMTOKEN_RE=RegExp(`^[`+e.NAME_CHAR+`]+$`,`u`);var t=9,n=10,r=13,i=32;e.S_LIST=[i,n,r,t];function a(e){return e>=1&&e<=55295||e>=57344&&e<=65533||e>=65536&&e<=1114111}e.isChar=a;function o(e){return e>=1&&e<=8||e===11||e===12||e>=14&&e<=31||e>=127&&e<=132||e>=134&&e<=159}e.isRestrictedChar=o;function s(e){return e===9||e===10||e===13||e>31&&e<127||e===133||e>159&&e<=55295||e>=57344&&e<=65533||e>=65536&&e<=1114111}e.isCharAndNotRestricted=s;function c(e){return e===i||e===n||e===r||e===t}e.isS=c;function l(e){return e>=65&&e<=90||e>=97&&e<=122||e===58||e===95||e===8204||e===8205||e>=192&&e<=214||e>=216&&e<=246||e>=248&&e<=767||e>=880&&e<=893||e>=895&&e<=8191||e>=8304&&e<=8591||e>=11264&&e<=12271||e>=12289&&e<=55295||e>=63744&&e<=64975||e>=65008&&e<=65533||e>=65536&&e<=983039}e.isNameStartChar=l;function u(e){return l(e)||e>=48&&e<=57||e===45||e===46||e===183||e>=768&&e<=879||e>=8255&&e<=8256}e.isNameChar=u})),sw=e((e=>{Object.defineProperty(e,"__esModule",{value:!0}),e.NC_NAME_START_CHAR=`A-Z_a-zÀ-ÖØ-öø-˿Ͱ-ͽͿ--⁰-Ⰰ-、-豈-﷏ﷰ-�𐀀-`,e.NC_NAME_CHAR=`-`+e.NC_NAME_START_CHAR+`.0-9·̀-ͯ‿-⁀`,e.NC_NAME_START_CHAR_RE=RegExp(`^[`+e.NC_NAME_START_CHAR+`]$`,`u`),e.NC_NAME_CHAR_RE=RegExp(`^[`+e.NC_NAME_CHAR+`]$`,`u`),e.NC_NAME_RE=RegExp(`^[`+e.NC_NAME_START_CHAR+`][`+e.NC_NAME_CHAR+`]*$`,`u`);function t(e){return e>=65&&e<=90||e===95||e>=97&&e<=122||e>=192&&e<=214||e>=216&&e<=246||e>=248&&e<=767||e>=880&&e<=893||e>=895&&e<=8191||e>=8204&&e<=8205||e>=8304&&e<=8591||e>=11264&&e<=12271||e>=12289&&e<=55295||e>=63744&&e<=64975||e>=65008&&e<=65533||e>=65536&&e<=983039}e.isNCNameStartChar=t;function n(e){return t(e)||e===45||e===46||e>=48&&e<=57||e===183||e>=768&&e<=879||e>=8255&&e<=8256}e.isNCNameChar=n})),cw=e((e=>{Object.defineProperty(e,"__esModule",{value:!0}),e.SaxesParser=e.EVENTS=void 0;var t=aw(),n=ow(),r=sw(),i=t.isS,a=t.isChar,o=t.isNameStartChar,s=t.isNameChar,c=t.S_LIST,l=t.NAME_RE,u=n.isChar,d=r.isNCNameStartChar,f=r.isNCNameChar,p=r.NC_NAME_RE,m=`http://www.w3.org/XML/1998/namespace`,h=`http://www.w3.org/2000/xmlns/`,g={__proto__:null,xml:m,xmlns:h},_={__proto__:null,amp:`&`,gt:`>`,lt:`<`,quot:`"`,apos:`'`},v=-1,y=-2,ee=0,te=1,ne=2,re=3,b=4,ie=5,ae=6,x=7,oe=8,S=9,se=10,ce=11,le=12,C=13,w=14,ue=15,de=16,fe=17,pe=18,me=19,he=20,T=21,ge=22,_e=23,E=24,ve=25,ye=26,be=27,xe=28,Se=29,Ce=30,we=31,Te=32,Ee=33,De=34,Oe=35,ke=36,Ae=37,je=38,Me=39,Ne=40,Pe=41,Fe=42,Ie=43,Le=44,Re=9,ze=10,Be=13,Ve=32,He=33,Ue=34,We=38,D=39,O=45,Ge=47,Ke=59,qe=60,Je=61,k=62,A=63,Ye=91,Xe=93,j=133,Ze=8232,Qe=e=>e===Ue||e===D,$e=[Ue,D],et=[...$e,Ye,k],M=[...$e,qe,Xe],tt=[Je,A,...c],nt=[...c,k,We,qe];function rt(e,t,n){switch(t){case`xml`:n!==m&&e.fail(`xml prefix must be bound to ${m}.`);break;case`xmlns`:n!==h&&e.fail(`xmlns prefix must be bound to ${h}.`)}switch(n){case h:e.fail(t===``?`the default namespace may not be set to ${n}.`:`may not assign a prefix (even "xmlns") to the URI \1647-${h}.`);break;case m:switch(t){case`xml`:break;case``:e.fail(`the default namespace may not be set to ${n}.`);break;default:e.fail(`may not assign the xml namespace to another prefix.`)}}}function it(e,t){for(let n of Object.keys(t))rt(e,n,t[n])}var at=e=>p.test(e),ot=e=>l.test(e),N=0,st=1,ct=2;e.EVENTS=[`xmldecl`,`text`,`processinginstruction`,`doctype`,`comment`,`opentagstart`,`attribute`,`opentag`,`closetag`,`cdata`,`error`,`end`,`ready`];var lt={xmldecl:`xmldeclHandler`,text:`textHandler`,processinginstruction:`piHandler`,doctype:`doctypeHandler`,comment:`commentHandler`,opentagstart:`openTagStartHandler`,attribute:`attributeHandler`,opentag:`openTagHandler`,closetag:`closeTagHandler`,cdata:`cdataHandler`,error:`errorHandler`,end:`endHandler`,ready:`readyHandler`};e.SaxesParser=class{constructor(e){this.opt=e??{},this.fragmentOpt=!!this.opt.fragment;let t=this.xmlnsOpt=!!this.opt.xmlns;if(this.trackPosition=this.opt.position!==!1,this.fileName=this.opt.fileName,t){this.nameStartCheck=d,this.nameCheck=f,this.isName=at,this.processAttribs=this.processAttribsNS,this.pushAttrib=this.pushAttribNS,this.ns=Object.assign({__proto__:null},g);let e=this.opt.additionalNamespaces;e!=null&&(it(this,e),Object.assign(this.ns,e))}else this.nameStartCheck=o,this.nameCheck=s,this.isName=ot,this.processAttribs=this.processAttribsPlain,this.pushAttrib=this.pushAttribPlain;this.stateTable=[this.sBegin,this.sBeginWhitespace,this.sDoctype,this.sDoctypeQuote,this.sDTD,this.sDTDQuoted,this.sDTDOpenWaka,this.sDTDOpenWakaBang,this.sDTDComment,this.sDTDCommentEnding,this.sDTDCommentEnded,this.sDTDPI,this.sDTDPIEnding,this.sText,this.sEntity,this.sOpenWaka,this.sOpenWakaBang,this.sComment,this.sCommentEnding,this.sCommentEnded,this.sCData,this.sCDataEnding,this.sCDataEnding2,this.sPIFirstChar,this.sPIRest,this.sPIBody,this.sPIEnding,this.sXMLDeclNameStart,this.sXMLDeclName,this.sXMLDeclEq,this.sXMLDeclValueStart,this.sXMLDeclValue,this.sXMLDeclSeparator,this.sXMLDeclEnding,this.sOpenTag,this.sOpenTagSlash,this.sAttrib,this.sAttribName,this.sAttribNameSawWhite,this.sAttribValue,this.sAttribValueQuoted,this.sAttribValueClosed,this.sAttribValueUnquoted,this.sCloseTag,this.sCloseTagSawWhite],this._init()}get closed(){return this._closed}_init(){var e;this.openWakaBang=``,this.text=``,this.name=``,this.piTarget=``,this.entity=``,this.q=null,this.tags=[],this.tag=null,this.topNS=null,this.chunk=``,this.chunkPosition=0,this.i=0,this.prevI=0,this.carriedFromPrevious=void 0,this.forbiddenState=N,this.attribList=[];let{fragmentOpt:t}=this;this.state=t?C:ee,this.reportedTextBeforeRoot=this.reportedTextAfterRoot=this.closedRoot=this.sawRoot=t,this.xmlDeclPossible=!t,this.xmlDeclExpects=[`version`],this.entityReturnState=void 0;let{defaultXMLVersion:n}=this.opt;if(n===void 0){if(this.opt.forceXMLVersion===!0)throw Error(`forceXMLVersion set but defaultXMLVersion is not set`);n=`1.0`}this.setXMLVersion(n),this.positionAtNewLine=0,this.doctype=!1,this._closed=!1,this.xmlDecl={version:void 0,encoding:void 0,standalone:void 0},this.line=1,this.column=0,this.ENTITIES=Object.create(_),(e=this.readyHandler)==null||e.call(this)}get position(){return this.chunkPosition+this.i}get columnIndex(){return this.position-this.positionAtNewLine}on(e,t){this[lt[e]]=t}off(e){this[lt[e]]=void 0}makeError(e){let t=this.fileName??``;return this.trackPosition&&(t.length>0&&(t+=`:`),t+=`${this.line}:${this.column}`),t.length>0&&(t+=`: `),Error(t+e)}fail(e){let t=this.makeError(e),n=this.errorHandler;if(n===void 0)throw t;return n(t),this}write(e){if(this.closed)return this.fail(`cannot write after close; assign an onready handler.`);let t=!1;e===null?(t=!0,e=``):typeof e==`object`&&(e=e.toString()),this.carriedFromPrevious!==void 0&&(e=`${this.carriedFromPrevious}${e}`,this.carriedFromPrevious=void 0);let n=e.length,r=e.charCodeAt(n-1);!t&&(r===Be||r>=55296&&r<=56319)&&(this.carriedFromPrevious=e[n-1],n--,e=e.slice(0,n));let{stateTable:i}=this;for(this.chunk=e,this.i=0;this.i<n;)i[this.state].call(this);return this.chunkPosition+=n,t?this.end():this}close(){return this.write(null)}getCode10(){let{chunk:e,i:t}=this;if(this.prevI=t,this.i=t+1,t>=e.length)return v;let n=e.charCodeAt(t);if(this.column++,n<55296){if(n>=Ve||n===Re)return n;switch(n){case ze:return this.line++,this.column=0,this.positionAtNewLine=this.position,ze;case Be:return e.charCodeAt(t+1)===ze&&(this.i=t+2),this.line++,this.column=0,this.positionAtNewLine=this.position,y;default:return this.fail(`disallowed character.`),n}}if(n>56319)return n>=57344&&n<=65533||this.fail(`disallowed character.`),n;let r=65536+(n-55296)*1024+(e.charCodeAt(t+1)-56320);return this.i=t+2,r>1114111&&this.fail(`disallowed character.`),r}getCode11(){let{chunk:e,i:t}=this;if(this.prevI=t,this.i=t+1,t>=e.length)return v;let n=e.charCodeAt(t);if(this.column++,n<55296){if(n>31&&n<127||n>159&&n!==Ze||n===Re)return n;switch(n){case ze:return this.line++,this.column=0,this.positionAtNewLine=this.position,ze;case Be:{let n=e.charCodeAt(t+1);(n===ze||n===j)&&(this.i=t+2)}case j:case Ze:return this.line++,this.column=0,this.positionAtNewLine=this.position,y;default:return this.fail(`disallowed character.`),n}}if(n>56319)return n>=57344&&n<=65533||this.fail(`disallowed character.`),n;let r=65536+(n-55296)*1024+(e.charCodeAt(t+1)-56320);return this.i=t+2,r>1114111&&this.fail(`disallowed character.`),r}getCodeNorm(){let e=this.getCode();return e===y?ze:e}unget(){this.i=this.prevI,this.column--}captureTo(e){let{i:t}=this,{chunk:n}=this;for(;;){let r=this.getCode(),i=r===y,a=i?ze:r;if(a===v||e.includes(a))return this.text+=n.slice(t,this.prevI),a;i&&(this.text+=`${n.slice(t,this.prevI)}\n`,t=this.i)}}captureToChar(e){let{i:t}=this,{chunk:n}=this;for(;;){let r=this.getCode();switch(r){case y:this.text+=`${n.slice(t,this.prevI)}\n`,t=this.i,r=ze;break;case v:return this.text+=n.slice(t),!1}if(r===e)return this.text+=n.slice(t,this.prevI),!0}}captureNameChars(){let{chunk:e,i:t}=this;for(;;){let n=this.getCode();if(n===v)return this.name+=e.slice(t),v;if(!s(n))return this.name+=e.slice(t,this.prevI),n===y?ze:n}}skipSpaces(){for(;;){let e=this.getCodeNorm();if(e===v||!i(e))return e}}setXMLVersion(e){this.currentXMLVersion=e,e===`1.0`?(this.isChar=a,this.getCode=this.getCode10):(this.isChar=u,this.getCode=this.getCode11)}sBegin(){this.chunk.charCodeAt(0)===65279&&(this.i++,this.column++),this.state=te}sBeginWhitespace(){let e=this.i,t=this.skipSpaces();switch(this.prevI!==e&&(this.xmlDeclPossible=!1),t){case qe:if(this.state=ue,this.text.length!==0)throw Error(`no-empty text at start`);break;case v:break;default:this.unget(),this.state=C,this.xmlDeclPossible=!1}}sDoctype(){var e;let t=this.captureTo(et);switch(t){case k:(e=this.doctypeHandler)==null||e.call(this,this.text),this.text=``,this.state=C,this.doctype=!0;break;case v:break;default:this.text+=String.fromCodePoint(t),t===Ye?this.state=b:Qe(t)&&(this.state=re,this.q=t)}}sDoctypeQuote(){let e=this.q;this.captureToChar(e)&&(this.text+=String.fromCodePoint(e),this.q=null,this.state=ne)}sDTD(){let e=this.captureTo(M);e!==v&&(this.text+=String.fromCodePoint(e),e===Xe?this.state=ne:e===qe?this.state=ae:Qe(e)&&(this.state=ie,this.q=e))}sDTDQuoted(){let e=this.q;this.captureToChar(e)&&(this.text+=String.fromCodePoint(e),this.state=b,this.q=null)}sDTDOpenWaka(){let e=this.getCodeNorm();switch(this.text+=String.fromCodePoint(e),e){case He:this.state=x,this.openWakaBang=``;break;case A:this.state=ce;break;default:this.state=b}}sDTDOpenWakaBang(){let e=String.fromCodePoint(this.getCodeNorm()),t=this.openWakaBang+=e;this.text+=e,t!==`-`&&(this.state=t===`--`?oe:b,this.openWakaBang=``)}sDTDComment(){this.captureToChar(O)&&(this.text+=`-`,this.state=S)}sDTDCommentEnding(){let e=this.getCodeNorm();this.text+=String.fromCodePoint(e),this.state=e===O?se:oe}sDTDCommentEnded(){let e=this.getCodeNorm();this.text+=String.fromCodePoint(e),e===k?this.state=b:(this.fail(`malformed comment.`),this.state=oe)}sDTDPI(){this.captureToChar(A)&&(this.text+=`?`,this.state=le)}sDTDPIEnding(){let e=this.getCodeNorm();this.text+=String.fromCodePoint(e),e===k&&(this.state=b)}sText(){this.tags.length===0?this.handleTextOutsideRoot():this.handleTextInRoot()}sEntity(){let{i:e}=this,{chunk:t}=this;loop:for(;;)switch(this.getCode()){case y:this.entity+=`${t.slice(e,this.prevI)}\n`,e=this.i;break;case Ke:{let{entityReturnState:n}=this,r=this.entity+t.slice(e,this.prevI);this.state=n;let i;r===``?(this.fail(`empty entity name.`),i=`&;`):(i=this.parseEntity(r),this.entity=``),(n!==C||this.textHandler!==void 0)&&(this.text+=i);break loop}case v:this.entity+=t.slice(e);break loop}}sOpenWaka(){let e=this.getCode();if(o(e))this.state=De,this.unget(),this.xmlDeclPossible=!1;else switch(e){case Ge:this.state=Ie,this.xmlDeclPossible=!1;break;case He:this.state=de,this.openWakaBang=``,this.xmlDeclPossible=!1;break;case A:this.state=_e;break;default:this.fail(`disallowed character in tag name`),this.state=C,this.xmlDeclPossible=!1}}sOpenWakaBang(){switch(this.openWakaBang+=String.fromCodePoint(this.getCodeNorm()),this.openWakaBang){case`[CDATA[`:!this.sawRoot&&!this.reportedTextBeforeRoot&&(this.fail(`text data outside of root node.`),this.reportedTextBeforeRoot=!0),this.closedRoot&&!this.reportedTextAfterRoot&&(this.fail(`text data outside of root node.`),this.reportedTextAfterRoot=!0),this.state=he,this.openWakaBang=``;break;case`--`:this.state=fe,this.openWakaBang=``;break;case`DOCTYPE`:this.state=ne,(this.doctype||this.sawRoot)&&this.fail(`inappropriately located doctype declaration.`),this.openWakaBang=``;break;default:this.openWakaBang.length>=7&&this.fail(`incorrect syntax.`)}}sComment(){this.captureToChar(O)&&(this.state=pe)}sCommentEnding(){var e;let t=this.getCodeNorm();t===O?(this.state=me,(e=this.commentHandler)==null||e.call(this,this.text),this.text=``):(this.text+=`-${String.fromCodePoint(t)}`,this.state=fe)}sCommentEnded(){let e=this.getCodeNorm();e===k?this.state=C:(this.fail(`malformed comment.`),this.text+=`--${String.fromCodePoint(e)}`,this.state=fe)}sCData(){this.captureToChar(Xe)&&(this.state=T)}sCDataEnding(){let e=this.getCodeNorm();e===Xe?this.state=ge:(this.text+=`]${String.fromCodePoint(e)}`,this.state=he)}sCDataEnding2(){var e;let t=this.getCodeNorm();switch(t){case k:(e=this.cdataHandler)==null||e.call(this,this.text),this.text=``,this.state=C;break;case Xe:this.text+=`]`;break;default:this.text+=`]]${String.fromCodePoint(t)}`,this.state=he}}sPIFirstChar(){let e=this.getCodeNorm();this.nameStartCheck(e)?(this.piTarget+=String.fromCodePoint(e),this.state=E):e===A||i(e)?(this.fail(`processing instruction without a target.`),this.state=e===A?ye:ve):(this.fail(`disallowed character in processing instruction name.`),this.piTarget+=String.fromCodePoint(e),this.state=E)}sPIRest(){let{chunk:e,i:t}=this;for(;;){let n=this.getCodeNorm();if(n===v){this.piTarget+=e.slice(t);return}if(!this.nameCheck(n)){this.piTarget+=e.slice(t,this.prevI);let r=n===A;r||i(n)?this.piTarget===`xml`?(this.xmlDeclPossible||this.fail(`an XML declaration must be at the start of the document.`),this.state=r?Ee:be):this.state=r?ye:ve:(this.fail(`disallowed character in processing instruction name.`),this.piTarget+=String.fromCodePoint(n));break}}}sPIBody(){if(this.text.length===0){let e=this.getCodeNorm();e===A?this.state=ye:i(e)||(this.text=String.fromCodePoint(e))}else this.captureToChar(A)&&(this.state=ye)}sPIEnding(){var e;let t=this.getCodeNorm();if(t===k){let{piTarget:t}=this;t.toLowerCase()===`xml`&&this.fail(`the XML declaration must appear at the start of the document.`),(e=this.piHandler)==null||e.call(this,{target:t,body:this.text}),this.piTarget=this.text=``,this.state=C}else t===A?this.text+=`?`:(this.text+=`?${String.fromCodePoint(t)}`,this.state=ve);this.xmlDeclPossible=!1}sXMLDeclNameStart(){let e=this.skipSpaces();if(e===A){this.state=Ee;return}e!==v&&(this.state=xe,this.name=String.fromCodePoint(e))}sXMLDeclName(){let e=this.captureTo(tt);if(e===A){this.state=Ee,this.name+=this.text,this.text=``,this.fail(`XML declaration is incomplete.`);return}if(i(e)||e===Je){if(this.name+=this.text,this.text=``,!this.xmlDeclExpects.includes(this.name))switch(this.name.length){case 0:this.fail(`did not expect any more name/value pairs.`);break;case 1:this.fail(`expected the name ${this.xmlDeclExpects[0]}.`);break;default:this.fail(`expected one of ${this.xmlDeclExpects.join(`, `)}`)}this.state=e===Je?Ce:Se}}sXMLDeclEq(){let e=this.getCodeNorm();if(e===A){this.state=Ee,this.fail(`XML declaration is incomplete.`);return}i(e)||(e!==Je&&this.fail(`value required.`),this.state=Ce)}sXMLDeclValueStart(){let e=this.getCodeNorm();if(e===A){this.state=Ee,this.fail(`XML declaration is incomplete.`);return}i(e)||(Qe(e)?this.q=e:(this.fail(`value must be quoted.`),this.q=Ve),this.state=we)}sXMLDeclValue(){let e=this.captureTo([this.q,A]);if(e===A){this.state=Ee,this.text=``,this.fail(`XML declaration is incomplete.`);return}if(e===v)return;let t=this.text;switch(this.text=``,this.name){case`version`:{this.xmlDeclExpects=[`encoding`,`standalone`];let e=t;this.xmlDecl.version=e,/^1\.[0-9]+$/.test(e)?this.opt.forceXMLVersion||this.setXMLVersion(e):this.fail(`version number must match /^1\\.[0-9]+$/.`);break}case`encoding`:/^[A-Za-z][A-Za-z0-9._-]*$/.test(t)||this.fail(`encoding value must match /^[A-Za-z0-9][A-Za-z0-9._-]*$/.`),this.xmlDeclExpects=[`standalone`],this.xmlDecl.encoding=t;break;case`standalone`:t!==`yes`&&t!==`no`&&this.fail(`standalone value must match "yes" or "no".`),this.xmlDeclExpects=[],this.xmlDecl.standalone=t}this.name=``,this.state=Te}sXMLDeclSeparator(){let e=this.getCodeNorm();if(e===A){this.state=Ee;return}i(e)||(this.fail(`whitespace required.`),this.unget()),this.state=be}sXMLDeclEnding(){var e;this.getCodeNorm()===k?(this.piTarget===`xml`?this.name!==`version`&&this.xmlDeclExpects.includes(`version`)&&this.fail(`XML declaration must contain a version.`):this.fail(`processing instructions are not allowed before root.`),(e=this.xmldeclHandler)==null||e.call(this,this.xmlDecl),this.name=``,this.piTarget=this.text=``,this.state=C):this.fail(`The character ? is disallowed anywhere in XML declarations.`),this.xmlDeclPossible=!1}sOpenTag(){var e;let t=this.captureNameChars();if(t===v)return;let n=this.tag={name:this.name,attributes:Object.create(null)};switch(this.name=``,this.xmlnsOpt&&(this.topNS=n.ns=Object.create(null)),(e=this.openTagStartHandler)==null||e.call(this,n),this.sawRoot=!0,!this.fragmentOpt&&this.closedRoot&&this.fail(`documents may contain only one root.`),t){case k:this.openTag();break;case Ge:this.state=Oe;break;default:i(t)||this.fail(`disallowed character in tag name.`),this.state=ke}}sOpenTagSlash(){this.getCode()===k?this.openSelfClosingTag():(this.fail(`forward-slash in opening tag not followed by >.`),this.state=ke)}sAttrib(){let e=this.skipSpaces();e!==v&&(o(e)?(this.unget(),this.state=Ae):e===k?this.openTag():e===Ge?this.state=Oe:this.fail(`disallowed character in attribute name.`))}sAttribName(){let e=this.captureNameChars();e===Je?this.state=Me:i(e)?this.state=je:e===k?(this.fail(`attribute without value.`),this.pushAttrib(this.name,this.name),this.name=this.text=``,this.openTag()):e!==v&&this.fail(`disallowed character in attribute name.`)}sAttribNameSawWhite(){let e=this.skipSpaces();switch(e){case v:return;case Je:this.state=Me;break;default:this.fail(`attribute without value.`),this.text=``,this.name=``,e===k?this.openTag():o(e)?(this.unget(),this.state=Ae):(this.fail(`disallowed character in attribute name.`),this.state=ke)}}sAttribValue(){let e=this.getCodeNorm();Qe(e)?(this.q=e,this.state=Ne):i(e)||(this.fail(`unquoted attribute value.`),this.state=Fe,this.unget())}sAttribValueQuoted(){let{q:e,chunk:t}=this,{i:n}=this;for(;;)switch(this.getCode()){case e:this.pushAttrib(this.name,this.text+t.slice(n,this.prevI)),this.name=this.text=``,this.q=null,this.state=Pe;return;case We:this.text+=t.slice(n,this.prevI),this.state=w,this.entityReturnState=Ne;return;case ze:case y:case Re:this.text+=`${t.slice(n,this.prevI)} `,n=this.i;break;case qe:this.text+=t.slice(n,this.prevI),this.fail(`disallowed character.`);return;case v:this.text+=t.slice(n);return}}sAttribValueClosed(){let e=this.getCodeNorm();i(e)?this.state=ke:e===k?this.openTag():e===Ge?this.state=Oe:o(e)?(this.fail(`no whitespace between attributes.`),this.unget(),this.state=Ae):this.fail(`disallowed character in attribute name.`)}sAttribValueUnquoted(){let e=this.captureTo(nt);switch(e){case We:this.state=w,this.entityReturnState=Fe;break;case qe:this.fail(`disallowed character.`);break;case v:break;default:this.text.includes(`]]>`)&&this.fail(`the string "]]>" is disallowed in char data.`),this.pushAttrib(this.name,this.text),this.name=this.text=``,e===k?this.openTag():this.state=ke}}sCloseTag(){let e=this.captureNameChars();e===k?this.closeTag():i(e)?this.state=Le:e!==v&&this.fail(`disallowed character in closing tag.`)}sCloseTagSawWhite(){switch(this.skipSpaces()){case k:this.closeTag();break;case v:break;default:this.fail(`disallowed character in closing tag.`)}}handleTextInRoot(){let{i:e,forbiddenState:t}=this,{chunk:n,textHandler:r}=this;scanLoop:for(;;)switch(this.getCode()){case qe:if(this.state=ue,r!==void 0){let{text:t}=this,i=n.slice(e,this.prevI);t.length===0?i.length!==0&&r(i):(r(t+i),this.text=``)}t=N;break scanLoop;case We:this.state=w,this.entityReturnState=C,r!==void 0&&(this.text+=n.slice(e,this.prevI)),t=N;break scanLoop;case Xe:switch(t){case N:t=st;break;case st:t=ct;break;case ct:break;default:throw Error(`impossible state`)}break;case k:t===ct&&this.fail(`the string "]]>" is disallowed in char data.`),t=N;break;case y:r!==void 0&&(this.text+=`${n.slice(e,this.prevI)}\n`),e=this.i,t=N;break;case v:r!==void 0&&(this.text+=n.slice(e));break scanLoop;default:t=N}this.forbiddenState=t}handleTextOutsideRoot(){let{i:e}=this,{chunk:t,textHandler:n}=this,r=!1;outRootLoop:for(;;){let a=this.getCode();switch(a){case qe:if(this.state=ue,n!==void 0){let{text:r}=this,i=t.slice(e,this.prevI);r.length===0?i.length!==0&&n(i):(n(r+i),this.text=``)}break outRootLoop;case We:this.state=w,this.entityReturnState=C,n!==void 0&&(this.text+=t.slice(e,this.prevI)),r=!0;break outRootLoop;case y:n!==void 0&&(this.text+=`${t.slice(e,this.prevI)}\n`),e=this.i;break;case v:n!==void 0&&(this.text+=t.slice(e));break outRootLoop;default:i(a)||(r=!0)}}r&&(!this.sawRoot&&!this.reportedTextBeforeRoot&&(this.fail(`text data outside of root node.`),this.reportedTextBeforeRoot=!0),this.closedRoot&&!this.reportedTextAfterRoot&&(this.fail(`text data outside of root node.`),this.reportedTextAfterRoot=!0))}pushAttribNS(e,t){var n;let{prefix:r,local:i}=this.qname(e),a={name:e,prefix:r,local:i,value:t};if(this.attribList.push(a),(n=this.attributeHandler)==null||n.call(this,a),r===`xmlns`){let e=t.trim();this.currentXMLVersion===`1.0`&&e===``&&this.fail(`invalid attempt to undefine prefix in XML 1.0`),this.topNS[i]=e,rt(this,i,e)}else if(e===`xmlns`){let e=t.trim();this.topNS[``]=e,rt(this,``,e)}}pushAttribPlain(e,t){var n;let r={name:e,value:t};this.attribList.push(r),(n=this.attributeHandler)==null||n.call(this,r)}end(){var e,t;this.sawRoot||this.fail(`document must contain a root element.`);let{tags:n}=this;for(;n.length>0;){let e=n.pop();this.fail(`unclosed tag: ${e.name}`)}this.state!==ee&&this.state!==C&&this.fail(`unexpected end.`);let{text:r}=this;return r.length!==0&&((e=this.textHandler)==null||e.call(this,r),this.text=``),this._closed=!0,(t=this.endHandler)==null||t.call(this),this._init(),this}resolve(e){var t;let n=this.topNS[e];if(n!==void 0)return n;let{tags:r}=this;for(let t=r.length-1;t>=0;t--)if(n=r[t].ns[e],n!==void 0)return n;return n=this.ns[e],n===void 0?(t=this.opt).resolvePrefix?.call(t,e):n}qname(e){let t=e.indexOf(`:`);if(t===-1)return{prefix:``,local:e};let n=e.slice(t+1),r=e.slice(0,t);return(r===``||n===``||n.includes(`:`))&&this.fail(`malformed name: ${e}.`),{prefix:r,local:n}}processAttribsNS(){let{attribList:e}=this,t=this.tag;{let{prefix:e,local:n}=this.qname(t.name);t.prefix=e,t.local=n;let r=t.uri=this.resolve(e)??``;e!==``&&(e===`xmlns`&&this.fail(`tags may not have "xmlns" as prefix.`),r===``&&(this.fail(`unbound namespace prefix: ${JSON.stringify(e)}.`),t.uri=e))}if(e.length===0)return;let{attributes:n}=t,r=new Set;for(let t of e){let{name:e,prefix:i,local:a}=t,o,s;i===``?(o=e===`xmlns`?h:``,s=e):(o=this.resolve(i),o===void 0&&(this.fail(`unbound namespace prefix: ${JSON.stringify(i)}.`),o=i),s=`{${o}}${a}`),r.has(s)&&this.fail(`duplicate attribute: ${s}.`),r.add(s),t.uri=o,n[e]=t}this.attribList=[]}processAttribsPlain(){let{attribList:e}=this,t=this.tag.attributes;for(let{name:n,value:r}of e)t[n]!==void 0&&this.fail(`duplicate attribute: ${n}.`),t[n]=r;this.attribList=[]}openTag(){var e;this.processAttribs();let{tags:t}=this,n=this.tag;n.isSelfClosing=!1,(e=this.openTagHandler)==null||e.call(this,n),t.push(n),this.state=C,this.name=``}openSelfClosingTag(){var e,t;this.processAttribs();let{tags:n}=this,r=this.tag;r.isSelfClosing=!0,(e=this.openTagHandler)==null||e.call(this,r),(t=this.closeTagHandler)==null||t.call(this,r),(this.tag=n[n.length-1]??null)===null&&(this.closedRoot=!0),this.state=C,this.name=``}closeTag(){let{tags:e,name:t}=this;if(this.state=C,this.name=``,t===``){this.fail(`weird empty close tag.`),this.text+=`</>`;return}let n=this.closeTagHandler,r=e.length;for(;r-->0;){let r=this.tag=e.pop();if(this.topNS=r.ns,n?.(r),r.name===t)break;this.fail(`unexpected close tag.`)}r===0?this.closedRoot=!0:r<0&&(this.fail(`unmatched closing tag: ${t}.`),this.text+=`</${t}>`)}parseEntity(e){if(e[0]!==`#`){let t=this.ENTITIES[e];return t===void 0?(this.fail(this.isName(e)?`undefined entity.`:`disallowed character in entity name.`),`&${e};`):t}let t=NaN;return e[1]===`x`&&/^#x[0-9a-f]+$/i.test(e)?t=parseInt(e.slice(2),16):/^#[0-9]+$/.test(e)&&(t=parseInt(e.slice(1),10)),this.isChar(t)?String.fromCodePoint(t):(this.fail(`malformed character entity.`),`&${e};`)}}}))(),lw=4194304,uw=new Set([`script`,`iframe`,`object`,`embed`,`audio`,`video`]),dw=new Set([`foreignobject`,`div`,`span`,`p`,`br`,`b`,`strong`,`i`,`em`,`small`,`sub`,`sup`,`code`,`ul`,`ol`,`li`,`a`]),fw=/^data:image\/(?:png|jpeg|gif|webp);base64,[a-z0-9+/=\s]+$/i,pw=/^data:(?:font\/(?:woff2?|opentype|truetype)|application\/(?:x-)?font-woff2?);base64,[a-z0-9+/=\s]+$/i,mw=class extends Error{constructor(e){super(e),this.name=`ClientSvgError`}};function hw(e){let t=e.trim();return t.startsWith(`#`)||fw.test(t)||pw.test(t)}function gw(e){if(/@import|expression\s*\(|javascript\s*:|data\s*:\s*text\/html|behavior\s*:|-moz-binding/i.test(e))return!0;let t=/url\s*\(\s*(['"]?)(.*?)\1\s*\)/gi;for(let n of e.matchAll(t))if(!hw(n[2]??``))return!0;return/url\s*\(/i.test(e.replace(t,``))}function _w(e){let t=e.trim();return t.startsWith(`#`)||fw.test(t)}function vw(e,t){let n=e.toLowerCase();return n.startsWith(`on`)?!1:n===`href`||n===`xlink:href`||n===`src`?_w(t):[`style`,`filter`,`fill`,`stroke`,`clip-path`,`mask`].includes(n)?!gw(t):n!==`xml:base`&&!/javascript\s*:/i.test(t)}function yw(e){return e.replaceAll(`&`,`&`).replaceAll(`<`,`<`).replaceAll(`>`,`>`)}function bw(e){return yw(e).replaceAll(`"`,`"`)}function xw(e){if(e.type===`text`)return yw(e.value);let t=[...e.attributes].map(([e,t])=>` ${e}="${bw(t)}"`).join(``);return`<${e.name}${t}>${e.children.map(xw).join(``)}</${e.name}>`}function Sw(e){return e.name.toLowerCase().split(`:`).at(-1)??e.name.toLowerCase()}function Cw(e){if(e===void 0||!/^-?\d+(?:\.\d+)?(?:px)?$/.test(e.trim()))return null;let t=Number.parseFloat(e);return Number.isFinite(t)&&t>0?t:null}function ww(e){let t=e.attributes.get(`viewBox`)?.trim().split(/[\s,]+/).map(Number);if(t?.length===4&&t.every(Number.isFinite)&&t[2]>0&&t[3]>0)return t;let n=Cw(e.attributes.get(`width`)),r=Cw(e.attributes.get(`height`));return n!==null&&r!==null?[0,0,n,r]:null}function Tw(e,t){let n=e.attributes.get(`style`);if(!n)return null;for(let e of n.split(`;`)){let n=e.indexOf(`:`);if(n>=0&&e.slice(0,n).trim().toLowerCase()===t)return e.slice(n+1).trim()}return null}function Ew(e){let t=(e.attributes.get(`fill`)??Tw(e,`fill`)??``).replaceAll(` `,``).toLowerCase();return t===`white`||t===`#fff`||t===`#ffffff`||t===`rgb(255,255,255)`}function Dw(e){if(e===void 0||!/^-?\d+(?:\.\d+)?$/.test(e.trim()))return null;let t=Number(e);return Number.isFinite(t)?t:null}function Ow(e,t){let n=e.attributes.get(`width`)?.trim(),r=e.attributes.get(`height`)?.trim();if(n===`100%`&&r===`100%`)return!0;let i=Dw(e.attributes.get(`x`)??`0`),a=Dw(e.attributes.get(`y`)??`0`),o=Dw(n),s=Dw(r);if([i,a,o,s].some(e=>e===null))return!1;let[c,l,u,d]=t,f=.01;return i<=c+f&&a<=l+f&&i+o>=c+u-f&&a+s>=l+d-f}function kw(e,t,n){let r=Sw(e),i=new Set((e.attributes.get(`class`)??``).toLowerCase().split(/\s+/));return r===`rect`&&i.has(`backdrop`)||r===`rect`&&t!==null&&Ew(e)&&Ow(e,t)?!0:n===`graphviz`&&r===`polygon`&&Ew(e)&&(e.attributes.get(`stroke`)??``).toLowerCase()===`none`}function Aw(e,t,n){let r=Sw(e)===`svg`?ww(e)??t:t;e.children=e.children.filter(e=>e.type===`text`||!kw(e,r,n)&&(Aw(e,r,n),!0))}function jw(e,t){let n=(e.attributes.get(`style`)??``).split(`;`).map(e=>e.trim()).filter(Boolean).filter(e=>!/^background(?:-color)?\s*:/i.test(e));n.push(`background-color:${t}`),e.attributes.set(`style`,`${n.join(`;`)};`)}function Mw(e,t=[],n=[]){return{type:`element`,name:e,attributes:new Map(t),children:n}}function Nw(e,t,n,r){let i=[],a=null;t.title&&i.push(Mw(`title`,[],[{type:`text`,value:t.title}])),t.description&&i.push(Mw(`desc`,[],[{type:`text`,value:t.description}]));let o=ww(e);if((n.padding||n.background||n.frame)&&o===null)throw new mw(`Renderer output has no usable SVG dimensions for presentation settings.`);if(o!==null){let[t,r,s,c]=o,l=n.padding,u=[t-l,r-l,s+l*2,c+l*2];e.attributes.set(`viewBox`,u.join(` `)),e.attributes.has(`width`)&&e.attributes.set(`width`,String(u[2])),e.attributes.has(`height`)&&e.attributes.set(`height`,String(u[3])),n.background&&i.push(Mw(`rect`,[[`x`,String(u[0])],[`y`,String(u[1])],[`width`,String(u[2])],[`height`,String(u[3])],[`fill`,n.background]])),n.frame&&(a=Mw(`rect`,[[`x`,String(u[0]+.5)],[`y`,String(u[1]+.5)],[`width`,String(Math.max(0,u[2]-1))],[`height`,String(Math.max(0,u[3]-1))],[`fill`,`none`],[`stroke`,`#000000`],[`stroke-width`,`1`],[`vector-effect`,`non-scaling-stroke`]]))}n.background&&(Aw(e,o,r),jw(e,n.background)),e.children.unshift(...i),a&&e.children.push(a)}function Pw(e,t,n,r){if(e.length>lw)throw new mw(`Rendered SVG is too large.`);let i=null,a=[],o=0,s=null,c=new cw.SaxesParser({xmlns:!0});c.on(`doctype`,e=>{e.includes(`[`)&&(s=Error(`Internal DOCTYPE subsets are not allowed`))}),c.on(`opentag`,e=>{let t=e.local.toLowerCase(),n=t===`foreignobject`||a.some(e=>Sw(e)===`foreignobject`);if(o>0||uw.has(t)||n&&!dw.has(t)){o++;return}let r=Mw(e.name);for(let t of Object.values(e.attributes))vw(t.name,t.value)&&r.attributes.set(t.name,t.value);let c=a.at(-1);c?c.children.push(r):i===null?i=r:s=Error(`Multiple root elements`),a.push(r)});let l=e=>{if(o>0||e===``)return;let t=a.at(-1);if(t){if(Sw(t)===`style`&&gw(e))throw new mw(`Renderer output contains unsafe CSS.`);t.children.push({type:`text`,value:e})}else e.trim()!==``&&(s=Error(`Text outside root element`))};c.on(`text`,l),c.on(`cdata`,l),c.on(`closetag`,()=>{o>0?o--:a.pop()}),c.on(`error`,e=>{s=e});try{c.write(e).close()}catch(e){if(e instanceof mw)throw e;s=e}if(s!==null||i===null||Sw(i)!==`svg`)throw new mw(`Renderer returned invalid SVG.`);return Nw(i,t,n,r),xw(i)}function Fw(e,t,n){return Math.min(Math.max(e,t),n)}var Iw=class{constructor({stage:e,image:t,status:n,minimap:r,minimapImage:i,minimapViewport:a}){this.stage=e,this.image=t,this.status=n,this.minimap=r,this.minimapImage=i,this.minimapViewport=a,this.scale=1,this.x=0,this.y=0,this.objectUrl=null,this.abortController=null,this.requestNumber=0,this.pendingRender=null,this.renderLoop=null,this.latestRenderKey=null,this.latestSvgBlob=null,this.imageFallbackUrl=null,this.activeImageUrl=null,this.drag=null,this.image.addEventListener(`load`,()=>{this.image.src===this.activeImageUrl&&(this.imageFallbackUrl=null,this.setStatus(`Rendered`,`ready`),this.fit())}),this.image.addEventListener(`error`,()=>this.retryBlockedImage()),this.stage.addEventListener(`pointerdown`,e=>this.startPan(e)),this.stage.addEventListener(`pointermove`,e=>this.pan(e)),this.stage.addEventListener(`pointerup`,e=>this.endPan(e)),this.stage.addEventListener(`pointercancel`,e=>this.endPan(e)),this.stage.addEventListener(`wheel`,e=>this.wheelZoom(e),{passive:!1}),this.minimap.addEventListener(`pointerdown`,e=>this.moveFromMinimap(e)),new ResizeObserver(()=>this.updateTransform()).observe(this.stage)}render({type:e,source:t,options:n={},meta:r={},presentation:i={}}){if(!t.trim()){this.requestNumber++,this.pendingRender=null,this.abortController?.abort(),this.setStatus(`Write something to render.`,`idle`);return}let a=JSON.stringify({type:e,source:t,options:n,meta:r,presentation:i});return this.latestRenderKey===a&&this.latestSvgBlob?Promise.resolve():(this.pendingRender={type:e,source:t,options:n,meta:r,presentation:i,renderKey:a,requestNumber:++this.requestNumber},this.abortController?.abort(),this.renderLoop||=this.drainRenderQueue(),this.renderLoop)}async drainRenderQueue(){try{for(;this.pendingRender;){let e=this.pendingRender;this.pendingRender=null,await this.performRender(e)}}finally{this.renderLoop=null,this.pendingRender&&(this.renderLoop=this.drainRenderQueue())}}async performRender({type:e,source:t,options:n,meta:r,presentation:i,renderKey:a,requestNumber:o}){let s=new AbortController;this.abortController=s,this.setStatus(`Rendering…`,`loading`),this.stage.style.setProperty(`--render-background`,`var(--preview-bg)`);try{let c=iw(e),l;if(c)try{let a=await c.render({type:e,source:t,options:n},s.signal);l=Pw(a.body,r,i,e),this.status.dataset.cache=`browser`,this.status.dataset.renderer=a.runtime}catch(a){if(a.name===`AbortError`)throw a;l=await this.renderThroughGateway({type:e,source:t,options:n,meta:r,presentation:i},s.signal)}else l=await this.renderThroughGateway({type:e,source:t,options:n,meta:r,presentation:i},s.signal);if(o!==this.requestNumber)return;let{blob:u,background:d}=this.normalizedSvgBlob(l);this.latestRenderKey=a,this.latestSvgBlob=u,this.imageFallbackUrl=`data:image/svg+xml;charset=utf-8,${encodeURIComponent(await u.text())}`,this.stage.style.setProperty(`--render-background`,d);let f=URL.createObjectURL(u),p=this.objectUrl;this.objectUrl=f,this.activeImageUrl=f,this.image.src=f,this.minimapImage.src=f,this.image.hidden=!1,this.setStatus(`Loading image…`,`loading`),p&&URL.revokeObjectURL(p)}catch(e){if(e.name===`AbortError`)return;this.setStatus(e.message||`Could not render this diagram.`,`error`)}finally{this.abortController===s&&(this.abortController=null)}}async renderThroughGateway({type:e,source:t,options:n,meta:r,presentation:i},a){let o=await fetch(`/render/v1/svg`,{method:`POST`,headers:{Accept:`image/svg+xml`,"Content-Type":`application/json`},body:JSON.stringify({engine:e,source:t,format:`svg`,options:n,metadata:r,presentation:i}),signal:a});if(!o.ok)throw Error(await this.errorMessage(o));return this.status.dataset.cache=o.headers.get(`X-Diagram-Cache`)?.toLowerCase()??`miss`,this.status.dataset.renderer=o.headers.get(`X-Diagram-Renderer`)?.toLowerCase()??`gateway`,o.text()}retryBlockedImage(){if(this.image.src===this.activeImageUrl){if(this.imageFallbackUrl&&this.activeImageUrl.startsWith(`blob:`)){let e=this.imageFallbackUrl;this.imageFallbackUrl=null,this.objectUrl&&URL.revokeObjectURL(this.objectUrl),this.objectUrl=null,this.activeImageUrl=e,this.image.src=e,this.minimapImage.src=e;return}this.setStatus(`The rendered image was blocked or invalid.`,`error`)}}svgBlobFor(e){let{type:t,source:n,options:r={},meta:i={},presentation:a={}}=e,o=JSON.stringify({type:t,source:n,options:r,meta:i,presentation:a});return this.latestRenderKey===o?this.latestSvgBlob:null}async errorMessage(e){let t=await e.text();if(e.headers.get(`Content-Type`)?.includes(`application/json`))try{let e=JSON.parse(t);if(typeof e?.error?.message==`string`)return e.error.message}catch{}return new DOMParser().parseFromString(t,`text/html`).body.textContent.trim().replace(/\s+/g,` `)||`Render failed with HTTP ${e.status}.`}normalizedSvgBlob(e){let t=new DOMParser().parseFromString(e,`image/svg+xml`).documentElement,n=t.getAttribute(`viewBox`)?.trim().split(/[\s,]+/).map(Number);t.nodeName===`svg`&&n?.length===4&&n.every(Number.isFinite)&&(t.hasAttribute(`width`)||t.setAttribute(`width`,String(n[2])),t.hasAttribute(`height`)||t.setAttribute(`height`,String(n[3])),e=new XMLSerializer().serializeToString(t));let r=t.style.backgroundColor||t.style.background,i=r&&r!==`transparent`?r:`#ffffff`;return{blob:new Blob([e],{type:`image/svg+xml`}),background:i}}setStatus(e,t){this.status.textContent=e,this.status.dataset.state=t}zoom(e){if(this.image.hidden)return;let t=this.stage.getBoundingClientRect();this.zoomAt(e,t.width/2,t.height/2)}zoomAt(e,t,n){let r=Fw(this.scale*e,.1,8),i=(t-this.x)/this.scale,a=(n-this.y)/this.scale;this.x=t-i*r,this.y=n-a*r,this.scale=r,this.updateTransform()}wheelZoom(e){if(this.image.hidden||e.target.closest(`.preview-toolbar, .minimap`))return;e.preventDefault();let t=this.stage.getBoundingClientRect(),n=e.deltaY*(e.deltaMode===WheelEvent.DOM_DELTA_LINE?16:e.deltaMode===WheelEvent.DOM_DELTA_PAGE?t.height:1);this.zoomAt(Math.exp(-Fw(n,-240,240)*.002),e.clientX-t.left,e.clientY-t.top)}oneToOne(){if(this.image.hidden)return;let e=this.stage.getBoundingClientRect();this.scale=1,this.x=(e.width-this.image.naturalWidth)/2,this.y=(e.height-this.image.naturalHeight)/2,this.updateTransform()}fit(){if(!this.image.naturalWidth||!this.image.naturalHeight)return;let e=this.stage.getBoundingClientRect(),t=Math.min(64,e.width*.12);this.scale=Fw(Math.min((e.width-t*2)/this.image.naturalWidth,(e.height-t*2)/this.image.naturalHeight),.1,2),this.x=(e.width-this.image.naturalWidth*this.scale)/2,this.y=(e.height-this.image.naturalHeight*this.scale)/2,this.updateTransform()}updateTransform(){this.image.style.transform=`translate(${this.x}px, ${this.y}px) scale(${this.scale})`,this.updateMinimap()}startPan(e){this.image.hidden||e.button!==0||e.target.closest(`.preview-toolbar, .minimap`)||(this.drag={pointerId:e.pointerId,x:e.clientX,y:e.clientY,originX:this.x,originY:this.y},this.stage.setPointerCapture(e.pointerId),this.stage.dataset.dragging=`true`)}pan(e){!this.drag||e.pointerId!==this.drag.pointerId||(this.x=this.drag.originX+e.clientX-this.drag.x,this.y=this.drag.originY+e.clientY-this.drag.y,this.updateTransform())}endPan(e){!this.drag||e.pointerId!==this.drag.pointerId||(this.drag=null,delete this.stage.dataset.dragging)}moveFromMinimap(e){if(!this.image.naturalWidth||!this.image.naturalHeight)return;let t=this.minimap.getBoundingClientRect(),n=Math.min(t.width/this.image.naturalWidth,t.height/this.image.naturalHeight),r=(t.width-this.image.naturalWidth*n)/2,i=(t.height-this.image.naturalHeight*n)/2,a=(e.clientX-t.left-r)/n,o=(e.clientY-t.top-i)/n,s=this.stage.getBoundingClientRect();this.x=s.width/2-a*this.scale,this.y=s.height/2-o*this.scale,this.updateTransform()}updateMinimap(){if(!this.image.naturalWidth||!this.image.naturalHeight)return;let e=this.stage.getBoundingClientRect(),t=this.image.naturalWidth*this.scale,n=this.image.naturalHeight*this.scale,r=this.x>=0&&this.y>=0&&this.x+t<=e.width&&this.y+n<=e.height;if(this.minimap.hidden=r,r)return;let i=this.minimap.getBoundingClientRect(),a=Math.min(i.width/this.image.naturalWidth,i.height/this.image.naturalHeight),o=(i.width-this.image.naturalWidth*a)/2,s=(i.height-this.image.naturalHeight*a)/2,c=Fw(-this.x/this.scale,0,this.image.naturalWidth),l=Fw(-this.y/this.scale,0,this.image.naturalHeight),u=Fw((e.width-this.x)/this.scale,0,this.image.naturalWidth),d=Fw((e.height-this.y)/this.scale,0,this.image.naturalHeight);this.minimapViewport.style.left=`${o+c*a}px`,this.minimapViewport.style.top=`${s+l*a}px`,this.minimapViewport.style.width=`${Math.max(4,(u-c)*a)}px`,this.minimapViewport.style.height=`${Math.max(4,(d-l)*a)}px`}},Lw=`diagram.zip:draft:local:v2`,Rw=`diagram.zip:draft:alias:v1:`,zw=`diagram.zip:write:v1:`,Bw=new ke,Vw=new DC,Hw,Uw=!1,Ww,Gw=!1,Kw=``,Q={aliasId:null,contentId:null,renderId:null,revision:null,mode:`open`,savedMode:null,writeCapability:null,savedState:null,savedSnapshot:null,bundleKey:null,keyEnvelope:null,encryptedContent:null,encryptedMetadata:null,keyEnvelopeDirty:!1,dirty:!0},qw=new Map;document.querySelector(`#app`).innerHTML=`1645+`,e.NAME_START_CHAR=`:A-Z_a-zÀ-ÖØ-öø-˿Ͱ-ͽͿ-⁰-Ⰰ-、-豈-﷏ﷰ-�𐀀-`,e.NAME_CHAR=`-`+e.NAME_START_CHAR+`.0-9·̀-ͯ‿-⁀`,e.CHAR_RE=RegExp(`^[`+e.CHAR+`]$`,`u`),e.S_RE=RegExp(`^[`+e.S+`]+$`,`u`),e.NAME_START_CHAR_RE=RegExp(`^[`+e.NAME_START_CHAR+`]$`,`u`),e.NAME_CHAR_RE=RegExp(`^[`+e.NAME_CHAR+`]$`,`u`),e.NAME_RE=RegExp(`^[`+e.NAME_START_CHAR+`][`+e.NAME_CHAR+`]*$`,`u`),e.NMTOKEN_RE=RegExp(`^[`+e.NAME_CHAR+`]+$`,`u`);var t=9,n=10,r=13,i=32;e.S_LIST=[i,n,r,t];function a(e){return e>=i&&e<=55295||e===n||e===r||e===t||e>=57344&&e<=65533||e>=65536&&e<=1114111}e.isChar=a;function o(e){return e===i||e===n||e===r||e===t}e.isS=o;function s(e){return e>=65&&e<=90||e>=97&&e<=122||e===58||e===95||e===8204||e===8205||e>=192&&e<=214||e>=216&&e<=246||e>=248&&e<=767||e>=880&&e<=893||e>=895&&e<=8191||e>=8304&&e<=8591||e>=11264&&e<=12271||e>=12289&&e<=55295||e>=63744&&e<=64975||e>=65008&&e<=65533||e>=65536&&e<=983039}e.isNameStartChar=s;function c(e){return s(e)||e>=48&&e<=57||e===45||e===46||e===183||e>=768&&e<=879||e>=8255&&e<=8256}e.isNameChar=c})),aw=e((e=>{Object.defineProperty(e,"__esModule",{value:!0}),e.CHAR=`--�𐀀-`,e.RESTRICTED_CHAR=`-\b\v\f---`,e.S=` \r1646+`,e.NAME_START_CHAR=`:A-Z_a-zÀ-ÖØ-öø-˿Ͱ-ͽͿ-⁰-Ⰰ-、-豈-﷏ﷰ-�𐀀-`,e.NAME_CHAR=`-`+e.NAME_START_CHAR+`.0-9·̀-ͯ‿-⁀`,e.CHAR_RE=RegExp(`^[`+e.CHAR+`]$`,`u`),e.RESTRICTED_CHAR_RE=RegExp(`^[`+e.RESTRICTED_CHAR+`]$`,`u`),e.S_RE=RegExp(`^[`+e.S+`]+$`,`u`),e.NAME_START_CHAR_RE=RegExp(`^[`+e.NAME_START_CHAR+`]$`,`u`),e.NAME_CHAR_RE=RegExp(`^[`+e.NAME_CHAR+`]$`,`u`),e.NAME_RE=RegExp(`^[`+e.NAME_START_CHAR+`][`+e.NAME_CHAR+`]*$`,`u`),e.NMTOKEN_RE=RegExp(`^[`+e.NAME_CHAR+`]+$`,`u`);var t=9,n=10,r=13,i=32;e.S_LIST=[i,n,r,t];function a(e){return e>=1&&e<=55295||e>=57344&&e<=65533||e>=65536&&e<=1114111}e.isChar=a;function o(e){return e>=1&&e<=8||e===11||e===12||e>=14&&e<=31||e>=127&&e<=132||e>=134&&e<=159}e.isRestrictedChar=o;function s(e){return e===9||e===10||e===13||e>31&&e<127||e===133||e>159&&e<=55295||e>=57344&&e<=65533||e>=65536&&e<=1114111}e.isCharAndNotRestricted=s;function c(e){return e===i||e===n||e===r||e===t}e.isS=c;function l(e){return e>=65&&e<=90||e>=97&&e<=122||e===58||e===95||e===8204||e===8205||e>=192&&e<=214||e>=216&&e<=246||e>=248&&e<=767||e>=880&&e<=893||e>=895&&e<=8191||e>=8304&&e<=8591||e>=11264&&e<=12271||e>=12289&&e<=55295||e>=63744&&e<=64975||e>=65008&&e<=65533||e>=65536&&e<=983039}e.isNameStartChar=l;function u(e){return l(e)||e>=48&&e<=57||e===45||e===46||e===183||e>=768&&e<=879||e>=8255&&e<=8256}e.isNameChar=u})),ow=e((e=>{Object.defineProperty(e,"__esModule",{value:!0}),e.NC_NAME_START_CHAR=`A-Z_a-zÀ-ÖØ-öø-˿Ͱ-ͽͿ--⁰-Ⰰ-、-豈-﷏ﷰ-�𐀀-`,e.NC_NAME_CHAR=`-`+e.NC_NAME_START_CHAR+`.0-9·̀-ͯ‿-⁀`,e.NC_NAME_START_CHAR_RE=RegExp(`^[`+e.NC_NAME_START_CHAR+`]$`,`u`),e.NC_NAME_CHAR_RE=RegExp(`^[`+e.NC_NAME_CHAR+`]$`,`u`),e.NC_NAME_RE=RegExp(`^[`+e.NC_NAME_START_CHAR+`][`+e.NC_NAME_CHAR+`]*$`,`u`);function t(e){return e>=65&&e<=90||e===95||e>=97&&e<=122||e>=192&&e<=214||e>=216&&e<=246||e>=248&&e<=767||e>=880&&e<=893||e>=895&&e<=8191||e>=8204&&e<=8205||e>=8304&&e<=8591||e>=11264&&e<=12271||e>=12289&&e<=55295||e>=63744&&e<=64975||e>=65008&&e<=65533||e>=65536&&e<=983039}e.isNCNameStartChar=t;function n(e){return t(e)||e===45||e===46||e>=48&&e<=57||e===183||e>=768&&e<=879||e>=8255&&e<=8256}e.isNCNameChar=n})),sw=e((e=>{Object.defineProperty(e,"__esModule",{value:!0}),e.SaxesParser=e.EVENTS=void 0;var t=iw(),n=aw(),r=ow(),i=t.isS,a=t.isChar,o=t.isNameStartChar,s=t.isNameChar,c=t.S_LIST,l=t.NAME_RE,u=n.isChar,d=r.isNCNameStartChar,f=r.isNCNameChar,p=r.NC_NAME_RE,m=`http://www.w3.org/XML/1998/namespace`,h=`http://www.w3.org/2000/xmlns/`,g={__proto__:null,xml:m,xmlns:h},_={__proto__:null,amp:`&`,gt:`>`,lt:`<`,quot:`"`,apos:`'`},v=-1,y=-2,ee=0,te=1,ne=2,re=3,b=4,ie=5,ae=6,x=7,oe=8,S=9,se=10,ce=11,le=12,C=13,w=14,ue=15,de=16,fe=17,pe=18,me=19,he=20,T=21,ge=22,_e=23,E=24,ve=25,ye=26,be=27,xe=28,Se=29,Ce=30,we=31,Te=32,Ee=33,De=34,Oe=35,ke=36,Ae=37,je=38,Me=39,Ne=40,Pe=41,Fe=42,Ie=43,Le=44,Re=9,ze=10,Be=13,Ve=32,He=33,Ue=34,We=38,D=39,O=45,Ge=47,Ke=59,qe=60,Je=61,k=62,A=63,Ye=91,Xe=93,j=133,Ze=8232,Qe=e=>e===Ue||e===D,$e=[Ue,D],et=[...$e,Ye,k],M=[...$e,qe,Xe],tt=[Je,A,...c],nt=[...c,k,We,qe];function rt(e,t,n){switch(t){case`xml`:n!==m&&e.fail(`xml prefix must be bound to ${m}.`);break;case`xmlns`:n!==h&&e.fail(`xmlns prefix must be bound to ${h}.`)}switch(n){case h:e.fail(t===``?`the default namespace may not be set to ${n}.`:`may not assign a prefix (even "xmlns") to the URI \1647+${h}.`);break;case m:switch(t){case`xml`:break;case``:e.fail(`the default namespace may not be set to ${n}.`);break;default:e.fail(`may not assign the xml namespace to another prefix.`)}}}function it(e,t){for(let n of Object.keys(t))rt(e,n,t[n])}var at=e=>p.test(e),ot=e=>l.test(e),N=0,st=1,ct=2;e.EVENTS=[`xmldecl`,`text`,`processinginstruction`,`doctype`,`comment`,`opentagstart`,`attribute`,`opentag`,`closetag`,`cdata`,`error`,`end`,`ready`];var lt={xmldecl:`xmldeclHandler`,text:`textHandler`,processinginstruction:`piHandler`,doctype:`doctypeHandler`,comment:`commentHandler`,opentagstart:`openTagStartHandler`,attribute:`attributeHandler`,opentag:`openTagHandler`,closetag:`closeTagHandler`,cdata:`cdataHandler`,error:`errorHandler`,end:`endHandler`,ready:`readyHandler`};e.SaxesParser=class{constructor(e){this.opt=e??{},this.fragmentOpt=!!this.opt.fragment;let t=this.xmlnsOpt=!!this.opt.xmlns;if(this.trackPosition=this.opt.position!==!1,this.fileName=this.opt.fileName,t){this.nameStartCheck=d,this.nameCheck=f,this.isName=at,this.processAttribs=this.processAttribsNS,this.pushAttrib=this.pushAttribNS,this.ns=Object.assign({__proto__:null},g);let e=this.opt.additionalNamespaces;e!=null&&(it(this,e),Object.assign(this.ns,e))}else this.nameStartCheck=o,this.nameCheck=s,this.isName=ot,this.processAttribs=this.processAttribsPlain,this.pushAttrib=this.pushAttribPlain;this.stateTable=[this.sBegin,this.sBeginWhitespace,this.sDoctype,this.sDoctypeQuote,this.sDTD,this.sDTDQuoted,this.sDTDOpenWaka,this.sDTDOpenWakaBang,this.sDTDComment,this.sDTDCommentEnding,this.sDTDCommentEnded,this.sDTDPI,this.sDTDPIEnding,this.sText,this.sEntity,this.sOpenWaka,this.sOpenWakaBang,this.sComment,this.sCommentEnding,this.sCommentEnded,this.sCData,this.sCDataEnding,this.sCDataEnding2,this.sPIFirstChar,this.sPIRest,this.sPIBody,this.sPIEnding,this.sXMLDeclNameStart,this.sXMLDeclName,this.sXMLDeclEq,this.sXMLDeclValueStart,this.sXMLDeclValue,this.sXMLDeclSeparator,this.sXMLDeclEnding,this.sOpenTag,this.sOpenTagSlash,this.sAttrib,this.sAttribName,this.sAttribNameSawWhite,this.sAttribValue,this.sAttribValueQuoted,this.sAttribValueClosed,this.sAttribValueUnquoted,this.sCloseTag,this.sCloseTagSawWhite],this._init()}get closed(){return this._closed}_init(){var e;this.openWakaBang=``,this.text=``,this.name=``,this.piTarget=``,this.entity=``,this.q=null,this.tags=[],this.tag=null,this.topNS=null,this.chunk=``,this.chunkPosition=0,this.i=0,this.prevI=0,this.carriedFromPrevious=void 0,this.forbiddenState=N,this.attribList=[];let{fragmentOpt:t}=this;this.state=t?C:ee,this.reportedTextBeforeRoot=this.reportedTextAfterRoot=this.closedRoot=this.sawRoot=t,this.xmlDeclPossible=!t,this.xmlDeclExpects=[`version`],this.entityReturnState=void 0;let{defaultXMLVersion:n}=this.opt;if(n===void 0){if(this.opt.forceXMLVersion===!0)throw Error(`forceXMLVersion set but defaultXMLVersion is not set`);n=`1.0`}this.setXMLVersion(n),this.positionAtNewLine=0,this.doctype=!1,this._closed=!1,this.xmlDecl={version:void 0,encoding:void 0,standalone:void 0},this.line=1,this.column=0,this.ENTITIES=Object.create(_),(e=this.readyHandler)==null||e.call(this)}get position(){return this.chunkPosition+this.i}get columnIndex(){return this.position-this.positionAtNewLine}on(e,t){this[lt[e]]=t}off(e){this[lt[e]]=void 0}makeError(e){let t=this.fileName??``;return this.trackPosition&&(t.length>0&&(t+=`:`),t+=`${this.line}:${this.column}`),t.length>0&&(t+=`: `),Error(t+e)}fail(e){let t=this.makeError(e),n=this.errorHandler;if(n===void 0)throw t;return n(t),this}write(e){if(this.closed)return this.fail(`cannot write after close; assign an onready handler.`);let t=!1;e===null?(t=!0,e=``):typeof e==`object`&&(e=e.toString()),this.carriedFromPrevious!==void 0&&(e=`${this.carriedFromPrevious}${e}`,this.carriedFromPrevious=void 0);let n=e.length,r=e.charCodeAt(n-1);!t&&(r===Be||r>=55296&&r<=56319)&&(this.carriedFromPrevious=e[n-1],n--,e=e.slice(0,n));let{stateTable:i}=this;for(this.chunk=e,this.i=0;this.i<n;)i[this.state].call(this);return this.chunkPosition+=n,t?this.end():this}close(){return this.write(null)}getCode10(){let{chunk:e,i:t}=this;if(this.prevI=t,this.i=t+1,t>=e.length)return v;let n=e.charCodeAt(t);if(this.column++,n<55296){if(n>=Ve||n===Re)return n;switch(n){case ze:return this.line++,this.column=0,this.positionAtNewLine=this.position,ze;case Be:return e.charCodeAt(t+1)===ze&&(this.i=t+2),this.line++,this.column=0,this.positionAtNewLine=this.position,y;default:return this.fail(`disallowed character.`),n}}if(n>56319)return n>=57344&&n<=65533||this.fail(`disallowed character.`),n;let r=65536+(n-55296)*1024+(e.charCodeAt(t+1)-56320);return this.i=t+2,r>1114111&&this.fail(`disallowed character.`),r}getCode11(){let{chunk:e,i:t}=this;if(this.prevI=t,this.i=t+1,t>=e.length)return v;let n=e.charCodeAt(t);if(this.column++,n<55296){if(n>31&&n<127||n>159&&n!==Ze||n===Re)return n;switch(n){case ze:return this.line++,this.column=0,this.positionAtNewLine=this.position,ze;case Be:{let n=e.charCodeAt(t+1);(n===ze||n===j)&&(this.i=t+2)}case j:case Ze:return this.line++,this.column=0,this.positionAtNewLine=this.position,y;default:return this.fail(`disallowed character.`),n}}if(n>56319)return n>=57344&&n<=65533||this.fail(`disallowed character.`),n;let r=65536+(n-55296)*1024+(e.charCodeAt(t+1)-56320);return this.i=t+2,r>1114111&&this.fail(`disallowed character.`),r}getCodeNorm(){let e=this.getCode();return e===y?ze:e}unget(){this.i=this.prevI,this.column--}captureTo(e){let{i:t}=this,{chunk:n}=this;for(;;){let r=this.getCode(),i=r===y,a=i?ze:r;if(a===v||e.includes(a))return this.text+=n.slice(t,this.prevI),a;i&&(this.text+=`${n.slice(t,this.prevI)}\n`,t=this.i)}}captureToChar(e){let{i:t}=this,{chunk:n}=this;for(;;){let r=this.getCode();switch(r){case y:this.text+=`${n.slice(t,this.prevI)}\n`,t=this.i,r=ze;break;case v:return this.text+=n.slice(t),!1}if(r===e)return this.text+=n.slice(t,this.prevI),!0}}captureNameChars(){let{chunk:e,i:t}=this;for(;;){let n=this.getCode();if(n===v)return this.name+=e.slice(t),v;if(!s(n))return this.name+=e.slice(t,this.prevI),n===y?ze:n}}skipSpaces(){for(;;){let e=this.getCodeNorm();if(e===v||!i(e))return e}}setXMLVersion(e){this.currentXMLVersion=e,e===`1.0`?(this.isChar=a,this.getCode=this.getCode10):(this.isChar=u,this.getCode=this.getCode11)}sBegin(){this.chunk.charCodeAt(0)===65279&&(this.i++,this.column++),this.state=te}sBeginWhitespace(){let e=this.i,t=this.skipSpaces();switch(this.prevI!==e&&(this.xmlDeclPossible=!1),t){case qe:if(this.state=ue,this.text.length!==0)throw Error(`no-empty text at start`);break;case v:break;default:this.unget(),this.state=C,this.xmlDeclPossible=!1}}sDoctype(){var e;let t=this.captureTo(et);switch(t){case k:(e=this.doctypeHandler)==null||e.call(this,this.text),this.text=``,this.state=C,this.doctype=!0;break;case v:break;default:this.text+=String.fromCodePoint(t),t===Ye?this.state=b:Qe(t)&&(this.state=re,this.q=t)}}sDoctypeQuote(){let e=this.q;this.captureToChar(e)&&(this.text+=String.fromCodePoint(e),this.q=null,this.state=ne)}sDTD(){let e=this.captureTo(M);e!==v&&(this.text+=String.fromCodePoint(e),e===Xe?this.state=ne:e===qe?this.state=ae:Qe(e)&&(this.state=ie,this.q=e))}sDTDQuoted(){let e=this.q;this.captureToChar(e)&&(this.text+=String.fromCodePoint(e),this.state=b,this.q=null)}sDTDOpenWaka(){let e=this.getCodeNorm();switch(this.text+=String.fromCodePoint(e),e){case He:this.state=x,this.openWakaBang=``;break;case A:this.state=ce;break;default:this.state=b}}sDTDOpenWakaBang(){let e=String.fromCodePoint(this.getCodeNorm()),t=this.openWakaBang+=e;this.text+=e,t!==`-`&&(this.state=t===`--`?oe:b,this.openWakaBang=``)}sDTDComment(){this.captureToChar(O)&&(this.text+=`-`,this.state=S)}sDTDCommentEnding(){let e=this.getCodeNorm();this.text+=String.fromCodePoint(e),this.state=e===O?se:oe}sDTDCommentEnded(){let e=this.getCodeNorm();this.text+=String.fromCodePoint(e),e===k?this.state=b:(this.fail(`malformed comment.`),this.state=oe)}sDTDPI(){this.captureToChar(A)&&(this.text+=`?`,this.state=le)}sDTDPIEnding(){let e=this.getCodeNorm();this.text+=String.fromCodePoint(e),e===k&&(this.state=b)}sText(){this.tags.length===0?this.handleTextOutsideRoot():this.handleTextInRoot()}sEntity(){let{i:e}=this,{chunk:t}=this;loop:for(;;)switch(this.getCode()){case y:this.entity+=`${t.slice(e,this.prevI)}\n`,e=this.i;break;case Ke:{let{entityReturnState:n}=this,r=this.entity+t.slice(e,this.prevI);this.state=n;let i;r===``?(this.fail(`empty entity name.`),i=`&;`):(i=this.parseEntity(r),this.entity=``),(n!==C||this.textHandler!==void 0)&&(this.text+=i);break loop}case v:this.entity+=t.slice(e);break loop}}sOpenWaka(){let e=this.getCode();if(o(e))this.state=De,this.unget(),this.xmlDeclPossible=!1;else switch(e){case Ge:this.state=Ie,this.xmlDeclPossible=!1;break;case He:this.state=de,this.openWakaBang=``,this.xmlDeclPossible=!1;break;case A:this.state=_e;break;default:this.fail(`disallowed character in tag name`),this.state=C,this.xmlDeclPossible=!1}}sOpenWakaBang(){switch(this.openWakaBang+=String.fromCodePoint(this.getCodeNorm()),this.openWakaBang){case`[CDATA[`:!this.sawRoot&&!this.reportedTextBeforeRoot&&(this.fail(`text data outside of root node.`),this.reportedTextBeforeRoot=!0),this.closedRoot&&!this.reportedTextAfterRoot&&(this.fail(`text data outside of root node.`),this.reportedTextAfterRoot=!0),this.state=he,this.openWakaBang=``;break;case`--`:this.state=fe,this.openWakaBang=``;break;case`DOCTYPE`:this.state=ne,(this.doctype||this.sawRoot)&&this.fail(`inappropriately located doctype declaration.`),this.openWakaBang=``;break;default:this.openWakaBang.length>=7&&this.fail(`incorrect syntax.`)}}sComment(){this.captureToChar(O)&&(this.state=pe)}sCommentEnding(){var e;let t=this.getCodeNorm();t===O?(this.state=me,(e=this.commentHandler)==null||e.call(this,this.text),this.text=``):(this.text+=`-${String.fromCodePoint(t)}`,this.state=fe)}sCommentEnded(){let e=this.getCodeNorm();e===k?this.state=C:(this.fail(`malformed comment.`),this.text+=`--${String.fromCodePoint(e)}`,this.state=fe)}sCData(){this.captureToChar(Xe)&&(this.state=T)}sCDataEnding(){let e=this.getCodeNorm();e===Xe?this.state=ge:(this.text+=`]${String.fromCodePoint(e)}`,this.state=he)}sCDataEnding2(){var e;let t=this.getCodeNorm();switch(t){case k:(e=this.cdataHandler)==null||e.call(this,this.text),this.text=``,this.state=C;break;case Xe:this.text+=`]`;break;default:this.text+=`]]${String.fromCodePoint(t)}`,this.state=he}}sPIFirstChar(){let e=this.getCodeNorm();this.nameStartCheck(e)?(this.piTarget+=String.fromCodePoint(e),this.state=E):e===A||i(e)?(this.fail(`processing instruction without a target.`),this.state=e===A?ye:ve):(this.fail(`disallowed character in processing instruction name.`),this.piTarget+=String.fromCodePoint(e),this.state=E)}sPIRest(){let{chunk:e,i:t}=this;for(;;){let n=this.getCodeNorm();if(n===v){this.piTarget+=e.slice(t);return}if(!this.nameCheck(n)){this.piTarget+=e.slice(t,this.prevI);let r=n===A;r||i(n)?this.piTarget===`xml`?(this.xmlDeclPossible||this.fail(`an XML declaration must be at the start of the document.`),this.state=r?Ee:be):this.state=r?ye:ve:(this.fail(`disallowed character in processing instruction name.`),this.piTarget+=String.fromCodePoint(n));break}}}sPIBody(){if(this.text.length===0){let e=this.getCodeNorm();e===A?this.state=ye:i(e)||(this.text=String.fromCodePoint(e))}else this.captureToChar(A)&&(this.state=ye)}sPIEnding(){var e;let t=this.getCodeNorm();if(t===k){let{piTarget:t}=this;t.toLowerCase()===`xml`&&this.fail(`the XML declaration must appear at the start of the document.`),(e=this.piHandler)==null||e.call(this,{target:t,body:this.text}),this.piTarget=this.text=``,this.state=C}else t===A?this.text+=`?`:(this.text+=`?${String.fromCodePoint(t)}`,this.state=ve);this.xmlDeclPossible=!1}sXMLDeclNameStart(){let e=this.skipSpaces();if(e===A){this.state=Ee;return}e!==v&&(this.state=xe,this.name=String.fromCodePoint(e))}sXMLDeclName(){let e=this.captureTo(tt);if(e===A){this.state=Ee,this.name+=this.text,this.text=``,this.fail(`XML declaration is incomplete.`);return}if(i(e)||e===Je){if(this.name+=this.text,this.text=``,!this.xmlDeclExpects.includes(this.name))switch(this.name.length){case 0:this.fail(`did not expect any more name/value pairs.`);break;case 1:this.fail(`expected the name ${this.xmlDeclExpects[0]}.`);break;default:this.fail(`expected one of ${this.xmlDeclExpects.join(`, `)}`)}this.state=e===Je?Ce:Se}}sXMLDeclEq(){let e=this.getCodeNorm();if(e===A){this.state=Ee,this.fail(`XML declaration is incomplete.`);return}i(e)||(e!==Je&&this.fail(`value required.`),this.state=Ce)}sXMLDeclValueStart(){let e=this.getCodeNorm();if(e===A){this.state=Ee,this.fail(`XML declaration is incomplete.`);return}i(e)||(Qe(e)?this.q=e:(this.fail(`value must be quoted.`),this.q=Ve),this.state=we)}sXMLDeclValue(){let e=this.captureTo([this.q,A]);if(e===A){this.state=Ee,this.text=``,this.fail(`XML declaration is incomplete.`);return}if(e===v)return;let t=this.text;switch(this.text=``,this.name){case`version`:{this.xmlDeclExpects=[`encoding`,`standalone`];let e=t;this.xmlDecl.version=e,/^1\.[0-9]+$/.test(e)?this.opt.forceXMLVersion||this.setXMLVersion(e):this.fail(`version number must match /^1\\.[0-9]+$/.`);break}case`encoding`:/^[A-Za-z][A-Za-z0-9._-]*$/.test(t)||this.fail(`encoding value must match /^[A-Za-z0-9][A-Za-z0-9._-]*$/.`),this.xmlDeclExpects=[`standalone`],this.xmlDecl.encoding=t;break;case`standalone`:t!==`yes`&&t!==`no`&&this.fail(`standalone value must match "yes" or "no".`),this.xmlDeclExpects=[],this.xmlDecl.standalone=t}this.name=``,this.state=Te}sXMLDeclSeparator(){let e=this.getCodeNorm();if(e===A){this.state=Ee;return}i(e)||(this.fail(`whitespace required.`),this.unget()),this.state=be}sXMLDeclEnding(){var e;this.getCodeNorm()===k?(this.piTarget===`xml`?this.name!==`version`&&this.xmlDeclExpects.includes(`version`)&&this.fail(`XML declaration must contain a version.`):this.fail(`processing instructions are not allowed before root.`),(e=this.xmldeclHandler)==null||e.call(this,this.xmlDecl),this.name=``,this.piTarget=this.text=``,this.state=C):this.fail(`The character ? is disallowed anywhere in XML declarations.`),this.xmlDeclPossible=!1}sOpenTag(){var e;let t=this.captureNameChars();if(t===v)return;let n=this.tag={name:this.name,attributes:Object.create(null)};switch(this.name=``,this.xmlnsOpt&&(this.topNS=n.ns=Object.create(null)),(e=this.openTagStartHandler)==null||e.call(this,n),this.sawRoot=!0,!this.fragmentOpt&&this.closedRoot&&this.fail(`documents may contain only one root.`),t){case k:this.openTag();break;case Ge:this.state=Oe;break;default:i(t)||this.fail(`disallowed character in tag name.`),this.state=ke}}sOpenTagSlash(){this.getCode()===k?this.openSelfClosingTag():(this.fail(`forward-slash in opening tag not followed by >.`),this.state=ke)}sAttrib(){let e=this.skipSpaces();e!==v&&(o(e)?(this.unget(),this.state=Ae):e===k?this.openTag():e===Ge?this.state=Oe:this.fail(`disallowed character in attribute name.`))}sAttribName(){let e=this.captureNameChars();e===Je?this.state=Me:i(e)?this.state=je:e===k?(this.fail(`attribute without value.`),this.pushAttrib(this.name,this.name),this.name=this.text=``,this.openTag()):e!==v&&this.fail(`disallowed character in attribute name.`)}sAttribNameSawWhite(){let e=this.skipSpaces();switch(e){case v:return;case Je:this.state=Me;break;default:this.fail(`attribute without value.`),this.text=``,this.name=``,e===k?this.openTag():o(e)?(this.unget(),this.state=Ae):(this.fail(`disallowed character in attribute name.`),this.state=ke)}}sAttribValue(){let e=this.getCodeNorm();Qe(e)?(this.q=e,this.state=Ne):i(e)||(this.fail(`unquoted attribute value.`),this.state=Fe,this.unget())}sAttribValueQuoted(){let{q:e,chunk:t}=this,{i:n}=this;for(;;)switch(this.getCode()){case e:this.pushAttrib(this.name,this.text+t.slice(n,this.prevI)),this.name=this.text=``,this.q=null,this.state=Pe;return;case We:this.text+=t.slice(n,this.prevI),this.state=w,this.entityReturnState=Ne;return;case ze:case y:case Re:this.text+=`${t.slice(n,this.prevI)} `,n=this.i;break;case qe:this.text+=t.slice(n,this.prevI),this.fail(`disallowed character.`);return;case v:this.text+=t.slice(n);return}}sAttribValueClosed(){let e=this.getCodeNorm();i(e)?this.state=ke:e===k?this.openTag():e===Ge?this.state=Oe:o(e)?(this.fail(`no whitespace between attributes.`),this.unget(),this.state=Ae):this.fail(`disallowed character in attribute name.`)}sAttribValueUnquoted(){let e=this.captureTo(nt);switch(e){case We:this.state=w,this.entityReturnState=Fe;break;case qe:this.fail(`disallowed character.`);break;case v:break;default:this.text.includes(`]]>`)&&this.fail(`the string "]]>" is disallowed in char data.`),this.pushAttrib(this.name,this.text),this.name=this.text=``,e===k?this.openTag():this.state=ke}}sCloseTag(){let e=this.captureNameChars();e===k?this.closeTag():i(e)?this.state=Le:e!==v&&this.fail(`disallowed character in closing tag.`)}sCloseTagSawWhite(){switch(this.skipSpaces()){case k:this.closeTag();break;case v:break;default:this.fail(`disallowed character in closing tag.`)}}handleTextInRoot(){let{i:e,forbiddenState:t}=this,{chunk:n,textHandler:r}=this;scanLoop:for(;;)switch(this.getCode()){case qe:if(this.state=ue,r!==void 0){let{text:t}=this,i=n.slice(e,this.prevI);t.length===0?i.length!==0&&r(i):(r(t+i),this.text=``)}t=N;break scanLoop;case We:this.state=w,this.entityReturnState=C,r!==void 0&&(this.text+=n.slice(e,this.prevI)),t=N;break scanLoop;case Xe:switch(t){case N:t=st;break;case st:t=ct;break;case ct:break;default:throw Error(`impossible state`)}break;case k:t===ct&&this.fail(`the string "]]>" is disallowed in char data.`),t=N;break;case y:r!==void 0&&(this.text+=`${n.slice(e,this.prevI)}\n`),e=this.i,t=N;break;case v:r!==void 0&&(this.text+=n.slice(e));break scanLoop;default:t=N}this.forbiddenState=t}handleTextOutsideRoot(){let{i:e}=this,{chunk:t,textHandler:n}=this,r=!1;outRootLoop:for(;;){let a=this.getCode();switch(a){case qe:if(this.state=ue,n!==void 0){let{text:r}=this,i=t.slice(e,this.prevI);r.length===0?i.length!==0&&n(i):(n(r+i),this.text=``)}break outRootLoop;case We:this.state=w,this.entityReturnState=C,n!==void 0&&(this.text+=t.slice(e,this.prevI)),r=!0;break outRootLoop;case y:n!==void 0&&(this.text+=`${t.slice(e,this.prevI)}\n`),e=this.i;break;case v:n!==void 0&&(this.text+=t.slice(e));break outRootLoop;default:i(a)||(r=!0)}}r&&(!this.sawRoot&&!this.reportedTextBeforeRoot&&(this.fail(`text data outside of root node.`),this.reportedTextBeforeRoot=!0),this.closedRoot&&!this.reportedTextAfterRoot&&(this.fail(`text data outside of root node.`),this.reportedTextAfterRoot=!0))}pushAttribNS(e,t){var n;let{prefix:r,local:i}=this.qname(e),a={name:e,prefix:r,local:i,value:t};if(this.attribList.push(a),(n=this.attributeHandler)==null||n.call(this,a),r===`xmlns`){let e=t.trim();this.currentXMLVersion===`1.0`&&e===``&&this.fail(`invalid attempt to undefine prefix in XML 1.0`),this.topNS[i]=e,rt(this,i,e)}else if(e===`xmlns`){let e=t.trim();this.topNS[``]=e,rt(this,``,e)}}pushAttribPlain(e,t){var n;let r={name:e,value:t};this.attribList.push(r),(n=this.attributeHandler)==null||n.call(this,r)}end(){var e,t;this.sawRoot||this.fail(`document must contain a root element.`);let{tags:n}=this;for(;n.length>0;){let e=n.pop();this.fail(`unclosed tag: ${e.name}`)}this.state!==ee&&this.state!==C&&this.fail(`unexpected end.`);let{text:r}=this;return r.length!==0&&((e=this.textHandler)==null||e.call(this,r),this.text=``),this._closed=!0,(t=this.endHandler)==null||t.call(this),this._init(),this}resolve(e){var t;let n=this.topNS[e];if(n!==void 0)return n;let{tags:r}=this;for(let t=r.length-1;t>=0;t--)if(n=r[t].ns[e],n!==void 0)return n;return n=this.ns[e],n===void 0?(t=this.opt).resolvePrefix?.call(t,e):n}qname(e){let t=e.indexOf(`:`);if(t===-1)return{prefix:``,local:e};let n=e.slice(t+1),r=e.slice(0,t);return(r===``||n===``||n.includes(`:`))&&this.fail(`malformed name: ${e}.`),{prefix:r,local:n}}processAttribsNS(){let{attribList:e}=this,t=this.tag;{let{prefix:e,local:n}=this.qname(t.name);t.prefix=e,t.local=n;let r=t.uri=this.resolve(e)??``;e!==``&&(e===`xmlns`&&this.fail(`tags may not have "xmlns" as prefix.`),r===``&&(this.fail(`unbound namespace prefix: ${JSON.stringify(e)}.`),t.uri=e))}if(e.length===0)return;let{attributes:n}=t,r=new Set;for(let t of e){let{name:e,prefix:i,local:a}=t,o,s;i===``?(o=e===`xmlns`?h:``,s=e):(o=this.resolve(i),o===void 0&&(this.fail(`unbound namespace prefix: ${JSON.stringify(i)}.`),o=i),s=`{${o}}${a}`),r.has(s)&&this.fail(`duplicate attribute: ${s}.`),r.add(s),t.uri=o,n[e]=t}this.attribList=[]}processAttribsPlain(){let{attribList:e}=this,t=this.tag.attributes;for(let{name:n,value:r}of e)t[n]!==void 0&&this.fail(`duplicate attribute: ${n}.`),t[n]=r;this.attribList=[]}openTag(){var e;this.processAttribs();let{tags:t}=this,n=this.tag;n.isSelfClosing=!1,(e=this.openTagHandler)==null||e.call(this,n),t.push(n),this.state=C,this.name=``}openSelfClosingTag(){var e,t;this.processAttribs();let{tags:n}=this,r=this.tag;r.isSelfClosing=!0,(e=this.openTagHandler)==null||e.call(this,r),(t=this.closeTagHandler)==null||t.call(this,r),(this.tag=n[n.length-1]??null)===null&&(this.closedRoot=!0),this.state=C,this.name=``}closeTag(){let{tags:e,name:t}=this;if(this.state=C,this.name=``,t===``){this.fail(`weird empty close tag.`),this.text+=`</>`;return}let n=this.closeTagHandler,r=e.length;for(;r-->0;){let r=this.tag=e.pop();if(this.topNS=r.ns,n?.(r),r.name===t)break;this.fail(`unexpected close tag.`)}r===0?this.closedRoot=!0:r<0&&(this.fail(`unmatched closing tag: ${t}.`),this.text+=`</${t}>`)}parseEntity(e){if(e[0]!==`#`){let t=this.ENTITIES[e];return t===void 0?(this.fail(this.isName(e)?`undefined entity.`:`disallowed character in entity name.`),`&${e};`):t}let t=NaN;return e[1]===`x`&&/^#x[0-9a-f]+$/i.test(e)?t=parseInt(e.slice(2),16):/^#[0-9]+$/.test(e)&&(t=parseInt(e.slice(1),10)),this.isChar(t)?String.fromCodePoint(t):(this.fail(`malformed character entity.`),`&${e};`)}}}))(),cw=4194304,lw=new Set([`script`,`iframe`,`object`,`embed`,`audio`,`video`]),uw=new Set([`foreignobject`,`div`,`span`,`p`,`br`,`b`,`strong`,`i`,`em`,`small`,`sub`,`sup`,`code`,`ul`,`ol`,`li`,`a`]),dw=/^data:image\/(?:png|jpeg|gif|webp);base64,[a-z0-9+/=\s]+$/i,fw=/^data:(?:font\/(?:woff2?|opentype|truetype)|application\/(?:x-)?font-woff2?);base64,[a-z0-9+/=\s]+$/i,pw=class extends Error{constructor(e){super(e),this.name=`ClientSvgError`}};function mw(e){let t=e.trim();return t.startsWith(`#`)||dw.test(t)||fw.test(t)}function hw(e){if(/@import|expression\s*\(|javascript\s*:|data\s*:\s*text\/html|behavior\s*:|-moz-binding/i.test(e))return!0;let t=/url\s*\(\s*(['"]?)(.*?)\1\s*\)/gi;for(let n of e.matchAll(t))if(!mw(n[2]??``))return!0;return/url\s*\(/i.test(e.replace(t,``))}function gw(e){let t=e.trim();return t.startsWith(`#`)||dw.test(t)}function _w(e,t){let n=e.toLowerCase();return n.startsWith(`on`)?!1:n===`href`||n===`xlink:href`||n===`src`?gw(t):[`style`,`filter`,`fill`,`stroke`,`clip-path`,`mask`].includes(n)?!hw(t):n!==`xml:base`&&!/javascript\s*:/i.test(t)}function vw(e){return e.replaceAll(`&`,`&`).replaceAll(`<`,`<`).replaceAll(`>`,`>`)}function yw(e){return vw(e).replaceAll(`"`,`"`)}function bw(e){if(e.type===`text`)return vw(e.value);let t=[...e.attributes].map(([e,t])=>` ${e}="${yw(t)}"`).join(``);return`<${e.name}${t}>${e.children.map(bw).join(``)}</${e.name}>`}function xw(e){return e.name.toLowerCase().split(`:`).at(-1)??e.name.toLowerCase()}function Sw(e){if(e===void 0||!/^-?\d+(?:\.\d+)?(?:px)?$/.test(e.trim()))return null;let t=Number.parseFloat(e);return Number.isFinite(t)&&t>0?t:null}function Cw(e){let t=e.attributes.get(`viewBox`)?.trim().split(/[\s,]+/).map(Number);if(t?.length===4&&t.every(Number.isFinite)&&t[2]>0&&t[3]>0)return t;let n=Sw(e.attributes.get(`width`)),r=Sw(e.attributes.get(`height`));return n!==null&&r!==null?[0,0,n,r]:null}function ww(e,t){let n=e.attributes.get(`style`);if(!n)return null;for(let e of n.split(`;`)){let n=e.indexOf(`:`);if(n>=0&&e.slice(0,n).trim().toLowerCase()===t)return e.slice(n+1).trim()}return null}function Tw(e){let t=(e.attributes.get(`fill`)??ww(e,`fill`)??``).replaceAll(` `,``).toLowerCase();return t===`white`||t===`#fff`||t===`#ffffff`||t===`rgb(255,255,255)`}function Ew(e){if(e===void 0||!/^-?\d+(?:\.\d+)?$/.test(e.trim()))return null;let t=Number(e);return Number.isFinite(t)?t:null}function Dw(e,t){let n=e.attributes.get(`width`)?.trim(),r=e.attributes.get(`height`)?.trim();if(n===`100%`&&r===`100%`)return!0;let i=Ew(e.attributes.get(`x`)??`0`),a=Ew(e.attributes.get(`y`)??`0`),o=Ew(n),s=Ew(r);if([i,a,o,s].some(e=>e===null))return!1;let[c,l,u,d]=t,f=.01;return i<=c+f&&a<=l+f&&i+o>=c+u-f&&a+s>=l+d-f}function Ow(e,t,n){let r=xw(e),i=new Set((e.attributes.get(`class`)??``).toLowerCase().split(/\s+/));return r===`rect`&&i.has(`backdrop`)||r===`rect`&&t!==null&&Tw(e)&&Dw(e,t)?!0:n===`graphviz`&&r===`polygon`&&Tw(e)&&(e.attributes.get(`stroke`)??``).toLowerCase()===`none`}function kw(e,t,n){let r=xw(e)===`svg`?Cw(e)??t:t;e.children=e.children.filter(e=>e.type===`text`||!Ow(e,r,n)&&(kw(e,r,n),!0))}function Aw(e,t){let n=(e.attributes.get(`style`)??``).split(`;`).map(e=>e.trim()).filter(Boolean).filter(e=>!/^background(?:-color)?\s*:/i.test(e));n.push(`background-color:${t}`),e.attributes.set(`style`,`${n.join(`;`)};`)}function jw(e,t=[],n=[]){return{type:`element`,name:e,attributes:new Map(t),children:n}}function Mw(e,t,n,r){let i=[],a=null;t.title&&i.push(jw(`title`,[],[{type:`text`,value:t.title}])),t.description&&i.push(jw(`desc`,[],[{type:`text`,value:t.description}]));let o=Cw(e);if((n.padding||n.background||n.frame)&&o===null)throw new pw(`Renderer output has no usable SVG dimensions for presentation settings.`);if(o!==null){let[t,r,s,c]=o,l=n.padding,u=[t-l,r-l,s+l*2,c+l*2];e.attributes.set(`viewBox`,u.join(` `)),e.attributes.has(`width`)&&e.attributes.set(`width`,String(u[2])),e.attributes.has(`height`)&&e.attributes.set(`height`,String(u[3])),n.background&&i.push(jw(`rect`,[[`x`,String(u[0])],[`y`,String(u[1])],[`width`,String(u[2])],[`height`,String(u[3])],[`fill`,n.background]])),n.frame&&(a=jw(`rect`,[[`x`,String(u[0]+.5)],[`y`,String(u[1]+.5)],[`width`,String(Math.max(0,u[2]-1))],[`height`,String(Math.max(0,u[3]-1))],[`fill`,`none`],[`stroke`,`#000000`],[`stroke-width`,`1`],[`vector-effect`,`non-scaling-stroke`]]))}n.background&&(kw(e,o,r),Aw(e,n.background)),e.children.unshift(...i),a&&e.children.push(a)}function Nw(e,t,n,r){if(e.length>cw)throw new pw(`Rendered SVG is too large.`);let i=null,a=[],o=0,s=null,c=new sw.SaxesParser({xmlns:!0});c.on(`doctype`,e=>{e.includes(`[`)&&(s=Error(`Internal DOCTYPE subsets are not allowed`))}),c.on(`opentag`,e=>{let t=e.local.toLowerCase(),n=t===`foreignobject`||a.some(e=>xw(e)===`foreignobject`);if(o>0||lw.has(t)||n&&!uw.has(t)){o++;return}let r=jw(e.name);for(let t of Object.values(e.attributes))_w(t.name,t.value)&&r.attributes.set(t.name,t.value);let c=a.at(-1);c?c.children.push(r):i===null?i=r:s=Error(`Multiple root elements`),a.push(r)});let l=e=>{if(o>0||e===``)return;let t=a.at(-1);if(t){if(xw(t)===`style`&&hw(e))throw new pw(`Renderer output contains unsafe CSS.`);t.children.push({type:`text`,value:e})}else e.trim()!==``&&(s=Error(`Text outside root element`))};c.on(`text`,l),c.on(`cdata`,l),c.on(`closetag`,()=>{o>0?o--:a.pop()}),c.on(`error`,e=>{s=e});try{c.write(e).close()}catch(e){if(e instanceof pw)throw e;s=e}if(s!==null||i===null||xw(i)!==`svg`)throw new pw(`Renderer returned invalid SVG.`);return Mw(i,t,n,r),bw(i)}var Pw=Object.freeze({bytefield:`https://bytefield.render.diagram.zip/v1/svg`,nomnoml:`https://nomnoml.render.diagram.zip/v1/svg`,vega:`https://vega.render.diagram.zip/v1/svg`,vegalite:`https://vegalite.render.diagram.zip/v1/svg`,wavedrom:`https://wavedrom.render.diagram.zip/v1/svg`});function Fw(e){return Pw[e]??null}function Iw(e,t,n){return Math.min(Math.max(e,t),n)}var Lw=class{constructor({stage:e,image:t,status:n,minimap:r,minimapImage:i,minimapViewport:a}){this.stage=e,this.image=t,this.status=n,this.minimap=r,this.minimapImage=i,this.minimapViewport=a,this.scale=1,this.x=0,this.y=0,this.objectUrl=null,this.abortController=null,this.requestNumber=0,this.pendingRender=null,this.renderLoop=null,this.latestRenderKey=null,this.latestSvgBlob=null,this.imageFallbackUrl=null,this.activeImageUrl=null,this.drag=null,this.image.addEventListener(`load`,()=>{this.image.src===this.activeImageUrl&&(this.imageFallbackUrl=null,this.setStatus(`Rendered`,`ready`),this.fit())}),this.image.addEventListener(`error`,()=>this.retryBlockedImage()),this.stage.addEventListener(`pointerdown`,e=>this.startPan(e)),this.stage.addEventListener(`pointermove`,e=>this.pan(e)),this.stage.addEventListener(`pointerup`,e=>this.endPan(e)),this.stage.addEventListener(`pointercancel`,e=>this.endPan(e)),this.stage.addEventListener(`wheel`,e=>this.wheelZoom(e),{passive:!1}),this.minimap.addEventListener(`pointerdown`,e=>this.moveFromMinimap(e)),new ResizeObserver(()=>this.updateTransform()).observe(this.stage)}render({type:e,source:t,options:n={},meta:r={},presentation:i={}}){if(!t.trim()){this.requestNumber++,this.pendingRender=null,this.abortController?.abort(),this.setStatus(`Write something to render.`,`idle`);return}let a=JSON.stringify({type:e,source:t,options:n,meta:r,presentation:i});return this.latestRenderKey===a&&this.latestSvgBlob?Promise.resolve():(this.pendingRender={type:e,source:t,options:n,meta:r,presentation:i,renderKey:a,requestNumber:++this.requestNumber},this.abortController?.abort(),this.renderLoop||=this.drainRenderQueue(),this.renderLoop)}async drainRenderQueue(){try{for(;this.pendingRender;){let e=this.pendingRender;this.pendingRender=null,await this.performRender(e)}}finally{this.renderLoop=null,this.pendingRender&&(this.renderLoop=this.drainRenderQueue())}}async performRender({type:e,source:t,options:n,meta:r,presentation:i,renderKey:a,requestNumber:o}){let s=new AbortController;this.abortController=s,this.setStatus(`Rendering…`,`loading`),this.stage.style.setProperty(`--render-background`,`var(--preview-bg)`);try{let c=rw(e),l;if(c)try{let a=await c.render({type:e,source:t,options:n},s.signal);l=Nw(a.body,r,i,e),this.status.dataset.cache=`browser`,this.status.dataset.renderer=a.runtime}catch(a){if(a.name===`AbortError`)throw a;l=await this.renderThroughGateway({type:e,source:t,options:n,meta:r,presentation:i},s.signal)}else l=await this.renderThroughGateway({type:e,source:t,options:n,meta:r,presentation:i},s.signal);if(o!==this.requestNumber)return;let{blob:u,background:d}=this.normalizedSvgBlob(l);this.latestRenderKey=a,this.latestSvgBlob=u,this.imageFallbackUrl=`data:image/svg+xml;charset=utf-8,${encodeURIComponent(await u.text())}`,this.stage.style.setProperty(`--render-background`,d);let f=URL.createObjectURL(u),p=this.objectUrl;this.objectUrl=f,this.activeImageUrl=f,this.image.src=f,this.minimapImage.src=f,this.image.hidden=!1,this.setStatus(`Loading image…`,`loading`),p&&URL.revokeObjectURL(p)}catch(e){if(e.name===`AbortError`)return;this.setStatus(e.message||`Could not render this diagram.`,`error`)}finally{this.abortController===s&&(this.abortController=null)}}async renderThroughGateway({type:e,source:t,options:n,meta:r,presentation:i},a){let o=Fw(e);if(o)try{let e=await this.renderRequest(o,{source:t,format:`svg`,options:n,metadata:r,presentation:i},a);if(e.ok||e.status<500)return await this.renderResponse(e);await e.body?.cancel()}catch(e){if(e.name===`AbortError`)throw e}let s=await this.renderRequest(`/render/v1/svg`,{engine:e,source:t,format:`svg`,options:n,metadata:r,presentation:i},a);return this.renderResponse(s)}renderRequest(e,t,n){return fetch(e,{method:`POST`,headers:{Accept:`image/svg+xml`,"Content-Type":`application/json`},body:JSON.stringify(t),signal:n})}async renderResponse(e){if(!e.ok)throw Error(await this.errorMessage(e));return this.status.dataset.cache=e.headers.get(`X-Diagram-Cache`)?.toLowerCase()??`miss`,this.status.dataset.renderer=e.headers.get(`X-Diagram-Unit`)?.toLowerCase()??e.headers.get(`X-Diagram-Renderer`)?.toLowerCase()??`gateway`,e.text()}retryBlockedImage(){if(this.image.src===this.activeImageUrl){if(this.imageFallbackUrl&&this.activeImageUrl.startsWith(`blob:`)){let e=this.imageFallbackUrl;this.imageFallbackUrl=null,this.objectUrl&&URL.revokeObjectURL(this.objectUrl),this.objectUrl=null,this.activeImageUrl=e,this.image.src=e,this.minimapImage.src=e;return}this.setStatus(`The rendered image was blocked or invalid.`,`error`)}}svgBlobFor(e){let{type:t,source:n,options:r={},meta:i={},presentation:a={}}=e,o=JSON.stringify({type:t,source:n,options:r,meta:i,presentation:a});return this.latestRenderKey===o?this.latestSvgBlob:null}async errorMessage(e){let t=await e.text();if(e.headers.get(`Content-Type`)?.includes(`application/json`))try{let e=JSON.parse(t);if(typeof e?.error?.message==`string`)return e.error.message}catch{}return new DOMParser().parseFromString(t,`text/html`).body.textContent.trim().replace(/\s+/g,` `)||`Render failed with HTTP ${e.status}.`}normalizedSvgBlob(e){let t=new DOMParser().parseFromString(e,`image/svg+xml`).documentElement,n=t.getAttribute(`viewBox`)?.trim().split(/[\s,]+/).map(Number);t.nodeName===`svg`&&n?.length===4&&n.every(Number.isFinite)&&(t.hasAttribute(`width`)||t.setAttribute(`width`,String(n[2])),t.hasAttribute(`height`)||t.setAttribute(`height`,String(n[3])),e=new XMLSerializer().serializeToString(t));let r=t.style.backgroundColor||t.style.background,i=r&&r!==`transparent`?r:`#ffffff`;return{blob:new Blob([e],{type:`image/svg+xml`}),background:i}}setStatus(e,t){this.status.textContent=e,this.status.dataset.state=t}zoom(e){if(this.image.hidden)return;let t=this.stage.getBoundingClientRect();this.zoomAt(e,t.width/2,t.height/2)}zoomAt(e,t,n){let r=Iw(this.scale*e,.1,8),i=(t-this.x)/this.scale,a=(n-this.y)/this.scale;this.x=t-i*r,this.y=n-a*r,this.scale=r,this.updateTransform()}wheelZoom(e){if(this.image.hidden||e.target.closest(`.preview-toolbar, .minimap`))return;e.preventDefault();let t=this.stage.getBoundingClientRect(),n=e.deltaY*(e.deltaMode===WheelEvent.DOM_DELTA_LINE?16:e.deltaMode===WheelEvent.DOM_DELTA_PAGE?t.height:1);this.zoomAt(Math.exp(-Iw(n,-240,240)*.002),e.clientX-t.left,e.clientY-t.top)}oneToOne(){if(this.image.hidden)return;let e=this.stage.getBoundingClientRect();this.scale=1,this.x=(e.width-this.image.naturalWidth)/2,this.y=(e.height-this.image.naturalHeight)/2,this.updateTransform()}fit(){if(!this.image.naturalWidth||!this.image.naturalHeight)return;let e=this.stage.getBoundingClientRect(),t=Math.min(64,e.width*.12);this.scale=Iw(Math.min((e.width-t*2)/this.image.naturalWidth,(e.height-t*2)/this.image.naturalHeight),.1,2),this.x=(e.width-this.image.naturalWidth*this.scale)/2,this.y=(e.height-this.image.naturalHeight*this.scale)/2,this.updateTransform()}updateTransform(){this.image.style.transform=`translate(${this.x}px, ${this.y}px) scale(${this.scale})`,this.updateMinimap()}startPan(e){this.image.hidden||e.button!==0||e.target.closest(`.preview-toolbar, .minimap`)||(this.drag={pointerId:e.pointerId,x:e.clientX,y:e.clientY,originX:this.x,originY:this.y},this.stage.setPointerCapture(e.pointerId),this.stage.dataset.dragging=`true`)}pan(e){!this.drag||e.pointerId!==this.drag.pointerId||(this.x=this.drag.originX+e.clientX-this.drag.x,this.y=this.drag.originY+e.clientY-this.drag.y,this.updateTransform())}endPan(e){!this.drag||e.pointerId!==this.drag.pointerId||(this.drag=null,delete this.stage.dataset.dragging)}moveFromMinimap(e){if(!this.image.naturalWidth||!this.image.naturalHeight)return;let t=this.minimap.getBoundingClientRect(),n=Math.min(t.width/this.image.naturalWidth,t.height/this.image.naturalHeight),r=(t.width-this.image.naturalWidth*n)/2,i=(t.height-this.image.naturalHeight*n)/2,a=(e.clientX-t.left-r)/n,o=(e.clientY-t.top-i)/n,s=this.stage.getBoundingClientRect();this.x=s.width/2-a*this.scale,this.y=s.height/2-o*this.scale,this.updateTransform()}updateMinimap(){if(!this.image.naturalWidth||!this.image.naturalHeight)return;let e=this.stage.getBoundingClientRect(),t=this.image.naturalWidth*this.scale,n=this.image.naturalHeight*this.scale,r=this.x>=0&&this.y>=0&&this.x+t<=e.width&&this.y+n<=e.height;if(this.minimap.hidden=r,r)return;let i=this.minimap.getBoundingClientRect(),a=Math.min(i.width/this.image.naturalWidth,i.height/this.image.naturalHeight),o=(i.width-this.image.naturalWidth*a)/2,s=(i.height-this.image.naturalHeight*a)/2,c=Iw(-this.x/this.scale,0,this.image.naturalWidth),l=Iw(-this.y/this.scale,0,this.image.naturalHeight),u=Iw((e.width-this.x)/this.scale,0,this.image.naturalWidth),d=Iw((e.height-this.y)/this.scale,0,this.image.naturalHeight);this.minimapViewport.style.left=`${o+c*a}px`,this.minimapViewport.style.top=`${s+l*a}px`,this.minimapViewport.style.width=`${Math.max(4,(u-c)*a)}px`,this.minimapViewport.style.height=`${Math.max(4,(d-l)*a)}px`}},Rw=`diagram.zip:draft:local:v2`,zw=`diagram.zip:draft:alias:v1:`,Bw=`diagram.zip:write:v1:`,Vw=new ke,Hw=new DC,Uw,Ww=!1,Gw,Kw=!1,qw=``,Q={aliasId:null,contentId:null,renderId:null,revision:null,mode:`open`,savedMode:null,writeCapability:null,savedState:null,savedSnapshot:null,bundleKey:null,keyEnvelope:null,encryptedContent:null,encryptedMetadata:null,keyEnvelopeDirty:!1,dirty:!0},Jw=new Map;document.querySelector(`#app`).innerHTML=`16481648 <main class="app-shell">16491649 <header class="app-header">16501650 <a class="brand" href="/" aria-label="New diagram"><img class="brand-mark" src="/diagram.zip/icon.svg" alt=""><span>diagram.zip</span></a>@@ -1790,4 +1790,4 @@ ${h}.`);break;case m:switch(t){case`xml`:break;case``:e.fail(`the default namesp
17901790 </dialog>17911791 17921792 <div class="toast" id="toast" role="status" aria-live="polite"></div>1793-`;var Jw=document.querySelector(`#diagram-type`),Yw=document.querySelector(`#diagram-title`),Xw=document.querySelector(`#diagram-description`),Zw=document.querySelector(`#diagram-background`),Qw=document.querySelector(`#diagram-padding`),$w=document.querySelector(`#diagram-frame`);for(let{id:e,label:t}of mx)Jw.add(new Option(t,e));var eT=await uT(),tT=sC(eT.meta),nT=cC(eT.presentation);Jw.value=eT.type,Yw.value=tT.title,Xw.value=tT.description,Zw.value=nT.background,Qw.value=String(nT.padding),$w.checked=nT.frame,RT(),Ww=eT.type,qw.set(eT.type,eT);var rT=sd.define([{tag:J.keyword,color:`var(--syntax-keyword)`,fontWeight:`650`},{tag:J.string,color:`var(--syntax-string)`},{tag:[J.comment,J.lineComment,J.blockComment],color:`var(--syntax-comment)`,fontStyle:`italic`},{tag:[J.number,J.bool],color:`var(--syntax-number)`},{tag:[J.operator,J.punctuation],color:`var(--syntax-operator)`},{tag:[J.variableName,J.typeName],color:`var(--syntax-variable)`}]),iT=new U({state:M.create({doc:eT.source,extensions:[j_,Bw.of(yx(eT.type)),dd(rT),U.theme({"&":{height:`100%`,backgroundColor:`transparent`},".cm-scroller":{fontFamily:`var(--font-mono)`,lineHeight:`1.65`},".cm-content":{padding:`28px 10px 80px`},".cm-gutters":{backgroundColor:`transparent`,border:`0`,paddingLeft:`12px`},".cm-activeLine, .cm-activeLineGutter":{backgroundColor:`var(--editor-active-line)`},".cm-cursor, .cm-dropCursor":{borderLeftColor:`var(--ink)`},"&.cm-focused":{outline:`none`}}),U.updateListener.of(e=>{e.docChanged&&!Uw&&sT()})]}),parent:document.querySelector(`#editor`)}),aT=new Iw({stage:document.querySelector(`#preview-stage`),image:document.querySelector(`#preview-image`),status:document.querySelector(`.render-status`),minimap:document.querySelector(`#minimap`),minimapImage:document.querySelector(`#minimap-image`),minimapViewport:document.querySelector(`#minimap-viewport`)});Jw.addEventListener(`change`,()=>{let e=Jw.value;dT(pC(qw,Ww,e,oT(),fC))}),document.querySelector(`#details`).addEventListener(`click`,()=>{document.querySelector(`#details-dialog`).showModal(),Yw.focus()});for(let e of[Yw,Xw,Zw,Qw,$w])e.addEventListener(`input`,()=>{RT(),clearTimeout(lT.timeout),lT.timeout=setTimeout(lT,220)});document.querySelector(`#details-dialog`).addEventListener(`close`,lT),document.querySelector(`#lock-diagram`).addEventListener(`click`,bT),document.querySelector(`#change-password`).addEventListener(`click`,xT),document.querySelector(`#unlock-diagram`).addEventListener(`click`,ST),document.querySelector(`#save`).addEventListener(`click`,()=>hT()),document.querySelector(`#share`).addEventListener(`click`,fT),document.querySelector(`#share-save`).addEventListener(`click`,async()=>{await hT(),pT()}),document.querySelector(`.brand`).addEventListener(`click`,e=>{e.preventDefault(),confirm(`Start a new diagram?`)&<()}),document.querySelectorAll(`[data-preview-action]`).forEach(e=>{e.addEventListener(`click`,()=>{let t=e.dataset.previewAction;t===`zoom-out`&&aT.zoom(.8),t===`zoom-in`&&aT.zoom(1.25),t===`fit`&&aT.fit(),t===`one-to-one`&&aT.oneToOne()})}),document.querySelectorAll(`.mobile-tabs button`).forEach(e=>{e.addEventListener(`click`,()=>{document.querySelector(`.workspace`).dataset.mobilePanel=e.dataset.panel,document.querySelectorAll(`.mobile-tabs button`).forEach(t=>{t.setAttribute(`aria-selected`,String(t===e))}),e.dataset.panel===`preview`&&aT.fit()})}),document.querySelectorAll(`[data-copy]`).forEach(e=>{e.addEventListener(`click`,async()=>{let t=document.querySelector(`#${e.dataset.copy}`);t.value&&(await zT(t.value),$(`Copied`))})}),window.addEventListener(`popstate`,()=>location.reload()),window.addEventListener(`keydown`,e=>{(e.metaKey||e.ctrlKey)&&e.key.toLowerCase()===`s`&&(e.preventDefault(),hT())});function oT(){let e=Math.min(256,Math.max(0,Number.parseInt(Qw.value,10)||0));return{type:Jw.value,source:iT.state.doc.toString(),options:{},meta:sC({title:Yw.value,description:Xw.value}),presentation:cC({background:Zw.value,padding:e,frame:$w.checked})}}function sT(e=1200){clearTimeout(Hw),Hw=setTimeout(cT,e)}function cT(e=!0){let t=oT();AT(t),Q.dirty=Q.keyEnvelopeDirty||Q.savedSnapshot!==DT(t,Q.mode),FT(),IT(),e&&aT.render(t)}function lT(){clearTimeout(lT.timeout),cT()}async function uT(){let e=yC(location.pathname);if(e){let t=CC(location.hash);t&&MT(e,t),location.hash&&history.replaceState(null,``,`${location.pathname}${location.search}`);try{let n=await Vw.getAlias(e),r=t??NT(e);if(n.mode===`locked`){let e=await CT(n);return e?(PT(n,r,e.state,e.bundleKey),e.state):(Kw=`A password is required to open this diagram.`,fC(aC))}PT(n,r,n.state);let i=kT(`${Rw}${e}`);return i?.revision===n.revision?i.state:n.state}catch(e){Kw=e instanceof wC?e.message:`This saved diagram could not be loaded.`}}location.hash&&history.replaceState(null,``,`${location.pathname}${location.search}`);let t=kT(Lw);return t?t.state:fC(aC)}function dT(e,t=!0){if(!bx(e.type))throw Error(`Unsupported diagram type.`);let n=sC(e.meta),r=cC(e.presentation);Uw=!0,Ww=e.type,qw.set(e.type,{...e,meta:n,presentation:r}),Jw.value=e.type,Yw.value=n.title,Xw.value=n.description,Zw.value=r.background,Qw.value=String(r.padding),$w.checked=r.frame,RT(),iT.dispatch({changes:{from:0,to:iT.state.doc.length,insert:e.source},effects:Bw.reconfigure(yx(e.type))}),Uw=!1,t?cT():aT.render(oT())}function fT(){cT(),pT(),document.querySelector(`#share-dialog`).showModal()}function pT(){let e=!!Q.aliasId,t=e&&Q.savedMode===`locked`,n=e?bC(location.origin,Q.aliasId):``,r=e&&Q.writeCapability?xC(location.origin,Q.aliasId,Q.writeCapability):``,i=t?null:Q.savedState,a=i?SC(location.origin,Q.aliasId,`svg`):``,o=document.querySelector(`#image-link`),s=document.querySelector(`#markdown-link`),c=i?.meta.title.trim().replace(/[\[\]\r\n]/g,` `)||`Diagram`;mT(`viewer-link`,n,`Save to create a read link`),mT(`editor-link`,r,e?`No write capability on this device`:`Save to create an edit link`),mT(`image-link`,a,t?`Encrypted diagrams cannot be embedded`:e?`Unavailable for this diagram`:`Save to create an image link`),mT(`markdown-link`,a?``:``,t?`Encrypted diagrams cannot be embedded`:e?`Unavailable for this diagram`:`Save to create Markdown`),document.querySelector(`#editor-link-note`).textContent=r?`Anyone with this link can update the diagram.`:e?`This device has read-only access. Save a copy to create a new edit link.`:`The edit link is a bearer credential and appears after saving.`,document.querySelector(`#image-link-note`).textContent=t?`This diagram is encrypted in your browser. Image embeds are disabled because they cannot ask for its password.`:``,o.dataset.state=t?`unavailable`:`ready`,s.dataset.state=t?`unavailable`:`ready`;let l=document.querySelector(`#share-status`),u=document.querySelector(`#share-save`);u.hidden=e&&!Q.dirty,e?Q.dirty&&Q.writeCapability?(l.textContent=`These links show the last saved version. Save your changes before sharing.`,u.textContent=`Save changes`):Q.dirty?(l.textContent=`You are editing a read-only diagram. Save a copy to share your changes.`,u.textContent=`Save as new`):l.textContent=t?Q.writeCapability?`The read link asks for the password. The edit link also grants permission to save changes.`:`The read link asks for the password. This device has read-only access.`:Q.writeCapability?`Copy a read link, or share the edit capability carefully.`:`This diagram is read-only on this device.`:(l.textContent=`Save this diagram to create stable share links.`,u.textContent=`Save diagram`)}function mT(e,t,n){let r=document.querySelector(`#${e}`),i=document.querySelector(`[data-copy="${e}"]`);r.value=t,r.placeholder=t?``:n,i.disabled=!t}async function hT(){if(Gw)return!1;cT(!1);let e=oT();if(Q.aliasId&&!Q.dirty)return $(`Already saved`),!0;Gw=!0,FT();try{if(Q.aliasId&&Q.writeCapability)return PT(Q.mode===`locked`?await Vw.updateLockedAlias(Q.aliasId,await _T(e),Q.revision,Q.writeCapability):await Vw.updateAlias(Q.aliasId,e,Q.revision,Q.writeCapability),Q.writeCapability,e,Q.mode===`locked`?Q.bundleKey:null),jT(`${Rw}${Q.aliasId}`),await vT(e),$(`Saved`),!0;let t=!!Q.aliasId;return await gT(e),$(t?`Saved as a new diagram`:`Saved`),!0}catch(t){return t instanceof wC&&t.status===412&&Q.aliasId?await TT(e):($(t instanceof Error?t.message:`Could not save this diagram.`),!1)}finally{Gw=!1,FT()}}async function gT(e){let t=Q.aliasId,n=t?`${Rw}${t}`:Lw,r=Q.bundleKey,i=Q.mode===`locked`?await Vw.createLockedAlias(await _T(e)):await Vw.createAlias(e);PT(i,i.writeCapability,e,Q.mode===`locked`?r:null),MT(i.aliasId,i.writeCapability),jT(n),history.pushState(null,``,`/d/${i.aliasId}`),await vT(e)}async function _T(e){if(!(Q.bundleKey instanceof Uint8Array)||!Q.keyEnvelope)throw Error(`This diagram is missing its browser encryption key.`);return Q.savedMode===`locked`&&Q.savedSnapshot===DT(e,`locked`)&&Q.encryptedContent&&Q.encryptedMetadata?{mode:`locked`,encryptedContent:Q.encryptedContent,encryptedMetadata:Q.encryptedMetadata,keyEnvelope:Q.keyEnvelope}:qC(e,Q.bundleKey,Q.keyEnvelope)}async function vT(e){if(!Q.aliasId||!Q.writeCapability)return;await aT.render(e);let t=aT.svgBlobFor(e);if(!t)return;let n=[[`svg`,t]];try{n.push([`png`,await yT(t)])}catch{}let r=n.map(async([e,t])=>{let n=Q.mode===`locked`?await XC(t,Q.bundleKey,e):t;return Vw.uploadRender({aliasId:Q.aliasId,renderId:Q.renderId,revision:Q.revision,writeCapability:Q.writeCapability,format:e,mode:Q.mode,render:n})});(await Promise.allSettled(r)).every(e=>e.status===`rejected`)&&aT.setStatus(`Saved; render cache unavailable`,`ready`)}async function yT(e){let t=URL.createObjectURL(e);try{let e=new Image;e.src=t,await e.decode();let n=Math.min(1,4096/Math.max(e.naturalWidth,e.naturalHeight)),r=Math.max(1,Math.round(e.naturalWidth*n)),i=Math.max(1,Math.round(e.naturalHeight*n)),a=document.createElement(`canvas`);a.width=r,a.height=i;let o=a.getContext(`2d`);if(!o)throw Error(`Canvas is unavailable.`);o.drawImage(e,0,0,r,i);let s=await new Promise(e=>a.toBlob(e,`image/png`));if(!s)throw Error(`Could not create a PNG render.`);return s}finally{URL.revokeObjectURL(t)}}async function bT(){let e=await wT({title:`Lock diagram`,copy:`The source, metadata, and saved render will be encrypted in this browser. The password cannot be recovered.`,submitLabel:`Lock diagram`,confirm:!0});if(e!==null)try{let{bundleKey:t,payload:n}=await JC(oT(),e);Q.mode=`locked`,Q.bundleKey=t,Q.keyEnvelope=n.keyEnvelope,Q.encryptedContent=n.encryptedContent,Q.encryptedMetadata=n.encryptedMetadata,Q.keyEnvelopeDirty=!0,jT(Q.aliasId?`${Rw}${Q.aliasId}`:Lw),cT(!1),$(`Locked in this browser — save to persist`)}catch(e){$(e instanceof Error?e.message:`Could not lock this diagram.`)}}async function xT(){if(Q.mode!==`locked`||!(Q.bundleKey instanceof Uint8Array))return;let e=await wT({title:`Change password`,copy:`Only the encrypted bundle key will be rewrapped. The diagram content does not need to be re-encrypted.`,submitLabel:`Change password`,confirm:!0});if(e!==null)try{Q.keyEnvelope=await GC(Q.bundleKey,e),Q.keyEnvelopeDirty=!0,cT(!1),$(`Password changed — save to persist`)}catch(e){$(e instanceof Error?e.message:`Could not change the password.`)}}function ST(){Q.mode===`locked`&&confirm(`Remove password protection? The next save will store the diagram in plaintext.`)&&(Q.mode=`open`,Q.keyEnvelopeDirty=!1,cT(!1),$(`Password removed — save to persist`))}async function CT(e){for(;;){let t=await wT({title:`Unlock diagram`,copy:`Decryption happens only in this browser. The password is never sent to diagram.zip.`,submitLabel:`Unlock`,confirm:!1});if(t===null)return null;try{return await YC(e,t)}catch(e){$(e instanceof Error?e.message:`Could not unlock this diagram.`)}}}function wT({title:e,copy:t,submitLabel:n,confirm:r}){let i=document.querySelector(`#password-dialog`),a=document.querySelector(`#password-form`),o=document.querySelector(`#diagram-password`),s=document.querySelector(`#diagram-password-confirm`),c=document.querySelector(`#password-confirm-field`),l=document.querySelector(`#password-error`);return document.querySelector(`#password-title`).textContent=e,document.querySelector(`#password-copy`).textContent=t,document.querySelector(`#password-submit`).textContent=n,c.hidden=!r,o.autocomplete=r?`new-password`:`current-password`,o.value=``,s.value=``,l.textContent=``,new Promise(e=>{let t=!1,n=n=>{t||(t=!0,a.removeEventListener(`submit`,c),document.querySelector(`#password-cancel`).removeEventListener(`click`,u),i.removeEventListener(`cancel`,u),i.removeEventListener(`close`,d),e(n))},c=e=>{e.preventDefault();let t=o.value;if(r&&t.length<8){l.textContent=`Use at least 8 characters.`,o.focus();return}if(r&&t!==s.value){l.textContent=`The passwords do not match.`,s.focus();return}i.close(),n(t)},u=e=>{e.preventDefault(),i.close(),n(null)},d=()=>n(null);a.addEventListener(`submit`,c),document.querySelector(`#password-cancel`).addEventListener(`click`,u),i.addEventListener(`cancel`,u),i.addEventListener(`close`,d),i.showModal(),o.focus()})}async function TT(e){let t=await ET();if(t===`reload`){let e=Q.aliasId,t=Q.writeCapability;try{let n=await Vw.getAlias(e),r=n.state,i=null;if(n.mode===`locked`){let e=await CT(n);if(!e)return!1;r=e.state,i=e.bundleKey}return PT(n,t,r,i),jT(`${Rw}${e}`),dT(r,!1),FT(),$(`Reloaded saved diagram`),!0}catch(e){return $(e instanceof Error?e.message:`Could not reload this diagram.`),!1}}return t===`copy`&&(await gT(e),$(`Saved as a new diagram`),!0)}function ET(){let e=document.querySelector(`#conflict-dialog`);return e.returnValue=``,e.showModal(),new Promise(t=>{e.addEventListener(`close`,()=>t(e.returnValue),{once:!0})})}function DT(e,t=`open`){return JSON.stringify({mode:t,type:e.type,source:e.source,options:e.options??{},meta:sC(e.meta),presentation:cC(e.presentation)})}function OT(e){if(!e||typeof e!=`object`||!bx(e.type)||typeof e.source!=`string`)return null;try{return{type:e.type,source:e.source,options:e.options??{},meta:sC(e.meta),presentation:cC(e.presentation)}}catch{return null}}function kT(e){try{let t=JSON.parse(localStorage.getItem(e)),n=OT(t?.state);return n?{state:n,revision:t.revision??null}:null}catch{return null}}function AT(e){if(Q.mode===`locked`)return;let t=Q.aliasId?`${Rw}${Q.aliasId}`:Lw;try{localStorage.setItem(t,JSON.stringify({state:e,revision:Q.revision}))}catch{}}function jT(e){try{localStorage.removeItem(e)}catch{}}function MT(e,t){try{localStorage.setItem(`${zw}${e}`,t)}catch{}}function NT(e){try{return CC(`#w=${localStorage.getItem(`${zw}${e}`)??``}`)}catch{return null}}function PT(e,t,n,r=null){Q={aliasId:e.aliasId,contentId:e.contentId,renderId:e.renderId,revision:e.revision,mode:e.mode,savedMode:e.mode,writeCapability:t,savedState:n,savedSnapshot:DT(n,e.mode),bundleKey:r,keyEnvelope:e.mode===`locked`?e.keyEnvelope:null,encryptedContent:e.mode===`locked`?e.encryptedContent:null,encryptedMetadata:e.mode===`locked`?e.encryptedMetadata:null,keyEnvelopeDirty:!1,dirty:!1},IT(),FT()}function FT(){let e=document.querySelector(`#save`);if(Gw){e.textContent=`Saving…`,e.disabled=!0;return}if(Q.aliasId&&!Q.dirty){e.textContent=`Saved`,e.disabled=!0;return}e.textContent=Q.aliasId&&!Q.writeCapability?`Save copy`:`Save`,e.disabled=!1}function IT(){let e=Q.mode===`locked`;document.querySelector(`#privacy-label`).textContent=e?`Password locked`:`Open`,document.querySelector(`#privacy-description`).textContent=e?`Source, metadata, and saved renders are encrypted in your browser. Password-locked diagrams cannot be embedded.`:`Anyone with the read link can open and embed this diagram.`,document.querySelector(`#lock-diagram`).hidden=e,document.querySelector(`#change-password`).hidden=!e,document.querySelector(`#unlock-diagram`).hidden=!e}function LT(){Q={aliasId:null,contentId:null,renderId:null,revision:null,mode:`open`,savedMode:null,writeCapability:null,savedState:null,savedSnapshot:null,bundleKey:null,keyEnvelope:null,encryptedContent:null,encryptedMetadata:null,keyEnvelopeDirty:!1,dirty:!0},qw.clear(),history.pushState(null,``,`/`),dT(fC(aC))}function RT(){let e=Yw.value.trim(),t=Xw.value.trim();document.title=e?`${e} — diagram.zip`:`diagram.zip`,document.querySelector(`meta[name="description"]`).content=t||`Create diagrams from text and share them as a link.`}async function zT(e){if(navigator.clipboard)return navigator.clipboard.writeText(e);let t=document.createElement(`textarea`);t.value=e,document.body.append(t),t.select(),document.execCommand(`copy`),t.remove()}function $(e){let t=document.querySelector(`#toast`);t.textContent=e,t.dataset.visible=`true`,clearTimeout($.timeout),$.timeout=setTimeout(()=>delete t.dataset.visible,1800)}cT(),Kw&&$(Kw);\ No newline at end of file1793+`;var Yw=document.querySelector(`#diagram-type`),Xw=document.querySelector(`#diagram-title`),Zw=document.querySelector(`#diagram-description`),Qw=document.querySelector(`#diagram-background`),$w=document.querySelector(`#diagram-padding`),eT=document.querySelector(`#diagram-frame`);for(let{id:e,label:t}of mx)Yw.add(new Option(t,e));var tT=await dT(),nT=sC(tT.meta),rT=cC(tT.presentation);Yw.value=tT.type,Xw.value=nT.title,Zw.value=nT.description,Qw.value=rT.background,$w.value=String(rT.padding),eT.checked=rT.frame,zT(),Gw=tT.type,Jw.set(tT.type,tT);var iT=sd.define([{tag:J.keyword,color:`var(--syntax-keyword)`,fontWeight:`650`},{tag:J.string,color:`var(--syntax-string)`},{tag:[J.comment,J.lineComment,J.blockComment],color:`var(--syntax-comment)`,fontStyle:`italic`},{tag:[J.number,J.bool],color:`var(--syntax-number)`},{tag:[J.operator,J.punctuation],color:`var(--syntax-operator)`},{tag:[J.variableName,J.typeName],color:`var(--syntax-variable)`}]),aT=new U({state:M.create({doc:tT.source,extensions:[j_,Vw.of(yx(tT.type)),dd(iT),U.theme({"&":{height:`100%`,backgroundColor:`transparent`},".cm-scroller":{fontFamily:`var(--font-mono)`,lineHeight:`1.65`},".cm-content":{padding:`28px 10px 80px`},".cm-gutters":{backgroundColor:`transparent`,border:`0`,paddingLeft:`12px`},".cm-activeLine, .cm-activeLineGutter":{backgroundColor:`var(--editor-active-line)`},".cm-cursor, .cm-dropCursor":{borderLeftColor:`var(--ink)`},"&.cm-focused":{outline:`none`}}),U.updateListener.of(e=>{e.docChanged&&!Ww&&cT()})]}),parent:document.querySelector(`#editor`)}),oT=new Lw({stage:document.querySelector(`#preview-stage`),image:document.querySelector(`#preview-image`),status:document.querySelector(`.render-status`),minimap:document.querySelector(`#minimap`),minimapImage:document.querySelector(`#minimap-image`),minimapViewport:document.querySelector(`#minimap-viewport`)});Yw.addEventListener(`change`,()=>{let e=Yw.value;fT(pC(Jw,Gw,e,sT(),fC))}),document.querySelector(`#details`).addEventListener(`click`,()=>{document.querySelector(`#details-dialog`).showModal(),Xw.focus()});for(let e of[Xw,Zw,Qw,$w,eT])e.addEventListener(`input`,()=>{zT(),clearTimeout(uT.timeout),uT.timeout=setTimeout(uT,220)});document.querySelector(`#details-dialog`).addEventListener(`close`,uT),document.querySelector(`#lock-diagram`).addEventListener(`click`,xT),document.querySelector(`#change-password`).addEventListener(`click`,ST),document.querySelector(`#unlock-diagram`).addEventListener(`click`,CT),document.querySelector(`#save`).addEventListener(`click`,()=>gT()),document.querySelector(`#share`).addEventListener(`click`,pT),document.querySelector(`#share-save`).addEventListener(`click`,async()=>{await gT(),mT()}),document.querySelector(`.brand`).addEventListener(`click`,e=>{e.preventDefault(),confirm(`Start a new diagram?`)&&RT()}),document.querySelectorAll(`[data-preview-action]`).forEach(e=>{e.addEventListener(`click`,()=>{let t=e.dataset.previewAction;t===`zoom-out`&&oT.zoom(.8),t===`zoom-in`&&oT.zoom(1.25),t===`fit`&&oT.fit(),t===`one-to-one`&&oT.oneToOne()})}),document.querySelectorAll(`.mobile-tabs button`).forEach(e=>{e.addEventListener(`click`,()=>{document.querySelector(`.workspace`).dataset.mobilePanel=e.dataset.panel,document.querySelectorAll(`.mobile-tabs button`).forEach(t=>{t.setAttribute(`aria-selected`,String(t===e))}),e.dataset.panel===`preview`&&oT.fit()})}),document.querySelectorAll(`[data-copy]`).forEach(e=>{e.addEventListener(`click`,async()=>{let t=document.querySelector(`#${e.dataset.copy}`);t.value&&(await BT(t.value),$(`Copied`))})}),window.addEventListener(`popstate`,()=>location.reload()),window.addEventListener(`keydown`,e=>{(e.metaKey||e.ctrlKey)&&e.key.toLowerCase()===`s`&&(e.preventDefault(),gT())});function sT(){let e=Math.min(256,Math.max(0,Number.parseInt($w.value,10)||0));return{type:Yw.value,source:aT.state.doc.toString(),options:{},meta:sC({title:Xw.value,description:Zw.value}),presentation:cC({background:Qw.value,padding:e,frame:eT.checked})}}function cT(e=1200){clearTimeout(Uw),Uw=setTimeout(lT,e)}function lT(e=!0){let t=sT();jT(t),Q.dirty=Q.keyEnvelopeDirty||Q.savedSnapshot!==OT(t,Q.mode),IT(),LT(),e&&oT.render(t)}function uT(){clearTimeout(uT.timeout),lT()}async function dT(){let e=yC(location.pathname);if(e){let t=CC(location.hash);t&&NT(e,t),location.hash&&history.replaceState(null,``,`${location.pathname}${location.search}`);try{let n=await Hw.getAlias(e),r=t??PT(e);if(n.mode===`locked`){let e=await wT(n);return e?(FT(n,r,e.state,e.bundleKey),e.state):(qw=`A password is required to open this diagram.`,fC(aC))}FT(n,r,n.state);let i=AT(`${zw}${e}`);return i?.revision===n.revision?i.state:n.state}catch(e){qw=e instanceof wC?e.message:`This saved diagram could not be loaded.`}}location.hash&&history.replaceState(null,``,`${location.pathname}${location.search}`);let t=AT(Rw);return t?t.state:fC(aC)}function fT(e,t=!0){if(!bx(e.type))throw Error(`Unsupported diagram type.`);let n=sC(e.meta),r=cC(e.presentation);Ww=!0,Gw=e.type,Jw.set(e.type,{...e,meta:n,presentation:r}),Yw.value=e.type,Xw.value=n.title,Zw.value=n.description,Qw.value=r.background,$w.value=String(r.padding),eT.checked=r.frame,zT(),aT.dispatch({changes:{from:0,to:aT.state.doc.length,insert:e.source},effects:Vw.reconfigure(yx(e.type))}),Ww=!1,t?lT():oT.render(sT())}function pT(){lT(),mT(),document.querySelector(`#share-dialog`).showModal()}function mT(){let e=!!Q.aliasId,t=e&&Q.savedMode===`locked`,n=e?bC(location.origin,Q.aliasId):``,r=e&&Q.writeCapability?xC(location.origin,Q.aliasId,Q.writeCapability):``,i=t?null:Q.savedState,a=i?SC(location.origin,Q.aliasId,`svg`):``,o=document.querySelector(`#image-link`),s=document.querySelector(`#markdown-link`),c=i?.meta.title.trim().replace(/[\[\]\r\n]/g,` `)||`Diagram`;hT(`viewer-link`,n,`Save to create a read link`),hT(`editor-link`,r,e?`No write capability on this device`:`Save to create an edit link`),hT(`image-link`,a,t?`Encrypted diagrams cannot be embedded`:e?`Unavailable for this diagram`:`Save to create an image link`),hT(`markdown-link`,a?``:``,t?`Encrypted diagrams cannot be embedded`:e?`Unavailable for this diagram`:`Save to create Markdown`),document.querySelector(`#editor-link-note`).textContent=r?`Anyone with this link can update the diagram.`:e?`This device has read-only access. Save a copy to create a new edit link.`:`The edit link is a bearer credential and appears after saving.`,document.querySelector(`#image-link-note`).textContent=t?`This diagram is encrypted in your browser. Image embeds are disabled because they cannot ask for its password.`:``,o.dataset.state=t?`unavailable`:`ready`,s.dataset.state=t?`unavailable`:`ready`;let l=document.querySelector(`#share-status`),u=document.querySelector(`#share-save`);u.hidden=e&&!Q.dirty,e?Q.dirty&&Q.writeCapability?(l.textContent=`These links show the last saved version. Save your changes before sharing.`,u.textContent=`Save changes`):Q.dirty?(l.textContent=`You are editing a read-only diagram. Save a copy to share your changes.`,u.textContent=`Save as new`):l.textContent=t?Q.writeCapability?`The read link asks for the password. The edit link also grants permission to save changes.`:`The read link asks for the password. This device has read-only access.`:Q.writeCapability?`Copy a read link, or share the edit capability carefully.`:`This diagram is read-only on this device.`:(l.textContent=`Save this diagram to create stable share links.`,u.textContent=`Save diagram`)}function hT(e,t,n){let r=document.querySelector(`#${e}`),i=document.querySelector(`[data-copy="${e}"]`);r.value=t,r.placeholder=t?``:n,i.disabled=!t}async function gT(){if(Kw)return!1;lT(!1);let e=sT();if(Q.aliasId&&!Q.dirty)return $(`Already saved`),!0;Kw=!0,IT();try{if(Q.aliasId&&Q.writeCapability)return FT(Q.mode===`locked`?await Hw.updateLockedAlias(Q.aliasId,await vT(e),Q.revision,Q.writeCapability):await Hw.updateAlias(Q.aliasId,e,Q.revision,Q.writeCapability),Q.writeCapability,e,Q.mode===`locked`?Q.bundleKey:null),MT(`${zw}${Q.aliasId}`),await yT(e),$(`Saved`),!0;let t=!!Q.aliasId;return await _T(e),$(t?`Saved as a new diagram`:`Saved`),!0}catch(t){return t instanceof wC&&t.status===412&&Q.aliasId?await ET(e):($(t instanceof Error?t.message:`Could not save this diagram.`),!1)}finally{Kw=!1,IT()}}async function _T(e){let t=Q.aliasId,n=t?`${zw}${t}`:Rw,r=Q.bundleKey,i=Q.mode===`locked`?await Hw.createLockedAlias(await vT(e)):await Hw.createAlias(e);FT(i,i.writeCapability,e,Q.mode===`locked`?r:null),NT(i.aliasId,i.writeCapability),MT(n),history.pushState(null,``,`/d/${i.aliasId}`),await yT(e)}async function vT(e){if(!(Q.bundleKey instanceof Uint8Array)||!Q.keyEnvelope)throw Error(`This diagram is missing its browser encryption key.`);return Q.savedMode===`locked`&&Q.savedSnapshot===OT(e,`locked`)&&Q.encryptedContent&&Q.encryptedMetadata?{mode:`locked`,encryptedContent:Q.encryptedContent,encryptedMetadata:Q.encryptedMetadata,keyEnvelope:Q.keyEnvelope}:qC(e,Q.bundleKey,Q.keyEnvelope)}async function yT(e){if(!Q.aliasId||!Q.writeCapability)return;await oT.render(e);let t=oT.svgBlobFor(e);if(!t)return;let n=[[`svg`,t]];try{n.push([`png`,await bT(t)])}catch{}let r=n.map(async([e,t])=>{let n=Q.mode===`locked`?await XC(t,Q.bundleKey,e):t;return Hw.uploadRender({aliasId:Q.aliasId,renderId:Q.renderId,revision:Q.revision,writeCapability:Q.writeCapability,format:e,mode:Q.mode,render:n})});(await Promise.allSettled(r)).every(e=>e.status===`rejected`)&&oT.setStatus(`Saved; render cache unavailable`,`ready`)}async function bT(e){let t=URL.createObjectURL(e);try{let e=new Image;e.src=t,await e.decode();let n=Math.min(1,4096/Math.max(e.naturalWidth,e.naturalHeight)),r=Math.max(1,Math.round(e.naturalWidth*n)),i=Math.max(1,Math.round(e.naturalHeight*n)),a=document.createElement(`canvas`);a.width=r,a.height=i;let o=a.getContext(`2d`);if(!o)throw Error(`Canvas is unavailable.`);o.drawImage(e,0,0,r,i);let s=await new Promise(e=>a.toBlob(e,`image/png`));if(!s)throw Error(`Could not create a PNG render.`);return s}finally{URL.revokeObjectURL(t)}}async function xT(){let e=await TT({title:`Lock diagram`,copy:`The source, metadata, and saved render will be encrypted in this browser. The password cannot be recovered.`,submitLabel:`Lock diagram`,confirm:!0});if(e!==null)try{let{bundleKey:t,payload:n}=await JC(sT(),e);Q.mode=`locked`,Q.bundleKey=t,Q.keyEnvelope=n.keyEnvelope,Q.encryptedContent=n.encryptedContent,Q.encryptedMetadata=n.encryptedMetadata,Q.keyEnvelopeDirty=!0,MT(Q.aliasId?`${zw}${Q.aliasId}`:Rw),lT(!1),$(`Locked in this browser — save to persist`)}catch(e){$(e instanceof Error?e.message:`Could not lock this diagram.`)}}async function ST(){if(Q.mode!==`locked`||!(Q.bundleKey instanceof Uint8Array))return;let e=await TT({title:`Change password`,copy:`Only the encrypted bundle key will be rewrapped. The diagram content does not need to be re-encrypted.`,submitLabel:`Change password`,confirm:!0});if(e!==null)try{Q.keyEnvelope=await GC(Q.bundleKey,e),Q.keyEnvelopeDirty=!0,lT(!1),$(`Password changed — save to persist`)}catch(e){$(e instanceof Error?e.message:`Could not change the password.`)}}function CT(){Q.mode===`locked`&&confirm(`Remove password protection? The next save will store the diagram in plaintext.`)&&(Q.mode=`open`,Q.keyEnvelopeDirty=!1,lT(!1),$(`Password removed — save to persist`))}async function wT(e){for(;;){let t=await TT({title:`Unlock diagram`,copy:`Decryption happens only in this browser. The password is never sent to diagram.zip.`,submitLabel:`Unlock`,confirm:!1});if(t===null)return null;try{return await YC(e,t)}catch(e){$(e instanceof Error?e.message:`Could not unlock this diagram.`)}}}function TT({title:e,copy:t,submitLabel:n,confirm:r}){let i=document.querySelector(`#password-dialog`),a=document.querySelector(`#password-form`),o=document.querySelector(`#diagram-password`),s=document.querySelector(`#diagram-password-confirm`),c=document.querySelector(`#password-confirm-field`),l=document.querySelector(`#password-error`);return document.querySelector(`#password-title`).textContent=e,document.querySelector(`#password-copy`).textContent=t,document.querySelector(`#password-submit`).textContent=n,c.hidden=!r,o.autocomplete=r?`new-password`:`current-password`,o.value=``,s.value=``,l.textContent=``,new Promise(e=>{let t=!1,n=n=>{t||(t=!0,a.removeEventListener(`submit`,c),document.querySelector(`#password-cancel`).removeEventListener(`click`,u),i.removeEventListener(`cancel`,u),i.removeEventListener(`close`,d),e(n))},c=e=>{e.preventDefault();let t=o.value;if(r&&t.length<8){l.textContent=`Use at least 8 characters.`,o.focus();return}if(r&&t!==s.value){l.textContent=`The passwords do not match.`,s.focus();return}i.close(),n(t)},u=e=>{e.preventDefault(),i.close(),n(null)},d=()=>n(null);a.addEventListener(`submit`,c),document.querySelector(`#password-cancel`).addEventListener(`click`,u),i.addEventListener(`cancel`,u),i.addEventListener(`close`,d),i.showModal(),o.focus()})}async function ET(e){let t=await DT();if(t===`reload`){let e=Q.aliasId,t=Q.writeCapability;try{let n=await Hw.getAlias(e),r=n.state,i=null;if(n.mode===`locked`){let e=await wT(n);if(!e)return!1;r=e.state,i=e.bundleKey}return FT(n,t,r,i),MT(`${zw}${e}`),fT(r,!1),IT(),$(`Reloaded saved diagram`),!0}catch(e){return $(e instanceof Error?e.message:`Could not reload this diagram.`),!1}}return t===`copy`&&(await _T(e),$(`Saved as a new diagram`),!0)}function DT(){let e=document.querySelector(`#conflict-dialog`);return e.returnValue=``,e.showModal(),new Promise(t=>{e.addEventListener(`close`,()=>t(e.returnValue),{once:!0})})}function OT(e,t=`open`){return JSON.stringify({mode:t,type:e.type,source:e.source,options:e.options??{},meta:sC(e.meta),presentation:cC(e.presentation)})}function kT(e){if(!e||typeof e!=`object`||!bx(e.type)||typeof e.source!=`string`)return null;try{return{type:e.type,source:e.source,options:e.options??{},meta:sC(e.meta),presentation:cC(e.presentation)}}catch{return null}}function AT(e){try{let t=JSON.parse(localStorage.getItem(e)),n=kT(t?.state);return n?{state:n,revision:t.revision??null}:null}catch{return null}}function jT(e){if(Q.mode===`locked`)return;let t=Q.aliasId?`${zw}${Q.aliasId}`:Rw;try{localStorage.setItem(t,JSON.stringify({state:e,revision:Q.revision}))}catch{}}function MT(e){try{localStorage.removeItem(e)}catch{}}function NT(e,t){try{localStorage.setItem(`${Bw}${e}`,t)}catch{}}function PT(e){try{return CC(`#w=${localStorage.getItem(`${Bw}${e}`)??``}`)}catch{return null}}function FT(e,t,n,r=null){Q={aliasId:e.aliasId,contentId:e.contentId,renderId:e.renderId,revision:e.revision,mode:e.mode,savedMode:e.mode,writeCapability:t,savedState:n,savedSnapshot:OT(n,e.mode),bundleKey:r,keyEnvelope:e.mode===`locked`?e.keyEnvelope:null,encryptedContent:e.mode===`locked`?e.encryptedContent:null,encryptedMetadata:e.mode===`locked`?e.encryptedMetadata:null,keyEnvelopeDirty:!1,dirty:!1},LT(),IT()}function IT(){let e=document.querySelector(`#save`);if(Kw){e.textContent=`Saving…`,e.disabled=!0;return}if(Q.aliasId&&!Q.dirty){e.textContent=`Saved`,e.disabled=!0;return}e.textContent=Q.aliasId&&!Q.writeCapability?`Save copy`:`Save`,e.disabled=!1}function LT(){let e=Q.mode===`locked`;document.querySelector(`#privacy-label`).textContent=e?`Password locked`:`Open`,document.querySelector(`#privacy-description`).textContent=e?`Source, metadata, and saved renders are encrypted in your browser. Password-locked diagrams cannot be embedded.`:`Anyone with the read link can open and embed this diagram.`,document.querySelector(`#lock-diagram`).hidden=e,document.querySelector(`#change-password`).hidden=!e,document.querySelector(`#unlock-diagram`).hidden=!e}function RT(){Q={aliasId:null,contentId:null,renderId:null,revision:null,mode:`open`,savedMode:null,writeCapability:null,savedState:null,savedSnapshot:null,bundleKey:null,keyEnvelope:null,encryptedContent:null,encryptedMetadata:null,keyEnvelopeDirty:!1,dirty:!0},Jw.clear(),history.pushState(null,``,`/`),fT(fC(aC))}function zT(){let e=Xw.value.trim(),t=Zw.value.trim();document.title=e?`${e} — diagram.zip`:`diagram.zip`,document.querySelector(`meta[name="description"]`).content=t||`Create diagrams from text and share them as a link.`}async function BT(e){if(navigator.clipboard)return navigator.clipboard.writeText(e);let t=document.createElement(`textarea`);t.value=e,document.body.append(t),t.select(),document.execCommand(`copy`),t.remove()}function $(e){let t=document.querySelector(`#toast`);t.textContent=e,t.dataset.visible=`true`,clearTimeout($.timeout),$.timeout=setTimeout(()=>delete t.dataset.visible,1800)}lT(),qw&&$(qw);\ No newline at end of file@@ -7,7 +7,7 @@
77 <meta name="description" content="Create diagrams from text and share them as a link.">88 <link rel="icon" href="/diagram.zip/icon.svg" type="image/svg+xml">99 <title>diagram.zip</title>10- <script type="module" crossorigin src="/diagram.zip/assets/index-HTr30hpP.js"></script>10+ <script type="module" crossorigin src="/diagram.zip/assets/index-Di0z2pwl.js"></script>1111 <link rel="stylesheet" crossorigin href="/diagram.zip/assets/index-B2XsKz37.css">1212 </head>1313 <body>