@pithy-sh/support 0.1.2 → 0.1.4

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 (170) hide show
  1. package/dist/ai/classify.d.ts +92 -0
  2. package/dist/ai/classify.d.ts.map +1 -0
  3. package/dist/ai/classify.js +153 -0
  4. package/dist/attachment/store.d.ts +55 -0
  5. package/dist/attachment/store.d.ts.map +1 -0
  6. package/dist/attachment/store.js +69 -0
  7. package/dist/audit/actions.d.ts +70 -0
  8. package/dist/audit/actions.d.ts.map +1 -0
  9. package/dist/audit/actions.js +70 -0
  10. package/dist/capability.d.ts +95 -0
  11. package/dist/capability.d.ts.map +1 -0
  12. package/dist/capability.js +189 -0
  13. package/dist/client/projection.d.ts +58 -0
  14. package/dist/client/projection.d.ts.map +1 -0
  15. package/dist/client/projection.js +2 -0
  16. package/dist/config/config.d.ts +217 -0
  17. package/dist/config/config.d.ts.map +1 -0
  18. package/dist/config/config.js +171 -0
  19. package/dist/data/attachment.d.ts +32 -0
  20. package/dist/data/attachment.d.ts.map +1 -0
  21. package/dist/data/attachment.js +34 -0
  22. package/dist/data/billingScope.d.ts +32 -0
  23. package/dist/data/billingScope.d.ts.map +1 -0
  24. package/dist/data/billingScope.js +34 -0
  25. package/dist/data/categories.d.ts +56 -0
  26. package/dist/data/categories.d.ts.map +1 -0
  27. package/dist/data/categories.js +99 -0
  28. package/dist/data/classification.d.ts +36 -0
  29. package/dist/data/classification.d.ts.map +1 -0
  30. package/dist/data/classification.js +30 -0
  31. package/dist/data/enums.d.ts +84 -0
  32. package/dist/data/enums.d.ts.map +1 -0
  33. package/dist/data/enums.js +72 -0
  34. package/dist/data/flag.d.ts +27 -0
  35. package/dist/data/flag.d.ts.map +1 -0
  36. package/dist/data/flag.js +29 -0
  37. package/dist/data/message.d.ts +83 -0
  38. package/dist/data/message.d.ts.map +1 -0
  39. package/dist/data/message.js +86 -0
  40. package/dist/data/tables.d.ts +162 -0
  41. package/dist/data/tables.d.ts.map +1 -0
  42. package/dist/data/tables.js +46 -0
  43. package/dist/data/thread.d.ts +79 -0
  44. package/dist/data/thread.d.ts.map +1 -0
  45. package/dist/data/thread.js +67 -0
  46. package/dist/error/errors.d.ts +66 -0
  47. package/dist/error/errors.d.ts.map +1 -0
  48. package/dist/error/errors.js +84 -0
  49. package/dist/http/guards.d.ts +46 -0
  50. package/dist/http/guards.d.ts.map +1 -0
  51. package/dist/http/guards.js +55 -0
  52. package/dist/http/handlers.d.ts +91 -0
  53. package/dist/http/handlers.d.ts.map +1 -0
  54. package/dist/http/handlers.js +250 -0
  55. package/dist/http/resolve.d.ts +46 -0
  56. package/dist/http/resolve.d.ts.map +1 -0
  57. package/dist/http/resolve.js +74 -0
  58. package/dist/http/responses.d.ts +831 -0
  59. package/dist/http/responses.d.ts.map +1 -0
  60. package/dist/http/responses.js +305 -0
  61. package/dist/http/routes.d.ts +111 -0
  62. package/dist/http/routes.d.ts.map +1 -0
  63. package/dist/http/routes.js +64 -0
  64. package/dist/http/schemas.d.ts +123 -0
  65. package/dist/http/schemas.d.ts.map +1 -0
  66. package/dist/http/schemas.js +91 -0
  67. package/dist/http/scopes.d.ts +58 -0
  68. package/dist/http/scopes.d.ts.map +1 -0
  69. package/dist/http/scopes.js +109 -0
  70. package/dist/http/views.d.ts +38 -0
  71. package/dist/http/views.d.ts.map +1 -0
  72. package/dist/http/views.js +146 -0
  73. package/dist/inbound/authenticity.d.ts +83 -0
  74. package/dist/inbound/authenticity.d.ts.map +1 -0
  75. package/dist/inbound/authenticity.js +63 -0
  76. package/dist/inbound/guard.d.ts +76 -0
  77. package/dist/inbound/guard.d.ts.map +1 -0
  78. package/dist/inbound/guard.js +80 -0
  79. package/dist/inbound/handler.d.ts +30 -0
  80. package/dist/inbound/handler.d.ts.map +1 -0
  81. package/dist/inbound/handler.js +84 -0
  82. package/dist/inbound/ingest.d.ts +106 -0
  83. package/dist/inbound/ingest.d.ts.map +1 -0
  84. package/dist/inbound/ingest.js +328 -0
  85. package/dist/inbound/recipient.d.ts +18 -0
  86. package/dist/inbound/recipient.d.ts.map +1 -0
  87. package/dist/inbound/recipient.js +48 -0
  88. package/dist/index.d.ts +22 -0
  89. package/dist/index.d.ts.map +1 -0
  90. package/dist/index.js +16 -0
  91. package/dist/link/sender.d.ts +162 -0
  92. package/dist/link/sender.d.ts.map +1 -0
  93. package/dist/link/sender.js +202 -0
  94. package/dist/migrations/0001_threads.d.ts +28 -0
  95. package/dist/migrations/0001_threads.d.ts.map +1 -0
  96. package/dist/migrations/0001_threads.js +105 -0
  97. package/dist/mime/address.d.ts +24 -0
  98. package/dist/mime/address.d.ts.map +1 -0
  99. package/dist/mime/address.js +30 -0
  100. package/dist/mime/parse.d.ts +98 -0
  101. package/dist/mime/parse.d.ts.map +1 -0
  102. package/dist/mime/parse.js +148 -0
  103. package/dist/mime/sanitize.d.ts +27 -0
  104. package/dist/mime/sanitize.d.ts.map +1 -0
  105. package/dist/mime/sanitize.js +214 -0
  106. package/dist/mime/threading.d.ts +81 -0
  107. package/dist/mime/threading.d.ts.map +1 -0
  108. package/dist/mime/threading.js +113 -0
  109. package/dist/mime/truncate.d.ts +19 -0
  110. package/dist/mime/truncate.d.ts.map +1 -0
  111. package/dist/mime/truncate.js +49 -0
  112. package/dist/provision/provisionSupport.d.ts +160 -0
  113. package/dist/provision/provisionSupport.d.ts.map +1 -0
  114. package/dist/provision/provisionSupport.js +112 -0
  115. package/dist/provision/resolveSupportConfig.d.ts +47 -0
  116. package/dist/provision/resolveSupportConfig.d.ts.map +1 -0
  117. package/dist/provision/resolveSupportConfig.js +24 -0
  118. package/dist/reply/send.d.ts +125 -0
  119. package/dist/reply/send.d.ts.map +1 -0
  120. package/dist/reply/send.js +155 -0
  121. package/dist/reply/snippets.d.ts +81 -0
  122. package/dist/reply/snippets.d.ts.map +1 -0
  123. package/dist/reply/snippets.js +137 -0
  124. package/dist/secret/registry.d.ts +20 -0
  125. package/dist/secret/registry.d.ts.map +1 -0
  126. package/dist/secret/registry.js +23 -0
  127. package/dist/seeds/example.d.ts +5 -0
  128. package/dist/seeds/example.d.ts.map +1 -0
  129. package/dist/seeds/example.js +352 -0
  130. package/dist/store/paging.d.ts +20 -0
  131. package/dist/store/paging.d.ts.map +1 -0
  132. package/dist/store/paging.js +22 -0
  133. package/dist/store/search.d.ts +69 -0
  134. package/dist/store/search.d.ts.map +1 -0
  135. package/dist/store/search.js +162 -0
  136. package/dist/store/searchIndex.d.ts +55 -0
  137. package/dist/store/searchIndex.d.ts.map +1 -0
  138. package/dist/store/searchIndex.js +68 -0
  139. package/dist/store/threads.d.ts +149 -0
  140. package/dist/store/threads.d.ts.map +1 -0
  141. package/dist/store/threads.js +199 -0
  142. package/dist/submission/encoding.d.ts +23 -0
  143. package/dist/submission/encoding.d.ts.map +1 -0
  144. package/dist/submission/encoding.js +57 -0
  145. package/dist/submission/guard.d.ts +73 -0
  146. package/dist/submission/guard.d.ts.map +1 -0
  147. package/dist/submission/guard.js +48 -0
  148. package/dist/submission/submit.d.ts +154 -0
  149. package/dist/submission/submit.d.ts.map +1 -0
  150. package/dist/submission/submit.js +321 -0
  151. package/dist/version.generated.d.ts +7 -0
  152. package/dist/version.generated.d.ts.map +1 -0
  153. package/dist/version.generated.js +9 -0
  154. package/dist/workflows/classify.d.ts +65 -0
  155. package/dist/workflows/classify.d.ts.map +1 -0
  156. package/dist/workflows/classify.js +70 -0
  157. package/dist/workflows/retryPolicy.d.ts +41 -0
  158. package/dist/workflows/retryPolicy.d.ts.map +1 -0
  159. package/dist/workflows/retryPolicy.js +45 -0
  160. package/dist/workflows/specs.d.ts +45 -0
  161. package/dist/workflows/specs.d.ts.map +1 -0
  162. package/dist/workflows/specs.js +48 -0
  163. package/dist/workflows/worker.d.ts +50 -0
  164. package/dist/workflows/worker.d.ts.map +1 -0
  165. package/dist/workflows/worker.js +39 -0
  166. package/package.json +24 -15
  167. package/src/http/handlers.ts +1 -1
  168. package/src/submission/encoding.ts +1 -1
  169. package/src/submission/submit.ts +1 -1
  170. package/src/version.generated.ts +1 -1
