@tldraw/tlschema 5.4.0-next.ef99ab47e5ce → 5.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/misc/b64Vecs.ts"],
4
- "sourcesContent": ["import { VecModel } from './geometry-types'\n\n// Each point = 3 Float16s = 6 bytes = 8 base64 chars (legacy format)\nconst _POINT_B64_LENGTH = 8\n\n// First point in delta encoding = 3 Float32s = 12 bytes = 16 base64 chars\nconst FIRST_POINT_B64_LENGTH = 16\n\n// First point in 2D delta encoding = 2 Float32s = 8 bytes = 12 base64 chars (incl. padding)\nconst FIRST_POINT_2D_B64_LENGTH = 12\n\n// Pressure value supplied when decoding non-pressure (2D) paths\nconst DEFAULT_PRESSURE = 0.5\n\n/** Draw segment path encoded with 2 dimensions, XY \u2014 the constant pressure Z is dropped. @public */\nexport const DIM_2D = 2\n/** Draw segment path encoded with 3 dimensions, XYZ. @public */\nexport const DIM_3D = 3\n\n// O(1) lookup table for base64 decoding (maps char code -> 6-bit value)\nconst BASE64_CHARS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'\nconst B64_LOOKUP = new Uint8Array(128)\nfor (let i = 0; i < 64; i++) {\n\tB64_LOOKUP[BASE64_CHARS.charCodeAt(i)] = i\n}\n\n// Mask for one base64 sextet: the low 6 bits select an index into BASE64_CHARS (0\u201363).\nconst SIX_BIT_MASK = 0x3f\n// '=' padding character, appended on encode so the output length is a multiple of 4.\nconst PADDING_CHAR_CODE = '='.charCodeAt(0)\n\n// Precomputed powers of 2 for Float16 exponents (exp - 15, so indices 0-30 map to 2^-15 to 2^15)\nconst POW2 = new Float64Array(31)\nfor (let i = 0; i < 31; i++) {\n\tPOW2[i] = Math.pow(2, i - 15)\n}\nconst POW2_SUBNORMAL = Math.pow(2, -14) / 1024 // For subnormal numbers\n\n// Precomputed mantissa values: 1 + frac/1024 for all 1024 possible frac values\n// Avoids division in hot path\nconst MANTISSA = new Float64Array(1024)\nfor (let i = 0; i < 1024; i++) {\n\tMANTISSA[i] = 1 + i / 1024\n}\n\ndeclare global {\n\tinterface Uint8Array {\n\t\ttoBase64?(): string\n\t}\n\tinterface Uint8ArrayConstructor {\n\t\tfromBase64?(base64: string): Uint8Array\n\t}\n}\n\nfunction nativeGetFloat16(dataView: DataView, offset: number): number {\n\treturn (dataView as any).getFloat16(offset, true)\n}\nfunction fallbackGetFloat16(dataView: DataView, offset: number): number {\n\treturn float16BitsToNumber(dataView.getUint16(offset, true))\n}\n\nconst getFloat16 =\n\ttypeof (DataView.prototype as any).getFloat16 === 'function'\n\t\t? nativeGetFloat16\n\t\t: fallbackGetFloat16\n\nfunction nativeSetFloat16(dataView: DataView, offset: number, value: number): void {\n\t;(dataView as any).setFloat16(offset, value, true)\n}\nfunction fallbackSetFloat16(dataView: DataView, offset: number, value: number): void {\n\tdataView.setUint16(offset, numberToFloat16Bits(value), true)\n}\n\nconst setFloat16 =\n\ttypeof (DataView.prototype as any).setFloat16 === 'function'\n\t\t? nativeSetFloat16\n\t\t: fallbackSetFloat16\n\nfunction nativeBase64ToUint8Array(base64: string): Uint8Array {\n\treturn Uint8Array.fromBase64!(base64)\n}\n\n/** @internal */\nexport function fallbackBase64ToUint8Array(base64: string): Uint8Array {\n\t// Strip up to 2 '=' padding characters to determine the real byte count.\n\t// The 2D point layout (8 + 4(n-1) bytes) is not a multiple of 3, so encoded\n\t// paths can carry padding the original multiple-of-3-only decoder couldn't read.\n\tconst paddedLength = base64.length\n\tlet padding = 0\n\tif (paddedLength > 0 && base64.charCodeAt(paddedLength - 1) === PADDING_CHAR_CODE) {\n\t\tpadding++\n\t\tif (paddedLength > 1 && base64.charCodeAt(paddedLength - 2) === PADDING_CHAR_CODE) {\n\t\t\tpadding++\n\t\t}\n\t}\n\tconst numBytes = Math.floor((paddedLength * 3) / 4) - padding\n\tconst bytes = new Uint8Array(numBytes)\n\tlet byteIndex = 0\n\n\t// The reverse of encoding: each 4 chars are 4 six-bit values that pack back into\n\t// one 24-bit number, which we then read out as 3 bytes (& 255 keeps one byte).\n\tconst fullGroups = Math.floor((paddedLength - padding) / 4) * 4\n\tfor (let i = 0; i < fullGroups; i += 4) {\n\t\tconst c0 = B64_LOOKUP[base64.charCodeAt(i)]\n\t\tconst c1 = B64_LOOKUP[base64.charCodeAt(i + 1)]\n\t\tconst c2 = B64_LOOKUP[base64.charCodeAt(i + 2)]\n\t\tconst c3 = B64_LOOKUP[base64.charCodeAt(i + 3)]\n\n\t\tconst bitmap = (c0 << 18) | (c1 << 12) | (c2 << 6) | c3\n\n\t\tbytes[byteIndex++] = (bitmap >> 16) & 255 // top byte (bits 23\u201316)\n\t\tbytes[byteIndex++] = (bitmap >> 8) & 255 // middle byte (bits 15\u20138)\n\t\tbytes[byteIndex++] = bitmap & 255 // bottom byte (bits 7\u20130)\n\t}\n\n\t// Final group when padded: 3 valid chars -> 2 bytes, 2 valid chars -> 1 byte.\n\tif (padding === 1) {\n\t\tconst c0 = B64_LOOKUP[base64.charCodeAt(fullGroups)]\n\t\tconst c1 = B64_LOOKUP[base64.charCodeAt(fullGroups + 1)]\n\t\tconst c2 = B64_LOOKUP[base64.charCodeAt(fullGroups + 2)]\n\t\tconst bitmap = (c0 << 18) | (c1 << 12) | (c2 << 6)\n\t\tbytes[byteIndex++] = (bitmap >> 16) & 255\n\t\tbytes[byteIndex++] = (bitmap >> 8) & 255\n\t} else if (padding === 2) {\n\t\tconst c0 = B64_LOOKUP[base64.charCodeAt(fullGroups)]\n\t\tconst c1 = B64_LOOKUP[base64.charCodeAt(fullGroups + 1)]\n\t\tconst bitmap = (c0 << 18) | (c1 << 12)\n\t\tbytes[byteIndex++] = (bitmap >> 16) & 255\n\t}\n\n\treturn bytes\n}\n\nfunction nativeUint8ArrayToBase64(uint8Array: Uint8Array): string {\n\treturn uint8Array.toBase64!()\n}\n\n/** @internal */\nexport function fallbackUint8ArrayToBase64(uint8Array: Uint8Array): string {\n\tconst len = uint8Array.length\n\tconst fullGroups = Math.floor(len / 3) * 3\n\tlet result = ''\n\n\t// base64 represents 3 bytes (24 bits) as 4 characters of 6 bits each. For each\n\t// group of 3 bytes we pack them into one 24-bit number, then read it back out as\n\t// four 6-bit slices and use each slice (a value 0\u201363) to index into the 64-char\n\t// alphabet. `>> n` shifts the wanted slice down to the bottom; SIX_BIT_MASK then\n\t// discards everything above those 6 bits.\n\tfor (let i = 0; i < fullGroups; i += 3) {\n\t\tconst byte1 = uint8Array[i]\n\t\tconst byte2 = uint8Array[i + 1]\n\t\tconst byte3 = uint8Array[i + 2]\n\n\t\tconst bitmap = (byte1 << 16) | (byte2 << 8) | byte3\n\t\tresult +=\n\t\t\tBASE64_CHARS[(bitmap >> 18) & SIX_BIT_MASK] + // bits 23\u201318 (top sextet)\n\t\t\tBASE64_CHARS[(bitmap >> 12) & SIX_BIT_MASK] + // bits 17\u201312\n\t\t\tBASE64_CHARS[(bitmap >> 6) & SIX_BIT_MASK] + // bits 11\u20136\n\t\t\tBASE64_CHARS[bitmap & SIX_BIT_MASK] // bits 5\u20130 (bottom sextet)\n\t}\n\n\t// A trailing 1 or 2 bytes can't fill a whole 4-char group, so we emit only the\n\t// chars their bits cover and pad the rest with '=' to keep the length a multiple\n\t// of 4. Standard base64 \u2014 matches the native API and Node's Buffer, so a path\n\t// encoded by the fallback round-trips on a runtime that decodes with the native one.\n\tconst remaining = len - fullGroups\n\tif (remaining === 1) {\n\t\t// 8 bits \u2192 2 sextets (the 2nd only partly filled), then \"==\"\n\t\tconst bitmap = uint8Array[fullGroups] << 16\n\t\tresult +=\n\t\t\tBASE64_CHARS[(bitmap >> 18) & SIX_BIT_MASK] +\n\t\t\tBASE64_CHARS[(bitmap >> 12) & SIX_BIT_MASK] +\n\t\t\t'=='\n\t} else if (remaining === 2) {\n\t\t// 16 bits \u2192 3 sextets (the 3rd only partly filled), then \"=\"\n\t\tconst bitmap = (uint8Array[fullGroups] << 16) | (uint8Array[fullGroups + 1] << 8)\n\t\tresult +=\n\t\t\tBASE64_CHARS[(bitmap >> 18) & SIX_BIT_MASK] +\n\t\t\tBASE64_CHARS[(bitmap >> 12) & SIX_BIT_MASK] +\n\t\t\tBASE64_CHARS[(bitmap >> 6) & SIX_BIT_MASK] +\n\t\t\t'='\n\t}\n\n\treturn result\n}\n\n/**\n * Convert a Uint8Array to base64.\n * Processes bytes in groups of 3 to produce 4 base64 characters.\n *\n * @internal\n */\nconst uint8ArrayToBase64 =\n\ttypeof Uint8Array.prototype.toBase64 === 'function'\n\t\t? nativeUint8ArrayToBase64\n\t\t: fallbackUint8ArrayToBase64\n\n/**\n * Convert a base64 string to Uint8Array.\n *\n * @internal\n */\nconst base64ToUint8Array =\n\ttypeof Uint8Array.fromBase64 === 'function'\n\t\t? nativeBase64ToUint8Array\n\t\t: fallbackBase64ToUint8Array\n\n/**\n * Convert Float16 bits to a number using optimized lookup tables.\n * Handles normal numbers, subnormal numbers, zero, infinity, and NaN.\n *\n * @param bits - The 16-bit Float16 value to decode\n * @returns The decoded number value\n * @internal\n */\nexport function float16BitsToNumber(bits: number): number {\n\tconst sign = bits >> 15\n\tconst exp = (bits >> 10) & 0x1f\n\tconst frac = bits & 0x3ff\n\n\tif (exp === 0) {\n\t\t// Subnormal or zero - rare case\n\t\treturn sign ? -frac * POW2_SUBNORMAL : frac * POW2_SUBNORMAL\n\t}\n\tif (exp === 31) {\n\t\t// Infinity or NaN - very rare\n\t\treturn frac ? NaN : sign ? -Infinity : Infinity\n\t}\n\t// Normal case - two table lookups, one multiply, no division\n\tconst magnitude = POW2[exp] * MANTISSA[frac]\n\treturn sign ? -magnitude : magnitude\n}\n\n/**\n * Convert a number to Float16 bits.\n * Handles normal numbers, subnormal numbers, zero, infinity, and NaN.\n *\n * @param value - The number to encode as Float16\n * @returns The 16-bit Float16 representation of the number\n * @internal\n */\nexport function numberToFloat16Bits(value: number): number {\n\tif (value === 0) return Object.is(value, -0) ? 0x8000 : 0\n\tif (!Number.isFinite(value)) {\n\t\tif (Number.isNaN(value)) return 0x7e00\n\t\treturn value > 0 ? 0x7c00 : 0xfc00\n\t}\n\n\tconst sign = value < 0 ? 1 : 0\n\tvalue = Math.abs(value)\n\n\t// Find exponent and mantissa\n\tconst exp = Math.floor(Math.log2(value))\n\tlet expBiased = exp + 15\n\n\tif (expBiased >= 31) {\n\t\t// Overflow to infinity\n\t\treturn (sign << 15) | 0x7c00\n\t}\n\tif (expBiased <= 0) {\n\t\t// Subnormal or underflow\n\t\tconst frac = Math.round(value * Math.pow(2, 14) * 1024)\n\t\treturn (sign << 15) | (frac & 0x3ff)\n\t}\n\n\t// Normal number\n\tconst mantissa = value / Math.pow(2, exp) - 1\n\tlet frac = Math.round(mantissa * 1024)\n\n\t// Handle rounding overflow: if frac rounds to 1024, increment exponent\n\tif (frac >= 1024) {\n\t\tfrac = 0\n\t\texpBiased++\n\t\tif (expBiased >= 31) {\n\t\t\t// Overflow to infinity\n\t\t\treturn (sign << 15) | 0x7c00\n\t\t}\n\t}\n\n\treturn (sign << 15) | (expBiased << 10) | frac\n}\n\n/**\n * Utilities for encoding and decoding points using base64 and Float16 encoding.\n * Provides functions for converting between VecModel arrays and compact base64 strings,\n * as well as individual point encoding/decoding operations.\n *\n * @public\n */\nexport class b64Vecs {\n\t/**\n\t * Encode a single point (x, y, z) to 8 base64 characters using legacy Float16 encoding.\n\t * Each coordinate is encoded as a Float16 value, resulting in 6 bytes total.\n\t *\n\t * @param x - The x coordinate\n\t * @param y - The y coordinate\n\t * @param z - The z coordinate\n\t * @returns An 8-character base64 string representing the point\n\t * @internal\n\t */\n\tstatic _legacyEncodePoint(x: number, y: number, z: number): string {\n\t\tconst buffer = new Uint8Array(6)\n\t\tconst dataView = new DataView(buffer.buffer)\n\n\t\tsetFloat16(dataView, 0, x)\n\t\tsetFloat16(dataView, 2, y)\n\t\tsetFloat16(dataView, 4, z)\n\n\t\treturn uint8ArrayToBase64(buffer)\n\t}\n\n\t/**\n\t * Convert an array of VecModels to a base64 string using legacy Float16 encoding.\n\t * Uses Float16 encoding for each coordinate (x, y, z). If a point's z value is\n\t * undefined, it defaults to 0.5.\n\t *\n\t * @param points - An array of VecModel objects to encode\n\t * @returns A base64-encoded string containing all points\n\t * @internal Used only for migrations from legacy format\n\t */\n\tstatic _legacyEncodePoints(points: VecModel[]): string {\n\t\tif (points.length === 0) return ''\n\n\t\t// 3 Float16s per point = 6 bytes per point\n\t\tconst buffer = new Uint8Array(points.length * 6)\n\t\tconst dataView = new DataView(buffer.buffer)\n\n\t\tfor (let i = 0; i < points.length; i++) {\n\t\t\tconst p = points[i]\n\t\t\tconst offset = i * 6\n\t\t\tsetFloat16(dataView, offset, p.x)\n\t\t\tsetFloat16(dataView, offset + 2, p.y)\n\t\t\tsetFloat16(dataView, offset + 4, p.z ?? 0.5)\n\t\t}\n\n\t\treturn uint8ArrayToBase64(buffer)\n\t}\n\n\t/**\n\t * Convert a legacy base64 string back to an array of VecModels.\n\t * Decodes Float16-encoded coordinates (x, y, z) from the base64 string.\n\t *\n\t * @param base64 - The base64-encoded string containing point data\n\t * @returns An array of VecModel objects decoded from the string\n\t * @internal Used only for migrations from legacy format\n\t */\n\tstatic _legacyDecodePoints(base64: string): VecModel[] {\n\t\tconst bytes = base64ToUint8Array(base64)\n\t\tconst dataView = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength)\n\t\tconst result: VecModel[] = []\n\t\tfor (let offset = 0; offset < bytes.length; offset += 6) {\n\t\t\tresult.push({\n\t\t\t\tx: getFloat16(dataView, offset),\n\t\t\t\ty: getFloat16(dataView, offset + 2),\n\t\t\t\tz: getFloat16(dataView, offset + 4),\n\t\t\t})\n\t\t}\n\t\treturn result\n\t}\n\n\t/**\n\t * Encode an array of VecModels using delta encoding for improved precision.\n\t * The first point is stored as Float32 (high precision for absolute position),\n\t * subsequent points are stored as Float16 deltas from the previous point.\n\t * This provides full precision for the starting position and excellent precision\n\t * for deltas between consecutive points (which are typically small values).\n\t *\n\t * Format:\n\t * - First point: 3 Float32 values = 12 bytes = 16 base64 chars\n\t * - Delta points: 3 Float16 values each = 6 bytes = 8 base64 chars each\n\t *\n\t * @param points - An array of VecModel objects to encode\n\t * @param dim - Encoding dimension; `2` routes through the 2D variant (drops z), `3` (default) keeps x, y, z\n\t * @returns A base64-encoded string containing delta-encoded points\n\t * @public\n\t */\n\tstatic encodePoints(points: VecModel[], dim?: 2 | 3): string {\n\t\tif (dim === DIM_2D) return b64Vecs.encodePoints2D(points)\n\t\tif (points.length === 0) return ''\n\n\t\t// First point: 3 Float32s = 12 bytes\n\t\t// Remaining points: 3 Float16s each = 6 bytes each\n\t\tconst firstPointBytes = 12\n\t\tconst deltaBytes = (points.length - 1) * 6\n\t\tconst totalBytes = firstPointBytes + deltaBytes\n\n\t\tconst buffer = new Uint8Array(totalBytes)\n\t\tconst dataView = new DataView(buffer.buffer)\n\n\t\t// First point is stored as Float32 for full precision\n\t\tconst first = points[0]\n\t\tdataView.setFloat32(0, first.x, true) // little-endian\n\t\tdataView.setFloat32(4, first.y, true)\n\t\tdataView.setFloat32(8, first.z ?? 0.5, true)\n\n\t\t// Subsequent points are Float16 deltas from the previous point\n\t\tlet prevX = first.x\n\t\tlet prevY = first.y\n\t\tlet prevZ = first.z ?? 0.5\n\n\t\tfor (let i = 1; i < points.length; i++) {\n\t\t\tconst p = points[i]\n\t\t\tconst z = p.z ?? 0.5\n\n\t\t\tconst offset = firstPointBytes + (i - 1) * 6\n\t\t\tsetFloat16(dataView, offset, p.x - prevX)\n\t\t\tsetFloat16(dataView, offset + 2, p.y - prevY)\n\t\t\tsetFloat16(dataView, offset + 4, z - prevZ)\n\n\t\t\tprevX = p.x\n\t\t\tprevY = p.y\n\t\t\tprevZ = z\n\t\t}\n\n\t\treturn uint8ArrayToBase64(buffer)\n\t}\n\n\t/**\n\t * Decode a delta-encoded base64 string back to an array of absolute VecModels.\n\t * The first point is stored as Float32 (high precision), subsequent points are\n\t * Float16 deltas that are accumulated to reconstruct absolute positions.\n\t *\n\t * @param base64 - The base64-encoded string containing delta-encoded point data\n\t * @param dim - Encoding dimension; `2` expects x/y only (z supplied as 0.5), `3` (default) expects x/y/z\n\t * @returns An array of VecModel objects with absolute coordinates\n\t * @public\n\t */\n\tstatic decodePoints(base64: string, dim?: 2 | 3): VecModel[] {\n\t\tif (dim === DIM_2D) return b64Vecs.decodePoints2D(base64)\n\t\tif (base64.length === 0) return []\n\n\t\tconst bytes = base64ToUint8Array(base64)\n\t\tconst dataView = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength)\n\t\tconst result: VecModel[] = []\n\n\t\t// First point is Float32 (12 bytes)\n\t\tlet x = dataView.getFloat32(0, true)\n\t\tlet y = dataView.getFloat32(4, true)\n\t\tlet z = dataView.getFloat32(8, true)\n\t\tresult.push({ x, y, z })\n\n\t\t// Subsequent points are Float16 deltas - accumulate to get absolute positions\n\t\tconst firstPointBytes = 12\n\t\tfor (let offset = firstPointBytes; offset < bytes.length; offset += 6) {\n\t\t\tx += getFloat16(dataView, offset)\n\t\t\ty += getFloat16(dataView, offset + 2)\n\t\t\tz += getFloat16(dataView, offset + 4)\n\t\t\tresult.push({ x, y, z })\n\t\t}\n\n\t\treturn result\n\t}\n\n\t/**\n\t * Get the first point from a delta-encoded base64 string.\n\t * The first point is stored as Float32 for full precision.\n\t *\n\t * @param b64Points - The delta-encoded base64 string\n\t * @param dim - Encoding dimension; `2` expects x/y only (z supplied as 0.5), `3` (default) expects x/y/z\n\t * @returns The first point as a VecModel, or null if the string is too short\n\t * @public\n\t */\n\tstatic decodeFirstPoint(b64Points: string, dim?: 2 | 3): VecModel | null {\n\t\tif (dim === DIM_2D) return b64Vecs.decodeFirstPoint2D(b64Points)\n\t\t// First point needs 16 base64 chars (12 bytes as Float32)\n\t\tif (b64Points.length < FIRST_POINT_B64_LENGTH) return null\n\n\t\tconst bytes = base64ToUint8Array(b64Points.slice(0, FIRST_POINT_B64_LENGTH))\n\t\tconst dataView = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength)\n\n\t\treturn {\n\t\t\tx: dataView.getFloat32(0, true),\n\t\t\ty: dataView.getFloat32(4, true),\n\t\t\tz: dataView.getFloat32(8, true),\n\t\t}\n\t}\n\n\t/**\n\t * Get the last point from a delta-encoded base64 string.\n\t * Requires decoding all points to accumulate deltas.\n\t *\n\t * @param b64Points - The delta-encoded base64 string\n\t * @param dim - Encoding dimension; `2` expects x/y only (z supplied as 0.5), `3` (default) expects x/y/z\n\t * @returns The last point as a VecModel, or null if the string is too short\n\t * @public\n\t */\n\tstatic decodeLastPoint(b64Points: string, dim?: 2 | 3): VecModel | null {\n\t\tif (dim === DIM_2D) return b64Vecs.decodeLastPoint2D(b64Points)\n\t\tif (b64Points.length < FIRST_POINT_B64_LENGTH) return null\n\n\t\tconst bytes = base64ToUint8Array(b64Points)\n\t\tconst dataView = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength)\n\n\t\t// Start with first point (Float32)\n\t\tlet x = dataView.getFloat32(0, true)\n\t\tlet y = dataView.getFloat32(4, true)\n\t\tlet z = dataView.getFloat32(8, true)\n\n\t\t// Accumulate all Float16 deltas to get the last point\n\t\tconst firstPointBytes = 12\n\t\tfor (let offset = firstPointBytes; offset < bytes.length; offset += 6) {\n\t\t\tx += getFloat16(dataView, offset)\n\t\t\ty += getFloat16(dataView, offset + 2)\n\t\t\tz += getFloat16(dataView, offset + 4)\n\t\t}\n\n\t\treturn { x, y, z }\n\t}\n\n\t/**\n\t * Encode an array of VecModels as 2D delta-encoded points, dropping z entirely.\n\t * Use for draw shapes from devices that don't report pressure, where z is a\n\t * constant 0.5 and storing it wastes ~33% of per-point bytes.\n\t *\n\t * Format:\n\t * - First point: 2 Float32 values (x, y) = 8 bytes\n\t * - Delta points: 2 Float16 values (dx, dy) = 4 bytes each\n\t *\n\t * @param points - An array of VecModel objects to encode (z is discarded)\n\t * @returns A base64-encoded string containing 2D delta-encoded points\n\t * @public\n\t */\n\tstatic encodePoints2D(points: VecModel[]): string {\n\t\tif (points.length === 0) return ''\n\n\t\tconst firstPointBytes = 8\n\t\tconst deltaBytes = (points.length - 1) * 4\n\t\tconst buffer = new Uint8Array(firstPointBytes + deltaBytes)\n\t\tconst dataView = new DataView(buffer.buffer)\n\n\t\tconst first = points[0]\n\t\tdataView.setFloat32(0, first.x, true)\n\t\tdataView.setFloat32(4, first.y, true)\n\n\t\tlet prevX = first.x\n\t\tlet prevY = first.y\n\n\t\tfor (let i = 1; i < points.length; i++) {\n\t\t\tconst p = points[i]\n\t\t\tconst offset = firstPointBytes + (i - 1) * 4\n\t\t\tsetFloat16(dataView, offset, p.x - prevX)\n\t\t\tsetFloat16(dataView, offset + 2, p.y - prevY)\n\t\t\tprevX = p.x\n\t\t\tprevY = p.y\n\t\t}\n\n\t\treturn uint8ArrayToBase64(buffer)\n\t}\n\n\t/**\n\t * Decode a 2D delta-encoded base64 string back to an array of absolute VecModels.\n\t * The z coordinate is always set to 0.5 (the default pressure value) so downstream\n\t * consumers don't need a separate code path.\n\t *\n\t * @param base64 - The base64-encoded string containing 2D delta-encoded point data\n\t * @returns An array of VecModel objects with absolute (x, y) and z = 0.5\n\t * @public\n\t */\n\tstatic decodePoints2D(base64: string): VecModel[] {\n\t\tif (base64.length === 0) return []\n\n\t\tconst bytes = base64ToUint8Array(base64)\n\t\tconst dataView = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength)\n\t\tconst result: VecModel[] = []\n\n\t\tlet x = dataView.getFloat32(0, true)\n\t\tlet y = dataView.getFloat32(4, true)\n\t\tresult.push({ x, y, z: DEFAULT_PRESSURE })\n\n\t\tconst firstPointBytes = 8\n\t\tfor (let offset = firstPointBytes; offset < bytes.length; offset += 4) {\n\t\t\tx += getFloat16(dataView, offset)\n\t\t\ty += getFloat16(dataView, offset + 2)\n\t\t\tresult.push({ x, y, z: DEFAULT_PRESSURE })\n\t\t}\n\n\t\treturn result\n\t}\n\n\t/**\n\t * Get the first point from a 2D delta-encoded base64 string.\n\t *\n\t * @param b64Points - The 2D delta-encoded base64 string\n\t * @returns The first point with z = 0.5, or null if the string is too short\n\t * @public\n\t */\n\tstatic decodeFirstPoint2D(b64Points: string): VecModel | null {\n\t\tif (b64Points.length < FIRST_POINT_2D_B64_LENGTH) return null\n\n\t\tconst bytes = base64ToUint8Array(b64Points.slice(0, FIRST_POINT_2D_B64_LENGTH))\n\t\tconst dataView = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength)\n\n\t\treturn {\n\t\t\tx: dataView.getFloat32(0, true),\n\t\t\ty: dataView.getFloat32(4, true),\n\t\t\tz: DEFAULT_PRESSURE,\n\t\t}\n\t}\n\n\t/**\n\t * Get the last point from a 2D delta-encoded base64 string.\n\t * Requires decoding all points to accumulate deltas.\n\t *\n\t * @param b64Points - The 2D delta-encoded base64 string\n\t * @returns The last point with z = 0.5, or null if the string is too short\n\t * @public\n\t */\n\tstatic decodeLastPoint2D(b64Points: string): VecModel | null {\n\t\tif (b64Points.length < FIRST_POINT_2D_B64_LENGTH) return null\n\n\t\tconst bytes = base64ToUint8Array(b64Points)\n\t\tconst dataView = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength)\n\n\t\tlet x = dataView.getFloat32(0, true)\n\t\tlet y = dataView.getFloat32(4, true)\n\n\t\tconst firstPointBytes = 8\n\t\tfor (let offset = firstPointBytes; offset < bytes.length; offset += 4) {\n\t\t\tx += getFloat16(dataView, offset)\n\t\t\ty += getFloat16(dataView, offset + 2)\n\t\t}\n\n\t\treturn { x, y, z: DEFAULT_PRESSURE }\n\t}\n\n\t/**\n\t * Whether an encoded path contains only a single point (a \"dot\"), inferred from\n\t * the encoded length without decoding \u2014 cheap enough for the render path.\n\t *\n\t * The single-point length depends on the encoding dimension, so this takes the\n\t * segment's `dim`: a one-point path is `FIRST_POINT_B64_LENGTH` chars (3D) or\n\t * `FIRST_POINT_2D_B64_LENGTH` chars (2D). Keeping this beside the layout constants\n\t * is deliberate \u2014 it is the single source of truth for \"how long is one point\", so\n\t * callers never hard-code a length threshold (which silently breaks when a new\n\t * encoding is added).\n\t *\n\t * @param b64Points - The encoded path string\n\t * @param dim - Encoding dimension; `2` for (x, y), `3` (default) for (x, y, z)\n\t * @returns true if the path encodes exactly one point\n\t * @public\n\t */\n\tstatic isSinglePoint(b64Points: string, dim?: 2 | 3): boolean {\n\t\treturn b64Points.length <= (dim === DIM_2D ? FIRST_POINT_2D_B64_LENGTH : FIRST_POINT_B64_LENGTH)\n\t}\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { VecModel } from './geometry-types'\n\n// Each point = 3 Float16s = 6 bytes = 8 base64 chars (legacy format)\nconst _POINT_B64_LENGTH = 8\n\n// First point in delta encoding = 3 Float32s = 12 bytes = 16 base64 chars\nconst FIRST_POINT_B64_LENGTH = 16\n\n// First point in 2D delta encoding = 2 Float32s = 8 bytes = 12 base64 chars (incl. padding)\nconst FIRST_POINT_2D_B64_LENGTH = 12\n\n// Pressure value supplied when decoding non-pressure (2D) paths\nconst DEFAULT_PRESSURE = 0.5\n\n/** Draw segment path encoded with 2 dimensions, XY \u2014 the constant pressure Z is dropped. @public */\nexport const DIM_2D = 2\n/** Draw segment path encoded with 3 dimensions, XYZ. @public */\nexport const DIM_3D = 3\n\n// O(1) lookup table for base64 decoding (maps char code -> 6-bit value)\nconst BASE64_CHARS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'\nconst B64_LOOKUP = new Uint8Array(128)\nfor (let i = 0; i < 64; i++) {\n\tB64_LOOKUP[BASE64_CHARS.charCodeAt(i)] = i\n}\n\n// Mask for one base64 sextet: the low 6 bits select an index into BASE64_CHARS (0\u201363).\nconst SIX_BIT_MASK = 0x3f\n// '=' padding character, appended on encode so the output length is a multiple of 4.\nconst PADDING_CHAR_CODE = '='.charCodeAt(0)\n\n// Precomputed powers of 2 for Float16 exponents (exp - 15, so indices 0-30 map to 2^-15 to 2^15)\nconst POW2 = new Float64Array(31)\nfor (let i = 0; i < 31; i++) {\n\tPOW2[i] = Math.pow(2, i - 15)\n}\nconst POW2_SUBNORMAL = Math.pow(2, -14) / 1024 // For subnormal numbers\n\n// Precomputed mantissa values: 1 + frac/1024 for all 1024 possible frac values\n// Avoids division in hot path\nconst MANTISSA = new Float64Array(1024)\nfor (let i = 0; i < 1024; i++) {\n\tMANTISSA[i] = 1 + i / 1024\n}\n\nfunction nativeGetFloat16(dataView: DataView, offset: number): number {\n\treturn (dataView as any).getFloat16(offset, true)\n}\nfunction fallbackGetFloat16(dataView: DataView, offset: number): number {\n\treturn float16BitsToNumber(dataView.getUint16(offset, true))\n}\n\nconst getFloat16 =\n\ttypeof (DataView.prototype as any).getFloat16 === 'function'\n\t\t? nativeGetFloat16\n\t\t: fallbackGetFloat16\n\nfunction nativeSetFloat16(dataView: DataView, offset: number, value: number): void {\n\t;(dataView as any).setFloat16(offset, value, true)\n}\nfunction fallbackSetFloat16(dataView: DataView, offset: number, value: number): void {\n\tdataView.setUint16(offset, numberToFloat16Bits(value), true)\n}\n\nconst setFloat16 =\n\ttypeof (DataView.prototype as any).setFloat16 === 'function'\n\t\t? nativeSetFloat16\n\t\t: fallbackSetFloat16\n\nfunction nativeBase64ToUint8Array(base64: string): Uint8Array {\n\treturn Uint8Array.fromBase64(base64)\n}\n\n/** @internal */\nexport function fallbackBase64ToUint8Array(base64: string): Uint8Array {\n\t// Strip up to 2 '=' padding characters to determine the real byte count.\n\t// The 2D point layout (8 + 4(n-1) bytes) is not a multiple of 3, so encoded\n\t// paths can carry padding the original multiple-of-3-only decoder couldn't read.\n\tconst paddedLength = base64.length\n\tlet padding = 0\n\tif (paddedLength > 0 && base64.charCodeAt(paddedLength - 1) === PADDING_CHAR_CODE) {\n\t\tpadding++\n\t\tif (paddedLength > 1 && base64.charCodeAt(paddedLength - 2) === PADDING_CHAR_CODE) {\n\t\t\tpadding++\n\t\t}\n\t}\n\tconst numBytes = Math.floor((paddedLength * 3) / 4) - padding\n\tconst bytes = new Uint8Array(numBytes)\n\tlet byteIndex = 0\n\n\t// The reverse of encoding: each 4 chars are 4 six-bit values that pack back into\n\t// one 24-bit number, which we then read out as 3 bytes (& 255 keeps one byte).\n\tconst fullGroups = Math.floor((paddedLength - padding) / 4) * 4\n\tfor (let i = 0; i < fullGroups; i += 4) {\n\t\tconst c0 = B64_LOOKUP[base64.charCodeAt(i)]\n\t\tconst c1 = B64_LOOKUP[base64.charCodeAt(i + 1)]\n\t\tconst c2 = B64_LOOKUP[base64.charCodeAt(i + 2)]\n\t\tconst c3 = B64_LOOKUP[base64.charCodeAt(i + 3)]\n\n\t\tconst bitmap = (c0 << 18) | (c1 << 12) | (c2 << 6) | c3\n\n\t\tbytes[byteIndex++] = (bitmap >> 16) & 255 // top byte (bits 23\u201316)\n\t\tbytes[byteIndex++] = (bitmap >> 8) & 255 // middle byte (bits 15\u20138)\n\t\tbytes[byteIndex++] = bitmap & 255 // bottom byte (bits 7\u20130)\n\t}\n\n\t// Final group when padded: 3 valid chars -> 2 bytes, 2 valid chars -> 1 byte.\n\tif (padding === 1) {\n\t\tconst c0 = B64_LOOKUP[base64.charCodeAt(fullGroups)]\n\t\tconst c1 = B64_LOOKUP[base64.charCodeAt(fullGroups + 1)]\n\t\tconst c2 = B64_LOOKUP[base64.charCodeAt(fullGroups + 2)]\n\t\tconst bitmap = (c0 << 18) | (c1 << 12) | (c2 << 6)\n\t\tbytes[byteIndex++] = (bitmap >> 16) & 255\n\t\tbytes[byteIndex++] = (bitmap >> 8) & 255\n\t} else if (padding === 2) {\n\t\tconst c0 = B64_LOOKUP[base64.charCodeAt(fullGroups)]\n\t\tconst c1 = B64_LOOKUP[base64.charCodeAt(fullGroups + 1)]\n\t\tconst bitmap = (c0 << 18) | (c1 << 12)\n\t\tbytes[byteIndex++] = (bitmap >> 16) & 255\n\t}\n\n\treturn bytes\n}\n\nfunction nativeUint8ArrayToBase64(uint8Array: Uint8Array): string {\n\treturn uint8Array.toBase64()\n}\n\n/** @internal */\nexport function fallbackUint8ArrayToBase64(uint8Array: Uint8Array): string {\n\tconst len = uint8Array.length\n\tconst fullGroups = Math.floor(len / 3) * 3\n\tlet result = ''\n\n\t// base64 represents 3 bytes (24 bits) as 4 characters of 6 bits each. For each\n\t// group of 3 bytes we pack them into one 24-bit number, then read it back out as\n\t// four 6-bit slices and use each slice (a value 0\u201363) to index into the 64-char\n\t// alphabet. `>> n` shifts the wanted slice down to the bottom; SIX_BIT_MASK then\n\t// discards everything above those 6 bits.\n\tfor (let i = 0; i < fullGroups; i += 3) {\n\t\tconst byte1 = uint8Array[i]\n\t\tconst byte2 = uint8Array[i + 1]\n\t\tconst byte3 = uint8Array[i + 2]\n\n\t\tconst bitmap = (byte1 << 16) | (byte2 << 8) | byte3\n\t\tresult +=\n\t\t\tBASE64_CHARS[(bitmap >> 18) & SIX_BIT_MASK] + // bits 23\u201318 (top sextet)\n\t\t\tBASE64_CHARS[(bitmap >> 12) & SIX_BIT_MASK] + // bits 17\u201312\n\t\t\tBASE64_CHARS[(bitmap >> 6) & SIX_BIT_MASK] + // bits 11\u20136\n\t\t\tBASE64_CHARS[bitmap & SIX_BIT_MASK] // bits 5\u20130 (bottom sextet)\n\t}\n\n\t// A trailing 1 or 2 bytes can't fill a whole 4-char group, so we emit only the\n\t// chars their bits cover and pad the rest with '=' to keep the length a multiple\n\t// of 4. Standard base64 \u2014 matches the native API and Node's Buffer, so a path\n\t// encoded by the fallback round-trips on a runtime that decodes with the native one.\n\tconst remaining = len - fullGroups\n\tif (remaining === 1) {\n\t\t// 8 bits \u2192 2 sextets (the 2nd only partly filled), then \"==\"\n\t\tconst bitmap = uint8Array[fullGroups] << 16\n\t\tresult +=\n\t\t\tBASE64_CHARS[(bitmap >> 18) & SIX_BIT_MASK] +\n\t\t\tBASE64_CHARS[(bitmap >> 12) & SIX_BIT_MASK] +\n\t\t\t'=='\n\t} else if (remaining === 2) {\n\t\t// 16 bits \u2192 3 sextets (the 3rd only partly filled), then \"=\"\n\t\tconst bitmap = (uint8Array[fullGroups] << 16) | (uint8Array[fullGroups + 1] << 8)\n\t\tresult +=\n\t\t\tBASE64_CHARS[(bitmap >> 18) & SIX_BIT_MASK] +\n\t\t\tBASE64_CHARS[(bitmap >> 12) & SIX_BIT_MASK] +\n\t\t\tBASE64_CHARS[(bitmap >> 6) & SIX_BIT_MASK] +\n\t\t\t'='\n\t}\n\n\treturn result\n}\n\n/**\n * Convert a Uint8Array to base64.\n * Processes bytes in groups of 3 to produce 4 base64 characters.\n *\n * @internal\n */\nconst uint8ArrayToBase64 =\n\ttypeof Uint8Array.prototype.toBase64 === 'function'\n\t\t? nativeUint8ArrayToBase64\n\t\t: fallbackUint8ArrayToBase64\n\n/**\n * Convert a base64 string to Uint8Array.\n *\n * @internal\n */\nconst base64ToUint8Array =\n\ttypeof Uint8Array.fromBase64 === 'function'\n\t\t? nativeBase64ToUint8Array\n\t\t: fallbackBase64ToUint8Array\n\n/**\n * Convert Float16 bits to a number using optimized lookup tables.\n * Handles normal numbers, subnormal numbers, zero, infinity, and NaN.\n *\n * @param bits - The 16-bit Float16 value to decode\n * @returns The decoded number value\n * @internal\n */\nexport function float16BitsToNumber(bits: number): number {\n\tconst sign = bits >> 15\n\tconst exp = (bits >> 10) & 0x1f\n\tconst frac = bits & 0x3ff\n\n\tif (exp === 0) {\n\t\t// Subnormal or zero - rare case\n\t\treturn sign ? -frac * POW2_SUBNORMAL : frac * POW2_SUBNORMAL\n\t}\n\tif (exp === 31) {\n\t\t// Infinity or NaN - very rare\n\t\treturn frac ? NaN : sign ? -Infinity : Infinity\n\t}\n\t// Normal case - two table lookups, one multiply, no division\n\tconst magnitude = POW2[exp] * MANTISSA[frac]\n\treturn sign ? -magnitude : magnitude\n}\n\n/**\n * Convert a number to Float16 bits.\n * Handles normal numbers, subnormal numbers, zero, infinity, and NaN.\n *\n * @param value - The number to encode as Float16\n * @returns The 16-bit Float16 representation of the number\n * @internal\n */\nexport function numberToFloat16Bits(value: number): number {\n\tif (value === 0) return Object.is(value, -0) ? 0x8000 : 0\n\tif (!Number.isFinite(value)) {\n\t\tif (Number.isNaN(value)) return 0x7e00\n\t\treturn value > 0 ? 0x7c00 : 0xfc00\n\t}\n\n\tconst sign = value < 0 ? 1 : 0\n\tvalue = Math.abs(value)\n\n\t// Find exponent and mantissa\n\tconst exp = Math.floor(Math.log2(value))\n\tlet expBiased = exp + 15\n\n\tif (expBiased >= 31) {\n\t\t// Overflow to infinity\n\t\treturn (sign << 15) | 0x7c00\n\t}\n\tif (expBiased <= 0) {\n\t\t// Subnormal or underflow\n\t\tconst frac = Math.round(value * Math.pow(2, 14) * 1024)\n\t\treturn (sign << 15) | (frac & 0x3ff)\n\t}\n\n\t// Normal number\n\tconst mantissa = value / Math.pow(2, exp) - 1\n\tlet frac = Math.round(mantissa * 1024)\n\n\t// Handle rounding overflow: if frac rounds to 1024, increment exponent\n\tif (frac >= 1024) {\n\t\tfrac = 0\n\t\texpBiased++\n\t\tif (expBiased >= 31) {\n\t\t\t// Overflow to infinity\n\t\t\treturn (sign << 15) | 0x7c00\n\t\t}\n\t}\n\n\treturn (sign << 15) | (expBiased << 10) | frac\n}\n\n/**\n * Utilities for encoding and decoding points using base64 and Float16 encoding.\n * Provides functions for converting between VecModel arrays and compact base64 strings,\n * as well as individual point encoding/decoding operations.\n *\n * @public\n */\nexport class b64Vecs {\n\t/**\n\t * Encode a single point (x, y, z) to 8 base64 characters using legacy Float16 encoding.\n\t * Each coordinate is encoded as a Float16 value, resulting in 6 bytes total.\n\t *\n\t * @param x - The x coordinate\n\t * @param y - The y coordinate\n\t * @param z - The z coordinate\n\t * @returns An 8-character base64 string representing the point\n\t * @internal\n\t */\n\tstatic _legacyEncodePoint(x: number, y: number, z: number): string {\n\t\tconst buffer = new Uint8Array(6)\n\t\tconst dataView = new DataView(buffer.buffer)\n\n\t\tsetFloat16(dataView, 0, x)\n\t\tsetFloat16(dataView, 2, y)\n\t\tsetFloat16(dataView, 4, z)\n\n\t\treturn uint8ArrayToBase64(buffer)\n\t}\n\n\t/**\n\t * Convert an array of VecModels to a base64 string using legacy Float16 encoding.\n\t * Uses Float16 encoding for each coordinate (x, y, z). If a point's z value is\n\t * undefined, it defaults to 0.5.\n\t *\n\t * @param points - An array of VecModel objects to encode\n\t * @returns A base64-encoded string containing all points\n\t * @internal Used only for migrations from legacy format\n\t */\n\tstatic _legacyEncodePoints(points: VecModel[]): string {\n\t\tif (points.length === 0) return ''\n\n\t\t// 3 Float16s per point = 6 bytes per point\n\t\tconst buffer = new Uint8Array(points.length * 6)\n\t\tconst dataView = new DataView(buffer.buffer)\n\n\t\tfor (let i = 0; i < points.length; i++) {\n\t\t\tconst p = points[i]\n\t\t\tconst offset = i * 6\n\t\t\tsetFloat16(dataView, offset, p.x)\n\t\t\tsetFloat16(dataView, offset + 2, p.y)\n\t\t\tsetFloat16(dataView, offset + 4, p.z ?? 0.5)\n\t\t}\n\n\t\treturn uint8ArrayToBase64(buffer)\n\t}\n\n\t/**\n\t * Convert a legacy base64 string back to an array of VecModels.\n\t * Decodes Float16-encoded coordinates (x, y, z) from the base64 string.\n\t *\n\t * @param base64 - The base64-encoded string containing point data\n\t * @returns An array of VecModel objects decoded from the string\n\t * @internal Used only for migrations from legacy format\n\t */\n\tstatic _legacyDecodePoints(base64: string): VecModel[] {\n\t\tconst bytes = base64ToUint8Array(base64)\n\t\tconst dataView = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength)\n\t\tconst result: VecModel[] = []\n\t\tfor (let offset = 0; offset < bytes.length; offset += 6) {\n\t\t\tresult.push({\n\t\t\t\tx: getFloat16(dataView, offset),\n\t\t\t\ty: getFloat16(dataView, offset + 2),\n\t\t\t\tz: getFloat16(dataView, offset + 4),\n\t\t\t})\n\t\t}\n\t\treturn result\n\t}\n\n\t/**\n\t * Encode an array of VecModels using delta encoding for improved precision.\n\t * The first point is stored as Float32 (high precision for absolute position),\n\t * subsequent points are stored as Float16 deltas from the previous point.\n\t * This provides full precision for the starting position and excellent precision\n\t * for deltas between consecutive points (which are typically small values).\n\t *\n\t * Format:\n\t * - First point: 3 Float32 values = 12 bytes = 16 base64 chars\n\t * - Delta points: 3 Float16 values each = 6 bytes = 8 base64 chars each\n\t *\n\t * @param points - An array of VecModel objects to encode\n\t * @param dim - Encoding dimension; `2` routes through the 2D variant (drops z), `3` (default) keeps x, y, z\n\t * @returns A base64-encoded string containing delta-encoded points\n\t * @public\n\t */\n\tstatic encodePoints(points: VecModel[], dim?: 2 | 3): string {\n\t\tif (dim === DIM_2D) return b64Vecs.encodePoints2D(points)\n\t\tif (points.length === 0) return ''\n\n\t\t// First point: 3 Float32s = 12 bytes\n\t\t// Remaining points: 3 Float16s each = 6 bytes each\n\t\tconst firstPointBytes = 12\n\t\tconst deltaBytes = (points.length - 1) * 6\n\t\tconst totalBytes = firstPointBytes + deltaBytes\n\n\t\tconst buffer = new Uint8Array(totalBytes)\n\t\tconst dataView = new DataView(buffer.buffer)\n\n\t\t// First point is stored as Float32 for full precision\n\t\tconst first = points[0]\n\t\tdataView.setFloat32(0, first.x, true) // little-endian\n\t\tdataView.setFloat32(4, first.y, true)\n\t\tdataView.setFloat32(8, first.z ?? 0.5, true)\n\n\t\t// Subsequent points are Float16 deltas from the previous point\n\t\tlet prevX = first.x\n\t\tlet prevY = first.y\n\t\tlet prevZ = first.z ?? 0.5\n\n\t\tfor (let i = 1; i < points.length; i++) {\n\t\t\tconst p = points[i]\n\t\t\tconst z = p.z ?? 0.5\n\n\t\t\tconst offset = firstPointBytes + (i - 1) * 6\n\t\t\tsetFloat16(dataView, offset, p.x - prevX)\n\t\t\tsetFloat16(dataView, offset + 2, p.y - prevY)\n\t\t\tsetFloat16(dataView, offset + 4, z - prevZ)\n\n\t\t\tprevX = p.x\n\t\t\tprevY = p.y\n\t\t\tprevZ = z\n\t\t}\n\n\t\treturn uint8ArrayToBase64(buffer)\n\t}\n\n\t/**\n\t * Decode a delta-encoded base64 string back to an array of absolute VecModels.\n\t * The first point is stored as Float32 (high precision), subsequent points are\n\t * Float16 deltas that are accumulated to reconstruct absolute positions.\n\t *\n\t * @param base64 - The base64-encoded string containing delta-encoded point data\n\t * @param dim - Encoding dimension; `2` expects x/y only (z supplied as 0.5), `3` (default) expects x/y/z\n\t * @returns An array of VecModel objects with absolute coordinates\n\t * @public\n\t */\n\tstatic decodePoints(base64: string, dim?: 2 | 3): VecModel[] {\n\t\tif (dim === DIM_2D) return b64Vecs.decodePoints2D(base64)\n\t\tif (base64.length === 0) return []\n\n\t\tconst bytes = base64ToUint8Array(base64)\n\t\tconst dataView = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength)\n\t\tconst result: VecModel[] = []\n\n\t\t// First point is Float32 (12 bytes)\n\t\tlet x = dataView.getFloat32(0, true)\n\t\tlet y = dataView.getFloat32(4, true)\n\t\tlet z = dataView.getFloat32(8, true)\n\t\tresult.push({ x, y, z })\n\n\t\t// Subsequent points are Float16 deltas - accumulate to get absolute positions\n\t\tconst firstPointBytes = 12\n\t\tfor (let offset = firstPointBytes; offset < bytes.length; offset += 6) {\n\t\t\tx += getFloat16(dataView, offset)\n\t\t\ty += getFloat16(dataView, offset + 2)\n\t\t\tz += getFloat16(dataView, offset + 4)\n\t\t\tresult.push({ x, y, z })\n\t\t}\n\n\t\treturn result\n\t}\n\n\t/**\n\t * Get the first point from a delta-encoded base64 string.\n\t * The first point is stored as Float32 for full precision.\n\t *\n\t * @param b64Points - The delta-encoded base64 string\n\t * @param dim - Encoding dimension; `2` expects x/y only (z supplied as 0.5), `3` (default) expects x/y/z\n\t * @returns The first point as a VecModel, or null if the string is too short\n\t * @public\n\t */\n\tstatic decodeFirstPoint(b64Points: string, dim?: 2 | 3): VecModel | null {\n\t\tif (dim === DIM_2D) return b64Vecs.decodeFirstPoint2D(b64Points)\n\t\t// First point needs 16 base64 chars (12 bytes as Float32)\n\t\tif (b64Points.length < FIRST_POINT_B64_LENGTH) return null\n\n\t\tconst bytes = base64ToUint8Array(b64Points.slice(0, FIRST_POINT_B64_LENGTH))\n\t\tconst dataView = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength)\n\n\t\treturn {\n\t\t\tx: dataView.getFloat32(0, true),\n\t\t\ty: dataView.getFloat32(4, true),\n\t\t\tz: dataView.getFloat32(8, true),\n\t\t}\n\t}\n\n\t/**\n\t * Get the last point from a delta-encoded base64 string.\n\t * Requires decoding all points to accumulate deltas.\n\t *\n\t * @param b64Points - The delta-encoded base64 string\n\t * @param dim - Encoding dimension; `2` expects x/y only (z supplied as 0.5), `3` (default) expects x/y/z\n\t * @returns The last point as a VecModel, or null if the string is too short\n\t * @public\n\t */\n\tstatic decodeLastPoint(b64Points: string, dim?: 2 | 3): VecModel | null {\n\t\tif (dim === DIM_2D) return b64Vecs.decodeLastPoint2D(b64Points)\n\t\tif (b64Points.length < FIRST_POINT_B64_LENGTH) return null\n\n\t\tconst bytes = base64ToUint8Array(b64Points)\n\t\tconst dataView = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength)\n\n\t\t// Start with first point (Float32)\n\t\tlet x = dataView.getFloat32(0, true)\n\t\tlet y = dataView.getFloat32(4, true)\n\t\tlet z = dataView.getFloat32(8, true)\n\n\t\t// Accumulate all Float16 deltas to get the last point\n\t\tconst firstPointBytes = 12\n\t\tfor (let offset = firstPointBytes; offset < bytes.length; offset += 6) {\n\t\t\tx += getFloat16(dataView, offset)\n\t\t\ty += getFloat16(dataView, offset + 2)\n\t\t\tz += getFloat16(dataView, offset + 4)\n\t\t}\n\n\t\treturn { x, y, z }\n\t}\n\n\t/**\n\t * Encode an array of VecModels as 2D delta-encoded points, dropping z entirely.\n\t * Use for draw shapes from devices that don't report pressure, where z is a\n\t * constant 0.5 and storing it wastes ~33% of per-point bytes.\n\t *\n\t * Format:\n\t * - First point: 2 Float32 values (x, y) = 8 bytes\n\t * - Delta points: 2 Float16 values (dx, dy) = 4 bytes each\n\t *\n\t * @param points - An array of VecModel objects to encode (z is discarded)\n\t * @returns A base64-encoded string containing 2D delta-encoded points\n\t * @public\n\t */\n\tstatic encodePoints2D(points: VecModel[]): string {\n\t\tif (points.length === 0) return ''\n\n\t\tconst firstPointBytes = 8\n\t\tconst deltaBytes = (points.length - 1) * 4\n\t\tconst buffer = new Uint8Array(firstPointBytes + deltaBytes)\n\t\tconst dataView = new DataView(buffer.buffer)\n\n\t\tconst first = points[0]\n\t\tdataView.setFloat32(0, first.x, true)\n\t\tdataView.setFloat32(4, first.y, true)\n\n\t\tlet prevX = first.x\n\t\tlet prevY = first.y\n\n\t\tfor (let i = 1; i < points.length; i++) {\n\t\t\tconst p = points[i]\n\t\t\tconst offset = firstPointBytes + (i - 1) * 4\n\t\t\tsetFloat16(dataView, offset, p.x - prevX)\n\t\t\tsetFloat16(dataView, offset + 2, p.y - prevY)\n\t\t\tprevX = p.x\n\t\t\tprevY = p.y\n\t\t}\n\n\t\treturn uint8ArrayToBase64(buffer)\n\t}\n\n\t/**\n\t * Decode a 2D delta-encoded base64 string back to an array of absolute VecModels.\n\t * The z coordinate is always set to 0.5 (the default pressure value) so downstream\n\t * consumers don't need a separate code path.\n\t *\n\t * @param base64 - The base64-encoded string containing 2D delta-encoded point data\n\t * @returns An array of VecModel objects with absolute (x, y) and z = 0.5\n\t * @public\n\t */\n\tstatic decodePoints2D(base64: string): VecModel[] {\n\t\tif (base64.length === 0) return []\n\n\t\tconst bytes = base64ToUint8Array(base64)\n\t\tconst dataView = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength)\n\t\tconst result: VecModel[] = []\n\n\t\tlet x = dataView.getFloat32(0, true)\n\t\tlet y = dataView.getFloat32(4, true)\n\t\tresult.push({ x, y, z: DEFAULT_PRESSURE })\n\n\t\tconst firstPointBytes = 8\n\t\tfor (let offset = firstPointBytes; offset < bytes.length; offset += 4) {\n\t\t\tx += getFloat16(dataView, offset)\n\t\t\ty += getFloat16(dataView, offset + 2)\n\t\t\tresult.push({ x, y, z: DEFAULT_PRESSURE })\n\t\t}\n\n\t\treturn result\n\t}\n\n\t/**\n\t * Get the first point from a 2D delta-encoded base64 string.\n\t *\n\t * @param b64Points - The 2D delta-encoded base64 string\n\t * @returns The first point with z = 0.5, or null if the string is too short\n\t * @public\n\t */\n\tstatic decodeFirstPoint2D(b64Points: string): VecModel | null {\n\t\tif (b64Points.length < FIRST_POINT_2D_B64_LENGTH) return null\n\n\t\tconst bytes = base64ToUint8Array(b64Points.slice(0, FIRST_POINT_2D_B64_LENGTH))\n\t\tconst dataView = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength)\n\n\t\treturn {\n\t\t\tx: dataView.getFloat32(0, true),\n\t\t\ty: dataView.getFloat32(4, true),\n\t\t\tz: DEFAULT_PRESSURE,\n\t\t}\n\t}\n\n\t/**\n\t * Get the last point from a 2D delta-encoded base64 string.\n\t * Requires decoding all points to accumulate deltas.\n\t *\n\t * @param b64Points - The 2D delta-encoded base64 string\n\t * @returns The last point with z = 0.5, or null if the string is too short\n\t * @public\n\t */\n\tstatic decodeLastPoint2D(b64Points: string): VecModel | null {\n\t\tif (b64Points.length < FIRST_POINT_2D_B64_LENGTH) return null\n\n\t\tconst bytes = base64ToUint8Array(b64Points)\n\t\tconst dataView = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength)\n\n\t\tlet x = dataView.getFloat32(0, true)\n\t\tlet y = dataView.getFloat32(4, true)\n\n\t\tconst firstPointBytes = 8\n\t\tfor (let offset = firstPointBytes; offset < bytes.length; offset += 4) {\n\t\t\tx += getFloat16(dataView, offset)\n\t\t\ty += getFloat16(dataView, offset + 2)\n\t\t}\n\n\t\treturn { x, y, z: DEFAULT_PRESSURE }\n\t}\n\n\t/**\n\t * Whether an encoded path contains only a single point (a \"dot\"), inferred from\n\t * the encoded length without decoding \u2014 cheap enough for the render path.\n\t *\n\t * The single-point length depends on the encoding dimension, so this takes the\n\t * segment's `dim`: a one-point path is `FIRST_POINT_B64_LENGTH` chars (3D) or\n\t * `FIRST_POINT_2D_B64_LENGTH` chars (2D). Keeping this beside the layout constants\n\t * is deliberate \u2014 it is the single source of truth for \"how long is one point\", so\n\t * callers never hard-code a length threshold (which silently breaks when a new\n\t * encoding is added).\n\t *\n\t * @param b64Points - The encoded path string\n\t * @param dim - Encoding dimension; `2` for (x, y), `3` (default) for (x, y, z)\n\t * @returns true if the path encodes exactly one point\n\t * @public\n\t */\n\tstatic isSinglePoint(b64Points: string, dim?: 2 | 3): boolean {\n\t\treturn b64Points.length <= (dim === DIM_2D ? FIRST_POINT_2D_B64_LENGTH : FIRST_POINT_B64_LENGTH)\n\t}\n}\n"],
5
+ "mappings": "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",
6
6
  "names": ["frac"]
