@platforma-sdk/model 1.75.5 → 1.75.10

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.
Files changed (37) hide show
  1. package/dist/block_model.cjs +3 -3
  2. package/dist/block_model.cjs.map +1 -1
  3. package/dist/block_model.d.ts +4 -5
  4. package/dist/block_model.d.ts.map +1 -1
  5. package/dist/block_model.js +3 -3
  6. package/dist/block_model.js.map +1 -1
  7. package/dist/block_model_legacy.cjs +2 -1
  8. package/dist/block_model_legacy.cjs.map +1 -1
  9. package/dist/block_model_legacy.js +2 -1
  10. package/dist/block_model_legacy.js.map +1 -1
  11. package/dist/index.d.ts +3 -3
  12. package/dist/labels/derive_distinct_labels.cjs +58 -23
  13. package/dist/labels/derive_distinct_labels.cjs.map +1 -1
  14. package/dist/labels/derive_distinct_labels.js +58 -23
  15. package/dist/labels/derive_distinct_labels.js.map +1 -1
  16. package/dist/package.cjs +1 -1
  17. package/dist/package.js +1 -1
  18. package/dist/platforma.d.ts +8 -5
  19. package/dist/platforma.d.ts.map +1 -1
  20. package/dist/plugin_handle.cjs.map +1 -1
  21. package/dist/plugin_handle.d.ts +1 -1
  22. package/dist/plugin_handle.js.map +1 -1
  23. package/dist/plugin_model.cjs +34 -37
  24. package/dist/plugin_model.cjs.map +1 -1
  25. package/dist/plugin_model.d.ts +55 -53
  26. package/dist/plugin_model.d.ts.map +1 -1
  27. package/dist/plugin_model.js +34 -37
  28. package/dist/plugin_model.js.map +1 -1
  29. package/package.json +8 -8
  30. package/src/block_model.ts +16 -5
  31. package/src/block_model_legacy.ts +1 -0
  32. package/src/index.ts +2 -0
  33. package/src/labels/derive_distinct_labels.test.ts +22 -0
  34. package/src/labels/derive_distinct_labels.ts +101 -31
  35. package/src/platforma.ts +11 -5
  36. package/src/plugin_handle.ts +1 -1
  37. package/src/plugin_model.ts +189 -76
