@redact-secret/core 0.1.0-beta.1 → 0.1.0-beta.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/README.md CHANGED
@@ -119,16 +119,99 @@ names the finding type instead (`<JWT_1>`).
119
119
 
120
120
  ## Incremental and stream availability
121
121
 
122
- The current Node and WebAssembly artifacts do not build incremental sessions.
123
- After initialization, `createIncrementalSanitizer`, `createNodeStreamSanitizer`,
124
- and `createWebStreamSanitizer` fail with `INCREMENTAL_UNAVAILABLE` when using
125
- these artifacts. Whole-input operations remain supported.
122
+ The Node artifact builds a real incremental session, wrapping the same core
123
+ `IncrementalSanitizer` the Python binding does, and the browser (WebAssembly)
124
+ artifact builds the same kind of session over the compiled WebAssembly
125
+ module. `createIncrementalSanitizer` retains unresolved text until its
126
+ detection window closes, then emits sanitized text and findings;
127
+ concatenating every `append`/`finalize` result's text reconstructs the whole
128
+ sanitized output. Findings carry absolute UTF-16 offsets into the logical
129
+ whole-session input, so `input.slice(finding.start, finding.end)` selects the
130
+ matched span, on every runtime. Do not scan chunks independently — a
131
+ credential may cross a chunk boundary.
126
132
 
127
- The session types and stream subpaths are exported contracts, not evidence of
128
- runtime support. Adapter constructors accept a supplied session, but the
129
- package cannot create one with either current artifact. Use bounded whole-input
130
- scanning, or use Python, Rust, or CLI streaming. Do not scan chunks independently:
131
- a credential may cross a chunk boundary.
133
+ ```ts
134
+ import { createIncrementalSanitizer, initialize } from "@redact-secret/core";
135
+
136
+ await initialize();
137
+
138
+ const limits = {
139
+ maxInputCodeUnits: 32_768,
140
+ maxBufferedCodeUnits: 16_512,
141
+ maxTokenCodeUnits: 8_192,
142
+ maxMultilineCodeUnits: 16_384,
143
+ };
144
+ const session = createIncrementalSanitizer({ limits });
145
+
146
+ const first = session.append("api_key=SYNTHETIC_REVOKED_");
147
+ const second = session.append("INCREMENTAL_VALUE\nordinary text");
148
+ const final = session.finalize();
149
+
150
+ const safeText = first.text + second.text + final.text;
151
+ ```
152
+
153
+ The four limit fields keep their existing `CodeUnits` names for compatibility,
154
+ but both artifacts enforce their values as UTF-8 byte ceilings in the Rust
155
+ core. Findings and their `start`/`end` ranges still use UTF-16 code units.
156
+
157
+ A session starts `accepting` and moves to the terminal `finalized` (one
158
+ successful `finalize()`), `aborted` (`abort()`), or `failed` (a limit,
159
+ detector, policy, or placeholder failure) state; every operation outside
160
+ `accepting` throws `INVALID_STATE`, and every terminal transition discards
161
+ whatever plaintext the session still retained.
162
+
163
+ `@redact-secret/core/node-stream` wraps a session in a byte-to-byte Node
164
+ `Transform`, finalizing it when the stream ends normally and aborting it on
165
+ every other exit:
166
+
167
+ ```ts
168
+ import { pipeline } from "node:stream/promises";
169
+
170
+ import { initialize } from "@redact-secret/core";
171
+ import { createNodeStreamSanitizer } from "@redact-secret/core/node-stream";
172
+
173
+ await initialize();
174
+
175
+ await pipeline(
176
+ process.stdin,
177
+ createNodeStreamSanitizer({
178
+ limits: {
179
+ maxInputCodeUnits: 32_768,
180
+ maxBufferedCodeUnits: 16_512,
181
+ maxTokenCodeUnits: 8_192,
182
+ maxMultilineCodeUnits: 16_384,
183
+ },
184
+ }),
185
+ process.stdout,
186
+ );
187
+ ```
188
+
189
+ `@redact-secret/core/web-stream` wraps a session in a byte-to-string Web
190
+ `TransformStream`, finalizing it when the writable side closes normally and
191
+ aborting it on every other exit:
192
+
193
+ ```ts
194
+ import { initialize } from "@redact-secret/core";
195
+ import { createWebStreamSanitizer } from "@redact-secret/core/web-stream";
196
+
197
+ await initialize();
198
+
199
+ declare const source: ReadableStream<Uint8Array>;
200
+ declare const destination: WritableStream<string>;
201
+
202
+ await source
203
+ .pipeThrough(
204
+ createWebStreamSanitizer({
205
+ limits: {
206
+ maxInputCodeUnits: 32_768,
207
+ maxBufferedCodeUnits: 16_512,
208
+ maxTokenCodeUnits: 8_192,
209
+ maxMultilineCodeUnits: 16_384,
210
+ },
211
+ }),
212
+ )
213
+ .pipeTo(destination);
214
+ ```
132
215
 
