@ai-matrx/alchemy 0.12.3 → 0.14.0

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 (105) hide show
  1. package/CHANGELOG.md +46 -0
  2. package/dist/actions.cjs.map +1 -1
  3. package/dist/actions.d.cts +19 -24
  4. package/dist/actions.d.ts +19 -24
  5. package/dist/actions.js.map +1 -1
  6. package/dist/checks.d.cts +2 -0
  7. package/dist/checks.d.ts +2 -0
  8. package/dist/core.cjs +4 -4
  9. package/dist/core.cjs.map +1 -1
  10. package/dist/core.d.cts +8 -58
  11. package/dist/core.d.ts +8 -58
  12. package/dist/core.js +4 -4
  13. package/dist/core.js.map +1 -1
  14. package/dist/declare/schema.json +3 -0
  15. package/dist/declare.cjs +1 -1
  16. package/dist/declare.cjs.map +1 -1
  17. package/dist/declare.d.cts +26 -1
  18. package/dist/declare.d.ts +26 -1
  19. package/dist/declare.js +1 -1
  20. package/dist/declare.js.map +1 -1
  21. package/dist/index.cjs +4 -4
  22. package/dist/index.cjs.map +1 -1
  23. package/dist/index.d.cts +8 -58
  24. package/dist/index.d.ts +8 -58
  25. package/dist/index.js +4 -4
  26. package/dist/index.js.map +1 -1
  27. package/dist/menu.d.cts +17 -22
  28. package/dist/menu.d.ts +17 -22
  29. package/dist/operate-document.cjs +2 -2
  30. package/dist/operate-document.cjs.map +1 -1
  31. package/dist/operate-document.d.cts +4 -42
  32. package/dist/operate-document.d.ts +4 -42
  33. package/dist/operate-document.js +2 -2
  34. package/dist/operate-document.js.map +1 -1
  35. package/dist/operate-rich-html.cjs +1 -1
  36. package/dist/operate-rich-html.cjs.map +1 -1
  37. package/dist/operate-rich-html.d.cts +3 -42
  38. package/dist/operate-rich-html.d.ts +3 -42
  39. package/dist/operate-rich-html.js +1 -1
  40. package/dist/operate-rich-html.js.map +1 -1
  41. package/dist/operate-server.cjs +1 -1
  42. package/dist/operate-server.cjs.map +1 -1
  43. package/dist/operate-server.d.cts +8 -46
  44. package/dist/operate-server.d.ts +8 -46
  45. package/dist/operate-server.js +1 -1
  46. package/dist/operate-server.js.map +1 -1
  47. package/dist/operate-xlsx.cjs +2 -2
  48. package/dist/operate-xlsx.cjs.map +1 -1
  49. package/dist/operate-xlsx.d.cts +4 -42
  50. package/dist/operate-xlsx.d.ts +4 -42
  51. package/dist/operate-xlsx.js +2 -2
  52. package/dist/operate-xlsx.js.map +1 -1
  53. package/dist/operate.cjs +4 -4
  54. package/dist/operate.cjs.map +1 -1
  55. package/dist/operate.d.cts +8 -58
  56. package/dist/operate.d.ts +8 -58
  57. package/dist/operate.js +4 -4
  58. package/dist/operate.js.map +1 -1
  59. package/dist/ports.d.cts +11 -15
  60. package/dist/ports.d.ts +11 -15
  61. package/dist/react-bar.cjs.map +1 -1
  62. package/dist/react-bar.d.cts +3 -1
  63. package/dist/react-bar.d.ts +3 -1
  64. package/dist/react-bar.js.map +1 -1
  65. package/dist/react-host.d.cts +17 -22
  66. package/dist/react-host.d.ts +17 -22
  67. package/dist/react-menu.cjs.map +1 -1
  68. package/dist/react-menu.d.cts +3 -1
  69. package/dist/react-menu.d.ts +3 -1
  70. package/dist/react-menu.js.map +1 -1
  71. package/dist/react-overflow.cjs.map +1 -1
  72. package/dist/react-overflow.d.cts +17 -22
  73. package/dist/react-overflow.d.ts +17 -22
  74. package/dist/react-overflow.js.map +1 -1
  75. package/dist/react-palette.cjs.map +1 -1
  76. package/dist/react-palette.d.cts +3 -1
  77. package/dist/react-palette.d.ts +3 -1
  78. package/dist/react-palette.js.map +1 -1
  79. package/dist/react-selection.cjs.map +1 -1
  80. package/dist/react-selection.d.cts +3 -1
  81. package/dist/react-selection.d.ts +3 -1
  82. package/dist/react-selection.js.map +1 -1
  83. package/dist/react-sheet.cjs.map +1 -1
  84. package/dist/react-sheet.d.cts +3 -1
  85. package/dist/react-sheet.d.ts +3 -1
  86. package/dist/react-sheet.js.map +1 -1
  87. package/dist/react-workspace.cjs +7 -0
  88. package/dist/react-workspace.cjs.map +1 -0
  89. package/dist/react-workspace.d.cts +441 -0
  90. package/dist/react-workspace.d.ts +441 -0
  91. package/dist/react-workspace.js +7 -0
  92. package/dist/react-workspace.js.map +1 -0
  93. package/dist/react.cjs +1 -1
  94. package/dist/react.cjs.map +1 -1
  95. package/dist/react.d.cts +2 -2
  96. package/dist/react.d.ts +2 -2
  97. package/dist/react.js +1 -1
  98. package/dist/react.js.map +1 -1
  99. package/dist/surface.cjs +1 -1
  100. package/dist/surface.cjs.map +1 -1
  101. package/dist/surface.d.cts +222 -16
  102. package/dist/surface.d.ts +222 -16
  103. package/dist/surface.js +1 -1
  104. package/dist/surface.js.map +1 -1
  105. package/package.json +14 -4
package/dist/menu.d.cts CHANGED
@@ -1,4 +1,5 @@
1
- import { TransferOutcome } from '@ai-matrx/kit/content-transfer';
1
+ import { TransferOutcome } from '@ai-matrx/alchemy/operate';
2
+ import { Json as Json$2 } from '@ai-matrx/kit/transfer-json';
2
3
 
3
4
  /**
4
5
  * Matrx Alchemy — the menu model (CONTRACT §2.5).
@@ -135,8 +136,8 @@ interface ArrangedSelectionToolbar {
135
136
  * no React. Runtime behaviour lives in `MountedSurface` (`/declare/host`) and in
136
137
  * handler registrations, never here. Zero React, zero `@ai-matrx/agents`.
137
138
  */
