@actuate-media/cms-core 0.42.0 → 0.43.0

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.
Files changed (64) hide show
  1. package/dist/__tests__/ai/ai.test.d.ts +2 -0
  2. package/dist/__tests__/ai/ai.test.d.ts.map +1 -0
  3. package/dist/__tests__/ai/ai.test.js +261 -0
  4. package/dist/__tests__/ai/ai.test.js.map +1 -0
  5. package/dist/ai/catalog.d.ts +29 -0
  6. package/dist/ai/catalog.d.ts.map +1 -0
  7. package/dist/ai/catalog.js +340 -0
  8. package/dist/ai/catalog.js.map +1 -0
  9. package/dist/ai/config-store.d.ts +55 -0
  10. package/dist/ai/config-store.d.ts.map +1 -0
  11. package/dist/ai/config-store.js +177 -0
  12. package/dist/ai/config-store.js.map +1 -0
  13. package/dist/ai/feature-defaults.d.ts +20 -0
  14. package/dist/ai/feature-defaults.d.ts.map +1 -0
  15. package/dist/ai/feature-defaults.js +104 -0
  16. package/dist/ai/feature-defaults.js.map +1 -0
  17. package/dist/ai/index.d.ts +13 -0
  18. package/dist/ai/index.d.ts.map +1 -0
  19. package/dist/ai/index.js +13 -0
  20. package/dist/ai/index.js.map +1 -0
  21. package/dist/ai/models.d.ts +37 -0
  22. package/dist/ai/models.d.ts.map +1 -0
  23. package/dist/ai/models.js +126 -0
  24. package/dist/ai/models.js.map +1 -0
  25. package/dist/ai/providers/anthropic.d.ts +9 -0
  26. package/dist/ai/providers/anthropic.d.ts.map +1 -0
  27. package/dist/ai/providers/anthropic.js +36 -0
  28. package/dist/ai/providers/anthropic.js.map +1 -0
  29. package/dist/ai/providers/custom.d.ts +11 -0
  30. package/dist/ai/providers/custom.d.ts.map +1 -0
  31. package/dist/ai/providers/custom.js +70 -0
  32. package/dist/ai/providers/custom.js.map +1 -0
  33. package/dist/ai/providers/http.d.ts +32 -0
  34. package/dist/ai/providers/http.d.ts.map +1 -0
  35. package/dist/ai/providers/http.js +90 -0
  36. package/dist/ai/providers/http.js.map +1 -0
  37. package/dist/ai/providers/index.d.ts +16 -0
  38. package/dist/ai/providers/index.d.ts.map +1 -0
  39. package/dist/ai/providers/index.js +25 -0
  40. package/dist/ai/providers/index.js.map +1 -0
  41. package/dist/ai/providers/openai.d.ts +10 -0
  42. package/dist/ai/providers/openai.d.ts.map +1 -0
  43. package/dist/ai/providers/openai.js +41 -0
  44. package/dist/ai/providers/openai.js.map +1 -0
  45. package/dist/ai/providers/xai.d.ts +9 -0
  46. package/dist/ai/providers/xai.d.ts.map +1 -0
  47. package/dist/ai/providers/xai.js +35 -0
  48. package/dist/ai/providers/xai.js.map +1 -0
  49. package/dist/ai/types.d.ts +161 -0
  50. package/dist/ai/types.d.ts.map +1 -0
  51. package/dist/ai/types.js +11 -0
  52. package/dist/ai/types.js.map +1 -0
  53. package/dist/ai/usage.d.ts +18 -0
  54. package/dist/ai/usage.d.ts.map +1 -0
  55. package/dist/ai/usage.js +70 -0
  56. package/dist/ai/usage.js.map +1 -0
  57. package/dist/api/handlers.d.ts.map +1 -1
  58. package/dist/api/handlers.js +477 -0
  59. package/dist/api/handlers.js.map +1 -1
  60. package/dist/index.d.ts +3 -0
  61. package/dist/index.d.ts.map +1 -1
  62. package/dist/index.js +4 -0
  63. package/dist/index.js.map +1 -1
  64. package/package.json +1 -1
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Anthropic adapter. Uses the `/v1/models` listing endpoint with `x-api-key`
3
+ * and the required `anthropic-version` header. Hostname is fixed.
4
+ */
5
+ import { extractModelIds, messageFromStatus, statusFromHttp, timedFetch, } from './http.js';
6
+ const ANTHROPIC_BASE = 'https://api.anthropic.com/v1';
7
+ const ANTHROPIC_VERSION = '2023-06-01';
8
+ function headers(ctx) {
9
+ return { 'x-api-key': ctx.apiKey, 'anthropic-version': ANTHROPIC_VERSION };
10
+ }
11
+ export async function testConnection(ctx) {
12
+ const testedAt = new Date().toISOString();
13
+ if (!ctx.apiKey) {
14
+ return { ok: false, status: 'needs_setup', message: messageFromStatus('needs_setup'), testedAt };
15
+ }
16
+ try {
17
+ const res = await timedFetch(`${ANTHROPIC_BASE}/models`, { method: 'GET', headers: headers(ctx) }, ctx);
18
+ const status = statusFromHttp(res.status);
19
+ return { ok: status === 'connected', status, message: messageFromStatus(status), testedAt };
20
+ }
21
+ catch {
22
+ return {
23
+ ok: false,
24
+ status: 'provider_down',
25
+ message: messageFromStatus('provider_down'),
26
+ testedAt,
27
+ };
28
+ }
29
+ }
30
+ export async function listModels(ctx) {
31
+ const res = await timedFetch(`${ANTHROPIC_BASE}/models`, { method: 'GET', headers: headers(ctx) }, ctx);
32
+ if (!res.ok)
33
+ throw new Error(`Anthropic model listing failed (${res.status})`);
34
+ return extractModelIds(await res.json());
35
+ }
36
+ //# sourceMappingURL=anthropic.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"anthropic.js","sourceRoot":"","sources":["../../../src/ai/providers/anthropic.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAEL,eAAe,EACf,iBAAiB,EACjB,cAAc,EACd,UAAU,GACX,MAAM,WAAW,CAAA;AAElB,MAAM,cAAc,GAAG,8BAA8B,CAAA;AACrD,MAAM,iBAAiB,GAAG,YAAY,CAAA;AAEtC,SAAS,OAAO,CAAC,GAAmB;IAClC,OAAO,EAAE,WAAW,EAAE,GAAG,CAAC,MAAM,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,CAAA;AAC5E,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,GAAmB;IACtD,MAAM,QAAQ,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAA;IACzC,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC;QAChB,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,aAAa,EAAE,OAAO,EAAE,iBAAiB,CAAC,aAAa,CAAC,EAAE,QAAQ,EAAE,CAAA;IAClG,CAAC;IACD,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,UAAU,CAC1B,GAAG,cAAc,SAAS,EAC1B,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,EAAE,EACxC,GAAG,CACJ,CAAA;QACD,MAAM,MAAM,GAAG,cAAc,CAAC,GAAG,CAAC,MAAM,CAAC,CAAA;QACzC,OAAO,EAAE,EAAE,EAAE,MAAM,KAAK,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,iBAAiB,CAAC,MAAM,CAAC,EAAE,QAAQ,EAAE,CAAA;IAC7F,CAAC;IAAC,MAAM,CAAC;QACP,OAAO;YACL,EAAE,EAAE,KAAK;YACT,MAAM,EAAE,eAAe;YACvB,OAAO,EAAE,iBAAiB,CAAC,eAAe,CAAC;YAC3C,QAAQ;SACT,CAAA;IACH,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,GAAmB;IAClD,MAAM,GAAG,GAAG,MAAM,UAAU,CAC1B,GAAG,cAAc,SAAS,EAC1B,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,EAAE,EACxC,GAAG,CACJ,CAAA;IACD,IAAI,CAAC,GAAG,CAAC,EAAE;QAAE,MAAM,IAAI,KAAK,CAAC,mCAAmC,GAAG,CAAC,MAAM,GAAG,CAAC,CAAA;IAC9E,OAAO,eAAe,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC,CAAA;AAC1C,CAAC"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Custom OpenAI-compatible provider adapter. The base URL is admin-controlled,
3
+ * so it is SSRF-validated and DNS-resolved before any request. Falls back to an
4
+ * empty model list (manual entry in the UI) when the endpoint doesn't support
5
+ * `/models`.
6
+ */
7
+ import type { AIConnectionTestResult } from '../types.js';
8
+ import { type AdapterContext } from './http.js';
9
+ export declare function testConnection(ctx: AdapterContext): Promise<AIConnectionTestResult>;
10
+ export declare function listModels(ctx: AdapterContext): Promise<string[]>;
11
+ //# sourceMappingURL=custom.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"custom.d.ts","sourceRoot":"","sources":["../../../src/ai/providers/custom.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAA;AACzD,OAAO,EACL,KAAK,cAAc,EAOpB,MAAM,WAAW,CAAA;AAMlB,wBAAsB,cAAc,CAAC,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,sBAAsB,CAAC,CAiDzF;AAED,wBAAsB,UAAU,CAAC,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAWvE"}
@@ -0,0 +1,70 @@
1
+ /**
2
+ * Custom OpenAI-compatible provider adapter. The base URL is admin-controlled,
3
+ * so it is SSRF-validated and DNS-resolved before any request. Falls back to an
4
+ * empty model list (manual entry in the UI) when the endpoint doesn't support
5
+ * `/models`.
6
+ */
7
+ import { assertSafeBaseUrl, extractModelIds, messageFromStatus, statusFromHttp, timedFetch, trimTrailingSlash, } from './http.js';
8
+ function headers(ctx) {
9
+ return { authorization: `Bearer ${ctx.apiKey}` };
10
+ }
11
+ export async function testConnection(ctx) {
12
+ const testedAt = new Date().toISOString();
13
+ if (!ctx.baseUrl) {
14
+ return {
15
+ ok: false,
16
+ status: 'needs_setup',
17
+ message: 'A base URL is required for a custom provider.',
18
+ testedAt,
19
+ };
20
+ }
21
+ try {
22
+ await assertSafeBaseUrl(ctx.baseUrl);
23
+ }
24
+ catch (err) {
25
+ return {
26
+ ok: false,
27
+ status: 'unknown',
28
+ message: err instanceof Error ? err.message : 'Invalid base URL.',
29
+ testedAt,
30
+ };
31
+ }
32
+ if (!ctx.apiKey) {
33
+ return { ok: false, status: 'needs_setup', message: messageFromStatus('needs_setup'), testedAt };
34
+ }
35
+ try {
36
+ const res = await timedFetch(`${trimTrailingSlash(ctx.baseUrl)}/models`, { method: 'GET', headers: headers(ctx) }, ctx);
37
+ // A 404 likely means the endpoint doesn't implement /models; the connection
38
+ // itself may still be usable with a manually-entered model id.
39
+ if (res.status === 404) {
40
+ return {
41
+ ok: true,
42
+ status: 'connected',
43
+ message: 'Connected. This endpoint does not list models; enter a model id manually.',
44
+ testedAt,
45
+ };
46
+ }
47
+ const status = statusFromHttp(res.status);
48
+ return { ok: status === 'connected', status, message: messageFromStatus(status), testedAt };
49
+ }
50
+ catch {
51
+ return {
52
+ ok: false,
53
+ status: 'provider_down',
54
+ message: messageFromStatus('provider_down'),
55
+ testedAt,
56
+ };
57
+ }
58
+ }
59
+ export async function listModels(ctx) {
60
+ if (!ctx.baseUrl)
61
+ return [];
62
+ await assertSafeBaseUrl(ctx.baseUrl);
63
+ const res = await timedFetch(`${trimTrailingSlash(ctx.baseUrl)}/models`, { method: 'GET', headers: headers(ctx) }, ctx);
64
+ if (res.status === 404)
65
+ return [];
66
+ if (!res.ok)
67
+ throw new Error(`Custom provider model listing failed (${res.status})`);
68
+ return extractModelIds(await res.json());
69
+ }
70
+ //# sourceMappingURL=custom.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"custom.js","sourceRoot":"","sources":["../../../src/ai/providers/custom.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Shared HTTP helpers for AI provider adapters: a timeout-bounded fetch, a
3
+ * status->AIConnectionStatus mapper, and an SSRF guard for custom base URLs.
4
+ * Built-in providers use fixed hostnames; only custom endpoints are
5
+ * admin-controlled and therefore validated/resolved.
6
+ */
7
+ import type { AIConnectionStatus } from '../types.js';
8
+ export interface AdapterContext {
9
+ apiKey: string;
10
+ baseUrl?: string;
11
+ organizationId?: string;
12
+ projectId?: string;
13
+ /** Injectable fetch for tests; defaults to global `fetch`. */
14
+ fetchImpl?: typeof fetch;
15
+ timeoutMs?: number;
16
+ }
17
+ /** Map an HTTP response status to a connection-health value. */
18
+ export declare function statusFromHttp(status: number): AIConnectionStatus;
19
+ /** A short, safe message for a status (never contains the key). */
20
+ export declare function messageFromStatus(status: AIConnectionStatus): string;
21
+ export declare function timedFetch(url: string, init: RequestInit, ctx: AdapterContext): Promise<Response>;
22
+ /**
23
+ * Validate a custom provider base URL against SSRF (no private/internal hosts,
24
+ * https/http only) AND resolve its DNS to defend against rebinding. Throws on
25
+ * rejection with a safe message.
26
+ */
27
+ export declare function assertSafeBaseUrl(baseUrl: string): Promise<void>;
28
+ /** Strip a trailing slash so we can append `/models` etc. cleanly. */
29
+ export declare function trimTrailingSlash(url: string): string;
30
+ /** Best-effort extraction of model ids from an OpenAI-compatible list payload. */
31
+ export declare function extractModelIds(payload: unknown): string[];
32
+ //# sourceMappingURL=http.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../../../src/ai/providers/http.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAA;AAErD,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,MAAM,CAAA;IACd,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,8DAA8D;IAC9D,SAAS,CAAC,EAAE,OAAO,KAAK,CAAA;IACxB,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED,gEAAgE;AAChE,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,kBAAkB,CAMjE;AAED,mEAAmE;AACnE,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,kBAAkB,GAAG,MAAM,CAepE;AAED,wBAAsB,UAAU,CAC9B,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,WAAW,EACjB,GAAG,EAAE,cAAc,GAClB,OAAO,CAAC,QAAQ,CAAC,CAYnB;AAED;;;;GAIG;AACH,wBAAsB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAetE;AAED,sEAAsE;AACtE,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAErD;AAED,kFAAkF;AAClF,wBAAgB,eAAe,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,EAAE,CAS1D"}
@@ -0,0 +1,90 @@
1
+ /**
2
+ * Shared HTTP helpers for AI provider adapters: a timeout-bounded fetch, a
3
+ * status->AIConnectionStatus mapper, and an SSRF guard for custom base URLs.
4
+ * Built-in providers use fixed hostnames; only custom endpoints are
5
+ * admin-controlled and therefore validated/resolved.
6
+ */
7
+ import { resolveAndCheck, validateWebhookUrl } from '../../security/webhook.js';
8
+ /** Map an HTTP response status to a connection-health value. */
9
+ export function statusFromHttp(status) {
10
+ if (status >= 200 && status < 300)
11
+ return 'connected';
12
+ if (status === 401 || status === 403)
13
+ return 'invalid_key';
14
+ if (status === 429)
15
+ return 'rate_limited';
16
+ if (status >= 500)
17
+ return 'provider_down';
18
+ return 'unknown';
19
+ }
20
+ /** A short, safe message for a status (never contains the key). */
21
+ export function messageFromStatus(status) {
22
+ switch (status) {
23
+ case 'connected':
24
+ return 'Connection successful.';
25
+ case 'invalid_key':
26
+ return 'The API key was rejected (invalid or unauthorized).';
27
+ case 'rate_limited':
28
+ return 'The provider rate-limited the request. Try again shortly.';
29
+ case 'provider_down':
30
+ return 'The provider returned a server error. It may be temporarily unavailable.';
31
+ case 'needs_setup':
32
+ return 'No API key is configured for this provider.';
33
+ default:
34
+ return 'Could not determine connection status.';
35
+ }
36
+ }
37
+ export async function timedFetch(url, init, ctx) {
38
+ const doFetch = ctx.fetchImpl ?? globalThis.fetch;
39
+ if (typeof doFetch !== 'function') {
40
+ throw new Error('fetch is not available in this runtime');
41
+ }
42
+ const controller = new AbortController();
43
+ const timer = setTimeout(() => controller.abort(), ctx.timeoutMs ?? 10_000);
44
+ try {
45
+ return await doFetch(url, { ...init, redirect: 'error', signal: controller.signal });
46
+ }
47
+ finally {
48
+ clearTimeout(timer);
49
+ }
50
+ }
51
+ /**
52
+ * Validate a custom provider base URL against SSRF (no private/internal hosts,
53
+ * https/http only) AND resolve its DNS to defend against rebinding. Throws on
54
+ * rejection with a safe message.
55
+ */
56
+ export async function assertSafeBaseUrl(baseUrl) {
57
+ const check = validateWebhookUrl(baseUrl);
58
+ if (!check.valid) {
59
+ throw new Error(`Unsafe base URL: ${check.error ?? 'invalid'}`);
60
+ }
61
+ let host;
62
+ try {
63
+ host = new URL(baseUrl).hostname;
64
+ }
65
+ catch {
66
+ throw new Error('Unsafe base URL: invalid URL');
67
+ }
68
+ const resolved = await resolveAndCheck(host);
69
+ if (!resolved.safe) {
70
+ throw new Error(`Unsafe base URL: ${resolved.error ?? 'resolves to a private address'}`);
71
+ }
72
+ }
73
+ /** Strip a trailing slash so we can append `/models` etc. cleanly. */
74
+ export function trimTrailingSlash(url) {
75
+ return url.replace(/\/+$/, '');
76
+ }
77
+ /** Best-effort extraction of model ids from an OpenAI-compatible list payload. */
78
+ export function extractModelIds(payload) {
79
+ const data = payload?.data;
80
+ if (!Array.isArray(data))
81
+ return [];
82
+ const ids = [];
83
+ for (const entry of data) {
84
+ const id = entry?.id;
85
+ if (typeof id === 'string' && id.trim())
86
+ ids.push(id.trim());
87
+ }
88
+ return ids;
89
+ }
90
+ //# sourceMappingURL=http.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http.js","sourceRoot":"","sources":["../../../src/ai/providers/http.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Provider adapter dispatcher. Selects the right adapter by provider key and
3
+ * exposes a uniform `testConnection` / `listModels` surface to the catalog and
4
+ * route layers.
5
+ */
6
+ import type { AIConnectionTestResult, AIProviderKey } from '../types.js';
7
+ import type { AdapterContext } from './http.js';
8
+ export type { AdapterContext } from './http.js';
9
+ interface ProviderAdapter {
10
+ testConnection(ctx: AdapterContext): Promise<AIConnectionTestResult>;
11
+ listModels(ctx: AdapterContext): Promise<string[]>;
12
+ }
13
+ export declare function getAdapter(provider: AIProviderKey): ProviderAdapter;
14
+ export declare function testConnection(provider: AIProviderKey, ctx: AdapterContext): Promise<AIConnectionTestResult>;
15
+ export declare function listModels(provider: AIProviderKey, ctx: AdapterContext): Promise<string[]>;
16
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/ai/providers/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,sBAAsB,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAGxE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,WAAW,CAAA;AAI/C,YAAY,EAAE,cAAc,EAAE,MAAM,WAAW,CAAA;AAE/C,UAAU,eAAe;IACvB,cAAc,CAAC,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,sBAAsB,CAAC,CAAA;IACpE,UAAU,CAAC,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAAA;CACnD;AASD,wBAAgB,UAAU,CAAC,QAAQ,EAAE,aAAa,GAAG,eAAe,CAEnE;AAED,wBAAgB,cAAc,CAC5B,QAAQ,EAAE,aAAa,EACvB,GAAG,EAAE,cAAc,GAClB,OAAO,CAAC,sBAAsB,CAAC,CAEjC;AAED,wBAAgB,UAAU,CAAC,QAAQ,EAAE,aAAa,EAAE,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAE1F"}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Provider adapter dispatcher. Selects the right adapter by provider key and
3
+ * exposes a uniform `testConnection` / `listModels` surface to the catalog and
4
+ * route layers.
5
+ */
6
+ import * as anthropic from './anthropic.js';
7
+ import * as custom from './custom.js';
8
+ import * as openai from './openai.js';
9
+ import * as xai from './xai.js';
10
+ const ADAPTERS = {
11
+ openai,
12
+ anthropic,
13
+ xai,
14
+ custom,
15
+ };
16
+ export function getAdapter(provider) {
17
+ return ADAPTERS[provider] ?? custom;
18
+ }
19
+ export function testConnection(provider, ctx) {
20
+ return getAdapter(provider).testConnection(ctx);
21
+ }
22
+ export function listModels(provider, ctx) {
23
+ return getAdapter(provider).listModels(ctx);
24
+ }
25
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/ai/providers/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,KAAK,SAAS,MAAM,gBAAgB,CAAA;AAC3C,OAAO,KAAK,MAAM,MAAM,aAAa,CAAA;AAErC,OAAO,KAAK,MAAM,MAAM,aAAa,CAAA;AACrC,OAAO,KAAK,GAAG,MAAM,UAAU,CAAA;AAS/B,MAAM,QAAQ,GAA2C;IACvD,MAAM;IACN,SAAS;IACT,GAAG;IACH,MAAM;CACP,CAAA;AAED,MAAM,UAAU,UAAU,CAAC,QAAuB;IAChD,OAAO,QAAQ,CAAC,QAAQ,CAAC,IAAI,MAAM,CAAA;AACrC,CAAC;AAED,MAAM,UAAU,cAAc,CAC5B,QAAuB,EACvB,GAAmB;IAEnB,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC,cAAc,CAAC,GAAG,CAAC,CAAA;AACjD,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,QAAuB,EAAE,GAAmB;IACrE,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,CAAA;AAC7C,CAAC"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * OpenAI (and OpenAI-compatible) adapter. Uses the `/v1/models` listing
3
+ * endpoint with Bearer auth. Hostname is fixed (api.openai.com) so no SSRF
4
+ * validation is needed here.
5
+ */
6
+ import type { AIConnectionTestResult } from '../types.js';
7
+ import { type AdapterContext } from './http.js';
8
+ export declare function testConnection(ctx: AdapterContext): Promise<AIConnectionTestResult>;
9
+ export declare function listModels(ctx: AdapterContext): Promise<string[]>;
10
+ //# sourceMappingURL=openai.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"openai.d.ts","sourceRoot":"","sources":["../../../src/ai/providers/openai.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAA;AACzD,OAAO,EACL,KAAK,cAAc,EAKpB,MAAM,WAAW,CAAA;AAWlB,wBAAsB,cAAc,CAAC,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,sBAAsB,CAAC,CAqBzF;AAED,wBAAsB,UAAU,CAAC,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAQvE"}
@@ -0,0 +1,41 @@
1
+ /**
2
+ * OpenAI (and OpenAI-compatible) adapter. Uses the `/v1/models` listing
3
+ * endpoint with Bearer auth. Hostname is fixed (api.openai.com) so no SSRF
4
+ * validation is needed here.
5
+ */
6
+ import { extractModelIds, messageFromStatus, statusFromHttp, timedFetch, } from './http.js';
7
+ const OPENAI_BASE = 'https://api.openai.com/v1';
8
+ function headers(ctx) {
9
+ const h = { authorization: `Bearer ${ctx.apiKey}` };
10
+ if (ctx.organizationId)
11
+ h['openai-organization'] = ctx.organizationId;
12
+ if (ctx.projectId)
13
+ h['openai-project'] = ctx.projectId;
14
+ return h;
15
+ }
16
+ export async function testConnection(ctx) {
17
+ const testedAt = new Date().toISOString();
18
+ if (!ctx.apiKey) {
19
+ return { ok: false, status: 'needs_setup', message: messageFromStatus('needs_setup'), testedAt };
20
+ }
21
+ try {
22
+ const res = await timedFetch(`${OPENAI_BASE}/models`, { method: 'GET', headers: headers(ctx) }, ctx);
23
+ const status = statusFromHttp(res.status);
24
+ return { ok: status === 'connected', status, message: messageFromStatus(status), testedAt };
25
+ }
26
+ catch {
27
+ return {
28
+ ok: false,
29
+ status: 'provider_down',
30
+ message: messageFromStatus('provider_down'),
31
+ testedAt,
32
+ };
33
+ }
34
+ }
35
+ export async function listModels(ctx) {
36
+ const res = await timedFetch(`${OPENAI_BASE}/models`, { method: 'GET', headers: headers(ctx) }, ctx);
37
+ if (!res.ok)
38
+ throw new Error(`OpenAI model listing failed (${res.status})`);
39
+ return extractModelIds(await res.json());
40
+ }
41
+ //# sourceMappingURL=openai.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"openai.js","sourceRoot":"","sources":["../../../src/ai/providers/openai.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,EAEL,eAAe,EACf,iBAAiB,EACjB,cAAc,EACd,UAAU,GACX,MAAM,WAAW,CAAA;AAElB,MAAM,WAAW,GAAG,2BAA2B,CAAA;AAE/C,SAAS,OAAO,CAAC,GAAmB;IAClC,MAAM,CAAC,GAA2B,EAAE,aAAa,EAAE,UAAU,GAAG,CAAC,MAAM,EAAE,EAAE,CAAA;IAC3E,IAAI,GAAG,CAAC,cAAc;QAAE,CAAC,CAAC,qBAAqB,CAAC,GAAG,GAAG,CAAC,cAAc,CAAA;IACrE,IAAI,GAAG,CAAC,SAAS;QAAE,CAAC,CAAC,gBAAgB,CAAC,GAAG,GAAG,CAAC,SAAS,CAAA;IACtD,OAAO,CAAC,CAAA;AACV,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,GAAmB;IACtD,MAAM,QAAQ,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAA;IACzC,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC;QAChB,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,aAAa,EAAE,OAAO,EAAE,iBAAiB,CAAC,aAAa,CAAC,EAAE,QAAQ,EAAE,CAAA;IAClG,CAAC;IACD,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,UAAU,CAC1B,GAAG,WAAW,SAAS,EACvB,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,EAAE,EACxC,GAAG,CACJ,CAAA;QACD,MAAM,MAAM,GAAG,cAAc,CAAC,GAAG,CAAC,MAAM,CAAC,CAAA;QACzC,OAAO,EAAE,EAAE,EAAE,MAAM,KAAK,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,iBAAiB,CAAC,MAAM,CAAC,EAAE,QAAQ,EAAE,CAAA;IAC7F,CAAC;IAAC,MAAM,CAAC;QACP,OAAO;YACL,EAAE,EAAE,KAAK;YACT,MAAM,EAAE,eAAe;YACvB,OAAO,EAAE,iBAAiB,CAAC,eAAe,CAAC;YAC3C,QAAQ;SACT,CAAA;IACH,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,GAAmB;IAClD,MAAM,GAAG,GAAG,MAAM,UAAU,CAC1B,GAAG,WAAW,SAAS,EACvB,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,EAAE,EACxC,GAAG,CACJ,CAAA;IACD,IAAI,CAAC,GAAG,CAAC,EAAE;QAAE,MAAM,IAAI,KAAK,CAAC,gCAAgC,GAAG,CAAC,MAAM,GAAG,CAAC,CAAA;IAC3E,OAAO,eAAe,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC,CAAA;AAC1C,CAAC"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * xAI (Grok) adapter. xAI's API is OpenAI-compatible: `/v1/models` with Bearer
3
+ * auth. Hostname is fixed (api.x.ai).
4
+ */
5
+ import type { AIConnectionTestResult } from '../types.js';
6
+ import { type AdapterContext } from './http.js';
7
+ export declare function testConnection(ctx: AdapterContext): Promise<AIConnectionTestResult>;
8
+ export declare function listModels(ctx: AdapterContext): Promise<string[]>;
9
+ //# sourceMappingURL=xai.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"xai.d.ts","sourceRoot":"","sources":["../../../src/ai/providers/xai.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAA;AACzD,OAAO,EACL,KAAK,cAAc,EAKpB,MAAM,WAAW,CAAA;AAQlB,wBAAsB,cAAc,CAAC,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,sBAAsB,CAAC,CAqBzF;AAED,wBAAsB,UAAU,CAAC,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAIvE"}
@@ -0,0 +1,35 @@
1
+ /**
2
+ * xAI (Grok) adapter. xAI's API is OpenAI-compatible: `/v1/models` with Bearer
3
+ * auth. Hostname is fixed (api.x.ai).
4
+ */
5
+ import { extractModelIds, messageFromStatus, statusFromHttp, timedFetch, } from './http.js';
6
+ const XAI_BASE = 'https://api.x.ai/v1';
7
+ function headers(ctx) {
8
+ return { authorization: `Bearer ${ctx.apiKey}` };
9
+ }
10
+ export async function testConnection(ctx) {
11
+ const testedAt = new Date().toISOString();
12
+ if (!ctx.apiKey) {
13
+ return { ok: false, status: 'needs_setup', message: messageFromStatus('needs_setup'), testedAt };
14
+ }
15
+ try {
16
+ const res = await timedFetch(`${XAI_BASE}/models`, { method: 'GET', headers: headers(ctx) }, ctx);
17
+ const status = statusFromHttp(res.status);
18
+ return { ok: status === 'connected', status, message: messageFromStatus(status), testedAt };
19
+ }
20
+ catch {
21
+ return {
22
+ ok: false,
23
+ status: 'provider_down',
24
+ message: messageFromStatus('provider_down'),
25
+ testedAt,
26
+ };
27
+ }
28
+ }
29
+ export async function listModels(ctx) {
30
+ const res = await timedFetch(`${XAI_BASE}/models`, { method: 'GET', headers: headers(ctx) }, ctx);
31
+ if (!res.ok)
32
+ throw new Error(`xAI model listing failed (${res.status})`);
33
+ return extractModelIds(await res.json());
34
+ }
35
+ //# sourceMappingURL=xai.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"xai.js","sourceRoot":"","sources":["../../../src/ai/providers/xai.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAEL,eAAe,EACf,iBAAiB,EACjB,cAAc,EACd,UAAU,GACX,MAAM,WAAW,CAAA;AAElB,MAAM,QAAQ,GAAG,qBAAqB,CAAA;AAEtC,SAAS,OAAO,CAAC,GAAmB;IAClC,OAAO,EAAE,aAAa,EAAE,UAAU,GAAG,CAAC,MAAM,EAAE,EAAE,CAAA;AAClD,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,GAAmB;IACtD,MAAM,QAAQ,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAA;IACzC,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC;QAChB,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,aAAa,EAAE,OAAO,EAAE,iBAAiB,CAAC,aAAa,CAAC,EAAE,QAAQ,EAAE,CAAA;IAClG,CAAC;IACD,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,UAAU,CAC1B,GAAG,QAAQ,SAAS,EACpB,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,EAAE,EACxC,GAAG,CACJ,CAAA;QACD,MAAM,MAAM,GAAG,cAAc,CAAC,GAAG,CAAC,MAAM,CAAC,CAAA;QACzC,OAAO,EAAE,EAAE,EAAE,MAAM,KAAK,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,iBAAiB,CAAC,MAAM,CAAC,EAAE,QAAQ,EAAE,CAAA;IAC7F,CAAC;IAAC,MAAM,CAAC;QACP,OAAO;YACL,EAAE,EAAE,KAAK;YACT,MAAM,EAAE,eAAe;YACvB,OAAO,EAAE,iBAAiB,CAAC,eAAe,CAAC;YAC3C,QAAQ;SACT,CAAA;IACH,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,GAAmB;IAClD,MAAM,GAAG,GAAG,MAAM,UAAU,CAAC,GAAG,QAAQ,SAAS,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,EAAE,EAAE,GAAG,CAAC,CAAA;IACjG,IAAI,CAAC,GAAG,CAAC,EAAE;QAAE,MAAM,IAAI,KAAK,CAAC,6BAA6B,GAAG,CAAC,MAAM,GAAG,CAAC,CAAA;IACxE,OAAO,eAAe,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC,CAAA;AAC1C,CAAC"}
@@ -0,0 +1,161 @@
1
+ /**
2
+ * Shared types for the Settings > AI governance layer.
3
+ *
4
+ * Phases 1-2 cover provider connections (encrypted keys) and a dynamic,
5
+ * normalized model catalog. Feature config, budget, and data-policy shapes are
6
+ * declared here for forward-compatibility (enforcement + metering land in later
7
+ * phases) but only `features[].enabled` and `budget.monthlyTokenLimit` are
8
+ * wired into the UI for now.
9
+ */
10
+ /** Provider keys are stable code identifiers. `openai` covers OpenAI/ChatGPT. */
11
+ export type AIProviderKey = 'openai' | 'anthropic' | 'xai' | 'custom';
12
+ /** Where a provider's API key actually comes from at runtime. */
13
+ export type AIKeySource = 'environment' | 'database' | 'config';
14
+ /** Connection health surfaced in the UI (always rendered as text, not color-only). */
15
+ export type AIConnectionStatus = 'connected' | 'invalid_key' | 'rate_limited' | 'provider_down' | 'needs_setup' | 'unknown';
16
+ /** Availability of a catalog model relative to the connected account. */
17
+ export type AIModelStatus = 'available' | 'unavailable' | 'deprecated' | 'unknown';
18
+ export interface AIModelCapabilities {
19
+ text: boolean;
20
+ vision: boolean;
21
+ imageGeneration: boolean;
22
+ embeddings: boolean;
23
+ toolCalling: boolean;
24
+ structuredOutput: boolean;
25
+ streaming: boolean;
26
+ reasoning: boolean;
27
+ longContext: boolean;
28
+ }
29
+ export interface AIModelPricing {
30
+ inputPerMillion?: number;
31
+ outputPerMillion?: number;
32
+ image?: number;
33
+ search?: number;
34
+ }
35
+ /** Normalized model record (merged from live listing + curated metadata). */
36
+ export interface AIModel {
37
+ /** Stable internal id: `${provider}:${providerModelId}`. */
38
+ id: string;
39
+ provider: AIProviderKey;
40
+ providerModelId: string;
41
+ displayName: string;
42
+ description?: string;
43
+ status: AIModelStatus;
44
+ capabilities: AIModelCapabilities;
45
+ contextWindow?: number;
46
+ maxOutputTokens?: number;
47
+ inputModalities: string[];
48
+ outputModalities: string[];
49
+ pricing?: AIModelPricing;
50
+ aliases?: string[];
51
+ lastSyncedAt: string;
52
+ source: 'provider' | 'manual' | 'config';
53
+ metadata: Record<string, unknown>;
54
+ }
55
+ /**
56
+ * Stored provider connection. The encrypted key NEVER leaves the server — API
57
+ * responses use {@link AIProviderConnectionPublic}.
58
+ */
59
+ export interface AIProviderConnection {
60
+ id: string;
61
+ provider: AIProviderKey;
62
+ displayName: string;
63
+ enabled: boolean;
64
+ status: AIConnectionStatus;
65
+ /** Encrypted via `encryptSecret`. Absent when the key is env-managed. */
66
+ apiKeyEncrypted?: string;
67
+ apiKeyLast4?: string;
68
+ baseUrl?: string;
69
+ organizationId?: string;
70
+ projectId?: string;
71
+ lastTestedAt?: string;
72
+ lastSuccessfulRunAt?: string;
73
+ lastModelSyncAt?: string;
74
+ createdAt: string;
75
+ updatedAt: string;
76
+ updatedBy: string;
77
+ }
78
+ /** Client-safe provider view: no key material, source resolved dynamically. */
79
+ export type AIProviderConnectionPublic = Omit<AIProviderConnection, 'apiKeyEncrypted'> & {
80
+ apiKeySource: AIKeySource;
81
+ /** True when the key is env-managed and therefore not editable in the UI. */
82
+ keyManagedExternally: boolean;
83
+ hasKey: boolean;
84
+ };
85
+ export type AIFeatureCategory = 'seo' | 'media' | 'content' | 'forms' | 'security' | 'developer' | 'search';
86
+ export interface AIFeatureConfig {
87
+ key: string;
88
+ label: string;
89
+ description: string;
90
+ enabled: boolean;
91
+ category: AIFeatureCategory;
92
+ requiredCapabilities: string[];
93
+ providerId?: string;
94
+ modelId?: string;
95
+ fallbackModelIds?: string[];
96
+ approvalRequired: boolean;
97
+ allowBulkApply: boolean;
98
+ maxMonthlyTokens?: number;
99
+ maxRequestsPerDay?: number;
100
+ rolesAllowed: string[];
101
+ permissionsRequired: string[];
102
+ dataPolicyKey?: string;
103
+ }
104
+ export interface AIBudgetSettings {
105
+ monthlyTokenLimit?: number;
106
+ monthlyCostLimit?: number;
107
+ alertAtPercentages: number[];
108
+ disableWhenExceeded: boolean;
109
+ perFeatureLimits?: Record<string, number>;
110
+ perUserLimits?: Record<string, number>;
111
+ }
112
+ export interface AISettings {
113
+ defaultProviderId?: string;
114
+ defaultModelId?: string;
115
+ defaultTextModelId?: string;
116
+ defaultReasoningModelId?: string;
117
+ defaultVisionModelId?: string;
118
+ defaultEmbeddingModelId?: string;
119
+ defaultImageGenerationModelId?: string;
120
+ features: AIFeatureConfig[];
121
+ budget: AIBudgetSettings;
122
+ logsRetentionDays: number;
123
+ }
124
+ /**
125
+ * Cached, normalized model catalog keyed by provider connection id. Persisted in
126
+ * the `__ai_config__` document so the model selector renders without a live call.
127
+ */
128
+ export interface AICatalogEntry {
129
+ models: AIModel[];
130
+ lastSyncedAt: string;
131
+ /** True when the entry came from the curated fallback (no live listing). */
132
+ fromFallback: boolean;
133
+ }
134
+ /** Shape of the `data` blob on the `__ai_config__` Document. */
135
+ export interface AIConfigDocument {
136
+ providers: AIProviderConnection[];
137
+ settings: AISettings;
138
+ catalog?: Record<string, AICatalogEntry>;
139
+ updatedAt?: string;
140
+ updatedBy?: string;
141
+ }
142
+ /** Monthly usage summary for the budget meter (real counts; 0 until Phase 4). */
143
+ export interface AIUsageSummary {
144
+ totalTokens: number;
145
+ promptTokens: number;
146
+ completionTokens: number;
147
+ estimatedCost?: number;
148
+ monthlyTokenLimit?: number;
149
+ periodStart: string;
150
+ periodEnd: string;
151
+ runCount: number;
152
+ }
153
+ /** Result of an adapter connection test. */
154
+ export interface AIConnectionTestResult {
155
+ ok: boolean;
156
+ status: AIConnectionStatus;
157
+ /** Human-readable detail (safe to show; never contains the key). */
158
+ message: string;
159
+ testedAt: string;
160
+ }
161
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/ai/types.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Shared types for the Settings > AI governance layer.
3
+ *
4
+ * Phases 1-2 cover provider connections (encrypted keys) and a dynamic,
5
+ * normalized model catalog. Feature config, budget, and data-policy shapes are
6
+ * declared here for forward-compatibility (enforcement + metering land in later
7
+ * phases) but only `features[].enabled` and `budget.monthlyTokenLimit` are
8
+ * wired into the UI for now.
9
+ */
10
+ export {};
11
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/ai/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * AI usage aggregation.
3
+ *
4
+ * Until the dedicated per-run metering table lands (Phase 4), usage is derived
5
+ * from token totals already recorded in `actuate_audit_logs` (`details
6
+ * .totalTokensUsed` / `details.tokensUsed`). This returns REAL counts — it is 0
7
+ * when nothing has run, never a fabricated number.
8
+ */
9
+ import type { AIUsageSummary } from './types.js';
10
+ /**
11
+ * Sum token usage from audit-log entries within the period. Recognizes the
12
+ * fields current AI handlers write today and is tolerant of missing data.
13
+ */
14
+ export declare function getUsageSummary(db: unknown, period?: {
15
+ start?: Date;
16
+ end?: Date;
17
+ }): Promise<AIUsageSummary>;
18
+ //# sourceMappingURL=usage.d.ts.map