@stigmer/runner 3.12.8 → 3.13.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 (98) hide show
  1. package/dist/.build-fingerprint +1 -1
  2. package/dist/activities/call-agent.d.ts +3 -2
  3. package/dist/activities/call-agent.js +13 -4
  4. package/dist/activities/call-agent.js.map +1 -1
  5. package/dist/activities/discover-mcp-server.js +1 -1
  6. package/dist/activities/execute-cursor/fetch-interceptor.js +29 -16
  7. package/dist/activities/execute-cursor/fetch-interceptor.js.map +1 -1
  8. package/dist/activities/execute-cursor/index.d.ts +14 -0
  9. package/dist/activities/execute-cursor/index.js +55 -5
  10. package/dist/activities/execute-cursor/index.js.map +1 -1
  11. package/dist/activities/execute-cursor/message-translator.d.ts +15 -9
  12. package/dist/activities/execute-cursor/message-translator.js +15 -9
  13. package/dist/activities/execute-cursor/message-translator.js.map +1 -1
  14. package/dist/activities/execute-deep-agent/attachment-injector.d.ts +1 -1
  15. package/dist/activities/execute-deep-agent/attachment-injector.js +2 -2
  16. package/dist/activities/execute-deep-agent/attachment-injector.js.map +1 -1
  17. package/dist/activities/execute-deep-agent/index.js +9 -0
  18. package/dist/activities/execute-deep-agent/index.js.map +1 -1
  19. package/dist/activities/execute-deep-agent/setup.d.ts +10 -1
  20. package/dist/activities/execute-deep-agent/setup.js +20 -3
  21. package/dist/activities/execute-deep-agent/setup.js.map +1 -1
  22. package/dist/client/stigmer-client.js +7 -2
  23. package/dist/client/stigmer-client.js.map +1 -1
  24. package/dist/payload-codecs.d.ts +1 -1
  25. package/dist/payload-codecs.js +6 -4
  26. package/dist/payload-codecs.js.map +1 -1
  27. package/dist/runner-manager.js +1 -1
  28. package/dist/runner-manager.js.map +1 -1
  29. package/dist/runner.js +1 -1
  30. package/dist/runner.js.map +1 -1
  31. package/dist/shared/memory-retrieval.d.ts +126 -0
  32. package/dist/shared/memory-retrieval.js +293 -0
  33. package/dist/shared/memory-retrieval.js.map +1 -0
  34. package/dist/shared/runner-credential-keys.js +2 -1
  35. package/dist/shared/runner-credential-keys.js.map +1 -1
  36. package/dist/shared/zip-extract.js +1 -1
  37. package/dist/shared/zip-extract.js.map +1 -1
  38. package/package.json +4 -2
  39. package/src/__tests__/history-encryption-e2e.test.ts +1 -1
  40. package/src/activities/call-agent.ts +14 -4
  41. package/src/activities/discover-mcp-server.ts +1 -1
  42. package/src/activities/execute-cursor/__tests__/build-prompt.test.ts +40 -1
  43. package/src/activities/execute-cursor/__tests__/fetch-interceptor.test.ts +49 -15
  44. package/src/activities/execute-cursor/__tests__/skill-resolver.test.ts +1 -1
  45. package/src/activities/execute-cursor/fetch-interceptor.ts +37 -16
  46. package/src/activities/execute-cursor/index.ts +58 -5
  47. package/src/activities/execute-cursor/message-translator.ts +15 -9
  48. package/src/activities/execute-deep-agent/__tests__/attachment-injector.test.ts +3 -2
  49. package/src/activities/execute-deep-agent/attachment-injector.ts +2 -2
  50. package/src/activities/execute-deep-agent/index.ts +10 -0
  51. package/src/activities/execute-deep-agent/setup.ts +34 -6
  52. package/src/client/stigmer-client.ts +7 -2
  53. package/src/payload-codecs.ts +12 -9
  54. package/src/runner-manager.ts +1 -1
  55. package/src/runner.ts +1 -1
  56. package/src/shared/__tests__/memory-retrieval.test.ts +310 -0
  57. package/src/shared/__tests__/skill-mount.test.ts +1 -1
  58. package/src/shared/__tests__/skill-writer.test.ts +1 -1
  59. package/src/shared/__tests__/zip-extract.test.ts +1 -1
  60. package/src/shared/memory-retrieval.ts +383 -0
  61. package/src/shared/runner-credential-keys.ts +2 -1
  62. package/src/shared/zip-extract.ts +1 -1
  63. package/dist/claimcheck/compressor.d.ts +0 -2
  64. package/dist/claimcheck/compressor.js +0 -8
  65. package/dist/claimcheck/compressor.js.map +0 -1
  66. package/dist/claimcheck/config.d.ts +0 -7
  67. package/dist/claimcheck/config.js +0 -10
  68. package/dist/claimcheck/config.js.map +0 -1
  69. package/dist/claimcheck/index.d.ts +0 -3
  70. package/dist/claimcheck/index.js +0 -4
  71. package/dist/claimcheck/index.js.map +0 -1
  72. package/dist/claimcheck/payload-codec.d.ts +0 -23
  73. package/dist/claimcheck/payload-codec.js +0 -105
  74. package/dist/claimcheck/payload-codec.js.map +0 -1
  75. package/dist/encryption/config.d.ts +0 -64
  76. package/dist/encryption/config.js +0 -113
  77. package/dist/encryption/config.js.map +0 -1
  78. package/dist/encryption/index.d.ts +0 -3
  79. package/dist/encryption/index.js +0 -3
  80. package/dist/encryption/index.js.map +0 -1
  81. package/dist/encryption/payload-codec.d.ts +0 -41
  82. package/dist/encryption/payload-codec.js +0 -130
  83. package/dist/encryption/payload-codec.js.map +0 -1
  84. package/dist/shared/zip-structure.d.ts +0 -61
  85. package/dist/shared/zip-structure.js +0 -128
  86. package/dist/shared/zip-structure.js.map +0 -1
  87. package/src/__test-utils__/zip-fixtures.ts +0 -206
  88. package/src/__tests__/claimcheck-codec.test.ts +0 -256
  89. package/src/__tests__/encryption-codec.test.ts +0 -287
  90. package/src/__tests__/fixtures/encrypted-payload-fixture.json +0 -15
  91. package/src/claimcheck/compressor.ts +0 -9
  92. package/src/claimcheck/config.ts +0 -20
  93. package/src/claimcheck/index.ts +0 -3
  94. package/src/claimcheck/payload-codec.ts +0 -139
  95. package/src/encryption/config.ts +0 -161
  96. package/src/encryption/index.ts +0 -3
  97. package/src/encryption/payload-codec.ts +0 -152
  98. package/src/shared/zip-structure.ts +0 -181
