latchkey 3.4.1 → 3.6.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.
- package/dist/skills/generic/latchkey/SKILL.md +2 -2
- package/dist/skills/openclaw/latchkey/SKILL.md +2 -2
- package/dist/src/apiCredentials/serialization.d.ts +12 -0
- package/dist/src/apiCredentials/serialization.d.ts.map +1 -1
- package/dist/src/apiCredentials/serialization.js +7 -0
- package/dist/src/apiCredentials/serialization.js.map +1 -1
- package/dist/src/serviceRegistry.d.ts.map +1 -1
- package/dist/src/serviceRegistry.js +4 -1
- package/dist/src/serviceRegistry.js.map +1 -1
- package/dist/src/services/google/gmail.d.ts.map +1 -1
- package/dist/src/services/google/gmail.js +6 -1
- package/dist/src/services/google/gmail.js.map +1 -1
- package/dist/src/services/huggingface.d.ts +40 -0
- package/dist/src/services/huggingface.d.ts.map +1 -0
- package/dist/src/services/huggingface.js +146 -0
- package/dist/src/services/huggingface.js.map +1 -0
- package/dist/src/services/index.d.ts +3 -0
- package/dist/src/services/index.d.ts.map +1 -1
- package/dist/src/services/index.js +3 -0
- package/dist/src/services/index.js.map +1 -1
- package/dist/src/services/openrouter.d.ts +37 -0
- package/dist/src/services/openrouter.d.ts.map +1 -0
- package/dist/src/services/openrouter.js +142 -0
- package/dist/src/services/openrouter.js.map +1 -0
- package/dist/src/services/tailscale.d.ts +74 -0
- package/dist/src/services/tailscale.d.ts.map +1 -0
- package/dist/src/services/tailscale.js +221 -0
- package/dist/src/services/tailscale.js.map +1 -0
- package/dist/src/version.d.ts +1 -1
- package/dist/src/version.js +1 -1
- package/dist/tests/huggingface.test.d.ts +2 -0
- package/dist/tests/huggingface.test.d.ts.map +1 -0
- package/dist/tests/huggingface.test.js +36 -0
- package/dist/tests/huggingface.test.js.map +1 -0
- package/dist/tests/servicesAgainstRecordings.test.js +12 -3
- package/dist/tests/servicesAgainstRecordings.test.js.map +1 -1
- package/dist/tests/tailscale.test.d.ts +2 -0
- package/dist/tests/tailscale.test.d.ts.map +1 -0
- package/dist/tests/tailscale.test.js +79 -0
- package/dist/tests/tailscale.test.js.map +1 -0
- package/package.json +2 -2
|
@@ -126,8 +126,8 @@ in the key means "unknown account".
|
|
|
126
126
|
|
|
127
127
|
Latchkey currently offers varying levels of support for the
|
|
128
128
|
following services: AWS, Calendly, Coolify, Discord, Dropbox, Figma, GitHub, GitLab,
|
|
129
|
-
Gmail, Google Analytics, Google Calendar, Google Docs, Google Drive, Google Sheets,
|
|
130
|
-
Linear, Mailchimp, ngrok, Notion, Ramp, Sentry, Slack, Stripe, Telegram, Todoist, Umami, Yelp, Zoom, and more.
|
|
129
|
+
Gmail, Google Analytics, Google Calendar, Google Docs, Google Drive, Google Sheets, Hugging Face,
|
|
130
|
+
Linear, Mailchimp, ngrok, Notion, OpenRouter, Ramp, Sentry, Slack, Stripe, Telegram, Tailscale, Todoist, Umami, Yelp, Zoom, and more.
|
|
131
131
|
|
|
132
132
|
### User-registered services
|
|
133
133
|
|
|
@@ -118,8 +118,8 @@ in the key means "unknown account".
|
|
|
118
118
|
|
|
119
119
|
Latchkey currently offers varying levels of support for the
|
|
120
120
|
following services: AWS, Calendly, Coolify, Discord, Dropbox, Figma, GitHub, GitLab,
|
|
121
|
-
Gmail, Google Analytics, Google Calendar, Google Docs, Google Drive, Google Sheets,
|
|
122
|
-
Linear, Mailchimp, ngrok, Notion, Ramp, Sentry, Slack, Stripe, Telegram, Todoist, Umami, Yelp, Zoom, and more.
|
|
121
|
+
Gmail, Google Analytics, Google Calendar, Google Docs, Google Drive, Google Sheets, Hugging Face,
|
|
122
|
+
Linear, Mailchimp, ngrok, Notion, OpenRouter, Ramp, Sentry, Slack, Stripe, Telegram, Tailscale, Todoist, Umami, Yelp, Zoom, and more.
|
|
123
123
|
|
|
124
124
|
### User-registered services
|
|
125
125
|
|
|
@@ -124,6 +124,18 @@ export declare const ApiCredentialsSchema: z.ZodDiscriminatedUnion<"objectType",
|
|
|
124
124
|
accountId: string;
|
|
125
125
|
accessToken?: string | undefined;
|
|
126
126
|
accessTokenExpiresAt?: string | undefined;
|
|
127
|
+
}>, z.ZodObject<{
|
|
128
|
+
objectType: z.ZodLiteral<"tailscale">;
|
|
129
|
+
token: z.ZodString;
|
|
130
|
+
tailnet: z.ZodString;
|
|
131
|
+
}, "strip", z.ZodTypeAny, {
|
|
132
|
+
objectType: "tailscale";
|
|
133
|
+
token: string;
|
|
134
|
+
tailnet: string;
|
|
135
|
+
}, {
|
|
136
|
+
objectType: "tailscale";
|
|
137
|
+
token: string;
|
|
138
|
+
tailnet: string;
|
|
127
139
|
}>]>;
|
|
128
140
|
export type ApiCredentialsData = z.infer<typeof ApiCredentialsSchema>;
|
|
129
141
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"serialization.d.ts","sourceRoot":"","sources":["../../../src/apiCredentials/serialization.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EACL,KAAK,cAAc,EASpB,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"serialization.d.ts","sourceRoot":"","sources":["../../../src/apiCredentials/serialization.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EACL,KAAK,cAAc,EASpB,MAAM,WAAW,CAAC;AAWnB;;GAEG;AACH,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAW/B,CAAC;AAEH,MAAM,MAAM,kBAAkB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAEtE;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,kBAAkB,GAAG,cAAc,CA6B/E;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,WAAW,EAAE,cAAc,GAAG,kBAAkB,CAgCpF;AAED,qBAAa,gCAAiC,SAAQ,KAAK;gBAC7C,OAAO,EAAE,MAAM;CAI5B"}
|
|
@@ -12,6 +12,7 @@ import { GoogleApiKeyCredentials, GoogleApiKeyCredentialsSchema } from '../servi
|
|
|
12
12
|
import { SlackApiCredentials, SlackApiCredentialsSchema } from '../services/slack.js';
|
|
13
13
|
import { TelegramBotCredentials, TelegramBotCredentialsSchema } from '../services/telegram.js';
|
|
14
14
|
import { ZoomServerToServerCredentials, ZoomServerToServerCredentialsSchema, } from '../services/zoom.js';
|
|
15
|
+
import { TailscaleCredentials, TailscaleCredentialsSchema } from '../services/tailscale.js';
|
|
15
16
|
/**
|
|
16
17
|
* Union schema for all credential types.
|
|
17
18
|
*/
|
|
@@ -25,6 +26,7 @@ export const ApiCredentialsSchema = z.discriminatedUnion('objectType', [
|
|
|
25
26
|
AwsCredentialsSchema,
|
|
26
27
|
GoogleApiKeyCredentialsSchema,
|
|
27
28
|
ZoomServerToServerCredentialsSchema,
|
|
29
|
+
TailscaleCredentialsSchema,
|
|
28
30
|
]);
|
|
29
31
|
/**
|
|
30
32
|
* Deserialize credentials from JSON data.
|
|
@@ -49,6 +51,8 @@ export function deserializeCredentials(data) {
|
|
|
49
51
|
return GoogleApiKeyCredentials.fromJSON(data);
|
|
50
52
|
case 'zoomServerToServer':
|
|
51
53
|
return ZoomServerToServerCredentials.fromJSON(data);
|
|
54
|
+
case 'tailscale':
|
|
55
|
+
return TailscaleCredentials.fromJSON(data);
|
|
52
56
|
default: {
|
|
53
57
|
const exhaustiveCheck = data;
|
|
54
58
|
throw new ApiCredentialsSerializationError(`Unknown credential type: ${exhaustiveCheck.objectType}`);
|
|
@@ -86,6 +90,9 @@ export function serializeCredentials(credentials) {
|
|
|
86
90
|
if (credentials instanceof ZoomServerToServerCredentials) {
|
|
87
91
|
return credentials.toJSON();
|
|
88
92
|
}
|
|
93
|
+
if (credentials instanceof TailscaleCredentials) {
|
|
94
|
+
return credentials.toJSON();
|
|
95
|
+
}
|
|
89
96
|
throw new ApiCredentialsSerializationError(`Unknown credential type: ${credentials.objectType}`);
|
|
90
97
|
}
|
|
91
98
|
export class ApiCredentialsSerializationError extends Error {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"serialization.js","sourceRoot":"","sources":["../../../src/apiCredentials/serialization.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAEL,iBAAiB,EACjB,uBAAuB,EACvB,mBAAmB,EACnB,yBAAyB,EACzB,gBAAgB,EAChB,sBAAsB,EACtB,kBAAkB,EAClB,wBAAwB,GACzB,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,cAAc,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAC1E,OAAO,EAAE,uBAAuB,EAAE,6BAA6B,EAAE,MAAM,4BAA4B,CAAC;AACpG,OAAO,EAAE,mBAAmB,EAAE,yBAAyB,EAAE,MAAM,sBAAsB,CAAC;AACtF,OAAO,EAAE,sBAAsB,EAAE,4BAA4B,EAAE,MAAM,yBAAyB,CAAC;AAC/F,OAAO,EACL,6BAA6B,EAC7B,mCAAmC,GACpC,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"serialization.js","sourceRoot":"","sources":["../../../src/apiCredentials/serialization.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"serviceRegistry.d.ts","sourceRoot":"","sources":["../../src/serviceRegistry.ts"],"names":[],"mappings":"AAAA;;GAEG;AAMH,OAAO,EACL,OAAO,
|
|
1
|
+
{"version":3,"file":"serviceRegistry.d.ts","sourceRoot":"","sources":["../../src/serviceRegistry.ts"],"names":[],"mappings":"AAAA;;GAEG;AAMH,OAAO,EACL,OAAO,EAmCR,MAAM,qBAAqB,CAAC;AAE7B,qBAAa,yBAA0B,SAAQ,KAAK;gBACtC,IAAI,EAAE,MAAM;CAIzB;AAED,qBAAa,uBAAwB,SAAQ,KAAK;gBACpC,IAAI,EAAE,MAAM;CAMzB;AAID,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAM5D;AAED,qBAAa,eAAe;IAC1B,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAY;gBAE1B,QAAQ,EAAE,SAAS,OAAO,EAAE;IAIxC,IAAI,QAAQ,IAAI,SAAS,OAAO,EAAE,CAEjC;IAED,UAAU,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI;IAOlC,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAOjC,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,GAAG,IAAI;IASvC,OAAO,CAAC,UAAU;IAelB;;;;;;;;OAQG;IACH,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,OAAO,EAAE;IAInD;;;;;;OAMG;IACH,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,GAAG,IAAI;CAGtC;AAED;;;;GAIG;AACH,wBAAgB,wBAAwB,CACtC,QAAQ,EAAE,eAAe,EACzB,YAAY,EAAE,SAAS,MAAM,EAAE,GAC9B,IAAI,CAIN;AAyBD,wBAAgB,yCAAyC,CACvD,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,eAAe,GACxB,IAAI,CAwBN;AAED,eAAO,MAAM,gBAAgB,iBAmC3B,CAAC"}
|
|
@@ -5,7 +5,7 @@ import { loadRegisteredServices } from './configDataStore.js';
|
|
|
5
5
|
import { buildRegisteredServiceOptions, RegisteredService } from './services/core/registered.js';
|
|
6
6
|
import { resolveLoginFlow, UnknownLoginFlowError } from './services/core/loginFlows/registry.js';
|
|
7
7
|
import { LoginFlowParamsInvalidError } from './services/core/loginFlows/base.js';
|
|
8
|
-
import { SLACK, DISCORD, DROPBOX, GITHUB, LINEAR, NOTION, NOTION_MCP, GOOGLE_GMAIL, GOOGLE_CALENDAR, GOOGLE_DRIVE, GOOGLE_SHEETS, GOOGLE_DOCS, GOOGLE_SLIDES, GOOGLE_PEOPLE, MAILCHIMP, GITLAB, ZOOM, SENTRY, STRIPE, FIGMA, GOOGLE_ANALYTICS, CALENDLY, YELP, TELEGRAM, AWS, GOOGLE_DIRECTIONS, COOLIFY, UMAMI, RAMP, TODOIST, NGROK, } from './services/index.js';
|
|
8
|
+
import { SLACK, DISCORD, DROPBOX, GITHUB, LINEAR, NOTION, NOTION_MCP, GOOGLE_GMAIL, GOOGLE_CALENDAR, GOOGLE_DRIVE, GOOGLE_SHEETS, GOOGLE_DOCS, GOOGLE_SLIDES, GOOGLE_PEOPLE, MAILCHIMP, GITLAB, ZOOM, SENTRY, STRIPE, FIGMA, GOOGLE_ANALYTICS, CALENDLY, YELP, TELEGRAM, AWS, GOOGLE_DIRECTIONS, COOLIFY, UMAMI, RAMP, TODOIST, NGROK, HUGGINGFACE, OPENROUTER, TAILSCALE, } from './services/index.js';
|
|
9
9
|
export class DuplicateServiceNameError extends Error {
|
|
10
10
|
constructor(name) {
|
|
11
11
|
super(`A service with the name '${name}' already exists.`);
|
|
@@ -172,5 +172,8 @@ export const SERVICE_REGISTRY = new ServiceRegistry([
|
|
|
172
172
|
RAMP,
|
|
173
173
|
TODOIST,
|
|
174
174
|
NGROK,
|
|
175
|
+
HUGGINGFACE,
|
|
176
|
+
OPENROUTER,
|
|
177
|
+
TAILSCALE,
|
|
175
178
|
]);
|
|
176
179
|
//# sourceMappingURL=serviceRegistry.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"serviceRegistry.js","sourceRoot":"","sources":["../../src/serviceRegistry.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,sBAAsB,EAA+B,MAAM,sBAAsB,CAAC;AAC3F,OAAO,EAAE,6BAA6B,EAAE,iBAAiB,EAAE,MAAM,+BAA+B,CAAC;AACjG,OAAO,EAAE,gBAAgB,EAAE,qBAAqB,EAAE,MAAM,wCAAwC,CAAC;AACjG,OAAO,EAAE,2BAA2B,EAAkB,MAAM,oCAAoC,CAAC;AACjG,OAAO,EAEL,KAAK,EACL,OAAO,EACP,OAAO,EACP,MAAM,EACN,MAAM,EACN,MAAM,EACN,UAAU,EACV,YAAY,EACZ,eAAe,EACf,YAAY,EACZ,aAAa,EACb,WAAW,EACX,aAAa,EACb,aAAa,EACb,SAAS,EACT,MAAM,EACN,IAAI,EACJ,MAAM,EACN,MAAM,EACN,KAAK,EACL,gBAAgB,EAChB,QAAQ,EACR,IAAI,EACJ,QAAQ,EACR,GAAG,EACH,iBAAiB,EACjB,OAAO,EACP,KAAK,EACL,IAAI,EACJ,OAAO,EACP,KAAK,
|
|
1
|
+
{"version":3,"file":"serviceRegistry.js","sourceRoot":"","sources":["../../src/serviceRegistry.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gmail.d.ts","sourceRoot":"","sources":["../../../../src/services/google/gmail.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,KAAK,mBAAmB,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"gmail.d.ts","sourceRoot":"","sources":["../../../../src/services/google/gmail.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,KAAK,mBAAmB,EAAE,MAAM,WAAW,CAAC;AAYpE,qBAAa,WAAY,SAAQ,aAAa;IAC5C,QAAQ,CAAC,IAAI,kBAAkB;IAC/B,QAAQ,CAAC,WAAW,kBAAkB;IACtC,QAAQ,CAAC,WAAW,6CAA8C;IAClE,QAAQ,CAAC,IAAI,SAK8D;IAE3E,SAAS,CAAC,QAAQ,CAAC,MAAM,sBAAU;CACpC;AAED,eAAO,MAAM,YAAY,aAAoB,CAAC"}
|
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
import { GoogleService } from './base.js';
|
|
2
2
|
const CONFIG = {
|
|
3
3
|
apis: ['gmail.googleapis.com'],
|
|
4
|
-
scopes: [
|
|
4
|
+
scopes: [
|
|
5
|
+
// gmail.modify covers reading/labeling messages and reading filters/labels,
|
|
6
|
+
// but creating or deleting filters requires gmail.settings.basic.
|
|
7
|
+
'https://www.googleapis.com/auth/gmail.modify',
|
|
8
|
+
'https://www.googleapis.com/auth/gmail.settings.basic',
|
|
9
|
+
],
|
|
5
10
|
};
|
|
6
11
|
export class GoogleGmail extends GoogleService {
|
|
7
12
|
name = 'google-gmail';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gmail.js","sourceRoot":"","sources":["../../../../src/services/google/gmail.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAA4B,MAAM,WAAW,CAAC;AAEpE,MAAM,MAAM,GAAwB;IAClC,IAAI,EAAE,CAAC,sBAAsB,CAAC;IAC9B,MAAM,EAAE,
|
|
1
|
+
{"version":3,"file":"gmail.js","sourceRoot":"","sources":["../../../../src/services/google/gmail.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAA4B,MAAM,WAAW,CAAC;AAEpE,MAAM,MAAM,GAAwB;IAClC,IAAI,EAAE,CAAC,sBAAsB,CAAC;IAC9B,MAAM,EAAE;QACN,4EAA4E;QAC5E,kEAAkE;QAClE,8CAA8C;QAC9C,sDAAsD;KACvD;CACF,CAAC;AAEF,MAAM,OAAO,WAAY,SAAQ,aAAa;IACnC,IAAI,GAAG,cAAc,CAAC;IACtB,WAAW,GAAG,cAAc,CAAC;IAC7B,WAAW,GAAG,CAAC,+BAA+B,CAAU,CAAC;IACzD,IAAI,GACX,0DAA0D;QAC1D,+FAA+F;QAC/F,qEAAqE;QACrE,+HAA+H;QAC/H,wEAAwE,CAAC;IAExD,MAAM,GAAG,MAAM,CAAC;CACpC;AAED,MAAM,CAAC,MAAM,YAAY,GAAG,IAAI,WAAW,EAAE,CAAC"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hugging Face service implementation.
|
|
3
|
+
*
|
|
4
|
+
* Hugging Face issues personal User Access Tokens from the account settings,
|
|
5
|
+
* and a token's value is revealed exactly once at creation time (like Linear).
|
|
6
|
+
* We sign the user into huggingface.co, create a fresh token on their behalf,
|
|
7
|
+
* and read its value from the one-time reveal dialog.
|
|
8
|
+
*
|
|
9
|
+
* A classic `write` token grants read and write access to the user's
|
|
10
|
+
* repositories and also serves as a bearer token for the Inference Providers
|
|
11
|
+
* router, so one minted token is capable of everything an agent might do
|
|
12
|
+
* through this service (download, upload, run inference). Requests to the Hub
|
|
13
|
+
* API and the Inference router authenticate with a single
|
|
14
|
+
* `Authorization: Bearer hf_...` header, so we store an AuthorizationBearer
|
|
15
|
+
* credential and let it inject that header into every matching request.
|
|
16
|
+
*/
|
|
17
|
+
import type { Response, BrowserContext } from 'playwright';
|
|
18
|
+
import { ApiCredentials } from '../apiCredentials/base.js';
|
|
19
|
+
import { Service, BrowserFollowupServiceSession, FollowupWork } from './core/base.js';
|
|
20
|
+
declare class HuggingfaceServiceSession extends BrowserFollowupServiceSession {
|
|
21
|
+
protected readonly followupWork = FollowupWork.CreateApiToken;
|
|
22
|
+
private isLoggedIn;
|
|
23
|
+
onResponse(response: Response): void;
|
|
24
|
+
protected isLoginComplete(): boolean;
|
|
25
|
+
protected performBrowserFollowup(context: BrowserContext, _oldCredentials?: ApiCredentials): Promise<ApiCredentials | null>;
|
|
26
|
+
}
|
|
27
|
+
export declare class Huggingface extends Service {
|
|
28
|
+
readonly name = "huggingface";
|
|
29
|
+
readonly displayName = "Hugging Face";
|
|
30
|
+
readonly baseApiUrls: readonly ["https://huggingface.co/", "https://hf.co/", "https://router.huggingface.co/", "https://datasets-server.huggingface.co/"];
|
|
31
|
+
readonly loginUrl = "https://huggingface.co/login";
|
|
32
|
+
readonly info: string;
|
|
33
|
+
readonly credentialCheckCurlArguments: readonly ["https://huggingface.co/api/whoami-v2"];
|
|
34
|
+
setCredentialsExample(serviceName: string): string;
|
|
35
|
+
getAccount(apiCredentials: ApiCredentials): Promise<string | null>;
|
|
36
|
+
getSession(appNamePrefix: string): HuggingfaceServiceSession;
|
|
37
|
+
}
|
|
38
|
+
export declare const HUGGINGFACE: Huggingface;
|
|
39
|
+
export {};
|
|
40
|
+
//# sourceMappingURL=huggingface.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"huggingface.d.ts","sourceRoot":"","sources":["../../../src/services/huggingface.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAC3D,OAAO,EAAE,cAAc,EAAuB,MAAM,2BAA2B,CAAC;AAGhF,OAAO,EACL,OAAO,EACP,6BAA6B,EAC7B,YAAY,EAEb,MAAM,gBAAgB,CAAC;AA4CxB,cAAM,yBAA0B,SAAQ,6BAA6B;IACnE,SAAS,CAAC,QAAQ,CAAC,YAAY,+BAA+B;IAC9D,OAAO,CAAC,UAAU,CAAS;IAE3B,UAAU,CAAC,QAAQ,EAAE,QAAQ,GAAG,IAAI;IAwBpC,SAAS,CAAC,eAAe,IAAI,OAAO;cAIpB,sBAAsB,CACpC,OAAO,EAAE,cAAc,EACvB,eAAe,CAAC,EAAE,cAAc,GAC/B,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC;CAmClC;AAED,qBAAa,WAAY,SAAQ,OAAO;IACtC,QAAQ,CAAC,IAAI,iBAAiB;IAC9B,QAAQ,CAAC,WAAW,kBAAkB;IACtC,QAAQ,CAAC,WAAW,sIAKT;IACX,QAAQ,CAAC,QAAQ,kCAAgB;IACjC,QAAQ,CAAC,IAAI,SAE8E;IAI3F,QAAQ,CAAC,4BAA4B,oDAA4B;IAEjE,qBAAqB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM;IAIzC,UAAU,CAAC,cAAc,EAAE,cAAc,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAWlE,UAAU,CAAC,aAAa,EAAE,MAAM,GAAG,yBAAyB;CAGtE;AAED,eAAO,MAAM,WAAW,aAAoB,CAAC"}
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hugging Face service implementation.
|
|
3
|
+
*
|
|
4
|
+
* Hugging Face issues personal User Access Tokens from the account settings,
|
|
5
|
+
* and a token's value is revealed exactly once at creation time (like Linear).
|
|
6
|
+
* We sign the user into huggingface.co, create a fresh token on their behalf,
|
|
7
|
+
* and read its value from the one-time reveal dialog.
|
|
8
|
+
*
|
|
9
|
+
* A classic `write` token grants read and write access to the user's
|
|
10
|
+
* repositories and also serves as a bearer token for the Inference Providers
|
|
11
|
+
* router, so one minted token is capable of everything an agent might do
|
|
12
|
+
* through this service (download, upload, run inference). Requests to the Hub
|
|
13
|
+
* API and the Inference router authenticate with a single
|
|
14
|
+
* `Authorization: Bearer hf_...` header, so we store an AuthorizationBearer
|
|
15
|
+
* credential and let it inject that header into every matching request.
|
|
16
|
+
*/
|
|
17
|
+
import { AuthorizationBearer } from '../apiCredentials/base.js';
|
|
18
|
+
import { fetchAccountFromEndpoint, tryParseJson } from '../apiCredentials/account.js';
|
|
19
|
+
import { typeLikeHuman } from '../playwrightUtils.js';
|
|
20
|
+
import { Service, BrowserFollowupServiceSession, FollowupWork, LoginFailedError, } from './core/base.js';
|
|
21
|
+
// Token creation can lag behind a slow sign-in or an extra confirmation step
|
|
22
|
+
// (a write token sometimes prompts before revealing), so this is more generous
|
|
23
|
+
// than the 8s default other services use for quick form interactions.
|
|
24
|
+
const DEFAULT_TIMEOUT_MS = 30000;
|
|
25
|
+
// Hub API + Inference router. The Hub API, repository file and git transfers and
|
|
26
|
+
// the whoami check live under huggingface.co (hf.co is an alias for the same
|
|
27
|
+
// host); hosted inference goes through the router, and the dataset viewer has
|
|
28
|
+
// its own host.
|
|
29
|
+
const HF_HUB_BASE_URL = 'https://huggingface.co/';
|
|
30
|
+
const HF_HUB_ALIAS_BASE_URL = 'https://hf.co/';
|
|
31
|
+
const HF_ROUTER_BASE_URL = 'https://router.huggingface.co/';
|
|
32
|
+
const HF_DATASETS_SERVER_BASE_URL = 'https://datasets-server.huggingface.co/';
|
|
33
|
+
// Deliberately not covered: the storage hosts that file transfers are redirected
|
|
34
|
+
// to (*.cdn.hf.co, cdn-lfs*.hf.co and the Xet hosts). They authenticate through
|
|
35
|
+
// the URL itself -- a signed CDN URL, or a repository-scoped Xet token the caller
|
|
36
|
+
// fetches from the hub -- so there is nothing for this service to contribute, and
|
|
37
|
+
// adding a bearer header there is at best ignored and at worst fatal (the Xet CAS
|
|
38
|
+
// server answers 400 once a second Authorization header shows up). Such requests
|
|
39
|
+
// need no credentials, so callers can make them directly.
|
|
40
|
+
const HF_LOGIN_URL = 'https://huggingface.co/login';
|
|
41
|
+
// Navigating here opens the "Create new Access Token" form preset to a classic
|
|
42
|
+
// write token (read + write, and a valid bearer for inference); the value is
|
|
43
|
+
// shown once in a dialog after creation. The settings page can trigger HF's
|
|
44
|
+
// "sudo" re-authentication, so we bring the page to the front first (see
|
|
45
|
+
// performBrowserFollowup) so the password prompt doesn't land on a tab the
|
|
46
|
+
// user isn't looking at.
|
|
47
|
+
const HF_NEW_TOKEN_URL = 'https://huggingface.co/settings/tokens/new?tokenType=write';
|
|
48
|
+
// Endpoint that returns the signed-in identity; also used as the credential check.
|
|
49
|
+
const HF_WHOAMI_URL = 'https://huggingface.co/api/whoami-v2';
|
|
50
|
+
// Hub host, and the path prefixes served before the user is signed in. A
|
|
51
|
+
// document response to the hub host on any *other* path only happens once login
|
|
52
|
+
// has succeeded, so we use it as the login-complete signal (works the same for
|
|
53
|
+
// a password or SSO sign-in, since the final redirect target is a hub page).
|
|
54
|
+
const HF_HUB_HOST = 'huggingface.co';
|
|
55
|
+
const HF_PRE_LOGIN_PATH_PATTERN = /^\/(login|join|signup|oauth|sso|auth|logout)/i;
|
|
56
|
+
class HuggingfaceServiceSession extends BrowserFollowupServiceSession {
|
|
57
|
+
followupWork = FollowupWork.CreateApiToken;
|
|
58
|
+
isLoggedIn = false;
|
|
59
|
+
onResponse(response) {
|
|
60
|
+
if (this.isLoggedIn) {
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
if (response.request().resourceType() !== 'document') {
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
let url;
|
|
67
|
+
try {
|
|
68
|
+
url = new URL(response.url());
|
|
69
|
+
}
|
|
70
|
+
catch {
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
if (url.hostname !== HF_HUB_HOST) {
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
if (HF_PRE_LOGIN_PATH_PATTERN.test(url.pathname)) {
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
if (response.status() >= 200 && response.status() < 400) {
|
|
80
|
+
this.isLoggedIn = true;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
isLoginComplete() {
|
|
84
|
+
return this.isLoggedIn;
|
|
85
|
+
}
|
|
86
|
+
async performBrowserFollowup(context, _oldCredentials) {
|
|
87
|
+
const page = context.pages()[0];
|
|
88
|
+
if (!page) {
|
|
89
|
+
throw new LoginFailedError('No page available in browser context.');
|
|
90
|
+
}
|
|
91
|
+
// The token settings page can trigger HF's "sudo" re-authentication; focus the
|
|
92
|
+
// page first so the password prompt surfaces on the tab the user is looking
|
|
93
|
+
// at, not a background one.
|
|
94
|
+
await page.bringToFront();
|
|
95
|
+
await page.goto(HF_NEW_TOKEN_URL);
|
|
96
|
+
// Give the token a recognizable name so the user can find and revoke it.
|
|
97
|
+
const tokenName = this.generateAppName();
|
|
98
|
+
const nameInput = page.locator('input[name="displayName"]');
|
|
99
|
+
await nameInput.waitFor({ timeout: DEFAULT_TIMEOUT_MS });
|
|
100
|
+
await typeLikeHuman(page, nameInput, tokenName);
|
|
101
|
+
// Locale-independent: the create button is the submit inside the token-name form.
|
|
102
|
+
const createButton = page.locator('form:has(input[name="displayName"]) button[type="submit"]');
|
|
103
|
+
await createButton.waitFor({ timeout: DEFAULT_TIMEOUT_MS });
|
|
104
|
+
await createButton.click();
|
|
105
|
+
// The new token is revealed exactly once, inside the success dialog. Its
|
|
106
|
+
// value sits in a text input; Hugging Face tokens are prefixed `hf_`.
|
|
107
|
+
const tokenInput = page.locator('dialog input').first();
|
|
108
|
+
await tokenInput.waitFor({ timeout: DEFAULT_TIMEOUT_MS });
|
|
109
|
+
const token = (await tokenInput.inputValue()).trim();
|
|
110
|
+
if (token === '' || !token.startsWith('hf_')) {
|
|
111
|
+
throw new LoginFailedError('Failed to extract access token from Hugging Face.');
|
|
112
|
+
}
|
|
113
|
+
await page.close();
|
|
114
|
+
return new AuthorizationBearer(token);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
export class Huggingface extends Service {
|
|
118
|
+
name = 'huggingface';
|
|
119
|
+
displayName = 'Hugging Face';
|
|
120
|
+
baseApiUrls = [
|
|
121
|
+
HF_HUB_BASE_URL,
|
|
122
|
+
HF_HUB_ALIAS_BASE_URL,
|
|
123
|
+
HF_ROUTER_BASE_URL,
|
|
124
|
+
HF_DATASETS_SERVER_BASE_URL,
|
|
125
|
+
];
|
|
126
|
+
loginUrl = HF_LOGIN_URL;
|
|
127
|
+
info = 'Hugging Face Hub + Inference: download models and datasets, manage ' +
|
|
128
|
+
'repositories, and run hosted inference. Docs: https://huggingface.co/docs/hub/llms.txt';
|
|
129
|
+
// whoami-v2 returns 200 for any valid token; the stored bearer header is
|
|
130
|
+
// added by the credential before the request is sent.
|
|
131
|
+
credentialCheckCurlArguments = [HF_WHOAMI_URL];
|
|
132
|
+
setCredentialsExample(serviceName) {
|
|
133
|
+
return `latchkey auth set ${serviceName} -H "Authorization: Bearer <token>"`;
|
|
134
|
+
}
|
|
135
|
+
getAccount(apiCredentials) {
|
|
136
|
+
return fetchAccountFromEndpoint(apiCredentials, this.credentialCheckCurlArguments, (responseBody) => {
|
|
137
|
+
const data = tryParseJson(responseBody);
|
|
138
|
+
return data?.name ?? data?.email ?? null;
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
getSession(appNamePrefix) {
|
|
142
|
+
return new HuggingfaceServiceSession(this, appNamePrefix);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
export const HUGGINGFACE = new Huggingface();
|
|
146
|
+
//# sourceMappingURL=huggingface.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"huggingface.js","sourceRoot":"","sources":["../../../src/services/huggingface.ts"],"names":[],"mappings":"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"}
|
|
@@ -39,4 +39,7 @@ export { Umami, UMAMI } from './umami.js';
|
|
|
39
39
|
export { Ramp, RAMP } from './ramp.js';
|
|
40
40
|
export { Todoist, TODOIST } from './todoist.js';
|
|
41
41
|
export { Ngrok, NGROK } from './ngrok.js';
|
|
42
|
+
export { Huggingface, HUGGINGFACE } from './huggingface.js';
|
|
43
|
+
export { Openrouter, OPENROUTER } from './openrouter.js';
|
|
44
|
+
export { Tailscale, TAILSCALE } from './tailscale.js';
|
|
42
45
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/services/index.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/services/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -39,4 +39,7 @@ export { Umami, UMAMI } from './umami.js';
|
|
|
39
39
|
export { Ramp, RAMP } from './ramp.js';
|
|
40
40
|
export { Todoist, TODOIST } from './todoist.js';
|
|
41
41
|
export { Ngrok, NGROK } from './ngrok.js';
|
|
42
|
+
export { Huggingface, HUGGINGFACE } from './huggingface.js';
|
|
43
|
+
export { Openrouter, OPENROUTER } from './openrouter.js';
|
|
44
|
+
export { Tailscale, TAILSCALE } from './tailscale.js';
|
|
42
45
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/services/index.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/services/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OpenRouter service implementation.
|
|
3
|
+
*
|
|
4
|
+
* OpenRouter issues personal API keys from the dashboard, and a key's value is
|
|
5
|
+
* revealed exactly once at creation time (like Linear). We sign the user into
|
|
6
|
+
* openrouter.ai, create a fresh API key on their behalf, and read its value from
|
|
7
|
+
* the one-time reveal dialog.
|
|
8
|
+
*
|
|
9
|
+
* The OpenRouter API is OpenAI-compatible: every request authenticates with a
|
|
10
|
+
* single `Authorization: Bearer sk-or-v1-...` header, so we store an
|
|
11
|
+
* AuthorizationBearer credential and let it inject that header into every
|
|
12
|
+
* matching request.
|
|
13
|
+
*/
|
|
14
|
+
import type { Response, BrowserContext } from 'playwright';
|
|
15
|
+
import { ApiCredentials } from '../apiCredentials/base.js';
|
|
16
|
+
import { Service, BrowserFollowupServiceSession, FollowupWork } from './core/base.js';
|
|
17
|
+
declare class OpenrouterServiceSession extends BrowserFollowupServiceSession {
|
|
18
|
+
protected readonly followupWork = FollowupWork.CreateApiToken;
|
|
19
|
+
private isLoggedIn;
|
|
20
|
+
onResponse(response: Response): void;
|
|
21
|
+
protected isLoginComplete(): boolean;
|
|
22
|
+
protected performBrowserFollowup(context: BrowserContext, _oldCredentials?: ApiCredentials): Promise<ApiCredentials | null>;
|
|
23
|
+
}
|
|
24
|
+
export declare class Openrouter extends Service {
|
|
25
|
+
readonly name = "openrouter";
|
|
26
|
+
readonly displayName = "OpenRouter";
|
|
27
|
+
readonly baseApiUrls: readonly ["https://openrouter.ai/api/v1/"];
|
|
28
|
+
readonly loginUrl = "https://openrouter.ai/sign-in";
|
|
29
|
+
readonly info = "OpenRouter unified LLM API (OpenAI-compatible). Docs: https://openrouter.ai/docs/llms.txt";
|
|
30
|
+
readonly credentialCheckCurlArguments: readonly ["https://openrouter.ai/api/v1/key"];
|
|
31
|
+
setCredentialsExample(serviceName: string): string;
|
|
32
|
+
getAccount(_apiCredentials: ApiCredentials): Promise<string | null>;
|
|
33
|
+
getSession(appNamePrefix: string): OpenrouterServiceSession;
|
|
34
|
+
}
|
|
35
|
+
export declare const OPENROUTER: Openrouter;
|
|
36
|
+
export {};
|
|
37
|
+
//# sourceMappingURL=openrouter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openrouter.d.ts","sourceRoot":"","sources":["../../../src/services/openrouter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAC3D,OAAO,EAAE,cAAc,EAAuB,MAAM,2BAA2B,CAAC;AAEhF,OAAO,EACL,OAAO,EACP,6BAA6B,EAC7B,YAAY,EAEb,MAAM,gBAAgB,CAAC;AA8BxB,cAAM,wBAAyB,SAAQ,6BAA6B;IAClE,SAAS,CAAC,QAAQ,CAAC,YAAY,+BAA+B;IAC9D,OAAO,CAAC,UAAU,CAAS;IAE3B,UAAU,CAAC,QAAQ,EAAE,QAAQ,GAAG,IAAI;IAwBpC,SAAS,CAAC,eAAe,IAAI,OAAO;cAIpB,sBAAsB,CACpC,OAAO,EAAE,cAAc,EACvB,eAAe,CAAC,EAAE,cAAc,GAC/B,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC;CAwDlC;AAED,qBAAa,UAAW,SAAQ,OAAO;IACrC,QAAQ,CAAC,IAAI,gBAAgB;IAC7B,QAAQ,CAAC,WAAW,gBAAgB;IACpC,QAAQ,CAAC,WAAW,6CAAsC;IAC1D,QAAQ,CAAC,QAAQ,mCAAwB;IACzC,QAAQ,CAAC,IAAI,+FACiF;IAI9F,QAAQ,CAAC,4BAA4B,gDAAsC;IAE3E,qBAAqB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM;IAMzC,UAAU,CAAC,eAAe,EAAE,cAAc,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAInE,UAAU,CAAC,aAAa,EAAE,MAAM,GAAG,wBAAwB;CAGrE;AAED,eAAO,MAAM,UAAU,YAAmB,CAAC"}
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OpenRouter service implementation.
|
|
3
|
+
*
|
|
4
|
+
* OpenRouter issues personal API keys from the dashboard, and a key's value is
|
|
5
|
+
* revealed exactly once at creation time (like Linear). We sign the user into
|
|
6
|
+
* openrouter.ai, create a fresh API key on their behalf, and read its value from
|
|
7
|
+
* the one-time reveal dialog.
|
|
8
|
+
*
|
|
9
|
+
* The OpenRouter API is OpenAI-compatible: every request authenticates with a
|
|
10
|
+
* single `Authorization: Bearer sk-or-v1-...` header, so we store an
|
|
11
|
+
* AuthorizationBearer credential and let it inject that header into every
|
|
12
|
+
* matching request.
|
|
13
|
+
*/
|
|
14
|
+
import { AuthorizationBearer } from '../apiCredentials/base.js';
|
|
15
|
+
import { typeLikeHuman } from '../playwrightUtils.js';
|
|
16
|
+
import { Service, BrowserFollowupServiceSession, FollowupWork, LoginFailedError, } from './core/base.js';
|
|
17
|
+
const DEFAULT_TIMEOUT_MS = 12000;
|
|
18
|
+
// The OpenRouter REST API (OpenAI-compatible), served under /api/v1.
|
|
19
|
+
const OPENROUTER_API_BASE_URL = 'https://openrouter.ai/api/v1/';
|
|
20
|
+
const OPENROUTER_LOGIN_URL = 'https://openrouter.ai/sign-in';
|
|
21
|
+
// The dashboard's API-keys page. It redirects to the workspace-scoped keys page
|
|
22
|
+
// (/workspaces/<workspace>/keys); a plain goto follows that redirect.
|
|
23
|
+
const OPENROUTER_KEYS_URL = 'https://openrouter.ai/keys';
|
|
24
|
+
// GET /api/v1/key returns the calling key's metadata (label, usage, limit) and
|
|
25
|
+
// answers 200 for any valid key, so it doubles as the credential check.
|
|
26
|
+
const OPENROUTER_KEY_INFO_URL = 'https://openrouter.ai/api/v1/key';
|
|
27
|
+
// Dashboard host, and the path prefixes served before the user is signed in. A
|
|
28
|
+
// dashboard document response on any *other* path only happens once login has
|
|
29
|
+
// succeeded, so we use it as the login-complete signal (works the same whether
|
|
30
|
+
// the user signs in with a password or an SSO provider, since the final redirect
|
|
31
|
+
// target is always a dashboard page). A new device also gets an email one-time
|
|
32
|
+
// code under /sign-in, which this pattern keeps waiting through.
|
|
33
|
+
const OPENROUTER_HOST = 'openrouter.ai';
|
|
34
|
+
const OPENROUTER_PRE_LOGIN_PATH_PATTERN = /^\/(sign-in|sign-up|signin|signup|sso|oauth|auth)/i;
|
|
35
|
+
// OpenRouter keys are prefixed `sk-or-v1-`; the reveal dialog renders the value
|
|
36
|
+
// as plain text (not inside an input), so we extract it from the dialog text.
|
|
37
|
+
const OPENROUTER_KEY_PATTERN = /sk-or-v1-[A-Za-z0-9-]+/;
|
|
38
|
+
class OpenrouterServiceSession extends BrowserFollowupServiceSession {
|
|
39
|
+
followupWork = FollowupWork.CreateApiToken;
|
|
40
|
+
isLoggedIn = false;
|
|
41
|
+
onResponse(response) {
|
|
42
|
+
if (this.isLoggedIn) {
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
if (response.request().resourceType() !== 'document') {
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
let url;
|
|
49
|
+
try {
|
|
50
|
+
url = new URL(response.url());
|
|
51
|
+
}
|
|
52
|
+
catch {
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
if (url.hostname !== OPENROUTER_HOST) {
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
if (OPENROUTER_PRE_LOGIN_PATH_PATTERN.test(url.pathname)) {
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
if (response.status() >= 200 && response.status() < 400) {
|
|
62
|
+
this.isLoggedIn = true;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
isLoginComplete() {
|
|
66
|
+
return this.isLoggedIn;
|
|
67
|
+
}
|
|
68
|
+
async performBrowserFollowup(context, _oldCredentials) {
|
|
69
|
+
const page = context.pages()[0];
|
|
70
|
+
if (!page) {
|
|
71
|
+
throw new LoginFailedError('No page available in browser context.');
|
|
72
|
+
}
|
|
73
|
+
await page.goto(OPENROUTER_KEYS_URL, { waitUntil: 'domcontentloaded' });
|
|
74
|
+
// Open the "Create API Key" dialog. The keys page is a heavy client-rendered
|
|
75
|
+
// table, so the New Key button can sit in the DOM before React attaches its
|
|
76
|
+
// click handler; a too-early click is a no-op. Click until the dialog's name
|
|
77
|
+
// field actually appears (guarding against re-clicking an already-open
|
|
78
|
+
// dialog, whose overlay would swallow the click).
|
|
79
|
+
const newKeyButton = page.getByRole('button', { name: 'New Key' });
|
|
80
|
+
await newKeyButton.waitFor({ timeout: DEFAULT_TIMEOUT_MS });
|
|
81
|
+
const nameInput = page.locator('input#name');
|
|
82
|
+
for (let attempt = 0; attempt < 5; attempt++) {
|
|
83
|
+
const alreadyOpen = await nameInput.isVisible().catch(() => false);
|
|
84
|
+
if (!alreadyOpen) {
|
|
85
|
+
await newKeyButton.click().catch(() => undefined);
|
|
86
|
+
}
|
|
87
|
+
try {
|
|
88
|
+
await nameInput.waitFor({ timeout: 3000 });
|
|
89
|
+
break;
|
|
90
|
+
}
|
|
91
|
+
catch {
|
|
92
|
+
if (attempt === 4) {
|
|
93
|
+
throw new LoginFailedError('OpenRouter "New Key" dialog did not open.');
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
// Give the key a recognizable name so the user can find and revoke it.
|
|
98
|
+
const keyName = this.generateAppName();
|
|
99
|
+
await typeLikeHuman(page, nameInput, keyName);
|
|
100
|
+
// Scope to the named dialog: a bare [role="dialog"] is ambiguous on this page
|
|
101
|
+
// (it also matches a hidden email-verification dialog and a password-manager
|
|
102
|
+
// modal), which makes every locator under it strict-mode-fail. The dialog keeps
|
|
103
|
+
// this title through the reveal step. Its Create button stays disabled until the
|
|
104
|
+
// name is non-empty.
|
|
105
|
+
const dialog = page.getByRole('dialog', { name: 'Create API Key' });
|
|
106
|
+
const createButton = dialog.getByRole('button', { name: 'Create', exact: true });
|
|
107
|
+
await createButton.waitFor({ timeout: DEFAULT_TIMEOUT_MS });
|
|
108
|
+
await createButton.click();
|
|
109
|
+
// The same dialog then reveals the new key exactly once, as plain text.
|
|
110
|
+
await dialog.getByText('Your new key:').waitFor({ timeout: DEFAULT_TIMEOUT_MS });
|
|
111
|
+
const dialogText = await dialog.innerText();
|
|
112
|
+
const match = OPENROUTER_KEY_PATTERN.exec(dialogText);
|
|
113
|
+
if (!match) {
|
|
114
|
+
throw new LoginFailedError('Failed to extract API key from OpenRouter.');
|
|
115
|
+
}
|
|
116
|
+
await page.close();
|
|
117
|
+
return new AuthorizationBearer(match[0]);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
export class Openrouter extends Service {
|
|
121
|
+
name = 'openrouter';
|
|
122
|
+
displayName = 'OpenRouter';
|
|
123
|
+
baseApiUrls = [OPENROUTER_API_BASE_URL];
|
|
124
|
+
loginUrl = OPENROUTER_LOGIN_URL;
|
|
125
|
+
info = 'OpenRouter unified LLM API (OpenAI-compatible). Docs: https://openrouter.ai/docs/llms.txt';
|
|
126
|
+
// GET /api/v1/key returns 200 for any valid key; the stored bearer header is
|
|
127
|
+
// added by the credential before the request is sent.
|
|
128
|
+
credentialCheckCurlArguments = [OPENROUTER_KEY_INFO_URL];
|
|
129
|
+
setCredentialsExample(serviceName) {
|
|
130
|
+
return `latchkey auth set ${serviceName} -H "Authorization: Bearer <token>"`;
|
|
131
|
+
}
|
|
132
|
+
// An OpenRouter API key has no queryable user-identity endpoint, so the account
|
|
133
|
+
// is left as the default rather than guessed.
|
|
134
|
+
getAccount(_apiCredentials) {
|
|
135
|
+
return Promise.resolve(null);
|
|
136
|
+
}
|
|
137
|
+
getSession(appNamePrefix) {
|
|
138
|
+
return new OpenrouterServiceSession(this, appNamePrefix);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
export const OPENROUTER = new Openrouter();
|
|
142
|
+
//# sourceMappingURL=openrouter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openrouter.js","sourceRoot":"","sources":["../../../src/services/openrouter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tailscale service implementation.
|
|
3
|
+
*
|
|
4
|
+
* The Tailscale admin API (https://api.tailscale.com/api/v2/) authenticates with
|
|
5
|
+
* an API access token (`tskey-api-...`) that an Owner/Admin creates in the
|
|
6
|
+
* admin console's Keys page. The token's value is revealed exactly once at
|
|
7
|
+
* creation time (like Linear, HuggingFace and OpenRouter), so we sign the user
|
|
8
|
+
* into the admin console, generate a fresh access token on their behalf, and
|
|
9
|
+
* read its value from the one-time reveal dialog.
|
|
10
|
+
*
|
|
11
|
+
* A single API access token grants the full set of actions its owning user may
|
|
12
|
+
* perform: tailnet-wide user management (role changes, approval, suspension,
|
|
13
|
+
* deletion), device management, ACL/policy, DNS, and the minting of further
|
|
14
|
+
* keys (including the auth keys the `tailscale` CLI consumes to bring up
|
|
15
|
+
* nodes). It expires after at most 90 days, after which the user re-runs the
|
|
16
|
+
* browser login to mint a new one -- the token is static and is not refreshable.
|
|
17
|
+
*/
|
|
18
|
+
import type { Response, BrowserContext } from 'playwright';
|
|
19
|
+
import { z } from 'zod';
|
|
20
|
+
import { ApiCredentialStatus, ApiCredentials } from '../apiCredentials/base.js';
|
|
21
|
+
import { Service, BrowserFollowupServiceSession, FollowupWork } from './core/base.js';
|
|
22
|
+
/**
|
|
23
|
+
* Credentials for the Tailscale API: a static API access token plus the tailnet
|
|
24
|
+
* it belongs to. The tailnet is part of nearly every useful Tailscale API path
|
|
25
|
+
* and the API exposes no tailnet-independent way to validate a token, so the
|
|
26
|
+
* connector captures it at mint time (it is shown in the admin console's
|
|
27
|
+
* navigation) and stores it alongside the token.
|
|
28
|
+
*/
|
|
29
|
+
export declare const TailscaleCredentialsSchema: z.ZodObject<{
|
|
30
|
+
objectType: z.ZodLiteral<"tailscale">;
|
|
31
|
+
token: z.ZodString;
|
|
32
|
+
tailnet: z.ZodString;
|
|
33
|
+
}, "strip", z.ZodTypeAny, {
|
|
34
|
+
objectType: "tailscale";
|
|
35
|
+
token: string;
|
|
36
|
+
tailnet: string;
|
|
37
|
+
}, {
|
|
38
|
+
objectType: "tailscale";
|
|
39
|
+
token: string;
|
|
40
|
+
tailnet: string;
|
|
41
|
+
}>;
|
|
42
|
+
export type TailscaleCredentialsData = z.infer<typeof TailscaleCredentialsSchema>;
|
|
43
|
+
export declare class TailscaleCredentials implements ApiCredentials {
|
|
44
|
+
readonly objectType: "tailscale";
|
|
45
|
+
readonly token: string;
|
|
46
|
+
readonly tailnet: string;
|
|
47
|
+
constructor(token: string, tailnet: string);
|
|
48
|
+
injectIntoCurlCall(curlArguments: readonly string[]): Promise<readonly string[]>;
|
|
49
|
+
isExpired(): boolean | undefined;
|
|
50
|
+
toJSON(): TailscaleCredentialsData;
|
|
51
|
+
static fromJSON(data: TailscaleCredentialsData): TailscaleCredentials;
|
|
52
|
+
}
|
|
53
|
+
declare class TailscaleServiceSession extends BrowserFollowupServiceSession {
|
|
54
|
+
protected readonly followupWork = FollowupWork.CreateApiToken;
|
|
55
|
+
private isLoggedIn;
|
|
56
|
+
onResponse(response: Response): void;
|
|
57
|
+
protected isLoginComplete(): boolean;
|
|
58
|
+
protected performBrowserFollowup(context: BrowserContext, _oldCredentials?: ApiCredentials): Promise<ApiCredentials | null>;
|
|
59
|
+
}
|
|
60
|
+
export declare class Tailscale extends Service {
|
|
61
|
+
readonly name = "tailscale";
|
|
62
|
+
readonly displayName = "Tailscale";
|
|
63
|
+
readonly baseApiUrls: readonly ["https://api.tailscale.com/"];
|
|
64
|
+
readonly loginUrl = "https://login.tailscale.com/admin";
|
|
65
|
+
readonly info: string;
|
|
66
|
+
readonly credentialCheckCurlArguments: readonly [];
|
|
67
|
+
checkApiCredentials(apiCredentials: ApiCredentials): Promise<ApiCredentialStatus>;
|
|
68
|
+
setCredentialsExample(serviceName: string): string;
|
|
69
|
+
getAccount(apiCredentials: ApiCredentials): Promise<string | null>;
|
|
70
|
+
getSession(appNamePrefix: string): TailscaleServiceSession;
|
|
71
|
+
}
|
|
72
|
+
export declare const TAILSCALE: Tailscale;
|
|
73
|
+
export {};
|
|
74
|
+
//# sourceMappingURL=tailscale.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tailscale.d.ts","sourceRoot":"","sources":["../../../src/services/tailscale.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAC3D,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,mBAAmB,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAGhF,OAAO,EACL,OAAO,EACP,6BAA6B,EAC7B,YAAY,EAIb,MAAM,gBAAgB,CAAC;AA4BxB;;;;;;GAMG;AACH,eAAO,MAAM,0BAA0B;;;;;;;;;;;;EAIrC,CAAC;AAEH,MAAM,MAAM,wBAAwB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,0BAA0B,CAAC,CAAC;AAElF,qBAAa,oBAAqB,YAAW,cAAc;IACzD,QAAQ,CAAC,UAAU,EAAG,WAAW,CAAU;IAC3C,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;gBAEb,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM;IAK1C,kBAAkB,CAAC,aAAa,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAAC,SAAS,MAAM,EAAE,CAAC;IAOhF,SAAS,IAAI,OAAO,GAAG,SAAS;IAIhC,MAAM,IAAI,wBAAwB;IAQlC,MAAM,CAAC,QAAQ,CAAC,IAAI,EAAE,wBAAwB,GAAG,oBAAoB;CAGtE;AAED,cAAM,uBAAwB,SAAQ,6BAA6B;IACjE,SAAS,CAAC,QAAQ,CAAC,YAAY,+BAA+B;IAC9D,OAAO,CAAC,UAAU,CAAS;IAE3B,UAAU,CAAC,QAAQ,EAAE,QAAQ,GAAG,IAAI;IAqBpC,SAAS,CAAC,eAAe,IAAI,OAAO;cAIpB,sBAAsB,CACpC,OAAO,EAAE,cAAc,EACvB,eAAe,CAAC,EAAE,cAAc,GAC/B,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC;CA+DlC;AAED,qBAAa,SAAU,SAAQ,OAAO;IACpC,QAAQ,CAAC,IAAI,eAAe;IAC5B,QAAQ,CAAC,WAAW,eAAe;IACnC,QAAQ,CAAC,WAAW,0CAAqC;IACzD,QAAQ,CAAC,QAAQ,uCAAuB;IACxC,QAAQ,CAAC,IAAI,SAO4B;IAKzC,QAAQ,CAAC,4BAA4B,cAAe;IAErC,mBAAmB,CAAC,cAAc,EAAE,cAAc,GAAG,OAAO,CAAC,mBAAmB,CAAC;IA4BhG,qBAAqB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM;IAOzC,UAAU,CAAC,cAAc,EAAE,cAAc,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAOlE,UAAU,CAAC,aAAa,EAAE,MAAM,GAAG,uBAAuB;CAGpE;AAED,eAAO,MAAM,SAAS,WAAkB,CAAC"}
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tailscale service implementation.
|
|
3
|
+
*
|
|
4
|
+
* The Tailscale admin API (https://api.tailscale.com/api/v2/) authenticates with
|
|
5
|
+
* an API access token (`tskey-api-...`) that an Owner/Admin creates in the
|
|
6
|
+
* admin console's Keys page. The token's value is revealed exactly once at
|
|
7
|
+
* creation time (like Linear, HuggingFace and OpenRouter), so we sign the user
|
|
8
|
+
* into the admin console, generate a fresh access token on their behalf, and
|
|
9
|
+
* read its value from the one-time reveal dialog.
|
|
10
|
+
*
|
|
11
|
+
* A single API access token grants the full set of actions its owning user may
|
|
12
|
+
* perform: tailnet-wide user management (role changes, approval, suspension,
|
|
13
|
+
* deletion), device management, ACL/policy, DNS, and the minting of further
|
|
14
|
+
* keys (including the auth keys the `tailscale` CLI consumes to bring up
|
|
15
|
+
* nodes). It expires after at most 90 days, after which the user re-runs the
|
|
16
|
+
* browser login to mint a new one -- the token is static and is not refreshable.
|
|
17
|
+
*/
|
|
18
|
+
import { z } from 'zod';
|
|
19
|
+
import { ApiCredentialStatus } from '../apiCredentials/base.js';
|
|
20
|
+
import { typeLikeHuman } from '../playwrightUtils.js';
|
|
21
|
+
import { runCapturedAsync } from '../curl.js';
|
|
22
|
+
import { Service, BrowserFollowupServiceSession, FollowupWork, LoginFailedError, isBrowserClosedError, LoginCancelledError, } from './core/base.js';
|
|
23
|
+
const DEFAULT_TIMEOUT_MS = 30000;
|
|
24
|
+
// The Tailscale admin REST API.
|
|
25
|
+
const TAILSCALE_API_BASE_URL = 'https://api.tailscale.com/';
|
|
26
|
+
// `latchkey auth browser` opens this; it redirects to the SSO sign-in page and
|
|
27
|
+
// then back to the admin console once the user is signed in.
|
|
28
|
+
const TAILSCALE_LOGIN_URL = 'https://login.tailscale.com/admin';
|
|
29
|
+
// The admin console's Keys page, where API access tokens are generated.
|
|
30
|
+
const TAILSCALE_KEYS_URL = 'https://console.tailscale.com/admin/settings/keys';
|
|
31
|
+
// The admin console host; a document response served from it means the user is
|
|
32
|
+
// signed in (the sign-in flow itself is served from login.tailscale.com and the
|
|
33
|
+
// SSO provider).
|
|
34
|
+
const TAILSCALE_CONSOLE_HOST = 'console.tailscale.com';
|
|
35
|
+
// GET /tailnet/{tailnet}/settings is a cheap read that answers 200 for any
|
|
36
|
+
// valid token with the access the API access token carries (full user powers).
|
|
37
|
+
// It doubles as the credential check once the tailnet is known.
|
|
38
|
+
const TAILSCALE_SETTINGS_URL_PREFIX = 'https://api.tailscale.com/api/v2/tailnet/';
|
|
39
|
+
// API access tokens are prefixed `tskey-api-`; the reveal dialog renders the
|
|
40
|
+
// value as plain text (not inside an input).
|
|
41
|
+
const TAILSCALE_TOKEN_PATTERN = /tskey-api-[A-Za-z0-9-]+/;
|
|
42
|
+
/**
|
|
43
|
+
* Credentials for the Tailscale API: a static API access token plus the tailnet
|
|
44
|
+
* it belongs to. The tailnet is part of nearly every useful Tailscale API path
|
|
45
|
+
* and the API exposes no tailnet-independent way to validate a token, so the
|
|
46
|
+
* connector captures it at mint time (it is shown in the admin console's
|
|
47
|
+
* navigation) and stores it alongside the token.
|
|
48
|
+
*/
|
|
49
|
+
export const TailscaleCredentialsSchema = z.object({
|
|
50
|
+
objectType: z.literal('tailscale'),
|
|
51
|
+
token: z.string(),
|
|
52
|
+
tailnet: z.string(),
|
|
53
|
+
});
|
|
54
|
+
export class TailscaleCredentials {
|
|
55
|
+
objectType = 'tailscale';
|
|
56
|
+
token;
|
|
57
|
+
tailnet;
|
|
58
|
+
constructor(token, tailnet) {
|
|
59
|
+
this.token = token;
|
|
60
|
+
this.tailnet = tailnet;
|
|
61
|
+
}
|
|
62
|
+
injectIntoCurlCall(curlArguments) {
|
|
63
|
+
return Promise.resolve(['-H', `Authorization: Bearer ${this.token}`, ...curlArguments]);
|
|
64
|
+
}
|
|
65
|
+
// The token is static and its expiry date is not exposed in a parseable form
|
|
66
|
+
// at creation time; validity is determined by the live credential check
|
|
67
|
+
// rather than a local clock.
|
|
68
|
+
isExpired() {
|
|
69
|
+
return undefined;
|
|
70
|
+
}
|
|
71
|
+
toJSON() {
|
|
72
|
+
return {
|
|
73
|
+
objectType: this.objectType,
|
|
74
|
+
token: this.token,
|
|
75
|
+
tailnet: this.tailnet,
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
static fromJSON(data) {
|
|
79
|
+
return new TailscaleCredentials(data.token, data.tailnet);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
class TailscaleServiceSession extends BrowserFollowupServiceSession {
|
|
83
|
+
followupWork = FollowupWork.CreateApiToken;
|
|
84
|
+
isLoggedIn = false;
|
|
85
|
+
onResponse(response) {
|
|
86
|
+
if (this.isLoggedIn) {
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
if (response.request().resourceType() !== 'document') {
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
let url;
|
|
93
|
+
try {
|
|
94
|
+
url = new URL(response.url());
|
|
95
|
+
}
|
|
96
|
+
catch {
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
if (url.hostname !== TAILSCALE_CONSOLE_HOST) {
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
if (response.status() >= 200 && response.status() < 400) {
|
|
103
|
+
this.isLoggedIn = true;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
isLoginComplete() {
|
|
107
|
+
return this.isLoggedIn;
|
|
108
|
+
}
|
|
109
|
+
async performBrowserFollowup(context, _oldCredentials) {
|
|
110
|
+
const page = context.pages()[0];
|
|
111
|
+
if (!page) {
|
|
112
|
+
throw new LoginFailedError('No page available in browser context.');
|
|
113
|
+
}
|
|
114
|
+
try {
|
|
115
|
+
await page.goto(TAILSCALE_KEYS_URL, { waitUntil: 'domcontentloaded' });
|
|
116
|
+
// The tailnet name is the first link in the admin shell's navigation; it
|
|
117
|
+
// is part of every useful API call, so read it before the mint dialog
|
|
118
|
+
// covers the page.
|
|
119
|
+
const tailnetLink = page.locator('#app-root a').first();
|
|
120
|
+
await tailnetLink.waitFor({ timeout: DEFAULT_TIMEOUT_MS });
|
|
121
|
+
const tailnet = (await tailnetLink.innerText()).trim();
|
|
122
|
+
if (!tailnet) {
|
|
123
|
+
throw new LoginFailedError('Failed to read the Tailscale tailnet name.');
|
|
124
|
+
}
|
|
125
|
+
// Open the "Generate API access token" dialog. There are two "Generate..."
|
|
126
|
+
// buttons on the Keys page (auth key and access token); the access-token
|
|
127
|
+
// one is labelled with a trailing ellipsis, which distinguishes it from
|
|
128
|
+
// the dialog's submit button.
|
|
129
|
+
const openButton = page.getByRole('button', { name: 'Generate access token\u2026' });
|
|
130
|
+
await openButton.waitFor({ timeout: DEFAULT_TIMEOUT_MS });
|
|
131
|
+
await openButton.click();
|
|
132
|
+
const mintDialog = page.getByRole('dialog', { name: 'Generate API access token' });
|
|
133
|
+
await mintDialog.waitFor({ timeout: DEFAULT_TIMEOUT_MS });
|
|
134
|
+
// The description input is the first input in the dialog (the "Add an
|
|
135
|
+
// optional description" text above it is a label, not a placeholder).
|
|
136
|
+
const descriptionInput = mintDialog.locator('input').first();
|
|
137
|
+
await descriptionInput.waitFor({ timeout: DEFAULT_TIMEOUT_MS });
|
|
138
|
+
await typeLikeHuman(page, descriptionInput, this.generateAppName());
|
|
139
|
+
// Expiration defaults to 90 days; leave it as-is.
|
|
140
|
+
const generateButton = mintDialog.getByRole('button', {
|
|
141
|
+
name: 'Generate access token',
|
|
142
|
+
exact: true,
|
|
143
|
+
});
|
|
144
|
+
await generateButton.waitFor({ timeout: DEFAULT_TIMEOUT_MS });
|
|
145
|
+
await generateButton.click();
|
|
146
|
+
// The same dialog is then reused to reveal the new token exactly once,
|
|
147
|
+
// as plain text.
|
|
148
|
+
const revealDialog = page.getByRole('dialog', { name: 'Generated new key' });
|
|
149
|
+
await revealDialog.waitFor({ timeout: DEFAULT_TIMEOUT_MS });
|
|
150
|
+
const revealText = await revealDialog.innerText();
|
|
151
|
+
const match = TAILSCALE_TOKEN_PATTERN.exec(revealText);
|
|
152
|
+
if (!match) {
|
|
153
|
+
throw new LoginFailedError('Failed to extract the API access token from Tailscale.');
|
|
154
|
+
}
|
|
155
|
+
await page.close();
|
|
156
|
+
return new TailscaleCredentials(match[0], tailnet);
|
|
157
|
+
}
|
|
158
|
+
catch (error) {
|
|
159
|
+
if (error instanceof Error && isBrowserClosedError(error)) {
|
|
160
|
+
throw new LoginCancelledError();
|
|
161
|
+
}
|
|
162
|
+
throw error;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
export class Tailscale extends Service {
|
|
167
|
+
name = 'tailscale';
|
|
168
|
+
displayName = 'Tailscale';
|
|
169
|
+
baseApiUrls = [TAILSCALE_API_BASE_URL];
|
|
170
|
+
loginUrl = TAILSCALE_LOGIN_URL;
|
|
171
|
+
info = 'Tailscale admin API for tailnet-wide management (users, devices, policy, keys). ' +
|
|
172
|
+
'Docs: https://tailscale.com/docs/reference/tailscale-api and interactive ' +
|
|
173
|
+
'https://tailscale.com/api. A browser login mints an API access token (tskey-api) ' +
|
|
174
|
+
'that carries the full set of actions its owning user may perform and expires ' +
|
|
175
|
+
'after at most 90 days; re-run the login to mint a new one. Most endpoints are ' +
|
|
176
|
+
'scoped to a tailnet (e.g. /api/v2/tailnet/{tailnet}/users); the stored credential ' +
|
|
177
|
+
'remembers the tailnet seen at login.';
|
|
178
|
+
// The credential check needs the tailnet, which the static
|
|
179
|
+
// credentialCheckCurlArguments cannot carry, so checkApiCredentials is
|
|
180
|
+
// overridden below and this value is unused (mirrors RegisteredService).
|
|
181
|
+
credentialCheckCurlArguments = [];
|
|
182
|
+
async checkApiCredentials(apiCredentials) {
|
|
183
|
+
// The tailnet is needed to validate a token and is only carried by the
|
|
184
|
+
// browser-minted credential. A manually-set credential (e.g. `auth set -H
|
|
185
|
+
// "Authorization: Bearer ..."`) has no tailnet to build the check URL
|
|
186
|
+
// from, so its status cannot be determined locally; `latchkey curl` still
|
|
187
|
+
// injects it normally.
|
|
188
|
+
if (!(apiCredentials instanceof TailscaleCredentials)) {
|
|
189
|
+
return ApiCredentialStatus.Unknown;
|
|
190
|
+
}
|
|
191
|
+
const checkUrl = `${TAILSCALE_SETTINGS_URL_PREFIX}${encodeURIComponent(apiCredentials.tailnet)}/settings`;
|
|
192
|
+
const result = await runCapturedAsync([
|
|
193
|
+
'-s',
|
|
194
|
+
'-w',
|
|
195
|
+
'\n%{http_code}',
|
|
196
|
+
'-H',
|
|
197
|
+
`Authorization: Bearer ${apiCredentials.token}`,
|
|
198
|
+
checkUrl,
|
|
199
|
+
], 10);
|
|
200
|
+
// The `-w '\n%{http_code}'` above appends the status code as the final line.
|
|
201
|
+
const statusCode = result.stdout.slice(result.stdout.lastIndexOf('\n') + 1).trim();
|
|
202
|
+
return statusCode === '200' ? ApiCredentialStatus.Valid : ApiCredentialStatus.Invalid;
|
|
203
|
+
}
|
|
204
|
+
setCredentialsExample(serviceName) {
|
|
205
|
+
return `latchkey auth set ${serviceName} -H "Authorization: Bearer <token>"`;
|
|
206
|
+
}
|
|
207
|
+
// The API access token is owned by the user who minted it but exposes no
|
|
208
|
+
// queryable "current user" endpoint; the tailnet it belongs to is the most
|
|
209
|
+
// meaningful account identifier available without an extra request.
|
|
210
|
+
getAccount(apiCredentials) {
|
|
211
|
+
if (apiCredentials instanceof TailscaleCredentials) {
|
|
212
|
+
return Promise.resolve(apiCredentials.tailnet);
|
|
213
|
+
}
|
|
214
|
+
return Promise.resolve(null);
|
|
215
|
+
}
|
|
216
|
+
getSession(appNamePrefix) {
|
|
217
|
+
return new TailscaleServiceSession(this, appNamePrefix);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
export const TAILSCALE = new Tailscale();
|
|
221
|
+
//# sourceMappingURL=tailscale.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tailscale.js","sourceRoot":"","sources":["../../../src/services/tailscale.ts"],"names":[],"mappings":"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"}
|
package/dist/src/version.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const VERSION = "3.
|
|
1
|
+
export declare const VERSION = "3.6.0";
|
|
2
2
|
//# sourceMappingURL=version.d.ts.map
|
package/dist/src/version.js
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"huggingface.test.d.ts","sourceRoot":"","sources":["../../tests/huggingface.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { HUGGINGFACE } from '../src/services/huggingface.js';
|
|
3
|
+
import { SERVICE_REGISTRY } from '../src/serviceRegistry.js';
|
|
4
|
+
function primaryServiceForUrl(url) {
|
|
5
|
+
return SERVICE_REGISTRY.getByUrl(url);
|
|
6
|
+
}
|
|
7
|
+
describe('Hugging Face URL matching', () => {
|
|
8
|
+
it('matches the Hub API on both hub hostnames', () => {
|
|
9
|
+
expect(primaryServiceForUrl('https://huggingface.co/api/whoami-v2')).toBe(HUGGINGFACE);
|
|
10
|
+
expect(primaryServiceForUrl('https://hf.co/api/models?limit=1')).toBe(HUGGINGFACE);
|
|
11
|
+
});
|
|
12
|
+
it('matches repository file transfers and git endpoints', () => {
|
|
13
|
+
expect(primaryServiceForUrl('https://huggingface.co/openai-community/gpt2/resolve/main/config.json')).toBe(HUGGINGFACE);
|
|
14
|
+
expect(primaryServiceForUrl('https://huggingface.co/owner/repo.git/info/refs?service=git-upload-pack')).toBe(HUGGINGFACE);
|
|
15
|
+
});
|
|
16
|
+
it('matches the inference router and the dataset viewer', () => {
|
|
17
|
+
expect(primaryServiceForUrl('https://router.huggingface.co/v1/chat/completions')).toBe(HUGGINGFACE);
|
|
18
|
+
expect(primaryServiceForUrl('https://datasets-server.huggingface.co/rows?dataset=x')).toBe(HUGGINGFACE);
|
|
19
|
+
});
|
|
20
|
+
// Redirected file transfers are authenticated by the URL itself, so the
|
|
21
|
+
// storage hosts are left to the caller: a bearer header would be pointless
|
|
22
|
+
// there, and the Xet CAS server even rejects the request once it sees a
|
|
23
|
+
// second Authorization header.
|
|
24
|
+
it('does not match the storage hosts that transfers are redirected to', () => {
|
|
25
|
+
expect(primaryServiceForUrl('https://us.aws.cdn.hf.co/xet-bridge-us/abc?Expires=1&Signature=x')).toBeNull();
|
|
26
|
+
expect(primaryServiceForUrl('https://cdn-lfs.hf.co/repos/aa/bb/file?Expires=1')).toBeNull();
|
|
27
|
+
expect(primaryServiceForUrl('https://cdn-lfs-us-1.hf.co/repos/aa/bb/file')).toBeNull();
|
|
28
|
+
expect(primaryServiceForUrl('https://cas-server.xethub.hf.co/reconstruction/abc')).toBeNull();
|
|
29
|
+
expect(primaryServiceForUrl('https://transfer.xethub.hf.co/xorbs/default/abc')).toBeNull();
|
|
30
|
+
});
|
|
31
|
+
it('does not match unrelated hosts, including hosted Spaces', () => {
|
|
32
|
+
expect(primaryServiceForUrl('https://myspace.hf.space/api/predict')).toBeNull();
|
|
33
|
+
expect(primaryServiceForUrl('https://hf.co.example.com/api/models')).toBeNull();
|
|
34
|
+
});
|
|
35
|
+
});
|
|
36
|
+
//# sourceMappingURL=huggingface.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"huggingface.test.js","sourceRoot":"","sources":["../../tests/huggingface.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,WAAW,EAAE,MAAM,gCAAgC,CAAC;AAC7D,OAAO,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAG7D,SAAS,oBAAoB,CAAC,GAAW;IACvC,OAAO,gBAAgB,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;AACxC,CAAC;AAED,QAAQ,CAAC,2BAA2B,EAAE,GAAG,EAAE;IACzC,EAAE,CAAC,2CAA2C,EAAE,GAAG,EAAE;QACnD,MAAM,CAAC,oBAAoB,CAAC,sCAAsC,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;QACvF,MAAM,CAAC,oBAAoB,CAAC,kCAAkC,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;IACrF,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,qDAAqD,EAAE,GAAG,EAAE;QAC7D,MAAM,CACJ,oBAAoB,CAAC,uEAAuE,CAAC,CAC9F,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;QACpB,MAAM,CACJ,oBAAoB,CAClB,yEAAyE,CAC1E,CACF,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;IACtB,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,qDAAqD,EAAE,GAAG,EAAE;QAC7D,MAAM,CAAC,oBAAoB,CAAC,mDAAmD,CAAC,CAAC,CAAC,IAAI,CACpF,WAAW,CACZ,CAAC;QACF,MAAM,CAAC,oBAAoB,CAAC,uDAAuD,CAAC,CAAC,CAAC,IAAI,CACxF,WAAW,CACZ,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,wEAAwE;IACxE,2EAA2E;IAC3E,wEAAwE;IACxE,+BAA+B;IAC/B,EAAE,CAAC,mEAAmE,EAAE,GAAG,EAAE;QAC3E,MAAM,CACJ,oBAAoB,CAAC,kEAAkE,CAAC,CACzF,CAAC,QAAQ,EAAE,CAAC;QACb,MAAM,CAAC,oBAAoB,CAAC,kDAAkD,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC;QAC5F,MAAM,CAAC,oBAAoB,CAAC,6CAA6C,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC;QACvF,MAAM,CAAC,oBAAoB,CAAC,oDAAoD,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC;QAC9F,MAAM,CAAC,oBAAoB,CAAC,iDAAiD,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC;IAC7F,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,yDAAyD,EAAE,GAAG,EAAE;QACjE,MAAM,CAAC,oBAAoB,CAAC,sCAAsC,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC;QAChF,MAAM,CAAC,oBAAoB,CAAC,sCAAsC,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC;IAClF,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -32,11 +32,20 @@ const DEFAULT_RECORDING_NAME = 'login_session.json';
|
|
|
32
32
|
// Do not test services that require special followup steps: their credential is
|
|
33
33
|
// minted by an interactive browser action (a BrowserFollowupServiceSession) and
|
|
34
34
|
// is not present in the recorded login network traffic, so replaying a recording
|
|
35
|
-
// cannot reconstruct it. ngrok
|
|
36
|
-
//
|
|
35
|
+
// cannot reconstruct it. ngrok, huggingface, openrouter and tailscale are such
|
|
36
|
+
// services -- their token is created and read from a one-time reveal dialog,
|
|
37
|
+
// exactly like linear.
|
|
37
38
|
// NOTE: todoist is also a BrowserFollowupServiceSession and arguably belongs here
|
|
38
39
|
// too; it predates this list and is left as-is to keep this change scoped.
|
|
39
|
-
const BLACKLIST = new Set([
|
|
40
|
+
const BLACKLIST = new Set([
|
|
41
|
+
'dropbox',
|
|
42
|
+
'github',
|
|
43
|
+
'linear',
|
|
44
|
+
'ngrok',
|
|
45
|
+
'huggingface',
|
|
46
|
+
'openrouter',
|
|
47
|
+
'tailscale',
|
|
48
|
+
]);
|
|
40
49
|
class InvalidRecordingError extends Error {
|
|
41
50
|
constructor(message) {
|
|
42
51
|
super(message);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"servicesAgainstRecordings.test.js","sourceRoot":"","sources":["../../tests/servicesAgainstRecordings.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAChE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACnD,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAG9C,OAAO,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAC7D,OAAO,EAAW,oBAAoB,EAAE,MAAM,8BAA8B,CAAC;AAE7E,iCAAiC;AACjC,MAAM,UAAU,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAClD,MAAM,SAAS,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;AAEtC,6CAA6C;AAC7C,MAAM,oBAAoB,GAAG,OAAO,CAAC,SAAS,EAAE,IAAI,EAAE,SAAS,EAAE,YAAY,CAAC,CAAC;AAE/E,+DAA+D;AAC/D,MAAM,sBAAsB,GAAG,oBAAoB,CAAC;AAEpD,gFAAgF;AAChF,gFAAgF;AAChF,iFAAiF;AACjF,
|
|
1
|
+
{"version":3,"file":"servicesAgainstRecordings.test.js","sourceRoot":"","sources":["../../tests/servicesAgainstRecordings.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tailscale.test.d.ts","sourceRoot":"","sources":["../../tests/tailscale.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { describe, it, expect, afterEach } from 'vitest';
|
|
2
|
+
import { TAILSCALE, TailscaleCredentials } from '../src/services/tailscale.js';
|
|
3
|
+
import { ApiCredentialStatus } from '../src/apiCredentials/base.js';
|
|
4
|
+
import { serializeCredentials, deserializeCredentials, ApiCredentialsSchema, } from '../src/apiCredentials/serialization.js';
|
|
5
|
+
import { SERVICE_REGISTRY } from '../src/serviceRegistry.js';
|
|
6
|
+
import { resetAsyncSubprocessRunner, setAsyncSubprocessRunner } from '../src/curl.js';
|
|
7
|
+
afterEach(() => {
|
|
8
|
+
resetAsyncSubprocessRunner();
|
|
9
|
+
});
|
|
10
|
+
function mockCurlStdout(stdout) {
|
|
11
|
+
setAsyncSubprocessRunner(() => Promise.resolve({ returncode: 0, stdout: Buffer.from(stdout), stderr: '' }));
|
|
12
|
+
}
|
|
13
|
+
function primaryServiceForUrl(url) {
|
|
14
|
+
return SERVICE_REGISTRY.getByUrl(url);
|
|
15
|
+
}
|
|
16
|
+
describe('Tailscale URL matching', () => {
|
|
17
|
+
it('matches the admin API host and not lookalikes', () => {
|
|
18
|
+
expect(primaryServiceForUrl('https://api.tailscale.com/api/v2/tailnet/example.com/users')).toBe(TAILSCALE);
|
|
19
|
+
expect(primaryServiceForUrl('https://api.tailscale.com/api/v2/tailnet/example.com/keys')).toBe(TAILSCALE);
|
|
20
|
+
});
|
|
21
|
+
it('does not match the admin console or login host', () => {
|
|
22
|
+
expect(primaryServiceForUrl('https://console.tailscale.com/admin/users')).toBeNull();
|
|
23
|
+
expect(primaryServiceForUrl('https://login.tailscale.com/admin')).toBeNull();
|
|
24
|
+
expect(primaryServiceForUrl('https://api.tailscale.com.example.com/api/v2/')).toBeNull();
|
|
25
|
+
});
|
|
26
|
+
});
|
|
27
|
+
describe('Tailscale credentials', () => {
|
|
28
|
+
it('inject an Authorization: Bearer header', async () => {
|
|
29
|
+
const credentials = new TailscaleCredentials('tskey-api-kTest11CNTRL-secret', 'example.com');
|
|
30
|
+
const injected = await credentials.injectIntoCurlCall(['https://api.tailscale.com/api/v2/']);
|
|
31
|
+
expect(injected).toEqual([
|
|
32
|
+
'-H',
|
|
33
|
+
'Authorization: Bearer tskey-api-kTest11CNTRL-secret',
|
|
34
|
+
'https://api.tailscale.com/api/v2/',
|
|
35
|
+
]);
|
|
36
|
+
});
|
|
37
|
+
it('reports the tailnet as the account and does not claim to know expiry', async () => {
|
|
38
|
+
const credentials = new TailscaleCredentials('tskey-api-kTest11CNTRL-secret', 'example.com');
|
|
39
|
+
expect(await TAILSCALE.getAccount(credentials)).toBe('example.com');
|
|
40
|
+
expect(credentials.isExpired()).toBeUndefined();
|
|
41
|
+
});
|
|
42
|
+
it('survives a serialization round-trip', () => {
|
|
43
|
+
const credentials = new TailscaleCredentials('tskey-api-kRound11CNTRL-secret', 'example.com');
|
|
44
|
+
const data = serializeCredentials(credentials);
|
|
45
|
+
// The discriminated union accepts the serialized form.
|
|
46
|
+
ApiCredentialsSchema.parse(data);
|
|
47
|
+
const restored = deserializeCredentials(data);
|
|
48
|
+
expect(restored).toBeInstanceOf(TailscaleCredentials);
|
|
49
|
+
expect(restored.token).toBe('tskey-api-kRound11CNTRL-secret');
|
|
50
|
+
expect(restored.tailnet).toBe('example.com');
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
describe('Tailscale credential check', () => {
|
|
54
|
+
// The check targets /tailnet/{tailnet}/settings; the response body is
|
|
55
|
+
// irrelevant, only the trailing HTTP status code (appended by `-w`) decides.
|
|
56
|
+
it('reports valid on a 200 from the tailnet settings endpoint', async () => {
|
|
57
|
+
mockCurlStdout('{"httpsEnabled":true}\n200');
|
|
58
|
+
const credentials = new TailscaleCredentials('tskey-api-kTest11CNTRL-secret', 'example.com');
|
|
59
|
+
expect(await TAILSCALE.checkApiCredentials(credentials)).toBe(ApiCredentialStatus.Valid);
|
|
60
|
+
});
|
|
61
|
+
it('reports invalid on a 401 (expired or revoked token)', async () => {
|
|
62
|
+
mockCurlStdout('\n401');
|
|
63
|
+
const credentials = new TailscaleCredentials('tskey-api-kTest11CNTRL-secret', 'example.com');
|
|
64
|
+
expect(await TAILSCALE.checkApiCredentials(credentials)).toBe(ApiCredentialStatus.Invalid);
|
|
65
|
+
});
|
|
66
|
+
it('reports invalid on a 404 (unknown tailnet)', async () => {
|
|
67
|
+
mockCurlStdout('\n404');
|
|
68
|
+
const credentials = new TailscaleCredentials('tskey-api-kTest11CNTRL-secret', 'example.com');
|
|
69
|
+
expect(await TAILSCALE.checkApiCredentials(credentials)).toBe(ApiCredentialStatus.Invalid);
|
|
70
|
+
});
|
|
71
|
+
it('reports unknown for a non-Tailscale credential (manual auth set)', async () => {
|
|
72
|
+
const raw = {
|
|
73
|
+
injectIntoCurlCall: () => Promise.resolve([]),
|
|
74
|
+
isExpired: () => undefined,
|
|
75
|
+
};
|
|
76
|
+
expect(await TAILSCALE.checkApiCredentials(raw)).toBe(ApiCredentialStatus.Unknown);
|
|
77
|
+
});
|
|
78
|
+
});
|
|
79
|
+
//# sourceMappingURL=tailscale.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tailscale.test.js","sourceRoot":"","sources":["../../tests/tailscale.test.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "latchkey",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.6.0",
|
|
4
4
|
"description": "A CLI tool that injects API credentials into curl requests to third-party services",
|
|
5
5
|
"author": "Imbue <hynek@imbue.com>",
|
|
6
6
|
"repository": {
|
|
@@ -58,7 +58,7 @@
|
|
|
58
58
|
"node": ">=20"
|
|
59
59
|
},
|
|
60
60
|
"dependencies": {
|
|
61
|
-
"@imbue-ai/detent": "^1.
|
|
61
|
+
"@imbue-ai/detent": "^1.14.0",
|
|
62
62
|
"@napi-rs/keyring": "^1.2.0",
|
|
63
63
|
"commander": "^12.0.0",
|
|
64
64
|
"playwright": "~1.60.0",
|