@embedpdf/plugin-measurement 3.0.0-next.14 → 3.0.0-next.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","names":["METRES","METRES","AnnotationToken","InteractionToken","squareOf","AnnotationToken","InteractionToken","EngineError","EngineErrorCode","PermissionDenied","MeasurementToken","AnnotationToken","InteractionToken"],"sources":["../src/scale.ts","../src/capability.ts","../src/effects.ts","../src/reducer.ts","../src/measurement.plugin.ts"],"sourcesContent":["import {\n areaUnitLabel,\n measureFromRatio,\n METRES,\n squareMetres,\n squareOf,\n viewportForPoint,\n} from '@embedpdf/engine-core/runtime';\nimport type {\n AreaUnit,\n LengthUnit,\n PageMeasurementViewport,\n PdfMeasure,\n PdfRect,\n} from '@embedpdf/engine-core/runtime';\nimport type { MeasurementConfig, PageScale, ScalePreset } from './types';\n\nexport const DEFAULT_PRESETS: ScalePreset[] = [\n ...[1, 10, 20, 50, 100, 200].map((real) => ({\n id: `metric-${real}`,\n label: `1:${real}`,\n paper: 1,\n real,\n unit: 'm' as const,\n })),\n { id: 'imperial-quarter', label: '1/4 in = 1 ft', paper: 1, real: 48, unit: 'ft' },\n { id: 'imperial-eighth', label: '1/8 in = 1 ft', paper: 1, real: 96, unit: 'ft' },\n];\n\nexport const defaultMeasure = (config: MeasurementConfig, userUnit = 1): PdfMeasure =>\n typeof config.defaultScale === 'object'\n ? config.defaultScale\n : measureFromRatio(1, 1, config.defaultScale === 'imperial' ? 'ft' : 'm', userUnit);\n\nexport function selectPageScale(\n viewports: PageMeasurementViewport[],\n crop: PdfRect,\n fallback: PdfMeasure,\n persistent: boolean,\n): PageScale {\n const selected =\n viewports.find((v) => v.owned) ??\n viewportForPoint(viewports, {\n x: (crop.left + crop.right) / 2,\n y: (crop.top + crop.bottom) / 2,\n });\n return {\n measure: selected ? (selected.measure ?? null) : fallback,\n source: selected ? (selected.owned ? 'owned' : 'foreign') : 'default',\n ready: true,\n persistent,\n };\n}\n\nexport function withUnit(\n m: PdfMeasure,\n unit: LengthUnit,\n area: AreaUnit = squareOf(unit),\n): PdfMeasure {\n const basis = m.x[0]?.unit.trim() as LengthUnit;\n if (!(basis in METRES)) {\n throw new RangeError('This scale has an unknown base unit; calibrate it first');\n }\n const previous = m.distance[m.distance.length - 1];\n const precision = previous?.fraction === 'fraction' ? 100 : (previous?.precision ?? 100);\n return {\n ...m,\n distance: [{ unit, conversion: METRES[basis] / METRES[unit], precision, fraction: 'decimal' }],\n area: [\n {\n unit: areaUnitLabel(area),\n conversion: METRES[basis] ** 2 / squareMetres(area),\n precision,\n fraction: 'decimal',\n },\n ],\n };\n}\n\nexport function withPrecision(m: PdfMeasure, precision: number): PdfMeasure {\n if (!Number.isInteger(Math.log10(precision)) || precision < 1 || precision > 1e9) {\n throw new RangeError('Invalid decimal precision');\n }\n const update = (formats: PdfMeasure['distance']) =>\n formats.map((f, i) =>\n i === formats.length - 1 ? { ...f, precision, fraction: 'decimal' as const } : f,\n );\n return { ...m, distance: update(m.distance), area: update(m.area) };\n}\n\n/** Change the area display unit while preserving imported distance formatting. */\nexport function withAreaUnit(measure: PdfMeasure, unit: AreaUnit): PdfMeasure {\n const basis = measure.x[0]?.unit.trim() as LengthUnit;\n if (!(basis in METRES)) {\n throw new RangeError('This scale has an unknown base unit; calibrate it first');\n }\n const previous = measure.area[measure.area.length - 1];\n const precision = previous?.fraction === 'fraction' ? 100 : (previous?.precision ?? 100);\n return {\n ...measure,\n area: [\n {\n unit: areaUnitLabel(unit),\n conversion: METRES[basis] ** 2 / squareMetres(unit),\n precision,\n fraction: 'decimal',\n },\n ],\n };\n}\n","import type { PluginContext } from '@embedpdf/core';\nimport { AnnotationToken } from '@embedpdf/plugin-annotation/contract';\nimport { InteractionToken } from '@embedpdf/plugin-interaction/contract';\nimport {\n measureFromKnownLength,\n measureFromRatio,\n measurementPoint,\n measurementReadout,\n METRES,\n squareOf,\n} from '@embedpdf/engine-core/runtime';\nimport type { PdfMeasure } from '@embedpdf/engine-core/runtime';\nimport type { MeasurementEffects } from './effects';\nimport { DEFAULT_PRESETS, withAreaUnit, withPrecision, withUnit } from './scale';\nimport type {\n MeasurementAction,\n MeasurementCapability,\n MeasurementConfig,\n MeasurementState,\n PageScale,\n SetScaleOptions,\n} from './types';\n\nconst LOADING: PageScale = { measure: null, source: 'default', ready: false, persistent: false };\nconst UNITS = Object.keys(METRES) as Array<keyof typeof METRES>;\n\nexport function createMeasurementCapability(\n ctx: PluginContext<MeasurementState, MeasurementAction>,\n config: MeasurementConfig,\n effects: MeasurementEffects,\n): MeasurementCapability {\n const anno = ctx.get(AnnotationToken);\n const interaction = ctx.get(InteractionToken);\n const canCalibrate = () => ctx.doc?.security.allows('doc.annotate.modify') ?? false;\n const pons = (pon: number | 'all', opts?: SetScaleOptions) =>\n pon === 'all' || opts?.allPages\n ? (ctx.document()?.pages ?? []).map((p) => p.pageObjectNumber)\n : [pon];\n const scaleOf = (pon: number): PdfMeasure => {\n const scale = ctx.getState().pages[pon]?.scale.measure;\n if (!scale || scale.subtype !== 'RL') {\n throw new RangeError('Calibrate this page before changing its units or precision');\n }\n return scale;\n };\n const presets = config.presets ?? DEFAULT_PRESETS;\n return {\n canCalibrate,\n canMeasure: (pon) => anno.canCreate() && !!ctx.getState().pages[pon]?.scale.ready,\n pageScale: (pon) => ctx.getState().pages[pon]?.scale ?? LOADING,\n isBusy: () => ctx.getState().pending > 0,\n lastReports: () => ctx.getState().reports,\n prepare: effects.prepare,\n setPageScale: (pon, measure, opts = {}) => effects.change(pons(pon, opts), () => measure, opts),\n calibrate: (pon, from, to, real, opts = {}) => {\n const a = measurementPoint(from);\n const b = measurementPoint(to);\n const scale = measureFromKnownLength(Math.hypot(b.x - a.x, b.y - a.y), real);\n return effects.change(pons(pon, opts), () => scale, opts);\n },\n setUnit: (pon, unit, areaUnit, opts = {}) =>\n effects.change(pons(pon, opts), (p) => withUnit(scaleOf(p), unit, areaUnit), {\n ...opts,\n allPages: pon === 'all' || opts.allPages,\n }),\n setPrecision: (pon, precision, opts = {}) =>\n effects.change(pons(pon, opts), (p) => withPrecision(scaleOf(p), precision), {\n ...opts,\n allPages: pon === 'all' || opts.allPages,\n }),\n setPreset: (pon, id, opts = {}) => {\n const preset = presets.find((p) => p.id === id);\n if (!preset) {\n return Promise.reject(new RangeError('Unknown scale preset'));\n }\n return effects.change(\n pons(pon, opts),\n (p) =>\n measureFromRatio(\n preset.paper,\n preset.real,\n preset.unit,\n ctx.document()?.pages.find((page) => page.pageObjectNumber === p)?.userUnit ?? 1,\n ),\n opts,\n );\n },\n presets: () => presets,\n units: () => UNITS,\n areaUnits: () => [...UNITS.map(squareOf), 'ha', 'acre'],\n setAreaUnit: (pon, unit, opts = {}) =>\n effects.change(pons(pon, opts), (p) => withAreaUnit(scaleOf(p), unit), opts),\n readout: (ref) => {\n const dto = anno.get(ref);\n return dto ? measurementReadout(dto) : { unavailable: 'not-dimension' };\n },\n startCalibration: () => {\n if (canCalibrate()) {\n ctx.dispatch({ type: 'CALIBRATION', request: null });\n interaction.activateTool('calibrate');\n }\n },\n calibrationRequest: () => ctx.getState().calibration,\n dismissCalibration: () => ctx.dispatch({ type: 'CALIBRATION', request: null }),\n onCalibrationRequested: (cb) => {\n effects.calibrationListeners.add(cb);\n return () => {\n effects.calibrationListeners.delete(cb);\n };\n },\n onScaleChanged: (cb) => {\n effects.scaleListeners.add(cb);\n return () => {\n effects.scaleListeners.delete(cb);\n };\n },\n };\n}\n","import type { PluginContext } from '@embedpdf/core';\nimport { AnnotationToken } from '@embedpdf/plugin-annotation/contract/host';\nimport { InteractionToken } from '@embedpdf/plugin-interaction/contract';\nimport {\n assertWritableMeasure,\n EngineError,\n EngineErrorCode,\n PermissionDenied,\n measurementPoint,\n serializeError,\n} from '@embedpdf/engine-core/runtime';\nimport type { PdfMeasure, PageMeasurementViewport } from '@embedpdf/engine-core/runtime';\nimport { defaultMeasure, selectPageScale } from './scale';\nimport type {\n CalibrationRequest,\n MeasurementAction,\n MeasurementConfig,\n MeasurementState,\n ScaleChangeReport,\n SetScaleOptions,\n} from './types';\n\ntype Context = PluginContext<MeasurementState, MeasurementAction>;\n/** All engine IO and cross-plugin lifecycle work lives here. Calls serialize\n * per page; refresh epochs prevent an old read from replacing a newer scale. */\nexport function createMeasurementEffects(ctx: Context, config: MeasurementConfig) {\n const anno = ctx.get(AnnotationToken);\n const interaction = ctx.get(InteractionToken);\n let disposed = false;\n const epochs = new Map<number, number>();\n const reading = new Map<number, Promise<void>>();\n const queues = new Map<number, Promise<unknown>>();\n const calibrationListeners = new Set<(r: CalibrationRequest) => void>();\n const scaleListeners = new Set<(e: { pon: number; report: ScaleChangeReport }) => void>();\n const meta = (pon: number) => ctx.document()?.pages.find((p) => p.pageObjectNumber === pon);\n const live = () => {\n if (disposed || !ctx.doc) {\n throw new EngineError(EngineErrorCode.DocNotOpen);\n }\n };\n const assertAllowed = () => {\n live();\n if (!ctx.doc!.security.allows('doc.annotate.modify')) {\n throw new PermissionDenied('doc.annotate.modify', 'measurement');\n }\n };\n const publish = (pon: number, viewports: PageMeasurementViewport[]) => {\n if (disposed) {\n return;\n }\n const page = meta(pon);\n if (!page) {\n return;\n }\n const fallback = defaultMeasure(config, page.userUnit);\n anno.setPageViewports(pon, viewports, fallback);\n ctx.dispatch({\n type: 'PAGE_SCALE',\n pon,\n viewports,\n scale: selectPageScale(viewports, page.boxes.crop, fallback, !!ctx.doc?.page(pon).measure),\n });\n };\n const refresh = (pon: number): Promise<void> => {\n live();\n const page = meta(pon);\n if (!page) {\n return Promise.reject(new EngineError(EngineErrorCode.NotFound, 'Page not found'));\n }\n const epoch = (epochs.get(pon) ?? 0) + 1;\n epochs.set(pon, epoch);\n // Disable creation until calibration is known; never race a default into an imported viewport.\n anno.setPageViewports(pon, undefined, defaultMeasure(config, page.userUnit));\n const previous = ctx.getState().pages[pon];\n ctx.dispatch({\n type: 'PAGE_SCALE',\n pon,\n viewports: previous?.viewports ?? [],\n scale: {\n ...(previous?.scale ?? {\n measure: null,\n source: 'default',\n persistent: !!ctx.doc!.page(pon).measure,\n }),\n ready: false,\n },\n });\n const service = ctx.doc!.page(pon).measure;\n const request = (async () => {\n try {\n const viewports = service\n ? await service.viewports()\n : (ctx.getState().pages[pon]?.viewports ?? []);\n if (!disposed && epochs.get(pon) === epoch) {\n publish(pon, viewports);\n }\n } catch (error) {\n if (!disposed && epochs.get(pon) === epoch) {\n ctx.dispatch({\n type: 'PAGE_SCALE',\n pon,\n viewports: [],\n scale: {\n measure: null,\n source: 'default',\n ready: false,\n persistent: !!service,\n error: serializeError(error),\n },\n });\n }\n throw error;\n } finally {\n if (epochs.get(pon) === epoch) {\n reading.delete(pon);\n }\n }\n })();\n reading.set(pon, request);\n return request;\n };\n const prepare = (pon: number) =>\n reading.get(pon) ?? (ctx.getState().pages[pon]?.scale.ready ? Promise.resolve() : refresh(pon));\n const enqueue = (\n pon: number,\n action: () => Promise<ScaleChangeReport>,\n ): Promise<ScaleChangeReport> => {\n const result = (queues.get(pon) ?? Promise.resolve()).catch(() => {}).then(action);\n queues.set(pon, result);\n void result\n .finally(() => {\n if (queues.get(pon) === result) {\n queues.delete(pon);\n }\n })\n .catch(() => {});\n return result;\n };\n const save = async (\n pon: number,\n scale: PdfMeasure,\n opts: SetScaleOptions,\n ): Promise<ScaleChangeReport> => {\n assertAllowed();\n await prepare(pon);\n assertAllowed();\n const service = ctx.doc!.page(pon).measure;\n if (service) {\n await service.setScale(scale);\n live();\n await refresh(pon);\n } else {\n const page = meta(pon)!;\n const old = ctx.getState().pages[pon]?.viewports ?? [];\n publish(pon, [\n ...old.filter((v) => !v.owned),\n { bbox: page.boxes.crop, name: 'EmbedPDF', owned: true, measure: scale },\n ]);\n }\n live();\n const report =\n opts.recalculate === false\n ? { pon, scale, updated: [], skipped: [], failed: [] }\n : await anno.remeasurePage(pon, scale);\n live();\n for (const cb of scaleListeners) {\n try {\n cb({ pon, report });\n } catch {\n /* observers do not roll back a committed scale */\n }\n }\n return report;\n };\n const change = async (\n pons: number[],\n measure: (pon: number) => PdfMeasure,\n opts: SetScaleOptions = {},\n ): Promise<ScaleChangeReport[]> => {\n assertAllowed();\n ctx.dispatch({ type: 'PENDING', delta: 1 });\n try {\n const reports = await Promise.all(\n pons.map((pon) =>\n enqueue(pon, async () => {\n try {\n await prepare(pon);\n const scale = measure(pon);\n assertWritableMeasure(scale);\n return await save(pon, scale, opts);\n } catch (error) {\n if (!opts.allPages) {\n throw error;\n }\n return {\n pon,\n updated: [],\n skipped: [],\n failed: [],\n scaleError: serializeError(error),\n };\n }\n }),\n ),\n );\n live();\n ctx.dispatch({ type: 'REPORTS', reports });\n return reports;\n } finally {\n if (!disposed) {\n ctx.dispatch({ type: 'PENDING', delta: -1 });\n }\n }\n };\n const start = () => {\n const doc = ctx.doc;\n if (!doc) {\n return;\n }\n ctx.cleanup(() => {\n disposed = true;\n epochs.clear();\n queues.clear();\n calibrationListeners.clear();\n scaleListeners.clear();\n });\n ctx.cleanup(\n anno.onDraftCaptured((draft) => {\n if (draft.tool !== 'calibrate' || !doc.security.allows('doc.annotate.modify')) {\n return;\n }\n const a = measurementPoint(draft.from);\n const b = measurementPoint(draft.to);\n const userSpaceLength = Math.hypot(b.x - a.x, b.y - a.y);\n if (!(userSpaceLength > 0)) {\n return;\n }\n const request = { pon: draft.pon, from: a, to: b, userSpaceLength };\n interaction.activateTool('pointer');\n ctx.dispatch({ type: 'CALIBRATION', request });\n for (const cb of calibrationListeners) {\n try {\n cb(request);\n } catch {\n /* observers */\n }\n }\n }),\n );\n const hydrate = () => {\n for (const page of ctx.document()?.pages ?? []) {\n void refresh(page.pageObjectNumber).catch(() => {});\n }\n };\n ctx.cleanup(\n doc.events.subscribe((event) => {\n if (event.type === 'page.viewportsChanged') {\n void refresh(event.pageObjectNumber).catch(() => {});\n } else if (event.type === 'stream.desynced' || event.type === 'document.versioned') {\n hydrate();\n }\n }),\n );\n // Covers pages inserted after this document-scoped instance was created.\n let pages = '';\n const reconcile = () => {\n const next = (ctx.document()?.pages ?? []).map((p) => p.pageObjectNumber).join(',');\n if (next === pages) {\n return;\n }\n pages = next;\n for (const page of ctx.document()?.pages ?? [])\n if (!ctx.getState().pages[page.pageObjectNumber]) {\n void prepare(page.pageObjectNumber).catch(() => {});\n }\n };\n ctx.cleanup(ctx.subscribe(reconcile));\n reconcile();\n };\n return { start, prepare, change, calibrationListeners, scaleListeners };\n}\n\nexport type MeasurementEffects = ReturnType<typeof createMeasurementEffects>;\n","import type { MeasurementAction, MeasurementState } from './types';\n\nexport const initialMeasurementState: MeasurementState = {\n pages: {},\n pending: 0,\n calibration: null,\n reports: [],\n};\n\nexport function measurementReducer(s: MeasurementState, a: MeasurementAction): MeasurementState {\n switch (a.type) {\n case 'PAGE_SCALE':\n return { ...s, pages: { ...s.pages, [a.pon]: { viewports: a.viewports, scale: a.scale } } };\n case 'PENDING':\n return { ...s, pending: Math.max(0, s.pending + a.delta) };\n case 'CALIBRATION':\n return { ...s, calibration: a.request };\n case 'REPORTS':\n return { ...s, reports: a.reports };\n }\n}\n","import { definePlugin } from '@embedpdf/core';\nimport { AnnotationToken } from '@embedpdf/plugin-annotation/contract/host';\nimport { InteractionToken } from '@embedpdf/plugin-interaction/contract';\nimport { createMeasurementCapability } from './capability';\nimport { createMeasurementEffects, type MeasurementEffects } from './effects';\nimport { initialMeasurementState, measurementReducer } from './reducer';\nimport { MeasurementToken } from './types';\nimport type {\n MeasurementAction,\n MeasurementCapability,\n MeasurementConfig,\n MeasurementState,\n} from './types';\n\nexport const measurementPlugin = (config: MeasurementConfig = {}) => {\n // A plugin definition is reused across documents. Drivers are keyed by the\n // bound instance, never one mutable closure shared between document tabs.\n const drivers = new Map<string, MeasurementEffects>();\n return definePlugin<MeasurementState, MeasurementAction, MeasurementCapability>({\n id: 'measurement',\n scope: 'document',\n token: MeasurementToken,\n requires: [AnnotationToken, InteractionToken],\n initialState: initialMeasurementState,\n reduce: measurementReducer,\n capability: (ctx) => {\n const effects = createMeasurementEffects(ctx, config);\n drivers.set(ctx.documentId!, effects);\n ctx.cleanup(() => {\n drivers.delete(ctx.documentId!);\n });\n return createMeasurementCapability(ctx, config, effects);\n },\n effects: (ctx) => {\n ctx.get(MeasurementToken); // Capabilities are lazy; construct this document's driver first.\n drivers.get(ctx.documentId!)!.start();\n },\n });\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs","names":["METRES","squareOf","NO_READOUT","AnnotationToken","InteractionToken","defaultMeasure","PluginError","PluginError","defaultMeasure","PluginError","withUnit","withAreaUnit","withPrecision","MeasurementToken","AnnotationToken","InteractionToken","MEASUREMENT_DEFAULTS","MeasurementToken"],"sources":["../src/read/scale.ts","../src/services/events.ts","../src/services/siblings.ts","../src/services/store.ts","../src/services/index.ts","../src/model.ts","../src/sync/viewports.ts","../src/write/calibration.ts","../src/write/create.ts","../src/write/scale.ts","../src/controller.ts","../src/measurement.plugin.ts","../src/state.ts"],"sourcesContent":["/** Reads: the page scale, the vocabulary, readouts, and pure conversions in the page's scale. */\nimport type { Point } from '@embedpdf/core-geometry';\nimport { measurementReadout, METRES, squareOf } from '@embedpdf/engine-core/runtime';\nimport type {\n Annotation,\n AnnotationRef,\n AreaUnit,\n MeasurementReadout,\n MeasurementUnavailable,\n PageRef,\n} from '@embedpdf/engine-core/runtime';\n\nimport { NO_READOUT, type MeasurementCapability } from '../contract';\nimport type { MeasurementContext, MeasurementServices } from '../services';\nimport type { MeasurementViewportSync } from '../sync/viewports';\n\nconst UNITS = Object.keys(METRES) as Array<keyof typeof METRES>;\nconst AREA_UNITS: readonly AreaUnit[] = [...UNITS.map(squareOf), 'ha', 'acre'];\n\nexport function createScaleReads(\n ctx: MeasurementContext,\n { siblings }: Pick<MeasurementServices, 'siblings'>,\n { scaleOf }: Pick<MeasurementViewportSync, 'scaleOf'>,\n) {\n const { annotation } = siblings;\n const settings = ctx.settings();\n const state = () => ctx.state.get();\n\n // One readout per annotation object: the annotation plugin hands out the same\n // object until the annotation changes, so the readout stays the same with it.\n const readouts = new WeakMap<Annotation, MeasurementReadout | MeasurementUnavailable>();\n const getReadout = (ref: AnnotationRef): MeasurementReadout | MeasurementUnavailable => {\n const raw = annotation.get(ref);\n if (!raw) return NO_READOUT;\n let readout = readouts.get(raw);\n if (!readout) {\n readout = measurementReadout(raw);\n readouts.set(raw, readout);\n }\n return readout;\n };\n const measureDistance = (\n page: PageRef | number,\n from: Point,\n to: Point,\n ): MeasurementReadout | MeasurementUnavailable =>\n measurementReadout({\n subtype: 'line',\n intent: 'line-dimension',\n measure: scaleOf(page).measure,\n linePoints: { start: from, end: to },\n });\n const measureArea = (\n page: PageRef | number,\n vertices: readonly Point[],\n ): MeasurementReadout | MeasurementUnavailable =>\n measurementReadout({\n subtype: 'polygon',\n intent: 'polygon-dimension',\n measure: scaleOf(page).measure,\n vertices: [...vertices],\n });\n\n return {\n api: {\n canMeasure: (page) => ctx.allows('annotations:create') && scaleOf(page).ready,\n getPageScale: scaleOf,\n isBusy: () => state().pending > 0,\n listLastReports: () => state().reports,\n listPresets: () => settings.get().presets,\n listUnits: () => UNITS,\n listAreaUnits: () => AREA_UNITS,\n getReadout,\n measureDistance,\n measureArea,\n getCalibrationRequest: () => state().calibration,\n } satisfies Partial<MeasurementCapability>,\n };\n}\nexport type MeasurementScaleReads = ReturnType<typeof createScaleReads>;\n","/** The capability's four event sources, disposed with the instance. */\nimport type {\n CalibrationCompletedEvent,\n CalibrationDismissedEvent,\n CalibrationRequestedEvent,\n MeasurementScaleChangedEvent,\n} from '../contract';\nimport type { MeasurementContext } from './context';\n\nexport function createEvents(ctx: MeasurementContext) {\n return {\n scaleChanged: ctx.events.source<MeasurementScaleChangedEvent>(),\n calibrationRequested: ctx.events.source<CalibrationRequestedEvent>(),\n calibrationCompleted: ctx.events.source<CalibrationCompletedEvent>(),\n calibrationDismissed: ctx.events.source<CalibrationDismissedEvent>(),\n };\n}\nexport type MeasurementEvents = ReturnType<typeof createEvents>;\n","/** The sibling plugins: annotation (host lens) and the interaction hub. */\nimport { AnnotationToken } from '@embedpdf/plugin-annotation/contract/host';\nimport { InteractionToken } from '@embedpdf/plugin-interaction/contract';\n\nimport type { MeasurementContext } from './context';\n\nexport function resolveSiblings(ctx: MeasurementContext) {\n return { annotation: ctx.get(AnnotationToken), interaction: ctx.get(InteractionToken) };\n}\nexport type MeasurementSiblings = ReturnType<typeof resolveSiblings>;\n","/** The page registry, the calibrate twin, and the page-target expansion. */\nimport type { PageRef } from '@embedpdf/engine-core/runtime';\n\nimport type { PageTarget } from '../contract';\nimport type { MeasurementContext } from './context';\n\n/** Changing a page's scale rewrites its measurement annotations. */\nexport const SCALE_PERMISSION = 'doc.annotate.modify';\n\nexport function createStore(ctx: MeasurementContext) {\n /** A page argument of a verb, as a ref or an index: the page, or `not-found`. */\n const requirePage = (page: PageRef | number) => ctx.pageOf(page);\n const canCalibrate = () => ctx.allows(SCALE_PERMISSION);\n /** The pages a verb changes, each resolved: a page that isn't there refuses the whole call. */\n const targets = (pages: PageTarget): readonly PageRef[] => {\n if (pages === 'all') return (ctx.document()?.pages ?? []).map((layout) => layout.ref);\n const list: readonly (PageRef | number)[] = Array.isArray(pages)\n ? pages\n : [pages as PageRef | number];\n return list.map((page) => ctx.pageOf(page).ref);\n };\n return { requirePage, canCalibrate, targets };\n}\nexport type MeasurementStore = ReturnType<typeof createStore>;\n","/** The plugin-private services every area is built on, created once per instance. */\nimport type { MeasurementContext } from './context';\nimport { createEvents, type MeasurementEvents } from './events';\nimport { resolveSiblings, type MeasurementSiblings } from './siblings';\nimport { createStore, type MeasurementStore } from './store';\n\nexport type { MeasurementContext } from './context';\n\nexport interface MeasurementServices {\n readonly events: MeasurementEvents;\n readonly store: MeasurementStore;\n readonly siblings: MeasurementSiblings;\n}\n\nexport function createServices(ctx: MeasurementContext): MeasurementServices {\n return { events: createEvents(ctx), store: createStore(ctx), siblings: resolveSiblings(ctx) };\n}\n","/**\n * The measurement session: scale changes in flight, the pending calibration,\n * the last change's reports, why a page's viewport read failed, and the\n * session-only viewports of engines that cannot persist a scale. The pages'\n * viewports themselves are engine data held by a page mirror. Every\n * transition below is pure; the controller applies them with\n * `ctx.state.update`. `selectPageScale` and `pageScaleOf` are the pure\n * projections from viewports to the public {@link PageScale}.\n */\nimport { viewportForPoint } from '@embedpdf/engine-core/runtime';\nimport type {\n PageMeasurementViewport,\n PdfMeasure,\n PdfSize,\n SerializedEngineError,\n} from '@embedpdf/engine-core/runtime';\nimport type { ResourceStatus } from '@embedpdf/core';\n\nimport type { CalibrationRequest, PageScale, ScaleChangeReport } from './contract';\n\nexport interface MeasurementState {\n /** Scale changes in flight. */\n readonly pending: number;\n readonly calibration: CalibrationRequest | null;\n readonly reports: readonly ScaleChangeReport[];\n /** Page object number → why the last read of the page's viewports failed. */\n readonly loadErrors: Readonly<Record<number, SerializedEngineError>>;\n /** Page object number → the page's viewports, when the engine has no page measure service. */\n readonly localViewports: Readonly<Record<number, readonly PageMeasurementViewport[]>>;\n}\n\n/** No reports yet: the same array every time. */\nexport const NO_REPORTS: readonly ScaleChangeReport[] = Object.freeze([]);\n\nexport const initialMeasurementState = (): MeasurementState => ({\n pending: 0,\n calibration: null,\n reports: NO_REPORTS,\n loadErrors: {},\n localViewports: {},\n});\n\nexport const beginScaleChange = (state: MeasurementState): MeasurementState => ({\n ...state,\n pending: state.pending + 1,\n});\n\nexport const endScaleChange = (state: MeasurementState): MeasurementState =>\n state.pending === 0 ? state : { ...state, pending: state.pending - 1 };\n\nexport const setCalibration = (\n state: MeasurementState,\n calibration: CalibrationRequest | null,\n): MeasurementState => (state.calibration === calibration ? state : { ...state, calibration });\n\nexport const setReports = (\n state: MeasurementState,\n reports: readonly ScaleChangeReport[],\n): MeasurementState => (state.reports === reports ? state : { ...state, reports });\n\nexport const recordLoadError = (\n state: MeasurementState,\n pageObjectNumber: number,\n error: SerializedEngineError,\n): MeasurementState => ({\n ...state,\n loadErrors: { ...state.loadErrors, [pageObjectNumber]: error },\n});\n\nexport const clearLoadError = (\n state: MeasurementState,\n pageObjectNumber: number,\n): MeasurementState => {\n if (!(pageObjectNumber in state.loadErrors)) return state;\n const { [pageObjectNumber]: _cleared, ...loadErrors } = state.loadErrors;\n return { ...state, loadErrors };\n};\n\nexport const setLocalViewports = (\n state: MeasurementState,\n pageObjectNumber: number,\n viewports: readonly PageMeasurementViewport[],\n): MeasurementState => ({\n ...state,\n localViewports: { ...state.localViewports, [pageObjectNumber]: viewports },\n});\n\n/**\n * The scale a page's viewports resolve to: the owned viewport, else the one\n * containing the page's center, else the fallback.\n */\nexport function selectPageScale(\n viewports: readonly PageMeasurementViewport[],\n size: PdfSize,\n fallback: PdfMeasure,\n persistent: boolean,\n): PageScale {\n const selected =\n viewports.find((viewport) => viewport.owned) ??\n viewportForPoint(viewports, { x: size.width / 2, y: size.height / 2 });\n return {\n measure: selected ? (selected.measure ?? null) : fallback,\n source: selected ? (selected.owned ? 'owned' : 'foreign') : 'default',\n ready: true,\n persistent,\n };\n}\n\n/** What `pageScaleOf` projects: the page's mirrored viewports and read state, and its layout. */\nexport interface PageScaleInputs {\n /** The last confirmed viewports; undefined until the first read lands. */\n readonly viewports: readonly PageMeasurementViewport[] | undefined;\n readonly status: ResourceStatus;\n readonly error: SerializedEngineError | undefined;\n /** The page's size; undefined when the page is not in the registry. */\n readonly size: PdfSize | undefined;\n readonly fallback: PdfMeasure;\n readonly persistent: boolean;\n}\n\n/**\n * The public page scale. A page is ready once its viewports were read; a\n * failed re-read keeps the last confirmed viewports in effect and reports\n * its error alongside them.\n */\nexport function pageScaleOf(inputs: PageScaleInputs): PageScale {\n const error = inputs.status === 'error' && inputs.error ? { error: inputs.error } : {};\n if (!inputs.viewports || !inputs.size) {\n return {\n measure: null,\n source: 'default',\n ready: false,\n persistent: inputs.persistent,\n ...error,\n };\n }\n return {\n ...selectPageScale(inputs.viewports, inputs.size, inputs.fallback, inputs.persistent),\n ...error,\n };\n}\n","/**\n * The pages' viewports: a page mirror re-read whenever a confirmed\n * `pages.scaleSet` names a loaded page, from this session or another\n * (stream gaps and version moves re-read every loaded page). Its `changed`\n * callback tells the annotation plugin a page's viewports, and a new\n * `defaultScale` setting tells it again. `connect` loads every page in the\n * registry, including pages inserted later.\n */\nimport {\n PluginError,\n memoByKey,\n toPageRef,\n type OperationOptions,\n type PageInfo,\n} from '@embedpdf/core';\nimport { serializeError } from '@embedpdf/engine-core/runtime';\nimport type { PageMeasurementViewport, PageRef } from '@embedpdf/engine-core/runtime';\n\nimport type { PageScale } from '../contract';\nimport { clearLoadError, pageScaleOf, recordLoadError } from '../model';\nimport { defaultMeasure } from '../scale';\nimport type { MeasurementContext, MeasurementServices } from '../services';\n\n/** The scale of a page index past the end: none, and never ready. */\nconst NO_PAGE: PageScale = Object.freeze({\n measure: null,\n source: 'default',\n ready: false,\n persistent: false,\n});\n\nexport function createViewportSync(\n ctx: MeasurementContext,\n { siblings }: Pick<MeasurementServices, 'siblings'>,\n) {\n const { annotation } = siblings;\n const settings = ctx.settings();\n /** The scale of a page without one: the `defaultScale` setting, in the page's user unit. */\n const fallbackOf = (layout: PageInfo | null) =>\n defaultMeasure(settings.get().defaultScale, layout?.userUnit ?? 1);\n\n const viewports = ctx.pageMirror<readonly PageMeasurementViewport[]>({\n name: 'viewports',\n load: async (doc, page, signal) => {\n ctx.assertPageRef(page);\n const service = doc.page(page).measure;\n // Without a page measure service, scales live for the session only.\n if (!service) return ctx.state.get().localViewports[page.objectNumber] ?? [];\n try {\n return (await service.listViewports()).viewports;\n } catch (error) {\n // A read the closing document cut short is no page's error, and there's no state left.\n if (!signal.aborted) {\n ctx.state.update(recordLoadError, page.objectNumber, serializeError(error));\n }\n throw error;\n }\n },\n affected: (event) => (event.type === 'pages.scaleSet' ? [event.page] : null),\n changed: ({ page, cause, next }) => {\n if (cause === 'drop' || next === undefined) return;\n ctx.state.update(clearLoadError, page.objectNumber);\n const layout = ctx.getPage(page);\n if (layout) annotation.setPageViewports(page, [...next], fallbackOf(layout));\n },\n });\n\n /** The engine can persist a scale into the document. */\n const isPersistent = (page: PageRef): boolean => ctx.doc.page(page).measure !== undefined;\n\n /** The page's public scale, the same object until its viewports, read state or layout change. */\n const scaleOfPage = memoByKey(\n (pageObjectNumber: number) => {\n const page = toPageRef(pageObjectNumber);\n const layout = ctx.getPage(page);\n return [\n viewports.get(page),\n viewports.getStatus(page),\n ctx.state.get().loadErrors[pageObjectNumber],\n layout,\n layout ? isPersistent(page) : false,\n settings.get().defaultScale,\n ] as const;\n },\n (_pageObjectNumber, pageViewports, status, error, layout, persistent): PageScale =>\n pageScaleOf({\n viewports: pageViewports,\n status,\n error,\n size: layout?.size,\n fallback: fallbackOf(layout),\n persistent,\n }),\n );\n /** A page's scale, by ref or index; a page that isn't there has none, and isn't ready. */\n const scaleOf = (page: PageRef | number): PageScale => {\n if (typeof page !== 'number') return scaleOfPage(page.objectNumber);\n const layout = ctx.getPage(page);\n return layout ? scaleOfPage(layout.ref.objectNumber) : NO_PAGE;\n };\n\n const ensureLoaded = (page: PageRef | number, options?: OperationOptions): Promise<void> => {\n const layout = ctx.getPage(page);\n if (!layout) {\n return Promise.reject(new PluginError('not-found', 'measurement', 'no such page'));\n }\n return ctx.cancellable(options?.signal, viewports.ensureLoaded(layout.ref));\n };\n\n const connect = (): void => {\n const hydrate = (layouts: readonly PageInfo[] | undefined) => {\n for (const layout of layouts ?? []) {\n if (viewports.getStatus(layout.ref) !== 'idle') continue;\n void viewports.ensureLoaded(layout.ref).catch(() => {\n /* reported through getPageScale(page).error */\n });\n }\n };\n hydrate(ctx.document()?.pages);\n ctx.watch(() => ctx.document()?.pages, hydrate);\n // A new default scale reaches the pages without one: the annotation\n // plugin measures new drawings on them with it.\n ctx.listen(settings.api.onSettingsChanged, ({ changed }) => {\n if (!changed.includes('defaultScale')) return;\n for (const layout of ctx.document()?.pages ?? []) {\n const known = viewports.get(layout.ref);\n if (known) annotation.setPageViewports(layout.ref, [...known], fallbackOf(layout));\n }\n });\n };\n\n return {\n ensureLoaded,\n scaleOf,\n /** Re-read one page; for session-only scales, which no engine event announces. */\n refresh: (page: PageRef) => viewports.refresh(page),\n connect,\n };\n}\nexport type MeasurementViewportSync = ReturnType<typeof createViewportSync>;\n","/** The calibrate flow: arm the tool, turn a captured distance draft into a\n * request (page space), and dismiss it. */\nimport { measurementPoint } from '@embedpdf/engine-core/runtime';\n\nimport type { MeasurementCapability } from '../contract';\nimport { setCalibration } from '../model';\nimport type { MeasurementContext, MeasurementServices } from '../services';\nimport { SCALE_PERMISSION } from '../services/store';\n\nexport function createCalibration(\n ctx: MeasurementContext,\n { events, store, siblings }: Pick<MeasurementServices, 'events' | 'store' | 'siblings'>,\n) {\n const { calibrationRequested, calibrationDismissed } = events;\n const { canCalibrate } = store;\n const { annotation, interaction } = siblings;\n\n const startCalibration = (): void => {\n ctx.assertAllowed(SCALE_PERMISSION, 'measurement.startCalibration');\n ctx.state.update(setCalibration, null);\n interaction.activateTool('calibrate');\n };\n const dismissCalibration = (): void => {\n if (!ctx.state.get().calibration) return;\n ctx.state.update(setCalibration, null);\n calibrationDismissed.emit({});\n };\n\n /** A distance draft from the calibrate tool becomes the pending request. */\n const connect = (): void => {\n ctx.listen(annotation.onDraftCaptured, (draft) => {\n if (draft.tool !== 'calibrate' || !canCalibrate()) return;\n const from = measurementPoint(draft.from);\n const to = measurementPoint(draft.to);\n const userSpaceLength = Math.hypot(to.x - from.x, to.y - from.y);\n if (!(userSpaceLength > 0)) return;\n const request = { page: draft.page, from, to, userSpaceLength };\n interaction.activateTool('pointer');\n ctx.state.update(setCalibration, request);\n calibrationRequested.emit({ request });\n });\n };\n\n return {\n connect,\n api: { startCalibration, dismissCalibration } satisfies Partial<MeasurementCapability>,\n };\n}\n","/** Measurement creation: a measurement annotation with the page's scale, through the annotation plugin. */\nimport { PluginError, type OperationOptions } from '@embedpdf/core';\nimport type { Annotation, AnnotationDraft, PageRef } from '@embedpdf/engine-core/runtime';\n\nimport type { CreateMeasurementInput, MeasurementCapability } from '../contract';\nimport type { MeasurementContext, MeasurementServices } from '../services';\nimport type { MeasurementViewportSync } from '../sync/viewports';\n\nexport function createMeasuring(\n ctx: Pick<MeasurementContext, 'assertAllowed' | 'pageOf'>,\n { siblings }: Pick<MeasurementServices, 'siblings'>,\n { scaleOf }: Pick<MeasurementViewportSync, 'scaleOf'>,\n) {\n const { annotation } = siblings;\n\n /**\n * The measurement's engine draft: the tool's current defaults (style,\n * caption and leader), the dimension intent, and the page's scale. The\n * engine works out the label from the points and the scale.\n */\n const draftOf = (\n input: CreateMeasurementInput,\n page: PageRef,\n tool: string,\n ): AnnotationDraft | Error => {\n const style = annotation.tools.getDefaults(tool);\n const shared = {\n color: style.color,\n strokeWidth: style.strokeWidth,\n opacity: style.opacity,\n measure: scaleOf(page).measure,\n captionEnabled: style.captionEnabled ?? true,\n };\n switch (input.kind) {\n case 'distance': {\n const [from, to] = input.points;\n if (!from || !to || input.points.length !== 2) {\n return new PluginError(\n 'invalid-input',\n 'measurement',\n 'a distance needs exactly two points',\n );\n }\n return {\n subtype: 'line',\n intent: 'line-dimension',\n linePoints: { start: from, end: to },\n lineEndings: style.lineEndings,\n // The arrowheads fill with the line's color unless the tool sets a fill.\n interiorColor: style.interiorColor ?? style.color,\n ...shared,\n captionPosition: style.captionPosition ?? 'inline',\n ...(style.leader ? { leader: style.leader } : {}),\n } as AnnotationDraft;\n }\n case 'perimeter':\n return {\n subtype: 'polyline',\n intent: 'polyline-dimension',\n vertices: input.points,\n lineEndings: style.lineEndings,\n ...shared,\n } as AnnotationDraft;\n case 'area':\n return {\n subtype: 'polygon',\n intent: 'polygon-dimension',\n vertices: input.points,\n interiorColor: style.interiorColor,\n ...shared,\n } as AnnotationDraft;\n }\n };\n\n const createMeasurement = async (\n input: CreateMeasurementInput,\n options?: OperationOptions,\n ): Promise<{ annotation: Annotation }> => {\n ctx.assertAllowed('annotations:create', 'measurement.createMeasurement');\n const page = ctx.pageOf(input.page).ref;\n if (!scaleOf(page).ready) {\n throw new PluginError('not-ready', 'measurement', 'the page scale is not known yet');\n }\n const draft = draftOf(input, page, input.tool ?? input.kind);\n if (draft instanceof Error) throw draft;\n return annotation.create(page, draft, undefined, { signal: options?.signal });\n };\n\n return { api: { createMeasurement } satisfies Partial<MeasurementCapability> };\n}\n","/**\n * Scale writes. Every change serializes per page, loads the page first, and\n * re-measures the page's measurement annotations unless told not to. A\n * multi-page change reports per-page failures; a single-page change rejects.\n */\nimport { PluginError, toPluginError, type SerialQueue } from '@embedpdf/core';\nimport {\n assertWritableMeasure,\n measureFromKnownLength,\n measureFromRatio,\n measurementPoint,\n pageRefsEqual,\n serializeError,\n} from '@embedpdf/engine-core/runtime';\nimport type { PageRef, PdfMeasure } from '@embedpdf/engine-core/runtime';\n\nimport type {\n CalibrateInput,\n MeasurementCapability,\n PageTarget,\n ScaleChangeOptions,\n ScaleChangeReport,\n} from '../contract';\nimport {\n beginScaleChange,\n endScaleChange,\n setCalibration,\n setLocalViewports,\n setReports,\n} from '../model';\nimport { defaultMeasure, withAreaUnit, withPrecision, withUnit } from '../scale';\nimport type { MeasurementContext, MeasurementServices } from '../services';\nimport { SCALE_PERMISSION } from '../services/store';\nimport type { MeasurementViewportSync } from '../sync/viewports';\n\nexport function createScaleWrites(\n ctx: MeasurementContext,\n { events, store, siblings }: Pick<MeasurementServices, 'events' | 'store' | 'siblings'>,\n {\n ensureLoaded,\n refresh,\n scaleOf,\n }: Pick<MeasurementViewportSync, 'ensureLoaded' | 'refresh' | 'scaleOf'>,\n) {\n const { scaleChanged, calibrationCompleted } = events;\n const { requirePage, targets } = store;\n const { annotation } = siblings;\n const settings = ctx.settings();\n\n /** One write queue per page, so a page's scale changes land in order. */\n const pageQueues = new Map<number, SerialQueue>();\n const queueOf = (page: PageRef): SerialQueue => {\n let queue = pageQueues.get(page.objectNumber);\n if (!queue) {\n queue = ctx.serialQueue(`scale:${page.objectNumber}`);\n pageQueues.set(page.objectNumber, queue);\n }\n return queue;\n };\n // A download waits for the scale changes on their way.\n ctx.onSettle(async () => {\n await Promise.all([...pageQueues.values()].map((queue) => queue.idle()));\n });\n\n /** Write one page's scale (`null` = back to the default) and re-measure. */\n const save = async (\n page: PageRef,\n scale: PdfMeasure | null,\n options: ScaleChangeOptions,\n ): Promise<ScaleChangeReport> => {\n const { signal } = options;\n ctx.assertAllowed(SCALE_PERMISSION, 'changing a scale');\n await ensureLoaded(page, { signal });\n ctx.assertAllowed(SCALE_PERMISSION, 'changing a scale');\n const service = ctx.doc.page(page).measure;\n if (service) {\n await ctx.cancellable(signal, service.setScale(scale));\n // The engine published `pages.scaleSet` before resolving, so the\n // mirror is already re-reading this page: join that read, never start another.\n await ensureLoaded(page);\n } else {\n // A session-only scale: no engine event announces it, so re-read the page.\n const layout = requirePage(page);\n const kept = (ctx.state.get().localViewports[page.objectNumber] ?? []).filter(\n (viewport) => !viewport.owned,\n );\n ctx.state.update(setLocalViewports, page.objectNumber, [\n ...kept,\n ...(scale\n ? [\n {\n bbox: { x: 0, y: 0, ...layout.size },\n name: 'EmbedPDF',\n owned: true,\n measure: scale,\n },\n ]\n : []),\n ]);\n await refresh(page);\n }\n const effective =\n scale ?? defaultMeasure(settings.get().defaultScale, requirePage(page).userUnit);\n const report =\n options.recalculate === false\n ? { page, scale: effective, updated: [], skipped: [], failed: [] }\n : await ctx.cancellable(signal, annotation.remeasurePage(page, effective));\n scaleChanged.emit({ page, report });\n return report;\n };\n\n const change = async (\n pages: PageTarget,\n measure: (page: PageRef) => PdfMeasure | null,\n options: ScaleChangeOptions = {},\n ): Promise<readonly ScaleChangeReport[]> => {\n ctx.assertAllowed(SCALE_PERMISSION, 'changing a scale');\n // Every page is resolved first: a page that isn't there refuses the call.\n const target = targets(pages);\n if (options.signal?.aborted) {\n throw new PluginError('operation-cancelled', 'measurement', 'operation cancelled', {\n cause: options.signal.reason,\n });\n }\n // One page: a failure rejects. Several: each page reports its own outcome.\n const tolerant = pages === 'all' || target.length > 1;\n ctx.state.update(beginScaleChange);\n try {\n const reports = await Promise.all(\n target.map((page) =>\n queueOf(page)(async (): Promise<ScaleChangeReport> => {\n try {\n await ensureLoaded(page, { signal: options.signal });\n const scale = measure(page);\n if (scale) assertWritableMeasure(scale);\n return await save(page, scale, options);\n } catch (error) {\n const refused = toPluginError('measurement', error);\n // A cancel ends the whole change, however many pages it has.\n if (!tolerant || refused.code === 'operation-cancelled') throw refused;\n return {\n page,\n updated: [],\n skipped: [],\n failed: [],\n scaleError: serializeError(error),\n };\n }\n }, options),\n ),\n );\n ctx.state.update(setReports, reports);\n return reports;\n } finally {\n ctx.state.update(endScaleChange);\n }\n };\n\n /** The page's current rectilinear scale, for unit and precision edits. */\n const rectilinearOf = (page: PageRef): PdfMeasure => {\n const scale = scaleOf(page).measure;\n if (!scale || scale.subtype !== 'rectilinear') {\n throw new PluginError(\n 'not-ready',\n 'measurement',\n 'calibrate this page before changing its units or precision',\n );\n }\n return scale;\n };\n\n const calibrate = async (\n input: CalibrateInput,\n options: ScaleChangeOptions & { applyTo?: PageTarget } = {},\n ): Promise<readonly ScaleChangeReport[]> => {\n const start = measurementPoint(input.from);\n const end = measurementPoint(input.to);\n let scale: PdfMeasure;\n try {\n scale = measureFromKnownLength(Math.hypot(end.x - start.x, end.y - start.y), input.distance);\n } catch (error) {\n throw new PluginError(\n 'invalid-input',\n 'measurement',\n String((error as Error).message ?? error),\n );\n }\n const { applyTo, ...rest } = options;\n const page = requirePage(input.page).ref;\n const reports = await change(applyTo ?? page, () => scale, rest);\n const request = ctx.state.get().calibration;\n if (request && pageRefsEqual(request.page, page)) {\n ctx.state.update(setCalibration, null);\n }\n calibrationCompleted.emit({ page });\n return reports;\n };\n\n return {\n api: {\n setScale: (pages, measure, options) => change(pages, () => measure, options),\n calibrate,\n setUnit: (pages, unit, options) =>\n change(pages, (page) => withUnit(rectilinearOf(page), unit), options),\n setAreaUnit: (pages, unit, options) =>\n change(pages, (page) => withAreaUnit(rectilinearOf(page), unit), options),\n setPrecision: (pages, precision, options) =>\n change(pages, (page) => withPrecision(rectilinearOf(page), precision), options),\n setPreset: (pages, presetId, options) => {\n const preset = settings.get().presets.find((candidate) => candidate.id === presetId);\n if (!preset) {\n return Promise.reject(\n new PluginError('not-found', 'measurement', `unknown scale preset '${presetId}'`),\n );\n }\n return change(\n pages,\n (page) =>\n measureFromRatio(preset.paper, preset.real, preset.unit, {\n userUnit: ctx.getPage(page)?.userUnit ?? 1,\n }),\n options,\n );\n },\n clearScale: (pages, options) => change(pages, () => null, options),\n } satisfies Partial<MeasurementCapability>,\n };\n}\n","/**\n * The measurement controller: the composition root. It builds the plugin's\n * services once, wires each area with the services it declares, and\n * assembles the capability from the areas' API slices. No behavior lives\n * here: every verb and read has a home in `read/`, `write/` or `sync/`.\n */\nimport { composeApi } from '@embedpdf/core';\n\nimport type { MeasurementCapability } from './contract';\nimport { createScaleReads } from './read/scale';\nimport { createServices, type MeasurementContext } from './services';\nimport { createViewportSync } from './sync/viewports';\nimport { createCalibration } from './write/calibration';\nimport { createMeasuring } from './write/create';\nimport { createScaleWrites } from './write/scale';\n\nexport function createMeasurementController(ctx: MeasurementContext) {\n const services = createServices(ctx);\n const { events, store } = services;\n const settings = ctx.settings();\n\n const viewports = createViewportSync(ctx, services);\n const reads = createScaleReads(ctx, services, viewports);\n const scale = createScaleWrites(ctx, services, viewports);\n const calibration = createCalibration(ctx, services);\n const measuring = createMeasuring(ctx, services, viewports);\n\n const api: MeasurementCapability = composeApi('measurement', [\n settings.api,\n reads.api,\n scale.api,\n calibration.api,\n measuring.api,\n {\n canCalibrate: store.canCalibrate,\n ensureLoaded: viewports.ensureLoaded,\n onScaleChanged: events.scaleChanged.on,\n onCalibrationRequested: events.calibrationRequested.on,\n onCalibrationCompleted: events.calibrationCompleted.on,\n onCalibrationDismissed: events.calibrationDismissed.on,\n },\n ]);\n\n return {\n api,\n connect() {\n calibration.connect();\n viewports.connect();\n },\n };\n}\n","import { definePlugin } from '@embedpdf/core';\nimport { AnnotationToken } from '@embedpdf/plugin-annotation/contract/host';\nimport { InteractionToken } from '@embedpdf/plugin-interaction/contract';\n\nimport { MEASUREMENT_DEFAULTS, MeasurementToken, type MeasurementConfig } from './contract';\nimport { createMeasurementController } from './controller';\nimport { initialMeasurementState } from './model';\n\n/**\n * Page scale, calibration and measurement readouts, document-scoped. The\n * annotation plugin owns the measurement annotations; this plugin owns the\n * page's viewports (the scale), keeps the annotation plugin's measure in step,\n * and turns the calibrate tool's drafts into scale requests. `config` is the\n * settings the app registers, over {@link MEASUREMENT_DEFAULTS}.\n */\nexport const measurementPlugin = (config?: MeasurementConfig) =>\n definePlugin({\n id: 'measurement',\n scope: 'document',\n token: MeasurementToken,\n requires: [AnnotationToken, InteractionToken],\n state: initialMeasurementState,\n // A scale is one value: a change replaces it, never merges into it.\n settings: { defaults: MEASUREMENT_DEFAULTS, registered: config, whole: ['defaultScale'] },\n create: createMeasurementController,\n });\n","/**\n * The measurements page's State table as code: what `useMeasurementState()`\n * returns, and the same fields in every other framework. A page's scale and a\n * measurement's readout are not here: `usePageScale(page)` and\n * `useMeasurementReadout(ref)` read them, so a component re-renders only for\n * its own page or measurement.\n */\nimport { defineState } from '@embedpdf/core';\n\nimport { MeasurementToken } from './contract';\nimport { NO_REPORTS } from './model';\n\nexport const measurementState = defineState(MeasurementToken, {\n read: (measurement) => ({\n busy: measurement.isBusy(),\n calibrationRequest: measurement.getCalibrationRequest(),\n lastReports: measurement.listLastReports(),\n }),\n empty: {\n busy: false,\n calibrationRequest: null,\n lastReports: NO_REPORTS,\n },\n});\n"],"mappings":"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"}
package/dist/index.d.cts CHANGED
@@ -1,6 +1,34 @@
1
- import { _ as SetScaleOptions, a as MeasurementAction, c as MeasurementReadout, d as MeasurementUnavailable, f as PageScale, g as ScalePreset, h as ScaleChangeReport, i as LengthUnit, l as MeasurementState, m as RecalibrationReport, n as AreaUnit, o as MeasurementCapability, p as PdfMeasure, r as CalibrationRequest, s as MeasurementConfig, t as AnnotationRef, u as MeasurementToken } from "./contract-BnLRuw-Z.cjs";
1
+ import { C as RecalibrationReport, D as MeasurementToken, E as ScalePreset, S as PdfMeasure, T as ScaleChangeReport, _ as MeasurementUnavailable, a as CalibrationDismissedEvent, b as PageScale, c as CreateMeasurementInput, d as MeasurementCapability, f as MeasurementConfig, g as MeasurementSettings, h as MeasurementScaleChangedEvent, i as CalibrationCompletedEvent, l as LengthUnit, m as MeasurementReadout, n as AreaUnit, o as CalibrationRequest, p as MeasurementKind, r as CalibrateInput, s as CalibrationRequestedEvent, t as AnnotationRef, u as MEASUREMENT_DEFAULTS, v as NO_PAGE_SCALE, w as ScaleChangeOptions, x as PageTarget, y as NO_READOUT } from "./contract-BGn30CU9.cjs";
2
+ import "@embedpdf/core";
3
+ import { PageMeasurementViewport, PdfMeasure as PdfMeasure$1, SerializedEngineError } from "@embedpdf/engine-core/runtime";
4
+ //#region src/model.d.ts
5
+ interface MeasurementState {
6
+ /** Scale changes in flight. */
7
+ readonly pending: number;
8
+ readonly calibration: CalibrationRequest | null;
9
+ readonly reports: readonly ScaleChangeReport[];
10
+ /** Page object number → why the last read of the page's viewports failed. */
11
+ readonly loadErrors: Readonly<Record<number, SerializedEngineError>>;
12
+ /** Page object number → the page's viewports, when the engine has no page measure service. */
13
+ readonly localViewports: Readonly<Record<number, readonly PageMeasurementViewport[]>>;
14
+ }
15
+ //#endregion
2
16
  //#region src/measurement.plugin.d.ts
3
- declare const measurementPlugin: (config?: MeasurementConfig) => import("@embedpdf/core").PluginDef<MeasurementState, MeasurementAction, MeasurementCapability>;
17
+ /**
18
+ * Page scale, calibration and measurement readouts, document-scoped. The
19
+ * annotation plugin owns the measurement annotations; this plugin owns the
20
+ * page's viewports (the scale), keeps the annotation plugin's measure in step,
21
+ * and turns the calibrate tool's drafts into scale requests. `config` is the
22
+ * settings the app registers, over {@link MEASUREMENT_DEFAULTS}.
23
+ */
24
+ declare const measurementPlugin: (config?: MeasurementConfig) => import("@embedpdf/core").PluginDef<MeasurementState, MeasurementCapability, MeasurementSettings>;
25
+ //#endregion
26
+ //#region src/state.d.ts
27
+ declare const measurementState: import("@embedpdf/core").StateDeclaration<MeasurementCapability, {
28
+ busy: boolean;
29
+ calibrationRequest: CalibrationRequest | null;
30
+ lastReports: readonly ScaleChangeReport[];
31
+ }>;
4
32
  //#endregion
5
- export { type AnnotationRef, type AreaUnit, type CalibrationRequest, type LengthUnit, type MeasurementAction, type MeasurementCapability, type MeasurementConfig, type MeasurementReadout, type MeasurementState, MeasurementToken, type MeasurementUnavailable, type PageScale, type PdfMeasure, type RecalibrationReport, type ScaleChangeReport, type ScalePreset, type SetScaleOptions, measurementPlugin };
33
+ export { type AnnotationRef, type AreaUnit, CalibrateInput, CalibrationCompletedEvent, CalibrationDismissedEvent, CalibrationRequest, CalibrationRequestedEvent, CreateMeasurementInput, type LengthUnit, MEASUREMENT_DEFAULTS, MeasurementCapability, MeasurementConfig, MeasurementKind, type MeasurementReadout, MeasurementScaleChangedEvent, MeasurementSettings, MeasurementToken, type MeasurementUnavailable, NO_PAGE_SCALE, NO_READOUT, PageScale, PageTarget, type PdfMeasure, type RecalibrationReport, ScaleChangeOptions, ScaleChangeReport, ScalePreset, measurementPlugin, measurementState };
6
34
  //# sourceMappingURL=index.d.cts.map
package/dist/index.d.ts CHANGED
@@ -1,6 +1,34 @@
1
- import { _ as SetScaleOptions, a as MeasurementAction, c as MeasurementReadout, d as MeasurementUnavailable, f as PageScale, g as ScalePreset, h as ScaleChangeReport, i as LengthUnit, l as MeasurementState, m as RecalibrationReport, n as AreaUnit, o as MeasurementCapability, p as PdfMeasure, r as CalibrationRequest, s as MeasurementConfig, t as AnnotationRef, u as MeasurementToken } from "./contract-C_ugpRGJ.js";
1
+ import { C as RecalibrationReport, D as MeasurementToken, E as ScalePreset, S as PdfMeasure, T as ScaleChangeReport, _ as MeasurementUnavailable, a as CalibrationDismissedEvent, b as PageScale, c as CreateMeasurementInput, d as MeasurementCapability, f as MeasurementConfig, g as MeasurementSettings, h as MeasurementScaleChangedEvent, i as CalibrationCompletedEvent, l as LengthUnit, m as MeasurementReadout, n as AreaUnit, o as CalibrationRequest, p as MeasurementKind, r as CalibrateInput, s as CalibrationRequestedEvent, t as AnnotationRef, u as MEASUREMENT_DEFAULTS, v as NO_PAGE_SCALE, w as ScaleChangeOptions, x as PageTarget, y as NO_READOUT } from "./contract-CSnWNeXI.js";
2
+ import "@embedpdf/core";
3
+ import { PageMeasurementViewport, PdfMeasure as PdfMeasure$1, SerializedEngineError } from "@embedpdf/engine-core/runtime";
4
+ //#region src/model.d.ts
5
+ interface MeasurementState {
6
+ /** Scale changes in flight. */
7
+ readonly pending: number;
8
+ readonly calibration: CalibrationRequest | null;
9
+ readonly reports: readonly ScaleChangeReport[];
10
+ /** Page object number → why the last read of the page's viewports failed. */
11
+ readonly loadErrors: Readonly<Record<number, SerializedEngineError>>;
12
+ /** Page object number → the page's viewports, when the engine has no page measure service. */
13
+ readonly localViewports: Readonly<Record<number, readonly PageMeasurementViewport[]>>;
14
+ }
15
+ //#endregion
2
16
  //#region src/measurement.plugin.d.ts
3
- declare const measurementPlugin: (config?: MeasurementConfig) => import("@embedpdf/core").PluginDef<MeasurementState, MeasurementAction, MeasurementCapability>;
17
+ /**
18
+ * Page scale, calibration and measurement readouts, document-scoped. The
19
+ * annotation plugin owns the measurement annotations; this plugin owns the
20
+ * page's viewports (the scale), keeps the annotation plugin's measure in step,
21
+ * and turns the calibrate tool's drafts into scale requests. `config` is the
22
+ * settings the app registers, over {@link MEASUREMENT_DEFAULTS}.
23
+ */
24
+ declare const measurementPlugin: (config?: MeasurementConfig) => import("@embedpdf/core").PluginDef<MeasurementState, MeasurementCapability, MeasurementSettings>;
25
+ //#endregion
26
+ //#region src/state.d.ts
27
+ declare const measurementState: import("@embedpdf/core").StateDeclaration<MeasurementCapability, {
28
+ busy: boolean;
29
+ calibrationRequest: CalibrationRequest | null;
30
+ lastReports: readonly ScaleChangeReport[];
31
+ }>;
4
32
  //#endregion
5
- export { type AnnotationRef, type AreaUnit, type CalibrationRequest, type LengthUnit, type MeasurementAction, type MeasurementCapability, type MeasurementConfig, type MeasurementReadout, type MeasurementState, MeasurementToken, type MeasurementUnavailable, type PageScale, type PdfMeasure, type RecalibrationReport, type ScaleChangeReport, type ScalePreset, type SetScaleOptions, measurementPlugin };
33
+ export { type AnnotationRef, type AreaUnit, CalibrateInput, CalibrationCompletedEvent, CalibrationDismissedEvent, CalibrationRequest, CalibrationRequestedEvent, CreateMeasurementInput, type LengthUnit, MEASUREMENT_DEFAULTS, MeasurementCapability, MeasurementConfig, MeasurementKind, type MeasurementReadout, MeasurementScaleChangedEvent, MeasurementSettings, MeasurementToken, type MeasurementUnavailable, NO_PAGE_SCALE, NO_READOUT, PageScale, PageTarget, type PdfMeasure, type RecalibrationReport, ScaleChangeOptions, ScaleChangeReport, ScalePreset, measurementPlugin, measurementState };
6
34
  //# sourceMappingURL=index.d.ts.map