From 7f5c1adfc23775aeddcd587fa9decbb465f03307 Mon Sep 17 00:00:00 2001 From: Fangdun Tsai Date: Wed, 6 Nov 2024 14:17:11 +0800 Subject: [PATCH] feat: pdf module --- package.json | 22 +- packages/frontend/component/package.json | 2 +- packages/frontend/core/package.json | 2 +- .../components/attachment-viewer/viewer.tsx | 193 ++++----- .../attachment-viewer/worker/utils.ts | 13 - .../attachment-viewer/worker/worker.ts | 223 ---------- packages/frontend/core/src/modules/index.ts | 2 + .../core/src/modules/pdf/entities/channel.ts | 60 +++ .../core/src/modules/pdf/entities/pdf.ts | 37 ++ .../core/src/modules/pdf/entities/worker.ts | 113 +++++ .../frontend/core/src/modules/pdf/index.ts | 16 + .../core/src/modules/pdf/services/pdf.ts | 16 + .../worker => modules/pdf/workers}/types.ts | 30 +- .../core/src/modules/pdf/workers/utils.ts | 39 ++ .../core/src/modules/pdf/workers/worker.ts | 177 ++++++++ .../i18n/src/i18n-completenesses.json | 6 +- yarn.lock | 394 ++++++++---------- 17 files changed, 766 insertions(+), 579 deletions(-) delete mode 100644 packages/frontend/core/src/components/attachment-viewer/worker/utils.ts delete mode 100644 packages/frontend/core/src/components/attachment-viewer/worker/worker.ts create mode 100644 packages/frontend/core/src/modules/pdf/entities/channel.ts create mode 100644 packages/frontend/core/src/modules/pdf/entities/pdf.ts create mode 100644 packages/frontend/core/src/modules/pdf/entities/worker.ts create mode 100644 packages/frontend/core/src/modules/pdf/index.ts create mode 100644 packages/frontend/core/src/modules/pdf/services/pdf.ts rename packages/frontend/core/src/{components/attachment-viewer/worker => modules/pdf/workers}/types.ts (72%) create mode 100644 packages/frontend/core/src/modules/pdf/workers/utils.ts create mode 100644 packages/frontend/core/src/modules/pdf/workers/worker.ts diff --git a/package.json b/package.json index 98c15d7f93849..1df3d8b5faac4 100644 --- a/package.json +++ b/package.json @@ -156,6 +156,26 @@ "which-typed-array": "npm:@nolyfill/which-typed-array@latest", "@reforged/maker-appimage/@electron-forge/maker-base": "7.5.0", "macos-alias": "npm:@napi-rs/macos-alias@0.0.4", - "fs-xattr": "npm:@napi-rs/xattr@latest" + "fs-xattr": "npm:@napi-rs/xattr@latest", + "@blocksuite/affine": "portal:/Users/fundon/dev/toeverything/blocksuite/packages/affine/all", + "@blocksuite/affine-block-embed": "portal:/Users/fundon/dev/toeverything/blocksuite/packages/affine/block-embed", + "@blocksuite/affine-block-list": "portal:/Users/fundon/dev/toeverything/blocksuite/packages/affine/block-list", + "@blocksuite/affine-block-paragraph": "portal:/Users/fundon/dev/toeverything/blocksuite/packages/affine/block-paragraph", + "@blocksuite/affine-block-surface": "portal:/Users/fundon/dev/toeverything/blocksuite/packages/affine/block-surface", + "@blocksuite/affine-components": "portal:/Users/fundon/dev/toeverything/blocksuite/packages/affine/components", + "@blocksuite/data-view": "portal:/Users/fundon/dev/toeverything/blocksuite/packages/affine/data-view", + "@blocksuite/affine-model": "portal:/Users/fundon/dev/toeverything/blocksuite/packages/affine/model", + "@blocksuite/affine-shared": "portal:/Users/fundon/dev/toeverything/blocksuite/packages/affine/shared", + "@blocksuite/affine-widget-scroll-anchoring": "portal:/Users/fundon/dev/toeverything/blocksuite/packages/affine/widget-scroll-anchoring", + "@blocksuite/blocks": "portal:/Users/fundon/dev/toeverything/blocksuite/packages/blocks", + "@blocksuite/block-std": "portal:/Users/fundon/dev/toeverything/blocksuite/packages/framework/block-std", + "@blocksuite/global": "portal:/Users/fundon/dev/toeverything/blocksuite/packages/framework/global", + "@blocksuite/inline": "portal:/Users/fundon/dev/toeverything/blocksuite/packages/framework/inline", + "@blocksuite/store": "portal:/Users/fundon/dev/toeverything/blocksuite/packages/framework/store", + "@blocksuite/sync": "portal:/Users/fundon/dev/toeverything/blocksuite/packages/framework/sync", + "@blocksuite/presets": "portal:/Users/fundon/dev/toeverything/blocksuite/packages/presets", + "@toeverything/pdf-viewer": "portal:/Users/fundon/dev/toeverything/pdfium-builder/packages/pdf-viewer", + "@toeverything/pdfium": "portal:/Users/fundon/dev/toeverything/pdfium-builder/packages/pdfium", + "@toeverything/pdf-viewer-types": "portal:/Users/fundon/dev/toeverything/pdfium-builder/packages/types" } } diff --git a/packages/frontend/component/package.json b/packages/frontend/component/package.json index deca102ba45c3..8bfd55f24ab62 100644 --- a/packages/frontend/component/package.json +++ b/packages/frontend/component/package.json @@ -41,7 +41,7 @@ "@radix-ui/react-toast": "^1.1.5", "@radix-ui/react-tooltip": "^1.0.7", "@radix-ui/react-visually-hidden": "^1.1.0", - "@toeverything/pdf-viewer": "^0.1.0", + "@toeverything/pdf-viewer": "^0.1.1", "@toeverything/theme": "^1.0.17", "@vanilla-extract/dynamic": "^2.1.0", "check-password-strength": "^2.0.10", diff --git a/packages/frontend/core/package.json b/packages/frontend/core/package.json index 7c2debb8b047f..dbf9e91d0f62b 100644 --- a/packages/frontend/core/package.json +++ b/packages/frontend/core/package.json @@ -36,7 +36,7 @@ "@radix-ui/react-scroll-area": "^1.0.5", "@radix-ui/react-toolbar": "^1.0.4", "@sentry/react": "^8.0.0", - "@toeverything/pdf-viewer": "^0.1.0", + "@toeverything/pdf-viewer": "^0.1.1", "@toeverything/theme": "^1.0.17", "@vanilla-extract/dynamic": "^2.1.0", "animejs": "^3.2.2", diff --git a/packages/frontend/core/src/components/attachment-viewer/viewer.tsx b/packages/frontend/core/src/components/attachment-viewer/viewer.tsx index b0bab7fe10b52..cbe248a1540dc 100644 --- a/packages/frontend/core/src/components/attachment-viewer/viewer.tsx +++ b/packages/frontend/core/src/components/attachment-viewer/viewer.tsx @@ -1,6 +1,13 @@ import { IconButton, observeResize, Scrollable } from '@affine/component'; +import { + type PDFChannel, + PDFService, + type PDFWorker, +} from '@affine/core/modules/pdf'; +import { MessageOp, RenderKind } from '@affine/core/modules/pdf/workers/types'; import type { AttachmentBlockModel } from '@blocksuite/affine/blocks'; import { CollapseIcon, ExpandIcon } from '@blocksuite/icons/rc'; +import { LiveData, useLiveData, useService } from '@toeverything/infra'; import clsx from 'clsx'; import { debounce } from 'lodash-es'; import type { ReactElement } from 'react'; @@ -18,8 +25,6 @@ import { Virtuoso } from 'react-virtuoso'; import * as styles from './styles.css'; import { getAttachmentBlob, renderItem } from './utils'; -import type { DocInfo, MessageData, MessageDataType } from './worker/types'; -import { MessageOp, RenderKind, State } from './worker/types'; type ItemProps = VirtuosoProps; @@ -100,22 +105,31 @@ interface ViewerProps { export const Viewer = ({ model }: ViewerProps): ReactElement => { const { showBoundary } = useErrorBoundary(); - const [state, setState] = useState(State.Connecting); + const service = useService(PDFService); + const [worker, setWorker] = useState(null); + const docInfo = useLiveData( + useMemo( + () => + worker + ? worker.docInfo$ + : new LiveData({ + total: 0, + width: 1, + height: 1, + }), + [worker] + ) + ); + const [channel, setChannel] = useState(null); + const [cursor, setCursor] = useState(0); const [viewportInfo, setViewportInfo] = useState({ dpi: window.devicePixelRatio, width: 1, height: 1, }); - const [docInfo, setDocInfo] = useState({ - total: 0, - width: 1, - height: 1, - }); - const [cursor, setCursor] = useState(0); const viewerRef = useRef(null); const scrollerRef = useRef(null); const scrollerHandleRef = useRef(null); - const workerRef = useRef(null); const [mainVisibleRange, setMainVisibleRange] = useState({ startIndex: 0, @@ -130,22 +144,6 @@ export const Viewer = ({ model }: ViewerProps): ReactElement => { endIndex: 0, }); - const post = useCallback( - ( - type: T, - data?: MessageDataType[T], - transfers?: Transferable[] - ) => { - const message = { type, [type]: data }; - if (transfers?.length) { - workerRef.current?.postMessage(message, transfers); - return; - } - workerRef.current?.postMessage(message); - }, - [workerRef] - ); - const render = useCallback( (id: number, kind: RenderKind, imageData: ImageData) => { const isPage = kind === RenderKind.Page; @@ -209,85 +207,35 @@ export const Viewer = ({ model }: ViewerProps): ReactElement => { }, [viewerRef]); useEffect(() => { - post(MessageOp.Render, { - range: mainVisibleRange, - kind: RenderKind.Page, - scale: 1 * viewportInfo.dpi, - }); - }, [viewportInfo, mainVisibleRange, post]); + if (!channel) return; - useEffect(() => { - if (collapsed) return; + const { startIndex, endIndex } = mainVisibleRange; + const scale = 1 * viewportInfo.dpi; - post(MessageOp.Render, { - range: thumbnailsVisibleRange, - kind: RenderKind.Thumbnail, - scale: (THUMBNAIL_WIDTH / docInfo.width) * viewportInfo.dpi, - }); - }, [collapsed, docInfo, viewportInfo, thumbnailsVisibleRange, post]); - - useLayoutEffect(() => { - workerRef.current = new Worker( - /* webpackChunkName: "pdf.worker" */ new URL( - './worker/worker.ts', - import.meta.url - ) - ); - - async function process({ data }: MessageEvent) { - const { type } = data; - - switch (type) { - case MessageOp.Init: { - setState(State.Connecting); - break; - } - - case MessageOp.Inited: { - setState(State.Connected); - break; - } - - case MessageOp.Opened: { - const info = data[type]; - setDocInfo(o => ({ ...o, ...info })); - setState(State.Opened); - break; - } - - case MessageOp.Rendered: { - const { index, kind, imageData } = data[type]; - render(index, kind, imageData); - break; - } - } + for (let i = startIndex; i <= endIndex; i++) { + channel.post(MessageOp.Render, { + index: i, + scale, + kind: RenderKind.Page, + }); } + }, [viewportInfo, mainVisibleRange, channel]); - workerRef.current.addEventListener('message', event => { - process(event).catch(console.error); - }); + useEffect(() => { + if (collapsed) return; + if (!channel) return; - return () => { - workerRef.current?.terminate(); - }; - }, [model, post, render]); + const { startIndex, endIndex } = thumbnailsVisibleRange; + const scale = (THUMBNAIL_WIDTH / docInfo.width) * viewportInfo.dpi; - useEffect(() => { - if (!model.sourceId) return; - if (state !== State.Connected) return; - - getAttachmentBlob(model) - .then(blob => { - if (!blob) return; - return blob.arrayBuffer(); - }) - .then(buffer => { - if (!buffer) return; - setState(State.Opening); - post(MessageOp.Open, buffer, [buffer]); - }) - .catch(showBoundary); - }, [showBoundary, state, post, model, docInfo]); + for (let i = startIndex; i <= endIndex; i++) { + channel.post(MessageOp.Render, { + index: i, + scale, + kind: RenderKind.Thumbnail, + }); + } + }, [collapsed, docInfo, viewportInfo, thumbnailsVisibleRange, channel]); const pageContent = useCallback( (index: number) => { @@ -348,10 +296,7 @@ export const Viewer = ({ model }: ViewerProps): ReactElement => { const size = Math.min(5, docInfo.total); const itemHeight = docInfo.height + 20; const height = Math.ceil(size * itemHeight); - return { - top: height, - bottom: height, - }; + return { top: height, bottom: height }; }, [docInfo]); const mainStyle = useMemo(() => { @@ -361,11 +306,47 @@ export const Viewer = ({ model }: ViewerProps): ReactElement => { vh - 60 - 24 - 24 - 2 - 8, t * THUMBNAIL_WIDTH * (h / w) + (t - 1) * 12 ); - return { - height: `${height}px`, - }; + return { height: `${height}px` }; }, [docInfo, viewportInfo]); + useLayoutEffect(() => { + const { worker, release } = service.get(model.id); + + setWorker(worker); + + const channel = worker.channel(); + channel + .on(({ index, kind, imageData }) => render(index, kind, imageData)) + .start(); + + setChannel(channel); + + const disposables = worker.on({ + ready: () => { + if (worker.docInfo$.value.total) { + return; + } + + getAttachmentBlob(model) + .then(blob => { + if (!blob) return; + return blob.arrayBuffer(); + }) + .then(buffer => { + if (!buffer) return; + worker.open(buffer); + }) + .catch(showBoundary); + }, + }); + + return () => { + channel.dispose(); + disposables[Symbol.dispose](); + release(); + }; + }, [showBoundary, render, service, model]); + return (
(); -const docInfo = { total: 0, width: 1, height: 1 }; -const flags = PageRenderingflags.REVERSE_BYTE_ORDER | PageRenderingflags.ANNOT; -const ranges = { - [`${RenderKind.Page}:startIndex`]: 0, - [`${RenderKind.Page}:endIndex`]: 0, - [`${RenderKind.Thumbnail}:startIndex`]: 0, - [`${RenderKind.Thumbnail}:endIndex`]: 0, -}; - -function post(type: T, data?: MessageDataType[T]) { - const message = { type, [type]: data }; - self.postMessage(message); -} - -function renderToImageData(index: number, scale: number) { - if (!viewer || !doc) return; - - const page = doc.page(index); - - if (!page) return; - - const width = Math.ceil(docInfo.width * scale); - const height = Math.ceil(docInfo.height * scale); - - const bitmap = viewer.createBitmap(width, height, 0); - bitmap.fill(0, 0, width, height); - page.render(bitmap, 0, 0, width, height, 0, flags); - - const data = new Uint8ClampedArray(bitmap.toBytes()); - - bitmap.close(); - page.close(); - - return new ImageData(data, width, height); -} - -function createJob(index: number, kind: RenderKind, scale: number) { - return () => runJob(index, kind, scale); -} - -async function runJob(index: number, kind: RenderKind, scale: number) { - const key = `${kind}:${index}`; - - let imageData = cached.size > 0 ? cached.get(key) : undefined; - - if (!imageData) { - try { - imageData = renderToImageData(index, scale); - } catch (err) { - console.error(err); - } - - if (!imageData) return; - - cached.set(key, imageData); - } - - post(MessageOp.Rendered, { index, kind, imageData }); -} - -function clearOut(kind: RenderKind, startIndex: number, endIndex: number) { - const oldStartIndex = ranges[`${kind}:startIndex`]; - const oldEndIndex = ranges[`${kind}:endIndex`]; - let i = 0; - let l = 0; - - if (oldEndIndex < startIndex || oldStartIndex > endIndex) { - i = oldStartIndex; - l = oldEndIndex; - } else { - const oldMid = Math.ceil((oldStartIndex + oldEndIndex) / 2); - const mid = Math.ceil((startIndex + endIndex) / 2); - const diff = Math.abs(mid - oldMid); - - if (mid > oldMid) { - i = oldStartIndex; - l = i + diff; - } else if (mid < oldMid) { - i = endIndex; - l = i + diff; - } - } - - for (; i < l + 1; i++) { - cached.delete(`${kind}:${i}`); - } - - ranges[`${kind}:startIndex`] = startIndex; - ranges[`${kind}:endIndex`] = endIndex; -} - -async function start() { - inited = true; - - logger.debug('pdf worker pending'); - self.postMessage({ type: MessageOp.Init }); - - const pdfium = await createPDFium(); - viewer = new Viewer(new Runtime(pdfium)); - - self.postMessage({ type: MessageOp.Inited }); - logger.debug('pdf worker ready'); -} - -async function process({ data }: MessageEvent) { - if (!inited) { - await start(); - } - - if (!viewer) return; - - const { type } = data; - - switch (type) { - case MessageOp.Open: { - const buffer = data[type]; - if (!buffer) return; - - doc = viewer.open(new Uint8Array(buffer)); - - if (!doc) return; - - const page = doc.page(0); - - if (!page) return; - - Object.assign(docInfo, { - total: doc.pageCount(), - height: Math.ceil(page.height()), - width: Math.ceil(page.width()), - }); - page.close(); - post(MessageOp.Opened, docInfo); - - break; - } - - case MessageOp.Render: { - if (!doc) return; - - const { - kind, - scale, - range: { startIndex, endIndex }, - } = data[type]; - - if (startIndex > endIndex || startIndex < 0) return; - - const { total } = docInfo; - const queue: (() => Promise)[] = []; - - if (startIndex === 0) { - for (let n = startIndex; n <= endIndex; n++) { - const b = createJob(n, kind, scale); - queue.push(b); - } - } else if (endIndex + 1 === total) { - for (let n = endIndex; n >= startIndex; n--) { - const a = createJob(n, kind, scale); - queue.push(a); - } - } else { - const mid = Math.floor((startIndex + endIndex) / 2); - const m = createJob(mid, kind, scale); - queue.push(m); - - let n = 1; - const s = Math.max(endIndex - mid, mid - startIndex); - for (; n <= s; n++) { - const j = Math.min(mid + n, endIndex); - const i = Math.max(mid - (j - mid), 0); - const a = createJob(j, kind, scale); - const b = createJob(i, kind, scale); - const ab = () => Promise.all([a(), b()]); - queue.push(ab); - } - } - - queueMicrotask(() => { - (async () => { - for (const q of queue) { - await q(); - } - })() - .catch(console.error) - .finally(() => { - clearOut(kind, startIndex, endIndex); - }); - }); - - break; - } - } -} - -self.addEventListener('message', (event: MessageEvent) => { - process(event).catch(console.error); -}); - -start().catch(error => { - inited = false; - console.log(error); -}); diff --git a/packages/frontend/core/src/modules/index.ts b/packages/frontend/core/src/modules/index.ts index 51c9b9501e519..26b7181de52e0 100644 --- a/packages/frontend/core/src/modules/index.ts +++ b/packages/frontend/core/src/modules/index.ts @@ -19,6 +19,7 @@ import { configureJournalModule } from './journal'; import { configureNavigationModule } from './navigation'; import { configureOpenInApp } from './open-in-app'; import { configureOrganizeModule } from './organize'; +import { configurePDFModule } from './pdf'; import { configurePeekViewModule } from './peek-view'; import { configurePermissionsModule } from './permissions'; import { configureQuickSearchModule } from './quicksearch'; @@ -44,6 +45,7 @@ export function configureCommonModules(framework: Framework) { configureShareDocsModule(framework); configureShareSettingModule(framework); configureTelemetryModule(framework); + configurePDFModule(framework); configurePeekViewModule(framework); configureDocDisplayMetaModule(framework); configureQuickSearchModule(framework); diff --git a/packages/frontend/core/src/modules/pdf/entities/channel.ts b/packages/frontend/core/src/modules/pdf/entities/channel.ts new file mode 100644 index 0000000000000..97e9904abcbf8 --- /dev/null +++ b/packages/frontend/core/src/modules/pdf/entities/channel.ts @@ -0,0 +1,60 @@ +import { DebugLogger } from '@affine/debug'; + +import type { + MessageData, + MessageDataMap, + MessageDataType, +} from '../workers/types'; +import { MessageOp } from '../workers/types'; + +const logger = new DebugLogger('affine:workspace:pdf:channel'); + +export class PDFChannel { + constructor( + public readonly id: string, + public readonly port: MessagePort + ) {} + + on(callback: (data: MessageDataMap[MessageOp.Rendered]) => void) { + this.port.addEventListener( + 'message', + ({ data }: MessageEvent) => { + const { type } = data; + if (type !== MessageOp.Rendered) return; + callback(data[type]); + } + ); + return this; + } + + start() { + this.port.start(); + logger.debug('opened', this.id); + } + + post( + type: T, + data?: MessageDataType[T], + transfers?: Transferable[] + ) { + const message = { type }; + if (data) { + Object.assign(message, { [type]: data }); + } + if (transfers?.length) { + this.port.postMessage(message, transfers); + return; + } + this.port.postMessage(message); + } + + dispose() { + this.post(MessageOp.ChannelClose, this.id); + this.port.close(); + logger.debug('closed', this.id); + } + + [Symbol.dispose]() { + this.dispose(); + } +} diff --git a/packages/frontend/core/src/modules/pdf/entities/pdf.ts b/packages/frontend/core/src/modules/pdf/entities/pdf.ts new file mode 100644 index 0000000000000..259ff420c7346 --- /dev/null +++ b/packages/frontend/core/src/modules/pdf/entities/pdf.ts @@ -0,0 +1,37 @@ +import type { WorkspaceService } from '@toeverything/infra'; +import { Entity, ObjectPool } from '@toeverything/infra'; + +import { PDFWorker } from './worker'; + +export class PDFEntity extends Entity { + workers = new ObjectPool({ + onDelete(worker) { + worker.dispose(); + }, + }); + + constructor(private readonly workspaceService: WorkspaceService) { + super(); + } + + get(id: string) { + let result = this.workers.get(id); + if (!result) { + const worker = new PDFWorker(id, this.name); + result = this.workers.put(id, worker); + } + return { worker: result.obj, release: result.release }; + } + + get name() { + return this.workspaceService.workspace.id; + } + + override dispose(): void { + for (const worker of this.workers.objects.values()) { + worker.obj.dispose(); + } + this.workers.clear(); + super.dispose(); + } +} diff --git a/packages/frontend/core/src/modules/pdf/entities/worker.ts b/packages/frontend/core/src/modules/pdf/entities/worker.ts new file mode 100644 index 0000000000000..fe76e87ce1fd7 --- /dev/null +++ b/packages/frontend/core/src/modules/pdf/entities/worker.ts @@ -0,0 +1,113 @@ +import { DebugLogger } from '@affine/debug'; +import { LiveData } from '@toeverything/infra'; +import { nanoid } from 'nanoid'; + +import type { MessageData, MessageDataType } from '../workers/types'; +import { MessageOp, State } from '../workers/types'; +import { PDFChannel } from './channel'; + +const logger = new DebugLogger('affine:workspace:pdf:worker'); + +export class PDFWorker { + public readonly worker: Worker; + + public docInfo$ = new LiveData({ total: 0, width: 1, height: 1 }); + + constructor( + public readonly id: string, + public readonly name: string + ) { + const worker = new Worker( + /* webpackChunkName: "pdf.worker" */ new URL( + '../workers/worker.ts', + import.meta.url + ) + ); + + worker.addEventListener('message', (e: MessageEvent) => { + this.process(e).catch(console.error); + }); + + this.worker = worker; + logger.debug('created'); + } + + async process({ data }: MessageEvent) { + const { type } = data; + + // @ts-expect-error allow + if (type === State.Loaded) { + this.worker.dispatchEvent(new CustomEvent('ready')); + return; + } + + if (type === MessageOp.Opened) { + this.docInfo$.value = data[type]; + this.worker.dispatchEvent(new CustomEvent('opened')); + return; + } + + if (type === MessageOp.Rendered) { + this.worker.dispatchEvent( + new CustomEvent('rendered', { + detail: data[type], + }) + ); + } + } + + on(listeners: Record void>) { + const disposables: Disposable[] = []; + + for (const [type, listener] of Object.entries(listeners)) { + this.worker.addEventListener(type, listener); + + disposables.push({ + [Symbol.dispose]: () => { + this.worker.removeEventListener(type, listener); + }, + }); + } + return { + [Symbol.dispose]: () => { + disposables.forEach(disposable => disposable[Symbol.dispose]()); + }, + }; + } + + // Creates a channel. + channel(id = nanoid()) { + const { port1, port2 } = new MessageChannel(); + this.post(MessageOp.ChannelOpen, id, [port2]); + return new PDFChannel(id, port1); + } + + open(buffer: ArrayBuffer) { + this.post(MessageOp.Open, buffer, [buffer]); + } + + post( + type: T, + data?: MessageDataType[T], + transfers?: Transferable[] + ) { + const message = { type }; + if (data) { + Object.assign(message, { [type]: data }); + } + if (transfers?.length) { + this.worker.postMessage(message, transfers); + return; + } + this.worker.postMessage(message); + } + + dispose() { + this.worker.terminate(); + logger.debug('closed'); + } + + [Symbol.dispose]() { + this.dispose(); + } +} diff --git a/packages/frontend/core/src/modules/pdf/index.ts b/packages/frontend/core/src/modules/pdf/index.ts new file mode 100644 index 0000000000000..89c97930bd263 --- /dev/null +++ b/packages/frontend/core/src/modules/pdf/index.ts @@ -0,0 +1,16 @@ +import type { Framework } from '@toeverything/infra'; +import { WorkspaceScope, WorkspaceService } from '@toeverything/infra'; + +import { PDFEntity } from './entities/pdf'; +import { PDFService } from './services/pdf'; + +export function configurePDFModule(framework: Framework) { + framework + .scope(WorkspaceScope) + .service(PDFService) + .entity(PDFEntity, [WorkspaceService]); +} + +export { PDFChannel } from './entities/channel'; +export { PDFWorker } from './entities/worker'; +export { PDFService } from './services/pdf'; diff --git a/packages/frontend/core/src/modules/pdf/services/pdf.ts b/packages/frontend/core/src/modules/pdf/services/pdf.ts new file mode 100644 index 0000000000000..115403a863627 --- /dev/null +++ b/packages/frontend/core/src/modules/pdf/services/pdf.ts @@ -0,0 +1,16 @@ +import { Service } from '@toeverything/infra'; + +import { PDFEntity } from '../entities/pdf'; + +export class PDFService extends Service { + pdf = this.framework.createEntity(PDFEntity); + + get(id: string) { + return this.pdf.get(id); + } + + override dispose(): void { + this.pdf.dispose(); + super.dispose(); + } +} diff --git a/packages/frontend/core/src/components/attachment-viewer/worker/types.ts b/packages/frontend/core/src/modules/pdf/workers/types.ts similarity index 72% rename from packages/frontend/core/src/components/attachment-viewer/worker/types.ts rename to packages/frontend/core/src/modules/pdf/workers/types.ts index 5a259dca391aa..8aa1e666c83b7 100644 --- a/packages/frontend/core/src/components/attachment-viewer/worker/types.ts +++ b/packages/frontend/core/src/modules/pdf/workers/types.ts @@ -1,8 +1,7 @@ export enum State { - Connecting = 0, - Connected, - Opening, - Opened, + IDLE = 0, + Loading, + Loaded, Failed, } @@ -19,18 +18,13 @@ export type ViewportInfo = { height: number; }; -export enum MessageState { - Poll, - Ready, -} - export enum MessageOp { - Init, - Inited, - Open, + Open = State.Failed + 1, Opened, Render, Rendered, + ChannelOpen, + ChannelClose, } export enum RenderKind { @@ -44,20 +38,24 @@ export type Range = { }; export interface MessageDataMap { - [MessageOp.Init]: undefined; - [MessageOp.Inited]: undefined; + [State.IDLE]: undefined; + [State.Loading]: undefined; + [State.Loaded]: undefined; + [State.Failed]: undefined; [MessageOp.Open]: ArrayBuffer; [MessageOp.Opened]: DocInfo; [MessageOp.Render]: { - range: Range; + index: number; kind: RenderKind; - scale: number; + scale?: number; }; [MessageOp.Rendered]: { index: number; kind: RenderKind; imageData: ImageData; }; + [MessageOp.ChannelOpen]: string; + [MessageOp.ChannelClose]: string; } export type MessageDataType = { diff --git a/packages/frontend/core/src/modules/pdf/workers/utils.ts b/packages/frontend/core/src/modules/pdf/workers/utils.ts new file mode 100644 index 0000000000000..0dc69eef46c13 --- /dev/null +++ b/packages/frontend/core/src/modules/pdf/workers/utils.ts @@ -0,0 +1,39 @@ +import type { Document, Viewer } from '@toeverything/pdf-viewer'; + +export function resizeImageBitmap( + imageData: ImageData, + options: { + resizeWidth: number; + resizeHeight: number; + } +) { + return createImageBitmap(imageData, 0, 0, imageData.width, imageData.height, { + colorSpaceConversion: 'none', + resizeQuality: 'pixelated', + ...options, + }); +} + +export function renderToImageData( + viewer: Viewer, + doc: Document, + flags: number, + index: number, + width: number, + height: number +) { + const page = doc.page(index); + + if (!page) return; + + const bitmap = viewer.createBitmap(width, height, 0); + bitmap.fill(0, 0, width, height); + page.render(bitmap, 0, 0, width, height, 0, flags); + + const data = new Uint8ClampedArray(bitmap.toUint8Array()); + + bitmap.close(); + page.close(); + + return new ImageData(data, width, height); +} diff --git a/packages/frontend/core/src/modules/pdf/workers/worker.ts b/packages/frontend/core/src/modules/pdf/workers/worker.ts new file mode 100644 index 0000000000000..53600cc521d0a --- /dev/null +++ b/packages/frontend/core/src/modules/pdf/workers/worker.ts @@ -0,0 +1,177 @@ +import type { Document } from '@toeverything/pdf-viewer'; +import { + createPDFium, + PageRenderingflags, + Runtime, + Viewer, +} from '@toeverything/pdf-viewer'; + +import type { MessageData, MessageDataType } from './types'; +import { MessageOp, State } from './types'; +import { renderToImageData } from './utils'; + +let state = State.IDLE; +let viewer: Viewer | null = null; +let doc: Document | undefined = undefined; +const docInfo = { total: 0, width: 1, height: 1 }; +const flags = PageRenderingflags.REVERSE_BYTE_ORDER | PageRenderingflags.ANNOT; +const channels = new Set(); + +// Waits for wasm to load and initialize. +async function start() { + if (state !== State.IDLE) return; + + waitForReady({ id: 0 }); + + state = State.Loading; + + const pdfium = await createPDFium(); + viewer = new Viewer(new Runtime(pdfium)); + + state = State.Loaded; +} + +function post( + sender: typeof globalThis | MessagePort, + type: T, + data?: MessageDataType[T], + transfers?: Transferable[] +) { + const message = { type }; + if (data) { + Object.assign(message, { [type]: data }); + } + if (transfers?.length) { + if (sender instanceof MessagePort) { + sender.postMessage(message, transfers); + return; + } + sender.postMessage(message, '*', transfers); + return; + } + sender.postMessage(message); +} + +function waitForReady(tick: { id: number }) { + post(self, state); + if (state === State.Loaded || state === State.Failed) { + if (tick.id) { + clearTimeout(tick.id); + tick.id = 0; + } + return; + } + // @ts-expect-error allow + tick.id = setTimeout(waitForReady, 55, tick); +} + +function rendering( + sender: typeof globalThis | MessagePort, + viewer: Viewer, + doc: Document, + data: MessageDataType[MessageOp.Render] +) { + const { index, kind, scale = 1 } = data; + + if (index < 0 || index >= docInfo.total) return; + + const width = Math.ceil(docInfo.width * scale); + const height = Math.ceil(docInfo.height * scale); + const imageData = renderToImageData(viewer, doc, flags, index, width, height); + if (!imageData) return; + + post(sender, MessageOp.Rendered, { index, kind, imageData }); +} + +function process({ data, ports: [port] }: MessageEvent) { + const { type } = data; + + switch (type) { + case MessageOp.Open: { + if (!viewer) return; + + const buffer = data[type]; + if (!buffer) return; + + // release loaded document + if (doc) { + doc.close(); + } + + doc = viewer.open(new Uint8Array(buffer)); + + if (!doc) return; + + const page = doc.page(0); + + if (!page) return; + + Object.assign(docInfo, { + total: doc.pageCount(), + height: Math.ceil(page.height()), + width: Math.ceil(page.width()), + }); + page.close(); + + post(self, MessageOp.Opened, docInfo); + + break; + } + + case MessageOp.Render: { + if (!viewer || !doc) return; + + rendering(self, viewer, doc, data[type]); + + break; + } + + // process only images + case MessageOp.ChannelOpen: { + const id = data[type]; + if (id && port) { + port.addEventListener( + 'message', + ({ data }: MessageEvent) => { + const { type } = data; + + if (type === MessageOp.ChannelClose) { + port.close(); + channels.delete(port); + return; + } + + if (!viewer || !doc) return; + + if (type !== MessageOp.Render) return; + + rendering(port, viewer, doc, data[type]); + } + ); + port.start(); + } + + break; + } + } +} + +self.addEventListener('message', process); + +start().catch(err => { + if (channels.size > 0) { + for (const channel of channels) { + channel.close(); + } + channels.clear(); + } + if (doc) { + doc.close(); + doc = undefined; + } + if (viewer) { + viewer.close(); + viewer = null; + } + console.error(err); +}); diff --git a/packages/frontend/i18n/src/i18n-completenesses.json b/packages/frontend/i18n/src/i18n-completenesses.json index 45df90c856fd8..05b1e8c02a975 100644 --- a/packages/frontend/i18n/src/i18n-completenesses.json +++ b/packages/frontend/i18n/src/i18n-completenesses.json @@ -11,12 +11,12 @@ "hi": 2, "it": 1, "ja": 94, - "ko": 84, + "ko": 83, "pl": 0, "pt-BR": 91, - "ru": 78, + "ru": 77, "sv-SE": 5, "ur": 3, "zh-Hans": 95, - "zh-Hant": 93 + "zh-Hant": 92 } \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index a87db47402c68..e4ce6b0442a0d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -352,7 +352,7 @@ __metadata: "@storybook/react": "npm:^8.2.9" "@storybook/react-vite": "npm:^8.2.9" "@testing-library/react": "npm:^16.0.0" - "@toeverything/pdf-viewer": "npm:^0.1.0" + "@toeverything/pdf-viewer": "npm:^0.1.1" "@toeverything/theme": "npm:^1.0.17" "@types/react": "npm:^18.2.75" "@types/react-dom": "npm:^18.2.24" @@ -431,7 +431,7 @@ __metadata: "@radix-ui/react-toolbar": "npm:^1.0.4" "@sentry/react": "npm:^8.0.0" "@testing-library/react": "npm:^16.0.0" - "@toeverything/pdf-viewer": "npm:^0.1.0" + "@toeverything/pdf-viewer": "npm:^0.1.1" "@toeverything/theme": "npm:^1.0.17" "@types/animejs": "npm:^3.1.12" "@types/bytes": "npm:^3.1.4" @@ -2529,19 +2529,19 @@ __metadata: languageName: node linkType: hard -"@blocksuite/affine-block-embed@npm:0.17.26": - version: 0.17.26 - resolution: "@blocksuite/affine-block-embed@npm:0.17.26" - dependencies: - "@blocksuite/affine-block-surface": "npm:0.17.26" - "@blocksuite/affine-components": "npm:0.17.26" - "@blocksuite/affine-model": "npm:0.17.26" - "@blocksuite/affine-shared": "npm:0.17.26" - "@blocksuite/block-std": "npm:0.17.26" - "@blocksuite/global": "npm:0.17.26" +"@blocksuite/affine-block-embed@portal:/Users/fundon/dev/toeverything/blocksuite/packages/affine/block-embed::locator=%40affine%2Fmonorepo%40workspace%3A.": + version: 0.0.0-use.local + resolution: "@blocksuite/affine-block-embed@portal:/Users/fundon/dev/toeverything/blocksuite/packages/affine/block-embed::locator=%40affine%2Fmonorepo%40workspace%3A." + dependencies: + "@blocksuite/affine-block-surface": "workspace:*" + "@blocksuite/affine-components": "workspace:*" + "@blocksuite/affine-model": "workspace:*" + "@blocksuite/affine-shared": "workspace:*" + "@blocksuite/block-std": "workspace:*" + "@blocksuite/global": "workspace:*" "@blocksuite/icons": "npm:^2.1.68" - "@blocksuite/inline": "npm:0.17.26" - "@blocksuite/store": "npm:0.17.26" + "@blocksuite/inline": "workspace:*" + "@blocksuite/store": "workspace:*" "@floating-ui/dom": "npm:^1.6.10" "@lit/context": "npm:^1.1.2" "@preact/signals-core": "npm:^1.8.0" @@ -2549,21 +2549,20 @@ __metadata: lit: "npm:^3.2.0" minimatch: "npm:^10.0.1" zod: "npm:^3.23.8" - checksum: 10/ca3771923a582d1e79ae719112f8b18a479dcc93bdf1eb995d8fe952296a7b89f10bf529e3badaf852923bd689e260e218112f71c6760754efacd3b3cb33817f languageName: node - linkType: hard + linkType: soft -"@blocksuite/affine-block-list@npm:0.17.26": - version: 0.17.26 - resolution: "@blocksuite/affine-block-list@npm:0.17.26" - dependencies: - "@blocksuite/affine-components": "npm:0.17.26" - "@blocksuite/affine-model": "npm:0.17.26" - "@blocksuite/affine-shared": "npm:0.17.26" - "@blocksuite/block-std": "npm:0.17.26" - "@blocksuite/global": "npm:0.17.26" - "@blocksuite/inline": "npm:0.17.26" - "@blocksuite/store": "npm:0.17.26" +"@blocksuite/affine-block-list@portal:/Users/fundon/dev/toeverything/blocksuite/packages/affine/block-list::locator=%40affine%2Fmonorepo%40workspace%3A.": + version: 0.0.0-use.local + resolution: "@blocksuite/affine-block-list@portal:/Users/fundon/dev/toeverything/blocksuite/packages/affine/block-list::locator=%40affine%2Fmonorepo%40workspace%3A." + dependencies: + "@blocksuite/affine-components": "workspace:*" + "@blocksuite/affine-model": "workspace:*" + "@blocksuite/affine-shared": "workspace:*" + "@blocksuite/block-std": "workspace:*" + "@blocksuite/global": "workspace:*" + "@blocksuite/inline": "workspace:*" + "@blocksuite/store": "workspace:*" "@floating-ui/dom": "npm:^1.6.10" "@lit/context": "npm:^1.1.2" "@preact/signals-core": "npm:^1.8.0" @@ -2571,21 +2570,20 @@ __metadata: lit: "npm:^3.2.0" minimatch: "npm:^10.0.1" zod: "npm:^3.23.8" - checksum: 10/eb3c73c23f6c828a453095bb29b6a1f6228a248833c9e1caf6c33eca653b727f52941cb0f504b4c01c4cf917e516b892fe605e59a20f5f319180237568f7bcc8 languageName: node - linkType: hard + linkType: soft -"@blocksuite/affine-block-paragraph@npm:0.17.26": - version: 0.17.26 - resolution: "@blocksuite/affine-block-paragraph@npm:0.17.26" - dependencies: - "@blocksuite/affine-components": "npm:0.17.26" - "@blocksuite/affine-model": "npm:0.17.26" - "@blocksuite/affine-shared": "npm:0.17.26" - "@blocksuite/block-std": "npm:0.17.26" - "@blocksuite/global": "npm:0.17.26" - "@blocksuite/inline": "npm:0.17.26" - "@blocksuite/store": "npm:0.17.26" +"@blocksuite/affine-block-paragraph@portal:/Users/fundon/dev/toeverything/blocksuite/packages/affine/block-paragraph::locator=%40affine%2Fmonorepo%40workspace%3A.": + version: 0.0.0-use.local + resolution: "@blocksuite/affine-block-paragraph@portal:/Users/fundon/dev/toeverything/blocksuite/packages/affine/block-paragraph::locator=%40affine%2Fmonorepo%40workspace%3A." + dependencies: + "@blocksuite/affine-components": "workspace:*" + "@blocksuite/affine-model": "workspace:*" + "@blocksuite/affine-shared": "workspace:*" + "@blocksuite/block-std": "workspace:*" + "@blocksuite/global": "workspace:*" + "@blocksuite/inline": "workspace:*" + "@blocksuite/store": "workspace:*" "@floating-ui/dom": "npm:^1.6.10" "@lit/context": "npm:^1.1.2" "@preact/signals-core": "npm:^1.8.0" @@ -2593,21 +2591,20 @@ __metadata: lit: "npm:^3.2.0" minimatch: "npm:^10.0.1" zod: "npm:^3.23.8" - checksum: 10/a880a4294b844c6c68970b6b04094f87990ced0874e338c3f44db3ae6619b54647f2ce67d2fd61c1b47add6b7043f6736fb1db16056d3f9bcbb84ea3ab7f8f0a languageName: node - linkType: hard + linkType: soft -"@blocksuite/affine-block-surface@npm:0.17.26": - version: 0.17.26 - resolution: "@blocksuite/affine-block-surface@npm:0.17.26" - dependencies: - "@blocksuite/affine-components": "npm:0.17.26" - "@blocksuite/affine-model": "npm:0.17.26" - "@blocksuite/affine-shared": "npm:0.17.26" - "@blocksuite/block-std": "npm:0.17.26" - "@blocksuite/global": "npm:0.17.26" - "@blocksuite/inline": "npm:0.17.26" - "@blocksuite/store": "npm:0.17.26" +"@blocksuite/affine-block-surface@portal:/Users/fundon/dev/toeverything/blocksuite/packages/affine/block-surface::locator=%40affine%2Fmonorepo%40workspace%3A.": + version: 0.0.0-use.local + resolution: "@blocksuite/affine-block-surface@portal:/Users/fundon/dev/toeverything/blocksuite/packages/affine/block-surface::locator=%40affine%2Fmonorepo%40workspace%3A." + dependencies: + "@blocksuite/affine-components": "workspace:*" + "@blocksuite/affine-model": "workspace:*" + "@blocksuite/affine-shared": "workspace:*" + "@blocksuite/block-std": "workspace:*" + "@blocksuite/global": "workspace:*" + "@blocksuite/inline": "workspace:*" + "@blocksuite/store": "workspace:*" "@lit/context": "npm:^1.1.2" "@preact/signals-core": "npm:^1.8.0" "@toeverything/theme": "npm:^1.0.15" @@ -2616,21 +2613,20 @@ __metadata: lodash.chunk: "npm:^4.2.0" nanoid: "npm:^5.0.7" zod: "npm:^3.23.8" - checksum: 10/02ec5958682d6c066679a74f3299142a16f7eed2833182e11eae8ab0cd6099feabedf5dd847ea63f4942183ce3cb8c8767f3e8a87b432022be8efe9de363fb23 languageName: node - linkType: hard + linkType: soft -"@blocksuite/affine-components@npm:0.17.26": - version: 0.17.26 - resolution: "@blocksuite/affine-components@npm:0.17.26" +"@blocksuite/affine-components@portal:/Users/fundon/dev/toeverything/blocksuite/packages/affine/components::locator=%40affine%2Fmonorepo%40workspace%3A.": + version: 0.0.0-use.local + resolution: "@blocksuite/affine-components@portal:/Users/fundon/dev/toeverything/blocksuite/packages/affine/components::locator=%40affine%2Fmonorepo%40workspace%3A." dependencies: - "@blocksuite/affine-model": "npm:0.17.26" - "@blocksuite/affine-shared": "npm:0.17.26" - "@blocksuite/block-std": "npm:0.17.26" - "@blocksuite/global": "npm:0.17.26" + "@blocksuite/affine-model": "workspace:*" + "@blocksuite/affine-shared": "workspace:*" + "@blocksuite/block-std": "workspace:*" + "@blocksuite/global": "workspace:*" "@blocksuite/icons": "npm:^2.1.68" - "@blocksuite/inline": "npm:0.17.26" - "@blocksuite/store": "npm:0.17.26" + "@blocksuite/inline": "workspace:*" + "@blocksuite/store": "workspace:*" "@floating-ui/dom": "npm:^1.6.10" "@lit/context": "npm:^1.1.2" "@lottiefiles/dotlottie-wc": "npm:^0.2.16" @@ -2640,35 +2636,34 @@ __metadata: katex: "npm:^0.16.11" lit: "npm:^3.2.0" lit-html: "npm:^3.2.1" + lodash.clonedeep: "npm:^4.5.0" shiki: "npm:^1.12.0" zod: "npm:^3.23.8" - checksum: 10/b503a884a3bea35dc525570df5e684ff68cdf8b0617d2c2d715b58fd45b6b2962f9f8938ebb3436451cc00f701f62024d8b738642669e32049fc78deae244aeb languageName: node - linkType: hard + linkType: soft -"@blocksuite/affine-model@npm:0.17.26": - version: 0.17.26 - resolution: "@blocksuite/affine-model@npm:0.17.26" +"@blocksuite/affine-model@portal:/Users/fundon/dev/toeverything/blocksuite/packages/affine/model::locator=%40affine%2Fmonorepo%40workspace%3A.": + version: 0.0.0-use.local + resolution: "@blocksuite/affine-model@portal:/Users/fundon/dev/toeverything/blocksuite/packages/affine/model::locator=%40affine%2Fmonorepo%40workspace%3A." dependencies: - "@blocksuite/block-std": "npm:0.17.26" - "@blocksuite/global": "npm:0.17.26" - "@blocksuite/inline": "npm:0.17.26" - "@blocksuite/store": "npm:0.17.26" + "@blocksuite/block-std": "workspace:*" + "@blocksuite/global": "workspace:*" + "@blocksuite/inline": "workspace:*" + "@blocksuite/store": "workspace:*" fractional-indexing: "npm:^3.2.0" zod: "npm:^3.23.8" - checksum: 10/5ae6c363f38c9ed7ee7a7c4790e115e71fbd294b9693fbdbb28c042929865332c240f61d745f6e69abf0240834a6884b590f0f2955ffbff73042a9d848f87a98 languageName: node - linkType: hard + linkType: soft -"@blocksuite/affine-shared@npm:0.17.26": - version: 0.17.26 - resolution: "@blocksuite/affine-shared@npm:0.17.26" +"@blocksuite/affine-shared@portal:/Users/fundon/dev/toeverything/blocksuite/packages/affine/shared::locator=%40affine%2Fmonorepo%40workspace%3A.": + version: 0.0.0-use.local + resolution: "@blocksuite/affine-shared@portal:/Users/fundon/dev/toeverything/blocksuite/packages/affine/shared::locator=%40affine%2Fmonorepo%40workspace%3A." dependencies: - "@blocksuite/affine-model": "npm:0.17.26" - "@blocksuite/block-std": "npm:0.17.26" - "@blocksuite/global": "npm:0.17.26" - "@blocksuite/inline": "npm:0.17.26" - "@blocksuite/store": "npm:0.17.26" + "@blocksuite/affine-model": "workspace:*" + "@blocksuite/block-std": "workspace:*" + "@blocksuite/global": "workspace:*" + "@blocksuite/inline": "workspace:*" + "@blocksuite/store": "workspace:*" "@floating-ui/dom": "npm:^1.6.10" "@lit/context": "npm:^1.1.2" "@preact/signals-core": "npm:^1.8.0" @@ -2678,46 +2673,43 @@ __metadata: lodash.mergewith: "npm:^4.6.2" minimatch: "npm:^10.0.1" zod: "npm:^3.23.8" - checksum: 10/157384c30320e820a00cac95b802f893cd745a3037485f69d750539fd03f8e67dabddd634a5b41b7b1395f79ee16ce8fdf1f072f9e6c82032bdbddcb2317a376 languageName: node - linkType: hard + linkType: soft -"@blocksuite/affine-widget-scroll-anchoring@npm:0.17.26": - version: 0.17.26 - resolution: "@blocksuite/affine-widget-scroll-anchoring@npm:0.17.26" +"@blocksuite/affine-widget-scroll-anchoring@portal:/Users/fundon/dev/toeverything/blocksuite/packages/affine/widget-scroll-anchoring::locator=%40affine%2Fmonorepo%40workspace%3A.": + version: 0.0.0-use.local + resolution: "@blocksuite/affine-widget-scroll-anchoring@portal:/Users/fundon/dev/toeverything/blocksuite/packages/affine/widget-scroll-anchoring::locator=%40affine%2Fmonorepo%40workspace%3A." dependencies: - "@blocksuite/affine-model": "npm:0.17.26" - "@blocksuite/affine-shared": "npm:0.17.26" - "@blocksuite/block-std": "npm:0.17.26" - "@blocksuite/global": "npm:0.17.26" + "@blocksuite/affine-model": "workspace:*" + "@blocksuite/affine-shared": "workspace:*" + "@blocksuite/block-std": "workspace:*" + "@blocksuite/global": "workspace:*" "@preact/signals-core": "npm:^1.8.0" "@toeverything/theme": "npm:^1.0.15" lit: "npm:^3.2.0" - checksum: 10/3d1aa19068008e0b67a9231bf56f7f88783a9cb59f0f0b5b75e6e5ebd1a16027d00f3fe965e86a8093e907f734047e4d008db86d038b00d4869e39e2abb87d5c languageName: node - linkType: hard + linkType: soft -"@blocksuite/affine@npm:0.17.26": - version: 0.17.26 - resolution: "@blocksuite/affine@npm:0.17.26" +"@blocksuite/affine@portal:/Users/fundon/dev/toeverything/blocksuite/packages/affine/all::locator=%40affine%2Fmonorepo%40workspace%3A.": + version: 0.0.0-use.local + resolution: "@blocksuite/affine@portal:/Users/fundon/dev/toeverything/blocksuite/packages/affine/all::locator=%40affine%2Fmonorepo%40workspace%3A." dependencies: - "@blocksuite/block-std": "npm:0.17.26" - "@blocksuite/blocks": "npm:0.17.26" - "@blocksuite/global": "npm:0.17.26" - "@blocksuite/inline": "npm:0.17.26" - "@blocksuite/presets": "npm:0.17.26" - "@blocksuite/store": "npm:0.17.26" - checksum: 10/4094463d0c0538de4aa903042961cf839ed5384f4c262166163120d0cd96ac03e38fb9aea34306a4d1c066a0c7f5497a238a725d474f766333a8530ef5cbf5c6 + "@blocksuite/block-std": "workspace:*" + "@blocksuite/blocks": "workspace:*" + "@blocksuite/global": "workspace:*" + "@blocksuite/inline": "workspace:*" + "@blocksuite/presets": "workspace:*" + "@blocksuite/store": "workspace:*" languageName: node - linkType: hard + linkType: soft -"@blocksuite/block-std@npm:0.17.26": - version: 0.17.26 - resolution: "@blocksuite/block-std@npm:0.17.26" +"@blocksuite/block-std@portal:/Users/fundon/dev/toeverything/blocksuite/packages/framework/block-std::locator=%40affine%2Fmonorepo%40workspace%3A.": + version: 0.0.0-use.local + resolution: "@blocksuite/block-std@portal:/Users/fundon/dev/toeverything/blocksuite/packages/framework/block-std::locator=%40affine%2Fmonorepo%40workspace%3A." dependencies: - "@blocksuite/global": "npm:0.17.26" - "@blocksuite/inline": "npm:0.17.26" - "@blocksuite/store": "npm:0.17.26" + "@blocksuite/global": "workspace:*" + "@blocksuite/inline": "workspace:*" + "@blocksuite/store": "workspace:*" "@lit/context": "npm:^1.1.2" "@preact/signals-core": "npm:^1.8.0" "@types/hast": "npm:^3.0.4" @@ -2729,35 +2721,33 @@ __metadata: unified: "npm:^11.0.5" w3c-keyname: "npm:^2.2.8" zod: "npm:^3.23.8" - checksum: 10/7028178c7f9b59b22a6507472dd17cd2af6805e4b4871a1eb77164bf7fbb9560f122d4cdd0a13bf1d1ba4b5d970efe7c9de9a9e261112f4283e1528161d26a61 languageName: node - linkType: hard + linkType: soft -"@blocksuite/blocks@npm:0.17.26": - version: 0.17.26 - resolution: "@blocksuite/blocks@npm:0.17.26" - dependencies: - "@blocksuite/affine-block-embed": "npm:0.17.26" - "@blocksuite/affine-block-list": "npm:0.17.26" - "@blocksuite/affine-block-paragraph": "npm:0.17.26" - "@blocksuite/affine-block-surface": "npm:0.17.26" - "@blocksuite/affine-components": "npm:0.17.26" - "@blocksuite/affine-model": "npm:0.17.26" - "@blocksuite/affine-shared": "npm:0.17.26" - "@blocksuite/affine-widget-scroll-anchoring": "npm:0.17.26" - "@blocksuite/block-std": "npm:0.17.26" - "@blocksuite/data-view": "npm:0.17.26" - "@blocksuite/global": "npm:0.17.26" +"@blocksuite/blocks@portal:/Users/fundon/dev/toeverything/blocksuite/packages/blocks::locator=%40affine%2Fmonorepo%40workspace%3A.": + version: 0.0.0-use.local + resolution: "@blocksuite/blocks@portal:/Users/fundon/dev/toeverything/blocksuite/packages/blocks::locator=%40affine%2Fmonorepo%40workspace%3A." + dependencies: + "@blocksuite/affine-block-embed": "workspace:*" + "@blocksuite/affine-block-list": "workspace:*" + "@blocksuite/affine-block-paragraph": "workspace:*" + "@blocksuite/affine-block-surface": "workspace:*" + "@blocksuite/affine-components": "workspace:*" + "@blocksuite/affine-model": "workspace:*" + "@blocksuite/affine-shared": "workspace:*" + "@blocksuite/affine-widget-scroll-anchoring": "workspace:*" + "@blocksuite/block-std": "workspace:*" + "@blocksuite/data-view": "workspace:*" + "@blocksuite/global": "workspace:*" "@blocksuite/icons": "npm:^2.1.68" - "@blocksuite/inline": "npm:0.17.26" - "@blocksuite/store": "npm:0.17.26" + "@blocksuite/inline": "workspace:*" + "@blocksuite/store": "workspace:*" "@floating-ui/dom": "npm:^1.6.10" "@lit/context": "npm:^1.1.2" "@preact/signals-core": "npm:^1.8.0" "@toeverything/theme": "npm:^1.0.15" "@types/hast": "npm:^3.0.4" "@types/mdast": "npm:^4.0.4" - "@types/sortablejs": "npm:^1.15.8" collapse-white-space: "npm:^2.1.0" date-fns: "npm:^4.0.0" dompurify: "npm:^3.1.6" @@ -2786,46 +2776,41 @@ __metadata: remark-stringify: "npm:^11.0.0" shiki: "npm:^1.14.1" simple-xml-to-json: "npm:^1.2.2" - sortablejs: "npm:^1.15.2" unified: "npm:^11.0.5" zod: "npm:^3.23.8" - checksum: 10/f9184097ad1ff6c6e419b028be1bd4906c961d0be3d0dc4524ac89bd19801d358987b78be1057a174ac25033b7b23b98bfbbb7cb092c7180eee56ed502a8d5a6 languageName: node - linkType: hard + linkType: soft -"@blocksuite/data-view@npm:0.17.26": - version: 0.17.26 - resolution: "@blocksuite/data-view@npm:0.17.26" +"@blocksuite/data-view@portal:/Users/fundon/dev/toeverything/blocksuite/packages/affine/data-view::locator=%40affine%2Fmonorepo%40workspace%3A.": + version: 0.0.0-use.local + resolution: "@blocksuite/data-view@portal:/Users/fundon/dev/toeverything/blocksuite/packages/affine/data-view::locator=%40affine%2Fmonorepo%40workspace%3A." dependencies: - "@blocksuite/affine-components": "npm:0.17.26" - "@blocksuite/affine-shared": "npm:0.17.26" - "@blocksuite/block-std": "npm:0.17.26" - "@blocksuite/global": "npm:0.17.26" + "@blocksuite/affine-components": "workspace:*" + "@blocksuite/affine-shared": "workspace:*" + "@blocksuite/block-std": "workspace:*" + "@blocksuite/global": "workspace:*" "@blocksuite/icons": "npm:^2.1.68" - "@blocksuite/store": "npm:0.17.26" + "@blocksuite/store": "workspace:*" "@floating-ui/dom": "npm:^1.6.10" "@lit/context": "npm:^1.1.2" "@preact/signals-core": "npm:^1.8.0" "@toeverything/theme": "npm:^1.0.15" date-fns: "npm:^4.0.0" lit: "npm:^3.2.0" - sortablejs: "npm:^1.15.2" zod: "npm:^3.23.8" - checksum: 10/98221b2d77458ce9ece60d3ea4bd5c9a3aa32b35905f02554e5e1744d5c30cc45c7b9614d0b984c8b9b3e74b0926aa4dc3da977176cbd84a88a8e3aa32d06920 languageName: node - linkType: hard + linkType: soft -"@blocksuite/global@npm:0.17.26": - version: 0.17.26 - resolution: "@blocksuite/global@npm:0.17.26" +"@blocksuite/global@portal:/Users/fundon/dev/toeverything/blocksuite/packages/framework/global::locator=%40affine%2Fmonorepo%40workspace%3A.": + version: 0.0.0-use.local + resolution: "@blocksuite/global@portal:/Users/fundon/dev/toeverything/blocksuite/packages/framework/global::locator=%40affine%2Fmonorepo%40workspace%3A." dependencies: "@preact/signals-core": "npm:^1.8.0" lib0: "npm:^0.2.97" lit: "npm:^3.2.0" zod: "npm:^3.23.8" - checksum: 10/c48dfa27b0caa0efdbe6eff15ed6c849c84ebc0b78c5375df68af475ac02f577203083f0d1cbfabe00c6dbf2a27f5a8046c6a9d455a2658b0d619604f6778bbe languageName: node - linkType: hard + linkType: soft "@blocksuite/icons@npm:2.1.69, @blocksuite/icons@npm:^2.1.67, @blocksuite/icons@npm:^2.1.68": version: 2.1.69 @@ -2843,49 +2828,47 @@ __metadata: languageName: node linkType: hard -"@blocksuite/inline@npm:0.17.26": - version: 0.17.26 - resolution: "@blocksuite/inline@npm:0.17.26" +"@blocksuite/inline@portal:/Users/fundon/dev/toeverything/blocksuite/packages/framework/inline::locator=%40affine%2Fmonorepo%40workspace%3A.": + version: 0.0.0-use.local + resolution: "@blocksuite/inline@portal:/Users/fundon/dev/toeverything/blocksuite/packages/framework/inline::locator=%40affine%2Fmonorepo%40workspace%3A." dependencies: - "@blocksuite/global": "npm:0.17.26" + "@blocksuite/global": "workspace:*" "@preact/signals-core": "npm:^1.8.0" zod: "npm:^3.23.8" peerDependencies: lit: ^3.2.0 yjs: ^13.6.18 - checksum: 10/530f5c8f0e4791331d5363c3af10d411cf08f771010b9bdc46ec512a4d1395523c2c3b85b74df11f00c87889b2f1b258040666209912309aabe9fe5f31681c7b languageName: node - linkType: hard + linkType: soft -"@blocksuite/presets@npm:0.17.26": - version: 0.17.26 - resolution: "@blocksuite/presets@npm:0.17.26" - dependencies: - "@blocksuite/affine-block-surface": "npm:0.17.26" - "@blocksuite/affine-model": "npm:0.17.26" - "@blocksuite/affine-shared": "npm:0.17.26" - "@blocksuite/block-std": "npm:0.17.26" - "@blocksuite/blocks": "npm:0.17.26" - "@blocksuite/global": "npm:0.17.26" - "@blocksuite/inline": "npm:0.17.26" - "@blocksuite/store": "npm:0.17.26" +"@blocksuite/presets@portal:/Users/fundon/dev/toeverything/blocksuite/packages/presets::locator=%40affine%2Fmonorepo%40workspace%3A.": + version: 0.0.0-use.local + resolution: "@blocksuite/presets@portal:/Users/fundon/dev/toeverything/blocksuite/packages/presets::locator=%40affine%2Fmonorepo%40workspace%3A." + dependencies: + "@blocksuite/affine-block-surface": "workspace:*" + "@blocksuite/affine-model": "workspace:*" + "@blocksuite/affine-shared": "workspace:*" + "@blocksuite/block-std": "workspace:*" + "@blocksuite/blocks": "workspace:*" + "@blocksuite/global": "workspace:*" + "@blocksuite/inline": "workspace:*" + "@blocksuite/store": "workspace:*" "@floating-ui/dom": "npm:^1.6.10" "@lottiefiles/dotlottie-wc": "npm:^0.2.16" "@preact/signals-core": "npm:^1.8.0" "@toeverything/theme": "npm:^1.0.15" lit: "npm:^3.2.0" zod: "npm:^3.23.8" - checksum: 10/0682cedf5b6445ab757ad0dd319fd4b621490db7d80c3096890dba87cbf51b44144a3badb8731d99655640451109c09e38ee385ba06fc07e77c545ceb749948b languageName: node - linkType: hard + linkType: soft -"@blocksuite/store@npm:0.17.26": - version: 0.17.26 - resolution: "@blocksuite/store@npm:0.17.26" +"@blocksuite/store@portal:/Users/fundon/dev/toeverything/blocksuite/packages/framework/store::locator=%40affine%2Fmonorepo%40workspace%3A.": + version: 0.0.0-use.local + resolution: "@blocksuite/store@portal:/Users/fundon/dev/toeverything/blocksuite/packages/framework/store::locator=%40affine%2Fmonorepo%40workspace%3A." dependencies: - "@blocksuite/global": "npm:0.17.26" - "@blocksuite/inline": "npm:0.17.26" - "@blocksuite/sync": "npm:0.17.26" + "@blocksuite/global": "workspace:*" + "@blocksuite/inline": "workspace:*" + "@blocksuite/sync": "workspace:*" "@preact/signals-core": "npm:^1.8.0" "@types/flexsearch": "npm:^0.7.6" "@types/lodash.ismatch": "npm:^4.4.9" @@ -2901,23 +2884,21 @@ __metadata: zod: "npm:^3.23.8" peerDependencies: yjs: ^13.6.18 - checksum: 10/0e7e8b8651b0405d126c52c5e96d71f0b3e78a80f399575461ad46f472a339daeaa3233e15db5404789c2dda6392681f59b085fe51d139224f10e3467ac506ad languageName: node - linkType: hard + linkType: soft -"@blocksuite/sync@npm:0.17.26": - version: 0.17.26 - resolution: "@blocksuite/sync@npm:0.17.26" +"@blocksuite/sync@portal:/Users/fundon/dev/toeverything/blocksuite/packages/framework/sync::locator=%40affine%2Fmonorepo%40workspace%3A.": + version: 0.0.0-use.local + resolution: "@blocksuite/sync@portal:/Users/fundon/dev/toeverything/blocksuite/packages/framework/sync::locator=%40affine%2Fmonorepo%40workspace%3A." dependencies: - "@blocksuite/global": "npm:0.17.26" + "@blocksuite/global": "workspace:*" idb: "npm:^8.0.0" idb-keyval: "npm:^6.2.1" y-protocols: "npm:^1.0.6" peerDependencies: yjs: ^13.6.15 - checksum: 10/f0ddc34e1b8d7ab0e7f32e2e5a77a1447961811f7cd1626eaf1637378bee8e26b1aea18a613153935112b6fe4f80144f01be2cc47bd336e13ad6a5bd82291fef languageName: node - linkType: hard + linkType: soft "@bundled-es-modules/cookie@npm:^2.0.0": version: 2.0.0 @@ -13085,29 +13066,26 @@ __metadata: languageName: unknown linkType: soft -"@toeverything/pdf-viewer-types@npm:0.1.0": - version: 0.1.0 - resolution: "@toeverything/pdf-viewer-types@npm:0.1.0" - checksum: 10/aed8a2e9375e121a663e96147d6a726d4dd7b4917cfa35bac5c422c820125b2bc3e129281cad8c3983d1da12191ba4c6e0e45231123fce5d89091ce18dbc9560 +"@toeverything/pdf-viewer-types@portal:/Users/fundon/dev/toeverything/pdfium-builder/packages/types::locator=%40affine%2Fmonorepo%40workspace%3A.": + version: 0.0.0-use.local + resolution: "@toeverything/pdf-viewer-types@portal:/Users/fundon/dev/toeverything/pdfium-builder/packages/types::locator=%40affine%2Fmonorepo%40workspace%3A." languageName: node - linkType: hard + linkType: soft -"@toeverything/pdf-viewer@npm:^0.1.0": - version: 0.1.0 - resolution: "@toeverything/pdf-viewer@npm:0.1.0" +"@toeverything/pdf-viewer@portal:/Users/fundon/dev/toeverything/pdfium-builder/packages/pdf-viewer::locator=%40affine%2Fmonorepo%40workspace%3A.": + version: 0.0.0-use.local + resolution: "@toeverything/pdf-viewer@portal:/Users/fundon/dev/toeverything/pdfium-builder/packages/pdf-viewer::locator=%40affine%2Fmonorepo%40workspace%3A." dependencies: - "@toeverything/pdf-viewer-types": "npm:0.1.0" - "@toeverything/pdfium": "npm:0.1.0" - checksum: 10/75e1df49ecce97e667ac9ec1a630ba4492f1b712d4380a9c999f05535e305e4fd2a069d004449477520ea308ec5928f02b51268659f75788ae4715a7b6e14da7 + "@toeverything/pdf-viewer-types": "workspace:*" + "@toeverything/pdfium": "workspace:*" languageName: node - linkType: hard + linkType: soft -"@toeverything/pdfium@npm:0.1.0": - version: 0.1.0 - resolution: "@toeverything/pdfium@npm:0.1.0" - checksum: 10/5fee0f76608d27d747b9266096cdd153027e8f3e8774571524f86afd88757833a61472400df5dcf2a6ea2e16bcfe9864b090ef7e483c260998ba3fad418a9ba8 +"@toeverything/pdfium@portal:/Users/fundon/dev/toeverything/pdfium-builder/packages/pdfium::locator=%40affine%2Fmonorepo%40workspace%3A.": + version: 0.0.0-use.local + resolution: "@toeverything/pdfium@portal:/Users/fundon/dev/toeverything/pdfium-builder/packages/pdfium::locator=%40affine%2Fmonorepo%40workspace%3A." languageName: node - linkType: hard + linkType: soft "@toeverything/theme@npm:^1.0.15, @toeverything/theme@npm:^1.0.17": version: 1.0.17 @@ -14103,13 +14081,6 @@ __metadata: languageName: node linkType: hard -"@types/sortablejs@npm:^1.15.8": - version: 1.15.8 - resolution: "@types/sortablejs@npm:1.15.8" - checksum: 10/aea58b08cf45f5e9633707a8df0df1212595c731bbdfd29805487138fdd0d8c51fa5c741999738a645c1e801d43a92ba0d3fb5b45625b52e247c56588aef6c55 - languageName: node - linkType: hard - "@types/statuses@npm:^2.0.4": version: 2.0.5 resolution: "@types/statuses@npm:2.0.5" @@ -30451,13 +30422,6 @@ __metadata: languageName: node linkType: hard -"sortablejs@npm:^1.15.2": - version: 1.15.3 - resolution: "sortablejs@npm:1.15.3" - checksum: 10/85d39a172ef47adedf273afa65daa8aefcbaafd43a5b5c480d8637add93033f5784da697d0d3545d9bb6e11fd71f1847f307ee26be452942f3785a683fd44bb5 - languageName: node - linkType: hard - "source-map-js@npm:^1.0.1, source-map-js@npm:^1.0.2, source-map-js@npm:^1.2.0, source-map-js@npm:^1.2.1": version: 1.2.1 resolution: "source-map-js@npm:1.2.1"