@ibodr/schema 0.2.5 → 0.2.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { structuredClone, sortByIndex, objectMapFromEntries, getIndices, objectMapEntries, registerDrawLibraryVersion, mapObjectMapValues, uniqueId, safeParseUrl, assert, filterEntries, objectMapValues, annotateError } from '@ibodr/utils';
1
+ import { structuredClone, sortByIndex, objectMapFromEntries, getIndices, objectMapEntries, registerDrawLibraryVersion, mapObjectMapValues, uniqueId, safeParseUrl, filterEntries, objectMapValues, annotateError, assert } from '@ibodr/utils';
2
2
  import { T } from '@ibodr/validate';
3
3
  import { createMigrationIds, createRecordMigrationSequence, createMigrationSequence, createRecordType, StoreSchema, RecordType } from '@ibodr/store';
4
4
  import { computed } from '@ibodr/state';
@@ -1046,6 +1046,49 @@ var arrowBindingMigrations = createBindingPropsMigrationSequence({
1046
1046
  }
1047
1047
  ]
1048
1048
  });
1049
+ var assetVersions = createMigrationIds("com.draw.asset", {
1050
+ AddMeta: 1
1051
+ });
1052
+ var assetMigrations = createRecordMigrationSequence({
1053
+ sequenceId: "com.draw.asset",
1054
+ recordType: "asset",
1055
+ sequence: [
1056
+ {
1057
+ id: assetVersions.AddMeta,
1058
+ up: (record) => {
1059
+ record.meta = {};
1060
+ }
1061
+ }
1062
+ ]
1063
+ });
1064
+ function createAssetRecordType(assets) {
1065
+ return createRecordType("asset", {
1066
+ scope: "document",
1067
+ validator: T.model(
1068
+ "asset",
1069
+ T.union(
1070
+ "type",
1071
+ mapObjectMapValues(
1072
+ assets,
1073
+ (type, { props, meta }) => createAssetValidator(type, props, meta)
1074
+ )
1075
+ )
1076
+ )
1077
+ }).withDefaultProperties(() => ({
1078
+ meta: {}
1079
+ }));
1080
+ }
1081
+ var AssetRecordType = createRecordType("asset", {
1082
+ scope: "document"
1083
+ }).withDefaultProperties(() => ({
1084
+ meta: {}
1085
+ }));
1086
+ function createAssetPropsMigrationSequence(migrations) {
1087
+ return migrations;
1088
+ }
1089
+ function createAssetPropsMigrationIds(assetType, ids) {
1090
+ return mapObjectMapValues(ids, (_k, v) => `com.draw.asset.${assetType}/${v}`);
1091
+ }
1049
1092
  var cameraValidator = T.model(
1050
1093
  "camera",
1051
1094
  T.object({
@@ -1083,11 +1126,132 @@ var CameraRecordType = createRecordType("camera", {
1083
1126
  meta: {}
1084
1127
  })
1085
1128
  );
1129
+ function createCustomRecordType(typeName, config) {
1130
+ return createRecordType(typeName, {
1131
+ scope: config.scope,
1132
+ validator: config.validator
1133
+ }).withDefaultProperties(config.createDefaultProperties ?? (() => ({})));
1134
+ }
1135
+ function processCustomRecordMigrations(records) {
1136
+ const result = [];
1137
+ for (const [typeName, config] of Object.entries(records)) {
1138
+ const sequenceId = `com.draw.${typeName}`;
1139
+ const { migrations } = config;
1140
+ if (!migrations) {
1141
+ result.push(
1142
+ createMigrationSequence({
1143
+ sequenceId,
1144
+ retroactive: true,
1145
+ sequence: []
1146
+ })
1147
+ );
1148
+ } else if ("sequenceId" in migrations) {
1149
+ assert(
1150
+ sequenceId === migrations.sequenceId,
1151
+ `sequenceId mismatch for ${typeName} custom record migrations. Expected '${sequenceId}', got '${migrations.sequenceId}'`
1152
+ );
1153
+ result.push(migrations);
1154
+ } else if ("sequence" in migrations) {
1155
+ result.push(
1156
+ createMigrationSequence({
1157
+ sequenceId,
1158
+ retroactive: true,
1159
+ sequence: migrations.sequence.map((m) => {
1160
+ if (!("id" in m)) return m;
1161
+ return {
1162
+ id: m.id,
1163
+ dependsOn: m.dependsOn,
1164
+ scope: "record",
1165
+ filter: (r) => r.typeName === typeName,
1166
+ up: (record) => {
1167
+ const result2 = m.up(record);
1168
+ if (result2) return result2;
1169
+ },
1170
+ down: typeof m.down === "function" ? (record) => {
1171
+ const result2 = m.down(record);
1172
+ if (result2) return result2;
1173
+ } : void 0
1174
+ };
1175
+ })
1176
+ })
1177
+ );
1178
+ }
1179
+ }
1180
+ return result;
1181
+ }
1182
+ function createCustomRecordMigrationIds(recordType, ids) {
1183
+ return mapObjectMapValues(ids, (_k, v) => `com.draw.${recordType}/${v}`);
1184
+ }
1185
+ function createCustomRecordMigrationSequence(migrations) {
1186
+ return migrations;
1187
+ }
1188
+ function createCustomRecordId(typeName, id) {
1189
+ return `${typeName}:${id ?? uniqueId()}`;
1190
+ }
1191
+ function isCustomRecordId(typeName, id) {
1192
+ if (!id) return false;
1193
+ return id.startsWith(`${typeName}:`);
1194
+ }
1195
+ function isCustomRecord(typeName, record) {
1196
+ if (!record) return false;
1197
+ return record.typeName === typeName;
1198
+ }
1199
+ var documentValidator = T.model(
1200
+ "document",
1201
+ T.object({
1202
+ typeName: T.literal("document"),
1203
+ id: T.literal("document:document"),
1204
+ gridSize: T.number,
1205
+ name: T.string,
1206
+ meta: T.jsonValue
1207
+ })
1208
+ );
1209
+ function isDocument(record) {
1210
+ if (!record) return false;
1211
+ return record.typeName === "document";
1212
+ }
1213
+ var documentVersions = createMigrationIds("com.draw.document", {
1214
+ AddName: 1,
1215
+ AddMeta: 2
1216
+ });
1217
+ var documentMigrations = createRecordMigrationSequence({
1218
+ sequenceId: "com.draw.document",
1219
+ recordType: "document",
1220
+ sequence: [
1221
+ {
1222
+ id: documentVersions.AddName,
1223
+ up: (document) => {
1224
+ document.name = "";
1225
+ },
1226
+ down: (document) => {
1227
+ delete document.name;
1228
+ }
1229
+ },
1230
+ {
1231
+ id: documentVersions.AddMeta,
1232
+ up: (record) => {
1233
+ record.meta = {};
1234
+ }
1235
+ }
1236
+ ]
1237
+ });
1238
+ var DocumentRecordType = createRecordType("document", {
1239
+ validator: documentValidator,
1240
+ scope: "document"
1241
+ }).withDefaultProperties(
1242
+ () => ({
1243
+ gridSize: 10,
1244
+ name: "",
1245
+ meta: {}
1246
+ })
1247
+ );
1248
+ var DrDOCUMENT_ID = DocumentRecordType.createId("document");
1086
1249
  var TL_CURSOR_TYPES = /* @__PURE__ */ new Set([
1087
1250
  "none",
1088
1251
  "default",
1089
1252
  "pointer",
1090
1253
  "cross",
1254
+ "comment",
1091
1255
  "grab",
1092
1256
  "rotate",
1093
1257
  "grabbing",
@@ -1173,9 +1337,80 @@ var PageRecordType = createRecordType("page", {
1173
1337
  }).withDefaultProperties(() => ({
1174
1338
  meta: {}
1175
1339
  }));
1340
+ function isPage(record) {
1341
+ if (!record) return false;
1342
+ return record.typeName === "page";
1343
+ }
1176
1344
  function isPageId(id) {
1177
1345
  return PageRecordType.isId(id);
1178
1346
  }
1347
+ var userIdValidator = idValidator("user");
1348
+ var userVersions = createMigrationIds("com.draw.user", {
1349
+ Initial: 1
1350
+ });
1351
+ var userMigrations = createRecordMigrationSequence({
1352
+ sequenceId: "com.draw.user",
1353
+ recordType: "user",
1354
+ sequence: [
1355
+ {
1356
+ id: userVersions.Initial,
1357
+ up: (_record) => {
1358
+ }
1359
+ }
1360
+ ]
1361
+ });
1362
+ function createUserRecordType(config) {
1363
+ const metaConfig = config?.meta;
1364
+ const metaValidator = metaConfig ? T.object(
1365
+ Object.fromEntries(
1366
+ Object.entries(metaConfig).map(([key, v]) => [
1367
+ key,
1368
+ new T.Validator((value) => {
1369
+ if (value === void 0) return void 0;
1370
+ return v.validate(value);
1371
+ })
1372
+ ])
1373
+ )
1374
+ ).allowUnknownProperties() : T.jsonValue;
1375
+ const validator = T.model(
1376
+ "user",
1377
+ T.object({
1378
+ typeName: T.literal("user"),
1379
+ id: userIdValidator,
1380
+ name: T.string,
1381
+ color: T.string,
1382
+ imageUrl: T.string,
1383
+ meta: metaValidator
1384
+ })
1385
+ );
1386
+ return createRecordType("user", {
1387
+ validator,
1388
+ scope: "document"
1389
+ }).withDefaultProperties(() => ({
1390
+ name: "",
1391
+ color: "",
1392
+ imageUrl: "",
1393
+ meta: {}
1394
+ }));
1395
+ }
1396
+ T.model(
1397
+ "user",
1398
+ T.object({
1399
+ typeName: T.literal("user"),
1400
+ id: userIdValidator,
1401
+ name: T.string,
1402
+ color: T.string,
1403
+ imageUrl: T.string,
1404
+ meta: T.jsonValue
1405
+ })
1406
+ );
1407
+ var UserRecordType = createUserRecordType();
1408
+ function isUserId(id) {
1409
+ return UserRecordType.isId(id);
1410
+ }
1411
+ function createUserId(id) {
1412
+ return UserRecordType.createId(id);
1413
+ }
1179
1414
 
1180
1415
  // src/records/DrInstance.ts
1181
1416
  var DR_BOARD_BACKGROUND_TYPES = [
@@ -1272,7 +1507,7 @@ function createInstanceRecordType(stylesById) {
1272
1507
  typeName: T.literal("instance"),
1273
1508
  id: idValidator("instance"),
1274
1509
  currentPageId: pageIdValidator,
1275
- followingUserId: T.string.nullable(),
1510
+ followingUserId: userIdValidator.nullable(),
1276
1511
  brush: boxModelValidator.nullable(),
1277
1512
  opacityForNextShape: opacityValidator,
1278
1513
  stylesForNextShape: T.object(stylesForNextShapeValidators),
@@ -1290,7 +1525,7 @@ function createInstanceRecordType(stylesById) {
1290
1525
  backgroundType: T.literalEnum(...DR_BOARD_BACKGROUND_TYPES),
1291
1526
  chatMessage: T.string,
1292
1527
  isChatting: T.boolean,
1293
- highlightedUserIds: T.arrayOf(T.string),
1528
+ highlightedUserIds: T.arrayOf(userIdValidator),
1294
1529
  isFocused: T.boolean,
1295
1530
  devicePixelRatio: T.number,
1296
1531
  isCoarsePointer: T.boolean,
@@ -1356,7 +1591,7 @@ function createInstanceRecordType(stylesById) {
1356
1591
  rotation: 0
1357
1592
  },
1358
1593
  isFocusMode: false,
1359
- exportBackground: false,
1594
+ exportBackground: true,
1360
1595
  isDebugMode: false,
1361
1596
  isToolLocked: false,
1362
1597
  screenBounds: { x: 0, y: 0, w: 1080, h: 720 },
@@ -1788,7 +2023,11 @@ var InstancePageStateRecordType = createRecordType(
1788
2023
  ephemeralKeys: {
1789
2024
  pageId: false,
1790
2025
  selectedShapeIds: false,
1791
- editingShapeId: false,
2026
+ // editingShapeId is set with `history: 'ignore'`, so entering the editing
2027
+ // state is never undoable. Marking it ephemeral keeps undo/redo from
2028
+ // reapplying a stale editingShapeId (e.g. after a shape it pointed at was
2029
+ // deleted), which could leave the editor pointing at a missing shape.
2030
+ editingShapeId: true,
1792
2031
  croppingShapeId: false,
1793
2032
  meta: false,
1794
2033
  hintingShapeIds: true,
@@ -1852,10 +2091,10 @@ var instancePresenceValidator = T.model(
1852
2091
  T.object({
1853
2092
  typeName: T.literal("instance_presence"),
1854
2093
  id: idValidator("instance_presence"),
1855
- userId: T.string,
2094
+ userId: userIdValidator,
1856
2095
  userName: T.string,
1857
2096
  lastActivityTimestamp: T.number.nullable(),
1858
- followingUserId: T.string.nullable(),
2097
+ followingUserId: userIdValidator.nullable(),
1859
2098
  cursor: T.object({
1860
2099
  x: T.number,
1861
2100
  y: T.number,
@@ -1898,350 +2137,68 @@ var instancePresenceMigrations = createRecordMigrationSequence({
1898
2137
  }
1899
2138
  },
1900
2139
  {
1901
- id: instancePresenceVersions.RemoveInstanceId,
1902
- up: (instance) => {
1903
- delete instance.instanceId;
1904
- }
1905
- },
1906
- {
1907
- id: instancePresenceVersions.AddChatMessage,
1908
- up: (instance) => {
1909
- instance.chatMessage = "";
1910
- }
1911
- },
1912
- {
1913
- id: instancePresenceVersions.AddMeta,
1914
- up: (record) => {
1915
- record.meta = {};
1916
- }
1917
- },
1918
- {
1919
- id: instancePresenceVersions.RenameSelectedShapeIds,
1920
- up: (_record) => {
1921
- }
1922
- },
1923
- {
1924
- id: instancePresenceVersions.NullableCameraCursor,
1925
- up: (_record) => {
1926
- },
1927
- down: (record) => {
1928
- if (record.camera === null) {
1929
- record.camera = { x: 0, y: 0, z: 1 };
1930
- }
1931
- if (record.lastActivityTimestamp === null) {
1932
- record.lastActivityTimestamp = 0;
1933
- }
1934
- if (record.cursor === null) {
1935
- record.cursor = { type: "default", x: 0, y: 0, rotation: 0 };
1936
- }
1937
- if (record.screenBounds === null) {
1938
- record.screenBounds = { x: 0, y: 0, w: 1, h: 1 };
1939
- }
1940
- }
1941
- }
1942
- ]
1943
- });
1944
- var InstancePresenceRecordType = createRecordType(
1945
- "instance_presence",
1946
- {
1947
- validator: instancePresenceValidator,
1948
- scope: "presence"
1949
- }
1950
- ).withDefaultProperties(() => ({
1951
- lastActivityTimestamp: null,
1952
- followingUserId: null,
1953
- color: "#FF0000",
1954
- camera: null,
1955
- cursor: null,
1956
- screenBounds: null,
1957
- selectedShapeIds: [],
1958
- brush: null,
1959
- scribbles: [],
1960
- chatMessage: "",
1961
- meta: {}
1962
- }));
1963
-
1964
- // src/createPresenceStateDerivation.ts
1965
- function createPresenceStateDerivation($user, opts) {
1966
- const { instanceId, getUserPresence: _getUserPresence } = opts ?? {};
1967
- const getUserPresence = _getUserPresence ?? getDefaultUserPresence;
1968
- return (store) => {
1969
- return computed("instancePresence", () => {
1970
- const user = $user.get();
1971
- if (!user) return null;
1972
- const state = getUserPresence(store, user);
1973
- if (!state) return null;
1974
- return InstancePresenceRecordType.create({
1975
- ...state,
1976
- id: instanceId ?? InstancePresenceRecordType.createId(store.id)
1977
- });
1978
- });
1979
- };
1980
- }
1981
- function getDefaultUserPresence(store, user) {
1982
- const instance = store.get(DrINSTANCE_ID);
1983
- const pageState = store.get(InstancePageStateRecordType.createId(instance?.currentPageId));
1984
- const camera = store.get(CameraRecordType.createId(instance?.currentPageId));
1985
- const pointer = store.get(DrPOINTER_ID);
1986
- if (!pageState || !instance || !camera || !pointer) {
1987
- return null;
1988
- }
1989
- return {
1990
- selectedShapeIds: pageState.selectedShapeIds,
1991
- brush: instance.brush,
1992
- scribbles: instance.scribbles,
1993
- userId: user.id,
1994
- userName: user.name,
1995
- followingUserId: instance.followingUserId,
1996
- camera: {
1997
- x: camera.x,
1998
- y: camera.y,
1999
- z: camera.z
2000
- },
2001
- color: user.color || "#FF0000",
2002
- currentPageId: instance.currentPageId,
2003
- cursor: {
2004
- x: pointer.x,
2005
- y: pointer.y,
2006
- rotation: instance.cursor.rotation,
2007
- type: instance.cursor.type
2008
- },
2009
- lastActivityTimestamp: pointer.lastActivityTimestamp,
2010
- screenBounds: instance.screenBounds,
2011
- chatMessage: instance.chatMessage,
2012
- meta: {}
2013
- };
2014
- }
2015
- var assetVersions = createMigrationIds("com.draw.asset", {
2016
- AddMeta: 1
2017
- });
2018
- var assetMigrations = createRecordMigrationSequence({
2019
- sequenceId: "com.draw.asset",
2020
- recordType: "asset",
2021
- sequence: [
2022
- {
2023
- id: assetVersions.AddMeta,
2024
- up: (record) => {
2025
- record.meta = {};
2026
- }
2027
- }
2028
- ]
2029
- });
2030
- function createAssetRecordType(assets) {
2031
- return createRecordType("asset", {
2032
- scope: "document",
2033
- validator: T.model(
2034
- "asset",
2035
- T.union(
2036
- "type",
2037
- mapObjectMapValues(
2038
- assets,
2039
- (type, { props, meta }) => createAssetValidator(type, props, meta)
2040
- )
2041
- )
2042
- )
2043
- }).withDefaultProperties(() => ({
2044
- meta: {}
2045
- }));
2046
- }
2047
- var AssetRecordType = createRecordType("asset", {
2048
- scope: "document"
2049
- }).withDefaultProperties(() => ({
2050
- meta: {}
2051
- }));
2052
- function createAssetPropsMigrationSequence(migrations) {
2053
- return migrations;
2054
- }
2055
- function createAssetPropsMigrationIds(assetType, ids) {
2056
- return mapObjectMapValues(ids, (_k, v) => `com.draw.asset.${assetType}/${v}`);
2057
- }
2058
- function createCustomRecordType(typeName, config) {
2059
- return createRecordType(typeName, {
2060
- scope: config.scope,
2061
- validator: config.validator
2062
- }).withDefaultProperties(config.createDefaultProperties ?? (() => ({})));
2063
- }
2064
- function processCustomRecordMigrations(records) {
2065
- const result = [];
2066
- for (const [typeName, config] of Object.entries(records)) {
2067
- const sequenceId = `com.draw.${typeName}`;
2068
- const { migrations } = config;
2069
- if (!migrations) {
2070
- result.push(
2071
- createMigrationSequence({
2072
- sequenceId,
2073
- retroactive: true,
2074
- sequence: []
2075
- })
2076
- );
2077
- } else if ("sequenceId" in migrations) {
2078
- assert(
2079
- sequenceId === migrations.sequenceId,
2080
- `sequenceId mismatch for ${typeName} custom record migrations. Expected '${sequenceId}', got '${migrations.sequenceId}'`
2081
- );
2082
- result.push(migrations);
2083
- } else if ("sequence" in migrations) {
2084
- result.push(
2085
- createMigrationSequence({
2086
- sequenceId,
2087
- retroactive: true,
2088
- sequence: migrations.sequence.map((m) => {
2089
- if (!("id" in m)) return m;
2090
- return {
2091
- id: m.id,
2092
- dependsOn: m.dependsOn,
2093
- scope: "record",
2094
- filter: (r) => r.typeName === typeName,
2095
- up: (record) => {
2096
- const result2 = m.up(record);
2097
- if (result2) return result2;
2098
- },
2099
- down: typeof m.down === "function" ? (record) => {
2100
- const result2 = m.down(record);
2101
- if (result2) return result2;
2102
- } : void 0
2103
- };
2104
- })
2105
- })
2106
- );
2107
- }
2108
- }
2109
- return result;
2110
- }
2111
- function createCustomRecordMigrationIds(recordType, ids) {
2112
- return mapObjectMapValues(ids, (_k, v) => `com.draw.${recordType}/${v}`);
2113
- }
2114
- function createCustomRecordMigrationSequence(migrations) {
2115
- return migrations;
2116
- }
2117
- function createCustomRecordId(typeName, id) {
2118
- return `${typeName}:${id ?? uniqueId()}`;
2119
- }
2120
- function isCustomRecordId(typeName, id) {
2121
- if (!id) return false;
2122
- return id.startsWith(`${typeName}:`);
2123
- }
2124
- function isCustomRecord(typeName, record) {
2125
- if (!record) return false;
2126
- return record.typeName === typeName;
2127
- }
2128
- var documentValidator = T.model(
2129
- "document",
2130
- T.object({
2131
- typeName: T.literal("document"),
2132
- id: T.literal("document:document"),
2133
- gridSize: T.number,
2134
- name: T.string,
2135
- meta: T.jsonValue
2136
- })
2137
- );
2138
- function isDocument(record) {
2139
- if (!record) return false;
2140
- return record.typeName === "document";
2141
- }
2142
- var documentVersions = createMigrationIds("com.draw.document", {
2143
- AddName: 1,
2144
- AddMeta: 2
2145
- });
2146
- var documentMigrations = createRecordMigrationSequence({
2147
- sequenceId: "com.draw.document",
2148
- recordType: "document",
2149
- sequence: [
2150
- {
2151
- id: documentVersions.AddName,
2152
- up: (document) => {
2153
- document.name = "";
2154
- },
2155
- down: (document) => {
2156
- delete document.name;
2157
- }
2158
- },
2159
- {
2160
- id: documentVersions.AddMeta,
2161
- up: (record) => {
2162
- record.meta = {};
2163
- }
2164
- }
2165
- ]
2166
- });
2167
- var DocumentRecordType = createRecordType("document", {
2168
- validator: documentValidator,
2169
- scope: "document"
2170
- }).withDefaultProperties(
2171
- () => ({
2172
- gridSize: 10,
2173
- name: "",
2174
- meta: {}
2175
- })
2176
- );
2177
- var DrDOCUMENT_ID = DocumentRecordType.createId("document");
2178
- var userIdValidator = idValidator("user");
2179
- var userVersions = createMigrationIds("com.draw.user", {
2180
- Initial: 1
2181
- });
2182
- var userMigrations = createRecordMigrationSequence({
2183
- sequenceId: "com.draw.user",
2184
- recordType: "user",
2185
- sequence: [
2140
+ id: instancePresenceVersions.RemoveInstanceId,
2141
+ up: (instance) => {
2142
+ delete instance.instanceId;
2143
+ }
2144
+ },
2186
2145
  {
2187
- id: userVersions.Initial,
2146
+ id: instancePresenceVersions.AddChatMessage,
2147
+ up: (instance) => {
2148
+ instance.chatMessage = "";
2149
+ }
2150
+ },
2151
+ {
2152
+ id: instancePresenceVersions.AddMeta,
2153
+ up: (record) => {
2154
+ record.meta = {};
2155
+ }
2156
+ },
2157
+ {
2158
+ id: instancePresenceVersions.RenameSelectedShapeIds,
2159
+ up: (_record) => {
2160
+ }
2161
+ },
2162
+ {
2163
+ id: instancePresenceVersions.NullableCameraCursor,
2188
2164
  up: (_record) => {
2165
+ },
2166
+ down: (record) => {
2167
+ if (record.camera === null) {
2168
+ record.camera = { x: 0, y: 0, z: 1 };
2169
+ }
2170
+ if (record.lastActivityTimestamp === null) {
2171
+ record.lastActivityTimestamp = 0;
2172
+ }
2173
+ if (record.cursor === null) {
2174
+ record.cursor = { type: "default", x: 0, y: 0, rotation: 0 };
2175
+ }
2176
+ if (record.screenBounds === null) {
2177
+ record.screenBounds = { x: 0, y: 0, w: 1, h: 1 };
2178
+ }
2189
2179
  }
2190
2180
  }
2191
2181
  ]
2192
2182
  });
2193
- function createUserRecordType(config) {
2194
- const metaConfig = config?.meta;
2195
- const metaValidator = metaConfig ? T.object(
2196
- Object.fromEntries(
2197
- Object.entries(metaConfig).map(([key, v]) => [
2198
- key,
2199
- new T.Validator((value) => {
2200
- if (value === void 0) return void 0;
2201
- return v.validate(value);
2202
- })
2203
- ])
2204
- )
2205
- ).allowUnknownProperties() : T.jsonValue;
2206
- const validator = T.model(
2207
- "user",
2208
- T.object({
2209
- typeName: T.literal("user"),
2210
- id: userIdValidator,
2211
- name: T.string,
2212
- color: T.string,
2213
- imageUrl: T.string,
2214
- meta: metaValidator
2215
- })
2216
- );
2217
- return createRecordType("user", {
2218
- validator,
2219
- scope: "document"
2220
- }).withDefaultProperties(() => ({
2221
- name: "",
2222
- color: "",
2223
- imageUrl: "",
2224
- meta: {}
2225
- }));
2226
- }
2227
- T.model(
2228
- "user",
2229
- T.object({
2230
- typeName: T.literal("user"),
2231
- id: userIdValidator,
2232
- name: T.string,
2233
- color: T.string,
2234
- imageUrl: T.string,
2235
- meta: T.jsonValue
2236
- })
2237
- );
2238
- var UserRecordType = createUserRecordType();
2239
- function isUserId(id) {
2240
- return UserRecordType.isId(id);
2241
- }
2242
- function createUserId(id) {
2243
- return UserRecordType.createId(id);
2244
- }
2183
+ var InstancePresenceRecordType = createRecordType(
2184
+ "instance_presence",
2185
+ {
2186
+ validator: instancePresenceValidator,
2187
+ scope: "presence"
2188
+ }
2189
+ ).withDefaultProperties(() => ({
2190
+ lastActivityTimestamp: null,
2191
+ followingUserId: null,
2192
+ color: "#FF0000",
2193
+ camera: null,
2194
+ cursor: null,
2195
+ screenBounds: null,
2196
+ selectedShapeIds: [],
2197
+ brush: null,
2198
+ scribbles: [],
2199
+ chatMessage: "",
2200
+ meta: {}
2201
+ }));
2245
2202
  var bookmarkShapeProps = {
2246
2203
  w: T.nonZeroNumber,
2247
2204
  h: T.nonZeroNumber,
@@ -2275,12 +2232,20 @@ var bookmarkShapeMigrations = createShapePropsMigrationSequence({
2275
2232
  }
2276
2233
  ]
2277
2234
  });
2235
+
2236
+ // src/misc/b64Vecs.ts
2278
2237
  var FIRST_POINT_B64_LENGTH = 16;
2238
+ var FIRST_POINT_2D_B64_LENGTH = 12;
2239
+ var DEFAULT_PRESSURE = 0.5;
2240
+ var DIM_2D = 2;
2241
+ var DIM_3D = 3;
2279
2242
  var BASE64_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
2280
2243
  var B64_LOOKUP = new Uint8Array(128);
2281
2244
  for (let i = 0; i < 64; i++) {
2282
2245
  B64_LOOKUP[BASE64_CHARS.charCodeAt(i)] = i;
2283
2246
  }
2247
+ var SIX_BIT_MASK = 63;
2248
+ var PADDING_CHAR_CODE = "=".charCodeAt(0);
2284
2249
  var POW2 = new Float64Array(31);
2285
2250
  for (let i = 0; i < 31; i++) {
2286
2251
  POW2[i] = Math.pow(2, i - 15);
@@ -2308,10 +2273,19 @@ function nativeBase64ToUint8Array(base64) {
2308
2273
  return Uint8Array.fromBase64(base64);
2309
2274
  }
2310
2275
  function fallbackBase64ToUint8Array(base64) {
2311
- const numBytes = Math.floor(base64.length * 3 / 4);
2276
+ const paddedLength = base64.length;
2277
+ let padding = 0;
2278
+ if (paddedLength > 0 && base64.charCodeAt(paddedLength - 1) === PADDING_CHAR_CODE) {
2279
+ padding++;
2280
+ if (paddedLength > 1 && base64.charCodeAt(paddedLength - 2) === PADDING_CHAR_CODE) {
2281
+ padding++;
2282
+ }
2283
+ }
2284
+ const numBytes = Math.floor(paddedLength * 3 / 4) - padding;
2312
2285
  const bytes = new Uint8Array(numBytes);
2313
2286
  let byteIndex = 0;
2314
- for (let i = 0; i < base64.length; i += 4) {
2287
+ const fullGroups = Math.floor((paddedLength - padding) / 4) * 4;
2288
+ for (let i = 0; i < fullGroups; i += 4) {
2315
2289
  const c0 = B64_LOOKUP[base64.charCodeAt(i)];
2316
2290
  const c1 = B64_LOOKUP[base64.charCodeAt(i + 1)];
2317
2291
  const c2 = B64_LOOKUP[base64.charCodeAt(i + 2)];
@@ -2321,20 +2295,45 @@ function fallbackBase64ToUint8Array(base64) {
2321
2295
  bytes[byteIndex++] = bitmap >> 8 & 255;
2322
2296
  bytes[byteIndex++] = bitmap & 255;
2323
2297
  }
2298
+ if (padding === 1) {
2299
+ const c0 = B64_LOOKUP[base64.charCodeAt(fullGroups)];
2300
+ const c1 = B64_LOOKUP[base64.charCodeAt(fullGroups + 1)];
2301
+ const c2 = B64_LOOKUP[base64.charCodeAt(fullGroups + 2)];
2302
+ const bitmap = c0 << 18 | c1 << 12 | c2 << 6;
2303
+ bytes[byteIndex++] = bitmap >> 16 & 255;
2304
+ bytes[byteIndex++] = bitmap >> 8 & 255;
2305
+ } else if (padding === 2) {
2306
+ const c0 = B64_LOOKUP[base64.charCodeAt(fullGroups)];
2307
+ const c1 = B64_LOOKUP[base64.charCodeAt(fullGroups + 1)];
2308
+ const bitmap = c0 << 18 | c1 << 12;
2309
+ bytes[byteIndex++] = bitmap >> 16 & 255;
2310
+ }
2324
2311
  return bytes;
2325
2312
  }
2326
2313
  function nativeUint8ArrayToBase64(uint8Array) {
2327
2314
  return uint8Array.toBase64();
2328
2315
  }
2329
2316
  function fallbackUint8ArrayToBase64(uint8Array) {
2330
- assert(uint8Array.length % 3 === 0, "Uint8Array length must be a multiple of 3");
2317
+ const len = uint8Array.length;
2318
+ const fullGroups = Math.floor(len / 3) * 3;
2331
2319
  let result = "";
2332
- for (let i = 0; i < uint8Array.length; i += 3) {
2320
+ for (let i = 0; i < fullGroups; i += 3) {
2333
2321
  const byte1 = uint8Array[i];
2334
2322
  const byte2 = uint8Array[i + 1];
2335
2323
  const byte3 = uint8Array[i + 2];
2336
2324
  const bitmap = byte1 << 16 | byte2 << 8 | byte3;
2337
- result += BASE64_CHARS[bitmap >> 18 & 63] + BASE64_CHARS[bitmap >> 12 & 63] + BASE64_CHARS[bitmap >> 6 & 63] + BASE64_CHARS[bitmap & 63];
2325
+ result += BASE64_CHARS[bitmap >> 18 & SIX_BIT_MASK] + // bits 23–18 (top sextet)
2326
+ BASE64_CHARS[bitmap >> 12 & SIX_BIT_MASK] + // bits 17–12
2327
+ BASE64_CHARS[bitmap >> 6 & SIX_BIT_MASK] + // bits 11–6
2328
+ BASE64_CHARS[bitmap & SIX_BIT_MASK];
2329
+ }
2330
+ const remaining = len - fullGroups;
2331
+ if (remaining === 1) {
2332
+ const bitmap = uint8Array[fullGroups] << 16;
2333
+ result += BASE64_CHARS[bitmap >> 18 & SIX_BIT_MASK] + BASE64_CHARS[bitmap >> 12 & SIX_BIT_MASK] + "==";
2334
+ } else if (remaining === 2) {
2335
+ const bitmap = uint8Array[fullGroups] << 16 | uint8Array[fullGroups + 1] << 8;
2336
+ result += BASE64_CHARS[bitmap >> 18 & SIX_BIT_MASK] + BASE64_CHARS[bitmap >> 12 & SIX_BIT_MASK] + BASE64_CHARS[bitmap >> 6 & SIX_BIT_MASK] + "=";
2338
2337
  }
2339
2338
  return result;
2340
2339
  }
@@ -2381,7 +2380,7 @@ function numberToFloat16Bits(value) {
2381
2380
  }
2382
2381
  return sign << 15 | expBiased << 10 | frac;
2383
2382
  }
2384
- var b64Vecs = class {
2383
+ var b64Vecs = class _b64Vecs {
2385
2384
  /**
2386
2385
  * Encode a single point (x, y, z) to 8 base64 characters using legacy Float16 encoding.
2387
2386
  * Each coordinate is encoded as a Float16 value, resulting in 6 bytes total.
@@ -2455,10 +2454,12 @@ var b64Vecs = class {
2455
2454
  * - Delta points: 3 Float16 values each = 6 bytes = 8 base64 chars each
2456
2455
  *
2457
2456
  * @param points - An array of VecModel objects to encode
2457
+ * @param dim - Encoding dimension; `2` routes through the 2D variant (drops z), `3` (default) keeps x, y, z
2458
2458
  * @returns A base64-encoded string containing delta-encoded points
2459
2459
  * @public
2460
2460
  */
2461
- static encodePoints(points) {
2461
+ static encodePoints(points, dim) {
2462
+ if (dim === DIM_2D) return _b64Vecs.encodePoints2D(points);
2462
2463
  if (points.length === 0) return "";
2463
2464
  const firstPointBytes = 12;
2464
2465
  const deltaBytes = (points.length - 1) * 6;
@@ -2491,10 +2492,12 @@ var b64Vecs = class {
2491
2492
  * Float16 deltas that are accumulated to reconstruct absolute positions.
2492
2493
  *
2493
2494
  * @param base64 - The base64-encoded string containing delta-encoded point data
2495
+ * @param dim - Encoding dimension; `2` expects x/y only (z supplied as 0.5), `3` (default) expects x/y/z
2494
2496
  * @returns An array of VecModel objects with absolute coordinates
2495
2497
  * @public
2496
2498
  */
2497
- static decodePoints(base64) {
2499
+ static decodePoints(base64, dim) {
2500
+ if (dim === DIM_2D) return _b64Vecs.decodePoints2D(base64);
2498
2501
  if (base64.length === 0) return [];
2499
2502
  const bytes = base64ToUint8Array(base64);
2500
2503
  const dataView = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
@@ -2517,10 +2520,12 @@ var b64Vecs = class {
2517
2520
  * The first point is stored as Float32 for full precision.
2518
2521
  *
2519
2522
  * @param b64Points - The delta-encoded base64 string
2523
+ * @param dim - Encoding dimension; `2` expects x/y only (z supplied as 0.5), `3` (default) expects x/y/z
2520
2524
  * @returns The first point as a VecModel, or null if the string is too short
2521
2525
  * @public
2522
2526
  */
2523
- static decodeFirstPoint(b64Points) {
2527
+ static decodeFirstPoint(b64Points, dim) {
2528
+ if (dim === DIM_2D) return _b64Vecs.decodeFirstPoint2D(b64Points);
2524
2529
  if (b64Points.length < FIRST_POINT_B64_LENGTH) return null;
2525
2530
  const bytes = base64ToUint8Array(b64Points.slice(0, FIRST_POINT_B64_LENGTH));
2526
2531
  const dataView = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
@@ -2535,10 +2540,12 @@ var b64Vecs = class {
2535
2540
  * Requires decoding all points to accumulate deltas.
2536
2541
  *
2537
2542
  * @param b64Points - The delta-encoded base64 string
2543
+ * @param dim - Encoding dimension; `2` expects x/y only (z supplied as 0.5), `3` (default) expects x/y/z
2538
2544
  * @returns The last point as a VecModel, or null if the string is too short
2539
2545
  * @public
2540
2546
  */
2541
- static decodeLastPoint(b64Points) {
2547
+ static decodeLastPoint(b64Points, dim) {
2548
+ if (dim === DIM_2D) return _b64Vecs.decodeLastPoint2D(b64Points);
2542
2549
  if (b64Points.length < FIRST_POINT_B64_LENGTH) return null;
2543
2550
  const bytes = base64ToUint8Array(b64Points);
2544
2551
  const dataView = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
@@ -2553,12 +2560,129 @@ var b64Vecs = class {
2553
2560
  }
2554
2561
  return { x, y, z };
2555
2562
  }
2563
+ /**
2564
+ * Encode an array of VecModels as 2D delta-encoded points, dropping z entirely.
2565
+ * Use for draw shapes from devices that don't report pressure, where z is a
2566
+ * constant 0.5 and storing it wastes ~33% of per-point bytes.
2567
+ *
2568
+ * Format:
2569
+ * - First point: 2 Float32 values (x, y) = 8 bytes
2570
+ * - Delta points: 2 Float16 values (dx, dy) = 4 bytes each
2571
+ *
2572
+ * @param points - An array of VecModel objects to encode (z is discarded)
2573
+ * @returns A base64-encoded string containing 2D delta-encoded points
2574
+ * @public
2575
+ */
2576
+ static encodePoints2D(points) {
2577
+ if (points.length === 0) return "";
2578
+ const firstPointBytes = 8;
2579
+ const deltaBytes = (points.length - 1) * 4;
2580
+ const buffer = new Uint8Array(firstPointBytes + deltaBytes);
2581
+ const dataView = new DataView(buffer.buffer);
2582
+ const first = points[0];
2583
+ dataView.setFloat32(0, first.x, true);
2584
+ dataView.setFloat32(4, first.y, true);
2585
+ let prevX = first.x;
2586
+ let prevY = first.y;
2587
+ for (let i = 1; i < points.length; i++) {
2588
+ const p = points[i];
2589
+ const offset = firstPointBytes + (i - 1) * 4;
2590
+ setFloat16(dataView, offset, p.x - prevX);
2591
+ setFloat16(dataView, offset + 2, p.y - prevY);
2592
+ prevX = p.x;
2593
+ prevY = p.y;
2594
+ }
2595
+ return uint8ArrayToBase64(buffer);
2596
+ }
2597
+ /**
2598
+ * Decode a 2D delta-encoded base64 string back to an array of absolute VecModels.
2599
+ * The z coordinate is always set to 0.5 (the default pressure value) so downstream
2600
+ * consumers don't need a separate code path.
2601
+ *
2602
+ * @param base64 - The base64-encoded string containing 2D delta-encoded point data
2603
+ * @returns An array of VecModel objects with absolute (x, y) and z = 0.5
2604
+ * @public
2605
+ */
2606
+ static decodePoints2D(base64) {
2607
+ if (base64.length === 0) return [];
2608
+ const bytes = base64ToUint8Array(base64);
2609
+ const dataView = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
2610
+ const result = [];
2611
+ let x = dataView.getFloat32(0, true);
2612
+ let y = dataView.getFloat32(4, true);
2613
+ result.push({ x, y, z: DEFAULT_PRESSURE });
2614
+ const firstPointBytes = 8;
2615
+ for (let offset = firstPointBytes; offset < bytes.length; offset += 4) {
2616
+ x += getFloat16(dataView, offset);
2617
+ y += getFloat16(dataView, offset + 2);
2618
+ result.push({ x, y, z: DEFAULT_PRESSURE });
2619
+ }
2620
+ return result;
2621
+ }
2622
+ /**
2623
+ * Get the first point from a 2D delta-encoded base64 string.
2624
+ *
2625
+ * @param b64Points - The 2D delta-encoded base64 string
2626
+ * @returns The first point with z = 0.5, or null if the string is too short
2627
+ * @public
2628
+ */
2629
+ static decodeFirstPoint2D(b64Points) {
2630
+ if (b64Points.length < FIRST_POINT_2D_B64_LENGTH) return null;
2631
+ const bytes = base64ToUint8Array(b64Points.slice(0, FIRST_POINT_2D_B64_LENGTH));
2632
+ const dataView = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
2633
+ return {
2634
+ x: dataView.getFloat32(0, true),
2635
+ y: dataView.getFloat32(4, true),
2636
+ z: DEFAULT_PRESSURE
2637
+ };
2638
+ }
2639
+ /**
2640
+ * Get the last point from a 2D delta-encoded base64 string.
2641
+ * Requires decoding all points to accumulate deltas.
2642
+ *
2643
+ * @param b64Points - The 2D delta-encoded base64 string
2644
+ * @returns The last point with z = 0.5, or null if the string is too short
2645
+ * @public
2646
+ */
2647
+ static decodeLastPoint2D(b64Points) {
2648
+ if (b64Points.length < FIRST_POINT_2D_B64_LENGTH) return null;
2649
+ const bytes = base64ToUint8Array(b64Points);
2650
+ const dataView = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
2651
+ let x = dataView.getFloat32(0, true);
2652
+ let y = dataView.getFloat32(4, true);
2653
+ const firstPointBytes = 8;
2654
+ for (let offset = firstPointBytes; offset < bytes.length; offset += 4) {
2655
+ x += getFloat16(dataView, offset);
2656
+ y += getFloat16(dataView, offset + 2);
2657
+ }
2658
+ return { x, y, z: DEFAULT_PRESSURE };
2659
+ }
2660
+ /**
2661
+ * Whether an encoded path contains only a single point (a "dot"), inferred from
2662
+ * the encoded length without decoding — cheap enough for the render path.
2663
+ *
2664
+ * The single-point length depends on the encoding dimension, so this takes the
2665
+ * segment's `dim`: a one-point path is `FIRST_POINT_B64_LENGTH` chars (3D) or
2666
+ * `FIRST_POINT_2D_B64_LENGTH` chars (2D). Keeping this beside the layout constants
2667
+ * is deliberate — it is the single source of truth for "how long is one point", so
2668
+ * callers never hard-code a length threshold (which silently breaks when a new
2669
+ * encoding is added).
2670
+ *
2671
+ * @param b64Points - The encoded path string
2672
+ * @param dim - Encoding dimension; `2` for (x, y), `3` (default) for (x, y, z)
2673
+ * @returns true if the path encodes exactly one point
2674
+ * @public
2675
+ */
2676
+ static isSinglePoint(b64Points, dim) {
2677
+ return b64Points.length <= (dim === DIM_2D ? FIRST_POINT_2D_B64_LENGTH : FIRST_POINT_B64_LENGTH);
2678
+ }
2556
2679
  };
2557
2680
 
2558
2681
  // src/shapes/DrDrawShape.ts
2559
2682
  var DrawShapeSegment = T.object({
2560
2683
  type: T.literalEnum("free", "straight"),
2561
- path: T.string
2684
+ path: T.string,
2685
+ dim: T.literalEnum(DIM_2D, DIM_3D).optional()
2562
2686
  });
2563
2687
  var drawShapeProps = {
2564
2688
  color: DefaultColorStyle,
@@ -2577,7 +2701,8 @@ var Versions5 = createShapePropsMigrationIds("draw", {
2577
2701
  AddInPen: 1,
2578
2702
  AddScale: 2,
2579
2703
  Base64: 3,
2580
- LegacyPointsConversion: 4
2704
+ LegacyPointsConversion: 4,
2705
+ OmitNonPressureZ: 5
2581
2706
  });
2582
2707
  var drawShapeMigrations = createShapePropsMigrationSequence({
2583
2708
  sequence: [
@@ -2648,6 +2773,18 @@ var drawShapeMigrations = createShapePropsMigrationSequence({
2648
2773
  },
2649
2774
  down: (_props) => {
2650
2775
  }
2776
+ },
2777
+ {
2778
+ id: Versions5.OmitNonPressureZ,
2779
+ up: (_props) => {
2780
+ },
2781
+ down: (props) => {
2782
+ props.segments = props.segments.map((segment) => {
2783
+ if (segment.dim === void 0) return segment;
2784
+ const { dim, ...rest } = segment;
2785
+ return dim === DIM_2D ? { ...rest, path: b64Vecs.encodePoints(b64Vecs.decodePoints(segment.path, DIM_2D)) } : rest;
2786
+ });
2787
+ }
2651
2788
  }
2652
2789
  ]
2653
2790
  });
@@ -3168,7 +3305,8 @@ var highlightShapeProps = {
3168
3305
  var Versions8 = createShapePropsMigrationIds("highlight", {
3169
3306
  AddScale: 1,
3170
3307
  Base64: 2,
3171
- LegacyPointsConversion: 3
3308
+ LegacyPointsConversion: 3,
3309
+ OmitNonPressureZ: 4
3172
3310
  });
3173
3311
  var highlightShapeMigrations = createShapePropsMigrationSequence({
3174
3312
  sequence: [
@@ -3223,6 +3361,18 @@ var highlightShapeMigrations = createShapePropsMigrationSequence({
3223
3361
  },
3224
3362
  down: (_props) => {
3225
3363
  }
3364
+ },
3365
+ {
3366
+ id: Versions8.OmitNonPressureZ,
3367
+ up: (_props) => {
3368
+ },
3369
+ down: (props) => {
3370
+ props.segments = props.segments.map((segment) => {
3371
+ if (segment.dim === void 0) return segment;
3372
+ const { dim, ...rest } = segment;
3373
+ return dim === DIM_2D ? { ...rest, path: b64Vecs.encodePoints(b64Vecs.decodePoints(segment.path, DIM_2D)) } : rest;
3374
+ });
3375
+ }
3226
3376
  }
3227
3377
  ]
3228
3378
  });
@@ -3440,7 +3590,7 @@ var noteShapeProps = {
3440
3590
  url: T.linkUrl,
3441
3591
  richText: richTextValidator,
3442
3592
  scale: T.nonZeroNumber,
3443
- textFirstEditedBy: T.string.nullable()
3593
+ textLastEditedBy: T.string.nullable()
3444
3594
  };
3445
3595
  var Versions10 = createShapePropsMigrationIds("note", {
3446
3596
  AddUrlProp: 1,
@@ -3454,7 +3604,8 @@ var Versions10 = createShapePropsMigrationIds("note", {
3454
3604
  AddRichText: 9,
3455
3605
  AddRichTextAttrs: 10,
3456
3606
  AddFirstEditedBy: 11,
3457
- MakeFontSizeAdjustmentRatio: 12
3607
+ MakeFontSizeAdjustmentRatio: 12,
3608
+ RenameFirstEditedByToLast: 13
3458
3609
  });
3459
3610
  var noteShapeMigrations = createShapePropsMigrationSequence({
3460
3611
  sequence: [
@@ -3573,6 +3724,17 @@ var noteShapeMigrations = createShapePropsMigrationSequence({
3573
3724
  down: (props) => {
3574
3725
  props.fontSizeAdjustment = 0;
3575
3726
  }
3727
+ },
3728
+ {
3729
+ id: Versions10.RenameFirstEditedByToLast,
3730
+ up: (props) => {
3731
+ props.textLastEditedBy = props.textFirstEditedBy ?? null;
3732
+ delete props.textFirstEditedBy;
3733
+ },
3734
+ down: (props) => {
3735
+ props.textFirstEditedBy = props.textLastEditedBy ?? null;
3736
+ delete props.textLastEditedBy;
3737
+ }
3576
3738
  }
3577
3739
  ]
3578
3740
  });
@@ -3863,8 +4025,7 @@ function createIntegrityChecker(store) {
3863
4025
  store.put([
3864
4026
  store.schema.types.instance.create({
3865
4027
  id: DrINSTANCE_ID,
3866
- currentPageId: getFirstPageId(),
3867
- exportBackground: true
4028
+ currentPageId: getFirstPageId()
3868
4029
  })
3869
4030
  ]);
3870
4031
  return ensureStoreIsUsable();
@@ -4045,6 +4206,56 @@ function createDrSchema({
4045
4206
  }
4046
4207
  );
4047
4208
  }
4209
+ function createPresenceStateDerivation($user, opts) {
4210
+ const { instanceId, getUserPresence: _getUserPresence } = opts ?? {};
4211
+ const getUserPresence = _getUserPresence ?? getDefaultUserPresence;
4212
+ return (store) => {
4213
+ return computed("instancePresence", () => {
4214
+ const user = $user.get();
4215
+ if (!user) return null;
4216
+ const state = getUserPresence(store, user);
4217
+ if (!state) return null;
4218
+ return InstancePresenceRecordType.create({
4219
+ ...state,
4220
+ id: instanceId ?? InstancePresenceRecordType.createId(store.id)
4221
+ });
4222
+ });
4223
+ };
4224
+ }
4225
+ function getDefaultUserPresence(store, user) {
4226
+ const instance = store.get(DrINSTANCE_ID);
4227
+ const pageState = store.get(InstancePageStateRecordType.createId(instance?.currentPageId));
4228
+ const camera = store.get(CameraRecordType.createId(instance?.currentPageId));
4229
+ const pointer = store.get(DrPOINTER_ID);
4230
+ if (!pageState || !instance || !camera || !pointer) {
4231
+ return null;
4232
+ }
4233
+ return {
4234
+ selectedShapeIds: pageState.selectedShapeIds,
4235
+ brush: instance.brush,
4236
+ scribbles: instance.scribbles,
4237
+ userId: user.id,
4238
+ userName: user.name,
4239
+ followingUserId: instance.followingUserId,
4240
+ camera: {
4241
+ x: camera.x,
4242
+ y: camera.y,
4243
+ z: camera.z
4244
+ },
4245
+ color: user.color || "#FF0000",
4246
+ currentPageId: instance.currentPageId,
4247
+ cursor: {
4248
+ x: pointer.x,
4249
+ y: pointer.y,
4250
+ rotation: instance.cursor.rotation,
4251
+ type: instance.cursor.type
4252
+ },
4253
+ lastActivityTimestamp: pointer.lastActivityTimestamp,
4254
+ screenBounds: instance.screenBounds,
4255
+ chatMessage: instance.chatMessage,
4256
+ meta: {}
4257
+ };
4258
+ }
4048
4259
 
4049
4260
  // src/misc/DrHandle.ts
4050
4261
  var TL_HANDLE_TYPES = /* @__PURE__ */ new Set(["vertex", "virtual", "create", "clone"]);
@@ -4143,10 +4354,10 @@ function getSupportedLocale(locale) {
4143
4354
  // src/index.ts
4144
4355
  registerDrawLibraryVersion(
4145
4356
  "@ibodr/schema",
4146
- "0.2.5",
4357
+ "0.2.7",
4147
4358
  "esm"
4148
4359
  );
4149
4360
 
4150
- export { ArrowShapeArrowheadEndStyle, ArrowShapeArrowheadStartStyle, ArrowShapeKindStyle, AssetRecordType, CameraRecordType, DR_BOARD_BACKGROUND_TYPES, DefaultColorStyle, DefaultDashStyle, DefaultFillStyle, DefaultFontFamilies, DefaultFontStyle, DefaultHorizontalAlignStyle, DefaultLabelColorStyle, DefaultSizeStyle, DefaultTextAlignStyle, DefaultVerticalAlignStyle, DocumentRecordType, DrDOCUMENT_ID, DrINSTANCE_ID, DrPOINTER_ID, ElbowArrowSnap, EnumStyleProp, GeoShapeGeoStyle, ImageShapeCrop, InstancePageStateRecordType, InstancePresenceRecordType, LANGUAGES, LineShapeSplineStyle, PageRecordType, PointerRecordType, StyleProp, TL_CANVAS_UI_COLOR_TYPES, TL_CURSOR_TYPES, TL_HANDLE_TYPES, TL_SCRIBBLE_STATES, UserRecordType, arrowBindingMigrations, arrowBindingProps, arrowBindingVersions, arrowShapeMigrations, arrowShapeProps, arrowShapeVersions, assetIdValidator, assetMigrations, b64Vecs, bindingIdValidator, bookmarkAssetMigrations, bookmarkAssetProps, bookmarkShapeMigrations, bookmarkShapeProps, boxModelValidator, canvasUiColorTypeValidator, compressLegacySegments, createAssetPropsMigrationIds, createAssetPropsMigrationSequence, createAssetRecordType, createAssetValidator, createBindingId, createBindingPropsMigrationIds, createBindingPropsMigrationSequence, createBindingValidator, createCachedUserResolve, createCustomRecordId, createCustomRecordMigrationIds, createCustomRecordMigrationSequence, createDrSchema, createPresenceStateDerivation, createShapeId, createShapePropsMigrationIds, createShapePropsMigrationSequence, createShapeValidator, createUserId, createUserRecordType, defaultAssetSchemas, defaultBindingSchemas, defaultShapeSchemas, drawShapeMigrations, drawShapeProps, embedShapeMigrations, embedShapeProps, frameShapeMigrations, frameShapeProps, geoShapeMigrations, geoShapeProps, getDefaultTranslationLocale, getDefaultUserPresence, getShapePropKeysByStyle, groupShapeMigrations, groupShapeProps, highlightShapeMigrations, highlightShapeProps, idValidator, imageAssetMigrations, imageAssetProps, imageShapeMigrations, imageShapeProps, isBinding, isBindingId, isCssHexColor, isCustomRecord, isCustomRecordId, isDocument, isFontEntry, isPageId, isShape, isShapeId, isUserId, lineShapeMigrations, lineShapeProps, noteShapeMigrations, noteShapeProps, opacityValidator, pageIdValidator, parentIdValidator, pluckPreservingValues, registerColorsFromThemes, registerFontsFromThemes, richTextValidator, rootBindingMigrations, rootShapeMigrations, scribbleValidator, shapeIdValidator, textShapeMigrations, textShapeProps, toRichText, userIdValidator, vecModelValidator, videoAssetMigrations, videoAssetProps, videoShapeMigrations, videoShapeProps };
4361
+ export { ArrowShapeArrowheadEndStyle, ArrowShapeArrowheadStartStyle, ArrowShapeKindStyle, AssetRecordType, CameraRecordType, DIM_2D, DIM_3D, DR_BOARD_BACKGROUND_TYPES, DefaultColorStyle, DefaultDashStyle, DefaultFillStyle, DefaultFontFamilies, DefaultFontStyle, DefaultHorizontalAlignStyle, DefaultLabelColorStyle, DefaultSizeStyle, DefaultTextAlignStyle, DefaultVerticalAlignStyle, DocumentRecordType, DrDOCUMENT_ID, DrINSTANCE_ID, DrPOINTER_ID, ElbowArrowSnap, EnumStyleProp, GeoShapeGeoStyle, ImageShapeCrop, InstancePageStateRecordType, InstancePresenceRecordType, LANGUAGES, LineShapeSplineStyle, PageRecordType, PointerRecordType, StyleProp, TL_CANVAS_UI_COLOR_TYPES, TL_CURSOR_TYPES, TL_HANDLE_TYPES, TL_SCRIBBLE_STATES, UserRecordType, arrowBindingMigrations, arrowBindingProps, arrowBindingVersions, arrowShapeMigrations, arrowShapeProps, arrowShapeVersions, assetIdValidator, assetMigrations, b64Vecs, bindingIdValidator, bookmarkAssetMigrations, bookmarkAssetProps, bookmarkShapeMigrations, bookmarkShapeProps, boxModelValidator, canvasUiColorTypeValidator, compressLegacySegments, createAssetPropsMigrationIds, createAssetPropsMigrationSequence, createAssetRecordType, createAssetValidator, createBindingId, createBindingPropsMigrationIds, createBindingPropsMigrationSequence, createBindingValidator, createCachedUserResolve, createCustomRecordId, createCustomRecordMigrationIds, createCustomRecordMigrationSequence, createDrSchema, createPresenceStateDerivation, createShapeId, createShapePropsMigrationIds, createShapePropsMigrationSequence, createShapeValidator, createUserId, createUserRecordType, defaultAssetSchemas, defaultBindingSchemas, defaultShapeSchemas, drawShapeMigrations, drawShapeProps, embedShapeMigrations, embedShapeProps, frameShapeMigrations, frameShapeProps, geoShapeMigrations, geoShapeProps, getDefaultTranslationLocale, getDefaultUserPresence, getShapePropKeysByStyle, groupShapeMigrations, groupShapeProps, highlightShapeMigrations, highlightShapeProps, idValidator, imageAssetMigrations, imageAssetProps, imageShapeMigrations, imageShapeProps, isBinding, isBindingId, isCssHexColor, isCustomRecord, isCustomRecordId, isDocument, isFontEntry, isPage, isPageId, isShape, isShapeId, isUserId, lineShapeMigrations, lineShapeProps, noteShapeMigrations, noteShapeProps, opacityValidator, pageIdValidator, parentIdValidator, pluckPreservingValues, registerColorsFromThemes, registerFontsFromThemes, richTextValidator, rootBindingMigrations, rootShapeMigrations, scribbleValidator, shapeIdValidator, textShapeMigrations, textShapeProps, toRichText, userIdValidator, vecModelValidator, videoAssetMigrations, videoAssetProps, videoShapeMigrations, videoShapeProps };
4151
4362
  //# sourceMappingURL=index.mjs.map
4152
4363
  //# sourceMappingURL=index.mjs.map