138
- type Json$2 = null | boolean | number | string | Json$2[] | {
139
- [key: string]: Json$2;
139
+ type Json$1 = null | boolean | number | string | Json$1[] | {
140
+ [key: string]: Json$1;
140
141
  };
141
142
  /** Unchanged from `ui_surface_value_type_chk`. */
142
143
  type ValueType = "string" | "number" | "boolean" | "object" | "array" | "document";
@@ -266,6 +267,8 @@ interface SurfaceDeclaration {
266
267
  configNamespaces?: readonly ConfigNamespaceDeclaration[];
267
268
  evidenceSources?: readonly EvidenceSourceDeclaration[];
268
269
  skipBaselineValues?: boolean;
270
+ /** Opt out of the host's baseline item types (`baselineItemTypes`, e.g. `TABLE_ROW_ITEM_TYPE`). */
271
+ skipBaselineItemTypes?: boolean;
269
272
  }
270
273
  type ValueProvenance = {
271
274
  kind: "own";
@@ -294,7 +297,7 @@ type QualifiedValueKey = string;
294
297
  /** Live slot payloads (page-capture's shapes, kept). */
295
298
  interface LiveValues {
296
299
  selection?: {
297
- choices: Record<string, Json$2>;
300
+ choices: Record<string, Json$1>;
298
301
  text: string | null;
299
302
  };
300
303
  "on-demand"?: readonly OnDemandSection[];
@@ -306,8 +309,8 @@ interface OnDemandSection {
306
309
  title: string;
307
310
  description?: string;
308
311
  role: "data" | "request";
309
- brief?: Json$2;
310
- load(signal: AbortSignal): Promise<Json$2>;
312
+ brief?: Json$1;
313
+ load(signal: AbortSignal): Promise<Json$1>;
311
314
  }
312
315
  interface RecentRequest {
313
316
  method: string;
@@ -317,7 +320,7 @@ interface RecentRequest {
317
320
  durationMs?: number;
318
321
  requestId?: string;
319
322
  client?: string;
320
- requestBody?: Json$2;
323
+ requestBody?: Json$1;
321
324
  requestBodyNote?: string;
322
325
  errorSentence?: string;
323
326
  timestamp: number;
@@ -386,14 +389,6 @@ interface ClickTarget {
386
389
  host?: unknown;
387
390
  }
388
391
 
389
- /**
390
- * Framework-neutral transfer contracts (Alchemy Operate, CONTRACT §2.3). All data crossing this boundary is JSON.
391
- * Moved from `@ai-matrx/kit/content-transfer` in ALC-16; the format-adapter contract lives in `./contract`.
392
- */
393
- type Json$1 = null | boolean | number | string | Json$1[] | {
394
- [key: string]: Json$1;
395
- };
396
-
397
392
  /**
398
393
  * Operate — the format and delivery contract (Matrx Alchemy CONTRACT §2.3, ALC-16).
399
394
  *
@@ -423,7 +418,7 @@ type Receipt = {
423
418
  sentence: string;
424
419
  warning?: string;
425
420
  fix?: string; /** What the handler produced (e.g. the created record). */
426
- result?: Json$1;
421
+ result?: Json$2;
427
422
  } | {
428
423
  status: "queued";
429
424
  to: WriteTargetRef;
@@ -583,7 +578,7 @@ type ActionResult<T = unknown> = {
583
578
  /** `POST /actions/run` (aidream) — the request. */
584
579
  interface ServerActionRunRequest {
585
580
  name: string;
586
- input: Json$2;
581
+ input: Json$1;
587
582
  by: ActionCaller;
588
583
  surface_name?: string;
589
584
  policy?: ActionPolicy;
@@ -592,8 +587,8 @@ interface ServerActionRunRequest {
592
587
  interface ServerActionRunResponse {
593
588
  status: "applied" | "proposed" | "refused";
594
589
  message: string;
595
- receipts: Json$2[];
596
- proposal?: Json$2;
590
+ receipts: Json$1[];
591
+ proposal?: Json$1;
597
592
  }
598
593
  /** A mandate run request: by alias (an Action's `target`) or by key. */
599
594
  type MandateRunRequest = ({
@@ -603,7 +598,7 @@ type MandateRunRequest = ({
603
598
  key: string;
604
599
  alias?: never;
605
600
  }) & {
606
- variables: Record<string, Json$2>;
601
+ variables: Record<string, Json$1>;
607
602
  userInput?: string;
608
603
  by: ActionCaller;
609
604
  policy: ActionPolicy;
@@ -1135,11 +1130,11 @@ interface ReadOmission {
1135
1130
  */
1136
1131
  interface ProjectedReads {
1137
1132
  values(signal: AbortSignal): Promise<{
1138
- values: Record<string, Json$2>;
1133
+ values: Record<string, Json$1>;
1139
1134
  omissions: readonly ReadOmission[];
1140
1135
  }>;
1141
1136
  item(signal: AbortSignal): Promise<{
1142
- values: Record<string, Json$2>;
1137
+ values: Record<string, Json$1>;
1143
1138
  omissions: readonly ReadOmission[];
1144
1139
  } | null>;
1145
1140
  live(signal: AbortSignal): Promise<LiveValues>;
package/dist/menu.d.ts CHANGED
@@ -1,4 +1,5 @@
1
- import { TransferOutcome } from '@ai-matrx/kit/content-transfer';
1
+ import { TransferOutcome } from '@ai-matrx/alchemy/operate';
2
+ import { Json as Json$2 } from '@ai-matrx/kit/transfer-json';
2
3
 
3
4
  /**
4
5
  * Matrx Alchemy — the menu model (CONTRACT §2.5).
@@ -135,8 +136,8 @@ interface ArrangedSelectionToolbar {
135
136
  * no React. Runtime behaviour lives in `MountedSurface` (`/declare/host`) and in
136
137
  * handler registrations, never here. Zero React, zero `@ai-matrx/agents`.
137
138
  */
138
- type Json$2 = null | boolean | number | string | Json$2[] | {
139
- [key: string]: Json$2;
139
+ type Json$1 = null | boolean | number | string | Json$1[] | {
140
+ [key: string]: Json$1;
140
141
  };
141
142
  /** Unchanged from `ui_surface_value_type_chk`. */
142
143
  type ValueType = "string" | "number" | "boolean" | "object" | "array" | "document";
@@ -266,6 +267,8 @@ interface SurfaceDeclaration {
266
267
  configNamespaces?: readonly ConfigNamespaceDeclaration[];
267
268
  evidenceSources?: readonly EvidenceSourceDeclaration[];
268
269
  skipBaselineValues?: boolean;
270
+ /** Opt out of the host's baseline item types (`baselineItemTypes`, e.g. `TABLE_ROW_ITEM_TYPE`). */
271
+ skipBaselineItemTypes?: boolean;
269
272
  }
270
273
  type ValueProvenance = {
271
274
  kind: "own";
@@ -294,7 +297,7 @@ type QualifiedValueKey = string;
294
297
  /** Live slot payloads (page-capture's shapes, kept). */
295
298
  interface LiveValues {
296
299
  selection?: {
297
- choices: Record<string, Json$2>;
300
+ choices: Record<string, Json$1>;
298
301
  text: string | null;
299
302
  };
300
303
  "on-demand"?: readonly OnDemandSection[];
@@ -306,8 +309,8 @@ interface OnDemandSection {
306
309
  title: string;
307
310
  description?: string;
308
311
  role: "data" | "request";
309
- brief?: Json$2;
310
- load(signal: AbortSignal): Promise<Json$2>;
312
+ brief?: Json$1;
313
+ load(signal: AbortSignal): Promise<Json$1>;
311
314
  }
312
315
  interface RecentRequest {
313
316
  method: string;
@@ -317,7 +320,7 @@ interface RecentRequest {
317
320
  durationMs?: number;
318
321
  requestId?: string;
319
322
  client?: string;
320
- requestBody?: Json$2;
323
+ requestBody?: Json$1;
321
324
  requestBodyNote?: string;
322
325
  errorSentence?: string;
323
326
  timestamp: number;
@@ -386,14 +389,6 @@ interface ClickTarget {
386
389
  host?: unknown;
387
390
  }
388
391
 
389
- /**
390
- * Framework-neutral transfer contracts (Alchemy Operate, CONTRACT §2.3). All data crossing this boundary is JSON.
391
- * Moved from `@ai-matrx/kit/content-transfer` in ALC-16; the format-adapter contract lives in `./contract`.
392
- */
393
- type Json$1 = null | boolean | number | string | Json$1[] | {
394
- [key: string]: Json$1;
395
- };
396
-
397
392
  /**
398
393
  * Operate — the format and delivery contract (Matrx Alchemy CONTRACT §2.3, ALC-16).
399
394
  *
@@ -423,7 +418,7 @@ type Receipt = {
423
418
  sentence: string;
424
419
  warning?: string;
425
420
  fix?: string; /** What the handler produced (e.g. the created record). */
426
- result?: Json$1;
421
+ result?: Json$2;
427
422
  } | {
428
423
  status: "queued";
429
424
  to: WriteTargetRef;
@@ -583,7 +578,7 @@ type ActionResult<T = unknown> = {
583
578
  /** `POST /actions/run` (aidream) — the request. */
584
579
  interface ServerActionRunRequest {
585
580
  name: string;
586
- input: Json$2;
581
+ input: Json$1;
587
582
  by: ActionCaller;
588
583
  surface_name?: string;
589
584
  policy?: ActionPolicy;
@@ -592,8 +587,8 @@ interface ServerActionRunRequest {
592
587
  interface ServerActionRunResponse {
593
588
  status: "applied" | "proposed" | "refused";
594
589
  message: string;
595
- receipts: Json$2[];
596
- proposal?: Json$2;
590
+ receipts: Json$1[];
591
+ proposal?: Json$1;
597
592
  }
598
593
  /** A mandate run request: by alias (an Action's `target`) or by key. */
599
594
  type MandateRunRequest = ({
@@ -603,7 +598,7 @@ type MandateRunRequest = ({
603
598
  key: string;
604
599
  alias?: never;
605
600
  }) & {
606
- variables: Record<string, Json$2>;
601
+ variables: Record<string, Json$1>;
607
602
  userInput?: string;
608
603
  by: ActionCaller;
609
604
  policy: ActionPolicy;
@@ -1135,11 +1130,11 @@ interface ReadOmission {
1135
1130
  */
1136
1131
  interface ProjectedReads {
1137
1132
  values(signal: AbortSignal): Promise<{
1138
- values: Record<string, Json$2>;
1133
+ values: Record<string, Json$1>;
1139
1134
  omissions: readonly ReadOmission[];
1140
1135
  }>;
1141
1136
  item(signal: AbortSignal): Promise<{
1142
- values: Record<string, Json$2>;
1137
+ values: Record<string, Json$1>;
1143
1138
  omissions: readonly ReadOmission[];
1144
1139
  } | null>;
1145
1140
  live(signal: AbortSignal): Promise<LiveValues>;
@@ -1,5 +1,5 @@
1
- "use strict";var __create=Object.create;var __defProp=Object.defineProperty;var __getOwnPropDesc=Object.getOwnPropertyDescriptor;var __getOwnPropNames=Object.getOwnPropertyNames;var __getProtoOf=Object.getPrototypeOf,__hasOwnProp=Object.prototype.hasOwnProperty;var __export=(target,all)=>{for(var name in all)__defProp(target,name,{get:all[name],enumerable:!0})},__copyProps=(to,from,except,desc)=>{if(from&&typeof from=="object"||typeof from=="function")for(let key of __getOwnPropNames(from))!__hasOwnProp.call(to,key)&&key!==except&&__defProp(to,key,{get:()=>from[key],enumerable:!(desc=__getOwnPropDesc(from,key))||desc.enumerable});return to};var __toESM=(mod,isNodeMode,target)=>(target=mod!=null?__create(__getProtoOf(mod)):{},__copyProps(isNodeMode||!mod||!mod.__esModule?__defProp(target,"default",{value:mod,enumerable:!0}):target,mod)),__toCommonJS=mod=>__copyProps(__defProp({},"__esModule",{value:!0}),mod);var operate_document_exports={};__export(operate_document_exports,{documentEngine:()=>documentEngine,documentHtmlEngine:()=>documentHtmlEngine});module.exports=__toCommonJS(operate_document_exports);var import_json_format=require("@ai-matrx/kit/json-format"),import_html_escape=require("@ai-matrx/kit/html-escape");function fencedCodeBlock(text,language){let runs=text.match(/`+/g)??[],fence="`".repeat(Math.max(3,...runs.map(run=>run.length+1)));return`${fence}${language}
1
+ "use strict";var __create=Object.create;var __defProp=Object.defineProperty;var __getOwnPropDesc=Object.getOwnPropertyDescriptor;var __getOwnPropNames=Object.getOwnPropertyNames;var __getProtoOf=Object.getPrototypeOf,__hasOwnProp=Object.prototype.hasOwnProperty;var __export=(target,all)=>{for(var name in all)__defProp(target,name,{get:all[name],enumerable:!0})},__copyProps=(to,from,except,desc)=>{if(from&&typeof from=="object"||typeof from=="function")for(let key of __getOwnPropNames(from))!__hasOwnProp.call(to,key)&&key!==except&&__defProp(to,key,{get:()=>from[key],enumerable:!(desc=__getOwnPropDesc(from,key))||desc.enumerable});return to};var __toESM=(mod,isNodeMode,target)=>(target=mod!=null?__create(__getProtoOf(mod)):{},__copyProps(isNodeMode||!mod||!mod.__esModule?__defProp(target,"default",{value:mod,enumerable:!0}):target,mod)),__toCommonJS=mod=>__copyProps(__defProp({},"__esModule",{value:!0}),mod);var operate_document_exports={};__export(operate_document_exports,{documentEngine:()=>documentEngine,documentHtmlEngine:()=>documentHtmlEngine});module.exports=__toCommonJS(operate_document_exports);var import_json_format=require("@ai-matrx/kit/json-format"),import_html_escape=require("@ai-matrx/kit/html-escape"),import_transfer_json=require("@ai-matrx/kit/transfer-json"),import_transfer_json2=require("@ai-matrx/kit/transfer-json");function fencedCodeBlock(text,language){let runs=text.match(/`+/g)??[],fence="`".repeat(Math.max(3,...runs.map(run=>run.length+1)));return`${fence}${language}
2
2
  ${text}${text.endsWith(`
3
3
  `)?"":`
4
- `}${fence}`}var TRANSFER_ERROR=Symbol.for("ai-matrx.alchemy.operate.transfer-error"),ContentTransferError=class extends Error{code;path;constructor(code,message,path){super(message),this.code=code,this.path=path,this[TRANSFER_ERROR]=!0}static[Symbol.hasInstance](value){return typeof value=="object"&&value!==null&&value[TRANSFER_ERROR]===!0}};function deepFreeze(v){if(ArrayBuffer.isView(v))return v;if(v&&typeof v=="object"&&!Object.isFrozen(v)){Object.freeze(v);for(let x of Object.values(v))deepFreeze(x)}return v}function sealTransferArtifact(artifact){if(!artifact.file)return deepFreeze({...artifact,omissions:artifact.omissions.map(o=>({...o}))});let bytes=artifact.file.bytes.slice(),file={filename:artifact.file.filename,mime:artifact.file.mime,get bytes(){return bytes.slice()}};return deepFreeze({...artifact,file,omissions:artifact.omissions.map(o=>({...o}))})}var ENGINE=Symbol.for("ai-matrx.alchemy.operate.markdown-html-engine");async function loadMarkdownHtmlEngine(){let g=globalThis;return g[ENGINE]??=import("@ai-matrx/print/markdown-html").then(m=>m.createMarkdownHtmlEngine()),g[ENGINE]}var enc=new TextEncoder;function markdownOf(draft){let p=draft.payload;if(p.kind==="markdown")return p.text;if(p.kind==="text")return p.language?fencedCodeBlock(p.text,p.language):p.text;throw new ContentTransferError("unsupported-format","A document needs text or Markdown content. Download it as JSON or CSV instead.")}var stem=filename=>filename?filename.replace(/\.[a-z0-9]+$/i,""):void 0,documentHtmlEngine={async build(draft,options,signal){if(signal.aborted)throw new DOMException("Cancelled","AbortError");let engine=await loadMarkdownHtmlEngine(),tree=await engine.parse(markdownOf(draft),{signal,...options.onNotice?{onNotice:options.onNotice}:{},...options.assets?{assets:options.assets}:{}}),page=engine.document(tree);return sealTransferArtifact({snapshotId:draft.snapshotId,draftRevision:draft.revision,format:"html",plainText:engine.plainText(tree),html:page,file:{filename:options.filename??"export.html",mime:"text/html;charset=utf-8",bytes:enc.encode(page)},omissions:draft.omissions.map(o=>({...o}))})}};function documentEngine(format){return{async build(draft,options,signal){if(signal.aborted)throw new DOMException("Cancelled","AbortError");let source=markdownOf(draft),{exportDocument}=await import("@ai-matrx/print/document"),name=stem(options.filename),out=await exportDocument(source,format,{...name?{fileName:name}:{},...options.onNotice?{onNotice:n=>options.onNotice?.({code:n.code,sentence:n.message,remedy:n.remedy})}:{}});if(signal.aborted)throw new DOMException("Cancelled","AbortError");return sealTransferArtifact({snapshotId:draft.snapshotId,draftRevision:draft.revision,format,plainText:source,file:{filename:out.fileName,mime:out.mime,bytes:out.bytes},omissions:draft.omissions.map(o=>({...o}))})}}}
4
+ `}${fence}`}function deepFreeze(v){if(ArrayBuffer.isView(v))return v;if(v&&typeof v=="object"&&!Object.isFrozen(v)){Object.freeze(v);for(let x of Object.values(v))deepFreeze(x)}return v}function sealTransferArtifact(artifact){if(!artifact.file)return deepFreeze({...artifact,omissions:artifact.omissions.map(o=>({...o}))});let bytes=artifact.file.bytes.slice(),file={filename:artifact.file.filename,mime:artifact.file.mime,get bytes(){return bytes.slice()}};return deepFreeze({...artifact,file,omissions:artifact.omissions.map(o=>({...o}))})}var ENGINE=Symbol.for("ai-matrx.alchemy.operate.markdown-html-engine");async function loadMarkdownHtmlEngine(){let g=globalThis;return g[ENGINE]??=import("@ai-matrx/print/markdown-html").then(m=>m.createMarkdownHtmlEngine()),g[ENGINE]}var enc=new TextEncoder;function markdownOf(draft){let p=draft.payload;if(p.kind==="markdown")return p.text;if(p.kind==="text")return p.language?fencedCodeBlock(p.text,p.language):p.text;throw new import_transfer_json2.ContentTransferError("unsupported-format","A document needs text or Markdown content. Download it as JSON or CSV instead.")}var stem=filename=>filename?filename.replace(/\.[a-z0-9]+$/i,""):void 0,documentHtmlEngine={async build(draft,options,signal){if(signal.aborted)throw new DOMException("Cancelled","AbortError");let engine=await loadMarkdownHtmlEngine(),tree=await engine.parse(markdownOf(draft),{signal,...options.onNotice?{onNotice:options.onNotice}:{},...options.assets?{assets:options.assets}:{}}),page=engine.document(tree);return sealTransferArtifact({snapshotId:draft.snapshotId,draftRevision:draft.revision,format:"html",plainText:engine.plainText(tree),html:page,file:{filename:options.filename??"export.html",mime:"text/html;charset=utf-8",bytes:enc.encode(page)},omissions:draft.omissions.map(o=>({...o}))})}};function documentEngine(format){return{async build(draft,options,signal){if(signal.aborted)throw new DOMException("Cancelled","AbortError");let source=markdownOf(draft),{exportDocument}=await import("@ai-matrx/print/document"),name=stem(options.filename),out=await exportDocument(source,format,{...name?{fileName:name}:{},...options.onNotice?{onNotice:n=>options.onNotice?.({code:n.code,sentence:n.message,remedy:n.remedy})}:{}});if(signal.aborted)throw new DOMException("Cancelled","AbortError");return sealTransferArtifact({snapshotId:draft.snapshotId,draftRevision:draft.revision,format,plainText:source,file:{filename:out.fileName,mime:out.mime,bytes:out.bytes},omissions:draft.omissions.map(o=>({...o}))})}}}
5
5
  //# sourceMappingURL=operate-document.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/operate-document.ts","../src/operate/core.ts","../src/operate/fenced-code.ts","../src/operate/formats/rich-html.ts","../src/operate/formats/document.ts"],"sourcesContent":["export { documentEngine, documentHtmlEngine } from \"./operate/formats/document\";\n","import { stringifyJson } from \"@ai-matrx/kit/json-format\";\nimport { escapeHtml } from \"@ai-matrx/kit/html-escape\";\nimport type {\n Artifact,\n CapturedAllMatching,\n CapturedSource,\n Column,\n Draft,\n ExportProjection,\n Json,\n Omission,\n Payload,\n RawSnapshot,\n Snapshot,\n Source,\n Transport,\n TransferScope,\n TransferLimits,\n TransferPreferences,\n SurfaceHandle,\n} from \"./types\";\nexport * from \"./types\";\nexport * from \"./agent-payload\";\n\nconst TRANSFER_ERROR = Symbol.for(\"ai-matrx.alchemy.operate.transfer-error\");\nexport class ContentTransferError extends Error {\n readonly code: string;\n readonly path: string | undefined;\n\n constructor(\n code: string,\n message: string,\n path?: string,\n ) {\n super(message);\n this.code = code;\n this.path = path;\n (this as unknown as Record<symbol, true>)[TRANSFER_ERROR] = true;\n }\n\n /**\n * One error class across every loaded copy: while `@ai-matrx/kit/content-transfer`\n * still bundles this module for its not-yet-repointed consumers (ALC-16), an\n * error raised by one copy is `instanceof` the other.\n */\n static override [Symbol.hasInstance](value: unknown): boolean {\n return typeof value === \"object\" && value !== null && (value as Record<symbol, unknown>)[TRANSFER_ERROR] === true;\n }\n}\n/** A realm-wide brand (Symbol.for), so a binding made by one loaded copy is recognised by another. */\nconst bound: unique symbol = Symbol.for(\"ai-matrx.alchemy.operate.bound-all-matching\");\nexport type BoundAllMatching = {\n readonly [bound]: true;\n readonly source: CapturedAllMatching;\n readonly projection: ExportProjection;\n readonly columns: readonly Column[];\n readonly limits?: TransferLimits;\n};\nconst stop = (s: AbortSignal) => {\n if (s.aborted) throw new DOMException(\"Cancelled\", \"AbortError\");\n};\nconst enc = (x: string) => x.replace(/~/g, \"~0\").replace(/\\//g, \"~1\");\nconst dec = (x: string) => x.replace(/~1/g, \"/\").replace(/~0/g, \"~\");\nexport type NormalizeTransferJsonOptions = {\n omitUndefinedObjectProperties?: boolean;\n};\nfunction clone<T extends Json>(\n v: T,\n path = \"\",\n seen = new WeakSet<object>(),\n policy: NormalizeTransferJsonOptions = {},\n): T {\n if (v === null || typeof v === \"string\" || typeof v === \"boolean\") return v;\n if (typeof v === \"number\") {\n if (!Number.isFinite(v))\n throw new ContentTransferError(\n \"unsupported-value\",\n \"Only finite numbers are transferable\",\n path,\n );\n return v;\n }\n if (typeof v !== \"object\")\n throw new ContentTransferError(\n \"unsupported-value\",\n \"Unsupported value\",\n path,\n );\n if (seen.has(v))\n throw new ContentTransferError(\n \"circular-value\",\n \"Circular values cannot be transferred\",\n path,\n );\n if (\n !Array.isArray(v) &&\n Object.getPrototypeOf(v) !== Object.prototype &&\n Object.getPrototypeOf(v) !== null\n )\n throw new ContentTransferError(\n \"unsupported-value\",\n \"Only plain JSON objects are transferable\",\n path,\n );\n seen.add(v);\n if (Array.isArray(v)) {\n for (let index = 0; index < v.length; index += 1)\n if (!Object.hasOwn(v, index))\n throw new ContentTransferError(\n \"unsupported-value\",\n \"Sparse arrays cannot be transferred\",\n `${path}/${index}`,\n );\n }\n const out: Json = Array.isArray(v)\n ? v.map((x, i) => clone(x, `${path}/${i}`, seen, policy))\n : Object.fromEntries(\n Object.entries(v)\n .filter(([, x]) => !policy.omitUndefinedObjectProperties || x !== undefined)\n .map(([k, x]) => [\n k,\n clone(x, `${path}/${enc(k)}`, seen, policy),\n ]),\n );\n seen.delete(v);\n return out as T;\n}\nconst maxSurfacePointerSegmentLength = 64;\nconst maxSurfacePointerLength = 192;\nconst truncateSurfacePointer = (value: string, maxLength: number) => {\n const characters = Array.from(value);\n return characters.length > maxLength\n ? `${characters.slice(0, maxLength - 1).join(\"\")}…`\n : value;\n};\nfunction displaySurfacePointer(path: string | undefined): string {\n if (!path) return \"/\";\n const safe = path\n .split(\"/\")\n .slice(1)\n .map((segment) => {\n const controlSafe = segment.replace(/[\\u0000-\\u001F\\u007F-\\u009F]/g, (character) =>\n `\\\\u${character.charCodeAt(0).toString(16).padStart(4, \"0\")}`,\n );\n return truncateSurfacePointer(controlSafe, maxSurfacePointerSegmentLength);\n })\n .join(\"/\");\n const pointer = `/${safe}`;\n return truncateSurfacePointer(pointer, maxSurfacePointerLength);\n}\nfunction cloneSurfaceValue(value: unknown, path: string): Json {\n try {\n return normalizeTransferJsonAtPath(value, path, {\n omitUndefinedObjectProperties: true,\n });\n } catch (error) {\n if (error instanceof ContentTransferError)\n throw new ContentTransferError(\n error.code,\n `Surface capture rejected value at ${displaySurfacePointer(error.path)}: ${error.message}`,\n error.path,\n );\n throw error;\n }\n}\n/**\n * Validates arbitrary host data at the transfer boundary and returns a detached\n * JSON value. This deliberately shares the capture validator: undefined,\n * functions, dates, non-finite numbers, and cycles are rejected rather than\n * silently coerced by a JSON stringify round trip.\n */\nfunction normalizeTransferJsonAtPath(\n value: unknown,\n path: string,\n options: NormalizeTransferJsonOptions = {},\n): Json {\n return clone(value as Json, path, new WeakSet<object>(), options);\n}\nexport function normalizeTransferJson(\n value: unknown,\n options: NormalizeTransferJsonOptions = {},\n): Json {\n return normalizeTransferJsonAtPath(value, \"\", options);\n}\nfunction deepFreeze<T>(v: T): T {\n if (ArrayBuffer.isView(v)) return v;\n if (v && typeof v === \"object\" && !Object.isFrozen(v)) {\n Object.freeze(v);\n for (const x of Object.values(v as object)) deepFreeze(x);\n }\n return v;\n}\nfunction at(v: Json, path: string): Json | undefined {\n validatePointer(path);\n if (path === \"\") return v;\n if (!path.startsWith(\"/\"))\n throw new ContentTransferError(\n \"invalid-path\",\n \"Expected RFC 6901 pointer\",\n path,\n );\n let cur: Json | undefined = v;\n for (const part of path.slice(1).split(\"/\").map(dec)) {\n if (Array.isArray(cur)) cur = cur[Number(part)];\n else if (cur && typeof cur === \"object\")\n cur = Object.hasOwn(cur, part) ? cur[part] : undefined;\n else return undefined;\n }\n return cur;\n}\nfunction validatePointer(path: string): void {\n if ((path !== \"\" && !path.startsWith(\"/\")) || /~(?![01])/u.test(path))\n throw new ContentTransferError(\n \"invalid-path\",\n \"Expected an RFC 6901 JSON pointer\",\n path,\n );\n}\n/** Column ids are identities, never an alternative data address. */\nexport function readTransferCell(\n row: Record<string, Json>,\n column: Column,\n): Json | undefined {\n return at(row, column.path);\n}\nfunction without(\n v: Json,\n paths: readonly string[],\n omit: Omission[],\n path = \"\",\n): Json | undefined {\n if (paths.includes(path)) {\n omit.push({ path, reason: \"excluded\" });\n return undefined;\n }\n if (Array.isArray(v))\n return v\n .map((x, i) => without(x, paths, omit, `${path}/${i}`))\n .filter((x): x is Json => x !== undefined);\n if (v && typeof v === \"object\") {\n const out: Record<string, Json> = Object.create(null);\n for (const [k, x] of Object.entries(v)) {\n const y = without(x, paths, omit, `${path}/${enc(k)}`);\n if (y !== undefined) out[k] = y;\n }\n return out;\n }\n return v;\n}\nfunction projectValue(\n v: Json,\n rules: ExportProjection[\"rules\"],\n target: \"payload\" | \"row\",\n omit: Omission[],\n): Json {\n rules.forEach((rule) => validatePointer(rule.path));\n return (\n without(\n clone(v),\n rules\n .filter(\n (r) =>\n r.target === target &&\n (!r.exportable || r.classification !== \"ordinary\"),\n )\n .map((r) => r.path),\n omit,\n ) ?? null\n );\n}\nfunction excludedColumn(column: Column): boolean {\n return (\n column.exportable === false ||\n column.classification === \"secret\" ||\n column.classification === \"credential\"\n );\n}\nfunction rowProjectionExcludesColumnSchema(\n column: Column,\n rules: ExportProjection[\"rules\"],\n): boolean {\n return rules.some(\n (rule) =>\n rule.target === \"row\" &&\n (!rule.exportable || rule.classification !== \"ordinary\") &&\n (rule.path === column.path || column.path.startsWith(`${rule.path}/`)),\n );\n}\n/** Project the schema with the same payload rules that govern column metadata. */\nfunction projectColumnSchema(\n column: Column,\n rules: ExportProjection[\"rules\"],\n omit: Omission[],\n): Column[\"schema\"] | undefined {\n if (column.schema === undefined) return undefined;\n const root = `/columns/${enc(column.id)}/schema`;\n const schemaRules = rules\n .filter((rule) => rule.target === \"payload\" && (rule.path === root || rule.path.startsWith(`${root}/`)))\n .map((rule) => ({ ...rule, path: rule.path.slice(root.length) }));\n const projected = projectValue(column.schema, schemaRules, \"payload\", omit);\n if (schemaRules.some((rule) => rule.path === \"\" && (!rule.exportable || rule.classification !== \"ordinary\")))\n return undefined;\n return projected as Column[\"schema\"];\n}\nfunction normalize(\n p: Payload,\n projection: ExportProjection,\n omit: Omission[],\n): Payload {\n if (p.kind === \"text\" || p.kind === \"markdown\") {\n if (typeof p.text !== \"string\")\n throw new ContentTransferError(\n \"unsupported-value\",\n \"Text payload must contain a string\",\n \"/text\",\n );\n const value = projectValue(p.text, projection.rules, \"payload\", omit);\n const text = typeof value === \"string\" ? value : \"\";\n // A code block keeps its language (downloads take its extension; Markdown fences it).\n return p.kind === \"text\" && typeof p.language === \"string\" && p.language.trim()\n ? { kind: \"text\", text, language: p.language.trim() }\n : { kind: p.kind, text };\n }\n if (p.kind === \"json\")\n return {\n kind: \"json\",\n value: projectValue(p.value, projection.rules, \"payload\", omit),\n };\n if (p.kind === \"registered\")\n return {\n kind: \"registered\",\n format: p.format,\n value: projectValue(p.value, projection.rules, \"payload\", omit),\n };\n const rowsPayload = p as Extract<Payload, { kind: \"rows\" }>;\n if (p.kind !== \"rows\")\n throw new ContentTransferError(\n \"invalid-payload\",\n \"Unsupported payload kind\",\n );\n const sourceColumns = rowsPayload.columns.map((column) => ({ ...column }));\n const columns = sourceColumns\n .filter((column) => !excludedColumn(column))\n .map((column) => {\n // Do not spread source schema back after an explicit schema or row exclusion.\n const { schema: _sourceSchema, ...withoutSchema } = column;\n const schema = rowProjectionExcludesColumnSchema(column, projection.rules)\n ? undefined\n : projectColumnSchema(column, projection.rules, omit);\n return {\n ...withoutSchema,\n ...(schema === undefined ? {} : { schema }),\n };\n });\n resolveTransferRegistry(columns);\n columns.forEach((column) => validatePointer(column.path));\n const rules = [\n ...projection.rules,\n ...sourceColumns\n .filter(excludedColumn)\n .map((c) => ({\n target: \"row\" as const,\n path: c.path,\n exportable: c.exportable ?? true,\n classification: c.classification ?? (\"ordinary\" as const),\n })),\n ];\n return {\n kind: \"rows\",\n columns,\n rows: rowsPayload.rows.map((row, index) => {\n if (!row || typeof row !== \"object\" || Array.isArray(row))\n throw new ContentTransferError(\n \"invalid-row\",\n \"A table row must be a JSON object\",\n `/rows/${index}`,\n );\n const projected = projectValue(row, rules, \"row\", omit);\n return projected === null ? {} : (projected as Record<string, Json>);\n }),\n };\n}\nexport function projectSnapshot(\n raw: RawSnapshot,\n projection: ExportProjection,\n): Snapshot {\n const omissions = raw.omissions.map((o) => ({ ...o }));\n const normalized = normalize(raw.payload, projection, omissions);\n const payload = raw.limits\n ? limitPayload(normalized, raw.limits, omissions)\n : normalized;\n const included =\n payload.kind === \"rows\" ? payload.rows.length : raw.coverage.included;\n return deepFreeze({\n ...raw,\n payload,\n coverage: {\n ...raw.coverage,\n included,\n ...(included < raw.coverage.included\n ? { status: \"partial\" as const, reason: \"Source export limit applied\" }\n : {}),\n },\n omissions,\n sections: raw.sections\n .filter(\n (section) =>\n !projection.rules.some(\n (rule) =>\n rule.target === \"payload\" &&\n (!rule.exportable || rule.classification !== \"ordinary\") &&\n (section.path === rule.path ||\n section.path.startsWith(`${rule.path}/`)),\n ),\n )\n .map((x) => ({ ...x })),\n ...(raw.limits ? { limits: { ...raw.limits } } : {}),\n } as Snapshot);\n}\nconst uid = () =>\n globalThis.crypto?.randomUUID?.() ?? `capture-${Date.now()}-${Math.random()}`;\nexport function directSource(\n payload: Payload,\n options: Partial<\n Pick<\n RawSnapshot,\n | \"id\"\n | \"sourceId\"\n | \"revision\"\n | \"label\"\n | \"coverage\"\n | \"unsavedChanges\"\n | \"sections\"\n | \"limits\"\n > & { projection: ExportProjection }\n > = {},\n): CapturedSource {\n const id = options.id ?? uid();\n return {\n projection: options.projection ?? { rules: [] },\n snapshot: {\n id,\n sourceId: options.sourceId ?? id,\n revision: options.revision ?? uid(),\n capturedAt: new Date().toISOString(),\n label: options.label ?? \"Content\",\n payload,\n coverage: options.coverage ?? {\n status: \"complete\",\n included: payload.kind === \"rows\" ? payload.rows.length : 1,\n total: payload.kind === \"rows\" ? payload.rows.length : 1,\n },\n unsavedChanges: options.unsavedChanges ?? false,\n omissions: [],\n sections: options.sections ?? [],\n ...(options.limits ? { limits: { ...options.limits } } : {}),\n },\n };\n}\nexport async function capture(\n source: Source | Payload,\n signal: AbortSignal,\n scope: TransferScope = \"target\",\n): Promise<{ snapshot: Snapshot; allMatching?: BoundAllMatching }> {\n stop(signal);\n const captured =\n \"kind\" in source\n ? directSource(source)\n : await source.capture({ scope, signal });\n stop(signal);\n const all = captured.allMatching;\n if (\n all &&\n (all.query.sourceId !== captured.snapshot.sourceId ||\n all.query.revision !== captured.snapshot.revision ||\n all.query.order.length === 0)\n )\n throw new ContentTransferError(\n \"query-mismatch\",\n \"All-matching query must be captured with stable ordering\",\n );\n const snapshot = projectSnapshot(captured.snapshot, captured.projection);\n if (!all) return { snapshot };\n return {\n snapshot,\n allMatching: deepFreeze({\n [bound]: true as const,\n source: {\n ...all,\n query: {\n ...all.query,\n query: clone(all.query.query),\n order: all.query.order.map((x) => ({ ...x })),\n },\n },\n projection: { rules: captured.projection.rules.map((x) => ({ ...x })) },\n // Page rows must be normalized against the original declaration so excluded\n // column values are removed before stable IDs or any caller can observe them.\n columns:\n captured.snapshot.payload.kind === \"rows\"\n ? captured.snapshot.payload.columns.map((column) => ({ ...column }))\n : [],\n ...(snapshot.limits ? { limits: { ...snapshot.limits } } : {}),\n }),\n };\n}\nexport function createDraft(s: Snapshot): Draft {\n return deepFreeze({\n snapshotId: s.id,\n sourceId: s.sourceId,\n sourceRevision: s.revision,\n revision: 0,\n payload: normalize(s.payload, { rules: [] }, []),\n omissions: [...s.omissions],\n manuallyEdited: false,\n provenance: [{ kind: \"original\", description: \"Captured source snapshot\" }],\n });\n}\nfunction revise(\n d: Draft,\n p: Payload,\n o: Omission[],\n description: string,\n manual = d.manuallyEdited,\n kind: Draft[\"provenance\"][number][\"kind\"] = \"deterministic\",\n baseOmissions: readonly Omission[] = d.omissions,\n): Draft {\n const { history: _history, ...previous } = d;\n return deepFreeze({\n ...d,\n revision: d.revision + 1,\n payload: normalize(p, { rules: [] }, []),\n omissions: [...baseOmissions, ...o],\n manuallyEdited: manual,\n provenance: [...d.provenance, { kind, description }],\n history: [...(d.history ?? []), previous],\n });\n}\nexport const editDraft = (d: Draft, p: Payload) =>\n revise(d, p, [], \"Manual edit\", true, \"manual\");\n/**\n * A deterministic revision of `d` (the structure trees, PP-06/07): same snapshot, next revision,\n * the given omissions added. `baseOmissions` replaces the draft's own when a step re-projects from\n * the snapshot (a section selection), exactly as `applySectionSelection` does.\n */\nexport const deriveDraft = (\n d: Draft,\n p: Payload,\n o: Omission[],\n description: string,\n baseOmissions: readonly Omission[] = d.omissions,\n) => revise(d, p, o, description, d.manuallyEdited, \"deterministic\", baseOmissions);\nexport const resetDraft = (s: Snapshot) => createDraft(s);\nexport const sourceChanged = (d: Draft, s: Snapshot) =>\n d.sourceId !== s.sourceId || d.sourceRevision !== s.revision;\nexport function undoDraft(d: Draft): Draft {\n const previous = d.history?.at(-1);\n if (!previous) return d;\n return deepFreeze({\n ...previous,\n revision: d.revision + 1,\n history: d.history!.slice(0, -1),\n });\n}\n/** Keep and regenerate are explicit choices; observing fresh data never overwrites edits. */\nexport function refreshDraft(\n draft: Draft,\n snapshot: Snapshot,\n choice: \"keep\" | \"regenerate\",\n): Draft {\n return choice === \"keep\" ? draft : createDraft(snapshot);\n}\nexport function applySectionSelection(\n d: Draft,\n s: Snapshot,\n ids: readonly string[],\n): Draft {\n if (\n d.snapshotId !== s.id ||\n d.sourceId !== s.sourceId ||\n d.sourceRevision !== s.revision\n )\n throw new ContentTransferError(\n \"snapshot-mismatch\",\n \"Section selection requires the draft's captured source snapshot\",\n );\n const selected = new Set(ids),\n omit: Omission[] = [],\n paths = s.sections\n .filter((x) => !selected.has(x.id))\n .map((x) => {\n omit.push({ path: x.path, reason: \"excluded\" });\n return x.path;\n }),\n // Selection is a replacement projection from the snapshot, so only the\n // snapshot's omissions remain authoritative. Retaining draft omissions\n // would preserve stale transforms after the snapshot payload is rebuilt.\n baseOmissions = s.omissions;\n if (s.payload.kind === \"json\")\n return revise(\n d,\n { kind: \"json\", value: without(s.payload.value, paths, []) ?? null },\n omit,\n \"Selected sections\",\n d.manuallyEdited,\n \"deterministic\",\n baseOmissions,\n );\n if (s.payload.kind === \"registered\")\n return revise(\n d,\n {\n kind: \"registered\",\n format: s.payload.format,\n value: without(s.payload.value, paths, []) ?? null,\n },\n omit,\n \"Selected sections\",\n d.manuallyEdited,\n \"deterministic\",\n baseOmissions,\n );\n if (s.payload.kind === \"markdown\" || s.payload.kind === \"text\") {\n // A prose section is a character range of the text: `/text/<start>-<end>`.\n const text = s.payload.text;\n const ranges = paths\n .map((path) => {\n const m = /^\\/text\\/(\\d+)-(\\d+)$/.exec(path);\n const start = m ? Number(m[1]) : NaN,\n end = m ? Number(m[2]) : NaN;\n if (!m || start > end || end > text.length)\n throw new ContentTransferError(\n \"invalid-section\",\n `Section \"${path}\" is not a range of this text. Declare a prose section as /text/<start>-<end> within the text.`,\n );\n return [start, end] as const;\n })\n .sort((a, b) => b[0] - a[0]);\n let kept = text;\n for (const [start, end] of ranges) kept = kept.slice(0, start) + kept.slice(end);\n return revise(\n d,\n { ...s.payload, text: kept },\n omit,\n \"Selected sections\",\n d.manuallyEdited,\n \"deterministic\",\n baseOmissions,\n );\n }\n return revise(\n d,\n s.payload,\n omit,\n \"Selected sections\",\n d.manuallyEdited,\n \"deterministic\",\n baseOmissions,\n );\n}\nexport function transformRows(\n d: Draft,\n o: {\n search?: string;\n sort?: { column: string; direction: \"asc\" | \"desc\" };\n filters?: Readonly<Record<string, string>>;\n /** Positions in this call's input draft rows; unlike ids, no guessed key is used. */\n selectedIndices?: readonly number[];\n selectedIds?: readonly string[];\n idColumn?: string;\n visibleColumns?: readonly string[];\n structuredProjection?: \"full\" | \"visible\";\n top?: number | null;\n },\n): Draft {\n if (d.payload.kind !== \"rows\") return d;\n // Validate before deciding whether truncation is necessary. A negative/NaN\n // top is an invalid request even for an empty result set.\n if (o.top != null) assertLimit(o.top, \"maxRows\");\n const cols = o.visibleColumns\n ? o.visibleColumns\n .map((id) =>\n d.payload.kind === \"rows\"\n ? d.payload.columns.find((c) => c.id === id)\n : undefined,\n )\n .filter((c): c is Column => Boolean(c))\n : d.payload.columns.filter((c) => c.visible);\n const get = readTransferCell;\n let rows = [...d.payload.rows],\n omit: Omission[] = [];\n const before = rows.length;\n if (o.selectedIndices !== undefined) {\n const selected = new Set<number>();\n for (const index of o.selectedIndices) {\n if (!Number.isSafeInteger(index) || index < 0 || index >= d.payload.rows.length)\n throw new ContentTransferError(\n \"invalid-selection-index\",\n \"Selected row indexes must be non-negative positions in the input draft rows\",\n );\n selected.add(index);\n }\n rows = d.payload.rows.filter((_, index) => selected.has(index));\n }\n if (o.selectedIds && o.idColumn) {\n const set = new Set(o.selectedIds);\n const idColumn = d.payload.columns.find((c) => c.id === o.idColumn);\n rows = rows.filter((r) =>\n set.has(String(idColumn ? get(r, idColumn) : r[o.idColumn!])),\n );\n }\n if (o.search) {\n const q = o.search.toLowerCase();\n rows = rows.filter((r) =>\n cols.some((c) =>\n String(get(r, c) ?? \"\")\n .toLowerCase()\n .includes(q),\n ),\n );\n }\n for (const [id, q] of Object.entries(o.filters ?? {})) {\n const c = cols.find((x) => x.id === id);\n if (c)\n rows = rows.filter((r) =>\n String(get(r, c) ?? \"\")\n .toLowerCase()\n .includes(q.toLowerCase()),\n );\n }\n if (rows.length !== before)\n omit.push({\n path: \"/rows\",\n reason: \"filtered\",\n count: before - rows.length,\n });\n if (o.sort) {\n const c = cols.find((x) => x.id === o.sort!.column);\n if (c)\n rows.sort((a, b) => {\n const left = get(a, c);\n const right = get(b, c);\n const compare =\n typeof left === \"number\" && typeof right === \"number\"\n ? left - right\n : String(left ?? \"\").localeCompare(String(right ?? \"\"));\n return compare * (o.sort!.direction === \"asc\" ? 1 : -1);\n });\n }\n if (o.top != null && rows.length > o.top) {\n omit.push({\n path: \"/rows\",\n reason: \"truncated\",\n count: rows.length - o.top,\n });\n rows = rows.slice(0, o.top);\n }\n if (o.structuredProjection === \"visible\") {\n rows = rows.map((r) =>\n Object.fromEntries(cols.map((c) => [c.id, get(r, c) ?? null])),\n );\n const excludedColumns = d.payload.columns.length - cols.length;\n if (excludedColumns > 0)\n omit.push({\n path: \"/columns\",\n reason: \"excluded\",\n count: excludedColumns,\n });\n }\n return revise(\n d,\n {\n kind: \"rows\",\n rows,\n columns: cols.map((c) => ({\n ...c,\n visible: true,\n ...(o.structuredProjection === \"visible\"\n ? { path: `/${enc(c.id)}` }\n : {}),\n })),\n },\n omit,\n \"Prepared row subset\",\n );\n}\nexport function reduceJson(\n draft: Draft,\n options: {\n exclude?: readonly string[];\n maxDepth?: number | null;\n maxStringChars?: number | null;\n maxArrayItems?: number | null;\n },\n): Draft {\n if (draft.payload.kind !== \"json\" && draft.payload.kind !== \"registered\")\n return draft;\n const omissions: Omission[] = [];\n options.exclude?.forEach(validatePointer);\n const filtered =\n without(clone(draft.payload.value), options.exclude ?? [], omissions) ??\n null;\n const payload = limitPayload(\n { ...draft.payload, value: filtered },\n options,\n omissions,\n );\n return revise(draft, payload, omissions, \"Reduced JSON\");\n}\nexport async function collectAllMatching(\n c: BoundAllMatching,\n signal: AbortSignal,\n): Promise<{\n rows: Record<string, Json>[];\n coverage: RawSnapshot[\"coverage\"];\n omissions: Omission[];\n error?: ContentTransferError;\n}> {\n const rows: Record<string, Json>[] = [],\n omissions: Omission[] = [],\n ids = new Set<string>(),\n cursors = new Set<string>();\n let cursor: string | null = null,\n token: string | null | undefined,\n last: RawSnapshot[\"coverage\"] = {\n status: \"unknown\",\n included: 0,\n total: null,\n };\n let certifiedTotal: number | null | undefined;\n const maxRows = c.limits?.maxRows;\n if (maxRows != null) assertLimit(maxRows, \"maxRows\");\n const finishAtLimit = (total: number | null, knownOmitted?: number) => ({\n rows: deepFreeze(rows),\n omissions: deepFreeze([\n ...omissions,\n {\n path: \"/rows\",\n reason: \"truncated\" as const,\n ...(knownOmitted === undefined || knownOmitted <= 0\n ? {}\n : { count: knownOmitted }),\n },\n ]),\n coverage: deepFreeze({\n status: \"partial\" as const,\n included: rows.length,\n total,\n reason: \"Source export limit applied\",\n }),\n });\n try {\n // A zero source cap is still a real cap: do not request a page merely to\n // discover data that the caller is not allowed to receive.\n if (maxRows === 0) return finishAtLimit(null);\n do {\n stop(signal);\n const page = await c.source.page({\n query: c.source.query,\n cursor,\n consistencyToken: token ?? null,\n signal,\n });\n stop(signal);\n if (token === undefined) token = page.consistencyToken;\n else if (page.consistencyToken !== token)\n throw new ContentTransferError(\n \"consistency-token-changed\",\n \"All-matching export changed during collection\",\n );\n if (page.coverage.included !== page.rows.length)\n throw new ContentTransferError(\n \"invalid-page-coverage\",\n \"Page count does not match returned rows\",\n );\n if (\n page.coverage.total !== null &&\n (!Number.isSafeInteger(page.coverage.total) || page.coverage.total < 0)\n )\n throw new ContentTransferError(\n \"invalid-page-coverage\",\n \"Page total must be a non-negative integer or null\",\n );\n if (certifiedTotal === undefined) certifiedTotal = page.coverage.total;\n else if (page.coverage.total !== certifiedTotal)\n throw new ContentTransferError(\n \"inconsistent-total\",\n \"All-matching source changed its reported total during collection\",\n );\n const projected = (\n normalize(\n { kind: \"rows\", rows: page.rows, columns: [...c.columns] },\n c.projection,\n omissions,\n ) as Extract<Payload, { kind: \"rows\" }>\n ).rows;\n let uniqueBeyondLimit = 0;\n for (const row of projected) {\n // The callback is part of the transfer boundary, so it receives only\n // the projected row. Sources requiring identity must declare an\n // exportable opaque ID; raw credential/non-exportable fields never\n // cross this seam merely for de-duplication.\n const id = c.source.getRowId(row);\n if (!id)\n throw new ContentTransferError(\n \"invalid-row-id\",\n \"All-matching source returned empty projected ID\",\n );\n if (!ids.has(id)) {\n ids.add(id);\n if (maxRows == null || rows.length < maxRows)\n rows.push(\n (\n limitPayload(\n { kind: \"rows\", rows: [row], columns: [...c.columns] },\n { ...c.limits, maxRows: null },\n omissions,\n ) as Extract<Payload, { kind: \"rows\" }>\n ).rows[0]!,\n );\n else uniqueBeyondLimit += 1;\n } else omissions.push({ path: `/rows/${enc(id)}`, reason: \"duplicate\" });\n }\n // Check after de-duplication and before the source-cap return: ids also\n // includes unique rows that the cap intentionally did not retain.\n if (page.coverage.total !== null && page.coverage.total < ids.size)\n throw new ContentTransferError(\n \"invalid-page-coverage\",\n \"Page total is smaller than the accumulated unique row count\",\n );\n last = page.coverage;\n if (\n maxRows != null &&\n rows.length >= maxRows &&\n (uniqueBeyondLimit > 0 || page.nextCursor !== null)\n )\n return finishAtLimit(\n page.coverage.total,\n page.nextCursor === null\n ? uniqueBeyondLimit\n : page.coverage.total != null && page.coverage.total > rows.length\n ? page.coverage.total - rows.length\n : undefined,\n );\n cursor = page.nextCursor;\n if (cursor !== null && (!cursor || cursors.has(cursor)))\n throw new ContentTransferError(\n \"non-advancing-cursor\",\n \"All-matching source repeated a cursor\",\n );\n if (cursor) cursors.add(cursor);\n } while (cursor !== null);\n const complete =\n c.source.stableSnapshot === true &&\n last.status === \"complete\" &&\n last.total === rows.length &&\n token !== undefined;\n return {\n rows: deepFreeze(rows),\n omissions: deepFreeze(omissions),\n coverage: deepFreeze(\n complete\n ? { ...last, included: rows.length }\n : {\n ...last,\n status: \"partial\",\n included: rows.length,\n reason:\n last.reason ??\n \"Source did not certify a stable complete snapshot\",\n },\n ),\n };\n } catch (e) {\n const error =\n e instanceof ContentTransferError\n ? e\n : new ContentTransferError(\n signal.aborted ? \"cancelled\" : \"page-failed\",\n e instanceof Error ? e.message : \"Page collection failed\",\n );\n return {\n rows: deepFreeze(rows),\n omissions: deepFreeze(omissions),\n coverage: deepFreeze({\n status: \"partial\",\n included: rows.length,\n total: last.total,\n reason: error.message,\n }),\n error,\n };\n }\n}\n// An EMPTY cell is empty text. `null` is how a row carries \"nothing here\"\n// (hosts normalise a missing cell to JSON null so the row keeps its shape), and\n// until 2026-09-21 it serialized as the word \"null\" in every plain / CSV / TSV\n// / Markdown copy — six \"null\"s across a copied row of a data table.\nconst textValue = (value: Json | undefined): string =>\n value === undefined || value === null\n ? \"\"\n : typeof value === \"string\"\n ? value\n : stringifyJson(value, { style: \"compact\" });\n\n/** Preserve artifact-byte identity even if a consumer mutates a returned view. */\nexport function sealTransferArtifact(artifact: Artifact): Artifact {\n if (!artifact.file)\n return deepFreeze({\n ...artifact,\n omissions: artifact.omissions.map((o) => ({ ...o })),\n });\n const bytes = artifact.file.bytes.slice();\n const file = {\n filename: artifact.file.filename,\n mime: artifact.file.mime,\n get bytes() {\n return bytes.slice();\n },\n };\n return deepFreeze({\n ...artifact,\n file,\n omissions: artifact.omissions.map((o) => ({ ...o })),\n });\n}\n\n/** The columns a text serialization writes: visible, exportable, never secret or credential. */\nexport function exportedColumns(columns: readonly Column[]): Column[] {\n return columns.filter(\n (c) =>\n c.visible &&\n c.exportable !== false &&\n c.classification !== \"secret\" &&\n c.classification !== \"credential\",\n );\n}\n\nexport function serialize(\n draft: Draft,\n format:\n \"plain\" | \"markdown\" | \"json\" | \"compact-json\" | \"csv\" | \"tsv\" | \"html\",\n options: { spreadsheetSafe?: boolean; filename?: string } = {},\n): Artifact {\n const payload = draft.payload;\n const omissions = draft.omissions.map((o) => ({ ...o }));\n let plainText = \"\",\n html: string | undefined;\n let mime = \"text/plain;charset=utf-8\",\n extension = \"txt\";\n const columnCell = (row: Record<string, Json>, column: Column) =>\n textValue(readTransferCell(row, column));\n if ((format === \"csv\" || format === \"tsv\") && payload.kind !== \"rows\") {\n throw new ContentTransferError(\n \"unsupported-format\",\n `${format.toUpperCase()} requires tabular data`,\n );\n }\n if (format === \"json\" || format === \"compact-json\") {\n const value =\n payload.kind === \"rows\"\n ? payload.rows\n : payload.kind === \"text\" || payload.kind === \"markdown\"\n ? payload.text\n : payload.value;\n plainText = stringifyJson(value, {\n style: format === \"json\" ? \"pretty\" : \"compact\",\n });\n mime = \"application/json;charset=utf-8\";\n extension = \"json\";\n } else if (payload.kind === \"rows\") {\n const columns = exportedColumns(payload.columns);\n if (format === \"markdown\") {\n const escapeCell = (value: string) =>\n escapeHtml(value)\n .replace(/\\\\/g, \"\\\\\\\\\")\n .replace(/\\|/g, \"\\\\|\")\n .replace(/\\r\\n|\\r|\\n/g, \"<br>\");\n plainText = [\n `| ${columns.map((c) => escapeCell(c.label)).join(\" | \")} |`,\n `| ${columns.map(() => \"---\").join(\" | \")} |`,\n ...payload.rows.map(\n (row) =>\n `| ${columns.map((c) => escapeCell(columnCell(row, c))).join(\" | \")} |`,\n ),\n ].join(\"\\n\");\n mime = \"text/markdown;charset=utf-8\";\n extension = \"md\";\n } else {\n const delimiter = format === \"csv\" ? \",\" : \"\\t\";\n const safe = options.spreadsheetSafe ?? format === \"tsv\";\n const encode = (value: string, path: string, isString = true) => {\n let text = value;\n if (safe && isString && /^[\\t\\r\\n ]*[=+\\-@]/.test(text)) {\n text = `'${text}`;\n omissions.push({ path, reason: \"escaped\", count: 1 });\n }\n return text.includes(delimiter) || /[\"\\n\\r]/.test(text)\n ? `\"${text.replace(/\"/g, '\"\"')}\"`\n : text;\n };\n plainText = [\n columns\n .map((c) => encode(c.label, `/columns/${enc(c.id)}`))\n .join(delimiter),\n ...payload.rows.map((row, index) =>\n columns\n .map((c) =>\n encode(\n columnCell(row, c),\n `/rows/${index}${c.path}`,\n typeof readTransferCell(row, c) === \"string\",\n ),\n )\n .join(delimiter),\n ),\n ].join(\"\\n\");\n if (format === \"csv\") {\n mime = \"text/csv;charset=utf-8\";\n extension = \"csv\";\n }\n if (format === \"tsv\") {\n mime = \"text/tab-separated-values;charset=utf-8\";\n extension = \"tsv\";\n }\n }\n if (format === \"html\")\n html = `<table><thead><tr>${columns.map((c) => `<th>${escapeHtml(c.label)}</th>`).join(\"\")}</tr></thead><tbody>${payload.rows.map((row) => `<tr>${columns.map((c) => `<td>${escapeHtml(columnCell(row, c)).replace(/\\r\\n|\\r|\\n/g, \"<br>\")}</td>`).join(\"\")}</tr>`).join(\"\")}</tbody></table>`;\n } else {\n plainText =\n payload.kind === \"text\" || payload.kind === \"markdown\"\n ? payload.text\n : stringifyJson(payload.value, { style: \"pretty\" });\n if (format === \"markdown\") {\n mime = \"text/markdown;charset=utf-8\";\n extension = \"md\";\n }\n if (format === \"html\") html = `<pre>${escapeHtml(plainText)}</pre>`;\n }\n if (format === \"html\") {\n mime = \"text/html;charset=utf-8\";\n extension = \"html\";\n }\n return sealTransferArtifact({\n snapshotId: draft.snapshotId,\n draftRevision: draft.revision,\n format,\n plainText,\n ...(html === undefined ? {} : { html }),\n file: {\n filename: options.filename ?? `export.${extension}`,\n mime,\n bytes: new TextEncoder().encode(\n format === \"html\" ? (html ?? plainText) : plainText,\n ),\n },\n omissions,\n });\n}\nexport function createBrowserTransport(): Transport {\n return {\n async copy(a, signal) {\n const cancelled = () =>\n signal.aborted ? { status: \"cancelled\" as const } : undefined;\n try {\n if (cancelled()) return cancelled()!;\n const c = globalThis.navigator?.clipboard;\n if (!c?.write && !c?.writeText)\n return {\n status: \"error\",\n code: \"clipboard-unavailable\",\n message: \"Clipboard writing is unavailable\",\n retryable: false,\n };\n if (\n a.html &&\n c.write &&\n typeof globalThis.ClipboardItem === \"function\"\n ) {\n try {\n await c.write([\n new ClipboardItem({\n \"text/plain\": new Blob([a.plainText], { type: \"text/plain\" }),\n \"text/html\": new Blob([a.html], { type: \"text/html\" }),\n }),\n ]);\n if (cancelled()) return cancelled()!;\n return {\n status: \"success\",\n delivered: \"clipboard\",\n mimeTypes: [\"text/plain\", \"text/html\"],\n };\n } catch {\n if (cancelled()) return cancelled()!;\n }\n }\n if (c.writeText) {\n await c.writeText(a.plainText);\n if (cancelled()) return cancelled()!;\n return a.html\n ? {\n status: \"degraded\",\n delivered: \"plain-text\",\n reason: \"Rich clipboard write was unavailable or rejected\",\n }\n : {\n status: \"success\",\n delivered: \"clipboard\",\n mimeTypes: [\"text/plain\"],\n };\n }\n return {\n status: \"error\",\n code: \"clipboard-rejected\",\n message: \"Clipboard rejected the write\",\n retryable: true,\n };\n } catch (e) {\n return (\n cancelled() ?? {\n status: \"error\",\n code: \"clipboard-rejected\",\n message:\n e instanceof Error ? e.message : \"Clipboard rejected the write\",\n retryable: true,\n }\n );\n }\n },\n async download(a, signal) {\n if (signal.aborted) return { status: \"cancelled\" };\n if (!a.file || typeof document === \"undefined\" || !URL?.createObjectURL)\n return {\n status: \"error\",\n code: \"download-unavailable\",\n message: \"Download is unavailable\",\n retryable: false,\n };\n let url: string | undefined;\n try {\n url = URL.createObjectURL(\n new Blob([a.file.bytes.slice().buffer as ArrayBuffer], {\n type: a.file.mime,\n }),\n );\n const link = document.createElement(\"a\");\n link.href = url;\n link.download = a.file.filename;\n link.click();\n return signal.aborted\n ? { status: \"cancelled\" }\n : {\n status: \"success\",\n delivered: \"download-started\",\n mimeTypes: [a.file.mime],\n };\n } catch (e) {\n return signal.aborted\n ? { status: \"cancelled\" }\n : {\n status: \"error\",\n code: \"download-failed\",\n message: e instanceof Error ? e.message : \"Download failed\",\n retryable: true,\n };\n } finally {\n if (url) setTimeout(() => URL.revokeObjectURL(url!), 0);\n }\n },\n };\n}\n\nfunction assertLimit(value: number | null | undefined, name: string): void {\n if (value != null && (!Number.isSafeInteger(value) || value < 0)) {\n throw new ContentTransferError(\n \"invalid-limit\",\n `${name} must be a non-negative safe integer or null`,\n );\n }\n}\nexport type TransferPreferenceOverrides = Partial<\n Omit<TransferPreferences, \"limits\">\n> & { limits?: Partial<TransferLimits> };\nconst limitKeys = [\n \"maxRows\",\n \"maxStringChars\",\n \"maxDepth\",\n \"maxArrayItems\",\n \"targetTokens\",\n] as const;\n/** Restrictions intersect: neither a menu nor a provider can relax a source limit. */\nexport function resolveTransferPreferences(\n provider: TransferPreferenceOverrides = {},\n menu: TransferPreferenceOverrides = {},\n sourceLimits: Partial<TransferLimits> = {},\n): TransferPreferences {\n const limits: TransferLimits = {\n maxRows: null,\n maxStringChars: null,\n maxDepth: null,\n maxArrayItems: null,\n targetTokens: null,\n };\n for (const key of limitKeys) {\n const candidates = [\n provider.limits?.[key],\n menu.limits?.[key],\n sourceLimits[key],\n ];\n candidates.forEach((value) => assertLimit(value, key));\n const finite = candidates.filter((value): value is number => value != null);\n limits[key] = finite.length ? Math.min(...finite) : null;\n }\n return deepFreeze({\n initialFormat: menu.initialFormat ?? provider.initialFormat ?? \"plain\",\n initialPreset: menu.initialPreset ?? provider.initialPreset ?? \"full\",\n initialEnvelope: menu.initialEnvelope ?? provider.initialEnvelope ?? \"ai\",\n limits,\n });\n}\n/**\n * True for the objects React uses to represent a component or an element —\n * `forwardRef`, `memo`, `lazy`, portals, elements. They are all tagged with the\n * `$$typeof` symbol, which is exactly the test React uses itself.\n */\nfunction isReactElementType(value: object): boolean {\n const tag = (value as { $$typeof?: unknown }).$$typeof;\n return typeof tag === \"symbol\";\n}\n\nfunction cloneTransferRegistration(\n value: unknown,\n path = \"registration\",\n seen = new WeakSet<object>(),\n): unknown {\n if (value === null || (typeof value !== \"object\" && typeof value !== \"function\"))\n return value;\n // Registered behavior remains callable by identity. Freezing a caller-owned\n // function would mutate it and its attached state.\n if (typeof value === \"function\") return value;\n // A React component or element is registered BEHAVIOUR too — it is rendered,\n // never inspected — and `React.forwardRef` / `React.memo` produce OBJECTS\n // rather than functions. React's development build defines their\n // `displayName` as an ACCESSOR, so walking into one threw \"cannot use\n // accessors\" at `registration/icon/displayName` and took EVERY dashboard page\n // that renders a transfer menu down behind its error boundary (2026-09-14;\n // every AI variant the admin dashboard registers carries a lucide `icon`).\n // Recognised the way React itself recognises them.\n if (isReactElementType(value)) return value;\n if (seen.has(value))\n throw new ContentTransferError(\n \"unsupported-registration-metadata\",\n \"Circular transfer registration metadata is unsupported\",\n path,\n );\n seen.add(value);\n if (Array.isArray(value)) {\n const copy = value.map((item, index) =>\n cloneTransferRegistration(item, `${path}/${index}`, seen),\n );\n seen.delete(value);\n return Object.freeze(copy);\n }\n const prototype = Object.getPrototypeOf(value);\n if (prototype !== Object.prototype && prototype !== null)\n throw new ContentTransferError(\n \"unsupported-registration-metadata\",\n \"Transfer registration metadata must use plain objects and arrays\",\n path,\n );\n const copy = Object.create(prototype) as Record<PropertyKey, unknown>;\n for (const key of Reflect.ownKeys(value)) {\n const descriptor = Object.getOwnPropertyDescriptor(value, key)!;\n if (!(\"value\" in descriptor))\n throw new ContentTransferError(\n \"unsupported-registration-metadata\",\n \"Transfer registration metadata cannot use accessors\",\n `${path}/${String(key)}`,\n );\n Object.defineProperty(copy, key, {\n value: cloneTransferRegistration(\n descriptor.value,\n `${path}/${String(key)}`,\n seen,\n ),\n enumerable: descriptor.enumerable === true,\n writable: false,\n configurable: false,\n });\n }\n seen.delete(value);\n return Object.freeze(copy);\n}\n\n/** One stable id per registered format or action; ambiguous overrides fail loudly. */\nexport function resolveTransferRegistry<T extends { id: string }>(\n ...groups: readonly (readonly T[])[]\n): readonly T[] {\n const ids = new Set<string>();\n const result: T[] = [];\n for (const group of groups)\n for (const item of group) {\n const copy = cloneTransferRegistration(item) as T;\n if (!copy.id.trim() || ids.has(copy.id))\n throw new ContentTransferError(\n \"duplicate-registration\",\n `Transfer id ${JSON.stringify(copy.id)} is empty or registered more than once`,\n );\n ids.add(copy.id);\n result.push(copy);\n }\n return Object.freeze(result);\n}\n\nexport type TransferSurfaceDeclaration = {\n surfaceName: string;\n label?: string;\n values: readonly {\n name: string;\n label: string;\n exportable?: boolean;\n classification?: \"ordinary\" | \"secret\" | \"credential\";\n includedByDefault?: boolean;\n }[];\n};\n/** A structural adapter to the actual mounted surface, never a global name lookup. */\nexport function createSurfaceTransferHandle(options: {\n instanceId: string;\n manifest: TransferSurfaceDeclaration;\n isMounted(): boolean;\n getScope(): Record<string, unknown> | Promise<Record<string, unknown>>;\n getRevision?(): string;\n unsavedChanges?(): boolean;\n projection?: ExportProjection;\n limits?: TransferLimits;\n}): SurfaceHandle {\n const declarations = resolveTransferRegistry(\n options.manifest.values.map((value) => ({ ...value, id: value.name })),\n );\n return {\n instanceId: options.instanceId,\n surfaceName: options.manifest.surfaceName,\n isMounted: options.isMounted,\n async capture(signal) {\n stop(signal);\n if (!options.isMounted())\n throw new ContentTransferError(\n \"surface-unmounted\",\n \"The captured surface is no longer mounted\",\n );\n const revisionBefore = options.getRevision?.();\n const scope = await options.getScope();\n stop(signal);\n if (!options.isMounted())\n throw new ContentTransferError(\n \"surface-unmounted\",\n \"The surface closed during capture\",\n );\n if (\n revisionBefore !== undefined &&\n options.getRevision?.() !== revisionBefore\n )\n throw new ContentTransferError(\n \"surface-changed\",\n \"The surface changed during capture; capture again\",\n );\n const value: Record<string, Json> = {};\n for (const declaration of declarations) {\n if (\n Object.hasOwn(scope, declaration.name) &&\n scope[declaration.name] !== undefined\n ) {\n Object.defineProperty(value, declaration.name, {\n value: cloneSurfaceValue(\n scope[declaration.name],\n `/${enc(declaration.name)}`,\n ),\n enumerable: true,\n writable: true,\n configurable: true,\n });\n }\n }\n return directSource(\n { kind: \"json\", value },\n {\n sourceId: options.instanceId,\n revision: revisionBefore ?? uid(),\n label: options.manifest.label ?? options.manifest.surfaceName,\n unsavedChanges: options.unsavedChanges?.() ?? false,\n sections: declarations\n .filter((d) => Object.hasOwn(value, d.name))\n .map((d) => ({\n id: d.name,\n label: d.label,\n path: `/${enc(d.name)}`,\n includedByDefault: d.includedByDefault ?? true,\n })),\n projection: {\n rules: [\n ...(options.projection?.rules ?? []),\n ...declarations.map((d) => ({\n target: \"payload\" as const,\n path: `/${enc(d.name)}`,\n exportable: d.exportable ?? true,\n classification: d.classification ?? (\"ordinary\" as const),\n })),\n ],\n },\n ...(options.limits ? { limits: options.limits } : {}),\n },\n );\n },\n };\n}\n\nfunction limitJson(\n value: Json,\n limits: Partial<TransferLimits>,\n omissions: Omission[],\n path = \"\",\n depth = 0,\n): Json {\n if (limits.maxDepth != null && depth > limits.maxDepth) {\n omissions.push({ path, reason: \"truncated\" });\n return null;\n }\n if (\n typeof value === \"string\" &&\n limits.maxStringChars != null &&\n Array.from(value).length > limits.maxStringChars\n ) {\n const chars = Array.from(value);\n omissions.push({\n path,\n reason: \"truncated\",\n count: chars.length - limits.maxStringChars,\n });\n return chars.slice(0, limits.maxStringChars).join(\"\");\n }\n if (Array.isArray(value)) {\n const count = Math.min(value.length, limits.maxArrayItems ?? value.length);\n if (count < value.length)\n omissions.push({\n path,\n reason: \"truncated\",\n count: value.length - count,\n });\n return value\n .slice(0, count)\n .map((item, index) =>\n limitJson(item, limits, omissions, `${path}/${index}`, depth + 1),\n );\n }\n if (value && typeof value === \"object\")\n return Object.fromEntries(\n Object.entries(value).map(([key, item]) => [\n key,\n limitJson(item, limits, omissions, `${path}/${enc(key)}`, depth + 1),\n ]),\n );\n return value;\n}\nfunction limitPayload(\n payload: Payload,\n limits: Partial<TransferLimits>,\n omissions: Omission[],\n): Payload {\n limitKeys.forEach((key) => assertLimit(limits[key], key));\n if (payload.kind === \"rows\") {\n const count = Math.min(\n payload.rows.length,\n limits.maxRows ?? payload.rows.length,\n );\n if (count < payload.rows.length)\n omissions.push({\n path: \"/rows\",\n reason: \"truncated\",\n count: payload.rows.length - count,\n });\n return {\n ...payload,\n rows: payload.rows\n .slice(0, count)\n .map(\n (row, index) =>\n limitJson(row, limits, omissions, `/rows/${index}`) as Record<\n string,\n Json\n >,\n ),\n };\n }\n if (payload.kind === \"json\" || payload.kind === \"registered\")\n return { ...payload, value: limitJson(payload.value, limits, omissions) };\n return {\n ...payload,\n text: limitJson(payload.text, limits, omissions) as string,\n };\n}\n/** Applies explicit preparation/source limits with exact omissions; token target is advisory. */\nexport function applyTransferLimits(\n draft: Draft,\n limits: Partial<TransferLimits>,\n): Draft {\n const omissions: Omission[] = [];\n const payload = limitPayload(draft.payload, limits, omissions);\n return omissions.length\n ? revise(draft, payload, omissions, \"Applied preparation limits\")\n : draft;\n}\n","/**\n * Wrap text in a Markdown code fence that cannot be closed by its contents.\n *\n * Fence writing is deliberately centralized here. Consumers should not grow\n * their own backtick-run detection when exporting code-shaped payloads.\n */\nexport function fencedCodeBlock(text: string, language: string): string {\n const runs = text.match(/`+/g) ?? [];\n const fence = \"`\".repeat(Math.max(3, ...runs.map((run) => run.length + 1)));\n return `${fence}${language}\\n${text}${text.endsWith(\"\\n\") ? \"\" : \"\\n\"}${fence}`;\n}\n","/**\n * `@ai-matrx/alchemy/operate/formats/rich-html` — the rich clipboard format (CONTRACT §1.9a).\n *\n * Engine: THE one Markdown→HTML engine (`@ai-matrx/print/markdown-html`, loaded lazily) with the\n * `inline` skin — styles on elements, no class dependence, because Google Docs and Word drop\n * `<style>` and classes on paste. Docs and Word are one action (\"Copy formatted\") until a\n * destination profile produces different bytes. Private images go through the host's asset\n * port. Every HTML string ends in print's allow-list.\n */\n\nimport type { MarkdownHtmlEngine } from \"@ai-matrx/print/markdown-html\";\nimport { ContentTransferError, sealTransferArtifact } from \"../core\";\nimport type { FormatEngine, FormatOptions } from \"../contract\";\nimport type { Artifact, Draft } from \"../types\";\n\nconst ENGINE = Symbol.for(\"ai-matrx.alchemy.operate.markdown-html-engine\");\n\n/** One engine per realm, created on first use (the print module itself loads only here). */\nexport async function loadMarkdownHtmlEngine(): Promise<MarkdownHtmlEngine> {\n const g = globalThis as unknown as Record<symbol, Promise<MarkdownHtmlEngine> | undefined>;\n g[ENGINE] ??= import(\"@ai-matrx/print/markdown-html\").then((m) => m.createMarkdownHtmlEngine());\n return g[ENGINE] as Promise<MarkdownHtmlEngine>;\n}\n\nfunction parseOptions(options: FormatOptions, signal: AbortSignal) {\n return {\n signal,\n ...(options.onNotice ? { onNotice: options.onNotice } : {}),\n ...(options.assets ? { assets: options.assets } : {}),\n };\n}\n\n/** Plain text from the one parse (the `plain` format for Markdown payloads). */\nexport async function markdownPlainText(markdown: string, options: FormatOptions, signal: AbortSignal): Promise<string> {\n const engine = await loadMarkdownHtmlEngine();\n return engine.plainText(await engine.parse(markdown, parseOptions(options, signal)));\n}\n\nexport const richHtmlEngine: FormatEngine = {\n async build(draft: Draft, options: FormatOptions, signal: AbortSignal): Promise<Artifact> {\n if (signal.aborted) throw new DOMException(\"Cancelled\", \"AbortError\");\n if (draft.payload.kind !== \"markdown\") {\n throw new ContentTransferError(\"unsupported-format\", \"Formatted copy needs Markdown content. Copy it as plain text instead.\");\n }\n const engine = await loadMarkdownHtmlEngine();\n const tree = await engine.parse(draft.payload.text, parseOptions(options, signal));\n if (signal.aborted) throw new DOMException(\"Cancelled\", \"AbortError\");\n const html = engine.fragment(tree, { skin: options.skin ?? \"inline\", profile: options.profile ?? \"generic\" });\n return sealTransferArtifact({\n snapshotId: draft.snapshotId,\n draftRevision: draft.revision,\n format: \"rich-html\",\n plainText: engine.plainText(tree),\n html,\n file: { filename: options.filename ?? \"export.html\", mime: \"text/html;charset=utf-8\", bytes: new TextEncoder().encode(html) },\n omissions: draft.omissions.map((o) => ({ ...o })),\n });\n },\n};\n","/**\n * `@ai-matrx/alchemy/operate/formats/document` — HTML page, PDF, DOCX and EPUB (CONTRACT §1.9).\n *\n * One tree: the HTML page is THE one Markdown→HTML engine's `document()` (print's\n * `documentToHtml`, body allow-listed); PDF (vector, selectable text), DOCX and EPUB are print's\n * `/document` writers over the same parse. Print loads only when one of these is chosen.\n * A text payload with a language exports as its fenced code block.\n */\n\nimport { ContentTransferError, sealTransferArtifact } from \"../core\";\nimport type { FormatEngine, FormatOptions } from \"../contract\";\nimport { fencedCodeBlock } from \"../fenced-code\";\nimport type { Artifact, Draft } from \"../types\";\nimport { loadMarkdownHtmlEngine } from \"./rich-html\";\n\nconst enc = new TextEncoder();\n\nfunction markdownOf(draft: Draft): string {\n const p = draft.payload;\n if (p.kind === \"markdown\") return p.text;\n if (p.kind === \"text\") {\n if (!p.language) return p.text;\n return fencedCodeBlock(p.text, p.language);\n }\n throw new ContentTransferError(\"unsupported-format\", \"A document needs text or Markdown content. Download it as JSON or CSV instead.\");\n}\n\nconst stem = (filename: string | undefined) => (filename ? filename.replace(/\\.[a-z0-9]+$/i, \"\") : undefined);\n\n/** The standalone HTML page (the `html` format for prose). */\nexport const documentHtmlEngine: FormatEngine = {\n async build(draft: Draft, options: FormatOptions, signal: AbortSignal): Promise<Artifact> {\n if (signal.aborted) throw new DOMException(\"Cancelled\", \"AbortError\");\n const engine = await loadMarkdownHtmlEngine();\n const tree = await engine.parse(markdownOf(draft), {\n signal,\n ...(options.onNotice ? { onNotice: options.onNotice } : {}),\n ...(options.assets ? { assets: options.assets } : {}),\n });\n const page = engine.document(tree);\n return sealTransferArtifact({\n snapshotId: draft.snapshotId,\n draftRevision: draft.revision,\n format: \"html\",\n plainText: engine.plainText(tree),\n html: page,\n file: { filename: options.filename ?? \"export.html\", mime: \"text/html;charset=utf-8\", bytes: enc.encode(page) },\n omissions: draft.omissions.map((o) => ({ ...o })),\n });\n },\n};\n\n/** PDF / DOCX / EPUB through print's `/document` (lazy). */\nexport function documentEngine(format: \"pdf\" | \"docx\" | \"epub\"): FormatEngine {\n return {\n async build(draft: Draft, options: FormatOptions, signal: AbortSignal): Promise<Artifact> {\n if (signal.aborted) throw new DOMException(\"Cancelled\", \"AbortError\");\n const source = markdownOf(draft);\n const { exportDocument } = await import(\"@ai-matrx/print/document\");\n const name = stem(options.filename);\n const out = await exportDocument(source, format, {\n ...(name ? { fileName: name } : {}),\n ...(options.onNotice ? { onNotice: (n) => options.onNotice?.({ code: n.code, sentence: n.message, remedy: n.remedy }) } : {}),\n });\n if (signal.aborted) throw new DOMException(\"Cancelled\", \"AbortError\");\n return sealTransferArtifact({\n snapshotId: draft.snapshotId,\n draftRevision: draft.revision,\n format,\n plainText: source,\n file: { filename: out.fileName, mime: out.mime, bytes: out.bytes },\n omissions: draft.omissions.map((o) => ({ ...o })),\n });\n },\n };\n}\n"],"mappings":"y5BAAA,uMCAA,uBAA8B,qCAC9B,mBAA2B,qCCKpB,SAAS,gBAAgB,KAAc,SAA0B,CACtE,IAAM,KAAO,KAAK,MAAM,KAAK,GAAK,CAAC,EAC7B,MAAQ,IAAI,OAAO,KAAK,IAAI,EAAG,GAAG,KAAK,IAAK,KAAQ,IAAI,OAAS,CAAC,CAAC,CAAC,EAC1E,MAAO,GAAG,KAAK,GAAG,QAAQ;AAAA,EAAK,IAAI,GAAG,KAAK,SAAS;AAAA,CAAI,EAAI,GAAK;AAAA,CAAI,GAAG,KAAK,EAC/E,CDcA,IAAM,eAAiB,OAAO,IAAI,yCAAyC,EAC9D,qBAAN,cAAmC,KAAM,CACrC,KACA,KAET,YACE,KACA,QACA,KACA,CACA,MAAM,OAAO,EACb,KAAK,KAAO,KACZ,KAAK,KAAO,KACX,KAAyC,cAAc,EAAI,EAC9D,CAOA,OAAiB,OAAO,WAAW,EAAE,MAAyB,CAC5D,OAAO,OAAO,OAAU,UAAY,QAAU,MAAS,MAAkC,cAAc,IAAM,EAC/G,CACF,EAwIA,SAAS,WAAc,EAAS,CAC9B,GAAI,YAAY,OAAO,CAAC,EAAG,OAAO,EAClC,GAAI,GAAK,OAAO,GAAM,UAAY,CAAC,OAAO,SAAS,CAAC,EAAG,CACrD,OAAO,OAAO,CAAC,EACf,QAAW,KAAK,OAAO,OAAO,CAAW,EAAG,WAAW,CAAC,CAC1D,CACA,OAAO,CACT,CA+yBO,SAAS,qBAAqB,SAA8B,CACjE,GAAI,CAAC,SAAS,KACZ,OAAO,WAAW,CAChB,GAAG,SACH,UAAW,SAAS,UAAU,IAAK,IAAO,CAAE,GAAG,CAAE,EAAE,CACrD,CAAC,EACH,IAAM,MAAQ,SAAS,KAAK,MAAM,MAAM,EAClC,KAAO,CACX,SAAU,SAAS,KAAK,SACxB,KAAM,SAAS,KAAK,KACpB,IAAI,OAAQ,CACV,OAAO,MAAM,MAAM,CACrB,CACF,EACA,OAAO,WAAW,CAChB,GAAG,SACH,KACA,UAAW,SAAS,UAAU,IAAK,IAAO,CAAE,GAAG,CAAE,EAAE,CACrD,CAAC,CACH,CEl/BA,IAAM,OAAS,OAAO,IAAI,+CAA+C,EAGzE,eAAsB,wBAAsD,CAC1E,IAAM,EAAI,WACV,SAAE,MAAM,IAAM,OAAO,+BAA+B,EAAE,KAAM,GAAM,EAAE,yBAAyB,CAAC,EACvF,EAAE,MAAM,CACjB,CCPA,IAAM,IAAM,IAAI,YAEhB,SAAS,WAAW,MAAsB,CACxC,IAAM,EAAI,MAAM,QAChB,GAAI,EAAE,OAAS,WAAY,OAAO,EAAE,KACpC,GAAI,EAAE,OAAS,OACb,OAAK,EAAE,SACA,gBAAgB,EAAE,KAAM,EAAE,QAAQ,EADjB,EAAE,KAG5B,MAAM,IAAI,qBAAqB,qBAAsB,gFAAgF,CACvI,CAEA,IAAM,KAAQ,UAAkC,SAAW,SAAS,QAAQ,gBAAiB,EAAE,EAAI,OAGtF,mBAAmC,CAC9C,MAAM,MAAM,MAAc,QAAwB,OAAwC,CACxF,GAAI,OAAO,QAAS,MAAM,IAAI,aAAa,YAAa,YAAY,EACpE,IAAM,OAAS,MAAM,uBAAuB,EACtC,KAAO,MAAM,OAAO,MAAM,WAAW,KAAK,EAAG,CACjD,OACA,GAAI,QAAQ,SAAW,CAAE,SAAU,QAAQ,QAAS,EAAI,CAAC,EACzD,GAAI,QAAQ,OAAS,CAAE,OAAQ,QAAQ,MAAO,EAAI,CAAC,CACrD,CAAC,EACK,KAAO,OAAO,SAAS,IAAI,EACjC,OAAO,qBAAqB,CAC1B,WAAY,MAAM,WAClB,cAAe,MAAM,SACrB,OAAQ,OACR,UAAW,OAAO,UAAU,IAAI,EAChC,KAAM,KACN,KAAM,CAAE,SAAU,QAAQ,UAAY,cAAe,KAAM,0BAA2B,MAAO,IAAI,OAAO,IAAI,CAAE,EAC9G,UAAW,MAAM,UAAU,IAAK,IAAO,CAAE,GAAG,CAAE,EAAE,CAClD,CAAC,CACH,CACF,EAGO,SAAS,eAAe,OAA+C,CAC5E,MAAO,CACL,MAAM,MAAM,MAAc,QAAwB,OAAwC,CACxF,GAAI,OAAO,QAAS,MAAM,IAAI,aAAa,YAAa,YAAY,EACpE,IAAM,OAAS,WAAW,KAAK,EACzB,CAAE,cAAe,EAAI,KAAM,QAAO,0BAA0B,EAC5D,KAAO,KAAK,QAAQ,QAAQ,EAC5B,IAAM,MAAM,eAAe,OAAQ,OAAQ,CAC/C,GAAI,KAAO,CAAE,SAAU,IAAK,EAAI,CAAC,EACjC,GAAI,QAAQ,SAAW,CAAE,SAAW,GAAM,QAAQ,WAAW,CAAE,KAAM,EAAE,KAAM,SAAU,EAAE,QAAS,OAAQ,EAAE,MAAO,CAAC,CAAE,EAAI,CAAC,CAC7H,CAAC,EACD,GAAI,OAAO,QAAS,MAAM,IAAI,aAAa,YAAa,YAAY,EACpE,OAAO,qBAAqB,CAC1B,WAAY,MAAM,WAClB,cAAe,MAAM,SACrB,OACA,UAAW,OACX,KAAM,CAAE,SAAU,IAAI,SAAU,KAAM,IAAI,KAAM,MAAO,IAAI,KAAM,EACjE,UAAW,MAAM,UAAU,IAAK,IAAO,CAAE,GAAG,CAAE,EAAE,CAClD,CAAC,CACH,CACF,CACF","names":[]}
1
+ {"version":3,"sources":["../src/operate-document.ts","../src/operate/core.ts","../src/operate/fenced-code.ts","../src/operate/formats/rich-html.ts","../src/operate/formats/document.ts"],"sourcesContent":["export { documentEngine, documentHtmlEngine } from \"./operate/formats/document\";\n","import { stringifyJson } from \"@ai-matrx/kit/json-format\";\nimport { escapeHtml } from \"@ai-matrx/kit/html-escape\";\nimport {\n ContentTransferError,\n cloneTransferJson,\n normalizeTransferJson,\n normalizeTransferJsonAtPath,\n} from \"@ai-matrx/kit/transfer-json\";\nexport {\n ContentTransferError,\n normalizeTransferJson,\n type NormalizeTransferJsonOptions,\n} from \"@ai-matrx/kit/transfer-json\";\nimport type {\n Artifact,\n CapturedAllMatching,\n CapturedSource,\n Column,\n Draft,\n ExportProjection,\n Json,\n Omission,\n Payload,\n RawSnapshot,\n Snapshot,\n Source,\n Transport,\n TransferScope,\n TransferLimits,\n TransferPreferences,\n SurfaceHandle,\n} from \"./types\";\nexport * from \"./types\";\nexport * from \"./agent-payload\";\n\n/** A realm-wide brand (Symbol.for), so a binding made by one loaded copy is recognised by another. */\nconst bound: unique symbol = Symbol.for(\"ai-matrx.alchemy.operate.bound-all-matching\");\nexport type BoundAllMatching = {\n readonly [bound]: true;\n readonly source: CapturedAllMatching;\n readonly projection: ExportProjection;\n readonly columns: readonly Column[];\n readonly limits?: TransferLimits;\n};\nconst stop = (s: AbortSignal) => {\n if (s.aborted) throw new DOMException(\"Cancelled\", \"AbortError\");\n};\nconst enc = (x: string) => x.replace(/~/g, \"~0\").replace(/\\//g, \"~1\");\nconst dec = (x: string) => x.replace(/~1/g, \"/\").replace(/~0/g, \"~\");\nconst maxSurfacePointerSegmentLength = 64;\nconst maxSurfacePointerLength = 192;\nconst truncateSurfacePointer = (value: string, maxLength: number) => {\n const characters = Array.from(value);\n return characters.length > maxLength\n ? `${characters.slice(0, maxLength - 1).join(\"\")}…`\n : value;\n};\nfunction displaySurfacePointer(path: string | undefined): string {\n if (!path) return \"/\";\n const safe = path\n .split(\"/\")\n .slice(1)\n .map((segment) => {\n const controlSafe = segment.replace(/[\\u0000-\\u001F\\u007F-\\u009F]/g, (character) =>\n `\\\\u${character.charCodeAt(0).toString(16).padStart(4, \"0\")}`,\n );\n return truncateSurfacePointer(controlSafe, maxSurfacePointerSegmentLength);\n })\n .join(\"/\");\n const pointer = `/${safe}`;\n return truncateSurfacePointer(pointer, maxSurfacePointerLength);\n}\nfunction cloneSurfaceValue(value: unknown, path: string): Json {\n try {\n return normalizeTransferJsonAtPath(value, path, {\n omitUndefinedObjectProperties: true,\n });\n } catch (error) {\n if (error instanceof ContentTransferError)\n throw new ContentTransferError(\n error.code,\n `Surface capture rejected value at ${displaySurfacePointer(error.path)}: ${error.message}`,\n error.path,\n );\n throw error;\n }\n}\nfunction deepFreeze<T>(v: T): T {\n if (ArrayBuffer.isView(v)) return v;\n if (v && typeof v === \"object\" && !Object.isFrozen(v)) {\n Object.freeze(v);\n for (const x of Object.values(v as object)) deepFreeze(x);\n }\n return v;\n}\nfunction at(v: Json, path: string): Json | undefined {\n validatePointer(path);\n if (path === \"\") return v;\n if (!path.startsWith(\"/\"))\n throw new ContentTransferError(\n \"invalid-path\",\n \"Expected RFC 6901 pointer\",\n path,\n );\n let cur: Json | undefined = v;\n for (const part of path.slice(1).split(\"/\").map(dec)) {\n if (Array.isArray(cur)) cur = cur[Number(part)];\n else if (cur && typeof cur === \"object\")\n cur = Object.hasOwn(cur, part) ? cur[part] : undefined;\n else return undefined;\n }\n return cur;\n}\nfunction validatePointer(path: string): void {\n if ((path !== \"\" && !path.startsWith(\"/\")) || /~(?![01])/u.test(path))\n throw new ContentTransferError(\n \"invalid-path\",\n \"Expected an RFC 6901 JSON pointer\",\n path,\n );\n}\n/** Column ids are identities, never an alternative data address. */\nexport function readTransferCell(\n row: Record<string, Json>,\n column: Column,\n): Json | undefined {\n return at(row, column.path);\n}\nfunction without(\n v: Json,\n paths: readonly string[],\n omit: Omission[],\n path = \"\",\n): Json | undefined {\n if (paths.includes(path)) {\n omit.push({ path, reason: \"excluded\" });\n return undefined;\n }\n if (Array.isArray(v))\n return v\n .map((x, i) => without(x, paths, omit, `${path}/${i}`))\n .filter((x): x is Json => x !== undefined);\n if (v && typeof v === \"object\") {\n const out: Record<string, Json> = Object.create(null);\n for (const [k, x] of Object.entries(v)) {\n const y = without(x, paths, omit, `${path}/${enc(k)}`);\n if (y !== undefined) out[k] = y;\n }\n return out;\n }\n return v;\n}\nfunction projectValue(\n v: Json,\n rules: ExportProjection[\"rules\"],\n target: \"payload\" | \"row\",\n omit: Omission[],\n): Json {\n rules.forEach((rule) => validatePointer(rule.path));\n return (\n without(\n cloneTransferJson(v),\n rules\n .filter(\n (r) =>\n r.target === target &&\n (!r.exportable || r.classification !== \"ordinary\"),\n )\n .map((r) => r.path),\n omit,\n ) ?? null\n );\n}\nfunction excludedColumn(column: Column): boolean {\n return (\n column.exportable === false ||\n column.classification === \"secret\" ||\n column.classification === \"credential\"\n );\n}\nfunction rowProjectionExcludesColumnSchema(\n column: Column,\n rules: ExportProjection[\"rules\"],\n): boolean {\n return rules.some(\n (rule) =>\n rule.target === \"row\" &&\n (!rule.exportable || rule.classification !== \"ordinary\") &&\n (rule.path === column.path || column.path.startsWith(`${rule.path}/`)),\n );\n}\n/** Project the schema with the same payload rules that govern column metadata. */\nfunction projectColumnSchema(\n column: Column,\n rules: ExportProjection[\"rules\"],\n omit: Omission[],\n): Column[\"schema\"] | undefined {\n if (column.schema === undefined) return undefined;\n const root = `/columns/${enc(column.id)}/schema`;\n const schemaRules = rules\n .filter((rule) => rule.target === \"payload\" && (rule.path === root || rule.path.startsWith(`${root}/`)))\n .map((rule) => ({ ...rule, path: rule.path.slice(root.length) }));\n const projected = projectValue(column.schema, schemaRules, \"payload\", omit);\n if (schemaRules.some((rule) => rule.path === \"\" && (!rule.exportable || rule.classification !== \"ordinary\")))\n return undefined;\n return projected as Column[\"schema\"];\n}\nfunction normalize(\n p: Payload,\n projection: ExportProjection,\n omit: Omission[],\n): Payload {\n if (p.kind === \"text\" || p.kind === \"markdown\") {\n if (typeof p.text !== \"string\")\n throw new ContentTransferError(\n \"unsupported-value\",\n \"Text payload must contain a string\",\n \"/text\",\n );\n const value = projectValue(p.text, projection.rules, \"payload\", omit);\n const text = typeof value === \"string\" ? value : \"\";\n // A code block keeps its language (downloads take its extension; Markdown fences it).\n return p.kind === \"text\" && typeof p.language === \"string\" && p.language.trim()\n ? { kind: \"text\", text, language: p.language.trim() }\n : { kind: p.kind, text };\n }\n if (p.kind === \"json\")\n return {\n kind: \"json\",\n value: projectValue(p.value, projection.rules, \"payload\", omit),\n };\n if (p.kind === \"registered\")\n return {\n kind: \"registered\",\n format: p.format,\n value: projectValue(p.value, projection.rules, \"payload\", omit),\n };\n const rowsPayload = p as Extract<Payload, { kind: \"rows\" }>;\n if (p.kind !== \"rows\")\n throw new ContentTransferError(\n \"invalid-payload\",\n \"Unsupported payload kind\",\n );\n const sourceColumns = rowsPayload.columns.map((column) => ({ ...column }));\n const columns = sourceColumns\n .filter((column) => !excludedColumn(column))\n .map((column) => {\n // Do not spread source schema back after an explicit schema or row exclusion.\n const { schema: _sourceSchema, ...withoutSchema } = column;\n const schema = rowProjectionExcludesColumnSchema(column, projection.rules)\n ? undefined\n : projectColumnSchema(column, projection.rules, omit);\n return {\n ...withoutSchema,\n ...(schema === undefined ? {} : { schema }),\n };\n });\n resolveTransferRegistry(columns);\n columns.forEach((column) => validatePointer(column.path));\n const rules = [\n ...projection.rules,\n ...sourceColumns\n .filter(excludedColumn)\n .map((c) => ({\n target: \"row\" as const,\n path: c.path,\n exportable: c.exportable ?? true,\n classification: c.classification ?? (\"ordinary\" as const),\n })),\n ];\n return {\n kind: \"rows\",\n columns,\n rows: rowsPayload.rows.map((row, index) => {\n if (!row || typeof row !== \"object\" || Array.isArray(row))\n throw new ContentTransferError(\n \"invalid-row\",\n \"A table row must be a JSON object\",\n `/rows/${index}`,\n );\n const projected = projectValue(row, rules, \"row\", omit);\n return projected === null ? {} : (projected as Record<string, Json>);\n }),\n };\n}\nexport function projectSnapshot(\n raw: RawSnapshot,\n projection: ExportProjection,\n): Snapshot {\n const omissions = raw.omissions.map((o) => ({ ...o }));\n const normalized = normalize(raw.payload, projection, omissions);\n const payload = raw.limits\n ? limitPayload(normalized, raw.limits, omissions)\n : normalized;\n const included =\n payload.kind === \"rows\" ? payload.rows.length : raw.coverage.included;\n return deepFreeze({\n ...raw,\n payload,\n coverage: {\n ...raw.coverage,\n included,\n ...(included < raw.coverage.included\n ? { status: \"partial\" as const, reason: \"Source export limit applied\" }\n : {}),\n },\n omissions,\n sections: raw.sections\n .filter(\n (section) =>\n !projection.rules.some(\n (rule) =>\n rule.target === \"payload\" &&\n (!rule.exportable || rule.classification !== \"ordinary\") &&\n (section.path === rule.path ||\n section.path.startsWith(`${rule.path}/`)),\n ),\n )\n .map((x) => ({ ...x })),\n ...(raw.limits ? { limits: { ...raw.limits } } : {}),\n } as Snapshot);\n}\nconst uid = () =>\n globalThis.crypto?.randomUUID?.() ?? `capture-${Date.now()}-${Math.random()}`;\nexport function directSource(\n payload: Payload,\n options: Partial<\n Pick<\n RawSnapshot,\n | \"id\"\n | \"sourceId\"\n | \"revision\"\n | \"label\"\n | \"coverage\"\n | \"unsavedChanges\"\n | \"sections\"\n | \"limits\"\n > & { projection: ExportProjection }\n > = {},\n): CapturedSource {\n const id = options.id ?? uid();\n return {\n projection: options.projection ?? { rules: [] },\n snapshot: {\n id,\n sourceId: options.sourceId ?? id,\n revision: options.revision ?? uid(),\n capturedAt: new Date().toISOString(),\n label: options.label ?? \"Content\",\n payload,\n coverage: options.coverage ?? {\n status: \"complete\",\n included: payload.kind === \"rows\" ? payload.rows.length : 1,\n total: payload.kind === \"rows\" ? payload.rows.length : 1,\n },\n unsavedChanges: options.unsavedChanges ?? false,\n omissions: [],\n sections: options.sections ?? [],\n ...(options.limits ? { limits: { ...options.limits } } : {}),\n },\n };\n}\nexport async function capture(\n source: Source | Payload,\n signal: AbortSignal,\n scope: TransferScope = \"target\",\n): Promise<{ snapshot: Snapshot; allMatching?: BoundAllMatching }> {\n stop(signal);\n const captured =\n \"kind\" in source\n ? directSource(source)\n : await source.capture({ scope, signal });\n stop(signal);\n const all = captured.allMatching;\n if (\n all &&\n (all.query.sourceId !== captured.snapshot.sourceId ||\n all.query.revision !== captured.snapshot.revision ||\n all.query.order.length === 0)\n )\n throw new ContentTransferError(\n \"query-mismatch\",\n \"All-matching query must be captured with stable ordering\",\n );\n const snapshot = projectSnapshot(captured.snapshot, captured.projection);\n if (!all) return { snapshot };\n return {\n snapshot,\n allMatching: deepFreeze({\n [bound]: true as const,\n source: {\n ...all,\n query: {\n ...all.query,\n query: cloneTransferJson(all.query.query),\n order: all.query.order.map((x) => ({ ...x })),\n },\n },\n projection: { rules: captured.projection.rules.map((x) => ({ ...x })) },\n // Page rows must be normalized against the original declaration so excluded\n // column values are removed before stable IDs or any caller can observe them.\n columns:\n captured.snapshot.payload.kind === \"rows\"\n ? captured.snapshot.payload.columns.map((column) => ({ ...column }))\n : [],\n ...(snapshot.limits ? { limits: { ...snapshot.limits } } : {}),\n }),\n };\n}\nexport function createDraft(s: Snapshot): Draft {\n return deepFreeze({\n snapshotId: s.id,\n sourceId: s.sourceId,\n sourceRevision: s.revision,\n revision: 0,\n payload: normalize(s.payload, { rules: [] }, []),\n omissions: [...s.omissions],\n manuallyEdited: false,\n provenance: [{ kind: \"original\", description: \"Captured source snapshot\" }],\n });\n}\nfunction revise(\n d: Draft,\n p: Payload,\n o: Omission[],\n description: string,\n manual = d.manuallyEdited,\n kind: Draft[\"provenance\"][number][\"kind\"] = \"deterministic\",\n baseOmissions: readonly Omission[] = d.omissions,\n): Draft {\n const { history: _history, ...previous } = d;\n return deepFreeze({\n ...d,\n revision: d.revision + 1,\n payload: normalize(p, { rules: [] }, []),\n omissions: [...baseOmissions, ...o],\n manuallyEdited: manual,\n provenance: [...d.provenance, { kind, description }],\n history: [...(d.history ?? []), previous],\n });\n}\nexport const editDraft = (d: Draft, p: Payload) =>\n revise(d, p, [], \"Manual edit\", true, \"manual\");\n/**\n * A deterministic revision of `d` (the structure trees, PP-06/07): same snapshot, next revision,\n * the given omissions added. `baseOmissions` replaces the draft's own when a step re-projects from\n * the snapshot (a section selection), exactly as `applySectionSelection` does.\n */\nexport const deriveDraft = (\n d: Draft,\n p: Payload,\n o: Omission[],\n description: string,\n baseOmissions: readonly Omission[] = d.omissions,\n) => revise(d, p, o, description, d.manuallyEdited, \"deterministic\", baseOmissions);\nexport const resetDraft = (s: Snapshot) => createDraft(s);\nexport const sourceChanged = (d: Draft, s: Snapshot) =>\n d.sourceId !== s.sourceId || d.sourceRevision !== s.revision;\nexport function undoDraft(d: Draft): Draft {\n const previous = d.history?.at(-1);\n if (!previous) return d;\n return deepFreeze({\n ...previous,\n revision: d.revision + 1,\n history: d.history!.slice(0, -1),\n });\n}\n/** Keep and regenerate are explicit choices; observing fresh data never overwrites edits. */\nexport function refreshDraft(\n draft: Draft,\n snapshot: Snapshot,\n choice: \"keep\" | \"regenerate\",\n): Draft {\n return choice === \"keep\" ? draft : createDraft(snapshot);\n}\nexport function applySectionSelection(\n d: Draft,\n s: Snapshot,\n ids: readonly string[],\n): Draft {\n if (\n d.snapshotId !== s.id ||\n d.sourceId !== s.sourceId ||\n d.sourceRevision !== s.revision\n )\n throw new ContentTransferError(\n \"snapshot-mismatch\",\n \"Section selection requires the draft's captured source snapshot\",\n );\n const selected = new Set(ids),\n omit: Omission[] = [],\n paths = s.sections\n .filter((x) => !selected.has(x.id))\n .map((x) => {\n omit.push({ path: x.path, reason: \"excluded\" });\n return x.path;\n }),\n // Selection is a replacement projection from the snapshot, so only the\n // snapshot's omissions remain authoritative. Retaining draft omissions\n // would preserve stale transforms after the snapshot payload is rebuilt.\n baseOmissions = s.omissions;\n if (s.payload.kind === \"json\")\n return revise(\n d,\n { kind: \"json\", value: without(s.payload.value, paths, []) ?? null },\n omit,\n \"Selected sections\",\n d.manuallyEdited,\n \"deterministic\",\n baseOmissions,\n );\n if (s.payload.kind === \"registered\")\n return revise(\n d,\n {\n kind: \"registered\",\n format: s.payload.format,\n value: without(s.payload.value, paths, []) ?? null,\n },\n omit,\n \"Selected sections\",\n d.manuallyEdited,\n \"deterministic\",\n baseOmissions,\n );\n if (s.payload.kind === \"markdown\" || s.payload.kind === \"text\") {\n // A prose section is a character range of the text: `/text/<start>-<end>`.\n const text = s.payload.text;\n const ranges = paths\n .map((path) => {\n const m = /^\\/text\\/(\\d+)-(\\d+)$/.exec(path);\n const start = m ? Number(m[1]) : NaN,\n end = m ? Number(m[2]) : NaN;\n if (!m || start > end || end > text.length)\n throw new ContentTransferError(\n \"invalid-section\",\n `Section \"${path}\" is not a range of this text. Declare a prose section as /text/<start>-<end> within the text.`,\n );\n return [start, end] as const;\n })\n .sort((a, b) => b[0] - a[0]);\n let kept = text;\n for (const [start, end] of ranges) kept = kept.slice(0, start) + kept.slice(end);\n return revise(\n d,\n { ...s.payload, text: kept },\n omit,\n \"Selected sections\",\n d.manuallyEdited,\n \"deterministic\",\n baseOmissions,\n );\n }\n return revise(\n d,\n s.payload,\n omit,\n \"Selected sections\",\n d.manuallyEdited,\n \"deterministic\",\n baseOmissions,\n );\n}\nexport function transformRows(\n d: Draft,\n o: {\n search?: string;\n sort?: { column: string; direction: \"asc\" | \"desc\" };\n filters?: Readonly<Record<string, string>>;\n /** Positions in this call's input draft rows; unlike ids, no guessed key is used. */\n selectedIndices?: readonly number[];\n selectedIds?: readonly string[];\n idColumn?: string;\n visibleColumns?: readonly string[];\n structuredProjection?: \"full\" | \"visible\";\n top?: number | null;\n },\n): Draft {\n if (d.payload.kind !== \"rows\") return d;\n // Validate before deciding whether truncation is necessary. A negative/NaN\n // top is an invalid request even for an empty result set.\n if (o.top != null) assertLimit(o.top, \"maxRows\");\n const cols = o.visibleColumns\n ? o.visibleColumns\n .map((id) =>\n d.payload.kind === \"rows\"\n ? d.payload.columns.find((c) => c.id === id)\n : undefined,\n )\n .filter((c): c is Column => Boolean(c))\n : d.payload.columns.filter((c) => c.visible);\n const get = readTransferCell;\n let rows = [...d.payload.rows],\n omit: Omission[] = [];\n const before = rows.length;\n if (o.selectedIndices !== undefined) {\n const selected = new Set<number>();\n for (const index of o.selectedIndices) {\n if (!Number.isSafeInteger(index) || index < 0 || index >= d.payload.rows.length)\n throw new ContentTransferError(\n \"invalid-selection-index\",\n \"Selected row indexes must be non-negative positions in the input draft rows\",\n );\n selected.add(index);\n }\n rows = d.payload.rows.filter((_, index) => selected.has(index));\n }\n if (o.selectedIds && o.idColumn) {\n const set = new Set(o.selectedIds);\n const idColumn = d.payload.columns.find((c) => c.id === o.idColumn);\n rows = rows.filter((r) =>\n set.has(String(idColumn ? get(r, idColumn) : r[o.idColumn!])),\n );\n }\n if (o.search) {\n const q = o.search.toLowerCase();\n rows = rows.filter((r) =>\n cols.some((c) =>\n String(get(r, c) ?? \"\")\n .toLowerCase()\n .includes(q),\n ),\n );\n }\n for (const [id, q] of Object.entries(o.filters ?? {})) {\n const c = cols.find((x) => x.id === id);\n if (c)\n rows = rows.filter((r) =>\n String(get(r, c) ?? \"\")\n .toLowerCase()\n .includes(q.toLowerCase()),\n );\n }\n if (rows.length !== before)\n omit.push({\n path: \"/rows\",\n reason: \"filtered\",\n count: before - rows.length,\n });\n if (o.sort) {\n const c = cols.find((x) => x.id === o.sort!.column);\n if (c)\n rows.sort((a, b) => {\n const left = get(a, c);\n const right = get(b, c);\n const compare =\n typeof left === \"number\" && typeof right === \"number\"\n ? left - right\n : String(left ?? \"\").localeCompare(String(right ?? \"\"));\n return compare * (o.sort!.direction === \"asc\" ? 1 : -1);\n });\n }\n if (o.top != null && rows.length > o.top) {\n omit.push({\n path: \"/rows\",\n reason: \"truncated\",\n count: rows.length - o.top,\n });\n rows = rows.slice(0, o.top);\n }\n if (o.structuredProjection === \"visible\") {\n rows = rows.map((r) =>\n Object.fromEntries(cols.map((c) => [c.id, get(r, c) ?? null])),\n );\n const excludedColumns = d.payload.columns.length - cols.length;\n if (excludedColumns > 0)\n omit.push({\n path: \"/columns\",\n reason: \"excluded\",\n count: excludedColumns,\n });\n }\n return revise(\n d,\n {\n kind: \"rows\",\n rows,\n columns: cols.map((c) => ({\n ...c,\n visible: true,\n ...(o.structuredProjection === \"visible\"\n ? { path: `/${enc(c.id)}` }\n : {}),\n })),\n },\n omit,\n \"Prepared row subset\",\n );\n}\nexport function reduceJson(\n draft: Draft,\n options: {\n exclude?: readonly string[];\n maxDepth?: number | null;\n maxStringChars?: number | null;\n maxArrayItems?: number | null;\n },\n): Draft {\n if (draft.payload.kind !== \"json\" && draft.payload.kind !== \"registered\")\n return draft;\n const omissions: Omission[] = [];\n options.exclude?.forEach(validatePointer);\n const filtered =\n without(cloneTransferJson(draft.payload.value), options.exclude ?? [], omissions) ??\n null;\n const payload = limitPayload(\n { ...draft.payload, value: filtered },\n options,\n omissions,\n );\n return revise(draft, payload, omissions, \"Reduced JSON\");\n}\nexport async function collectAllMatching(\n c: BoundAllMatching,\n signal: AbortSignal,\n): Promise<{\n rows: Record<string, Json>[];\n coverage: RawSnapshot[\"coverage\"];\n omissions: Omission[];\n error?: ContentTransferError;\n}> {\n const rows: Record<string, Json>[] = [],\n omissions: Omission[] = [],\n ids = new Set<string>(),\n cursors = new Set<string>();\n let cursor: string | null = null,\n token: string | null | undefined,\n last: RawSnapshot[\"coverage\"] = {\n status: \"unknown\",\n included: 0,\n total: null,\n };\n let certifiedTotal: number | null | undefined;\n const maxRows = c.limits?.maxRows;\n if (maxRows != null) assertLimit(maxRows, \"maxRows\");\n const finishAtLimit = (total: number | null, knownOmitted?: number) => ({\n rows: deepFreeze(rows),\n omissions: deepFreeze([\n ...omissions,\n {\n path: \"/rows\",\n reason: \"truncated\" as const,\n ...(knownOmitted === undefined || knownOmitted <= 0\n ? {}\n : { count: knownOmitted }),\n },\n ]),\n coverage: deepFreeze({\n status: \"partial\" as const,\n included: rows.length,\n total,\n reason: \"Source export limit applied\",\n }),\n });\n try {\n // A zero source cap is still a real cap: do not request a page merely to\n // discover data that the caller is not allowed to receive.\n if (maxRows === 0) return finishAtLimit(null);\n do {\n stop(signal);\n const page = await c.source.page({\n query: c.source.query,\n cursor,\n consistencyToken: token ?? null,\n signal,\n });\n stop(signal);\n if (token === undefined) token = page.consistencyToken;\n else if (page.consistencyToken !== token)\n throw new ContentTransferError(\n \"consistency-token-changed\",\n \"All-matching export changed during collection\",\n );\n if (page.coverage.included !== page.rows.length)\n throw new ContentTransferError(\n \"invalid-page-coverage\",\n \"Page count does not match returned rows\",\n );\n if (\n page.coverage.total !== null &&\n (!Number.isSafeInteger(page.coverage.total) || page.coverage.total < 0)\n )\n throw new ContentTransferError(\n \"invalid-page-coverage\",\n \"Page total must be a non-negative integer or null\",\n );\n if (certifiedTotal === undefined) certifiedTotal = page.coverage.total;\n else if (page.coverage.total !== certifiedTotal)\n throw new ContentTransferError(\n \"inconsistent-total\",\n \"All-matching source changed its reported total during collection\",\n );\n const projected = (\n normalize(\n { kind: \"rows\", rows: page.rows, columns: [...c.columns] },\n c.projection,\n omissions,\n ) as Extract<Payload, { kind: \"rows\" }>\n ).rows;\n let uniqueBeyondLimit = 0;\n for (const row of projected) {\n // The callback is part of the transfer boundary, so it receives only\n // the projected row. Sources requiring identity must declare an\n // exportable opaque ID; raw credential/non-exportable fields never\n // cross this seam merely for de-duplication.\n const id = c.source.getRowId(row);\n if (!id)\n throw new ContentTransferError(\n \"invalid-row-id\",\n \"All-matching source returned empty projected ID\",\n );\n if (!ids.has(id)) {\n ids.add(id);\n if (maxRows == null || rows.length < maxRows)\n rows.push(\n (\n limitPayload(\n { kind: \"rows\", rows: [row], columns: [...c.columns] },\n { ...c.limits, maxRows: null },\n omissions,\n ) as Extract<Payload, { kind: \"rows\" }>\n ).rows[0]!,\n );\n else uniqueBeyondLimit += 1;\n } else omissions.push({ path: `/rows/${enc(id)}`, reason: \"duplicate\" });\n }\n // Check after de-duplication and before the source-cap return: ids also\n // includes unique rows that the cap intentionally did not retain.\n if (page.coverage.total !== null && page.coverage.total < ids.size)\n throw new ContentTransferError(\n \"invalid-page-coverage\",\n \"Page total is smaller than the accumulated unique row count\",\n );\n last = page.coverage;\n if (\n maxRows != null &&\n rows.length >= maxRows &&\n (uniqueBeyondLimit > 0 || page.nextCursor !== null)\n )\n return finishAtLimit(\n page.coverage.total,\n page.nextCursor === null\n ? uniqueBeyondLimit\n : page.coverage.total != null && page.coverage.total > rows.length\n ? page.coverage.total - rows.length\n : undefined,\n );\n cursor = page.nextCursor;\n if (cursor !== null && (!cursor || cursors.has(cursor)))\n throw new ContentTransferError(\n \"non-advancing-cursor\",\n \"All-matching source repeated a cursor\",\n );\n if (cursor) cursors.add(cursor);\n } while (cursor !== null);\n const complete =\n c.source.stableSnapshot === true &&\n last.status === \"complete\" &&\n last.total === rows.length &&\n token !== undefined;\n return {\n rows: deepFreeze(rows),\n omissions: deepFreeze(omissions),\n coverage: deepFreeze(\n complete\n ? { ...last, included: rows.length }\n : {\n ...last,\n status: \"partial\",\n included: rows.length,\n reason:\n last.reason ??\n \"Source did not certify a stable complete snapshot\",\n },\n ),\n };\n } catch (e) {\n const error =\n e instanceof ContentTransferError\n ? e\n : new ContentTransferError(\n signal.aborted ? \"cancelled\" : \"page-failed\",\n e instanceof Error ? e.message : \"Page collection failed\",\n );\n return {\n rows: deepFreeze(rows),\n omissions: deepFreeze(omissions),\n coverage: deepFreeze({\n status: \"partial\",\n included: rows.length,\n total: last.total,\n reason: error.message,\n }),\n error,\n };\n }\n}\n// An EMPTY cell is empty text. `null` is how a row carries \"nothing here\"\n// (hosts normalise a missing cell to JSON null so the row keeps its shape), and\n// until 2026-09-21 it serialized as the word \"null\" in every plain / CSV / TSV\n// / Markdown copy — six \"null\"s across a copied row of a data table.\nconst textValue = (value: Json | undefined): string =>\n value === undefined || value === null\n ? \"\"\n : typeof value === \"string\"\n ? value\n : stringifyJson(value, { style: \"compact\" });\n\n/** Preserve artifact-byte identity even if a consumer mutates a returned view. */\nexport function sealTransferArtifact(artifact: Artifact): Artifact {\n if (!artifact.file)\n return deepFreeze({\n ...artifact,\n omissions: artifact.omissions.map((o) => ({ ...o })),\n });\n const bytes = artifact.file.bytes.slice();\n const file = {\n filename: artifact.file.filename,\n mime: artifact.file.mime,\n get bytes() {\n return bytes.slice();\n },\n };\n return deepFreeze({\n ...artifact,\n file,\n omissions: artifact.omissions.map((o) => ({ ...o })),\n });\n}\n\n/** The columns a text serialization writes: visible, exportable, never secret or credential. */\nexport function exportedColumns(columns: readonly Column[]): Column[] {\n return columns.filter(\n (c) =>\n c.visible &&\n c.exportable !== false &&\n c.classification !== \"secret\" &&\n c.classification !== \"credential\",\n );\n}\n\nexport function serialize(\n draft: Draft,\n format:\n \"plain\" | \"markdown\" | \"json\" | \"compact-json\" | \"csv\" | \"tsv\" | \"html\",\n options: { spreadsheetSafe?: boolean; filename?: string } = {},\n): Artifact {\n const payload = draft.payload;\n const omissions = draft.omissions.map((o) => ({ ...o }));\n let plainText = \"\",\n html: string | undefined;\n let mime = \"text/plain;charset=utf-8\",\n extension = \"txt\";\n const columnCell = (row: Record<string, Json>, column: Column) =>\n textValue(readTransferCell(row, column));\n if ((format === \"csv\" || format === \"tsv\") && payload.kind !== \"rows\") {\n throw new ContentTransferError(\n \"unsupported-format\",\n `${format.toUpperCase()} requires tabular data`,\n );\n }\n if (format === \"json\" || format === \"compact-json\") {\n const value =\n payload.kind === \"rows\"\n ? payload.rows\n : payload.kind === \"text\" || payload.kind === \"markdown\"\n ? payload.text\n : payload.value;\n plainText = stringifyJson(value, {\n style: format === \"json\" ? \"pretty\" : \"compact\",\n });\n mime = \"application/json;charset=utf-8\";\n extension = \"json\";\n } else if (payload.kind === \"rows\") {\n const columns = exportedColumns(payload.columns);\n if (format === \"markdown\") {\n const escapeCell = (value: string) =>\n escapeHtml(value)\n .replace(/\\\\/g, \"\\\\\\\\\")\n .replace(/\\|/g, \"\\\\|\")\n .replace(/\\r\\n|\\r|\\n/g, \"<br>\");\n plainText = [\n `| ${columns.map((c) => escapeCell(c.label)).join(\" | \")} |`,\n `| ${columns.map(() => \"---\").join(\" | \")} |`,\n ...payload.rows.map(\n (row) =>\n `| ${columns.map((c) => escapeCell(columnCell(row, c))).join(\" | \")} |`,\n ),\n ].join(\"\\n\");\n mime = \"text/markdown;charset=utf-8\";\n extension = \"md\";\n } else {\n const delimiter = format === \"csv\" ? \",\" : \"\\t\";\n const safe = options.spreadsheetSafe ?? format === \"tsv\";\n const encode = (value: string, path: string, isString = true) => {\n let text = value;\n if (safe && isString && /^[\\t\\r\\n ]*[=+\\-@]/.test(text)) {\n text = `'${text}`;\n omissions.push({ path, reason: \"escaped\", count: 1 });\n }\n return text.includes(delimiter) || /[\"\\n\\r]/.test(text)\n ? `\"${text.replace(/\"/g, '\"\"')}\"`\n : text;\n };\n plainText = [\n columns\n .map((c) => encode(c.label, `/columns/${enc(c.id)}`))\n .join(delimiter),\n ...payload.rows.map((row, index) =>\n columns\n .map((c) =>\n encode(\n columnCell(row, c),\n `/rows/${index}${c.path}`,\n typeof readTransferCell(row, c) === \"string\",\n ),\n )\n .join(delimiter),\n ),\n ].join(\"\\n\");\n if (format === \"csv\") {\n mime = \"text/csv;charset=utf-8\";\n extension = \"csv\";\n }\n if (format === \"tsv\") {\n mime = \"text/tab-separated-values;charset=utf-8\";\n extension = \"tsv\";\n }\n }\n if (format === \"html\")\n html = `<table><thead><tr>${columns.map((c) => `<th>${escapeHtml(c.label)}</th>`).join(\"\")}</tr></thead><tbody>${payload.rows.map((row) => `<tr>${columns.map((c) => `<td>${escapeHtml(columnCell(row, c)).replace(/\\r\\n|\\r|\\n/g, \"<br>\")}</td>`).join(\"\")}</tr>`).join(\"\")}</tbody></table>`;\n } else {\n plainText =\n payload.kind === \"text\" || payload.kind === \"markdown\"\n ? payload.text\n : stringifyJson(payload.value, { style: \"pretty\" });\n if (format === \"markdown\") {\n mime = \"text/markdown;charset=utf-8\";\n extension = \"md\";\n }\n if (format === \"html\") html = `<pre>${escapeHtml(plainText)}</pre>`;\n }\n if (format === \"html\") {\n mime = \"text/html;charset=utf-8\";\n extension = \"html\";\n }\n return sealTransferArtifact({\n snapshotId: draft.snapshotId,\n draftRevision: draft.revision,\n format,\n plainText,\n ...(html === undefined ? {} : { html }),\n file: {\n filename: options.filename ?? `export.${extension}`,\n mime,\n bytes: new TextEncoder().encode(\n format === \"html\" ? (html ?? plainText) : plainText,\n ),\n },\n omissions,\n });\n}\nexport function createBrowserTransport(): Transport {\n return {\n async copy(a, signal) {\n const cancelled = () =>\n signal.aborted ? { status: \"cancelled\" as const } : undefined;\n try {\n if (cancelled()) return cancelled()!;\n const c = globalThis.navigator?.clipboard;\n if (!c?.write && !c?.writeText)\n return {\n status: \"error\",\n code: \"clipboard-unavailable\",\n message: \"Clipboard writing is unavailable\",\n retryable: false,\n };\n if (\n a.html &&\n c.write &&\n typeof globalThis.ClipboardItem === \"function\"\n ) {\n try {\n await c.write([\n new ClipboardItem({\n \"text/plain\": new Blob([a.plainText], { type: \"text/plain\" }),\n \"text/html\": new Blob([a.html], { type: \"text/html\" }),\n }),\n ]);\n if (cancelled()) return cancelled()!;\n return {\n status: \"success\",\n delivered: \"clipboard\",\n mimeTypes: [\"text/plain\", \"text/html\"],\n };\n } catch {\n if (cancelled()) return cancelled()!;\n }\n }\n if (c.writeText) {\n await c.writeText(a.plainText);\n if (cancelled()) return cancelled()!;\n return a.html\n ? {\n status: \"degraded\",\n delivered: \"plain-text\",\n reason: \"Rich clipboard write was unavailable or rejected\",\n }\n : {\n status: \"success\",\n delivered: \"clipboard\",\n mimeTypes: [\"text/plain\"],\n };\n }\n return {\n status: \"error\",\n code: \"clipboard-rejected\",\n message: \"Clipboard rejected the write\",\n retryable: true,\n };\n } catch (e) {\n return (\n cancelled() ?? {\n status: \"error\",\n code: \"clipboard-rejected\",\n message:\n e instanceof Error ? e.message : \"Clipboard rejected the write\",\n retryable: true,\n }\n );\n }\n },\n async download(a, signal) {\n if (signal.aborted) return { status: \"cancelled\" };\n if (!a.file || typeof document === \"undefined\" || !URL?.createObjectURL)\n return {\n status: \"error\",\n code: \"download-unavailable\",\n message: \"Download is unavailable\",\n retryable: false,\n };\n let url: string | undefined;\n try {\n url = URL.createObjectURL(\n new Blob([a.file.bytes.slice().buffer as ArrayBuffer], {\n type: a.file.mime,\n }),\n );\n const link = document.createElement(\"a\");\n link.href = url;\n link.download = a.file.filename;\n link.click();\n return signal.aborted\n ? { status: \"cancelled\" }\n : {\n status: \"success\",\n delivered: \"download-started\",\n mimeTypes: [a.file.mime],\n };\n } catch (e) {\n return signal.aborted\n ? { status: \"cancelled\" }\n : {\n status: \"error\",\n code: \"download-failed\",\n message: e instanceof Error ? e.message : \"Download failed\",\n retryable: true,\n };\n } finally {\n if (url) setTimeout(() => URL.revokeObjectURL(url!), 0);\n }\n },\n };\n}\n\nfunction assertLimit(value: number | null | undefined, name: string): void {\n if (value != null && (!Number.isSafeInteger(value) || value < 0)) {\n throw new ContentTransferError(\n \"invalid-limit\",\n `${name} must be a non-negative safe integer or null`,\n );\n }\n}\nexport type TransferPreferenceOverrides = Partial<\n Omit<TransferPreferences, \"limits\">\n> & { limits?: Partial<TransferLimits> };\nconst limitKeys = [\n \"maxRows\",\n \"maxStringChars\",\n \"maxDepth\",\n \"maxArrayItems\",\n \"targetTokens\",\n] as const;\n/** Restrictions intersect: neither a menu nor a provider can relax a source limit. */\nexport function resolveTransferPreferences(\n provider: TransferPreferenceOverrides = {},\n menu: TransferPreferenceOverrides = {},\n sourceLimits: Partial<TransferLimits> = {},\n): TransferPreferences {\n const limits: TransferLimits = {\n maxRows: null,\n maxStringChars: null,\n maxDepth: null,\n maxArrayItems: null,\n targetTokens: null,\n };\n for (const key of limitKeys) {\n const candidates = [\n provider.limits?.[key],\n menu.limits?.[key],\n sourceLimits[key],\n ];\n candidates.forEach((value) => assertLimit(value, key));\n const finite = candidates.filter((value): value is number => value != null);\n limits[key] = finite.length ? Math.min(...finite) : null;\n }\n return deepFreeze({\n initialFormat: menu.initialFormat ?? provider.initialFormat ?? \"plain\",\n initialPreset: menu.initialPreset ?? provider.initialPreset ?? \"full\",\n initialEnvelope: menu.initialEnvelope ?? provider.initialEnvelope ?? \"ai\",\n limits,\n });\n}\n/**\n * True for the objects React uses to represent a component or an element —\n * `forwardRef`, `memo`, `lazy`, portals, elements. They are all tagged with the\n * `$$typeof` symbol, which is exactly the test React uses itself.\n */\nfunction isReactElementType(value: object): boolean {\n const tag = (value as { $$typeof?: unknown }).$$typeof;\n return typeof tag === \"symbol\";\n}\n\nfunction cloneTransferRegistration(\n value: unknown,\n path = \"registration\",\n seen = new WeakSet<object>(),\n): unknown {\n if (value === null || (typeof value !== \"object\" && typeof value !== \"function\"))\n return value;\n // Registered behavior remains callable by identity. Freezing a caller-owned\n // function would mutate it and its attached state.\n if (typeof value === \"function\") return value;\n // A React component or element is registered BEHAVIOUR too — it is rendered,\n // never inspected — and `React.forwardRef` / `React.memo` produce OBJECTS\n // rather than functions. React's development build defines their\n // `displayName` as an ACCESSOR, so walking into one threw \"cannot use\n // accessors\" at `registration/icon/displayName` and took EVERY dashboard page\n // that renders a transfer menu down behind its error boundary (2026-09-14;\n // every AI variant the admin dashboard registers carries a lucide `icon`).\n // Recognised the way React itself recognises them.\n if (isReactElementType(value)) return value;\n if (seen.has(value))\n throw new ContentTransferError(\n \"unsupported-registration-metadata\",\n \"Circular transfer registration metadata is unsupported\",\n path,\n );\n seen.add(value);\n if (Array.isArray(value)) {\n const copy = value.map((item, index) =>\n cloneTransferRegistration(item, `${path}/${index}`, seen),\n );\n seen.delete(value);\n return Object.freeze(copy);\n }\n const prototype = Object.getPrototypeOf(value);\n if (prototype !== Object.prototype && prototype !== null)\n throw new ContentTransferError(\n \"unsupported-registration-metadata\",\n \"Transfer registration metadata must use plain objects and arrays\",\n path,\n );\n const copy = Object.create(prototype) as Record<PropertyKey, unknown>;\n for (const key of Reflect.ownKeys(value)) {\n const descriptor = Object.getOwnPropertyDescriptor(value, key)!;\n if (!(\"value\" in descriptor))\n throw new ContentTransferError(\n \"unsupported-registration-metadata\",\n \"Transfer registration metadata cannot use accessors\",\n `${path}/${String(key)}`,\n );\n Object.defineProperty(copy, key, {\n value: cloneTransferRegistration(\n descriptor.value,\n `${path}/${String(key)}`,\n seen,\n ),\n enumerable: descriptor.enumerable === true,\n writable: false,\n configurable: false,\n });\n }\n seen.delete(value);\n return Object.freeze(copy);\n}\n\n/** One stable id per registered format or action; ambiguous overrides fail loudly. */\nexport function resolveTransferRegistry<T extends { id: string }>(\n ...groups: readonly (readonly T[])[]\n): readonly T[] {\n const ids = new Set<string>();\n const result: T[] = [];\n for (const group of groups)\n for (const item of group) {\n const copy = cloneTransferRegistration(item) as T;\n if (!copy.id.trim() || ids.has(copy.id))\n throw new ContentTransferError(\n \"duplicate-registration\",\n `Transfer id ${JSON.stringify(copy.id)} is empty or registered more than once`,\n );\n ids.add(copy.id);\n result.push(copy);\n }\n return Object.freeze(result);\n}\n\nexport type TransferSurfaceDeclaration = {\n surfaceName: string;\n label?: string;\n values: readonly {\n name: string;\n label: string;\n exportable?: boolean;\n classification?: \"ordinary\" | \"secret\" | \"credential\";\n includedByDefault?: boolean;\n }[];\n};\n/** A structural adapter to the actual mounted surface, never a global name lookup. */\nexport function createSurfaceTransferHandle(options: {\n instanceId: string;\n manifest: TransferSurfaceDeclaration;\n isMounted(): boolean;\n getScope(): Record<string, unknown> | Promise<Record<string, unknown>>;\n getRevision?(): string;\n unsavedChanges?(): boolean;\n projection?: ExportProjection;\n limits?: TransferLimits;\n}): SurfaceHandle {\n const declarations = resolveTransferRegistry(\n options.manifest.values.map((value) => ({ ...value, id: value.name })),\n );\n return {\n instanceId: options.instanceId,\n surfaceName: options.manifest.surfaceName,\n isMounted: options.isMounted,\n async capture(signal) {\n stop(signal);\n if (!options.isMounted())\n throw new ContentTransferError(\n \"surface-unmounted\",\n \"The captured surface is no longer mounted\",\n );\n const revisionBefore = options.getRevision?.();\n const scope = await options.getScope();\n stop(signal);\n if (!options.isMounted())\n throw new ContentTransferError(\n \"surface-unmounted\",\n \"The surface closed during capture\",\n );\n if (\n revisionBefore !== undefined &&\n options.getRevision?.() !== revisionBefore\n )\n throw new ContentTransferError(\n \"surface-changed\",\n \"The surface changed during capture; capture again\",\n );\n const value: Record<string, Json> = {};\n for (const declaration of declarations) {\n if (\n Object.hasOwn(scope, declaration.name) &&\n scope[declaration.name] !== undefined\n ) {\n Object.defineProperty(value, declaration.name, {\n value: cloneSurfaceValue(\n scope[declaration.name],\n `/${enc(declaration.name)}`,\n ),\n enumerable: true,\n writable: true,\n configurable: true,\n });\n }\n }\n return directSource(\n { kind: \"json\", value },\n {\n sourceId: options.instanceId,\n revision: revisionBefore ?? uid(),\n label: options.manifest.label ?? options.manifest.surfaceName,\n unsavedChanges: options.unsavedChanges?.() ?? false,\n sections: declarations\n .filter((d) => Object.hasOwn(value, d.name))\n .map((d) => ({\n id: d.name,\n label: d.label,\n path: `/${enc(d.name)}`,\n includedByDefault: d.includedByDefault ?? true,\n })),\n projection: {\n rules: [\n ...(options.projection?.rules ?? []),\n ...declarations.map((d) => ({\n target: \"payload\" as const,\n path: `/${enc(d.name)}`,\n exportable: d.exportable ?? true,\n classification: d.classification ?? (\"ordinary\" as const),\n })),\n ],\n },\n ...(options.limits ? { limits: options.limits } : {}),\n },\n );\n },\n };\n}\n\nfunction limitJson(\n value: Json,\n limits: Partial<TransferLimits>,\n omissions: Omission[],\n path = \"\",\n depth = 0,\n): Json {\n if (limits.maxDepth != null && depth > limits.maxDepth) {\n omissions.push({ path, reason: \"truncated\" });\n return null;\n }\n if (\n typeof value === \"string\" &&\n limits.maxStringChars != null &&\n Array.from(value).length > limits.maxStringChars\n ) {\n const chars = Array.from(value);\n omissions.push({\n path,\n reason: \"truncated\",\n count: chars.length - limits.maxStringChars,\n });\n return chars.slice(0, limits.maxStringChars).join(\"\");\n }\n if (Array.isArray(value)) {\n const count = Math.min(value.length, limits.maxArrayItems ?? value.length);\n if (count < value.length)\n omissions.push({\n path,\n reason: \"truncated\",\n count: value.length - count,\n });\n return value\n .slice(0, count)\n .map((item, index) =>\n limitJson(item, limits, omissions, `${path}/${index}`, depth + 1),\n );\n }\n if (value && typeof value === \"object\")\n return Object.fromEntries(\n Object.entries(value).map(([key, item]) => [\n key,\n limitJson(item, limits, omissions, `${path}/${enc(key)}`, depth + 1),\n ]),\n );\n return value;\n}\nfunction limitPayload(\n payload: Payload,\n limits: Partial<TransferLimits>,\n omissions: Omission[],\n): Payload {\n limitKeys.forEach((key) => assertLimit(limits[key], key));\n if (payload.kind === \"rows\") {\n const count = Math.min(\n payload.rows.length,\n limits.maxRows ?? payload.rows.length,\n );\n if (count < payload.rows.length)\n omissions.push({\n path: \"/rows\",\n reason: \"truncated\",\n count: payload.rows.length - count,\n });\n return {\n ...payload,\n rows: payload.rows\n .slice(0, count)\n .map(\n (row, index) =>\n limitJson(row, limits, omissions, `/rows/${index}`) as Record<\n string,\n Json\n >,\n ),\n };\n }\n if (payload.kind === \"json\" || payload.kind === \"registered\")\n return { ...payload, value: limitJson(payload.value, limits, omissions) };\n return {\n ...payload,\n text: limitJson(payload.text, limits, omissions) as string,\n };\n}\n/** Applies explicit preparation/source limits with exact omissions; token target is advisory. */\nexport function applyTransferLimits(\n draft: Draft,\n limits: Partial<TransferLimits>,\n): Draft {\n const omissions: Omission[] = [];\n const payload = limitPayload(draft.payload, limits, omissions);\n return omissions.length\n ? revise(draft, payload, omissions, \"Applied preparation limits\")\n : draft;\n}\n","/**\n * Wrap text in a Markdown code fence that cannot be closed by its contents.\n *\n * Fence writing is deliberately centralized here. Consumers should not grow\n * their own backtick-run detection when exporting code-shaped payloads.\n */\nexport function fencedCodeBlock(text: string, language: string): string {\n const runs = text.match(/`+/g) ?? [];\n const fence = \"`\".repeat(Math.max(3, ...runs.map((run) => run.length + 1)));\n return `${fence}${language}\\n${text}${text.endsWith(\"\\n\") ? \"\" : \"\\n\"}${fence}`;\n}\n","/**\n * `@ai-matrx/alchemy/operate/formats/rich-html` — the rich clipboard format (CONTRACT §1.9a).\n *\n * Engine: THE one Markdown→HTML engine (`@ai-matrx/print/markdown-html`, loaded lazily) with the\n * `inline` skin — styles on elements, no class dependence, because Google Docs and Word drop\n * `<style>` and classes on paste. Docs and Word are one action (\"Copy formatted\") until a\n * destination profile produces different bytes. Private images go through the host's asset\n * port. Every HTML string ends in print's allow-list.\n */\n\nimport type { MarkdownHtmlEngine } from \"@ai-matrx/print/markdown-html\";\nimport { ContentTransferError, sealTransferArtifact } from \"../core\";\nimport type { FormatEngine, FormatOptions } from \"../contract\";\nimport type { Artifact, Draft } from \"../types\";\n\nconst ENGINE = Symbol.for(\"ai-matrx.alchemy.operate.markdown-html-engine\");\n\n/** One engine per realm, created on first use (the print module itself loads only here). */\nexport async function loadMarkdownHtmlEngine(): Promise<MarkdownHtmlEngine> {\n const g = globalThis as unknown as Record<symbol, Promise<MarkdownHtmlEngine> | undefined>;\n g[ENGINE] ??= import(\"@ai-matrx/print/markdown-html\").then((m) => m.createMarkdownHtmlEngine());\n return g[ENGINE] as Promise<MarkdownHtmlEngine>;\n}\n\nfunction parseOptions(options: FormatOptions, signal: AbortSignal) {\n return {\n signal,\n ...(options.onNotice ? { onNotice: options.onNotice } : {}),\n ...(options.assets ? { assets: options.assets } : {}),\n };\n}\n\n/** Plain text from the one parse (the `plain` format for Markdown payloads). */\nexport async function markdownPlainText(markdown: string, options: FormatOptions, signal: AbortSignal): Promise<string> {\n const engine = await loadMarkdownHtmlEngine();\n return engine.plainText(await engine.parse(markdown, parseOptions(options, signal)));\n}\n\nexport const richHtmlEngine: FormatEngine = {\n async build(draft: Draft, options: FormatOptions, signal: AbortSignal): Promise<Artifact> {\n if (signal.aborted) throw new DOMException(\"Cancelled\", \"AbortError\");\n if (draft.payload.kind !== \"markdown\") {\n throw new ContentTransferError(\"unsupported-format\", \"Formatted copy needs Markdown content. Copy it as plain text instead.\");\n }\n const engine = await loadMarkdownHtmlEngine();\n const tree = await engine.parse(draft.payload.text, parseOptions(options, signal));\n if (signal.aborted) throw new DOMException(\"Cancelled\", \"AbortError\");\n const html = engine.fragment(tree, { skin: options.skin ?? \"inline\", profile: options.profile ?? \"generic\" });\n return sealTransferArtifact({\n snapshotId: draft.snapshotId,\n draftRevision: draft.revision,\n format: \"rich-html\",\n plainText: engine.plainText(tree),\n html,\n file: { filename: options.filename ?? \"export.html\", mime: \"text/html;charset=utf-8\", bytes: new TextEncoder().encode(html) },\n omissions: draft.omissions.map((o) => ({ ...o })),\n });\n },\n};\n","/**\n * `@ai-matrx/alchemy/operate/formats/document` — HTML page, PDF, DOCX and EPUB (CONTRACT §1.9).\n *\n * One tree: the HTML page is THE one Markdown→HTML engine's `document()` (print's\n * `documentToHtml`, body allow-listed); PDF (vector, selectable text), DOCX and EPUB are print's\n * `/document` writers over the same parse. Print loads only when one of these is chosen.\n * A text payload with a language exports as its fenced code block.\n */\n\nimport { ContentTransferError, sealTransferArtifact } from \"../core\";\nimport type { FormatEngine, FormatOptions } from \"../contract\";\nimport { fencedCodeBlock } from \"../fenced-code\";\nimport type { Artifact, Draft } from \"../types\";\nimport { loadMarkdownHtmlEngine } from \"./rich-html\";\n\nconst enc = new TextEncoder();\n\nfunction markdownOf(draft: Draft): string {\n const p = draft.payload;\n if (p.kind === \"markdown\") return p.text;\n if (p.kind === \"text\") {\n if (!p.language) return p.text;\n return fencedCodeBlock(p.text, p.language);\n }\n throw new ContentTransferError(\"unsupported-format\", \"A document needs text or Markdown content. Download it as JSON or CSV instead.\");\n}\n\nconst stem = (filename: string | undefined) => (filename ? filename.replace(/\\.[a-z0-9]+$/i, \"\") : undefined);\n\n/** The standalone HTML page (the `html` format for prose). */\nexport const documentHtmlEngine: FormatEngine = {\n async build(draft: Draft, options: FormatOptions, signal: AbortSignal): Promise<Artifact> {\n if (signal.aborted) throw new DOMException(\"Cancelled\", \"AbortError\");\n const engine = await loadMarkdownHtmlEngine();\n const tree = await engine.parse(markdownOf(draft), {\n signal,\n ...(options.onNotice ? { onNotice: options.onNotice } : {}),\n ...(options.assets ? { assets: options.assets } : {}),\n });\n const page = engine.document(tree);\n return sealTransferArtifact({\n snapshotId: draft.snapshotId,\n draftRevision: draft.revision,\n format: \"html\",\n plainText: engine.plainText(tree),\n html: page,\n file: { filename: options.filename ?? \"export.html\", mime: \"text/html;charset=utf-8\", bytes: enc.encode(page) },\n omissions: draft.omissions.map((o) => ({ ...o })),\n });\n },\n};\n\n/** PDF / DOCX / EPUB through print's `/document` (lazy). */\nexport function documentEngine(format: \"pdf\" | \"docx\" | \"epub\"): FormatEngine {\n return {\n async build(draft: Draft, options: FormatOptions, signal: AbortSignal): Promise<Artifact> {\n if (signal.aborted) throw new DOMException(\"Cancelled\", \"AbortError\");\n const source = markdownOf(draft);\n const { exportDocument } = await import(\"@ai-matrx/print/document\");\n const name = stem(options.filename);\n const out = await exportDocument(source, format, {\n ...(name ? { fileName: name } : {}),\n ...(options.onNotice ? { onNotice: (n) => options.onNotice?.({ code: n.code, sentence: n.message, remedy: n.remedy }) } : {}),\n });\n if (signal.aborted) throw new DOMException(\"Cancelled\", \"AbortError\");\n return sealTransferArtifact({\n snapshotId: draft.snapshotId,\n draftRevision: draft.revision,\n format,\n plainText: source,\n file: { filename: out.fileName, mime: out.mime, bytes: out.bytes },\n omissions: draft.omissions.map((o) => ({ ...o })),\n });\n },\n };\n}\n"],"mappings":"y5BAAA,uMCAA,uBAA8B,qCAC9B,mBAA2B,qCAC3B,qBAKO,uCACPA,sBAIO,uCCNA,SAAS,gBAAgB,KAAc,SAA0B,CACtE,IAAM,KAAO,KAAK,MAAM,KAAK,GAAK,CAAC,EAC7B,MAAQ,IAAI,OAAO,KAAK,IAAI,EAAG,GAAG,KAAK,IAAK,KAAQ,IAAI,OAAS,CAAC,CAAC,CAAC,EAC1E,MAAO,GAAG,KAAK,GAAG,QAAQ;AAAA,EAAK,IAAI,GAAG,KAAK,SAAS;AAAA,CAAI,EAAI,GAAK;AAAA,CAAI,GAAG,KAAK,EAC/E,CD6EA,SAAS,WAAc,EAAS,CAC9B,GAAI,YAAY,OAAO,CAAC,EAAG,OAAO,EAClC,GAAI,GAAK,OAAO,GAAM,UAAY,CAAC,OAAO,SAAS,CAAC,EAAG,CACrD,OAAO,OAAO,CAAC,EACf,QAAW,KAAK,OAAO,OAAO,CAAW,EAAG,WAAW,CAAC,CAC1D,CACA,OAAO,CACT,CA+yBO,SAAS,qBAAqB,SAA8B,CACjE,GAAI,CAAC,SAAS,KACZ,OAAO,WAAW,CAChB,GAAG,SACH,UAAW,SAAS,UAAU,IAAK,IAAO,CAAE,GAAG,CAAE,EAAE,CACrD,CAAC,EACH,IAAM,MAAQ,SAAS,KAAK,MAAM,MAAM,EAClC,KAAO,CACX,SAAU,SAAS,KAAK,SACxB,KAAM,SAAS,KAAK,KACpB,IAAI,OAAQ,CACV,OAAO,MAAM,MAAM,CACrB,CACF,EACA,OAAO,WAAW,CAChB,GAAG,SACH,KACA,UAAW,SAAS,UAAU,IAAK,IAAO,CAAE,GAAG,CAAE,EAAE,CACrD,CAAC,CACH,CEj5BA,IAAM,OAAS,OAAO,IAAI,+CAA+C,EAGzE,eAAsB,wBAAsD,CAC1E,IAAM,EAAI,WACV,SAAE,MAAM,IAAM,OAAO,+BAA+B,EAAE,KAAM,GAAM,EAAE,yBAAyB,CAAC,EACvF,EAAE,MAAM,CACjB,CCPA,IAAM,IAAM,IAAI,YAEhB,SAAS,WAAW,MAAsB,CACxC,IAAM,EAAI,MAAM,QAChB,GAAI,EAAE,OAAS,WAAY,OAAO,EAAE,KACpC,GAAI,EAAE,OAAS,OACb,OAAK,EAAE,SACA,gBAAgB,EAAE,KAAM,EAAE,QAAQ,EADjB,EAAE,KAG5B,MAAM,IAAI,2CAAqB,qBAAsB,gFAAgF,CACvI,CAEA,IAAM,KAAQ,UAAkC,SAAW,SAAS,QAAQ,gBAAiB,EAAE,EAAI,OAGtF,mBAAmC,CAC9C,MAAM,MAAM,MAAc,QAAwB,OAAwC,CACxF,GAAI,OAAO,QAAS,MAAM,IAAI,aAAa,YAAa,YAAY,EACpE,IAAM,OAAS,MAAM,uBAAuB,EACtC,KAAO,MAAM,OAAO,MAAM,WAAW,KAAK,EAAG,CACjD,OACA,GAAI,QAAQ,SAAW,CAAE,SAAU,QAAQ,QAAS,EAAI,CAAC,EACzD,GAAI,QAAQ,OAAS,CAAE,OAAQ,QAAQ,MAAO,EAAI,CAAC,CACrD,CAAC,EACK,KAAO,OAAO,SAAS,IAAI,EACjC,OAAO,qBAAqB,CAC1B,WAAY,MAAM,WAClB,cAAe,MAAM,SACrB,OAAQ,OACR,UAAW,OAAO,UAAU,IAAI,EAChC,KAAM,KACN,KAAM,CAAE,SAAU,QAAQ,UAAY,cAAe,KAAM,0BAA2B,MAAO,IAAI,OAAO,IAAI,CAAE,EAC9G,UAAW,MAAM,UAAU,IAAK,IAAO,CAAE,GAAG,CAAE,EAAE,CAClD,CAAC,CACH,CACF,EAGO,SAAS,eAAe,OAA+C,CAC5E,MAAO,CACL,MAAM,MAAM,MAAc,QAAwB,OAAwC,CACxF,GAAI,OAAO,QAAS,MAAM,IAAI,aAAa,YAAa,YAAY,EACpE,IAAM,OAAS,WAAW,KAAK,EACzB,CAAE,cAAe,EAAI,KAAM,QAAO,0BAA0B,EAC5D,KAAO,KAAK,QAAQ,QAAQ,EAC5B,IAAM,MAAM,eAAe,OAAQ,OAAQ,CAC/C,GAAI,KAAO,CAAE,SAAU,IAAK,EAAI,CAAC,EACjC,GAAI,QAAQ,SAAW,CAAE,SAAW,GAAM,QAAQ,WAAW,CAAE,KAAM,EAAE,KAAM,SAAU,EAAE,QAAS,OAAQ,EAAE,MAAO,CAAC,CAAE,EAAI,CAAC,CAC7H,CAAC,EACD,GAAI,OAAO,QAAS,MAAM,IAAI,aAAa,YAAa,YAAY,EACpE,OAAO,qBAAqB,CAC1B,WAAY,MAAM,WAClB,cAAe,MAAM,SACrB,OACA,UAAW,OACX,KAAM,CAAE,SAAU,IAAI,SAAU,KAAM,IAAI,KAAM,MAAO,IAAI,KAAM,EACjE,UAAW,MAAM,UAAU,IAAK,IAAO,CAAE,GAAG,CAAE,EAAE,CAClD,CAAC,CACH,CACF,CACF","names":["import_transfer_json"]}