@@ -1 +1 @@
1
- {"version":3,"file":"derive_distinct_labels.js","names":["isNil"],"sources":["../../src/labels/derive_distinct_labels.ts"],"sourcesContent":["import {\n Annotation,\n parseJson,\n readAnnotation,\n type AxisQualification,\n type PObjectId,\n type PObjectSpec,\n type StringifiedJson,\n type Trace,\n} from \"@milaboratories/pl-model-common\";\nimport { throwError } from \"@milaboratories/helpers\";\nimport { isFunction, isNil } from \"es-toolkit\";\nimport type { MatchQualifications } from \"../columns/column_collection_builder\";\n\nexport type { Trace, TraceEntry } from \"@milaboratories/pl-model-common\";\n\nconst DISTANCE_PENALTY = 0.001;\nconst LABEL_TYPE = \"__LABEL__\";\nconst LABEL_TYPE_FULL = \"__LABEL__@1\";\nconst LINKER_TYPE = \"__LINKER__\";\nconst LINKER_TYPE_FULL = \"__LINKER__@1\";\nconst HIT_QUAL_TYPE = \"__HIT_QUAL__\";\nconst ANCHOR_QUAL_TYPE_PREFIX = \"__ANCHOR_QUAL__:\";\n\nfunction isAnchorQualType(t: string): boolean {\n return t.startsWith(ANCHOR_QUAL_TYPE_PREFIX);\n}\n\nfunction isSyntheticType(t: string): boolean {\n return t === LINKER_TYPE || t === HIT_QUAL_TYPE || isAnchorQualType(t);\n}\n\n/** SDK-internal trace shape — adds fields used by this algorithm only, not part of the on-disk contract. */\ntype ExtendedTraceEntry = Trace[number] & {\n importance?: number;\n position?: \"prefix\" | \"suffix\";\n};\n\nexport type LinkerStep = {\n spec: PObjectSpec;\n qualifications?: AxisQualification[];\n};\n\nexport type Entry =\n | PObjectSpec\n | {\n spec: PObjectSpec;\n /** Extra trace entries merged with the base trace from annotations. */\n extraTrace?: ExtendedTraceEntry[];\n /** Linker steps traversed to discover this column; rendered as \"via …\" only when needed for uniqueness. */\n linkerPath?: LinkerStep[];\n /** Axis qualifications applied to the hit column / already-bound anchors; rendered as \"[…]\" suffixes. */\n qualifications?: MatchQualifications;\n };\n\n/**\n * Per-zone formatters. Each one receives raw inputs and returns the rendered text for that zone,\n * or `undefined` to suppress the zone entirely (no synthetic injection → no minimization, no render).\n */\nexport type DeriveLabelsFormatters = {\n /** Native column label. Default: identity. `undefined` → label entry not added (treated as if spec had no label). */\n native?: (label: string, spec: PObjectSpec, index: number) => string | undefined;\n /** Linker zone (whole \"via …\" piece). Receives step labels with step-quals already inlined.\n * Default: `via ${steps.join(\" > \")}`. */\n linker?: (linkerLabels: string[], spec: PObjectSpec, index: number) => string | undefined;\n /** Per-step linker qualifications inlined into the step base label.\n * Default: `[${formatQualifications(qs)}]`. `undefined` → step rendered without quals. */\n linkerStepQualification?: (\n qualifications: AxisQualification[],\n stepIndex: number,\n stepSpec: PObjectSpec,\n ) => string | undefined;\n /** Hit-axis qualifications block. Default: `[${formatQualifications(qs)}]`. */\n hitQualification?: (\n qualifications: AxisQualification[],\n spec: PObjectSpec,\n index: number,\n ) => string | undefined;\n /** Per-anchor qualifications block. Default: `[${anchorId}: ${formatQualifications(qs)}]`. */\n anchorQualification?: (\n anchorId: PObjectId,\n qualifications: AxisQualification[],\n spec: PObjectSpec,\n index: number,\n ) => string | undefined;\n};\n\nexport type DeriveLabelsOptions = {\n /** Separator to use between label parts (\" / \" by default). */\n separator?: string;\n /** If true, native label is appended at the end of the trace zone. By default it is prepended (label is the most important name). */\n addLabelAsSuffix?: boolean;\n /** Force inclusion of native column label even when not needed for uniqueness. */\n includeNativeLabel?: boolean;\n /** Trace types that must be included in the label. */\n forceTraceElements?: string[];\n /** Per-zone custom formatters. Returning `undefined` from any formatter suppresses the corresponding zone. */\n formatters?: DeriveLabelsFormatters;\n};\n\nexport function deriveDistinctLabels(values: Entry[], options: DeriveLabelsOptions = {}): string[] {\n const forceTraceElements =\n options.forceTraceElements !== undefined && options.forceTraceElements.length > 0\n ? new Set(options.forceTraceElements)\n : undefined;\n const separator = options.separator ?? \" / \";\n\n const records = values.map((v, i) => enrichRecord(v, i, options));\n const stats = collectTypeStats(records);\n\n const hasAnySynthetic = records.some((r) => r.fullTrace.some((ft) => isSyntheticType(ft.type)));\n const labelForced =\n (options.includeNativeLabel === true || hasAnySynthetic) &&\n stats.countByType.has(LABEL_TYPE_FULL);\n // Tied to labeled-step presence, not path presence: entries with a non-empty linkerPath\n // but no labeled steps contribute no LINKER_TYPE trace entry, so they do not count here.\n const linkerForced = stats.countByType.get(LINKER_TYPE_FULL) === values.length;\n\n const forcedSet = new Set<string>();\n if (labelForced) forcedSet.add(LABEL_TYPE_FULL);\n if (linkerForced) forcedSet.add(LINKER_TYPE_FULL);\n\n const { mainTypes, secondaryTypes } = classifyTypes(stats, values.length);\n\n const build = (typeSet: Set<string>, force: boolean) =>\n buildLabels(records, typeSet, forceTraceElements, separator, force);\n\n if (mainTypes.length === 0) {\n if (secondaryTypes.length !== 0)\n throw new Error(\"Non-empty secondary types list while main types list is empty.\");\n\n return (\n build(new Set([LABEL_TYPE_FULL]), true) ??\n throwError(\"Failed to derive labels using native column labels\")\n );\n }\n\n let includedCount = 0;\n let additionalType = -1;\n while (includedCount < mainTypes.length) {\n const currentSet = new Set<string>(forcedSet);\n for (let i = 0; i < includedCount; ++i) currentSet.add(mainTypes[i]);\n if (additionalType >= 0) currentSet.add(mainTypes[additionalType]);\n\n const candidateResult = build(currentSet, false);\n if (candidateResult !== undefined && countUniqueLabels(candidateResult) === values.length) {\n const minimized = minimizeTypeSet(\n currentSet,\n records,\n stats,\n forceTraceElements,\n forcedSet,\n separator,\n );\n return build(minimized, false) ?? throwError(\"Failed to derive unique labels\");\n }\n\n additionalType++;\n if (additionalType >= mainTypes.length) {\n includedCount++;\n additionalType = includedCount;\n }\n }\n\n const fallbackSet = new Set([...forcedSet, ...mainTypes, ...secondaryTypes]);\n const minimized = minimizeTypeSet(\n fallbackSet,\n records,\n stats,\n forceTraceElements,\n forcedSet,\n separator,\n );\n return build(minimized, true) ?? throwError(\"Failed to derive unique labels\");\n}\n\n// --- Pure helpers ---\ntype FullTraceEntry = ExtendedTraceEntry & { fullType: string; occurrenceIndex: number };\n\ntype EnrichedRecord = {\n fullTrace: FullTraceEntry[];\n};\n\nfunction extractEntryParts(entry: Entry): {\n spec: PObjectSpec;\n extraTrace: ExtendedTraceEntry[] | undefined;\n linkerPath: LinkerStep[] | undefined;\n qualifications: MatchQualifications | undefined;\n} {\n const isEnriched = \"spec\" in entry && typeof entry.spec === \"object\";\n if (!isEnriched) {\n return {\n spec: entry as PObjectSpec,\n extraTrace: undefined,\n linkerPath: undefined,\n qualifications: undefined,\n };\n }\n return {\n spec: entry.spec,\n extraTrace: entry.extraTrace,\n linkerPath: entry.linkerPath,\n qualifications: entry.qualifications,\n };\n}\n\nfunction formatQualification(q: AxisQualification): string {\n const ctx = q.contextDomain ?? {};\n const keys = Object.keys(ctx);\n if (keys.length === 0) return q.axis.name;\n const pairs = keys.map((k) => `${k}=${ctx[k]}`).join(\", \");\n return Object.prototype.hasOwnProperty.call(ctx, q.axis.name) ? pairs : `${q.axis.name} ${pairs}`;\n}\n\nfunction formatQualifications(qs: AxisQualification[]): string {\n return qs.map(formatQualification).join(\"; \");\n}\n\nfunction computeStepLabel(\n step: LinkerStep,\n stepIndex: number,\n formatters: DeriveLabelsFormatters | undefined,\n): string | undefined {\n const base = (\n readAnnotation(step.spec, Annotation.LinkLabel) ?? readAnnotation(step.spec, Annotation.Label)\n )?.trim();\n if (isNil(base) || base.length === 0) return undefined;\n if (step.qualifications === undefined || step.qualifications.length === 0) return base;\n const qualText = isFunction(formatters?.linkerStepQualification)\n ? formatters.linkerStepQualification(step.qualifications, stepIndex, step.spec)\n : `[${formatQualifications(step.qualifications)}]`;\n return isNil(qualText) ? base : `${base} ${qualText}`;\n}\n\nfunction buildFullTrace(trace: ExtendedTraceEntry[]): FullTraceEntry[] {\n const result: FullTraceEntry[] = [];\n const occurrences = new Map<string, number>();\n\n for (let i = trace.length - 1; i >= 0; --i) {\n const entry = trace[i];\n const occurrenceIndex = (occurrences.get(entry.type) ?? 0) + 1;\n occurrences.set(entry.type, occurrenceIndex);\n result.push({\n ...entry,\n fullType: `${entry.type}@${occurrenceIndex}`,\n occurrenceIndex,\n });\n }\n\n result.reverse();\n return result;\n}\n\nfunction enrichRecord(value: Entry, index: number, options: DeriveLabelsOptions): EnrichedRecord {\n const { spec, extraTrace, linkerPath, qualifications } = extractEntryParts(value);\n const formatters = options.formatters;\n\n const rawLabel = readAnnotation(spec, Annotation.Label);\n const traceStr = readAnnotation(spec, Annotation.Trace);\n const baseTrace = traceStr\n ? (parseJson(traceStr as StringifiedJson<ExtendedTraceEntry[]>) ?? [])\n : [];\n const prefixExtra = extraTrace?.filter((e) => e.position === \"prefix\") ?? [];\n const suffixExtra = extraTrace?.filter((e) => e.position !== \"prefix\") ?? [];\n const trace: ExtendedTraceEntry[] = [...prefixExtra, ...baseTrace, ...suffixExtra];\n\n if (!isNil(rawLabel)) {\n const label = isFunction(formatters?.native)\n ? formatters.native(rawLabel, spec, index)\n : rawLabel;\n if (!isNil(label)) {\n const labelEntry = { label, type: LABEL_TYPE, importance: -2 };\n if (options.addLabelAsSuffix === true) trace.push(labelEntry);\n else trace.splice(0, 0, labelEntry);\n }\n }\n\n if (linkerPath !== undefined && linkerPath.length > 0) {\n const stepLabels = linkerPath\n .map((step, i) => computeStepLabel(step, i, formatters))\n .filter((s): s is string => !isNil(s));\n if (stepLabels.length > 0) {\n const linkerText = isFunction(formatters?.linker)\n ? formatters.linker(stepLabels, spec, index)\n : `via ${stepLabels.join(\" > \")}`;\n if (!isNil(linkerText)) {\n trace.push({ type: LINKER_TYPE, label: linkerText, importance: -10 });\n }\n }\n }\n\n if (qualifications !== undefined && qualifications.forQueries !== undefined) {\n for (const [anchorId, qs] of Object.entries(qualifications.forQueries)) {\n if (qs.length === 0) continue;\n const anchorText = isFunction(formatters?.anchorQualification)\n ? formatters.anchorQualification(anchorId as PObjectId, qs, spec, index)\n : `[${anchorId}: ${formatQualifications(qs)}]`;\n if (isNil(anchorText)) continue;\n trace.push({\n type: `${ANCHOR_QUAL_TYPE_PREFIX}${anchorId}`,\n label: anchorText,\n importance: -11,\n });\n }\n if (qualifications.forHit !== undefined && qualifications.forHit.length > 0) {\n const hitText = isFunction(formatters?.hitQualification)\n ? formatters.hitQualification(qualifications.forHit, spec, index)\n : `[${formatQualifications(qualifications.forHit)}]`;\n if (!isNil(hitText)) {\n trace.push({ type: HIT_QUAL_TYPE, label: hitText, importance: -12 });\n }\n }\n }\n\n return { fullTrace: buildFullTrace(trace) };\n}\n\ntype TypeStats = {\n importances: Map<string, number>;\n countByType: Map<string, number>;\n};\n\nfunction collectTypeStats(records: EnrichedRecord[]): TypeStats {\n const importances = new Map<string, number>();\n const countByType = new Map<string, number>();\n\n for (const record of records) {\n for (let i = 0; i < record.fullTrace.length; i++) {\n const { fullType, importance: rawImportance } = record.fullTrace[i];\n const importance = rawImportance ?? 0;\n const distance = (record.fullTrace.length - i) * DISTANCE_PENALTY;\n\n countByType.set(fullType, (countByType.get(fullType) ?? 0) + 1);\n importances.set(\n fullType,\n Math.max(importances.get(fullType) ?? Number.NEGATIVE_INFINITY, importance - distance),\n );\n }\n }\n\n return { importances, countByType };\n}\n\nfunction classifyTypes(\n stats: TypeStats,\n totalRecords: number,\n): { mainTypes: string[]; secondaryTypes: string[] } {\n const sorted = [...stats.importances].sort(([, i1], [, i2]) => i2 - i1);\n\n const mainTypes: string[] = [];\n const secondaryTypes: string[] = [];\n\n for (const [typeName] of sorted) {\n if (typeName.endsWith(\"@1\") || stats.countByType.get(typeName) === totalRecords)\n mainTypes.push(typeName);\n else secondaryTypes.push(typeName);\n }\n\n return { mainTypes, secondaryTypes };\n}\n\nfunction buildLabels(\n records: EnrichedRecord[],\n includedTypes: Set<string>,\n forceTraceElements: Set<string> | undefined,\n separator: string,\n force: boolean,\n): string[] | undefined {\n const result: string[] = [];\n\n for (const r of records) {\n const traceParts: string[] = [];\n const anchorParts: string[] = [];\n let linkerLabel: string | undefined;\n let hitLabel: string | undefined;\n\n for (const ft of r.fullTrace) {\n if (!(includedTypes.has(ft.fullType) || forceTraceElements?.has(ft.type))) continue;\n if (ft.type === LINKER_TYPE) linkerLabel = ft.label;\n else if (ft.type === HIT_QUAL_TYPE) hitLabel = ft.label;\n else if (isAnchorQualType(ft.type)) anchorParts.push(ft.label);\n else traceParts.push(ft.label);\n }\n\n const isEmpty =\n traceParts.length === 0 &&\n anchorParts.length === 0 &&\n linkerLabel === undefined &&\n hitLabel === undefined;\n\n if (isEmpty) {\n if (!force) return undefined;\n result.push(\"Unlabeled\");\n continue;\n }\n\n let label = traceParts.join(separator);\n const append = (part: string) => {\n label = label.length === 0 ? part : `${label} ${part}`;\n };\n if (linkerLabel !== undefined) append(linkerLabel);\n for (const a of anchorParts) append(a);\n if (hitLabel !== undefined) append(hitLabel);\n\n result.push(label);\n }\n\n return result;\n}\n\nfunction countUniqueLabels(result: string[] | undefined): number {\n if (result === undefined) return 0;\n return new Set(result).size;\n}\n\nfunction minimizeTypeSet(\n typeSet: Set<string>,\n records: EnrichedRecord[],\n stats: TypeStats,\n forceTraceElements: Set<string> | undefined,\n forcedSet: Set<string>,\n separator: string,\n): Set<string> {\n const initialResult = buildLabels(records, typeSet, forceTraceElements, separator, false);\n if (initialResult === undefined) return typeSet;\n\n const targetCardinality = countUniqueLabels(initialResult);\n const result = new Set(typeSet);\n\n const removable = [...result]\n .filter((t) => !forceTraceElements?.has(t.split(\"@\")[0]) && !forcedSet.has(t))\n .sort((a, b) => (stats.importances.get(a) ?? 0) - (stats.importances.get(b) ?? 0));\n\n for (const typeToRemove of removable) {\n const candidate = new Set(result);\n candidate.delete(typeToRemove);\n const candidateResult = buildLabels(records, candidate, forceTraceElements, separator, false);\n if (candidateResult !== undefined && countUniqueLabels(candidateResult) >= targetCardinality) {\n result.delete(typeToRemove);\n }\n }\n\n return result;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"derive_distinct_labels.js","names":["isNil"],"sources":["../../src/labels/derive_distinct_labels.ts"],"sourcesContent":["import {\n Annotation,\n parseJson,\n readAnnotation,\n type AxisQualification,\n type PObjectId,\n type PObjectSpec,\n type StringifiedJson,\n type Trace,\n} from \"@milaboratories/pl-model-common\";\nimport { throwError } from \"@milaboratories/helpers\";\nimport { isFunction, isNil } from \"es-toolkit\";\nimport type { MatchQualifications } from \"../columns/column_collection_builder\";\n\nexport type { Trace, TraceEntry } from \"@milaboratories/pl-model-common\";\n\nconst DISTANCE_PENALTY = 0.001;\nconst LABEL_TYPE = \"__LABEL__\";\nconst LABEL_TYPE_FULL = \"__LABEL__@1\";\nconst LINKER_TYPE = \"__LINKER__\";\nconst LINKER_TYPE_FULL = \"__LINKER__@1\";\nconst HIT_QUAL_TYPE = \"__HIT_QUAL__\";\nconst ANCHOR_QUAL_TYPE_PREFIX = \"__ANCHOR_QUAL__:\";\n\nfunction isAnchorQualType(t: string): boolean {\n return t.startsWith(ANCHOR_QUAL_TYPE_PREFIX);\n}\n\nfunction isSyntheticType(t: string): boolean {\n return t === LINKER_TYPE || t === HIT_QUAL_TYPE || isAnchorQualType(t);\n}\n\n/** SDK-internal trace shape — adds fields used by this algorithm only, not part of the on-disk contract. */\ntype ExtendedTraceEntry = Trace[number] & {\n importance?: number;\n position?: \"prefix\" | \"suffix\";\n};\n\nexport type LinkerStep = {\n spec: PObjectSpec;\n qualifications?: AxisQualification[];\n};\n\nexport type Entry =\n | PObjectSpec\n | {\n spec: PObjectSpec;\n /** Extra trace entries merged with the base trace from annotations. */\n extraTrace?: ExtendedTraceEntry[];\n /** Linker steps traversed to discover this column; rendered as \"via …\" only when needed for uniqueness. */\n linkerPath?: LinkerStep[];\n /** Axis qualifications applied to the hit column / already-bound anchors; rendered as \"[…]\" suffixes. */\n qualifications?: MatchQualifications;\n };\n\n/**\n * Per-zone formatters. Each one receives raw inputs and returns the rendered text for that zone,\n * or `undefined` to suppress the zone entirely (no synthetic injection → no minimization, no render).\n */\nexport type DeriveLabelsFormatters = {\n /** Native column label. Default: identity. `undefined` → label entry not added (treated as if spec had no label). */\n native?: (label: string, spec: PObjectSpec, index: number) => string | undefined;\n /** Linker zone (whole \"via …\" piece). Receives step labels with step-quals already inlined.\n * Default: `via ${steps.join(\" > \")}`. */\n linker?: (linkerLabels: string[], spec: PObjectSpec, index: number) => string | undefined;\n /** Per-step linker qualifications inlined into the step base label.\n * Default: `[${formatQualifications(qs)}]`. `undefined` → step rendered without quals. */\n linkerStepQualification?: (\n qualifications: AxisQualification[],\n stepIndex: number,\n stepSpec: PObjectSpec,\n ) => string | undefined;\n /** Hit-axis qualifications block. Default: `[${formatQualifications(qs)}]`. */\n hitQualification?: (\n qualifications: AxisQualification[],\n spec: PObjectSpec,\n index: number,\n ) => string | undefined;\n /** Per-anchor qualifications block. Default: `[${anchorId}: ${formatQualifications(qs)}]`. */\n anchorQualification?: (\n anchorId: PObjectId,\n qualifications: AxisQualification[],\n spec: PObjectSpec,\n index: number,\n ) => string | undefined;\n};\n\nexport type DeriveLabelsOptions = {\n /** Separator to use between label parts (\" / \" by default). */\n separator?: string;\n /** If true, native label is appended at the end of the trace zone. By default it is prepended (label is the most important name). */\n addLabelAsSuffix?: boolean;\n /** Force inclusion of native column label even when not needed for uniqueness. */\n includeNativeLabel?: boolean;\n /** Trace types that must be included in the label. */\n forceTraceElements?: string[];\n /** Per-zone custom formatters. Returning `undefined` from any formatter suppresses the corresponding zone. */\n formatters?: DeriveLabelsFormatters;\n};\n\nexport function deriveDistinctLabels(values: Entry[], options: DeriveLabelsOptions = {}): string[] {\n const forceTraceElements =\n options.forceTraceElements !== undefined && options.forceTraceElements.length > 0\n ? new Set(options.forceTraceElements)\n : undefined;\n const separator = options.separator ?? \" / \";\n\n const records = values.map((v, i) => enrichRecord(v, i, options));\n const stats = collectTypeStats(records);\n\n const hasAnySynthetic = records.some((r) => r.fullTrace.some((ft) => isSyntheticType(ft.type)));\n const labelForced =\n (options.includeNativeLabel === true || hasAnySynthetic) &&\n stats.countByType.has(LABEL_TYPE_FULL);\n // Tied to labeled-step presence, not path presence: entries with a non-empty linkerPath\n // but no labeled steps contribute no LINKER_TYPE trace entry, so they do not count here.\n const linkerForced = stats.countByType.get(LINKER_TYPE_FULL) === values.length;\n\n const forcedSet = new Set<string>();\n if (labelForced) forcedSet.add(LABEL_TYPE_FULL);\n if (linkerForced) forcedSet.add(LINKER_TYPE_FULL);\n\n const { mainTypes, secondaryTypes } = classifyTypes(stats, values.length);\n\n const build = (typeSet: Set<string>, force: boolean) =>\n buildLabels(records, typeSet, forceTraceElements, separator, force);\n\n if (mainTypes.length === 0) {\n if (secondaryTypes.length !== 0)\n throw new Error(\"Non-empty secondary types list while main types list is empty.\");\n\n return (\n build(new Set([LABEL_TYPE_FULL]), true) ??\n throwError(\"Failed to derive labels using native column labels\")\n );\n }\n\n let includedCount = 0;\n let additionalType = -1;\n while (includedCount < mainTypes.length) {\n const currentSet = new Set<string>(forcedSet);\n for (let i = 0; i < includedCount; ++i) currentSet.add(mainTypes[i]);\n if (additionalType >= 0) currentSet.add(mainTypes[additionalType]);\n\n const candidateResult = build(currentSet, false);\n if (candidateResult !== undefined && countUniqueLabels(candidateResult) === values.length) {\n const minimized = minimizeTypeSet(\n currentSet,\n records,\n stats,\n forceTraceElements,\n forcedSet,\n separator,\n );\n const minimizedLabels =\n build(minimized, false) ?? throwError(\"Failed to derive unique labels\");\n return dropRedundantLinkerSuffix(\n records,\n minimized,\n forceTraceElements,\n forcedSet,\n separator,\n minimizedLabels,\n );\n }\n\n additionalType++;\n if (additionalType >= mainTypes.length) {\n includedCount++;\n additionalType = includedCount;\n }\n }\n\n const fallbackSet = new Set([...forcedSet, ...mainTypes, ...secondaryTypes]);\n const minimized = minimizeTypeSet(\n fallbackSet,\n records,\n stats,\n forceTraceElements,\n forcedSet,\n separator,\n );\n const minimizedLabels = build(minimized, true) ?? throwError(\"Failed to derive unique labels\");\n return dropRedundantLinkerSuffix(\n records,\n minimized,\n forceTraceElements,\n forcedSet,\n separator,\n minimizedLabels,\n );\n}\n\n// --- Pure helpers ---\ntype FullTraceEntry = ExtendedTraceEntry & { fullType: string; occurrenceIndex: number };\n\ntype EnrichedRecord = {\n fullTrace: FullTraceEntry[];\n};\n\nfunction extractEntryParts(entry: Entry): {\n spec: PObjectSpec;\n extraTrace: ExtendedTraceEntry[] | undefined;\n linkerPath: LinkerStep[] | undefined;\n qualifications: MatchQualifications | undefined;\n} {\n const isEnriched = \"spec\" in entry && typeof entry.spec === \"object\";\n if (!isEnriched) {\n return {\n spec: entry as PObjectSpec,\n extraTrace: undefined,\n linkerPath: undefined,\n qualifications: undefined,\n };\n }\n return {\n spec: entry.spec,\n extraTrace: entry.extraTrace,\n linkerPath: entry.linkerPath,\n qualifications: entry.qualifications,\n };\n}\n\nfunction formatQualification(q: AxisQualification): string {\n const ctx = q.contextDomain ?? {};\n const keys = Object.keys(ctx);\n if (keys.length === 0) return q.axis.name;\n const pairs = keys.map((k) => `${k}=${ctx[k]}`).join(\", \");\n return Object.prototype.hasOwnProperty.call(ctx, q.axis.name) ? pairs : `${q.axis.name} ${pairs}`;\n}\n\nfunction formatQualifications(qs: AxisQualification[]): string {\n return qs.map(formatQualification).join(\"; \");\n}\n\nfunction computeStepLabel(\n step: LinkerStep,\n stepIndex: number,\n formatters: DeriveLabelsFormatters | undefined,\n): string | undefined {\n const base = (\n readAnnotation(step.spec, Annotation.LinkLabel) ?? readAnnotation(step.spec, Annotation.Label)\n )?.trim();\n if (isNil(base) || base.length === 0) return undefined;\n if (step.qualifications === undefined || step.qualifications.length === 0) return base;\n const qualText = isFunction(formatters?.linkerStepQualification)\n ? formatters.linkerStepQualification(step.qualifications, stepIndex, step.spec)\n : `[${formatQualifications(step.qualifications)}]`;\n return isNil(qualText) ? base : `${base} ${qualText}`;\n}\n\nfunction buildFullTrace(trace: ExtendedTraceEntry[]): FullTraceEntry[] {\n const result: FullTraceEntry[] = [];\n const occurrences = new Map<string, number>();\n\n for (let i = trace.length - 1; i >= 0; --i) {\n const entry = trace[i];\n const occurrenceIndex = (occurrences.get(entry.type) ?? 0) + 1;\n occurrences.set(entry.type, occurrenceIndex);\n result.push({\n ...entry,\n fullType: `${entry.type}@${occurrenceIndex}`,\n occurrenceIndex,\n });\n }\n\n result.reverse();\n return result;\n}\n\nfunction enrichRecord(value: Entry, index: number, options: DeriveLabelsOptions): EnrichedRecord {\n const { spec, extraTrace, linkerPath, qualifications } = extractEntryParts(value);\n const formatters = options.formatters;\n\n const rawLabel = readAnnotation(spec, Annotation.Label);\n const traceStr = readAnnotation(spec, Annotation.Trace);\n const baseTrace = traceStr\n ? (parseJson(traceStr as StringifiedJson<ExtendedTraceEntry[]>) ?? [])\n : [];\n const prefixExtra = extraTrace?.filter((e) => e.position === \"prefix\") ?? [];\n const suffixExtra = extraTrace?.filter((e) => e.position !== \"prefix\") ?? [];\n const trace: ExtendedTraceEntry[] = [...prefixExtra, ...baseTrace, ...suffixExtra];\n\n if (!isNil(rawLabel)) {\n const label = isFunction(formatters?.native)\n ? formatters.native(rawLabel, spec, index)\n : rawLabel;\n if (!isNil(label)) {\n const labelEntry = { label, type: LABEL_TYPE, importance: -2 };\n if (options.addLabelAsSuffix === true) trace.push(labelEntry);\n else trace.splice(0, 0, labelEntry);\n }\n }\n\n if (linkerPath !== undefined && linkerPath.length > 0) {\n const stepLabels = linkerPath\n .map((step, i) => computeStepLabel(step, i, formatters))\n .filter((s): s is string => !isNil(s));\n if (stepLabels.length > 0) {\n const linkerText = isFunction(formatters?.linker)\n ? formatters.linker(stepLabels, spec, index)\n : `via ${stepLabels.join(\" > \")}`;\n if (!isNil(linkerText)) {\n trace.push({ type: LINKER_TYPE, label: linkerText, importance: -10 });\n }\n }\n }\n\n if (qualifications !== undefined && qualifications.forQueries !== undefined) {\n for (const [anchorId, qs] of Object.entries(qualifications.forQueries)) {\n if (qs.length === 0) continue;\n const anchorText = isFunction(formatters?.anchorQualification)\n ? formatters.anchorQualification(anchorId as PObjectId, qs, spec, index)\n : `[${anchorId}: ${formatQualifications(qs)}]`;\n if (isNil(anchorText)) continue;\n trace.push({\n type: `${ANCHOR_QUAL_TYPE_PREFIX}${anchorId}`,\n label: anchorText,\n importance: -11,\n });\n }\n if (qualifications.forHit !== undefined && qualifications.forHit.length > 0) {\n const hitText = isFunction(formatters?.hitQualification)\n ? formatters.hitQualification(qualifications.forHit, spec, index)\n : `[${formatQualifications(qualifications.forHit)}]`;\n if (!isNil(hitText)) {\n trace.push({ type: HIT_QUAL_TYPE, label: hitText, importance: -12 });\n }\n }\n }\n\n return { fullTrace: buildFullTrace(trace) };\n}\n\ntype TypeStats = {\n importances: Map<string, number>;\n countByType: Map<string, number>;\n};\n\nfunction collectTypeStats(records: EnrichedRecord[]): TypeStats {\n const importances = new Map<string, number>();\n const countByType = new Map<string, number>();\n\n for (const record of records) {\n for (let i = 0; i < record.fullTrace.length; i++) {\n const { fullType, importance: rawImportance } = record.fullTrace[i];\n const importance = rawImportance ?? 0;\n const distance = (record.fullTrace.length - i) * DISTANCE_PENALTY;\n\n countByType.set(fullType, (countByType.get(fullType) ?? 0) + 1);\n importances.set(\n fullType,\n Math.max(importances.get(fullType) ?? Number.NEGATIVE_INFINITY, importance - distance),\n );\n }\n }\n\n return { importances, countByType };\n}\n\nfunction classifyTypes(\n stats: TypeStats,\n totalRecords: number,\n): { mainTypes: string[]; secondaryTypes: string[] } {\n const sorted = [...stats.importances].sort(([, i1], [, i2]) => i2 - i1);\n\n const mainTypes: string[] = [];\n const secondaryTypes: string[] = [];\n\n for (const [typeName] of sorted) {\n if (typeName.endsWith(\"@1\") || stats.countByType.get(typeName) === totalRecords)\n mainTypes.push(typeName);\n else secondaryTypes.push(typeName);\n }\n\n return { mainTypes, secondaryTypes };\n}\n\nfunction renderRecordLabel(\n record: EnrichedRecord,\n includedTypes: Set<string>,\n forceTraceElements: Set<string> | undefined,\n separator: string,\n): string | undefined {\n const traceParts: string[] = [];\n const anchorParts: string[] = [];\n let linkerLabel: string | undefined;\n let hitLabel: string | undefined;\n\n for (const ft of record.fullTrace) {\n if (!(includedTypes.has(ft.fullType) || forceTraceElements?.has(ft.type))) continue;\n if (ft.type === LINKER_TYPE) linkerLabel = ft.label;\n else if (ft.type === HIT_QUAL_TYPE) hitLabel = ft.label;\n else if (isAnchorQualType(ft.type)) anchorParts.push(ft.label);\n else traceParts.push(ft.label);\n }\n\n const isEmpty =\n traceParts.length === 0 &&\n anchorParts.length === 0 &&\n linkerLabel === undefined &&\n hitLabel === undefined;\n\n if (isEmpty) return undefined;\n\n let label = traceParts.join(separator);\n const append = (part: string) => {\n label = label.length === 0 ? part : `${label} ${part}`;\n };\n if (linkerLabel !== undefined) append(linkerLabel);\n for (const a of anchorParts) append(a);\n if (hitLabel !== undefined) append(hitLabel);\n\n return label;\n}\n\nfunction buildLabels(\n records: EnrichedRecord[],\n includedTypes: Set<string>,\n forceTraceElements: Set<string> | undefined,\n separator: string,\n force: boolean,\n): string[] | undefined {\n const result: string[] = [];\n\n for (const r of records) {\n const rendered = renderRecordLabel(r, includedTypes, forceTraceElements, separator);\n if (rendered === undefined) {\n if (!force) return undefined;\n result.push(\"Unlabeled\");\n continue;\n }\n result.push(rendered);\n }\n\n return result;\n}\n\n/**\n * Drop the \"via …\" linker suffix from records whose label is already unique without it.\n *\n * Global minimization may include `LINKER_TYPE_FULL` solely to resolve a collision between a\n * subset of records — but `buildLabels` then renders the suffix on every record that carries a\n * linker trace entry, including ones whose stem is already unique. We strip the suffix where it\n * isn't load-bearing while keeping the symmetric rendering required by `linkerForced` /\n * `forceTraceElements`.\n *\n * Rule: a record's linker suffix is redundant iff its stem (label rendered without LINKER) does\n * not appear anywhere else in the set.\n */\nfunction dropRedundantLinkerSuffix(\n records: EnrichedRecord[],\n globalTypeSet: Set<string>,\n forceTraceElements: Set<string> | undefined,\n forcedSet: Set<string>,\n separator: string,\n labels: string[],\n): string[] {\n if (!globalTypeSet.has(LINKER_TYPE_FULL)) return labels;\n if (forcedSet.has(LINKER_TYPE_FULL) || forceTraceElements?.has(LINKER_TYPE)) return labels;\n\n const setWithoutLinker = new Set(globalTypeSet);\n setWithoutLinker.delete(LINKER_TYPE_FULL);\n\n const stems = records.map((r) =>\n renderRecordLabel(r, setWithoutLinker, forceTraceElements, separator),\n );\n\n const stemOccurrences = new Map<string, number>();\n for (const s of stems) {\n if (s !== undefined) stemOccurrences.set(s, (stemOccurrences.get(s) ?? 0) + 1);\n }\n\n return labels.map((label, i) => {\n const stem = stems[i];\n if (stem === undefined) return label;\n return stemOccurrences.get(stem) === 1 ? stem : label;\n });\n}\n\nfunction countUniqueLabels(result: string[] | undefined): number {\n if (result === undefined) return 0;\n return new Set(result).size;\n}\n\nfunction minimizeTypeSet(\n typeSet: Set<string>,\n records: EnrichedRecord[],\n stats: TypeStats,\n forceTraceElements: Set<string> | undefined,\n forcedSet: Set<string>,\n separator: string,\n): Set<string> {\n const initialResult = buildLabels(records, typeSet, forceTraceElements, separator, false);\n if (initialResult === undefined) return typeSet;\n\n const targetCardinality = countUniqueLabels(initialResult);\n const result = new Set(typeSet);\n\n const removable = [...result]\n .filter((t) => !forceTraceElements?.has(t.split(\"@\")[0]) && !forcedSet.has(t))\n .sort((a, b) => (stats.importances.get(a) ?? 0) - (stats.importances.get(b) ?? 0));\n\n for (const typeToRemove of removable) {\n const candidate = new Set(result);\n candidate.delete(typeToRemove);\n const candidateResult = buildLabels(records, candidate, forceTraceElements, separator, false);\n if (candidateResult !== undefined && countUniqueLabels(candidateResult) >= targetCardinality) {\n result.delete(typeToRemove);\n }\n }\n\n return result;\n}\n"],"mappings":";;;;AAgBA,MAAM,mBAAmB;AACzB,MAAM,aAAa;AACnB,MAAM,kBAAkB;AACxB,MAAM,cAAc;AACpB,MAAM,mBAAmB;AACzB,MAAM,gBAAgB;AACtB,MAAM,0BAA0B;AAEhC,SAAS,iBAAiB,GAAoB;AAC5C,QAAO,EAAE,WAAW,wBAAwB;;AAG9C,SAAS,gBAAgB,GAAoB;AAC3C,QAAO,MAAM,eAAe,MAAM,iBAAiB,iBAAiB,EAAE;;AAuExE,SAAgB,qBAAqB,QAAiB,UAA+B,EAAE,EAAY;CACjG,MAAM,qBACJ,QAAQ,uBAAuB,KAAA,KAAa,QAAQ,mBAAmB,SAAS,IAC5E,IAAI,IAAI,QAAQ,mBAAmB,GACnC,KAAA;CACN,MAAM,YAAY,QAAQ,aAAa;CAEvC,MAAM,UAAU,OAAO,KAAK,GAAG,MAAM,aAAa,GAAG,GAAG,QAAQ,CAAC;CACjE,MAAM,QAAQ,iBAAiB,QAAQ;CAEvC,MAAM,kBAAkB,QAAQ,MAAM,MAAM,EAAE,UAAU,MAAM,OAAO,gBAAgB,GAAG,KAAK,CAAC,CAAC;CAC/F,MAAM,eACH,QAAQ,uBAAuB,QAAQ,oBACxC,MAAM,YAAY,IAAI,gBAAgB;CAGxC,MAAM,eAAe,MAAM,YAAY,IAAI,iBAAiB,KAAK,OAAO;CAExE,MAAM,4BAAY,IAAI,KAAa;AACnC,KAAI,YAAa,WAAU,IAAI,gBAAgB;AAC/C,KAAI,aAAc,WAAU,IAAI,iBAAiB;CAEjD,MAAM,EAAE,WAAW,mBAAmB,cAAc,OAAO,OAAO,OAAO;CAEzE,MAAM,SAAS,SAAsB,UACnC,YAAY,SAAS,SAAS,oBAAoB,WAAW,MAAM;AAErE,KAAI,UAAU,WAAW,GAAG;AAC1B,MAAI,eAAe,WAAW,EAC5B,OAAM,IAAI,MAAM,iEAAiE;AAEnF,SACE,MAAM,IAAI,IAAI,CAAC,gBAAgB,CAAC,EAAE,KAAK,IACvC,WAAW,qDAAqD;;CAIpE,IAAI,gBAAgB;CACpB,IAAI,iBAAiB;AACrB,QAAO,gBAAgB,UAAU,QAAQ;EACvC,MAAM,aAAa,IAAI,IAAY,UAAU;AAC7C,OAAK,IAAI,IAAI,GAAG,IAAI,eAAe,EAAE,EAAG,YAAW,IAAI,UAAU,GAAG;AACpE,MAAI,kBAAkB,EAAG,YAAW,IAAI,UAAU,gBAAgB;EAElE,MAAM,kBAAkB,MAAM,YAAY,MAAM;AAChD,MAAI,oBAAoB,KAAA,KAAa,kBAAkB,gBAAgB,KAAK,OAAO,QAAQ;GACzF,MAAM,YAAY,gBAChB,YACA,SACA,OACA,oBACA,WACA,UACD;AAGD,UAAO,0BACL,SACA,WACA,oBACA,WACA,WANA,MAAM,WAAW,MAAM,IAAI,WAAW,iCAAiC,CAQxE;;AAGH;AACA,MAAI,kBAAkB,UAAU,QAAQ;AACtC;AACA,oBAAiB;;;CAKrB,MAAM,YAAY,gBADE,IAAI,IAAI;EAAC,GAAG;EAAW,GAAG;EAAW,GAAG;EAAe,CAAC,EAG1E,SACA,OACA,oBACA,WACA,UACD;AAED,QAAO,0BACL,SACA,WACA,oBACA,WACA,WANsB,MAAM,WAAW,KAAK,IAAI,WAAW,iCAAiC,CAQ7F;;AAUH,SAAS,kBAAkB,OAKzB;AAEA,KAAI,EADe,UAAU,SAAS,OAAO,MAAM,SAAS,UAE1D,QAAO;EACL,MAAM;EACN,YAAY,KAAA;EACZ,YAAY,KAAA;EACZ,gBAAgB,KAAA;EACjB;AAEH,QAAO;EACL,MAAM,MAAM;EACZ,YAAY,MAAM;EAClB,YAAY,MAAM;EAClB,gBAAgB,MAAM;EACvB;;AAGH,SAAS,oBAAoB,GAA8B;CACzD,MAAM,MAAM,EAAE,iBAAiB,EAAE;CACjC,MAAM,OAAO,OAAO,KAAK,IAAI;AAC7B,KAAI,KAAK,WAAW,EAAG,QAAO,EAAE,KAAK;CACrC,MAAM,QAAQ,KAAK,KAAK,MAAM,GAAG,EAAE,GAAG,IAAI,KAAK,CAAC,KAAK,KAAK;AAC1D,QAAO,OAAO,UAAU,eAAe,KAAK,KAAK,EAAE,KAAK,KAAK,GAAG,QAAQ,GAAG,EAAE,KAAK,KAAK,GAAG;;AAG5F,SAAS,qBAAqB,IAAiC;AAC7D,QAAO,GAAG,IAAI,oBAAoB,CAAC,KAAK,KAAK;;AAG/C,SAAS,iBACP,MACA,WACA,YACoB;CACpB,MAAM,QACJ,eAAe,KAAK,MAAM,WAAW,UAAU,IAAI,eAAe,KAAK,MAAM,WAAW,MAAM,GAC7F,MAAM;AACT,KAAIA,QAAM,KAAK,IAAI,KAAK,WAAW,EAAG,QAAO,KAAA;AAC7C,KAAI,KAAK,mBAAmB,KAAA,KAAa,KAAK,eAAe,WAAW,EAAG,QAAO;CAClF,MAAM,WAAW,WAAW,YAAY,wBAAwB,GAC5D,WAAW,wBAAwB,KAAK,gBAAgB,WAAW,KAAK,KAAK,GAC7E,IAAI,qBAAqB,KAAK,eAAe,CAAC;AAClD,QAAOA,QAAM,SAAS,GAAG,OAAO,GAAG,KAAK,GAAG;;AAG7C,SAAS,eAAe,OAA+C;CACrE,MAAM,SAA2B,EAAE;CACnC,MAAM,8BAAc,IAAI,KAAqB;AAE7C,MAAK,IAAI,IAAI,MAAM,SAAS,GAAG,KAAK,GAAG,EAAE,GAAG;EAC1C,MAAM,QAAQ,MAAM;EACpB,MAAM,mBAAmB,YAAY,IAAI,MAAM,KAAK,IAAI,KAAK;AAC7D,cAAY,IAAI,MAAM,MAAM,gBAAgB;AAC5C,SAAO,KAAK;GACV,GAAG;GACH,UAAU,GAAG,MAAM,KAAK,GAAG;GAC3B;GACD,CAAC;;AAGJ,QAAO,SAAS;AAChB,QAAO;;AAGT,SAAS,aAAa,OAAc,OAAe,SAA8C;CAC/F,MAAM,EAAE,MAAM,YAAY,YAAY,mBAAmB,kBAAkB,MAAM;CACjF,MAAM,aAAa,QAAQ;CAE3B,MAAM,WAAW,eAAe,MAAM,WAAW,MAAM;CACvD,MAAM,WAAW,eAAe,MAAM,WAAW,MAAM;CACvD,MAAM,YAAY,WACb,UAAU,SAAkD,IAAI,EAAE,GACnE,EAAE;CACN,MAAM,cAAc,YAAY,QAAQ,MAAM,EAAE,aAAa,SAAS,IAAI,EAAE;CAC5E,MAAM,cAAc,YAAY,QAAQ,MAAM,EAAE,aAAa,SAAS,IAAI,EAAE;CAC5E,MAAM,QAA8B;EAAC,GAAG;EAAa,GAAG;EAAW,GAAG;EAAY;AAElF,KAAI,CAACA,QAAM,SAAS,EAAE;EACpB,MAAM,QAAQ,WAAW,YAAY,OAAO,GACxC,WAAW,OAAO,UAAU,MAAM,MAAM,GACxC;AACJ,MAAI,CAACA,QAAM,MAAM,EAAE;GACjB,MAAM,aAAa;IAAE;IAAO,MAAM;IAAY,YAAY;IAAI;AAC9D,OAAI,QAAQ,qBAAqB,KAAM,OAAM,KAAK,WAAW;OACxD,OAAM,OAAO,GAAG,GAAG,WAAW;;;AAIvC,KAAI,eAAe,KAAA,KAAa,WAAW,SAAS,GAAG;EACrD,MAAM,aAAa,WAChB,KAAK,MAAM,MAAM,iBAAiB,MAAM,GAAG,WAAW,CAAC,CACvD,QAAQ,MAAmB,CAACA,QAAM,EAAE,CAAC;AACxC,MAAI,WAAW,SAAS,GAAG;GACzB,MAAM,aAAa,WAAW,YAAY,OAAO,GAC7C,WAAW,OAAO,YAAY,MAAM,MAAM,GAC1C,OAAO,WAAW,KAAK,MAAM;AACjC,OAAI,CAACA,QAAM,WAAW,CACpB,OAAM,KAAK;IAAE,MAAM;IAAa,OAAO;IAAY,YAAY;IAAK,CAAC;;;AAK3E,KAAI,mBAAmB,KAAA,KAAa,eAAe,eAAe,KAAA,GAAW;AAC3E,OAAK,MAAM,CAAC,UAAU,OAAO,OAAO,QAAQ,eAAe,WAAW,EAAE;AACtE,OAAI,GAAG,WAAW,EAAG;GACrB,MAAM,aAAa,WAAW,YAAY,oBAAoB,GAC1D,WAAW,oBAAoB,UAAuB,IAAI,MAAM,MAAM,GACtE,IAAI,SAAS,IAAI,qBAAqB,GAAG,CAAC;AAC9C,OAAIA,QAAM,WAAW,CAAE;AACvB,SAAM,KAAK;IACT,MAAM,GAAG,0BAA0B;IACnC,OAAO;IACP,YAAY;IACb,CAAC;;AAEJ,MAAI,eAAe,WAAW,KAAA,KAAa,eAAe,OAAO,SAAS,GAAG;GAC3E,MAAM,UAAU,WAAW,YAAY,iBAAiB,GACpD,WAAW,iBAAiB,eAAe,QAAQ,MAAM,MAAM,GAC/D,IAAI,qBAAqB,eAAe,OAAO,CAAC;AACpD,OAAI,CAACA,QAAM,QAAQ,CACjB,OAAM,KAAK;IAAE,MAAM;IAAe,OAAO;IAAS,YAAY;IAAK,CAAC;;;AAK1E,QAAO,EAAE,WAAW,eAAe,MAAM,EAAE;;AAQ7C,SAAS,iBAAiB,SAAsC;CAC9D,MAAM,8BAAc,IAAI,KAAqB;CAC7C,MAAM,8BAAc,IAAI,KAAqB;AAE7C,MAAK,MAAM,UAAU,QACnB,MAAK,IAAI,IAAI,GAAG,IAAI,OAAO,UAAU,QAAQ,KAAK;EAChD,MAAM,EAAE,UAAU,YAAY,kBAAkB,OAAO,UAAU;EACjE,MAAM,aAAa,iBAAiB;EACpC,MAAM,YAAY,OAAO,UAAU,SAAS,KAAK;AAEjD,cAAY,IAAI,WAAW,YAAY,IAAI,SAAS,IAAI,KAAK,EAAE;AAC/D,cAAY,IACV,UACA,KAAK,IAAI,YAAY,IAAI,SAAS,IAAI,OAAO,mBAAmB,aAAa,SAAS,CACvF;;AAIL,QAAO;EAAE;EAAa;EAAa;;AAGrC,SAAS,cACP,OACA,cACmD;CACnD,MAAM,SAAS,CAAC,GAAG,MAAM,YAAY,CAAC,MAAM,GAAG,KAAK,GAAG,QAAQ,KAAK,GAAG;CAEvE,MAAM,YAAsB,EAAE;CAC9B,MAAM,iBAA2B,EAAE;AAEnC,MAAK,MAAM,CAAC,aAAa,OACvB,KAAI,SAAS,SAAS,KAAK,IAAI,MAAM,YAAY,IAAI,SAAS,KAAK,aACjE,WAAU,KAAK,SAAS;KACrB,gBAAe,KAAK,SAAS;AAGpC,QAAO;EAAE;EAAW;EAAgB;;AAGtC,SAAS,kBACP,QACA,eACA,oBACA,WACoB;CACpB,MAAM,aAAuB,EAAE;CAC/B,MAAM,cAAwB,EAAE;CAChC,IAAI;CACJ,IAAI;AAEJ,MAAK,MAAM,MAAM,OAAO,WAAW;AACjC,MAAI,EAAE,cAAc,IAAI,GAAG,SAAS,IAAI,oBAAoB,IAAI,GAAG,KAAK,EAAG;AAC3E,MAAI,GAAG,SAAS,YAAa,eAAc,GAAG;WACrC,GAAG,SAAS,cAAe,YAAW,GAAG;WACzC,iBAAiB,GAAG,KAAK,CAAE,aAAY,KAAK,GAAG,MAAM;MACzD,YAAW,KAAK,GAAG,MAAM;;AAShC,KALE,WAAW,WAAW,KACtB,YAAY,WAAW,KACvB,gBAAgB,KAAA,KAChB,aAAa,KAAA,EAEF,QAAO,KAAA;CAEpB,IAAI,QAAQ,WAAW,KAAK,UAAU;CACtC,MAAM,UAAU,SAAiB;AAC/B,UAAQ,MAAM,WAAW,IAAI,OAAO,GAAG,MAAM,GAAG;;AAElD,KAAI,gBAAgB,KAAA,EAAW,QAAO,YAAY;AAClD,MAAK,MAAM,KAAK,YAAa,QAAO,EAAE;AACtC,KAAI,aAAa,KAAA,EAAW,QAAO,SAAS;AAE5C,QAAO;;AAGT,SAAS,YACP,SACA,eACA,oBACA,WACA,OACsB;CACtB,MAAM,SAAmB,EAAE;AAE3B,MAAK,MAAM,KAAK,SAAS;EACvB,MAAM,WAAW,kBAAkB,GAAG,eAAe,oBAAoB,UAAU;AACnF,MAAI,aAAa,KAAA,GAAW;AAC1B,OAAI,CAAC,MAAO,QAAO,KAAA;AACnB,UAAO,KAAK,YAAY;AACxB;;AAEF,SAAO,KAAK,SAAS;;AAGvB,QAAO;;;;;;;;;;;;;;AAeT,SAAS,0BACP,SACA,eACA,oBACA,WACA,WACA,QACU;AACV,KAAI,CAAC,cAAc,IAAI,iBAAiB,CAAE,QAAO;AACjD,KAAI,UAAU,IAAI,iBAAiB,IAAI,oBAAoB,IAAI,YAAY,CAAE,QAAO;CAEpF,MAAM,mBAAmB,IAAI,IAAI,cAAc;AAC/C,kBAAiB,OAAO,iBAAiB;CAEzC,MAAM,QAAQ,QAAQ,KAAK,MACzB,kBAAkB,GAAG,kBAAkB,oBAAoB,UAAU,CACtE;CAED,MAAM,kCAAkB,IAAI,KAAqB;AACjD,MAAK,MAAM,KAAK,MACd,KAAI,MAAM,KAAA,EAAW,iBAAgB,IAAI,IAAI,gBAAgB,IAAI,EAAE,IAAI,KAAK,EAAE;AAGhF,QAAO,OAAO,KAAK,OAAO,MAAM;EAC9B,MAAM,OAAO,MAAM;AACnB,MAAI,SAAS,KAAA,EAAW,QAAO;AAC/B,SAAO,gBAAgB,IAAI,KAAK,KAAK,IAAI,OAAO;GAChD;;AAGJ,SAAS,kBAAkB,QAAsC;AAC/D,KAAI,WAAW,KAAA,EAAW,QAAO;AACjC,QAAO,IAAI,IAAI,OAAO,CAAC;;AAGzB,SAAS,gBACP,SACA,SACA,OACA,oBACA,WACA,WACa;CACb,MAAM,gBAAgB,YAAY,SAAS,SAAS,oBAAoB,WAAW,MAAM;AACzF,KAAI,kBAAkB,KAAA,EAAW,QAAO;CAExC,MAAM,oBAAoB,kBAAkB,cAAc;CAC1D,MAAM,SAAS,IAAI,IAAI,QAAQ;CAE/B,MAAM,YAAY,CAAC,GAAG,OAAO,CAC1B,QAAQ,MAAM,CAAC,oBAAoB,IAAI,EAAE,MAAM,IAAI,CAAC,GAAG,IAAI,CAAC,UAAU,IAAI,EAAE,CAAC,CAC7E,MAAM,GAAG,OAAO,MAAM,YAAY,IAAI,EAAE,IAAI,MAAM,MAAM,YAAY,IAAI,EAAE,IAAI,GAAG;AAEpF,MAAK,MAAM,gBAAgB,WAAW;EACpC,MAAM,YAAY,IAAI,IAAI,OAAO;AACjC,YAAU,OAAO,aAAa;EAC9B,MAAM,kBAAkB,YAAY,SAAS,WAAW,oBAAoB,WAAW,MAAM;AAC7F,MAAI,oBAAoB,KAAA,KAAa,kBAAkB,gBAAgB,IAAI,kBACzE,QAAO,OAAO,aAAa;;AAI/B,QAAO"}
package/dist/package.cjs CHANGED
@@ -1,5 +1,5 @@
1
1
  //#region package.json
