@netlify/ai 0.2.1 → 0.3.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.
@@ -26,41 +26,23 @@ __export(main_exports, {
26
26
  setupAIGateway: () => setupAIGateway
27
27
  });
28
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
29
  var fetchAIProviders = async ({ api }) => {
36
30
  try {
37
31
  if (!api.accessToken) {
38
32
  return [];
39
33
  }
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");
34
+ const data = await api.getAIGatewayProviders();
35
+ if (!data.providers) {
36
+ return [];
57
37
  }
58
38
  const envVars = [];
59
39
  for (const provider of Object.values(data.providers)) {
60
- envVars.push({
61
- key: provider.token_env_var,
62
- url: provider.url_env_var
63
- });
40
+ if (provider.token_env_var && provider.url_env_var) {
41
+ envVars.push({
42
+ key: provider.token_env_var,
43
+ url: provider.url_env_var
44
+ });
45
+ }
64
46
  }
65
47
  return envVars;
66
48
  } catch (error) {
@@ -76,23 +58,9 @@ var fetchAIGatewayToken = async ({
76
58
  if (!api.accessToken) {
77
59
  return null;
78
60
  }
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");
61
+ const data = await api.getAIGatewayToken({ site_id: siteId });
62
+ if (!data.token || !data.url) {
63
+ return null;
96
64
  }
97
65
  return {
98
66
  token: data.token,
@@ -1 +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":[]}
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 const fetchAIProviders = async ({ api }: { api: NetlifyAPI }): Promise<AIProviderEnvVar[]> => {\n try {\n if (!api.accessToken) {\n return []\n }\n\n const data = await api.getAIGatewayProviders()\n\n if (!data.providers) {\n return []\n }\n\n const envVars: AIProviderEnvVar[] = []\n\n for (const provider of Object.values(data.providers)) {\n if (provider.token_env_var && provider.url_env_var) {\n envVars.push({\n key: provider.token_env_var,\n url: provider.url_env_var,\n })\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 const data = await api.getAIGatewayToken({ site_id: siteId })\n\n if (!data.token || !data.url) {\n return null\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":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAyBO,IAAM,mBAAmB,OAAO,EAAE,IAAI,MAAwD;AACnG,MAAI;AACF,QAAI,CAAC,IAAI,aAAa;AACpB,aAAO,CAAC;AAAA,IACV;AAEA,UAAM,OAAO,MAAM,IAAI,sBAAsB;AAE7C,QAAI,CAAC,KAAK,WAAW;AACnB,aAAO,CAAC;AAAA,IACV;AAEA,UAAM,UAA8B,CAAC;AAErC,eAAW,YAAY,OAAO,OAAO,KAAK,SAAS,GAAG;AACpD,UAAI,SAAS,iBAAiB,SAAS,aAAa;AAClD,gBAAQ,KAAK;AAAA,UACX,KAAK,SAAS;AAAA,UACd,KAAK,SAAS;AAAA,QAChB,CAAC;AAAA,MACH;AAAA,IACF;AAEA,WAAO;AAAA,EACT,SAAS,OAAO;AACd,YAAQ,KAAK,iCAAiC,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC,EAAE;AACtG,WAAO,CAAC;AAAA,EACV;AACF;AAEO,IAAM,sBAAsB,OAAO;AAAA,EACxC;AAAA,EACA;AACF,MAG8C;AAC5C,MAAI;AACF,QAAI,CAAC,IAAI,aAAa;AACpB,aAAO;AAAA,IACT;AAEA,UAAM,OAAO,MAAM,IAAI,kBAAkB,EAAE,SAAS,OAAO,CAAC;AAE5D,QAAI,CAAC,KAAK,SAAS,CAAC,KAAK,KAAK;AAC5B,aAAO;AAAA,IACT;AAEA,WAAO;AAAA,MACL,OAAO,KAAK;AAAA,MACZ,KAAK,KAAK;AAAA,IACZ;AAAA,EACF,SAAS,OAAO;AACd,YAAQ;AAAA,MACN,6CAA6C,MAAM,KAAK,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC;AAAA,IAChH;AACA,WAAO;AAAA,EACT;AACF;AAEO,IAAM,iBAAiB,OAAO,WAA2C;AAC9E,QAAM,EAAE,KAAK,KAAK,QAAQ,QAAQ,IAAI;AAEtC,MAAI,UAAU,WAAW,cAAc,SAAS;AAC9C,UAAM,CAAC,gBAAgB,OAAO,IAAI,MAAM,QAAQ,IAAI;AAAA,MAClD,oBAAoB,EAAE,KAAK,QAAQ,OAAO,CAAC;AAAA,MAC3C,iBAAiB,EAAE,IAAI,CAAC;AAAA,IAC1B,CAAC;AAED,QAAI,gBAAgB;AAClB,YAAM,mBAAmB,KAAK,UAAU;AAAA,QACtC,OAAO,eAAe;AAAA,QACtB,KAAK,GAAG,OAAO;AAAA,QACf;AAAA,MACF,CAAC;AACD,YAAM,gBAAgB,OAAO,KAAK,gBAAgB,EAAE,SAAS,QAAQ;AACrE,UAAI,aAAa,EAAE,SAAS,CAAC,UAAU,GAAG,OAAO,cAAc;AAAA,IACjE;AAAA,EACF;AACF;AAEO,IAAM,wBAAwB,CAAC,mBAAgE;AACpG,MAAI;AACF,QAAI,gBAAgB;AAClB,YAAM,iBAAiB,OAAO,KAAK,gBAAgB,QAAQ,EAAE,SAAS,MAAM;AAC5E,YAAM,mBAAmB,KAAK,MAAM,cAAc;AAClD,aAAO;AAAA,IACT;AAAA,EACF,QAAQ;AAAA,EAER;AACA,SAAO;AACT;","names":[]}
@@ -22,14 +22,6 @@ interface AIGatewayTokenResponse {
22
22
  url: string;
23
23
  envVars?: AIProviderEnvVar[];
24
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
25
  declare const fetchAIProviders: ({ api }: {
34
26
  api: NetlifyAPI;
35
27
  }) => Promise<AIProviderEnvVar[]>;
@@ -40,4 +32,4 @@ declare const fetchAIGatewayToken: ({ api, siteId, }: {
40
32
  declare const setupAIGateway: (config: AIGatewayConfig) => Promise<void>;
41
33
  declare const parseAIGatewayContext: (aiGatewayValue?: string) => AIGatewayTokenResponse | undefined;
42
34
 
43
- export { type AIGatewayConfig, type AIGatewayContext, type AIGatewayTokenResponse, type AIProvider, type AIProviderEnvVar, type ProvidersResponse, fetchAIGatewayToken, fetchAIProviders, parseAIGatewayContext, setupAIGateway };
35
+ export { type AIGatewayConfig, type AIGatewayContext, type AIGatewayTokenResponse, type AIProviderEnvVar, fetchAIGatewayToken, fetchAIProviders, parseAIGatewayContext, setupAIGateway };
@@ -22,14 +22,6 @@ interface AIGatewayTokenResponse {
22
22
  url: string;
23
23
  envVars?: AIProviderEnvVar[];
24
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
25
  declare const fetchAIProviders: ({ api }: {
34
26
  api: NetlifyAPI;
35
27
  }) => Promise<AIProviderEnvVar[]>;
@@ -40,4 +32,4 @@ declare const fetchAIGatewayToken: ({ api, siteId, }: {
40
32
  declare const setupAIGateway: (config: AIGatewayConfig) => Promise<void>;
41
33
  declare const parseAIGatewayContext: (aiGatewayValue?: string) => AIGatewayTokenResponse | undefined;
42
34
 
43
- export { type AIGatewayConfig, type AIGatewayContext, type AIGatewayTokenResponse, type AIProvider, type AIProviderEnvVar, type ProvidersResponse, fetchAIGatewayToken, fetchAIProviders, parseAIGatewayContext, setupAIGateway };
35
+ export { type AIGatewayConfig, type AIGatewayContext, type AIGatewayTokenResponse, type AIProviderEnvVar, fetchAIGatewayToken, fetchAIProviders, parseAIGatewayContext, setupAIGateway };
@@ -1,39 +1,21 @@
1
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
2
  var fetchAIProviders = async ({ api }) => {
9
3
  try {
10
4
  if (!api.accessToken) {
11
5
  return [];
12
6
  }
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");
7
+ const data = await api.getAIGatewayProviders();
8
+ if (!data.providers) {
9
+ return [];
30
10
  }
31
11
  const envVars = [];
32
12
  for (const provider of Object.values(data.providers)) {
33
- envVars.push({
34
- key: provider.token_env_var,
35
- url: provider.url_env_var
36
- });
13
+ if (provider.token_env_var && provider.url_env_var) {
14
+ envVars.push({
15
+ key: provider.token_env_var,
16
+ url: provider.url_env_var
17
+ });
18
+ }
37
19
  }
38
20
  return envVars;
39
21
  } catch (error) {
@@ -49,23 +31,9 @@ var fetchAIGatewayToken = async ({
49
31
  if (!api.accessToken) {
50
32
  return null;
51
33
  }
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");
34
+ const data = await api.getAIGatewayToken({ site_id: siteId });
35
+ if (!data.token || !data.url) {
36
+ return null;
69
37
  }
70
38
  return {
71
39
  token: data.token,
@@ -1 +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":[]}
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 const fetchAIProviders = async ({ api }: { api: NetlifyAPI }): Promise<AIProviderEnvVar[]> => {\n try {\n if (!api.accessToken) {\n return []\n }\n\n const data = await api.getAIGatewayProviders()\n\n if (!data.providers) {\n return []\n }\n\n const envVars: AIProviderEnvVar[] = []\n\n for (const provider of Object.values(data.providers)) {\n if (provider.token_env_var && provider.url_env_var) {\n envVars.push({\n key: provider.token_env_var,\n url: provider.url_env_var,\n })\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 const data = await api.getAIGatewayToken({ site_id: siteId })\n\n if (!data.token || !data.url) {\n return null\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":";AAyBO,IAAM,mBAAmB,OAAO,EAAE,IAAI,MAAwD;AACnG,MAAI;AACF,QAAI,CAAC,IAAI,aAAa;AACpB,aAAO,CAAC;AAAA,IACV;AAEA,UAAM,OAAO,MAAM,IAAI,sBAAsB;AAE7C,QAAI,CAAC,KAAK,WAAW;AACnB,aAAO,CAAC;AAAA,IACV;AAEA,UAAM,UAA8B,CAAC;AAErC,eAAW,YAAY,OAAO,OAAO,KAAK,SAAS,GAAG;AACpD,UAAI,SAAS,iBAAiB,SAAS,aAAa;AAClD,gBAAQ,KAAK;AAAA,UACX,KAAK,SAAS;AAAA,UACd,KAAK,SAAS;AAAA,QAChB,CAAC;AAAA,MACH;AAAA,IACF;AAEA,WAAO;AAAA,EACT,SAAS,OAAO;AACd,YAAQ,KAAK,iCAAiC,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC,EAAE;AACtG,WAAO,CAAC;AAAA,EACV;AACF;AAEO,IAAM,sBAAsB,OAAO;AAAA,EACxC;AAAA,EACA;AACF,MAG8C;AAC5C,MAAI;AACF,QAAI,CAAC,IAAI,aAAa;AACpB,aAAO;AAAA,IACT;AAEA,UAAM,OAAO,MAAM,IAAI,kBAAkB,EAAE,SAAS,OAAO,CAAC;AAE5D,QAAI,CAAC,KAAK,SAAS,CAAC,KAAK,KAAK;AAC5B,aAAO;AAAA,IACT;AAEA,WAAO;AAAA,MACL,OAAO,KAAK;AAAA,MACZ,KAAK,KAAK;AAAA,IACZ;AAAA,EACF,SAAS,OAAO;AACd,YAAQ;AAAA,MACN,6CAA6C,MAAM,KAAK,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC;AAAA,IAChH;AACA,WAAO;AAAA,EACT;AACF;AAEO,IAAM,iBAAiB,OAAO,WAA2C;AAC9E,QAAM,EAAE,KAAK,KAAK,QAAQ,QAAQ,IAAI;AAEtC,MAAI,UAAU,WAAW,cAAc,SAAS;AAC9C,UAAM,CAAC,gBAAgB,OAAO,IAAI,MAAM,QAAQ,IAAI;AAAA,MAClD,oBAAoB,EAAE,KAAK,QAAQ,OAAO,CAAC;AAAA,MAC3C,iBAAiB,EAAE,IAAI,CAAC;AAAA,IAC1B,CAAC;AAED,QAAI,gBAAgB;AAClB,YAAM,mBAAmB,KAAK,UAAU;AAAA,QACtC,OAAO,eAAe;AAAA,QACtB,KAAK,GAAG,OAAO;AAAA,QACf;AAAA,MACF,CAAC;AACD,YAAM,gBAAgB,OAAO,KAAK,gBAAgB,EAAE,SAAS,QAAQ;AACrE,UAAI,aAAa,EAAE,SAAS,CAAC,UAAU,GAAG,OAAO,cAAc;AAAA,IACjE;AAAA,EACF;AACF;AAEO,IAAM,wBAAwB,CAAC,mBAAgE;AACpG,MAAI;AACF,QAAI,gBAAgB;AAClB,YAAM,iBAAiB,OAAO,KAAK,gBAAgB,QAAQ,EAAE,SAAS,MAAM;AAC5E,YAAM,mBAAmB,KAAK,MAAM,cAAc;AAClD,aAAO;AAAA,IACT;AAAA,EACF,QAAQ;AAAA,EAER;AACA,SAAO;AACT;","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@netlify/ai",
3
- "version": "0.2.1",
3
+ "version": "0.3.1",
4
4
  "description": "TypeScript utilities for interacting with Netlify AI features",
5
5
  "type": "module",
6
6
  "engines": {
@@ -56,7 +56,7 @@
56
56
  "publint": "npx -y publint --strict"
57
57
  },
58
58
  "dependencies": {
59
- "@netlify/api": "^14.0.4"
59
+ "@netlify/api": "^14.0.7"
60
60
  },
61
61
  "devDependencies": {
62
62
  "@types/node": "20.14.15",