@x12i/ai-tools 1.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 +214 -0
- package/dist/AiModelsCatalogClient-4RF5BCDL.cjs +9 -0
- package/dist/AiModelsCatalogClient-4RF5BCDL.cjs.map +1 -0
- package/dist/AiModelsCatalogClient-B-dNLXX0.d.ts +29 -0
- package/dist/AiModelsCatalogClient-CSVlKql5.d.cts +29 -0
- package/dist/AiModelsCatalogClient-NUF3CBLW.js +9 -0
- package/dist/AiModelsCatalogClient-NUF3CBLW.js.map +1 -0
- package/dist/aliases/index.cjs +11 -0
- package/dist/aliases/index.cjs.map +1 -0
- package/dist/aliases/index.d.cts +21 -0
- package/dist/aliases/index.d.ts +21 -0
- package/dist/aliases/index.js +11 -0
- package/dist/aliases/index.js.map +1 -0
- package/dist/catalox/index.cjs +21 -0
- package/dist/catalox/index.cjs.map +1 -0
- package/dist/catalox/index.d.cts +23 -0
- package/dist/catalox/index.d.ts +23 -0
- package/dist/catalox/index.js +21 -0
- package/dist/catalox/index.js.map +1 -0
- package/dist/chunk-2PYACSZ5.cjs +1 -0
- package/dist/chunk-2PYACSZ5.cjs.map +1 -0
- package/dist/chunk-3E67S427.cjs +1 -0
- package/dist/chunk-3E67S427.cjs.map +1 -0
- package/dist/chunk-4NAY6HRP.js +137 -0
- package/dist/chunk-4NAY6HRP.js.map +1 -0
- package/dist/chunk-5HNFAYTO.cjs +254 -0
- package/dist/chunk-5HNFAYTO.cjs.map +1 -0
- package/dist/chunk-6QGDZTGH.js +127 -0
- package/dist/chunk-6QGDZTGH.js.map +1 -0
- package/dist/chunk-7Q742NI3.cjs +106 -0
- package/dist/chunk-7Q742NI3.cjs.map +1 -0
- package/dist/chunk-AJEKEWWB.js +106 -0
- package/dist/chunk-AJEKEWWB.js.map +1 -0
- package/dist/chunk-AV6OE2YQ.cjs +127 -0
- package/dist/chunk-AV6OE2YQ.cjs.map +1 -0
- package/dist/chunk-COK34C6P.js +1 -0
- package/dist/chunk-COK34C6P.js.map +1 -0
- package/dist/chunk-DJ5SWJDY.js +729 -0
- package/dist/chunk-DJ5SWJDY.js.map +1 -0
- package/dist/chunk-F2F4UEFD.cjs +75 -0
- package/dist/chunk-F2F4UEFD.cjs.map +1 -0
- package/dist/chunk-G2G4KSC5.js +30 -0
- package/dist/chunk-G2G4KSC5.js.map +1 -0
- package/dist/chunk-HHNHWYTP.cjs +105 -0
- package/dist/chunk-HHNHWYTP.cjs.map +1 -0
- package/dist/chunk-HN6UAQAE.cjs +83 -0
- package/dist/chunk-HN6UAQAE.cjs.map +1 -0
- package/dist/chunk-KHODXGPV.js +1 -0
- package/dist/chunk-KHODXGPV.js.map +1 -0
- package/dist/chunk-KQOALKKX.js +75 -0
- package/dist/chunk-KQOALKKX.js.map +1 -0
- package/dist/chunk-LYOU7CA2.cjs +30 -0
- package/dist/chunk-LYOU7CA2.cjs.map +1 -0
- package/dist/chunk-ML2FRR4L.js +105 -0
- package/dist/chunk-ML2FRR4L.js.map +1 -0
- package/dist/chunk-MLRHYOCD.js +160 -0
- package/dist/chunk-MLRHYOCD.js.map +1 -0
- package/dist/chunk-O2A6OVEH.js +240 -0
- package/dist/chunk-O2A6OVEH.js.map +1 -0
- package/dist/chunk-ONA73BU6.cjs +160 -0
- package/dist/chunk-ONA73BU6.cjs.map +1 -0
- package/dist/chunk-QCRLKVB3.cjs +137 -0
- package/dist/chunk-QCRLKVB3.cjs.map +1 -0
- package/dist/chunk-QWAX7VQO.cjs +240 -0
- package/dist/chunk-QWAX7VQO.cjs.map +1 -0
- package/dist/chunk-TF4L2NEC.cjs +729 -0
- package/dist/chunk-TF4L2NEC.cjs.map +1 -0
- package/dist/chunk-XRBZQQQU.js +254 -0
- package/dist/chunk-XRBZQQQU.js.map +1 -0
- package/dist/chunk-YHO57D2V.js +83 -0
- package/dist/chunk-YHO57D2V.js.map +1 -0
- package/dist/cli/index.cjs +403 -0
- package/dist/cli/index.cjs.map +1 -0
- package/dist/cli/index.d.cts +1 -0
- package/dist/cli/index.d.ts +1 -0
- package/dist/cli/index.js +403 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cost/index.cjs +7 -0
- package/dist/cost/index.cjs.map +1 -0
- package/dist/cost/index.d.cts +52 -0
- package/dist/cost/index.d.ts +52 -0
- package/dist/cost/index.js +7 -0
- package/dist/cost/index.js.map +1 -0
- package/dist/index.cjs +104 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +58 -0
- package/dist/index.d.ts +58 -0
- package/dist/index.js +104 -0
- package/dist/index.js.map +1 -0
- package/dist/modelNameResolver-Bn8QnkSj.d.ts +80 -0
- package/dist/modelNameResolver-bZD-eBSJ.d.cts +80 -0
- package/dist/models/index.cjs +33 -0
- package/dist/models/index.cjs.map +1 -0
- package/dist/models/index.d.cts +75 -0
- package/dist/models/index.d.ts +75 -0
- package/dist/models/index.js +33 -0
- package/dist/models/index.js.map +1 -0
- package/dist/sync/index.cjs +38 -0
- package/dist/sync/index.cjs.map +1 -0
- package/dist/sync/index.d.cts +12 -0
- package/dist/sync/index.d.ts +12 -0
- package/dist/sync/index.js +38 -0
- package/dist/sync/index.js.map +1 -0
- package/dist/toolbox/index.cjs +7 -0
- package/dist/toolbox/index.cjs.map +1 -0
- package/dist/toolbox/index.d.cts +72 -0
- package/dist/toolbox/index.d.ts +72 -0
- package/dist/toolbox/index.js +7 -0
- package/dist/toolbox/index.js.map +1 -0
- package/dist/types-DdGB3YaA.d.cts +278 -0
- package/dist/types-DdGB3YaA.d.ts +278 -0
- package/package.json +115 -0
- package/schemas/aliases.json +28 -0
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
// src/catalox/modelDocId.ts
|
|
2
|
+
var CX = "cx~";
|
|
3
|
+
var MODEL_MARKER = "m~";
|
|
4
|
+
function encodeModelFirestoreDocId(modelId) {
|
|
5
|
+
if (!modelId.includes("/")) return modelId;
|
|
6
|
+
return `${CX}${MODEL_MARKER}${Buffer.from(modelId, "utf8").toString("base64url")}`;
|
|
7
|
+
}
|
|
8
|
+
function decodeModelFirestoreDocId(docId) {
|
|
9
|
+
const prefix = `${CX}${MODEL_MARKER}`;
|
|
10
|
+
if (docId.startsWith(prefix)) {
|
|
11
|
+
return Buffer.from(docId.slice(prefix.length), "base64url").toString("utf8");
|
|
12
|
+
}
|
|
13
|
+
return docId;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// src/catalox/upsertAiModelRecord.ts
|
|
17
|
+
import {
|
|
18
|
+
flatNativeItemsCollectionRef,
|
|
19
|
+
legacyNativeItemsCollectionRef,
|
|
20
|
+
resolveNativeItemsLayout
|
|
21
|
+
} from "@x12i/catalox/firebase";
|
|
22
|
+
function sanitizeForFirestore(value) {
|
|
23
|
+
return JSON.parse(JSON.stringify(value));
|
|
24
|
+
}
|
|
25
|
+
function buildIndexed(record) {
|
|
26
|
+
return {
|
|
27
|
+
modelId: record.modelId,
|
|
28
|
+
providerId: record.providerId,
|
|
29
|
+
name: record.name,
|
|
30
|
+
canonicalSlug: record.canonicalSlug,
|
|
31
|
+
contextLength: record.contextLength,
|
|
32
|
+
status: record.status,
|
|
33
|
+
primaryOutputModality: record.primaryOutputModality,
|
|
34
|
+
supportsTools: record.supportsTools,
|
|
35
|
+
supportsReasoning: record.supportsReasoning,
|
|
36
|
+
supportsStreaming: record.supportsStreaming,
|
|
37
|
+
isModerated: record.isModerated,
|
|
38
|
+
syncedAt: record.syncedAt
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
async function upsertAiModelRecord(options) {
|
|
42
|
+
const { record, catalogId, context, firestore } = options;
|
|
43
|
+
const appId = context.appId ?? "ai-tools";
|
|
44
|
+
const layout = await resolveNativeItemsLayout(firestore, catalogId);
|
|
45
|
+
const col = layout === "legacy" ? legacyNativeItemsCollectionRef(firestore, catalogId) : flatNativeItemsCollectionRef(firestore, catalogId);
|
|
46
|
+
const storageDocId = encodeModelFirestoreDocId(record.modelId);
|
|
47
|
+
const existing = await col.doc(storageDocId).get();
|
|
48
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
49
|
+
const data = sanitizeForFirestore(record);
|
|
50
|
+
const payload = sanitizeForFirestore({
|
|
51
|
+
itemId: record.modelId,
|
|
52
|
+
catalogId,
|
|
53
|
+
appScopedOwnerId: appId,
|
|
54
|
+
indexed: buildIndexed(record),
|
|
55
|
+
data,
|
|
56
|
+
metadata: {
|
|
57
|
+
createdAt: String(existing.data()?.metadata?.createdAt ?? now),
|
|
58
|
+
lastUpdate: now,
|
|
59
|
+
domainIds: [],
|
|
60
|
+
agentIds: []
|
|
61
|
+
},
|
|
62
|
+
version: (existing.data()?.version ?? 0) + 1
|
|
63
|
+
});
|
|
64
|
+
await col.doc(storageDocId).set(payload, { merge: true });
|
|
65
|
+
}
|
|
66
|
+
var BATCH_SIZE = 400;
|
|
67
|
+
async function batchUpsertAiModelRecords(firestore, catalogId, context, records) {
|
|
68
|
+
const layout = await resolveNativeItemsLayout(firestore, catalogId);
|
|
69
|
+
const col = layout === "legacy" ? legacyNativeItemsCollectionRef(firestore, catalogId) : flatNativeItemsCollectionRef(firestore, catalogId);
|
|
70
|
+
const appId = context.appId ?? "ai-tools";
|
|
71
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
72
|
+
for (let i = 0; i < records.length; i += BATCH_SIZE) {
|
|
73
|
+
const chunk = records.slice(i, i + BATCH_SIZE);
|
|
74
|
+
const batch = firestore.batch();
|
|
75
|
+
for (const record of chunk) {
|
|
76
|
+
const storageDocId = encodeModelFirestoreDocId(record.modelId);
|
|
77
|
+
const data = sanitizeForFirestore(record);
|
|
78
|
+
const payload = sanitizeForFirestore({
|
|
79
|
+
itemId: record.modelId,
|
|
80
|
+
catalogId,
|
|
81
|
+
appScopedOwnerId: appId,
|
|
82
|
+
indexed: buildIndexed(record),
|
|
83
|
+
data,
|
|
84
|
+
metadata: {
|
|
85
|
+
createdAt: now,
|
|
86
|
+
lastUpdate: now,
|
|
87
|
+
domainIds: [],
|
|
88
|
+
agentIds: []
|
|
89
|
+
},
|
|
90
|
+
version: 1
|
|
91
|
+
});
|
|
92
|
+
batch.set(col.doc(storageDocId), payload, { merge: true });
|
|
93
|
+
}
|
|
94
|
+
await batch.commit();
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export {
|
|
99
|
+
encodeModelFirestoreDocId,
|
|
100
|
+
decodeModelFirestoreDocId,
|
|
101
|
+
sanitizeForFirestore,
|
|
102
|
+
upsertAiModelRecord,
|
|
103
|
+
batchUpsertAiModelRecords
|
|
104
|
+
};
|
|
105
|
+
//# sourceMappingURL=chunk-ML2FRR4L.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/catalox/modelDocId.ts","../src/catalox/upsertAiModelRecord.ts"],"sourcesContent":["/**\n * Firestore document ids cannot contain `/`. OpenRouter model ids use `provider/model`.\n * We encode global item doc ids as `cx~m~<base64url(modelId)>` while keeping logical `modelId` in data.\n */\nconst CX = \"cx~\";\nconst MODEL_MARKER = \"m~\";\n\nexport function encodeModelFirestoreDocId(modelId: string): string {\n if (!modelId.includes(\"/\")) return modelId;\n return `${CX}${MODEL_MARKER}${Buffer.from(modelId, \"utf8\").toString(\"base64url\")}`;\n}\n\nexport function decodeModelFirestoreDocId(docId: string): string {\n const prefix = `${CX}${MODEL_MARKER}`;\n if (docId.startsWith(prefix)) {\n return Buffer.from(docId.slice(prefix.length), \"base64url\").toString(\"utf8\");\n }\n return docId;\n}\n\nexport function modelIdNeedsEncodedDocId(modelId: string): boolean {\n return modelId.includes(\"/\");\n}\n","import type { Firestore } from \"firebase-admin/firestore\";\nimport type { CataloxContext } from \"@x12i/catalox\";\nimport {\n flatNativeItemsCollectionRef,\n legacyNativeItemsCollectionRef,\n resolveNativeItemsLayout,\n} from \"@x12i/catalox/firebase\";\nimport type { AiModelRecord } from \"../models/types.js\";\nimport { encodeModelFirestoreDocId } from \"./modelDocId.js\";\n\n/** Firestore rejects `undefined` — strip before write. */\nexport function sanitizeForFirestore<T>(value: T): T {\n return JSON.parse(JSON.stringify(value)) as T;\n}\n\nfunction buildIndexed(record: AiModelRecord): Record<string, string | number | boolean> {\n return {\n modelId: record.modelId,\n providerId: record.providerId,\n name: record.name,\n canonicalSlug: record.canonicalSlug,\n contextLength: record.contextLength,\n status: record.status,\n primaryOutputModality: record.primaryOutputModality,\n supportsTools: record.supportsTools,\n supportsReasoning: record.supportsReasoning,\n supportsStreaming: record.supportsStreaming,\n isModerated: record.isModerated,\n syncedAt: record.syncedAt,\n };\n}\n\nexport type UpsertAiModelRecordOptions = {\n firestore: Firestore;\n context: CataloxContext;\n catalogId: string;\n record: AiModelRecord;\n};\n\n/**\n * Upserts one ai-models row via Firestore (safe doc ids for `provider/model` ids).\n */\nexport async function upsertAiModelRecord(options: UpsertAiModelRecordOptions): Promise<void> {\n const { record, catalogId, context, firestore } = options;\n const appId = context.appId ?? \"ai-tools\";\n\n const layout = await resolveNativeItemsLayout(firestore, catalogId);\n const col =\n layout === \"legacy\"\n ? legacyNativeItemsCollectionRef(firestore, catalogId)\n : flatNativeItemsCollectionRef(firestore, catalogId);\n\n const storageDocId = encodeModelFirestoreDocId(record.modelId);\n const existing = await col.doc(storageDocId).get();\n const now = new Date().toISOString();\n const data = sanitizeForFirestore(record);\n\n const payload = sanitizeForFirestore({\n itemId: record.modelId,\n catalogId,\n appScopedOwnerId: appId,\n indexed: buildIndexed(record),\n data,\n metadata: {\n createdAt: String(existing.data()?.metadata?.createdAt ?? now),\n lastUpdate: now,\n domainIds: [],\n agentIds: [],\n },\n version: (existing.data()?.version ?? 0) + 1,\n });\n\n await col.doc(storageDocId).set(payload, { merge: true });\n}\n\nconst BATCH_SIZE = 400;\n\nexport async function batchUpsertAiModelRecords(\n firestore: Firestore,\n catalogId: string,\n context: CataloxContext,\n records: AiModelRecord[],\n): Promise<void> {\n const layout = await resolveNativeItemsLayout(firestore, catalogId);\n const col =\n layout === \"legacy\"\n ? legacyNativeItemsCollectionRef(firestore, catalogId)\n : flatNativeItemsCollectionRef(firestore, catalogId);\n\n const appId = context.appId ?? \"ai-tools\";\n const now = new Date().toISOString();\n\n for (let i = 0; i < records.length; i += BATCH_SIZE) {\n const chunk = records.slice(i, i + BATCH_SIZE);\n const batch = firestore.batch();\n\n for (const record of chunk) {\n const storageDocId = encodeModelFirestoreDocId(record.modelId);\n const data = sanitizeForFirestore(record);\n const payload = sanitizeForFirestore({\n itemId: record.modelId,\n catalogId,\n appScopedOwnerId: appId,\n indexed: buildIndexed(record),\n data,\n metadata: {\n createdAt: now,\n lastUpdate: now,\n domainIds: [],\n agentIds: [],\n },\n version: 1,\n });\n batch.set(col.doc(storageDocId), payload, { merge: true });\n }\n\n await batch.commit();\n }\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
import {
|
|
2
|
+
batchUpsertAiModelRecords
|
|
3
|
+
} from "./chunk-ML2FRR4L.js";
|
|
4
|
+
import {
|
|
5
|
+
normalizeOpenRouterModel
|
|
6
|
+
} from "./chunk-6QGDZTGH.js";
|
|
7
|
+
import {
|
|
8
|
+
AI_MODELS_CATALOG_ID,
|
|
9
|
+
AI_MODELS_DESCRIPTOR,
|
|
10
|
+
AI_TOOLS_APP_ID,
|
|
11
|
+
invalidateModelsCache
|
|
12
|
+
} from "./chunk-DJ5SWJDY.js";
|
|
13
|
+
import {
|
|
14
|
+
AiToolsError,
|
|
15
|
+
SyncError
|
|
16
|
+
} from "./chunk-AJEKEWWB.js";
|
|
17
|
+
|
|
18
|
+
// src/catalog/ensureAiModelsCatalog.ts
|
|
19
|
+
async function ensureAiModelsCatalog(catalox, options = {}) {
|
|
20
|
+
const appId = options.appId ?? AI_TOOLS_APP_ID;
|
|
21
|
+
const catalogId = options.catalogId ?? AI_MODELS_CATALOG_ID;
|
|
22
|
+
const ctx = { appId, superAdmin: true };
|
|
23
|
+
try {
|
|
24
|
+
await catalox.ensureCatalog(ctx, {
|
|
25
|
+
catalogId,
|
|
26
|
+
name: AI_MODELS_DESCRIPTOR.label,
|
|
27
|
+
status: "active"
|
|
28
|
+
});
|
|
29
|
+
await catalox.bindCatalogToApp(ctx, {
|
|
30
|
+
appId,
|
|
31
|
+
catalogId,
|
|
32
|
+
access: { canRead: true, canWrite: true, canAdmin: true }
|
|
33
|
+
});
|
|
34
|
+
await catalox.upsertCatalogDescriptor(ctx, catalogId, {
|
|
35
|
+
descriptorVersion: "1.0.0",
|
|
36
|
+
descriptor: AI_MODELS_DESCRIPTOR
|
|
37
|
+
});
|
|
38
|
+
} catch (cause) {
|
|
39
|
+
throw new AiToolsError(
|
|
40
|
+
"CATALOG_BOOTSTRAP_FAILED",
|
|
41
|
+
`Failed to bootstrap catalog "${catalogId}" for app "${appId}".`,
|
|
42
|
+
cause
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// src/sync/OpenRouterSyncProvider.ts
|
|
48
|
+
function buildFetchHeaders(apiKey) {
|
|
49
|
+
const headers = { Accept: "application/json" };
|
|
50
|
+
if (apiKey?.trim()) headers.Authorization = `Bearer ${apiKey.trim()}`;
|
|
51
|
+
return headers;
|
|
52
|
+
}
|
|
53
|
+
function buildModelsUrl(baseUrl, query) {
|
|
54
|
+
const url = new URL(`${baseUrl.replace(/\/$/, "")}/models`);
|
|
55
|
+
const q = { output_modalities: "all", ...query };
|
|
56
|
+
for (const [key, value] of Object.entries(q)) {
|
|
57
|
+
if (value !== void 0 && value !== "") url.searchParams.set(key, value);
|
|
58
|
+
}
|
|
59
|
+
return url.toString();
|
|
60
|
+
}
|
|
61
|
+
var OpenRouterSyncProvider = class {
|
|
62
|
+
apiKey;
|
|
63
|
+
baseUrl;
|
|
64
|
+
query;
|
|
65
|
+
constructor(options = {}) {
|
|
66
|
+
this.apiKey = options.apiKey;
|
|
67
|
+
this.baseUrl = options.baseUrl ?? "https://openrouter.ai/api/v1";
|
|
68
|
+
this.query = options.query ?? { output_modalities: "all" };
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Fetches the full OpenRouter model catalog (public, no API key required).
|
|
72
|
+
* @see https://openrouter.ai/api/v1/models
|
|
73
|
+
*/
|
|
74
|
+
async fetchModels() {
|
|
75
|
+
const url = buildModelsUrl(this.baseUrl, this.query);
|
|
76
|
+
let response;
|
|
77
|
+
try {
|
|
78
|
+
response = await fetch(url, { headers: buildFetchHeaders(this.apiKey) });
|
|
79
|
+
} catch (cause) {
|
|
80
|
+
throw new SyncError("OPENROUTER_MODELS_FETCH_FAILED", `Failed to fetch OpenRouter models from ${url}`, cause);
|
|
81
|
+
}
|
|
82
|
+
if (response.status === 401 || response.status === 403) {
|
|
83
|
+
throw new SyncError(
|
|
84
|
+
"OPENROUTER_AUTH_FAILED",
|
|
85
|
+
this.apiKey ? "OpenRouter API key is invalid or unauthorized." : "OpenRouter returned unauthorized \u2014 remove OPENROUTER_API_KEY to use the public models endpoint."
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
if (!response.ok) {
|
|
89
|
+
const body = await response.text().catch(() => "");
|
|
90
|
+
throw new SyncError(
|
|
91
|
+
"OPENROUTER_MODELS_FETCH_FAILED",
|
|
92
|
+
`OpenRouter models fetch failed (${response.status}): ${body.slice(0, 200)}`
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
const json = await response.json();
|
|
96
|
+
const syncedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
97
|
+
return (json.data ?? []).map((row) => normalizeOpenRouterModel(row, syncedAt));
|
|
98
|
+
}
|
|
99
|
+
/** Build the URL used for the last fetch pattern (for debugging). */
|
|
100
|
+
getModelsUrl() {
|
|
101
|
+
return buildModelsUrl(this.baseUrl, this.query);
|
|
102
|
+
}
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
// src/sync/syncAiModelsCatalog.ts
|
|
106
|
+
async function syncAiModelsCatalog(options) {
|
|
107
|
+
const start = Date.now();
|
|
108
|
+
const appId = options.appId ?? AI_TOOLS_APP_ID;
|
|
109
|
+
const catalogId = options.catalogId ?? AI_MODELS_CATALOG_ID;
|
|
110
|
+
const ctx = { appId, superAdmin: true };
|
|
111
|
+
if (options.forceCache) {
|
|
112
|
+
invalidateModelsCache(appId);
|
|
113
|
+
}
|
|
114
|
+
await ensureAiModelsCatalog(options.catalox, { appId, catalogId });
|
|
115
|
+
const provider = new OpenRouterSyncProvider({
|
|
116
|
+
apiKey: options.openRouterApiKey,
|
|
117
|
+
query: options.openRouterQuery ?? { output_modalities: "all" }
|
|
118
|
+
});
|
|
119
|
+
let models;
|
|
120
|
+
try {
|
|
121
|
+
models = await provider.fetchModels();
|
|
122
|
+
} catch (error) {
|
|
123
|
+
if (error instanceof SyncError) throw error;
|
|
124
|
+
throw new SyncError("SYNC_FETCH_FAILED", "Failed to fetch models from OpenRouter.", error);
|
|
125
|
+
}
|
|
126
|
+
if (options.verbose) {
|
|
127
|
+
console.log(`[sync] fetched ${models.length} models from ${provider.getModelsUrl()}`);
|
|
128
|
+
}
|
|
129
|
+
if (options.dryRun) {
|
|
130
|
+
return {
|
|
131
|
+
fetched: models.length,
|
|
132
|
+
upserted: 0,
|
|
133
|
+
skipped: models.length,
|
|
134
|
+
errors: [],
|
|
135
|
+
durationMs: Date.now() - start
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
const errors = [];
|
|
139
|
+
try {
|
|
140
|
+
await batchUpsertAiModelRecords(options.firestore, catalogId, ctx, models);
|
|
141
|
+
} catch (cause) {
|
|
142
|
+
const message = cause instanceof Error ? cause.message : String(cause);
|
|
143
|
+
throw new SyncError("SYNC_UPSERT_FAILED", `Batch upsert failed: ${message}`, cause);
|
|
144
|
+
}
|
|
145
|
+
invalidateModelsCache(appId);
|
|
146
|
+
return {
|
|
147
|
+
fetched: models.length,
|
|
148
|
+
upserted: models.length,
|
|
149
|
+
skipped: 0,
|
|
150
|
+
errors,
|
|
151
|
+
durationMs: Date.now() - start
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
export {
|
|
156
|
+
ensureAiModelsCatalog,
|
|
157
|
+
OpenRouterSyncProvider,
|
|
158
|
+
syncAiModelsCatalog
|
|
159
|
+
};
|
|
160
|
+
//# sourceMappingURL=chunk-MLRHYOCD.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/catalog/ensureAiModelsCatalog.ts","../src/sync/OpenRouterSyncProvider.ts","../src/sync/syncAiModelsCatalog.ts"],"sourcesContent":["import type { Catalox, CataloxContext } from \"@x12i/catalox\";\nimport { AiToolsError } from \"../errors.js\";\nimport {\n AI_MODELS_CATALOG_ID,\n AI_MODELS_DESCRIPTOR,\n AI_TOOLS_APP_ID,\n} from \"./aiModelsCatalogDescriptor.js\";\n\nexport type EnsureAiModelsCatalogOptions = {\n appId?: string;\n catalogId?: string;\n};\n\nexport async function ensureAiModelsCatalog(\n catalox: Catalox,\n options: EnsureAiModelsCatalogOptions = {},\n): Promise<void> {\n const appId = options.appId ?? AI_TOOLS_APP_ID;\n const catalogId = options.catalogId ?? AI_MODELS_CATALOG_ID;\n\n const ctx: CataloxContext = { appId, superAdmin: true };\n\n try {\n await catalox.ensureCatalog(ctx, {\n catalogId,\n name: AI_MODELS_DESCRIPTOR.label,\n status: \"active\",\n });\n\n await catalox.bindCatalogToApp(ctx, {\n appId,\n catalogId,\n access: { canRead: true, canWrite: true, canAdmin: true },\n });\n\n await catalox.upsertCatalogDescriptor(ctx, catalogId, {\n descriptorVersion: \"1.0.0\",\n descriptor: AI_MODELS_DESCRIPTOR,\n });\n } catch (cause) {\n throw new AiToolsError(\n \"CATALOG_BOOTSTRAP_FAILED\",\n `Failed to bootstrap catalog \"${catalogId}\" for app \"${appId}\".`,\n cause,\n );\n }\n}\n","import { SyncError } from \"../errors.js\";\nimport { normalizeOpenRouterModel } from \"../models/normalizeOpenRouterModel.js\";\nimport type { AiModelRecord } from \"../models/types.js\";\nimport type {\n OpenRouterModelsQuery,\n OpenRouterModelsResponse,\n} from \"../models/openrouter.types.js\";\n\nexport type OpenRouterSyncProviderOptions = {\n /** Optional — public GET /models needs no key. */\n apiKey?: string;\n baseUrl?: string;\n /** Query params passed to OpenRouter (default: all modalities). */\n query?: OpenRouterModelsQuery;\n};\n\nfunction buildFetchHeaders(apiKey?: string): Record<string, string> {\n const headers: Record<string, string> = { Accept: \"application/json\" };\n if (apiKey?.trim()) headers.Authorization = `Bearer ${apiKey.trim()}`;\n return headers;\n}\n\nfunction buildModelsUrl(baseUrl: string, query?: OpenRouterModelsQuery): string {\n const url = new URL(`${baseUrl.replace(/\\/$/, \"\")}/models`);\n const q = { output_modalities: \"all\", ...query };\n for (const [key, value] of Object.entries(q)) {\n if (value !== undefined && value !== \"\") url.searchParams.set(key, value);\n }\n return url.toString();\n}\n\nexport class OpenRouterSyncProvider {\n private readonly apiKey?: string;\n private readonly baseUrl: string;\n private readonly query?: OpenRouterModelsQuery;\n\n constructor(options: OpenRouterSyncProviderOptions = {}) {\n this.apiKey = options.apiKey;\n this.baseUrl = options.baseUrl ?? \"https://openrouter.ai/api/v1\";\n this.query = options.query ?? { output_modalities: \"all\" };\n }\n\n /**\n * Fetches the full OpenRouter model catalog (public, no API key required).\n * @see https://openrouter.ai/api/v1/models\n */\n async fetchModels(): Promise<AiModelRecord[]> {\n const url = buildModelsUrl(this.baseUrl, this.query);\n let response: Response;\n\n try {\n response = await fetch(url, { headers: buildFetchHeaders(this.apiKey) });\n } catch (cause) {\n throw new SyncError(\"OPENROUTER_MODELS_FETCH_FAILED\", `Failed to fetch OpenRouter models from ${url}`, cause);\n }\n\n if (response.status === 401 || response.status === 403) {\n throw new SyncError(\n \"OPENROUTER_AUTH_FAILED\",\n this.apiKey\n ? \"OpenRouter API key is invalid or unauthorized.\"\n : \"OpenRouter returned unauthorized — remove OPENROUTER_API_KEY to use the public models endpoint.\",\n );\n }\n\n if (!response.ok) {\n const body = await response.text().catch(() => \"\");\n throw new SyncError(\n \"OPENROUTER_MODELS_FETCH_FAILED\",\n `OpenRouter models fetch failed (${response.status}): ${body.slice(0, 200)}`,\n );\n }\n\n const json = (await response.json()) as OpenRouterModelsResponse;\n const syncedAt = new Date().toISOString();\n return (json.data ?? []).map((row) => normalizeOpenRouterModel(row, syncedAt));\n }\n\n /** Build the URL used for the last fetch pattern (for debugging). */\n getModelsUrl(): string {\n return buildModelsUrl(this.baseUrl, this.query);\n }\n}\n","import type { Catalox, CataloxContext } from \"@x12i/catalox\";\nimport type { Firestore } from \"firebase-admin/firestore\";\nimport { ensureAiModelsCatalog } from \"../catalog/ensureAiModelsCatalog.js\";\nimport { AI_MODELS_CATALOG_ID, AI_TOOLS_APP_ID } from \"../catalog/aiModelsCatalogDescriptor.js\";\nimport { invalidateModelsCache } from \"../cache/modelCache.js\";\nimport { batchUpsertAiModelRecords } from \"../catalox/upsertAiModelRecord.js\";\nimport { SyncError } from \"../errors.js\";\nimport type { AiModelRecord } from \"../models/types.js\";\nimport type { OpenRouterModelsQuery } from \"../models/openrouter.types.js\";\nimport { OpenRouterSyncProvider } from \"./OpenRouterSyncProvider.js\";\n\nexport type SyncOptions = {\n catalox: Catalox;\n firestore: Firestore;\n openRouterApiKey?: string;\n openRouterQuery?: OpenRouterModelsQuery;\n appId?: string;\n catalogId?: string;\n dryRun?: boolean;\n verbose?: boolean;\n forceCache?: boolean;\n};\n\nexport type SyncResult = {\n fetched: number;\n upserted: number;\n skipped: number;\n errors: Array<{ modelId: string; error: string }>;\n durationMs: number;\n};\n\nexport async function syncAiModelsCatalog(options: SyncOptions): Promise<SyncResult> {\n const start = Date.now();\n const appId = options.appId ?? AI_TOOLS_APP_ID;\n const catalogId = options.catalogId ?? AI_MODELS_CATALOG_ID;\n const ctx: CataloxContext = { appId, superAdmin: true };\n\n if (options.forceCache) {\n invalidateModelsCache(appId);\n }\n\n await ensureAiModelsCatalog(options.catalox, { appId, catalogId });\n\n const provider = new OpenRouterSyncProvider({\n apiKey: options.openRouterApiKey,\n query: options.openRouterQuery ?? { output_modalities: \"all\" },\n });\n\n let models: AiModelRecord[];\n try {\n models = await provider.fetchModels();\n } catch (error) {\n if (error instanceof SyncError) throw error;\n throw new SyncError(\"SYNC_FETCH_FAILED\", \"Failed to fetch models from OpenRouter.\", error);\n }\n\n if (options.verbose) {\n console.log(`[sync] fetched ${models.length} models from ${provider.getModelsUrl()}`);\n }\n\n if (options.dryRun) {\n return {\n fetched: models.length,\n upserted: 0,\n skipped: models.length,\n errors: [],\n durationMs: Date.now() - start,\n };\n }\n\n const errors: SyncResult[\"errors\"] = [];\n try {\n await batchUpsertAiModelRecords(options.firestore, catalogId, ctx, models);\n } catch (cause) {\n const message = cause instanceof Error ? cause.message : String(cause);\n throw new SyncError(\"SYNC_UPSERT_FAILED\", `Batch upsert failed: ${message}`, cause);\n }\n\n invalidateModelsCache(appId);\n\n return {\n fetched: models.length,\n upserted: models.length,\n skipped: 0,\n errors,\n durationMs: Date.now() - start,\n };\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
import {
|
|
2
|
+
AliasConflictError,
|
|
3
|
+
AliasFileParseError,
|
|
4
|
+
AliasFileWriteError,
|
|
5
|
+
AliasInvalidNameError,
|
|
6
|
+
AliasNotFoundError
|
|
7
|
+
} from "./chunk-AJEKEWWB.js";
|
|
8
|
+
|
|
9
|
+
// src/aliases/AliasRegistry.ts
|
|
10
|
+
import fs from "fs";
|
|
11
|
+
import path from "path";
|
|
12
|
+
import { z } from "zod";
|
|
13
|
+
var ALIAS_NAME_RE = /^[a-z0-9][a-z0-9-]*$/;
|
|
14
|
+
var aliasEntrySchema = z.object({
|
|
15
|
+
modelId: z.string().min(1),
|
|
16
|
+
provider: z.string().min(1),
|
|
17
|
+
description: z.string().optional(),
|
|
18
|
+
tags: z.array(z.string()).optional(),
|
|
19
|
+
addedAt: z.string(),
|
|
20
|
+
updatedAt: z.string()
|
|
21
|
+
});
|
|
22
|
+
var aliasFileSchema = z.object({
|
|
23
|
+
$schema: z.string().optional(),
|
|
24
|
+
version: z.literal(1),
|
|
25
|
+
updatedAt: z.string(),
|
|
26
|
+
aliases: z.record(aliasEntrySchema)
|
|
27
|
+
});
|
|
28
|
+
function defaultAliasesPath() {
|
|
29
|
+
if (process.env.AI_TOOLS_ALIASES_PATH) {
|
|
30
|
+
return path.resolve(process.env.AI_TOOLS_ALIASES_PATH);
|
|
31
|
+
}
|
|
32
|
+
return path.resolve(process.cwd(), "ai-tools/aliases.json");
|
|
33
|
+
}
|
|
34
|
+
function emptySchema() {
|
|
35
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
36
|
+
return {
|
|
37
|
+
$schema: "https://unpkg.com/@x12i/ai-tools/schemas/aliases.json",
|
|
38
|
+
version: 1,
|
|
39
|
+
updatedAt: now,
|
|
40
|
+
aliases: {}
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
var AliasRegistry = class {
|
|
44
|
+
aliasesPath;
|
|
45
|
+
constructor(options = {}) {
|
|
46
|
+
this.aliasesPath = options.aliasesPath ?? defaultAliasesPath();
|
|
47
|
+
}
|
|
48
|
+
get path() {
|
|
49
|
+
return this.aliasesPath;
|
|
50
|
+
}
|
|
51
|
+
exists() {
|
|
52
|
+
return fs.existsSync(this.aliasesPath);
|
|
53
|
+
}
|
|
54
|
+
init() {
|
|
55
|
+
if (this.exists()) return;
|
|
56
|
+
fs.mkdirSync(path.dirname(this.aliasesPath), { recursive: true });
|
|
57
|
+
this.writeFile(emptySchema());
|
|
58
|
+
}
|
|
59
|
+
load() {
|
|
60
|
+
if (!this.exists()) return emptySchema();
|
|
61
|
+
let raw;
|
|
62
|
+
try {
|
|
63
|
+
raw = fs.readFileSync(this.aliasesPath, "utf8");
|
|
64
|
+
} catch (cause) {
|
|
65
|
+
throw new AliasFileParseError(this.aliasesPath, cause);
|
|
66
|
+
}
|
|
67
|
+
let parsed;
|
|
68
|
+
try {
|
|
69
|
+
parsed = JSON.parse(raw);
|
|
70
|
+
} catch (cause) {
|
|
71
|
+
throw new AliasFileParseError(this.aliasesPath, cause);
|
|
72
|
+
}
|
|
73
|
+
const result = aliasFileSchema.safeParse(parsed);
|
|
74
|
+
if (!result.success) {
|
|
75
|
+
throw new AliasFileParseError(this.aliasesPath, result.error);
|
|
76
|
+
}
|
|
77
|
+
return result.data;
|
|
78
|
+
}
|
|
79
|
+
get(aliasName) {
|
|
80
|
+
const schema = this.load();
|
|
81
|
+
return schema.aliases[aliasName] ?? null;
|
|
82
|
+
}
|
|
83
|
+
list(filter) {
|
|
84
|
+
const schema = this.load();
|
|
85
|
+
return Object.entries(schema.aliases).filter(([, entry]) => !filter?.tag || (entry.tags ?? []).includes(filter.tag)).map(([name, entry]) => ({ name, ...entry }));
|
|
86
|
+
}
|
|
87
|
+
set(aliasName, entry) {
|
|
88
|
+
if (!ALIAS_NAME_RE.test(aliasName)) {
|
|
89
|
+
throw new AliasInvalidNameError(aliasName);
|
|
90
|
+
}
|
|
91
|
+
if (!this.exists()) this.init();
|
|
92
|
+
const schema = this.load();
|
|
93
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
94
|
+
const existing = schema.aliases[aliasName];
|
|
95
|
+
const full = {
|
|
96
|
+
...entry,
|
|
97
|
+
addedAt: existing?.addedAt ?? now,
|
|
98
|
+
updatedAt: now
|
|
99
|
+
};
|
|
100
|
+
schema.aliases[aliasName] = full;
|
|
101
|
+
schema.updatedAt = now;
|
|
102
|
+
this.writeFile(schema);
|
|
103
|
+
return full;
|
|
104
|
+
}
|
|
105
|
+
remove(aliasName) {
|
|
106
|
+
if (!this.exists()) return false;
|
|
107
|
+
const schema = this.load();
|
|
108
|
+
if (!schema.aliases[aliasName]) return false;
|
|
109
|
+
delete schema.aliases[aliasName];
|
|
110
|
+
schema.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
111
|
+
this.writeFile(schema);
|
|
112
|
+
return true;
|
|
113
|
+
}
|
|
114
|
+
rename(from, to, options) {
|
|
115
|
+
if (!ALIAS_NAME_RE.test(to)) {
|
|
116
|
+
throw new AliasInvalidNameError(to);
|
|
117
|
+
}
|
|
118
|
+
const schema = this.load();
|
|
119
|
+
const entry = schema.aliases[from];
|
|
120
|
+
if (!entry) {
|
|
121
|
+
throw new AliasNotFoundError(from);
|
|
122
|
+
}
|
|
123
|
+
if (schema.aliases[to] && !options?.force) {
|
|
124
|
+
throw new AliasConflictError(to);
|
|
125
|
+
}
|
|
126
|
+
delete schema.aliases[from];
|
|
127
|
+
entry.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
128
|
+
schema.aliases[to] = entry;
|
|
129
|
+
schema.updatedAt = entry.updatedAt;
|
|
130
|
+
this.writeFile(schema);
|
|
131
|
+
}
|
|
132
|
+
writeFile(schema) {
|
|
133
|
+
const tmp = `${this.aliasesPath}.tmp`;
|
|
134
|
+
try {
|
|
135
|
+
fs.mkdirSync(path.dirname(this.aliasesPath), { recursive: true });
|
|
136
|
+
fs.writeFileSync(tmp, JSON.stringify(schema, null, 2), "utf8");
|
|
137
|
+
fs.renameSync(tmp, this.aliasesPath);
|
|
138
|
+
} catch (cause) {
|
|
139
|
+
throw new AliasFileWriteError(this.aliasesPath, cause);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
// src/aliases/AliasResolver.ts
|
|
145
|
+
var ALIAS_NAME_RE2 = /^[a-z0-9][a-z0-9-]*$/;
|
|
146
|
+
var AliasResolver = class {
|
|
147
|
+
registry;
|
|
148
|
+
catalogClient;
|
|
149
|
+
constructor(options) {
|
|
150
|
+
this.registry = options.registry;
|
|
151
|
+
this.catalogClient = options.catalogClient;
|
|
152
|
+
}
|
|
153
|
+
async getModel(aliasName) {
|
|
154
|
+
const entry = this.registry.get(aliasName);
|
|
155
|
+
if (!entry) {
|
|
156
|
+
throw new AliasNotFoundError(aliasName);
|
|
157
|
+
}
|
|
158
|
+
return this.resolveEntry(aliasName, entry);
|
|
159
|
+
}
|
|
160
|
+
async getModels(aliasNames) {
|
|
161
|
+
const results = [];
|
|
162
|
+
for (const name of aliasNames) {
|
|
163
|
+
const entry = this.registry.get(name);
|
|
164
|
+
if (!entry) {
|
|
165
|
+
console.warn(`[ai-tools] Unknown alias "${name}" \u2014 skipped.`);
|
|
166
|
+
continue;
|
|
167
|
+
}
|
|
168
|
+
results.push(await this.resolveEntry(name, entry));
|
|
169
|
+
}
|
|
170
|
+
return results;
|
|
171
|
+
}
|
|
172
|
+
async getAllResolved() {
|
|
173
|
+
const list = this.registry.list();
|
|
174
|
+
return Promise.all(list.map(({ name, ...entry }) => this.resolveEntry(name, entry)));
|
|
175
|
+
}
|
|
176
|
+
async validate() {
|
|
177
|
+
const list = this.registry.list();
|
|
178
|
+
const entries = [];
|
|
179
|
+
let ok = 0;
|
|
180
|
+
let unknown = 0;
|
|
181
|
+
let broken = 0;
|
|
182
|
+
for (const { name, modelId } of list) {
|
|
183
|
+
if (!ALIAS_NAME_RE2.test(name) || !modelId) {
|
|
184
|
+
broken++;
|
|
185
|
+
entries.push({
|
|
186
|
+
name,
|
|
187
|
+
status: "broken",
|
|
188
|
+
modelId: modelId ?? "",
|
|
189
|
+
issue: "Invalid alias name or empty modelId"
|
|
190
|
+
});
|
|
191
|
+
continue;
|
|
192
|
+
}
|
|
193
|
+
const ref = await this.resolveEntry(name, this.registry.get(name));
|
|
194
|
+
if (ref.modelRecord) {
|
|
195
|
+
ok++;
|
|
196
|
+
entries.push({
|
|
197
|
+
name,
|
|
198
|
+
status: "ok",
|
|
199
|
+
modelId: ref.modelId,
|
|
200
|
+
resolvedName: ref.name
|
|
201
|
+
});
|
|
202
|
+
} else {
|
|
203
|
+
unknown++;
|
|
204
|
+
entries.push({
|
|
205
|
+
name,
|
|
206
|
+
status: "unknown",
|
|
207
|
+
modelId: ref.modelId,
|
|
208
|
+
issue: "Model not found in catalog"
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
return {
|
|
213
|
+
total: list.length,
|
|
214
|
+
ok,
|
|
215
|
+
unknown,
|
|
216
|
+
broken,
|
|
217
|
+
entries
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
async resolveEntry(alias, entry) {
|
|
221
|
+
const result = await this.catalogClient.resolveModel({
|
|
222
|
+
model: entry.modelId,
|
|
223
|
+
provider: entry.provider
|
|
224
|
+
});
|
|
225
|
+
return {
|
|
226
|
+
alias,
|
|
227
|
+
entry,
|
|
228
|
+
modelRecord: result.found ? result.record : null,
|
|
229
|
+
modelId: result.found ? result.modelId : entry.modelId,
|
|
230
|
+
provider: entry.provider,
|
|
231
|
+
name: result.record?.name ?? entry.modelId
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
};
|
|
235
|
+
|
|
236
|
+
export {
|
|
237
|
+
AliasRegistry,
|
|
238
|
+
AliasResolver
|
|
239
|
+
};
|
|
240
|
+
//# sourceMappingURL=chunk-O2A6OVEH.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/aliases/AliasRegistry.ts","../src/aliases/AliasResolver.ts"],"sourcesContent":["import fs from \"node:fs\";\nimport path from \"node:path\";\nimport { z } from \"zod\";\nimport {\n AliasConflictError,\n AliasFileParseError,\n AliasFileWriteError,\n AliasInvalidNameError,\n AliasNotFoundError,\n} from \"../errors.js\";\nimport type { AliasEntry, AliasFileSchema } from \"./types.js\";\n\nconst ALIAS_NAME_RE = /^[a-z0-9][a-z0-9-]*$/;\n\nconst aliasEntrySchema = z.object({\n modelId: z.string().min(1),\n provider: z.string().min(1),\n description: z.string().optional(),\n tags: z.array(z.string()).optional(),\n addedAt: z.string(),\n updatedAt: z.string(),\n});\n\nconst aliasFileSchema = z.object({\n $schema: z.string().optional(),\n version: z.literal(1),\n updatedAt: z.string(),\n aliases: z.record(aliasEntrySchema),\n});\n\nexport type AliasRegistryOptions = {\n aliasesPath?: string;\n};\n\nfunction defaultAliasesPath(): string {\n if (process.env.AI_TOOLS_ALIASES_PATH) {\n return path.resolve(process.env.AI_TOOLS_ALIASES_PATH);\n }\n return path.resolve(process.cwd(), \"ai-tools/aliases.json\");\n}\n\nfunction emptySchema(): AliasFileSchema {\n const now = new Date().toISOString();\n return {\n $schema: \"https://unpkg.com/@x12i/ai-tools/schemas/aliases.json\",\n version: 1,\n updatedAt: now,\n aliases: {},\n };\n}\n\nexport class AliasRegistry {\n private readonly aliasesPath: string;\n\n constructor(options: AliasRegistryOptions = {}) {\n this.aliasesPath = options.aliasesPath ?? defaultAliasesPath();\n }\n\n get path(): string {\n return this.aliasesPath;\n }\n\n exists(): boolean {\n return fs.existsSync(this.aliasesPath);\n }\n\n init(): void {\n if (this.exists()) return;\n fs.mkdirSync(path.dirname(this.aliasesPath), { recursive: true });\n this.writeFile(emptySchema());\n }\n\n load(): AliasFileSchema {\n if (!this.exists()) return emptySchema();\n\n let raw: string;\n try {\n raw = fs.readFileSync(this.aliasesPath, \"utf8\");\n } catch (cause) {\n throw new AliasFileParseError(this.aliasesPath, cause);\n }\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch (cause) {\n throw new AliasFileParseError(this.aliasesPath, cause);\n }\n\n const result = aliasFileSchema.safeParse(parsed);\n if (!result.success) {\n throw new AliasFileParseError(this.aliasesPath, result.error);\n }\n\n return result.data;\n }\n\n get(aliasName: string): AliasEntry | null {\n const schema = this.load();\n return schema.aliases[aliasName] ?? null;\n }\n\n list(filter?: { tag?: string }): Array<{ name: string } & AliasEntry> {\n const schema = this.load();\n return Object.entries(schema.aliases)\n .filter(([, entry]) => !filter?.tag || (entry.tags ?? []).includes(filter.tag))\n .map(([name, entry]) => ({ name, ...entry }));\n }\n\n set(\n aliasName: string,\n entry: Omit<AliasEntry, \"addedAt\" | \"updatedAt\">,\n ): AliasEntry {\n if (!ALIAS_NAME_RE.test(aliasName)) {\n throw new AliasInvalidNameError(aliasName);\n }\n\n if (!this.exists()) this.init();\n\n const schema = this.load();\n const now = new Date().toISOString();\n const existing = schema.aliases[aliasName];\n\n const full: AliasEntry = {\n ...entry,\n addedAt: existing?.addedAt ?? now,\n updatedAt: now,\n };\n\n schema.aliases[aliasName] = full;\n schema.updatedAt = now;\n this.writeFile(schema);\n return full;\n }\n\n remove(aliasName: string): boolean {\n if (!this.exists()) return false;\n const schema = this.load();\n if (!schema.aliases[aliasName]) return false;\n delete schema.aliases[aliasName];\n schema.updatedAt = new Date().toISOString();\n this.writeFile(schema);\n return true;\n }\n\n rename(from: string, to: string, options?: { force?: boolean }): void {\n if (!ALIAS_NAME_RE.test(to)) {\n throw new AliasInvalidNameError(to);\n }\n\n const schema = this.load();\n const entry = schema.aliases[from];\n if (!entry) {\n throw new AliasNotFoundError(from);\n }\n if (schema.aliases[to] && !options?.force) {\n throw new AliasConflictError(to);\n }\n\n delete schema.aliases[from];\n entry.updatedAt = new Date().toISOString();\n schema.aliases[to] = entry;\n schema.updatedAt = entry.updatedAt;\n this.writeFile(schema);\n }\n\n private writeFile(schema: AliasFileSchema): void {\n const tmp = `${this.aliasesPath}.tmp`;\n try {\n fs.mkdirSync(path.dirname(this.aliasesPath), { recursive: true });\n fs.writeFileSync(tmp, JSON.stringify(schema, null, 2), \"utf8\");\n fs.renameSync(tmp, this.aliasesPath);\n } catch (cause) {\n throw new AliasFileWriteError(this.aliasesPath, cause);\n }\n }\n}\n","import { AliasNotFoundError } from \"../errors.js\";\nimport type { AiModelsCatalogClient } from \"../catalox/AiModelsCatalogClient.js\";\nimport type { AliasRegistry } from \"./AliasRegistry.js\";\nimport type { AliasValidationReport, ResolvedModelRef } from \"./types.js\";\n\nconst ALIAS_NAME_RE = /^[a-z0-9][a-z0-9-]*$/;\n\nexport type AliasResolverOptions = {\n registry: AliasRegistry;\n catalogClient: AiModelsCatalogClient;\n};\n\nexport class AliasResolver {\n private readonly registry: AliasRegistry;\n private readonly catalogClient: AiModelsCatalogClient;\n\n constructor(options: AliasResolverOptions) {\n this.registry = options.registry;\n this.catalogClient = options.catalogClient;\n }\n\n async getModel(aliasName: string): Promise<ResolvedModelRef> {\n const entry = this.registry.get(aliasName);\n if (!entry) {\n throw new AliasNotFoundError(aliasName);\n }\n return this.resolveEntry(aliasName, entry);\n }\n\n async getModels(aliasNames: string[]): Promise<ResolvedModelRef[]> {\n const results: ResolvedModelRef[] = [];\n for (const name of aliasNames) {\n const entry = this.registry.get(name);\n if (!entry) {\n console.warn(`[ai-tools] Unknown alias \"${name}\" — skipped.`);\n continue;\n }\n results.push(await this.resolveEntry(name, entry));\n }\n return results;\n }\n\n async getAllResolved(): Promise<ResolvedModelRef[]> {\n const list = this.registry.list();\n return Promise.all(list.map(({ name, ...entry }) => this.resolveEntry(name, entry)));\n }\n\n async validate(): Promise<AliasValidationReport> {\n const list = this.registry.list();\n const entries: AliasValidationReport[\"entries\"] = [];\n let ok = 0;\n let unknown = 0;\n let broken = 0;\n\n for (const { name, modelId } of list) {\n if (!ALIAS_NAME_RE.test(name) || !modelId) {\n broken++;\n entries.push({\n name,\n status: \"broken\",\n modelId: modelId ?? \"\",\n issue: \"Invalid alias name or empty modelId\",\n });\n continue;\n }\n\n const ref = await this.resolveEntry(name, this.registry.get(name)!);\n if (ref.modelRecord) {\n ok++;\n entries.push({\n name,\n status: \"ok\",\n modelId: ref.modelId,\n resolvedName: ref.name,\n });\n } else {\n unknown++;\n entries.push({\n name,\n status: \"unknown\",\n modelId: ref.modelId,\n issue: \"Model not found in catalog\",\n });\n }\n }\n\n return {\n total: list.length,\n ok,\n unknown,\n broken,\n entries,\n };\n }\n\n private async resolveEntry(\n alias: string,\n entry: import(\"./types.js\").AliasEntry,\n ): Promise<ResolvedModelRef> {\n const result = await this.catalogClient.resolveModel({\n model: entry.modelId,\n provider: entry.provider,\n });\n\n return {\n alias,\n entry,\n modelRecord: result.found ? result.record : null,\n modelId: result.found ? result.modelId : entry.modelId,\n provider: entry.provider,\n name: result.record?.name ?? entry.modelId,\n };\n }\n}\n"],"mappings":"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","names":["ALIAS_NAME_RE"]}
|