@pliuz/sdk 0.1.0 → 0.2.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/CHANGELOG.md +75 -0
- package/README.md +51 -22
- package/dist/adapters/ai.cjs +125 -47
- package/dist/adapters/ai.cjs.map +1 -1
- package/dist/adapters/ai.d.cts +8 -5
- package/dist/adapters/ai.d.ts +8 -5
- package/dist/adapters/ai.js +125 -47
- package/dist/adapters/ai.js.map +1 -1
- package/dist/{client-BABvN_88.d.cts → client-K9c9HsAc.d.cts} +9 -3
- package/dist/{client-BABvN_88.d.ts → client-K9c9HsAc.d.ts} +9 -3
- package/dist/index.cjs +104 -27
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +47 -5
- package/dist/index.d.ts +47 -5
- package/dist/index.js +103 -28
- package/dist/index.js.map +1 -1
- package/package.json +4 -5
package/dist/index.d.cts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { P as PliuzClient, O as Originator } from './client-
|
|
2
|
-
export { A as ApiErrorBody, a as ApprovalRequest, b as ApprovalStatus, C as CreateApprovalInput, c as CreateApprovalResponse, D as DEFAULT_BASE_URL, d as DEFAULT_MAX_RETRIES, e as DEFAULT_TIMEOUT_MS, E as ENV_API_KEY, f as ENV_BASE_URL, g as ExecutionInput, h as ExecutionResult, i as ExecutionStatus, j as OriginatorType, k as PliuzClientOptions } from './client-
|
|
1
|
+
import { P as PliuzClient, O as Originator } from './client-K9c9HsAc.cjs';
|
|
2
|
+
export { A as ApiErrorBody, a as ApprovalRequest, b as ApprovalStatus, C as CreateApprovalInput, c as CreateApprovalResponse, D as DEFAULT_BASE_URL, d as DEFAULT_MAX_RETRIES, e as DEFAULT_TIMEOUT_MS, E as ENV_API_KEY, f as ENV_BASE_URL, g as ExecutionInput, h as ExecutionResult, i as ExecutionStatus, j as OriginatorType, k as PliuzClientOptions } from './client-K9c9HsAc.cjs';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Single source of truth for the package version.
|
|
6
6
|
* Kept in sync with `package.json` by release tooling at publish time.
|
|
7
7
|
*/
|
|
8
|
-
declare const VERSION: "0.
|
|
8
|
+
declare const VERSION: "0.2.2";
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
11
|
* Field-level redaction applied client-side BEFORE sending to Pliuz.
|
|
@@ -31,11 +31,16 @@ declare const REDACTED_PLACEHOLDER: "<redacted>";
|
|
|
31
31
|
* Returns a deep copy of `payload` with values at `paths` replaced by
|
|
32
32
|
* `REDACTED_PLACEHOLDER`. Does not mutate the input.
|
|
33
33
|
*
|
|
34
|
+
* When `strict` is true, a syntactically valid path that resolves to no
|
|
35
|
+
* existing field throws {@link PliuzRedactionPathError} instead of being a
|
|
36
|
+
* silent no-op — turn it on to fail loud and avoid leaking a field you meant
|
|
37
|
+
* to redact. Defaults to false (lenient: a typo'd path is ignored).
|
|
38
|
+
*
|
|
34
39
|
* @example
|
|
35
40
|
* applyRedaction({ customer: { ssn: '123-45-6789' } }, ['customer.ssn'])
|
|
36
41
|
* // → { customer: { ssn: '<redacted>' } }
|
|
37
42
|
*/
|
|
38
|
-
declare function applyRedaction<T extends Record<string, unknown>>(payload: T, paths: readonly string[] | null | undefined): T;
|
|
43
|
+
declare function applyRedaction<T extends Record<string, unknown>>(payload: T, paths: readonly string[] | null | undefined, strict?: boolean): T;
|
|
39
44
|
|
|
40
45
|
/**
|
|
41
46
|
* Error hierarchy for the Pliuz SDK.
|
|
@@ -65,6 +70,16 @@ declare class PliuzNetworkError extends PliuzError {
|
|
|
65
70
|
readonly cause?: unknown | undefined;
|
|
66
71
|
constructor(message: string, cause?: unknown | undefined);
|
|
67
72
|
}
|
|
73
|
+
/**
|
|
74
|
+
* A redaction path was syntactically valid but matched no field. Thrown only
|
|
75
|
+
* in strict mode (`redactStrict: true`) to catch the silent-leak footgun where
|
|
76
|
+
* a typo like `'customer.ssnn'` would otherwise be a no-op, leaving the real
|
|
77
|
+
* `customer.ssn` unredacted in the payload sent to Pliuz.
|
|
78
|
+
*/
|
|
79
|
+
declare class PliuzRedactionPathError extends PliuzError {
|
|
80
|
+
readonly path: string;
|
|
81
|
+
constructor(path: string);
|
|
82
|
+
}
|
|
68
83
|
declare class PliuzTimeoutError extends PliuzError {
|
|
69
84
|
constructor(message: string);
|
|
70
85
|
}
|
|
@@ -112,6 +127,19 @@ declare class PliuzApprovalTimeoutError extends PliuzError {
|
|
|
112
127
|
readonly timeoutMs: number;
|
|
113
128
|
constructor(approvalId: string, timeoutMs: number);
|
|
114
129
|
}
|
|
130
|
+
/**
|
|
131
|
+
* A human approved with EDITED args (action='edit') but the SDK cannot map
|
|
132
|
+
* `final_args` back onto the wrapped function's parameters. The SDK refuses
|
|
133
|
+
* to execute the ORIGINAL (unapproved) args — that would make the audit
|
|
134
|
+
* trail lie about what was approved vs executed. Carries `finalArgs` so the
|
|
135
|
+
* caller can apply the edit manually, or pass an `applyFinalArgs` mapper in
|
|
136
|
+
* GatedOptions to handle edits automatically.
|
|
137
|
+
*/
|
|
138
|
+
declare class PliuzEditNotApplicableError extends PliuzError {
|
|
139
|
+
readonly approvalId: string;
|
|
140
|
+
readonly finalArgs: Record<string, unknown>;
|
|
141
|
+
constructor(approvalId: string, finalArgs: Record<string, unknown>);
|
|
142
|
+
}
|
|
115
143
|
declare function errorForStatus(statusCode: number, errorCode: string, message: string, details?: Record<string, unknown>): PliuzApiError;
|
|
116
144
|
|
|
117
145
|
/**
|
|
@@ -147,6 +175,12 @@ interface GatedOptions<TArgs extends readonly unknown[]> {
|
|
|
147
175
|
policy?: string;
|
|
148
176
|
/** Redaction paths applied to tool_args BEFORE sending. */
|
|
149
177
|
redact?: readonly string[];
|
|
178
|
+
/**
|
|
179
|
+
* When true, a `redact` path that matches no field throws
|
|
180
|
+
* PliuzRedactionPathError instead of being a silent no-op — fail loud so a
|
|
181
|
+
* typo'd path never leaks the field you meant to redact. Default: false.
|
|
182
|
+
*/
|
|
183
|
+
redactStrict?: boolean;
|
|
150
184
|
/** Override the tool name. Default: `fn.name` (may be empty for anonymous). */
|
|
151
185
|
toolName?: string;
|
|
152
186
|
/**
|
|
@@ -167,6 +201,14 @@ interface GatedOptions<TArgs extends readonly unknown[]> {
|
|
|
167
201
|
sessionId?: string;
|
|
168
202
|
/** Optional originator (default: { type: 'system' }). */
|
|
169
203
|
originator?: Originator;
|
|
204
|
+
/**
|
|
205
|
+
* Map human-EDITED args (approval decided with action='edit') back onto
|
|
206
|
+
* the wrapped function's argument tuple. Required to honor edits when a
|
|
207
|
+
* custom `toolArgs` mapper is used (the SDK cannot invert an arbitrary
|
|
208
|
+
* mapper). Without it, an edited approval throws
|
|
209
|
+
* PliuzEditNotApplicableError instead of executing the original args.
|
|
210
|
+
*/
|
|
211
|
+
applyFinalArgs?: (finalArgs: Record<string, unknown>, originalArgs: TArgs) => TArgs;
|
|
170
212
|
}
|
|
171
213
|
/**
|
|
172
214
|
* Wrap a function so every call is gated by Pliuz.
|
|
@@ -176,4 +218,4 @@ interface GatedOptions<TArgs extends readonly unknown[]> {
|
|
|
176
218
|
*/
|
|
177
219
|
declare function gated<TArgs extends readonly unknown[], TResult>(options: GatedOptions<TArgs>, fn: (...args: TArgs) => Promise<TResult> | TResult): (...args: TArgs) => Promise<TResult>;
|
|
178
220
|
|
|
179
|
-
export { DEFAULT_GATED_POLL_INTERVAL_MS, DEFAULT_GATED_TIMEOUT_MS, type GatedOptions, Originator, PliuzApiError, PliuzApprovalExpiredError, PliuzApprovalTimeoutError, PliuzAuthError, PliuzClient, PliuzConflictError, PliuzError, PliuzForbiddenError, PliuzNetworkError, PliuzNotFoundError, PliuzPolicyError, PliuzRateLimitError, PliuzRejectedError, PliuzServerError, PliuzTimeoutError, PliuzValidationError, REDACTED_PLACEHOLDER, VERSION, applyRedaction, errorForStatus, gated };
|
|
221
|
+
export { DEFAULT_GATED_POLL_INTERVAL_MS, DEFAULT_GATED_TIMEOUT_MS, type GatedOptions, Originator, PliuzApiError, PliuzApprovalExpiredError, PliuzApprovalTimeoutError, PliuzAuthError, PliuzClient, PliuzConflictError, PliuzEditNotApplicableError, PliuzError, PliuzForbiddenError, PliuzNetworkError, PliuzNotFoundError, PliuzPolicyError, PliuzRateLimitError, PliuzRedactionPathError, PliuzRejectedError, PliuzServerError, PliuzTimeoutError, PliuzValidationError, REDACTED_PLACEHOLDER, VERSION, applyRedaction, errorForStatus, gated };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { P as PliuzClient, O as Originator } from './client-
|
|
2
|
-
export { A as ApiErrorBody, a as ApprovalRequest, b as ApprovalStatus, C as CreateApprovalInput, c as CreateApprovalResponse, D as DEFAULT_BASE_URL, d as DEFAULT_MAX_RETRIES, e as DEFAULT_TIMEOUT_MS, E as ENV_API_KEY, f as ENV_BASE_URL, g as ExecutionInput, h as ExecutionResult, i as ExecutionStatus, j as OriginatorType, k as PliuzClientOptions } from './client-
|
|
1
|
+
import { P as PliuzClient, O as Originator } from './client-K9c9HsAc.js';
|
|
2
|
+
export { A as ApiErrorBody, a as ApprovalRequest, b as ApprovalStatus, C as CreateApprovalInput, c as CreateApprovalResponse, D as DEFAULT_BASE_URL, d as DEFAULT_MAX_RETRIES, e as DEFAULT_TIMEOUT_MS, E as ENV_API_KEY, f as ENV_BASE_URL, g as ExecutionInput, h as ExecutionResult, i as ExecutionStatus, j as OriginatorType, k as PliuzClientOptions } from './client-K9c9HsAc.js';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Single source of truth for the package version.
|
|
6
6
|
* Kept in sync with `package.json` by release tooling at publish time.
|
|
7
7
|
*/
|
|
8
|
-
declare const VERSION: "0.
|
|
8
|
+
declare const VERSION: "0.2.2";
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
11
|
* Field-level redaction applied client-side BEFORE sending to Pliuz.
|
|
@@ -31,11 +31,16 @@ declare const REDACTED_PLACEHOLDER: "<redacted>";
|
|
|
31
31
|
* Returns a deep copy of `payload` with values at `paths` replaced by
|
|
32
32
|
* `REDACTED_PLACEHOLDER`. Does not mutate the input.
|
|
33
33
|
*
|
|
34
|
+
* When `strict` is true, a syntactically valid path that resolves to no
|
|
35
|
+
* existing field throws {@link PliuzRedactionPathError} instead of being a
|
|
36
|
+
* silent no-op — turn it on to fail loud and avoid leaking a field you meant
|
|
37
|
+
* to redact. Defaults to false (lenient: a typo'd path is ignored).
|
|
38
|
+
*
|
|
34
39
|
* @example
|
|
35
40
|
* applyRedaction({ customer: { ssn: '123-45-6789' } }, ['customer.ssn'])
|
|
36
41
|
* // → { customer: { ssn: '<redacted>' } }
|
|
37
42
|
*/
|
|
38
|
-
declare function applyRedaction<T extends Record<string, unknown>>(payload: T, paths: readonly string[] | null | undefined): T;
|
|
43
|
+
declare function applyRedaction<T extends Record<string, unknown>>(payload: T, paths: readonly string[] | null | undefined, strict?: boolean): T;
|
|
39
44
|
|
|
40
45
|
/**
|
|
41
46
|
* Error hierarchy for the Pliuz SDK.
|
|
@@ -65,6 +70,16 @@ declare class PliuzNetworkError extends PliuzError {
|
|
|
65
70
|
readonly cause?: unknown | undefined;
|
|
66
71
|
constructor(message: string, cause?: unknown | undefined);
|
|
67
72
|
}
|
|
73
|
+
/**
|
|
74
|
+
* A redaction path was syntactically valid but matched no field. Thrown only
|
|
75
|
+
* in strict mode (`redactStrict: true`) to catch the silent-leak footgun where
|
|
76
|
+
* a typo like `'customer.ssnn'` would otherwise be a no-op, leaving the real
|
|
77
|
+
* `customer.ssn` unredacted in the payload sent to Pliuz.
|
|
78
|
+
*/
|
|
79
|
+
declare class PliuzRedactionPathError extends PliuzError {
|
|
80
|
+
readonly path: string;
|
|
81
|
+
constructor(path: string);
|
|
82
|
+
}
|
|
68
83
|
declare class PliuzTimeoutError extends PliuzError {
|
|
69
84
|
constructor(message: string);
|
|
70
85
|
}
|
|
@@ -112,6 +127,19 @@ declare class PliuzApprovalTimeoutError extends PliuzError {
|
|
|
112
127
|
readonly timeoutMs: number;
|
|
113
128
|
constructor(approvalId: string, timeoutMs: number);
|
|
114
129
|
}
|
|
130
|
+
/**
|
|
131
|
+
* A human approved with EDITED args (action='edit') but the SDK cannot map
|
|
132
|
+
* `final_args` back onto the wrapped function's parameters. The SDK refuses
|
|
133
|
+
* to execute the ORIGINAL (unapproved) args — that would make the audit
|
|
134
|
+
* trail lie about what was approved vs executed. Carries `finalArgs` so the
|
|
135
|
+
* caller can apply the edit manually, or pass an `applyFinalArgs` mapper in
|
|
136
|
+
* GatedOptions to handle edits automatically.
|
|
137
|
+
*/
|
|
138
|
+
declare class PliuzEditNotApplicableError extends PliuzError {
|
|
139
|
+
readonly approvalId: string;
|
|
140
|
+
readonly finalArgs: Record<string, unknown>;
|
|
141
|
+
constructor(approvalId: string, finalArgs: Record<string, unknown>);
|
|
142
|
+
}
|
|
115
143
|
declare function errorForStatus(statusCode: number, errorCode: string, message: string, details?: Record<string, unknown>): PliuzApiError;
|
|
116
144
|
|
|
117
145
|
/**
|
|
@@ -147,6 +175,12 @@ interface GatedOptions<TArgs extends readonly unknown[]> {
|
|
|
147
175
|
policy?: string;
|
|
148
176
|
/** Redaction paths applied to tool_args BEFORE sending. */
|
|
149
177
|
redact?: readonly string[];
|
|
178
|
+
/**
|
|
179
|
+
* When true, a `redact` path that matches no field throws
|
|
180
|
+
* PliuzRedactionPathError instead of being a silent no-op — fail loud so a
|
|
181
|
+
* typo'd path never leaks the field you meant to redact. Default: false.
|
|
182
|
+
*/
|
|
183
|
+
redactStrict?: boolean;
|
|
150
184
|
/** Override the tool name. Default: `fn.name` (may be empty for anonymous). */
|
|
151
185
|
toolName?: string;
|
|
152
186
|
/**
|
|
@@ -167,6 +201,14 @@ interface GatedOptions<TArgs extends readonly unknown[]> {
|
|
|
167
201
|
sessionId?: string;
|
|
168
202
|
/** Optional originator (default: { type: 'system' }). */
|
|
169
203
|
originator?: Originator;
|
|
204
|
+
/**
|
|
205
|
+
* Map human-EDITED args (approval decided with action='edit') back onto
|
|
206
|
+
* the wrapped function's argument tuple. Required to honor edits when a
|
|
207
|
+
* custom `toolArgs` mapper is used (the SDK cannot invert an arbitrary
|
|
208
|
+
* mapper). Without it, an edited approval throws
|
|
209
|
+
* PliuzEditNotApplicableError instead of executing the original args.
|
|
210
|
+
*/
|
|
211
|
+
applyFinalArgs?: (finalArgs: Record<string, unknown>, originalArgs: TArgs) => TArgs;
|
|
170
212
|
}
|
|
171
213
|
/**
|
|
172
214
|
* Wrap a function so every call is gated by Pliuz.
|
|
@@ -176,4 +218,4 @@ interface GatedOptions<TArgs extends readonly unknown[]> {
|
|
|
176
218
|
*/
|
|
177
219
|
declare function gated<TArgs extends readonly unknown[], TResult>(options: GatedOptions<TArgs>, fn: (...args: TArgs) => Promise<TResult> | TResult): (...args: TArgs) => Promise<TResult>;
|
|
178
220
|
|
|
179
|
-
export { DEFAULT_GATED_POLL_INTERVAL_MS, DEFAULT_GATED_TIMEOUT_MS, type GatedOptions, Originator, PliuzApiError, PliuzApprovalExpiredError, PliuzApprovalTimeoutError, PliuzAuthError, PliuzClient, PliuzConflictError, PliuzError, PliuzForbiddenError, PliuzNetworkError, PliuzNotFoundError, PliuzPolicyError, PliuzRateLimitError, PliuzRejectedError, PliuzServerError, PliuzTimeoutError, PliuzValidationError, REDACTED_PLACEHOLDER, VERSION, applyRedaction, errorForStatus, gated };
|
|
221
|
+
export { DEFAULT_GATED_POLL_INTERVAL_MS, DEFAULT_GATED_TIMEOUT_MS, type GatedOptions, Originator, PliuzApiError, PliuzApprovalExpiredError, PliuzApprovalTimeoutError, PliuzAuthError, PliuzClient, PliuzConflictError, PliuzEditNotApplicableError, PliuzError, PliuzForbiddenError, PliuzNetworkError, PliuzNotFoundError, PliuzPolicyError, PliuzRateLimitError, PliuzRedactionPathError, PliuzRejectedError, PliuzServerError, PliuzTimeoutError, PliuzValidationError, REDACTED_PLACEHOLDER, VERSION, applyRedaction, errorForStatus, gated };
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createHash } from 'crypto';
|
|
2
2
|
|
|
3
3
|
// src/version.ts
|
|
4
|
-
var VERSION = "0.
|
|
4
|
+
var VERSION = "0.2.2";
|
|
5
5
|
|
|
6
6
|
// src/errors.ts
|
|
7
7
|
var PliuzError = class extends Error {
|
|
@@ -20,6 +20,17 @@ var PliuzNetworkError = class extends PliuzError {
|
|
|
20
20
|
}
|
|
21
21
|
cause;
|
|
22
22
|
};
|
|
23
|
+
var PliuzRedactionPathError = class extends PliuzError {
|
|
24
|
+
constructor(path) {
|
|
25
|
+
super(
|
|
26
|
+
`redaction path '${path}' did not match any field in the payload (strict mode). Fix the path or set redactStrict=false to ignore misses.`
|
|
27
|
+
);
|
|
28
|
+
this.path = path;
|
|
29
|
+
this.name = "PliuzRedactionPathError";
|
|
30
|
+
Object.setPrototypeOf(this, new.target.prototype);
|
|
31
|
+
}
|
|
32
|
+
path;
|
|
33
|
+
};
|
|
23
34
|
var PliuzTimeoutError = class extends PliuzError {
|
|
24
35
|
constructor(message) {
|
|
25
36
|
super(message);
|
|
@@ -130,6 +141,19 @@ var PliuzApprovalTimeoutError = class extends PliuzError {
|
|
|
130
141
|
approvalId;
|
|
131
142
|
timeoutMs;
|
|
132
143
|
};
|
|
144
|
+
var PliuzEditNotApplicableError = class extends PliuzError {
|
|
145
|
+
constructor(approvalId, finalArgs) {
|
|
146
|
+
super(
|
|
147
|
+
`approval ${approvalId} was approved with edited args, but they cannot be mapped back to the wrapped function (custom toolArgs mapper without applyFinalArgs, or incompatible shape) \u2014 refusing to execute the original (unapproved) args. Apply e.finalArgs manually.`
|
|
148
|
+
);
|
|
149
|
+
this.approvalId = approvalId;
|
|
150
|
+
this.finalArgs = finalArgs;
|
|
151
|
+
this.name = "PliuzEditNotApplicableError";
|
|
152
|
+
Object.setPrototypeOf(this, new.target.prototype);
|
|
153
|
+
}
|
|
154
|
+
approvalId;
|
|
155
|
+
finalArgs;
|
|
156
|
+
};
|
|
133
157
|
var STATUS_TO_ERROR = {
|
|
134
158
|
400: PliuzValidationError,
|
|
135
159
|
401: PliuzAuthError,
|
|
@@ -236,7 +260,7 @@ async function request(opts) {
|
|
|
236
260
|
}
|
|
237
261
|
|
|
238
262
|
// src/client.ts
|
|
239
|
-
var DEFAULT_BASE_URL = "https://pliuz
|
|
263
|
+
var DEFAULT_BASE_URL = "https://pliuz.com";
|
|
240
264
|
var DEFAULT_TIMEOUT_MS = 3e4;
|
|
241
265
|
var DEFAULT_MAX_RETRIES = 3;
|
|
242
266
|
var ENV_API_KEY = "PLIUZ_API_KEY";
|
|
@@ -261,6 +285,7 @@ function approvalUrl(baseUrl, approvalId, suffix) {
|
|
|
261
285
|
if (suffix) path += `/${suffix}`;
|
|
262
286
|
return baseUrl + path;
|
|
263
287
|
}
|
|
288
|
+
var MAX_WAIT_SECONDS = 25;
|
|
264
289
|
var PliuzClient = class {
|
|
265
290
|
apiKey;
|
|
266
291
|
baseUrl;
|
|
@@ -310,13 +335,22 @@ var PliuzClient = class {
|
|
|
310
335
|
/**
|
|
311
336
|
* Fetch the current state of an approval request.
|
|
312
337
|
* Used by polling in `gated()` to detect status transitions.
|
|
338
|
+
*
|
|
339
|
+
* Pass `waitSeconds` (1..25) to long-poll: the server holds the request
|
|
340
|
+
* open and returns the instant the approval stops being `pending`, or after
|
|
341
|
+
* `waitSeconds` (still pending). Cuts polling volume and decision latency
|
|
342
|
+
* ~12x vs fixed-interval polling. The per-request HTTP timeout is bumped to
|
|
343
|
+
* cover the wait window.
|
|
313
344
|
*/
|
|
314
|
-
async getApproval(approvalId) {
|
|
345
|
+
async getApproval(approvalId, waitSeconds) {
|
|
346
|
+
const wait = waitSeconds && waitSeconds > 0 ? Math.min(Math.floor(waitSeconds), MAX_WAIT_SECONDS) : 0;
|
|
347
|
+
const url = wait > 0 ? `${approvalUrl(this.baseUrl, approvalId)}?wait=${wait}` : approvalUrl(this.baseUrl, approvalId);
|
|
315
348
|
return request({
|
|
316
349
|
method: "GET",
|
|
317
|
-
url
|
|
350
|
+
url,
|
|
318
351
|
apiKey: this.apiKey,
|
|
319
|
-
|
|
352
|
+
// Give the socket head-room over the server-side wait window.
|
|
353
|
+
timeoutMs: wait > 0 ? Math.max(this.timeoutMs, wait * 1e3 + 5e3) : this.timeoutMs,
|
|
320
354
|
maxRetries: this.maxRetries,
|
|
321
355
|
fetchImpl: this.fetchImpl
|
|
322
356
|
});
|
|
@@ -349,13 +383,16 @@ var PliuzClient = class {
|
|
|
349
383
|
|
|
350
384
|
// src/redaction.ts
|
|
351
385
|
var REDACTED_PLACEHOLDER = "<redacted>";
|
|
352
|
-
function applyRedaction(payload, paths) {
|
|
386
|
+
function applyRedaction(payload, paths, strict = false) {
|
|
353
387
|
if (!paths || paths.length === 0) {
|
|
354
388
|
return deepClone(payload);
|
|
355
389
|
}
|
|
356
390
|
const result = deepClone(payload);
|
|
357
391
|
for (const path of paths) {
|
|
358
|
-
redactPath(result, parsePath(path));
|
|
392
|
+
const matched = redactPath(result, parsePath(path));
|
|
393
|
+
if (strict && !matched) {
|
|
394
|
+
throw new PliuzRedactionPathError(path);
|
|
395
|
+
}
|
|
359
396
|
}
|
|
360
397
|
return result;
|
|
361
398
|
}
|
|
@@ -383,28 +420,30 @@ function parsePath(path) {
|
|
|
383
420
|
return segments;
|
|
384
421
|
}
|
|
385
422
|
function redactPath(node, segments) {
|
|
386
|
-
if (segments.length === 0) return;
|
|
387
|
-
if (!isPlainObject(node)) return;
|
|
423
|
+
if (segments.length === 0) return true;
|
|
424
|
+
if (!isPlainObject(node)) return false;
|
|
388
425
|
const [head, ...rest] = segments;
|
|
389
|
-
if (!head) return;
|
|
426
|
+
if (!head) return false;
|
|
390
427
|
const { key, isArrayWildcard } = head;
|
|
391
|
-
if (!(key in node)) return;
|
|
428
|
+
if (!(key in node)) return false;
|
|
392
429
|
if (isArrayWildcard) {
|
|
393
430
|
const target = node[key];
|
|
394
|
-
if (!Array.isArray(target)) return;
|
|
431
|
+
if (!Array.isArray(target)) return false;
|
|
395
432
|
if (rest.length === 0) {
|
|
396
433
|
node[key] = target.map(() => REDACTED_PLACEHOLDER);
|
|
397
|
-
return;
|
|
434
|
+
return true;
|
|
398
435
|
}
|
|
436
|
+
let matched = target.length > 0;
|
|
399
437
|
for (const item of target) {
|
|
400
|
-
redactPath(item, rest);
|
|
438
|
+
if (!redactPath(item, rest)) matched = false;
|
|
401
439
|
}
|
|
440
|
+
return matched;
|
|
402
441
|
} else {
|
|
403
442
|
if (rest.length === 0) {
|
|
404
443
|
node[key] = REDACTED_PLACEHOLDER;
|
|
405
|
-
|
|
406
|
-
redactPath(node[key], rest);
|
|
444
|
+
return true;
|
|
407
445
|
}
|
|
446
|
+
return redactPath(node[key], rest);
|
|
408
447
|
}
|
|
409
448
|
}
|
|
410
449
|
function isPlainObject(v) {
|
|
@@ -430,8 +469,8 @@ function gated(options, fn) {
|
|
|
430
469
|
return async (...args) => {
|
|
431
470
|
const activeClient = options.client ?? new PliuzClient();
|
|
432
471
|
const rawArgs = toolArgsMapper(...args);
|
|
433
|
-
const sendArgs = redactPaths && redactPaths.length > 0 ? applyRedaction(rawArgs, redactPaths) : rawArgs;
|
|
434
|
-
const idempotencyKey = idempotencyKeyFor(toolName,
|
|
472
|
+
const sendArgs = redactPaths && redactPaths.length > 0 ? applyRedaction(rawArgs, redactPaths, options.redactStrict ?? false) : rawArgs;
|
|
473
|
+
const idempotencyKey = idempotencyKeyFor(toolName, rawArgs, options.sessionId);
|
|
435
474
|
const metadata = {};
|
|
436
475
|
if (options.policy) metadata.policy = options.policy;
|
|
437
476
|
const response = await activeClient.createApproval({
|
|
@@ -450,27 +489,38 @@ function gated(options, fn) {
|
|
|
450
489
|
if (TERMINAL_EXPIRED.has(response.status)) {
|
|
451
490
|
throw new PliuzApprovalExpiredError(approvalId);
|
|
452
491
|
}
|
|
492
|
+
let approval = null;
|
|
453
493
|
if (!TERMINAL_OK.has(response.status)) {
|
|
454
494
|
const deadline = Date.now() + timeoutMs;
|
|
455
495
|
while (true) {
|
|
456
|
-
|
|
496
|
+
const remainingMs = deadline - Date.now();
|
|
497
|
+
if (remainingMs <= 0) {
|
|
457
498
|
throw new PliuzApprovalTimeoutError(approvalId, timeoutMs);
|
|
458
499
|
}
|
|
459
|
-
|
|
460
|
-
const
|
|
500
|
+
const waitSeconds = Math.max(1, Math.ceil(Math.min(remainingMs, pollIntervalMs * 1e3) / 1e3));
|
|
501
|
+
const callStart = Date.now();
|
|
502
|
+
approval = await activeClient.getApproval(approvalId, waitSeconds);
|
|
461
503
|
if (terminalOrThrow(approval)) break;
|
|
504
|
+
if (Date.now() - callStart < 250) await sleep2(pollIntervalMs);
|
|
462
505
|
}
|
|
506
|
+
} else if (response.is_replay) {
|
|
507
|
+
approval = await activeClient.getApproval(approvalId);
|
|
508
|
+
}
|
|
509
|
+
let callArgs = args;
|
|
510
|
+
const finalArgs = approval?.final_args ?? null;
|
|
511
|
+
if (finalArgs) {
|
|
512
|
+
callArgs = resolveEditedArgs(approvalId, rawArgs, finalArgs, args, options);
|
|
463
513
|
}
|
|
464
514
|
const started = Date.now();
|
|
465
515
|
try {
|
|
466
|
-
const result = await fn(...
|
|
516
|
+
const result = await fn(...callArgs);
|
|
467
517
|
const latencyMs = Date.now() - started;
|
|
468
|
-
|
|
518
|
+
await safeReport(activeClient, approvalId, "success", null, latencyMs, result, redactPaths);
|
|
469
519
|
return result;
|
|
470
520
|
} catch (e) {
|
|
471
521
|
const latencyMs = Date.now() - started;
|
|
472
522
|
const errMsg = e instanceof Error ? e.message : String(e);
|
|
473
|
-
|
|
523
|
+
await safeReport(activeClient, approvalId, "error", errMsg.slice(0, 2e3), latencyMs, null, redactPaths);
|
|
474
524
|
throw e;
|
|
475
525
|
}
|
|
476
526
|
};
|
|
@@ -494,6 +544,30 @@ function canonicalJSON(value) {
|
|
|
494
544
|
const keys = Object.keys(obj).sort();
|
|
495
545
|
return "{" + keys.map((k) => JSON.stringify(k) + ":" + canonicalJSON(obj[k])).join(",") + "}";
|
|
496
546
|
}
|
|
547
|
+
function mergeFinalArgs(raw, final) {
|
|
548
|
+
if (isPlainRecord(raw) && isPlainRecord(final)) {
|
|
549
|
+
const out = {};
|
|
550
|
+
for (const [k, v] of Object.entries(final)) {
|
|
551
|
+
out[k] = k in raw ? mergeFinalArgs(raw[k], v) : v;
|
|
552
|
+
}
|
|
553
|
+
return out;
|
|
554
|
+
}
|
|
555
|
+
if (final === REDACTED_PLACEHOLDER) return raw;
|
|
556
|
+
return final;
|
|
557
|
+
}
|
|
558
|
+
function isPlainRecord(v) {
|
|
559
|
+
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
560
|
+
}
|
|
561
|
+
function resolveEditedArgs(approvalId, rawArgs, finalArgs, originalArgs, options) {
|
|
562
|
+
const merged = mergeFinalArgs(rawArgs, finalArgs);
|
|
563
|
+
if (options.applyFinalArgs) {
|
|
564
|
+
return options.applyFinalArgs(merged, originalArgs);
|
|
565
|
+
}
|
|
566
|
+
if (options.toolArgs === void 0 && Array.isArray(merged.args)) {
|
|
567
|
+
return merged.args;
|
|
568
|
+
}
|
|
569
|
+
throw new PliuzEditNotApplicableError(approvalId, merged);
|
|
570
|
+
}
|
|
497
571
|
function terminalOrThrow(approval) {
|
|
498
572
|
if (TERMINAL_OK.has(approval.status)) return true;
|
|
499
573
|
if (TERMINAL_REJECT.has(approval.status)) {
|
|
@@ -504,13 +578,14 @@ function terminalOrThrow(approval) {
|
|
|
504
578
|
}
|
|
505
579
|
return false;
|
|
506
580
|
}
|
|
507
|
-
async function safeReport(client, approvalId, status, errorMessage, latencyMs, result) {
|
|
581
|
+
async function safeReport(client, approvalId, status, errorMessage, latencyMs, result, redactPaths) {
|
|
508
582
|
let excerpt = null;
|
|
509
583
|
if (result != null) {
|
|
584
|
+
const toDump = redactPaths && redactPaths.length > 0 && isPlainRecord(result) ? applyRedaction(result, redactPaths) : result;
|
|
510
585
|
try {
|
|
511
|
-
excerpt = JSON.stringify(
|
|
586
|
+
excerpt = JSON.stringify(toDump).slice(0, 2e3);
|
|
512
587
|
} catch {
|
|
513
|
-
excerpt = String(
|
|
588
|
+
excerpt = String(toDump).slice(0, 2e3);
|
|
514
589
|
}
|
|
515
590
|
}
|
|
516
591
|
try {
|
|
@@ -527,6 +602,6 @@ function sleep2(ms) {
|
|
|
527
602
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
528
603
|
}
|
|
529
604
|
|
|
530
|
-
export { DEFAULT_BASE_URL, DEFAULT_GATED_POLL_INTERVAL_MS, DEFAULT_GATED_TIMEOUT_MS, DEFAULT_MAX_RETRIES, DEFAULT_TIMEOUT_MS, ENV_API_KEY, ENV_BASE_URL, PliuzApiError, PliuzApprovalExpiredError, PliuzApprovalTimeoutError, PliuzAuthError, PliuzClient, PliuzConflictError, PliuzError, PliuzForbiddenError, PliuzNetworkError, PliuzNotFoundError, PliuzPolicyError, PliuzRateLimitError, PliuzRejectedError, PliuzServerError, PliuzTimeoutError, PliuzValidationError, REDACTED_PLACEHOLDER, VERSION, applyRedaction, errorForStatus, gated };
|
|
605
|
+
export { DEFAULT_BASE_URL, DEFAULT_GATED_POLL_INTERVAL_MS, DEFAULT_GATED_TIMEOUT_MS, DEFAULT_MAX_RETRIES, DEFAULT_TIMEOUT_MS, ENV_API_KEY, ENV_BASE_URL, PliuzApiError, PliuzApprovalExpiredError, PliuzApprovalTimeoutError, PliuzAuthError, PliuzClient, PliuzConflictError, PliuzEditNotApplicableError, PliuzError, PliuzForbiddenError, PliuzNetworkError, PliuzNotFoundError, PliuzPolicyError, PliuzRateLimitError, PliuzRedactionPathError, PliuzRejectedError, PliuzServerError, PliuzTimeoutError, PliuzValidationError, REDACTED_PLACEHOLDER, VERSION, applyRedaction, errorForStatus, gated };
|
|
531
606
|
//# sourceMappingURL=index.js.map
|
|
532
607
|
//# sourceMappingURL=index.js.map
|