@cdot65/prisma-airs-sdk 0.1.2 → 0.2.1
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 +33 -1
- package/dist/index.cjs +704 -42
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +9312 -32
- package/dist/index.d.ts +9312 -32
- package/dist/index.js +675 -42
- package/dist/index.js.map +1 -1
- package/package.json +10 -3
package/dist/index.js
CHANGED
|
@@ -23,12 +23,24 @@ var MAX_NUMBER_OF_BATCH_SCAN_OBJECTS = 5;
|
|
|
23
23
|
var MAX_CONNECTION_POOL_SIZE = 100;
|
|
24
24
|
var MAX_NUMBER_OF_RETRIES = 5;
|
|
25
25
|
var HTTP_FORCE_RETRY_STATUS_CODES = [500, 502, 503, 504];
|
|
26
|
-
var SDK_VERSION = "0.1
|
|
26
|
+
var SDK_VERSION = "0.2.1";
|
|
27
27
|
var USER_AGENT = `PAN-AIRS/${SDK_VERSION}-typescript-sdk`;
|
|
28
|
+
var DEFAULT_MGMT_ENDPOINT = "https://api.sase.paloaltonetworks.com/aisec";
|
|
29
|
+
var DEFAULT_TOKEN_ENDPOINT = "https://auth.apps.paloaltonetworks.com/oauth2/access_token";
|
|
30
|
+
var MGMT_CLIENT_ID = "PANW_MGMT_CLIENT_ID";
|
|
31
|
+
var MGMT_CLIENT_SECRET = "PANW_MGMT_CLIENT_SECRET";
|
|
32
|
+
var MGMT_TSG_ID = "PANW_MGMT_TSG_ID";
|
|
33
|
+
var MGMT_ENDPOINT = "PANW_MGMT_ENDPOINT";
|
|
34
|
+
var MGMT_TOKEN_ENDPOINT = "PANW_MGMT_TOKEN_ENDPOINT";
|
|
28
35
|
var SYNC_SCAN_PATH = "/v1/scan/sync/request";
|
|
29
36
|
var ASYNC_SCAN_PATH = "/v1/scan/async/request";
|
|
30
37
|
var SCAN_RESULTS_PATH = "/v1/scan/results";
|
|
31
38
|
var SCAN_REPORTS_PATH = "/v1/scan/reports";
|
|
39
|
+
var MGMT_PROFILE_PATH = "/v1/mgmt/profile";
|
|
40
|
+
var MGMT_PROFILES_TSG_PATH = "/v1/mgmt/profiles/tsg";
|
|
41
|
+
var MGMT_TOPIC_PATH = "/v1/mgmt/topic";
|
|
42
|
+
var MGMT_TOPICS_TSG_PATH = "/v1/mgmt/topics/tsg";
|
|
43
|
+
var MGMT_TOPIC_FORCE_PATH = "/v1/mgmt/topic/force";
|
|
32
44
|
|
|
33
45
|
// src/errors.ts
|
|
34
46
|
var ErrorType = /* @__PURE__ */ ((ErrorType2) => {
|
|
@@ -37,10 +49,15 @@ var ErrorType = /* @__PURE__ */ ((ErrorType2) => {
|
|
|
37
49
|
ErrorType2["USER_REQUEST_PAYLOAD_ERROR"] = "AISEC_USER_REQUEST_PAYLOAD_ERROR";
|
|
38
50
|
ErrorType2["MISSING_VARIABLE"] = "AISEC_MISSING_VARIABLE";
|
|
39
51
|
ErrorType2["AISEC_SDK_ERROR"] = "AISEC_SDK_ERROR";
|
|
52
|
+
ErrorType2["OAUTH_ERROR"] = "AISEC_OAUTH_ERROR";
|
|
40
53
|
return ErrorType2;
|
|
41
54
|
})(ErrorType || {});
|
|
42
55
|
var AISecSDKException = class _AISecSDKException extends Error {
|
|
43
56
|
errorType;
|
|
57
|
+
/**
|
|
58
|
+
* @param message - Human-readable error description.
|
|
59
|
+
* @param errorType - Classification of the error.
|
|
60
|
+
*/
|
|
44
61
|
constructor(message, errorType) {
|
|
45
62
|
super(errorType ? `${errorType}:${message}` : message);
|
|
46
63
|
this.name = "AISecSDKException";
|
|
@@ -122,6 +139,68 @@ function init(opts = {}) {
|
|
|
122
139
|
globalConfiguration.init(opts);
|
|
123
140
|
}
|
|
124
141
|
|
|
142
|
+
// src/http-retry.ts
|
|
143
|
+
function sleep(ms) {
|
|
144
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
145
|
+
}
|
|
146
|
+
function backoffDelay(attempt) {
|
|
147
|
+
return Math.pow(2, attempt) * 1e3;
|
|
148
|
+
}
|
|
149
|
+
function isRetryableStatus(status) {
|
|
150
|
+
return HTTP_FORCE_RETRY_STATUS_CODES.includes(status);
|
|
151
|
+
}
|
|
152
|
+
function classifyErrorType(status) {
|
|
153
|
+
return status >= 500 ? "AISEC_SERVER_SIDE_ERROR" /* SERVER_SIDE_ERROR */ : "AISEC_CLIENT_SIDE_ERROR" /* CLIENT_SIDE_ERROR */;
|
|
154
|
+
}
|
|
155
|
+
function extractErrorMessage(body, status) {
|
|
156
|
+
try {
|
|
157
|
+
const parsed = JSON.parse(body);
|
|
158
|
+
return parsed.error_message ?? parsed.message ?? parsed.error?.message ?? `API error ${status}`;
|
|
159
|
+
} catch {
|
|
160
|
+
return body ? `API error ${status}: ${body}` : `API error ${status}`;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
async function executeWithRetry(opts) {
|
|
164
|
+
const { maxRetries, execute, onRetryableFailure } = opts;
|
|
165
|
+
let lastError;
|
|
166
|
+
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
167
|
+
let response;
|
|
168
|
+
try {
|
|
169
|
+
response = await execute(attempt);
|
|
170
|
+
} catch (err) {
|
|
171
|
+
if (err instanceof AISecSDKException) throw err;
|
|
172
|
+
lastError = err;
|
|
173
|
+
if (attempt < maxRetries) {
|
|
174
|
+
await sleep(backoffDelay(attempt));
|
|
175
|
+
continue;
|
|
176
|
+
}
|
|
177
|
+
throw new AISecSDKException(
|
|
178
|
+
lastError.message ?? "Network error",
|
|
179
|
+
"AISEC_CLIENT_SIDE_ERROR" /* CLIENT_SIDE_ERROR */
|
|
180
|
+
);
|
|
181
|
+
}
|
|
182
|
+
if (response.ok) return response;
|
|
183
|
+
if (onRetryableFailure) {
|
|
184
|
+
const handled = await onRetryableFailure(response, attempt);
|
|
185
|
+
if (handled) {
|
|
186
|
+
attempt--;
|
|
187
|
+
continue;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
if (isRetryableStatus(response.status) && attempt < maxRetries) {
|
|
191
|
+
await sleep(backoffDelay(attempt));
|
|
192
|
+
continue;
|
|
193
|
+
}
|
|
194
|
+
const errorText = await response.text();
|
|
195
|
+
const errorMessage = extractErrorMessage(errorText, response.status);
|
|
196
|
+
throw new AISecSDKException(errorMessage, classifyErrorType(response.status));
|
|
197
|
+
}
|
|
198
|
+
throw new AISecSDKException(
|
|
199
|
+
lastError?.message ?? "Max retries exceeded",
|
|
200
|
+
"AISEC_CLIENT_SIDE_ERROR" /* CLIENT_SIDE_ERROR */
|
|
201
|
+
);
|
|
202
|
+
}
|
|
203
|
+
|
|
125
204
|
// src/utils.ts
|
|
126
205
|
import { createHmac } from "crypto";
|
|
127
206
|
var UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
@@ -147,9 +226,6 @@ function buildHeaders() {
|
|
|
147
226
|
}
|
|
148
227
|
return headers;
|
|
149
228
|
}
|
|
150
|
-
function sleep(ms) {
|
|
151
|
-
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
152
|
-
}
|
|
153
229
|
async function httpRequest(opts) {
|
|
154
230
|
if (!globalConfiguration.initialized) {
|
|
155
231
|
throw new AISecSDKException(
|
|
@@ -172,48 +248,27 @@ async function httpRequest(opts) {
|
|
|
172
248
|
headers[PAYLOAD_HASH] = generatePayloadHash(bodyStr, globalConfiguration.apiKey);
|
|
173
249
|
}
|
|
174
250
|
}
|
|
175
|
-
const
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
const data = await response.json();
|
|
186
|
-
return { status: response.status, data };
|
|
187
|
-
}
|
|
188
|
-
if (HTTP_FORCE_RETRY_STATUS_CODES.includes(response.status) && attempt < maxRetries) {
|
|
189
|
-
await sleep(Math.pow(2, attempt) * 1e3);
|
|
190
|
-
continue;
|
|
191
|
-
}
|
|
192
|
-
let errorMessage;
|
|
193
|
-
try {
|
|
194
|
-
const errorBody = await response.json();
|
|
195
|
-
errorMessage = errorBody.message ?? errorBody.error?.message ?? `API error ${response.status}`;
|
|
196
|
-
} catch {
|
|
197
|
-
errorMessage = `API error ${response.status}`;
|
|
198
|
-
}
|
|
199
|
-
const errorType = response.status >= 500 ? "AISEC_SERVER_SIDE_ERROR" /* SERVER_SIDE_ERROR */ : "AISEC_CLIENT_SIDE_ERROR" /* CLIENT_SIDE_ERROR */;
|
|
200
|
-
throw new AISecSDKException(errorMessage, errorType);
|
|
201
|
-
} catch (err) {
|
|
202
|
-
if (err instanceof AISecSDKException) {
|
|
203
|
-
throw err;
|
|
204
|
-
}
|
|
205
|
-
lastError = err;
|
|
206
|
-
if (attempt < maxRetries) {
|
|
207
|
-
await sleep(Math.pow(2, attempt) * 1e3);
|
|
208
|
-
continue;
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
|
-
throw new AISecSDKException(lastError?.message ?? "Network error", "AISEC_CLIENT_SIDE_ERROR" /* CLIENT_SIDE_ERROR */);
|
|
251
|
+
const response = await executeWithRetry({
|
|
252
|
+
maxRetries: globalConfiguration.numRetries,
|
|
253
|
+
execute: () => fetch(url.toString(), {
|
|
254
|
+
method: opts.method,
|
|
255
|
+
headers,
|
|
256
|
+
body: bodyStr
|
|
257
|
+
})
|
|
258
|
+
});
|
|
259
|
+
const data = await response.json();
|
|
260
|
+
return { status: response.status, data };
|
|
213
261
|
}
|
|
214
262
|
|
|
215
263
|
// src/scan/scanner.ts
|
|
216
264
|
var Scanner = class {
|
|
265
|
+
/**
|
|
266
|
+
* Perform a synchronous content scan.
|
|
267
|
+
* @param aiProfile - AI security profile to scan against.
|
|
268
|
+
* @param content - Content to scan.
|
|
269
|
+
* @param opts - Optional transaction/session IDs and metadata.
|
|
270
|
+
* @returns Scan response with verdict, action, and detection details.
|
|
271
|
+
*/
|
|
217
272
|
async syncScan(aiProfile, content, opts = {}) {
|
|
218
273
|
if (opts.trId && opts.trId.length > MAX_TRANSACTION_ID_STR_LENGTH) {
|
|
219
274
|
throw new AISecSDKException(
|
|
@@ -241,6 +296,11 @@ var Scanner = class {
|
|
|
241
296
|
});
|
|
242
297
|
return res.data;
|
|
243
298
|
}
|
|
299
|
+
/**
|
|
300
|
+
* Submit content for asynchronous scanning.
|
|
301
|
+
* @param scanObjects - Array of scan objects (1–5 items).
|
|
302
|
+
* @returns Response containing scan IDs for later querying.
|
|
303
|
+
*/
|
|
244
304
|
async asyncScan(scanObjects) {
|
|
245
305
|
if (scanObjects.length < 1) {
|
|
246
306
|
throw new AISecSDKException(
|
|
@@ -261,6 +321,11 @@ var Scanner = class {
|
|
|
261
321
|
});
|
|
262
322
|
return res.data;
|
|
263
323
|
}
|
|
324
|
+
/**
|
|
325
|
+
* Query scan results by scan IDs.
|
|
326
|
+
* @param scanIds - Array of scan UUIDs (1–5 items).
|
|
327
|
+
* @returns Array of scan results with status and response data.
|
|
328
|
+
*/
|
|
264
329
|
async queryByScanIds(scanIds) {
|
|
265
330
|
if (scanIds.length < 1) {
|
|
266
331
|
throw new AISecSDKException(
|
|
@@ -286,6 +351,11 @@ var Scanner = class {
|
|
|
286
351
|
});
|
|
287
352
|
return res.data;
|
|
288
353
|
}
|
|
354
|
+
/**
|
|
355
|
+
* Query detailed threat reports by report IDs.
|
|
356
|
+
* @param reportIds - Array of report IDs (1–5 items).
|
|
357
|
+
* @returns Array of threat scan reports with detection details.
|
|
358
|
+
*/
|
|
289
359
|
async queryByReportIds(reportIds) {
|
|
290
360
|
if (reportIds.length < 1) {
|
|
291
361
|
throw new AISecSDKException(
|
|
@@ -397,6 +467,7 @@ var Content = class _Content {
|
|
|
397
467
|
set toolEvent(value) {
|
|
398
468
|
this._toolEvent = value;
|
|
399
469
|
}
|
|
470
|
+
/** Total byte length of all text content fields. */
|
|
400
471
|
get length() {
|
|
401
472
|
let total = 0;
|
|
402
473
|
if (this._prompt) total += Buffer.byteLength(this._prompt);
|
|
@@ -406,6 +477,7 @@ var Content = class _Content {
|
|
|
406
477
|
if (this._codeResponse) total += Buffer.byteLength(this._codeResponse);
|
|
407
478
|
return total;
|
|
408
479
|
}
|
|
480
|
+
/** Serialize to the API request format. */
|
|
409
481
|
toJSON() {
|
|
410
482
|
const obj = {};
|
|
411
483
|
if (this._prompt !== void 0) obj.prompt = this._prompt;
|
|
@@ -416,6 +488,10 @@ var Content = class _Content {
|
|
|
416
488
|
if (this._toolEvent !== void 0) obj.tool_event = this._toolEvent;
|
|
417
489
|
return obj;
|
|
418
490
|
}
|
|
491
|
+
/**
|
|
492
|
+
* Create a Content instance from an API response object.
|
|
493
|
+
* @param json - Scan request contents inner object.
|
|
494
|
+
*/
|
|
419
495
|
static fromJSON(json) {
|
|
420
496
|
return new _Content({
|
|
421
497
|
prompt: json.prompt,
|
|
@@ -426,6 +502,10 @@ var Content = class _Content {
|
|
|
426
502
|
toolEvent: json.tool_event
|
|
427
503
|
});
|
|
428
504
|
}
|
|
505
|
+
/**
|
|
506
|
+
* Load content from a JSON file.
|
|
507
|
+
* @param filePath - Path to JSON file containing scan request contents.
|
|
508
|
+
*/
|
|
429
509
|
static fromJSONFile(filePath) {
|
|
430
510
|
const raw = readFileSync(filePath, "utf-8");
|
|
431
511
|
const parsed = JSON.parse(raw);
|
|
@@ -433,6 +513,23 @@ var Content = class _Content {
|
|
|
433
513
|
}
|
|
434
514
|
};
|
|
435
515
|
|
|
516
|
+
// src/models/enums.ts
|
|
517
|
+
var Verdict = {
|
|
518
|
+
BENIGN: "benign",
|
|
519
|
+
MALICIOUS: "malicious",
|
|
520
|
+
UNKNOWN: "unknown"
|
|
521
|
+
};
|
|
522
|
+
var Action = {
|
|
523
|
+
ALLOW: "allow",
|
|
524
|
+
BLOCK: "block",
|
|
525
|
+
ALERT: "alert"
|
|
526
|
+
};
|
|
527
|
+
var Category = {
|
|
528
|
+
BENIGN: "benign",
|
|
529
|
+
MALICIOUS: "malicious",
|
|
530
|
+
UNKNOWN: "unknown"
|
|
531
|
+
};
|
|
532
|
+
|
|
436
533
|
// src/models/ai-profile.ts
|
|
437
534
|
import { z } from "zod";
|
|
438
535
|
var AiProfileSchema = z.object({
|
|
@@ -657,21 +754,540 @@ var ErrorResponseSchema = z14.object({
|
|
|
657
754
|
unit: z14.string().optional()
|
|
658
755
|
}).optional()
|
|
659
756
|
});
|
|
757
|
+
|
|
758
|
+
// src/models/mgmt-security-profile.ts
|
|
759
|
+
import { z as z15 } from "zod";
|
|
760
|
+
var DlpDataProfileSchema = z15.object({
|
|
761
|
+
profile_name: z15.string(),
|
|
762
|
+
active: z15.boolean().optional()
|
|
763
|
+
}).passthrough();
|
|
764
|
+
var DlpSchema = z15.object({
|
|
765
|
+
dlp_status: z15.string().optional(),
|
|
766
|
+
data_profiles: z15.array(DlpDataProfileSchema).optional()
|
|
767
|
+
}).passthrough();
|
|
768
|
+
var DataLeakDetectionSchema = z15.object({
|
|
769
|
+
"data-leak-detection-status": z15.string().optional(),
|
|
770
|
+
dlp: DlpSchema.optional()
|
|
771
|
+
}).passthrough();
|
|
772
|
+
var AppProtectionSchema = z15.object({
|
|
773
|
+
"prompt-injection": z15.string().optional(),
|
|
774
|
+
"jailbreak-detection": z15.string().optional()
|
|
775
|
+
}).passthrough();
|
|
776
|
+
var ModelProtectionSchema = z15.object({
|
|
777
|
+
"model-denial-of-service": z15.string().optional()
|
|
778
|
+
}).passthrough();
|
|
779
|
+
var AgentProtectionSchema = z15.object({
|
|
780
|
+
"malicious-agent-activity": z15.string().optional()
|
|
781
|
+
}).passthrough();
|
|
782
|
+
var LatencySchema = z15.object({
|
|
783
|
+
status: z15.string().optional(),
|
|
784
|
+
max_latency_ms: z15.number().optional()
|
|
785
|
+
}).passthrough();
|
|
786
|
+
var ModelConfigurationSchema = z15.object({
|
|
787
|
+
latency: LatencySchema.optional()
|
|
788
|
+
}).passthrough();
|
|
789
|
+
var PolicySchema = z15.object({
|
|
790
|
+
"data-leak-detection": DataLeakDetectionSchema.optional(),
|
|
791
|
+
"app-protection": AppProtectionSchema.optional(),
|
|
792
|
+
"model-protection": ModelProtectionSchema.optional(),
|
|
793
|
+
"agent-protection": AgentProtectionSchema.optional(),
|
|
794
|
+
"model-configuration": ModelConfigurationSchema.optional()
|
|
795
|
+
}).passthrough();
|
|
796
|
+
var SecurityProfileSchema = z15.object({
|
|
797
|
+
profile_id: z15.string().optional(),
|
|
798
|
+
profile_name: z15.string(),
|
|
799
|
+
revision: z15.number().optional(),
|
|
800
|
+
active: z15.boolean().optional(),
|
|
801
|
+
policy: PolicySchema.optional(),
|
|
802
|
+
created_by: z15.string().optional(),
|
|
803
|
+
updated_by: z15.string().optional(),
|
|
804
|
+
last_modified_ts: z15.string().optional()
|
|
805
|
+
}).passthrough();
|
|
806
|
+
var CreateSecurityProfileRequestSchema = z15.object({
|
|
807
|
+
profile_id: z15.string().optional(),
|
|
808
|
+
profile_name: z15.string(),
|
|
809
|
+
revision: z15.number().optional(),
|
|
810
|
+
active: z15.boolean().optional(),
|
|
811
|
+
policy: PolicySchema.optional(),
|
|
812
|
+
created_by: z15.string().optional(),
|
|
813
|
+
updated_by: z15.string().optional(),
|
|
814
|
+
last_modified_ts: z15.string().optional()
|
|
815
|
+
}).passthrough();
|
|
816
|
+
var SecurityProfileListResponseSchema = z15.object({
|
|
817
|
+
ai_profiles: z15.array(SecurityProfileSchema),
|
|
818
|
+
next_offset: z15.number().optional()
|
|
819
|
+
}).passthrough();
|
|
820
|
+
var DeleteProfileResponseSchema = z15.object({
|
|
821
|
+
message: z15.string()
|
|
822
|
+
}).passthrough();
|
|
823
|
+
var DeleteProfileConflictSchema = z15.object({
|
|
824
|
+
message: z15.string(),
|
|
825
|
+
payload: z15.array(
|
|
826
|
+
z15.object({
|
|
827
|
+
policy_id: z15.string(),
|
|
828
|
+
policy_name: z15.string(),
|
|
829
|
+
priority: z15.number()
|
|
830
|
+
}).passthrough()
|
|
831
|
+
)
|
|
832
|
+
}).passthrough();
|
|
833
|
+
|
|
834
|
+
// src/models/mgmt-custom-topic.ts
|
|
835
|
+
import { z as z16 } from "zod";
|
|
836
|
+
var CustomTopicSchema = z16.object({
|
|
837
|
+
topic_id: z16.string().optional(),
|
|
838
|
+
topic_name: z16.string(),
|
|
839
|
+
revision: z16.number().optional(),
|
|
840
|
+
active: z16.boolean().optional(),
|
|
841
|
+
description: z16.string().optional(),
|
|
842
|
+
examples: z16.array(z16.string()).optional(),
|
|
843
|
+
created_by: z16.string().optional(),
|
|
844
|
+
updated_by: z16.string().optional(),
|
|
845
|
+
last_modified_ts: z16.string().optional(),
|
|
846
|
+
created_ts: z16.string().optional()
|
|
847
|
+
}).passthrough();
|
|
848
|
+
var CreateCustomTopicRequestSchema = z16.object({
|
|
849
|
+
topic_id: z16.string().optional(),
|
|
850
|
+
topic_name: z16.string(),
|
|
851
|
+
revision: z16.number().optional(),
|
|
852
|
+
active: z16.boolean().optional(),
|
|
853
|
+
description: z16.string().optional(),
|
|
854
|
+
examples: z16.array(z16.string()).optional(),
|
|
855
|
+
created_by: z16.string().optional(),
|
|
856
|
+
updated_by: z16.string().optional(),
|
|
857
|
+
last_modified_ts: z16.string().optional(),
|
|
858
|
+
created_ts: z16.string().optional()
|
|
859
|
+
}).passthrough();
|
|
860
|
+
var CustomTopicListResponseSchema = z16.object({
|
|
861
|
+
custom_topics: z16.array(CustomTopicSchema),
|
|
862
|
+
next_offset: z16.number().optional()
|
|
863
|
+
}).passthrough();
|
|
864
|
+
var DeleteTopicResponseSchema = z16.object({
|
|
865
|
+
message: z16.string()
|
|
866
|
+
}).passthrough();
|
|
867
|
+
var DeleteTopicConflictSchema = z16.object({
|
|
868
|
+
message: z16.string(),
|
|
869
|
+
payload: z16.array(
|
|
870
|
+
z16.object({
|
|
871
|
+
profile_id: z16.string(),
|
|
872
|
+
profile_name: z16.string(),
|
|
873
|
+
revision: z16.number()
|
|
874
|
+
}).passthrough()
|
|
875
|
+
)
|
|
876
|
+
}).passthrough();
|
|
877
|
+
|
|
878
|
+
// src/models/oauth-token.ts
|
|
879
|
+
import { z as z17 } from "zod";
|
|
880
|
+
var OAuthTokenResponseSchema = z17.object({
|
|
881
|
+
access_token: z17.string(),
|
|
882
|
+
token_type: z17.string().optional(),
|
|
883
|
+
expires_in: z17.number(),
|
|
884
|
+
scope: z17.string().optional()
|
|
885
|
+
});
|
|
886
|
+
|
|
887
|
+
// src/management/oauth-client.ts
|
|
888
|
+
var TOKEN_BUFFER_MS = 3e4;
|
|
889
|
+
var OAuthClient = class {
|
|
890
|
+
tokenEndpoint;
|
|
891
|
+
clientId;
|
|
892
|
+
clientSecret;
|
|
893
|
+
tsgId;
|
|
894
|
+
accessToken = null;
|
|
895
|
+
expiresAt = 0;
|
|
896
|
+
pendingFetch = null;
|
|
897
|
+
constructor(opts) {
|
|
898
|
+
this.clientId = opts.clientId;
|
|
899
|
+
this.clientSecret = opts.clientSecret;
|
|
900
|
+
this.tsgId = opts.tsgId;
|
|
901
|
+
this.tokenEndpoint = opts.tokenEndpoint ?? DEFAULT_TOKEN_ENDPOINT;
|
|
902
|
+
}
|
|
903
|
+
/**
|
|
904
|
+
* Get a valid access token, refreshing if needed.
|
|
905
|
+
* @returns Bearer access token string.
|
|
906
|
+
*/
|
|
907
|
+
async getToken() {
|
|
908
|
+
if (this.accessToken && Date.now() < this.expiresAt - TOKEN_BUFFER_MS) {
|
|
909
|
+
return this.accessToken;
|
|
910
|
+
}
|
|
911
|
+
if (this.pendingFetch) {
|
|
912
|
+
return this.pendingFetch;
|
|
913
|
+
}
|
|
914
|
+
this.pendingFetch = this.fetchToken().finally(() => {
|
|
915
|
+
this.pendingFetch = null;
|
|
916
|
+
});
|
|
917
|
+
return this.pendingFetch;
|
|
918
|
+
}
|
|
919
|
+
/** Clear the cached token, forcing a fresh fetch on next call. */
|
|
920
|
+
clearToken() {
|
|
921
|
+
this.accessToken = null;
|
|
922
|
+
this.expiresAt = 0;
|
|
923
|
+
}
|
|
924
|
+
async fetchToken() {
|
|
925
|
+
const credentials = btoa(`${this.clientId}:${this.clientSecret}`);
|
|
926
|
+
const body = new URLSearchParams({
|
|
927
|
+
grant_type: "client_credentials",
|
|
928
|
+
scope: `tsg_id:${this.tsgId}`
|
|
929
|
+
});
|
|
930
|
+
let response;
|
|
931
|
+
try {
|
|
932
|
+
response = await fetch(this.tokenEndpoint, {
|
|
933
|
+
method: "POST",
|
|
934
|
+
headers: {
|
|
935
|
+
"Content-Type": "application/x-www-form-urlencoded",
|
|
936
|
+
Authorization: `Basic ${credentials}`
|
|
937
|
+
},
|
|
938
|
+
body: body.toString()
|
|
939
|
+
});
|
|
940
|
+
} catch (err) {
|
|
941
|
+
throw new AISecSDKException(
|
|
942
|
+
`Token request failed: ${err.message}`,
|
|
943
|
+
"AISEC_OAUTH_ERROR" /* OAUTH_ERROR */
|
|
944
|
+
);
|
|
945
|
+
}
|
|
946
|
+
if (!response.ok) {
|
|
947
|
+
let errorMsg;
|
|
948
|
+
try {
|
|
949
|
+
const errorBody = await response.json();
|
|
950
|
+
errorMsg = errorBody.error_description ?? errorBody.error ?? `Token request failed with status ${response.status}`;
|
|
951
|
+
} catch {
|
|
952
|
+
errorMsg = `Token request failed with status ${response.status}`;
|
|
953
|
+
}
|
|
954
|
+
throw new AISecSDKException(errorMsg, "AISEC_OAUTH_ERROR" /* OAUTH_ERROR */);
|
|
955
|
+
}
|
|
956
|
+
const data = OAuthTokenResponseSchema.parse(await response.json());
|
|
957
|
+
this.accessToken = data.access_token;
|
|
958
|
+
this.expiresAt = Date.now() + data.expires_in * 1e3;
|
|
959
|
+
return this.accessToken;
|
|
960
|
+
}
|
|
961
|
+
};
|
|
962
|
+
|
|
963
|
+
// src/management/management-http-client.ts
|
|
964
|
+
async function managementHttpRequest(opts) {
|
|
965
|
+
const { method, baseUrl, path, body, params, oauthClient, numRetries } = opts;
|
|
966
|
+
let hadTokenRefresh = false;
|
|
967
|
+
const response = await executeWithRetry({
|
|
968
|
+
maxRetries: numRetries,
|
|
969
|
+
execute: async () => {
|
|
970
|
+
const token = await oauthClient.getToken();
|
|
971
|
+
const stripped = baseUrl.replace(/\/+$/, "");
|
|
972
|
+
const url = new URL(`${stripped}${path}`);
|
|
973
|
+
if (params) {
|
|
974
|
+
for (const [key, value] of Object.entries(params)) {
|
|
975
|
+
url.searchParams.set(key, value);
|
|
976
|
+
}
|
|
977
|
+
}
|
|
978
|
+
const headers = {
|
|
979
|
+
Authorization: `Bearer ${token}`,
|
|
980
|
+
"User-Agent": USER_AGENT
|
|
981
|
+
};
|
|
982
|
+
let bodyStr;
|
|
983
|
+
if (body !== void 0) {
|
|
984
|
+
headers["Content-Type"] = "application/json";
|
|
985
|
+
bodyStr = JSON.stringify(body);
|
|
986
|
+
}
|
|
987
|
+
return fetch(url.toString(), { method, headers, body: bodyStr });
|
|
988
|
+
},
|
|
989
|
+
onRetryableFailure: async (response2) => {
|
|
990
|
+
if (response2.status === 401 && !hadTokenRefresh) {
|
|
991
|
+
hadTokenRefresh = true;
|
|
992
|
+
oauthClient.clearToken();
|
|
993
|
+
return true;
|
|
994
|
+
}
|
|
995
|
+
return false;
|
|
996
|
+
}
|
|
997
|
+
});
|
|
998
|
+
const text = await response.text();
|
|
999
|
+
const data = text ? JSON.parse(text) : {};
|
|
1000
|
+
return { status: response.status, data };
|
|
1001
|
+
}
|
|
1002
|
+
|
|
1003
|
+
// src/management/profiles.ts
|
|
1004
|
+
var ProfilesClient = class {
|
|
1005
|
+
baseUrl;
|
|
1006
|
+
oauthClient;
|
|
1007
|
+
tsgId;
|
|
1008
|
+
numRetries;
|
|
1009
|
+
constructor(opts) {
|
|
1010
|
+
this.baseUrl = opts.baseUrl;
|
|
1011
|
+
this.oauthClient = opts.oauthClient;
|
|
1012
|
+
this.tsgId = opts.tsgId;
|
|
1013
|
+
this.numRetries = opts.numRetries;
|
|
1014
|
+
}
|
|
1015
|
+
/**
|
|
1016
|
+
* Create a new security profile.
|
|
1017
|
+
* @param request - Profile configuration.
|
|
1018
|
+
* @returns The created security profile.
|
|
1019
|
+
*/
|
|
1020
|
+
async create(request) {
|
|
1021
|
+
const res = await managementHttpRequest({
|
|
1022
|
+
method: "POST",
|
|
1023
|
+
baseUrl: this.baseUrl,
|
|
1024
|
+
path: MGMT_PROFILE_PATH,
|
|
1025
|
+
body: request,
|
|
1026
|
+
oauthClient: this.oauthClient,
|
|
1027
|
+
numRetries: this.numRetries
|
|
1028
|
+
});
|
|
1029
|
+
return res.data;
|
|
1030
|
+
}
|
|
1031
|
+
/**
|
|
1032
|
+
* List security profiles for the TSG.
|
|
1033
|
+
* @param opts - Pagination options.
|
|
1034
|
+
* @returns Paginated list of security profiles.
|
|
1035
|
+
*/
|
|
1036
|
+
async list(opts) {
|
|
1037
|
+
const params = {
|
|
1038
|
+
offset: String(opts?.offset ?? 0),
|
|
1039
|
+
limit: String(opts?.limit ?? 100)
|
|
1040
|
+
};
|
|
1041
|
+
const res = await managementHttpRequest({
|
|
1042
|
+
method: "GET",
|
|
1043
|
+
baseUrl: this.baseUrl,
|
|
1044
|
+
path: `${MGMT_PROFILES_TSG_PATH}/${this.tsgId}`,
|
|
1045
|
+
params,
|
|
1046
|
+
oauthClient: this.oauthClient,
|
|
1047
|
+
numRetries: this.numRetries
|
|
1048
|
+
});
|
|
1049
|
+
return res.data;
|
|
1050
|
+
}
|
|
1051
|
+
/**
|
|
1052
|
+
* Update an existing security profile.
|
|
1053
|
+
* @param profileId - UUID of the profile to update.
|
|
1054
|
+
* @param request - Updated profile configuration.
|
|
1055
|
+
* @returns The updated security profile.
|
|
1056
|
+
*/
|
|
1057
|
+
async update(profileId, request) {
|
|
1058
|
+
if (!isValidUuid(profileId)) {
|
|
1059
|
+
throw new AISecSDKException(
|
|
1060
|
+
`Invalid profile_id: ${profileId}`,
|
|
1061
|
+
"AISEC_USER_REQUEST_PAYLOAD_ERROR" /* USER_REQUEST_PAYLOAD_ERROR */
|
|
1062
|
+
);
|
|
1063
|
+
}
|
|
1064
|
+
const res = await managementHttpRequest({
|
|
1065
|
+
method: "PUT",
|
|
1066
|
+
baseUrl: this.baseUrl,
|
|
1067
|
+
path: `${MGMT_PROFILE_PATH}/uuid/${profileId}`,
|
|
1068
|
+
body: request,
|
|
1069
|
+
oauthClient: this.oauthClient,
|
|
1070
|
+
numRetries: this.numRetries
|
|
1071
|
+
});
|
|
1072
|
+
return res.data;
|
|
1073
|
+
}
|
|
1074
|
+
/**
|
|
1075
|
+
* Delete a security profile.
|
|
1076
|
+
* @param profileId - UUID of the profile to delete.
|
|
1077
|
+
* @returns Deletion confirmation message.
|
|
1078
|
+
*/
|
|
1079
|
+
async delete(profileId) {
|
|
1080
|
+
if (!isValidUuid(profileId)) {
|
|
1081
|
+
throw new AISecSDKException(
|
|
1082
|
+
`Invalid profile_id: ${profileId}`,
|
|
1083
|
+
"AISEC_USER_REQUEST_PAYLOAD_ERROR" /* USER_REQUEST_PAYLOAD_ERROR */
|
|
1084
|
+
);
|
|
1085
|
+
}
|
|
1086
|
+
const res = await managementHttpRequest({
|
|
1087
|
+
method: "DELETE",
|
|
1088
|
+
baseUrl: this.baseUrl,
|
|
1089
|
+
path: `${MGMT_PROFILE_PATH}/${profileId}`,
|
|
1090
|
+
oauthClient: this.oauthClient,
|
|
1091
|
+
numRetries: this.numRetries
|
|
1092
|
+
});
|
|
1093
|
+
return res.data;
|
|
1094
|
+
}
|
|
1095
|
+
};
|
|
1096
|
+
|
|
1097
|
+
// src/management/topics.ts
|
|
1098
|
+
var TopicsClient = class {
|
|
1099
|
+
baseUrl;
|
|
1100
|
+
oauthClient;
|
|
1101
|
+
tsgId;
|
|
1102
|
+
numRetries;
|
|
1103
|
+
constructor(opts) {
|
|
1104
|
+
this.baseUrl = opts.baseUrl;
|
|
1105
|
+
this.oauthClient = opts.oauthClient;
|
|
1106
|
+
this.tsgId = opts.tsgId;
|
|
1107
|
+
this.numRetries = opts.numRetries;
|
|
1108
|
+
}
|
|
1109
|
+
/**
|
|
1110
|
+
* Create a new custom topic.
|
|
1111
|
+
* @param request - Topic definition with name, description, and examples.
|
|
1112
|
+
* @returns The created custom topic.
|
|
1113
|
+
*/
|
|
1114
|
+
async create(request) {
|
|
1115
|
+
const res = await managementHttpRequest({
|
|
1116
|
+
method: "POST",
|
|
1117
|
+
baseUrl: this.baseUrl,
|
|
1118
|
+
path: MGMT_TOPIC_PATH,
|
|
1119
|
+
body: request,
|
|
1120
|
+
oauthClient: this.oauthClient,
|
|
1121
|
+
numRetries: this.numRetries
|
|
1122
|
+
});
|
|
1123
|
+
return res.data;
|
|
1124
|
+
}
|
|
1125
|
+
/**
|
|
1126
|
+
* List custom topics for the TSG.
|
|
1127
|
+
* @param opts - Pagination options.
|
|
1128
|
+
* @returns Paginated list of custom topics.
|
|
1129
|
+
*/
|
|
1130
|
+
async list(opts) {
|
|
1131
|
+
const params = {
|
|
1132
|
+
offset: String(opts?.offset ?? 0),
|
|
1133
|
+
limit: String(opts?.limit ?? 100)
|
|
1134
|
+
};
|
|
1135
|
+
const res = await managementHttpRequest({
|
|
1136
|
+
method: "GET",
|
|
1137
|
+
baseUrl: this.baseUrl,
|
|
1138
|
+
path: `${MGMT_TOPICS_TSG_PATH}/${this.tsgId}`,
|
|
1139
|
+
params,
|
|
1140
|
+
oauthClient: this.oauthClient,
|
|
1141
|
+
numRetries: this.numRetries
|
|
1142
|
+
});
|
|
1143
|
+
return res.data;
|
|
1144
|
+
}
|
|
1145
|
+
/**
|
|
1146
|
+
* Update an existing custom topic.
|
|
1147
|
+
* @param topicId - UUID of the topic to update.
|
|
1148
|
+
* @param request - Updated topic definition.
|
|
1149
|
+
* @returns The updated custom topic.
|
|
1150
|
+
*/
|
|
1151
|
+
async update(topicId, request) {
|
|
1152
|
+
if (!isValidUuid(topicId)) {
|
|
1153
|
+
throw new AISecSDKException(
|
|
1154
|
+
`Invalid topic_id: ${topicId}`,
|
|
1155
|
+
"AISEC_USER_REQUEST_PAYLOAD_ERROR" /* USER_REQUEST_PAYLOAD_ERROR */
|
|
1156
|
+
);
|
|
1157
|
+
}
|
|
1158
|
+
const res = await managementHttpRequest({
|
|
1159
|
+
method: "PUT",
|
|
1160
|
+
baseUrl: this.baseUrl,
|
|
1161
|
+
path: `${MGMT_TOPIC_PATH}/uuid/${topicId}`,
|
|
1162
|
+
body: request,
|
|
1163
|
+
oauthClient: this.oauthClient,
|
|
1164
|
+
numRetries: this.numRetries
|
|
1165
|
+
});
|
|
1166
|
+
return res.data;
|
|
1167
|
+
}
|
|
1168
|
+
/**
|
|
1169
|
+
* Delete a custom topic. Fails if topic is referenced by a profile.
|
|
1170
|
+
* @param topicId - UUID of the topic to delete.
|
|
1171
|
+
* @returns Deletion confirmation message.
|
|
1172
|
+
*/
|
|
1173
|
+
async delete(topicId) {
|
|
1174
|
+
if (!isValidUuid(topicId)) {
|
|
1175
|
+
throw new AISecSDKException(
|
|
1176
|
+
`Invalid topic_id: ${topicId}`,
|
|
1177
|
+
"AISEC_USER_REQUEST_PAYLOAD_ERROR" /* USER_REQUEST_PAYLOAD_ERROR */
|
|
1178
|
+
);
|
|
1179
|
+
}
|
|
1180
|
+
const res = await managementHttpRequest({
|
|
1181
|
+
method: "DELETE",
|
|
1182
|
+
baseUrl: this.baseUrl,
|
|
1183
|
+
path: `${MGMT_TOPIC_PATH}/${topicId}`,
|
|
1184
|
+
oauthClient: this.oauthClient,
|
|
1185
|
+
numRetries: this.numRetries
|
|
1186
|
+
});
|
|
1187
|
+
return res.data;
|
|
1188
|
+
}
|
|
1189
|
+
/**
|
|
1190
|
+
* Force-delete a custom topic, removing it from any referencing profiles.
|
|
1191
|
+
* @param topicId - UUID of the topic to force-delete.
|
|
1192
|
+
* @returns Deletion confirmation message.
|
|
1193
|
+
*/
|
|
1194
|
+
async forceDelete(topicId) {
|
|
1195
|
+
if (!isValidUuid(topicId)) {
|
|
1196
|
+
throw new AISecSDKException(
|
|
1197
|
+
`Invalid topic_id: ${topicId}`,
|
|
1198
|
+
"AISEC_USER_REQUEST_PAYLOAD_ERROR" /* USER_REQUEST_PAYLOAD_ERROR */
|
|
1199
|
+
);
|
|
1200
|
+
}
|
|
1201
|
+
const res = await managementHttpRequest({
|
|
1202
|
+
method: "DELETE",
|
|
1203
|
+
baseUrl: this.baseUrl,
|
|
1204
|
+
path: `${MGMT_TOPIC_FORCE_PATH}/${topicId}`,
|
|
1205
|
+
oauthClient: this.oauthClient,
|
|
1206
|
+
numRetries: this.numRetries
|
|
1207
|
+
});
|
|
1208
|
+
return res.data;
|
|
1209
|
+
}
|
|
1210
|
+
};
|
|
1211
|
+
|
|
1212
|
+
// src/management/client.ts
|
|
1213
|
+
var ManagementClient = class {
|
|
1214
|
+
profiles;
|
|
1215
|
+
topics;
|
|
1216
|
+
constructor(opts = {}) {
|
|
1217
|
+
const clientId = opts.clientId ?? process.env[MGMT_CLIENT_ID];
|
|
1218
|
+
const clientSecret = opts.clientSecret ?? process.env[MGMT_CLIENT_SECRET];
|
|
1219
|
+
const tsgId = opts.tsgId ?? process.env[MGMT_TSG_ID];
|
|
1220
|
+
const apiEndpoint = opts.apiEndpoint ?? process.env[MGMT_ENDPOINT] ?? DEFAULT_MGMT_ENDPOINT;
|
|
1221
|
+
const tokenEndpoint = opts.tokenEndpoint ?? process.env[MGMT_TOKEN_ENDPOINT];
|
|
1222
|
+
const numRetries = Math.min(
|
|
1223
|
+
Math.max(opts.numRetries ?? MAX_NUMBER_OF_RETRIES, 0),
|
|
1224
|
+
MAX_NUMBER_OF_RETRIES
|
|
1225
|
+
);
|
|
1226
|
+
if (!clientId) {
|
|
1227
|
+
throw new AISecSDKException(
|
|
1228
|
+
"clientId is required (option or PANW_MGMT_CLIENT_ID env var)",
|
|
1229
|
+
"AISEC_MISSING_VARIABLE" /* MISSING_VARIABLE */
|
|
1230
|
+
);
|
|
1231
|
+
}
|
|
1232
|
+
if (!clientSecret) {
|
|
1233
|
+
throw new AISecSDKException(
|
|
1234
|
+
"clientSecret is required (option or PANW_MGMT_CLIENT_SECRET env var)",
|
|
1235
|
+
"AISEC_MISSING_VARIABLE" /* MISSING_VARIABLE */
|
|
1236
|
+
);
|
|
1237
|
+
}
|
|
1238
|
+
if (!tsgId) {
|
|
1239
|
+
throw new AISecSDKException(
|
|
1240
|
+
"tsgId is required (option or PANW_MGMT_TSG_ID env var)",
|
|
1241
|
+
"AISEC_MISSING_VARIABLE" /* MISSING_VARIABLE */
|
|
1242
|
+
);
|
|
1243
|
+
}
|
|
1244
|
+
const oauthClient = new OAuthClient({
|
|
1245
|
+
clientId,
|
|
1246
|
+
clientSecret,
|
|
1247
|
+
tsgId,
|
|
1248
|
+
tokenEndpoint
|
|
1249
|
+
});
|
|
1250
|
+
this.profiles = new ProfilesClient({
|
|
1251
|
+
baseUrl: apiEndpoint,
|
|
1252
|
+
oauthClient,
|
|
1253
|
+
tsgId,
|
|
1254
|
+
numRetries
|
|
1255
|
+
});
|
|
1256
|
+
this.topics = new TopicsClient({
|
|
1257
|
+
baseUrl: apiEndpoint,
|
|
1258
|
+
oauthClient,
|
|
1259
|
+
tsgId,
|
|
1260
|
+
numRetries
|
|
1261
|
+
});
|
|
1262
|
+
}
|
|
1263
|
+
};
|
|
660
1264
|
export {
|
|
661
1265
|
AISecSDKException,
|
|
662
1266
|
AI_SEC_API_ENDPOINT,
|
|
663
1267
|
AI_SEC_API_KEY,
|
|
664
1268
|
AI_SEC_API_TOKEN,
|
|
665
1269
|
ASYNC_SCAN_PATH,
|
|
1270
|
+
Action,
|
|
666
1271
|
AgentMetaSchema,
|
|
667
1272
|
AiProfileSchema,
|
|
668
1273
|
AsyncScanObjectSchema,
|
|
669
1274
|
AsyncScanResponseSchema,
|
|
670
1275
|
BEARER,
|
|
1276
|
+
Category,
|
|
671
1277
|
Content,
|
|
1278
|
+
CreateCustomTopicRequestSchema,
|
|
1279
|
+
CreateSecurityProfileRequestSchema,
|
|
1280
|
+
CustomTopicListResponseSchema,
|
|
1281
|
+
CustomTopicSchema,
|
|
672
1282
|
DEFAULT_ENDPOINT,
|
|
1283
|
+
DEFAULT_MGMT_ENDPOINT,
|
|
1284
|
+
DEFAULT_TOKEN_ENDPOINT,
|
|
673
1285
|
DSDetailResultSchema,
|
|
674
1286
|
DSResultMetadataSchema,
|
|
1287
|
+
DeleteProfileConflictSchema,
|
|
1288
|
+
DeleteProfileResponseSchema,
|
|
1289
|
+
DeleteTopicConflictSchema,
|
|
1290
|
+
DeleteTopicResponseSchema,
|
|
675
1291
|
DetectionServiceResultSchema,
|
|
676
1292
|
DlpReportSchema,
|
|
677
1293
|
ErrorResponseSchema,
|
|
@@ -695,9 +1311,22 @@ export {
|
|
|
695
1311
|
MAX_SESSION_ID_STR_LENGTH,
|
|
696
1312
|
MAX_TOKEN_LENGTH,
|
|
697
1313
|
MAX_TRANSACTION_ID_STR_LENGTH,
|
|
1314
|
+
MGMT_CLIENT_ID,
|
|
1315
|
+
MGMT_CLIENT_SECRET,
|
|
1316
|
+
MGMT_ENDPOINT,
|
|
1317
|
+
MGMT_PROFILES_TSG_PATH,
|
|
1318
|
+
MGMT_PROFILE_PATH,
|
|
1319
|
+
MGMT_TOKEN_ENDPOINT,
|
|
1320
|
+
MGMT_TOPICS_TSG_PATH,
|
|
1321
|
+
MGMT_TOPIC_FORCE_PATH,
|
|
1322
|
+
MGMT_TOPIC_PATH,
|
|
1323
|
+
MGMT_TSG_ID,
|
|
1324
|
+
ManagementClient,
|
|
698
1325
|
MaskedDataSchema,
|
|
699
1326
|
MetadataSchema,
|
|
700
1327
|
PAYLOAD_HASH,
|
|
1328
|
+
PolicySchema,
|
|
1329
|
+
ProfilesClient,
|
|
701
1330
|
PromptDetectedSchema,
|
|
702
1331
|
PromptDetectionDetailsSchema,
|
|
703
1332
|
ResponseDetectedSchema,
|
|
@@ -712,12 +1341,16 @@ export {
|
|
|
712
1341
|
ScanResponseSchema,
|
|
713
1342
|
ScanSummarySchema,
|
|
714
1343
|
Scanner,
|
|
1344
|
+
SecurityProfileListResponseSchema,
|
|
1345
|
+
SecurityProfileSchema,
|
|
715
1346
|
ThreatScanReportSchema,
|
|
716
1347
|
ToolDetectedSchema,
|
|
717
1348
|
ToolEventMetadataSchema,
|
|
718
1349
|
ToolEventSchema,
|
|
1350
|
+
TopicsClient,
|
|
719
1351
|
USER_AGENT,
|
|
720
1352
|
UrlfEntrySchema,
|
|
1353
|
+
Verdict,
|
|
721
1354
|
globalConfiguration,
|
|
722
1355
|
init
|
|
723
1356
|
};
|