@@ -0,0 +1,48 @@
1
+ // SPDX-FileCopyrightText: 2026 Pithy
2
+ // SPDX-License-Identifier: MIT
3
+ import { z } from "zod";
4
+ import { workflowKey } from "@pithy-sh/core/src/workflow/naming";
5
+ //#region src/workflows/specs.ts
6
+ /**
7
+ * The one durable job support owns, declared once.
8
+ *
9
+ * **Classification is a Workflow, not part of the `email()` handler**, and that is a hard constraint
10
+ * rather than a preference. An inbound handler runs under a tight CPU budget; a model call is
11
+ * hundreds of milliseconds of wall time it cannot spend, and a model that is slow or briefly
12
+ * unavailable would take the *persistence* of the message down with it. So the handler does the
13
+ * cheap, must-not-fail half — parse, bound, store — and hands off. A classification that fails
14
+ * retries against a message that is already safely in D1.
15
+ *
16
+ * `optional: true`: the Workflow lives in the prebuilt support worker that `pithy support provision`
17
+ * deploys, so a project that has not provisioned must still boot and still receive mail. An absent
18
+ * binding degrades to a logged skip and a thread that stays `uncategorized` — which is exactly the
19
+ * state a classification is allowed to be in.
20
+ */
21
+ /** The capability name — the first segment of the dispatch key and of every deployed workflow name. */
22
+ const SUPPORT_CAPABILITY = "support";
23
+ /** Which message to classify. */
24
+ const SupportClassifyParams = z.object({ messageId: z.string().min(1).describe("The `pithy_support_messages.id` to classify. The Workflow reads that message, asks the model about it, appends a classification row, and denormalizes the answer onto its thread.") }).describe("The instance parameters of the classification Workflow — the one message it runs against.");
25
+ /** Support's durable jobs, keyed by job name. The key is the second segment of the `support/<job>` dispatch key. */
26
+ const supportWorkflows = { classify: {
27
+ binding: "SUPPORT_CLASSIFY",
28
+ className: "SupportClassifyWorkflow",
29
+ params: SupportClassifyParams,
30
+ optional: true
31
+ } };
32
+ /**
33
+ * Support's jobs as a dispatch registry, keyed `support/<job>`. Built here rather than through
34
+ * `composeWorkflows` because the inbound handler dispatches from inside the capability, before any
35
+ * project-wide registry exists — and the key format comes from core's {@link workflowKey} either
36
+ * way, so the two cannot drift.
37
+ */
38
+ const supportWorkflowRegistry = Object.fromEntries(Object.entries(supportWorkflows).map(([job, spec]) => {
39
+ const key = workflowKey(SUPPORT_CAPABILITY, job);
40
+ return [key, {
41
+ key,
42
+ capability: SUPPORT_CAPABILITY,
43
+ job,
44
+ spec
45
+ }];
46
+ }));
47
+ //#endregion
48
+ export { SUPPORT_CAPABILITY, SupportClassifyParams, supportWorkflowRegistry, supportWorkflows };
@@ -0,0 +1,50 @@
1
+ // SPDX-FileCopyrightText: 2026 Pithy
2
+ // SPDX-License-Identifier: MIT
3
+ import { WorkflowEntrypoint, type WorkflowEvent, type WorkflowStep } from "cloudflare:workers";
4
+ import type { D1Database } from "@cloudflare/workers-types";
5
+ import type { SupportAi } from "../ai/classify";
6
+ /**
7
+ * The prebuilt support worker. `pithy support provision` deploys one per environment; the adopter
8
+ * authors no code for it. It hosts the classification Workflow — a thin durable shell around the
9
+ * tested orchestration in `classify.ts`. The app worker receives the mail, stores it, and starts an
10
+ * instance.
11
+ *
12
+ * This module imports `cloudflare:workers`, so it runs only in the Workers runtime and is excluded
13
+ * from the node `.describe()` meta-test.
14
+ *
15
+ * **The effective taxonomy arrives as config, not as code.** `SUPPORT_CONFIG` carries the adopter's
16
+ * own categories, so their `tournament_dispute` reaches the prompt without this worker importing
17
+ * anything of theirs — which it could not do anyway, since it is deployed from this package.
18
+ *
19
+ * **The default export is what makes this an ES module** (#426). It exports one Workflow class and has
20
+ * no cron, so until now it exported no default — and wrangler infers a worker's module format from
21
+ * exactly that, so the build read it as a service worker and refused `cloudflare:workers` outright.
22
+ * The host did not build, `pithy dev` carried on past it, and classification silently never ran. The
23
+ * refusal it exports is the honest body for a host with no request surface; see
24
+ * `@pithy-sh/core/src/workflow/hostEntry`.
25
+ */
26
+ /** The support worker's env: the app database, the AI binding, and the serialized config. */
27
+ export interface SupportWorkerEnv {
28
+ /** The app database the support tables live in. */
29
+ DB: D1Database;
30
+ /** The Workers AI binding. */
31
+ AI: SupportAi;
32
+ /** The resolved support config as a JSON string, filled at provision. */
33
+ SUPPORT_CONFIG?: string;
34
+ }
35
+ /** Classify one stored message and write the result. */
36
+ export declare class SupportClassifyWorkflow extends WorkflowEntrypoint<SupportWorkerEnv, {
37
+ messageId: string;
38
+ }> {
39
+ run(event: WorkflowEvent<{
40
+ messageId: string;
41
+ }>, step: WorkflowStep): Promise<void>;
42
+ }
43
+ /**
44
+ * The module's default export, and therefore its format. See `hostEntry` for why a Workflow host needs
45
+ * one at all, and why this one refuses rather than being empty: nothing reaches this worker over HTTP —
46
+ * the app worker stores the message and starts an instance on the `SUPPORT_CLASSIFY` binding.
47
+ */
48
+ declare const _default: import("@pithy-sh/core/src/workflow/hostEntry").WorkflowHostEntry;
49
+ export default _default;
50
+ //# sourceMappingURL=worker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"worker.d.ts","sourceRoot":"","sources":["../../src/workflows/worker.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,kBAAkB,EAAE,KAAK,aAAa,EAAE,KAAK,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAE/F,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC;AAG5D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAQhD;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,6FAA6F;AAC7F,MAAM,WAAW,gBAAgB;IAC/B,mDAAmD;IACnD,EAAE,EAAE,UAAU,CAAC;IACf,8BAA8B;IAC9B,EAAE,EAAE,SAAS,CAAC;IACd,yEAAyE;IACzE,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,wDAAwD;AACxD,qBAAa,uBAAwB,SAAQ,kBAAkB,CAAC,gBAAgB,EAAE;IAAE,SAAS,EAAE,MAAM,CAAA;CAAE,CAAC;IACvF,GAAG,CAAC,KAAK,EAAE,aAAa,CAAC;QAAE,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC,EAAE,IAAI,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAwBjG;CACF;AAED;;;;GAIG"}
@@ -0,0 +1,39 @@
1
+ // SPDX-FileCopyrightText: 2026 Pithy
2
+ // SPDX-License-Identifier: MIT
3
+ import { SupportConfig } from "../config/config.js";
4
+ import { resolveCategories } from "../data/categories.js";
5
+ import { supportDatabase } from "../data/tables.js";
6
+ import { SUPPORT_CAPABILITY } from "./specs.js";
7
+ import { runClassification } from "./classify.js";
8
+ import { supportWorkflowRetry } from "./retryPolicy.js";
9
+ import { WorkflowEntrypoint } from "cloudflare:workers";
10
+ import { NonRetryableError } from "cloudflare:workflows";
11
+ import { classifiedSteps } from "@pithy-sh/core/src/workflow/faults";
12
+ import { workflowHostEntry } from "@pithy-sh/core/src/workflow/hostEntry";
13
+ //#region src/workflows/worker.ts
14
+ /** Classify one stored message and write the result. */
15
+ var SupportClassifyWorkflow = class extends WorkflowEntrypoint {
16
+ async run(event, step) {
17
+ const config = SupportConfig.parse(this.env.SUPPORT_CONFIG ? JSON.parse(this.env.SUPPORT_CONFIG) : {});
18
+ const deps = {
19
+ db: supportDatabase(this.env.DB),
20
+ ai: this.env.AI,
21
+ categories: resolveCategories(config.categories),
22
+ ai_config: config.ai,
23
+ archiveSpam: config.guard.archiveSpam,
24
+ newId: () => crypto.randomUUID(),
25
+ now: () => /* @__PURE__ */ new Date()
26
+ };
27
+ await classifiedSteps(step, supportWorkflowRetry, NonRetryableError).do(`classify-${event.payload.messageId}`, async () => {
28
+ await runClassification(deps, event.payload.messageId);
29
+ });
30
+ }
31
+ };
32
+ /**
33
+ * The module's default export, and therefore its format. See `hostEntry` for why a Workflow host needs
34
+ * one at all, and why this one refuses rather than being empty: nothing reaches this worker over HTTP —
35
+ * the app worker stores the message and starts an instance on the `SUPPORT_CLASSIFY` binding.
36
+ */
37
+ var worker_default = workflowHostEntry(SUPPORT_CAPABILITY);
38
+ //#endregion
39
+ export { SupportClassifyWorkflow, worker_default as default };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pithy-sh/support",
3
- "version": "0.1.2",
3
+ "version": "0.1.4",
4
4
  "license": "MIT",
