@vettly/shared 0.1.9
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 +29 -0
- package/dist/index.cjs +362 -0
- package/dist/index.d.cts +795 -0
- package/dist/index.d.ts +795 -0
- package/dist/index.js +299 -0
- package/package.json +54 -0
package/README.md
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# @nextauralabs/vettly-shared
|
|
2
|
+
|
|
3
|
+
Shared TypeScript types for the Vettly SDK ecosystem.
|
|
4
|
+
|
|
5
|
+
## Vettly Packages
|
|
6
|
+
|
|
7
|
+
| Package | Description |
|
|
8
|
+
|---------|-------------|
|
|
9
|
+
| [@nextauralabs/vettly-sdk](https://npmjs.com/package/@nextauralabs/vettly-sdk) | Core TypeScript SDK |
|
|
10
|
+
| [@nextauralabs/vettly-react](https://npmjs.com/package/@nextauralabs/vettly-react) | React components |
|
|
11
|
+
| [@nextauralabs/vettly-express](https://npmjs.com/package/@nextauralabs/vettly-express) | Express middleware |
|
|
12
|
+
| [@nextauralabs/vettly-nextjs](https://npmjs.com/package/@nextauralabs/vettly-nextjs) | Next.js integration |
|
|
13
|
+
|
|
14
|
+
## Usage
|
|
15
|
+
|
|
16
|
+
```typescript
|
|
17
|
+
import type {
|
|
18
|
+
CheckRequest,
|
|
19
|
+
CheckResponse,
|
|
20
|
+
Policy,
|
|
21
|
+
Category,
|
|
22
|
+
Action
|
|
23
|
+
} from '@nextauralabs/vettly-shared'
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Links
|
|
27
|
+
|
|
28
|
+
- [vettly.dev](https://vettly.dev) - Sign up
|
|
29
|
+
- [docs.vettly.dev](https://docs.vettly.dev) - Documentation
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,362 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
|
|
30
|
+
// src/index.ts
|
|
31
|
+
var index_exports = {};
|
|
32
|
+
__export(index_exports, {
|
|
33
|
+
ActionSchema: () => ActionSchema,
|
|
34
|
+
CategorySchema: () => CategorySchema,
|
|
35
|
+
CheckRequestSchema: () => CheckRequestSchema,
|
|
36
|
+
CheckResponseSchema: () => CheckResponseSchema,
|
|
37
|
+
ContentItemResultSchema: () => ContentItemResultSchema,
|
|
38
|
+
ContentTypeSchema: () => ContentTypeSchema,
|
|
39
|
+
DecisionSchema: () => DecisionSchema,
|
|
40
|
+
FallbackConfigSchema: () => FallbackConfigSchema,
|
|
41
|
+
ModerationError: () => ModerationError,
|
|
42
|
+
MultiModalCheckRequestSchema: () => MultiModalCheckRequestSchema,
|
|
43
|
+
MultiModalCheckResponseSchema: () => MultiModalCheckResponseSchema,
|
|
44
|
+
OverrideSchema: () => OverrideSchema,
|
|
45
|
+
PolicySchema: () => PolicySchema,
|
|
46
|
+
PolicyValidationError: () => PolicyValidationError,
|
|
47
|
+
ProviderError: () => ProviderError,
|
|
48
|
+
ProviderNameSchema: () => ProviderNameSchema,
|
|
49
|
+
ReplayRequestSchema: () => ReplayRequestSchema,
|
|
50
|
+
RuleSchema: () => RuleSchema,
|
|
51
|
+
UseCaseTypeSchema: () => UseCaseTypeSchema,
|
|
52
|
+
WebhookEndpointSchema: () => WebhookEndpointSchema,
|
|
53
|
+
WebhookEventTypeSchema: () => WebhookEventTypeSchema,
|
|
54
|
+
calculatePolicyVersion: () => calculatePolicyVersion,
|
|
55
|
+
formatCost: () => formatCost,
|
|
56
|
+
formatLatency: () => formatLatency,
|
|
57
|
+
generateRequestId: () => generateRequestId,
|
|
58
|
+
generateUUID: () => generateUUID,
|
|
59
|
+
hashContent: () => hashContent
|
|
60
|
+
});
|
|
61
|
+
module.exports = __toCommonJS(index_exports);
|
|
62
|
+
|
|
63
|
+
// src/types.ts
|
|
64
|
+
var import_zod = require("zod");
|
|
65
|
+
var ContentTypeSchema = import_zod.z.enum(["text", "image", "video"]);
|
|
66
|
+
var UseCaseTypeSchema = import_zod.z.enum([
|
|
67
|
+
"social_post",
|
|
68
|
+
"comment",
|
|
69
|
+
"profile",
|
|
70
|
+
"message",
|
|
71
|
+
"review",
|
|
72
|
+
"listing",
|
|
73
|
+
"bio",
|
|
74
|
+
"other"
|
|
75
|
+
]);
|
|
76
|
+
var CategorySchema = import_zod.z.enum([
|
|
77
|
+
"hate_speech",
|
|
78
|
+
"harassment",
|
|
79
|
+
"violence",
|
|
80
|
+
"self_harm",
|
|
81
|
+
"sexual",
|
|
82
|
+
"spam",
|
|
83
|
+
"profanity",
|
|
84
|
+
"scam",
|
|
85
|
+
"illegal"
|
|
86
|
+
]);
|
|
87
|
+
var ProviderNameSchema = import_zod.z.enum([
|
|
88
|
+
"openai",
|
|
89
|
+
"perspective",
|
|
90
|
+
"hive",
|
|
91
|
+
"azure",
|
|
92
|
+
"bot_detection",
|
|
93
|
+
"gemini_vision",
|
|
94
|
+
"mock",
|
|
95
|
+
"fallback"
|
|
96
|
+
]);
|
|
97
|
+
var ActionSchema = import_zod.z.enum(["block", "warn", "flag", "allow"]);
|
|
98
|
+
var RuleSchema = import_zod.z.object({
|
|
99
|
+
category: CategorySchema,
|
|
100
|
+
threshold: import_zod.z.number().min(0).max(1),
|
|
101
|
+
provider: ProviderNameSchema,
|
|
102
|
+
action: ActionSchema,
|
|
103
|
+
priority: import_zod.z.number().optional().default(0),
|
|
104
|
+
// Custom prompt-based moderation (Pro+ tier only)
|
|
105
|
+
// When set, uses Gemini Vision for semantic image analysis
|
|
106
|
+
customPrompt: import_zod.z.string().min(1).max(500).optional(),
|
|
107
|
+
customCategory: import_zod.z.string().min(1).max(100).optional()
|
|
108
|
+
}).refine(
|
|
109
|
+
(data) => {
|
|
110
|
+
const hasPrompt = !!data.customPrompt;
|
|
111
|
+
const hasCategory = !!data.customCategory;
|
|
112
|
+
return hasPrompt === hasCategory;
|
|
113
|
+
},
|
|
114
|
+
{
|
|
115
|
+
message: "customPrompt and customCategory must both be set, or both be omitted",
|
|
116
|
+
path: ["customPrompt"]
|
|
117
|
+
}
|
|
118
|
+
);
|
|
119
|
+
var OverrideSchema = import_zod.z.object({
|
|
120
|
+
locale: import_zod.z.string().optional(),
|
|
121
|
+
region: import_zod.z.string().optional(),
|
|
122
|
+
data_residency: import_zod.z.string().optional(),
|
|
123
|
+
provider: ProviderNameSchema.optional()
|
|
124
|
+
});
|
|
125
|
+
var FallbackConfigSchema = import_zod.z.object({
|
|
126
|
+
provider: ProviderNameSchema,
|
|
127
|
+
on_timeout: import_zod.z.boolean().optional().default(true),
|
|
128
|
+
timeout_ms: import_zod.z.number().optional().default(5e3)
|
|
129
|
+
});
|
|
130
|
+
var PolicySchema = import_zod.z.object({
|
|
131
|
+
name: import_zod.z.string(),
|
|
132
|
+
version: import_zod.z.string(),
|
|
133
|
+
rules: import_zod.z.array(RuleSchema),
|
|
134
|
+
overrides: import_zod.z.array(OverrideSchema).optional(),
|
|
135
|
+
fallback: FallbackConfigSchema.optional()
|
|
136
|
+
});
|
|
137
|
+
var DecisionSchema = import_zod.z.object({
|
|
138
|
+
id: import_zod.z.string().uuid(),
|
|
139
|
+
content: import_zod.z.string(),
|
|
140
|
+
contentHash: import_zod.z.string(),
|
|
141
|
+
contentType: ContentTypeSchema,
|
|
142
|
+
policy: import_zod.z.object({
|
|
143
|
+
id: import_zod.z.string(),
|
|
144
|
+
version: import_zod.z.string()
|
|
145
|
+
}),
|
|
146
|
+
result: import_zod.z.object({
|
|
147
|
+
safe: import_zod.z.boolean(),
|
|
148
|
+
flagged: import_zod.z.boolean(),
|
|
149
|
+
action: ActionSchema,
|
|
150
|
+
categories: import_zod.z.array(
|
|
151
|
+
import_zod.z.object({
|
|
152
|
+
category: CategorySchema,
|
|
153
|
+
score: import_zod.z.number(),
|
|
154
|
+
threshold: import_zod.z.number(),
|
|
155
|
+
triggered: import_zod.z.boolean()
|
|
156
|
+
})
|
|
157
|
+
)
|
|
158
|
+
}),
|
|
159
|
+
provider: import_zod.z.object({
|
|
160
|
+
name: ProviderNameSchema,
|
|
161
|
+
latency: import_zod.z.number(),
|
|
162
|
+
cost: import_zod.z.number()
|
|
163
|
+
}),
|
|
164
|
+
metadata: import_zod.z.record(import_zod.z.unknown()).optional(),
|
|
165
|
+
timestamp: import_zod.z.string().datetime(),
|
|
166
|
+
requestId: import_zod.z.string().optional()
|
|
167
|
+
});
|
|
168
|
+
var MultiModalCheckRequestSchema = import_zod.z.object({
|
|
169
|
+
// Multi-modal content inputs
|
|
170
|
+
text: import_zod.z.string().max(1e5, "Text exceeds maximum size of 100KB").optional(),
|
|
171
|
+
images: import_zod.z.array(
|
|
172
|
+
import_zod.z.string().refine(
|
|
173
|
+
(val) => {
|
|
174
|
+
return val.startsWith("http://") || val.startsWith("https://") || val.startsWith("data:image/");
|
|
175
|
+
},
|
|
176
|
+
{ message: "Images must be URLs or base64 data URIs" }
|
|
177
|
+
)
|
|
178
|
+
).max(10, "Maximum 10 images per request").optional(),
|
|
179
|
+
video: import_zod.z.string().url("Video must be a valid URL").optional(),
|
|
180
|
+
// Moderation context
|
|
181
|
+
context: import_zod.z.object({
|
|
182
|
+
useCase: UseCaseTypeSchema.default("other"),
|
|
183
|
+
userId: import_zod.z.string().optional(),
|
|
184
|
+
userReputation: import_zod.z.number().min(0).max(1).optional(),
|
|
185
|
+
// 0-1 score
|
|
186
|
+
locale: import_zod.z.string().optional(),
|
|
187
|
+
region: import_zod.z.string().optional()
|
|
188
|
+
}).optional(),
|
|
189
|
+
// Policy and metadata
|
|
190
|
+
policyId: import_zod.z.string(),
|
|
191
|
+
metadata: import_zod.z.record(import_zod.z.unknown()).optional(),
|
|
192
|
+
requestId: import_zod.z.string().optional()
|
|
193
|
+
// For idempotency
|
|
194
|
+
}).refine(
|
|
195
|
+
(data) => {
|
|
196
|
+
return data.text || data.images?.length || data.video;
|
|
197
|
+
},
|
|
198
|
+
{ message: "At least one of text, images, or video must be provided" }
|
|
199
|
+
);
|
|
200
|
+
var CheckRequestSchema = import_zod.z.object({
|
|
201
|
+
content: import_zod.z.string().min(1).max(1e5, "Content exceeds maximum size of 100KB"),
|
|
202
|
+
policyId: import_zod.z.string(),
|
|
203
|
+
contentType: ContentTypeSchema.optional().default("text"),
|
|
204
|
+
metadata: import_zod.z.record(import_zod.z.unknown()).optional(),
|
|
205
|
+
requestId: import_zod.z.string().optional()
|
|
206
|
+
// For idempotency
|
|
207
|
+
});
|
|
208
|
+
var ContentItemResultSchema = import_zod.z.object({
|
|
209
|
+
contentType: ContentTypeSchema,
|
|
210
|
+
contentRef: import_zod.z.string().optional(),
|
|
211
|
+
// URL or identifier for images/video
|
|
212
|
+
contentItemId: import_zod.z.string().uuid().optional(),
|
|
213
|
+
// Database ID for linking evidence
|
|
214
|
+
safe: import_zod.z.boolean(),
|
|
215
|
+
flagged: import_zod.z.boolean(),
|
|
216
|
+
action: ActionSchema,
|
|
217
|
+
categories: import_zod.z.array(
|
|
218
|
+
import_zod.z.object({
|
|
219
|
+
category: CategorySchema,
|
|
220
|
+
score: import_zod.z.number(),
|
|
221
|
+
triggered: import_zod.z.boolean()
|
|
222
|
+
})
|
|
223
|
+
),
|
|
224
|
+
provider: ProviderNameSchema,
|
|
225
|
+
latency: import_zod.z.number(),
|
|
226
|
+
cost: import_zod.z.number(),
|
|
227
|
+
evidence: import_zod.z.object({
|
|
228
|
+
url: import_zod.z.string().url().optional(),
|
|
229
|
+
// Signed URL to evidence (screenshot, frame)
|
|
230
|
+
expiresAt: import_zod.z.string().datetime().optional()
|
|
231
|
+
}).optional()
|
|
232
|
+
});
|
|
233
|
+
var MultiModalCheckResponseSchema = import_zod.z.object({
|
|
234
|
+
decisionId: import_zod.z.string().uuid(),
|
|
235
|
+
safe: import_zod.z.boolean(),
|
|
236
|
+
// Overall safe if ALL content items are safe
|
|
237
|
+
flagged: import_zod.z.boolean(),
|
|
238
|
+
// Overall flagged if ANY content item is flagged
|
|
239
|
+
action: ActionSchema,
|
|
240
|
+
// Most severe action across all content
|
|
241
|
+
results: import_zod.z.array(ContentItemResultSchema),
|
|
242
|
+
// Per-content-type results
|
|
243
|
+
totalLatency: import_zod.z.number(),
|
|
244
|
+
totalCost: import_zod.z.number(),
|
|
245
|
+
requestId: import_zod.z.string().optional()
|
|
246
|
+
});
|
|
247
|
+
var CheckResponseSchema = import_zod.z.object({
|
|
248
|
+
decisionId: import_zod.z.string().uuid(),
|
|
249
|
+
safe: import_zod.z.boolean(),
|
|
250
|
+
flagged: import_zod.z.boolean(),
|
|
251
|
+
action: ActionSchema,
|
|
252
|
+
categories: import_zod.z.array(
|
|
253
|
+
import_zod.z.object({
|
|
254
|
+
category: CategorySchema,
|
|
255
|
+
score: import_zod.z.number(),
|
|
256
|
+
triggered: import_zod.z.boolean()
|
|
257
|
+
})
|
|
258
|
+
),
|
|
259
|
+
provider: ProviderNameSchema,
|
|
260
|
+
latency: import_zod.z.number(),
|
|
261
|
+
cost: import_zod.z.number(),
|
|
262
|
+
requestId: import_zod.z.string().optional()
|
|
263
|
+
});
|
|
264
|
+
var ReplayRequestSchema = import_zod.z.object({
|
|
265
|
+
decisionId: import_zod.z.string().uuid(),
|
|
266
|
+
policyId: import_zod.z.string()
|
|
267
|
+
});
|
|
268
|
+
var ModerationError = class extends Error {
|
|
269
|
+
constructor(message, code, statusCode = 500, details) {
|
|
270
|
+
super(message);
|
|
271
|
+
this.code = code;
|
|
272
|
+
this.statusCode = statusCode;
|
|
273
|
+
this.details = details;
|
|
274
|
+
this.name = "ModerationError";
|
|
275
|
+
}
|
|
276
|
+
};
|
|
277
|
+
var PolicyValidationError = class extends ModerationError {
|
|
278
|
+
constructor(message, details) {
|
|
279
|
+
super(message, "POLICY_VALIDATION_ERROR", 400, details);
|
|
280
|
+
this.name = "PolicyValidationError";
|
|
281
|
+
}
|
|
282
|
+
};
|
|
283
|
+
var ProviderError = class extends ModerationError {
|
|
284
|
+
constructor(message, provider, details) {
|
|
285
|
+
super(message, "PROVIDER_ERROR", 502, { provider, ...details });
|
|
286
|
+
this.name = "ProviderError";
|
|
287
|
+
}
|
|
288
|
+
};
|
|
289
|
+
var WebhookEventTypeSchema = import_zod.z.enum([
|
|
290
|
+
"decision.created",
|
|
291
|
+
"decision.flagged",
|
|
292
|
+
"decision.blocked",
|
|
293
|
+
"policy.created",
|
|
294
|
+
"policy.updated"
|
|
295
|
+
]);
|
|
296
|
+
var WebhookEndpointSchema = import_zod.z.object({
|
|
297
|
+
url: import_zod.z.string().url().refine(
|
|
298
|
+
(url) => {
|
|
299
|
+
if (process.env.NODE_ENV === "production") {
|
|
300
|
+
return !url.includes("localhost") && !url.includes("127.0.0.1");
|
|
301
|
+
}
|
|
302
|
+
return true;
|
|
303
|
+
},
|
|
304
|
+
"Localhost webhooks are not allowed in production"
|
|
305
|
+
),
|
|
306
|
+
events: import_zod.z.array(WebhookEventTypeSchema),
|
|
307
|
+
description: import_zod.z.string().max(500).optional()
|
|
308
|
+
});
|
|
309
|
+
|
|
310
|
+
// src/utils.ts
|
|
311
|
+
var import_crypto = __toESM(require("crypto"), 1);
|
|
312
|
+
function hashContent(content) {
|
|
313
|
+
return import_crypto.default.createHash("sha256").update(content).digest("hex");
|
|
314
|
+
}
|
|
315
|
+
function generateUUID() {
|
|
316
|
+
return import_crypto.default.randomUUID();
|
|
317
|
+
}
|
|
318
|
+
function generateRequestId() {
|
|
319
|
+
return `req_${Date.now()}_${Math.random().toString(36).substring(7)}`;
|
|
320
|
+
}
|
|
321
|
+
function calculatePolicyVersion(yaml) {
|
|
322
|
+
return hashContent(yaml).substring(0, 16);
|
|
323
|
+
}
|
|
324
|
+
function formatCost(cost) {
|
|
325
|
+
return `$${cost.toFixed(6)}`;
|
|
326
|
+
}
|
|
327
|
+
function formatLatency(ms) {
|
|
328
|
+
if (ms < 1e3) {
|
|
329
|
+
return `${ms.toFixed(0)}ms`;
|
|
330
|
+
}
|
|
331
|
+
return `${(ms / 1e3).toFixed(2)}s`;
|
|
332
|
+
}
|
|
333
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
334
|
+
0 && (module.exports = {
|
|
335
|
+
ActionSchema,
|
|
336
|
+
CategorySchema,
|
|
337
|
+
CheckRequestSchema,
|
|
338
|
+
CheckResponseSchema,
|
|
339
|
+
ContentItemResultSchema,
|
|
340
|
+
ContentTypeSchema,
|
|
341
|
+
DecisionSchema,
|
|
342
|
+
FallbackConfigSchema,
|
|
343
|
+
ModerationError,
|
|
344
|
+
MultiModalCheckRequestSchema,
|
|
345
|
+
MultiModalCheckResponseSchema,
|
|
346
|
+
OverrideSchema,
|
|
347
|
+
PolicySchema,
|
|
348
|
+
PolicyValidationError,
|
|
349
|
+
ProviderError,
|
|
350
|
+
ProviderNameSchema,
|
|
351
|
+
ReplayRequestSchema,
|
|
352
|
+
RuleSchema,
|
|
353
|
+
UseCaseTypeSchema,
|
|
354
|
+
WebhookEndpointSchema,
|
|
355
|
+
WebhookEventTypeSchema,
|
|
356
|
+
calculatePolicyVersion,
|
|
357
|
+
formatCost,
|
|
358
|
+
formatLatency,
|
|
359
|
+
generateRequestId,
|
|
360
|
+
generateUUID,
|
|
361
|
+
hashContent
|
|
362
|
+
});
|