2
- var version = "1.75.5";
2
+ var version = "1.75.10";
3
3
  //#endregion
4
4
  Object.defineProperty(exports, "version", {
5
5
  enumerable: true,
package/dist/package.js CHANGED
@@ -1,5 +1,5 @@
1
1
  //#region package.json
2
- var version = "1.75.5";
2
+ var version = "1.75.10";
3
3
  //#endregion
4
4
  export { version };
5
5
 
@@ -4,6 +4,7 @@ import { BlockApiV1 } from "./block_api_v1.js";
4
4
  import { BlockApiV2 } from "./block_api_v2.js";
5
5
  import { BlockApiV3 } from "./block_api_v3.js";
6
6
  import { SdkInfo } from "./version.js";
7
+ import { PublicOutputFieldDef } from "./plugin_model.js";
7
8
  import { PluginRecord } from "./block_model.js";
8
9
  import { BlockCodeKnownFeatureFlags, BlockOutputsBase, BlockStateV3, DriverKit, OutputWithStatus, ServiceDispatch, UiServices as UiServices$1 } from "@milaboratories/pl-model-common";
9
10
 
@@ -41,6 +42,7 @@ type BlockModelInfo = {
41
42
  }>;
42
43
  pluginIds: PluginHandle[];
43
44
  featureFlags: BlockCodeKnownFeatureFlags;
45
+ pluginPublicOutputs: Record<string, Record<string, PublicOutputFieldDef>>;
44
46
  };
45
47
  type PlatformaApiVersion = Platforma["apiVersion"];
46
48
  type InferArgsType<Pl extends Platforma> = Pl extends Platforma<infer Args> ? Args : never;
@@ -58,13 +60,14 @@ type InferPluginNames<Pl> = Pl extends PlatformaV3<unknown, unknown, BlockOutput
58
60
  /** Extract the Data type for a specific plugin by its ID. */
59
61
  type InferPluginData<Pl, PluginId extends string> = Pl extends PlatformaV3<unknown, unknown, BlockOutputsBase, `/${string}`, infer P> ? PluginId extends keyof P ? P[PluginId] extends PluginRecord<infer D, any, any> ? D : never : never : never;
60
62
  /**
61
- * Map each plugin instance to a type-safe opaque handle branded with normalized phantom.
62
- * Uses the same brand structure as InferPluginHandle only data/params/outputs, no config
63
- * because PluginRecord doesn't carry Config (lost after factory.create()).
63
+ * Derives the UI-facing entry map for a plugin registry.
64
+ * For each plugin instance, produces a typed handle and its public outputs
65
+ * the subset of plugin state accessible to block UI without usePlugin().
64
66
  */
65
- type InferPluginHandles<T extends Record<string, unknown>> = { readonly [K in keyof T]: T[K] extends PluginRecord<infer Data, infer Params, infer Outputs, infer ModelServices, infer UiServices> ? {
67
+ type InferPluginUiEntries<T extends Record<string, unknown>> = { readonly [K in keyof T]: T[K] extends PluginRecord<infer Data, infer Params, infer Outputs, infer PublicOutputs, infer ModelServices, infer UiServices> ? {
66
68
  handle: PluginHandle<PluginFactoryLike<Data, Params, Outputs, ModelServices, UiServices>>;
69
+ publicOutputs: PublicOutputs;
67
70
  } : never };
68
71
  //#endregion
69
- export { BlockModelInfo, InferArgsType, InferBlockState, InferBlockStatePatch, InferDataType, InferHrefType, InferOutputsType, InferPluginData, InferPluginHandles, InferPluginNames, InferUiState, Platforma, PlatformaApiVersion, PlatformaExtended, PlatformaFactory, PlatformaV1, PlatformaV2, PlatformaV3 };
72
+ export { BlockModelInfo, InferArgsType, InferBlockState, InferBlockStatePatch, InferDataType, InferHrefType, InferOutputsType, InferPluginData, InferPluginNames, InferPluginUiEntries, InferUiState, Platforma, PlatformaApiVersion, PlatformaExtended, PlatformaFactory, PlatformaV1, PlatformaV2, PlatformaV3 };
70
73
  //# sourceMappingURL=platforma.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"platforma.d.ts","names":[],"sources":["../src/platforma.ts"],"mappings":"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"}
1
+ {"version":3,"file":"platforma.d.ts","names":[],"sources":["../src/platforma.ts"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"plugin_handle.cjs","names":[],"sources":["../src/plugin_handle.ts"],"sourcesContent":["/**\n * PluginHandle — Opaque branded handle and output key utilities for plugin instances.\n *\n * Extracted into its own module to break circular dependencies:\n * both block_storage.ts and plugin_model.ts can import from here\n * without depending on each other.\n *\n * @module plugin_handle\n */\n\nimport type { Branded } from \"@milaboratories/helpers\";\n\n/**\n * Phantom-only base type for constraining PluginHandle's type parameter.\n *\n * PluginFactory has create() → PluginInstance with function properties, making it invariant\n * under strictFunctionTypes. PluginFactoryLike exposes only the covariant `__types` phantom,\n * avoiding the contravariance chain. Handles only need `__types` for type extraction.\n *\n * PluginFactory extends PluginFactoryLike, so every concrete factory satisfies this constraint.\n */\nexport interface PluginFactoryLike<\n Data extends Record<string, unknown> = Record<string, unknown>,\n Params extends undefined | Record<string, unknown> = undefined | Record<string, unknown>,\n Outputs extends Record<string, unknown> = Record<string, unknown>,\n ModelServices = unknown,\n UiServices = unknown,\n> {\n readonly __types?: {\n data: Data;\n params: Params;\n outputs: Outputs;\n modelServices: ModelServices;\n uiServices: UiServices;\n };\n}\n\n/** Extract the Data type from a PluginFactoryLike phantom. */\nexport type InferFactoryData<F extends PluginFactoryLike> = NonNullable<\n F extends PluginFactoryLike<infer D, any, any, any, any> ? D : Record<string, unknown>\n>;\n\n/** Extract the Params type from a PluginFactoryLike phantom. */\nexport type InferFactoryParams<F extends PluginFactoryLike> = NonNullable<\n F extends PluginFactoryLike<any, infer P, any, any, any> ? P : undefined\n>;\n\n/** Extract the Outputs type from a PluginFactoryLike phantom. */\nexport type InferFactoryOutputs<F extends PluginFactoryLike> = NonNullable<\n F extends PluginFactoryLike<any, any, infer O, any, any> ? O : Record<string, unknown>\n>;\n\n/** Extract the pre-resolved model services type from a PluginFactoryLike phantom. */\nexport type InferFactoryModelServices<F extends PluginFactoryLike> =\n F extends PluginFactoryLike<any, any, any, infer ModelServices, any> ? ModelServices : {};\n\n/** Extract the pre-resolved UI services type from a PluginFactoryLike phantom. */\nexport type InferFactoryUiServices<F extends PluginFactoryLike> =\n F extends PluginFactoryLike<any, any, any, any, infer UiServices> ? UiServices : {};\n\n/**\n * Derive a typed PluginHandle from a PluginFactory type.\n * Normalizes the brand to data/params/outputs/services (strips config) so handles\n * from InferPluginHandles match handles from InferPluginHandle.\n */\nexport type InferPluginHandle<F extends PluginFactoryLike> = NonNullable<\n F extends PluginFactoryLike<\n infer Data,\n infer Params,\n infer Outputs,\n infer ModelServices,\n infer UiServices\n >\n ? PluginHandle<PluginFactoryLike<Data, Params, Outputs, ModelServices, UiServices>>\n : PluginHandle\n>;\n\n/**\n * Opaque handle for a plugin instance. Runtime value is the plugin instance ID string.\n * Branded with factory phantom `F` for type-safe data/outputs extraction.\n * Constrained with PluginFactoryLike (not PluginFactory) to avoid variance issues.\n */\nexport type PluginHandle<F extends PluginFactoryLike = PluginFactoryLike> = Branded<string, F>;\n\nconst PLUGIN_OUTPUT_PREFIX = \"plugin-output#\";\n\n/** Construct the output key for a plugin output in the block outputs map. */\nexport function pluginOutputKey<F extends PluginFactoryLike>(\n handle: PluginHandle<F>,\n outputKey: string,\n): string {\n return `${PLUGIN_OUTPUT_PREFIX}${handle}#${outputKey}`;\n}\n\n/** Check whether an output key belongs to a plugin (vs block-level output). */\nexport function isPluginOutputKey(key: string): boolean {\n return key.startsWith(PLUGIN_OUTPUT_PREFIX);\n}\n\n/** Get the prefix used for all outputs of a specific plugin instance. */\nexport function pluginOutputPrefix<F extends PluginFactoryLike>(handle: PluginHandle<F>): string {\n return pluginOutputKey(handle, \"\");\n}\n"],"mappings":";AAoFA,MAAM,uBAAuB;;AAG7B,SAAgB,gBACd,QACA,WACQ;AACR,QAAO,GAAG,uBAAuB,OAAO,GAAG;;;AAI7C,SAAgB,kBAAkB,KAAsB;AACtD,QAAO,IAAI,WAAW,qBAAqB;;;AAI7C,SAAgB,mBAAgD,QAAiC;AAC/F,QAAO,gBAAgB,QAAQ,GAAG"}
1
+ {"version":3,"file":"plugin_handle.cjs","names":[],"sources":["../src/plugin_handle.ts"],"sourcesContent":["/**\n * PluginHandle — Opaque branded handle and output key utilities for plugin instances.\n *\n * Extracted into its own module to break circular dependencies:\n * both block_storage.ts and plugin_model.ts can import from here\n * without depending on each other.\n *\n * @module plugin_handle\n */\n\nimport type { Branded } from \"@milaboratories/helpers\";\n\n/**\n * Phantom-only base type for constraining PluginHandle's type parameter.\n *\n * PluginFactory has create() → PluginInstance with function properties, making it invariant\n * under strictFunctionTypes. PluginFactoryLike exposes only the covariant `__types` phantom,\n * avoiding the contravariance chain. Handles only need `__types` for type extraction.\n *\n * PluginFactory extends PluginFactoryLike, so every concrete factory satisfies this constraint.\n */\nexport interface PluginFactoryLike<\n Data extends Record<string, unknown> = Record<string, unknown>,\n Params extends undefined | Record<string, unknown> = undefined | Record<string, unknown>,\n Outputs extends Record<string, unknown> = Record<string, unknown>,\n ModelServices = unknown,\n UiServices = unknown,\n> {\n readonly __types?: {\n data: Data;\n params: Params;\n outputs: Outputs;\n modelServices: ModelServices;\n uiServices: UiServices;\n };\n}\n\n/** Extract the Data type from a PluginFactoryLike phantom. */\nexport type InferFactoryData<F extends PluginFactoryLike> = NonNullable<\n F extends PluginFactoryLike<infer D, any, any, any, any> ? D : Record<string, unknown>\n>;\n\n/** Extract the Params type from a PluginFactoryLike phantom. */\nexport type InferFactoryParams<F extends PluginFactoryLike> = NonNullable<\n F extends PluginFactoryLike<any, infer P, any, any, any> ? P : undefined\n>;\n\n/** Extract the Outputs type from a PluginFactoryLike phantom. */\nexport type InferFactoryOutputs<F extends PluginFactoryLike> = NonNullable<\n F extends PluginFactoryLike<any, any, infer O, any, any> ? O : Record<string, unknown>\n>;\n\n/** Extract the pre-resolved model services type from a PluginFactoryLike phantom. */\nexport type InferFactoryModelServices<F extends PluginFactoryLike> =\n F extends PluginFactoryLike<any, any, any, infer ModelServices, any> ? ModelServices : {};\n\n/** Extract the pre-resolved UI services type from a PluginFactoryLike phantom. */\nexport type InferFactoryUiServices<F extends PluginFactoryLike> =\n F extends PluginFactoryLike<any, any, any, any, infer UiServices> ? UiServices : {};\n\n/**\n * Derive a typed PluginHandle from a PluginFactory type.\n * Normalizes the brand to data/params/outputs/services (strips config) so handles\n * from InferPluginUiEntries match handles from InferPluginHandle.\n */\nexport type InferPluginHandle<F extends PluginFactoryLike> = NonNullable<\n F extends PluginFactoryLike<\n infer Data,\n infer Params,\n infer Outputs,\n infer ModelServices,\n infer UiServices\n >\n ? PluginHandle<PluginFactoryLike<Data, Params, Outputs, ModelServices, UiServices>>\n : PluginHandle\n>;\n\n/**\n * Opaque handle for a plugin instance. Runtime value is the plugin instance ID string.\n * Branded with factory phantom `F` for type-safe data/outputs extraction.\n * Constrained with PluginFactoryLike (not PluginFactory) to avoid variance issues.\n */\nexport type PluginHandle<F extends PluginFactoryLike = PluginFactoryLike> = Branded<string, F>;\n\nconst PLUGIN_OUTPUT_PREFIX = \"plugin-output#\";\n\n/** Construct the output key for a plugin output in the block outputs map. */\nexport function pluginOutputKey<F extends PluginFactoryLike>(\n handle: PluginHandle<F>,\n outputKey: string,\n): string {\n return `${PLUGIN_OUTPUT_PREFIX}${handle}#${outputKey}`;\n}\n\n/** Check whether an output key belongs to a plugin (vs block-level output). */\nexport function isPluginOutputKey(key: string): boolean {\n return key.startsWith(PLUGIN_OUTPUT_PREFIX);\n}\n\n/** Get the prefix used for all outputs of a specific plugin instance. */\nexport function pluginOutputPrefix<F extends PluginFactoryLike>(handle: PluginHandle<F>): string {\n return pluginOutputKey(handle, \"\");\n}\n"],"mappings":";AAoFA,MAAM,uBAAuB;;AAG7B,SAAgB,gBACd,QACA,WACQ;AACR,QAAO,GAAG,uBAAuB,OAAO,GAAG;;;AAI7C,SAAgB,kBAAkB,KAAsB;AACtD,QAAO,IAAI,WAAW,qBAAqB;;;AAI7C,SAAgB,mBAAgD,QAAiC;AAC/F,QAAO,gBAAgB,QAAQ,GAAG"}
@@ -32,7 +32,7 @@ type InferFactoryUiServices<F extends PluginFactoryLike> = F extends PluginFacto
32
32
  /**
33
33
  * Derive a typed PluginHandle from a PluginFactory type.
34
34
  * Normalizes the brand to data/params/outputs/services (strips config) so handles
35
- * from InferPluginHandles match handles from InferPluginHandle.
35
+ * from InferPluginUiEntries match handles from InferPluginHandle.
36
36
  */
37
37
  type InferPluginHandle<F extends PluginFactoryLike> = NonNullable<F extends PluginFactoryLike<infer Data, infer Params, infer Outputs, infer ModelServices, infer UiServices> ? PluginHandle<PluginFactoryLike<Data, Params, Outputs, ModelServices, UiServices>> : PluginHandle>;
38
38
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"plugin_handle.js","names":[],"sources":["../src/plugin_handle.ts"],"sourcesContent":["/**\n * PluginHandle — Opaque branded handle and output key utilities for plugin instances.\n *\n * Extracted into its own module to break circular dependencies:\n * both block_storage.ts and plugin_model.ts can import from here\n * without depending on each other.\n *\n * @module plugin_handle\n */\n\nimport type { Branded } from \"@milaboratories/helpers\";\n\n/**\n * Phantom-only base type for constraining PluginHandle's type parameter.\n *\n * PluginFactory has create() → PluginInstance with function properties, making it invariant\n * under strictFunctionTypes. PluginFactoryLike exposes only the covariant `__types` phantom,\n * avoiding the contravariance chain. Handles only need `__types` for type extraction.\n *\n * PluginFactory extends PluginFactoryLike, so every concrete factory satisfies this constraint.\n */\nexport interface PluginFactoryLike<\n Data extends Record<string, unknown> = Record<string, unknown>,\n Params extends undefined | Record<string, unknown> = undefined | Record<string, unknown>,\n Outputs extends Record<string, unknown> = Record<string, unknown>,\n ModelServices = unknown,\n UiServices = unknown,\n> {\n readonly __types?: {\n data: Data;\n params: Params;\n outputs: Outputs;\n modelServices: ModelServices;\n uiServices: UiServices;\n };\n}\n\n/** Extract the Data type from a PluginFactoryLike phantom. */\nexport type InferFactoryData<F extends PluginFactoryLike> = NonNullable<\n F extends PluginFactoryLike<infer D, any, any, any, any> ? D : Record<string, unknown>\n>;\n\n/** Extract the Params type from a PluginFactoryLike phantom. */\nexport type InferFactoryParams<F extends PluginFactoryLike> = NonNullable<\n F extends PluginFactoryLike<any, infer P, any, any, any> ? P : undefined\n>;\n\n/** Extract the Outputs type from a PluginFactoryLike phantom. */\nexport type InferFactoryOutputs<F extends PluginFactoryLike> = NonNullable<\n F extends PluginFactoryLike<any, any, infer O, any, any> ? O : Record<string, unknown>\n>;\n\n/** Extract the pre-resolved model services type from a PluginFactoryLike phantom. */\nexport type InferFactoryModelServices<F extends PluginFactoryLike> =\n F extends PluginFactoryLike<any, any, any, infer ModelServices, any> ? ModelServices : {};\n\n/** Extract the pre-resolved UI services type from a PluginFactoryLike phantom. */\nexport type InferFactoryUiServices<F extends PluginFactoryLike> =\n F extends PluginFactoryLike<any, any, any, any, infer UiServices> ? UiServices : {};\n\n/**\n * Derive a typed PluginHandle from a PluginFactory type.\n * Normalizes the brand to data/params/outputs/services (strips config) so handles\n * from InferPluginHandles match handles from InferPluginHandle.\n */\nexport type InferPluginHandle<F extends PluginFactoryLike> = NonNullable<\n F extends PluginFactoryLike<\n infer Data,\n infer Params,\n infer Outputs,\n infer ModelServices,\n infer UiServices\n >\n ? PluginHandle<PluginFactoryLike<Data, Params, Outputs, ModelServices, UiServices>>\n : PluginHandle\n>;\n\n/**\n * Opaque handle for a plugin instance. Runtime value is the plugin instance ID string.\n * Branded with factory phantom `F` for type-safe data/outputs extraction.\n * Constrained with PluginFactoryLike (not PluginFactory) to avoid variance issues.\n */\nexport type PluginHandle<F extends PluginFactoryLike = PluginFactoryLike> = Branded<string, F>;\n\nconst PLUGIN_OUTPUT_PREFIX = \"plugin-output#\";\n\n/** Construct the output key for a plugin output in the block outputs map. */\nexport function pluginOutputKey<F extends PluginFactoryLike>(\n handle: PluginHandle<F>,\n outputKey: string,\n): string {\n return `${PLUGIN_OUTPUT_PREFIX}${handle}#${outputKey}`;\n}\n\n/** Check whether an output key belongs to a plugin (vs block-level output). */\nexport function isPluginOutputKey(key: string): boolean {\n return key.startsWith(PLUGIN_OUTPUT_PREFIX);\n}\n\n/** Get the prefix used for all outputs of a specific plugin instance. */\nexport function pluginOutputPrefix<F extends PluginFactoryLike>(handle: PluginHandle<F>): string {\n return pluginOutputKey(handle, \"\");\n}\n"],"mappings":";AAoFA,MAAM,uBAAuB;;AAG7B,SAAgB,gBACd,QACA,WACQ;AACR,QAAO,GAAG,uBAAuB,OAAO,GAAG;;;AAI7C,SAAgB,kBAAkB,KAAsB;AACtD,QAAO,IAAI,WAAW,qBAAqB;;;AAI7C,SAAgB,mBAAgD,QAAiC;AAC/F,QAAO,gBAAgB,QAAQ,GAAG"}
1
+ {"version":3,"file":"plugin_handle.js","names":[],"sources":["../src/plugin_handle.ts"],"sourcesContent":["/**\n * PluginHandle — Opaque branded handle and output key utilities for plugin instances.\n *\n * Extracted into its own module to break circular dependencies:\n * both block_storage.ts and plugin_model.ts can import from here\n * without depending on each other.\n *\n * @module plugin_handle\n */\n\nimport type { Branded } from \"@milaboratories/helpers\";\n\n/**\n * Phantom-only base type for constraining PluginHandle's type parameter.\n *\n * PluginFactory has create() → PluginInstance with function properties, making it invariant\n * under strictFunctionTypes. PluginFactoryLike exposes only the covariant `__types` phantom,\n * avoiding the contravariance chain. Handles only need `__types` for type extraction.\n *\n * PluginFactory extends PluginFactoryLike, so every concrete factory satisfies this constraint.\n */\nexport interface PluginFactoryLike<\n Data extends Record<string, unknown> = Record<string, unknown>,\n Params extends undefined | Record<string, unknown> = undefined | Record<string, unknown>,\n Outputs extends Record<string, unknown> = Record<string, unknown>,\n ModelServices = unknown,\n UiServices = unknown,\n> {\n readonly __types?: {\n data: Data;\n params: Params;\n outputs: Outputs;\n modelServices: ModelServices;\n uiServices: UiServices;\n };\n}\n\n/** Extract the Data type from a PluginFactoryLike phantom. */\nexport type InferFactoryData<F extends PluginFactoryLike> = NonNullable<\n F extends PluginFactoryLike<infer D, any, any, any, any> ? D : Record<string, unknown>\n>;\n\n/** Extract the Params type from a PluginFactoryLike phantom. */\nexport type InferFactoryParams<F extends PluginFactoryLike> = NonNullable<\n F extends PluginFactoryLike<any, infer P, any, any, any> ? P : undefined\n>;\n\n/** Extract the Outputs type from a PluginFactoryLike phantom. */\nexport type InferFactoryOutputs<F extends PluginFactoryLike> = NonNullable<\n F extends PluginFactoryLike<any, any, infer O, any, any> ? O : Record<string, unknown>\n>;\n\n/** Extract the pre-resolved model services type from a PluginFactoryLike phantom. */\nexport type InferFactoryModelServices<F extends PluginFactoryLike> =\n F extends PluginFactoryLike<any, any, any, infer ModelServices, any> ? ModelServices : {};\n\n/** Extract the pre-resolved UI services type from a PluginFactoryLike phantom. */\nexport type InferFactoryUiServices<F extends PluginFactoryLike> =\n F extends PluginFactoryLike<any, any, any, any, infer UiServices> ? UiServices : {};\n\n/**\n * Derive a typed PluginHandle from a PluginFactory type.\n * Normalizes the brand to data/params/outputs/services (strips config) so handles\n * from InferPluginUiEntries match handles from InferPluginHandle.\n */\nexport type InferPluginHandle<F extends PluginFactoryLike> = NonNullable<\n F extends PluginFactoryLike<\n infer Data,\n infer Params,\n infer Outputs,\n infer ModelServices,\n infer UiServices\n >\n ? PluginHandle<PluginFactoryLike<Data, Params, Outputs, ModelServices, UiServices>>\n : PluginHandle\n>;\n\n/**\n * Opaque handle for a plugin instance. Runtime value is the plugin instance ID string.\n * Branded with factory phantom `F` for type-safe data/outputs extraction.\n * Constrained with PluginFactoryLike (not PluginFactory) to avoid variance issues.\n */\nexport type PluginHandle<F extends PluginFactoryLike = PluginFactoryLike> = Branded<string, F>;\n\nconst PLUGIN_OUTPUT_PREFIX = \"plugin-output#\";\n\n/** Construct the output key for a plugin output in the block outputs map. */\nexport function pluginOutputKey<F extends PluginFactoryLike>(\n handle: PluginHandle<F>,\n outputKey: string,\n): string {\n return `${PLUGIN_OUTPUT_PREFIX}${handle}#${outputKey}`;\n}\n\n/** Check whether an output key belongs to a plugin (vs block-level output). */\nexport function isPluginOutputKey(key: string): boolean {\n return key.startsWith(PLUGIN_OUTPUT_PREFIX);\n}\n\n/** Get the prefix used for all outputs of a specific plugin instance. */\nexport function pluginOutputPrefix<F extends PluginFactoryLike>(handle: PluginHandle<F>): string {\n return pluginOutputKey(handle, \"\");\n}\n"],"mappings":";AAoFA,MAAM,uBAAuB;;AAG7B,SAAgB,gBACd,QACA,WACQ;AACR,QAAO,GAAG,uBAAuB,OAAO,GAAG;;;AAI7C,SAAgB,kBAAkB,KAAsB;AACtD,QAAO,IAAI,WAAW,qBAAqB;;;AAI7C,SAAgB,mBAAgD,QAAiC;AAC/F,QAAO,gBAAgB,QAAQ,GAAG"}
@@ -208,19 +208,19 @@ var PluginModel = class PluginModel {
208
208
  dataModel;
209
209
  /** Output definitions - functions that compute outputs from plugin context */
210
210
  outputs;
211
- /** Per-output flags (e.g. withStatus) */
212
- outputFlags;
213
211
  /** Feature flags declared by this plugin */
214
212
  featureFlags;
215
213
  /** Create fresh default data. Config (if any) is captured at creation time. */
216
214
  getDefaultData;
215
+ /** Public output definitions — accessible without usePlugin() via app.plugins */
216
+ publicOutputDef;
217
217
  constructor(options) {
218
218
  this.name = options.name;
219
219
  this.dataModel = options.dataModel;
220
220
  this.outputs = options.outputs;
221
- this.outputFlags = options.outputFlags;
222
221
  this.featureFlags = options.featureFlags;
223
222
  this.getDefaultData = options.getDefaultData;
223
+ this.publicOutputDef = options.publicOutputDef;
224
224
  }
225
225
  /**
226
226
  * Internal method for creating PluginModel from factory.
@@ -252,15 +252,15 @@ var PluginModelFactory = class PluginModelFactory {
252
252
  dataFn;
253
253
  getDefaultDataFn;
254
254
  outputs;
255
- outputFlags;
256
255
  featureFlags;
256
+ publicOutputDef;
257
257
  constructor(options) {
258
258
  this.name = options.name;
259
259
  this.dataFn = options.dataFn;
260
260
  this.getDefaultDataFn = options.getDefaultDataFn;
261
261
  this.outputs = options.outputs;
262
- this.outputFlags = options.outputFlags;
263
262
  this.featureFlags = options.featureFlags;
263
+ this.publicOutputDef = options.publicOutputDef;
264
264
  }
265
265
  /** @internal */
266
266
  static [FROM_BUILDER](options) {
@@ -278,9 +278,9 @@ var PluginModelFactory = class PluginModelFactory {
278
278
  name: this.name,
279
279
  dataModel,
280
280
  outputs: this.outputs,
281
- outputFlags: this.outputFlags,
282
281
  featureFlags: this.featureFlags,
283
- getDefaultData: getDefaultDataFn ? () => getDefaultDataFn(config) : () => dataModel.getDefaultData()
282
+ getDefaultData: getDefaultDataFn ? () => getDefaultDataFn(config) : () => dataModel.getDefaultData(),
283
+ publicOutputDef: this.publicOutputDef
284
284
  });
285
285
  }
286
286
  };
@@ -308,15 +308,15 @@ var PluginModelBuilder = class PluginModelBuilder {
308
308
  dataFn;
309
309
  getDefaultDataFn;
310
310
  outputs;
311
- outputFlags;
312
311
  featureFlags;
312
+ publicOutputDef;
313
313
  constructor(options) {
314
314
  this.name = options.name;
315
315
  this.dataFn = options.dataFn;
316
316
  this.getDefaultDataFn = options.getDefaultDataFn;
317
317
  this.outputs = options.outputs ?? {};
318
- this.outputFlags = options.outputFlags ?? {};
319
318
  this.featureFlags = options.featureFlags;
319
+ this.publicOutputDef = options.publicOutputDef;
320
320
  }
321
321
  /** @internal */
322
322
  static [FROM_BUILDER](options) {
@@ -324,14 +324,17 @@ var PluginModelBuilder = class PluginModelBuilder {
324
324
  }
325
325
  /**
326
326
  * Adds an output to the plugin.
327
+ * All plugin outputs are always wrapped with status — the UI receives
328
+ * {@link OutputWithStatus} for every output, allowing it to distinguish
329
+ * between pending, success, and error states.
327
330
  *
328
331
  * @param key - Output name
329
332
  * @param fn - Function that computes the output value from plugin context
330
- * @returns PluginModel with the new output added
333
+ * @returns Builder with the new output added
331
334
  *
332
335
  * @example
333
336
  * .output('model', (ctx) => createModel(ctx.params.columns, ctx.data.state))
334
- * .output('isReady', (ctx) => ctx.params.columns !== undefined)
337
+ * .output('pFrame', (ctx) => ctx.createPFrame([...]))
335
338
  */
336
339
  output(key, fn) {
337
340
  return new PluginModelBuilder({
@@ -343,42 +346,32 @@ var PluginModelBuilder = class PluginModelBuilder {
343
346
  ...this.outputs,
344
347
  [key]: fn
345
348
  },
346
- outputFlags: {
347
- ...this.outputFlags,
348
- [key]: { withStatus: false }
349
- }
349
+ publicOutputDef: this.publicOutputDef
350
350
  });
351
351
  }
352
352
  /**
353
- * Adds an output wrapped with status information to the plugin.
353
+ * Exposes a plugin data field as a public output — accessible without `usePlugin()`
354
+ * via `app.plugins.pluginName.publicOutputs.key`.
354
355
  *
355
- * The UI receives the full {@link OutputWithStatus} object instead of an unwrapped value,
356
- * allowing it to distinguish between pending, success, and error states.
356
+ * The getter runs against the plugin's reactive data object.
357
+ * Public outputs are read-only.
357
358
  *
358
- * @param key - Output name
359
- * @param fn - Function that computes the output value from plugin context
360
- * @returns PluginModel with the new status-wrapped output added
359
+ * @param key - Name of the public output field
360
+ * @param getter - Function deriving the value from plugin data
361
361
  *
362
362
  * @example
363
- * .outputWithStatus('table', (ctx) => {
364
- * const pCols = ctx.params.pFrame?.getPColumns();
365
- * if (pCols === undefined) return undefined;
366
- * return createPlDataTableV2(ctx, pCols, ctx.data.tableState);
367
- * })
363
+ * .publicOutput('selection', (d) => d.selection)
368
364
  */
369
- outputWithStatus(key, fn) {
365
+ publicOutput(key, getter) {
370
366
  return new PluginModelBuilder({
371
367
  name: this.name,
372
368
  dataFn: this.dataFn,
373
369
  getDefaultDataFn: this.getDefaultDataFn,
374
370
  featureFlags: this.featureFlags,
375
- outputs: {
376
- ...this.outputs,
377
- [key]: fn
378
- },
379
- outputFlags: {
380
- ...this.outputFlags,
381
- [key]: { withStatus: true }
371
+ outputs: this.outputs,
372
+ publicOutputDef: {
373
+ ...this.publicOutputDef,
374
+ [key]: { getter }
382
375
  }
383
376
  });
384
377
  }
@@ -401,7 +394,7 @@ var PluginModelBuilder = class PluginModelBuilder {
401
394
  dataFn: this.dataFn,
402
395
  getDefaultDataFn: this.getDefaultDataFn,
403
396
  outputs: this.outputs,
404
- outputFlags: this.outputFlags,
397
+ publicOutputDef: this.publicOutputDef,
405
398
  featureFlags: this.featureFlags
406
399
  });
407
400
  }
@@ -413,7 +406,10 @@ var PluginModelBuilder = class PluginModelBuilder {
413
406
  var PluginModelInitialBuilder = class PluginModelInitialBuilder extends PluginModelBuilder {
414
407
  /** @internal */
415
408
  static create(options) {
416
- return new PluginModelInitialBuilder(options);
409
+ return new PluginModelInitialBuilder({
410
+ ...options,
411
+ publicOutputDef: {}
412
+ });
417
413
  }
418
414
  /**
419
415
  * Sets the Params type for this plugin — the shape of data derived from the block's
@@ -429,7 +425,8 @@ var PluginModelInitialBuilder = class PluginModelInitialBuilder extends PluginMo
429
425
  name: this.name,
430
426
  dataFn: this.dataFn,
431
427
  getDefaultDataFn: this.getDefaultDataFn,
432
- featureFlags: this.featureFlags
428
+ featureFlags: this.featureFlags,
429
+ publicOutputDef: {}
433
430
  });
434
431
  }
435
432
  };
@@ -1 +1 @@
1
- {"version":3,"file":"plugin_model.cjs","names":["DATA_MODEL_LEGACY_VERSION","DataModelBuilder"],"sources":["../src/plugin_model.ts"],"sourcesContent":["/**\n * PluginModel - Builder for creating plugin types with data model and outputs.\n *\n * Plugins are UI components with their own model logic and persistent state.\n * Block developers register plugin instances via BlockModelV3.plugin() method.\n *\n * @module plugin_model\n */\n\nimport type { BlockCodeKnownFeatureFlags, OutputWithStatus } from \"@milaboratories/pl-model-common\";\nimport type { ResolveModelServices, ResolveUiServices } from \"./services/service_resolve\";\nimport {\n type DataModel,\n DataModelBuilder,\n type DataRecoverFn,\n type DataVersioned,\n type TransferTarget,\n} from \"./block_migrations\";\nimport { type PluginName, DATA_MODEL_LEGACY_VERSION } from \"./block_storage\";\nimport type { PluginFactoryLike } from \"./plugin_handle\";\nimport type { PluginRenderCtx } from \"./render\";\n\n/** Symbol for internal builder creation method */\nconst FROM_BUILDER = Symbol(\"fromBuilder\");\n\n/** Output function signature for plugin render context. */\ntype PluginOutputFn<\n Data extends PluginData,\n Params extends PluginParams,\n ModelServices,\n UiServices,\n T,\n> = (\n ctx: PluginRenderCtx<\n PluginFactoryLike<Data, Params, Record<string, unknown>, ModelServices, UiServices>\n >,\n) => T;\n\n/** Mapped output functions for a plugin's outputs. */\ntype PluginOutputFns<\n Data extends PluginData,\n Params extends PluginParams,\n Outputs extends PluginOutputs,\n ModelServices,\n UiServices,\n> = {\n [K in keyof Outputs]: PluginOutputFn<Data, Params, ModelServices, UiServices, Outputs[K]>;\n};\n\n/** Symbol for internal plugin model creation — not accessible to external consumers */\nexport const CREATE_PLUGIN_MODEL = Symbol(\"createPluginModel\");\n\n/** Sentinel for PluginInstance without transferAt — no transfer possible. */\nconst NO_TRANSFER_VERSION = \"\";\n\nexport type PluginData = Record<string, unknown>;\nexport type PluginParams = undefined | Record<string, unknown>;\nexport type PluginOutputs = Record<string, unknown>;\nexport type PluginConfig = undefined | Record<string, unknown>;\n\n/**\n * Plugin data model with typed migration chain and config-aware initialization.\n *\n * @typeParam Data - Current (latest) plugin data type\n * @typeParam Versions - Map of version keys to their data types (accumulated by the chain)\n * @typeParam Config - Config type passed to init function (undefined if none)\n */\nexport class PluginDataModel<\n Data extends PluginData,\n Versions extends Record<string, unknown> = {},\n Config = undefined,\n> {\n readonly dataModel: DataModel<Data>;\n private readonly configInitFn: (config?: Config) => Data;\n\n /** @internal Phantom field to anchor the Versions type parameter. */\n declare readonly __versions?: Versions;\n\n private constructor(dataModel: DataModel<Data>, configInitFn: (config?: Config) => Data) {\n this.dataModel = dataModel;\n this.configInitFn = configInitFn;\n }\n\n /** @internal */\n static [FROM_BUILDER]<Data extends PluginData, Versions extends Record<string, unknown>, Config>(\n dataModel: DataModel<Data>,\n configInitFn: (config?: Config) => Data,\n ): PluginDataModel<Data, Versions, Config> {\n return new PluginDataModel<Data, Versions, Config>(dataModel, configInitFn);\n }\n\n /** Create fresh data with optional config. */\n getDefaultData(config?: Config): DataVersioned<Data> {\n const data = this.configInitFn(config);\n return { version: this.dataModel.version, data };\n }\n}\n\n/** Internal state for plugin data model chain. */\ntype PluginChainState = {\n initialVersion: string;\n migrations: Array<{ toVersion: string; fn: (data: unknown) => unknown }>;\n recoverFn?: (version: string, data: unknown) => unknown;\n recoverAtIndex?: number;\n};\n\n/** Version → persisted data shape for each migration step (third generic of `PluginModel.define` when `data` is a `PluginDataModel`). */\nexport type PluginDataModelVersions<\n M extends PluginDataModel<PluginData, Record<string, unknown>, unknown>,\n> = M extends PluginDataModel<PluginData, infer Versions, unknown> ? Versions : never;\n\n/**\n * Builder for creating PluginDataModel with type-safe migrations.\n * Mirrors DataModelBuilder — same .from(), .migrate(), .recover(), .init() chain.\n *\n * @example\n * const pluginData = new PluginDataModelBuilder()\n * .from<TableData>(\"v1\")\n * .migrate<FilteredTableData>(\"v2\", (v1) => ({ ...v1, filters: [] }))\n * .init<TableConfig>((config?) => ({\n * state: createDefaultState(config?.ops),\n * filters: [],\n * }));\n */\nexport class PluginDataModelBuilder {\n from<Data extends PluginData, const V extends string>(\n version: V,\n ): PluginDataModelInitialChain<Data, Record<V, Data>> {\n return PluginDataModelInitialChain[FROM_BUILDER]<Data, Record<V, Data>>({\n initialVersion: version,\n migrations: [],\n });\n }\n}\n\n/**\n * Chain returned by .migrate(). Supports .migrate(), .recover(), .init().\n * No .upgradeLegacy() — that is only available on the initial chain.\n */\nexport class PluginDataModelChain<\n Data extends PluginData,\n Versions extends Record<string, unknown>,\n> {\n protected constructor(protected readonly state: PluginChainState) {}\n\n /** @internal */\n static [FROM_BUILDER]<Data extends PluginData, Versions extends Record<string, unknown>>(\n state: PluginChainState,\n ): PluginDataModelChain<Data, Versions> {\n return new PluginDataModelChain(state);\n }\n\n /**\n * Add a migration step transforming data from the current version to the next.\n */\n migrate<Next extends PluginData, const NextV extends string>(\n version: NextV,\n fn: (current: Data) => Next,\n ): PluginDataModelChain<Next, Versions & Record<NextV, Next>> {\n return PluginDataModelChain[FROM_BUILDER]<Next, Versions & Record<NextV, Next>>({\n ...this.state,\n migrations: [\n ...this.state.migrations,\n { toVersion: version, fn: fn as (data: unknown) => unknown },\n ],\n });\n }\n\n /**\n * Set a recovery handler for unknown or legacy versions.\n * Can only be called once — the returned chain has no recover() method.\n */\n recover(fn: DataRecoverFn<Data>): PluginDataModelWithRecover<Data, Versions> {\n return PluginDataModelWithRecover[FROM_BUILDER]<Data, Versions>({\n ...this.state,\n recoverFn: fn as (version: string, data: unknown) => unknown,\n recoverAtIndex: this.state.migrations.length,\n });\n }\n\n /** Finalize the PluginDataModel. */\n init<Config = undefined>(fn: (config?: Config) => Data): PluginDataModel<Data, Versions, Config> {\n return buildPluginDataModel(this.state, fn);\n }\n}\n\n/**\n * Initial chain returned by new PluginDataModelBuilder().from().\n * Extends PluginDataModelChain with .upgradeLegacy() — available only before\n * any .migrate() calls, matching the block's DataModelInitialChain pattern.\n */\nexport class PluginDataModelInitialChain<\n Data extends PluginData,\n Versions extends Record<string, unknown>,\n> extends PluginDataModelChain<Data, Versions> {\n /** @internal */\n static override [FROM_BUILDER]<Data extends PluginData, Versions extends Record<string, unknown>>(\n state: PluginChainState,\n ): PluginDataModelInitialChain<Data, Versions> {\n return new PluginDataModelInitialChain(state);\n }\n\n /**\n * Handle data from a previous plugin type occupying this slot.\n * Prepends a migration from DATA_MODEL_LEGACY_VERSION to the initial version.\n * When a plugin type changes, the old data arrives with DATA_MODEL_LEGACY_VERSION —\n * this function transforms it into the initial version, then the normal chain runs.\n *\n * Must be called right after .from() — not available after .migrate().\n * Mutually exclusive with recover().\n *\n * @param fn - Transform from old plugin's raw data to this plugin's initial data type\n */\n upgradeLegacy(fn: (data: unknown) => Data): PluginDataModelWithRecover<Data, Versions> {\n return PluginDataModelWithRecover[FROM_BUILDER]<Data, Versions>({\n ...this.state,\n migrations: [\n { toVersion: this.state.initialVersion, fn: fn as (data: unknown) => unknown },\n ...this.state.migrations,\n ],\n initialVersion: DATA_MODEL_LEGACY_VERSION,\n });\n }\n}\n\n/**\n * Chain after .recover() — supports .migrate(), .init(). No second recover().\n */\nexport class PluginDataModelWithRecover<\n Data extends PluginData,\n Versions extends Record<string, unknown>,\n> {\n private constructor(private readonly state: PluginChainState) {}\n\n /** @internal */\n static [FROM_BUILDER]<Data extends PluginData, Versions extends Record<string, unknown>>(\n state: PluginChainState,\n ): PluginDataModelWithRecover<Data, Versions> {\n return new PluginDataModelWithRecover(state);\n }\n\n migrate<Next extends PluginData, const NextV extends string>(\n version: NextV,\n fn: (current: Data) => Next,\n ): PluginDataModelWithRecover<Next, Versions & Record<NextV, Next>> {\n return PluginDataModelWithRecover[FROM_BUILDER]<Next, Versions & Record<NextV, Next>>({\n ...this.state,\n migrations: [\n ...this.state.migrations,\n { toVersion: version, fn: fn as (data: unknown) => unknown },\n ],\n });\n }\n\n init<Config = undefined>(fn: (config?: Config) => Data): PluginDataModel<Data, Versions, Config> {\n return buildPluginDataModel(this.state, fn);\n }\n}\n\n/**\n * Builds a PluginDataModel by replaying the stored chain state through DataModelBuilder.\n * @internal\n */\nfunction buildPluginDataModel<\n Data extends PluginData,\n Versions extends Record<string, unknown>,\n Config,\n>(\n state: PluginChainState,\n configInitFn: (config?: Config) => Data,\n): PluginDataModel<Data, Versions, Config> {\n // Build inner DataModel by replaying migrations through DataModelBuilder chain.\n // Uses `any` internally — type safety is maintained by the public chain types.\n let chain: any = new DataModelBuilder().from(state.initialVersion);\n\n for (let i = 0; i < state.migrations.length; i++) {\n if (state.recoverFn !== undefined && state.recoverAtIndex === i) {\n chain = chain.recover(state.recoverFn);\n }\n chain = chain.migrate(state.migrations[i].toVersion, state.migrations[i].fn);\n }\n\n // If recover was placed at or after the last migration\n if (state.recoverFn !== undefined && state.recoverAtIndex === state.migrations.length) {\n chain = chain.recover(state.recoverFn);\n }\n\n const dataModel: DataModel<Data> = chain.init(() => configInitFn());\n\n return PluginDataModel[FROM_BUILDER]<Data, Versions, Config>(dataModel, configInitFn);\n}\n\n/**\n * A named plugin instance created by `factory.create({ pluginId, ... })`.\n * Passed to both `.transfer()` (on migration chain) and `.plugin()` (on BlockModelV3).\n * Implements TransferTarget so the migration chain can accept it.\n *\n * @typeParam Id - Plugin instance ID literal type\n * @typeParam Data - Plugin data type\n * @typeParam Params - Plugin params type\n * @typeParam Outputs - Plugin outputs type\n * @typeParam TransferData - Type of data entering the plugin via transfer (never if no transfer)\n */\nexport class PluginInstance<\n Id extends string = string,\n Data extends PluginData = PluginData,\n Params extends PluginParams = undefined,\n Outputs extends PluginOutputs = PluginOutputs,\n TransferData = never,\n ModelServices = unknown,\n UiServices = unknown,\n> implements TransferTarget<Id, TransferData> {\n readonly id: Id;\n readonly transferVersion: string;\n /** @internal Phantom for type inference; never set at runtime. */\n readonly __instanceTypes?: {\n data: Data;\n params: Params;\n outputs: Outputs;\n modelServices: ModelServices;\n uiServices: UiServices;\n };\n /** Bound closure that creates the PluginModel. Config is captured at factory.create() time. */\n private readonly createPluginModel: () => PluginModel<\n Data,\n Params,\n Outputs,\n ModelServices,\n UiServices\n >;\n\n private constructor(\n id: Id,\n createPluginModel: () => PluginModel<Data, Params, Outputs, ModelServices, UiServices>,\n transferVersion: string,\n ) {\n this.id = id;\n this.createPluginModel = createPluginModel;\n this.transferVersion = transferVersion;\n }\n\n /** @internal Accepts concrete Config — binds it into a closure, avoiding Config variance issues. */\n static [FROM_BUILDER]<\n Id extends string,\n Data extends PluginData,\n Params extends PluginParams,\n Outputs extends PluginOutputs,\n TransferData,\n Config extends PluginConfig = PluginConfig,\n ModelServices = unknown,\n UiServices = unknown,\n >(\n id: Id,\n factory: PluginModelFactory<\n Data,\n Params,\n Outputs,\n Config,\n Record<string, unknown>,\n ModelServices,\n UiServices\n >,\n transferVersion: string,\n config?: Config,\n ): PluginInstance<Id, Data, Params, Outputs, TransferData, ModelServices, UiServices> {\n return new PluginInstance(id, () => factory[CREATE_PLUGIN_MODEL](config), transferVersion);\n }\n\n /** @internal Create a PluginModel from this instance. Used by BlockModelV3.plugin(). */\n [CREATE_PLUGIN_MODEL](): PluginModel<Data, Params, Outputs, ModelServices, UiServices> {\n return this.createPluginModel();\n }\n}\n\n/**\n * Configured plugin instance returned by PluginModelFactory[CREATE_PLUGIN_MODEL]().\n * Contains the plugin's name, data model, and output definitions.\n */\nexport class PluginModel<\n Data extends PluginData = PluginData,\n Params extends PluginParams = undefined,\n Outputs extends PluginOutputs = PluginOutputs,\n ModelServices = {},\n UiServices = {},\n> {\n /** Globally unique plugin name */\n readonly name: PluginName;\n /** Data model instance for this plugin */\n readonly dataModel: DataModel<Data>;\n /** Output definitions - functions that compute outputs from plugin context */\n readonly outputs: PluginOutputFns<Data, Params, Outputs, ModelServices, UiServices>;\n /** Per-output flags (e.g. withStatus) */\n readonly outputFlags: Record<string, { withStatus: boolean }>;\n /** Feature flags declared by this plugin */\n readonly featureFlags?: BlockCodeKnownFeatureFlags;\n /** Create fresh default data. Config (if any) is captured at creation time. */\n readonly getDefaultData: () => DataVersioned<Data>;\n\n private constructor(options: {\n name: PluginName;\n dataModel: DataModel<Data>;\n outputs: PluginOutputFns<Data, Params, Outputs, ModelServices, UiServices>;\n outputFlags: Record<string, { withStatus: boolean }>;\n featureFlags?: BlockCodeKnownFeatureFlags;\n getDefaultData: () => DataVersioned<Data>;\n }) {\n this.name = options.name;\n this.dataModel = options.dataModel;\n this.outputs = options.outputs;\n this.outputFlags = options.outputFlags;\n this.featureFlags = options.featureFlags;\n this.getDefaultData = options.getDefaultData;\n }\n\n /**\n * Internal method for creating PluginModel from factory.\n * Uses Symbol key to prevent external access.\n * @internal\n */\n static [FROM_BUILDER]<\n Data extends PluginData,\n Params extends PluginParams,\n Outputs extends PluginOutputs,\n ModelServices = {},\n UiServices = {},\n >(options: {\n name: PluginName;\n dataModel: DataModel<Data>;\n outputs: PluginOutputFns<Data, Params, Outputs, ModelServices, UiServices>;\n outputFlags: Record<string, { withStatus: boolean }>;\n featureFlags?: BlockCodeKnownFeatureFlags;\n getDefaultData: () => DataVersioned<Data>;\n }): PluginModel<Data, Params, Outputs, ModelServices, UiServices> {\n return new PluginModel<Data, Params, Outputs, ModelServices, UiServices>(options);\n }\n\n /**\n * Creates a new PluginModelBuilder with a PluginDataModel (supports transfer / config).\n *\n * @example\n * const pluginData = new PluginDataModelBuilder().from<TableData>(\"v1\")\n * .migrate<FilteredTableData>(\"v2\", (v1) => ({ ...v1, filters: [] }))\n * .init<TableConfig>((config?) => ({\n * state: createDefaultState(config?.ops),\n * filters: [],\n * }));\n *\n * const myPlugin = PluginModel.define({\n * name: 'myPlugin' as PluginName,\n * data: pluginData,\n * }).build();\n */\n static define<\n Data extends PluginData,\n Params extends PluginParams = undefined,\n Versions extends Record<string, unknown> = {},\n Config extends PluginConfig = undefined,\n Flags extends BlockCodeKnownFeatureFlags = {},\n >(options: {\n name: PluginName;\n data: PluginDataModel<Data, Versions, Config>;\n featureFlags?: Flags;\n }): PluginModelInitialBuilder<\n Data,\n Params,\n Config,\n Versions,\n ResolveModelServices<Flags>,\n ResolveUiServices<Flags>\n >;\n /**\n * Creates a new PluginModelBuilder with a data model factory function (backward compatible).\n *\n * @example\n * const myPlugin = PluginModel.define({\n * name: 'myPlugin' as PluginName,\n * data: (cfg) => dataModelChain.init(() => ({ value: cfg.defaultValue })),\n * }).build();\n */\n static define<\n Data extends PluginData,\n Params extends PluginParams = undefined,\n Config extends PluginConfig = undefined,\n Flags extends BlockCodeKnownFeatureFlags = {},\n >(options: {\n name: PluginName;\n data: (config?: Config) => DataModel<Data>;\n featureFlags?: Flags;\n }): PluginModelInitialBuilder<\n Data,\n Params,\n Config,\n {},\n ResolveModelServices<Flags>,\n ResolveUiServices<Flags>\n >;\n static define(options: {\n name: PluginName;\n data: PluginDataModel<any, any, any> | ((config?: any) => DataModel<any>);\n featureFlags?: BlockCodeKnownFeatureFlags;\n }): PluginModelInitialBuilder {\n if (options.data instanceof PluginDataModel) {\n const pdm = options.data;\n return PluginModelInitialBuilder.create({\n name: options.name,\n dataFn: () => pdm.dataModel,\n getDefaultDataFn: (config: any) => pdm.getDefaultData(config),\n featureFlags: options.featureFlags,\n });\n }\n return PluginModelInitialBuilder.create({\n name: options.name,\n dataFn: options.data,\n featureFlags: options.featureFlags,\n });\n }\n}\n\n/** Plugin factory returned by PluginModelBuilder.build(). */\nexport interface PluginFactory<\n Data extends PluginData = PluginData,\n Params extends PluginParams = undefined,\n Outputs extends PluginOutputs = PluginOutputs,\n Config extends PluginConfig = undefined,\n Versions extends Record<string, unknown> = {},\n ModelServices = {},\n UiServices = {},\n> extends PluginFactoryLike<Data, Params, Outputs, ModelServices, UiServices> {\n /** Create a named plugin instance, optionally with transfer at a specific version. */\n create<const Id extends string, const V extends string & keyof Versions = never>(options: {\n pluginId: Id;\n transferAt?: V;\n config?: Config;\n }): PluginInstance<Id, Data, Params, Outputs, Versions[V], ModelServices, UiServices>;\n\n /**\n * @internal Phantom field for structural type extraction.\n * Enables InferFactoryData/InferFactoryOutputs to work via PluginFactoryLike.\n */\n readonly __types?: {\n data: Data;\n params: Params;\n outputs: Outputs;\n modelServices: ModelServices;\n uiServices: UiServices;\n config: Config;\n versions: Versions;\n };\n}\n\nclass PluginModelFactory<\n Data extends PluginData = PluginData,\n Params extends PluginParams = undefined,\n Outputs extends PluginOutputs = PluginOutputs,\n Config extends PluginConfig = undefined,\n Versions extends Record<string, unknown> = {},\n ModelServices = {},\n UiServices = {},\n> implements PluginFactory<Data, Params, Outputs, Config, Versions, ModelServices, UiServices> {\n private readonly name: PluginName;\n private readonly dataFn: (config?: Config) => DataModel<Data>;\n private readonly getDefaultDataFn?: (config?: Config) => DataVersioned<Data>;\n readonly outputs: PluginOutputFns<Data, Params, Outputs, ModelServices, UiServices>;\n private readonly outputFlags: Record<string, { withStatus: boolean }>;\n private readonly featureFlags?: BlockCodeKnownFeatureFlags;\n\n private constructor(options: {\n name: PluginName;\n dataFn: (config?: Config) => DataModel<Data>;\n getDefaultDataFn?: (config?: Config) => DataVersioned<Data>;\n outputs: PluginOutputFns<Data, Params, Outputs, ModelServices, UiServices>;\n outputFlags: Record<string, { withStatus: boolean }>;\n featureFlags?: BlockCodeKnownFeatureFlags;\n }) {\n this.name = options.name;\n this.dataFn = options.dataFn;\n this.getDefaultDataFn = options.getDefaultDataFn;\n this.outputs = options.outputs;\n this.outputFlags = options.outputFlags;\n this.featureFlags = options.featureFlags;\n }\n\n /** @internal */\n static [FROM_BUILDER]<\n Data extends PluginData,\n Params extends PluginParams,\n Outputs extends PluginOutputs,\n Config extends PluginConfig,\n Versions extends Record<string, unknown>,\n ModelServices = {},\n UiServices = {},\n >(options: {\n name: PluginName;\n dataFn: (config?: Config) => DataModel<Data>;\n getDefaultDataFn?: (config?: Config) => DataVersioned<Data>;\n outputs: PluginOutputFns<Data, Params, Outputs, ModelServices, UiServices>;\n outputFlags: Record<string, { withStatus: boolean }>;\n featureFlags?: BlockCodeKnownFeatureFlags;\n }): PluginModelFactory<Data, Params, Outputs, Config, Versions, ModelServices, UiServices> {\n return new PluginModelFactory(options);\n }\n\n create<const Id extends string, const V extends string & keyof Versions = never>(options: {\n pluginId: Id;\n transferAt?: V;\n config?: Config;\n }): PluginInstance<Id, Data, Params, Outputs, Versions[V], ModelServices, UiServices> {\n const transferVersion = options.transferAt ?? NO_TRANSFER_VERSION;\n return PluginInstance[FROM_BUILDER]<\n Id,\n Data,\n Params,\n Outputs,\n Versions[V],\n Config,\n ModelServices,\n UiServices\n >(options.pluginId as Id, this, transferVersion, options.config);\n }\n\n /** @internal Create a PluginModel from config. Config is captured in getDefaultData closure. */\n [CREATE_PLUGIN_MODEL](\n config?: Config,\n ): PluginModel<Data, Params, Outputs, ModelServices, UiServices> {\n const dataModel = this.dataFn(config);\n const getDefaultDataFn = this.getDefaultDataFn;\n return PluginModel[FROM_BUILDER]<Data, Params, Outputs, ModelServices, UiServices>({\n name: this.name,\n dataModel,\n outputs: this.outputs,\n outputFlags: this.outputFlags,\n featureFlags: this.featureFlags,\n getDefaultData: getDefaultDataFn\n ? () => getDefaultDataFn(config)\n : () => dataModel.getDefaultData(),\n });\n }\n}\n\n/**\n * Builder for creating PluginType with type-safe output definitions.\n *\n * Use `PluginModel.define()` to create a builder instance.\n *\n * @typeParam Data - Plugin's persistent data type\n * @typeParam Params - Params derived from block's RenderCtx (optional)\n * @typeParam Config - Static configuration passed to plugin factory (optional)\n * @typeParam Outputs - Accumulated output types\n * @typeParam Versions - Version map from PluginDataModel (empty for function-based data)\n *\n * @example\n * const dataTable = PluginModel.define({\n * name: 'dataTable' as PluginName,\n * data: pluginDataModel,\n * })\n * .output('model', (ctx) => createTableModel(ctx))\n * .build();\n */\nclass PluginModelBuilder<\n Data extends PluginData = PluginData,\n Params extends PluginParams = undefined,\n Outputs extends PluginOutputs = PluginOutputs,\n Config extends PluginConfig = undefined,\n Versions extends Record<string, unknown> = {},\n ModelServices = {},\n UiServices = {},\n> {\n protected readonly name: PluginName;\n protected readonly dataFn: (config?: Config) => DataModel<Data>;\n protected readonly getDefaultDataFn?: (config?: Config) => DataVersioned<Data>;\n private readonly outputs: PluginOutputFns<Data, Params, Outputs, ModelServices, UiServices>;\n private readonly outputFlags: Record<string, { withStatus: boolean }>;\n protected readonly featureFlags?: BlockCodeKnownFeatureFlags;\n\n protected constructor(options: {\n name: PluginName;\n dataFn: (config?: Config) => DataModel<Data>;\n getDefaultDataFn?: (config?: Config) => DataVersioned<Data>;\n outputs?: PluginOutputFns<Data, Params, Outputs, ModelServices, UiServices>;\n outputFlags?: Record<string, { withStatus: boolean }>;\n featureFlags?: BlockCodeKnownFeatureFlags;\n }) {\n this.name = options.name;\n this.dataFn = options.dataFn;\n this.getDefaultDataFn = options.getDefaultDataFn;\n this.outputs =\n options.outputs ?? ({} as PluginOutputFns<Data, Params, Outputs, ModelServices, UiServices>);\n this.outputFlags = options.outputFlags ?? {};\n this.featureFlags = options.featureFlags;\n }\n\n /** @internal */\n static [FROM_BUILDER]<\n Data extends PluginData,\n Params extends PluginParams,\n Outputs extends PluginOutputs,\n Config extends PluginConfig,\n Versions extends Record<string, unknown> = {},\n ModelServices = {},\n UiServices = {},\n >(options: {\n name: PluginName;\n dataFn: (config?: Config) => DataModel<Data>;\n getDefaultDataFn?: (config?: Config) => DataVersioned<Data>;\n outputs?: PluginOutputFns<Data, Params, Outputs, ModelServices, UiServices>;\n outputFlags?: Record<string, { withStatus: boolean }>;\n featureFlags?: BlockCodeKnownFeatureFlags;\n }): PluginModelBuilder<Data, Params, Outputs, Config, Versions, ModelServices, UiServices> {\n return new PluginModelBuilder(options);\n }\n\n /**\n * Adds an output to the plugin.\n *\n * @param key - Output name\n * @param fn - Function that computes the output value from plugin context\n * @returns PluginModel with the new output added\n *\n * @example\n * .output('model', (ctx) => createModel(ctx.params.columns, ctx.data.state))\n * .output('isReady', (ctx) => ctx.params.columns !== undefined)\n */\n output<const Key extends string, T>(\n key: Key,\n fn: (\n ctx: PluginRenderCtx<\n PluginFactoryLike<Data, Params, Record<string, unknown>, ModelServices, UiServices>\n >,\n ) => T,\n ): PluginModelBuilder<\n Data,\n Params,\n Outputs & { [K in Key]: T },\n Config,\n Versions,\n ModelServices,\n UiServices\n > {\n return new PluginModelBuilder<\n Data,\n Params,\n Outputs & { [K in Key]: T },\n Config,\n Versions,\n ModelServices,\n UiServices\n >({\n name: this.name,\n dataFn: this.dataFn,\n getDefaultDataFn: this.getDefaultDataFn,\n featureFlags: this.featureFlags,\n outputs: {\n ...this.outputs,\n [key]: fn,\n } as {\n [K in keyof (Outputs & { [P in Key]: T })]: (\n ctx: PluginRenderCtx<\n PluginFactoryLike<Data, Params, Record<string, unknown>, ModelServices, UiServices>\n >,\n ) => (Outputs & { [P in Key]: T })[K];\n },\n outputFlags: { ...this.outputFlags, [key]: { withStatus: false } },\n });\n }\n\n /**\n * Adds an output wrapped with status information to the plugin.\n *\n * The UI receives the full {@link OutputWithStatus} object instead of an unwrapped value,\n * allowing it to distinguish between pending, success, and error states.\n *\n * @param key - Output name\n * @param fn - Function that computes the output value from plugin context\n * @returns PluginModel with the new status-wrapped output added\n *\n * @example\n * .outputWithStatus('table', (ctx) => {\n * const pCols = ctx.params.pFrame?.getPColumns();\n * if (pCols === undefined) return undefined;\n * return createPlDataTableV2(ctx, pCols, ctx.data.tableState);\n * })\n */\n outputWithStatus<const Key extends string, T>(\n key: Key,\n fn: (\n ctx: PluginRenderCtx<\n PluginFactoryLike<Data, Params, Record<string, unknown>, ModelServices, UiServices>\n >,\n ) => T,\n ): PluginModelBuilder<\n Data,\n Params,\n Outputs & { [K in Key]: OutputWithStatus<T> },\n Config,\n Versions,\n ModelServices,\n UiServices\n > {\n return new PluginModelBuilder<\n Data,\n Params,\n Outputs & { [K in Key]: OutputWithStatus<T> },\n Config,\n Versions,\n ModelServices,\n UiServices\n >({\n name: this.name,\n dataFn: this.dataFn,\n getDefaultDataFn: this.getDefaultDataFn,\n featureFlags: this.featureFlags,\n outputs: {\n ...this.outputs,\n [key]: fn,\n } as {\n [K in keyof (Outputs & { [P in Key]: OutputWithStatus<T> })]: (\n ctx: PluginRenderCtx<\n PluginFactoryLike<Data, Params, Record<string, unknown>, ModelServices, UiServices>\n >,\n ) => (Outputs & { [P in Key]: OutputWithStatus<T> })[K];\n },\n outputFlags: { ...this.outputFlags, [key]: { withStatus: true } },\n });\n }\n\n /**\n * Finalizes the plugin definition and returns a PluginFactory.\n *\n * @returns Plugin factory that creates named plugin instances via .create()\n *\n * @example\n * const myPlugin = PluginModel.define({ ... })\n * .output('value', (ctx) => ctx.data.value)\n * .build();\n *\n * // Create a named instance:\n * const table = myPlugin.create({ pluginId: 'mainTable', config: { ... } });\n */\n build(): PluginFactory<Data, Params, Outputs, Config, Versions, ModelServices, UiServices> {\n return PluginModelFactory[FROM_BUILDER]<\n Data,\n Params,\n Outputs,\n Config,\n Versions,\n ModelServices,\n UiServices\n >({\n name: this.name,\n dataFn: this.dataFn,\n getDefaultDataFn: this.getDefaultDataFn,\n outputs: this.outputs,\n outputFlags: this.outputFlags,\n featureFlags: this.featureFlags,\n });\n }\n}\n\n/**\n * Initial builder returned by PluginModel.define(). Extends PluginModelBuilder with .params().\n * Once .params() or .output() is called, transitions to PluginModelBuilder (no second .params()).\n */\nclass PluginModelInitialBuilder<\n Data extends PluginData = PluginData,\n Params extends PluginParams = undefined,\n Config extends PluginConfig = undefined,\n Versions extends Record<string, unknown> = {},\n ModelServices = {},\n UiServices = {},\n> extends PluginModelBuilder<Data, Params, {}, Config, Versions, ModelServices, UiServices> {\n /** @internal */\n static create<\n Data extends PluginData,\n Config extends PluginConfig,\n Versions extends Record<string, unknown> = {},\n ModelServices = {},\n UiServices = {},\n >(options: {\n name: PluginName;\n dataFn: (config?: Config) => DataModel<Data>;\n getDefaultDataFn?: (config?: Config) => DataVersioned<Data>;\n featureFlags?: BlockCodeKnownFeatureFlags;\n }): PluginModelInitialBuilder<Data, undefined, Config, Versions, ModelServices, UiServices> {\n return new PluginModelInitialBuilder(options);\n }\n\n /**\n * Sets the Params type for this plugin — the shape of data derived from the block's\n * render context and passed into plugin output functions via `ctx.params`.\n * Must be called before .output(). Available only on the initial builder.\n *\n * @example\n * .params<{ title: string }>()\n * .output('displayText', (ctx) => ctx.params.title)\n */\n params<P extends PluginParams>(): PluginModelBuilder<\n Data,\n P,\n {},\n Config,\n Versions,\n ModelServices,\n UiServices\n > {\n return PluginModelBuilder[FROM_BUILDER]<\n Data,\n P,\n {},\n Config,\n Versions,\n ModelServices,\n UiServices\n >({\n name: this.name,\n dataFn: this.dataFn,\n getDefaultDataFn: this.getDefaultDataFn,\n featureFlags: this.featureFlags,\n });\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"plugin_model.cjs","names":["DATA_MODEL_LEGACY_VERSION","DataModelBuilder"],"sources":["../src/plugin_model.ts"],"sourcesContent":["/**\n * PluginModel - Builder for creating plugin types with data model and outputs.\n *\n * Plugins are UI components with their own model logic and persistent state.\n * Block developers register plugin instances via BlockModelV3.plugin() method.\n *\n * @module plugin_model\n */\n\nimport type { BlockCodeKnownFeatureFlags, OutputWithStatus } from \"@milaboratories/pl-model-common\";\nimport type { ResolveModelServices, ResolveUiServices } from \"./services/service_resolve\";\nimport {\n type DataModel,\n DataModelBuilder,\n type DataRecoverFn,\n type DataVersioned,\n type TransferTarget,\n} from \"./block_migrations\";\nimport { type PluginName, DATA_MODEL_LEGACY_VERSION } from \"./block_storage\";\nimport type { PluginFactoryLike } from \"./plugin_handle\";\nimport type { PluginRenderCtx } from \"./render\";\n\n/** Symbol for internal builder creation method */\nconst FROM_BUILDER = Symbol(\"fromBuilder\");\n\n/** Output function signature for plugin render context. */\ntype PluginOutputFn<\n Data extends PluginData,\n Params extends PluginParams,\n ModelServices,\n UiServices,\n T,\n> = (\n ctx: PluginRenderCtx<\n PluginFactoryLike<Data, Params, Record<string, unknown>, ModelServices, UiServices>\n >,\n) => T;\n\n/** Mapped output functions for a plugin's outputs. */\ntype PluginOutputFns<\n Data extends PluginData,\n Params extends PluginParams,\n Outputs extends PluginOutputs,\n ModelServices,\n UiServices,\n> = {\n [K in keyof Outputs]: PluginOutputFn<Data, Params, ModelServices, UiServices, Outputs[K]>;\n};\n\n/** Symbol for internal plugin model creation — not accessible to external consumers */\nexport const CREATE_PLUGIN_MODEL = Symbol(\"createPluginModel\");\n\n/** Sentinel for PluginInstance without transferAt — no transfer possible. */\nconst NO_TRANSFER_VERSION = \"\";\n\n/**\n * Runtime definition for a single public output field.\n * Stored in PluginModel and passed through BlockModelInfo to the UI layer.\n */\nexport type PublicOutputFieldDef = {\n readonly getter: (data: unknown) => unknown;\n};\n\nexport type PublicOutputDef<PublicOutputs extends PluginPublicOutputs> = {\n [K in keyof PublicOutputs]: PublicOutputFieldDef;\n};\n\nexport type PluginData = Record<string, unknown>;\nexport type PluginParams = undefined | Record<string, unknown>;\nexport type PluginOutputs = Record<string, unknown>;\nexport type PluginPublicOutputs = Record<string, unknown>;\nexport type PluginConfig = undefined | Record<string, unknown>;\n\n/**\n * Plugin data model with typed migration chain and config-aware initialization.\n *\n * @typeParam Data - Current (latest) plugin data type\n * @typeParam Versions - Map of version keys to their data types (accumulated by the chain)\n * @typeParam Config - Config type passed to init function (undefined if none)\n */\nexport class PluginDataModel<\n Data extends PluginData,\n Versions extends Record<string, unknown> = {},\n Config = undefined,\n> {\n readonly dataModel: DataModel<Data>;\n private readonly configInitFn: (config?: Config) => Data;\n\n /** @internal Phantom field to anchor the Versions type parameter. */\n declare readonly __versions?: Versions;\n\n private constructor(dataModel: DataModel<Data>, configInitFn: (config?: Config) => Data) {\n this.dataModel = dataModel;\n this.configInitFn = configInitFn;\n }\n\n /** @internal */\n static [FROM_BUILDER]<Data extends PluginData, Versions extends Record<string, unknown>, Config>(\n dataModel: DataModel<Data>,\n configInitFn: (config?: Config) => Data,\n ): PluginDataModel<Data, Versions, Config> {\n return new PluginDataModel<Data, Versions, Config>(dataModel, configInitFn);\n }\n\n /** Create fresh data with optional config. */\n getDefaultData(config?: Config): DataVersioned<Data> {\n const data = this.configInitFn(config);\n return { version: this.dataModel.version, data };\n }\n}\n\n/** Internal state for plugin data model chain. */\ntype PluginChainState = {\n initialVersion: string;\n migrations: Array<{ toVersion: string; fn: (data: unknown) => unknown }>;\n recoverFn?: (version: string, data: unknown) => unknown;\n recoverAtIndex?: number;\n};\n\n/** Version → persisted data shape for each migration step (third generic of `PluginModel.define` when `data` is a `PluginDataModel`). */\nexport type PluginDataModelVersions<\n M extends PluginDataModel<PluginData, Record<string, unknown>, unknown>,\n> = M extends PluginDataModel<PluginData, infer Versions, unknown> ? Versions : never;\n\n/**\n * Builder for creating PluginDataModel with type-safe migrations.\n * Mirrors DataModelBuilder — same .from(), .migrate(), .recover(), .init() chain.\n *\n * @example\n * const pluginData = new PluginDataModelBuilder()\n * .from<TableData>(\"v1\")\n * .migrate<FilteredTableData>(\"v2\", (v1) => ({ ...v1, filters: [] }))\n * .init<TableConfig>((config?) => ({\n * state: createDefaultState(config?.ops),\n * filters: [],\n * }));\n */\nexport class PluginDataModelBuilder {\n from<Data extends PluginData, const V extends string>(\n version: V,\n ): PluginDataModelInitialChain<Data, Record<V, Data>> {\n return PluginDataModelInitialChain[FROM_BUILDER]<Data, Record<V, Data>>({\n initialVersion: version,\n migrations: [],\n });\n }\n}\n\n/**\n * Chain returned by .migrate(). Supports .migrate(), .recover(), .init().\n * No .upgradeLegacy() — that is only available on the initial chain.\n */\nexport class PluginDataModelChain<\n Data extends PluginData,\n Versions extends Record<string, unknown>,\n> {\n protected constructor(protected readonly state: PluginChainState) {}\n\n /** @internal */\n static [FROM_BUILDER]<Data extends PluginData, Versions extends Record<string, unknown>>(\n state: PluginChainState,\n ): PluginDataModelChain<Data, Versions> {\n return new PluginDataModelChain(state);\n }\n\n /**\n * Add a migration step transforming data from the current version to the next.\n */\n migrate<Next extends PluginData, const NextV extends string>(\n version: NextV,\n fn: (current: Data) => Next,\n ): PluginDataModelChain<Next, Versions & Record<NextV, Next>> {\n return PluginDataModelChain[FROM_BUILDER]<Next, Versions & Record<NextV, Next>>({\n ...this.state,\n migrations: [\n ...this.state.migrations,\n { toVersion: version, fn: fn as (data: unknown) => unknown },\n ],\n });\n }\n\n /**\n * Set a recovery handler for unknown or legacy versions.\n * Can only be called once — the returned chain has no recover() method.\n */\n recover(fn: DataRecoverFn<Data>): PluginDataModelWithRecover<Data, Versions> {\n return PluginDataModelWithRecover[FROM_BUILDER]<Data, Versions>({\n ...this.state,\n recoverFn: fn as (version: string, data: unknown) => unknown,\n recoverAtIndex: this.state.migrations.length,\n });\n }\n\n /** Finalize the PluginDataModel. */\n init<Config = undefined>(fn: (config?: Config) => Data): PluginDataModel<Data, Versions, Config> {\n return buildPluginDataModel(this.state, fn);\n }\n}\n\n/**\n * Initial chain returned by new PluginDataModelBuilder().from().\n * Extends PluginDataModelChain with .upgradeLegacy() — available only before\n * any .migrate() calls, matching the block's DataModelInitialChain pattern.\n */\nexport class PluginDataModelInitialChain<\n Data extends PluginData,\n Versions extends Record<string, unknown>,\n> extends PluginDataModelChain<Data, Versions> {\n /** @internal */\n static override [FROM_BUILDER]<Data extends PluginData, Versions extends Record<string, unknown>>(\n state: PluginChainState,\n ): PluginDataModelInitialChain<Data, Versions> {\n return new PluginDataModelInitialChain(state);\n }\n\n /**\n * Handle data from a previous plugin type occupying this slot.\n * Prepends a migration from DATA_MODEL_LEGACY_VERSION to the initial version.\n * When a plugin type changes, the old data arrives with DATA_MODEL_LEGACY_VERSION —\n * this function transforms it into the initial version, then the normal chain runs.\n *\n * Must be called right after .from() — not available after .migrate().\n * Mutually exclusive with recover().\n *\n * @param fn - Transform from old plugin's raw data to this plugin's initial data type\n */\n upgradeLegacy(fn: (data: unknown) => Data): PluginDataModelWithRecover<Data, Versions> {\n return PluginDataModelWithRecover[FROM_BUILDER]<Data, Versions>({\n ...this.state,\n migrations: [\n { toVersion: this.state.initialVersion, fn: fn as (data: unknown) => unknown },\n ...this.state.migrations,\n ],\n initialVersion: DATA_MODEL_LEGACY_VERSION,\n });\n }\n}\n\n/**\n * Chain after .recover() — supports .migrate(), .init(). No second recover().\n */\nexport class PluginDataModelWithRecover<\n Data extends PluginData,\n Versions extends Record<string, unknown>,\n> {\n private constructor(private readonly state: PluginChainState) {}\n\n /** @internal */\n static [FROM_BUILDER]<Data extends PluginData, Versions extends Record<string, unknown>>(\n state: PluginChainState,\n ): PluginDataModelWithRecover<Data, Versions> {\n return new PluginDataModelWithRecover(state);\n }\n\n migrate<Next extends PluginData, const NextV extends string>(\n version: NextV,\n fn: (current: Data) => Next,\n ): PluginDataModelWithRecover<Next, Versions & Record<NextV, Next>> {\n return PluginDataModelWithRecover[FROM_BUILDER]<Next, Versions & Record<NextV, Next>>({\n ...this.state,\n migrations: [\n ...this.state.migrations,\n { toVersion: version, fn: fn as (data: unknown) => unknown },\n ],\n });\n }\n\n init<Config = undefined>(fn: (config?: Config) => Data): PluginDataModel<Data, Versions, Config> {\n return buildPluginDataModel(this.state, fn);\n }\n}\n\n/**\n * Builds a PluginDataModel by replaying the stored chain state through DataModelBuilder.\n * @internal\n */\nfunction buildPluginDataModel<\n Data extends PluginData,\n Versions extends Record<string, unknown>,\n Config,\n>(\n state: PluginChainState,\n configInitFn: (config?: Config) => Data,\n): PluginDataModel<Data, Versions, Config> {\n // Build inner DataModel by replaying migrations through DataModelBuilder chain.\n // Uses `any` internally — type safety is maintained by the public chain types.\n let chain: any = new DataModelBuilder().from(state.initialVersion);\n\n for (let i = 0; i < state.migrations.length; i++) {\n if (state.recoverFn !== undefined && state.recoverAtIndex === i) {\n chain = chain.recover(state.recoverFn);\n }\n chain = chain.migrate(state.migrations[i].toVersion, state.migrations[i].fn);\n }\n\n // If recover was placed at or after the last migration\n if (state.recoverFn !== undefined && state.recoverAtIndex === state.migrations.length) {\n chain = chain.recover(state.recoverFn);\n }\n\n const dataModel: DataModel<Data> = chain.init(() => configInitFn());\n\n return PluginDataModel[FROM_BUILDER]<Data, Versions, Config>(dataModel, configInitFn);\n}\n\n/**\n * A named plugin instance created by `factory.create({ pluginId, ... })`.\n * Passed to both `.transfer()` (on migration chain) and `.plugin()` (on BlockModelV3).\n * Implements TransferTarget so the migration chain can accept it.\n *\n * @typeParam Id - Plugin instance ID literal type\n * @typeParam Data - Plugin data type\n * @typeParam Params - Plugin params type\n * @typeParam Outputs - Plugin outputs type\n * @typeParam TransferData - Type of data entering the plugin via transfer (never if no transfer)\n */\nexport class PluginInstance<\n Id extends string = string,\n Data extends PluginData = PluginData,\n Params extends PluginParams = undefined,\n Outputs extends PluginOutputs = PluginOutputs,\n PublicOutputs extends PluginPublicOutputs = PluginPublicOutputs,\n TransferData = never,\n ModelServices = unknown,\n UiServices = unknown,\n> implements TransferTarget<Id, TransferData> {\n readonly id: Id;\n readonly transferVersion: string;\n /** @internal Phantom for type inference; never set at runtime. */\n readonly __instanceTypes?: {\n data: Data;\n params: Params;\n outputs: Outputs;\n modelServices: ModelServices;\n uiServices: UiServices;\n publicOutputs: PublicOutputs;\n };\n /** Bound closure that creates the PluginModel. Config is captured at factory.create() time. */\n private readonly createPluginModel: () => PluginModel<\n Data,\n Params,\n Outputs,\n PublicOutputs,\n ModelServices,\n UiServices\n >;\n\n private constructor(\n id: Id,\n createPluginModel: () => PluginModel<\n Data,\n Params,\n Outputs,\n PublicOutputs,\n ModelServices,\n UiServices\n >,\n transferVersion: string,\n ) {\n this.id = id;\n this.createPluginModel = createPluginModel;\n this.transferVersion = transferVersion;\n }\n\n /** @internal Accepts concrete Config — binds it into a closure, avoiding Config variance issues. */\n static [FROM_BUILDER]<\n Id extends string,\n Data extends PluginData,\n Params extends PluginParams,\n Outputs extends PluginOutputs,\n PublicOutputs extends PluginPublicOutputs = PluginPublicOutputs,\n TransferData = never,\n Config extends PluginConfig = PluginConfig,\n ModelServices = unknown,\n UiServices = unknown,\n >(\n id: Id,\n factory: PluginModelFactory<\n Data,\n Params,\n Outputs,\n PublicOutputs,\n Config,\n Record<string, unknown>,\n ModelServices,\n UiServices\n >,\n transferVersion: string,\n config?: Config,\n ): PluginInstance<\n Id,\n Data,\n Params,\n Outputs,\n PublicOutputs,\n TransferData,\n ModelServices,\n UiServices\n > {\n return new PluginInstance(id, () => factory[CREATE_PLUGIN_MODEL](config), transferVersion);\n }\n\n /** @internal Create a PluginModel from this instance. Used by BlockModelV3.plugin(). */\n [CREATE_PLUGIN_MODEL](): PluginModel<\n Data,\n Params,\n Outputs,\n PublicOutputs,\n ModelServices,\n UiServices\n > {\n return this.createPluginModel();\n }\n}\n\n/**\n * Configured plugin instance returned by PluginModelFactory[CREATE_PLUGIN_MODEL]().\n * Contains the plugin's name, data model, and output definitions.\n */\nexport class PluginModel<\n Data extends PluginData = PluginData,\n Params extends PluginParams = undefined,\n Outputs extends PluginOutputs = PluginOutputs,\n PublicOutputs extends PluginPublicOutputs = PluginPublicOutputs,\n ModelServices = {},\n UiServices = {},\n> {\n /** Globally unique plugin name */\n readonly name: PluginName;\n /** Data model instance for this plugin */\n readonly dataModel: DataModel<Data>;\n /** Output definitions - functions that compute outputs from plugin context */\n readonly outputs: PluginOutputFns<Data, Params, Outputs, ModelServices, UiServices>;\n /** Feature flags declared by this plugin */\n readonly featureFlags?: BlockCodeKnownFeatureFlags;\n /** Create fresh default data. Config (if any) is captured at creation time. */\n readonly getDefaultData: () => DataVersioned<Data>;\n /** Public output definitions — accessible without usePlugin() via app.plugins */\n readonly publicOutputDef: PublicOutputDef<PublicOutputs>;\n\n private constructor(options: {\n name: PluginName;\n dataModel: DataModel<Data>;\n outputs: PluginOutputFns<Data, Params, Outputs, ModelServices, UiServices>;\n featureFlags?: BlockCodeKnownFeatureFlags;\n getDefaultData: () => DataVersioned<Data>;\n publicOutputDef: PublicOutputDef<PublicOutputs>;\n }) {\n this.name = options.name;\n this.dataModel = options.dataModel;\n this.outputs = options.outputs;\n this.featureFlags = options.featureFlags;\n this.getDefaultData = options.getDefaultData;\n this.publicOutputDef = options.publicOutputDef;\n }\n\n /**\n * Internal method for creating PluginModel from factory.\n * Uses Symbol key to prevent external access.\n * @internal\n */\n static [FROM_BUILDER]<\n Data extends PluginData,\n Params extends PluginParams,\n Outputs extends PluginOutputs,\n PublicOutputs extends PluginPublicOutputs = PluginPublicOutputs,\n ModelServices = {},\n UiServices = {},\n >(options: {\n name: PluginName;\n dataModel: DataModel<Data>;\n outputs: PluginOutputFns<Data, Params, Outputs, ModelServices, UiServices>;\n featureFlags?: BlockCodeKnownFeatureFlags;\n getDefaultData: () => DataVersioned<Data>;\n publicOutputDef: PublicOutputDef<PublicOutputs>;\n }): PluginModel<Data, Params, Outputs, PublicOutputs, ModelServices, UiServices> {\n return new PluginModel<Data, Params, Outputs, PublicOutputs, ModelServices, UiServices>(\n options,\n );\n }\n\n /**\n * Creates a new PluginModelBuilder with a PluginDataModel (supports transfer / config).\n *\n * @example\n * const pluginData = new PluginDataModelBuilder().from<TableData>(\"v1\")\n * .migrate<FilteredTableData>(\"v2\", (v1) => ({ ...v1, filters: [] }))\n * .init<TableConfig>((config?) => ({\n * state: createDefaultState(config?.ops),\n * filters: [],\n * }));\n *\n * const myPlugin = PluginModel.define({\n * name: 'myPlugin' as PluginName,\n * data: pluginData,\n * }).build();\n */\n static define<\n Data extends PluginData,\n Params extends PluginParams = undefined,\n Versions extends Record<string, unknown> = {},\n Config extends PluginConfig = undefined,\n Flags extends BlockCodeKnownFeatureFlags = {},\n >(options: {\n name: PluginName;\n data: PluginDataModel<Data, Versions, Config>;\n featureFlags?: Flags;\n }): PluginModelInitialBuilder<\n Data,\n Params,\n Config,\n Versions,\n ResolveModelServices<Flags>,\n ResolveUiServices<Flags>\n >;\n /**\n * Creates a new PluginModelBuilder with a data model factory function (backward compatible).\n *\n * @example\n * const myPlugin = PluginModel.define({\n * name: 'myPlugin' as PluginName,\n * data: (cfg) => dataModelChain.init(() => ({ value: cfg.defaultValue })),\n * }).build();\n */\n static define<\n Data extends PluginData,\n Params extends PluginParams = undefined,\n Config extends PluginConfig = undefined,\n Flags extends BlockCodeKnownFeatureFlags = {},\n >(options: {\n name: PluginName;\n data: (config?: Config) => DataModel<Data>;\n featureFlags?: Flags;\n }): PluginModelInitialBuilder<\n Data,\n Params,\n Config,\n {},\n ResolveModelServices<Flags>,\n ResolveUiServices<Flags>\n >;\n static define(options: {\n name: PluginName;\n data: PluginDataModel<any, any, any> | ((config?: any) => DataModel<any>);\n featureFlags?: BlockCodeKnownFeatureFlags;\n }): PluginModelInitialBuilder {\n if (options.data instanceof PluginDataModel) {\n const pdm = options.data;\n return PluginModelInitialBuilder.create({\n name: options.name,\n dataFn: () => pdm.dataModel,\n getDefaultDataFn: (config: any) => pdm.getDefaultData(config),\n featureFlags: options.featureFlags,\n });\n }\n return PluginModelInitialBuilder.create({\n name: options.name,\n dataFn: options.data,\n featureFlags: options.featureFlags,\n });\n }\n}\n\n/** Plugin factory returned by PluginModelBuilder.build(). */\nexport interface PluginFactory<\n Data extends PluginData = PluginData,\n Params extends PluginParams = undefined,\n Outputs extends PluginOutputs = PluginOutputs,\n PublicOutputs extends PluginPublicOutputs = PluginPublicOutputs,\n Config extends PluginConfig = undefined,\n Versions extends Record<string, unknown> = {},\n ModelServices = {},\n UiServices = {},\n> extends PluginFactoryLike<Data, Params, Outputs, ModelServices, UiServices> {\n /** Create a named plugin instance, optionally with transfer at a specific version. */\n create<const Id extends string, const V extends string & keyof Versions = never>(options: {\n pluginId: Id;\n transferAt?: V;\n config?: Config;\n }): PluginInstance<\n Id,\n Data,\n Params,\n Outputs,\n PublicOutputs,\n Versions[V],\n ModelServices,\n UiServices\n >;\n\n /** Public output field definitions declared via .publicOutput(). */\n readonly publicOutputDef: PublicOutputDef<PublicOutputs>;\n\n /**\n * @internal Phantom field for structural type extraction.\n * Enables InferFactoryData/InferFactoryOutputs to work via PluginFactoryLike.\n */\n readonly __types?: {\n data: Data;\n params: Params;\n outputs: Outputs;\n modelServices: ModelServices;\n uiServices: UiServices;\n config: Config;\n versions: Versions;\n publicOutputs: PublicOutputs;\n };\n}\n\nclass PluginModelFactory<\n Data extends PluginData = PluginData,\n Params extends PluginParams = undefined,\n Outputs extends PluginOutputs = PluginOutputs,\n PublicOutputs extends PluginPublicOutputs = PluginPublicOutputs,\n Config extends PluginConfig = undefined,\n Versions extends Record<string, unknown> = {},\n ModelServices = {},\n UiServices = {},\n> implements PluginFactory<\n Data,\n Params,\n Outputs,\n PublicOutputs,\n Config,\n Versions,\n ModelServices,\n UiServices\n> {\n private readonly name: PluginName;\n private readonly dataFn: (config?: Config) => DataModel<Data>;\n private readonly getDefaultDataFn?: (config?: Config) => DataVersioned<Data>;\n readonly outputs: PluginOutputFns<Data, Params, Outputs, ModelServices, UiServices>;\n private readonly featureFlags?: BlockCodeKnownFeatureFlags;\n readonly publicOutputDef: PublicOutputDef<PublicOutputs>;\n\n private constructor(options: {\n name: PluginName;\n dataFn: (config?: Config) => DataModel<Data>;\n getDefaultDataFn?: (config?: Config) => DataVersioned<Data>;\n outputs: PluginOutputFns<Data, Params, Outputs, ModelServices, UiServices>;\n featureFlags?: BlockCodeKnownFeatureFlags;\n publicOutputDef: PublicOutputDef<PublicOutputs>;\n }) {\n this.name = options.name;\n this.dataFn = options.dataFn;\n this.getDefaultDataFn = options.getDefaultDataFn;\n this.outputs = options.outputs;\n this.featureFlags = options.featureFlags;\n this.publicOutputDef = options.publicOutputDef;\n }\n\n /** @internal */\n static [FROM_BUILDER]<\n Data extends PluginData,\n Params extends PluginParams,\n Outputs extends PluginOutputs,\n PublicOutputs extends PluginPublicOutputs = PluginPublicOutputs,\n Config extends PluginConfig = undefined,\n Versions extends Record<string, unknown> = {},\n ModelServices = {},\n UiServices = {},\n >(options: {\n name: PluginName;\n dataFn: (config?: Config) => DataModel<Data>;\n getDefaultDataFn?: (config?: Config) => DataVersioned<Data>;\n outputs: PluginOutputFns<Data, Params, Outputs, ModelServices, UiServices>;\n featureFlags?: BlockCodeKnownFeatureFlags;\n publicOutputDef: PublicOutputDef<PublicOutputs>;\n }): PluginModelFactory<\n Data,\n Params,\n Outputs,\n PublicOutputs,\n Config,\n Versions,\n ModelServices,\n UiServices\n > {\n return new PluginModelFactory(options);\n }\n\n create<const Id extends string, const V extends string & keyof Versions = never>(options: {\n pluginId: Id;\n transferAt?: V;\n config?: Config;\n }): PluginInstance<\n Id,\n Data,\n Params,\n Outputs,\n PublicOutputs,\n Versions[V],\n ModelServices,\n UiServices\n > {\n const transferVersion = options.transferAt ?? NO_TRANSFER_VERSION;\n return PluginInstance[FROM_BUILDER]<\n Id,\n Data,\n Params,\n Outputs,\n PublicOutputs,\n Versions[V],\n Config,\n ModelServices,\n UiServices\n >(options.pluginId as Id, this, transferVersion, options.config);\n }\n\n /** @internal Create a PluginModel from config. Config is captured in getDefaultData closure. */\n [CREATE_PLUGIN_MODEL](\n config?: Config,\n ): PluginModel<Data, Params, Outputs, PublicOutputs, ModelServices, UiServices> {\n const dataModel = this.dataFn(config);\n const getDefaultDataFn = this.getDefaultDataFn;\n return PluginModel[FROM_BUILDER]<\n Data,\n Params,\n Outputs,\n PublicOutputs,\n ModelServices,\n UiServices\n >({\n name: this.name,\n dataModel,\n outputs: this.outputs,\n featureFlags: this.featureFlags,\n getDefaultData: getDefaultDataFn\n ? () => getDefaultDataFn(config)\n : () => dataModel.getDefaultData(),\n publicOutputDef: this.publicOutputDef,\n });\n }\n}\n\n/**\n * Builder for creating PluginType with type-safe output definitions.\n *\n * Use `PluginModel.define()` to create a builder instance.\n *\n * @typeParam Data - Plugin's persistent data type\n * @typeParam Params - Params derived from block's RenderCtx (optional)\n * @typeParam Config - Static configuration passed to plugin factory (optional)\n * @typeParam Outputs - Accumulated output types\n * @typeParam Versions - Version map from PluginDataModel (empty for function-based data)\n *\n * @example\n * const dataTable = PluginModel.define({\n * name: 'dataTable' as PluginName,\n * data: pluginDataModel,\n * })\n * .output('model', (ctx) => createTableModel(ctx))\n * .build();\n */\nclass PluginModelBuilder<\n Data extends PluginData = PluginData,\n Params extends PluginParams = undefined,\n Outputs extends PluginOutputs = PluginOutputs,\n PublicOutputs extends PluginPublicOutputs = PluginPublicOutputs,\n Config extends PluginConfig = undefined,\n Versions extends Record<string, unknown> = {},\n ModelServices = {},\n UiServices = {},\n> {\n protected readonly name: PluginName;\n protected readonly dataFn: (config?: Config) => DataModel<Data>;\n protected readonly getDefaultDataFn?: (config?: Config) => DataVersioned<Data>;\n private readonly outputs: PluginOutputFns<Data, Params, Outputs, ModelServices, UiServices>;\n protected readonly featureFlags?: BlockCodeKnownFeatureFlags;\n private readonly publicOutputDef: PublicOutputDef<PublicOutputs>;\n\n protected constructor(options: {\n name: PluginName;\n dataFn: (config?: Config) => DataModel<Data>;\n getDefaultDataFn?: (config?: Config) => DataVersioned<Data>;\n outputs?: PluginOutputFns<Data, Params, Outputs, ModelServices, UiServices>;\n featureFlags?: BlockCodeKnownFeatureFlags;\n publicOutputDef: PublicOutputDef<PublicOutputs>;\n }) {\n this.name = options.name;\n this.dataFn = options.dataFn;\n this.getDefaultDataFn = options.getDefaultDataFn;\n this.outputs =\n options.outputs ?? ({} as PluginOutputFns<Data, Params, Outputs, ModelServices, UiServices>);\n this.featureFlags = options.featureFlags;\n this.publicOutputDef = options.publicOutputDef;\n }\n\n /** @internal */\n static [FROM_BUILDER]<\n Data extends PluginData,\n Params extends PluginParams,\n Outputs extends PluginOutputs,\n PublicOutputs extends PluginPublicOutputs = PluginPublicOutputs,\n Config extends PluginConfig = undefined,\n Versions extends Record<string, unknown> = {},\n ModelServices = {},\n UiServices = {},\n >(options: {\n name: PluginName;\n dataFn: (config?: Config) => DataModel<Data>;\n getDefaultDataFn?: (config?: Config) => DataVersioned<Data>;\n outputs?: PluginOutputFns<Data, Params, Outputs, ModelServices, UiServices>;\n featureFlags?: BlockCodeKnownFeatureFlags;\n publicOutputDef: PublicOutputDef<PublicOutputs>;\n }): PluginModelBuilder<\n Data,\n Params,\n Outputs,\n PublicOutputs,\n Config,\n Versions,\n ModelServices,\n UiServices\n > {\n return new PluginModelBuilder(options);\n }\n\n /**\n * Adds an output to the plugin.\n * All plugin outputs are always wrapped with status — the UI receives\n * {@link OutputWithStatus} for every output, allowing it to distinguish\n * between pending, success, and error states.\n *\n * @param key - Output name\n * @param fn - Function that computes the output value from plugin context\n * @returns Builder with the new output added\n *\n * @example\n * .output('model', (ctx) => createModel(ctx.params.columns, ctx.data.state))\n * .output('pFrame', (ctx) => ctx.createPFrame([...]))\n */\n output<const Key extends string, T>(\n key: Key,\n fn: (\n ctx: PluginRenderCtx<\n PluginFactoryLike<Data, Params, Record<string, unknown>, ModelServices, UiServices>\n >,\n ) => T,\n ): PluginModelBuilder<\n Data,\n Params,\n Outputs & { [K in Key]: OutputWithStatus<T> },\n PublicOutputs,\n Config,\n Versions,\n ModelServices,\n UiServices\n > {\n return new PluginModelBuilder<\n Data,\n Params,\n Outputs & { [K in Key]: OutputWithStatus<T> },\n PublicOutputs,\n Config,\n Versions,\n ModelServices,\n UiServices\n >({\n name: this.name,\n dataFn: this.dataFn,\n getDefaultDataFn: this.getDefaultDataFn,\n featureFlags: this.featureFlags,\n outputs: {\n ...this.outputs,\n [key]: fn,\n } as unknown as PluginOutputFns<\n Data,\n Params,\n Outputs & { [P in Key]: OutputWithStatus<T> },\n ModelServices,\n UiServices\n >,\n publicOutputDef: this.publicOutputDef,\n });\n }\n\n /**\n * Exposes a plugin data field as a public output — accessible without `usePlugin()`\n * via `app.plugins.pluginName.publicOutputs.key`.\n *\n * The getter runs against the plugin's reactive data object.\n * Public outputs are read-only.\n *\n * @param key - Name of the public output field\n * @param getter - Function deriving the value from plugin data\n *\n * @example\n * .publicOutput('selection', (d) => d.selection)\n */\n publicOutput<const Key extends string, T>(\n key: Key,\n getter: (data: Data) => T,\n ): PluginModelBuilder<\n Data,\n Params,\n Outputs,\n PublicOutputs & { [K in Key]: T },\n Config,\n Versions,\n ModelServices,\n UiServices\n > {\n return new PluginModelBuilder<\n Data,\n Params,\n Outputs,\n PublicOutputs & { [K in Key]: T },\n Config,\n Versions,\n ModelServices,\n UiServices\n >({\n name: this.name,\n dataFn: this.dataFn,\n getDefaultDataFn: this.getDefaultDataFn,\n featureFlags: this.featureFlags,\n outputs: this.outputs,\n publicOutputDef: {\n ...this.publicOutputDef,\n [key]: { getter: getter as (data: unknown) => unknown },\n } as PublicOutputDef<PublicOutputs & { [K in Key]: T }>,\n });\n }\n\n /**\n * Finalizes the plugin definition and returns a PluginFactory.\n *\n * @returns Plugin factory that creates named plugin instances via .create()\n *\n * @example\n * const myPlugin = PluginModel.define({ ... })\n * .output('value', (ctx) => ctx.data.value)\n * .build();\n *\n * // Create a named instance:\n * const table = myPlugin.create({ pluginId: 'mainTable', config: { ... } });\n */\n build(): PluginFactory<\n Data,\n Params,\n Outputs,\n PublicOutputs,\n Config,\n Versions,\n ModelServices,\n UiServices\n > {\n return PluginModelFactory[FROM_BUILDER]<\n Data,\n Params,\n Outputs,\n PublicOutputs,\n Config,\n Versions,\n ModelServices,\n UiServices\n >({\n name: this.name,\n dataFn: this.dataFn,\n getDefaultDataFn: this.getDefaultDataFn,\n outputs: this.outputs,\n publicOutputDef: this.publicOutputDef,\n featureFlags: this.featureFlags,\n });\n }\n}\n\n/**\n * Initial builder returned by PluginModel.define(). Extends PluginModelBuilder with .params().\n * Once .params() or .output() is called, transitions to PluginModelBuilder (no second .params()).\n */\nclass PluginModelInitialBuilder<\n Data extends PluginData = PluginData,\n Params extends PluginParams = undefined,\n Config extends PluginConfig = undefined,\n Versions extends Record<string, unknown> = {},\n ModelServices = {},\n UiServices = {},\n> extends PluginModelBuilder<Data, Params, {}, {}, Config, Versions, ModelServices, UiServices> {\n /** @internal */\n static create<\n Data extends PluginData,\n Config extends PluginConfig,\n Versions extends Record<string, unknown> = {},\n ModelServices = {},\n UiServices = {},\n >(options: {\n name: PluginName;\n dataFn: (config?: Config) => DataModel<Data>;\n getDefaultDataFn?: (config?: Config) => DataVersioned<Data>;\n featureFlags?: BlockCodeKnownFeatureFlags;\n }): PluginModelInitialBuilder<Data, undefined, Config, Versions, ModelServices, UiServices> {\n return new PluginModelInitialBuilder({ ...options, publicOutputDef: {} });\n }\n\n /**\n * Sets the Params type for this plugin — the shape of data derived from the block's\n * render context and passed into plugin output functions via `ctx.params`.\n * Must be called before .output(). Available only on the initial builder.\n *\n * @example\n * .params<{ title: string }>()\n * .output('displayText', (ctx) => ctx.params.title)\n */\n params<P extends PluginParams>(): PluginModelBuilder<\n Data,\n P,\n {},\n {},\n Config,\n Versions,\n ModelServices,\n UiServices\n > {\n return PluginModelBuilder[FROM_BUILDER]<\n Data,\n P,\n {},\n {},\n Config,\n Versions,\n ModelServices,\n UiServices\n >({\n name: this.name,\n dataFn: this.dataFn,\n getDefaultDataFn: this.getDefaultDataFn,\n featureFlags: this.featureFlags,\n publicOutputDef: {},\n });\n }\n}\n"],"mappings":"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"}