7
7
  }
@@ -201,7 +201,7 @@ function createInstanceRecordType(stylesById) {
201
201
  rotation: 0
202
202
  },
203
203
  isFocusMode: false,
204
- exportBackground: false,
204
+ exportBackground: true,
205
205
  isDebugMode: false,
206
206
  isToolLocked: false,
207
207
  screenBounds: { x: 0, y: 0, w: 1080, h: 720 },
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/records/TLInstance.ts"],
4
- "sourcesContent": ["import {\n\tBaseRecord,\n\tcreateMigrationIds,\n\tcreateRecordMigrationSequence,\n\tcreateRecordType,\n\tRecordId,\n} from '@tldraw/store'\nimport { filterEntries, JsonObject } from '@tldraw/utils'\nimport { T } from '@tldraw/validate'\nimport { BoxModel, boxModelValidator } from '../misc/geometry-types'\nimport { idValidator } from '../misc/id-validator'\nimport { cursorValidator, TLCursor } from '../misc/TLCursor'\nimport { opacityValidator, TLOpacityType } from '../misc/TLOpacity'\nimport { scribbleValidator, TLScribble } from '../misc/TLScribble'\nimport { StyleProp } from '../styles/StyleProp'\nimport { pageIdValidator, TLPageId } from './TLPage'\nimport { TLShapeId } from './TLShape'\nimport { TLUserId, userIdValidator } from './TLUser'\n\n/**\n * State that is particular to a single browser tab. The TLInstance record stores\n * all session-specific state including cursor position, selected tools, UI preferences,\n * and temporary interaction state.\n *\n * Each browser tab has exactly one TLInstance record that persists for the duration\n * of the session and tracks the user's current interaction state.\n *\n * @example\n * ```ts\n * const instance: TLInstance = {\n * id: 'instance:instance',\n * typeName: 'instance',\n * currentPageId: 'page:page1',\n * cursor: { type: 'default', rotation: 0 },\n * screenBounds: { x: 0, y: 0, w: 1920, h: 1080 },\n * isFocusMode: false,\n * isGridMode: true\n * }\n * ```\n *\n * @public\n */\nexport interface TLInstance extends BaseRecord<'instance', TLInstanceId> {\n\tcurrentPageId: TLPageId\n\topacityForNextShape: TLOpacityType\n\tstylesForNextShape: Record<string, unknown>\n\tfollowingUserId: TLUserId | null\n\thighlightedUserIds: TLUserId[]\n\tbrush: BoxModel | null\n\tcursor: TLCursor\n\tscribbles: TLScribble[]\n\tisFocusMode: boolean\n\tisDebugMode: boolean\n\tisToolLocked: boolean\n\texportBackground: boolean\n\tscreenBounds: BoxModel\n\tinsets: boolean[]\n\tzoomBrush: BoxModel | null\n\tchatMessage: string\n\tisChatting: boolean\n\tisPenMode: boolean\n\tisGridMode: boolean\n\tisFocused: boolean\n\tdevicePixelRatio: number\n\t/**\n\t * This is whether the primary input mechanism includes a pointing device of limited accuracy,\n\t * such as a finger on a touchscreen.\n\t */\n\tisCoarsePointer: boolean\n\t/**\n\t * Will be null if the pointer doesn't support hovering (e.g. touch), but true or false\n\t * otherwise\n\t */\n\tisHoveringCanvas: boolean | null\n\topenMenus: string[]\n\tisChangingStyle: boolean\n\tisReadonly: boolean\n\tmeta: JsonObject\n\tduplicateProps: {\n\t\tshapeIds: TLShapeId[]\n\t\toffset: {\n\t\t\tx: number\n\t\t\ty: number\n\t\t}\n\t} | null\n\t/**\n\t * Whether the camera is currently moving or idle. Used to optimize rendering\n\t * and hit-testing during panning/zooming.\n\t */\n\tcameraState: 'idle' | 'moving'\n}\n\n/**\n * Configuration object defining which TLInstance properties should be preserved\n * when loading snapshots across browser sessions. Properties marked as `true`\n * represent user preferences that should persist, while `false` indicates\n * temporary state that should reset.\n *\n * @internal\n */\nexport const shouldKeyBePreservedBetweenSessions = {\n\t// This object defines keys that should be preserved across calls to loadSnapshot()\n\n\tid: false, // meta\n\ttypeName: false, // meta\n\n\tcurrentPageId: false, // does not preserve because who knows if the page still exists\n\topacityForNextShape: false, // does not preserve because it's a temporary state\n\tstylesForNextShape: false, // does not preserve because it's a temporary state\n\tfollowingUserId: false, // does not preserve because it's a temporary state\n\thighlightedUserIds: false, // does not preserve because it's a temporary state\n\tbrush: false, // does not preserve because it's a temporary state\n\tcursor: false, // does not preserve because it's a temporary state\n\tscribbles: false, // does not preserve because it's a temporary state\n\n\tisFocusMode: true, // preserves because it's a user preference\n\tisDebugMode: true, // preserves because it's a user preference\n\tisToolLocked: true, // preserves because it's a user preference\n\texportBackground: true, // preserves because it's a user preference\n\tscreenBounds: true, // preserves because it's capturing the user's screen state\n\tinsets: true, // preserves because it's capturing the user's screen state\n\n\tzoomBrush: false, // does not preserve because it's a temporary state\n\tchatMessage: false, // does not preserve because it's a temporary state\n\tisChatting: false, // does not preserve because it's a temporary state\n\tisPenMode: false, // does not preserve because it's a temporary state\n\n\tisGridMode: true, // preserves because it's a user preference\n\tisFocused: true, // preserves because obviously\n\tdevicePixelRatio: true, // preserves because it captures the user's screen state\n\tisCoarsePointer: true, // preserves because it captures the user's screen state\n\tisHoveringCanvas: false, // does not preserve because it's a temporary state\n\topenMenus: false, // does not preserve because it's a temporary state\n\tisChangingStyle: false, // does not preserve because it's a temporary state\n\tisReadonly: true, // preserves because it's a config option\n\tmeta: false, // does not preserve because who knows what's in there, leave it up to sdk users to save and reinstate\n\tduplicateProps: false, //\n\tcameraState: false, // does not preserve because it's a temporary state\n} as const satisfies { [K in keyof TLInstance]: boolean }\n\n/**\n * Extracts only the properties from a TLInstance that should be preserved\n * between browser sessions, filtering out temporary state.\n *\n * @param val - The TLInstance to filter, or null/undefined\n * @returns A partial TLInstance containing only preservable properties, or null\n *\n * @internal\n */\nexport function pluckPreservingValues(val?: TLInstance | null): null | Partial<TLInstance> {\n\treturn val\n\t\t? (filterEntries(val, (key) => {\n\t\t\t\treturn shouldKeyBePreservedBetweenSessions[key as keyof TLInstance]\n\t\t\t}) as Partial<TLInstance>)\n\t\t: null\n}\n\n/**\n * A unique identifier for TLInstance records.\n *\n * TLInstance IDs are always the constant 'instance:instance' since there\n * is exactly one instance record per browser tab.\n *\n * @public\n */\nexport type TLInstanceId = RecordId<TLInstance>\n\n/**\n * Validator for TLInstanceId values. Ensures the ID follows the correct\n * format for instance records.\n *\n * @example\n * ```ts\n * const isValid = instanceIdValidator.isValid('instance:instance') // true\n * const isValid2 = instanceIdValidator.isValid('invalid') // false\n * ```\n *\n * @public\n */\nexport const instanceIdValidator = idValidator<TLInstanceId>('instance')\n\n/**\n * Creates the record type definition for TLInstance records, including validation\n * and default properties. The function takes a map of available style properties\n * to configure validation for the stylesForNextShape field.\n *\n * @param stylesById - Map of style property IDs to their corresponding StyleProp definitions\n * @returns A configured RecordType for TLInstance records\n *\n * @example\n * ```ts\n * const stylesMap = new Map([['color', DefaultColorStyle]])\n * const InstanceRecordType = createInstanceRecordType(stylesMap)\n *\n * const instance = InstanceRecordType.create({\n * id: 'instance:instance',\n * currentPageId: 'page:page1'\n * })\n * ```\n *\n * @public\n */\nexport function createInstanceRecordType(stylesById: Map<string, StyleProp<unknown>>) {\n\tconst stylesForNextShapeValidators = {} as Record<string, T.Validator<unknown>>\n\tfor (const [id, style] of stylesById) {\n\t\tstylesForNextShapeValidators[id] = T.optional(style)\n\t}\n\n\tconst instanceTypeValidator: T.Validator<TLInstance> = T.model(\n\t\t'instance',\n\t\tT.object({\n\t\t\ttypeName: T.literal('instance'),\n\t\t\tid: idValidator<TLInstanceId>('instance'),\n\t\t\tcurrentPageId: pageIdValidator,\n\t\t\tfollowingUserId: userIdValidator.nullable(),\n\t\t\tbrush: boxModelValidator.nullable(),\n\t\t\topacityForNextShape: opacityValidator,\n\t\t\tstylesForNextShape: T.object(stylesForNextShapeValidators),\n\t\t\tcursor: cursorValidator,\n\t\t\tscribbles: T.arrayOf(scribbleValidator),\n\t\t\tisFocusMode: T.boolean,\n\t\t\tisDebugMode: T.boolean,\n\t\t\tisToolLocked: T.boolean,\n\t\t\texportBackground: T.boolean,\n\t\t\tscreenBounds: boxModelValidator,\n\t\t\tinsets: T.arrayOf(T.boolean),\n\t\t\tzoomBrush: boxModelValidator.nullable(),\n\t\t\tisPenMode: T.boolean,\n\t\t\tisGridMode: T.boolean,\n\t\t\tchatMessage: T.string,\n\t\t\tisChatting: T.boolean,\n\t\t\thighlightedUserIds: T.arrayOf(userIdValidator),\n\t\t\tisFocused: T.boolean,\n\t\t\tdevicePixelRatio: T.number,\n\t\t\tisCoarsePointer: T.boolean,\n\t\t\tisHoveringCanvas: T.boolean.nullable(),\n\t\t\topenMenus: T.arrayOf(T.string),\n\t\t\tisChangingStyle: T.boolean,\n\t\t\tisReadonly: T.boolean,\n\t\t\tmeta: T.jsonValue as T.ObjectValidator<JsonObject>,\n\t\t\tduplicateProps: T.object({\n\t\t\t\tshapeIds: T.arrayOf(idValidator<TLShapeId>('shape')),\n\t\t\t\toffset: T.object({\n\t\t\t\t\tx: T.number,\n\t\t\t\t\ty: T.number,\n\t\t\t\t}),\n\t\t\t}).nullable(),\n\t\t\tcameraState: T.literalEnum('idle', 'moving'),\n\t\t})\n\t)\n\n\treturn createRecordType<TLInstance>('instance', {\n\t\tvalidator: instanceTypeValidator,\n\t\tscope: 'session',\n\t\tephemeralKeys: {\n\t\t\tcurrentPageId: false,\n\t\t\tmeta: false,\n\n\t\t\tfollowingUserId: true,\n\t\t\topacityForNextShape: true,\n\t\t\tstylesForNextShape: true,\n\t\t\tbrush: true,\n\t\t\tcursor: true,\n\t\t\tscribbles: true,\n\t\t\tisFocusMode: true,\n\t\t\tisDebugMode: true,\n\t\t\tisToolLocked: true,\n\t\t\texportBackground: true,\n\t\t\tscreenBounds: true,\n\t\t\tinsets: true,\n\t\t\tzoomBrush: true,\n\t\t\tisPenMode: true,\n\t\t\tisGridMode: true,\n\t\t\tchatMessage: true,\n\t\t\tisChatting: true,\n\t\t\thighlightedUserIds: true,\n\t\t\tisFocused: true,\n\t\t\tdevicePixelRatio: true,\n\t\t\tisCoarsePointer: true,\n\t\t\tisHoveringCanvas: true,\n\t\t\topenMenus: true,\n\t\t\tisChangingStyle: true,\n\t\t\tisReadonly: true,\n\t\t\tduplicateProps: true,\n\t\t\tcameraState: true,\n\t\t},\n\t}).withDefaultProperties(\n\t\t(): Omit<TLInstance, 'typeName' | 'id' | 'currentPageId'> => ({\n\t\t\tfollowingUserId: null,\n\t\t\topacityForNextShape: 1,\n\t\t\tstylesForNextShape: {},\n\t\t\tbrush: null,\n\t\t\tscribbles: [],\n\t\t\tcursor: {\n\t\t\t\ttype: 'default',\n\t\t\t\trotation: 0,\n\t\t\t},\n\t\t\tisFocusMode: false,\n\t\t\texportBackground: false,\n\t\t\tisDebugMode: false,\n\t\t\tisToolLocked: false,\n\t\t\tscreenBounds: { x: 0, y: 0, w: 1080, h: 720 },\n\t\t\tinsets: [false, false, false, false],\n\t\t\tzoomBrush: null,\n\t\t\tisGridMode: false,\n\t\t\tisPenMode: false,\n\t\t\tchatMessage: '',\n\t\t\tisChatting: false,\n\t\t\thighlightedUserIds: [],\n\t\t\tisFocused: false,\n\t\t\tdevicePixelRatio: typeof window === 'undefined' ? 1 : window.devicePixelRatio,\n\t\t\tisCoarsePointer: false,\n\t\t\tisHoveringCanvas: null,\n\t\t\topenMenus: [] as string[],\n\t\t\tisChangingStyle: false,\n\t\t\tisReadonly: false,\n\t\t\tmeta: {},\n\t\t\tduplicateProps: null,\n\t\t\tcameraState: 'idle',\n\t\t})\n\t)\n}\n\n/**\n * Migration version identifiers for TLInstance records. Each version represents\n * a schema change that requires data transformation when loading older documents.\n *\n * The versions track the evolution of the instance record structure over time,\n * enabling backward and forward compatibility.\n *\n * @public\n */\nexport const instanceVersions = createMigrationIds('com.tldraw.instance', {\n\tAddTransparentExportBgs: 1,\n\tRemoveDialog: 2,\n\tAddToolLockMode: 3,\n\tRemoveExtraPropsForNextShape: 4,\n\tAddLabelColor: 5,\n\tAddFollowingUserId: 6,\n\tRemoveAlignJustify: 7,\n\tAddZoom: 8,\n\tAddVerticalAlign: 9,\n\tAddScribbleDelay: 10,\n\tRemoveUserId: 11,\n\tAddIsPenModeAndIsGridMode: 12,\n\tHoistOpacity: 13,\n\tAddChat: 14,\n\tAddHighlightedUserIds: 15,\n\tReplacePropsForNextShapeWithStylesForNextShape: 16,\n\tAddMeta: 17,\n\tRemoveCursorColor: 18,\n\tAddLonelyProperties: 19,\n\tReadOnlyReadonly: 20,\n\tAddHoveringCanvas: 21,\n\tAddScribbles: 22,\n\tAddInset: 23,\n\tAddDuplicateProps: 24,\n\tRemoveCanMoveCamera: 25,\n\tAddCameraState: 26,\n} as const)\n\n// TODO: rewrite these to use mutation\n\n/**\n * Migration sequence for TLInstance records. Defines how to transform instance\n * records between different schema versions, ensuring data compatibility when\n * loading documents created with different versions of tldraw.\n *\n * Each migration includes an 'up' function to migrate forward and optionally\n * a 'down' function for reverse migration.\n *\n * @example\n * ```ts\n * // Migrations are applied automatically when loading documents\n * const migratedInstance = instanceMigrations.migrate(oldInstance, targetVersion)\n * ```\n *\n * @public\n */\nexport const instanceMigrations = createRecordMigrationSequence({\n\tsequenceId: 'com.tldraw.instance',\n\trecordType: 'instance',\n\tsequence: [\n\t\t{\n\t\t\tid: instanceVersions.AddTransparentExportBgs,\n\t\t\tup: (instance) => {\n\t\t\t\treturn { ...instance, exportBackground: true }\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tid: instanceVersions.RemoveDialog,\n\t\t\tup: ({ dialog: _, ...instance }: any) => {\n\t\t\t\treturn instance\n\t\t\t},\n\t\t},\n\n\t\t{\n\t\t\tid: instanceVersions.AddToolLockMode,\n\t\t\tup: (instance) => {\n\t\t\t\treturn { ...instance, isToolLocked: false }\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tid: instanceVersions.RemoveExtraPropsForNextShape,\n\t\t\tup: ({ propsForNextShape, ...instance }: any) => {\n\t\t\t\treturn {\n\t\t\t\t\t...instance,\n\t\t\t\t\tpropsForNextShape: Object.fromEntries(\n\t\t\t\t\t\tObject.entries(propsForNextShape).filter(([key]) =>\n\t\t\t\t\t\t\t[\n\t\t\t\t\t\t\t\t'color',\n\t\t\t\t\t\t\t\t'labelColor',\n\t\t\t\t\t\t\t\t'dash',\n\t\t\t\t\t\t\t\t'fill',\n\t\t\t\t\t\t\t\t'size',\n\t\t\t\t\t\t\t\t'font',\n\t\t\t\t\t\t\t\t'align',\n\t\t\t\t\t\t\t\t'verticalAlign',\n\t\t\t\t\t\t\t\t'icon',\n\t\t\t\t\t\t\t\t'geo',\n\t\t\t\t\t\t\t\t'arrowheadStart',\n\t\t\t\t\t\t\t\t'arrowheadEnd',\n\t\t\t\t\t\t\t\t'spline',\n\t\t\t\t\t\t\t].includes(key)\n\t\t\t\t\t\t)\n\t\t\t\t\t),\n\t\t\t\t}\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tid: instanceVersions.AddLabelColor,\n\t\t\tup: ({ propsForNextShape, ...instance }: any) => {\n\t\t\t\treturn {\n\t\t\t\t\t...instance,\n\t\t\t\t\tpropsForNextShape: {\n\t\t\t\t\t\t...propsForNextShape,\n\t\t\t\t\t\tlabelColor: 'black',\n\t\t\t\t\t},\n\t\t\t\t}\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tid: instanceVersions.AddFollowingUserId,\n\t\t\tup: (instance) => {\n\t\t\t\treturn { ...instance, followingUserId: null }\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tid: instanceVersions.RemoveAlignJustify,\n\t\t\tup: (instance: any) => {\n\t\t\t\tlet newAlign = instance.propsForNextShape.align\n\t\t\t\tif (newAlign === 'justify') {\n\t\t\t\t\tnewAlign = 'start'\n\t\t\t\t}\n\n\t\t\t\treturn {\n\t\t\t\t\t...instance,\n\t\t\t\t\tpropsForNextShape: {\n\t\t\t\t\t\t...instance.propsForNextShape,\n\t\t\t\t\t\talign: newAlign,\n\t\t\t\t\t},\n\t\t\t\t}\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tid: instanceVersions.AddZoom,\n\t\t\tup: (instance) => {\n\t\t\t\treturn { ...instance, zoomBrush: null }\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tid: instanceVersions.AddVerticalAlign,\n\t\t\tup: (instance: any) => {\n\t\t\t\treturn {\n\t\t\t\t\t...instance,\n\t\t\t\t\tpropsForNextShape: {\n\t\t\t\t\t\t...instance.propsForNextShape,\n\t\t\t\t\t\tverticalAlign: 'middle',\n\t\t\t\t\t},\n\t\t\t\t}\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tid: instanceVersions.AddScribbleDelay,\n\t\t\tup: (instance: any) => {\n\t\t\t\tif (instance.scribble !== null) {\n\t\t\t\t\treturn { ...instance, scribble: { ...instance.scribble, delay: 0 } }\n\t\t\t\t}\n\t\t\t\treturn { ...instance }\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tid: instanceVersions.RemoveUserId,\n\t\t\tup: ({ userId: _, ...instance }: any) => {\n\t\t\t\treturn instance\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tid: instanceVersions.AddIsPenModeAndIsGridMode,\n\t\t\tup: (instance) => {\n\t\t\t\treturn { ...instance, isPenMode: false, isGridMode: false }\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tid: instanceVersions.HoistOpacity,\n\t\t\tup: ({ propsForNextShape: { opacity, ...propsForNextShape }, ...instance }: any) => {\n\t\t\t\treturn { ...instance, opacityForNextShape: Number(opacity ?? '1'), propsForNextShape }\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tid: instanceVersions.AddChat,\n\t\t\tup: (instance) => {\n\t\t\t\treturn { ...instance, chatMessage: '', isChatting: false }\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tid: instanceVersions.AddHighlightedUserIds,\n\t\t\tup: (instance) => {\n\t\t\t\treturn { ...instance, highlightedUserIds: [] }\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tid: instanceVersions.ReplacePropsForNextShapeWithStylesForNextShape,\n\t\t\tup: ({ propsForNextShape: _, ...instance }: any) => {\n\t\t\t\treturn { ...instance, stylesForNextShape: {} }\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tid: instanceVersions.AddMeta,\n\t\t\tup: (record) => {\n\t\t\t\treturn {\n\t\t\t\t\t...record,\n\t\t\t\t\tmeta: {},\n\t\t\t\t}\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tid: instanceVersions.RemoveCursorColor,\n\t\t\tup: (record: any) => {\n\t\t\t\tconst { color: _, ...cursor } = record.cursor\n\t\t\t\treturn {\n\t\t\t\t\t...record,\n\t\t\t\t\tcursor,\n\t\t\t\t}\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tid: instanceVersions.AddLonelyProperties,\n\t\t\tup: (record) => {\n\t\t\t\treturn {\n\t\t\t\t\t...record,\n\t\t\t\t\tcanMoveCamera: true,\n\t\t\t\t\tisFocused: false,\n\t\t\t\t\tdevicePixelRatio: 1,\n\t\t\t\t\tisCoarsePointer: false,\n\t\t\t\t\topenMenus: [],\n\t\t\t\t\tisChangingStyle: false,\n\t\t\t\t\tisReadOnly: false,\n\t\t\t\t}\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tid: instanceVersions.ReadOnlyReadonly,\n\t\t\tup: ({ isReadOnly: _isReadOnly, ...record }: any) => {\n\t\t\t\treturn {\n\t\t\t\t\t...record,\n\t\t\t\t\tisReadonly: _isReadOnly,\n\t\t\t\t}\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tid: instanceVersions.AddHoveringCanvas,\n\t\t\tup: (record) => {\n\t\t\t\treturn {\n\t\t\t\t\t...record,\n\t\t\t\t\tisHoveringCanvas: null,\n\t\t\t\t}\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tid: instanceVersions.AddScribbles,\n\t\t\tup: ({ scribble: _, ...record }: any) => {\n\t\t\t\treturn {\n\t\t\t\t\t...record,\n\t\t\t\t\tscribbles: [],\n\t\t\t\t}\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tid: instanceVersions.AddInset,\n\t\t\tup: (record) => {\n\t\t\t\treturn {\n\t\t\t\t\t...record,\n\t\t\t\t\tinsets: [false, false, false, false],\n\t\t\t\t}\n\t\t\t},\n\t\t\tdown: ({ insets: _, ...record }: any) => {\n\t\t\t\treturn {\n\t\t\t\t\t...record,\n\t\t\t\t}\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tid: instanceVersions.AddDuplicateProps,\n\t\t\tup: (record) => {\n\t\t\t\treturn {\n\t\t\t\t\t...record,\n\t\t\t\t\tduplicateProps: null,\n\t\t\t\t}\n\t\t\t},\n\t\t\tdown: ({ duplicateProps: _, ...record }: any) => {\n\t\t\t\treturn {\n\t\t\t\t\t...record,\n\t\t\t\t}\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tid: instanceVersions.RemoveCanMoveCamera,\n\t\t\tup: ({ canMoveCamera: _, ...record }: any) => {\n\t\t\t\treturn {\n\t\t\t\t\t...record,\n\t\t\t\t}\n\t\t\t},\n\t\t\tdown: (instance) => {\n\t\t\t\treturn { ...instance, canMoveCamera: true }\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tid: instanceVersions.AddCameraState,\n\t\t\tup: (record) => {\n\t\t\t\treturn { ...record, cameraState: 'idle' }\n\t\t\t},\n\t\t\tdown: ({ cameraState: _, ...record }: any) => {\n\t\t\t\treturn record\n\t\t\t},\n\t\t},\n\t],\n})\n\n/**\n * The constant ID used for the singleton TLInstance record.\n *\n * Since each browser tab has exactly one instance, this constant ID\n * is used universally across the application.\n *\n * @example\n * ```ts\n * const instance = store.get(TLINSTANCE_ID)\n * if (instance) {\n * console.log('Current page:', instance.currentPageId)\n * }\n * ```\n *\n * @public\n */\nexport const TLINSTANCE_ID = 'instance:instance' as TLInstanceId\n"],
4
+ "sourcesContent": ["import {\n\tBaseRecord,\n\tcreateMigrationIds,\n\tcreateRecordMigrationSequence,\n\tcreateRecordType,\n\tRecordId,\n} from '@tldraw/store'\nimport { filterEntries, JsonObject } from '@tldraw/utils'\nimport { T } from '@tldraw/validate'\nimport { BoxModel, boxModelValidator } from '../misc/geometry-types'\nimport { idValidator } from '../misc/id-validator'\nimport { cursorValidator, TLCursor } from '../misc/TLCursor'\nimport { opacityValidator, TLOpacityType } from '../misc/TLOpacity'\nimport { scribbleValidator, TLScribble } from '../misc/TLScribble'\nimport { StyleProp } from '../styles/StyleProp'\nimport { pageIdValidator, TLPageId } from './TLPage'\nimport { TLShapeId } from './TLShape'\nimport { TLUserId, userIdValidator } from './TLUser'\n\n/**\n * State that is particular to a single browser tab. The TLInstance record stores\n * all session-specific state including cursor position, selected tools, UI preferences,\n * and temporary interaction state.\n *\n * Each browser tab has exactly one TLInstance record that persists for the duration\n * of the session and tracks the user's current interaction state.\n *\n * @example\n * ```ts\n * const instance: TLInstance = {\n * id: 'instance:instance',\n * typeName: 'instance',\n * currentPageId: 'page:page1',\n * cursor: { type: 'default', rotation: 0 },\n * screenBounds: { x: 0, y: 0, w: 1920, h: 1080 },\n * isFocusMode: false,\n * isGridMode: true\n * }\n * ```\n *\n * @public\n */\nexport interface TLInstance extends BaseRecord<'instance', TLInstanceId> {\n\tcurrentPageId: TLPageId\n\topacityForNextShape: TLOpacityType\n\tstylesForNextShape: Record<string, unknown>\n\tfollowingUserId: TLUserId | null\n\thighlightedUserIds: TLUserId[]\n\tbrush: BoxModel | null\n\tcursor: TLCursor\n\tscribbles: TLScribble[]\n\tisFocusMode: boolean\n\tisDebugMode: boolean\n\tisToolLocked: boolean\n\texportBackground: boolean\n\tscreenBounds: BoxModel\n\tinsets: boolean[]\n\tzoomBrush: BoxModel | null\n\tchatMessage: string\n\tisChatting: boolean\n\tisPenMode: boolean\n\tisGridMode: boolean\n\tisFocused: boolean\n\tdevicePixelRatio: number\n\t/**\n\t * This is whether the primary input mechanism includes a pointing device of limited accuracy,\n\t * such as a finger on a touchscreen.\n\t */\n\tisCoarsePointer: boolean\n\t/**\n\t * Will be null if the pointer doesn't support hovering (e.g. touch), but true or false\n\t * otherwise\n\t */\n\tisHoveringCanvas: boolean | null\n\topenMenus: string[]\n\tisChangingStyle: boolean\n\tisReadonly: boolean\n\tmeta: JsonObject\n\tduplicateProps: {\n\t\tshapeIds: TLShapeId[]\n\t\toffset: {\n\t\t\tx: number\n\t\t\ty: number\n\t\t}\n\t} | null\n\t/**\n\t * Whether the camera is currently moving or idle. Used to optimize rendering\n\t * and hit-testing during panning/zooming.\n\t */\n\tcameraState: 'idle' | 'moving'\n}\n\n/**\n * Configuration object defining which TLInstance properties should be preserved\n * when loading snapshots across browser sessions. Properties marked as `true`\n * represent user preferences that should persist, while `false` indicates\n * temporary state that should reset.\n *\n * @internal\n */\nexport const shouldKeyBePreservedBetweenSessions = {\n\t// This object defines keys that should be preserved across calls to loadSnapshot()\n\n\tid: false, // meta\n\ttypeName: false, // meta\n\n\tcurrentPageId: false, // does not preserve because who knows if the page still exists\n\topacityForNextShape: false, // does not preserve because it's a temporary state\n\tstylesForNextShape: false, // does not preserve because it's a temporary state\n\tfollowingUserId: false, // does not preserve because it's a temporary state\n\thighlightedUserIds: false, // does not preserve because it's a temporary state\n\tbrush: false, // does not preserve because it's a temporary state\n\tcursor: false, // does not preserve because it's a temporary state\n\tscribbles: false, // does not preserve because it's a temporary state\n\n\tisFocusMode: true, // preserves because it's a user preference\n\tisDebugMode: true, // preserves because it's a user preference\n\tisToolLocked: true, // preserves because it's a user preference\n\texportBackground: true, // preserves because it's a user preference\n\tscreenBounds: true, // preserves because it's capturing the user's screen state\n\tinsets: true, // preserves because it's capturing the user's screen state\n\n\tzoomBrush: false, // does not preserve because it's a temporary state\n\tchatMessage: false, // does not preserve because it's a temporary state\n\tisChatting: false, // does not preserve because it's a temporary state\n\tisPenMode: false, // does not preserve because it's a temporary state\n\n\tisGridMode: true, // preserves because it's a user preference\n\tisFocused: true, // preserves because obviously\n\tdevicePixelRatio: true, // preserves because it captures the user's screen state\n\tisCoarsePointer: true, // preserves because it captures the user's screen state\n\tisHoveringCanvas: false, // does not preserve because it's a temporary state\n\topenMenus: false, // does not preserve because it's a temporary state\n\tisChangingStyle: false, // does not preserve because it's a temporary state\n\tisReadonly: true, // preserves because it's a config option\n\tmeta: false, // does not preserve because who knows what's in there, leave it up to sdk users to save and reinstate\n\tduplicateProps: false, //\n\tcameraState: false, // does not preserve because it's a temporary state\n} as const satisfies { [K in keyof TLInstance]: boolean }\n\n/**\n * Extracts only the properties from a TLInstance that should be preserved\n * between browser sessions, filtering out temporary state.\n *\n * @param val - The TLInstance to filter, or null/undefined\n * @returns A partial TLInstance containing only preservable properties, or null\n *\n * @internal\n */\nexport function pluckPreservingValues(val?: TLInstance | null): null | Partial<TLInstance> {\n\treturn val\n\t\t? (filterEntries(val, (key) => {\n\t\t\t\treturn shouldKeyBePreservedBetweenSessions[key as keyof TLInstance]\n\t\t\t}) as Partial<TLInstance>)\n\t\t: null\n}\n\n/**\n * A unique identifier for TLInstance records.\n *\n * TLInstance IDs are always the constant 'instance:instance' since there\n * is exactly one instance record per browser tab.\n *\n * @public\n */\nexport type TLInstanceId = RecordId<TLInstance>\n\n/**\n * Validator for TLInstanceId values. Ensures the ID follows the correct\n * format for instance records.\n *\n * @example\n * ```ts\n * const isValid = instanceIdValidator.isValid('instance:instance') // true\n * const isValid2 = instanceIdValidator.isValid('invalid') // false\n * ```\n *\n * @public\n */\nexport const instanceIdValidator = idValidator<TLInstanceId>('instance')\n\n/**\n * Creates the record type definition for TLInstance records, including validation\n * and default properties. The function takes a map of available style properties\n * to configure validation for the stylesForNextShape field.\n *\n * @param stylesById - Map of style property IDs to their corresponding StyleProp definitions\n * @returns A configured RecordType for TLInstance records\n *\n * @example\n * ```ts\n * const stylesMap = new Map([['color', DefaultColorStyle]])\n * const InstanceRecordType = createInstanceRecordType(stylesMap)\n *\n * const instance = InstanceRecordType.create({\n * id: 'instance:instance',\n * currentPageId: 'page:page1'\n * })\n * ```\n *\n * @public\n */\nexport function createInstanceRecordType(stylesById: Map<string, StyleProp<unknown>>) {\n\tconst stylesForNextShapeValidators = {} as Record<string, T.Validator<unknown>>\n\tfor (const [id, style] of stylesById) {\n\t\tstylesForNextShapeValidators[id] = T.optional(style)\n\t}\n\n\tconst instanceTypeValidator: T.Validator<TLInstance> = T.model(\n\t\t'instance',\n\t\tT.object({\n\t\t\ttypeName: T.literal('instance'),\n\t\t\tid: idValidator<TLInstanceId>('instance'),\n\t\t\tcurrentPageId: pageIdValidator,\n\t\t\tfollowingUserId: userIdValidator.nullable(),\n\t\t\tbrush: boxModelValidator.nullable(),\n\t\t\topacityForNextShape: opacityValidator,\n\t\t\tstylesForNextShape: T.object(stylesForNextShapeValidators),\n\t\t\tcursor: cursorValidator,\n\t\t\tscribbles: T.arrayOf(scribbleValidator),\n\t\t\tisFocusMode: T.boolean,\n\t\t\tisDebugMode: T.boolean,\n\t\t\tisToolLocked: T.boolean,\n\t\t\texportBackground: T.boolean,\n\t\t\tscreenBounds: boxModelValidator,\n\t\t\tinsets: T.arrayOf(T.boolean),\n\t\t\tzoomBrush: boxModelValidator.nullable(),\n\t\t\tisPenMode: T.boolean,\n\t\t\tisGridMode: T.boolean,\n\t\t\tchatMessage: T.string,\n\t\t\tisChatting: T.boolean,\n\t\t\thighlightedUserIds: T.arrayOf(userIdValidator),\n\t\t\tisFocused: T.boolean,\n\t\t\tdevicePixelRatio: T.number,\n\t\t\tisCoarsePointer: T.boolean,\n\t\t\tisHoveringCanvas: T.boolean.nullable(),\n\t\t\topenMenus: T.arrayOf(T.string),\n\t\t\tisChangingStyle: T.boolean,\n\t\t\tisReadonly: T.boolean,\n\t\t\tmeta: T.jsonValue as T.ObjectValidator<JsonObject>,\n\t\t\tduplicateProps: T.object({\n\t\t\t\tshapeIds: T.arrayOf(idValidator<TLShapeId>('shape')),\n\t\t\t\toffset: T.object({\n\t\t\t\t\tx: T.number,\n\t\t\t\t\ty: T.number,\n\t\t\t\t}),\n\t\t\t}).nullable(),\n\t\t\tcameraState: T.literalEnum('idle', 'moving'),\n\t\t})\n\t)\n\n\treturn createRecordType<TLInstance>('instance', {\n\t\tvalidator: instanceTypeValidator,\n\t\tscope: 'session',\n\t\tephemeralKeys: {\n\t\t\tcurrentPageId: false,\n\t\t\tmeta: false,\n\n\t\t\tfollowingUserId: true,\n\t\t\topacityForNextShape: true,\n\t\t\tstylesForNextShape: true,\n\t\t\tbrush: true,\n\t\t\tcursor: true,\n\t\t\tscribbles: true,\n\t\t\tisFocusMode: true,\n\t\t\tisDebugMode: true,\n\t\t\tisToolLocked: true,\n\t\t\texportBackground: true,\n\t\t\tscreenBounds: true,\n\t\t\tinsets: true,\n\t\t\tzoomBrush: true,\n\t\t\tisPenMode: true,\n\t\t\tisGridMode: true,\n\t\t\tchatMessage: true,\n\t\t\tisChatting: true,\n\t\t\thighlightedUserIds: true,\n\t\t\tisFocused: true,\n\t\t\tdevicePixelRatio: true,\n\t\t\tisCoarsePointer: true,\n\t\t\tisHoveringCanvas: true,\n\t\t\topenMenus: true,\n\t\t\tisChangingStyle: true,\n\t\t\tisReadonly: true,\n\t\t\tduplicateProps: true,\n\t\t\tcameraState: true,\n\t\t},\n\t}).withDefaultProperties(\n\t\t(): Omit<TLInstance, 'typeName' | 'id' | 'currentPageId'> => ({\n\t\t\tfollowingUserId: null,\n\t\t\topacityForNextShape: 1,\n\t\t\tstylesForNextShape: {},\n\t\t\tbrush: null,\n\t\t\tscribbles: [],\n\t\t\tcursor: {\n\t\t\t\ttype: 'default',\n\t\t\t\trotation: 0,\n\t\t\t},\n\t\t\tisFocusMode: false,\n\t\t\texportBackground: true,\n\t\t\tisDebugMode: false,\n\t\t\tisToolLocked: false,\n\t\t\tscreenBounds: { x: 0, y: 0, w: 1080, h: 720 },\n\t\t\tinsets: [false, false, false, false],\n\t\t\tzoomBrush: null,\n\t\t\tisGridMode: false,\n\t\t\tisPenMode: false,\n\t\t\tchatMessage: '',\n\t\t\tisChatting: false,\n\t\t\thighlightedUserIds: [],\n\t\t\tisFocused: false,\n\t\t\tdevicePixelRatio: typeof window === 'undefined' ? 1 : window.devicePixelRatio,\n\t\t\tisCoarsePointer: false,\n\t\t\tisHoveringCanvas: null,\n\t\t\topenMenus: [] as string[],\n\t\t\tisChangingStyle: false,\n\t\t\tisReadonly: false,\n\t\t\tmeta: {},\n\t\t\tduplicateProps: null,\n\t\t\tcameraState: 'idle',\n\t\t})\n\t)\n}\n\n/**\n * Migration version identifiers for TLInstance records. Each version represents\n * a schema change that requires data transformation when loading older documents.\n *\n * The versions track the evolution of the instance record structure over time,\n * enabling backward and forward compatibility.\n *\n * @public\n */\nexport const instanceVersions = createMigrationIds('com.tldraw.instance', {\n\tAddTransparentExportBgs: 1,\n\tRemoveDialog: 2,\n\tAddToolLockMode: 3,\n\tRemoveExtraPropsForNextShape: 4,\n\tAddLabelColor: 5,\n\tAddFollowingUserId: 6,\n\tRemoveAlignJustify: 7,\n\tAddZoom: 8,\n\tAddVerticalAlign: 9,\n\tAddScribbleDelay: 10,\n\tRemoveUserId: 11,\n\tAddIsPenModeAndIsGridMode: 12,\n\tHoistOpacity: 13,\n\tAddChat: 14,\n\tAddHighlightedUserIds: 15,\n\tReplacePropsForNextShapeWithStylesForNextShape: 16,\n\tAddMeta: 17,\n\tRemoveCursorColor: 18,\n\tAddLonelyProperties: 19,\n\tReadOnlyReadonly: 20,\n\tAddHoveringCanvas: 21,\n\tAddScribbles: 22,\n\tAddInset: 23,\n\tAddDuplicateProps: 24,\n\tRemoveCanMoveCamera: 25,\n\tAddCameraState: 26,\n} as const)\n\n// TODO: rewrite these to use mutation\n\n/**\n * Migration sequence for TLInstance records. Defines how to transform instance\n * records between different schema versions, ensuring data compatibility when\n * loading documents created with different versions of tldraw.\n *\n * Each migration includes an 'up' function to migrate forward and optionally\n * a 'down' function for reverse migration.\n *\n * @example\n * ```ts\n * // Migrations are applied automatically when loading documents\n * const migratedInstance = instanceMigrations.migrate(oldInstance, targetVersion)\n * ```\n *\n * @public\n */\nexport const instanceMigrations = createRecordMigrationSequence({\n\tsequenceId: 'com.tldraw.instance',\n\trecordType: 'instance',\n\tsequence: [\n\t\t{\n\t\t\tid: instanceVersions.AddTransparentExportBgs,\n\t\t\tup: (instance) => {\n\t\t\t\treturn { ...instance, exportBackground: true }\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tid: instanceVersions.RemoveDialog,\n\t\t\tup: ({ dialog: _, ...instance }: any) => {\n\t\t\t\treturn instance\n\t\t\t},\n\t\t},\n\n\t\t{\n\t\t\tid: instanceVersions.AddToolLockMode,\n\t\t\tup: (instance) => {\n\t\t\t\treturn { ...instance, isToolLocked: false }\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tid: instanceVersions.RemoveExtraPropsForNextShape,\n\t\t\tup: ({ propsForNextShape, ...instance }: any) => {\n\t\t\t\treturn {\n\t\t\t\t\t...instance,\n\t\t\t\t\tpropsForNextShape: Object.fromEntries(\n\t\t\t\t\t\tObject.entries(propsForNextShape).filter(([key]) =>\n\t\t\t\t\t\t\t[\n\t\t\t\t\t\t\t\t'color',\n\t\t\t\t\t\t\t\t'labelColor',\n\t\t\t\t\t\t\t\t'dash',\n\t\t\t\t\t\t\t\t'fill',\n\t\t\t\t\t\t\t\t'size',\n\t\t\t\t\t\t\t\t'font',\n\t\t\t\t\t\t\t\t'align',\n\t\t\t\t\t\t\t\t'verticalAlign',\n\t\t\t\t\t\t\t\t'icon',\n\t\t\t\t\t\t\t\t'geo',\n\t\t\t\t\t\t\t\t'arrowheadStart',\n\t\t\t\t\t\t\t\t'arrowheadEnd',\n\t\t\t\t\t\t\t\t'spline',\n\t\t\t\t\t\t\t].includes(key)\n\t\t\t\t\t\t)\n\t\t\t\t\t),\n\t\t\t\t}\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tid: instanceVersions.AddLabelColor,\n\t\t\tup: ({ propsForNextShape, ...instance }: any) => {\n\t\t\t\treturn {\n\t\t\t\t\t...instance,\n\t\t\t\t\tpropsForNextShape: {\n\t\t\t\t\t\t...propsForNextShape,\n\t\t\t\t\t\tlabelColor: 'black',\n\t\t\t\t\t},\n\t\t\t\t}\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tid: instanceVersions.AddFollowingUserId,\n\t\t\tup: (instance) => {\n\t\t\t\treturn { ...instance, followingUserId: null }\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tid: instanceVersions.RemoveAlignJustify,\n\t\t\tup: (instance: any) => {\n\t\t\t\tlet newAlign = instance.propsForNextShape.align\n\t\t\t\tif (newAlign === 'justify') {\n\t\t\t\t\tnewAlign = 'start'\n\t\t\t\t}\n\n\t\t\t\treturn {\n\t\t\t\t\t...instance,\n\t\t\t\t\tpropsForNextShape: {\n\t\t\t\t\t\t...instance.propsForNextShape,\n\t\t\t\t\t\talign: newAlign,\n\t\t\t\t\t},\n\t\t\t\t}\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tid: instanceVersions.AddZoom,\n\t\t\tup: (instance) => {\n\t\t\t\treturn { ...instance, zoomBrush: null }\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tid: instanceVersions.AddVerticalAlign,\n\t\t\tup: (instance: any) => {\n\t\t\t\treturn {\n\t\t\t\t\t...instance,\n\t\t\t\t\tpropsForNextShape: {\n\t\t\t\t\t\t...instance.propsForNextShape,\n\t\t\t\t\t\tverticalAlign: 'middle',\n\t\t\t\t\t},\n\t\t\t\t}\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tid: instanceVersions.AddScribbleDelay,\n\t\t\tup: (instance: any) => {\n\t\t\t\tif (instance.scribble !== null) {\n\t\t\t\t\treturn { ...instance, scribble: { ...instance.scribble, delay: 0 } }\n\t\t\t\t}\n\t\t\t\treturn { ...instance }\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tid: instanceVersions.RemoveUserId,\n\t\t\tup: ({ userId: _, ...instance }: any) => {\n\t\t\t\treturn instance\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tid: instanceVersions.AddIsPenModeAndIsGridMode,\n\t\t\tup: (instance) => {\n\t\t\t\treturn { ...instance, isPenMode: false, isGridMode: false }\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tid: instanceVersions.HoistOpacity,\n\t\t\tup: ({ propsForNextShape: { opacity, ...propsForNextShape }, ...instance }: any) => {\n\t\t\t\treturn { ...instance, opacityForNextShape: Number(opacity ?? '1'), propsForNextShape }\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tid: instanceVersions.AddChat,\n\t\t\tup: (instance) => {\n\t\t\t\treturn { ...instance, chatMessage: '', isChatting: false }\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tid: instanceVersions.AddHighlightedUserIds,\n\t\t\tup: (instance) => {\n\t\t\t\treturn { ...instance, highlightedUserIds: [] }\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tid: instanceVersions.ReplacePropsForNextShapeWithStylesForNextShape,\n\t\t\tup: ({ propsForNextShape: _, ...instance }: any) => {\n\t\t\t\treturn { ...instance, stylesForNextShape: {} }\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tid: instanceVersions.AddMeta,\n\t\t\tup: (record) => {\n\t\t\t\treturn {\n\t\t\t\t\t...record,\n\t\t\t\t\tmeta: {},\n\t\t\t\t}\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tid: instanceVersions.RemoveCursorColor,\n\t\t\tup: (record: any) => {\n\t\t\t\tconst { color: _, ...cursor } = record.cursor\n\t\t\t\treturn {\n\t\t\t\t\t...record,\n\t\t\t\t\tcursor,\n\t\t\t\t}\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tid: instanceVersions.AddLonelyProperties,\n\t\t\tup: (record) => {\n\t\t\t\treturn {\n\t\t\t\t\t...record,\n\t\t\t\t\tcanMoveCamera: true,\n\t\t\t\t\tisFocused: false,\n\t\t\t\t\tdevicePixelRatio: 1,\n\t\t\t\t\tisCoarsePointer: false,\n\t\t\t\t\topenMenus: [],\n\t\t\t\t\tisChangingStyle: false,\n\t\t\t\t\tisReadOnly: false,\n\t\t\t\t}\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tid: instanceVersions.ReadOnlyReadonly,\n\t\t\tup: ({ isReadOnly: _isReadOnly, ...record }: any) => {\n\t\t\t\treturn {\n\t\t\t\t\t...record,\n\t\t\t\t\tisReadonly: _isReadOnly,\n\t\t\t\t}\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tid: instanceVersions.AddHoveringCanvas,\n\t\t\tup: (record) => {\n\t\t\t\treturn {\n\t\t\t\t\t...record,\n\t\t\t\t\tisHoveringCanvas: null,\n\t\t\t\t}\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tid: instanceVersions.AddScribbles,\n\t\t\tup: ({ scribble: _, ...record }: any) => {\n\t\t\t\treturn {\n\t\t\t\t\t...record,\n\t\t\t\t\tscribbles: [],\n\t\t\t\t}\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tid: instanceVersions.AddInset,\n\t\t\tup: (record) => {\n\t\t\t\treturn {\n\t\t\t\t\t...record,\n\t\t\t\t\tinsets: [false, false, false, false],\n\t\t\t\t}\n\t\t\t},\n\t\t\tdown: ({ insets: _, ...record }: any) => {\n\t\t\t\treturn {\n\t\t\t\t\t...record,\n\t\t\t\t}\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tid: instanceVersions.AddDuplicateProps,\n\t\t\tup: (record) => {\n\t\t\t\treturn {\n\t\t\t\t\t...record,\n\t\t\t\t\tduplicateProps: null,\n\t\t\t\t}\n\t\t\t},\n\t\t\tdown: ({ duplicateProps: _, ...record }: any) => {\n\t\t\t\treturn {\n\t\t\t\t\t...record,\n\t\t\t\t}\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tid: instanceVersions.RemoveCanMoveCamera,\n\t\t\tup: ({ canMoveCamera: _, ...record }: any) => {\n\t\t\t\treturn {\n\t\t\t\t\t...record,\n\t\t\t\t}\n\t\t\t},\n\t\t\tdown: (instance) => {\n\t\t\t\treturn { ...instance, canMoveCamera: true }\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tid: instanceVersions.AddCameraState,\n\t\t\tup: (record) => {\n\t\t\t\treturn { ...record, cameraState: 'idle' }\n\t\t\t},\n\t\t\tdown: ({ cameraState: _, ...record }: any) => {\n\t\t\t\treturn record\n\t\t\t},\n\t\t},\n\t],\n})\n\n/**\n * The constant ID used for the singleton TLInstance record.\n *\n * Since each browser tab has exactly one instance, this constant ID\n * is used universally across the application.\n *\n * @example\n * ```ts\n * const instance = store.get(TLINSTANCE_ID)\n * if (instance) {\n * console.log('Current page:', instance.currentPageId)\n * }\n * ```\n *\n * @public\n */\nexport const TLINSTANCE_ID = 'instance:instance' as TLInstanceId\n"],
5
5
  "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -19,6 +19,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
