slackmark 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (97) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +134 -0
  3. package/dist/adapters/blockquote-adapter.d.ts +11 -0
  4. package/dist/adapters/blockquote-adapter.d.ts.map +1 -0
  5. package/dist/adapters/code-fence-adapter.d.ts +12 -0
  6. package/dist/adapters/code-fence-adapter.d.ts.map +1 -0
  7. package/dist/adapters/heading-adapter.d.ts +11 -0
  8. package/dist/adapters/heading-adapter.d.ts.map +1 -0
  9. package/dist/adapters/html-block-adapter.d.ts +11 -0
  10. package/dist/adapters/html-block-adapter.d.ts.map +1 -0
  11. package/dist/adapters/inline.d.ts +41 -0
  12. package/dist/adapters/inline.d.ts.map +1 -0
  13. package/dist/adapters/list-adapter.d.ts +12 -0
  14. package/dist/adapters/list-adapter.d.ts.map +1 -0
  15. package/dist/adapters/math-block-adapter.d.ts +11 -0
  16. package/dist/adapters/math-block-adapter.d.ts.map +1 -0
  17. package/dist/adapters/mermaid-fence-adapter.d.ts +19 -0
  18. package/dist/adapters/mermaid-fence-adapter.d.ts.map +1 -0
  19. package/dist/adapters/node-adapter.d.ts +21 -0
  20. package/dist/adapters/node-adapter.d.ts.map +1 -0
  21. package/dist/adapters/paragraph-adapter.d.ts +11 -0
  22. package/dist/adapters/paragraph-adapter.d.ts.map +1 -0
  23. package/dist/adapters/skip-adapter.d.ts +11 -0
  24. package/dist/adapters/skip-adapter.d.ts.map +1 -0
  25. package/dist/adapters/table-adapter.d.ts +11 -0
  26. package/dist/adapters/table-adapter.d.ts.map +1 -0
  27. package/dist/adapters/task-list-adapter.d.ts +11 -0
  28. package/dist/adapters/task-list-adapter.d.ts.map +1 -0
  29. package/dist/adapters/thematic-break-adapter.d.ts +11 -0
  30. package/dist/adapters/thematic-break-adapter.d.ts.map +1 -0
  31. package/dist/assemble/message-assembler.d.ts +24 -0
  32. package/dist/assemble/message-assembler.d.ts.map +1 -0
  33. package/dist/assemble/text-fallback.d.ts +10 -0
  34. package/dist/assemble/text-fallback.d.ts.map +1 -0
  35. package/dist/assert-never.d.ts +5 -0
  36. package/dist/assert-never.d.ts.map +1 -0
  37. package/dist/blocks/types.d.ts +196 -0
  38. package/dist/blocks/types.d.ts.map +1 -0
  39. package/dist/budget/conversion-context.d.ts +44 -0
  40. package/dist/budget/conversion-context.d.ts.map +1 -0
  41. package/dist/budget/recording-degradation-collector.d.ts +11 -0
  42. package/dist/budget/recording-degradation-collector.d.ts.map +1 -0
  43. package/dist/budget/standard-budget-ledger.d.ts +35 -0
  44. package/dist/budget/standard-budget-ledger.d.ts.map +1 -0
  45. package/dist/capabilities/capabilities.d.ts +42 -0
  46. package/dist/capabilities/capabilities.d.ts.map +1 -0
  47. package/dist/constants.d.ts +59 -0
  48. package/dist/constants.d.ts.map +1 -0
  49. package/dist/converter/create-converter.d.ts +25 -0
  50. package/dist/converter/create-converter.d.ts.map +1 -0
  51. package/dist/converter/resolve-config.d.ts +7 -0
  52. package/dist/converter/resolve-config.d.ts.map +1 -0
  53. package/dist/converter/slackmark-converter.d.ts +33 -0
  54. package/dist/converter/slackmark-converter.d.ts.map +1 -0
  55. package/dist/errors.d.ts +10 -0
  56. package/dist/errors.d.ts.map +1 -0
  57. package/dist/index.d.ts +27 -0
  58. package/dist/index.d.ts.map +1 -0
  59. package/dist/index.js +3402 -0
  60. package/dist/index.js.map +1 -0
  61. package/dist/mermaid/mermaid-pie-parser.d.ts +10 -0
  62. package/dist/mermaid/mermaid-pie-parser.d.ts.map +1 -0
  63. package/dist/mermaid/mermaid-xychart-parser.d.ts +10 -0
  64. package/dist/mermaid/mermaid-xychart-parser.d.ts.map +1 -0
  65. package/dist/parsers/remark-markdown-parser.d.ts +9 -0
  66. package/dist/parsers/remark-markdown-parser.d.ts.map +1 -0
  67. package/dist/registry/adapter-registry.d.ts +13 -0
  68. package/dist/registry/adapter-registry.d.ts.map +1 -0
  69. package/dist/renderers/codecogs-renderer.d.ts +18 -0
  70. package/dist/renderers/codecogs-renderer.d.ts.map +1 -0
  71. package/dist/renderers/encoding.d.ts +5 -0
  72. package/dist/renderers/encoding.d.ts.map +1 -0
  73. package/dist/renderers/kroki-renderer.d.ts +27 -0
  74. package/dist/renderers/kroki-renderer.d.ts.map +1 -0
  75. package/dist/renderers/mermaid-ink-renderer.d.ts +24 -0
  76. package/dist/renderers/mermaid-ink-renderer.d.ts.map +1 -0
  77. package/dist/renderers/quickchart-renderer.d.ts +25 -0
  78. package/dist/renderers/quickchart-renderer.d.ts.map +1 -0
  79. package/dist/renderers/url-utils.d.ts +3 -0
  80. package/dist/renderers/url-utils.d.ts.map +1 -0
  81. package/dist/renderers.d.ts +12 -0
  82. package/dist/renderers.d.ts.map +1 -0
  83. package/dist/renderers.js +269 -0
  84. package/dist/renderers.js.map +1 -0
  85. package/dist/slack/fetch-slack-uploader.d.ts +52 -0
  86. package/dist/slack/fetch-slack-uploader.d.ts.map +1 -0
  87. package/dist/slack/slack-upload-error.d.ts +25 -0
  88. package/dist/slack/slack-upload-error.d.ts.map +1 -0
  89. package/dist/slack.d.ts +8 -0
  90. package/dist/slack.d.ts.map +1 -0
  91. package/dist/slack.js +255 -0
  92. package/dist/slack.js.map +1 -0
  93. package/dist/types.d.ts +202 -0
  94. package/dist/types.d.ts.map +1 -0
  95. package/dist/validate/validate-blocks.d.ts +18 -0
  96. package/dist/validate/validate-blocks.d.ts.map +1 -0
  97. package/package.json +76 -0
