feat: optimize query path and add smoke test/demo assets

This commit is contained in:
2026-03-07 07:00:51 +00:00
parent 0ede080e85
commit 76d6a31d25
9 changed files with 709 additions and 10 deletions

View File

@@ -78,7 +78,12 @@ export class Yonexus {
if (this.registrars.size > 0 && !this.registrars.has(actor.agentId)) {
throw new YonexusError("REGISTRAR_DENIED", `registrar_denied: ${actor.agentId}`);
}
authorize("register_agent", actor, {}, this.store);
const isBootstrap = this.store.listAgents().length === 0 && actor.agentId === agentId;
if (!isBootstrap) {
authorize("register_agent", actor, {}, this.store);
}
if (this.store.findAgent(agentId)) {
throw new YonexusError("ALREADY_EXISTS", `agent_exists: ${agentId}`, { agentId });
}

View File

@@ -4,6 +4,25 @@ import type { Identity, QueryFilter, QueryInput, QueryOptions, YonexusSchema } f
const DEFAULT_LIMIT = 20;
const MAX_LIMIT = 100;
const regexCache = new Map<string, RegExp>();
const containsCache = new Map<string, string>();
function getRegex(pattern: string): RegExp {
const cached = regexCache.get(pattern);
if (cached) return cached;
const created = new RegExp(pattern);
regexCache.set(pattern, created);
return created;
}
function normalizeNeedle(value: string): string {
const cached = containsCache.get(value);
if (cached) return cached;
const normalized = value.toLowerCase();
containsCache.set(value, normalized);
return normalized;
}
function isQueryable(field: string, schema: YonexusSchema): boolean {
return Boolean(schema[field]?.queryable);
}
@@ -15,9 +34,9 @@ function matchFilter(identity: Identity, filter: QueryFilter): boolean {
case "eq":
return raw === filter.value;
case "contains":
return raw.toLowerCase().includes(filter.value.toLowerCase());
return raw.toLowerCase().includes(normalizeNeedle(filter.value));
case "regex": {
const re = new RegExp(filter.value);
const re = getRegex(filter.value);
return re.test(raw);
}
default:
@@ -31,6 +50,15 @@ function normalizeOptions(options?: QueryOptions): Required<QueryOptions> {
return { limit, offset };
}
function sortFilters(filters: QueryFilter[]): QueryFilter[] {
const weight = (f: QueryFilter): number => {
if (f.op === 'eq') return 1;
if (f.op === 'contains') return 2;
return 3;
};
return [...filters].sort((a, b) => weight(a) - weight(b));
}
export function queryIdentities(identities: Identity[], input: QueryInput, schema: YonexusSchema): Identity[] {
for (const filter of input.filters) {
if (!isQueryable(filter.field, schema)) {
@@ -40,7 +68,8 @@ export function queryIdentities(identities: Identity[], input: QueryInput, schem
}
}
const filtered = identities.filter((identity) => input.filters.every((f) => matchFilter(identity, f)));
const orderedFilters = sortFilters(input.filters);
const filtered = identities.filter((identity) => orderedFilters.every((f) => matchFilter(identity, f)));
const { limit, offset } = normalizeOptions(input.options);
return filtered.slice(offset, offset + limit);
}