19
19
  var TLPage_exports = {};
20
20
  __export(TLPage_exports, {
21
21
  PageRecordType: () => PageRecordType,
22
+ isPage: () => isPage,
22
23
  isPageId: () => isPageId,
23
24
  pageIdValidator: () => pageIdValidator,
24
25
  pageMigrations: () => pageMigrations,
@@ -61,6 +62,10 @@ const PageRecordType = (0, import_store.createRecordType)("page", {
61
62
  }).withDefaultProperties(() => ({
62
63
  meta: {}
63
64
  }));
65
+ function isPage(record) {
66
+ if (!record) return false;
67
+ return record.typeName === "page";
68
+ }
64
69
  function isPageId(id) {
65
70
  return PageRecordType.isId(id);
66
71
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/records/TLPage.ts"],
4
- "sourcesContent": ["import {\n\tBaseRecord,\n\tcreateMigrationIds,\n\tcreateRecordMigrationSequence,\n\tcreateRecordType,\n\tRecordId,\n} from '@tldraw/store'\nimport { IndexKey, JsonObject } from '@tldraw/utils'\nimport { T } from '@tldraw/validate'\nimport { idValidator } from '../misc/id-validator'\n\n/**\n * A page within a tldraw document. Pages are containers for shapes and provide\n * a way to organize content into separate canvases. Each document can have multiple\n * pages, and users can navigate between them.\n *\n * Pages have a name for identification, an index for ordering, and can store\n * custom metadata.\n *\n * @example\n * ```ts\n * const page: TLPage = {\n * id: 'page:page1',\n * typeName: 'page',\n * name: 'Page 1',\n * index: 'a1',\n * meta: { description: 'Main design page' }\n * }\n * ```\n *\n * @public\n */\nexport interface TLPage extends BaseRecord<'page', TLPageId> {\n\tname: string\n\tindex: IndexKey\n\tmeta: JsonObject\n}\n\n/**\n * A unique identifier for TLPage records.\n *\n * Page IDs follow the format 'page:' followed by a unique string identifier.\n *\n * @example\n * ```ts\n * const pageId: TLPageId = 'page:main'\n * const pageId2: TLPageId = createShapeId() // generates 'page:abc123'\n * ```\n *\n * @public\n */\nexport type TLPageId = RecordId<TLPage>\n\n/**\n * Validator for TLPageId values. Ensures the ID follows the correct\n * format for page records ('page:' prefix).\n *\n * @example\n * ```ts\n * const isValid = pageIdValidator.isValid('page:main') // true\n * const isValid2 = pageIdValidator.isValid('shape:abc') // false\n * ```\n *\n * @public\n */\nexport const pageIdValidator = idValidator<TLPageId>('page')\n\n/**\n * Runtime validator for TLPage records. Validates the structure and types\n * of all page properties to ensure data integrity.\n *\n * @example\n * ```ts\n * const page = { id: 'page:1', typeName: 'page', name: 'My Page', index: 'a1', meta: {} }\n * const isValid = pageValidator.isValid(page) // true\n * ```\n *\n * @public\n */\nexport const pageValidator: T.Validator<TLPage> = T.model(\n\t'page',\n\tT.object({\n\t\ttypeName: T.literal('page'),\n\t\tid: pageIdValidator,\n\t\tname: T.string,\n\t\tindex: T.indexKey,\n\t\tmeta: T.jsonValue as T.ObjectValidator<JsonObject>,\n\t})\n)\n\n/**\n * Migration version identifiers for TLPage records. Each version represents\n * a schema change that requires data transformation when loading older documents.\n *\n * @public\n */\nexport const pageVersions = createMigrationIds('com.tldraw.page', {\n\tAddMeta: 1,\n})\n\n/**\n * Migration sequence for TLPage records. Defines how to transform page\n * records between different schema versions, ensuring data compatibility.\n *\n * @example\n * ```ts\n * // Migrations are applied automatically when loading documents\n * const migratedPage = pageMigrations.migrate(oldPage, targetVersion)\n * ```\n *\n * @public\n */\nexport const pageMigrations = createRecordMigrationSequence({\n\tsequenceId: 'com.tldraw.page',\n\trecordType: 'page',\n\tsequence: [\n\t\t{\n\t\t\tid: pageVersions.AddMeta,\n\t\t\tup: (record: any) => {\n\t\t\t\trecord.meta = {}\n\t\t\t},\n\t\t},\n\t],\n})\n\n/**\n * The RecordType definition for TLPage records. Defines validation, scope,\n * and default properties for page records in the tldraw store.\n *\n * Pages are scoped to the document level, meaning they persist across sessions\n * and are shared in collaborative environments.\n *\n * @example\n * ```ts\n * const page = PageRecordType.create({\n * id: 'page:main',\n * name: 'Main Page',\n * index: 'a1'\n * })\n * ```\n *\n * @public\n */\nexport const PageRecordType = createRecordType<TLPage>('page', {\n\tvalidator: pageValidator,\n\tscope: 'document',\n}).withDefaultProperties(() => ({\n\tmeta: {},\n}))\n\n/**\n * Type guard to check if a string is a valid TLPageId.\n *\n * @param id - The string to check\n * @returns True if the ID is a valid page ID, false otherwise\n *\n * @example\n * ```ts\n * if (isPageId('page:main')) {\n * // TypeScript knows this is a TLPageId\n * console.log('Valid page ID')\n * }\n * ```\n *\n * @public\n */\nexport function isPageId(id: string): id is TLPageId {\n\treturn PageRecordType.isId(id)\n}\n"],
5
- "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mBAMO;AAEP,sBAAkB;AAClB,0BAA4B;AAwDrB,MAAM,sBAAkB,iCAAsB,MAAM;AAcpD,MAAM,gBAAqC,kBAAE;AAAA,EACnD;AAAA,EACA,kBAAE,OAAO;AAAA,IACR,UAAU,kBAAE,QAAQ,MAAM;AAAA,IAC1B,IAAI;AAAA,IACJ,MAAM,kBAAE;AAAA,IACR,OAAO,kBAAE;AAAA,IACT,MAAM,kBAAE;AAAA,EACT,CAAC;AACF;AAQO,MAAM,mBAAe,iCAAmB,mBAAmB;AAAA,EACjE,SAAS;AACV,CAAC;AAcM,MAAM,qBAAiB,4CAA8B;AAAA,EAC3D,YAAY;AAAA,EACZ,YAAY;AAAA,EACZ,UAAU;AAAA,IACT;AAAA,MACC,IAAI,aAAa;AAAA,MACjB,IAAI,CAAC,WAAgB;AACpB,eAAO,OAAO,CAAC;AAAA,MAChB;AAAA,IACD;AAAA,EACD;AACD,CAAC;AAoBM,MAAM,qBAAiB,+BAAyB,QAAQ;AAAA,EAC9D,WAAW;AAAA,EACX,OAAO;AACR,CAAC,EAAE,sBAAsB,OAAO;AAAA,EAC/B,MAAM,CAAC;AACR,EAAE;AAkBK,SAAS,SAAS,IAA4B;AACpD,SAAO,eAAe,KAAK,EAAE;AAC9B;",
4
+ "sourcesContent": ["import {\n\tBaseRecord,\n\tcreateMigrationIds,\n\tcreateRecordMigrationSequence,\n\tcreateRecordType,\n\tRecordId,\n\tUnknownRecord,\n} from '@tldraw/store'\nimport { IndexKey, JsonObject } from '@tldraw/utils'\nimport { T } from '@tldraw/validate'\nimport { idValidator } from '../misc/id-validator'\n\n/**\n * A page within a tldraw document. Pages are containers for shapes and provide\n * a way to organize content into separate canvases. Each document can have multiple\n * pages, and users can navigate between them.\n *\n * Pages have a name for identification, an index for ordering, and can store\n * custom metadata.\n *\n * @example\n * ```ts\n * const page: TLPage = {\n * id: 'page:page1',\n * typeName: 'page',\n * name: 'Page 1',\n * index: 'a1',\n * meta: { description: 'Main design page' }\n * }\n * ```\n *\n * @public\n */\nexport interface TLPage extends BaseRecord<'page', TLPageId> {\n\tname: string\n\tindex: IndexKey\n\tmeta: JsonObject\n}\n\n/**\n * A unique identifier for TLPage records.\n *\n * Page IDs follow the format 'page:' followed by a unique string identifier.\n *\n * @example\n * ```ts\n * const pageId: TLPageId = 'page:main'\n * const pageId2: TLPageId = createShapeId() // generates 'page:abc123'\n * ```\n *\n * @public\n */\nexport type TLPageId = RecordId<TLPage>\n\n/**\n * Validator for TLPageId values. Ensures the ID follows the correct\n * format for page records ('page:' prefix).\n *\n * @example\n * ```ts\n * const isValid = pageIdValidator.isValid('page:main') // true\n * const isValid2 = pageIdValidator.isValid('shape:abc') // false\n * ```\n *\n * @public\n */\nexport const pageIdValidator = idValidator<TLPageId>('page')\n\n/**\n * Runtime validator for TLPage records. Validates the structure and types\n * of all page properties to ensure data integrity.\n *\n * @example\n * ```ts\n * const page = { id: 'page:1', typeName: 'page', name: 'My Page', index: 'a1', meta: {} }\n * const isValid = pageValidator.isValid(page) // true\n * ```\n *\n * @public\n */\nexport const pageValidator: T.Validator<TLPage> = T.model(\n\t'page',\n\tT.object({\n\t\ttypeName: T.literal('page'),\n\t\tid: pageIdValidator,\n\t\tname: T.string,\n\t\tindex: T.indexKey,\n\t\tmeta: T.jsonValue as T.ObjectValidator<JsonObject>,\n\t})\n)\n\n/**\n * Migration version identifiers for TLPage records. Each version represents\n * a schema change that requires data transformation when loading older documents.\n *\n * @public\n */\nexport const pageVersions = createMigrationIds('com.tldraw.page', {\n\tAddMeta: 1,\n})\n\n/**\n * Migration sequence for TLPage records. Defines how to transform page\n * records between different schema versions, ensuring data compatibility.\n *\n * @example\n * ```ts\n * // Migrations are applied automatically when loading documents\n * const migratedPage = pageMigrations.migrate(oldPage, targetVersion)\n * ```\n *\n * @public\n */\nexport const pageMigrations = createRecordMigrationSequence({\n\tsequenceId: 'com.tldraw.page',\n\trecordType: 'page',\n\tsequence: [\n\t\t{\n\t\t\tid: pageVersions.AddMeta,\n\t\t\tup: (record: any) => {\n\t\t\t\trecord.meta = {}\n\t\t\t},\n\t\t},\n\t],\n})\n\n/**\n * The RecordType definition for TLPage records. Defines validation, scope,\n * and default properties for page records in the tldraw store.\n *\n * Pages are scoped to the document level, meaning they persist across sessions\n * and are shared in collaborative environments.\n *\n * @example\n * ```ts\n * const page = PageRecordType.create({\n * id: 'page:main',\n * name: 'Main Page',\n * index: 'a1'\n * })\n * ```\n *\n * @public\n */\nexport const PageRecordType = createRecordType<TLPage>('page', {\n\tvalidator: pageValidator,\n\tscope: 'document',\n}).withDefaultProperties(() => ({\n\tmeta: {},\n}))\n\n/**\n * Type guard to check if a record is a page.\n *\n * @param record - The record to check\n * @returns True if the record is a page, false otherwise\n *\n * @example\n * ```ts\n * const record = store.get('page:abc123')\n\n * if (isPage(record)) {\n * console.log(`Page name: ${record.name}`)\n * }\n * ```\n *\n * @public\n */\nexport function isPage(record?: UnknownRecord): record is TLPage {\n\tif (!record) return false\n\treturn record.typeName === 'page'\n}\n\n/**\n * Type guard to check if a string is a valid TLPageId.\n *\n * @param id - The string to check\n * @returns True if the ID is a valid page ID, false otherwise\n *\n * @example\n * ```ts\n * if (isPageId('page:main')) {\n * // TypeScript knows this is a TLPageId\n * console.log('Valid page ID')\n * }\n * ```\n *\n * @public\n */\nexport function isPageId(id: string): id is TLPageId {\n\treturn PageRecordType.isId(id)\n}\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mBAOO;AAEP,sBAAkB;AAClB,0BAA4B;AAwDrB,MAAM,sBAAkB,iCAAsB,MAAM;AAcpD,MAAM,gBAAqC,kBAAE;AAAA,EACnD;AAAA,EACA,kBAAE,OAAO;AAAA,IACR,UAAU,kBAAE,QAAQ,MAAM;AAAA,IAC1B,IAAI;AAAA,IACJ,MAAM,kBAAE;AAAA,IACR,OAAO,kBAAE;AAAA,IACT,MAAM,kBAAE;AAAA,EACT,CAAC;AACF;AAQO,MAAM,mBAAe,iCAAmB,mBAAmB;AAAA,EACjE,SAAS;AACV,CAAC;AAcM,MAAM,qBAAiB,4CAA8B;AAAA,EAC3D,YAAY;AAAA,EACZ,YAAY;AAAA,EACZ,UAAU;AAAA,IACT;AAAA,MACC,IAAI,aAAa;AAAA,MACjB,IAAI,CAAC,WAAgB;AACpB,eAAO,OAAO,CAAC;AAAA,MAChB;AAAA,IACD;AAAA,EACD;AACD,CAAC;AAoBM,MAAM,qBAAiB,+BAAyB,QAAQ;AAAA,EAC9D,WAAW;AAAA,EACX,OAAO;AACR,CAAC,EAAE,sBAAsB,OAAO;AAAA,EAC/B,MAAM,CAAC;AACR,EAAE;AAmBK,SAAS,OAAO,QAA0C;AAChE,MAAI,CAAC,OAAQ,QAAO;AACpB,SAAO,OAAO,aAAa;AAC5B;AAkBO,SAAS,SAAS,IAA4B;AACpD,SAAO,eAAe,KAAK,EAAE;AAC9B;",
6
6
  "names": []
7
7
  }
@@ -84,8 +84,7 @@ function createIntegrityChecker(store) {
84
84
  store.put([
85
85
  store.schema.types.instance.create({
86
86
  id: TLINSTANCE_ID,
87
- currentPageId: getFirstPageId(),
88
- exportBackground: true
87
+ currentPageId: getFirstPageId()
89
88
  })
90
89
  ]);
91
90
  return ensureStoreIsUsable();
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/TLStore.ts"],
4
- "sourcesContent": ["import { Signal, computed } from '@tldraw/state'\nimport {\n\tSerializedStore,\n\tStore,\n\tStoreSchema,\n\tStoreSnapshot,\n\tStoreValidationFailure,\n} from '@tldraw/store'\nimport { IndexKey, JsonObject, annotateError, sortByIndex, structuredClone } from '@tldraw/utils'\nimport { TLAsset, TLAssetId } from './records/TLAsset'\nimport { CameraRecordType, TLCameraId } from './records/TLCamera'\nimport { DocumentRecordType, TLDOCUMENT_ID } from './records/TLDocument'\nimport { TLINSTANCE_ID } from './records/TLInstance'\nimport { PageRecordType, TLPageId } from './records/TLPage'\nimport { InstancePageStateRecordType, TLInstancePageStateId } from './records/TLPageState'\nimport { PointerRecordType, TLPOINTER_ID } from './records/TLPointer'\nimport { TLRecord } from './records/TLRecord'\nimport { TLUser } from './records/TLUser'\n\n/**\n * Redacts the source of an asset record for error reporting.\n *\n * @param record - The asset record to redact\n * @returns The redacted record\n * @internal\n */\nexport function redactRecordForErrorReporting(record: any) {\n\tif (record.typeName === 'asset') {\n\t\tif ('src' in record) {\n\t\t\trecord.src = '<redacted>'\n\t\t}\n\n\t\tif ('src' in record.props) {\n\t\t\trecord.props.src = '<redacted>'\n\t\t}\n\t}\n}\n\n/**\n * The complete schema type for a tldraw store, defining the structure and validation rules\n * for all tldraw records and store properties.\n *\n * @public\n * @example\n * ```ts\n * import { createTLSchema } from '@tldraw/tlschema'\n *\n * const schema = createTLSchema()\n * const storeSchema: TLStoreSchema = schema\n * ```\n */\nexport type TLStoreSchema = StoreSchema<TLRecord, TLStoreProps>\n\n/**\n * A serialized representation of a tldraw store that can be persisted or transmitted.\n * Contains all store records in a JSON-serializable format.\n *\n * @public\n * @example\n * ```ts\n * // Serialize a store\n * const serializedStore: TLSerializedStore = store.serialize()\n *\n * // Save to localStorage\n * localStorage.setItem('drawing', JSON.stringify(serializedStore))\n * ```\n */\nexport type TLSerializedStore = SerializedStore<TLRecord>\n\n/**\n * A snapshot of a tldraw store at a specific point in time, containing all records\n * and metadata. Used for persistence, synchronization, and creating store backups.\n *\n * @public\n * @example\n * ```ts\n * // Create a snapshot\n * const snapshot: TLStoreSnapshot = store.getSnapshot()\n *\n * // Restore from snapshot\n * store.loadSnapshot(snapshot)\n * ```\n */\nexport type TLStoreSnapshot = StoreSnapshot<TLRecord>\n\n/**\n * Context information provided when resolving asset URLs, containing details about\n * the current rendering environment and user's connection to optimize asset delivery.\n *\n * @public\n * @example\n * ```ts\n * const assetStore: TLAssetStore = {\n * async resolve(asset, context: TLAssetContext) {\n * // Use low resolution for slow connections\n * if (context.networkEffectiveType === 'slow-2g') {\n * return `${asset.props.src}?quality=low`\n * }\n * // Use high DPI version for retina displays\n * if (context.dpr > 1) {\n * return `${asset.props.src}@2x`\n * }\n * return asset.props.src\n * }\n * }\n * ```\n */\nexport interface TLAssetContext {\n\t/**\n\t * The scale at which the asset is being rendered on-screen relative to its native dimensions.\n\t * If the asset is 1000px wide, but it's been resized/zoom so it takes 500px on-screen, this\n\t * will be 0.5.\n\t *\n\t * The scale measures CSS pixels, not device pixels.\n\t */\n\tscreenScale: number\n\t/** The {@link TLAssetContext.screenScale}, stepped to the nearest power-of-2 multiple. */\n\tsteppedScreenScale: number\n\t/** The device pixel ratio - how many CSS pixels are in one device pixel? */\n\tdpr: number\n\t/**\n\t * An alias for\n\t * {@link https://developer.mozilla.org/en-US/docs/Web/API/NetworkInformation/effectiveType | `navigator.connection.effectiveType` }\n\t * if it's available in the current browser. Use this to e.g. serve lower-resolution images to\n\t * users on slow connections.\n\t */\n\tnetworkEffectiveType: string | null\n\t/**\n\t * In some circumstances, we need to resolve a URL that points to the original version of a\n\t * particular asset. This is used when the asset will leave the current tldraw instance - e.g.\n\t * for copy/paste, or exports.\n\t */\n\tshouldResolveToOriginal: boolean\n}\n\n/**\n * Interface for storing and managing assets (images, videos, etc.) in tldraw.\n * Provides methods for uploading, resolving, and removing assets from storage.\n *\n * A `TLAssetStore` sits alongside the main {@link TLStore} and is responsible for storing and\n * retrieving large assets such as images. Generally, this should be part of a wider sync system:\n *\n * - By default, the store is in-memory only, so `TLAssetStore` converts images to data URLs\n * - When using\n * {@link @tldraw/editor#TldrawEditorWithoutStoreProps.persistenceKey | `persistenceKey`}, the\n * store is synced to the browser's local IndexedDB, so `TLAssetStore` stores images there too\n * - When using a multiplayer sync server, you would implement `TLAssetStore` to upload images to\n * e.g. an S3 bucket.\n *\n * @public\n * @example\n * ```ts\n * // Simple in-memory asset store\n * const assetStore: TLAssetStore = {\n * async upload(asset, file) {\n * const dataUrl = await fileToDataUrl(file)\n * return { src: dataUrl }\n * },\n *\n * async resolve(asset, context) {\n * return asset.props.src\n * },\n *\n * async remove(assetIds) {\n * // Clean up if needed\n * }\n * }\n * ```\n */\nexport interface TLAssetStore {\n\t/**\n\t * Upload an asset to your storage, returning a URL that can be used to refer to the asset\n\t * long-term.\n\t *\n\t * @param asset - Information & metadata about the asset being uploaded\n\t * @param file - The `File` to be uploaded\n\t * @returns A promise that resolves to the URL of the uploaded asset\n\t */\n\tupload(\n\t\tasset: TLAsset,\n\t\tfile: File,\n\t\tabortSignal?: AbortSignal\n\t): Promise<{ src: string; meta?: JsonObject }>\n\t/**\n\t * Resolve an asset to a URL. This is used when rendering the asset in the editor. By default,\n\t * this will just use `asset.props.src`, the URL returned by `upload()`. This can be used to\n\t * rewrite that URL to add access credentials, or optimized the asset for how it's currently\n\t * being displayed using the {@link TLAssetContext | information provided}.\n\t *\n\t * @param asset - the asset being resolved\n\t * @param ctx - information about the current environment and where the asset is being used\n\t * @returns The URL of the resolved asset, or `null` if the asset is not available\n\t */\n\tresolve?(asset: TLAsset, ctx: TLAssetContext): Promise<string | null> | string | null\n\t/**\n\t * Remove an asset from storage. This is called when the asset is no longer needed, e.g. when\n\t * the user deletes it from the editor.\n\t * @param asset - the asset being removed\n\t * @returns A promise that resolves when the asset has been removed\n\t */\n\tremove?(assetIds: TLAssetId[]): Promise<void>\n}\n\n/**\n * Interface for resolving user information in tldraw.\n *\n * A `TLUserStore` sits alongside the main {@link TLStore} and provides user\n * resolution for attribution labels and display names. Implement this interface\n * to connect tldraw to your auth/user system.\n *\n * `currentUser` and `resolve` are reactive {@link @tldraw/state#Signal | Signals}\n * so that the editor can automatically track changes to user data and\n * re-render when a user's name, color, or avatar updates.\n *\n * Implementations should cache signals returned by `resolve` \u2014 e.g. return the\n * same `Signal` for repeated calls with the same `userId` \u2014 to avoid\n * unnecessary re-computation.\n *\n * @public\n * @example\n * ```ts\n * const currentUser = computed('currentUser', () =>\n * UserRecordType.create({\n * id: createUserId(myAuth.userId),\n * name: myAuth.displayName,\n * color: myAuth.color,\n * })\n * )\n *\n * const userStore: TLUserStore = {\n * currentUser,\n * resolve(userId) {\n * return computed('resolve-' + userId, () =>\n * myUserCache.get(userId) ?? null\n * )\n * },\n * }\n * ```\n */\nexport interface TLUserStore {\n\t/**\n\t * A signal resolving to the currently authenticated user,\n\t * or `null` for anonymous / unknown.\n\t * Read when stamping attribution on shape create/update.\n\t */\n\tcurrentUser: Signal<TLUser | null>\n\n\t/**\n\t * Return a signal resolving an arbitrary user ID to display info.\n\t * Called when rendering attribution labels for shapes that may have been\n\t * created or edited by someone else.\n\t * The signal's value should be `null` if the user cannot be resolved.\n\t */\n\tresolve?(userId: string): Signal<TLUser | null>\n}\n\n/**\n * Create a cached {@link TLUserStore.resolve} implementation.\n *\n * Wraps a reactive lookup function so that each `userId` gets a single\n * stable {@link @tldraw/state#Signal | Signal} that is reused across calls.\n * The `resolveFn` is evaluated inside a `computed`, so any `.get()` calls\n * it makes are automatically tracked.\n *\n * @param resolveFn - A function that resolves a raw user-ID string to a\n * {@link TLUser} or `null`. Called reactively inside a `computed`.\n * @returns A function suitable for use as `TLUserStore.resolve`.\n *\n * @example\n * ```ts\n * const users: TLUserStore = {\n * currentUser: currentUserSignal,\n * resolve: createCachedUserResolve(\n * (userId) => usersAtom.get()[createUserId(userId)] ?? null\n * ),\n * }\n * ```\n *\n * @public\n */\nexport function createCachedUserResolve(\n\tresolveFn: (userId: string) => TLUser | null\n): (userId: string) => Signal<TLUser | null> {\n\tconst cache = new Map<string, Signal<TLUser | null>>()\n\treturn (userId: string) => {\n\t\tlet signal = cache.get(userId)\n\t\tif (!signal) {\n\t\t\tsignal = computed('resolve-user-' + userId, () => resolveFn(userId))\n\t\t\tcache.set(userId, signal)\n\t\t}\n\t\treturn signal\n\t}\n}\n\n/**\n * Configuration properties for a tldraw store, defining its behavior and integrations.\n * These props are passed when creating a new store instance.\n *\n * @public\n * @example\n * ```ts\n * const storeProps: TLStoreProps = {\n * defaultName: 'My Drawing',\n * assets: myAssetStore,\n * onMount: (editor) => {\n * console.log('Editor mounted')\n * return () => console.log('Editor unmounted')\n * },\n * collaboration: {\n * status: statusSignal,\n * mode: modeSignal\n * }\n * }\n *\n * const store = new Store({ schema, props: storeProps })\n * ```\n */\nexport interface TLStoreProps {\n\t/** Default name for new documents created in this store */\n\tdefaultName: string\n\t/** Asset store implementation for handling file uploads and storage */\n\tassets: Required<TLAssetStore>\n\t/** User store implementation for user resolution and attribution */\n\tusers: Required<TLUserStore>\n\t/**\n\t * Called when an {@link @tldraw/editor#Editor} connected to this store is mounted.\n\t * Can optionally return a cleanup function that will be called when unmounted.\n\t *\n\t * @param editor - The editor instance that was mounted\n\t * @returns Optional cleanup function\n\t */\n\tonMount(editor: unknown): void | (() => void)\n\t/** Optional collaboration configuration for multiplayer features */\n\tcollaboration?: {\n\t\t/** Signal indicating online/offline collaboration status */\n\t\tstatus: Signal<'online' | 'offline'> | null\n\t\t/** Signal indicating collaboration mode permissions */\n\t\tmode?: Signal<'readonly' | 'readwrite'> | null\n\t}\n}\n\n/**\n * The main tldraw store type, representing a reactive database of tldraw records\n * with associated store properties. This is the central data structure that holds\n * all shapes, assets, pages, and user state.\n *\n * @public\n * @example\n * ```ts\n * import { Store } from '@tldraw/store'\n * import { createTLSchema } from '@tldraw/tlschema'\n *\n * const schema = createTLSchema()\n * const store: TLStore = new Store({\n * schema,\n * props: {\n * defaultName: 'Untitled',\n * assets: myAssetStore,\n * onMount: () => console.log('Store mounted')\n * }\n * })\n * ```\n */\nexport type TLStore = Store<TLRecord, TLStoreProps>\n\n/**\n * Default validation failure handler for tldraw stores. This function is called\n * when a record fails validation during store operations. It annotates errors\n * with debugging information and determines whether to allow invalid records\n * during store initialization.\n *\n * @param options - The validation failure details\n * - error - The validation error that occurred\n * - phase - The store operation phase when validation failed\n * - record - The invalid record that caused the failure\n * - recordBefore - The previous state of the record (if applicable)\n * @returns The record to use (typically throws the annotated error)\n * @throws The original validation error with additional debugging context\n *\n * @public\n * @example\n * ```ts\n * const store = new Store({\n * schema,\n * props: storeProps,\n * onValidationFailure // Use this as the validation failure handler\n * })\n *\n * // The handler will be called automatically when validation fails\n * try {\n * store.put([invalidRecord])\n * } catch (error) {\n * // Error will contain debugging information added by onValidationFailure\n * }\n * ```\n */\nexport function onValidationFailure({\n\terror,\n\tphase,\n\trecord,\n\trecordBefore,\n}: StoreValidationFailure<TLRecord>): TLRecord {\n\tconst isExistingValidationIssue =\n\t\t// if we're initializing the store for the first time, we should\n\t\t// allow invalid records so people can load old buggy data:\n\t\tphase === 'initialize'\n\n\tannotateError(error, {\n\t\ttags: {\n\t\t\torigin: 'store.validateRecord',\n\t\t\tstorePhase: phase,\n\t\t\tisExistingValidationIssue,\n\t\t},\n\t\textras: {\n\t\t\trecordBefore: recordBefore\n\t\t\t\t? redactRecordForErrorReporting(structuredClone(recordBefore))\n\t\t\t\t: undefined,\n\t\t\trecordAfter: redactRecordForErrorReporting(structuredClone(record)),\n\t\t},\n\t})\n\n\tthrow error\n}\n\nfunction getDefaultPages() {\n\treturn [\n\t\tPageRecordType.create({\n\t\t\tid: 'page:page' as TLPageId,\n\t\t\tname: 'Page 1',\n\t\t\tindex: 'a1' as IndexKey,\n\t\t\tmeta: {},\n\t\t}),\n\t]\n}\n\n/**\n * Creates an integrity checker function that ensures the tldraw store maintains\n * a consistent and usable state. The checker validates that required records exist\n * and relationships between records are maintained.\n *\n * The integrity checker ensures:\n * - Document and pointer records exist\n * - At least one page exists\n * - Instance state references valid pages\n * - Page states and cameras exist for all pages\n * - Shape references in page states are valid\n *\n * @param store - The tldraw store to check for integrity\n * @returns A function that when called, validates and fixes store integrity\n *\n * @internal\n * @example\n * ```ts\n * const checker = createIntegrityChecker(store)\n *\n * // Run integrity check (typically called automatically)\n * checker()\n *\n * // The checker will create missing records and fix invalid references\n * ```\n */\nexport function createIntegrityChecker(store: Store<TLRecord, TLStoreProps>): () => void {\n\tconst $pageIds = store.query.ids('page')\n\tconst $pageStates = store.query.records('instance_page_state')\n\n\tconst ensureStoreIsUsable = (): void => {\n\t\t// make sure we have exactly one document\n\t\tif (!store.has(TLDOCUMENT_ID)) {\n\t\t\tstore.put([DocumentRecordType.create({ id: TLDOCUMENT_ID, name: store.props.defaultName })])\n\t\t\treturn ensureStoreIsUsable()\n\t\t}\n\n\t\tif (!store.has(TLPOINTER_ID)) {\n\t\t\tstore.put([PointerRecordType.create({ id: TLPOINTER_ID })])\n\t\t\treturn ensureStoreIsUsable()\n\t\t}\n\n\t\t// make sure there is at least one page\n\t\tconst pageIds = $pageIds.get()\n\t\tif (pageIds.size === 0) {\n\t\t\tstore.put(getDefaultPages())\n\t\t\treturn ensureStoreIsUsable()\n\t\t}\n\n\t\tconst getFirstPageId = () => [...pageIds].map((id) => store.get(id)!).sort(sortByIndex)[0].id!\n\n\t\t// make sure we have state for the current user's current tab\n\t\tconst instanceState = store.get(TLINSTANCE_ID)\n\t\tif (!instanceState) {\n\t\t\tstore.put([\n\t\t\t\tstore.schema.types.instance.create({\n\t\t\t\t\tid: TLINSTANCE_ID,\n\t\t\t\t\tcurrentPageId: getFirstPageId(),\n\t\t\t\t\texportBackground: true,\n\t\t\t\t}),\n\t\t\t])\n\n\t\t\treturn ensureStoreIsUsable()\n\t\t} else if (!pageIds.has(instanceState.currentPageId)) {\n\t\t\tstore.put([{ ...instanceState, currentPageId: getFirstPageId() }])\n\t\t\treturn ensureStoreIsUsable()\n\t\t}\n\n\t\t// make sure we have page states and cameras for all the pages\n\t\tconst missingPageStateIds = new Set<TLInstancePageStateId>()\n\t\tconst missingCameraIds = new Set<TLCameraId>()\n\t\tfor (const id of pageIds) {\n\t\t\tconst pageStateId = InstancePageStateRecordType.createId(id)\n\t\t\tconst pageState = store.get(pageStateId)\n\t\t\tif (!pageState) {\n\t\t\t\tmissingPageStateIds.add(pageStateId)\n\t\t\t}\n\t\t\tconst cameraId = CameraRecordType.createId(id)\n\t\t\tif (!store.has(cameraId)) {\n\t\t\t\tmissingCameraIds.add(cameraId)\n\t\t\t}\n\t\t}\n\n\t\tif (missingPageStateIds.size > 0) {\n\t\t\tstore.put(\n\t\t\t\t[...missingPageStateIds].map((id) =>\n\t\t\t\t\tInstancePageStateRecordType.create({\n\t\t\t\t\t\tid,\n\t\t\t\t\t\tpageId: InstancePageStateRecordType.parseId(id) as TLPageId,\n\t\t\t\t\t})\n\t\t\t\t)\n\t\t\t)\n\t\t}\n\n\t\tif (missingCameraIds.size > 0) {\n\t\t\tstore.put([...missingCameraIds].map((id) => CameraRecordType.create({ id })))\n\t\t}\n\n\t\tconst pageStates = $pageStates.get()\n\t\tfor (const pageState of pageStates) {\n\t\t\tif (!pageIds.has(pageState.pageId)) {\n\t\t\t\tstore.remove([pageState.id])\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tif (pageState.croppingShapeId && !store.has(pageState.croppingShapeId)) {\n\t\t\t\tstore.put([{ ...pageState, croppingShapeId: null }])\n\t\t\t\treturn ensureStoreIsUsable()\n\t\t\t}\n\t\t\tif (pageState.focusedGroupId && !store.has(pageState.focusedGroupId)) {\n\t\t\t\tstore.put([{ ...pageState, focusedGroupId: null }])\n\t\t\t\treturn ensureStoreIsUsable()\n\t\t\t}\n\t\t\tif (pageState.hoveredShapeId && !store.has(pageState.hoveredShapeId)) {\n\t\t\t\tstore.put([{ ...pageState, hoveredShapeId: null }])\n\t\t\t\treturn ensureStoreIsUsable()\n\t\t\t}\n\t\t\tconst filteredSelectedIds = pageState.selectedShapeIds.filter((id) => store.has(id))\n\t\t\tif (filteredSelectedIds.length !== pageState.selectedShapeIds.length) {\n\t\t\t\tstore.put([{ ...pageState, selectedShapeIds: filteredSelectedIds }])\n\t\t\t\treturn ensureStoreIsUsable()\n\t\t\t}\n\t\t\tconst filteredHintingIds = pageState.hintingShapeIds.filter((id) => store.has(id))\n\t\t\tif (filteredHintingIds.length !== pageState.hintingShapeIds.length) {\n\t\t\t\tstore.put([{ ...pageState, hintingShapeIds: filteredHintingIds }])\n\t\t\t\treturn ensureStoreIsUsable()\n\t\t\t}\n\t\t\tconst filteredErasingIds = pageState.erasingShapeIds.filter((id) => store.has(id))\n\t\t\tif (filteredErasingIds.length !== pageState.erasingShapeIds.length) {\n\t\t\t\tstore.put([{ ...pageState, erasingShapeIds: filteredErasingIds }])\n\t\t\t\treturn ensureStoreIsUsable()\n\t\t\t}\n\t\t}\n\t}\n\n\treturn ensureStoreIsUsable\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { Signal, computed } from '@tldraw/state'\nimport {\n\tSerializedStore,\n\tStore,\n\tStoreSchema,\n\tStoreSnapshot,\n\tStoreValidationFailure,\n} from '@tldraw/store'\nimport { IndexKey, JsonObject, annotateError, sortByIndex, structuredClone } from '@tldraw/utils'\nimport { TLAsset, TLAssetId } from './records/TLAsset'\nimport { CameraRecordType, TLCameraId } from './records/TLCamera'\nimport { DocumentRecordType, TLDOCUMENT_ID } from './records/TLDocument'\nimport { TLINSTANCE_ID } from './records/TLInstance'\nimport { PageRecordType, TLPageId } from './records/TLPage'\nimport { InstancePageStateRecordType, TLInstancePageStateId } from './records/TLPageState'\nimport { PointerRecordType, TLPOINTER_ID } from './records/TLPointer'\nimport { TLRecord } from './records/TLRecord'\nimport { TLUser } from './records/TLUser'\n\n/**\n * Redacts the source of an asset record for error reporting.\n *\n * @param record - The asset record to redact\n * @returns The redacted record\n * @internal\n */\nexport function redactRecordForErrorReporting(record: any) {\n\tif (record.typeName === 'asset') {\n\t\tif ('src' in record) {\n\t\t\trecord.src = '<redacted>'\n\t\t}\n\n\t\tif ('src' in record.props) {\n\t\t\trecord.props.src = '<redacted>'\n\t\t}\n\t}\n}\n\n/**\n * The complete schema type for a tldraw store, defining the structure and validation rules\n * for all tldraw records and store properties.\n *\n * @public\n * @example\n * ```ts\n * import { createTLSchema } from '@tldraw/tlschema'\n *\n * const schema = createTLSchema()\n * const storeSchema: TLStoreSchema = schema\n * ```\n */\nexport type TLStoreSchema = StoreSchema<TLRecord, TLStoreProps>\n\n/**\n * A serialized representation of a tldraw store that can be persisted or transmitted.\n * Contains all store records in a JSON-serializable format.\n *\n * @public\n * @example\n * ```ts\n * // Serialize a store\n * const serializedStore: TLSerializedStore = store.serialize()\n *\n * // Save to localStorage\n * localStorage.setItem('drawing', JSON.stringify(serializedStore))\n * ```\n */\nexport type TLSerializedStore = SerializedStore<TLRecord>\n\n/**\n * A snapshot of a tldraw store at a specific point in time, containing all records\n * and metadata. Used for persistence, synchronization, and creating store backups.\n *\n * @public\n * @example\n * ```ts\n * // Create a snapshot\n * const snapshot: TLStoreSnapshot = store.getSnapshot()\n *\n * // Restore from snapshot\n * store.loadSnapshot(snapshot)\n * ```\n */\nexport type TLStoreSnapshot = StoreSnapshot<TLRecord>\n\n/**\n * Context information provided when resolving asset URLs, containing details about\n * the current rendering environment and user's connection to optimize asset delivery.\n *\n * @public\n * @example\n * ```ts\n * const assetStore: TLAssetStore = {\n * async resolve(asset, context: TLAssetContext) {\n * // Use low resolution for slow connections\n * if (context.networkEffectiveType === 'slow-2g') {\n * return `${asset.props.src}?quality=low`\n * }\n * // Use high DPI version for retina displays\n * if (context.dpr > 1) {\n * return `${asset.props.src}@2x`\n * }\n * return asset.props.src\n * }\n * }\n * ```\n */\nexport interface TLAssetContext {\n\t/**\n\t * The scale at which the asset is being rendered on-screen relative to its native dimensions.\n\t * If the asset is 1000px wide, but it's been resized/zoom so it takes 500px on-screen, this\n\t * will be 0.5.\n\t *\n\t * The scale measures CSS pixels, not device pixels.\n\t */\n\tscreenScale: number\n\t/** The {@link TLAssetContext.screenScale}, stepped to the nearest power-of-2 multiple. */\n\tsteppedScreenScale: number\n\t/** The device pixel ratio - how many CSS pixels are in one device pixel? */\n\tdpr: number\n\t/**\n\t * An alias for\n\t * {@link https://developer.mozilla.org/en-US/docs/Web/API/NetworkInformation/effectiveType | `navigator.connection.effectiveType` }\n\t * if it's available in the current browser. Use this to e.g. serve lower-resolution images to\n\t * users on slow connections.\n\t */\n\tnetworkEffectiveType: string | null\n\t/**\n\t * In some circumstances, we need to resolve a URL that points to the original version of a\n\t * particular asset. This is used when the asset will leave the current tldraw instance - e.g.\n\t * for copy/paste, or exports.\n\t */\n\tshouldResolveToOriginal: boolean\n}\n\n/**\n * Interface for storing and managing assets (images, videos, etc.) in tldraw.\n * Provides methods for uploading, resolving, and removing assets from storage.\n *\n * A `TLAssetStore` sits alongside the main {@link TLStore} and is responsible for storing and\n * retrieving large assets such as images. Generally, this should be part of a wider sync system:\n *\n * - By default, the store is in-memory only, so `TLAssetStore` converts images to data URLs\n * - When using\n * {@link @tldraw/editor#TldrawEditorWithoutStoreProps.persistenceKey | `persistenceKey`}, the\n * store is synced to the browser's local IndexedDB, so `TLAssetStore` stores images there too\n * - When using a multiplayer sync server, you would implement `TLAssetStore` to upload images to\n * e.g. an S3 bucket.\n *\n * @public\n * @example\n * ```ts\n * // Simple in-memory asset store\n * const assetStore: TLAssetStore = {\n * async upload(asset, file) {\n * const dataUrl = await fileToDataUrl(file)\n * return { src: dataUrl }\n * },\n *\n * async resolve(asset, context) {\n * return asset.props.src\n * },\n *\n * async remove(assetIds) {\n * // Clean up if needed\n * }\n * }\n * ```\n */\nexport interface TLAssetStore {\n\t/**\n\t * Upload an asset to your storage, returning a URL that can be used to refer to the asset\n\t * long-term.\n\t *\n\t * @param asset - Information & metadata about the asset being uploaded\n\t * @param file - The `File` to be uploaded\n\t * @returns A promise that resolves to the URL of the uploaded asset\n\t */\n\tupload(\n\t\tasset: TLAsset,\n\t\tfile: File,\n\t\tabortSignal?: AbortSignal\n\t): Promise<{ src: string; meta?: JsonObject }>\n\t/**\n\t * Resolve an asset to a URL. This is used when rendering the asset in the editor. By default,\n\t * this will just use `asset.props.src`, the URL returned by `upload()`. This can be used to\n\t * rewrite that URL to add access credentials, or optimized the asset for how it's currently\n\t * being displayed using the {@link TLAssetContext | information provided}.\n\t *\n\t * @param asset - the asset being resolved\n\t * @param ctx - information about the current environment and where the asset is being used\n\t * @returns The URL of the resolved asset, or `null` if the asset is not available\n\t */\n\tresolve?(asset: TLAsset, ctx: TLAssetContext): Promise<string | null> | string | null\n\t/**\n\t * Remove an asset from storage. This is called when the asset is no longer needed, e.g. when\n\t * the user deletes it from the editor.\n\t * @param asset - the asset being removed\n\t * @returns A promise that resolves when the asset has been removed\n\t */\n\tremove?(assetIds: TLAssetId[]): Promise<void>\n}\n\n/**\n * Interface for resolving user information in tldraw.\n *\n * A `TLUserStore` sits alongside the main {@link TLStore} and provides user\n * resolution for attribution labels and display names. Implement this interface\n * to connect tldraw to your auth/user system.\n *\n * `currentUser` and `resolve` are reactive {@link @tldraw/state#Signal | Signals}\n * so that the editor can automatically track changes to user data and\n * re-render when a user's name, color, or avatar updates.\n *\n * Implementations should cache signals returned by `resolve` \u2014 e.g. return the\n * same `Signal` for repeated calls with the same `userId` \u2014 to avoid\n * unnecessary re-computation.\n *\n * @public\n * @example\n * ```ts\n * const currentUser = computed('currentUser', () =>\n * UserRecordType.create({\n * id: createUserId(myAuth.userId),\n * name: myAuth.displayName,\n * color: myAuth.color,\n * })\n * )\n *\n * const userStore: TLUserStore = {\n * currentUser,\n * resolve(userId) {\n * return computed('resolve-' + userId, () =>\n * myUserCache.get(userId) ?? null\n * )\n * },\n * }\n * ```\n */\nexport interface TLUserStore {\n\t/**\n\t * A signal resolving to the currently authenticated user,\n\t * or `null` for anonymous / unknown.\n\t * Read when stamping attribution on shape create/update.\n\t */\n\tcurrentUser: Signal<TLUser | null>\n\n\t/**\n\t * Return a signal resolving an arbitrary user ID to display info.\n\t * Called when rendering attribution labels for shapes that may have been\n\t * created or edited by someone else.\n\t * The signal's value should be `null` if the user cannot be resolved.\n\t */\n\tresolve?(userId: string): Signal<TLUser | null>\n}\n\n/**\n * Create a cached {@link TLUserStore.resolve} implementation.\n *\n * Wraps a reactive lookup function so that each `userId` gets a single\n * stable {@link @tldraw/state#Signal | Signal} that is reused across calls.\n * The `resolveFn` is evaluated inside a `computed`, so any `.get()` calls\n * it makes are automatically tracked.\n *\n * @param resolveFn - A function that resolves a raw user-ID string to a\n * {@link TLUser} or `null`. Called reactively inside a `computed`.\n * @returns A function suitable for use as `TLUserStore.resolve`.\n *\n * @example\n * ```ts\n * const users: TLUserStore = {\n * currentUser: currentUserSignal,\n * resolve: createCachedUserResolve(\n * (userId) => usersAtom.get()[createUserId(userId)] ?? null\n * ),\n * }\n * ```\n *\n * @public\n */\nexport function createCachedUserResolve(\n\tresolveFn: (userId: string) => TLUser | null\n): (userId: string) => Signal<TLUser | null> {\n\tconst cache = new Map<string, Signal<TLUser | null>>()\n\treturn (userId: string) => {\n\t\tlet signal = cache.get(userId)\n\t\tif (!signal) {\n\t\t\tsignal = computed('resolve-user-' + userId, () => resolveFn(userId))\n\t\t\tcache.set(userId, signal)\n\t\t}\n\t\treturn signal\n\t}\n}\n\n/**\n * Configuration properties for a tldraw store, defining its behavior and integrations.\n * These props are passed when creating a new store instance.\n *\n * @public\n * @example\n * ```ts\n * const storeProps: TLStoreProps = {\n * defaultName: 'My Drawing',\n * assets: myAssetStore,\n * onMount: (editor) => {\n * console.log('Editor mounted')\n * return () => console.log('Editor unmounted')\n * },\n * collaboration: {\n * status: statusSignal,\n * mode: modeSignal\n * }\n * }\n *\n * const store = new Store({ schema, props: storeProps })\n * ```\n */\nexport interface TLStoreProps {\n\t/** Default name for new documents created in this store */\n\tdefaultName: string\n\t/** Asset store implementation for handling file uploads and storage */\n\tassets: Required<TLAssetStore>\n\t/** User store implementation for user resolution and attribution */\n\tusers: Required<TLUserStore>\n\t/**\n\t * Called when an {@link @tldraw/editor#Editor} connected to this store is mounted.\n\t * Can optionally return a cleanup function that will be called when unmounted.\n\t *\n\t * @param editor - The editor instance that was mounted\n\t * @returns Optional cleanup function\n\t */\n\tonMount(editor: unknown): void | (() => void)\n\t/** Optional collaboration configuration for multiplayer features */\n\tcollaboration?: {\n\t\t/** Signal indicating online/offline collaboration status */\n\t\tstatus: Signal<'online' | 'offline'> | null\n\t\t/** Signal indicating collaboration mode permissions */\n\t\tmode?: Signal<'readonly' | 'readwrite'> | null\n\t}\n}\n\n/**\n * The main tldraw store type, representing a reactive database of tldraw records\n * with associated store properties. This is the central data structure that holds\n * all shapes, assets, pages, and user state.\n *\n * @public\n * @example\n * ```ts\n * import { Store } from '@tldraw/store'\n * import { createTLSchema } from '@tldraw/tlschema'\n *\n * const schema = createTLSchema()\n * const store: TLStore = new Store({\n * schema,\n * props: {\n * defaultName: 'Untitled',\n * assets: myAssetStore,\n * onMount: () => console.log('Store mounted')\n * }\n * })\n * ```\n */\nexport type TLStore = Store<TLRecord, TLStoreProps>\n\n/**\n * Default validation failure handler for tldraw stores. This function is called\n * when a record fails validation during store operations. It annotates errors\n * with debugging information and determines whether to allow invalid records\n * during store initialization.\n *\n * @param options - The validation failure details\n * - error - The validation error that occurred\n * - phase - The store operation phase when validation failed\n * - record - The invalid record that caused the failure\n * - recordBefore - The previous state of the record (if applicable)\n * @returns The record to use (typically throws the annotated error)\n * @throws The original validation error with additional debugging context\n *\n * @public\n * @example\n * ```ts\n * const store = new Store({\n * schema,\n * props: storeProps,\n * onValidationFailure // Use this as the validation failure handler\n * })\n *\n * // The handler will be called automatically when validation fails\n * try {\n * store.put([invalidRecord])\n * } catch (error) {\n * // Error will contain debugging information added by onValidationFailure\n * }\n * ```\n */\nexport function onValidationFailure({\n\terror,\n\tphase,\n\trecord,\n\trecordBefore,\n}: StoreValidationFailure<TLRecord>): TLRecord {\n\tconst isExistingValidationIssue =\n\t\t// if we're initializing the store for the first time, we should\n\t\t// allow invalid records so people can load old buggy data:\n\t\tphase === 'initialize'\n\n\tannotateError(error, {\n\t\ttags: {\n\t\t\torigin: 'store.validateRecord',\n\t\t\tstorePhase: phase,\n\t\t\tisExistingValidationIssue,\n\t\t},\n\t\textras: {\n\t\t\trecordBefore: recordBefore\n\t\t\t\t? redactRecordForErrorReporting(structuredClone(recordBefore))\n\t\t\t\t: undefined,\n\t\t\trecordAfter: redactRecordForErrorReporting(structuredClone(record)),\n\t\t},\n\t})\n\n\tthrow error\n}\n\nfunction getDefaultPages() {\n\treturn [\n\t\tPageRecordType.create({\n\t\t\tid: 'page:page' as TLPageId,\n\t\t\tname: 'Page 1',\n\t\t\tindex: 'a1' as IndexKey,\n\t\t\tmeta: {},\n\t\t}),\n\t]\n}\n\n/**\n * Creates an integrity checker function that ensures the tldraw store maintains\n * a consistent and usable state. The checker validates that required records exist\n * and relationships between records are maintained.\n *\n * The integrity checker ensures:\n * - Document and pointer records exist\n * - At least one page exists\n * - Instance state references valid pages\n * - Page states and cameras exist for all pages\n * - Shape references in page states are valid\n *\n * @param store - The tldraw store to check for integrity\n * @returns A function that when called, validates and fixes store integrity\n *\n * @internal\n * @example\n * ```ts\n * const checker = createIntegrityChecker(store)\n *\n * // Run integrity check (typically called automatically)\n * checker()\n *\n * // The checker will create missing records and fix invalid references\n * ```\n */\nexport function createIntegrityChecker(store: Store<TLRecord, TLStoreProps>): () => void {\n\tconst $pageIds = store.query.ids('page')\n\tconst $pageStates = store.query.records('instance_page_state')\n\n\tconst ensureStoreIsUsable = (): void => {\n\t\t// make sure we have exactly one document\n\t\tif (!store.has(TLDOCUMENT_ID)) {\n\t\t\tstore.put([DocumentRecordType.create({ id: TLDOCUMENT_ID, name: store.props.defaultName })])\n\t\t\treturn ensureStoreIsUsable()\n\t\t}\n\n\t\tif (!store.has(TLPOINTER_ID)) {\n\t\t\tstore.put([PointerRecordType.create({ id: TLPOINTER_ID })])\n\t\t\treturn ensureStoreIsUsable()\n\t\t}\n\n\t\t// make sure there is at least one page\n\t\tconst pageIds = $pageIds.get()\n\t\tif (pageIds.size === 0) {\n\t\t\tstore.put(getDefaultPages())\n\t\t\treturn ensureStoreIsUsable()\n\t\t}\n\n\t\tconst getFirstPageId = () => [...pageIds].map((id) => store.get(id)!).sort(sortByIndex)[0].id!\n\n\t\t// make sure we have state for the current user's current tab\n\t\tconst instanceState = store.get(TLINSTANCE_ID)\n\t\tif (!instanceState) {\n\t\t\tstore.put([\n\t\t\t\tstore.schema.types.instance.create({\n\t\t\t\t\tid: TLINSTANCE_ID,\n\t\t\t\t\tcurrentPageId: getFirstPageId(),\n\t\t\t\t}),\n\t\t\t])\n\n\t\t\treturn ensureStoreIsUsable()\n\t\t} else if (!pageIds.has(instanceState.currentPageId)) {\n\t\t\tstore.put([{ ...instanceState, currentPageId: getFirstPageId() }])\n\t\t\treturn ensureStoreIsUsable()\n\t\t}\n\n\t\t// make sure we have page states and cameras for all the pages\n\t\tconst missingPageStateIds = new Set<TLInstancePageStateId>()\n\t\tconst missingCameraIds = new Set<TLCameraId>()\n\t\tfor (const id of pageIds) {\n\t\t\tconst pageStateId = InstancePageStateRecordType.createId(id)\n\t\t\tconst pageState = store.get(pageStateId)\n\t\t\tif (!pageState) {\n\t\t\t\tmissingPageStateIds.add(pageStateId)\n\t\t\t}\n\t\t\tconst cameraId = CameraRecordType.createId(id)\n\t\t\tif (!store.has(cameraId)) {\n\t\t\t\tmissingCameraIds.add(cameraId)\n\t\t\t}\n\t\t}\n\n\t\tif (missingPageStateIds.size > 0) {\n\t\t\tstore.put(\n\t\t\t\t[...missingPageStateIds].map((id) =>\n\t\t\t\t\tInstancePageStateRecordType.create({\n\t\t\t\t\t\tid,\n\t\t\t\t\t\tpageId: InstancePageStateRecordType.parseId(id) as TLPageId,\n\t\t\t\t\t})\n\t\t\t\t)\n\t\t\t)\n\t\t}\n\n\t\tif (missingCameraIds.size > 0) {\n\t\t\tstore.put([...missingCameraIds].map((id) => CameraRecordType.create({ id })))\n\t\t}\n\n\t\tconst pageStates = $pageStates.get()\n\t\tfor (const pageState of pageStates) {\n\t\t\tif (!pageIds.has(pageState.pageId)) {\n\t\t\t\tstore.remove([pageState.id])\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tif (pageState.croppingShapeId && !store.has(pageState.croppingShapeId)) {\n\t\t\t\tstore.put([{ ...pageState, croppingShapeId: null }])\n\t\t\t\treturn ensureStoreIsUsable()\n\t\t\t}\n\t\t\tif (pageState.focusedGroupId && !store.has(pageState.focusedGroupId)) {\n\t\t\t\tstore.put([{ ...pageState, focusedGroupId: null }])\n\t\t\t\treturn ensureStoreIsUsable()\n\t\t\t}\n\t\t\tif (pageState.hoveredShapeId && !store.has(pageState.hoveredShapeId)) {\n\t\t\t\tstore.put([{ ...pageState, hoveredShapeId: null }])\n\t\t\t\treturn ensureStoreIsUsable()\n\t\t\t}\n\t\t\tconst filteredSelectedIds = pageState.selectedShapeIds.filter((id) => store.has(id))\n\t\t\tif (filteredSelectedIds.length !== pageState.selectedShapeIds.length) {\n\t\t\t\tstore.put([{ ...pageState, selectedShapeIds: filteredSelectedIds }])\n\t\t\t\treturn ensureStoreIsUsable()\n\t\t\t}\n\t\t\tconst filteredHintingIds = pageState.hintingShapeIds.filter((id) => store.has(id))\n\t\t\tif (filteredHintingIds.length !== pageState.hintingShapeIds.length) {\n\t\t\t\tstore.put([{ ...pageState, hintingShapeIds: filteredHintingIds }])\n\t\t\t\treturn ensureStoreIsUsable()\n\t\t\t}\n\t\t\tconst filteredErasingIds = pageState.erasingShapeIds.filter((id) => store.has(id))\n\t\t\tif (filteredErasingIds.length !== pageState.erasingShapeIds.length) {\n\t\t\t\tstore.put([{ ...pageState, erasingShapeIds: filteredErasingIds }])\n\t\t\t\treturn ensureStoreIsUsable()\n\t\t\t}\n\t\t}\n\t}\n\n\treturn ensureStoreIsUsable\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }