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.
Files changed (41) hide show
  1. package/dist/skills/generic/latchkey/SKILL.md +2 -2
  2. package/dist/skills/openclaw/latchkey/SKILL.md +2 -2
  3. package/dist/src/apiCredentials/serialization.d.ts +12 -0
  4. package/dist/src/apiCredentials/serialization.d.ts.map +1 -1
  5. package/dist/src/apiCredentials/serialization.js +7 -0
  6. package/dist/src/apiCredentials/serialization.js.map +1 -1
  7. package/dist/src/serviceRegistry.d.ts.map +1 -1
  8. package/dist/src/serviceRegistry.js +4 -1
  9. package/dist/src/serviceRegistry.js.map +1 -1
  10. package/dist/src/services/google/gmail.d.ts.map +1 -1
  11. package/dist/src/services/google/gmail.js +6 -1
  12. package/dist/src/services/google/gmail.js.map +1 -1
  13. package/dist/src/services/huggingface.d.ts +40 -0
  14. package/dist/src/services/huggingface.d.ts.map +1 -0
  15. package/dist/src/services/huggingface.js +146 -0
  16. package/dist/src/services/huggingface.js.map +1 -0
  17. package/dist/src/services/index.d.ts +3 -0
  18. package/dist/src/services/index.d.ts.map +1 -1
  19. package/dist/src/services/index.js +3 -0
  20. package/dist/src/services/index.js.map +1 -1
  21. package/dist/src/services/openrouter.d.ts +37 -0
  22. package/dist/src/services/openrouter.d.ts.map +1 -0
  23. package/dist/src/services/openrouter.js +142 -0
  24. package/dist/src/services/openrouter.js.map +1 -0
  25. package/dist/src/services/tailscale.d.ts +74 -0
  26. package/dist/src/services/tailscale.d.ts.map +1 -0
  27. package/dist/src/services/tailscale.js +221 -0
  28. package/dist/src/services/tailscale.js.map +1 -0
  29. package/dist/src/version.d.ts +1 -1
  30. package/dist/src/version.js +1 -1
  31. package/dist/tests/huggingface.test.d.ts +2 -0
  32. package/dist/tests/huggingface.test.d.ts.map +1 -0
  33. package/dist/tests/huggingface.test.js +36 -0
  34. package/dist/tests/huggingface.test.js.map +1 -0
  35. package/dist/tests/servicesAgainstRecordings.test.js +12 -3
  36. package/dist/tests/servicesAgainstRecordings.test.js.map +1 -1
  37. package/dist/tests/tailscale.test.d.ts +2 -0
  38. package/dist/tests/tailscale.test.d.ts.map +1 -0
  39. package/dist/tests/tailscale.test.js +79 -0
  40. package/dist/tests/tailscale.test.js.map +1 -0
  41. 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;AAUnB;;GAEG;AACH,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAU/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,CA2B/E;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,WAAW,EAAE,cAAc,GAAG,kBAAkB,CA6BpF;AAED,qBAAa,gCAAiC,SAAQ,KAAK;gBAC7C,OAAO,EAAE,MAAM;CAI5B"}
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":"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"}
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,EAgCR,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,iBAgC3B,CAAC"}
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":"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"}
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;AAOpE,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
+ {"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: ['https://www.googleapis.com/auth/gmail.modify'],
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,CAAC,8CAA8C,CAAC;CACzD,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"}
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":"AAAA;;GAEG;AAEH,OAAO,EACL,OAAO,EACP,cAAc,EACd,oBAAoB,EACpB,6BAA6B,EAC7B,YAAY,EACZ,2BAA2B,EAC3B,KAAK,WAAW,GACjB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACL,mBAAmB,EACnB,gBAAgB,EAChB,kCAAkC,EAClC,wBAAwB,EACxB,wBAAwB,GACzB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AACzD,OAAO,EACL,WAAW,EACX,qBAAqB,EACrB,oBAAoB,EACpB,gBAAgB,GACjB,MAAM,+BAA+B,CAAC;AACvC,OAAO,EACL,2BAA2B,EAC3B,oBAAoB,EACpB,KAAK,SAAS,EACd,KAAK,cAAc,GACpB,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAAE,sBAAsB,EAAE,MAAM,oCAAoC,CAAC;AAE5E,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAChD,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAChD,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAC9D,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACvE,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAC9D,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACjE,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC3D,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACjE,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACjE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AACxD,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AACtD,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACvC,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACnD,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,GAAG,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AACpC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAC1E,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACnD,OAAO,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAC7E,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACvC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAChD,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACvC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAChD,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC"}
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":"AAAA;;;;;;;;;;;;GAYG;AAGH,OAAO,EAAkB,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AAChF,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AACtD,OAAO,EACL,OAAO,EACP,6BAA6B,EAC7B,YAAY,EACZ,gBAAgB,GACjB,MAAM,gBAAgB,CAAC;AAExB,MAAM,kBAAkB,GAAG,KAAK,CAAC;AAEjC,qEAAqE;AACrE,MAAM,uBAAuB,GAAG,+BAA+B,CAAC;AAEhE,MAAM,oBAAoB,GAAG,+BAA+B,CAAC;AAE7D,gFAAgF;AAChF,sEAAsE;AACtE,MAAM,mBAAmB,GAAG,4BAA4B,CAAC;AAEzD,+EAA+E;AAC/E,wEAAwE;AACxE,MAAM,uBAAuB,GAAG,kCAAkC,CAAC;AAEnE,+EAA+E;AAC/E,8EAA8E;AAC9E,+EAA+E;AAC/E,iFAAiF;AACjF,+EAA+E;AAC/E,iEAAiE;AACjE,MAAM,eAAe,GAAG,eAAe,CAAC;AACxC,MAAM,iCAAiC,GAAG,oDAAoD,CAAC;AAE/F,gFAAgF;AAChF,8EAA8E;AAC9E,MAAM,sBAAsB,GAAG,wBAAwB,CAAC;AAExD,MAAM,wBAAyB,SAAQ,6BAA6B;IAC/C,YAAY,GAAG,YAAY,CAAC,cAAc,CAAC;IACtD,UAAU,GAAG,KAAK,CAAC;IAE3B,UAAU,CAAC,QAAkB;QAC3B,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;YACpB,OAAO;QACT,CAAC;QACD,IAAI,QAAQ,CAAC,OAAO,EAAE,CAAC,YAAY,EAAE,KAAK,UAAU,EAAE,CAAC;YACrD,OAAO;QACT,CAAC;QACD,IAAI,GAAQ,CAAC;QACb,IAAI,CAAC;YACH,GAAG,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,GAAG,EAAE,CAAC,CAAC;QAChC,CAAC;QAAC,MAAM,CAAC;YACP,OAAO;QACT,CAAC;QACD,IAAI,GAAG,CAAC,QAAQ,KAAK,eAAe,EAAE,CAAC;YACrC,OAAO;QACT,CAAC;QACD,IAAI,iCAAiC,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC;YACzD,OAAO;QACT,CAAC;QACD,IAAI,QAAQ,CAAC,MAAM,EAAE,IAAI,GAAG,IAAI,QAAQ,CAAC,MAAM,EAAE,GAAG,GAAG,EAAE,CAAC;YACxD,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC;QACzB,CAAC;IACH,CAAC;IAES,eAAe;QACvB,OAAO,IAAI,CAAC,UAAU,CAAC;IACzB,CAAC;IAES,KAAK,CAAC,sBAAsB,CACpC,OAAuB,EACvB,eAAgC;QAEhC,MAAM,IAAI,GAAG,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC;QAChC,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,MAAM,IAAI,gBAAgB,CAAC,uCAAuC,CAAC,CAAC;QACtE,CAAC;QAED,MAAM,IAAI,CAAC,IAAI,CAAC,mBAAmB,EAAE,EAAE,SAAS,EAAE,kBAAkB,EAAE,CAAC,CAAC;QAExE,6EAA6E;QAC7E,4EAA4E;QAC5E,6EAA6E;QAC7E,uEAAuE;QACvE,kDAAkD;QAClD,MAAM,YAAY,GAAG,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC,CAAC;QACnE,MAAM,YAAY,CAAC,OAAO,CAAC,EAAE,OAAO,EAAE,kBAAkB,EAAE,CAAC,CAAC;QAC5D,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC;QAC7C,KAAK,IAAI,OAAO,GAAG,CAAC,EAAE,OAAO,GAAG,CAAC,EAAE,OAAO,EAAE,EAAE,CAAC;YAC7C,MAAM,WAAW,GAAG,MAAM,SAAS,CAAC,SAAS,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,CAAC;YACnE,IAAI,CAAC,WAAW,EAAE,CAAC;gBACjB,MAAM,YAAY,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;YACpD,CAAC;YACD,IAAI,CAAC;gBACH,MAAM,SAAS,CAAC,OAAO,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;gBAC3C,MAAM;YACR,CAAC;YAAC,MAAM,CAAC;gBACP,IAAI,OAAO,KAAK,CAAC,EAAE,CAAC;oBAClB,MAAM,IAAI,gBAAgB,CAAC,2CAA2C,CAAC,CAAC;gBAC1E,CAAC;YACH,CAAC;QACH,CAAC;QAED,uEAAuE;QACvE,MAAM,OAAO,GAAG,IAAI,CAAC,eAAe,EAAE,CAAC;QACvC,MAAM,aAAa,CAAC,IAAI,EAAE,SAAS,EAAE,OAAO,CAAC,CAAC;QAE9C,8EAA8E;QAC9E,6EAA6E;QAC7E,gFAAgF;QAChF,iFAAiF;QACjF,qBAAqB;QACrB,MAAM,MAAM,GAAG,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,EAAE,IAAI,EAAE,gBAAgB,EAAE,CAAC,CAAC;QACpE,MAAM,YAAY,GAAG,MAAM,CAAC,SAAS,CAAC,QAAQ,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;QACjF,MAAM,YAAY,CAAC,OAAO,CAAC,EAAE,OAAO,EAAE,kBAAkB,EAAE,CAAC,CAAC;QAC5D,MAAM,YAAY,CAAC,KAAK,EAAE,CAAC;QAE3B,wEAAwE;QACxE,MAAM,MAAM,CAAC,SAAS,CAAC,eAAe,CAAC,CAAC,OAAO,CAAC,EAAE,OAAO,EAAE,kBAAkB,EAAE,CAAC,CAAC;QACjF,MAAM,UAAU,GAAG,MAAM,MAAM,CAAC,SAAS,EAAE,CAAC;QAC5C,MAAM,KAAK,GAAG,sBAAsB,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QACtD,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,MAAM,IAAI,gBAAgB,CAAC,4CAA4C,CAAC,CAAC;QAC3E,CAAC;QAED,MAAM,IAAI,CAAC,KAAK,EAAE,CAAC;QACnB,OAAO,IAAI,mBAAmB,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IAC3C,CAAC;CACF;AAED,MAAM,OAAO,UAAW,SAAQ,OAAO;IAC5B,IAAI,GAAG,YAAY,CAAC;IACpB,WAAW,GAAG,YAAY,CAAC;IAC3B,WAAW,GAAG,CAAC,uBAAuB,CAAU,CAAC;IACjD,QAAQ,GAAG,oBAAoB,CAAC;IAChC,IAAI,GACX,2FAA2F,CAAC;IAE9F,6EAA6E;IAC7E,sDAAsD;IAC7C,4BAA4B,GAAG,CAAC,uBAAuB,CAAU,CAAC;IAE3E,qBAAqB,CAAC,WAAmB;QACvC,OAAO,qBAAqB,WAAW,qCAAqC,CAAC;IAC/E,CAAC;IAED,gFAAgF;IAChF,8CAA8C;IACrC,UAAU,CAAC,eAA+B;QACjD,OAAO,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/B,CAAC;IAEQ,UAAU,CAAC,aAAqB;QACvC,OAAO,IAAI,wBAAwB,CAAC,IAAI,EAAE,aAAa,CAAC,CAAC;IAC3D,CAAC;CACF;AAED,MAAM,CAAC,MAAM,UAAU,GAAG,IAAI,UAAU,EAAE,CAAC"}
@@ -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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"}
@@ -1,2 +1,2 @@
1
- export declare const VERSION = "3.4.1";
1
+ export declare const VERSION = "3.6.0";
2
2
  //# sourceMappingURL=version.d.ts.map
@@ -1,4 +1,4 @@
1
1
  // Auto-generated from package.json by scripts/generateVersion.js.
2
2
  // Do not edit by hand; run `node scripts/generateVersion.js` to refresh.
3
- export const VERSION = "3.4.1";
3
+ export const VERSION = "3.6.0";
4
4
  //# sourceMappingURL=version.js.map
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=huggingface.test.d.ts.map
@@ -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 is such a service (its API key is created and read
36
- // from the dashboard's "New API Key" dialog, exactly like linear).
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(['dropbox', 'github', 'linear', 'ngrok']);
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":"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"}
1
+ {"version":3,"file":"servicesAgainstRecordings.test.js","sourceRoot":"","sources":["../../tests/servicesAgainstRecordings.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=tailscale.test.d.ts.map
@@ -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.4.1",
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.12.0",
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",