@tldraw/tlschema 4.1.0-canary.e653ec63c99b → 4.1.0-canary.f2f81cd6fe2c
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-cjs/TLStore.js +3 -10
- package/dist-cjs/TLStore.js.map +2 -2
- package/dist-cjs/assets/TLBaseAsset.js.map +2 -2
- package/dist-cjs/assets/TLBookmarkAsset.js.map +2 -2
- package/dist-cjs/assets/TLImageAsset.js.map +2 -2
- package/dist-cjs/assets/TLVideoAsset.js.map +2 -2
- package/dist-cjs/bindings/TLArrowBinding.js.map +2 -2
- package/dist-cjs/bindings/TLBaseBinding.js.map +2 -2
- package/dist-cjs/createPresenceStateDerivation.js.map +2 -2
- package/dist-cjs/createTLSchema.js.map +2 -2
- package/dist-cjs/index.d.ts +4416 -223
- package/dist-cjs/index.js +1 -1
- package/dist-cjs/index.js.map +2 -2
- package/dist-cjs/misc/TLColor.js.map +2 -2
- package/dist-cjs/misc/TLCursor.js.map +2 -2
- package/dist-cjs/misc/TLHandle.js.map +2 -2
- package/dist-cjs/misc/TLOpacity.js.map +2 -2
- package/dist-cjs/misc/TLRichText.js.map +2 -2
- package/dist-cjs/misc/TLScribble.js.map +2 -2
- package/dist-cjs/misc/geometry-types.js.map +2 -2
- package/dist-cjs/misc/id-validator.js.map +2 -2
- package/dist-cjs/records/TLAsset.js.map +2 -2
- package/dist-cjs/records/TLBinding.js.map +2 -2
- package/dist-cjs/records/TLCamera.js.map +2 -2
- package/dist-cjs/records/TLDocument.js.map +2 -2
- package/dist-cjs/records/TLInstance.js.map +2 -2
- package/dist-cjs/records/TLPage.js.map +2 -2
- package/dist-cjs/records/TLPageState.js.map +2 -2
- package/dist-cjs/records/TLPointer.js.map +2 -2
- package/dist-cjs/records/TLPresence.js.map +2 -2
- package/dist-cjs/records/TLRecord.js.map +1 -1
- package/dist-cjs/records/TLShape.js.map +2 -2
- package/dist-cjs/recordsWithProps.js.map +2 -2
- package/dist-cjs/shapes/ShapeWithCrop.js.map +1 -1
- package/dist-cjs/shapes/TLArrowShape.js.map +2 -2
- package/dist-cjs/shapes/TLBaseShape.js.map +2 -2
- package/dist-cjs/shapes/TLBookmarkShape.js.map +2 -2
- package/dist-cjs/shapes/TLDrawShape.js.map +2 -2
- package/dist-cjs/shapes/TLEmbedShape.js +0 -10
- package/dist-cjs/shapes/TLEmbedShape.js.map +2 -2
- package/dist-cjs/shapes/TLFrameShape.js.map +2 -2
- package/dist-cjs/shapes/TLGeoShape.js.map +2 -2
- package/dist-cjs/shapes/TLGroupShape.js.map +2 -2
- package/dist-cjs/shapes/TLHighlightShape.js.map +2 -2
- package/dist-cjs/shapes/TLImageShape.js.map +2 -2
- package/dist-cjs/shapes/TLLineShape.js.map +2 -2
- package/dist-cjs/shapes/TLNoteShape.js.map +2 -2
- package/dist-cjs/shapes/TLTextShape.js.map +2 -2
- package/dist-cjs/shapes/TLVideoShape.js.map +2 -2
- package/dist-cjs/store-migrations.js.map +2 -2
- package/dist-cjs/styles/TLColorStyle.js.map +2 -2
- package/dist-cjs/styles/TLDashStyle.js.map +2 -2
- package/dist-cjs/styles/TLFillStyle.js.map +2 -2
- package/dist-cjs/styles/TLFontStyle.js.map +2 -2
- package/dist-cjs/styles/TLHorizontalAlignStyle.js.map +2 -2
- package/dist-cjs/styles/TLSizeStyle.js.map +2 -2
- package/dist-cjs/styles/TLTextAlignStyle.js.map +2 -2
- package/dist-cjs/styles/TLVerticalAlignStyle.js.map +2 -2
- package/dist-cjs/translations/translations.js +1 -1
- package/dist-cjs/translations/translations.js.map +2 -2
- package/dist-cjs/util-types.js.map +1 -1
- package/dist-esm/TLStore.mjs +3 -10
- package/dist-esm/TLStore.mjs.map +2 -2
- package/dist-esm/assets/TLBaseAsset.mjs.map +2 -2
- package/dist-esm/assets/TLBookmarkAsset.mjs.map +2 -2
- package/dist-esm/assets/TLImageAsset.mjs.map +2 -2
- package/dist-esm/assets/TLVideoAsset.mjs.map +2 -2
- package/dist-esm/bindings/TLArrowBinding.mjs.map +2 -2
- package/dist-esm/bindings/TLBaseBinding.mjs.map +2 -2
- package/dist-esm/createPresenceStateDerivation.mjs.map +2 -2
- package/dist-esm/createTLSchema.mjs.map +2 -2
- package/dist-esm/index.d.mts +4416 -223
- package/dist-esm/index.mjs +1 -1
- package/dist-esm/index.mjs.map +2 -2
- package/dist-esm/misc/TLColor.mjs.map +2 -2
- package/dist-esm/misc/TLCursor.mjs.map +2 -2
- package/dist-esm/misc/TLHandle.mjs.map +2 -2
- package/dist-esm/misc/TLOpacity.mjs.map +2 -2
- package/dist-esm/misc/TLRichText.mjs.map +2 -2
- package/dist-esm/misc/TLScribble.mjs.map +2 -2
- package/dist-esm/misc/geometry-types.mjs.map +2 -2
- package/dist-esm/misc/id-validator.mjs.map +2 -2
- package/dist-esm/records/TLAsset.mjs.map +2 -2
- package/dist-esm/records/TLBinding.mjs.map +2 -2
- package/dist-esm/records/TLCamera.mjs.map +2 -2
- package/dist-esm/records/TLDocument.mjs.map +2 -2
- package/dist-esm/records/TLInstance.mjs.map +2 -2
- package/dist-esm/records/TLPage.mjs.map +2 -2
- package/dist-esm/records/TLPageState.mjs.map +2 -2
- package/dist-esm/records/TLPointer.mjs.map +2 -2
- package/dist-esm/records/TLPresence.mjs.map +2 -2
- package/dist-esm/records/TLShape.mjs.map +2 -2
- package/dist-esm/recordsWithProps.mjs.map +2 -2
- package/dist-esm/shapes/TLArrowShape.mjs.map +2 -2
- package/dist-esm/shapes/TLBaseShape.mjs.map +2 -2
- package/dist-esm/shapes/TLBookmarkShape.mjs.map +2 -2
- package/dist-esm/shapes/TLDrawShape.mjs.map +2 -2
- package/dist-esm/shapes/TLEmbedShape.mjs +0 -10
- package/dist-esm/shapes/TLEmbedShape.mjs.map +2 -2
- package/dist-esm/shapes/TLFrameShape.mjs.map +2 -2
- package/dist-esm/shapes/TLGeoShape.mjs.map +2 -2
- package/dist-esm/shapes/TLGroupShape.mjs.map +2 -2
- package/dist-esm/shapes/TLHighlightShape.mjs.map +2 -2
- package/dist-esm/shapes/TLImageShape.mjs.map +2 -2
- package/dist-esm/shapes/TLLineShape.mjs.map +2 -2
- package/dist-esm/shapes/TLNoteShape.mjs.map +2 -2
- package/dist-esm/shapes/TLTextShape.mjs.map +2 -2
- package/dist-esm/shapes/TLVideoShape.mjs.map +2 -2
- package/dist-esm/store-migrations.mjs.map +2 -2
- package/dist-esm/styles/TLColorStyle.mjs.map +2 -2
- package/dist-esm/styles/TLDashStyle.mjs.map +2 -2
- package/dist-esm/styles/TLFillStyle.mjs.map +2 -2
- package/dist-esm/styles/TLFontStyle.mjs.map +2 -2
- package/dist-esm/styles/TLHorizontalAlignStyle.mjs.map +2 -2
- package/dist-esm/styles/TLSizeStyle.mjs.map +2 -2
- package/dist-esm/styles/TLTextAlignStyle.mjs.map +2 -2
- package/dist-esm/styles/TLVerticalAlignStyle.mjs.map +2 -2
- package/dist-esm/translations/translations.mjs +1 -1
- package/dist-esm/translations/translations.mjs.map +2 -2
- package/package.json +5 -5
- package/src/TLStore.test.ts +644 -0
- package/src/TLStore.ts +205 -20
- package/src/assets/TLBaseAsset.ts +90 -7
- package/src/assets/TLBookmarkAsset.test.ts +96 -0
- package/src/assets/TLBookmarkAsset.ts +52 -2
- package/src/assets/TLImageAsset.test.ts +213 -0
- package/src/assets/TLImageAsset.ts +60 -2
- package/src/assets/TLVideoAsset.test.ts +105 -0
- package/src/assets/TLVideoAsset.ts +93 -4
- package/src/bindings/TLArrowBinding.test.ts +55 -0
- package/src/bindings/TLArrowBinding.ts +132 -10
- package/src/bindings/TLBaseBinding.ts +140 -3
- package/src/createPresenceStateDerivation.test.ts +158 -0
- package/src/createPresenceStateDerivation.ts +71 -2
- package/src/createTLSchema.test.ts +181 -0
- package/src/createTLSchema.ts +164 -7
- package/src/index.ts +32 -0
- package/src/misc/TLColor.ts +50 -6
- package/src/misc/TLCursor.ts +110 -8
- package/src/misc/TLHandle.ts +86 -6
- package/src/misc/TLOpacity.ts +51 -2
- package/src/misc/TLRichText.ts +56 -3
- package/src/misc/TLScribble.ts +105 -5
- package/src/misc/geometry-types.ts +30 -2
- package/src/misc/id-validator.test.ts +50 -0
- package/src/misc/id-validator.ts +20 -1
- package/src/records/TLAsset.test.ts +234 -0
- package/src/records/TLAsset.ts +165 -8
- package/src/records/TLBinding.test.ts +22 -0
- package/src/records/TLBinding.ts +277 -11
- package/src/records/TLCamera.test.ts +19 -0
- package/src/records/TLCamera.ts +118 -7
- package/src/records/TLDocument.test.ts +35 -0
- package/src/records/TLDocument.ts +148 -8
- package/src/records/TLInstance.test.ts +201 -0
- package/src/records/TLInstance.ts +117 -9
- package/src/records/TLPage.test.ts +110 -0
- package/src/records/TLPage.ts +106 -8
- package/src/records/TLPageState.test.ts +228 -0
- package/src/records/TLPageState.ts +88 -7
- package/src/records/TLPointer.test.ts +63 -0
- package/src/records/TLPointer.ts +105 -7
- package/src/records/TLPresence.test.ts +190 -0
- package/src/records/TLPresence.ts +99 -5
- package/src/records/TLRecord.test.ts +70 -0
- package/src/records/TLRecord.ts +43 -1
- package/src/records/TLShape.test.ts +232 -0
- package/src/records/TLShape.ts +289 -12
- package/src/recordsWithProps.test.ts +188 -0
- package/src/recordsWithProps.ts +131 -2
- package/src/shapes/ShapeWithCrop.test.ts +18 -0
- package/src/shapes/ShapeWithCrop.ts +64 -2
- package/src/shapes/TLArrowShape.test.ts +505 -0
- package/src/shapes/TLArrowShape.ts +188 -10
- package/src/shapes/TLBaseShape.test.ts +142 -0
- package/src/shapes/TLBaseShape.ts +103 -4
- package/src/shapes/TLBookmarkShape.test.ts +122 -0
- package/src/shapes/TLBookmarkShape.ts +58 -4
- package/src/shapes/TLDrawShape.test.ts +177 -0
- package/src/shapes/TLDrawShape.ts +97 -6
- package/src/shapes/TLEmbedShape.test.ts +286 -0
- package/src/shapes/TLEmbedShape.ts +57 -14
- package/src/shapes/TLFrameShape.test.ts +71 -0
- package/src/shapes/TLFrameShape.ts +59 -4
- package/src/shapes/TLGeoShape.test.ts +247 -0
- package/src/shapes/TLGeoShape.ts +103 -7
- package/src/shapes/TLGroupShape.test.ts +59 -0
- package/src/shapes/TLGroupShape.ts +52 -4
- package/src/shapes/TLHighlightShape.test.ts +325 -0
- package/src/shapes/TLHighlightShape.ts +79 -4
- package/src/shapes/TLImageShape.test.ts +534 -0
- package/src/shapes/TLImageShape.ts +105 -5
- package/src/shapes/TLLineShape.test.ts +269 -0
- package/src/shapes/TLLineShape.ts +128 -8
- package/src/shapes/TLNoteShape.test.ts +1568 -0
- package/src/shapes/TLNoteShape.ts +97 -4
- package/src/shapes/TLTextShape.test.ts +407 -0
- package/src/shapes/TLTextShape.ts +94 -4
- package/src/shapes/TLVideoShape.test.ts +112 -0
- package/src/shapes/TLVideoShape.ts +99 -4
- package/src/store-migrations.test.ts +88 -0
- package/src/store-migrations.ts +47 -1
- package/src/styles/TLColorStyle.test.ts +439 -0
- package/src/styles/TLColorStyle.ts +228 -10
- package/src/styles/TLDashStyle.ts +54 -2
- package/src/styles/TLFillStyle.ts +54 -2
- package/src/styles/TLFontStyle.ts +72 -3
- package/src/styles/TLHorizontalAlignStyle.ts +55 -2
- package/src/styles/TLSizeStyle.ts +54 -2
- package/src/styles/TLTextAlignStyle.ts +52 -2
- package/src/styles/TLVerticalAlignStyle.ts +52 -2
- package/src/translations/translations.test.ts +378 -35
- package/src/translations/translations.ts +157 -10
- package/src/util-types.ts +51 -1
package/src/TLStore.ts
CHANGED
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
StoreSnapshot,
|
|
7
7
|
StoreValidationFailure,
|
|
8
8
|
} from '@tldraw/store'
|
|
9
|
-
import { IndexKey, JsonObject, annotateError, structuredClone } from '@tldraw/utils'
|
|
9
|
+
import { IndexKey, JsonObject, annotateError, sortByIndex, structuredClone } from '@tldraw/utils'
|
|
10
10
|
import { TLAsset, TLAssetId } from './records/TLAsset'
|
|
11
11
|
import { CameraRecordType, TLCameraId } from './records/TLCamera'
|
|
12
12
|
import { DocumentRecordType, TLDOCUMENT_ID } from './records/TLDocument'
|
|
@@ -16,16 +16,14 @@ import { InstancePageStateRecordType, TLInstancePageStateId } from './records/TL
|
|
|
16
16
|
import { PointerRecordType, TLPOINTER_ID } from './records/TLPointer'
|
|
17
17
|
import { TLRecord } from './records/TLRecord'
|
|
18
18
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
function redactRecordForErrorReporting(record: any) {
|
|
19
|
+
/**
|
|
20
|
+
* Redacts the source of an asset record for error reporting.
|
|
21
|
+
*
|
|
22
|
+
* @param record - The asset record to redact
|
|
23
|
+
* @returns The redacted record
|
|
24
|
+
* @internal
|
|
25
|
+
*/
|
|
26
|
+
export function redactRecordForErrorReporting(record: any) {
|
|
29
27
|
if (record.typeName === 'asset') {
|
|
30
28
|
if ('src' in record) {
|
|
31
29
|
record.src = '<redacted>'
|
|
@@ -37,16 +35,75 @@ function redactRecordForErrorReporting(record: any) {
|
|
|
37
35
|
}
|
|
38
36
|
}
|
|
39
37
|
|
|
40
|
-
/**
|
|
38
|
+
/**
|
|
39
|
+
* The complete schema type for a tldraw store, defining the structure and validation rules
|
|
40
|
+
* for all tldraw records and store properties.
|
|
41
|
+
*
|
|
42
|
+
* @public
|
|
43
|
+
* @example
|
|
44
|
+
* ```ts
|
|
45
|
+
* import { createTLSchema } from '@tldraw/tlschema'
|
|
46
|
+
*
|
|
47
|
+
* const schema = createTLSchema()
|
|
48
|
+
* const storeSchema: TLStoreSchema = schema
|
|
49
|
+
* ```
|
|
50
|
+
*/
|
|
41
51
|
export type TLStoreSchema = StoreSchema<TLRecord, TLStoreProps>
|
|
42
52
|
|
|
43
|
-
/**
|
|
53
|
+
/**
|
|
54
|
+
* A serialized representation of a tldraw store that can be persisted or transmitted.
|
|
55
|
+
* Contains all store records in a JSON-serializable format.
|
|
56
|
+
*
|
|
57
|
+
* @public
|
|
58
|
+
* @example
|
|
59
|
+
* ```ts
|
|
60
|
+
* // Serialize a store
|
|
61
|
+
* const serializedStore: TLSerializedStore = store.serialize()
|
|
62
|
+
*
|
|
63
|
+
* // Save to localStorage
|
|
64
|
+
* localStorage.setItem('drawing', JSON.stringify(serializedStore))
|
|
65
|
+
* ```
|
|
66
|
+
*/
|
|
44
67
|
export type TLSerializedStore = SerializedStore<TLRecord>
|
|
45
68
|
|
|
46
|
-
/**
|
|
69
|
+
/**
|
|
70
|
+
* A snapshot of a tldraw store at a specific point in time, containing all records
|
|
71
|
+
* and metadata. Used for persistence, synchronization, and creating store backups.
|
|
72
|
+
*
|
|
73
|
+
* @public
|
|
74
|
+
* @example
|
|
75
|
+
* ```ts
|
|
76
|
+
* // Create a snapshot
|
|
77
|
+
* const snapshot: TLStoreSnapshot = store.getSnapshot()
|
|
78
|
+
*
|
|
79
|
+
* // Restore from snapshot
|
|
80
|
+
* store.loadSnapshot(snapshot)
|
|
81
|
+
* ```
|
|
82
|
+
*/
|
|
47
83
|
export type TLStoreSnapshot = StoreSnapshot<TLRecord>
|
|
48
84
|
|
|
49
|
-
/**
|
|
85
|
+
/**
|
|
86
|
+
* Context information provided when resolving asset URLs, containing details about
|
|
87
|
+
* the current rendering environment and user's connection to optimize asset delivery.
|
|
88
|
+
*
|
|
89
|
+
* @public
|
|
90
|
+
* @example
|
|
91
|
+
* ```ts
|
|
92
|
+
* const assetStore: TLAssetStore = {
|
|
93
|
+
* async resolve(asset, context: TLAssetContext) {
|
|
94
|
+
* // Use low resolution for slow connections
|
|
95
|
+
* if (context.networkEffectiveType === 'slow-2g') {
|
|
96
|
+
* return `${asset.props.src}?quality=low`
|
|
97
|
+
* }
|
|
98
|
+
* // Use high DPI version for retina displays
|
|
99
|
+
* if (context.dpr > 1) {
|
|
100
|
+
* return `${asset.props.src}@2x`
|
|
101
|
+
* }
|
|
102
|
+
* return asset.props.src
|
|
103
|
+
* }
|
|
104
|
+
* }
|
|
105
|
+
* ```
|
|
106
|
+
*/
|
|
50
107
|
export interface TLAssetContext {
|
|
51
108
|
/**
|
|
52
109
|
* The scale at which the asset is being rendered on-screen relative to its native dimensions.
|
|
@@ -76,6 +133,9 @@ export interface TLAssetContext {
|
|
|
76
133
|
}
|
|
77
134
|
|
|
78
135
|
/**
|
|
136
|
+
* Interface for storing and managing assets (images, videos, etc.) in tldraw.
|
|
137
|
+
* Provides methods for uploading, resolving, and removing assets from storage.
|
|
138
|
+
*
|
|
79
139
|
* A `TLAssetStore` sits alongside the main {@link TLStore} and is responsible for storing and
|
|
80
140
|
* retrieving large assets such as images. Generally, this should be part of a wider sync system:
|
|
81
141
|
*
|
|
@@ -87,6 +147,24 @@ export interface TLAssetContext {
|
|
|
87
147
|
* e.g. an S3 bucket.
|
|
88
148
|
*
|
|
89
149
|
* @public
|
|
150
|
+
* @example
|
|
151
|
+
* ```ts
|
|
152
|
+
* // Simple in-memory asset store
|
|
153
|
+
* const assetStore: TLAssetStore = {
|
|
154
|
+
* async upload(asset, file) {
|
|
155
|
+
* const dataUrl = await fileToDataUrl(file)
|
|
156
|
+
* return { src: dataUrl }
|
|
157
|
+
* },
|
|
158
|
+
*
|
|
159
|
+
* async resolve(asset, context) {
|
|
160
|
+
* return asset.props.src
|
|
161
|
+
* },
|
|
162
|
+
*
|
|
163
|
+
* async remove(assetIds) {
|
|
164
|
+
* // Clean up if needed
|
|
165
|
+
* }
|
|
166
|
+
* }
|
|
167
|
+
* ```
|
|
90
168
|
*/
|
|
91
169
|
export interface TLAssetStore {
|
|
92
170
|
/**
|
|
@@ -122,24 +200,106 @@ export interface TLAssetStore {
|
|
|
122
200
|
remove?(assetIds: TLAssetId[]): Promise<void>
|
|
123
201
|
}
|
|
124
202
|
|
|
125
|
-
/**
|
|
203
|
+
/**
|
|
204
|
+
* Configuration properties for a tldraw store, defining its behavior and integrations.
|
|
205
|
+
* These props are passed when creating a new store instance.
|
|
206
|
+
*
|
|
207
|
+
* @public
|
|
208
|
+
* @example
|
|
209
|
+
* ```ts
|
|
210
|
+
* const storeProps: TLStoreProps = {
|
|
211
|
+
* defaultName: 'My Drawing',
|
|
212
|
+
* assets: myAssetStore,
|
|
213
|
+
* onMount: (editor) => {
|
|
214
|
+
* console.log('Editor mounted')
|
|
215
|
+
* return () => console.log('Editor unmounted')
|
|
216
|
+
* },
|
|
217
|
+
* collaboration: {
|
|
218
|
+
* status: statusSignal,
|
|
219
|
+
* mode: modeSignal
|
|
220
|
+
* }
|
|
221
|
+
* }
|
|
222
|
+
*
|
|
223
|
+
* const store = new Store({ schema, props: storeProps })
|
|
224
|
+
* ```
|
|
225
|
+
*/
|
|
126
226
|
export interface TLStoreProps {
|
|
227
|
+
/** Default name for new documents created in this store */
|
|
127
228
|
defaultName: string
|
|
229
|
+
/** Asset store implementation for handling file uploads and storage */
|
|
128
230
|
assets: Required<TLAssetStore>
|
|
129
231
|
/**
|
|
130
|
-
* Called an {@link @tldraw/editor#Editor} connected to this store is mounted.
|
|
232
|
+
* Called when an {@link @tldraw/editor#Editor} connected to this store is mounted.
|
|
233
|
+
* Can optionally return a cleanup function that will be called when unmounted.
|
|
234
|
+
*
|
|
235
|
+
* @param editor - The editor instance that was mounted
|
|
236
|
+
* @returns Optional cleanup function
|
|
131
237
|
*/
|
|
132
238
|
onMount(editor: unknown): void | (() => void)
|
|
239
|
+
/** Optional collaboration configuration for multiplayer features */
|
|
133
240
|
collaboration?: {
|
|
241
|
+
/** Signal indicating online/offline collaboration status */
|
|
134
242
|
status: Signal<'online' | 'offline'> | null
|
|
243
|
+
/** Signal indicating collaboration mode permissions */
|
|
135
244
|
mode?: Signal<'readonly' | 'readwrite'> | null
|
|
136
245
|
}
|
|
137
246
|
}
|
|
138
247
|
|
|
139
|
-
/**
|
|
248
|
+
/**
|
|
249
|
+
* The main tldraw store type, representing a reactive database of tldraw records
|
|
250
|
+
* with associated store properties. This is the central data structure that holds
|
|
251
|
+
* all shapes, assets, pages, and user state.
|
|
252
|
+
*
|
|
253
|
+
* @public
|
|
254
|
+
* @example
|
|
255
|
+
* ```ts
|
|
256
|
+
* import { Store } from '@tldraw/store'
|
|
257
|
+
* import { createTLSchema } from '@tldraw/tlschema'
|
|
258
|
+
*
|
|
259
|
+
* const schema = createTLSchema()
|
|
260
|
+
* const store: TLStore = new Store({
|
|
261
|
+
* schema,
|
|
262
|
+
* props: {
|
|
263
|
+
* defaultName: 'Untitled',
|
|
264
|
+
* assets: myAssetStore,
|
|
265
|
+
* onMount: () => console.log('Store mounted')
|
|
266
|
+
* }
|
|
267
|
+
* })
|
|
268
|
+
* ```
|
|
269
|
+
*/
|
|
140
270
|
export type TLStore = Store<TLRecord, TLStoreProps>
|
|
141
271
|
|
|
142
|
-
/**
|
|
272
|
+
/**
|
|
273
|
+
* Default validation failure handler for tldraw stores. This function is called
|
|
274
|
+
* when a record fails validation during store operations. It annotates errors
|
|
275
|
+
* with debugging information and determines whether to allow invalid records
|
|
276
|
+
* during store initialization.
|
|
277
|
+
*
|
|
278
|
+
* @param options - The validation failure details
|
|
279
|
+
* - error - The validation error that occurred
|
|
280
|
+
* - phase - The store operation phase when validation failed
|
|
281
|
+
* - record - The invalid record that caused the failure
|
|
282
|
+
* - recordBefore - The previous state of the record (if applicable)
|
|
283
|
+
* @returns The record to use (typically throws the annotated error)
|
|
284
|
+
* @throws The original validation error with additional debugging context
|
|
285
|
+
*
|
|
286
|
+
* @public
|
|
287
|
+
* @example
|
|
288
|
+
* ```ts
|
|
289
|
+
* const store = new Store({
|
|
290
|
+
* schema,
|
|
291
|
+
* props: storeProps,
|
|
292
|
+
* onValidationFailure // Use this as the validation failure handler
|
|
293
|
+
* })
|
|
294
|
+
*
|
|
295
|
+
* // The handler will be called automatically when validation fails
|
|
296
|
+
* try {
|
|
297
|
+
* store.put([invalidRecord])
|
|
298
|
+
* } catch (error) {
|
|
299
|
+
* // Error will contain debugging information added by onValidationFailure
|
|
300
|
+
* }
|
|
301
|
+
* ```
|
|
302
|
+
*/
|
|
143
303
|
export function onValidationFailure({
|
|
144
304
|
error,
|
|
145
305
|
phase,
|
|
@@ -179,7 +339,32 @@ function getDefaultPages() {
|
|
|
179
339
|
]
|
|
180
340
|
}
|
|
181
341
|
|
|
182
|
-
/**
|
|
342
|
+
/**
|
|
343
|
+
* Creates an integrity checker function that ensures the tldraw store maintains
|
|
344
|
+
* a consistent and usable state. The checker validates that required records exist
|
|
345
|
+
* and relationships between records are maintained.
|
|
346
|
+
*
|
|
347
|
+
* The integrity checker ensures:
|
|
348
|
+
* - Document and pointer records exist
|
|
349
|
+
* - At least one page exists
|
|
350
|
+
* - Instance state references valid pages
|
|
351
|
+
* - Page states and cameras exist for all pages
|
|
352
|
+
* - Shape references in page states are valid
|
|
353
|
+
*
|
|
354
|
+
* @param store - The tldraw store to check for integrity
|
|
355
|
+
* @returns A function that when called, validates and fixes store integrity
|
|
356
|
+
*
|
|
357
|
+
* @internal
|
|
358
|
+
* @example
|
|
359
|
+
* ```ts
|
|
360
|
+
* const checker = createIntegrityChecker(store)
|
|
361
|
+
*
|
|
362
|
+
* // Run integrity check (typically called automatically)
|
|
363
|
+
* checker()
|
|
364
|
+
*
|
|
365
|
+
* // The checker will create missing records and fix invalid references
|
|
366
|
+
* ```
|
|
367
|
+
*/
|
|
183
368
|
export function createIntegrityChecker(store: Store<TLRecord, TLStoreProps>): () => void {
|
|
184
369
|
const $pageIds = store.query.ids('page')
|
|
185
370
|
const $pageStates = store.query.records('instance_page_state')
|
|
@@ -4,26 +4,109 @@ import { T } from '@tldraw/validate'
|
|
|
4
4
|
import { idValidator } from '../misc/id-validator'
|
|
5
5
|
import { TLAssetId } from '../records/TLAsset'
|
|
6
6
|
|
|
7
|
-
/**
|
|
7
|
+
/**
|
|
8
|
+
* Base interface for all asset records in tldraw. Assets represent external resources
|
|
9
|
+
* like images, videos, or bookmarks that shapes can reference. This interface extends
|
|
10
|
+
* the base record system with asset-specific typing.
|
|
11
|
+
*
|
|
12
|
+
* @param Type - The specific asset type identifier (e.g., 'image', 'video', 'bookmark')
|
|
13
|
+
* @param Props - The properties object specific to this asset type
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* ```ts
|
|
17
|
+
* // Define a custom asset type
|
|
18
|
+
* interface MyCustomAsset extends TLBaseAsset<'custom', { url: string; title: string }> {}
|
|
19
|
+
*
|
|
20
|
+
* const customAsset: MyCustomAsset = {
|
|
21
|
+
* id: 'asset:custom123',
|
|
22
|
+
* typeName: 'asset',
|
|
23
|
+
* type: 'custom',
|
|
24
|
+
* props: {
|
|
25
|
+
* url: 'https://example.com',
|
|
26
|
+
* title: 'My Custom Asset'
|
|
27
|
+
* },
|
|
28
|
+
* meta: {}
|
|
29
|
+
* }
|
|
30
|
+
* ```
|
|
31
|
+
*
|
|
32
|
+
* @public
|
|
33
|
+
*/
|
|
8
34
|
export interface TLBaseAsset<Type extends string, Props> extends BaseRecord<'asset', TLAssetId> {
|
|
35
|
+
/** The specific type of this asset (e.g., 'image', 'video', 'bookmark') */
|
|
9
36
|
type: Type
|
|
37
|
+
/** Type-specific properties for this asset */
|
|
10
38
|
props: Props
|
|
39
|
+
/** User-defined metadata that can be attached to this asset */
|
|
11
40
|
meta: JsonObject
|
|
12
41
|
}
|
|
13
42
|
|
|
14
43
|
/**
|
|
15
|
-
* A validator for asset record type
|
|
44
|
+
* A validator for asset record type IDs. This validator ensures that asset IDs
|
|
45
|
+
* follow the correct format and type structure required by tldraw's asset system.
|
|
46
|
+
* Asset IDs are prefixed with 'asset:' followed by a unique identifier.
|
|
47
|
+
*
|
|
48
|
+
* @example
|
|
49
|
+
* ```ts
|
|
50
|
+
* import { assetIdValidator } from '@tldraw/tlschema'
|
|
51
|
+
*
|
|
52
|
+
* // Valid asset ID
|
|
53
|
+
* const validId = 'asset:abc123'
|
|
54
|
+
* console.log(assetIdValidator.isValid(validId)) // true
|
|
16
55
|
*
|
|
17
|
-
*
|
|
56
|
+
* // Invalid asset ID
|
|
57
|
+
* const invalidId = 'shape:abc123'
|
|
58
|
+
* console.log(assetIdValidator.isValid(invalidId)) // false
|
|
59
|
+
* ```
|
|
60
|
+
*
|
|
61
|
+
* @public
|
|
62
|
+
*/
|
|
18
63
|
export const assetIdValidator = idValidator<TLAssetId>('asset')
|
|
19
64
|
|
|
20
65
|
/**
|
|
21
|
-
*
|
|
66
|
+
* Creates a validator for a specific asset record type. This factory function generates
|
|
67
|
+
* a complete validator that validates the entire asset record structure including the
|
|
68
|
+
* base properties (id, typeName, type, meta) and the type-specific props.
|
|
69
|
+
*
|
|
70
|
+
* @param type - The asset type identifier (e.g., 'image', 'video', 'bookmark')
|
|
71
|
+
* @param props - The validator for the asset's type-specific properties
|
|
72
|
+
* @returns A complete validator for the asset record type
|
|
73
|
+
*
|
|
74
|
+
* @example
|
|
75
|
+
* ```ts
|
|
76
|
+
* import { createAssetValidator, TLBaseAsset } from '@tldraw/tlschema'
|
|
77
|
+
* import { T } from '@tldraw/validate'
|
|
78
|
+
*
|
|
79
|
+
* // Define a custom asset type
|
|
80
|
+
* type TLCustomAsset = TLBaseAsset<'custom', {
|
|
81
|
+
* url: string
|
|
82
|
+
* title: string
|
|
83
|
+
* description?: string
|
|
84
|
+
* }>
|
|
85
|
+
*
|
|
86
|
+
* // Create validator for the custom asset
|
|
87
|
+
* const customAssetValidator = createAssetValidator('custom', T.object({
|
|
88
|
+
* url: T.string,
|
|
89
|
+
* title: T.string,
|
|
90
|
+
* description: T.string.optional()
|
|
91
|
+
* }))
|
|
92
|
+
*
|
|
93
|
+
* // Use the validator
|
|
94
|
+
* const assetData = {
|
|
95
|
+
* id: 'asset:custom123',
|
|
96
|
+
* typeName: 'asset' as const,
|
|
97
|
+
* type: 'custom' as const,
|
|
98
|
+
* props: {
|
|
99
|
+
* url: 'https://example.com',
|
|
100
|
+
* title: 'My Custom Asset'
|
|
101
|
+
* },
|
|
102
|
+
* meta: {}
|
|
103
|
+
* }
|
|
22
104
|
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
105
|
+
* const validatedAsset = customAssetValidator.validate(assetData)
|
|
106
|
+
* ```
|
|
25
107
|
*
|
|
26
|
-
* @public
|
|
108
|
+
* @public
|
|
109
|
+
*/
|
|
27
110
|
export function createAssetValidator<Type extends string, Props extends JsonObject>(
|
|
28
111
|
type: Type,
|
|
29
112
|
props: T.Validator<Props>
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest'
|
|
2
|
+
import { getTestMigration } from '../__tests__/migrationTestUtils'
|
|
3
|
+
import { bookmarkAssetVersions } from './TLBookmarkAsset'
|
|
4
|
+
|
|
5
|
+
describe('TLBookmarkAsset', () => {
|
|
6
|
+
describe('MakeUrlsValid migration', () => {
|
|
7
|
+
const { up, down } = getTestMigration(bookmarkAssetVersions.MakeUrlsValid)
|
|
8
|
+
|
|
9
|
+
it('should clean invalid src URLs and preserve valid ones', () => {
|
|
10
|
+
const assetWithInvalidSrc = {
|
|
11
|
+
id: 'asset:bookmark1',
|
|
12
|
+
type: 'bookmark',
|
|
13
|
+
props: {
|
|
14
|
+
title: 'Test Bookmark',
|
|
15
|
+
description: 'Test Description',
|
|
16
|
+
image: 'https://example.com/image.jpg',
|
|
17
|
+
src: 'invalid-url-format',
|
|
18
|
+
},
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const result = up(assetWithInvalidSrc)
|
|
22
|
+
expect(result.props.src).toBe('')
|
|
23
|
+
|
|
24
|
+
// Test valid URL is preserved
|
|
25
|
+
const assetWithValidSrc = {
|
|
26
|
+
...assetWithInvalidSrc,
|
|
27
|
+
props: { ...assetWithInvalidSrc.props, src: 'https://example.com' },
|
|
28
|
+
}
|
|
29
|
+
const validResult = up(assetWithValidSrc)
|
|
30
|
+
expect(validResult.props.src).toBe('https://example.com')
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
it('should be a no-op down migration', () => {
|
|
34
|
+
const asset = {
|
|
35
|
+
id: 'asset:bookmark1',
|
|
36
|
+
type: 'bookmark',
|
|
37
|
+
props: {
|
|
38
|
+
title: 'Test Bookmark',
|
|
39
|
+
description: 'Test Description',
|
|
40
|
+
image: 'https://example.com/image.jpg',
|
|
41
|
+
src: 'https://example.com',
|
|
42
|
+
},
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const result = down(asset)
|
|
46
|
+
expect(result).toEqual(asset)
|
|
47
|
+
})
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
describe('AddFavicon migration', () => {
|
|
51
|
+
const { up, down } = getTestMigration(bookmarkAssetVersions.AddFavicon)
|
|
52
|
+
|
|
53
|
+
it('should add favicon property and clean invalid URLs', () => {
|
|
54
|
+
// Test adding favicon property to asset without one
|
|
55
|
+
const assetWithoutFavicon = {
|
|
56
|
+
id: 'asset:bookmark1',
|
|
57
|
+
type: 'bookmark',
|
|
58
|
+
props: {
|
|
59
|
+
title: 'Test Bookmark',
|
|
60
|
+
description: 'Test Description',
|
|
61
|
+
image: 'https://example.com/image.jpg',
|
|
62
|
+
src: 'https://example.com',
|
|
63
|
+
},
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const result = up(assetWithoutFavicon)
|
|
67
|
+
expect(result.props.favicon).toBe('')
|
|
68
|
+
|
|
69
|
+
// Test cleaning invalid favicon URL
|
|
70
|
+
const assetWithInvalidFavicon = {
|
|
71
|
+
...assetWithoutFavicon,
|
|
72
|
+
props: { ...assetWithoutFavicon.props, favicon: 'invalid-url' },
|
|
73
|
+
}
|
|
74
|
+
const cleanResult = up(assetWithInvalidFavicon)
|
|
75
|
+
expect(cleanResult.props.favicon).toBe('')
|
|
76
|
+
})
|
|
77
|
+
|
|
78
|
+
it('should remove favicon property in down migration', () => {
|
|
79
|
+
const assetWithFavicon = {
|
|
80
|
+
id: 'asset:bookmark1',
|
|
81
|
+
type: 'bookmark',
|
|
82
|
+
props: {
|
|
83
|
+
title: 'Test Bookmark',
|
|
84
|
+
description: 'Test Description',
|
|
85
|
+
image: 'https://example.com/image.jpg',
|
|
86
|
+
src: 'https://example.com',
|
|
87
|
+
favicon: 'https://example.com/favicon.ico',
|
|
88
|
+
},
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const result = down(assetWithFavicon)
|
|
92
|
+
expect(result.props).not.toHaveProperty('favicon')
|
|
93
|
+
expect(result.props.title).toBe('Test Bookmark')
|
|
94
|
+
})
|
|
95
|
+
})
|
|
96
|
+
})
|
|
@@ -18,7 +18,30 @@ export type TLBookmarkAsset = TLBaseAsset<
|
|
|
18
18
|
}
|
|
19
19
|
>
|
|
20
20
|
|
|
21
|
-
/**
|
|
21
|
+
/**
|
|
22
|
+
* Validator for TLBookmarkAsset records. Validates the structure and data types
|
|
23
|
+
* of bookmark asset properties including title, description, image, favicon, and source URL.
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* ```ts
|
|
27
|
+
* const bookmarkData = {
|
|
28
|
+
* id: 'asset:bookmark1',
|
|
29
|
+
* typeName: 'asset',
|
|
30
|
+
* type: 'bookmark',
|
|
31
|
+
* props: {
|
|
32
|
+
* title: 'Example Website',
|
|
33
|
+
* description: 'A great example site',
|
|
34
|
+
* image: 'https://example.com/preview.jpg',
|
|
35
|
+
* favicon: 'https://example.com/favicon.ico',
|
|
36
|
+
* src: 'https://example.com'
|
|
37
|
+
* }
|
|
38
|
+
* }
|
|
39
|
+
*
|
|
40
|
+
* const isValid = bookmarkAssetValidator.isValid(bookmarkData)
|
|
41
|
+
* ```
|
|
42
|
+
*
|
|
43
|
+
* @public
|
|
44
|
+
*/
|
|
22
45
|
export const bookmarkAssetValidator: T.Validator<TLBookmarkAsset> = createAssetValidator(
|
|
23
46
|
'bookmark',
|
|
24
47
|
T.object({
|
|
@@ -35,9 +58,36 @@ const Versions = createMigrationIds('com.tldraw.asset.bookmark', {
|
|
|
35
58
|
AddFavicon: 2,
|
|
36
59
|
} as const)
|
|
37
60
|
|
|
61
|
+
/**
|
|
62
|
+
* Migration version identifiers for bookmark assets. These versions track
|
|
63
|
+
* the evolution of the bookmark asset schema over time.
|
|
64
|
+
*
|
|
65
|
+
* Available versions:
|
|
66
|
+
* - `MakeUrlsValid` (v1): Ensures src URLs are valid or empty
|
|
67
|
+
* - `AddFavicon` (v2): Adds favicon property to bookmark assets
|
|
68
|
+
*
|
|
69
|
+
* @example
|
|
70
|
+
* ```ts
|
|
71
|
+
* import { bookmarkAssetVersions } from '@tldraw/tlschema'
|
|
72
|
+
*
|
|
73
|
+
* // Check if a migration exists
|
|
74
|
+
* console.log(bookmarkAssetVersions.AddFavicon) // 2
|
|
75
|
+
* ```
|
|
76
|
+
*
|
|
77
|
+
* @public
|
|
78
|
+
*/
|
|
38
79
|
export { Versions as bookmarkAssetVersions }
|
|
39
80
|
|
|
40
|
-
/**
|
|
81
|
+
/**
|
|
82
|
+
* Migration sequence for bookmark assets. Handles the evolution of bookmark asset
|
|
83
|
+
* data structure over time, ensuring backward and forward compatibility.
|
|
84
|
+
*
|
|
85
|
+
* The migration sequence includes:
|
|
86
|
+
* 1. **MakeUrlsValid** (v1): Validates and cleans up src URLs, setting invalid URLs to empty string
|
|
87
|
+
* 2. **AddFavicon** (v2): Adds the favicon property and validates it, setting invalid favicons to empty string
|
|
88
|
+
*
|
|
89
|
+
* @public
|
|
90
|
+
*/
|
|
41
91
|
export const bookmarkAssetMigrations = createRecordMigrationSequence({
|
|
42
92
|
sequenceId: 'com.tldraw.asset.bookmark',
|
|
43
93
|
recordType: 'asset',
|