canvas-website/.wrangler/tmp/dev-xuTKLz/worker.js

9355 lines
275 KiB
JavaScript

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-VlWfGj/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-VlWfGj/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-VlWfGj/middleware-loader.entry.ts
init_checked_fetch();
init_modules_watch_stub();
// .wrangler/tmp/bundle-VlWfGj/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.<string, string|null>}
*/
og = {};
/**
* The Twitter metadata extracted from elements.
* @type {Object.<string, string|null>}
*/
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) {
try {
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 };
} catch (error) {
console.error("Asset upload failed:", error);
return new Response(`Upload failed: ${error.message}`, { status: 500 });
}
}
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/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/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/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/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/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 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/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 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/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/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/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/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 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/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/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/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/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/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/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/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/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/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/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 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/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_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/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_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/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/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/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/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/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/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/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 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/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 = "<redacted>";
}
if ("src" in record.props) {
record.props.src = "<redacted>";
}
}
}
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/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/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/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/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/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/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/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}&center=${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/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/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 DefaultHorizontalAlignStyle = StyleProp.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 DefaultVerticalAlignStyle = StyleProp.defineEnum("tldraw:verticalAlign", {
defaultValue: "middle",
values: ["start", "middle", "end"]
});
// 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/tlschema/dist-esm/shapes/TLGroupShape.mjs
init_checked_fetch();
init_modules_watch_stub();
var groupShapeProps = {};
var groupShapeMigrations = createShapePropsMigrationSequence({ sequence: [] });
// 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/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/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/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/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 DefaultTextAlignStyle = StyleProp.defineEnum("tldraw:textAlign", {
defaultValue: "start",
values: ["start", "middle", "end"]
});
// 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/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/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/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/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();
// 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: {}
};
}
// worker/TldrawDurableObject.ts
var import_lodash7 = __toESM(require_lodash(), 1);
var schema = createTLSchema({
shapes: { ...defaultShapeSchemas }
// 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-VlWfGj/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-VlWfGj/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 <https://github.com/qzb/is-animated>
* Copyright (c) 2016 Józef Sokołowski <j.k.sokolowski@gmail.com>
*)
@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 <sindresorhus@gmail.com> (https://sindresorhus.com)
*)
*/
//# sourceMappingURL=worker.js.map