brainhub-mcp 0.1.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 +201 -0
- package/README.md +84 -0
- package/dist/adapters/claude.d.ts +2 -0
- package/dist/adapters/claude.js +50 -0
- package/dist/adapters/claude.js.map +1 -0
- package/dist/adapters/codex.d.ts +2 -0
- package/dist/adapters/codex.js +52 -0
- package/dist/adapters/codex.js.map +1 -0
- package/dist/adapters/content.d.ts +6 -0
- package/dist/adapters/content.js +68 -0
- package/dist/adapters/content.js.map +1 -0
- package/dist/adapters/grok.d.ts +2 -0
- package/dist/adapters/grok.js +44 -0
- package/dist/adapters/grok.js.map +1 -0
- package/dist/adapters/index.d.ts +31 -0
- package/dist/adapters/index.js +111 -0
- package/dist/adapters/index.js.map +1 -0
- package/dist/adapters/jsonl.d.ts +6 -0
- package/dist/adapters/jsonl.js +26 -0
- package/dist/adapters/jsonl.js.map +1 -0
- package/dist/adapters/types.d.ts +10 -0
- package/dist/adapters/types.js +2 -0
- package/dist/adapters/types.js.map +1 -0
- package/dist/auth/account-status.d.ts +50 -0
- package/dist/auth/account-status.js +59 -0
- package/dist/auth/account-status.js.map +1 -0
- package/dist/auth/google-account.d.ts +21 -0
- package/dist/auth/google-account.js +45 -0
- package/dist/auth/google-account.js.map +1 -0
- package/dist/auth/google-oauth.d.ts +35 -0
- package/dist/auth/google-oauth.js +191 -0
- package/dist/auth/google-oauth.js.map +1 -0
- package/dist/auth/oauth-loopback.d.ts +10 -0
- package/dist/auth/oauth-loopback.js +81 -0
- package/dist/auth/oauth-loopback.js.map +1 -0
- package/dist/auth/official-oauth-client.d.ts +5 -0
- package/dist/auth/official-oauth-client.js +6 -0
- package/dist/auth/official-oauth-client.js.map +1 -0
- package/dist/auth/platform-secrets.d.ts +14 -0
- package/dist/auth/platform-secrets.js +81 -0
- package/dist/auth/platform-secrets.js.map +1 -0
- package/dist/auth/secret-store-factory.d.ts +11 -0
- package/dist/auth/secret-store-factory.js +37 -0
- package/dist/auth/secret-store-factory.js.map +1 -0
- package/dist/auth/secret-store.d.ts +13 -0
- package/dist/auth/secret-store.js +40 -0
- package/dist/auth/secret-store.js.map +1 -0
- package/dist/capture/images.d.ts +11 -0
- package/dist/capture/images.js +27 -0
- package/dist/capture/images.js.map +1 -0
- package/dist/capture/normalize.d.ts +11 -0
- package/dist/capture/normalize.js +43 -0
- package/dist/capture/normalize.js.map +1 -0
- package/dist/capture/redact.d.ts +10 -0
- package/dist/capture/redact.js +60 -0
- package/dist/capture/redact.js.map +1 -0
- package/dist/cli/index.d.ts +20 -0
- package/dist/cli/index.js +781 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/clients/registry.d.ts +24 -0
- package/dist/clients/registry.js +105 -0
- package/dist/clients/registry.js.map +1 -0
- package/dist/domain/config-io.d.ts +15 -0
- package/dist/domain/config-io.js +168 -0
- package/dist/domain/config-io.js.map +1 -0
- package/dist/domain/config.d.ts +74 -0
- package/dist/domain/config.js +130 -0
- package/dist/domain/config.js.map +1 -0
- package/dist/domain/errors.d.ts +6 -0
- package/dist/domain/errors.js +11 -0
- package/dist/domain/errors.js.map +1 -0
- package/dist/domain/session.d.ts +62 -0
- package/dist/domain/session.js +47 -0
- package/dist/domain/session.js.map +1 -0
- package/dist/drive/drive-port.d.ts +51 -0
- package/dist/drive/drive-port.js +2 -0
- package/dist/drive/drive-port.js.map +1 -0
- package/dist/drive/google-drive.d.ts +28 -0
- package/dist/drive/google-drive.js +501 -0
- package/dist/drive/google-drive.js.map +1 -0
- package/dist/drive/memory-drive.d.ts +19 -0
- package/dist/drive/memory-drive.js +148 -0
- package/dist/drive/memory-drive.js.map +1 -0
- package/dist/drive/scoped-drive.d.ts +17 -0
- package/dist/drive/scoped-drive.js +115 -0
- package/dist/drive/scoped-drive.js.map +1 -0
- package/dist/mcp/server.d.ts +55 -0
- package/dist/mcp/server.js +133 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/portrait/obsidian.d.ts +7 -0
- package/dist/portrait/obsidian.js +16 -0
- package/dist/portrait/obsidian.js.map +1 -0
- package/dist/portrait/portrait-service.d.ts +12 -0
- package/dist/portrait/portrait-service.js +18 -0
- package/dist/portrait/portrait-service.js.map +1 -0
- package/dist/portrait/portrait-sync-service.d.ts +21 -0
- package/dist/portrait/portrait-sync-service.js +43 -0
- package/dist/portrait/portrait-sync-service.js.map +1 -0
- package/dist/runtime/command.d.ts +4 -0
- package/dist/runtime/command.js +2 -0
- package/dist/runtime/command.js.map +1 -0
- package/dist/runtime/container.d.ts +72 -0
- package/dist/runtime/container.js +361 -0
- package/dist/runtime/container.js.map +1 -0
- package/dist/scheduler/jobs.d.ts +2 -0
- package/dist/scheduler/jobs.js +7 -0
- package/dist/scheduler/jobs.js.map +1 -0
- package/dist/scheduler/launchd.d.ts +7 -0
- package/dist/scheduler/launchd.js +40 -0
- package/dist/scheduler/launchd.js.map +1 -0
- package/dist/scheduler/manager.d.ts +26 -0
- package/dist/scheduler/manager.js +113 -0
- package/dist/scheduler/manager.js.map +1 -0
- package/dist/search/chunk-text.d.ts +11 -0
- package/dist/search/chunk-text.js +40 -0
- package/dist/search/chunk-text.js.map +1 -0
- package/dist/search/e5-embedder.d.ts +19 -0
- package/dist/search/e5-embedder.js +71 -0
- package/dist/search/e5-embedder.js.map +1 -0
- package/dist/search/embedder.d.ts +8 -0
- package/dist/search/embedder.js +5 -0
- package/dist/search/embedder.js.map +1 -0
- package/dist/search/model-cache.d.ts +7 -0
- package/dist/search/model-cache.js +38 -0
- package/dist/search/model-cache.js.map +1 -0
- package/dist/search/search-service.d.ts +46 -0
- package/dist/search/search-service.js +319 -0
- package/dist/search/search-service.js.map +1 -0
- package/dist/setup/backfill-service.d.ts +33 -0
- package/dist/setup/backfill-service.js +47 -0
- package/dist/setup/backfill-service.js.map +1 -0
- package/dist/setup/setup-service.d.ts +65 -0
- package/dist/setup/setup-service.js +90 -0
- package/dist/setup/setup-service.js.map +1 -0
- package/dist/setup/uninstall-service.d.ts +34 -0
- package/dist/setup/uninstall-service.js +91 -0
- package/dist/setup/uninstall-service.js.map +1 -0
- package/dist/state/sqlite-store.d.ts +19 -0
- package/dist/state/sqlite-store.js +299 -0
- package/dist/state/sqlite-store.js.map +1 -0
- package/dist/state/store.d.ts +52 -0
- package/dist/state/store.js +2 -0
- package/dist/state/store.js.map +1 -0
- package/dist/status/status-service.d.ts +38 -0
- package/dist/status/status-service.js +93 -0
- package/dist/status/status-service.js.map +1 -0
- package/dist/update/update-check-service.d.ts +38 -0
- package/dist/update/update-check-service.js +105 -0
- package/dist/update/update-check-service.js.map +1 -0
- package/dist/upload/lock.d.ts +7 -0
- package/dist/upload/lock.js +68 -0
- package/dist/upload/lock.js.map +1 -0
- package/dist/upload/upload-service.d.ts +36 -0
- package/dist/upload/upload-service.js +360 -0
- package/dist/upload/upload-service.js.map +1 -0
- package/package.json +82 -0
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { stat } from "node:fs/promises";
|
|
2
|
+
import { dirname, join } from "node:path";
|
|
3
|
+
import fg from "fast-glob";
|
|
4
|
+
import { parseClaudeSession } from "./claude.js";
|
|
5
|
+
import { parseCodexSession } from "./codex.js";
|
|
6
|
+
import { parseGrokSession } from "./grok.js";
|
|
7
|
+
const emptyStatus = () => ({
|
|
8
|
+
discovered: 0,
|
|
9
|
+
captured: 0,
|
|
10
|
+
skippedSubagents: 0,
|
|
11
|
+
malformed: 0,
|
|
12
|
+
errors: 0,
|
|
13
|
+
});
|
|
14
|
+
async function globFiles(patterns) {
|
|
15
|
+
return fg(patterns, {
|
|
16
|
+
absolute: true,
|
|
17
|
+
onlyFiles: true,
|
|
18
|
+
unique: true,
|
|
19
|
+
followSymbolicLinks: false,
|
|
20
|
+
suppressErrors: true,
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
async function incrementalFiles(paths, modifiedAfter, includePaths, sourcePath = (path) => path) {
|
|
24
|
+
if (!modifiedAfter)
|
|
25
|
+
return paths;
|
|
26
|
+
const candidates = await Promise.all(paths.map(async (path) => {
|
|
27
|
+
if (includePaths.has(path) || includePaths.has(sourcePath(path)))
|
|
28
|
+
return path;
|
|
29
|
+
try {
|
|
30
|
+
return (await stat(path)).mtime.toISOString() > modifiedAfter
|
|
31
|
+
? path
|
|
32
|
+
: null;
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
return path;
|
|
36
|
+
}
|
|
37
|
+
}));
|
|
38
|
+
return candidates.filter((path) => path !== null);
|
|
39
|
+
}
|
|
40
|
+
export async function discoverSessions(options) {
|
|
41
|
+
const status = {
|
|
42
|
+
claude: emptyStatus(),
|
|
43
|
+
codex: emptyStatus(),
|
|
44
|
+
grok: emptyStatus(),
|
|
45
|
+
};
|
|
46
|
+
const output = {
|
|
47
|
+
sessions: [],
|
|
48
|
+
skippedSubagents: 0,
|
|
49
|
+
malformed: 0,
|
|
50
|
+
warnings: [],
|
|
51
|
+
status,
|
|
52
|
+
};
|
|
53
|
+
const parserOptions = {
|
|
54
|
+
device: options.device,
|
|
55
|
+
includeSubagents: options.includeSubagents,
|
|
56
|
+
};
|
|
57
|
+
const includePaths = new Set(options.includePaths ?? []);
|
|
58
|
+
const work = [];
|
|
59
|
+
if (options.sources.includes("claude-code")) {
|
|
60
|
+
const paths = await incrementalFiles(await globFiles(options.paths.claude.map((root) => join(root, "**", "*.jsonl"))), options.modifiedAfter?.["claude-code"], includePaths);
|
|
61
|
+
status.claude.discovered = paths.length;
|
|
62
|
+
work.push(...paths.map((path) => ({
|
|
63
|
+
name: "claude",
|
|
64
|
+
path,
|
|
65
|
+
parse: () => parseClaudeSession(path, parserOptions),
|
|
66
|
+
})));
|
|
67
|
+
}
|
|
68
|
+
if (options.sources.includes("codex")) {
|
|
69
|
+
const paths = await incrementalFiles(await globFiles(options.paths.codex.map((root) => join(root, "**", "rollout-*.jsonl"))), options.modifiedAfter?.codex, includePaths);
|
|
70
|
+
status.codex.discovered = paths.length;
|
|
71
|
+
work.push(...paths.map((path) => ({
|
|
72
|
+
name: "codex",
|
|
73
|
+
path,
|
|
74
|
+
parse: () => parseCodexSession(path, parserOptions),
|
|
75
|
+
})));
|
|
76
|
+
}
|
|
77
|
+
if (options.sources.includes("grok-build")) {
|
|
78
|
+
const histories = await incrementalFiles(await globFiles(options.paths.grok.map((root) => join(root, "**", "chat_history.jsonl"))), options.modifiedAfter?.["grok-build"], includePaths, dirname);
|
|
79
|
+
status.grok.discovered = histories.length;
|
|
80
|
+
work.push(...histories.map((path) => ({
|
|
81
|
+
name: "grok",
|
|
82
|
+
path: dirname(path),
|
|
83
|
+
parse: () => parseGrokSession(dirname(path), parserOptions),
|
|
84
|
+
})));
|
|
85
|
+
}
|
|
86
|
+
for (const item of work) {
|
|
87
|
+
try {
|
|
88
|
+
const result = await item.parse();
|
|
89
|
+
status[item.name].malformed += result.malformedLines;
|
|
90
|
+
output.malformed += result.malformedLines;
|
|
91
|
+
if (result.skippedSubagent) {
|
|
92
|
+
status[item.name].skippedSubagents += 1;
|
|
93
|
+
output.skippedSubagents += 1;
|
|
94
|
+
}
|
|
95
|
+
if (result.session) {
|
|
96
|
+
status[item.name].captured += 1;
|
|
97
|
+
output.sessions.push(result.session);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
catch {
|
|
101
|
+
status[item.name].errors += 1;
|
|
102
|
+
output.warnings.push({
|
|
103
|
+
code: "SOURCE_PARSE_FAILED",
|
|
104
|
+
message: `${item.name} session could not be parsed: ${item.path}`,
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
output.sessions.sort((left, right) => left.updatedAt.localeCompare(right.updatedAt));
|
|
109
|
+
return output;
|
|
110
|
+
}
|
|
111
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/adapters/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { readFile } from "node:fs/promises";
|
|
2
|
+
export async function readJsonLines(path) {
|
|
3
|
+
const input = await readFile(path, "utf8");
|
|
4
|
+
const records = [];
|
|
5
|
+
let malformedLines = 0;
|
|
6
|
+
for (const line of input.split(/\r?\n/u)) {
|
|
7
|
+
if (!line.trim())
|
|
8
|
+
continue;
|
|
9
|
+
try {
|
|
10
|
+
records.push(JSON.parse(line));
|
|
11
|
+
}
|
|
12
|
+
catch {
|
|
13
|
+
malformedLines += 1;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
return { records, malformedLines };
|
|
17
|
+
}
|
|
18
|
+
export function asRecord(value) {
|
|
19
|
+
return value !== null && typeof value === "object" && !Array.isArray(value)
|
|
20
|
+
? value
|
|
21
|
+
: null;
|
|
22
|
+
}
|
|
23
|
+
export function asString(value) {
|
|
24
|
+
return typeof value === "string" && value.length > 0 ? value : null;
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=jsonl.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jsonl.js","sourceRoot":"","sources":["../../src/adapters/jsonl.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAE5C,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,IAAY;IAEZ,MAAM,KAAK,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IAC3C,MAAM,OAAO,GAAc,EAAE,CAAC;IAC9B,IAAI,cAAc,GAAG,CAAC,CAAC;IAEvB,KAAK,MAAM,IAAI,IAAI,KAAK,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC;QACzC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE;YAAE,SAAS;QAC3B,IAAI,CAAC;YACH,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAY,CAAC,CAAC;QAC5C,CAAC;QAAC,MAAM,CAAC;YACP,cAAc,IAAI,CAAC,CAAC;QACtB,CAAC;IACH,CAAC;IAED,OAAO,EAAE,OAAO,EAAE,cAAc,EAAE,CAAC;AACrC,CAAC;AAED,MAAM,UAAU,QAAQ,CAAC,KAAc;IACrC,OAAO,KAAK,KAAK,IAAI,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QACzE,CAAC,CAAE,KAAiC;QACpC,CAAC,CAAC,IAAI,CAAC;AACX,CAAC;AAED,MAAM,UAAU,QAAQ,CAAC,KAAc;IACrC,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC;AACtE,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { NormalizedSession } from "../domain/session.js";
|
|
2
|
+
export interface AdapterOptions {
|
|
3
|
+
device: string;
|
|
4
|
+
includeSubagents: boolean;
|
|
5
|
+
}
|
|
6
|
+
export interface AdapterResult {
|
|
7
|
+
session: NormalizedSession | null;
|
|
8
|
+
skippedSubagent: boolean;
|
|
9
|
+
malformedLines: number;
|
|
10
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/adapters/types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import type { BrainHubConfig } from "../domain/config.js";
|
|
2
|
+
import type { GoogleDriveAccount } from "./google-account.js";
|
|
3
|
+
export declare function resolveGoogleAccountStatus(options: {
|
|
4
|
+
config: BrainHubConfig;
|
|
5
|
+
credential: string | null;
|
|
6
|
+
loadAccount: () => Promise<GoogleDriveAccount>;
|
|
7
|
+
}): Promise<{
|
|
8
|
+
drive: {
|
|
9
|
+
rootFolderName: string;
|
|
10
|
+
rootFolderId?: string;
|
|
11
|
+
configured: boolean;
|
|
12
|
+
};
|
|
13
|
+
configuredAccount?: {
|
|
14
|
+
email: string;
|
|
15
|
+
displayName: string;
|
|
16
|
+
};
|
|
17
|
+
authenticated: false;
|
|
18
|
+
reason: "missing_credential";
|
|
19
|
+
} | {
|
|
20
|
+
identityMatches: boolean;
|
|
21
|
+
drive: {
|
|
22
|
+
rootFolderName: string;
|
|
23
|
+
rootFolderId?: string;
|
|
24
|
+
configured: boolean;
|
|
25
|
+
};
|
|
26
|
+
configuredAccount?: {
|
|
27
|
+
email: string;
|
|
28
|
+
displayName: string;
|
|
29
|
+
};
|
|
30
|
+
authenticated: true;
|
|
31
|
+
account: {
|
|
32
|
+
email: string;
|
|
33
|
+
displayName: string;
|
|
34
|
+
};
|
|
35
|
+
} | {
|
|
36
|
+
drive: {
|
|
37
|
+
rootFolderName: string;
|
|
38
|
+
rootFolderId?: string;
|
|
39
|
+
configured: boolean;
|
|
40
|
+
};
|
|
41
|
+
configuredAccount?: {
|
|
42
|
+
email: string;
|
|
43
|
+
displayName: string;
|
|
44
|
+
};
|
|
45
|
+
authenticated: false;
|
|
46
|
+
reason: "invalid_credential";
|
|
47
|
+
}>;
|
|
48
|
+
export declare function resolveReusableGoogleAccount(options: Parameters<typeof resolveGoogleAccountStatus>[0]): Promise<{
|
|
49
|
+
email: string;
|
|
50
|
+
} | null>;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
function configuredAccount(config) {
|
|
2
|
+
if (!config.drive.accountEmail || !config.drive.accountDisplayName) {
|
|
3
|
+
return undefined;
|
|
4
|
+
}
|
|
5
|
+
return {
|
|
6
|
+
email: config.drive.accountEmail,
|
|
7
|
+
displayName: config.drive.accountDisplayName,
|
|
8
|
+
};
|
|
9
|
+
}
|
|
10
|
+
function driveStatus(config) {
|
|
11
|
+
return {
|
|
12
|
+
configured: Boolean(config.drive.rootFolderId),
|
|
13
|
+
...(config.drive.rootFolderId
|
|
14
|
+
? { rootFolderId: config.drive.rootFolderId }
|
|
15
|
+
: {}),
|
|
16
|
+
rootFolderName: config.drive.rootFolderName,
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
export async function resolveGoogleAccountStatus(options) {
|
|
20
|
+
const configured = configuredAccount(options.config);
|
|
21
|
+
const drive = driveStatus(options.config);
|
|
22
|
+
if (!options.credential) {
|
|
23
|
+
return {
|
|
24
|
+
authenticated: false,
|
|
25
|
+
reason: "missing_credential",
|
|
26
|
+
...(configured ? { configuredAccount: configured } : {}),
|
|
27
|
+
drive,
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
try {
|
|
31
|
+
const account = await options.loadAccount();
|
|
32
|
+
return {
|
|
33
|
+
authenticated: true,
|
|
34
|
+
account: { email: account.email, displayName: account.displayName },
|
|
35
|
+
...(configured ? { configuredAccount: configured } : {}),
|
|
36
|
+
identityMatches: Boolean(options.config.drive.accountPermissionId) &&
|
|
37
|
+
options.config.drive.accountPermissionId === account.permissionId,
|
|
38
|
+
drive,
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
catch {
|
|
42
|
+
return {
|
|
43
|
+
authenticated: false,
|
|
44
|
+
reason: "invalid_credential",
|
|
45
|
+
...(configured ? { configuredAccount: configured } : {}),
|
|
46
|
+
drive,
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
export async function resolveReusableGoogleAccount(options) {
|
|
51
|
+
const status = await resolveGoogleAccountStatus(options);
|
|
52
|
+
if (!status.authenticated ||
|
|
53
|
+
!status.identityMatches ||
|
|
54
|
+
!status.drive.configured) {
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
return { email: status.account.email };
|
|
58
|
+
}
|
|
59
|
+
//# sourceMappingURL=account-status.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"account-status.js","sourceRoot":"","sources":["../../src/auth/account-status.ts"],"names":[],"mappings":"AAGA,SAAS,iBAAiB,CAAC,MAAsB;IAC/C,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,YAAY,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,kBAAkB,EAAE,CAAC;QACnE,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,OAAO;QACL,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC,YAAY;QAChC,WAAW,EAAE,MAAM,CAAC,KAAK,CAAC,kBAAkB;KAC7C,CAAC;AACJ,CAAC;AAED,SAAS,WAAW,CAAC,MAAsB;IACzC,OAAO;QACL,UAAU,EAAE,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,YAAY,CAAC;QAC9C,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,YAAY;YAC3B,CAAC,CAAC,EAAE,YAAY,EAAE,MAAM,CAAC,KAAK,CAAC,YAAY,EAAE;YAC7C,CAAC,CAAC,EAAE,CAAC;QACP,cAAc,EAAE,MAAM,CAAC,KAAK,CAAC,cAAc;KAC5C,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,0BAA0B,CAAC,OAIhD;IACC,MAAM,UAAU,GAAG,iBAAiB,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IACrD,MAAM,KAAK,GAAG,WAAW,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IAC1C,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE,CAAC;QACxB,OAAO;YACL,aAAa,EAAE,KAAc;YAC7B,MAAM,EAAE,oBAA6B;YACrC,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,iBAAiB,EAAE,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACxD,KAAK;SACN,CAAC;IACJ,CAAC;IACD,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,WAAW,EAAE,CAAC;QAC5C,OAAO;YACL,aAAa,EAAE,IAAa;YAC5B,OAAO,EAAE,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,WAAW,EAAE,OAAO,CAAC,WAAW,EAAE;YACnE,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,iBAAiB,EAAE,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACxD,eAAe,EACb,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,mBAAmB,CAAC;gBACjD,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,mBAAmB,KAAK,OAAO,CAAC,YAAY;YACnE,KAAK;SACN,CAAC;IACJ,CAAC;IAAC,MAAM,CAAC;QACP,OAAO;YACL,aAAa,EAAE,KAAc;YAC7B,MAAM,EAAE,oBAA6B;YACrC,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,iBAAiB,EAAE,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACxD,KAAK;SACN,CAAC;IACJ,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,4BAA4B,CAChD,OAAyD;IAEzD,MAAM,MAAM,GAAG,MAAM,0BAA0B,CAAC,OAAO,CAAC,CAAC;IACzD,IACE,CAAC,MAAM,CAAC,aAAa;QACrB,CAAC,MAAM,CAAC,eAAe;QACvB,CAAC,MAAM,CAAC,KAAK,CAAC,UAAU,EACxB,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IACD,OAAO,EAAE,KAAK,EAAE,MAAM,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;AACzC,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { drive_v3 } from "googleapis";
|
|
2
|
+
import type { BrainHubConfig } from "../domain/config.js";
|
|
3
|
+
import type { GoogleOAuthClient } from "./google-oauth.js";
|
|
4
|
+
export interface GoogleDriveAccount {
|
|
5
|
+
email: string;
|
|
6
|
+
displayName: string;
|
|
7
|
+
permissionId: string;
|
|
8
|
+
}
|
|
9
|
+
export interface GoogleAccountConnection {
|
|
10
|
+
account: GoogleDriveAccount;
|
|
11
|
+
rootFolderId: string;
|
|
12
|
+
}
|
|
13
|
+
export declare function readGoogleDriveAccount(client: drive_v3.Drive): Promise<GoogleDriveAccount>;
|
|
14
|
+
export declare function connectGoogleAccount(options: {
|
|
15
|
+
authClient: GoogleOAuthClient;
|
|
16
|
+
drive: (auth: GoogleOAuthClient) => drive_v3.Drive;
|
|
17
|
+
rootFolderName: string;
|
|
18
|
+
rootFolderId?: string;
|
|
19
|
+
}): Promise<GoogleAccountConnection>;
|
|
20
|
+
export declare function applyGoogleConnection(config: BrainHubConfig, connection: GoogleAccountConnection): BrainHubConfig;
|
|
21
|
+
export declare function clearGoogleConnection(config: BrainHubConfig): BrainHubConfig;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { BrainHubError } from "../domain/errors.js";
|
|
2
|
+
import { GoogleDrive } from "../drive/google-drive.js";
|
|
3
|
+
export async function readGoogleDriveAccount(client) {
|
|
4
|
+
const response = await client.about.get({
|
|
5
|
+
fields: "user(displayName,emailAddress,permissionId)",
|
|
6
|
+
});
|
|
7
|
+
const email = response.data.user?.emailAddress?.trim();
|
|
8
|
+
const displayName = response.data.user?.displayName?.trim();
|
|
9
|
+
const permissionId = response.data.user?.permissionId?.trim();
|
|
10
|
+
if (!email || !displayName || !permissionId) {
|
|
11
|
+
throw new BrainHubError("AUTH_ACCOUNT_UNAVAILABLE", "Google Drive did not return a complete account identity");
|
|
12
|
+
}
|
|
13
|
+
return { email, displayName, permissionId };
|
|
14
|
+
}
|
|
15
|
+
export async function connectGoogleAccount(options) {
|
|
16
|
+
const client = options.drive(options.authClient);
|
|
17
|
+
const account = await readGoogleDriveAccount(client);
|
|
18
|
+
const rootFolderId = await GoogleDrive.createRoot(client, options.rootFolderName, options.rootFolderId);
|
|
19
|
+
return { account, rootFolderId };
|
|
20
|
+
}
|
|
21
|
+
export function applyGoogleConnection(config, connection) {
|
|
22
|
+
return {
|
|
23
|
+
...config,
|
|
24
|
+
drive: {
|
|
25
|
+
...config.drive,
|
|
26
|
+
rootFolderId: connection.rootFolderId,
|
|
27
|
+
accountEmail: connection.account.email,
|
|
28
|
+
accountDisplayName: connection.account.displayName,
|
|
29
|
+
accountPermissionId: connection.account.permissionId,
|
|
30
|
+
},
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
export function clearGoogleConnection(config) {
|
|
34
|
+
return {
|
|
35
|
+
...config,
|
|
36
|
+
drive: {
|
|
37
|
+
...config.drive,
|
|
38
|
+
rootFolderId: "",
|
|
39
|
+
accountEmail: "",
|
|
40
|
+
accountDisplayName: "",
|
|
41
|
+
accountPermissionId: "",
|
|
42
|
+
},
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=google-account.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"google-account.js","sourceRoot":"","sources":["../../src/auth/google-account.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAcvD,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAC1C,MAAsB;IAEtB,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC;QACtC,MAAM,EAAE,6CAA6C;KACtD,CAAC,CAAC;IACH,MAAM,KAAK,GAAG,QAAQ,CAAC,IAAI,CAAC,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC;IACvD,MAAM,WAAW,GAAG,QAAQ,CAAC,IAAI,CAAC,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC;IAC5D,MAAM,YAAY,GAAG,QAAQ,CAAC,IAAI,CAAC,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC;IAC9D,IAAI,CAAC,KAAK,IAAI,CAAC,WAAW,IAAI,CAAC,YAAY,EAAE,CAAC;QAC5C,MAAM,IAAI,aAAa,CACrB,0BAA0B,EAC1B,yDAAyD,CAC1D,CAAC;IACJ,CAAC;IACD,OAAO,EAAE,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,CAAC;AAC9C,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,oBAAoB,CAAC,OAK1C;IACC,MAAM,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;IACjD,MAAM,OAAO,GAAG,MAAM,sBAAsB,CAAC,MAAM,CAAC,CAAC;IACrD,MAAM,YAAY,GAAG,MAAM,WAAW,CAAC,UAAU,CAC/C,MAAM,EACN,OAAO,CAAC,cAAc,EACtB,OAAO,CAAC,YAAY,CACrB,CAAC;IACF,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,CAAC;AACnC,CAAC;AAED,MAAM,UAAU,qBAAqB,CACnC,MAAsB,EACtB,UAAmC;IAEnC,OAAO;QACL,GAAG,MAAM;QACT,KAAK,EAAE;YACL,GAAG,MAAM,CAAC,KAAK;YACf,YAAY,EAAE,UAAU,CAAC,YAAY;YACrC,YAAY,EAAE,UAAU,CAAC,OAAO,CAAC,KAAK;YACtC,kBAAkB,EAAE,UAAU,CAAC,OAAO,CAAC,WAAW;YAClD,mBAAmB,EAAE,UAAU,CAAC,OAAO,CAAC,YAAY;SACrD;KACF,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,qBAAqB,CAAC,MAAsB;IAC1D,OAAO;QACL,GAAG,MAAM;QACT,KAAK,EAAE;YACL,GAAG,MAAM,CAAC,KAAK;YACf,YAAY,EAAE,EAAE;YAChB,YAAY,EAAE,EAAE;YAChB,kBAAkB,EAAE,EAAE;YACtB,mBAAmB,EAAE,EAAE;SACxB;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { google } from "googleapis";
|
|
2
|
+
import { type OAuthLoopbackSession } from "./oauth-loopback.js";
|
|
3
|
+
import type { SecretStore } from "./secret-store.js";
|
|
4
|
+
export declare const GOOGLE_DRIVE_SCOPE = "https://www.googleapis.com/auth/drive";
|
|
5
|
+
export type GoogleOAuthClient = InstanceType<typeof google.auth.OAuth2>;
|
|
6
|
+
type GoogleAuthorizationOptions = NonNullable<Parameters<GoogleOAuthClient["generateAuthUrl"]>[0]>;
|
|
7
|
+
export interface StagedGoogleAuthorization {
|
|
8
|
+
client: GoogleOAuthClient;
|
|
9
|
+
commit(): Promise<void>;
|
|
10
|
+
rollback(): Promise<void>;
|
|
11
|
+
}
|
|
12
|
+
export interface GoogleOAuthDependencies {
|
|
13
|
+
createClient?: (clientId: string, clientSecret: string, redirectUri?: string) => GoogleOAuthClient;
|
|
14
|
+
startLoopback?: (state: string) => Promise<OAuthLoopbackSession>;
|
|
15
|
+
}
|
|
16
|
+
export interface OAuthClientConfig {
|
|
17
|
+
clientId: string;
|
|
18
|
+
clientSecret: string;
|
|
19
|
+
redirectUris: string[];
|
|
20
|
+
}
|
|
21
|
+
export declare function parseOAuthClientConfig(value: unknown): OAuthClientConfig;
|
|
22
|
+
export declare function googleAuthorizationOptions(state: string, codeChallenge: string): GoogleAuthorizationOptions;
|
|
23
|
+
export declare function readOAuthClientConfig(path: string, bundled?: OAuthClientConfig): Promise<OAuthClientConfig>;
|
|
24
|
+
export declare function revokeGoogleCredential(serialized: string, fetcher?: typeof fetch): Promise<boolean>;
|
|
25
|
+
export declare class GoogleOAuth {
|
|
26
|
+
#private;
|
|
27
|
+
readonly clientFile: string;
|
|
28
|
+
readonly secrets: SecretStore;
|
|
29
|
+
constructor(clientFile: string, secrets: SecretStore, dependencies?: GoogleOAuthDependencies);
|
|
30
|
+
getClient(options: {
|
|
31
|
+
interactive: boolean;
|
|
32
|
+
}): Promise<GoogleOAuthClient>;
|
|
33
|
+
beginInteractiveAuthorization(): Promise<StagedGoogleAuthorization>;
|
|
34
|
+
}
|
|
35
|
+
export {};
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
import { randomBytes } from "node:crypto";
|
|
2
|
+
import { readFile } from "node:fs/promises";
|
|
3
|
+
import { google } from "googleapis";
|
|
4
|
+
import { BrainHubError } from "../domain/errors.js";
|
|
5
|
+
import { BUNDLED_GOOGLE_OAUTH_CLIENT } from "./official-oauth-client.js";
|
|
6
|
+
import { startOAuthLoopback, } from "./oauth-loopback.js";
|
|
7
|
+
export const GOOGLE_DRIVE_SCOPE = "https://www.googleapis.com/auth/drive";
|
|
8
|
+
export function parseOAuthClientConfig(value) {
|
|
9
|
+
const root = value && typeof value === "object"
|
|
10
|
+
? value
|
|
11
|
+
: {};
|
|
12
|
+
const candidate = (root.installed ?? root.web);
|
|
13
|
+
const clientId = candidate?.client_id;
|
|
14
|
+
const clientSecret = candidate?.client_secret;
|
|
15
|
+
const redirectUris = candidate?.redirect_uris;
|
|
16
|
+
if (typeof clientId !== "string" ||
|
|
17
|
+
typeof clientSecret !== "string" ||
|
|
18
|
+
!Array.isArray(redirectUris) ||
|
|
19
|
+
!redirectUris.every((uri) => typeof uri === "string")) {
|
|
20
|
+
throw new Error("OAuth client file is incomplete");
|
|
21
|
+
}
|
|
22
|
+
return { clientId, clientSecret, redirectUris };
|
|
23
|
+
}
|
|
24
|
+
export function googleAuthorizationOptions(state, codeChallenge) {
|
|
25
|
+
return {
|
|
26
|
+
access_type: "offline",
|
|
27
|
+
prompt: "select_account consent",
|
|
28
|
+
scope: [GOOGLE_DRIVE_SCOPE],
|
|
29
|
+
state,
|
|
30
|
+
code_challenge: codeChallenge,
|
|
31
|
+
code_challenge_method: "S256",
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
export async function readOAuthClientConfig(path, bundled = BUNDLED_GOOGLE_OAUTH_CLIENT) {
|
|
35
|
+
if (!path) {
|
|
36
|
+
if (bundled.clientId.endsWith(".apps.googleusercontent.com") &&
|
|
37
|
+
!bundled.clientId.startsWith("__") &&
|
|
38
|
+
bundled.clientSecret.length > 0 &&
|
|
39
|
+
!bundled.clientSecret.startsWith("__") &&
|
|
40
|
+
bundled.redirectUris.length > 0) {
|
|
41
|
+
return bundled;
|
|
42
|
+
}
|
|
43
|
+
throw new BrainHubError("AUTH_REQUIRED", "Official Google OAuth client is missing from this build; source builds must configure BRAINHUB_GOOGLE_OAUTH_CLIENT_FILE");
|
|
44
|
+
}
|
|
45
|
+
try {
|
|
46
|
+
return parseOAuthClientConfig(JSON.parse(await readFile(path, "utf8")));
|
|
47
|
+
}
|
|
48
|
+
catch (error) {
|
|
49
|
+
if (error instanceof BrainHubError)
|
|
50
|
+
throw error;
|
|
51
|
+
throw new BrainHubError("AUTH_REQUIRED", "Unable to read a valid Google OAuth client file");
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
export async function revokeGoogleCredential(serialized, fetcher = fetch) {
|
|
55
|
+
let credentials;
|
|
56
|
+
try {
|
|
57
|
+
credentials = JSON.parse(serialized);
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
return false;
|
|
61
|
+
}
|
|
62
|
+
const token = typeof credentials.refresh_token === "string"
|
|
63
|
+
? credentials.refresh_token
|
|
64
|
+
: typeof credentials.access_token === "string"
|
|
65
|
+
? credentials.access_token
|
|
66
|
+
: null;
|
|
67
|
+
if (!token)
|
|
68
|
+
return false;
|
|
69
|
+
const response = await fetcher("https://oauth2.googleapis.com/revoke", {
|
|
70
|
+
method: "POST",
|
|
71
|
+
headers: { "content-type": "application/x-www-form-urlencoded" },
|
|
72
|
+
body: new URLSearchParams({ token }),
|
|
73
|
+
});
|
|
74
|
+
if (!response.ok) {
|
|
75
|
+
throw new Error(`Google OAuth revocation failed with ${response.status}`);
|
|
76
|
+
}
|
|
77
|
+
return true;
|
|
78
|
+
}
|
|
79
|
+
export class GoogleOAuth {
|
|
80
|
+
clientFile;
|
|
81
|
+
secrets;
|
|
82
|
+
#createClient;
|
|
83
|
+
#startLoopback;
|
|
84
|
+
constructor(clientFile, secrets, dependencies = {}) {
|
|
85
|
+
this.clientFile = clientFile;
|
|
86
|
+
this.secrets = secrets;
|
|
87
|
+
this.#createClient =
|
|
88
|
+
dependencies.createClient ??
|
|
89
|
+
((clientId, clientSecret, redirectUri) => new google.auth.OAuth2(clientId, clientSecret, redirectUri));
|
|
90
|
+
this.#startLoopback = dependencies.startLoopback ?? startOAuthLoopback;
|
|
91
|
+
}
|
|
92
|
+
async getClient(options) {
|
|
93
|
+
const config = await readOAuthClientConfig(this.clientFile);
|
|
94
|
+
const stored = await this.secrets.get();
|
|
95
|
+
if (!stored) {
|
|
96
|
+
if (!options.interactive) {
|
|
97
|
+
throw new BrainHubError("AUTH_REQUIRED", "Google Drive authentication is required");
|
|
98
|
+
}
|
|
99
|
+
const staged = await this.#authorizeInteractive(config, null);
|
|
100
|
+
await staged.commit();
|
|
101
|
+
return staged.client;
|
|
102
|
+
}
|
|
103
|
+
const client = this.#createClient(config.clientId, config.clientSecret);
|
|
104
|
+
try {
|
|
105
|
+
const credentials = JSON.parse(stored);
|
|
106
|
+
if (!credentials.refresh_token)
|
|
107
|
+
throw new Error("refresh token missing");
|
|
108
|
+
client.setCredentials(credentials);
|
|
109
|
+
this.#persistNewTokens(client, credentials);
|
|
110
|
+
await client.getAccessToken();
|
|
111
|
+
return client;
|
|
112
|
+
}
|
|
113
|
+
catch {
|
|
114
|
+
if (!options.interactive) {
|
|
115
|
+
throw new BrainHubError("AUTH_REQUIRED", "Stored Google authentication is invalid");
|
|
116
|
+
}
|
|
117
|
+
const staged = await this.#authorizeInteractive(config, stored);
|
|
118
|
+
await staged.commit();
|
|
119
|
+
return staged.client;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
#persistNewTokens(client, base) {
|
|
123
|
+
client.on("tokens", (tokens) => {
|
|
124
|
+
void this.secrets
|
|
125
|
+
.set(JSON.stringify({ ...base, ...tokens }))
|
|
126
|
+
.catch(() => undefined);
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
async beginInteractiveAuthorization() {
|
|
130
|
+
const config = await readOAuthClientConfig(this.clientFile);
|
|
131
|
+
const previousCredential = await this.secrets.get();
|
|
132
|
+
return this.#authorizeInteractive(config, previousCredential);
|
|
133
|
+
}
|
|
134
|
+
async #authorizeInteractive(config, previousCredential) {
|
|
135
|
+
const state = randomBytes(24).toString("hex");
|
|
136
|
+
const loopback = await this.#startLoopback(state);
|
|
137
|
+
const client = this.#createClient(config.clientId, config.clientSecret, loopback.redirectUri);
|
|
138
|
+
try {
|
|
139
|
+
const { codeVerifier, codeChallenge } = await client.generateCodeVerifierAsync();
|
|
140
|
+
if (!codeChallenge)
|
|
141
|
+
throw new Error("Unable to generate PKCE challenge");
|
|
142
|
+
const authorizationUrl = client.generateAuthUrl(googleAuthorizationOptions(state, codeChallenge));
|
|
143
|
+
const code = await loopback.authorize(authorizationUrl);
|
|
144
|
+
const { tokens } = await client.getToken({ code, codeVerifier });
|
|
145
|
+
if (!tokens.refresh_token)
|
|
146
|
+
throw new Error("Google did not return a refresh token");
|
|
147
|
+
client.setCredentials(tokens);
|
|
148
|
+
let pending = tokens;
|
|
149
|
+
let active = true;
|
|
150
|
+
let committed = false;
|
|
151
|
+
let commitAttempted = false;
|
|
152
|
+
client.on("tokens", (newTokens) => {
|
|
153
|
+
pending = { ...pending, ...newTokens };
|
|
154
|
+
if (active && committed) {
|
|
155
|
+
void this.secrets.set(JSON.stringify(pending)).catch(() => undefined);
|
|
156
|
+
}
|
|
157
|
+
});
|
|
158
|
+
return {
|
|
159
|
+
client,
|
|
160
|
+
commit: async () => {
|
|
161
|
+
if (!active)
|
|
162
|
+
throw new Error("OAuth authorization was rolled back");
|
|
163
|
+
if (committed)
|
|
164
|
+
return;
|
|
165
|
+
commitAttempted = true;
|
|
166
|
+
const serialized = JSON.stringify(pending);
|
|
167
|
+
await this.secrets.set(serialized);
|
|
168
|
+
committed = true;
|
|
169
|
+
const latest = JSON.stringify(pending);
|
|
170
|
+
if (latest !== serialized)
|
|
171
|
+
await this.secrets.set(latest);
|
|
172
|
+
},
|
|
173
|
+
rollback: async () => {
|
|
174
|
+
if (!active)
|
|
175
|
+
return;
|
|
176
|
+
active = false;
|
|
177
|
+
if (!commitAttempted && !committed)
|
|
178
|
+
return;
|
|
179
|
+
if (previousCredential)
|
|
180
|
+
await this.secrets.set(previousCredential);
|
|
181
|
+
else
|
|
182
|
+
await this.secrets.delete();
|
|
183
|
+
},
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
finally {
|
|
187
|
+
await loopback.close();
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
//# sourceMappingURL=google-oauth.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"google-oauth.js","sourceRoot":"","sources":["../../src/auth/google-oauth.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAE5C,OAAO,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAEpC,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,2BAA2B,EAAE,MAAM,4BAA4B,CAAC;AACzE,OAAO,EACL,kBAAkB,GAEnB,MAAM,qBAAqB,CAAC;AAG7B,MAAM,CAAC,MAAM,kBAAkB,GAAG,uCAAuC,CAAC;AA6B1E,MAAM,UAAU,sBAAsB,CAAC,KAAc;IACnD,MAAM,IAAI,GACR,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ;QAChC,CAAC,CAAE,KAAiC;QACpC,CAAC,CAAC,EAAE,CAAC;IACT,MAAM,SAAS,GAAG,CAAC,IAAI,CAAC,SAAS,IAAI,IAAI,CAAC,GAAG,CACR,CAAC;IACtC,MAAM,QAAQ,GAAG,SAAS,EAAE,SAAS,CAAC;IACtC,MAAM,YAAY,GAAG,SAAS,EAAE,aAAa,CAAC;IAC9C,MAAM,YAAY,GAAG,SAAS,EAAE,aAAa,CAAC;IAC9C,IACE,OAAO,QAAQ,KAAK,QAAQ;QAC5B,OAAO,YAAY,KAAK,QAAQ;QAChC,CAAC,KAAK,CAAC,OAAO,CAAC,YAAY,CAAC;QAC5B,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,OAAO,GAAG,KAAK,QAAQ,CAAC,EACrD,CAAC;QACD,MAAM,IAAI,KAAK,CAAC,iCAAiC,CAAC,CAAC;IACrD,CAAC;IACD,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,YAAY,EAAE,CAAC;AAClD,CAAC;AAED,MAAM,UAAU,0BAA0B,CACxC,KAAa,EACb,aAAqB;IAErB,OAAO;QACL,WAAW,EAAE,SAAS;QACtB,MAAM,EAAE,wBAAwB;QAChC,KAAK,EAAE,CAAC,kBAAkB,CAAC;QAC3B,KAAK;QACL,cAAc,EAAE,aAAa;QAC7B,qBAAqB,EAAE,MAEtB;KACF,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,qBAAqB,CACzC,IAAY,EACZ,UAA6B,2BAA2B;IAExD,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,IACE,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,6BAA6B,CAAC;YACxD,CAAC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAC,IAAI,CAAC;YAClC,OAAO,CAAC,YAAY,CAAC,MAAM,GAAG,CAAC;YAC/B,CAAC,OAAO,CAAC,YAAY,CAAC,UAAU,CAAC,IAAI,CAAC;YACtC,OAAO,CAAC,YAAY,CAAC,MAAM,GAAG,CAAC,EAC/B,CAAC;YACD,OAAO,OAAO,CAAC;QACjB,CAAC;QACD,MAAM,IAAI,aAAa,CACrB,eAAe,EACf,yHAAyH,CAC1H,CAAC;IACJ,CAAC;IACD,IAAI,CAAC;QACH,OAAO,sBAAsB,CAC3B,IAAI,CAAC,KAAK,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAY,CACpD,CAAC;IACJ,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,KAAK,YAAY,aAAa;YAAE,MAAM,KAAK,CAAC;QAChD,MAAM,IAAI,aAAa,CACrB,eAAe,EACf,iDAAiD,CAClD,CAAC;IACJ,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAC1C,UAAkB,EAClB,UAAwB,KAAK;IAE7B,IAAI,WAAgE,CAAC;IACrE,IAAI,CAAC;QACH,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,UAAU,CAAuB,CAAC;IAC7D,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;IACD,MAAM,KAAK,GACT,OAAO,WAAW,CAAC,aAAa,KAAK,QAAQ;QAC3C,CAAC,CAAC,WAAW,CAAC,aAAa;QAC3B,CAAC,CAAC,OAAO,WAAW,CAAC,YAAY,KAAK,QAAQ;YAC5C,CAAC,CAAC,WAAW,CAAC,YAAY;YAC1B,CAAC,CAAC,IAAI,CAAC;IACb,IAAI,CAAC,KAAK;QAAE,OAAO,KAAK,CAAC;IACzB,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,sCAAsC,EAAE;QACrE,MAAM,EAAE,MAAM;QACd,OAAO,EAAE,EAAE,cAAc,EAAE,mCAAmC,EAAE;QAChE,IAAI,EAAE,IAAI,eAAe,CAAC,EAAE,KAAK,EAAE,CAAC;KACrC,CAAC,CAAC;IACH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;QACjB,MAAM,IAAI,KAAK,CAAC,uCAAuC,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;IAC5E,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,OAAO,WAAW;IAOX;IACA;IAPF,aAAa,CAAuD;IACpE,cAAc,CAErB;IAEF,YACW,UAAkB,EAClB,OAAoB,EAC7B,eAAwC,EAAE;QAFjC,eAAU,GAAV,UAAU,CAAQ;QAClB,YAAO,GAAP,OAAO,CAAa;QAG7B,IAAI,CAAC,aAAa;YAChB,YAAY,CAAC,YAAY;gBACzB,CAAC,CAAC,QAAQ,EAAE,YAAY,EAAE,WAAW,EAAE,EAAE,CACvC,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,YAAY,EAAE,WAAW,CAAC,CAAC,CAAC;QACjE,IAAI,CAAC,cAAc,GAAG,YAAY,CAAC,aAAa,IAAI,kBAAkB,CAAC;IACzE,CAAC;IAED,KAAK,CAAC,SAAS,CAAC,OAEf;QACC,MAAM,MAAM,GAAG,MAAM,qBAAqB,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAC5D,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC;QACxC,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC;gBACzB,MAAM,IAAI,aAAa,CACrB,eAAe,EACf,yCAAyC,CAC1C,CAAC;YACJ,CAAC;YACD,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,qBAAqB,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;YAC9D,MAAM,MAAM,CAAC,MAAM,EAAE,CAAC;YACtB,OAAO,MAAM,CAAC,MAAM,CAAC;QACvB,CAAC;QAED,MAAM,MAAM,GAAG,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC,YAAY,CAAC,CAAC;QACxE,IAAI,CAAC;YACH,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAsB,CAAC;YAC5D,IAAI,CAAC,WAAW,CAAC,aAAa;gBAAE,MAAM,IAAI,KAAK,CAAC,uBAAuB,CAAC,CAAC;YACzE,MAAM,CAAC,cAAc,CAAC,WAAW,CAAC,CAAC;YACnC,IAAI,CAAC,iBAAiB,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;YAC5C,MAAM,MAAM,CAAC,cAAc,EAAE,CAAC;YAC9B,OAAO,MAAM,CAAC;QAChB,CAAC;QAAC,MAAM,CAAC;YACP,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC;gBACzB,MAAM,IAAI,aAAa,CACrB,eAAe,EACf,yCAAyC,CAC1C,CAAC;YACJ,CAAC;YACD,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,qBAAqB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;YAChE,MAAM,MAAM,CAAC,MAAM,EAAE,CAAC;YACtB,OAAO,MAAM,CAAC,MAAM,CAAC;QACvB,CAAC;IACH,CAAC;IAED,iBAAiB,CAAC,MAAyB,EAAE,IAAuB;QAClE,MAAM,CAAC,EAAE,CAAC,QAAQ,EAAE,CAAC,MAAM,EAAE,EAAE;YAC7B,KAAK,IAAI,CAAC,OAAO;iBACd,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,GAAG,IAAI,EAAE,GAAG,MAAM,EAAE,CAAC,CAAC;iBAC3C,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;QAC5B,CAAC,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,6BAA6B;QACjC,MAAM,MAAM,GAAG,MAAM,qBAAqB,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAC5D,MAAM,kBAAkB,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC;QACpD,OAAO,IAAI,CAAC,qBAAqB,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC;IAChE,CAAC;IAED,KAAK,CAAC,qBAAqB,CACzB,MAAyB,EACzB,kBAAiC;QAEjC,MAAM,KAAK,GAAG,WAAW,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;QAC9C,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC;QAClD,MAAM,MAAM,GAAG,IAAI,CAAC,aAAa,CAC/B,MAAM,CAAC,QAAQ,EACf,MAAM,CAAC,YAAY,EACnB,QAAQ,CAAC,WAAW,CACrB,CAAC;QACF,IAAI,CAAC;YACH,MAAM,EAAE,YAAY,EAAE,aAAa,EAAE,GACnC,MAAM,MAAM,CAAC,yBAAyB,EAAE,CAAC;YAC3C,IAAI,CAAC,aAAa;gBAAE,MAAM,IAAI,KAAK,CAAC,mCAAmC,CAAC,CAAC;YACzE,MAAM,gBAAgB,GAAG,MAAM,CAAC,eAAe,CAC7C,0BAA0B,CAAC,KAAK,EAAE,aAAa,CAAC,CACjD,CAAC;YACF,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,SAAS,CAAC,gBAAgB,CAAC,CAAC;YACxD,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,MAAM,CAAC,QAAQ,CAAC,EAAE,IAAI,EAAE,YAAY,EAAE,CAAC,CAAC;YACjE,IAAI,CAAC,MAAM,CAAC,aAAa;gBACvB,MAAM,IAAI,KAAK,CAAC,uCAAuC,CAAC,CAAC;YAC3D,MAAM,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC;YAC9B,IAAI,OAAO,GAAsB,MAAM,CAAC;YACxC,IAAI,MAAM,GAAG,IAAI,CAAC;YAClB,IAAI,SAAS,GAAG,KAAK,CAAC;YACtB,IAAI,eAAe,GAAG,KAAK,CAAC;YAC5B,MAAM,CAAC,EAAE,CAAC,QAAQ,EAAE,CAAC,SAAS,EAAE,EAAE;gBAChC,OAAO,GAAG,EAAE,GAAG,OAAO,EAAE,GAAG,SAAS,EAAE,CAAC;gBACvC,IAAI,MAAM,IAAI,SAAS,EAAE,CAAC;oBACxB,KAAK,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;gBACxE,CAAC;YACH,CAAC,CAAC,CAAC;YACH,OAAO;gBACL,MAAM;gBACN,MAAM,EAAE,KAAK,IAAI,EAAE;oBACjB,IAAI,CAAC,MAAM;wBAAE,MAAM,IAAI,KAAK,CAAC,qCAAqC,CAAC,CAAC;oBACpE,IAAI,SAAS;wBAAE,OAAO;oBACtB,eAAe,GAAG,IAAI,CAAC;oBACvB,MAAM,UAAU,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;oBAC3C,MAAM,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;oBACnC,SAAS,GAAG,IAAI,CAAC;oBACjB,MAAM,MAAM,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;oBACvC,IAAI,MAAM,KAAK,UAAU;wBAAE,MAAM,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;gBAC5D,CAAC;gBACD,QAAQ,EAAE,KAAK,IAAI,EAAE;oBACnB,IAAI,CAAC,MAAM;wBAAE,OAAO;oBACpB,MAAM,GAAG,KAAK,CAAC;oBACf,IAAI,CAAC,eAAe,IAAI,CAAC,SAAS;wBAAE,OAAO;oBAC3C,IAAI,kBAAkB;wBAAE,MAAM,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAC;;wBAC9D,MAAM,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC;gBACnC,CAAC;aACF,CAAC;QACJ,CAAC;gBAAS,CAAC;YACT,MAAM,QAAQ,CAAC,KAAK,EAAE,CAAC;QACzB,CAAC;IACH,CAAC;CACF"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export interface OAuthLoopbackSession {
|
|
2
|
+
redirectUri: string;
|
|
3
|
+
authorize(authorizationUrl: string): Promise<string>;
|
|
4
|
+
close(): Promise<void>;
|
|
5
|
+
}
|
|
6
|
+
export interface OAuthLoopbackOptions {
|
|
7
|
+
openUrl?: (url: string) => Promise<unknown>;
|
|
8
|
+
timeoutMs?: number;
|
|
9
|
+
}
|
|
10
|
+
export declare function startOAuthLoopback(state: string, options?: OAuthLoopbackOptions): Promise<OAuthLoopbackSession>;
|