package/dist/slack.js ADDED
@@ -0,0 +1,255 @@
1
+ // src/slack/slack-upload-error.ts
2
+ var SlackUploadStage = {
3
+ GetUploadUrl: "get-upload-url",
4
+ UploadBytes: "upload-bytes",
5
+ CompleteUpload: "complete-upload",
6
+ FileInfo: "file-info",
7
+ ProcessingTimeout: "processing-timeout"
8
+ };
9
+ var SlackUploadError = class extends Error {
10
+ name;
11
+ stage;
12
+ status;
13
+ code;
14
+ constructor(message, details) {
15
+ super(message, details.cause !== void 0 ? { cause: details.cause } : void 0);
16
+ this.name = "SlackUploadError";
17
+ this.stage = details.stage;
18
+ this.status = details.status;
19
+ this.code = details.code;
20
+ }
21
+ };
22
+
23
+ // src/slack/fetch-slack-uploader.ts
24
+ var SLACK_API_BASE_URL = "https://slack.com/api";
25
+ var DEFAULT_POLL_INTERVAL_MS = 250;
26
+ var DEFAULT_POLL_MAX_ATTEMPTS = 20;
27
+ var DEFAULT_POLL_TIMEOUT_MS = 3e4;
28
+ var FetchSlackUploader = class {
29
+ token;
30
+ fetcher;
31
+ channelId;
32
+ pollIntervalMs;
33
+ pollMaxAttempts;
34
+ pollTimeoutMs;
35
+ sleep;
36
+ clock;
37
+ constructor(options) {
38
+ this.token = options.token;
39
+ this.fetcher = options.fetch ?? defaultFetch;
40
+ this.channelId = options.channelId;
41
+ this.pollIntervalMs = options.poll?.intervalMs ?? DEFAULT_POLL_INTERVAL_MS;
42
+ this.pollMaxAttempts = options.poll?.maxAttempts ?? DEFAULT_POLL_MAX_ATTEMPTS;
43
+ this.pollTimeoutMs = options.poll?.timeoutMs ?? DEFAULT_POLL_TIMEOUT_MS;
44
+ this.sleep = options.poll?.sleep ?? defaultSleep;
45
+ this.clock = options.poll?.clock ?? defaultClock;
46
+ validateOptions({
47
+ token: this.token,
48
+ pollIntervalMs: this.pollIntervalMs,
49
+ pollMaxAttempts: this.pollMaxAttempts,
50
+ pollTimeoutMs: this.pollTimeoutMs
51
+ });
52
+ }
53
+ async upload(img) {
54
+ const target = await this.getUploadTarget(img);
55
+ await this.uploadBytes(target, img);
56
+ await this.completeUpload(target.fileId, img.filename);
57
+ await this.waitUntilProcessed(target.fileId);
58
+ return { fileId: target.fileId };
59
+ }
60
+ async getUploadTarget(img) {
61
+ const payload = await this.callSlackApi(
62
+ "files.getUploadURLExternal",
63
+ encodeForm([
64
+ ["filename", img.filename],
65
+ ["length", String(img.data.byteLength)]
66
+ ]),
67
+ SlackUploadStage.GetUploadUrl
68
+ );
69
+ const uploadUrl = payload["upload_url"];
70
+ const fileId = payload["file_id"];
71
+ if (!isNonEmptyString(uploadUrl) || !isNonEmptyString(fileId)) {
72
+ throw new SlackUploadError("files.getUploadURLExternal returned no upload_url or file_id", {
73
+ stage: SlackUploadStage.GetUploadUrl,
74
+ code: "invalid_response"
75
+ });
76
+ }
77
+ return { uploadUrl, fileId };
78
+ }
79
+ async uploadBytes(target, img) {
80
+ let response;
81
+ try {
82
+ response = await this.fetcher(target.uploadUrl, {
83
+ method: "POST",
84
+ headers: { "content-type": img.mimeType },
85
+ body: img.data
86
+ });
87
+ } catch (cause) {
88
+ throw new SlackUploadError("Uploading bytes to Slack failed", {
89
+ stage: SlackUploadStage.UploadBytes,
90
+ code: "fetch_failed",
91
+ cause
92
+ });
93
+ }
94
+ if (!response.ok) {
95
+ throw new SlackUploadError(`Slack upload URL returned HTTP ${String(response.status)}`, {
96
+ stage: SlackUploadStage.UploadBytes,
97
+ status: response.status,
98
+ code: `http_${String(response.status)}`
99
+ });
100
+ }
101
+ }
102
+ async completeUpload(fileId, filename) {
103
+ const fields = [
104
+ [
105
+ "files",
106
+ JSON.stringify([
107
+ {
108
+ id: fileId,
109
+ title: filename
110
+ }
111
+ ])
112
+ ]
113
+ ];
114
+ if (this.channelId !== void 0) {
115
+ fields.push(["channel_id", this.channelId]);
116
+ }
117
+ await this.callSlackApi(
118
+ "files.completeUploadExternal",
119
+ encodeForm(fields),
120
+ SlackUploadStage.CompleteUpload
121
+ );
122
+ }
123
+ async waitUntilProcessed(fileId) {
124
+ const startedAt = this.clock();
125
+ for (let attempt = 1; attempt <= this.pollMaxAttempts; attempt += 1) {
126
+ const payload = await this.callSlackApi(
127
+ "files.info",
128
+ encodeForm([["file", fileId]]),
129
+ SlackUploadStage.FileInfo
130
+ );
131
+ if (isProcessedImageFile(payload["file"])) {
132
+ return;
133
+ }
134
+ if (attempt === this.pollMaxAttempts || this.clock() - startedAt >= this.pollTimeoutMs) {
135
+ throw processingTimeout(fileId, attempt);
136
+ }
137
+ try {
138
+ await this.sleep(this.pollIntervalMs);
139
+ } catch (cause) {
140
+ throw new SlackUploadError("Slack file-processing poll sleep failed", {
141
+ stage: SlackUploadStage.ProcessingTimeout,
142
+ code: "sleep_failed",
143
+ cause
144
+ });
145
+ }
146
+ if (this.clock() - startedAt >= this.pollTimeoutMs) {
147
+ throw processingTimeout(fileId, attempt);
148
+ }
149
+ }
150
+ }
151
+ async callSlackApi(method, body, stage) {
152
+ let response;
153
+ try {
154
+ response = await this.fetcher(`${SLACK_API_BASE_URL}/${method}`, {
155
+ method: "POST",
156
+ headers: {
157
+ authorization: `Bearer ${this.token}`,
158
+ "content-type": "application/x-www-form-urlencoded;charset=UTF-8"
159
+ },
160
+ body
161
+ });
162
+ } catch (cause) {
163
+ throw new SlackUploadError(`${method} request failed`, {
164
+ stage,
165
+ code: "fetch_failed",
166
+ cause
167
+ });
168
+ }
169
+ let payload;
170
+ try {
171
+ payload = await response.json();
172
+ } catch (cause) {
173
+ throw new SlackUploadError(`${method} returned invalid JSON`, {
174
+ stage,
175
+ status: response.status,
176
+ code: "invalid_json",
177
+ cause
178
+ });
179
+ }
180
+ const slackCode = getSlackErrorCode(payload);
181
+ if (!response.ok || !isRecord(payload) || payload["ok"] !== true) {
182
+ throw new SlackUploadError(`${method} was rejected by Slack`, {
183
+ stage,
184
+ status: response.status,
185
+ code: slackCode ?? (response.ok ? "invalid_response" : `http_${String(response.status)}`)
186
+ });
187
+ }
188
+ return payload;
189
+ }
190
+ };
191
+ function validateOptions(uploader) {
192
+ if (uploader.token.length === 0) {
193
+ throw new TypeError("token must not be empty");
194
+ }
195
+ if (!Number.isInteger(uploader.pollIntervalMs) || uploader.pollIntervalMs < 0) {
196
+ throw new RangeError("poll.intervalMs must be a non-negative integer");
197
+ }
198
+ if (!Number.isInteger(uploader.pollMaxAttempts) || uploader.pollMaxAttempts <= 0) {
199
+ throw new RangeError("poll.maxAttempts must be a positive integer");
200
+ }
201
+ if (!Number.isFinite(uploader.pollTimeoutMs) || uploader.pollTimeoutMs <= 0) {
202
+ throw new RangeError("poll.timeoutMs must be positive");
203
+ }
204
+ }
205
+ function encodeForm(fields) {
206
+ return fields.map(([name, value]) => `${encodeURIComponent(name)}=${encodeURIComponent(value)}`).join("&");
207
+ }
208
+ function isRecord(value) {
209
+ return typeof value === "object" && value !== null;
210
+ }
211
+ function isNonEmptyString(value) {
212
+ return typeof value === "string" && value.length > 0;
213
+ }
214
+ function isPositiveNumber(value) {
215
+ return typeof value === "number" && Number.isFinite(value) && value > 0;
216
+ }
217
+ function isProcessedImageFile(value) {
218
+ if (!isRecord(value)) {
219
+ return false;
220
+ }
221
+ return isNonEmptyString(value["mimetype"]) && isNonEmptyString(value["filetype"]) && isPositiveNumber(value["original_w"]) && isPositiveNumber(value["original_h"]);
222
+ }
223
+ function getSlackErrorCode(payload) {
224
+ if (!isRecord(payload)) {
225
+ return void 0;
226
+ }
227
+ const error = payload["error"];
228
+ return typeof error === "string" ? error : void 0;
229
+ }
230
+ function processingTimeout(fileId, attempts) {
231
+ return new SlackUploadError(
232
+ `Slack file ${fileId} was not processed after ${String(attempts)} polls`,
233
+ {
234
+ stage: SlackUploadStage.ProcessingTimeout,
235
+ code: "processing_timeout"
236
+ }
237
+ );
238
+ }
239
+ function defaultFetch(input, init) {
240
+ return globalThis.fetch(input, init);
241
+ }
242
+ function defaultSleep(milliseconds) {
243
+ return new Promise((resolve) => {
244
+ setTimeout(resolve, milliseconds);
245
+ });
246
+ }
247
+ function defaultClock() {
248
+ return Date.now();
249
+ }
250
+ export {
251
+ FetchSlackUploader,
252
+ SlackUploadError,
253
+ SlackUploadStage
254
+ };
255
+ //# sourceMappingURL=slack.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/slack/slack-upload-error.ts","../src/slack/fetch-slack-uploader.ts"],"sourcesContent":["export const SlackUploadStage = {\n GetUploadUrl: \"get-upload-url\",\n UploadBytes: \"upload-bytes\",\n CompleteUpload: \"complete-upload\",\n FileInfo: \"file-info\",\n ProcessingTimeout: \"processing-timeout\",\n} as const;\n\nexport type SlackUploadStage = (typeof SlackUploadStage)[keyof typeof SlackUploadStage];\n\nexport interface SlackUploadErrorDetails {\n readonly stage: SlackUploadStage;\n readonly status?: number;\n readonly code?: string;\n readonly cause?: unknown;\n}\n\n/**\n * Integration error from one explicit stage of Slack's external-upload flow.\n */\nexport class SlackUploadError extends Error {\n override readonly name: string;\n readonly stage: SlackUploadStage;\n readonly status: number | undefined;\n readonly code: string | undefined;\n\n constructor(message: string, details: SlackUploadErrorDetails) {\n super(message, details.cause !== undefined ? { cause: details.cause } : undefined);\n this.name = \"SlackUploadError\";\n this.stage = details.stage;\n this.status = details.status;\n this.code = details.code;\n }\n}\n","import type { BytesImage, SlackUploader } from \"../types.js\";\n\nimport {\n SlackUploadError,\n SlackUploadStage,\n type SlackUploadStage as SlackUploadStageType,\n} from \"./slack-upload-error.js\";\n\nconst SLACK_API_BASE_URL = \"https://slack.com/api\";\nconst DEFAULT_POLL_INTERVAL_MS = 250;\nconst DEFAULT_POLL_MAX_ATTEMPTS = 20;\nconst DEFAULT_POLL_TIMEOUT_MS = 30_000;\n\nexport interface SlackFetchRequestInit {\n readonly method: \"POST\";\n readonly headers: Readonly<Record<string, string>>;\n readonly body: string | Uint8Array;\n}\n\nexport interface SlackFetchResponse {\n readonly ok: boolean;\n readonly status: number;\n json(): Promise<unknown>;\n}\n\nexport type SlackFetch = (\n input: string,\n init: SlackFetchRequestInit,\n) => Promise<SlackFetchResponse>;\n\nexport type SlackUploadSleep = (milliseconds: number) => Promise<void>;\nexport type SlackUploadClock = () => number;\n\nexport interface SlackUploadPollOptions {\n readonly intervalMs?: number;\n readonly maxAttempts?: number;\n readonly timeoutMs?: number;\n readonly sleep?: SlackUploadSleep;\n readonly clock?: SlackUploadClock;\n}\n\nexport interface FetchSlackUploaderOptions {\n readonly token: string;\n readonly fetch?: SlackFetch;\n readonly channelId?: string;\n readonly poll?: SlackUploadPollOptions;\n}\n\ninterface UploadTarget {\n readonly uploadUrl: string;\n readonly fileId: string;\n}\n\n/**\n * Web-standard implementation of Slack's external file-upload flow.\n *\n * @see https://docs.slack.dev/messaging/working-with-files\n */\nexport class FetchSlackUploader implements SlackUploader {\n private readonly token: string;\n private readonly fetcher: SlackFetch;\n private readonly channelId: string | undefined;\n private readonly pollIntervalMs: number;\n private readonly pollMaxAttempts: number;\n private readonly pollTimeoutMs: number;\n private readonly sleep: SlackUploadSleep;\n private readonly clock: SlackUploadClock;\n\n constructor(options: FetchSlackUploaderOptions) {\n this.token = options.token;\n this.fetcher = options.fetch ?? defaultFetch;\n this.channelId = options.channelId;\n this.pollIntervalMs = options.poll?.intervalMs ?? DEFAULT_POLL_INTERVAL_MS;\n this.pollMaxAttempts = options.poll?.maxAttempts ?? DEFAULT_POLL_MAX_ATTEMPTS;\n this.pollTimeoutMs = options.poll?.timeoutMs ?? DEFAULT_POLL_TIMEOUT_MS;\n this.sleep = options.poll?.sleep ?? defaultSleep;\n this.clock = options.poll?.clock ?? defaultClock;\n\n validateOptions({\n token: this.token,\n pollIntervalMs: this.pollIntervalMs,\n pollMaxAttempts: this.pollMaxAttempts,\n pollTimeoutMs: this.pollTimeoutMs,\n });\n }\n\n async upload(img: BytesImage): Promise<{ readonly fileId: string }> {\n const target = await this.getUploadTarget(img);\n await this.uploadBytes(target, img);\n await this.completeUpload(target.fileId, img.filename);\n await this.waitUntilProcessed(target.fileId);\n return { fileId: target.fileId };\n }\n\n private async getUploadTarget(img: BytesImage): Promise<UploadTarget> {\n const payload = await this.callSlackApi(\n \"files.getUploadURLExternal\",\n encodeForm([\n [\"filename\", img.filename],\n [\"length\", String(img.data.byteLength)],\n ]),\n SlackUploadStage.GetUploadUrl,\n );\n const uploadUrl = payload[\"upload_url\"];\n const fileId = payload[\"file_id\"];\n if (!isNonEmptyString(uploadUrl) || !isNonEmptyString(fileId)) {\n throw new SlackUploadError(\"files.getUploadURLExternal returned no upload_url or file_id\", {\n stage: SlackUploadStage.GetUploadUrl,\n code: \"invalid_response\",\n });\n }\n return { uploadUrl, fileId };\n }\n\n private async uploadBytes(target: UploadTarget, img: BytesImage): Promise<void> {\n let response: SlackFetchResponse;\n try {\n response = await this.fetcher(target.uploadUrl, {\n method: \"POST\",\n headers: { \"content-type\": img.mimeType },\n body: img.data,\n });\n } catch (cause) {\n throw new SlackUploadError(\"Uploading bytes to Slack failed\", {\n stage: SlackUploadStage.UploadBytes,\n code: \"fetch_failed\",\n cause,\n });\n }\n if (!response.ok) {\n throw new SlackUploadError(`Slack upload URL returned HTTP ${String(response.status)}`, {\n stage: SlackUploadStage.UploadBytes,\n status: response.status,\n code: `http_${String(response.status)}`,\n });\n }\n }\n\n private async completeUpload(fileId: string, filename: string): Promise<void> {\n const fields: Array<readonly [string, string]> = [\n [\n \"files\",\n JSON.stringify([\n {\n id: fileId,\n title: filename,\n },\n ]),\n ],\n ];\n if (this.channelId !== undefined) {\n fields.push([\"channel_id\", this.channelId]);\n }\n await this.callSlackApi(\n \"files.completeUploadExternal\",\n encodeForm(fields),\n SlackUploadStage.CompleteUpload,\n );\n }\n\n private async waitUntilProcessed(fileId: string): Promise<void> {\n const startedAt = this.clock();\n\n for (let attempt = 1; attempt <= this.pollMaxAttempts; attempt += 1) {\n const payload = await this.callSlackApi(\n \"files.info\",\n encodeForm([[\"file\", fileId]]),\n SlackUploadStage.FileInfo,\n );\n if (isProcessedImageFile(payload[\"file\"])) {\n return;\n }\n\n if (attempt === this.pollMaxAttempts || this.clock() - startedAt >= this.pollTimeoutMs) {\n throw processingTimeout(fileId, attempt);\n }\n\n try {\n await this.sleep(this.pollIntervalMs);\n } catch (cause) {\n throw new SlackUploadError(\"Slack file-processing poll sleep failed\", {\n stage: SlackUploadStage.ProcessingTimeout,\n code: \"sleep_failed\",\n cause,\n });\n }\n\n if (this.clock() - startedAt >= this.pollTimeoutMs) {\n throw processingTimeout(fileId, attempt);\n }\n }\n }\n\n private async callSlackApi(\n method: string,\n body: string,\n stage: SlackUploadStageType,\n ): Promise<Record<string, unknown>> {\n let response: SlackFetchResponse;\n try {\n response = await this.fetcher(`${SLACK_API_BASE_URL}/${method}`, {\n method: \"POST\",\n headers: {\n authorization: `Bearer ${this.token}`,\n \"content-type\": \"application/x-www-form-urlencoded;charset=UTF-8\",\n },\n body,\n });\n } catch (cause) {\n throw new SlackUploadError(`${method} request failed`, {\n stage,\n code: \"fetch_failed\",\n cause,\n });\n }\n\n let payload: unknown;\n try {\n payload = await response.json();\n } catch (cause) {\n throw new SlackUploadError(`${method} returned invalid JSON`, {\n stage,\n status: response.status,\n code: \"invalid_json\",\n cause,\n });\n }\n\n const slackCode = getSlackErrorCode(payload);\n if (!response.ok || !isRecord(payload) || payload[\"ok\"] !== true) {\n throw new SlackUploadError(`${method} was rejected by Slack`, {\n stage,\n status: response.status,\n code: slackCode ?? (response.ok ? \"invalid_response\" : `http_${String(response.status)}`),\n });\n }\n return payload;\n }\n}\n\nfunction validateOptions(uploader: {\n readonly token: string;\n readonly pollIntervalMs: number;\n readonly pollMaxAttempts: number;\n readonly pollTimeoutMs: number;\n}): void {\n if (uploader.token.length === 0) {\n throw new TypeError(\"token must not be empty\");\n }\n if (!Number.isInteger(uploader.pollIntervalMs) || uploader.pollIntervalMs < 0) {\n throw new RangeError(\"poll.intervalMs must be a non-negative integer\");\n }\n if (!Number.isInteger(uploader.pollMaxAttempts) || uploader.pollMaxAttempts <= 0) {\n throw new RangeError(\"poll.maxAttempts must be a positive integer\");\n }\n if (!Number.isFinite(uploader.pollTimeoutMs) || uploader.pollTimeoutMs <= 0) {\n throw new RangeError(\"poll.timeoutMs must be positive\");\n }\n}\n\nfunction encodeForm(fields: ReadonlyArray<readonly [string, string]>): string {\n return fields\n .map(([name, value]) => `${encodeURIComponent(name)}=${encodeURIComponent(value)}`)\n .join(\"&\");\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null;\n}\n\nfunction isNonEmptyString(value: unknown): value is string {\n return typeof value === \"string\" && value.length > 0;\n}\n\nfunction isPositiveNumber(value: unknown): value is number {\n return typeof value === \"number\" && Number.isFinite(value) && value > 0;\n}\n\nfunction isProcessedImageFile(value: unknown): boolean {\n if (!isRecord(value)) {\n return false;\n }\n return (\n isNonEmptyString(value[\"mimetype\"]) &&\n isNonEmptyString(value[\"filetype\"]) &&\n isPositiveNumber(value[\"original_w\"]) &&\n isPositiveNumber(value[\"original_h\"])\n );\n}\n\nfunction getSlackErrorCode(payload: unknown): string | undefined {\n if (!isRecord(payload)) {\n return undefined;\n }\n const error = payload[\"error\"];\n return typeof error === \"string\" ? error : undefined;\n}\n\nfunction processingTimeout(fileId: string, attempts: number): SlackUploadError {\n return new SlackUploadError(\n `Slack file ${fileId} was not processed after ${String(attempts)} polls`,\n {\n stage: SlackUploadStage.ProcessingTimeout,\n code: \"processing_timeout\",\n },\n );\n}\n\nfunction defaultFetch(input: string, init: SlackFetchRequestInit): Promise<SlackFetchResponse> {\n return globalThis.fetch(input, init);\n}\n\nfunction defaultSleep(milliseconds: number): Promise<void> {\n return new Promise((resolve) => {\n setTimeout(resolve, milliseconds);\n });\n}\n\nfunction defaultClock(): number {\n return Date.now();\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,202 @@
1
+ import type { Root } from "mdast";
2
+ import type { Block } from "./blocks/types.js";
3
+ import type { CapabilityFlags, CapabilityPresetName } from "./capabilities/capabilities.js";
4
+ /**
5
+ * Structured degradation emitted when content falls back or is truncated.
6
+ */
7
+ export interface Degradation {
8
+ readonly nodeType: string;
9
+ readonly from: string;
10
+ readonly to: string;
11
+ readonly reason: string;
12
+ readonly path: string;
13
+ }
14
+ /**
15
+ * Total conversion result — never throws on user markdown.
16
+ */
17
+ export interface ConversionResult {
18
+ readonly blocks: ReadonlyArray<Block>;
19
+ readonly text: string;
20
+ readonly degradations: ReadonlyArray<Degradation>;
21
+ }
22
+ /**
23
+ * One message chunk from multi-message conversion.
24
+ */
25
+ export interface ConversionMessage {
26
+ readonly blocks: ReadonlyArray<Block>;
27
+ readonly text: string;
28
+ }
29
+ /**
30
+ * Multi-message conversion result.
31
+ */
32
+ export interface ConversionMessagesResult {
33
+ readonly messages: ReadonlyArray<ConversionMessage>;
34
+ readonly degradations: ReadonlyArray<Degradation>;
35
+ }
36
+ export declare const OverflowMode: {
37
+ readonly Degrade: "degrade";
38
+ readonly Split: "split";
39
+ };
40
+ export type OverflowMode = (typeof OverflowMode)[keyof typeof OverflowMode];
41
+ export declare const ConversionStrategy: {
42
+ readonly RichTextFirst: "rich-text-first";
43
+ readonly MarkdownBlock: "markdown-block";
44
+ };
45
+ export type ConversionStrategy = (typeof ConversionStrategy)[keyof typeof ConversionStrategy];
46
+ /**
47
+ * Request passed to {@link ImageRenderer}.
48
+ */
49
+ export interface RenderRequest {
50
+ readonly lang: string;
51
+ readonly source: string;
52
+ readonly altText: string;
53
+ }
54
+ export type BytesImage = {
55
+ readonly kind: "bytes";
56
+ readonly data: Uint8Array;
57
+ readonly mimeType: "image/png" | "image/jpeg" | "image/gif";
58
+ readonly filename: string;
59
+ };
60
+ export type UrlImage = {
61
+ readonly kind: "url";
62
+ readonly imageUrl: string;
63
+ };
64
+ export type RenderedImage = UrlImage | BytesImage;
65
+ /**
66
+ * Pluggable image renderer for mermaid/math/diagram fences (phase-2 adapters).
67
+ */
68
+ export interface ImageRenderer {
69
+ canRender(req: RenderRequest): boolean;
70
+ render(req: RenderRequest): Promise<(RenderedImage & {
71
+ readonly altText: string;
72
+ }) | null>;
73
+ }
74
+ /**
75
+ * Uploads bytes-producing renderer output to Slack files API.
76
+ */
77
+ export interface SlackUploader {
78
+ upload(img: BytesImage): Promise<{
79
+ readonly fileId: string;
80
+ }>;
81
+ }
82
+ /**
83
+ * Optional mention resolvers (off by default).
84
+ */
85
+ export interface MentionResolvers {
86
+ readonly resolveUser?: (handle: string) => string | undefined;
87
+ readonly resolveChannel?: (name: string) => string | undefined;
88
+ }
89
+ /**
90
+ * Public conversion options (per-call).
91
+ * Custom adapters are wired via {@link createConverter}, not per-call options.
92
+ */
93
+ export interface ConvertOptions {
94
+ readonly capabilities?: CapabilityPresetName | CapabilityFlags | CapabilityFlagsPartial | undefined;
95
+ readonly capabilityOverrides?: CapabilityFlagsPartial | undefined;
96
+ readonly overflow?: OverflowMode | undefined;
97
+ readonly strategy?: ConversionStrategy | undefined;
98
+ readonly renderers?: ReadonlyArray<ImageRenderer> | undefined;
99
+ readonly uploader?: SlackUploader | undefined;
100
+ readonly enableMath?: boolean | undefined;
101
+ readonly enableFrontmatter?: boolean | undefined;
102
+ readonly mentionResolvers?: MentionResolvers | undefined;
103
+ }
104
+ export type CapabilityFlagsPartial = {
105
+ readonly [K in keyof CapabilityFlags]?: boolean;
106
+ };
107
+ /**
108
+ * Collects degradations during a single conversion.
109
+ */
110
+ export interface DegradationCollector {
111
+ add(d: Degradation): void;
112
+ all(): ReadonlyArray<Degradation>;
113
+ }
114
+ /**
115
+ * Budget reservation claimed while planning a candidate.
116
+ */
117
+ export interface BudgetClaim {
118
+ readonly blocks?: number;
119
+ readonly tableChars?: number;
120
+ readonly dataTableChars?: number;
121
+ readonly markdownChars?: number;
122
+ readonly chart?: boolean;
123
+ readonly totalChars?: number;
124
+ }
125
+ /**
126
+ * Message-wide budget ledger.
127
+ */
128
+ export interface BudgetLedger {
129
+ readonly maxBlocks: number;
130
+ tryReserveBlocks(count: number): boolean;
131
+ tryReserveTableChars(chars: number): boolean;
132
+ tryReserveDataTableChars(chars: number): boolean;
133
+ tryReserveMarkdownChars(chars: number): boolean;
134
+ tryReserveChart(): boolean;
135
+ tryReserveTotalChars(chars: number): boolean;
136
+ tryReserveClaim(claim: BudgetClaim | undefined): boolean;
137
+ remainingBlocks(): number;
138
+ snapshot(): BudgetSnapshot;
139
+ /** Restore counters to a prior {@link snapshot} (e.g. after an empty emit). */
140
+ restore(snapshot: BudgetSnapshot): void;
141
+ resetForNewMessage(): void;
142
+ }
143
+ export interface BudgetSnapshot {
144
+ readonly blocks: number;
145
+ readonly tableChars: number;
146
+ readonly dataTableChars: number;
147
+ readonly markdownChars: number;
148
+ readonly charts: number;
149
+ readonly totalChars: number;
150
+ }
151
+ /**
152
+ * Deterministic markdown → plain text for notification fallbacks.
153
+ */
154
+ export interface PlainTextRenderer {
155
+ render(markdown: string): string;
156
+ renderFromBlocks(blocks: ReadonlyArray<Block>): string;
157
+ }
158
+ /**
159
+ * Swappable markdown parser (wraps remark by default).
160
+ */
161
+ export interface MarkdownParser {
162
+ parse(markdown: string, options: ParserOptions): Promise<Root>;
163
+ }
164
+ export interface ParserOptions {
165
+ readonly enableMath: boolean;
166
+ readonly enableFrontmatter: boolean;
167
+ }
168
+ /**
169
+ * Mermaid chart grammar parser (pie / xychart).
170
+ */
171
+ export interface MermaidChartParser {
172
+ readonly diagramType: "pie" | "xychart-beta";
173
+ parse(source: string): MermaidParseResult;
174
+ }
175
+ export type MermaidParseResult = {
176
+ readonly ok: true;
177
+ readonly value: MermaidPieAst | MermaidXyChartAst;
178
+ } | {
179
+ readonly ok: false;
180
+ readonly reason: string;
181
+ };
182
+ export interface MermaidPieAst {
183
+ readonly kind: "pie";
184
+ readonly title: string | undefined;
185
+ readonly showData: boolean;
186
+ readonly segments: ReadonlyArray<{
187
+ readonly label: string;
188
+ readonly value: number;
189
+ }>;
190
+ }
191
+ export interface MermaidXyChartAst {
192
+ readonly kind: "xychart-beta";
193
+ readonly title: string | undefined;
194
+ readonly categories: ReadonlyArray<string>;
195
+ readonly xLabel: string | undefined;
196
+ readonly yLabel: string | undefined;
197
+ readonly yMin: number | undefined;
198
+ readonly yMax: number | undefined;
199
+ readonly bars: ReadonlyArray<ReadonlyArray<number>>;
200
+ readonly lines: ReadonlyArray<ReadonlyArray<number>>;
201
+ }
202
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ import type { Block } from "../blocks/types.js";
2
+ export interface ValidationIssue {
3
+ readonly path: string;
4
+ readonly message: string;
5
+ }
6
+ declare const validatedBlocksBrand: unique symbol;
7
+ /**
8
+ * Blocks that have passed {@link validateBlocks}.
9
+ */
10
+ export type ValidatedBlocks = ReadonlyArray<Block> & {
11
+ readonly [validatedBlocksBrand]: true;
12
+ };
13
+ /**
14
+ * Assert every documented Block Kit limit from the research doc.
15
+ */
16
+ export declare function validateBlocks(blocks: ReadonlyArray<Block>): ValidatedBlocks;
17
+ export {};
18
+ //# sourceMappingURL=validate-blocks.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validate-blocks.d.ts","sourceRoot":"","sources":["../../src/validate/validate-blocks.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAa,MAAM,oBAAoB,CAAC;AAwB3D,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AAED,OAAO,CAAC,MAAM,oBAAoB,EAAE,OAAO,MAAM,CAAC;AAElD;;GAEG;AACH,MAAM,MAAM,eAAe,GAAG,aAAa,CAAC,KAAK,CAAC,GAAG;IACnD,QAAQ,CAAC,CAAC,oBAAoB,CAAC,EAAE,IAAI,CAAC;CACvC,CAAC;AAEF;;GAEG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,aAAa,CAAC,KAAK,CAAC,GAAG,eAAe,CAmI5E"}
package/package.json ADDED
@@ -0,0 +1,76 @@
1
+ {
2
+ "name": "slackmark",
3
+ "version": "0.1.0",
4
+ "description": "Compile SlackMark (CommonMark and GFM plus Slack extensions) to Slack Block Kit JSON",
5
+ "keywords": [
6
+ "block kit",
7
+ "blockkit",
8
+ "gfm",
9
+ "gfm-to-slack",
10
+ "markdown",
11
+ "mrkdwn",
12
+ "slack"
13
+ ],
14
+ "license": "MIT",
15
+ "author": "Siraj",
16
+ "repository": {
17
+ "type": "git",
18
+ "url": "git+https://github.com/SirajChokshi/slackmark.git",
19
+ "directory": "packages/core"
20
+ },
21
+ "files": [
22
+ "dist",
23
+ "LICENSE",
24
+ "README.md"
25
+ ],
26
+ "type": "module",
27
+ "sideEffects": false,
28
+ "exports": {
29
+ ".": {
30
+ "types": "./dist/index.d.ts",
31
+ "default": "./dist/index.js"
32
+ },
33
+ "./renderers": {
34
+ "types": "./dist/renderers.d.ts",
35
+ "default": "./dist/renderers.js"
36
+ },
37
+ "./slack": {
38
+ "types": "./dist/slack.d.ts",
39
+ "default": "./dist/slack.js"
40
+ },
41
+ "./package.json": "./package.json"
42
+ },
43
+ "publishConfig": {
44
+ "access": "public"
45
+ },
46
+ "dependencies": {
47
+ "mdast-util-from-markdown": "^2.0.3",
48
+ "mdast-util-gfm": "^3.1.0",
49
+ "mdast-util-to-string": "^4.0.0",
50
+ "micromark-extension-gfm": "^3.0.0",
51
+ "remark-frontmatter": "^5.0.0",
52
+ "remark-gfm": "^4.0.1",
53
+ "remark-math": "^6.0.0",
54
+ "remark-parse": "^11.0.0",
55
+ "unified": "^11.0.5",
56
+ "unist-util-visit": "^5.1.0"
57
+ },
58
+ "devDependencies": {
59
+ "@slack/types": "^3.0.0",
60
+ "@types/mdast": "^4.0.4",
61
+ "@types/node": "^22.15.30",
62
+ "@types/unist": "^3.0.3",
63
+ "tsup": "^8.5.1",
64
+ "vitest": "^4.1.7"
65
+ },
66
+ "engines": {
67
+ "node": "^20.19.0 || >=22.12.0"
68
+ },
69
+ "scripts": {
70
+ "build": "tsup && tsc -p tsconfig.build.json",
71
+ "test": "vitest run",
72
+ "test:watch": "vitest",
73
+ "typecheck": "tsc -p tsconfig.json --noEmit && tsc -p tsconfig.test.json --noEmit",
74
+ "typecheck:src": "tsc -p tsconfig.json --noEmit"
75
+ }
76
+ }