latchkey 0.1.4 → 1.0.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/LICENSE +1 -1
- package/README.md +93 -56
- package/dist/integrations/SKILL.md +77 -0
- package/dist/package.json +67 -0
- package/dist/scripts/encryptFile.d.ts +21 -0
- package/dist/scripts/encryptFile.d.ts.map +1 -0
- package/dist/scripts/encryptFile.js +101 -0
- package/dist/scripts/encryptFile.js.map +1 -0
- package/dist/src/apiCredentialStore.d.ts +1 -0
- package/dist/src/apiCredentialStore.d.ts.map +1 -1
- package/dist/src/apiCredentialStore.js +12 -0
- package/dist/src/apiCredentialStore.js.map +1 -1
- package/dist/src/apiCredentials.d.ts +116 -1
- package/dist/src/apiCredentials.d.ts.map +1 -1
- package/dist/src/apiCredentials.js +119 -1
- package/dist/src/apiCredentials.js.map +1 -1
- package/dist/src/browserState.d.ts +8 -0
- package/dist/src/browserState.d.ts.map +1 -0
- package/dist/src/browserState.js +21 -0
- package/dist/src/browserState.js.map +1 -0
- package/dist/src/cli.js +5 -3
- package/dist/src/cli.js.map +1 -1
- package/dist/src/cliCommands.d.ts.map +1 -1
- package/dist/src/cliCommands.js +218 -81
- package/dist/src/cliCommands.js.map +1 -1
- package/dist/src/config.d.ts +13 -0
- package/dist/src/config.d.ts.map +1 -1
- package/dist/src/config.js +50 -4
- package/dist/src/config.js.map +1 -1
- package/dist/src/index.d.ts +1 -1
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +2 -2
- package/dist/src/index.js.map +1 -1
- package/dist/src/oauthUtils.d.ts +49 -0
- package/dist/src/oauthUtils.d.ts.map +1 -0
- package/dist/src/oauthUtils.js +183 -0
- package/dist/src/oauthUtils.js.map +1 -0
- package/dist/src/playwrightUtils.d.ts +14 -1
- package/dist/src/playwrightUtils.d.ts.map +1 -1
- package/dist/src/playwrightUtils.js +37 -8
- package/dist/src/playwrightUtils.js.map +1 -1
- package/dist/src/registry.d.ts.map +1 -1
- package/dist/src/registry.js +20 -4
- package/dist/src/registry.js.map +1 -1
- package/dist/src/services/base.d.ts +43 -15
- package/dist/src/services/base.d.ts.map +1 -1
- package/dist/src/services/base.js +49 -9
- package/dist/src/services/base.js.map +1 -1
- package/dist/src/services/discord.d.ts +4 -3
- package/dist/src/services/discord.d.ts.map +1 -1
- package/dist/src/services/discord.js +6 -22
- package/dist/src/services/discord.js.map +1 -1
- package/dist/src/services/dropbox.d.ts +5 -4
- package/dist/src/services/dropbox.d.ts.map +1 -1
- package/dist/src/services/dropbox.js +10 -27
- package/dist/src/services/dropbox.js.map +1 -1
- package/dist/src/services/github.d.ts +5 -4
- package/dist/src/services/github.d.ts.map +1 -1
- package/dist/src/services/github.js +21 -30
- package/dist/src/services/github.js.map +1 -1
- package/dist/src/services/google.d.ts +34 -0
- package/dist/src/services/google.d.ts.map +1 -0
- package/dist/src/services/google.js +336 -0
- package/dist/src/services/google.js.map +1 -0
- package/dist/src/services/index.d.ts +4 -2
- package/dist/src/services/index.d.ts.map +1 -1
- package/dist/src/services/index.js +4 -1
- package/dist/src/services/index.js.map +1 -1
- package/dist/src/services/linear.d.ts +5 -4
- package/dist/src/services/linear.d.ts.map +1 -1
- package/dist/src/services/linear.js +10 -29
- package/dist/src/services/linear.js.map +1 -1
- package/dist/src/services/mailchimp.d.ts +11 -0
- package/dist/src/services/mailchimp.d.ts.map +1 -0
- package/dist/src/services/mailchimp.js +16 -0
- package/dist/src/services/mailchimp.js.map +1 -0
- package/dist/src/services/notion.d.ts +29 -0
- package/dist/src/services/notion.d.ts.map +1 -0
- package/dist/src/services/notion.js +102 -0
- package/dist/src/services/notion.js.map +1 -0
- package/dist/src/services/slack.d.ts +3 -1
- package/dist/src/services/slack.d.ts.map +1 -1
- package/dist/src/services/slack.js +5 -5
- package/dist/src/services/slack.js.map +1 -1
- package/dist/src/skillMd.d.ts +2 -0
- package/dist/src/skillMd.d.ts.map +1 -0
- package/dist/src/skillMd.js +19 -0
- package/dist/src/skillMd.js.map +1 -0
- package/dist/tests/apiCredentials.test.js +59 -1
- package/dist/tests/apiCredentials.test.js.map +1 -1
- package/dist/tests/cli.test.js +283 -104
- package/dist/tests/cli.test.js.map +1 -1
- package/dist/tests/playwrightDownload.test.js +2 -2
- package/dist/tests/playwrightDownload.test.js.map +1 -1
- package/dist/tests/registry.test.js +28 -3
- package/dist/tests/registry.test.js.map +1 -1
- package/dist/tests/servicesAgainstRecordings.test.js +3 -0
- package/dist/tests/servicesAgainstRecordings.test.js.map +1 -1
- package/package.json +6 -6
package/dist/src/index.js
CHANGED
|
@@ -9,9 +9,9 @@ export { encrypt, decrypt, generateKey, EncryptionError, DecryptionError } from
|
|
|
9
9
|
export { EncryptedStorage, EncryptedStorageError } from './encryptedStorage.js';
|
|
10
10
|
export { storeInKeychain, retrieveFromKeychain, deleteFromKeychain, isKeychainAvailable, KeychainError, KeychainNotAvailableError, } from './keychain.js';
|
|
11
11
|
export { run as runCurl, runCaptured as runCurlCaptured, setSubprocessRunner, resetSubprocessRunner, setCapturingSubprocessRunner, resetCapturingSubprocessRunner, } from './curl.js';
|
|
12
|
-
export { typeLikeHuman } from './playwrightUtils.js';
|
|
12
|
+
export { typeLikeHuman, BrowserDisabledError, BrowserFlowsNotSupportedError, } from './playwrightUtils.js';
|
|
13
13
|
// Services
|
|
14
|
-
export { ServiceSession, SimpleServiceSession, BrowserFollowupServiceSession, LoginCancelledError, LoginFailedError, Slack, SLACK, Discord, DISCORD, Github, GITHUB, Dropbox, DROPBOX, Linear, LINEAR, } from './services/index.js';
|
|
14
|
+
export { Service, ServiceSession, SimpleServiceSession, BrowserFollowupServiceSession, LoginCancelledError, LoginFailedError, Slack, SLACK, Discord, DISCORD, Github, GITHUB, Dropbox, DROPBOX, Linear, LINEAR, } from './services/index.js';
|
|
15
15
|
// Registry
|
|
16
16
|
export { Registry, REGISTRY } from './registry.js';
|
|
17
17
|
//# sourceMappingURL=index.js.map
|
package/dist/src/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,2BAA2B;AAC3B,OAAO,EAEL,mBAAmB,EACnB,mBAAmB,EACnB,iBAAiB,EACjB,mBAAmB,EACnB,sBAAsB,EACtB,oBAAoB,GACrB,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EAAE,kBAAkB,EAAE,uBAAuB,EAAE,MAAM,yBAAyB,CAAC;AAEtF,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,4BAA4B,EAAE,MAAM,aAAa,CAAC;AAE3E,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAElG,OAAO,EAAE,gBAAgB,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAEhF,OAAO,EACL,eAAe,EACf,oBAAoB,EACpB,kBAAkB,EAClB,mBAAmB,EACnB,aAAa,EACb,yBAAyB,GAC1B,MAAM,eAAe,CAAC;AAEvB,OAAO,EACL,GAAG,IAAI,OAAO,EACd,WAAW,IAAI,eAAe,EAC9B,mBAAmB,EACnB,qBAAqB,EACrB,4BAA4B,EAC5B,8BAA8B,GAC/B,MAAM,WAAW,CAAC;AAEnB,OAAO,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,2BAA2B;AAC3B,OAAO,EAEL,mBAAmB,EACnB,mBAAmB,EACnB,iBAAiB,EACjB,mBAAmB,EACnB,sBAAsB,EACtB,oBAAoB,GACrB,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EAAE,kBAAkB,EAAE,uBAAuB,EAAE,MAAM,yBAAyB,CAAC;AAEtF,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,4BAA4B,EAAE,MAAM,aAAa,CAAC;AAE3E,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAElG,OAAO,EAAE,gBAAgB,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAEhF,OAAO,EACL,eAAe,EACf,oBAAoB,EACpB,kBAAkB,EAClB,mBAAmB,EACnB,aAAa,EACb,yBAAyB,GAC1B,MAAM,eAAe,CAAC;AAEvB,OAAO,EACL,GAAG,IAAI,OAAO,EACd,WAAW,IAAI,eAAe,EAC9B,mBAAmB,EACnB,qBAAqB,EACrB,4BAA4B,EAC5B,8BAA8B,GAC/B,MAAM,WAAW,CAAC;AAEnB,OAAO,EACL,aAAa,EACb,oBAAoB,EACpB,6BAA6B,GAC9B,MAAM,sBAAsB,CAAC;AAE9B,WAAW;AACX,OAAO,EACL,OAAO,EACP,cAAc,EACd,oBAAoB,EACpB,6BAA6B,EAC7B,mBAAmB,EACnB,gBAAgB,EAChB,KAAK,EACL,KAAK,EACL,OAAO,EACP,OAAO,EACP,MAAM,EACN,MAAM,EACN,OAAO,EACP,OAAO,EACP,MAAM,EACN,MAAM,GACP,MAAM,qBAAqB,CAAC;AAE7B,WAAW;AACX,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generic OAuth utilities for localhost callback server and token exchange.
|
|
3
|
+
*/
|
|
4
|
+
export interface OAuthTokenResponse {
|
|
5
|
+
access_token: string;
|
|
6
|
+
refresh_token?: string;
|
|
7
|
+
expires_in: number;
|
|
8
|
+
token_type: string;
|
|
9
|
+
}
|
|
10
|
+
export declare class OAuthTokenExchangeError extends Error {
|
|
11
|
+
constructor(message: string);
|
|
12
|
+
}
|
|
13
|
+
export declare class OAuthCallbackServerTimeoutError extends Error {
|
|
14
|
+
constructor();
|
|
15
|
+
}
|
|
16
|
+
export interface OAuthCallbackServer {
|
|
17
|
+
/** The port the server is listening on */
|
|
18
|
+
port: number;
|
|
19
|
+
/** Promise that resolves with the authorization code when received */
|
|
20
|
+
codePromise: Promise<string>;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Start a temporary HTTP server to receive OAuth callback.
|
|
24
|
+
* Returns the assigned port and a promise that resolves with the authorization code.
|
|
25
|
+
* The server uses port 0 to get an auto-assigned available port.
|
|
26
|
+
* @param timeoutMs - Timeout in milliseconds
|
|
27
|
+
* @param signal - Optional AbortSignal to cancel the server early
|
|
28
|
+
* @param callbackPath - Path to listen for OAuth callback (default: '/oauth2callback')
|
|
29
|
+
*/
|
|
30
|
+
export declare function startOAuthCallbackServer(timeoutMs: number, signal?: AbortSignal, callbackPath?: string): Promise<OAuthCallbackServer>;
|
|
31
|
+
/**
|
|
32
|
+
* Exchange authorization code for access and refresh tokens.
|
|
33
|
+
* @param tokenEndpoint - The OAuth token endpoint URL
|
|
34
|
+
* @param code - The authorization code received from the OAuth callback
|
|
35
|
+
* @param clientId - The OAuth client ID
|
|
36
|
+
* @param clientSecret - The OAuth client secret
|
|
37
|
+
* @param redirectUri - The redirect URI used in the authorization request
|
|
38
|
+
*/
|
|
39
|
+
export declare function exchangeCodeForTokens(tokenEndpoint: string, code: string, clientId: string, clientSecret: string, redirectUri: string): OAuthTokenResponse;
|
|
40
|
+
/**
|
|
41
|
+
* Refresh OAuth access token using the refresh token.
|
|
42
|
+
* @param tokenEndpoint - The OAuth token endpoint URL
|
|
43
|
+
* @param refreshToken - The refresh token
|
|
44
|
+
* @param clientId - The OAuth client ID
|
|
45
|
+
* @param clientSecret - The OAuth client secret
|
|
46
|
+
* @returns The new token response, or null if refresh failed
|
|
47
|
+
*/
|
|
48
|
+
export declare function refreshAccessToken(tokenEndpoint: string, refreshToken: string, clientId: string, clientSecret: string): OAuthTokenResponse | null;
|
|
49
|
+
//# sourceMappingURL=oauthUtils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"oauthUtils.d.ts","sourceRoot":"","sources":["../../src/oauthUtils.ts"],"names":[],"mappings":"AAAA;;GAEG;AAMH,MAAM,WAAW,kBAAkB;IACjC,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,qBAAa,uBAAwB,SAAQ,KAAK;gBACpC,OAAO,EAAE,MAAM;CAI5B;AAED,qBAAa,+BAAgC,SAAQ,KAAK;;CAKzD;AAED,MAAM,WAAW,mBAAmB;IAClC,0CAA0C;IAC1C,IAAI,EAAE,MAAM,CAAC;IACb,sEAAsE;IACtE,WAAW,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;CAC9B;AAED;;;;;;;GAOG;AACH,wBAAgB,wBAAwB,CACtC,SAAS,EAAE,MAAM,EACjB,MAAM,CAAC,EAAE,WAAW,EACpB,YAAY,SAAoB,GAC/B,OAAO,CAAC,mBAAmB,CAAC,CAmF9B;AAED;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CACnC,aAAa,EAAE,MAAM,EACrB,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,EAChB,YAAY,EAAE,MAAM,EACpB,WAAW,EAAE,MAAM,GAClB,kBAAkB,CA2CpB;AAED;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAChC,aAAa,EAAE,MAAM,EACrB,YAAY,EAAE,MAAM,EACpB,QAAQ,EAAE,MAAM,EAChB,YAAY,EAAE,MAAM,GACnB,kBAAkB,GAAG,IAAI,CAmC3B"}
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generic OAuth utilities for localhost callback server and token exchange.
|
|
3
|
+
*/
|
|
4
|
+
import * as http from 'node:http';
|
|
5
|
+
import { runCaptured } from './curl.js';
|
|
6
|
+
import { LoginCancelledError, LoginFailedError } from './services/base.js';
|
|
7
|
+
export class OAuthTokenExchangeError extends Error {
|
|
8
|
+
constructor(message) {
|
|
9
|
+
super(message);
|
|
10
|
+
this.name = 'OAuthTokenExchangeError';
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
export class OAuthCallbackServerTimeoutError extends Error {
|
|
14
|
+
constructor() {
|
|
15
|
+
super('OAuth callback server timed out waiting for authorization code.');
|
|
16
|
+
this.name = 'OAuthCallbackServerTimeoutError';
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Start a temporary HTTP server to receive OAuth callback.
|
|
21
|
+
* Returns the assigned port and a promise that resolves with the authorization code.
|
|
22
|
+
* The server uses port 0 to get an auto-assigned available port.
|
|
23
|
+
* @param timeoutMs - Timeout in milliseconds
|
|
24
|
+
* @param signal - Optional AbortSignal to cancel the server early
|
|
25
|
+
* @param callbackPath - Path to listen for OAuth callback (default: '/oauth2callback')
|
|
26
|
+
*/
|
|
27
|
+
export function startOAuthCallbackServer(timeoutMs, signal, callbackPath = '/oauth2callback') {
|
|
28
|
+
const server = http.createServer();
|
|
29
|
+
return new Promise((resolveServer, rejectServer) => {
|
|
30
|
+
server.on('error', (error) => {
|
|
31
|
+
rejectServer(error);
|
|
32
|
+
});
|
|
33
|
+
server.listen(0, 'localhost', () => {
|
|
34
|
+
const address = server.address();
|
|
35
|
+
if (address === null || typeof address === 'string') {
|
|
36
|
+
server.close();
|
|
37
|
+
rejectServer(new Error('Failed to get server address'));
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
const port = address.port;
|
|
41
|
+
let timeout;
|
|
42
|
+
const codePromise = new Promise((resolve, reject) => {
|
|
43
|
+
const cleanup = () => {
|
|
44
|
+
if (timeout !== undefined) {
|
|
45
|
+
clearTimeout(timeout);
|
|
46
|
+
}
|
|
47
|
+
server.closeAllConnections();
|
|
48
|
+
server.close();
|
|
49
|
+
};
|
|
50
|
+
const abortHandler = () => {
|
|
51
|
+
cleanup();
|
|
52
|
+
reject(new LoginCancelledError());
|
|
53
|
+
};
|
|
54
|
+
if (signal) {
|
|
55
|
+
if (signal.aborted) {
|
|
56
|
+
cleanup();
|
|
57
|
+
reject(new LoginCancelledError());
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
signal.addEventListener('abort', abortHandler, { once: true });
|
|
61
|
+
}
|
|
62
|
+
server.on('request', (req, res) => {
|
|
63
|
+
const parsedUrl = new URL(req.url ?? '', `http://localhost:${port.toString()}`);
|
|
64
|
+
if (parsedUrl.pathname === callbackPath) {
|
|
65
|
+
const code = parsedUrl.searchParams.get('code') ?? undefined;
|
|
66
|
+
if (code) {
|
|
67
|
+
res.writeHead(200, { 'Content-Type': 'text/plain' });
|
|
68
|
+
res.end('OK');
|
|
69
|
+
signal?.removeEventListener('abort', abortHandler);
|
|
70
|
+
cleanup();
|
|
71
|
+
resolve(code);
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
res.writeHead(400, { 'Content-Type': 'text/plain' });
|
|
75
|
+
res.end('ERROR');
|
|
76
|
+
signal?.removeEventListener('abort', abortHandler);
|
|
77
|
+
cleanup();
|
|
78
|
+
reject(new LoginFailedError('No authorization code received from OAuth callback.'));
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
res.writeHead(404);
|
|
83
|
+
res.end();
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
timeout = setTimeout(() => {
|
|
87
|
+
signal?.removeEventListener('abort', abortHandler);
|
|
88
|
+
cleanup();
|
|
89
|
+
reject(new OAuthCallbackServerTimeoutError());
|
|
90
|
+
}, timeoutMs);
|
|
91
|
+
server.on('error', (error) => {
|
|
92
|
+
signal?.removeEventListener('abort', abortHandler);
|
|
93
|
+
cleanup();
|
|
94
|
+
reject(error);
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
resolveServer({ port, codePromise });
|
|
98
|
+
});
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Exchange authorization code for access and refresh tokens.
|
|
103
|
+
* @param tokenEndpoint - The OAuth token endpoint URL
|
|
104
|
+
* @param code - The authorization code received from the OAuth callback
|
|
105
|
+
* @param clientId - The OAuth client ID
|
|
106
|
+
* @param clientSecret - The OAuth client secret
|
|
107
|
+
* @param redirectUri - The redirect URI used in the authorization request
|
|
108
|
+
*/
|
|
109
|
+
export function exchangeCodeForTokens(tokenEndpoint, code, clientId, clientSecret, redirectUri) {
|
|
110
|
+
const body = new URLSearchParams({
|
|
111
|
+
code,
|
|
112
|
+
client_id: clientId,
|
|
113
|
+
client_secret: clientSecret,
|
|
114
|
+
redirect_uri: redirectUri,
|
|
115
|
+
grant_type: 'authorization_code',
|
|
116
|
+
});
|
|
117
|
+
const result = runCaptured([
|
|
118
|
+
'-s',
|
|
119
|
+
'-X',
|
|
120
|
+
'POST',
|
|
121
|
+
'-H',
|
|
122
|
+
'Content-Type: application/x-www-form-urlencoded',
|
|
123
|
+
'-d',
|
|
124
|
+
body.toString(),
|
|
125
|
+
tokenEndpoint,
|
|
126
|
+
], 30);
|
|
127
|
+
if (result.returncode !== 0) {
|
|
128
|
+
throw new OAuthTokenExchangeError(`Failed to exchange authorization code for tokens: ${result.stderr}`);
|
|
129
|
+
}
|
|
130
|
+
try {
|
|
131
|
+
const response = JSON.parse(result.stdout);
|
|
132
|
+
if (!response.access_token || !response.refresh_token) {
|
|
133
|
+
throw new OAuthTokenExchangeError('Token response missing access_token or refresh_token.');
|
|
134
|
+
}
|
|
135
|
+
return response;
|
|
136
|
+
}
|
|
137
|
+
catch (error) {
|
|
138
|
+
if (error instanceof OAuthTokenExchangeError) {
|
|
139
|
+
throw error;
|
|
140
|
+
}
|
|
141
|
+
throw new OAuthTokenExchangeError(`Failed to parse token response: ${error instanceof Error ? error.message : String(error)}`);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Refresh OAuth access token using the refresh token.
|
|
146
|
+
* @param tokenEndpoint - The OAuth token endpoint URL
|
|
147
|
+
* @param refreshToken - The refresh token
|
|
148
|
+
* @param clientId - The OAuth client ID
|
|
149
|
+
* @param clientSecret - The OAuth client secret
|
|
150
|
+
* @returns The new token response, or null if refresh failed
|
|
151
|
+
*/
|
|
152
|
+
export function refreshAccessToken(tokenEndpoint, refreshToken, clientId, clientSecret) {
|
|
153
|
+
const body = new URLSearchParams({
|
|
154
|
+
refresh_token: refreshToken,
|
|
155
|
+
client_id: clientId,
|
|
156
|
+
client_secret: clientSecret,
|
|
157
|
+
grant_type: 'refresh_token',
|
|
158
|
+
});
|
|
159
|
+
const result = runCaptured([
|
|
160
|
+
'-s',
|
|
161
|
+
'-X',
|
|
162
|
+
'POST',
|
|
163
|
+
'-H',
|
|
164
|
+
'Content-Type: application/x-www-form-urlencoded',
|
|
165
|
+
'-d',
|
|
166
|
+
body.toString(),
|
|
167
|
+
tokenEndpoint,
|
|
168
|
+
], 30);
|
|
169
|
+
if (result.returncode !== 0) {
|
|
170
|
+
return null;
|
|
171
|
+
}
|
|
172
|
+
try {
|
|
173
|
+
const response = JSON.parse(result.stdout);
|
|
174
|
+
if (!response.access_token) {
|
|
175
|
+
return null;
|
|
176
|
+
}
|
|
177
|
+
return response;
|
|
178
|
+
}
|
|
179
|
+
catch {
|
|
180
|
+
return null;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
//# sourceMappingURL=oauthUtils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"oauthUtils.js","sourceRoot":"","sources":["../../src/oauthUtils.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Playwright utility functions for browser automation.
|
|
3
3
|
*/
|
|
4
|
+
export declare class BrowserDisabledError extends Error {
|
|
5
|
+
constructor();
|
|
6
|
+
}
|
|
7
|
+
export declare class BrowserFlowsNotSupportedError extends Error {
|
|
8
|
+
constructor(serviceName: string);
|
|
9
|
+
}
|
|
4
10
|
import type { Browser, BrowserContext, Page, Locator } from 'playwright';
|
|
5
11
|
import { EncryptedStorage } from './encryptedStorage.js';
|
|
6
12
|
export interface BrowserWithContext {
|
|
@@ -13,6 +19,11 @@ export interface BrowserLaunchOptions {
|
|
|
13
19
|
/** Path to the encrypted browser state file for persisting cookies/storage. */
|
|
14
20
|
browserStatePath?: string;
|
|
15
21
|
}
|
|
22
|
+
/**
|
|
23
|
+
* Generate a random Latchkey-prefixed app name.
|
|
24
|
+
* Used for creating unique names when registering API keys, apps, or tokens.
|
|
25
|
+
*/
|
|
26
|
+
export declare function generateLatchkeyAppName(): string;
|
|
16
27
|
/**
|
|
17
28
|
* Run a callback with a browser context initialized from encrypted storage state.
|
|
18
29
|
* After the callback completes, persists browser state back to encrypted storage.
|
|
@@ -28,6 +39,8 @@ export declare function typeLikeHuman(page: Page, locator: Locator, text: string
|
|
|
28
39
|
/**
|
|
29
40
|
* Show a spinner overlay that hides page content from the user.
|
|
30
41
|
* The overlay persists across page navigations within the browser context.
|
|
42
|
+
*
|
|
43
|
+
* Can be disabled by setting LATCHKEY_DISABLE_SPINNER=1 environment variable.
|
|
31
44
|
*/
|
|
32
|
-
export declare function showSpinnerPage(context: BrowserContext,
|
|
45
|
+
export declare function showSpinnerPage(context: BrowserContext, message: string): Promise<void>;
|
|
33
46
|
//# sourceMappingURL=playwrightUtils.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"playwrightUtils.d.ts","sourceRoot":"","sources":["../../src/playwrightUtils.ts"],"names":[],"mappings":"AAAA;;GAEG;
|
|
1
|
+
{"version":3,"file":"playwrightUtils.d.ts","sourceRoot":"","sources":["../../src/playwrightUtils.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,qBAAa,oBAAqB,SAAQ,KAAK;;CAK9C;AAED,qBAAa,6BAA8B,SAAQ,KAAK;gBAC1C,WAAW,EAAE,MAAM;CAMhC;AAMD,OAAO,KAAK,EAAE,OAAO,EAAE,cAAc,EAAE,IAAI,EAAE,OAAO,EAAiB,MAAM,YAAY,CAAC;AAExF,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAEzD,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,OAAO,EAAE,cAAc,CAAC;CAClC;AAED,MAAM,WAAW,oBAAoB;IACnC,qFAAqF;IACrF,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,+EAA+E;IAC/E,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED;;;GAGG;AACH,wBAAgB,uBAAuB,IAAI,MAAM,CAIhD;AAED;;;GAGG;AACH,wBAAsB,sBAAsB,CAAC,CAAC,EAC5C,gBAAgB,EAAE,gBAAgB,EAClC,OAAO,EAAE,oBAAoB,EAC7B,QAAQ,EAAE,CAAC,KAAK,EAAE,kBAAkB,KAAK,OAAO,CAAC,CAAC,CAAC,GAClD,OAAO,CAAC,CAAC,CAAC,CA2CZ;AAMD;;;;;GAKG;AACH,wBAAsB,aAAa,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAS7F;AAsDD;;;;;GAKG;AACH,wBAAsB,eAAe,CAAC,OAAO,EAAE,cAAc,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAO7F"}
|
|
@@ -1,10 +1,32 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Playwright utility functions for browser automation.
|
|
3
3
|
*/
|
|
4
|
+
export class BrowserDisabledError extends Error {
|
|
5
|
+
constructor() {
|
|
6
|
+
super('Browser is disabled via LATCHKEY_DISABLE_BROWSER environment variable.');
|
|
7
|
+
this.name = 'BrowserDisabledError';
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
export class BrowserFlowsNotSupportedError extends Error {
|
|
11
|
+
constructor(serviceName) {
|
|
12
|
+
super(`Service '${serviceName}' does not support browser flows. Use 'latchkey auth set ${serviceName}' to set credentials manually.`);
|
|
13
|
+
this.name = 'BrowserFlowNotSupportedError';
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
import { randomUUID } from 'node:crypto';
|
|
4
17
|
import { existsSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
|
|
5
18
|
import { tmpdir } from 'node:os';
|
|
6
19
|
import { join } from 'node:path';
|
|
7
20
|
import { chromium } from 'playwright';
|
|
21
|
+
/**
|
|
22
|
+
* Generate a random Latchkey-prefixed app name.
|
|
23
|
+
* Used for creating unique names when registering API keys, apps, or tokens.
|
|
24
|
+
*/
|
|
25
|
+
export function generateLatchkeyAppName() {
|
|
26
|
+
const date = new Date().toISOString().slice(0, 10);
|
|
27
|
+
const randomSuffix = randomUUID().slice(0, 4);
|
|
28
|
+
return `Latchkey-${date}-${randomSuffix}`;
|
|
29
|
+
}
|
|
8
30
|
/**
|
|
9
31
|
* Run a callback with a browser context initialized from encrypted storage state.
|
|
10
32
|
* After the callback completes, persists browser state back to encrypted storage.
|
|
@@ -26,10 +48,9 @@ export async function withTempBrowserContext(encryptedStorage, options, callback
|
|
|
26
48
|
}
|
|
27
49
|
const browser = await chromium.launch(playwrightLaunchOptions);
|
|
28
50
|
try {
|
|
29
|
-
const contextOptions = {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
}
|
|
51
|
+
const contextOptions = {
|
|
52
|
+
storageState: initialStorageState,
|
|
53
|
+
};
|
|
33
54
|
const context = await browser.newContext(contextOptions);
|
|
34
55
|
const result = await callback({ browser, context });
|
|
35
56
|
// Persist browser state back to encrypted storage
|
|
@@ -69,7 +90,7 @@ export async function typeLikeHuman(page, locator, text) {
|
|
|
69
90
|
}
|
|
70
91
|
}
|
|
71
92
|
// Script that creates the spinner overlay, designed to run in browser context
|
|
72
|
-
function createSpinnerOverlayScript(
|
|
93
|
+
function createSpinnerOverlayScript(message) {
|
|
73
94
|
return `
|
|
74
95
|
(() => {
|
|
75
96
|
if (document.getElementById('latchkey-spinner-overlay')) return;
|
|
@@ -104,13 +125,16 @@ function createSpinnerOverlayScript(serviceName) {
|
|
|
104
125
|
margin-top: 20px;
|
|
105
126
|
color: #555;
|
|
106
127
|
font-size: 16px;
|
|
128
|
+
text-align: center;
|
|
129
|
+
max-width: 80%;
|
|
130
|
+
white-space: pre-line;
|
|
107
131
|
}
|
|
108
132
|
@keyframes latchkey-spin {
|
|
109
133
|
to { transform: rotate(360deg); }
|
|
110
134
|
}
|
|
111
135
|
</style>
|
|
112
136
|
<div class="spinner"></div>
|
|
113
|
-
<div class="message"
|
|
137
|
+
<div class="message">${message}</div>
|
|
114
138
|
\`;
|
|
115
139
|
document.body.appendChild(overlay);
|
|
116
140
|
})()
|
|
@@ -119,10 +143,15 @@ function createSpinnerOverlayScript(serviceName) {
|
|
|
119
143
|
/**
|
|
120
144
|
* Show a spinner overlay that hides page content from the user.
|
|
121
145
|
* The overlay persists across page navigations within the browser context.
|
|
146
|
+
*
|
|
147
|
+
* Can be disabled by setting LATCHKEY_DISABLE_SPINNER=1 environment variable.
|
|
122
148
|
*/
|
|
123
|
-
export async function showSpinnerPage(context,
|
|
149
|
+
export async function showSpinnerPage(context, message) {
|
|
150
|
+
if (process.env.LATCHKEY_DISABLE_SPINNER === '1') {
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
124
153
|
const spinnerPage = await context.newPage();
|
|
125
|
-
await spinnerPage.evaluate(createSpinnerOverlayScript(
|
|
154
|
+
await spinnerPage.evaluate(createSpinnerOverlayScript(message));
|
|
126
155
|
await spinnerPage.bringToFront();
|
|
127
156
|
}
|
|
128
157
|
//# sourceMappingURL=playwrightUtils.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"playwrightUtils.js","sourceRoot":"","sources":["../../src/playwrightUtils.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AACvF,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAetC;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAC1C,gBAAkC,EAClC,OAA6B,EAC7B,QAAmD;IAEnD,MAAM,OAAO,GAAG,WAAW,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,yBAAyB,CAAC,CAAC,CAAC;IACvE,MAAM,YAAY,GAAG,IAAI,CAAC,OAAO,EAAE,oBAAoB,CAAC,CAAC;IAEzD,IAAI,mBAAuC,CAAC;IAC5C,IAAI,OAAO,CAAC,gBAAgB,IAAI,UAAU,CAAC,OAAO,CAAC,gBAAgB,CAAC,EAAE,CAAC;QACrE,MAAM,OAAO,GAAG,gBAAgB,CAAC,QAAQ,CAAC,OAAO,CAAC,gBAAgB,CAAC,CAAC;QACpE,IAAI,OAAO,KAAK,IAAI,EAAE,CAAC;YACrB,aAAa,CAAC,YAAY,EAAE,OAAO,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;YACzE,mBAAmB,GAAG,YAAY,CAAC;QACrC,CAAC;IACH,CAAC;IAED,MAAM,uBAAuB,GAAkB,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC;IACnE,IAAI,OAAO,CAAC,cAAc,EAAE,CAAC;QAC3B,uBAAuB,CAAC,cAAc,GAAG,OAAO,CAAC,cAAc,CAAC;IAClE,CAAC;IACD,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,MAAM,CAAC,uBAAuB,CAAC,CAAC;IAE/D,IAAI,CAAC;QACH,MAAM,cAAc,GAA8B
|
|
1
|
+
{"version":3,"file":"playwrightUtils.js","sourceRoot":"","sources":["../../src/playwrightUtils.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,OAAO,oBAAqB,SAAQ,KAAK;IAC7C;QACE,KAAK,CAAC,wEAAwE,CAAC,CAAC;QAChF,IAAI,CAAC,IAAI,GAAG,sBAAsB,CAAC;IACrC,CAAC;CACF;AAED,MAAM,OAAO,6BAA8B,SAAQ,KAAK;IACtD,YAAY,WAAmB;QAC7B,KAAK,CACH,YAAY,WAAW,4DAA4D,WAAW,gCAAgC,CAC/H,CAAC;QACF,IAAI,CAAC,IAAI,GAAG,8BAA8B,CAAC;IAC7C,CAAC;CACF;AAED,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AACvF,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAetC;;;GAGG;AACH,MAAM,UAAU,uBAAuB;IACrC,MAAM,IAAI,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IACnD,MAAM,YAAY,GAAG,UAAU,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAC9C,OAAO,YAAY,IAAI,IAAI,YAAY,EAAE,CAAC;AAC5C,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAC1C,gBAAkC,EAClC,OAA6B,EAC7B,QAAmD;IAEnD,MAAM,OAAO,GAAG,WAAW,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,yBAAyB,CAAC,CAAC,CAAC;IACvE,MAAM,YAAY,GAAG,IAAI,CAAC,OAAO,EAAE,oBAAoB,CAAC,CAAC;IAEzD,IAAI,mBAAuC,CAAC;IAC5C,IAAI,OAAO,CAAC,gBAAgB,IAAI,UAAU,CAAC,OAAO,CAAC,gBAAgB,CAAC,EAAE,CAAC;QACrE,MAAM,OAAO,GAAG,gBAAgB,CAAC,QAAQ,CAAC,OAAO,CAAC,gBAAgB,CAAC,CAAC;QACpE,IAAI,OAAO,KAAK,IAAI,EAAE,CAAC;YACrB,aAAa,CAAC,YAAY,EAAE,OAAO,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;YACzE,mBAAmB,GAAG,YAAY,CAAC;QACrC,CAAC;IACH,CAAC;IAED,MAAM,uBAAuB,GAAkB,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC;IACnE,IAAI,OAAO,CAAC,cAAc,EAAE,CAAC;QAC3B,uBAAuB,CAAC,cAAc,GAAG,OAAO,CAAC,cAAc,CAAC;IAClE,CAAC;IACD,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,MAAM,CAAC,uBAAuB,CAAC,CAAC;IAE/D,IAAI,CAAC;QACH,MAAM,cAAc,GAA8B;YAChD,YAAY,EAAE,mBAAmB;SAClC,CAAC;QACF,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,UAAU,CAAC,cAAc,CAAC,CAAC;QAEzD,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,CAAC;QAEpD,kDAAkD;QAClD,IAAI,OAAO,CAAC,gBAAgB,EAAE,CAAC;YAC7B,MAAM,OAAO,CAAC,YAAY,CAAC,EAAE,IAAI,EAAE,YAAY,EAAE,CAAC,CAAC;YACnD,MAAM,OAAO,GAAG,YAAY,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;YACpD,gBAAgB,CAAC,SAAS,CAAC,OAAO,CAAC,gBAAgB,EAAE,OAAO,CAAC,CAAC;QAChE,CAAC;QAED,OAAO,MAAM,CAAC;IAChB,CAAC;YAAS,CAAC;QACT,MAAM,OAAO,CAAC,KAAK,EAAE,CAAC;QACtB,IAAI,CAAC;YACH,MAAM,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;QACpD,CAAC;QAAC,MAAM,CAAC;YACP,wBAAwB;QAC1B,CAAC;IACH,CAAC;AACH,CAAC;AAED,8EAA8E;AAC9E,MAAM,mBAAmB,GAAG,EAAE,CAAC;AAC/B,MAAM,mBAAmB,GAAG,GAAG,CAAC;AAEhC;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,IAAU,EAAE,OAAgB,EAAE,IAAY;IAC5E,MAAM,OAAO,CAAC,KAAK,EAAE,CAAC;IACtB,KAAK,MAAM,SAAS,IAAI,IAAI,EAAE,CAAC;QAC7B,MAAM,OAAO,CAAC,iBAAiB,CAAC,SAAS,CAAC,CAAC;QAC3C,MAAM,KAAK,GACT,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,CAAC,mBAAmB,GAAG,mBAAmB,GAAG,CAAC,CAAC,CAAC;YAC3E,mBAAmB,CAAC;QACtB,MAAM,IAAI,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC;IACnC,CAAC;AACH,CAAC;AAED,8EAA8E;AAC9E,SAAS,0BAA0B,CAAC,OAAe;IACjD,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2BA2CkB,OAAO;;;;CAIjC,CAAC;AACF,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,OAAuB,EAAE,OAAe;IAC5E,IAAI,OAAO,CAAC,GAAG,CAAC,wBAAwB,KAAK,GAAG,EAAE,CAAC;QACjD,OAAO;IACT,CAAC;IACD,MAAM,WAAW,GAAG,MAAM,OAAO,CAAC,OAAO,EAAE,CAAC;IAC5C,MAAM,WAAW,CAAC,QAAQ,CAAC,0BAA0B,CAAC,OAAO,CAAC,CAAC,CAAC;IAChE,MAAM,WAAW,CAAC,YAAY,EAAE,CAAC;AACnC,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/registry.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,
|
|
1
|
+
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/registry.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EACL,OAAO,EASR,MAAM,qBAAqB,CAAC;AAE7B,qBAAa,QAAQ;IACnB,QAAQ,CAAC,QAAQ,EAAE,SAAS,OAAO,EAAE,CAAC;gBAE1B,QAAQ,EAAE,SAAS,OAAO,EAAE;IAIxC,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,GAAG,IAAI;IASvC,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,GAAG,IAAI;CAgBtC;AAED,eAAO,MAAM,QAAQ,UASnB,CAAC"}
|
package/dist/src/registry.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Service registry for looking up services by name or URL.
|
|
3
3
|
*/
|
|
4
|
-
import { SLACK, DISCORD, DROPBOX, GITHUB, LINEAR } from './services/index.js';
|
|
4
|
+
import { SLACK, DISCORD, DROPBOX, GITHUB, LINEAR, NOTION, GOOGLE, MAILCHIMP, } from './services/index.js';
|
|
5
5
|
export class Registry {
|
|
6
6
|
services;
|
|
7
7
|
constructor(services) {
|
|
@@ -18,13 +18,29 @@ export class Registry {
|
|
|
18
18
|
getByUrl(url) {
|
|
19
19
|
for (const service of this.services) {
|
|
20
20
|
for (const baseApiUrl of service.baseApiUrls) {
|
|
21
|
-
if (
|
|
22
|
-
|
|
21
|
+
if (typeof baseApiUrl === 'string') {
|
|
22
|
+
if (url.startsWith(baseApiUrl)) {
|
|
23
|
+
return service;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
else {
|
|
27
|
+
if (baseApiUrl.test(url)) {
|
|
28
|
+
return service;
|
|
29
|
+
}
|
|
23
30
|
}
|
|
24
31
|
}
|
|
25
32
|
}
|
|
26
33
|
return null;
|
|
27
34
|
}
|
|
28
35
|
}
|
|
29
|
-
export const REGISTRY = new Registry([
|
|
36
|
+
export const REGISTRY = new Registry([
|
|
37
|
+
SLACK,
|
|
38
|
+
DISCORD,
|
|
39
|
+
DROPBOX,
|
|
40
|
+
GITHUB,
|
|
41
|
+
LINEAR,
|
|
42
|
+
NOTION,
|
|
43
|
+
GOOGLE,
|
|
44
|
+
MAILCHIMP,
|
|
45
|
+
]);
|
|
30
46
|
//# sourceMappingURL=registry.js.map
|
package/dist/src/registry.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/registry.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,
|
|
1
|
+
{"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/registry.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAEL,KAAK,EACL,OAAO,EACP,OAAO,EACP,MAAM,EACN,MAAM,EACN,MAAM,EACN,MAAM,EACN,SAAS,GACV,MAAM,qBAAqB,CAAC;AAE7B,MAAM,OAAO,QAAQ;IACV,QAAQ,CAAqB;IAEtC,YAAY,QAA4B;QACtC,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;IAC3B,CAAC;IAED,SAAS,CAAC,IAAY;QACpB,KAAK,MAAM,OAAO,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YACpC,IAAI,OAAO,CAAC,IAAI,KAAK,IAAI,EAAE,CAAC;gBAC1B,OAAO,OAAO,CAAC;YACjB,CAAC;QACH,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAED,QAAQ,CAAC,GAAW;QAClB,KAAK,MAAM,OAAO,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YACpC,KAAK,MAAM,UAAU,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC;gBAC7C,IAAI,OAAO,UAAU,KAAK,QAAQ,EAAE,CAAC;oBACnC,IAAI,GAAG,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;wBAC/B,OAAO,OAAO,CAAC;oBACjB,CAAC;gBACH,CAAC;qBAAM,CAAC;oBACN,IAAI,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;wBACzB,OAAO,OAAO,CAAC;oBACjB,CAAC;gBACH,CAAC;YACH,CAAC;QACH,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;CACF;AAED,MAAM,CAAC,MAAM,QAAQ,GAAG,IAAI,QAAQ,CAAC;IACnC,KAAK;IACL,OAAO;IACP,OAAO;IACP,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,SAAS;CACV,CAAC,CAAC"}
|
|
@@ -11,28 +11,43 @@ export declare class LoginCancelledError extends Error {
|
|
|
11
11
|
export declare class LoginFailedError extends Error {
|
|
12
12
|
constructor(message?: string);
|
|
13
13
|
}
|
|
14
|
+
export declare function isBrowserClosedError(error: Error): boolean;
|
|
14
15
|
/**
|
|
15
|
-
*
|
|
16
|
+
* Abstract base class for services that latchkey can authenticate with.
|
|
16
17
|
*/
|
|
17
|
-
export
|
|
18
|
-
readonly name: string;
|
|
19
|
-
readonly
|
|
20
|
-
readonly
|
|
18
|
+
export declare abstract class Service {
|
|
19
|
+
abstract readonly name: string;
|
|
20
|
+
abstract readonly displayName: string;
|
|
21
|
+
abstract readonly baseApiUrls: readonly (string | RegExp)[];
|
|
22
|
+
abstract readonly loginUrl: string;
|
|
21
23
|
/**
|
|
22
|
-
*
|
|
24
|
+
* Developer notes about this service for agents and users.
|
|
23
25
|
*/
|
|
24
|
-
|
|
26
|
+
abstract readonly info: string;
|
|
25
27
|
/**
|
|
26
28
|
* Return curl arguments for checking credentials (excluding auth headers).
|
|
27
29
|
*/
|
|
28
|
-
readonly credentialCheckCurlArguments: readonly string[];
|
|
30
|
+
abstract readonly credentialCheckCurlArguments: readonly string[];
|
|
31
|
+
/**
|
|
32
|
+
* Check if the given API credentials are valid for this service.
|
|
33
|
+
*/
|
|
34
|
+
checkApiCredentials(apiCredentials: ApiCredentials): ApiCredentialStatus;
|
|
29
35
|
/**
|
|
30
36
|
* Get a new session for the login flow.
|
|
37
|
+
* Services that don't support browser login should not implement this method.
|
|
38
|
+
*/
|
|
39
|
+
getSession?(): ServiceSession;
|
|
40
|
+
/**
|
|
41
|
+
* Optional method to refresh expired credentials.
|
|
42
|
+
* Services can implement this to refresh access tokens without user interaction.
|
|
43
|
+
* @param apiCredentials - The expired credentials
|
|
44
|
+
* @returns New credentials if refresh succeeded, null otherwise
|
|
31
45
|
*/
|
|
32
|
-
|
|
46
|
+
refreshCredentials?(apiCredentials: ApiCredentials): Promise<ApiCredentials | null>;
|
|
33
47
|
}
|
|
34
48
|
/**
|
|
35
|
-
* Base class for service sessions that handle
|
|
49
|
+
* Base class for service sessions that handle browser-based interactions.
|
|
50
|
+
* This includes login, preparation steps, and any other browser automation.
|
|
36
51
|
*/
|
|
37
52
|
export declare abstract class ServiceSession {
|
|
38
53
|
readonly service: Service;
|
|
@@ -48,8 +63,11 @@ export declare abstract class ServiceSession {
|
|
|
48
63
|
/**
|
|
49
64
|
* Finalize credentials after the headful login phase.
|
|
50
65
|
* Receives the browser and context from the login phase, which are still open.
|
|
66
|
+
* @param browser - Browser instance
|
|
67
|
+
* @param context - Browser context
|
|
68
|
+
* @param oldCredentials - Optional existing credentials to reuse
|
|
51
69
|
*/
|
|
52
|
-
protected abstract finalizeCredentials(browser: Browser, context: BrowserContext): Promise<ApiCredentials | null>;
|
|
70
|
+
protected abstract finalizeCredentials(browser: Browser, context: BrowserContext, oldCredentials?: ApiCredentials): Promise<ApiCredentials | null>;
|
|
53
71
|
/**
|
|
54
72
|
* Wait until the browser login phase is complete.
|
|
55
73
|
*/
|
|
@@ -63,10 +81,18 @@ export declare abstract class ServiceSession {
|
|
|
63
81
|
* LoginFailedError. If it returns null, the original timeout error message is used.
|
|
64
82
|
*/
|
|
65
83
|
protected diagnoseTimeoutError(_context: BrowserContext, _originalError: Error): Promise<Error | null>;
|
|
84
|
+
/**
|
|
85
|
+
* Optional preparation step before login.
|
|
86
|
+
* Services can override this to perform setup (e.g., creating OAuth clients).
|
|
87
|
+
*/
|
|
88
|
+
prepare?(encryptedStorage: EncryptedStorage, launchOptions?: BrowserLaunchOptions): Promise<ApiCredentials>;
|
|
66
89
|
/**
|
|
67
90
|
* Perform the login flow and return the extracted credentials.
|
|
91
|
+
* @param encryptedStorage - Storage for managing credentials
|
|
92
|
+
* @param launchOptions - Browser launch options
|
|
93
|
+
* @param oldCredentials - Optional existing credentials to reuse (e.g., client ID/secret)
|
|
68
94
|
*/
|
|
69
|
-
login(encryptedStorage: EncryptedStorage, launchOptions?: BrowserLaunchOptions): Promise<ApiCredentials>;
|
|
95
|
+
login(encryptedStorage: EncryptedStorage, launchOptions?: BrowserLaunchOptions, oldCredentials?: ApiCredentials): Promise<ApiCredentials>;
|
|
70
96
|
}
|
|
71
97
|
/**
|
|
72
98
|
* Simple service session where credentials are extracted by observing requests during login.
|
|
@@ -79,7 +105,7 @@ export declare abstract class SimpleServiceSession extends ServiceSession {
|
|
|
79
105
|
protected abstract getApiCredentialsFromResponse(response: Response): Promise<ApiCredentials | null>;
|
|
80
106
|
onResponse(response: Response): void;
|
|
81
107
|
protected isLoginComplete(): boolean;
|
|
82
|
-
protected finalizeCredentials(_browser: Browser, _context: BrowserContext): Promise<ApiCredentials | null>;
|
|
108
|
+
protected finalizeCredentials(_browser: Browser, _context: BrowserContext, _oldCredentials?: ApiCredentials): Promise<ApiCredentials | null>;
|
|
83
109
|
}
|
|
84
110
|
/**
|
|
85
111
|
* Service session that requires a browser followup to finalize credentials.
|
|
@@ -92,8 +118,10 @@ export declare abstract class BrowserFollowupServiceSession extends ServiceSessi
|
|
|
92
118
|
/**
|
|
93
119
|
* Perform actions in the browser to finalize and extract API credentials.
|
|
94
120
|
* This runs in the same browser session used for login.
|
|
121
|
+
* @param context - Browser context
|
|
122
|
+
* @param oldCredentials - Optional existing credentials to reuse
|
|
95
123
|
*/
|
|
96
|
-
protected abstract performBrowserFollowup(context: BrowserContext): Promise<ApiCredentials | null>;
|
|
97
|
-
protected finalizeCredentials(_browser: Browser, context: BrowserContext): Promise<ApiCredentials | null>;
|
|
124
|
+
protected abstract performBrowserFollowup(context: BrowserContext, oldCredentials?: ApiCredentials): Promise<ApiCredentials | null>;
|
|
125
|
+
protected finalizeCredentials(_browser: Browser, context: BrowserContext, oldCredentials?: ApiCredentials): Promise<ApiCredentials | null>;
|
|
98
126
|
}
|
|
99
127
|
//# sourceMappingURL=base.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"base.d.ts","sourceRoot":"","sources":["../../../src/services/base.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,cAAc,EAAQ,QAAQ,EAAE,MAAM,YAAY,CAAC;AAC1E,OAAO,
|
|
1
|
+
{"version":3,"file":"base.d.ts","sourceRoot":"","sources":["../../../src/services/base.ts"],"names":[],"mappings":"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"}
|