latchkey 2.21.0 → 3.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/README.md +36 -4
- package/dist/skills/generic/latchkey/SKILL.md +21 -0
- package/dist/skills/openclaw/latchkey/SKILL.md +21 -0
- package/dist/src/apiCredentials/account.d.ts +28 -0
- package/dist/src/apiCredentials/account.d.ts.map +1 -0
- package/dist/src/apiCredentials/account.js +49 -0
- package/dist/src/apiCredentials/account.js.map +1 -0
- package/dist/src/apiCredentials/store.d.ts +70 -4
- package/dist/src/apiCredentials/store.d.ts.map +1 -1
- package/dist/src/apiCredentials/store.js +161 -19
- package/dist/src/apiCredentials/store.js.map +1 -1
- package/dist/src/apiCredentials/utils.d.ts +2 -2
- package/dist/src/apiCredentials/utils.d.ts.map +1 -1
- package/dist/src/apiCredentials/utils.js +5 -5
- package/dist/src/apiCredentials/utils.js.map +1 -1
- package/dist/src/cli.js +1 -1
- package/dist/src/cli.js.map +1 -1
- package/dist/src/cliCommands.d.ts.map +1 -1
- package/dist/src/cliCommands.js +118 -22
- package/dist/src/cliCommands.js.map +1 -1
- package/dist/src/config.d.ts +6 -0
- package/dist/src/config.d.ts.map +1 -1
- package/dist/src/config.js +8 -0
- package/dist/src/config.js.map +1 -1
- package/dist/src/configDataStore.d.ts +3 -0
- package/dist/src/configDataStore.d.ts.map +1 -1
- package/dist/src/configDataStore.js +1 -0
- package/dist/src/configDataStore.js.map +1 -1
- package/dist/src/curl.d.ts +21 -16
- package/dist/src/curl.d.ts.map +1 -1
- package/dist/src/curl.js +17 -24
- package/dist/src/curl.js.map +1 -1
- package/dist/src/curlInjection.d.ts +8 -2
- package/dist/src/curlInjection.d.ts.map +1 -1
- package/dist/src/curlInjection.js +13 -8
- package/dist/src/curlInjection.js.map +1 -1
- package/dist/src/errorMessages.d.ts +2 -2
- package/dist/src/errorMessages.d.ts.map +1 -1
- package/dist/src/errorMessages.js +22 -6
- package/dist/src/errorMessages.js.map +1 -1
- package/dist/src/gateway/gatewayEndpoint.d.ts +1 -1
- package/dist/src/gateway/gatewayEndpoint.d.ts.map +1 -1
- package/dist/src/gateway/gatewayEndpoint.js +3 -1
- package/dist/src/gateway/gatewayEndpoint.js.map +1 -1
- package/dist/src/gateway/latchkeyEndpoint.d.ts +6 -0
- package/dist/src/gateway/latchkeyEndpoint.d.ts.map +1 -1
- package/dist/src/gateway/latchkeyEndpoint.js +6 -4
- package/dist/src/gateway/latchkeyEndpoint.js.map +1 -1
- package/dist/src/index.d.ts +2 -2
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +1 -1
- package/dist/src/index.js.map +1 -1
- package/dist/src/migrations.d.ts +21 -1
- package/dist/src/migrations.d.ts.map +1 -1
- package/dist/src/migrations.js +112 -4
- package/dist/src/migrations.js.map +1 -1
- package/dist/src/oauthUtils.d.ts +2 -2
- package/dist/src/oauthUtils.d.ts.map +1 -1
- package/dist/src/oauthUtils.js +5 -5
- package/dist/src/oauthUtils.js.map +1 -1
- package/dist/src/services/aws.d.ts +1 -0
- package/dist/src/services/aws.d.ts.map +1 -1
- package/dist/src/services/aws.js +13 -0
- package/dist/src/services/aws.js.map +1 -1
- package/dist/src/services/calendly.d.ts +2 -0
- package/dist/src/services/calendly.d.ts.map +1 -1
- package/dist/src/services/calendly.js +7 -0
- package/dist/src/services/calendly.js.map +1 -1
- package/dist/src/services/coolify.d.ts +3 -1
- package/dist/src/services/coolify.d.ts.map +1 -1
- package/dist/src/services/coolify.js +10 -1
- package/dist/src/services/coolify.js.map +1 -1
- package/dist/src/services/core/base.d.ts +43 -1
- package/dist/src/services/core/base.d.ts.map +1 -1
- package/dist/src/services/core/base.js +29 -9
- package/dist/src/services/core/base.js.map +1 -1
- package/dist/src/services/core/registered.d.ts +1 -0
- package/dist/src/services/core/registered.d.ts.map +1 -1
- package/dist/src/services/core/registered.js +5 -0
- package/dist/src/services/core/registered.js.map +1 -1
- package/dist/src/services/discord.d.ts +1 -0
- package/dist/src/services/discord.d.ts.map +1 -1
- package/dist/src/services/discord.js +9 -0
- package/dist/src/services/discord.js.map +1 -1
- package/dist/src/services/dropbox.d.ts +2 -1
- package/dist/src/services/dropbox.d.ts.map +1 -1
- package/dist/src/services/dropbox.js +17 -11
- package/dist/src/services/dropbox.js.map +1 -1
- package/dist/src/services/figma.d.ts +2 -0
- package/dist/src/services/figma.d.ts.map +1 -1
- package/dist/src/services/figma.js +7 -0
- package/dist/src/services/figma.js.map +1 -1
- package/dist/src/services/github.d.ts +1 -0
- package/dist/src/services/github.d.ts.map +1 -1
- package/dist/src/services/github.js +9 -0
- package/dist/src/services/github.js.map +1 -1
- package/dist/src/services/gitlab.d.ts +2 -0
- package/dist/src/services/gitlab.d.ts.map +1 -1
- package/dist/src/services/gitlab.js +9 -0
- package/dist/src/services/gitlab.js.map +1 -1
- package/dist/src/services/google/analytics.d.ts +0 -1
- package/dist/src/services/google/analytics.d.ts.map +1 -1
- package/dist/src/services/google/analytics.js +0 -3
- package/dist/src/services/google/analytics.js.map +1 -1
- package/dist/src/services/google/base.d.ts +11 -0
- package/dist/src/services/google/base.d.ts.map +1 -1
- package/dist/src/services/google/base.js +26 -7
- package/dist/src/services/google/base.js.map +1 -1
- package/dist/src/services/google/calendar.d.ts +0 -1
- package/dist/src/services/google/calendar.d.ts.map +1 -1
- package/dist/src/services/google/calendar.js +0 -3
- package/dist/src/services/google/calendar.js.map +1 -1
- package/dist/src/services/google/directions.d.ts +1 -0
- package/dist/src/services/google/directions.d.ts.map +1 -1
- package/dist/src/services/google/directions.js +5 -0
- package/dist/src/services/google/directions.js.map +1 -1
- package/dist/src/services/google/docs.d.ts +0 -1
- package/dist/src/services/google/docs.d.ts.map +1 -1
- package/dist/src/services/google/docs.js +0 -3
- package/dist/src/services/google/docs.js.map +1 -1
- package/dist/src/services/google/drive.d.ts +0 -1
- package/dist/src/services/google/drive.d.ts.map +1 -1
- package/dist/src/services/google/drive.js +0 -3
- package/dist/src/services/google/drive.js.map +1 -1
- package/dist/src/services/google/gmail.d.ts +0 -1
- package/dist/src/services/google/gmail.d.ts.map +1 -1
- package/dist/src/services/google/gmail.js +0 -3
- package/dist/src/services/google/gmail.js.map +1 -1
- package/dist/src/services/google/people.d.ts +0 -1
- package/dist/src/services/google/people.d.ts.map +1 -1
- package/dist/src/services/google/people.js +0 -3
- package/dist/src/services/google/people.js.map +1 -1
- package/dist/src/services/google/sheets.d.ts +0 -1
- package/dist/src/services/google/sheets.d.ts.map +1 -1
- package/dist/src/services/google/sheets.js +0 -3
- package/dist/src/services/google/sheets.js.map +1 -1
- package/dist/src/services/google/slides.d.ts +0 -1
- package/dist/src/services/google/slides.d.ts.map +1 -1
- package/dist/src/services/google/slides.js +0 -3
- package/dist/src/services/google/slides.js.map +1 -1
- package/dist/src/services/index.d.ts +1 -1
- package/dist/src/services/index.d.ts.map +1 -1
- package/dist/src/services/index.js.map +1 -1
- package/dist/src/services/linear.d.ts +2 -1
- package/dist/src/services/linear.d.ts.map +1 -1
- package/dist/src/services/linear.js +8 -1
- package/dist/src/services/linear.js.map +1 -1
- package/dist/src/services/mailchimp.d.ts +2 -0
- package/dist/src/services/mailchimp.d.ts.map +1 -1
- package/dist/src/services/mailchimp.js +7 -0
- package/dist/src/services/mailchimp.js.map +1 -1
- package/dist/src/services/notion-mcp.d.ts +3 -2
- package/dist/src/services/notion-mcp.d.ts.map +1 -1
- package/dist/src/services/notion-mcp.js +111 -14
- package/dist/src/services/notion-mcp.js.map +1 -1
- package/dist/src/services/notion.d.ts +2 -0
- package/dist/src/services/notion.d.ts.map +1 -1
- package/dist/src/services/notion.js +17 -0
- package/dist/src/services/notion.js.map +1 -1
- package/dist/src/services/ramp.d.ts +11 -2
- package/dist/src/services/ramp.d.ts.map +1 -1
- package/dist/src/services/ramp.js +35 -9
- package/dist/src/services/ramp.js.map +1 -1
- package/dist/src/services/sentry.d.ts +3 -2
- package/dist/src/services/sentry.d.ts.map +1 -1
- package/dist/src/services/sentry.js +12 -27
- package/dist/src/services/sentry.js.map +1 -1
- package/dist/src/services/slack.d.ts +3 -2
- package/dist/src/services/slack.d.ts.map +1 -1
- package/dist/src/services/slack.js +19 -13
- package/dist/src/services/slack.js.map +1 -1
- package/dist/src/services/stripe.d.ts +7 -0
- package/dist/src/services/stripe.d.ts.map +1 -1
- package/dist/src/services/stripe.js +15 -0
- package/dist/src/services/stripe.js.map +1 -1
- package/dist/src/services/telegram.d.ts +1 -0
- package/dist/src/services/telegram.d.ts.map +1 -1
- package/dist/src/services/telegram.js +7 -0
- package/dist/src/services/telegram.js.map +1 -1
- package/dist/src/services/todoist.d.ts +2 -1
- package/dist/src/services/todoist.d.ts.map +1 -1
- package/dist/src/services/todoist.js +9 -1
- package/dist/src/services/todoist.js.map +1 -1
- package/dist/src/services/umami.d.ts +3 -1
- package/dist/src/services/umami.d.ts.map +1 -1
- package/dist/src/services/umami.js +11 -1
- package/dist/src/services/umami.js.map +1 -1
- package/dist/src/services/yelp.d.ts +1 -0
- package/dist/src/services/yelp.d.ts.map +1 -1
- package/dist/src/services/yelp.js +5 -0
- package/dist/src/services/yelp.js.map +1 -1
- package/dist/src/services/zoom.d.ts +8 -0
- package/dist/src/services/zoom.d.ts.map +1 -1
- package/dist/src/services/zoom.js +16 -0
- package/dist/src/services/zoom.js.map +1 -1
- package/dist/src/sharedOperations.d.ts +30 -10
- package/dist/src/sharedOperations.d.ts.map +1 -1
- package/dist/src/sharedOperations.js +67 -29
- package/dist/src/sharedOperations.js.map +1 -1
- package/dist/src/version.d.ts +1 -1
- package/dist/src/version.d.ts.map +1 -1
- package/dist/src/version.js +1 -1
- package/dist/src/version.js.map +1 -1
- package/dist/tests/apiCredentialStore.test.js +155 -2
- package/dist/tests/apiCredentialStore.test.js.map +1 -1
- package/dist/tests/apiCredentialsUtils.test.js +1 -1
- package/dist/tests/apiCredentialsUtils.test.js.map +1 -1
- package/dist/tests/cli.test.js +334 -147
- package/dist/tests/cli.test.js.map +1 -1
- package/dist/tests/config.test.js +5 -0
- package/dist/tests/config.test.js.map +1 -1
- package/dist/tests/gateway.test.js +8 -18
- package/dist/tests/gateway.test.js.map +1 -1
- package/dist/tests/latchkeyEndpoint.test.js +18 -28
- package/dist/tests/latchkeyEndpoint.test.js.map +1 -1
- package/dist/tests/migrations.test.js +220 -39
- package/dist/tests/migrations.test.js.map +1 -1
- package/dist/tests/mockService.d.ts +25 -0
- package/dist/tests/mockService.d.ts.map +1 -0
- package/dist/tests/mockService.js +40 -0
- package/dist/tests/mockService.js.map +1 -0
- package/dist/tests/oauthUtils.test.js +12 -12
- package/dist/tests/oauthUtils.test.js.map +1 -1
- package/dist/tests/serviceAccounts.test.d.ts +12 -0
- package/dist/tests/serviceAccounts.test.d.ts.map +1 -0
- package/dist/tests/serviceAccounts.test.js +278 -0
- package/dist/tests/serviceAccounts.test.js.map +1 -0
- package/dist/tests/sharedOperations.test.js +327 -58
- package/dist/tests/sharedOperations.test.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Service } from './core/base.js';
|
|
2
|
+
import { fetchAccountFromEndpoint, tryParseJson } from '../apiCredentials/account.js';
|
|
2
3
|
export class Mailchimp extends Service {
|
|
3
4
|
name = 'mailchimp';
|
|
4
5
|
displayName = 'Mailchimp';
|
|
@@ -12,6 +13,12 @@ export class Mailchimp extends Service {
|
|
|
12
13
|
setCredentialsExample(serviceName) {
|
|
13
14
|
return `latchkey auth set ${serviceName} -H "Authorization: Bearer <token>"`;
|
|
14
15
|
}
|
|
16
|
+
getAccount(apiCredentials) {
|
|
17
|
+
return fetchAccountFromEndpoint(apiCredentials, this.credentialCheckCurlArguments, (responseBody) => {
|
|
18
|
+
const data = tryParseJson(responseBody);
|
|
19
|
+
return data?.login?.email ?? data?.login?.login_email ?? data?.accountname ?? null;
|
|
20
|
+
});
|
|
21
|
+
}
|
|
15
22
|
}
|
|
16
23
|
export const MAILCHIMP = new Mailchimp();
|
|
17
24
|
//# sourceMappingURL=mailchimp.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mailchimp.js","sourceRoot":"","sources":["../../../src/services/mailchimp.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"mailchimp.js","sourceRoot":"","sources":["../../../src/services/mailchimp.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AACzC,OAAO,EAAE,wBAAwB,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAEtF,MAAM,OAAO,SAAU,SAAQ,OAAO;IAC3B,IAAI,GAAG,WAAW,CAAC;IACnB,WAAW,GAAG,WAAW,CAAC;IAC1B,WAAW,GAAG;QACrB,4BAA4B;QAC5B,yCAAyC;KACjC,CAAC;IACF,QAAQ,GAAG,8BAA8B,CAAC;IAC1C,IAAI,GAAG,iDAAiD,CAAC;IAEzD,4BAA4B,GAAG,CAAC,6CAA6C,CAAU,CAAC;IAEjG,qBAAqB,CAAC,WAAmB;QACvC,OAAO,qBAAqB,WAAW,qCAAqC,CAAC;IAC/E,CAAC;IAEQ,UAAU,CAAC,cAA8B;QAChD,OAAO,wBAAwB,CAC7B,cAAc,EACd,IAAI,CAAC,4BAA4B,EACjC,CAAC,YAAY,EAAE,EAAE;YACf,MAAM,IAAI,GAAG,YAAY,CAAC,YAAY,CAG9B,CAAC;YACT,OAAO,IAAI,EAAE,KAAK,EAAE,KAAK,IAAI,IAAI,EAAE,KAAK,EAAE,WAAW,IAAI,IAAI,EAAE,WAAW,IAAI,IAAI,CAAC;QACrF,CAAC,CACF,CAAC;IACJ,CAAC;CACF;AAED,MAAM,CAAC,MAAM,SAAS,GAAG,IAAI,SAAS,EAAE,CAAC"}
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
import { z } from 'zod';
|
|
8
8
|
import type { Browser, BrowserContext, Response } from 'playwright';
|
|
9
9
|
import { type ApiCredentials } from '../apiCredentials/base.js';
|
|
10
|
-
import { Service, ServiceSession } from './core/base.js';
|
|
10
|
+
import { Service, ServiceSession, type LoginResult } from './core/base.js';
|
|
11
11
|
/**
|
|
12
12
|
* JSON accepted by `latchkey auth prepare notion-mcp`: the OAuth client id to
|
|
13
13
|
* reuse instead of registering a new client dynamically at mcp.notion.com.
|
|
@@ -26,7 +26,7 @@ declare class NotionMcpSession extends ServiceSession {
|
|
|
26
26
|
onResponse(_response: Response): void;
|
|
27
27
|
protected isLoginComplete(): boolean;
|
|
28
28
|
protected finalizeCredentials(_browser: Browser, _context: BrowserContext, _oldCredentials?: ApiCredentials): Promise<ApiCredentials | null>;
|
|
29
|
-
login(encryptedStorage: import('../encryptedStorage.js').EncryptedStorage, launchOptions?: import('../playwrightUtils.js').BrowserLaunchOptions, oldCredentials?: ApiCredentials): Promise<
|
|
29
|
+
login(encryptedStorage: import('../encryptedStorage.js').EncryptedStorage, launchOptions?: import('../playwrightUtils.js').BrowserLaunchOptions, oldCredentials?: ApiCredentials): Promise<LoginResult>;
|
|
30
30
|
}
|
|
31
31
|
export declare class NotionMcp extends Service {
|
|
32
32
|
readonly name = "notion-mcp";
|
|
@@ -42,6 +42,7 @@ export declare class NotionMcp extends Service {
|
|
|
42
42
|
* The login flow reuses this client id instead of registering a new client.
|
|
43
43
|
*/
|
|
44
44
|
prepareFromJson(parsedJson: unknown): ApiCredentials;
|
|
45
|
+
getAccount(apiCredentials: ApiCredentials): Promise<string | null>;
|
|
45
46
|
getSession(appNamePrefix: string): NotionMcpSession;
|
|
46
47
|
refreshCredentials(apiCredentials: ApiCredentials): Promise<ApiCredentials | null>;
|
|
47
48
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"notion-mcp.d.ts","sourceRoot":"","sources":["../../../src/services/notion-mcp.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,EAAE,OAAO,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACpE,OAAO,EAAE,KAAK,cAAc,EAAoB,MAAM,2BAA2B,CAAC;
|
|
1
|
+
{"version":3,"file":"notion-mcp.d.ts","sourceRoot":"","sources":["../../../src/services/notion-mcp.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,EAAE,OAAO,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACpE,OAAO,EAAE,KAAK,cAAc,EAAoB,MAAM,2BAA2B,CAAC;AAclF,OAAO,EACL,OAAO,EACP,cAAc,EACd,KAAK,WAAW,EAKjB,MAAM,gBAAgB,CAAC;AAExB;;;;;GAKG;AACH,eAAO,MAAM,2BAA2B;;;;;;EAI7B,CAAC;AAEZ,MAAM,MAAM,qBAAqB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,2BAA2B,CAAC,CAAC;AAiJhF,cAAM,gBAAiB,SAAQ,cAAc;IAC3C,UAAU,CAAC,SAAS,EAAE,QAAQ,GAAG,IAAI;IAIrC,SAAS,CAAC,eAAe,IAAI,OAAO;IAKpC,SAAS,CAAC,mBAAmB,CAC3B,QAAQ,EAAE,OAAO,EACjB,QAAQ,EAAE,cAAc,EACxB,eAAe,CAAC,EAAE,cAAc,GAC/B,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC;IAKlB,KAAK,CAClB,gBAAgB,EAAE,OAAO,wBAAwB,EAAE,gBAAgB,EACnE,aAAa,GAAE,OAAO,uBAAuB,EAAE,oBAAyB,EACxE,cAAc,CAAC,EAAE,cAAc,GAC9B,OAAO,CAAC,WAAW,CAAC;CA6FxB;AAED,qBAAa,SAAU,SAAQ,OAAO;IACpC,QAAQ,CAAC,IAAI,gBAAgB;IAC7B,QAAQ,CAAC,WAAW,gBAAgB;IACpC,QAAQ,CAAC,WAAW,uCAAwC;IAC5D,QAAQ,CAAC,QAAQ,sCAA0B;IAC3C,QAAQ,CAAC,IAAI,SAK8G;IAE3H,QAAQ,CAAC,4BAA4B,oVAa1B;IAEX,qBAAqB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM;IAIlD;;;;OAIG;IACM,eAAe,CAAC,UAAU,EAAE,OAAO,GAAG,cAAc;IAY7D,UAAU,CAAC,cAAc,EAAE,cAAc,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAQzD,UAAU,CAAC,aAAa,EAAE,MAAM,GAAG,gBAAgB;IAI7C,kBAAkB,CAC/B,cAAc,EAAE,cAAc,GAC7B,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC;CA+BlC;AAED,eAAO,MAAM,UAAU,WAAkB,CAAC"}
|
|
@@ -6,7 +6,8 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import { z } from 'zod';
|
|
8
8
|
import { OAuthCredentials } from '../apiCredentials/base.js';
|
|
9
|
-
import {
|
|
9
|
+
import { DEFAULT_ACCOUNT, fetchAccountFromEndpoint, tryParseJson, } from '../apiCredentials/account.js';
|
|
10
|
+
import { runCapturedAsync } from '../curl.js';
|
|
10
11
|
import { exchangeCodeForTokens, generateCodeChallenge, generateCodeVerifier, refreshAccessToken, startOAuthCallbackServer, } from '../oauthUtils.js';
|
|
11
12
|
import { Service, ServiceSession, LoginFailedError, LoginCancelledError, buildPreparedCredentials, isBrowserClosedError, } from './core/base.js';
|
|
12
13
|
/**
|
|
@@ -20,11 +21,12 @@ export const NotionMcpPrepareInputSchema = z
|
|
|
20
21
|
clientId: z.string().min(1),
|
|
21
22
|
})
|
|
22
23
|
.strict();
|
|
24
|
+
const MCP_ENDPOINT = 'https://mcp.notion.com/mcp';
|
|
23
25
|
const TOKEN_ENDPOINT = 'https://mcp.notion.com/token';
|
|
24
26
|
const REGISTRATION_ENDPOINT = 'https://mcp.notion.com/register';
|
|
25
27
|
const AUTHORIZATION_ENDPOINT = 'https://mcp.notion.com/authorize';
|
|
26
28
|
const LOGIN_TIMEOUT_MS = 120000;
|
|
27
|
-
function registerClient(redirectUri, clientName) {
|
|
29
|
+
async function registerClient(redirectUri, clientName) {
|
|
28
30
|
const body = JSON.stringify({
|
|
29
31
|
client_name: clientName,
|
|
30
32
|
redirect_uris: [redirectUri],
|
|
@@ -32,7 +34,7 @@ function registerClient(redirectUri, clientName) {
|
|
|
32
34
|
response_types: ['code'],
|
|
33
35
|
token_endpoint_auth_method: 'none',
|
|
34
36
|
});
|
|
35
|
-
const result =
|
|
37
|
+
const result = await runCapturedAsync(['-s', '-X', 'POST', '-H', 'Content-Type: application/json', '-d', body, REGISTRATION_ENDPOINT], 30);
|
|
36
38
|
if (result.returncode !== 0) {
|
|
37
39
|
throw new LoginFailedError(`Failed to register OAuth client: ${result.stderr}`);
|
|
38
40
|
}
|
|
@@ -50,6 +52,87 @@ function registerClient(redirectUri, clientName) {
|
|
|
50
52
|
throw new LoginFailedError(`Failed to parse client registration response: ${error instanceof Error ? error.message : String(error)}`);
|
|
51
53
|
}
|
|
52
54
|
}
|
|
55
|
+
/**
|
|
56
|
+
* Fallback account derivation from the token-exchange response, used when the
|
|
57
|
+
* MCP `get-users` lookup fails. Notion's MCP token endpoint reports `user_id`,
|
|
58
|
+
* `workspace_id` and `email_domain` (but not the full e-mail or the workspace
|
|
59
|
+
* name), so the best it can offer is the opaque user id combined with the
|
|
60
|
+
* e-mail domain.
|
|
61
|
+
*/
|
|
62
|
+
function parseAccountFromTokenResponse(tokens) {
|
|
63
|
+
const workspacePart = tokens.email_domain ?? tokens.workspace_id;
|
|
64
|
+
if (tokens.user_id !== undefined && workspacePart !== undefined) {
|
|
65
|
+
return `${tokens.user_id}@${workspacePart}`;
|
|
66
|
+
}
|
|
67
|
+
return tokens.user_id ?? tokens.workspace_id ?? DEFAULT_ACCOUNT;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* A single stateless `tools/call` asking the `notion-get-users` tool for the
|
|
71
|
+
* current user. Notion's MCP server does not require the initialize handshake
|
|
72
|
+
* or a session id for this, so one POST is enough.
|
|
73
|
+
*/
|
|
74
|
+
const GET_SELF_CURL_ARGUMENTS = [
|
|
75
|
+
'-X',
|
|
76
|
+
'POST',
|
|
77
|
+
'-H',
|
|
78
|
+
'Content-Type: application/json',
|
|
79
|
+
'-H',
|
|
80
|
+
'Accept: application/json, text/event-stream',
|
|
81
|
+
'-d',
|
|
82
|
+
JSON.stringify({
|
|
83
|
+
jsonrpc: '2.0',
|
|
84
|
+
id: 1,
|
|
85
|
+
method: 'tools/call',
|
|
86
|
+
params: { name: 'notion-get-users', arguments: { user_id: 'self' } },
|
|
87
|
+
}),
|
|
88
|
+
MCP_ENDPOINT,
|
|
89
|
+
];
|
|
90
|
+
/**
|
|
91
|
+
* Parse an MCP Streamable HTTP response body: either a plain JSON-RPC message
|
|
92
|
+
* or an SSE stream whose `data:` lines carry JSON-RPC messages (the last
|
|
93
|
+
* parseable one wins, which is the response to our request).
|
|
94
|
+
*/
|
|
95
|
+
function parseMcpResponseBody(body) {
|
|
96
|
+
const trimmed = body.trim();
|
|
97
|
+
if (trimmed.startsWith('data:') || trimmed.startsWith('event:') || trimmed.startsWith(':')) {
|
|
98
|
+
let lastParsedMessage = null;
|
|
99
|
+
for (const line of trimmed.split('\n')) {
|
|
100
|
+
if (line.startsWith('data:')) {
|
|
101
|
+
const parsed = tryParseJson(line.slice('data:'.length).trim());
|
|
102
|
+
if (parsed !== null) {
|
|
103
|
+
lastParsedMessage = parsed;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return lastParsedMessage;
|
|
108
|
+
}
|
|
109
|
+
return tryParseJson(trimmed);
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Extract the current user from a `notion-get-users` tool response. The tool
|
|
113
|
+
* result rides as JSON text inside the MCP content parts, e.g.
|
|
114
|
+
* `{"results":[{"type":"person","id":"...","name":"Hynek Urban","email":
|
|
115
|
+
* "hynek@imbue.com"}],"has_more":false}`. Prefers the e-mail; falls back to
|
|
116
|
+
* the name (bots have no e-mail).
|
|
117
|
+
*/
|
|
118
|
+
function parseAccountFromGetUsersResponse(responseBody) {
|
|
119
|
+
const message = parseMcpResponseBody(responseBody);
|
|
120
|
+
const content = message?.result?.content;
|
|
121
|
+
if (!Array.isArray(content)) {
|
|
122
|
+
return null;
|
|
123
|
+
}
|
|
124
|
+
for (const part of content) {
|
|
125
|
+
if (part.type !== 'text' || typeof part.text !== 'string') {
|
|
126
|
+
continue;
|
|
127
|
+
}
|
|
128
|
+
const toolResult = tryParseJson(part.text);
|
|
129
|
+
const self = toolResult?.results?.[0];
|
|
130
|
+
if (self !== undefined) {
|
|
131
|
+
return self.email ?? self.name ?? null;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
return null;
|
|
135
|
+
}
|
|
53
136
|
class NotionMcpSession extends ServiceSession {
|
|
54
137
|
onResponse(_response) {
|
|
55
138
|
// Not used — login detection is via OAuth callback, not response inspection.
|
|
@@ -82,7 +165,7 @@ class NotionMcpSession extends ServiceSession {
|
|
|
82
165
|
clientId = oldCredentials.clientId;
|
|
83
166
|
}
|
|
84
167
|
else {
|
|
85
|
-
const registration = registerClient(redirectUri, this.generateAppName('-mcp'));
|
|
168
|
+
const registration = await registerClient(redirectUri, this.generateAppName('-mcp'));
|
|
86
169
|
clientId = registration.client_id;
|
|
87
170
|
}
|
|
88
171
|
// 3. Generate PKCE verifier/challenge
|
|
@@ -98,13 +181,21 @@ class NotionMcpSession extends ServiceSession {
|
|
|
98
181
|
await page.goto(authUrl.toString());
|
|
99
182
|
// 5. Wait for user to authorize and callback to receive code
|
|
100
183
|
const code = await codePromise;
|
|
101
|
-
// 6. Exchange code for tokens
|
|
102
|
-
|
|
103
|
-
|
|
184
|
+
// 6. Exchange code for tokens. Besides the tokens, Notion's MCP token
|
|
185
|
+
// endpoint reports who authorized: user_id, workspace_id and
|
|
186
|
+
// email_domain ride along in the same response.
|
|
187
|
+
const tokens = (await exchangeCodeForTokens(TOKEN_ENDPOINT, code, clientId, '', // public client, no secret
|
|
188
|
+
redirectUri, codeVerifier));
|
|
104
189
|
const accessTokenExpiresAt = new Date(Date.now() + tokens.expires_in * 1000).toISOString();
|
|
105
190
|
await page.close();
|
|
106
|
-
|
|
191
|
+
const credentials = new OAuthCredentials(clientId, '', // public client
|
|
107
192
|
tokens.access_token, tokens.refresh_token, accessTokenExpiresAt);
|
|
193
|
+
return {
|
|
194
|
+
credentials,
|
|
195
|
+
// Prefer the full e-mail resolved via the MCP get-users tool; fall
|
|
196
|
+
// back to the coarser identity riding along in the token response.
|
|
197
|
+
account: (await this.service.getAccount(credentials)) ?? parseAccountFromTokenResponse(tokens),
|
|
198
|
+
};
|
|
108
199
|
}
|
|
109
200
|
catch (error) {
|
|
110
201
|
if (error instanceof Error && isBrowserClosedError(error)) {
|
|
@@ -154,22 +245,28 @@ export class NotionMcp extends Service {
|
|
|
154
245
|
prepareFromJson(parsedJson) {
|
|
155
246
|
return buildPreparedCredentials(this.name, NotionMcpPrepareInputSchema, parsedJson, ({ clientId }) => new OAuthCredentials(clientId, ''));
|
|
156
247
|
}
|
|
248
|
+
// MCP-audienced tokens cannot call the classic REST API, but the MCP
|
|
249
|
+
// endpoint itself can reveal the identity: the `get-users` tool returns the
|
|
250
|
+
// current user's name and e-mail when asked for `self`.
|
|
251
|
+
getAccount(apiCredentials) {
|
|
252
|
+
return fetchAccountFromEndpoint(apiCredentials, GET_SELF_CURL_ARGUMENTS, parseAccountFromGetUsersResponse);
|
|
253
|
+
}
|
|
157
254
|
getSession(appNamePrefix) {
|
|
158
255
|
return new NotionMcpSession(this, appNamePrefix);
|
|
159
256
|
}
|
|
160
|
-
refreshCredentials(apiCredentials) {
|
|
257
|
+
async refreshCredentials(apiCredentials) {
|
|
161
258
|
if (!(apiCredentials instanceof OAuthCredentials)) {
|
|
162
|
-
return
|
|
259
|
+
return null;
|
|
163
260
|
}
|
|
164
261
|
if (!apiCredentials.refreshToken) {
|
|
165
|
-
return
|
|
262
|
+
return null;
|
|
166
263
|
}
|
|
167
|
-
const tokens = refreshAccessToken(TOKEN_ENDPOINT, apiCredentials.refreshToken, apiCredentials.clientId, apiCredentials.clientSecret);
|
|
264
|
+
const tokens = await refreshAccessToken(TOKEN_ENDPOINT, apiCredentials.refreshToken, apiCredentials.clientId, apiCredentials.clientSecret);
|
|
168
265
|
if (tokens === null) {
|
|
169
|
-
return
|
|
266
|
+
return null;
|
|
170
267
|
}
|
|
171
268
|
const accessTokenExpiresAt = new Date(Date.now() + tokens.expires_in * 1000).toISOString();
|
|
172
|
-
return
|
|
269
|
+
return new OAuthCredentials(apiCredentials.clientId, apiCredentials.clientSecret, tokens.access_token, tokens.refresh_token ?? apiCredentials.refreshToken, accessTokenExpiresAt, apiCredentials.refreshTokenExpiresAt);
|
|
173
270
|
}
|
|
174
271
|
}
|
|
175
272
|
export const NOTION_MCP = new NotionMcp();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"notion-mcp.js","sourceRoot":"","sources":["../../../src/services/notion-mcp.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAuB,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAClF,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"notion-mcp.js","sourceRoot":"","sources":["../../../src/services/notion-mcp.ts"],"names":[],"mappings":"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"}
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* Browser-based login is not supported. Credentials must be set manually
|
|
5
5
|
* (e.g. by creating an internal integration at the loginUrl below).
|
|
6
6
|
*/
|
|
7
|
+
import type { ApiCredentials } from '../apiCredentials/base.js';
|
|
7
8
|
import { Service } from './core/base.js';
|
|
8
9
|
export declare class Notion extends Service {
|
|
9
10
|
readonly name = "notion";
|
|
@@ -13,6 +14,7 @@ export declare class Notion extends Service {
|
|
|
13
14
|
readonly info: string;
|
|
14
15
|
readonly credentialCheckCurlArguments: readonly ["-H", "Notion-Version: 2022-06-28", "https://api.notion.com/v1/users/me"];
|
|
15
16
|
setCredentialsExample(serviceName: string): string;
|
|
17
|
+
getAccount(apiCredentials: ApiCredentials): Promise<string | null>;
|
|
16
18
|
}
|
|
17
19
|
export declare const NOTION: Notion;
|
|
18
20
|
//# sourceMappingURL=notion.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"notion.d.ts","sourceRoot":"","sources":["../../../src/services/notion.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"notion.d.ts","sourceRoot":"","sources":["../../../src/services/notion.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAChE,OAAO,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AAMzC,qBAAa,MAAO,SAAQ,OAAO;IACjC,QAAQ,CAAC,IAAI,YAAY;IACzB,QAAQ,CAAC,WAAW,YAAY;IAChC,QAAQ,CAAC,WAAW,uCAAwC;IAC5D,QAAQ,CAAC,QAAQ,8EAA2B;IAC5C,QAAQ,CAAC,IAAI,SAEwI;IAErJ,QAAQ,CAAC,4BAA4B,sFAI1B;IAEX,qBAAqB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM;IAIzC,UAAU,CAAC,cAAc,EAAE,cAAc,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;CAwB5E;AAED,eAAO,MAAM,MAAM,QAAe,CAAC"}
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
* (e.g. by creating an internal integration at the loginUrl below).
|
|
6
6
|
*/
|
|
7
7
|
import { Service } from './core/base.js';
|
|
8
|
+
import { fetchAccountFromEndpoint, tryParseJson } from '../apiCredentials/account.js';
|
|
8
9
|
const NOTION_INTEGRATIONS_URL = 'https://www.notion.so/profile/integrations/internal/form/new-integration';
|
|
9
10
|
export class Notion extends Service {
|
|
10
11
|
name = 'notion';
|
|
@@ -21,6 +22,22 @@ export class Notion extends Service {
|
|
|
21
22
|
setCredentialsExample(serviceName) {
|
|
22
23
|
return `latchkey auth set ${serviceName} -H "Authorization: Bearer <token>"`;
|
|
23
24
|
}
|
|
25
|
+
getAccount(apiCredentials) {
|
|
26
|
+
return fetchAccountFromEndpoint(apiCredentials, this.credentialCheckCurlArguments, (responseBody) => {
|
|
27
|
+
// Internal-integration tokens authenticate as a bot user; the workspace
|
|
28
|
+
// name distinguishes tokens for different workspaces better than the
|
|
29
|
+
// per-integration bot name alone.
|
|
30
|
+
const data = tryParseJson(responseBody);
|
|
31
|
+
if (data === null) {
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
const workspaceName = data.bot?.workspace_name;
|
|
35
|
+
if (data.name !== undefined && workspaceName !== undefined) {
|
|
36
|
+
return `${data.name}@${workspaceName}`;
|
|
37
|
+
}
|
|
38
|
+
return data.name ?? workspaceName ?? data.id ?? null;
|
|
39
|
+
});
|
|
40
|
+
}
|
|
24
41
|
}
|
|
25
42
|
export const NOTION = new Notion();
|
|
26
43
|
//# sourceMappingURL=notion.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"notion.js","sourceRoot":"","sources":["../../../src/services/notion.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;
|
|
1
|
+
{"version":3,"file":"notion.js","sourceRoot":"","sources":["../../../src/services/notion.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AACzC,OAAO,EAAE,wBAAwB,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAEtF,MAAM,uBAAuB,GAC3B,0EAA0E,CAAC;AAE7E,MAAM,OAAO,MAAO,SAAQ,OAAO;IACxB,IAAI,GAAG,QAAQ,CAAC;IAChB,WAAW,GAAG,QAAQ,CAAC;IACvB,WAAW,GAAG,CAAC,yBAAyB,CAAU,CAAC;IACnD,QAAQ,GAAG,uBAAuB,CAAC;IACnC,IAAI,GACX,yEAAyE;QACzE,kJAAkJ,CAAC;IAE5I,4BAA4B,GAAG;QACtC,IAAI;QACJ,4BAA4B;QAC5B,oCAAoC;KAC5B,CAAC;IAEX,qBAAqB,CAAC,WAAmB;QACvC,OAAO,qBAAqB,WAAW,qCAAqC,CAAC;IAC/E,CAAC;IAEQ,UAAU,CAAC,cAA8B;QAChD,OAAO,wBAAwB,CAC7B,cAAc,EACd,IAAI,CAAC,4BAA4B,EACjC,CAAC,YAAY,EAAE,EAAE;YACf,wEAAwE;YACxE,qEAAqE;YACrE,kCAAkC;YAClC,MAAM,IAAI,GAAG,YAAY,CAAC,YAAY,CAI9B,CAAC;YACT,IAAI,IAAI,KAAK,IAAI,EAAE,CAAC;gBAClB,OAAO,IAAI,CAAC;YACd,CAAC;YACD,MAAM,aAAa,GAAG,IAAI,CAAC,GAAG,EAAE,cAAc,CAAC;YAC/C,IAAI,IAAI,CAAC,IAAI,KAAK,SAAS,IAAI,aAAa,KAAK,SAAS,EAAE,CAAC;gBAC3D,OAAO,GAAG,IAAI,CAAC,IAAI,IAAI,aAAa,EAAE,CAAC;YACzC,CAAC;YACD,OAAO,IAAI,CAAC,IAAI,IAAI,aAAa,IAAI,IAAI,CAAC,EAAE,IAAI,IAAI,CAAC;QACvD,CAAC,CACF,CAAC;IACJ,CAAC;CACF;AAED,MAAM,CAAC,MAAM,MAAM,GAAG,IAAI,MAAM,EAAE,CAAC"}
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
*/
|
|
14
14
|
import type { Browser, BrowserContext, Response } from 'playwright';
|
|
15
15
|
import { ApiCredentials } from '../apiCredentials/base.js';
|
|
16
|
-
import { Service, ServiceSession } from './core/base.js';
|
|
16
|
+
import { type LoginResult, Service, ServiceSession } from './core/base.js';
|
|
17
17
|
/**
|
|
18
18
|
* Browser login session: runs the OAuth authorization-code + PKCE flow in a
|
|
19
19
|
* Playwright browser and returns OAuthCredentials. login() is overridden wholesale
|
|
@@ -24,7 +24,7 @@ declare class RampOAuthServiceSession extends ServiceSession {
|
|
|
24
24
|
onResponse(_response: Response): void;
|
|
25
25
|
protected isLoginComplete(): boolean;
|
|
26
26
|
protected finalizeCredentials(_browser: Browser, _context: BrowserContext, _oldCredentials?: ApiCredentials): Promise<ApiCredentials | null>;
|
|
27
|
-
login(encryptedStorage: import('../encryptedStorage.js').EncryptedStorage, launchOptions?: import('../playwrightUtils.js').BrowserLaunchOptions, _oldCredentials?: ApiCredentials): Promise<
|
|
27
|
+
login(encryptedStorage: import('../encryptedStorage.js').EncryptedStorage, launchOptions?: import('../playwrightUtils.js').BrowserLaunchOptions, _oldCredentials?: ApiCredentials): Promise<LoginResult>;
|
|
28
28
|
}
|
|
29
29
|
export declare class Ramp extends Service {
|
|
30
30
|
readonly name = "ramp";
|
|
@@ -34,6 +34,15 @@ export declare class Ramp extends Service {
|
|
|
34
34
|
readonly info: string;
|
|
35
35
|
readonly credentialCheckCurlArguments: readonly ["-X", "POST", "-H", "Content-Type: application/json", "-d", "{\"query\":\"ping\",\"rationale\":\"latchkey credential check\"}", "https://api.ramp.com/developer/v1/agent-tools/search-help-center-snippets"];
|
|
36
36
|
setCredentialsExample(serviceName: string): string;
|
|
37
|
+
/**
|
|
38
|
+
* The account comes from `get-simplified-user-detail` — the agent-tools
|
|
39
|
+
* endpoint that returns the caller's user — rather than the scope-less
|
|
40
|
+
* help-center endpoint used by the credential check, which carries no
|
|
41
|
+
* identity. It needs the `users:read` scope (requested during login, but
|
|
42
|
+
* granted only if the signed-in user is entitled to it), so the account may
|
|
43
|
+
* stay undetermined.
|
|
44
|
+
*/
|
|
45
|
+
getAccount(apiCredentials: ApiCredentials): Promise<string | null>;
|
|
37
46
|
/**
|
|
38
47
|
* Browser login: run the OAuth authorization-code + PKCE flow and store the
|
|
39
48
|
* resulting bearer + refresh token.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ramp.d.ts","sourceRoot":"","sources":["../../../src/services/ramp.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAGH,OAAO,KAAK,EAAE,OAAO,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACpE,OAAO,EAAE,cAAc,EAAoB,MAAM,2BAA2B,CAAC;
|
|
1
|
+
{"version":3,"file":"ramp.d.ts","sourceRoot":"","sources":["../../../src/services/ramp.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAGH,OAAO,KAAK,EAAE,OAAO,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACpE,OAAO,EAAE,cAAc,EAAoB,MAAM,2BAA2B,CAAC;AAa7E,OAAO,EAEL,KAAK,WAAW,EAEhB,OAAO,EACP,cAAc,EACf,MAAM,gBAAgB,CAAC;AAqDxB;;;;;GAKG;AACH,cAAM,uBAAwB,SAAQ,cAAc;IAClD,UAAU,CAAC,SAAS,EAAE,QAAQ,GAAG,IAAI;IAKrC,SAAS,CAAC,eAAe,IAAI,OAAO;IAKpC,SAAS,CAAC,mBAAmB,CAC3B,QAAQ,EAAE,OAAO,EACjB,QAAQ,EAAE,cAAc,EACxB,eAAe,CAAC,EAAE,cAAc,GAC/B,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC;IAKlB,KAAK,CAClB,gBAAgB,EAAE,OAAO,wBAAwB,EAAE,gBAAgB,EACnE,aAAa,GAAE,OAAO,uBAAuB,EAAE,oBAAyB,EACxE,eAAe,CAAC,EAAE,cAAc,GAC/B,OAAO,CAAC,WAAW,CAAC;CA+ExB;AAED,qBAAa,IAAK,SAAQ,OAAO;IAC/B,QAAQ,CAAC,IAAI,UAAU;IACvB,QAAQ,CAAC,WAAW,UAAU;IAC9B,QAAQ,CAAC,WAAW,qCAAsC;IAC1D,QAAQ,CAAC,QAAQ,2BAA2B;IAC5C,QAAQ,CAAC,IAAI,SAE+C;IAO5D,QAAQ,CAAC,4BAA4B,yNAQ1B;IAEX,qBAAqB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM;IAIlD;;;;;;;OAOG;IACM,UAAU,CAAC,cAAc,EAAE,cAAc,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAsB3E;;;OAGG;IACM,UAAU,CAAC,aAAa,EAAE,MAAM,GAAG,uBAAuB;IAIpD,kBAAkB,CAC/B,cAAc,EAAE,cAAc,GAC7B,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC;CA6BlC;AAED,eAAO,MAAM,IAAI,MAAa,CAAC"}
|
|
@@ -13,8 +13,9 @@
|
|
|
13
13
|
*/
|
|
14
14
|
import { randomUUID } from 'node:crypto';
|
|
15
15
|
import { OAuthCredentials } from '../apiCredentials/base.js';
|
|
16
|
+
import { DEFAULT_ACCOUNT, fetchAccountFromEndpoint, tryParseJson, } from '../apiCredentials/account.js';
|
|
16
17
|
import { exchangeCodeForTokens, generateCodeChallenge, generateCodeVerifier, refreshAccessToken, startOAuthCallbackServer, } from '../oauthUtils.js';
|
|
17
|
-
import { isBrowserClosedError, LoginCancelledError, Service, ServiceSession } from './core/base.js';
|
|
18
|
+
import { isBrowserClosedError, LoginCancelledError, Service, ServiceSession, } from './core/base.js';
|
|
18
19
|
/** Ramp's public OAuth client (PKCE, no secret), from ramp-cli. */
|
|
19
20
|
const RAMP_OAUTH_CLIENT_ID = 'ramp_id_6pKvd0IR3d8Kuzp82SV6YgpVCZOlz68Px6s3wVsr';
|
|
20
21
|
/** Hosted authorize endpoint (where the user signs in / approves the agent key). */
|
|
@@ -113,11 +114,13 @@ class RampOAuthServiceSession extends ServiceSession {
|
|
|
113
114
|
// 4. Wait for the user to finish and the callback to deliver the code.
|
|
114
115
|
const code = await codePromise;
|
|
115
116
|
// 5. Exchange the code for tokens (public client: no secret).
|
|
116
|
-
const tokens = exchangeCodeForTokens(RAMP_PKCE_TOKEN_ENDPOINT, code, clientId, '', redirectUri, codeVerifier);
|
|
117
|
+
const tokens = await exchangeCodeForTokens(RAMP_PKCE_TOKEN_ENDPOINT, code, clientId, '', redirectUri, codeVerifier);
|
|
117
118
|
const accessTokenExpiresAt = new Date(Date.now() + tokens.expires_in * 1000).toISOString();
|
|
118
119
|
await page.close();
|
|
119
120
|
// Public client: clientSecret is stored as '' so refresh sends client_id only.
|
|
120
|
-
|
|
121
|
+
const credentials = new OAuthCredentials(clientId, '', tokens.access_token, tokens.refresh_token, accessTokenExpiresAt);
|
|
122
|
+
const account = (await this.service.getAccount(credentials)) ?? DEFAULT_ACCOUNT;
|
|
123
|
+
return { credentials, account };
|
|
121
124
|
}
|
|
122
125
|
catch (error) {
|
|
123
126
|
if (error instanceof Error && isBrowserClosedError(error)) {
|
|
@@ -156,6 +159,29 @@ export class Ramp extends Service {
|
|
|
156
159
|
setCredentialsExample(serviceName) {
|
|
157
160
|
return `latchkey auth browser ${serviceName}`;
|
|
158
161
|
}
|
|
162
|
+
/**
|
|
163
|
+
* The account comes from `get-simplified-user-detail` — the agent-tools
|
|
164
|
+
* endpoint that returns the caller's user — rather than the scope-less
|
|
165
|
+
* help-center endpoint used by the credential check, which carries no
|
|
166
|
+
* identity. It needs the `users:read` scope (requested during login, but
|
|
167
|
+
* granted only if the signed-in user is entitled to it), so the account may
|
|
168
|
+
* stay undetermined.
|
|
169
|
+
*/
|
|
170
|
+
getAccount(apiCredentials) {
|
|
171
|
+
return fetchAccountFromEndpoint(apiCredentials, [
|
|
172
|
+
'-X',
|
|
173
|
+
'POST',
|
|
174
|
+
'-H',
|
|
175
|
+
'Content-Type: application/json',
|
|
176
|
+
'-d',
|
|
177
|
+
'{"rationale":"latchkey determines which account these credentials belong to"}',
|
|
178
|
+
'https://api.ramp.com/developer/v1/agent-tools/get-simplified-user-detail',
|
|
179
|
+
], (responseBody) => {
|
|
180
|
+
const data = tryParseJson(responseBody);
|
|
181
|
+
const user = data?.users?.[0];
|
|
182
|
+
return user?.email ?? user?.id ?? null;
|
|
183
|
+
});
|
|
184
|
+
}
|
|
159
185
|
/**
|
|
160
186
|
* Browser login: run the OAuth authorization-code + PKCE flow and store the
|
|
161
187
|
* resulting bearer + refresh token.
|
|
@@ -163,22 +189,22 @@ export class Ramp extends Service {
|
|
|
163
189
|
getSession(appNamePrefix) {
|
|
164
190
|
return new RampOAuthServiceSession(this, appNamePrefix);
|
|
165
191
|
}
|
|
166
|
-
refreshCredentials(apiCredentials) {
|
|
192
|
+
async refreshCredentials(apiCredentials) {
|
|
167
193
|
// Refresh the PKCE access token with the (rotating) refresh token against the
|
|
168
194
|
// `/token/pkce` endpoint, mirroring ramp-cli.
|
|
169
195
|
if (!(apiCredentials instanceof OAuthCredentials)) {
|
|
170
|
-
return
|
|
196
|
+
return null;
|
|
171
197
|
}
|
|
172
198
|
if (apiCredentials.refreshToken === undefined || apiCredentials.refreshToken === '') {
|
|
173
|
-
return
|
|
199
|
+
return null;
|
|
174
200
|
}
|
|
175
|
-
const tokens = refreshAccessToken(RAMP_PKCE_TOKEN_ENDPOINT, apiCredentials.refreshToken, apiCredentials.clientId, apiCredentials.clientSecret);
|
|
201
|
+
const tokens = await refreshAccessToken(RAMP_PKCE_TOKEN_ENDPOINT, apiCredentials.refreshToken, apiCredentials.clientId, apiCredentials.clientSecret);
|
|
176
202
|
if (tokens === null) {
|
|
177
|
-
return
|
|
203
|
+
return null;
|
|
178
204
|
}
|
|
179
205
|
const accessTokenExpiresAt = new Date(Date.now() + tokens.expires_in * 1000).toISOString();
|
|
180
206
|
// Ramp rotates refresh tokens; keep the old one only if none came back.
|
|
181
|
-
return
|
|
207
|
+
return new OAuthCredentials(apiCredentials.clientId, apiCredentials.clientSecret, tokens.access_token, tokens.refresh_token ?? apiCredentials.refreshToken, accessTokenExpiresAt, apiCredentials.refreshTokenExpiresAt);
|
|
182
208
|
}
|
|
183
209
|
}
|
|
184
210
|
export const RAMP = new Ramp();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ramp.js","sourceRoot":"","sources":["../../../src/services/ramp.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC,OAAO,EAAkB,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAC7E,OAAO,EACL,qBAAqB,EACrB,qBAAqB,EACrB,oBAAoB,EACpB,kBAAkB,EAClB,wBAAwB,GACzB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,
|
|
1
|
+
{"version":3,"file":"ramp.js","sourceRoot":"","sources":["../../../src/services/ramp.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { ApiCredentials } from '../apiCredentials/base.js';
|
|
2
2
|
import { Service } from './core/base.js';
|
|
3
3
|
export declare class Sentry extends Service {
|
|
4
4
|
readonly name = "sentry";
|
|
@@ -8,7 +8,8 @@ export declare class Sentry extends Service {
|
|
|
8
8
|
readonly info = "https://docs.sentry.io/api/.";
|
|
9
9
|
readonly credentialCheckCurlArguments: readonly ["-H", "Content-Type: application/json", "https://sentry.io/api/0/"];
|
|
10
10
|
setCredentialsExample(serviceName: string): string;
|
|
11
|
-
|
|
11
|
+
protected isCredentialCheckResponseValid(_httpStatusCode: string, responseBody: string): boolean;
|
|
12
|
+
getAccount(apiCredentials: ApiCredentials): Promise<string | null>;
|
|
12
13
|
}
|
|
13
14
|
export declare const SENTRY: Sentry;
|
|
14
15
|
//# sourceMappingURL=sentry.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sentry.d.ts","sourceRoot":"","sources":["../../../src/services/sentry.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"sentry.d.ts","sourceRoot":"","sources":["../../../src/services/sentry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAChE,OAAO,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AAGzC,qBAAa,MAAO,SAAQ,OAAO;IACjC,QAAQ,CAAC,IAAI,YAAY;IACzB,QAAQ,CAAC,WAAW,YAAY;IAChC,QAAQ,CAAC,WAAW,sCAAuC;IAC3D,QAAQ,CAAC,QAAQ,mCAAmC;IACpD,QAAQ,CAAC,IAAI,kCAAkC;IAE/C,QAAQ,CAAC,4BAA4B,gFAI1B;IAEX,qBAAqB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM;cAM/B,8BAA8B,CAC/C,eAAe,EAAE,MAAM,EACvB,YAAY,EAAE,MAAM,GACnB,OAAO;IAKD,UAAU,CAAC,cAAc,EAAE,cAAc,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;CAY5E;AAED,eAAO,MAAM,MAAM,QAAe,CAAC"}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import { ApiCredentialStatus, ApiCredentialsUsageError, } from '../apiCredentials/base.js';
|
|
2
|
-
import { runCaptured } from '../curl.js';
|
|
3
1
|
import { Service } from './core/base.js';
|
|
2
|
+
import { fetchAccountFromEndpoint, tryParseJson } from '../apiCredentials/account.js';
|
|
4
3
|
export class Sentry extends Service {
|
|
5
4
|
name = 'sentry';
|
|
6
5
|
displayName = 'Sentry';
|
|
@@ -15,31 +14,17 @@ export class Sentry extends Service {
|
|
|
15
14
|
setCredentialsExample(serviceName) {
|
|
16
15
|
return `latchkey auth set ${serviceName} -H "Authorization: Bearer <token>"`;
|
|
17
16
|
}
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
}
|
|
30
|
-
throw error;
|
|
31
|
-
}
|
|
32
|
-
const result = runCaptured(allCurlArgs, 10);
|
|
33
|
-
try {
|
|
34
|
-
const data = JSON.parse(result.stdout);
|
|
35
|
-
if (data.user) {
|
|
36
|
-
return ApiCredentialStatus.Valid;
|
|
37
|
-
}
|
|
38
|
-
return ApiCredentialStatus.Invalid;
|
|
39
|
-
}
|
|
40
|
-
catch {
|
|
41
|
-
return ApiCredentialStatus.Invalid;
|
|
42
|
-
}
|
|
17
|
+
// The root API endpoint responds HTTP 200 even without valid credentials;
|
|
18
|
+
// authenticated requests are recognizable by the `user` field in the body.
|
|
19
|
+
isCredentialCheckResponseValid(_httpStatusCode, responseBody) {
|
|
20
|
+
const data = tryParseJson(responseBody);
|
|
21
|
+
return data?.user !== undefined && data.user !== null && data.user !== false;
|
|
22
|
+
}
|
|
23
|
+
getAccount(apiCredentials) {
|
|
24
|
+
return fetchAccountFromEndpoint(apiCredentials, this.credentialCheckCurlArguments, (responseBody) => {
|
|
25
|
+
const data = tryParseJson(responseBody);
|
|
26
|
+
return data?.user?.email ?? data?.user?.username ?? data?.user?.id ?? null;
|
|
27
|
+
});
|
|
43
28
|
}
|
|
44
29
|
}
|
|
45
30
|
export const SENTRY = new Sentry();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sentry.js","sourceRoot":"","sources":["../../../src/services/sentry.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"sentry.js","sourceRoot":"","sources":["../../../src/services/sentry.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AACzC,OAAO,EAAE,wBAAwB,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAEtF,MAAM,OAAO,MAAO,SAAQ,OAAO;IACxB,IAAI,GAAG,QAAQ,CAAC;IAChB,WAAW,GAAG,QAAQ,CAAC;IACvB,WAAW,GAAG,CAAC,wBAAwB,CAAU,CAAC;IAClD,QAAQ,GAAG,+BAA+B,CAAC;IAC3C,IAAI,GAAG,8BAA8B,CAAC;IAEtC,4BAA4B,GAAG;QACtC,IAAI;QACJ,gCAAgC;QAChC,0BAA0B;KAClB,CAAC;IAEX,qBAAqB,CAAC,WAAmB;QACvC,OAAO,qBAAqB,WAAW,qCAAqC,CAAC;IAC/E,CAAC;IAED,0EAA0E;IAC1E,2EAA2E;IACxD,8BAA8B,CAC/C,eAAuB,EACvB,YAAoB;QAEpB,MAAM,IAAI,GAAG,YAAY,CAAC,YAAY,CAA8B,CAAC;QACrE,OAAO,IAAI,EAAE,IAAI,KAAK,SAAS,IAAI,IAAI,CAAC,IAAI,KAAK,IAAI,IAAI,IAAI,CAAC,IAAI,KAAK,KAAK,CAAC;IAC/E,CAAC;IAEQ,UAAU,CAAC,cAA8B;QAChD,OAAO,wBAAwB,CAC7B,cAAc,EACd,IAAI,CAAC,4BAA4B,EACjC,CAAC,YAAY,EAAE,EAAE;YACf,MAAM,IAAI,GAAG,YAAY,CAAC,YAAY,CAE9B,CAAC;YACT,OAAO,IAAI,EAAE,IAAI,EAAE,KAAK,IAAI,IAAI,EAAE,IAAI,EAAE,QAAQ,IAAI,IAAI,EAAE,IAAI,EAAE,EAAE,IAAI,IAAI,CAAC;QAC7E,CAAC,CACF,CAAC;IACJ,CAAC;CACF;AAED,MAAM,CAAC,MAAM,MAAM,GAAG,IAAI,MAAM,EAAE,CAAC"}
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
import type { Response } from 'playwright';
|
|
5
5
|
import { z } from 'zod';
|
|
6
|
-
import {
|
|
6
|
+
import type { ApiCredentials } from '../apiCredentials/base.js';
|
|
7
7
|
import { Service, SimpleServiceSession } from './core/base.js';
|
|
8
8
|
/**
|
|
9
9
|
* Slack-specific credentials (token + d cookie).
|
|
@@ -45,7 +45,8 @@ export declare class Slack extends Service {
|
|
|
45
45
|
readonly credentialCheckCurlArguments: readonly ["https://slack.com/api/auth.test"];
|
|
46
46
|
setCredentialsExample(serviceName: string): string;
|
|
47
47
|
getSession(appNamePrefix: string): SlackServiceSession;
|
|
48
|
-
|
|
48
|
+
protected isCredentialCheckResponseValid(_httpStatusCode: string, responseBody: string): boolean;
|
|
49
|
+
getAccount(apiCredentials: ApiCredentials): Promise<string | null>;
|
|
49
50
|
}
|
|
50
51
|
export declare const SLACK: Slack;
|
|
51
52
|
export {};
|