Skip to content

Commit 2ec4332

Browse files
feat: AI Gateway credentials endpoint instance url (backport to release-candidate/2.17.x) (#28527)
Co-authored-by: Michael Kret <88898367+michael-radency@users.noreply.github.com>
1 parent 2d50843 commit 2ec4332

File tree

2 files changed

+24
-3
lines changed

2 files changed

+24
-3
lines changed

packages/cli/src/services/__tests__/ai-gateway.service.test.ts

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ import type { License } from '@/license';
1010
import { AiGatewayService } from '@/services/ai-gateway.service';
1111
import type { Project, User, UserRepository } from '@n8n/db';
1212
import type { OwnershipService } from '@/services/ownership.service';
13+
import type { UrlService } from '@/services/url.service';
14+
15+
const INSTANCE_BASE_URL = 'https://my-n8n.example.com';
1316

1417
const BASE_URL = 'http://gateway.test';
1518
const INSTANCE_ID = 'test-instance-id';
@@ -34,6 +37,9 @@ function makeService({
3437
isAiGatewayLicensed = true,
3538
ownershipService = mock<OwnershipService>(),
3639
userRepository = mock<UserRepository>({ findOneBy: jest.fn().mockResolvedValue(null) }),
40+
urlService = mock<UrlService>({
41+
getInstanceBaseUrl: jest.fn().mockReturnValue(INSTANCE_BASE_URL),
42+
}),
3743
} = {}) {
3844
const globalConfig = {
3945
aiAssistant: { baseUrl: baseUrl ?? undefined },
@@ -53,6 +59,7 @@ function makeService({
5359
instanceSettings,
5460
ownershipService,
5561
userRepository,
62+
urlService,
5663
);
5764
}
5865

@@ -189,11 +196,21 @@ describe('AiGatewayService', () => {
189196
'x-n8n-version': N8N_VERSION,
190197
'x-instance-id': INSTANCE_ID,
191198
},
192-
body: JSON.stringify({ licenseCert: LICENSE_CERT }),
199+
body: JSON.stringify({ licenseCert: LICENSE_CERT, instanceUrl: INSTANCE_BASE_URL }),
193200
}),
194201
);
195202
});
196203

204+
it('includes instanceUrl in token body', async () => {
205+
mockConfigThenToken(fetchMock);
206+
const service = makeService();
207+
208+
await service.getSyntheticCredential({ credentialType: 'googlePalmApi', userId: USER_ID });
209+
210+
const body = JSON.parse(fetchMock.mock.calls[1][1].body as string);
211+
expect(body.instanceUrl).toBe(INSTANCE_BASE_URL);
212+
});
213+
197214
it('includes userEmail and userName in token body when user exists', async () => {
198215
const userRepository = mock<UserRepository>({
199216
findOneBy: jest
@@ -215,6 +232,7 @@ describe('AiGatewayService', () => {
215232
licenseCert: LICENSE_CERT,
216233
userEmail: 'alice@example.com',
217234
userName: 'Alice Smith',
235+
instanceUrl: INSTANCE_BASE_URL,
218236
}),
219237
}),
220238
);
@@ -245,7 +263,7 @@ describe('AiGatewayService', () => {
245263
await service.getSyntheticCredential({ credentialType: 'googlePalmApi', userId: USER_ID });
246264

247265
const body = JSON.parse(fetchMock.mock.calls[1][1].body as string);
248-
expect(body).toEqual({ licenseCert: LICENSE_CERT });
266+
expect(body).toEqual({ licenseCert: LICENSE_CERT, instanceUrl: INSTANCE_BASE_URL });
249267
});
250268

251269
it('caches config and token — second call makes no additional fetches', async () => {
@@ -416,7 +434,7 @@ describe('AiGatewayService', () => {
416434
`${BASE_URL}/v1/gateway/credentials`,
417435
expect.objectContaining({
418436
method: 'POST',
419-
body: JSON.stringify({ licenseCert: LICENSE_CERT }),
437+
body: JSON.stringify({ licenseCert: LICENSE_CERT, instanceUrl: INSTANCE_BASE_URL }),
420438
}),
421439
);
422440
expect(fetchMock).toHaveBeenNthCalledWith(2, `${BASE_URL}/v1/gateway/wallet`, {

packages/cli/src/services/ai-gateway.service.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import { N8N_VERSION, AI_ASSISTANT_SDK_VERSION } from '@/constants';
1212
import { FeatureNotLicensedError } from '@/errors/feature-not-licensed.error';
1313
import { License } from '@/license';
1414
import { OwnershipService } from '@/services/ownership.service';
15+
import { UrlService } from '@/services/url.service';
1516

1617
interface GatewayTokenResponse {
1718
token: string;
@@ -44,6 +45,7 @@ export class AiGatewayService {
4445
private readonly instanceSettings: InstanceSettings,
4546
private readonly ownershipService: OwnershipService,
4647
private readonly userRepository: UserRepository,
48+
private readonly urlService: UrlService,
4749
) {}
4850

4951
/**
@@ -273,6 +275,7 @@ export class AiGatewayService {
273275
...(user && {
274276
userName: [user.firstName, user.lastName].filter(Boolean).join(' ') || undefined,
275277
}),
278+
instanceUrl: this.urlService.getInstanceBaseUrl(),
276279
}),
277280
});
278281

0 commit comments

Comments
 (0)