@netlify/ai 0.2.1
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/dist/bootstrap/main.cjs +144 -0
- package/dist/bootstrap/main.cjs.map +1 -0
- package/dist/bootstrap/main.d.cts +43 -0
- package/dist/bootstrap/main.d.ts +43 -0
- package/dist/bootstrap/main.js +116 -0
- package/dist/bootstrap/main.js.map +1 -0
- package/dist/main.cjs +2 -0
- package/dist/main.cjs.map +1 -0
- package/dist/main.d.cts +2 -0
- package/dist/main.d.ts +2 -0
- package/dist/main.js +1 -0
- package/dist/main.js.map +1 -0
- package/package.json +80 -0
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/bootstrap/main.ts
|
|
21
|
+
var main_exports = {};
|
|
22
|
+
__export(main_exports, {
|
|
23
|
+
fetchAIGatewayToken: () => fetchAIGatewayToken,
|
|
24
|
+
fetchAIProviders: () => fetchAIProviders,
|
|
25
|
+
parseAIGatewayContext: () => parseAIGatewayContext,
|
|
26
|
+
setupAIGateway: () => setupAIGateway
|
|
27
|
+
});
|
|
28
|
+
module.exports = __toCommonJS(main_exports);
|
|
29
|
+
var isValidTokenResponse = (data) => {
|
|
30
|
+
return typeof data === "object" && data !== null && typeof data.token === "string" && typeof data.url === "string";
|
|
31
|
+
};
|
|
32
|
+
var isValidProvidersResponse = (data) => {
|
|
33
|
+
return typeof data === "object" && data !== null && typeof data.providers === "object" && data.providers !== null;
|
|
34
|
+
};
|
|
35
|
+
var fetchAIProviders = async ({ api }) => {
|
|
36
|
+
try {
|
|
37
|
+
if (!api.accessToken) {
|
|
38
|
+
return [];
|
|
39
|
+
}
|
|
40
|
+
const url = `${api.scheme}://${api.host}/api/v1/ai-gateway/providers`;
|
|
41
|
+
const response = await fetch(url, {
|
|
42
|
+
method: "GET",
|
|
43
|
+
headers: {
|
|
44
|
+
Authorization: `Bearer ${api.accessToken}`,
|
|
45
|
+
"Content-Type": "application/json"
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
if (!response.ok) {
|
|
49
|
+
if (response.status === 404) {
|
|
50
|
+
return [];
|
|
51
|
+
}
|
|
52
|
+
throw new Error(`HTTP ${String(response.status)}: ${response.statusText}`);
|
|
53
|
+
}
|
|
54
|
+
const data = await response.json();
|
|
55
|
+
if (!isValidProvidersResponse(data)) {
|
|
56
|
+
throw new Error("Invalid providers response format");
|
|
57
|
+
}
|
|
58
|
+
const envVars = [];
|
|
59
|
+
for (const provider of Object.values(data.providers)) {
|
|
60
|
+
envVars.push({
|
|
61
|
+
key: provider.token_env_var,
|
|
62
|
+
url: provider.url_env_var
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
return envVars;
|
|
66
|
+
} catch (error) {
|
|
67
|
+
console.warn(`Failed to fetch AI providers: ${error instanceof Error ? error.message : String(error)}`);
|
|
68
|
+
return [];
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
var fetchAIGatewayToken = async ({
|
|
72
|
+
api,
|
|
73
|
+
siteId
|
|
74
|
+
}) => {
|
|
75
|
+
try {
|
|
76
|
+
if (!api.accessToken) {
|
|
77
|
+
return null;
|
|
78
|
+
}
|
|
79
|
+
const url = `${api.scheme}://${api.host}/api/v1/sites/${siteId}/ai-gateway/token`;
|
|
80
|
+
const response = await fetch(url, {
|
|
81
|
+
method: "GET",
|
|
82
|
+
headers: {
|
|
83
|
+
Authorization: `Bearer ${api.accessToken}`,
|
|
84
|
+
"Content-Type": "application/json"
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
if (!response.ok) {
|
|
88
|
+
if (response.status === 404) {
|
|
89
|
+
return null;
|
|
90
|
+
}
|
|
91
|
+
throw new Error(`HTTP ${String(response.status)}: ${response.statusText}`);
|
|
92
|
+
}
|
|
93
|
+
const data = await response.json();
|
|
94
|
+
if (!isValidTokenResponse(data)) {
|
|
95
|
+
throw new Error("Invalid response: missing token or url");
|
|
96
|
+
}
|
|
97
|
+
return {
|
|
98
|
+
token: data.token,
|
|
99
|
+
url: data.url
|
|
100
|
+
};
|
|
101
|
+
} catch (error) {
|
|
102
|
+
console.warn(
|
|
103
|
+
`Failed to fetch AI Gateway token for site ${siteId}: ${error instanceof Error ? error.message : String(error)}`
|
|
104
|
+
);
|
|
105
|
+
return null;
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
var setupAIGateway = async (config) => {
|
|
109
|
+
const { api, env, siteID, siteURL } = config;
|
|
110
|
+
if (siteID && siteID !== "unlinked" && siteURL) {
|
|
111
|
+
const [aiGatewayToken, envVars] = await Promise.all([
|
|
112
|
+
fetchAIGatewayToken({ api, siteId: siteID }),
|
|
113
|
+
fetchAIProviders({ api })
|
|
114
|
+
]);
|
|
115
|
+
if (aiGatewayToken) {
|
|
116
|
+
const aiGatewayContext = JSON.stringify({
|
|
117
|
+
token: aiGatewayToken.token,
|
|
118
|
+
url: `${siteURL}/.netlify/ai`,
|
|
119
|
+
envVars
|
|
120
|
+
});
|
|
121
|
+
const base64Context = Buffer.from(aiGatewayContext).toString("base64");
|
|
122
|
+
env.AI_GATEWAY = { sources: ["internal"], value: base64Context };
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
};
|
|
126
|
+
var parseAIGatewayContext = (aiGatewayValue) => {
|
|
127
|
+
try {
|
|
128
|
+
if (aiGatewayValue) {
|
|
129
|
+
const decodedContext = Buffer.from(aiGatewayValue, "base64").toString("utf8");
|
|
130
|
+
const aiGatewayContext = JSON.parse(decodedContext);
|
|
131
|
+
return aiGatewayContext;
|
|
132
|
+
}
|
|
133
|
+
} catch {
|
|
134
|
+
}
|
|
135
|
+
return void 0;
|
|
136
|
+
};
|
|
137
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
138
|
+
0 && (module.exports = {
|
|
139
|
+
fetchAIGatewayToken,
|
|
140
|
+
fetchAIProviders,
|
|
141
|
+
parseAIGatewayContext,
|
|
142
|
+
setupAIGateway
|
|
143
|
+
});
|
|
144
|
+
//# sourceMappingURL=main.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/bootstrap/main.ts"],"sourcesContent":["import type { NetlifyAPI } from '@netlify/api'\n\nexport interface AIGatewayContext {\n token: string\n url: string\n}\n\nexport interface AIGatewayConfig {\n api: NetlifyAPI\n env: Record<string, { sources: string[]; value: string }>\n siteID: string | undefined\n siteURL: string | undefined\n}\n\nexport interface AIProviderEnvVar {\n key: string\n url: string\n}\n\nexport interface AIGatewayTokenResponse {\n token: string\n url: string\n envVars?: AIProviderEnvVar[]\n}\n\nexport interface AIProvider {\n token_env_var: string\n url_env_var: string\n models: string[]\n}\n\nexport interface ProvidersResponse {\n providers: Record<string, AIProvider>\n}\n\nconst isValidTokenResponse = (data: unknown): data is AIGatewayTokenResponse => {\n return (\n typeof data === 'object' &&\n data !== null &&\n typeof (data as Record<string, unknown>).token === 'string' &&\n typeof (data as Record<string, unknown>).url === 'string'\n )\n}\n\nconst isValidProvidersResponse = (data: unknown): data is ProvidersResponse => {\n return (\n typeof data === 'object' &&\n data !== null &&\n typeof (data as Record<string, unknown>).providers === 'object' &&\n (data as Record<string, unknown>).providers !== null\n )\n}\n\nexport const fetchAIProviders = async ({ api }: { api: NetlifyAPI }): Promise<AIProviderEnvVar[]> => {\n try {\n if (!api.accessToken) {\n return []\n }\n\n const url = `${api.scheme}://${api.host}/api/v1/ai-gateway/providers`\n\n const response = await fetch(url, {\n method: 'GET',\n headers: {\n Authorization: `Bearer ${api.accessToken}`,\n 'Content-Type': 'application/json',\n },\n })\n\n if (!response.ok) {\n if (response.status === 404) {\n return []\n }\n throw new Error(`HTTP ${String(response.status)}: ${response.statusText}`)\n }\n\n const data: unknown = await response.json()\n\n if (!isValidProvidersResponse(data)) {\n throw new Error('Invalid providers response format')\n }\n\n const envVars: AIProviderEnvVar[] = []\n\n for (const provider of Object.values(data.providers)) {\n envVars.push({\n key: provider.token_env_var,\n url: provider.url_env_var,\n })\n }\n\n return envVars\n } catch (error) {\n console.warn(`Failed to fetch AI providers: ${error instanceof Error ? error.message : String(error)}`)\n return []\n }\n}\n\nexport const fetchAIGatewayToken = async ({\n api,\n siteId,\n}: {\n api: NetlifyAPI\n siteId: string\n}): Promise<AIGatewayTokenResponse | null> => {\n try {\n if (!api.accessToken) {\n return null\n }\n\n // TODO: update once available in openApi\n const url = `${api.scheme}://${api.host}/api/v1/sites/${siteId}/ai-gateway/token`\n\n const response = await fetch(url, {\n method: 'GET',\n headers: {\n Authorization: `Bearer ${api.accessToken}`,\n 'Content-Type': 'application/json',\n },\n })\n\n if (!response.ok) {\n if (response.status === 404) {\n return null\n }\n throw new Error(`HTTP ${String(response.status)}: ${response.statusText}`)\n }\n\n const data: unknown = await response.json()\n\n if (!isValidTokenResponse(data)) {\n throw new Error('Invalid response: missing token or url')\n }\n\n return {\n token: data.token,\n url: data.url,\n }\n } catch (error) {\n console.warn(\n `Failed to fetch AI Gateway token for site ${siteId}: ${error instanceof Error ? error.message : String(error)}`,\n )\n return null\n }\n}\n\nexport const setupAIGateway = async (config: AIGatewayConfig): Promise<void> => {\n const { api, env, siteID, siteURL } = config\n\n if (siteID && siteID !== 'unlinked' && siteURL) {\n const [aiGatewayToken, envVars] = await Promise.all([\n fetchAIGatewayToken({ api, siteId: siteID }),\n fetchAIProviders({ api }),\n ])\n\n if (aiGatewayToken) {\n const aiGatewayContext = JSON.stringify({\n token: aiGatewayToken.token,\n url: `${siteURL}/.netlify/ai`,\n envVars,\n })\n const base64Context = Buffer.from(aiGatewayContext).toString('base64')\n env.AI_GATEWAY = { sources: ['internal'], value: base64Context }\n }\n }\n}\n\nexport const parseAIGatewayContext = (aiGatewayValue?: string): AIGatewayTokenResponse | undefined => {\n try {\n if (aiGatewayValue) {\n const decodedContext = Buffer.from(aiGatewayValue, 'base64').toString('utf8')\n const aiGatewayContext = JSON.parse(decodedContext) as AIGatewayTokenResponse\n return aiGatewayContext\n }\n } catch {\n // Ignore parsing errors - AI Gateway is optional\n }\n return undefined\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { NetlifyAPI } from '@netlify/api';
|
|
2
|
+
|
|
3
|
+
interface AIGatewayContext {
|
|
4
|
+
token: string;
|
|
5
|
+
url: string;
|
|
6
|
+
}
|
|
7
|
+
interface AIGatewayConfig {
|
|
8
|
+
api: NetlifyAPI;
|
|
9
|
+
env: Record<string, {
|
|
10
|
+
sources: string[];
|
|
11
|
+
value: string;
|
|
12
|
+
}>;
|
|
13
|
+
siteID: string | undefined;
|
|
14
|
+
siteURL: string | undefined;
|
|
15
|
+
}
|
|
16
|
+
interface AIProviderEnvVar {
|
|
17
|
+
key: string;
|
|
18
|
+
url: string;
|
|
19
|
+
}
|
|
20
|
+
interface AIGatewayTokenResponse {
|
|
21
|
+
token: string;
|
|
22
|
+
url: string;
|
|
23
|
+
envVars?: AIProviderEnvVar[];
|
|
24
|
+
}
|
|
25
|
+
interface AIProvider {
|
|
26
|
+
token_env_var: string;
|
|
27
|
+
url_env_var: string;
|
|
28
|
+
models: string[];
|
|
29
|
+
}
|
|
30
|
+
interface ProvidersResponse {
|
|
31
|
+
providers: Record<string, AIProvider>;
|
|
32
|
+
}
|
|
33
|
+
declare const fetchAIProviders: ({ api }: {
|
|
34
|
+
api: NetlifyAPI;
|
|
35
|
+
}) => Promise<AIProviderEnvVar[]>;
|
|
36
|
+
declare const fetchAIGatewayToken: ({ api, siteId, }: {
|
|
37
|
+
api: NetlifyAPI;
|
|
38
|
+
siteId: string;
|
|
39
|
+
}) => Promise<AIGatewayTokenResponse | null>;
|
|
40
|
+
declare const setupAIGateway: (config: AIGatewayConfig) => Promise<void>;
|
|
41
|
+
declare const parseAIGatewayContext: (aiGatewayValue?: string) => AIGatewayTokenResponse | undefined;
|
|
42
|
+
|
|
43
|
+
export { type AIGatewayConfig, type AIGatewayContext, type AIGatewayTokenResponse, type AIProvider, type AIProviderEnvVar, type ProvidersResponse, fetchAIGatewayToken, fetchAIProviders, parseAIGatewayContext, setupAIGateway };
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { NetlifyAPI } from '@netlify/api';
|
|
2
|
+
|
|
3
|
+
interface AIGatewayContext {
|
|
4
|
+
token: string;
|
|
5
|
+
url: string;
|
|
6
|
+
}
|
|
7
|
+
interface AIGatewayConfig {
|
|
8
|
+
api: NetlifyAPI;
|
|
9
|
+
env: Record<string, {
|
|
10
|
+
sources: string[];
|
|
11
|
+
value: string;
|
|
12
|
+
}>;
|
|
13
|
+
siteID: string | undefined;
|
|
14
|
+
siteURL: string | undefined;
|
|
15
|
+
}
|
|
16
|
+
interface AIProviderEnvVar {
|
|
17
|
+
key: string;
|
|
18
|
+
url: string;
|
|
19
|
+
}
|
|
20
|
+
interface AIGatewayTokenResponse {
|
|
21
|
+
token: string;
|
|
22
|
+
url: string;
|
|
23
|
+
envVars?: AIProviderEnvVar[];
|
|
24
|
+
}
|
|
25
|
+
interface AIProvider {
|
|
26
|
+
token_env_var: string;
|
|
27
|
+
url_env_var: string;
|
|
28
|
+
models: string[];
|
|
29
|
+
}
|
|
30
|
+
interface ProvidersResponse {
|
|
31
|
+
providers: Record<string, AIProvider>;
|
|
32
|
+
}
|
|
33
|
+
declare const fetchAIProviders: ({ api }: {
|
|
34
|
+
api: NetlifyAPI;
|
|
35
|
+
}) => Promise<AIProviderEnvVar[]>;
|
|
36
|
+
declare const fetchAIGatewayToken: ({ api, siteId, }: {
|
|
37
|
+
api: NetlifyAPI;
|
|
38
|
+
siteId: string;
|
|
39
|
+
}) => Promise<AIGatewayTokenResponse | null>;
|
|
40
|
+
declare const setupAIGateway: (config: AIGatewayConfig) => Promise<void>;
|
|
41
|
+
declare const parseAIGatewayContext: (aiGatewayValue?: string) => AIGatewayTokenResponse | undefined;
|
|
42
|
+
|
|
43
|
+
export { type AIGatewayConfig, type AIGatewayContext, type AIGatewayTokenResponse, type AIProvider, type AIProviderEnvVar, type ProvidersResponse, fetchAIGatewayToken, fetchAIProviders, parseAIGatewayContext, setupAIGateway };
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
// src/bootstrap/main.ts
|
|
2
|
+
var isValidTokenResponse = (data) => {
|
|
3
|
+
return typeof data === "object" && data !== null && typeof data.token === "string" && typeof data.url === "string";
|
|
4
|
+
};
|
|
5
|
+
var isValidProvidersResponse = (data) => {
|
|
6
|
+
return typeof data === "object" && data !== null && typeof data.providers === "object" && data.providers !== null;
|
|
7
|
+
};
|
|
8
|
+
var fetchAIProviders = async ({ api }) => {
|
|
9
|
+
try {
|
|
10
|
+
if (!api.accessToken) {
|
|
11
|
+
return [];
|
|
12
|
+
}
|
|
13
|
+
const url = `${api.scheme}://${api.host}/api/v1/ai-gateway/providers`;
|
|
14
|
+
const response = await fetch(url, {
|
|
15
|
+
method: "GET",
|
|
16
|
+
headers: {
|
|
17
|
+
Authorization: `Bearer ${api.accessToken}`,
|
|
18
|
+
"Content-Type": "application/json"
|
|
19
|
+
}
|
|
20
|
+
});
|
|
21
|
+
if (!response.ok) {
|
|
22
|
+
if (response.status === 404) {
|
|
23
|
+
return [];
|
|
24
|
+
}
|
|
25
|
+
throw new Error(`HTTP ${String(response.status)}: ${response.statusText}`);
|
|
26
|
+
}
|
|
27
|
+
const data = await response.json();
|
|
28
|
+
if (!isValidProvidersResponse(data)) {
|
|
29
|
+
throw new Error("Invalid providers response format");
|
|
30
|
+
}
|
|
31
|
+
const envVars = [];
|
|
32
|
+
for (const provider of Object.values(data.providers)) {
|
|
33
|
+
envVars.push({
|
|
34
|
+
key: provider.token_env_var,
|
|
35
|
+
url: provider.url_env_var
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
return envVars;
|
|
39
|
+
} catch (error) {
|
|
40
|
+
console.warn(`Failed to fetch AI providers: ${error instanceof Error ? error.message : String(error)}`);
|
|
41
|
+
return [];
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
var fetchAIGatewayToken = async ({
|
|
45
|
+
api,
|
|
46
|
+
siteId
|
|
47
|
+
}) => {
|
|
48
|
+
try {
|
|
49
|
+
if (!api.accessToken) {
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
52
|
+
const url = `${api.scheme}://${api.host}/api/v1/sites/${siteId}/ai-gateway/token`;
|
|
53
|
+
const response = await fetch(url, {
|
|
54
|
+
method: "GET",
|
|
55
|
+
headers: {
|
|
56
|
+
Authorization: `Bearer ${api.accessToken}`,
|
|
57
|
+
"Content-Type": "application/json"
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
if (!response.ok) {
|
|
61
|
+
if (response.status === 404) {
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
64
|
+
throw new Error(`HTTP ${String(response.status)}: ${response.statusText}`);
|
|
65
|
+
}
|
|
66
|
+
const data = await response.json();
|
|
67
|
+
if (!isValidTokenResponse(data)) {
|
|
68
|
+
throw new Error("Invalid response: missing token or url");
|
|
69
|
+
}
|
|
70
|
+
return {
|
|
71
|
+
token: data.token,
|
|
72
|
+
url: data.url
|
|
73
|
+
};
|
|
74
|
+
} catch (error) {
|
|
75
|
+
console.warn(
|
|
76
|
+
`Failed to fetch AI Gateway token for site ${siteId}: ${error instanceof Error ? error.message : String(error)}`
|
|
77
|
+
);
|
|
78
|
+
return null;
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
var setupAIGateway = async (config) => {
|
|
82
|
+
const { api, env, siteID, siteURL } = config;
|
|
83
|
+
if (siteID && siteID !== "unlinked" && siteURL) {
|
|
84
|
+
const [aiGatewayToken, envVars] = await Promise.all([
|
|
85
|
+
fetchAIGatewayToken({ api, siteId: siteID }),
|
|
86
|
+
fetchAIProviders({ api })
|
|
87
|
+
]);
|
|
88
|
+
if (aiGatewayToken) {
|
|
89
|
+
const aiGatewayContext = JSON.stringify({
|
|
90
|
+
token: aiGatewayToken.token,
|
|
91
|
+
url: `${siteURL}/.netlify/ai`,
|
|
92
|
+
envVars
|
|
93
|
+
});
|
|
94
|
+
const base64Context = Buffer.from(aiGatewayContext).toString("base64");
|
|
95
|
+
env.AI_GATEWAY = { sources: ["internal"], value: base64Context };
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
};
|
|
99
|
+
var parseAIGatewayContext = (aiGatewayValue) => {
|
|
100
|
+
try {
|
|
101
|
+
if (aiGatewayValue) {
|
|
102
|
+
const decodedContext = Buffer.from(aiGatewayValue, "base64").toString("utf8");
|
|
103
|
+
const aiGatewayContext = JSON.parse(decodedContext);
|
|
104
|
+
return aiGatewayContext;
|
|
105
|
+
}
|
|
106
|
+
} catch {
|
|
107
|
+
}
|
|
108
|
+
return void 0;
|
|
109
|
+
};
|
|
110
|
+
export {
|
|
111
|
+
fetchAIGatewayToken,
|
|
112
|
+
fetchAIProviders,
|
|
113
|
+
parseAIGatewayContext,
|
|
114
|
+
setupAIGateway
|
|
115
|
+
};
|
|
116
|
+
//# sourceMappingURL=main.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/bootstrap/main.ts"],"sourcesContent":["import type { NetlifyAPI } from '@netlify/api'\n\nexport interface AIGatewayContext {\n token: string\n url: string\n}\n\nexport interface AIGatewayConfig {\n api: NetlifyAPI\n env: Record<string, { sources: string[]; value: string }>\n siteID: string | undefined\n siteURL: string | undefined\n}\n\nexport interface AIProviderEnvVar {\n key: string\n url: string\n}\n\nexport interface AIGatewayTokenResponse {\n token: string\n url: string\n envVars?: AIProviderEnvVar[]\n}\n\nexport interface AIProvider {\n token_env_var: string\n url_env_var: string\n models: string[]\n}\n\nexport interface ProvidersResponse {\n providers: Record<string, AIProvider>\n}\n\nconst isValidTokenResponse = (data: unknown): data is AIGatewayTokenResponse => {\n return (\n typeof data === 'object' &&\n data !== null &&\n typeof (data as Record<string, unknown>).token === 'string' &&\n typeof (data as Record<string, unknown>).url === 'string'\n )\n}\n\nconst isValidProvidersResponse = (data: unknown): data is ProvidersResponse => {\n return (\n typeof data === 'object' &&\n data !== null &&\n typeof (data as Record<string, unknown>).providers === 'object' &&\n (data as Record<string, unknown>).providers !== null\n )\n}\n\nexport const fetchAIProviders = async ({ api }: { api: NetlifyAPI }): Promise<AIProviderEnvVar[]> => {\n try {\n if (!api.accessToken) {\n return []\n }\n\n const url = `${api.scheme}://${api.host}/api/v1/ai-gateway/providers`\n\n const response = await fetch(url, {\n method: 'GET',\n headers: {\n Authorization: `Bearer ${api.accessToken}`,\n 'Content-Type': 'application/json',\n },\n })\n\n if (!response.ok) {\n if (response.status === 404) {\n return []\n }\n throw new Error(`HTTP ${String(response.status)}: ${response.statusText}`)\n }\n\n const data: unknown = await response.json()\n\n if (!isValidProvidersResponse(data)) {\n throw new Error('Invalid providers response format')\n }\n\n const envVars: AIProviderEnvVar[] = []\n\n for (const provider of Object.values(data.providers)) {\n envVars.push({\n key: provider.token_env_var,\n url: provider.url_env_var,\n })\n }\n\n return envVars\n } catch (error) {\n console.warn(`Failed to fetch AI providers: ${error instanceof Error ? error.message : String(error)}`)\n return []\n }\n}\n\nexport const fetchAIGatewayToken = async ({\n api,\n siteId,\n}: {\n api: NetlifyAPI\n siteId: string\n}): Promise<AIGatewayTokenResponse | null> => {\n try {\n if (!api.accessToken) {\n return null\n }\n\n // TODO: update once available in openApi\n const url = `${api.scheme}://${api.host}/api/v1/sites/${siteId}/ai-gateway/token`\n\n const response = await fetch(url, {\n method: 'GET',\n headers: {\n Authorization: `Bearer ${api.accessToken}`,\n 'Content-Type': 'application/json',\n },\n })\n\n if (!response.ok) {\n if (response.status === 404) {\n return null\n }\n throw new Error(`HTTP ${String(response.status)}: ${response.statusText}`)\n }\n\n const data: unknown = await response.json()\n\n if (!isValidTokenResponse(data)) {\n throw new Error('Invalid response: missing token or url')\n }\n\n return {\n token: data.token,\n url: data.url,\n }\n } catch (error) {\n console.warn(\n `Failed to fetch AI Gateway token for site ${siteId}: ${error instanceof Error ? error.message : String(error)}`,\n )\n return null\n }\n}\n\nexport const setupAIGateway = async (config: AIGatewayConfig): Promise<void> => {\n const { api, env, siteID, siteURL } = config\n\n if (siteID && siteID !== 'unlinked' && siteURL) {\n const [aiGatewayToken, envVars] = await Promise.all([\n fetchAIGatewayToken({ api, siteId: siteID }),\n fetchAIProviders({ api }),\n ])\n\n if (aiGatewayToken) {\n const aiGatewayContext = JSON.stringify({\n token: aiGatewayToken.token,\n url: `${siteURL}/.netlify/ai`,\n envVars,\n })\n const base64Context = Buffer.from(aiGatewayContext).toString('base64')\n env.AI_GATEWAY = { sources: ['internal'], value: base64Context }\n }\n }\n}\n\nexport const parseAIGatewayContext = (aiGatewayValue?: string): AIGatewayTokenResponse | undefined => {\n try {\n if (aiGatewayValue) {\n const decodedContext = Buffer.from(aiGatewayValue, 'base64').toString('utf8')\n const aiGatewayContext = JSON.parse(decodedContext) as AIGatewayTokenResponse\n return aiGatewayContext\n }\n } catch {\n // Ignore parsing errors - AI Gateway is optional\n }\n return undefined\n}\n"],"mappings":"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","names":[]}
|
package/dist/main.cjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
package/dist/main.d.cts
ADDED
package/dist/main.d.ts
ADDED
package/dist/main.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
//# sourceMappingURL=main.js.map
|
package/dist/main.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
package/package.json
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@netlify/ai",
|
|
3
|
+
"version": "0.2.1",
|
|
4
|
+
"description": "TypeScript utilities for interacting with Netlify AI features",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"engines": {
|
|
7
|
+
"node": ">=20.6.1"
|
|
8
|
+
},
|
|
9
|
+
"main": "./dist/main.cjs",
|
|
10
|
+
"module": "./dist/main.js",
|
|
11
|
+
"types": "./dist/main.d.ts",
|
|
12
|
+
"exports": {
|
|
13
|
+
".": {
|
|
14
|
+
"require": {
|
|
15
|
+
"types": "./dist/main.d.cts",
|
|
16
|
+
"default": "./dist/main.cjs"
|
|
17
|
+
},
|
|
18
|
+
"import": {
|
|
19
|
+
"types": "./dist/main.d.ts",
|
|
20
|
+
"default": "./dist/main.js"
|
|
21
|
+
},
|
|
22
|
+
"default": {
|
|
23
|
+
"types": "./dist/main.d.ts",
|
|
24
|
+
"default": "./dist/main.js"
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
"./package.json": "./package.json",
|
|
28
|
+
"./bootstrap": {
|
|
29
|
+
"require": {
|
|
30
|
+
"types": "./dist/bootstrap/main.d.cts",
|
|
31
|
+
"default": "./dist/bootstrap/main.cjs"
|
|
32
|
+
},
|
|
33
|
+
"import": {
|
|
34
|
+
"types": "./dist/bootstrap/main.d.ts",
|
|
35
|
+
"default": "./dist/bootstrap/main.js"
|
|
36
|
+
},
|
|
37
|
+
"default": {
|
|
38
|
+
"types": "./dist/bootstrap/main.d.ts",
|
|
39
|
+
"default": "./dist/bootstrap/main.js"
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
"files": [
|
|
44
|
+
"dist/**/*"
|
|
45
|
+
],
|
|
46
|
+
"scripts": {
|
|
47
|
+
"build": "tsup-node",
|
|
48
|
+
"dev": "tsup-node --watch",
|
|
49
|
+
"prepack": "npm run build",
|
|
50
|
+
"test": "run-s build test:ci",
|
|
51
|
+
"test:dev": "run-s build test:dev:*",
|
|
52
|
+
"test:ci": "run-s build test:ci:*",
|
|
53
|
+
"test:dev:vitest": "vitest",
|
|
54
|
+
"test:dev:vitest:watch": "vitest watch",
|
|
55
|
+
"test:ci:vitest": "vitest run",
|
|
56
|
+
"publint": "npx -y publint --strict"
|
|
57
|
+
},
|
|
58
|
+
"dependencies": {
|
|
59
|
+
"@netlify/api": "^14.0.4"
|
|
60
|
+
},
|
|
61
|
+
"devDependencies": {
|
|
62
|
+
"@types/node": "20.14.15",
|
|
63
|
+
"npm-run-all2": "^7.0.2",
|
|
64
|
+
"tsup": "8.5.0",
|
|
65
|
+
"typescript": "5.9.2",
|
|
66
|
+
"vitest": "^3.0.0"
|
|
67
|
+
},
|
|
68
|
+
"peerDependencies": {
|
|
69
|
+
"@netlify/api": ">=14.0.0"
|
|
70
|
+
},
|
|
71
|
+
"repository": {
|
|
72
|
+
"type": "git",
|
|
73
|
+
"url": "https://github.com/netlify/primitives.git",
|
|
74
|
+
"directory": "packages/ai"
|
|
75
|
+
},
|
|
76
|
+
"homepage": "https://github.com/netlify/primitives/tree/main/packages/ai",
|
|
77
|
+
"bugs": {
|
|
78
|
+
"url": "https://github.com/netlify/primitives/issues"
|
|
79
|
+
}
|
|
80
|
+
}
|