@@ -1,206 +0,0 @@
1
- /**
2
- * Shared ZIP fixture builder for runner unit tests.
3
- *
4
- * Emits complete, real-shaped archives — local file headers (optionally
5
- * streaming-style, the Go stdlib writer's default), payloads, central
6
- * directory, and EOCD — because that is the only shape that can reach the
7
- * runner: both editions' skill push gates validate artifacts with
8
- * central-directory-based readers (see zip-extract.ts's module doc and
9
- * design record 017). Earlier fixtures emitted local headers only, a
10
- * shape no real ZIP writer produces, and were coupled to the old parser's
11
- * front-to-back walk.
12
- *
13
- * Mirrors the conformance suite's `zipFilesStreaming()`
14
- * (test/conformance/src/support/skills.ts) so unit fixtures and
15
- * cross-edition fixtures share one shape.
16
- *
17
- * Lives in src/__test-utils__/ so `tsc --noEmit` covers it while
18
- * tsconfig.build.json keeps it out of dist/.
19
- */
20
-
21
- import { deflateRawSync } from "node:zlib";
22
-
23
- export interface ZipFixtureFile {
24
- name: string;
25
- /** Text content is UTF-8 encoded; pass bytes directly for binary payloads. */
26
- content: string | Uint8Array;
27
- /** Compression method for the entry. Defaults to stored. */
28
- method?: "stored" | "deflated";
29
- /**
30
- * Emit the entry the way Go's archive/zip does by default: general-purpose
31
- * flag bit 3 set, zeroed sizes in the local header, and a trailing data
32
- * descriptor (with the conventional signature) carrying the real values.
33
- */
34
- streaming?: boolean;
35
- /**
36
- * Lie about the entry's uncompressed size everywhere the writer would
37
- * declare it (local header, data descriptor, central directory). Models a
38
- * crafted archive whose declarations disagree with its actual payload —
39
- * the input class the attachment injector's declared-size enforcement
40
- * exists to reject (issue #567).
41
- */
42
- declaredUncompressedSize?: number;
43
- }
44
-
45
- export interface ZipFixtureOptions {
46
- /** Trailing archive comment appended after the EOCD record. */
47
- comment?: string;
48
- /**
49
- * Drop the central directory and EOCD, leaving only local headers and
50
- * payloads. No real ZIP writer produces this shape — it models a download
51
- * truncated before the archive's index.
52
- */
53
- omitCentralDirectory?: boolean;
54
- }
55
-
56
- /** Build a ZIP archive from path + content pairs. */
57
- export function buildZip(files: ZipFixtureFile[], options?: ZipFixtureOptions): Uint8Array {
58
- const out = new ByteWriter();
59
-
60
- interface WrittenEntry {
61
- nameBytes: Uint8Array;
62
- payload: Uint8Array;
63
- declaredUncompressed: number;
64
- crc: number;
65
- flags: number;
66
- method: number;
67
- localHeaderOffset: number;
68
- }
69
- const written: WrittenEntry[] = [];
70
-
71
- for (const file of files) {
72
- const contentBytes =
73
- typeof file.content === "string" ? new TextEncoder().encode(file.content) : file.content;
74
- const deflated = file.method === "deflated";
75
- const payload = deflated ? new Uint8Array(deflateRawSync(contentBytes)) : contentBytes;
76
- const entry: WrittenEntry = {
77
- nameBytes: new TextEncoder().encode(file.name),
78
- payload,
79
- declaredUncompressed: file.declaredUncompressedSize ?? contentBytes.length,
80
- crc: crc32(contentBytes),
81
- flags: file.streaming ? 0x0008 : 0,
82
- method: deflated ? 8 : 0,
83
- localHeaderOffset: out.length,
84
- };
85
- written.push(entry);
86
-
87
- out.u32(0x04034b50); // local file header signature
88
- out.u16(20); // version needed to extract
89
- out.u16(entry.flags);
90
- out.u16(entry.method);
91
- out.u16(0); // mod time
92
- out.u16(0); // mod date
93
- out.u32(file.streaming ? 0 : entry.crc);
94
- out.u32(file.streaming ? 0 : payload.length);
95
- out.u32(file.streaming ? 0 : entry.declaredUncompressed);
96
- out.u16(entry.nameBytes.length);
97
- out.u16(0); // extra field length
98
- out.raw(entry.nameBytes);
99
- out.raw(payload);
100
-
101
- if (file.streaming) {
102
- out.u32(0x08074b50); // data descriptor signature (Go writes it)
103
- out.u32(entry.crc);
104
- out.u32(payload.length);
105
- out.u32(entry.declaredUncompressed);
106
- }
107
- }
108
-
109
- if (options?.omitCentralDirectory) {
110
- return out.toUint8Array();
111
- }
112
-
113
- const centralDirectoryOffset = out.length;
114
- for (const entry of written) {
115
- out.u32(0x02014b50); // central directory record signature
116
- out.u16(20); // version made by
117
- out.u16(20); // version needed to extract
118
- out.u16(entry.flags);
119
- out.u16(entry.method);
120
- out.u16(0); // mod time
121
- out.u16(0); // mod date
122
- out.u32(entry.crc);
123
- out.u32(entry.payload.length);
124
- out.u32(entry.declaredUncompressed);
125
- out.u16(entry.nameBytes.length);
126
- out.u16(0); // extra field length
127
- out.u16(0); // comment length
128
- out.u16(0); // disk number start
129
- out.u16(0); // internal attributes
130
- out.u32(0); // external attributes
131
- out.u32(entry.localHeaderOffset);
132
- out.raw(entry.nameBytes);
133
- }
134
- const centralDirectorySize = out.length - centralDirectoryOffset;
135
-
136
- const commentBytes = new TextEncoder().encode(options?.comment ?? "");
137
- out.u32(0x06054b50); // EOCD signature
138
- out.u16(0); // disk number
139
- out.u16(0); // disk with central directory
140
- out.u16(written.length); // entries on this disk
141
- out.u16(written.length); // total entries
142
- out.u32(centralDirectorySize);
143
- out.u32(centralDirectoryOffset);
144
- out.u16(commentBytes.length);
145
- out.raw(commentBytes);
146
-
147
- return out.toUint8Array();
148
- }
149
-
150
- // Chunked assembly instead of a number[]-per-byte accumulator: fixtures at
151
- // the injector's 100 MB zip-bomb limit are built from payload-sized chunks,
152
- // which a per-byte spread-push cannot survive (argument-count overflow).
153
- class ByteWriter {
154
- private readonly chunks: Uint8Array[] = [];
155
- private size = 0;
156
-
157
- get length(): number {
158
- return this.size;
159
- }
160
-
161
- u16(v: number): void {
162
- this.raw(new Uint8Array([v & 0xff, (v >>> 8) & 0xff]));
163
- }
164
-
165
- u32(v: number): void {
166
- this.raw(new Uint8Array([v & 0xff, (v >>> 8) & 0xff, (v >>> 16) & 0xff, (v >>> 24) & 0xff]));
167
- }
168
-
169
- raw(b: Uint8Array): void {
170
- this.chunks.push(b);
171
- this.size += b.length;
172
- }
173
-
174
- toUint8Array(): Uint8Array {
175
- const result = new Uint8Array(this.size);
176
- let offset = 0;
177
- for (const chunk of this.chunks) {
178
- result.set(chunk, offset);
179
- offset += chunk.length;
180
- }
181
- return result;
182
- }
183
- }
184
-
185
- // Standard CRC-32 (IEEE 802.3, the ZIP checksum), table-driven so fixtures
186
- // at the injector's 100 MB limit stay cheap to build. Semantically identical
187
- // to the conformance suite's inline bit-loop helper.
188
- const CRC_TABLE = (() => {
189
- const table = new Uint32Array(256);
190
- for (let n = 0; n < 256; n++) {
191
- let c = n;
192
- for (let bit = 0; bit < 8; bit++) {
193
- c = (c >>> 1) ^ (0xedb88320 & -(c & 1));
194
- }
195
- table[n] = c;
196
- }
197
- return table;
198
- })();
199
-
200
- function crc32(data: Uint8Array): number {
201
- let crc = 0xffffffff;
202
- for (let i = 0; i < data.length; i++) {
203
- crc = (crc >>> 8) ^ CRC_TABLE[(crc ^ data[i]!) & 0xff]!;
204
- }
205
- return (crc ^ 0xffffffff) >>> 0;
206
- }
@@ -1,256 +0,0 @@
1
- import { describe, it, expect, beforeEach } from "vitest";
2
- import { ClaimcheckPayloadCodec } from "../claimcheck/payload-codec.js";
3
- import { compress } from "../claimcheck/compressor.js";
4
- import type { ClaimcheckConfig } from "../claimcheck/config.js";
5
- import { makeInMemoryArtifactStorage } from "../__test-utils__/fake-artifact-storage.js";
6
- import type { Payload } from "@temporalio/common";
7
-
8
- function makeConfig(overrides: Partial<ClaimcheckConfig> = {}): ClaimcheckConfig {
9
- return {
10
- enabled: true,
11
- thresholdBytes: 1024,
12
- compressionEnabled: true,
13
- keyPrefix: "claimcheck/",
14
- ...overrides,
15
- };
16
- }
17
-
18
- function makeStorage() {
19
- // The canonical in-memory double; `uploads` aliases its backing Map so the
20
- // existing `storage.uploads.*` assertions keep working, and `download` reads
21
- // straight from what `encode` uploaded (no fetch to stub).
22
- const { storage, blobs } = makeInMemoryArtifactStorage();
23
- return Object.assign(storage, { uploads: blobs });
24
- }
25
-
26
- function makePayload(data: string | Buffer): Payload {
27
- const buf = typeof data === "string" ? Buffer.from(data) : data;
28
- return {
29
- metadata: { encoding: Buffer.from("binary/plain") },
30
- data: buf,
31
- };
32
- }
33
-
34
- function makeLargePayload(sizeBytes: number): Payload {
35
- const buf = Buffer.alloc(sizeBytes, "x");
36
- return {
37
- metadata: { encoding: Buffer.from("binary/plain") },
38
- data: buf,
39
- };
40
- }
41
-
42
- describe("ClaimcheckPayloadCodec", () => {
43
- let storage: ReturnType<typeof makeStorage>;
44
- let codec: ClaimcheckPayloadCodec;
45
-
46
- beforeEach(() => {
47
- storage = makeStorage();
48
- codec = new ClaimcheckPayloadCodec(storage, makeConfig());
49
- });
50
-
51
- describe("encode", () => {
52
- it("passes through payloads below threshold unchanged", async () => {
53
- const payload = makePayload("small data");
54
- const [result] = await codec.encode([payload]);
55
- expect(result).toBe(payload);
56
- expect(storage.uploads.size).toBe(0);
57
- });
58
-
59
- it("passes through empty payloads", async () => {
60
- const payload: Payload = { metadata: {}, data: undefined };
61
- const [result] = await codec.encode([payload]);
62
- expect(result).toBe(payload);
63
- });
64
-
65
- it("offloads payloads at or above threshold", async () => {
66
- const payload = makeLargePayload(1024);
67
- const [result] = await codec.encode([payload]);
68
-
69
- expect(result).not.toBe(payload);
70
- expect(storage.uploads.size).toBe(1);
71
-
72
- const markerMeta = result.metadata?.["encoding"];
73
- expect(Buffer.from(markerMeta!).toString()).toBe("binary/claimcheck");
74
-
75
- const marker = JSON.parse(Buffer.from(result.data!).toString());
76
- expect(marker.key).toMatch(/^claimcheck\//);
77
- expect(marker.size).toBe(1024);
78
- expect(marker.compressed).toBe(true);
79
- });
80
-
81
- it("skips compression when it does not reduce size", async () => {
82
- const randomBuf = Buffer.from(
83
- Array.from({ length: 1024 }, () => Math.floor(Math.random() * 256)),
84
- );
85
- const payload: Payload = {
86
- metadata: { encoding: Buffer.from("binary/plain") },
87
- data: randomBuf,
88
- };
89
-
90
- const compressedSize = compress(randomBuf).length;
91
- if (compressedSize >= randomBuf.length) {
92
- const [result] = await codec.encode([payload]);
93
- const marker = JSON.parse(Buffer.from(result.data!).toString());
94
- expect(marker.compressed).toBe(false);
95
-
96
- const uploaded = storage.uploads.values().next().value!;
97
- expect(uploaded.length).toBe(randomBuf.length);
98
- }
99
- });
100
-
101
- it("does not compress when compression is disabled", async () => {
102
- codec = new ClaimcheckPayloadCodec(
103
- storage,
104
- makeConfig({ compressionEnabled: false }),
105
- );
106
- const payload = makeLargePayload(1024);
107
- const [result] = await codec.encode([payload]);
108
-
109
- const marker = JSON.parse(Buffer.from(result.data!).toString());
110
- expect(marker.compressed).toBe(false);
111
-
112
- const uploaded = storage.uploads.values().next().value!;
113
- expect(uploaded.length).toBe(1024);
114
- });
115
-
116
- it("handles multiple payloads in a batch", async () => {
117
- const small = makePayload("tiny");
118
- const large = makeLargePayload(2048);
119
-
120
- const results = await codec.encode([small, large]);
121
- expect(results[0]).toBe(small);
122
- expect(results[1]).not.toBe(large);
123
- expect(storage.uploads.size).toBe(1);
124
- });
125
-
126
- it("uses configured key prefix", async () => {
127
- codec = new ClaimcheckPayloadCodec(
128
- storage,
129
- makeConfig({ keyPrefix: "custom-prefix/" }),
130
- );
131
- const payload = makeLargePayload(1024);
132
- const [result] = await codec.encode([payload]);
133
-
134
- const marker = JSON.parse(Buffer.from(result.data!).toString());
135
- expect(marker.key).toMatch(/^custom-prefix\//);
136
- });
137
- });
138
-
139
- describe("decode", () => {
140
- it("passes through non-claimcheck payloads unchanged", async () => {
141
- const payload = makePayload("normal data");
142
- const [result] = await codec.decode([payload]);
143
- expect(result).toBe(payload);
144
- });
145
-
146
- it("retrieves and decompresses offloaded payloads (round-trip)", async () => {
147
- const original = makeLargePayload(2048);
148
- const [encoded] = await codec.encode([original]);
149
-
150
- // decode reads back through storage.download from what encode uploaded.
151
- const [decoded] = await codec.decode([encoded]);
152
- expect(Buffer.from(decoded.data!)).toEqual(original.data);
153
- });
154
-
155
- it("restores the original payload metadata (round-trip)", async () => {
156
- // The restored payload must carry its ORIGINAL encoding, not the
157
- // marker's binary/claimcheck — otherwise no payload converter can
158
- // interpret it and composition with the encryption codec breaks.
159
- const original: Payload = {
160
- metadata: {
161
- encoding: Buffer.from("json/plain"),
162
- "custom-key": Buffer.from("custom-value"),
163
- },
164
- data: Buffer.alloc(2048, "y"),
165
- };
166
-
167
- const [encoded] = await codec.encode([original]);
168
- const [decoded] = await codec.decode([encoded]);
169
-
170
- expect(Buffer.from(decoded.metadata!["encoding"]!).toString()).toBe("json/plain");
171
- expect(Buffer.from(decoded.metadata!["custom-key"]!).toString()).toBe("custom-value");
172
- expect(Buffer.from(decoded.data!)).toEqual(original.data);
173
- });
174
-
175
- it("decodes legacy markers written before metadata preservation", async () => {
176
- const original = makeLargePayload(2048);
177
- const [encoded] = await codec.encode([original]);
178
-
179
- // Simulate a pre-fix marker: strip the metadata field.
180
- const marker = JSON.parse(Buffer.from(encoded.data!).toString());
181
- delete marker.metadata;
182
- const legacy: Payload = {
183
- metadata: encoded.metadata,
184
- data: Buffer.from(JSON.stringify(marker)),
185
- };
186
-
187
- const [decoded] = await codec.decode([legacy]);
188
- expect(Buffer.from(decoded.data!)).toEqual(original.data);
189
- });
190
-
191
- it("retrieves uncompressed payloads correctly", async () => {
192
- codec = new ClaimcheckPayloadCodec(
193
- storage,
194
- makeConfig({ compressionEnabled: false }),
195
- );
196
-
197
- const original = makeLargePayload(1500);
198
- const [encoded] = await codec.encode([original]);
199
-
200
- const [decoded] = await codec.decode([encoded]);
201
- expect(Buffer.from(decoded.data!)).toEqual(original.data);
202
- });
203
-
204
- it("wraps a download failure with the claimcheck error contract", async () => {
205
- const encoded: Payload = {
206
- metadata: { encoding: Buffer.from("binary/claimcheck") },
207
- data: Buffer.from(JSON.stringify({
208
- key: "claimcheck/missing",
209
- size: 100,
210
- compressed: false,
211
- })),
212
- };
213
-
214
- // Drive the failure through the port; the proxy download surfaces the HTTP
215
- // status, which the codec must preserve in its wrapped, key-scoped message.
216
- storage.download.mockRejectedValueOnce(
217
- new Error("Artifact download failed (HTTP 404) for key 'claimcheck/missing'"),
218
- );
219
-
220
- await expect(codec.decode([encoded])).rejects.toThrow(
221
- /Claimcheck retrieve failed for key claimcheck\/missing.*HTTP 404/,
222
- );
223
- });
224
- });
225
-
226
- describe("threshold boundary", () => {
227
- it("does NOT offload at threshold - 1", async () => {
228
- const payload = makeLargePayload(1023);
229
- const [result] = await codec.encode([payload]);
230
- expect(result).toBe(payload);
231
- });
232
-
233
- it("offloads at exactly threshold", async () => {
234
- const payload = makeLargePayload(1024);
235
- const [result] = await codec.encode([payload]);
236
- expect(result).not.toBe(payload);
237
- });
238
-
239
- it("offloads above threshold", async () => {
240
- const payload = makeLargePayload(1025);
241
- const [result] = await codec.encode([payload]);
242
- expect(result).not.toBe(payload);
243
- });
244
- });
245
-
246
- describe("compressor", () => {
247
- it("compresses and decompresses correctly", async () => {
248
- const { compress: c, decompress: d } = await import("../claimcheck/compressor.js");
249
- const input = Buffer.from("hello world ".repeat(100));
250
- const compressed = c(input);
251
- expect(compressed.length).toBeLessThan(input.length);
252
- const decompressed = d(compressed);
253
- expect(decompressed).toEqual(input);
254
- });
255
- });
256
- });