diff --git a/.wrangler/tmp/bundle-fO5AAb/checked-fetch.js b/.wrangler/tmp/bundle-fO5AAb/checked-fetch.js deleted file mode 100644 index 8c007fd..0000000 --- a/.wrangler/tmp/bundle-fO5AAb/checked-fetch.js +++ /dev/null @@ -1,30 +0,0 @@ -const urls = new Set(); - -function checkURL(request, init) { - const url = - request instanceof URL - ? request - : new URL( - (typeof request === "string" - ? new Request(request, init) - : request - ).url - ); - if (url.port && url.port !== "443" && url.protocol === "https:") { - if (!urls.has(url.toString())) { - urls.add(url.toString()); - console.warn( - `WARNING: known issue with \`fetch()\` requests to custom HTTPS ports in published Workers:\n` + - ` - ${url.toString()} - the custom port will be ignored when the Worker is published using the \`wrangler deploy\` command.\n` - ); - } - } -} - -globalThis.fetch = new Proxy(globalThis.fetch, { - apply(target, thisArg, argArray) { - const [request, init] = argArray; - checkURL(request, init); - return Reflect.apply(target, thisArg, argArray); - }, -}); diff --git a/.wrangler/tmp/bundle-fO5AAb/middleware-insertion-facade.js b/.wrangler/tmp/bundle-fO5AAb/middleware-insertion-facade.js deleted file mode 100644 index 08ffb62..0000000 --- a/.wrangler/tmp/bundle-fO5AAb/middleware-insertion-facade.js +++ /dev/null @@ -1,11 +0,0 @@ - import worker, * as OTHER_EXPORTS from "C:\\Users\\jeffe\\Documents\\GitHub\\canvas-website\\worker\\worker.ts"; - import * as __MIDDLEWARE_0__ from "C:\\Users\\jeffe\\Documents\\GitHub\\canvas-website\\node_modules\\wrangler\\templates\\middleware\\middleware-ensure-req-body-drained.ts"; -import * as __MIDDLEWARE_1__ from "C:\\Users\\jeffe\\Documents\\GitHub\\canvas-website\\node_modules\\wrangler\\templates\\middleware\\middleware-miniflare3-json-error.ts"; - - export * from "C:\\Users\\jeffe\\Documents\\GitHub\\canvas-website\\worker\\worker.ts"; - - export const __INTERNAL_WRANGLER_MIDDLEWARE__ = [ - - __MIDDLEWARE_0__.default,__MIDDLEWARE_1__.default - ] - export default worker; \ No newline at end of file diff --git a/.wrangler/tmp/bundle-fO5AAb/middleware-loader.entry.ts b/.wrangler/tmp/bundle-fO5AAb/middleware-loader.entry.ts deleted file mode 100644 index 4d0c179..0000000 --- a/.wrangler/tmp/bundle-fO5AAb/middleware-loader.entry.ts +++ /dev/null @@ -1,134 +0,0 @@ -// This loads all middlewares exposed on the middleware object and then starts -// the invocation chain. The big idea is that we can add these to the middleware -// export dynamically through wrangler, or we can potentially let users directly -// add them as a sort of "plugin" system. - -import ENTRY, { __INTERNAL_WRANGLER_MIDDLEWARE__ } from "C:\\Users\\jeffe\\Documents\\GitHub\\canvas-website\\.wrangler\\tmp\\bundle-fO5AAb\\middleware-insertion-facade.js"; -import { __facade_invoke__, __facade_register__, Dispatcher } from "C:\\Users\\jeffe\\Documents\\GitHub\\canvas-website\\node_modules\\wrangler\\templates\\middleware\\common.ts"; -import type { WorkerEntrypointConstructor } from "C:\\Users\\jeffe\\Documents\\GitHub\\canvas-website\\.wrangler\\tmp\\bundle-fO5AAb\\middleware-insertion-facade.js"; - -// Preserve all the exports from the worker -export * from "C:\\Users\\jeffe\\Documents\\GitHub\\canvas-website\\.wrangler\\tmp\\bundle-fO5AAb\\middleware-insertion-facade.js"; - -class __Facade_ScheduledController__ implements ScheduledController { - readonly #noRetry: ScheduledController["noRetry"]; - - constructor( - readonly scheduledTime: number, - readonly cron: string, - noRetry: ScheduledController["noRetry"] - ) { - this.#noRetry = noRetry; - } - - noRetry() { - if (!(this instanceof __Facade_ScheduledController__)) { - throw new TypeError("Illegal invocation"); - } - // Need to call native method immediately in case uncaught error thrown - this.#noRetry(); - } -} - -function wrapExportedHandler(worker: ExportedHandler): ExportedHandler { - // If we don't have any middleware defined, just return the handler as is - if ( - __INTERNAL_WRANGLER_MIDDLEWARE__ === undefined || - __INTERNAL_WRANGLER_MIDDLEWARE__.length === 0 - ) { - return worker; - } - // Otherwise, register all middleware once - for (const middleware of __INTERNAL_WRANGLER_MIDDLEWARE__) { - __facade_register__(middleware); - } - - const fetchDispatcher: ExportedHandlerFetchHandler = function ( - request, - env, - ctx - ) { - if (worker.fetch === undefined) { - throw new Error("Handler does not export a fetch() function."); - } - return worker.fetch(request, env, ctx); - }; - - return { - ...worker, - fetch(request, env, ctx) { - const dispatcher: Dispatcher = function (type, init) { - if (type === "scheduled" && worker.scheduled !== undefined) { - const controller = new __Facade_ScheduledController__( - Date.now(), - init.cron ?? "", - () => {} - ); - return worker.scheduled(controller, env, ctx); - } - }; - return __facade_invoke__(request, env, ctx, dispatcher, fetchDispatcher); - }, - }; -} - -function wrapWorkerEntrypoint( - klass: WorkerEntrypointConstructor -): WorkerEntrypointConstructor { - // If we don't have any middleware defined, just return the handler as is - if ( - __INTERNAL_WRANGLER_MIDDLEWARE__ === undefined || - __INTERNAL_WRANGLER_MIDDLEWARE__.length === 0 - ) { - return klass; - } - // Otherwise, register all middleware once - for (const middleware of __INTERNAL_WRANGLER_MIDDLEWARE__) { - __facade_register__(middleware); - } - - // `extend`ing `klass` here so other RPC methods remain callable - return class extends klass { - #fetchDispatcher: ExportedHandlerFetchHandler> = ( - request, - env, - ctx - ) => { - this.env = env; - this.ctx = ctx; - if (super.fetch === undefined) { - throw new Error("Entrypoint class does not define a fetch() function."); - } - return super.fetch(request); - }; - - #dispatcher: Dispatcher = (type, init) => { - if (type === "scheduled" && super.scheduled !== undefined) { - const controller = new __Facade_ScheduledController__( - Date.now(), - init.cron ?? "", - () => {} - ); - return super.scheduled(controller); - } - }; - - fetch(request: Request) { - return __facade_invoke__( - request, - this.env, - this.ctx, - this.#dispatcher, - this.#fetchDispatcher - ); - } - }; -} - -let WRAPPED_ENTRY: ExportedHandler | WorkerEntrypointConstructor | undefined; -if (typeof ENTRY === "object") { - WRAPPED_ENTRY = wrapExportedHandler(ENTRY); -} else if (typeof ENTRY === "function") { - WRAPPED_ENTRY = wrapWorkerEntrypoint(ENTRY); -} -export default WRAPPED_ENTRY; diff --git a/.wrangler/tmp/dev-g4n6ra/worker.js b/.wrangler/tmp/dev-g4n6ra/worker.js deleted file mode 100644 index 81ba359..0000000 --- a/.wrangler/tmp/dev-g4n6ra/worker.js +++ /dev/null @@ -1,12639 +0,0 @@ -var __create = Object.create; -var __defProp = Object.defineProperty; -var __getOwnPropDesc = Object.getOwnPropertyDescriptor; -var __getOwnPropNames = Object.getOwnPropertyNames; -var __getProtoOf = Object.getPrototypeOf; -var __hasOwnProp = Object.prototype.hasOwnProperty; -var __esm = (fn, res) => function __init() { - return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res; -}; -var __commonJS = (cb, mod) => function __require() { - return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports; -}; -var __export = (target, all) => { - for (var name in all) - __defProp(target, name, { get: all[name], enumerable: true }); -}; -var __copyProps = (to, from, except, desc) => { - if (from && typeof from === "object" || typeof from === "function") { - for (let key of __getOwnPropNames(from)) - if (!__hasOwnProp.call(to, key) && key !== except) - __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); - } - return to; -}; -var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( - // If the importer is in node compatibility mode or this is not an ESM - // file that has been converted to a CommonJS file using a Babel- - // compatible transform (i.e. "__esModule" has not been set), then set - // "default" to the CommonJS "module.exports" for node compatibility. - isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, - mod -)); - -// .wrangler/tmp/bundle-fO5AAb/checked-fetch.js -function checkURL(request, init) { - const url = request instanceof URL ? request : new URL( - (typeof request === "string" ? new Request(request, init) : request).url - ); - if (url.port && url.port !== "443" && url.protocol === "https:") { - if (!urls.has(url.toString())) { - urls.add(url.toString()); - console.warn( - `WARNING: known issue with \`fetch()\` requests to custom HTTPS ports in published Workers: - - ${url.toString()} - the custom port will be ignored when the Worker is published using the \`wrangler deploy\` command. -` - ); - } - } -} -var urls; -var init_checked_fetch = __esm({ - ".wrangler/tmp/bundle-fO5AAb/checked-fetch.js"() { - "use strict"; - urls = /* @__PURE__ */ new Set(); - globalThis.fetch = new Proxy(globalThis.fetch, { - apply(target, thisArg, argArray) { - const [request, init] = argArray; - checkURL(request, init); - return Reflect.apply(target, thisArg, argArray); - } - }); - } -}); - -// wrangler-modules-watch:wrangler:modules-watch -var init_wrangler_modules_watch = __esm({ - "wrangler-modules-watch:wrangler:modules-watch"() { - init_checked_fetch(); - init_modules_watch_stub(); - } -}); - -// node_modules/wrangler/templates/modules-watch-stub.js -var init_modules_watch_stub = __esm({ - "node_modules/wrangler/templates/modules-watch-stub.js"() { - init_wrangler_modules_watch(); - } -}); - -// node_modules/lodash.throttle/index.js -var require_lodash = __commonJS({ - "node_modules/lodash.throttle/index.js"(exports, module) { - init_checked_fetch(); - init_modules_watch_stub(); - var FUNC_ERROR_TEXT = "Expected a function"; - var NAN = 0 / 0; - var symbolTag = "[object Symbol]"; - var reTrim = /^\s+|\s+$/g; - var reIsBadHex = /^[-+]0x[0-9a-f]+$/i; - var reIsBinary = /^0b[01]+$/i; - var reIsOctal = /^0o[0-7]+$/i; - var freeParseInt = parseInt; - var freeGlobal = typeof global == "object" && global && global.Object === Object && global; - var freeSelf = typeof self == "object" && self && self.Object === Object && self; - var root = freeGlobal || freeSelf || Function("return this")(); - var objectProto = Object.prototype; - var objectToString = objectProto.toString; - var nativeMax = Math.max; - var nativeMin = Math.min; - var now = function() { - return root.Date.now(); - }; - function debounce2(func, wait, options) { - var lastArgs, lastThis, maxWait, result, timerId, lastCallTime, lastInvokeTime = 0, leading = false, maxing = false, trailing = true; - if (typeof func != "function") { - throw new TypeError(FUNC_ERROR_TEXT); - } - wait = toNumber(wait) || 0; - if (isObject(options)) { - leading = !!options.leading; - maxing = "maxWait" in options; - maxWait = maxing ? nativeMax(toNumber(options.maxWait) || 0, wait) : maxWait; - trailing = "trailing" in options ? !!options.trailing : trailing; - } - function invokeFunc(time) { - var args = lastArgs, thisArg = lastThis; - lastArgs = lastThis = void 0; - lastInvokeTime = time; - result = func.apply(thisArg, args); - return result; - } - function leadingEdge(time) { - lastInvokeTime = time; - timerId = setTimeout(timerExpired, wait); - return leading ? invokeFunc(time) : result; - } - function remainingWait(time) { - var timeSinceLastCall = time - lastCallTime, timeSinceLastInvoke = time - lastInvokeTime, result2 = wait - timeSinceLastCall; - return maxing ? nativeMin(result2, maxWait - timeSinceLastInvoke) : result2; - } - function shouldInvoke(time) { - var timeSinceLastCall = time - lastCallTime, timeSinceLastInvoke = time - lastInvokeTime; - return lastCallTime === void 0 || timeSinceLastCall >= wait || timeSinceLastCall < 0 || maxing && timeSinceLastInvoke >= maxWait; - } - function timerExpired() { - var time = now(); - if (shouldInvoke(time)) { - return trailingEdge(time); - } - timerId = setTimeout(timerExpired, remainingWait(time)); - } - function trailingEdge(time) { - timerId = void 0; - if (trailing && lastArgs) { - return invokeFunc(time); - } - lastArgs = lastThis = void 0; - return result; - } - function cancel() { - if (timerId !== void 0) { - clearTimeout(timerId); - } - lastInvokeTime = 0; - lastArgs = lastCallTime = lastThis = timerId = void 0; - } - function flush() { - return timerId === void 0 ? result : trailingEdge(now()); - } - function debounced() { - var time = now(), isInvoking = shouldInvoke(time); - lastArgs = arguments; - lastThis = this; - lastCallTime = time; - if (isInvoking) { - if (timerId === void 0) { - return leadingEdge(lastCallTime); - } - if (maxing) { - timerId = setTimeout(timerExpired, wait); - return invokeFunc(lastCallTime); - } - } - if (timerId === void 0) { - timerId = setTimeout(timerExpired, wait); - } - return result; - } - debounced.cancel = cancel; - debounced.flush = flush; - return debounced; - } - function throttle2(func, wait, options) { - var leading = true, trailing = true; - if (typeof func != "function") { - throw new TypeError(FUNC_ERROR_TEXT); - } - if (isObject(options)) { - leading = "leading" in options ? !!options.leading : leading; - trailing = "trailing" in options ? !!options.trailing : trailing; - } - return debounce2(func, wait, { - "leading": leading, - "maxWait": wait, - "trailing": trailing - }); - } - function isObject(value) { - var type = typeof value; - return !!value && (type == "object" || type == "function"); - } - function isObjectLike(value) { - return !!value && typeof value == "object"; - } - function isSymbol(value) { - return typeof value == "symbol" || isObjectLike(value) && objectToString.call(value) == symbolTag; - } - function toNumber(value) { - if (typeof value == "number") { - return value; - } - if (isSymbol(value)) { - return NAN; - } - if (isObject(value)) { - var other = typeof value.valueOf == "function" ? value.valueOf() : value; - value = isObject(other) ? other + "" : other; - } - if (typeof value != "string") { - return value === 0 ? value : +value; - } - value = value.replace(reTrim, ""); - var isBinary = reIsBinary.test(value); - return isBinary || reIsOctal.test(value) ? freeParseInt(value.slice(2), isBinary ? 2 : 8) : reIsBadHex.test(value) ? NAN : +value; - } - module.exports = throttle2; - } -}); - -// node_modules/lodash.uniq/index.js -var require_lodash2 = __commonJS({ - "node_modules/lodash.uniq/index.js"(exports, module) { - init_checked_fetch(); - init_modules_watch_stub(); - var LARGE_ARRAY_SIZE = 200; - var HASH_UNDEFINED = "__lodash_hash_undefined__"; - var INFINITY = 1 / 0; - var funcTag = "[object Function]"; - var genTag = "[object GeneratorFunction]"; - var reRegExpChar = /[\\^$.*+?()[\]{}|]/g; - var reIsHostCtor = /^\[object .+?Constructor\]$/; - var freeGlobal = typeof global == "object" && global && global.Object === Object && global; - var freeSelf = typeof self == "object" && self && self.Object === Object && self; - var root = freeGlobal || freeSelf || Function("return this")(); - function arrayIncludes(array2, value) { - var length = array2 ? array2.length : 0; - return !!length && baseIndexOf(array2, value, 0) > -1; - } - function arrayIncludesWith(array2, value, comparator) { - var index = -1, length = array2 ? array2.length : 0; - while (++index < length) { - if (comparator(value, array2[index])) { - return true; - } - } - return false; - } - function baseFindIndex(array2, predicate, fromIndex, fromRight) { - var length = array2.length, index = fromIndex + (fromRight ? 1 : -1); - while (fromRight ? index-- : ++index < length) { - if (predicate(array2[index], index, array2)) { - return index; - } - } - return -1; - } - function baseIndexOf(array2, value, fromIndex) { - if (value !== value) { - return baseFindIndex(array2, baseIsNaN, fromIndex); - } - var index = fromIndex - 1, length = array2.length; - while (++index < length) { - if (array2[index] === value) { - return index; - } - } - return -1; - } - function baseIsNaN(value) { - return value !== value; - } - function cacheHas(cache, key) { - return cache.has(key); - } - function getValue(object2, key) { - return object2 == null ? void 0 : object2[key]; - } - function isHostObject(value) { - var result = false; - if (value != null && typeof value.toString != "function") { - try { - result = !!(value + ""); - } catch (e) { - } - } - return result; - } - function setToArray(set) { - var index = -1, result = Array(set.size); - set.forEach(function(value) { - result[++index] = value; - }); - return result; - } - var arrayProto = Array.prototype; - var funcProto = Function.prototype; - var objectProto = Object.prototype; - var coreJsData = root["__core-js_shared__"]; - var maskSrcKey = function() { - var uid = /[^.]+$/.exec(coreJsData && coreJsData.keys && coreJsData.keys.IE_PROTO || ""); - return uid ? "Symbol(src)_1." + uid : ""; - }(); - var funcToString = funcProto.toString; - var hasOwnProperty2 = objectProto.hasOwnProperty; - var objectToString = objectProto.toString; - var reIsNative = RegExp( - "^" + funcToString.call(hasOwnProperty2).replace(reRegExpChar, "\\$&").replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g, "$1.*?") + "$" - ); - var splice = arrayProto.splice; - var Map2 = getNative(root, "Map"); - var Set2 = getNative(root, "Set"); - var nativeCreate = getNative(Object, "create"); - function Hash(entries) { - var index = -1, length = entries ? entries.length : 0; - this.clear(); - while (++index < length) { - var entry = entries[index]; - this.set(entry[0], entry[1]); - } - } - function hashClear() { - this.__data__ = nativeCreate ? nativeCreate(null) : {}; - } - function hashDelete(key) { - return this.has(key) && delete this.__data__[key]; - } - function hashGet(key) { - var data = this.__data__; - if (nativeCreate) { - var result = data[key]; - return result === HASH_UNDEFINED ? void 0 : result; - } - return hasOwnProperty2.call(data, key) ? data[key] : void 0; - } - function hashHas(key) { - var data = this.__data__; - return nativeCreate ? data[key] !== void 0 : hasOwnProperty2.call(data, key); - } - function hashSet(key, value) { - var data = this.__data__; - data[key] = nativeCreate && value === void 0 ? HASH_UNDEFINED : value; - return this; - } - Hash.prototype.clear = hashClear; - Hash.prototype["delete"] = hashDelete; - Hash.prototype.get = hashGet; - Hash.prototype.has = hashHas; - Hash.prototype.set = hashSet; - function ListCache(entries) { - var index = -1, length = entries ? entries.length : 0; - this.clear(); - while (++index < length) { - var entry = entries[index]; - this.set(entry[0], entry[1]); - } - } - function listCacheClear() { - this.__data__ = []; - } - function listCacheDelete(key) { - var data = this.__data__, index = assocIndexOf(data, key); - if (index < 0) { - return false; - } - var lastIndex = data.length - 1; - if (index == lastIndex) { - data.pop(); - } else { - splice.call(data, index, 1); - } - return true; - } - function listCacheGet(key) { - var data = this.__data__, index = assocIndexOf(data, key); - return index < 0 ? void 0 : data[index][1]; - } - function listCacheHas(key) { - return assocIndexOf(this.__data__, key) > -1; - } - function listCacheSet(key, value) { - var data = this.__data__, index = assocIndexOf(data, key); - if (index < 0) { - data.push([key, value]); - } else { - data[index][1] = value; - } - return this; - } - ListCache.prototype.clear = listCacheClear; - ListCache.prototype["delete"] = listCacheDelete; - ListCache.prototype.get = listCacheGet; - ListCache.prototype.has = listCacheHas; - ListCache.prototype.set = listCacheSet; - function MapCache(entries) { - var index = -1, length = entries ? entries.length : 0; - this.clear(); - while (++index < length) { - var entry = entries[index]; - this.set(entry[0], entry[1]); - } - } - function mapCacheClear() { - this.__data__ = { - "hash": new Hash(), - "map": new (Map2 || ListCache)(), - "string": new Hash() - }; - } - function mapCacheDelete(key) { - return getMapData(this, key)["delete"](key); - } - function mapCacheGet(key) { - return getMapData(this, key).get(key); - } - function mapCacheHas(key) { - return getMapData(this, key).has(key); - } - function mapCacheSet(key, value) { - getMapData(this, key).set(key, value); - return this; - } - MapCache.prototype.clear = mapCacheClear; - MapCache.prototype["delete"] = mapCacheDelete; - MapCache.prototype.get = mapCacheGet; - MapCache.prototype.has = mapCacheHas; - MapCache.prototype.set = mapCacheSet; - function SetCache(values) { - var index = -1, length = values ? values.length : 0; - this.__data__ = new MapCache(); - while (++index < length) { - this.add(values[index]); - } - } - function setCacheAdd(value) { - this.__data__.set(value, HASH_UNDEFINED); - return this; - } - function setCacheHas(value) { - return this.__data__.has(value); - } - SetCache.prototype.add = SetCache.prototype.push = setCacheAdd; - SetCache.prototype.has = setCacheHas; - function assocIndexOf(array2, key) { - var length = array2.length; - while (length--) { - if (eq(array2[length][0], key)) { - return length; - } - } - return -1; - } - function baseIsNative(value) { - if (!isObject(value) || isMasked(value)) { - return false; - } - var pattern = isFunction(value) || isHostObject(value) ? reIsNative : reIsHostCtor; - return pattern.test(toSource(value)); - } - function baseUniq(array2, iteratee, comparator) { - var index = -1, includes = arrayIncludes, length = array2.length, isCommon = true, result = [], seen = result; - if (comparator) { - isCommon = false; - includes = arrayIncludesWith; - } else if (length >= LARGE_ARRAY_SIZE) { - var set = iteratee ? null : createSet(array2); - if (set) { - return setToArray(set); - } - isCommon = false; - includes = cacheHas; - seen = new SetCache(); - } else { - seen = iteratee ? [] : result; - } - outer: - while (++index < length) { - var value = array2[index], computed2 = iteratee ? iteratee(value) : value; - value = comparator || value !== 0 ? value : 0; - if (isCommon && computed2 === computed2) { - var seenIndex = seen.length; - while (seenIndex--) { - if (seen[seenIndex] === computed2) { - continue outer; - } - } - if (iteratee) { - seen.push(computed2); - } - result.push(value); - } else if (!includes(seen, computed2, comparator)) { - if (seen !== result) { - seen.push(computed2); - } - result.push(value); - } - } - return result; - } - var createSet = !(Set2 && 1 / setToArray(new Set2([, -0]))[1] == INFINITY) ? noop2 : function(values) { - return new Set2(values); - }; - function getMapData(map, key) { - var data = map.__data__; - return isKeyable(key) ? data[typeof key == "string" ? "string" : "hash"] : data.map; - } - function getNative(object2, key) { - var value = getValue(object2, key); - return baseIsNative(value) ? value : void 0; - } - function isKeyable(value) { - var type = typeof value; - return type == "string" || type == "number" || type == "symbol" || type == "boolean" ? value !== "__proto__" : value === null; - } - function isMasked(func) { - return !!maskSrcKey && maskSrcKey in func; - } - function toSource(func) { - if (func != null) { - try { - return funcToString.call(func); - } catch (e) { - } - try { - return func + ""; - } catch (e) { - } - } - return ""; - } - function uniq(array2) { - return array2 && array2.length ? baseUniq(array2) : []; - } - function eq(value, other) { - return value === other || value !== value && other !== other; - } - function isFunction(value) { - var tag = isObject(value) ? objectToString.call(value) : ""; - return tag == funcTag || tag == genTag; - } - function isObject(value) { - var type = typeof value; - return !!value && (type == "object" || type == "function"); - } - function noop2() { - } - module.exports = uniq; - } -}); - -// node_modules/lodash.isequal/index.js -var require_lodash3 = __commonJS({ - "node_modules/lodash.isequal/index.js"(exports, module) { - init_checked_fetch(); - init_modules_watch_stub(); - var LARGE_ARRAY_SIZE = 200; - var HASH_UNDEFINED = "__lodash_hash_undefined__"; - var COMPARE_PARTIAL_FLAG = 1; - var COMPARE_UNORDERED_FLAG = 2; - var MAX_SAFE_INTEGER = 9007199254740991; - var argsTag = "[object Arguments]"; - var arrayTag = "[object Array]"; - var asyncTag = "[object AsyncFunction]"; - var boolTag = "[object Boolean]"; - var dateTag = "[object Date]"; - var errorTag = "[object Error]"; - var funcTag = "[object Function]"; - var genTag = "[object GeneratorFunction]"; - var mapTag = "[object Map]"; - var numberTag = "[object Number]"; - var nullTag = "[object Null]"; - var objectTag = "[object Object]"; - var promiseTag = "[object Promise]"; - var proxyTag = "[object Proxy]"; - var regexpTag = "[object RegExp]"; - var setTag = "[object Set]"; - var stringTag = "[object String]"; - var symbolTag = "[object Symbol]"; - var undefinedTag = "[object Undefined]"; - var weakMapTag = "[object WeakMap]"; - var arrayBufferTag = "[object ArrayBuffer]"; - var dataViewTag = "[object DataView]"; - var float32Tag = "[object Float32Array]"; - var float64Tag = "[object Float64Array]"; - var int8Tag = "[object Int8Array]"; - var int16Tag = "[object Int16Array]"; - var int32Tag = "[object Int32Array]"; - var uint8Tag = "[object Uint8Array]"; - var uint8ClampedTag = "[object Uint8ClampedArray]"; - var uint16Tag = "[object Uint16Array]"; - var uint32Tag = "[object Uint32Array]"; - var reRegExpChar = /[\\^$.*+?()[\]{}|]/g; - var reIsHostCtor = /^\[object .+?Constructor\]$/; - var reIsUint = /^(?:0|[1-9]\d*)$/; - var typedArrayTags = {}; - typedArrayTags[float32Tag] = typedArrayTags[float64Tag] = typedArrayTags[int8Tag] = typedArrayTags[int16Tag] = typedArrayTags[int32Tag] = typedArrayTags[uint8Tag] = typedArrayTags[uint8ClampedTag] = typedArrayTags[uint16Tag] = typedArrayTags[uint32Tag] = true; - typedArrayTags[argsTag] = typedArrayTags[arrayTag] = typedArrayTags[arrayBufferTag] = typedArrayTags[boolTag] = typedArrayTags[dataViewTag] = typedArrayTags[dateTag] = typedArrayTags[errorTag] = typedArrayTags[funcTag] = typedArrayTags[mapTag] = typedArrayTags[numberTag] = typedArrayTags[objectTag] = typedArrayTags[regexpTag] = typedArrayTags[setTag] = typedArrayTags[stringTag] = typedArrayTags[weakMapTag] = false; - var freeGlobal = typeof global == "object" && global && global.Object === Object && global; - var freeSelf = typeof self == "object" && self && self.Object === Object && self; - var root = freeGlobal || freeSelf || Function("return this")(); - var freeExports = typeof exports == "object" && exports && !exports.nodeType && exports; - var freeModule = freeExports && typeof module == "object" && module && !module.nodeType && module; - var moduleExports = freeModule && freeModule.exports === freeExports; - var freeProcess = moduleExports && freeGlobal.process; - var nodeUtil = function() { - try { - return freeProcess && freeProcess.binding && freeProcess.binding("util"); - } catch (e) { - } - }(); - var nodeIsTypedArray = nodeUtil && nodeUtil.isTypedArray; - function arrayFilter(array2, predicate) { - var index = -1, length = array2 == null ? 0 : array2.length, resIndex = 0, result = []; - while (++index < length) { - var value = array2[index]; - if (predicate(value, index, array2)) { - result[resIndex++] = value; - } - } - return result; - } - function arrayPush(array2, values) { - var index = -1, length = values.length, offset = array2.length; - while (++index < length) { - array2[offset + index] = values[index]; - } - return array2; - } - function arraySome(array2, predicate) { - var index = -1, length = array2 == null ? 0 : array2.length; - while (++index < length) { - if (predicate(array2[index], index, array2)) { - return true; - } - } - return false; - } - function baseTimes(n2, iteratee) { - var index = -1, result = Array(n2); - while (++index < n2) { - result[index] = iteratee(index); - } - return result; - } - function baseUnary(func) { - return function(value) { - return func(value); - }; - } - function cacheHas(cache, key) { - return cache.has(key); - } - function getValue(object2, key) { - return object2 == null ? void 0 : object2[key]; - } - function mapToArray(map) { - var index = -1, result = Array(map.size); - map.forEach(function(value, key) { - result[++index] = [key, value]; - }); - return result; - } - function overArg(func, transform) { - return function(arg) { - return func(transform(arg)); - }; - } - function setToArray(set) { - var index = -1, result = Array(set.size); - set.forEach(function(value) { - result[++index] = value; - }); - return result; - } - var arrayProto = Array.prototype; - var funcProto = Function.prototype; - var objectProto = Object.prototype; - var coreJsData = root["__core-js_shared__"]; - var funcToString = funcProto.toString; - var hasOwnProperty2 = objectProto.hasOwnProperty; - var maskSrcKey = function() { - var uid = /[^.]+$/.exec(coreJsData && coreJsData.keys && coreJsData.keys.IE_PROTO || ""); - return uid ? "Symbol(src)_1." + uid : ""; - }(); - var nativeObjectToString = objectProto.toString; - var reIsNative = RegExp( - "^" + funcToString.call(hasOwnProperty2).replace(reRegExpChar, "\\$&").replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g, "$1.*?") + "$" - ); - var Buffer2 = moduleExports ? root.Buffer : void 0; - var Symbol2 = root.Symbol; - var Uint8Array2 = root.Uint8Array; - var propertyIsEnumerable = objectProto.propertyIsEnumerable; - var splice = arrayProto.splice; - var symToStringTag = Symbol2 ? Symbol2.toStringTag : void 0; - var nativeGetSymbols = Object.getOwnPropertySymbols; - var nativeIsBuffer = Buffer2 ? Buffer2.isBuffer : void 0; - var nativeKeys = overArg(Object.keys, Object); - var DataView2 = getNative(root, "DataView"); - var Map2 = getNative(root, "Map"); - var Promise2 = getNative(root, "Promise"); - var Set2 = getNative(root, "Set"); - var WeakMap2 = getNative(root, "WeakMap"); - var nativeCreate = getNative(Object, "create"); - var dataViewCtorString = toSource(DataView2); - var mapCtorString = toSource(Map2); - var promiseCtorString = toSource(Promise2); - var setCtorString = toSource(Set2); - var weakMapCtorString = toSource(WeakMap2); - var symbolProto = Symbol2 ? Symbol2.prototype : void 0; - var symbolValueOf = symbolProto ? symbolProto.valueOf : void 0; - function Hash(entries) { - var index = -1, length = entries == null ? 0 : entries.length; - this.clear(); - while (++index < length) { - var entry = entries[index]; - this.set(entry[0], entry[1]); - } - } - function hashClear() { - this.__data__ = nativeCreate ? nativeCreate(null) : {}; - this.size = 0; - } - function hashDelete(key) { - var result = this.has(key) && delete this.__data__[key]; - this.size -= result ? 1 : 0; - return result; - } - function hashGet(key) { - var data = this.__data__; - if (nativeCreate) { - var result = data[key]; - return result === HASH_UNDEFINED ? void 0 : result; - } - return hasOwnProperty2.call(data, key) ? data[key] : void 0; - } - function hashHas(key) { - var data = this.__data__; - return nativeCreate ? data[key] !== void 0 : hasOwnProperty2.call(data, key); - } - function hashSet(key, value) { - var data = this.__data__; - this.size += this.has(key) ? 0 : 1; - data[key] = nativeCreate && value === void 0 ? HASH_UNDEFINED : value; - return this; - } - Hash.prototype.clear = hashClear; - Hash.prototype["delete"] = hashDelete; - Hash.prototype.get = hashGet; - Hash.prototype.has = hashHas; - Hash.prototype.set = hashSet; - function ListCache(entries) { - var index = -1, length = entries == null ? 0 : entries.length; - this.clear(); - while (++index < length) { - var entry = entries[index]; - this.set(entry[0], entry[1]); - } - } - function listCacheClear() { - this.__data__ = []; - this.size = 0; - } - function listCacheDelete(key) { - var data = this.__data__, index = assocIndexOf(data, key); - if (index < 0) { - return false; - } - var lastIndex = data.length - 1; - if (index == lastIndex) { - data.pop(); - } else { - splice.call(data, index, 1); - } - --this.size; - return true; - } - function listCacheGet(key) { - var data = this.__data__, index = assocIndexOf(data, key); - return index < 0 ? void 0 : data[index][1]; - } - function listCacheHas(key) { - return assocIndexOf(this.__data__, key) > -1; - } - function listCacheSet(key, value) { - var data = this.__data__, index = assocIndexOf(data, key); - if (index < 0) { - ++this.size; - data.push([key, value]); - } else { - data[index][1] = value; - } - return this; - } - ListCache.prototype.clear = listCacheClear; - ListCache.prototype["delete"] = listCacheDelete; - ListCache.prototype.get = listCacheGet; - ListCache.prototype.has = listCacheHas; - ListCache.prototype.set = listCacheSet; - function MapCache(entries) { - var index = -1, length = entries == null ? 0 : entries.length; - this.clear(); - while (++index < length) { - var entry = entries[index]; - this.set(entry[0], entry[1]); - } - } - function mapCacheClear() { - this.size = 0; - this.__data__ = { - "hash": new Hash(), - "map": new (Map2 || ListCache)(), - "string": new Hash() - }; - } - function mapCacheDelete(key) { - var result = getMapData(this, key)["delete"](key); - this.size -= result ? 1 : 0; - return result; - } - function mapCacheGet(key) { - return getMapData(this, key).get(key); - } - function mapCacheHas(key) { - return getMapData(this, key).has(key); - } - function mapCacheSet(key, value) { - var data = getMapData(this, key), size = data.size; - data.set(key, value); - this.size += data.size == size ? 0 : 1; - return this; - } - MapCache.prototype.clear = mapCacheClear; - MapCache.prototype["delete"] = mapCacheDelete; - MapCache.prototype.get = mapCacheGet; - MapCache.prototype.has = mapCacheHas; - MapCache.prototype.set = mapCacheSet; - function SetCache(values) { - var index = -1, length = values == null ? 0 : values.length; - this.__data__ = new MapCache(); - while (++index < length) { - this.add(values[index]); - } - } - function setCacheAdd(value) { - this.__data__.set(value, HASH_UNDEFINED); - return this; - } - function setCacheHas(value) { - return this.__data__.has(value); - } - SetCache.prototype.add = SetCache.prototype.push = setCacheAdd; - SetCache.prototype.has = setCacheHas; - function Stack(entries) { - var data = this.__data__ = new ListCache(entries); - this.size = data.size; - } - function stackClear() { - this.__data__ = new ListCache(); - this.size = 0; - } - function stackDelete(key) { - var data = this.__data__, result = data["delete"](key); - this.size = data.size; - return result; - } - function stackGet(key) { - return this.__data__.get(key); - } - function stackHas(key) { - return this.__data__.has(key); - } - function stackSet(key, value) { - var data = this.__data__; - if (data instanceof ListCache) { - var pairs = data.__data__; - if (!Map2 || pairs.length < LARGE_ARRAY_SIZE - 1) { - pairs.push([key, value]); - this.size = ++data.size; - return this; - } - data = this.__data__ = new MapCache(pairs); - } - data.set(key, value); - this.size = data.size; - return this; - } - Stack.prototype.clear = stackClear; - Stack.prototype["delete"] = stackDelete; - Stack.prototype.get = stackGet; - Stack.prototype.has = stackHas; - Stack.prototype.set = stackSet; - function arrayLikeKeys(value, inherited) { - var isArr = isArray(value), isArg = !isArr && isArguments(value), isBuff = !isArr && !isArg && isBuffer(value), isType = !isArr && !isArg && !isBuff && isTypedArray(value), skipIndexes = isArr || isArg || isBuff || isType, result = skipIndexes ? baseTimes(value.length, String) : [], length = result.length; - for (var key in value) { - if ((inherited || hasOwnProperty2.call(value, key)) && !(skipIndexes && // Safari 9 has enumerable `arguments.length` in strict mode. - (key == "length" || // Node.js 0.10 has enumerable non-index properties on buffers. - isBuff && (key == "offset" || key == "parent") || // PhantomJS 2 has enumerable non-index properties on typed arrays. - isType && (key == "buffer" || key == "byteLength" || key == "byteOffset") || // Skip index properties. - isIndex(key, length)))) { - result.push(key); - } - } - return result; - } - function assocIndexOf(array2, key) { - var length = array2.length; - while (length--) { - if (eq(array2[length][0], key)) { - return length; - } - } - return -1; - } - function baseGetAllKeys(object2, keysFunc, symbolsFunc) { - var result = keysFunc(object2); - return isArray(object2) ? result : arrayPush(result, symbolsFunc(object2)); - } - function baseGetTag(value) { - if (value == null) { - return value === void 0 ? undefinedTag : nullTag; - } - return symToStringTag && symToStringTag in Object(value) ? getRawTag(value) : objectToString(value); - } - function baseIsArguments(value) { - return isObjectLike(value) && baseGetTag(value) == argsTag; - } - function baseIsEqual(value, other, bitmask, customizer, stack) { - if (value === other) { - return true; - } - if (value == null || other == null || !isObjectLike(value) && !isObjectLike(other)) { - return value !== value && other !== other; - } - return baseIsEqualDeep(value, other, bitmask, customizer, baseIsEqual, stack); - } - function baseIsEqualDeep(object2, other, bitmask, customizer, equalFunc, stack) { - var objIsArr = isArray(object2), othIsArr = isArray(other), objTag = objIsArr ? arrayTag : getTag(object2), othTag = othIsArr ? arrayTag : getTag(other); - objTag = objTag == argsTag ? objectTag : objTag; - othTag = othTag == argsTag ? objectTag : othTag; - var objIsObj = objTag == objectTag, othIsObj = othTag == objectTag, isSameTag = objTag == othTag; - if (isSameTag && isBuffer(object2)) { - if (!isBuffer(other)) { - return false; - } - objIsArr = true; - objIsObj = false; - } - if (isSameTag && !objIsObj) { - stack || (stack = new Stack()); - return objIsArr || isTypedArray(object2) ? equalArrays(object2, other, bitmask, customizer, equalFunc, stack) : equalByTag(object2, other, objTag, bitmask, customizer, equalFunc, stack); - } - if (!(bitmask & COMPARE_PARTIAL_FLAG)) { - var objIsWrapped = objIsObj && hasOwnProperty2.call(object2, "__wrapped__"), othIsWrapped = othIsObj && hasOwnProperty2.call(other, "__wrapped__"); - if (objIsWrapped || othIsWrapped) { - var objUnwrapped = objIsWrapped ? object2.value() : object2, othUnwrapped = othIsWrapped ? other.value() : other; - stack || (stack = new Stack()); - return equalFunc(objUnwrapped, othUnwrapped, bitmask, customizer, stack); - } - } - if (!isSameTag) { - return false; - } - stack || (stack = new Stack()); - return equalObjects(object2, other, bitmask, customizer, equalFunc, stack); - } - function baseIsNative(value) { - if (!isObject(value) || isMasked(value)) { - return false; - } - var pattern = isFunction(value) ? reIsNative : reIsHostCtor; - return pattern.test(toSource(value)); - } - function baseIsTypedArray(value) { - return isObjectLike(value) && isLength(value.length) && !!typedArrayTags[baseGetTag(value)]; - } - function baseKeys(object2) { - if (!isPrototype(object2)) { - return nativeKeys(object2); - } - var result = []; - for (var key in Object(object2)) { - if (hasOwnProperty2.call(object2, key) && key != "constructor") { - result.push(key); - } - } - return result; - } - function equalArrays(array2, other, bitmask, customizer, equalFunc, stack) { - var isPartial = bitmask & COMPARE_PARTIAL_FLAG, arrLength = array2.length, othLength = other.length; - if (arrLength != othLength && !(isPartial && othLength > arrLength)) { - return false; - } - var stacked = stack.get(array2); - if (stacked && stack.get(other)) { - return stacked == other; - } - var index = -1, result = true, seen = bitmask & COMPARE_UNORDERED_FLAG ? new SetCache() : void 0; - stack.set(array2, other); - stack.set(other, array2); - while (++index < arrLength) { - var arrValue = array2[index], othValue = other[index]; - if (customizer) { - var compared = isPartial ? customizer(othValue, arrValue, index, other, array2, stack) : customizer(arrValue, othValue, index, array2, other, stack); - } - if (compared !== void 0) { - if (compared) { - continue; - } - result = false; - break; - } - if (seen) { - if (!arraySome(other, function(othValue2, othIndex) { - if (!cacheHas(seen, othIndex) && (arrValue === othValue2 || equalFunc(arrValue, othValue2, bitmask, customizer, stack))) { - return seen.push(othIndex); - } - })) { - result = false; - break; - } - } else if (!(arrValue === othValue || equalFunc(arrValue, othValue, bitmask, customizer, stack))) { - result = false; - break; - } - } - stack["delete"](array2); - stack["delete"](other); - return result; - } - function equalByTag(object2, other, tag, bitmask, customizer, equalFunc, stack) { - switch (tag) { - case dataViewTag: - if (object2.byteLength != other.byteLength || object2.byteOffset != other.byteOffset) { - return false; - } - object2 = object2.buffer; - other = other.buffer; - case arrayBufferTag: - if (object2.byteLength != other.byteLength || !equalFunc(new Uint8Array2(object2), new Uint8Array2(other))) { - return false; - } - return true; - case boolTag: - case dateTag: - case numberTag: - return eq(+object2, +other); - case errorTag: - return object2.name == other.name && object2.message == other.message; - case regexpTag: - case stringTag: - return object2 == other + ""; - case mapTag: - var convert = mapToArray; - case setTag: - var isPartial = bitmask & COMPARE_PARTIAL_FLAG; - convert || (convert = setToArray); - if (object2.size != other.size && !isPartial) { - return false; - } - var stacked = stack.get(object2); - if (stacked) { - return stacked == other; - } - bitmask |= COMPARE_UNORDERED_FLAG; - stack.set(object2, other); - var result = equalArrays(convert(object2), convert(other), bitmask, customizer, equalFunc, stack); - stack["delete"](object2); - return result; - case symbolTag: - if (symbolValueOf) { - return symbolValueOf.call(object2) == symbolValueOf.call(other); - } - } - return false; - } - function equalObjects(object2, other, bitmask, customizer, equalFunc, stack) { - var isPartial = bitmask & COMPARE_PARTIAL_FLAG, objProps = getAllKeys(object2), objLength = objProps.length, othProps = getAllKeys(other), othLength = othProps.length; - if (objLength != othLength && !isPartial) { - return false; - } - var index = objLength; - while (index--) { - var key = objProps[index]; - if (!(isPartial ? key in other : hasOwnProperty2.call(other, key))) { - return false; - } - } - var stacked = stack.get(object2); - if (stacked && stack.get(other)) { - return stacked == other; - } - var result = true; - stack.set(object2, other); - stack.set(other, object2); - var skipCtor = isPartial; - while (++index < objLength) { - key = objProps[index]; - var objValue = object2[key], othValue = other[key]; - if (customizer) { - var compared = isPartial ? customizer(othValue, objValue, key, other, object2, stack) : customizer(objValue, othValue, key, object2, other, stack); - } - if (!(compared === void 0 ? objValue === othValue || equalFunc(objValue, othValue, bitmask, customizer, stack) : compared)) { - result = false; - break; - } - skipCtor || (skipCtor = key == "constructor"); - } - if (result && !skipCtor) { - var objCtor = object2.constructor, othCtor = other.constructor; - if (objCtor != othCtor && ("constructor" in object2 && "constructor" in other) && !(typeof objCtor == "function" && objCtor instanceof objCtor && typeof othCtor == "function" && othCtor instanceof othCtor)) { - result = false; - } - } - stack["delete"](object2); - stack["delete"](other); - return result; - } - function getAllKeys(object2) { - return baseGetAllKeys(object2, keys, getSymbols); - } - function getMapData(map, key) { - var data = map.__data__; - return isKeyable(key) ? data[typeof key == "string" ? "string" : "hash"] : data.map; - } - function getNative(object2, key) { - var value = getValue(object2, key); - return baseIsNative(value) ? value : void 0; - } - function getRawTag(value) { - var isOwn = hasOwnProperty2.call(value, symToStringTag), tag = value[symToStringTag]; - try { - value[symToStringTag] = void 0; - var unmasked = true; - } catch (e) { - } - var result = nativeObjectToString.call(value); - if (unmasked) { - if (isOwn) { - value[symToStringTag] = tag; - } else { - delete value[symToStringTag]; - } - } - return result; - } - var getSymbols = !nativeGetSymbols ? stubArray : function(object2) { - if (object2 == null) { - return []; - } - object2 = Object(object2); - return arrayFilter(nativeGetSymbols(object2), function(symbol) { - return propertyIsEnumerable.call(object2, symbol); - }); - }; - var getTag = baseGetTag; - if (DataView2 && getTag(new DataView2(new ArrayBuffer(1))) != dataViewTag || Map2 && getTag(new Map2()) != mapTag || Promise2 && getTag(Promise2.resolve()) != promiseTag || Set2 && getTag(new Set2()) != setTag || WeakMap2 && getTag(new WeakMap2()) != weakMapTag) { - getTag = function(value) { - var result = baseGetTag(value), Ctor = result == objectTag ? value.constructor : void 0, ctorString = Ctor ? toSource(Ctor) : ""; - if (ctorString) { - switch (ctorString) { - case dataViewCtorString: - return dataViewTag; - case mapCtorString: - return mapTag; - case promiseCtorString: - return promiseTag; - case setCtorString: - return setTag; - case weakMapCtorString: - return weakMapTag; - } - } - return result; - }; - } - function isIndex(value, length) { - length = length == null ? MAX_SAFE_INTEGER : length; - return !!length && (typeof value == "number" || reIsUint.test(value)) && (value > -1 && value % 1 == 0 && value < length); - } - function isKeyable(value) { - var type = typeof value; - return type == "string" || type == "number" || type == "symbol" || type == "boolean" ? value !== "__proto__" : value === null; - } - function isMasked(func) { - return !!maskSrcKey && maskSrcKey in func; - } - function isPrototype(value) { - var Ctor = value && value.constructor, proto = typeof Ctor == "function" && Ctor.prototype || objectProto; - return value === proto; - } - function objectToString(value) { - return nativeObjectToString.call(value); - } - function toSource(func) { - if (func != null) { - try { - return funcToString.call(func); - } catch (e) { - } - try { - return func + ""; - } catch (e) { - } - } - return ""; - } - function eq(value, other) { - return value === other || value !== value && other !== other; - } - var isArguments = baseIsArguments(function() { - return arguments; - }()) ? baseIsArguments : function(value) { - return isObjectLike(value) && hasOwnProperty2.call(value, "callee") && !propertyIsEnumerable.call(value, "callee"); - }; - var isArray = Array.isArray; - function isArrayLike(value) { - return value != null && isLength(value.length) && !isFunction(value); - } - var isBuffer = nativeIsBuffer || stubFalse; - function isEqual5(value, other) { - return baseIsEqual(value, other); - } - function isFunction(value) { - if (!isObject(value)) { - return false; - } - var tag = baseGetTag(value); - return tag == funcTag || tag == genTag || tag == asyncTag || tag == proxyTag; - } - function isLength(value) { - return typeof value == "number" && value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER; - } - function isObject(value) { - var type = typeof value; - return value != null && (type == "object" || type == "function"); - } - function isObjectLike(value) { - return value != null && typeof value == "object"; - } - var isTypedArray = nodeIsTypedArray ? baseUnary(nodeIsTypedArray) : baseIsTypedArray; - function keys(object2) { - return isArrayLike(object2) ? arrayLikeKeys(object2) : baseKeys(object2); - } - function stubArray() { - return []; - } - function stubFalse() { - return false; - } - module.exports = isEqual5; - } -}); - -// .wrangler/tmp/bundle-fO5AAb/middleware-loader.entry.ts -init_checked_fetch(); -init_modules_watch_stub(); - -// .wrangler/tmp/bundle-fO5AAb/middleware-insertion-facade.js -init_checked_fetch(); -init_modules_watch_stub(); - -// worker/worker.ts -init_checked_fetch(); -init_modules_watch_stub(); - -// node_modules/cloudflare-workers-unfurl/unfurl.js -init_checked_fetch(); -init_modules_watch_stub(); -var validContentTypes = [ - "text/html", - "application/xhtml+xml", - "application/xml", - "image/*" -]; -function isValidContentType(contentType) { - return ( - // allow unspecified, try to parse it anyway - !contentType || contentType.startsWith("image/") || validContentTypes.some((valid) => contentType.startsWith(valid)) - ); -} -async function unfurl(url) { - if (typeof url !== "string" || !url.match(/^https?:\/\//)) { - return { ok: false, error: "bad-param" }; - } - const meta$ = new MetaExtractor(); - const title$ = new TextExtractor(); - const icon$ = new IconExtractor(); - try { - const headers = new Headers(); - for (const contentType of validContentTypes) { - headers.append("accept", contentType); - } - const res = await fetch(url, { headers }); - if (!res.ok || !isValidContentType(res.headers.get("content-type") ?? "")) { - return { ok: false, error: "failed-fetch" }; - } - if (res.headers.get("content-type")?.startsWith("image/")) { - return { - ok: true, - value: { - image: url, - title: new URL(url).pathname.split("/").pop() || void 0 - } - }; - } - await new HTMLRewriter().on("meta", meta$).on("title", title$).on("link", icon$).transform(res).blob(); - } catch { - return { ok: false, error: "failed-fetch" }; - } - const { og, twitter } = meta$; - const title = og["og:title"] ?? twitter["twitter:title"] ?? title$.string ?? void 0; - const description = og["og:description"] ?? twitter["twitter:description"] ?? meta$.description ?? void 0; - let image = og["og:image:secure_url"] ?? og["og:image"] ?? twitter["twitter:image"] ?? void 0; - let favicon = icon$.appleIcon ?? icon$.icon ?? void 0; - if (image && !image?.startsWith("http")) { - image = new URL(image, url).href; - } - if (favicon && !favicon?.startsWith("http")) { - favicon = new URL(favicon, url).href; - } - return { - ok: true, - value: { - title, - description, - image, - favicon - } - }; -} -async function handleUnfurlRequest(request) { - const url = new URL(request.url).searchParams.get("url"); - if (!url) { - return new Response("Missing URL query parameter.", { status: 400 }); - } - const result = await unfurl(url); - if (result.ok) { - return new Response(JSON.stringify(result.value), { - headers: { "Content-Type": "application/json" } - }); - } else if (result.error === "bad-param") { - return new Response("Bad URL query parameter.", { status: 400 }); - } else { - return new Response("Failed to fetch URL.", { status: 422 }); - } -} -var TextExtractor = class { - /** - * The accumulated text extracted from elements. - * @type {string} - */ - string = ""; - /** - * Handles an incoming piece of text. - * @param {Object} param - The text object. - * @param {string} param.text - The incoming text. - */ - text({ text }) { - this.string += text; - } -}; -var MetaExtractor = class { - /** - * The Open Graph (og) metadata extracted from elements. - * @type {Object.} - */ - og = {}; - /** - * The Twitter metadata extracted from elements. - * @type {Object.} - */ - twitter = {}; - /** - * The description extracted from elements. - * @type {string|null} - */ - description = null; - /** - * Handles an incoming element. - * @param {Element} element - The incoming element. - */ - element(element) { - const property = element.getAttribute("property"); - const name = element.getAttribute("name"); - if (property && property.startsWith("og:")) { - this.og[property] = element.getAttribute("content"); - } else if (name && name.startsWith("twitter:")) { - this.twitter[name] = element.getAttribute("content"); - } else if (name === "description") { - this.description = element.getAttribute("content"); - } - } -}; -var IconExtractor = class { - /** - * The Apple touch icon URL extracted from elements. - * @type {string|null} - */ - appleIcon = null; - /** - * The favicon URL extracted from elements. - * @type {string|null} - */ - icon = null; - /** - * Handles an incoming element. - * @param {Element} element - The incoming element. - */ - element(element) { - if (element.getAttribute("rel") === "icon") { - this.icon = element.getAttribute("href"); - } else if (element.getAttribute("rel") === "apple-touch-icon") { - this.appleIcon = element.getAttribute("href"); - } - } -}; - -// node_modules/itty-router/index.mjs -init_checked_fetch(); -init_modules_watch_stub(); -var t = ({ base: e = "", routes: t2 = [], ...r2 } = {}) => ({ __proto__: new Proxy({}, { get: (r3, o2, a2, s2) => (r4, ...c2) => t2.push([o2.toUpperCase?.(), RegExp(`^${(s2 = (e + r4).replace(/\/+(\/|$)/g, "$1")).replace(/(\/?\.?):(\w+)\+/g, "($1(?<$2>*))").replace(/(\/?\.?):(\w+)/g, "($1(?<$2>[^$1/]+?))").replace(/\./g, "\\.").replace(/(\/?)\*/g, "($1.*)?")}/*$`), c2, s2]) && a2 }), routes: t2, ...r2, async fetch(e2, ...o2) { - let a2, s2, c2 = new URL(e2.url), n2 = e2.query = { __proto__: null }; - for (let [e3, t3] of c2.searchParams) - n2[e3] = n2[e3] ? [].concat(n2[e3], t3) : t3; - e: - try { - for (let t3 of r2.before || []) - if (null != (a2 = await t3(e2.proxy ?? e2, ...o2))) - break e; - t: - for (let [r3, n3, l, i] of t2) - if ((r3 == e2.method || "ALL" == r3) && (s2 = c2.pathname.match(n3))) { - e2.params = s2.groups || {}, e2.route = i; - for (let t3 of l) - if (null != (a2 = await t3(e2.proxy ?? e2, ...o2))) - break t; - } - } catch (t3) { - if (!r2.catch) - throw t3; - a2 = await r2.catch(t3, e2.proxy ?? e2, ...o2); - } - try { - for (let t3 of r2.finally || []) - a2 = await t3(a2, e2.proxy ?? e2, ...o2) ?? a2; - } catch (t3) { - if (!r2.catch) - throw t3; - a2 = await r2.catch(t3, e2.proxy ?? e2, ...o2); - } - return a2; -} }); -var r = (e = "text/plain; charset=utf-8", t2) => (r2, o2 = {}) => { - if (void 0 === r2 || r2 instanceof Response) - return r2; - const a2 = new Response(t2?.(r2) ?? r2, o2.url ? void 0 : o2); - return a2.headers.set("content-type", e), a2; -}; -var o = r("application/json; charset=utf-8", JSON.stringify); -var a = (e) => ({ 400: "Bad Request", 401: "Unauthorized", 403: "Forbidden", 404: "Not Found", 500: "Internal Server Error" })[e] || "Unknown Error"; -var s = (e = 500, t2) => { - if (e instanceof Error) { - const { message: r2, ...o2 } = e; - e = e.status || 500, t2 = { error: r2 || a(e), ...o2 }; - } - return t2 = { status: e, ..."object" == typeof t2 ? t2 : { error: t2 || a(e) } }, o(t2, { status: e }); -}; -var c = (e) => { - e.proxy = new Proxy(e.proxy ?? e, { get: (t2, r2) => t2[r2]?.bind?.(e) ?? t2[r2] ?? t2?.params?.[r2] }); -}; -var n = ({ format: e = o, missing: r2 = () => s(404), finally: a2 = [], before: n2 = [], ...l } = {}) => t({ before: [c, ...n2], catch: s, finally: [(e2, ...t2) => e2 ?? r2(...t2), e, ...a2], ...l }); -var p = r("text/plain; charset=utf-8", String); -var f = r("text/html"); -var u = r("image/jpeg"); -var h = r("image/png"); -var g = r("image/webp"); -var y = (e = {}) => { - const { origin: t2 = "*", credentials: r2 = false, allowMethods: o2 = "*", allowHeaders: a2, exposeHeaders: s2, maxAge: c2 } = e, n2 = (e2) => { - const o3 = e2?.headers.get("origin"); - return true === t2 ? o3 : t2 instanceof RegExp ? t2.test(o3) ? o3 : void 0 : Array.isArray(t2) ? t2.includes(o3) ? o3 : void 0 : t2 instanceof Function ? t2(o3) : "*" == t2 && r2 ? o3 : t2; - }, l = (e2, t3) => { - for (const [r3, o3] of Object.entries(t3)) - o3 && e2.headers.append(r3, o3); - return e2; - }; - return { corsify: (e2, t3) => e2?.headers?.get("access-control-allow-origin") || 101 == e2.status ? e2 : l(e2.clone(), { "access-control-allow-origin": n2(t3), "access-control-allow-credentials": r2 }), preflight: (e2) => { - if ("OPTIONS" == e2.method) { - const t3 = new Response(null, { status: 204 }); - return l(t3, { "access-control-allow-origin": n2(e2), "access-control-allow-methods": o2?.join?.(",") ?? o2, "access-control-expose-headers": s2?.join?.(",") ?? s2, "access-control-allow-headers": a2?.join?.(",") ?? a2 ?? e2.headers.get("access-control-request-headers"), "access-control-max-age": c2, "access-control-allow-credentials": r2 }); - } - } }; -}; - -// worker/assetUploads.ts -init_checked_fetch(); -init_modules_watch_stub(); -function getAssetObjectName(uploadId) { - return `uploads/${uploadId.replace(/[^a-zA-Z0-9\_\-]+/g, "_")}`; -} -async function handleAssetUpload(request, env) { - const objectName = getAssetObjectName(request.params.uploadId); - const contentType = request.headers.get("content-type") ?? ""; - if (!contentType.startsWith("image/") && !contentType.startsWith("video/")) { - return s(400, "Invalid content type"); - } - if (await env.TLDRAW_BUCKET.head(objectName)) { - return s(409, "Upload already exists"); - } - await env.TLDRAW_BUCKET.put(objectName, request.body, { - httpMetadata: request.headers - }); - return { ok: true }; -} -async function handleAssetDownload(request, env, ctx) { - const objectName = getAssetObjectName(request.params.uploadId); - const cacheKey = new Request(request.url, { headers: request.headers }); - const cachedResponse = await caches.default.match(cacheKey); - if (cachedResponse) { - return cachedResponse; - } - const object2 = await env.TLDRAW_BUCKET.get(objectName, { - range: request.headers, - onlyIf: request.headers - }); - if (!object2) { - return s(404); - } - const headers = new Headers(); - object2.writeHttpMetadata(headers); - headers.set("cache-control", "public, max-age=31536000, immutable"); - headers.set("etag", object2.httpEtag); - headers.set("access-control-allow-origin", "*"); - let contentRange; - if (object2.range) { - if ("suffix" in object2.range) { - const start = object2.size - object2.range.suffix; - const end = object2.size - 1; - contentRange = `bytes ${start}-${end}/${object2.size}`; - } else { - const start = object2.range.offset ?? 0; - const end = object2.range.length ? start + object2.range.length - 1 : object2.size - 1; - if (start !== 0 || end !== object2.size - 1) { - contentRange = `bytes ${start}-${end}/${object2.size}`; - } - } - } - if (contentRange) { - headers.set("content-range", contentRange); - } - const body = "body" in object2 && object2.body ? object2.body : null; - const status = body ? contentRange ? 206 : 200 : 304; - if (status === 200) { - const [cacheBody, responseBody] = body.tee(); - ctx.waitUntil(caches.default.put(cacheKey, new Response(cacheBody, { headers, status }))); - return new Response(responseBody, { headers, status }); - } - return new Response(body, { headers, status }); -} - -// worker/TldrawDurableObject.ts -init_checked_fetch(); -init_modules_watch_stub(); - -// node_modules/@tldraw/sync-core/dist-esm/index.mjs -init_checked_fetch(); -init_modules_watch_stub(); - -// node_modules/@tldraw/sync-core/dist-esm/lib/ClientWebSocketAdapter.mjs -init_checked_fetch(); -init_modules_watch_stub(); - -// node_modules/@tldraw/state/dist-esm/index.mjs -init_checked_fetch(); -init_modules_watch_stub(); - -// node_modules/@tldraw/state/dist-esm/lib/helpers.mjs -init_checked_fetch(); -init_modules_watch_stub(); -function isChild(x) { - return x && typeof x === "object" && "parents" in x; -} -function haveParentsChanged(child) { - for (let i = 0, n2 = child.parents.length; i < n2; i++) { - child.parents[i].__unsafe__getWithoutCapture(true); - if (child.parents[i].lastChangedEpoch !== child.parentEpochs[i]) { - return true; - } - } - return false; -} -var detach = (parent, child) => { - if (!parent.children.remove(child)) { - return; - } - if (parent.children.isEmpty && isChild(parent)) { - for (let i = 0, n2 = parent.parents.length; i < n2; i++) { - detach(parent.parents[i], parent); - } - } -}; -var attach = (parent, child) => { - if (!parent.children.add(child)) { - return; - } - if (isChild(parent)) { - for (let i = 0, n2 = parent.parents.length; i < n2; i++) { - attach(parent.parents[i], parent); - } - } -}; -function equals(a2, b) { - const shallowEquals = a2 === b || Object.is(a2, b) || Boolean(a2 && b && typeof a2.equals === "function" && a2.equals(b)); - return shallowEquals; -} -function singleton(key, init) { - const symbol = Symbol.for(`com.tldraw.state/${key}`); - const global2 = globalThis; - global2[symbol] ??= init(); - return global2[symbol]; -} -var EMPTY_ARRAY = singleton("empty_array", () => Object.freeze([])); - -// node_modules/@tldraw/state/dist-esm/lib/ArraySet.mjs -init_checked_fetch(); -init_modules_watch_stub(); -var ARRAY_SIZE_THRESHOLD = 8; -var ArraySet = class { - arraySize = 0; - array = Array(ARRAY_SIZE_THRESHOLD); - set = null; - /** - * Get whether this ArraySet has any elements. - * - * @returns True if this ArraySet has any elements, false otherwise. - */ - // eslint-disable-next-line no-restricted-syntax - get isEmpty() { - if (this.array) { - return this.arraySize === 0; - } - if (this.set) { - return this.set.size === 0; - } - throw new Error("no set or array"); - } - /** - * Add an item to the ArraySet if it is not already present. - * - * @param elem - The element to add. - */ - add(elem) { - if (this.array) { - const idx = this.array.indexOf(elem); - if (idx !== -1) { - return false; - } - if (this.arraySize < ARRAY_SIZE_THRESHOLD) { - this.array[this.arraySize] = elem; - this.arraySize++; - return true; - } else { - this.set = new Set(this.array); - this.array = null; - this.set.add(elem); - return true; - } - } - if (this.set) { - if (this.set.has(elem)) { - return false; - } - this.set.add(elem); - return true; - } - throw new Error("no set or array"); - } - /** - * Remove an item from the ArraySet if it is present. - * - * @param elem - The element to remove - */ - remove(elem) { - if (this.array) { - const idx = this.array.indexOf(elem); - if (idx === -1) { - return false; - } - this.array[idx] = void 0; - this.arraySize--; - if (idx !== this.arraySize) { - this.array[idx] = this.array[this.arraySize]; - this.array[this.arraySize] = void 0; - } - return true; - } - if (this.set) { - if (!this.set.has(elem)) { - return false; - } - this.set.delete(elem); - return true; - } - throw new Error("no set or array"); - } - /** - * Run a callback for each element in the ArraySet. - * - * @param visitor - The callback to run for each element. - */ - visit(visitor) { - if (this.array) { - for (let i = 0; i < this.arraySize; i++) { - const elem = this.array[i]; - if (typeof elem !== "undefined") { - visitor(elem); - } - } - return; - } - if (this.set) { - this.set.forEach(visitor); - return; - } - throw new Error("no set or array"); - } - has(elem) { - if (this.array) { - return this.array.indexOf(elem) !== -1; - } else { - return this.set.has(elem); - } - } - clear() { - if (this.set) { - this.set.clear(); - } else { - this.arraySize = 0; - this.array = []; - } - } - size() { - if (this.set) { - return this.set.size; - } else { - return this.arraySize; - } - } -}; - -// node_modules/@tldraw/state/dist-esm/lib/Atom.mjs -init_checked_fetch(); -init_modules_watch_stub(); - -// node_modules/@tldraw/state/dist-esm/lib/HistoryBuffer.mjs -init_checked_fetch(); -init_modules_watch_stub(); - -// node_modules/@tldraw/state/dist-esm/lib/types.mjs -init_checked_fetch(); -init_modules_watch_stub(); -var RESET_VALUE = Symbol.for("com.tldraw.state/RESET_VALUE"); - -// node_modules/@tldraw/state/dist-esm/lib/HistoryBuffer.mjs -var HistoryBuffer = class { - constructor(capacity) { - this.capacity = capacity; - this.buffer = new Array(capacity); - } - index = 0; - // use a wrap around buffer to store the last N values - buffer; - /** - * Add a diff to the history buffer. - * - * @param lastComputedEpoch - The epoch when the diff was computed. - * @param currentEpoch - The current epoch. - * @param diff - The diff to add, or else a reset value. - */ - pushEntry(lastComputedEpoch, currentEpoch, diff) { - if (diff === void 0) { - return; - } - if (diff === RESET_VALUE) { - this.clear(); - return; - } - this.buffer[this.index] = [lastComputedEpoch, currentEpoch, diff]; - this.index = (this.index + 1) % this.capacity; - } - /** - * Clear the history buffer. - */ - clear() { - this.index = 0; - this.buffer.fill(void 0); - } - /** - * Get the diffs since the given epoch. - * - * @param epoch - The epoch to get diffs since. - * @returns An array of diffs or a flag to reset the history buffer. - */ - getChangesSince(sinceEpoch) { - const { index, capacity, buffer } = this; - for (let i = 0; i < capacity; i++) { - const offset = (index - 1 + capacity - i) % capacity; - const elem = buffer[offset]; - if (!elem) { - return RESET_VALUE; - } - const [fromEpoch, toEpoch] = elem; - if (i === 0 && sinceEpoch >= toEpoch) { - return []; - } - if (fromEpoch <= sinceEpoch && sinceEpoch < toEpoch) { - const len = i + 1; - const result = new Array(len); - for (let j = 0; j < len; j++) { - result[j] = buffer[(offset + j) % capacity][2]; - } - return result; - } - } - return RESET_VALUE; - } -}; - -// node_modules/@tldraw/state/dist-esm/lib/capture.mjs -init_checked_fetch(); -init_modules_watch_stub(); -var CaptureStackFrame = class { - constructor(below, child) { - this.below = below; - this.child = child; - } - offset = 0; - maybeRemoved; -}; -var inst = singleton("capture", () => ({ stack: null })); -function startCapturingParents(child) { - inst.stack = new CaptureStackFrame(inst.stack, child); - child.parentSet.clear(); -} -function stopCapturingParents() { - const frame = inst.stack; - inst.stack = frame.below; - if (frame.offset < frame.child.parents.length) { - for (let i = frame.offset; i < frame.child.parents.length; i++) { - const maybeRemovedParent = frame.child.parents[i]; - if (!frame.child.parentSet.has(maybeRemovedParent)) { - detach(maybeRemovedParent, frame.child); - } - } - frame.child.parents.length = frame.offset; - frame.child.parentEpochs.length = frame.offset; - } - if (frame.maybeRemoved) { - for (let i = 0; i < frame.maybeRemoved.length; i++) { - const maybeRemovedParent = frame.maybeRemoved[i]; - if (!frame.child.parentSet.has(maybeRemovedParent)) { - detach(maybeRemovedParent, frame.child); - } - } - } -} -function maybeCaptureParent(p2) { - if (inst.stack) { - const wasCapturedAlready = inst.stack.child.parentSet.has(p2); - if (wasCapturedAlready) { - return; - } - inst.stack.child.parentSet.add(p2); - if (inst.stack.child.isActivelyListening) { - attach(p2, inst.stack.child); - } - if (inst.stack.offset < inst.stack.child.parents.length) { - const maybeRemovedParent = inst.stack.child.parents[inst.stack.offset]; - if (maybeRemovedParent !== p2) { - if (!inst.stack.maybeRemoved) { - inst.stack.maybeRemoved = [maybeRemovedParent]; - } else { - inst.stack.maybeRemoved.push(maybeRemovedParent); - } - } - } - inst.stack.child.parents[inst.stack.offset] = p2; - inst.stack.child.parentEpochs[inst.stack.offset] = p2.lastChangedEpoch; - inst.stack.offset++; - } -} - -// node_modules/@tldraw/state/dist-esm/lib/transactions.mjs -init_checked_fetch(); -init_modules_watch_stub(); - -// node_modules/@tldraw/state/dist-esm/lib/EffectScheduler.mjs -init_checked_fetch(); -init_modules_watch_stub(); - -// node_modules/@tldraw/state/dist-esm/lib/constants.mjs -init_checked_fetch(); -init_modules_watch_stub(); -var GLOBAL_START_EPOCH = -1; - -// node_modules/@tldraw/state/dist-esm/lib/EffectScheduler.mjs -var __EffectScheduler__ = class { - constructor(name, runEffect, options) { - this.name = name; - this.runEffect = runEffect; - this._scheduleEffect = options?.scheduleEffect; - } - _isActivelyListening = false; - /** - * Whether this scheduler is attached and actively listening to its parents. - * @public - */ - // eslint-disable-next-line no-restricted-syntax - get isActivelyListening() { - return this._isActivelyListening; - } - /** @internal */ - lastTraversedEpoch = GLOBAL_START_EPOCH; - lastReactedEpoch = GLOBAL_START_EPOCH; - _scheduleCount = 0; - /** - * The number of times this effect has been scheduled. - * @public - */ - // eslint-disable-next-line no-restricted-syntax - get scheduleCount() { - return this._scheduleCount; - } - /** @internal */ - parentSet = new ArraySet(); - /** @internal */ - parentEpochs = []; - /** @internal */ - parents = []; - _scheduleEffect; - /** @internal */ - maybeScheduleEffect() { - if (!this._isActivelyListening) - return; - if (this.lastReactedEpoch === getGlobalEpoch()) - return; - if (this.parents.length && !haveParentsChanged(this)) { - this.lastReactedEpoch = getGlobalEpoch(); - return; - } - this.scheduleEffect(); - } - /** @internal */ - scheduleEffect() { - this._scheduleCount++; - if (this._scheduleEffect) { - this._scheduleEffect(this.maybeExecute); - } else { - this.execute(); - } - } - /** @internal */ - maybeExecute = () => { - if (!this._isActivelyListening) - return; - this.execute(); - }; - /** - * Makes this scheduler become 'actively listening' to its parents. - * If it has been executed before it will immediately become eligible to receive 'maybeScheduleEffect' calls. - * If it has not executed before it will need to be manually executed once to become eligible for scheduling, i.e. by calling [[EffectScheduler.execute]]. - * @public - */ - attach() { - this._isActivelyListening = true; - for (let i = 0, n2 = this.parents.length; i < n2; i++) { - attach(this.parents[i], this); - } - } - /** - * Makes this scheduler stop 'actively listening' to its parents. - * It will no longer be eligible to receive 'maybeScheduleEffect' calls until [[EffectScheduler.attach]] is called again. - */ - detach() { - this._isActivelyListening = false; - for (let i = 0, n2 = this.parents.length; i < n2; i++) { - detach(this.parents[i], this); - } - } - /** - * Executes the effect immediately and returns the result. - * @returns The result of the effect. - */ - execute() { - try { - startCapturingParents(this); - const currentEpoch = getGlobalEpoch(); - const result = this.runEffect(this.lastReactedEpoch); - this.lastReactedEpoch = currentEpoch; - return result; - } finally { - stopCapturingParents(); - } - } -}; -var EffectScheduler = singleton( - "EffectScheduler", - () => __EffectScheduler__ -); - -// node_modules/@tldraw/state/dist-esm/lib/transactions.mjs -var Transaction = class { - constructor(parent) { - this.parent = parent; - } - initialAtomValues = /* @__PURE__ */ new Map(); - /** - * Get whether this transaction is a root (no parents). - * - * @public - */ - // eslint-disable-next-line no-restricted-syntax - get isRoot() { - return this.parent === null; - } - /** - * Commit the transaction's changes. - * - * @public - */ - commit() { - if (this.isRoot) { - flushChanges(this.initialAtomValues.keys()); - } else { - this.initialAtomValues.forEach((value, atom2) => { - if (!this.parent.initialAtomValues.has(atom2)) { - this.parent.initialAtomValues.set(atom2, value); - } - }); - } - } - /** - * Abort the transaction. - * - * @public - */ - abort() { - inst2.globalEpoch++; - this.initialAtomValues.forEach((value, atom2) => { - atom2.set(value); - atom2.historyBuffer?.clear(); - }); - this.commit(); - } -}; -var inst2 = singleton("transactions", () => ({ - // The current epoch (global to all atoms). - globalEpoch: GLOBAL_START_EPOCH + 1, - // Whether any transaction is reacting. - globalIsReacting: false, - currentTransaction: null, - cleanupReactors: null, - reactionEpoch: GLOBAL_START_EPOCH + 1 -})); -function getReactionEpoch() { - return inst2.reactionEpoch; -} -function getGlobalEpoch() { - return inst2.globalEpoch; -} -function getIsReacting() { - return inst2.globalIsReacting; -} -function traverse(reactors, child) { - if (child.lastTraversedEpoch === inst2.globalEpoch) { - return; - } - child.lastTraversedEpoch = inst2.globalEpoch; - if (child instanceof EffectScheduler) { - reactors.add(child); - } else { - ; - child.children.visit((c2) => traverse(reactors, c2)); - } -} -function flushChanges(atoms) { - if (inst2.globalIsReacting) { - throw new Error("cannot change atoms during reaction cycle"); - } - try { - inst2.globalIsReacting = true; - inst2.reactionEpoch = inst2.globalEpoch; - const reactors = /* @__PURE__ */ new Set(); - for (const atom2 of atoms) { - atom2.children.visit((child) => traverse(reactors, child)); - } - for (const r2 of reactors) { - r2.maybeScheduleEffect(); - } - let updateDepth = 0; - while (inst2.cleanupReactors?.size) { - if (updateDepth++ > 1e3) { - throw new Error("Reaction update depth limit exceeded"); - } - const reactors2 = inst2.cleanupReactors; - inst2.cleanupReactors = null; - for (const r2 of reactors2) { - r2.maybeScheduleEffect(); - } - } - } finally { - inst2.cleanupReactors = null; - inst2.globalIsReacting = false; - } -} -function atomDidChange(atom2, previousValue) { - if (inst2.globalIsReacting) { - const rs = inst2.cleanupReactors ??= /* @__PURE__ */ new Set(); - atom2.children.visit((child) => traverse(rs, child)); - } else if (!inst2.currentTransaction) { - flushChanges([atom2]); - } else if (!inst2.currentTransaction.initialAtomValues.has(atom2)) { - inst2.currentTransaction.initialAtomValues.set(atom2, previousValue); - } -} -function advanceGlobalEpoch() { - inst2.globalEpoch++; -} -function transaction(fn) { - const txn = new Transaction(inst2.currentTransaction); - inst2.currentTransaction = txn; - try { - let result = void 0; - let rollback = false; - try { - result = fn(() => rollback = true); - } catch (e) { - txn.abort(); - throw e; - } - if (rollback) { - txn.abort(); - } else { - txn.commit(); - } - return result; - } finally { - inst2.currentTransaction = inst2.currentTransaction.parent; - } -} - -// node_modules/@tldraw/state/dist-esm/lib/Atom.mjs -var __Atom__ = class { - constructor(name, current, options) { - this.name = name; - this.current = current; - this.isEqual = options?.isEqual ?? null; - if (!options) - return; - if (options.historyLength) { - this.historyBuffer = new HistoryBuffer(options.historyLength); - } - this.computeDiff = options.computeDiff; - } - isEqual; - computeDiff; - lastChangedEpoch = getGlobalEpoch(); - children = new ArraySet(); - historyBuffer; - __unsafe__getWithoutCapture(_ignoreErrors) { - return this.current; - } - get() { - maybeCaptureParent(this); - return this.current; - } - set(value, diff) { - if (this.isEqual?.(this.current, value) ?? equals(this.current, value)) { - return this.current; - } - advanceGlobalEpoch(); - if (this.historyBuffer) { - this.historyBuffer.pushEntry( - this.lastChangedEpoch, - getGlobalEpoch(), - diff ?? this.computeDiff?.(this.current, value, this.lastChangedEpoch, getGlobalEpoch()) ?? RESET_VALUE - ); - } - this.lastChangedEpoch = getGlobalEpoch(); - const oldValue = this.current; - this.current = value; - atomDidChange(this, oldValue); - return value; - } - update(updater) { - return this.set(updater(this.current)); - } - getDiffSince(epoch) { - maybeCaptureParent(this); - if (epoch >= this.lastChangedEpoch) { - return EMPTY_ARRAY; - } - return this.historyBuffer?.getChangesSince(epoch) ?? RESET_VALUE; - } -}; -var _Atom = singleton("Atom", () => __Atom__); -function atom(name, initialValue, options) { - return new _Atom(name, initialValue, options); -} - -// node_modules/@tldraw/state/dist-esm/lib/Computed.mjs -init_checked_fetch(); -init_modules_watch_stub(); - -// node_modules/@tldraw/state/dist-esm/lib/warnings.mjs -init_checked_fetch(); -init_modules_watch_stub(); - -// node_modules/@tldraw/state/dist-esm/lib/Computed.mjs -var UNINITIALIZED = Symbol.for("com.tldraw.state/UNINITIALIZED"); -var WithDiff = singleton( - "WithDiff", - () => class WithDiff { - constructor(value, diff) { - this.value = value; - this.diff = diff; - } - } -); -var __UNSAFE__Computed = class { - constructor(name, derive, options) { - this.name = name; - this.derive = derive; - if (options?.historyLength) { - this.historyBuffer = new HistoryBuffer(options.historyLength); - } - this.computeDiff = options?.computeDiff; - this.isEqual = options?.isEqual ?? equals; - } - lastChangedEpoch = GLOBAL_START_EPOCH; - lastTraversedEpoch = GLOBAL_START_EPOCH; - /** - * The epoch when the reactor was last checked. - */ - lastCheckedEpoch = GLOBAL_START_EPOCH; - parentSet = new ArraySet(); - parents = []; - parentEpochs = []; - children = new ArraySet(); - // eslint-disable-next-line no-restricted-syntax - get isActivelyListening() { - return !this.children.isEmpty; - } - historyBuffer; - // The last-computed value of this signal. - state = UNINITIALIZED; - // If the signal throws an error we stash it so we can rethrow it on the next get() - error = null; - computeDiff; - isEqual; - __unsafe__getWithoutCapture(ignoreErrors) { - const isNew = this.lastChangedEpoch === GLOBAL_START_EPOCH; - const globalEpoch = getGlobalEpoch(); - if (!isNew && (this.lastCheckedEpoch === globalEpoch || this.isActivelyListening && getIsReacting() && this.lastTraversedEpoch < getReactionEpoch() || !haveParentsChanged(this))) { - this.lastCheckedEpoch = globalEpoch; - if (this.error) { - if (!ignoreErrors) { - throw this.error.thrownValue; - } else { - return this.state; - } - } else { - return this.state; - } - } - try { - startCapturingParents(this); - const result = this.derive(this.state, this.lastCheckedEpoch); - const newState = result instanceof WithDiff ? result.value : result; - const isUninitialized2 = this.state === UNINITIALIZED; - if (isUninitialized2 || !this.isEqual(newState, this.state)) { - if (this.historyBuffer && !isUninitialized2) { - const diff = result instanceof WithDiff ? result.diff : void 0; - this.historyBuffer.pushEntry( - this.lastChangedEpoch, - getGlobalEpoch(), - diff ?? this.computeDiff?.(this.state, newState, this.lastCheckedEpoch, getGlobalEpoch()) ?? RESET_VALUE - ); - } - this.lastChangedEpoch = getGlobalEpoch(); - this.state = newState; - } - this.error = null; - this.lastCheckedEpoch = getGlobalEpoch(); - return this.state; - } catch (e) { - if (this.state !== UNINITIALIZED) { - this.state = UNINITIALIZED; - this.lastChangedEpoch = getGlobalEpoch(); - } - this.lastCheckedEpoch = getGlobalEpoch(); - if (this.historyBuffer) { - this.historyBuffer.clear(); - } - this.error = { thrownValue: e }; - if (!ignoreErrors) - throw e; - return this.state; - } finally { - stopCapturingParents(); - } - } - get() { - try { - return this.__unsafe__getWithoutCapture(); - } finally { - maybeCaptureParent(this); - } - } - getDiffSince(epoch) { - this.__unsafe__getWithoutCapture(true); - maybeCaptureParent(this); - if (epoch >= this.lastChangedEpoch) { - return EMPTY_ARRAY; - } - return this.historyBuffer?.getChangesSince(epoch) ?? RESET_VALUE; - } -}; -var _Computed = singleton("Computed", () => __UNSAFE__Computed); - -// node_modules/@tldraw/state/dist-esm/lib/isSignal.mjs -init_checked_fetch(); -init_modules_watch_stub(); - -// node_modules/@tldraw/state/dist-esm/index.mjs -var currentApiVersion = 1; -var actualApiVersion = singleton("apiVersion", () => currentApiVersion); -if (actualApiVersion !== currentApiVersion) { - throw new Error( - `You have multiple incompatible versions of @tldraw/state in your app. Please deduplicate the package.` - ); -} - -// node_modules/@tldraw/utils/dist-esm/index.mjs -init_checked_fetch(); -init_modules_watch_stub(); -var import_lodash = __toESM(require_lodash(), 1); -var import_lodash2 = __toESM(require_lodash2(), 1); - -// node_modules/@tldraw/utils/dist-esm/lib/PerformanceTracker.mjs -init_checked_fetch(); -init_modules_watch_stub(); - -// node_modules/@tldraw/utils/dist-esm/lib/perf.mjs -init_checked_fetch(); -init_modules_watch_stub(); -var PERFORMANCE_COLORS = { - Good: "#40C057", - Mid: "#FFC078", - Poor: "#E03131" -}; -var PERFORMANCE_PREFIX_COLOR = PERFORMANCE_COLORS.Good; - -// node_modules/@tldraw/utils/dist-esm/lib/array.mjs -init_checked_fetch(); -init_modules_watch_stub(); - -// node_modules/@tldraw/utils/dist-esm/lib/cache.mjs -init_checked_fetch(); -init_modules_watch_stub(); - -// node_modules/@tldraw/utils/dist-esm/lib/control.mjs -init_checked_fetch(); -init_modules_watch_stub(); - -// node_modules/@tldraw/utils/dist-esm/lib/function.mjs -init_checked_fetch(); -init_modules_watch_stub(); -function omitFromStackTrace(fn) { - const wrappedFn = (...args) => { - try { - return fn(...args); - } catch (error) { - if (error instanceof Error && Error.captureStackTrace) { - Error.captureStackTrace(error, wrappedFn); - } - throw error; - } - }; - return wrappedFn; -} - -// node_modules/@tldraw/utils/dist-esm/lib/control.mjs -var Result = { - ok(value) { - return { ok: true, value }; - }, - err(error) { - return { ok: false, error }; - } -}; -function exhaustiveSwitchError(value, property) { - const debugValue = property && value && typeof value === "object" && property in value ? value[property] : value; - throw new Error(`Unknown switch case ${debugValue}`); -} -var assert = omitFromStackTrace( - (value, message) => { - if (!value) { - throw new Error(message || "Assertion Error"); - } - } -); -var assertExists = omitFromStackTrace((value, message) => { - if (value == null) { - throw new Error(message ?? "value must be defined"); - } - return value; -}); - -// node_modules/@tldraw/utils/dist-esm/lib/debounce.mjs -init_checked_fetch(); -init_modules_watch_stub(); - -// node_modules/@tldraw/utils/dist-esm/lib/error.mjs -init_checked_fetch(); -init_modules_watch_stub(); -var annotationsByError = /* @__PURE__ */ new WeakMap(); -function annotateError(error, annotations) { - if (typeof error !== "object" || error === null) - return; - let currentAnnotations = annotationsByError.get(error); - if (!currentAnnotations) { - currentAnnotations = { tags: {}, extras: {} }; - annotationsByError.set(error, currentAnnotations); - } - if (annotations.tags) { - currentAnnotations.tags = { - ...currentAnnotations.tags, - ...annotations.tags - }; - } - if (annotations.extras) { - currentAnnotations.extras = { - ...currentAnnotations.extras, - ...annotations.extras - }; - } -} - -// node_modules/@tldraw/utils/dist-esm/lib/file.mjs -init_checked_fetch(); -init_modules_watch_stub(); - -// node_modules/@tldraw/utils/dist-esm/lib/network.mjs -init_checked_fetch(); -init_modules_watch_stub(); - -// node_modules/@tldraw/utils/dist-esm/lib/hash.mjs -init_checked_fetch(); -init_modules_watch_stub(); - -// node_modules/@tldraw/utils/dist-esm/lib/iterable.mjs -init_checked_fetch(); -init_modules_watch_stub(); - -// node_modules/@tldraw/utils/dist-esm/lib/media/media.mjs -init_checked_fetch(); -init_modules_watch_stub(); - -// node_modules/@tldraw/utils/dist-esm/lib/media/apng.mjs -init_checked_fetch(); -init_modules_watch_stub(); - -// node_modules/@tldraw/utils/dist-esm/lib/media/avif.mjs -init_checked_fetch(); -init_modules_watch_stub(); - -// node_modules/@tldraw/utils/dist-esm/lib/media/gif.mjs -init_checked_fetch(); -init_modules_watch_stub(); - -// node_modules/@tldraw/utils/dist-esm/lib/media/png.mjs -init_checked_fetch(); -init_modules_watch_stub(); -var TABLE = [ - 0, - 1996959894, - 3993919788, - 2567524794, - 124634137, - 1886057615, - 3915621685, - 2657392035, - 249268274, - 2044508324, - 3772115230, - 2547177864, - 162941995, - 2125561021, - 3887607047, - 2428444049, - 498536548, - 1789927666, - 4089016648, - 2227061214, - 450548861, - 1843258603, - 4107580753, - 2211677639, - 325883990, - 1684777152, - 4251122042, - 2321926636, - 335633487, - 1661365465, - 4195302755, - 2366115317, - 997073096, - 1281953886, - 3579855332, - 2724688242, - 1006888145, - 1258607687, - 3524101629, - 2768942443, - 901097722, - 1119000684, - 3686517206, - 2898065728, - 853044451, - 1172266101, - 3705015759, - 2882616665, - 651767980, - 1373503546, - 3369554304, - 3218104598, - 565507253, - 1454621731, - 3485111705, - 3099436303, - 671266974, - 1594198024, - 3322730930, - 2970347812, - 795835527, - 1483230225, - 3244367275, - 3060149565, - 1994146192, - 31158534, - 2563907772, - 4023717930, - 1907459465, - 112637215, - 2680153253, - 3904427059, - 2013776290, - 251722036, - 2517215374, - 3775830040, - 2137656763, - 141376813, - 2439277719, - 3865271297, - 1802195444, - 476864866, - 2238001368, - 4066508878, - 1812370925, - 453092731, - 2181625025, - 4111451223, - 1706088902, - 314042704, - 2344532202, - 4240017532, - 1658658271, - 366619977, - 2362670323, - 4224994405, - 1303535960, - 984961486, - 2747007092, - 3569037538, - 1256170817, - 1037604311, - 2765210733, - 3554079995, - 1131014506, - 879679996, - 2909243462, - 3663771856, - 1141124467, - 855842277, - 2852801631, - 3708648649, - 1342533948, - 654459306, - 3188396048, - 3373015174, - 1466479909, - 544179635, - 3110523913, - 3462522015, - 1591671054, - 702138776, - 2966460450, - 3352799412, - 1504918807, - 783551873, - 3082640443, - 3233442989, - 3988292384, - 2596254646, - 62317068, - 1957810842, - 3939845945, - 2647816111, - 81470997, - 1943803523, - 3814918930, - 2489596804, - 225274430, - 2053790376, - 3826175755, - 2466906013, - 167816743, - 2097651377, - 4027552580, - 2265490386, - 503444072, - 1762050814, - 4150417245, - 2154129355, - 426522225, - 1852507879, - 4275313526, - 2312317920, - 282753626, - 1742555852, - 4189708143, - 2394877945, - 397917763, - 1622183637, - 3604390888, - 2714866558, - 953729732, - 1340076626, - 3518719985, - 2797360999, - 1068828381, - 1219638859, - 3624741850, - 2936675148, - 906185462, - 1090812512, - 3747672003, - 2825379669, - 829329135, - 1181335161, - 3412177804, - 3160834842, - 628085408, - 1382605366, - 3423369109, - 3138078467, - 570562233, - 1426400815, - 3317316542, - 2998733608, - 733239954, - 1555261956, - 3268935591, - 3050360625, - 752459403, - 1541320221, - 2607071920, - 3965973030, - 1969922972, - 40735498, - 2617837225, - 3943577151, - 1913087877, - 83908371, - 2512341634, - 3803740692, - 2075208622, - 213261112, - 2463272603, - 3855990285, - 2094854071, - 198958881, - 2262029012, - 4057260610, - 1759359992, - 534414190, - 2176718541, - 4139329115, - 1873836001, - 414664567, - 2282248934, - 4279200368, - 1711684554, - 285281116, - 2405801727, - 4167216745, - 1634467795, - 376229701, - 2685067896, - 3608007406, - 1308918612, - 956543938, - 2808555105, - 3495958263, - 1231636301, - 1047427035, - 2932959818, - 3654703836, - 1088359270, - 936918e3, - 2847714899, - 3736837829, - 1202900863, - 817233897, - 3183342108, - 3401237130, - 1404277552, - 615818150, - 3134207493, - 3453421203, - 1423857449, - 601450431, - 3009837614, - 3294710456, - 1567103746, - 711928724, - 3020668471, - 3272380065, - 1510334235, - 755167117 -]; -if (typeof Int32Array !== "undefined") { - TABLE = new Int32Array(TABLE); -} - -// node_modules/@tldraw/utils/dist-esm/lib/media/webp.mjs -init_checked_fetch(); -init_modules_watch_stub(); - -// node_modules/@tldraw/utils/dist-esm/lib/media/media.mjs -var DEFAULT_SUPPORTED_VECTOR_IMAGE_TYPES = Object.freeze(["image/svg+xml"]); -var DEFAULT_SUPPORTED_STATIC_IMAGE_TYPES = Object.freeze([ - "image/jpeg", - "image/png", - "image/webp" -]); -var DEFAULT_SUPPORTED_ANIMATED_IMAGE_TYPES = Object.freeze([ - "image/gif", - "image/apng", - "image/avif" -]); -var DEFAULT_SUPPORTED_IMAGE_TYPES = Object.freeze([ - ...DEFAULT_SUPPORTED_STATIC_IMAGE_TYPES, - ...DEFAULT_SUPPORTED_VECTOR_IMAGE_TYPES, - ...DEFAULT_SUPPORTED_ANIMATED_IMAGE_TYPES -]); -var DEFAULT_SUPPORT_VIDEO_TYPES = Object.freeze([ - "video/mp4", - "video/webm", - "video/quicktime" -]); -var DEFAULT_SUPPORTED_MEDIA_TYPE_LIST = [ - ...DEFAULT_SUPPORTED_IMAGE_TYPES, - ...DEFAULT_SUPPORT_VIDEO_TYPES -].join(","); - -// node_modules/@tldraw/utils/dist-esm/lib/number.mjs -init_checked_fetch(); -init_modules_watch_stub(); - -// node_modules/@tldraw/utils/dist-esm/lib/object.mjs -init_checked_fetch(); -init_modules_watch_stub(); -function hasOwnProperty(obj, key) { - return Object.prototype.hasOwnProperty.call(obj, key); -} -function getOwnProperty(obj, key) { - if (!hasOwnProperty(obj, key)) { - return void 0; - } - return obj[key]; -} -function objectMapKeys(object2) { - return Object.keys(object2); -} -function objectMapValues(object2) { - return Object.values(object2); -} -function objectMapEntries(object2) { - return Object.entries(object2); -} -function objectMapFromEntries(entries) { - return Object.fromEntries(entries); -} -function mapObjectMapValues(object2, mapper) { - const result = {}; - for (const [key, value] of objectMapEntries(object2)) { - const newValue = mapper(key, value); - result[key] = newValue; - } - return result; -} - -// node_modules/@tldraw/utils/dist-esm/lib/reordering/reordering.mjs -init_checked_fetch(); -init_modules_watch_stub(); - -// node_modules/@tldraw/utils/dist-esm/lib/reordering/dgreensp/dgreensp.mjs -init_checked_fetch(); -init_modules_watch_stub(); -var DIGITS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; -var INTEGER_ZERO = "a0"; -var SMALLEST_INTEGER = "A00000000000000000000000000"; -function getIntegerLength(head) { - if (head >= "a" && head <= "z") { - return head.charCodeAt(0) - "a".charCodeAt(0) + 2; - } else if (head >= "A" && head <= "Z") { - return "Z".charCodeAt(0) - head.charCodeAt(0) + 2; - } else { - throw new Error("Invalid index key head: " + head); - } -} -function validateInteger(int) { - if (int.length !== getIntegerLength(int.charAt(0))) { - throw new Error("invalid integer part of index key: " + int); - } -} -function isNotUndefined(n2) { - if (n2 === void 0) - throw Error("n is undefined"); -} -function incrementInteger(x) { - validateInteger(x); - const [head, ...digs] = x.split(""); - let carry = true; - for (let i = digs.length - 1; carry && i >= 0; i--) { - const d = DIGITS.indexOf(digs[i]) + 1; - if (d === DIGITS.length) { - digs[i] = "0"; - } else { - digs[i] = DIGITS.charAt(d); - carry = false; - } - } - if (carry) { - if (head === "Z") - return "a0"; - if (head === "z") - return void 0; - const h2 = String.fromCharCode(head.charCodeAt(0) + 1); - if (h2 > "a") { - digs.push("0"); - } else { - digs.pop(); - } - return h2 + digs.join(""); - } else { - return head + digs.join(""); - } -} -function decrementInteger(x) { - validateInteger(x); - const [head, ...digs] = x.split(""); - let borrow = true; - for (let i = digs.length - 1; borrow && i >= 0; i--) { - const d = DIGITS.indexOf(digs[i]) - 1; - if (d === -1) { - digs[i] = DIGITS.slice(-1); - } else { - digs[i] = DIGITS.charAt(d); - borrow = false; - } - } - if (borrow) { - if (head === "a") - return "Z" + DIGITS.slice(-1); - if (head === "A") - return void 0; - const h2 = String.fromCharCode(head.charCodeAt(0) - 1); - if (h2 < "Z") { - digs.push(DIGITS.slice(-1)); - } else { - digs.pop(); - } - return h2 + digs.join(""); - } else { - return head + digs.join(""); - } -} -function midpoint(a2, b) { - if (b !== void 0 && a2 >= b) { - throw new Error(a2 + " >= " + b); - } - if (a2.slice(-1) === "0" || b && b.slice(-1) === "0") { - throw new Error("trailing zero"); - } - if (b) { - let n2 = 0; - while ((a2.charAt(n2) || "0") === b.charAt(n2)) { - n2++; - } - if (n2 > 0) { - return b.slice(0, n2) + midpoint(a2.slice(n2), b.slice(n2)); - } - } - const digitA = a2 ? DIGITS.indexOf(a2.charAt(0)) : 0; - const digitB = b !== void 0 ? DIGITS.indexOf(b.charAt(0)) : DIGITS.length; - if (digitB - digitA > 1) { - const midDigit = Math.round(0.5 * (digitA + digitB)); - return DIGITS.charAt(midDigit); - } else { - if (b && b.length > 1) { - return b.slice(0, 1); - } else { - return DIGITS.charAt(digitA) + midpoint(a2.slice(1), void 0); - } - } -} -function getIntegerPart(index) { - const integerPartLength = getIntegerLength(index.charAt(0)); - if (integerPartLength > index.length) { - throw new Error("invalid index: " + index); - } - return index.slice(0, integerPartLength); -} -function validateOrder(index) { - if (index === SMALLEST_INTEGER) { - throw new Error("invalid index: " + index); - } - const i = getIntegerPart(index); - const f2 = index.slice(i.length); - if (f2.slice(-1) === "0") { - throw new Error("invalid index: " + index); - } -} -function generateKeyBetween(a2, b) { - if (a2 !== void 0) - validateOrder(a2); - if (b !== void 0) - validateOrder(b); - if (a2 !== void 0 && b !== void 0 && a2 >= b) { - throw new Error(a2 + " >= " + b); - } - if (a2 === void 0 && b === void 0) { - return INTEGER_ZERO; - } - if (a2 === void 0) { - if (b === void 0) - throw Error("b is undefined"); - const ib2 = getIntegerPart(b); - const fb2 = b.slice(ib2.length); - if (ib2 === SMALLEST_INTEGER) { - return ib2 + midpoint("", fb2); - } - if (ib2 < b) { - return ib2; - } - const ibl = decrementInteger(ib2); - isNotUndefined(ibl); - return ibl; - } - if (b === void 0) { - const ia2 = getIntegerPart(a2); - const fa2 = a2.slice(ia2.length); - const i2 = incrementInteger(ia2); - return i2 === void 0 ? ia2 + midpoint(fa2, void 0) : i2; - } - const ia = getIntegerPart(a2); - const fa = a2.slice(ia.length); - const ib = getIntegerPart(b); - const fb = b.slice(ib.length); - if (ia === ib) { - return ia + midpoint(fa, fb); - } - const i = incrementInteger(ia); - isNotUndefined(i); - return i < b ? i : ia + midpoint(fa, void 0); -} -function generateNKeysBetween(a2, b, n2) { - if (n2 === 0) - return []; - if (n2 === 1) - return [generateKeyBetween(a2, b)]; - if (b === void 0) { - let c22 = generateKeyBetween(a2, b); - const result = [c22]; - for (let i = 0; i < n2 - 1; i++) { - c22 = generateKeyBetween(c22, b); - result.push(c22); - } - return result; - } - if (a2 === void 0) { - let c22 = generateKeyBetween(a2, b); - const result = [c22]; - for (let i = 0; i < n2 - 1; i++) { - c22 = generateKeyBetween(a2, c22); - result.push(c22); - } - result.reverse(); - return result; - } - const mid = Math.floor(n2 / 2); - const c2 = generateKeyBetween(a2, b); - return [...generateNKeysBetween(a2, c2, mid), c2, ...generateNKeysBetween(c2, b, n2 - mid - 1)]; -} - -// node_modules/@tldraw/utils/dist-esm/lib/reordering/reordering.mjs -function validateIndexKey(key) { - validateOrder(key); -} -function getIndices(n2, start = "a1") { - return [start, ...generateNKeysBetween(start, void 0, n2)]; -} -function sortByIndex(a2, b) { - if (a2.index < b.index) { - return -1; - } else if (a2.index > b.index) { - return 1; - } - return 0; -} - -// node_modules/@tldraw/utils/dist-esm/lib/sort.mjs -init_checked_fetch(); -init_modules_watch_stub(); - -// node_modules/@tldraw/utils/dist-esm/lib/storage.mjs -init_checked_fetch(); -init_modules_watch_stub(); - -// node_modules/@tldraw/utils/dist-esm/lib/throttle.mjs -init_checked_fetch(); -init_modules_watch_stub(); -var targetFps = 60; -var targetTimePerFrame = Math.ceil(1e3 / targetFps); - -// node_modules/@tldraw/utils/dist-esm/lib/timers.mjs -init_checked_fetch(); -init_modules_watch_stub(); - -// node_modules/@tldraw/utils/dist-esm/lib/value.mjs -init_checked_fetch(); -init_modules_watch_stub(); -function getStructuredClone() { - if (typeof globalThis !== "undefined" && globalThis.structuredClone) { - return [globalThis.structuredClone, true]; - } - if (typeof global !== "undefined" && global.structuredClone) { - return [global.structuredClone, true]; - } - if (typeof window !== "undefined" && window.structuredClone) { - return [window.structuredClone, true]; - } - return [(i) => i ? JSON.parse(JSON.stringify(i)) : i, false]; -} -var _structuredClone = getStructuredClone(); -var structuredClone = _structuredClone[0]; -var isNativeStructuredClone = _structuredClone[1]; -var STRUCTURED_CLONE_OBJECT_PROTOTYPE = Object.getPrototypeOf(structuredClone({})); - -// node_modules/@tldraw/utils/dist-esm/lib/warn.mjs -init_checked_fetch(); -init_modules_watch_stub(); - -// node_modules/@tldraw/sync-core/dist-esm/lib/chunk.mjs -init_checked_fetch(); -init_modules_watch_stub(); -var MAX_CLIENT_SENT_MESSAGE_SIZE_BYTES = 1024 * 1024; -var MAX_BYTES_PER_CHAR = 4; -var MAX_SAFE_MESSAGE_SIZE = MAX_CLIENT_SENT_MESSAGE_SIZE_BYTES / MAX_BYTES_PER_CHAR; -var chunkRe = /^(\d+)_(.*)$/; -var JsonChunkAssembler = class { - state = "idle"; - handleMessage(msg) { - if (msg.startsWith("{")) { - const error = this.state === "idle" ? void 0 : new Error("Unexpected non-chunk message"); - this.state = "idle"; - return error ? { error } : { data: JSON.parse(msg), stringified: msg }; - } else { - const match = chunkRe.exec(msg); - if (!match) { - this.state = "idle"; - return { error: new Error("Invalid chunk: " + JSON.stringify(msg.slice(0, 20) + "...")) }; - } - const numChunksRemaining = Number(match[1]); - const data = match[2]; - if (this.state === "idle") { - this.state = { - chunksReceived: [data], - totalChunks: numChunksRemaining + 1 - }; - } else { - this.state.chunksReceived.push(data); - if (numChunksRemaining !== this.state.totalChunks - this.state.chunksReceived.length) { - this.state = "idle"; - return { error: new Error(`Chunks received in wrong order`) }; - } - } - if (this.state.chunksReceived.length === this.state.totalChunks) { - try { - const stringified = this.state.chunksReceived.join(""); - const data2 = JSON.parse(stringified); - return { data: data2, stringified }; - } catch (e) { - return { error: e }; - } finally { - this.state = "idle"; - } - } - return null; - } - } -}; - -// node_modules/@tldraw/sync-core/dist-esm/lib/TLSyncClient.mjs -init_checked_fetch(); -init_modules_watch_stub(); - -// node_modules/@tldraw/store/dist-esm/index.mjs -init_checked_fetch(); -init_modules_watch_stub(); - -// node_modules/@tldraw/store/dist-esm/lib/IncrementalSetConstructor.mjs -init_checked_fetch(); -init_modules_watch_stub(); - -// node_modules/@tldraw/store/dist-esm/lib/RecordType.mjs -init_checked_fetch(); -init_modules_watch_stub(); - -// node_modules/nanoid/index.browser.js -init_checked_fetch(); -init_modules_watch_stub(); -var nanoid = (size = 21) => crypto.getRandomValues(new Uint8Array(size)).reduce((id, byte) => { - byte &= 63; - if (byte < 36) { - id += byte.toString(36); - } else if (byte < 62) { - id += (byte - 26).toString(36).toUpperCase(); - } else if (byte > 62) { - id += "-"; - } else { - id += "_"; - } - return id; -}, ""); - -// node_modules/@tldraw/store/dist-esm/lib/RecordType.mjs -var RecordType = class { - constructor(typeName, config) { - this.typeName = typeName; - this.createDefaultProperties = config.createDefaultProperties; - this.validator = config.validator ?? { validate: (r2) => r2 }; - this.scope = config.scope ?? "document"; - this.ephemeralKeys = config.ephemeralKeys; - const ephemeralKeySet = /* @__PURE__ */ new Set(); - if (config.ephemeralKeys) { - for (const [key, isEphemeral] of objectMapEntries(config.ephemeralKeys)) { - if (isEphemeral) - ephemeralKeySet.add(key); - } - } - this.ephemeralKeySet = ephemeralKeySet; - } - createDefaultProperties; - validator; - ephemeralKeys; - ephemeralKeySet; - scope; - /** - * Create a new record of this type. - * - * @param properties - The properties of the record. - * @returns The new record. - */ - create(properties) { - const result = { ...this.createDefaultProperties(), id: this.createId() }; - for (const [k, v] of Object.entries(properties)) { - if (v !== void 0) { - result[k] = v; - } - } - result.typeName = this.typeName; - return result; - } - /** - * Clone a record of this type. - * - * @param record - The record to clone. - * @returns The cloned record. - * @public - */ - clone(record) { - return { ...structuredClone(record), id: this.createId() }; - } - /** - * Create a new ID for this record type. - * - * @example - * - * ```ts - * const id = recordType.createId() - * ``` - * - * @returns The new ID. - * @public - */ - createId(customUniquePart) { - return this.typeName + ":" + (customUniquePart ?? nanoid()); - } - /** - * Create a new ID for this record type based on the given ID. - * - * @example - * - * ```ts - * const id = recordType.createCustomId('myId') - * ``` - * - * @deprecated - Use `createId` instead. - * @param id - The ID to base the new ID on. - * @returns The new ID. - */ - createCustomId(id) { - return this.typeName + ":" + id; - } - /** - * Takes an id like `user:123` and returns the part after the colon `123` - * - * @param id - The id - * @returns - */ - parseId(id) { - if (!this.isId(id)) { - throw new Error(`ID "${id}" is not a valid ID for type "${this.typeName}"`); - } - return id.slice(this.typeName.length + 1); - } - /** - * Check whether a record is an instance of this record type. - * - * @example - * - * ```ts - * const result = recordType.isInstance(someRecord) - * ``` - * - * @param record - The record to check. - * @returns Whether the record is an instance of this record type. - */ - isInstance = (record) => { - return record?.typeName === this.typeName; - }; - /** - * Check whether an id is an id of this type. - * - * @example - * - * ```ts - * const result = recordType.isIn('someId') - * ``` - * - * @param id - The id to check. - * @returns Whether the id is an id of this type. - */ - isId(id) { - if (!id) - return false; - for (let i = 0; i < this.typeName.length; i++) { - if (id[i] !== this.typeName[i]) - return false; - } - return id[this.typeName.length] === ":"; - } - /** - * Create a new RecordType that has the same type name as this RecordType and includes the given - * default properties. - * - * @example - * - * ```ts - * const authorType = createRecordType('author', () => ({ living: true })) - * const deadAuthorType = authorType.withDefaultProperties({ living: false }) - * ``` - * - * @param fn - A function that returns the default properties of the new RecordType. - * @returns The new RecordType. - */ - withDefaultProperties(createDefaultProperties) { - return new RecordType(this.typeName, { - createDefaultProperties, - validator: this.validator, - scope: this.scope, - ephemeralKeys: this.ephemeralKeys - }); - } - /** - * Check that the passed in record passes the validations for this type. Returns its input - * correctly typed if it does, but throws an error otherwise. - */ - validate(record, recordBefore) { - if (recordBefore && this.validator.validateUsingKnownGoodVersion) { - return this.validator.validateUsingKnownGoodVersion(recordBefore, record); - } - return this.validator.validate(record); - } -}; -function createRecordType(typeName, config) { - return new RecordType(typeName, { - createDefaultProperties: () => ({}), - validator: config.validator, - scope: config.scope, - ephemeralKeys: config.ephemeralKeys - }); -} - -// node_modules/@tldraw/store/dist-esm/lib/RecordsDiff.mjs -init_checked_fetch(); -init_modules_watch_stub(); - -// node_modules/@tldraw/store/dist-esm/lib/Store.mjs -init_checked_fetch(); -init_modules_watch_stub(); - -// node_modules/@tldraw/store/dist-esm/lib/StoreQueries.mjs -init_checked_fetch(); -init_modules_watch_stub(); -var import_lodash3 = __toESM(require_lodash3(), 1); - -// node_modules/@tldraw/store/dist-esm/lib/executeQuery.mjs -init_checked_fetch(); -init_modules_watch_stub(); - -// node_modules/@tldraw/store/dist-esm/lib/setUtils.mjs -init_checked_fetch(); -init_modules_watch_stub(); - -// node_modules/@tldraw/store/dist-esm/lib/StoreSideEffects.mjs -init_checked_fetch(); -init_modules_watch_stub(); - -// node_modules/@tldraw/store/dist-esm/lib/devFreeze.mjs -init_checked_fetch(); -init_modules_watch_stub(); - -// node_modules/@tldraw/store/dist-esm/lib/StoreSchema.mjs -init_checked_fetch(); -init_modules_watch_stub(); - -// node_modules/@tldraw/store/dist-esm/lib/migrate.mjs -init_checked_fetch(); -init_modules_watch_stub(); -function squashDependsOn(sequence) { - const result = []; - for (let i = sequence.length - 1; i >= 0; i--) { - const elem = sequence[i]; - if (!("id" in elem)) { - const dependsOn = elem.dependsOn; - const prev = result[0]; - if (prev) { - result[0] = { - ...prev, - dependsOn: dependsOn.concat(prev.dependsOn ?? []) - }; - } - } else { - result.unshift(elem); - } - } - return result; -} -function createMigrationSequence({ - sequence, - sequenceId, - retroactive = true -}) { - const migrations = { - sequenceId, - retroactive, - sequence: squashDependsOn(sequence) - }; - validateMigrations(migrations); - return migrations; -} -function createMigrationIds(sequenceId, versions) { - return Object.fromEntries( - objectMapEntries(versions).map(([key, version]) => [key, `${sequenceId}/${version}`]) - ); -} -function createRecordMigrationSequence(opts) { - const sequenceId = opts.sequenceId; - return createMigrationSequence({ - sequenceId, - retroactive: opts.retroactive ?? true, - sequence: opts.sequence.map( - (m) => "id" in m ? { - ...m, - scope: "record", - filter: (r2) => r2.typeName === opts.recordType && (m.filter?.(r2) ?? true) && (opts.filter?.(r2) ?? true) - } : m - ) - }); -} -function sortMigrations(migrations) { - const byId = new Map(migrations.map((m) => [m.id, m])); - const isProcessing = /* @__PURE__ */ new Set(); - const result = []; - function process2(m) { - assert(!isProcessing.has(m.id), `Circular dependency in migrations: ${m.id}`); - isProcessing.add(m.id); - const { version, sequenceId } = parseMigrationId(m.id); - const parent = byId.get(`${sequenceId}/${version - 1}`); - if (parent) { - process2(parent); - } - if (m.dependsOn) { - for (const dep of m.dependsOn) { - const depMigration = byId.get(dep); - if (depMigration) { - process2(depMigration); - } - } - } - byId.delete(m.id); - result.push(m); - } - for (const m of byId.values()) { - process2(m); - } - return result; -} -function parseMigrationId(id) { - const [sequenceId, version] = id.split("/"); - return { sequenceId, version: parseInt(version) }; -} -function validateMigrationId(id, expectedSequenceId) { - if (expectedSequenceId) { - assert( - id.startsWith(expectedSequenceId + "/"), - `Every migration in sequence '${expectedSequenceId}' must have an id starting with '${expectedSequenceId}/'. Got invalid id: '${id}'` - ); - } - assert(id.match(/^(.*?)\/(0|[1-9]\d*)$/), `Invalid migration id: '${id}'`); -} -function validateMigrations(migrations) { - assert( - !migrations.sequenceId.includes("/"), - `sequenceId cannot contain a '/', got ${migrations.sequenceId}` - ); - assert(migrations.sequenceId.length, "sequenceId must be a non-empty string"); - if (migrations.sequence.length === 0) { - return; - } - validateMigrationId(migrations.sequence[0].id, migrations.sequenceId); - let n2 = parseMigrationId(migrations.sequence[0].id).version; - assert( - n2 === 1, - `Expected the first migrationId to be '${migrations.sequenceId}/1' but got '${migrations.sequence[0].id}'` - ); - for (let i = 1; i < migrations.sequence.length; i++) { - const id = migrations.sequence[i].id; - validateMigrationId(id, migrations.sequenceId); - const m = parseMigrationId(id).version; - assert( - m === n2 + 1, - `Migration id numbers must increase in increments of 1, expected ${migrations.sequenceId}/${n2 + 1} but got '${migrations.sequence[i].id}'` - ); - n2 = m; - } -} -var MigrationFailureReason = /* @__PURE__ */ ((MigrationFailureReason2) => { - MigrationFailureReason2["IncompatibleSubtype"] = "incompatible-subtype"; - MigrationFailureReason2["UnknownType"] = "unknown-type"; - MigrationFailureReason2["TargetVersionTooNew"] = "target-version-too-new"; - MigrationFailureReason2["TargetVersionTooOld"] = "target-version-too-old"; - MigrationFailureReason2["MigrationError"] = "migration-error"; - MigrationFailureReason2["UnrecognizedSubtype"] = "unrecognized-subtype"; - return MigrationFailureReason2; -})(MigrationFailureReason || {}); - -// node_modules/@tldraw/store/dist-esm/lib/StoreSchema.mjs -function upgradeSchema(schema2) { - if (schema2.schemaVersion > 2 || schema2.schemaVersion < 1) - return Result.err("Bad schema version"); - if (schema2.schemaVersion === 2) - return Result.ok(schema2); - const result = { - schemaVersion: 2, - sequences: {} - }; - for (const [typeName, recordVersion] of Object.entries(schema2.recordVersions)) { - result.sequences[`com.tldraw.${typeName}`] = recordVersion.version; - if ("subTypeKey" in recordVersion) { - for (const [subType, version] of Object.entries(recordVersion.subTypeVersions)) { - result.sequences[`com.tldraw.${typeName}.${subType}`] = version; - } - } - } - return Result.ok(result); -} -var StoreSchema = class { - constructor(types, options) { - this.types = types; - this.options = options; - for (const m of options.migrations ?? []) { - assert(!this.migrations[m.sequenceId], `Duplicate migration sequenceId ${m.sequenceId}`); - validateMigrations(m); - this.migrations[m.sequenceId] = m; - } - const allMigrations = Object.values(this.migrations).flatMap((m) => m.sequence); - this.sortedMigrations = sortMigrations(allMigrations); - for (const migration of this.sortedMigrations) { - if (!migration.dependsOn?.length) - continue; - for (const dep of migration.dependsOn) { - const depMigration = allMigrations.find((m) => m.id === dep); - assert(depMigration, `Migration '${migration.id}' depends on missing migration '${dep}'`); - } - } - } - static create(types, options) { - return new StoreSchema(types, options ?? {}); - } - migrations = {}; - sortedMigrations; - validateRecord(store, record, phase, recordBefore) { - try { - const recordType = getOwnProperty(this.types, record.typeName); - if (!recordType) { - throw new Error(`Missing definition for record type ${record.typeName}`); - } - return recordType.validate(record, recordBefore ?? void 0); - } catch (error) { - if (this.options.onValidationFailure) { - return this.options.onValidationFailure({ - store, - record, - phase, - recordBefore, - error - }); - } else { - throw error; - } - } - } - // TODO: use a weakmap to store the result of this function - getMigrationsSince(persistedSchema) { - const upgradeResult = upgradeSchema(persistedSchema); - if (!upgradeResult.ok) { - return upgradeResult; - } - const schema2 = upgradeResult.value; - const sequenceIdsToInclude = new Set( - // start with any shared sequences - Object.keys(schema2.sequences).filter((sequenceId) => this.migrations[sequenceId]) - ); - for (const sequenceId in this.migrations) { - if (schema2.sequences[sequenceId] === void 0 && this.migrations[sequenceId].retroactive) { - sequenceIdsToInclude.add(sequenceId); - } - } - if (sequenceIdsToInclude.size === 0) { - return Result.ok([]); - } - const allMigrationsToInclude = /* @__PURE__ */ new Set(); - for (const sequenceId of sequenceIdsToInclude) { - const theirVersion = schema2.sequences[sequenceId]; - if (typeof theirVersion !== "number" && this.migrations[sequenceId].retroactive || theirVersion === 0) { - for (const migration of this.migrations[sequenceId].sequence) { - allMigrationsToInclude.add(migration.id); - } - continue; - } - const theirVersionId = `${sequenceId}/${theirVersion}`; - const idx = this.migrations[sequenceId].sequence.findIndex((m) => m.id === theirVersionId); - if (idx === -1) { - return Result.err("Incompatible schema?"); - } - for (const migration of this.migrations[sequenceId].sequence.slice(idx + 1)) { - allMigrationsToInclude.add(migration.id); - } - } - return Result.ok(this.sortedMigrations.filter(({ id }) => allMigrationsToInclude.has(id))); - } - migratePersistedRecord(record, persistedSchema, direction = "up") { - const migrations = this.getMigrationsSince(persistedSchema); - if (!migrations.ok) { - console.error("Error migrating record", migrations.error); - return { type: "error", reason: MigrationFailureReason.MigrationError }; - } - let migrationsToApply = migrations.value; - if (migrationsToApply.length === 0) { - return { type: "success", value: record }; - } - if (migrationsToApply.some((m) => m.scope === "store")) { - return { - type: "error", - reason: direction === "down" ? MigrationFailureReason.TargetVersionTooOld : MigrationFailureReason.TargetVersionTooNew - }; - } - if (direction === "down") { - if (!migrationsToApply.every((m) => m.down)) { - return { - type: "error", - reason: MigrationFailureReason.TargetVersionTooOld - }; - } - migrationsToApply = migrationsToApply.slice().reverse(); - } - record = structuredClone(record); - try { - for (const migration of migrationsToApply) { - if (migration.scope === "store") - throw new Error( - /* won't happen, just for TS */ - ); - const shouldApply = migration.filter ? migration.filter(record) : true; - if (!shouldApply) - continue; - const result = migration[direction](record); - if (result) { - record = structuredClone(result); - } - } - } catch (e) { - console.error("Error migrating record", e); - return { type: "error", reason: MigrationFailureReason.MigrationError }; - } - return { type: "success", value: record }; - } - migrateStoreSnapshot(snapshot) { - let { store } = snapshot; - const migrations = this.getMigrationsSince(snapshot.schema); - if (!migrations.ok) { - console.error("Error migrating store", migrations.error); - return { type: "error", reason: MigrationFailureReason.MigrationError }; - } - const migrationsToApply = migrations.value; - if (migrationsToApply.length === 0) { - return { type: "success", value: store }; - } - store = structuredClone(store); - try { - for (const migration of migrationsToApply) { - if (migration.scope === "record") { - for (const [id, record] of Object.entries(store)) { - const shouldApply = migration.filter ? migration.filter(record) : true; - if (!shouldApply) - continue; - const result = migration.up(record); - if (result) { - store[id] = structuredClone(result); - } - } - } else if (migration.scope === "store") { - const result = migration.up(store); - if (result) { - store = structuredClone(result); - } - } else { - exhaustiveSwitchError(migration); - } - } - } catch (e) { - console.error("Error migrating store", e); - return { type: "error", reason: MigrationFailureReason.MigrationError }; - } - return { type: "success", value: store }; - } - /** @internal */ - createIntegrityChecker(store) { - return this.options.createIntegrityChecker?.(store) ?? void 0; - } - serialize() { - return { - schemaVersion: 2, - sequences: Object.fromEntries( - Object.values(this.migrations).map(({ sequenceId, sequence }) => [ - sequenceId, - sequence.length ? parseMigrationId(sequence.at(-1).id).version : 0 - ]) - ) - }; - } - /** - * @deprecated This is only here for legacy reasons, don't use it unless you have david's blessing! - */ - serializeEarliestVersion() { - return { - schemaVersion: 2, - sequences: Object.fromEntries( - Object.values(this.migrations).map(({ sequenceId }) => [sequenceId, 0]) - ) - }; - } - /** @internal */ - getType(typeName) { - const type = getOwnProperty(this.types, typeName); - assert(type, "record type does not exists"); - return type; - } -}; - -// node_modules/@tldraw/sync-core/dist-esm/lib/TLSyncClient.mjs -var import_lodash5 = __toESM(require_lodash3(), 1); - -// node_modules/@tldraw/sync-core/dist-esm/lib/diff.mjs -init_checked_fetch(); -init_modules_watch_stub(); -var import_lodash4 = __toESM(require_lodash3(), 1); -var RecordOpType = { - Put: "put", - Patch: "patch", - Remove: "remove" -}; -var ValueOpType = { - Put: "put", - Delete: "delete", - Append: "append", - Patch: "patch" -}; -function diffRecord(prev, next) { - return diffObject(prev, next, /* @__PURE__ */ new Set(["props"])); -} -function diffObject(prev, next, nestedKeys) { - if (prev === next) { - return null; - } - let result = null; - for (const key of Object.keys(prev)) { - if (!(key in next)) { - if (!result) - result = {}; - result[key] = [ValueOpType.Delete]; - continue; - } - const prevVal = prev[key]; - const nextVal = next[key]; - if (!(0, import_lodash4.default)(prevVal, nextVal)) { - if (nestedKeys?.has(key) && prevVal && nextVal) { - const diff = diffObject(prevVal, nextVal); - if (diff) { - if (!result) - result = {}; - result[key] = [ValueOpType.Patch, diff]; - } - } else if (Array.isArray(nextVal) && Array.isArray(prevVal)) { - const op = diffArray(prevVal, nextVal); - if (op) { - if (!result) - result = {}; - result[key] = op; - } - } else { - if (!result) - result = {}; - result[key] = [ValueOpType.Put, nextVal]; - } - } - } - for (const key of Object.keys(next)) { - if (!(key in prev)) { - if (!result) - result = {}; - result[key] = [ValueOpType.Put, next[key]]; - } - } - return result; -} -function diffValue(valueA, valueB) { - if (Object.is(valueA, valueB)) - return null; - if (Array.isArray(valueA) && Array.isArray(valueB)) { - return diffArray(valueA, valueB); - } else if (!valueA || !valueB || typeof valueA !== "object" || typeof valueB !== "object") { - return (0, import_lodash4.default)(valueA, valueB) ? null : [ValueOpType.Put, valueB]; - } else { - const diff = diffObject(valueA, valueB); - return diff ? [ValueOpType.Patch, diff] : null; - } -} -function diffArray(prevArray, nextArray) { - if (Object.is(prevArray, nextArray)) - return null; - if (prevArray.length === nextArray.length) { - const maxPatchIndexes = Math.max(prevArray.length / 5, 1); - const toPatchIndexes = []; - for (let i = 0; i < prevArray.length; i++) { - if (!(0, import_lodash4.default)(prevArray[i], nextArray[i])) { - toPatchIndexes.push(i); - if (toPatchIndexes.length > maxPatchIndexes) { - return [ValueOpType.Put, nextArray]; - } - } - } - if (toPatchIndexes.length === 0) { - return null; - } - const diff = {}; - for (const i of toPatchIndexes) { - const prevItem = prevArray[i]; - const nextItem = nextArray[i]; - if (!prevItem || !nextItem) { - diff[i] = [ValueOpType.Put, nextItem]; - } else if (typeof prevItem === "object" && typeof nextItem === "object") { - const op = diffValue(prevItem, nextItem); - if (op) { - diff[i] = op; - } - } else { - diff[i] = [ValueOpType.Put, nextItem]; - } - } - return [ValueOpType.Patch, diff]; - } - for (let i = 0; i < prevArray.length; i++) { - if (!(0, import_lodash4.default)(prevArray[i], nextArray[i])) { - return [ValueOpType.Put, nextArray]; - } - } - return [ValueOpType.Append, nextArray.slice(prevArray.length), prevArray.length]; -} -function applyObjectDiff(object2, objectDiff) { - if (!object2 || typeof object2 !== "object") - return object2; - const isArray = Array.isArray(object2); - let newObject = void 0; - const set = (k, v) => { - if (!newObject) { - if (isArray) { - newObject = [...object2]; - } else { - newObject = { ...object2 }; - } - } - if (isArray) { - newObject[Number(k)] = v; - } else { - newObject[k] = v; - } - }; - for (const [key, op] of Object.entries(objectDiff)) { - switch (op[0]) { - case ValueOpType.Put: { - const value = op[1]; - if (!(0, import_lodash4.default)(object2[key], value)) { - set(key, value); - } - break; - } - case ValueOpType.Append: { - const values = op[1]; - const offset = op[2]; - const arr = object2[key]; - if (Array.isArray(arr) && arr.length === offset) { - set(key, [...arr, ...values]); - } - break; - } - case ValueOpType.Patch: { - if (object2[key] && typeof object2[key] === "object") { - const diff = op[1]; - const patched = applyObjectDiff(object2[key], diff); - if (patched !== object2[key]) { - set(key, patched); - } - } - break; - } - case ValueOpType.Delete: { - if (key in object2) { - if (!newObject) { - if (isArray) { - console.error("Can't delete array item yet (this should never happen)"); - newObject = [...object2]; - } else { - newObject = { ...object2 }; - } - } - delete newObject[key]; - } - } - } - } - return newObject ?? object2; -} - -// node_modules/@tldraw/sync-core/dist-esm/lib/interval.mjs -init_checked_fetch(); -init_modules_watch_stub(); -function interval(cb, timeout) { - const i = setInterval(cb, timeout); - return () => clearInterval(i); -} - -// node_modules/@tldraw/sync-core/dist-esm/lib/protocol.mjs -init_checked_fetch(); -init_modules_watch_stub(); -var TLSYNC_PROTOCOL_VERSION = 6; -function getTlsyncProtocolVersion() { - return TLSYNC_PROTOCOL_VERSION; -} -var TLIncompatibilityReason = { - ClientTooOld: "clientTooOld", - ServerTooOld: "serverTooOld", - InvalidRecord: "invalidRecord", - InvalidOperation: "invalidOperation", - RoomNotFound: "roomNotFound" -}; - -// node_modules/@tldraw/sync-core/dist-esm/lib/TLSyncClient.mjs -var PING_INTERVAL = 5e3; -var MAX_TIME_TO_WAIT_FOR_SERVER_INTERACTION_BEFORE_RESETTING_CONNECTION = PING_INTERVAL * 2; - -// node_modules/@tldraw/sync-core/dist-esm/lib/ClientWebSocketAdapter.mjs -var INACTIVE_MAX_DELAY = 1e3 * 60 * 5; - -// node_modules/@tldraw/sync-core/dist-esm/lib/RoomSession.mjs -init_checked_fetch(); -init_modules_watch_stub(); -var RoomSessionState = { - AwaitingConnectMessage: "awaiting-connect-message", - AwaitingRemoval: "awaiting-removal", - Connected: "connected" -}; -var SESSION_START_WAIT_TIME = 1e4; -var SESSION_REMOVAL_WAIT_TIME = 1e4; -var SESSION_IDLE_TIMEOUT = 2e4; - -// node_modules/@tldraw/sync-core/dist-esm/lib/TLRemoteSyncError.mjs -init_checked_fetch(); -init_modules_watch_stub(); - -// node_modules/@tldraw/sync-core/dist-esm/lib/TLSocketRoom.mjs -init_checked_fetch(); -init_modules_watch_stub(); - -// node_modules/@tldraw/sync-core/node_modules/@tldraw/tlschema/dist-esm/index.mjs -init_checked_fetch(); -init_modules_watch_stub(); - -// node_modules/@tldraw/sync-core/node_modules/@tldraw/tlschema/dist-esm/assets/TLBaseAsset.mjs -init_checked_fetch(); -init_modules_watch_stub(); - -// node_modules/@tldraw/validate/dist-esm/index.mjs -init_checked_fetch(); -init_modules_watch_stub(); - -// node_modules/@tldraw/validate/dist-esm/lib/validation.mjs -var validation_exports = {}; -__export(validation_exports, { - ArrayOfValidator: () => ArrayOfValidator, - DictValidator: () => DictValidator, - ObjectValidator: () => ObjectValidator, - UnionValidator: () => UnionValidator, - ValidationError: () => ValidationError, - Validator: () => Validator, - any: () => any, - array: () => array, - arrayOf: () => arrayOf, - bigint: () => bigint, - boolean: () => boolean, - dict: () => dict, - httpUrl: () => httpUrl, - indexKey: () => indexKey, - integer: () => integer, - jsonDict: () => jsonDict, - jsonValue: () => jsonValue, - linkUrl: () => linkUrl, - literal: () => literal, - literalEnum: () => literalEnum, - model: () => model, - nonZeroInteger: () => nonZeroInteger, - nonZeroNumber: () => nonZeroNumber, - nullable: () => nullable, - number: () => number, - numberUnion: () => numberUnion, - object: () => object, - optional: () => optional, - positiveInteger: () => positiveInteger, - positiveNumber: () => positiveNumber, - setEnum: () => setEnum, - srcUrl: () => srcUrl, - string: () => string, - union: () => union, - unknown: () => unknown, - unknownObject: () => unknownObject -}); -init_checked_fetch(); -init_modules_watch_stub(); -function formatPath(path) { - if (!path.length) { - return null; - } - let formattedPath = ""; - for (const item of path) { - if (typeof item === "number") { - formattedPath += `.${item}`; - } else if (item.startsWith("(")) { - if (formattedPath.endsWith(")")) { - formattedPath = `${formattedPath.slice(0, -1)}, ${item.slice(1)}`; - } else { - formattedPath += item; - } - } else { - formattedPath += `.${item}`; - } - } - formattedPath = formattedPath.replace(/id = [^,]+, /, "").replace(/id = [^)]+/, ""); - if (formattedPath.startsWith(".")) { - return formattedPath.slice(1); - } - return formattedPath; -} -var ValidationError = class extends Error { - constructor(rawMessage, path = []) { - const formattedPath = formatPath(path); - const indentedMessage = rawMessage.split("\n").map((line, i) => i === 0 ? line : ` ${line}`).join("\n"); - super(path ? `At ${formattedPath}: ${indentedMessage}` : indentedMessage); - this.rawMessage = rawMessage; - this.path = path; - } - name = "ValidationError"; -}; -function prefixError(path, fn) { - try { - return fn(); - } catch (err) { - if (err instanceof ValidationError) { - throw new ValidationError(err.rawMessage, [path, ...err.path]); - } - throw new ValidationError(err.toString(), [path]); - } -} -function typeToString(value) { - if (value === null) - return "null"; - if (Array.isArray(value)) - return "an array"; - const type = typeof value; - switch (type) { - case "bigint": - case "boolean": - case "function": - case "number": - case "string": - case "symbol": - return `a ${type}`; - case "object": - return `an ${type}`; - case "undefined": - return "undefined"; - default: - exhaustiveSwitchError(type); - } -} -var Validator = class { - constructor(validationFn, validateUsingKnownGoodVersionFn) { - this.validationFn = validationFn; - this.validateUsingKnownGoodVersionFn = validateUsingKnownGoodVersionFn; - } - /** - * Asserts that the passed value is of the correct type and returns it. The returned value is - * guaranteed to be referentially equal to the passed value. - */ - validate(value) { - const validated = this.validationFn(value); - if (!Object.is(value, validated)) { - throw new ValidationError("Validator functions must return the same value they were passed"); - } - return validated; - } - validateUsingKnownGoodVersion(knownGoodValue, newValue) { - if (Object.is(knownGoodValue, newValue)) { - return knownGoodValue; - } - if (this.validateUsingKnownGoodVersionFn) { - return this.validateUsingKnownGoodVersionFn(knownGoodValue, newValue); - } - return this.validate(newValue); - } - /** Checks that the passed value is of the correct type. */ - isValid(value) { - try { - this.validate(value); - return true; - } catch { - return false; - } - } - /** - * Returns a new validator that also accepts null or undefined. The resulting value will always be - * null. - */ - nullable() { - return nullable(this); - } - /** - * Returns a new validator that also accepts null or undefined. The resulting value will always be - * null. - */ - optional() { - return optional(this); - } - /** - * Refine this validation to a new type. The passed-in validation function should throw an error - * if the value can't be converted to the new type, or return the new type otherwise. - */ - refine(otherValidationFn) { - return new Validator( - (value) => { - return otherValidationFn(this.validate(value)); - }, - (knownGoodValue, newValue) => { - const validated = this.validateUsingKnownGoodVersion(knownGoodValue, newValue); - if (Object.is(knownGoodValue, validated)) { - return knownGoodValue; - } - return otherValidationFn(validated); - } - ); - } - check(nameOrCheckFn, checkFn) { - if (typeof nameOrCheckFn === "string") { - return this.refine((value) => { - prefixError(`(check ${nameOrCheckFn})`, () => checkFn(value)); - return value; - }); - } else { - return this.refine((value) => { - nameOrCheckFn(value); - return value; - }); - } - } -}; -var ArrayOfValidator = class extends Validator { - constructor(itemValidator) { - super( - (value) => { - const arr = array.validate(value); - for (let i = 0; i < arr.length; i++) { - prefixError(i, () => itemValidator.validate(arr[i])); - } - return arr; - }, - (knownGoodValue, newValue) => { - if (!itemValidator.validateUsingKnownGoodVersion) - return this.validate(newValue); - const arr = array.validate(newValue); - let isDifferent = knownGoodValue.length !== arr.length; - for (let i = 0; i < arr.length; i++) { - const item = arr[i]; - if (i >= knownGoodValue.length) { - isDifferent = true; - prefixError(i, () => itemValidator.validate(item)); - continue; - } - if (Object.is(knownGoodValue[i], item)) { - continue; - } - const checkedItem = prefixError( - i, - () => itemValidator.validateUsingKnownGoodVersion(knownGoodValue[i], item) - ); - if (!Object.is(checkedItem, knownGoodValue[i])) { - isDifferent = true; - } - } - return isDifferent ? newValue : knownGoodValue; - } - ); - this.itemValidator = itemValidator; - } - nonEmpty() { - return this.check((value) => { - if (value.length === 0) { - throw new ValidationError("Expected a non-empty array"); - } - }); - } - lengthGreaterThan1() { - return this.check((value) => { - if (value.length <= 1) { - throw new ValidationError("Expected an array with length greater than 1"); - } - }); - } -}; -var ObjectValidator = class extends Validator { - constructor(config, shouldAllowUnknownProperties = false) { - super( - (object2) => { - if (typeof object2 !== "object" || object2 === null) { - throw new ValidationError(`Expected object, got ${typeToString(object2)}`); - } - for (const [key, validator] of Object.entries(config)) { - prefixError(key, () => { - ; - validator.validate(getOwnProperty(object2, key)); - }); - } - if (!shouldAllowUnknownProperties) { - for (const key of Object.keys(object2)) { - if (!hasOwnProperty(config, key)) { - throw new ValidationError(`Unexpected property`, [key]); - } - } - } - return object2; - }, - (knownGoodValue, newValue) => { - if (typeof newValue !== "object" || newValue === null) { - throw new ValidationError(`Expected object, got ${typeToString(newValue)}`); - } - let isDifferent = false; - for (const [key, validator] of Object.entries(config)) { - const prev = getOwnProperty(knownGoodValue, key); - const next = getOwnProperty(newValue, key); - if (Object.is(prev, next)) { - continue; - } - const checked = prefixError(key, () => { - const validatable = validator; - if (validatable.validateUsingKnownGoodVersion) { - return validatable.validateUsingKnownGoodVersion(prev, next); - } else { - return validatable.validate(next); - } - }); - if (!Object.is(checked, prev)) { - isDifferent = true; - } - } - if (!shouldAllowUnknownProperties) { - for (const key of Object.keys(newValue)) { - if (!hasOwnProperty(config, key)) { - throw new ValidationError(`Unexpected property`, [key]); - } - } - } - for (const key of Object.keys(knownGoodValue)) { - if (!hasOwnProperty(newValue, key)) { - isDifferent = true; - break; - } - } - return isDifferent ? newValue : knownGoodValue; - } - ); - this.config = config; - this.shouldAllowUnknownProperties = shouldAllowUnknownProperties; - } - allowUnknownProperties() { - return new ObjectValidator(this.config, true); - } - /** - * Extend an object validator by adding additional properties. - * - * @example - * - * ```ts - * const animalValidator = T.object({ - * name: T.string, - * }) - * const catValidator = animalValidator.extend({ - * meowVolume: T.number, - * }) - * ``` - */ - extend(extension) { - return new ObjectValidator({ ...this.config, ...extension }); - } -}; -var UnionValidator = class extends Validator { - constructor(key, config, unknownValueValidation, useNumberKeys) { - super( - (input) => { - this.expectObject(input); - const { matchingSchema, variant } = this.getMatchingSchemaAndVariant(input); - if (matchingSchema === void 0) { - return this.unknownValueValidation(input, variant); - } - return prefixError(`(${key} = ${variant})`, () => matchingSchema.validate(input)); - }, - (prevValue, newValue) => { - this.expectObject(newValue); - this.expectObject(prevValue); - const { matchingSchema, variant } = this.getMatchingSchemaAndVariant(newValue); - if (matchingSchema === void 0) { - return this.unknownValueValidation(newValue, variant); - } - if (getOwnProperty(prevValue, key) !== getOwnProperty(newValue, key)) { - return prefixError(`(${key} = ${variant})`, () => matchingSchema.validate(newValue)); - } - return prefixError(`(${key} = ${variant})`, () => { - if (matchingSchema.validateUsingKnownGoodVersion) { - return matchingSchema.validateUsingKnownGoodVersion(prevValue, newValue); - } else { - return matchingSchema.validate(newValue); - } - }); - } - ); - this.key = key; - this.config = config; - this.unknownValueValidation = unknownValueValidation; - this.useNumberKeys = useNumberKeys; - } - expectObject(value) { - if (typeof value !== "object" || value === null) { - throw new ValidationError(`Expected an object, got ${typeToString(value)}`, []); - } - } - getMatchingSchemaAndVariant(object2) { - const variant = getOwnProperty(object2, this.key); - if (!this.useNumberKeys && typeof variant !== "string") { - throw new ValidationError( - `Expected a string for key "${this.key}", got ${typeToString(variant)}` - ); - } else if (this.useNumberKeys && !Number.isFinite(Number(variant))) { - throw new ValidationError(`Expected a number for key "${this.key}", got "${variant}"`); - } - const matchingSchema = hasOwnProperty(this.config, variant) ? this.config[variant] : void 0; - return { matchingSchema, variant }; - } - validateUnknownVariants(unknownValueValidation) { - return new UnionValidator(this.key, this.config, unknownValueValidation, this.useNumberKeys); - } -}; -var DictValidator = class extends Validator { - constructor(keyValidator, valueValidator) { - super( - (object2) => { - if (typeof object2 !== "object" || object2 === null) { - throw new ValidationError(`Expected object, got ${typeToString(object2)}`); - } - for (const [key, value] of Object.entries(object2)) { - prefixError(key, () => { - keyValidator.validate(key); - valueValidator.validate(value); - }); - } - return object2; - }, - (knownGoodValue, newValue) => { - if (typeof newValue !== "object" || newValue === null) { - throw new ValidationError(`Expected object, got ${typeToString(newValue)}`); - } - let isDifferent = false; - for (const [key, value] of Object.entries(newValue)) { - if (!hasOwnProperty(knownGoodValue, key)) { - isDifferent = true; - prefixError(key, () => { - keyValidator.validate(key); - valueValidator.validate(value); - }); - continue; - } - const prev = getOwnProperty(knownGoodValue, key); - const next = value; - if (Object.is(prev, next)) { - continue; - } - const checked = prefixError(key, () => { - if (valueValidator.validateUsingKnownGoodVersion) { - return valueValidator.validateUsingKnownGoodVersion(prev, next); - } else { - return valueValidator.validate(next); - } - }); - if (!Object.is(checked, prev)) { - isDifferent = true; - } - } - for (const key of Object.keys(knownGoodValue)) { - if (!hasOwnProperty(newValue, key)) { - isDifferent = true; - break; - } - } - return isDifferent ? newValue : knownGoodValue; - } - ); - this.keyValidator = keyValidator; - this.valueValidator = valueValidator; - } -}; -function typeofValidator(type) { - return new Validator((value) => { - if (typeof value !== type) { - throw new ValidationError(`Expected ${type}, got ${typeToString(value)}`); - } - return value; - }); -} -var unknown = new Validator((value) => value); -var any = new Validator((value) => value); -var string = typeofValidator("string"); -var number = typeofValidator("number").check((number2) => { - if (Number.isNaN(number2)) { - throw new ValidationError("Expected a number, got NaN"); - } - if (!Number.isFinite(number2)) { - throw new ValidationError(`Expected a finite number, got ${number2}`); - } -}); -var positiveNumber = number.check((value) => { - if (value < 0) - throw new ValidationError(`Expected a positive number, got ${value}`); -}); -var nonZeroNumber = number.check((value) => { - if (value <= 0) - throw new ValidationError(`Expected a non-zero positive number, got ${value}`); -}); -var integer = number.check((value) => { - if (!Number.isInteger(value)) - throw new ValidationError(`Expected an integer, got ${value}`); -}); -var positiveInteger = integer.check((value) => { - if (value < 0) - throw new ValidationError(`Expected a positive integer, got ${value}`); -}); -var nonZeroInteger = integer.check((value) => { - if (value <= 0) - throw new ValidationError(`Expected a non-zero positive integer, got ${value}`); -}); -var boolean = typeofValidator("boolean"); -var bigint = typeofValidator("bigint"); -function literal(expectedValue) { - return new Validator((actualValue) => { - if (actualValue !== expectedValue) { - throw new ValidationError(`Expected ${expectedValue}, got ${JSON.stringify(actualValue)}`); - } - return expectedValue; - }); -} -var array = new Validator((value) => { - if (!Array.isArray(value)) { - throw new ValidationError(`Expected an array, got ${typeToString(value)}`); - } - return value; -}); -function arrayOf(itemValidator) { - return new ArrayOfValidator(itemValidator); -} -var unknownObject = new Validator((value) => { - if (typeof value !== "object" || value === null) { - throw new ValidationError(`Expected object, got ${typeToString(value)}`); - } - return value; -}); -function object(config) { - return new ObjectValidator(config); -} -function isPlainObject(value) { - return typeof value === "object" && value !== null && (Object.getPrototypeOf(value) === Object.prototype || Object.getPrototypeOf(value) === null || Object.getPrototypeOf(value) === STRUCTURED_CLONE_OBJECT_PROTOTYPE); -} -function isValidJson(value) { - if (value === null || typeof value === "number" || typeof value === "string" || typeof value === "boolean") { - return true; - } - if (Array.isArray(value)) { - return value.every(isValidJson); - } - if (isPlainObject(value)) { - return Object.values(value).every(isValidJson); - } - return false; -} -var jsonValue = new Validator( - (value) => { - if (isValidJson(value)) { - return value; - } - throw new ValidationError(`Expected json serializable value, got ${typeof value}`); - }, - (knownGoodValue, newValue) => { - if (Array.isArray(knownGoodValue) && Array.isArray(newValue)) { - let isDifferent = knownGoodValue.length !== newValue.length; - for (let i = 0; i < newValue.length; i++) { - if (i >= knownGoodValue.length) { - isDifferent = true; - jsonValue.validate(newValue[i]); - continue; - } - const prev = knownGoodValue[i]; - const next = newValue[i]; - if (Object.is(prev, next)) { - continue; - } - const checked = jsonValue.validateUsingKnownGoodVersion(prev, next); - if (!Object.is(checked, prev)) { - isDifferent = true; - } - } - return isDifferent ? newValue : knownGoodValue; - } else if (isPlainObject(knownGoodValue) && isPlainObject(newValue)) { - let isDifferent = false; - for (const key of Object.keys(newValue)) { - if (!hasOwnProperty(knownGoodValue, key)) { - isDifferent = true; - jsonValue.validate(newValue[key]); - continue; - } - const prev = knownGoodValue[key]; - const next = newValue[key]; - if (Object.is(prev, next)) { - continue; - } - const checked = jsonValue.validateUsingKnownGoodVersion(prev, next); - if (!Object.is(checked, prev)) { - isDifferent = true; - } - } - for (const key of Object.keys(knownGoodValue)) { - if (!hasOwnProperty(newValue, key)) { - isDifferent = true; - break; - } - } - return isDifferent ? newValue : knownGoodValue; - } else { - return jsonValue.validate(newValue); - } - } -); -function jsonDict() { - return dict(string, jsonValue); -} -function dict(keyValidator, valueValidator) { - return new DictValidator(keyValidator, valueValidator); -} -function union(key, config) { - return new UnionValidator( - key, - config, - (unknownValue, unknownVariant) => { - throw new ValidationError( - `Expected one of ${Object.keys(config).map((key2) => JSON.stringify(key2)).join(" or ")}, got ${JSON.stringify(unknownVariant)}`, - [key] - ); - }, - false - ); -} -function numberUnion(key, config) { - return new UnionValidator( - key, - config, - (unknownValue, unknownVariant) => { - throw new ValidationError( - `Expected one of ${Object.keys(config).map((key2) => JSON.stringify(key2)).join(" or ")}, got ${JSON.stringify(unknownVariant)}`, - [key] - ); - }, - true - ); -} -function model(name, validator) { - return new Validator( - (value) => { - return prefixError(name, () => validator.validate(value)); - }, - (prevValue, newValue) => { - return prefixError(name, () => { - if (validator.validateUsingKnownGoodVersion) { - return validator.validateUsingKnownGoodVersion(prevValue, newValue); - } else { - return validator.validate(newValue); - } - }); - } - ); -} -function setEnum(values) { - return new Validator((value) => { - if (!values.has(value)) { - const valuesString = Array.from(values, (value2) => JSON.stringify(value2)).join(" or "); - throw new ValidationError(`Expected ${valuesString}, got ${value}`); - } - return value; - }); -} -function optional(validator) { - return new Validator( - (value) => { - if (value === void 0) - return void 0; - return validator.validate(value); - }, - (knownGoodValue, newValue) => { - if (knownGoodValue === void 0 && newValue === void 0) - return void 0; - if (newValue === void 0) - return void 0; - if (validator.validateUsingKnownGoodVersion && knownGoodValue !== void 0) { - return validator.validateUsingKnownGoodVersion(knownGoodValue, newValue); - } - return validator.validate(newValue); - } - ); -} -function nullable(validator) { - return new Validator( - (value) => { - if (value === null) - return null; - return validator.validate(value); - }, - (knownGoodValue, newValue) => { - if (newValue === null) - return null; - if (validator.validateUsingKnownGoodVersion && knownGoodValue !== null) { - return validator.validateUsingKnownGoodVersion(knownGoodValue, newValue); - } - return validator.validate(newValue); - } - ); -} -function literalEnum(...values) { - return setEnum(new Set(values)); -} -function parseUrl(str) { - try { - return new URL(str); - } catch (error) { - if (str.startsWith("/") || str.startsWith("./")) { - try { - return new URL(str, "http://example.com"); - } catch (error2) { - throw new ValidationError(`Expected a valid url, got ${JSON.stringify(str)}`); - } - } - throw new ValidationError(`Expected a valid url, got ${JSON.stringify(str)}`); - } -} -var validLinkProtocols = /* @__PURE__ */ new Set(["http:", "https:", "mailto:"]); -var linkUrl = string.check((value) => { - if (value === "") - return; - const url = parseUrl(value); - if (!validLinkProtocols.has(url.protocol.toLowerCase())) { - throw new ValidationError( - `Expected a valid url, got ${JSON.stringify(value)} (invalid protocol)` - ); - } -}); -var validSrcProtocols = /* @__PURE__ */ new Set(["http:", "https:", "data:", "asset:"]); -var srcUrl = string.check((value) => { - if (value === "") - return; - const url = parseUrl(value); - if (!validSrcProtocols.has(url.protocol.toLowerCase())) { - throw new ValidationError( - `Expected a valid url, got ${JSON.stringify(value)} (invalid protocol)` - ); - } -}); -var httpUrl = string.check((value) => { - if (value === "") - return; - const url = parseUrl(value); - if (!url.protocol.toLowerCase().match(/^https?:$/)) { - throw new ValidationError( - `Expected a valid url, got ${JSON.stringify(value)} (invalid protocol)` - ); - } -}); -var indexKey = string.refine((key) => { - try { - validateIndexKey(key); - return key; - } catch { - throw new ValidationError(`Expected an index key, got ${JSON.stringify(key)}`); - } -}); - -// node_modules/@tldraw/sync-core/node_modules/@tldraw/tlschema/dist-esm/misc/id-validator.mjs -init_checked_fetch(); -init_modules_watch_stub(); -function idValidator(prefix) { - return validation_exports.string.refine((id) => { - if (!id.startsWith(`${prefix}:`)) { - throw new Error(`${prefix} ID must start with "${prefix}:"`); - } - return id; - }); -} - -// node_modules/@tldraw/sync-core/node_modules/@tldraw/tlschema/dist-esm/assets/TLBaseAsset.mjs -var assetIdValidator = idValidator("asset"); -function createAssetValidator(type, props) { - return validation_exports.object({ - id: assetIdValidator, - typeName: validation_exports.literal("asset"), - type: validation_exports.literal(type), - props, - meta: validation_exports.jsonValue - }); -} - -// node_modules/@tldraw/sync-core/node_modules/@tldraw/tlschema/dist-esm/bindings/TLArrowBinding.mjs -init_checked_fetch(); -init_modules_watch_stub(); - -// node_modules/@tldraw/sync-core/node_modules/@tldraw/tlschema/dist-esm/misc/geometry-types.mjs -init_checked_fetch(); -init_modules_watch_stub(); -var vecModelValidator = validation_exports.object({ - x: validation_exports.number, - y: validation_exports.number, - z: validation_exports.number.optional() -}); -var boxModelValidator = validation_exports.object({ - x: validation_exports.number, - y: validation_exports.number, - w: validation_exports.number, - h: validation_exports.number -}); - -// node_modules/@tldraw/sync-core/node_modules/@tldraw/tlschema/dist-esm/records/TLBinding.mjs -init_checked_fetch(); -init_modules_watch_stub(); - -// node_modules/@tldraw/sync-core/node_modules/@tldraw/tlschema/dist-esm/bindings/TLBaseBinding.mjs -init_checked_fetch(); -init_modules_watch_stub(); - -// node_modules/@tldraw/sync-core/node_modules/@tldraw/tlschema/dist-esm/shapes/TLBaseShape.mjs -init_checked_fetch(); -init_modules_watch_stub(); - -// node_modules/@tldraw/sync-core/node_modules/@tldraw/tlschema/dist-esm/misc/TLOpacity.mjs -init_checked_fetch(); -init_modules_watch_stub(); -var opacityValidator = validation_exports.number.check((n2) => { - if (n2 < 0 || n2 > 1) { - throw new validation_exports.ValidationError("Opacity must be between 0 and 1"); - } -}); - -// node_modules/@tldraw/sync-core/node_modules/@tldraw/tlschema/dist-esm/shapes/TLBaseShape.mjs -var parentIdValidator = validation_exports.string.refine((id) => { - if (!id.startsWith("page:") && !id.startsWith("shape:")) { - throw new Error('Parent ID must start with "page:" or "shape:"'); - } - return id; -}); -var shapeIdValidator = idValidator("shape"); -function createShapeValidator(type, props, meta) { - return validation_exports.object({ - id: shapeIdValidator, - typeName: validation_exports.literal("shape"), - x: validation_exports.number, - y: validation_exports.number, - rotation: validation_exports.number, - index: validation_exports.indexKey, - parentId: parentIdValidator, - type: validation_exports.literal(type), - isLocked: validation_exports.boolean, - opacity: opacityValidator, - props: props ? validation_exports.object(props) : validation_exports.jsonValue, - meta: meta ? validation_exports.object(meta) : validation_exports.jsonValue - }); -} - -// node_modules/@tldraw/sync-core/node_modules/@tldraw/tlschema/dist-esm/bindings/TLBaseBinding.mjs -var bindingIdValidator = idValidator("binding"); -function createBindingValidator(type, props, meta) { - return validation_exports.object({ - id: bindingIdValidator, - typeName: validation_exports.literal("binding"), - type: validation_exports.literal(type), - fromId: shapeIdValidator, - toId: shapeIdValidator, - props: props ? validation_exports.object(props) : validation_exports.jsonValue, - meta: meta ? validation_exports.object(meta) : validation_exports.jsonValue - }); -} - -// node_modules/@tldraw/sync-core/node_modules/@tldraw/tlschema/dist-esm/records/TLBinding.mjs -var rootBindingVersions = createMigrationIds("com.tldraw.binding", {}); -var rootBindingMigrations = createRecordMigrationSequence({ - sequenceId: "com.tldraw.binding", - recordType: "binding", - sequence: [] -}); -function createBindingId(id) { - return `binding:${id ?? nanoid()}`; -} -function createBindingPropsMigrationSequence(migrations) { - return migrations; -} -function createBindingRecordType(bindings) { - return createRecordType("binding", { - scope: "document", - validator: validation_exports.model( - "binding", - validation_exports.union( - "type", - mapObjectMapValues( - bindings, - (type, { props, meta }) => createBindingValidator(type, props, meta) - ) - ) - ) - }).withDefaultProperties(() => ({ - meta: {} - })); -} - -// node_modules/@tldraw/sync-core/node_modules/@tldraw/tlschema/dist-esm/shapes/TLArrowShape.mjs -init_checked_fetch(); -init_modules_watch_stub(); - -// node_modules/@tldraw/sync-core/node_modules/@tldraw/tlschema/dist-esm/records/TLShape.mjs -init_checked_fetch(); -init_modules_watch_stub(); - -// node_modules/@tldraw/sync-core/node_modules/@tldraw/tlschema/dist-esm/styles/StyleProp.mjs -init_checked_fetch(); -init_modules_watch_stub(); -var StyleProp = class { - /** @internal */ - constructor(id, defaultValue, type) { - this.id = id; - this.defaultValue = defaultValue; - this.type = type; - } - /** - * Define a new {@link StyleProp}. - * - * @param uniqueId - Each StyleProp must have a unique ID. We recommend you prefix this with - * your app/library name. - * @param options - - * - `defaultValue`: The default value for this style prop. - * - * - `type`: Optionally, describe what type of data you expect for this style prop. - * - * @example - * ```ts - * import {T} from '@tldraw/validate' - * import {StyleProp} from '@tldraw/tlschema' - * - * const MyLineWidthProp = StyleProp.define('myApp:lineWidth', { - * defaultValue: 1, - * type: T.number, - * }) - * ``` - * @public - */ - static define(uniqueId, options) { - const { defaultValue, type = validation_exports.any } = options; - return new StyleProp(uniqueId, defaultValue, type); - } - /** - * Define a new {@link StyleProp} as a list of possible values. - * - * @param uniqueId - Each StyleProp must have a unique ID. We recommend you prefix this with - * your app/library name. - * @param options - - * - `defaultValue`: The default value for this style prop. - * - * - `values`: An array of possible values of this style prop. - * - * @example - * ```ts - * import {StyleProp} from '@tldraw/tlschema' - * - * const MySizeProp = StyleProp.defineEnum('myApp:size', { - * defaultValue: 'medium', - * values: ['small', 'medium', 'large'], - * }) - * ``` - */ - static defineEnum(uniqueId, options) { - const { defaultValue, values } = options; - return new EnumStyleProp(uniqueId, defaultValue, values); - } - setDefaultValue(value) { - this.defaultValue = value; - } - validate(value) { - return this.type.validate(value); - } - validateUsingKnownGoodVersion(prevValue, newValue) { - if (this.type.validateUsingKnownGoodVersion) { - return this.type.validateUsingKnownGoodVersion(prevValue, newValue); - } else { - return this.validate(newValue); - } - } -}; -var EnumStyleProp = class extends StyleProp { - /** @internal */ - constructor(id, defaultValue, values) { - super(id, defaultValue, validation_exports.literalEnum(...values)); - this.values = values; - } -}; - -// node_modules/@tldraw/sync-core/node_modules/@tldraw/tlschema/dist-esm/records/TLShape.mjs -var rootShapeVersions = createMigrationIds("com.tldraw.shape", { - AddIsLocked: 1, - HoistOpacity: 2, - AddMeta: 3, - AddWhite: 4 -}); -var rootShapeMigrations = createRecordMigrationSequence({ - sequenceId: "com.tldraw.shape", - recordType: "shape", - sequence: [ - { - id: rootShapeVersions.AddIsLocked, - up: (record) => { - record.isLocked = false; - }, - down: (record) => { - delete record.isLocked; - } - }, - { - id: rootShapeVersions.HoistOpacity, - up: (record) => { - record.opacity = Number(record.props.opacity ?? "1"); - delete record.props.opacity; - }, - down: (record) => { - const opacity = record.opacity; - delete record.opacity; - record.props.opacity = opacity < 0.175 ? "0.1" : opacity < 0.375 ? "0.25" : opacity < 0.625 ? "0.5" : opacity < 0.875 ? "0.75" : "1"; - } - }, - { - id: rootShapeVersions.AddMeta, - up: (record) => { - record.meta = {}; - } - }, - { - id: rootShapeVersions.AddWhite, - up: (_record) => { - }, - down: (record) => { - if (record.props.color === "white") { - record.props.color = "black"; - } - } - } - ] -}); -function getShapePropKeysByStyle(props) { - const propKeysByStyle = /* @__PURE__ */ new Map(); - for (const [key, prop] of Object.entries(props)) { - if (prop instanceof StyleProp) { - if (propKeysByStyle.has(prop)) { - throw new Error( - `Duplicate style prop ${prop.id}. Each style prop can only be used once within a shape.` - ); - } - propKeysByStyle.set(prop, key); - } - } - return propKeysByStyle; -} -function createShapePropsMigrationSequence(migrations) { - return migrations; -} -function createShapePropsMigrationIds(shapeType, ids) { - return mapObjectMapValues(ids, (_k, v) => `com.tldraw.shape.${shapeType}/${v}`); -} -function createShapeRecordType(shapes) { - return createRecordType("shape", { - scope: "document", - validator: validation_exports.model( - "shape", - validation_exports.union( - "type", - mapObjectMapValues( - shapes, - (type, { props, meta }) => createShapeValidator(type, props, meta) - ) - ) - ) - }).withDefaultProperties(() => ({ - x: 0, - y: 0, - rotation: 0, - isLocked: false, - opacity: 1, - meta: {} - })); -} - -// node_modules/@tldraw/sync-core/node_modules/@tldraw/tlschema/dist-esm/recordsWithProps.mjs -init_checked_fetch(); -init_modules_watch_stub(); -function processPropsMigrations(typeName, records) { - const result = []; - for (const [subType, { migrations }] of Object.entries(records)) { - const sequenceId = `com.tldraw.${typeName}.${subType}`; - if (!migrations) { - result.push( - createMigrationSequence({ - sequenceId, - retroactive: false, - sequence: [] - }) - ); - } else if ("sequenceId" in migrations) { - assert( - sequenceId === migrations.sequenceId, - `sequenceId mismatch for ${subType} ${RecordType} migrations. Expected '${sequenceId}', got '${migrations.sequenceId}'` - ); - result.push(migrations); - } else if ("sequence" in migrations) { - result.push( - createMigrationSequence({ - sequenceId, - retroactive: false, - sequence: migrations.sequence.map( - (m) => "id" in m ? createPropsMigration(typeName, subType, m) : m - ) - }) - ); - } else { - result.push( - createMigrationSequence({ - sequenceId, - retroactive: false, - sequence: Object.keys(migrations.migrators).map((k) => Number(k)).sort((a2, b) => a2 - b).map( - (version) => ({ - id: `${sequenceId}/${version}`, - scope: "record", - filter: (r2) => r2.typeName === typeName && r2.type === subType, - up: (record) => { - const result2 = migrations.migrators[version].up(record); - if (result2) { - return result2; - } - }, - down: (record) => { - const result2 = migrations.migrators[version].down(record); - if (result2) { - return result2; - } - } - }) - ) - }) - ); - } - } - return result; -} -function createPropsMigration(typeName, subType, m) { - return { - id: m.id, - dependsOn: m.dependsOn, - scope: "record", - filter: (r2) => r2.typeName === typeName && r2.type === subType, - up: (record) => { - const result = m.up(record.props); - if (result) { - record.props = result; - } - }, - down: typeof m.down === "function" ? (record) => { - const result = m.down(record.props); - if (result) { - record.props = result; - } - } : void 0 - }; -} - -// node_modules/@tldraw/sync-core/node_modules/@tldraw/tlschema/dist-esm/styles/TLColorStyle.mjs -init_checked_fetch(); -init_modules_watch_stub(); -var defaultColorNames = [ - "black", - "grey", - "light-violet", - "violet", - "blue", - "light-blue", - "yellow", - "orange", - "green", - "light-green", - "light-red", - "red", - "white" -]; -var DefaultColorStyle = StyleProp.defineEnum("tldraw:color", { - defaultValue: "black", - values: defaultColorNames -}); -var DefaultLabelColorStyle = StyleProp.defineEnum("tldraw:labelColor", { - defaultValue: "black", - values: defaultColorNames -}); - -// node_modules/@tldraw/sync-core/node_modules/@tldraw/tlschema/dist-esm/styles/TLDashStyle.mjs -init_checked_fetch(); -init_modules_watch_stub(); -var DefaultDashStyle = StyleProp.defineEnum("tldraw:dash", { - defaultValue: "draw", - values: ["draw", "solid", "dashed", "dotted"] -}); - -// node_modules/@tldraw/sync-core/node_modules/@tldraw/tlschema/dist-esm/styles/TLFillStyle.mjs -init_checked_fetch(); -init_modules_watch_stub(); -var DefaultFillStyle = StyleProp.defineEnum("tldraw:fill", { - defaultValue: "none", - values: ["none", "semi", "solid", "pattern", "fill"] -}); - -// node_modules/@tldraw/sync-core/node_modules/@tldraw/tlschema/dist-esm/styles/TLFontStyle.mjs -init_checked_fetch(); -init_modules_watch_stub(); -var DefaultFontStyle = StyleProp.defineEnum("tldraw:font", { - defaultValue: "draw", - values: ["draw", "sans", "serif", "mono"] -}); - -// node_modules/@tldraw/sync-core/node_modules/@tldraw/tlschema/dist-esm/styles/TLSizeStyle.mjs -init_checked_fetch(); -init_modules_watch_stub(); -var DefaultSizeStyle = StyleProp.defineEnum("tldraw:size", { - defaultValue: "m", - values: ["s", "m", "l", "xl"] -}); - -// node_modules/@tldraw/sync-core/node_modules/@tldraw/tlschema/dist-esm/shapes/TLArrowShape.mjs -var arrowheadTypes = [ - "arrow", - "triangle", - "square", - "dot", - "pipe", - "diamond", - "inverted", - "bar", - "none" -]; -var ArrowShapeArrowheadStartStyle = StyleProp.defineEnum("tldraw:arrowheadStart", { - defaultValue: "none", - values: arrowheadTypes -}); -var ArrowShapeArrowheadEndStyle = StyleProp.defineEnum("tldraw:arrowheadEnd", { - defaultValue: "arrow", - values: arrowheadTypes -}); -var arrowShapeProps = { - labelColor: DefaultLabelColorStyle, - color: DefaultColorStyle, - fill: DefaultFillStyle, - dash: DefaultDashStyle, - size: DefaultSizeStyle, - arrowheadStart: ArrowShapeArrowheadStartStyle, - arrowheadEnd: ArrowShapeArrowheadEndStyle, - font: DefaultFontStyle, - start: vecModelValidator, - end: vecModelValidator, - bend: validation_exports.number, - text: validation_exports.string, - labelPosition: validation_exports.number, - scale: validation_exports.nonZeroNumber -}; -var arrowShapeVersions = createShapePropsMigrationIds("arrow", { - AddLabelColor: 1, - AddIsPrecise: 2, - AddLabelPosition: 3, - ExtractBindings: 4, - AddScale: 5 -}); -function propsMigration(migration) { - return createPropsMigration("shape", "arrow", migration); -} -var arrowShapeMigrations = createMigrationSequence({ - sequenceId: "com.tldraw.shape.arrow", - retroactive: false, - sequence: [ - propsMigration({ - id: arrowShapeVersions.AddLabelColor, - up: (props) => { - props.labelColor = "black"; - }, - down: "retired" - }), - propsMigration({ - id: arrowShapeVersions.AddIsPrecise, - up: ({ start, end }) => { - if (start.type === "binding") { - start.isPrecise = !(start.normalizedAnchor.x === 0.5 && start.normalizedAnchor.y === 0.5); - } - if (end.type === "binding") { - end.isPrecise = !(end.normalizedAnchor.x === 0.5 && end.normalizedAnchor.y === 0.5); - } - }, - down: ({ start, end }) => { - if (start.type === "binding") { - if (!start.isPrecise) { - start.normalizedAnchor = { x: 0.5, y: 0.5 }; - } - delete start.isPrecise; - } - if (end.type === "binding") { - if (!end.isPrecise) { - end.normalizedAnchor = { x: 0.5, y: 0.5 }; - } - delete end.isPrecise; - } - } - }), - propsMigration({ - id: arrowShapeVersions.AddLabelPosition, - up: (props) => { - props.labelPosition = 0.5; - }, - down: (props) => { - delete props.labelPosition; - } - }), - { - id: arrowShapeVersions.ExtractBindings, - scope: "store", - up: (oldStore) => { - const arrows = Object.values(oldStore).filter( - (r2) => r2.typeName === "shape" && r2.type === "arrow" - ); - for (const arrow of arrows) { - const { start, end } = arrow.props; - if (start.type === "binding") { - const id = createBindingId(); - const binding = { - typeName: "binding", - id, - type: "arrow", - fromId: arrow.id, - toId: start.boundShapeId, - meta: {}, - props: { - terminal: "start", - normalizedAnchor: start.normalizedAnchor, - isExact: start.isExact, - isPrecise: start.isPrecise - } - }; - oldStore[id] = binding; - arrow.props.start = { x: 0, y: 0 }; - } else { - delete arrow.props.start.type; - } - if (end.type === "binding") { - const id = createBindingId(); - const binding = { - typeName: "binding", - id, - type: "arrow", - fromId: arrow.id, - toId: end.boundShapeId, - meta: {}, - props: { - terminal: "end", - normalizedAnchor: end.normalizedAnchor, - isExact: end.isExact, - isPrecise: end.isPrecise - } - }; - oldStore[id] = binding; - arrow.props.end = { x: 0, y: 0 }; - } else { - delete arrow.props.end.type; - } - } - } - }, - propsMigration({ - id: arrowShapeVersions.AddScale, - up: (props) => { - props.scale = 1; - }, - down: (props) => { - delete props.scale; - } - }) - ] -}); - -// node_modules/@tldraw/sync-core/node_modules/@tldraw/tlschema/dist-esm/bindings/TLArrowBinding.mjs -var arrowBindingProps = { - terminal: validation_exports.literalEnum("start", "end"), - normalizedAnchor: vecModelValidator, - isExact: validation_exports.boolean, - isPrecise: validation_exports.boolean -}; -var arrowBindingMigrations = createBindingPropsMigrationSequence({ - sequence: [{ dependsOn: [arrowShapeVersions.ExtractBindings] }] -}); - -// node_modules/@tldraw/sync-core/node_modules/@tldraw/tlschema/dist-esm/createPresenceStateDerivation.mjs -init_checked_fetch(); -init_modules_watch_stub(); - -// node_modules/@tldraw/sync-core/node_modules/@tldraw/tlschema/dist-esm/records/TLCamera.mjs -init_checked_fetch(); -init_modules_watch_stub(); -var cameraValidator = validation_exports.model( - "camera", - validation_exports.object({ - typeName: validation_exports.literal("camera"), - id: idValidator("camera"), - x: validation_exports.number, - y: validation_exports.number, - z: validation_exports.number, - meta: validation_exports.jsonValue - }) -); -var cameraVersions = createMigrationIds("com.tldraw.camera", { - AddMeta: 1 -}); -var cameraMigrations = createRecordMigrationSequence({ - sequenceId: "com.tldraw.camera", - recordType: "camera", - sequence: [ - { - id: cameraVersions.AddMeta, - up: (record) => { - ; - record.meta = {}; - } - } - ] -}); -var CameraRecordType = createRecordType("camera", { - validator: cameraValidator, - scope: "session" -}).withDefaultProperties( - () => ({ - x: 0, - y: 0, - z: 1, - meta: {} - }) -); - -// node_modules/@tldraw/sync-core/node_modules/@tldraw/tlschema/dist-esm/records/TLInstance.mjs -init_checked_fetch(); -init_modules_watch_stub(); - -// node_modules/@tldraw/sync-core/node_modules/@tldraw/tlschema/dist-esm/misc/TLCursor.mjs -init_checked_fetch(); -init_modules_watch_stub(); -var TL_CURSOR_TYPES = /* @__PURE__ */ new Set([ - "none", - "default", - "pointer", - "cross", - "grab", - "rotate", - "grabbing", - "resize-edge", - "resize-corner", - "text", - "move", - "ew-resize", - "ns-resize", - "nesw-resize", - "nwse-resize", - "nesw-rotate", - "nwse-rotate", - "swne-rotate", - "senw-rotate", - "zoom-in", - "zoom-out" -]); -var cursorTypeValidator = validation_exports.setEnum(TL_CURSOR_TYPES); -var cursorValidator = validation_exports.object({ - type: cursorTypeValidator, - rotation: validation_exports.number -}); - -// node_modules/@tldraw/sync-core/node_modules/@tldraw/tlschema/dist-esm/misc/TLScribble.mjs -init_checked_fetch(); -init_modules_watch_stub(); - -// node_modules/@tldraw/sync-core/node_modules/@tldraw/tlschema/dist-esm/misc/TLColor.mjs -init_checked_fetch(); -init_modules_watch_stub(); -var TL_CANVAS_UI_COLOR_TYPES = /* @__PURE__ */ new Set([ - "accent", - "white", - "black", - "selection-stroke", - "selection-fill", - "laser", - "muted-1" -]); -var canvasUiColorTypeValidator = validation_exports.setEnum(TL_CANVAS_UI_COLOR_TYPES); - -// node_modules/@tldraw/sync-core/node_modules/@tldraw/tlschema/dist-esm/misc/TLScribble.mjs -var TL_SCRIBBLE_STATES = /* @__PURE__ */ new Set(["starting", "paused", "active", "stopping"]); -var scribbleValidator = validation_exports.object({ - id: validation_exports.string, - points: validation_exports.arrayOf(vecModelValidator), - size: validation_exports.positiveNumber, - color: canvasUiColorTypeValidator, - opacity: validation_exports.number, - state: validation_exports.setEnum(TL_SCRIBBLE_STATES), - delay: validation_exports.number, - shrink: validation_exports.number, - taper: validation_exports.boolean -}); - -// node_modules/@tldraw/sync-core/node_modules/@tldraw/tlschema/dist-esm/records/TLPage.mjs -init_checked_fetch(); -init_modules_watch_stub(); -var pageIdValidator = idValidator("page"); -var pageValidator = validation_exports.model( - "page", - validation_exports.object({ - typeName: validation_exports.literal("page"), - id: pageIdValidator, - name: validation_exports.string, - index: validation_exports.indexKey, - meta: validation_exports.jsonValue - }) -); -var pageVersions = createMigrationIds("com.tldraw.page", { - AddMeta: 1 -}); -var pageMigrations = createRecordMigrationSequence({ - sequenceId: "com.tldraw.page", - recordType: "page", - sequence: [ - { - id: pageVersions.AddMeta, - up: (record) => { - record.meta = {}; - } - } - ] -}); -var PageRecordType = createRecordType("page", { - validator: pageValidator, - scope: "document" -}).withDefaultProperties(() => ({ - meta: {} -})); - -// node_modules/@tldraw/sync-core/node_modules/@tldraw/tlschema/dist-esm/records/TLInstance.mjs -var instanceIdValidator = idValidator("instance"); -function createInstanceRecordType(stylesById) { - const stylesForNextShapeValidators = {}; - for (const [id, style] of stylesById) { - stylesForNextShapeValidators[id] = validation_exports.optional(style); - } - const instanceTypeValidator = validation_exports.model( - "instance", - validation_exports.object({ - typeName: validation_exports.literal("instance"), - id: idValidator("instance"), - currentPageId: pageIdValidator, - followingUserId: validation_exports.string.nullable(), - brush: boxModelValidator.nullable(), - opacityForNextShape: opacityValidator, - stylesForNextShape: validation_exports.object(stylesForNextShapeValidators), - cursor: cursorValidator, - scribbles: validation_exports.arrayOf(scribbleValidator), - isFocusMode: validation_exports.boolean, - isDebugMode: validation_exports.boolean, - isToolLocked: validation_exports.boolean, - exportBackground: validation_exports.boolean, - screenBounds: boxModelValidator, - insets: validation_exports.arrayOf(validation_exports.boolean), - zoomBrush: boxModelValidator.nullable(), - isPenMode: validation_exports.boolean, - isGridMode: validation_exports.boolean, - chatMessage: validation_exports.string, - isChatting: validation_exports.boolean, - highlightedUserIds: validation_exports.arrayOf(validation_exports.string), - isFocused: validation_exports.boolean, - devicePixelRatio: validation_exports.number, - isCoarsePointer: validation_exports.boolean, - isHoveringCanvas: validation_exports.boolean.nullable(), - openMenus: validation_exports.arrayOf(validation_exports.string), - isChangingStyle: validation_exports.boolean, - isReadonly: validation_exports.boolean, - meta: validation_exports.jsonValue, - duplicateProps: validation_exports.object({ - shapeIds: validation_exports.arrayOf(idValidator("shape")), - offset: validation_exports.object({ - x: validation_exports.number, - y: validation_exports.number - }) - }).nullable() - }) - ); - return createRecordType("instance", { - validator: instanceTypeValidator, - scope: "session", - ephemeralKeys: { - currentPageId: false, - meta: false, - followingUserId: true, - opacityForNextShape: true, - stylesForNextShape: true, - brush: true, - cursor: true, - scribbles: true, - isFocusMode: true, - isDebugMode: true, - isToolLocked: true, - exportBackground: true, - screenBounds: true, - insets: true, - zoomBrush: true, - isPenMode: true, - isGridMode: true, - chatMessage: true, - isChatting: true, - highlightedUserIds: true, - isFocused: true, - devicePixelRatio: true, - isCoarsePointer: true, - isHoveringCanvas: true, - openMenus: true, - isChangingStyle: true, - isReadonly: true, - duplicateProps: true - } - }).withDefaultProperties( - () => ({ - followingUserId: null, - opacityForNextShape: 1, - stylesForNextShape: {}, - brush: null, - scribbles: [], - cursor: { - type: "default", - rotation: 0 - }, - isFocusMode: false, - exportBackground: false, - isDebugMode: false, - isToolLocked: false, - screenBounds: { x: 0, y: 0, w: 1080, h: 720 }, - insets: [false, false, false, false], - zoomBrush: null, - isGridMode: false, - isPenMode: false, - chatMessage: "", - isChatting: false, - highlightedUserIds: [], - isFocused: false, - devicePixelRatio: typeof window === "undefined" ? 1 : window.devicePixelRatio, - isCoarsePointer: false, - isHoveringCanvas: null, - openMenus: [], - isChangingStyle: false, - isReadonly: false, - meta: {}, - duplicateProps: null - }) - ); -} -var instanceVersions = createMigrationIds("com.tldraw.instance", { - AddTransparentExportBgs: 1, - RemoveDialog: 2, - AddToolLockMode: 3, - RemoveExtraPropsForNextShape: 4, - AddLabelColor: 5, - AddFollowingUserId: 6, - RemoveAlignJustify: 7, - AddZoom: 8, - AddVerticalAlign: 9, - AddScribbleDelay: 10, - RemoveUserId: 11, - AddIsPenModeAndIsGridMode: 12, - HoistOpacity: 13, - AddChat: 14, - AddHighlightedUserIds: 15, - ReplacePropsForNextShapeWithStylesForNextShape: 16, - AddMeta: 17, - RemoveCursorColor: 18, - AddLonelyProperties: 19, - ReadOnlyReadonly: 20, - AddHoveringCanvas: 21, - AddScribbles: 22, - AddInset: 23, - AddDuplicateProps: 24, - RemoveCanMoveCamera: 25 -}); -var instanceMigrations = createRecordMigrationSequence({ - sequenceId: "com.tldraw.instance", - recordType: "instance", - sequence: [ - { - id: instanceVersions.AddTransparentExportBgs, - up: (instance) => { - return { ...instance, exportBackground: true }; - } - }, - { - id: instanceVersions.RemoveDialog, - up: ({ dialog: _, ...instance }) => { - return instance; - } - }, - { - id: instanceVersions.AddToolLockMode, - up: (instance) => { - return { ...instance, isToolLocked: false }; - } - }, - { - id: instanceVersions.RemoveExtraPropsForNextShape, - up: ({ propsForNextShape, ...instance }) => { - return { - ...instance, - propsForNextShape: Object.fromEntries( - Object.entries(propsForNextShape).filter( - ([key]) => [ - "color", - "labelColor", - "dash", - "fill", - "size", - "font", - "align", - "verticalAlign", - "icon", - "geo", - "arrowheadStart", - "arrowheadEnd", - "spline" - ].includes(key) - ) - ) - }; - } - }, - { - id: instanceVersions.AddLabelColor, - up: ({ propsForNextShape, ...instance }) => { - return { - ...instance, - propsForNextShape: { - ...propsForNextShape, - labelColor: "black" - } - }; - } - }, - { - id: instanceVersions.AddFollowingUserId, - up: (instance) => { - return { ...instance, followingUserId: null }; - } - }, - { - id: instanceVersions.RemoveAlignJustify, - up: (instance) => { - let newAlign = instance.propsForNextShape.align; - if (newAlign === "justify") { - newAlign = "start"; - } - return { - ...instance, - propsForNextShape: { - ...instance.propsForNextShape, - align: newAlign - } - }; - } - }, - { - id: instanceVersions.AddZoom, - up: (instance) => { - return { ...instance, zoomBrush: null }; - } - }, - { - id: instanceVersions.AddVerticalAlign, - up: (instance) => { - return { - ...instance, - propsForNextShape: { - ...instance.propsForNextShape, - verticalAlign: "middle" - } - }; - } - }, - { - id: instanceVersions.AddScribbleDelay, - up: (instance) => { - if (instance.scribble !== null) { - return { ...instance, scribble: { ...instance.scribble, delay: 0 } }; - } - return { ...instance }; - } - }, - { - id: instanceVersions.RemoveUserId, - up: ({ userId: _, ...instance }) => { - return instance; - } - }, - { - id: instanceVersions.AddIsPenModeAndIsGridMode, - up: (instance) => { - return { ...instance, isPenMode: false, isGridMode: false }; - } - }, - { - id: instanceVersions.HoistOpacity, - up: ({ propsForNextShape: { opacity, ...propsForNextShape }, ...instance }) => { - return { ...instance, opacityForNextShape: Number(opacity ?? "1"), propsForNextShape }; - } - }, - { - id: instanceVersions.AddChat, - up: (instance) => { - return { ...instance, chatMessage: "", isChatting: false }; - } - }, - { - id: instanceVersions.AddHighlightedUserIds, - up: (instance) => { - return { ...instance, highlightedUserIds: [] }; - } - }, - { - id: instanceVersions.ReplacePropsForNextShapeWithStylesForNextShape, - up: ({ propsForNextShape: _, ...instance }) => { - return { ...instance, stylesForNextShape: {} }; - } - }, - { - id: instanceVersions.AddMeta, - up: (record) => { - return { - ...record, - meta: {} - }; - } - }, - { - id: instanceVersions.RemoveCursorColor, - up: (record) => { - const { color: _, ...cursor } = record.cursor; - return { - ...record, - cursor - }; - } - }, - { - id: instanceVersions.AddLonelyProperties, - up: (record) => { - return { - ...record, - canMoveCamera: true, - isFocused: false, - devicePixelRatio: 1, - isCoarsePointer: false, - openMenus: [], - isChangingStyle: false, - isReadOnly: false - }; - } - }, - { - id: instanceVersions.ReadOnlyReadonly, - up: ({ isReadOnly: _isReadOnly, ...record }) => { - return { - ...record, - isReadonly: _isReadOnly - }; - } - }, - { - id: instanceVersions.AddHoveringCanvas, - up: (record) => { - return { - ...record, - isHoveringCanvas: null - }; - } - }, - { - id: instanceVersions.AddScribbles, - up: ({ scribble: _, ...record }) => { - return { - ...record, - scribbles: [] - }; - } - }, - { - id: instanceVersions.AddInset, - up: (record) => { - return { - ...record, - insets: [false, false, false, false] - }; - }, - down: ({ insets: _, ...record }) => { - return { - ...record - }; - } - }, - { - id: instanceVersions.AddDuplicateProps, - up: (record) => { - return { - ...record, - duplicateProps: null - }; - }, - down: ({ duplicateProps: _, ...record }) => { - return { - ...record - }; - } - }, - { - id: instanceVersions.RemoveCanMoveCamera, - up: ({ canMoveCamera: _, ...record }) => { - return { - ...record - }; - }, - down: (instance) => { - return { ...instance, canMoveCamera: true }; - } - } - ] -}); -var TLINSTANCE_ID = "instance:instance"; - -// node_modules/@tldraw/sync-core/node_modules/@tldraw/tlschema/dist-esm/records/TLPageState.mjs -init_checked_fetch(); -init_modules_watch_stub(); -var instancePageStateValidator = validation_exports.model( - "instance_page_state", - validation_exports.object({ - typeName: validation_exports.literal("instance_page_state"), - id: idValidator("instance_page_state"), - pageId: pageIdValidator, - selectedShapeIds: validation_exports.arrayOf(shapeIdValidator), - hintingShapeIds: validation_exports.arrayOf(shapeIdValidator), - erasingShapeIds: validation_exports.arrayOf(shapeIdValidator), - hoveredShapeId: shapeIdValidator.nullable(), - editingShapeId: shapeIdValidator.nullable(), - croppingShapeId: shapeIdValidator.nullable(), - focusedGroupId: shapeIdValidator.nullable(), - meta: validation_exports.jsonValue - }) -); -var instancePageStateVersions = createMigrationIds("com.tldraw.instance_page_state", { - AddCroppingId: 1, - RemoveInstanceIdAndCameraId: 2, - AddMeta: 3, - RenameProperties: 4, - RenamePropertiesAgain: 5 -}); -var instancePageStateMigrations = createRecordMigrationSequence({ - sequenceId: "com.tldraw.instance_page_state", - recordType: "instance_page_state", - sequence: [ - { - id: instancePageStateVersions.AddCroppingId, - up(instance) { - instance.croppingShapeId = null; - } - }, - { - id: instancePageStateVersions.RemoveInstanceIdAndCameraId, - up(instance) { - delete instance.instanceId; - delete instance.cameraId; - } - }, - { - id: instancePageStateVersions.AddMeta, - up: (record) => { - record.meta = {}; - } - }, - { - id: instancePageStateVersions.RenameProperties, - // this migration is cursed: it was written wrong and doesn't do anything. - // rather than replace it, I've added another migration below that fixes it. - up: (_record) => { - }, - down: (_record) => { - } - }, - { - id: instancePageStateVersions.RenamePropertiesAgain, - up: (record) => { - record.selectedShapeIds = record.selectedIds; - delete record.selectedIds; - record.hintingShapeIds = record.hintingIds; - delete record.hintingIds; - record.erasingShapeIds = record.erasingIds; - delete record.erasingIds; - record.hoveredShapeId = record.hoveredId; - delete record.hoveredId; - record.editingShapeId = record.editingId; - delete record.editingId; - record.croppingShapeId = record.croppingShapeId ?? record.croppingId ?? null; - delete record.croppingId; - record.focusedGroupId = record.focusLayerId; - delete record.focusLayerId; - }, - down: (record) => { - record.selectedIds = record.selectedShapeIds; - delete record.selectedShapeIds; - record.hintingIds = record.hintingShapeIds; - delete record.hintingShapeIds; - record.erasingIds = record.erasingShapeIds; - delete record.erasingShapeIds; - record.hoveredId = record.hoveredShapeId; - delete record.hoveredShapeId; - record.editingId = record.editingShapeId; - delete record.editingShapeId; - record.croppingId = record.croppingShapeId; - delete record.croppingShapeId; - record.focusLayerId = record.focusedGroupId; - delete record.focusedGroupId; - } - } - ] -}); -var InstancePageStateRecordType = createRecordType( - "instance_page_state", - { - validator: instancePageStateValidator, - scope: "session", - ephemeralKeys: { - pageId: false, - selectedShapeIds: false, - editingShapeId: false, - croppingShapeId: false, - meta: false, - hintingShapeIds: true, - erasingShapeIds: true, - hoveredShapeId: true, - focusedGroupId: true - } - } -).withDefaultProperties( - () => ({ - editingShapeId: null, - croppingShapeId: null, - selectedShapeIds: [], - hoveredShapeId: null, - erasingShapeIds: [], - hintingShapeIds: [], - focusedGroupId: null, - meta: {} - }) -); - -// node_modules/@tldraw/sync-core/node_modules/@tldraw/tlschema/dist-esm/records/TLPointer.mjs -init_checked_fetch(); -init_modules_watch_stub(); -var pointerValidator = validation_exports.model( - "pointer", - validation_exports.object({ - typeName: validation_exports.literal("pointer"), - id: idValidator("pointer"), - x: validation_exports.number, - y: validation_exports.number, - lastActivityTimestamp: validation_exports.number, - meta: validation_exports.jsonValue - }) -); -var pointerVersions = createMigrationIds("com.tldraw.pointer", { - AddMeta: 1 -}); -var pointerMigrations = createRecordMigrationSequence({ - sequenceId: "com.tldraw.pointer", - recordType: "pointer", - sequence: [ - { - id: pointerVersions.AddMeta, - up: (record) => { - record.meta = {}; - } - } - ] -}); -var PointerRecordType = createRecordType("pointer", { - validator: pointerValidator, - scope: "session" -}).withDefaultProperties( - () => ({ - x: 0, - y: 0, - lastActivityTimestamp: 0, - meta: {} - }) -); -var TLPOINTER_ID = PointerRecordType.createId("pointer"); - -// node_modules/@tldraw/sync-core/node_modules/@tldraw/tlschema/dist-esm/records/TLPresence.mjs -init_checked_fetch(); -init_modules_watch_stub(); -var instancePresenceValidator = validation_exports.model( - "instance_presence", - validation_exports.object({ - typeName: validation_exports.literal("instance_presence"), - id: idValidator("instance_presence"), - userId: validation_exports.string, - userName: validation_exports.string, - lastActivityTimestamp: validation_exports.number, - followingUserId: validation_exports.string.nullable(), - cursor: validation_exports.object({ - x: validation_exports.number, - y: validation_exports.number, - type: cursorTypeValidator, - rotation: validation_exports.number - }), - color: validation_exports.string, - camera: validation_exports.object({ - x: validation_exports.number, - y: validation_exports.number, - z: validation_exports.number - }), - screenBounds: boxModelValidator, - selectedShapeIds: validation_exports.arrayOf(idValidator("shape")), - currentPageId: idValidator("page"), - brush: boxModelValidator.nullable(), - scribbles: validation_exports.arrayOf(scribbleValidator), - chatMessage: validation_exports.string, - meta: validation_exports.jsonValue - }) -); -var instancePresenceVersions = createMigrationIds("com.tldraw.instance_presence", { - AddScribbleDelay: 1, - RemoveInstanceId: 2, - AddChatMessage: 3, - AddMeta: 4, - RenameSelectedShapeIds: 5 -}); -var instancePresenceMigrations = createRecordMigrationSequence({ - sequenceId: "com.tldraw.instance_presence", - recordType: "instance_presence", - sequence: [ - { - id: instancePresenceVersions.AddScribbleDelay, - up: (instance) => { - if (instance.scribble !== null) { - instance.scribble.delay = 0; - } - } - }, - { - id: instancePresenceVersions.RemoveInstanceId, - up: (instance) => { - delete instance.instanceId; - } - }, - { - id: instancePresenceVersions.AddChatMessage, - up: (instance) => { - instance.chatMessage = ""; - } - }, - { - id: instancePresenceVersions.AddMeta, - up: (record) => { - record.meta = {}; - } - }, - { - id: instancePresenceVersions.RenameSelectedShapeIds, - up: (_record) => { - } - } - ] -}); -var InstancePresenceRecordType = createRecordType( - "instance_presence", - { - validator: instancePresenceValidator, - scope: "presence" - } -).withDefaultProperties(() => ({ - lastActivityTimestamp: 0, - followingUserId: null, - color: "#FF0000", - camera: { - x: 0, - y: 0, - z: 1 - }, - cursor: { - x: 0, - y: 0, - type: "default", - rotation: 0 - }, - screenBounds: { - x: 0, - y: 0, - w: 1, - h: 1 - }, - selectedShapeIds: [], - brush: null, - scribbles: [], - chatMessage: "", - meta: {} -})); - -// node_modules/@tldraw/sync-core/node_modules/@tldraw/tlschema/dist-esm/createTLSchema.mjs -init_checked_fetch(); -init_modules_watch_stub(); - -// node_modules/@tldraw/sync-core/node_modules/@tldraw/tlschema/dist-esm/TLStore.mjs -init_checked_fetch(); -init_modules_watch_stub(); - -// node_modules/@tldraw/sync-core/node_modules/@tldraw/tlschema/dist-esm/records/TLDocument.mjs -init_checked_fetch(); -init_modules_watch_stub(); -var documentValidator = validation_exports.model( - "document", - validation_exports.object({ - typeName: validation_exports.literal("document"), - id: validation_exports.literal("document:document"), - gridSize: validation_exports.number, - name: validation_exports.string, - meta: validation_exports.jsonValue - }) -); -var documentVersions = createMigrationIds("com.tldraw.document", { - AddName: 1, - AddMeta: 2 -}); -var documentMigrations = createRecordMigrationSequence({ - sequenceId: "com.tldraw.document", - recordType: "document", - sequence: [ - { - id: documentVersions.AddName, - up: (document2) => { - ; - document2.name = ""; - }, - down: (document2) => { - delete document2.name; - } - }, - { - id: documentVersions.AddMeta, - up: (record) => { - ; - record.meta = {}; - } - } - ] -}); -var DocumentRecordType = createRecordType("document", { - validator: documentValidator, - scope: "document" -}).withDefaultProperties( - () => ({ - gridSize: 10, - name: "", - meta: {} - }) -); -var TLDOCUMENT_ID = DocumentRecordType.createId("document"); - -// node_modules/@tldraw/sync-core/node_modules/@tldraw/tlschema/dist-esm/TLStore.mjs -function sortByIndex2(a2, b) { - if (a2.index < b.index) { - return -1; - } else if (a2.index > b.index) { - return 1; - } - return 0; -} -function redactRecordForErrorReporting(record) { - if (record.typeName === "asset") { - if ("src" in record) { - record.src = ""; - } - if ("src" in record.props) { - record.props.src = ""; - } - } -} -var onValidationFailure = ({ error, phase, record, recordBefore }) => { - const isExistingValidationIssue = ( - // if we're initializing the store for the first time, we should - // allow invalid records so people can load old buggy data: - phase === "initialize" - ); - annotateError(error, { - tags: { - origin: "store.validateRecord", - storePhase: phase, - isExistingValidationIssue - }, - extras: { - recordBefore: recordBefore ? redactRecordForErrorReporting(structuredClone(recordBefore)) : void 0, - recordAfter: redactRecordForErrorReporting(structuredClone(record)) - } - }); - throw error; -}; -function getDefaultPages() { - return [ - PageRecordType.create({ - id: "page:page", - name: "Page 1", - index: "a1", - meta: {} - }) - ]; -} -function createIntegrityChecker(store) { - const $pageIds = store.query.ids("page"); - const ensureStoreIsUsable = () => { - if (!store.has(TLDOCUMENT_ID)) { - store.put([DocumentRecordType.create({ id: TLDOCUMENT_ID, name: store.props.defaultName })]); - return ensureStoreIsUsable(); - } - if (!store.has(TLPOINTER_ID)) { - store.put([PointerRecordType.create({ id: TLPOINTER_ID })]); - return ensureStoreIsUsable(); - } - const pageIds = $pageIds.get(); - if (pageIds.size === 0) { - store.put(getDefaultPages()); - return ensureStoreIsUsable(); - } - const getFirstPageId = () => [...pageIds].map((id) => store.get(id)).sort(sortByIndex2)[0].id; - const instanceState = store.get(TLINSTANCE_ID); - if (!instanceState) { - store.put([ - store.schema.types.instance.create({ - id: TLINSTANCE_ID, - currentPageId: getFirstPageId(), - exportBackground: true - }) - ]); - return ensureStoreIsUsable(); - } else if (!pageIds.has(instanceState.currentPageId)) { - store.put([{ ...instanceState, currentPageId: getFirstPageId() }]); - return ensureStoreIsUsable(); - } - const missingPageStateIds = /* @__PURE__ */ new Set(); - const missingCameraIds = /* @__PURE__ */ new Set(); - for (const id of pageIds) { - const pageStateId = InstancePageStateRecordType.createId(id); - if (!store.has(pageStateId)) { - missingPageStateIds.add(pageStateId); - } - const cameraId = CameraRecordType.createId(id); - if (!store.has(cameraId)) { - missingCameraIds.add(cameraId); - } - } - if (missingPageStateIds.size > 0) { - store.put( - [...missingPageStateIds].map( - (id) => InstancePageStateRecordType.create({ - id, - pageId: InstancePageStateRecordType.parseId(id) - }) - ) - ); - } - if (missingCameraIds.size > 0) { - store.put([...missingCameraIds].map((id) => CameraRecordType.create({ id }))); - } - }; - return ensureStoreIsUsable; -} - -// node_modules/@tldraw/sync-core/node_modules/@tldraw/tlschema/dist-esm/assets/TLBookmarkAsset.mjs -init_checked_fetch(); -init_modules_watch_stub(); -var bookmarkAssetValidator = createAssetValidator( - "bookmark", - validation_exports.object({ - title: validation_exports.string, - description: validation_exports.string, - image: validation_exports.string, - favicon: validation_exports.string, - src: validation_exports.srcUrl.nullable() - }) -); -var Versions = createMigrationIds("com.tldraw.asset.bookmark", { - MakeUrlsValid: 1, - AddFavicon: 2 -}); -var bookmarkAssetMigrations = createRecordMigrationSequence({ - sequenceId: "com.tldraw.asset.bookmark", - recordType: "asset", - filter: (asset) => asset.type === "bookmark", - sequence: [ - { - id: Versions.MakeUrlsValid, - up: (asset) => { - if (!validation_exports.srcUrl.isValid(asset.props.src)) { - asset.props.src = ""; - } - }, - down: (_asset) => { - } - }, - { - id: Versions.AddFavicon, - up: (asset) => { - if (!validation_exports.srcUrl.isValid(asset.props.favicon)) { - asset.props.favicon = ""; - } - }, - down: (asset) => { - delete asset.props.favicon; - } - } - ] -}); - -// node_modules/@tldraw/sync-core/node_modules/@tldraw/tlschema/dist-esm/assets/TLImageAsset.mjs -init_checked_fetch(); -init_modules_watch_stub(); -var imageAssetValidator = createAssetValidator( - "image", - validation_exports.object({ - w: validation_exports.number, - h: validation_exports.number, - name: validation_exports.string, - isAnimated: validation_exports.boolean, - mimeType: validation_exports.string.nullable(), - src: validation_exports.srcUrl.nullable(), - fileSize: validation_exports.nonZeroNumber.optional() - }) -); -var Versions2 = createMigrationIds("com.tldraw.asset.image", { - AddIsAnimated: 1, - RenameWidthHeight: 2, - MakeUrlsValid: 3, - AddFileSize: 4, - MakeFileSizeOptional: 5 -}); -var imageAssetMigrations = createRecordMigrationSequence({ - sequenceId: "com.tldraw.asset.image", - recordType: "asset", - filter: (asset) => asset.type === "image", - sequence: [ - { - id: Versions2.AddIsAnimated, - up: (asset) => { - asset.props.isAnimated = false; - }, - down: (asset) => { - delete asset.props.isAnimated; - } - }, - { - id: Versions2.RenameWidthHeight, - up: (asset) => { - asset.props.w = asset.props.width; - asset.props.h = asset.props.height; - delete asset.props.width; - delete asset.props.height; - }, - down: (asset) => { - asset.props.width = asset.props.w; - asset.props.height = asset.props.h; - delete asset.props.w; - delete asset.props.h; - } - }, - { - id: Versions2.MakeUrlsValid, - up: (asset) => { - if (!validation_exports.srcUrl.isValid(asset.props.src)) { - asset.props.src = ""; - } - }, - down: (_asset) => { - } - }, - { - id: Versions2.AddFileSize, - up: (asset) => { - asset.props.fileSize = -1; - }, - down: (asset) => { - delete asset.props.fileSize; - } - }, - { - id: Versions2.MakeFileSizeOptional, - up: (asset) => { - if (asset.props.fileSize === -1) { - asset.props.fileSize = void 0; - } - }, - down: (asset) => { - if (asset.props.fileSize === void 0) { - asset.props.fileSize = -1; - } - } - } - ] -}); - -// node_modules/@tldraw/sync-core/node_modules/@tldraw/tlschema/dist-esm/assets/TLVideoAsset.mjs -init_checked_fetch(); -init_modules_watch_stub(); -var videoAssetValidator = createAssetValidator( - "video", - validation_exports.object({ - w: validation_exports.number, - h: validation_exports.number, - name: validation_exports.string, - isAnimated: validation_exports.boolean, - mimeType: validation_exports.string.nullable(), - src: validation_exports.srcUrl.nullable(), - fileSize: validation_exports.number.optional() - }) -); -var Versions3 = createMigrationIds("com.tldraw.asset.video", { - AddIsAnimated: 1, - RenameWidthHeight: 2, - MakeUrlsValid: 3, - AddFileSize: 4, - MakeFileSizeOptional: 5 -}); -var videoAssetMigrations = createRecordMigrationSequence({ - sequenceId: "com.tldraw.asset.video", - recordType: "asset", - filter: (asset) => asset.type === "video", - sequence: [ - { - id: Versions3.AddIsAnimated, - up: (asset) => { - asset.props.isAnimated = false; - }, - down: (asset) => { - delete asset.props.isAnimated; - } - }, - { - id: Versions3.RenameWidthHeight, - up: (asset) => { - asset.props.w = asset.props.width; - asset.props.h = asset.props.height; - delete asset.props.width; - delete asset.props.height; - }, - down: (asset) => { - asset.props.width = asset.props.w; - asset.props.height = asset.props.h; - delete asset.props.w; - delete asset.props.h; - } - }, - { - id: Versions3.MakeUrlsValid, - up: (asset) => { - if (!validation_exports.srcUrl.isValid(asset.props.src)) { - asset.props.src = ""; - } - }, - down: (_asset) => { - } - }, - { - id: Versions3.AddFileSize, - up: (asset) => { - asset.props.fileSize = -1; - }, - down: (asset) => { - delete asset.props.fileSize; - } - }, - { - id: Versions3.MakeFileSizeOptional, - up: (asset) => { - if (asset.props.fileSize === -1) { - asset.props.fileSize = void 0; - } - }, - down: (asset) => { - if (asset.props.fileSize === void 0) { - asset.props.fileSize = -1; - } - } - } - ] -}); - -// node_modules/@tldraw/sync-core/node_modules/@tldraw/tlschema/dist-esm/records/TLAsset.mjs -init_checked_fetch(); -init_modules_watch_stub(); -var assetValidator = validation_exports.model( - "asset", - validation_exports.union("type", { - image: imageAssetValidator, - video: videoAssetValidator, - bookmark: bookmarkAssetValidator - }) -); -var assetVersions = createMigrationIds("com.tldraw.asset", { - AddMeta: 1 -}); -var assetMigrations = createRecordMigrationSequence({ - sequenceId: "com.tldraw.asset", - recordType: "asset", - sequence: [ - { - id: assetVersions.AddMeta, - up: (record) => { - ; - record.meta = {}; - } - } - ] -}); -var AssetRecordType = createRecordType("asset", { - validator: assetValidator, - scope: "document" -}).withDefaultProperties(() => ({ - meta: {} -})); - -// node_modules/@tldraw/sync-core/node_modules/@tldraw/tlschema/dist-esm/shapes/TLBookmarkShape.mjs -init_checked_fetch(); -init_modules_watch_stub(); -var bookmarkShapeProps = { - w: validation_exports.nonZeroNumber, - h: validation_exports.nonZeroNumber, - assetId: assetIdValidator.nullable(), - url: validation_exports.linkUrl -}; -var Versions4 = createShapePropsMigrationIds("bookmark", { - NullAssetId: 1, - MakeUrlsValid: 2 -}); -var bookmarkShapeMigrations = createShapePropsMigrationSequence({ - sequence: [ - { - id: Versions4.NullAssetId, - up: (props) => { - if (props.assetId === void 0) { - props.assetId = null; - } - }, - down: "retired" - }, - { - id: Versions4.MakeUrlsValid, - up: (props) => { - if (!validation_exports.linkUrl.isValid(props.url)) { - props.url = ""; - } - }, - down: (_props) => { - } - } - ] -}); - -// node_modules/@tldraw/sync-core/node_modules/@tldraw/tlschema/dist-esm/shapes/TLDrawShape.mjs -init_checked_fetch(); -init_modules_watch_stub(); -var DrawShapeSegment = validation_exports.object({ - type: validation_exports.literalEnum("free", "straight"), - points: validation_exports.arrayOf(vecModelValidator) -}); -var drawShapeProps = { - color: DefaultColorStyle, - fill: DefaultFillStyle, - dash: DefaultDashStyle, - size: DefaultSizeStyle, - segments: validation_exports.arrayOf(DrawShapeSegment), - isComplete: validation_exports.boolean, - isClosed: validation_exports.boolean, - isPen: validation_exports.boolean, - scale: validation_exports.nonZeroNumber -}; -var Versions5 = createShapePropsMigrationIds("draw", { - AddInPen: 1, - AddScale: 2 -}); -var drawShapeMigrations = createShapePropsMigrationSequence({ - sequence: [ - { - id: Versions5.AddInPen, - up: (props) => { - const { points } = props.segments[0]; - if (points.length === 0) { - props.isPen = false; - return; - } - let isPen = !(points[0].z === 0 || points[0].z === 0.5); - if (points[1]) { - isPen = isPen && !(points[1].z === 0 || points[1].z === 0.5); - } - props.isPen = isPen; - }, - down: "retired" - }, - { - id: Versions5.AddScale, - up: (props) => { - props.scale = 1; - }, - down: (props) => { - delete props.scale; - } - } - ] -}); - -// node_modules/@tldraw/sync-core/node_modules/@tldraw/tlschema/dist-esm/shapes/TLEmbedShape.mjs -init_checked_fetch(); -init_modules_watch_stub(); -var TLDRAW_APP_RE = /(^\/r\/[^/]+\/?$)/; -var safeParseUrl = (url) => { - try { - return new URL(url); - } catch (err) { - return; - } -}; -var EMBED_DEFINITIONS = [ - { - type: "tldraw", - title: "tldraw", - hostnames: ["beta.tldraw.com", "tldraw.com", "localhost:3000"], - minWidth: 300, - minHeight: 300, - width: 720, - height: 500, - doesResize: true, - overridePermissions: { - "allow-top-navigation": true - }, - toEmbedUrl: (url) => { - const urlObj = safeParseUrl(url); - if (urlObj && urlObj.pathname.match(TLDRAW_APP_RE)) { - return url; - } - return; - }, - fromEmbedUrl: (url) => { - const urlObj = safeParseUrl(url); - if (urlObj && urlObj.pathname.match(TLDRAW_APP_RE)) { - return url; - } - return; - } - }, - { - type: "figma", - title: "Figma", - hostnames: ["figma.com"], - width: 720, - height: 500, - doesResize: true, - toEmbedUrl: (url) => { - if (!!url.match( - // eslint-disable-next-line no-useless-escape - /https:\/\/([\w\.-]+\.)?figma.com\/(file|proto)\/([0-9a-zA-Z]{22,128})(?:\/.*)?$/ - ) && !url.includes("figma.com/embed")) { - return `https://www.figma.com/embed?embed_host=share&url=${url}`; - } - return; - }, - fromEmbedUrl: (url) => { - const urlObj = safeParseUrl(url); - if (urlObj && urlObj.pathname.match(/^\/embed\/?$/)) { - const outUrl = urlObj.searchParams.get("url"); - if (outUrl) { - return outUrl; - } - } - return; - } - }, - { - type: "google_maps", - title: "Google Maps", - hostnames: ["google.*"], - width: 720, - height: 500, - doesResize: true, - overridePermissions: { - "allow-presentation": true - }, - toEmbedUrl: (url) => { - if (url.includes("/maps/")) { - const match = url.match(/@(.*),(.*),(.*)z/); - let result; - if (match) { - const [, lat, lng, z] = match; - const host = new URL(url).host.replace("www.", ""); - result = `https://${host}/maps/embed/v1/view?key=${process.env.NEXT_PUBLIC_GC_API_KEY}¢er=${lat},${lng}&zoom=${z}`; - } else { - result = ""; - } - return result; - } - return; - }, - fromEmbedUrl: (url) => { - const urlObj = safeParseUrl(url); - if (!urlObj) - return; - const matches = urlObj.pathname.match(/^\/maps\/embed\/v1\/view\/?$/); - if (matches && urlObj.searchParams.has("center") && urlObj.searchParams.get("zoom")) { - const zoom = urlObj.searchParams.get("zoom"); - const [lat, lon] = urlObj.searchParams.get("center").split(","); - return `https://www.google.com/maps/@${lat},${lon},${zoom}z`; - } - return; - } - }, - { - type: "val_town", - title: "Val Town", - hostnames: ["val.town"], - minWidth: 260, - minHeight: 100, - width: 720, - height: 500, - doesResize: true, - toEmbedUrl: (url) => { - const urlObj = safeParseUrl(url); - const matches = urlObj && urlObj.pathname.match(/\/v\/(.+)\/?/); - if (matches) { - return `https://www.val.town/embed/${matches[1]}`; - } - return; - }, - fromEmbedUrl: (url) => { - const urlObj = safeParseUrl(url); - const matches = urlObj && urlObj.pathname.match(/\/embed\/(.+)\/?/); - if (matches) { - return `https://www.val.town/v/${matches[1]}`; - } - return; - } - }, - { - type: "codesandbox", - title: "CodeSandbox", - hostnames: ["codesandbox.io"], - minWidth: 300, - minHeight: 300, - width: 720, - height: 500, - doesResize: true, - toEmbedUrl: (url) => { - const urlObj = safeParseUrl(url); - const matches = urlObj && urlObj.pathname.match(/\/s\/([^/]+)\/?/); - if (matches) { - return `https://codesandbox.io/embed/${matches[1]}`; - } - return; - }, - fromEmbedUrl: (url) => { - const urlObj = safeParseUrl(url); - const matches = urlObj && urlObj.pathname.match(/\/embed\/([^/]+)\/?/); - if (matches) { - return `https://codesandbox.io/s/${matches[1]}`; - } - return; - } - }, - { - type: "codepen", - title: "Codepen", - hostnames: ["codepen.io"], - minWidth: 300, - minHeight: 300, - width: 520, - height: 400, - doesResize: true, - toEmbedUrl: (url) => { - const CODEPEN_URL_REGEXP = /https:\/\/codepen.io\/([^/]+)\/pen\/([^/]+)/; - const matches = url.match(CODEPEN_URL_REGEXP); - if (matches) { - const [_, user, id] = matches; - return `https://codepen.io/${user}/embed/${id}`; - } - return; - }, - fromEmbedUrl: (url) => { - const CODEPEN_EMBED_REGEXP = /https:\/\/codepen.io\/([^/]+)\/embed\/([^/]+)/; - const matches = url.match(CODEPEN_EMBED_REGEXP); - if (matches) { - const [_, user, id] = matches; - return `https://codepen.io/${user}/pen/${id}`; - } - return; - } - }, - { - type: "scratch", - title: "Scratch", - hostnames: ["scratch.mit.edu"], - width: 520, - height: 400, - doesResize: false, - toEmbedUrl: (url) => { - const SCRATCH_URL_REGEXP = /https?:\/\/scratch.mit.edu\/projects\/([^/]+)/; - const matches = url.match(SCRATCH_URL_REGEXP); - if (matches) { - const [_, id] = matches; - return `https://scratch.mit.edu/projects/embed/${id}`; - } - return; - }, - fromEmbedUrl: (url) => { - const SCRATCH_EMBED_REGEXP = /https:\/\/scratch.mit.edu\/projects\/embed\/([^/]+)/; - const matches = url.match(SCRATCH_EMBED_REGEXP); - if (matches) { - const [_, id] = matches; - return `https://scratch.mit.edu/projects/${id}`; - } - return; - } - }, - { - type: "youtube", - title: "YouTube", - hostnames: ["*.youtube.com", "youtube.com", "youtu.be"], - width: 800, - height: 450, - doesResize: true, - overridePermissions: { - "allow-presentation": true, - "allow-popups-to-escape-sandbox": true - }, - isAspectRatioLocked: true, - toEmbedUrl: (url) => { - const urlObj = safeParseUrl(url); - if (!urlObj) - return; - const hostname = urlObj.hostname.replace(/^www./, ""); - if (hostname === "youtu.be") { - const videoId = urlObj.pathname.split("/").filter(Boolean)[0]; - return `https://www.youtube.com/embed/${videoId}`; - } else if ((hostname === "youtube.com" || hostname === "m.youtube.com") && urlObj.pathname.match(/^\/watch/)) { - const videoId = urlObj.searchParams.get("v"); - return `https://www.youtube.com/embed/${videoId}`; - } - return; - }, - fromEmbedUrl: (url) => { - const urlObj = safeParseUrl(url); - if (!urlObj) - return; - const hostname = urlObj.hostname.replace(/^www./, ""); - if (hostname === "youtube.com") { - const matches = urlObj.pathname.match(/^\/embed\/([^/]+)\/?/); - if (matches) { - return `https://www.youtube.com/watch?v=${matches[1]}`; - } - } - return; - } - }, - { - type: "google_calendar", - title: "Google Calendar", - hostnames: ["calendar.google.*"], - width: 720, - height: 500, - minWidth: 460, - minHeight: 360, - doesResize: true, - instructionLink: "https://support.google.com/calendar/answer/41207?hl=en", - overridePermissions: { - "allow-popups-to-escape-sandbox": true - }, - toEmbedUrl: (url) => { - const urlObj = safeParseUrl(url); - const cidQs = urlObj?.searchParams.get("cid"); - if (urlObj?.pathname.match(/\/calendar\/u\/0/) && cidQs) { - urlObj.pathname = "/calendar/embed"; - const keys = Array.from(urlObj.searchParams.keys()); - for (const key of keys) { - urlObj.searchParams.delete(key); - } - urlObj.searchParams.set("src", cidQs); - return urlObj.href; - } - return; - }, - fromEmbedUrl: (url) => { - const urlObj = safeParseUrl(url); - const srcQs = urlObj?.searchParams.get("src"); - if (urlObj?.pathname.match(/\/calendar\/embed/) && srcQs) { - urlObj.pathname = "/calendar/u/0"; - const keys = Array.from(urlObj.searchParams.keys()); - for (const key of keys) { - urlObj.searchParams.delete(key); - } - urlObj.searchParams.set("cid", srcQs); - return urlObj.href; - } - return; - } - }, - { - type: "google_slides", - title: "Google Slides", - hostnames: ["docs.google.*"], - width: 720, - height: 500, - minWidth: 460, - minHeight: 360, - doesResize: true, - overridePermissions: { - "allow-popups-to-escape-sandbox": true - }, - toEmbedUrl: (url) => { - const urlObj = safeParseUrl(url); - if (urlObj?.pathname.match(/^\/presentation/) && urlObj?.pathname.match(/\/pub\/?$/)) { - urlObj.pathname = urlObj.pathname.replace(/\/pub$/, "/embed"); - const keys = Array.from(urlObj.searchParams.keys()); - for (const key of keys) { - urlObj.searchParams.delete(key); - } - return urlObj.href; - } - return; - }, - fromEmbedUrl: (url) => { - const urlObj = safeParseUrl(url); - if (urlObj?.pathname.match(/^\/presentation/) && urlObj?.pathname.match(/\/embed\/?$/)) { - urlObj.pathname = urlObj.pathname.replace(/\/embed$/, "/pub"); - const keys = Array.from(urlObj.searchParams.keys()); - for (const key of keys) { - urlObj.searchParams.delete(key); - } - return urlObj.href; - } - return; - } - }, - { - type: "github_gist", - title: "GitHub Gist", - hostnames: ["gist.github.com"], - width: 720, - height: 500, - doesResize: true, - toEmbedUrl: (url) => { - const urlObj = safeParseUrl(url); - if (urlObj && urlObj.pathname.match(/\/([^/]+)\/([^/]+)/)) { - if (!url.split("/").pop()) - return; - return url; - } - return; - }, - fromEmbedUrl: (url) => { - const urlObj = safeParseUrl(url); - if (urlObj && urlObj.pathname.match(/\/([^/]+)\/([^/]+)/)) { - if (!url.split("/").pop()) - return; - return url; - } - return; - } - }, - { - type: "replit", - title: "Replit", - hostnames: ["replit.com"], - width: 720, - height: 500, - doesResize: true, - toEmbedUrl: (url) => { - const urlObj = safeParseUrl(url); - if (urlObj && urlObj.pathname.match(/\/@([^/]+)\/([^/]+)/)) { - return `${url}?embed=true`; - } - return; - }, - fromEmbedUrl: (url) => { - const urlObj = safeParseUrl(url); - if (urlObj && urlObj.pathname.match(/\/@([^/]+)\/([^/]+)/) && urlObj.searchParams.has("embed")) { - urlObj.searchParams.delete("embed"); - return urlObj.href; - } - return; - } - }, - { - type: "felt", - title: "Felt", - hostnames: ["felt.com"], - width: 720, - height: 500, - doesResize: true, - toEmbedUrl: (url) => { - const urlObj = safeParseUrl(url); - if (urlObj && urlObj.pathname.match(/^\/map\//)) { - return urlObj.origin + "/embed" + urlObj.pathname; - } - return; - }, - fromEmbedUrl: (url) => { - const urlObj = safeParseUrl(url); - if (urlObj && urlObj.pathname.match(/^\/embed\/map\//)) { - urlObj.pathname = urlObj.pathname.replace(/^\/embed/, ""); - return urlObj.href; - } - return; - } - }, - { - type: "spotify", - title: "Spotify", - hostnames: ["open.spotify.com"], - width: 720, - height: 500, - minHeight: 500, - overrideOutlineRadius: 12, - doesResize: true, - toEmbedUrl: (url) => { - const urlObj = safeParseUrl(url); - if (urlObj && urlObj.pathname.match(/^\/(artist|album)\//)) { - return urlObj.origin + "/embed" + urlObj.pathname; - } - return; - }, - fromEmbedUrl: (url) => { - const urlObj = safeParseUrl(url); - if (urlObj && urlObj.pathname.match(/^\/embed\/(artist|album)\//)) { - return urlObj.origin + urlObj.pathname.replace(/^\/embed/, ""); - } - return; - } - }, - { - type: "vimeo", - title: "Vimeo", - hostnames: ["vimeo.com", "player.vimeo.com"], - width: 640, - height: 360, - doesResize: true, - isAspectRatioLocked: true, - toEmbedUrl: (url) => { - const urlObj = safeParseUrl(url); - if (urlObj && urlObj.hostname === "vimeo.com") { - if (urlObj.pathname.match(/^\/[0-9]+/)) { - return "https://player.vimeo.com/video/" + urlObj.pathname.split("/")[1] + "?title=0&byline=0"; - } - } - return; - }, - fromEmbedUrl: (url) => { - const urlObj = safeParseUrl(url); - if (urlObj && urlObj.hostname === "player.vimeo.com") { - const matches = urlObj.pathname.match(/^\/video\/([^/]+)\/?$/); - if (matches) { - return "https://vimeo.com/" + matches[1]; - } - } - return; - } - }, - { - type: "excalidraw", - title: "Excalidraw", - hostnames: ["excalidraw.com"], - width: 720, - height: 500, - doesResize: true, - isAspectRatioLocked: true, - toEmbedUrl: (url) => { - const urlObj = safeParseUrl(url); - if (urlObj && urlObj.hash.match(/#room=/)) { - return url; - } - return; - }, - fromEmbedUrl: (url) => { - const urlObj = safeParseUrl(url); - if (urlObj && urlObj.hash.match(/#room=/)) { - return url; - } - return; - } - }, - { - type: "observable", - title: "Observable", - hostnames: ["observablehq.com"], - width: 720, - height: 500, - doesResize: true, - isAspectRatioLocked: false, - backgroundColor: "#fff", - toEmbedUrl: (url) => { - const urlObj = safeParseUrl(url); - if (urlObj && urlObj.pathname.match(/^\/@([^/]+)\/([^/]+)\/?$/)) { - return `${urlObj.origin}/embed${urlObj.pathname}?cell=*`; - } - if (urlObj && urlObj.pathname.match(/^\/d\/([^/]+)\/?$/)) { - const pathName = urlObj.pathname.replace(/^\/d/, ""); - return `${urlObj.origin}/embed${pathName}?cell=*`; - } - return; - }, - fromEmbedUrl: (url) => { - const urlObj = safeParseUrl(url); - if (urlObj && urlObj.pathname.match(/^\/embed\/@([^/]+)\/([^/]+)\/?$/)) { - return `${urlObj.origin}${urlObj.pathname.replace("/embed", "")}#cell-*`; - } - if (urlObj && urlObj.pathname.match(/^\/embed\/([^/]+)\/?$/)) { - return `${urlObj.origin}${urlObj.pathname.replace("/embed", "/d")}#cell-*`; - } - return; - } - }, - { - type: "desmos", - title: "Desmos", - hostnames: ["desmos.com"], - width: 700, - height: 450, - doesResize: true, - toEmbedUrl: (url) => { - const urlObj = safeParseUrl(url); - if (urlObj && urlObj.hostname === "www.desmos.com" && urlObj.pathname.match(/^\/calculator\/([^/]+)\/?$/) && urlObj.search === "" && urlObj.hash === "") { - return `${url}?embed`; - } - return; - }, - fromEmbedUrl: (url) => { - const urlObj = safeParseUrl(url); - if (urlObj && urlObj.hostname === "www.desmos.com" && urlObj.pathname.match(/^\/calculator\/([^/]+)\/?$/) && urlObj.search === "?embed" && urlObj.hash === "") { - return url.replace("?embed", ""); - } - return; - } - } -]; -var embedShapeProps = { - w: validation_exports.nonZeroNumber, - h: validation_exports.nonZeroNumber, - url: validation_exports.string -}; -var Versions6 = createShapePropsMigrationIds("embed", { - GenOriginalUrlInEmbed: 1, - RemoveDoesResize: 2, - RemoveTmpOldUrl: 3, - RemovePermissionOverrides: 4 -}); -var embedShapeMigrations = createShapePropsMigrationSequence({ - sequence: [ - { - id: Versions6.GenOriginalUrlInEmbed, - // add tmpOldUrl property - up: (props) => { - try { - const url = props.url; - const host = new URL(url).host.replace("www.", ""); - let originalUrl; - for (const localEmbedDef of EMBED_DEFINITIONS) { - if (localEmbedDef.hostnames.includes(host)) { - try { - originalUrl = localEmbedDef.fromEmbedUrl(url); - } catch (err) { - console.warn(err); - } - } - } - props.tmpOldUrl = props.url; - props.url = originalUrl ?? ""; - } catch (e) { - props.url = ""; - props.tmpOldUrl = props.url; - } - }, - down: "retired" - }, - { - id: Versions6.RemoveDoesResize, - up: (props) => { - delete props.doesResize; - }, - down: "retired" - }, - { - id: Versions6.RemoveTmpOldUrl, - up: (props) => { - delete props.tmpOldUrl; - }, - down: "retired" - }, - { - id: Versions6.RemovePermissionOverrides, - up: (props) => { - delete props.overridePermissions; - }, - down: "retired" - } - ] -}); - -// node_modules/@tldraw/sync-core/node_modules/@tldraw/tlschema/dist-esm/shapes/TLFrameShape.mjs -init_checked_fetch(); -init_modules_watch_stub(); -var frameShapeProps = { - w: validation_exports.nonZeroNumber, - h: validation_exports.nonZeroNumber, - name: validation_exports.string -}; -var frameShapeMigrations = createShapePropsMigrationSequence({ - sequence: [] -}); - -// node_modules/@tldraw/sync-core/node_modules/@tldraw/tlschema/dist-esm/shapes/TLGeoShape.mjs -init_checked_fetch(); -init_modules_watch_stub(); - -// node_modules/@tldraw/sync-core/node_modules/@tldraw/tlschema/dist-esm/styles/TLHorizontalAlignStyle.mjs -init_checked_fetch(); -init_modules_watch_stub(); -var DefaultHorizontalAlignStyle = StyleProp.defineEnum("tldraw:horizontalAlign", { - defaultValue: "middle", - values: ["start", "middle", "end", "start-legacy", "end-legacy", "middle-legacy"] -}); - -// node_modules/@tldraw/sync-core/node_modules/@tldraw/tlschema/dist-esm/styles/TLVerticalAlignStyle.mjs -init_checked_fetch(); -init_modules_watch_stub(); -var DefaultVerticalAlignStyle = StyleProp.defineEnum("tldraw:verticalAlign", { - defaultValue: "middle", - values: ["start", "middle", "end"] -}); - -// node_modules/@tldraw/sync-core/node_modules/@tldraw/tlschema/dist-esm/shapes/TLGeoShape.mjs -var GeoShapeGeoStyle = StyleProp.defineEnum("tldraw:geo", { - defaultValue: "rectangle", - values: [ - "cloud", - "rectangle", - "ellipse", - "triangle", - "diamond", - "pentagon", - "hexagon", - "octagon", - "star", - "rhombus", - "rhombus-2", - "oval", - "trapezoid", - "arrow-right", - "arrow-left", - "arrow-up", - "arrow-down", - "x-box", - "check-box", - "heart" - ] -}); -var geoShapeProps = { - geo: GeoShapeGeoStyle, - labelColor: DefaultLabelColorStyle, - color: DefaultColorStyle, - fill: DefaultFillStyle, - dash: DefaultDashStyle, - size: DefaultSizeStyle, - font: DefaultFontStyle, - align: DefaultHorizontalAlignStyle, - verticalAlign: DefaultVerticalAlignStyle, - url: validation_exports.linkUrl, - w: validation_exports.nonZeroNumber, - h: validation_exports.nonZeroNumber, - growY: validation_exports.positiveNumber, - text: validation_exports.string, - scale: validation_exports.nonZeroNumber -}; -var geoShapeVersions = createShapePropsMigrationIds("geo", { - AddUrlProp: 1, - AddLabelColor: 2, - RemoveJustify: 3, - AddCheckBox: 4, - AddVerticalAlign: 5, - MigrateLegacyAlign: 6, - AddCloud: 7, - MakeUrlsValid: 8, - AddScale: 9 -}); -var geoShapeMigrations = createShapePropsMigrationSequence({ - sequence: [ - { - id: geoShapeVersions.AddUrlProp, - up: (props) => { - props.url = ""; - }, - down: "retired" - }, - { - id: geoShapeVersions.AddLabelColor, - up: (props) => { - props.labelColor = "black"; - }, - down: "retired" - }, - { - id: geoShapeVersions.RemoveJustify, - up: (props) => { - if (props.align === "justify") { - props.align = "start"; - } - }, - down: "retired" - }, - { - id: geoShapeVersions.AddCheckBox, - up: (_props) => { - }, - down: "retired" - }, - { - id: geoShapeVersions.AddVerticalAlign, - up: (props) => { - props.verticalAlign = "middle"; - }, - down: "retired" - }, - { - id: geoShapeVersions.MigrateLegacyAlign, - up: (props) => { - let newAlign; - switch (props.align) { - case "start": - newAlign = "start-legacy"; - break; - case "end": - newAlign = "end-legacy"; - break; - default: - newAlign = "middle-legacy"; - break; - } - props.align = newAlign; - }, - down: "retired" - }, - { - id: geoShapeVersions.AddCloud, - up: (_props) => { - }, - down: "retired" - }, - { - id: geoShapeVersions.MakeUrlsValid, - up: (props) => { - if (!validation_exports.linkUrl.isValid(props.url)) { - props.url = ""; - } - }, - down: (_props) => { - } - }, - { - id: geoShapeVersions.AddScale, - up: (props) => { - props.scale = 1; - }, - down: (props) => { - delete props.scale; - } - } - ] -}); - -// node_modules/@tldraw/sync-core/node_modules/@tldraw/tlschema/dist-esm/shapes/TLGroupShape.mjs -init_checked_fetch(); -init_modules_watch_stub(); -var groupShapeProps = {}; -var groupShapeMigrations = createShapePropsMigrationSequence({ sequence: [] }); - -// node_modules/@tldraw/sync-core/node_modules/@tldraw/tlschema/dist-esm/shapes/TLHighlightShape.mjs -init_checked_fetch(); -init_modules_watch_stub(); -var highlightShapeProps = { - color: DefaultColorStyle, - size: DefaultSizeStyle, - segments: validation_exports.arrayOf(DrawShapeSegment), - isComplete: validation_exports.boolean, - isPen: validation_exports.boolean, - scale: validation_exports.nonZeroNumber -}; -var Versions7 = createShapePropsMigrationIds("highlight", { - AddScale: 1 -}); -var highlightShapeMigrations = createShapePropsMigrationSequence({ - sequence: [ - { - id: Versions7.AddScale, - up: (props) => { - props.scale = 1; - }, - down: (props) => { - delete props.scale; - } - } - ] -}); - -// node_modules/@tldraw/sync-core/node_modules/@tldraw/tlschema/dist-esm/shapes/TLImageShape.mjs -init_checked_fetch(); -init_modules_watch_stub(); -var ImageShapeCrop = validation_exports.object({ - topLeft: vecModelValidator, - bottomRight: vecModelValidator -}); -var imageShapeProps = { - w: validation_exports.nonZeroNumber, - h: validation_exports.nonZeroNumber, - playing: validation_exports.boolean, - url: validation_exports.linkUrl, - assetId: assetIdValidator.nullable(), - crop: ImageShapeCrop.nullable(), - flipX: validation_exports.boolean, - flipY: validation_exports.boolean -}; -var Versions8 = createShapePropsMigrationIds("image", { - AddUrlProp: 1, - AddCropProp: 2, - MakeUrlsValid: 3, - AddFlipProps: 4 -}); -var imageShapeMigrations = createShapePropsMigrationSequence({ - sequence: [ - { - id: Versions8.AddUrlProp, - up: (props) => { - props.url = ""; - }, - down: "retired" - }, - { - id: Versions8.AddCropProp, - up: (props) => { - props.crop = null; - }, - down: (props) => { - delete props.crop; - } - }, - { - id: Versions8.MakeUrlsValid, - up: (props) => { - if (!validation_exports.linkUrl.isValid(props.url)) { - props.url = ""; - } - }, - down: (_props) => { - } - }, - { - id: Versions8.AddFlipProps, - up: (props) => { - props.flipX = false; - props.flipY = false; - }, - down: (props) => { - delete props.flipX; - delete props.flipY; - } - } - ] -}); - -// node_modules/@tldraw/sync-core/node_modules/@tldraw/tlschema/dist-esm/shapes/TLLineShape.mjs -init_checked_fetch(); -init_modules_watch_stub(); -var LineShapeSplineStyle = StyleProp.defineEnum("tldraw:spline", { - defaultValue: "line", - values: ["cubic", "line"] -}); -var lineShapePointValidator = validation_exports.object({ - id: validation_exports.string, - index: validation_exports.indexKey, - x: validation_exports.number, - y: validation_exports.number -}); -var lineShapeProps = { - color: DefaultColorStyle, - dash: DefaultDashStyle, - size: DefaultSizeStyle, - spline: LineShapeSplineStyle, - points: validation_exports.dict(validation_exports.string, lineShapePointValidator), - scale: validation_exports.nonZeroNumber -}; -var lineShapeVersions = createShapePropsMigrationIds("line", { - AddSnapHandles: 1, - RemoveExtraHandleProps: 2, - HandlesToPoints: 3, - PointIndexIds: 4, - AddScale: 5 -}); -var lineShapeMigrations = createShapePropsMigrationSequence({ - sequence: [ - { - id: lineShapeVersions.AddSnapHandles, - up: (props) => { - for (const handle of Object.values(props.handles)) { - ; - handle.canSnap = true; - } - }, - down: "retired" - }, - { - id: lineShapeVersions.RemoveExtraHandleProps, - up: (props) => { - props.handles = objectMapFromEntries( - Object.values(props.handles).map((handle) => [ - handle.index, - { - x: handle.x, - y: handle.y - } - ]) - ); - }, - down: (props) => { - const handles = Object.entries(props.handles).map(([index, handle]) => ({ index, ...handle })).sort(sortByIndex); - props.handles = Object.fromEntries( - handles.map((handle, i) => { - const id = i === 0 ? "start" : i === handles.length - 1 ? "end" : `handle:${handle.index}`; - return [ - id, - { - id, - type: "vertex", - canBind: false, - canSnap: true, - index: handle.index, - x: handle.x, - y: handle.y - } - ]; - }) - ); - } - }, - { - id: lineShapeVersions.HandlesToPoints, - up: (props) => { - const sortedHandles = Object.entries(props.handles).map(([index, { x, y: y2 }]) => ({ x, y: y2, index })).sort(sortByIndex); - props.points = sortedHandles.map(({ x, y: y2 }) => ({ x, y: y2 })); - delete props.handles; - }, - down: (props) => { - const indices = getIndices(props.points.length); - props.handles = Object.fromEntries( - props.points.map((handle, i) => { - const index = indices[i]; - return [ - index, - { - x: handle.x, - y: handle.y - } - ]; - }) - ); - delete props.points; - } - }, - { - id: lineShapeVersions.PointIndexIds, - up: (props) => { - const indices = getIndices(props.points.length); - props.points = Object.fromEntries( - props.points.map((point, i) => { - const id = indices[i]; - return [ - id, - { - id, - index: id, - x: point.x, - y: point.y - } - ]; - }) - ); - }, - down: (props) => { - const sortedHandles = Object.values(props.points).sort(sortByIndex); - props.points = sortedHandles.map(({ x, y: y2 }) => ({ x, y: y2 })); - } - }, - { - id: lineShapeVersions.AddScale, - up: (props) => { - props.scale = 1; - }, - down: (props) => { - delete props.scale; - } - } - ] -}); - -// node_modules/@tldraw/sync-core/node_modules/@tldraw/tlschema/dist-esm/shapes/TLNoteShape.mjs -init_checked_fetch(); -init_modules_watch_stub(); -var noteShapeProps = { - color: DefaultColorStyle, - size: DefaultSizeStyle, - font: DefaultFontStyle, - fontSizeAdjustment: validation_exports.positiveNumber, - align: DefaultHorizontalAlignStyle, - verticalAlign: DefaultVerticalAlignStyle, - growY: validation_exports.positiveNumber, - url: validation_exports.linkUrl, - text: validation_exports.string, - scale: validation_exports.nonZeroNumber -}; -var Versions9 = createShapePropsMigrationIds("note", { - AddUrlProp: 1, - RemoveJustify: 2, - MigrateLegacyAlign: 3, - AddVerticalAlign: 4, - MakeUrlsValid: 5, - AddFontSizeAdjustment: 6, - AddScale: 7 -}); -var noteShapeMigrations = createShapePropsMigrationSequence({ - sequence: [ - { - id: Versions9.AddUrlProp, - up: (props) => { - props.url = ""; - }, - down: "retired" - }, - { - id: Versions9.RemoveJustify, - up: (props) => { - if (props.align === "justify") { - props.align = "start"; - } - }, - down: "retired" - }, - { - id: Versions9.MigrateLegacyAlign, - up: (props) => { - switch (props.align) { - case "start": - props.align = "start-legacy"; - return; - case "end": - props.align = "end-legacy"; - return; - default: - props.align = "middle-legacy"; - return; - } - }, - down: "retired" - }, - { - id: Versions9.AddVerticalAlign, - up: (props) => { - props.verticalAlign = "middle"; - }, - down: "retired" - }, - { - id: Versions9.MakeUrlsValid, - up: (props) => { - if (!validation_exports.linkUrl.isValid(props.url)) { - props.url = ""; - } - }, - down: (_props) => { - } - }, - { - id: Versions9.AddFontSizeAdjustment, - up: (props) => { - props.fontSizeAdjustment = 0; - }, - down: (props) => { - delete props.fontSizeAdjustment; - } - }, - { - id: Versions9.AddScale, - up: (props) => { - props.scale = 1; - }, - down: (props) => { - delete props.scale; - } - } - ] -}); - -// node_modules/@tldraw/sync-core/node_modules/@tldraw/tlschema/dist-esm/shapes/TLTextShape.mjs -init_checked_fetch(); -init_modules_watch_stub(); - -// node_modules/@tldraw/sync-core/node_modules/@tldraw/tlschema/dist-esm/styles/TLTextAlignStyle.mjs -init_checked_fetch(); -init_modules_watch_stub(); -var DefaultTextAlignStyle = StyleProp.defineEnum("tldraw:textAlign", { - defaultValue: "start", - values: ["start", "middle", "end"] -}); - -// node_modules/@tldraw/sync-core/node_modules/@tldraw/tlschema/dist-esm/shapes/TLTextShape.mjs -var textShapeProps = { - color: DefaultColorStyle, - size: DefaultSizeStyle, - font: DefaultFontStyle, - textAlign: DefaultTextAlignStyle, - w: validation_exports.nonZeroNumber, - text: validation_exports.string, - scale: validation_exports.nonZeroNumber, - autoSize: validation_exports.boolean -}; -var Versions10 = createShapePropsMigrationIds("text", { - RemoveJustify: 1, - AddTextAlign: 2 -}); -var textShapeMigrations = createShapePropsMigrationSequence({ - sequence: [ - { - id: Versions10.RemoveJustify, - up: (props) => { - if (props.align === "justify") { - props.align = "start"; - } - }, - down: "retired" - }, - { - id: Versions10.AddTextAlign, - up: (props) => { - props.textAlign = props.align; - delete props.align; - }, - down: (props) => { - props.align = props.textAlign; - delete props.textAlign; - } - } - ] -}); - -// node_modules/@tldraw/sync-core/node_modules/@tldraw/tlschema/dist-esm/shapes/TLVideoShape.mjs -init_checked_fetch(); -init_modules_watch_stub(); -var videoShapeProps = { - w: validation_exports.nonZeroNumber, - h: validation_exports.nonZeroNumber, - time: validation_exports.number, - playing: validation_exports.boolean, - url: validation_exports.linkUrl, - assetId: assetIdValidator.nullable() -}; -var Versions11 = createShapePropsMigrationIds("video", { - AddUrlProp: 1, - MakeUrlsValid: 2 -}); -var videoShapeMigrations = createShapePropsMigrationSequence({ - sequence: [ - { - id: Versions11.AddUrlProp, - up: (props) => { - props.url = ""; - }, - down: "retired" - }, - { - id: Versions11.MakeUrlsValid, - up: (props) => { - if (!validation_exports.linkUrl.isValid(props.url)) { - props.url = ""; - } - }, - down: (_props) => { - } - } - ] -}); - -// node_modules/@tldraw/sync-core/node_modules/@tldraw/tlschema/dist-esm/store-migrations.mjs -init_checked_fetch(); -init_modules_watch_stub(); -var Versions12 = createMigrationIds("com.tldraw.store", { - RemoveCodeAndIconShapeTypes: 1, - AddInstancePresenceType: 2, - RemoveTLUserAndPresenceAndAddPointer: 3, - RemoveUserDocument: 4 -}); -var storeMigrations = createMigrationSequence({ - sequenceId: "com.tldraw.store", - retroactive: false, - sequence: [ - { - id: Versions12.RemoveCodeAndIconShapeTypes, - scope: "store", - up: (store) => { - for (const [id, record] of objectMapEntries(store)) { - if (record.typeName === "shape" && (record.type === "icon" || record.type === "code")) { - delete store[id]; - } - } - } - }, - { - id: Versions12.AddInstancePresenceType, - scope: "store", - up(_store) { - } - }, - { - // remove user and presence records and add pointer records - id: Versions12.RemoveTLUserAndPresenceAndAddPointer, - scope: "store", - up: (store) => { - for (const [id, record] of objectMapEntries(store)) { - if (record.typeName.match(/^(user|user_presence)$/)) { - delete store[id]; - } - } - } - }, - { - // remove user document records - id: Versions12.RemoveUserDocument, - scope: "store", - up: (store) => { - for (const [id, record] of objectMapEntries(store)) { - if (record.typeName.match("user_document")) { - delete store[id]; - } - } - } - } - ] -}); - -// node_modules/@tldraw/sync-core/node_modules/@tldraw/tlschema/dist-esm/createTLSchema.mjs -var defaultShapeSchemas = { - arrow: { migrations: arrowShapeMigrations, props: arrowShapeProps }, - bookmark: { migrations: bookmarkShapeMigrations, props: bookmarkShapeProps }, - draw: { migrations: drawShapeMigrations, props: drawShapeProps }, - embed: { migrations: embedShapeMigrations, props: embedShapeProps }, - frame: { migrations: frameShapeMigrations, props: frameShapeProps }, - geo: { migrations: geoShapeMigrations, props: geoShapeProps }, - group: { migrations: groupShapeMigrations, props: groupShapeProps }, - highlight: { migrations: highlightShapeMigrations, props: highlightShapeProps }, - image: { migrations: imageShapeMigrations, props: imageShapeProps }, - line: { migrations: lineShapeMigrations, props: lineShapeProps }, - note: { migrations: noteShapeMigrations, props: noteShapeProps }, - text: { migrations: textShapeMigrations, props: textShapeProps }, - video: { migrations: videoShapeMigrations, props: videoShapeProps } -}; -var defaultBindingSchemas = { - arrow: { migrations: arrowBindingMigrations, props: arrowBindingProps } -}; -function createTLSchema({ - shapes = defaultShapeSchemas, - bindings = defaultBindingSchemas, - migrations -} = {}) { - const stylesById = /* @__PURE__ */ new Map(); - for (const shape of objectMapValues(shapes)) { - for (const style of getShapePropKeysByStyle(shape.props ?? {}).keys()) { - if (stylesById.has(style.id) && stylesById.get(style.id) !== style) { - throw new Error(`Multiple StyleProp instances with the same id: ${style.id}`); - } - stylesById.set(style.id, style); - } - } - const ShapeRecordType = createShapeRecordType(shapes); - const BindingRecordType = createBindingRecordType(bindings); - const InstanceRecordType = createInstanceRecordType(stylesById); - return StoreSchema.create( - { - asset: AssetRecordType, - binding: BindingRecordType, - camera: CameraRecordType, - document: DocumentRecordType, - instance: InstanceRecordType, - instance_page_state: InstancePageStateRecordType, - page: PageRecordType, - instance_presence: InstancePresenceRecordType, - pointer: PointerRecordType, - shape: ShapeRecordType - }, - { - migrations: [ - storeMigrations, - assetMigrations, - cameraMigrations, - documentMigrations, - instanceMigrations, - instancePageStateMigrations, - pageMigrations, - instancePresenceMigrations, - pointerMigrations, - rootShapeMigrations, - bookmarkAssetMigrations, - imageAssetMigrations, - videoAssetMigrations, - ...processPropsMigrations("shape", shapes), - ...processPropsMigrations("binding", bindings), - ...migrations ?? [] - ], - onValidationFailure, - createIntegrityChecker - } - ); -} - -// node_modules/@tldraw/sync-core/node_modules/@tldraw/tlschema/dist-esm/misc/TLHandle.mjs -init_checked_fetch(); -init_modules_watch_stub(); - -// node_modules/@tldraw/sync-core/node_modules/@tldraw/tlschema/dist-esm/translations/translations.mjs -init_checked_fetch(); -init_modules_watch_stub(); - -// node_modules/@tldraw/sync-core/node_modules/@tldraw/tlschema/dist-esm/translations/languages.mjs -init_checked_fetch(); -init_modules_watch_stub(); - -// node_modules/@tldraw/sync-core/dist-esm/lib/ServerSocketAdapter.mjs -init_checked_fetch(); -init_modules_watch_stub(); -var ServerSocketAdapter = class { - constructor(opts) { - this.opts = opts; - } - // eslint-disable-next-line no-restricted-syntax - get isOpen() { - return this.opts.ws.readyState === 1; - } - // see TLRoomSocket for details on why this accepts a union and not just arrays - sendMessage(msg) { - const message = JSON.stringify(msg); - this.opts.onBeforeSendMessage?.(msg, message); - this.opts.ws.send(message); - } - close() { - this.opts.ws.close(); - } -}; - -// node_modules/@tldraw/sync-core/dist-esm/lib/TLSyncRoom.mjs -init_checked_fetch(); -init_modules_watch_stub(); -var import_lodash6 = __toESM(require_lodash3(), 1); - -// node_modules/nanoevents/index.js -init_checked_fetch(); -init_modules_watch_stub(); -var createNanoEvents = () => ({ - events: {}, - emit(event, ...args) { - let callbacks = this.events[event] || []; - for (let i = 0, length = callbacks.length; i < length; i++) { - callbacks[i](...args); - } - }, - on(event, cb) { - this.events[event]?.push(cb) || (this.events[event] = [cb]); - return () => { - this.events[event] = this.events[event]?.filter((i) => cb !== i); - }; - } -}); - -// node_modules/@tldraw/sync-core/dist-esm/lib/TLSyncRoom.mjs -var MAX_TOMBSTONES = 3e3; -var TOMBSTONE_PRUNE_BUFFER_SIZE = 300; -var DATA_MESSAGE_DEBOUNCE_INTERVAL = 1e3 / 60; -var timeSince = (time) => Date.now() - time; -var DocumentState = class { - constructor(state, lastChangedClock, recordType) { - this.recordType = recordType; - this._atom = atom("document:" + state.id, { state, lastChangedClock }); - } - _atom; - static createWithoutValidating(state, lastChangedClock, recordType) { - return new DocumentState(state, lastChangedClock, recordType); - } - static createAndValidate(state, lastChangedClock, recordType) { - try { - recordType.validate(state); - } catch (error) { - return Result.err(error); - } - return Result.ok(new DocumentState(state, lastChangedClock, recordType)); - } - // eslint-disable-next-line no-restricted-syntax - get state() { - return this._atom.get().state; - } - // eslint-disable-next-line no-restricted-syntax - get lastChangedClock() { - return this._atom.get().lastChangedClock; - } - replaceState(state, clock) { - const diff = diffRecord(this.state, state); - if (!diff) - return Result.ok(null); - try { - this.recordType.validate(state); - } catch (error) { - return Result.err(error); - } - this._atom.set({ state, lastChangedClock: clock }); - return Result.ok(diff); - } - mergeDiff(diff, clock) { - const newState = applyObjectDiff(this.state, diff); - return this.replaceState(newState, clock); - } -}; -var TLSyncRoom = class { - // A table of connected clients - sessions = /* @__PURE__ */ new Map(); - pruneSessions = () => { - for (const client of this.sessions.values()) { - switch (client.state) { - case RoomSessionState.Connected: { - const hasTimedOut = timeSince(client.lastInteractionTime) > SESSION_IDLE_TIMEOUT; - if (hasTimedOut || !client.socket.isOpen) { - this.cancelSession(client.sessionId); - } - break; - } - case RoomSessionState.AwaitingConnectMessage: { - const hasTimedOut = timeSince(client.sessionStartTime) > SESSION_START_WAIT_TIME; - if (hasTimedOut || !client.socket.isOpen) { - this.removeSession(client.sessionId); - } - break; - } - case RoomSessionState.AwaitingRemoval: { - const hasTimedOut = timeSince(client.cancellationTime) > SESSION_REMOVAL_WAIT_TIME; - if (hasTimedOut) { - this.removeSession(client.sessionId); - } - break; - } - default: { - exhaustiveSwitchError(client); - } - } - } - }; - disposables = [interval(this.pruneSessions, 2e3)]; - _isClosed = false; - close() { - this.disposables.forEach((d) => d()); - this.sessions.forEach((session) => { - session.socket.close(); - }); - this._isClosed = true; - } - isClosed() { - return this._isClosed; - } - events = createNanoEvents(); - // Values associated with each uid (must be serializable). - /** @internal */ - state = atom("room state", { - documents: {}, - tombstones: {} - }); - // this clock should start higher than the client, to make sure that clients who sync with their - // initial lastServerClock value get the full state - // in this case clients will start with 0, and the server will start with 1 - clock = 1; - documentClock = 1; - tombstoneHistoryStartsAtClock = this.clock; - // map from record id to clock upon deletion - serializedSchema; - documentTypes; - presenceType; - log; - schema; - constructor(opts) { - this.schema = opts.schema; - let snapshot = opts.snapshot; - this.log = opts.log; - assert( - isNativeStructuredClone, - "TLSyncRoom is supposed to run either on Cloudflare Workersor on a 18+ version of Node.js, which both support the native structuredClone API" - ); - this.serializedSchema = JSON.parse(JSON.stringify(this.schema.serialize())); - this.documentTypes = new Set( - Object.values(this.schema.types).filter((t2) => t2.scope === "document").map((t2) => t2.typeName) - ); - const presenceTypes = new Set( - Object.values(this.schema.types).filter((t2) => t2.scope === "presence") - ); - if (presenceTypes.size != 1) { - throw new Error( - `TLSyncRoom: exactly one presence type is expected, but found ${presenceTypes.size}` - ); - } - this.presenceType = presenceTypes.values().next().value; - if (!snapshot) { - snapshot = { - clock: 0, - documents: [ - { - state: DocumentRecordType.create({ id: TLDOCUMENT_ID }), - lastChangedClock: 0 - }, - { - state: PageRecordType.create({ name: "Page 1", index: "a1" }), - lastChangedClock: 0 - } - ] - }; - } - this.clock = snapshot.clock; - let didIncrementClock = false; - const ensureClockDidIncrement = (_reason) => { - if (!didIncrementClock) { - didIncrementClock = true; - this.clock++; - } - }; - const tombstones = { ...snapshot.tombstones }; - const filteredDocuments = []; - for (const doc of snapshot.documents) { - if (this.documentTypes.has(doc.state.typeName)) { - filteredDocuments.push(doc); - } else { - ensureClockDidIncrement("doc type was not doc type"); - tombstones[doc.state.id] = this.clock; - } - } - const documents = Object.fromEntries( - filteredDocuments.map((r2) => [ - r2.state.id, - DocumentState.createWithoutValidating( - r2.state, - r2.lastChangedClock, - assertExists(getOwnProperty(this.schema.types, r2.state.typeName)) - ) - ]) - ); - const migrationResult = this.schema.migrateStoreSnapshot({ - store: Object.fromEntries( - objectMapEntries(documents).map(([id, { state }]) => [id, state]) - ), - // eslint-disable-next-line deprecation/deprecation - schema: snapshot.schema ?? this.schema.serializeEarliestVersion() - }); - if (migrationResult.type === "error") { - throw new Error("Failed to migrate: " + migrationResult.reason); - } - for (const [id, r2] of objectMapEntries(migrationResult.value)) { - const existing = documents[id]; - if (!existing) { - ensureClockDidIncrement("record was added during migration"); - documents[id] = DocumentState.createWithoutValidating( - r2, - this.clock, - assertExists(getOwnProperty(this.schema.types, r2.typeName)) - ); - } else if (!(0, import_lodash6.default)(existing.state, r2)) { - ensureClockDidIncrement("record was maybe updated during migration"); - existing.replaceState(r2, this.clock); - } - } - for (const id of objectMapKeys(documents)) { - if (!migrationResult.value[id]) { - ensureClockDidIncrement("record was removed during migration"); - tombstones[id] = this.clock; - delete documents[id]; - } - } - this.state.set({ documents, tombstones }); - this.pruneTombstones(); - this.documentClock = this.clock; - } - pruneTombstones = () => { - this.state.update(({ tombstones, documents }) => { - const entries = Object.entries(this.state.get().tombstones); - if (entries.length > MAX_TOMBSTONES) { - entries.sort((a2, b) => a2[1] - b[1]); - const excessQuantity = entries.length - MAX_TOMBSTONES; - tombstones = Object.fromEntries(entries.slice(excessQuantity + TOMBSTONE_PRUNE_BUFFER_SIZE)); - } - return { - documents, - tombstones - }; - }); - }; - getDocument(id) { - return this.state.get().documents[id]; - } - addDocument(id, state, clock) { - let { documents, tombstones } = this.state.get(); - if (hasOwnProperty(tombstones, id)) { - tombstones = { ...tombstones }; - delete tombstones[id]; - } - const createResult = DocumentState.createAndValidate( - state, - clock, - assertExists(getOwnProperty(this.schema.types, state.typeName)) - ); - if (!createResult.ok) - return createResult; - documents = { ...documents, [id]: createResult.value }; - this.state.set({ documents, tombstones }); - return Result.ok(void 0); - } - removeDocument(id, clock) { - this.state.update(({ documents, tombstones }) => { - documents = { ...documents }; - delete documents[id]; - tombstones = { ...tombstones, [id]: clock }; - return { documents, tombstones }; - }); - } - getSnapshot() { - const { documents, tombstones } = this.state.get(); - return { - clock: this.clock, - tombstones, - schema: this.serializedSchema, - documents: Object.values(documents).map((doc) => ({ - state: doc.state, - lastChangedClock: doc.lastChangedClock - })).filter((d) => this.documentTypes.has(d.state.typeName)) - }; - } - /** - * Send a message to a particular client. Debounces data events - * - * @param sessionId - The id of the session to send the message to. - * @param message - The message to send. - */ - sendMessage(sessionId, message) { - const session = this.sessions.get(sessionId); - if (!session) { - this.log?.warn?.("Tried to send message to unknown session", message.type); - return; - } - if (session.state !== RoomSessionState.Connected) { - this.log?.warn?.("Tried to send message to disconnected client", message.type); - return; - } - if (session.socket.isOpen) { - if (message.type !== "patch" && message.type !== "push_result") { - if (message.type !== "pong") { - this._flushDataMessages(sessionId); - } - session.socket.sendMessage(message); - } else { - if (session.debounceTimer === null) { - session.socket.sendMessage({ type: "data", data: [message] }); - session.debounceTimer = setTimeout( - () => this._flushDataMessages(sessionId), - DATA_MESSAGE_DEBOUNCE_INTERVAL - ); - } else { - session.outstandingDataMessages.push(message); - } - } - } else { - this.cancelSession(session.sessionId); - } - } - // needs to accept sessionId and not a session because the session might be dead by the time - // the timer fires - _flushDataMessages(sessionId) { - const session = this.sessions.get(sessionId); - if (!session || session.state !== RoomSessionState.Connected) { - return; - } - session.debounceTimer = null; - if (session.outstandingDataMessages.length > 0) { - session.socket.sendMessage({ type: "data", data: session.outstandingDataMessages }); - session.outstandingDataMessages.length = 0; - } - } - removeSession(sessionId) { - const session = this.sessions.get(sessionId); - if (!session) { - this.log?.warn?.("Tried to remove unknown session"); - return; - } - this.sessions.delete(sessionId); - const presence = this.getDocument(session.presenceId); - try { - if (session.socket.isOpen) { - session.socket.close(); - } - } catch (_e) { - } - if (presence) { - this.state.update(({ tombstones, documents }) => { - documents = { ...documents }; - delete documents[session.presenceId]; - return { documents, tombstones }; - }); - this.broadcastPatch({ - diff: { [session.presenceId]: [RecordOpType.Remove] }, - sourceSessionId: sessionId - }); - } - this.events.emit("session_removed", { sessionId, meta: session.meta }); - if (this.sessions.size === 0) { - this.events.emit("room_became_empty"); - } - } - cancelSession(sessionId) { - const session = this.sessions.get(sessionId); - if (!session) { - return; - } - if (session.state === RoomSessionState.AwaitingRemoval) { - this.log?.warn?.("Tried to cancel session that is already awaiting removal"); - return; - } - this.sessions.set(sessionId, { - state: RoomSessionState.AwaitingRemoval, - sessionId, - presenceId: session.presenceId, - socket: session.socket, - cancellationTime: Date.now(), - meta: session.meta - }); - } - /** - * Broadcast a message to all connected clients except the one with the sessionId provided. - * - * @param message - The message to broadcast. - * @param sourceSessionId - The session to exclude. - */ - broadcastPatch({ diff, sourceSessionId }) { - this.sessions.forEach((session) => { - if (session.state !== RoomSessionState.Connected) - return; - if (sourceSessionId === session.sessionId) - return; - if (!session.socket.isOpen) { - this.cancelSession(session.sessionId); - return; - } - const res = this.migrateDiffForSession(session.serializedSchema, diff); - if (!res.ok) { - this.rejectSession( - session, - res.error === MigrationFailureReason.TargetVersionTooNew ? TLIncompatibilityReason.ServerTooOld : TLIncompatibilityReason.ClientTooOld - ); - return; - } - this.sendMessage(session.sessionId, { - type: "patch", - diff: res.value, - serverClock: this.clock - }); - }); - return this; - } - /** - * When a client connects to the room, add them to the list of clients and then merge the history - * down into the snapshots. - * - * @param sessionId - The session of the client that connected to the room. - * @param socket - Their socket. - */ - handleNewSession = (sessionId, socket, meta) => { - const existing = this.sessions.get(sessionId); - this.sessions.set(sessionId, { - state: RoomSessionState.AwaitingConnectMessage, - sessionId, - socket, - presenceId: existing?.presenceId ?? this.presenceType.createId(), - sessionStartTime: Date.now(), - meta - }); - return this; - }; - /** - * When we send a diff to a client, if that client is on a lower version than us, we need to make - * the diff compatible with their version. At the moment this means migrating each affected record - * to the client's version and sending the whole record again. We can optimize this later by - * keeping the previous versions of records around long enough to recalculate these diffs for - * older client versions. - */ - migrateDiffForSession(serializedSchema, diff) { - if (serializedSchema === this.serializedSchema) { - return Result.ok(diff); - } - const result = {}; - for (const [id, op] of Object.entries(diff)) { - if (op[0] === RecordOpType.Remove) { - result[id] = op; - continue; - } - const migrationResult = this.schema.migratePersistedRecord( - this.getDocument(id).state, - serializedSchema, - "down" - ); - if (migrationResult.type === "error") { - return Result.err(migrationResult.reason); - } - result[id] = [RecordOpType.Put, migrationResult.value]; - } - return Result.ok(result); - } - /** - * When the server receives a message from the clients Currently, supports connect and patches. - * Invalid messages types throws an error. Currently, doesn't validate data. - * - * @param sessionId - The session that sent the message - * @param message - The message that was sent - */ - handleMessage = async (sessionId, message) => { - const session = this.sessions.get(sessionId); - if (!session) { - this.log?.warn?.("Received message from unknown session"); - return; - } - switch (message.type) { - case "connect": { - return this.handleConnectRequest(session, message); - } - case "push": { - return this.handlePushRequest(session, message); - } - case "ping": { - if (session.state === RoomSessionState.Connected) { - session.lastInteractionTime = Date.now(); - } - return this.sendMessage(session.sessionId, { type: "pong" }); - } - default: { - exhaustiveSwitchError(message); - } - } - }; - /** If the client is out of date, or we are out of date, we need to let them know */ - rejectSession(session, reason) { - try { - if (session.socket.isOpen) { - session.socket.sendMessage({ - type: "incompatibility_error", - reason - }); - } - } catch (e) { - } finally { - this.removeSession(session.sessionId); - } - } - handleConnectRequest(session, message) { - let theirProtocolVersion = message.protocolVersion; - if (theirProtocolVersion === 5) { - theirProtocolVersion = 6; - } - if (theirProtocolVersion == null || theirProtocolVersion < getTlsyncProtocolVersion()) { - this.rejectSession(session, TLIncompatibilityReason.ClientTooOld); - return; - } else if (theirProtocolVersion > getTlsyncProtocolVersion()) { - this.rejectSession(session, TLIncompatibilityReason.ServerTooOld); - return; - } - if (message.schema == null) { - this.rejectSession(session, TLIncompatibilityReason.ClientTooOld); - return; - } - const migrations = this.schema.getMigrationsSince(message.schema); - if (!migrations.ok || migrations.value.some((m) => m.scope === "store" || !m.down)) { - this.rejectSession(session, TLIncompatibilityReason.ClientTooOld); - return; - } - const sessionSchema = (0, import_lodash6.default)(message.schema, this.serializedSchema) ? this.serializedSchema : message.schema; - const connect = (msg) => { - this.sessions.set(session.sessionId, { - state: RoomSessionState.Connected, - sessionId: session.sessionId, - presenceId: session.presenceId, - socket: session.socket, - serializedSchema: sessionSchema, - lastInteractionTime: Date.now(), - debounceTimer: null, - outstandingDataMessages: [], - meta: session.meta - }); - this.sendMessage(session.sessionId, msg); - }; - transaction((rollback) => { - if ( - // if the client requests changes since a time before we have tombstone history, send them the full state - message.lastServerClock < this.tombstoneHistoryStartsAtClock || // similarly, if they ask for a time we haven't reached yet, send them the full state - // this will only happen if the DB is reset (or there is no db) and the server restarts - // or if the server exits/crashes with unpersisted changes - message.lastServerClock > this.clock - ) { - const diff = {}; - for (const [id, doc] of Object.entries(this.state.get().documents)) { - if (id !== session.presenceId) { - diff[id] = [RecordOpType.Put, doc.state]; - } - } - const migrated = this.migrateDiffForSession(sessionSchema, diff); - if (!migrated.ok) { - rollback(); - this.rejectSession( - session, - migrated.error === MigrationFailureReason.TargetVersionTooNew ? TLIncompatibilityReason.ServerTooOld : TLIncompatibilityReason.ClientTooOld - ); - return; - } - connect({ - type: "connect", - connectRequestId: message.connectRequestId, - hydrationType: "wipe_all", - protocolVersion: getTlsyncProtocolVersion(), - schema: this.schema.serialize(), - serverClock: this.clock, - diff: migrated.value - }); - } else { - const diff = {}; - const updatedDocs = Object.values(this.state.get().documents).filter( - (doc) => doc.lastChangedClock > message.lastServerClock - ); - const presenceDocs = Object.values(this.state.get().documents).filter( - (doc) => this.presenceType.typeName === doc.state.typeName && doc.state.id !== session.presenceId - ); - const deletedDocsIds = Object.entries(this.state.get().tombstones).filter(([_id, deletedAtClock]) => deletedAtClock > message.lastServerClock).map(([id]) => id); - for (const doc of updatedDocs) { - diff[doc.state.id] = [RecordOpType.Put, doc.state]; - } - for (const doc of presenceDocs) { - diff[doc.state.id] = [RecordOpType.Put, doc.state]; - } - for (const docId of deletedDocsIds) { - diff[docId] = [RecordOpType.Remove]; - } - const migrated = this.migrateDiffForSession(sessionSchema, diff); - if (!migrated.ok) { - rollback(); - this.rejectSession( - session, - migrated.error === MigrationFailureReason.TargetVersionTooNew ? TLIncompatibilityReason.ServerTooOld : TLIncompatibilityReason.ClientTooOld - ); - return; - } - connect({ - type: "connect", - connectRequestId: message.connectRequestId, - hydrationType: "wipe_presence", - schema: this.schema.serialize(), - protocolVersion: getTlsyncProtocolVersion(), - serverClock: this.clock, - diff: migrated.value - }); - } - }); - } - handlePushRequest(session, message) { - if (session.state !== RoomSessionState.Connected) { - return; - } - session.lastInteractionTime = Date.now(); - this.clock++; - transaction((rollback) => { - const docChanges = { diff: null }; - const presenceChanges = { diff: null }; - const propagateOp = (changes, id, op) => { - if (!changes.diff) - changes.diff = {}; - changes.diff[id] = op; - }; - const fail = (reason) => { - rollback(); - this.rejectSession(session, reason); - if (typeof process !== "undefined" && true) { - this.log?.error?.("failed to apply push", reason, message); - } - return Result.err(void 0); - }; - const addDocument = (changes, id, _state) => { - const res = this.schema.migratePersistedRecord(_state, session.serializedSchema, "up"); - if (res.type === "error") { - return fail( - res.reason === MigrationFailureReason.TargetVersionTooOld ? TLIncompatibilityReason.ServerTooOld : TLIncompatibilityReason.ClientTooOld - ); - } - const { value: state } = res; - const doc = this.getDocument(id); - if (doc) { - const diff = doc.replaceState(state, this.clock); - if (!diff.ok) { - return fail(TLIncompatibilityReason.InvalidRecord); - } - if (diff.value) { - propagateOp(changes, id, [RecordOpType.Patch, diff.value]); - } - } else { - const result = this.addDocument(id, state, this.clock); - if (!result.ok) { - return fail(TLIncompatibilityReason.InvalidRecord); - } - propagateOp(changes, id, [RecordOpType.Put, state]); - } - return Result.ok(void 0); - }; - const patchDocument = (changes, id, patch) => { - const doc = this.getDocument(id); - if (!doc) - return Result.ok(void 0); - const downgraded = this.schema.migratePersistedRecord( - doc.state, - session.serializedSchema, - "down" - ); - if (downgraded.type === "error") { - return fail(TLIncompatibilityReason.ClientTooOld); - } - if (downgraded.value === doc.state) { - const diff = doc.mergeDiff(patch, this.clock); - if (!diff.ok) { - return fail(TLIncompatibilityReason.InvalidRecord); - } - if (diff.value) { - propagateOp(changes, id, [RecordOpType.Patch, diff.value]); - } - } else { - const patched = applyObjectDiff(downgraded.value, patch); - const upgraded = this.schema.migratePersistedRecord( - patched, - session.serializedSchema, - "up" - ); - if (upgraded.type === "error") { - return fail(TLIncompatibilityReason.ClientTooOld); - } - const diff = doc.replaceState(upgraded.value, this.clock); - if (!diff.ok) { - return fail(TLIncompatibilityReason.InvalidRecord); - } - if (diff.value) { - propagateOp(changes, id, [RecordOpType.Patch, diff.value]); - } - } - return Result.ok(void 0); - }; - const { clientClock } = message; - if ("presence" in message && message.presence) { - const id = session.presenceId; - const [type, val] = message.presence; - const { typeName } = this.presenceType; - switch (type) { - case RecordOpType.Put: { - const res = addDocument(presenceChanges, id, { ...val, id, typeName }); - if (!res.ok) - return; - break; - } - case RecordOpType.Patch: { - const res = patchDocument(presenceChanges, id, { - ...val, - id: [ValueOpType.Put, id], - typeName: [ValueOpType.Put, typeName] - }); - if (!res.ok) - return; - break; - } - } - } - if (message.diff) { - for (const [id, op] of Object.entries(message.diff)) { - switch (op[0]) { - case RecordOpType.Put: { - if (!this.documentTypes.has(op[1].typeName)) { - return fail(TLIncompatibilityReason.InvalidRecord); - } - const res = addDocument(docChanges, id, op[1]); - if (!res.ok) - return; - break; - } - case RecordOpType.Patch: { - const res = patchDocument(docChanges, id, op[1]); - if (!res.ok) - return; - break; - } - case RecordOpType.Remove: { - const doc = this.getDocument(id); - if (!doc) { - continue; - } - if (!this.documentTypes.has(doc.state.typeName)) { - return fail(TLIncompatibilityReason.InvalidOperation); - } - this.removeDocument(id, this.clock); - setTimeout(this.pruneTombstones, 0); - propagateOp(docChanges, id, op); - break; - } - } - } - } - if ( - // if there was only a presence push, the client doesn't need to do anything aside from - // shift the push request. - !message.diff || (0, import_lodash6.default)(docChanges.diff, message.diff) - ) { - this.sendMessage(session.sessionId, { - type: "push_result", - serverClock: this.clock, - clientClock, - action: "commit" - }); - } else if (!docChanges.diff) { - this.sendMessage(session.sessionId, { - type: "push_result", - serverClock: this.clock, - clientClock, - action: "discard" - }); - } else { - const migrateResult = this.migrateDiffForSession(session.serializedSchema, docChanges.diff); - if (!migrateResult.ok) { - return fail( - migrateResult.error === MigrationFailureReason.TargetVersionTooNew ? TLIncompatibilityReason.ServerTooOld : TLIncompatibilityReason.ClientTooOld - ); - } - this.sendMessage(session.sessionId, { - type: "push_result", - serverClock: this.clock, - clientClock, - action: { rebaseWithDiff: migrateResult.value } - }); - } - if (docChanges.diff || presenceChanges.diff) { - this.broadcastPatch({ - sourceSessionId: session.sessionId, - diff: { - ...docChanges.diff, - ...presenceChanges.diff - } - }); - } - if (docChanges.diff) { - this.documentClock = this.clock; - } - return; - }); - } - /** - * Handle the event when a client disconnects. - * - * @param sessionId - The session that disconnected. - */ - handleClose = (sessionId) => { - this.cancelSession(sessionId); - }; -}; - -// node_modules/@tldraw/sync-core/dist-esm/lib/TLSocketRoom.mjs -var TLSocketRoom = class { - constructor(opts) { - this.opts = opts; - const initialSnapshot = opts.initialSnapshot && "store" in opts.initialSnapshot ? convertStoreSnapshotToRoomSnapshot(opts.initialSnapshot) : opts.initialSnapshot; - const initialClock = initialSnapshot?.clock ?? 0; - this.room = new TLSyncRoom({ - schema: opts.schema ?? createTLSchema(), - snapshot: initialSnapshot, - log: opts.log - }); - if (this.room.clock !== initialClock) { - this.opts?.onDataChange?.(); - } - this.room.events.on("session_removed", (args) => { - this.sessions.delete(args.sessionId); - if (this.opts.onSessionRemoved) { - this.opts.onSessionRemoved(this, { - sessionId: args.sessionId, - numSessionsRemaining: this.room.sessions.size, - meta: args.meta - }); - } - }); - this.log = "log" in opts ? opts.log : { error: console.error }; - } - room; - sessions = /* @__PURE__ */ new Map(); - log; - /** - * Returns the number of active sessions. - * Note that this is not the same as the number of connected sockets! - * Sessions time out a few moments after sockets close, to smooth over network hiccups. - * - * @returns the number of active sessions - */ - getNumActiveSessions() { - return this.room.sessions.size; - } - /** - * Call this when a client establishes a new socket connection. - * - * - `sessionId` is a unique ID for a browser tab. This is passed as a query param by the useSync hook. - * - `socket` is a WebSocket-like object that the server uses to communicate with the client. - * - `meta` is an optional object that can be used to store additional information about the session. - * - * @param opts - The options object - */ - handleSocketConnect(opts) { - const { sessionId, socket } = opts; - const handleSocketMessage = (event) => this.handleSocketMessage(sessionId, event.data); - const handleSocketError = this.handleSocketError.bind(this, sessionId); - const handleSocketClose = this.handleSocketClose.bind(this, sessionId); - this.sessions.set(sessionId, { - assembler: new JsonChunkAssembler(), - socket, - unlisten: () => { - socket.removeEventListener?.("message", handleSocketMessage); - socket.removeEventListener?.("close", handleSocketClose); - socket.removeEventListener?.("error", handleSocketError); - } - }); - this.room.handleNewSession( - sessionId, - new ServerSocketAdapter({ - ws: socket, - onBeforeSendMessage: this.opts.onBeforeSendMessage ? (message, stringified) => this.opts.onBeforeSendMessage({ - sessionId, - message, - stringified, - meta: this.room.sessions.get(sessionId)?.meta - }) : void 0 - }), - "meta" in opts ? opts.meta : void 0 - ); - socket.addEventListener?.("message", handleSocketMessage); - socket.addEventListener?.("close", handleSocketClose); - socket.addEventListener?.("error", handleSocketError); - } - /** - * If executing in a server environment where sockets do not have instance-level listeners - * (e.g. Bun.serve, Cloudflare Worker with WebSocket hibernation), you should call this - * method when messages are received. See our self-hosting example for Bun.serve for an example. - * - * @param sessionId - The id of the session. (should match the one used when calling handleSocketConnect) - * @param message - The message received from the client. - */ - handleSocketMessage(sessionId, message) { - const documentClockAtStart = this.room.documentClock; - const assembler = this.sessions.get(sessionId)?.assembler; - if (!assembler) { - this.log?.warn?.("Received message from unknown session", sessionId); - return; - } - try { - const messageString = typeof message === "string" ? message : new TextDecoder().decode(message); - const res = assembler.handleMessage(messageString); - if (!res) { - return; - } - if ("data" in res) { - if (this.opts.onAfterReceiveMessage) { - const session = this.room.sessions.get(sessionId); - if (session) { - this.opts.onAfterReceiveMessage({ - sessionId, - message: res.data, - stringified: res.stringified, - meta: session.meta - }); - } - } - this.room.handleMessage(sessionId, res.data); - } else { - this.log?.error?.("Error assembling message", res.error); - this.handleSocketError(sessionId); - } - } catch (e) { - this.log?.error?.(e); - const socket = this.sessions.get(sessionId)?.socket; - if (socket) { - socket.send( - JSON.stringify({ - type: "error", - error: typeof e?.toString === "function" ? e.toString() : e - }) - ); - socket.close(); - } - } finally { - if (this.room.documentClock !== documentClockAtStart) { - this.opts.onDataChange?.(); - } - } - } - /** - * If executing in a server environment where sockets do not have instance-level listeners, - * call this when a socket error occurs. - * @param sessionId - The id of the session. (should match the one used when calling handleSocketConnect) - */ - handleSocketError(sessionId) { - this.room.handleClose(sessionId); - } - /** - * If executing in a server environment where sockets do not have instance-level listeners, - * call this when a socket is closed. - * @param sessionId - The id of the session. (should match the one used when calling handleSocketConnect) - */ - handleSocketClose(sessionId) { - this.room.handleClose(sessionId); - } - /** - * Returns the current 'clock' of the document. - * The clock is an integer that increments every time the document changes. - * The clock is stored as part of the snapshot of the document for consistency purposes. - * - * @returns The clock - */ - getCurrentDocumentClock() { - return this.room.documentClock; - } - /** - * Return a snapshot of the document state, including clock-related bookkeeping. - * You can store this and load it later on when initializing a TLSocketRoom. - * You can also pass a snapshot to {@link TLSocketRoom#loadSnapshot} if you need to revert to a previous state. - * @returns The snapshot - */ - getCurrentSnapshot() { - return this.room.getSnapshot(); - } - /** - * Load a snapshot of the document state, overwriting the current state. - * @param snapshot - The snapshot to load - */ - loadSnapshot(snapshot) { - if ("store" in snapshot) { - snapshot = convertStoreSnapshotToRoomSnapshot(snapshot); - } - const oldRoom = this.room; - const oldIds = oldRoom.getSnapshot().documents.map((d) => d.state.id); - const newIds = new Set(snapshot.documents.map((d) => d.state.id)); - const removedIds = oldIds.filter((id) => !newIds.has(id)); - const tombstones = { ...snapshot.tombstones }; - removedIds.forEach((id) => { - tombstones[id] = oldRoom.clock + 1; - }); - newIds.forEach((id) => { - delete tombstones[id]; - }); - const newRoom = new TLSyncRoom({ - schema: oldRoom.schema, - snapshot: { - clock: oldRoom.clock + 1, - documents: snapshot.documents.map((d) => ({ - lastChangedClock: oldRoom.clock + 1, - state: d.state - })), - schema: snapshot.schema, - tombstones - }, - log: this.log - }); - this.room = newRoom; - oldRoom.close(); - } - /** - * Close the room and disconnect all clients. Call this before discarding the room instance or shutting down the server. - */ - close() { - this.room.close(); - } - /** - * @returns true if the room is closed - */ - isClosed() { - return this.room.isClosed(); - } -}; -function convertStoreSnapshotToRoomSnapshot(snapshot) { - return { - clock: 0, - documents: objectMapValues(snapshot.store).map((state) => ({ - state, - lastChangedClock: 0 - })), - schema: snapshot.schema, - tombstones: {} - }; -} - -// node_modules/@tldraw/tlschema/dist-esm/index.mjs -init_checked_fetch(); -init_modules_watch_stub(); - -// node_modules/@tldraw/tlschema/dist-esm/assets/TLBaseAsset.mjs -init_checked_fetch(); -init_modules_watch_stub(); - -// node_modules/@tldraw/tlschema/dist-esm/misc/id-validator.mjs -init_checked_fetch(); -init_modules_watch_stub(); -function idValidator2(prefix) { - return validation_exports.string.refine((id) => { - if (!id.startsWith(`${prefix}:`)) { - throw new Error(`${prefix} ID must start with "${prefix}:"`); - } - return id; - }); -} - -// node_modules/@tldraw/tlschema/dist-esm/assets/TLBaseAsset.mjs -var assetIdValidator2 = idValidator2("asset"); -function createAssetValidator2(type, props) { - return validation_exports.object({ - id: assetIdValidator2, - typeName: validation_exports.literal("asset"), - type: validation_exports.literal(type), - props, - meta: validation_exports.jsonValue - }); -} - -// node_modules/@tldraw/tlschema/dist-esm/bindings/TLArrowBinding.mjs -init_checked_fetch(); -init_modules_watch_stub(); - -// node_modules/@tldraw/tlschema/dist-esm/misc/geometry-types.mjs -init_checked_fetch(); -init_modules_watch_stub(); -var vecModelValidator2 = validation_exports.object({ - x: validation_exports.number, - y: validation_exports.number, - z: validation_exports.number.optional() -}); -var boxModelValidator2 = validation_exports.object({ - x: validation_exports.number, - y: validation_exports.number, - w: validation_exports.number, - h: validation_exports.number -}); - -// node_modules/@tldraw/tlschema/dist-esm/records/TLBinding.mjs -init_checked_fetch(); -init_modules_watch_stub(); - -// node_modules/@tldraw/tlschema/dist-esm/bindings/TLBaseBinding.mjs -init_checked_fetch(); -init_modules_watch_stub(); - -// node_modules/@tldraw/tlschema/dist-esm/shapes/TLBaseShape.mjs -init_checked_fetch(); -init_modules_watch_stub(); - -// node_modules/@tldraw/tlschema/dist-esm/misc/TLOpacity.mjs -init_checked_fetch(); -init_modules_watch_stub(); -var opacityValidator2 = validation_exports.number.check((n2) => { - if (n2 < 0 || n2 > 1) { - throw new validation_exports.ValidationError("Opacity must be between 0 and 1"); - } -}); - -// node_modules/@tldraw/tlschema/dist-esm/shapes/TLBaseShape.mjs -var parentIdValidator2 = validation_exports.string.refine((id) => { - if (!id.startsWith("page:") && !id.startsWith("shape:")) { - throw new Error('Parent ID must start with "page:" or "shape:"'); - } - return id; -}); -var shapeIdValidator2 = idValidator2("shape"); -function createShapeValidator2(type, props, meta) { - return validation_exports.object({ - id: shapeIdValidator2, - typeName: validation_exports.literal("shape"), - x: validation_exports.number, - y: validation_exports.number, - rotation: validation_exports.number, - index: validation_exports.indexKey, - parentId: parentIdValidator2, - type: validation_exports.literal(type), - isLocked: validation_exports.boolean, - opacity: opacityValidator2, - props: props ? validation_exports.object(props) : validation_exports.jsonValue, - meta: meta ? validation_exports.object(meta) : validation_exports.jsonValue - }); -} - -// node_modules/@tldraw/tlschema/dist-esm/bindings/TLBaseBinding.mjs -var bindingIdValidator2 = idValidator2("binding"); -function createBindingValidator2(type, props, meta) { - return validation_exports.object({ - id: bindingIdValidator2, - typeName: validation_exports.literal("binding"), - type: validation_exports.literal(type), - fromId: shapeIdValidator2, - toId: shapeIdValidator2, - props: props ? validation_exports.object(props) : validation_exports.jsonValue, - meta: meta ? validation_exports.object(meta) : validation_exports.jsonValue - }); -} - -// node_modules/@tldraw/tlschema/dist-esm/records/TLBinding.mjs -var rootBindingVersions2 = createMigrationIds("com.tldraw.binding", {}); -var rootBindingMigrations2 = createRecordMigrationSequence({ - sequenceId: "com.tldraw.binding", - recordType: "binding", - sequence: [] -}); -function createBindingId2(id) { - return `binding:${id ?? nanoid()}`; -} -function createBindingPropsMigrationSequence2(migrations) { - return migrations; -} -function createBindingRecordType2(bindings) { - return createRecordType("binding", { - scope: "document", - validator: validation_exports.model( - "binding", - validation_exports.union( - "type", - mapObjectMapValues( - bindings, - (type, { props, meta }) => createBindingValidator2(type, props, meta) - ) - ) - ) - }).withDefaultProperties(() => ({ - meta: {} - })); -} - -// node_modules/@tldraw/tlschema/dist-esm/shapes/TLArrowShape.mjs -init_checked_fetch(); -init_modules_watch_stub(); - -// node_modules/@tldraw/tlschema/dist-esm/records/TLShape.mjs -init_checked_fetch(); -init_modules_watch_stub(); - -// node_modules/@tldraw/tlschema/dist-esm/styles/StyleProp.mjs -init_checked_fetch(); -init_modules_watch_stub(); -var StyleProp2 = class { - /** @internal */ - constructor(id, defaultValue, type) { - this.id = id; - this.defaultValue = defaultValue; - this.type = type; - } - /** - * Define a new {@link StyleProp}. - * - * @param uniqueId - Each StyleProp must have a unique ID. We recommend you prefix this with - * your app/library name. - * @param options - - * - `defaultValue`: The default value for this style prop. - * - * - `type`: Optionally, describe what type of data you expect for this style prop. - * - * @example - * ```ts - * import {T} from '@tldraw/validate' - * import {StyleProp} from '@tldraw/tlschema' - * - * const MyLineWidthProp = StyleProp.define('myApp:lineWidth', { - * defaultValue: 1, - * type: T.number, - * }) - * ``` - * @public - */ - static define(uniqueId, options) { - const { defaultValue, type = validation_exports.any } = options; - return new StyleProp2(uniqueId, defaultValue, type); - } - /** - * Define a new {@link StyleProp} as a list of possible values. - * - * @param uniqueId - Each StyleProp must have a unique ID. We recommend you prefix this with - * your app/library name. - * @param options - - * - `defaultValue`: The default value for this style prop. - * - * - `values`: An array of possible values of this style prop. - * - * @example - * ```ts - * import {StyleProp} from '@tldraw/tlschema' - * - * const MySizeProp = StyleProp.defineEnum('myApp:size', { - * defaultValue: 'medium', - * values: ['small', 'medium', 'large'], - * }) - * ``` - */ - static defineEnum(uniqueId, options) { - const { defaultValue, values } = options; - return new EnumStyleProp2(uniqueId, defaultValue, values); - } - setDefaultValue(value) { - this.defaultValue = value; - } - validate(value) { - return this.type.validate(value); - } - validateUsingKnownGoodVersion(prevValue, newValue) { - if (this.type.validateUsingKnownGoodVersion) { - return this.type.validateUsingKnownGoodVersion(prevValue, newValue); - } else { - return this.validate(newValue); - } - } -}; -var EnumStyleProp2 = class extends StyleProp2 { - /** @internal */ - constructor(id, defaultValue, values) { - super(id, defaultValue, validation_exports.literalEnum(...values)); - this.values = values; - } -}; - -// node_modules/@tldraw/tlschema/dist-esm/records/TLShape.mjs -var rootShapeVersions2 = createMigrationIds("com.tldraw.shape", { - AddIsLocked: 1, - HoistOpacity: 2, - AddMeta: 3, - AddWhite: 4 -}); -var rootShapeMigrations2 = createRecordMigrationSequence({ - sequenceId: "com.tldraw.shape", - recordType: "shape", - sequence: [ - { - id: rootShapeVersions2.AddIsLocked, - up: (record) => { - record.isLocked = false; - }, - down: (record) => { - delete record.isLocked; - } - }, - { - id: rootShapeVersions2.HoistOpacity, - up: (record) => { - record.opacity = Number(record.props.opacity ?? "1"); - delete record.props.opacity; - }, - down: (record) => { - const opacity = record.opacity; - delete record.opacity; - record.props.opacity = opacity < 0.175 ? "0.1" : opacity < 0.375 ? "0.25" : opacity < 0.625 ? "0.5" : opacity < 0.875 ? "0.75" : "1"; - } - }, - { - id: rootShapeVersions2.AddMeta, - up: (record) => { - record.meta = {}; - } - }, - { - id: rootShapeVersions2.AddWhite, - up: (_record) => { - }, - down: (record) => { - if (record.props.color === "white") { - record.props.color = "black"; - } - } - } - ] -}); -function getShapePropKeysByStyle2(props) { - const propKeysByStyle = /* @__PURE__ */ new Map(); - for (const [key, prop] of Object.entries(props)) { - if (prop instanceof StyleProp2) { - if (propKeysByStyle.has(prop)) { - throw new Error( - `Duplicate style prop ${prop.id}. Each style prop can only be used once within a shape.` - ); - } - propKeysByStyle.set(prop, key); - } - } - return propKeysByStyle; -} -function createShapePropsMigrationSequence2(migrations) { - return migrations; -} -function createShapePropsMigrationIds2(shapeType, ids) { - return mapObjectMapValues(ids, (_k, v) => `com.tldraw.shape.${shapeType}/${v}`); -} -function createShapeRecordType2(shapes) { - return createRecordType("shape", { - scope: "document", - validator: validation_exports.model( - "shape", - validation_exports.union( - "type", - mapObjectMapValues( - shapes, - (type, { props, meta }) => createShapeValidator2(type, props, meta) - ) - ) - ) - }).withDefaultProperties(() => ({ - x: 0, - y: 0, - rotation: 0, - isLocked: false, - opacity: 1, - meta: {} - })); -} - -// node_modules/@tldraw/tlschema/dist-esm/recordsWithProps.mjs -init_checked_fetch(); -init_modules_watch_stub(); -function processPropsMigrations2(typeName, records) { - const result = []; - for (const [subType, { migrations }] of Object.entries(records)) { - const sequenceId = `com.tldraw.${typeName}.${subType}`; - if (!migrations) { - result.push( - createMigrationSequence({ - sequenceId, - retroactive: false, - sequence: [] - }) - ); - } else if ("sequenceId" in migrations) { - assert( - sequenceId === migrations.sequenceId, - `sequenceId mismatch for ${subType} ${RecordType} migrations. Expected '${sequenceId}', got '${migrations.sequenceId}'` - ); - result.push(migrations); - } else if ("sequence" in migrations) { - result.push( - createMigrationSequence({ - sequenceId, - retroactive: false, - sequence: migrations.sequence.map( - (m) => "id" in m ? createPropsMigration2(typeName, subType, m) : m - ) - }) - ); - } else { - result.push( - createMigrationSequence({ - sequenceId, - retroactive: false, - sequence: Object.keys(migrations.migrators).map((k) => Number(k)).sort((a2, b) => a2 - b).map( - (version) => ({ - id: `${sequenceId}/${version}`, - scope: "record", - filter: (r2) => r2.typeName === typeName && r2.type === subType, - up: (record) => { - const result2 = migrations.migrators[version].up(record); - if (result2) { - return result2; - } - }, - down: (record) => { - const result2 = migrations.migrators[version].down(record); - if (result2) { - return result2; - } - } - }) - ) - }) - ); - } - } - return result; -} -function createPropsMigration2(typeName, subType, m) { - return { - id: m.id, - dependsOn: m.dependsOn, - scope: "record", - filter: (r2) => r2.typeName === typeName && r2.type === subType, - up: (record) => { - const result = m.up(record.props); - if (result) { - record.props = result; - } - }, - down: typeof m.down === "function" ? (record) => { - const result = m.down(record.props); - if (result) { - record.props = result; - } - } : void 0 - }; -} - -// node_modules/@tldraw/tlschema/dist-esm/styles/TLColorStyle.mjs -init_checked_fetch(); -init_modules_watch_stub(); -var defaultColorNames2 = [ - "black", - "grey", - "light-violet", - "violet", - "blue", - "light-blue", - "yellow", - "orange", - "green", - "light-green", - "light-red", - "red", - "white" -]; -var DefaultColorStyle2 = StyleProp2.defineEnum("tldraw:color", { - defaultValue: "black", - values: defaultColorNames2 -}); -var DefaultLabelColorStyle2 = StyleProp2.defineEnum("tldraw:labelColor", { - defaultValue: "black", - values: defaultColorNames2 -}); - -// node_modules/@tldraw/tlschema/dist-esm/styles/TLDashStyle.mjs -init_checked_fetch(); -init_modules_watch_stub(); -var DefaultDashStyle2 = StyleProp2.defineEnum("tldraw:dash", { - defaultValue: "draw", - values: ["draw", "solid", "dashed", "dotted"] -}); - -// node_modules/@tldraw/tlschema/dist-esm/styles/TLFillStyle.mjs -init_checked_fetch(); -init_modules_watch_stub(); -var DefaultFillStyle2 = StyleProp2.defineEnum("tldraw:fill", { - defaultValue: "none", - values: ["none", "semi", "solid", "pattern", "fill"] -}); - -// node_modules/@tldraw/tlschema/dist-esm/styles/TLFontStyle.mjs -init_checked_fetch(); -init_modules_watch_stub(); -var DefaultFontStyle2 = StyleProp2.defineEnum("tldraw:font", { - defaultValue: "draw", - values: ["draw", "sans", "serif", "mono"] -}); - -// node_modules/@tldraw/tlschema/dist-esm/styles/TLSizeStyle.mjs -init_checked_fetch(); -init_modules_watch_stub(); -var DefaultSizeStyle2 = StyleProp2.defineEnum("tldraw:size", { - defaultValue: "m", - values: ["s", "m", "l", "xl"] -}); - -// node_modules/@tldraw/tlschema/dist-esm/shapes/TLArrowShape.mjs -var arrowheadTypes2 = [ - "arrow", - "triangle", - "square", - "dot", - "pipe", - "diamond", - "inverted", - "bar", - "none" -]; -var ArrowShapeArrowheadStartStyle2 = StyleProp2.defineEnum("tldraw:arrowheadStart", { - defaultValue: "none", - values: arrowheadTypes2 -}); -var ArrowShapeArrowheadEndStyle2 = StyleProp2.defineEnum("tldraw:arrowheadEnd", { - defaultValue: "arrow", - values: arrowheadTypes2 -}); -var arrowShapeProps2 = { - labelColor: DefaultLabelColorStyle2, - color: DefaultColorStyle2, - fill: DefaultFillStyle2, - dash: DefaultDashStyle2, - size: DefaultSizeStyle2, - arrowheadStart: ArrowShapeArrowheadStartStyle2, - arrowheadEnd: ArrowShapeArrowheadEndStyle2, - font: DefaultFontStyle2, - start: vecModelValidator2, - end: vecModelValidator2, - bend: validation_exports.number, - text: validation_exports.string, - labelPosition: validation_exports.number, - scale: validation_exports.nonZeroNumber -}; -var arrowShapeVersions2 = createShapePropsMigrationIds2("arrow", { - AddLabelColor: 1, - AddIsPrecise: 2, - AddLabelPosition: 3, - ExtractBindings: 4, - AddScale: 5 -}); -function propsMigration2(migration) { - return createPropsMigration2("shape", "arrow", migration); -} -var arrowShapeMigrations2 = createMigrationSequence({ - sequenceId: "com.tldraw.shape.arrow", - retroactive: false, - sequence: [ - propsMigration2({ - id: arrowShapeVersions2.AddLabelColor, - up: (props) => { - props.labelColor = "black"; - }, - down: "retired" - }), - propsMigration2({ - id: arrowShapeVersions2.AddIsPrecise, - up: ({ start, end }) => { - if (start.type === "binding") { - start.isPrecise = !(start.normalizedAnchor.x === 0.5 && start.normalizedAnchor.y === 0.5); - } - if (end.type === "binding") { - end.isPrecise = !(end.normalizedAnchor.x === 0.5 && end.normalizedAnchor.y === 0.5); - } - }, - down: ({ start, end }) => { - if (start.type === "binding") { - if (!start.isPrecise) { - start.normalizedAnchor = { x: 0.5, y: 0.5 }; - } - delete start.isPrecise; - } - if (end.type === "binding") { - if (!end.isPrecise) { - end.normalizedAnchor = { x: 0.5, y: 0.5 }; - } - delete end.isPrecise; - } - } - }), - propsMigration2({ - id: arrowShapeVersions2.AddLabelPosition, - up: (props) => { - props.labelPosition = 0.5; - }, - down: (props) => { - delete props.labelPosition; - } - }), - { - id: arrowShapeVersions2.ExtractBindings, - scope: "store", - up: (oldStore) => { - const arrows = Object.values(oldStore).filter( - (r2) => r2.typeName === "shape" && r2.type === "arrow" - ); - for (const arrow of arrows) { - const { start, end } = arrow.props; - if (start.type === "binding") { - const id = createBindingId2(); - const binding = { - typeName: "binding", - id, - type: "arrow", - fromId: arrow.id, - toId: start.boundShapeId, - meta: {}, - props: { - terminal: "start", - normalizedAnchor: start.normalizedAnchor, - isExact: start.isExact, - isPrecise: start.isPrecise - } - }; - oldStore[id] = binding; - arrow.props.start = { x: 0, y: 0 }; - } else { - delete arrow.props.start.type; - } - if (end.type === "binding") { - const id = createBindingId2(); - const binding = { - typeName: "binding", - id, - type: "arrow", - fromId: arrow.id, - toId: end.boundShapeId, - meta: {}, - props: { - terminal: "end", - normalizedAnchor: end.normalizedAnchor, - isExact: end.isExact, - isPrecise: end.isPrecise - } - }; - oldStore[id] = binding; - arrow.props.end = { x: 0, y: 0 }; - } else { - delete arrow.props.end.type; - } - } - } - }, - propsMigration2({ - id: arrowShapeVersions2.AddScale, - up: (props) => { - props.scale = 1; - }, - down: (props) => { - delete props.scale; - } - }) - ] -}); - -// node_modules/@tldraw/tlschema/dist-esm/bindings/TLArrowBinding.mjs -var arrowBindingProps2 = { - terminal: validation_exports.literalEnum("start", "end"), - normalizedAnchor: vecModelValidator2, - isExact: validation_exports.boolean, - isPrecise: validation_exports.boolean -}; -var arrowBindingMigrations2 = createBindingPropsMigrationSequence2({ - sequence: [{ dependsOn: [arrowShapeVersions2.ExtractBindings] }] -}); - -// node_modules/@tldraw/tlschema/dist-esm/createPresenceStateDerivation.mjs -init_checked_fetch(); -init_modules_watch_stub(); - -// node_modules/@tldraw/tlschema/dist-esm/records/TLCamera.mjs -init_checked_fetch(); -init_modules_watch_stub(); -var cameraValidator2 = validation_exports.model( - "camera", - validation_exports.object({ - typeName: validation_exports.literal("camera"), - id: idValidator2("camera"), - x: validation_exports.number, - y: validation_exports.number, - z: validation_exports.number, - meta: validation_exports.jsonValue - }) -); -var cameraVersions2 = createMigrationIds("com.tldraw.camera", { - AddMeta: 1 -}); -var cameraMigrations2 = createRecordMigrationSequence({ - sequenceId: "com.tldraw.camera", - recordType: "camera", - sequence: [ - { - id: cameraVersions2.AddMeta, - up: (record) => { - ; - record.meta = {}; - } - } - ] -}); -var CameraRecordType2 = createRecordType("camera", { - validator: cameraValidator2, - scope: "session" -}).withDefaultProperties( - () => ({ - x: 0, - y: 0, - z: 1, - meta: {} - }) -); - -// node_modules/@tldraw/tlschema/dist-esm/records/TLInstance.mjs -init_checked_fetch(); -init_modules_watch_stub(); - -// node_modules/@tldraw/tlschema/dist-esm/misc/TLCursor.mjs -init_checked_fetch(); -init_modules_watch_stub(); -var TL_CURSOR_TYPES2 = /* @__PURE__ */ new Set([ - "none", - "default", - "pointer", - "cross", - "grab", - "rotate", - "grabbing", - "resize-edge", - "resize-corner", - "text", - "move", - "ew-resize", - "ns-resize", - "nesw-resize", - "nwse-resize", - "nesw-rotate", - "nwse-rotate", - "swne-rotate", - "senw-rotate", - "zoom-in", - "zoom-out" -]); -var cursorTypeValidator2 = validation_exports.setEnum(TL_CURSOR_TYPES2); -var cursorValidator2 = validation_exports.object({ - type: cursorTypeValidator2, - rotation: validation_exports.number -}); - -// node_modules/@tldraw/tlschema/dist-esm/misc/TLScribble.mjs -init_checked_fetch(); -init_modules_watch_stub(); - -// node_modules/@tldraw/tlschema/dist-esm/misc/TLColor.mjs -init_checked_fetch(); -init_modules_watch_stub(); -var TL_CANVAS_UI_COLOR_TYPES2 = /* @__PURE__ */ new Set([ - "accent", - "white", - "black", - "selection-stroke", - "selection-fill", - "laser", - "muted-1" -]); -var canvasUiColorTypeValidator2 = validation_exports.setEnum(TL_CANVAS_UI_COLOR_TYPES2); - -// node_modules/@tldraw/tlschema/dist-esm/misc/TLScribble.mjs -var TL_SCRIBBLE_STATES2 = /* @__PURE__ */ new Set(["starting", "paused", "active", "stopping"]); -var scribbleValidator2 = validation_exports.object({ - id: validation_exports.string, - points: validation_exports.arrayOf(vecModelValidator2), - size: validation_exports.positiveNumber, - color: canvasUiColorTypeValidator2, - opacity: validation_exports.number, - state: validation_exports.setEnum(TL_SCRIBBLE_STATES2), - delay: validation_exports.number, - shrink: validation_exports.number, - taper: validation_exports.boolean -}); - -// node_modules/@tldraw/tlschema/dist-esm/records/TLPage.mjs -init_checked_fetch(); -init_modules_watch_stub(); -var pageIdValidator2 = idValidator2("page"); -var pageValidator2 = validation_exports.model( - "page", - validation_exports.object({ - typeName: validation_exports.literal("page"), - id: pageIdValidator2, - name: validation_exports.string, - index: validation_exports.indexKey, - meta: validation_exports.jsonValue - }) -); -var pageVersions2 = createMigrationIds("com.tldraw.page", { - AddMeta: 1 -}); -var pageMigrations2 = createRecordMigrationSequence({ - sequenceId: "com.tldraw.page", - recordType: "page", - sequence: [ - { - id: pageVersions2.AddMeta, - up: (record) => { - record.meta = {}; - } - } - ] -}); -var PageRecordType2 = createRecordType("page", { - validator: pageValidator2, - scope: "document" -}).withDefaultProperties(() => ({ - meta: {} -})); - -// node_modules/@tldraw/tlschema/dist-esm/records/TLInstance.mjs -var instanceIdValidator2 = idValidator2("instance"); -function createInstanceRecordType2(stylesById) { - const stylesForNextShapeValidators = {}; - for (const [id, style] of stylesById) { - stylesForNextShapeValidators[id] = validation_exports.optional(style); - } - const instanceTypeValidator = validation_exports.model( - "instance", - validation_exports.object({ - typeName: validation_exports.literal("instance"), - id: idValidator2("instance"), - currentPageId: pageIdValidator2, - followingUserId: validation_exports.string.nullable(), - brush: boxModelValidator2.nullable(), - opacityForNextShape: opacityValidator2, - stylesForNextShape: validation_exports.object(stylesForNextShapeValidators), - cursor: cursorValidator2, - scribbles: validation_exports.arrayOf(scribbleValidator2), - isFocusMode: validation_exports.boolean, - isDebugMode: validation_exports.boolean, - isToolLocked: validation_exports.boolean, - exportBackground: validation_exports.boolean, - screenBounds: boxModelValidator2, - insets: validation_exports.arrayOf(validation_exports.boolean), - zoomBrush: boxModelValidator2.nullable(), - isPenMode: validation_exports.boolean, - isGridMode: validation_exports.boolean, - chatMessage: validation_exports.string, - isChatting: validation_exports.boolean, - highlightedUserIds: validation_exports.arrayOf(validation_exports.string), - isFocused: validation_exports.boolean, - devicePixelRatio: validation_exports.number, - isCoarsePointer: validation_exports.boolean, - isHoveringCanvas: validation_exports.boolean.nullable(), - openMenus: validation_exports.arrayOf(validation_exports.string), - isChangingStyle: validation_exports.boolean, - isReadonly: validation_exports.boolean, - meta: validation_exports.jsonValue, - duplicateProps: validation_exports.object({ - shapeIds: validation_exports.arrayOf(idValidator2("shape")), - offset: validation_exports.object({ - x: validation_exports.number, - y: validation_exports.number - }) - }).nullable() - }) - ); - return createRecordType("instance", { - validator: instanceTypeValidator, - scope: "session", - ephemeralKeys: { - currentPageId: false, - meta: false, - followingUserId: true, - opacityForNextShape: true, - stylesForNextShape: true, - brush: true, - cursor: true, - scribbles: true, - isFocusMode: true, - isDebugMode: true, - isToolLocked: true, - exportBackground: true, - screenBounds: true, - insets: true, - zoomBrush: true, - isPenMode: true, - isGridMode: true, - chatMessage: true, - isChatting: true, - highlightedUserIds: true, - isFocused: true, - devicePixelRatio: true, - isCoarsePointer: true, - isHoveringCanvas: true, - openMenus: true, - isChangingStyle: true, - isReadonly: true, - duplicateProps: true - } - }).withDefaultProperties( - () => ({ - followingUserId: null, - opacityForNextShape: 1, - stylesForNextShape: {}, - brush: null, - scribbles: [], - cursor: { - type: "default", - rotation: 0 - }, - isFocusMode: false, - exportBackground: false, - isDebugMode: false, - isToolLocked: false, - screenBounds: { x: 0, y: 0, w: 1080, h: 720 }, - insets: [false, false, false, false], - zoomBrush: null, - isGridMode: false, - isPenMode: false, - chatMessage: "", - isChatting: false, - highlightedUserIds: [], - isFocused: false, - devicePixelRatio: typeof window === "undefined" ? 1 : window.devicePixelRatio, - isCoarsePointer: false, - isHoveringCanvas: null, - openMenus: [], - isChangingStyle: false, - isReadonly: false, - meta: {}, - duplicateProps: null - }) - ); -} -var instanceVersions2 = createMigrationIds("com.tldraw.instance", { - AddTransparentExportBgs: 1, - RemoveDialog: 2, - AddToolLockMode: 3, - RemoveExtraPropsForNextShape: 4, - AddLabelColor: 5, - AddFollowingUserId: 6, - RemoveAlignJustify: 7, - AddZoom: 8, - AddVerticalAlign: 9, - AddScribbleDelay: 10, - RemoveUserId: 11, - AddIsPenModeAndIsGridMode: 12, - HoistOpacity: 13, - AddChat: 14, - AddHighlightedUserIds: 15, - ReplacePropsForNextShapeWithStylesForNextShape: 16, - AddMeta: 17, - RemoveCursorColor: 18, - AddLonelyProperties: 19, - ReadOnlyReadonly: 20, - AddHoveringCanvas: 21, - AddScribbles: 22, - AddInset: 23, - AddDuplicateProps: 24, - RemoveCanMoveCamera: 25 -}); -var instanceMigrations2 = createRecordMigrationSequence({ - sequenceId: "com.tldraw.instance", - recordType: "instance", - sequence: [ - { - id: instanceVersions2.AddTransparentExportBgs, - up: (instance) => { - return { ...instance, exportBackground: true }; - } - }, - { - id: instanceVersions2.RemoveDialog, - up: ({ dialog: _, ...instance }) => { - return instance; - } - }, - { - id: instanceVersions2.AddToolLockMode, - up: (instance) => { - return { ...instance, isToolLocked: false }; - } - }, - { - id: instanceVersions2.RemoveExtraPropsForNextShape, - up: ({ propsForNextShape, ...instance }) => { - return { - ...instance, - propsForNextShape: Object.fromEntries( - Object.entries(propsForNextShape).filter( - ([key]) => [ - "color", - "labelColor", - "dash", - "fill", - "size", - "font", - "align", - "verticalAlign", - "icon", - "geo", - "arrowheadStart", - "arrowheadEnd", - "spline" - ].includes(key) - ) - ) - }; - } - }, - { - id: instanceVersions2.AddLabelColor, - up: ({ propsForNextShape, ...instance }) => { - return { - ...instance, - propsForNextShape: { - ...propsForNextShape, - labelColor: "black" - } - }; - } - }, - { - id: instanceVersions2.AddFollowingUserId, - up: (instance) => { - return { ...instance, followingUserId: null }; - } - }, - { - id: instanceVersions2.RemoveAlignJustify, - up: (instance) => { - let newAlign = instance.propsForNextShape.align; - if (newAlign === "justify") { - newAlign = "start"; - } - return { - ...instance, - propsForNextShape: { - ...instance.propsForNextShape, - align: newAlign - } - }; - } - }, - { - id: instanceVersions2.AddZoom, - up: (instance) => { - return { ...instance, zoomBrush: null }; - } - }, - { - id: instanceVersions2.AddVerticalAlign, - up: (instance) => { - return { - ...instance, - propsForNextShape: { - ...instance.propsForNextShape, - verticalAlign: "middle" - } - }; - } - }, - { - id: instanceVersions2.AddScribbleDelay, - up: (instance) => { - if (instance.scribble !== null) { - return { ...instance, scribble: { ...instance.scribble, delay: 0 } }; - } - return { ...instance }; - } - }, - { - id: instanceVersions2.RemoveUserId, - up: ({ userId: _, ...instance }) => { - return instance; - } - }, - { - id: instanceVersions2.AddIsPenModeAndIsGridMode, - up: (instance) => { - return { ...instance, isPenMode: false, isGridMode: false }; - } - }, - { - id: instanceVersions2.HoistOpacity, - up: ({ propsForNextShape: { opacity, ...propsForNextShape }, ...instance }) => { - return { ...instance, opacityForNextShape: Number(opacity ?? "1"), propsForNextShape }; - } - }, - { - id: instanceVersions2.AddChat, - up: (instance) => { - return { ...instance, chatMessage: "", isChatting: false }; - } - }, - { - id: instanceVersions2.AddHighlightedUserIds, - up: (instance) => { - return { ...instance, highlightedUserIds: [] }; - } - }, - { - id: instanceVersions2.ReplacePropsForNextShapeWithStylesForNextShape, - up: ({ propsForNextShape: _, ...instance }) => { - return { ...instance, stylesForNextShape: {} }; - } - }, - { - id: instanceVersions2.AddMeta, - up: (record) => { - return { - ...record, - meta: {} - }; - } - }, - { - id: instanceVersions2.RemoveCursorColor, - up: (record) => { - const { color: _, ...cursor } = record.cursor; - return { - ...record, - cursor - }; - } - }, - { - id: instanceVersions2.AddLonelyProperties, - up: (record) => { - return { - ...record, - canMoveCamera: true, - isFocused: false, - devicePixelRatio: 1, - isCoarsePointer: false, - openMenus: [], - isChangingStyle: false, - isReadOnly: false - }; - } - }, - { - id: instanceVersions2.ReadOnlyReadonly, - up: ({ isReadOnly: _isReadOnly, ...record }) => { - return { - ...record, - isReadonly: _isReadOnly - }; - } - }, - { - id: instanceVersions2.AddHoveringCanvas, - up: (record) => { - return { - ...record, - isHoveringCanvas: null - }; - } - }, - { - id: instanceVersions2.AddScribbles, - up: ({ scribble: _, ...record }) => { - return { - ...record, - scribbles: [] - }; - } - }, - { - id: instanceVersions2.AddInset, - up: (record) => { - return { - ...record, - insets: [false, false, false, false] - }; - }, - down: ({ insets: _, ...record }) => { - return { - ...record - }; - } - }, - { - id: instanceVersions2.AddDuplicateProps, - up: (record) => { - return { - ...record, - duplicateProps: null - }; - }, - down: ({ duplicateProps: _, ...record }) => { - return { - ...record - }; - } - }, - { - id: instanceVersions2.RemoveCanMoveCamera, - up: ({ canMoveCamera: _, ...record }) => { - return { - ...record - }; - }, - down: (instance) => { - return { ...instance, canMoveCamera: true }; - } - } - ] -}); -var TLINSTANCE_ID2 = "instance:instance"; - -// node_modules/@tldraw/tlschema/dist-esm/records/TLPageState.mjs -init_checked_fetch(); -init_modules_watch_stub(); -var instancePageStateValidator2 = validation_exports.model( - "instance_page_state", - validation_exports.object({ - typeName: validation_exports.literal("instance_page_state"), - id: idValidator2("instance_page_state"), - pageId: pageIdValidator2, - selectedShapeIds: validation_exports.arrayOf(shapeIdValidator2), - hintingShapeIds: validation_exports.arrayOf(shapeIdValidator2), - erasingShapeIds: validation_exports.arrayOf(shapeIdValidator2), - hoveredShapeId: shapeIdValidator2.nullable(), - editingShapeId: shapeIdValidator2.nullable(), - croppingShapeId: shapeIdValidator2.nullable(), - focusedGroupId: shapeIdValidator2.nullable(), - meta: validation_exports.jsonValue - }) -); -var instancePageStateVersions2 = createMigrationIds("com.tldraw.instance_page_state", { - AddCroppingId: 1, - RemoveInstanceIdAndCameraId: 2, - AddMeta: 3, - RenameProperties: 4, - RenamePropertiesAgain: 5 -}); -var instancePageStateMigrations2 = createRecordMigrationSequence({ - sequenceId: "com.tldraw.instance_page_state", - recordType: "instance_page_state", - sequence: [ - { - id: instancePageStateVersions2.AddCroppingId, - up(instance) { - instance.croppingShapeId = null; - } - }, - { - id: instancePageStateVersions2.RemoveInstanceIdAndCameraId, - up(instance) { - delete instance.instanceId; - delete instance.cameraId; - } - }, - { - id: instancePageStateVersions2.AddMeta, - up: (record) => { - record.meta = {}; - } - }, - { - id: instancePageStateVersions2.RenameProperties, - // this migration is cursed: it was written wrong and doesn't do anything. - // rather than replace it, I've added another migration below that fixes it. - up: (_record) => { - }, - down: (_record) => { - } - }, - { - id: instancePageStateVersions2.RenamePropertiesAgain, - up: (record) => { - record.selectedShapeIds = record.selectedIds; - delete record.selectedIds; - record.hintingShapeIds = record.hintingIds; - delete record.hintingIds; - record.erasingShapeIds = record.erasingIds; - delete record.erasingIds; - record.hoveredShapeId = record.hoveredId; - delete record.hoveredId; - record.editingShapeId = record.editingId; - delete record.editingId; - record.croppingShapeId = record.croppingShapeId ?? record.croppingId ?? null; - delete record.croppingId; - record.focusedGroupId = record.focusLayerId; - delete record.focusLayerId; - }, - down: (record) => { - record.selectedIds = record.selectedShapeIds; - delete record.selectedShapeIds; - record.hintingIds = record.hintingShapeIds; - delete record.hintingShapeIds; - record.erasingIds = record.erasingShapeIds; - delete record.erasingShapeIds; - record.hoveredId = record.hoveredShapeId; - delete record.hoveredShapeId; - record.editingId = record.editingShapeId; - delete record.editingShapeId; - record.croppingId = record.croppingShapeId; - delete record.croppingShapeId; - record.focusLayerId = record.focusedGroupId; - delete record.focusedGroupId; - } - } - ] -}); -var InstancePageStateRecordType2 = createRecordType( - "instance_page_state", - { - validator: instancePageStateValidator2, - scope: "session", - ephemeralKeys: { - pageId: false, - selectedShapeIds: false, - editingShapeId: false, - croppingShapeId: false, - meta: false, - hintingShapeIds: true, - erasingShapeIds: true, - hoveredShapeId: true, - focusedGroupId: true - } - } -).withDefaultProperties( - () => ({ - editingShapeId: null, - croppingShapeId: null, - selectedShapeIds: [], - hoveredShapeId: null, - erasingShapeIds: [], - hintingShapeIds: [], - focusedGroupId: null, - meta: {} - }) -); - -// node_modules/@tldraw/tlschema/dist-esm/records/TLPointer.mjs -init_checked_fetch(); -init_modules_watch_stub(); -var pointerValidator2 = validation_exports.model( - "pointer", - validation_exports.object({ - typeName: validation_exports.literal("pointer"), - id: idValidator2("pointer"), - x: validation_exports.number, - y: validation_exports.number, - lastActivityTimestamp: validation_exports.number, - meta: validation_exports.jsonValue - }) -); -var pointerVersions2 = createMigrationIds("com.tldraw.pointer", { - AddMeta: 1 -}); -var pointerMigrations2 = createRecordMigrationSequence({ - sequenceId: "com.tldraw.pointer", - recordType: "pointer", - sequence: [ - { - id: pointerVersions2.AddMeta, - up: (record) => { - record.meta = {}; - } - } - ] -}); -var PointerRecordType2 = createRecordType("pointer", { - validator: pointerValidator2, - scope: "session" -}).withDefaultProperties( - () => ({ - x: 0, - y: 0, - lastActivityTimestamp: 0, - meta: {} - }) -); -var TLPOINTER_ID2 = PointerRecordType2.createId("pointer"); - -// node_modules/@tldraw/tlschema/dist-esm/records/TLPresence.mjs -init_checked_fetch(); -init_modules_watch_stub(); -var instancePresenceValidator2 = validation_exports.model( - "instance_presence", - validation_exports.object({ - typeName: validation_exports.literal("instance_presence"), - id: idValidator2("instance_presence"), - userId: validation_exports.string, - userName: validation_exports.string, - lastActivityTimestamp: validation_exports.number, - followingUserId: validation_exports.string.nullable(), - cursor: validation_exports.object({ - x: validation_exports.number, - y: validation_exports.number, - type: cursorTypeValidator2, - rotation: validation_exports.number - }), - color: validation_exports.string, - camera: validation_exports.object({ - x: validation_exports.number, - y: validation_exports.number, - z: validation_exports.number - }), - screenBounds: boxModelValidator2, - selectedShapeIds: validation_exports.arrayOf(idValidator2("shape")), - currentPageId: idValidator2("page"), - brush: boxModelValidator2.nullable(), - scribbles: validation_exports.arrayOf(scribbleValidator2), - chatMessage: validation_exports.string, - meta: validation_exports.jsonValue - }) -); -var instancePresenceVersions2 = createMigrationIds("com.tldraw.instance_presence", { - AddScribbleDelay: 1, - RemoveInstanceId: 2, - AddChatMessage: 3, - AddMeta: 4, - RenameSelectedShapeIds: 5 -}); -var instancePresenceMigrations2 = createRecordMigrationSequence({ - sequenceId: "com.tldraw.instance_presence", - recordType: "instance_presence", - sequence: [ - { - id: instancePresenceVersions2.AddScribbleDelay, - up: (instance) => { - if (instance.scribble !== null) { - instance.scribble.delay = 0; - } - } - }, - { - id: instancePresenceVersions2.RemoveInstanceId, - up: (instance) => { - delete instance.instanceId; - } - }, - { - id: instancePresenceVersions2.AddChatMessage, - up: (instance) => { - instance.chatMessage = ""; - } - }, - { - id: instancePresenceVersions2.AddMeta, - up: (record) => { - record.meta = {}; - } - }, - { - id: instancePresenceVersions2.RenameSelectedShapeIds, - up: (_record) => { - } - } - ] -}); -var InstancePresenceRecordType2 = createRecordType( - "instance_presence", - { - validator: instancePresenceValidator2, - scope: "presence" - } -).withDefaultProperties(() => ({ - lastActivityTimestamp: 0, - followingUserId: null, - color: "#FF0000", - camera: { - x: 0, - y: 0, - z: 1 - }, - cursor: { - x: 0, - y: 0, - type: "default", - rotation: 0 - }, - screenBounds: { - x: 0, - y: 0, - w: 1, - h: 1 - }, - selectedShapeIds: [], - brush: null, - scribbles: [], - chatMessage: "", - meta: {} -})); - -// node_modules/@tldraw/tlschema/dist-esm/createTLSchema.mjs -init_checked_fetch(); -init_modules_watch_stub(); - -// node_modules/@tldraw/tlschema/dist-esm/TLStore.mjs -init_checked_fetch(); -init_modules_watch_stub(); - -// node_modules/@tldraw/tlschema/dist-esm/records/TLDocument.mjs -init_checked_fetch(); -init_modules_watch_stub(); -var documentValidator2 = validation_exports.model( - "document", - validation_exports.object({ - typeName: validation_exports.literal("document"), - id: validation_exports.literal("document:document"), - gridSize: validation_exports.number, - name: validation_exports.string, - meta: validation_exports.jsonValue - }) -); -var documentVersions2 = createMigrationIds("com.tldraw.document", { - AddName: 1, - AddMeta: 2 -}); -var documentMigrations2 = createRecordMigrationSequence({ - sequenceId: "com.tldraw.document", - recordType: "document", - sequence: [ - { - id: documentVersions2.AddName, - up: (document2) => { - ; - document2.name = ""; - }, - down: (document2) => { - delete document2.name; - } - }, - { - id: documentVersions2.AddMeta, - up: (record) => { - ; - record.meta = {}; - } - } - ] -}); -var DocumentRecordType2 = createRecordType("document", { - validator: documentValidator2, - scope: "document" -}).withDefaultProperties( - () => ({ - gridSize: 10, - name: "", - meta: {} - }) -); -var TLDOCUMENT_ID2 = DocumentRecordType2.createId("document"); - -// node_modules/@tldraw/tlschema/dist-esm/TLStore.mjs -function sortByIndex3(a2, b) { - if (a2.index < b.index) { - return -1; - } else if (a2.index > b.index) { - return 1; - } - return 0; -} -function redactRecordForErrorReporting2(record) { - if (record.typeName === "asset") { - if ("src" in record) { - record.src = ""; - } - if ("src" in record.props) { - record.props.src = ""; - } - } -} -var onValidationFailure2 = ({ error, phase, record, recordBefore }) => { - const isExistingValidationIssue = ( - // if we're initializing the store for the first time, we should - // allow invalid records so people can load old buggy data: - phase === "initialize" - ); - annotateError(error, { - tags: { - origin: "store.validateRecord", - storePhase: phase, - isExistingValidationIssue - }, - extras: { - recordBefore: recordBefore ? redactRecordForErrorReporting2(structuredClone(recordBefore)) : void 0, - recordAfter: redactRecordForErrorReporting2(structuredClone(record)) - } - }); - throw error; -}; -function getDefaultPages2() { - return [ - PageRecordType2.create({ - id: "page:page", - name: "Page 1", - index: "a1", - meta: {} - }) - ]; -} -function createIntegrityChecker2(store) { - const $pageIds = store.query.ids("page"); - const ensureStoreIsUsable = () => { - if (!store.has(TLDOCUMENT_ID2)) { - store.put([DocumentRecordType2.create({ id: TLDOCUMENT_ID2, name: store.props.defaultName })]); - return ensureStoreIsUsable(); - } - if (!store.has(TLPOINTER_ID2)) { - store.put([PointerRecordType2.create({ id: TLPOINTER_ID2 })]); - return ensureStoreIsUsable(); - } - const pageIds = $pageIds.get(); - if (pageIds.size === 0) { - store.put(getDefaultPages2()); - return ensureStoreIsUsable(); - } - const getFirstPageId = () => [...pageIds].map((id) => store.get(id)).sort(sortByIndex3)[0].id; - const instanceState = store.get(TLINSTANCE_ID2); - if (!instanceState) { - store.put([ - store.schema.types.instance.create({ - id: TLINSTANCE_ID2, - currentPageId: getFirstPageId(), - exportBackground: true - }) - ]); - return ensureStoreIsUsable(); - } else if (!pageIds.has(instanceState.currentPageId)) { - store.put([{ ...instanceState, currentPageId: getFirstPageId() }]); - return ensureStoreIsUsable(); - } - const missingPageStateIds = /* @__PURE__ */ new Set(); - const missingCameraIds = /* @__PURE__ */ new Set(); - for (const id of pageIds) { - const pageStateId = InstancePageStateRecordType2.createId(id); - if (!store.has(pageStateId)) { - missingPageStateIds.add(pageStateId); - } - const cameraId = CameraRecordType2.createId(id); - if (!store.has(cameraId)) { - missingCameraIds.add(cameraId); - } - } - if (missingPageStateIds.size > 0) { - store.put( - [...missingPageStateIds].map( - (id) => InstancePageStateRecordType2.create({ - id, - pageId: InstancePageStateRecordType2.parseId(id) - }) - ) - ); - } - if (missingCameraIds.size > 0) { - store.put([...missingCameraIds].map((id) => CameraRecordType2.create({ id }))); - } - }; - return ensureStoreIsUsable; -} - -// node_modules/@tldraw/tlschema/dist-esm/assets/TLBookmarkAsset.mjs -init_checked_fetch(); -init_modules_watch_stub(); -var bookmarkAssetValidator2 = createAssetValidator2( - "bookmark", - validation_exports.object({ - title: validation_exports.string, - description: validation_exports.string, - image: validation_exports.string, - favicon: validation_exports.string, - src: validation_exports.srcUrl.nullable() - }) -); -var Versions13 = createMigrationIds("com.tldraw.asset.bookmark", { - MakeUrlsValid: 1, - AddFavicon: 2 -}); -var bookmarkAssetMigrations2 = createRecordMigrationSequence({ - sequenceId: "com.tldraw.asset.bookmark", - recordType: "asset", - filter: (asset) => asset.type === "bookmark", - sequence: [ - { - id: Versions13.MakeUrlsValid, - up: (asset) => { - if (!validation_exports.srcUrl.isValid(asset.props.src)) { - asset.props.src = ""; - } - }, - down: (_asset) => { - } - }, - { - id: Versions13.AddFavicon, - up: (asset) => { - if (!validation_exports.srcUrl.isValid(asset.props.favicon)) { - asset.props.favicon = ""; - } - }, - down: (asset) => { - delete asset.props.favicon; - } - } - ] -}); - -// node_modules/@tldraw/tlschema/dist-esm/assets/TLImageAsset.mjs -init_checked_fetch(); -init_modules_watch_stub(); -var imageAssetValidator2 = createAssetValidator2( - "image", - validation_exports.object({ - w: validation_exports.number, - h: validation_exports.number, - name: validation_exports.string, - isAnimated: validation_exports.boolean, - mimeType: validation_exports.string.nullable(), - src: validation_exports.srcUrl.nullable(), - fileSize: validation_exports.nonZeroNumber.optional() - }) -); -var Versions14 = createMigrationIds("com.tldraw.asset.image", { - AddIsAnimated: 1, - RenameWidthHeight: 2, - MakeUrlsValid: 3, - AddFileSize: 4, - MakeFileSizeOptional: 5 -}); -var imageAssetMigrations2 = createRecordMigrationSequence({ - sequenceId: "com.tldraw.asset.image", - recordType: "asset", - filter: (asset) => asset.type === "image", - sequence: [ - { - id: Versions14.AddIsAnimated, - up: (asset) => { - asset.props.isAnimated = false; - }, - down: (asset) => { - delete asset.props.isAnimated; - } - }, - { - id: Versions14.RenameWidthHeight, - up: (asset) => { - asset.props.w = asset.props.width; - asset.props.h = asset.props.height; - delete asset.props.width; - delete asset.props.height; - }, - down: (asset) => { - asset.props.width = asset.props.w; - asset.props.height = asset.props.h; - delete asset.props.w; - delete asset.props.h; - } - }, - { - id: Versions14.MakeUrlsValid, - up: (asset) => { - if (!validation_exports.srcUrl.isValid(asset.props.src)) { - asset.props.src = ""; - } - }, - down: (_asset) => { - } - }, - { - id: Versions14.AddFileSize, - up: (asset) => { - asset.props.fileSize = -1; - }, - down: (asset) => { - delete asset.props.fileSize; - } - }, - { - id: Versions14.MakeFileSizeOptional, - up: (asset) => { - if (asset.props.fileSize === -1) { - asset.props.fileSize = void 0; - } - }, - down: (asset) => { - if (asset.props.fileSize === void 0) { - asset.props.fileSize = -1; - } - } - } - ] -}); - -// node_modules/@tldraw/tlschema/dist-esm/assets/TLVideoAsset.mjs -init_checked_fetch(); -init_modules_watch_stub(); -var videoAssetValidator2 = createAssetValidator2( - "video", - validation_exports.object({ - w: validation_exports.number, - h: validation_exports.number, - name: validation_exports.string, - isAnimated: validation_exports.boolean, - mimeType: validation_exports.string.nullable(), - src: validation_exports.srcUrl.nullable(), - fileSize: validation_exports.number.optional() - }) -); -var Versions15 = createMigrationIds("com.tldraw.asset.video", { - AddIsAnimated: 1, - RenameWidthHeight: 2, - MakeUrlsValid: 3, - AddFileSize: 4, - MakeFileSizeOptional: 5 -}); -var videoAssetMigrations2 = createRecordMigrationSequence({ - sequenceId: "com.tldraw.asset.video", - recordType: "asset", - filter: (asset) => asset.type === "video", - sequence: [ - { - id: Versions15.AddIsAnimated, - up: (asset) => { - asset.props.isAnimated = false; - }, - down: (asset) => { - delete asset.props.isAnimated; - } - }, - { - id: Versions15.RenameWidthHeight, - up: (asset) => { - asset.props.w = asset.props.width; - asset.props.h = asset.props.height; - delete asset.props.width; - delete asset.props.height; - }, - down: (asset) => { - asset.props.width = asset.props.w; - asset.props.height = asset.props.h; - delete asset.props.w; - delete asset.props.h; - } - }, - { - id: Versions15.MakeUrlsValid, - up: (asset) => { - if (!validation_exports.srcUrl.isValid(asset.props.src)) { - asset.props.src = ""; - } - }, - down: (_asset) => { - } - }, - { - id: Versions15.AddFileSize, - up: (asset) => { - asset.props.fileSize = -1; - }, - down: (asset) => { - delete asset.props.fileSize; - } - }, - { - id: Versions15.MakeFileSizeOptional, - up: (asset) => { - if (asset.props.fileSize === -1) { - asset.props.fileSize = void 0; - } - }, - down: (asset) => { - if (asset.props.fileSize === void 0) { - asset.props.fileSize = -1; - } - } - } - ] -}); - -// node_modules/@tldraw/tlschema/dist-esm/records/TLAsset.mjs -init_checked_fetch(); -init_modules_watch_stub(); -var assetValidator2 = validation_exports.model( - "asset", - validation_exports.union("type", { - image: imageAssetValidator2, - video: videoAssetValidator2, - bookmark: bookmarkAssetValidator2 - }) -); -var assetVersions2 = createMigrationIds("com.tldraw.asset", { - AddMeta: 1 -}); -var assetMigrations2 = createRecordMigrationSequence({ - sequenceId: "com.tldraw.asset", - recordType: "asset", - sequence: [ - { - id: assetVersions2.AddMeta, - up: (record) => { - ; - record.meta = {}; - } - } - ] -}); -var AssetRecordType2 = createRecordType("asset", { - validator: assetValidator2, - scope: "document" -}).withDefaultProperties(() => ({ - meta: {} -})); - -// node_modules/@tldraw/tlschema/dist-esm/shapes/TLBookmarkShape.mjs -init_checked_fetch(); -init_modules_watch_stub(); -var bookmarkShapeProps2 = { - w: validation_exports.nonZeroNumber, - h: validation_exports.nonZeroNumber, - assetId: assetIdValidator2.nullable(), - url: validation_exports.linkUrl -}; -var Versions16 = createShapePropsMigrationIds2("bookmark", { - NullAssetId: 1, - MakeUrlsValid: 2 -}); -var bookmarkShapeMigrations2 = createShapePropsMigrationSequence2({ - sequence: [ - { - id: Versions16.NullAssetId, - up: (props) => { - if (props.assetId === void 0) { - props.assetId = null; - } - }, - down: "retired" - }, - { - id: Versions16.MakeUrlsValid, - up: (props) => { - if (!validation_exports.linkUrl.isValid(props.url)) { - props.url = ""; - } - }, - down: (_props) => { - } - } - ] -}); - -// node_modules/@tldraw/tlschema/dist-esm/shapes/TLDrawShape.mjs -init_checked_fetch(); -init_modules_watch_stub(); -var DrawShapeSegment2 = validation_exports.object({ - type: validation_exports.literalEnum("free", "straight"), - points: validation_exports.arrayOf(vecModelValidator2) -}); -var drawShapeProps2 = { - color: DefaultColorStyle2, - fill: DefaultFillStyle2, - dash: DefaultDashStyle2, - size: DefaultSizeStyle2, - segments: validation_exports.arrayOf(DrawShapeSegment2), - isComplete: validation_exports.boolean, - isClosed: validation_exports.boolean, - isPen: validation_exports.boolean, - scale: validation_exports.nonZeroNumber -}; -var Versions17 = createShapePropsMigrationIds2("draw", { - AddInPen: 1, - AddScale: 2 -}); -var drawShapeMigrations2 = createShapePropsMigrationSequence2({ - sequence: [ - { - id: Versions17.AddInPen, - up: (props) => { - const { points } = props.segments[0]; - if (points.length === 0) { - props.isPen = false; - return; - } - let isPen = !(points[0].z === 0 || points[0].z === 0.5); - if (points[1]) { - isPen = isPen && !(points[1].z === 0 || points[1].z === 0.5); - } - props.isPen = isPen; - }, - down: "retired" - }, - { - id: Versions17.AddScale, - up: (props) => { - props.scale = 1; - }, - down: (props) => { - delete props.scale; - } - } - ] -}); - -// node_modules/@tldraw/tlschema/dist-esm/shapes/TLEmbedShape.mjs -init_checked_fetch(); -init_modules_watch_stub(); -var TLDRAW_APP_RE2 = /(^\/r\/[^/]+\/?$)/; -var safeParseUrl2 = (url) => { - try { - return new URL(url); - } catch (err) { - return; - } -}; -var EMBED_DEFINITIONS2 = [ - { - type: "tldraw", - title: "tldraw", - hostnames: ["beta.tldraw.com", "tldraw.com", "localhost:3000"], - minWidth: 300, - minHeight: 300, - width: 720, - height: 500, - doesResize: true, - overridePermissions: { - "allow-top-navigation": true - }, - toEmbedUrl: (url) => { - const urlObj = safeParseUrl2(url); - if (urlObj && urlObj.pathname.match(TLDRAW_APP_RE2)) { - return url; - } - return; - }, - fromEmbedUrl: (url) => { - const urlObj = safeParseUrl2(url); - if (urlObj && urlObj.pathname.match(TLDRAW_APP_RE2)) { - return url; - } - return; - } - }, - { - type: "figma", - title: "Figma", - hostnames: ["figma.com"], - width: 720, - height: 500, - doesResize: true, - toEmbedUrl: (url) => { - if (!!url.match( - // eslint-disable-next-line no-useless-escape - /https:\/\/([\w\.-]+\.)?figma.com\/(file|proto)\/([0-9a-zA-Z]{22,128})(?:\/.*)?$/ - ) && !url.includes("figma.com/embed")) { - return `https://www.figma.com/embed?embed_host=share&url=${url}`; - } - return; - }, - fromEmbedUrl: (url) => { - const urlObj = safeParseUrl2(url); - if (urlObj && urlObj.pathname.match(/^\/embed\/?$/)) { - const outUrl = urlObj.searchParams.get("url"); - if (outUrl) { - return outUrl; - } - } - return; - } - }, - { - type: "google_maps", - title: "Google Maps", - hostnames: ["google.*"], - width: 720, - height: 500, - doesResize: true, - overridePermissions: { - "allow-presentation": true - }, - toEmbedUrl: (url) => { - if (url.includes("/maps/")) { - const match = url.match(/@(.*),(.*),(.*)z/); - let result; - if (match) { - const [, lat, lng, z] = match; - const host = new URL(url).host.replace("www.", ""); - result = `https://${host}/maps/embed/v1/view?key=${process.env.NEXT_PUBLIC_GC_API_KEY}¢er=${lat},${lng}&zoom=${z}`; - } else { - result = ""; - } - return result; - } - return; - }, - fromEmbedUrl: (url) => { - const urlObj = safeParseUrl2(url); - if (!urlObj) - return; - const matches = urlObj.pathname.match(/^\/maps\/embed\/v1\/view\/?$/); - if (matches && urlObj.searchParams.has("center") && urlObj.searchParams.get("zoom")) { - const zoom = urlObj.searchParams.get("zoom"); - const [lat, lon] = urlObj.searchParams.get("center").split(","); - return `https://www.google.com/maps/@${lat},${lon},${zoom}z`; - } - return; - } - }, - { - type: "val_town", - title: "Val Town", - hostnames: ["val.town"], - minWidth: 260, - minHeight: 100, - width: 720, - height: 500, - doesResize: true, - toEmbedUrl: (url) => { - const urlObj = safeParseUrl2(url); - const matches = urlObj && urlObj.pathname.match(/\/v\/(.+)\/?/); - if (matches) { - return `https://www.val.town/embed/${matches[1]}`; - } - return; - }, - fromEmbedUrl: (url) => { - const urlObj = safeParseUrl2(url); - const matches = urlObj && urlObj.pathname.match(/\/embed\/(.+)\/?/); - if (matches) { - return `https://www.val.town/v/${matches[1]}`; - } - return; - } - }, - { - type: "codesandbox", - title: "CodeSandbox", - hostnames: ["codesandbox.io"], - minWidth: 300, - minHeight: 300, - width: 720, - height: 500, - doesResize: true, - toEmbedUrl: (url) => { - const urlObj = safeParseUrl2(url); - const matches = urlObj && urlObj.pathname.match(/\/s\/([^/]+)\/?/); - if (matches) { - return `https://codesandbox.io/embed/${matches[1]}`; - } - return; - }, - fromEmbedUrl: (url) => { - const urlObj = safeParseUrl2(url); - const matches = urlObj && urlObj.pathname.match(/\/embed\/([^/]+)\/?/); - if (matches) { - return `https://codesandbox.io/s/${matches[1]}`; - } - return; - } - }, - { - type: "codepen", - title: "Codepen", - hostnames: ["codepen.io"], - minWidth: 300, - minHeight: 300, - width: 520, - height: 400, - doesResize: true, - toEmbedUrl: (url) => { - const CODEPEN_URL_REGEXP = /https:\/\/codepen.io\/([^/]+)\/pen\/([^/]+)/; - const matches = url.match(CODEPEN_URL_REGEXP); - if (matches) { - const [_, user, id] = matches; - return `https://codepen.io/${user}/embed/${id}`; - } - return; - }, - fromEmbedUrl: (url) => { - const CODEPEN_EMBED_REGEXP = /https:\/\/codepen.io\/([^/]+)\/embed\/([^/]+)/; - const matches = url.match(CODEPEN_EMBED_REGEXP); - if (matches) { - const [_, user, id] = matches; - return `https://codepen.io/${user}/pen/${id}`; - } - return; - } - }, - { - type: "scratch", - title: "Scratch", - hostnames: ["scratch.mit.edu"], - width: 520, - height: 400, - doesResize: false, - toEmbedUrl: (url) => { - const SCRATCH_URL_REGEXP = /https?:\/\/scratch.mit.edu\/projects\/([^/]+)/; - const matches = url.match(SCRATCH_URL_REGEXP); - if (matches) { - const [_, id] = matches; - return `https://scratch.mit.edu/projects/embed/${id}`; - } - return; - }, - fromEmbedUrl: (url) => { - const SCRATCH_EMBED_REGEXP = /https:\/\/scratch.mit.edu\/projects\/embed\/([^/]+)/; - const matches = url.match(SCRATCH_EMBED_REGEXP); - if (matches) { - const [_, id] = matches; - return `https://scratch.mit.edu/projects/${id}`; - } - return; - } - }, - { - type: "youtube", - title: "YouTube", - hostnames: ["*.youtube.com", "youtube.com", "youtu.be"], - width: 800, - height: 450, - doesResize: true, - overridePermissions: { - "allow-presentation": true, - "allow-popups-to-escape-sandbox": true - }, - isAspectRatioLocked: true, - toEmbedUrl: (url) => { - const urlObj = safeParseUrl2(url); - if (!urlObj) - return; - const hostname = urlObj.hostname.replace(/^www./, ""); - if (hostname === "youtu.be") { - const videoId = urlObj.pathname.split("/").filter(Boolean)[0]; - return `https://www.youtube.com/embed/${videoId}`; - } else if ((hostname === "youtube.com" || hostname === "m.youtube.com") && urlObj.pathname.match(/^\/watch/)) { - const videoId = urlObj.searchParams.get("v"); - return `https://www.youtube.com/embed/${videoId}`; - } - return; - }, - fromEmbedUrl: (url) => { - const urlObj = safeParseUrl2(url); - if (!urlObj) - return; - const hostname = urlObj.hostname.replace(/^www./, ""); - if (hostname === "youtube.com") { - const matches = urlObj.pathname.match(/^\/embed\/([^/]+)\/?/); - if (matches) { - return `https://www.youtube.com/watch?v=${matches[1]}`; - } - } - return; - } - }, - { - type: "google_calendar", - title: "Google Calendar", - hostnames: ["calendar.google.*"], - width: 720, - height: 500, - minWidth: 460, - minHeight: 360, - doesResize: true, - instructionLink: "https://support.google.com/calendar/answer/41207?hl=en", - overridePermissions: { - "allow-popups-to-escape-sandbox": true - }, - toEmbedUrl: (url) => { - const urlObj = safeParseUrl2(url); - const cidQs = urlObj?.searchParams.get("cid"); - if (urlObj?.pathname.match(/\/calendar\/u\/0/) && cidQs) { - urlObj.pathname = "/calendar/embed"; - const keys = Array.from(urlObj.searchParams.keys()); - for (const key of keys) { - urlObj.searchParams.delete(key); - } - urlObj.searchParams.set("src", cidQs); - return urlObj.href; - } - return; - }, - fromEmbedUrl: (url) => { - const urlObj = safeParseUrl2(url); - const srcQs = urlObj?.searchParams.get("src"); - if (urlObj?.pathname.match(/\/calendar\/embed/) && srcQs) { - urlObj.pathname = "/calendar/u/0"; - const keys = Array.from(urlObj.searchParams.keys()); - for (const key of keys) { - urlObj.searchParams.delete(key); - } - urlObj.searchParams.set("cid", srcQs); - return urlObj.href; - } - return; - } - }, - { - type: "google_slides", - title: "Google Slides", - hostnames: ["docs.google.*"], - width: 720, - height: 500, - minWidth: 460, - minHeight: 360, - doesResize: true, - overridePermissions: { - "allow-popups-to-escape-sandbox": true - }, - toEmbedUrl: (url) => { - const urlObj = safeParseUrl2(url); - if (urlObj?.pathname.match(/^\/presentation/) && urlObj?.pathname.match(/\/pub\/?$/)) { - urlObj.pathname = urlObj.pathname.replace(/\/pub$/, "/embed"); - const keys = Array.from(urlObj.searchParams.keys()); - for (const key of keys) { - urlObj.searchParams.delete(key); - } - return urlObj.href; - } - return; - }, - fromEmbedUrl: (url) => { - const urlObj = safeParseUrl2(url); - if (urlObj?.pathname.match(/^\/presentation/) && urlObj?.pathname.match(/\/embed\/?$/)) { - urlObj.pathname = urlObj.pathname.replace(/\/embed$/, "/pub"); - const keys = Array.from(urlObj.searchParams.keys()); - for (const key of keys) { - urlObj.searchParams.delete(key); - } - return urlObj.href; - } - return; - } - }, - { - type: "github_gist", - title: "GitHub Gist", - hostnames: ["gist.github.com"], - width: 720, - height: 500, - doesResize: true, - toEmbedUrl: (url) => { - const urlObj = safeParseUrl2(url); - if (urlObj && urlObj.pathname.match(/\/([^/]+)\/([^/]+)/)) { - if (!url.split("/").pop()) - return; - return url; - } - return; - }, - fromEmbedUrl: (url) => { - const urlObj = safeParseUrl2(url); - if (urlObj && urlObj.pathname.match(/\/([^/]+)\/([^/]+)/)) { - if (!url.split("/").pop()) - return; - return url; - } - return; - } - }, - { - type: "replit", - title: "Replit", - hostnames: ["replit.com"], - width: 720, - height: 500, - doesResize: true, - toEmbedUrl: (url) => { - const urlObj = safeParseUrl2(url); - if (urlObj && urlObj.pathname.match(/\/@([^/]+)\/([^/]+)/)) { - return `${url}?embed=true`; - } - return; - }, - fromEmbedUrl: (url) => { - const urlObj = safeParseUrl2(url); - if (urlObj && urlObj.pathname.match(/\/@([^/]+)\/([^/]+)/) && urlObj.searchParams.has("embed")) { - urlObj.searchParams.delete("embed"); - return urlObj.href; - } - return; - } - }, - { - type: "felt", - title: "Felt", - hostnames: ["felt.com"], - width: 720, - height: 500, - doesResize: true, - toEmbedUrl: (url) => { - const urlObj = safeParseUrl2(url); - if (urlObj && urlObj.pathname.match(/^\/map\//)) { - return urlObj.origin + "/embed" + urlObj.pathname; - } - return; - }, - fromEmbedUrl: (url) => { - const urlObj = safeParseUrl2(url); - if (urlObj && urlObj.pathname.match(/^\/embed\/map\//)) { - urlObj.pathname = urlObj.pathname.replace(/^\/embed/, ""); - return urlObj.href; - } - return; - } - }, - { - type: "spotify", - title: "Spotify", - hostnames: ["open.spotify.com"], - width: 720, - height: 500, - minHeight: 500, - overrideOutlineRadius: 12, - doesResize: true, - toEmbedUrl: (url) => { - const urlObj = safeParseUrl2(url); - if (urlObj && urlObj.pathname.match(/^\/(artist|album)\//)) { - return urlObj.origin + "/embed" + urlObj.pathname; - } - return; - }, - fromEmbedUrl: (url) => { - const urlObj = safeParseUrl2(url); - if (urlObj && urlObj.pathname.match(/^\/embed\/(artist|album)\//)) { - return urlObj.origin + urlObj.pathname.replace(/^\/embed/, ""); - } - return; - } - }, - { - type: "vimeo", - title: "Vimeo", - hostnames: ["vimeo.com", "player.vimeo.com"], - width: 640, - height: 360, - doesResize: true, - isAspectRatioLocked: true, - toEmbedUrl: (url) => { - const urlObj = safeParseUrl2(url); - if (urlObj && urlObj.hostname === "vimeo.com") { - if (urlObj.pathname.match(/^\/[0-9]+/)) { - return "https://player.vimeo.com/video/" + urlObj.pathname.split("/")[1] + "?title=0&byline=0"; - } - } - return; - }, - fromEmbedUrl: (url) => { - const urlObj = safeParseUrl2(url); - if (urlObj && urlObj.hostname === "player.vimeo.com") { - const matches = urlObj.pathname.match(/^\/video\/([^/]+)\/?$/); - if (matches) { - return "https://vimeo.com/" + matches[1]; - } - } - return; - } - }, - { - type: "excalidraw", - title: "Excalidraw", - hostnames: ["excalidraw.com"], - width: 720, - height: 500, - doesResize: true, - isAspectRatioLocked: true, - toEmbedUrl: (url) => { - const urlObj = safeParseUrl2(url); - if (urlObj && urlObj.hash.match(/#room=/)) { - return url; - } - return; - }, - fromEmbedUrl: (url) => { - const urlObj = safeParseUrl2(url); - if (urlObj && urlObj.hash.match(/#room=/)) { - return url; - } - return; - } - }, - { - type: "observable", - title: "Observable", - hostnames: ["observablehq.com"], - width: 720, - height: 500, - doesResize: true, - isAspectRatioLocked: false, - backgroundColor: "#fff", - toEmbedUrl: (url) => { - const urlObj = safeParseUrl2(url); - if (urlObj && urlObj.pathname.match(/^\/@([^/]+)\/([^/]+)\/?$/)) { - return `${urlObj.origin}/embed${urlObj.pathname}?cell=*`; - } - if (urlObj && urlObj.pathname.match(/^\/d\/([^/]+)\/?$/)) { - const pathName = urlObj.pathname.replace(/^\/d/, ""); - return `${urlObj.origin}/embed${pathName}?cell=*`; - } - return; - }, - fromEmbedUrl: (url) => { - const urlObj = safeParseUrl2(url); - if (urlObj && urlObj.pathname.match(/^\/embed\/@([^/]+)\/([^/]+)\/?$/)) { - return `${urlObj.origin}${urlObj.pathname.replace("/embed", "")}#cell-*`; - } - if (urlObj && urlObj.pathname.match(/^\/embed\/([^/]+)\/?$/)) { - return `${urlObj.origin}${urlObj.pathname.replace("/embed", "/d")}#cell-*`; - } - return; - } - }, - { - type: "desmos", - title: "Desmos", - hostnames: ["desmos.com"], - width: 700, - height: 450, - doesResize: true, - toEmbedUrl: (url) => { - const urlObj = safeParseUrl2(url); - if (urlObj && urlObj.hostname === "www.desmos.com" && urlObj.pathname.match(/^\/calculator\/([^/]+)\/?$/) && urlObj.search === "" && urlObj.hash === "") { - return `${url}?embed`; - } - return; - }, - fromEmbedUrl: (url) => { - const urlObj = safeParseUrl2(url); - if (urlObj && urlObj.hostname === "www.desmos.com" && urlObj.pathname.match(/^\/calculator\/([^/]+)\/?$/) && urlObj.search === "?embed" && urlObj.hash === "") { - return url.replace("?embed", ""); - } - return; - } - } -]; -var embedShapeProps2 = { - w: validation_exports.nonZeroNumber, - h: validation_exports.nonZeroNumber, - url: validation_exports.string -}; -var Versions18 = createShapePropsMigrationIds2("embed", { - GenOriginalUrlInEmbed: 1, - RemoveDoesResize: 2, - RemoveTmpOldUrl: 3, - RemovePermissionOverrides: 4 -}); -var embedShapeMigrations2 = createShapePropsMigrationSequence2({ - sequence: [ - { - id: Versions18.GenOriginalUrlInEmbed, - // add tmpOldUrl property - up: (props) => { - try { - const url = props.url; - const host = new URL(url).host.replace("www.", ""); - let originalUrl; - for (const localEmbedDef of EMBED_DEFINITIONS2) { - if (localEmbedDef.hostnames.includes(host)) { - try { - originalUrl = localEmbedDef.fromEmbedUrl(url); - } catch (err) { - console.warn(err); - } - } - } - props.tmpOldUrl = props.url; - props.url = originalUrl ?? ""; - } catch (e) { - props.url = ""; - props.tmpOldUrl = props.url; - } - }, - down: "retired" - }, - { - id: Versions18.RemoveDoesResize, - up: (props) => { - delete props.doesResize; - }, - down: "retired" - }, - { - id: Versions18.RemoveTmpOldUrl, - up: (props) => { - delete props.tmpOldUrl; - }, - down: "retired" - }, - { - id: Versions18.RemovePermissionOverrides, - up: (props) => { - delete props.overridePermissions; - }, - down: "retired" - } - ] -}); - -// node_modules/@tldraw/tlschema/dist-esm/shapes/TLFrameShape.mjs -init_checked_fetch(); -init_modules_watch_stub(); -var frameShapeProps2 = { - w: validation_exports.nonZeroNumber, - h: validation_exports.nonZeroNumber, - name: validation_exports.string -}; -var frameShapeMigrations2 = createShapePropsMigrationSequence2({ - sequence: [] -}); - -// node_modules/@tldraw/tlschema/dist-esm/shapes/TLGeoShape.mjs -init_checked_fetch(); -init_modules_watch_stub(); - -// node_modules/@tldraw/tlschema/dist-esm/styles/TLHorizontalAlignStyle.mjs -init_checked_fetch(); -init_modules_watch_stub(); -var DefaultHorizontalAlignStyle2 = StyleProp2.defineEnum("tldraw:horizontalAlign", { - defaultValue: "middle", - values: ["start", "middle", "end", "start-legacy", "end-legacy", "middle-legacy"] -}); - -// node_modules/@tldraw/tlschema/dist-esm/styles/TLVerticalAlignStyle.mjs -init_checked_fetch(); -init_modules_watch_stub(); -var DefaultVerticalAlignStyle2 = StyleProp2.defineEnum("tldraw:verticalAlign", { - defaultValue: "middle", - values: ["start", "middle", "end"] -}); - -// node_modules/@tldraw/tlschema/dist-esm/shapes/TLGeoShape.mjs -var GeoShapeGeoStyle2 = StyleProp2.defineEnum("tldraw:geo", { - defaultValue: "rectangle", - values: [ - "cloud", - "rectangle", - "ellipse", - "triangle", - "diamond", - "pentagon", - "hexagon", - "octagon", - "star", - "rhombus", - "rhombus-2", - "oval", - "trapezoid", - "arrow-right", - "arrow-left", - "arrow-up", - "arrow-down", - "x-box", - "check-box", - "heart" - ] -}); -var geoShapeProps2 = { - geo: GeoShapeGeoStyle2, - labelColor: DefaultLabelColorStyle2, - color: DefaultColorStyle2, - fill: DefaultFillStyle2, - dash: DefaultDashStyle2, - size: DefaultSizeStyle2, - font: DefaultFontStyle2, - align: DefaultHorizontalAlignStyle2, - verticalAlign: DefaultVerticalAlignStyle2, - url: validation_exports.linkUrl, - w: validation_exports.nonZeroNumber, - h: validation_exports.nonZeroNumber, - growY: validation_exports.positiveNumber, - text: validation_exports.string, - scale: validation_exports.nonZeroNumber -}; -var geoShapeVersions2 = createShapePropsMigrationIds2("geo", { - AddUrlProp: 1, - AddLabelColor: 2, - RemoveJustify: 3, - AddCheckBox: 4, - AddVerticalAlign: 5, - MigrateLegacyAlign: 6, - AddCloud: 7, - MakeUrlsValid: 8, - AddScale: 9 -}); -var geoShapeMigrations2 = createShapePropsMigrationSequence2({ - sequence: [ - { - id: geoShapeVersions2.AddUrlProp, - up: (props) => { - props.url = ""; - }, - down: "retired" - }, - { - id: geoShapeVersions2.AddLabelColor, - up: (props) => { - props.labelColor = "black"; - }, - down: "retired" - }, - { - id: geoShapeVersions2.RemoveJustify, - up: (props) => { - if (props.align === "justify") { - props.align = "start"; - } - }, - down: "retired" - }, - { - id: geoShapeVersions2.AddCheckBox, - up: (_props) => { - }, - down: "retired" - }, - { - id: geoShapeVersions2.AddVerticalAlign, - up: (props) => { - props.verticalAlign = "middle"; - }, - down: "retired" - }, - { - id: geoShapeVersions2.MigrateLegacyAlign, - up: (props) => { - let newAlign; - switch (props.align) { - case "start": - newAlign = "start-legacy"; - break; - case "end": - newAlign = "end-legacy"; - break; - default: - newAlign = "middle-legacy"; - break; - } - props.align = newAlign; - }, - down: "retired" - }, - { - id: geoShapeVersions2.AddCloud, - up: (_props) => { - }, - down: "retired" - }, - { - id: geoShapeVersions2.MakeUrlsValid, - up: (props) => { - if (!validation_exports.linkUrl.isValid(props.url)) { - props.url = ""; - } - }, - down: (_props) => { - } - }, - { - id: geoShapeVersions2.AddScale, - up: (props) => { - props.scale = 1; - }, - down: (props) => { - delete props.scale; - } - } - ] -}); - -// node_modules/@tldraw/tlschema/dist-esm/shapes/TLGroupShape.mjs -init_checked_fetch(); -init_modules_watch_stub(); -var groupShapeProps2 = {}; -var groupShapeMigrations2 = createShapePropsMigrationSequence2({ sequence: [] }); - -// node_modules/@tldraw/tlschema/dist-esm/shapes/TLHighlightShape.mjs -init_checked_fetch(); -init_modules_watch_stub(); -var highlightShapeProps2 = { - color: DefaultColorStyle2, - size: DefaultSizeStyle2, - segments: validation_exports.arrayOf(DrawShapeSegment2), - isComplete: validation_exports.boolean, - isPen: validation_exports.boolean, - scale: validation_exports.nonZeroNumber -}; -var Versions19 = createShapePropsMigrationIds2("highlight", { - AddScale: 1 -}); -var highlightShapeMigrations2 = createShapePropsMigrationSequence2({ - sequence: [ - { - id: Versions19.AddScale, - up: (props) => { - props.scale = 1; - }, - down: (props) => { - delete props.scale; - } - } - ] -}); - -// node_modules/@tldraw/tlschema/dist-esm/shapes/TLImageShape.mjs -init_checked_fetch(); -init_modules_watch_stub(); -var ImageShapeCrop2 = validation_exports.object({ - topLeft: vecModelValidator2, - bottomRight: vecModelValidator2 -}); -var imageShapeProps2 = { - w: validation_exports.nonZeroNumber, - h: validation_exports.nonZeroNumber, - playing: validation_exports.boolean, - url: validation_exports.linkUrl, - assetId: assetIdValidator2.nullable(), - crop: ImageShapeCrop2.nullable(), - flipX: validation_exports.boolean, - flipY: validation_exports.boolean -}; -var Versions20 = createShapePropsMigrationIds2("image", { - AddUrlProp: 1, - AddCropProp: 2, - MakeUrlsValid: 3, - AddFlipProps: 4 -}); -var imageShapeMigrations2 = createShapePropsMigrationSequence2({ - sequence: [ - { - id: Versions20.AddUrlProp, - up: (props) => { - props.url = ""; - }, - down: "retired" - }, - { - id: Versions20.AddCropProp, - up: (props) => { - props.crop = null; - }, - down: (props) => { - delete props.crop; - } - }, - { - id: Versions20.MakeUrlsValid, - up: (props) => { - if (!validation_exports.linkUrl.isValid(props.url)) { - props.url = ""; - } - }, - down: (_props) => { - } - }, - { - id: Versions20.AddFlipProps, - up: (props) => { - props.flipX = false; - props.flipY = false; - }, - down: (props) => { - delete props.flipX; - delete props.flipY; - } - } - ] -}); - -// node_modules/@tldraw/tlschema/dist-esm/shapes/TLLineShape.mjs -init_checked_fetch(); -init_modules_watch_stub(); -var LineShapeSplineStyle2 = StyleProp2.defineEnum("tldraw:spline", { - defaultValue: "line", - values: ["cubic", "line"] -}); -var lineShapePointValidator2 = validation_exports.object({ - id: validation_exports.string, - index: validation_exports.indexKey, - x: validation_exports.number, - y: validation_exports.number -}); -var lineShapeProps2 = { - color: DefaultColorStyle2, - dash: DefaultDashStyle2, - size: DefaultSizeStyle2, - spline: LineShapeSplineStyle2, - points: validation_exports.dict(validation_exports.string, lineShapePointValidator2), - scale: validation_exports.nonZeroNumber -}; -var lineShapeVersions2 = createShapePropsMigrationIds2("line", { - AddSnapHandles: 1, - RemoveExtraHandleProps: 2, - HandlesToPoints: 3, - PointIndexIds: 4, - AddScale: 5 -}); -var lineShapeMigrations2 = createShapePropsMigrationSequence2({ - sequence: [ - { - id: lineShapeVersions2.AddSnapHandles, - up: (props) => { - for (const handle of Object.values(props.handles)) { - ; - handle.canSnap = true; - } - }, - down: "retired" - }, - { - id: lineShapeVersions2.RemoveExtraHandleProps, - up: (props) => { - props.handles = objectMapFromEntries( - Object.values(props.handles).map((handle) => [ - handle.index, - { - x: handle.x, - y: handle.y - } - ]) - ); - }, - down: (props) => { - const handles = Object.entries(props.handles).map(([index, handle]) => ({ index, ...handle })).sort(sortByIndex); - props.handles = Object.fromEntries( - handles.map((handle, i) => { - const id = i === 0 ? "start" : i === handles.length - 1 ? "end" : `handle:${handle.index}`; - return [ - id, - { - id, - type: "vertex", - canBind: false, - canSnap: true, - index: handle.index, - x: handle.x, - y: handle.y - } - ]; - }) - ); - } - }, - { - id: lineShapeVersions2.HandlesToPoints, - up: (props) => { - const sortedHandles = Object.entries(props.handles).map(([index, { x, y: y2 }]) => ({ x, y: y2, index })).sort(sortByIndex); - props.points = sortedHandles.map(({ x, y: y2 }) => ({ x, y: y2 })); - delete props.handles; - }, - down: (props) => { - const indices = getIndices(props.points.length); - props.handles = Object.fromEntries( - props.points.map((handle, i) => { - const index = indices[i]; - return [ - index, - { - x: handle.x, - y: handle.y - } - ]; - }) - ); - delete props.points; - } - }, - { - id: lineShapeVersions2.PointIndexIds, - up: (props) => { - const indices = getIndices(props.points.length); - props.points = Object.fromEntries( - props.points.map((point, i) => { - const id = indices[i]; - return [ - id, - { - id, - index: id, - x: point.x, - y: point.y - } - ]; - }) - ); - }, - down: (props) => { - const sortedHandles = Object.values(props.points).sort(sortByIndex); - props.points = sortedHandles.map(({ x, y: y2 }) => ({ x, y: y2 })); - } - }, - { - id: lineShapeVersions2.AddScale, - up: (props) => { - props.scale = 1; - }, - down: (props) => { - delete props.scale; - } - } - ] -}); - -// node_modules/@tldraw/tlschema/dist-esm/shapes/TLNoteShape.mjs -init_checked_fetch(); -init_modules_watch_stub(); -var noteShapeProps2 = { - color: DefaultColorStyle2, - size: DefaultSizeStyle2, - font: DefaultFontStyle2, - fontSizeAdjustment: validation_exports.positiveNumber, - align: DefaultHorizontalAlignStyle2, - verticalAlign: DefaultVerticalAlignStyle2, - growY: validation_exports.positiveNumber, - url: validation_exports.linkUrl, - text: validation_exports.string, - scale: validation_exports.nonZeroNumber -}; -var Versions21 = createShapePropsMigrationIds2("note", { - AddUrlProp: 1, - RemoveJustify: 2, - MigrateLegacyAlign: 3, - AddVerticalAlign: 4, - MakeUrlsValid: 5, - AddFontSizeAdjustment: 6, - AddScale: 7 -}); -var noteShapeMigrations2 = createShapePropsMigrationSequence2({ - sequence: [ - { - id: Versions21.AddUrlProp, - up: (props) => { - props.url = ""; - }, - down: "retired" - }, - { - id: Versions21.RemoveJustify, - up: (props) => { - if (props.align === "justify") { - props.align = "start"; - } - }, - down: "retired" - }, - { - id: Versions21.MigrateLegacyAlign, - up: (props) => { - switch (props.align) { - case "start": - props.align = "start-legacy"; - return; - case "end": - props.align = "end-legacy"; - return; - default: - props.align = "middle-legacy"; - return; - } - }, - down: "retired" - }, - { - id: Versions21.AddVerticalAlign, - up: (props) => { - props.verticalAlign = "middle"; - }, - down: "retired" - }, - { - id: Versions21.MakeUrlsValid, - up: (props) => { - if (!validation_exports.linkUrl.isValid(props.url)) { - props.url = ""; - } - }, - down: (_props) => { - } - }, - { - id: Versions21.AddFontSizeAdjustment, - up: (props) => { - props.fontSizeAdjustment = 0; - }, - down: (props) => { - delete props.fontSizeAdjustment; - } - }, - { - id: Versions21.AddScale, - up: (props) => { - props.scale = 1; - }, - down: (props) => { - delete props.scale; - } - } - ] -}); - -// node_modules/@tldraw/tlschema/dist-esm/shapes/TLTextShape.mjs -init_checked_fetch(); -init_modules_watch_stub(); - -// node_modules/@tldraw/tlschema/dist-esm/styles/TLTextAlignStyle.mjs -init_checked_fetch(); -init_modules_watch_stub(); -var DefaultTextAlignStyle2 = StyleProp2.defineEnum("tldraw:textAlign", { - defaultValue: "start", - values: ["start", "middle", "end"] -}); - -// node_modules/@tldraw/tlschema/dist-esm/shapes/TLTextShape.mjs -var textShapeProps2 = { - color: DefaultColorStyle2, - size: DefaultSizeStyle2, - font: DefaultFontStyle2, - textAlign: DefaultTextAlignStyle2, - w: validation_exports.nonZeroNumber, - text: validation_exports.string, - scale: validation_exports.nonZeroNumber, - autoSize: validation_exports.boolean -}; -var Versions22 = createShapePropsMigrationIds2("text", { - RemoveJustify: 1, - AddTextAlign: 2 -}); -var textShapeMigrations2 = createShapePropsMigrationSequence2({ - sequence: [ - { - id: Versions22.RemoveJustify, - up: (props) => { - if (props.align === "justify") { - props.align = "start"; - } - }, - down: "retired" - }, - { - id: Versions22.AddTextAlign, - up: (props) => { - props.textAlign = props.align; - delete props.align; - }, - down: (props) => { - props.align = props.textAlign; - delete props.textAlign; - } - } - ] -}); - -// node_modules/@tldraw/tlschema/dist-esm/shapes/TLVideoShape.mjs -init_checked_fetch(); -init_modules_watch_stub(); -var videoShapeProps2 = { - w: validation_exports.nonZeroNumber, - h: validation_exports.nonZeroNumber, - time: validation_exports.number, - playing: validation_exports.boolean, - url: validation_exports.linkUrl, - assetId: assetIdValidator2.nullable() -}; -var Versions23 = createShapePropsMigrationIds2("video", { - AddUrlProp: 1, - MakeUrlsValid: 2 -}); -var videoShapeMigrations2 = createShapePropsMigrationSequence2({ - sequence: [ - { - id: Versions23.AddUrlProp, - up: (props) => { - props.url = ""; - }, - down: "retired" - }, - { - id: Versions23.MakeUrlsValid, - up: (props) => { - if (!validation_exports.linkUrl.isValid(props.url)) { - props.url = ""; - } - }, - down: (_props) => { - } - } - ] -}); - -// node_modules/@tldraw/tlschema/dist-esm/store-migrations.mjs -init_checked_fetch(); -init_modules_watch_stub(); -var Versions24 = createMigrationIds("com.tldraw.store", { - RemoveCodeAndIconShapeTypes: 1, - AddInstancePresenceType: 2, - RemoveTLUserAndPresenceAndAddPointer: 3, - RemoveUserDocument: 4 -}); -var storeMigrations2 = createMigrationSequence({ - sequenceId: "com.tldraw.store", - retroactive: false, - sequence: [ - { - id: Versions24.RemoveCodeAndIconShapeTypes, - scope: "store", - up: (store) => { - for (const [id, record] of objectMapEntries(store)) { - if (record.typeName === "shape" && (record.type === "icon" || record.type === "code")) { - delete store[id]; - } - } - } - }, - { - id: Versions24.AddInstancePresenceType, - scope: "store", - up(_store) { - } - }, - { - // remove user and presence records and add pointer records - id: Versions24.RemoveTLUserAndPresenceAndAddPointer, - scope: "store", - up: (store) => { - for (const [id, record] of objectMapEntries(store)) { - if (record.typeName.match(/^(user|user_presence)$/)) { - delete store[id]; - } - } - } - }, - { - // remove user document records - id: Versions24.RemoveUserDocument, - scope: "store", - up: (store) => { - for (const [id, record] of objectMapEntries(store)) { - if (record.typeName.match("user_document")) { - delete store[id]; - } - } - } - } - ] -}); - -// node_modules/@tldraw/tlschema/dist-esm/createTLSchema.mjs -var defaultShapeSchemas2 = { - arrow: { migrations: arrowShapeMigrations2, props: arrowShapeProps2 }, - bookmark: { migrations: bookmarkShapeMigrations2, props: bookmarkShapeProps2 }, - draw: { migrations: drawShapeMigrations2, props: drawShapeProps2 }, - embed: { migrations: embedShapeMigrations2, props: embedShapeProps2 }, - frame: { migrations: frameShapeMigrations2, props: frameShapeProps2 }, - geo: { migrations: geoShapeMigrations2, props: geoShapeProps2 }, - group: { migrations: groupShapeMigrations2, props: groupShapeProps2 }, - highlight: { migrations: highlightShapeMigrations2, props: highlightShapeProps2 }, - image: { migrations: imageShapeMigrations2, props: imageShapeProps2 }, - line: { migrations: lineShapeMigrations2, props: lineShapeProps2 }, - note: { migrations: noteShapeMigrations2, props: noteShapeProps2 }, - text: { migrations: textShapeMigrations2, props: textShapeProps2 }, - video: { migrations: videoShapeMigrations2, props: videoShapeProps2 } -}; -var defaultBindingSchemas2 = { - arrow: { migrations: arrowBindingMigrations2, props: arrowBindingProps2 } -}; -function createTLSchema2({ - shapes = defaultShapeSchemas2, - bindings = defaultBindingSchemas2, - migrations -} = {}) { - const stylesById = /* @__PURE__ */ new Map(); - for (const shape of objectMapValues(shapes)) { - for (const style of getShapePropKeysByStyle2(shape.props ?? {}).keys()) { - if (stylesById.has(style.id) && stylesById.get(style.id) !== style) { - throw new Error(`Multiple StyleProp instances with the same id: ${style.id}`); - } - stylesById.set(style.id, style); - } - } - const ShapeRecordType = createShapeRecordType2(shapes); - const BindingRecordType = createBindingRecordType2(bindings); - const InstanceRecordType = createInstanceRecordType2(stylesById); - return StoreSchema.create( - { - asset: AssetRecordType2, - binding: BindingRecordType, - camera: CameraRecordType2, - document: DocumentRecordType2, - instance: InstanceRecordType, - instance_page_state: InstancePageStateRecordType2, - page: PageRecordType2, - instance_presence: InstancePresenceRecordType2, - pointer: PointerRecordType2, - shape: ShapeRecordType - }, - { - migrations: [ - storeMigrations2, - assetMigrations2, - cameraMigrations2, - documentMigrations2, - instanceMigrations2, - instancePageStateMigrations2, - pageMigrations2, - instancePresenceMigrations2, - pointerMigrations2, - rootShapeMigrations2, - bookmarkAssetMigrations2, - imageAssetMigrations2, - videoAssetMigrations2, - ...processPropsMigrations2("shape", shapes), - ...processPropsMigrations2("binding", bindings), - ...migrations ?? [] - ], - onValidationFailure: onValidationFailure2, - createIntegrityChecker: createIntegrityChecker2 - } - ); -} - -// node_modules/@tldraw/tlschema/dist-esm/misc/TLHandle.mjs -init_checked_fetch(); -init_modules_watch_stub(); - -// node_modules/@tldraw/tlschema/dist-esm/translations/translations.mjs -init_checked_fetch(); -init_modules_watch_stub(); - -// node_modules/@tldraw/tlschema/dist-esm/translations/languages.mjs -init_checked_fetch(); -init_modules_watch_stub(); - -// worker/TldrawDurableObject.ts -var import_lodash7 = __toESM(require_lodash(), 1); -var schema = createTLSchema2({ - shapes: { ...defaultShapeSchemas2 } - // bindings: { ...defaultBindingSchemas }, -}); -var TldrawDurableObject = class { - constructor(ctx, env) { - this.ctx = ctx; - this.r2 = env.TLDRAW_BUCKET; - ctx.blockConcurrencyWhile(async () => { - this.roomId = await this.ctx.storage.get("roomId") ?? null; - }); - } - r2; - // the room ID will be missing whilst the room is being initialized - roomId = null; - // when we load the room from the R2 bucket, we keep it here. it's a promise so we only ever - // load it once. - roomPromise = null; - router = n({ - catch: (e) => { - console.log(e); - return s(e); - } - }).get("/connect/:roomId", async (request) => { - if (!this.roomId) { - await this.ctx.blockConcurrencyWhile(async () => { - await this.ctx.storage.put("roomId", request.params.roomId); - this.roomId = request.params.roomId; - }); - } - return this.handleConnect(request); - }); - // `fetch` is the entry point for all requests to the Durable Object - fetch(request) { - return this.router.fetch(request); - } - // what happens when someone tries to connect to this room? - async handleConnect(request) { - const sessionId = request.query.sessionId; - if (!sessionId) - return s(400, "Missing sessionId"); - const { 0: clientWebSocket, 1: serverWebSocket } = new WebSocketPair(); - serverWebSocket.accept(); - const room = await this.getRoom(); - room.handleSocketConnect({ sessionId, socket: serverWebSocket }); - return new Response(null, { status: 101, webSocket: clientWebSocket }); - } - getRoom() { - const roomId = this.roomId; - if (!roomId) - throw new Error("Missing roomId"); - if (!this.roomPromise) { - this.roomPromise = (async () => { - const roomFromBucket = await this.r2.get(`rooms/${roomId}`); - const initialSnapshot = roomFromBucket ? await roomFromBucket.json() : void 0; - return new TLSocketRoom({ - schema, - initialSnapshot, - onDataChange: () => { - this.schedulePersistToR2(); - } - }); - })(); - } - return this.roomPromise; - } - // we throttle persistance so it only happens every 10 seconds - schedulePersistToR2 = (0, import_lodash7.default)(async () => { - if (!this.roomPromise || !this.roomId) - return; - const room = await this.getRoom(); - const snapshot = JSON.stringify(room.getCurrentSnapshot()); - await this.r2.put(`rooms/${this.roomId}`, snapshot); - }, 1e4); -}; - -// worker/worker.ts -var { preflight, corsify } = y({ origin: "*" }); -var router = n({ - before: [preflight], - finally: [corsify], - catch: (e) => { - console.error(e); - return s(e); - } -}).get("/connect/:roomId", (request, env) => { - const id = env.TLDRAW_DURABLE_OBJECT.idFromName(request.params.roomId); - const room = env.TLDRAW_DURABLE_OBJECT.get(id); - return room.fetch(request.url, { headers: request.headers, body: request.body }); -}).post("/uploads/:uploadId", handleAssetUpload).get("/uploads/:uploadId", handleAssetDownload).get("/unfurl", handleUnfurlRequest); -var worker_default = router; - -// node_modules/wrangler/templates/middleware/middleware-ensure-req-body-drained.ts -init_checked_fetch(); -init_modules_watch_stub(); -var drainBody = async (request, env, _ctx, middlewareCtx) => { - try { - return await middlewareCtx.next(request, env); - } finally { - try { - if (request.body !== null && !request.bodyUsed) { - const reader = request.body.getReader(); - while (!(await reader.read()).done) { - } - } - } catch (e) { - console.error("Failed to drain the unused request body.", e); - } - } -}; -var middleware_ensure_req_body_drained_default = drainBody; - -// node_modules/wrangler/templates/middleware/middleware-miniflare3-json-error.ts -init_checked_fetch(); -init_modules_watch_stub(); -function reduceError(e) { - return { - name: e?.name, - message: e?.message ?? String(e), - stack: e?.stack, - cause: e?.cause === void 0 ? void 0 : reduceError(e.cause) - }; -} -var jsonError = async (request, env, _ctx, middlewareCtx) => { - try { - return await middlewareCtx.next(request, env); - } catch (e) { - const error = reduceError(e); - return Response.json(error, { - status: 500, - headers: { "MF-Experimental-Error-Stack": "true" } - }); - } -}; -var middleware_miniflare3_json_error_default = jsonError; - -// .wrangler/tmp/bundle-fO5AAb/middleware-insertion-facade.js -var __INTERNAL_WRANGLER_MIDDLEWARE__ = [ - middleware_ensure_req_body_drained_default, - middleware_miniflare3_json_error_default -]; -var middleware_insertion_facade_default = worker_default; - -// node_modules/wrangler/templates/middleware/common.ts -init_checked_fetch(); -init_modules_watch_stub(); -var __facade_middleware__ = []; -function __facade_register__(...args) { - __facade_middleware__.push(...args.flat()); -} -function __facade_invokeChain__(request, env, ctx, dispatch, middlewareChain) { - const [head, ...tail] = middlewareChain; - const middlewareCtx = { - dispatch, - next(newRequest, newEnv) { - return __facade_invokeChain__(newRequest, newEnv, ctx, dispatch, tail); - } - }; - return head(request, env, ctx, middlewareCtx); -} -function __facade_invoke__(request, env, ctx, dispatch, finalMiddleware) { - return __facade_invokeChain__(request, env, ctx, dispatch, [ - ...__facade_middleware__, - finalMiddleware - ]); -} - -// .wrangler/tmp/bundle-fO5AAb/middleware-loader.entry.ts -var __Facade_ScheduledController__ = class { - constructor(scheduledTime, cron, noRetry) { - this.scheduledTime = scheduledTime; - this.cron = cron; - this.#noRetry = noRetry; - } - #noRetry; - noRetry() { - if (!(this instanceof __Facade_ScheduledController__)) { - throw new TypeError("Illegal invocation"); - } - this.#noRetry(); - } -}; -function wrapExportedHandler(worker) { - if (__INTERNAL_WRANGLER_MIDDLEWARE__ === void 0 || __INTERNAL_WRANGLER_MIDDLEWARE__.length === 0) { - return worker; - } - for (const middleware of __INTERNAL_WRANGLER_MIDDLEWARE__) { - __facade_register__(middleware); - } - const fetchDispatcher = function(request, env, ctx) { - if (worker.fetch === void 0) { - throw new Error("Handler does not export a fetch() function."); - } - return worker.fetch(request, env, ctx); - }; - return { - ...worker, - fetch(request, env, ctx) { - const dispatcher = function(type, init) { - if (type === "scheduled" && worker.scheduled !== void 0) { - const controller = new __Facade_ScheduledController__( - Date.now(), - init.cron ?? "", - () => { - } - ); - return worker.scheduled(controller, env, ctx); - } - }; - return __facade_invoke__(request, env, ctx, dispatcher, fetchDispatcher); - } - }; -} -function wrapWorkerEntrypoint(klass) { - if (__INTERNAL_WRANGLER_MIDDLEWARE__ === void 0 || __INTERNAL_WRANGLER_MIDDLEWARE__.length === 0) { - return klass; - } - for (const middleware of __INTERNAL_WRANGLER_MIDDLEWARE__) { - __facade_register__(middleware); - } - return class extends klass { - #fetchDispatcher = (request, env, ctx) => { - this.env = env; - this.ctx = ctx; - if (super.fetch === void 0) { - throw new Error("Entrypoint class does not define a fetch() function."); - } - return super.fetch(request); - }; - #dispatcher = (type, init) => { - if (type === "scheduled" && super.scheduled !== void 0) { - const controller = new __Facade_ScheduledController__( - Date.now(), - init.cron ?? "", - () => { - } - ); - return super.scheduled(controller); - } - }; - fetch(request) { - return __facade_invoke__( - request, - this.env, - this.ctx, - this.#dispatcher, - this.#fetchDispatcher - ); - } - }; -} -var WRAPPED_ENTRY; -if (typeof middleware_insertion_facade_default === "object") { - WRAPPED_ENTRY = wrapExportedHandler(middleware_insertion_facade_default); -} else if (typeof middleware_insertion_facade_default === "function") { - WRAPPED_ENTRY = wrapWorkerEntrypoint(middleware_insertion_facade_default); -} -var middleware_loader_entry_default = WRAPPED_ENTRY; -export { - TldrawDurableObject, - __INTERNAL_WRANGLER_MIDDLEWARE__, - middleware_loader_entry_default as default -}; -/*! Bundled license information: - -@tldraw/utils/dist-esm/lib/media/apng.mjs: - (*! - * MIT License: https://github.com/vHeemstra/is-apng/blob/main/license - * Copyright (c) Philip van Heemstra - *) - -@tldraw/utils/dist-esm/lib/media/gif.mjs: - (*! - * MIT License - * Modified code originally from - * Copyright (c) 2016 Józef SokoÅ‚owski - *) - -@tldraw/utils/dist-esm/lib/media/png.mjs: - (*! - * MIT License: https://github.com/alexgorbatchev/crc/blob/master/LICENSE - * Copyright: 2014 Alex Gorbatchev - * Code: crc32, https://github.com/alexgorbatchev/crc/blob/master/src/calculators/crc32.ts - *) - -@tldraw/utils/dist-esm/lib/media/webp.mjs: - (*! - * MIT License: https://github.com/sindresorhus/is-webp/blob/main/license - * Copyright (c) Sindre Sorhus (https://sindresorhus.com) - *) -*/ -//# sourceMappingURL=worker.js.map diff --git a/.wrangler/tmp/dev-g4n6ra/worker.js.map b/.wrangler/tmp/dev-g4n6ra/worker.js.map deleted file mode 100644 index e447192..0000000 --- a/.wrangler/tmp/dev-g4n6ra/worker.js.map +++ /dev/null @@ -1,8 +0,0 @@ -{ - "version": 3, - "sources": ["../bundle-fO5AAb/checked-fetch.js", "wrangler-modules-watch:wrangler:modules-watch", "../../../node_modules/wrangler/templates/modules-watch-stub.js", "../../../node_modules/lodash.throttle/index.js", "../../../node_modules/lodash.uniq/index.js", "../../../node_modules/lodash.isequal/index.js", "../bundle-fO5AAb/middleware-loader.entry.ts", "../bundle-fO5AAb/middleware-insertion-facade.js", "../../../worker/worker.ts", "../../../node_modules/cloudflare-workers-unfurl/unfurl.js", "../../../node_modules/src/src/IttyRouter.ts", "../../../node_modules/src/src/Router.ts", "../../../node_modules/src/src/createResponse.ts", "../../../node_modules/src/src/json.ts", "../../../node_modules/src/src/error.ts", "../../../node_modules/src/src/withParams.ts", "../../../node_modules/src/src/AutoRouter.ts", "../../../node_modules/src/src/StatusError.ts", "../../../node_modules/src/src/status.ts", "../../../node_modules/src/src/text.ts", "../../../node_modules/src/src/html.ts", "../../../node_modules/src/src/jpeg.ts", "../../../node_modules/src/src/png.ts", "../../../node_modules/src/src/webp.ts", "../../../node_modules/src/src/withContent.ts", "../../../node_modules/src/src/withCookies.ts", "../../../node_modules/src/src/cors.ts", "../../../worker/assetUploads.ts", "../../../worker/TldrawDurableObject.ts", "../../../node_modules/@tldraw/sync-core/src/index.ts", "../../../node_modules/@tldraw/sync-core/src/lib/ClientWebSocketAdapter.ts", "../../../node_modules/@tldraw/state/src/index.ts", "../../../node_modules/@tldraw/state/src/lib/helpers.ts", "../../../node_modules/@tldraw/state/src/lib/ArraySet.ts", "../../../node_modules/@tldraw/state/src/lib/Atom.ts", "../../../node_modules/@tldraw/state/src/lib/HistoryBuffer.ts", "../../../node_modules/@tldraw/state/src/lib/types.ts", "../../../node_modules/@tldraw/state/src/lib/capture.ts", "../../../node_modules/@tldraw/state/src/lib/transactions.ts", "../../../node_modules/@tldraw/state/src/lib/EffectScheduler.ts", "../../../node_modules/@tldraw/state/src/lib/constants.ts", "../../../node_modules/@tldraw/state/src/lib/Computed.ts", "../../../node_modules/@tldraw/state/src/lib/warnings.ts", "../../../node_modules/@tldraw/state/src/lib/isSignal.ts", "../../../node_modules/@tldraw/utils/src/index.ts", "../../../node_modules/@tldraw/utils/src/lib/PerformanceTracker.ts", "../../../node_modules/@tldraw/utils/src/lib/perf.ts", "../../../node_modules/@tldraw/utils/src/lib/array.ts", "../../../node_modules/@tldraw/utils/src/lib/cache.ts", "../../../node_modules/@tldraw/utils/src/lib/control.ts", "../../../node_modules/@tldraw/utils/src/lib/function.ts", "../../../node_modules/@tldraw/utils/src/lib/debounce.ts", "../../../node_modules/@tldraw/utils/src/lib/error.ts", "../../../node_modules/@tldraw/utils/src/lib/file.ts", "../../../node_modules/@tldraw/utils/src/lib/network.ts", "../../../node_modules/@tldraw/utils/src/lib/hash.ts", "../../../node_modules/@tldraw/utils/src/lib/iterable.ts", "../../../node_modules/@tldraw/utils/src/lib/media/media.ts", "../../../node_modules/@tldraw/utils/src/lib/media/apng.ts", "../../../node_modules/@tldraw/utils/src/lib/media/avif.ts", "../../../node_modules/@tldraw/utils/src/lib/media/gif.ts", "../../../node_modules/@tldraw/utils/src/lib/media/png.ts", "../../../node_modules/@tldraw/utils/src/lib/media/webp.ts", "../../../node_modules/@tldraw/utils/src/lib/number.ts", "../../../node_modules/@tldraw/utils/src/lib/object.ts", "../../../node_modules/@tldraw/utils/src/lib/reordering/reordering.ts", "../../../node_modules/@tldraw/utils/src/lib/reordering/dgreensp/dgreensp.ts", "../../../node_modules/@tldraw/utils/src/lib/sort.ts", "../../../node_modules/@tldraw/utils/src/lib/storage.tsx", "../../../node_modules/@tldraw/utils/src/lib/throttle.ts", "../../../node_modules/@tldraw/utils/src/lib/timers.ts", "../../../node_modules/@tldraw/utils/src/lib/value.ts", "../../../node_modules/@tldraw/utils/src/lib/warn.ts", "../../../node_modules/@tldraw/sync-core/src/lib/chunk.ts", "../../../node_modules/@tldraw/sync-core/src/lib/TLSyncClient.ts", "../../../node_modules/@tldraw/store/src/index.ts", "../../../node_modules/@tldraw/store/src/lib/IncrementalSetConstructor.ts", "../../../node_modules/@tldraw/store/src/lib/RecordType.ts", "../../../node_modules/nanoid/index.browser.js", "../../../node_modules/@tldraw/store/src/lib/RecordsDiff.ts", "../../../node_modules/@tldraw/store/src/lib/Store.ts", "../../../node_modules/@tldraw/store/src/lib/StoreQueries.ts", "../../../node_modules/@tldraw/store/src/lib/executeQuery.ts", "../../../node_modules/@tldraw/store/src/lib/setUtils.ts", "../../../node_modules/@tldraw/store/src/lib/StoreSideEffects.ts", "../../../node_modules/@tldraw/store/src/lib/devFreeze.ts", "../../../node_modules/@tldraw/store/src/lib/StoreSchema.ts", "../../../node_modules/@tldraw/store/src/lib/migrate.ts", "../../../node_modules/@tldraw/sync-core/src/lib/diff.ts", "../../../node_modules/@tldraw/sync-core/src/lib/interval.ts", "../../../node_modules/@tldraw/sync-core/src/lib/protocol.ts", "../../../node_modules/@tldraw/sync-core/src/lib/RoomSession.ts", "../../../node_modules/@tldraw/sync-core/src/lib/TLRemoteSyncError.ts", "../../../node_modules/@tldraw/sync-core/src/lib/TLSocketRoom.ts", "../../../node_modules/@tldraw/sync-core/node_modules/@tldraw/tlschema/src/index.ts", "../../../node_modules/@tldraw/sync-core/node_modules/@tldraw/tlschema/src/assets/TLBaseAsset.ts", "../../../node_modules/@tldraw/validate/src/index.ts", "../../../node_modules/@tldraw/validate/src/lib/validation.ts", "../../../node_modules/@tldraw/sync-core/node_modules/@tldraw/tlschema/src/misc/id-validator.ts", "../../../node_modules/@tldraw/sync-core/node_modules/@tldraw/tlschema/src/bindings/TLArrowBinding.ts", "../../../node_modules/@tldraw/sync-core/node_modules/@tldraw/tlschema/src/misc/geometry-types.ts", "../../../node_modules/@tldraw/sync-core/node_modules/@tldraw/tlschema/src/records/TLBinding.ts", "../../../node_modules/@tldraw/sync-core/node_modules/@tldraw/tlschema/src/bindings/TLBaseBinding.ts", "../../../node_modules/@tldraw/sync-core/node_modules/@tldraw/tlschema/src/shapes/TLBaseShape.ts", "../../../node_modules/@tldraw/sync-core/node_modules/@tldraw/tlschema/src/misc/TLOpacity.ts", "../../../node_modules/@tldraw/sync-core/node_modules/@tldraw/tlschema/src/shapes/TLArrowShape.ts", "../../../node_modules/@tldraw/sync-core/node_modules/@tldraw/tlschema/src/records/TLShape.ts", "../../../node_modules/@tldraw/sync-core/node_modules/@tldraw/tlschema/src/styles/StyleProp.ts", "../../../node_modules/@tldraw/sync-core/node_modules/@tldraw/tlschema/src/recordsWithProps.ts", "../../../node_modules/@tldraw/sync-core/node_modules/@tldraw/tlschema/src/styles/TLColorStyle.ts", "../../../node_modules/@tldraw/sync-core/node_modules/@tldraw/tlschema/src/styles/TLDashStyle.ts", "../../../node_modules/@tldraw/sync-core/node_modules/@tldraw/tlschema/src/styles/TLFillStyle.ts", "../../../node_modules/@tldraw/sync-core/node_modules/@tldraw/tlschema/src/styles/TLFontStyle.ts", "../../../node_modules/@tldraw/sync-core/node_modules/@tldraw/tlschema/src/styles/TLSizeStyle.ts", "../../../node_modules/@tldraw/sync-core/node_modules/@tldraw/tlschema/src/createPresenceStateDerivation.ts", "../../../node_modules/@tldraw/sync-core/node_modules/@tldraw/tlschema/src/records/TLCamera.ts", "../../../node_modules/@tldraw/sync-core/node_modules/@tldraw/tlschema/src/records/TLInstance.ts", "../../../node_modules/@tldraw/sync-core/node_modules/@tldraw/tlschema/src/misc/TLCursor.ts", "../../../node_modules/@tldraw/sync-core/node_modules/@tldraw/tlschema/src/misc/TLScribble.ts", "../../../node_modules/@tldraw/sync-core/node_modules/@tldraw/tlschema/src/misc/TLColor.ts", "../../../node_modules/@tldraw/sync-core/node_modules/@tldraw/tlschema/src/records/TLPage.ts", "../../../node_modules/@tldraw/sync-core/node_modules/@tldraw/tlschema/src/records/TLPageState.ts", "../../../node_modules/@tldraw/sync-core/node_modules/@tldraw/tlschema/src/records/TLPointer.ts", "../../../node_modules/@tldraw/sync-core/node_modules/@tldraw/tlschema/src/records/TLPresence.ts", "../../../node_modules/@tldraw/sync-core/node_modules/@tldraw/tlschema/src/createTLSchema.ts", "../../../node_modules/@tldraw/sync-core/node_modules/@tldraw/tlschema/src/TLStore.ts", "../../../node_modules/@tldraw/sync-core/node_modules/@tldraw/tlschema/src/records/TLDocument.ts", "../../../node_modules/@tldraw/sync-core/node_modules/@tldraw/tlschema/src/assets/TLBookmarkAsset.ts", "../../../node_modules/@tldraw/sync-core/node_modules/@tldraw/tlschema/src/assets/TLImageAsset.ts", "../../../node_modules/@tldraw/sync-core/node_modules/@tldraw/tlschema/src/assets/TLVideoAsset.ts", "../../../node_modules/@tldraw/sync-core/node_modules/@tldraw/tlschema/src/records/TLAsset.ts", "../../../node_modules/@tldraw/sync-core/node_modules/@tldraw/tlschema/src/shapes/TLBookmarkShape.ts", "../../../node_modules/@tldraw/sync-core/node_modules/@tldraw/tlschema/src/shapes/TLDrawShape.ts", "../../../node_modules/@tldraw/sync-core/node_modules/@tldraw/tlschema/src/shapes/TLEmbedShape.ts", "../../../node_modules/@tldraw/sync-core/node_modules/@tldraw/tlschema/src/shapes/TLFrameShape.ts", "../../../node_modules/@tldraw/sync-core/node_modules/@tldraw/tlschema/src/shapes/TLGeoShape.ts", "../../../node_modules/@tldraw/sync-core/node_modules/@tldraw/tlschema/src/styles/TLHorizontalAlignStyle.ts", "../../../node_modules/@tldraw/sync-core/node_modules/@tldraw/tlschema/src/styles/TLVerticalAlignStyle.ts", "../../../node_modules/@tldraw/sync-core/node_modules/@tldraw/tlschema/src/shapes/TLGroupShape.ts", "../../../node_modules/@tldraw/sync-core/node_modules/@tldraw/tlschema/src/shapes/TLHighlightShape.ts", "../../../node_modules/@tldraw/sync-core/node_modules/@tldraw/tlschema/src/shapes/TLImageShape.ts", "../../../node_modules/@tldraw/sync-core/node_modules/@tldraw/tlschema/src/shapes/TLLineShape.ts", "../../../node_modules/@tldraw/sync-core/node_modules/@tldraw/tlschema/src/shapes/TLNoteShape.ts", "../../../node_modules/@tldraw/sync-core/node_modules/@tldraw/tlschema/src/shapes/TLTextShape.ts", "../../../node_modules/@tldraw/sync-core/node_modules/@tldraw/tlschema/src/styles/TLTextAlignStyle.ts", "../../../node_modules/@tldraw/sync-core/node_modules/@tldraw/tlschema/src/shapes/TLVideoShape.ts", "../../../node_modules/@tldraw/sync-core/node_modules/@tldraw/tlschema/src/store-migrations.ts", "../../../node_modules/@tldraw/sync-core/node_modules/@tldraw/tlschema/src/misc/TLHandle.ts", "../../../node_modules/@tldraw/sync-core/node_modules/@tldraw/tlschema/src/translations/translations.ts", "../../../node_modules/@tldraw/sync-core/node_modules/@tldraw/tlschema/src/translations/languages.ts", "../../../node_modules/@tldraw/sync-core/src/lib/ServerSocketAdapter.ts", "../../../node_modules/@tldraw/sync-core/src/lib/TLSyncRoom.ts", "../../../node_modules/nanoevents/index.js", "../../../node_modules/@tldraw/tlschema/src/index.ts", "../../../node_modules/@tldraw/tlschema/src/assets/TLBaseAsset.ts", "../../../node_modules/@tldraw/tlschema/src/misc/id-validator.ts", "../../../node_modules/@tldraw/tlschema/src/bindings/TLArrowBinding.ts", "../../../node_modules/@tldraw/tlschema/src/misc/geometry-types.ts", "../../../node_modules/@tldraw/tlschema/src/records/TLBinding.ts", "../../../node_modules/@tldraw/tlschema/src/bindings/TLBaseBinding.ts", "../../../node_modules/@tldraw/tlschema/src/shapes/TLBaseShape.ts", "../../../node_modules/@tldraw/tlschema/src/misc/TLOpacity.ts", "../../../node_modules/@tldraw/tlschema/src/shapes/TLArrowShape.ts", "../../../node_modules/@tldraw/tlschema/src/records/TLShape.ts", "../../../node_modules/@tldraw/tlschema/src/styles/StyleProp.ts", "../../../node_modules/@tldraw/tlschema/src/recordsWithProps.ts", "../../../node_modules/@tldraw/tlschema/src/styles/TLColorStyle.ts", "../../../node_modules/@tldraw/tlschema/src/styles/TLDashStyle.ts", "../../../node_modules/@tldraw/tlschema/src/styles/TLFillStyle.ts", "../../../node_modules/@tldraw/tlschema/src/styles/TLFontStyle.ts", "../../../node_modules/@tldraw/tlschema/src/styles/TLSizeStyle.ts", "../../../node_modules/@tldraw/tlschema/src/createPresenceStateDerivation.ts", "../../../node_modules/@tldraw/tlschema/src/records/TLCamera.ts", "../../../node_modules/@tldraw/tlschema/src/records/TLInstance.ts", "../../../node_modules/@tldraw/tlschema/src/misc/TLCursor.ts", "../../../node_modules/@tldraw/tlschema/src/misc/TLScribble.ts", "../../../node_modules/@tldraw/tlschema/src/misc/TLColor.ts", "../../../node_modules/@tldraw/tlschema/src/records/TLPage.ts", "../../../node_modules/@tldraw/tlschema/src/records/TLPageState.ts", "../../../node_modules/@tldraw/tlschema/src/records/TLPointer.ts", "../../../node_modules/@tldraw/tlschema/src/records/TLPresence.ts", "../../../node_modules/@tldraw/tlschema/src/createTLSchema.ts", "../../../node_modules/@tldraw/tlschema/src/TLStore.ts", "../../../node_modules/@tldraw/tlschema/src/records/TLDocument.ts", "../../../node_modules/@tldraw/tlschema/src/assets/TLBookmarkAsset.ts", "../../../node_modules/@tldraw/tlschema/src/assets/TLImageAsset.ts", "../../../node_modules/@tldraw/tlschema/src/assets/TLVideoAsset.ts", "../../../node_modules/@tldraw/tlschema/src/records/TLAsset.ts", "../../../node_modules/@tldraw/tlschema/src/shapes/TLBookmarkShape.ts", "../../../node_modules/@tldraw/tlschema/src/shapes/TLDrawShape.ts", "../../../node_modules/@tldraw/tlschema/src/shapes/TLEmbedShape.ts", "../../../node_modules/@tldraw/tlschema/src/shapes/TLFrameShape.ts", "../../../node_modules/@tldraw/tlschema/src/shapes/TLGeoShape.ts", "../../../node_modules/@tldraw/tlschema/src/styles/TLHorizontalAlignStyle.ts", "../../../node_modules/@tldraw/tlschema/src/styles/TLVerticalAlignStyle.ts", "../../../node_modules/@tldraw/tlschema/src/shapes/TLGroupShape.ts", "../../../node_modules/@tldraw/tlschema/src/shapes/TLHighlightShape.ts", "../../../node_modules/@tldraw/tlschema/src/shapes/TLImageShape.ts", "../../../node_modules/@tldraw/tlschema/src/shapes/TLLineShape.ts", "../../../node_modules/@tldraw/tlschema/src/shapes/TLNoteShape.ts", "../../../node_modules/@tldraw/tlschema/src/shapes/TLTextShape.ts", "../../../node_modules/@tldraw/tlschema/src/styles/TLTextAlignStyle.ts", "../../../node_modules/@tldraw/tlschema/src/shapes/TLVideoShape.ts", "../../../node_modules/@tldraw/tlschema/src/store-migrations.ts", "../../../node_modules/@tldraw/tlschema/src/misc/TLHandle.ts", "../../../node_modules/@tldraw/tlschema/src/translations/translations.ts", "../../../node_modules/@tldraw/tlschema/src/translations/languages.ts", "../../../node_modules/wrangler/templates/middleware/middleware-ensure-req-body-drained.ts", "../../../node_modules/wrangler/templates/middleware/middleware-miniflare3-json-error.ts", "../../../node_modules/wrangler/templates/middleware/common.ts"], - "sourceRoot": "C:\\Users\\jeffe\\Documents\\GitHub\\canvas-website\\.wrangler\\tmp\\dev-g4n6ra", - "sourcesContent": ["const urls = new Set();\n\nfunction checkURL(request, init) {\n\tconst url =\n\t\trequest instanceof URL\n\t\t\t? request\n\t\t\t: new URL(\n\t\t\t\t\t(typeof request === \"string\"\n\t\t\t\t\t\t? new Request(request, init)\n\t\t\t\t\t\t: request\n\t\t\t\t\t).url\n\t\t\t\t);\n\tif (url.port && url.port !== \"443\" && url.protocol === \"https:\") {\n\t\tif (!urls.has(url.toString())) {\n\t\t\turls.add(url.toString());\n\t\t\tconsole.warn(\n\t\t\t\t`WARNING: known issue with \\`fetch()\\` requests to custom HTTPS ports in published Workers:\\n` +\n\t\t\t\t\t` - ${url.toString()} - the custom port will be ignored when the Worker is published using the \\`wrangler deploy\\` command.\\n`\n\t\t\t);\n\t\t}\n\t}\n}\n\nglobalThis.fetch = new Proxy(globalThis.fetch, {\n\tapply(target, thisArg, argArray) {\n\t\tconst [request, init] = argArray;\n\t\tcheckURL(request, init);\n\t\treturn Reflect.apply(target, thisArg, argArray);\n\t},\n});\n", "", "// `esbuild` doesn't support returning `watch*` options from `onStart()`\n// plugin callbacks. Instead, we define an empty virtual module that is\n// imported by this injected file. Importing the module registers watchers.\nimport \"wrangler:modules-watch\";\n", "/**\n * lodash (Custom Build) \n * Build: `lodash modularize exports=\"npm\" -o ./`\n * Copyright jQuery Foundation and other contributors \n * Released under MIT license \n * Based on Underscore.js 1.8.3 \n * Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors\n */\n\n/** Used as the `TypeError` message for \"Functions\" methods. */\nvar FUNC_ERROR_TEXT = 'Expected a function';\n\n/** Used as references for various `Number` constants. */\nvar NAN = 0 / 0;\n\n/** `Object#toString` result references. */\nvar symbolTag = '[object Symbol]';\n\n/** Used to match leading and trailing whitespace. */\nvar reTrim = /^\\s+|\\s+$/g;\n\n/** Used to detect bad signed hexadecimal string values. */\nvar reIsBadHex = /^[-+]0x[0-9a-f]+$/i;\n\n/** Used to detect binary string values. */\nvar reIsBinary = /^0b[01]+$/i;\n\n/** Used to detect octal string values. */\nvar reIsOctal = /^0o[0-7]+$/i;\n\n/** Built-in method references without a dependency on `root`. */\nvar freeParseInt = parseInt;\n\n/** Detect free variable `global` from Node.js. */\nvar freeGlobal = typeof global == 'object' && global && global.Object === Object && global;\n\n/** Detect free variable `self`. */\nvar freeSelf = typeof self == 'object' && self && self.Object === Object && self;\n\n/** Used as a reference to the global object. */\nvar root = freeGlobal || freeSelf || Function('return this')();\n\n/** Used for built-in method references. */\nvar objectProto = Object.prototype;\n\n/**\n * Used to resolve the\n * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)\n * of values.\n */\nvar objectToString = objectProto.toString;\n\n/* Built-in method references for those with the same name as other `lodash` methods. */\nvar nativeMax = Math.max,\n nativeMin = Math.min;\n\n/**\n * Gets the timestamp of the number of milliseconds that have elapsed since\n * the Unix epoch (1 January 1970 00:00:00 UTC).\n *\n * @static\n * @memberOf _\n * @since 2.4.0\n * @category Date\n * @returns {number} Returns the timestamp.\n * @example\n *\n * _.defer(function(stamp) {\n * console.log(_.now() - stamp);\n * }, _.now());\n * // => Logs the number of milliseconds it took for the deferred invocation.\n */\nvar now = function() {\n return root.Date.now();\n};\n\n/**\n * Creates a debounced function that delays invoking `func` until after `wait`\n * milliseconds have elapsed since the last time the debounced function was\n * invoked. The debounced function comes with a `cancel` method to cancel\n * delayed `func` invocations and a `flush` method to immediately invoke them.\n * Provide `options` to indicate whether `func` should be invoked on the\n * leading and/or trailing edge of the `wait` timeout. The `func` is invoked\n * with the last arguments provided to the debounced function. Subsequent\n * calls to the debounced function return the result of the last `func`\n * invocation.\n *\n * **Note:** If `leading` and `trailing` options are `true`, `func` is\n * invoked on the trailing edge of the timeout only if the debounced function\n * is invoked more than once during the `wait` timeout.\n *\n * If `wait` is `0` and `leading` is `false`, `func` invocation is deferred\n * until to the next tick, similar to `setTimeout` with a timeout of `0`.\n *\n * See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/)\n * for details over the differences between `_.debounce` and `_.throttle`.\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Function\n * @param {Function} func The function to debounce.\n * @param {number} [wait=0] The number of milliseconds to delay.\n * @param {Object} [options={}] The options object.\n * @param {boolean} [options.leading=false]\n * Specify invoking on the leading edge of the timeout.\n * @param {number} [options.maxWait]\n * The maximum time `func` is allowed to be delayed before it's invoked.\n * @param {boolean} [options.trailing=true]\n * Specify invoking on the trailing edge of the timeout.\n * @returns {Function} Returns the new debounced function.\n * @example\n *\n * // Avoid costly calculations while the window size is in flux.\n * jQuery(window).on('resize', _.debounce(calculateLayout, 150));\n *\n * // Invoke `sendMail` when clicked, debouncing subsequent calls.\n * jQuery(element).on('click', _.debounce(sendMail, 300, {\n * 'leading': true,\n * 'trailing': false\n * }));\n *\n * // Ensure `batchLog` is invoked once after 1 second of debounced calls.\n * var debounced = _.debounce(batchLog, 250, { 'maxWait': 1000 });\n * var source = new EventSource('/stream');\n * jQuery(source).on('message', debounced);\n *\n * // Cancel the trailing debounced invocation.\n * jQuery(window).on('popstate', debounced.cancel);\n */\nfunction debounce(func, wait, options) {\n var lastArgs,\n lastThis,\n maxWait,\n result,\n timerId,\n lastCallTime,\n lastInvokeTime = 0,\n leading = false,\n maxing = false,\n trailing = true;\n\n if (typeof func != 'function') {\n throw new TypeError(FUNC_ERROR_TEXT);\n }\n wait = toNumber(wait) || 0;\n if (isObject(options)) {\n leading = !!options.leading;\n maxing = 'maxWait' in options;\n maxWait = maxing ? nativeMax(toNumber(options.maxWait) || 0, wait) : maxWait;\n trailing = 'trailing' in options ? !!options.trailing : trailing;\n }\n\n function invokeFunc(time) {\n var args = lastArgs,\n thisArg = lastThis;\n\n lastArgs = lastThis = undefined;\n lastInvokeTime = time;\n result = func.apply(thisArg, args);\n return result;\n }\n\n function leadingEdge(time) {\n // Reset any `maxWait` timer.\n lastInvokeTime = time;\n // Start the timer for the trailing edge.\n timerId = setTimeout(timerExpired, wait);\n // Invoke the leading edge.\n return leading ? invokeFunc(time) : result;\n }\n\n function remainingWait(time) {\n var timeSinceLastCall = time - lastCallTime,\n timeSinceLastInvoke = time - lastInvokeTime,\n result = wait - timeSinceLastCall;\n\n return maxing ? nativeMin(result, maxWait - timeSinceLastInvoke) : result;\n }\n\n function shouldInvoke(time) {\n var timeSinceLastCall = time - lastCallTime,\n timeSinceLastInvoke = time - lastInvokeTime;\n\n // Either this is the first call, activity has stopped and we're at the\n // trailing edge, the system time has gone backwards and we're treating\n // it as the trailing edge, or we've hit the `maxWait` limit.\n return (lastCallTime === undefined || (timeSinceLastCall >= wait) ||\n (timeSinceLastCall < 0) || (maxing && timeSinceLastInvoke >= maxWait));\n }\n\n function timerExpired() {\n var time = now();\n if (shouldInvoke(time)) {\n return trailingEdge(time);\n }\n // Restart the timer.\n timerId = setTimeout(timerExpired, remainingWait(time));\n }\n\n function trailingEdge(time) {\n timerId = undefined;\n\n // Only invoke if we have `lastArgs` which means `func` has been\n // debounced at least once.\n if (trailing && lastArgs) {\n return invokeFunc(time);\n }\n lastArgs = lastThis = undefined;\n return result;\n }\n\n function cancel() {\n if (timerId !== undefined) {\n clearTimeout(timerId);\n }\n lastInvokeTime = 0;\n lastArgs = lastCallTime = lastThis = timerId = undefined;\n }\n\n function flush() {\n return timerId === undefined ? result : trailingEdge(now());\n }\n\n function debounced() {\n var time = now(),\n isInvoking = shouldInvoke(time);\n\n lastArgs = arguments;\n lastThis = this;\n lastCallTime = time;\n\n if (isInvoking) {\n if (timerId === undefined) {\n return leadingEdge(lastCallTime);\n }\n if (maxing) {\n // Handle invocations in a tight loop.\n timerId = setTimeout(timerExpired, wait);\n return invokeFunc(lastCallTime);\n }\n }\n if (timerId === undefined) {\n timerId = setTimeout(timerExpired, wait);\n }\n return result;\n }\n debounced.cancel = cancel;\n debounced.flush = flush;\n return debounced;\n}\n\n/**\n * Creates a throttled function that only invokes `func` at most once per\n * every `wait` milliseconds. The throttled function comes with a `cancel`\n * method to cancel delayed `func` invocations and a `flush` method to\n * immediately invoke them. Provide `options` to indicate whether `func`\n * should be invoked on the leading and/or trailing edge of the `wait`\n * timeout. The `func` is invoked with the last arguments provided to the\n * throttled function. Subsequent calls to the throttled function return the\n * result of the last `func` invocation.\n *\n * **Note:** If `leading` and `trailing` options are `true`, `func` is\n * invoked on the trailing edge of the timeout only if the throttled function\n * is invoked more than once during the `wait` timeout.\n *\n * If `wait` is `0` and `leading` is `false`, `func` invocation is deferred\n * until to the next tick, similar to `setTimeout` with a timeout of `0`.\n *\n * See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/)\n * for details over the differences between `_.throttle` and `_.debounce`.\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Function\n * @param {Function} func The function to throttle.\n * @param {number} [wait=0] The number of milliseconds to throttle invocations to.\n * @param {Object} [options={}] The options object.\n * @param {boolean} [options.leading=true]\n * Specify invoking on the leading edge of the timeout.\n * @param {boolean} [options.trailing=true]\n * Specify invoking on the trailing edge of the timeout.\n * @returns {Function} Returns the new throttled function.\n * @example\n *\n * // Avoid excessively updating the position while scrolling.\n * jQuery(window).on('scroll', _.throttle(updatePosition, 100));\n *\n * // Invoke `renewToken` when the click event is fired, but not more than once every 5 minutes.\n * var throttled = _.throttle(renewToken, 300000, { 'trailing': false });\n * jQuery(element).on('click', throttled);\n *\n * // Cancel the trailing throttled invocation.\n * jQuery(window).on('popstate', throttled.cancel);\n */\nfunction throttle(func, wait, options) {\n var leading = true,\n trailing = true;\n\n if (typeof func != 'function') {\n throw new TypeError(FUNC_ERROR_TEXT);\n }\n if (isObject(options)) {\n leading = 'leading' in options ? !!options.leading : leading;\n trailing = 'trailing' in options ? !!options.trailing : trailing;\n }\n return debounce(func, wait, {\n 'leading': leading,\n 'maxWait': wait,\n 'trailing': trailing\n });\n}\n\n/**\n * Checks if `value` is the\n * [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types)\n * of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is an object, else `false`.\n * @example\n *\n * _.isObject({});\n * // => true\n *\n * _.isObject([1, 2, 3]);\n * // => true\n *\n * _.isObject(_.noop);\n * // => true\n *\n * _.isObject(null);\n * // => false\n */\nfunction isObject(value) {\n var type = typeof value;\n return !!value && (type == 'object' || type == 'function');\n}\n\n/**\n * Checks if `value` is object-like. A value is object-like if it's not `null`\n * and has a `typeof` result of \"object\".\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is object-like, else `false`.\n * @example\n *\n * _.isObjectLike({});\n * // => true\n *\n * _.isObjectLike([1, 2, 3]);\n * // => true\n *\n * _.isObjectLike(_.noop);\n * // => false\n *\n * _.isObjectLike(null);\n * // => false\n */\nfunction isObjectLike(value) {\n return !!value && typeof value == 'object';\n}\n\n/**\n * Checks if `value` is classified as a `Symbol` primitive or object.\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a symbol, else `false`.\n * @example\n *\n * _.isSymbol(Symbol.iterator);\n * // => true\n *\n * _.isSymbol('abc');\n * // => false\n */\nfunction isSymbol(value) {\n return typeof value == 'symbol' ||\n (isObjectLike(value) && objectToString.call(value) == symbolTag);\n}\n\n/**\n * Converts `value` to a number.\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to process.\n * @returns {number} Returns the number.\n * @example\n *\n * _.toNumber(3.2);\n * // => 3.2\n *\n * _.toNumber(Number.MIN_VALUE);\n * // => 5e-324\n *\n * _.toNumber(Infinity);\n * // => Infinity\n *\n * _.toNumber('3.2');\n * // => 3.2\n */\nfunction toNumber(value) {\n if (typeof value == 'number') {\n return value;\n }\n if (isSymbol(value)) {\n return NAN;\n }\n if (isObject(value)) {\n var other = typeof value.valueOf == 'function' ? value.valueOf() : value;\n value = isObject(other) ? (other + '') : other;\n }\n if (typeof value != 'string') {\n return value === 0 ? value : +value;\n }\n value = value.replace(reTrim, '');\n var isBinary = reIsBinary.test(value);\n return (isBinary || reIsOctal.test(value))\n ? freeParseInt(value.slice(2), isBinary ? 2 : 8)\n : (reIsBadHex.test(value) ? NAN : +value);\n}\n\nmodule.exports = throttle;\n", "/**\n * lodash (Custom Build) \n * Build: `lodash modularize exports=\"npm\" -o ./`\n * Copyright jQuery Foundation and other contributors \n * Released under MIT license \n * Based on Underscore.js 1.8.3 \n * Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors\n */\n\n/** Used as the size to enable large array optimizations. */\nvar LARGE_ARRAY_SIZE = 200;\n\n/** Used to stand-in for `undefined` hash values. */\nvar HASH_UNDEFINED = '__lodash_hash_undefined__';\n\n/** Used as references for various `Number` constants. */\nvar INFINITY = 1 / 0;\n\n/** `Object#toString` result references. */\nvar funcTag = '[object Function]',\n genTag = '[object GeneratorFunction]';\n\n/**\n * Used to match `RegExp`\n * [syntax characters](http://ecma-international.org/ecma-262/7.0/#sec-patterns).\n */\nvar reRegExpChar = /[\\\\^$.*+?()[\\]{}|]/g;\n\n/** Used to detect host constructors (Safari). */\nvar reIsHostCtor = /^\\[object .+?Constructor\\]$/;\n\n/** Detect free variable `global` from Node.js. */\nvar freeGlobal = typeof global == 'object' && global && global.Object === Object && global;\n\n/** Detect free variable `self`. */\nvar freeSelf = typeof self == 'object' && self && self.Object === Object && self;\n\n/** Used as a reference to the global object. */\nvar root = freeGlobal || freeSelf || Function('return this')();\n\n/**\n * A specialized version of `_.includes` for arrays without support for\n * specifying an index to search from.\n *\n * @private\n * @param {Array} [array] The array to inspect.\n * @param {*} target The value to search for.\n * @returns {boolean} Returns `true` if `target` is found, else `false`.\n */\nfunction arrayIncludes(array, value) {\n var length = array ? array.length : 0;\n return !!length && baseIndexOf(array, value, 0) > -1;\n}\n\n/**\n * This function is like `arrayIncludes` except that it accepts a comparator.\n *\n * @private\n * @param {Array} [array] The array to inspect.\n * @param {*} target The value to search for.\n * @param {Function} comparator The comparator invoked per element.\n * @returns {boolean} Returns `true` if `target` is found, else `false`.\n */\nfunction arrayIncludesWith(array, value, comparator) {\n var index = -1,\n length = array ? array.length : 0;\n\n while (++index < length) {\n if (comparator(value, array[index])) {\n return true;\n }\n }\n return false;\n}\n\n/**\n * The base implementation of `_.findIndex` and `_.findLastIndex` without\n * support for iteratee shorthands.\n *\n * @private\n * @param {Array} array The array to inspect.\n * @param {Function} predicate The function invoked per iteration.\n * @param {number} fromIndex The index to search from.\n * @param {boolean} [fromRight] Specify iterating from right to left.\n * @returns {number} Returns the index of the matched value, else `-1`.\n */\nfunction baseFindIndex(array, predicate, fromIndex, fromRight) {\n var length = array.length,\n index = fromIndex + (fromRight ? 1 : -1);\n\n while ((fromRight ? index-- : ++index < length)) {\n if (predicate(array[index], index, array)) {\n return index;\n }\n }\n return -1;\n}\n\n/**\n * The base implementation of `_.indexOf` without `fromIndex` bounds checks.\n *\n * @private\n * @param {Array} array The array to inspect.\n * @param {*} value The value to search for.\n * @param {number} fromIndex The index to search from.\n * @returns {number} Returns the index of the matched value, else `-1`.\n */\nfunction baseIndexOf(array, value, fromIndex) {\n if (value !== value) {\n return baseFindIndex(array, baseIsNaN, fromIndex);\n }\n var index = fromIndex - 1,\n length = array.length;\n\n while (++index < length) {\n if (array[index] === value) {\n return index;\n }\n }\n return -1;\n}\n\n/**\n * The base implementation of `_.isNaN` without support for number objects.\n *\n * @private\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is `NaN`, else `false`.\n */\nfunction baseIsNaN(value) {\n return value !== value;\n}\n\n/**\n * Checks if a cache value for `key` exists.\n *\n * @private\n * @param {Object} cache The cache to query.\n * @param {string} key The key of the entry to check.\n * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.\n */\nfunction cacheHas(cache, key) {\n return cache.has(key);\n}\n\n/**\n * Gets the value at `key` of `object`.\n *\n * @private\n * @param {Object} [object] The object to query.\n * @param {string} key The key of the property to get.\n * @returns {*} Returns the property value.\n */\nfunction getValue(object, key) {\n return object == null ? undefined : object[key];\n}\n\n/**\n * Checks if `value` is a host object in IE < 9.\n *\n * @private\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a host object, else `false`.\n */\nfunction isHostObject(value) {\n // Many host objects are `Object` objects that can coerce to strings\n // despite having improperly defined `toString` methods.\n var result = false;\n if (value != null && typeof value.toString != 'function') {\n try {\n result = !!(value + '');\n } catch (e) {}\n }\n return result;\n}\n\n/**\n * Converts `set` to an array of its values.\n *\n * @private\n * @param {Object} set The set to convert.\n * @returns {Array} Returns the values.\n */\nfunction setToArray(set) {\n var index = -1,\n result = Array(set.size);\n\n set.forEach(function(value) {\n result[++index] = value;\n });\n return result;\n}\n\n/** Used for built-in method references. */\nvar arrayProto = Array.prototype,\n funcProto = Function.prototype,\n objectProto = Object.prototype;\n\n/** Used to detect overreaching core-js shims. */\nvar coreJsData = root['__core-js_shared__'];\n\n/** Used to detect methods masquerading as native. */\nvar maskSrcKey = (function() {\n var uid = /[^.]+$/.exec(coreJsData && coreJsData.keys && coreJsData.keys.IE_PROTO || '');\n return uid ? ('Symbol(src)_1.' + uid) : '';\n}());\n\n/** Used to resolve the decompiled source of functions. */\nvar funcToString = funcProto.toString;\n\n/** Used to check objects for own properties. */\nvar hasOwnProperty = objectProto.hasOwnProperty;\n\n/**\n * Used to resolve the\n * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)\n * of values.\n */\nvar objectToString = objectProto.toString;\n\n/** Used to detect if a method is native. */\nvar reIsNative = RegExp('^' +\n funcToString.call(hasOwnProperty).replace(reRegExpChar, '\\\\$&')\n .replace(/hasOwnProperty|(function).*?(?=\\\\\\()| for .+?(?=\\\\\\])/g, '$1.*?') + '$'\n);\n\n/** Built-in value references. */\nvar splice = arrayProto.splice;\n\n/* Built-in method references that are verified to be native. */\nvar Map = getNative(root, 'Map'),\n Set = getNative(root, 'Set'),\n nativeCreate = getNative(Object, 'create');\n\n/**\n * Creates a hash object.\n *\n * @private\n * @constructor\n * @param {Array} [entries] The key-value pairs to cache.\n */\nfunction Hash(entries) {\n var index = -1,\n length = entries ? entries.length : 0;\n\n this.clear();\n while (++index < length) {\n var entry = entries[index];\n this.set(entry[0], entry[1]);\n }\n}\n\n/**\n * Removes all key-value entries from the hash.\n *\n * @private\n * @name clear\n * @memberOf Hash\n */\nfunction hashClear() {\n this.__data__ = nativeCreate ? nativeCreate(null) : {};\n}\n\n/**\n * Removes `key` and its value from the hash.\n *\n * @private\n * @name delete\n * @memberOf Hash\n * @param {Object} hash The hash to modify.\n * @param {string} key The key of the value to remove.\n * @returns {boolean} Returns `true` if the entry was removed, else `false`.\n */\nfunction hashDelete(key) {\n return this.has(key) && delete this.__data__[key];\n}\n\n/**\n * Gets the hash value for `key`.\n *\n * @private\n * @name get\n * @memberOf Hash\n * @param {string} key The key of the value to get.\n * @returns {*} Returns the entry value.\n */\nfunction hashGet(key) {\n var data = this.__data__;\n if (nativeCreate) {\n var result = data[key];\n return result === HASH_UNDEFINED ? undefined : result;\n }\n return hasOwnProperty.call(data, key) ? data[key] : undefined;\n}\n\n/**\n * Checks if a hash value for `key` exists.\n *\n * @private\n * @name has\n * @memberOf Hash\n * @param {string} key The key of the entry to check.\n * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.\n */\nfunction hashHas(key) {\n var data = this.__data__;\n return nativeCreate ? data[key] !== undefined : hasOwnProperty.call(data, key);\n}\n\n/**\n * Sets the hash `key` to `value`.\n *\n * @private\n * @name set\n * @memberOf Hash\n * @param {string} key The key of the value to set.\n * @param {*} value The value to set.\n * @returns {Object} Returns the hash instance.\n */\nfunction hashSet(key, value) {\n var data = this.__data__;\n data[key] = (nativeCreate && value === undefined) ? HASH_UNDEFINED : value;\n return this;\n}\n\n// Add methods to `Hash`.\nHash.prototype.clear = hashClear;\nHash.prototype['delete'] = hashDelete;\nHash.prototype.get = hashGet;\nHash.prototype.has = hashHas;\nHash.prototype.set = hashSet;\n\n/**\n * Creates an list cache object.\n *\n * @private\n * @constructor\n * @param {Array} [entries] The key-value pairs to cache.\n */\nfunction ListCache(entries) {\n var index = -1,\n length = entries ? entries.length : 0;\n\n this.clear();\n while (++index < length) {\n var entry = entries[index];\n this.set(entry[0], entry[1]);\n }\n}\n\n/**\n * Removes all key-value entries from the list cache.\n *\n * @private\n * @name clear\n * @memberOf ListCache\n */\nfunction listCacheClear() {\n this.__data__ = [];\n}\n\n/**\n * Removes `key` and its value from the list cache.\n *\n * @private\n * @name delete\n * @memberOf ListCache\n * @param {string} key The key of the value to remove.\n * @returns {boolean} Returns `true` if the entry was removed, else `false`.\n */\nfunction listCacheDelete(key) {\n var data = this.__data__,\n index = assocIndexOf(data, key);\n\n if (index < 0) {\n return false;\n }\n var lastIndex = data.length - 1;\n if (index == lastIndex) {\n data.pop();\n } else {\n splice.call(data, index, 1);\n }\n return true;\n}\n\n/**\n * Gets the list cache value for `key`.\n *\n * @private\n * @name get\n * @memberOf ListCache\n * @param {string} key The key of the value to get.\n * @returns {*} Returns the entry value.\n */\nfunction listCacheGet(key) {\n var data = this.__data__,\n index = assocIndexOf(data, key);\n\n return index < 0 ? undefined : data[index][1];\n}\n\n/**\n * Checks if a list cache value for `key` exists.\n *\n * @private\n * @name has\n * @memberOf ListCache\n * @param {string} key The key of the entry to check.\n * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.\n */\nfunction listCacheHas(key) {\n return assocIndexOf(this.__data__, key) > -1;\n}\n\n/**\n * Sets the list cache `key` to `value`.\n *\n * @private\n * @name set\n * @memberOf ListCache\n * @param {string} key The key of the value to set.\n * @param {*} value The value to set.\n * @returns {Object} Returns the list cache instance.\n */\nfunction listCacheSet(key, value) {\n var data = this.__data__,\n index = assocIndexOf(data, key);\n\n if (index < 0) {\n data.push([key, value]);\n } else {\n data[index][1] = value;\n }\n return this;\n}\n\n// Add methods to `ListCache`.\nListCache.prototype.clear = listCacheClear;\nListCache.prototype['delete'] = listCacheDelete;\nListCache.prototype.get = listCacheGet;\nListCache.prototype.has = listCacheHas;\nListCache.prototype.set = listCacheSet;\n\n/**\n * Creates a map cache object to store key-value pairs.\n *\n * @private\n * @constructor\n * @param {Array} [entries] The key-value pairs to cache.\n */\nfunction MapCache(entries) {\n var index = -1,\n length = entries ? entries.length : 0;\n\n this.clear();\n while (++index < length) {\n var entry = entries[index];\n this.set(entry[0], entry[1]);\n }\n}\n\n/**\n * Removes all key-value entries from the map.\n *\n * @private\n * @name clear\n * @memberOf MapCache\n */\nfunction mapCacheClear() {\n this.__data__ = {\n 'hash': new Hash,\n 'map': new (Map || ListCache),\n 'string': new Hash\n };\n}\n\n/**\n * Removes `key` and its value from the map.\n *\n * @private\n * @name delete\n * @memberOf MapCache\n * @param {string} key The key of the value to remove.\n * @returns {boolean} Returns `true` if the entry was removed, else `false`.\n */\nfunction mapCacheDelete(key) {\n return getMapData(this, key)['delete'](key);\n}\n\n/**\n * Gets the map value for `key`.\n *\n * @private\n * @name get\n * @memberOf MapCache\n * @param {string} key The key of the value to get.\n * @returns {*} Returns the entry value.\n */\nfunction mapCacheGet(key) {\n return getMapData(this, key).get(key);\n}\n\n/**\n * Checks if a map value for `key` exists.\n *\n * @private\n * @name has\n * @memberOf MapCache\n * @param {string} key The key of the entry to check.\n * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.\n */\nfunction mapCacheHas(key) {\n return getMapData(this, key).has(key);\n}\n\n/**\n * Sets the map `key` to `value`.\n *\n * @private\n * @name set\n * @memberOf MapCache\n * @param {string} key The key of the value to set.\n * @param {*} value The value to set.\n * @returns {Object} Returns the map cache instance.\n */\nfunction mapCacheSet(key, value) {\n getMapData(this, key).set(key, value);\n return this;\n}\n\n// Add methods to `MapCache`.\nMapCache.prototype.clear = mapCacheClear;\nMapCache.prototype['delete'] = mapCacheDelete;\nMapCache.prototype.get = mapCacheGet;\nMapCache.prototype.has = mapCacheHas;\nMapCache.prototype.set = mapCacheSet;\n\n/**\n *\n * Creates an array cache object to store unique values.\n *\n * @private\n * @constructor\n * @param {Array} [values] The values to cache.\n */\nfunction SetCache(values) {\n var index = -1,\n length = values ? values.length : 0;\n\n this.__data__ = new MapCache;\n while (++index < length) {\n this.add(values[index]);\n }\n}\n\n/**\n * Adds `value` to the array cache.\n *\n * @private\n * @name add\n * @memberOf SetCache\n * @alias push\n * @param {*} value The value to cache.\n * @returns {Object} Returns the cache instance.\n */\nfunction setCacheAdd(value) {\n this.__data__.set(value, HASH_UNDEFINED);\n return this;\n}\n\n/**\n * Checks if `value` is in the array cache.\n *\n * @private\n * @name has\n * @memberOf SetCache\n * @param {*} value The value to search for.\n * @returns {number} Returns `true` if `value` is found, else `false`.\n */\nfunction setCacheHas(value) {\n return this.__data__.has(value);\n}\n\n// Add methods to `SetCache`.\nSetCache.prototype.add = SetCache.prototype.push = setCacheAdd;\nSetCache.prototype.has = setCacheHas;\n\n/**\n * Gets the index at which the `key` is found in `array` of key-value pairs.\n *\n * @private\n * @param {Array} array The array to inspect.\n * @param {*} key The key to search for.\n * @returns {number} Returns the index of the matched value, else `-1`.\n */\nfunction assocIndexOf(array, key) {\n var length = array.length;\n while (length--) {\n if (eq(array[length][0], key)) {\n return length;\n }\n }\n return -1;\n}\n\n/**\n * The base implementation of `_.isNative` without bad shim checks.\n *\n * @private\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a native function,\n * else `false`.\n */\nfunction baseIsNative(value) {\n if (!isObject(value) || isMasked(value)) {\n return false;\n }\n var pattern = (isFunction(value) || isHostObject(value)) ? reIsNative : reIsHostCtor;\n return pattern.test(toSource(value));\n}\n\n/**\n * The base implementation of `_.uniqBy` without support for iteratee shorthands.\n *\n * @private\n * @param {Array} array The array to inspect.\n * @param {Function} [iteratee] The iteratee invoked per element.\n * @param {Function} [comparator] The comparator invoked per element.\n * @returns {Array} Returns the new duplicate free array.\n */\nfunction baseUniq(array, iteratee, comparator) {\n var index = -1,\n includes = arrayIncludes,\n length = array.length,\n isCommon = true,\n result = [],\n seen = result;\n\n if (comparator) {\n isCommon = false;\n includes = arrayIncludesWith;\n }\n else if (length >= LARGE_ARRAY_SIZE) {\n var set = iteratee ? null : createSet(array);\n if (set) {\n return setToArray(set);\n }\n isCommon = false;\n includes = cacheHas;\n seen = new SetCache;\n }\n else {\n seen = iteratee ? [] : result;\n }\n outer:\n while (++index < length) {\n var value = array[index],\n computed = iteratee ? iteratee(value) : value;\n\n value = (comparator || value !== 0) ? value : 0;\n if (isCommon && computed === computed) {\n var seenIndex = seen.length;\n while (seenIndex--) {\n if (seen[seenIndex] === computed) {\n continue outer;\n }\n }\n if (iteratee) {\n seen.push(computed);\n }\n result.push(value);\n }\n else if (!includes(seen, computed, comparator)) {\n if (seen !== result) {\n seen.push(computed);\n }\n result.push(value);\n }\n }\n return result;\n}\n\n/**\n * Creates a set object of `values`.\n *\n * @private\n * @param {Array} values The values to add to the set.\n * @returns {Object} Returns the new set.\n */\nvar createSet = !(Set && (1 / setToArray(new Set([,-0]))[1]) == INFINITY) ? noop : function(values) {\n return new Set(values);\n};\n\n/**\n * Gets the data for `map`.\n *\n * @private\n * @param {Object} map The map to query.\n * @param {string} key The reference key.\n * @returns {*} Returns the map data.\n */\nfunction getMapData(map, key) {\n var data = map.__data__;\n return isKeyable(key)\n ? data[typeof key == 'string' ? 'string' : 'hash']\n : data.map;\n}\n\n/**\n * Gets the native function at `key` of `object`.\n *\n * @private\n * @param {Object} object The object to query.\n * @param {string} key The key of the method to get.\n * @returns {*} Returns the function if it's native, else `undefined`.\n */\nfunction getNative(object, key) {\n var value = getValue(object, key);\n return baseIsNative(value) ? value : undefined;\n}\n\n/**\n * Checks if `value` is suitable for use as unique object key.\n *\n * @private\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is suitable, else `false`.\n */\nfunction isKeyable(value) {\n var type = typeof value;\n return (type == 'string' || type == 'number' || type == 'symbol' || type == 'boolean')\n ? (value !== '__proto__')\n : (value === null);\n}\n\n/**\n * Checks if `func` has its source masked.\n *\n * @private\n * @param {Function} func The function to check.\n * @returns {boolean} Returns `true` if `func` is masked, else `false`.\n */\nfunction isMasked(func) {\n return !!maskSrcKey && (maskSrcKey in func);\n}\n\n/**\n * Converts `func` to its source code.\n *\n * @private\n * @param {Function} func The function to process.\n * @returns {string} Returns the source code.\n */\nfunction toSource(func) {\n if (func != null) {\n try {\n return funcToString.call(func);\n } catch (e) {}\n try {\n return (func + '');\n } catch (e) {}\n }\n return '';\n}\n\n/**\n * Creates a duplicate-free version of an array, using\n * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)\n * for equality comparisons, in which only the first occurrence of each\n * element is kept.\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Array\n * @param {Array} array The array to inspect.\n * @returns {Array} Returns the new duplicate free array.\n * @example\n *\n * _.uniq([2, 1, 2]);\n * // => [2, 1]\n */\nfunction uniq(array) {\n return (array && array.length)\n ? baseUniq(array)\n : [];\n}\n\n/**\n * Performs a\n * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)\n * comparison between two values to determine if they are equivalent.\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to compare.\n * @param {*} other The other value to compare.\n * @returns {boolean} Returns `true` if the values are equivalent, else `false`.\n * @example\n *\n * var object = { 'a': 1 };\n * var other = { 'a': 1 };\n *\n * _.eq(object, object);\n * // => true\n *\n * _.eq(object, other);\n * // => false\n *\n * _.eq('a', 'a');\n * // => true\n *\n * _.eq('a', Object('a'));\n * // => false\n *\n * _.eq(NaN, NaN);\n * // => true\n */\nfunction eq(value, other) {\n return value === other || (value !== value && other !== other);\n}\n\n/**\n * Checks if `value` is classified as a `Function` object.\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a function, else `false`.\n * @example\n *\n * _.isFunction(_);\n * // => true\n *\n * _.isFunction(/abc/);\n * // => false\n */\nfunction isFunction(value) {\n // The use of `Object#toString` avoids issues with the `typeof` operator\n // in Safari 8-9 which returns 'object' for typed array and other constructors.\n var tag = isObject(value) ? objectToString.call(value) : '';\n return tag == funcTag || tag == genTag;\n}\n\n/**\n * Checks if `value` is the\n * [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types)\n * of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is an object, else `false`.\n * @example\n *\n * _.isObject({});\n * // => true\n *\n * _.isObject([1, 2, 3]);\n * // => true\n *\n * _.isObject(_.noop);\n * // => true\n *\n * _.isObject(null);\n * // => false\n */\nfunction isObject(value) {\n var type = typeof value;\n return !!value && (type == 'object' || type == 'function');\n}\n\n/**\n * This method returns `undefined`.\n *\n * @static\n * @memberOf _\n * @since 2.3.0\n * @category Util\n * @example\n *\n * _.times(2, _.noop);\n * // => [undefined, undefined]\n */\nfunction noop() {\n // No operation performed.\n}\n\nmodule.exports = uniq;\n", "/**\n * Lodash (Custom Build) \n * Build: `lodash modularize exports=\"npm\" -o ./`\n * Copyright JS Foundation and other contributors \n * Released under MIT license \n * Based on Underscore.js 1.8.3 \n * Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors\n */\n\n/** Used as the size to enable large array optimizations. */\nvar LARGE_ARRAY_SIZE = 200;\n\n/** Used to stand-in for `undefined` hash values. */\nvar HASH_UNDEFINED = '__lodash_hash_undefined__';\n\n/** Used to compose bitmasks for value comparisons. */\nvar COMPARE_PARTIAL_FLAG = 1,\n COMPARE_UNORDERED_FLAG = 2;\n\n/** Used as references for various `Number` constants. */\nvar MAX_SAFE_INTEGER = 9007199254740991;\n\n/** `Object#toString` result references. */\nvar argsTag = '[object Arguments]',\n arrayTag = '[object Array]',\n asyncTag = '[object AsyncFunction]',\n boolTag = '[object Boolean]',\n dateTag = '[object Date]',\n errorTag = '[object Error]',\n funcTag = '[object Function]',\n genTag = '[object GeneratorFunction]',\n mapTag = '[object Map]',\n numberTag = '[object Number]',\n nullTag = '[object Null]',\n objectTag = '[object Object]',\n promiseTag = '[object Promise]',\n proxyTag = '[object Proxy]',\n regexpTag = '[object RegExp]',\n setTag = '[object Set]',\n stringTag = '[object String]',\n symbolTag = '[object Symbol]',\n undefinedTag = '[object Undefined]',\n weakMapTag = '[object WeakMap]';\n\nvar arrayBufferTag = '[object ArrayBuffer]',\n dataViewTag = '[object DataView]',\n float32Tag = '[object Float32Array]',\n float64Tag = '[object Float64Array]',\n int8Tag = '[object Int8Array]',\n int16Tag = '[object Int16Array]',\n int32Tag = '[object Int32Array]',\n uint8Tag = '[object Uint8Array]',\n uint8ClampedTag = '[object Uint8ClampedArray]',\n uint16Tag = '[object Uint16Array]',\n uint32Tag = '[object Uint32Array]';\n\n/**\n * Used to match `RegExp`\n * [syntax characters](http://ecma-international.org/ecma-262/7.0/#sec-patterns).\n */\nvar reRegExpChar = /[\\\\^$.*+?()[\\]{}|]/g;\n\n/** Used to detect host constructors (Safari). */\nvar reIsHostCtor = /^\\[object .+?Constructor\\]$/;\n\n/** Used to detect unsigned integer values. */\nvar reIsUint = /^(?:0|[1-9]\\d*)$/;\n\n/** Used to identify `toStringTag` values of typed arrays. */\nvar typedArrayTags = {};\ntypedArrayTags[float32Tag] = typedArrayTags[float64Tag] =\ntypedArrayTags[int8Tag] = typedArrayTags[int16Tag] =\ntypedArrayTags[int32Tag] = typedArrayTags[uint8Tag] =\ntypedArrayTags[uint8ClampedTag] = typedArrayTags[uint16Tag] =\ntypedArrayTags[uint32Tag] = true;\ntypedArrayTags[argsTag] = typedArrayTags[arrayTag] =\ntypedArrayTags[arrayBufferTag] = typedArrayTags[boolTag] =\ntypedArrayTags[dataViewTag] = typedArrayTags[dateTag] =\ntypedArrayTags[errorTag] = typedArrayTags[funcTag] =\ntypedArrayTags[mapTag] = typedArrayTags[numberTag] =\ntypedArrayTags[objectTag] = typedArrayTags[regexpTag] =\ntypedArrayTags[setTag] = typedArrayTags[stringTag] =\ntypedArrayTags[weakMapTag] = false;\n\n/** Detect free variable `global` from Node.js. */\nvar freeGlobal = typeof global == 'object' && global && global.Object === Object && global;\n\n/** Detect free variable `self`. */\nvar freeSelf = typeof self == 'object' && self && self.Object === Object && self;\n\n/** Used as a reference to the global object. */\nvar root = freeGlobal || freeSelf || Function('return this')();\n\n/** Detect free variable `exports`. */\nvar freeExports = typeof exports == 'object' && exports && !exports.nodeType && exports;\n\n/** Detect free variable `module`. */\nvar freeModule = freeExports && typeof module == 'object' && module && !module.nodeType && module;\n\n/** Detect the popular CommonJS extension `module.exports`. */\nvar moduleExports = freeModule && freeModule.exports === freeExports;\n\n/** Detect free variable `process` from Node.js. */\nvar freeProcess = moduleExports && freeGlobal.process;\n\n/** Used to access faster Node.js helpers. */\nvar nodeUtil = (function() {\n try {\n return freeProcess && freeProcess.binding && freeProcess.binding('util');\n } catch (e) {}\n}());\n\n/* Node.js helper references. */\nvar nodeIsTypedArray = nodeUtil && nodeUtil.isTypedArray;\n\n/**\n * A specialized version of `_.filter` for arrays without support for\n * iteratee shorthands.\n *\n * @private\n * @param {Array} [array] The array to iterate over.\n * @param {Function} predicate The function invoked per iteration.\n * @returns {Array} Returns the new filtered array.\n */\nfunction arrayFilter(array, predicate) {\n var index = -1,\n length = array == null ? 0 : array.length,\n resIndex = 0,\n result = [];\n\n while (++index < length) {\n var value = array[index];\n if (predicate(value, index, array)) {\n result[resIndex++] = value;\n }\n }\n return result;\n}\n\n/**\n * Appends the elements of `values` to `array`.\n *\n * @private\n * @param {Array} array The array to modify.\n * @param {Array} values The values to append.\n * @returns {Array} Returns `array`.\n */\nfunction arrayPush(array, values) {\n var index = -1,\n length = values.length,\n offset = array.length;\n\n while (++index < length) {\n array[offset + index] = values[index];\n }\n return array;\n}\n\n/**\n * A specialized version of `_.some` for arrays without support for iteratee\n * shorthands.\n *\n * @private\n * @param {Array} [array] The array to iterate over.\n * @param {Function} predicate The function invoked per iteration.\n * @returns {boolean} Returns `true` if any element passes the predicate check,\n * else `false`.\n */\nfunction arraySome(array, predicate) {\n var index = -1,\n length = array == null ? 0 : array.length;\n\n while (++index < length) {\n if (predicate(array[index], index, array)) {\n return true;\n }\n }\n return false;\n}\n\n/**\n * The base implementation of `_.times` without support for iteratee shorthands\n * or max array length checks.\n *\n * @private\n * @param {number} n The number of times to invoke `iteratee`.\n * @param {Function} iteratee The function invoked per iteration.\n * @returns {Array} Returns the array of results.\n */\nfunction baseTimes(n, iteratee) {\n var index = -1,\n result = Array(n);\n\n while (++index < n) {\n result[index] = iteratee(index);\n }\n return result;\n}\n\n/**\n * The base implementation of `_.unary` without support for storing metadata.\n *\n * @private\n * @param {Function} func The function to cap arguments for.\n * @returns {Function} Returns the new capped function.\n */\nfunction baseUnary(func) {\n return function(value) {\n return func(value);\n };\n}\n\n/**\n * Checks if a `cache` value for `key` exists.\n *\n * @private\n * @param {Object} cache The cache to query.\n * @param {string} key The key of the entry to check.\n * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.\n */\nfunction cacheHas(cache, key) {\n return cache.has(key);\n}\n\n/**\n * Gets the value at `key` of `object`.\n *\n * @private\n * @param {Object} [object] The object to query.\n * @param {string} key The key of the property to get.\n * @returns {*} Returns the property value.\n */\nfunction getValue(object, key) {\n return object == null ? undefined : object[key];\n}\n\n/**\n * Converts `map` to its key-value pairs.\n *\n * @private\n * @param {Object} map The map to convert.\n * @returns {Array} Returns the key-value pairs.\n */\nfunction mapToArray(map) {\n var index = -1,\n result = Array(map.size);\n\n map.forEach(function(value, key) {\n result[++index] = [key, value];\n });\n return result;\n}\n\n/**\n * Creates a unary function that invokes `func` with its argument transformed.\n *\n * @private\n * @param {Function} func The function to wrap.\n * @param {Function} transform The argument transform.\n * @returns {Function} Returns the new function.\n */\nfunction overArg(func, transform) {\n return function(arg) {\n return func(transform(arg));\n };\n}\n\n/**\n * Converts `set` to an array of its values.\n *\n * @private\n * @param {Object} set The set to convert.\n * @returns {Array} Returns the values.\n */\nfunction setToArray(set) {\n var index = -1,\n result = Array(set.size);\n\n set.forEach(function(value) {\n result[++index] = value;\n });\n return result;\n}\n\n/** Used for built-in method references. */\nvar arrayProto = Array.prototype,\n funcProto = Function.prototype,\n objectProto = Object.prototype;\n\n/** Used to detect overreaching core-js shims. */\nvar coreJsData = root['__core-js_shared__'];\n\n/** Used to resolve the decompiled source of functions. */\nvar funcToString = funcProto.toString;\n\n/** Used to check objects for own properties. */\nvar hasOwnProperty = objectProto.hasOwnProperty;\n\n/** Used to detect methods masquerading as native. */\nvar maskSrcKey = (function() {\n var uid = /[^.]+$/.exec(coreJsData && coreJsData.keys && coreJsData.keys.IE_PROTO || '');\n return uid ? ('Symbol(src)_1.' + uid) : '';\n}());\n\n/**\n * Used to resolve the\n * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)\n * of values.\n */\nvar nativeObjectToString = objectProto.toString;\n\n/** Used to detect if a method is native. */\nvar reIsNative = RegExp('^' +\n funcToString.call(hasOwnProperty).replace(reRegExpChar, '\\\\$&')\n .replace(/hasOwnProperty|(function).*?(?=\\\\\\()| for .+?(?=\\\\\\])/g, '$1.*?') + '$'\n);\n\n/** Built-in value references. */\nvar Buffer = moduleExports ? root.Buffer : undefined,\n Symbol = root.Symbol,\n Uint8Array = root.Uint8Array,\n propertyIsEnumerable = objectProto.propertyIsEnumerable,\n splice = arrayProto.splice,\n symToStringTag = Symbol ? Symbol.toStringTag : undefined;\n\n/* Built-in method references for those with the same name as other `lodash` methods. */\nvar nativeGetSymbols = Object.getOwnPropertySymbols,\n nativeIsBuffer = Buffer ? Buffer.isBuffer : undefined,\n nativeKeys = overArg(Object.keys, Object);\n\n/* Built-in method references that are verified to be native. */\nvar DataView = getNative(root, 'DataView'),\n Map = getNative(root, 'Map'),\n Promise = getNative(root, 'Promise'),\n Set = getNative(root, 'Set'),\n WeakMap = getNative(root, 'WeakMap'),\n nativeCreate = getNative(Object, 'create');\n\n/** Used to detect maps, sets, and weakmaps. */\nvar dataViewCtorString = toSource(DataView),\n mapCtorString = toSource(Map),\n promiseCtorString = toSource(Promise),\n setCtorString = toSource(Set),\n weakMapCtorString = toSource(WeakMap);\n\n/** Used to convert symbols to primitives and strings. */\nvar symbolProto = Symbol ? Symbol.prototype : undefined,\n symbolValueOf = symbolProto ? symbolProto.valueOf : undefined;\n\n/**\n * Creates a hash object.\n *\n * @private\n * @constructor\n * @param {Array} [entries] The key-value pairs to cache.\n */\nfunction Hash(entries) {\n var index = -1,\n length = entries == null ? 0 : entries.length;\n\n this.clear();\n while (++index < length) {\n var entry = entries[index];\n this.set(entry[0], entry[1]);\n }\n}\n\n/**\n * Removes all key-value entries from the hash.\n *\n * @private\n * @name clear\n * @memberOf Hash\n */\nfunction hashClear() {\n this.__data__ = nativeCreate ? nativeCreate(null) : {};\n this.size = 0;\n}\n\n/**\n * Removes `key` and its value from the hash.\n *\n * @private\n * @name delete\n * @memberOf Hash\n * @param {Object} hash The hash to modify.\n * @param {string} key The key of the value to remove.\n * @returns {boolean} Returns `true` if the entry was removed, else `false`.\n */\nfunction hashDelete(key) {\n var result = this.has(key) && delete this.__data__[key];\n this.size -= result ? 1 : 0;\n return result;\n}\n\n/**\n * Gets the hash value for `key`.\n *\n * @private\n * @name get\n * @memberOf Hash\n * @param {string} key The key of the value to get.\n * @returns {*} Returns the entry value.\n */\nfunction hashGet(key) {\n var data = this.__data__;\n if (nativeCreate) {\n var result = data[key];\n return result === HASH_UNDEFINED ? undefined : result;\n }\n return hasOwnProperty.call(data, key) ? data[key] : undefined;\n}\n\n/**\n * Checks if a hash value for `key` exists.\n *\n * @private\n * @name has\n * @memberOf Hash\n * @param {string} key The key of the entry to check.\n * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.\n */\nfunction hashHas(key) {\n var data = this.__data__;\n return nativeCreate ? (data[key] !== undefined) : hasOwnProperty.call(data, key);\n}\n\n/**\n * Sets the hash `key` to `value`.\n *\n * @private\n * @name set\n * @memberOf Hash\n * @param {string} key The key of the value to set.\n * @param {*} value The value to set.\n * @returns {Object} Returns the hash instance.\n */\nfunction hashSet(key, value) {\n var data = this.__data__;\n this.size += this.has(key) ? 0 : 1;\n data[key] = (nativeCreate && value === undefined) ? HASH_UNDEFINED : value;\n return this;\n}\n\n// Add methods to `Hash`.\nHash.prototype.clear = hashClear;\nHash.prototype['delete'] = hashDelete;\nHash.prototype.get = hashGet;\nHash.prototype.has = hashHas;\nHash.prototype.set = hashSet;\n\n/**\n * Creates an list cache object.\n *\n * @private\n * @constructor\n * @param {Array} [entries] The key-value pairs to cache.\n */\nfunction ListCache(entries) {\n var index = -1,\n length = entries == null ? 0 : entries.length;\n\n this.clear();\n while (++index < length) {\n var entry = entries[index];\n this.set(entry[0], entry[1]);\n }\n}\n\n/**\n * Removes all key-value entries from the list cache.\n *\n * @private\n * @name clear\n * @memberOf ListCache\n */\nfunction listCacheClear() {\n this.__data__ = [];\n this.size = 0;\n}\n\n/**\n * Removes `key` and its value from the list cache.\n *\n * @private\n * @name delete\n * @memberOf ListCache\n * @param {string} key The key of the value to remove.\n * @returns {boolean} Returns `true` if the entry was removed, else `false`.\n */\nfunction listCacheDelete(key) {\n var data = this.__data__,\n index = assocIndexOf(data, key);\n\n if (index < 0) {\n return false;\n }\n var lastIndex = data.length - 1;\n if (index == lastIndex) {\n data.pop();\n } else {\n splice.call(data, index, 1);\n }\n --this.size;\n return true;\n}\n\n/**\n * Gets the list cache value for `key`.\n *\n * @private\n * @name get\n * @memberOf ListCache\n * @param {string} key The key of the value to get.\n * @returns {*} Returns the entry value.\n */\nfunction listCacheGet(key) {\n var data = this.__data__,\n index = assocIndexOf(data, key);\n\n return index < 0 ? undefined : data[index][1];\n}\n\n/**\n * Checks if a list cache value for `key` exists.\n *\n * @private\n * @name has\n * @memberOf ListCache\n * @param {string} key The key of the entry to check.\n * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.\n */\nfunction listCacheHas(key) {\n return assocIndexOf(this.__data__, key) > -1;\n}\n\n/**\n * Sets the list cache `key` to `value`.\n *\n * @private\n * @name set\n * @memberOf ListCache\n * @param {string} key The key of the value to set.\n * @param {*} value The value to set.\n * @returns {Object} Returns the list cache instance.\n */\nfunction listCacheSet(key, value) {\n var data = this.__data__,\n index = assocIndexOf(data, key);\n\n if (index < 0) {\n ++this.size;\n data.push([key, value]);\n } else {\n data[index][1] = value;\n }\n return this;\n}\n\n// Add methods to `ListCache`.\nListCache.prototype.clear = listCacheClear;\nListCache.prototype['delete'] = listCacheDelete;\nListCache.prototype.get = listCacheGet;\nListCache.prototype.has = listCacheHas;\nListCache.prototype.set = listCacheSet;\n\n/**\n * Creates a map cache object to store key-value pairs.\n *\n * @private\n * @constructor\n * @param {Array} [entries] The key-value pairs to cache.\n */\nfunction MapCache(entries) {\n var index = -1,\n length = entries == null ? 0 : entries.length;\n\n this.clear();\n while (++index < length) {\n var entry = entries[index];\n this.set(entry[0], entry[1]);\n }\n}\n\n/**\n * Removes all key-value entries from the map.\n *\n * @private\n * @name clear\n * @memberOf MapCache\n */\nfunction mapCacheClear() {\n this.size = 0;\n this.__data__ = {\n 'hash': new Hash,\n 'map': new (Map || ListCache),\n 'string': new Hash\n };\n}\n\n/**\n * Removes `key` and its value from the map.\n *\n * @private\n * @name delete\n * @memberOf MapCache\n * @param {string} key The key of the value to remove.\n * @returns {boolean} Returns `true` if the entry was removed, else `false`.\n */\nfunction mapCacheDelete(key) {\n var result = getMapData(this, key)['delete'](key);\n this.size -= result ? 1 : 0;\n return result;\n}\n\n/**\n * Gets the map value for `key`.\n *\n * @private\n * @name get\n * @memberOf MapCache\n * @param {string} key The key of the value to get.\n * @returns {*} Returns the entry value.\n */\nfunction mapCacheGet(key) {\n return getMapData(this, key).get(key);\n}\n\n/**\n * Checks if a map value for `key` exists.\n *\n * @private\n * @name has\n * @memberOf MapCache\n * @param {string} key The key of the entry to check.\n * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.\n */\nfunction mapCacheHas(key) {\n return getMapData(this, key).has(key);\n}\n\n/**\n * Sets the map `key` to `value`.\n *\n * @private\n * @name set\n * @memberOf MapCache\n * @param {string} key The key of the value to set.\n * @param {*} value The value to set.\n * @returns {Object} Returns the map cache instance.\n */\nfunction mapCacheSet(key, value) {\n var data = getMapData(this, key),\n size = data.size;\n\n data.set(key, value);\n this.size += data.size == size ? 0 : 1;\n return this;\n}\n\n// Add methods to `MapCache`.\nMapCache.prototype.clear = mapCacheClear;\nMapCache.prototype['delete'] = mapCacheDelete;\nMapCache.prototype.get = mapCacheGet;\nMapCache.prototype.has = mapCacheHas;\nMapCache.prototype.set = mapCacheSet;\n\n/**\n *\n * Creates an array cache object to store unique values.\n *\n * @private\n * @constructor\n * @param {Array} [values] The values to cache.\n */\nfunction SetCache(values) {\n var index = -1,\n length = values == null ? 0 : values.length;\n\n this.__data__ = new MapCache;\n while (++index < length) {\n this.add(values[index]);\n }\n}\n\n/**\n * Adds `value` to the array cache.\n *\n * @private\n * @name add\n * @memberOf SetCache\n * @alias push\n * @param {*} value The value to cache.\n * @returns {Object} Returns the cache instance.\n */\nfunction setCacheAdd(value) {\n this.__data__.set(value, HASH_UNDEFINED);\n return this;\n}\n\n/**\n * Checks if `value` is in the array cache.\n *\n * @private\n * @name has\n * @memberOf SetCache\n * @param {*} value The value to search for.\n * @returns {number} Returns `true` if `value` is found, else `false`.\n */\nfunction setCacheHas(value) {\n return this.__data__.has(value);\n}\n\n// Add methods to `SetCache`.\nSetCache.prototype.add = SetCache.prototype.push = setCacheAdd;\nSetCache.prototype.has = setCacheHas;\n\n/**\n * Creates a stack cache object to store key-value pairs.\n *\n * @private\n * @constructor\n * @param {Array} [entries] The key-value pairs to cache.\n */\nfunction Stack(entries) {\n var data = this.__data__ = new ListCache(entries);\n this.size = data.size;\n}\n\n/**\n * Removes all key-value entries from the stack.\n *\n * @private\n * @name clear\n * @memberOf Stack\n */\nfunction stackClear() {\n this.__data__ = new ListCache;\n this.size = 0;\n}\n\n/**\n * Removes `key` and its value from the stack.\n *\n * @private\n * @name delete\n * @memberOf Stack\n * @param {string} key The key of the value to remove.\n * @returns {boolean} Returns `true` if the entry was removed, else `false`.\n */\nfunction stackDelete(key) {\n var data = this.__data__,\n result = data['delete'](key);\n\n this.size = data.size;\n return result;\n}\n\n/**\n * Gets the stack value for `key`.\n *\n * @private\n * @name get\n * @memberOf Stack\n * @param {string} key The key of the value to get.\n * @returns {*} Returns the entry value.\n */\nfunction stackGet(key) {\n return this.__data__.get(key);\n}\n\n/**\n * Checks if a stack value for `key` exists.\n *\n * @private\n * @name has\n * @memberOf Stack\n * @param {string} key The key of the entry to check.\n * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.\n */\nfunction stackHas(key) {\n return this.__data__.has(key);\n}\n\n/**\n * Sets the stack `key` to `value`.\n *\n * @private\n * @name set\n * @memberOf Stack\n * @param {string} key The key of the value to set.\n * @param {*} value The value to set.\n * @returns {Object} Returns the stack cache instance.\n */\nfunction stackSet(key, value) {\n var data = this.__data__;\n if (data instanceof ListCache) {\n var pairs = data.__data__;\n if (!Map || (pairs.length < LARGE_ARRAY_SIZE - 1)) {\n pairs.push([key, value]);\n this.size = ++data.size;\n return this;\n }\n data = this.__data__ = new MapCache(pairs);\n }\n data.set(key, value);\n this.size = data.size;\n return this;\n}\n\n// Add methods to `Stack`.\nStack.prototype.clear = stackClear;\nStack.prototype['delete'] = stackDelete;\nStack.prototype.get = stackGet;\nStack.prototype.has = stackHas;\nStack.prototype.set = stackSet;\n\n/**\n * Creates an array of the enumerable property names of the array-like `value`.\n *\n * @private\n * @param {*} value The value to query.\n * @param {boolean} inherited Specify returning inherited property names.\n * @returns {Array} Returns the array of property names.\n */\nfunction arrayLikeKeys(value, inherited) {\n var isArr = isArray(value),\n isArg = !isArr && isArguments(value),\n isBuff = !isArr && !isArg && isBuffer(value),\n isType = !isArr && !isArg && !isBuff && isTypedArray(value),\n skipIndexes = isArr || isArg || isBuff || isType,\n result = skipIndexes ? baseTimes(value.length, String) : [],\n length = result.length;\n\n for (var key in value) {\n if ((inherited || hasOwnProperty.call(value, key)) &&\n !(skipIndexes && (\n // Safari 9 has enumerable `arguments.length` in strict mode.\n key == 'length' ||\n // Node.js 0.10 has enumerable non-index properties on buffers.\n (isBuff && (key == 'offset' || key == 'parent')) ||\n // PhantomJS 2 has enumerable non-index properties on typed arrays.\n (isType && (key == 'buffer' || key == 'byteLength' || key == 'byteOffset')) ||\n // Skip index properties.\n isIndex(key, length)\n ))) {\n result.push(key);\n }\n }\n return result;\n}\n\n/**\n * Gets the index at which the `key` is found in `array` of key-value pairs.\n *\n * @private\n * @param {Array} array The array to inspect.\n * @param {*} key The key to search for.\n * @returns {number} Returns the index of the matched value, else `-1`.\n */\nfunction assocIndexOf(array, key) {\n var length = array.length;\n while (length--) {\n if (eq(array[length][0], key)) {\n return length;\n }\n }\n return -1;\n}\n\n/**\n * The base implementation of `getAllKeys` and `getAllKeysIn` which uses\n * `keysFunc` and `symbolsFunc` to get the enumerable property names and\n * symbols of `object`.\n *\n * @private\n * @param {Object} object The object to query.\n * @param {Function} keysFunc The function to get the keys of `object`.\n * @param {Function} symbolsFunc The function to get the symbols of `object`.\n * @returns {Array} Returns the array of property names and symbols.\n */\nfunction baseGetAllKeys(object, keysFunc, symbolsFunc) {\n var result = keysFunc(object);\n return isArray(object) ? result : arrayPush(result, symbolsFunc(object));\n}\n\n/**\n * The base implementation of `getTag` without fallbacks for buggy environments.\n *\n * @private\n * @param {*} value The value to query.\n * @returns {string} Returns the `toStringTag`.\n */\nfunction baseGetTag(value) {\n if (value == null) {\n return value === undefined ? undefinedTag : nullTag;\n }\n return (symToStringTag && symToStringTag in Object(value))\n ? getRawTag(value)\n : objectToString(value);\n}\n\n/**\n * The base implementation of `_.isArguments`.\n *\n * @private\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is an `arguments` object,\n */\nfunction baseIsArguments(value) {\n return isObjectLike(value) && baseGetTag(value) == argsTag;\n}\n\n/**\n * The base implementation of `_.isEqual` which supports partial comparisons\n * and tracks traversed objects.\n *\n * @private\n * @param {*} value The value to compare.\n * @param {*} other The other value to compare.\n * @param {boolean} bitmask The bitmask flags.\n * 1 - Unordered comparison\n * 2 - Partial comparison\n * @param {Function} [customizer] The function to customize comparisons.\n * @param {Object} [stack] Tracks traversed `value` and `other` objects.\n * @returns {boolean} Returns `true` if the values are equivalent, else `false`.\n */\nfunction baseIsEqual(value, other, bitmask, customizer, stack) {\n if (value === other) {\n return true;\n }\n if (value == null || other == null || (!isObjectLike(value) && !isObjectLike(other))) {\n return value !== value && other !== other;\n }\n return baseIsEqualDeep(value, other, bitmask, customizer, baseIsEqual, stack);\n}\n\n/**\n * A specialized version of `baseIsEqual` for arrays and objects which performs\n * deep comparisons and tracks traversed objects enabling objects with circular\n * references to be compared.\n *\n * @private\n * @param {Object} object The object to compare.\n * @param {Object} other The other object to compare.\n * @param {number} bitmask The bitmask flags. See `baseIsEqual` for more details.\n * @param {Function} customizer The function to customize comparisons.\n * @param {Function} equalFunc The function to determine equivalents of values.\n * @param {Object} [stack] Tracks traversed `object` and `other` objects.\n * @returns {boolean} Returns `true` if the objects are equivalent, else `false`.\n */\nfunction baseIsEqualDeep(object, other, bitmask, customizer, equalFunc, stack) {\n var objIsArr = isArray(object),\n othIsArr = isArray(other),\n objTag = objIsArr ? arrayTag : getTag(object),\n othTag = othIsArr ? arrayTag : getTag(other);\n\n objTag = objTag == argsTag ? objectTag : objTag;\n othTag = othTag == argsTag ? objectTag : othTag;\n\n var objIsObj = objTag == objectTag,\n othIsObj = othTag == objectTag,\n isSameTag = objTag == othTag;\n\n if (isSameTag && isBuffer(object)) {\n if (!isBuffer(other)) {\n return false;\n }\n objIsArr = true;\n objIsObj = false;\n }\n if (isSameTag && !objIsObj) {\n stack || (stack = new Stack);\n return (objIsArr || isTypedArray(object))\n ? equalArrays(object, other, bitmask, customizer, equalFunc, stack)\n : equalByTag(object, other, objTag, bitmask, customizer, equalFunc, stack);\n }\n if (!(bitmask & COMPARE_PARTIAL_FLAG)) {\n var objIsWrapped = objIsObj && hasOwnProperty.call(object, '__wrapped__'),\n othIsWrapped = othIsObj && hasOwnProperty.call(other, '__wrapped__');\n\n if (objIsWrapped || othIsWrapped) {\n var objUnwrapped = objIsWrapped ? object.value() : object,\n othUnwrapped = othIsWrapped ? other.value() : other;\n\n stack || (stack = new Stack);\n return equalFunc(objUnwrapped, othUnwrapped, bitmask, customizer, stack);\n }\n }\n if (!isSameTag) {\n return false;\n }\n stack || (stack = new Stack);\n return equalObjects(object, other, bitmask, customizer, equalFunc, stack);\n}\n\n/**\n * The base implementation of `_.isNative` without bad shim checks.\n *\n * @private\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a native function,\n * else `false`.\n */\nfunction baseIsNative(value) {\n if (!isObject(value) || isMasked(value)) {\n return false;\n }\n var pattern = isFunction(value) ? reIsNative : reIsHostCtor;\n return pattern.test(toSource(value));\n}\n\n/**\n * The base implementation of `_.isTypedArray` without Node.js optimizations.\n *\n * @private\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a typed array, else `false`.\n */\nfunction baseIsTypedArray(value) {\n return isObjectLike(value) &&\n isLength(value.length) && !!typedArrayTags[baseGetTag(value)];\n}\n\n/**\n * The base implementation of `_.keys` which doesn't treat sparse arrays as dense.\n *\n * @private\n * @param {Object} object The object to query.\n * @returns {Array} Returns the array of property names.\n */\nfunction baseKeys(object) {\n if (!isPrototype(object)) {\n return nativeKeys(object);\n }\n var result = [];\n for (var key in Object(object)) {\n if (hasOwnProperty.call(object, key) && key != 'constructor') {\n result.push(key);\n }\n }\n return result;\n}\n\n/**\n * A specialized version of `baseIsEqualDeep` for arrays with support for\n * partial deep comparisons.\n *\n * @private\n * @param {Array} array The array to compare.\n * @param {Array} other The other array to compare.\n * @param {number} bitmask The bitmask flags. See `baseIsEqual` for more details.\n * @param {Function} customizer The function to customize comparisons.\n * @param {Function} equalFunc The function to determine equivalents of values.\n * @param {Object} stack Tracks traversed `array` and `other` objects.\n * @returns {boolean} Returns `true` if the arrays are equivalent, else `false`.\n */\nfunction equalArrays(array, other, bitmask, customizer, equalFunc, stack) {\n var isPartial = bitmask & COMPARE_PARTIAL_FLAG,\n arrLength = array.length,\n othLength = other.length;\n\n if (arrLength != othLength && !(isPartial && othLength > arrLength)) {\n return false;\n }\n // Assume cyclic values are equal.\n var stacked = stack.get(array);\n if (stacked && stack.get(other)) {\n return stacked == other;\n }\n var index = -1,\n result = true,\n seen = (bitmask & COMPARE_UNORDERED_FLAG) ? new SetCache : undefined;\n\n stack.set(array, other);\n stack.set(other, array);\n\n // Ignore non-index properties.\n while (++index < arrLength) {\n var arrValue = array[index],\n othValue = other[index];\n\n if (customizer) {\n var compared = isPartial\n ? customizer(othValue, arrValue, index, other, array, stack)\n : customizer(arrValue, othValue, index, array, other, stack);\n }\n if (compared !== undefined) {\n if (compared) {\n continue;\n }\n result = false;\n break;\n }\n // Recursively compare arrays (susceptible to call stack limits).\n if (seen) {\n if (!arraySome(other, function(othValue, othIndex) {\n if (!cacheHas(seen, othIndex) &&\n (arrValue === othValue || equalFunc(arrValue, othValue, bitmask, customizer, stack))) {\n return seen.push(othIndex);\n }\n })) {\n result = false;\n break;\n }\n } else if (!(\n arrValue === othValue ||\n equalFunc(arrValue, othValue, bitmask, customizer, stack)\n )) {\n result = false;\n break;\n }\n }\n stack['delete'](array);\n stack['delete'](other);\n return result;\n}\n\n/**\n * A specialized version of `baseIsEqualDeep` for comparing objects of\n * the same `toStringTag`.\n *\n * **Note:** This function only supports comparing values with tags of\n * `Boolean`, `Date`, `Error`, `Number`, `RegExp`, or `String`.\n *\n * @private\n * @param {Object} object The object to compare.\n * @param {Object} other The other object to compare.\n * @param {string} tag The `toStringTag` of the objects to compare.\n * @param {number} bitmask The bitmask flags. See `baseIsEqual` for more details.\n * @param {Function} customizer The function to customize comparisons.\n * @param {Function} equalFunc The function to determine equivalents of values.\n * @param {Object} stack Tracks traversed `object` and `other` objects.\n * @returns {boolean} Returns `true` if the objects are equivalent, else `false`.\n */\nfunction equalByTag(object, other, tag, bitmask, customizer, equalFunc, stack) {\n switch (tag) {\n case dataViewTag:\n if ((object.byteLength != other.byteLength) ||\n (object.byteOffset != other.byteOffset)) {\n return false;\n }\n object = object.buffer;\n other = other.buffer;\n\n case arrayBufferTag:\n if ((object.byteLength != other.byteLength) ||\n !equalFunc(new Uint8Array(object), new Uint8Array(other))) {\n return false;\n }\n return true;\n\n case boolTag:\n case dateTag:\n case numberTag:\n // Coerce booleans to `1` or `0` and dates to milliseconds.\n // Invalid dates are coerced to `NaN`.\n return eq(+object, +other);\n\n case errorTag:\n return object.name == other.name && object.message == other.message;\n\n case regexpTag:\n case stringTag:\n // Coerce regexes to strings and treat strings, primitives and objects,\n // as equal. See http://www.ecma-international.org/ecma-262/7.0/#sec-regexp.prototype.tostring\n // for more details.\n return object == (other + '');\n\n case mapTag:\n var convert = mapToArray;\n\n case setTag:\n var isPartial = bitmask & COMPARE_PARTIAL_FLAG;\n convert || (convert = setToArray);\n\n if (object.size != other.size && !isPartial) {\n return false;\n }\n // Assume cyclic values are equal.\n var stacked = stack.get(object);\n if (stacked) {\n return stacked == other;\n }\n bitmask |= COMPARE_UNORDERED_FLAG;\n\n // Recursively compare objects (susceptible to call stack limits).\n stack.set(object, other);\n var result = equalArrays(convert(object), convert(other), bitmask, customizer, equalFunc, stack);\n stack['delete'](object);\n return result;\n\n case symbolTag:\n if (symbolValueOf) {\n return symbolValueOf.call(object) == symbolValueOf.call(other);\n }\n }\n return false;\n}\n\n/**\n * A specialized version of `baseIsEqualDeep` for objects with support for\n * partial deep comparisons.\n *\n * @private\n * @param {Object} object The object to compare.\n * @param {Object} other The other object to compare.\n * @param {number} bitmask The bitmask flags. See `baseIsEqual` for more details.\n * @param {Function} customizer The function to customize comparisons.\n * @param {Function} equalFunc The function to determine equivalents of values.\n * @param {Object} stack Tracks traversed `object` and `other` objects.\n * @returns {boolean} Returns `true` if the objects are equivalent, else `false`.\n */\nfunction equalObjects(object, other, bitmask, customizer, equalFunc, stack) {\n var isPartial = bitmask & COMPARE_PARTIAL_FLAG,\n objProps = getAllKeys(object),\n objLength = objProps.length,\n othProps = getAllKeys(other),\n othLength = othProps.length;\n\n if (objLength != othLength && !isPartial) {\n return false;\n }\n var index = objLength;\n while (index--) {\n var key = objProps[index];\n if (!(isPartial ? key in other : hasOwnProperty.call(other, key))) {\n return false;\n }\n }\n // Assume cyclic values are equal.\n var stacked = stack.get(object);\n if (stacked && stack.get(other)) {\n return stacked == other;\n }\n var result = true;\n stack.set(object, other);\n stack.set(other, object);\n\n var skipCtor = isPartial;\n while (++index < objLength) {\n key = objProps[index];\n var objValue = object[key],\n othValue = other[key];\n\n if (customizer) {\n var compared = isPartial\n ? customizer(othValue, objValue, key, other, object, stack)\n : customizer(objValue, othValue, key, object, other, stack);\n }\n // Recursively compare objects (susceptible to call stack limits).\n if (!(compared === undefined\n ? (objValue === othValue || equalFunc(objValue, othValue, bitmask, customizer, stack))\n : compared\n )) {\n result = false;\n break;\n }\n skipCtor || (skipCtor = key == 'constructor');\n }\n if (result && !skipCtor) {\n var objCtor = object.constructor,\n othCtor = other.constructor;\n\n // Non `Object` object instances with different constructors are not equal.\n if (objCtor != othCtor &&\n ('constructor' in object && 'constructor' in other) &&\n !(typeof objCtor == 'function' && objCtor instanceof objCtor &&\n typeof othCtor == 'function' && othCtor instanceof othCtor)) {\n result = false;\n }\n }\n stack['delete'](object);\n stack['delete'](other);\n return result;\n}\n\n/**\n * Creates an array of own enumerable property names and symbols of `object`.\n *\n * @private\n * @param {Object} object The object to query.\n * @returns {Array} Returns the array of property names and symbols.\n */\nfunction getAllKeys(object) {\n return baseGetAllKeys(object, keys, getSymbols);\n}\n\n/**\n * Gets the data for `map`.\n *\n * @private\n * @param {Object} map The map to query.\n * @param {string} key The reference key.\n * @returns {*} Returns the map data.\n */\nfunction getMapData(map, key) {\n var data = map.__data__;\n return isKeyable(key)\n ? data[typeof key == 'string' ? 'string' : 'hash']\n : data.map;\n}\n\n/**\n * Gets the native function at `key` of `object`.\n *\n * @private\n * @param {Object} object The object to query.\n * @param {string} key The key of the method to get.\n * @returns {*} Returns the function if it's native, else `undefined`.\n */\nfunction getNative(object, key) {\n var value = getValue(object, key);\n return baseIsNative(value) ? value : undefined;\n}\n\n/**\n * A specialized version of `baseGetTag` which ignores `Symbol.toStringTag` values.\n *\n * @private\n * @param {*} value The value to query.\n * @returns {string} Returns the raw `toStringTag`.\n */\nfunction getRawTag(value) {\n var isOwn = hasOwnProperty.call(value, symToStringTag),\n tag = value[symToStringTag];\n\n try {\n value[symToStringTag] = undefined;\n var unmasked = true;\n } catch (e) {}\n\n var result = nativeObjectToString.call(value);\n if (unmasked) {\n if (isOwn) {\n value[symToStringTag] = tag;\n } else {\n delete value[symToStringTag];\n }\n }\n return result;\n}\n\n/**\n * Creates an array of the own enumerable symbols of `object`.\n *\n * @private\n * @param {Object} object The object to query.\n * @returns {Array} Returns the array of symbols.\n */\nvar getSymbols = !nativeGetSymbols ? stubArray : function(object) {\n if (object == null) {\n return [];\n }\n object = Object(object);\n return arrayFilter(nativeGetSymbols(object), function(symbol) {\n return propertyIsEnumerable.call(object, symbol);\n });\n};\n\n/**\n * Gets the `toStringTag` of `value`.\n *\n * @private\n * @param {*} value The value to query.\n * @returns {string} Returns the `toStringTag`.\n */\nvar getTag = baseGetTag;\n\n// Fallback for data views, maps, sets, and weak maps in IE 11 and promises in Node.js < 6.\nif ((DataView && getTag(new DataView(new ArrayBuffer(1))) != dataViewTag) ||\n (Map && getTag(new Map) != mapTag) ||\n (Promise && getTag(Promise.resolve()) != promiseTag) ||\n (Set && getTag(new Set) != setTag) ||\n (WeakMap && getTag(new WeakMap) != weakMapTag)) {\n getTag = function(value) {\n var result = baseGetTag(value),\n Ctor = result == objectTag ? value.constructor : undefined,\n ctorString = Ctor ? toSource(Ctor) : '';\n\n if (ctorString) {\n switch (ctorString) {\n case dataViewCtorString: return dataViewTag;\n case mapCtorString: return mapTag;\n case promiseCtorString: return promiseTag;\n case setCtorString: return setTag;\n case weakMapCtorString: return weakMapTag;\n }\n }\n return result;\n };\n}\n\n/**\n * Checks if `value` is a valid array-like index.\n *\n * @private\n * @param {*} value The value to check.\n * @param {number} [length=MAX_SAFE_INTEGER] The upper bounds of a valid index.\n * @returns {boolean} Returns `true` if `value` is a valid index, else `false`.\n */\nfunction isIndex(value, length) {\n length = length == null ? MAX_SAFE_INTEGER : length;\n return !!length &&\n (typeof value == 'number' || reIsUint.test(value)) &&\n (value > -1 && value % 1 == 0 && value < length);\n}\n\n/**\n * Checks if `value` is suitable for use as unique object key.\n *\n * @private\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is suitable, else `false`.\n */\nfunction isKeyable(value) {\n var type = typeof value;\n return (type == 'string' || type == 'number' || type == 'symbol' || type == 'boolean')\n ? (value !== '__proto__')\n : (value === null);\n}\n\n/**\n * Checks if `func` has its source masked.\n *\n * @private\n * @param {Function} func The function to check.\n * @returns {boolean} Returns `true` if `func` is masked, else `false`.\n */\nfunction isMasked(func) {\n return !!maskSrcKey && (maskSrcKey in func);\n}\n\n/**\n * Checks if `value` is likely a prototype object.\n *\n * @private\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a prototype, else `false`.\n */\nfunction isPrototype(value) {\n var Ctor = value && value.constructor,\n proto = (typeof Ctor == 'function' && Ctor.prototype) || objectProto;\n\n return value === proto;\n}\n\n/**\n * Converts `value` to a string using `Object.prototype.toString`.\n *\n * @private\n * @param {*} value The value to convert.\n * @returns {string} Returns the converted string.\n */\nfunction objectToString(value) {\n return nativeObjectToString.call(value);\n}\n\n/**\n * Converts `func` to its source code.\n *\n * @private\n * @param {Function} func The function to convert.\n * @returns {string} Returns the source code.\n */\nfunction toSource(func) {\n if (func != null) {\n try {\n return funcToString.call(func);\n } catch (e) {}\n try {\n return (func + '');\n } catch (e) {}\n }\n return '';\n}\n\n/**\n * Performs a\n * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)\n * comparison between two values to determine if they are equivalent.\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to compare.\n * @param {*} other The other value to compare.\n * @returns {boolean} Returns `true` if the values are equivalent, else `false`.\n * @example\n *\n * var object = { 'a': 1 };\n * var other = { 'a': 1 };\n *\n * _.eq(object, object);\n * // => true\n *\n * _.eq(object, other);\n * // => false\n *\n * _.eq('a', 'a');\n * // => true\n *\n * _.eq('a', Object('a'));\n * // => false\n *\n * _.eq(NaN, NaN);\n * // => true\n */\nfunction eq(value, other) {\n return value === other || (value !== value && other !== other);\n}\n\n/**\n * Checks if `value` is likely an `arguments` object.\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is an `arguments` object,\n * else `false`.\n * @example\n *\n * _.isArguments(function() { return arguments; }());\n * // => true\n *\n * _.isArguments([1, 2, 3]);\n * // => false\n */\nvar isArguments = baseIsArguments(function() { return arguments; }()) ? baseIsArguments : function(value) {\n return isObjectLike(value) && hasOwnProperty.call(value, 'callee') &&\n !propertyIsEnumerable.call(value, 'callee');\n};\n\n/**\n * Checks if `value` is classified as an `Array` object.\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is an array, else `false`.\n * @example\n *\n * _.isArray([1, 2, 3]);\n * // => true\n *\n * _.isArray(document.body.children);\n * // => false\n *\n * _.isArray('abc');\n * // => false\n *\n * _.isArray(_.noop);\n * // => false\n */\nvar isArray = Array.isArray;\n\n/**\n * Checks if `value` is array-like. A value is considered array-like if it's\n * not a function and has a `value.length` that's an integer greater than or\n * equal to `0` and less than or equal to `Number.MAX_SAFE_INTEGER`.\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is array-like, else `false`.\n * @example\n *\n * _.isArrayLike([1, 2, 3]);\n * // => true\n *\n * _.isArrayLike(document.body.children);\n * // => true\n *\n * _.isArrayLike('abc');\n * // => true\n *\n * _.isArrayLike(_.noop);\n * // => false\n */\nfunction isArrayLike(value) {\n return value != null && isLength(value.length) && !isFunction(value);\n}\n\n/**\n * Checks if `value` is a buffer.\n *\n * @static\n * @memberOf _\n * @since 4.3.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a buffer, else `false`.\n * @example\n *\n * _.isBuffer(new Buffer(2));\n * // => true\n *\n * _.isBuffer(new Uint8Array(2));\n * // => false\n */\nvar isBuffer = nativeIsBuffer || stubFalse;\n\n/**\n * Performs a deep comparison between two values to determine if they are\n * equivalent.\n *\n * **Note:** This method supports comparing arrays, array buffers, booleans,\n * date objects, error objects, maps, numbers, `Object` objects, regexes,\n * sets, strings, symbols, and typed arrays. `Object` objects are compared\n * by their own, not inherited, enumerable properties. Functions and DOM\n * nodes are compared by strict equality, i.e. `===`.\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Lang\n * @param {*} value The value to compare.\n * @param {*} other The other value to compare.\n * @returns {boolean} Returns `true` if the values are equivalent, else `false`.\n * @example\n *\n * var object = { 'a': 1 };\n * var other = { 'a': 1 };\n *\n * _.isEqual(object, other);\n * // => true\n *\n * object === other;\n * // => false\n */\nfunction isEqual(value, other) {\n return baseIsEqual(value, other);\n}\n\n/**\n * Checks if `value` is classified as a `Function` object.\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a function, else `false`.\n * @example\n *\n * _.isFunction(_);\n * // => true\n *\n * _.isFunction(/abc/);\n * // => false\n */\nfunction isFunction(value) {\n if (!isObject(value)) {\n return false;\n }\n // The use of `Object#toString` avoids issues with the `typeof` operator\n // in Safari 9 which returns 'object' for typed arrays and other constructors.\n var tag = baseGetTag(value);\n return tag == funcTag || tag == genTag || tag == asyncTag || tag == proxyTag;\n}\n\n/**\n * Checks if `value` is a valid array-like length.\n *\n * **Note:** This method is loosely based on\n * [`ToLength`](http://ecma-international.org/ecma-262/7.0/#sec-tolength).\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a valid length, else `false`.\n * @example\n *\n * _.isLength(3);\n * // => true\n *\n * _.isLength(Number.MIN_VALUE);\n * // => false\n *\n * _.isLength(Infinity);\n * // => false\n *\n * _.isLength('3');\n * // => false\n */\nfunction isLength(value) {\n return typeof value == 'number' &&\n value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER;\n}\n\n/**\n * Checks if `value` is the\n * [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types)\n * of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is an object, else `false`.\n * @example\n *\n * _.isObject({});\n * // => true\n *\n * _.isObject([1, 2, 3]);\n * // => true\n *\n * _.isObject(_.noop);\n * // => true\n *\n * _.isObject(null);\n * // => false\n */\nfunction isObject(value) {\n var type = typeof value;\n return value != null && (type == 'object' || type == 'function');\n}\n\n/**\n * Checks if `value` is object-like. A value is object-like if it's not `null`\n * and has a `typeof` result of \"object\".\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is object-like, else `false`.\n * @example\n *\n * _.isObjectLike({});\n * // => true\n *\n * _.isObjectLike([1, 2, 3]);\n * // => true\n *\n * _.isObjectLike(_.noop);\n * // => false\n *\n * _.isObjectLike(null);\n * // => false\n */\nfunction isObjectLike(value) {\n return value != null && typeof value == 'object';\n}\n\n/**\n * Checks if `value` is classified as a typed array.\n *\n * @static\n * @memberOf _\n * @since 3.0.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a typed array, else `false`.\n * @example\n *\n * _.isTypedArray(new Uint8Array);\n * // => true\n *\n * _.isTypedArray([]);\n * // => false\n */\nvar isTypedArray = nodeIsTypedArray ? baseUnary(nodeIsTypedArray) : baseIsTypedArray;\n\n/**\n * Creates an array of the own enumerable property names of `object`.\n *\n * **Note:** Non-object values are coerced to objects. See the\n * [ES spec](http://ecma-international.org/ecma-262/7.0/#sec-object.keys)\n * for more details.\n *\n * @static\n * @since 0.1.0\n * @memberOf _\n * @category Object\n * @param {Object} object The object to query.\n * @returns {Array} Returns the array of property names.\n * @example\n *\n * function Foo() {\n * this.a = 1;\n * this.b = 2;\n * }\n *\n * Foo.prototype.c = 3;\n *\n * _.keys(new Foo);\n * // => ['a', 'b'] (iteration order is not guaranteed)\n *\n * _.keys('hi');\n * // => ['0', '1']\n */\nfunction keys(object) {\n return isArrayLike(object) ? arrayLikeKeys(object) : baseKeys(object);\n}\n\n/**\n * This method returns a new empty array.\n *\n * @static\n * @memberOf _\n * @since 4.13.0\n * @category Util\n * @returns {Array} Returns the new empty array.\n * @example\n *\n * var arrays = _.times(2, _.stubArray);\n *\n * console.log(arrays);\n * // => [[], []]\n *\n * console.log(arrays[0] === arrays[1]);\n * // => false\n */\nfunction stubArray() {\n return [];\n}\n\n/**\n * This method returns `false`.\n *\n * @static\n * @memberOf _\n * @since 4.13.0\n * @category Util\n * @returns {boolean} Returns `false`.\n * @example\n *\n * _.times(2, _.stubFalse);\n * // => [false, false]\n */\nfunction stubFalse() {\n return false;\n}\n\nmodule.exports = isEqual;\n", "// This loads all middlewares exposed on the middleware object and then starts\n// the invocation chain. The big idea is that we can add these to the middleware\n// export dynamically through wrangler, or we can potentially let users directly\n// add them as a sort of \"plugin\" system.\n\nimport ENTRY, { __INTERNAL_WRANGLER_MIDDLEWARE__ } from \"C:\\\\Users\\\\jeffe\\\\Documents\\\\GitHub\\\\canvas-website\\\\.wrangler\\\\tmp\\\\bundle-fO5AAb\\\\middleware-insertion-facade.js\";\nimport { __facade_invoke__, __facade_register__, Dispatcher } from \"C:\\\\Users\\\\jeffe\\\\Documents\\\\GitHub\\\\canvas-website\\\\node_modules\\\\wrangler\\\\templates\\\\middleware\\\\common.ts\";\nimport type { WorkerEntrypointConstructor } from \"C:\\\\Users\\\\jeffe\\\\Documents\\\\GitHub\\\\canvas-website\\\\.wrangler\\\\tmp\\\\bundle-fO5AAb\\\\middleware-insertion-facade.js\";\n\n// Preserve all the exports from the worker\nexport * from \"C:\\\\Users\\\\jeffe\\\\Documents\\\\GitHub\\\\canvas-website\\\\.wrangler\\\\tmp\\\\bundle-fO5AAb\\\\middleware-insertion-facade.js\";\n\nclass __Facade_ScheduledController__ implements ScheduledController {\n\treadonly #noRetry: ScheduledController[\"noRetry\"];\n\n\tconstructor(\n\t\treadonly scheduledTime: number,\n\t\treadonly cron: string,\n\t\tnoRetry: ScheduledController[\"noRetry\"]\n\t) {\n\t\tthis.#noRetry = noRetry;\n\t}\n\n\tnoRetry() {\n\t\tif (!(this instanceof __Facade_ScheduledController__)) {\n\t\t\tthrow new TypeError(\"Illegal invocation\");\n\t\t}\n\t\t// Need to call native method immediately in case uncaught error thrown\n\t\tthis.#noRetry();\n\t}\n}\n\nfunction wrapExportedHandler(worker: ExportedHandler): ExportedHandler {\n\t// If we don't have any middleware defined, just return the handler as is\n\tif (\n\t\t__INTERNAL_WRANGLER_MIDDLEWARE__ === undefined ||\n\t\t__INTERNAL_WRANGLER_MIDDLEWARE__.length === 0\n\t) {\n\t\treturn worker;\n\t}\n\t// Otherwise, register all middleware once\n\tfor (const middleware of __INTERNAL_WRANGLER_MIDDLEWARE__) {\n\t\t__facade_register__(middleware);\n\t}\n\n\tconst fetchDispatcher: ExportedHandlerFetchHandler = function (\n\t\trequest,\n\t\tenv,\n\t\tctx\n\t) {\n\t\tif (worker.fetch === undefined) {\n\t\t\tthrow new Error(\"Handler does not export a fetch() function.\");\n\t\t}\n\t\treturn worker.fetch(request, env, ctx);\n\t};\n\n\treturn {\n\t\t...worker,\n\t\tfetch(request, env, ctx) {\n\t\t\tconst dispatcher: Dispatcher = function (type, init) {\n\t\t\t\tif (type === \"scheduled\" && worker.scheduled !== undefined) {\n\t\t\t\t\tconst controller = new __Facade_ScheduledController__(\n\t\t\t\t\t\tDate.now(),\n\t\t\t\t\t\tinit.cron ?? \"\",\n\t\t\t\t\t\t() => {}\n\t\t\t\t\t);\n\t\t\t\t\treturn worker.scheduled(controller, env, ctx);\n\t\t\t\t}\n\t\t\t};\n\t\t\treturn __facade_invoke__(request, env, ctx, dispatcher, fetchDispatcher);\n\t\t},\n\t};\n}\n\nfunction wrapWorkerEntrypoint(\n\tklass: WorkerEntrypointConstructor\n): WorkerEntrypointConstructor {\n\t// If we don't have any middleware defined, just return the handler as is\n\tif (\n\t\t__INTERNAL_WRANGLER_MIDDLEWARE__ === undefined ||\n\t\t__INTERNAL_WRANGLER_MIDDLEWARE__.length === 0\n\t) {\n\t\treturn klass;\n\t}\n\t// Otherwise, register all middleware once\n\tfor (const middleware of __INTERNAL_WRANGLER_MIDDLEWARE__) {\n\t\t__facade_register__(middleware);\n\t}\n\n\t// `extend`ing `klass` here so other RPC methods remain callable\n\treturn class extends klass {\n\t\t#fetchDispatcher: ExportedHandlerFetchHandler> = (\n\t\t\trequest,\n\t\t\tenv,\n\t\t\tctx\n\t\t) => {\n\t\t\tthis.env = env;\n\t\t\tthis.ctx = ctx;\n\t\t\tif (super.fetch === undefined) {\n\t\t\t\tthrow new Error(\"Entrypoint class does not define a fetch() function.\");\n\t\t\t}\n\t\t\treturn super.fetch(request);\n\t\t};\n\n\t\t#dispatcher: Dispatcher = (type, init) => {\n\t\t\tif (type === \"scheduled\" && super.scheduled !== undefined) {\n\t\t\t\tconst controller = new __Facade_ScheduledController__(\n\t\t\t\t\tDate.now(),\n\t\t\t\t\tinit.cron ?? \"\",\n\t\t\t\t\t() => {}\n\t\t\t\t);\n\t\t\t\treturn super.scheduled(controller);\n\t\t\t}\n\t\t};\n\n\t\tfetch(request: Request) {\n\t\t\treturn __facade_invoke__(\n\t\t\t\trequest,\n\t\t\t\tthis.env,\n\t\t\t\tthis.ctx,\n\t\t\t\tthis.#dispatcher,\n\t\t\t\tthis.#fetchDispatcher\n\t\t\t);\n\t\t}\n\t};\n}\n\nlet WRAPPED_ENTRY: ExportedHandler | WorkerEntrypointConstructor | undefined;\nif (typeof ENTRY === \"object\") {\n\tWRAPPED_ENTRY = wrapExportedHandler(ENTRY);\n} else if (typeof ENTRY === \"function\") {\n\tWRAPPED_ENTRY = wrapWorkerEntrypoint(ENTRY);\n}\nexport default WRAPPED_ENTRY;\n", "\t\t\t\timport worker, * as OTHER_EXPORTS from \"C:\\\\Users\\\\jeffe\\\\Documents\\\\GitHub\\\\canvas-website\\\\worker\\\\worker.ts\";\n\t\t\t\timport * as __MIDDLEWARE_0__ from \"C:\\\\Users\\\\jeffe\\\\Documents\\\\GitHub\\\\canvas-website\\\\node_modules\\\\wrangler\\\\templates\\\\middleware\\\\middleware-ensure-req-body-drained.ts\";\nimport * as __MIDDLEWARE_1__ from \"C:\\\\Users\\\\jeffe\\\\Documents\\\\GitHub\\\\canvas-website\\\\node_modules\\\\wrangler\\\\templates\\\\middleware\\\\middleware-miniflare3-json-error.ts\";\n\n\t\t\t\texport * from \"C:\\\\Users\\\\jeffe\\\\Documents\\\\GitHub\\\\canvas-website\\\\worker\\\\worker.ts\";\n\n\t\t\t\texport const __INTERNAL_WRANGLER_MIDDLEWARE__ = [\n\t\t\t\t\t\n\t\t\t\t\t__MIDDLEWARE_0__.default,__MIDDLEWARE_1__.default\n\t\t\t\t]\n\t\t\t\texport default worker;", "import { handleUnfurlRequest } from 'cloudflare-workers-unfurl'\nimport { AutoRouter, cors, error, IRequest } from 'itty-router'\nimport { handleAssetDownload, handleAssetUpload } from './assetUploads'\nimport { Environment } from './types'\n\n// make sure our sync durable object is made available to cloudflare\nexport { TldrawDurableObject } from './TldrawDurableObject'\n\n// we use itty-router (https://itty.dev/) to handle routing. in this example we turn on CORS because\n// we're hosting the worker separately to the client. you should restrict this to your own domain.\nconst { preflight, corsify } = cors({ origin: '*' })\nconst router = AutoRouter({\n\tbefore: [preflight],\n\tfinally: [corsify],\n\tcatch: (e) => {\n\t\tconsole.error(e)\n\t\treturn error(e)\n\t},\n})\n\t// requests to /connect are routed to the Durable Object, and handle realtime websocket syncing\n\t.get('/connect/:roomId', (request, env) => {\n\t\tconst id = env.TLDRAW_DURABLE_OBJECT.idFromName(request.params.roomId)\n\t\tconst room = env.TLDRAW_DURABLE_OBJECT.get(id)\n\t\treturn room.fetch(request.url, { headers: request.headers, body: request.body })\n\t})\n\n\t// assets can be uploaded to the bucket under /uploads:\n\t.post('/uploads/:uploadId', handleAssetUpload)\n\n\t// they can be retrieved from the bucket too:\n\t.get('/uploads/:uploadId', handleAssetDownload)\n\n\t// bookmarks need to extract metadata from pasted URLs:\n\t.get('/unfurl', handleUnfurlRequest)\n\n// export our router for cloudflare\nexport default router\n", "/**\n * @template Value\n * @typedef {Object} GoodResult\n * @property {true} ok - The success status.\n * @property {Value} value - The data extracted from the URL.\n */\n\n/**\n * @template Error\n * @typedef {Object} BadResult\n * @property {false} ok - The success status.\n * @property {Error} error - The error\n */\n\n/**\n * @template Value, Error\n * @typedef {GoodResult | BadResult} Result\n */\n\n/**\n * @typedef {Object} UnfurledData\n * @property {string} [title] - The title extracted from the URL.\n * @property {string} [description] - The description extracted from the URL.\n * @property {string} [image] - The image URL extracted from the URL.\n * @property {string} [favicon] - The favicon URL extracted from the URL.\n */\n\n/**\n * @typedef {'bad-param' | 'failed-fetch'} UnfurlError\n */\n\nconst validContentTypes = [\n \"text/html\",\n \"application/xhtml+xml\",\n \"application/xml\",\n \"image/*\",\n];\n\n/**\n *\n * @param {string} contentType\n * @returns {boolean}\n */\nfunction isValidContentType(contentType) {\n return (\n // allow unspecified, try to parse it anyway\n !contentType ||\n contentType.startsWith(\"image/\") ||\n validContentTypes.some((valid) => contentType.startsWith(valid))\n );\n}\n\n/**\n * Handles the unfurling of a URL by extracting metadata such as title, description, image, and favicon.\n * @param {string} url - The URL to unfurl.\n * @returns {Promise>} - A promise that resolves to an object containing the extracted metadata, or null if an error occurs.\n */\nexport async function unfurl(url) {\n if (typeof url !== \"string\" || !url.match(/^https?:\\/\\//)) {\n return { ok: false, error: \"bad-param\" };\n }\n\n // cloudflare has a built-in HTML parser/rewriter called HTMLRewriter. in order to use it, we\n // need to define classes that act as event handlers for certain elements, attributes, etc.\n // see https://developers.cloudflare.com/workers/runtime-apis/html-rewriter/\n const meta$ = new MetaExtractor();\n const title$ = new TextExtractor();\n const icon$ = new IconExtractor();\n\n try {\n const headers = new Headers();\n for (const contentType of validContentTypes) {\n headers.append(\"accept\", contentType);\n }\n const res = await fetch(url, { headers });\n if (!res.ok || !isValidContentType(res.headers.get(\"content-type\") ?? \"\")) {\n return { ok: false, error: \"failed-fetch\" };\n }\n if (res.headers.get(\"content-type\")?.startsWith(\"image/\")) {\n return {\n ok: true,\n value: {\n image: url,\n title: new URL(url).pathname.split(\"/\").pop() || undefined,\n },\n };\n }\n await new HTMLRewriter()\n .on(\"meta\", meta$)\n .on(\"title\", title$)\n .on(\"link\", icon$)\n .transform(res)\n .blob();\n } catch {\n return { ok: false, error: \"failed-fetch\" };\n }\n\n // we don't know exactly what we'll end up with, so this is a best-effort extraction\n const { og, twitter } = meta$;\n const title =\n og[\"og:title\"] ?? twitter[\"twitter:title\"] ?? title$.string ?? undefined;\n const description =\n og[\"og:description\"] ??\n twitter[\"twitter:description\"] ??\n meta$.description ??\n undefined;\n let image =\n og[\"og:image:secure_url\"] ??\n og[\"og:image\"] ??\n twitter[\"twitter:image\"] ??\n undefined;\n let favicon = icon$.appleIcon ?? icon$.icon ?? undefined;\n\n if (image && !image?.startsWith(\"http\")) {\n image = new URL(image, url).href;\n }\n if (favicon && !favicon?.startsWith(\"http\")) {\n favicon = new URL(favicon, url).href;\n }\n\n return {\n ok: true,\n value: {\n title,\n description,\n image,\n favicon,\n },\n };\n}\n\n/**\n * Implements a handler for a GET request where the uri is passed in as a search param called `url`.\n *\n * e.g. GET /foo/bar?url=https://example.com\n *\n * @param {Request} request\n * @returns {Promise}\n */\nexport async function handleUnfurlRequest(request) {\n const url = new URL(request.url).searchParams.get(\"url\");\n\n if (!url) {\n return new Response(\"Missing URL query parameter.\", { status: 400 });\n }\n\n const result = await unfurl(url);\n\n if (result.ok) {\n return new Response(JSON.stringify(result.value), {\n headers: { \"Content-Type\": \"application/json\" },\n });\n } else if (result.error === \"bad-param\") {\n return new Response(\"Bad URL query parameter.\", { status: 400 });\n } else {\n return new Response(\"Failed to fetch URL.\", { status: 422 });\n }\n}\n\n/**\n * Extracts text from HTML elements.\n */\nclass TextExtractor {\n /**\n * The accumulated text extracted from elements.\n * @type {string}\n */\n string = \"\";\n\n /**\n * Handles an incoming piece of text.\n * @param {Object} param - The text object.\n * @param {string} param.text - The incoming text.\n */\n text({ text }) {\n this.string += text;\n }\n}\n\n/**\n * Extracts metadata from HTML elements.\n */\nclass MetaExtractor {\n /**\n * The Open Graph (og) metadata extracted from elements.\n * @type {Object.}\n */\n og = {};\n\n /**\n * The Twitter metadata extracted from elements.\n * @type {Object.}\n */\n twitter = {};\n\n /**\n * The description extracted from elements.\n * @type {string|null}\n */\n description = null;\n\n /**\n * Handles an incoming element.\n * @param {Element} element - The incoming element.\n */\n element(element) {\n const property = element.getAttribute(\"property\");\n const name = element.getAttribute(\"name\");\n\n if (property && property.startsWith(\"og:\")) {\n this.og[property] = element.getAttribute(\"content\");\n } else if (name && name.startsWith(\"twitter:\")) {\n this.twitter[name] = element.getAttribute(\"content\");\n } else if (name === \"description\") {\n this.description = element.getAttribute(\"content\");\n }\n }\n}\n\n/**\n * Extracts favicon URLs from HTML elements.\n */\nclass IconExtractor {\n /**\n * The Apple touch icon URL extracted from elements.\n * @type {string|null}\n */\n appleIcon = null;\n\n /**\n * The favicon URL extracted from elements.\n * @type {string|null}\n */\n icon = null;\n\n /**\n * Handles an incoming element.\n * @param {Element} element - The incoming element.\n */\n element(element) {\n if (element.getAttribute(\"rel\") === \"icon\") {\n this.icon = element.getAttribute(\"href\");\n } else if (element.getAttribute(\"rel\") === \"apple-touch-icon\") {\n this.appleIcon = element.getAttribute(\"href\");\n }\n }\n}\n", null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, "import { IRequest, error } from 'itty-router'\nimport { Environment } from './types'\n\n// assets are stored in the bucket under the /uploads path\nfunction getAssetObjectName(uploadId: string) {\n\treturn `uploads/${uploadId.replace(/[^a-zA-Z0-9\\_\\-]+/g, '_')}`\n}\n\n// when a user uploads an asset, we store it in the bucket. we only allow image and video assets.\nexport async function handleAssetUpload(request: IRequest, env: Environment) {\n\tconst objectName = getAssetObjectName(request.params.uploadId)\n\n\tconst contentType = request.headers.get('content-type') ?? ''\n\tif (!contentType.startsWith('image/') && !contentType.startsWith('video/')) {\n\t\treturn error(400, 'Invalid content type')\n\t}\n\n\tif (await env.TLDRAW_BUCKET.head(objectName)) {\n\t\treturn error(409, 'Upload already exists')\n\t}\n\n\tawait env.TLDRAW_BUCKET.put(objectName, request.body, {\n\t\thttpMetadata: request.headers,\n\t})\n\n\treturn { ok: true }\n}\n\n// when a user downloads an asset, we retrieve it from the bucket. we also cache the response for performance.\nexport async function handleAssetDownload(\n\trequest: IRequest,\n\tenv: Environment,\n\tctx: ExecutionContext\n) {\n\tconst objectName = getAssetObjectName(request.params.uploadId)\n\n\t// if we have a cached response for this request (automatically handling ranges etc.), return it\n\tconst cacheKey = new Request(request.url, { headers: request.headers })\n\tconst cachedResponse = await caches.default.match(cacheKey)\n\tif (cachedResponse) {\n\t\treturn cachedResponse\n\t}\n\n\t// if not, we try to fetch the asset from the bucket\n\tconst object = await env.TLDRAW_BUCKET.get(objectName, {\n\t\trange: request.headers,\n\t\tonlyIf: request.headers,\n\t})\n\n\tif (!object) {\n\t\treturn error(404)\n\t}\n\n\t// write the relevant metadata to the response headers\n\tconst headers = new Headers()\n\tobject.writeHttpMetadata(headers)\n\n\t// assets are immutable, so we can cache them basically forever:\n\theaders.set('cache-control', 'public, max-age=31536000, immutable')\n\theaders.set('etag', object.httpEtag)\n\n\t// we set CORS headers so all clients can access assets. we do this here so our `cors` helper in\n\t// worker.ts doesn't try to set extra cors headers on responses that have been read from the\n\t// cache, which isn't allowed by cloudflare.\n\theaders.set('access-control-allow-origin', '*')\n\n\t// cloudflare doesn't set the content-range header automatically in writeHttpMetadata, so we\n\t// need to do it ourselves.\n\tlet contentRange\n\tif (object.range) {\n\t\tif ('suffix' in object.range) {\n\t\t\tconst start = object.size - object.range.suffix\n\t\t\tconst end = object.size - 1\n\t\t\tcontentRange = `bytes ${start}-${end}/${object.size}`\n\t\t} else {\n\t\t\tconst start = object.range.offset ?? 0\n\t\t\tconst end = object.range.length ? start + object.range.length - 1 : object.size - 1\n\t\t\tif (start !== 0 || end !== object.size - 1) {\n\t\t\t\tcontentRange = `bytes ${start}-${end}/${object.size}`\n\t\t\t}\n\t\t}\n\t}\n\n\tif (contentRange) {\n\t\theaders.set('content-range', contentRange)\n\t}\n\n\t// make sure we get the correct body/status for the response\n\tconst body = 'body' in object && object.body ? object.body : null\n\tconst status = body ? (contentRange ? 206 : 200) : 304\n\n\t// we only cache complete (200) responses\n\tif (status === 200) {\n\t\tconst [cacheBody, responseBody] = body!.tee()\n\t\tctx.waitUntil(caches.default.put(cacheKey, new Response(cacheBody, { headers, status })))\n\t\treturn new Response(responseBody, { headers, status })\n\t}\n\n\treturn new Response(body, { headers, status })\n}\n", "import { RoomSnapshot, TLSocketRoom } from '@tldraw/sync-core'\nimport {\n\tTLRecord,\n\tcreateTLSchema,\n\t// defaultBindingSchemas,\n\tdefaultShapeSchemas,\n} from '@tldraw/tlschema'\nimport { AutoRouter, IRequest, error } from 'itty-router'\nimport throttle from 'lodash.throttle'\nimport { Environment } from './types'\n\n// add custom shapes and bindings here if needed:\nconst schema = createTLSchema({\n\tshapes: { ...defaultShapeSchemas },\n\t// bindings: { ...defaultBindingSchemas },\n})\n\n// each whiteboard room is hosted in a DurableObject:\n// https://developers.cloudflare.com/durable-objects/\n\n// there's only ever one durable object instance per room. it keeps all the room state in memory and\n// handles websocket connections. periodically, it persists the room state to the R2 bucket.\nexport class TldrawDurableObject {\n\tprivate r2: R2Bucket\n\t// the room ID will be missing whilst the room is being initialized\n\tprivate roomId: string | null = null\n\t// when we load the room from the R2 bucket, we keep it here. it's a promise so we only ever\n\t// load it once.\n\tprivate roomPromise: Promise> | null = null\n\n\tconstructor(\n\t\tprivate readonly ctx: DurableObjectState,\n\t\tenv: Environment\n\t) {\n\t\tthis.r2 = env.TLDRAW_BUCKET\n\n\t\tctx.blockConcurrencyWhile(async () => {\n\t\t\tthis.roomId = ((await this.ctx.storage.get('roomId')) ?? null) as string | null\n\t\t})\n\t}\n\n\tprivate readonly router = AutoRouter({\n\t\tcatch: (e) => {\n\t\t\tconsole.log(e)\n\t\t\treturn error(e)\n\t\t},\n\t})\n\t\t// when we get a connection request, we stash the room id if needed and handle the connection\n\t\t.get('/connect/:roomId', async (request) => {\n\t\t\tif (!this.roomId) {\n\t\t\t\tawait this.ctx.blockConcurrencyWhile(async () => {\n\t\t\t\t\tawait this.ctx.storage.put('roomId', request.params.roomId)\n\t\t\t\t\tthis.roomId = request.params.roomId\n\t\t\t\t})\n\t\t\t}\n\t\t\treturn this.handleConnect(request)\n\t\t})\n\n\t// `fetch` is the entry point for all requests to the Durable Object\n\tfetch(request: Request): Response | Promise {\n\t\treturn this.router.fetch(request)\n\t}\n\n\t// what happens when someone tries to connect to this room?\n\tasync handleConnect(request: IRequest): Promise {\n\t\t// extract query params from request\n\t\tconst sessionId = request.query.sessionId as string\n\t\tif (!sessionId) return error(400, 'Missing sessionId')\n\n\t\t// Create the websocket pair for the client\n\t\tconst { 0: clientWebSocket, 1: serverWebSocket } = new WebSocketPair()\n\t\tserverWebSocket.accept()\n\n\t\t// load the room, or retrieve it if it's already loaded\n\t\tconst room = await this.getRoom()\n\n\t\t// connect the client to the room\n\t\troom.handleSocketConnect({ sessionId, socket: serverWebSocket })\n\n\t\t// return the websocket connection to the client\n\t\treturn new Response(null, { status: 101, webSocket: clientWebSocket })\n\t}\n\n\tgetRoom() {\n\t\tconst roomId = this.roomId\n\t\tif (!roomId) throw new Error('Missing roomId')\n\n\t\tif (!this.roomPromise) {\n\t\t\tthis.roomPromise = (async () => {\n\t\t\t\t// fetch the room from R2\n\t\t\t\tconst roomFromBucket = await this.r2.get(`rooms/${roomId}`)\n\n\t\t\t\t// if it doesn't exist, we'll just create a new empty room\n\t\t\t\tconst initialSnapshot = roomFromBucket\n\t\t\t\t\t? ((await roomFromBucket.json()) as RoomSnapshot)\n\t\t\t\t\t: undefined\n\n\t\t\t\t// create a new TLSocketRoom. This handles all the sync protocol & websocket connections.\n\t\t\t\t// it's up to us to persist the room state to R2 when needed though.\n\t\t\t\treturn new TLSocketRoom({\n\t\t\t\t\tschema,\n\t\t\t\t\tinitialSnapshot,\n\t\t\t\t\tonDataChange: () => {\n\t\t\t\t\t\t// and persist whenever the data in the room changes\n\t\t\t\t\t\tthis.schedulePersistToR2()\n\t\t\t\t\t},\n\t\t\t\t})\n\t\t\t})()\n\t\t}\n\n\t\treturn this.roomPromise\n\t}\n\n\t// we throttle persistance so it only happens every 10 seconds\n\tschedulePersistToR2 = throttle(async () => {\n\t\tif (!this.roomPromise || !this.roomId) return\n\t\tconst room = await this.getRoom()\n\n\t\t// convert the room to JSON and upload it to R2\n\t\tconst snapshot = JSON.stringify(room.getCurrentSnapshot())\n\t\tawait this.r2.put(`rooms/${this.roomId}`, snapshot)\n\t}, 10_000)\n}\n", "export { ClientWebSocketAdapter, ReconnectManager } from './lib/ClientWebSocketAdapter'\nexport { RoomSessionState, type RoomSession } from './lib/RoomSession'\nexport type { WebSocketMinimal } from './lib/ServerSocketAdapter'\nexport { TLRemoteSyncError } from './lib/TLRemoteSyncError'\nexport { TLSocketRoom, type OmitVoid, type TLSyncLog } from './lib/TLSocketRoom'\nexport {\n\tTLCloseEventCode,\n\tTLSyncClient,\n\ttype SubscribingFn,\n\ttype TLPersistentClientSocket,\n\ttype TLPersistentClientSocketStatus,\n} from './lib/TLSyncClient'\nexport { DocumentState, TLSyncRoom, type RoomSnapshot, type TLRoomSocket } from './lib/TLSyncRoom'\nexport { chunk } from './lib/chunk'\nexport {\n\tRecordOpType,\n\tValueOpType,\n\tapplyObjectDiff,\n\tdiffRecord,\n\tgetNetworkDiff,\n\ttype AppendOp,\n\ttype DeleteOp,\n\ttype NetworkDiff,\n\ttype ObjectDiff,\n\ttype PatchOp,\n\ttype PutOp,\n\ttype RecordOp,\n\ttype ValueOp,\n} from './lib/diff'\nexport {\n\tTLIncompatibilityReason,\n\tgetTlsyncProtocolVersion,\n\ttype TLConnectRequest,\n\ttype TLPingRequest,\n\ttype TLPushRequest,\n\ttype TLSocketClientSentEvent,\n\ttype TLSocketServerSentDataEvent,\n\ttype TLSocketServerSentEvent,\n} from './lib/protocol'\nexport type { PersistedRoomSnapshotForSupabase } from './lib/server-types'\n", "import { atom, Atom } from '@tldraw/state'\nimport { TLRecord } from '@tldraw/tlschema'\nimport { assert, warnOnce } from '@tldraw/utils'\nimport { chunk } from './chunk'\nimport { TLSocketClientSentEvent, TLSocketServerSentEvent } from './protocol'\nimport {\n\tTLCloseEventCode,\n\tTLPersistentClientSocket,\n\tTLPersistentClientSocketStatus,\n} from './TLSyncClient'\n\nfunction listenTo(target: T, event: string, handler: () => void) {\n\ttarget.addEventListener(event, handler)\n\treturn () => {\n\t\ttarget.removeEventListener(event, handler)\n\t}\n}\n\nfunction debug(...args: any[]) {\n\t// @ts-ignore\n\tif (typeof window !== 'undefined' && window.__tldraw_socket_debug) {\n\t\tconst now = new Date()\n\t\t// eslint-disable-next-line no-console\n\t\tconsole.log(\n\t\t\t`${now.getHours()}:${now.getMinutes()}:${now.getSeconds()}.${now.getMilliseconds()}`,\n\t\t\t...args\n\t\t\t//, new Error().stack\n\t\t)\n\t}\n}\n\n// NOTE: ClientWebSocketAdapter requires its users to implement their own connection loss\n// detection, for example by regularly pinging the server and .restart()ing\n// the connection when a number of pings goes unanswered. Without this mechanism,\n// we might not be able to detect the websocket connection going down in a timely manner\n// (it will probably time out on outgoing data packets at some point).\n//\n// This is by design. Whilst the Websocket protocol specifies protocol-level pings,\n// they don't seem to be surfaced in browser APIs and can't be relied on. Therefore,\n// pings need to be implemented one level up, on the application API side, which for our\n// codebase means whatever code that uses ClientWebSocketAdapter.\n\n/** @internal */\nexport class ClientWebSocketAdapter implements TLPersistentClientSocket {\n\t_ws: WebSocket | null = null\n\n\tisDisposed = false\n\n\t/** @internal */\n\treadonly _reconnectManager: ReconnectManager\n\n\t// TODO: .close should be a project-wide interface with a common contract (.close()d thing\n\t// can only be garbage collected, and can't be used anymore)\n\tclose() {\n\t\tthis.isDisposed = true\n\t\tthis._reconnectManager.close()\n\t\t// WebSocket.close() is idempotent\n\t\tthis._ws?.close()\n\t}\n\n\tconstructor(getUri: () => Promise | string) {\n\t\tthis._reconnectManager = new ReconnectManager(this, getUri)\n\t}\n\n\tprivate _handleConnect() {\n\t\tdebug('handleConnect')\n\n\t\tthis._connectionStatus.set('online')\n\t\tthis.statusListeners.forEach((cb) => cb('online'))\n\n\t\tthis._reconnectManager.connected()\n\t}\n\n\tprivate _handleDisconnect(\n\t\treason: 'closed' | 'error' | 'manual',\n\t\tcloseCode?: number,\n\t\tdidOpen?: boolean\n\t) {\n\t\tdebug('handleDisconnect', {\n\t\t\tcurrentStatus: this.connectionStatus,\n\t\t\tcloseCode,\n\t\t\treason,\n\t\t})\n\n\t\tlet newStatus: 'offline' | 'error'\n\t\tswitch (reason) {\n\t\t\tcase 'closed':\n\t\t\t\tif (closeCode === TLCloseEventCode.NOT_FOUND) {\n\t\t\t\t\tnewStatus = 'error'\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\tnewStatus = 'offline'\n\t\t\t\tbreak\n\t\t\tcase 'error':\n\t\t\t\tnewStatus = 'error'\n\t\t\t\tbreak\n\t\t\tcase 'manual':\n\t\t\t\tnewStatus = 'offline'\n\t\t\t\tbreak\n\t\t}\n\n\t\tif (closeCode === 1006 && !didOpen) {\n\t\t\twarnOnce(\n\t\t\t\t\"Could not open WebSocket connection. This might be because you're trying to load a URL that doesn't support websockets. Check the URL you're trying to connect to.\"\n\t\t\t)\n\t\t}\n\n\t\tif (\n\t\t\t// it the status changed\n\t\t\tthis.connectionStatus !== newStatus &&\n\t\t\t// ignore errors if we're already in the offline state\n\t\t\t!(newStatus === 'error' && this.connectionStatus === 'offline')\n\t\t) {\n\t\t\tthis._connectionStatus.set(newStatus)\n\t\t\tthis.statusListeners.forEach((cb) => cb(newStatus, closeCode))\n\t\t}\n\n\t\tthis._reconnectManager.disconnected()\n\t}\n\n\t_setNewSocket(ws: WebSocket) {\n\t\tassert(!this.isDisposed, 'Tried to set a new websocket on a disposed socket')\n\t\tassert(\n\t\t\tthis._ws === null ||\n\t\t\t\tthis._ws.readyState === WebSocket.CLOSED ||\n\t\t\t\tthis._ws.readyState === WebSocket.CLOSING,\n\t\t\t`Tried to set a new websocket in when the existing one was ${this._ws?.readyState}`\n\t\t)\n\n\t\tlet didOpen = false\n\n\t\t// NOTE: Sockets can stay for quite a while in the CLOSING state. This is because the transition\n\t\t// between CLOSING and CLOSED happens either after the closing handshake, or after a\n\t\t// timeout, but in either case those sockets don't need any special handling, the browser\n\t\t// will close them eventually. We just \"orphan\" such sockets and ignore their onclose/onerror.\n\t\tws.onopen = () => {\n\t\t\tdebug('ws.onopen')\n\t\t\tassert(\n\t\t\t\tthis._ws === ws,\n\t\t\t\t\"sockets must only be orphaned when they are CLOSING or CLOSED, so they can't open\"\n\t\t\t)\n\t\t\tdidOpen = true\n\t\t\tthis._handleConnect()\n\t\t}\n\t\tws.onclose = (event: CloseEvent) => {\n\t\t\tdebug('ws.onclose', event)\n\t\t\tif (this._ws === ws) {\n\t\t\t\tthis._handleDisconnect('closed', event.code, didOpen)\n\t\t\t} else {\n\t\t\t\tdebug('ignoring onclose for an orphaned socket')\n\t\t\t}\n\t\t}\n\t\tws.onerror = (event) => {\n\t\t\tdebug('ws.onerror', event)\n\t\t\tif (this._ws === ws) {\n\t\t\t\tthis._handleDisconnect('error')\n\t\t\t} else {\n\t\t\t\tdebug('ignoring onerror for an orphaned socket')\n\t\t\t}\n\t\t}\n\t\tws.onmessage = (ev) => {\n\t\t\tassert(\n\t\t\t\tthis._ws === ws,\n\t\t\t\t\"sockets must only be orphaned when they are CLOSING or CLOSED, so they can't receive messages\"\n\t\t\t)\n\t\t\tconst parsed = JSON.parse(ev.data.toString())\n\t\t\tthis.messageListeners.forEach((cb) => cb(parsed))\n\t\t}\n\n\t\tthis._ws = ws\n\t}\n\n\t_closeSocket() {\n\t\tif (this._ws === null) return\n\n\t\tthis._ws.close()\n\t\t// explicitly orphan the socket to ignore its onclose/onerror, because onclose can be delayed\n\t\tthis._ws = null\n\t\tthis._handleDisconnect('manual')\n\t}\n\n\t// TLPersistentClientSocket stuff\n\n\t_connectionStatus: Atom = atom(\n\t\t'websocket connection status',\n\t\t'initial'\n\t)\n\n\t// eslint-disable-next-line no-restricted-syntax\n\tget connectionStatus(): TLPersistentClientSocketStatus {\n\t\tconst status = this._connectionStatus.get()\n\t\treturn status === 'initial' ? 'offline' : status\n\t}\n\n\tsendMessage(msg: TLSocketClientSentEvent) {\n\t\tassert(!this.isDisposed, 'Tried to send message on a disposed socket')\n\n\t\tif (!this._ws) return\n\t\tif (this.connectionStatus === 'online') {\n\t\t\tconst chunks = chunk(JSON.stringify(msg))\n\t\t\tfor (const part of chunks) {\n\t\t\t\tthis._ws.send(part)\n\t\t\t}\n\t\t} else {\n\t\t\tconsole.warn('Tried to send message while ' + this.connectionStatus)\n\t\t}\n\t}\n\n\tprivate messageListeners = new Set<(msg: TLSocketServerSentEvent) => void>()\n\tonReceiveMessage(cb: (val: TLSocketServerSentEvent) => void) {\n\t\tassert(!this.isDisposed, 'Tried to add message listener on a disposed socket')\n\n\t\tthis.messageListeners.add(cb)\n\t\treturn () => {\n\t\t\tthis.messageListeners.delete(cb)\n\t\t}\n\t}\n\n\tprivate statusListeners = new Set<\n\t\t(status: TLPersistentClientSocketStatus, closeCode?: number) => void\n\t>()\n\tonStatusChange(cb: (val: TLPersistentClientSocketStatus, closeCode?: number) => void) {\n\t\tassert(!this.isDisposed, 'Tried to add status listener on a disposed socket')\n\n\t\tthis.statusListeners.add(cb)\n\t\treturn () => {\n\t\t\tthis.statusListeners.delete(cb)\n\t\t}\n\t}\n\n\trestart() {\n\t\tassert(!this.isDisposed, 'Tried to restart a disposed socket')\n\t\tdebug('restarting')\n\n\t\tthis._closeSocket()\n\t\tthis._reconnectManager.maybeReconnected()\n\t}\n}\n\n// Those constants are exported primarily for tests\n// ACTIVE_ means the tab is active, document.hidden is false\nexport const ACTIVE_MIN_DELAY = 500\nexport const ACTIVE_MAX_DELAY = 2000\n// Correspondingly, here document.hidden is true. It's intended to reduce the load and battery drain\n// on client devices somewhat when they aren't looking at the tab. We don't disconnect completely\n// to minimise issues with reconnection/sync when the tab becomes visible again\nexport const INACTIVE_MIN_DELAY = 1000\nexport const INACTIVE_MAX_DELAY = 1000 * 60 * 5\nexport const DELAY_EXPONENT = 1.5\n// this is a tradeoff between quickly detecting connections stuck in the CONNECTING state and\n// not needlessly reconnecting if the connection is just slow to establish\nexport const ATTEMPT_TIMEOUT = 1000\n\n/** @internal */\nexport class ReconnectManager {\n\tprivate isDisposed = false\n\tprivate disposables: (() => void)[] = [\n\t\t() => {\n\t\t\tif (this.reconnectTimeout) clearTimeout(this.reconnectTimeout)\n\t\t\tif (this.recheckConnectingTimeout) clearTimeout(this.recheckConnectingTimeout)\n\t\t},\n\t]\n\tprivate reconnectTimeout: ReturnType | null = null\n\tprivate recheckConnectingTimeout: ReturnType | null = null\n\n\tprivate lastAttemptStart: number | null = null\n\tintendedDelay: number = ACTIVE_MIN_DELAY\n\tprivate state: 'pendingAttempt' | 'pendingAttemptResult' | 'delay' | 'connected'\n\n\tconstructor(\n\t\tprivate socketAdapter: ClientWebSocketAdapter,\n\t\tprivate getUri: () => Promise | string\n\t) {\n\t\tthis.subscribeToReconnectHints()\n\n\t\tthis.disposables.push(\n\t\t\tlistenTo(window, 'offline', () => {\n\t\t\t\tdebug('window went offline')\n\t\t\t\t// On the one hand, 'offline' event is not really reliable; on the other, the only\n\t\t\t\t// alternative is to wait for pings not being delivered, which takes more than 20 seconds,\n\t\t\t\t// which means we won't see the ClientWebSocketAdapter status change for more than\n\t\t\t\t// 20 seconds after the tab goes offline. Our application layer must be resistent to\n\t\t\t\t// connection restart anyway, so we can just try to reconnect and see if\n\t\t\t\t// we're truly offline.\n\t\t\t\tthis.socketAdapter._closeSocket()\n\t\t\t})\n\t\t)\n\n\t\tthis.state = 'pendingAttempt'\n\t\tthis.intendedDelay = ACTIVE_MIN_DELAY\n\t\tthis.scheduleAttempt()\n\t}\n\n\tprivate subscribeToReconnectHints() {\n\t\tthis.disposables.push(\n\t\t\tlistenTo(window, 'online', () => {\n\t\t\t\tdebug('window went online')\n\t\t\t\tthis.maybeReconnected()\n\t\t\t}),\n\t\t\tlistenTo(document, 'visibilitychange', () => {\n\t\t\t\tif (!document.hidden) {\n\t\t\t\t\tdebug('document became visible')\n\t\t\t\t\tthis.maybeReconnected()\n\t\t\t\t}\n\t\t\t})\n\t\t)\n\n\t\tif (Object.prototype.hasOwnProperty.call(navigator, 'connection')) {\n\t\t\tconst connection = (navigator as any)['connection'] as EventTarget\n\t\t\tthis.disposables.push(\n\t\t\t\tlistenTo(connection, 'change', () => {\n\t\t\t\t\tdebug('navigator.connection change')\n\t\t\t\t\tthis.maybeReconnected()\n\t\t\t\t})\n\t\t\t)\n\t\t}\n\t}\n\n\tprivate scheduleAttempt() {\n\t\tassert(this.state === 'pendingAttempt')\n\t\tdebug('scheduling a connection attempt')\n\t\tPromise.resolve(this.getUri()).then((uri) => {\n\t\t\t// this can happen if the promise gets resolved too late\n\t\t\tif (this.state !== 'pendingAttempt' || this.isDisposed) return\n\t\t\tassert(\n\t\t\t\tthis.socketAdapter._ws?.readyState !== WebSocket.OPEN,\n\t\t\t\t'There should be no connection attempts while already connected'\n\t\t\t)\n\n\t\t\tthis.lastAttemptStart = Date.now()\n\t\t\tthis.socketAdapter._setNewSocket(new WebSocket(httpToWs(uri)))\n\t\t\tthis.state = 'pendingAttemptResult'\n\t\t})\n\t}\n\n\tprivate getMaxDelay() {\n\t\treturn document.hidden ? INACTIVE_MAX_DELAY : ACTIVE_MAX_DELAY\n\t}\n\n\tprivate getMinDelay() {\n\t\treturn document.hidden ? INACTIVE_MIN_DELAY : ACTIVE_MIN_DELAY\n\t}\n\n\tprivate clearReconnectTimeout() {\n\t\tif (this.reconnectTimeout) {\n\t\t\tclearTimeout(this.reconnectTimeout)\n\t\t\tthis.reconnectTimeout = null\n\t\t}\n\t}\n\n\tprivate clearRecheckConnectingTimeout() {\n\t\tif (this.recheckConnectingTimeout) {\n\t\t\tclearTimeout(this.recheckConnectingTimeout)\n\t\t\tthis.recheckConnectingTimeout = null\n\t\t}\n\t}\n\n\tmaybeReconnected() {\n\t\tdebug('ReconnectManager.maybeReconnected')\n\t\t// It doesn't make sense to have another check scheduled if we're already checking it now.\n\t\t// If we have a CONNECTING check scheduled and relevant, it'll be recreated below anyway\n\t\tthis.clearRecheckConnectingTimeout()\n\n\t\t// readyState can be CONNECTING, OPEN, CLOSING, CLOSED, or null (if getUri() is still pending)\n\t\tif (this.socketAdapter._ws?.readyState === WebSocket.OPEN) {\n\t\t\tdebug('ReconnectManager.maybeReconnected: already connected')\n\t\t\t// nothing to do, we're already OK\n\t\t\treturn\n\t\t}\n\n\t\tif (this.socketAdapter._ws?.readyState === WebSocket.CONNECTING) {\n\t\t\tdebug('ReconnectManager.maybeReconnected: connecting')\n\t\t\t// We might be waiting for a TCP connection that sent SYN out and will never get it back,\n\t\t\t// while a new connection appeared. On the other hand, we might have just started connecting\n\t\t\t// and will succeed in a bit. Thus, we're checking how old the attempt is and retry anew\n\t\t\t// if it's old enough. This by itself can delay the connection a bit, but shouldn't prevent\n\t\t\t// new connections as long as `maybeReconnected` is not looped itself\n\t\t\tassert(\n\t\t\t\tthis.lastAttemptStart,\n\t\t\t\t'ReadyState=CONNECTING without lastAttemptStart should be impossible'\n\t\t\t)\n\t\t\tconst sinceLastStart = Date.now() - this.lastAttemptStart\n\t\t\tif (sinceLastStart < ATTEMPT_TIMEOUT) {\n\t\t\t\tdebug('ReconnectManager.maybeReconnected: connecting, rechecking later')\n\t\t\t\tthis.recheckConnectingTimeout = setTimeout(\n\t\t\t\t\t() => this.maybeReconnected(),\n\t\t\t\t\tATTEMPT_TIMEOUT - sinceLastStart\n\t\t\t\t)\n\t\t\t} else {\n\t\t\t\tdebug('ReconnectManager.maybeReconnected: connecting, but for too long, retry now')\n\t\t\t\t// Last connection attempt was started a while ago, it's possible that network conditions\n\t\t\t\t// changed, and it's worth retrying to connect. `disconnected` will handle reconnection\n\t\t\t\t//\n\t\t\t\t// NOTE: The danger here is looping in connection attemps if connections are slow.\n\t\t\t\t// Make sure that `maybeReconnected` is not called in the `disconnected` codepath!\n\t\t\t\tthis.clearRecheckConnectingTimeout()\n\t\t\t\tthis.socketAdapter._closeSocket()\n\t\t\t}\n\n\t\t\treturn\n\t\t}\n\n\t\tdebug('ReconnectManager.maybeReconnected: closing/closed/null, retry now')\n\t\t// readyState is CLOSING or CLOSED, or the websocket is null\n\t\t// Restart the backoff and retry ASAP (honouring the min delay)\n\t\t// this.state doesn't really matter, because disconnected() will handle any state correctly\n\t\tthis.intendedDelay = ACTIVE_MIN_DELAY\n\t\tthis.disconnected()\n\t}\n\n\tdisconnected() {\n\t\tdebug('ReconnectManager.disconnected')\n\t\t// This either means we're freshly disconnected, or the last connection attempt failed;\n\t\t// either way, time to try again.\n\n\t\t// Guard against delayed notifications and recheck synchronously\n\t\tif (\n\t\t\tthis.socketAdapter._ws?.readyState !== WebSocket.OPEN &&\n\t\t\tthis.socketAdapter._ws?.readyState !== WebSocket.CONNECTING\n\t\t) {\n\t\t\tdebug('ReconnectManager.disconnected: websocket is not OPEN or CONNECTING')\n\t\t\tthis.clearReconnectTimeout()\n\n\t\t\tlet delayLeft\n\t\t\tif (this.state === 'connected') {\n\t\t\t\t// it's the first sign that we got disconnected; the state will be updated below,\n\t\t\t\t// just set the appropriate delay for now\n\t\t\t\tthis.intendedDelay = this.getMinDelay()\n\t\t\t\tdelayLeft = this.intendedDelay\n\t\t\t} else {\n\t\t\t\tdelayLeft =\n\t\t\t\t\tthis.lastAttemptStart !== null\n\t\t\t\t\t\t? this.lastAttemptStart + this.intendedDelay - Date.now()\n\t\t\t\t\t\t: 0\n\t\t\t}\n\n\t\t\tif (delayLeft > 0) {\n\t\t\t\tdebug('ReconnectManager.disconnected: delaying, delayLeft', delayLeft)\n\t\t\t\t// try again later\n\t\t\t\tthis.state = 'delay'\n\n\t\t\t\tthis.reconnectTimeout = setTimeout(() => this.disconnected(), delayLeft)\n\t\t\t} else {\n\t\t\t\t// not connected and not delayed, time to retry\n\t\t\t\tthis.state = 'pendingAttempt'\n\n\t\t\t\tthis.intendedDelay = Math.min(\n\t\t\t\t\tthis.getMaxDelay(),\n\t\t\t\t\tMath.max(this.getMinDelay(), this.intendedDelay) * DELAY_EXPONENT\n\t\t\t\t)\n\t\t\t\tdebug(\n\t\t\t\t\t'ReconnectManager.disconnected: attempting a connection, next delay',\n\t\t\t\t\tthis.intendedDelay\n\t\t\t\t)\n\t\t\t\tthis.scheduleAttempt()\n\t\t\t}\n\t\t}\n\t}\n\n\tconnected() {\n\t\tdebug('ReconnectManager.connected')\n\t\t// this notification could've been delayed, recheck synchronously\n\t\tif (this.socketAdapter._ws?.readyState === WebSocket.OPEN) {\n\t\t\tdebug('ReconnectManager.connected: websocket is OPEN')\n\t\t\tthis.state = 'connected'\n\t\t\tthis.clearReconnectTimeout()\n\t\t\tthis.intendedDelay = ACTIVE_MIN_DELAY\n\t\t}\n\t}\n\n\tclose() {\n\t\tthis.disposables.forEach((d) => d())\n\t\tthis.isDisposed = true\n\t}\n}\n\nfunction httpToWs(url: string) {\n\treturn url.replace(/^http(s)?:/, 'ws$1:')\n}\n", "import { singleton } from './lib/helpers'\n\nexport { ArraySet } from './lib/ArraySet'\nexport { atom, isAtom } from './lib/Atom'\nexport type { Atom, AtomOptions } from './lib/Atom'\nexport {\n\tUNINITIALIZED,\n\tcomputed,\n\tgetComputedInstance,\n\tisUninitialized,\n\twithDiff,\n} from './lib/Computed'\nexport type { Computed, ComputedOptions, WithDiff } from './lib/Computed'\nexport { EffectScheduler, react, reactor } from './lib/EffectScheduler'\nexport type { EffectSchedulerOptions, Reactor } from './lib/EffectScheduler'\nexport { unsafe__withoutCapture, whyAmIRunning } from './lib/capture'\nexport { EMPTY_ARRAY } from './lib/helpers'\nexport { isSignal } from './lib/isSignal'\nexport { transact, transaction } from './lib/transactions'\nexport { RESET_VALUE } from './lib/types'\nexport type { Child, ComputeDiff, Signal } from './lib/types'\n\n// This should be incremented any time an API change is made. i.e. for additions or removals.\n// Bugfixes need not increment this.\nconst currentApiVersion = 1\n\nconst actualApiVersion = singleton('apiVersion', () => currentApiVersion)\n\nif (actualApiVersion !== currentApiVersion) {\n\tthrow new Error(\n\t\t`You have multiple incompatible versions of @tldraw/state in your app. Please deduplicate the package.`\n\t)\n}\n", "import { Child, Signal } from './types'\n\n/**\n * Get whether the given value is a child.\n *\n * @param x The value to check.\n * @returns True if the value is a child, false otherwise.\n */\nfunction isChild(x: any): x is Child {\n\treturn x && typeof x === 'object' && 'parents' in x\n}\n\n/**\n * Get whether a child's parents have changed.\n *\n * @param child The child to check.\n * @returns True if the child's parents have changed, false otherwise.\n */\nexport function haveParentsChanged(child: Child) {\n\tfor (let i = 0, n = child.parents.length; i < n; i++) {\n\t\t// Get the parent's value without capturing it.\n\t\tchild.parents[i].__unsafe__getWithoutCapture(true)\n\n\t\t// If the parent's epoch does not match the child's view of the parent's epoch, then the parent has changed.\n\t\tif (child.parents[i].lastChangedEpoch !== child.parentEpochs[i]) {\n\t\t\treturn true\n\t\t}\n\t}\n\n\treturn false\n}\n\n/**\n * Detach a child from a parent.\n *\n * @param parent The parent to detach from.\n * @param child The child to detach.\n */\nexport const detach = (parent: Signal, child: Child) => {\n\t// If the child is not attached to the parent, do nothing.\n\tif (!parent.children.remove(child)) {\n\t\treturn\n\t}\n\n\t// If the parent has no more children, then detach the parent from its parents.\n\tif (parent.children.isEmpty && isChild(parent)) {\n\t\tfor (let i = 0, n = parent.parents.length; i < n; i++) {\n\t\t\tdetach(parent.parents[i], parent)\n\t\t}\n\t}\n}\n\n/**\n * Attach a child to a parent.\n *\n * @param parent The parent to attach to.\n * @param child The child to attach.\n */\nexport const attach = (parent: Signal, child: Child) => {\n\t// If the child is already attached to the parent, do nothing.\n\tif (!parent.children.add(child)) {\n\t\treturn\n\t}\n\n\t// If the parent itself is a child, add the parent to the parent's parents.\n\tif (isChild(parent)) {\n\t\tfor (let i = 0, n = parent.parents.length; i < n; i++) {\n\t\t\tattach(parent.parents[i], parent)\n\t\t}\n\t}\n}\n\n/**\n * Get whether two values are equal (insofar as @tldraw/state is concerned).\n *\n * @param a The first value.\n * @param b The second value.\n */\nexport function equals(a: any, b: any): boolean {\n\tconst shallowEquals =\n\t\ta === b || Object.is(a, b) || Boolean(a && b && typeof a.equals === 'function' && a.equals(b))\n\treturn shallowEquals\n}\n\nexport declare function assertNever(x: never): never\n\nexport function singleton(key: string, init: () => T): T {\n\tconst symbol = Symbol.for(`com.tldraw.state/${key}`)\n\tconst global = globalThis as any\n\tglobal[symbol] ??= init()\n\treturn global[symbol]\n}\n\n/**\n * @public\n */\nexport const EMPTY_ARRAY: [] = singleton('empty_array', () => Object.freeze([]) as any)\n", "// The maximum size for an array in an ArraySet\nexport const ARRAY_SIZE_THRESHOLD = 8\n\n/**\n * An ArraySet operates as an array until it reaches a certain size, after which a Set is used\n * instead. In either case, the same methods are used to get, set, remove, and visit the items.\n * @internal\n */\nexport class ArraySet {\n\tprivate arraySize = 0\n\n\tprivate array: (T | undefined)[] | null = Array(ARRAY_SIZE_THRESHOLD)\n\n\tprivate set: Set | null = null\n\n\t/**\n\t * Get whether this ArraySet has any elements.\n\t *\n\t * @returns True if this ArraySet has any elements, false otherwise.\n\t */\n\t// eslint-disable-next-line no-restricted-syntax\n\tget isEmpty() {\n\t\tif (this.array) {\n\t\t\treturn this.arraySize === 0\n\t\t}\n\n\t\tif (this.set) {\n\t\t\treturn this.set.size === 0\n\t\t}\n\n\t\tthrow new Error('no set or array')\n\t}\n\n\t/**\n\t * Add an item to the ArraySet if it is not already present.\n\t *\n\t * @param elem - The element to add.\n\t */\n\n\tadd(elem: T) {\n\t\tif (this.array) {\n\t\t\tconst idx = this.array.indexOf(elem)\n\n\t\t\t// Return false if the element is already in the array.\n\t\t\tif (idx !== -1) {\n\t\t\t\treturn false\n\t\t\t}\n\n\t\t\tif (this.arraySize < ARRAY_SIZE_THRESHOLD) {\n\t\t\t\t// If the array is below the size threshold, push items into the array.\n\n\t\t\t\t// Insert the element into the array's next available slot.\n\t\t\t\tthis.array[this.arraySize] = elem\n\t\t\t\tthis.arraySize++\n\n\t\t\t\treturn true\n\t\t\t} else {\n\t\t\t\t// If the array is full, convert it to a set and remove the array.\n\t\t\t\tthis.set = new Set(this.array as any)\n\t\t\t\tthis.array = null\n\t\t\t\tthis.set.add(elem)\n\n\t\t\t\treturn true\n\t\t\t}\n\t\t}\n\n\t\tif (this.set) {\n\t\t\t// Return false if the element is already in the set.\n\t\t\tif (this.set.has(elem)) {\n\t\t\t\treturn false\n\t\t\t}\n\n\t\t\tthis.set.add(elem)\n\t\t\treturn true\n\t\t}\n\n\t\tthrow new Error('no set or array')\n\t}\n\n\t/**\n\t * Remove an item from the ArraySet if it is present.\n\t *\n\t * @param elem - The element to remove\n\t */\n\tremove(elem: T) {\n\t\tif (this.array) {\n\t\t\tconst idx = this.array.indexOf(elem)\n\n\t\t\t// If the item is not in the array, return false.\n\t\t\tif (idx === -1) {\n\t\t\t\treturn false\n\t\t\t}\n\n\t\t\tthis.array[idx] = undefined\n\t\t\tthis.arraySize--\n\n\t\t\tif (idx !== this.arraySize) {\n\t\t\t\t// If the item is not the last item in the array, move the last item into the\n\t\t\t\t// removed item's slot.\n\t\t\t\tthis.array[idx] = this.array[this.arraySize]\n\t\t\t\tthis.array[this.arraySize] = undefined\n\t\t\t}\n\n\t\t\treturn true\n\t\t}\n\n\t\tif (this.set) {\n\t\t\t// If the item is not in the set, return false.\n\t\t\tif (!this.set.has(elem)) {\n\t\t\t\treturn false\n\t\t\t}\n\n\t\t\tthis.set.delete(elem)\n\n\t\t\treturn true\n\t\t}\n\n\t\tthrow new Error('no set or array')\n\t}\n\n\t/**\n\t * Run a callback for each element in the ArraySet.\n\t *\n\t * @param visitor - The callback to run for each element.\n\t */\n\tvisit(visitor: (item: T) => void) {\n\t\tif (this.array) {\n\t\t\tfor (let i = 0; i < this.arraySize; i++) {\n\t\t\t\tconst elem = this.array[i]\n\n\t\t\t\tif (typeof elem !== 'undefined') {\n\t\t\t\t\tvisitor(elem)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn\n\t\t}\n\n\t\tif (this.set) {\n\t\t\tthis.set.forEach(visitor)\n\n\t\t\treturn\n\t\t}\n\n\t\tthrow new Error('no set or array')\n\t}\n\n\thas(elem: T) {\n\t\tif (this.array) {\n\t\t\treturn this.array.indexOf(elem) !== -1\n\t\t} else {\n\t\t\treturn this.set!.has(elem)\n\t\t}\n\t}\n\n\tclear() {\n\t\tif (this.set) {\n\t\t\tthis.set.clear()\n\t\t} else {\n\t\t\tthis.arraySize = 0\n\t\t\tthis.array = []\n\t\t}\n\t}\n\n\tsize() {\n\t\tif (this.set) {\n\t\t\treturn this.set.size\n\t\t} else {\n\t\t\treturn this.arraySize\n\t\t}\n\t}\n}\n", "import { ArraySet } from './ArraySet'\nimport { HistoryBuffer } from './HistoryBuffer'\nimport { maybeCaptureParent } from './capture'\nimport { EMPTY_ARRAY, equals, singleton } from './helpers'\nimport { advanceGlobalEpoch, atomDidChange, getGlobalEpoch } from './transactions'\nimport { Child, ComputeDiff, RESET_VALUE, Signal } from './types'\n\n/**\n * The options to configure an atom, passed into the [[atom]] function.\n * @public\n */\nexport interface AtomOptions {\n\t/**\n\t * The maximum number of diffs to keep in the history buffer.\n\t *\n\t * If you don't need to compute diffs, or if you will supply diffs manually via [[Atom.set]], you can leave this as `undefined` and no history buffer will be created.\n\t *\n\t * If you expect the value to be part of an active effect subscription all the time, and to not change multiple times inside of a single transaction, you can set this to a relatively low number (e.g. 10).\n\t *\n\t * Otherwise, set this to a higher number based on your usage pattern and memory constraints.\n\t *\n\t */\n\thistoryLength?: number\n\t/**\n\t * A method used to compute a diff between the atom's old and new values. If provided, it will not be used unless you also specify [[AtomOptions.historyLength]].\n\t */\n\tcomputeDiff?: ComputeDiff\n\t/**\n\t * If provided, this will be used to compare the old and new values of the atom to determine if the value has changed.\n\t * By default, values are compared using first using strict equality (`===`), then `Object.is`, and finally any `.equals` method present in the object's prototype chain.\n\t * @param a - The old value\n\t * @param b - The new value\n\t * @returns\n\t */\n\tisEqual?: (a: any, b: any) => boolean\n}\n\n/**\n * An Atom is a signal that can be updated directly by calling [[Atom.set]] or [[Atom.update]].\n *\n * Atoms are created using the [[atom]] function.\n *\n * @example\n * ```ts\n * const name = atom('name', 'John')\n *\n * print(name.get()) // 'John'\n * ```\n *\n * @public\n */\nexport interface Atom extends Signal {\n\t/**\n\t * Sets the value of this atom to the given value. If the value is the same as the current value, this is a no-op.\n\t *\n\t * @param value - The new value to set.\n\t * @param diff - The diff to use for the update. If not provided, the diff will be computed using [[AtomOptions.computeDiff]].\n\t */\n\tset(value: Value, diff?: Diff): Value\n\t/**\n\t * Updates the value of this atom using the given updater function. If the returned value is the same as the current value, this is a no-op.\n\t *\n\t * @param updater - A function that takes the current value and returns the new value.\n\t */\n\tupdate(updater: (value: Value) => Value): Value\n}\n\n/**\n * @internal\n */\nclass __Atom__ implements Atom {\n\tconstructor(\n\t\tpublic readonly name: string,\n\t\tprivate current: Value,\n\t\toptions?: AtomOptions\n\t) {\n\t\tthis.isEqual = options?.isEqual ?? null\n\n\t\tif (!options) return\n\n\t\tif (options.historyLength) {\n\t\t\tthis.historyBuffer = new HistoryBuffer(options.historyLength)\n\t\t}\n\n\t\tthis.computeDiff = options.computeDiff\n\t}\n\n\treadonly isEqual: null | ((a: any, b: any) => boolean)\n\n\tcomputeDiff?: ComputeDiff\n\n\tlastChangedEpoch = getGlobalEpoch()\n\n\tchildren = new ArraySet()\n\n\thistoryBuffer?: HistoryBuffer\n\n\t__unsafe__getWithoutCapture(_ignoreErrors?: boolean): Value {\n\t\treturn this.current\n\t}\n\n\tget() {\n\t\tmaybeCaptureParent(this)\n\t\treturn this.current\n\t}\n\n\tset(value: Value, diff?: Diff): Value {\n\t\t// If the value has not changed, do nothing.\n\t\tif (this.isEqual?.(this.current, value) ?? equals(this.current, value)) {\n\t\t\treturn this.current\n\t\t}\n\n\t\t// Tick forward the global epoch\n\t\tadvanceGlobalEpoch()\n\n\t\t// Add the diff to the history buffer.\n\t\tif (this.historyBuffer) {\n\t\t\tthis.historyBuffer.pushEntry(\n\t\t\t\tthis.lastChangedEpoch,\n\t\t\t\tgetGlobalEpoch(),\n\t\t\t\tdiff ??\n\t\t\t\t\tthis.computeDiff?.(this.current, value, this.lastChangedEpoch, getGlobalEpoch()) ??\n\t\t\t\t\tRESET_VALUE\n\t\t\t)\n\t\t}\n\n\t\t// Update the atom's record of the epoch when last changed.\n\t\tthis.lastChangedEpoch = getGlobalEpoch()\n\n\t\tconst oldValue = this.current\n\t\tthis.current = value\n\n\t\t// Notify all children that this atom has changed.\n\t\tatomDidChange(this as any, oldValue)\n\n\t\treturn value\n\t}\n\n\tupdate(updater: (value: Value) => Value): Value {\n\t\treturn this.set(updater(this.current))\n\t}\n\n\tgetDiffSince(epoch: number): RESET_VALUE | Diff[] {\n\t\tmaybeCaptureParent(this)\n\n\t\t// If no changes have occurred since the given epoch, return an empty array.\n\t\tif (epoch >= this.lastChangedEpoch) {\n\t\t\treturn EMPTY_ARRAY\n\t\t}\n\n\t\treturn this.historyBuffer?.getChangesSince(epoch) ?? RESET_VALUE\n\t}\n}\n\nexport const _Atom = singleton('Atom', () => __Atom__)\nexport type _Atom = InstanceType\n\n/**\n * Creates a new [[Atom]].\n *\n * An Atom is a signal that can be updated directly by calling [[Atom.set]] or [[Atom.update]].\n *\n * @example\n * ```ts\n * const name = atom('name', 'John')\n *\n * name.get() // 'John'\n *\n * name.set('Jane')\n *\n * name.get() // 'Jane'\n * ```\n *\n * @public\n */\nexport function atom(\n\t/**\n\t * A name for the signal. This is used for debugging and profiling purposes, it does not need to be unique.\n\t */\n\tname: string,\n\t/**\n\t * The initial value of the signal.\n\t */\n\tinitialValue: Value,\n\t/**\n\t * The options to configure the atom. See [[AtomOptions]].\n\t */\n\toptions?: AtomOptions\n): Atom {\n\treturn new _Atom(name, initialValue, options)\n}\n\n/**\n * Returns true if the given value is an [[Atom]].\n * @public\n */\nexport function isAtom(value: unknown): value is Atom {\n\treturn value instanceof _Atom\n}\n", "import { RESET_VALUE } from './types'\n\ntype RangeTuple = [fromEpoch: number, toEpoch: number, diff: Diff]\n\n/**\n * A structure that stores diffs between values of an atom.\n *\n * @internal\n */\nexport class HistoryBuffer {\n\tprivate index = 0\n\n\t// use a wrap around buffer to store the last N values\n\tbuffer: Array | undefined>\n\n\tconstructor(private readonly capacity: number) {\n\t\tthis.buffer = new Array(capacity)\n\t}\n\n\t/**\n\t * Add a diff to the history buffer.\n\t *\n\t * @param lastComputedEpoch - The epoch when the diff was computed.\n\t * @param currentEpoch - The current epoch.\n\t * @param diff - The diff to add, or else a reset value.\n\t */\n\tpushEntry(lastComputedEpoch: number, currentEpoch: number, diff: Diff | RESET_VALUE) {\n\t\tif (diff === undefined) {\n\t\t\treturn\n\t\t}\n\n\t\tif (diff === RESET_VALUE) {\n\t\t\tthis.clear()\n\t\t\treturn\n\t\t}\n\n\t\t// Add the diff to the buffer as a range tuple.\n\t\tthis.buffer[this.index] = [lastComputedEpoch, currentEpoch, diff]\n\n\t\t// Bump the index, wrapping around if necessary.\n\t\tthis.index = (this.index + 1) % this.capacity\n\t}\n\n\t/**\n\t * Clear the history buffer.\n\t */\n\tclear() {\n\t\tthis.index = 0\n\t\tthis.buffer.fill(undefined)\n\t}\n\n\t/**\n\t * Get the diffs since the given epoch.\n\t *\n\t * @param epoch - The epoch to get diffs since.\n\t * @returns An array of diffs or a flag to reset the history buffer.\n\t */\n\tgetChangesSince(sinceEpoch: number): RESET_VALUE | Diff[] {\n\t\tconst { index, capacity, buffer } = this\n\n\t\t// For each item in the buffer...\n\t\tfor (let i = 0; i < capacity; i++) {\n\t\t\tconst offset = (index - 1 + capacity - i) % capacity\n\n\t\t\tconst elem = buffer[offset]\n\n\t\t\t// If there's no element in the offset position, return the reset value\n\t\t\tif (!elem) {\n\t\t\t\treturn RESET_VALUE\n\t\t\t}\n\n\t\t\tconst [fromEpoch, toEpoch] = elem\n\n\t\t\t// If the first element is already too early, bail\n\t\t\tif (i === 0 && sinceEpoch >= toEpoch) {\n\t\t\t\treturn []\n\t\t\t}\n\n\t\t\t// If the element is since the given epoch, return an array with all diffs from this element and all following elements\n\t\t\tif (fromEpoch <= sinceEpoch && sinceEpoch < toEpoch) {\n\t\t\t\tconst len = i + 1\n\t\t\t\tconst result = new Array(len)\n\n\t\t\t\tfor (let j = 0; j < len; j++) {\n\t\t\t\t\tresult[j] = buffer[(offset + j) % capacity]![2]\n\t\t\t\t}\n\n\t\t\t\treturn result\n\t\t\t}\n\t\t}\n\n\t\t// If we haven't returned yet, return the reset value\n\t\treturn RESET_VALUE\n\t}\n}\n", "import { ArraySet } from './ArraySet'\n\n/** @public */\nexport const RESET_VALUE: unique symbol = Symbol.for('com.tldraw.state/RESET_VALUE')\n\n/** @public */\nexport type RESET_VALUE = typeof RESET_VALUE\n\n/**\n * A Signal is a reactive value container. The value may change over time, and it may keep track of the diffs between sequential values.\n *\n * There are two types of signal:\n *\n * - Atomic signals, created using [[atom]]. These are mutable references to values that can be changed using [[Atom.set]].\n * - Computed signals, created using [[computed]]. These are values that are computed from other signals. They are recomputed lazily if their dependencies change.\n *\n * @public\n */\nexport interface Signal {\n\t/**\n\t * The name of the signal. This is used at runtime for debugging and perf profiling only. It does not need to be globally unique.\n\t */\n\tname: string\n\t/**\n\t * The current value of the signal. This is a reactive value, and will update when the signal changes.\n\t * Any computed signal that depends on this signal will be lazily recomputed if this signal changes.\n\t * Any effect that depends on this signal will be rescheduled if this signal changes.\n\t */\n\tget(): Value\n\n\t/**\n\t * The epoch when this signal's value last changed. Note tha this is not the same as when the value was last computed.\n\t * A signal may recopmute it's value without changing it.\n\t */\n\tlastChangedEpoch: number\n\t/**\n\t * Returns the sequence of diffs between the the value at the given epoch and the current value.\n\t * Returns the [[RESET_VALUE]] constant if there is not enough information to compute the diff sequence.\n\t * @param epoch - The epoch to get diffs since.\n\t */\n\tgetDiffSince(epoch: number): RESET_VALUE | Diff[]\n\t/**\n\t * Returns the current value of the signal without capturing it as a dependency.\n\t * Use this if you need to retrieve the signal's value in a hot loop where the performance overhead of dependency tracking is too high.\n\t */\n\t__unsafe__getWithoutCapture(ignoreErrors?: boolean): Value\n\t/** @internal */\n\tchildren: ArraySet\n}\n\n/** @internal */\nexport interface Child {\n\tlastTraversedEpoch: number\n\treadonly parentSet: ArraySet>\n\treadonly parents: Signal[]\n\treadonly parentEpochs: number[]\n\tisActivelyListening: boolean\n}\n\n/**\n * Computes the diff between the previous and current value.\n *\n * If the diff cannot be computed for whatever reason, it should return [[RESET_VALUE]].\n *\n * @public\n */\nexport type ComputeDiff = (\n\tpreviousValue: Value,\n\tcurrentValue: Value,\n\tlastComputedEpoch: number,\n\tcurrentEpoch: number\n) => Diff | RESET_VALUE\n", "import { attach, detach, singleton } from './helpers'\nimport type { Child, Signal } from './types'\n\nclass CaptureStackFrame {\n\toffset = 0\n\n\tmaybeRemoved?: Signal[]\n\n\tconstructor(\n\t\tpublic readonly below: CaptureStackFrame | null,\n\t\tpublic readonly child: Child\n\t) {}\n}\n\nconst inst = singleton('capture', () => ({ stack: null as null | CaptureStackFrame }))\n\n/**\n * Executes the given function without capturing any parents in the current capture context.\n *\n * This is mainly useful if you want to run an effect only when certain signals change while also\n * dereferencing other signals which should not cause the effect to rerun on their own.\n *\n * @example\n * ```ts\n * const name = atom('name', 'Sam')\n * const time = atom('time', () => new Date().getTime())\n *\n * setInterval(() => {\n * time.set(new Date().getTime())\n * })\n *\n * react('log name changes', () => {\n * \t print(name.get(), 'was changed at', unsafe__withoutCapture(() => time.get()))\n * })\n *\n * ```\n *\n * @public\n */\nexport function unsafe__withoutCapture(fn: () => T): T {\n\tconst oldStack = inst.stack\n\tinst.stack = null\n\ttry {\n\t\treturn fn()\n\t} finally {\n\t\tinst.stack = oldStack\n\t}\n}\n\nexport function startCapturingParents(child: Child) {\n\tinst.stack = new CaptureStackFrame(inst.stack, child)\n\tchild.parentSet.clear()\n}\n\nexport function stopCapturingParents() {\n\tconst frame = inst.stack!\n\tinst.stack = frame.below\n\n\tif (frame.offset < frame.child.parents.length) {\n\t\tfor (let i = frame.offset; i < frame.child.parents.length; i++) {\n\t\t\tconst maybeRemovedParent = frame.child.parents[i]\n\t\t\tif (!frame.child.parentSet.has(maybeRemovedParent)) {\n\t\t\t\tdetach(maybeRemovedParent, frame.child)\n\t\t\t}\n\t\t}\n\n\t\tframe.child.parents.length = frame.offset\n\t\tframe.child.parentEpochs.length = frame.offset\n\t}\n\n\tif (frame.maybeRemoved) {\n\t\tfor (let i = 0; i < frame.maybeRemoved.length; i++) {\n\t\t\tconst maybeRemovedParent = frame.maybeRemoved[i]\n\t\t\tif (!frame.child.parentSet.has(maybeRemovedParent)) {\n\t\t\t\tdetach(maybeRemovedParent, frame.child)\n\t\t\t}\n\t\t}\n\t}\n}\n\n// this must be called after the parent is up to date\nexport function maybeCaptureParent(p: Signal) {\n\tif (inst.stack) {\n\t\tconst wasCapturedAlready = inst.stack.child.parentSet.has(p)\n\t\t// if the child didn't deref this parent last time it executed, then idx will be -1\n\t\t// if the child did deref this parent last time but in a different order relative to other parents, then idx will be greater than stack.offset\n\t\t// if the child did deref this parent last time in the same order, then idx will be the same as stack.offset\n\t\t// if the child did deref this parent already during this capture session then 0 <= idx < stack.offset\n\n\t\tif (wasCapturedAlready) {\n\t\t\treturn\n\t\t}\n\n\t\tinst.stack.child.parentSet.add(p)\n\t\tif (inst.stack.child.isActivelyListening) {\n\t\t\tattach(p, inst.stack.child)\n\t\t}\n\n\t\tif (inst.stack.offset < inst.stack.child.parents.length) {\n\t\t\tconst maybeRemovedParent = inst.stack.child.parents[inst.stack.offset]\n\t\t\tif (maybeRemovedParent !== p) {\n\t\t\t\tif (!inst.stack.maybeRemoved) {\n\t\t\t\t\tinst.stack.maybeRemoved = [maybeRemovedParent]\n\t\t\t\t} else {\n\t\t\t\t\tinst.stack.maybeRemoved.push(maybeRemovedParent)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tinst.stack.child.parents[inst.stack.offset] = p\n\t\tinst.stack.child.parentEpochs[inst.stack.offset] = p.lastChangedEpoch\n\t\tinst.stack.offset++\n\t}\n}\n\n/**\n * A debugging tool that tells you why a computed signal or effect is running.\n * Call in the body of a computed signal or effect function.\n *\n * @example\n * ```ts\n * const name = atom('name', 'Bob')\n * react('greeting', () => {\n * \twhyAmIRunning()\n *\tprint('Hello', name.get())\n * })\n *\n * name.set('Alice')\n *\n * // 'greeting' is running because:\n * // 'name' changed => 'Alice'\n * ```\n *\n * @public\n */\nexport function whyAmIRunning() {\n\tconst child = inst.stack?.child\n\tif (!child) {\n\t\tthrow new Error('whyAmIRunning() called outside of a reactive context')\n\t}\n\n\tconst changedParents = []\n\tfor (let i = 0; i < child.parents.length; i++) {\n\t\tconst parent = child.parents[i]\n\n\t\tif (parent.lastChangedEpoch > child.parentEpochs[i]) {\n\t\t\tchangedParents.push(parent)\n\t\t}\n\t}\n\n\tif (changedParents.length === 0) {\n\t\t// eslint-disable-next-line no-console\n\t\tconsole.log((child as any).name, 'is running but none of the parents changed')\n\t} else {\n\t\t// eslint-disable-next-line no-console\n\t\tconsole.log((child as any).name, 'is running because:')\n\t\tfor (const changedParent of changedParents) {\n\t\t\t// eslint-disable-next-line no-console\n\t\t\tconsole.log(\n\t\t\t\t'\\t',\n\t\t\t\t(changedParent as any).name,\n\t\t\t\t'changed =>',\n\t\t\t\tchangedParent.__unsafe__getWithoutCapture(true)\n\t\t\t)\n\t\t}\n\t}\n}\n", "import { _Atom } from './Atom'\nimport { EffectScheduler } from './EffectScheduler'\nimport { GLOBAL_START_EPOCH } from './constants'\nimport { singleton } from './helpers'\nimport { Child, Signal } from './types'\n\nclass Transaction {\n\tconstructor(public readonly parent: Transaction | null) {}\n\tinitialAtomValues = new Map<_Atom, any>()\n\n\t/**\n\t * Get whether this transaction is a root (no parents).\n\t *\n\t * @public\n\t */\n\t// eslint-disable-next-line no-restricted-syntax\n\tget isRoot() {\n\t\treturn this.parent === null\n\t}\n\n\t/**\n\t * Commit the transaction's changes.\n\t *\n\t * @public\n\t */\n\tcommit() {\n\t\tif (this.isRoot) {\n\t\t\t// For root transactions, flush changed atoms\n\t\t\tflushChanges(this.initialAtomValues.keys())\n\t\t} else {\n\t\t\t// For transactions with parents, add the transaction's initial values to the parent's.\n\t\t\tthis.initialAtomValues.forEach((value, atom) => {\n\t\t\t\tif (!this.parent!.initialAtomValues.has(atom)) {\n\t\t\t\t\tthis.parent!.initialAtomValues.set(atom, value)\n\t\t\t\t}\n\t\t\t})\n\t\t}\n\t}\n\n\t/**\n\t * Abort the transaction.\n\t *\n\t * @public\n\t */\n\tabort() {\n\t\tinst.globalEpoch++\n\n\t\t// Reset each of the transaction's atoms to its initial value.\n\t\tthis.initialAtomValues.forEach((value, atom) => {\n\t\t\tatom.set(value)\n\t\t\tatom.historyBuffer?.clear()\n\t\t})\n\n\t\t// Commit the changes.\n\t\tthis.commit()\n\t}\n}\n\nconst inst = singleton('transactions', () => ({\n\t// The current epoch (global to all atoms).\n\tglobalEpoch: GLOBAL_START_EPOCH + 1,\n\t// Whether any transaction is reacting.\n\tglobalIsReacting: false,\n\tcurrentTransaction: null as Transaction | null,\n\n\tcleanupReactors: null as null | Set>,\n\treactionEpoch: GLOBAL_START_EPOCH + 1,\n}))\n\nexport function getReactionEpoch() {\n\treturn inst.reactionEpoch\n}\n\nexport function getGlobalEpoch() {\n\treturn inst.globalEpoch\n}\n\nexport function getIsReacting() {\n\treturn inst.globalIsReacting\n}\n\nfunction traverse(reactors: Set>, child: Child) {\n\tif (child.lastTraversedEpoch === inst.globalEpoch) {\n\t\treturn\n\t}\n\n\tchild.lastTraversedEpoch = inst.globalEpoch\n\n\tif (child instanceof EffectScheduler) {\n\t\treactors.add(child)\n\t} else {\n\t\t;(child as any as Signal).children.visit((c) => traverse(reactors, c))\n\t}\n}\n\n/**\n * Collect all of the reactors that need to run for an atom and run them.\n *\n * @param atom The atom to flush changes for.\n */\nfunction flushChanges(atoms: Iterable<_Atom>) {\n\tif (inst.globalIsReacting) {\n\t\tthrow new Error('cannot change atoms during reaction cycle')\n\t}\n\n\ttry {\n\t\tinst.globalIsReacting = true\n\t\tinst.reactionEpoch = inst.globalEpoch\n\n\t\t// Collect all of the visited reactors.\n\t\tconst reactors = new Set>()\n\n\t\tfor (const atom of atoms) {\n\t\t\tatom.children.visit((child) => traverse(reactors, child))\n\t\t}\n\n\t\t// Run each reactor.\n\t\tfor (const r of reactors) {\n\t\t\tr.maybeScheduleEffect()\n\t\t}\n\n\t\tlet updateDepth = 0\n\t\twhile (inst.cleanupReactors?.size) {\n\t\t\tif (updateDepth++ > 1000) {\n\t\t\t\tthrow new Error('Reaction update depth limit exceeded')\n\t\t\t}\n\t\t\tconst reactors = inst.cleanupReactors\n\t\t\tinst.cleanupReactors = null\n\t\t\tfor (const r of reactors) {\n\t\t\t\tr.maybeScheduleEffect()\n\t\t\t}\n\t\t}\n\t} finally {\n\t\tinst.cleanupReactors = null\n\t\tinst.globalIsReacting = false\n\t}\n}\n\n/**\n * Handle a change to an atom.\n *\n * @param atom The atom that changed.\n * @param previousValue The atom's previous value.\n *\n * @internal\n */\nexport function atomDidChange(atom: _Atom, previousValue: any) {\n\tif (inst.globalIsReacting) {\n\t\t// If the atom changed during the reaction phase of flushChanges\n\t\t// then we are past the point where a transaction can be aborted\n\t\t// so we don't need to note down the previousValue.\n\t\tconst rs = (inst.cleanupReactors ??= new Set())\n\t\tatom.children.visit((child) => traverse(rs, child))\n\t} else if (!inst.currentTransaction) {\n\t\t// If there is no transaction, flush the changes immediately.\n\t\tflushChanges([atom])\n\t} else if (!inst.currentTransaction.initialAtomValues.has(atom)) {\n\t\t// If we are in a transaction, then all we have to do is preserve\n\t\t// the value of the atom at the start of the transaction in case\n\t\t// we need to roll back.\n\t\tinst.currentTransaction.initialAtomValues.set(atom, previousValue)\n\t}\n}\n\nexport function advanceGlobalEpoch() {\n\tinst.globalEpoch++\n}\n\n/**\n * Batches state updates, deferring side effects until after the transaction completes.\n *\n * @example\n * ```ts\n * const firstName = atom('John')\n * const lastName = atom('Doe')\n *\n * react('greet', () => {\n * print(`Hello, ${firstName.get()} ${lastName.get()}!`)\n * })\n *\n * // Logs \"Hello, John Doe!\"\n *\n * transaction(() => {\n * firstName.set('Jane')\n * lastName.set('Smith')\n * })\n *\n * // Logs \"Hello, Jane Smith!\"\n * ```\n *\n * If the function throws, the transaction is aborted and any signals that were updated during the transaction revert to their state before the transaction began.\n *\n * @example\n * ```ts\n * const firstName = atom('John')\n * const lastName = atom('Doe')\n *\n * react('greet', () => {\n * print(`Hello, ${firstName.get()} ${lastName.get()}!`)\n * })\n *\n * // Logs \"Hello, John Doe!\"\n *\n * transaction(() => {\n * firstName.set('Jane')\n * throw new Error('oops')\n * })\n *\n * // Does not log\n * // firstName.get() === 'John'\n * ```\n *\n * A `rollback` callback is passed into the function.\n * Calling this will prevent the transaction from committing and will revert any signals that were updated during the transaction to their state before the transaction began.\n *\n * * @example\n * ```ts\n * const firstName = atom('John')\n * const lastName = atom('Doe')\n *\n * react('greet', () => {\n * print(`Hello, ${firstName.get()} ${lastName.get()}!`)\n * })\n *\n * // Logs \"Hello, John Doe!\"\n *\n * transaction((rollback) => {\n * firstName.set('Jane')\n * lastName.set('Smith')\n * rollback()\n * })\n *\n * // Does not log\n * // firstName.get() === 'John'\n * // lastName.get() === 'Doe'\n * ```\n *\n * @param fn - The function to run in a transaction, called with a function to roll back the change.\n * @public\n */\nexport function transaction(fn: (rollback: () => void) => T) {\n\tconst txn = new Transaction(inst.currentTransaction)\n\n\t// Set the current transaction to the transaction\n\tinst.currentTransaction = txn\n\n\ttry {\n\t\tlet result = undefined as T | undefined\n\t\tlet rollback = false\n\n\t\ttry {\n\t\t\t// Run the function.\n\t\t\tresult = fn(() => (rollback = true))\n\t\t} catch (e) {\n\t\t\t// Abort the transaction if the function throws.\n\t\t\ttxn.abort()\n\t\t\tthrow e\n\t\t}\n\n\t\tif (rollback) {\n\t\t\t// If the rollback was triggered, abort the transaction.\n\t\t\ttxn.abort()\n\t\t} else {\n\t\t\ttxn.commit()\n\t\t}\n\n\t\treturn result\n\t} finally {\n\t\t// Set the current transaction to the transaction's parent.\n\t\tinst.currentTransaction = inst.currentTransaction.parent\n\t}\n}\n\n/**\n * Like [transaction](#transaction), but does not create a new transaction if there is already one in progress.\n *\n * @param fn - The function to run in a transaction.\n * @public\n */\nexport function transact(fn: () => T): T {\n\tif (inst.currentTransaction) {\n\t\treturn fn()\n\t}\n\treturn transaction(fn)\n}\n", "import { ArraySet } from './ArraySet'\nimport { startCapturingParents, stopCapturingParents } from './capture'\nimport { GLOBAL_START_EPOCH } from './constants'\nimport { attach, detach, haveParentsChanged, singleton } from './helpers'\nimport { getGlobalEpoch } from './transactions'\nimport { Signal } from './types'\n\n/** @public */\nexport interface EffectSchedulerOptions {\n\t/**\n\t * scheduleEffect is a function that will be called when the effect is scheduled.\n\t *\n\t * It can be used to defer running effects until a later time, for example to batch them together with requestAnimationFrame.\n\t *\n\t *\n\t * @example\n\t * ```ts\n\t * let isRafScheduled = false\n\t * const scheduledEffects: Array<() => void> = []\n\t * const scheduleEffect = (runEffect: () => void) => {\n\t * \tscheduledEffects.push(runEffect)\n\t * \tif (!isRafScheduled) {\n\t * \t\tisRafScheduled = true\n\t * \t\trequestAnimationFrame(() => {\n\t * \t\t\tisRafScheduled = false\n\t * \t\t\tscheduledEffects.forEach((runEffect) => runEffect())\n\t * \t\t\tscheduledEffects.length = 0\n\t * \t\t})\n\t * \t}\n\t * }\n\t * const stop = react('set page title', () => {\n\t * \tdocument.title = doc.title,\n\t * }, scheduleEffect)\n\t * ```\n\t *\n\t * @param execute - A function that will execute the effect.\n\t * @returns\n\t */\n\tscheduleEffect?: (execute: () => void) => void\n}\n\nclass __EffectScheduler__ implements EffectScheduler {\n\tprivate _isActivelyListening = false\n\t/**\n\t * Whether this scheduler is attached and actively listening to its parents.\n\t * @public\n\t */\n\t// eslint-disable-next-line no-restricted-syntax\n\tget isActivelyListening() {\n\t\treturn this._isActivelyListening\n\t}\n\t/** @internal */\n\tlastTraversedEpoch = GLOBAL_START_EPOCH\n\n\tprivate lastReactedEpoch = GLOBAL_START_EPOCH\n\tprivate _scheduleCount = 0\n\n\t/**\n\t * The number of times this effect has been scheduled.\n\t * @public\n\t */\n\t// eslint-disable-next-line no-restricted-syntax\n\tget scheduleCount() {\n\t\treturn this._scheduleCount\n\t}\n\n\t/** @internal */\n\treadonly parentSet = new ArraySet>()\n\t/** @internal */\n\treadonly parentEpochs: number[] = []\n\t/** @internal */\n\treadonly parents: Signal[] = []\n\tprivate readonly _scheduleEffect?: (execute: () => void) => void\n\tconstructor(\n\t\tpublic readonly name: string,\n\t\tprivate readonly runEffect: (lastReactedEpoch: number) => Result,\n\t\toptions?: EffectSchedulerOptions\n\t) {\n\t\tthis._scheduleEffect = options?.scheduleEffect\n\t}\n\n\t/** @internal */\n\tmaybeScheduleEffect() {\n\t\t// bail out if we have been cancelled by another effect\n\t\tif (!this._isActivelyListening) return\n\t\t// bail out if no atoms have changed since the last time we ran this effect\n\t\tif (this.lastReactedEpoch === getGlobalEpoch()) return\n\n\t\t// bail out if we have parents and they have not changed since last time\n\t\tif (this.parents.length && !haveParentsChanged(this)) {\n\t\t\tthis.lastReactedEpoch = getGlobalEpoch()\n\t\t\treturn\n\t\t}\n\t\t// if we don't have parents it's probably the first time this is running.\n\t\tthis.scheduleEffect()\n\t}\n\n\t/** @internal */\n\tscheduleEffect() {\n\t\tthis._scheduleCount++\n\t\tif (this._scheduleEffect) {\n\t\t\t// if the effect should be deferred (e.g. until a react render), do so\n\t\t\tthis._scheduleEffect(this.maybeExecute)\n\t\t} else {\n\t\t\t// otherwise execute right now!\n\t\t\tthis.execute()\n\t\t}\n\t}\n\n\t/** @internal */\n\treadonly maybeExecute = () => {\n\t\t// bail out if we have been detached before this runs\n\t\tif (!this._isActivelyListening) return\n\t\tthis.execute()\n\t}\n\n\t/**\n\t * Makes this scheduler become 'actively listening' to its parents.\n\t * If it has been executed before it will immediately become eligible to receive 'maybeScheduleEffect' calls.\n\t * If it has not executed before it will need to be manually executed once to become eligible for scheduling, i.e. by calling [[EffectScheduler.execute]].\n\t * @public\n\t */\n\tattach() {\n\t\tthis._isActivelyListening = true\n\t\tfor (let i = 0, n = this.parents.length; i < n; i++) {\n\t\t\tattach(this.parents[i], this)\n\t\t}\n\t}\n\n\t/**\n\t * Makes this scheduler stop 'actively listening' to its parents.\n\t * It will no longer be eligible to receive 'maybeScheduleEffect' calls until [[EffectScheduler.attach]] is called again.\n\t */\n\tdetach() {\n\t\tthis._isActivelyListening = false\n\t\tfor (let i = 0, n = this.parents.length; i < n; i++) {\n\t\t\tdetach(this.parents[i], this)\n\t\t}\n\t}\n\n\t/**\n\t * Executes the effect immediately and returns the result.\n\t * @returns The result of the effect.\n\t */\n\texecute(): Result {\n\t\ttry {\n\t\t\tstartCapturingParents(this)\n\t\t\t// Important! We have to make a note of the current epoch before running the effect.\n\t\t\t// We allow atoms to be updated during effects, which increments the global epoch,\n\t\t\t// so if we were to wait until after the effect runs, the this.lastReactedEpoch value might get ahead of itself.\n\t\t\tconst currentEpoch = getGlobalEpoch()\n\t\t\tconst result = this.runEffect(this.lastReactedEpoch)\n\t\t\tthis.lastReactedEpoch = currentEpoch\n\t\t\treturn result\n\t\t} finally {\n\t\t\tstopCapturingParents()\n\t\t}\n\t}\n}\n\n/**\n * An EffectScheduler is responsible for executing side effects in response to changes in state.\n *\n * You probably don't need to use this directly unless you're integrating this library with a framework of some kind.\n *\n * Instead, use the [[react]] and [[reactor]] functions.\n *\n * @example\n * ```ts\n * const render = new EffectScheduler('render', drawToCanvas)\n *\n * render.attach()\n * render.execute()\n * ```\n *\n * @public\n */\nexport const EffectScheduler = singleton(\n\t'EffectScheduler',\n\t(): {\n\t\tnew (\n\t\t\tname: string,\n\t\t\trunEffect: (lastReactedEpoch: number) => Result,\n\t\t\toptions?: EffectSchedulerOptions\n\t\t): EffectScheduler\n\t} => __EffectScheduler__\n)\n/** @public */\nexport interface EffectScheduler {\n\t/**\n\t * Whether this scheduler is attached and actively listening to its parents.\n\t * @public\n\t */\n\treadonly isActivelyListening: boolean\n\n\t/** @internal */\n\treadonly lastTraversedEpoch: number\n\n\t/**\n\t * The number of times this effect has been scheduled.\n\t * @public\n\t */\n\treadonly scheduleCount: number\n\n\t/** @internal */\n\treadonly parentSet: ArraySet>\n\n\t/** @internal */\n\treadonly parentEpochs: number[]\n\n\t/** @internal */\n\treadonly parents: Signal[]\n\n\t/** @internal */\n\tmaybeScheduleEffect(): void\n\n\t/** @internal */\n\tscheduleEffect(): void\n\n\t/** @internal */\n\tmaybeExecute(): void\n\n\t/**\n\t * Makes this scheduler become 'actively listening' to its parents.\n\t * If it has been executed before it will immediately become eligible to receive 'maybeScheduleEffect' calls.\n\t * If it has not executed before it will need to be manually executed once to become eligible for scheduling, i.e. by calling [[EffectScheduler.execute]].\n\t * @public\n\t */\n\tattach(): void\n\n\t/**\n\t * Makes this scheduler stop 'actively listening' to its parents.\n\t * It will no longer be eligible to receive 'maybeScheduleEffect' calls until [[EffectScheduler.attach]] is called again.\n\t */\n\tdetach(): void\n\n\t/**\n\t * Executes the effect immediately and returns the result.\n\t * @returns The result of the effect.\n\t */\n\texecute(): Result\n}\n\n/**\n * Starts a new effect scheduler, scheduling the effect immediately.\n *\n * Returns a function that can be called to stop the scheduler.\n *\n * @example\n * ```ts\n * const color = atom('color', 'red')\n * const stop = react('set style', () => {\n * divElem.style.color = color.get()\n * })\n * color.set('blue')\n * // divElem.style.color === 'blue'\n * stop()\n * color.set('green')\n * // divElem.style.color === 'blue'\n * ```\n *\n *\n * Also useful in React applications for running effects outside of the render cycle.\n *\n * @example\n * ```ts\n * useEffect(() => react('set style', () => {\n * divRef.current.style.color = color.get()\n * }), [])\n * ```\n *\n * @public\n */\nexport function react(\n\tname: string,\n\tfn: (lastReactedEpoch: number) => any,\n\toptions?: EffectSchedulerOptions\n) {\n\tconst scheduler = new EffectScheduler(name, fn, options)\n\tscheduler.attach()\n\tscheduler.scheduleEffect()\n\treturn () => {\n\t\tscheduler.detach()\n\t}\n}\n\n/**\n * The reactor is a user-friendly interface for starting and stopping an [[EffectScheduler]].\n *\n * Calling .start() will attach the scheduler and execute the effect immediately the first time it is called.\n *\n * If the reactor is stopped, calling `.start()` will re-attach the scheduler but will only execute the effect if any of its parents have changed since it was stopped.\n *\n * You can create a reactor with [[reactor]].\n * @public\n */\nexport interface Reactor {\n\t/**\n\t * The underlying effect scheduler.\n\t * @public\n\t */\n\tscheduler: EffectScheduler\n\t/**\n\t * Start the scheduler. The first time this is called the effect will be scheduled immediately.\n\t *\n\t * If the reactor is stopped, calling this will start the scheduler again but will only execute the effect if any of its parents have changed since it was stopped.\n\t *\n\t * If you need to force re-execution of the effect, pass `{ force: true }`.\n\t * @public\n\t */\n\tstart(options?: { force?: boolean }): void\n\t/**\n\t * Stop the scheduler.\n\t * @public\n\t */\n\tstop(): void\n}\n\n/**\n * Creates a [[Reactor]], which is a thin wrapper around an [[EffectScheduler]].\n *\n * @public\n */\nexport function reactor(\n\tname: string,\n\tfn: (lastReactedEpoch: number) => Result,\n\toptions?: EffectSchedulerOptions\n): Reactor {\n\tconst scheduler = new EffectScheduler(name, fn, options)\n\treturn {\n\t\tscheduler,\n\t\tstart: (options?: { force?: boolean }) => {\n\t\t\tconst force = options?.force ?? false\n\t\t\tscheduler.attach()\n\t\t\tif (force) {\n\t\t\t\tscheduler.scheduleEffect()\n\t\t\t} else {\n\t\t\t\tscheduler.maybeScheduleEffect()\n\t\t\t}\n\t\t},\n\t\tstop: () => {\n\t\t\tscheduler.detach()\n\t\t},\n\t}\n}\n", "// Derivations start on GLOBAL_START_EPOCH so they are dirty before having been computed\nexport const GLOBAL_START_EPOCH = -1\n", "/* eslint-disable prefer-rest-params */\nimport { ArraySet } from './ArraySet'\nimport { HistoryBuffer } from './HistoryBuffer'\nimport { maybeCaptureParent, startCapturingParents, stopCapturingParents } from './capture'\nimport { GLOBAL_START_EPOCH } from './constants'\nimport { EMPTY_ARRAY, equals, haveParentsChanged, singleton } from './helpers'\nimport { getGlobalEpoch, getIsReacting, getReactionEpoch } from './transactions'\nimport { Child, ComputeDiff, RESET_VALUE, Signal } from './types'\nimport { logComputedGetterWarning } from './warnings'\n\n/**\n * @public\n */\nexport const UNINITIALIZED = Symbol.for('com.tldraw.state/UNINITIALIZED')\n/**\n * The type of the first value passed to a computed signal function as the 'prevValue' parameter.\n *\n * @see [[isUninitialized]].\n * @public\n */\nexport type UNINITIALIZED = typeof UNINITIALIZED\n\n/**\n * Call this inside a computed signal function to determine whether it is the first time the function is being called.\n *\n * Mainly useful for incremental signal computation.\n *\n * @example\n * ```ts\n * const count = atom('count', 0)\n * const double = computed('double', (prevValue) => {\n * if (isUninitialized(prevValue)) {\n * print('First time!')\n * }\n * return count.get() * 2\n * })\n * ```\n *\n * @param value - The value to check.\n * @public\n */\nexport const isUninitialized = (value: any): value is UNINITIALIZED => {\n\treturn value === UNINITIALIZED\n}\n\n/** @public */\nexport const WithDiff = singleton(\n\t'WithDiff',\n\t() =>\n\t\tclass WithDiff {\n\t\t\tconstructor(\n\t\t\t\tpublic value: Value,\n\t\t\t\tpublic diff: Diff\n\t\t\t) {}\n\t\t}\n)\n\n/** @public */\nexport interface WithDiff {\n\tvalue: Value\n\tdiff: Diff\n}\n\n/**\n * When writing incrementally-computed signals it is convenient (and usually more performant) to incrementally compute the diff too.\n *\n * You can use this function to wrap the return value of a computed signal function to indicate that the diff should be used instead of calculating a new one with [[AtomOptions.computeDiff]].\n *\n * @example\n * ```ts\n * const count = atom('count', 0)\n * const double = computed('double', (prevValue) => {\n * const nextValue = count.get() * 2\n * if (isUninitialized(prevValue)) {\n * return nextValue\n * }\n * return withDiff(nextValue, nextValue - prevValue)\n * }, { historyLength: 10 })\n * ```\n *\n *\n * @param value - The value.\n * @param diff - The diff.\n * @public\n */\nexport function withDiff(value: Value, diff: Diff): WithDiff {\n\treturn new WithDiff(value, diff)\n}\n\n/**\n * Options for creating computed signals. Used when calling [[computed]].\n * @public\n */\nexport interface ComputedOptions {\n\t/**\n\t * The maximum number of diffs to keep in the history buffer.\n\t *\n\t * If you don't need to compute diffs, or if you will supply diffs manually via [[Atom.set]], you can leave this as `undefined` and no history buffer will be created.\n\t *\n\t * If you expect the value to be part of an active effect subscription all the time, and to not change multiple times inside of a single transaction, you can set this to a relatively low number (e.g. 10).\n\t *\n\t * Otherwise, set this to a higher number based on your usage pattern and memory constraints.\n\t *\n\t */\n\thistoryLength?: number\n\t/**\n\t * A method used to compute a diff between the atom's old and new values. If provided, it will not be used unless you also specify [[AtomOptions.historyLength]].\n\t */\n\tcomputeDiff?: ComputeDiff\n\t/**\n\t * If provided, this will be used to compare the old and new values of the atom to determine if the value has changed.\n\t * By default, values are compared using first using strict equality (`===`), then `Object.is`, and finally any `.equals` method present in the object's prototype chain.\n\t * @param a - The old value\n\t * @param b - The new value\n\t * @returns\n\t */\n\tisEqual?: (a: any, b: any) => boolean\n}\n\n/**\n * A computed signal created via [[computed]].\n *\n * @public\n */\nexport interface Computed extends Signal {\n\t/**\n\t * Whether this computed child is involved in an actively-running effect graph.\n\t * @public\n\t */\n\treadonly isActivelyListening: boolean\n\n\t/** @internal */\n\treadonly parentSet: ArraySet>\n\t/** @internal */\n\treadonly parents: Signal[]\n\t/** @internal */\n\treadonly parentEpochs: number[]\n}\n\n/**\n * @internal\n */\nclass __UNSAFE__Computed implements Computed {\n\tlastChangedEpoch = GLOBAL_START_EPOCH\n\tlastTraversedEpoch = GLOBAL_START_EPOCH\n\n\t/**\n\t * The epoch when the reactor was last checked.\n\t */\n\tprivate lastCheckedEpoch = GLOBAL_START_EPOCH\n\n\tparentSet = new ArraySet>()\n\tparents: Signal[] = []\n\tparentEpochs: number[] = []\n\n\tchildren = new ArraySet()\n\n\t// eslint-disable-next-line no-restricted-syntax\n\tget isActivelyListening(): boolean {\n\t\treturn !this.children.isEmpty\n\t}\n\n\thistoryBuffer?: HistoryBuffer\n\n\t// The last-computed value of this signal.\n\tprivate state: Value = UNINITIALIZED as unknown as Value\n\t// If the signal throws an error we stash it so we can rethrow it on the next get()\n\tprivate error: null | { thrownValue: any } = null\n\n\tprivate computeDiff?: ComputeDiff\n\n\tprivate readonly isEqual: (a: any, b: any) => boolean\n\n\tconstructor(\n\t\t/**\n\t\t * The name of the signal. This is used for debugging and performance profiling purposes. It does not need to be globally unique.\n\t\t */\n\t\tpublic readonly name: string,\n\t\t/**\n\t\t * The function that computes the value of the signal.\n\t\t */\n\t\tprivate readonly derive: (\n\t\t\tpreviousValue: Value | UNINITIALIZED,\n\t\t\tlastComputedEpoch: number\n\t\t) => Value | WithDiff,\n\t\toptions?: ComputedOptions\n\t) {\n\t\tif (options?.historyLength) {\n\t\t\tthis.historyBuffer = new HistoryBuffer(options.historyLength)\n\t\t}\n\t\tthis.computeDiff = options?.computeDiff\n\t\tthis.isEqual = options?.isEqual ?? equals\n\t}\n\n\t__unsafe__getWithoutCapture(ignoreErrors?: boolean): Value {\n\t\tconst isNew = this.lastChangedEpoch === GLOBAL_START_EPOCH\n\n\t\tconst globalEpoch = getGlobalEpoch()\n\n\t\tif (\n\t\t\t!isNew &&\n\t\t\t(this.lastCheckedEpoch === globalEpoch ||\n\t\t\t\t(this.isActivelyListening &&\n\t\t\t\t\tgetIsReacting() &&\n\t\t\t\t\tthis.lastTraversedEpoch < getReactionEpoch()) ||\n\t\t\t\t!haveParentsChanged(this))\n\t\t) {\n\t\t\tthis.lastCheckedEpoch = globalEpoch\n\t\t\tif (this.error) {\n\t\t\t\tif (!ignoreErrors) {\n\t\t\t\t\tthrow this.error.thrownValue\n\t\t\t\t} else {\n\t\t\t\t\treturn this.state // will be UNINITIALIZED\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\treturn this.state\n\t\t\t}\n\t\t}\n\n\t\ttry {\n\t\t\tstartCapturingParents(this)\n\t\t\tconst result = this.derive(this.state, this.lastCheckedEpoch)\n\t\t\tconst newState = result instanceof WithDiff ? result.value : result\n\t\t\tconst isUninitialized = this.state === UNINITIALIZED\n\t\t\tif (isUninitialized || !this.isEqual(newState, this.state)) {\n\t\t\t\tif (this.historyBuffer && !isUninitialized) {\n\t\t\t\t\tconst diff = result instanceof WithDiff ? result.diff : undefined\n\t\t\t\t\tthis.historyBuffer.pushEntry(\n\t\t\t\t\t\tthis.lastChangedEpoch,\n\t\t\t\t\t\tgetGlobalEpoch(),\n\t\t\t\t\t\tdiff ??\n\t\t\t\t\t\t\tthis.computeDiff?.(this.state, newState, this.lastCheckedEpoch, getGlobalEpoch()) ??\n\t\t\t\t\t\t\tRESET_VALUE\n\t\t\t\t\t)\n\t\t\t\t}\n\t\t\t\tthis.lastChangedEpoch = getGlobalEpoch()\n\t\t\t\tthis.state = newState\n\t\t\t}\n\t\t\tthis.error = null\n\t\t\tthis.lastCheckedEpoch = getGlobalEpoch()\n\n\t\t\treturn this.state\n\t\t} catch (e) {\n\t\t\t// if a derived value throws an error, we reset the state to UNINITIALIZED\n\t\t\tif (this.state !== UNINITIALIZED) {\n\t\t\t\tthis.state = UNINITIALIZED as unknown as Value\n\t\t\t\tthis.lastChangedEpoch = getGlobalEpoch()\n\t\t\t}\n\t\t\tthis.lastCheckedEpoch = getGlobalEpoch()\n\t\t\t// we also clear the history buffer if an error was thrown\n\t\t\tif (this.historyBuffer) {\n\t\t\t\tthis.historyBuffer.clear()\n\t\t\t}\n\t\t\tthis.error = { thrownValue: e }\n\t\t\t// we don't wish to propagate errors when derefed via haveParentsChanged()\n\t\t\tif (!ignoreErrors) throw e\n\t\t\treturn this.state\n\t\t} finally {\n\t\t\tstopCapturingParents()\n\t\t}\n\t}\n\n\tget(): Value {\n\t\ttry {\n\t\t\treturn this.__unsafe__getWithoutCapture()\n\t\t} finally {\n\t\t\t// if the deriver throws an error we still need to capture\n\t\t\tmaybeCaptureParent(this)\n\t\t}\n\t}\n\n\tgetDiffSince(epoch: number): RESET_VALUE | Diff[] {\n\t\t// we can ignore any errors thrown during derive\n\t\tthis.__unsafe__getWithoutCapture(true)\n\t\t// and we still need to capture this signal as a parent\n\t\tmaybeCaptureParent(this)\n\n\t\tif (epoch >= this.lastChangedEpoch) {\n\t\t\treturn EMPTY_ARRAY\n\t\t}\n\n\t\treturn this.historyBuffer?.getChangesSince(epoch) ?? RESET_VALUE\n\t}\n}\n\nexport const _Computed = singleton('Computed', () => __UNSAFE__Computed)\nexport type _Computed = InstanceType\n\nfunction computedMethodAnnotation(\n\toptions: ComputedOptions = {},\n\t_target: any,\n\tkey: string,\n\tdescriptor: PropertyDescriptor\n) {\n\tconst originalMethod = descriptor.value\n\tconst derivationKey = Symbol.for('__@tldraw/state__computed__' + key)\n\n\tdescriptor.value = function (this: any) {\n\t\tlet d = this[derivationKey] as Computed | undefined\n\n\t\tif (!d) {\n\t\t\td = new _Computed(key, originalMethod!.bind(this) as any, options)\n\t\t\tObject.defineProperty(this, derivationKey, {\n\t\t\t\tenumerable: false,\n\t\t\t\tconfigurable: false,\n\t\t\t\twritable: false,\n\t\t\t\tvalue: d,\n\t\t\t})\n\t\t}\n\t\treturn d.get()\n\t}\n\tdescriptor.value[isComputedMethodKey] = true\n\n\treturn descriptor\n}\n\nfunction computedAnnotation(\n\toptions: ComputedOptions = {},\n\t_target: any,\n\tkey: string,\n\tdescriptor: PropertyDescriptor\n) {\n\tif (descriptor.get) {\n\t\tlogComputedGetterWarning()\n\t\treturn computedGetterAnnotation(options, _target, key, descriptor)\n\t} else {\n\t\treturn computedMethodAnnotation(options, _target, key, descriptor)\n\t}\n}\n\nfunction computedGetterAnnotation(\n\toptions: ComputedOptions = {},\n\t_target: any,\n\tkey: string,\n\tdescriptor: PropertyDescriptor\n) {\n\tconst originalMethod = descriptor.get\n\tconst derivationKey = Symbol.for('__@tldraw/state__computed__' + key)\n\n\tdescriptor.get = function (this: any) {\n\t\tlet d = this[derivationKey] as Computed | undefined\n\n\t\tif (!d) {\n\t\t\td = new _Computed(key, originalMethod!.bind(this) as any, options)\n\t\t\tObject.defineProperty(this, derivationKey, {\n\t\t\t\tenumerable: false,\n\t\t\t\tconfigurable: false,\n\t\t\t\twritable: false,\n\t\t\t\tvalue: d,\n\t\t\t})\n\t\t}\n\t\treturn d.get()\n\t}\n\n\treturn descriptor\n}\n\nconst isComputedMethodKey = '@@__isComputedMethod__@@'\n\n/**\n * Retrieves the underlying computed instance for a given property created with the [[computed]]\n * decorator.\n *\n * @example\n * ```ts\n * class Counter {\n * max = 100\n * count = atom(0)\n *\n * @computed getRemaining() {\n * return this.max - this.count.get()\n * }\n * }\n *\n * const c = new Counter()\n * const remaining = getComputedInstance(c, 'getRemaining')\n * remaining.get() === 100 // true\n * c.count.set(13)\n * remaining.get() === 87 // true\n * ```\n *\n * @param obj - The object\n * @param propertyName - The property name\n * @public\n */\nexport function getComputedInstance(\n\tobj: Obj,\n\tpropertyName: Prop\n): Computed {\n\tconst key = Symbol.for('__@tldraw/state__computed__' + propertyName.toString())\n\tlet inst = obj[key as keyof typeof obj] as Computed | undefined\n\tif (!inst) {\n\t\t// deref to make sure it exists first\n\t\tconst val = obj[propertyName]\n\t\tif (typeof val === 'function' && (val as any)[isComputedMethodKey]) {\n\t\t\tval.call(obj)\n\t\t}\n\n\t\tinst = obj[key as keyof typeof obj] as Computed | undefined\n\t}\n\treturn inst as any\n}\n\n/**\n * Creates a computed signal.\n *\n * @example\n * ```ts\n * const name = atom('name', 'John')\n * const greeting = computed('greeting', () => `Hello ${name.get()}!`)\n * console.log(greeting.get()) // 'Hello John!'\n * ```\n *\n * `computed` may also be used as a decorator for creating computed getter methods.\n *\n * @example\n * ```ts\n * class Counter {\n * max = 100\n * count = atom(0)\n *\n * @computed getRemaining() {\n * return this.max - this.count.get()\n * }\n * }\n * ```\n *\n * You may optionally pass in a [[ComputedOptions]] when used as a decorator:\n *\n * @example\n * ```ts\n * class Counter {\n * max = 100\n * count = atom(0)\n *\n * @computed({isEqual: (a, b) => a === b})\n * getRemaining() {\n * return this.max - this.count.get()\n * }\n * }\n * ```\n *\n * @param name - The name of the signal.\n * @param compute - The function that computes the value of the signal.\n * @param options - Options for the signal.\n *\n * @public\n */\nexport function computed(\n\tname: string,\n\tcompute: (\n\t\tpreviousValue: Value | typeof UNINITIALIZED,\n\t\tlastComputedEpoch: number\n\t) => Value | WithDiff,\n\toptions?: ComputedOptions\n): Computed\n\n/** @public */\nexport function computed(\n\ttarget: any,\n\tkey: string,\n\tdescriptor: PropertyDescriptor\n): PropertyDescriptor\n/** @public */\nexport function computed(\n\toptions?: ComputedOptions\n): (target: any, key: string, descriptor: PropertyDescriptor) => PropertyDescriptor\n/** @public */\nexport function computed() {\n\tif (arguments.length === 1) {\n\t\tconst options = arguments[0]\n\t\treturn (target: any, key: string, descriptor: PropertyDescriptor) =>\n\t\t\tcomputedAnnotation(options, target, key, descriptor)\n\t} else if (typeof arguments[0] === 'string') {\n\t\treturn new _Computed(arguments[0], arguments[1], arguments[2])\n\t} else {\n\t\treturn computedAnnotation(undefined, arguments[0], arguments[1], arguments[2])\n\t}\n}\n\n/**\n * Returns true if the given value is a computed signal.\n *\n * @param value\n * @returns {value is Computed}\n * @public\n */\nexport function isComputed(value: any): value is Computed {\n\treturn value && value instanceof _Computed\n}\n", "let didWarnComputedGetter = false\n\nexport function logComputedGetterWarning() {\n\tif (didWarnComputedGetter) return\n\tdidWarnComputedGetter = true\n\tconsole.warn(\n\t\t`Using \\`@computed\\` as a decorator for getters is deprecated and will be removed in the near future. Please refactor to use \\`@computed\\` as a decorator for methods.\n\n// Before\n@computed\nget foo() {\n\treturn 'foo'\n}\n\n// After\n@computed\ngetFoo() {\n\treturn 'foo'\n}\n`\n\t)\n}\n", "import { _Atom } from './Atom'\nimport { _Computed } from './Computed'\nimport { Signal } from './types'\n\n/**\n * @public\n */\nexport function isSignal(value: any): value is Signal {\n\treturn value instanceof _Atom || value instanceof _Computed\n}\n", "export { default as throttle } from 'lodash.throttle'\nexport { default as uniq } from 'lodash.uniq'\nexport { PerformanceTracker } from './lib/PerformanceTracker'\nexport {\n\tareArraysShallowEqual,\n\tcompact,\n\tdedupe,\n\tlast,\n\tminBy,\n\tpartition,\n\trotateArray,\n} from './lib/array'\nexport { WeakCache } from './lib/cache'\nexport {\n\tResult,\n\tassert,\n\tassertExists,\n\texhaustiveSwitchError,\n\tpromiseWithResolve,\n\ttype ErrorResult,\n\ttype OkResult,\n} from './lib/control'\nexport { debounce } from './lib/debounce'\nexport { annotateError, getErrorAnnotations, type ErrorAnnotations } from './lib/error'\nexport { FileHelpers } from './lib/file'\nexport { noop, omitFromStackTrace } from './lib/function'\nexport { getHashForBuffer, getHashForObject, getHashForString, lns } from './lib/hash'\nexport { getFirstFromIterable } from './lib/iterable'\nexport type { JsonArray, JsonObject, JsonPrimitive, JsonValue } from './lib/json-value'\nexport {\n\tDEFAULT_SUPPORTED_IMAGE_TYPES,\n\tDEFAULT_SUPPORTED_MEDIA_TYPE_LIST,\n\tDEFAULT_SUPPORT_VIDEO_TYPES,\n\tMediaHelpers,\n} from './lib/media/media'\nexport { PngHelpers } from './lib/media/png'\nexport { Image, fetch } from './lib/network'\nexport { invLerp, lerp, modulate, rng } from './lib/number'\nexport {\n\tareObjectsShallowEqual,\n\tfilterEntries,\n\tgetOwnProperty,\n\thasOwnProperty,\n\tmapObjectMapValues,\n\tobjectMapEntries,\n\tobjectMapFromEntries,\n\tobjectMapKeys,\n\tobjectMapValues,\n} from './lib/object'\nexport { measureAverageDuration, measureCbDuration, measureDuration } from './lib/perf'\nexport { type IndexKey } from './lib/reordering/IndexKey'\nexport {\n\tZERO_INDEX_KEY,\n\tgetIndexAbove,\n\tgetIndexBelow,\n\tgetIndexBetween,\n\tgetIndices,\n\tgetIndicesAbove,\n\tgetIndicesBelow,\n\tgetIndicesBetween,\n\tsortByIndex,\n\tvalidateIndexKey,\n} from './lib/reordering/reordering'\nexport { sortById } from './lib/sort'\nexport {\n\tclearLocalStorage,\n\tclearSessionStorage,\n\tdeleteFromLocalStorage,\n\tdeleteFromSessionStorage,\n\tgetFromLocalStorage,\n\tgetFromSessionStorage,\n\tsetInLocalStorage,\n\tsetInSessionStorage,\n} from './lib/storage'\nexport { fpsThrottle, throttleToNextFrame } from './lib/throttle'\nexport { Timers } from './lib/timers'\nexport type { Expand, RecursivePartial, Required } from './lib/types'\nexport {\n\tSTRUCTURED_CLONE_OBJECT_PROTOTYPE,\n\tisDefined,\n\tisNativeStructuredClone,\n\tisNonNull,\n\tisNonNullish,\n\tstructuredClone,\n} from './lib/value'\nexport { warnDeprecatedGetter, warnOnce } from './lib/warn'\n", "import { PERFORMANCE_COLORS, PERFORMANCE_PREFIX_COLOR } from './perf'\n\n/** @public */\nexport class PerformanceTracker {\n\tprivate startTime = 0\n\tprivate name = ''\n\tprivate frames = 0\n\tprivate started = false\n\tprivate frame: number | null = null\n\n\trecordFrame = () => {\n\t\tthis.frames++\n\t\tif (!this.started) return\n\t\t// eslint-disable-next-line no-restricted-globals\n\t\tthis.frame = requestAnimationFrame(this.recordFrame)\n\t}\n\n\tstart(name: string) {\n\t\tthis.name = name\n\t\tthis.frames = 0\n\t\tthis.started = true\n\t\tif (this.frame !== null) cancelAnimationFrame(this.frame)\n\t\t// eslint-disable-next-line no-restricted-globals\n\t\tthis.frame = requestAnimationFrame(this.recordFrame)\n\t\tthis.startTime = performance.now()\n\t}\n\n\tstop() {\n\t\tthis.started = false\n\t\tif (this.frame !== null) cancelAnimationFrame(this.frame)\n\t\tconst duration = (performance.now() - this.startTime) / 1000\n\t\tconst fps = duration === 0 ? 0 : Math.floor(this.frames / duration)\n\t\tconst background =\n\t\t\tfps > 55\n\t\t\t\t? PERFORMANCE_COLORS.Good\n\t\t\t\t: fps > 30\n\t\t\t\t\t? PERFORMANCE_COLORS.Mid\n\t\t\t\t\t: PERFORMANCE_COLORS.Poor\n\t\tconst color = background === PERFORMANCE_COLORS.Mid ? 'black' : 'white'\n\t\tconst capitalized = this.name[0].toUpperCase() + this.name.slice(1)\n\t\t// eslint-disable-next-line no-console\n\t\tconsole.debug(\n\t\t\t`%cPerf%c ${capitalized} %c${fps}%c fps`,\n\t\t\t`color: white; background: ${PERFORMANCE_PREFIX_COLOR};padding: 2px;border-radius: 3px;`,\n\t\t\t'font-weight: normal',\n\t\t\t`font-weight: bold; padding: 2px; background: ${background};color: ${color};`,\n\t\t\t'font-weight: normal'\n\t\t)\n\t}\n\n\tisStarted() {\n\t\treturn this.started\n\t}\n}\n", "export const PERFORMANCE_COLORS = {\n\tGood: '#40C057',\n\tMid: '#FFC078',\n\tPoor: '#E03131',\n}\n\nexport const PERFORMANCE_PREFIX_COLOR = PERFORMANCE_COLORS.Good\n\n/** @internal */\nexport function measureCbDuration(name: string, cb: () => any) {\n\tconst start = performance.now()\n\tconst result = cb()\n\t// eslint-disable-next-line no-console\n\tconsole.debug(\n\t\t`%cPerf%c ${name} took ${performance.now() - start}ms`,\n\t\t`color: white; background: ${PERFORMANCE_PREFIX_COLOR};padding: 2px;border-radius: 3px;`,\n\t\t'font-weight: normal'\n\t)\n\treturn result\n}\n\n/** @internal */\nexport function measureDuration(_target: any, propertyKey: string, descriptor: PropertyDescriptor) {\n\tconst originalMethod = descriptor.value\n\tdescriptor.value = function (...args: any[]) {\n\t\tconst start = performance.now()\n\t\tconst result = originalMethod.apply(this, args)\n\t\t// eslint-disable-next-line no-console\n\t\tconsole.debug(\n\t\t\t`%cPerf%c ${propertyKey} took: ${performance.now() - start}ms`,\n\t\t\t`color: white; background: ${PERFORMANCE_PREFIX_COLOR};padding: 2px;border-radius: 3px;`,\n\t\t\t'font-weight: normal'\n\t\t)\n\t\treturn result\n\t}\n\treturn descriptor\n}\n\nconst averages = new Map()\n\n/** @internal */\nexport function measureAverageDuration(\n\t_target: any,\n\tpropertyKey: string,\n\tdescriptor: PropertyDescriptor\n) {\n\tconst originalMethod = descriptor.value\n\tdescriptor.value = function (...args: any[]) {\n\t\tconst start = performance.now()\n\t\tconst result = originalMethod.apply(this, args)\n\t\tconst end = performance.now()\n\t\tconst length = end - start\n\t\tif (length !== 0) {\n\t\t\tconst value = averages.get(descriptor.value)!\n\t\t\tconst total = value.total + length\n\t\t\tconst count = value.count + 1\n\t\t\taverages.set(descriptor.value, { total, count })\n\t\t\t// eslint-disable-next-line no-console\n\t\t\tconsole.debug(\n\t\t\t\t`%cPerf%c ${propertyKey} took ${(end - start).toFixed(2)}ms | average ${(total / count).toFixed(2)}ms`,\n\t\t\t\t`color: white; background: ${PERFORMANCE_PREFIX_COLOR};padding: 2px;border-radius: 3px;`,\n\t\t\t\t'font-weight: normal'\n\t\t\t)\n\t\t}\n\t\treturn result\n\t}\n\taverages.set(descriptor.value, { total: 0, count: 0 })\n\treturn descriptor\n}\n", "/**\n * Rotate the contents of an array.\n *\n * @public\n */\nexport function rotateArray(arr: T[], offset: number): T[] {\n\treturn arr.map((_, i) => arr[(i + offset) % arr.length])\n}\n\n/**\n * Deduplicate the items in an array\n *\n * @public\n */\nexport function dedupe(input: T[], equals?: (a: any, b: any) => boolean): T[] {\n\tconst result: T[] = []\n\tmainLoop: for (const item of input) {\n\t\tfor (const existing of result) {\n\t\t\tif (equals ? equals(item, existing) : item === existing) {\n\t\t\t\tcontinue mainLoop\n\t\t\t}\n\t\t}\n\t\tresult.push(item)\n\t}\n\treturn result\n}\n\n/** @internal */\nexport function compact(arr: T[]): NonNullable[] {\n\treturn arr.filter((i) => i !== undefined && i !== null) as any\n}\n\n/** @internal */\nexport function last(arr: readonly T[]): T | undefined {\n\treturn arr[arr.length - 1]\n}\n\n/** @internal */\nexport function minBy(arr: readonly T[], fn: (item: T) => number): T | undefined {\n\tlet min: T | undefined\n\tlet minVal = Infinity\n\tfor (const item of arr) {\n\t\tconst val = fn(item)\n\t\tif (val < minVal) {\n\t\t\tmin = item\n\t\t\tminVal = val\n\t\t}\n\t}\n\treturn min\n}\n\n/**\n * Partitions an array into two arrays, one with items that satisfy the predicate, and one with\n * items that do not.\n *\n * @param arr - The array to partition\n * @param predicate - The predicate to use to partition the array\n * @returns A tuple of two arrays, the first one with items that satisfy the predicate and the\n * second one with the ones that dont\n * @internal\n */\nexport function partition(arr: T[], predicate: (item: T) => boolean): [T[], T[]] {\n\tconst satisfies: T[] = []\n\tconst doesNotSatisfy: T[] = []\n\tfor (const item of arr) {\n\t\tif (predicate(item)) {\n\t\t\tsatisfies.push(item)\n\t\t} else {\n\t\t\tdoesNotSatisfy.push(item)\n\t\t}\n\t}\n\treturn [satisfies, doesNotSatisfy]\n}\n\n/** @internal */\nexport function areArraysShallowEqual(arr1: readonly T[], arr2: readonly T[]): boolean {\n\tif (arr1 === arr2) return true\n\tif (arr1.length !== arr2.length) return false\n\tfor (let i = 0; i < arr1.length; i++) {\n\t\tif (!Object.is(arr1[i], arr2[i])) {\n\t\t\treturn false\n\t\t}\n\t}\n\treturn true\n}\n", "/**\n * A micro cache used when storing records in memory (using a WeakMap).\n * @public\n */\nexport class WeakCache {\n\t/** The map of items to their cached values. */\n\titems = new WeakMap()\n\n\t/**\n\t * Get the cached value for a given record. If the record is not present in the map, the callback\n\t * will be used to create the value (with the result being stored in the cache for next time).\n\t *\n\t * @param item - The item to get.\n\t * @param cb - The callback to use to create the value when a cached value is not found.\n\t */\n\tget

(item: P, cb: (item: P) => V) {\n\t\tif (!this.items.has(item)) {\n\t\t\tthis.items.set(item, cb(item))\n\t\t}\n\n\t\treturn this.items.get(item)!\n\t}\n}\n", "import { omitFromStackTrace } from './function'\n\n/** @public */\nexport interface OkResult {\n\treadonly ok: true\n\treadonly value: T\n}\n/** @public */\nexport interface ErrorResult {\n\treadonly ok: false\n\treadonly error: E\n}\n/** @public */\nexport type Result = OkResult | ErrorResult\n\n/** @public */\nexport const Result = {\n\tok(value: T): OkResult {\n\t\treturn { ok: true, value }\n\t},\n\terr(error: E): ErrorResult {\n\t\treturn { ok: false, error }\n\t},\n}\n\n/** @internal */\nexport function exhaustiveSwitchError(value: never, property?: string): never {\n\tconst debugValue =\n\t\tproperty && value && typeof value === 'object' && property in value ? value[property] : value\n\tthrow new Error(`Unknown switch case ${debugValue}`)\n}\n\n/** @internal */\nexport const assert: (value: unknown, message?: string) => asserts value = omitFromStackTrace(\n\t(value, message) => {\n\t\tif (!value) {\n\t\t\tthrow new Error(message || 'Assertion Error')\n\t\t}\n\t}\n)\n\n/** @internal */\nexport const assertExists = omitFromStackTrace((value: T, message?: string): NonNullable => {\n\t// note that value == null is equivalent to value === null || value === undefined\n\tif (value == null) {\n\t\tthrow new Error(message ?? 'value must be defined')\n\t}\n\treturn value as NonNullable\n})\n\n/** @internal */\nexport function promiseWithResolve(): Promise & {\n\tresolve: (value: T) => void\n\treject: (reason?: any) => void\n} {\n\tlet resolve: (value: T) => void\n\tlet reject: (reason?: any) => void\n\tconst promise = new Promise((res, rej) => {\n\t\tresolve = res\n\t\treject = rej\n\t})\n\treturn Object.assign(promise, {\n\t\tresolve: resolve!,\n\t\treject: reject!,\n\t})\n}\n", "/**\n * When a function is wrapped in `omitFromStackTrace`, if it throws an error the stack trace won't\n * include the function itself or any stack frames above it. Useful for assertion-style function\n * where the error will ideally originate from the call-site rather than within the implementation\n * of the assert fn.\n *\n * Only works in platforms that support `Error.captureStackTrace` (ie v8).\n *\n * @internal\n */\nexport function omitFromStackTrace, Return>(\n\tfn: (...args: Args) => Return\n): (...args: Args) => Return {\n\tconst wrappedFn = (...args: Args) => {\n\t\ttry {\n\t\t\treturn fn(...args)\n\t\t} catch (error) {\n\t\t\tif (error instanceof Error && Error.captureStackTrace) {\n\t\t\t\tError.captureStackTrace(error, wrappedFn)\n\t\t\t}\n\t\t\tthrow error\n\t\t}\n\t}\n\n\treturn wrappedFn\n}\n\n/**\n * Does nothing, but it's really really good at it.\n * @internal\n */\n// eslint-disable-next-line @typescript-eslint/no-empty-function\nexport const noop: () => void = () => {}\n", "/**\n * Debounce a function.\n *\n * @example\n *\n * ```ts\n * const A = debounce(myFunction, 1000)\n * ```\n *\n * @public\n * @see source - https://gist.github.com/ca0v/73a31f57b397606c9813472f7493a940\n */\nexport function debounce(\n\tcallback: (...args: T) => PromiseLike | U,\n\twait: number\n) {\n\tlet state:\n\t\t| undefined\n\t\t| {\n\t\t\t\t// eslint-disable-next-line no-restricted-globals\n\t\t\t\ttimeout: ReturnType\n\t\t\t\tpromise: Promise\n\t\t\t\tresolve: (value: U | PromiseLike) => void\n\t\t\t\treject: (value: any) => void\n\t\t\t\tlatestArgs: T\n\t\t } = undefined\n\n\tconst fn = (...args: T): Promise => {\n\t\tif (!state) {\n\t\t\tstate = {} as any\n\t\t\tstate!.promise = new Promise((resolve, reject) => {\n\t\t\t\tstate!.resolve = resolve\n\t\t\t\tstate!.reject = reject\n\t\t\t})\n\t\t}\n\t\tclearTimeout(state!.timeout)\n\t\tstate!.latestArgs = args\n\t\t// It's up to the consumer of debounce to call `cancel`\n\t\t// eslint-disable-next-line no-restricted-globals\n\t\tstate!.timeout = setTimeout(() => {\n\t\t\tconst s = state!\n\t\t\tstate = undefined\n\t\t\ttry {\n\t\t\t\ts.resolve(callback(...s.latestArgs))\n\t\t\t} catch (e) {\n\t\t\t\ts.reject(e)\n\t\t\t}\n\t\t}, wait)\n\n\t\treturn state!.promise\n\t}\n\tfn.cancel = () => {\n\t\tif (!state) return\n\t\tclearTimeout(state.timeout)\n\t}\n\treturn fn\n}\n", "/** @public */\nexport interface ErrorAnnotations {\n\ttags: Record\n\textras: Record\n}\n\nconst annotationsByError = new WeakMap()\n\n/**\n * Annotate an error with tags and additional data. Annotations won't overwrite existing ones.\n * Retrieve them with `getErrorAnnotations`.\n *\n * @internal\n */\nexport function annotateError(error: unknown, annotations: Partial) {\n\tif (typeof error !== 'object' || error === null) return\n\n\tlet currentAnnotations = annotationsByError.get(error)\n\tif (!currentAnnotations) {\n\t\tcurrentAnnotations = { tags: {}, extras: {} }\n\t\tannotationsByError.set(error, currentAnnotations)\n\t}\n\n\tif (annotations.tags) {\n\t\tcurrentAnnotations.tags = {\n\t\t\t...currentAnnotations.tags,\n\t\t\t...annotations.tags,\n\t\t}\n\t}\n\tif (annotations.extras) {\n\t\tcurrentAnnotations.extras = {\n\t\t\t...currentAnnotations.extras,\n\t\t\t...annotations.extras,\n\t\t}\n\t}\n}\n\n/** @internal */\nexport function getErrorAnnotations(error: Error): ErrorAnnotations {\n\treturn annotationsByError.get(error) ?? { tags: {}, extras: {} }\n}\n", "import { fetch } from './network'\n\n/**\n * Helpers for files\n *\n * @public\n */\nexport class FileHelpers {\n\t/**\n\t * @param dataURL - The file as a string.\n\t *\n\t * from https://stackoverflow.com/a/53817185\n\t */\n\tstatic async dataUrlToArrayBuffer(dataURL: string) {\n\t\treturn fetch(dataURL).then(function (result) {\n\t\t\treturn result.arrayBuffer()\n\t\t})\n\t}\n\n\t/**\n\t * Convert a file to a base64 encoded data url.\n\t *\n\t * @example\n\t *\n\t * ```ts\n\t * const A = FileHelpers.toDataUrl(myImageFile)\n\t * ```\n\t *\n\t * @param value - The file as a blob.\n\t */\n\tstatic async blobToDataUrl(file: Blob): Promise {\n\t\treturn await new Promise((resolve, reject) => {\n\t\t\tif (file) {\n\t\t\t\tconst reader = new FileReader()\n\t\t\t\treader.onload = () => resolve(reader.result as string)\n\t\t\t\treader.onerror = (error) => reject(error)\n\t\t\t\treader.onabort = (error) => reject(error)\n\t\t\t\treader.readAsDataURL(file)\n\t\t\t}\n\t\t})\n\t}\n\n\t/**\n\t * Convert a file to a unicode text string.\n\t *\n\t * @example\n\t *\n\t * ```ts\n\t * const A = FileHelpers.fileToDataUrl(myTextFile)\n\t * ```\n\t *\n\t * @param value - The file as a blob.\n\t */\n\tstatic async blobToText(file: Blob): Promise {\n\t\treturn await new Promise((resolve, reject) => {\n\t\t\tif (file) {\n\t\t\t\tconst reader = new FileReader()\n\t\t\t\treader.onload = () => resolve(reader.result as string)\n\t\t\t\treader.onerror = (error) => reject(error)\n\t\t\t\treader.onabort = (error) => reject(error)\n\t\t\t\treader.readAsText(file)\n\t\t\t}\n\t\t})\n\t}\n}\n", "/**\n * Just a wrapper around `window.fetch` that sets the `referrerPolicy` to `strict-origin-when-cross-origin`.\n *\n * @internal\n */\nexport async function fetch(input: RequestInfo | URL, init?: RequestInit): Promise {\n\t// eslint-disable-next-line no-restricted-properties\n\treturn window.fetch(input, {\n\t\t// We want to make sure that the referrer is not sent to other domains.\n\t\treferrerPolicy: 'strict-origin-when-cross-origin',\n\t\t...init,\n\t})\n}\n\n/**\n * Just a wrapper around `new Image`, and yeah, it's a bit strange that it's in the network.ts file\n * but the main concern here is the referrerPolicy and setting it correctly.\n *\n * @internal\n */\nexport const Image = (width?: number, height?: number) => {\n\t// eslint-disable-next-line no-restricted-properties\n\tconst img = new window.Image(width, height)\n\timg.referrerPolicy = 'strict-origin-when-cross-origin'\n\treturn img\n}\n", "/**\n * Hash a string using the FNV-1a algorithm.\n *\n * @public\n */\nexport function getHashForString(string: string) {\n\tlet hash = 0\n\tfor (let i = 0; i < string.length; i++) {\n\t\thash = (hash << 5) - hash + string.charCodeAt(i)\n\t\thash |= 0 // Convert to 32bit integer\n\t}\n\treturn hash + ''\n}\n\n/**\n * Hash a string using the FNV-1a algorithm.\n *\n * @public\n */\nexport function getHashForObject(obj: any) {\n\treturn getHashForString(JSON.stringify(obj))\n}\n\n/**\n * Hash an ArrayBuffer using the FNV-1a algorithm.\n *\n * @public\n */\nexport function getHashForBuffer(buffer: ArrayBuffer) {\n\tconst view = new DataView(buffer)\n\tlet hash = 0\n\tfor (let i = 0; i < view.byteLength; i++) {\n\t\thash = (hash << 5) - hash + view.getUint8(i)\n\t\thash |= 0 // Convert to 32bit integer\n\t}\n\treturn hash + ''\n}\n\n/** @public */\nexport function lns(str: string) {\n\tconst result = str.split('')\n\tresult.push(...result.splice(0, Math.round(result.length / 5)))\n\tresult.push(...result.splice(0, Math.round(result.length / 4)))\n\tresult.push(...result.splice(0, Math.round(result.length / 3)))\n\tresult.push(...result.splice(0, Math.round(result.length / 2)))\n\treturn result\n\t\t.reverse()\n\t\t.map((n) => (+n ? (+n < 5 ? 5 + +n : +n > 5 ? +n - 5 : n) : n))\n\t\t.join('')\n}\n", "/**\n * Get the first item from an iterable Set or Map.\n *\n * @example\n *\n * ```ts\n * const A = getFirstItem(new Set([1, 2, 3])) // 1\n * const B = getFirstItem(\n * \tnew Map([\n * \t\t['a', 1],\n * \t\t['b', 2],\n * \t])\n * ) // 1\n * ```\n *\n * @param value - The iterable Set or Map.\n * @public\n */\nexport function getFirstFromIterable(set: Set | Map): T {\n\treturn set.values().next().value\n}\n", "import { Image } from '../network'\nimport { isApngAnimated } from './apng'\nimport { isAvifAnimated } from './avif'\nimport { isGifAnimated } from './gif'\nimport { PngHelpers } from './png'\nimport { isWebpAnimated } from './webp'\n\n/** @public */\nexport const DEFAULT_SUPPORTED_VECTOR_IMAGE_TYPES = Object.freeze(['image/svg+xml'])\n/** @public */\nexport const DEFAULT_SUPPORTED_STATIC_IMAGE_TYPES = Object.freeze([\n\t'image/jpeg',\n\t'image/png',\n\t'image/webp',\n])\n/** @public */\nexport const DEFAULT_SUPPORTED_ANIMATED_IMAGE_TYPES = Object.freeze([\n\t'image/gif',\n\t'image/apng',\n\t'image/avif',\n])\n/** @public */\nexport const DEFAULT_SUPPORTED_IMAGE_TYPES = Object.freeze([\n\t...DEFAULT_SUPPORTED_STATIC_IMAGE_TYPES,\n\t...DEFAULT_SUPPORTED_VECTOR_IMAGE_TYPES,\n\t...DEFAULT_SUPPORTED_ANIMATED_IMAGE_TYPES,\n])\n/** @public */\nexport const DEFAULT_SUPPORT_VIDEO_TYPES = Object.freeze([\n\t'video/mp4',\n\t'video/webm',\n\t'video/quicktime',\n])\n/** @public */\nexport const DEFAULT_SUPPORTED_MEDIA_TYPE_LIST = [\n\t...DEFAULT_SUPPORTED_IMAGE_TYPES,\n\t...DEFAULT_SUPPORT_VIDEO_TYPES,\n].join(',')\n\n/**\n * Helpers for media\n *\n * @public\n */\nexport class MediaHelpers {\n\t/**\n\t * Load a video from a url.\n\t * @public\n\t */\n\tstatic loadVideo(src: string): Promise {\n\t\treturn new Promise((resolve, reject) => {\n\t\t\tconst video = document.createElement('video')\n\t\t\tvideo.onloadeddata = () => resolve(video)\n\t\t\tvideo.onerror = (e) => {\n\t\t\t\tconsole.error(e)\n\t\t\t\treject(new Error('Could not load video'))\n\t\t\t}\n\t\t\tvideo.crossOrigin = 'anonymous'\n\t\t\tvideo.src = src\n\t\t})\n\t}\n\n\t/**\n\t * Load an image from a url.\n\t * @public\n\t */\n\tstatic loadImage(src: string): Promise {\n\t\treturn new Promise((resolve, reject) => {\n\t\t\tconst img = Image()\n\t\t\timg.onload = () => resolve(img)\n\t\t\timg.onerror = (e) => {\n\t\t\t\tconsole.error(e)\n\t\t\t\treject(new Error('Could not load image'))\n\t\t\t}\n\t\t\timg.crossOrigin = 'anonymous'\n\t\t\timg.referrerPolicy = 'strict-origin-when-cross-origin'\n\t\t\timg.src = src\n\t\t})\n\t}\n\n\t/**\n\t * Get the size of a video blob\n\t *\n\t * @param src - A SharedBlob containing the video\n\t * @public\n\t */\n\tstatic async getVideoSize(blob: Blob): Promise<{ w: number; h: number }> {\n\t\treturn MediaHelpers.usingObjectURL(blob, async (url) => {\n\t\t\tconst video = await MediaHelpers.loadVideo(url)\n\t\t\treturn { w: video.videoWidth, h: video.videoHeight }\n\t\t})\n\t}\n\n\t/**\n\t * Get the size of an image blob\n\t *\n\t * @param dataURL - A Blob containing the image.\n\t * @public\n\t */\n\tstatic async getImageSize(blob: Blob): Promise<{ w: number; h: number }> {\n\t\tconst image = await MediaHelpers.usingObjectURL(blob, MediaHelpers.loadImage)\n\n\t\ttry {\n\t\t\tif (blob.type === 'image/png') {\n\t\t\t\tconst view = new DataView(await blob.arrayBuffer())\n\t\t\t\tif (PngHelpers.isPng(view, 0)) {\n\t\t\t\t\tconst physChunk = PngHelpers.findChunk(view, 'pHYs')\n\t\t\t\t\tif (physChunk) {\n\t\t\t\t\t\tconst physData = PngHelpers.parsePhys(view, physChunk.dataOffset)\n\t\t\t\t\t\tif (physData.unit === 0 && physData.ppux === physData.ppuy) {\n\t\t\t\t\t\t\tconst pixelRatio = Math.max(physData.ppux / 2834.5, 1)\n\t\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t\tw: Math.round(image.naturalWidth / pixelRatio),\n\t\t\t\t\t\t\t\th: Math.round(image.naturalHeight / pixelRatio),\n\t\t\t\t\t\t\t}\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} catch (err) {\n\t\t\tconsole.error(err)\n\t\t\treturn { w: image.naturalWidth, h: image.naturalHeight }\n\t\t}\n\t\treturn { w: image.naturalWidth, h: image.naturalHeight }\n\t}\n\n\tstatic async isAnimated(file: Blob): Promise {\n\t\tif (file.type === 'image/gif') {\n\t\t\treturn isGifAnimated(await file.arrayBuffer())\n\t\t}\n\n\t\tif (file.type === 'image/avif') {\n\t\t\treturn isAvifAnimated(await file.arrayBuffer())\n\t\t}\n\n\t\tif (file.type === 'image/webp') {\n\t\t\treturn isWebpAnimated(await file.arrayBuffer())\n\t\t}\n\n\t\tif (file.type === 'image/apng') {\n\t\t\treturn isApngAnimated(await file.arrayBuffer())\n\t\t}\n\n\t\treturn false\n\t}\n\n\tstatic isAnimatedImageType(mimeType: string | null): boolean {\n\t\treturn DEFAULT_SUPPORTED_ANIMATED_IMAGE_TYPES.includes(mimeType || '')\n\t}\n\n\tstatic isStaticImageType(mimeType: string | null): boolean {\n\t\treturn DEFAULT_SUPPORTED_STATIC_IMAGE_TYPES.includes(mimeType || '')\n\t}\n\n\tstatic isVectorImageType(mimeType: string | null): boolean {\n\t\treturn DEFAULT_SUPPORTED_VECTOR_IMAGE_TYPES.includes(mimeType || '')\n\t}\n\n\tstatic isImageType(mimeType: string): boolean {\n\t\treturn DEFAULT_SUPPORTED_IMAGE_TYPES.includes(mimeType)\n\t}\n\n\tstatic async usingObjectURL(blob: Blob, fn: (url: string) => Promise): Promise {\n\t\tconst url = URL.createObjectURL(blob)\n\t\ttry {\n\t\t\treturn await fn(url)\n\t\t} finally {\n\t\t\tURL.revokeObjectURL(url)\n\t\t}\n\t}\n}\n", "/*!\n * MIT License: https://github.com/vHeemstra/is-apng/blob/main/license\n * Copyright (c) Philip van Heemstra\n */\n\nexport function isApngAnimated(buffer: ArrayBuffer): boolean {\n\tconst view = new Uint8Array(buffer)\n\n\tif (\n\t\t!view ||\n\t\t!((typeof Buffer !== 'undefined' && Buffer.isBuffer(view)) || view instanceof Uint8Array) ||\n\t\tview.length < 16\n\t) {\n\t\treturn false\n\t}\n\n\tconst isPNG =\n\t\tview[0] === 0x89 &&\n\t\tview[1] === 0x50 &&\n\t\tview[2] === 0x4e &&\n\t\tview[3] === 0x47 &&\n\t\tview[4] === 0x0d &&\n\t\tview[5] === 0x0a &&\n\t\tview[6] === 0x1a &&\n\t\tview[7] === 0x0a\n\n\tif (!isPNG) {\n\t\treturn false\n\t}\n\n\t/**\n\t * Returns the index of the first occurrence of a sequence in an typed array, or -1 if it is not present.\n\t *\n\t * Works similar to `Array.prototype.indexOf()`, but it searches for a sequence of array values (bytes).\n\t * The bytes in the `haystack` array are decoded (UTF-8) and then used to search for `needle`.\n\t *\n\t * @param haystack `Uint8Array`\n\t * Array to search in.\n\t *\n\t * @param needle `string | RegExp`\n\t * The value to locate in the array.\n\t *\n\t * @param fromIndex `number`\n\t * The array index at which to begin the search.\n\t *\n\t * @param upToIndex `number`\n\t * The array index up to which to search.\n\t * If omitted, search until the end.\n\t *\n\t * @param chunksize `number`\n\t * Size of the chunks used when searching (default 1024).\n\t *\n\t * @returns boolean\n\t * Whether the array holds Animated PNG data.\n\t */\n\tfunction indexOfSubstring(\n\t\thaystack: Uint8Array,\n\t\tneedle: string | RegExp,\n\t\tfromIndex: number,\n\t\tupToIndex?: number,\n\t\tchunksize = 1024 /* Bytes */\n\t) {\n\t\t/**\n\t\t * Adopted from: https://stackoverflow.com/a/67771214/2142071\n\t\t */\n\n\t\tif (!needle) {\n\t\t\treturn -1\n\t\t}\n\t\tneedle = new RegExp(needle, 'g')\n\n\t\t// The needle could get split over two chunks.\n\t\t// So, at every chunk we prepend the last few characters\n\t\t// of the last chunk.\n\t\tconst needle_length = needle.source.length\n\t\tconst decoder = new TextDecoder()\n\n\t\t// Handle search offset in line with\n\t\t// `Array.prototype.indexOf()` and `TypedArray.prototype.subarray()`.\n\t\tconst full_haystack_length = haystack.length\n\t\tif (typeof upToIndex === 'undefined') {\n\t\t\tupToIndex = full_haystack_length\n\t\t}\n\t\tif (fromIndex >= full_haystack_length || upToIndex <= 0 || fromIndex >= upToIndex) {\n\t\t\treturn -1\n\t\t}\n\t\thaystack = haystack.subarray(fromIndex, upToIndex)\n\n\t\tlet position = -1\n\t\tlet current_index = 0\n\t\tlet full_length = 0\n\t\tlet needle_buffer = ''\n\n\t\touter: while (current_index < haystack.length) {\n\t\t\tconst next_index = current_index + chunksize\n\t\t\t// subarray doesn't copy\n\t\t\tconst chunk = haystack.subarray(current_index, next_index)\n\t\t\tconst decoded = decoder.decode(chunk, { stream: true })\n\n\t\t\tconst text = needle_buffer + decoded\n\n\t\t\tlet match: RegExpExecArray | null\n\t\t\tlet last_index = -1\n\t\t\twhile ((match = needle.exec(text)) !== null) {\n\t\t\t\tlast_index = match.index - needle_buffer.length\n\t\t\t\tposition = full_length + last_index\n\t\t\t\tbreak outer\n\t\t\t}\n\n\t\t\tcurrent_index = next_index\n\t\t\tfull_length += decoded.length\n\n\t\t\t// Check that the buffer doesn't itself include the needle\n\t\t\t// this would cause duplicate finds (we could also use a Set to avoid that).\n\t\t\tconst needle_index =\n\t\t\t\tlast_index > -1 ? last_index + needle_length : decoded.length - needle_length\n\t\t\tneedle_buffer = decoded.slice(needle_index)\n\t\t}\n\n\t\t// Correct for search offset.\n\t\tif (position >= 0) {\n\t\t\tposition += fromIndex >= 0 ? fromIndex : full_haystack_length + fromIndex\n\t\t}\n\n\t\treturn position\n\t}\n\n\t// APNGs have an animation control chunk ('acTL') preceding the IDATs.\n\t// See: https://en.wikipedia.org/wiki/APNG#File_format\n\tconst idatIdx = indexOfSubstring(view, 'IDAT', 12)\n\tif (idatIdx >= 12) {\n\t\tconst actlIdx = indexOfSubstring(view, 'acTL', 8, idatIdx)\n\t\treturn actlIdx >= 8\n\t}\n\n\treturn false\n}\n\n// globalThis.isApng = isApng\n\n// (new TextEncoder()).encode('IDAT')\n// Decimal: [73, 68, 65, 84]\n// Hex: [0x49, 0x44, 0x41, 0x54]\n\n// (new TextEncoder()).encode('acTL')\n// Decimal: [97, 99, 84, 76]\n// Hex: [0x61, 0x63, 0x54, 0x4C]\n\n// const idatIdx = buffer.indexOf('IDAT')\n// const actlIdx = buffer.indexOf('acTL')\n", "export const isAvifAnimated = (buffer: ArrayBuffer) => {\n\tconst view = new Uint8Array(buffer)\n\treturn view[3] === 44\n}\n", "/*!\n * MIT License\n * Modified code originally from \n * Copyright (c) 2016 J\u00F3zef Soko\u0142owski \n */\n\n/** Returns total length of data blocks sequence */\nfunction getDataBlocksLength(buffer: Uint8Array, offset: number): number {\n\tlet length = 0\n\n\twhile (buffer[offset + length]) {\n\t\tlength += buffer[offset + length] + 1\n\t}\n\n\treturn length + 1\n}\n\n/**\n * Checks if buffer contains GIF image\n *\n * @public\n */\nexport function isGIF(buffer: ArrayBuffer): boolean {\n\tconst enc = new TextDecoder('ascii')\n\tconst header = enc.decode(buffer.slice(0, 3))\n\treturn header === 'GIF'\n}\n\n/**\n * Checks if buffer contains animated GIF image\n *\n * @public\n */\nexport function isGifAnimated(buffer: ArrayBuffer): boolean {\n\tconst view = new Uint8Array(buffer)\n\tlet hasColorTable, colorTableSize\n\tlet offset = 0\n\tlet imagesCount = 0\n\n\t// Check if this is this image has valid GIF header.\n\t// If not return false. Chrome, FF and IE doesn't handle GIFs with invalid version.\n\tif (!isGIF(buffer)) {\n\t\treturn false\n\t}\n\n\t// Skip header, logical screen descriptor and global color table\n\n\thasColorTable = view[10] & 0x80 // 0b10000000\n\tcolorTableSize = view[10] & 0x07 // 0b00000111\n\n\toffset += 6 // skip header\n\toffset += 7 // skip logical screen descriptor\n\toffset += hasColorTable ? 3 * Math.pow(2, colorTableSize + 1) : 0 // skip global color table\n\n\t// Find if there is more than one image descriptor\n\n\twhile (imagesCount < 2 && offset < view.length) {\n\t\tswitch (view[offset]) {\n\t\t\t// Image descriptor block. According to specification there could be any\n\t\t\t// number of these blocks (even zero). When there is more than one image\n\t\t\t// descriptor browsers will display animation (they shouldn't when there\n\t\t\t// is no delays defined, but they do it anyway).\n\t\t\tcase 0x2c:\n\t\t\t\timagesCount += 1\n\n\t\t\t\thasColorTable = view[offset + 9] & 0x80 // 0b10000000\n\t\t\t\tcolorTableSize = view[offset + 9] & 0x07 // 0b00000111\n\n\t\t\t\toffset += 10 // skip image descriptor\n\t\t\t\toffset += hasColorTable ? 3 * Math.pow(2, colorTableSize + 1) : 0 // skip local color table\n\t\t\t\toffset += getDataBlocksLength(view, offset + 1) + 1 // skip image data\n\n\t\t\t\tbreak\n\n\t\t\t// Skip all extension blocks. In theory this \"plain text extension\" blocks\n\t\t\t// could be frames of animation, but no browser renders them.\n\t\t\tcase 0x21:\n\t\t\t\toffset += 2 // skip introducer and label\n\t\t\t\toffset += getDataBlocksLength(view, offset) // skip this block and following data blocks\n\n\t\t\t\tbreak\n\n\t\t\t// Stop processing on trailer block,\n\t\t\t// all data after this point will is ignored by decoders\n\t\t\tcase 0x3b:\n\t\t\t\toffset = view.length // fast forward to end of buffer\n\t\t\t\tbreak\n\n\t\t\t// Oops! This GIF seems to be invalid\n\t\t\tdefault:\n\t\t\t\t// fast forward to end of buffer\n\t\t\t\toffset = view.length\n\t\t\t\tbreak\n\t\t}\n\t}\n\n\treturn imagesCount > 1\n}\n", "type BufferInput = string | ArrayBuffer | Buffer\n\ninterface CRCCalculator {\n\t(value: T, previous?: number): number\n}\n\nlet TABLE: Array | Int32Array = [\n\t0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,\n\t0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,\n\t0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,\n\t0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,\n\t0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,\n\t0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,\n\t0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,\n\t0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,\n\t0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,\n\t0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,\n\t0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,\n\t0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,\n\t0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,\n\t0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,\n\t0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,\n\t0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,\n\t0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,\n\t0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,\n\t0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,\n\t0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,\n\t0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,\n\t0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,\n\t0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,\n\t0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,\n\t0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,\n\t0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,\n\t0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,\n\t0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,\n\t0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,\n\t0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,\n\t0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,\n\t0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,\n]\n\nif (typeof Int32Array !== 'undefined') {\n\tTABLE = new Int32Array(TABLE)\n}\n\n/*!\n * MIT License: https://github.com/alexgorbatchev/crc/blob/master/LICENSE\n * Copyright: 2014 Alex Gorbatchev\n * Code: crc32, https://github.com/alexgorbatchev/crc/blob/master/src/calculators/crc32.ts\n */\nconst crc: CRCCalculator = (current, previous) => {\n\tlet crc = previous === 0 ? 0 : ~~previous! ^ -1\n\n\tfor (let index = 0; index < current.length; index++) {\n\t\tcrc = TABLE[(crc ^ current[index]) & 0xff] ^ (crc >>> 8)\n\t}\n\n\treturn crc ^ -1\n}\n\nconst LEN_SIZE = 4\nconst CRC_SIZE = 4\n\n/** @public */\nexport class PngHelpers {\n\tstatic isPng(view: DataView, offset: number) {\n\t\tif (\n\t\t\tview.getUint8(offset + 0) === 0x89 &&\n\t\t\tview.getUint8(offset + 1) === 0x50 &&\n\t\t\tview.getUint8(offset + 2) === 0x4e &&\n\t\t\tview.getUint8(offset + 3) === 0x47 &&\n\t\t\tview.getUint8(offset + 4) === 0x0d &&\n\t\t\tview.getUint8(offset + 5) === 0x0a &&\n\t\t\tview.getUint8(offset + 6) === 0x1a &&\n\t\t\tview.getUint8(offset + 7) === 0x0a\n\t\t) {\n\t\t\treturn true\n\t\t}\n\t\treturn false\n\t}\n\n\tstatic getChunkType(view: DataView, offset: number) {\n\t\treturn [\n\t\t\tString.fromCharCode(view.getUint8(offset)),\n\t\t\tString.fromCharCode(view.getUint8(offset + 1)),\n\t\t\tString.fromCharCode(view.getUint8(offset + 2)),\n\t\t\tString.fromCharCode(view.getUint8(offset + 3)),\n\t\t].join('')\n\t}\n\n\tstatic readChunks(view: DataView, offset = 0) {\n\t\tconst chunks: Record = {}\n\t\tif (!PngHelpers.isPng(view, offset)) {\n\t\t\tthrow new Error('Not a PNG')\n\t\t}\n\t\toffset += 8\n\n\t\twhile (offset <= view.buffer.byteLength) {\n\t\t\tconst start = offset\n\t\t\tconst len = view.getInt32(offset)\n\t\t\toffset += 4\n\t\t\tconst chunkType = PngHelpers.getChunkType(view, offset)\n\n\t\t\tif (chunkType === 'IDAT' && chunks[chunkType]) {\n\t\t\t\toffset += len + LEN_SIZE + CRC_SIZE\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tif (chunkType === 'IEND') {\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\tchunks[chunkType] = {\n\t\t\t\tstart,\n\t\t\t\tdataOffset: offset + 4,\n\t\t\t\tsize: len,\n\t\t\t}\n\t\t\toffset += len + LEN_SIZE + CRC_SIZE\n\t\t}\n\n\t\treturn chunks\n\t}\n\n\tstatic parsePhys(view: DataView, offset: number) {\n\t\treturn {\n\t\t\tppux: view.getUint32(offset),\n\t\t\tppuy: view.getUint32(offset + 4),\n\t\t\tunit: view.getUint8(offset + 4),\n\t\t}\n\t}\n\n\tstatic findChunk(view: DataView, type: string) {\n\t\tconst chunks = PngHelpers.readChunks(view)\n\t\treturn chunks[type]\n\t}\n\n\tstatic setPhysChunk(view: DataView, dpr = 1, options?: BlobPropertyBag) {\n\t\tlet offset = 46\n\t\tlet size = 0\n\t\tconst res1 = PngHelpers.findChunk(view, 'pHYs')\n\t\tif (res1) {\n\t\t\toffset = res1.start\n\t\t\tsize = res1.size\n\t\t}\n\n\t\tconst res2 = PngHelpers.findChunk(view, 'IDAT')\n\t\tif (res2) {\n\t\t\toffset = res2.start\n\t\t\tsize = 0\n\t\t}\n\n\t\tconst pHYsData = new ArrayBuffer(21)\n\t\tconst pHYsDataView = new DataView(pHYsData)\n\n\t\tpHYsDataView.setUint32(0, 9)\n\n\t\tpHYsDataView.setUint8(4, 'p'.charCodeAt(0))\n\t\tpHYsDataView.setUint8(5, 'H'.charCodeAt(0))\n\t\tpHYsDataView.setUint8(6, 'Y'.charCodeAt(0))\n\t\tpHYsDataView.setUint8(7, 's'.charCodeAt(0))\n\n\t\tconst DPI_96 = 2835.5\n\n\t\tpHYsDataView.setInt32(8, DPI_96 * dpr)\n\t\tpHYsDataView.setInt32(12, DPI_96 * dpr)\n\t\tpHYsDataView.setInt8(16, 1)\n\n\t\tconst crcBit = new Uint8Array(pHYsData.slice(4, 17))\n\t\tpHYsDataView.setInt32(17, crc(crcBit))\n\n\t\tconst startBuf = view.buffer.slice(0, offset)\n\t\tconst endBuf = view.buffer.slice(offset + size)\n\n\t\treturn new Blob([startBuf, pHYsData, endBuf], options)\n\t}\n}\n", "/*!\n * MIT License: https://github.com/sindresorhus/is-webp/blob/main/license\n * Copyright (c) Sindre Sorhus (https://sindresorhus.com)\n */\nfunction isWebp(view: Uint8Array) {\n\tif (!view || view.length < 12) {\n\t\treturn false\n\t}\n\n\treturn view[8] === 87 && view[9] === 69 && view[10] === 66 && view[11] === 80\n}\n\nexport function isWebpAnimated(buffer: ArrayBuffer) {\n\tconst view = new Uint8Array(buffer)\n\n\tif (!isWebp(view)) {\n\t\treturn false\n\t}\n\n\tif (!view || view.length < 21) {\n\t\treturn false\n\t}\n\n\treturn ((view[20] >> 1) & 1) === 1\n}\n", "/**\n * Linear interpolate between two values.\n *\n * @example\n *\n * ```ts\n * const A = lerp(0, 1, 0.5)\n * ```\n *\n * @public\n */\nexport function lerp(a: number, b: number, t: number) {\n\treturn a + (b - a) * t\n}\n\n/**\n * Inverse lerp between two values. Given a value `n` in the range [a, b], returns a number between\n * 0 and 1.\n *\n * @public\n */\nexport function invLerp(a: number, b: number, t: number) {\n\treturn (t - a) / (b - a)\n}\n\n/**\n * Seeded random number generator, using [xorshift](https://en.wikipedia.org/wiki/Xorshift). The\n * result will always be betweeen -1 and 1.\n *\n * Adapted from [seedrandom](https://github.com/davidbau/seedrandom).\n *\n * @public\n */\nexport function rng(seed = '') {\n\tlet x = 0\n\tlet y = 0\n\tlet z = 0\n\tlet w = 0\n\n\tfunction next() {\n\t\tconst t = x ^ (x << 11)\n\t\tx = y\n\t\ty = z\n\t\tz = w\n\t\tw ^= ((w >>> 19) ^ t ^ (t >>> 8)) >>> 0\n\t\treturn (w / 0x100000000) * 2\n\t}\n\n\tfor (let k = 0; k < seed.length + 64; k++) {\n\t\tx ^= seed.charCodeAt(k) | 0\n\t\tnext()\n\t}\n\n\treturn next\n}\n\n/**\n * Modulate a value between two ranges.\n *\n * @example\n *\n * ```ts\n * const A = modulate(0, [0, 1], [0, 100])\n * ```\n *\n * @param value - The interpolation value.\n * @param rangeA - From [low, high]\n * @param rangeB - To [low, high]\n * @param clamp - Whether to clamp the the result to [low, high]\n * @public\n */\nexport function modulate(value: number, rangeA: number[], rangeB: number[], clamp = false): number {\n\tconst [fromLow, fromHigh] = rangeA\n\tconst [v0, v1] = rangeB\n\tconst result = v0 + ((value - fromLow) / (fromHigh - fromLow)) * (v1 - v0)\n\n\treturn clamp\n\t\t? v0 < v1\n\t\t\t? Math.max(Math.min(result, v1), v0)\n\t\t\t: Math.max(Math.min(result, v0), v1)\n\t\t: result\n}\n", "/** @internal */\nexport function hasOwnProperty(obj: object, key: string): boolean {\n\treturn Object.prototype.hasOwnProperty.call(obj, key)\n}\n\n/** @internal */\nexport function getOwnProperty(\n\tobj: Partial>,\n\tkey: K\n): V | undefined\n/** @internal */\nexport function getOwnProperty(obj: object, key: string): unknown\n/** @internal */\nexport function getOwnProperty(obj: object, key: string): unknown {\n\tif (!hasOwnProperty(obj, key)) {\n\t\treturn undefined\n\t}\n\t// @ts-expect-error we know the property exists\n\treturn obj[key]\n}\n\n/**\n * An alias for `Object.keys` that treats the object as a map and so preserves the type of the keys.\n *\n * @internal\n */\nexport function objectMapKeys(object: {\n\treadonly [K in Key]: unknown\n}): Array {\n\treturn Object.keys(object) as Key[]\n}\n\n/**\n * An alias for `Object.values` that treats the object as a map and so preserves the type of the\n * keys.\n *\n * @internal\n */\nexport function objectMapValues(object: {\n\t[K in Key]: Value\n}): Array {\n\treturn Object.values(object) as Value[]\n}\n\n/**\n * An alias for `Object.entries` that treats the object as a map and so preserves the type of the\n * keys.\n *\n * @internal\n */\nexport function objectMapEntries(object: {\n\t[K in Key]: Value\n}): Array<[Key, Value]> {\n\treturn Object.entries(object) as [Key, Value][]\n}\n\n/**\n * An alias for `Object.fromEntries` that treats the object as a map and so preserves the type of the\n * keys.\n *\n * @internal\n */\nexport function objectMapFromEntries(\n\tentries: ReadonlyArray\n): { [K in Key]: Value } {\n\treturn Object.fromEntries(entries) as { [K in Key]: Value }\n}\n\n/**\n * Filters an object using a predicate function.\n * @returns a new object with only the entries that pass the predicate\n * @internal\n */\nexport function filterEntries(\n\tobject: { [K in Key]: Value },\n\tpredicate: (key: Key, value: Value) => boolean\n): { [K in Key]: Value } {\n\tconst result: { [K in Key]?: Value } = {}\n\tlet didChange = false\n\tfor (const [key, value] of objectMapEntries(object)) {\n\t\tif (predicate(key, value)) {\n\t\t\tresult[key] = value\n\t\t} else {\n\t\t\tdidChange = true\n\t\t}\n\t}\n\treturn didChange ? (result as { [K in Key]: Value }) : object\n}\n\n/**\n * Maps the values of one object map to another.\n * @returns a new object with the entries mapped\n * @internal\n */\nexport function mapObjectMapValues(\n\tobject: { readonly [K in Key]: ValueBefore },\n\tmapper: (key: Key, value: ValueBefore) => ValueAfter\n): { [K in Key]: ValueAfter } {\n\tconst result = {} as { [K in Key]: ValueAfter }\n\tfor (const [key, value] of objectMapEntries(object)) {\n\t\tconst newValue = mapper(key, value)\n\t\tresult[key] = newValue\n\t}\n\treturn result\n}\n\n/** @internal */\nexport function areObjectsShallowEqual(obj1: T, obj2: T): boolean {\n\tif (obj1 === obj2) return true\n\tconst keys1 = new Set(Object.keys(obj1))\n\tconst keys2 = new Set(Object.keys(obj2))\n\tif (keys1.size !== keys2.size) return false\n\tfor (const key of keys1) {\n\t\tif (!keys2.has(key)) return false\n\t\tif (!Object.is((obj1 as any)[key], (obj2 as any)[key])) return false\n\t}\n\treturn true\n}\n", "import { IndexKey } from './IndexKey'\nimport { INTEGER_ZERO, generateNKeysBetween, validateOrder } from './dgreensp/dgreensp'\n\n/**\n * The index key for the first index - 'a0'.\n * @public\n */\nexport const ZERO_INDEX_KEY = INTEGER_ZERO\n\n/** @internal */\nexport function validateIndexKey(key: string): asserts key is IndexKey {\n\tvalidateOrder(key)\n}\n\n/**\n * Get a number of indices between two indices.\n * @param below - The index below.\n * @param above - The index above.\n * @param n - The number of indices to get.\n * @public\n */\nexport function getIndicesBetween(\n\tbelow: IndexKey | undefined,\n\tabove: IndexKey | undefined,\n\tn: number\n) {\n\treturn generateNKeysBetween(below, above, n)\n}\n\n/**\n * Get a number of indices above an index.\n * @param below - The index below.\n * @param n - The number of indices to get.\n * @public\n */\nexport function getIndicesAbove(below: IndexKey | undefined, n: number) {\n\treturn generateNKeysBetween(below, undefined, n)\n}\n\n/**\n * Get a number of indices below an index.\n * @param above - The index above.\n * @param n - The number of indices to get.\n * @public\n */\nexport function getIndicesBelow(above: IndexKey | undefined, n: number) {\n\treturn generateNKeysBetween(undefined, above, n)\n}\n\n/**\n * Get the index between two indices.\n * @param below - The index below.\n * @param above - The index above.\n * @public\n */\nexport function getIndexBetween(below: IndexKey | undefined, above: IndexKey | undefined) {\n\treturn generateNKeysBetween(below, above, 1)[0]\n}\n\n/**\n * Get the index above a given index.\n * @param below - The index below.\n * @public\n */\nexport function getIndexAbove(below?: IndexKey | undefined) {\n\treturn generateNKeysBetween(below, undefined, 1)[0]\n}\n\n/**\n * Get the index below a given index.\n * @param above - The index above.\n * @public\n */\nexport function getIndexBelow(above?: IndexKey | undefined) {\n\treturn generateNKeysBetween(undefined, above, 1)[0]\n}\n\n/**\n * Get n number of indices, starting at an index.\n * @param n - The number of indices to get.\n * @param start - The index to start at.\n * @public\n */\nexport function getIndices(n: number, start = 'a1' as IndexKey) {\n\treturn [start, ...generateNKeysBetween(start, undefined, n)]\n}\n\n/**\n * Sort by index.\n * @param a - An object with an index property.\n * @param b - An object with an index property.\n * @public */\nexport function sortByIndex(a: T, b: T) {\n\tif (a.index < b.index) {\n\t\treturn -1\n\t} else if (a.index > b.index) {\n\t\treturn 1\n\t}\n\treturn 0\n}\n", "// Adapted from https://observablehq.com/@dgreensp/implementing-fractional-indexing\n// by @dgreensp (twitter @DavidLG)\n\nimport { IndexKey } from '../IndexKey'\n\nconst DIGITS = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'\nexport const INTEGER_ZERO = 'a0' as IndexKey\nconst SMALLEST_INTEGER = 'A00000000000000000000000000'\n\n/**\n * Get the length of an integer.\n *\n * @param head - The integer to use.\n */\nfunction getIntegerLength(head: string): number {\n\tif (head >= 'a' && head <= 'z') {\n\t\treturn head.charCodeAt(0) - 'a'.charCodeAt(0) + 2\n\t} else if (head >= 'A' && head <= 'Z') {\n\t\treturn 'Z'.charCodeAt(0) - head.charCodeAt(0) + 2\n\t} else {\n\t\tthrow new Error('Invalid index key head: ' + head)\n\t}\n}\n\n/**\n * Validate an integer.\n *\n * @param int - The integer to use.\n */\nfunction validateInteger(int: string): asserts int is string {\n\tif (int.length !== getIntegerLength(int.charAt(0))) {\n\t\tthrow new Error('invalid integer part of index key: ' + int)\n\t}\n}\n\nfunction isNotUndefined(n: string | undefined): asserts n is string {\n\tif (n === undefined) throw Error('n is undefined')\n}\n\n/**\n * Increment an integer.\n *\n * @param x - The integer to increment\n *\n * @internal\n */\nfunction incrementInteger(x: string): string | undefined {\n\tvalidateInteger(x)\n\tconst [head, ...digs] = x.split('')\n\tlet carry = true\n\tfor (let i = digs.length - 1; carry && i >= 0; i--) {\n\t\tconst d = DIGITS.indexOf(digs[i]) + 1\n\t\tif (d === DIGITS.length) {\n\t\t\tdigs[i] = '0'\n\t\t} else {\n\t\t\tdigs[i] = DIGITS.charAt(d)\n\t\t\tcarry = false\n\t\t}\n\t}\n\tif (carry) {\n\t\tif (head === 'Z') return 'a0'\n\t\tif (head === 'z') return undefined\n\t\tconst h = String.fromCharCode(head.charCodeAt(0) + 1)\n\t\tif (h > 'a') {\n\t\t\tdigs.push('0')\n\t\t} else {\n\t\t\tdigs.pop()\n\t\t}\n\t\treturn h + digs.join('')\n\t} else {\n\t\treturn head + digs.join('')\n\t}\n}\n\n/**\n * Decrement an integer.\n *\n * @param x - The integer to decrement\n *\n * @internal\n */\nfunction decrementInteger(x: string): string | undefined {\n\tvalidateInteger(x)\n\tconst [head, ...digs] = x.split('')\n\tlet borrow = true\n\tfor (let i = digs.length - 1; borrow && i >= 0; i--) {\n\t\tconst d = DIGITS.indexOf(digs[i]) - 1\n\t\tif (d === -1) {\n\t\t\tdigs[i] = DIGITS.slice(-1)\n\t\t} else {\n\t\t\tdigs[i] = DIGITS.charAt(d)\n\t\t\tborrow = false\n\t\t}\n\t}\n\tif (borrow) {\n\t\tif (head === 'a') return 'Z' + DIGITS.slice(-1)\n\t\tif (head === 'A') return undefined\n\t\tconst h = String.fromCharCode(head.charCodeAt(0) - 1)\n\t\tif (h < 'Z') {\n\t\t\tdigs.push(DIGITS.slice(-1))\n\t\t} else {\n\t\t\tdigs.pop()\n\t\t}\n\t\treturn h + digs.join('')\n\t} else {\n\t\treturn head + digs.join('')\n\t}\n}\n\n/**\n * Get the midpoint between two indexs.\n *\n * @param a - The start index.\n * @param b - The end index.\n *\n * @internal\n */\nfunction midpoint(a: string, b: string | undefined): string {\n\tif (b !== undefined && a >= b) {\n\t\tthrow new Error(a + ' >= ' + b)\n\t}\n\tif (a.slice(-1) === '0' || (b && b.slice(-1) === '0')) {\n\t\tthrow new Error('trailing zero')\n\t}\n\tif (b) {\n\t\tlet n = 0\n\t\twhile ((a.charAt(n) || '0') === b.charAt(n)) {\n\t\t\tn++\n\t\t}\n\t\tif (n > 0) {\n\t\t\treturn b.slice(0, n) + midpoint(a.slice(n), b.slice(n))\n\t\t}\n\t}\n\tconst digitA = a ? DIGITS.indexOf(a.charAt(0)) : 0\n\tconst digitB = b !== undefined ? DIGITS.indexOf(b.charAt(0)) : DIGITS.length\n\tif (digitB - digitA > 1) {\n\t\tconst midDigit = Math.round(0.5 * (digitA + digitB))\n\t\treturn DIGITS.charAt(midDigit)\n\t} else {\n\t\tif (b && b.length > 1) {\n\t\t\treturn b.slice(0, 1)\n\t\t} else {\n\t\t\treturn DIGITS.charAt(digitA) + midpoint(a.slice(1), undefined)\n\t\t}\n\t}\n}\n\n/**\n * Get the integer part of an index.\n *\n * @param index - The index to use.\n */\nfunction getIntegerPart(index: string): string {\n\tconst integerPartLength = getIntegerLength(index.charAt(0))\n\tif (integerPartLength > index.length) {\n\t\tthrow new Error('invalid index: ' + index)\n\t}\n\treturn index.slice(0, integerPartLength)\n}\n\n/**\n * Validate an index.\n *\n * @param x - The index to validate.\n */\nexport function validateOrder(index: string): asserts index is string {\n\tif (index === SMALLEST_INTEGER) {\n\t\tthrow new Error('invalid index: ' + index)\n\t}\n\t// getIntegerPart will throw if the first character is bad,\n\t// or the key is too short. we'd call it to check these things\n\t// even if we didn't need the result\n\tconst i = getIntegerPart(index)\n\tconst f = index.slice(i.length)\n\tif (f.slice(-1) === '0') {\n\t\tthrow new Error('invalid index: ' + index)\n\t}\n}\n\n/**\n * Generate an index key at the midpoint between a start and end.\n *\n * @param a - The start index key string.\n * @param b - The end index key string, greater than A.\n */\nfunction generateKeyBetween(a: IndexKey | undefined, b: IndexKey | undefined): IndexKey {\n\tif (a !== undefined) validateOrder(a)\n\tif (b !== undefined) validateOrder(b)\n\tif (a !== undefined && b !== undefined && a >= b) {\n\t\tthrow new Error(a + ' >= ' + b)\n\t}\n\tif (a === undefined && b === undefined) {\n\t\treturn INTEGER_ZERO\n\t}\n\tif (a === undefined) {\n\t\tif (b === undefined) throw Error('b is undefined')\n\t\tconst ib = getIntegerPart(b)\n\t\tconst fb = b.slice(ib.length)\n\t\tif (ib === SMALLEST_INTEGER) {\n\t\t\treturn (ib + midpoint('', fb)) as IndexKey\n\t\t}\n\t\tif (ib < b) {\n\t\t\treturn ib as IndexKey\n\t\t}\n\t\tconst ibl = decrementInteger(ib)\n\t\tisNotUndefined(ibl)\n\t\treturn ibl as IndexKey\n\t}\n\tif (b === undefined) {\n\t\tconst ia = getIntegerPart(a)\n\t\tconst fa = a.slice(ia.length)\n\t\tconst i = incrementInteger(ia)\n\t\treturn (i === undefined ? ia + midpoint(fa, undefined) : i) as IndexKey\n\t}\n\tconst ia = getIntegerPart(a)\n\tconst fa = a.slice(ia.length)\n\tconst ib = getIntegerPart(b)\n\tconst fb = b.slice(ib.length)\n\tif (ia === ib) {\n\t\treturn (ia + midpoint(fa, fb)) as IndexKey\n\t}\n\tconst i = incrementInteger(ia)\n\tisNotUndefined(i)\n\treturn (i < b ? i : ia + midpoint(fa, undefined)) as IndexKey\n}\n\n/**\n * Generate N number of index keys between the start and end index.\n *\n * @param a - The start index key string.\n * @param b - The end index key, greater than A string.\n * @param n - The number of index keys to generate.\n */\nexport function generateNKeysBetween(\n\ta: IndexKey | undefined,\n\tb: IndexKey | undefined,\n\tn: number\n): IndexKey[] {\n\tif (n === 0) return []\n\tif (n === 1) return [generateKeyBetween(a, b)]\n\tif (b === undefined) {\n\t\tlet c = generateKeyBetween(a, b)\n\t\tconst result = [c]\n\t\tfor (let i = 0; i < n - 1; i++) {\n\t\t\tc = generateKeyBetween(c, b)\n\t\t\tresult.push(c)\n\t\t}\n\t\treturn result\n\t}\n\tif (a === undefined) {\n\t\tlet c = generateKeyBetween(a, b)\n\t\tconst result = [c]\n\t\tfor (let i = 0; i < n - 1; i++) {\n\t\t\tc = generateKeyBetween(a, c)\n\t\t\tresult.push(c)\n\t\t}\n\t\tresult.reverse()\n\t\treturn result\n\t}\n\tconst mid = Math.floor(n / 2)\n\tconst c = generateKeyBetween(a, b)\n\treturn [...generateNKeysBetween(a, c, mid), c, ...generateNKeysBetween(c, b, n - mid - 1)]\n}\n", "/** @public */\nexport function sortById(a: T, b: T) {\n\treturn a.id > b.id ? 1 : -1\n}\n", "/* eslint-disable no-restricted-syntax */\n\n/**\n * Get a value from local storage.\n *\n * @param key - The key to get.\n *\n * @internal\n */\nexport function getFromLocalStorage(key: string) {\n\ttry {\n\t\treturn localStorage.getItem(key)\n\t} catch {\n\t\treturn null\n\t}\n}\n\n/**\n * Set a value in local storage. Will not throw an error if localStorage is not available.\n *\n * @param key - The key to set.\n * @param value - The value to set.\n *\n * @internal\n */\nexport function setInLocalStorage(key: string, value: string) {\n\ttry {\n\t\tlocalStorage.setItem(key, value)\n\t} catch {\n\t\t// noop\n\t}\n}\n\n/**\n * Remove a value from local storage. Will not throw an error if localStorage is not available.\n *\n * @param key - The key to set.\n *\n * @internal\n */\nexport function deleteFromLocalStorage(key: string) {\n\ttry {\n\t\tlocalStorage.removeItem(key)\n\t} catch {\n\t\t// noop\n\t}\n}\n\n/**\n * Clear all values from local storage. Will not throw an error if localStorage is not available.\n *\n * @internal\n */\nexport function clearLocalStorage() {\n\ttry {\n\t\tlocalStorage.clear()\n\t} catch {\n\t\t// noop\n\t}\n}\n\n/**\n * Get a value from session storage.\n *\n * @param key - The key to get.\n *\n * @internal\n */\nexport function getFromSessionStorage(key: string) {\n\ttry {\n\t\treturn sessionStorage.getItem(key)\n\t} catch {\n\t\treturn null\n\t}\n}\n\n/**\n * Set a value in session storage. Will not throw an error if sessionStorage is not available.\n *\n * @param key - The key to set.\n * @param value - The value to set.\n *\n * @internal\n */\nexport function setInSessionStorage(key: string, value: string) {\n\ttry {\n\t\tsessionStorage.setItem(key, value)\n\t} catch {\n\t\t// noop\n\t}\n}\n\n/**\n * Remove a value from session storage. Will not throw an error if sessionStorage is not available.\n *\n * @param key - The key to set.\n *\n * @internal\n */\nexport function deleteFromSessionStorage(key: string) {\n\ttry {\n\t\tsessionStorage.removeItem(key)\n\t} catch {\n\t\t// noop\n\t}\n}\n\n/**\n * Clear all values from session storage. Will not throw an error if sessionStorage is not available.\n *\n * @internal\n */\nexport function clearSessionStorage() {\n\ttry {\n\t\tsessionStorage.clear()\n\t} catch {\n\t\t// noop\n\t}\n}\n", "const isTest = () =>\n\ttypeof process !== 'undefined' &&\n\tprocess.env.NODE_ENV === 'test' &&\n\t// @ts-expect-error\n\t!globalThis.__FORCE_RAF_IN_TESTS__\n\nconst fpsQueue: Array<() => void> = []\nconst targetFps = 60\nconst targetTimePerFrame = Math.ceil(1000 / targetFps)\nlet frame: number | undefined\nlet time = 0\nlet last = 0\n\nconst flush = () => {\n\tconst queue = fpsQueue.splice(0, fpsQueue.length)\n\tfor (const fn of queue) {\n\t\tfn()\n\t}\n}\n\nfunction tick() {\n\tif (frame) {\n\t\treturn\n\t}\n\tconst now = Date.now()\n\tconst elapsed = now - last\n\n\tif (time + elapsed < targetTimePerFrame) {\n\t\t// It's up to the consumer of debounce to call `cancel`\n\t\t// eslint-disable-next-line no-restricted-globals\n\t\tframe = requestAnimationFrame(() => {\n\t\t\tframe = undefined\n\t\t\ttick()\n\t\t})\n\t\treturn\n\t}\n\t// It's up to the consumer of debounce to call `cancel`\n\t// eslint-disable-next-line no-restricted-globals\n\tframe = requestAnimationFrame(() => {\n\t\tframe = undefined\n\t\tlast = now\n\t\t// If we fall behind more than 10 frames, we'll just reset the time so we don't try to update a number of times\n\t\t// This can happen if we don't interact with the page for a while\n\t\ttime = Math.min(time + elapsed - targetTimePerFrame, targetTimePerFrame * 10)\n\t\tflush()\n\t})\n}\n\nlet started = false\n\n/**\n * Returns a throttled version of the function that will only be called max once per frame.\n * The target frame rate is 60fps.\n * @param fn - the fun to return a throttled version of\n * @returns\n * @internal\n */\nexport function fpsThrottle(fn: { (): void; cancel?(): void }): {\n\t(): void\n\tcancel?(): void\n} {\n\tif (isTest()) {\n\t\tfn.cancel = () => frame && cancelAnimationFrame(frame)\n\t\treturn fn\n\t}\n\n\tconst throttledFn = () => {\n\t\tif (fpsQueue.includes(fn)) {\n\t\t\treturn\n\t\t}\n\t\tfpsQueue.push(fn)\n\t\tif (!started) {\n\t\t\tstarted = true\n\t\t\t// We set last to Date.now() - targetTimePerFrame - 1 so that the first run will happen immediately\n\t\t\tlast = Date.now() - targetTimePerFrame - 1\n\t\t}\n\t\ttick()\n\t}\n\tthrottledFn.cancel = () => {\n\t\tconst index = fpsQueue.indexOf(fn)\n\t\tif (index > -1) {\n\t\t\tfpsQueue.splice(index, 1)\n\t\t}\n\t}\n\treturn throttledFn\n}\n\n/**\n * Calls the function on the next frame. The target frame rate is 60fps.\n * If the same fn is passed again before the next frame, it will still be called only once.\n * @param fn - the fun to call on the next frame\n * @returns a function that will cancel the call if called before the next frame\n * @internal\n */\nexport function throttleToNextFrame(fn: () => void): () => void {\n\tif (isTest()) {\n\t\tfn()\n\t\treturn () => {\n\t\t\t// noop\n\t\t}\n\t}\n\n\tif (!fpsQueue.includes(fn)) {\n\t\tfpsQueue.push(fn)\n\t\tif (!started) {\n\t\t\tstarted = true\n\t\t\t// We set last to Date.now() - targetTimePerFrame - 1 so that the first run will happen immediately\n\t\t\tlast = Date.now() - targetTimePerFrame - 1\n\t\t}\n\t\ttick()\n\t}\n\n\treturn () => {\n\t\tconst index = fpsQueue.indexOf(fn)\n\t\tif (index > -1) {\n\t\t\tfpsQueue.splice(index, 1)\n\t\t}\n\t}\n}\n", "/* eslint-disable no-restricted-properties */\n\n/** @public */\nexport class Timers {\n\tprivate timeouts: number[] = []\n\tprivate intervals: number[] = []\n\tprivate rafs: number[] = []\n\n\t/** @public */\n\tsetTimeout(handler: TimerHandler, timeout?: number, ...args: any[]): number {\n\t\tconst id = window.setTimeout(handler, timeout, args)\n\t\tthis.timeouts.push(id)\n\t\treturn id\n\t}\n\n\t/** @public */\n\tsetInterval(handler: TimerHandler, timeout?: number, ...args: any[]): number {\n\t\tconst id = window.setInterval(handler, timeout, args)\n\t\tthis.intervals.push(id)\n\t\treturn id\n\t}\n\n\t/** @public */\n\trequestAnimationFrame(callback: FrameRequestCallback): number {\n\t\tconst id = window.requestAnimationFrame(callback)\n\t\tthis.rafs.push(id)\n\t\treturn id\n\t}\n\n\t/** @public */\n\tdispose() {\n\t\tthis.timeouts.forEach((id) => clearTimeout(id))\n\t\tthis.intervals.forEach((id) => clearInterval(id))\n\t\tthis.rafs.forEach((id) => cancelAnimationFrame(id))\n\n\t\tthis.timeouts.length = 0\n\t\tthis.intervals.length = 0\n\t\tthis.rafs.length = 0\n\t}\n}\n", "/**\n * Get whether a value is not undefined.\n *\n * @param value - The value to check.\n * @public\n */\nexport function isDefined(value: T): value is typeof value extends undefined ? never : T {\n\treturn value !== undefined\n}\n\n/**\n * Get whether a value is null\n *\n * @param value - The value to check.\n * @public\n */\nexport function isNonNull(value: T): value is typeof value extends null ? never : T {\n\treturn value !== null\n}\n\n/**\n * Get whether a value is nullish (null, undefined).\n *\n * @param value - The value to check.\n * @public\n */\nexport function isNonNullish(\n\tvalue: T\n): value is typeof value extends undefined ? never : typeof value extends null ? never : T {\n\treturn value !== null && value !== undefined\n}\n\nfunction getStructuredClone(): [(i: T) => T, boolean] {\n\tif (typeof globalThis !== 'undefined' && (globalThis as any).structuredClone) {\n\t\treturn [globalThis.structuredClone as (i: T) => T, true]\n\t}\n\n\tif (typeof global !== 'undefined' && (global as any).structuredClone) {\n\t\treturn [global.structuredClone as (i: T) => T, true]\n\t}\n\n\tif (typeof window !== 'undefined' && (window as any).structuredClone) {\n\t\treturn [window.structuredClone as (i: T) => T, true]\n\t}\n\n\treturn [(i: T): T => (i ? JSON.parse(JSON.stringify(i)) : i), false]\n}\n\nconst _structuredClone = getStructuredClone()\n\n/**\n * Create a deep copy of a value. Uses the structuredClone API if available, otherwise uses JSON.parse(JSON.stringify()).\n *\n * @param i - The value to clone.\n * @public */\nexport const structuredClone = _structuredClone[0]\n\n/**\n * @internal\n */\nexport const isNativeStructuredClone = _structuredClone[1]\n\n/**\n * When we patch structuredClone in jsdom for testing (see https://github.com/jsdom/jsdom/issues/3363),\n * the Object that is used as a prototype for the cloned object is not the same as the Object in\n * the code under test (that comes from jsdom's fake global context). This constant is used in\n * our code to work around this case.\n *\n * This is also the case for Array prototype, but that problem can be worked around with an\n * Array.isArray() check.\n * @internal\n */\nexport const STRUCTURED_CLONE_OBJECT_PROTOTYPE = Object.getPrototypeOf(structuredClone({}))\n", "const usedWarnings = new Set()\n\n/** @internal */\nexport function warnDeprecatedGetter(name: string) {\n\twarnOnce(\n\t\t`Using '${name}' is deprecated and will be removed in the near future. Please refactor to use 'get${name[0].toLocaleUpperCase()}${name.slice(\n\t\t\t1\n\t\t)}' instead.`\n\t)\n}\n\n/** @internal */\nexport function warnOnce(message: string) {\n\tif (usedWarnings.has(message)) return\n\n\tusedWarnings.add(message)\n\tconsole.warn(`[tldraw] ${message}`)\n}\n", "// quarter of a megabyte, max possible utf-8 string size\n\n// cloudflare workers only accept messages of max 1mb\nconst MAX_CLIENT_SENT_MESSAGE_SIZE_BYTES = 1024 * 1024\n// utf-8 is max 4 bytes per char\nconst MAX_BYTES_PER_CHAR = 4\n\n// in the (admittedly impossible) worst case, the max size is 1/4 of a megabyte\nconst MAX_SAFE_MESSAGE_SIZE = MAX_CLIENT_SENT_MESSAGE_SIZE_BYTES / MAX_BYTES_PER_CHAR\n\n/** @internal */\nexport function chunk(msg: string, maxSafeMessageSize = MAX_SAFE_MESSAGE_SIZE) {\n\tif (msg.length < maxSafeMessageSize) {\n\t\treturn [msg]\n\t} else {\n\t\tconst chunks = []\n\t\tlet chunkNumber = 0\n\t\tlet offset = msg.length\n\t\twhile (offset > 0) {\n\t\t\tconst prefix = `${chunkNumber}_`\n\t\t\tconst chunkSize = Math.max(Math.min(maxSafeMessageSize - prefix.length, offset), 1)\n\t\t\tchunks.unshift(prefix + msg.slice(offset - chunkSize, offset))\n\t\t\toffset -= chunkSize\n\t\t\tchunkNumber++\n\t\t}\n\t\treturn chunks\n\t}\n}\n\nconst chunkRe = /^(\\d+)_(.*)$/\n\nexport class JsonChunkAssembler {\n\tstate:\n\t\t| 'idle'\n\t\t| {\n\t\t\t\tchunksReceived: string[]\n\t\t\t\ttotalChunks: number\n\t\t } = 'idle'\n\n\thandleMessage(msg: string): { error: Error } | { stringified: string; data: object } | null {\n\t\tif (msg.startsWith('{')) {\n\t\t\tconst error = this.state === 'idle' ? undefined : new Error('Unexpected non-chunk message')\n\t\t\tthis.state = 'idle'\n\t\t\treturn error ? { error } : { data: JSON.parse(msg), stringified: msg }\n\t\t} else {\n\t\t\tconst match = chunkRe.exec(msg)!\n\t\t\tif (!match) {\n\t\t\t\tthis.state = 'idle'\n\t\t\t\treturn { error: new Error('Invalid chunk: ' + JSON.stringify(msg.slice(0, 20) + '...')) }\n\t\t\t}\n\t\t\tconst numChunksRemaining = Number(match[1])\n\t\t\tconst data = match[2]\n\n\t\t\tif (this.state === 'idle') {\n\t\t\t\tthis.state = {\n\t\t\t\t\tchunksReceived: [data],\n\t\t\t\t\ttotalChunks: numChunksRemaining + 1,\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tthis.state.chunksReceived.push(data)\n\t\t\t\tif (numChunksRemaining !== this.state.totalChunks - this.state.chunksReceived.length) {\n\t\t\t\t\tthis.state = 'idle'\n\t\t\t\t\treturn { error: new Error(`Chunks received in wrong order`) }\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (this.state.chunksReceived.length === this.state.totalChunks) {\n\t\t\t\ttry {\n\t\t\t\t\tconst stringified = this.state.chunksReceived.join('')\n\t\t\t\t\tconst data = JSON.parse(stringified)\n\t\t\t\t\treturn { data, stringified }\n\t\t\t\t} catch (e) {\n\t\t\t\t\treturn { error: e as Error }\n\t\t\t\t} finally {\n\t\t\t\t\tthis.state = 'idle'\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn null\n\t\t}\n\t}\n}\n", "import { Signal, react, transact } from '@tldraw/state'\nimport {\n\tRecordId,\n\tRecordsDiff,\n\tStore,\n\tUnknownRecord,\n\treverseRecordsDiff,\n\tsquashRecordDiffs,\n} from '@tldraw/store'\nimport { exhaustiveSwitchError, fpsThrottle, objectMapEntries } from '@tldraw/utils'\nimport isEqual from 'lodash.isequal'\nimport { nanoid } from 'nanoid'\nimport { NetworkDiff, RecordOpType, applyObjectDiff, diffRecord, getNetworkDiff } from './diff'\nimport { interval } from './interval'\nimport {\n\tTLIncompatibilityReason,\n\tTLPushRequest,\n\tTLSocketClientSentEvent,\n\tTLSocketServerSentDataEvent,\n\tTLSocketServerSentEvent,\n\tgetTlsyncProtocolVersion,\n} from './protocol'\n\n/** @internal */\nexport type SubscribingFn = (cb: (val: T) => void) => () => void\n\n/**\n * These are our private codes to be sent from server-\\>client.\n * They are in the private range of the websocket code range.\n * See: https://developer.mozilla.org/en-US/docs/Web/API/CloseEvent/code\n *\n * @internal\n */\nexport const TLCloseEventCode = {\n\tNOT_FOUND: 4099,\n} as const\n\n/** @internal */\nexport type TLPersistentClientSocketStatus = 'online' | 'offline' | 'error'\n/**\n * A socket that can be used to send and receive messages to the server. It should handle staying\n * open and reconnecting when the connection is lost. In actual client code this will be a wrapper\n * around a websocket or socket.io or something similar.\n *\n * @internal\n */\nexport interface TLPersistentClientSocket {\n\t/** Whether there is currently an open connection to the server. */\n\tconnectionStatus: 'online' | 'offline' | 'error'\n\t/** Send a message to the server */\n\tsendMessage: (msg: TLSocketClientSentEvent) => void\n\t/** Attach a listener for messages sent by the server */\n\tonReceiveMessage: SubscribingFn>\n\t/** Attach a listener for connection status changes */\n\tonStatusChange: SubscribingFn\n\t/** Restart the connection */\n\trestart: () => void\n}\n\nconst PING_INTERVAL = 5000\nconst MAX_TIME_TO_WAIT_FOR_SERVER_INTERACTION_BEFORE_RESETTING_CONNECTION = PING_INTERVAL * 2\n\n// Should connect support chunking the response to allow for large payloads?\n\n/**\n * TLSyncClient manages syncing data in a local Store with a remote server.\n *\n * It uses a git-style push/pull/rebase model.\n *\n * @internal\n */\nexport class TLSyncClient = Store> {\n\t/** The last clock time from the most recent server update */\n\tprivate lastServerClock = 0\n\tprivate lastServerInteractionTimestamp = Date.now()\n\n\t/** The queue of in-flight push requests that have not yet been acknowledged by the server */\n\tprivate pendingPushRequests: { request: TLPushRequest; sent: boolean }[] = []\n\n\t/**\n\t * The diff of 'unconfirmed', 'optimistic' changes that have been made locally by the user if we\n\t * take this diff, reverse it, and apply that to the store, our store will match exactly the most\n\t * recent state of the server that we know about\n\t */\n\tprivate speculativeChanges: RecordsDiff = {\n\t\tadded: {} as any,\n\t\tupdated: {} as any,\n\t\tremoved: {} as any,\n\t}\n\n\tprivate disposables: Array<() => void> = []\n\n\treadonly store: S\n\treadonly socket: TLPersistentClientSocket\n\n\treadonly presenceState: Signal | undefined\n\n\t// isOnline is true when we have an open socket connection and we have\n\t// established a connection with the server room (i.e. we have received a 'connect' message)\n\tisConnectedToRoom = false\n\n\t/**\n\t * The client clock is essentially a counter for push requests Each time a push request is created\n\t * the clock is incremented. This clock is sent with the push request to the server, and the\n\t * server returns it with the response so that we can match up the response with the request.\n\t *\n\t * The clock may also be used at one point in the future to allow the client to re-send push\n\t * requests idempotently (i.e. the server will keep track of each client's clock and not execute\n\t * requests it has already handled), but at the time of writing this is neither needed nor\n\t * implemented.\n\t */\n\tprivate clientClock = 0\n\n\t/**\n\t * Called immediately after a connect acceptance has been received and processed Use this to make\n\t * any changes to the store that are required to keep it operational\n\t */\n\tpublic readonly onAfterConnect?: (self: TLSyncClient, isNew: boolean) => void\n\tpublic readonly onSyncError: (reason: TLIncompatibilityReason) => void\n\n\tprivate isDebugging = false\n\tprivate debug(...args: any[]) {\n\t\tif (this.isDebugging) {\n\t\t\t// eslint-disable-next-line no-console\n\t\t\tconsole.debug(...args)\n\t\t}\n\t}\n\n\tprivate readonly presenceType: R['typeName']\n\n\tdidCancel?: () => boolean\n\n\tconstructor(config: {\n\t\tstore: S\n\t\tsocket: TLPersistentClientSocket\n\t\tpresence: Signal\n\t\tonLoad: (self: TLSyncClient) => void\n\t\tonLoadError: (error: Error) => void\n\t\tonSyncError: (reason: TLIncompatibilityReason) => void\n\t\tonAfterConnect?: (self: TLSyncClient, isNew: boolean) => void\n\t\tdidCancel?: () => boolean\n\t}) {\n\t\tthis.didCancel = config.didCancel\n\n\t\tthis.presenceType = config.store.scopedTypes.presence.values().next().value\n\t\tif (!this.presenceType || config.store.scopedTypes.presence.size > 1) {\n\t\t\tthrow new Error('Store must have exactly one presence type')\n\t\t}\n\n\t\tif (typeof window !== 'undefined') {\n\t\t\t;(window as any).tlsync = this\n\t\t}\n\t\tthis.store = config.store\n\t\tthis.socket = config.socket\n\t\tthis.onAfterConnect = config.onAfterConnect\n\t\tthis.onSyncError = config.onSyncError\n\n\t\tlet didLoad = false\n\n\t\tthis.presenceState = config.presence\n\n\t\tthis.disposables.push(\n\t\t\t// when local 'user' changes are made, send them to the server\n\t\t\t// or stash them locally in offline mode\n\t\t\tthis.store.listen(\n\t\t\t\t({ changes }) => {\n\t\t\t\t\tif (this.didCancel?.()) return this.close()\n\t\t\t\t\tthis.debug('received store changes', { changes })\n\t\t\t\t\tthis.push(changes)\n\t\t\t\t},\n\t\t\t\t{ source: 'user', scope: 'document' }\n\t\t\t),\n\t\t\t// when the server sends us events, handle them\n\t\t\tthis.socket.onReceiveMessage((msg) => {\n\t\t\t\tif (this.didCancel?.()) return this.close()\n\t\t\t\tthis.debug('received message from server', msg)\n\t\t\t\tthis.handleServerEvent(msg)\n\t\t\t\t// the first time we receive a message from the server, we should trigger\n\n\t\t\t\t// one of the load callbacks\n\t\t\t\tif (!didLoad) {\n\t\t\t\t\tdidLoad = true\n\t\t\t\t\tif (msg.type === 'error') {\n\t\t\t\t\t\tconfig.onLoadError(msg.error)\n\t\t\t\t\t} else {\n\t\t\t\t\t\tconfig.onLoad(this)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}),\n\t\t\t// handle switching between online and offline\n\t\t\tthis.socket.onStatusChange((status) => {\n\t\t\t\tif (this.didCancel?.()) return this.close()\n\t\t\t\tthis.debug('socket status changed', status)\n\t\t\t\tif (status === 'online') {\n\t\t\t\t\tthis.sendConnectMessage()\n\t\t\t\t} else {\n\t\t\t\t\tthis.resetConnection()\n\t\t\t\t\t// if we reached here before connecting to the server\n\t\t\t\t\t// it's a socket error, mostly likely the server is down or\n\t\t\t\t\t// it's the wrong url.\n\t\t\t\t\tif (status === 'error' && !didLoad) {\n\t\t\t\t\t\tdidLoad = true\n\t\t\t\t\t\tconfig.onLoadError(new Error('socket error'))\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}),\n\t\t\t// Send a ping every PING_INTERVAL ms while online\n\t\t\tinterval(() => {\n\t\t\t\tif (this.didCancel?.()) return this.close()\n\t\t\t\tthis.debug('ping loop', { isConnectedToRoom: this.isConnectedToRoom })\n\t\t\t\tif (!this.isConnectedToRoom) return\n\t\t\t\ttry {\n\t\t\t\t\tthis.socket.sendMessage({ type: 'ping' })\n\t\t\t\t} catch (error) {\n\t\t\t\t\tconsole.warn('ping failed, resetting', error)\n\t\t\t\t\tthis.resetConnection()\n\t\t\t\t}\n\t\t\t}, PING_INTERVAL),\n\t\t\t// Check the server connection health, reset the connection if needed\n\t\t\tinterval(() => {\n\t\t\t\tif (this.didCancel?.()) return this.close()\n\t\t\t\tthis.debug('health check loop', { isConnectedToRoom: this.isConnectedToRoom })\n\t\t\t\tif (!this.isConnectedToRoom) return\n\t\t\t\tconst timeSinceLastServerInteraction = Date.now() - this.lastServerInteractionTimestamp\n\n\t\t\t\tif (\n\t\t\t\t\ttimeSinceLastServerInteraction <\n\t\t\t\t\tMAX_TIME_TO_WAIT_FOR_SERVER_INTERACTION_BEFORE_RESETTING_CONNECTION\n\t\t\t\t) {\n\t\t\t\t\tthis.debug('health check passed', { timeSinceLastServerInteraction })\n\t\t\t\t\t// last ping was recent, so no need to take any action\n\t\t\t\t\treturn\n\t\t\t\t}\n\n\t\t\t\tconsole.warn(`Haven't heard from the server in a while, resetting connection...`)\n\t\t\t\tthis.resetConnection()\n\t\t\t}, PING_INTERVAL * 2)\n\t\t)\n\n\t\tif (this.presenceState) {\n\t\t\tthis.disposables.push(\n\t\t\t\treact('pushPresence', () => {\n\t\t\t\t\tif (this.didCancel?.()) return this.close()\n\t\t\t\t\tthis.pushPresence(this.presenceState!.get())\n\t\t\t\t})\n\t\t\t)\n\t\t}\n\n\t\t// if the socket is already online before this client was instantiated\n\t\t// then we should send a connect message right away\n\t\tif (this.socket.connectionStatus === 'online') {\n\t\t\tthis.sendConnectMessage()\n\t\t}\n\t}\n\n\tlatestConnectRequestId: string | null = null\n\n\t/**\n\t * This is the first message that is sent over a newly established socket connection. And we need\n\t * to wait for the response before this client can be used.\n\t */\n\tprivate sendConnectMessage() {\n\t\tif (this.isConnectedToRoom) {\n\t\t\tconsole.error('sendConnectMessage called while already connected')\n\t\t\treturn\n\t\t}\n\t\tthis.debug('sending connect message')\n\t\tthis.latestConnectRequestId = nanoid()\n\t\tthis.socket.sendMessage({\n\t\t\ttype: 'connect',\n\t\t\tconnectRequestId: this.latestConnectRequestId,\n\t\t\tschema: this.store.schema.serialize(),\n\t\t\tprotocolVersion: getTlsyncProtocolVersion(),\n\t\t\tlastServerClock: this.lastServerClock,\n\t\t})\n\t}\n\n\t/** Switch to offline mode */\n\tprivate resetConnection(hard = false) {\n\t\tthis.debug('resetting connection')\n\t\tif (hard) {\n\t\t\tthis.lastServerClock = 0\n\t\t}\n\t\t// kill all presence state\n\t\tthis.store.mergeRemoteChanges(() => {\n\t\t\tthis.store.remove(Object.keys(this.store.serialize('presence')) as any)\n\t\t})\n\t\tthis.lastPushedPresenceState = null\n\t\tthis.isConnectedToRoom = false\n\t\tthis.pendingPushRequests = []\n\t\tthis.incomingDiffBuffer = []\n\t\tif (this.socket.connectionStatus === 'online') {\n\t\t\tthis.socket.restart()\n\t\t}\n\t}\n\n\t/**\n\t * Invoked when the socket connection comes online, either for the first time or as the result of\n\t * a reconnect. The goal is to rebase on the server's state and fire off a new push request for\n\t * any local changes that were made while offline.\n\t */\n\tprivate didReconnect(event: Extract, { type: 'connect' }>) {\n\t\tthis.debug('did reconnect', event)\n\t\tif (event.connectRequestId !== this.latestConnectRequestId) {\n\t\t\t// ignore connect events for old connect requests\n\t\t\treturn\n\t\t}\n\t\tthis.latestConnectRequestId = null\n\n\t\tif (this.isConnectedToRoom) {\n\t\t\tconsole.error('didReconnect called while already connected')\n\t\t\tthis.resetConnection(true)\n\t\t\treturn\n\t\t}\n\t\tif (this.pendingPushRequests.length > 0) {\n\t\t\tconsole.error('pendingPushRequests should already be empty when we reconnect')\n\t\t\tthis.resetConnection(true)\n\t\t\treturn\n\t\t}\n\t\t// at the end of this process we want to have at most one pending push request\n\t\t// based on anything inside this.speculativeChanges\n\t\ttransact(() => {\n\t\t\t// Now our goal is to rebase on the server's state.\n\t\t\t// This means wiping away any peer presence data, which the server will replace in full on every connect.\n\t\t\t// If the server does not have enough history to give us a partial document state hydration we will\n\t\t\t// also need to wipe away all of our document state before hydrating with the server's state from scratch.\n\t\t\tconst stashedChanges = this.speculativeChanges\n\t\t\tthis.speculativeChanges = { added: {} as any, updated: {} as any, removed: {} as any }\n\n\t\t\tthis.store.mergeRemoteChanges(() => {\n\t\t\t\t// gather records to delete in a NetworkDiff\n\t\t\t\tconst wipeDiff: NetworkDiff = {}\n\t\t\t\tconst wipeAll = event.hydrationType === 'wipe_all'\n\t\t\t\tif (!wipeAll) {\n\t\t\t\t\t// if we're only wiping presence data, undo the speculative changes first\n\t\t\t\t\tthis.store.applyDiff(reverseRecordsDiff(stashedChanges), { runCallbacks: false })\n\t\t\t\t}\n\n\t\t\t\t// now wipe all presence data and, if needed, all document data\n\t\t\t\tfor (const [id, record] of objectMapEntries(this.store.serialize('all'))) {\n\t\t\t\t\tif (\n\t\t\t\t\t\t(wipeAll && this.store.scopedTypes.document.has(record.typeName)) ||\n\t\t\t\t\t\trecord.typeName === this.presenceType\n\t\t\t\t\t) {\n\t\t\t\t\t\twipeDiff[id] = [RecordOpType.Remove]\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// then apply the upstream changes\n\t\t\t\tthis.applyNetworkDiff({ ...wipeDiff, ...event.diff }, true)\n\n\t\t\t\tthis.isConnectedToRoom = true\n\n\t\t\t\t// now re-apply the speculative changes creating a new push request with the\n\t\t\t\t// appropriate diff\n\t\t\t\tconst speculativeChanges = this.store.filterChangesByScope(\n\t\t\t\t\tthis.store.extractingChanges(() => {\n\t\t\t\t\t\tthis.store.applyDiff(stashedChanges)\n\t\t\t\t\t}),\n\t\t\t\t\t'document'\n\t\t\t\t)\n\t\t\t\tif (speculativeChanges) this.push(speculativeChanges)\n\t\t\t})\n\n\t\t\t// this.isConnectedToRoom = true\n\t\t\t// this.store.applyDiff(stashedChanges, false)\n\n\t\t\tthis.store.ensureStoreIsUsable()\n\t\t\t// TODO: reinstate isNew\n\t\t\tthis.onAfterConnect?.(this, false)\n\t\t})\n\n\t\tthis.lastServerClock = event.serverClock\n\t}\n\n\tincomingDiffBuffer: TLSocketServerSentDataEvent[] = []\n\n\t/** Handle events received from the server */\n\tprivate handleServerEvent = (event: TLSocketServerSentEvent) => {\n\t\tthis.debug('received server event', event)\n\t\tthis.lastServerInteractionTimestamp = Date.now()\n\t\t// always update the lastServerClock when it is present\n\t\tswitch (event.type) {\n\t\t\tcase 'connect':\n\t\t\t\tthis.didReconnect(event)\n\t\t\t\tbreak\n\t\t\tcase 'error':\n\t\t\t\tconsole.error('Server error', event.error)\n\t\t\t\tconsole.error('Restarting socket')\n\t\t\t\tthis.socket.restart()\n\t\t\t\tbreak\n\t\t\t// legacy v4 events\n\t\t\tcase 'patch':\n\t\t\tcase 'push_result':\n\t\t\t\tif (!this.isConnectedToRoom) break\n\t\t\t\tthis.incomingDiffBuffer.push(event)\n\t\t\t\tthis.scheduleRebase()\n\t\t\t\tbreak\n\t\t\tcase 'data':\n\t\t\t\t// wait for a connect to succeed before processing more events\n\t\t\t\tif (!this.isConnectedToRoom) break\n\t\t\t\tthis.incomingDiffBuffer.push(...event.data)\n\t\t\t\tthis.scheduleRebase()\n\t\t\t\tbreak\n\t\t\tcase 'incompatibility_error':\n\t\t\t\tthis.onSyncError(event.reason)\n\t\t\t\tbreak\n\t\t\tcase 'pong':\n\t\t\t\t// noop, we only use ping/pong to set lastSeverInteractionTimestamp\n\t\t\t\tbreak\n\t\t\tdefault:\n\t\t\t\texhaustiveSwitchError(event)\n\t\t}\n\t}\n\n\tclose() {\n\t\tthis.debug('closing')\n\t\tthis.disposables.forEach((dispose) => dispose())\n\t\tthis.flushPendingPushRequests.cancel?.()\n\t\tthis.scheduleRebase.cancel?.()\n\t}\n\n\tlastPushedPresenceState: R | null = null\n\n\tprivate pushPresence(nextPresence: R | null) {\n\t\t// make sure we push any document changes first\n\t\tthis.store._flushHistory()\n\n\t\tif (!this.isConnectedToRoom) {\n\t\t\t// if we're offline, don't do anything\n\t\t\treturn\n\t\t}\n\n\t\tlet presence: TLPushRequest['presence'] = undefined\n\t\tif (!this.lastPushedPresenceState && nextPresence) {\n\t\t\t// we don't have a last presence state, so we need to push the full state\n\t\t\tpresence = [RecordOpType.Put, nextPresence]\n\t\t} else if (this.lastPushedPresenceState && nextPresence) {\n\t\t\t// we have a last presence state, so we need to push a diff if there is one\n\t\t\tconst diff = diffRecord(this.lastPushedPresenceState, nextPresence)\n\t\t\tif (diff) {\n\t\t\t\tpresence = [RecordOpType.Patch, diff]\n\t\t\t}\n\t\t}\n\n\t\tif (!presence) return\n\t\tthis.lastPushedPresenceState = nextPresence\n\n\t\t// if there is a pending push that has not been sent and does not already include a presence update,\n\t\t// then add this presence update to it\n\t\tconst lastPush = this.pendingPushRequests.at(-1)\n\t\tif (lastPush && !lastPush.sent && !lastPush.request.presence) {\n\t\t\tlastPush.request.presence = presence\n\t\t\treturn\n\t\t}\n\n\t\t// otherwise, create a new push request\n\t\tconst req: TLPushRequest = {\n\t\t\ttype: 'push',\n\t\t\tclientClock: this.clientClock++,\n\t\t\tpresence,\n\t\t}\n\n\t\tif (req) {\n\t\t\tthis.pendingPushRequests.push({ request: req, sent: false })\n\t\t\tthis.flushPendingPushRequests()\n\t\t}\n\t}\n\n\t/** Push a change to the server, or stash it locally if we're offline */\n\tprivate push(change: RecordsDiff) {\n\t\tthis.debug('push', change)\n\t\t// the Store doesn't do deep equality checks when making changes\n\t\t// so it's possible that the diff passed in here is actually a no-op.\n\t\t// either way, we also don't want to send whole objects over the wire if\n\t\t// only small parts of them have changed, so we'll do a shallow-ish diff\n\t\t// which also uses deep equality checks to see if the change is actually\n\t\t// a no-op.\n\t\tconst diff = getNetworkDiff(change)\n\t\tif (!diff) return\n\n\t\t// the change is not a no-op so we'll send it to the server\n\t\t// but first let's merge the records diff into the speculative changes\n\t\tthis.speculativeChanges = squashRecordDiffs([this.speculativeChanges, change])\n\n\t\tif (!this.isConnectedToRoom) {\n\t\t\t// don't sent push requests or even store them up while offline\n\t\t\t// when we come back online we'll generate another push request from\n\t\t\t// scratch based on the speculativeChanges diff\n\t\t\treturn\n\t\t}\n\n\t\tconst pushRequest: TLPushRequest = {\n\t\t\ttype: 'push',\n\t\t\tdiff,\n\t\t\tclientClock: this.clientClock++,\n\t\t}\n\n\t\tthis.pendingPushRequests.push({ request: pushRequest, sent: false })\n\n\t\t// immediately calling .send on the websocket here was causing some interaction\n\t\t// slugishness when e.g. drawing or translating shapes. Seems like it blocks\n\t\t// until the send completes. So instead we'll schedule a send to happen on some\n\t\t// tick in the near future.\n\t\tthis.flushPendingPushRequests()\n\t}\n\n\t/** Send any unsent push requests to the server */\n\tprivate flushPendingPushRequests = fpsThrottle(() => {\n\t\tthis.debug('flushing pending push requests', {\n\t\t\tisConnectedToRoom: this.isConnectedToRoom,\n\t\t\tpendingPushRequests: this.pendingPushRequests,\n\t\t})\n\t\tif (!this.isConnectedToRoom || this.store.isPossiblyCorrupted()) {\n\t\t\treturn\n\t\t}\n\t\tfor (const pendingPushRequest of this.pendingPushRequests) {\n\t\t\tif (!pendingPushRequest.sent) {\n\t\t\t\tif (this.socket.connectionStatus !== 'online') {\n\t\t\t\t\t// we went offline, so don't send anything\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tthis.socket.sendMessage(pendingPushRequest.request)\n\t\t\t\tpendingPushRequest.sent = true\n\t\t\t}\n\t\t}\n\t})\n\n\t/**\n\t * Applies a 'network' diff to the store this does value-based equality checking so that if the\n\t * data is the same (as opposed to merely identical with ===), then no change is made and no\n\t * changes will be propagated back to store listeners\n\t */\n\tprivate applyNetworkDiff(diff: NetworkDiff, runCallbacks: boolean) {\n\t\tthis.debug('applyNetworkDiff', diff)\n\t\tconst changes: RecordsDiff = { added: {} as any, updated: {} as any, removed: {} as any }\n\t\ttype k = keyof typeof changes.updated\n\t\tlet hasChanges = false\n\t\tfor (const [id, op] of objectMapEntries(diff)) {\n\t\t\tif (op[0] === RecordOpType.Put) {\n\t\t\t\tconst existing = this.store.get(id as RecordId)\n\t\t\t\tif (existing && !isEqual(existing, op[1])) {\n\t\t\t\t\thasChanges = true\n\t\t\t\t\tchanges.updated[id as k] = [existing, op[1]]\n\t\t\t\t} else {\n\t\t\t\t\thasChanges = true\n\t\t\t\t\tchanges.added[id as k] = op[1]\n\t\t\t\t}\n\t\t\t} else if (op[0] === RecordOpType.Patch) {\n\t\t\t\tconst record = this.store.get(id as RecordId)\n\t\t\t\tif (!record) {\n\t\t\t\t\t// the record was removed upstream\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tconst patched = applyObjectDiff(record, op[1])\n\t\t\t\thasChanges = true\n\t\t\t\tchanges.updated[id as k] = [record, patched]\n\t\t\t} else if (op[0] === RecordOpType.Remove) {\n\t\t\t\tif (this.store.has(id as RecordId)) {\n\t\t\t\t\thasChanges = true\n\t\t\t\t\tchanges.removed[id as k] = this.store.get(id as RecordId)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif (hasChanges) {\n\t\t\tthis.store.applyDiff(changes, { runCallbacks })\n\t\t}\n\t}\n\n\tprivate rebase = () => {\n\t\t// need to make sure that our speculative changes are in sync with the actual store instance before\n\t\t// proceeding, to avoid inconsistency bugs.\n\t\tthis.store._flushHistory()\n\t\tif (this.incomingDiffBuffer.length === 0) return\n\n\t\tconst diffs = this.incomingDiffBuffer\n\t\tthis.incomingDiffBuffer = []\n\n\t\ttry {\n\t\t\tthis.store.mergeRemoteChanges(() => {\n\t\t\t\t// first undo speculative changes\n\t\t\t\tthis.store.applyDiff(reverseRecordsDiff(this.speculativeChanges), { runCallbacks: false })\n\n\t\t\t\t// then apply network diffs on top of known-to-be-synced data\n\t\t\t\tfor (const diff of diffs) {\n\t\t\t\t\tif (diff.type === 'patch') {\n\t\t\t\t\t\tthis.applyNetworkDiff(diff.diff, true)\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\t\t\t\t\t// handling push_result\n\t\t\t\t\tif (this.pendingPushRequests.length === 0) {\n\t\t\t\t\t\tthrow new Error('Received push_result but there are no pending push requests')\n\t\t\t\t\t}\n\t\t\t\t\tif (this.pendingPushRequests[0].request.clientClock !== diff.clientClock) {\n\t\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t\t'Received push_result for a push request that is not at the front of the queue'\n\t\t\t\t\t\t)\n\t\t\t\t\t}\n\t\t\t\t\tif (diff.action === 'discard') {\n\t\t\t\t\t\tthis.pendingPushRequests.shift()\n\t\t\t\t\t} else if (diff.action === 'commit') {\n\t\t\t\t\t\tconst { request } = this.pendingPushRequests.shift()!\n\t\t\t\t\t\tif ('diff' in request && request.diff) {\n\t\t\t\t\t\t\tthis.applyNetworkDiff(request.diff, true)\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\tthis.applyNetworkDiff(diff.action.rebaseWithDiff, true)\n\t\t\t\t\t\tthis.pendingPushRequests.shift()\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t// update the speculative diff while re-applying pending changes\n\t\t\t\ttry {\n\t\t\t\t\tthis.speculativeChanges = this.store.extractingChanges(() => {\n\t\t\t\t\t\tfor (const { request } of this.pendingPushRequests) {\n\t\t\t\t\t\t\tif (!('diff' in request) || !request.diff) continue\n\t\t\t\t\t\t\tthis.applyNetworkDiff(request.diff, true)\n\t\t\t\t\t\t}\n\t\t\t\t\t})\n\t\t\t\t} catch (e) {\n\t\t\t\t\tconsole.error(e)\n\t\t\t\t\t// throw away the speculative changes and start over\n\t\t\t\t\tthis.speculativeChanges = { added: {} as any, updated: {} as any, removed: {} as any }\n\t\t\t\t\tthis.resetConnection()\n\t\t\t\t}\n\t\t\t})\n\t\t\tthis.store.ensureStoreIsUsable()\n\t\t\tthis.lastServerClock = diffs.at(-1)?.serverClock ?? this.lastServerClock\n\t\t} catch (e) {\n\t\t\tconsole.error(e)\n\t\t\tthis.store.ensureStoreIsUsable()\n\t\t\tthis.resetConnection()\n\t\t}\n\t}\n\n\tprivate scheduleRebase = fpsThrottle(this.rebase)\n}\n", "export type { BaseRecord, IdOf, RecordId, UnknownRecord } from './lib/BaseRecord'\nexport { IncrementalSetConstructor } from './lib/IncrementalSetConstructor'\nexport { RecordType, assertIdType, createRecordType, type RecordScope } from './lib/RecordType'\nexport {\n\tcreateEmptyRecordsDiff,\n\tisRecordsDiffEmpty,\n\treverseRecordsDiff,\n\tsquashRecordDiffs,\n\tsquashRecordDiffsMutable,\n\ttype RecordsDiff,\n} from './lib/RecordsDiff'\nexport {\n\tStore,\n\tcreateComputedCache,\n\ttype ChangeSource,\n\ttype RecordFromId,\n\ttype StoreListenerFilters,\n\ttype StoreObject,\n\ttype StoreObjectRecordType,\n} from './lib/Store'\nexport type {\n\tCollectionDiff,\n\tComputedCache,\n\tHistoryEntry,\n\tSerializedStore,\n\tStoreError,\n\tStoreListener,\n\tStoreSnapshot,\n\tStoreValidator,\n\tStoreValidators,\n} from './lib/Store'\nexport { StoreQueries, type RSIndex, type RSIndexDiff, type RSIndexMap } from './lib/StoreQueries'\nexport { StoreSchema } from './lib/StoreSchema'\nexport type {\n\tSerializedSchema,\n\tSerializedSchemaV1,\n\tSerializedSchemaV2,\n\tStoreSchemaOptions,\n} from './lib/StoreSchema'\nexport {\n\tStoreSideEffects,\n\ttype StoreAfterChangeHandler,\n\ttype StoreAfterCreateHandler,\n\ttype StoreAfterDeleteHandler,\n\ttype StoreBeforeChangeHandler,\n\ttype StoreBeforeCreateHandler,\n\ttype StoreBeforeDeleteHandler,\n\ttype StoreOperationCompleteHandler,\n} from './lib/StoreSideEffects'\nexport { devFreeze } from './lib/devFreeze'\nexport { type QueryExpression, type QueryValueMatcher } from './lib/executeQuery'\nexport {\n\tMigrationFailureReason,\n\tcreateMigrationIds,\n\tcreateMigrationSequence,\n\tcreateRecordMigrationSequence,\n\t// eslint-disable-next-line deprecation/deprecation\n\tdefineMigrations,\n\tparseMigrationId,\n\ttype LegacyBaseMigrationsInfo,\n\ttype LegacyMigration,\n\ttype LegacyMigrations,\n\ttype Migration,\n\ttype MigrationId,\n\ttype MigrationResult,\n\ttype MigrationSequence,\n\ttype StandaloneDependsOn,\n} from './lib/migrate'\n", "import { CollectionDiff } from './Store'\n\n/**\n * A class that can be used to incrementally construct a set of records.\n *\n * @internal\n */\nexport class IncrementalSetConstructor {\n\t/**\n\t * The next value of the set.\n\t *\n\t * @internal\n\t */\n\tprivate nextValue?: Set\n\n\t/**\n\t * The diff of the set.\n\t *\n\t * @internal\n\t */\n\tprivate diff?: CollectionDiff\n\n\tconstructor(\n\t\t/**\n\t\t * The previous value of the set.\n\t\t *\n\t\t * @internal\n\t\t * @readonly\n\t\t */\n\t\tprivate readonly previousValue: Set\n\t) {}\n\n\t/**\n\t * Get the next value of the set.\n\t *\n\t * @public\n\t */\n\tpublic get() {\n\t\tconst numRemoved = this.diff?.removed?.size ?? 0\n\t\tconst numAdded = this.diff?.added?.size ?? 0\n\t\tif (numRemoved === 0 && numAdded === 0) {\n\t\t\treturn undefined\n\t\t}\n\t\treturn { value: this.nextValue!, diff: this.diff! }\n\t}\n\n\t/**\n\t * Add an item to the set.\n\t *\n\t * @param item - The item to add.\n\t * @param wasAlreadyPresent - Whether the item was already present in the set.\n\t * @internal\n\t */\n\tprivate _add(item: T, wasAlreadyPresent: boolean) {\n\t\tthis.nextValue ??= new Set(this.previousValue)\n\t\tthis.nextValue.add(item)\n\n\t\tthis.diff ??= {}\n\t\tif (wasAlreadyPresent) {\n\t\t\tthis.diff.removed?.delete(item)\n\t\t} else {\n\t\t\tthis.diff.added ??= new Set()\n\t\t\tthis.diff.added.add(item)\n\t\t}\n\t}\n\n\t/**\n\t * Add an item to the set.\n\t *\n\t * @param item - The item to add.\n\t * @public\n\t */\n\tadd(item: T) {\n\t\tconst wasAlreadyPresent = this.previousValue.has(item)\n\t\tif (wasAlreadyPresent) {\n\t\t\tconst wasRemoved = this.diff?.removed?.has(item)\n\t\t\t// if it wasn't removed during the lifetime of this set constructor, there's no need to add it again\n\t\t\tif (!wasRemoved) return\n\t\t\treturn this._add(item, wasAlreadyPresent)\n\t\t}\n\t\tconst isCurrentlyPresent = this.nextValue?.has(item)\n\t\t// if it's already there, no need to add it again\n\t\tif (isCurrentlyPresent) return\n\t\t// otherwise add it\n\t\tthis._add(item, wasAlreadyPresent)\n\t}\n\n\t/**\n\t * Remove an item from the set.\n\t *\n\t * @param item - The item to remove.\n\t * @param wasAlreadyPresent - Whether the item was already present in the set.\n\t * @internal\n\t */\n\tprivate _remove(item: T, wasAlreadyPresent: boolean) {\n\t\tthis.nextValue ??= new Set(this.previousValue)\n\t\tthis.nextValue.delete(item)\n\n\t\tthis.diff ??= {}\n\t\tif (wasAlreadyPresent) {\n\t\t\t// it was in the original set, so we need to add it to the removed diff\n\t\t\tthis.diff.removed ??= new Set()\n\t\t\tthis.diff.removed.add(item)\n\t\t} else {\n\t\t\t// if it was added during the lifetime of this set constructor, we need to remove it from the added diff\n\t\t\tthis.diff.added?.delete(item)\n\t\t}\n\t}\n\n\t/**\n\t * Remove an item from the set.\n\t *\n\t * @param item - The item to remove.\n\t * @public\n\t */\n\tremove(item: T) {\n\t\tconst wasAlreadyPresent = this.previousValue.has(item)\n\t\tif (!wasAlreadyPresent) {\n\t\t\tconst wasAdded = this.diff?.added?.has(item)\n\t\t\t// if it wasn't added during the lifetime of this set constructor, there's no need to remove it\n\t\t\tif (!wasAdded) return\n\t\t\treturn this._remove(item, wasAlreadyPresent)\n\t\t}\n\t\tconst hasAlreadyBeenRemoved = this.diff?.removed?.has(item)\n\t\t// if it's already removed, no need to remove it again\n\t\tif (hasAlreadyBeenRemoved) return\n\t\t// otherwise remove it\n\t\tthis._remove(item, wasAlreadyPresent)\n\t}\n}\n", "import { objectMapEntries, structuredClone } from '@tldraw/utils'\nimport { nanoid } from 'nanoid'\nimport { IdOf, UnknownRecord } from './BaseRecord'\nimport { StoreValidator } from './Store'\n\nexport type RecordTypeRecord> = ReturnType\n\n/**\n * Defines the scope of the record\n *\n * session: The record belongs to a single instance of the store. It should not be synced, and any persistence logic should 'de-instance-ize' the record before persisting it, and apply the reverse when rehydrating.\n * document: The record is persisted and synced. It is available to all store instances.\n * presence: The record belongs to a single instance of the store. It may be synced to other instances, but other instances should not make changes to it. It should not be persisted.\n *\n * @public\n * */\nexport type RecordScope = 'session' | 'document' | 'presence'\n\n/**\n * A record type is a type that can be stored in a record store. It is created with\n * `createRecordType`.\n *\n * @public\n */\nexport class RecordType<\n\tR extends UnknownRecord,\n\tRequiredProperties extends keyof Omit,\n> {\n\treadonly createDefaultProperties: () => Exclude, RequiredProperties>\n\treadonly validator: StoreValidator\n\treadonly ephemeralKeys?: { readonly [K in Exclude]: boolean }\n\treadonly ephemeralKeySet: ReadonlySet\n\treadonly scope: RecordScope\n\n\tconstructor(\n\t\t/**\n\t\t * The unique type associated with this record.\n\t\t *\n\t\t * @public\n\t\t * @readonly\n\t\t */\n\t\tpublic readonly typeName: R['typeName'],\n\t\tconfig: {\n\t\t\treadonly createDefaultProperties: () => Exclude<\n\t\t\t\tOmit,\n\t\t\t\tRequiredProperties\n\t\t\t>\n\t\t\treadonly validator?: StoreValidator\n\t\t\treadonly scope?: RecordScope\n\t\t\treadonly ephemeralKeys?: { readonly [K in Exclude]: boolean }\n\t\t}\n\t) {\n\t\tthis.createDefaultProperties = config.createDefaultProperties\n\t\tthis.validator = config.validator ?? { validate: (r: unknown) => r as R }\n\t\tthis.scope = config.scope ?? 'document'\n\t\tthis.ephemeralKeys = config.ephemeralKeys\n\n\t\tconst ephemeralKeySet = new Set()\n\t\tif (config.ephemeralKeys) {\n\t\t\tfor (const [key, isEphemeral] of objectMapEntries(config.ephemeralKeys)) {\n\t\t\t\tif (isEphemeral) ephemeralKeySet.add(key)\n\t\t\t}\n\t\t}\n\t\tthis.ephemeralKeySet = ephemeralKeySet\n\t}\n\n\t/**\n\t * Create a new record of this type.\n\t *\n\t * @param properties - The properties of the record.\n\t * @returns The new record.\n\t */\n\tcreate(properties: Pick & Omit, RequiredProperties>): R {\n\t\tconst result = { ...this.createDefaultProperties(), id: this.createId() } as any\n\n\t\tfor (const [k, v] of Object.entries(properties)) {\n\t\t\tif (v !== undefined) {\n\t\t\t\tresult[k] = v\n\t\t\t}\n\t\t}\n\n\t\tresult.typeName = this.typeName\n\n\t\treturn result as R\n\t}\n\n\t/**\n\t * Clone a record of this type.\n\t *\n\t * @param record - The record to clone.\n\t * @returns The cloned record.\n\t * @public\n\t */\n\tclone(record: R): R {\n\t\treturn { ...structuredClone(record), id: this.createId() }\n\t}\n\n\t/**\n\t * Create a new ID for this record type.\n\t *\n\t * @example\n\t *\n\t * ```ts\n\t * const id = recordType.createId()\n\t * ```\n\t *\n\t * @returns The new ID.\n\t * @public\n\t */\n\tcreateId(customUniquePart?: string): IdOf {\n\t\treturn (this.typeName + ':' + (customUniquePart ?? nanoid())) as IdOf\n\t}\n\n\t/**\n\t * Create a new ID for this record type based on the given ID.\n\t *\n\t * @example\n\t *\n\t * ```ts\n\t * const id = recordType.createCustomId('myId')\n\t * ```\n\t *\n\t * @deprecated - Use `createId` instead.\n\t * @param id - The ID to base the new ID on.\n\t * @returns The new ID.\n\t */\n\tcreateCustomId(id: string): IdOf {\n\t\treturn (this.typeName + ':' + id) as IdOf\n\t}\n\n\t/**\n\t * Takes an id like `user:123` and returns the part after the colon `123`\n\t *\n\t * @param id - The id\n\t * @returns\n\t */\n\tparseId(id: IdOf): string {\n\t\tif (!this.isId(id)) {\n\t\t\tthrow new Error(`ID \"${id}\" is not a valid ID for type \"${this.typeName}\"`)\n\t\t}\n\n\t\treturn id.slice(this.typeName.length + 1)\n\t}\n\n\t/**\n\t * Check whether a record is an instance of this record type.\n\t *\n\t * @example\n\t *\n\t * ```ts\n\t * const result = recordType.isInstance(someRecord)\n\t * ```\n\t *\n\t * @param record - The record to check.\n\t * @returns Whether the record is an instance of this record type.\n\t */\n\tisInstance = (record?: UnknownRecord): record is R => {\n\t\treturn record?.typeName === this.typeName\n\t}\n\n\t/**\n\t * Check whether an id is an id of this type.\n\t *\n\t * @example\n\t *\n\t * ```ts\n\t * const result = recordType.isIn('someId')\n\t * ```\n\t *\n\t * @param id - The id to check.\n\t * @returns Whether the id is an id of this type.\n\t */\n\tisId(id?: string): id is IdOf {\n\t\tif (!id) return false\n\t\tfor (let i = 0; i < this.typeName.length; i++) {\n\t\t\tif (id[i] !== this.typeName[i]) return false\n\t\t}\n\n\t\treturn id[this.typeName.length] === ':'\n\t}\n\n\t/**\n\t * Create a new RecordType that has the same type name as this RecordType and includes the given\n\t * default properties.\n\t *\n\t * @example\n\t *\n\t * ```ts\n\t * const authorType = createRecordType('author', () => ({ living: true }))\n\t * const deadAuthorType = authorType.withDefaultProperties({ living: false })\n\t * ```\n\t *\n\t * @param fn - A function that returns the default properties of the new RecordType.\n\t * @returns The new RecordType.\n\t */\n\twithDefaultProperties, 'typeName' | 'id'>>(\n\t\tcreateDefaultProperties: () => DefaultProps\n\t): RecordType> {\n\t\treturn new RecordType>(this.typeName, {\n\t\t\tcreateDefaultProperties: createDefaultProperties as any,\n\t\t\tvalidator: this.validator,\n\t\t\tscope: this.scope,\n\t\t\tephemeralKeys: this.ephemeralKeys,\n\t\t})\n\t}\n\n\t/**\n\t * Check that the passed in record passes the validations for this type. Returns its input\n\t * correctly typed if it does, but throws an error otherwise.\n\t */\n\tvalidate(record: unknown, recordBefore?: R): R {\n\t\tif (recordBefore && this.validator.validateUsingKnownGoodVersion) {\n\t\t\treturn this.validator.validateUsingKnownGoodVersion(recordBefore, record)\n\t\t}\n\t\treturn this.validator.validate(record)\n\t}\n}\n\n/**\n * Create a record type.\n *\n * @example\n *\n * ```ts\n * const Book = createRecordType('book')\n * ```\n *\n * @param typeName - The name of the type to create.\n * @public\n */\nexport function createRecordType(\n\ttypeName: R['typeName'],\n\tconfig: {\n\t\tvalidator?: StoreValidator\n\t\tscope: RecordScope\n\t\tephemeralKeys?: { readonly [K in Exclude]: boolean }\n\t}\n): RecordType> {\n\treturn new RecordType>(typeName, {\n\t\tcreateDefaultProperties: () => ({}) as any,\n\t\tvalidator: config.validator,\n\t\tscope: config.scope,\n\t\tephemeralKeys: config.ephemeralKeys,\n\t})\n}\n\n/**\n * Assert whether an id correspond to a record type.\n *\n * @example\n *\n * ```ts\n * assertIdType(myId, \"shape\")\n * ```\n *\n * @param id - The id to check.\n * @param type - The type of the record.\n * @public\n */\nexport function assertIdType(\n\tid: string | undefined,\n\ttype: RecordType\n): asserts id is IdOf {\n\tif (!id || !type.isId(id)) {\n\t\tthrow new Error(`string ${JSON.stringify(id)} is not a valid ${type.typeName} id`)\n\t}\n}\n", "export { urlAlphabet } from './url-alphabet/index.js'\nexport let random = bytes => crypto.getRandomValues(new Uint8Array(bytes))\nexport let customRandom = (alphabet, defaultSize, getRandom) => {\n let mask = (2 << (Math.log(alphabet.length - 1) / Math.LN2)) - 1\n let step = -~((1.6 * mask * defaultSize) / alphabet.length)\n return (size = defaultSize) => {\n let id = ''\n while (true) {\n let bytes = getRandom(step)\n let j = step\n while (j--) {\n id += alphabet[bytes[j] & mask] || ''\n if (id.length === size) return id\n }\n }\n }\n}\nexport let customAlphabet = (alphabet, size = 21) =>\n customRandom(alphabet, size, random)\nexport let nanoid = (size = 21) =>\n crypto.getRandomValues(new Uint8Array(size)).reduce((id, byte) => {\n byte &= 63\n if (byte < 36) {\n id += byte.toString(36)\n } else if (byte < 62) {\n id += (byte - 26).toString(36).toUpperCase()\n } else if (byte > 62) {\n id += '-'\n } else {\n id += '_'\n }\n return id\n }, '')\n", "import { objectMapEntries } from '@tldraw/utils'\nimport { IdOf, UnknownRecord } from './BaseRecord'\n\n/**\n * A diff describing the changes to a record.\n *\n * @public\n */\nexport interface RecordsDiff {\n\tadded: Record, R>\n\tupdated: Record, [from: R, to: R]>\n\tremoved: Record, R>\n}\n\n/** @internal */\nexport function createEmptyRecordsDiff(): RecordsDiff {\n\treturn { added: {}, updated: {}, removed: {} } as RecordsDiff\n}\n\n/** @public */\nexport function reverseRecordsDiff(diff: RecordsDiff) {\n\tconst result: RecordsDiff = { added: diff.removed, removed: diff.added, updated: {} }\n\tfor (const [from, to] of Object.values(diff.updated)) {\n\t\tresult.updated[from.id] = [to, from]\n\t}\n\treturn result\n}\n\n/**\n * Is a records diff empty?\n * @internal\n */\nexport function isRecordsDiffEmpty(diff: RecordsDiff) {\n\treturn (\n\t\tObject.keys(diff.added).length === 0 &&\n\t\tObject.keys(diff.updated).length === 0 &&\n\t\tObject.keys(diff.removed).length === 0\n\t)\n}\n\n/**\n * Squash a collection of diffs into a single diff.\n *\n * @param diffs - An array of diffs to squash.\n * @returns A single diff that represents the squashed diffs.\n * @public\n */\nexport function squashRecordDiffs(\n\tdiffs: RecordsDiff[]\n): RecordsDiff {\n\tconst result = { added: {}, removed: {}, updated: {} } as RecordsDiff\n\n\tsquashRecordDiffsMutable(result, diffs)\n\treturn result\n}\n\n/**\n * Apply the array `diffs` to the `target` diff, mutating it in-place.\n * @internal\n */\nexport function squashRecordDiffsMutable(\n\ttarget: RecordsDiff,\n\tdiffs: RecordsDiff[]\n): void {\n\tfor (const diff of diffs) {\n\t\tfor (const [id, value] of objectMapEntries(diff.added)) {\n\t\t\tif (target.removed[id]) {\n\t\t\t\tconst original = target.removed[id]\n\t\t\t\tdelete target.removed[id]\n\t\t\t\tif (original !== value) {\n\t\t\t\t\ttarget.updated[id] = [original, value]\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\ttarget.added[id] = value\n\t\t\t}\n\t\t}\n\n\t\tfor (const [id, [_from, to]] of objectMapEntries(diff.updated)) {\n\t\t\tif (target.added[id]) {\n\t\t\t\ttarget.added[id] = to\n\t\t\t\tdelete target.updated[id]\n\t\t\t\tdelete target.removed[id]\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tif (target.updated[id]) {\n\t\t\t\ttarget.updated[id] = [target.updated[id][0], to]\n\t\t\t\tdelete target.removed[id]\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\ttarget.updated[id] = diff.updated[id]\n\t\t\tdelete target.removed[id]\n\t\t}\n\n\t\tfor (const [id, value] of objectMapEntries(diff.removed)) {\n\t\t\t// the same record was added in this diff sequence, just drop it\n\t\t\tif (target.added[id]) {\n\t\t\t\tdelete target.added[id]\n\t\t\t} else if (target.updated[id]) {\n\t\t\t\ttarget.removed[id] = target.updated[id][0]\n\t\t\t\tdelete target.updated[id]\n\t\t\t} else {\n\t\t\t\ttarget.removed[id] = value\n\t\t\t}\n\t\t}\n\t}\n}\n", "import { Atom, Computed, Reactor, atom, computed, reactor, transact } from '@tldraw/state'\nimport {\n\tWeakCache,\n\tassert,\n\tfilterEntries,\n\tgetOwnProperty,\n\tobjectMapEntries,\n\tobjectMapFromEntries,\n\tobjectMapKeys,\n\tobjectMapValues,\n\tthrottleToNextFrame,\n} from '@tldraw/utils'\nimport { nanoid } from 'nanoid'\nimport { IdOf, RecordId, UnknownRecord } from './BaseRecord'\nimport { RecordScope } from './RecordType'\nimport { RecordsDiff, squashRecordDiffs } from './RecordsDiff'\nimport { StoreQueries } from './StoreQueries'\nimport { SerializedSchema, StoreSchema } from './StoreSchema'\nimport { StoreSideEffects } from './StoreSideEffects'\nimport { devFreeze } from './devFreeze'\n\n/** @public */\nexport type RecordFromId> =\n\tK extends RecordId ? R : never\n\n/**\n * A diff describing the changes to a collection.\n *\n * @public\n */\nexport interface CollectionDiff {\n\tadded?: Set\n\tremoved?: Set\n}\n\n/** @public */\nexport type ChangeSource = 'user' | 'remote'\n\n/** @public */\nexport interface StoreListenerFilters {\n\tsource: ChangeSource | 'all'\n\tscope: RecordScope | 'all'\n}\n\n/**\n * An entry containing changes that originated either by user actions or remote changes.\n *\n * @public\n */\nexport interface HistoryEntry {\n\tchanges: RecordsDiff\n\tsource: ChangeSource\n}\n\n/**\n * A function that will be called when the history changes.\n *\n * @public\n */\nexport type StoreListener = (entry: HistoryEntry) => void\n\n/**\n * A record store is a collection of records of different types.\n *\n * @public\n */\nexport interface ComputedCache {\n\tget(id: IdOf): Data | undefined\n}\n\n/**\n * A serialized snapshot of the record store's values.\n *\n * @public\n */\nexport type SerializedStore = Record, R>\n\n/** @public */\nexport interface StoreSnapshot {\n\tstore: SerializedStore\n\tschema: SerializedSchema\n}\n\n/** @public */\nexport interface StoreValidator {\n\tvalidate: (record: unknown) => R\n\tvalidateUsingKnownGoodVersion?: (knownGoodVersion: R, record: unknown) => R\n}\n\n/** @public */\nexport type StoreValidators = {\n\t[K in R['typeName']]: StoreValidator>\n}\n\n/** @public */\nexport interface StoreError {\n\terror: Error\n\tphase: 'initialize' | 'createRecord' | 'updateRecord' | 'tests'\n\trecordBefore?: unknown\n\trecordAfter: unknown\n\tisExistingValidationIssue: boolean\n}\n\n/** @internal */\nexport type StoreRecord> = S extends Store ? R : never\n\n/**\n * A store of records.\n *\n * @public\n */\nexport class Store {\n\t/**\n\t * The random id of the store.\n\t */\n\tpublic readonly id: string\n\t/**\n\t * An atom containing the store's atoms.\n\t *\n\t * @internal\n\t * @readonly\n\t */\n\tprivate readonly atoms = atom('store_atoms', {} as Record, Atom>)\n\n\t/**\n\t * An atom containing the store's history.\n\t *\n\t * @public\n\t * @readonly\n\t */\n\treadonly history: Atom> = atom('history', 0, {\n\t\thistoryLength: 1000,\n\t})\n\n\t/**\n\t * A StoreQueries instance for this store.\n\t *\n\t * @public\n\t * @readonly\n\t */\n\treadonly query = new StoreQueries(this.atoms, this.history)\n\n\t/**\n\t * A set containing listeners that have been added to this store.\n\t *\n\t * @internal\n\t */\n\tprivate listeners = new Set<{ onHistory: StoreListener; filters: StoreListenerFilters }>()\n\n\t/**\n\t * An array of history entries that have not yet been flushed.\n\t *\n\t * @internal\n\t */\n\tprivate historyAccumulator = new HistoryAccumulator()\n\n\t/**\n\t * A reactor that responds to changes to the history by squashing the accumulated history and\n\t * notifying listeners of the changes.\n\t *\n\t * @internal\n\t */\n\tprivate historyReactor: Reactor\n\n\t/**\n\t * Function to dispose of any in-flight timeouts.\n\t *\n\t * @internal\n\t */\n\tprivate cancelHistoryReactor: () => void = () => {\n\t\t/* noop */\n\t}\n\n\treadonly schema: StoreSchema\n\n\treadonly props: Props\n\n\tpublic readonly scopedTypes: { readonly [K in RecordScope]: ReadonlySet }\n\n\tpublic readonly sideEffects = new StoreSideEffects(this)\n\n\tconstructor(config: {\n\t\tid?: string\n\t\t/** The store's initial data. */\n\t\tinitialData?: SerializedStore\n\t\t/**\n\t\t * A map of validators for each record type. A record's validator will be called when the record\n\t\t * is created or updated. It should throw an error if the record is invalid.\n\t\t */\n\t\tschema: StoreSchema\n\t\tprops: Props\n\t}) {\n\t\tconst { initialData, schema, id } = config\n\n\t\tthis.id = id ?? nanoid()\n\t\tthis.schema = schema\n\t\tthis.props = config.props\n\n\t\tif (initialData) {\n\t\t\tthis.atoms.set(\n\t\t\t\tobjectMapFromEntries(\n\t\t\t\t\tobjectMapEntries(initialData).map(([id, record]) => [\n\t\t\t\t\t\tid,\n\t\t\t\t\t\tatom(\n\t\t\t\t\t\t\t'atom:' + id,\n\t\t\t\t\t\t\tdevFreeze(this.schema.validateRecord(this, record, 'initialize', null))\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\n\t\tthis.historyReactor = reactor(\n\t\t\t'Store.historyReactor',\n\t\t\t() => {\n\t\t\t\t// deref to make sure we're subscribed regardless of whether we need to propagate\n\t\t\t\tthis.history.get()\n\t\t\t\t// If we have accumulated history, flush it and update listeners\n\t\t\t\tthis._flushHistory()\n\t\t\t},\n\t\t\t{ scheduleEffect: (cb) => (this.cancelHistoryReactor = throttleToNextFrame(cb)) }\n\t\t)\n\t\tthis.scopedTypes = {\n\t\t\tdocument: new Set(\n\t\t\t\tobjectMapValues(this.schema.types)\n\t\t\t\t\t.filter((t) => t.scope === 'document')\n\t\t\t\t\t.map((t) => t.typeName)\n\t\t\t),\n\t\t\tsession: new Set(\n\t\t\t\tobjectMapValues(this.schema.types)\n\t\t\t\t\t.filter((t) => t.scope === 'session')\n\t\t\t\t\t.map((t) => t.typeName)\n\t\t\t),\n\t\t\tpresence: new Set(\n\t\t\t\tobjectMapValues(this.schema.types)\n\t\t\t\t\t.filter((t) => t.scope === 'presence')\n\t\t\t\t\t.map((t) => t.typeName)\n\t\t\t),\n\t\t}\n\t}\n\n\tpublic _flushHistory() {\n\t\t// If we have accumulated history, flush it and update listeners\n\t\tif (this.historyAccumulator.hasChanges()) {\n\t\t\tconst entries = this.historyAccumulator.flush()\n\t\t\tfor (const { changes, source } of entries) {\n\t\t\t\tlet instanceChanges = null as null | RecordsDiff\n\t\t\t\tlet documentChanges = null as null | RecordsDiff\n\t\t\t\tlet presenceChanges = null as null | RecordsDiff\n\t\t\t\tfor (const { onHistory, filters } of this.listeners) {\n\t\t\t\t\tif (filters.source !== 'all' && filters.source !== source) {\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\t\t\t\t\tif (filters.scope !== 'all') {\n\t\t\t\t\t\tif (filters.scope === 'document') {\n\t\t\t\t\t\t\tdocumentChanges ??= this.filterChangesByScope(changes, 'document')\n\t\t\t\t\t\t\tif (!documentChanges) continue\n\t\t\t\t\t\t\tonHistory({ changes: documentChanges, source })\n\t\t\t\t\t\t} else if (filters.scope === 'session') {\n\t\t\t\t\t\t\tinstanceChanges ??= this.filterChangesByScope(changes, 'session')\n\t\t\t\t\t\t\tif (!instanceChanges) continue\n\t\t\t\t\t\t\tonHistory({ changes: instanceChanges, source })\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tpresenceChanges ??= this.filterChangesByScope(changes, 'presence')\n\t\t\t\t\t\t\tif (!presenceChanges) continue\n\t\t\t\t\t\t\tonHistory({ changes: presenceChanges, source })\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\tonHistory({ changes, source })\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tdispose() {\n\t\tthis.cancelHistoryReactor()\n\t}\n\n\t/**\n\t * Filters out non-document changes from a diff. Returns null if there are no changes left.\n\t * @param change - the records diff\n\t * @returns\n\t */\n\tfilterChangesByScope(change: RecordsDiff, scope: RecordScope) {\n\t\tconst result = {\n\t\t\tadded: filterEntries(change.added, (_, r) => this.scopedTypes[scope].has(r.typeName)),\n\t\t\tupdated: filterEntries(change.updated, (_, r) => this.scopedTypes[scope].has(r[1].typeName)),\n\t\t\tremoved: filterEntries(change.removed, (_, r) => this.scopedTypes[scope].has(r.typeName)),\n\t\t}\n\t\tif (\n\t\t\tObject.keys(result.added).length === 0 &&\n\t\t\tObject.keys(result.updated).length === 0 &&\n\t\t\tObject.keys(result.removed).length === 0\n\t\t) {\n\t\t\treturn null\n\t\t}\n\t\treturn result\n\t}\n\n\t/**\n\t * Update the history with a diff of changes.\n\t *\n\t * @param changes - The changes to add to the history.\n\t */\n\tprivate updateHistory(changes: RecordsDiff): void {\n\t\tthis.historyAccumulator.add({\n\t\t\tchanges,\n\t\t\tsource: this.isMergingRemoteChanges ? 'remote' : 'user',\n\t\t})\n\t\tif (this.listeners.size === 0) {\n\t\t\tthis.historyAccumulator.clear()\n\t\t}\n\t\tthis.history.set(this.history.get() + 1, changes)\n\t}\n\n\tvalidate(phase: 'initialize' | 'createRecord' | 'updateRecord' | 'tests') {\n\t\tthis.allRecords().forEach((record) => this.schema.validateRecord(this, record, phase, null))\n\t}\n\n\t/**\n\t * Add some records to the store. It's an error if they already exist.\n\t *\n\t * @param records - The records to add.\n\t * @public\n\t */\n\tput = (records: R[], phaseOverride?: 'initialize'): void => {\n\t\tthis.atomic(() => {\n\t\t\tconst updates: Record, [from: R, to: R]> = {}\n\t\t\tconst additions: Record, R> = {}\n\n\t\t\tconst currentMap = this.atoms.__unsafe__getWithoutCapture()\n\t\t\tlet map = null as null | Record, Atom>\n\n\t\t\t// Iterate through all records, creating, updating or removing as needed\n\t\t\tlet record: R\n\n\t\t\t// There's a chance that, despite having records, all of the values are\n\t\t\t// identical to what they were before; and so we'd end up with an \"empty\"\n\t\t\t// history entry. Let's keep track of whether we've actually made any\n\t\t\t// changes (e.g. additions, deletions, or updates that produce a new value).\n\t\t\tlet didChange = false\n\n\t\t\tconst source = this.isMergingRemoteChanges ? 'remote' : 'user'\n\n\t\t\tfor (let i = 0, n = records.length; i < n; i++) {\n\t\t\t\trecord = records[i]\n\n\t\t\t\tconst recordAtom = (map ?? currentMap)[record.id as IdOf]\n\n\t\t\t\tif (recordAtom) {\n\t\t\t\t\t// If we already have an atom for this record, update its value.\n\t\t\t\t\tconst initialValue = recordAtom.__unsafe__getWithoutCapture()\n\n\t\t\t\t\t// If we have a beforeUpdate callback, run it against the initial and next records\n\t\t\t\t\trecord = this.sideEffects.handleBeforeChange(initialValue, record, source)\n\n\t\t\t\t\t// Validate the record\n\t\t\t\t\tconst validated = this.schema.validateRecord(\n\t\t\t\t\t\tthis,\n\t\t\t\t\t\trecord,\n\t\t\t\t\t\tphaseOverride ?? 'updateRecord',\n\t\t\t\t\t\tinitialValue\n\t\t\t\t\t)\n\n\t\t\t\t\tif (validated === initialValue) continue\n\n\t\t\t\t\trecordAtom.set(devFreeze(record))\n\n\t\t\t\t\tdidChange = true\n\t\t\t\t\tconst updated = recordAtom.__unsafe__getWithoutCapture()\n\t\t\t\t\tupdates[record.id] = [initialValue, updated]\n\t\t\t\t\tthis.addDiffForAfterEvent(initialValue, updated)\n\t\t\t\t} else {\n\t\t\t\t\trecord = this.sideEffects.handleBeforeCreate(record, source)\n\n\t\t\t\t\tdidChange = true\n\n\t\t\t\t\t// If we don't have an atom, create one.\n\n\t\t\t\t\t// Validate the record\n\t\t\t\t\trecord = this.schema.validateRecord(\n\t\t\t\t\t\tthis,\n\t\t\t\t\t\trecord as R,\n\t\t\t\t\t\tphaseOverride ?? 'createRecord',\n\t\t\t\t\t\tnull\n\t\t\t\t\t)\n\n\t\t\t\t\t// Mark the change as a new addition.\n\t\t\t\t\tadditions[record.id] = record\n\t\t\t\t\tthis.addDiffForAfterEvent(null, record)\n\n\t\t\t\t\t// Assign the atom to the map under the record's id.\n\t\t\t\t\tif (!map) {\n\t\t\t\t\t\tmap = { ...currentMap }\n\t\t\t\t\t}\n\t\t\t\t\tmap[record.id] = atom('atom:' + record.id, record)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Set the map of atoms to the store.\n\t\t\tif (map) {\n\t\t\t\tthis.atoms.set(map)\n\t\t\t}\n\n\t\t\t// If we did change, update the history\n\t\t\tif (!didChange) return\n\t\t\tthis.updateHistory({\n\t\t\t\tadded: additions,\n\t\t\t\tupdated: updates,\n\t\t\t\tremoved: {} as Record, R>,\n\t\t\t})\n\t\t})\n\t}\n\n\t/**\n\t * Remove some records from the store via their ids.\n\t *\n\t * @param ids - The ids of the records to remove.\n\t * @public\n\t */\n\tremove = (ids: IdOf[]): void => {\n\t\tthis.atomic(() => {\n\t\t\tconst cancelled = new Set>()\n\t\t\tconst source = this.isMergingRemoteChanges ? 'remote' : 'user'\n\n\t\t\tif (this.sideEffects.isEnabled()) {\n\t\t\t\tfor (const id of ids) {\n\t\t\t\t\tconst atom = this.atoms.__unsafe__getWithoutCapture()[id]\n\t\t\t\t\tif (!atom) continue\n\n\t\t\t\t\tif (this.sideEffects.handleBeforeDelete(atom.get(), source) === false) {\n\t\t\t\t\t\tcancelled.add(id)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tlet removed = undefined as undefined | RecordsDiff['removed']\n\n\t\t\t// For each map in our atoms, remove the ids that we are removing.\n\t\t\tthis.atoms.update((atoms) => {\n\t\t\t\tlet result: typeof atoms | undefined = undefined\n\n\t\t\t\tfor (const id of ids) {\n\t\t\t\t\tif (cancelled.has(id)) continue\n\t\t\t\t\tif (!(id in atoms)) continue\n\t\t\t\t\tif (!result) result = { ...atoms }\n\t\t\t\t\tif (!removed) removed = {} as Record, R>\n\t\t\t\t\tdelete result[id]\n\t\t\t\t\tconst record = atoms[id].get()\n\t\t\t\t\tremoved[id] = record\n\t\t\t\t\tthis.addDiffForAfterEvent(record, null)\n\t\t\t\t}\n\n\t\t\t\treturn result ?? atoms\n\t\t\t})\n\n\t\t\tif (!removed) return\n\t\t\t// Update the history with the removed records.\n\t\t\tthis.updateHistory({ added: {}, updated: {}, removed } as RecordsDiff)\n\t\t})\n\t}\n\n\t/**\n\t * Get the value of a store record by its id.\n\t *\n\t * @param id - The id of the record to get.\n\t * @public\n\t */\n\tget = >(id: K): RecordFromId | undefined => {\n\t\treturn this.atoms.get()[id]?.get() as any\n\t}\n\n\t/**\n\t * Get the value of a store record by its id without updating its epoch.\n\t *\n\t * @param id - The id of the record to get.\n\t * @public\n\t */\n\tunsafeGetWithoutCapture = >(id: K): RecordFromId | undefined => {\n\t\treturn this.atoms.__unsafe__getWithoutCapture()[id]?.__unsafe__getWithoutCapture() as any\n\t}\n\n\t/**\n\t * Creates a JSON payload from the record store.\n\t *\n\t * @param scope - The scope of records to serialize. Defaults to 'document'.\n\t * @returns The record store snapshot as a JSON payload.\n\t */\n\tserialize = (scope: RecordScope | 'all' = 'document'): SerializedStore => {\n\t\tconst result = {} as SerializedStore\n\t\tfor (const [id, atom] of objectMapEntries(this.atoms.get())) {\n\t\t\tconst record = atom.get()\n\t\t\tif (scope === 'all' || this.scopedTypes[scope].has(record.typeName)) {\n\t\t\t\tresult[id as IdOf] = record\n\t\t\t}\n\t\t}\n\t\treturn result\n\t}\n\n\t/**\n\t * Get a serialized snapshot of the store and its schema.\n\t *\n\t * ```ts\n\t * const snapshot = store.getStoreSnapshot()\n\t * store.loadStoreSnapshot(snapshot)\n\t * ```\n\t *\n\t * @param scope - The scope of records to serialize. Defaults to 'document'.\n\t *\n\t * @public\n\t */\n\tgetStoreSnapshot(scope: RecordScope | 'all' = 'document'): StoreSnapshot {\n\t\treturn {\n\t\t\tstore: this.serialize(scope),\n\t\t\tschema: this.schema.serialize(),\n\t\t}\n\t}\n\n\t/**\n\t * @deprecated use `getSnapshot` from the 'tldraw' package instead.\n\t */\n\tgetSnapshot(scope: RecordScope | 'all' = 'document') {\n\t\tconsole.warn(\n\t\t\t'[tldraw] `Store.getSnapshot` is deprecated and will be removed in a future release. Use `getSnapshot` from the `tldraw` package instead.'\n\t\t)\n\t\treturn this.getStoreSnapshot(scope)\n\t}\n\n\t/**\n\t * Migrate a serialized snapshot of the store and its schema.\n\t *\n\t * ```ts\n\t * const snapshot = store.getSnapshot()\n\t * store.migrateSnapshot(snapshot)\n\t * ```\n\t *\n\t * @param snapshot - The snapshot to load.\n\t * @public\n\t */\n\tmigrateSnapshot(snapshot: StoreSnapshot): StoreSnapshot {\n\t\tconst migrationResult = this.schema.migrateStoreSnapshot(snapshot)\n\n\t\tif (migrationResult.type === 'error') {\n\t\t\tthrow new Error(`Failed to migrate snapshot: ${migrationResult.reason}`)\n\t\t}\n\n\t\treturn {\n\t\t\tstore: migrationResult.value,\n\t\t\tschema: this.schema.serialize(),\n\t\t}\n\t}\n\n\t/**\n\t * Load a serialized snapshot.\n\t *\n\t * ```ts\n\t * const snapshot = store.getStoreSnapshot()\n\t * store.loadStoreSnapshot(snapshot)\n\t * ```\n\t *\n\t * @param snapshot - The snapshot to load.\n\t * @public\n\t */\n\tloadStoreSnapshot(snapshot: StoreSnapshot): void {\n\t\tconst migrationResult = this.schema.migrateStoreSnapshot(snapshot)\n\n\t\tif (migrationResult.type === 'error') {\n\t\t\tthrow new Error(`Failed to migrate snapshot: ${migrationResult.reason}`)\n\t\t}\n\n\t\tconst prevSideEffectsEnabled = this.sideEffects.isEnabled()\n\t\ttry {\n\t\t\tthis.sideEffects.setIsEnabled(false)\n\t\t\tthis.atomic(() => {\n\t\t\t\tthis.clear()\n\t\t\t\tthis.put(Object.values(migrationResult.value))\n\t\t\t\tthis.ensureStoreIsUsable()\n\t\t\t})\n\t\t} finally {\n\t\t\tthis.sideEffects.setIsEnabled(prevSideEffectsEnabled)\n\t\t}\n\t}\n\n\t/**\n\t * @public\n\t * @deprecated use `loadSnapshot` from the 'tldraw' package instead.\n\t */\n\tloadSnapshot(snapshot: StoreSnapshot) {\n\t\tconsole.warn(\n\t\t\t\"[tldraw] `Store.loadSnapshot` is deprecated and will be removed in a future release. Use `loadSnapshot` from the 'tldraw' package instead.\"\n\t\t)\n\t\tthis.loadStoreSnapshot(snapshot)\n\t}\n\n\t/**\n\t * Get an array of all values in the store.\n\t *\n\t * @returns An array of all values in the store.\n\t * @public\n\t */\n\tallRecords = (): R[] => {\n\t\treturn objectMapValues(this.atoms.get()).map((atom) => atom.get())\n\t}\n\n\t/**\n\t * Removes all records from the store.\n\t *\n\t * @public\n\t */\n\tclear = (): void => {\n\t\tthis.remove(objectMapKeys(this.atoms.get()))\n\t}\n\n\t/**\n\t * Update a record. To update multiple records at once, use the `update` method of the\n\t * `TypedStore` class.\n\t *\n\t * @param id - The id of the record to update.\n\t * @param updater - A function that updates the record.\n\t */\n\tupdate = >(id: K, updater: (record: RecordFromId) => RecordFromId) => {\n\t\tconst atom = this.atoms.get()[id]\n\t\tif (!atom) {\n\t\t\tconsole.error(`Record ${id} not found. This is probably an error`)\n\t\t\treturn\n\t\t}\n\n\t\tthis.put([updater(atom.__unsafe__getWithoutCapture() as any as RecordFromId) as any])\n\t}\n\n\t/**\n\t * Get whether the record store has a id.\n\t *\n\t * @param id - The id of the record to check.\n\t * @public\n\t */\n\thas = >(id: K): boolean => {\n\t\treturn !!this.atoms.get()[id]\n\t}\n\n\t/**\n\t * Add a new listener to the store.\n\t *\n\t * @param onHistory - The listener to call when the store updates.\n\t * @param filters - Filters to apply to the listener.\n\t * @returns A function to remove the listener.\n\t */\n\tlisten = (onHistory: StoreListener, filters?: Partial) => {\n\t\t// flush history so that this listener's history starts from exactly now\n\t\tthis._flushHistory()\n\n\t\tconst listener = {\n\t\t\tonHistory,\n\t\t\tfilters: {\n\t\t\t\tsource: filters?.source ?? 'all',\n\t\t\t\tscope: filters?.scope ?? 'all',\n\t\t\t},\n\t\t}\n\n\t\tthis.listeners.add(listener)\n\n\t\tif (!this.historyReactor.scheduler.isActivelyListening) {\n\t\t\tthis.historyReactor.start()\n\t\t}\n\n\t\treturn () => {\n\t\t\tthis.listeners.delete(listener)\n\n\t\t\tif (this.listeners.size === 0) {\n\t\t\t\tthis.historyReactor.stop()\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate isMergingRemoteChanges = false\n\n\t/**\n\t * Merge changes from a remote source without triggering listeners.\n\t *\n\t * @param fn - A function that merges the external changes.\n\t * @public\n\t */\n\tmergeRemoteChanges = (fn: () => void) => {\n\t\tif (this.isMergingRemoteChanges) {\n\t\t\treturn fn()\n\t\t}\n\n\t\tif (this._isInAtomicOp) {\n\t\t\tthrow new Error('Cannot merge remote changes while in atomic operation')\n\t\t}\n\n\t\ttry {\n\t\t\tthis.isMergingRemoteChanges = true\n\t\t\ttransact(fn)\n\t\t} finally {\n\t\t\tthis.isMergingRemoteChanges = false\n\t\t}\n\t}\n\n\t/**\n\t * Run `fn` and return a {@link RecordsDiff} of the changes that occurred as a result.\n\t */\n\textractingChanges(fn: () => void): RecordsDiff {\n\t\tconst changes: Array> = []\n\t\tconst dispose = this.historyAccumulator.addInterceptor((entry) => changes.push(entry.changes))\n\t\ttry {\n\t\t\ttransact(fn)\n\t\t\treturn squashRecordDiffs(changes)\n\t\t} finally {\n\t\t\tdispose()\n\t\t}\n\t}\n\n\tapplyDiff(\n\t\tdiff: RecordsDiff,\n\t\t{\n\t\t\trunCallbacks = true,\n\t\t\tignoreEphemeralKeys = false,\n\t\t}: { runCallbacks?: boolean; ignoreEphemeralKeys?: boolean } = {}\n\t) {\n\t\tthis.atomic(() => {\n\t\t\tconst toPut = objectMapValues(diff.added)\n\n\t\t\tfor (const [_from, to] of objectMapValues(diff.updated)) {\n\t\t\t\tconst type = this.schema.getType(to.typeName)\n\t\t\t\tif (ignoreEphemeralKeys && type.ephemeralKeySet.size) {\n\t\t\t\t\tconst existing = this.get(to.id)\n\t\t\t\t\tif (!existing) {\n\t\t\t\t\t\ttoPut.push(to)\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\t\t\t\t\tlet changed: R | null = null\n\t\t\t\t\tfor (const [key, value] of Object.entries(to)) {\n\t\t\t\t\t\tif (type.ephemeralKeySet.has(key) || Object.is(value, getOwnProperty(existing, key))) {\n\t\t\t\t\t\t\tcontinue\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (!changed) changed = { ...existing } as R\n\t\t\t\t\t\t;(changed as any)[key] = value\n\t\t\t\t\t}\n\t\t\t\t\tif (changed) toPut.push(changed)\n\t\t\t\t} else {\n\t\t\t\t\ttoPut.push(to)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst toRemove = objectMapKeys(diff.removed)\n\t\t\tif (toPut.length) {\n\t\t\t\tthis.put(toPut)\n\t\t\t}\n\t\t\tif (toRemove.length) {\n\t\t\t\tthis.remove(toRemove)\n\t\t\t}\n\t\t}, runCallbacks)\n\t}\n\n\t/**\n\t * Create a computed cache.\n\t *\n\t * @param name - The name of the derivation cache.\n\t * @param derive - A function used to derive the value of the cache.\n\t * @public\n\t */\n\tcreateComputedCache = (\n\t\tname: string,\n\t\tderive: (record: Record) => Result | undefined,\n\t\tisEqual?: (a: Record, b: Record) => boolean\n\t): ComputedCache => {\n\t\tconst cache = new WeakCache, Computed>()\n\t\treturn {\n\t\t\tget: (id: IdOf) => {\n\t\t\t\tconst atom = this.atoms.get()[id]\n\t\t\t\tif (!atom) {\n\t\t\t\t\treturn undefined\n\t\t\t\t}\n\t\t\t\treturn cache\n\t\t\t\t\t.get(atom, () => {\n\t\t\t\t\t\tconst recordSignal = isEqual\n\t\t\t\t\t\t\t? computed(atom.name + ':equals', () => atom.get(), { isEqual })\n\t\t\t\t\t\t\t: atom\n\t\t\t\t\t\treturn computed(name + ':' + id, () => {\n\t\t\t\t\t\t\treturn derive(recordSignal.get() as Record)\n\t\t\t\t\t\t})\n\t\t\t\t\t})\n\t\t\t\t\t.get()\n\t\t\t},\n\t\t}\n\t}\n\n\t/**\n\t * Create a computed cache from a selector\n\t *\n\t * @param name - The name of the derivation cache.\n\t * @param selector - A function that returns a subset of the original shape\n\t * @param derive - A function used to derive the value of the cache.\n\t * @public\n\t */\n\tcreateSelectedComputedCache = (\n\t\tname: string,\n\t\tselector: (record: Record) => Selection | undefined,\n\t\tderive: (input: Selection) => Result | undefined\n\t): ComputedCache => {\n\t\tconst cache = new WeakCache, Computed>()\n\t\treturn {\n\t\t\tget: (id: IdOf) => {\n\t\t\t\tconst atom = this.atoms.get()[id]\n\t\t\t\tif (!atom) {\n\t\t\t\t\treturn undefined\n\t\t\t\t}\n\n\t\t\t\treturn cache\n\t\t\t\t\t.get(atom, () => {\n\t\t\t\t\t\tconst d = computed(name + ':' + id + ':selector', () =>\n\t\t\t\t\t\t\tselector(atom.get() as Record)\n\t\t\t\t\t\t)\n\t\t\t\t\t\treturn computed(name + ':' + id, () => derive(d.get() as Selection))\n\t\t\t\t\t})\n\t\t\t\t\t.get()\n\t\t\t},\n\t\t}\n\t}\n\n\tprivate _integrityChecker?: () => void | undefined\n\n\t/** @internal */\n\tensureStoreIsUsable() {\n\t\tthis.atomic(() => {\n\t\t\tthis._integrityChecker ??= this.schema.createIntegrityChecker(this)\n\t\t\tthis._integrityChecker?.()\n\t\t})\n\t}\n\n\tprivate _isPossiblyCorrupted = false\n\t/** @internal */\n\tmarkAsPossiblyCorrupted() {\n\t\tthis._isPossiblyCorrupted = true\n\t}\n\t/** @internal */\n\tisPossiblyCorrupted() {\n\t\treturn this._isPossiblyCorrupted\n\t}\n\n\tprivate pendingAfterEvents: Map, { before: R | null; after: R | null }> | null = null\n\tprivate addDiffForAfterEvent(before: R | null, after: R | null) {\n\t\tassert(this.pendingAfterEvents, 'must be in event operation')\n\t\tif (before === after) return\n\t\tif (before && after) assert(before.id === after.id)\n\t\tif (!before && !after) return\n\t\tconst id = (before || after)!.id\n\t\tconst existing = this.pendingAfterEvents.get(id)\n\t\tif (existing) {\n\t\t\texisting.after = after\n\t\t} else {\n\t\t\tthis.pendingAfterEvents.set(id, { before, after })\n\t\t}\n\t}\n\tprivate flushAtomicCallbacks() {\n\t\tlet updateDepth = 0\n\t\tconst source = this.isMergingRemoteChanges ? 'remote' : 'user'\n\t\twhile (this.pendingAfterEvents) {\n\t\t\tconst events = this.pendingAfterEvents\n\t\t\tthis.pendingAfterEvents = null\n\n\t\t\tif (!this.sideEffects.isEnabled()) continue\n\n\t\t\tupdateDepth++\n\t\t\tif (updateDepth > 100) {\n\t\t\t\tthrow new Error('Maximum store update depth exceeded, bailing out')\n\t\t\t}\n\n\t\t\tfor (const { before, after } of events.values()) {\n\t\t\t\tif (before && after) {\n\t\t\t\t\tthis.sideEffects.handleAfterChange(before, after, source)\n\t\t\t\t} else if (before && !after) {\n\t\t\t\t\tthis.sideEffects.handleAfterDelete(before, source)\n\t\t\t\t} else if (!before && after) {\n\t\t\t\t\tthis.sideEffects.handleAfterCreate(after, source)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (!this.pendingAfterEvents) {\n\t\t\t\tthis.sideEffects.handleOperationComplete(source)\n\t\t\t}\n\t\t}\n\t}\n\tprivate _isInAtomicOp = false\n\t/** @internal */\n\tatomic(fn: () => T, runCallbacks = true): T {\n\t\treturn transact(() => {\n\t\t\tif (this._isInAtomicOp) {\n\t\t\t\tif (!this.pendingAfterEvents) this.pendingAfterEvents = new Map()\n\t\t\t\treturn fn()\n\t\t\t}\n\n\t\t\tthis.pendingAfterEvents = new Map()\n\t\t\tconst prevSideEffectsEnabled = this.sideEffects.isEnabled()\n\t\t\tthis.sideEffects.setIsEnabled(runCallbacks ?? prevSideEffectsEnabled)\n\t\t\tthis._isInAtomicOp = true\n\t\t\ttry {\n\t\t\t\tconst result = fn()\n\n\t\t\t\tthis.flushAtomicCallbacks()\n\n\t\t\t\treturn result\n\t\t\t} finally {\n\t\t\t\tthis.pendingAfterEvents = null\n\t\t\t\tthis.sideEffects.setIsEnabled(prevSideEffectsEnabled)\n\t\t\t\tthis._isInAtomicOp = false\n\t\t\t}\n\t\t})\n\t}\n\n\t/** @internal */\n\taddHistoryInterceptor(fn: (entry: HistoryEntry, source: ChangeSource) => void) {\n\t\treturn this.historyAccumulator.addInterceptor((entry) =>\n\t\t\tfn(entry, this.isMergingRemoteChanges ? 'remote' : 'user')\n\t\t)\n\t}\n}\n\n/**\n * Collect all history entries by their adjacent sources.\n * For example, [user, user, remote, remote, user] would result in [user, remote, user],\n * with adjacent entries of the same source squashed into a single entry.\n *\n * @param entries - The array of history entries.\n * @returns A map of history entries by their sources.\n * @public\n */\nfunction squashHistoryEntries(\n\tentries: HistoryEntry[]\n): HistoryEntry[] {\n\tif (entries.length === 0) return []\n\n\tconst chunked: HistoryEntry[][] = []\n\tlet chunk: HistoryEntry[] = [entries[0]]\n\tlet entry: HistoryEntry\n\n\tfor (let i = 1, n = entries.length; i < n; i++) {\n\t\tentry = entries[i]\n\t\tif (chunk[0].source !== entry.source) {\n\t\t\tchunked.push(chunk)\n\t\t\tchunk = []\n\t\t}\n\t\tchunk.push(entry)\n\t}\n\t// Push the last chunk\n\tchunked.push(chunk)\n\n\treturn devFreeze(\n\t\tchunked.map((chunk) => ({\n\t\t\tsource: chunk[0].source,\n\t\t\tchanges: squashRecordDiffs(chunk.map((e) => e.changes)),\n\t\t}))\n\t)\n}\n\nclass HistoryAccumulator {\n\tprivate _history: HistoryEntry[] = []\n\n\tprivate _interceptors: Set<(entry: HistoryEntry) => void> = new Set()\n\n\taddInterceptor(fn: (entry: HistoryEntry) => void) {\n\t\tthis._interceptors.add(fn)\n\t\treturn () => {\n\t\t\tthis._interceptors.delete(fn)\n\t\t}\n\t}\n\n\tadd(entry: HistoryEntry) {\n\t\tthis._history.push(entry)\n\t\tfor (const interceptor of this._interceptors) {\n\t\t\tinterceptor(entry)\n\t\t}\n\t}\n\n\tflush() {\n\t\tconst history = squashHistoryEntries(this._history)\n\t\tthis._history = []\n\t\treturn history\n\t}\n\n\tclear() {\n\t\tthis._history = []\n\t}\n\n\thasChanges() {\n\t\treturn this._history.length > 0\n\t}\n}\n\n/** @public */\nexport type StoreObject = Store | { store: Store }\n/** @public */\nexport type StoreObjectRecordType> =\n\tContext extends Store ? R : Context extends { store: Store } ? R : never\n\n/**\n * Free version of {@link Store.createComputedCache}.\n *\n * @example\n * ```ts\n * const myCache = createComputedCache('myCache', (editor: Editor, shape: TLShape) => {\n * return editor.getSomethingExpensive(shape)\n * })\n *\n * myCache.get(editor, shape.id)\n * ```\n *\n * @public\n */\nexport function createComputedCache<\n\tContext extends StoreObject,\n\tResult,\n\tRecord extends StoreObjectRecordType = StoreObjectRecordType,\n>(\n\tname: string,\n\tderive: (context: Context, record: Record) => Result | undefined,\n\tisEqual?: (a: Record, b: Record) => boolean\n) {\n\tconst cache = new WeakCache>()\n\treturn {\n\t\tget(context: Context, id: IdOf) {\n\t\t\tconst computedCache = cache.get(context, () => {\n\t\t\t\tconst store = (context instanceof Store ? context : context.store) as Store\n\t\t\t\treturn store.createComputedCache(name, (record) => derive(context, record), isEqual)\n\t\t\t})\n\t\t\treturn computedCache.get(id)\n\t\t},\n\t}\n}\n", "import {\n\tAtom,\n\tcomputed,\n\tComputed,\n\tEMPTY_ARRAY,\n\tisUninitialized,\n\tRESET_VALUE,\n\twithDiff,\n} from '@tldraw/state'\nimport { objectMapValues } from '@tldraw/utils'\nimport isEqual from 'lodash.isequal'\nimport { IdOf, UnknownRecord } from './BaseRecord'\nimport { executeQuery, objectMatchesQuery, QueryExpression } from './executeQuery'\nimport { IncrementalSetConstructor } from './IncrementalSetConstructor'\nimport { RecordsDiff } from './RecordsDiff'\nimport { diffSets } from './setUtils'\nimport { CollectionDiff } from './Store'\n\n/** @public */\nexport type RSIndexDiff<\n\tR extends UnknownRecord,\n\tProperty extends string & keyof R = string & keyof R,\n> = Map>>\n\n/** @public */\nexport type RSIndexMap<\n\tR extends UnknownRecord,\n\tProperty extends string & keyof R = string & keyof R,\n> = Map>>\n\n/** @public */\nexport type RSIndex<\n\tR extends UnknownRecord,\n\tProperty extends string & keyof R = string & keyof R,\n> = Computed, RSIndexDiff>\n\n/**\n * A class that provides a 'namespace' for the various kinds of indexes one may wish to derive from\n * the record store.\n * @public\n */\nexport class StoreQueries {\n\tconstructor(\n\t\tprivate readonly atoms: Atom, Atom>>,\n\t\tprivate readonly history: Atom>\n\t) {}\n\n\t/**\n\t * A cache of derivations (indexes).\n\t *\n\t * @internal\n\t */\n\tprivate indexCache = new Map>()\n\n\t/**\n\t * A cache of derivations (filtered histories).\n\t *\n\t * @internal\n\t */\n\tprivate historyCache = new Map>>()\n\n\t/**\n\t * Create a derivation that contains the history for a given type\n\t *\n\t * @param typeName - The name of the type to filter by.\n\t * @returns A derivation that returns the ids of all records of the given type.\n\t * @public\n\t */\n\tpublic filterHistory(\n\t\ttypeName: TypeName\n\t): Computed>> {\n\t\ttype S = Extract\n\n\t\tif (this.historyCache.has(typeName)) {\n\t\t\treturn this.historyCache.get(typeName) as any\n\t\t}\n\n\t\tconst filtered = computed>(\n\t\t\t'filterHistory:' + typeName,\n\t\t\t(lastValue, lastComputedEpoch) => {\n\t\t\t\tif (isUninitialized(lastValue)) {\n\t\t\t\t\treturn this.history.get()\n\t\t\t\t}\n\n\t\t\t\tconst diff = this.history.getDiffSince(lastComputedEpoch)\n\t\t\t\tif (diff === RESET_VALUE) return this.history.get()\n\n\t\t\t\tconst res = { added: {}, removed: {}, updated: {} } as RecordsDiff\n\t\t\t\tlet numAdded = 0\n\t\t\t\tlet numRemoved = 0\n\t\t\t\tlet numUpdated = 0\n\n\t\t\t\tfor (const changes of diff) {\n\t\t\t\t\tfor (const added of objectMapValues(changes.added)) {\n\t\t\t\t\t\tif (added.typeName === typeName) {\n\t\t\t\t\t\t\tif (res.removed[added.id as IdOf]) {\n\t\t\t\t\t\t\t\tconst original = res.removed[added.id as IdOf]\n\t\t\t\t\t\t\t\tdelete res.removed[added.id as IdOf]\n\t\t\t\t\t\t\t\tnumRemoved--\n\t\t\t\t\t\t\t\tif (original !== added) {\n\t\t\t\t\t\t\t\t\tres.updated[added.id as IdOf] = [original, added as S]\n\t\t\t\t\t\t\t\t\tnumUpdated++\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tres.added[added.id as IdOf] = added as S\n\t\t\t\t\t\t\t\tnumAdded++\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tfor (const [from, to] of objectMapValues(changes.updated)) {\n\t\t\t\t\t\tif (to.typeName === typeName) {\n\t\t\t\t\t\t\tif (res.added[to.id as IdOf]) {\n\t\t\t\t\t\t\t\tres.added[to.id as IdOf] = to as S\n\t\t\t\t\t\t\t} else if (res.updated[to.id as IdOf]) {\n\t\t\t\t\t\t\t\tres.updated[to.id as IdOf] = [res.updated[to.id as IdOf][0], to as S]\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tres.updated[to.id as IdOf] = [from as S, to as S]\n\t\t\t\t\t\t\t\tnumUpdated++\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tfor (const removed of objectMapValues(changes.removed)) {\n\t\t\t\t\t\tif (removed.typeName === typeName) {\n\t\t\t\t\t\t\tif (res.added[removed.id as IdOf]) {\n\t\t\t\t\t\t\t\t// was added during this diff sequence, so just undo the add\n\t\t\t\t\t\t\t\tdelete res.added[removed.id as IdOf]\n\t\t\t\t\t\t\t\tnumAdded--\n\t\t\t\t\t\t\t} else if (res.updated[removed.id as IdOf]) {\n\t\t\t\t\t\t\t\t// remove oldest version\n\t\t\t\t\t\t\t\tres.removed[removed.id as IdOf] = res.updated[removed.id as IdOf][0]\n\t\t\t\t\t\t\t\tdelete res.updated[removed.id as IdOf]\n\t\t\t\t\t\t\t\tnumUpdated--\n\t\t\t\t\t\t\t\tnumRemoved++\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tres.removed[removed.id as IdOf] = removed as S\n\t\t\t\t\t\t\t\tnumRemoved++\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (numAdded || numRemoved || numUpdated) {\n\t\t\t\t\treturn withDiff(this.history.get(), res)\n\t\t\t\t} else {\n\t\t\t\t\treturn lastValue\n\t\t\t\t}\n\t\t\t},\n\t\t\t{ historyLength: 100 }\n\t\t)\n\n\t\tthis.historyCache.set(typeName, filtered)\n\n\t\treturn filtered\n\t}\n\n\t/**\n\t * Create a derivation that returns an index on a property for the given type.\n\t *\n\t * @param typeName - The name of the type.\n\t * @param property - The name of the property.\n\t * @public\n\t */\n\tpublic index<\n\t\tTypeName extends R['typeName'],\n\t\tProperty extends string & keyof Extract,\n\t>(typeName: TypeName, property: Property): RSIndex, Property> {\n\t\tconst cacheKey = typeName + ':' + property\n\n\t\tif (this.indexCache.has(cacheKey)) {\n\t\t\treturn this.indexCache.get(cacheKey) as any\n\t\t}\n\n\t\tconst index = this.__uncached_createIndex(typeName, property)\n\n\t\tthis.indexCache.set(cacheKey, index as any)\n\n\t\treturn index\n\t}\n\n\t/**\n\t * Create a derivation that returns an index on a property for the given type.\n\t *\n\t * @param typeName - The name of the type?.\n\t * @param property - The name of the property?.\n\t * @internal\n\t */\n\t__uncached_createIndex<\n\t\tTypeName extends R['typeName'],\n\t\tProperty extends string & keyof Extract,\n\t>(typeName: TypeName, property: Property): RSIndex, Property> {\n\t\ttype S = Extract\n\n\t\tconst typeHistory = this.filterHistory(typeName)\n\n\t\tconst fromScratch = () => {\n\t\t\t// deref typeHistory early so that the first time the incremental version runs\n\t\t\t// it gets a diff to work with instead of having to bail to this from-scratch version\n\t\t\ttypeHistory.get()\n\t\t\tconst res = new Map>>()\n\t\t\tfor (const atom of objectMapValues(this.atoms.get())) {\n\t\t\t\tconst record = atom.get()\n\t\t\t\tif (record.typeName === typeName) {\n\t\t\t\t\tconst value = (record as S)[property]\n\t\t\t\t\tif (!res.has(value)) {\n\t\t\t\t\t\tres.set(value, new Set())\n\t\t\t\t\t}\n\t\t\t\t\tres.get(value)!.add(record.id)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn res\n\t\t}\n\n\t\treturn computed, RSIndexDiff>(\n\t\t\t'index:' + typeName + ':' + property,\n\t\t\t(prevValue, lastComputedEpoch) => {\n\t\t\t\tif (isUninitialized(prevValue)) return fromScratch()\n\n\t\t\t\tconst history = typeHistory.getDiffSince(lastComputedEpoch)\n\t\t\t\tif (history === RESET_VALUE) {\n\t\t\t\t\treturn fromScratch()\n\t\t\t\t}\n\n\t\t\t\tconst setConstructors = new Map>>()\n\n\t\t\t\tconst add = (value: S[Property], id: IdOf) => {\n\t\t\t\t\tlet setConstructor = setConstructors.get(value)\n\t\t\t\t\tif (!setConstructor)\n\t\t\t\t\t\tsetConstructor = new IncrementalSetConstructor>(\n\t\t\t\t\t\t\tprevValue.get(value) ?? new Set()\n\t\t\t\t\t\t)\n\t\t\t\t\tsetConstructor.add(id)\n\t\t\t\t\tsetConstructors.set(value, setConstructor)\n\t\t\t\t}\n\n\t\t\t\tconst remove = (value: S[Property], id: IdOf) => {\n\t\t\t\t\tlet set = setConstructors.get(value)\n\t\t\t\t\tif (!set) set = new IncrementalSetConstructor>(prevValue.get(value) ?? new Set())\n\t\t\t\t\tset.remove(id)\n\t\t\t\t\tsetConstructors.set(value, set)\n\t\t\t\t}\n\n\t\t\t\tfor (const changes of history) {\n\t\t\t\t\tfor (const record of objectMapValues(changes.added)) {\n\t\t\t\t\t\tif (record.typeName === typeName) {\n\t\t\t\t\t\t\tconst value = (record as S)[property]\n\t\t\t\t\t\t\tadd(value, record.id)\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tfor (const [from, to] of objectMapValues(changes.updated)) {\n\t\t\t\t\t\tif (to.typeName === typeName) {\n\t\t\t\t\t\t\tconst prev = (from as S)[property]\n\t\t\t\t\t\t\tconst next = (to as S)[property]\n\t\t\t\t\t\t\tif (prev !== next) {\n\t\t\t\t\t\t\t\tremove(prev, to.id)\n\t\t\t\t\t\t\t\tadd(next, to.id)\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tfor (const record of objectMapValues(changes.removed)) {\n\t\t\t\t\t\tif (record.typeName === typeName) {\n\t\t\t\t\t\t\tconst value = (record as S)[property]\n\t\t\t\t\t\t\tremove(value, record.id)\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tlet nextValue: undefined | RSIndexMap = undefined\n\t\t\t\tlet nextDiff: undefined | RSIndexDiff = undefined\n\n\t\t\t\tfor (const [value, setConstructor] of setConstructors) {\n\t\t\t\t\tconst result = setConstructor.get()\n\t\t\t\t\tif (!result) continue\n\t\t\t\t\tif (!nextValue) nextValue = new Map(prevValue)\n\t\t\t\t\tif (!nextDiff) nextDiff = new Map()\n\t\t\t\t\tif (result.value.size === 0) {\n\t\t\t\t\t\tnextValue.delete(value)\n\t\t\t\t\t} else {\n\t\t\t\t\t\tnextValue.set(value, result.value)\n\t\t\t\t\t}\n\t\t\t\t\tnextDiff.set(value, result.diff)\n\t\t\t\t}\n\n\t\t\t\tif (nextValue && nextDiff) {\n\t\t\t\t\treturn withDiff(nextValue, nextDiff)\n\t\t\t\t}\n\n\t\t\t\treturn prevValue\n\t\t\t},\n\t\t\t{ historyLength: 100 }\n\t\t)\n\t}\n\n\t/**\n\t * Create a derivation that will return a signle record matching the given query.\n\t *\n\t * It will return undefined if there is no matching record\n\t *\n\t * @param typeName - The name of the type?\n\t * @param queryCreator - A function that returns the query expression.\n\t * @param name - (optinal) The name of the query.\n\t */\n\trecord(\n\t\ttypeName: TypeName,\n\t\tqueryCreator: () => QueryExpression> = () => ({}),\n\t\tname = 'record:' + typeName + (queryCreator ? ':' + queryCreator.toString() : '')\n\t): Computed | undefined> {\n\t\ttype S = Extract\n\t\tconst ids = this.ids(typeName, queryCreator, name)\n\n\t\treturn computed(name, () => {\n\t\t\tfor (const id of ids.get()) {\n\t\t\t\treturn this.atoms.get()[id]?.get() as S\n\t\t\t}\n\t\t\treturn undefined\n\t\t})\n\t}\n\n\t/**\n\t * Create a derivation that will return an array of records matching the given query\n\t *\n\t * @param typeName - The name of the type?\n\t * @param queryCreator - A function that returns the query expression.\n\t * @param name - (optinal) The name of the query.\n\t */\n\trecords(\n\t\ttypeName: TypeName,\n\t\tqueryCreator: () => QueryExpression> = () => ({}),\n\t\tname = 'records:' + typeName + (queryCreator ? ':' + queryCreator.toString() : '')\n\t): Computed>> {\n\t\ttype S = Extract\n\t\tconst ids = this.ids(typeName, queryCreator, 'ids:' + name)\n\n\t\treturn computed(name, () => {\n\t\t\treturn [...ids.get()].map((id) => {\n\t\t\t\tconst atom = this.atoms.get()[id]\n\t\t\t\tif (!atom) {\n\t\t\t\t\tthrow new Error('no atom found for record id: ' + id)\n\t\t\t\t}\n\t\t\t\treturn atom.get() as S\n\t\t\t})\n\t\t})\n\t}\n\n\t/**\n\t * Create a derivation that will return the ids of all records of the given type.\n\t *\n\t * @param typeName - The name of the type.\n\t * @param queryCreator - A function that returns the query expression.\n\t * @param name - (optinal) The name of the query.\n\t */\n\tids(\n\t\ttypeName: TypeName,\n\t\tqueryCreator: () => QueryExpression> = () => ({}),\n\t\tname = 'ids:' + typeName + (queryCreator ? ':' + queryCreator.toString() : '')\n\t): Computed<\n\t\tSet>>,\n\t\tCollectionDiff>>\n\t> {\n\t\ttype S = Extract\n\n\t\tconst typeHistory = this.filterHistory(typeName)\n\n\t\tconst fromScratch = () => {\n\t\t\t// deref type history early to allow first incremental update to use diffs\n\t\t\ttypeHistory.get()\n\t\t\tconst query: QueryExpression = queryCreator()\n\t\t\tif (Object.keys(query).length === 0) {\n\t\t\t\treturn new Set>(\n\t\t\t\t\tobjectMapValues(this.atoms.get()).flatMap((v) => {\n\t\t\t\t\t\tconst r = v.get()\n\t\t\t\t\t\tif (r.typeName === typeName) {\n\t\t\t\t\t\t\treturn r.id\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\treturn []\n\t\t\t\t\t\t}\n\t\t\t\t\t})\n\t\t\t\t)\n\t\t\t}\n\n\t\t\treturn executeQuery(this, typeName, query)\n\t\t}\n\n\t\tconst fromScratchWithDiff = (prevValue: Set>) => {\n\t\t\tconst nextValue = fromScratch()\n\t\t\tconst diff = diffSets(prevValue, nextValue)\n\t\t\tif (diff) {\n\t\t\t\treturn withDiff(nextValue, diff)\n\t\t\t} else {\n\t\t\t\treturn prevValue\n\t\t\t}\n\t\t}\n\t\tconst cachedQuery = computed('ids_query:' + name, queryCreator, {\n\t\t\tisEqual,\n\t\t})\n\n\t\treturn computed(\n\t\t\t'query:' + name,\n\t\t\t(prevValue, lastComputedEpoch) => {\n\t\t\t\tconst query = cachedQuery.get()\n\t\t\t\tif (isUninitialized(prevValue)) {\n\t\t\t\t\treturn fromScratch()\n\t\t\t\t}\n\n\t\t\t\t// if the query changed since last time this ran then we need to start again\n\t\t\t\tif (lastComputedEpoch < cachedQuery.lastChangedEpoch) {\n\t\t\t\t\treturn fromScratchWithDiff(prevValue)\n\t\t\t\t}\n\n\t\t\t\t// otherwise iterate over the changes from the store and apply them to the previous value if needed\n\t\t\t\tconst history = typeHistory.getDiffSince(lastComputedEpoch)\n\t\t\t\tif (history === RESET_VALUE) {\n\t\t\t\t\treturn fromScratchWithDiff(prevValue)\n\t\t\t\t}\n\n\t\t\t\tconst setConstructor = new IncrementalSetConstructor>(\n\t\t\t\t\tprevValue\n\t\t\t\t) as IncrementalSetConstructor>\n\n\t\t\t\tfor (const changes of history) {\n\t\t\t\t\tfor (const added of objectMapValues(changes.added)) {\n\t\t\t\t\t\tif (added.typeName === typeName && objectMatchesQuery(query, added)) {\n\t\t\t\t\t\t\tsetConstructor.add(added.id)\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tfor (const [_, updated] of objectMapValues(changes.updated)) {\n\t\t\t\t\t\tif (updated.typeName === typeName) {\n\t\t\t\t\t\t\tif (objectMatchesQuery(query, updated)) {\n\t\t\t\t\t\t\t\tsetConstructor.add(updated.id)\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tsetConstructor.remove(updated.id)\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tfor (const removed of objectMapValues(changes.removed)) {\n\t\t\t\t\t\tif (removed.typeName === typeName) {\n\t\t\t\t\t\t\tsetConstructor.remove(removed.id)\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tconst result = setConstructor.get()\n\t\t\t\tif (!result) {\n\t\t\t\t\treturn prevValue\n\t\t\t\t}\n\n\t\t\t\treturn withDiff(result.value, result.diff)\n\t\t\t},\n\t\t\t{ historyLength: 50 }\n\t\t)\n\t}\n\n\texec(\n\t\ttypeName: TypeName,\n\t\tquery: QueryExpression>\n\t): Array> {\n\t\tconst ids = executeQuery(this, typeName, query)\n\t\tif (ids.size === 0) {\n\t\t\treturn EMPTY_ARRAY\n\t\t}\n\t\tconst atoms = this.atoms.get()\n\t\treturn [...ids].map((id) => atoms[id].get() as Extract)\n\t}\n}\n", "import { IdOf, UnknownRecord } from './BaseRecord'\nimport { intersectSets } from './setUtils'\nimport { StoreQueries } from './StoreQueries'\n\n/** @public */\nexport type QueryValueMatcher = { eq: T } | { neq: T } | { gt: number }\n\n/** @public */\nexport type QueryExpression = {\n\t[k in keyof R & string]?: QueryValueMatcher\n\t// todo: handle nesting\n\t// | (R[k] extends object ? { match: QueryExpression } : never)\n}\n\nexport function objectMatchesQuery(query: QueryExpression, object: T) {\n\tfor (const [key, _matcher] of Object.entries(query)) {\n\t\tconst matcher = _matcher as QueryValueMatcher\n\t\tconst value = object[key as keyof T]\n\t\t// if you add matching logic here, make sure you also update executeQuery,\n\t\t// where initial data is pulled out of the indexes, since that requires different\n\t\t// matching logic\n\t\tif ('eq' in matcher && value !== matcher.eq) return false\n\t\tif ('neq' in matcher && value === matcher.neq) return false\n\t\tif ('gt' in matcher && (typeof value !== 'number' || value <= matcher.gt)) return false\n\t}\n\treturn true\n}\n\nexport function executeQuery(\n\tstore: StoreQueries,\n\ttypeName: TypeName,\n\tquery: QueryExpression>\n): Set>> {\n\tconst matchIds = Object.fromEntries(Object.keys(query).map((key) => [key, new Set()]))\n\n\tfor (const [k, matcher] of Object.entries(query)) {\n\t\tif ('eq' in matcher) {\n\t\t\tconst index = store.index(typeName, k as any)\n\t\t\tconst ids = index.get().get(matcher.eq)\n\t\t\tif (ids) {\n\t\t\t\tfor (const id of ids) {\n\t\t\t\t\tmatchIds[k].add(id)\n\t\t\t\t}\n\t\t\t}\n\t\t} else if ('neq' in matcher) {\n\t\t\tconst index = store.index(typeName, k as any)\n\t\t\tfor (const [value, ids] of index.get()) {\n\t\t\t\tif (value !== matcher.neq) {\n\t\t\t\t\tfor (const id of ids) {\n\t\t\t\t\t\tmatchIds[k].add(id)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t} else if ('gt' in matcher) {\n\t\t\tconst index = store.index(typeName, k as any)\n\t\t\tfor (const [value, ids] of index.get()) {\n\t\t\t\tif (value > matcher.gt) {\n\t\t\t\t\tfor (const id of ids) {\n\t\t\t\t\t\tmatchIds[k].add(id)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn intersectSets(Object.values(matchIds)) as Set>>\n}\n", "import { CollectionDiff } from './Store'\n\n/**\n * Combine multiple sets into a single set containing only the common elements of all sets.\n *\n * @param sets - The sets to combine.\n */\nexport function intersectSets(sets: Set[]) {\n\tif (sets.length === 0) return new Set()\n\tconst first = sets[0]\n\tconst rest = sets.slice(1)\n\tconst result = new Set()\n\n\tfor (const val of first) {\n\t\tif (rest.every((set) => set.has(val))) {\n\t\t\tresult.add(val)\n\t\t}\n\t}\n\n\treturn result\n}\n\n/**\n * Calculates a diff between two sets.\n *\n * @param prev - The previous set\n * @param next - The next set\n */\nexport function diffSets(prev: Set, next: Set): CollectionDiff | undefined {\n\tconst result: CollectionDiff = {}\n\n\tfor (const val of next) {\n\t\tif (!prev.has(val)) {\n\t\t\tresult.added ??= new Set()\n\t\t\tresult.added.add(val)\n\t\t}\n\t}\n\n\tfor (const val of prev) {\n\t\tif (!next.has(val)) {\n\t\t\tresult.removed ??= new Set()\n\t\t\tresult.removed.add(val)\n\t\t}\n\t}\n\n\treturn result.added || result.removed ? result : undefined\n}\n", "import { UnknownRecord } from './BaseRecord'\nimport { Store } from './Store'\n\n/** @public */\nexport type StoreBeforeCreateHandler = (\n\trecord: R,\n\tsource: 'remote' | 'user'\n) => R\n/** @public */\nexport type StoreAfterCreateHandler = (\n\trecord: R,\n\tsource: 'remote' | 'user'\n) => void\n/** @public */\nexport type StoreBeforeChangeHandler = (\n\tprev: R,\n\tnext: R,\n\tsource: 'remote' | 'user'\n) => R\n/** @public */\nexport type StoreAfterChangeHandler = (\n\tprev: R,\n\tnext: R,\n\tsource: 'remote' | 'user'\n) => void\n/** @public */\nexport type StoreBeforeDeleteHandler = (\n\trecord: R,\n\tsource: 'remote' | 'user'\n) => void | false\n/** @public */\nexport type StoreAfterDeleteHandler = (\n\trecord: R,\n\tsource: 'remote' | 'user'\n) => void\n\n/** @public */\nexport type StoreOperationCompleteHandler = (source: 'remote' | 'user') => void\n\n/**\n * The side effect manager (aka a \"correct state enforcer\") is responsible\n * for making sure that the editor's state is always correct. This includes\n * things like: deleting a shape if its parent is deleted; unbinding\n * arrows when their binding target is deleted; etc.\n *\n * @public\n */\nexport class StoreSideEffects {\n\tconstructor(private readonly store: Store) {}\n\n\tprivate _beforeCreateHandlers: { [K in string]?: StoreBeforeCreateHandler[] } = {}\n\tprivate _afterCreateHandlers: { [K in string]?: StoreAfterCreateHandler[] } = {}\n\tprivate _beforeChangeHandlers: { [K in string]?: StoreBeforeChangeHandler[] } = {}\n\tprivate _afterChangeHandlers: { [K in string]?: StoreAfterChangeHandler[] } = {}\n\tprivate _beforeDeleteHandlers: { [K in string]?: StoreBeforeDeleteHandler[] } = {}\n\tprivate _afterDeleteHandlers: { [K in string]?: StoreAfterDeleteHandler[] } = {}\n\tprivate _operationCompleteHandlers: StoreOperationCompleteHandler[] = []\n\n\tprivate _isEnabled = true\n\t/** @internal */\n\tisEnabled() {\n\t\treturn this._isEnabled\n\t}\n\t/** @internal */\n\tsetIsEnabled(enabled: boolean) {\n\t\tthis._isEnabled = enabled\n\t}\n\n\t/** @internal */\n\thandleBeforeCreate(record: R, source: 'remote' | 'user') {\n\t\tif (!this._isEnabled) return record\n\n\t\tconst handlers = this._beforeCreateHandlers[record.typeName] as StoreBeforeCreateHandler[]\n\t\tif (handlers) {\n\t\t\tlet r = record\n\t\t\tfor (const handler of handlers) {\n\t\t\t\tr = handler(r, source)\n\t\t\t}\n\t\t\treturn r\n\t\t}\n\n\t\treturn record\n\t}\n\n\t/** @internal */\n\thandleAfterCreate(record: R, source: 'remote' | 'user') {\n\t\tif (!this._isEnabled) return\n\n\t\tconst handlers = this._afterCreateHandlers[record.typeName] as StoreAfterCreateHandler[]\n\t\tif (handlers) {\n\t\t\tfor (const handler of handlers) {\n\t\t\t\thandler(record, source)\n\t\t\t}\n\t\t}\n\t}\n\n\t/** @internal */\n\thandleBeforeChange(prev: R, next: R, source: 'remote' | 'user') {\n\t\tif (!this._isEnabled) return next\n\n\t\tconst handlers = this._beforeChangeHandlers[next.typeName] as StoreBeforeChangeHandler[]\n\t\tif (handlers) {\n\t\t\tlet r = next\n\t\t\tfor (const handler of handlers) {\n\t\t\t\tr = handler(prev, r, source)\n\t\t\t}\n\t\t\treturn r\n\t\t}\n\n\t\treturn next\n\t}\n\n\t/** @internal */\n\thandleAfterChange(prev: R, next: R, source: 'remote' | 'user') {\n\t\tif (!this._isEnabled) return\n\n\t\tconst handlers = this._afterChangeHandlers[next.typeName] as StoreAfterChangeHandler[]\n\t\tif (handlers) {\n\t\t\tfor (const handler of handlers) {\n\t\t\t\thandler(prev, next, source)\n\t\t\t}\n\t\t}\n\t}\n\n\t/** @internal */\n\thandleBeforeDelete(record: R, source: 'remote' | 'user') {\n\t\tif (!this._isEnabled) return true\n\n\t\tconst handlers = this._beforeDeleteHandlers[record.typeName] as StoreBeforeDeleteHandler[]\n\t\tif (handlers) {\n\t\t\tfor (const handler of handlers) {\n\t\t\t\tif (handler(record, source) === false) {\n\t\t\t\t\treturn false\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn true\n\t}\n\n\t/** @internal */\n\thandleAfterDelete(record: R, source: 'remote' | 'user') {\n\t\tif (!this._isEnabled) return\n\n\t\tconst handlers = this._afterDeleteHandlers[record.typeName] as StoreAfterDeleteHandler[]\n\t\tif (handlers) {\n\t\t\tfor (const handler of handlers) {\n\t\t\t\thandler(record, source)\n\t\t\t}\n\t\t}\n\t}\n\n\t/** @internal */\n\thandleOperationComplete(source: 'remote' | 'user') {\n\t\tif (!this._isEnabled) return\n\n\t\tfor (const handler of this._operationCompleteHandlers) {\n\t\t\thandler(source)\n\t\t}\n\t}\n\n\t/**\n\t * Internal helper for registering a bunch of side effects at once and keeping them organized.\n\t * @internal\n\t */\n\tregister(handlersByType: {\n\t\t[T in R as T['typeName']]?: {\n\t\t\tbeforeCreate?: StoreBeforeCreateHandler\n\t\t\tafterCreate?: StoreAfterCreateHandler\n\t\t\tbeforeChange?: StoreBeforeChangeHandler\n\t\t\tafterChange?: StoreAfterChangeHandler\n\t\t\tbeforeDelete?: StoreBeforeDeleteHandler\n\t\t\tafterDelete?: StoreAfterDeleteHandler\n\t\t}\n\t}) {\n\t\tconst disposes: (() => void)[] = []\n\t\tfor (const [type, handlers] of Object.entries(handlersByType) as any) {\n\t\t\tif (handlers?.beforeCreate) {\n\t\t\t\tdisposes.push(this.registerBeforeCreateHandler(type, handlers.beforeCreate))\n\t\t\t}\n\t\t\tif (handlers?.afterCreate) {\n\t\t\t\tdisposes.push(this.registerAfterCreateHandler(type, handlers.afterCreate))\n\t\t\t}\n\t\t\tif (handlers?.beforeChange) {\n\t\t\t\tdisposes.push(this.registerBeforeChangeHandler(type, handlers.beforeChange))\n\t\t\t}\n\t\t\tif (handlers?.afterChange) {\n\t\t\t\tdisposes.push(this.registerAfterChangeHandler(type, handlers.afterChange))\n\t\t\t}\n\t\t\tif (handlers?.beforeDelete) {\n\t\t\t\tdisposes.push(this.registerBeforeDeleteHandler(type, handlers.beforeDelete))\n\t\t\t}\n\t\t\tif (handlers?.afterDelete) {\n\t\t\t\tdisposes.push(this.registerAfterDeleteHandler(type, handlers.afterDelete))\n\t\t\t}\n\t\t}\n\t\treturn () => {\n\t\t\tfor (const dispose of disposes) dispose()\n\t\t}\n\t}\n\n\t/**\n\t * Register a handler to be called before a record of a certain type is created. Return a\n\t * modified record from the handler to change the record that will be created.\n\t *\n\t * Use this handle only to modify the creation of the record itself. If you want to trigger a\n\t * side-effect on a different record (for example, moving one shape when another is created),\n\t * use {@link StoreSideEffects.registerAfterCreateHandler} instead.\n\t *\n\t * @example\n\t * ```ts\n\t * editor.sideEffects.registerBeforeCreateHandler('shape', (shape, source) => {\n\t * // only modify shapes created by the user\n\t * if (source !== 'user') return shape\n\t *\n\t * //by default, arrow shapes have no label. Let's make sure they always have a label.\n\t * if (shape.type === 'arrow') {\n\t * return {...shape, props: {...shape.props, text: 'an arrow'}}\n\t * }\n\t *\n\t * // other shapes get returned unmodified\n\t * return shape\n\t * })\n\t * ```\n\t *\n\t * @param typeName - The type of record to listen for\n\t * @param handler - The handler to call\n\t *\n\t * @returns A callback that removes the handler.\n\t */\n\tregisterBeforeCreateHandler(\n\t\ttypeName: T,\n\t\thandler: StoreBeforeCreateHandler\n\t) {\n\t\tconst handlers = this._beforeCreateHandlers[typeName] as StoreBeforeCreateHandler[]\n\t\tif (!handlers) this._beforeCreateHandlers[typeName] = []\n\t\tthis._beforeCreateHandlers[typeName]!.push(handler)\n\t\treturn () => remove(this._beforeCreateHandlers[typeName]!, handler)\n\t}\n\n\t/**\n\t * Register a handler to be called after a record is created. This is useful for side-effects\n\t * that would update _other_ records. If you want to modify the record being created use\n\t * {@link StoreSideEffects.registerBeforeCreateHandler} instead.\n\t *\n\t * @example\n\t * ```ts\n\t * editor.sideEffects.registerAfterCreateHandler('page', (page, source) => {\n\t * // Automatically create a shape when a page is created\n\t * editor.createShape({\n\t * id: createShapeId(),\n\t * type: 'text',\n\t * props: { text: page.name },\n\t * })\n\t * })\n\t * ```\n\t *\n\t * @param typeName - The type of record to listen for\n\t * @param handler - The handler to call\n\t *\n\t * @returns A callback that removes the handler.\n\t */\n\tregisterAfterCreateHandler(\n\t\ttypeName: T,\n\t\thandler: StoreAfterCreateHandler\n\t) {\n\t\tconst handlers = this._afterCreateHandlers[typeName] as StoreAfterCreateHandler[]\n\t\tif (!handlers) this._afterCreateHandlers[typeName] = []\n\t\tthis._afterCreateHandlers[typeName]!.push(handler)\n\t\treturn () => remove(this._afterCreateHandlers[typeName]!, handler)\n\t}\n\n\t/**\n\t * Register a handler to be called before a record is changed. The handler is given the old and\n\t * new record - you can return a modified record to apply a different update, or the old record\n\t * to block the update entirely.\n\t *\n\t * Use this handler only for intercepting updates to the record itself. If you want to update\n\t * other records in response to a change, use\n\t * {@link StoreSideEffects.registerAfterChangeHandler} instead.\n\t *\n\t * @example\n\t * ```ts\n\t * editor.sideEffects.registerBeforeChangeHandler('shape', (prev, next, source) => {\n\t * if (next.isLocked && !prev.isLocked) {\n\t * // prevent shapes from ever being locked:\n\t * return prev\n\t * }\n\t * // other types of change are allowed\n\t * return next\n\t * })\n\t * ```\n\t *\n\t * @param typeName - The type of record to listen for\n\t * @param handler - The handler to call\n\t *\n\t * @returns A callback that removes the handler.\n\t */\n\tregisterBeforeChangeHandler(\n\t\ttypeName: T,\n\t\thandler: StoreBeforeChangeHandler\n\t) {\n\t\tconst handlers = this._beforeChangeHandlers[typeName] as StoreBeforeChangeHandler[]\n\t\tif (!handlers) this._beforeChangeHandlers[typeName] = []\n\t\tthis._beforeChangeHandlers[typeName]!.push(handler)\n\t\treturn () => remove(this._beforeChangeHandlers[typeName]!, handler)\n\t}\n\n\t/**\n\t * Register a handler to be called after a record is changed. This is useful for side-effects\n\t * that would update _other_ records - if you want to modify the record being changed, use\n\t * {@link StoreSideEffects.registerBeforeChangeHandler} instead.\n\t *\n\t * @example\n\t * ```ts\n\t * editor.sideEffects.registerAfterChangeHandler('shape', (prev, next, source) => {\n\t * if (next.props.color === 'red') {\n\t * // there can only be one red shape at a time:\n\t * const otherRedShapes = editor.getCurrentPageShapes().filter(s => s.props.color === 'red' && s.id !== next.id)\n\t * editor.updateShapes(otherRedShapes.map(s => ({...s, props: {...s.props, color: 'blue'}})))\n\t * }\n\t * })\n\t * ```\n\t *\n\t * @param typeName - The type of record to listen for\n\t * @param handler - The handler to call\n\t *\n\t * @returns A callback that removes the handler.\n\t */\n\tregisterAfterChangeHandler(\n\t\ttypeName: T,\n\t\thandler: StoreAfterChangeHandler\n\t) {\n\t\tconst handlers = this._afterChangeHandlers[typeName] as StoreAfterChangeHandler[]\n\t\tif (!handlers) this._afterChangeHandlers[typeName] = []\n\t\tthis._afterChangeHandlers[typeName]!.push(handler as StoreAfterChangeHandler)\n\t\treturn () => remove(this._afterChangeHandlers[typeName]!, handler)\n\t}\n\n\t/**\n\t * Register a handler to be called before a record is deleted. The handler can return `false` to\n\t * prevent the deletion.\n\t *\n\t * Use this handler only for intercepting deletions of the record itself. If you want to do\n\t * something to other records in response to a deletion, use\n\t * {@link StoreSideEffects.registerAfterDeleteHandler} instead.\n\t *\n\t * @example\n\t * ```ts\n\t * editor.sideEffects.registerBeforeDeleteHandler('shape', (shape, source) => {\n\t * if (shape.props.color === 'red') {\n\t * // prevent red shapes from being deleted\n\t * \t return false\n\t * }\n\t * })\n\t * ```\n\t *\n\t * @param typeName - The type of record to listen for\n\t * @param handler - The handler to call\n\t *\n\t * @returns A callback that removes the handler.\n\t */\n\tregisterBeforeDeleteHandler(\n\t\ttypeName: T,\n\t\thandler: StoreBeforeDeleteHandler\n\t) {\n\t\tconst handlers = this._beforeDeleteHandlers[typeName] as StoreBeforeDeleteHandler[]\n\t\tif (!handlers) this._beforeDeleteHandlers[typeName] = []\n\t\tthis._beforeDeleteHandlers[typeName]!.push(handler as StoreBeforeDeleteHandler)\n\t\treturn () => remove(this._beforeDeleteHandlers[typeName]!, handler)\n\t}\n\n\t/**\n\t * Register a handler to be called after a record is deleted. This is useful for side-effects\n\t * that would update _other_ records - if you want to block the deletion of the record itself,\n\t * use {@link StoreSideEffects.registerBeforeDeleteHandler} instead.\n\t *\n\t * @example\n\t * ```ts\n\t * editor.sideEffects.registerAfterDeleteHandler('shape', (shape, source) => {\n\t * // if the last shape in a frame is deleted, delete the frame too:\n\t * const parentFrame = editor.getShape(shape.parentId)\n\t * if (!parentFrame || parentFrame.type !== 'frame') return\n\t *\n\t * const siblings = editor.getSortedChildIdsForParent(parentFrame)\n\t * if (siblings.length === 0) {\n\t * editor.deleteShape(parentFrame.id)\n\t * }\n\t * })\n\t * ```\n\t *\n\t * @param typeName - The type of record to listen for\n\t * @param handler - The handler to call\n\t *\n\t * @returns A callback that removes the handler.\n\t */\n\tregisterAfterDeleteHandler(\n\t\ttypeName: T,\n\t\thandler: StoreAfterDeleteHandler\n\t) {\n\t\tconst handlers = this._afterDeleteHandlers[typeName] as StoreAfterDeleteHandler[]\n\t\tif (!handlers) this._afterDeleteHandlers[typeName] = []\n\t\tthis._afterDeleteHandlers[typeName]!.push(handler as StoreAfterDeleteHandler)\n\t\treturn () => remove(this._afterDeleteHandlers[typeName]!, handler)\n\t}\n\n\t/**\n\t * Register a handler to be called when a store completes an atomic operation.\n\t *\n\t * @example\n\t * ```ts\n\t * let count = 0\n\t *\n\t * editor.sideEffects.registerOperationCompleteHandler(() => count++)\n\t *\n\t * editor.selectAll()\n\t * expect(count).toBe(1)\n\t *\n\t * editor.store.atomic(() => {\n\t *\teditor.selectNone()\n\t * \teditor.selectAll()\n\t * })\n\t *\n\t * expect(count).toBe(2)\n\t * ```\n\t *\n\t * @param handler - The handler to call\n\t *\n\t * @returns A callback that removes the handler.\n\t *\n\t * @public\n\t */\n\tregisterOperationCompleteHandler(handler: StoreOperationCompleteHandler) {\n\t\tthis._operationCompleteHandlers.push(handler)\n\t\treturn () => remove(this._operationCompleteHandlers, handler)\n\t}\n}\n\nfunction remove(array: any[], item: any) {\n\tconst index = array.indexOf(item)\n\tif (index >= 0) {\n\t\tarray.splice(index, 1)\n\t}\n}\n", "import { STRUCTURED_CLONE_OBJECT_PROTOTYPE } from '@tldraw/utils'\n\n/**\n * Freeze an object when in development mode. Copied from\n * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/freeze\n *\n * @example\n *\n * ```ts\n * const frozen = devFreeze({ a: 1 })\n * ```\n *\n * @param object - The object to freeze.\n * @returns The frozen object when in development mode, or else the object when in other modes.\n * @public\n */\nexport function devFreeze(object: T): T {\n\tif (process.env.NODE_ENV === 'production') {\n\t\treturn object\n\t}\n\tconst proto = Object.getPrototypeOf(object)\n\tif (\n\t\tproto &&\n\t\t!(\n\t\t\tArray.isArray(object) ||\n\t\t\tproto === Object.prototype ||\n\t\t\tproto === null ||\n\t\t\tproto === STRUCTURED_CLONE_OBJECT_PROTOTYPE\n\t\t)\n\t) {\n\t\tconsole.error('cannot include non-js data in a record', object)\n\t\tthrow new Error('cannot include non-js data in a record')\n\t}\n\n\t// Retrieve the property names defined on object\n\tconst propNames = Object.getOwnPropertyNames(object)\n\n\t// Recursively freeze properties before freezing self\n\tfor (const name of propNames) {\n\t\tconst value = (object as any)[name]\n\n\t\tif (value && typeof value === 'object') {\n\t\t\tdevFreeze(value)\n\t\t}\n\t}\n\n\treturn Object.freeze(object)\n}\n", "import {\n\tResult,\n\tassert,\n\texhaustiveSwitchError,\n\tgetOwnProperty,\n\tstructuredClone,\n} from '@tldraw/utils'\nimport { UnknownRecord } from './BaseRecord'\nimport { RecordType } from './RecordType'\nimport { SerializedStore, Store, StoreSnapshot } from './Store'\nimport {\n\tMigration,\n\tMigrationFailureReason,\n\tMigrationId,\n\tMigrationResult,\n\tMigrationSequence,\n\tparseMigrationId,\n\tsortMigrations,\n\tvalidateMigrations,\n} from './migrate'\n\n/** @public */\nexport interface SerializedSchemaV1 {\n\t/** Schema version is the version for this type you're looking at right now */\n\tschemaVersion: 1\n\t/**\n\t * Store version is the version for the structure of the store. e.g. higher level structure like\n\t * removing or renaming a record type.\n\t */\n\tstoreVersion: number\n\t/** Record versions are the versions for each record type. e.g. adding a new field to a record */\n\trecordVersions: Record<\n\t\tstring,\n\t\t| {\n\t\t\t\tversion: number\n\t\t }\n\t\t| {\n\t\t\t\t// subtypes are used for migrating shape and asset props\n\t\t\t\tversion: number\n\t\t\t\tsubTypeVersions: Record\n\t\t\t\tsubTypeKey: string\n\t\t }\n\t>\n}\n\n/** @public */\nexport interface SerializedSchemaV2 {\n\tschemaVersion: 2\n\tsequences: {\n\t\t[sequenceId: string]: number\n\t}\n}\n\n/** @public */\nexport type SerializedSchema = SerializedSchemaV1 | SerializedSchemaV2\n\nexport function upgradeSchema(schema: SerializedSchema): Result {\n\tif (schema.schemaVersion > 2 || schema.schemaVersion < 1) return Result.err('Bad schema version')\n\tif (schema.schemaVersion === 2) return Result.ok(schema as SerializedSchemaV2)\n\tconst result: SerializedSchemaV2 = {\n\t\tschemaVersion: 2,\n\t\tsequences: {},\n\t}\n\n\tfor (const [typeName, recordVersion] of Object.entries(schema.recordVersions)) {\n\t\tresult.sequences[`com.tldraw.${typeName}`] = recordVersion.version\n\t\tif ('subTypeKey' in recordVersion) {\n\t\t\tfor (const [subType, version] of Object.entries(recordVersion.subTypeVersions)) {\n\t\t\t\tresult.sequences[`com.tldraw.${typeName}.${subType}`] = version\n\t\t\t}\n\t\t}\n\t}\n\treturn Result.ok(result)\n}\n\n/** @public */\nexport interface StoreSchemaOptions {\n\tmigrations?: MigrationSequence[]\n\t/** @public */\n\tonValidationFailure?: (data: {\n\t\terror: unknown\n\t\tstore: Store\n\t\trecord: R\n\t\tphase: 'initialize' | 'createRecord' | 'updateRecord' | 'tests'\n\t\trecordBefore: R | null\n\t}) => R\n\t/** @internal */\n\tcreateIntegrityChecker?: (store: Store) => void\n}\n\n/** @public */\nexport class StoreSchema {\n\tstatic create(\n\t\t// HACK: making this param work with RecordType is an enormous pain\n\t\t// let's just settle for making sure each typeName has a corresponding RecordType\n\t\t// and accept that this function won't be able to infer the record type from it's arguments\n\t\ttypes: { [TypeName in R['typeName']]: { createId: any } },\n\t\toptions?: StoreSchemaOptions\n\t): StoreSchema {\n\t\treturn new StoreSchema(types as any, options ?? {})\n\t}\n\n\treadonly migrations: Record = {}\n\treadonly sortedMigrations: readonly Migration[]\n\n\tprivate constructor(\n\t\tpublic readonly types: {\n\t\t\t[Record in R as Record['typeName']]: RecordType\n\t\t},\n\t\tprivate readonly options: StoreSchemaOptions\n\t) {\n\t\tfor (const m of options.migrations ?? []) {\n\t\t\tassert(!this.migrations[m.sequenceId], `Duplicate migration sequenceId ${m.sequenceId}`)\n\t\t\tvalidateMigrations(m)\n\t\t\tthis.migrations[m.sequenceId] = m\n\t\t}\n\t\tconst allMigrations = Object.values(this.migrations).flatMap((m) => m.sequence)\n\t\tthis.sortedMigrations = sortMigrations(allMigrations)\n\n\t\tfor (const migration of this.sortedMigrations) {\n\t\t\tif (!migration.dependsOn?.length) continue\n\t\t\tfor (const dep of migration.dependsOn) {\n\t\t\t\tconst depMigration = allMigrations.find((m) => m.id === dep)\n\t\t\t\tassert(depMigration, `Migration '${migration.id}' depends on missing migration '${dep}'`)\n\t\t\t}\n\t\t}\n\t}\n\n\tvalidateRecord(\n\t\tstore: Store,\n\t\trecord: R,\n\t\tphase: 'initialize' | 'createRecord' | 'updateRecord' | 'tests',\n\t\trecordBefore: R | null\n\t): R {\n\t\ttry {\n\t\t\tconst recordType = getOwnProperty(this.types, record.typeName)\n\t\t\tif (!recordType) {\n\t\t\t\tthrow new Error(`Missing definition for record type ${record.typeName}`)\n\t\t\t}\n\t\t\treturn recordType.validate(record, recordBefore ?? undefined)\n\t\t} catch (error: unknown) {\n\t\t\tif (this.options.onValidationFailure) {\n\t\t\t\treturn this.options.onValidationFailure({\n\t\t\t\t\tstore,\n\t\t\t\t\trecord,\n\t\t\t\t\tphase,\n\t\t\t\t\trecordBefore,\n\t\t\t\t\terror,\n\t\t\t\t})\n\t\t\t} else {\n\t\t\t\tthrow error\n\t\t\t}\n\t\t}\n\t}\n\n\t// TODO: use a weakmap to store the result of this function\n\tpublic getMigrationsSince(persistedSchema: SerializedSchema): Result {\n\t\tconst upgradeResult = upgradeSchema(persistedSchema)\n\t\tif (!upgradeResult.ok) {\n\t\t\treturn upgradeResult\n\t\t}\n\t\tconst schema = upgradeResult.value\n\t\tconst sequenceIdsToInclude = new Set(\n\t\t\t// start with any shared sequences\n\t\t\tObject.keys(schema.sequences).filter((sequenceId) => this.migrations[sequenceId])\n\t\t)\n\n\t\t// also include any sequences that are not in the persisted schema but are marked as postHoc\n\t\tfor (const sequenceId in this.migrations) {\n\t\t\tif (schema.sequences[sequenceId] === undefined && this.migrations[sequenceId].retroactive) {\n\t\t\t\tsequenceIdsToInclude.add(sequenceId)\n\t\t\t}\n\t\t}\n\n\t\tif (sequenceIdsToInclude.size === 0) {\n\t\t\treturn Result.ok([])\n\t\t}\n\n\t\tconst allMigrationsToInclude = new Set()\n\t\tfor (const sequenceId of sequenceIdsToInclude) {\n\t\t\tconst theirVersion = schema.sequences[sequenceId]\n\t\t\tif (\n\t\t\t\t(typeof theirVersion !== 'number' && this.migrations[sequenceId].retroactive) ||\n\t\t\t\ttheirVersion === 0\n\t\t\t) {\n\t\t\t\tfor (const migration of this.migrations[sequenceId].sequence) {\n\t\t\t\t\tallMigrationsToInclude.add(migration.id)\n\t\t\t\t}\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tconst theirVersionId = `${sequenceId}/${theirVersion}`\n\t\t\tconst idx = this.migrations[sequenceId].sequence.findIndex((m) => m.id === theirVersionId)\n\t\t\t// todo: better error handling\n\t\t\tif (idx === -1) {\n\t\t\t\treturn Result.err('Incompatible schema?')\n\t\t\t}\n\t\t\tfor (const migration of this.migrations[sequenceId].sequence.slice(idx + 1)) {\n\t\t\t\tallMigrationsToInclude.add(migration.id)\n\t\t\t}\n\t\t}\n\n\t\t// collect any migrations\n\t\treturn Result.ok(this.sortedMigrations.filter(({ id }) => allMigrationsToInclude.has(id)))\n\t}\n\n\tmigratePersistedRecord(\n\t\trecord: R,\n\t\tpersistedSchema: SerializedSchema,\n\t\tdirection: 'up' | 'down' = 'up'\n\t): MigrationResult {\n\t\tconst migrations = this.getMigrationsSince(persistedSchema)\n\t\tif (!migrations.ok) {\n\t\t\t// TODO: better error\n\t\t\tconsole.error('Error migrating record', migrations.error)\n\t\t\treturn { type: 'error', reason: MigrationFailureReason.MigrationError }\n\t\t}\n\t\tlet migrationsToApply = migrations.value\n\t\tif (migrationsToApply.length === 0) {\n\t\t\treturn { type: 'success', value: record }\n\t\t}\n\n\t\tif (migrationsToApply.some((m) => m.scope === 'store')) {\n\t\t\treturn {\n\t\t\t\ttype: 'error',\n\t\t\t\treason:\n\t\t\t\t\tdirection === 'down'\n\t\t\t\t\t\t? MigrationFailureReason.TargetVersionTooOld\n\t\t\t\t\t\t: MigrationFailureReason.TargetVersionTooNew,\n\t\t\t}\n\t\t}\n\n\t\tif (direction === 'down') {\n\t\t\tif (!migrationsToApply.every((m) => m.down)) {\n\t\t\t\treturn {\n\t\t\t\t\ttype: 'error',\n\t\t\t\t\treason: MigrationFailureReason.TargetVersionTooOld,\n\t\t\t\t}\n\t\t\t}\n\t\t\tmigrationsToApply = migrationsToApply.slice().reverse()\n\t\t}\n\n\t\trecord = structuredClone(record)\n\t\ttry {\n\t\t\tfor (const migration of migrationsToApply) {\n\t\t\t\tif (migration.scope === 'store') throw new Error(/* won't happen, just for TS */)\n\t\t\t\tconst shouldApply = migration.filter ? migration.filter(record) : true\n\t\t\t\tif (!shouldApply) continue\n\t\t\t\tconst result = migration[direction]!(record)\n\t\t\t\tif (result) {\n\t\t\t\t\trecord = structuredClone(result) as any\n\t\t\t\t}\n\t\t\t}\n\t\t} catch (e) {\n\t\t\tconsole.error('Error migrating record', e)\n\t\t\treturn { type: 'error', reason: MigrationFailureReason.MigrationError }\n\t\t}\n\n\t\treturn { type: 'success', value: record }\n\t}\n\n\tmigrateStoreSnapshot(snapshot: StoreSnapshot): MigrationResult> {\n\t\tlet { store } = snapshot\n\t\tconst migrations = this.getMigrationsSince(snapshot.schema)\n\t\tif (!migrations.ok) {\n\t\t\t// TODO: better error\n\t\t\tconsole.error('Error migrating store', migrations.error)\n\t\t\treturn { type: 'error', reason: MigrationFailureReason.MigrationError }\n\t\t}\n\t\tconst migrationsToApply = migrations.value\n\t\tif (migrationsToApply.length === 0) {\n\t\t\treturn { type: 'success', value: store }\n\t\t}\n\n\t\tstore = structuredClone(store)\n\n\t\ttry {\n\t\t\tfor (const migration of migrationsToApply) {\n\t\t\t\tif (migration.scope === 'record') {\n\t\t\t\t\tfor (const [id, record] of Object.entries(store)) {\n\t\t\t\t\t\tconst shouldApply = migration.filter ? migration.filter(record as UnknownRecord) : true\n\t\t\t\t\t\tif (!shouldApply) continue\n\t\t\t\t\t\tconst result = migration.up!(record as any)\n\t\t\t\t\t\tif (result) {\n\t\t\t\t\t\t\tstore[id as keyof typeof store] = structuredClone(result) as any\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} else if (migration.scope === 'store') {\n\t\t\t\t\tconst result = migration.up!(store)\n\t\t\t\t\tif (result) {\n\t\t\t\t\t\tstore = structuredClone(result) as any\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\texhaustiveSwitchError(migration)\n\t\t\t\t}\n\t\t\t}\n\t\t} catch (e) {\n\t\t\tconsole.error('Error migrating store', e)\n\t\t\treturn { type: 'error', reason: MigrationFailureReason.MigrationError }\n\t\t}\n\n\t\treturn { type: 'success', value: store }\n\t}\n\n\t/** @internal */\n\tcreateIntegrityChecker(store: Store): (() => void) | undefined {\n\t\treturn this.options.createIntegrityChecker?.(store) ?? undefined\n\t}\n\n\tserialize(): SerializedSchemaV2 {\n\t\treturn {\n\t\t\tschemaVersion: 2,\n\t\t\tsequences: Object.fromEntries(\n\t\t\t\tObject.values(this.migrations).map(({ sequenceId, sequence }) => [\n\t\t\t\t\tsequenceId,\n\t\t\t\t\tsequence.length ? parseMigrationId(sequence.at(-1)!.id).version : 0,\n\t\t\t\t])\n\t\t\t),\n\t\t}\n\t}\n\n\t/**\n\t * @deprecated This is only here for legacy reasons, don't use it unless you have david's blessing!\n\t */\n\tserializeEarliestVersion(): SerializedSchema {\n\t\treturn {\n\t\t\tschemaVersion: 2,\n\t\t\tsequences: Object.fromEntries(\n\t\t\t\tObject.values(this.migrations).map(({ sequenceId }) => [sequenceId, 0])\n\t\t\t),\n\t\t}\n\t}\n\n\t/** @internal */\n\tgetType(typeName: string) {\n\t\tconst type = getOwnProperty(this.types, typeName)\n\t\tassert(type, 'record type does not exists')\n\t\treturn type\n\t}\n}\n", "import { assert, objectMapEntries } from '@tldraw/utils'\nimport { UnknownRecord } from './BaseRecord'\nimport { SerializedStore } from './Store'\n\nlet didWarn = false\n\n/**\n * @public\n * @deprecated use `createShapePropsMigrationSequence` instead. See [the docs](https://tldraw.dev/docs/persistence#Updating-legacy-shape-migrations-defineMigrations) for how to migrate.\n */\nexport function defineMigrations(opts: {\n\tfirstVersion?: number\n\tcurrentVersion?: number\n\tmigrators?: Record\n\tsubTypeKey?: string\n\tsubTypeMigrations?: Record\n}): LegacyMigrations {\n\tconst { currentVersion, firstVersion, migrators = {}, subTypeKey, subTypeMigrations } = opts\n\tif (!didWarn) {\n\t\tconsole.warn(\n\t\t\t`The 'defineMigrations' function is deprecated and will be removed in a future release. Use the new migrations API instead. See the migration guide for more info: https://tldraw.dev/docs/persistence#Updating-legacy-shape-migrations-defineMigrations`\n\t\t)\n\t\tdidWarn = true\n\t}\n\n\t// Some basic guards against impossible version combinations, some of which will be caught by TypeScript\n\tif (typeof currentVersion === 'number' && typeof firstVersion === 'number') {\n\t\tif ((currentVersion as number) === (firstVersion as number)) {\n\t\t\tthrow Error(`Current version is equal to initial version.`)\n\t\t} else if (currentVersion < firstVersion) {\n\t\t\tthrow Error(`Current version is lower than initial version.`)\n\t\t}\n\t}\n\n\treturn {\n\t\tfirstVersion: (firstVersion as number) ?? 0, // defaults\n\t\tcurrentVersion: (currentVersion as number) ?? 0, // defaults\n\t\tmigrators,\n\t\tsubTypeKey,\n\t\tsubTypeMigrations,\n\t}\n}\n\nfunction squashDependsOn(sequence: Array): Migration[] {\n\tconst result: Migration[] = []\n\tfor (let i = sequence.length - 1; i >= 0; i--) {\n\t\tconst elem = sequence[i]\n\t\tif (!('id' in elem)) {\n\t\t\tconst dependsOn = elem.dependsOn\n\t\t\tconst prev = result[0]\n\t\t\tif (prev) {\n\t\t\t\tresult[0] = {\n\t\t\t\t\t...prev,\n\t\t\t\t\tdependsOn: dependsOn.concat(prev.dependsOn ?? []),\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tresult.unshift(elem)\n\t\t}\n\t}\n\treturn result\n}\n\n/**\n * Creates a migration sequence.\n * See the [migration guide](https://tldraw.dev/docs/persistence#Migrations) for more info on how to use this API.\n * @public\n */\nexport function createMigrationSequence({\n\tsequence,\n\tsequenceId,\n\tretroactive = true,\n}: {\n\tsequenceId: string\n\tretroactive?: boolean\n\tsequence: Array\n}): MigrationSequence {\n\tconst migrations: MigrationSequence = {\n\t\tsequenceId,\n\t\tretroactive,\n\t\tsequence: squashDependsOn(sequence),\n\t}\n\tvalidateMigrations(migrations)\n\treturn migrations\n}\n\n/**\n * Creates a named set of migration ids given a named set of version numbers and a sequence id.\n *\n * See the [migration guide](https://tldraw.dev/docs/persistence#Migrations) for more info on how to use this API.\n * @public\n * @public\n */\nexport function createMigrationIds<\n\tconst ID extends string,\n\tconst Versions extends Record,\n>(sequenceId: ID, versions: Versions): { [K in keyof Versions]: `${ID}/${Versions[K]}` } {\n\treturn Object.fromEntries(\n\t\tobjectMapEntries(versions).map(([key, version]) => [key, `${sequenceId}/${version}`] as const)\n\t) as any\n}\n\n/** @internal */\nexport function createRecordMigrationSequence(opts: {\n\trecordType: string\n\tfilter?: (record: UnknownRecord) => boolean\n\tretroactive?: boolean\n\tsequenceId: string\n\tsequence: Omit, 'scope'>[]\n}): MigrationSequence {\n\tconst sequenceId = opts.sequenceId\n\treturn createMigrationSequence({\n\t\tsequenceId,\n\t\tretroactive: opts.retroactive ?? true,\n\t\tsequence: opts.sequence.map((m) =>\n\t\t\t'id' in m\n\t\t\t\t? {\n\t\t\t\t\t\t...m,\n\t\t\t\t\t\tscope: 'record',\n\t\t\t\t\t\tfilter: (r: UnknownRecord) =>\n\t\t\t\t\t\t\tr.typeName === opts.recordType &&\n\t\t\t\t\t\t\t(m.filter?.(r) ?? true) &&\n\t\t\t\t\t\t\t(opts.filter?.(r) ?? true),\n\t\t\t\t\t}\n\t\t\t\t: m\n\t\t),\n\t})\n}\n\n/** @public */\nexport interface LegacyMigration {\n\tup: (oldState: Before) => After\n\tdown: (newState: After) => Before\n}\n\n/** @public */\nexport type MigrationId = `${string}/${number}`\n\n/** @public */\nexport interface StandaloneDependsOn {\n\treadonly dependsOn: readonly MigrationId[]\n}\n\n/** @public */\nexport type Migration = {\n\treadonly id: MigrationId\n\treadonly dependsOn?: readonly MigrationId[] | undefined\n} & (\n\t| {\n\t\t\treadonly scope: 'record'\n\t\t\treadonly filter?: (record: UnknownRecord) => boolean\n\t\t\treadonly up: (oldState: UnknownRecord) => void | UnknownRecord\n\t\t\treadonly down?: (newState: UnknownRecord) => void | UnknownRecord\n\t }\n\t| {\n\t\t\treadonly scope: 'store'\n\t\t\treadonly up: (\n\t\t\t\toldState: SerializedStore\n\t\t\t) => void | SerializedStore\n\t\t\treadonly down?: (\n\t\t\t\tnewState: SerializedStore\n\t\t\t) => void | SerializedStore\n\t }\n)\n\n/** @public */\nexport interface LegacyBaseMigrationsInfo {\n\tfirstVersion: number\n\tcurrentVersion: number\n\tmigrators: { [version: number]: LegacyMigration }\n}\n\n/** @public */\nexport interface LegacyMigrations extends LegacyBaseMigrationsInfo {\n\tsubTypeKey?: string\n\tsubTypeMigrations?: Record\n}\n\n/** @public */\nexport interface MigrationSequence {\n\tsequenceId: string\n\t/**\n\t * retroactive should be true if the migrations should be applied to snapshots that were created before\n\t * this migration sequence was added to the schema.\n\t *\n\t * In general:\n\t *\n\t * - retroactive should be true when app developers create their own new migration sequences.\n\t * - retroactive should be false when library developers ship a migration sequence. When you install a library for the first time, any migrations that were added in the library before that point should generally _not_ be applied to your existing data.\n\t */\n\tretroactive: boolean\n\tsequence: Migration[]\n}\n\nexport function sortMigrations(migrations: Migration[]): Migration[] {\n\t// we do a topological sort using dependsOn and implicit dependencies between migrations in the same sequence\n\tconst byId = new Map(migrations.map((m) => [m.id, m]))\n\tconst isProcessing = new Set()\n\n\tconst result: Migration[] = []\n\n\tfunction process(m: Migration) {\n\t\tassert(!isProcessing.has(m.id), `Circular dependency in migrations: ${m.id}`)\n\t\tisProcessing.add(m.id)\n\n\t\tconst { version, sequenceId } = parseMigrationId(m.id)\n\t\tconst parent = byId.get(`${sequenceId}/${version - 1}`)\n\t\tif (parent) {\n\t\t\tprocess(parent)\n\t\t}\n\n\t\tif (m.dependsOn) {\n\t\t\tfor (const dep of m.dependsOn) {\n\t\t\t\tconst depMigration = byId.get(dep)\n\t\t\t\tif (depMigration) {\n\t\t\t\t\tprocess(depMigration)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tbyId.delete(m.id)\n\t\tresult.push(m)\n\t}\n\n\tfor (const m of byId.values()) {\n\t\tprocess(m)\n\t}\n\n\treturn result\n}\n\n/** @internal */\nexport function parseMigrationId(id: MigrationId): { sequenceId: string; version: number } {\n\tconst [sequenceId, version] = id.split('/')\n\treturn { sequenceId, version: parseInt(version) }\n}\n\nfunction validateMigrationId(id: string, expectedSequenceId?: string) {\n\tif (expectedSequenceId) {\n\t\tassert(\n\t\t\tid.startsWith(expectedSequenceId + '/'),\n\t\t\t`Every migration in sequence '${expectedSequenceId}' must have an id starting with '${expectedSequenceId}/'. Got invalid id: '${id}'`\n\t\t)\n\t}\n\n\tassert(id.match(/^(.*?)\\/(0|[1-9]\\d*)$/), `Invalid migration id: '${id}'`)\n}\n\nexport function validateMigrations(migrations: MigrationSequence) {\n\tassert(\n\t\t!migrations.sequenceId.includes('/'),\n\t\t`sequenceId cannot contain a '/', got ${migrations.sequenceId}`\n\t)\n\tassert(migrations.sequenceId.length, 'sequenceId must be a non-empty string')\n\n\tif (migrations.sequence.length === 0) {\n\t\treturn\n\t}\n\n\tvalidateMigrationId(migrations.sequence[0].id, migrations.sequenceId)\n\tlet n = parseMigrationId(migrations.sequence[0].id).version\n\tassert(\n\t\tn === 1,\n\t\t`Expected the first migrationId to be '${migrations.sequenceId}/1' but got '${migrations.sequence[0].id}'`\n\t)\n\tfor (let i = 1; i < migrations.sequence.length; i++) {\n\t\tconst id = migrations.sequence[i].id\n\t\tvalidateMigrationId(id, migrations.sequenceId)\n\t\tconst m = parseMigrationId(id).version\n\t\tassert(\n\t\t\tm === n + 1,\n\t\t\t`Migration id numbers must increase in increments of 1, expected ${migrations.sequenceId}/${n + 1} but got '${migrations.sequence[i].id}'`\n\t\t)\n\t\tn = m\n\t}\n}\n\n/** @public */\nexport type MigrationResult =\n\t| { type: 'success'; value: T }\n\t| { type: 'error'; reason: MigrationFailureReason }\n\n/** @public */\nexport enum MigrationFailureReason {\n\tIncompatibleSubtype = 'incompatible-subtype',\n\tUnknownType = 'unknown-type',\n\tTargetVersionTooNew = 'target-version-too-new',\n\tTargetVersionTooOld = 'target-version-too-old',\n\tMigrationError = 'migration-error',\n\tUnrecognizedSubtype = 'unrecognized-subtype',\n}\n", "import { RecordsDiff, UnknownRecord } from '@tldraw/store'\nimport { objectMapEntries, objectMapValues } from '@tldraw/utils'\nimport isEqual from 'lodash.isequal'\n\n/** @internal */\nexport const RecordOpType = {\n\tPut: 'put',\n\tPatch: 'patch',\n\tRemove: 'remove',\n} as const\n\n/** @internal */\nexport type RecordOpType = (typeof RecordOpType)[keyof typeof RecordOpType]\n\n/** @internal */\nexport type RecordOp =\n\t| [typeof RecordOpType.Put, R]\n\t| [typeof RecordOpType.Patch, ObjectDiff]\n\t| [typeof RecordOpType.Remove]\n\n/**\n * A one-way (non-reversible) diff designed for small json footprint. These are mainly intended to\n * be sent over the wire. Either as push requests from the client to the server, or as patch\n * operations in the opposite direction.\n *\n * Each key in this object is the id of a record that has been added, updated, or removed.\n *\n * @internal\n */\nexport interface NetworkDiff {\n\t[id: string]: RecordOp\n}\n\n/**\n * Converts a (reversible, verbose) RecordsDiff into a (non-reversible, concise) NetworkDiff\n *\n *@internal\n */\nexport const getNetworkDiff = (\n\tdiff: RecordsDiff\n): NetworkDiff | null => {\n\tlet res: NetworkDiff | null = null\n\n\tfor (const [k, v] of objectMapEntries(diff.added)) {\n\t\tif (!res) res = {}\n\t\tres[k] = [RecordOpType.Put, v]\n\t}\n\n\tfor (const [from, to] of objectMapValues(diff.updated)) {\n\t\tconst diff = diffRecord(from, to)\n\t\tif (diff) {\n\t\t\tif (!res) res = {}\n\t\t\tres[to.id] = [RecordOpType.Patch, diff]\n\t\t}\n\t}\n\n\tfor (const removed of Object.keys(diff.removed)) {\n\t\tif (!res) res = {}\n\t\tres[removed] = [RecordOpType.Remove]\n\t}\n\n\treturn res\n}\n\n/** @internal */\nexport const ValueOpType = {\n\tPut: 'put',\n\tDelete: 'delete',\n\tAppend: 'append',\n\tPatch: 'patch',\n} as const\n/** @internal */\nexport type ValueOpType = (typeof ValueOpType)[keyof typeof ValueOpType]\n\n/** @internal */\nexport type PutOp = [type: typeof ValueOpType.Put, value: unknown]\n/** @internal */\nexport type AppendOp = [type: typeof ValueOpType.Append, values: unknown[], offset: number]\n/** @internal */\nexport type PatchOp = [type: typeof ValueOpType.Patch, diff: ObjectDiff]\n/** @internal */\nexport type DeleteOp = [type: typeof ValueOpType.Delete]\n\n/** @internal */\nexport type ValueOp = PutOp | AppendOp | PatchOp | DeleteOp\n\n/** @internal */\nexport interface ObjectDiff {\n\t[k: string]: ValueOp\n}\n\n/** @internal */\nexport function diffRecord(prev: object, next: object): ObjectDiff | null {\n\treturn diffObject(prev, next, new Set(['props']))\n}\n\nfunction diffObject(prev: object, next: object, nestedKeys?: Set): ObjectDiff | null {\n\tif (prev === next) {\n\t\treturn null\n\t}\n\tlet result: ObjectDiff | null = null\n\tfor (const key of Object.keys(prev)) {\n\t\t// if key is not in next then it was deleted\n\t\tif (!(key in next)) {\n\t\t\tif (!result) result = {}\n\t\t\tresult[key] = [ValueOpType.Delete]\n\t\t\tcontinue\n\t\t}\n\t\t// if key is in both places, then compare values\n\t\tconst prevVal = (prev as any)[key]\n\t\tconst nextVal = (next as any)[key]\n\t\tif (!isEqual(prevVal, nextVal)) {\n\t\t\tif (nestedKeys?.has(key) && prevVal && nextVal) {\n\t\t\t\tconst diff = diffObject(prevVal, nextVal)\n\t\t\t\tif (diff) {\n\t\t\t\t\tif (!result) result = {}\n\t\t\t\t\tresult[key] = [ValueOpType.Patch, diff]\n\t\t\t\t}\n\t\t\t} else if (Array.isArray(nextVal) && Array.isArray(prevVal)) {\n\t\t\t\tconst op = diffArray(prevVal, nextVal)\n\t\t\t\tif (op) {\n\t\t\t\t\tif (!result) result = {}\n\t\t\t\t\tresult[key] = op\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif (!result) result = {}\n\t\t\t\tresult[key] = [ValueOpType.Put, nextVal]\n\t\t\t}\n\t\t}\n\t}\n\tfor (const key of Object.keys(next)) {\n\t\t// if key is in next but not in prev then it was added\n\t\tif (!(key in prev)) {\n\t\t\tif (!result) result = {}\n\t\t\tresult[key] = [ValueOpType.Put, (next as any)[key]]\n\t\t}\n\t}\n\treturn result\n}\n\nfunction diffValue(valueA: unknown, valueB: unknown): ValueOp | null {\n\tif (Object.is(valueA, valueB)) return null\n\tif (Array.isArray(valueA) && Array.isArray(valueB)) {\n\t\treturn diffArray(valueA, valueB)\n\t} else if (!valueA || !valueB || typeof valueA !== 'object' || typeof valueB !== 'object') {\n\t\treturn isEqual(valueA, valueB) ? null : [ValueOpType.Put, valueB]\n\t} else {\n\t\tconst diff = diffObject(valueA, valueB)\n\t\treturn diff ? [ValueOpType.Patch, diff] : null\n\t}\n}\n\nfunction diffArray(prevArray: unknown[], nextArray: unknown[]): PutOp | AppendOp | PatchOp | null {\n\tif (Object.is(prevArray, nextArray)) return null\n\t// if lengths are equal, check for patch operation\n\tif (prevArray.length === nextArray.length) {\n\t\t// bail out if more than len/5 items need patching\n\t\tconst maxPatchIndexes = Math.max(prevArray.length / 5, 1)\n\t\tconst toPatchIndexes = []\n\t\tfor (let i = 0; i < prevArray.length; i++) {\n\t\t\tif (!isEqual(prevArray[i], nextArray[i])) {\n\t\t\t\ttoPatchIndexes.push(i)\n\t\t\t\tif (toPatchIndexes.length > maxPatchIndexes) {\n\t\t\t\t\treturn [ValueOpType.Put, nextArray]\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif (toPatchIndexes.length === 0) {\n\t\t\t// same length and no items changed, so no diff\n\t\t\treturn null\n\t\t}\n\t\tconst diff: ObjectDiff = {}\n\t\tfor (const i of toPatchIndexes) {\n\t\t\tconst prevItem = prevArray[i]\n\t\t\tconst nextItem = nextArray[i]\n\t\t\tif (!prevItem || !nextItem) {\n\t\t\t\tdiff[i] = [ValueOpType.Put, nextItem]\n\t\t\t} else if (typeof prevItem === 'object' && typeof nextItem === 'object') {\n\t\t\t\tconst op = diffValue(prevItem, nextItem)\n\t\t\t\tif (op) {\n\t\t\t\t\tdiff[i] = op\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tdiff[i] = [ValueOpType.Put, nextItem]\n\t\t\t}\n\t\t}\n\t\treturn [ValueOpType.Patch, diff]\n\t}\n\n\t// if lengths are not equal, check for append operation, and bail out\n\t// to replace whole array if any shared elems changed\n\tfor (let i = 0; i < prevArray.length; i++) {\n\t\tif (!isEqual(prevArray[i], nextArray[i])) {\n\t\t\treturn [ValueOpType.Put, nextArray]\n\t\t}\n\t}\n\n\treturn [ValueOpType.Append, nextArray.slice(prevArray.length), prevArray.length]\n}\n\n/** @internal */\nexport function applyObjectDiff(object: T, objectDiff: ObjectDiff): T {\n\t// don't patch nulls\n\tif (!object || typeof object !== 'object') return object\n\tconst isArray = Array.isArray(object)\n\tlet newObject: any | undefined = undefined\n\tconst set = (k: any, v: any) => {\n\t\tif (!newObject) {\n\t\t\tif (isArray) {\n\t\t\t\tnewObject = [...object]\n\t\t\t} else {\n\t\t\t\tnewObject = { ...object }\n\t\t\t}\n\t\t}\n\t\tif (isArray) {\n\t\t\tnewObject[Number(k)] = v\n\t\t} else {\n\t\t\tnewObject[k] = v\n\t\t}\n\t}\n\tfor (const [key, op] of Object.entries(objectDiff)) {\n\t\tswitch (op[0]) {\n\t\t\tcase ValueOpType.Put: {\n\t\t\t\tconst value = op[1]\n\t\t\t\tif (!isEqual(object[key as keyof T], value)) {\n\t\t\t\t\tset(key, value)\n\t\t\t\t}\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tcase ValueOpType.Append: {\n\t\t\t\tconst values = op[1]\n\t\t\t\tconst offset = op[2]\n\t\t\t\tconst arr = object[key as keyof T]\n\t\t\t\tif (Array.isArray(arr) && arr.length === offset) {\n\t\t\t\t\tset(key, [...arr, ...values])\n\t\t\t\t}\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tcase ValueOpType.Patch: {\n\t\t\t\tif (object[key as keyof T] && typeof object[key as keyof T] === 'object') {\n\t\t\t\t\tconst diff = op[1]\n\t\t\t\t\tconst patched = applyObjectDiff(object[key as keyof T] as object, diff)\n\t\t\t\t\tif (patched !== object[key as keyof T]) {\n\t\t\t\t\t\tset(key, patched)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tcase ValueOpType.Delete: {\n\t\t\t\tif (key in object) {\n\t\t\t\t\tif (!newObject) {\n\t\t\t\t\t\tif (isArray) {\n\t\t\t\t\t\t\tconsole.error(\"Can't delete array item yet (this should never happen)\")\n\t\t\t\t\t\t\tnewObject = [...object]\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tnewObject = { ...object }\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tdelete newObject[key]\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn newObject ?? object\n}\n", "export function interval(cb: () => void, timeout: number) {\n\tconst i = setInterval(cb, timeout)\n\treturn () => clearInterval(i)\n}\n", "import { SerializedSchema, UnknownRecord } from '@tldraw/store'\nimport { NetworkDiff, ObjectDiff, RecordOpType } from './diff'\n\nconst TLSYNC_PROTOCOL_VERSION = 6\n\n/** @internal */\nexport function getTlsyncProtocolVersion() {\n\treturn TLSYNC_PROTOCOL_VERSION\n}\n\n/** @internal */\nexport const TLIncompatibilityReason = {\n\tClientTooOld: 'clientTooOld',\n\tServerTooOld: 'serverTooOld',\n\tInvalidRecord: 'invalidRecord',\n\tInvalidOperation: 'invalidOperation',\n\tRoomNotFound: 'roomNotFound',\n} as const\n\n/** @internal */\nexport type TLIncompatibilityReason =\n\t(typeof TLIncompatibilityReason)[keyof typeof TLIncompatibilityReason]\n\n/** @internal */\nexport type TLSocketServerSentEvent =\n\t| {\n\t\t\ttype: 'connect'\n\t\t\thydrationType: 'wipe_all' | 'wipe_presence'\n\t\t\tconnectRequestId: string\n\t\t\tprotocolVersion: number\n\t\t\tschema: SerializedSchema\n\t\t\tdiff: NetworkDiff\n\t\t\tserverClock: number\n\t }\n\t| {\n\t\t\ttype: 'incompatibility_error'\n\t\t\treason: TLIncompatibilityReason\n\t }\n\t| {\n\t\t\ttype: 'error'\n\t\t\terror?: any\n\t }\n\t| {\n\t\t\ttype: 'pong'\n\t }\n\t| { type: 'data'; data: TLSocketServerSentDataEvent[] }\n\t| TLSocketServerSentDataEvent\n\n/** @internal */\nexport type TLSocketServerSentDataEvent =\n\t| {\n\t\t\ttype: 'patch'\n\t\t\tdiff: NetworkDiff\n\t\t\tserverClock: number\n\t }\n\t| {\n\t\t\ttype: 'push_result'\n\t\t\tclientClock: number\n\t\t\tserverClock: number\n\t\t\taction: 'discard' | 'commit' | { rebaseWithDiff: NetworkDiff }\n\t }\n\n/** @internal */\nexport interface TLPushRequest {\n\ttype: 'push'\n\tclientClock: number\n\tdiff?: NetworkDiff\n\tpresence?: [typeof RecordOpType.Patch, ObjectDiff] | [typeof RecordOpType.Put, R]\n}\n\n/** @internal */\nexport interface TLConnectRequest {\n\ttype: 'connect'\n\tconnectRequestId: string\n\tlastServerClock: number\n\tprotocolVersion: number\n\tschema: SerializedSchema\n}\n\n/** @internal */\nexport interface TLPingRequest {\n\ttype: 'ping'\n}\n\n/** @internal */\nexport type TLSocketClientSentEvent =\n\t| TLPushRequest\n\t| TLConnectRequest\n\t| TLPingRequest\n", "import { SerializedSchema, UnknownRecord } from '@tldraw/store'\nimport { TLRoomSocket } from './TLSyncRoom'\nimport { TLSocketServerSentDataEvent } from './protocol'\n\n/** @internal */\nexport const RoomSessionState = {\n\tAwaitingConnectMessage: 'awaiting-connect-message',\n\tAwaitingRemoval: 'awaiting-removal',\n\tConnected: 'connected',\n} as const\n\n/** @internal */\nexport type RoomSessionState = (typeof RoomSessionState)[keyof typeof RoomSessionState]\n\nexport const SESSION_START_WAIT_TIME = 10000\nexport const SESSION_REMOVAL_WAIT_TIME = 10000\nexport const SESSION_IDLE_TIMEOUT = 20000\n\n/** @internal */\nexport type RoomSession =\n\t| {\n\t\t\tstate: typeof RoomSessionState.AwaitingConnectMessage\n\t\t\tsessionId: string\n\t\t\tpresenceId: string\n\t\t\tsocket: TLRoomSocket\n\t\t\tsessionStartTime: number\n\t\t\tmeta: Meta\n\t }\n\t| {\n\t\t\tstate: typeof RoomSessionState.AwaitingRemoval\n\t\t\tsessionId: string\n\t\t\tpresenceId: string\n\t\t\tsocket: TLRoomSocket\n\t\t\tcancellationTime: number\n\t\t\tmeta: Meta\n\t }\n\t| {\n\t\t\tstate: typeof RoomSessionState.Connected\n\t\t\tsessionId: string\n\t\t\tpresenceId: string\n\t\t\tsocket: TLRoomSocket\n\t\t\tserializedSchema: SerializedSchema\n\t\t\tlastInteractionTime: number\n\t\t\tdebounceTimer: ReturnType | null\n\t\t\toutstandingDataMessages: TLSocketServerSentDataEvent[]\n\t\t\tmeta: Meta\n\t }\n", "import { TLIncompatibilityReason } from './protocol'\n\n/** @internal */\nexport class TLRemoteSyncError extends Error {\n\toverride name = 'RemoteSyncError'\n\tconstructor(public readonly reason: TLIncompatibilityReason) {\n\t\tsuper(`remote sync error: ${reason}`)\n\t}\n}\n", "import type { StoreSchema, UnknownRecord } from '@tldraw/store'\nimport { TLStoreSnapshot, createTLSchema } from '@tldraw/tlschema'\nimport { objectMapValues } from '@tldraw/utils'\nimport { ServerSocketAdapter, WebSocketMinimal } from './ServerSocketAdapter'\nimport { RoomSnapshot, TLSyncRoom } from './TLSyncRoom'\nimport { JsonChunkAssembler } from './chunk'\nimport { TLSocketServerSentEvent } from './protocol'\n\n// TODO: structured logging support\n/** @public */\nexport interface TLSyncLog {\n\twarn?: (...args: any[]) => void\n\terror?: (...args: any[]) => void\n}\n\n/** @public */\nexport class TLSocketRoom {\n\tprivate room: TLSyncRoom\n\tprivate readonly sessions = new Map<\n\t\tstring,\n\t\t{ assembler: JsonChunkAssembler; socket: WebSocketMinimal; unlisten: () => void }\n\t>()\n\treadonly log?: TLSyncLog\n\n\tconstructor(\n\t\tpublic readonly opts: {\n\t\t\tinitialSnapshot?: RoomSnapshot | TLStoreSnapshot\n\t\t\tschema?: StoreSchema\n\t\t\t// how long to wait for a client to communicate before disconnecting them\n\t\t\tclientTimeout?: number\n\t\t\tlog?: TLSyncLog\n\t\t\t// a callback that is called when a client is disconnected\n\t\t\tonSessionRemoved?: (\n\t\t\t\troom: TLSocketRoom,\n\t\t\t\targs: { sessionId: string; numSessionsRemaining: number; meta: SessionMeta }\n\t\t\t) => void\n\t\t\t// a callback that is called whenever a message is sent\n\t\t\tonBeforeSendMessage?: (args: {\n\t\t\t\tsessionId: string\n\t\t\t\t/** @internal keep the protocol private for now */\n\t\t\t\tmessage: TLSocketServerSentEvent\n\t\t\t\tstringified: string\n\t\t\t\tmeta: SessionMeta\n\t\t\t}) => void\n\t\t\tonAfterReceiveMessage?: (args: {\n\t\t\t\tsessionId: string\n\t\t\t\t/** @internal keep the protocol private for now */\n\t\t\t\tmessage: TLSocketServerSentEvent\n\t\t\t\tstringified: string\n\t\t\t\tmeta: SessionMeta\n\t\t\t}) => void\n\t\t\tonDataChange?: () => void\n\t\t}\n\t) {\n\t\tconst initialSnapshot =\n\t\t\topts.initialSnapshot && 'store' in opts.initialSnapshot\n\t\t\t\t? convertStoreSnapshotToRoomSnapshot(opts.initialSnapshot!)\n\t\t\t\t: opts.initialSnapshot\n\n\t\tconst initialClock = initialSnapshot?.clock ?? 0\n\t\tthis.room = new TLSyncRoom({\n\t\t\tschema: opts.schema ?? (createTLSchema() as any),\n\t\t\tsnapshot: initialSnapshot,\n\t\t\tlog: opts.log,\n\t\t})\n\t\tif (this.room.clock !== initialClock) {\n\t\t\tthis.opts?.onDataChange?.()\n\t\t}\n\t\tthis.room.events.on('session_removed', (args) => {\n\t\t\tthis.sessions.delete(args.sessionId)\n\t\t\tif (this.opts.onSessionRemoved) {\n\t\t\t\tthis.opts.onSessionRemoved(this, {\n\t\t\t\t\tsessionId: args.sessionId,\n\t\t\t\t\tnumSessionsRemaining: this.room.sessions.size,\n\t\t\t\t\tmeta: args.meta,\n\t\t\t\t})\n\t\t\t}\n\t\t})\n\t\tthis.log = 'log' in opts ? opts.log : { error: console.error }\n\t}\n\n\t/**\n\t * Returns the number of active sessions.\n\t * Note that this is not the same as the number of connected sockets!\n\t * Sessions time out a few moments after sockets close, to smooth over network hiccups.\n\t *\n\t * @returns the number of active sessions\n\t */\n\tgetNumActiveSessions() {\n\t\treturn this.room.sessions.size\n\t}\n\n\t/**\n\t * Call this when a client establishes a new socket connection.\n\t *\n\t * - `sessionId` is a unique ID for a browser tab. This is passed as a query param by the useSync hook.\n\t * - `socket` is a WebSocket-like object that the server uses to communicate with the client.\n\t * - `meta` is an optional object that can be used to store additional information about the session.\n\t *\n\t * @param opts - The options object\n\t */\n\thandleSocketConnect(\n\t\topts: OmitVoid<{ sessionId: string; socket: WebSocketMinimal; meta: SessionMeta }>\n\t) {\n\t\tconst { sessionId, socket } = opts\n\t\tconst handleSocketMessage = (event: MessageEvent) =>\n\t\t\tthis.handleSocketMessage(sessionId, event.data)\n\t\tconst handleSocketError = this.handleSocketError.bind(this, sessionId)\n\t\tconst handleSocketClose = this.handleSocketClose.bind(this, sessionId)\n\n\t\tthis.sessions.set(sessionId, {\n\t\t\tassembler: new JsonChunkAssembler(),\n\t\t\tsocket,\n\t\t\tunlisten: () => {\n\t\t\t\tsocket.removeEventListener?.('message', handleSocketMessage)\n\t\t\t\tsocket.removeEventListener?.('close', handleSocketClose)\n\t\t\t\tsocket.removeEventListener?.('error', handleSocketError)\n\t\t\t},\n\t\t})\n\n\t\tthis.room.handleNewSession(\n\t\t\tsessionId,\n\t\t\tnew ServerSocketAdapter({\n\t\t\t\tws: socket,\n\t\t\t\tonBeforeSendMessage: this.opts.onBeforeSendMessage\n\t\t\t\t\t? (message, stringified) =>\n\t\t\t\t\t\t\tthis.opts.onBeforeSendMessage!({\n\t\t\t\t\t\t\t\tsessionId,\n\t\t\t\t\t\t\t\tmessage,\n\t\t\t\t\t\t\t\tstringified,\n\t\t\t\t\t\t\t\tmeta: this.room.sessions.get(sessionId)?.meta as SessionMeta,\n\t\t\t\t\t\t\t})\n\t\t\t\t\t: undefined,\n\t\t\t}),\n\t\t\t'meta' in opts ? (opts.meta as any) : undefined\n\t\t)\n\n\t\tsocket.addEventListener?.('message', handleSocketMessage)\n\t\tsocket.addEventListener?.('close', handleSocketClose)\n\t\tsocket.addEventListener?.('error', handleSocketError)\n\t}\n\n\t/**\n\t * If executing in a server environment where sockets do not have instance-level listeners\n\t * (e.g. Bun.serve, Cloudflare Worker with WebSocket hibernation), you should call this\n\t * method when messages are received. See our self-hosting example for Bun.serve for an example.\n\t *\n\t * @param sessionId - The id of the session. (should match the one used when calling handleSocketConnect)\n\t * @param message - The message received from the client.\n\t */\n\thandleSocketMessage(sessionId: string, message: string | AllowSharedBufferSource) {\n\t\tconst documentClockAtStart = this.room.documentClock\n\t\tconst assembler = this.sessions.get(sessionId)?.assembler\n\t\tif (!assembler) {\n\t\t\tthis.log?.warn?.('Received message from unknown session', sessionId)\n\t\t\treturn\n\t\t}\n\n\t\ttry {\n\t\t\tconst messageString =\n\t\t\t\ttypeof message === 'string' ? message : new TextDecoder().decode(message)\n\t\t\tconst res = assembler.handleMessage(messageString)\n\t\t\tif (!res) {\n\t\t\t\t// not enough chunks yet\n\t\t\t\treturn\n\t\t\t}\n\t\t\tif ('data' in res) {\n\t\t\t\t// need to do this first in case the session gets removed as a result of handling the message\n\t\t\t\tif (this.opts.onAfterReceiveMessage) {\n\t\t\t\t\tconst session = this.room.sessions.get(sessionId)\n\t\t\t\t\tif (session) {\n\t\t\t\t\t\tthis.opts.onAfterReceiveMessage({\n\t\t\t\t\t\t\tsessionId,\n\t\t\t\t\t\t\tmessage: res.data as any,\n\t\t\t\t\t\t\tstringified: res.stringified,\n\t\t\t\t\t\t\tmeta: session.meta,\n\t\t\t\t\t\t})\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tthis.room.handleMessage(sessionId, res.data as any)\n\t\t\t} else {\n\t\t\t\tthis.log?.error?.('Error assembling message', res.error)\n\t\t\t\t// close the socket to reset the connection\n\t\t\t\tthis.handleSocketError(sessionId)\n\t\t\t}\n\t\t} catch (e) {\n\t\t\tthis.log?.error?.(e)\n\t\t\tconst socket = this.sessions.get(sessionId)?.socket\n\t\t\tif (socket) {\n\t\t\t\tsocket.send(\n\t\t\t\t\tJSON.stringify({\n\t\t\t\t\t\ttype: 'error',\n\t\t\t\t\t\terror: typeof e?.toString === 'function' ? e.toString() : e,\n\t\t\t\t\t} satisfies TLSocketServerSentEvent)\n\t\t\t\t)\n\t\t\t\tsocket.close()\n\t\t\t}\n\t\t} finally {\n\t\t\tif (this.room.documentClock !== documentClockAtStart) {\n\t\t\t\tthis.opts.onDataChange?.()\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * If executing in a server environment where sockets do not have instance-level listeners,\n\t * call this when a socket error occurs.\n\t * @param sessionId - The id of the session. (should match the one used when calling handleSocketConnect)\n\t */\n\thandleSocketError(sessionId: string) {\n\t\tthis.room.handleClose(sessionId)\n\t}\n\n\t/**\n\t * If executing in a server environment where sockets do not have instance-level listeners,\n\t * call this when a socket is closed.\n\t * @param sessionId - The id of the session. (should match the one used when calling handleSocketConnect)\n\t */\n\thandleSocketClose(sessionId: string) {\n\t\tthis.room.handleClose(sessionId)\n\t}\n\n\t/**\n\t * Returns the current 'clock' of the document.\n\t * The clock is an integer that increments every time the document changes.\n\t * The clock is stored as part of the snapshot of the document for consistency purposes.\n\t *\n\t * @returns The clock\n\t */\n\tgetCurrentDocumentClock() {\n\t\treturn this.room.documentClock\n\t}\n\n\t/**\n\t * Return a snapshot of the document state, including clock-related bookkeeping.\n\t * You can store this and load it later on when initializing a TLSocketRoom.\n\t * You can also pass a snapshot to {@link TLSocketRoom#loadSnapshot} if you need to revert to a previous state.\n\t * @returns The snapshot\n\t */\n\tgetCurrentSnapshot() {\n\t\treturn this.room.getSnapshot()\n\t}\n\n\t/**\n\t * Load a snapshot of the document state, overwriting the current state.\n\t * @param snapshot - The snapshot to load\n\t */\n\tloadSnapshot(snapshot: RoomSnapshot | TLStoreSnapshot) {\n\t\tif ('store' in snapshot) {\n\t\t\tsnapshot = convertStoreSnapshotToRoomSnapshot(snapshot)\n\t\t}\n\t\tconst oldRoom = this.room\n\t\tconst oldIds = oldRoom.getSnapshot().documents.map((d) => d.state.id)\n\t\tconst newIds = new Set(snapshot.documents.map((d) => d.state.id))\n\t\tconst removedIds = oldIds.filter((id) => !newIds.has(id))\n\n\t\tconst tombstones = { ...snapshot.tombstones }\n\t\tremovedIds.forEach((id) => {\n\t\t\ttombstones[id] = oldRoom.clock + 1\n\t\t})\n\t\tnewIds.forEach((id) => {\n\t\t\tdelete tombstones[id]\n\t\t})\n\n\t\tconst newRoom = new TLSyncRoom({\n\t\t\tschema: oldRoom.schema,\n\t\t\tsnapshot: {\n\t\t\t\tclock: oldRoom.clock + 1,\n\t\t\t\tdocuments: snapshot.documents.map((d) => ({\n\t\t\t\t\tlastChangedClock: oldRoom.clock + 1,\n\t\t\t\t\tstate: d.state,\n\t\t\t\t})),\n\t\t\t\tschema: snapshot.schema,\n\t\t\t\ttombstones,\n\t\t\t},\n\t\t\tlog: this.log,\n\t\t})\n\n\t\t// replace room with new one and kick out all the clients\n\t\tthis.room = newRoom\n\t\toldRoom.close()\n\t}\n\n\t/**\n\t * Close the room and disconnect all clients. Call this before discarding the room instance or shutting down the server.\n\t */\n\tclose() {\n\t\tthis.room.close()\n\t}\n\n\t/**\n\t * @returns true if the room is closed\n\t */\n\tisClosed() {\n\t\treturn this.room.isClosed()\n\t}\n}\n\n/** @public */\nexport type OmitVoid = {\n\t[K in KS extends any ? (void extends T[KS] ? never : KS) : never]: T[K]\n}\n\nfunction convertStoreSnapshotToRoomSnapshot(snapshot: TLStoreSnapshot): RoomSnapshot {\n\treturn {\n\t\tclock: 0,\n\t\tdocuments: objectMapValues(snapshot.store).map((state) => ({\n\t\t\tstate,\n\t\t\tlastChangedClock: 0,\n\t\t})),\n\t\tschema: snapshot.schema,\n\t\ttombstones: {},\n\t}\n}\n", "export {\n\ttype TLAssetContext,\n\ttype TLAssetStore,\n\ttype TLSerializedStore,\n\ttype TLStore,\n\ttype TLStoreProps,\n\ttype TLStoreSchema,\n\ttype TLStoreSnapshot,\n} from './TLStore'\nexport { assetIdValidator, createAssetValidator, type TLBaseAsset } from './assets/TLBaseAsset'\nexport { type TLBookmarkAsset } from './assets/TLBookmarkAsset'\nexport { type TLImageAsset } from './assets/TLImageAsset'\nexport { type TLVideoAsset } from './assets/TLVideoAsset'\nexport {\n\tarrowBindingMigrations,\n\tarrowBindingProps,\n\ttype TLArrowBinding,\n\ttype TLArrowBindingProps,\n} from './bindings/TLArrowBinding'\nexport {\n\tbindingIdValidator,\n\tcreateBindingValidator,\n\ttype TLBaseBinding,\n} from './bindings/TLBaseBinding'\nexport { createPresenceStateDerivation } from './createPresenceStateDerivation'\nexport {\n\tcreateTLSchema,\n\tdefaultBindingSchemas,\n\tdefaultShapeSchemas,\n\ttype SchemaPropsInfo,\n\ttype TLSchema,\n} from './createTLSchema'\nexport {\n\tTL_CANVAS_UI_COLOR_TYPES,\n\tcanvasUiColorTypeValidator,\n\ttype TLCanvasUiColor,\n} from './misc/TLColor'\nexport { TL_CURSOR_TYPES, type TLCursor, type TLCursorType } from './misc/TLCursor'\nexport { TL_HANDLE_TYPES, type TLHandle, type TLHandleType } from './misc/TLHandle'\nexport { opacityValidator, type TLOpacityType } from './misc/TLOpacity'\nexport { TL_SCRIBBLE_STATES, scribbleValidator, type TLScribble } from './misc/TLScribble'\nexport {\n\tboxModelValidator,\n\tvecModelValidator,\n\ttype BoxModel,\n\ttype VecModel,\n} from './misc/geometry-types'\nexport { idValidator } from './misc/id-validator'\nexport {\n\tAssetRecordType,\n\tassetMigrations,\n\tassetValidator,\n\ttype TLAsset,\n\ttype TLAssetId,\n\ttype TLAssetPartial,\n\ttype TLAssetShape,\n} from './records/TLAsset'\nexport {\n\tcreateBindingId,\n\tcreateBindingPropsMigrationIds,\n\tcreateBindingPropsMigrationSequence,\n\tisBinding,\n\tisBindingId,\n\trootBindingMigrations,\n\ttype TLBinding,\n\ttype TLBindingCreate,\n\ttype TLBindingId,\n\ttype TLBindingUpdate,\n\ttype TLDefaultBinding,\n\ttype TLUnknownBinding,\n} from './records/TLBinding'\nexport { CameraRecordType, type TLCamera, type TLCameraId } from './records/TLCamera'\nexport { DocumentRecordType, TLDOCUMENT_ID, type TLDocument } from './records/TLDocument'\nexport {\n\tTLINSTANCE_ID,\n\tpluckPreservingValues,\n\ttype TLInstance,\n\ttype TLInstanceId,\n} from './records/TLInstance'\nexport {\n\tPageRecordType,\n\tisPageId,\n\tpageIdValidator,\n\ttype TLPage,\n\ttype TLPageId,\n} from './records/TLPage'\nexport {\n\tInstancePageStateRecordType,\n\ttype TLInstancePageState,\n\ttype TLInstancePageStateId,\n} from './records/TLPageState'\nexport {\n\tPointerRecordType,\n\tTLPOINTER_ID,\n\ttype TLPointer,\n\ttype TLPointerId,\n} from './records/TLPointer'\nexport {\n\tInstancePresenceRecordType,\n\ttype TLInstancePresence,\n\ttype TLInstancePresenceID,\n} from './records/TLPresence'\nexport { type TLRecord } from './records/TLRecord'\nexport {\n\tcreateShapeId,\n\tcreateShapePropsMigrationIds,\n\tcreateShapePropsMigrationSequence,\n\tgetShapePropKeysByStyle,\n\tisShape,\n\tisShapeId,\n\trootShapeMigrations,\n\ttype TLDefaultShape,\n\ttype TLParentId,\n\ttype TLShape,\n\ttype TLShapeId,\n\ttype TLShapePartial,\n\ttype TLUnknownShape,\n} from './records/TLShape'\nexport {\n\ttype RecordProps,\n\ttype RecordPropsType,\n\ttype TLPropsMigration,\n\ttype TLPropsMigrations,\n} from './recordsWithProps'\nexport {\n\tArrowShapeArrowheadEndStyle,\n\tArrowShapeArrowheadStartStyle,\n\tarrowShapeMigrations,\n\tarrowShapeProps,\n\ttype TLArrowShape,\n\ttype TLArrowShapeArrowheadStyle,\n\ttype TLArrowShapeProps,\n} from './shapes/TLArrowShape'\nexport {\n\tcreateShapeValidator,\n\tparentIdValidator,\n\tshapeIdValidator,\n\ttype TLBaseShape,\n} from './shapes/TLBaseShape'\nexport {\n\tbookmarkShapeMigrations,\n\tbookmarkShapeProps,\n\ttype TLBookmarkShape,\n\ttype TLBookmarkShapeProps,\n} from './shapes/TLBookmarkShape'\nexport {\n\tdrawShapeMigrations,\n\tdrawShapeProps,\n\ttype TLDrawShape,\n\ttype TLDrawShapeProps,\n\ttype TLDrawShapeSegment,\n} from './shapes/TLDrawShape'\nexport {\n\tEMBED_DEFINITIONS,\n\tembedShapeMigrations,\n\tembedShapePermissionDefaults,\n\tembedShapeProps,\n\ttype EmbedDefinition,\n\ttype TLEmbedShape,\n\ttype TLEmbedShapePermissions,\n\ttype TLEmbedShapeProps,\n} from './shapes/TLEmbedShape'\nexport {\n\tframeShapeMigrations,\n\tframeShapeProps,\n\ttype TLFrameShape,\n\ttype TLFrameShapeProps,\n} from './shapes/TLFrameShape'\nexport {\n\tGeoShapeGeoStyle,\n\tgeoShapeMigrations,\n\tgeoShapeProps,\n\ttype TLGeoShape,\n\ttype TLGeoShapeGeoStyle,\n\ttype TLGeoShapeProps,\n} from './shapes/TLGeoShape'\nexport {\n\tgroupShapeMigrations,\n\tgroupShapeProps,\n\ttype TLGroupShape,\n\ttype TLGroupShapeProps,\n} from './shapes/TLGroupShape'\nexport {\n\thighlightShapeMigrations,\n\thighlightShapeProps,\n\ttype TLHighlightShape,\n\ttype TLHighlightShapeProps,\n} from './shapes/TLHighlightShape'\nexport {\n\tImageShapeCrop,\n\timageShapeMigrations,\n\timageShapeProps,\n\ttype TLImageShape,\n\ttype TLImageShapeCrop,\n\ttype TLImageShapeProps,\n} from './shapes/TLImageShape'\nexport {\n\tLineShapeSplineStyle,\n\tlineShapeMigrations,\n\tlineShapeProps,\n\ttype TLLineShape,\n\ttype TLLineShapePoint,\n\ttype TLLineShapeProps,\n\ttype TLLineShapeSplineStyle,\n} from './shapes/TLLineShape'\nexport {\n\tnoteShapeMigrations,\n\tnoteShapeProps,\n\ttype TLNoteShape,\n\ttype TLNoteShapeProps,\n} from './shapes/TLNoteShape'\nexport {\n\ttextShapeMigrations,\n\ttextShapeProps,\n\ttype TLTextShape,\n\ttype TLTextShapeProps,\n} from './shapes/TLTextShape'\nexport {\n\tvideoShapeMigrations,\n\tvideoShapeProps,\n\ttype TLVideoShape,\n\ttype TLVideoShapeProps,\n} from './shapes/TLVideoShape'\nexport { EnumStyleProp, StyleProp, type StylePropValue } from './styles/StyleProp'\nexport {\n\tDefaultColorStyle,\n\tDefaultColorThemePalette,\n\tdefaultColorNames,\n\tgetDefaultColorTheme,\n\ttype TLDefaultColorStyle,\n\ttype TLDefaultColorTheme,\n\ttype TLDefaultColorThemeColor,\n} from './styles/TLColorStyle'\nexport { DefaultDashStyle, type TLDefaultDashStyle } from './styles/TLDashStyle'\nexport { DefaultFillStyle, type TLDefaultFillStyle } from './styles/TLFillStyle'\nexport {\n\tDefaultFontFamilies,\n\tDefaultFontStyle,\n\ttype TLDefaultFontStyle,\n} from './styles/TLFontStyle'\nexport {\n\tDefaultHorizontalAlignStyle,\n\ttype TLDefaultHorizontalAlignStyle,\n} from './styles/TLHorizontalAlignStyle'\nexport { DefaultSizeStyle, type TLDefaultSizeStyle } from './styles/TLSizeStyle'\nexport { DefaultTextAlignStyle, type TLDefaultTextAlignStyle } from './styles/TLTextAlignStyle'\nexport {\n\tDefaultVerticalAlignStyle,\n\ttype TLDefaultVerticalAlignStyle,\n} from './styles/TLVerticalAlignStyle'\nexport {\n\tLANGUAGES,\n\tgetDefaultTranslationLocale,\n\ttype TLLanguage,\n} from './translations/translations'\nexport { type SetValue } from './util-types'\n", "import { BaseRecord } from '@tldraw/store'\nimport { JsonObject } from '@tldraw/utils'\nimport { T } from '@tldraw/validate'\nimport { idValidator } from '../misc/id-validator'\nimport { TLAssetId } from '../records/TLAsset'\n\n/** @public */\nexport interface TLBaseAsset extends BaseRecord<'asset', TLAssetId> {\n\ttype: Type\n\tprops: Props\n\tmeta: JsonObject\n}\n\n/**\n * A validator for asset record type Ids.\n *\n * @public */\nexport const assetIdValidator = idValidator('asset')\n\n/**\n * Create a validator for an asset record type.\n *\n * @param type - The type of the asset\n * @param props - The validator for the asset's props\n *\n * @public */\nexport function createAssetValidator(\n\ttype: Type,\n\tprops: T.Validator\n) {\n\treturn T.object<{\n\t\tid: TLAssetId\n\t\ttypeName: 'asset'\n\t\ttype: Type\n\t\tprops: Props\n\t\tmeta: JsonObject\n\t}>({\n\t\tid: assetIdValidator,\n\t\ttypeName: T.literal('asset'),\n\t\ttype: T.literal(type),\n\t\tprops,\n\t\tmeta: T.jsonValue as T.ObjectValidator,\n\t})\n}\n", "import * as T from './lib/validation'\n\nexport {\n\tArrayOfValidator,\n\tDictValidator,\n\tObjectValidator,\n\tUnionValidator,\n\tValidator,\n\ttype ExtractOptionalKeys,\n\ttype ExtractRequiredKeys,\n\ttype UnionValidatorConfig,\n} from './lib/validation'\nexport { T }\n", "import {\n\tExpand,\n\tIndexKey,\n\tJsonValue,\n\tSTRUCTURED_CLONE_OBJECT_PROTOTYPE,\n\texhaustiveSwitchError,\n\tgetOwnProperty,\n\thasOwnProperty,\n\tvalidateIndexKey,\n} from '@tldraw/utils'\n\n/** @public */\nexport type ValidatorFn = (value: unknown) => T\n/** @public */\nexport type ValidatorUsingKnownGoodVersionFn = (\n\tknownGoodValue: In,\n\tvalue: unknown\n) => Out\n\n/** @public */\nexport interface Validatable {\n\tvalidate: (value: unknown) => T\n\t/**\n\t * This is a performance optimizing version of validate that can use a previous\n\t * version of the value to avoid revalidating every part of the new value if\n\t * any part of it has not changed since the last validation.\n\t *\n\t * If the value has not changed but is not referentially equal, the function\n\t * should return the previous value.\n\t * @returns\n\t */\n\tvalidateUsingKnownGoodVersion?: (knownGoodValue: T, newValue: unknown) => T\n}\n\nfunction formatPath(path: ReadonlyArray): string | null {\n\tif (!path.length) {\n\t\treturn null\n\t}\n\n\tlet formattedPath = ''\n\tfor (const item of path) {\n\t\tif (typeof item === 'number') {\n\t\t\tformattedPath += `.${item}`\n\t\t} else if (item.startsWith('(')) {\n\t\t\tif (formattedPath.endsWith(')')) {\n\t\t\t\tformattedPath = `${formattedPath.slice(0, -1)}, ${item.slice(1)}`\n\t\t\t} else {\n\t\t\t\tformattedPath += item\n\t\t\t}\n\t\t} else {\n\t\t\tformattedPath += `.${item}`\n\t\t}\n\t}\n\n\t// N.B. We don't want id's in the path because they make grouping in Sentry tough.\n\tformattedPath = formattedPath.replace(/id = [^,]+, /, '').replace(/id = [^)]+/, '')\n\n\tif (formattedPath.startsWith('.')) {\n\t\treturn formattedPath.slice(1)\n\t}\n\treturn formattedPath\n}\n\n/** @public */\nexport class ValidationError extends Error {\n\toverride name = 'ValidationError'\n\n\tconstructor(\n\t\tpublic readonly rawMessage: string,\n\t\tpublic readonly path: ReadonlyArray = []\n\t) {\n\t\tconst formattedPath = formatPath(path)\n\t\tconst indentedMessage = rawMessage\n\t\t\t.split('\\n')\n\t\t\t.map((line, i) => (i === 0 ? line : ` ${line}`))\n\t\t\t.join('\\n')\n\t\tsuper(path ? `At ${formattedPath}: ${indentedMessage}` : indentedMessage)\n\t}\n}\n\nfunction prefixError(path: string | number, fn: () => T): T {\n\ttry {\n\t\treturn fn()\n\t} catch (err) {\n\t\tif (err instanceof ValidationError) {\n\t\t\tthrow new ValidationError(err.rawMessage, [path, ...err.path])\n\t\t}\n\t\tthrow new ValidationError((err as Error).toString(), [path])\n\t}\n}\n\nfunction typeToString(value: unknown): string {\n\tif (value === null) return 'null'\n\tif (Array.isArray(value)) return 'an array'\n\tconst type = typeof value\n\tswitch (type) {\n\t\tcase 'bigint':\n\t\tcase 'boolean':\n\t\tcase 'function':\n\t\tcase 'number':\n\t\tcase 'string':\n\t\tcase 'symbol':\n\t\t\treturn `a ${type}`\n\t\tcase 'object':\n\t\t\treturn `an ${type}`\n\t\tcase 'undefined':\n\t\t\treturn 'undefined'\n\t\tdefault:\n\t\t\texhaustiveSwitchError(type)\n\t}\n}\n\n/** @public */\nexport type TypeOf> = V extends Validatable ? T : never\n\n/** @public */\nexport class Validator implements Validatable {\n\tconstructor(\n\t\treadonly validationFn: ValidatorFn,\n\t\treadonly validateUsingKnownGoodVersionFn?: ValidatorUsingKnownGoodVersionFn\n\t) {}\n\n\t/**\n\t * Asserts that the passed value is of the correct type and returns it. The returned value is\n\t * guaranteed to be referentially equal to the passed value.\n\t */\n\tvalidate(value: unknown): T {\n\t\tconst validated = this.validationFn(value)\n\t\tif (process.env.NODE_ENV !== 'production' && !Object.is(value, validated)) {\n\t\t\tthrow new ValidationError('Validator functions must return the same value they were passed')\n\t\t}\n\t\treturn validated\n\t}\n\n\tvalidateUsingKnownGoodVersion(knownGoodValue: T, newValue: unknown): T {\n\t\tif (Object.is(knownGoodValue, newValue)) {\n\t\t\treturn knownGoodValue as T\n\t\t}\n\n\t\tif (this.validateUsingKnownGoodVersionFn) {\n\t\t\treturn this.validateUsingKnownGoodVersionFn(knownGoodValue, newValue)\n\t\t}\n\n\t\treturn this.validate(newValue)\n\t}\n\n\t/** Checks that the passed value is of the correct type. */\n\tisValid(value: unknown): value is T {\n\t\ttry {\n\t\t\tthis.validate(value)\n\t\t\treturn true\n\t\t} catch {\n\t\t\treturn false\n\t\t}\n\t}\n\n\t/**\n\t * Returns a new validator that also accepts null or undefined. The resulting value will always be\n\t * null.\n\t */\n\tnullable(): Validator {\n\t\treturn nullable(this)\n\t}\n\n\t/**\n\t * Returns a new validator that also accepts null or undefined. The resulting value will always be\n\t * null.\n\t */\n\toptional(): Validator {\n\t\treturn optional(this)\n\t}\n\n\t/**\n\t * Refine this validation to a new type. The passed-in validation function should throw an error\n\t * if the value can't be converted to the new type, or return the new type otherwise.\n\t */\n\trefine(otherValidationFn: (value: T) => U): Validator {\n\t\treturn new Validator(\n\t\t\t(value) => {\n\t\t\t\treturn otherValidationFn(this.validate(value))\n\t\t\t},\n\n\t\t\t(knownGoodValue, newValue) => {\n\t\t\t\tconst validated = this.validateUsingKnownGoodVersion(knownGoodValue as any, newValue)\n\t\t\t\tif (Object.is(knownGoodValue, validated)) {\n\t\t\t\t\treturn knownGoodValue\n\t\t\t\t}\n\t\t\t\treturn otherValidationFn(validated)\n\t\t\t}\n\t\t)\n\t}\n\n\t/**\n\t * Refine this validation with an additional check that doesn't change the resulting value.\n\t *\n\t * @example\n\t *\n\t * ```ts\n\t * const numberLessThan10Validator = T.number.check((value) => {\n\t * \tif (value >= 10) {\n\t * \t\tthrow new ValidationError(`Expected number less than 10, got ${value}`)\n\t * \t}\n\t * })\n\t * ```\n\t */\n\tcheck(name: string, checkFn: (value: T) => void): Validator\n\tcheck(checkFn: (value: T) => void): Validator\n\tcheck(nameOrCheckFn: string | ((value: T) => void), checkFn?: (value: T) => void): Validator {\n\t\tif (typeof nameOrCheckFn === 'string') {\n\t\t\treturn this.refine((value) => {\n\t\t\t\tprefixError(`(check ${nameOrCheckFn})`, () => checkFn!(value))\n\t\t\t\treturn value\n\t\t\t})\n\t\t} else {\n\t\t\treturn this.refine((value) => {\n\t\t\t\tnameOrCheckFn(value)\n\t\t\t\treturn value\n\t\t\t})\n\t\t}\n\t}\n}\n\n/** @public */\nexport class ArrayOfValidator extends Validator {\n\tconstructor(readonly itemValidator: Validatable) {\n\t\tsuper(\n\t\t\t(value) => {\n\t\t\t\tconst arr = array.validate(value)\n\t\t\t\tfor (let i = 0; i < arr.length; i++) {\n\t\t\t\t\tprefixError(i, () => itemValidator.validate(arr[i]))\n\t\t\t\t}\n\t\t\t\treturn arr as T[]\n\t\t\t},\n\t\t\t(knownGoodValue, newValue) => {\n\t\t\t\tif (!itemValidator.validateUsingKnownGoodVersion) return this.validate(newValue)\n\t\t\t\tconst arr = array.validate(newValue)\n\t\t\t\tlet isDifferent = knownGoodValue.length !== arr.length\n\t\t\t\tfor (let i = 0; i < arr.length; i++) {\n\t\t\t\t\tconst item = arr[i]\n\t\t\t\t\tif (i >= knownGoodValue.length) {\n\t\t\t\t\t\tisDifferent = true\n\t\t\t\t\t\tprefixError(i, () => itemValidator.validate(item))\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\t\t\t\t\t// sneaky quick check here to avoid the prefix + validator overhead\n\t\t\t\t\tif (Object.is(knownGoodValue[i], item)) {\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\t\t\t\t\tconst checkedItem = prefixError(i, () =>\n\t\t\t\t\t\titemValidator.validateUsingKnownGoodVersion!(knownGoodValue[i], item)\n\t\t\t\t\t)\n\t\t\t\t\tif (!Object.is(checkedItem, knownGoodValue[i])) {\n\t\t\t\t\t\tisDifferent = true\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn isDifferent ? (newValue as T[]) : knownGoodValue\n\t\t\t}\n\t\t)\n\t}\n\n\tnonEmpty() {\n\t\treturn this.check((value) => {\n\t\t\tif (value.length === 0) {\n\t\t\t\tthrow new ValidationError('Expected a non-empty array')\n\t\t\t}\n\t\t})\n\t}\n\n\tlengthGreaterThan1() {\n\t\treturn this.check((value) => {\n\t\t\tif (value.length <= 1) {\n\t\t\t\tthrow new ValidationError('Expected an array with length greater than 1')\n\t\t\t}\n\t\t})\n\t}\n}\n\n/** @public */\nexport class ObjectValidator extends Validator {\n\tconstructor(\n\t\tpublic readonly config: {\n\t\t\treadonly [K in keyof Shape]: Validatable\n\t\t},\n\t\tprivate readonly shouldAllowUnknownProperties = false\n\t) {\n\t\tsuper(\n\t\t\t(object) => {\n\t\t\t\tif (typeof object !== 'object' || object === null) {\n\t\t\t\t\tthrow new ValidationError(`Expected object, got ${typeToString(object)}`)\n\t\t\t\t}\n\n\t\t\t\tfor (const [key, validator] of Object.entries(config)) {\n\t\t\t\t\tprefixError(key, () => {\n\t\t\t\t\t\t;(validator as Validatable).validate(getOwnProperty(object, key))\n\t\t\t\t\t})\n\t\t\t\t}\n\n\t\t\t\tif (!shouldAllowUnknownProperties) {\n\t\t\t\t\tfor (const key of Object.keys(object)) {\n\t\t\t\t\t\tif (!hasOwnProperty(config, key)) {\n\t\t\t\t\t\t\tthrow new ValidationError(`Unexpected property`, [key])\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn object as Shape\n\t\t\t},\n\t\t\t(knownGoodValue, newValue) => {\n\t\t\t\tif (typeof newValue !== 'object' || newValue === null) {\n\t\t\t\t\tthrow new ValidationError(`Expected object, got ${typeToString(newValue)}`)\n\t\t\t\t}\n\n\t\t\t\tlet isDifferent = false\n\n\t\t\t\tfor (const [key, validator] of Object.entries(config)) {\n\t\t\t\t\tconst prev = getOwnProperty(knownGoodValue, key)\n\t\t\t\t\tconst next = getOwnProperty(newValue, key)\n\t\t\t\t\t// sneaky quick check here to avoid the prefix + validator overhead\n\t\t\t\t\tif (Object.is(prev, next)) {\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\t\t\t\t\tconst checked = prefixError(key, () => {\n\t\t\t\t\t\tconst validatable = validator as Validatable\n\t\t\t\t\t\tif (validatable.validateUsingKnownGoodVersion) {\n\t\t\t\t\t\t\treturn validatable.validateUsingKnownGoodVersion(prev, next)\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\treturn validatable.validate(next)\n\t\t\t\t\t\t}\n\t\t\t\t\t})\n\t\t\t\t\tif (!Object.is(checked, prev)) {\n\t\t\t\t\t\tisDifferent = true\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (!shouldAllowUnknownProperties) {\n\t\t\t\t\tfor (const key of Object.keys(newValue)) {\n\t\t\t\t\t\tif (!hasOwnProperty(config, key)) {\n\t\t\t\t\t\t\tthrow new ValidationError(`Unexpected property`, [key])\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tfor (const key of Object.keys(knownGoodValue)) {\n\t\t\t\t\tif (!hasOwnProperty(newValue, key)) {\n\t\t\t\t\t\tisDifferent = true\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn isDifferent ? (newValue as Shape) : knownGoodValue\n\t\t\t}\n\t\t)\n\t}\n\n\tallowUnknownProperties() {\n\t\treturn new ObjectValidator(this.config, true)\n\t}\n\n\t/**\n\t * Extend an object validator by adding additional properties.\n\t *\n\t * @example\n\t *\n\t * ```ts\n\t * const animalValidator = T.object({\n\t * \tname: T.string,\n\t * })\n\t * const catValidator = animalValidator.extend({\n\t * \tmeowVolume: T.number,\n\t * })\n\t * ```\n\t */\n\textend>(extension: {\n\t\treadonly [K in keyof Extension]: Validatable\n\t}): ObjectValidator {\n\t\treturn new ObjectValidator({ ...this.config, ...extension }) as any as ObjectValidator<\n\t\t\tShape & Extension\n\t\t>\n\t}\n}\n\n// pass this into itself e.g. Config extends UnionObjectSchemaConfig\n/** @public */\nexport type UnionValidatorConfig = {\n\treadonly [Variant in keyof Config]: Validatable & {\n\t\tvalidate: (input: any) => { readonly [K in Key]: Variant }\n\t}\n}\n/** @public */\nexport class UnionValidator<\n\tKey extends string,\n\tConfig extends UnionValidatorConfig,\n\tUnknownValue = never,\n> extends Validator | UnknownValue> {\n\tconstructor(\n\t\tprivate readonly key: Key,\n\t\tprivate readonly config: Config,\n\t\tprivate readonly unknownValueValidation: (value: object, variant: string) => UnknownValue,\n\t\tprivate readonly useNumberKeys: boolean\n\t) {\n\t\tsuper(\n\t\t\t(input) => {\n\t\t\t\tthis.expectObject(input)\n\n\t\t\t\tconst { matchingSchema, variant } = this.getMatchingSchemaAndVariant(input)\n\t\t\t\tif (matchingSchema === undefined) {\n\t\t\t\t\treturn this.unknownValueValidation(input, variant)\n\t\t\t\t}\n\n\t\t\t\treturn prefixError(`(${key} = ${variant})`, () => matchingSchema.validate(input))\n\t\t\t},\n\t\t\t(prevValue, newValue) => {\n\t\t\t\tthis.expectObject(newValue)\n\t\t\t\tthis.expectObject(prevValue)\n\n\t\t\t\tconst { matchingSchema, variant } = this.getMatchingSchemaAndVariant(newValue)\n\t\t\t\tif (matchingSchema === undefined) {\n\t\t\t\t\treturn this.unknownValueValidation(newValue, variant)\n\t\t\t\t}\n\n\t\t\t\tif (getOwnProperty(prevValue, key) !== getOwnProperty(newValue, key)) {\n\t\t\t\t\t// the type has changed so bail out and do a regular validation\n\t\t\t\t\treturn prefixError(`(${key} = ${variant})`, () => matchingSchema.validate(newValue))\n\t\t\t\t}\n\n\t\t\t\treturn prefixError(`(${key} = ${variant})`, () => {\n\t\t\t\t\tif (matchingSchema.validateUsingKnownGoodVersion) {\n\t\t\t\t\t\treturn matchingSchema.validateUsingKnownGoodVersion(prevValue, newValue)\n\t\t\t\t\t} else {\n\t\t\t\t\t\treturn matchingSchema.validate(newValue)\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t\t}\n\t\t)\n\t}\n\n\tprivate expectObject(value: unknown): asserts value is object {\n\t\tif (typeof value !== 'object' || value === null) {\n\t\t\tthrow new ValidationError(`Expected an object, got ${typeToString(value)}`, [])\n\t\t}\n\t}\n\n\tprivate getMatchingSchemaAndVariant(object: object): {\n\t\tmatchingSchema: Validatable | undefined\n\t\tvariant: string\n\t} {\n\t\tconst variant = getOwnProperty(object, this.key) as string & keyof Config\n\t\tif (!this.useNumberKeys && typeof variant !== 'string') {\n\t\t\tthrow new ValidationError(\n\t\t\t\t`Expected a string for key \"${this.key}\", got ${typeToString(variant)}`\n\t\t\t)\n\t\t} else if (this.useNumberKeys && !Number.isFinite(Number(variant))) {\n\t\t\tthrow new ValidationError(`Expected a number for key \"${this.key}\", got \"${variant as any}\"`)\n\t\t}\n\n\t\tconst matchingSchema = hasOwnProperty(this.config, variant) ? this.config[variant] : undefined\n\t\treturn { matchingSchema, variant }\n\t}\n\n\tvalidateUnknownVariants(\n\t\tunknownValueValidation: (value: object, variant: string) => Unknown\n\t): UnionValidator {\n\t\treturn new UnionValidator(this.key, this.config, unknownValueValidation, this.useNumberKeys)\n\t}\n}\n\n/** @public */\nexport class DictValidator extends Validator> {\n\tconstructor(\n\t\tpublic readonly keyValidator: Validatable,\n\t\tpublic readonly valueValidator: Validatable\n\t) {\n\t\tsuper(\n\t\t\t(object) => {\n\t\t\t\tif (typeof object !== 'object' || object === null) {\n\t\t\t\t\tthrow new ValidationError(`Expected object, got ${typeToString(object)}`)\n\t\t\t\t}\n\n\t\t\t\tfor (const [key, value] of Object.entries(object)) {\n\t\t\t\t\tprefixError(key, () => {\n\t\t\t\t\t\tkeyValidator.validate(key)\n\t\t\t\t\t\tvalueValidator.validate(value)\n\t\t\t\t\t})\n\t\t\t\t}\n\n\t\t\t\treturn object as Record\n\t\t\t},\n\t\t\t(knownGoodValue, newValue) => {\n\t\t\t\tif (typeof newValue !== 'object' || newValue === null) {\n\t\t\t\t\tthrow new ValidationError(`Expected object, got ${typeToString(newValue)}`)\n\t\t\t\t}\n\n\t\t\t\tlet isDifferent = false\n\n\t\t\t\tfor (const [key, value] of Object.entries(newValue)) {\n\t\t\t\t\tif (!hasOwnProperty(knownGoodValue, key)) {\n\t\t\t\t\t\tisDifferent = true\n\t\t\t\t\t\tprefixError(key, () => {\n\t\t\t\t\t\t\tkeyValidator.validate(key)\n\t\t\t\t\t\t\tvalueValidator.validate(value)\n\t\t\t\t\t\t})\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\t\t\t\t\tconst prev = getOwnProperty(knownGoodValue, key)\n\t\t\t\t\tconst next = value\n\t\t\t\t\t// sneaky quick check here to avoid the prefix + validator overhead\n\t\t\t\t\tif (Object.is(prev, next)) {\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\t\t\t\t\tconst checked = prefixError(key, () => {\n\t\t\t\t\t\tif (valueValidator.validateUsingKnownGoodVersion) {\n\t\t\t\t\t\t\treturn valueValidator.validateUsingKnownGoodVersion(prev as any, next)\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\treturn valueValidator.validate(next)\n\t\t\t\t\t\t}\n\t\t\t\t\t})\n\t\t\t\t\tif (!Object.is(checked, prev)) {\n\t\t\t\t\t\tisDifferent = true\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tfor (const key of Object.keys(knownGoodValue)) {\n\t\t\t\t\tif (!hasOwnProperty(newValue, key)) {\n\t\t\t\t\t\tisDifferent = true\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn isDifferent ? (newValue as Record) : knownGoodValue\n\t\t\t}\n\t\t)\n\t}\n}\n\nfunction typeofValidator(type: string): Validator {\n\treturn new Validator((value) => {\n\t\tif (typeof value !== type) {\n\t\t\tthrow new ValidationError(`Expected ${type}, got ${typeToString(value)}`)\n\t\t}\n\t\treturn value as T\n\t})\n}\n\n/**\n * Validation that accepts any value. Useful as a starting point for building your own custom\n * validations.\n *\n * @public\n */\nexport const unknown = new Validator((value) => value)\n/**\n * Validation that accepts any value. Generally this should be avoided, but you can use it as an\n * escape hatch if you want to work without validations for e.g. a prototype.\n *\n * @public\n */\nexport const any = new Validator((value): any => value)\n\n/**\n * Validates that a value is a string.\n *\n * @public\n */\nexport const string = typeofValidator('string')\n\n/**\n * Validates that a value is a finite non-NaN number.\n *\n * @public\n */\nexport const number = typeofValidator('number').check((number) => {\n\tif (Number.isNaN(number)) {\n\t\tthrow new ValidationError('Expected a number, got NaN')\n\t}\n\tif (!Number.isFinite(number)) {\n\t\tthrow new ValidationError(`Expected a finite number, got ${number}`)\n\t}\n})\n/**\n * Fails if value \\< 0\n *\n * @public\n */\nexport const positiveNumber = number.check((value) => {\n\tif (value < 0) throw new ValidationError(`Expected a positive number, got ${value}`)\n})\n/**\n * Fails if value \\<= 0\n *\n * @public\n */\nexport const nonZeroNumber = number.check((value) => {\n\tif (value <= 0) throw new ValidationError(`Expected a non-zero positive number, got ${value}`)\n})\n/**\n * Fails if number is not an integer\n *\n * @public\n */\nexport const integer = number.check((value) => {\n\tif (!Number.isInteger(value)) throw new ValidationError(`Expected an integer, got ${value}`)\n})\n/**\n * Fails if value \\< 0 and is not an integer\n *\n * @public\n */\nexport const positiveInteger = integer.check((value) => {\n\tif (value < 0) throw new ValidationError(`Expected a positive integer, got ${value}`)\n})\n/**\n * Fails if value \\<= 0 and is not an integer\n *\n * @public\n */\nexport const nonZeroInteger = integer.check((value) => {\n\tif (value <= 0) throw new ValidationError(`Expected a non-zero positive integer, got ${value}`)\n})\n\n/**\n * Validates that a value is boolean.\n *\n * @public\n */\nexport const boolean = typeofValidator('boolean')\n/**\n * Validates that a value is a bigint.\n *\n * @public\n */\nexport const bigint = typeofValidator('bigint')\n/**\n * Validates that a value matches another that was passed in.\n *\n * @example\n *\n * ```ts\n * const trueValidator = T.literal(true)\n * ```\n *\n * @public\n */\nexport function literal(expectedValue: T): Validator {\n\treturn new Validator((actualValue) => {\n\t\tif (actualValue !== expectedValue) {\n\t\t\tthrow new ValidationError(`Expected ${expectedValue}, got ${JSON.stringify(actualValue)}`)\n\t\t}\n\t\treturn expectedValue\n\t})\n}\n\n/**\n * Validates that a value is an array. To check the contents of the array, use T.arrayOf.\n *\n * @public\n */\nexport const array = new Validator((value) => {\n\tif (!Array.isArray(value)) {\n\t\tthrow new ValidationError(`Expected an array, got ${typeToString(value)}`)\n\t}\n\treturn value\n})\n\n/**\n * Validates that a value is an array whose contents matches the passed-in validator.\n *\n * @public\n */\nexport function arrayOf(itemValidator: Validatable): ArrayOfValidator {\n\treturn new ArrayOfValidator(itemValidator)\n}\n\n/** @public */\nexport const unknownObject = new Validator>((value) => {\n\tif (typeof value !== 'object' || value === null) {\n\t\tthrow new ValidationError(`Expected object, got ${typeToString(value)}`)\n\t}\n\treturn value as Record\n})\n\n/** @public */\nexport type ExtractRequiredKeys = {\n\t[K in keyof T]: undefined extends T[K] ? never : K\n}[keyof T]\n\n/** @public */\nexport type ExtractOptionalKeys = {\n\t[K in keyof T]: undefined extends T[K] ? K : never\n}[keyof T]\n\n/**\n * Validate an object has a particular shape.\n *\n * @public\n */\nexport function object(config: {\n\treadonly [K in keyof Shape]: Validatable\n}): ObjectValidator<\n\tExpand<\n\t\t{ [P in ExtractRequiredKeys]: Shape[P] } & {\n\t\t\t[P in ExtractOptionalKeys]?: Shape[P]\n\t\t}\n\t>\n> {\n\treturn new ObjectValidator(config) as any\n}\n\nfunction isPlainObject(value: unknown): value is Record {\n\treturn (\n\t\ttypeof value === 'object' &&\n\t\tvalue !== null &&\n\t\t(Object.getPrototypeOf(value) === Object.prototype ||\n\t\t\tObject.getPrototypeOf(value) === null ||\n\t\t\tObject.getPrototypeOf(value) === STRUCTURED_CLONE_OBJECT_PROTOTYPE)\n\t)\n}\n\nfunction isValidJson(value: any): value is JsonValue {\n\tif (\n\t\tvalue === null ||\n\t\ttypeof value === 'number' ||\n\t\ttypeof value === 'string' ||\n\t\ttypeof value === 'boolean'\n\t) {\n\t\treturn true\n\t}\n\n\tif (Array.isArray(value)) {\n\t\treturn value.every(isValidJson)\n\t}\n\n\tif (isPlainObject(value)) {\n\t\treturn Object.values(value).every(isValidJson)\n\t}\n\n\treturn false\n}\n\n/**\n * Validate that a value is valid JSON.\n *\n * @public\n */\nexport const jsonValue: Validator = new Validator(\n\t(value): JsonValue => {\n\t\tif (isValidJson(value)) {\n\t\t\treturn value as JsonValue\n\t\t}\n\n\t\tthrow new ValidationError(`Expected json serializable value, got ${typeof value}`)\n\t},\n\t(knownGoodValue, newValue) => {\n\t\tif (Array.isArray(knownGoodValue) && Array.isArray(newValue)) {\n\t\t\tlet isDifferent = knownGoodValue.length !== newValue.length\n\t\t\tfor (let i = 0; i < newValue.length; i++) {\n\t\t\t\tif (i >= knownGoodValue.length) {\n\t\t\t\t\tisDifferent = true\n\t\t\t\t\tjsonValue.validate(newValue[i])\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tconst prev = knownGoodValue[i]\n\t\t\t\tconst next = newValue[i]\n\t\t\t\tif (Object.is(prev, next)) {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tconst checked = jsonValue.validateUsingKnownGoodVersion!(prev, next)\n\t\t\t\tif (!Object.is(checked, prev)) {\n\t\t\t\t\tisDifferent = true\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn isDifferent ? (newValue as JsonValue) : knownGoodValue\n\t\t} else if (isPlainObject(knownGoodValue) && isPlainObject(newValue)) {\n\t\t\tlet isDifferent = false\n\t\t\tfor (const key of Object.keys(newValue)) {\n\t\t\t\tif (!hasOwnProperty(knownGoodValue, key)) {\n\t\t\t\t\tisDifferent = true\n\t\t\t\t\tjsonValue.validate(newValue[key])\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tconst prev = knownGoodValue[key]\n\t\t\t\tconst next = newValue[key]\n\t\t\t\tif (Object.is(prev, next)) {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tconst checked = jsonValue.validateUsingKnownGoodVersion!(prev!, next)\n\t\t\t\tif (!Object.is(checked, prev)) {\n\t\t\t\t\tisDifferent = true\n\t\t\t\t}\n\t\t\t}\n\t\t\tfor (const key of Object.keys(knownGoodValue)) {\n\t\t\t\tif (!hasOwnProperty(newValue, key)) {\n\t\t\t\t\tisDifferent = true\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn isDifferent ? (newValue as JsonValue) : knownGoodValue\n\t\t} else {\n\t\t\treturn jsonValue.validate(newValue)\n\t\t}\n\t}\n)\n\n/**\n * Validate an object has a particular shape.\n *\n * @public\n */\nexport function jsonDict(): DictValidator {\n\treturn dict(string, jsonValue)\n}\n\n/**\n * Validation that an option is a dict with particular keys and values.\n *\n * @public\n */\nexport function dict(\n\tkeyValidator: Validatable,\n\tvalueValidator: Validatable\n): DictValidator {\n\treturn new DictValidator(keyValidator, valueValidator)\n}\n\n/**\n * Validate a union of several object types. Each object must have a property matching `key` which\n * should be a unique string.\n *\n * @example\n *\n * ```ts\n * const catValidator = T.object({ kind: T.literal('cat'), meow: T.boolean })\n * const dogValidator = T.object({ kind: T.literal('dog'), bark: T.boolean })\n * const animalValidator = T.union('kind', { cat: catValidator, dog: dogValidator })\n * ```\n *\n * @public\n */\nexport function union>(\n\tkey: Key,\n\tconfig: Config\n): UnionValidator {\n\treturn new UnionValidator(\n\t\tkey,\n\t\tconfig,\n\t\t(unknownValue, unknownVariant) => {\n\t\t\tthrow new ValidationError(\n\t\t\t\t`Expected one of ${Object.keys(config)\n\t\t\t\t\t.map((key) => JSON.stringify(key))\n\t\t\t\t\t.join(' or ')}, got ${JSON.stringify(unknownVariant)}`,\n\t\t\t\t[key]\n\t\t\t)\n\t\t},\n\t\tfalse\n\t)\n}\n\n/**\n * @internal\n */\nexport function numberUnion>(\n\tkey: Key,\n\tconfig: Config\n): UnionValidator {\n\treturn new UnionValidator(\n\t\tkey,\n\t\tconfig,\n\t\t(unknownValue, unknownVariant) => {\n\t\t\tthrow new ValidationError(\n\t\t\t\t`Expected one of ${Object.keys(config)\n\t\t\t\t\t.map((key) => JSON.stringify(key))\n\t\t\t\t\t.join(' or ')}, got ${JSON.stringify(unknownVariant)}`,\n\t\t\t\t[key]\n\t\t\t)\n\t\t},\n\t\ttrue\n\t)\n}\n\n/**\n * A named object with an ID. Errors will be reported as being part of the object with the given\n * name.\n *\n * @public\n */\nexport function model(\n\tname: string,\n\tvalidator: Validatable\n): Validator {\n\treturn new Validator(\n\t\t(value) => {\n\t\t\treturn prefixError(name, () => validator.validate(value))\n\t\t},\n\t\t(prevValue, newValue) => {\n\t\t\treturn prefixError(name, () => {\n\t\t\t\tif (validator.validateUsingKnownGoodVersion) {\n\t\t\t\t\treturn validator.validateUsingKnownGoodVersion(prevValue, newValue)\n\t\t\t\t} else {\n\t\t\t\t\treturn validator.validate(newValue)\n\t\t\t\t}\n\t\t\t})\n\t\t}\n\t)\n}\n\n/** @public */\nexport function setEnum(values: ReadonlySet): Validator {\n\treturn new Validator((value) => {\n\t\tif (!values.has(value as T)) {\n\t\t\tconst valuesString = Array.from(values, (value) => JSON.stringify(value)).join(' or ')\n\t\t\tthrow new ValidationError(`Expected ${valuesString}, got ${value}`)\n\t\t}\n\t\treturn value as T\n\t})\n}\n\n/** @public */\nexport function optional(validator: Validatable): Validator {\n\treturn new Validator(\n\t\t(value) => {\n\t\t\tif (value === undefined) return undefined\n\t\t\treturn validator.validate(value)\n\t\t},\n\t\t(knownGoodValue, newValue) => {\n\t\t\tif (knownGoodValue === undefined && newValue === undefined) return undefined\n\t\t\tif (newValue === undefined) return undefined\n\t\t\tif (validator.validateUsingKnownGoodVersion && knownGoodValue !== undefined) {\n\t\t\t\treturn validator.validateUsingKnownGoodVersion(knownGoodValue as T, newValue)\n\t\t\t}\n\t\t\treturn validator.validate(newValue)\n\t\t}\n\t)\n}\n\n/** @public */\nexport function nullable(validator: Validatable): Validator {\n\treturn new Validator(\n\t\t(value) => {\n\t\t\tif (value === null) return null\n\t\t\treturn validator.validate(value)\n\t\t},\n\t\t(knownGoodValue, newValue) => {\n\t\t\tif (newValue === null) return null\n\t\t\tif (validator.validateUsingKnownGoodVersion && knownGoodValue !== null) {\n\t\t\t\treturn validator.validateUsingKnownGoodVersion(knownGoodValue as T, newValue)\n\t\t\t}\n\t\t\treturn validator.validate(newValue)\n\t\t}\n\t)\n}\n\n/** @public */\nexport function literalEnum(\n\t...values: Values\n): Validator {\n\treturn setEnum(new Set(values))\n}\n\nfunction parseUrl(str: string) {\n\ttry {\n\t\treturn new URL(str)\n\t} catch (error) {\n\t\tif (str.startsWith('/') || str.startsWith('./')) {\n\t\t\ttry {\n\t\t\t\treturn new URL(str, 'http://example.com')\n\t\t\t} catch (error) {\n\t\t\t\tthrow new ValidationError(`Expected a valid url, got ${JSON.stringify(str)}`)\n\t\t\t}\n\t\t}\n\t\tthrow new ValidationError(`Expected a valid url, got ${JSON.stringify(str)}`)\n\t}\n}\n\nconst validLinkProtocols = new Set(['http:', 'https:', 'mailto:'])\n\n/**\n * Validates that a value is a url safe to use as a link.\n *\n * @public\n */\nexport const linkUrl = string.check((value) => {\n\tif (value === '') return\n\tconst url = parseUrl(value)\n\n\tif (!validLinkProtocols.has(url.protocol.toLowerCase())) {\n\t\tthrow new ValidationError(\n\t\t\t`Expected a valid url, got ${JSON.stringify(value)} (invalid protocol)`\n\t\t)\n\t}\n})\n\n// N.B. asset: is a reference to the local indexedDB object store.\nconst validSrcProtocols = new Set(['http:', 'https:', 'data:', 'asset:'])\n\n/**\n * Validates that a valid is a url safe to load as an asset.\n *\n * @public\n */\nexport const srcUrl = string.check((value) => {\n\tif (value === '') return\n\tconst url = parseUrl(value)\n\n\tif (!validSrcProtocols.has(url.protocol.toLowerCase())) {\n\t\tthrow new ValidationError(\n\t\t\t`Expected a valid url, got ${JSON.stringify(value)} (invalid protocol)`\n\t\t)\n\t}\n})\n\n/**\n * Validates an http(s) url\n *\n * @public\n */\nexport const httpUrl = string.check((value) => {\n\tif (value === '') return\n\tconst url = parseUrl(value)\n\n\tif (!url.protocol.toLowerCase().match(/^https?:$/)) {\n\t\tthrow new ValidationError(\n\t\t\t`Expected a valid url, got ${JSON.stringify(value)} (invalid protocol)`\n\t\t)\n\t}\n})\n\n/**\n * Validates that a value is an IndexKey.\n * @public\n */\nexport const indexKey = string.refine((key) => {\n\ttry {\n\t\tvalidateIndexKey(key)\n\t\treturn key\n\t} catch {\n\t\tthrow new ValidationError(`Expected an index key, got ${JSON.stringify(key)}`)\n\t}\n})\n", "import type { RecordId, UnknownRecord } from '@tldraw/store'\nimport { T } from '@tldraw/validate'\n\n/** @public */\nexport function idValidator>(\n\tprefix: Id['__type__']['typeName']\n): T.Validator {\n\treturn T.string.refine((id) => {\n\t\tif (!id.startsWith(`${prefix}:`)) {\n\t\t\tthrow new Error(`${prefix} ID must start with \"${prefix}:\"`)\n\t\t}\n\t\treturn id as Id\n\t})\n}\n", "import { T } from '@tldraw/validate'\nimport { VecModel, vecModelValidator } from '../misc/geometry-types'\nimport { createBindingPropsMigrationSequence } from '../records/TLBinding'\nimport { RecordProps } from '../recordsWithProps'\nimport { arrowShapeVersions } from '../shapes/TLArrowShape'\nimport { TLBaseBinding } from './TLBaseBinding'\n\n/** @public */\nexport interface TLArrowBindingProps {\n\tterminal: 'start' | 'end'\n\tnormalizedAnchor: VecModel\n\t/**\n\t * exact is whether the arrow head 'enters' the bound shape to point directly at the binding\n\t * anchor point\n\t */\n\tisExact: boolean\n\t/**\n\t * precise is whether to bind to the normalizedAnchor, or to the middle of the shape\n\t */\n\tisPrecise: boolean\n}\n\n/** @public */\nexport const arrowBindingProps: RecordProps = {\n\tterminal: T.literalEnum('start', 'end'),\n\tnormalizedAnchor: vecModelValidator,\n\tisExact: T.boolean,\n\tisPrecise: T.boolean,\n}\n\n/** @public */\nexport type TLArrowBinding = TLBaseBinding<'arrow', TLArrowBindingProps>\n\nexport const arrowBindingVersions = {} as const\n\n/** @public */\nexport const arrowBindingMigrations = createBindingPropsMigrationSequence({\n\tsequence: [{ dependsOn: [arrowShapeVersions.ExtractBindings] }],\n})\n", "import { T } from '@tldraw/validate'\n\n/**\n * A serializable model for 2D boxes.\n *\n * @public */\nexport interface BoxModel {\n\tx: number\n\ty: number\n\tw: number\n\th: number\n}\n\n/**\n * A serializable model for 2D vectors.\n *\n * @public */\nexport interface VecModel {\n\tx: number\n\ty: number\n\tz?: number\n}\n\n/** @public */\nexport const vecModelValidator: T.ObjectValidator = T.object({\n\tx: T.number,\n\ty: T.number,\n\tz: T.number.optional(),\n})\n\n/** @public */\nexport const boxModelValidator: T.ObjectValidator = T.object({\n\tx: T.number,\n\ty: T.number,\n\tw: T.number,\n\th: T.number,\n})\n", "import {\n\tRecordId,\n\tUnknownRecord,\n\tcreateMigrationIds,\n\tcreateRecordMigrationSequence,\n\tcreateRecordType,\n} from '@tldraw/store'\nimport { Expand, mapObjectMapValues } from '@tldraw/utils'\nimport { T } from '@tldraw/validate'\nimport { nanoid } from 'nanoid'\nimport { TLArrowBinding } from '../bindings/TLArrowBinding'\nimport { TLBaseBinding, createBindingValidator } from '../bindings/TLBaseBinding'\nimport { SchemaPropsInfo } from '../createTLSchema'\nimport { TLPropsMigrations } from '../recordsWithProps'\n\n/**\n * The default set of bindings that are available in the editor.\n *\n * @public */\nexport type TLDefaultBinding = TLArrowBinding\n\n/**\n * A type for a binding that is available in the editor but whose type is\n * unknown\u2014either one of the editor's default bindings or else a custom binding.\n *\n * @public */\nexport type TLUnknownBinding = TLBaseBinding\n\n/**\n * The set of all bindings that are available in the editor, including unknown bindings.\n *\n * @public\n */\nexport type TLBinding = TLDefaultBinding | TLUnknownBinding\n\n/** @public */\nexport type TLBindingUpdate = Expand<{\n\tid: TLBindingId\n\ttype: T['type']\n\ttypeName?: T['typeName']\n\tfromId?: T['fromId']\n\ttoId?: T['toId']\n\tprops?: Partial\n\tmeta?: Partial\n}>\n\n/** @public */\nexport type TLBindingCreate = Expand<{\n\tid?: TLBindingId\n\ttype: T['type']\n\ttypeName?: T['typeName']\n\tfromId: T['fromId']\n\ttoId: T['toId']\n\tprops?: Partial\n\tmeta?: Partial\n}>\n\n/**\n * An ID for a {@link TLBinding}.\n *\n * @public\n */\nexport type TLBindingId = RecordId\n\n/** @public */\nexport const rootBindingVersions = createMigrationIds('com.tldraw.binding', {} as const)\n\n/** @public */\nexport const rootBindingMigrations = createRecordMigrationSequence({\n\tsequenceId: 'com.tldraw.binding',\n\trecordType: 'binding',\n\tsequence: [],\n})\n\n/** @public */\nexport function isBinding(record?: UnknownRecord): record is TLBinding {\n\tif (!record) return false\n\treturn record.typeName === 'binding'\n}\n\n/** @public */\nexport function isBindingId(id?: string): id is TLBindingId {\n\tif (!id) return false\n\treturn id.startsWith('binding:')\n}\n\n/** @public */\nexport function createBindingId(id?: string): TLBindingId {\n\treturn `binding:${id ?? nanoid()}` as TLBindingId\n}\n\n/**\n * @public\n */\nexport function createBindingPropsMigrationSequence(\n\tmigrations: TLPropsMigrations\n): TLPropsMigrations {\n\treturn migrations\n}\n\n/**\n * @public\n */\nexport function createBindingPropsMigrationIds>(\n\tbindingType: S,\n\tids: T\n): { [k in keyof T]: `com.tldraw.binding.${S}/${T[k]}` } {\n\treturn mapObjectMapValues(ids, (_k, v) => `com.tldraw.binding.${bindingType}/${v}`) as any\n}\n\n/** @internal */\nexport function createBindingRecordType(bindings: Record) {\n\treturn createRecordType('binding', {\n\t\tscope: 'document',\n\t\tvalidator: T.model(\n\t\t\t'binding',\n\t\t\tT.union(\n\t\t\t\t'type',\n\t\t\t\tmapObjectMapValues(bindings, (type, { props, meta }) =>\n\t\t\t\t\tcreateBindingValidator(type, props, meta)\n\t\t\t\t)\n\t\t\t)\n\t\t),\n\t}).withDefaultProperties(() => ({\n\t\tmeta: {},\n\t}))\n}\n", "import { BaseRecord } from '@tldraw/store'\nimport { JsonObject } from '@tldraw/utils'\nimport { T } from '@tldraw/validate'\nimport { idValidator } from '../misc/id-validator'\nimport { TLBindingId } from '../records/TLBinding'\nimport { TLShapeId } from '../records/TLShape'\nimport { shapeIdValidator } from '../shapes/TLBaseShape'\n\n/** @public */\nexport interface TLBaseBinding\n\textends BaseRecord<'binding', TLBindingId> {\n\ttype: Type\n\tfromId: TLShapeId\n\ttoId: TLShapeId\n\tprops: Props\n\tmeta: JsonObject\n}\n\n/** @public */\nexport const bindingIdValidator = idValidator('binding')\n\n/** @public */\nexport function createBindingValidator<\n\tType extends string,\n\tProps extends JsonObject,\n\tMeta extends JsonObject,\n>(\n\ttype: Type,\n\tprops?: { [K in keyof Props]: T.Validatable },\n\tmeta?: { [K in keyof Meta]: T.Validatable }\n) {\n\treturn T.object>({\n\t\tid: bindingIdValidator,\n\t\ttypeName: T.literal('binding'),\n\t\ttype: T.literal(type),\n\t\tfromId: shapeIdValidator,\n\t\ttoId: shapeIdValidator,\n\t\tprops: props ? T.object(props) : (T.jsonValue as any),\n\t\tmeta: meta ? T.object(meta) : (T.jsonValue as any),\n\t})\n}\n", "import { BaseRecord } from '@tldraw/store'\nimport { IndexKey, JsonObject } from '@tldraw/utils'\nimport { T } from '@tldraw/validate'\nimport { TLOpacityType, opacityValidator } from '../misc/TLOpacity'\nimport { idValidator } from '../misc/id-validator'\nimport { TLParentId, TLShapeId } from '../records/TLShape'\n\n/** @public */\nexport interface TLBaseShape\n\textends BaseRecord<'shape', TLShapeId> {\n\ttype: Type\n\tx: number\n\ty: number\n\trotation: number\n\tindex: IndexKey\n\tparentId: TLParentId\n\tisLocked: boolean\n\topacity: TLOpacityType\n\tprops: Props\n\tmeta: JsonObject\n}\n\n/** @public */\nexport const parentIdValidator = T.string.refine((id) => {\n\tif (!id.startsWith('page:') && !id.startsWith('shape:')) {\n\t\tthrow new Error('Parent ID must start with \"page:\" or \"shape:\"')\n\t}\n\treturn id as TLParentId\n})\n\n/** @public */\nexport const shapeIdValidator = idValidator('shape')\n\n/** @public */\nexport function createShapeValidator<\n\tType extends string,\n\tProps extends JsonObject,\n\tMeta extends JsonObject,\n>(\n\ttype: Type,\n\tprops?: { [K in keyof Props]: T.Validatable },\n\tmeta?: { [K in keyof Meta]: T.Validatable }\n) {\n\treturn T.object>({\n\t\tid: shapeIdValidator,\n\t\ttypeName: T.literal('shape'),\n\t\tx: T.number,\n\t\ty: T.number,\n\t\trotation: T.number,\n\t\tindex: T.indexKey,\n\t\tparentId: parentIdValidator,\n\t\ttype: T.literal(type),\n\t\tisLocked: T.boolean,\n\t\topacity: opacityValidator,\n\t\tprops: props ? T.object(props) : (T.jsonValue as any),\n\t\tmeta: meta ? T.object(meta) : (T.jsonValue as any),\n\t})\n}\n", "import { T } from '@tldraw/validate'\n\n/** @public */\nexport type TLOpacityType = number\n\n/** @public */\nexport const opacityValidator = T.number.check((n) => {\n\tif (n < 0 || n > 1) {\n\t\tthrow new T.ValidationError('Opacity must be between 0 and 1')\n\t}\n})\n", "import { createMigrationSequence } from '@tldraw/store'\nimport { T } from '@tldraw/validate'\nimport { TLArrowBinding } from '../bindings/TLArrowBinding'\nimport { VecModel, vecModelValidator } from '../misc/geometry-types'\nimport { createBindingId } from '../records/TLBinding'\nimport { TLShapeId, createShapePropsMigrationIds } from '../records/TLShape'\nimport { RecordProps, TLPropsMigration, createPropsMigration } from '../recordsWithProps'\nimport { StyleProp } from '../styles/StyleProp'\nimport {\n\tDefaultColorStyle,\n\tDefaultLabelColorStyle,\n\tTLDefaultColorStyle,\n} from '../styles/TLColorStyle'\nimport { DefaultDashStyle, TLDefaultDashStyle } from '../styles/TLDashStyle'\nimport { DefaultFillStyle, TLDefaultFillStyle } from '../styles/TLFillStyle'\nimport { DefaultFontStyle, TLDefaultFontStyle } from '../styles/TLFontStyle'\nimport { DefaultSizeStyle, TLDefaultSizeStyle } from '../styles/TLSizeStyle'\nimport { TLBaseShape } from './TLBaseShape'\n\nconst arrowheadTypes = [\n\t'arrow',\n\t'triangle',\n\t'square',\n\t'dot',\n\t'pipe',\n\t'diamond',\n\t'inverted',\n\t'bar',\n\t'none',\n] as const\n\n/** @public */\nexport const ArrowShapeArrowheadStartStyle = StyleProp.defineEnum('tldraw:arrowheadStart', {\n\tdefaultValue: 'none',\n\tvalues: arrowheadTypes,\n})\n\n/** @public */\nexport const ArrowShapeArrowheadEndStyle = StyleProp.defineEnum('tldraw:arrowheadEnd', {\n\tdefaultValue: 'arrow',\n\tvalues: arrowheadTypes,\n})\n\n/** @public */\nexport type TLArrowShapeArrowheadStyle = T.TypeOf\n\n/** @public */\nexport interface TLArrowShapeProps {\n\tlabelColor: TLDefaultColorStyle\n\tcolor: TLDefaultColorStyle\n\tfill: TLDefaultFillStyle\n\tdash: TLDefaultDashStyle\n\tsize: TLDefaultSizeStyle\n\tarrowheadStart: TLArrowShapeArrowheadStyle\n\tarrowheadEnd: TLArrowShapeArrowheadStyle\n\tfont: TLDefaultFontStyle\n\tstart: VecModel\n\tend: VecModel\n\tbend: number\n\ttext: string\n\tlabelPosition: number\n\tscale: number\n}\n\n/** @public */\nexport type TLArrowShape = TLBaseShape<'arrow', TLArrowShapeProps>\n\n/** @public */\nexport const arrowShapeProps: RecordProps = {\n\tlabelColor: DefaultLabelColorStyle,\n\tcolor: DefaultColorStyle,\n\tfill: DefaultFillStyle,\n\tdash: DefaultDashStyle,\n\tsize: DefaultSizeStyle,\n\tarrowheadStart: ArrowShapeArrowheadStartStyle,\n\tarrowheadEnd: ArrowShapeArrowheadEndStyle,\n\tfont: DefaultFontStyle,\n\tstart: vecModelValidator,\n\tend: vecModelValidator,\n\tbend: T.number,\n\ttext: T.string,\n\tlabelPosition: T.number,\n\tscale: T.nonZeroNumber,\n}\n\nexport const arrowShapeVersions = createShapePropsMigrationIds('arrow', {\n\tAddLabelColor: 1,\n\tAddIsPrecise: 2,\n\tAddLabelPosition: 3,\n\tExtractBindings: 4,\n\tAddScale: 5,\n})\n\nfunction propsMigration(migration: TLPropsMigration) {\n\treturn createPropsMigration('shape', 'arrow', migration)\n}\n\n/** @public */\nexport const arrowShapeMigrations = createMigrationSequence({\n\tsequenceId: 'com.tldraw.shape.arrow',\n\tretroactive: false,\n\tsequence: [\n\t\tpropsMigration({\n\t\t\tid: arrowShapeVersions.AddLabelColor,\n\t\t\tup: (props) => {\n\t\t\t\tprops.labelColor = 'black'\n\t\t\t},\n\t\t\tdown: 'retired',\n\t\t}),\n\n\t\tpropsMigration({\n\t\t\tid: arrowShapeVersions.AddIsPrecise,\n\t\t\tup: ({ start, end }) => {\n\t\t\t\tif (start.type === 'binding') {\n\t\t\t\t\tstart.isPrecise = !(start.normalizedAnchor.x === 0.5 && start.normalizedAnchor.y === 0.5)\n\t\t\t\t}\n\t\t\t\tif (end.type === 'binding') {\n\t\t\t\t\tend.isPrecise = !(end.normalizedAnchor.x === 0.5 && end.normalizedAnchor.y === 0.5)\n\t\t\t\t}\n\t\t\t},\n\t\t\tdown: ({ start, end }) => {\n\t\t\t\tif (start.type === 'binding') {\n\t\t\t\t\tif (!start.isPrecise) {\n\t\t\t\t\t\tstart.normalizedAnchor = { x: 0.5, y: 0.5 }\n\t\t\t\t\t}\n\t\t\t\t\tdelete start.isPrecise\n\t\t\t\t}\n\t\t\t\tif (end.type === 'binding') {\n\t\t\t\t\tif (!end.isPrecise) {\n\t\t\t\t\t\tend.normalizedAnchor = { x: 0.5, y: 0.5 }\n\t\t\t\t\t}\n\t\t\t\t\tdelete end.isPrecise\n\t\t\t\t}\n\t\t\t},\n\t\t}),\n\n\t\tpropsMigration({\n\t\t\tid: arrowShapeVersions.AddLabelPosition,\n\t\t\tup: (props) => {\n\t\t\t\tprops.labelPosition = 0.5\n\t\t\t},\n\t\t\tdown: (props) => {\n\t\t\t\tdelete props.labelPosition\n\t\t\t},\n\t\t}),\n\n\t\t{\n\t\t\tid: arrowShapeVersions.ExtractBindings,\n\t\t\tscope: 'store',\n\t\t\tup: (oldStore) => {\n\t\t\t\ttype OldArrowTerminal =\n\t\t\t\t\t| {\n\t\t\t\t\t\t\ttype: 'point'\n\t\t\t\t\t\t\tx: number\n\t\t\t\t\t\t\ty: number\n\t\t\t\t\t }\n\t\t\t\t\t| {\n\t\t\t\t\t\t\ttype: 'binding'\n\t\t\t\t\t\t\tboundShapeId: TLShapeId\n\t\t\t\t\t\t\tnormalizedAnchor: VecModel\n\t\t\t\t\t\t\tisExact: boolean\n\t\t\t\t\t\t\tisPrecise: boolean\n\t\t\t\t\t }\n\t\t\t\t\t// new type:\n\t\t\t\t\t| { type?: undefined; x: number; y: number }\n\n\t\t\t\ttype OldArrow = TLBaseShape<'arrow', { start: OldArrowTerminal; end: OldArrowTerminal }>\n\n\t\t\t\tconst arrows = Object.values(oldStore).filter(\n\t\t\t\t\t(r: any): r is OldArrow => r.typeName === 'shape' && r.type === 'arrow'\n\t\t\t\t)\n\n\t\t\t\tfor (const arrow of arrows) {\n\t\t\t\t\tconst { start, end } = arrow.props\n\t\t\t\t\tif (start.type === 'binding') {\n\t\t\t\t\t\tconst id = createBindingId()\n\t\t\t\t\t\tconst binding: TLArrowBinding = {\n\t\t\t\t\t\t\ttypeName: 'binding',\n\t\t\t\t\t\t\tid,\n\t\t\t\t\t\t\ttype: 'arrow',\n\t\t\t\t\t\t\tfromId: arrow.id,\n\t\t\t\t\t\t\ttoId: start.boundShapeId,\n\t\t\t\t\t\t\tmeta: {},\n\t\t\t\t\t\t\tprops: {\n\t\t\t\t\t\t\t\tterminal: 'start',\n\t\t\t\t\t\t\t\tnormalizedAnchor: start.normalizedAnchor,\n\t\t\t\t\t\t\t\tisExact: start.isExact,\n\t\t\t\t\t\t\t\tisPrecise: start.isPrecise,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\toldStore[id] = binding\n\t\t\t\t\t\tarrow.props.start = { x: 0, y: 0 }\n\t\t\t\t\t} else {\n\t\t\t\t\t\tdelete arrow.props.start.type\n\t\t\t\t\t}\n\t\t\t\t\tif (end.type === 'binding') {\n\t\t\t\t\t\tconst id = createBindingId()\n\t\t\t\t\t\tconst binding: TLArrowBinding = {\n\t\t\t\t\t\t\ttypeName: 'binding',\n\t\t\t\t\t\t\tid,\n\t\t\t\t\t\t\ttype: 'arrow',\n\t\t\t\t\t\t\tfromId: arrow.id,\n\t\t\t\t\t\t\ttoId: end.boundShapeId,\n\t\t\t\t\t\t\tmeta: {},\n\t\t\t\t\t\t\tprops: {\n\t\t\t\t\t\t\t\tterminal: 'end',\n\t\t\t\t\t\t\t\tnormalizedAnchor: end.normalizedAnchor,\n\t\t\t\t\t\t\t\tisExact: end.isExact,\n\t\t\t\t\t\t\t\tisPrecise: end.isPrecise,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\toldStore[id] = binding\n\t\t\t\t\t\tarrow.props.end = { x: 0, y: 0 }\n\t\t\t\t\t} else {\n\t\t\t\t\t\tdelete arrow.props.end.type\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\t\t},\n\t\tpropsMigration({\n\t\t\tid: arrowShapeVersions.AddScale,\n\t\t\tup: (props) => {\n\t\t\t\tprops.scale = 1\n\t\t\t},\n\t\t\tdown: (props) => {\n\t\t\t\tdelete props.scale\n\t\t\t},\n\t\t}),\n\t],\n})\n", "import {\n\tRecordId,\n\tUnknownRecord,\n\tcreateMigrationIds,\n\tcreateRecordMigrationSequence,\n\tcreateRecordType,\n} from '@tldraw/store'\nimport { mapObjectMapValues } from '@tldraw/utils'\nimport { T } from '@tldraw/validate'\nimport { nanoid } from 'nanoid'\nimport { SchemaPropsInfo } from '../createTLSchema'\nimport { TLPropsMigrations } from '../recordsWithProps'\nimport { TLArrowShape } from '../shapes/TLArrowShape'\nimport { TLBaseShape, createShapeValidator } from '../shapes/TLBaseShape'\nimport { TLBookmarkShape } from '../shapes/TLBookmarkShape'\nimport { TLDrawShape } from '../shapes/TLDrawShape'\nimport { TLEmbedShape } from '../shapes/TLEmbedShape'\nimport { TLFrameShape } from '../shapes/TLFrameShape'\nimport { TLGeoShape } from '../shapes/TLGeoShape'\nimport { TLGroupShape } from '../shapes/TLGroupShape'\nimport { TLHighlightShape } from '../shapes/TLHighlightShape'\nimport { TLImageShape } from '../shapes/TLImageShape'\nimport { TLLineShape } from '../shapes/TLLineShape'\nimport { TLNoteShape } from '../shapes/TLNoteShape'\nimport { TLTextShape } from '../shapes/TLTextShape'\nimport { TLVideoShape } from '../shapes/TLVideoShape'\nimport { StyleProp } from '../styles/StyleProp'\nimport { TLPageId } from './TLPage'\n\n/**\n * The default set of shapes that are available in the editor.\n *\n * @public */\nexport type TLDefaultShape =\n\t| TLArrowShape\n\t| TLBookmarkShape\n\t| TLDrawShape\n\t| TLEmbedShape\n\t| TLFrameShape\n\t| TLGeoShape\n\t| TLGroupShape\n\t| TLImageShape\n\t| TLLineShape\n\t| TLNoteShape\n\t| TLTextShape\n\t| TLVideoShape\n\t| TLHighlightShape\n\n/**\n * A type for a shape that is available in the editor but whose type is\n * unknown\u2014either one of the editor's default shapes or else a custom shape.\n *\n * @public */\nexport type TLUnknownShape = TLBaseShape\n\n/**\n * The set of all shapes that are available in the editor, including unknown shapes.\n *\n * @public\n */\nexport type TLShape = TLDefaultShape | TLUnknownShape\n\n/** @public */\nexport type TLShapePartial = T extends T\n\t? {\n\t\t\tid: TLShapeId\n\t\t\ttype: T['type']\n\t\t\tprops?: Partial\n\t\t\tmeta?: Partial\n\t\t} & Partial>\n\t: never\n\n/** @public */\nexport type TLShapeId = RecordId\n\n/** @public */\nexport type TLParentId = TLPageId | TLShapeId\n\n/** @public */\nexport const rootShapeVersions = createMigrationIds('com.tldraw.shape', {\n\tAddIsLocked: 1,\n\tHoistOpacity: 2,\n\tAddMeta: 3,\n\tAddWhite: 4,\n} as const)\n\n/** @public */\nexport const rootShapeMigrations = createRecordMigrationSequence({\n\tsequenceId: 'com.tldraw.shape',\n\trecordType: 'shape',\n\tsequence: [\n\t\t{\n\t\t\tid: rootShapeVersions.AddIsLocked,\n\t\t\tup: (record: any) => {\n\t\t\t\trecord.isLocked = false\n\t\t\t},\n\t\t\tdown: (record: any) => {\n\t\t\t\tdelete record.isLocked\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tid: rootShapeVersions.HoistOpacity,\n\t\t\tup: (record: any) => {\n\t\t\t\trecord.opacity = Number(record.props.opacity ?? '1')\n\t\t\t\tdelete record.props.opacity\n\t\t\t},\n\t\t\tdown: (record: any) => {\n\t\t\t\tconst opacity = record.opacity\n\t\t\t\tdelete record.opacity\n\t\t\t\trecord.props.opacity =\n\t\t\t\t\topacity < 0.175\n\t\t\t\t\t\t? '0.1'\n\t\t\t\t\t\t: opacity < 0.375\n\t\t\t\t\t\t\t? '0.25'\n\t\t\t\t\t\t\t: opacity < 0.625\n\t\t\t\t\t\t\t\t? '0.5'\n\t\t\t\t\t\t\t\t: opacity < 0.875\n\t\t\t\t\t\t\t\t\t? '0.75'\n\t\t\t\t\t\t\t\t\t: '1'\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tid: rootShapeVersions.AddMeta,\n\t\t\tup: (record: any) => {\n\t\t\t\trecord.meta = {}\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tid: rootShapeVersions.AddWhite,\n\t\t\tup: (_record) => {\n\t\t\t\t// noop\n\t\t\t},\n\t\t\tdown: (record: any) => {\n\t\t\t\tif (record.props.color === 'white') {\n\t\t\t\t\trecord.props.color = 'black'\n\t\t\t\t}\n\t\t\t},\n\t\t},\n\t],\n})\n\n/** @public */\nexport function isShape(record?: UnknownRecord): record is TLShape {\n\tif (!record) return false\n\treturn record.typeName === 'shape'\n}\n\n/** @public */\nexport function isShapeId(id?: string): id is TLShapeId {\n\tif (!id) return false\n\treturn id.startsWith('shape:')\n}\n\n/** @public */\nexport function createShapeId(id?: string): TLShapeId {\n\treturn `shape:${id ?? nanoid()}` as TLShapeId\n}\n\n/** @internal */\nexport function getShapePropKeysByStyle(props: Record>) {\n\tconst propKeysByStyle = new Map, string>()\n\tfor (const [key, prop] of Object.entries(props)) {\n\t\tif (prop instanceof StyleProp) {\n\t\t\tif (propKeysByStyle.has(prop)) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Duplicate style prop ${prop.id}. Each style prop can only be used once within a shape.`\n\t\t\t\t)\n\t\t\t}\n\t\t\tpropKeysByStyle.set(prop, key)\n\t\t}\n\t}\n\treturn propKeysByStyle\n}\n\n/**\n * @public\n */\nexport function createShapePropsMigrationSequence(\n\tmigrations: TLPropsMigrations\n): TLPropsMigrations {\n\treturn migrations\n}\n\n/**\n * @public\n */\nexport function createShapePropsMigrationIds<\n\tconst S extends string,\n\tconst T extends Record,\n>(shapeType: S, ids: T): { [k in keyof T]: `com.tldraw.shape.${S}/${T[k]}` } {\n\treturn mapObjectMapValues(ids, (_k, v) => `com.tldraw.shape.${shapeType}/${v}`) as any\n}\n\n/** @internal */\nexport function createShapeRecordType(shapes: Record) {\n\treturn createRecordType('shape', {\n\t\tscope: 'document',\n\t\tvalidator: T.model(\n\t\t\t'shape',\n\t\t\tT.union(\n\t\t\t\t'type',\n\t\t\t\tmapObjectMapValues(shapes, (type, { props, meta }) =>\n\t\t\t\t\tcreateShapeValidator(type, props, meta)\n\t\t\t\t)\n\t\t\t)\n\t\t),\n\t}).withDefaultProperties(() => ({\n\t\tx: 0,\n\t\ty: 0,\n\t\trotation: 0,\n\t\tisLocked: false,\n\t\topacity: 1,\n\t\tmeta: {},\n\t}))\n}\n", "import { T } from '@tldraw/validate'\n\n/**\n * A `StyleProp` is a property of a shape that follows some special rules.\n *\n * 1. The same value can be set on lots of shapes at the same time.\n *\n * 2. The last used value is automatically saved and applied to new shapes.\n *\n * For example, {@link DefaultColorStyle} is a style prop used by tldraw's default shapes to set\n * their color. If you try selecting several shapes on tldraw.com and changing their color, you'll\n * see that the color is applied to all of them. Then, if you draw a new shape, it'll have the same\n * color as the one you just set.\n *\n * You can use styles in your own shapes by either defining your own (see {@link StyleProp.define}\n * and {@link StyleProp.defineEnum}) or using tldraw's default ones, like {@link DefaultColorStyle}.\n * When you define a shape, pass a `props` object describing all of your shape's properties, using\n * `StyleProp`s for the ones you want to be styles. See the\n * {@link https://github.com/tldraw/tldraw/tree/main/apps/examples | custom styles example}\n * for more.\n *\n * @public\n */\nexport class StyleProp implements T.Validatable {\n\t/**\n\t * Define a new {@link StyleProp}.\n\t *\n\t * @param uniqueId - Each StyleProp must have a unique ID. We recommend you prefix this with\n\t * your app/library name.\n\t * @param options -\n\t * - `defaultValue`: The default value for this style prop.\n\t *\n\t * - `type`: Optionally, describe what type of data you expect for this style prop.\n\t *\n\t * @example\n\t * ```ts\n\t * import {T} from '@tldraw/validate'\n\t * import {StyleProp} from '@tldraw/tlschema'\n\t *\n\t * const MyLineWidthProp = StyleProp.define('myApp:lineWidth', {\n\t * defaultValue: 1,\n\t * type: T.number,\n\t * })\n\t * ```\n\t * @public\n\t */\n\tstatic define(\n\t\tuniqueId: string,\n\t\toptions: { defaultValue: Type; type?: T.Validatable }\n\t) {\n\t\tconst { defaultValue, type = T.any } = options\n\t\treturn new StyleProp(uniqueId, defaultValue, type)\n\t}\n\n\t/**\n\t * Define a new {@link StyleProp} as a list of possible values.\n\t *\n\t * @param uniqueId - Each StyleProp must have a unique ID. We recommend you prefix this with\n\t * your app/library name.\n\t * @param options -\n\t * - `defaultValue`: The default value for this style prop.\n\t *\n\t * - `values`: An array of possible values of this style prop.\n\t *\n\t * @example\n\t * ```ts\n\t * import {StyleProp} from '@tldraw/tlschema'\n\t *\n\t * const MySizeProp = StyleProp.defineEnum('myApp:size', {\n\t * defaultValue: 'medium',\n\t * values: ['small', 'medium', 'large'],\n\t * })\n\t * ```\n\t */\n\tstatic defineEnum(\n\t\tuniqueId: string,\n\t\toptions: { defaultValue: Values[number]; values: Values }\n\t) {\n\t\tconst { defaultValue, values } = options\n\t\treturn new EnumStyleProp(uniqueId, defaultValue, values)\n\t}\n\n\t/** @internal */\n\tprotected constructor(\n\t\treadonly id: string,\n\t\tpublic defaultValue: Type,\n\t\treadonly type: T.Validatable\n\t) {}\n\n\tsetDefaultValue(value: Type) {\n\t\tthis.defaultValue = value\n\t}\n\n\tvalidate(value: unknown) {\n\t\treturn this.type.validate(value)\n\t}\n\n\tvalidateUsingKnownGoodVersion(prevValue: Type, newValue: unknown) {\n\t\tif (this.type.validateUsingKnownGoodVersion) {\n\t\t\treturn this.type.validateUsingKnownGoodVersion(prevValue, newValue)\n\t\t} else {\n\t\t\treturn this.validate(newValue)\n\t\t}\n\t}\n}\n\n/**\n * See {@link StyleProp} & {@link StyleProp.defineEnum}\n *\n * @public\n */\nexport class EnumStyleProp extends StyleProp {\n\t/** @internal */\n\tconstructor(\n\t\tid: string,\n\t\tdefaultValue: T,\n\t\treadonly values: readonly T[]\n\t) {\n\t\tsuper(id, defaultValue, T.literalEnum(...values))\n\t}\n}\n\n/**\n * @public\n */\nexport type StylePropValue> = T extends StyleProp ? U : never\n", "import {\n\tMigration,\n\tMigrationId,\n\tMigrationSequence,\n\tRecordType,\n\tStandaloneDependsOn,\n\tUnknownRecord,\n\tcreateMigrationSequence,\n} from '@tldraw/store'\nimport { Expand, assert } from '@tldraw/utils'\nimport { T } from '@tldraw/validate'\nimport { SchemaPropsInfo } from './createTLSchema'\n\n/** @public */\nexport type RecordProps = {\n\t[K in keyof R['props']]: T.Validatable\n}\n\n/** @public */\nexport type RecordPropsType>> = Expand<{\n\t[K in keyof Config]: T.TypeOf\n}>\n\n/**\n * @public\n */\nexport interface TLPropsMigration {\n\treadonly id: MigrationId\n\treadonly dependsOn?: MigrationId[]\n\treadonly up: (props: any) => any\n\t/**\n\t * If a down migration was deployed more than a couple of months ago it should be safe to retire it.\n\t * We only really need them to smooth over the transition between versions, and some folks do keep\n\t * browser tabs open for months without refreshing, but at a certain point that kind of behavior is\n\t * on them. Plus anyway recently chrome has started to actually kill tabs that are open for too long\n\t * rather than just suspending them, so if other browsers follow suit maybe it's less of a concern.\n\t *\n\t * @public\n\t */\n\treadonly down?: 'none' | 'retired' | ((props: any) => any)\n}\n\n/**\n * @public\n */\nexport interface TLPropsMigrations {\n\treadonly sequence: Array\n}\n\nexport function processPropsMigrations(\n\ttypeName: R['typeName'],\n\trecords: Record\n) {\n\tconst result: MigrationSequence[] = []\n\n\tfor (const [subType, { migrations }] of Object.entries(records)) {\n\t\tconst sequenceId = `com.tldraw.${typeName}.${subType}`\n\t\tif (!migrations) {\n\t\t\t// provide empty migrations sequence to allow for future migrations\n\t\t\tresult.push(\n\t\t\t\tcreateMigrationSequence({\n\t\t\t\t\tsequenceId,\n\t\t\t\t\tretroactive: false,\n\t\t\t\t\tsequence: [],\n\t\t\t\t})\n\t\t\t)\n\t\t} else if ('sequenceId' in migrations) {\n\t\t\tassert(\n\t\t\t\tsequenceId === migrations.sequenceId,\n\t\t\t\t`sequenceId mismatch for ${subType} ${RecordType} migrations. Expected '${sequenceId}', got '${migrations.sequenceId}'`\n\t\t\t)\n\t\t\tresult.push(migrations)\n\t\t} else if ('sequence' in migrations) {\n\t\t\tresult.push(\n\t\t\t\tcreateMigrationSequence({\n\t\t\t\t\tsequenceId,\n\t\t\t\t\tretroactive: false,\n\t\t\t\t\tsequence: migrations.sequence.map((m) =>\n\t\t\t\t\t\t'id' in m ? createPropsMigration(typeName, subType, m) : m\n\t\t\t\t\t),\n\t\t\t\t})\n\t\t\t)\n\t\t} else {\n\t\t\t// legacy migrations, will be removed in the future\n\t\t\tresult.push(\n\t\t\t\tcreateMigrationSequence({\n\t\t\t\t\tsequenceId,\n\t\t\t\t\tretroactive: false,\n\t\t\t\t\tsequence: Object.keys(migrations.migrators)\n\t\t\t\t\t\t.map((k) => Number(k))\n\t\t\t\t\t\t.sort((a: number, b: number) => a - b)\n\t\t\t\t\t\t.map(\n\t\t\t\t\t\t\t(version): Migration => ({\n\t\t\t\t\t\t\t\tid: `${sequenceId}/${version}`,\n\t\t\t\t\t\t\t\tscope: 'record',\n\t\t\t\t\t\t\t\tfilter: (r) => r.typeName === typeName && (r as R).type === subType,\n\t\t\t\t\t\t\t\tup: (record: any) => {\n\t\t\t\t\t\t\t\t\tconst result = migrations.migrators[version].up(record)\n\t\t\t\t\t\t\t\t\tif (result) {\n\t\t\t\t\t\t\t\t\t\treturn result\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tdown: (record: any) => {\n\t\t\t\t\t\t\t\t\tconst result = migrations.migrators[version].down(record)\n\t\t\t\t\t\t\t\t\tif (result) {\n\t\t\t\t\t\t\t\t\t\treturn result\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t})\n\t\t\t\t\t\t),\n\t\t\t\t})\n\t\t\t)\n\t\t}\n\t}\n\n\treturn result\n}\n\nexport function createPropsMigration(\n\ttypeName: R['typeName'],\n\tsubType: R['type'],\n\tm: TLPropsMigration\n): Migration {\n\treturn {\n\t\tid: m.id,\n\t\tdependsOn: m.dependsOn,\n\t\tscope: 'record',\n\t\tfilter: (r) => r.typeName === typeName && (r as R).type === subType,\n\t\tup: (record: any) => {\n\t\t\tconst result = m.up(record.props)\n\t\t\tif (result) {\n\t\t\t\trecord.props = result\n\t\t\t}\n\t\t},\n\t\tdown:\n\t\t\ttypeof m.down === 'function'\n\t\t\t\t? (record: any) => {\n\t\t\t\t\t\tconst result = (m.down as (props: any) => any)(record.props)\n\t\t\t\t\t\tif (result) {\n\t\t\t\t\t\t\trecord.props = result\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t: undefined,\n\t}\n}\n", "import { Expand } from '@tldraw/utils'\nimport { T } from '@tldraw/validate'\nimport { StyleProp } from './StyleProp'\n\n/** @public */\nexport const defaultColorNames = [\n\t'black',\n\t'grey',\n\t'light-violet',\n\t'violet',\n\t'blue',\n\t'light-blue',\n\t'yellow',\n\t'orange',\n\t'green',\n\t'light-green',\n\t'light-red',\n\t'red',\n\t'white',\n] as const\n\n/** @public */\nexport interface TLDefaultColorThemeColor {\n\tsolid: string\n\tsemi: string\n\tpattern: string\n\tfill: string // same as solid\n\tnote: {\n\t\tfill: string\n\t\ttext: string\n\t}\n\thighlight: {\n\t\tsrgb: string\n\t\tp3: string\n\t}\n}\n\n/** @public */\nexport type TLDefaultColorTheme = Expand<\n\t{\n\t\tid: 'light' | 'dark'\n\t\ttext: string\n\t\tbackground: string\n\t\tsolid: string\n\t} & Record<(typeof defaultColorNames)[number], TLDefaultColorThemeColor>\n>\n\n/** @public */\nexport const DefaultColorThemePalette: {\n\tlightMode: TLDefaultColorTheme\n\tdarkMode: TLDefaultColorTheme\n} = {\n\tlightMode: {\n\t\tid: 'light',\n\t\ttext: '#000000',\n\t\tbackground: 'rgb(249, 250, 251)',\n\t\tsolid: '#fcfffe',\n\t\tblack: {\n\t\t\tsolid: '#1d1d1d',\n\t\t\tfill: '#1d1d1d',\n\t\t\tnote: {\n\t\t\t\tfill: '#FCE19C',\n\t\t\t\ttext: '#000000',\n\t\t\t},\n\t\t\tsemi: '#e8e8e8',\n\t\t\tpattern: '#494949',\n\t\t\thighlight: {\n\t\t\t\tsrgb: '#fddd00',\n\t\t\t\tp3: 'color(display-p3 0.972 0.8705 0.05)',\n\t\t\t},\n\t\t},\n\t\tblue: {\n\t\t\tsolid: '#4465e9',\n\t\t\tfill: '#4465e9',\n\t\t\tnote: {\n\t\t\t\tfill: '#8AA3FF',\n\t\t\t\ttext: '#000000',\n\t\t\t},\n\t\t\tsemi: '#dce1f8',\n\t\t\tpattern: '#6681ee',\n\t\t\thighlight: {\n\t\t\t\tsrgb: '#10acff',\n\t\t\t\tp3: 'color(display-p3 0.308 0.6632 0.9996)',\n\t\t\t},\n\t\t},\n\t\tgreen: {\n\t\t\tsolid: '#099268',\n\t\t\tfill: '#099268',\n\t\t\tnote: {\n\t\t\t\tfill: '#6FC896',\n\t\t\t\ttext: '#000000',\n\t\t\t},\n\t\t\tsemi: '#d3e9e3',\n\t\t\tpattern: '#39a785',\n\t\t\thighlight: {\n\t\t\t\tsrgb: '#00ffc8',\n\t\t\t\tp3: 'color(display-p3 0.2536 0.984 0.7981)',\n\t\t\t},\n\t\t},\n\t\tgrey: {\n\t\t\tsolid: '#9fa8b2',\n\t\t\tfill: '#9fa8b2',\n\t\t\tnote: {\n\t\t\t\tfill: '#C0CAD3',\n\t\t\t\ttext: '#000000',\n\t\t\t},\n\t\t\tsemi: '#eceef0',\n\t\t\tpattern: '#bcc3c9',\n\t\t\thighlight: {\n\t\t\t\tsrgb: '#cbe7f1',\n\t\t\t\tp3: 'color(display-p3 0.8163 0.9023 0.9416)',\n\t\t\t},\n\t\t},\n\t\t'light-blue': {\n\t\t\tsolid: '#4ba1f1',\n\t\t\tfill: '#4ba1f1',\n\t\t\tnote: {\n\t\t\t\tfill: '#9BC4FD',\n\t\t\t\ttext: '#000000',\n\t\t\t},\n\t\t\tsemi: '#ddedfa',\n\t\t\tpattern: '#6fbbf8',\n\t\t\thighlight: {\n\t\t\t\tsrgb: '#00f4ff',\n\t\t\t\tp3: 'color(display-p3 0.1512 0.9414 0.9996)',\n\t\t\t},\n\t\t},\n\t\t'light-green': {\n\t\t\tsolid: '#4cb05e',\n\t\t\tfill: '#4cb05e',\n\t\t\tnote: {\n\t\t\t\tfill: '#98D08A',\n\t\t\t\ttext: '#000000',\n\t\t\t},\n\t\t\tsemi: '#dbf0e0',\n\t\t\tpattern: '#65cb78',\n\t\t\thighlight: {\n\t\t\t\tsrgb: '#65f641',\n\t\t\t\tp3: 'color(display-p3 0.563 0.9495 0.3857)',\n\t\t\t},\n\t\t},\n\t\t'light-red': {\n\t\t\tsolid: '#f87777',\n\t\t\tfill: '#f87777',\n\t\t\tnote: {\n\t\t\t\tfill: '#F7A5A1',\n\t\t\t\ttext: '#000000',\n\t\t\t},\n\t\t\tsemi: '#f4dadb',\n\t\t\tpattern: '#fe9e9e',\n\t\t\thighlight: {\n\t\t\t\tsrgb: '#ff7fa3',\n\t\t\t\tp3: 'color(display-p3 0.9988 0.5301 0.6397)',\n\t\t\t},\n\t\t},\n\t\t'light-violet': {\n\t\t\tsolid: '#e085f4',\n\t\t\tfill: '#e085f4',\n\t\t\tnote: {\n\t\t\t\tfill: '#DFB0F9',\n\t\t\t\ttext: '#000000',\n\t\t\t},\n\t\t\tsemi: '#f5eafa',\n\t\t\tpattern: '#e9acf8',\n\t\t\thighlight: {\n\t\t\t\tsrgb: '#ff88ff',\n\t\t\t\tp3: 'color(display-p3 0.9676 0.5652 0.9999)',\n\t\t\t},\n\t\t},\n\t\torange: {\n\t\t\tsolid: '#e16919',\n\t\t\tfill: '#e16919',\n\t\t\tnote: {\n\t\t\t\tfill: '#FAA475',\n\t\t\t\ttext: '#000000',\n\t\t\t},\n\t\t\tsemi: '#f8e2d4',\n\t\t\tpattern: '#f78438',\n\t\t\thighlight: {\n\t\t\t\tsrgb: '#ffa500',\n\t\t\t\tp3: 'color(display-p3 0.9988 0.6905 0.266)',\n\t\t\t},\n\t\t},\n\t\tred: {\n\t\t\tsolid: '#e03131',\n\t\t\tfill: '#e03131',\n\t\t\tnote: {\n\t\t\t\tfill: '#FC8282',\n\t\t\t\ttext: '#000000',\n\t\t\t},\n\t\t\tsemi: '#f4dadb',\n\t\t\tpattern: '#e55959',\n\t\t\thighlight: {\n\t\t\t\tsrgb: '#ff636e',\n\t\t\t\tp3: 'color(display-p3 0.9992 0.4376 0.45)',\n\t\t\t},\n\t\t},\n\t\tviolet: {\n\t\t\tsolid: '#ae3ec9',\n\t\t\tfill: '#ae3ec9',\n\t\t\tnote: {\n\t\t\t\tfill: '#DB91FD',\n\t\t\t\ttext: '#000000',\n\t\t\t},\n\t\t\tsemi: '#ecdcf2',\n\t\t\tpattern: '#bd63d3',\n\t\t\thighlight: {\n\t\t\t\tsrgb: '#c77cff',\n\t\t\t\tp3: 'color(display-p3 0.7469 0.5089 0.9995)',\n\t\t\t},\n\t\t},\n\t\tyellow: {\n\t\t\tsolid: '#f1ac4b',\n\t\t\tfill: '#f1ac4b',\n\t\t\tnote: {\n\t\t\t\tfill: '#FED49A',\n\t\t\t\ttext: '#000000',\n\t\t\t},\n\t\t\tsemi: '#f9f0e6',\n\t\t\tpattern: '#fecb92',\n\t\t\thighlight: {\n\t\t\t\tsrgb: '#fddd00',\n\t\t\t\tp3: 'color(display-p3 0.972 0.8705 0.05)',\n\t\t\t},\n\t\t},\n\t\twhite: {\n\t\t\tsolid: '#FFFFFF',\n\t\t\tfill: '#FFFFFF',\n\t\t\tsemi: '#f5f5f5',\n\t\t\tpattern: '#f9f9f9',\n\t\t\tnote: {\n\t\t\t\tfill: '#FFFFFF',\n\t\t\t\ttext: '#000000',\n\t\t\t},\n\t\t\thighlight: {\n\t\t\t\tsrgb: '#ffffff',\n\t\t\t\tp3: 'color(display-p3 1 1 1)',\n\t\t\t},\n\t\t},\n\t},\n\tdarkMode: {\n\t\tid: 'dark',\n\t\ttext: 'hsl(210, 17%, 98%)',\n\t\tbackground: 'hsl(240, 5%, 6.5%)',\n\t\tsolid: '#010403',\n\n\t\tblack: {\n\t\t\tsolid: '#f2f2f2',\n\t\t\tfill: '#f2f2f2',\n\t\t\tnote: {\n\t\t\t\tfill: '#2c2c2c',\n\t\t\t\ttext: '#f2f2f2',\n\t\t\t},\n\t\t\tsemi: '#2c3036',\n\t\t\tpattern: '#989898',\n\t\t\thighlight: {\n\t\t\t\tsrgb: '#d2b700',\n\t\t\t\tp3: 'color(display-p3 0.8078 0.7225 0.0312)',\n\t\t\t},\n\t\t},\n\t\tblue: {\n\t\t\tsolid: '#4f72fc', // 3c60f0\n\t\t\tfill: '#4f72fc',\n\t\t\tnote: {\n\t\t\t\tfill: '#2A3F98',\n\t\t\t\ttext: '#f2f2f2',\n\t\t\t},\n\t\t\tsemi: '#262d40',\n\t\t\tpattern: '#3a4b9e',\n\t\t\thighlight: {\n\t\t\t\tsrgb: '#0079d2',\n\t\t\t\tp3: 'color(display-p3 0.0032 0.4655 0.7991)',\n\t\t\t},\n\t\t},\n\t\tgreen: {\n\t\t\tsolid: '#099268',\n\t\t\tfill: '#099268',\n\t\t\tnote: {\n\t\t\t\tfill: '#014429',\n\t\t\t\ttext: '#f2f2f2',\n\t\t\t},\n\t\t\tsemi: '#253231',\n\t\t\tpattern: '#366a53',\n\t\t\thighlight: {\n\t\t\t\tsrgb: '#009774',\n\t\t\t\tp3: 'color(display-p3 0.0085 0.582 0.4604)',\n\t\t\t},\n\t\t},\n\t\tgrey: {\n\t\t\tsolid: '#9398b0',\n\t\t\tfill: '#9398b0',\n\t\t\tnote: {\n\t\t\t\tfill: '#56595F',\n\t\t\t\ttext: '#f2f2f2',\n\t\t\t},\n\t\t\tsemi: '#33373c',\n\t\t\tpattern: '#7c8187',\n\t\t\thighlight: {\n\t\t\t\tsrgb: '#9cb4cb',\n\t\t\t\tp3: 'color(display-p3 0.6299 0.7012 0.7856)',\n\t\t\t},\n\t\t},\n\t\t'light-blue': {\n\t\t\tsolid: '#4dabf7',\n\t\t\tfill: '#4dabf7',\n\t\t\tnote: {\n\t\t\t\tfill: '#1F5495',\n\t\t\t\ttext: '#f2f2f2',\n\t\t\t},\n\t\t\tsemi: '#2a3642',\n\t\t\tpattern: '#4d7aa9',\n\t\t\thighlight: {\n\t\t\t\tsrgb: '#00bdc8',\n\t\t\t\tp3: 'color(display-p3 0.0023 0.7259 0.7735)',\n\t\t\t},\n\t\t},\n\t\t'light-green': {\n\t\t\tsolid: '#40c057',\n\t\t\tfill: '#40c057',\n\t\t\tnote: {\n\t\t\t\tfill: '#21581D',\n\t\t\t\ttext: '#f2f2f2',\n\t\t\t},\n\t\t\tsemi: '#2a3830',\n\t\t\tpattern: '#4e874e',\n\t\t\thighlight: {\n\t\t\t\tsrgb: '#00a000',\n\t\t\t\tp3: 'color(display-p3 0.2711 0.6172 0.0195)',\n\t\t\t},\n\t\t},\n\t\t'light-red': {\n\t\t\tsolid: '#ff8787',\n\t\t\tfill: '#ff8787',\n\t\t\tnote: {\n\t\t\t\tfill: '#923632',\n\t\t\t\ttext: '#f2f2f2',\n\t\t\t},\n\t\t\tsemi: '#3b3235',\n\t\t\tpattern: '#a56767',\n\t\t\thighlight: {\n\t\t\t\tsrgb: '#db005b',\n\t\t\t\tp3: 'color(display-p3 0.7849 0.0585 0.3589)',\n\t\t\t},\n\t\t},\n\t\t'light-violet': {\n\t\t\tsolid: '#e599f7',\n\t\t\tfill: '#e599f7',\n\t\t\tnote: {\n\t\t\t\tfill: '#762F8E',\n\t\t\t\ttext: '#f2f2f2',\n\t\t\t},\n\t\t\tsemi: '#383442',\n\t\t\tpattern: '#9770a9',\n\t\t\thighlight: {\n\t\t\t\tsrgb: '#c400c7',\n\t\t\t\tp3: 'color(display-p3 0.7024 0.0403 0.753)',\n\t\t\t},\n\t\t},\n\t\torange: {\n\t\t\tsolid: '#f76707',\n\t\t\tfill: '#f76707',\n\t\t\tnote: {\n\t\t\t\tfill: '#843906',\n\t\t\t\ttext: '#f2f2f2',\n\t\t\t},\n\t\t\tsemi: '#3a2e2a',\n\t\t\tpattern: '#9f552d',\n\t\t\thighlight: {\n\t\t\t\tsrgb: '#d07a00',\n\t\t\t\tp3: 'color(display-p3 0.7699 0.4937 0.0085)',\n\t\t\t},\n\t\t},\n\t\tred: {\n\t\t\tsolid: '#e03131',\n\t\t\tfill: '#e03131',\n\t\t\tnote: {\n\t\t\t\tfill: '#89231A',\n\t\t\t\ttext: '#f2f2f2',\n\t\t\t},\n\t\t\tsemi: '#36292b',\n\t\t\tpattern: '#8f3734',\n\t\t\thighlight: {\n\t\t\t\tsrgb: '#de002c',\n\t\t\t\tp3: 'color(display-p3 0.7978 0.0509 0.2035)',\n\t\t\t},\n\t\t},\n\t\tviolet: {\n\t\t\tsolid: '#ae3ec9',\n\t\t\tfill: '#ae3ec9',\n\t\t\tnote: {\n\t\t\t\tfill: '#681683',\n\t\t\t\ttext: '#f2f2f2',\n\t\t\t},\n\t\t\tsemi: '#31293c',\n\t\t\tpattern: '#763a8b',\n\t\t\thighlight: {\n\t\t\t\tsrgb: '#9e00ee',\n\t\t\t\tp3: 'color(display-p3 0.5651 0.0079 0.8986)',\n\t\t\t},\n\t\t},\n\t\tyellow: {\n\t\t\tsolid: '#ffc034',\n\t\t\tfill: '#ffc034',\n\t\t\tnote: {\n\t\t\t\tfill: '#98571B',\n\t\t\t\ttext: '#f2f2f2',\n\t\t\t},\n\t\t\tsemi: '#3c3934',\n\t\t\tpattern: '#fecb92',\n\t\t\thighlight: {\n\t\t\t\tsrgb: '#d2b700',\n\t\t\t\tp3: 'color(display-p3 0.8078 0.7225 0.0312)',\n\t\t\t},\n\t\t},\n\t\twhite: {\n\t\t\tsolid: '#f3f3f3',\n\t\t\tfill: '#f3f3f3',\n\t\t\tsemi: '#f5f5f5',\n\t\t\tpattern: '#f9f9f9',\n\t\t\tnote: {\n\t\t\t\tfill: '#eaeaea',\n\t\t\t\ttext: '#1d1d1d',\n\t\t\t},\n\t\t\thighlight: {\n\t\t\t\tsrgb: '#ffffff',\n\t\t\t\tp3: 'color(display-p3 1 1 1)',\n\t\t\t},\n\t\t},\n\t},\n}\n\n/** @public */\nexport function getDefaultColorTheme(opts: { isDarkMode: boolean }): TLDefaultColorTheme {\n\treturn opts.isDarkMode ? DefaultColorThemePalette.darkMode : DefaultColorThemePalette.lightMode\n}\n\n/** @public */\nexport const DefaultColorStyle = StyleProp.defineEnum('tldraw:color', {\n\tdefaultValue: 'black',\n\tvalues: defaultColorNames,\n})\n\n/** @public */\nexport const DefaultLabelColorStyle = StyleProp.defineEnum('tldraw:labelColor', {\n\tdefaultValue: 'black',\n\tvalues: defaultColorNames,\n})\n\n/** @public */\nexport type TLDefaultColorStyle = T.TypeOf\n", "import { T } from '@tldraw/validate'\nimport { StyleProp } from './StyleProp'\n\n/** @public */\nexport const DefaultDashStyle = StyleProp.defineEnum('tldraw:dash', {\n\tdefaultValue: 'draw',\n\tvalues: ['draw', 'solid', 'dashed', 'dotted'],\n})\n\n/** @public */\nexport type TLDefaultDashStyle = T.TypeOf\n", "import { T } from '@tldraw/validate'\nimport { StyleProp } from './StyleProp'\n\n/** @public */\nexport const DefaultFillStyle = StyleProp.defineEnum('tldraw:fill', {\n\tdefaultValue: 'none',\n\tvalues: ['none', 'semi', 'solid', 'pattern', 'fill'],\n})\n\n/** @public */\nexport type TLDefaultFillStyle = T.TypeOf\n", "import { T } from '@tldraw/validate'\nimport { StyleProp } from './StyleProp'\n\n/** @public */\nexport const DefaultFontStyle = StyleProp.defineEnum('tldraw:font', {\n\tdefaultValue: 'draw',\n\tvalues: ['draw', 'sans', 'serif', 'mono'],\n})\n\n/** @public */\nexport type TLDefaultFontStyle = T.TypeOf\n\n/** @public */\nexport const DefaultFontFamilies = {\n\tdraw: \"'tldraw_draw', sans-serif\",\n\tsans: \"'tldraw_sans', sans-serif\",\n\tserif: \"'tldraw_serif', serif\",\n\tmono: \"'tldraw_mono', monospace\",\n}\n", "import { T } from '@tldraw/validate'\nimport { StyleProp } from './StyleProp'\n\n/** @public */\nexport const DefaultSizeStyle = StyleProp.defineEnum('tldraw:size', {\n\tdefaultValue: 'm',\n\tvalues: ['s', 'm', 'l', 'xl'],\n})\n\n/** @public */\nexport type TLDefaultSizeStyle = T.TypeOf\n", "import { Signal, computed } from '@tldraw/state'\nimport { TLStore } from './TLStore'\nimport { CameraRecordType } from './records/TLCamera'\nimport { TLINSTANCE_ID } from './records/TLInstance'\nimport { InstancePageStateRecordType } from './records/TLPageState'\nimport { TLPOINTER_ID } from './records/TLPointer'\nimport { InstancePresenceRecordType, TLInstancePresence } from './records/TLPresence'\n\n/**\n * Creates a derivation that represents the current presence state of the current user.\n * @public\n */\nexport const createPresenceStateDerivation =\n\t(\n\t\t$user: Signal<{ id: string; color: string; name: string }>,\n\t\tinstanceId?: TLInstancePresence['id']\n\t) =>\n\t(store: TLStore): Signal => {\n\t\treturn computed('instancePresence', () => {\n\t\t\tconst instance = store.get(TLINSTANCE_ID)\n\t\t\tconst pageState = store.get(InstancePageStateRecordType.createId(instance?.currentPageId))\n\t\t\tconst camera = store.get(CameraRecordType.createId(instance?.currentPageId))\n\t\t\tconst pointer = store.get(TLPOINTER_ID)\n\t\t\tconst user = $user.get()\n\t\t\tif (!pageState || !instance || !camera || !pointer || !user) {\n\t\t\t\treturn null\n\t\t\t}\n\n\t\t\treturn InstancePresenceRecordType.create({\n\t\t\t\tid: instanceId ?? InstancePresenceRecordType.createId(store.id),\n\t\t\t\tselectedShapeIds: pageState.selectedShapeIds,\n\t\t\t\tbrush: instance.brush,\n\t\t\t\tscribbles: instance.scribbles,\n\t\t\t\tuserId: user.id,\n\t\t\t\tuserName: user.name,\n\t\t\t\tfollowingUserId: instance.followingUserId,\n\t\t\t\tcamera: {\n\t\t\t\t\tx: camera.x,\n\t\t\t\t\ty: camera.y,\n\t\t\t\t\tz: camera.z,\n\t\t\t\t},\n\t\t\t\tcolor: user.color,\n\t\t\t\tcurrentPageId: instance.currentPageId,\n\t\t\t\tcursor: {\n\t\t\t\t\tx: pointer.x,\n\t\t\t\t\ty: pointer.y,\n\t\t\t\t\trotation: instance.cursor.rotation,\n\t\t\t\t\ttype: instance.cursor.type,\n\t\t\t\t},\n\t\t\t\tlastActivityTimestamp: pointer.lastActivityTimestamp,\n\t\t\t\tscreenBounds: instance.screenBounds,\n\t\t\t\tchatMessage: instance.chatMessage,\n\t\t\t\tmeta: {},\n\t\t\t})\n\t\t})\n\t}\n", "import {\n\tBaseRecord,\n\tcreateMigrationIds,\n\tcreateRecordMigrationSequence,\n\tcreateRecordType,\n\tRecordId,\n} from '@tldraw/store'\nimport { JsonObject } from '@tldraw/utils'\nimport { T } from '@tldraw/validate'\nimport { idValidator } from '../misc/id-validator'\n\n/**\n * A camera record.\n *\n * @public\n */\nexport interface TLCamera extends BaseRecord<'camera', TLCameraId> {\n\tx: number\n\ty: number\n\tz: number\n\tmeta: JsonObject\n}\n\n/**\n * The id of a camera record.\n *\n * @public */\nexport type TLCameraId = RecordId\n\n/** @public */\nexport const cameraValidator: T.Validator = T.model(\n\t'camera',\n\tT.object({\n\t\ttypeName: T.literal('camera'),\n\t\tid: idValidator('camera'),\n\t\tx: T.number,\n\t\ty: T.number,\n\t\tz: T.number,\n\t\tmeta: T.jsonValue as T.ObjectValidator,\n\t})\n)\n\n/** @public */\nexport const cameraVersions = createMigrationIds('com.tldraw.camera', {\n\tAddMeta: 1,\n})\n\n/** @public */\nexport const cameraMigrations = createRecordMigrationSequence({\n\tsequenceId: 'com.tldraw.camera',\n\trecordType: 'camera',\n\tsequence: [\n\t\t{\n\t\t\tid: cameraVersions.AddMeta,\n\t\t\tup: (record) => {\n\t\t\t\t;(record as any).meta = {}\n\t\t\t},\n\t\t},\n\t],\n})\n\n/** @public */\nexport const CameraRecordType = createRecordType('camera', {\n\tvalidator: cameraValidator,\n\tscope: 'session',\n}).withDefaultProperties(\n\t(): Omit => ({\n\t\tx: 0,\n\t\ty: 0,\n\t\tz: 1,\n\t\tmeta: {},\n\t})\n)\n", "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'\n\n/**\n * TLInstance\n *\n * State that is particular to a single browser tab\n *\n * @public\n */\nexport interface TLInstance extends BaseRecord<'instance', TLInstanceId> {\n\tcurrentPageId: TLPageId\n\topacityForNextShape: TLOpacityType\n\tstylesForNextShape: Record\n\tfollowingUserId: string | null\n\thighlightedUserIds: string[]\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 * See: https://developer.mozilla.org/en-US/docs/Web/CSS/\\@media/pointer\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}\n\n/** @internal */\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} as const satisfies { [K in keyof TLInstance]: boolean }\n\n/** @internal */\nexport const pluckPreservingValues = (val?: TLInstance | null): null | Partial =>\n\tval\n\t\t? (filterEntries(val, (key) => {\n\t\t\t\treturn shouldKeyBePreservedBetweenSessions[key as keyof TLInstance]\n\t\t\t}) as Partial)\n\t\t: null\n\n/** @public */\nexport type TLInstanceId = RecordId\n\n/** @public */\nexport const instanceIdValidator = idValidator('instance')\n\nexport function createInstanceRecordType(stylesById: Map>) {\n\tconst stylesForNextShapeValidators = {} as Record>\n\tfor (const [id, style] of stylesById) {\n\t\tstylesForNextShapeValidators[id] = T.optional(style)\n\t}\n\n\tconst instanceTypeValidator: T.Validator = T.model(\n\t\t'instance',\n\t\tT.object({\n\t\t\ttypeName: T.literal('instance'),\n\t\t\tid: idValidator('instance'),\n\t\t\tcurrentPageId: pageIdValidator,\n\t\t\tfollowingUserId: T.string.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(T.string),\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,\n\t\t\tduplicateProps: T.object({\n\t\t\t\tshapeIds: T.arrayOf(idValidator('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})\n\t)\n\n\treturn createRecordType('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},\n\t}).withDefaultProperties(\n\t\t(): Omit => ({\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: process.env.NODE_ENV === 'development',\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})\n\t)\n}\n\n/** @public */\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} as const)\n\n// TODO: rewrite these to use mutation\n\n/** @public */\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],\n})\n\n/** @public */\nexport const TLINSTANCE_ID = 'instance:instance' as TLInstanceId\n", "import { T } from '@tldraw/validate'\nimport { SetValue } from '../util-types'\n\n/**\n * The cursor types used by tldraw's default shapes.\n *\n * @public */\nexport const TL_CURSOR_TYPES = new Set([\n\t'none',\n\t'default',\n\t'pointer',\n\t'cross',\n\t'grab',\n\t'rotate',\n\t'grabbing',\n\t'resize-edge',\n\t'resize-corner',\n\t'text',\n\t'move',\n\t'ew-resize',\n\t'ns-resize',\n\t'nesw-resize',\n\t'nwse-resize',\n\t'nesw-rotate',\n\t'nwse-rotate',\n\t'swne-rotate',\n\t'senw-rotate',\n\t'zoom-in',\n\t'zoom-out',\n])\n\n/**\n * A type for the cursor types used by tldraw's default shapes.\n *\n * @public */\nexport type TLCursorType = SetValue\n\n/** @public */\nexport const cursorTypeValidator = T.setEnum(TL_CURSOR_TYPES)\n\n/**\n * A cursor used by tldraw.\n *\n * @public */\nexport interface TLCursor {\n\ttype: TLCursorType\n\trotation: number\n}\n\n/** @public */\nexport const cursorValidator: T.ObjectValidator = T.object({\n\ttype: cursorTypeValidator,\n\trotation: T.number,\n})\n", "import { T } from '@tldraw/validate'\nimport { SetValue } from '../util-types'\nimport { TLCanvasUiColor, canvasUiColorTypeValidator } from './TLColor'\nimport { VecModel, vecModelValidator } from './geometry-types'\n\n/**\n * The scribble states used by tldraw.\n *\n * @public */\nexport const TL_SCRIBBLE_STATES = new Set(['starting', 'paused', 'active', 'stopping'] as const)\n\n/**\n * A type for the scribble used by tldraw.\n *\n * @public */\nexport interface TLScribble {\n\tid: string\n\tpoints: VecModel[]\n\tsize: number\n\tcolor: TLCanvasUiColor\n\topacity: number\n\tstate: SetValue\n\tdelay: number\n\tshrink: number\n\ttaper: boolean\n}\n\n/** @public */\nexport const scribbleValidator: T.ObjectValidator = T.object({\n\tid: T.string,\n\tpoints: T.arrayOf(vecModelValidator),\n\tsize: T.positiveNumber,\n\tcolor: canvasUiColorTypeValidator,\n\topacity: T.number,\n\tstate: T.setEnum(TL_SCRIBBLE_STATES),\n\tdelay: T.number,\n\tshrink: T.number,\n\ttaper: T.boolean,\n})\n", "import { T } from '@tldraw/validate'\nimport { SetValue } from '../util-types'\n\n/**\n * The colors used by tldraw's default shapes.\n *\n * @public */\nexport const TL_CANVAS_UI_COLOR_TYPES = new Set([\n\t'accent',\n\t'white',\n\t'black',\n\t'selection-stroke',\n\t'selection-fill',\n\t'laser',\n\t'muted-1',\n] as const)\n\n/**\n * A type for the colors used by tldraw's default shapes.\n *\n * @public */\nexport type TLCanvasUiColor = SetValue\n\n/**\n * A validator for the colors used by tldraw's default shapes.\n *\n * @public */\nexport const canvasUiColorTypeValidator = T.setEnum(TL_CANVAS_UI_COLOR_TYPES)\n", "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 * TLPage\n *\n * @public\n */\nexport interface TLPage extends BaseRecord<'page', TLPageId> {\n\tname: string\n\tindex: IndexKey\n\tmeta: JsonObject\n}\n\n/** @public */\nexport type TLPageId = RecordId\n\n/** @public */\nexport const pageIdValidator = idValidator('page')\n\n/** @public */\nexport const pageValidator: T.Validator = 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,\n\t})\n)\n\n/** @public */\nexport const pageVersions = createMigrationIds('com.tldraw.page', {\n\tAddMeta: 1,\n})\n\n/** @public */\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/** @public */\nexport const PageRecordType = createRecordType('page', {\n\tvalidator: pageValidator,\n\tscope: 'document',\n}).withDefaultProperties(() => ({\n\tmeta: {},\n}))\n\n/** @public */\nexport function isPageId(id: string): id is TLPageId {\n\treturn PageRecordType.isId(id)\n}\n", "import {\n\tBaseRecord,\n\tcreateMigrationIds,\n\tcreateRecordMigrationSequence,\n\tcreateRecordType,\n\tRecordId,\n} from '@tldraw/store'\nimport { JsonObject } from '@tldraw/utils'\nimport { T } from '@tldraw/validate'\nimport { idValidator } from '../misc/id-validator'\nimport { shapeIdValidator } from '../shapes/TLBaseShape'\nimport { pageIdValidator, TLPage } from './TLPage'\nimport { TLShapeId } from './TLShape'\n\n/**\n * TLInstancePageState\n *\n * State that is unique to a particular page of the document in a particular browser tab\n *\n * @public\n */\nexport interface TLInstancePageState\n\textends BaseRecord<'instance_page_state', TLInstancePageStateId> {\n\tpageId: RecordId\n\tselectedShapeIds: TLShapeId[]\n\thintingShapeIds: TLShapeId[]\n\terasingShapeIds: TLShapeId[]\n\thoveredShapeId: TLShapeId | null\n\teditingShapeId: TLShapeId | null\n\tcroppingShapeId: TLShapeId | null\n\tfocusedGroupId: TLShapeId | null\n\tmeta: JsonObject\n}\n\n/** @public */\nexport const instancePageStateValidator: T.Validator = T.model(\n\t'instance_page_state',\n\tT.object({\n\t\ttypeName: T.literal('instance_page_state'),\n\t\tid: idValidator('instance_page_state'),\n\t\tpageId: pageIdValidator,\n\t\tselectedShapeIds: T.arrayOf(shapeIdValidator),\n\t\thintingShapeIds: T.arrayOf(shapeIdValidator),\n\t\terasingShapeIds: T.arrayOf(shapeIdValidator),\n\t\thoveredShapeId: shapeIdValidator.nullable(),\n\t\teditingShapeId: shapeIdValidator.nullable(),\n\t\tcroppingShapeId: shapeIdValidator.nullable(),\n\t\tfocusedGroupId: shapeIdValidator.nullable(),\n\t\tmeta: T.jsonValue as T.ObjectValidator,\n\t})\n)\n\n/** @public */\nexport const instancePageStateVersions = createMigrationIds('com.tldraw.instance_page_state', {\n\tAddCroppingId: 1,\n\tRemoveInstanceIdAndCameraId: 2,\n\tAddMeta: 3,\n\tRenameProperties: 4,\n\tRenamePropertiesAgain: 5,\n} as const)\n\n/** @public */\nexport const instancePageStateMigrations = createRecordMigrationSequence({\n\tsequenceId: 'com.tldraw.instance_page_state',\n\trecordType: 'instance_page_state',\n\tsequence: [\n\t\t{\n\t\t\tid: instancePageStateVersions.AddCroppingId,\n\t\t\tup(instance: any) {\n\t\t\t\tinstance.croppingShapeId = null\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tid: instancePageStateVersions.RemoveInstanceIdAndCameraId,\n\t\t\tup(instance: any) {\n\t\t\t\tdelete instance.instanceId\n\t\t\t\tdelete instance.cameraId\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tid: instancePageStateVersions.AddMeta,\n\t\t\tup: (record: any) => {\n\t\t\t\trecord.meta = {}\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tid: instancePageStateVersions.RenameProperties,\n\t\t\t// this migration is cursed: it was written wrong and doesn't do anything.\n\t\t\t// rather than replace it, I've added another migration below that fixes it.\n\t\t\tup: (_record) => {\n\t\t\t\t// noop\n\t\t\t},\n\t\t\tdown: (_record) => {\n\t\t\t\t// noop\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tid: instancePageStateVersions.RenamePropertiesAgain,\n\t\t\tup: (record: any) => {\n\t\t\t\trecord.selectedShapeIds = record.selectedIds\n\t\t\t\tdelete record.selectedIds\n\t\t\t\trecord.hintingShapeIds = record.hintingIds\n\t\t\t\tdelete record.hintingIds\n\t\t\t\trecord.erasingShapeIds = record.erasingIds\n\t\t\t\tdelete record.erasingIds\n\t\t\t\trecord.hoveredShapeId = record.hoveredId\n\t\t\t\tdelete record.hoveredId\n\t\t\t\trecord.editingShapeId = record.editingId\n\t\t\t\tdelete record.editingId\n\t\t\t\trecord.croppingShapeId = record.croppingShapeId ?? record.croppingId ?? null\n\t\t\t\tdelete record.croppingId\n\t\t\t\trecord.focusedGroupId = record.focusLayerId\n\t\t\t\tdelete record.focusLayerId\n\t\t\t},\n\t\t\tdown: (record: any) => {\n\t\t\t\trecord.selectedIds = record.selectedShapeIds\n\t\t\t\tdelete record.selectedShapeIds\n\t\t\t\trecord.hintingIds = record.hintingShapeIds\n\t\t\t\tdelete record.hintingShapeIds\n\t\t\t\trecord.erasingIds = record.erasingShapeIds\n\t\t\t\tdelete record.erasingShapeIds\n\t\t\t\trecord.hoveredId = record.hoveredShapeId\n\t\t\t\tdelete record.hoveredShapeId\n\t\t\t\trecord.editingId = record.editingShapeId\n\t\t\t\tdelete record.editingShapeId\n\t\t\t\trecord.croppingId = record.croppingShapeId\n\t\t\t\tdelete record.croppingShapeId\n\t\t\t\trecord.focusLayerId = record.focusedGroupId\n\t\t\t\tdelete record.focusedGroupId\n\t\t\t},\n\t\t},\n\t],\n})\n\n/** @public */\nexport const InstancePageStateRecordType = createRecordType(\n\t'instance_page_state',\n\t{\n\t\tvalidator: instancePageStateValidator,\n\t\tscope: 'session',\n\t\tephemeralKeys: {\n\t\t\tpageId: false,\n\t\t\tselectedShapeIds: false,\n\t\t\teditingShapeId: false,\n\t\t\tcroppingShapeId: false,\n\t\t\tmeta: false,\n\n\t\t\thintingShapeIds: true,\n\t\t\terasingShapeIds: true,\n\t\t\thoveredShapeId: true,\n\t\t\tfocusedGroupId: true,\n\t\t},\n\t}\n).withDefaultProperties(\n\t(): Omit => ({\n\t\teditingShapeId: null,\n\t\tcroppingShapeId: null,\n\t\tselectedShapeIds: [],\n\t\thoveredShapeId: null,\n\t\terasingShapeIds: [],\n\t\thintingShapeIds: [],\n\t\tfocusedGroupId: null,\n\t\tmeta: {},\n\t})\n)\n\n/** @public */\nexport type TLInstancePageStateId = RecordId\n", "import {\n\tBaseRecord,\n\tcreateMigrationIds,\n\tcreateRecordMigrationSequence,\n\tcreateRecordType,\n\tRecordId,\n} from '@tldraw/store'\nimport { JsonObject } from '@tldraw/utils'\nimport { T } from '@tldraw/validate'\nimport { idValidator } from '../misc/id-validator'\n\n/**\n * TLPointer\n *\n * @public\n */\nexport interface TLPointer extends BaseRecord<'pointer', TLPointerId> {\n\tx: number\n\ty: number\n\tlastActivityTimestamp: number\n\tmeta: JsonObject\n}\n\n/** @public */\nexport type TLPointerId = RecordId\n\n/** @public */\nexport const pointerValidator: T.Validator = T.model(\n\t'pointer',\n\tT.object({\n\t\ttypeName: T.literal('pointer'),\n\t\tid: idValidator('pointer'),\n\t\tx: T.number,\n\t\ty: T.number,\n\t\tlastActivityTimestamp: T.number,\n\t\tmeta: T.jsonValue as T.ObjectValidator,\n\t})\n)\n\n/** @public */\nexport const pointerVersions = createMigrationIds('com.tldraw.pointer', {\n\tAddMeta: 1,\n})\n\n/** @public */\nexport const pointerMigrations = createRecordMigrationSequence({\n\tsequenceId: 'com.tldraw.pointer',\n\trecordType: 'pointer',\n\tsequence: [\n\t\t{\n\t\t\tid: pointerVersions.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/** @public */\nexport const PointerRecordType = createRecordType('pointer', {\n\tvalidator: pointerValidator,\n\tscope: 'session',\n}).withDefaultProperties(\n\t(): Omit => ({\n\t\tx: 0,\n\t\ty: 0,\n\t\tlastActivityTimestamp: 0,\n\t\tmeta: {},\n\t})\n)\n\n/** @public */\nexport const TLPOINTER_ID = PointerRecordType.createId('pointer')\n", "import {\n\tBaseRecord,\n\tcreateMigrationIds,\n\tcreateRecordMigrationSequence,\n\tcreateRecordType,\n\tRecordId,\n} from '@tldraw/store'\nimport { JsonObject } from '@tldraw/utils'\nimport { T } from '@tldraw/validate'\nimport { BoxModel, boxModelValidator } from '../misc/geometry-types'\nimport { idValidator } from '../misc/id-validator'\nimport { cursorTypeValidator, TLCursor } from '../misc/TLCursor'\nimport { scribbleValidator, TLScribble } from '../misc/TLScribble'\nimport { TLPageId } from './TLPage'\nimport { TLShapeId } from './TLShape'\n\n/** @public */\nexport interface TLInstancePresence extends BaseRecord<'instance_presence', TLInstancePresenceID> {\n\tuserId: string\n\tuserName: string\n\tlastActivityTimestamp: number\n\tcolor: string // can be any hex color\n\tcamera: { x: number; y: number; z: number }\n\tselectedShapeIds: TLShapeId[]\n\tcurrentPageId: TLPageId\n\tbrush: BoxModel | null\n\tscribbles: TLScribble[]\n\tscreenBounds: BoxModel\n\tfollowingUserId: string | null\n\tcursor: {\n\t\tx: number\n\t\ty: number\n\t\ttype: TLCursor['type']\n\t\trotation: number\n\t}\n\tchatMessage: string\n\tmeta: JsonObject\n}\n\n/** @public */\nexport type TLInstancePresenceID = RecordId\n\n/** @public */\nexport const instancePresenceValidator: T.Validator = T.model(\n\t'instance_presence',\n\tT.object({\n\t\ttypeName: T.literal('instance_presence'),\n\t\tid: idValidator('instance_presence'),\n\t\tuserId: T.string,\n\t\tuserName: T.string,\n\t\tlastActivityTimestamp: T.number,\n\t\tfollowingUserId: T.string.nullable(),\n\t\tcursor: T.object({\n\t\t\tx: T.number,\n\t\t\ty: T.number,\n\t\t\ttype: cursorTypeValidator,\n\t\t\trotation: T.number,\n\t\t}),\n\t\tcolor: T.string,\n\t\tcamera: T.object({\n\t\t\tx: T.number,\n\t\t\ty: T.number,\n\t\t\tz: T.number,\n\t\t}),\n\t\tscreenBounds: boxModelValidator,\n\t\tselectedShapeIds: T.arrayOf(idValidator('shape')),\n\t\tcurrentPageId: idValidator('page'),\n\t\tbrush: boxModelValidator.nullable(),\n\t\tscribbles: T.arrayOf(scribbleValidator),\n\t\tchatMessage: T.string,\n\t\tmeta: T.jsonValue as T.ObjectValidator,\n\t})\n)\n\n/** @public */\nexport const instancePresenceVersions = createMigrationIds('com.tldraw.instance_presence', {\n\tAddScribbleDelay: 1,\n\tRemoveInstanceId: 2,\n\tAddChatMessage: 3,\n\tAddMeta: 4,\n\tRenameSelectedShapeIds: 5,\n} as const)\n\nexport const instancePresenceMigrations = createRecordMigrationSequence({\n\tsequenceId: 'com.tldraw.instance_presence',\n\trecordType: 'instance_presence',\n\tsequence: [\n\t\t{\n\t\t\tid: instancePresenceVersions.AddScribbleDelay,\n\t\t\tup: (instance: any) => {\n\t\t\t\tif (instance.scribble !== null) {\n\t\t\t\t\tinstance.scribble.delay = 0\n\t\t\t\t}\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tid: instancePresenceVersions.RemoveInstanceId,\n\t\t\tup: (instance: any) => {\n\t\t\t\tdelete instance.instanceId\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tid: instancePresenceVersions.AddChatMessage,\n\t\t\tup: (instance: any) => {\n\t\t\t\tinstance.chatMessage = ''\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tid: instancePresenceVersions.AddMeta,\n\t\t\tup: (record: any) => {\n\t\t\t\trecord.meta = {}\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tid: instancePresenceVersions.RenameSelectedShapeIds,\n\t\t\tup: (_record) => {\n\t\t\t\t// noop, whoopsie\n\t\t\t},\n\t\t},\n\t],\n})\n\n/** @public */\nexport const InstancePresenceRecordType = createRecordType(\n\t'instance_presence',\n\t{\n\t\tvalidator: instancePresenceValidator,\n\t\tscope: 'presence',\n\t}\n).withDefaultProperties(() => ({\n\tlastActivityTimestamp: 0,\n\tfollowingUserId: null,\n\tcolor: '#FF0000',\n\tcamera: {\n\t\tx: 0,\n\t\ty: 0,\n\t\tz: 1,\n\t},\n\tcursor: {\n\t\tx: 0,\n\t\ty: 0,\n\t\ttype: 'default',\n\t\trotation: 0,\n\t},\n\tscreenBounds: {\n\t\tx: 0,\n\t\ty: 0,\n\t\tw: 1,\n\t\th: 1,\n\t},\n\tselectedShapeIds: [],\n\tbrush: null,\n\tscribbles: [],\n\tchatMessage: '',\n\tmeta: {},\n}))\n", "import { LegacyMigrations, MigrationSequence, StoreSchema, StoreValidator } from '@tldraw/store'\nimport { objectMapValues } from '@tldraw/utils'\nimport { TLStoreProps, createIntegrityChecker, onValidationFailure } from './TLStore'\nimport { bookmarkAssetMigrations } from './assets/TLBookmarkAsset'\nimport { imageAssetMigrations } from './assets/TLImageAsset'\nimport { videoAssetMigrations } from './assets/TLVideoAsset'\nimport { arrowBindingMigrations, arrowBindingProps } from './bindings/TLArrowBinding'\nimport { AssetRecordType, assetMigrations } from './records/TLAsset'\nimport { TLBinding, TLDefaultBinding, createBindingRecordType } from './records/TLBinding'\nimport { CameraRecordType, cameraMigrations } from './records/TLCamera'\nimport { DocumentRecordType, documentMigrations } from './records/TLDocument'\nimport { createInstanceRecordType, instanceMigrations } from './records/TLInstance'\nimport { PageRecordType, pageMigrations } from './records/TLPage'\nimport { InstancePageStateRecordType, instancePageStateMigrations } from './records/TLPageState'\nimport { PointerRecordType, pointerMigrations } from './records/TLPointer'\nimport { InstancePresenceRecordType, instancePresenceMigrations } from './records/TLPresence'\nimport { TLRecord } from './records/TLRecord'\nimport {\n\tTLDefaultShape,\n\tTLShape,\n\tcreateShapeRecordType,\n\tgetShapePropKeysByStyle,\n\trootShapeMigrations,\n} from './records/TLShape'\nimport { TLPropsMigrations, processPropsMigrations } from './recordsWithProps'\nimport { arrowShapeMigrations, arrowShapeProps } from './shapes/TLArrowShape'\nimport { bookmarkShapeMigrations, bookmarkShapeProps } from './shapes/TLBookmarkShape'\nimport { drawShapeMigrations, drawShapeProps } from './shapes/TLDrawShape'\nimport { embedShapeMigrations, embedShapeProps } from './shapes/TLEmbedShape'\nimport { frameShapeMigrations, frameShapeProps } from './shapes/TLFrameShape'\nimport { geoShapeMigrations, geoShapeProps } from './shapes/TLGeoShape'\nimport { groupShapeMigrations, groupShapeProps } from './shapes/TLGroupShape'\nimport { highlightShapeMigrations, highlightShapeProps } from './shapes/TLHighlightShape'\nimport { imageShapeMigrations, imageShapeProps } from './shapes/TLImageShape'\nimport { lineShapeMigrations, lineShapeProps } from './shapes/TLLineShape'\nimport { noteShapeMigrations, noteShapeProps } from './shapes/TLNoteShape'\nimport { textShapeMigrations, textShapeProps } from './shapes/TLTextShape'\nimport { videoShapeMigrations, videoShapeProps } from './shapes/TLVideoShape'\nimport { storeMigrations } from './store-migrations'\nimport { StyleProp } from './styles/StyleProp'\n\n/** @public */\nexport interface SchemaPropsInfo {\n\tmigrations?: LegacyMigrations | TLPropsMigrations | MigrationSequence\n\tprops?: Record>\n\tmeta?: Record>\n}\n\n/** @public */\nexport type TLSchema = StoreSchema\n\n/** @public */\nexport const defaultShapeSchemas = {\n\tarrow: { migrations: arrowShapeMigrations, props: arrowShapeProps },\n\tbookmark: { migrations: bookmarkShapeMigrations, props: bookmarkShapeProps },\n\tdraw: { migrations: drawShapeMigrations, props: drawShapeProps },\n\tembed: { migrations: embedShapeMigrations, props: embedShapeProps },\n\tframe: { migrations: frameShapeMigrations, props: frameShapeProps },\n\tgeo: { migrations: geoShapeMigrations, props: geoShapeProps },\n\tgroup: { migrations: groupShapeMigrations, props: groupShapeProps },\n\thighlight: { migrations: highlightShapeMigrations, props: highlightShapeProps },\n\timage: { migrations: imageShapeMigrations, props: imageShapeProps },\n\tline: { migrations: lineShapeMigrations, props: lineShapeProps },\n\tnote: { migrations: noteShapeMigrations, props: noteShapeProps },\n\ttext: { migrations: textShapeMigrations, props: textShapeProps },\n\tvideo: { migrations: videoShapeMigrations, props: videoShapeProps },\n} satisfies { [T in TLDefaultShape['type']]: SchemaPropsInfo }\n\n/** @public */\nexport const defaultBindingSchemas = {\n\tarrow: { migrations: arrowBindingMigrations, props: arrowBindingProps },\n} satisfies { [T in TLDefaultBinding['type']]: SchemaPropsInfo }\n\n/**\n * Create a TLSchema with custom shapes. Custom shapes cannot override default shapes.\n *\n * @param opts - Options\n *\n * @public */\nexport function createTLSchema({\n\tshapes = defaultShapeSchemas,\n\tbindings = defaultBindingSchemas,\n\tmigrations,\n}: {\n\tshapes?: Record\n\tbindings?: Record\n\tmigrations?: readonly MigrationSequence[]\n} = {}): TLSchema {\n\tconst stylesById = new Map>()\n\tfor (const shape of objectMapValues(shapes)) {\n\t\tfor (const style of getShapePropKeysByStyle(shape.props ?? {}).keys()) {\n\t\t\tif (stylesById.has(style.id) && stylesById.get(style.id) !== style) {\n\t\t\t\tthrow new Error(`Multiple StyleProp instances with the same id: ${style.id}`)\n\t\t\t}\n\t\t\tstylesById.set(style.id, style)\n\t\t}\n\t}\n\n\tconst ShapeRecordType = createShapeRecordType(shapes)\n\tconst BindingRecordType = createBindingRecordType(bindings)\n\tconst InstanceRecordType = createInstanceRecordType(stylesById)\n\n\treturn StoreSchema.create(\n\t\t{\n\t\t\tasset: AssetRecordType,\n\t\t\tbinding: BindingRecordType,\n\t\t\tcamera: CameraRecordType,\n\t\t\tdocument: DocumentRecordType,\n\t\t\tinstance: InstanceRecordType,\n\t\t\tinstance_page_state: InstancePageStateRecordType,\n\t\t\tpage: PageRecordType,\n\t\t\tinstance_presence: InstancePresenceRecordType,\n\t\t\tpointer: PointerRecordType,\n\t\t\tshape: ShapeRecordType,\n\t\t},\n\t\t{\n\t\t\tmigrations: [\n\t\t\t\tstoreMigrations,\n\t\t\t\tassetMigrations,\n\t\t\t\tcameraMigrations,\n\t\t\t\tdocumentMigrations,\n\t\t\t\tinstanceMigrations,\n\t\t\t\tinstancePageStateMigrations,\n\t\t\t\tpageMigrations,\n\t\t\t\tinstancePresenceMigrations,\n\t\t\t\tpointerMigrations,\n\t\t\t\trootShapeMigrations,\n\n\t\t\t\tbookmarkAssetMigrations,\n\t\t\t\timageAssetMigrations,\n\t\t\t\tvideoAssetMigrations,\n\n\t\t\t\t...processPropsMigrations('shape', shapes),\n\t\t\t\t...processPropsMigrations('binding', bindings),\n\n\t\t\t\t...(migrations ?? []),\n\t\t\t],\n\t\t\tonValidationFailure,\n\t\t\tcreateIntegrityChecker,\n\t\t}\n\t)\n}\n", "import { Signal } from '@tldraw/state'\nimport {\n\tSerializedStore,\n\tStore,\n\tStoreSchema,\n\tStoreSchemaOptions,\n\tStoreSnapshot,\n} from '@tldraw/store'\nimport { IndexKey, annotateError, structuredClone } from '@tldraw/utils'\nimport { TLAsset } 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'\n\nfunction sortByIndex(a: T, b: T) {\n\tif (a.index < b.index) {\n\t\treturn -1\n\t} else if (a.index > b.index) {\n\t\treturn 1\n\t}\n\treturn 0\n}\n\nfunction redactRecordForErrorReporting(record: any) {\n\tif (record.typeName === 'asset') {\n\t\tif ('src' in record) {\n\t\t\trecord.src = ''\n\t\t}\n\n\t\tif ('src' in record.props) {\n\t\t\trecord.props.src = ''\n\t\t}\n\t}\n}\n\n/** @public */\nexport type TLStoreSchema = StoreSchema\n\n/** @public */\nexport type TLSerializedStore = SerializedStore\n\n/** @public */\nexport type TLStoreSnapshot = StoreSnapshot\n\n/** @public */\nexport interface TLAssetContext {\n\tscreenScale: number\n\tsteppedScreenScale: number\n\tdpr: number\n\tnetworkEffectiveType: string | null\n\tshouldResolveToOriginal: boolean\n}\n\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 */\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(asset: TLAsset, file: File): Promise\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\n}\n\n/** @public */\nexport interface TLStoreProps {\n\tdefaultName: string\n\tassets: Required\n\t/**\n\t * Called an {@link @tldraw/editor#Editor} connected to this store is mounted.\n\t */\n\tonMount(editor: unknown): void | (() => void)\n\tcollaboration?: {\n\t\tstatus: Signal<'online' | 'offline'> | null\n\t}\n}\n\n/** @public */\nexport type TLStore = Store\n\n/** @public */\nexport const onValidationFailure: StoreSchemaOptions<\n\tTLRecord,\n\tTLStoreProps\n>['onValidationFailure'] = ({ error, phase, record, recordBefore }): 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/** @internal */\nexport function createIntegrityChecker(store: Store): () => void {\n\tconst $pageIds = store.query.ids('page')\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()\n\t\tconst missingCameraIds = new Set()\n\t\tfor (const id of pageIds) {\n\t\t\tconst pageStateId = InstancePageStateRecordType.createId(id)\n\t\t\tif (!store.has(pageStateId)) {\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\t\tif (missingCameraIds.size > 0) {\n\t\t\tstore.put([...missingCameraIds].map((id) => CameraRecordType.create({ id })))\n\t\t}\n\t}\n\n\treturn ensureStoreIsUsable\n}\n", "import {\n\tBaseRecord,\n\tcreateMigrationIds,\n\tcreateRecordMigrationSequence,\n\tcreateRecordType,\n\tRecordId,\n} from '@tldraw/store'\nimport { JsonObject } from '@tldraw/utils'\nimport { T } from '@tldraw/validate'\n\n/**\n * TLDocument\n *\n * @public\n */\nexport interface TLDocument extends BaseRecord<'document', RecordId> {\n\tgridSize: number\n\tname: string\n\tmeta: JsonObject\n}\n\n/** @public */\nexport const documentValidator: T.Validator = T.model(\n\t'document',\n\tT.object({\n\t\ttypeName: T.literal('document'),\n\t\tid: T.literal('document:document' as RecordId),\n\t\tgridSize: T.number,\n\t\tname: T.string,\n\t\tmeta: T.jsonValue as T.ObjectValidator,\n\t})\n)\n\n/** @public */\nexport const documentVersions = createMigrationIds('com.tldraw.document', {\n\tAddName: 1,\n\tAddMeta: 2,\n} as const)\n\n/** @public */\nexport const documentMigrations = createRecordMigrationSequence({\n\tsequenceId: 'com.tldraw.document',\n\trecordType: 'document',\n\tsequence: [\n\t\t{\n\t\t\tid: documentVersions.AddName,\n\t\t\tup: (document) => {\n\t\t\t\t;(document as any).name = ''\n\t\t\t},\n\t\t\tdown: (document) => {\n\t\t\t\tdelete (document as any).name\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tid: documentVersions.AddMeta,\n\t\t\tup: (record) => {\n\t\t\t\t;(record as any).meta = {}\n\t\t\t},\n\t\t},\n\t],\n})\n\n/** @public */\nexport const DocumentRecordType = createRecordType('document', {\n\tvalidator: documentValidator,\n\tscope: 'document',\n}).withDefaultProperties(\n\t(): Omit => ({\n\t\tgridSize: 10,\n\t\tname: '',\n\t\tmeta: {},\n\t})\n)\n\n// all document records have the same ID: 'document:document'\n/** @public */\nexport const TLDOCUMENT_ID: RecordId = DocumentRecordType.createId('document')\n", "import { createMigrationIds, createRecordMigrationSequence } from '@tldraw/store'\nimport { T } from '@tldraw/validate'\nimport { TLAsset } from '../records/TLAsset'\nimport { TLBaseAsset, createAssetValidator } from './TLBaseAsset'\n\n/**\n * An asset used for URL bookmarks, used by the TLBookmarkShape.\n *\n * @public */\nexport type TLBookmarkAsset = TLBaseAsset<\n\t'bookmark',\n\t{\n\t\ttitle: string\n\t\tdescription: string\n\t\timage: string\n\t\tfavicon: string\n\t\tsrc: string | null\n\t}\n>\n\n/** @public */\nexport const bookmarkAssetValidator: T.Validator = createAssetValidator(\n\t'bookmark',\n\tT.object({\n\t\ttitle: T.string,\n\t\tdescription: T.string,\n\t\timage: T.string,\n\t\tfavicon: T.string,\n\t\tsrc: T.srcUrl.nullable(),\n\t})\n)\n\nconst Versions = createMigrationIds('com.tldraw.asset.bookmark', {\n\tMakeUrlsValid: 1,\n\tAddFavicon: 2,\n} as const)\n\nexport { Versions as bookmarkAssetVersions }\n\n/** @public */\nexport const bookmarkAssetMigrations = createRecordMigrationSequence({\n\tsequenceId: 'com.tldraw.asset.bookmark',\n\trecordType: 'asset',\n\tfilter: (asset) => (asset as TLAsset).type === 'bookmark',\n\tsequence: [\n\t\t{\n\t\t\tid: Versions.MakeUrlsValid,\n\t\t\tup: (asset: any) => {\n\t\t\t\tif (!T.srcUrl.isValid(asset.props.src)) {\n\t\t\t\t\tasset.props.src = ''\n\t\t\t\t}\n\t\t\t},\n\t\t\tdown: (_asset) => {\n\t\t\t\t// noop\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tid: Versions.AddFavicon,\n\t\t\tup: (asset: any) => {\n\t\t\t\tif (!T.srcUrl.isValid(asset.props.favicon)) {\n\t\t\t\t\tasset.props.favicon = ''\n\t\t\t\t}\n\t\t\t},\n\t\t\tdown: (asset: any) => {\n\t\t\t\tdelete asset.props.favicon\n\t\t\t},\n\t\t},\n\t],\n})\n", "import { createMigrationIds, createRecordMigrationSequence } from '@tldraw/store'\nimport { T } from '@tldraw/validate'\nimport { TLAsset } from '../records/TLAsset'\nimport { TLBaseAsset, createAssetValidator } from './TLBaseAsset'\n\n/**\n * An asset for images such as PNGs and JPEGs, used by the TLImageShape.\n *\n * @public */\nexport type TLImageAsset = TLBaseAsset<\n\t'image',\n\t{\n\t\tw: number\n\t\th: number\n\t\tname: string\n\t\tisAnimated: boolean\n\t\tmimeType: string | null\n\t\tsrc: string | null\n\t\tfileSize?: number\n\t}\n>\n\n/** @public */\nexport const imageAssetValidator: T.Validator = createAssetValidator(\n\t'image',\n\tT.object({\n\t\tw: T.number,\n\t\th: T.number,\n\t\tname: T.string,\n\t\tisAnimated: T.boolean,\n\t\tmimeType: T.string.nullable(),\n\t\tsrc: T.srcUrl.nullable(),\n\t\tfileSize: T.nonZeroNumber.optional(),\n\t})\n)\n\nconst Versions = createMigrationIds('com.tldraw.asset.image', {\n\tAddIsAnimated: 1,\n\tRenameWidthHeight: 2,\n\tMakeUrlsValid: 3,\n\tAddFileSize: 4,\n\tMakeFileSizeOptional: 5,\n} as const)\n\nexport { Versions as imageAssetVersions }\n\n/** @public */\nexport const imageAssetMigrations = createRecordMigrationSequence({\n\tsequenceId: 'com.tldraw.asset.image',\n\trecordType: 'asset',\n\tfilter: (asset) => (asset as TLAsset).type === 'image',\n\tsequence: [\n\t\t{\n\t\t\tid: Versions.AddIsAnimated,\n\t\t\tup: (asset: any) => {\n\t\t\t\tasset.props.isAnimated = false\n\t\t\t},\n\t\t\tdown: (asset: any) => {\n\t\t\t\tdelete asset.props.isAnimated\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tid: Versions.RenameWidthHeight,\n\t\t\tup: (asset: any) => {\n\t\t\t\tasset.props.w = asset.props.width\n\t\t\t\tasset.props.h = asset.props.height\n\t\t\t\tdelete asset.props.width\n\t\t\t\tdelete asset.props.height\n\t\t\t},\n\t\t\tdown: (asset: any) => {\n\t\t\t\tasset.props.width = asset.props.w\n\t\t\t\tasset.props.height = asset.props.h\n\t\t\t\tdelete asset.props.w\n\t\t\t\tdelete asset.props.h\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tid: Versions.MakeUrlsValid,\n\t\t\tup: (asset: any) => {\n\t\t\t\tif (!T.srcUrl.isValid(asset.props.src)) {\n\t\t\t\t\tasset.props.src = ''\n\t\t\t\t}\n\t\t\t},\n\t\t\tdown: (_asset) => {\n\t\t\t\t// noop\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tid: Versions.AddFileSize,\n\t\t\tup: (asset: any) => {\n\t\t\t\tasset.props.fileSize = -1\n\t\t\t},\n\t\t\tdown: (asset: any) => {\n\t\t\t\tdelete asset.props.fileSize\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tid: Versions.MakeFileSizeOptional,\n\t\t\tup: (asset: any) => {\n\t\t\t\tif (asset.props.fileSize === -1) {\n\t\t\t\t\tasset.props.fileSize = undefined\n\t\t\t\t}\n\t\t\t},\n\t\t\tdown: (asset: any) => {\n\t\t\t\tif (asset.props.fileSize === undefined) {\n\t\t\t\t\tasset.props.fileSize = -1\n\t\t\t\t}\n\t\t\t},\n\t\t},\n\t],\n})\n", "import { createMigrationIds, createRecordMigrationSequence } from '@tldraw/store'\nimport { T } from '@tldraw/validate'\nimport { TLAsset } from '../records/TLAsset'\nimport { TLBaseAsset, createAssetValidator } from './TLBaseAsset'\n\n/**\n * An asset used for videos, used by the TLVideoShape.\n *\n * @public */\nexport type TLVideoAsset = TLBaseAsset<\n\t'video',\n\t{\n\t\tw: number\n\t\th: number\n\t\tname: string\n\t\tisAnimated: boolean\n\t\tmimeType: string | null\n\t\tsrc: string | null\n\t\tfileSize?: number\n\t}\n>\n\n/** @public */\nexport const videoAssetValidator: T.Validator = createAssetValidator(\n\t'video',\n\tT.object({\n\t\tw: T.number,\n\t\th: T.number,\n\t\tname: T.string,\n\t\tisAnimated: T.boolean,\n\t\tmimeType: T.string.nullable(),\n\t\tsrc: T.srcUrl.nullable(),\n\t\tfileSize: T.number.optional(),\n\t})\n)\n\nconst Versions = createMigrationIds('com.tldraw.asset.video', {\n\tAddIsAnimated: 1,\n\tRenameWidthHeight: 2,\n\tMakeUrlsValid: 3,\n\tAddFileSize: 4,\n\tMakeFileSizeOptional: 5,\n} as const)\n\nexport { Versions as videoAssetVersions }\n\n/** @public */\nexport const videoAssetMigrations = createRecordMigrationSequence({\n\tsequenceId: 'com.tldraw.asset.video',\n\trecordType: 'asset',\n\tfilter: (asset) => (asset as TLAsset).type === 'video',\n\tsequence: [\n\t\t{\n\t\t\tid: Versions.AddIsAnimated,\n\t\t\tup: (asset: any) => {\n\t\t\t\tasset.props.isAnimated = false\n\t\t\t},\n\t\t\tdown: (asset: any) => {\n\t\t\t\tdelete asset.props.isAnimated\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tid: Versions.RenameWidthHeight,\n\t\t\tup: (asset: any) => {\n\t\t\t\tasset.props.w = asset.props.width\n\t\t\t\tasset.props.h = asset.props.height\n\t\t\t\tdelete asset.props.width\n\t\t\t\tdelete asset.props.height\n\t\t\t},\n\t\t\tdown: (asset: any) => {\n\t\t\t\tasset.props.width = asset.props.w\n\t\t\t\tasset.props.height = asset.props.h\n\t\t\t\tdelete asset.props.w\n\t\t\t\tdelete asset.props.h\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tid: Versions.MakeUrlsValid,\n\t\t\tup: (asset: any) => {\n\t\t\t\tif (!T.srcUrl.isValid(asset.props.src)) {\n\t\t\t\t\tasset.props.src = ''\n\t\t\t\t}\n\t\t\t},\n\t\t\tdown: (_asset) => {\n\t\t\t\t// noop\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tid: Versions.AddFileSize,\n\t\t\tup: (asset: any) => {\n\t\t\t\tasset.props.fileSize = -1\n\t\t\t},\n\t\t\tdown: (asset: any) => {\n\t\t\t\tdelete asset.props.fileSize\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tid: Versions.MakeFileSizeOptional,\n\t\t\tup: (asset: any) => {\n\t\t\t\tif (asset.props.fileSize === -1) {\n\t\t\t\t\tasset.props.fileSize = undefined\n\t\t\t\t}\n\t\t\t},\n\t\t\tdown: (asset: any) => {\n\t\t\t\tif (asset.props.fileSize === undefined) {\n\t\t\t\t\tasset.props.fileSize = -1\n\t\t\t\t}\n\t\t\t},\n\t\t},\n\t],\n})\n", "import {\n\tcreateMigrationIds,\n\tcreateRecordMigrationSequence,\n\tcreateRecordType,\n\tRecordId,\n} from '@tldraw/store'\nimport { T } from '@tldraw/validate'\nimport { TLBaseAsset } from '../assets/TLBaseAsset'\nimport { bookmarkAssetValidator, TLBookmarkAsset } from '../assets/TLBookmarkAsset'\nimport { imageAssetValidator, TLImageAsset } from '../assets/TLImageAsset'\nimport { TLVideoAsset, videoAssetValidator } from '../assets/TLVideoAsset'\nimport { TLShape } from './TLShape'\n\n/** @public */\nexport type TLAsset = TLImageAsset | TLVideoAsset | TLBookmarkAsset\n\n/** @public */\nexport const assetValidator: T.Validator = T.model(\n\t'asset',\n\tT.union('type', {\n\t\timage: imageAssetValidator,\n\t\tvideo: videoAssetValidator,\n\t\tbookmark: bookmarkAssetValidator,\n\t})\n)\n\n/** @public */\nexport const assetVersions = createMigrationIds('com.tldraw.asset', {\n\tAddMeta: 1,\n} as const)\n\n/** @public */\nexport const assetMigrations = createRecordMigrationSequence({\n\tsequenceId: 'com.tldraw.asset',\n\trecordType: 'asset',\n\tsequence: [\n\t\t{\n\t\t\tid: assetVersions.AddMeta,\n\t\t\tup: (record) => {\n\t\t\t\t;(record as any).meta = {}\n\t\t\t},\n\t\t},\n\t],\n})\n\n/** @public */\nexport type TLAssetPartial = T extends T\n\t? {\n\t\t\tid: TLAssetId\n\t\t\ttype: T['type']\n\t\t\tprops?: Partial\n\t\t\tmeta?: Partial\n\t\t} & Partial>\n\t: never\n\n/** @public */\nexport const AssetRecordType = createRecordType('asset', {\n\tvalidator: assetValidator,\n\tscope: 'document',\n}).withDefaultProperties(() => ({\n\tmeta: {},\n}))\n\n/** @public */\nexport type TLAssetId = RecordId>\n\n/** @public */\nexport type TLAssetShape = Extract\n", "import { T } from '@tldraw/validate'\nimport { assetIdValidator } from '../assets/TLBaseAsset'\nimport { TLAssetId } from '../records/TLAsset'\nimport { createShapePropsMigrationIds, createShapePropsMigrationSequence } from '../records/TLShape'\nimport { RecordProps } from '../recordsWithProps'\nimport { TLBaseShape } from './TLBaseShape'\n\n/** @public */\nexport interface TLBookmarkShapeProps {\n\tw: number\n\th: number\n\tassetId: TLAssetId | null\n\turl: string\n}\n\n/** @public */\nexport type TLBookmarkShape = TLBaseShape<'bookmark', TLBookmarkShapeProps>\n\n/** @public */\nexport const bookmarkShapeProps: RecordProps = {\n\tw: T.nonZeroNumber,\n\th: T.nonZeroNumber,\n\tassetId: assetIdValidator.nullable(),\n\turl: T.linkUrl,\n}\n\nconst Versions = createShapePropsMigrationIds('bookmark', {\n\tNullAssetId: 1,\n\tMakeUrlsValid: 2,\n})\n\nexport { Versions as bookmarkShapeVersions }\n\n/** @public */\nexport const bookmarkShapeMigrations = createShapePropsMigrationSequence({\n\tsequence: [\n\t\t{\n\t\t\tid: Versions.NullAssetId,\n\t\t\tup: (props) => {\n\t\t\t\tif (props.assetId === undefined) {\n\t\t\t\t\tprops.assetId = null\n\t\t\t\t}\n\t\t\t},\n\t\t\tdown: 'retired',\n\t\t},\n\t\t{\n\t\t\tid: Versions.MakeUrlsValid,\n\t\t\tup: (props) => {\n\t\t\t\tif (!T.linkUrl.isValid(props.url)) {\n\t\t\t\t\tprops.url = ''\n\t\t\t\t}\n\t\t\t},\n\t\t\tdown: (_props) => {\n\t\t\t\t// noop\n\t\t\t},\n\t\t},\n\t],\n})\n", "import { T } from '@tldraw/validate'\nimport { VecModel, vecModelValidator } from '../misc/geometry-types'\nimport { createShapePropsMigrationIds, createShapePropsMigrationSequence } from '../records/TLShape'\nimport { RecordProps } from '../recordsWithProps'\nimport { DefaultColorStyle, TLDefaultColorStyle } from '../styles/TLColorStyle'\nimport { DefaultDashStyle, TLDefaultDashStyle } from '../styles/TLDashStyle'\nimport { DefaultFillStyle, TLDefaultFillStyle } from '../styles/TLFillStyle'\nimport { DefaultSizeStyle, TLDefaultSizeStyle } from '../styles/TLSizeStyle'\nimport { TLBaseShape } from './TLBaseShape'\n\n/** @public */\nexport interface TLDrawShapeSegment {\n\ttype: 'free' | 'straight'\n\tpoints: VecModel[]\n}\n\n/** @public */\nexport const DrawShapeSegment: T.ObjectValidator = T.object({\n\ttype: T.literalEnum('free', 'straight'),\n\tpoints: T.arrayOf(vecModelValidator),\n})\n\n/** @public */\nexport interface TLDrawShapeProps {\n\tcolor: TLDefaultColorStyle\n\tfill: TLDefaultFillStyle\n\tdash: TLDefaultDashStyle\n\tsize: TLDefaultSizeStyle\n\tsegments: TLDrawShapeSegment[]\n\tisComplete: boolean\n\tisClosed: boolean\n\tisPen: boolean\n\tscale: number\n}\n\n/** @public */\nexport type TLDrawShape = TLBaseShape<'draw', TLDrawShapeProps>\n\n/** @public */\nexport const drawShapeProps: RecordProps = {\n\tcolor: DefaultColorStyle,\n\tfill: DefaultFillStyle,\n\tdash: DefaultDashStyle,\n\tsize: DefaultSizeStyle,\n\tsegments: T.arrayOf(DrawShapeSegment),\n\tisComplete: T.boolean,\n\tisClosed: T.boolean,\n\tisPen: T.boolean,\n\tscale: T.nonZeroNumber,\n}\n\nconst Versions = createShapePropsMigrationIds('draw', {\n\tAddInPen: 1,\n\tAddScale: 2,\n})\n\nexport { Versions as drawShapeVersions }\n\n/** @public */\nexport const drawShapeMigrations = createShapePropsMigrationSequence({\n\tsequence: [\n\t\t{\n\t\t\tid: Versions.AddInPen,\n\t\t\tup: (props) => {\n\t\t\t\t// Rather than checking to see whether the shape is a pen at runtime,\n\t\t\t\t// from now on we're going to use the type of device reported to us\n\t\t\t\t// as well as the pressure data received; but for existing shapes we\n\t\t\t\t// need to check the pressure data to see if it's a pen or not.\n\n\t\t\t\tconst { points } = props.segments[0]\n\n\t\t\t\tif (points.length === 0) {\n\t\t\t\t\tprops.isPen = false\n\t\t\t\t\treturn\n\t\t\t\t}\n\n\t\t\t\tlet isPen = !(points[0].z === 0 || points[0].z === 0.5)\n\n\t\t\t\tif (points[1]) {\n\t\t\t\t\t// Double check if we have a second point (we probably should)\n\t\t\t\t\tisPen = isPen && !(points[1].z === 0 || points[1].z === 0.5)\n\t\t\t\t}\n\t\t\t\tprops.isPen = isPen\n\t\t\t},\n\t\t\tdown: 'retired',\n\t\t},\n\t\t{\n\t\t\tid: Versions.AddScale,\n\t\t\tup: (props) => {\n\t\t\t\tprops.scale = 1\n\t\t\t},\n\t\t\tdown: (props) => {\n\t\t\t\tdelete props.scale\n\t\t\t},\n\t\t},\n\t],\n})\n", "import { T } from '@tldraw/validate'\nimport { createShapePropsMigrationIds, createShapePropsMigrationSequence } from '../records/TLShape'\nimport { RecordProps } from '../recordsWithProps'\nimport { TLBaseShape } from './TLBaseShape'\n\n// Only allow multiplayer embeds. If we add additional routes later for example '/help' this won't match\nconst TLDRAW_APP_RE = /(^\\/r\\/[^/]+\\/?$)/\n\nconst safeParseUrl = (url: string) => {\n\ttry {\n\t\treturn new URL(url)\n\t} catch (err) {\n\t\treturn\n\t}\n}\n\n/** @public */\nexport const EMBED_DEFINITIONS = [\n\t{\n\t\ttype: 'tldraw',\n\t\ttitle: 'tldraw',\n\t\thostnames: ['beta.tldraw.com', 'tldraw.com', 'localhost:3000'],\n\t\tminWidth: 300,\n\t\tminHeight: 300,\n\t\twidth: 720,\n\t\theight: 500,\n\t\tdoesResize: true,\n\t\toverridePermissions: {\n\t\t\t'allow-top-navigation': true,\n\t\t},\n\t\ttoEmbedUrl: (url) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\tif (urlObj && urlObj.pathname.match(TLDRAW_APP_RE)) {\n\t\t\t\treturn url\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t\tfromEmbedUrl: (url) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\tif (urlObj && urlObj.pathname.match(TLDRAW_APP_RE)) {\n\t\t\t\treturn url\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t},\n\t{\n\t\ttype: 'figma',\n\t\ttitle: 'Figma',\n\t\thostnames: ['figma.com'],\n\t\twidth: 720,\n\t\theight: 500,\n\t\tdoesResize: true,\n\t\ttoEmbedUrl: (url) => {\n\t\t\tif (\n\t\t\t\t!!url.match(\n\t\t\t\t\t// eslint-disable-next-line no-useless-escape\n\t\t\t\t\t/https:\\/\\/([\\w\\.-]+\\.)?figma.com\\/(file|proto)\\/([0-9a-zA-Z]{22,128})(?:\\/.*)?$/\n\t\t\t\t) &&\n\t\t\t\t!url.includes('figma.com/embed')\n\t\t\t) {\n\t\t\t\treturn `https://www.figma.com/embed?embed_host=share&url=${url}`\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t\tfromEmbedUrl: (url) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\tif (urlObj && urlObj.pathname.match(/^\\/embed\\/?$/)) {\n\t\t\t\tconst outUrl = urlObj.searchParams.get('url')\n\t\t\t\tif (outUrl) {\n\t\t\t\t\treturn outUrl\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t},\n\t{\n\t\ttype: 'google_maps',\n\t\ttitle: 'Google Maps',\n\t\thostnames: ['google.*'],\n\t\twidth: 720,\n\t\theight: 500,\n\t\tdoesResize: true,\n\t\toverridePermissions: {\n\t\t\t'allow-presentation': true,\n\t\t},\n\t\ttoEmbedUrl: (url) => {\n\t\t\tif (url.includes('/maps/')) {\n\t\t\t\tconst match = url.match(/@(.*),(.*),(.*)z/)\n\t\t\t\tlet result: string\n\t\t\t\tif (match) {\n\t\t\t\t\tconst [, lat, lng, z] = match\n\t\t\t\t\tconst host = new URL(url).host.replace('www.', '')\n\t\t\t\t\tresult = `https://${host}/maps/embed/v1/view?key=${process.env.NEXT_PUBLIC_GC_API_KEY}¢er=${lat},${lng}&zoom=${z}`\n\t\t\t\t} else {\n\t\t\t\t\tresult = ''\n\t\t\t\t}\n\n\t\t\t\treturn result\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t\tfromEmbedUrl: (url) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\tif (!urlObj) return\n\n\t\t\tconst matches = urlObj.pathname.match(/^\\/maps\\/embed\\/v1\\/view\\/?$/)\n\t\t\tif (matches && urlObj.searchParams.has('center') && urlObj.searchParams.get('zoom')) {\n\t\t\t\tconst zoom = urlObj.searchParams.get('zoom')\n\t\t\t\tconst [lat, lon] = urlObj.searchParams.get('center')!.split(',')\n\t\t\t\treturn `https://www.google.com/maps/@${lat},${lon},${zoom}z`\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t},\n\t{\n\t\ttype: 'val_town',\n\t\ttitle: 'Val Town',\n\t\thostnames: ['val.town'],\n\t\tminWidth: 260,\n\t\tminHeight: 100,\n\t\twidth: 720,\n\t\theight: 500,\n\t\tdoesResize: true,\n\t\ttoEmbedUrl: (url) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\t// e.g. extract \"steveruizok/mathFact\" from https://www.val.town/v/steveruizok/mathFact\n\t\t\tconst matches = urlObj && urlObj.pathname.match(/\\/v\\/(.+)\\/?/)\n\t\t\tif (matches) {\n\t\t\t\treturn `https://www.val.town/embed/${matches[1]}`\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t\tfromEmbedUrl: (url) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\t// e.g. extract \"steveruizok/mathFact\" from https://www.val.town/v/steveruizok/mathFact\n\t\t\tconst matches = urlObj && urlObj.pathname.match(/\\/embed\\/(.+)\\/?/)\n\t\t\tif (matches) {\n\t\t\t\treturn `https://www.val.town/v/${matches[1]}`\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t},\n\t{\n\t\ttype: 'codesandbox',\n\t\ttitle: 'CodeSandbox',\n\t\thostnames: ['codesandbox.io'],\n\t\tminWidth: 300,\n\t\tminHeight: 300,\n\t\twidth: 720,\n\t\theight: 500,\n\t\tdoesResize: true,\n\t\ttoEmbedUrl: (url) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\tconst matches = urlObj && urlObj.pathname.match(/\\/s\\/([^/]+)\\/?/)\n\t\t\tif (matches) {\n\t\t\t\treturn `https://codesandbox.io/embed/${matches[1]}`\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t\tfromEmbedUrl: (url) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\tconst matches = urlObj && urlObj.pathname.match(/\\/embed\\/([^/]+)\\/?/)\n\t\t\tif (matches) {\n\t\t\t\treturn `https://codesandbox.io/s/${matches[1]}`\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t},\n\t{\n\t\ttype: 'codepen',\n\t\ttitle: 'Codepen',\n\t\thostnames: ['codepen.io'],\n\t\tminWidth: 300,\n\t\tminHeight: 300,\n\t\twidth: 520,\n\t\theight: 400,\n\t\tdoesResize: true,\n\t\ttoEmbedUrl: (url) => {\n\t\t\tconst CODEPEN_URL_REGEXP = /https:\\/\\/codepen.io\\/([^/]+)\\/pen\\/([^/]+)/\n\t\t\tconst matches = url.match(CODEPEN_URL_REGEXP)\n\t\t\tif (matches) {\n\t\t\t\tconst [_, user, id] = matches\n\t\t\t\treturn `https://codepen.io/${user}/embed/${id}`\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t\tfromEmbedUrl: (url) => {\n\t\t\tconst CODEPEN_EMBED_REGEXP = /https:\\/\\/codepen.io\\/([^/]+)\\/embed\\/([^/]+)/\n\t\t\tconst matches = url.match(CODEPEN_EMBED_REGEXP)\n\t\t\tif (matches) {\n\t\t\t\tconst [_, user, id] = matches\n\t\t\t\treturn `https://codepen.io/${user}/pen/${id}`\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t},\n\t{\n\t\ttype: 'scratch',\n\t\ttitle: 'Scratch',\n\t\thostnames: ['scratch.mit.edu'],\n\t\twidth: 520,\n\t\theight: 400,\n\t\tdoesResize: false,\n\t\ttoEmbedUrl: (url) => {\n\t\t\tconst SCRATCH_URL_REGEXP = /https?:\\/\\/scratch.mit.edu\\/projects\\/([^/]+)/\n\t\t\tconst matches = url.match(SCRATCH_URL_REGEXP)\n\t\t\tif (matches) {\n\t\t\t\tconst [_, id] = matches\n\t\t\t\treturn `https://scratch.mit.edu/projects/embed/${id}`\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t\tfromEmbedUrl: (url) => {\n\t\t\tconst SCRATCH_EMBED_REGEXP = /https:\\/\\/scratch.mit.edu\\/projects\\/embed\\/([^/]+)/\n\t\t\tconst matches = url.match(SCRATCH_EMBED_REGEXP)\n\t\t\tif (matches) {\n\t\t\t\tconst [_, id] = matches\n\t\t\t\treturn `https://scratch.mit.edu/projects/${id}`\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t},\n\t{\n\t\ttype: 'youtube',\n\t\ttitle: 'YouTube',\n\t\thostnames: ['*.youtube.com', 'youtube.com', 'youtu.be'],\n\t\twidth: 800,\n\t\theight: 450,\n\t\tdoesResize: true,\n\t\toverridePermissions: {\n\t\t\t'allow-presentation': true,\n\t\t\t'allow-popups-to-escape-sandbox': true,\n\t\t},\n\t\tisAspectRatioLocked: true,\n\t\ttoEmbedUrl: (url) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\tif (!urlObj) return\n\n\t\t\tconst hostname = urlObj.hostname.replace(/^www./, '')\n\t\t\tif (hostname === 'youtu.be') {\n\t\t\t\tconst videoId = urlObj.pathname.split('/').filter(Boolean)[0]\n\t\t\t\treturn `https://www.youtube.com/embed/${videoId}`\n\t\t\t} else if (\n\t\t\t\t(hostname === 'youtube.com' || hostname === 'm.youtube.com') &&\n\t\t\t\turlObj.pathname.match(/^\\/watch/)\n\t\t\t) {\n\t\t\t\tconst videoId = urlObj.searchParams.get('v')\n\t\t\t\treturn `https://www.youtube.com/embed/${videoId}`\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t\tfromEmbedUrl: (url) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\tif (!urlObj) return\n\n\t\t\tconst hostname = urlObj.hostname.replace(/^www./, '')\n\t\t\tif (hostname === 'youtube.com') {\n\t\t\t\tconst matches = urlObj.pathname.match(/^\\/embed\\/([^/]+)\\/?/)\n\t\t\t\tif (matches) {\n\t\t\t\t\treturn `https://www.youtube.com/watch?v=${matches[1]}`\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t},\n\t{\n\t\ttype: 'google_calendar',\n\t\ttitle: 'Google Calendar',\n\t\thostnames: ['calendar.google.*'],\n\t\twidth: 720,\n\t\theight: 500,\n\t\tminWidth: 460,\n\t\tminHeight: 360,\n\t\tdoesResize: true,\n\t\tinstructionLink: 'https://support.google.com/calendar/answer/41207?hl=en',\n\t\toverridePermissions: {\n\t\t\t'allow-popups-to-escape-sandbox': true,\n\t\t},\n\t\ttoEmbedUrl: (url) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\tconst cidQs = urlObj?.searchParams.get('cid')\n\n\t\t\tif (urlObj?.pathname.match(/\\/calendar\\/u\\/0/) && cidQs) {\n\t\t\t\turlObj.pathname = '/calendar/embed'\n\n\t\t\t\tconst keys = Array.from(urlObj.searchParams.keys())\n\t\t\t\tfor (const key of keys) {\n\t\t\t\t\turlObj.searchParams.delete(key)\n\t\t\t\t}\n\t\t\t\turlObj.searchParams.set('src', cidQs)\n\t\t\t\treturn urlObj.href\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t\tfromEmbedUrl: (url) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\tconst srcQs = urlObj?.searchParams.get('src')\n\n\t\t\tif (urlObj?.pathname.match(/\\/calendar\\/embed/) && srcQs) {\n\t\t\t\turlObj.pathname = '/calendar/u/0'\n\t\t\t\tconst keys = Array.from(urlObj.searchParams.keys())\n\t\t\t\tfor (const key of keys) {\n\t\t\t\t\turlObj.searchParams.delete(key)\n\t\t\t\t}\n\t\t\t\turlObj.searchParams.set('cid', srcQs)\n\t\t\t\treturn urlObj.href\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t},\n\t{\n\t\ttype: 'google_slides',\n\t\ttitle: 'Google Slides',\n\t\thostnames: ['docs.google.*'],\n\t\twidth: 720,\n\t\theight: 500,\n\t\tminWidth: 460,\n\t\tminHeight: 360,\n\t\tdoesResize: true,\n\t\toverridePermissions: {\n\t\t\t'allow-popups-to-escape-sandbox': true,\n\t\t},\n\t\ttoEmbedUrl: (url) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\n\t\t\tif (urlObj?.pathname.match(/^\\/presentation/) && urlObj?.pathname.match(/\\/pub\\/?$/)) {\n\t\t\t\turlObj.pathname = urlObj.pathname.replace(/\\/pub$/, '/embed')\n\t\t\t\tconst keys = Array.from(urlObj.searchParams.keys())\n\t\t\t\tfor (const key of keys) {\n\t\t\t\t\turlObj.searchParams.delete(key)\n\t\t\t\t}\n\t\t\t\treturn urlObj.href\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t\tfromEmbedUrl: (url) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\n\t\t\tif (urlObj?.pathname.match(/^\\/presentation/) && urlObj?.pathname.match(/\\/embed\\/?$/)) {\n\t\t\t\turlObj.pathname = urlObj.pathname.replace(/\\/embed$/, '/pub')\n\t\t\t\tconst keys = Array.from(urlObj.searchParams.keys())\n\t\t\t\tfor (const key of keys) {\n\t\t\t\t\turlObj.searchParams.delete(key)\n\t\t\t\t}\n\t\t\t\treturn urlObj.href\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t},\n\t{\n\t\ttype: 'github_gist',\n\t\ttitle: 'GitHub Gist',\n\t\thostnames: ['gist.github.com'],\n\t\twidth: 720,\n\t\theight: 500,\n\t\tdoesResize: true,\n\t\ttoEmbedUrl: (url) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\tif (urlObj && urlObj.pathname.match(/\\/([^/]+)\\/([^/]+)/)) {\n\t\t\t\tif (!url.split('/').pop()) return\n\t\t\t\treturn url\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t\tfromEmbedUrl: (url) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\tif (urlObj && urlObj.pathname.match(/\\/([^/]+)\\/([^/]+)/)) {\n\t\t\t\tif (!url.split('/').pop()) return\n\t\t\t\treturn url\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t},\n\t{\n\t\ttype: 'replit',\n\t\ttitle: 'Replit',\n\t\thostnames: ['replit.com'],\n\t\twidth: 720,\n\t\theight: 500,\n\t\tdoesResize: true,\n\t\ttoEmbedUrl: (url) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\tif (urlObj && urlObj.pathname.match(/\\/@([^/]+)\\/([^/]+)/)) {\n\t\t\t\treturn `${url}?embed=true`\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t\tfromEmbedUrl: (url) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\tif (\n\t\t\t\turlObj &&\n\t\t\t\turlObj.pathname.match(/\\/@([^/]+)\\/([^/]+)/) &&\n\t\t\t\turlObj.searchParams.has('embed')\n\t\t\t) {\n\t\t\t\turlObj.searchParams.delete('embed')\n\t\t\t\treturn urlObj.href\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t},\n\t{\n\t\ttype: 'felt',\n\t\ttitle: 'Felt',\n\t\thostnames: ['felt.com'],\n\t\twidth: 720,\n\t\theight: 500,\n\t\tdoesResize: true,\n\t\ttoEmbedUrl: (url) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\tif (urlObj && urlObj.pathname.match(/^\\/map\\//)) {\n\t\t\t\treturn urlObj.origin + '/embed' + urlObj.pathname\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t\tfromEmbedUrl: (url) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\tif (urlObj && urlObj.pathname.match(/^\\/embed\\/map\\//)) {\n\t\t\t\turlObj.pathname = urlObj.pathname.replace(/^\\/embed/, '')\n\t\t\t\treturn urlObj.href\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t},\n\t{\n\t\ttype: 'spotify',\n\t\ttitle: 'Spotify',\n\t\thostnames: ['open.spotify.com'],\n\t\twidth: 720,\n\t\theight: 500,\n\t\tminHeight: 500,\n\t\toverrideOutlineRadius: 12,\n\t\tdoesResize: true,\n\t\ttoEmbedUrl: (url) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\tif (urlObj && urlObj.pathname.match(/^\\/(artist|album)\\//)) {\n\t\t\t\treturn urlObj.origin + '/embed' + urlObj.pathname\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t\tfromEmbedUrl: (url) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\tif (urlObj && urlObj.pathname.match(/^\\/embed\\/(artist|album)\\//)) {\n\t\t\t\treturn urlObj.origin + urlObj.pathname.replace(/^\\/embed/, '')\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t},\n\t{\n\t\ttype: 'vimeo',\n\t\ttitle: 'Vimeo',\n\t\thostnames: ['vimeo.com', 'player.vimeo.com'],\n\t\twidth: 640,\n\t\theight: 360,\n\t\tdoesResize: true,\n\t\tisAspectRatioLocked: true,\n\t\ttoEmbedUrl: (url) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\tif (urlObj && urlObj.hostname === 'vimeo.com') {\n\t\t\t\tif (urlObj.pathname.match(/^\\/[0-9]+/)) {\n\t\t\t\t\treturn (\n\t\t\t\t\t\t'https://player.vimeo.com/video/' + urlObj.pathname.split('/')[1] + '?title=0&byline=0'\n\t\t\t\t\t)\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t\tfromEmbedUrl: (url) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\tif (urlObj && urlObj.hostname === 'player.vimeo.com') {\n\t\t\t\tconst matches = urlObj.pathname.match(/^\\/video\\/([^/]+)\\/?$/)\n\t\t\t\tif (matches) {\n\t\t\t\t\treturn 'https://vimeo.com/' + matches[1]\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t},\n\t{\n\t\ttype: 'excalidraw',\n\t\ttitle: 'Excalidraw',\n\t\thostnames: ['excalidraw.com'],\n\t\twidth: 720,\n\t\theight: 500,\n\t\tdoesResize: true,\n\t\tisAspectRatioLocked: true,\n\t\ttoEmbedUrl: (url) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\tif (urlObj && urlObj.hash.match(/#room=/)) {\n\t\t\t\treturn url\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t\tfromEmbedUrl: (url) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\tif (urlObj && urlObj.hash.match(/#room=/)) {\n\t\t\t\treturn url\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t},\n\t{\n\t\ttype: 'observable',\n\t\ttitle: 'Observable',\n\t\thostnames: ['observablehq.com'],\n\t\twidth: 720,\n\t\theight: 500,\n\t\tdoesResize: true,\n\t\tisAspectRatioLocked: false,\n\t\tbackgroundColor: '#fff',\n\t\ttoEmbedUrl: (url) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\tif (urlObj && urlObj.pathname.match(/^\\/@([^/]+)\\/([^/]+)\\/?$/)) {\n\t\t\t\treturn `${urlObj.origin}/embed${urlObj.pathname}?cell=*`\n\t\t\t}\n\t\t\tif (urlObj && urlObj.pathname.match(/^\\/d\\/([^/]+)\\/?$/)) {\n\t\t\t\tconst pathName = urlObj.pathname.replace(/^\\/d/, '')\n\t\t\t\treturn `${urlObj.origin}/embed${pathName}?cell=*`\n\t\t\t}\n\n\t\t\treturn\n\t\t},\n\t\tfromEmbedUrl: (url) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\tif (urlObj && urlObj.pathname.match(/^\\/embed\\/@([^/]+)\\/([^/]+)\\/?$/)) {\n\t\t\t\treturn `${urlObj.origin}${urlObj.pathname.replace('/embed', '')}#cell-*`\n\t\t\t}\n\t\t\tif (urlObj && urlObj.pathname.match(/^\\/embed\\/([^/]+)\\/?$/)) {\n\t\t\t\treturn `${urlObj.origin}${urlObj.pathname.replace('/embed', '/d')}#cell-*`\n\t\t\t}\n\n\t\t\treturn\n\t\t},\n\t},\n\t{\n\t\ttype: 'desmos',\n\t\ttitle: 'Desmos',\n\t\thostnames: ['desmos.com'],\n\t\twidth: 700,\n\t\theight: 450,\n\t\tdoesResize: true,\n\t\ttoEmbedUrl: (url) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\tif (\n\t\t\t\turlObj &&\n\t\t\t\turlObj.hostname === 'www.desmos.com' &&\n\t\t\t\turlObj.pathname.match(/^\\/calculator\\/([^/]+)\\/?$/) &&\n\t\t\t\turlObj.search === '' &&\n\t\t\t\turlObj.hash === ''\n\t\t\t) {\n\t\t\t\treturn `${url}?embed`\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t\tfromEmbedUrl: (url) => {\n\t\t\tconst urlObj = safeParseUrl(url)\n\t\t\tif (\n\t\t\t\turlObj &&\n\t\t\t\turlObj.hostname === 'www.desmos.com' &&\n\t\t\t\turlObj.pathname.match(/^\\/calculator\\/([^/]+)\\/?$/) &&\n\t\t\t\turlObj.search === '?embed' &&\n\t\t\t\turlObj.hash === ''\n\t\t\t) {\n\t\t\t\treturn url.replace('?embed', '')\n\t\t\t}\n\t\t\treturn\n\t\t},\n\t},\n] as const satisfies readonly EmbedDefinition[]\n\n/**\n * Permissions with note inline from\n * https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe#attr-sandbox\n *\n * @public\n */\nexport const embedShapePermissionDefaults = {\n\t// ========================================================================================\n\t// Disabled permissions\n\t// ========================================================================================\n\t// [MDN] Experimental: Allows for downloads to occur without a gesture from the user.\n\t// [REASON] Disabled because otherwise the