133
216
  See the [streaming guide](https://github.com/redact-secret/redact-secret/blob/main/docs/guides/streaming.md).
134
217
 
@@ -159,9 +242,8 @@ try {
159
242
  string may contain a lone UTF-16 surrogate, which has no UTF-8
160
243
  representation, so `scan`, `redact`, `scanAndRedact`, and an incremental
161
244
  sanitizer's `append` all reject one with this fixed code before it reaches
162
- either binding, identically on Node.js and in the browser and
163
- `INCREMENTAL_UNAVAILABLE` from both current runtime adapters. Core failures
164
- are mapped to the same fixed error vocabulary.
245
+ either binding, identically on Node.js and in the browser. Core failures are
246
+ mapped to the same fixed error vocabulary.
165
247
 
166
248
  ## Public API
167
249
 
@@ -17,7 +17,10 @@
17
17
  */
18
18
  import { SecretScanError } from "../errors.js";
19
19
  export function createStreamSanitizerRuntime(session) {
20
- const decoder = new TextDecoder("utf-8", { fatal: true });
20
+ const decoder = new TextDecoder("utf-8", {
21
+ fatal: true,
22
+ ignoreBOM: true,
23
+ });
21
24
  const findings = [];
22
25
  /** Idempotent, and safe after the session has already left `accepting`. */
23
26
  function abort() {
@@ -33,13 +36,23 @@ export function createStreamSanitizerRuntime(session) {
33
36
  throw new SecretScanError("INVALID_UTF8");
34
37
  }
35
38
  }
39
+ function accumulateFindings(next) {
40
+ try {
41
+ for (const finding of next)
42
+ findings.push(finding);
43
+ }
44
+ catch {
45
+ abort();
46
+ throw new SecretScanError("INVALID_STATE");
47
+ }
48
+ }
36
49
  function append(chunk) {
37
50
  if (!(chunk instanceof Uint8Array)) {
38
51
  abort();
39
52
  throw new SecretScanError("INVALID_CHUNK");
40
53
  }
41
54
  const result = session.append(decode(chunk, true));
42
- findings.push(...result.findings);
55
+ accumulateFindings(result.findings);
43
56
  return result;
44
57
  }
45
58
  /**
@@ -61,7 +74,8 @@ export function createStreamSanitizerRuntime(session) {
61
74
  abort();
62
75
  throw error;
63
76
  }
64
- findings.push(...decodedResult.findings, ...finalResult.findings);
77
+ accumulateFindings(decodedResult.findings);
78
+ accumulateFindings(finalResult.findings);
65
79
  return Object.freeze({
66
80
  text: decodedResult.text + finalResult.text,
67
81
  findings: Object.freeze([
package/dist/errors.d.ts CHANGED
@@ -6,11 +6,8 @@
6
6
  * message (`decision-define-runtime-bindings`). Sixteen codes come from the
7
7
  * Rust core; `NOT_INITIALIZED` and `INITIALIZATION_FAILED` are produced by the
8
8
  * binding layer, `INVALID_CHUNK` and `INVALID_UTF8` by the stream adapters,
9
- * `UNPAIRED_SURROGATE` by this package's own runtime-neutral input check, and
10
- * `INCREMENTAL_UNAVAILABLE` by any binding that does not implement
11
- * incremental sanitization — the browser binding always (`bindings/wasm` has
12
- * no such export by design) and the Node binding until `bindings/node` gains
13
- * one; and this package normalizes all of them into the same class so
9
+ * `UNPAIRED_SURROGATE` by this package's own runtime-neutral input check. The
10
+ * package normalizes all of them into the same class so
14
11
  * `instanceof SecretScanError` holds on every runtime and every subpath.
15
12
  *
16
13
  * `UNPAIRED_SURROGATE` resolves `B/F-10`
@@ -24,7 +21,7 @@
24
21
  * Node and browser runtimes by construction rather than by parallel
25
22
  * implementation.
26
23
  */
27
- export type SecretScanErrorCode = "INVALID_INPUT" | "INVALID_OPTIONS" | "INVALID_DETECTOR" | "DETECTOR_FAILURE" | "INVALID_CANDIDATE" | "POLICY_FAILURE" | "INVALID_POLICY_ACTION" | "INVALID_FINDINGS" | "PLACEHOLDER_FAILURE" | "INVALID_PLACEHOLDER" | "INVALID_LIMITS" | "INPUT_LIMIT_EXCEEDED" | "BUFFER_LIMIT_EXCEEDED" | "TOKEN_LIMIT_EXCEEDED" | "MULTILINE_LIMIT_EXCEEDED" | "INVALID_STATE" | "NOT_INITIALIZED" | "INITIALIZATION_FAILED" | "INVALID_CHUNK" | "INVALID_UTF8" | "UNPAIRED_SURROGATE" | "INCREMENTAL_UNAVAILABLE";
24
+ export type SecretScanErrorCode = "INVALID_INPUT" | "INVALID_OPTIONS" | "INVALID_DETECTOR" | "DETECTOR_FAILURE" | "INVALID_CANDIDATE" | "POLICY_FAILURE" | "INVALID_POLICY_ACTION" | "INVALID_FINDINGS" | "PLACEHOLDER_FAILURE" | "INVALID_PLACEHOLDER" | "INVALID_LIMITS" | "INPUT_LIMIT_EXCEEDED" | "BUFFER_LIMIT_EXCEEDED" | "TOKEN_LIMIT_EXCEEDED" | "MULTILINE_LIMIT_EXCEEDED" | "INVALID_STATE" | "NOT_INITIALIZED" | "INITIALIZATION_FAILED" | "INVALID_CHUNK" | "INVALID_UTF8" | "UNPAIRED_SURROGATE";
28
25
  /** A sanitized failure. It carries nothing but its fixed code and message. */
29
26
  export declare class SecretScanError extends Error {
30
27
  readonly code: SecretScanErrorCode;
package/dist/errors.js CHANGED
@@ -6,11 +6,8 @@
6
6
  * message (`decision-define-runtime-bindings`). Sixteen codes come from the
7
7
  * Rust core; `NOT_INITIALIZED` and `INITIALIZATION_FAILED` are produced by the
8
8
  * binding layer, `INVALID_CHUNK` and `INVALID_UTF8` by the stream adapters,
9
- * `UNPAIRED_SURROGATE` by this package's own runtime-neutral input check, and
10
- * `INCREMENTAL_UNAVAILABLE` by any binding that does not implement
11
- * incremental sanitization — the browser binding always (`bindings/wasm` has
12
- * no such export by design) and the Node binding until `bindings/node` gains
13
- * one; and this package normalizes all of them into the same class so
9
+ * `UNPAIRED_SURROGATE` by this package's own runtime-neutral input check. The
10
+ * package normalizes all of them into the same class so
14
11
  * `instanceof SecretScanError` holds on every runtime and every subpath.
15
12
  *
16
13
  * `UNPAIRED_SURROGATE` resolves `B/F-10`
@@ -47,7 +44,6 @@ const ERROR_MESSAGES = {
47
44
  INVALID_CHUNK: "Stream sanitizer input must contain bytes.",
48
45
  INVALID_UTF8: "Stream sanitizer input is not valid UTF-8.",
49
46
  UNPAIRED_SURROGATE: "Secret scan input contains an unpaired UTF-16 surrogate.",
50
- INCREMENTAL_UNAVAILABLE: "Incremental sanitization is not available on this runtime.",
51
47
  };
52
48
  const ERROR_CODES = new Set(Object.keys(ERROR_MESSAGES));
53
49
  /** A sanitized failure. It carries nothing but its fixed code and message. */
@@ -12,11 +12,13 @@
12
12
  * binding's own idempotent `initialize()` that builds the detector registry.
13
13
  * Wrapping both is exactly this adapter's job.
14
14
  *
15
- * `bindings/wasm` does not export a `createIncrementalSanitizer` (see its
16
- * `README.md`): incremental sanitization is deliberately unavailable on this
17
- * runtime, so this adapter's `createIncrementalSanitizer` always rejects with
18
- * the fixed `INCREMENTAL_UNAVAILABLE` code. `./web-stream` rejects the same
19
- * way, through this same binding, and `initialize()` itself still resolves.
15
+ * `bindings/wasm` exports a real `createIncrementalSanitizer`
16
+ * (`decision-define-runtime-bindings`): it builds a bounded
17
+ * `IncrementalSanitizer` session, wrapping the same core session
18
+ * `bindings/node` and `bindings/python` wrap, with an explicit
19
+ * `accepting`/`finalized`/`aborted`/`failed` lifecycle and absolute UTF-16
20
+ * ranges converted chunk by chunk. `./web-stream` reaches it through this
21
+ * same binding.
20
22
  */
21
23
  import { type NativeBinding } from "../native.js";
22
24
  import type { PlaceholderContext, PolicyContext } from "../types.js";
@@ -58,6 +60,23 @@ export interface WasmFindingMetadata extends WasmDetectedFindingMetadata {
58
60
  }
59
61
  type WasmPolicyCallback = (finding: WasmDetectedFindingMetadata, context: PolicyContext) => string;
60
62
  type WasmFormatterCallback = (finding: WasmFindingMetadata, context: PlaceholderContext) => string;
63
+ /** The position information an incremental policy callback receives. */
64
+ export interface WasmIncrementalPolicyContext {
65
+ readonly findingIndex: number;
66
+ }
67
+ type WasmIncrementalPolicyCallback = (finding: WasmDetectedFindingMetadata, context: WasmIncrementalPolicyContext) => string;
68
+ /** The result of one incremental `append`/`finalize` call. */
69
+ export interface WasmIncrementalResult {
70
+ readonly text: string;
71
+ readonly findings: readonly WasmFinding[];
72
+ }
73
+ /** The `IncrementalSanitizer` class `createIncrementalSanitizer` returns. */
74
+ export interface WasmIncrementalSanitizer {
75
+ readonly state: string;
76
+ append(chunk: string): WasmIncrementalResult;
77
+ finalize(): WasmIncrementalResult;
78
+ abort(): void;
79
+ }
61
80
  export interface WasmModule {
62
81
  default(): Promise<unknown>;
63
82
  version(): string;
@@ -68,15 +87,16 @@ export interface WasmModule {
68
87
  readonly text: string;
69
88
  readonly findings: readonly WasmFinding[];
70
89
  };
90
+ createIncrementalSanitizer(maxInputCodeUnits: number, maxBufferedCodeUnits: number, maxTokenCodeUnits: number, maxMultilineCodeUnits: number, policy?: WasmIncrementalPolicyCallback, formatter?: WasmFormatterCallback): WasmIncrementalSanitizer;
71
91
  }
72
92
  /**
73
93
  * Builds the internal binding contract from an already-loaded WebAssembly
74
94
  * module.
75
95
  *
76
96
  * Exported so a test double can exercise this exact normalization — the
77
- * nested-metadata flattening above and the fixed `INCREMENTAL_UNAVAILABLE`
78
- * rejection below — against a fake module shaped like the real artifact,
79
- * without loading the artifact itself.
97
+ * nested-metadata flattening above and the incremental session wiring below
98
+ * — against a fake module shaped like the real artifact, without loading the
99
+ * artifact itself.
80
100
  */
81
101
  export declare function createBindingFromWasmModule(wasm: WasmModule): NativeBinding;
82
102
  export declare const loadNativeBinding: () => Promise<NativeBinding>;
@@ -12,11 +12,13 @@
12
12
  * binding's own idempotent `initialize()` that builds the detector registry.
13
13
  * Wrapping both is exactly this adapter's job.
14
14
  *
15
- * `bindings/wasm` does not export a `createIncrementalSanitizer` (see its
16
- * `README.md`): incremental sanitization is deliberately unavailable on this
17
- * runtime, so this adapter's `createIncrementalSanitizer` always rejects with
18
- * the fixed `INCREMENTAL_UNAVAILABLE` code. `./web-stream` rejects the same
19
- * way, through this same binding, and `initialize()` itself still resolves.
15
+ * `bindings/wasm` exports a real `createIncrementalSanitizer`
16
+ * (`decision-define-runtime-bindings`): it builds a bounded
17
+ * `IncrementalSanitizer` session, wrapping the same core session
18
+ * `bindings/node` and `bindings/python` wrap, with an explicit
19
+ * `accepting`/`finalized`/`aborted`/`failed` lifecycle and absolute UTF-16
20
+ * ranges converted chunk by chunk. `./web-stream` reaches it through this
21
+ * same binding.
20
22
  */
21
23
  import { SecretScanError } from "../errors.js";
22
24
  import { NATIVE_HANDLE, } from "../native.js";
@@ -84,6 +86,17 @@ function toWasmFormatterCallback(formatter) {
84
86
  return undefined;
85
87
  return (finding, context) => formatter(toNativeFormatterMetadata(finding), context);
86
88
  }
89
+ function toWasmIncrementalPolicyCallback(policy) {
90
+ if (policy === undefined)
91
+ return undefined;
92
+ return (finding, context) => policy(toNativeDetectedFinding(finding), context);
93
+ }
94
+ function toNativeIncrementalResult(result) {
95
+ return {
96
+ text: result.text,
97
+ findings: result.findings.map(toNativeFinding),
98
+ };
99
+ }
87
100
  /**
88
101
  * Loads the WebAssembly artifact published in lockstep with this package.
89
102
  *
@@ -100,6 +113,7 @@ async function loadWasmModule() {
100
113
  "scan",
101
114
  "redact",
102
115
  "scanAndRedact",
116
+ "createIncrementalSanitizer",
103
117
  ]) {
104
118
  if (typeof module[name] !== "function") {
105
119
  throw new SecretScanError("INITIALIZATION_FAILED");
@@ -112,9 +126,9 @@ async function loadWasmModule() {
112
126
  * module.
113
127
  *
114
128
  * Exported so a test double can exercise this exact normalization — the
115
- * nested-metadata flattening above and the fixed `INCREMENTAL_UNAVAILABLE`
116
- * rejection below — against a fake module shaped like the real artifact,
117
- * without loading the artifact itself.
129
+ * nested-metadata flattening above and the incremental session wiring below
130
+ * — against a fake module shaped like the real artifact, without loading the
131
+ * artifact itself.
118
132
  */
119
133
  export function createBindingFromWasmModule(wasm) {
120
134
  return {
@@ -131,8 +145,18 @@ export function createBindingFromWasmModule(wasm) {
131
145
  findings: result.findings.map(toNativeFinding),
132
146
  };
133
147
  },
134
- createIncrementalSanitizer: () => {
135
- throw new SecretScanError("INCREMENTAL_UNAVAILABLE");
148
+ createIncrementalSanitizer: (options) => {
149
+ const session = wasm.createIncrementalSanitizer(options.limits.maxInputCodeUnits, options.limits.maxBufferedCodeUnits, options.limits.maxTokenCodeUnits, options.limits.maxMultilineCodeUnits, toWasmIncrementalPolicyCallback(options.policy), toWasmFormatterCallback(options.formatter));
150
+ return {
151
+ get state() {
152
+ return session.state;
153
+ },
154
+ append: (chunk) => toNativeIncrementalResult(session.append(chunk)),
155
+ finalize: () => toNativeIncrementalResult(session.finalize()),
156
+ abort: () => {
157
+ session.abort();
158
+ },
159
+ };
136
160
  },
137
161
  };
138
162
  }
@@ -16,11 +16,10 @@ import type { NativeBinding, NativeFinding, NativeFormatterCallback, NativeIncre
16
16
  * which this adapter renames to the contract's `text`; everything else is
17
17
  * already the documented UTF-16 shape.
18
18
  *
19
- * `createIncrementalSanitizer` is optional: `bindings/node` does not implement
20
- * it yet (unlike `bindings/python`, which wraps the same core
21
- * `IncrementalSanitizer`), so this adapter treats its absence the same way
22
- * `runtime/browser.ts` treats `bindings/wasm`'s documented non-support —
23
- * `INCREMENTAL_UNAVAILABLE` at call time, not a load-time failure.
19
+ * Incremental sanitization is part of the artifact contract. A package and
20
+ * platform addon are released in lockstep, so an addon without that export is
21
+ * an invalid installation and fails initialization with the other missing
22
+ * required exports.
24
23
  */
25
24
  interface NodeAddon {
26
25
  version(): string;
@@ -31,7 +30,7 @@ interface NodeAddon {
31
30
  readonly findings: readonly NativeFinding[];
32
31
  readonly redacted: string;
33
32
  };
34
- createIncrementalSanitizer?(options: NativeIncrementalOptions): NativeIncrementalSanitizer;
33
+ createIncrementalSanitizer(options: NativeIncrementalOptions): NativeIncrementalSanitizer;
35
34
  }
36
35
  /**
37
36
  * The addon package this host should have installed, or `undefined` on a
@@ -48,9 +47,8 @@ export declare function resolveAddonSpecifier(): string | undefined;
48
47
  /**
49
48
  * Builds the internal binding contract from an already-loaded addon.
50
49
  *
51
- * Exported so a test double can exercise this exact normalization
52
- * including the `createIncrementalSanitizer` fallback without loading the
53
- * real addon, the way `runtime/browser.ts`'s
50
+ * Exported so a test double can exercise this exact normalization without
51
+ * loading the real addon, the way `runtime/browser.ts`'s
54
52
  * `createBindingFromWasmModule` does for the WebAssembly artifact.
55
53
  */
56
54
  export declare function createBindingFromAddon(addon: NodeAddon): NativeBinding;
@@ -84,6 +84,7 @@ function loadAddon() {
84
84
  "scan",
85
85
  "redact",
86
86
  "scanAndRedact",
87
+ "createIncrementalSanitizer",
87
88
  ]) {
88
89
  if (typeof addon[name] !== "function") {
89
90
  throw new SecretScanError("INITIALIZATION_FAILED");
@@ -94,9 +95,8 @@ function loadAddon() {
94
95
  /**
95
96
  * Builds the internal binding contract from an already-loaded addon.
96
97
  *
97
- * Exported so a test double can exercise this exact normalization
98
- * including the `createIncrementalSanitizer` fallback without loading the
99
- * real addon, the way `runtime/browser.ts`'s
98
+ * Exported so a test double can exercise this exact normalization without
99
+ * loading the real addon, the way `runtime/browser.ts`'s
100
100
  * `createBindingFromWasmModule` does for the WebAssembly artifact.
101
101
  */
102
102
  export function createBindingFromAddon(addon) {
@@ -111,12 +111,7 @@ export function createBindingFromAddon(addon) {
111
111
  const result = addon.scanAndRedact(input, policy, formatter);
112
112
  return { text: result.redacted, findings: result.findings };
113
113
  },
114
- createIncrementalSanitizer: (options) => {
115
- if (typeof addon.createIncrementalSanitizer !== "function") {
116
- throw new SecretScanError("INCREMENTAL_UNAVAILABLE");
117
- }
118
- return addon.createIncrementalSanitizer(options);
119
- },
114
+ createIncrementalSanitizer: (options) => addon.createIncrementalSanitizer(options),
120
115
  };
121
116
  }
122
117
  export const loadNativeBinding = async () => createBindingFromAddon(loadAddon());
package/dist/runtime.js CHANGED
@@ -217,6 +217,13 @@ export function createRedactSecretRuntime(loadNativeBinding) {
217
217
  catch (thrown) {
218
218
  throw toSecretScanError(thrown, "INVALID_LIMITS");
219
219
  }
220
+ // Host validation cannot reach the core; abort releases its buffer and index.
221
+ let inputFailed = false;
222
+ function requireAccepting() {
223
+ if (inputFailed || session.state !== "accepting") {
224
+ throw new SecretScanError("INVALID_STATE");
225
+ }
226
+ }
220
227
  function run(operation, fallback) {
221
228
  let result;
222
229
  try {
@@ -232,11 +239,31 @@ export function createRedactSecretRuntime(loadNativeBinding) {
232
239
  }
233
240
  return Object.freeze({
234
241
  get state() {
235
- return session.state;
242
+ return inputFailed ? "failed" : session.state;
243
+ },
244
+ append: (chunk) => {
245
+ requireAccepting();
246
+ let text;
247
+ try {
248
+ text = requireString(chunk);
249
+ }
250
+ catch (thrown) {
251
+ inputFailed = true;
252
+ try {
253
+ session.abort();
254
+ }
255
+ finally {
256
+ throw toSecretScanError(thrown, "INVALID_INPUT");
257
+ }
258
+ }
259
+ return run(() => session.append(text), "DETECTOR_FAILURE");
260
+ },
261
+ finalize: () => {
262
+ requireAccepting();
263
+ return run(() => session.finalize(), "DETECTOR_FAILURE");
236
264
  },
237
- append: (chunk) => run(() => session.append(requireString(chunk)), "DETECTOR_FAILURE"),
238
- finalize: () => run(() => session.finalize(), "DETECTOR_FAILURE"),
239
265
  abort: () => {
266
+ requireAccepting();
240
267
  try {
241
268
  session.abort();
242
269
  }
package/dist/types.d.ts CHANGED
@@ -92,9 +92,13 @@ export interface IncrementalSecretPolicy {
92
92
  * requires. There are no environment-derived or silent defaults.
93
93
  */
94
94
  export interface IncrementalLimits {
95
+ /** UTF-8 byte ceiling; the legacy field name is retained for compatibility. */
95
96
  readonly maxInputCodeUnits: number;
97
+ /** UTF-8 byte ceiling; the legacy field name is retained for compatibility. */
96
98
  readonly maxBufferedCodeUnits: number;
99
+ /** UTF-8 byte ceiling; the legacy field name is retained for compatibility. */
97
100
  readonly maxTokenCodeUnits: number;
101
+ /** UTF-8 byte ceiling; the legacy field name is retained for compatibility. */
98
102
  readonly maxMultilineCodeUnits: number;
99
103
  }
100
104
  export interface IncrementalSanitizerOptions extends RedactOptions {
package/dist/version.d.ts CHANGED
@@ -5,4 +5,4 @@
5
5
  * SemVer version per release (`decision-release-bindings-in-lockstep`), so
6
6
  * `initialize()` refuses a binding artifact that reports a different one.
7
7
  */
8
- export declare const VERSION = "0.1.0-beta.1";
8
+ export declare const VERSION = "0.1.0-beta.2";
package/dist/version.js CHANGED
@@ -5,4 +5,4 @@
5
5
  * SemVer version per release (`decision-release-bindings-in-lockstep`), so
6
6
  * `initialize()` refuses a binding artifact that reports a different one.
7
7
  */
8
- export const VERSION = "0.1.0-beta.1";
8
+ export const VERSION = "0.1.0-beta.2";
package/package.json CHANGED
@@ -51,16 +51,16 @@
51
51
  "engines": {
52
52
  "node": "20.x || 22.x || 24.x"
53
53
  },
54
- "version": "0.1.0-beta.1",
54
+ "version": "0.1.0-beta.2",
55
55
  "dependencies": {
56
- "@redact-secret/wasm": "0.1.0-beta.1"
56
+ "@redact-secret/wasm": "0.1.0-beta.2"
57
57
  },
58
58
  "optionalDependencies": {
59
- "@redact-secret/node-darwin-arm64": "0.1.0-beta.1",
60
- "@redact-secret/node-darwin-x64": "0.1.0-beta.1",
61
- "@redact-secret/node-linux-arm64-gnu": "0.1.0-beta.1",
62
- "@redact-secret/node-linux-x64-gnu": "0.1.0-beta.1",
63
- "@redact-secret/node-win32-arm64-msvc": "0.1.0-beta.1",
64
- "@redact-secret/node-win32-x64-msvc": "0.1.0-beta.1"
59
+ "@redact-secret/node-darwin-arm64": "0.1.0-beta.2",
60
+ "@redact-secret/node-darwin-x64": "0.1.0-beta.2",
61
+ "@redact-secret/node-linux-arm64-gnu": "0.1.0-beta.2",
62
+ "@redact-secret/node-linux-x64-gnu": "0.1.0-beta.2",
63
+ "@redact-secret/node-win32-arm64-msvc": "0.1.0-beta.2",
64
+ "@redact-secret/node-win32-x64-msvc": "0.1.0-beta.2"
65
65
  }
66
66
  }