5
5
  "repository": {
6
6
  "type": "git",
@@ -8,19 +8,24 @@
8
8
  "directory": "packages/support"
9
9
  },
10
10
  "files": [
11
+ "dist",
11
12
  "src",
12
13
  "pithy.manifest.json",
13
- "!src/**/*.test.*"
14
+ "!src/**/*.test.*",
15
+ "!dist/**/*.test.*"
14
16
  ],
15
17
  "type": "module",
16
18
  "engines": {
17
19
  "node": ">=22"
18
20
  },
19
21
  "exports": {
20
- "./src/*": "./src/*.ts"
22
+ "./src/*": {
23
+ "types": "./dist/*.d.ts",
24
+ "default": "./dist/*.js"
25
+ }
21
26
  },
22
27
  "scripts": {
23
- "build": "tsc -p tsconfig.json --noEmit false --outDir dist",
28
+ "build": "tsdown && tsc -p tsconfig.build.json && bun ../../tooling/build/src/stampDeclarations.ts",
24
29
  "typecheck": "tsc -p tsconfig.json",
25
30
  "test": "vitest run",
26
31
  "test:node": "vitest run --project=node",
@@ -31,19 +36,19 @@
31
36
  "dependencies": {
32
37
  "@cloudflare/workers-types": "^5.20260729.1",
33
38
  "@hono/zod-validator": "^0.9.0",
34
- "@pithy-sh/core": "^0.1.2",
35
- "@pithy-sh/email": "^0.1.2",
36
- "@pithy-sh/secrets": "^0.1.2",
37
- "@pithy-sh/storage": "^0.1.2",
38
- "hono": "^4.13.2",
39
- "kysely": "^0.29.0",
39
+ "@pithy-sh/core": "^0.1.5",
40
+ "@pithy-sh/email": "^0.1.4",
41
+ "@pithy-sh/secrets": "^0.1.4",
42
+ "@pithy-sh/storage": "^0.1.4",
40
43
  "postal-mime": "^3.0.0",
41
- "tldts": "^7.4.10",
42
- "zod": "^4.0.0"
44
+ "tldts": "^7.4.10"
43
45
  },
44
46
  "peerDependencies": {
45
- "@pithy-sh/auth": "^0.1.2",
46
- "@pithy-sh/payments": "^0.1.2"
47
+ "@pithy-sh/auth": "^0.1.4",
48
+ "@pithy-sh/payments": "^0.1.5",
49
+ "hono": "^4.13.2",
50
+ "kysely": "^0.29.0",
51
+ "zod": "^4.4.0"
47
52
  },
48
53
  "peerDependenciesMeta": {
49
54
  "@pithy-sh/auth": {
@@ -60,9 +65,13 @@
60
65
  "@pithy-sh/tsconfig": "workspace:*",
61
66
  "@types/node": "^22.15.0",
62
67
  "@vitest/coverage-v8": "^4.1.0",
68
+ "hono": "^4.13.2",
69
+ "kysely": "^0.29.0",
63
70
  "kysely-d1": "^0.4.0",
71
+ "tsdown": "^0.23.0",
64
72
  "typescript": "^7.0.2",
65
73
  "vitest": "^4.1.0",
66
- "wrangler": "^4.115.0"
74
+ "wrangler": "^4.115.0",
75
+ "zod": "^4.4.0"
67
76
  }
68
77
  }
@@ -359,7 +359,7 @@ export async function submitFeedbackRequest(
359
359
  context: input.context,
360
360
  // Decoded here, at the transport boundary, so `submitFeedback` takes bytes and stays testable
361
361
  // without a request — the same split `ingest.ts` has from the `email()` handler. The decode is
362
- // bounded before it allocates: `atob` materialises the whole result, so a size check afterwards
362
+ // bounded before it allocates: `atob` materializes the whole result, so a size check afterwards
363
363
  // has already paid for the attack it was meant to refuse.
364
364
  attachments: input.attachments.map((attachment) => ({
365
365
  filename: attachment.filename,
@@ -19,7 +19,7 @@ const BASE64_EXPANSION = 4 / 3;
19
19
  /**
20
20
  * The largest base64 string worth decoding, derived from a decoded-byte bound.
21
21
  *
22
- * Checked **before** decoding, not after. `atob` materialises the whole result, so a client that sends
22
+ * Checked **before** decoding, not after. `atob` materializes the whole result, so a client that sends
23
23
  * fifty megabytes of base64 has already been allocated fifty megabytes of Worker memory by the time a
24
24
  * post-hoc size check could refuse it — and the request that does that is the one an attacker sends.
25
25
  * A little slack for padding and any whitespace a client's encoder inserted.
@@ -50,7 +50,7 @@ import { checkAccountRate, checkAttachment } from "./guard";
50
50
  * The mail path's rule, applied to a different shape: **refuse on the cheapest true reason first.**
51
51
  * The two shape bounds a client controls the cost of — how many files, and how large each encoded one
52
52
  * is — are applied at the transport boundary in `http/handlers.ts` *before* anything is decoded,
53
- * because `atob` materialises its whole result and a size check after it has already been handed the
53
+ * because `atob` materializes its whole result and a size check after it has already been handed the
54
54
  * allocation it meant to refuse. What is left arrives here as bytes:
55
55
  *
56
56
  * 0. **The declared category**, which needs no I/O at all — it is a comparison against a taxonomy this
@@ -13,4 +13,4 @@
13
13
  export const PACKAGE_NAME = "@pithy-sh/support";
14
14
 
15
15
  /** This package's version, stamped from its own package.json at generation time. */
16
- export const PACKAGE_VERSION = "0.1.2";
16
+ export const PACKAGE_VERSION = "0.1.4";