derived presence state (#1204)
This PR adds - A new `TLInstancePresence` record type, to collect info about the presence state in a particular instance of the editor. This will eventually be used to sync presence data instead of sending instance-only state across the wire. - **Record Scopes** `RecordType` now has a `scope` property which can be one of three things: - `document`: the record belongs to the document and should be synced and persisted freely. Currently: `TLDocument`, `TLPage`, `TLShape`, and `TLAsset` - `instance`: the record belongs to a single instance of the store and should not be synced at all. It should not be persisted directly in most cases, but rather compiled into a kind of 'instance configuration' to store alongside the local document data so that when reopening the associated document it can remember some of the previous instance state. Currently: `TLInstance`, `TLInstancePageState`, `TLCamera`, `TLUser`, `TLUserDocument`, `TLUserPresence` - `presence`: the record belongs to a single instance of the store and should not be persisted, but may be synced using the special presence sync protocol. Currently just `TLInstancePresence` This sets us up for the following changes, which are gonna be pretty high-impact in terms of integrating tldraw into existing systems: - Removing `instanceId` as a config option. Each instance gets a randomly generated ID. - We'd replace it with an `instanceConfig` option that has stuff like selectedIds, camera positions, and so on. Then it's up to library users to get and reinstate the instance config at persistence boundaries. - Removing `userId` as config option, and removing the `TLUser` type altogether. - We might need to revisit when doing auth-enabled features like locking shapes, but I suspect that will be separate.
This commit is contained in:
parent
da613ea6ef
commit
731da1bc77
40 changed files with 396 additions and 93 deletions
|
@ -49,11 +49,10 @@ export function generateSharedTasks(bublic: '<rootDir>' | '<rootDir>/bublic') {
|
|||
cache: {
|
||||
inputs: {
|
||||
include: [
|
||||
'{.,./bublic}/packages/*/src/**/*.{ts,tsx}',
|
||||
'{.,./bublic}/{apps,scripts,e2e}/**/*.{ts,tsx}',
|
||||
'{.,./bublic}/{apps,packages}/*/tsconfig.json',
|
||||
'{.,./bublic}/{scripts,e2e}/tsconfig.json',
|
||||
`${bublic}/config/tsconfig.base.json`,
|
||||
'{,bublic/}packages/*/src/**/*.{ts,tsx}',
|
||||
'{,bublic/}{apps,scripts,e2e}/**/*.{ts,tsx}',
|
||||
'{,bublic/}{apps,packages}/*/tsconfig.json',
|
||||
'{,bublic/}{scripts,e2e}/tsconfig.json',
|
||||
],
|
||||
exclude: ['**/dist*/**/*.d.ts'],
|
||||
},
|
||||
|
@ -95,7 +94,7 @@ export function generateSharedTasks(bublic: '<rootDir>' | '<rootDir>/bublic') {
|
|||
baseCommand: `tsx ${bublic}/scripts/api-check.ts`,
|
||||
runsAfter: { 'build:api': {} },
|
||||
cache: {
|
||||
inputs: ['**/api/bublic.d.ts'],
|
||||
inputs: [`${bublic}/packages/*/api/public.d.ts`],
|
||||
},
|
||||
},
|
||||
} satisfies LazyConfig['tasks']
|
||||
|
|
|
@ -87,8 +87,8 @@
|
|||
},
|
||||
"devDependencies": {
|
||||
"@microsoft/api-extractor": "^7.34.1",
|
||||
"@swc/core": "^1.3.41",
|
||||
"@swc/jest": "^0.2.24",
|
||||
"@swc/core": "^1.3.55",
|
||||
"@swc/jest": "^0.2.26",
|
||||
"@types/glob": "^8.1.0",
|
||||
"auto": "^10.44.0",
|
||||
"fs-extra": "^11.1.0",
|
||||
|
|
|
@ -48,8 +48,6 @@
|
|||
"@tldraw/utils": "workspace:*"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@swc/core": "^1.2.204",
|
||||
"@swc/jest": "^0.2.21",
|
||||
"lazyrepo": "0.0.0-alpha.22",
|
||||
"ts-node-dev": "^1.1.8"
|
||||
},
|
||||
|
|
|
@ -31,6 +31,7 @@ import { SelectionCorner } from '@tldraw/primitives';
|
|||
import { SelectionEdge } from '@tldraw/primitives';
|
||||
import { SelectionHandle } from '@tldraw/primitives';
|
||||
import { SerializedSchema } from '@tldraw/tlstore';
|
||||
import { Signal } from 'signia';
|
||||
import { StoreSchema } from '@tldraw/tlstore';
|
||||
import { StoreSnapshot } from '@tldraw/tlstore';
|
||||
import { StoreValidator } from '@tldraw/tlstore';
|
||||
|
@ -62,6 +63,7 @@ import { TLImageShape } from '@tldraw/tlschema';
|
|||
import { TLInstance } from '@tldraw/tlschema';
|
||||
import { TLInstanceId } from '@tldraw/tlschema';
|
||||
import { TLInstancePageState } from '@tldraw/tlschema';
|
||||
import { TLInstancePresence } from '@tldraw/tlschema';
|
||||
import { TLInstancePropsForNextShape } from '@tldraw/tlschema';
|
||||
import { TLLineShape } from '@tldraw/tlschema';
|
||||
import { TLNoteShape } from '@tldraw/tlschema';
|
||||
|
@ -1797,10 +1799,11 @@ export function TldrawEditor(props: TldrawEditorProps): JSX.Element;
|
|||
|
||||
// @public (undocumented)
|
||||
export class TldrawEditorConfig {
|
||||
constructor({ shapes, tools, allowUnknownShapes, }: {
|
||||
constructor(args: {
|
||||
shapes?: readonly TLShapeDef<any, any>[];
|
||||
tools?: readonly StateNodeConstructor[];
|
||||
allowUnknownShapes?: boolean;
|
||||
derivePresenceState?: (store: TLStore) => Signal<null | TLInstancePresence>;
|
||||
});
|
||||
// (undocumented)
|
||||
createStore(config: {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
require('fake-indexeddb/auto')
|
||||
global.ResizeObserver = require('resize-observer-polyfill')
|
||||
global.crypto = new (require('@peculiar/webcrypto').Crypto)()
|
||||
global.crypto ??= new (require('@peculiar/webcrypto').Crypto)()
|
||||
global.FontFace = class FontFace {
|
||||
load() {
|
||||
return Promise.resolve()
|
||||
|
|
|
@ -1,16 +1,13 @@
|
|||
import {
|
||||
CLIENT_FIXUP_SCRIPT,
|
||||
ensureStoreIsUsable,
|
||||
onValidationFailure,
|
||||
rootShapeTypeMigrations,
|
||||
storeMigrations,
|
||||
TLAsset,
|
||||
TLCamera,
|
||||
TLDocument,
|
||||
TLDOCUMENT_ID,
|
||||
TLDocument,
|
||||
TLInstance,
|
||||
TLInstanceId,
|
||||
TLInstancePageState,
|
||||
TLInstancePresence,
|
||||
TLPage,
|
||||
TLRecord,
|
||||
TLShape,
|
||||
|
@ -20,16 +17,21 @@ import {
|
|||
TLUserDocument,
|
||||
TLUserId,
|
||||
TLUserPresence,
|
||||
ensureStoreIsUsable,
|
||||
onValidationFailure,
|
||||
rootShapeTypeMigrations,
|
||||
storeMigrations,
|
||||
} from '@tldraw/tlschema'
|
||||
import {
|
||||
createRecordType,
|
||||
defineMigrations,
|
||||
RecordType,
|
||||
Store,
|
||||
StoreSchema,
|
||||
StoreSnapshot,
|
||||
createRecordType,
|
||||
defineMigrations,
|
||||
} from '@tldraw/tlstore'
|
||||
import { T } from '@tldraw/tlvalidate'
|
||||
import { Signal } from 'signia'
|
||||
import { TLArrowShapeDef } from '../app/shapeutils/TLArrowUtil/TLArrowUtil'
|
||||
import { TLBookmarkShapeDef } from '../app/shapeutils/TLBookmarkUtil/TLBookmarkUtil'
|
||||
import { TLDrawShapeDef } from '../app/shapeutils/TLDrawUtil/TLDrawUtil'
|
||||
|
@ -44,6 +46,7 @@ import { TLTextShapeDef } from '../app/shapeutils/TLTextUtil/TLTextUtil'
|
|||
import { TLVideoShapeDef } from '../app/shapeutils/TLVideoUtil/TLVideoUtil'
|
||||
import { StateNodeConstructor } from '../app/statechart/StateNode'
|
||||
import { TLShapeDef, TLUnknownShapeDef } from './TLShapeDefinition'
|
||||
import { defaultDerivePresenceState } from './defaultDerivePresenceState'
|
||||
|
||||
const CORE_SHAPE_DEFS = () =>
|
||||
[
|
||||
|
@ -70,15 +73,19 @@ export class TldrawEditorConfig {
|
|||
readonly TLShape: RecordType<TLShape, 'type' | 'props' | 'index' | 'parentId'>
|
||||
readonly tools: readonly StateNodeConstructor[]
|
||||
|
||||
constructor({
|
||||
shapes = [],
|
||||
tools = [],
|
||||
allowUnknownShapes = false,
|
||||
}: {
|
||||
constructor(args: {
|
||||
shapes?: readonly TLShapeDef<any, any>[]
|
||||
tools?: readonly StateNodeConstructor[]
|
||||
allowUnknownShapes?: boolean
|
||||
/** @internal */
|
||||
derivePresenceState?: (store: TLStore) => Signal<TLInstancePresence | null>
|
||||
}) {
|
||||
const {
|
||||
shapes = [],
|
||||
tools = [],
|
||||
allowUnknownShapes = false,
|
||||
derivePresenceState = defaultDerivePresenceState,
|
||||
} = args
|
||||
this.tools = tools
|
||||
|
||||
const allShapeDefs = [...CORE_SHAPE_DEFS(), ...shapes]
|
||||
|
@ -110,6 +117,7 @@ export class TldrawEditorConfig {
|
|||
const shapeRecord = createRecordType<TLShape>('shape', {
|
||||
migrations: shapeTypeMigrations,
|
||||
validator: T.model('shape', shapeValidator),
|
||||
scope: 'document',
|
||||
}).withDefaultProperties(() => ({ x: 0, y: 0, rotation: 0, isLocked: false }))
|
||||
this.TLShape = shapeRecord
|
||||
|
||||
|
@ -125,11 +133,13 @@ export class TldrawEditorConfig {
|
|||
user: TLUser,
|
||||
user_document: TLUserDocument,
|
||||
user_presence: TLUserPresence,
|
||||
instance_presence: TLInstancePresence,
|
||||
},
|
||||
{
|
||||
snapshotMigrations: storeMigrations,
|
||||
onValidationFailure,
|
||||
ensureStoreIsUsable,
|
||||
derivePresenceState,
|
||||
}
|
||||
)
|
||||
}
|
||||
|
|
56
packages/editor/src/lib/config/defaultDerivePresenceState.ts
Normal file
56
packages/editor/src/lib/config/defaultDerivePresenceState.ts
Normal file
|
@ -0,0 +1,56 @@
|
|||
import { TLInstancePresence, TLStore } from '@tldraw/tlschema'
|
||||
import { Signal, computed } from 'signia'
|
||||
|
||||
/** @internal */
|
||||
export const defaultDerivePresenceState = (store: TLStore): Signal<TLInstancePresence | null> => {
|
||||
const $instance = store.query.record('instance', () => ({
|
||||
id: { eq: store.props.instanceId },
|
||||
}))
|
||||
const $user = store.query.record('user', () => ({ id: { eq: store.props.userId } }))
|
||||
const $userPresence = store.query.record('user_presence', () => ({
|
||||
userId: { eq: store.props.userId },
|
||||
}))
|
||||
const $pageState = store.query.record('instance_page_state', () => ({
|
||||
instanceId: { eq: store.props.instanceId },
|
||||
pageId: { eq: $instance.value?.currentPageId ?? ('' as any) },
|
||||
}))
|
||||
const $camera = store.query.record('camera', () => ({
|
||||
id: { eq: $pageState.value?.cameraId ?? ('' as any) },
|
||||
}))
|
||||
return computed('instancePresence', () => {
|
||||
const pageState = $pageState.value
|
||||
const instance = $instance.value
|
||||
const user = $user.value
|
||||
const userPresence = $userPresence.value
|
||||
const camera = $camera.value
|
||||
if (!pageState || !instance || !user || !userPresence || !camera) {
|
||||
return null
|
||||
}
|
||||
|
||||
return TLInstancePresence.create({
|
||||
id: TLInstancePresence.createCustomId(store.props.instanceId),
|
||||
instanceId: store.props.instanceId,
|
||||
selectedIds: pageState.selectedIds,
|
||||
brush: instance.brush,
|
||||
scribble: instance.scribble,
|
||||
userId: store.props.userId,
|
||||
userName: user.name,
|
||||
followingUserId: instance.followingUserId,
|
||||
camera: {
|
||||
x: camera.x,
|
||||
y: camera.y,
|
||||
z: camera.z,
|
||||
},
|
||||
color: userPresence.color,
|
||||
currentPageId: instance.currentPageId,
|
||||
cursor: {
|
||||
x: userPresence.cursor.x,
|
||||
y: userPresence.cursor.y,
|
||||
rotation: instance.cursor.rotation,
|
||||
type: instance.cursor.type,
|
||||
},
|
||||
lastActivityTimestamp: userPresence.lastActivityTimestamp,
|
||||
screenBounds: instance.screenBounds,
|
||||
})
|
||||
})
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
require('fake-indexeddb/auto')
|
||||
require('jest-canvas-mock')
|
||||
global.ResizeObserver = require('resize-observer-polyfill')
|
||||
global.crypto = new (require('@peculiar/webcrypto').Crypto)()
|
||||
global.crypto ??= new (require('@peculiar/webcrypto').Crypto)()
|
||||
global.FontFace = class FontFace {
|
||||
load() {
|
||||
return Promise.resolve()
|
||||
|
|
|
@ -1011,6 +1011,48 @@ export const TLInstancePageState: RecordType<TLInstancePageState, "cameraId" | "
|
|||
// @public (undocumented)
|
||||
export type TLInstancePageStateId = ID<TLInstancePageState>;
|
||||
|
||||
// @public (undocumented)
|
||||
export interface TLInstancePresence extends BaseRecord<'instance_presence'> {
|
||||
// (undocumented)
|
||||
brush: Box2dModel | null;
|
||||
// (undocumented)
|
||||
camera: {
|
||||
x: number;
|
||||
y: number;
|
||||
z: number;
|
||||
};
|
||||
// (undocumented)
|
||||
color: string;
|
||||
// (undocumented)
|
||||
currentPageId: TLPageId;
|
||||
// (undocumented)
|
||||
cursor: {
|
||||
x: number;
|
||||
y: number;
|
||||
type: TLCursor['type'];
|
||||
rotation: number;
|
||||
};
|
||||
// (undocumented)
|
||||
followingUserId: null | TLUserId;
|
||||
// (undocumented)
|
||||
instanceId: TLInstanceId;
|
||||
// (undocumented)
|
||||
lastActivityTimestamp: number;
|
||||
// (undocumented)
|
||||
screenBounds: Box2dModel;
|
||||
// (undocumented)
|
||||
scribble: null | TLScribble;
|
||||
// (undocumented)
|
||||
selectedIds: TLShapeId[];
|
||||
// (undocumented)
|
||||
userId: TLUserId;
|
||||
// (undocumented)
|
||||
userName: string;
|
||||
}
|
||||
|
||||
// @public (undocumented)
|
||||
export const TLInstancePresence: RecordType<TLInstancePresence, "brush" | "camera" | "color" | "currentPageId" | "cursor" | "followingUserId" | "instanceId" | "lastActivityTimestamp" | "screenBounds" | "scribble" | "selectedIds" | "userId" | "userName">;
|
||||
|
||||
// @public (undocumented)
|
||||
export type TLInstancePropsForNextShape = Pick<TLShapeProps, TLStyleType>;
|
||||
|
||||
|
@ -1078,7 +1120,7 @@ export type TLPageId = ID<TLPage>;
|
|||
export type TLParentId = TLPageId | TLShapeId;
|
||||
|
||||
// @public (undocumented)
|
||||
export type TLRecord = TLAsset | TLCamera | TLDocument | TLInstance | TLInstancePageState | TLPage | TLShape | TLUser | TLUserDocument | TLUserPresence;
|
||||
export type TLRecord = TLAsset | TLCamera | TLDocument | TLInstance | TLInstancePageState | TLInstancePresence | TLPage | TLShape | TLUser | TLUserDocument | TLUserPresence;
|
||||
|
||||
// @public (undocumented)
|
||||
export type TLScribble = {
|
||||
|
|
|
@ -3,6 +3,7 @@ import { TLCamera } from './records/TLCamera'
|
|||
import { TLDocument } from './records/TLDocument'
|
||||
import { TLInstance } from './records/TLInstance'
|
||||
import { TLInstancePageState } from './records/TLInstancePageState'
|
||||
import { TLInstancePresence } from './records/TLInstancePresence'
|
||||
import { TLPage } from './records/TLPage'
|
||||
import { TLShape } from './records/TLShape'
|
||||
import { TLUser } from './records/TLUser'
|
||||
|
@ -21,3 +22,4 @@ export type TLRecord =
|
|||
| TLUser
|
||||
| TLUserDocument
|
||||
| TLUserPresence
|
||||
| TLInstancePresence
|
||||
|
|
|
@ -59,6 +59,7 @@ export {
|
|||
instancePageStateTypeValidator,
|
||||
type TLInstancePageStateId,
|
||||
} from './records/TLInstancePageState'
|
||||
export { TLInstancePresence } from './records/TLInstancePresence'
|
||||
export { TLPage, pageTypeMigrations, pageTypeValidator, type TLPageId } from './records/TLPage'
|
||||
export {
|
||||
createCustomShapeId,
|
||||
|
|
|
@ -172,6 +172,7 @@ describe('TLImageAsset AddIsAnimated', () => {
|
|||
|
||||
const ShapeRecord = createRecordType('shape', {
|
||||
validator: { validate: (record) => record as TLShape },
|
||||
scope: 'document',
|
||||
})
|
||||
|
||||
describe('Store removing Icon and Code shapes', () => {
|
||||
|
@ -634,6 +635,24 @@ describe('Add crop=null to image shapes', () => {
|
|||
})
|
||||
})
|
||||
|
||||
describe('Adding instance_presence to the schema', () => {
|
||||
const { up, down } = storeMigrations.migrators[2]
|
||||
|
||||
test('up works as expected', () => {
|
||||
expect(up({})).toEqual({})
|
||||
})
|
||||
test('down works as expected', () => {
|
||||
expect(
|
||||
down({
|
||||
'instance_presence:123': { id: 'instance_presence:123', typeName: 'instance_presence' },
|
||||
'instance:123': { id: 'instance:123', typeName: 'instance' },
|
||||
})
|
||||
).toEqual({
|
||||
'instance:123': { id: 'instance:123', typeName: 'instance' },
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
/* --- PUT YOUR MIGRATIONS TESTS ABOVE HERE --- */
|
||||
|
||||
for (const migrator of allMigrators) {
|
||||
|
|
|
@ -60,6 +60,7 @@ export type TLAssetPartial<T extends TLAsset = TLAsset> = T extends T
|
|||
export const TLAsset = createRecordType<TLAsset>('asset', {
|
||||
migrations: assetTypeMigrations,
|
||||
validator: assetTypeValidator,
|
||||
scope: 'document',
|
||||
})
|
||||
|
||||
/** @public */
|
||||
|
|
|
@ -49,6 +49,7 @@ export const cameraTypeMigrations = defineMigrations({
|
|||
export const TLCamera = createRecordType<TLCamera>('camera', {
|
||||
migrations: cameraTypeMigrations,
|
||||
validator: cameraTypeValidator,
|
||||
scope: 'instance',
|
||||
}).withDefaultProperties(
|
||||
(): Omit<TLCamera, 'id' | 'typeName'> => ({
|
||||
x: 0,
|
||||
|
|
|
@ -41,6 +41,7 @@ export const documentTypeMigrations = defineMigrations({
|
|||
export const TLDocument = createRecordType<TLDocument>('document', {
|
||||
migrations: documentTypeMigrations,
|
||||
validator: documentTypeValidator,
|
||||
scope: 'document',
|
||||
}).withDefaultProperties(
|
||||
(): Omit<TLDocument, 'id' | 'typeName'> => ({
|
||||
gridSize: 10,
|
||||
|
|
|
@ -213,6 +213,7 @@ export const instanceTypeMigrations = defineMigrations({
|
|||
export const TLInstance = createRecordType<TLInstance>('instance', {
|
||||
migrations: instanceTypeMigrations,
|
||||
validator: instanceTypeValidator,
|
||||
scope: 'instance',
|
||||
}).withDefaultProperties(
|
||||
(): Omit<TLInstance, 'typeName' | 'id' | 'userId' | 'currentPageId'> => ({
|
||||
followingUserId: null,
|
||||
|
|
|
@ -74,6 +74,7 @@ export const instancePageStateMigrations = defineMigrations({
|
|||
export const TLInstancePageState = createRecordType<TLInstancePageState>('instance_page_state', {
|
||||
migrations: instancePageStateMigrations,
|
||||
validator: instancePageStateTypeValidator,
|
||||
scope: 'instance',
|
||||
}).withDefaultProperties(
|
||||
(): Omit<
|
||||
TLInstancePageState,
|
||||
|
|
89
packages/tlschema/src/records/TLInstancePresence.ts
Normal file
89
packages/tlschema/src/records/TLInstancePresence.ts
Normal file
|
@ -0,0 +1,89 @@
|
|||
import { BaseRecord, createRecordType, defineMigrations, ID } from '@tldraw/tlstore'
|
||||
import { T } from '@tldraw/tlvalidate'
|
||||
import { Box2dModel } from '../geometry-types'
|
||||
import { cursorTypeValidator, scribbleTypeValidator, TLCursor, TLScribble } from '../ui-types'
|
||||
import { idValidator, userIdValidator } from '../validation'
|
||||
import { TLInstanceId } from './TLInstance'
|
||||
import { TLPageId } from './TLPage'
|
||||
import { TLShapeId } from './TLShape'
|
||||
import { TLUserId } from './TLUser'
|
||||
|
||||
/** @public */
|
||||
export interface TLInstancePresence extends BaseRecord<'instance_presence'> {
|
||||
instanceId: TLInstanceId
|
||||
userId: TLUserId
|
||||
userName: string
|
||||
lastActivityTimestamp: number
|
||||
color: string // can be any hex color
|
||||
camera: { x: number; y: number; z: number }
|
||||
selectedIds: TLShapeId[]
|
||||
currentPageId: TLPageId
|
||||
brush: Box2dModel | null
|
||||
scribble: TLScribble | null
|
||||
screenBounds: Box2dModel
|
||||
followingUserId: TLUserId | null
|
||||
cursor: {
|
||||
x: number
|
||||
y: number
|
||||
type: TLCursor['type']
|
||||
rotation: number
|
||||
}
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export type TLInstancePresenceID = ID<TLInstancePresence>
|
||||
|
||||
// --- VALIDATION ---
|
||||
/** @public */
|
||||
export const instancePresenceTypeValidator: T.Validator<TLInstancePresence> = T.model(
|
||||
'instance_presence',
|
||||
T.object({
|
||||
instanceId: idValidator<TLInstanceId>('instance'),
|
||||
typeName: T.literal('instance_presence'),
|
||||
id: idValidator<TLInstancePresenceID>('instance_presence'),
|
||||
userId: userIdValidator,
|
||||
userName: T.string,
|
||||
lastActivityTimestamp: T.number,
|
||||
followingUserId: userIdValidator.nullable(),
|
||||
cursor: T.object({
|
||||
x: T.number,
|
||||
y: T.number,
|
||||
type: cursorTypeValidator,
|
||||
rotation: T.number,
|
||||
}),
|
||||
color: T.string,
|
||||
camera: T.object({
|
||||
x: T.number,
|
||||
y: T.number,
|
||||
z: T.number,
|
||||
}),
|
||||
screenBounds: T.boxModel,
|
||||
selectedIds: T.arrayOf(idValidator<TLShapeId>('shape')),
|
||||
currentPageId: idValidator<TLPageId>('page'),
|
||||
brush: T.boxModel.nullable(),
|
||||
scribble: scribbleTypeValidator.nullable(),
|
||||
})
|
||||
)
|
||||
|
||||
// --- MIGRATIONS ---
|
||||
// STEP 1: Add a new version number here, give it a meaningful name.
|
||||
// It should be 1 higher than the current version
|
||||
const Versions = {
|
||||
Initial: 0,
|
||||
} as const
|
||||
|
||||
export const userPresenceTypeMigrations = defineMigrations({
|
||||
// STEP 2: Update the current version to point to your latest version
|
||||
currentVersion: Versions.Initial,
|
||||
firstVersion: Versions.Initial,
|
||||
migrators: {
|
||||
// STEP 3: Add an up+down migration for the new version here
|
||||
},
|
||||
})
|
||||
|
||||
/** @public */
|
||||
export const TLInstancePresence = createRecordType<TLInstancePresence>('instance_presence', {
|
||||
migrations: userPresenceTypeMigrations,
|
||||
validator: instancePresenceTypeValidator,
|
||||
scope: 'presence',
|
||||
})
|
|
@ -47,4 +47,5 @@ export const pageTypeMigrations = defineMigrations({
|
|||
export const TLPage = createRecordType<TLPage>('page', {
|
||||
migrations: pageTypeMigrations,
|
||||
validator: pageTypeValidator,
|
||||
scope: 'document',
|
||||
})
|
||||
|
|
|
@ -48,6 +48,7 @@ export const userTypeMigrations = defineMigrations({
|
|||
export const TLUser = createRecordType<TLUser>('user', {
|
||||
migrations: userTypeMigrations,
|
||||
validator: userTypeValidator,
|
||||
scope: 'instance',
|
||||
}).withDefaultProperties((): Omit<TLUser, 'id' | 'typeName'> => {
|
||||
let lang
|
||||
if (typeof window !== 'undefined' && window.navigator) {
|
||||
|
|
|
@ -87,6 +87,7 @@ export const userDocumentTypeMigrations = defineMigrations({
|
|||
export const TLUserDocument = createRecordType<TLUserDocument>('user_document', {
|
||||
migrations: userDocumentTypeMigrations,
|
||||
validator: userDocumentTypeValidator,
|
||||
scope: 'instance',
|
||||
}).withDefaultProperties(
|
||||
(): Omit<TLUserDocument, 'id' | 'typeName' | 'userId'> => ({
|
||||
/* STEP 6: Add any new default values for properties here */
|
||||
|
|
|
@ -65,6 +65,7 @@ export const userPresenceTypeMigrations = defineMigrations({
|
|||
export const TLUserPresence = createRecordType<TLUserPresence>('user_presence', {
|
||||
migrations: userPresenceTypeMigrations,
|
||||
validator: userPresenceTypeValidator,
|
||||
scope: 'instance',
|
||||
}).withDefaultProperties(
|
||||
(): Omit<TLUserPresence, 'id' | 'typeName' | 'userId'> => ({
|
||||
lastUsedInstanceId: null,
|
||||
|
|
|
@ -7,13 +7,14 @@ import { TLRecord } from './TLRecord'
|
|||
const Versions = {
|
||||
Initial: 0,
|
||||
RemoveCodeAndIconShapeTypes: 1,
|
||||
AddInstancePresenceType: 2,
|
||||
} as const
|
||||
|
||||
/** @public */
|
||||
export const storeMigrations = defineMigrations({
|
||||
// STEP 2: Update the current version to point to your latest version
|
||||
firstVersion: Versions.Initial,
|
||||
currentVersion: Versions.RemoveCodeAndIconShapeTypes,
|
||||
currentVersion: Versions.AddInstancePresenceType,
|
||||
migrators: {
|
||||
// STEP 3: Add an up+down migration for the new version here
|
||||
[Versions.RemoveCodeAndIconShapeTypes]: {
|
||||
|
@ -29,5 +30,15 @@ export const storeMigrations = defineMigrations({
|
|||
return store
|
||||
},
|
||||
},
|
||||
[Versions.AddInstancePresenceType]: {
|
||||
up: (store: StoreSnapshot<TLRecord>) => {
|
||||
return store
|
||||
},
|
||||
down: (store: StoreSnapshot<TLRecord>) => {
|
||||
return Object.fromEntries(
|
||||
Object.entries(store).filter(([_, v]) => v.typeName !== 'instance_presence')
|
||||
)
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
import { Atom } from 'signia';
|
||||
import { Computed } from 'signia';
|
||||
import { Signal } from 'signia';
|
||||
|
||||
// @public
|
||||
export type AllRecords<T extends Store<any>> = ExtractR<ExtractRecordType<T>>;
|
||||
|
@ -31,7 +32,7 @@ export type CollectionDiff<T> = {
|
|||
export function compareRecordVersions(a: RecordVersion, b: RecordVersion): -1 | 0 | 1;
|
||||
|
||||
// @public (undocumented)
|
||||
export const compareSchemas: (a: SerializedSchema, b: SerializedSchema) => number;
|
||||
export const compareSchemas: (a: SerializedSchema, b: SerializedSchema) => -1 | 0 | 1;
|
||||
|
||||
// @public
|
||||
export type ComputedCache<Data, R extends BaseRecord> = {
|
||||
|
@ -42,6 +43,7 @@ export type ComputedCache<Data, R extends BaseRecord> = {
|
|||
export function createRecordType<R extends BaseRecord>(typeName: R['typeName'], config: {
|
||||
migrations?: Migrations;
|
||||
validator: StoreValidator<R>;
|
||||
scope: Scope;
|
||||
}): RecordType<R, keyof Omit<R, 'id' | 'typeName'>>;
|
||||
|
||||
// @public (undocumented)
|
||||
|
@ -158,6 +160,7 @@ export class RecordType<R extends BaseRecord, RequiredProperties extends keyof O
|
|||
readonly validator?: {
|
||||
validate: (r: unknown) => R;
|
||||
} | StoreValidator<R>;
|
||||
readonly scope?: Scope;
|
||||
});
|
||||
clone(record: R): R;
|
||||
create(properties: Pick<R, RequiredProperties> & Omit<Partial<R>, RequiredProperties>): R;
|
||||
|
@ -170,6 +173,8 @@ export class RecordType<R extends BaseRecord, RequiredProperties extends keyof O
|
|||
// (undocumented)
|
||||
readonly migrations: Migrations;
|
||||
parseId(id: string): ID<R>;
|
||||
// (undocumented)
|
||||
readonly scope: Scope;
|
||||
readonly typeName: R['typeName'];
|
||||
validate(record: unknown): R;
|
||||
// (undocumented)
|
||||
|
@ -274,6 +279,8 @@ export class StoreSchema<R extends BaseRecord, P = unknown> {
|
|||
// (undocumented)
|
||||
get currentStoreVersion(): number;
|
||||
// @internal (undocumented)
|
||||
derivePresenceState(store: Store<R, P>): Signal<null | R> | undefined;
|
||||
// @internal (undocumented)
|
||||
ensureStoreIsUsable(store: Store<R, P>): void;
|
||||
// (undocumented)
|
||||
migratePersistedRecord(record: R, persistedSchema: SerializedSchema, direction?: 'down' | 'up'): MigrationResult<R>;
|
||||
|
@ -302,6 +309,7 @@ export type StoreSchemaOptions<R extends BaseRecord, P> = {
|
|||
recordBefore: null | R;
|
||||
}) => R;
|
||||
ensureStoreIsUsable?: (store: Store<R, P>) => void;
|
||||
derivePresenceState?: (store: Store<R, P>) => Signal<null | R>;
|
||||
};
|
||||
|
||||
// @public
|
||||
|
|
|
@ -6,6 +6,17 @@ import { Migrations } from './migrate'
|
|||
|
||||
export type RecordTypeRecord<R extends RecordType<any, any>> = ReturnType<R['create']>
|
||||
|
||||
/**
|
||||
* Defines the scope of the record
|
||||
*
|
||||
* instance: The record belongs to a single instance of the store. It should not be synced, and any persistence logic should 'de-instance-ize' the record before persisting it, and apply the reverse when rehydrating.
|
||||
* document: The record is persisted and synced. It is available to all store instances.
|
||||
* presence: The record belongs to a single instance of the store. It may be synced to other instances, but other instances should not make changes to it. It should not be persisted.
|
||||
*
|
||||
* @public
|
||||
* */
|
||||
export type Scope = 'instance' | 'document' | 'presence'
|
||||
|
||||
/**
|
||||
* A record type is a type that can be stored in a record store. It is created with
|
||||
* `createRecordType`.
|
||||
|
@ -20,6 +31,8 @@ export class RecordType<
|
|||
readonly migrations: Migrations
|
||||
readonly validator: StoreValidator<R> | { validate: (r: unknown) => R }
|
||||
|
||||
readonly scope: Scope
|
||||
|
||||
constructor(
|
||||
/**
|
||||
* The unique type associated with this record.
|
||||
|
@ -32,11 +45,13 @@ export class RecordType<
|
|||
readonly createDefaultProperties: () => Exclude<OmitMeta<R>, RequiredProperties>
|
||||
readonly migrations: Migrations
|
||||
readonly validator?: StoreValidator<R> | { validate: (r: unknown) => R }
|
||||
readonly scope?: Scope
|
||||
}
|
||||
) {
|
||||
this.createDefaultProperties = config.createDefaultProperties
|
||||
this.migrations = config.migrations
|
||||
this.validator = config.validator ?? { validate: (r: unknown) => r as R }
|
||||
this.scope = config.scope ?? 'document'
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -174,6 +189,7 @@ export class RecordType<
|
|||
createDefaultProperties: createDefaultProperties as any,
|
||||
migrations: this.migrations,
|
||||
validator: this.validator,
|
||||
scope: this.scope,
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -204,12 +220,14 @@ export function createRecordType<R extends BaseRecord>(
|
|||
migrations?: Migrations
|
||||
// todo: optional validations
|
||||
validator: StoreValidator<R>
|
||||
scope: Scope
|
||||
}
|
||||
): RecordType<R, keyof Omit<R, 'id' | 'typeName'>> {
|
||||
return new RecordType<R, keyof Omit<R, 'id' | 'typeName'>>(typeName, {
|
||||
createDefaultProperties: () => ({} as any),
|
||||
migrations: config.migrations ?? { currentVersion: 0, firstVersion: 0, migrators: {} },
|
||||
validator: config.validator,
|
||||
scope: config.scope,
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -766,15 +766,4 @@ class HistoryAccumulator<T extends BaseRecord> {
|
|||
hasChanges() {
|
||||
return this._history.length > 0
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure that the store is usable. A class that extends this store should override this method.
|
||||
*
|
||||
* @param config - The configuration object. This can be any object that allows the store to
|
||||
* validate that it is usable; the extending class should specify the type.
|
||||
* @public
|
||||
*/
|
||||
ensureStoreIsUsable(_config = {} as any): void {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import { getOwnProperty, objectMapValues } from '@tldraw/utils'
|
||||
import { Signal } from 'signia'
|
||||
import { BaseRecord } from './BaseRecord'
|
||||
import { RecordType } from './RecordType'
|
||||
import { Store, StoreSnapshot } from './Store'
|
||||
|
@ -48,6 +49,8 @@ export type StoreSchemaOptions<R extends BaseRecord, P> = {
|
|||
}) => R
|
||||
/** @internal */
|
||||
ensureStoreIsUsable?: (store: Store<R, P>) => void
|
||||
/** @internal */
|
||||
derivePresenceState?: (store: Store<R, P>) => Signal<R | null>
|
||||
}
|
||||
|
||||
/** @public */
|
||||
|
@ -241,6 +244,11 @@ export class StoreSchema<R extends BaseRecord, P = unknown> {
|
|||
this.options.ensureStoreIsUsable?.(store)
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
derivePresenceState(store: Store<R, P>): Signal<R | null> | undefined {
|
||||
return this.options.derivePresenceState?.(store)
|
||||
}
|
||||
|
||||
serialize(): SerializedSchema {
|
||||
return {
|
||||
schemaVersion: 1,
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { SerializedSchema } from './StoreSchema'
|
||||
|
||||
/** @public */
|
||||
export const compareSchemas = (a: SerializedSchema, b: SerializedSchema): number => {
|
||||
export const compareSchemas = (a: SerializedSchema, b: SerializedSchema): 0 | 1 | -1 => {
|
||||
if (a.schemaVersion > b.schemaVersion) {
|
||||
return 1
|
||||
}
|
||||
|
|
|
@ -10,7 +10,10 @@ interface Book extends BaseRecord<'book'> {
|
|||
numPages: number
|
||||
}
|
||||
|
||||
const Book = createRecordType<Book>('book', { validator: { validate: (book) => book as Book } })
|
||||
const Book = createRecordType<Book>('book', {
|
||||
validator: { validate: (book) => book as Book },
|
||||
scope: 'document',
|
||||
})
|
||||
|
||||
interface Author extends BaseRecord<'author'> {
|
||||
name: string
|
||||
|
@ -19,6 +22,7 @@ interface Author extends BaseRecord<'author'> {
|
|||
|
||||
const Author = createRecordType<Author>('author', {
|
||||
validator: { validate: (author) => author as Author },
|
||||
scope: 'document',
|
||||
}).withDefaultProperties(() => ({
|
||||
isPseudonym: false,
|
||||
}))
|
||||
|
|
|
@ -21,6 +21,7 @@ const Author = createRecordType<Author>('author', {
|
|||
return author
|
||||
},
|
||||
},
|
||||
scope: 'document',
|
||||
}).withDefaultProperties(() => ({ age: 23 }))
|
||||
|
||||
interface Book extends BaseRecord<'book'> {
|
||||
|
@ -38,6 +39,7 @@ const Book = createRecordType<Book>('book', {
|
|||
return book
|
||||
},
|
||||
},
|
||||
scope: 'document',
|
||||
})
|
||||
|
||||
const bookComparator = (a: Book, b: Book) => a.id.localeCompare(b.id)
|
||||
|
|
|
@ -19,6 +19,7 @@ const Author = createRecordType<Author>('author', {
|
|||
return author
|
||||
},
|
||||
},
|
||||
scope: 'document',
|
||||
}).withDefaultProperties(() => ({ age: 23 }))
|
||||
|
||||
interface Book extends BaseRecord<'book'> {
|
||||
|
@ -36,6 +37,7 @@ const Book = createRecordType<Book>('book', {
|
|||
return book
|
||||
},
|
||||
},
|
||||
scope: 'document',
|
||||
})
|
||||
const authors = {
|
||||
tolkein: Author.create({ name: 'J.R.R. Tolkein' }),
|
||||
|
|
|
@ -29,6 +29,7 @@ const User = createRecordType<User>('user', {
|
|||
return record as User
|
||||
},
|
||||
},
|
||||
scope: 'document',
|
||||
})
|
||||
|
||||
const ShapeVersion = {
|
||||
|
@ -90,6 +91,7 @@ const Shape = createRecordType<Shape<RectangleProps | OvalProps>>('shape', {
|
|||
return record as Shape<RectangleProps | OvalProps>
|
||||
},
|
||||
},
|
||||
scope: 'document',
|
||||
})
|
||||
|
||||
// this interface only exists to be removed
|
||||
|
@ -107,6 +109,7 @@ const Org = createRecordType<Org>('org', {
|
|||
return record as Org
|
||||
},
|
||||
},
|
||||
scope: 'document',
|
||||
})
|
||||
|
||||
export const testSchemaV0 = StoreSchema.create(
|
||||
|
|
|
@ -62,6 +62,7 @@ const User = createRecordType<User>('user', {
|
|||
return record as User
|
||||
},
|
||||
},
|
||||
scope: 'document',
|
||||
}).withDefaultProperties(() => ({
|
||||
/* STEP 6: Add any new default values for properties here */
|
||||
name: 'New User',
|
||||
|
@ -192,6 +193,7 @@ const Shape = createRecordType<Shape<RectangleProps | OvalProps>>('shape', {
|
|||
return record as Shape<RectangleProps | OvalProps>
|
||||
},
|
||||
},
|
||||
scope: 'document',
|
||||
}).withDefaultProperties(() => ({
|
||||
x: 0,
|
||||
y: 0,
|
||||
|
|
|
@ -21,6 +21,7 @@ const Book = createRecordType<Book>('book', {
|
|||
return book
|
||||
},
|
||||
},
|
||||
scope: 'document',
|
||||
})
|
||||
|
||||
interface Author extends BaseRecord<'author'> {
|
||||
|
@ -39,6 +40,7 @@ const Author = createRecordType<Author>('author', {
|
|||
return author
|
||||
},
|
||||
},
|
||||
scope: 'document',
|
||||
}).withDefaultProperties(() => ({
|
||||
isPseudonym: false,
|
||||
}))
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
require('fake-indexeddb/auto')
|
||||
global.ResizeObserver = require('resize-observer-polyfill')
|
||||
global.crypto = new (require('@peculiar/webcrypto').Crypto)()
|
||||
global.crypto ??= new (require('@peculiar/webcrypto').Crypto)()
|
||||
|
|
|
@ -37,6 +37,13 @@ export type ErrorResult<E> = {
|
|||
// @internal (undocumented)
|
||||
export function exhaustiveSwitchError(value: never, property?: string): never;
|
||||
|
||||
// @internal
|
||||
export function filterEntries<Key extends string, Value>(object: {
|
||||
[K in Key]: Value;
|
||||
}, predicate: (key: Key, value: Value) => boolean): {
|
||||
[K in Key]: Value;
|
||||
};
|
||||
|
||||
// @internal (undocumented)
|
||||
export function getErrorAnnotations(error: Error): ErrorAnnotations;
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@ export { getFirstFromIterable } from './lib/iterable'
|
|||
export { lerp, modulate, rng } from './lib/number'
|
||||
export {
|
||||
deepCopy,
|
||||
filterEntries,
|
||||
getOwnProperty,
|
||||
hasOwnProperty,
|
||||
objectMapEntries,
|
||||
|
|
|
@ -87,3 +87,24 @@ export function objectMapEntries<Key extends string, Value>(object: {
|
|||
}): Array<[Key, Value]> {
|
||||
return Object.entries(object) as [Key, Value][]
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters an object using a predicate function.
|
||||
* @returns a new object with only the entries that pass the predicate
|
||||
* @internal
|
||||
*/
|
||||
export function filterEntries<Key extends string, Value>(
|
||||
object: { [K in Key]: Value },
|
||||
predicate: (key: Key, value: Value) => boolean
|
||||
): { [K in Key]: Value } {
|
||||
const result: { [K in Key]?: Value } = {}
|
||||
let didChange = false
|
||||
for (const [key, value] of objectMapEntries(object)) {
|
||||
if (predicate(key, value)) {
|
||||
result[key] = value
|
||||
} else {
|
||||
didChange = true
|
||||
}
|
||||
}
|
||||
return didChange ? (result as { [K in Key]: Value }) : object
|
||||
}
|
||||
|
|
|
@ -4049,90 +4049,90 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@swc/core-darwin-arm64@npm:1.3.52":
|
||||
version: 1.3.52
|
||||
resolution: "@swc/core-darwin-arm64@npm:1.3.52"
|
||||
"@swc/core-darwin-arm64@npm:1.3.55":
|
||||
version: 1.3.55
|
||||
resolution: "@swc/core-darwin-arm64@npm:1.3.55"
|
||||
conditions: os=darwin & cpu=arm64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@swc/core-darwin-x64@npm:1.3.52":
|
||||
version: 1.3.52
|
||||
resolution: "@swc/core-darwin-x64@npm:1.3.52"
|
||||
"@swc/core-darwin-x64@npm:1.3.55":
|
||||
version: 1.3.55
|
||||
resolution: "@swc/core-darwin-x64@npm:1.3.55"
|
||||
conditions: os=darwin & cpu=x64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@swc/core-linux-arm-gnueabihf@npm:1.3.52":
|
||||
version: 1.3.52
|
||||
resolution: "@swc/core-linux-arm-gnueabihf@npm:1.3.52"
|
||||
"@swc/core-linux-arm-gnueabihf@npm:1.3.55":
|
||||
version: 1.3.55
|
||||
resolution: "@swc/core-linux-arm-gnueabihf@npm:1.3.55"
|
||||
conditions: os=linux & cpu=arm
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@swc/core-linux-arm64-gnu@npm:1.3.52":
|
||||
version: 1.3.52
|
||||
resolution: "@swc/core-linux-arm64-gnu@npm:1.3.52"
|
||||
"@swc/core-linux-arm64-gnu@npm:1.3.55":
|
||||
version: 1.3.55
|
||||
resolution: "@swc/core-linux-arm64-gnu@npm:1.3.55"
|
||||
conditions: os=linux & cpu=arm64 & libc=glibc
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@swc/core-linux-arm64-musl@npm:1.3.52":
|
||||
version: 1.3.52
|
||||
resolution: "@swc/core-linux-arm64-musl@npm:1.3.52"
|
||||
"@swc/core-linux-arm64-musl@npm:1.3.55":
|
||||
version: 1.3.55
|
||||
resolution: "@swc/core-linux-arm64-musl@npm:1.3.55"
|
||||
conditions: os=linux & cpu=arm64 & libc=musl
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@swc/core-linux-x64-gnu@npm:1.3.52":
|
||||
version: 1.3.52
|
||||
resolution: "@swc/core-linux-x64-gnu@npm:1.3.52"
|
||||
"@swc/core-linux-x64-gnu@npm:1.3.55":
|
||||
version: 1.3.55
|
||||
resolution: "@swc/core-linux-x64-gnu@npm:1.3.55"
|
||||
conditions: os=linux & cpu=x64 & libc=glibc
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@swc/core-linux-x64-musl@npm:1.3.52":
|
||||
version: 1.3.52
|
||||
resolution: "@swc/core-linux-x64-musl@npm:1.3.52"
|
||||
"@swc/core-linux-x64-musl@npm:1.3.55":
|
||||
version: 1.3.55
|
||||
resolution: "@swc/core-linux-x64-musl@npm:1.3.55"
|
||||
conditions: os=linux & cpu=x64 & libc=musl
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@swc/core-win32-arm64-msvc@npm:1.3.52":
|
||||
version: 1.3.52
|
||||
resolution: "@swc/core-win32-arm64-msvc@npm:1.3.52"
|
||||
"@swc/core-win32-arm64-msvc@npm:1.3.55":
|
||||
version: 1.3.55
|
||||
resolution: "@swc/core-win32-arm64-msvc@npm:1.3.55"
|
||||
conditions: os=win32 & cpu=arm64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@swc/core-win32-ia32-msvc@npm:1.3.52":
|
||||
version: 1.3.52
|
||||
resolution: "@swc/core-win32-ia32-msvc@npm:1.3.52"
|
||||
"@swc/core-win32-ia32-msvc@npm:1.3.55":
|
||||
version: 1.3.55
|
||||
resolution: "@swc/core-win32-ia32-msvc@npm:1.3.55"
|
||||
conditions: os=win32 & cpu=ia32
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@swc/core-win32-x64-msvc@npm:1.3.52":
|
||||
version: 1.3.52
|
||||
resolution: "@swc/core-win32-x64-msvc@npm:1.3.52"
|
||||
"@swc/core-win32-x64-msvc@npm:1.3.55":
|
||||
version: 1.3.55
|
||||
resolution: "@swc/core-win32-x64-msvc@npm:1.3.55"
|
||||
conditions: os=win32 & cpu=x64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@swc/core@npm:^1.2.204, @swc/core@npm:^1.3.41":
|
||||
version: 1.3.52
|
||||
resolution: "@swc/core@npm:1.3.52"
|
||||
"@swc/core@npm:^1.3.55":
|
||||
version: 1.3.55
|
||||
resolution: "@swc/core@npm:1.3.55"
|
||||
dependencies:
|
||||
"@swc/core-darwin-arm64": 1.3.52
|
||||
"@swc/core-darwin-x64": 1.3.52
|
||||
"@swc/core-linux-arm-gnueabihf": 1.3.52
|
||||
"@swc/core-linux-arm64-gnu": 1.3.52
|
||||
"@swc/core-linux-arm64-musl": 1.3.52
|
||||
"@swc/core-linux-x64-gnu": 1.3.52
|
||||
"@swc/core-linux-x64-musl": 1.3.52
|
||||
"@swc/core-win32-arm64-msvc": 1.3.52
|
||||
"@swc/core-win32-ia32-msvc": 1.3.52
|
||||
"@swc/core-win32-x64-msvc": 1.3.52
|
||||
"@swc/core-darwin-arm64": 1.3.55
|
||||
"@swc/core-darwin-x64": 1.3.55
|
||||
"@swc/core-linux-arm-gnueabihf": 1.3.55
|
||||
"@swc/core-linux-arm64-gnu": 1.3.55
|
||||
"@swc/core-linux-arm64-musl": 1.3.55
|
||||
"@swc/core-linux-x64-gnu": 1.3.55
|
||||
"@swc/core-linux-x64-musl": 1.3.55
|
||||
"@swc/core-win32-arm64-msvc": 1.3.55
|
||||
"@swc/core-win32-ia32-msvc": 1.3.55
|
||||
"@swc/core-win32-x64-msvc": 1.3.55
|
||||
peerDependencies:
|
||||
"@swc/helpers": ^0.5.0
|
||||
dependenciesMeta:
|
||||
|
@ -4159,7 +4159,7 @@ __metadata:
|
|||
peerDependenciesMeta:
|
||||
"@swc/helpers":
|
||||
optional: true
|
||||
checksum: ae92657347b223ddbcc47d995966517356bbd600f775fcd74805c95eb8b10e80d0db1def315c710675fa40cae3c89cf26c413bccf1ea884066ba435f65425864
|
||||
checksum: e8ae32e21e78761597b802bd76bb5f0d819441454c4cc5624c077dfa8cf84760eb589e4a1eb6fdc1b1ec65a4b03f7ab42413952b38234f5c13b8b2afb4d453f4
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
|
@ -4172,7 +4172,7 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@swc/jest@npm:^0.2.21, @swc/jest@npm:^0.2.24":
|
||||
"@swc/jest@npm:^0.2.26":
|
||||
version: 0.2.26
|
||||
resolution: "@swc/jest@npm:0.2.26"
|
||||
dependencies:
|
||||
|
@ -4274,8 +4274,6 @@ __metadata:
|
|||
version: 0.0.0-use.local
|
||||
resolution: "@tldraw/assets@workspace:packages/assets"
|
||||
dependencies:
|
||||
"@swc/core": ^1.2.204
|
||||
"@swc/jest": ^0.2.21
|
||||
"@tldraw/utils": "workspace:*"
|
||||
lazyrepo: 0.0.0-alpha.22
|
||||
ts-node-dev: ^1.1.8
|
||||
|
@ -4382,8 +4380,8 @@ __metadata:
|
|||
dependencies:
|
||||
"@microsoft/api-extractor": ^7.34.1
|
||||
"@next/eslint-plugin-next": ^13.3.0
|
||||
"@swc/core": ^1.3.41
|
||||
"@swc/jest": ^0.2.24
|
||||
"@swc/core": ^1.3.55
|
||||
"@swc/jest": ^0.2.26
|
||||
"@types/glob": ^8.1.0
|
||||
"@types/jest": ^28.1.2
|
||||
"@types/node": 18.7.3
|
||||
|
|
|
@ -55,9 +55,8 @@ async function main() {
|
|||
console.log('Checking with tsconfig:', tsconfig)
|
||||
writeFileSync(`${tempDir}/tsconfig.json`, JSON.stringify(tsconfig, null, '\t'), 'utf8')
|
||||
writeFileSync(`${tempDir}/package.json`, JSON.stringify({ dependencies: {} }, null, '\t'), 'utf8')
|
||||
writeFileSync(`${tempDir}/.yarnrc.yml`, 'nodeLinker: node-modules\n', 'utf8')
|
||||
|
||||
await exec('yarn', ['add', ...packagesOurTypesCanDependOn], { pwd: tempDir })
|
||||
await exec('npm', ['install', ...packagesOurTypesCanDependOn], { pwd: tempDir })
|
||||
await exec(resolve('./node_modules/.bin/tsc'), [], { pwd: tempDir })
|
||||
|
||||
await exec('rm', ['-rf', tempDir])
|
||||
|
|
Loading…
Reference in a new issue