@x12i/ai-tools 1.0.2 → 1.0.3
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 +114 -12
- package/dist/{AiModelsCatalogClient-CSVlKql5.d.cts → AiModelsCatalogClient-CNeqFiFs.d.cts} +2 -1
- package/dist/{AiModelsCatalogClient-B-dNLXX0.d.ts → AiModelsCatalogClient-nwFoEaqL.d.ts} +2 -1
- package/dist/aliases/index.d.cts +4 -3
- package/dist/aliases/index.d.ts +4 -3
- package/dist/catalog/index.cjs +30 -0
- package/dist/catalog/index.cjs.map +1 -0
- package/dist/catalog/index.d.cts +100 -0
- package/dist/catalog/index.d.ts +100 -0
- package/dist/catalog/index.js +30 -0
- package/dist/catalog/index.js.map +1 -0
- package/dist/catalox/index.cjs +2 -2
- package/dist/catalox/index.d.cts +7 -19
- package/dist/catalox/index.d.ts +7 -19
- package/dist/catalox/index.js +1 -1
- package/dist/chunk-C3H7RTFR.cjs +1 -0
- package/dist/chunk-C3H7RTFR.cjs.map +1 -0
- package/dist/{chunk-ONA73BU6.cjs → chunk-DKHGWHXP.cjs} +21 -12
- package/dist/chunk-DKHGWHXP.cjs.map +1 -0
- package/dist/{chunk-HHNHWYTP.cjs → chunk-FGP3QXWL.cjs} +94 -36
- package/dist/chunk-FGP3QXWL.cjs.map +1 -0
- package/dist/chunk-HS74X2OJ.cjs +172 -0
- package/dist/chunk-HS74X2OJ.cjs.map +1 -0
- package/dist/chunk-HYGXZY25.js +163 -0
- package/dist/chunk-HYGXZY25.js.map +1 -0
- package/dist/chunk-M5TMA73F.js +1 -0
- package/dist/chunk-M5TMA73F.js.map +1 -0
- package/dist/chunk-MX3AMQFC.js +172 -0
- package/dist/chunk-MX3AMQFC.js.map +1 -0
- package/dist/{chunk-MLRHYOCD.js → chunk-VRFVF5RH.js} +21 -12
- package/dist/chunk-VRFVF5RH.js.map +1 -0
- package/dist/cli/index.cjs +133 -30
- package/dist/cli/index.cjs.map +1 -1
- package/dist/cli/index.js +134 -31
- package/dist/cli/index.js.map +1 -1
- package/dist/cost/index.d.cts +4 -3
- package/dist/cost/index.d.ts +4 -3
- package/dist/index.cjs +17 -6
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +10 -16
- package/dist/index.d.ts +10 -16
- package/dist/index.js +22 -11
- package/dist/{modelNameResolver-Bn8QnkSj.d.ts → modelNameResolver-D9V_GfUK.d.cts} +3 -27
- package/dist/{modelNameResolver-bZD-eBSJ.d.cts → modelNameResolver-DqFt7g6W.d.ts} +3 -27
- package/dist/models/index.d.cts +3 -2
- package/dist/models/index.d.ts +3 -2
- package/dist/sync/index.cjs +3 -3
- package/dist/sync/index.d.cts +6 -3
- package/dist/sync/index.d.ts +6 -3
- package/dist/sync/index.js +2 -2
- package/dist/syncAiModelsCatalog-CnXRLm2c.d.cts +32 -0
- package/dist/syncAiModelsCatalog-DpkN_w7S.d.ts +32 -0
- package/dist/types-BYXnCvKx.d.cts +137 -0
- package/dist/types-BYXnCvKx.d.ts +137 -0
- package/dist/types-CX6QFNNy.d.cts +144 -0
- package/dist/types-CuiPDcVs.d.ts +144 -0
- package/dist/upsertAiModelRecord-C831wOIF.d.ts +35 -0
- package/dist/upsertAiModelRecord-CjY-sny0.d.cts +35 -0
- package/package.json +8 -1
- package/dist/chunk-HHNHWYTP.cjs.map +0 -1
- package/dist/chunk-ML2FRR4L.js +0 -105
- package/dist/chunk-ML2FRR4L.js.map +0 -1
- package/dist/chunk-MLRHYOCD.js.map +0 -1
- package/dist/chunk-ONA73BU6.cjs.map +0 -1
- package/dist/types-DdGB3YaA.d.cts +0 -278
- package/dist/types-DdGB3YaA.d.ts +0 -278
package/README.md
CHANGED
|
@@ -61,7 +61,117 @@ npx ai-tools models list --reasoning
|
|
|
61
61
|
npx ai-tools models count --reasoning
|
|
62
62
|
```
|
|
63
63
|
|
|
64
|
-
Re-run
|
|
64
|
+
Re-run [Updating the model catalog](#updating-the-model-catalog) after upgrading `@x12i/ai-tools` so existing Firestore rows pick up new fields (e.g. `supportsReasoning`).
|
|
65
|
+
|
|
66
|
+
## Updating the model catalog
|
|
67
|
+
|
|
68
|
+
The **ai-models** catalog in Catalox/Firestore is a mirror of the [OpenRouter Models API](https://openrouter.ai/docs/api-reference/models). OpenRouter’s public `/models` endpoint needs **no API key**; optional `OPENROUTER_API_KEY` only helps with rate limits.
|
|
69
|
+
|
|
70
|
+
### Prerequisites
|
|
71
|
+
|
|
72
|
+
Add to `.env` (see [Environment variables](#environment-variables)):
|
|
73
|
+
|
|
74
|
+
| Variable | Required for sync |
|
|
75
|
+
|----------|-------------------|
|
|
76
|
+
| `GOOGLE_SERVICE_ACCOUNT_BASE64` | Yes |
|
|
77
|
+
| `FIREBASE_PROJECT_ID` | Yes |
|
|
78
|
+
| `FIRESTORE_DATABASE_ID` | No (defaults to `(default)`) |
|
|
79
|
+
| `AI_TOOLS_APP_ID` | No (default: `ai-tools`) |
|
|
80
|
+
| `AI_TOOLS_CATALOG_ID` | No (default: `ai-models`) |
|
|
81
|
+
|
|
82
|
+
First time only, register the catalog descriptor and app binding:
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
npx ai-tools catalog ensure
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### When to run an update
|
|
89
|
+
|
|
90
|
+
| Situation | What to run |
|
|
91
|
+
|-----------|-------------|
|
|
92
|
+
| **First deploy** | `npx ai-tools catalog ensure` then `npx ai-tools sync` |
|
|
93
|
+
| **Routine refresh** (new models/pricing on OpenRouter) | `npx ai-tools sync` |
|
|
94
|
+
| **After upgrading `@x12i/ai-tools`** (new indexed fields) | `npx ai-tools sync` |
|
|
95
|
+
| **Health check only** (no writes) | `npx ai-tools catalog verify` |
|
|
96
|
+
| **Remove models OpenRouter dropped** | `npx ai-tools sync --prune-stale` |
|
|
97
|
+
|
|
98
|
+
### Recommended commands
|
|
99
|
+
|
|
100
|
+
**Full update (production default)** — fetch OpenRouter, upsert every model, then verify counts match:
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
npx ai-tools sync
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
Same job via npm script:
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
npm run seed
|
|
110
|
+
npm run seed:verbose # progress lines
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
**CI / cron** — JSON on stdout, non-zero exit if sync or verify fails:
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
npx ai-tools sync --json
|
|
117
|
+
# or
|
|
118
|
+
npm run verify:seed
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
**Verify only** (read-only; good between scheduled syncs):
|
|
122
|
+
|
|
123
|
+
```bash
|
|
124
|
+
npx ai-tools catalog verify
|
|
125
|
+
npx ai-tools catalog verify --json
|
|
126
|
+
# or
|
|
127
|
+
npm run verify:sync
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
**Dry run** (fetch OpenRouter, no Firestore writes):
|
|
131
|
+
|
|
132
|
+
```bash
|
|
133
|
+
npx ai-tools sync --dry-run
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
| npm script | Equivalent |
|
|
137
|
+
|------------|------------|
|
|
138
|
+
| `npm run seed` | `npx ai-tools sync` |
|
|
139
|
+
| `npm run seed:verbose` | `npx ai-tools sync --verbose` |
|
|
140
|
+
| `npm run verify:seed` | `npx ai-tools sync` (via seed script, sync + verify) |
|
|
141
|
+
| `npm run verify:sync` | `npx ai-tools catalog verify` |
|
|
142
|
+
|
|
143
|
+
### What `sync` does
|
|
144
|
+
|
|
145
|
+
1. Ensures catalog + descriptor exist (`catalog ensure` logic).
|
|
146
|
+
2. Fetches all models from OpenRouter (`output_modalities=all`).
|
|
147
|
+
3. Upserts each row into Firestore/Catalox (`data` + `indexed` fields).
|
|
148
|
+
4. Verifies Catalox count equals OpenRouter count (unless `--no-verify`).
|
|
149
|
+
|
|
150
|
+
On re-sync, existing rows are **updated** (`syncedAt`, pricing, metadata); `createdAt` is preserved and `version` increments.
|
|
151
|
+
|
|
152
|
+
### Cron example
|
|
153
|
+
|
|
154
|
+
```bash
|
|
155
|
+
# Daily at 04:00 — fail the job if sync or verify fails
|
|
156
|
+
0 4 * * * cd /path/to/app && npx ai-tools sync --json >> /var/log/ai-tools-sync.log 2>&1
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
### Programmatic update
|
|
160
|
+
|
|
161
|
+
```ts
|
|
162
|
+
import { createCataloxFromEnv } from "@x12i/catalox/firebase";
|
|
163
|
+
import { runAiModelsCatalogSync, verifyAiModelsCatalog } from "@x12i/ai-tools/catalog";
|
|
164
|
+
|
|
165
|
+
const { catalox, firestore } = createCataloxFromEnv();
|
|
166
|
+
|
|
167
|
+
// Sync + verify (throws CatalogSyncJobError on failure)
|
|
168
|
+
const job = await runAiModelsCatalogSync({ catalox, firestore, verifyAfter: true });
|
|
169
|
+
console.log(job.sync.upserted, job.verify?.ok);
|
|
170
|
+
|
|
171
|
+
// Verify only
|
|
172
|
+
const report = await verifyAiModelsCatalog({ catalox });
|
|
173
|
+
if (!report.ok) throw new Error(`catalog drift: missing=${report.missingInCatalox.length}`);
|
|
174
|
+
```
|
|
65
175
|
|
|
66
176
|
## Smart model name resolution
|
|
67
177
|
|
|
@@ -139,15 +249,6 @@ npx ai-tools models resolve --model claude-sonnet --verbose
|
|
|
139
249
|
npx ai-tools models resolve --model turbomax-9000 --json
|
|
140
250
|
```
|
|
141
251
|
|
|
142
|
-
## Seed catalog (Firestore + OpenRouter)
|
|
143
|
-
|
|
144
|
-
```bash
|
|
145
|
-
# Requires .env: GOOGLE_SERVICE_ACCOUNT_BASE64, FIREBASE_PROJECT_ID
|
|
146
|
-
# OpenRouter /models is public — no API key required
|
|
147
|
-
npm run seed
|
|
148
|
-
npm run seed:verbose
|
|
149
|
-
```
|
|
150
|
-
|
|
151
252
|
## Tests
|
|
152
253
|
|
|
153
254
|
```bash
|
|
@@ -158,9 +259,9 @@ npm run test:all # both
|
|
|
158
259
|
|
|
159
260
|
## CLI
|
|
160
261
|
|
|
262
|
+
Catalog update commands are documented in [Updating the model catalog](#updating-the-model-catalog). Other commands:
|
|
263
|
+
|
|
161
264
|
```bash
|
|
162
|
-
npx ai-tools catalog ensure
|
|
163
|
-
npx ai-tools sync --verbose
|
|
164
265
|
npx ai-tools models list --provider openai
|
|
165
266
|
npx ai-tools models list --reasoning
|
|
166
267
|
npx ai-tools models resolve --model gpt4o --provider openrouter --verbose
|
|
@@ -194,6 +295,7 @@ npx ai-tools alias check
|
|
|
194
295
|
- `@x12i/ai-tools/catalox`
|
|
195
296
|
- `@x12i/ai-tools/aliases`
|
|
196
297
|
- `@x12i/ai-tools/models`
|
|
298
|
+
- `@x12i/ai-tools/catalog` — `runAiModelsCatalogSync`, `verifyAiModelsCatalog`, bootstrap
|
|
197
299
|
|
|
198
300
|
## Project aliases
|
|
199
301
|
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Catalox } from '@x12i/catalox';
|
|
2
|
-
import {
|
|
2
|
+
import { a as AiModelRecord } from './types-BYXnCvKx.cjs';
|
|
3
|
+
import { h as ModelResolverOptions, M as ModelResolutionInput, f as ModelResolutionResult } from './types-CX6QFNNy.cjs';
|
|
3
4
|
|
|
4
5
|
type AiModelsCatalogClientOptions = {
|
|
5
6
|
catalox: Catalox;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Catalox } from '@x12i/catalox';
|
|
2
|
-
import {
|
|
2
|
+
import { a as AiModelRecord } from './types-BYXnCvKx.js';
|
|
3
|
+
import { h as ModelResolverOptions, M as ModelResolutionInput, f as ModelResolutionResult } from './types-CuiPDcVs.js';
|
|
3
4
|
|
|
4
5
|
type AiModelsCatalogClientOptions = {
|
|
5
6
|
catalox: Catalox;
|
package/dist/aliases/index.d.cts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export {
|
|
3
|
-
import { A as AiModelsCatalogClient } from '../AiModelsCatalogClient-
|
|
1
|
+
import { b as AliasRegistry, j as ResolvedModelRef, d as AliasValidationReport } from '../types-CX6QFNNy.cjs';
|
|
2
|
+
export { A as AliasEntry, a as AliasFileSchema, c as AliasRegistryOptions } from '../types-CX6QFNNy.cjs';
|
|
3
|
+
import { A as AiModelsCatalogClient } from '../AiModelsCatalogClient-CNeqFiFs.cjs';
|
|
4
|
+
import '../types-BYXnCvKx.cjs';
|
|
4
5
|
import '@x12i/catalox';
|
|
5
6
|
|
|
6
7
|
type AliasResolverOptions = {
|
package/dist/aliases/index.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export {
|
|
3
|
-
import { A as AiModelsCatalogClient } from '../AiModelsCatalogClient-
|
|
1
|
+
import { b as AliasRegistry, j as ResolvedModelRef, d as AliasValidationReport } from '../types-CuiPDcVs.js';
|
|
2
|
+
export { A as AliasEntry, a as AliasFileSchema, c as AliasRegistryOptions } from '../types-CuiPDcVs.js';
|
|
3
|
+
import { A as AiModelsCatalogClient } from '../AiModelsCatalogClient-nwFoEaqL.js';
|
|
4
|
+
import '../types-BYXnCvKx.js';
|
|
4
5
|
import '@x12i/catalox';
|
|
5
6
|
|
|
6
7
|
type AliasResolverOptions = {
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports, "__esModule", {value: true});require('../chunk-C3H7RTFR.cjs');
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
var _chunkHS74X2OJcjs = require('../chunk-HS74X2OJ.cjs');
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
var _chunkDKHGWHXPcjs = require('../chunk-DKHGWHXP.cjs');
|
|
11
|
+
require('../chunk-FGP3QXWL.cjs');
|
|
12
|
+
require('../chunk-AV6OE2YQ.cjs');
|
|
13
|
+
require('../chunk-F2F4UEFD.cjs');
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
var _chunkTF4L2NECcjs = require('../chunk-TF4L2NEC.cjs');
|
|
19
|
+
require('../chunk-7Q742NI3.cjs');
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
exports.AI_MODELS_CATALOG_ID = _chunkTF4L2NECcjs.AI_MODELS_CATALOG_ID; exports.AI_MODELS_DESCRIPTOR = _chunkTF4L2NECcjs.AI_MODELS_DESCRIPTOR; exports.AI_TOOLS_APP_ID = _chunkTF4L2NECcjs.AI_TOOLS_APP_ID; exports.CatalogSyncJobError = _chunkHS74X2OJcjs.CatalogSyncJobError; exports.ensureAiModelsCatalog = _chunkDKHGWHXPcjs.ensureAiModelsCatalog; exports.pruneStaleCatalogModels = _chunkHS74X2OJcjs.pruneStaleCatalogModels; exports.runAiModelsCatalogSync = _chunkHS74X2OJcjs.runAiModelsCatalogSync; exports.verifyAiModelsCatalog = _chunkHS74X2OJcjs.verifyAiModelsCatalog;
|
|
30
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["/Users/ami/Documents/prometheus/x12i/ai-tools/dist/catalog/index.cjs"],"names":[],"mappings":"AAAA,0GAA8B;AAC9B;AACE;AACA;AACA;AACA;AACF,yDAA8B;AAC9B;AACE;AACF,yDAA8B;AAC9B,iCAA8B;AAC9B,iCAA8B;AAC9B,iCAA8B;AAC9B;AACE;AACA;AACA;AACF,yDAA8B;AAC9B,iCAA8B;AAC9B;AACE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACF,yjBAAC","file":"/Users/ami/Documents/prometheus/x12i/ai-tools/dist/catalog/index.cjs"}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { Catalox, CatalogDescriptor, CataloxContext } from '@x12i/catalox';
|
|
2
|
+
import { a as AiModelRecord, d as OpenRouterModelsQuery } from '../types-BYXnCvKx.cjs';
|
|
3
|
+
import { a as SyncResult, S as SyncOptions } from '../syncAiModelsCatalog-CnXRLm2c.cjs';
|
|
4
|
+
import { Firestore } from 'firebase-admin/firestore';
|
|
5
|
+
import '../upsertAiModelRecord-CjY-sny0.cjs';
|
|
6
|
+
|
|
7
|
+
type EnsureAiModelsCatalogOptions = {
|
|
8
|
+
appId?: string;
|
|
9
|
+
catalogId?: string;
|
|
10
|
+
};
|
|
11
|
+
declare function ensureAiModelsCatalog(catalox: Catalox, options?: EnsureAiModelsCatalogOptions): Promise<void>;
|
|
12
|
+
|
|
13
|
+
declare const AI_MODELS_CATALOG_ID = "ai-models";
|
|
14
|
+
declare const AI_TOOLS_APP_ID = "ai-tools";
|
|
15
|
+
declare const AI_MODELS_DESCRIPTOR: CatalogDescriptor;
|
|
16
|
+
|
|
17
|
+
type CatalogVerifyOptions = {
|
|
18
|
+
catalox: Catalox;
|
|
19
|
+
appId?: string;
|
|
20
|
+
catalogId?: string;
|
|
21
|
+
/** When set, compare against this id set (e.g. from a sync that just ran). */
|
|
22
|
+
expectedModelIds?: Set<string>;
|
|
23
|
+
/** When set, compare against this list instead of fetching OpenRouter. */
|
|
24
|
+
openRouterModels?: AiModelRecord[];
|
|
25
|
+
openRouterApiKey?: string;
|
|
26
|
+
openRouterQuery?: OpenRouterModelsQuery;
|
|
27
|
+
/** Ensure descriptor is registered before reading (default true). */
|
|
28
|
+
ensureDescriptor?: boolean;
|
|
29
|
+
/** Max model ids to include in report samples (default 20). */
|
|
30
|
+
sampleLimit?: number;
|
|
31
|
+
};
|
|
32
|
+
type CatalogVerifyReport = {
|
|
33
|
+
ok: boolean;
|
|
34
|
+
openRouterCount: number;
|
|
35
|
+
cataloxCount: number;
|
|
36
|
+
missingInCatalox: string[];
|
|
37
|
+
extraInCatalox: string[];
|
|
38
|
+
supportsReasoningMissing: number;
|
|
39
|
+
openRouterMirrorMissing: number;
|
|
40
|
+
descriptorKeysMatch: boolean;
|
|
41
|
+
durationMs: number;
|
|
42
|
+
};
|
|
43
|
+
/**
|
|
44
|
+
* Compare the live OpenRouter catalog with Catalox/Firestore ai-models items.
|
|
45
|
+
* Use after sync in CI/cron, or standalone health checks.
|
|
46
|
+
*/
|
|
47
|
+
declare function verifyAiModelsCatalog(options: CatalogVerifyOptions): Promise<CatalogVerifyReport>;
|
|
48
|
+
|
|
49
|
+
type CatalogSyncJobOptions = SyncOptions & {
|
|
50
|
+
/**
|
|
51
|
+
* After upsert, compare Catalox to OpenRouter (default true).
|
|
52
|
+
* Set false only when you will verify separately.
|
|
53
|
+
*/
|
|
54
|
+
verifyAfter?: boolean;
|
|
55
|
+
/** Fail the job when verification does not pass (default true). */
|
|
56
|
+
failOnVerifyError?: boolean;
|
|
57
|
+
/** Delete Firestore rows not present in the latest OpenRouter list (default false). */
|
|
58
|
+
pruneStale?: boolean;
|
|
59
|
+
};
|
|
60
|
+
type CatalogSyncJobResult = {
|
|
61
|
+
sync: SyncResult;
|
|
62
|
+
verify?: CatalogVerifyReport;
|
|
63
|
+
prune?: {
|
|
64
|
+
scanned: number;
|
|
65
|
+
pruned: number;
|
|
66
|
+
prunedModelIds: string[];
|
|
67
|
+
};
|
|
68
|
+
ok: boolean;
|
|
69
|
+
};
|
|
70
|
+
declare class CatalogSyncJobError extends Error {
|
|
71
|
+
readonly sync: SyncResult;
|
|
72
|
+
readonly verify?: CatalogVerifyReport | undefined;
|
|
73
|
+
constructor(message: string, sync: SyncResult, verify?: CatalogVerifyReport | undefined);
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Production entry point: sync OpenRouter → Catalox, optionally prune stale rows, then verify.
|
|
77
|
+
* Suitable for cron, Cloud Run jobs, and `ai-tools sync`.
|
|
78
|
+
*/
|
|
79
|
+
declare function runAiModelsCatalogSync(options: CatalogSyncJobOptions): Promise<CatalogSyncJobResult>;
|
|
80
|
+
|
|
81
|
+
type PruneStaleCatalogModelsOptions = {
|
|
82
|
+
firestore: Firestore;
|
|
83
|
+
catalogId: string;
|
|
84
|
+
context: CataloxContext;
|
|
85
|
+
/** Canonical model ids from the latest OpenRouter fetch. */
|
|
86
|
+
activeModelIds: Set<string>;
|
|
87
|
+
dryRun?: boolean;
|
|
88
|
+
};
|
|
89
|
+
type PruneStaleCatalogModelsResult = {
|
|
90
|
+
scanned: number;
|
|
91
|
+
pruned: number;
|
|
92
|
+
prunedModelIds: string[];
|
|
93
|
+
};
|
|
94
|
+
/**
|
|
95
|
+
* Remove catalog documents that are no longer listed on OpenRouter.
|
|
96
|
+
* Off by default — enable explicitly when running production sync jobs.
|
|
97
|
+
*/
|
|
98
|
+
declare function pruneStaleCatalogModels(options: PruneStaleCatalogModelsOptions): Promise<PruneStaleCatalogModelsResult>;
|
|
99
|
+
|
|
100
|
+
export { AI_MODELS_CATALOG_ID, AI_MODELS_DESCRIPTOR, AI_TOOLS_APP_ID, CatalogSyncJobError, type CatalogSyncJobOptions, type CatalogSyncJobResult, type CatalogVerifyOptions, type CatalogVerifyReport, type EnsureAiModelsCatalogOptions, type PruneStaleCatalogModelsOptions, type PruneStaleCatalogModelsResult, ensureAiModelsCatalog, pruneStaleCatalogModels, runAiModelsCatalogSync, verifyAiModelsCatalog };
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { Catalox, CatalogDescriptor, CataloxContext } from '@x12i/catalox';
|
|
2
|
+
import { a as AiModelRecord, d as OpenRouterModelsQuery } from '../types-BYXnCvKx.js';
|
|
3
|
+
import { a as SyncResult, S as SyncOptions } from '../syncAiModelsCatalog-DpkN_w7S.js';
|
|
4
|
+
import { Firestore } from 'firebase-admin/firestore';
|
|
5
|
+
import '../upsertAiModelRecord-C831wOIF.js';
|
|
6
|
+
|
|
7
|
+
type EnsureAiModelsCatalogOptions = {
|
|
8
|
+
appId?: string;
|
|
9
|
+
catalogId?: string;
|
|
10
|
+
};
|
|
11
|
+
declare function ensureAiModelsCatalog(catalox: Catalox, options?: EnsureAiModelsCatalogOptions): Promise<void>;
|
|
12
|
+
|
|
13
|
+
declare const AI_MODELS_CATALOG_ID = "ai-models";
|
|
14
|
+
declare const AI_TOOLS_APP_ID = "ai-tools";
|
|
15
|
+
declare const AI_MODELS_DESCRIPTOR: CatalogDescriptor;
|
|
16
|
+
|
|
17
|
+
type CatalogVerifyOptions = {
|
|
18
|
+
catalox: Catalox;
|
|
19
|
+
appId?: string;
|
|
20
|
+
catalogId?: string;
|
|
21
|
+
/** When set, compare against this id set (e.g. from a sync that just ran). */
|
|
22
|
+
expectedModelIds?: Set<string>;
|
|
23
|
+
/** When set, compare against this list instead of fetching OpenRouter. */
|
|
24
|
+
openRouterModels?: AiModelRecord[];
|
|
25
|
+
openRouterApiKey?: string;
|
|
26
|
+
openRouterQuery?: OpenRouterModelsQuery;
|
|
27
|
+
/** Ensure descriptor is registered before reading (default true). */
|
|
28
|
+
ensureDescriptor?: boolean;
|
|
29
|
+
/** Max model ids to include in report samples (default 20). */
|
|
30
|
+
sampleLimit?: number;
|
|
31
|
+
};
|
|
32
|
+
type CatalogVerifyReport = {
|
|
33
|
+
ok: boolean;
|
|
34
|
+
openRouterCount: number;
|
|
35
|
+
cataloxCount: number;
|
|
36
|
+
missingInCatalox: string[];
|
|
37
|
+
extraInCatalox: string[];
|
|
38
|
+
supportsReasoningMissing: number;
|
|
39
|
+
openRouterMirrorMissing: number;
|
|
40
|
+
descriptorKeysMatch: boolean;
|
|
41
|
+
durationMs: number;
|
|
42
|
+
};
|
|
43
|
+
/**
|
|
44
|
+
* Compare the live OpenRouter catalog with Catalox/Firestore ai-models items.
|
|
45
|
+
* Use after sync in CI/cron, or standalone health checks.
|
|
46
|
+
*/
|
|
47
|
+
declare function verifyAiModelsCatalog(options: CatalogVerifyOptions): Promise<CatalogVerifyReport>;
|
|
48
|
+
|
|
49
|
+
type CatalogSyncJobOptions = SyncOptions & {
|
|
50
|
+
/**
|
|
51
|
+
* After upsert, compare Catalox to OpenRouter (default true).
|
|
52
|
+
* Set false only when you will verify separately.
|
|
53
|
+
*/
|
|
54
|
+
verifyAfter?: boolean;
|
|
55
|
+
/** Fail the job when verification does not pass (default true). */
|
|
56
|
+
failOnVerifyError?: boolean;
|
|
57
|
+
/** Delete Firestore rows not present in the latest OpenRouter list (default false). */
|
|
58
|
+
pruneStale?: boolean;
|
|
59
|
+
};
|
|
60
|
+
type CatalogSyncJobResult = {
|
|
61
|
+
sync: SyncResult;
|
|
62
|
+
verify?: CatalogVerifyReport;
|
|
63
|
+
prune?: {
|
|
64
|
+
scanned: number;
|
|
65
|
+
pruned: number;
|
|
66
|
+
prunedModelIds: string[];
|
|
67
|
+
};
|
|
68
|
+
ok: boolean;
|
|
69
|
+
};
|
|
70
|
+
declare class CatalogSyncJobError extends Error {
|
|
71
|
+
readonly sync: SyncResult;
|
|
72
|
+
readonly verify?: CatalogVerifyReport | undefined;
|
|
73
|
+
constructor(message: string, sync: SyncResult, verify?: CatalogVerifyReport | undefined);
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Production entry point: sync OpenRouter → Catalox, optionally prune stale rows, then verify.
|
|
77
|
+
* Suitable for cron, Cloud Run jobs, and `ai-tools sync`.
|
|
78
|
+
*/
|
|
79
|
+
declare function runAiModelsCatalogSync(options: CatalogSyncJobOptions): Promise<CatalogSyncJobResult>;
|
|
80
|
+
|
|
81
|
+
type PruneStaleCatalogModelsOptions = {
|
|
82
|
+
firestore: Firestore;
|
|
83
|
+
catalogId: string;
|
|
84
|
+
context: CataloxContext;
|
|
85
|
+
/** Canonical model ids from the latest OpenRouter fetch. */
|
|
86
|
+
activeModelIds: Set<string>;
|
|
87
|
+
dryRun?: boolean;
|
|
88
|
+
};
|
|
89
|
+
type PruneStaleCatalogModelsResult = {
|
|
90
|
+
scanned: number;
|
|
91
|
+
pruned: number;
|
|
92
|
+
prunedModelIds: string[];
|
|
93
|
+
};
|
|
94
|
+
/**
|
|
95
|
+
* Remove catalog documents that are no longer listed on OpenRouter.
|
|
96
|
+
* Off by default — enable explicitly when running production sync jobs.
|
|
97
|
+
*/
|
|
98
|
+
declare function pruneStaleCatalogModels(options: PruneStaleCatalogModelsOptions): Promise<PruneStaleCatalogModelsResult>;
|
|
99
|
+
|
|
100
|
+
export { AI_MODELS_CATALOG_ID, AI_MODELS_DESCRIPTOR, AI_TOOLS_APP_ID, CatalogSyncJobError, type CatalogSyncJobOptions, type CatalogSyncJobResult, type CatalogVerifyOptions, type CatalogVerifyReport, type EnsureAiModelsCatalogOptions, type PruneStaleCatalogModelsOptions, type PruneStaleCatalogModelsResult, ensureAiModelsCatalog, pruneStaleCatalogModels, runAiModelsCatalogSync, verifyAiModelsCatalog };
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import "../chunk-M5TMA73F.js";
|
|
2
|
+
import {
|
|
3
|
+
CatalogSyncJobError,
|
|
4
|
+
pruneStaleCatalogModels,
|
|
5
|
+
runAiModelsCatalogSync,
|
|
6
|
+
verifyAiModelsCatalog
|
|
7
|
+
} from "../chunk-MX3AMQFC.js";
|
|
8
|
+
import {
|
|
9
|
+
ensureAiModelsCatalog
|
|
10
|
+
} from "../chunk-VRFVF5RH.js";
|
|
11
|
+
import "../chunk-HYGXZY25.js";
|
|
12
|
+
import "../chunk-6QGDZTGH.js";
|
|
13
|
+
import "../chunk-KQOALKKX.js";
|
|
14
|
+
import {
|
|
15
|
+
AI_MODELS_CATALOG_ID,
|
|
16
|
+
AI_MODELS_DESCRIPTOR,
|
|
17
|
+
AI_TOOLS_APP_ID
|
|
18
|
+
} from "../chunk-DJ5SWJDY.js";
|
|
19
|
+
import "../chunk-AJEKEWWB.js";
|
|
20
|
+
export {
|
|
21
|
+
AI_MODELS_CATALOG_ID,
|
|
22
|
+
AI_MODELS_DESCRIPTOR,
|
|
23
|
+
AI_TOOLS_APP_ID,
|
|
24
|
+
CatalogSyncJobError,
|
|
25
|
+
ensureAiModelsCatalog,
|
|
26
|
+
pruneStaleCatalogModels,
|
|
27
|
+
runAiModelsCatalogSync,
|
|
28
|
+
verifyAiModelsCatalog
|
|
29
|
+
};
|
|
30
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
package/dist/catalox/index.cjs
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
|
|
7
|
-
var
|
|
7
|
+
var _chunkFGP3QXWLcjs = require('../chunk-FGP3QXWL.cjs');
|
|
8
8
|
|
|
9
9
|
|
|
10
10
|
var _chunkF2F4UEFDcjs = require('../chunk-F2F4UEFD.cjs');
|
|
@@ -17,5 +17,5 @@ require('../chunk-7Q742NI3.cjs');
|
|
|
17
17
|
|
|
18
18
|
|
|
19
19
|
|
|
20
|
-
exports.AiModelsCatalogClient = _chunkF2F4UEFDcjs.AiModelsCatalogClient; exports.batchUpsertAiModelRecords =
|
|
20
|
+
exports.AiModelsCatalogClient = _chunkF2F4UEFDcjs.AiModelsCatalogClient; exports.batchUpsertAiModelRecords = _chunkFGP3QXWLcjs.batchUpsertAiModelRecords; exports.decodeModelFirestoreDocId = _chunkFGP3QXWLcjs.decodeModelFirestoreDocId; exports.encodeModelFirestoreDocId = _chunkFGP3QXWLcjs.encodeModelFirestoreDocId; exports.sanitizeForFirestore = _chunkFGP3QXWLcjs.sanitizeForFirestore; exports.upsertAiModelRecord = _chunkFGP3QXWLcjs.upsertAiModelRecord;
|
|
21
21
|
//# sourceMappingURL=index.cjs.map
|
package/dist/catalox/index.d.cts
CHANGED
|
@@ -1,23 +1,11 @@
|
|
|
1
|
-
export { A as AiModelsCatalogClient, a as AiModelsCatalogClientOptions } from '../AiModelsCatalogClient-
|
|
2
|
-
|
|
3
|
-
import
|
|
4
|
-
import
|
|
1
|
+
export { A as AiModelsCatalogClient, a as AiModelsCatalogClientOptions } from '../AiModelsCatalogClient-CNeqFiFs.cjs';
|
|
2
|
+
export { b as batchUpsertAiModelRecords, s as sanitizeForFirestore, u as upsertAiModelRecord } from '../upsertAiModelRecord-CjY-sny0.cjs';
|
|
3
|
+
import '@x12i/catalox';
|
|
4
|
+
import '../types-BYXnCvKx.cjs';
|
|
5
|
+
import '../types-CX6QFNNy.cjs';
|
|
6
|
+
import 'firebase-admin/firestore';
|
|
5
7
|
|
|
6
8
|
declare function encodeModelFirestoreDocId(modelId: string): string;
|
|
7
9
|
declare function decodeModelFirestoreDocId(docId: string): string;
|
|
8
10
|
|
|
9
|
-
|
|
10
|
-
declare function sanitizeForFirestore<T>(value: T): T;
|
|
11
|
-
type UpsertAiModelRecordOptions = {
|
|
12
|
-
firestore: Firestore;
|
|
13
|
-
context: CataloxContext;
|
|
14
|
-
catalogId: string;
|
|
15
|
-
record: AiModelRecord;
|
|
16
|
-
};
|
|
17
|
-
/**
|
|
18
|
-
* Upserts one ai-models row via Firestore (safe doc ids for `provider/model` ids).
|
|
19
|
-
*/
|
|
20
|
-
declare function upsertAiModelRecord(options: UpsertAiModelRecordOptions): Promise<void>;
|
|
21
|
-
declare function batchUpsertAiModelRecords(firestore: Firestore, catalogId: string, context: CataloxContext, records: AiModelRecord[]): Promise<void>;
|
|
22
|
-
|
|
23
|
-
export { batchUpsertAiModelRecords, decodeModelFirestoreDocId, encodeModelFirestoreDocId, sanitizeForFirestore, upsertAiModelRecord };
|
|
11
|
+
export { decodeModelFirestoreDocId, encodeModelFirestoreDocId };
|
package/dist/catalox/index.d.ts
CHANGED
|
@@ -1,23 +1,11 @@
|
|
|
1
|
-
export { A as AiModelsCatalogClient, a as AiModelsCatalogClientOptions } from '../AiModelsCatalogClient-
|
|
2
|
-
|
|
3
|
-
import
|
|
4
|
-
import
|
|
1
|
+
export { A as AiModelsCatalogClient, a as AiModelsCatalogClientOptions } from '../AiModelsCatalogClient-nwFoEaqL.js';
|
|
2
|
+
export { b as batchUpsertAiModelRecords, s as sanitizeForFirestore, u as upsertAiModelRecord } from '../upsertAiModelRecord-C831wOIF.js';
|
|
3
|
+
import '@x12i/catalox';
|
|
4
|
+
import '../types-BYXnCvKx.js';
|
|
5
|
+
import '../types-CuiPDcVs.js';
|
|
6
|
+
import 'firebase-admin/firestore';
|
|
5
7
|
|
|
6
8
|
declare function encodeModelFirestoreDocId(modelId: string): string;
|
|
7
9
|
declare function decodeModelFirestoreDocId(docId: string): string;
|
|
8
10
|
|
|
9
|
-
|
|
10
|
-
declare function sanitizeForFirestore<T>(value: T): T;
|
|
11
|
-
type UpsertAiModelRecordOptions = {
|
|
12
|
-
firestore: Firestore;
|
|
13
|
-
context: CataloxContext;
|
|
14
|
-
catalogId: string;
|
|
15
|
-
record: AiModelRecord;
|
|
16
|
-
};
|
|
17
|
-
/**
|
|
18
|
-
* Upserts one ai-models row via Firestore (safe doc ids for `provider/model` ids).
|
|
19
|
-
*/
|
|
20
|
-
declare function upsertAiModelRecord(options: UpsertAiModelRecordOptions): Promise<void>;
|
|
21
|
-
declare function batchUpsertAiModelRecords(firestore: Firestore, catalogId: string, context: CataloxContext, records: AiModelRecord[]): Promise<void>;
|
|
22
|
-
|
|
23
|
-
export { batchUpsertAiModelRecords, decodeModelFirestoreDocId, encodeModelFirestoreDocId, sanitizeForFirestore, upsertAiModelRecord };
|
|
11
|
+
export { decodeModelFirestoreDocId, encodeModelFirestoreDocId };
|
package/dist/catalox/index.js
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";//# sourceMappingURL=chunk-C3H7RTFR.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["/Users/ami/Documents/prometheus/x12i/ai-tools/dist/chunk-C3H7RTFR.cjs"],"names":[],"mappings":"AAAA","file":"/Users/ami/Documents/prometheus/x12i/ai-tools/dist/chunk-C3H7RTFR.cjs"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var _chunkFGP3QXWLcjs = require('./chunk-FGP3QXWL.cjs');
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
var _chunkAV6OE2YQcjs = require('./chunk-AV6OE2YQ.cjs');
|
|
@@ -126,28 +126,37 @@ async function syncAiModelsCatalog(options) {
|
|
|
126
126
|
if (options.verbose) {
|
|
127
127
|
console.log(`[sync] fetched ${models.length} models from ${provider.getModelsUrl()}`);
|
|
128
128
|
}
|
|
129
|
+
const syncedModelIds = models.map((m) => m.modelId);
|
|
129
130
|
if (options.dryRun) {
|
|
130
131
|
return {
|
|
131
132
|
fetched: models.length,
|
|
132
133
|
upserted: 0,
|
|
133
134
|
skipped: models.length,
|
|
134
135
|
errors: [],
|
|
136
|
+
syncedModelIds,
|
|
135
137
|
durationMs: Date.now() - start
|
|
136
138
|
};
|
|
137
139
|
}
|
|
138
|
-
const
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
140
|
+
const upsert = await _chunkFGP3QXWLcjs.batchUpsertAiModelRecords.call(void 0,
|
|
141
|
+
options.firestore,
|
|
142
|
+
catalogId,
|
|
143
|
+
ctx,
|
|
144
|
+
models,
|
|
145
|
+
{ onProgress: options.onProgress }
|
|
146
|
+
);
|
|
145
147
|
_chunkTF4L2NECcjs.invalidateModelsCache.call(void 0, appId);
|
|
148
|
+
if (upsert.failed.length > 0 && upsert.upserted === 0) {
|
|
149
|
+
throw new (0, _chunk7Q742NI3cjs.SyncError)(
|
|
150
|
+
"SYNC_UPSERT_FAILED",
|
|
151
|
+
`All ${upsert.failed.length} model upserts failed. First error: ${upsert.failed[0].error}`
|
|
152
|
+
);
|
|
153
|
+
}
|
|
146
154
|
return {
|
|
147
155
|
fetched: models.length,
|
|
148
|
-
upserted:
|
|
149
|
-
skipped:
|
|
150
|
-
errors,
|
|
156
|
+
upserted: upsert.upserted,
|
|
157
|
+
skipped: models.length - upsert.upserted,
|
|
158
|
+
errors: upsert.failed,
|
|
159
|
+
syncedModelIds,
|
|
151
160
|
durationMs: Date.now() - start
|
|
152
161
|
};
|
|
153
162
|
}
|
|
@@ -157,4 +166,4 @@ async function syncAiModelsCatalog(options) {
|
|
|
157
166
|
|
|
158
167
|
|
|
159
168
|
exports.ensureAiModelsCatalog = ensureAiModelsCatalog; exports.OpenRouterSyncProvider = OpenRouterSyncProvider; exports.syncAiModelsCatalog = syncAiModelsCatalog;
|
|
160
|
-
//# sourceMappingURL=chunk-
|
|
169
|
+
//# sourceMappingURL=chunk-DKHGWHXP.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["/Users/ami/Documents/prometheus/x12i/ai-tools/dist/chunk-DKHGWHXP.cjs","../src/catalog/ensureAiModelsCatalog.ts","../src/sync/OpenRouterSyncProvider.ts","../src/sync/syncAiModelsCatalog.ts"],"names":[],"mappings":"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","file":"/Users/ami/Documents/prometheus/x12i/ai-tools/dist/chunk-DKHGWHXP.cjs","sourcesContent":[null,"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 {\n batchUpsertAiModelRecords,\n type BatchUpsertProgress,\n} 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 onProgress?: (progress: BatchUpsertProgress) => void;\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 /** Model ids written (or that would be written on dry-run). */\n syncedModelIds: string[];\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 const syncedModelIds = models.map((m) => m.modelId);\n\n if (options.dryRun) {\n return {\n fetched: models.length,\n upserted: 0,\n skipped: models.length,\n errors: [],\n syncedModelIds,\n durationMs: Date.now() - start,\n };\n }\n\n const upsert = await batchUpsertAiModelRecords(\n options.firestore,\n catalogId,\n ctx,\n models,\n { onProgress: options.onProgress },\n );\n\n invalidateModelsCache(appId);\n\n if (upsert.failed.length > 0 && upsert.upserted === 0) {\n throw new SyncError(\n \"SYNC_UPSERT_FAILED\",\n `All ${upsert.failed.length} model upserts failed. First error: ${upsert.failed[0]!.error}`,\n );\n }\n\n return {\n fetched: models.length,\n upserted: upsert.upserted,\n skipped: models.length - upsert.upserted,\n errors: upsert.failed,\n syncedModelIds,\n durationMs: Date.now() - start,\n };\n}\n"]}
|