mirror of
https://gitlab.com/soapbox-pub/ditto.git
synced 2025-12-06 11:29:46 +00:00
fmt
This commit is contained in:
parent
e533ec22b6
commit
3ace715498
4 changed files with 153 additions and 153 deletions
|
|
@ -9,42 +9,42 @@ type ParamValue = string | number | boolean;
|
|||
export { PolicyRegistry };
|
||||
|
||||
export const policyRegistry = new PolicyRegistry({
|
||||
antiDuplicationPolicyStore: {
|
||||
get: (key: Deno.KvKey) => Promise.resolve({ key, value: null, versionstamp: null }),
|
||||
set: () => Promise.resolve({ ok: true, versionstamp: '00000000000000000000' }),
|
||||
},
|
||||
store: new MockRelay(),
|
||||
antiDuplicationPolicyStore: {
|
||||
get: (key: Deno.KvKey) => Promise.resolve({ key, value: null, versionstamp: null }),
|
||||
set: () => Promise.resolve({ ok: true, versionstamp: '00000000000000000000' }),
|
||||
},
|
||||
store: new MockRelay(),
|
||||
});
|
||||
|
||||
interface PolicySpecItem {
|
||||
name: keyof typeof policyRegistry.available;
|
||||
params?: Record<string, ParamValue | (number | string)[]>;
|
||||
name: keyof typeof policyRegistry.available;
|
||||
params?: Record<string, ParamValue | (number | string)[]>;
|
||||
}
|
||||
|
||||
export interface PolicySpec {
|
||||
policies: PolicySpecItem[];
|
||||
policies: PolicySpecItem[];
|
||||
}
|
||||
|
||||
export const normalizeNpub = (itm: string) => {
|
||||
if (!itm.startsWith('npub1')) return itm;
|
||||
return nip19.decode(itm as `npub1${string}`).data;
|
||||
if (!itm.startsWith('npub1')) return itm;
|
||||
return nip19.decode(itm as `npub1${string}`).data;
|
||||
};
|
||||
|
||||
export const DEFAULT_POLICY_SPEC: PolicySpec = {
|
||||
policies: [
|
||||
{ 'name': 'AntiDuplicationPolicy' },
|
||||
{ 'name': 'HellthreadPolicy' },
|
||||
{ 'name': 'ReplyBotPolicy' },
|
||||
{ 'name': 'SizePolicy' },
|
||||
{ 'name': 'HashtagPolicy', 'params': { 'hashtags': ['NSFW', 'explicit', 'violence', 'cp', 'porn'] } },
|
||||
],
|
||||
policies: [
|
||||
{ 'name': 'AntiDuplicationPolicy' },
|
||||
{ 'name': 'HellthreadPolicy' },
|
||||
{ 'name': 'ReplyBotPolicy' },
|
||||
{ 'name': 'SizePolicy' },
|
||||
{ 'name': 'HashtagPolicy', 'params': { 'hashtags': ['NSFW', 'explicit', 'violence', 'cp', 'porn'] } },
|
||||
],
|
||||
};
|
||||
|
||||
export const createPolicyEvent = async (conf: DittoConf, policies: PolicySpec) => {
|
||||
return await conf.signer.signEvent({
|
||||
kind: 11984,
|
||||
content: JSON.stringify(policies),
|
||||
created_at: nostrNow(),
|
||||
tags: [],
|
||||
});
|
||||
return await conf.signer.signEvent({
|
||||
kind: 11984,
|
||||
content: JSON.stringify(policies),
|
||||
created_at: nostrNow(),
|
||||
tags: [],
|
||||
});
|
||||
};
|
||||
|
|
|
|||
|
|
@ -3,103 +3,103 @@ import { z } from 'zod';
|
|||
import { zodSchemaToFields } from './parameters.ts';
|
||||
|
||||
Deno.test('zodSchemaToFields - basic types', () => {
|
||||
const schema = z.object({
|
||||
name: z.string(),
|
||||
age: z.number(),
|
||||
});
|
||||
const schema = z.object({
|
||||
name: z.string(),
|
||||
age: z.number(),
|
||||
});
|
||||
|
||||
const result = zodSchemaToFields(schema);
|
||||
assertEquals(result, {
|
||||
name: { type: 'string' },
|
||||
age: { type: 'number' },
|
||||
});
|
||||
const result = zodSchemaToFields(schema);
|
||||
assertEquals(result, {
|
||||
name: { type: 'string' },
|
||||
age: { type: 'number' },
|
||||
});
|
||||
});
|
||||
|
||||
Deno.test('zodSchemaToFields - array types', () => {
|
||||
const schema = z.object({
|
||||
tags: z.array(z.string()),
|
||||
scores: z.array(z.number()),
|
||||
});
|
||||
const schema = z.object({
|
||||
tags: z.array(z.string()),
|
||||
scores: z.array(z.number()),
|
||||
});
|
||||
|
||||
const result = zodSchemaToFields(schema);
|
||||
assertEquals(result, {
|
||||
tags: { type: 'multi_string' },
|
||||
scores: { type: 'multi_number' },
|
||||
});
|
||||
const result = zodSchemaToFields(schema);
|
||||
assertEquals(result, {
|
||||
tags: { type: 'multi_string' },
|
||||
scores: { type: 'multi_number' },
|
||||
});
|
||||
});
|
||||
|
||||
Deno.test('zodSchemaToFields - special-case NIP-01 filters', () => {
|
||||
const schema = z.object({
|
||||
filters: z.array(z.string()),
|
||||
keywords: z.array(z.string()),
|
||||
});
|
||||
const schema = z.object({
|
||||
filters: z.array(z.string()),
|
||||
keywords: z.array(z.string()),
|
||||
});
|
||||
|
||||
const result = zodSchemaToFields(schema);
|
||||
assertEquals(result, {
|
||||
filters: { type: 'multi_string' },
|
||||
keywords: { type: 'multi_string' },
|
||||
});
|
||||
const result = zodSchemaToFields(schema);
|
||||
assertEquals(result, {
|
||||
filters: { type: 'multi_string' },
|
||||
keywords: { type: 'multi_string' },
|
||||
});
|
||||
});
|
||||
|
||||
Deno.test('zodSchemaToFields - mixed types', () => {
|
||||
const schema = z.object({
|
||||
id: z.string(),
|
||||
values: z.array(z.number()),
|
||||
flags: z.array(z.string()).describe('Test description'),
|
||||
});
|
||||
const schema = z.object({
|
||||
id: z.string(),
|
||||
values: z.array(z.number()),
|
||||
flags: z.array(z.string()).describe('Test description'),
|
||||
});
|
||||
|
||||
const result = zodSchemaToFields(schema);
|
||||
assertEquals(result, {
|
||||
id: { type: 'string' },
|
||||
values: { type: 'multi_number' },
|
||||
flags: { type: 'multi_string', description: 'Test description' },
|
||||
});
|
||||
const result = zodSchemaToFields(schema);
|
||||
assertEquals(result, {
|
||||
id: { type: 'string' },
|
||||
values: { type: 'multi_number' },
|
||||
flags: { type: 'multi_string', description: 'Test description' },
|
||||
});
|
||||
});
|
||||
|
||||
Deno.test('zodSchemaToFields - optional fields', () => {
|
||||
const schema = z.object({
|
||||
name: z.string().optional(),
|
||||
age: z.number().optional(),
|
||||
});
|
||||
const schema = z.object({
|
||||
name: z.string().optional(),
|
||||
age: z.number().optional(),
|
||||
});
|
||||
|
||||
const result = zodSchemaToFields(schema);
|
||||
assertEquals(result, {
|
||||
name: { type: 'string', optional: true },
|
||||
age: { type: 'number', optional: true },
|
||||
});
|
||||
const result = zodSchemaToFields(schema);
|
||||
assertEquals(result, {
|
||||
name: { type: 'string', optional: true },
|
||||
age: { type: 'number', optional: true },
|
||||
});
|
||||
});
|
||||
|
||||
Deno.test('zodSchemaToFields - default values', () => {
|
||||
const schema = z.object({
|
||||
name: z.string().default('John Doe'),
|
||||
age: z.number().default(30),
|
||||
});
|
||||
const schema = z.object({
|
||||
name: z.string().default('John Doe'),
|
||||
age: z.number().default(30),
|
||||
});
|
||||
|
||||
const result = zodSchemaToFields(schema);
|
||||
assertEquals(result, {
|
||||
name: { type: 'string', default: 'John Doe' },
|
||||
age: { type: 'number', default: 30 },
|
||||
});
|
||||
const result = zodSchemaToFields(schema);
|
||||
assertEquals(result, {
|
||||
name: { type: 'string', default: 'John Doe' },
|
||||
age: { type: 'number', default: 30 },
|
||||
});
|
||||
});
|
||||
|
||||
Deno.test('zodSchemaToFields - boolean fields', () => {
|
||||
const schema = z.object({
|
||||
active: z.boolean(),
|
||||
});
|
||||
const schema = z.object({
|
||||
active: z.boolean(),
|
||||
});
|
||||
|
||||
const result = zodSchemaToFields(schema);
|
||||
assertEquals(result, {
|
||||
active: { type: 'boolean' },
|
||||
});
|
||||
const result = zodSchemaToFields(schema);
|
||||
assertEquals(result, {
|
||||
active: { type: 'boolean' },
|
||||
});
|
||||
});
|
||||
|
||||
Deno.test('zodSchemaToFields - invalid schema', () => {
|
||||
const schema = z.object({
|
||||
invalid: z.any(),
|
||||
});
|
||||
const schema = z.object({
|
||||
invalid: z.any(),
|
||||
});
|
||||
|
||||
const result = zodSchemaToFields(schema);
|
||||
assertEquals(result, {
|
||||
invalid: { type: 'unknown' },
|
||||
});
|
||||
const result = zodSchemaToFields(schema);
|
||||
assertEquals(result, {
|
||||
invalid: { type: 'unknown' },
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -3,52 +3,52 @@ import { z } from 'zod';
|
|||
type FieldType = 'string' | 'multi_string' | 'number' | 'multi_number' | 'boolean' | 'unknown';
|
||||
|
||||
export interface FieldItem {
|
||||
type: FieldType;
|
||||
description?: string;
|
||||
optional?: boolean;
|
||||
default?: any;
|
||||
type: FieldType;
|
||||
description?: string;
|
||||
optional?: boolean;
|
||||
default?: any;
|
||||
}
|
||||
|
||||
interface UnwrappedZodType {
|
||||
baseType: z.ZodTypeAny;
|
||||
optional?: boolean;
|
||||
defaultValue?: any;
|
||||
description?: string;
|
||||
baseType: z.ZodTypeAny;
|
||||
optional?: boolean;
|
||||
defaultValue?: any;
|
||||
description?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the base type from wrapped Zod types like ZodOptional and ZodDefault.
|
||||
*/
|
||||
function unwrapZodType(field: z.ZodTypeAny): UnwrappedZodType {
|
||||
let optional = false;
|
||||
let defaultValue: any = undefined;
|
||||
let description: string | undefined = undefined;
|
||||
let optional = false;
|
||||
let defaultValue: any = undefined;
|
||||
let description: string | undefined = undefined;
|
||||
|
||||
description = field.description;
|
||||
description = field.description;
|
||||
|
||||
while (field instanceof z.ZodOptional || field instanceof z.ZodDefault) {
|
||||
if (field instanceof z.ZodOptional) optional = true;
|
||||
if (field instanceof z.ZodDefault) defaultValue = field._def.defaultValue();
|
||||
if (!description) description = field.description;
|
||||
while (field instanceof z.ZodOptional || field instanceof z.ZodDefault) {
|
||||
if (field instanceof z.ZodOptional) optional = true;
|
||||
if (field instanceof z.ZodDefault) defaultValue = field._def.defaultValue();
|
||||
if (!description) description = field.description;
|
||||
|
||||
field = field._def.innerType;
|
||||
field = field._def.innerType;
|
||||
}
|
||||
|
||||
const result: UnwrappedZodType = { baseType: field };
|
||||
|
||||
if (optional) result.optional = true;
|
||||
if (typeof defaultValue !== 'undefined') {
|
||||
if (
|
||||
typeof defaultValue === 'string' && defaultValue.length > 0 ||
|
||||
(typeof defaultValue === 'number') ||
|
||||
(typeof defaultValue === 'object' && Object.keys(defaultValue).length > 0) ||
|
||||
(Array.isArray(defaultValue) && defaultValue.length > 0)
|
||||
) {
|
||||
result.defaultValue = defaultValue;
|
||||
}
|
||||
|
||||
const result: UnwrappedZodType = { baseType: field };
|
||||
|
||||
if (optional) result.optional = true;
|
||||
if (typeof defaultValue !== 'undefined') {
|
||||
if (
|
||||
typeof defaultValue === 'string' && defaultValue.length > 0 ||
|
||||
(typeof defaultValue === 'number') ||
|
||||
(typeof defaultValue === 'object' && Object.keys(defaultValue).length > 0) ||
|
||||
(Array.isArray(defaultValue) && defaultValue.length > 0)
|
||||
) {
|
||||
result.defaultValue = defaultValue;
|
||||
}
|
||||
}
|
||||
if (description) result.description = description;
|
||||
return result;
|
||||
}
|
||||
if (description) result.description = description;
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -64,27 +64,27 @@ function unwrapZodType(field: z.ZodTypeAny): UnwrappedZodType {
|
|||
* Special-cases NIP-01 filters as `multi_string`.
|
||||
*/
|
||||
export function zodSchemaToFields(schema: z.ZodObject<any>): Record<string, FieldItem> {
|
||||
const result: Record<string, FieldItem> = {};
|
||||
const result: Record<string, FieldItem> = {};
|
||||
|
||||
for (const [key, field] of Object.entries(schema.shape) as [string, z.ZodTypeAny][]) {
|
||||
const { baseType, optional, defaultValue, description } = unwrapZodType(field);
|
||||
result[key] = { type: 'unknown' };
|
||||
if (optional) result[key].optional = optional;
|
||||
if (defaultValue) result[key].default = defaultValue;
|
||||
if (description) result[key].description = description;
|
||||
for (const [key, field] of Object.entries(schema.shape) as [string, z.ZodTypeAny][]) {
|
||||
const { baseType, optional, defaultValue, description } = unwrapZodType(field);
|
||||
result[key] = { type: 'unknown' };
|
||||
if (optional) result[key].optional = optional;
|
||||
if (defaultValue) result[key].default = defaultValue;
|
||||
if (description) result[key].description = description;
|
||||
|
||||
if (key === 'filters') {
|
||||
result[key].type = 'multi_string';
|
||||
} else if (baseType instanceof z.ZodArray) {
|
||||
const elementType = unwrapZodType(baseType._def.type).baseType._def.typeName;
|
||||
if (elementType === 'ZodNumber') result[key].type = 'multi_number';
|
||||
else result[key].type = 'multi_string';
|
||||
} else if (baseType instanceof z.ZodNumber) result[key].type = 'number';
|
||||
else if (baseType instanceof z.ZodBoolean) result[key].type = 'boolean';
|
||||
else if (baseType instanceof z.ZodString) result[key].type = 'string';
|
||||
if (key === 'filters') {
|
||||
result[key].type = 'multi_string';
|
||||
} else if (baseType instanceof z.ZodArray) {
|
||||
const elementType = unwrapZodType(baseType._def.type).baseType._def.typeName;
|
||||
if (elementType === 'ZodNumber') result[key].type = 'multi_number';
|
||||
else result[key].type = 'multi_string';
|
||||
} else if (baseType instanceof z.ZodNumber) result[key].type = 'number';
|
||||
else if (baseType instanceof z.ZodBoolean) result[key].type = 'boolean';
|
||||
else if (baseType instanceof z.ZodString) result[key].type = 'string';
|
||||
|
||||
if (baseType.description && !result[key].description) result[key].description = baseType.description;
|
||||
}
|
||||
if (baseType.description && !result[key].description) result[key].description = baseType.description;
|
||||
}
|
||||
|
||||
return result;
|
||||
return result;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,21 +17,21 @@ export const FiltersPolicyOptsSchema = z.object({
|
|||
filters: z.array(n.filter()),
|
||||
});
|
||||
|
||||
interface FiltersPolicyOpts extends z.TypeOf<typeof FiltersPolicyOptsSchema> { }
|
||||
interface FiltersPolicyOpts extends z.TypeOf<typeof FiltersPolicyOptsSchema> {}
|
||||
|
||||
/** Options for `HashtagPolicy`. */
|
||||
export const HashtagPolicyOptsSchema = z.object({
|
||||
hashtags: z.array(z.string()).describe('Banned hashtags (case-insensitive)'),
|
||||
});
|
||||
|
||||
export interface HashtagPolicyOpts extends z.TypeOf<typeof HashtagPolicyOptsSchema> { }
|
||||
export interface HashtagPolicyOpts extends z.TypeOf<typeof HashtagPolicyOptsSchema> {}
|
||||
|
||||
/** Options for `WhitelistPolicy`. */
|
||||
export const WhitelistPolicyOptsSchema = z.object({
|
||||
pubkeys: z.array(z.string()).describe('Allowed pubkeys'),
|
||||
});
|
||||
|
||||
export interface WhitelistPolicyOpts extends z.TypeOf<typeof WhitelistPolicyOptsSchema> { }
|
||||
export interface WhitelistPolicyOpts extends z.TypeOf<typeof WhitelistPolicyOptsSchema> {}
|
||||
|
||||
/** Options for `RegexPolicy`. */
|
||||
export const RegexPolicyOptsSchema = z.object({
|
||||
|
|
@ -48,7 +48,7 @@ export const KeywordPolicyOptsSchema = z.object({
|
|||
keywords: z.array(z.string()).describe('Banned keywords (case-insensitive)'),
|
||||
});
|
||||
|
||||
export interface KeywordPolicyOpts extends z.TypeOf<typeof KeywordPolicyOptsSchema> { }
|
||||
export interface KeywordPolicyOpts extends z.TypeOf<typeof KeywordPolicyOptsSchema> {}
|
||||
|
||||
/** Options for `DomainPolicy`. */
|
||||
export const DomainPolicyOptsSchema = z.object({
|
||||
|
|
@ -66,7 +66,7 @@ export const PubkeyBanPolicyOptsSchema = z.object({
|
|||
pubkeys: z.array(z.string()).describe('Banned pubkeys'),
|
||||
});
|
||||
|
||||
export interface PubkeyBanPolicyOpts extends z.TypeOf<typeof PubkeyBanPolicyOptsSchema> { }
|
||||
export interface PubkeyBanPolicyOpts extends z.TypeOf<typeof PubkeyBanPolicyOptsSchema> {}
|
||||
|
||||
/** Options for `OpenAIPolicy`. */
|
||||
export const OpenAIPolicyOptsSchema = z.object({
|
||||
|
|
@ -122,7 +122,7 @@ export const SizePolicyOptsSchema = z.object({
|
|||
maxBytes: z.number().default(8 * 1024).describe('Max allowed message size in bytes'),
|
||||
});
|
||||
|
||||
export interface SizePolicyOpts extends Partial<z.TypeOf<typeof SizePolicyOptsSchema>> { }
|
||||
export interface SizePolicyOpts extends Partial<z.TypeOf<typeof SizePolicyOptsSchema>> {}
|
||||
|
||||
/** Options for `AntiDuplicationPolicy`. */
|
||||
export const AntiDuplicationPolicyOptsSchema = z.object({
|
||||
|
|
@ -140,11 +140,11 @@ export const HellthreadPolicyOptsSchema = z.object({
|
|||
limit: z.number().default(100).describe('Maximum number of mentions to allow per post'),
|
||||
});
|
||||
|
||||
export interface HellthreadPolicyOpts extends Partial<z.TypeOf<typeof HellthreadPolicyOptsSchema>> { }
|
||||
export interface HellthreadPolicyOpts extends Partial<z.TypeOf<typeof HellthreadPolicyOptsSchema>> {}
|
||||
|
||||
/** Options for `PowPolicy`. */
|
||||
export const PowPolicyOptsSchema = z.object({
|
||||
difficulty: z.number().default(1).describe('Number of bits of proof-of-work to require'),
|
||||
});
|
||||
|
||||
export interface PowPolicyOpts extends Partial<z.TypeOf<typeof PowPolicyOptsSchema>> { }
|
||||
export interface PowPolicyOpts extends Partial<z.TypeOf<typeof PowPolicyOptsSchema>> {}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue