@codemation/core-nodes-ocr 0.2.3 → 0.2.5
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.
- package/CHANGELOG.md +14 -0
- package/dist/{analyzeInvoiceNode-uVwe3GHD.js → analyzeInvoiceNode-BqZsN8iL.js} +4 -36
- package/dist/analyzeInvoiceNode-BqZsN8iL.js.map +1 -0
- package/dist/{analyzeInvoiceNode-BIw8j_Zb.cjs → analyzeInvoiceNode-CmMsifbw.cjs} +4 -36
- package/dist/analyzeInvoiceNode-CmMsifbw.cjs.map +1 -0
- package/dist/codemation.plugin.cjs +140 -49
- package/dist/codemation.plugin.cjs.map +1 -1
- package/dist/codemation.plugin.d.cts +10 -3
- package/dist/codemation.plugin.d.ts +10 -3
- package/dist/codemation.plugin.js +140 -49
- package/dist/codemation.plugin.js.map +1 -1
- package/dist/{index-rc7dB1Ws.d.ts → index-DF2ht42F.d.ts} +20 -4
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/metadata.json +1 -1
- package/dist/{runtimeTypes-MQgcsey7.d.cts → runtimeTypes-WCvsnJMY.d.cts} +17 -1
- package/package.json +2 -2
- package/src/nodes/analyzeDocumentNode.ts +1 -2
- package/src/nodes/analyzeImageNode.ts +1 -2
- package/src/nodes/analyzeInvoiceNode.ts +1 -2
- package/dist/analyzeInvoiceNode-BIw8j_Zb.cjs.map +0 -1
- package/dist/analyzeInvoiceNode-uVwe3GHD.js.map +0 -1
- package/src/lib/readBinaryBody.ts +0 -51
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# @codemation/core-nodes-ocr
|
|
2
2
|
|
|
3
|
+
## 0.2.5
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Updated dependencies [[`2fcb715`](https://github.com/MadeRelevant/codemation/commit/2fcb7153d9c732b2f846b8a8d1cc5626b4363fa6)]:
|
|
8
|
+
- @codemation/core@0.13.1
|
|
9
|
+
|
|
10
|
+
## 0.2.4
|
|
11
|
+
|
|
12
|
+
### Patch Changes
|
|
13
|
+
|
|
14
|
+
- Updated dependencies [[`c1b081f`](https://github.com/MadeRelevant/codemation/commit/c1b081ffc8b66b0c4593c94f1d57a1cdf5c41140), [`be520d2`](https://github.com/MadeRelevant/codemation/commit/be520d2755144a3709ecc109019b84e2c502337e)]:
|
|
15
|
+
- @codemation/core@0.13.0
|
|
16
|
+
|
|
3
17
|
## 0.2.3
|
|
4
18
|
|
|
5
19
|
### Patch Changes
|
|
@@ -124,38 +124,6 @@ function resolveFieldKind(field) {
|
|
|
124
124
|
return field.type;
|
|
125
125
|
}
|
|
126
126
|
|
|
127
|
-
//#endregion
|
|
128
|
-
//#region src/lib/readBinaryBody.ts
|
|
129
|
-
/** Default cap on bytes read into memory. Tuned for prebuilt OCR analyzers (single document). */
|
|
130
|
-
const DEFAULT_MAX_BYTES = 50 * 1024 * 1024;
|
|
131
|
-
/**
|
|
132
|
-
* Reads the binary body for an OCR analyzer call.
|
|
133
|
-
*
|
|
134
|
-
* The Azure Content Understanding SDK requires a contiguous `Uint8Array`, so the bytes must
|
|
135
|
-
* land in memory at some point. To bound that:
|
|
136
|
-
* - The attachment's declared `size` is checked against `maxBytes` *before* any allocation.
|
|
137
|
-
* - A single buffer of exactly `attachment.size` is pre-allocated (no chunks array, no doubling).
|
|
138
|
-
* - The stream fills the buffer directly; a length mismatch fails fast.
|
|
139
|
-
*/
|
|
140
|
-
async function readBinaryBody(ctx, attachment, maxBytes = DEFAULT_MAX_BYTES) {
|
|
141
|
-
if (attachment.size > maxBytes) throw new Error(`Binary attachment size ${attachment.size} bytes exceeds maxBytes ${maxBytes}. Raise the node's maxBytes setting if this document is expected to be larger.`);
|
|
142
|
-
const stream = await ctx.binary.openReadStream(attachment);
|
|
143
|
-
if (!stream) throw new Error("Binary attachment stream is unavailable.");
|
|
144
|
-
const out = new Uint8Array(attachment.size);
|
|
145
|
-
const reader = stream.body.getReader();
|
|
146
|
-
let offset = 0;
|
|
147
|
-
while (true) {
|
|
148
|
-
const { done, value } = await reader.read();
|
|
149
|
-
if (done) break;
|
|
150
|
-
if (!value) continue;
|
|
151
|
-
if (offset + value.byteLength > out.byteLength) throw new Error(`Binary stream produced more bytes than the attachment's declared size (${attachment.size}).`);
|
|
152
|
-
out.set(value, offset);
|
|
153
|
-
offset += value.byteLength;
|
|
154
|
-
}
|
|
155
|
-
if (offset !== out.byteLength) throw new Error(`Binary stream produced ${offset} bytes but attachment declared size ${attachment.size}.`);
|
|
156
|
-
return out;
|
|
157
|
-
}
|
|
158
|
-
|
|
159
127
|
//#endregion
|
|
160
128
|
//#region src/nodes/analyzeDocumentNode.ts
|
|
161
129
|
/** Default Azure Content Understanding prebuilt general document analyzer ID. */
|
|
@@ -204,7 +172,7 @@ const analyzeDocumentNode = defineNode({
|
|
|
204
172
|
return analyzeWithAzure({
|
|
205
173
|
session,
|
|
206
174
|
analyzerId,
|
|
207
|
-
body: await
|
|
175
|
+
body: await ctx.binary.getBytes(attachment, config.maxBytes),
|
|
208
176
|
contentType
|
|
209
177
|
});
|
|
210
178
|
}
|
|
@@ -258,7 +226,7 @@ const analyzeImageNode = defineNode({
|
|
|
258
226
|
return analyzeWithAzure({
|
|
259
227
|
session,
|
|
260
228
|
analyzerId,
|
|
261
|
-
body: await
|
|
229
|
+
body: await ctx.binary.getBytes(attachment, config.maxBytes),
|
|
262
230
|
contentType
|
|
263
231
|
});
|
|
264
232
|
}
|
|
@@ -310,7 +278,7 @@ const analyzeInvoiceNode = defineNode({
|
|
|
310
278
|
return analyzeWithAzure({
|
|
311
279
|
session,
|
|
312
280
|
analyzerId: PREBUILT_INVOICE_ANALYZER_ID,
|
|
313
|
-
body: await
|
|
281
|
+
body: await ctx.binary.getBytes(attachment, config.maxBytes),
|
|
314
282
|
contentType
|
|
315
283
|
});
|
|
316
284
|
}
|
|
@@ -318,4 +286,4 @@ const analyzeInvoiceNode = defineNode({
|
|
|
318
286
|
|
|
319
287
|
//#endregion
|
|
320
288
|
export { mapAnalysisResult as a, analyzeWithAzure as i, analyzeImageNode as n, azureContentUnderstandingCredentialType as o, analyzeDocumentNode as r, analyzeInvoiceNode as t };
|
|
321
|
-
//# sourceMappingURL=analyzeInvoiceNode-
|
|
289
|
+
//# sourceMappingURL=analyzeInvoiceNode-BqZsN8iL.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"analyzeInvoiceNode-BqZsN8iL.js","names":["markdownParts: string[]","out: Record<string, unknown>"],"sources":["../src/credentials/azureContentUnderstandingCredential.ts","../src/lib/analyzeWithAzure.ts","../src/nodes/analyzeDocumentNode.ts","../src/nodes/analyzeImageNode.ts","../src/nodes/analyzeInvoiceNode.ts"],"sourcesContent":["import { ContentUnderstandingClient } from \"@azure/ai-content-understanding\";\nimport { AzureKeyCredential } from \"@azure/core-auth\";\nimport { defineCredential } from \"@codemation/core\";\n\nexport type AzureContentUnderstandingSession = Readonly<{\n endpoint: string;\n apiKey: string;\n}>;\n\nfunction normalizeEndpoint(raw: string): string {\n return raw.trim().replace(/\\/+$/, \"\");\n}\n\nfunction buildSession(args: {\n readonly publicConfig: Readonly<Record<string, unknown>>;\n readonly material: Readonly<Record<string, unknown>>;\n}): AzureContentUnderstandingSession {\n const endpoint = normalizeEndpoint(String(args.publicConfig[\"endpoint\"] ?? \"\"));\n const apiKey = String(args.material[\"apiKey\"] ?? \"\").trim();\n if (!endpoint) {\n throw new Error(\"Azure Content Understanding credential is incomplete: endpoint is required.\");\n }\n if (!apiKey) {\n throw new Error(\"Azure Content Understanding credential is incomplete: API key is required.\");\n }\n return { endpoint, apiKey };\n}\n\nexport const azureContentUnderstandingCredentialType = defineCredential({\n key: \"azure.contentUnderstanding\",\n label: \"Azure Content Understanding\",\n description: \"Azure AI Content Understanding (endpoint + key) for prebuilt document, invoice, and image analyzers.\",\n public: {\n endpoint: {\n key: \"endpoint\",\n label: \"Endpoint\",\n type: \"string\" as const,\n required: true,\n placeholder: \"https://your-resource.cognitiveservices.azure.com/\",\n helpText: \"Content Understanding resource endpoint URL (no trailing slash).\",\n order: 0,\n },\n },\n secret: {\n apiKey: {\n key: \"apiKey\",\n label: \"API key\",\n type: \"password\" as const,\n required: true,\n order: 1,\n },\n },\n async createSession(args) {\n return buildSession(args);\n },\n async test(args) {\n try {\n const session = buildSession(args);\n const client = new ContentUnderstandingClient(session.endpoint, new AzureKeyCredential(session.apiKey));\n const iter = client.listAnalyzers();\n await iter.next();\n return {\n status: \"healthy\",\n message: \"Listed analyzers successfully.\",\n testedAt: new Date().toISOString(),\n };\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n return {\n status: \"failing\",\n message: message || \"Azure Content Understanding connection failed.\",\n testedAt: new Date().toISOString(),\n };\n }\n },\n});\n","import type {\n AnalysisResult,\n ArrayField,\n BooleanField,\n ContentField,\n ContentFieldUnion,\n DateField,\n IntegerField,\n JsonField,\n NumberField,\n ObjectField,\n StringField,\n TimeField,\n} from \"@azure/ai-content-understanding\";\nimport { ContentUnderstandingClient } from \"@azure/ai-content-understanding\";\nimport { AzureKeyCredential } from \"@azure/core-auth\";\nimport type { AzureContentUnderstandingSession } from \"../credentials/azureContentUnderstandingCredential\";\n\n/** Structured analyzer fields: scalars at leaves; nested objects and arrays preserved. */\nexport type OcrStructuredFields = Readonly<Record<string, unknown>>;\n\n/** The output shape returned by all OCR analyzer nodes. */\nexport type OcrAnalysisOutput = Readonly<{\n /** Markdown representation of the document content. */\n content: string;\n /** Structured fields extracted by the prebuilt analyzer. */\n fields: OcrStructuredFields;\n}>;\n\n/**\n * Analyzes a binary document using an Azure Content Understanding prebuilt analyzer.\n * Retries on transient failures are handled by the engine via the node's `retryPolicy`.\n */\nexport async function analyzeWithAzure(\n args: Readonly<{\n session: AzureContentUnderstandingSession;\n analyzerId: string;\n body: Uint8Array;\n contentType: string;\n }>,\n): Promise<OcrAnalysisOutput> {\n const client = new ContentUnderstandingClient(args.session.endpoint, new AzureKeyCredential(args.session.apiKey));\n const poller = client.analyzeBinary(args.analyzerId, args.body, args.contentType);\n const result = await poller.pollUntilDone();\n return mapAnalysisResult(result);\n}\n\n/** @internal Exported for testing — maps a raw AnalysisResult to the node output shape. */\nexport function mapAnalysisResult(result: AnalysisResult): OcrAnalysisOutput {\n const contents = result.contents ?? [];\n const markdownParts: string[] = [];\n for (const c of contents) {\n if (typeof c.markdown === \"string\" && c.markdown.length > 0) {\n markdownParts.push(c.markdown);\n }\n }\n const content = markdownParts.join(\"\\n\\n\");\n if (contents.length === 0) {\n return { content: \"\", fields: {} };\n }\n if (contents.length === 1) {\n const c = contents[0]!;\n return {\n content,\n fields: c.fields ? fieldsToStructuredMap(c.fields) : {},\n };\n }\n return {\n content,\n fields: {\n segments: contents.map((c, index) => ({\n index,\n markdown: typeof c.markdown === \"string\" && c.markdown.trim().length > 0 ? c.markdown : undefined,\n fields: c.fields ? fieldsToStructuredMap(c.fields) : {},\n })),\n },\n };\n}\n\nfunction fieldsToStructuredMap(fields: Readonly<Record<string, ContentFieldUnion>>): OcrStructuredFields {\n const out: Record<string, unknown> = {};\n for (const [name, field] of Object.entries(fields)) {\n out[name] = fieldToStructuredValue(field);\n }\n return out;\n}\n\nfunction fieldToStructuredValue(field: ContentFieldUnion): unknown {\n const kind = resolveFieldKind(field);\n switch (kind) {\n case \"string\":\n return (field as StringField).value ?? null;\n case \"date\": {\n const d = (field as DateField).value;\n return d ? d.toISOString() : null;\n }\n case \"time\":\n return (field as TimeField).value ?? null;\n case \"number\":\n return (field as NumberField).value ?? null;\n case \"integer\":\n return (field as IntegerField).value ?? null;\n case \"boolean\":\n return (field as BooleanField).value ?? null;\n case \"array\": {\n const values = (field as ArrayField).value ?? [];\n return values.map((element) => fieldToStructuredValue(element));\n }\n case \"object\": {\n const properties = (field as ObjectField).value ?? {};\n return fieldsToStructuredMap(properties);\n }\n case \"json\":\n return (field as JsonField).value ?? null;\n default: {\n const base = field as ContentField;\n if (base.value === undefined || base.value === null) {\n return null;\n }\n return typeof base.value === \"object\" ? base.value : String(base.value);\n }\n }\n}\n\nfunction resolveFieldKind(field: ContentFieldUnion): string {\n if (\"fieldType\" in field && typeof field.fieldType === \"string\") {\n return field.fieldType;\n }\n return (field as ContentField).type;\n}\n","import { defineNode } from \"@codemation/core\";\nimport type { AzureContentUnderstandingSession } from \"../credentials/azureContentUnderstandingCredential\";\nimport { azureContentUnderstandingCredentialType } from \"../credentials/azureContentUnderstandingCredential\";\nimport { analyzeWithAzure } from \"../lib/analyzeWithAzure\";\n\n/** Default Azure Content Understanding prebuilt general document analyzer ID. */\nconst DEFAULT_DOCUMENT_ANALYZER_ID = \"prebuilt-document\";\n\nexport type AnalyzeDocumentConfig = Readonly<{\n /** Key on `item.binary` that holds the document bytes. Default: `\"data\"`. */\n binaryField?: string;\n /** MIME type override sent to the analyzer. Falls back to attachment `mimeType` when not set. */\n contentType?: string;\n /**\n * Azure Content Understanding analyzer ID to use.\n * Defaults to `\"prebuilt-document\"`. Set this to a custom analyzer ID when you have\n * a trained model or need a different prebuilt variant.\n */\n analyzerId?: string;\n /** Max bytes the attachment may have before reading. Defaults to 50 MiB. */\n maxBytes?: number;\n}>;\n\nexport const analyzeDocumentNode = defineNode({\n key: \"azure-ocr.analyze-document\",\n title: \"Analyze Document\",\n description:\n \"Runs an Azure Content Understanding document analyzer on a binary attachment and returns markdown text plus structured fields. Defaults to the prebuilt general document analyzer.\",\n icon: \"lucide:scan-text\",\n input: {\n binaryField: \"data\",\n contentType: undefined as string | undefined,\n analyzerId: undefined as string | undefined,\n maxBytes: undefined as number | undefined,\n },\n credentials: {\n contentUnderstanding: {\n type: azureContentUnderstandingCredentialType as import(\"@codemation/core\").AnyCredentialType,\n label: \"Azure Content Understanding\",\n helpText: \"Bind an Azure Content Understanding credential (endpoint + key).\",\n },\n },\n inspectorSummary({ config }) {\n const cfg = config as unknown as AnalyzeDocumentConfig;\n const analyzerId = cfg.analyzerId ?? DEFAULT_DOCUMENT_ANALYZER_ID;\n const rows = [{ label: \"Analyzer\", value: analyzerId }];\n const binaryField = cfg.binaryField ?? \"data\";\n if (binaryField !== \"data\") {\n rows.push({ label: \"Binary field\", value: binaryField });\n }\n if (cfg.contentType) {\n rows.push({ label: \"Content type\", value: cfg.contentType });\n }\n return rows;\n },\n async execute({ item, ctx }, { config: rawConfig, credentials }) {\n const config = rawConfig as unknown as AnalyzeDocumentConfig;\n const session = (await credentials.contentUnderstanding()) as AzureContentUnderstandingSession;\n const binaryField = config.binaryField ?? \"data\";\n const attachment = item.binary?.[binaryField];\n if (!attachment) {\n throw new Error(`Analyze Document: no binary attachment at key \"${binaryField}\".`);\n }\n const analyzerId = config.analyzerId ?? DEFAULT_DOCUMENT_ANALYZER_ID;\n const contentType = config.contentType ?? attachment.mimeType ?? \"application/octet-stream\";\n const body = await ctx.binary.getBytes(attachment, config.maxBytes);\n return analyzeWithAzure({ session, analyzerId, body, contentType });\n },\n});\n","import { defineNode } from \"@codemation/core\";\nimport type { AzureContentUnderstandingSession } from \"../credentials/azureContentUnderstandingCredential\";\nimport { azureContentUnderstandingCredentialType } from \"../credentials/azureContentUnderstandingCredential\";\nimport { analyzeWithAzure } from \"../lib/analyzeWithAzure\";\n\n/** Default Azure Content Understanding prebuilt image analyzer ID. */\nconst DEFAULT_IMAGE_ANALYZER_ID = \"prebuilt-imageAnalyzer\";\n\nexport type AnalyzeImageConfig = Readonly<{\n /** Key on `item.binary` that holds the image bytes. Default: `\"data\"`. */\n binaryField?: string;\n /** MIME type override sent to the analyzer. Falls back to attachment `mimeType` when not set. */\n contentType?: string;\n /**\n * Azure Content Understanding analyzer ID to use.\n * Defaults to `\"prebuilt-imageAnalyzer\"`. Set this to a custom analyzer ID when you have\n * a trained model or need a different prebuilt variant.\n */\n analyzerId?: string;\n /** Max bytes the attachment may have before reading. Defaults to 50 MiB. */\n maxBytes?: number;\n}>;\n\nexport const analyzeImageNode = defineNode({\n key: \"azure-ocr.analyze-image\",\n title: \"Analyze Image\",\n description:\n \"Runs an Azure Content Understanding image analyzer on a binary attachment and returns markdown text plus structured fields. Defaults to the prebuilt image analyzer.\",\n icon: \"lucide:image-search\",\n input: {\n binaryField: \"data\",\n contentType: undefined as string | undefined,\n analyzerId: undefined as string | undefined,\n maxBytes: undefined as number | undefined,\n },\n credentials: {\n contentUnderstanding: {\n type: azureContentUnderstandingCredentialType as import(\"@codemation/core\").AnyCredentialType,\n label: \"Azure Content Understanding\",\n helpText: \"Bind an Azure Content Understanding credential (endpoint + key).\",\n },\n },\n inspectorSummary({ config }) {\n const cfg = config as unknown as AnalyzeImageConfig;\n const analyzerId = cfg.analyzerId ?? DEFAULT_IMAGE_ANALYZER_ID;\n const rows = [{ label: \"Analyzer\", value: analyzerId }];\n const binaryField = cfg.binaryField ?? \"data\";\n if (binaryField !== \"data\") {\n rows.push({ label: \"Binary field\", value: binaryField });\n }\n if (cfg.contentType) {\n rows.push({ label: \"Content type\", value: cfg.contentType });\n }\n return rows;\n },\n async execute({ item, ctx }, { config: rawConfig, credentials }) {\n const config = rawConfig as unknown as AnalyzeImageConfig;\n const session = (await credentials.contentUnderstanding()) as AzureContentUnderstandingSession;\n const binaryField = config.binaryField ?? \"data\";\n const attachment = item.binary?.[binaryField];\n if (!attachment) {\n throw new Error(`Analyze Image: no binary attachment at key \"${binaryField}\".`);\n }\n const analyzerId = config.analyzerId ?? DEFAULT_IMAGE_ANALYZER_ID;\n const contentType = config.contentType ?? attachment.mimeType ?? \"application/octet-stream\";\n const body = await ctx.binary.getBytes(attachment, config.maxBytes);\n return analyzeWithAzure({ session, analyzerId, body, contentType });\n },\n});\n","import { defineNode } from \"@codemation/core\";\nimport type { AzureContentUnderstandingSession } from \"../credentials/azureContentUnderstandingCredential\";\nimport { azureContentUnderstandingCredentialType } from \"../credentials/azureContentUnderstandingCredential\";\nimport { analyzeWithAzure } from \"../lib/analyzeWithAzure\";\n\n/** Azure Content Understanding prebuilt invoice analyzer ID. */\nconst PREBUILT_INVOICE_ANALYZER_ID = \"prebuilt-invoice\";\n\nexport type AnalyzeInvoiceConfig = Readonly<{\n /** Key on `item.binary` that holds the document bytes. Default: `\"data\"`. */\n binaryField?: string;\n /** MIME type override sent to the analyzer. Falls back to attachment `mimeType` when not set. */\n contentType?: string;\n /** Max bytes the attachment may have before reading. Defaults to 50 MiB. */\n maxBytes?: number;\n}>;\n\nexport const analyzeInvoiceNode = defineNode({\n key: \"azure-ocr.analyze-invoice\",\n title: \"Analyze Invoice\",\n description:\n \"Runs the Azure Content Understanding prebuilt invoice analyzer on a binary attachment and returns markdown text plus structured fields.\",\n icon: \"lucide:receipt\",\n input: {\n binaryField: \"data\",\n contentType: undefined as string | undefined,\n maxBytes: undefined as number | undefined,\n },\n credentials: {\n contentUnderstanding: {\n type: azureContentUnderstandingCredentialType as import(\"@codemation/core\").AnyCredentialType,\n label: \"Azure Content Understanding\",\n helpText: \"Bind an Azure Content Understanding credential (endpoint + key).\",\n },\n },\n inspectorSummary({ config }) {\n const cfg = config as unknown as AnalyzeInvoiceConfig;\n const rows = [{ label: \"Analyzer\", value: \"Invoice (prebuilt)\" }];\n const binaryField = cfg.binaryField ?? \"data\";\n if (binaryField !== \"data\") {\n rows.push({ label: \"Binary field\", value: binaryField });\n }\n if (cfg.contentType) {\n rows.push({ label: \"Content type\", value: cfg.contentType });\n }\n return rows;\n },\n async execute({ item, ctx }, { config: rawConfig, credentials }) {\n const config = rawConfig as unknown as AnalyzeInvoiceConfig;\n const session = (await credentials.contentUnderstanding()) as AzureContentUnderstandingSession;\n const binaryField = config.binaryField ?? \"data\";\n const attachment = item.binary?.[binaryField];\n if (!attachment) {\n throw new Error(`Analyze Invoice: no binary attachment at key \"${binaryField}\".`);\n }\n const contentType = config.contentType ?? attachment.mimeType ?? \"application/octet-stream\";\n const body = await ctx.binary.getBytes(attachment, config.maxBytes);\n return analyzeWithAzure({ session, analyzerId: PREBUILT_INVOICE_ANALYZER_ID, body, contentType });\n },\n});\n"],"mappings":";;;;;AASA,SAAS,kBAAkB,KAAqB;AAC9C,QAAO,IAAI,MAAM,CAAC,QAAQ,QAAQ,GAAG;;AAGvC,SAAS,aAAa,MAGe;CACnC,MAAM,WAAW,kBAAkB,OAAO,KAAK,aAAa,eAAe,GAAG,CAAC;CAC/E,MAAM,SAAS,OAAO,KAAK,SAAS,aAAa,GAAG,CAAC,MAAM;AAC3D,KAAI,CAAC,SACH,OAAM,IAAI,MAAM,8EAA8E;AAEhG,KAAI,CAAC,OACH,OAAM,IAAI,MAAM,6EAA6E;AAE/F,QAAO;EAAE;EAAU;EAAQ;;AAG7B,MAAa,0CAA0C,iBAAiB;CACtE,KAAK;CACL,OAAO;CACP,aAAa;CACb,QAAQ,EACN,UAAU;EACR,KAAK;EACL,OAAO;EACP,MAAM;EACN,UAAU;EACV,aAAa;EACb,UAAU;EACV,OAAO;EACR,EACF;CACD,QAAQ,EACN,QAAQ;EACN,KAAK;EACL,OAAO;EACP,MAAM;EACN,UAAU;EACV,OAAO;EACR,EACF;CACD,MAAM,cAAc,MAAM;AACxB,SAAO,aAAa,KAAK;;CAE3B,MAAM,KAAK,MAAM;AACf,MAAI;GACF,MAAM,UAAU,aAAa,KAAK;AAGlC,SAFe,IAAI,2BAA2B,QAAQ,UAAU,IAAI,mBAAmB,QAAQ,OAAO,CAAC,CACnF,eAAe,CACxB,MAAM;AACjB,UAAO;IACL,QAAQ;IACR,SAAS;IACT,2BAAU,IAAI,MAAM,EAAC,aAAa;IACnC;WACM,OAAO;AAEd,UAAO;IACL,QAAQ;IACR,UAHc,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM,KAGhD;IACpB,2BAAU,IAAI,MAAM,EAAC,aAAa;IACnC;;;CAGN,CAAC;;;;;;;;AC1CF,eAAsB,iBACpB,MAM4B;AAI5B,QAAO,kBADQ,MAFA,IAAI,2BAA2B,KAAK,QAAQ,UAAU,IAAI,mBAAmB,KAAK,QAAQ,OAAO,CAAC,CAC3F,cAAc,KAAK,YAAY,KAAK,MAAM,KAAK,YAAY,CACrD,eAAe,CACX;;;AAIlC,SAAgB,kBAAkB,QAA2C;CAC3E,MAAM,WAAW,OAAO,YAAY,EAAE;CACtC,MAAMA,gBAA0B,EAAE;AAClC,MAAK,MAAM,KAAK,SACd,KAAI,OAAO,EAAE,aAAa,YAAY,EAAE,SAAS,SAAS,EACxD,eAAc,KAAK,EAAE,SAAS;CAGlC,MAAM,UAAU,cAAc,KAAK,OAAO;AAC1C,KAAI,SAAS,WAAW,EACtB,QAAO;EAAE,SAAS;EAAI,QAAQ,EAAE;EAAE;AAEpC,KAAI,SAAS,WAAW,GAAG;EACzB,MAAM,IAAI,SAAS;AACnB,SAAO;GACL;GACA,QAAQ,EAAE,SAAS,sBAAsB,EAAE,OAAO,GAAG,EAAE;GACxD;;AAEH,QAAO;EACL;EACA,QAAQ,EACN,UAAU,SAAS,KAAK,GAAG,WAAW;GACpC;GACA,UAAU,OAAO,EAAE,aAAa,YAAY,EAAE,SAAS,MAAM,CAAC,SAAS,IAAI,EAAE,WAAW;GACxF,QAAQ,EAAE,SAAS,sBAAsB,EAAE,OAAO,GAAG,EAAE;GACxD,EAAE,EACJ;EACF;;AAGH,SAAS,sBAAsB,QAA0E;CACvG,MAAMC,MAA+B,EAAE;AACvC,MAAK,MAAM,CAAC,MAAM,UAAU,OAAO,QAAQ,OAAO,CAChD,KAAI,QAAQ,uBAAuB,MAAM;AAE3C,QAAO;;AAGT,SAAS,uBAAuB,OAAmC;AAEjE,SADa,iBAAiB,MAAM,EACpC;EACE,KAAK,SACH,QAAQ,MAAsB,SAAS;EACzC,KAAK,QAAQ;GACX,MAAM,IAAK,MAAoB;AAC/B,UAAO,IAAI,EAAE,aAAa,GAAG;;EAE/B,KAAK,OACH,QAAQ,MAAoB,SAAS;EACvC,KAAK,SACH,QAAQ,MAAsB,SAAS;EACzC,KAAK,UACH,QAAQ,MAAuB,SAAS;EAC1C,KAAK,UACH,QAAQ,MAAuB,SAAS;EAC1C,KAAK,QAEH,SADgB,MAAqB,SAAS,EAAE,EAClC,KAAK,YAAY,uBAAuB,QAAQ,CAAC;EAEjE,KAAK,SAEH,QAAO,sBADa,MAAsB,SAAS,EAAE,CACb;EAE1C,KAAK,OACH,QAAQ,MAAoB,SAAS;EACvC,SAAS;GACP,MAAM,OAAO;AACb,OAAI,KAAK,UAAU,UAAa,KAAK,UAAU,KAC7C,QAAO;AAET,UAAO,OAAO,KAAK,UAAU,WAAW,KAAK,QAAQ,OAAO,KAAK,MAAM;;;;AAK7E,SAAS,iBAAiB,OAAkC;AAC1D,KAAI,eAAe,SAAS,OAAO,MAAM,cAAc,SACrD,QAAO,MAAM;AAEf,QAAQ,MAAuB;;;;;;AC1HjC,MAAM,+BAA+B;AAiBrC,MAAa,sBAAsB,WAAW;CAC5C,KAAK;CACL,OAAO;CACP,aACE;CACF,MAAM;CACN,OAAO;EACL,aAAa;EACb,aAAa;EACb,YAAY;EACZ,UAAU;EACX;CACD,aAAa,EACX,sBAAsB;EACpB,MAAM;EACN,OAAO;EACP,UAAU;EACX,EACF;CACD,iBAAiB,EAAE,UAAU;EAC3B,MAAM,MAAM;EAEZ,MAAM,OAAO,CAAC;GAAE,OAAO;GAAY,OADhB,IAAI,cAAc;GACiB,CAAC;EACvD,MAAM,cAAc,IAAI,eAAe;AACvC,MAAI,gBAAgB,OAClB,MAAK,KAAK;GAAE,OAAO;GAAgB,OAAO;GAAa,CAAC;AAE1D,MAAI,IAAI,YACN,MAAK,KAAK;GAAE,OAAO;GAAgB,OAAO,IAAI;GAAa,CAAC;AAE9D,SAAO;;CAET,MAAM,QAAQ,EAAE,MAAM,OAAO,EAAE,QAAQ,WAAW,eAAe;EAC/D,MAAM,SAAS;EACf,MAAM,UAAW,MAAM,YAAY,sBAAsB;EACzD,MAAM,cAAc,OAAO,eAAe;EAC1C,MAAM,aAAa,KAAK,SAAS;AACjC,MAAI,CAAC,WACH,OAAM,IAAI,MAAM,kDAAkD,YAAY,IAAI;EAEpF,MAAM,aAAa,OAAO,cAAc;EACxC,MAAM,cAAc,OAAO,eAAe,WAAW,YAAY;AAEjE,SAAO,iBAAiB;GAAE;GAAS;GAAY,MADlC,MAAM,IAAI,OAAO,SAAS,YAAY,OAAO,SAAS;GACd;GAAa,CAAC;;CAEtE,CAAC;;;;;AC9DF,MAAM,4BAA4B;AAiBlC,MAAa,mBAAmB,WAAW;CACzC,KAAK;CACL,OAAO;CACP,aACE;CACF,MAAM;CACN,OAAO;EACL,aAAa;EACb,aAAa;EACb,YAAY;EACZ,UAAU;EACX;CACD,aAAa,EACX,sBAAsB;EACpB,MAAM;EACN,OAAO;EACP,UAAU;EACX,EACF;CACD,iBAAiB,EAAE,UAAU;EAC3B,MAAM,MAAM;EAEZ,MAAM,OAAO,CAAC;GAAE,OAAO;GAAY,OADhB,IAAI,cAAc;GACiB,CAAC;EACvD,MAAM,cAAc,IAAI,eAAe;AACvC,MAAI,gBAAgB,OAClB,MAAK,KAAK;GAAE,OAAO;GAAgB,OAAO;GAAa,CAAC;AAE1D,MAAI,IAAI,YACN,MAAK,KAAK;GAAE,OAAO;GAAgB,OAAO,IAAI;GAAa,CAAC;AAE9D,SAAO;;CAET,MAAM,QAAQ,EAAE,MAAM,OAAO,EAAE,QAAQ,WAAW,eAAe;EAC/D,MAAM,SAAS;EACf,MAAM,UAAW,MAAM,YAAY,sBAAsB;EACzD,MAAM,cAAc,OAAO,eAAe;EAC1C,MAAM,aAAa,KAAK,SAAS;AACjC,MAAI,CAAC,WACH,OAAM,IAAI,MAAM,+CAA+C,YAAY,IAAI;EAEjF,MAAM,aAAa,OAAO,cAAc;EACxC,MAAM,cAAc,OAAO,eAAe,WAAW,YAAY;AAEjE,SAAO,iBAAiB;GAAE;GAAS;GAAY,MADlC,MAAM,IAAI,OAAO,SAAS,YAAY,OAAO,SAAS;GACd;GAAa,CAAC;;CAEtE,CAAC;;;;;AC9DF,MAAM,+BAA+B;AAWrC,MAAa,qBAAqB,WAAW;CAC3C,KAAK;CACL,OAAO;CACP,aACE;CACF,MAAM;CACN,OAAO;EACL,aAAa;EACb,aAAa;EACb,UAAU;EACX;CACD,aAAa,EACX,sBAAsB;EACpB,MAAM;EACN,OAAO;EACP,UAAU;EACX,EACF;CACD,iBAAiB,EAAE,UAAU;EAC3B,MAAM,MAAM;EACZ,MAAM,OAAO,CAAC;GAAE,OAAO;GAAY,OAAO;GAAsB,CAAC;EACjE,MAAM,cAAc,IAAI,eAAe;AACvC,MAAI,gBAAgB,OAClB,MAAK,KAAK;GAAE,OAAO;GAAgB,OAAO;GAAa,CAAC;AAE1D,MAAI,IAAI,YACN,MAAK,KAAK;GAAE,OAAO;GAAgB,OAAO,IAAI;GAAa,CAAC;AAE9D,SAAO;;CAET,MAAM,QAAQ,EAAE,MAAM,OAAO,EAAE,QAAQ,WAAW,eAAe;EAC/D,MAAM,SAAS;EACf,MAAM,UAAW,MAAM,YAAY,sBAAsB;EACzD,MAAM,cAAc,OAAO,eAAe;EAC1C,MAAM,aAAa,KAAK,SAAS;AACjC,MAAI,CAAC,WACH,OAAM,IAAI,MAAM,iDAAiD,YAAY,IAAI;EAEnF,MAAM,cAAc,OAAO,eAAe,WAAW,YAAY;AAEjE,SAAO,iBAAiB;GAAE;GAAS,YAAY;GAA8B,MADhE,MAAM,IAAI,OAAO,SAAS,YAAY,OAAO,SAAS;GACgB;GAAa,CAAC;;CAEpG,CAAC"}
|
|
@@ -128,38 +128,6 @@ function resolveFieldKind(field) {
|
|
|
128
128
|
return field.type;
|
|
129
129
|
}
|
|
130
130
|
|
|
131
|
-
//#endregion
|
|
132
|
-
//#region src/lib/readBinaryBody.ts
|
|
133
|
-
/** Default cap on bytes read into memory. Tuned for prebuilt OCR analyzers (single document). */
|
|
134
|
-
const DEFAULT_MAX_BYTES = 50 * 1024 * 1024;
|
|
135
|
-
/**
|
|
136
|
-
* Reads the binary body for an OCR analyzer call.
|
|
137
|
-
*
|
|
138
|
-
* The Azure Content Understanding SDK requires a contiguous `Uint8Array`, so the bytes must
|
|
139
|
-
* land in memory at some point. To bound that:
|
|
140
|
-
* - The attachment's declared `size` is checked against `maxBytes` *before* any allocation.
|
|
141
|
-
* - A single buffer of exactly `attachment.size` is pre-allocated (no chunks array, no doubling).
|
|
142
|
-
* - The stream fills the buffer directly; a length mismatch fails fast.
|
|
143
|
-
*/
|
|
144
|
-
async function readBinaryBody(ctx, attachment, maxBytes = DEFAULT_MAX_BYTES) {
|
|
145
|
-
if (attachment.size > maxBytes) throw new Error(`Binary attachment size ${attachment.size} bytes exceeds maxBytes ${maxBytes}. Raise the node's maxBytes setting if this document is expected to be larger.`);
|
|
146
|
-
const stream = await ctx.binary.openReadStream(attachment);
|
|
147
|
-
if (!stream) throw new Error("Binary attachment stream is unavailable.");
|
|
148
|
-
const out = new Uint8Array(attachment.size);
|
|
149
|
-
const reader = stream.body.getReader();
|
|
150
|
-
let offset = 0;
|
|
151
|
-
while (true) {
|
|
152
|
-
const { done, value } = await reader.read();
|
|
153
|
-
if (done) break;
|
|
154
|
-
if (!value) continue;
|
|
155
|
-
if (offset + value.byteLength > out.byteLength) throw new Error(`Binary stream produced more bytes than the attachment's declared size (${attachment.size}).`);
|
|
156
|
-
out.set(value, offset);
|
|
157
|
-
offset += value.byteLength;
|
|
158
|
-
}
|
|
159
|
-
if (offset !== out.byteLength) throw new Error(`Binary stream produced ${offset} bytes but attachment declared size ${attachment.size}.`);
|
|
160
|
-
return out;
|
|
161
|
-
}
|
|
162
|
-
|
|
163
131
|
//#endregion
|
|
164
132
|
//#region src/nodes/analyzeDocumentNode.ts
|
|
165
133
|
/** Default Azure Content Understanding prebuilt general document analyzer ID. */
|
|
@@ -208,7 +176,7 @@ const analyzeDocumentNode = (0, __codemation_core.defineNode)({
|
|
|
208
176
|
return analyzeWithAzure({
|
|
209
177
|
session,
|
|
210
178
|
analyzerId,
|
|
211
|
-
body: await
|
|
179
|
+
body: await ctx.binary.getBytes(attachment, config.maxBytes),
|
|
212
180
|
contentType
|
|
213
181
|
});
|
|
214
182
|
}
|
|
@@ -262,7 +230,7 @@ const analyzeImageNode = (0, __codemation_core.defineNode)({
|
|
|
262
230
|
return analyzeWithAzure({
|
|
263
231
|
session,
|
|
264
232
|
analyzerId,
|
|
265
|
-
body: await
|
|
233
|
+
body: await ctx.binary.getBytes(attachment, config.maxBytes),
|
|
266
234
|
contentType
|
|
267
235
|
});
|
|
268
236
|
}
|
|
@@ -314,7 +282,7 @@ const analyzeInvoiceNode = (0, __codemation_core.defineNode)({
|
|
|
314
282
|
return analyzeWithAzure({
|
|
315
283
|
session,
|
|
316
284
|
analyzerId: PREBUILT_INVOICE_ANALYZER_ID,
|
|
317
|
-
body: await
|
|
285
|
+
body: await ctx.binary.getBytes(attachment, config.maxBytes),
|
|
318
286
|
contentType
|
|
319
287
|
});
|
|
320
288
|
}
|
|
@@ -357,4 +325,4 @@ Object.defineProperty(exports, 'mapAnalysisResult', {
|
|
|
357
325
|
return mapAnalysisResult;
|
|
358
326
|
}
|
|
359
327
|
});
|
|
360
|
-
//# sourceMappingURL=analyzeInvoiceNode-
|
|
328
|
+
//# sourceMappingURL=analyzeInvoiceNode-CmMsifbw.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"analyzeInvoiceNode-CmMsifbw.cjs","names":["ContentUnderstandingClient","AzureKeyCredential","ContentUnderstandingClient","AzureKeyCredential","markdownParts: string[]","out: Record<string, unknown>"],"sources":["../src/credentials/azureContentUnderstandingCredential.ts","../src/lib/analyzeWithAzure.ts","../src/nodes/analyzeDocumentNode.ts","../src/nodes/analyzeImageNode.ts","../src/nodes/analyzeInvoiceNode.ts"],"sourcesContent":["import { ContentUnderstandingClient } from \"@azure/ai-content-understanding\";\nimport { AzureKeyCredential } from \"@azure/core-auth\";\nimport { defineCredential } from \"@codemation/core\";\n\nexport type AzureContentUnderstandingSession = Readonly<{\n endpoint: string;\n apiKey: string;\n}>;\n\nfunction normalizeEndpoint(raw: string): string {\n return raw.trim().replace(/\\/+$/, \"\");\n}\n\nfunction buildSession(args: {\n readonly publicConfig: Readonly<Record<string, unknown>>;\n readonly material: Readonly<Record<string, unknown>>;\n}): AzureContentUnderstandingSession {\n const endpoint = normalizeEndpoint(String(args.publicConfig[\"endpoint\"] ?? \"\"));\n const apiKey = String(args.material[\"apiKey\"] ?? \"\").trim();\n if (!endpoint) {\n throw new Error(\"Azure Content Understanding credential is incomplete: endpoint is required.\");\n }\n if (!apiKey) {\n throw new Error(\"Azure Content Understanding credential is incomplete: API key is required.\");\n }\n return { endpoint, apiKey };\n}\n\nexport const azureContentUnderstandingCredentialType = defineCredential({\n key: \"azure.contentUnderstanding\",\n label: \"Azure Content Understanding\",\n description: \"Azure AI Content Understanding (endpoint + key) for prebuilt document, invoice, and image analyzers.\",\n public: {\n endpoint: {\n key: \"endpoint\",\n label: \"Endpoint\",\n type: \"string\" as const,\n required: true,\n placeholder: \"https://your-resource.cognitiveservices.azure.com/\",\n helpText: \"Content Understanding resource endpoint URL (no trailing slash).\",\n order: 0,\n },\n },\n secret: {\n apiKey: {\n key: \"apiKey\",\n label: \"API key\",\n type: \"password\" as const,\n required: true,\n order: 1,\n },\n },\n async createSession(args) {\n return buildSession(args);\n },\n async test(args) {\n try {\n const session = buildSession(args);\n const client = new ContentUnderstandingClient(session.endpoint, new AzureKeyCredential(session.apiKey));\n const iter = client.listAnalyzers();\n await iter.next();\n return {\n status: \"healthy\",\n message: \"Listed analyzers successfully.\",\n testedAt: new Date().toISOString(),\n };\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n return {\n status: \"failing\",\n message: message || \"Azure Content Understanding connection failed.\",\n testedAt: new Date().toISOString(),\n };\n }\n },\n});\n","import type {\n AnalysisResult,\n ArrayField,\n BooleanField,\n ContentField,\n ContentFieldUnion,\n DateField,\n IntegerField,\n JsonField,\n NumberField,\n ObjectField,\n StringField,\n TimeField,\n} from \"@azure/ai-content-understanding\";\nimport { ContentUnderstandingClient } from \"@azure/ai-content-understanding\";\nimport { AzureKeyCredential } from \"@azure/core-auth\";\nimport type { AzureContentUnderstandingSession } from \"../credentials/azureContentUnderstandingCredential\";\n\n/** Structured analyzer fields: scalars at leaves; nested objects and arrays preserved. */\nexport type OcrStructuredFields = Readonly<Record<string, unknown>>;\n\n/** The output shape returned by all OCR analyzer nodes. */\nexport type OcrAnalysisOutput = Readonly<{\n /** Markdown representation of the document content. */\n content: string;\n /** Structured fields extracted by the prebuilt analyzer. */\n fields: OcrStructuredFields;\n}>;\n\n/**\n * Analyzes a binary document using an Azure Content Understanding prebuilt analyzer.\n * Retries on transient failures are handled by the engine via the node's `retryPolicy`.\n */\nexport async function analyzeWithAzure(\n args: Readonly<{\n session: AzureContentUnderstandingSession;\n analyzerId: string;\n body: Uint8Array;\n contentType: string;\n }>,\n): Promise<OcrAnalysisOutput> {\n const client = new ContentUnderstandingClient(args.session.endpoint, new AzureKeyCredential(args.session.apiKey));\n const poller = client.analyzeBinary(args.analyzerId, args.body, args.contentType);\n const result = await poller.pollUntilDone();\n return mapAnalysisResult(result);\n}\n\n/** @internal Exported for testing — maps a raw AnalysisResult to the node output shape. */\nexport function mapAnalysisResult(result: AnalysisResult): OcrAnalysisOutput {\n const contents = result.contents ?? [];\n const markdownParts: string[] = [];\n for (const c of contents) {\n if (typeof c.markdown === \"string\" && c.markdown.length > 0) {\n markdownParts.push(c.markdown);\n }\n }\n const content = markdownParts.join(\"\\n\\n\");\n if (contents.length === 0) {\n return { content: \"\", fields: {} };\n }\n if (contents.length === 1) {\n const c = contents[0]!;\n return {\n content,\n fields: c.fields ? fieldsToStructuredMap(c.fields) : {},\n };\n }\n return {\n content,\n fields: {\n segments: contents.map((c, index) => ({\n index,\n markdown: typeof c.markdown === \"string\" && c.markdown.trim().length > 0 ? c.markdown : undefined,\n fields: c.fields ? fieldsToStructuredMap(c.fields) : {},\n })),\n },\n };\n}\n\nfunction fieldsToStructuredMap(fields: Readonly<Record<string, ContentFieldUnion>>): OcrStructuredFields {\n const out: Record<string, unknown> = {};\n for (const [name, field] of Object.entries(fields)) {\n out[name] = fieldToStructuredValue(field);\n }\n return out;\n}\n\nfunction fieldToStructuredValue(field: ContentFieldUnion): unknown {\n const kind = resolveFieldKind(field);\n switch (kind) {\n case \"string\":\n return (field as StringField).value ?? null;\n case \"date\": {\n const d = (field as DateField).value;\n return d ? d.toISOString() : null;\n }\n case \"time\":\n return (field as TimeField).value ?? null;\n case \"number\":\n return (field as NumberField).value ?? null;\n case \"integer\":\n return (field as IntegerField).value ?? null;\n case \"boolean\":\n return (field as BooleanField).value ?? null;\n case \"array\": {\n const values = (field as ArrayField).value ?? [];\n return values.map((element) => fieldToStructuredValue(element));\n }\n case \"object\": {\n const properties = (field as ObjectField).value ?? {};\n return fieldsToStructuredMap(properties);\n }\n case \"json\":\n return (field as JsonField).value ?? null;\n default: {\n const base = field as ContentField;\n if (base.value === undefined || base.value === null) {\n return null;\n }\n return typeof base.value === \"object\" ? base.value : String(base.value);\n }\n }\n}\n\nfunction resolveFieldKind(field: ContentFieldUnion): string {\n if (\"fieldType\" in field && typeof field.fieldType === \"string\") {\n return field.fieldType;\n }\n return (field as ContentField).type;\n}\n","import { defineNode } from \"@codemation/core\";\nimport type { AzureContentUnderstandingSession } from \"../credentials/azureContentUnderstandingCredential\";\nimport { azureContentUnderstandingCredentialType } from \"../credentials/azureContentUnderstandingCredential\";\nimport { analyzeWithAzure } from \"../lib/analyzeWithAzure\";\n\n/** Default Azure Content Understanding prebuilt general document analyzer ID. */\nconst DEFAULT_DOCUMENT_ANALYZER_ID = \"prebuilt-document\";\n\nexport type AnalyzeDocumentConfig = Readonly<{\n /** Key on `item.binary` that holds the document bytes. Default: `\"data\"`. */\n binaryField?: string;\n /** MIME type override sent to the analyzer. Falls back to attachment `mimeType` when not set. */\n contentType?: string;\n /**\n * Azure Content Understanding analyzer ID to use.\n * Defaults to `\"prebuilt-document\"`. Set this to a custom analyzer ID when you have\n * a trained model or need a different prebuilt variant.\n */\n analyzerId?: string;\n /** Max bytes the attachment may have before reading. Defaults to 50 MiB. */\n maxBytes?: number;\n}>;\n\nexport const analyzeDocumentNode = defineNode({\n key: \"azure-ocr.analyze-document\",\n title: \"Analyze Document\",\n description:\n \"Runs an Azure Content Understanding document analyzer on a binary attachment and returns markdown text plus structured fields. Defaults to the prebuilt general document analyzer.\",\n icon: \"lucide:scan-text\",\n input: {\n binaryField: \"data\",\n contentType: undefined as string | undefined,\n analyzerId: undefined as string | undefined,\n maxBytes: undefined as number | undefined,\n },\n credentials: {\n contentUnderstanding: {\n type: azureContentUnderstandingCredentialType as import(\"@codemation/core\").AnyCredentialType,\n label: \"Azure Content Understanding\",\n helpText: \"Bind an Azure Content Understanding credential (endpoint + key).\",\n },\n },\n inspectorSummary({ config }) {\n const cfg = config as unknown as AnalyzeDocumentConfig;\n const analyzerId = cfg.analyzerId ?? DEFAULT_DOCUMENT_ANALYZER_ID;\n const rows = [{ label: \"Analyzer\", value: analyzerId }];\n const binaryField = cfg.binaryField ?? \"data\";\n if (binaryField !== \"data\") {\n rows.push({ label: \"Binary field\", value: binaryField });\n }\n if (cfg.contentType) {\n rows.push({ label: \"Content type\", value: cfg.contentType });\n }\n return rows;\n },\n async execute({ item, ctx }, { config: rawConfig, credentials }) {\n const config = rawConfig as unknown as AnalyzeDocumentConfig;\n const session = (await credentials.contentUnderstanding()) as AzureContentUnderstandingSession;\n const binaryField = config.binaryField ?? \"data\";\n const attachment = item.binary?.[binaryField];\n if (!attachment) {\n throw new Error(`Analyze Document: no binary attachment at key \"${binaryField}\".`);\n }\n const analyzerId = config.analyzerId ?? DEFAULT_DOCUMENT_ANALYZER_ID;\n const contentType = config.contentType ?? attachment.mimeType ?? \"application/octet-stream\";\n const body = await ctx.binary.getBytes(attachment, config.maxBytes);\n return analyzeWithAzure({ session, analyzerId, body, contentType });\n },\n});\n","import { defineNode } from \"@codemation/core\";\nimport type { AzureContentUnderstandingSession } from \"../credentials/azureContentUnderstandingCredential\";\nimport { azureContentUnderstandingCredentialType } from \"../credentials/azureContentUnderstandingCredential\";\nimport { analyzeWithAzure } from \"../lib/analyzeWithAzure\";\n\n/** Default Azure Content Understanding prebuilt image analyzer ID. */\nconst DEFAULT_IMAGE_ANALYZER_ID = \"prebuilt-imageAnalyzer\";\n\nexport type AnalyzeImageConfig = Readonly<{\n /** Key on `item.binary` that holds the image bytes. Default: `\"data\"`. */\n binaryField?: string;\n /** MIME type override sent to the analyzer. Falls back to attachment `mimeType` when not set. */\n contentType?: string;\n /**\n * Azure Content Understanding analyzer ID to use.\n * Defaults to `\"prebuilt-imageAnalyzer\"`. Set this to a custom analyzer ID when you have\n * a trained model or need a different prebuilt variant.\n */\n analyzerId?: string;\n /** Max bytes the attachment may have before reading. Defaults to 50 MiB. */\n maxBytes?: number;\n}>;\n\nexport const analyzeImageNode = defineNode({\n key: \"azure-ocr.analyze-image\",\n title: \"Analyze Image\",\n description:\n \"Runs an Azure Content Understanding image analyzer on a binary attachment and returns markdown text plus structured fields. Defaults to the prebuilt image analyzer.\",\n icon: \"lucide:image-search\",\n input: {\n binaryField: \"data\",\n contentType: undefined as string | undefined,\n analyzerId: undefined as string | undefined,\n maxBytes: undefined as number | undefined,\n },\n credentials: {\n contentUnderstanding: {\n type: azureContentUnderstandingCredentialType as import(\"@codemation/core\").AnyCredentialType,\n label: \"Azure Content Understanding\",\n helpText: \"Bind an Azure Content Understanding credential (endpoint + key).\",\n },\n },\n inspectorSummary({ config }) {\n const cfg = config as unknown as AnalyzeImageConfig;\n const analyzerId = cfg.analyzerId ?? DEFAULT_IMAGE_ANALYZER_ID;\n const rows = [{ label: \"Analyzer\", value: analyzerId }];\n const binaryField = cfg.binaryField ?? \"data\";\n if (binaryField !== \"data\") {\n rows.push({ label: \"Binary field\", value: binaryField });\n }\n if (cfg.contentType) {\n rows.push({ label: \"Content type\", value: cfg.contentType });\n }\n return rows;\n },\n async execute({ item, ctx }, { config: rawConfig, credentials }) {\n const config = rawConfig as unknown as AnalyzeImageConfig;\n const session = (await credentials.contentUnderstanding()) as AzureContentUnderstandingSession;\n const binaryField = config.binaryField ?? \"data\";\n const attachment = item.binary?.[binaryField];\n if (!attachment) {\n throw new Error(`Analyze Image: no binary attachment at key \"${binaryField}\".`);\n }\n const analyzerId = config.analyzerId ?? DEFAULT_IMAGE_ANALYZER_ID;\n const contentType = config.contentType ?? attachment.mimeType ?? \"application/octet-stream\";\n const body = await ctx.binary.getBytes(attachment, config.maxBytes);\n return analyzeWithAzure({ session, analyzerId, body, contentType });\n },\n});\n","import { defineNode } from \"@codemation/core\";\nimport type { AzureContentUnderstandingSession } from \"../credentials/azureContentUnderstandingCredential\";\nimport { azureContentUnderstandingCredentialType } from \"../credentials/azureContentUnderstandingCredential\";\nimport { analyzeWithAzure } from \"../lib/analyzeWithAzure\";\n\n/** Azure Content Understanding prebuilt invoice analyzer ID. */\nconst PREBUILT_INVOICE_ANALYZER_ID = \"prebuilt-invoice\";\n\nexport type AnalyzeInvoiceConfig = Readonly<{\n /** Key on `item.binary` that holds the document bytes. Default: `\"data\"`. */\n binaryField?: string;\n /** MIME type override sent to the analyzer. Falls back to attachment `mimeType` when not set. */\n contentType?: string;\n /** Max bytes the attachment may have before reading. Defaults to 50 MiB. */\n maxBytes?: number;\n}>;\n\nexport const analyzeInvoiceNode = defineNode({\n key: \"azure-ocr.analyze-invoice\",\n title: \"Analyze Invoice\",\n description:\n \"Runs the Azure Content Understanding prebuilt invoice analyzer on a binary attachment and returns markdown text plus structured fields.\",\n icon: \"lucide:receipt\",\n input: {\n binaryField: \"data\",\n contentType: undefined as string | undefined,\n maxBytes: undefined as number | undefined,\n },\n credentials: {\n contentUnderstanding: {\n type: azureContentUnderstandingCredentialType as import(\"@codemation/core\").AnyCredentialType,\n label: \"Azure Content Understanding\",\n helpText: \"Bind an Azure Content Understanding credential (endpoint + key).\",\n },\n },\n inspectorSummary({ config }) {\n const cfg = config as unknown as AnalyzeInvoiceConfig;\n const rows = [{ label: \"Analyzer\", value: \"Invoice (prebuilt)\" }];\n const binaryField = cfg.binaryField ?? \"data\";\n if (binaryField !== \"data\") {\n rows.push({ label: \"Binary field\", value: binaryField });\n }\n if (cfg.contentType) {\n rows.push({ label: \"Content type\", value: cfg.contentType });\n }\n return rows;\n },\n async execute({ item, ctx }, { config: rawConfig, credentials }) {\n const config = rawConfig as unknown as AnalyzeInvoiceConfig;\n const session = (await credentials.contentUnderstanding()) as AzureContentUnderstandingSession;\n const binaryField = config.binaryField ?? \"data\";\n const attachment = item.binary?.[binaryField];\n if (!attachment) {\n throw new Error(`Analyze Invoice: no binary attachment at key \"${binaryField}\".`);\n }\n const contentType = config.contentType ?? attachment.mimeType ?? \"application/octet-stream\";\n const body = await ctx.binary.getBytes(attachment, config.maxBytes);\n return analyzeWithAzure({ session, analyzerId: PREBUILT_INVOICE_ANALYZER_ID, body, contentType });\n },\n});\n"],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
const require_chunk = require('./chunk-BaqVhFee.cjs');
|
|
2
|
-
const require_analyzeInvoiceNode = require('./analyzeInvoiceNode-
|
|
2
|
+
const require_analyzeInvoiceNode = require('./analyzeInvoiceNode-CmMsifbw.cjs');
|
|
3
3
|
const require_token_util$1 = require('./token-util-B2kSJtEV.cjs');
|
|
4
4
|
let __codemation_core = require("@codemation/core");
|
|
5
5
|
__codemation_core = require_chunk.__toESM(__codemation_core);
|
|
@@ -8289,6 +8289,59 @@ var OpenAiChatModelPresets = class {
|
|
|
8289
8289
|
};
|
|
8290
8290
|
const openAiChatModelPresets = new OpenAiChatModelPresets();
|
|
8291
8291
|
|
|
8292
|
+
//#endregion
|
|
8293
|
+
//#region ../core-nodes/src/chatModels/ManagedHmacSignerFactory.types.ts
|
|
8294
|
+
/**
|
|
8295
|
+
* Creates an HMAC-signing fetch wrapper that authenticates requests to
|
|
8296
|
+
* Codemation managed services (LLM broker, doc-scanner) with the
|
|
8297
|
+
* Codemation-Hmac v=1 scheme.
|
|
8298
|
+
*
|
|
8299
|
+
* Mirrors HmacRequestSigner from @codemation/host/pairing without importing
|
|
8300
|
+
* that package (which would create a circular dependency since @codemation/host
|
|
8301
|
+
* depends on @codemation/core-nodes).
|
|
8302
|
+
*
|
|
8303
|
+
* @param workspaceId - Workspace identifier injected by the CP provisioner.
|
|
8304
|
+
* @param pairingSecret - Base64-encoded 32-byte HMAC key injected by the provisioner.
|
|
8305
|
+
* @param options - Optional behaviour flags and test seams.
|
|
8306
|
+
*/
|
|
8307
|
+
function managedHmacFetchFactory(workspaceId, pairingSecret, options) {
|
|
8308
|
+
const signBody = options?.signBody ?? true;
|
|
8309
|
+
return async (input, init) => {
|
|
8310
|
+
const url = typeof input === "string" ? input : input instanceof URL ? input.href : input.url;
|
|
8311
|
+
const method = init?.method ?? "POST";
|
|
8312
|
+
let bodyForSigning = "";
|
|
8313
|
+
if (signBody && init?.body !== void 0 && init.body !== null) bodyForSigning = typeof init.body === "string" ? init.body : await new Response(init.body).text();
|
|
8314
|
+
const authHeader = buildHmacAuthHeader(workspaceId, pairingSecret, method, url, bodyForSigning, options);
|
|
8315
|
+
const headers = new Headers(init?.headers);
|
|
8316
|
+
headers.set("Authorization", authHeader);
|
|
8317
|
+
const outgoingBody = signBody ? bodyForSigning || init?.body : init?.body;
|
|
8318
|
+
return fetch(input, {
|
|
8319
|
+
...init,
|
|
8320
|
+
body: outgoingBody,
|
|
8321
|
+
headers
|
|
8322
|
+
});
|
|
8323
|
+
};
|
|
8324
|
+
}
|
|
8325
|
+
/**
|
|
8326
|
+
* Produces a Codemation-Hmac v=1 Authorization header value.
|
|
8327
|
+
* Algorithm must match HmacVerifier.computeSignature() in the control-plane.
|
|
8328
|
+
*/
|
|
8329
|
+
function buildHmacAuthHeader(workspaceId, pairingSecret, method, url, body, overrides) {
|
|
8330
|
+
const ts = overrides?.now ? overrides.now() : Math.floor(Date.now() / 1e3);
|
|
8331
|
+
const nonce = overrides?.nonce ? overrides.nonce() : (0, node_crypto.randomBytes)(16).toString("base64");
|
|
8332
|
+
const parsed = new URL(url);
|
|
8333
|
+
const path = (parsed.pathname + parsed.search).toLowerCase();
|
|
8334
|
+
const bodyHash = (0, node_crypto.createHash)("sha256").update(body, "utf8").digest("hex");
|
|
8335
|
+
const baseString = [
|
|
8336
|
+
method.toUpperCase(),
|
|
8337
|
+
path,
|
|
8338
|
+
ts,
|
|
8339
|
+
nonce,
|
|
8340
|
+
bodyHash
|
|
8341
|
+
].join("\n");
|
|
8342
|
+
return `Codemation-Hmac v=1,workspaceId=${workspaceId},ts=${ts},nonce=${nonce},sig=${(0, node_crypto.createHmac)("sha256", Buffer.from(pairingSecret, "base64")).update(baseString, "utf8").digest("base64")}`;
|
|
8343
|
+
}
|
|
8344
|
+
|
|
8292
8345
|
//#endregion
|
|
8293
8346
|
//#region ../core-nodes/src/chatModels/CodemationChatModelFactory.ts
|
|
8294
8347
|
let CodemationChatModelFactory = class CodemationChatModelFactory$1 {
|
|
@@ -8298,7 +8351,7 @@ let CodemationChatModelFactory = class CodemationChatModelFactory$1 {
|
|
|
8298
8351
|
const workspaceId = process.env["WORKSPACE_ID"];
|
|
8299
8352
|
const pairingSecret = process.env["WORKSPACE_PAIRING_SECRET"];
|
|
8300
8353
|
if (!workspaceId || !pairingSecret) throw new Error("Codemation managed AI not available in this environment (workspace pairing is not configured).");
|
|
8301
|
-
const hmacFetch =
|
|
8354
|
+
const hmacFetch = managedHmacFetchFactory(workspaceId, pairingSecret);
|
|
8302
8355
|
const languageModel = createOpenAI({
|
|
8303
8356
|
baseURL: `${gatewayUrl}/v1`,
|
|
8304
8357
|
apiKey: "codemation-managed",
|
|
@@ -8314,52 +8367,6 @@ let CodemationChatModelFactory = class CodemationChatModelFactory$1 {
|
|
|
8314
8367
|
}
|
|
8315
8368
|
});
|
|
8316
8369
|
}
|
|
8317
|
-
/**
|
|
8318
|
-
* Creates an HMAC-signed fetch wrapper for use with AI SDK's createOpenAI.
|
|
8319
|
-
* Each call signs the request body with the workspace pairing secret so the
|
|
8320
|
-
* LLM broker can authenticate the workspace without a user-managed API key.
|
|
8321
|
-
*
|
|
8322
|
-
* Mirrors HmacRequestSigner from @codemation/host/pairing without importing
|
|
8323
|
-
* that package (which would create a circular dependency since @codemation/host
|
|
8324
|
-
* depends on @codemation/core-nodes).
|
|
8325
|
-
*/
|
|
8326
|
-
buildHmacSignedFetch(workspaceId, pairingSecret) {
|
|
8327
|
-
return async (input, init) => {
|
|
8328
|
-
const url = typeof input === "string" ? input : input instanceof URL ? input.href : input.url;
|
|
8329
|
-
const method = init?.method ?? "POST";
|
|
8330
|
-
let bodyString = "";
|
|
8331
|
-
if (init?.body !== void 0 && init.body !== null) if (typeof init.body === "string") bodyString = init.body;
|
|
8332
|
-
else bodyString = await new Response(init.body).text();
|
|
8333
|
-
const authHeader = this.buildHmacAuthHeader(workspaceId, pairingSecret, method, url, bodyString);
|
|
8334
|
-
const headers = new Headers(init?.headers);
|
|
8335
|
-
headers.set("Authorization", authHeader);
|
|
8336
|
-
const effectiveBody = bodyString || init?.body;
|
|
8337
|
-
return fetch(input, {
|
|
8338
|
-
...init,
|
|
8339
|
-
body: effectiveBody,
|
|
8340
|
-
headers
|
|
8341
|
-
});
|
|
8342
|
-
};
|
|
8343
|
-
}
|
|
8344
|
-
/**
|
|
8345
|
-
* Produces a Codemation-Hmac v1 Authorization header value.
|
|
8346
|
-
* The algorithm must match HmacVerifier.computeSignature() in the control-plane.
|
|
8347
|
-
*/
|
|
8348
|
-
buildHmacAuthHeader(workspaceId, pairingSecret, method, url, body) {
|
|
8349
|
-
const ts = Math.floor(Date.now() / 1e3);
|
|
8350
|
-
const nonce = (0, node_crypto.randomBytes)(16).toString("base64");
|
|
8351
|
-
const parsed = new URL(url);
|
|
8352
|
-
const path = (parsed.pathname + parsed.search).toLowerCase();
|
|
8353
|
-
const bodyHash = (0, node_crypto.createHash)("sha256").update(body, "utf8").digest("hex");
|
|
8354
|
-
const baseString = [
|
|
8355
|
-
method.toUpperCase(),
|
|
8356
|
-
path,
|
|
8357
|
-
ts,
|
|
8358
|
-
nonce,
|
|
8359
|
-
bodyHash
|
|
8360
|
-
].join("\n");
|
|
8361
|
-
return `Codemation-Hmac v=1,workspaceId=${workspaceId},ts=${ts},nonce=${nonce},sig=${(0, node_crypto.createHmac)("sha256", Buffer.from(pairingSecret, "base64")).update(baseString, "utf8").digest("base64")}`;
|
|
8362
|
-
}
|
|
8363
8370
|
};
|
|
8364
8371
|
CodemationChatModelFactory = __decorate([(0, __codemation_core.chatModel)({ packageName: "@codemation/core-nodes" })], CodemationChatModelFactory);
|
|
8365
8372
|
|
|
@@ -15997,7 +16004,11 @@ let AIAgentNode = class AIAgentNode$1 {
|
|
|
15997
16004
|
});
|
|
15998
16005
|
try {
|
|
15999
16006
|
const callOptions = this.resolveCallOptions(model, guardrails.modelInvocationOptions);
|
|
16000
|
-
const
|
|
16007
|
+
const schemaRecord = this.isZodSchema(schema) ? this.executionHelpers.createJsonSchemaRecord(schema, {
|
|
16008
|
+
schemaName: structuredOptions?.schemaName ?? "structured_output",
|
|
16009
|
+
requireObjectRoot: true
|
|
16010
|
+
}) : schema;
|
|
16011
|
+
const outputSchema$1 = output_exports.object({ schema: jsonSchema(schemaRecord) });
|
|
16001
16012
|
const result = await generateText({
|
|
16002
16013
|
model: model.languageModel,
|
|
16003
16014
|
messages: [...messages],
|
|
@@ -18008,6 +18019,86 @@ const inboxApproval = (0, __codemation_core.defineHumanApprovalNode)({
|
|
|
18008
18019
|
}
|
|
18009
18020
|
});
|
|
18010
18021
|
|
|
18022
|
+
//#endregion
|
|
18023
|
+
//#region ../core-nodes/src/nodes/codemationDocumentScannerNode.ts
|
|
18024
|
+
const ANALYZER_TYPES = [
|
|
18025
|
+
"document",
|
|
18026
|
+
"invoice",
|
|
18027
|
+
"image",
|
|
18028
|
+
"auto"
|
|
18029
|
+
];
|
|
18030
|
+
const codemationDocumentScannerNode = (0, __codemation_core.defineNode)({
|
|
18031
|
+
key: "codemation.document-scanner",
|
|
18032
|
+
title: "Codemation Document Scanner",
|
|
18033
|
+
description: "Analyzes a binary attachment (document or image) via the managed Codemation document-scanning service and returns markdown text plus structured fields. No Azure credential required — auth uses the workspace pairing secret. Enable includeConfidence to get per-field confidence scores (0–1).",
|
|
18034
|
+
icon: "lucide:scan-text",
|
|
18035
|
+
input: {
|
|
18036
|
+
binaryField: "data",
|
|
18037
|
+
analyzerType: "auto",
|
|
18038
|
+
contentType: void 0,
|
|
18039
|
+
includeConfidence: false,
|
|
18040
|
+
maxBytes: void 0
|
|
18041
|
+
},
|
|
18042
|
+
configSchema: zod.z.object({
|
|
18043
|
+
binaryField: zod.z.string().optional(),
|
|
18044
|
+
analyzerType: zod.z.enum(ANALYZER_TYPES).optional(),
|
|
18045
|
+
contentType: zod.z.string().optional(),
|
|
18046
|
+
includeConfidence: zod.z.boolean().optional(),
|
|
18047
|
+
maxBytes: zod.z.number().int().positive().optional()
|
|
18048
|
+
}),
|
|
18049
|
+
inspectorSummary({ config }) {
|
|
18050
|
+
const cfg = config;
|
|
18051
|
+
const rows = [{
|
|
18052
|
+
label: "Analyzer type",
|
|
18053
|
+
value: cfg.analyzerType ?? "auto"
|
|
18054
|
+
}];
|
|
18055
|
+
const binaryField = cfg.binaryField ?? "data";
|
|
18056
|
+
if (binaryField !== "data") rows.push({
|
|
18057
|
+
label: "Binary field",
|
|
18058
|
+
value: binaryField
|
|
18059
|
+
});
|
|
18060
|
+
if (cfg.includeConfidence) rows.push({
|
|
18061
|
+
label: "Confidence",
|
|
18062
|
+
value: "enabled"
|
|
18063
|
+
});
|
|
18064
|
+
if (cfg.contentType) rows.push({
|
|
18065
|
+
label: "Content type",
|
|
18066
|
+
value: cfg.contentType
|
|
18067
|
+
});
|
|
18068
|
+
return rows;
|
|
18069
|
+
},
|
|
18070
|
+
async execute({ item, ctx }, { config: rawConfig }) {
|
|
18071
|
+
const config = rawConfig;
|
|
18072
|
+
const gatewayUrl = process.env["DOC_SCANNER_GATEWAY_URL"];
|
|
18073
|
+
if (!gatewayUrl) throw new Error("Codemation Document Scanner not available in this environment (DOC_SCANNER_GATEWAY_URL is not set).");
|
|
18074
|
+
const workspaceId = process.env["WORKSPACE_ID"];
|
|
18075
|
+
const pairingSecret = process.env["WORKSPACE_PAIRING_SECRET"];
|
|
18076
|
+
if (!workspaceId || !pairingSecret) throw new Error("Codemation Document Scanner not available (workspace pairing is not configured).");
|
|
18077
|
+
const binaryField = config.binaryField ?? "data";
|
|
18078
|
+
const attachment = item.binary?.[binaryField];
|
|
18079
|
+
if (!attachment) throw new Error(`Codemation Document Scanner: no binary attachment at key "${binaryField}".`);
|
|
18080
|
+
const body = await ctx.binary.getBytes(attachment, config.maxBytes);
|
|
18081
|
+
const contentType = config.contentType ?? attachment.mimeType ?? "application/octet-stream";
|
|
18082
|
+
const analyzerType = config.analyzerType ?? "auto";
|
|
18083
|
+
const confidenceSuffix = config.includeConfidence ?? false ? "&confidence=true" : "";
|
|
18084
|
+
const url = `${gatewayUrl}/analyze?type=${encodeURIComponent(analyzerType)}${confidenceSuffix}`;
|
|
18085
|
+
const response = await managedHmacFetchFactory(workspaceId, pairingSecret, { signBody: false })(url, {
|
|
18086
|
+
method: "POST",
|
|
18087
|
+
body: body.buffer,
|
|
18088
|
+
headers: {
|
|
18089
|
+
"Content-Type": contentType,
|
|
18090
|
+
"Content-Length": String(body.byteLength),
|
|
18091
|
+
"X-Codemation-Caller": "workflow-node"
|
|
18092
|
+
}
|
|
18093
|
+
});
|
|
18094
|
+
if (!response.ok) {
|
|
18095
|
+
const text$1 = await response.text().catch(() => "(unreadable)");
|
|
18096
|
+
throw new Error(`Codemation Document Scanner: service responded ${response.status} ${response.statusText} — ${text$1}`);
|
|
18097
|
+
}
|
|
18098
|
+
return await response.json();
|
|
18099
|
+
}
|
|
18100
|
+
});
|
|
18101
|
+
|
|
18011
18102
|
//#endregion
|
|
18012
18103
|
//#region ../host/src/presentation/config/CodemationAuthoring.types.ts
|
|
18013
18104
|
var CodemationAuthoringConfigFactory = class {
|