slackmark 0.6.0 → 0.6.2
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/dist/adapters/block-to-plain-text.d.ts +24 -0
- package/dist/adapters/block-to-plain-text.d.ts.map +1 -0
- package/dist/adapters/blockquote-adapter.d.ts.map +1 -1
- package/dist/adapters/inline.d.ts.map +1 -1
- package/dist/adapters/list-adapter.d.ts.map +1 -1
- package/dist/adapters/phrasing-to-markdown.d.ts +15 -0
- package/dist/adapters/phrasing-to-markdown.d.ts.map +1 -0
- package/dist/adapters/table-adapter.d.ts.map +1 -1
- package/dist/adapters/task-list-adapter.d.ts +6 -1
- package/dist/adapters/task-list-adapter.d.ts.map +1 -1
- package/dist/assemble/text-fallback.d.ts.map +1 -1
- package/dist/constants.d.ts +8 -0
- package/dist/constants.d.ts.map +1 -1
- package/dist/converter/slackmark-converter.d.ts.map +1 -1
- package/dist/index.js +453 -47
- package/dist/index.js.map +1 -1
- package/dist/renderers.d.ts +1 -0
- package/dist/renderers.d.ts.map +1 -1
- package/dist/renderers.js +61 -50
- package/dist/renderers.js.map +1 -1
- package/dist/slack.d.ts +1 -0
- package/dist/slack.d.ts.map +1 -1
- package/dist/slack.js +32 -22
- package/dist/slack.js.map +1 -1
- package/dist/validate/validate-blocks.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/renderers.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* First-party hosted image renderers. None are enabled by default.
|
|
3
3
|
*/
|
|
4
|
+
export { isConfigurationError, isOperationError } from "./errors.js";
|
|
4
5
|
export { KrokiRenderer, KROKI_DIAGRAM_TYPES } from "./renderers/kroki-renderer.js";
|
|
5
6
|
export type { KrokiRendererOptions } from "./renderers/kroki-renderer.js";
|
|
6
7
|
export { MermaidInkRenderer } from "./renderers/mermaid-ink-renderer.js";
|
package/dist/renderers.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"renderers.d.ts","sourceRoot":"","sources":["../src/renderers.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,aAAa,EAAE,mBAAmB,EAAE,MAAM,+BAA+B,CAAC;AACnF,YAAY,EAAE,oBAAoB,EAAE,MAAM,+BAA+B,CAAC;AAE1E,OAAO,EAAE,kBAAkB,EAAE,MAAM,qCAAqC,CAAC;AACzE,YAAY,EACV,yBAAyB,EACzB,eAAe,GAChB,MAAM,qCAAqC,CAAC;AAE7C,OAAO,EAAE,gBAAgB,EAAE,MAAM,kCAAkC,CAAC;AACpE,YAAY,EAAE,uBAAuB,EAAE,MAAM,kCAAkC,CAAC;AAEhF,OAAO,EAAE,kBAAkB,EAAE,MAAM,oCAAoC,CAAC;AACxE,YAAY,EAAE,yBAAyB,EAAE,MAAM,oCAAoC,CAAC"}
|
|
1
|
+
{"version":3,"file":"renderers.d.ts","sourceRoot":"","sources":["../src/renderers.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,oBAAoB,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAErE,OAAO,EAAE,aAAa,EAAE,mBAAmB,EAAE,MAAM,+BAA+B,CAAC;AACnF,YAAY,EAAE,oBAAoB,EAAE,MAAM,+BAA+B,CAAC;AAE1E,OAAO,EAAE,kBAAkB,EAAE,MAAM,qCAAqC,CAAC;AACzE,YAAY,EACV,yBAAyB,EACzB,eAAe,GAChB,MAAM,qCAAqC,CAAC;AAE7C,OAAO,EAAE,gBAAgB,EAAE,MAAM,kCAAkC,CAAC;AACpE,YAAY,EAAE,uBAAuB,EAAE,MAAM,kCAAkC,CAAC;AAEhF,OAAO,EAAE,kBAAkB,EAAE,MAAM,oCAAoC,CAAC;AACxE,YAAY,EAAE,yBAAyB,EAAE,MAAM,oCAAoC,CAAC"}
|
package/dist/renderers.js
CHANGED
|
@@ -1,52 +1,3 @@
|
|
|
1
|
-
//#endregion
|
|
2
|
-
//#region src/renderers/encoding.ts
|
|
3
|
-
const BASE64URL_ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
|
|
4
|
-
/**
|
|
5
|
-
* Kroki and mermaid.ink both accept zlib-deflated, unpadded base64url payloads.
|
|
6
|
-
*/
|
|
7
|
-
async function deflateBase64Url(value) {
|
|
8
|
-
const stream = new CompressionStream("deflate");
|
|
9
|
-
const compressed = readAll(stream.readable);
|
|
10
|
-
const writer = stream.writable.getWriter();
|
|
11
|
-
await writer.write(new TextEncoder().encode(value));
|
|
12
|
-
await writer.close();
|
|
13
|
-
writer.releaseLock();
|
|
14
|
-
return encodeBase64Url(await compressed);
|
|
15
|
-
}
|
|
16
|
-
async function readAll(stream) {
|
|
17
|
-
const reader = stream.getReader();
|
|
18
|
-
const chunks = [];
|
|
19
|
-
let length = 0;
|
|
20
|
-
while (true) {
|
|
21
|
-
const result = await reader.read();
|
|
22
|
-
if (result.done) break;
|
|
23
|
-
if (result.value !== void 0) {
|
|
24
|
-
chunks.push(result.value);
|
|
25
|
-
length += result.value.byteLength;
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
reader.releaseLock();
|
|
29
|
-
const output = new Uint8Array(length);
|
|
30
|
-
let offset = 0;
|
|
31
|
-
for (const chunk of chunks) {
|
|
32
|
-
output.set(chunk, offset);
|
|
33
|
-
offset += chunk.byteLength;
|
|
34
|
-
}
|
|
35
|
-
return output;
|
|
36
|
-
}
|
|
37
|
-
function encodeBase64Url(bytes) {
|
|
38
|
-
const output = [];
|
|
39
|
-
for (let index = 0; index < bytes.length; index += 3) {
|
|
40
|
-
const first = bytes[index] ?? 0;
|
|
41
|
-
const second = bytes[index + 1];
|
|
42
|
-
const third = bytes[index + 2];
|
|
43
|
-
output.push(BASE64URL_ALPHABET[first >> 2] ?? "", BASE64URL_ALPHABET[(first & 3) << 4 | (second ?? 0) >> 4] ?? "");
|
|
44
|
-
if (second !== void 0) output.push(BASE64URL_ALPHABET[(second & 15) << 2 | (third ?? 0) >> 6] ?? "");
|
|
45
|
-
if (third !== void 0) output.push(BASE64URL_ALPHABET[third & 63] ?? "");
|
|
46
|
-
}
|
|
47
|
-
return output.join("");
|
|
48
|
-
}
|
|
49
|
-
//#endregion
|
|
50
1
|
//#region src/errors.ts
|
|
51
2
|
const CONFIGURATION_ERROR_BRAND = Symbol.for("slackmark.error.configuration");
|
|
52
3
|
const OPERATION_ERROR_BRAND = Symbol.for("slackmark.error.operation");
|
|
@@ -123,10 +74,70 @@ var ConfigurationError = class extends Error {
|
|
|
123
74
|
function isConfigurationError(value) {
|
|
124
75
|
return hasErrorBrand(value, CONFIGURATION_ERROR_BRAND);
|
|
125
76
|
}
|
|
77
|
+
/**
|
|
78
|
+
* Identifies an {@link OperationError} — abort, deadline, or shutdown — from any entry of
|
|
79
|
+
* this package, including its subclasses.
|
|
80
|
+
*
|
|
81
|
+
* Use this instead of `instanceof` when the error may have been thrown by a different
|
|
82
|
+
* entry — for example an abort raised inside `FetchSlackUploader` from `slackmark/slack`
|
|
83
|
+
* caught by code that imported the class from `slackmark`. Narrow further with `code`
|
|
84
|
+
* against {@link OperationErrorCode} rather than testing a subclass with `instanceof`.
|
|
85
|
+
*/
|
|
86
|
+
function isOperationError(value) {
|
|
87
|
+
return hasErrorBrand(value, OPERATION_ERROR_BRAND);
|
|
88
|
+
}
|
|
126
89
|
function freezeReceipts(receipts) {
|
|
127
90
|
return Object.freeze(receipts.map((receipt) => Object.freeze({ ...receipt })));
|
|
128
91
|
}
|
|
129
92
|
//#endregion
|
|
93
|
+
//#region src/renderers/encoding.ts
|
|
94
|
+
const BASE64URL_ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
|
|
95
|
+
/**
|
|
96
|
+
* Kroki and mermaid.ink both accept zlib-deflated, unpadded base64url payloads.
|
|
97
|
+
*/
|
|
98
|
+
async function deflateBase64Url(value) {
|
|
99
|
+
const stream = new CompressionStream("deflate");
|
|
100
|
+
const compressed = readAll(stream.readable);
|
|
101
|
+
const writer = stream.writable.getWriter();
|
|
102
|
+
await writer.write(new TextEncoder().encode(value));
|
|
103
|
+
await writer.close();
|
|
104
|
+
writer.releaseLock();
|
|
105
|
+
return encodeBase64Url(await compressed);
|
|
106
|
+
}
|
|
107
|
+
async function readAll(stream) {
|
|
108
|
+
const reader = stream.getReader();
|
|
109
|
+
const chunks = [];
|
|
110
|
+
let length = 0;
|
|
111
|
+
while (true) {
|
|
112
|
+
const result = await reader.read();
|
|
113
|
+
if (result.done) break;
|
|
114
|
+
if (result.value !== void 0) {
|
|
115
|
+
chunks.push(result.value);
|
|
116
|
+
length += result.value.byteLength;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
reader.releaseLock();
|
|
120
|
+
const output = new Uint8Array(length);
|
|
121
|
+
let offset = 0;
|
|
122
|
+
for (const chunk of chunks) {
|
|
123
|
+
output.set(chunk, offset);
|
|
124
|
+
offset += chunk.byteLength;
|
|
125
|
+
}
|
|
126
|
+
return output;
|
|
127
|
+
}
|
|
128
|
+
function encodeBase64Url(bytes) {
|
|
129
|
+
const output = [];
|
|
130
|
+
for (let index = 0; index < bytes.length; index += 3) {
|
|
131
|
+
const first = bytes[index] ?? 0;
|
|
132
|
+
const second = bytes[index + 1];
|
|
133
|
+
const third = bytes[index + 2];
|
|
134
|
+
output.push(BASE64URL_ALPHABET[first >> 2] ?? "", BASE64URL_ALPHABET[(first & 3) << 4 | (second ?? 0) >> 4] ?? "");
|
|
135
|
+
if (second !== void 0) output.push(BASE64URL_ALPHABET[(second & 15) << 2 | (third ?? 0) >> 6] ?? "");
|
|
136
|
+
if (third !== void 0) output.push(BASE64URL_ALPHABET[third & 63] ?? "");
|
|
137
|
+
}
|
|
138
|
+
return output.join("");
|
|
139
|
+
}
|
|
140
|
+
//#endregion
|
|
130
141
|
//#region src/renderers/renderer-options.ts
|
|
131
142
|
function snapshotRendererOptions(options, allowed, label) {
|
|
132
143
|
if (typeof options !== "object" || options === null || Array.isArray(options)) throw invalidRendererOptions(`${label} options must be a plain object`);
|
|
@@ -417,6 +428,6 @@ var QuickChartRenderer = class {
|
|
|
417
428
|
}
|
|
418
429
|
};
|
|
419
430
|
//#endregion
|
|
420
|
-
export { CodeCogsRenderer, KROKI_DIAGRAM_TYPES, KrokiRenderer, MermaidInkRenderer, QuickChartRenderer };
|
|
431
|
+
export { CodeCogsRenderer, KROKI_DIAGRAM_TYPES, KrokiRenderer, MermaidInkRenderer, QuickChartRenderer, isConfigurationError, isOperationError };
|
|
421
432
|
|
|
422
433
|
//# sourceMappingURL=renderers.js.map
|
package/dist/renderers.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"renderers.js","names":[],"sources":["../src/constants.ts","../src/renderers/encoding.ts","../src/errors.ts","../src/renderers/renderer-options.ts","../src/renderers/url-utils.ts","../src/renderers/kroki-renderer.ts","../src/renderers/mermaid-ink-renderer.ts","../src/renderers/codecogs-renderer.ts","../src/renderers/quickchart-renderer.ts"],"sourcesContent":["/**\n * Named Slack Block Kit limits.\n * Sources: https://docs.slack.dev/block-kit and block reference pages (July 2026 research).\n */\n\n/** https://docs.slack.dev/block-kit */\nexport const MAX_BLOCKS_PER_MESSAGE = 50;\n\n/** https://docs.slack.dev/reference/block-kit/blocks/section-block */\nexport const SECTION_TEXT_MAX_CHARS = 3000;\n\n/** https://docs.slack.dev/reference/block-kit/blocks/header-block */\nexport const HEADER_TEXT_MAX_CHARS = 150;\n\n/** https://docs.slack.dev/reference/block-kit/blocks/header-block */\nexport const HEADER_LEVEL_MAX = 4;\n\n/** https://docs.slack.dev/reference/block-kit/blocks/image-block */\nexport const IMAGE_URL_MAX_CHARS = 3000;\n\n/** https://docs.slack.dev/reference/block-kit/blocks/image-block */\nexport const IMAGE_ALT_MAX_CHARS = 2000;\n\n/** slackmark renderer safety limit for retained/uploaded image bytes. */\nexport const RENDERED_IMAGE_MAX_BYTES: number = 10 * 1024 * 1024;\n\n/** Portable filename component limit used by renderer output validation. */\nexport const RENDERED_IMAGE_FILENAME_MAX_CHARS = 255;\n\n/** Defensive upper bound for Slack file IDs returned by uploaders. */\nexport const SLACK_FILE_ID_MAX_CHARS = 255;\n\n/** https://docs.slack.dev/reference/block-kit/blocks/context-block */\nexport const CONTEXT_ELEMENTS_MAX = 10;\n\n/** https://docs.slack.dev/reference/block-kit/blocks/markdown-block */\nexport const MARKDOWN_CUMULATIVE_MAX_CHARS = 12_000;\n\n/** https://docs.slack.dev/reference/block-kit/blocks/table-block */\nexport const TABLE_MAX_ROWS = 100;\n\n/** https://docs.slack.dev/reference/block-kit/blocks/table-block */\nexport const TABLE_MAX_COLS = 20;\n\n/** https://docs.slack.dev/reference/block-kit/blocks/table-block */\nexport const TABLE_CELL_CHARS_MAX = 10_000;\n\n/** Spec decision: prefer `table` up to this many rows (incl. header). */\nexport const TABLE_PREFERRED_MAX_ROWS = 50;\n\n/** https://docs.slack.dev/reference/block-kit/blocks/data-table-block */\nexport const DATA_TABLE_MAX_DATA_ROWS = 200;\n\n/** https://docs.slack.dev/reference/block-kit/blocks/data-table-block */\nexport const DATA_TABLE_CELL_CHARS_MAX = 20_000;\n\n/** https://docs.slack.dev/reference/block-kit/blocks/data-visualization-block */\nexport const CHART_TITLE_MAX_CHARS = 50;\n\n/** https://docs.slack.dev/reference/block-kit/blocks/data-visualization-block */\nexport const CHART_LABEL_MAX_CHARS = 20;\n\n/** https://docs.slack.dev/reference/block-kit/blocks/data-visualization-block */\nexport const CHART_SEGMENTS_MAX = 12;\n\n/** https://docs.slack.dev/reference/block-kit/blocks/data-visualization-block */\nexport const CHART_SERIES_MAX = 12;\n\n/** https://docs.slack.dev/reference/block-kit/blocks/data-visualization-block */\nexport const CHART_POINTS_MAX = 20;\n\n/**\n * Community-reported cap (ENG-4936); not in official docs.\n * Enforced defensively with degradation.\n */\nexport const DATA_VISUALIZATION_MAX_PER_MESSAGE = 2;\n\n/** https://docs.slack.dev/reference/methods/chat.postMessage#truncating */\nexport const MESSAGE_TEXT_SAFETY_MAX_CHARS = 40_000;\n\n/** Undocumented; defensive clamp for rich_text_list.indent. */\nexport const RICH_TEXT_LIST_INDENT_MAX = 6;\n\n/** https://docs.slack.dev/reference/block-kit/blocks/container-block */\nexport const CONTAINER_CHILDREN_MAX = 10;\n\n/** https://docs.slack.dev/reference/block-kit/blocks/container-block */\nexport const CONTAINER_TITLE_MAX_CHARS = 150;\n\n/** Cell wrap heuristic for table column_settings.is_wrapped. */\nexport const TABLE_CELL_WRAP_THRESHOLD = 40;\n\nexport const ELLIPSIS = \"…\";\n","const BASE64URL_ALPHABET = \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_\";\n\n/**\n * Kroki and mermaid.ink both accept zlib-deflated, unpadded base64url payloads.\n */\nexport async function deflateBase64Url(value: string): Promise<string> {\n const stream = new CompressionStream(\"deflate\");\n const compressed = readAll(stream.readable);\n const writer = stream.writable.getWriter();\n\n await writer.write(new TextEncoder().encode(value));\n await writer.close();\n writer.releaseLock();\n\n return encodeBase64Url(await compressed);\n}\n\nasync function readAll(stream: GfmReadableStream<Uint8Array>): Promise<Uint8Array> {\n const reader = stream.getReader();\n const chunks: Uint8Array[] = [];\n let length = 0;\n\n while (true) {\n const result = await reader.read();\n if (result.done) {\n break;\n }\n if (result.value !== undefined) {\n chunks.push(result.value);\n length += result.value.byteLength;\n }\n }\n reader.releaseLock();\n\n const output = new Uint8Array(length);\n let offset = 0;\n for (const chunk of chunks) {\n output.set(chunk, offset);\n offset += chunk.byteLength;\n }\n return output;\n}\n\nfunction encodeBase64Url(bytes: Uint8Array): string {\n const output: string[] = [];\n for (let index = 0; index < bytes.length; index += 3) {\n const first = bytes[index] ?? 0;\n const second = bytes[index + 1];\n const third = bytes[index + 2];\n\n output.push(\n BASE64URL_ALPHABET[first >> 2] ?? \"\",\n BASE64URL_ALPHABET[((first & 0b11) << 4) | ((second ?? 0) >> 4)] ?? \"\",\n );\n if (second !== undefined) {\n output.push(BASE64URL_ALPHABET[((second & 0b1111) << 2) | ((third ?? 0) >> 6)] ?? \"\");\n }\n if (third !== undefined) {\n output.push(BASE64URL_ALPHABET[third & 0b11_1111] ?? \"\");\n }\n }\n return output.join(\"\");\n}\n","import type { UploadReceipt } from \"./receipts.js\";\n\n/**\n * Registry-keyed markers, not module-local symbols.\n *\n * Each published entry (`slackmark`, `slackmark/renderers`, `slackmark/slack`) is bundled\n * without code splitting, so every entry carries its own copy of these classes and\n * `instanceof` is false for an error that crosses an entry boundary. `Symbol.for` keys are\n * shared by every copy, which is what makes the exported guards below reliable. Prefer\n * those guards to `instanceof` for any error that can cross an entry.\n */\nconst RECEIPT_SNAPSHOT_LOCK = Symbol.for(\"slackmark.receiptSnapshotLock\");\nconst OPERATION_ERROR_CARRIER = Symbol.for(\"slackmark.operationErrorCarrier\");\nconst CONFIGURATION_ERROR_BRAND = Symbol.for(\"slackmark.error.configuration\");\nconst OPERATION_ERROR_BRAND = Symbol.for(\"slackmark.error.operation\");\n\n/**\n * Marks a class prototype so instances from any bundled copy answer to one identity.\n * Subclasses inherit the brand, and instances carry no extra own property.\n */\nexport function brandErrorPrototype(prototype: object, brand: symbol): void {\n Object.defineProperty(prototype, brand, {\n configurable: false,\n enumerable: false,\n value: true,\n writable: false,\n });\n}\n\n/**\n * Reads a brand without trusting the value: a hostile getter must not escape a guard.\n */\nexport function hasErrorBrand(value: unknown, brand: symbol): boolean {\n if (typeof value !== \"object\" || value === null) {\n return false;\n }\n try {\n return Reflect.get(value, brand) === true;\n } catch {\n return false;\n }\n}\n\n/**\n * Programmer/configuration error thrown only from the composition root.\n */\nexport interface ConfigurationErrorOptions {\n readonly code?: string | undefined;\n readonly stage?: string | undefined;\n readonly receipts?: ReadonlyArray<UploadReceipt> | undefined;\n readonly settledReceipts?: Promise<ReadonlyArray<UploadReceipt>> | undefined;\n readonly cause?: unknown;\n}\n\nexport class ConfigurationError extends Error {\n static {\n brandErrorPrototype(this.prototype, CONFIGURATION_ERROR_BRAND);\n }\n\n override readonly name: string;\n readonly code: string;\n readonly stage: string | undefined;\n readonly retryable: false;\n readonly receipts: ReadonlyArray<UploadReceipt>;\n readonly settledReceipts: Promise<ReadonlyArray<UploadReceipt>>;\n\n constructor(message: string, options: ConfigurationErrorOptions = {}) {\n super(message, options?.cause !== undefined ? { cause: options.cause } : undefined);\n this.name = \"ConfigurationError\";\n this.code = options.code ?? \"invalid_configuration\";\n this.stage = options.stage;\n this.retryable = false;\n this.receipts = freezeReceipts(options.receipts ?? []);\n this.settledReceipts = options.settledReceipts ?? Promise.resolve(this.receipts);\n }\n}\n\nexport const OperationErrorCode = {\n Aborted: \"operation_aborted\",\n DeadlineExceeded: \"operation_deadline_exceeded\",\n Shutdown: \"operation_shutdown\",\n} as const;\n\nexport type OperationErrorCode = (typeof OperationErrorCode)[keyof typeof OperationErrorCode];\n\nexport interface OperationErrorOptions {\n readonly receipts?: ReadonlyArray<UploadReceipt> | undefined;\n readonly settledReceipts?: Promise<ReadonlyArray<UploadReceipt>> | undefined;\n readonly cause?: unknown;\n}\n\n/**\n * Operational control-flow error. These failures are never degradations.\n */\nexport class OperationError extends Error {\n static {\n brandErrorPrototype(this.prototype, OPERATION_ERROR_BRAND);\n }\n\n override readonly name: string;\n readonly code: OperationErrorCode;\n readonly stage: string;\n readonly retryable: boolean;\n readonly receipts: ReadonlyArray<UploadReceipt>;\n readonly settledReceipts: Promise<ReadonlyArray<UploadReceipt>>;\n\n constructor(\n message: string,\n code: OperationErrorCode,\n stage: string,\n retryable: boolean,\n options: OperationErrorOptions = {},\n ) {\n super(message, options.cause !== undefined ? { cause: options.cause } : undefined);\n this.name = \"OperationError\";\n this.code = code;\n this.stage = stage;\n this.retryable = retryable;\n this.receipts = freezeReceipts(options.receipts ?? []);\n this.settledReceipts = options.settledReceipts ?? Promise.resolve(this.receipts);\n }\n}\n\nexport class OperationAbortedError extends OperationError {\n override readonly name: string;\n\n constructor(stage: string, options: OperationErrorOptions = {}) {\n super(\"Operation aborted by caller\", OperationErrorCode.Aborted, stage, false, options);\n this.name = \"OperationAbortedError\";\n }\n}\n\nexport class OperationDeadlineExceededError extends OperationError {\n override readonly name: string;\n\n constructor(stage: string, options: OperationErrorOptions = {}) {\n super(\"Operation deadline exceeded\", OperationErrorCode.DeadlineExceeded, stage, true, options);\n this.name = \"OperationDeadlineExceededError\";\n }\n}\n\nexport class OperationShutdownError extends OperationError {\n override readonly name: string;\n\n constructor(stage: string, options: OperationErrorOptions = {}) {\n super(\"Operation interrupted by shutdown\", OperationErrorCode.Shutdown, stage, true, options);\n this.name = \"OperationShutdownError\";\n }\n}\n\n/**\n * Identifies a {@link ConfigurationError} from any entry of this package.\n *\n * Use this instead of `instanceof` when the error may have been thrown by a different\n * entry — for example a `ConfigurationError` from `slackmark/renderers` caught by code\n * that imported the class from `slackmark`.\n */\nexport function isConfigurationError(value: unknown): value is ConfigurationError {\n return hasErrorBrand(value, CONFIGURATION_ERROR_BRAND);\n}\n\n/**\n * Identifies an {@link OperationError} — abort, deadline, or shutdown — from any entry of\n * this package, including its subclasses.\n *\n * Use this instead of `instanceof` when the error may have been thrown by a different\n * entry — for example an abort raised inside `FetchSlackUploader` from `slackmark/slack`\n * caught by code that imported the class from `slackmark`. Narrow further with `code`\n * against {@link OperationErrorCode} rather than testing a subclass with `instanceof`.\n */\nexport function isOperationError(value: unknown): value is OperationError {\n return hasErrorBrand(value, OPERATION_ERROR_BRAND);\n}\n\nexport function cloneOperationError(error: OperationError, fallbackStage: string): OperationError {\n const stage = error.stage.length > 0 ? error.stage : fallbackStage;\n const options: OperationErrorOptions = {\n cause: error,\n receipts: error.receipts,\n settledReceipts: error.settledReceipts,\n };\n let cloned: OperationError;\n switch (error.code) {\n case OperationErrorCode.Aborted:\n cloned = new OperationAbortedError(stage, options);\n break;\n case OperationErrorCode.DeadlineExceeded:\n cloned = new OperationDeadlineExceededError(stage, options);\n break;\n case OperationErrorCode.Shutdown:\n cloned = new OperationShutdownError(stage, options);\n break;\n }\n Reflect.defineProperty(cloned, OPERATION_ERROR_CARRIER, {\n configurable: false,\n enumerable: false,\n value: true,\n writable: false,\n });\n return cloned;\n}\n\nexport function isOperationErrorCarrier(error: OperationError): boolean {\n return Reflect.get(error, OPERATION_ERROR_CARRIER) === true;\n}\n\nexport function cloneConfigurationError(error: ConfigurationError): ConfigurationError {\n return new ConfigurationError(error.message, {\n code: error.code,\n stage: error.stage,\n cause: error,\n receipts: error.receipts,\n settledReceipts: error.settledReceipts,\n });\n}\n\nexport function attachReceipts(\n error: unknown,\n receipts: ReadonlyArray<UploadReceipt>,\n settledReceipts?: Promise<ReadonlyArray<UploadReceipt>>,\n): unknown {\n if (!(error instanceof Error)) {\n return error;\n }\n try {\n if (Reflect.get(error, RECEIPT_SNAPSHOT_LOCK) === true) {\n return error;\n }\n } catch {\n return error;\n }\n let existing: ReadonlyArray<UploadReceipt> = [];\n try {\n const candidate = Reflect.get(error, \"receipts\");\n if (Array.isArray(candidate)) {\n existing = candidate.filter(isUploadReceipt);\n }\n } catch {\n existing = [];\n }\n Reflect.defineProperty(error, \"receipts\", {\n configurable: true,\n enumerable: true,\n value: freezeReceipts(mergeReceipts(existing, receipts)),\n writable: false,\n });\n if (settledReceipts !== undefined) {\n const finalReceipts = freezeSettledReceipts(settledReceipts, receipts);\n Reflect.defineProperty(error, \"settledReceipts\", {\n configurable: true,\n enumerable: true,\n value: finalReceipts,\n writable: false,\n });\n }\n return error;\n}\n\nexport function lockReceiptSnapshot(error: unknown): unknown {\n if (error instanceof Error) {\n Reflect.defineProperty(error, RECEIPT_SNAPSHOT_LOCK, {\n configurable: false,\n enumerable: false,\n value: true,\n writable: false,\n });\n }\n return error;\n}\n\nasync function freezeSettledReceipts(\n settledReceipts: Promise<ReadonlyArray<UploadReceipt>>,\n fallback: ReadonlyArray<UploadReceipt>,\n): Promise<ReadonlyArray<UploadReceipt>> {\n try {\n return freezeReceipts(await settledReceipts);\n } catch {\n return freezeReceipts(fallback);\n }\n}\n\nfunction mergeReceipts(\n existing: ReadonlyArray<UploadReceipt>,\n incoming: ReadonlyArray<UploadReceipt>,\n): ReadonlyArray<UploadReceipt> {\n const existingGroups = groupReceipts(existing);\n const incomingGroups = groupReceipts(incoming);\n const merged: UploadReceipt[] = [...incoming];\n for (const [key, values] of existingGroups) {\n const overlap = incomingGroups.get(key)?.length ?? 0;\n if (values.length > overlap) {\n merged.push(...values.slice(overlap));\n }\n }\n return merged;\n}\n\nfunction groupReceipts(\n receipts: ReadonlyArray<UploadReceipt>,\n): ReadonlyMap<string, ReadonlyArray<UploadReceipt>> {\n const grouped = new Map<string, UploadReceipt[]>();\n for (const receipt of receipts) {\n const key = receiptKey(receipt);\n const values = grouped.get(key);\n if (values === undefined) {\n grouped.set(key, [receipt]);\n } else {\n values.push(receipt);\n }\n }\n return grouped;\n}\n\nfunction receiptKey(receipt: UploadReceipt): string {\n return [\n receipt.provider,\n receipt.phase,\n receipt.fileId ?? \"\",\n String(receipt.shared),\n receipt.processing,\n String(receipt.status ?? \"\"),\n String(receipt.retryAfterMs ?? \"\"),\n receipt.providerCode ?? \"\",\n receipt.retrySafety,\n ].join(\"\\u0000\");\n}\n\nfunction freezeReceipts(receipts: ReadonlyArray<UploadReceipt>): ReadonlyArray<UploadReceipt> {\n return Object.freeze(receipts.map((receipt) => Object.freeze({ ...receipt })));\n}\n\nfunction isUploadReceipt(value: unknown): value is UploadReceipt {\n return typeof value === \"object\" && value !== null && Reflect.get(value, \"kind\") === \"upload\";\n}\n","import { ConfigurationError } from \"../errors.js\";\n\nexport function snapshotRendererOptions<T extends object>(\n options: T,\n allowed: ReadonlyArray<string>,\n label: string,\n): T {\n if (typeof options !== \"object\" || options === null || Array.isArray(options)) {\n throw invalidRendererOptions(`${label} options must be a plain object`);\n }\n let prototype: object | null;\n let keys: ReadonlyArray<string>;\n try {\n prototype = Object.getPrototypeOf(options);\n keys = Object.keys(options);\n } catch (cause) {\n throw invalidRendererOptions(`${label} options could not be inspected`, cause);\n }\n if (prototype !== Object.prototype && prototype !== null) {\n throw invalidRendererOptions(`${label} options must be a plain object`);\n }\n const allowedKeys = new Set(allowed);\n const snapshot: Record<string, unknown> = {};\n for (const key of keys) {\n if (!allowedKeys.has(key)) {\n throw invalidRendererOptions(`Unknown ${label} option: ${key}`);\n }\n try {\n snapshot[key] = Reflect.get(options, key);\n } catch (cause) {\n throw invalidRendererOptions(`${label}.${key} could not be read`, cause);\n }\n }\n return Object.freeze(snapshot) as T;\n}\n\nexport function invalidRendererOptions(message: string, cause?: unknown): ConfigurationError {\n return new ConfigurationError(message, {\n code: \"invalid_renderer_options\",\n stage: \"configuration\",\n cause,\n });\n}\n","import { isConfigurationError } from \"../errors.js\";\nimport { invalidRendererOptions } from \"./renderer-options.js\";\n\nexport function normalizeBaseUrl(baseUrl: string): string {\n if (typeof baseUrl !== \"string\" || baseUrl.length === 0 || baseUrl !== baseUrl.trim()) {\n throw invalidRendererOptions(\"baseUrl must be a nonempty trimmed string\");\n }\n const normalized = baseUrl.replace(/\\/+$/u, \"\");\n try {\n const parsed = new URL(normalized);\n if (parsed.protocol !== \"https:\" || parsed.username.length > 0 || parsed.password.length > 0) {\n throw invalidRendererOptions(\"baseUrl must be credential-free absolute HTTPS\");\n }\n } catch (cause) {\n if (isConfigurationError(cause)) {\n throw cause;\n }\n throw invalidRendererOptions(\"baseUrl must be credential-free absolute HTTPS\", cause);\n }\n return normalized;\n}\n\nexport function normalizeFenceLanguage(lang: string): string {\n return lang.trim().toLowerCase();\n}\n","import { IMAGE_URL_MAX_CHARS } from \"../constants.js\";\nimport type { OperationContext, RenderRequest, UrlImage, UrlImageRenderer } from \"../types.js\";\n\nimport { deflateBase64Url } from \"./encoding.js\";\nimport { invalidRendererOptions, snapshotRendererOptions } from \"./renderer-options.js\";\nimport { normalizeBaseUrl, normalizeFenceLanguage } from \"./url-utils.js\";\n\nconst DEFAULT_KROKI_BASE_URL = \"https://kroki.io\";\n\n/**\n * Fence-language aliases for Kroki's supported diagram types.\n *\n * @see https://docs.kroki.io/kroki/setup/usage/\n */\nexport const KROKI_DIAGRAM_TYPES: Readonly<Record<string, string>> = Object.freeze({\n blockdiag: \"blockdiag\",\n bpmn: \"bpmn\",\n bytefield: \"bytefield\",\n c4: \"c4plantuml\",\n c4plantuml: \"c4plantuml\",\n d2: \"d2\",\n dbml: \"dbml\",\n ditaa: \"ditaa\",\n dot: \"graphviz\",\n erd: \"erd\",\n excalidraw: \"excalidraw\",\n graphviz: \"graphviz\",\n mermaid: \"mermaid\",\n nomnoml: \"nomnoml\",\n pikchr: \"pikchr\",\n plantuml: \"plantuml\",\n puml: \"plantuml\",\n structurizr: \"structurizr\",\n svgbob: \"svgbob\",\n symbolator: \"symbolator\",\n tikz: \"tikz\",\n umlet: \"umlet\",\n vega: \"vega\",\n \"vega-lite\": \"vegalite\",\n vegalite: \"vegalite\",\n wavedrom: \"wavedrom\",\n wireviz: \"wireviz\",\n});\n\nexport interface KrokiRendererOptions {\n readonly baseUrl?: string;\n /**\n * Additional or replacement fence-language aliases, merged over the defaults.\n */\n readonly diagramTypes?: Readonly<Record<string, string>>;\n}\n\n/**\n * Produces durable Kroki GET URLs without performing network I/O.\n */\nexport class KrokiRenderer implements UrlImageRenderer {\n readonly id: string;\n readonly output: \"url\";\n private readonly baseUrl: string;\n private readonly diagramTypes: Readonly<Record<string, string>>;\n\n constructor(options: KrokiRendererOptions = {}) {\n const validated = snapshotRendererOptions(\n options,\n [\"baseUrl\", \"diagramTypes\"],\n \"KrokiRenderer\",\n );\n this.id = \"kroki\";\n this.output = \"url\";\n this.baseUrl = normalizeBaseUrl(\n validated.baseUrl === undefined ? DEFAULT_KROKI_BASE_URL : validated.baseUrl,\n );\n this.diagramTypes = Object.freeze({\n ...KROKI_DIAGRAM_TYPES,\n ...validateDiagramTypes(validated.diagramTypes),\n });\n }\n\n canRender(req: RenderRequest): boolean {\n return this.diagramTypes[normalizeFenceLanguage(req.lang)] !== undefined;\n }\n\n async render(req: RenderRequest, _context: OperationContext): Promise<UrlImage | null> {\n const diagramType = this.diagramTypes[normalizeFenceLanguage(req.lang)];\n if (diagramType === undefined) {\n return null;\n }\n\n const encoded = await deflateBase64Url(req.source);\n const imageUrl = `${this.baseUrl}/${encodeURIComponent(diagramType)}/png/${encoded}`;\n\n // https://docs.slack.dev/reference/block-kit/blocks/image-block\n if (imageUrl.length > IMAGE_URL_MAX_CHARS) {\n return null;\n }\n return {\n kind: \"url\",\n imageUrl,\n altText: req.altText,\n };\n }\n}\n\nfunction validateDiagramTypes(\n value: Readonly<Record<string, string>> | undefined,\n): Readonly<Record<string, string>> {\n if (value === undefined) {\n return {};\n }\n let keys: ReadonlyArray<string>;\n try {\n keys = Object.keys(value);\n } catch (cause) {\n throw invalidRendererOptions(\"KrokiRenderer.diagramTypes could not be inspected\", cause);\n }\n const snapshot = snapshotRendererOptions(value, keys, \"KrokiRenderer.diagramTypes\");\n for (const [language, diagramType] of Object.entries(snapshot)) {\n if (language.length === 0 || typeof diagramType !== \"string\" || diagramType.length === 0) {\n throw invalidRendererOptions(\"KrokiRenderer.diagramTypes values must be nonempty strings\");\n }\n }\n return snapshot;\n}\n","import { IMAGE_URL_MAX_CHARS } from \"../constants.js\";\nimport type { OperationContext, RenderRequest, UrlImage, UrlImageRenderer } from \"../types.js\";\n\nimport { deflateBase64Url } from \"./encoding.js\";\nimport { invalidRendererOptions, snapshotRendererOptions } from \"./renderer-options.js\";\nimport { normalizeBaseUrl, normalizeFenceLanguage } from \"./url-utils.js\";\n\nconst DEFAULT_MERMAID_INK_BASE_URL = \"https://mermaid.ink\";\nconst DEFAULT_MERMAID_INK_BACKGROUND = \"!white\";\n\nexport type MermaidInkTheme = \"default\" | \"neutral\" | \"dark\" | \"forest\";\n\nexport interface MermaidInkRendererOptions {\n readonly baseUrl?: string;\n readonly theme?: MermaidInkTheme;\n /**\n * mermaid.ink color value, such as `!white` or `FF0000`.\n */\n readonly bgColor?: string;\n}\n\ninterface MermaidInkState {\n readonly code: string;\n readonly mermaid: {\n readonly theme: MermaidInkTheme;\n };\n}\n\n/**\n * Produces mermaid.ink pako-state PNG URLs without performing network I/O.\n */\nexport class MermaidInkRenderer implements UrlImageRenderer {\n readonly id: string;\n readonly output: \"url\";\n private readonly baseUrl: string;\n private readonly theme: MermaidInkTheme;\n private readonly bgColor: string;\n\n constructor(options: MermaidInkRendererOptions = {}) {\n const validated = snapshotRendererOptions(\n options,\n [\"baseUrl\", \"theme\", \"bgColor\"],\n \"MermaidInkRenderer\",\n );\n this.id = \"mermaid-ink\";\n this.output = \"url\";\n this.baseUrl = normalizeBaseUrl(\n validated.baseUrl === undefined ? DEFAULT_MERMAID_INK_BASE_URL : validated.baseUrl,\n );\n this.theme = validated.theme === undefined ? \"default\" : validated.theme;\n this.bgColor =\n validated.bgColor === undefined ? DEFAULT_MERMAID_INK_BACKGROUND : validated.bgColor;\n if (\n ![\"default\", \"neutral\", \"dark\", \"forest\"].includes(this.theme) ||\n typeof this.bgColor !== \"string\" ||\n this.bgColor.length === 0\n ) {\n throw invalidRendererOptions(\"MermaidInkRenderer theme or bgColor is invalid\");\n }\n }\n\n canRender(req: RenderRequest): boolean {\n return normalizeFenceLanguage(req.lang) === \"mermaid\";\n }\n\n async render(req: RenderRequest, _context: OperationContext): Promise<UrlImage | null> {\n if (!this.canRender(req)) {\n return null;\n }\n\n const state: MermaidInkState = {\n code: req.source,\n mermaid: { theme: this.theme },\n };\n const encoded = await deflateBase64Url(JSON.stringify(state));\n const imageUrl =\n `${this.baseUrl}/img/pako:${encoded}` +\n `?type=png&bgColor=${encodeURIComponent(this.bgColor)}`;\n\n // https://docs.slack.dev/reference/block-kit/blocks/image-block\n if (imageUrl.length > IMAGE_URL_MAX_CHARS) {\n return null;\n }\n return {\n kind: \"url\",\n imageUrl,\n altText: req.altText,\n };\n }\n}\n","import { IMAGE_URL_MAX_CHARS } from \"../constants.js\";\nimport type { OperationContext, RenderRequest, UrlImage, UrlImageRenderer } from \"../types.js\";\n\nimport { invalidRendererOptions, snapshotRendererOptions } from \"./renderer-options.js\";\nimport { normalizeBaseUrl, normalizeFenceLanguage } from \"./url-utils.js\";\n\nconst DEFAULT_CODECOGS_BASE_URL = \"https://latex.codecogs.com\";\nconst DEFAULT_CODECOGS_DPI = 200;\nconst MATH_FENCE_LANGUAGES: ReadonlySet<string> = new Set([\"katex\", \"latex\", \"math\", \"tex\"]);\n\nexport interface CodeCogsRendererOptions {\n readonly baseUrl?: string;\n readonly dpi?: number;\n}\n\n/**\n * Produces deterministic CodeCogs `png.image` URLs for display math.\n */\nexport class CodeCogsRenderer implements UrlImageRenderer {\n readonly id: string;\n readonly output: \"url\";\n private readonly baseUrl: string;\n private readonly dpi: number;\n\n constructor(options: CodeCogsRendererOptions = {}) {\n const validated = snapshotRendererOptions(options, [\"baseUrl\", \"dpi\"], \"CodeCogsRenderer\");\n this.id = \"codecogs\";\n this.output = \"url\";\n this.baseUrl = normalizeBaseUrl(\n validated.baseUrl === undefined ? DEFAULT_CODECOGS_BASE_URL : validated.baseUrl,\n );\n this.dpi = validated.dpi === undefined ? DEFAULT_CODECOGS_DPI : validated.dpi;\n\n if (!Number.isInteger(this.dpi) || this.dpi <= 0) {\n throw invalidRendererOptions(\"dpi must be a positive integer\");\n }\n }\n\n canRender(req: RenderRequest): boolean {\n return MATH_FENCE_LANGUAGES.has(normalizeFenceLanguage(req.lang));\n }\n\n async render(req: RenderRequest, _context: OperationContext): Promise<UrlImage | null> {\n if (!this.canRender(req)) {\n return null;\n }\n\n const formula = `\\\\dpi{${String(this.dpi)}} ${req.source}`;\n const imageUrl = `${this.baseUrl}/png.image?${encodeURIComponent(formula)}`;\n\n // https://docs.slack.dev/reference/block-kit/blocks/image-block\n if (imageUrl.length > IMAGE_URL_MAX_CHARS) {\n return null;\n }\n return {\n kind: \"url\",\n imageUrl,\n altText: req.altText,\n };\n }\n}\n","import { IMAGE_URL_MAX_CHARS } from \"../constants.js\";\nimport type { OperationContext, RenderRequest, UrlImage, UrlImageRenderer } from \"../types.js\";\n\nimport { invalidRendererOptions, snapshotRendererOptions } from \"./renderer-options.js\";\nimport { normalizeBaseUrl, normalizeFenceLanguage } from \"./url-utils.js\";\n\nconst DEFAULT_QUICKCHART_BASE_URL = \"https://quickchart.io\";\nconst DEFAULT_QUICKCHART_WIDTH = 500;\nconst DEFAULT_QUICKCHART_HEIGHT = 300;\nconst DEFAULT_QUICKCHART_BACKGROUND = \"white\";\nconst DEFAULT_QUICKCHART_DEVICE_PIXEL_RATIO = 2;\nconst CHART_FENCE_LANGUAGES: ReadonlySet<string> = new Set([\n \"chart\",\n \"chart.js\",\n \"chartjs\",\n \"quickchart\",\n]);\n\nexport interface QuickChartRendererOptions {\n readonly baseUrl?: string;\n readonly width?: number;\n readonly height?: number;\n readonly backgroundColor?: string;\n readonly devicePixelRatio?: number;\n}\n\n/**\n * Produces full, durable QuickChart GET URLs. It never uses the expiring\n * `/chart/create` short-URL API.\n */\nexport class QuickChartRenderer implements UrlImageRenderer {\n readonly id: string;\n readonly output: \"url\";\n private readonly baseUrl: string;\n private readonly width: number;\n private readonly height: number;\n private readonly backgroundColor: string;\n private readonly devicePixelRatio: number;\n\n constructor(options: QuickChartRendererOptions = {}) {\n const validated = snapshotRendererOptions(\n options,\n [\"baseUrl\", \"width\", \"height\", \"backgroundColor\", \"devicePixelRatio\"],\n \"QuickChartRenderer\",\n );\n this.id = \"quickchart\";\n this.output = \"url\";\n this.baseUrl = normalizeBaseUrl(\n validated.baseUrl === undefined ? DEFAULT_QUICKCHART_BASE_URL : validated.baseUrl,\n );\n this.width = validated.width === undefined ? DEFAULT_QUICKCHART_WIDTH : validated.width;\n this.height = validated.height === undefined ? DEFAULT_QUICKCHART_HEIGHT : validated.height;\n this.backgroundColor =\n validated.backgroundColor === undefined\n ? DEFAULT_QUICKCHART_BACKGROUND\n : validated.backgroundColor;\n this.devicePixelRatio =\n validated.devicePixelRatio === undefined\n ? DEFAULT_QUICKCHART_DEVICE_PIXEL_RATIO\n : validated.devicePixelRatio;\n\n if (!Number.isInteger(this.width) || this.width <= 0) {\n throw invalidRendererOptions(\"width must be a positive integer\");\n }\n if (!Number.isInteger(this.height) || this.height <= 0) {\n throw invalidRendererOptions(\"height must be a positive integer\");\n }\n if (!Number.isFinite(this.devicePixelRatio) || this.devicePixelRatio <= 0) {\n throw invalidRendererOptions(\"devicePixelRatio must be positive\");\n }\n if (typeof this.backgroundColor !== \"string\" || this.backgroundColor.length === 0) {\n throw invalidRendererOptions(\"backgroundColor must be a nonempty string\");\n }\n }\n\n canRender(req: RenderRequest): boolean {\n return CHART_FENCE_LANGUAGES.has(normalizeFenceLanguage(req.lang));\n }\n\n async render(req: RenderRequest, _context: OperationContext): Promise<UrlImage | null> {\n if (!this.canRender(req)) {\n return null;\n }\n\n const query = [\n `c=${encodeURIComponent(req.source)}`,\n `width=${String(this.width)}`,\n `height=${String(this.height)}`,\n `backgroundColor=${encodeURIComponent(this.backgroundColor)}`,\n `devicePixelRatio=${String(this.devicePixelRatio)}`,\n \"format=png\",\n ].join(\"&\");\n const imageUrl = `${this.baseUrl}/chart?${query}`;\n\n // https://docs.slack.dev/reference/block-kit/blocks/image-block\n if (imageUrl.length > IMAGE_URL_MAX_CHARS) {\n return null;\n }\n return {\n kind: \"url\",\n imageUrl,\n altText: req.altText,\n };\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"renderers.js","names":[],"sources":["../src/errors.ts","../src/constants.ts","../src/renderers/encoding.ts","../src/renderers/renderer-options.ts","../src/renderers/url-utils.ts","../src/renderers/kroki-renderer.ts","../src/renderers/mermaid-ink-renderer.ts","../src/renderers/codecogs-renderer.ts","../src/renderers/quickchart-renderer.ts"],"sourcesContent":["import type { UploadReceipt } from \"./receipts.js\";\n\n/**\n * Registry-keyed markers, not module-local symbols.\n *\n * Each published entry (`slackmark`, `slackmark/renderers`, `slackmark/slack`) is bundled\n * without code splitting, so every entry carries its own copy of these classes and\n * `instanceof` is false for an error that crosses an entry boundary. `Symbol.for` keys are\n * shared by every copy, which is what makes the exported guards below reliable. Prefer\n * those guards to `instanceof` for any error that can cross an entry.\n */\nconst RECEIPT_SNAPSHOT_LOCK = Symbol.for(\"slackmark.receiptSnapshotLock\");\nconst OPERATION_ERROR_CARRIER = Symbol.for(\"slackmark.operationErrorCarrier\");\nconst CONFIGURATION_ERROR_BRAND = Symbol.for(\"slackmark.error.configuration\");\nconst OPERATION_ERROR_BRAND = Symbol.for(\"slackmark.error.operation\");\n\n/**\n * Marks a class prototype so instances from any bundled copy answer to one identity.\n * Subclasses inherit the brand, and instances carry no extra own property.\n */\nexport function brandErrorPrototype(prototype: object, brand: symbol): void {\n Object.defineProperty(prototype, brand, {\n configurable: false,\n enumerable: false,\n value: true,\n writable: false,\n });\n}\n\n/**\n * Reads a brand without trusting the value: a hostile getter must not escape a guard.\n */\nexport function hasErrorBrand(value: unknown, brand: symbol): boolean {\n if (typeof value !== \"object\" || value === null) {\n return false;\n }\n try {\n return Reflect.get(value, brand) === true;\n } catch {\n return false;\n }\n}\n\n/**\n * Programmer/configuration error thrown only from the composition root.\n */\nexport interface ConfigurationErrorOptions {\n readonly code?: string | undefined;\n readonly stage?: string | undefined;\n readonly receipts?: ReadonlyArray<UploadReceipt> | undefined;\n readonly settledReceipts?: Promise<ReadonlyArray<UploadReceipt>> | undefined;\n readonly cause?: unknown;\n}\n\nexport class ConfigurationError extends Error {\n static {\n brandErrorPrototype(this.prototype, CONFIGURATION_ERROR_BRAND);\n }\n\n override readonly name: string;\n readonly code: string;\n readonly stage: string | undefined;\n readonly retryable: false;\n readonly receipts: ReadonlyArray<UploadReceipt>;\n readonly settledReceipts: Promise<ReadonlyArray<UploadReceipt>>;\n\n constructor(message: string, options: ConfigurationErrorOptions = {}) {\n super(message, options?.cause !== undefined ? { cause: options.cause } : undefined);\n this.name = \"ConfigurationError\";\n this.code = options.code ?? \"invalid_configuration\";\n this.stage = options.stage;\n this.retryable = false;\n this.receipts = freezeReceipts(options.receipts ?? []);\n this.settledReceipts = options.settledReceipts ?? Promise.resolve(this.receipts);\n }\n}\n\nexport const OperationErrorCode = {\n Aborted: \"operation_aborted\",\n DeadlineExceeded: \"operation_deadline_exceeded\",\n Shutdown: \"operation_shutdown\",\n} as const;\n\nexport type OperationErrorCode = (typeof OperationErrorCode)[keyof typeof OperationErrorCode];\n\nexport interface OperationErrorOptions {\n readonly receipts?: ReadonlyArray<UploadReceipt> | undefined;\n readonly settledReceipts?: Promise<ReadonlyArray<UploadReceipt>> | undefined;\n readonly cause?: unknown;\n}\n\n/**\n * Operational control-flow error. These failures are never degradations.\n */\nexport class OperationError extends Error {\n static {\n brandErrorPrototype(this.prototype, OPERATION_ERROR_BRAND);\n }\n\n override readonly name: string;\n readonly code: OperationErrorCode;\n readonly stage: string;\n readonly retryable: boolean;\n readonly receipts: ReadonlyArray<UploadReceipt>;\n readonly settledReceipts: Promise<ReadonlyArray<UploadReceipt>>;\n\n constructor(\n message: string,\n code: OperationErrorCode,\n stage: string,\n retryable: boolean,\n options: OperationErrorOptions = {},\n ) {\n super(message, options.cause !== undefined ? { cause: options.cause } : undefined);\n this.name = \"OperationError\";\n this.code = code;\n this.stage = stage;\n this.retryable = retryable;\n this.receipts = freezeReceipts(options.receipts ?? []);\n this.settledReceipts = options.settledReceipts ?? Promise.resolve(this.receipts);\n }\n}\n\nexport class OperationAbortedError extends OperationError {\n override readonly name: string;\n\n constructor(stage: string, options: OperationErrorOptions = {}) {\n super(\"Operation aborted by caller\", OperationErrorCode.Aborted, stage, false, options);\n this.name = \"OperationAbortedError\";\n }\n}\n\nexport class OperationDeadlineExceededError extends OperationError {\n override readonly name: string;\n\n constructor(stage: string, options: OperationErrorOptions = {}) {\n super(\"Operation deadline exceeded\", OperationErrorCode.DeadlineExceeded, stage, true, options);\n this.name = \"OperationDeadlineExceededError\";\n }\n}\n\nexport class OperationShutdownError extends OperationError {\n override readonly name: string;\n\n constructor(stage: string, options: OperationErrorOptions = {}) {\n super(\"Operation interrupted by shutdown\", OperationErrorCode.Shutdown, stage, true, options);\n this.name = \"OperationShutdownError\";\n }\n}\n\n/**\n * Identifies a {@link ConfigurationError} from any entry of this package.\n *\n * Use this instead of `instanceof` when the error may have been thrown by a different\n * entry — for example a `ConfigurationError` from `slackmark/renderers` caught by code\n * that imported the class from `slackmark`.\n */\nexport function isConfigurationError(value: unknown): value is ConfigurationError {\n return hasErrorBrand(value, CONFIGURATION_ERROR_BRAND);\n}\n\n/**\n * Identifies an {@link OperationError} — abort, deadline, or shutdown — from any entry of\n * this package, including its subclasses.\n *\n * Use this instead of `instanceof` when the error may have been thrown by a different\n * entry — for example an abort raised inside `FetchSlackUploader` from `slackmark/slack`\n * caught by code that imported the class from `slackmark`. Narrow further with `code`\n * against {@link OperationErrorCode} rather than testing a subclass with `instanceof`.\n */\nexport function isOperationError(value: unknown): value is OperationError {\n return hasErrorBrand(value, OPERATION_ERROR_BRAND);\n}\n\nexport function cloneOperationError(error: OperationError, fallbackStage: string): OperationError {\n const stage = error.stage.length > 0 ? error.stage : fallbackStage;\n const options: OperationErrorOptions = {\n cause: error,\n receipts: error.receipts,\n settledReceipts: error.settledReceipts,\n };\n let cloned: OperationError;\n switch (error.code) {\n case OperationErrorCode.Aborted:\n cloned = new OperationAbortedError(stage, options);\n break;\n case OperationErrorCode.DeadlineExceeded:\n cloned = new OperationDeadlineExceededError(stage, options);\n break;\n case OperationErrorCode.Shutdown:\n cloned = new OperationShutdownError(stage, options);\n break;\n }\n Reflect.defineProperty(cloned, OPERATION_ERROR_CARRIER, {\n configurable: false,\n enumerable: false,\n value: true,\n writable: false,\n });\n return cloned;\n}\n\nexport function isOperationErrorCarrier(error: OperationError): boolean {\n return Reflect.get(error, OPERATION_ERROR_CARRIER) === true;\n}\n\nexport function cloneConfigurationError(error: ConfigurationError): ConfigurationError {\n return new ConfigurationError(error.message, {\n code: error.code,\n stage: error.stage,\n cause: error,\n receipts: error.receipts,\n settledReceipts: error.settledReceipts,\n });\n}\n\nexport function attachReceipts(\n error: unknown,\n receipts: ReadonlyArray<UploadReceipt>,\n settledReceipts?: Promise<ReadonlyArray<UploadReceipt>>,\n): unknown {\n if (!(error instanceof Error)) {\n return error;\n }\n try {\n if (Reflect.get(error, RECEIPT_SNAPSHOT_LOCK) === true) {\n return error;\n }\n } catch {\n return error;\n }\n let existing: ReadonlyArray<UploadReceipt> = [];\n try {\n const candidate = Reflect.get(error, \"receipts\");\n if (Array.isArray(candidate)) {\n existing = candidate.filter(isUploadReceipt);\n }\n } catch {\n existing = [];\n }\n Reflect.defineProperty(error, \"receipts\", {\n configurable: true,\n enumerable: true,\n value: freezeReceipts(mergeReceipts(existing, receipts)),\n writable: false,\n });\n if (settledReceipts !== undefined) {\n const finalReceipts = freezeSettledReceipts(settledReceipts, receipts);\n Reflect.defineProperty(error, \"settledReceipts\", {\n configurable: true,\n enumerable: true,\n value: finalReceipts,\n writable: false,\n });\n }\n return error;\n}\n\nexport function lockReceiptSnapshot(error: unknown): unknown {\n if (error instanceof Error) {\n Reflect.defineProperty(error, RECEIPT_SNAPSHOT_LOCK, {\n configurable: false,\n enumerable: false,\n value: true,\n writable: false,\n });\n }\n return error;\n}\n\nasync function freezeSettledReceipts(\n settledReceipts: Promise<ReadonlyArray<UploadReceipt>>,\n fallback: ReadonlyArray<UploadReceipt>,\n): Promise<ReadonlyArray<UploadReceipt>> {\n try {\n return freezeReceipts(await settledReceipts);\n } catch {\n return freezeReceipts(fallback);\n }\n}\n\nfunction mergeReceipts(\n existing: ReadonlyArray<UploadReceipt>,\n incoming: ReadonlyArray<UploadReceipt>,\n): ReadonlyArray<UploadReceipt> {\n const existingGroups = groupReceipts(existing);\n const incomingGroups = groupReceipts(incoming);\n const merged: UploadReceipt[] = [...incoming];\n for (const [key, values] of existingGroups) {\n const overlap = incomingGroups.get(key)?.length ?? 0;\n if (values.length > overlap) {\n merged.push(...values.slice(overlap));\n }\n }\n return merged;\n}\n\nfunction groupReceipts(\n receipts: ReadonlyArray<UploadReceipt>,\n): ReadonlyMap<string, ReadonlyArray<UploadReceipt>> {\n const grouped = new Map<string, UploadReceipt[]>();\n for (const receipt of receipts) {\n const key = receiptKey(receipt);\n const values = grouped.get(key);\n if (values === undefined) {\n grouped.set(key, [receipt]);\n } else {\n values.push(receipt);\n }\n }\n return grouped;\n}\n\nfunction receiptKey(receipt: UploadReceipt): string {\n return [\n receipt.provider,\n receipt.phase,\n receipt.fileId ?? \"\",\n String(receipt.shared),\n receipt.processing,\n String(receipt.status ?? \"\"),\n String(receipt.retryAfterMs ?? \"\"),\n receipt.providerCode ?? \"\",\n receipt.retrySafety,\n ].join(\"\\u0000\");\n}\n\nfunction freezeReceipts(receipts: ReadonlyArray<UploadReceipt>): ReadonlyArray<UploadReceipt> {\n return Object.freeze(receipts.map((receipt) => Object.freeze({ ...receipt })));\n}\n\nfunction isUploadReceipt(value: unknown): value is UploadReceipt {\n return typeof value === \"object\" && value !== null && Reflect.get(value, \"kind\") === \"upload\";\n}\n","/**\n * Named Slack Block Kit limits.\n * Sources: https://docs.slack.dev/block-kit and block reference pages (July 2026 research).\n */\n\n/** https://docs.slack.dev/block-kit */\nexport const MAX_BLOCKS_PER_MESSAGE = 50;\n\n/** https://docs.slack.dev/reference/block-kit/blocks/section-block */\nexport const SECTION_TEXT_MAX_CHARS = 3000;\n\n/** https://docs.slack.dev/reference/block-kit/blocks/header-block */\nexport const HEADER_TEXT_MAX_CHARS = 150;\n\n/** https://docs.slack.dev/reference/block-kit/blocks/header-block */\nexport const HEADER_LEVEL_MAX = 4;\n\n/** https://docs.slack.dev/reference/block-kit/blocks/image-block */\nexport const IMAGE_URL_MAX_CHARS = 3000;\n\n/** https://docs.slack.dev/reference/block-kit/blocks/image-block */\nexport const IMAGE_ALT_MAX_CHARS = 2000;\n\n/** slackmark renderer safety limit for retained/uploaded image bytes. */\nexport const RENDERED_IMAGE_MAX_BYTES: number = 10 * 1024 * 1024;\n\n/** Portable filename component limit used by renderer output validation. */\nexport const RENDERED_IMAGE_FILENAME_MAX_CHARS = 255;\n\n/** Defensive upper bound for Slack file IDs returned by uploaders. */\nexport const SLACK_FILE_ID_MAX_CHARS = 255;\n\n/** https://docs.slack.dev/reference/block-kit/blocks/context-block */\nexport const CONTEXT_ELEMENTS_MAX = 10;\n\n/** https://docs.slack.dev/reference/block-kit/blocks/markdown-block */\nexport const MARKDOWN_CUMULATIVE_MAX_CHARS = 12_000;\n\n/** https://docs.slack.dev/reference/block-kit/blocks/table-block */\nexport const TABLE_MAX_ROWS = 100;\n\n/** https://docs.slack.dev/reference/block-kit/blocks/table-block */\nexport const TABLE_MAX_COLS = 20;\n\n/** https://docs.slack.dev/reference/block-kit/blocks/table-block */\nexport const TABLE_CELL_CHARS_MAX = 10_000;\n\n/**\n * `raw_text.text` / `raw_number.text` declare `minLength: 1`; a blank markdown\n * cell must be padded or Slack rejects the payload with `invalid_blocks`.\n * https://docs.slack.dev/reference/block-kit/blocks/data-table-block\n */\nexport const TABLE_CELL_MIN_CHARS = 1;\n\n/** Spec decision: prefer `table` up to this many rows (incl. header). */\nexport const TABLE_PREFERRED_MAX_ROWS = 50;\n\n/** https://docs.slack.dev/reference/block-kit/blocks/data-table-block */\nexport const DATA_TABLE_MAX_DATA_ROWS = 200;\n\n/** https://docs.slack.dev/reference/block-kit/blocks/data-table-block */\nexport const DATA_TABLE_CELL_CHARS_MAX = 20_000;\n\n/** Spec decision: caption is required but unbounded in Slack's docs; match header. */\nexport const DATA_TABLE_CAPTION_MAX_CHARS = 150;\n\n/** https://docs.slack.dev/reference/block-kit/blocks/data-visualization-block */\nexport const CHART_TITLE_MAX_CHARS = 50;\n\n/** https://docs.slack.dev/reference/block-kit/blocks/data-visualization-block */\nexport const CHART_LABEL_MAX_CHARS = 20;\n\n/** https://docs.slack.dev/reference/block-kit/blocks/data-visualization-block */\nexport const CHART_SEGMENTS_MAX = 12;\n\n/** https://docs.slack.dev/reference/block-kit/blocks/data-visualization-block */\nexport const CHART_SERIES_MAX = 12;\n\n/** https://docs.slack.dev/reference/block-kit/blocks/data-visualization-block */\nexport const CHART_POINTS_MAX = 20;\n\n/**\n * Community-reported cap (ENG-4936); not in official docs.\n * Enforced defensively with degradation.\n */\nexport const DATA_VISUALIZATION_MAX_PER_MESSAGE = 2;\n\n/** https://docs.slack.dev/reference/methods/chat.postMessage#truncating */\nexport const MESSAGE_TEXT_SAFETY_MAX_CHARS = 40_000;\n\n/** Undocumented; defensive clamp for rich_text_list.indent. */\nexport const RICH_TEXT_LIST_INDENT_MAX = 6;\n\n/** https://docs.slack.dev/reference/block-kit/blocks/container-block */\nexport const CONTAINER_CHILDREN_MAX = 10;\n\n/** https://docs.slack.dev/reference/block-kit/blocks/container-block */\nexport const CONTAINER_TITLE_MAX_CHARS = 150;\n\n/** Cell wrap heuristic for table column_settings.is_wrapped. */\nexport const TABLE_CELL_WRAP_THRESHOLD = 40;\n\nexport const ELLIPSIS = \"…\";\n","const BASE64URL_ALPHABET = \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_\";\n\n/**\n * Kroki and mermaid.ink both accept zlib-deflated, unpadded base64url payloads.\n */\nexport async function deflateBase64Url(value: string): Promise<string> {\n const stream = new CompressionStream(\"deflate\");\n const compressed = readAll(stream.readable);\n const writer = stream.writable.getWriter();\n\n await writer.write(new TextEncoder().encode(value));\n await writer.close();\n writer.releaseLock();\n\n return encodeBase64Url(await compressed);\n}\n\nasync function readAll(stream: GfmReadableStream<Uint8Array>): Promise<Uint8Array> {\n const reader = stream.getReader();\n const chunks: Uint8Array[] = [];\n let length = 0;\n\n while (true) {\n const result = await reader.read();\n if (result.done) {\n break;\n }\n if (result.value !== undefined) {\n chunks.push(result.value);\n length += result.value.byteLength;\n }\n }\n reader.releaseLock();\n\n const output = new Uint8Array(length);\n let offset = 0;\n for (const chunk of chunks) {\n output.set(chunk, offset);\n offset += chunk.byteLength;\n }\n return output;\n}\n\nfunction encodeBase64Url(bytes: Uint8Array): string {\n const output: string[] = [];\n for (let index = 0; index < bytes.length; index += 3) {\n const first = bytes[index] ?? 0;\n const second = bytes[index + 1];\n const third = bytes[index + 2];\n\n output.push(\n BASE64URL_ALPHABET[first >> 2] ?? \"\",\n BASE64URL_ALPHABET[((first & 0b11) << 4) | ((second ?? 0) >> 4)] ?? \"\",\n );\n if (second !== undefined) {\n output.push(BASE64URL_ALPHABET[((second & 0b1111) << 2) | ((third ?? 0) >> 6)] ?? \"\");\n }\n if (third !== undefined) {\n output.push(BASE64URL_ALPHABET[third & 0b11_1111] ?? \"\");\n }\n }\n return output.join(\"\");\n}\n","import { ConfigurationError } from \"../errors.js\";\n\nexport function snapshotRendererOptions<T extends object>(\n options: T,\n allowed: ReadonlyArray<string>,\n label: string,\n): T {\n if (typeof options !== \"object\" || options === null || Array.isArray(options)) {\n throw invalidRendererOptions(`${label} options must be a plain object`);\n }\n let prototype: object | null;\n let keys: ReadonlyArray<string>;\n try {\n prototype = Object.getPrototypeOf(options);\n keys = Object.keys(options);\n } catch (cause) {\n throw invalidRendererOptions(`${label} options could not be inspected`, cause);\n }\n if (prototype !== Object.prototype && prototype !== null) {\n throw invalidRendererOptions(`${label} options must be a plain object`);\n }\n const allowedKeys = new Set(allowed);\n const snapshot: Record<string, unknown> = {};\n for (const key of keys) {\n if (!allowedKeys.has(key)) {\n throw invalidRendererOptions(`Unknown ${label} option: ${key}`);\n }\n try {\n snapshot[key] = Reflect.get(options, key);\n } catch (cause) {\n throw invalidRendererOptions(`${label}.${key} could not be read`, cause);\n }\n }\n return Object.freeze(snapshot) as T;\n}\n\nexport function invalidRendererOptions(message: string, cause?: unknown): ConfigurationError {\n return new ConfigurationError(message, {\n code: \"invalid_renderer_options\",\n stage: \"configuration\",\n cause,\n });\n}\n","import { isConfigurationError } from \"../errors.js\";\nimport { invalidRendererOptions } from \"./renderer-options.js\";\n\nexport function normalizeBaseUrl(baseUrl: string): string {\n if (typeof baseUrl !== \"string\" || baseUrl.length === 0 || baseUrl !== baseUrl.trim()) {\n throw invalidRendererOptions(\"baseUrl must be a nonempty trimmed string\");\n }\n const normalized = baseUrl.replace(/\\/+$/u, \"\");\n try {\n const parsed = new URL(normalized);\n if (parsed.protocol !== \"https:\" || parsed.username.length > 0 || parsed.password.length > 0) {\n throw invalidRendererOptions(\"baseUrl must be credential-free absolute HTTPS\");\n }\n } catch (cause) {\n if (isConfigurationError(cause)) {\n throw cause;\n }\n throw invalidRendererOptions(\"baseUrl must be credential-free absolute HTTPS\", cause);\n }\n return normalized;\n}\n\nexport function normalizeFenceLanguage(lang: string): string {\n return lang.trim().toLowerCase();\n}\n","import { IMAGE_URL_MAX_CHARS } from \"../constants.js\";\nimport type { OperationContext, RenderRequest, UrlImage, UrlImageRenderer } from \"../types.js\";\n\nimport { deflateBase64Url } from \"./encoding.js\";\nimport { invalidRendererOptions, snapshotRendererOptions } from \"./renderer-options.js\";\nimport { normalizeBaseUrl, normalizeFenceLanguage } from \"./url-utils.js\";\n\nconst DEFAULT_KROKI_BASE_URL = \"https://kroki.io\";\n\n/**\n * Fence-language aliases for Kroki's supported diagram types.\n *\n * @see https://docs.kroki.io/kroki/setup/usage/\n */\nexport const KROKI_DIAGRAM_TYPES: Readonly<Record<string, string>> = Object.freeze({\n blockdiag: \"blockdiag\",\n bpmn: \"bpmn\",\n bytefield: \"bytefield\",\n c4: \"c4plantuml\",\n c4plantuml: \"c4plantuml\",\n d2: \"d2\",\n dbml: \"dbml\",\n ditaa: \"ditaa\",\n dot: \"graphviz\",\n erd: \"erd\",\n excalidraw: \"excalidraw\",\n graphviz: \"graphviz\",\n mermaid: \"mermaid\",\n nomnoml: \"nomnoml\",\n pikchr: \"pikchr\",\n plantuml: \"plantuml\",\n puml: \"plantuml\",\n structurizr: \"structurizr\",\n svgbob: \"svgbob\",\n symbolator: \"symbolator\",\n tikz: \"tikz\",\n umlet: \"umlet\",\n vega: \"vega\",\n \"vega-lite\": \"vegalite\",\n vegalite: \"vegalite\",\n wavedrom: \"wavedrom\",\n wireviz: \"wireviz\",\n});\n\nexport interface KrokiRendererOptions {\n readonly baseUrl?: string;\n /**\n * Additional or replacement fence-language aliases, merged over the defaults.\n */\n readonly diagramTypes?: Readonly<Record<string, string>>;\n}\n\n/**\n * Produces durable Kroki GET URLs without performing network I/O.\n */\nexport class KrokiRenderer implements UrlImageRenderer {\n readonly id: string;\n readonly output: \"url\";\n private readonly baseUrl: string;\n private readonly diagramTypes: Readonly<Record<string, string>>;\n\n constructor(options: KrokiRendererOptions = {}) {\n const validated = snapshotRendererOptions(\n options,\n [\"baseUrl\", \"diagramTypes\"],\n \"KrokiRenderer\",\n );\n this.id = \"kroki\";\n this.output = \"url\";\n this.baseUrl = normalizeBaseUrl(\n validated.baseUrl === undefined ? DEFAULT_KROKI_BASE_URL : validated.baseUrl,\n );\n this.diagramTypes = Object.freeze({\n ...KROKI_DIAGRAM_TYPES,\n ...validateDiagramTypes(validated.diagramTypes),\n });\n }\n\n canRender(req: RenderRequest): boolean {\n return this.diagramTypes[normalizeFenceLanguage(req.lang)] !== undefined;\n }\n\n async render(req: RenderRequest, _context: OperationContext): Promise<UrlImage | null> {\n const diagramType = this.diagramTypes[normalizeFenceLanguage(req.lang)];\n if (diagramType === undefined) {\n return null;\n }\n\n const encoded = await deflateBase64Url(req.source);\n const imageUrl = `${this.baseUrl}/${encodeURIComponent(diagramType)}/png/${encoded}`;\n\n // https://docs.slack.dev/reference/block-kit/blocks/image-block\n if (imageUrl.length > IMAGE_URL_MAX_CHARS) {\n return null;\n }\n return {\n kind: \"url\",\n imageUrl,\n altText: req.altText,\n };\n }\n}\n\nfunction validateDiagramTypes(\n value: Readonly<Record<string, string>> | undefined,\n): Readonly<Record<string, string>> {\n if (value === undefined) {\n return {};\n }\n let keys: ReadonlyArray<string>;\n try {\n keys = Object.keys(value);\n } catch (cause) {\n throw invalidRendererOptions(\"KrokiRenderer.diagramTypes could not be inspected\", cause);\n }\n const snapshot = snapshotRendererOptions(value, keys, \"KrokiRenderer.diagramTypes\");\n for (const [language, diagramType] of Object.entries(snapshot)) {\n if (language.length === 0 || typeof diagramType !== \"string\" || diagramType.length === 0) {\n throw invalidRendererOptions(\"KrokiRenderer.diagramTypes values must be nonempty strings\");\n }\n }\n return snapshot;\n}\n","import { IMAGE_URL_MAX_CHARS } from \"../constants.js\";\nimport type { OperationContext, RenderRequest, UrlImage, UrlImageRenderer } from \"../types.js\";\n\nimport { deflateBase64Url } from \"./encoding.js\";\nimport { invalidRendererOptions, snapshotRendererOptions } from \"./renderer-options.js\";\nimport { normalizeBaseUrl, normalizeFenceLanguage } from \"./url-utils.js\";\n\nconst DEFAULT_MERMAID_INK_BASE_URL = \"https://mermaid.ink\";\nconst DEFAULT_MERMAID_INK_BACKGROUND = \"!white\";\n\nexport type MermaidInkTheme = \"default\" | \"neutral\" | \"dark\" | \"forest\";\n\nexport interface MermaidInkRendererOptions {\n readonly baseUrl?: string;\n readonly theme?: MermaidInkTheme;\n /**\n * mermaid.ink color value, such as `!white` or `FF0000`.\n */\n readonly bgColor?: string;\n}\n\ninterface MermaidInkState {\n readonly code: string;\n readonly mermaid: {\n readonly theme: MermaidInkTheme;\n };\n}\n\n/**\n * Produces mermaid.ink pako-state PNG URLs without performing network I/O.\n */\nexport class MermaidInkRenderer implements UrlImageRenderer {\n readonly id: string;\n readonly output: \"url\";\n private readonly baseUrl: string;\n private readonly theme: MermaidInkTheme;\n private readonly bgColor: string;\n\n constructor(options: MermaidInkRendererOptions = {}) {\n const validated = snapshotRendererOptions(\n options,\n [\"baseUrl\", \"theme\", \"bgColor\"],\n \"MermaidInkRenderer\",\n );\n this.id = \"mermaid-ink\";\n this.output = \"url\";\n this.baseUrl = normalizeBaseUrl(\n validated.baseUrl === undefined ? DEFAULT_MERMAID_INK_BASE_URL : validated.baseUrl,\n );\n this.theme = validated.theme === undefined ? \"default\" : validated.theme;\n this.bgColor =\n validated.bgColor === undefined ? DEFAULT_MERMAID_INK_BACKGROUND : validated.bgColor;\n if (\n ![\"default\", \"neutral\", \"dark\", \"forest\"].includes(this.theme) ||\n typeof this.bgColor !== \"string\" ||\n this.bgColor.length === 0\n ) {\n throw invalidRendererOptions(\"MermaidInkRenderer theme or bgColor is invalid\");\n }\n }\n\n canRender(req: RenderRequest): boolean {\n return normalizeFenceLanguage(req.lang) === \"mermaid\";\n }\n\n async render(req: RenderRequest, _context: OperationContext): Promise<UrlImage | null> {\n if (!this.canRender(req)) {\n return null;\n }\n\n const state: MermaidInkState = {\n code: req.source,\n mermaid: { theme: this.theme },\n };\n const encoded = await deflateBase64Url(JSON.stringify(state));\n const imageUrl =\n `${this.baseUrl}/img/pako:${encoded}` +\n `?type=png&bgColor=${encodeURIComponent(this.bgColor)}`;\n\n // https://docs.slack.dev/reference/block-kit/blocks/image-block\n if (imageUrl.length > IMAGE_URL_MAX_CHARS) {\n return null;\n }\n return {\n kind: \"url\",\n imageUrl,\n altText: req.altText,\n };\n }\n}\n","import { IMAGE_URL_MAX_CHARS } from \"../constants.js\";\nimport type { OperationContext, RenderRequest, UrlImage, UrlImageRenderer } from \"../types.js\";\n\nimport { invalidRendererOptions, snapshotRendererOptions } from \"./renderer-options.js\";\nimport { normalizeBaseUrl, normalizeFenceLanguage } from \"./url-utils.js\";\n\nconst DEFAULT_CODECOGS_BASE_URL = \"https://latex.codecogs.com\";\nconst DEFAULT_CODECOGS_DPI = 200;\nconst MATH_FENCE_LANGUAGES: ReadonlySet<string> = new Set([\"katex\", \"latex\", \"math\", \"tex\"]);\n\nexport interface CodeCogsRendererOptions {\n readonly baseUrl?: string;\n readonly dpi?: number;\n}\n\n/**\n * Produces deterministic CodeCogs `png.image` URLs for display math.\n */\nexport class CodeCogsRenderer implements UrlImageRenderer {\n readonly id: string;\n readonly output: \"url\";\n private readonly baseUrl: string;\n private readonly dpi: number;\n\n constructor(options: CodeCogsRendererOptions = {}) {\n const validated = snapshotRendererOptions(options, [\"baseUrl\", \"dpi\"], \"CodeCogsRenderer\");\n this.id = \"codecogs\";\n this.output = \"url\";\n this.baseUrl = normalizeBaseUrl(\n validated.baseUrl === undefined ? DEFAULT_CODECOGS_BASE_URL : validated.baseUrl,\n );\n this.dpi = validated.dpi === undefined ? DEFAULT_CODECOGS_DPI : validated.dpi;\n\n if (!Number.isInteger(this.dpi) || this.dpi <= 0) {\n throw invalidRendererOptions(\"dpi must be a positive integer\");\n }\n }\n\n canRender(req: RenderRequest): boolean {\n return MATH_FENCE_LANGUAGES.has(normalizeFenceLanguage(req.lang));\n }\n\n async render(req: RenderRequest, _context: OperationContext): Promise<UrlImage | null> {\n if (!this.canRender(req)) {\n return null;\n }\n\n const formula = `\\\\dpi{${String(this.dpi)}} ${req.source}`;\n const imageUrl = `${this.baseUrl}/png.image?${encodeURIComponent(formula)}`;\n\n // https://docs.slack.dev/reference/block-kit/blocks/image-block\n if (imageUrl.length > IMAGE_URL_MAX_CHARS) {\n return null;\n }\n return {\n kind: \"url\",\n imageUrl,\n altText: req.altText,\n };\n }\n}\n","import { IMAGE_URL_MAX_CHARS } from \"../constants.js\";\nimport type { OperationContext, RenderRequest, UrlImage, UrlImageRenderer } from \"../types.js\";\n\nimport { invalidRendererOptions, snapshotRendererOptions } from \"./renderer-options.js\";\nimport { normalizeBaseUrl, normalizeFenceLanguage } from \"./url-utils.js\";\n\nconst DEFAULT_QUICKCHART_BASE_URL = \"https://quickchart.io\";\nconst DEFAULT_QUICKCHART_WIDTH = 500;\nconst DEFAULT_QUICKCHART_HEIGHT = 300;\nconst DEFAULT_QUICKCHART_BACKGROUND = \"white\";\nconst DEFAULT_QUICKCHART_DEVICE_PIXEL_RATIO = 2;\nconst CHART_FENCE_LANGUAGES: ReadonlySet<string> = new Set([\n \"chart\",\n \"chart.js\",\n \"chartjs\",\n \"quickchart\",\n]);\n\nexport interface QuickChartRendererOptions {\n readonly baseUrl?: string;\n readonly width?: number;\n readonly height?: number;\n readonly backgroundColor?: string;\n readonly devicePixelRatio?: number;\n}\n\n/**\n * Produces full, durable QuickChart GET URLs. It never uses the expiring\n * `/chart/create` short-URL API.\n */\nexport class QuickChartRenderer implements UrlImageRenderer {\n readonly id: string;\n readonly output: \"url\";\n private readonly baseUrl: string;\n private readonly width: number;\n private readonly height: number;\n private readonly backgroundColor: string;\n private readonly devicePixelRatio: number;\n\n constructor(options: QuickChartRendererOptions = {}) {\n const validated = snapshotRendererOptions(\n options,\n [\"baseUrl\", \"width\", \"height\", \"backgroundColor\", \"devicePixelRatio\"],\n \"QuickChartRenderer\",\n );\n this.id = \"quickchart\";\n this.output = \"url\";\n this.baseUrl = normalizeBaseUrl(\n validated.baseUrl === undefined ? DEFAULT_QUICKCHART_BASE_URL : validated.baseUrl,\n );\n this.width = validated.width === undefined ? DEFAULT_QUICKCHART_WIDTH : validated.width;\n this.height = validated.height === undefined ? DEFAULT_QUICKCHART_HEIGHT : validated.height;\n this.backgroundColor =\n validated.backgroundColor === undefined\n ? DEFAULT_QUICKCHART_BACKGROUND\n : validated.backgroundColor;\n this.devicePixelRatio =\n validated.devicePixelRatio === undefined\n ? DEFAULT_QUICKCHART_DEVICE_PIXEL_RATIO\n : validated.devicePixelRatio;\n\n if (!Number.isInteger(this.width) || this.width <= 0) {\n throw invalidRendererOptions(\"width must be a positive integer\");\n }\n if (!Number.isInteger(this.height) || this.height <= 0) {\n throw invalidRendererOptions(\"height must be a positive integer\");\n }\n if (!Number.isFinite(this.devicePixelRatio) || this.devicePixelRatio <= 0) {\n throw invalidRendererOptions(\"devicePixelRatio must be positive\");\n }\n if (typeof this.backgroundColor !== \"string\" || this.backgroundColor.length === 0) {\n throw invalidRendererOptions(\"backgroundColor must be a nonempty string\");\n }\n }\n\n canRender(req: RenderRequest): boolean {\n return CHART_FENCE_LANGUAGES.has(normalizeFenceLanguage(req.lang));\n }\n\n async render(req: RenderRequest, _context: OperationContext): Promise<UrlImage | null> {\n if (!this.canRender(req)) {\n return null;\n }\n\n const query = [\n `c=${encodeURIComponent(req.source)}`,\n `width=${String(this.width)}`,\n `height=${String(this.height)}`,\n `backgroundColor=${encodeURIComponent(this.backgroundColor)}`,\n `devicePixelRatio=${String(this.devicePixelRatio)}`,\n \"format=png\",\n ].join(\"&\");\n const imageUrl = `${this.baseUrl}/chart?${query}`;\n\n // https://docs.slack.dev/reference/block-kit/blocks/image-block\n if (imageUrl.length > IMAGE_URL_MAX_CHARS) {\n return null;\n }\n return {\n kind: \"url\",\n imageUrl,\n altText: req.altText,\n };\n }\n}\n"],"mappings":"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"}
|
package/dist/slack.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Slack Web API integrations. No request occurs until `upload()` is called.
|
|
3
3
|
*/
|
|
4
|
+
export { isConfigurationError, isOperationError } from "./errors.js";
|
|
4
5
|
export { FetchSlackUploader } from "./slack/fetch-slack-uploader.js";
|
|
5
6
|
export type { FetchSlackUploaderOptions, SlackFetch, SlackFetchRequestInit, SlackFetchResponse, SlackUploadClock, SlackUploadPollOptions, SlackUploadSleep, } from "./slack/fetch-slack-uploader.js";
|
|
6
7
|
export { SlackUploadError, SlackUploadStage, isSlackUploadError, } from "./slack/slack-upload-error.js";
|
package/dist/slack.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"slack.d.ts","sourceRoot":"","sources":["../src/slack.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,kBAAkB,EAAE,MAAM,iCAAiC,CAAC;AACrE,YAAY,EACV,yBAAyB,EACzB,UAAU,EACV,qBAAqB,EACrB,kBAAkB,EAClB,gBAAgB,EAChB,sBAAsB,EACtB,gBAAgB,GACjB,MAAM,iCAAiC,CAAC;AAEzC,OAAO,EACL,gBAAgB,EAChB,gBAAgB,EAChB,kBAAkB,GACnB,MAAM,+BAA+B,CAAC;AACvC,YAAY,EAAE,uBAAuB,EAAE,MAAM,+BAA+B,CAAC"}
|
|
1
|
+
{"version":3,"file":"slack.d.ts","sourceRoot":"","sources":["../src/slack.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,oBAAoB,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAErE,OAAO,EAAE,kBAAkB,EAAE,MAAM,iCAAiC,CAAC;AACrE,YAAY,EACV,yBAAyB,EACzB,UAAU,EACV,qBAAqB,EACrB,kBAAkB,EAClB,gBAAgB,EAChB,sBAAsB,EACtB,gBAAgB,GACjB,MAAM,iCAAiC,CAAC;AAEzC,OAAO,EACL,gBAAgB,EAChB,gBAAgB,EAChB,kBAAkB,GACnB,MAAM,+BAA+B,CAAC;AACvC,YAAY,EAAE,uBAAuB,EAAE,MAAM,+BAA+B,CAAC"}
|
package/dist/slack.js
CHANGED
|
@@ -1,24 +1,3 @@
|
|
|
1
|
-
//#region src/receipts.ts
|
|
2
|
-
const UploadPhase = {
|
|
3
|
-
Requested: "requested",
|
|
4
|
-
Allocated: "allocated",
|
|
5
|
-
Uploaded: "uploaded",
|
|
6
|
-
Completed: "completed",
|
|
7
|
-
Shared: "shared",
|
|
8
|
-
Unknown: "unknown"
|
|
9
|
-
};
|
|
10
|
-
const UploadProcessing = {
|
|
11
|
-
NotRequested: "not-requested",
|
|
12
|
-
Pending: "pending",
|
|
13
|
-
Verified: "verified",
|
|
14
|
-
Unverified: "unverified"
|
|
15
|
-
};
|
|
16
|
-
const RetrySafety = {
|
|
17
|
-
Never: "never",
|
|
18
|
-
Safe: "safe",
|
|
19
|
-
MayDuplicate: "may-duplicate"
|
|
20
|
-
};
|
|
21
|
-
//#endregion
|
|
22
1
|
//#region src/errors.ts
|
|
23
2
|
/**
|
|
24
3
|
* Registry-keyed markers, not module-local symbols.
|
|
@@ -118,6 +97,16 @@ var OperationDeadlineExceededError = class extends OperationError {
|
|
|
118
97
|
}
|
|
119
98
|
};
|
|
120
99
|
/**
|
|
100
|
+
* Identifies a {@link ConfigurationError} from any entry of this package.
|
|
101
|
+
*
|
|
102
|
+
* Use this instead of `instanceof` when the error may have been thrown by a different
|
|
103
|
+
* entry — for example a `ConfigurationError` from `slackmark/renderers` caught by code
|
|
104
|
+
* that imported the class from `slackmark`.
|
|
105
|
+
*/
|
|
106
|
+
function isConfigurationError(value) {
|
|
107
|
+
return hasErrorBrand(value, CONFIGURATION_ERROR_BRAND);
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
121
110
|
* Identifies an {@link OperationError} — abort, deadline, or shutdown — from any entry of
|
|
122
111
|
* this package, including its subclasses.
|
|
123
112
|
*
|
|
@@ -207,6 +196,27 @@ function isUploadReceipt(value) {
|
|
|
207
196
|
return typeof value === "object" && value !== null && Reflect.get(value, "kind") === "upload";
|
|
208
197
|
}
|
|
209
198
|
//#endregion
|
|
199
|
+
//#region src/receipts.ts
|
|
200
|
+
const UploadPhase = {
|
|
201
|
+
Requested: "requested",
|
|
202
|
+
Allocated: "allocated",
|
|
203
|
+
Uploaded: "uploaded",
|
|
204
|
+
Completed: "completed",
|
|
205
|
+
Shared: "shared",
|
|
206
|
+
Unknown: "unknown"
|
|
207
|
+
};
|
|
208
|
+
const UploadProcessing = {
|
|
209
|
+
NotRequested: "not-requested",
|
|
210
|
+
Pending: "pending",
|
|
211
|
+
Verified: "verified",
|
|
212
|
+
Unverified: "unverified"
|
|
213
|
+
};
|
|
214
|
+
const RetrySafety = {
|
|
215
|
+
Never: "never",
|
|
216
|
+
Safe: "safe",
|
|
217
|
+
MayDuplicate: "may-duplicate"
|
|
218
|
+
};
|
|
219
|
+
//#endregion
|
|
210
220
|
//#region src/slack/slack-upload-error.ts
|
|
211
221
|
/** See the brand rationale in `errors.ts`: this class is bundled into more than one entry. */
|
|
212
222
|
const SLACK_UPLOAD_ERROR_BRAND = Symbol.for("slackmark.error.slackUpload");
|
|
@@ -763,6 +773,6 @@ function defaultClock() {
|
|
|
763
773
|
return Date.now();
|
|
764
774
|
}
|
|
765
775
|
//#endregion
|
|
766
|
-
export { FetchSlackUploader, SlackUploadError, SlackUploadStage, isSlackUploadError };
|
|
776
|
+
export { FetchSlackUploader, SlackUploadError, SlackUploadStage, isConfigurationError, isOperationError, isSlackUploadError };
|
|
767
777
|
|
|
768
778
|
//# sourceMappingURL=slack.js.map
|