plugin-sensitive-filter-xr 0.0.1 → 0.0.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
@@ -39,13 +39,18 @@ type GeneralPackConfig = {
39
39
  };
40
40
 
41
41
  type SensitiveFilterConfig = {
42
- rules?: Array<Partial<SensitiveRule> | null>; // 允许空,支持仅通用规则包
42
+ rules: Array<Partial<SensitiveRule> | null>; // 必填,且至少 1 条业务规则
43
43
  generalPack?: GeneralPackConfig;
44
44
  caseSensitive?: boolean; // default false
45
45
  normalize?: boolean; // default true
46
46
  };
47
47
  ```
48
48
 
49
+ 业务规则字段约束:
50
+ - 必填:`pattern`、`type`、`action`
51
+ - 条件必填:当 `action='rewrite'` 时,`replacementText` 必填
52
+ - 可选:`id`(留空自动生成)、`scope`(默认 `both`)、`severity`(默认 `medium`)
53
+
49
54
  ## 通用规则包(General Pack)
50
55
 
51
56
  - `enabled=false`:不启用通用规则
@@ -1 +1 @@
1
- {"version":3,"file":"sensitiveFilter.d.ts","sourceRoot":"","sources":["../../src/lib/sensitiveFilter.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAA;AAEvD,OAAO,EACL,eAAe,EAEf,uBAAuB,EACvB,wBAAwB,EACxB,cAAc,EACf,MAAM,sBAAsB,CAAA;AAC7B,OAAO,EAGL,qBAAqB,EAKtB,MAAM,YAAY,CAAA;AAuQnB,qBAEa,yBAA0B,YAAW,wBAAwB,CAAC,qBAAqB,CAAC;IAC/F,QAAQ,CAAC,IAAI,EAAE,oBAAoB,CA4IlC;IAED,gBAAgB,CACd,OAAO,EAAE,qBAAqB,EAC9B,QAAQ,EAAE,uBAAuB,GAChC,cAAc,CAAC,eAAe,CAAC;CA4GnC;AAED,YAAY,EAAE,qBAAqB,EAAE,CAAA"}
1
+ {"version":3,"file":"sensitiveFilter.d.ts","sourceRoot":"","sources":["../../src/lib/sensitiveFilter.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAA;AAEvD,OAAO,EACL,eAAe,EAEf,uBAAuB,EACvB,wBAAwB,EACxB,cAAc,EACf,MAAM,sBAAsB,CAAA;AAC7B,OAAO,EAGL,qBAAqB,EAKtB,MAAM,YAAY,CAAA;AA6QnB,qBAEa,yBAA0B,YAAW,wBAAwB,CAAC,qBAAqB,CAAC;IAC/F,QAAQ,CAAC,IAAI,EAAE,oBAAoB,CAgKlC;IAED,gBAAgB,CACd,OAAO,EAAE,qBAAqB,EAC9B,QAAQ,EAAE,uBAAuB,GAChC,cAAc,CAAC,eAAe,CAAC;CA4GnC;AAED,YAAY,EAAE,qBAAqB,EAAE,CAAA"}
@@ -166,9 +166,9 @@ function rewriteModelRequestInput(request, rewrittenText) {
166
166
  }
167
167
  function normalizeRuleDrafts(input) {
168
168
  const rules = [];
169
- for (const draft of input) {
169
+ for (const [index, draft] of input.entries()) {
170
170
  if (!isRecord(draft)) {
171
- continue;
171
+ throw new Error(`Invalid rule at index ${index}: rule must be an object`);
172
172
  }
173
173
  const id = toNonEmptyString(draft['id']);
174
174
  const pattern = toNonEmptyString(draft['pattern']);
@@ -177,31 +177,38 @@ function normalizeRuleDrafts(input) {
177
177
  const severity = toNonEmptyString(draft['severity']);
178
178
  const action = toNonEmptyString(draft['action']);
179
179
  const replacementText = toNonEmptyString(draft['replacementText']) ?? undefined;
180
- const hasAnyValue = Boolean(id || pattern || type || scope || severity || action || replacementText);
181
- if (!hasAnyValue) {
182
- continue;
180
+ if (!pattern) {
181
+ throw new Error(`Invalid rule at index ${index}: pattern is required`);
183
182
  }
184
- if (!id || !pattern || !type || !scope || !severity || !action) {
185
- continue;
183
+ if (!type) {
184
+ throw new Error(`Invalid rule at index ${index}: type is required`);
185
+ }
186
+ if (!action) {
187
+ throw new Error(`Invalid rule at index ${index}: action is required`);
188
+ }
189
+ if (action === 'rewrite' && !replacementText) {
190
+ throw new Error(`Invalid rule at index ${index}: replacementText is required when action is rewrite`);
186
191
  }
187
192
  if (!['keyword', 'regex'].includes(type)) {
188
- continue;
193
+ throw new Error(`Invalid rule at index ${index}: unsupported type '${type}'`);
189
194
  }
190
- if (!['input', 'output', 'both'].includes(scope)) {
191
- continue;
195
+ const normalizedScope = scope ?? 'both';
196
+ if (!['input', 'output', 'both'].includes(normalizedScope)) {
197
+ throw new Error(`Invalid rule at index ${index}: unsupported scope '${normalizedScope}'`);
192
198
  }
193
- if (!['high', 'medium'].includes(severity)) {
194
- continue;
199
+ const normalizedSeverity = severity ?? 'medium';
200
+ if (!['high', 'medium'].includes(normalizedSeverity)) {
201
+ throw new Error(`Invalid rule at index ${index}: unsupported severity '${normalizedSeverity}'`);
195
202
  }
196
203
  if (!['block', 'rewrite'].includes(action)) {
197
- continue;
204
+ throw new Error(`Invalid rule at index ${index}: unsupported action '${action}'`);
198
205
  }
199
206
  rules.push({
200
- id,
207
+ id: id ?? `rule-${index + 1}`,
201
208
  pattern,
202
209
  type,
203
- scope,
204
- severity,
210
+ scope: normalizedScope,
211
+ severity: normalizedSeverity,
205
212
  action,
206
213
  replacementText,
207
214
  });
@@ -243,6 +250,10 @@ let SensitiveFilterMiddleware = class SensitiveFilterMiddleware {
243
250
  id: {
244
251
  type: 'string',
245
252
  title: { en_US: 'Rule ID', zh_Hans: '规则标识' },
253
+ description: {
254
+ en_US: 'Optional. Auto-generated when empty.',
255
+ zh_Hans: '可选。留空时系统自动生成。',
256
+ },
246
257
  },
247
258
  pattern: {
248
259
  type: 'string',
@@ -295,10 +306,26 @@ let SensitiveFilterMiddleware = class SensitiveFilterMiddleware {
295
306
  },
296
307
  replacementText: {
297
308
  type: 'string',
298
- title: { en_US: 'Replacement Text', zh_Hans: '替换文本(可选)' },
309
+ title: { en_US: 'Replacement Text', zh_Hans: '替换文本(rewrite 必填)' },
299
310
  },
300
311
  },
312
+ required: ['pattern', 'type', 'action'],
313
+ allOf: [
314
+ {
315
+ if: {
316
+ properties: {
317
+ action: {
318
+ const: 'rewrite',
319
+ },
320
+ },
321
+ },
322
+ then: {
323
+ required: ['replacementText'],
324
+ },
325
+ },
326
+ ],
301
327
  },
328
+ minItems: 1,
302
329
  },
303
330
  generalPack: {
304
331
  type: 'object',
@@ -356,7 +383,7 @@ let SensitiveFilterMiddleware = class SensitiveFilterMiddleware {
356
383
  const config = parsed.data;
357
384
  const caseSensitive = config.caseSensitive ?? false;
358
385
  const normalize = config.normalize ?? true;
359
- const customRules = normalizeRuleDrafts(config.rules ?? []);
386
+ const customRules = normalizeRuleDrafts(config.rules);
360
387
  const generalRules = resolveGeneralPackRules(config.generalPack);
361
388
  const allRules = [...customRules, ...generalRules];
362
389
  const compiledRules = allRules.map((rule, index) => {
@@ -13,7 +13,7 @@ export type GeneralPackConfig = {
13
13
  profile?: 'strict' | 'balanced';
14
14
  };
15
15
  export type SensitiveFilterConfig = {
16
- rules?: Array<Partial<SensitiveRule> | null>;
16
+ rules: Array<Partial<SensitiveRule> | null>;
17
17
  generalPack?: GeneralPackConfig;
18
18
  caseSensitive?: boolean;
19
19
  normalize?: boolean;
@@ -26,13 +26,13 @@ export type CompiledSensitiveRule = SensitiveRule & {
26
26
  };
27
27
  export declare const SensitiveFilterIcon = "<svg width=\"800px\" height=\"800px\" viewBox=\"0 0 24 24\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M12 2l7 3v6c0 5.2-3.3 9.9-7 11-3.7-1.1-7-5.8-7-11V5l7-3zm0 2.1L7 6v5c0 3.9 2.3 7.8 5 8.9 2.7-1.1 5-5 5-8.9V6l-5-1.9zM8.8 12.6l1.4-1.4 1.8 1.8 3.8-3.8 1.4 1.4-5.2 5.2-3.2-3.2z\"/></svg>";
28
28
  export declare const sensitiveFilterConfigSchema: z.ZodObject<{
29
- rules: z.ZodDefault<z.ZodOptional<z.ZodArray<z.ZodNullable<z.ZodObject<{
29
+ rules: z.ZodArray<z.ZodNullable<z.ZodEffects<z.ZodObject<{
30
30
  id: z.ZodNullable<z.ZodOptional<z.ZodString>>;
31
- pattern: z.ZodNullable<z.ZodOptional<z.ZodString>>;
32
- type: z.ZodNullable<z.ZodOptional<z.ZodEnum<["keyword", "regex"]>>>;
31
+ pattern: z.ZodString;
32
+ type: z.ZodEnum<["keyword", "regex"]>;
33
33
  scope: z.ZodNullable<z.ZodOptional<z.ZodEnum<["input", "output", "both"]>>>;
34
34
  severity: z.ZodNullable<z.ZodOptional<z.ZodEnum<["high", "medium"]>>>;
35
- action: z.ZodNullable<z.ZodOptional<z.ZodEnum<["block", "rewrite"]>>>;
35
+ action: z.ZodEnum<["block", "rewrite"]>;
36
36
  replacementText: z.ZodNullable<z.ZodOptional<z.ZodString>>;
37
37
  }, "strip", z.ZodTypeAny, {
38
38
  id?: string;
@@ -50,7 +50,23 @@ export declare const sensitiveFilterConfigSchema: z.ZodObject<{
50
50
  severity?: "high" | "medium";
51
51
  action?: "block" | "rewrite";
52
52
  replacementText?: string;
53
- }>>, "many">>>;
53
+ }>, {
54
+ id?: string;
55
+ pattern?: string;
56
+ type?: "keyword" | "regex";
57
+ scope?: "input" | "output" | "both";
58
+ severity?: "high" | "medium";
59
+ action?: "block" | "rewrite";
60
+ replacementText?: string;
61
+ }, {
62
+ id?: string;
63
+ pattern?: string;
64
+ type?: "keyword" | "regex";
65
+ scope?: "input" | "output" | "both";
66
+ severity?: "high" | "medium";
67
+ action?: "block" | "rewrite";
68
+ replacementText?: string;
69
+ }>>, "many">;
54
70
  generalPack: z.ZodOptional<z.ZodObject<{
55
71
  enabled: z.ZodDefault<z.ZodBoolean>;
56
72
  profile: z.ZodOptional<z.ZodDefault<z.ZodEnum<["strict", "balanced"]>>>;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/lib/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,QAAQ,CAAA;AAE1B,MAAM,MAAM,aAAa,GAAG;IAC1B,EAAE,EAAE,MAAM,CAAA;IACV,OAAO,EAAE,MAAM,CAAA;IACf,IAAI,EAAE,SAAS,GAAG,OAAO,CAAA;IACzB,KAAK,EAAE,OAAO,GAAG,QAAQ,GAAG,MAAM,CAAA;IAClC,QAAQ,EAAE,MAAM,GAAG,QAAQ,CAAA;IAC3B,MAAM,EAAE,OAAO,GAAG,SAAS,CAAA;IAC3B,eAAe,CAAC,EAAE,MAAM,CAAA;CACzB,CAAA;AAED,MAAM,MAAM,iBAAiB,GAAG;IAC9B,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,OAAO,CAAC,EAAE,QAAQ,GAAG,UAAU,CAAA;CAChC,CAAA;AAED,MAAM,MAAM,qBAAqB,GAAG;IAClC,KAAK,CAAC,EAAE,KAAK,CAAC,OAAO,CAAC,aAAa,CAAC,GAAG,IAAI,CAAC,CAAA;IAC5C,WAAW,CAAC,EAAE,iBAAiB,CAAA;IAC/B,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB,SAAS,CAAC,EAAE,OAAO,CAAA;CACpB,CAAA;AAED,MAAM,MAAM,qBAAqB,GAAG,aAAa,GAAG;IAClD,KAAK,EAAE,MAAM,CAAA;IACb,iBAAiB,EAAE,MAAM,CAAA;IACzB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,YAAY,CAAC,EAAE,MAAM,CAAA;CACtB,CAAA;AAED,eAAO,MAAM,mBAAmB,wSAA8R,CAAA;AAmC9T,eAAO,MAAM,2BAA2B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAKtC,CAAA;AAYF,wBAAgB,uBAAuB,CAAC,MAAM,CAAC,EAAE,iBAAiB,GAAG,aAAa,EAAE,CA6CnF"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/lib/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,QAAQ,CAAA;AAE1B,MAAM,MAAM,aAAa,GAAG;IAC1B,EAAE,EAAE,MAAM,CAAA;IACV,OAAO,EAAE,MAAM,CAAA;IACf,IAAI,EAAE,SAAS,GAAG,OAAO,CAAA;IACzB,KAAK,EAAE,OAAO,GAAG,QAAQ,GAAG,MAAM,CAAA;IAClC,QAAQ,EAAE,MAAM,GAAG,QAAQ,CAAA;IAC3B,MAAM,EAAE,OAAO,GAAG,SAAS,CAAA;IAC3B,eAAe,CAAC,EAAE,MAAM,CAAA;CACzB,CAAA;AAED,MAAM,MAAM,iBAAiB,GAAG;IAC9B,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,OAAO,CAAC,EAAE,QAAQ,GAAG,UAAU,CAAA;CAChC,CAAA;AAED,MAAM,MAAM,qBAAqB,GAAG;IAClC,KAAK,EAAE,KAAK,CAAC,OAAO,CAAC,aAAa,CAAC,GAAG,IAAI,CAAC,CAAA;IAC3C,WAAW,CAAC,EAAE,iBAAiB,CAAA;IAC/B,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB,SAAS,CAAC,EAAE,OAAO,CAAA;CACpB,CAAA;AAED,MAAM,MAAM,qBAAqB,GAAG,aAAa,GAAG;IAClD,KAAK,EAAE,MAAM,CAAA;IACb,iBAAiB,EAAE,MAAM,CAAA;IACzB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,YAAY,CAAC,EAAE,MAAM,CAAA;CACtB,CAAA;AAED,eAAO,MAAM,mBAAmB,wSAA8R,CAAA;AAoD9T,eAAO,MAAM,2BAA2B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAKtC,CAAA;AAYF,wBAAgB,uBAAuB,CAAC,MAAM,CAAC,EAAE,iBAAiB,GAAG,aAAa,EAAE,CA6CnF"}
package/dist/lib/types.js CHANGED
@@ -18,12 +18,28 @@ const OPEN_SOURCE_LEXICON = {
18
18
  const sensitiveRuleDraftSchema = z
19
19
  .object({
20
20
  id: z.string().optional().nullable(),
21
- pattern: z.string().optional().nullable(),
22
- type: z.enum(['keyword', 'regex']).optional().nullable(),
21
+ pattern: z.string(),
22
+ type: z.enum(['keyword', 'regex']),
23
23
  scope: z.enum(['input', 'output', 'both']).optional().nullable(),
24
24
  severity: z.enum(['high', 'medium']).optional().nullable(),
25
- action: z.enum(['block', 'rewrite']).optional().nullable(),
25
+ action: z.enum(['block', 'rewrite']),
26
26
  replacementText: z.string().optional().nullable(),
27
+ })
28
+ .superRefine((value, ctx) => {
29
+ if (!value.pattern?.trim()) {
30
+ ctx.addIssue({
31
+ code: z.ZodIssueCode.custom,
32
+ path: ['pattern'],
33
+ message: 'pattern is required',
34
+ });
35
+ }
36
+ if (value.action === 'rewrite' && !value.replacementText?.trim()) {
37
+ ctx.addIssue({
38
+ code: z.ZodIssueCode.custom,
39
+ path: ['replacementText'],
40
+ message: 'replacementText is required when action is rewrite',
41
+ });
42
+ }
27
43
  })
28
44
  .nullable();
29
45
  const generalPackSchema = z.object({
@@ -31,7 +47,7 @@ const generalPackSchema = z.object({
31
47
  profile: z.enum(['strict', 'balanced']).default('balanced').optional(),
32
48
  });
33
49
  export const sensitiveFilterConfigSchema = z.object({
34
- rules: z.array(sensitiveRuleDraftSchema).optional().default([]),
50
+ rules: z.array(sensitiveRuleDraftSchema).min(1, 'at least one business rule is required'),
35
51
  generalPack: generalPackSchema.optional(),
36
52
  caseSensitive: z.boolean().optional().default(false),
37
53
  normalize: z.boolean().optional().default(true),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "plugin-sensitive-filter-xr",
3
- "version": "0.0.1",
3
+ "version": "0.0.2",
4
4
  "author": {
5
5
  "name": "XpertAI",
6
6
  "url": "https://xpertai.cn"