@framers/agentos 0.1.37 → 0.1.39

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. package/dist/config/extension-secrets.json +38 -0
  2. package/dist/core/llm/auth/BrowserOAuthFlow.d.ts +62 -0
  3. package/dist/core/llm/auth/BrowserOAuthFlow.d.ts.map +1 -0
  4. package/dist/core/llm/auth/BrowserOAuthFlow.js +134 -0
  5. package/dist/core/llm/auth/BrowserOAuthFlow.js.map +1 -0
  6. package/dist/core/llm/auth/FileTokenStore.d.ts.map +1 -1
  7. package/dist/core/llm/auth/FileTokenStore.js +1 -0
  8. package/dist/core/llm/auth/FileTokenStore.js.map +1 -1
  9. package/dist/core/llm/auth/InstagramOAuthFlow.d.ts +40 -0
  10. package/dist/core/llm/auth/InstagramOAuthFlow.d.ts.map +1 -0
  11. package/dist/core/llm/auth/InstagramOAuthFlow.js +143 -0
  12. package/dist/core/llm/auth/InstagramOAuthFlow.js.map +1 -0
  13. package/dist/core/llm/auth/TwitterOAuthFlow.d.ts +26 -0
  14. package/dist/core/llm/auth/TwitterOAuthFlow.d.ts.map +1 -0
  15. package/dist/core/llm/auth/TwitterOAuthFlow.js +86 -0
  16. package/dist/core/llm/auth/TwitterOAuthFlow.js.map +1 -0
  17. package/dist/core/llm/auth/callback-server.d.ts +32 -0
  18. package/dist/core/llm/auth/callback-server.d.ts.map +1 -0
  19. package/dist/core/llm/auth/callback-server.js +111 -0
  20. package/dist/core/llm/auth/callback-server.js.map +1 -0
  21. package/dist/core/llm/auth/index.d.ts +10 -0
  22. package/dist/core/llm/auth/index.d.ts.map +1 -1
  23. package/dist/core/llm/auth/index.js +8 -0
  24. package/dist/core/llm/auth/index.js.map +1 -1
  25. package/dist/core/llm/auth/pkce.d.ts +18 -0
  26. package/dist/core/llm/auth/pkce.d.ts.map +1 -0
  27. package/dist/core/llm/auth/pkce.js +25 -0
  28. package/dist/core/llm/auth/pkce.js.map +1 -0
  29. package/dist/core/llm/auth/types.d.ts +2 -0
  30. package/dist/core/llm/auth/types.d.ts.map +1 -1
  31. package/dist/core/llm/auth/utils.d.ts +16 -0
  32. package/dist/core/llm/auth/utils.d.ts.map +1 -0
  33. package/dist/core/llm/auth/utils.js +38 -0
  34. package/dist/core/llm/auth/utils.js.map +1 -0
  35. package/package.json +1 -1
@@ -840,5 +840,43 @@
840
840
  "docsUrl": "https://modern.ircdocs.horse/",
841
841
  "providers": ["irc"],
842
842
  "optional": true
843
+ },
844
+ {
845
+ "id": "github.token",
846
+ "label": "GitHub Personal Access Token",
847
+ "description": "PAT for GitHub API access. Used by the GitHub extension for repo search, issues, PRs, and gists.",
848
+ "envVar": "GITHUB_TOKEN",
849
+ "docsUrl": "https://github.com/settings/tokens",
850
+ "providers": ["github"],
851
+ "optional": true
852
+ },
853
+ {
854
+ "id": "twitter.clientId",
855
+ "label": "Twitter/X OAuth 2.0 Client ID",
856
+ "description": "Client ID for Twitter OAuth 2.0 PKCE flow. Used by wunderland login --provider twitter.",
857
+ "envVar": "TWITTER_CLIENT_ID",
858
+ "docsUrl": "https://developer.x.com/en/portal/dashboard",
859
+ "providers": ["twitter"],
860
+ "optional": true
861
+ },
862
+ {
863
+ "id": "meta.appId",
864
+ "label": "Meta/Facebook App ID",
865
+ "description": "App ID for Instagram OAuth via Meta. Used by wunderland login --provider instagram.",
866
+ "envVar": "META_APP_ID",
867
+ "aliases": ["FACEBOOK_APP_ID"],
868
+ "docsUrl": "https://developers.facebook.com/apps/",
869
+ "providers": ["instagram"],
870
+ "optional": true
871
+ },
872
+ {
873
+ "id": "meta.appSecret",
874
+ "label": "Meta/Facebook App Secret",
875
+ "description": "App secret for Instagram OAuth via Meta. Used by wunderland login --provider instagram.",
876
+ "envVar": "META_APP_SECRET",
877
+ "aliases": ["FACEBOOK_APP_SECRET"],
878
+ "docsUrl": "https://developers.facebook.com/apps/",
879
+ "providers": ["instagram"],
880
+ "optional": true
843
881
  }
844
882
  ]
@@ -0,0 +1,62 @@
1
+ /**
2
+ * @fileoverview Abstract base class for browser-based OAuth 2.0 authorization code
3
+ * flows with PKCE support.
4
+ *
5
+ * Orchestrates: localhost callback server → browser open → code exchange → token storage.
6
+ * Subclasses implement provider-specific URL building, code exchange, and token refresh.
7
+ *
8
+ * @module agentos/core/llm/auth/BrowserOAuthFlow
9
+ */
10
+ import type { IOAuthFlow, IOAuthTokenStore, OAuthTokenSet } from './types.js';
11
+ export interface BrowserOAuthConfig {
12
+ /** Human-readable provider name for CLI output. */
13
+ displayName: string;
14
+ /** OAuth authorization endpoint URL. */
15
+ authorizationEndpoint: string;
16
+ /** OAuth token endpoint URL. */
17
+ tokenEndpoint: string;
18
+ /** Requested OAuth scopes. */
19
+ scopes: string[];
20
+ /** OAuth client ID. */
21
+ clientId: string;
22
+ /** OAuth client secret (optional — PKCE flows may not need it). */
23
+ clientSecret?: string;
24
+ /** Maximum time to wait for user authorization (ms). */
25
+ timeoutMs?: number;
26
+ /** Buffer before expiry to trigger auto-refresh (ms). */
27
+ refreshBufferMs?: number;
28
+ }
29
+ export interface BrowserOAuthFlowOptions {
30
+ tokenStore?: IOAuthTokenStore;
31
+ /** Called with the authorization URL (for custom display). */
32
+ onAuthUrl?: (url: string) => void;
33
+ }
34
+ export declare abstract class BrowserOAuthFlow implements IOAuthFlow {
35
+ abstract readonly providerId: string;
36
+ protected readonly store: IOAuthTokenStore;
37
+ protected readonly onAuthUrl?: (url: string) => void;
38
+ private refreshPromise;
39
+ constructor(opts?: BrowserOAuthFlowOptions);
40
+ /** Return provider-specific OAuth configuration. */
41
+ protected abstract getConfig(): BrowserOAuthConfig;
42
+ /**
43
+ * Exchange an authorization code for tokens.
44
+ * Called after the callback server receives the code.
45
+ */
46
+ protected abstract exchangeCode(code: string, redirectUri: string, codeVerifier: string): Promise<OAuthTokenSet>;
47
+ /**
48
+ * Refresh an expired access token using the refresh token.
49
+ */
50
+ protected abstract refreshTokens(refreshToken: string): Promise<OAuthTokenSet>;
51
+ /**
52
+ * Post-exchange hook for provider-specific processing.
53
+ * E.g., Instagram exchanges short-lived for long-lived tokens here.
54
+ * Default: passthrough.
55
+ */
56
+ protected postExchange(tokens: OAuthTokenSet): Promise<OAuthTokenSet>;
57
+ authenticate(): Promise<OAuthTokenSet>;
58
+ refresh(tokens: OAuthTokenSet): Promise<OAuthTokenSet>;
59
+ isValid(tokens: OAuthTokenSet): boolean;
60
+ getAccessToken(): Promise<string>;
61
+ }
62
+ //# sourceMappingURL=BrowserOAuthFlow.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BrowserOAuthFlow.d.ts","sourceRoot":"","sources":["../../../../src/core/llm/auth/BrowserOAuthFlow.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAY9E,MAAM,WAAW,kBAAkB;IACjC,mDAAmD;IACnD,WAAW,EAAE,MAAM,CAAC;IACpB,wCAAwC;IACxC,qBAAqB,EAAE,MAAM,CAAC;IAC9B,gCAAgC;IAChC,aAAa,EAAE,MAAM,CAAC;IACtB,8BAA8B;IAC9B,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,uBAAuB;IACvB,QAAQ,EAAE,MAAM,CAAC;IACjB,mEAAmE;IACnE,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,wDAAwD;IACxD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,yDAAyD;IACzD,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,uBAAuB;IACtC,UAAU,CAAC,EAAE,gBAAgB,CAAC;IAC9B,8DAA8D;IAC9D,SAAS,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;CACnC;AAED,8BAAsB,gBAAiB,YAAW,UAAU;IAC1D,QAAQ,CAAC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAErC,SAAS,CAAC,QAAQ,CAAC,KAAK,EAAE,gBAAgB,CAAC;IAC3C,SAAS,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IACrD,OAAO,CAAC,cAAc,CAAuC;gBAEjD,IAAI,CAAC,EAAE,uBAAuB;IAO1C,oDAAoD;IACpD,SAAS,CAAC,QAAQ,CAAC,SAAS,IAAI,kBAAkB;IAElD;;;OAGG;IACH,SAAS,CAAC,QAAQ,CAAC,YAAY,CAC7B,IAAI,EAAE,MAAM,EACZ,WAAW,EAAE,MAAM,EACnB,YAAY,EAAE,MAAM,GACnB,OAAO,CAAC,aAAa,CAAC;IAEzB;;OAEG;IACH,SAAS,CAAC,QAAQ,CAAC,aAAa,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC;IAI9E;;;;OAIG;cACa,YAAY,CAAC,MAAM,EAAE,aAAa,GAAG,OAAO,CAAC,aAAa,CAAC;IAMrE,YAAY,IAAI,OAAO,CAAC,aAAa,CAAC;IAwEtC,OAAO,CAAC,MAAM,EAAE,aAAa,GAAG,OAAO,CAAC,aAAa,CAAC;IAqB5D,OAAO,CAAC,MAAM,EAAE,aAAa,GAAG,OAAO;IAKjC,cAAc,IAAI,OAAO,CAAC,MAAM,CAAC;CAsBxC"}
@@ -0,0 +1,134 @@
1
+ /**
2
+ * @fileoverview Abstract base class for browser-based OAuth 2.0 authorization code
3
+ * flows with PKCE support.
4
+ *
5
+ * Orchestrates: localhost callback server → browser open → code exchange → token storage.
6
+ * Subclasses implement provider-specific URL building, code exchange, and token refresh.
7
+ *
8
+ * @module agentos/core/llm/auth/BrowserOAuthFlow
9
+ */
10
+ import { FileTokenStore } from './FileTokenStore.js';
11
+ import { generateCodeVerifier, generateCodeChallenge, generateState } from './pkce.js';
12
+ import { startCallbackServer } from './callback-server.js';
13
+ import { isTokenValid, openBrowser } from './utils.js';
14
+ /** Default timeout for user authorization (5 minutes). */
15
+ const DEFAULT_TIMEOUT_MS = 5 * 60 * 1000;
16
+ /** Default refresh buffer (5 minutes before expiry). */
17
+ const DEFAULT_REFRESH_BUFFER_MS = 5 * 60 * 1000;
18
+ export class BrowserOAuthFlow {
19
+ constructor(opts) {
20
+ this.refreshPromise = null;
21
+ this.store = opts?.tokenStore ?? new FileTokenStore();
22
+ this.onAuthUrl = opts?.onAuthUrl;
23
+ }
24
+ // ── Optional hooks ──
25
+ /**
26
+ * Post-exchange hook for provider-specific processing.
27
+ * E.g., Instagram exchanges short-lived for long-lived tokens here.
28
+ * Default: passthrough.
29
+ */
30
+ async postExchange(tokens) {
31
+ return tokens;
32
+ }
33
+ // ── IOAuthFlow implementation ──
34
+ async authenticate() {
35
+ const config = this.getConfig();
36
+ const timeoutMs = config.timeoutMs ?? DEFAULT_TIMEOUT_MS;
37
+ // 1. Generate PKCE pair + state
38
+ const codeVerifier = generateCodeVerifier();
39
+ const codeChallenge = generateCodeChallenge(codeVerifier);
40
+ const state = generateState();
41
+ // 2. Start callback server (port 0 = OS-assigned)
42
+ let assignedPort = 0;
43
+ const { promise: callbackPromise, shutdown } = startCallbackServer({
44
+ expectedState: state,
45
+ timeoutMs,
46
+ onListening: (port) => { assignedPort = port; },
47
+ });
48
+ // Wait briefly for the server to start listening
49
+ await new Promise((resolve) => {
50
+ const check = () => {
51
+ if (assignedPort > 0) {
52
+ resolve();
53
+ return;
54
+ }
55
+ setTimeout(check, 10);
56
+ };
57
+ check();
58
+ });
59
+ const redirectUri = `http://localhost:${assignedPort}/callback`;
60
+ // 3. Build authorization URL
61
+ const params = new URLSearchParams({
62
+ response_type: 'code',
63
+ client_id: config.clientId,
64
+ redirect_uri: redirectUri,
65
+ scope: config.scopes.join(' '),
66
+ state,
67
+ code_challenge: codeChallenge,
68
+ code_challenge_method: 'S256',
69
+ });
70
+ const authUrl = `${config.authorizationEndpoint}?${params.toString()}`;
71
+ // 4. Open browser (or print URL)
72
+ if (this.onAuthUrl) {
73
+ this.onAuthUrl(authUrl);
74
+ }
75
+ const opened = await openBrowser(authUrl);
76
+ if (!opened && !this.onAuthUrl) {
77
+ console.log(`\n Open this URL in your browser to authorize:\n ${authUrl}\n`);
78
+ }
79
+ // 5. Wait for callback
80
+ let result;
81
+ try {
82
+ result = await callbackPromise;
83
+ }
84
+ catch (err) {
85
+ shutdown();
86
+ throw err;
87
+ }
88
+ // 6. Exchange code for tokens
89
+ let tokens = await this.exchangeCode(result.code, redirectUri, codeVerifier);
90
+ // 7. Post-exchange hook
91
+ tokens = await this.postExchange(tokens);
92
+ // 8. Store
93
+ await this.store.save(this.providerId, tokens);
94
+ return tokens;
95
+ }
96
+ async refresh(tokens) {
97
+ if (!tokens.refreshToken) {
98
+ throw new Error(`No refresh token available for ${this.providerId}. Run \`wunderland login --provider ${this.providerId}\` to re-authenticate.`);
99
+ }
100
+ const refreshed = await this.refreshTokens(tokens.refreshToken);
101
+ // Preserve refresh token if the provider omits it in the response
102
+ if (!refreshed.refreshToken && tokens.refreshToken) {
103
+ refreshed.refreshToken = tokens.refreshToken;
104
+ }
105
+ // Preserve metadata
106
+ if (!refreshed.metadata && tokens.metadata) {
107
+ refreshed.metadata = tokens.metadata;
108
+ }
109
+ await this.store.save(this.providerId, refreshed);
110
+ return refreshed;
111
+ }
112
+ isValid(tokens) {
113
+ const config = this.getConfig();
114
+ return isTokenValid(tokens, config.refreshBufferMs ?? DEFAULT_REFRESH_BUFFER_MS);
115
+ }
116
+ async getAccessToken() {
117
+ const tokens = await this.store.load(this.providerId);
118
+ if (!tokens) {
119
+ throw new Error(`No ${this.providerId} OAuth tokens found. Run \`wunderland login --provider ${this.providerId}\` to authenticate.`);
120
+ }
121
+ if (this.isValid(tokens)) {
122
+ return tokens.accessToken;
123
+ }
124
+ // Need refresh — use mutex to prevent concurrent refreshes
125
+ if (!this.refreshPromise) {
126
+ this.refreshPromise = this.refresh(tokens).finally(() => {
127
+ this.refreshPromise = null;
128
+ });
129
+ }
130
+ const refreshed = await this.refreshPromise;
131
+ return refreshed.accessToken;
132
+ }
133
+ }
134
+ //# sourceMappingURL=BrowserOAuthFlow.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BrowserOAuthFlow.js","sourceRoot":"","sources":["../../../../src/core/llm/auth/BrowserOAuthFlow.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"FileTokenStore.d.ts","sourceRoot":"","sources":["../../../../src/core/llm/auth/FileTokenStore.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAMH,OAAO,KAAK,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAElE,qBAAa,cAAe,YAAW,gBAAgB;IACrD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;gBAErB,OAAO,CAAC,EAAE,MAAM;IAI5B,OAAO,CAAC,SAAS;IAMX,IAAI,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC;IAmBvD,IAAI,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC;IAW9D,KAAK,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAM/C"}
1
+ {"version":3,"file":"FileTokenStore.d.ts","sourceRoot":"","sources":["../../../../src/core/llm/auth/FileTokenStore.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAMH,OAAO,KAAK,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAElE,qBAAa,cAAe,YAAW,gBAAgB;IACrD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;gBAErB,OAAO,CAAC,EAAE,MAAM;IAI5B,OAAO,CAAC,SAAS;IAMX,IAAI,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC;IAoBvD,IAAI,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC;IAW9D,KAAK,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAM/C"}
@@ -30,6 +30,7 @@ export class FileTokenStore {
30
30
  accessToken: data.accessToken,
31
31
  refreshToken: typeof data.refreshToken === 'string' ? data.refreshToken : undefined,
32
32
  expiresAt: data.expiresAt,
33
+ metadata: typeof data.metadata === 'object' && data.metadata !== null ? data.metadata : undefined,
33
34
  };
34
35
  }
35
36
  catch {
@@ -1 +1 @@
1
- {"version":3,"file":"FileTokenStore.js","sourceRoot":"","sources":["../../../../src/core/llm/auth/FileTokenStore.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAC7E,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAGlC,MAAM,OAAO,cAAc;IAGzB,YAAY,OAAgB;QAC1B,IAAI,CAAC,OAAO,GAAG,OAAO,IAAI,IAAI,CAAC,OAAO,EAAE,EAAE,aAAa,EAAE,MAAM,CAAC,CAAC;IACnE,CAAC;IAEO,SAAS,CAAC,UAAkB;QAClC,iDAAiD;QACjD,MAAM,IAAI,GAAG,UAAU,CAAC,OAAO,CAAC,iBAAiB,EAAE,GAAG,CAAC,CAAC;QACxD,OAAO,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,IAAI,OAAO,CAAC,CAAC;IAC5C,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,UAAkB;QAC3B,MAAM,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC;QACrC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC;YAAE,OAAO,IAAI,CAAC;QAChC,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;YACtC,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;YAC7B,IAAI,OAAO,IAAI,CAAC,WAAW,KAAK,QAAQ,IAAI,OAAO,IAAI,CAAC,SAAS,KAAK,QAAQ,EAAE,CAAC;gBAC/E,OAAO,IAAI,CAAC;YACd,CAAC;YACD,OAAO;gBACL,WAAW,EAAE,IAAI,CAAC,WAAW;gBAC7B,YAAY,EAAE,OAAO,IAAI,CAAC,YAAY,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,SAAS;gBACnF,SAAS,EAAE,IAAI,CAAC,SAAS;aAC1B,CAAC;QACJ,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,UAAkB,EAAE,MAAqB;QAClD,MAAM,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC/C,MAAM,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC;QACrC,MAAM,SAAS,CAAC,CAAC,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;QAC5D,IAAI,CAAC;YACH,MAAM,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;QACxB,CAAC;QAAC,MAAM,CAAC;YACP,wCAAwC;QAC1C,CAAC;IACH,CAAC;IAED,KAAK,CAAC,KAAK,CAAC,UAAkB;QAC5B,MAAM,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC;QACrC,IAAI,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC;YAClB,MAAM,MAAM,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;IACH,CAAC;CACF"}
1
+ {"version":3,"file":"FileTokenStore.js","sourceRoot":"","sources":["../../../../src/core/llm/auth/FileTokenStore.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAC7E,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAGlC,MAAM,OAAO,cAAc;IAGzB,YAAY,OAAgB;QAC1B,IAAI,CAAC,OAAO,GAAG,OAAO,IAAI,IAAI,CAAC,OAAO,EAAE,EAAE,aAAa,EAAE,MAAM,CAAC,CAAC;IACnE,CAAC;IAEO,SAAS,CAAC,UAAkB;QAClC,iDAAiD;QACjD,MAAM,IAAI,GAAG,UAAU,CAAC,OAAO,CAAC,iBAAiB,EAAE,GAAG,CAAC,CAAC;QACxD,OAAO,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,IAAI,OAAO,CAAC,CAAC;IAC5C,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,UAAkB;QAC3B,MAAM,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC;QACrC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC;YAAE,OAAO,IAAI,CAAC;QAChC,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;YACtC,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;YAC7B,IAAI,OAAO,IAAI,CAAC,WAAW,KAAK,QAAQ,IAAI,OAAO,IAAI,CAAC,SAAS,KAAK,QAAQ,EAAE,CAAC;gBAC/E,OAAO,IAAI,CAAC;YACd,CAAC;YACD,OAAO;gBACL,WAAW,EAAE,IAAI,CAAC,WAAW;gBAC7B,YAAY,EAAE,OAAO,IAAI,CAAC,YAAY,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,SAAS;gBACnF,SAAS,EAAE,IAAI,CAAC,SAAS;gBACzB,QAAQ,EAAE,OAAO,IAAI,CAAC,QAAQ,KAAK,QAAQ,IAAI,IAAI,CAAC,QAAQ,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS;aAClG,CAAC;QACJ,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,UAAkB,EAAE,MAAqB;QAClD,MAAM,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC/C,MAAM,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC;QACrC,MAAM,SAAS,CAAC,CAAC,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;QAC5D,IAAI,CAAC;YACH,MAAM,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;QACxB,CAAC;QAAC,MAAM,CAAC;YACP,wCAAwC;QAC1C,CAAC;IACH,CAAC;IAED,KAAK,CAAC,KAAK,CAAC,UAAkB;QAC5B,MAAM,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC;QACrC,IAAI,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC;YAClB,MAAM,MAAM,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;IACH,CAAC;CACF"}
@@ -0,0 +1,40 @@
1
+ /**
2
+ * @fileoverview Instagram/Meta OAuth 2.0 authorization code flow.
3
+ *
4
+ * Uses Facebook's OAuth 2.0 to obtain an Instagram Graph API access token.
5
+ * After the initial code exchange, the short-lived token is swapped for a
6
+ * long-lived token (60 days). The IG Business Account ID is resolved and
7
+ * stored in token metadata.
8
+ *
9
+ * @module agentos/core/llm/auth/InstagramOAuthFlow
10
+ */
11
+ import type { OAuthTokenSet } from './types.js';
12
+ import { BrowserOAuthFlow, type BrowserOAuthConfig, type BrowserOAuthFlowOptions } from './BrowserOAuthFlow.js';
13
+ export interface InstagramOAuthFlowOptions extends BrowserOAuthFlowOptions {
14
+ /** Meta/Facebook App ID. Falls back to META_APP_ID or FACEBOOK_APP_ID env var. */
15
+ appId?: string;
16
+ /** Meta/Facebook App Secret. Falls back to META_APP_SECRET or FACEBOOK_APP_SECRET env var. */
17
+ appSecret?: string;
18
+ /** Override scopes. */
19
+ scopes?: string[];
20
+ }
21
+ export declare class InstagramOAuthFlow extends BrowserOAuthFlow {
22
+ readonly providerId = "instagram";
23
+ private readonly appId;
24
+ private readonly appSecret;
25
+ private readonly scopes;
26
+ constructor(opts?: InstagramOAuthFlowOptions);
27
+ protected getConfig(): BrowserOAuthConfig;
28
+ protected exchangeCode(code: string, redirectUri: string, _codeVerifier: string): Promise<OAuthTokenSet>;
29
+ /**
30
+ * Exchange short-lived token for long-lived token (60 days),
31
+ * then resolve the IG Business Account ID.
32
+ */
33
+ protected postExchange(tokens: OAuthTokenSet): Promise<OAuthTokenSet>;
34
+ protected refreshTokens(refreshToken: string): Promise<OAuthTokenSet>;
35
+ /**
36
+ * Resolve the Instagram Business Account ID from the user's Facebook pages.
37
+ */
38
+ private resolveIgUserId;
39
+ }
40
+ //# sourceMappingURL=InstagramOAuthFlow.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"InstagramOAuthFlow.d.ts","sourceRoot":"","sources":["../../../../src/core/llm/auth/InstagramOAuthFlow.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAoB,aAAa,EAAE,MAAM,YAAY,CAAC;AAClE,OAAO,EAAE,gBAAgB,EAAE,KAAK,kBAAkB,EAAE,KAAK,uBAAuB,EAAE,MAAM,uBAAuB,CAAC;AAehH,MAAM,WAAW,yBAA0B,SAAQ,uBAAuB;IACxE,kFAAkF;IAClF,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,8FAA8F;IAC9F,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,uBAAuB;IACvB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;CACnB;AAED,qBAAa,kBAAmB,SAAQ,gBAAgB;IACtD,QAAQ,CAAC,UAAU,eAAe;IAClC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAS;IAC/B,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAW;gBAEtB,IAAI,CAAC,EAAE,yBAAyB;IAqB5C,SAAS,CAAC,SAAS,IAAI,kBAAkB;cAWzB,YAAY,CAC1B,IAAI,EAAE,MAAM,EACZ,WAAW,EAAE,MAAM,EACnB,aAAa,EAAE,MAAM,GACpB,OAAO,CAAC,aAAa,CAAC;IA4BzB;;;OAGG;cACsB,YAAY,CAAC,MAAM,EAAE,aAAa,GAAG,OAAO,CAAC,aAAa,CAAC;cAkCpE,aAAa,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC;IA6B3E;;OAEG;YACW,eAAe;CA4B9B"}
@@ -0,0 +1,143 @@
1
+ /**
2
+ * @fileoverview Instagram/Meta OAuth 2.0 authorization code flow.
3
+ *
4
+ * Uses Facebook's OAuth 2.0 to obtain an Instagram Graph API access token.
5
+ * After the initial code exchange, the short-lived token is swapped for a
6
+ * long-lived token (60 days). The IG Business Account ID is resolved and
7
+ * stored in token metadata.
8
+ *
9
+ * @module agentos/core/llm/auth/InstagramOAuthFlow
10
+ */
11
+ import { BrowserOAuthFlow } from './BrowserOAuthFlow.js';
12
+ const META_AUTH_URL = 'https://www.facebook.com/v21.0/dialog/oauth';
13
+ const META_TOKEN_URL = 'https://graph.facebook.com/v21.0/oauth/access_token';
14
+ const GRAPH_API = 'https://graph.facebook.com/v21.0';
15
+ const DEFAULT_SCOPES = [
16
+ 'instagram_basic',
17
+ 'instagram_content_publish',
18
+ 'instagram_manage_comments',
19
+ 'instagram_manage_insights',
20
+ 'pages_read_engagement',
21
+ 'pages_show_list',
22
+ ];
23
+ export class InstagramOAuthFlow extends BrowserOAuthFlow {
24
+ constructor(opts) {
25
+ super(opts);
26
+ this.providerId = 'instagram';
27
+ this.appId = opts?.appId ?? process.env.META_APP_ID ?? process.env.FACEBOOK_APP_ID ?? '';
28
+ this.appSecret = opts?.appSecret ?? process.env.META_APP_SECRET ?? process.env.FACEBOOK_APP_SECRET ?? '';
29
+ this.scopes = opts?.scopes ?? DEFAULT_SCOPES;
30
+ if (!this.appId) {
31
+ throw new Error('Meta/Facebook App ID is required for Instagram OAuth. '
32
+ + 'Pass it via --app-id flag, set META_APP_ID env var, '
33
+ + 'or create an app at https://developers.facebook.com/apps/');
34
+ }
35
+ if (!this.appSecret) {
36
+ throw new Error('Meta/Facebook App Secret is required for Instagram OAuth. '
37
+ + 'Pass it via --app-secret flag or set META_APP_SECRET env var.');
38
+ }
39
+ }
40
+ getConfig() {
41
+ return {
42
+ displayName: 'Instagram',
43
+ authorizationEndpoint: META_AUTH_URL,
44
+ tokenEndpoint: META_TOKEN_URL,
45
+ scopes: this.scopes,
46
+ clientId: this.appId,
47
+ clientSecret: this.appSecret,
48
+ };
49
+ }
50
+ async exchangeCode(code, redirectUri, _codeVerifier) {
51
+ // Meta uses query params (not POST body) for the token exchange
52
+ const params = new URLSearchParams({
53
+ client_id: this.appId,
54
+ client_secret: this.appSecret,
55
+ redirect_uri: redirectUri,
56
+ code,
57
+ });
58
+ const res = await fetch(`${META_TOKEN_URL}?${params.toString()}`);
59
+ if (!res.ok) {
60
+ const body = await res.text();
61
+ throw new Error(`Instagram token exchange failed: ${res.status} ${body}`);
62
+ }
63
+ const data = await res.json();
64
+ return {
65
+ accessToken: data.access_token,
66
+ expiresAt: Date.now() + (data.expires_in ?? 3600) * 1000,
67
+ };
68
+ }
69
+ /**
70
+ * Exchange short-lived token for long-lived token (60 days),
71
+ * then resolve the IG Business Account ID.
72
+ */
73
+ async postExchange(tokens) {
74
+ // 1. Exchange for long-lived token
75
+ const llParams = new URLSearchParams({
76
+ grant_type: 'fb_exchange_token',
77
+ client_id: this.appId,
78
+ client_secret: this.appSecret,
79
+ fb_exchange_token: tokens.accessToken,
80
+ });
81
+ const llRes = await fetch(`${META_TOKEN_URL}?${llParams.toString()}`);
82
+ if (llRes.ok) {
83
+ const llData = await llRes.json();
84
+ tokens = {
85
+ accessToken: llData.access_token,
86
+ // Long-lived tokens don't have traditional refresh tokens;
87
+ // they're refreshed by calling the same endpoint before expiry
88
+ refreshToken: llData.access_token,
89
+ expiresAt: Date.now() + (llData.expires_in ?? 5184000) * 1000, // ~60 days
90
+ };
91
+ }
92
+ // 2. Resolve IG Business Account ID
93
+ const igUserId = await this.resolveIgUserId(tokens.accessToken);
94
+ if (igUserId) {
95
+ tokens.metadata = { ...tokens.metadata, igUserId };
96
+ }
97
+ return tokens;
98
+ }
99
+ async refreshTokens(refreshToken) {
100
+ // For Meta long-lived tokens, "refresh" means exchanging the current
101
+ // long-lived token for a new one (must be done before expiry)
102
+ const params = new URLSearchParams({
103
+ grant_type: 'fb_exchange_token',
104
+ client_id: this.appId,
105
+ client_secret: this.appSecret,
106
+ fb_exchange_token: refreshToken,
107
+ });
108
+ const res = await fetch(`${META_TOKEN_URL}?${params.toString()}`);
109
+ if (!res.ok) {
110
+ const body = await res.text();
111
+ throw new Error(`Instagram token refresh failed: ${res.status} ${body}`);
112
+ }
113
+ const data = await res.json();
114
+ return {
115
+ accessToken: data.access_token,
116
+ refreshToken: data.access_token,
117
+ expiresAt: Date.now() + (data.expires_in ?? 5184000) * 1000,
118
+ };
119
+ }
120
+ /**
121
+ * Resolve the Instagram Business Account ID from the user's Facebook pages.
122
+ */
123
+ async resolveIgUserId(accessToken) {
124
+ try {
125
+ // Get user's pages
126
+ const pagesRes = await fetch(`${GRAPH_API}/me/accounts?fields=id,name,instagram_business_account&access_token=${accessToken}`);
127
+ if (!pagesRes.ok)
128
+ return undefined;
129
+ const pagesData = await pagesRes.json();
130
+ // Find first page with an Instagram business account
131
+ for (const page of pagesData.data) {
132
+ if (page.instagram_business_account?.id) {
133
+ return page.instagram_business_account.id;
134
+ }
135
+ }
136
+ return undefined;
137
+ }
138
+ catch {
139
+ return undefined;
140
+ }
141
+ }
142
+ }
143
+ //# sourceMappingURL=InstagramOAuthFlow.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"InstagramOAuthFlow.js","sourceRoot":"","sources":["../../../../src/core/llm/auth/InstagramOAuthFlow.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * @fileoverview Twitter/X OAuth 2.0 authorization code flow with PKCE.
3
+ *
4
+ * Uses Twitter API v2 OAuth 2.0 endpoints. PKCE is required (public client,
5
+ * no client secret needed). Supports offline.access scope for refresh tokens.
6
+ *
7
+ * @module agentos/core/llm/auth/TwitterOAuthFlow
8
+ */
9
+ import type { OAuthTokenSet } from './types.js';
10
+ import { BrowserOAuthFlow, type BrowserOAuthConfig, type BrowserOAuthFlowOptions } from './BrowserOAuthFlow.js';
11
+ export interface TwitterOAuthFlowOptions extends BrowserOAuthFlowOptions {
12
+ /** Twitter OAuth 2.0 Client ID. Falls back to TWITTER_CLIENT_ID env var. */
13
+ clientId?: string;
14
+ /** Override scopes (default includes tweet.read/write, users.read, follows, offline.access). */
15
+ scopes?: string[];
16
+ }
17
+ export declare class TwitterOAuthFlow extends BrowserOAuthFlow {
18
+ readonly providerId = "twitter";
19
+ private readonly clientId;
20
+ private readonly scopes;
21
+ constructor(opts?: TwitterOAuthFlowOptions);
22
+ protected getConfig(): BrowserOAuthConfig;
23
+ protected exchangeCode(code: string, redirectUri: string, codeVerifier: string): Promise<OAuthTokenSet>;
24
+ protected refreshTokens(refreshToken: string): Promise<OAuthTokenSet>;
25
+ }
26
+ //# sourceMappingURL=TwitterOAuthFlow.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TwitterOAuthFlow.d.ts","sourceRoot":"","sources":["../../../../src/core/llm/auth/TwitterOAuthFlow.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAoB,aAAa,EAAE,MAAM,YAAY,CAAC;AAClE,OAAO,EAAE,gBAAgB,EAAE,KAAK,kBAAkB,EAAE,KAAK,uBAAuB,EAAE,MAAM,uBAAuB,CAAC;AAchH,MAAM,WAAW,uBAAwB,SAAQ,uBAAuB;IACtE,4EAA4E;IAC5E,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,gGAAgG;IAChG,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;CACnB;AAED,qBAAa,gBAAiB,SAAQ,gBAAgB;IACpD,QAAQ,CAAC,UAAU,aAAa;IAChC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAW;gBAEtB,IAAI,CAAC,EAAE,uBAAuB;IAc1C,SAAS,CAAC,SAAS,IAAI,kBAAkB;cAUzB,YAAY,CAC1B,IAAI,EAAE,MAAM,EACZ,WAAW,EAAE,MAAM,EACnB,YAAY,EAAE,MAAM,GACnB,OAAO,CAAC,aAAa,CAAC;cAgCT,aAAa,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC;CA4B5E"}
@@ -0,0 +1,86 @@
1
+ /**
2
+ * @fileoverview Twitter/X OAuth 2.0 authorization code flow with PKCE.
3
+ *
4
+ * Uses Twitter API v2 OAuth 2.0 endpoints. PKCE is required (public client,
5
+ * no client secret needed). Supports offline.access scope for refresh tokens.
6
+ *
7
+ * @module agentos/core/llm/auth/TwitterOAuthFlow
8
+ */
9
+ import { BrowserOAuthFlow } from './BrowserOAuthFlow.js';
10
+ const TWITTER_AUTH_URL = 'https://twitter.com/i/oauth2/authorize';
11
+ const TWITTER_TOKEN_URL = 'https://api.twitter.com/2/oauth2/token';
12
+ const DEFAULT_SCOPES = [
13
+ 'tweet.read',
14
+ 'tweet.write',
15
+ 'users.read',
16
+ 'follows.read',
17
+ 'follows.write',
18
+ 'offline.access',
19
+ ];
20
+ export class TwitterOAuthFlow extends BrowserOAuthFlow {
21
+ constructor(opts) {
22
+ super(opts);
23
+ this.providerId = 'twitter';
24
+ this.clientId = opts?.clientId ?? process.env.TWITTER_CLIENT_ID ?? '';
25
+ this.scopes = opts?.scopes ?? DEFAULT_SCOPES;
26
+ if (!this.clientId) {
27
+ throw new Error('Twitter OAuth 2.0 Client ID is required. '
28
+ + 'Pass it via --client-id flag, set TWITTER_CLIENT_ID env var, '
29
+ + 'or create one at https://developer.x.com/en/portal/dashboard');
30
+ }
31
+ }
32
+ getConfig() {
33
+ return {
34
+ displayName: 'Twitter/X',
35
+ authorizationEndpoint: TWITTER_AUTH_URL,
36
+ tokenEndpoint: TWITTER_TOKEN_URL,
37
+ scopes: this.scopes,
38
+ clientId: this.clientId,
39
+ };
40
+ }
41
+ async exchangeCode(code, redirectUri, codeVerifier) {
42
+ const res = await fetch(TWITTER_TOKEN_URL, {
43
+ method: 'POST',
44
+ headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
45
+ body: new URLSearchParams({
46
+ grant_type: 'authorization_code',
47
+ code,
48
+ redirect_uri: redirectUri,
49
+ client_id: this.clientId,
50
+ code_verifier: codeVerifier,
51
+ }).toString(),
52
+ });
53
+ if (!res.ok) {
54
+ const body = await res.text();
55
+ throw new Error(`Twitter token exchange failed: ${res.status} ${body}`);
56
+ }
57
+ const data = await res.json();
58
+ return {
59
+ accessToken: data.access_token,
60
+ refreshToken: data.refresh_token,
61
+ expiresAt: Date.now() + (data.expires_in ?? 7200) * 1000,
62
+ };
63
+ }
64
+ async refreshTokens(refreshToken) {
65
+ const res = await fetch(TWITTER_TOKEN_URL, {
66
+ method: 'POST',
67
+ headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
68
+ body: new URLSearchParams({
69
+ grant_type: 'refresh_token',
70
+ refresh_token: refreshToken,
71
+ client_id: this.clientId,
72
+ }).toString(),
73
+ });
74
+ if (!res.ok) {
75
+ const body = await res.text();
76
+ throw new Error(`Twitter token refresh failed: ${res.status} ${body}`);
77
+ }
78
+ const data = await res.json();
79
+ return {
80
+ accessToken: data.access_token,
81
+ refreshToken: data.refresh_token,
82
+ expiresAt: Date.now() + (data.expires_in ?? 7200) * 1000,
83
+ };
84
+ }
85
+ }
86
+ //# sourceMappingURL=TwitterOAuthFlow.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TwitterOAuthFlow.js","sourceRoot":"","sources":["../../../../src/core/llm/auth/TwitterOAuthFlow.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,32 @@
1
+ /**
2
+ * @fileoverview Ephemeral localhost HTTP server for OAuth 2.0 authorization code callbacks.
3
+ *
4
+ * Listens on an OS-assigned port, waits for a single GET /callback with
5
+ * code + state query params, validates the state, and resolves.
6
+ *
7
+ * @module agentos/core/llm/auth/callback-server
8
+ */
9
+ export interface CallbackResult {
10
+ code: string;
11
+ state: string;
12
+ }
13
+ export interface CallbackServerOptions {
14
+ /** Expected state value for CSRF validation. */
15
+ expectedState: string;
16
+ /** Maximum time (ms) to wait for the callback before timing out. */
17
+ timeoutMs: number;
18
+ /** Called once the server is listening, with the assigned port. */
19
+ onListening?: (port: number) => void;
20
+ }
21
+ /**
22
+ * Start an ephemeral localhost HTTP server to receive the OAuth callback.
23
+ *
24
+ * @returns An object with:
25
+ * - `promise` — resolves with `{ code, state }` on success, rejects on timeout/error
26
+ * - `shutdown()` — forcibly close the server
27
+ */
28
+ export declare function startCallbackServer(opts: CallbackServerOptions): {
29
+ promise: Promise<CallbackResult>;
30
+ shutdown: () => void;
31
+ };
32
+ //# sourceMappingURL=callback-server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"callback-server.d.ts","sourceRoot":"","sources":["../../../../src/core/llm/auth/callback-server.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAKH,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,qBAAqB;IACpC,gDAAgD;IAChD,aAAa,EAAE,MAAM,CAAC;IACtB,oEAAoE;IACpE,SAAS,EAAE,MAAM,CAAC;IAClB,mEAAmE;IACnE,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CACtC;AAkCD;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,qBAAqB,GAAG;IAChE,OAAO,EAAE,OAAO,CAAC,cAAc,CAAC,CAAC;IACjC,QAAQ,EAAE,MAAM,IAAI,CAAC;CACtB,CAsEA"}
@@ -0,0 +1,111 @@
1
+ /**
2
+ * @fileoverview Ephemeral localhost HTTP server for OAuth 2.0 authorization code callbacks.
3
+ *
4
+ * Listens on an OS-assigned port, waits for a single GET /callback with
5
+ * code + state query params, validates the state, and resolves.
6
+ *
7
+ * @module agentos/core/llm/auth/callback-server
8
+ */
9
+ import { createServer } from 'node:http';
10
+ import { URL } from 'node:url';
11
+ const SUCCESS_HTML = `<!DOCTYPE html>
12
+ <html><head><title>Authorization Complete</title>
13
+ <style>
14
+ body { font-family: -apple-system, BlinkMacSystemFont, sans-serif; display: flex;
15
+ justify-content: center; align-items: center; height: 100vh; margin: 0;
16
+ background: #0a0a0a; color: #e0e0e0; }
17
+ .card { text-align: center; padding: 3rem; border-radius: 12px;
18
+ background: #1a1a1a; border: 1px solid #333; }
19
+ h1 { color: #4ade80; margin-bottom: 0.5rem; }
20
+ p { color: #888; }
21
+ </style></head>
22
+ <body><div class="card">
23
+ <h1>Authorized</h1>
24
+ <p>You can close this tab and return to the terminal.</p>
25
+ </div></body></html>`;
26
+ const ERROR_HTML = (msg) => `<!DOCTYPE html>
27
+ <html><head><title>Authorization Failed</title>
28
+ <style>
29
+ body { font-family: -apple-system, BlinkMacSystemFont, sans-serif; display: flex;
30
+ justify-content: center; align-items: center; height: 100vh; margin: 0;
31
+ background: #0a0a0a; color: #e0e0e0; }
32
+ .card { text-align: center; padding: 3rem; border-radius: 12px;
33
+ background: #1a1a1a; border: 1px solid #333; }
34
+ h1 { color: #f87171; margin-bottom: 0.5rem; }
35
+ p { color: #888; }
36
+ </style></head>
37
+ <body><div class="card">
38
+ <h1>Authorization Failed</h1>
39
+ <p>${msg}</p>
40
+ </div></body></html>`;
41
+ /**
42
+ * Start an ephemeral localhost HTTP server to receive the OAuth callback.
43
+ *
44
+ * @returns An object with:
45
+ * - `promise` — resolves with `{ code, state }` on success, rejects on timeout/error
46
+ * - `shutdown()` — forcibly close the server
47
+ */
48
+ export function startCallbackServer(opts) {
49
+ let server;
50
+ let timer;
51
+ const promise = new Promise((resolve, reject) => {
52
+ server = createServer((req, res) => {
53
+ if (!req.url || !req.url.startsWith('/callback')) {
54
+ res.writeHead(404, { 'Content-Type': 'text/plain' });
55
+ res.end('Not found');
56
+ return;
57
+ }
58
+ const url = new URL(req.url, `http://localhost`);
59
+ const code = url.searchParams.get('code');
60
+ const state = url.searchParams.get('state');
61
+ const error = url.searchParams.get('error');
62
+ const errorDescription = url.searchParams.get('error_description');
63
+ if (error) {
64
+ res.writeHead(200, { 'Content-Type': 'text/html' });
65
+ res.end(ERROR_HTML(errorDescription || error));
66
+ cleanup();
67
+ reject(new Error(`OAuth error: ${errorDescription || error}`));
68
+ return;
69
+ }
70
+ if (!code || !state) {
71
+ res.writeHead(400, { 'Content-Type': 'text/html' });
72
+ res.end(ERROR_HTML('Missing code or state parameter.'));
73
+ return;
74
+ }
75
+ if (state !== opts.expectedState) {
76
+ res.writeHead(400, { 'Content-Type': 'text/html' });
77
+ res.end(ERROR_HTML('State mismatch — possible CSRF attack.'));
78
+ return;
79
+ }
80
+ res.writeHead(200, { 'Content-Type': 'text/html' });
81
+ res.end(SUCCESS_HTML);
82
+ cleanup();
83
+ resolve({ code, state });
84
+ });
85
+ server.listen(0, '127.0.0.1', () => {
86
+ const addr = server.address();
87
+ const port = typeof addr === 'object' && addr ? addr.port : 0;
88
+ opts.onListening?.(port);
89
+ });
90
+ server.on('error', (err) => {
91
+ cleanup();
92
+ reject(err);
93
+ });
94
+ timer = setTimeout(() => {
95
+ cleanup();
96
+ reject(new Error(`OAuth callback timed out after ${Math.round(opts.timeoutMs / 1000)}s. Please try again.`));
97
+ }, opts.timeoutMs);
98
+ });
99
+ function cleanup() {
100
+ clearTimeout(timer);
101
+ try {
102
+ server?.close();
103
+ }
104
+ catch { /* ignore */ }
105
+ }
106
+ return {
107
+ promise,
108
+ shutdown: cleanup,
109
+ };
110
+ }
111
+ //# sourceMappingURL=callback-server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"callback-server.js","sourceRoot":"","sources":["../../../../src/core/llm/auth/callback-server.ts"],"names":[],"mappings":"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"}
@@ -6,4 +6,14 @@ export type { AuthMethod, OAuthTokenSet, OAuthProviderConfig, IOAuthTokenStore,
6
6
  export { FileTokenStore } from './FileTokenStore.js';
7
7
  export { OpenAIOAuthFlow } from './OpenAIOAuthFlow.js';
8
8
  export type { OpenAIOAuthFlowOptions } from './OpenAIOAuthFlow.js';
9
+ export { BrowserOAuthFlow } from './BrowserOAuthFlow.js';
10
+ export type { BrowserOAuthConfig, BrowserOAuthFlowOptions } from './BrowserOAuthFlow.js';
11
+ export { TwitterOAuthFlow } from './TwitterOAuthFlow.js';
12
+ export type { TwitterOAuthFlowOptions } from './TwitterOAuthFlow.js';
13
+ export { InstagramOAuthFlow } from './InstagramOAuthFlow.js';
14
+ export type { InstagramOAuthFlowOptions } from './InstagramOAuthFlow.js';
15
+ export { isTokenValid, openBrowser } from './utils.js';
16
+ export { startCallbackServer } from './callback-server.js';
17
+ export type { CallbackResult, CallbackServerOptions } from './callback-server.js';
18
+ export { generateCodeVerifier, generateCodeChallenge, generateState } from './pkce.js';
9
19
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/core/llm/auth/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,YAAY,EACV,UAAU,EACV,aAAa,EACb,mBAAmB,EACnB,gBAAgB,EAChB,UAAU,GACX,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACvD,YAAY,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/core/llm/auth/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,YAAY,EACV,UAAU,EACV,aAAa,EACb,mBAAmB,EACnB,gBAAgB,EAChB,UAAU,GACX,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACvD,YAAY,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAGnE,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AACzD,YAAY,EAAE,kBAAkB,EAAE,uBAAuB,EAAE,MAAM,uBAAuB,CAAC;AACzF,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AACzD,YAAY,EAAE,uBAAuB,EAAE,MAAM,uBAAuB,CAAC;AACrE,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAC7D,YAAY,EAAE,yBAAyB,EAAE,MAAM,yBAAyB,CAAC;AAGzE,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACvD,OAAO,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAC3D,YAAY,EAAE,cAAc,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAClF,OAAO,EAAE,oBAAoB,EAAE,qBAAqB,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC"}
@@ -4,4 +4,12 @@
4
4
  */
5
5
  export { FileTokenStore } from './FileTokenStore.js';
6
6
  export { OpenAIOAuthFlow } from './OpenAIOAuthFlow.js';
7
+ // Browser-based OAuth 2.0 flows
8
+ export { BrowserOAuthFlow } from './BrowserOAuthFlow.js';
9
+ export { TwitterOAuthFlow } from './TwitterOAuthFlow.js';
10
+ export { InstagramOAuthFlow } from './InstagramOAuthFlow.js';
11
+ // Utilities
12
+ export { isTokenValid, openBrowser } from './utils.js';
13
+ export { startCallbackServer } from './callback-server.js';
14
+ export { generateCodeVerifier, generateCodeChallenge, generateState } from './pkce.js';
7
15
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/core/llm/auth/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAUH,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/core/llm/auth/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAUH,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAGvD,gCAAgC;AAChC,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAEzD,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAEzD,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAG7D,YAAY;AACZ,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACvD,OAAO,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAE3D,OAAO,EAAE,oBAAoB,EAAE,qBAAqB,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * @fileoverview PKCE (Proof Key for Code Exchange) utilities for OAuth 2.0.
3
+ * @module agentos/core/llm/auth/pkce
4
+ */
5
+ /**
6
+ * Generate a cryptographically random code verifier for PKCE.
7
+ * @param length Number of random bytes (output will be base64url-encoded, up to 128 chars).
8
+ */
9
+ export declare function generateCodeVerifier(length?: number): string;
10
+ /**
11
+ * Derive a S256 code challenge from a code verifier.
12
+ */
13
+ export declare function generateCodeChallenge(verifier: string): string;
14
+ /**
15
+ * Generate a random state parameter for CSRF protection.
16
+ */
17
+ export declare function generateState(): string;
18
+ //# sourceMappingURL=pkce.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pkce.d.ts","sourceRoot":"","sources":["../../../../src/core/llm/auth/pkce.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,SAAK,GAAG,MAAM,CAExD;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAE9D;AAED;;GAEG;AACH,wBAAgB,aAAa,IAAI,MAAM,CAEtC"}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * @fileoverview PKCE (Proof Key for Code Exchange) utilities for OAuth 2.0.
3
+ * @module agentos/core/llm/auth/pkce
4
+ */
5
+ import { randomBytes, createHash } from 'node:crypto';
6
+ /**
7
+ * Generate a cryptographically random code verifier for PKCE.
8
+ * @param length Number of random bytes (output will be base64url-encoded, up to 128 chars).
9
+ */
10
+ export function generateCodeVerifier(length = 64) {
11
+ return randomBytes(length).toString('base64url').slice(0, 128);
12
+ }
13
+ /**
14
+ * Derive a S256 code challenge from a code verifier.
15
+ */
16
+ export function generateCodeChallenge(verifier) {
17
+ return createHash('sha256').update(verifier).digest('base64url');
18
+ }
19
+ /**
20
+ * Generate a random state parameter for CSRF protection.
21
+ */
22
+ export function generateState() {
23
+ return randomBytes(32).toString('hex');
24
+ }
25
+ //# sourceMappingURL=pkce.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pkce.js","sourceRoot":"","sources":["../../../../src/core/llm/auth/pkce.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEtD;;;GAGG;AACH,MAAM,UAAU,oBAAoB,CAAC,MAAM,GAAG,EAAE;IAC9C,OAAO,WAAW,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;AACjE,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,qBAAqB,CAAC,QAAgB;IACpD,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;AACnE,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,aAAa;IAC3B,OAAO,WAAW,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;AACzC,CAAC"}
@@ -10,6 +10,8 @@ export interface OAuthTokenSet {
10
10
  refreshToken?: string;
11
11
  /** Unix epoch milliseconds when the access token expires. */
12
12
  expiresAt: number;
13
+ /** Provider-specific metadata (e.g., igUserId for Instagram). */
14
+ metadata?: Record<string, string>;
13
15
  }
14
16
  /** Provider-specific OAuth configuration. */
15
17
  export interface OAuthProviderConfig {
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/core/llm/auth/types.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,iDAAiD;AACjD,MAAM,MAAM,UAAU,GAAG,SAAS,GAAG,OAAO,CAAC;AAE7C,8BAA8B;AAC9B,MAAM,WAAW,aAAa;IAC5B,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,6DAA6D;IAC7D,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,6CAA6C;AAC7C,MAAM,WAAW,mBAAmB;IAClC,QAAQ,EAAE,MAAM,CAAC;IACjB,4DAA4D;IAC5D,kBAAkB,EAAE,MAAM,CAAC;IAC3B,wEAAwE;IACxE,mBAAmB,EAAE,MAAM,CAAC;IAC5B,+DAA+D;IAC/D,aAAa,EAAE,MAAM,CAAC;IACtB,+CAA+C;IAC/C,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,2CAA2C;AAC3C,MAAM,WAAW,gBAAgB;IAC/B,IAAI,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC,CAAC;IACxD,IAAI,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/D,KAAK,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC1C;AAED,qDAAqD;AACrD,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAE5B,iEAAiE;IACjE,YAAY,IAAI,OAAO,CAAC,aAAa,CAAC,CAAC;IAEvC,sEAAsE;IACtE,OAAO,CAAC,MAAM,EAAE,aAAa,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC;IAEvD,sEAAsE;IACtE,OAAO,CAAC,MAAM,EAAE,aAAa,GAAG,OAAO,CAAC;IAExC;;;;OAIG;IACH,cAAc,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC;CACnC"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/core/llm/auth/types.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,iDAAiD;AACjD,MAAM,MAAM,UAAU,GAAG,SAAS,GAAG,OAAO,CAAC;AAE7C,8BAA8B;AAC9B,MAAM,WAAW,aAAa;IAC5B,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,6DAA6D;IAC7D,SAAS,EAAE,MAAM,CAAC;IAClB,iEAAiE;IACjE,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACnC;AAED,6CAA6C;AAC7C,MAAM,WAAW,mBAAmB;IAClC,QAAQ,EAAE,MAAM,CAAC;IACjB,4DAA4D;IAC5D,kBAAkB,EAAE,MAAM,CAAC;IAC3B,wEAAwE;IACxE,mBAAmB,EAAE,MAAM,CAAC;IAC5B,+DAA+D;IAC/D,aAAa,EAAE,MAAM,CAAC;IACtB,+CAA+C;IAC/C,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,2CAA2C;AAC3C,MAAM,WAAW,gBAAgB;IAC/B,IAAI,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC,CAAC;IACxD,IAAI,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/D,KAAK,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC1C;AAED,qDAAqD;AACrD,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAE5B,iEAAiE;IACjE,YAAY,IAAI,OAAO,CAAC,aAAa,CAAC,CAAC;IAEvC,sEAAsE;IACtE,OAAO,CAAC,MAAM,EAAE,aAAa,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC;IAEvD,sEAAsE;IACtE,OAAO,CAAC,MAAM,EAAE,aAAa,GAAG,OAAO,CAAC;IAExC;;;;OAIG;IACH,cAAc,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC;CACnC"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * @fileoverview Shared OAuth utilities.
3
+ * @module agentos/core/llm/auth/utils
4
+ */
5
+ import type { OAuthTokenSet } from './types.js';
6
+ /**
7
+ * Check whether an OAuth token set is still valid (not expired, with buffer).
8
+ * Provider-agnostic — works with any OAuthTokenSet.
9
+ */
10
+ export declare function isTokenValid(tokens: OAuthTokenSet, bufferMs?: number): boolean;
11
+ /**
12
+ * Attempt to open a URL in the user's default browser.
13
+ * Returns true if the command was launched, false on failure (e.g., headless environment).
14
+ */
15
+ export declare function openBrowser(url: string): Promise<boolean>;
16
+ //# sourceMappingURL=utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../../src/core/llm/auth/utils.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAKhD;;;GAGG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,aAAa,EAAE,QAAQ,SAA4B,GAAG,OAAO,CAEjG;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAiBzD"}
@@ -0,0 +1,38 @@
1
+ /**
2
+ * @fileoverview Shared OAuth utilities.
3
+ * @module agentos/core/llm/auth/utils
4
+ */
5
+ import { exec } from 'node:child_process';
6
+ import { platform } from 'node:os';
7
+ /** Default buffer in ms before expiry to consider token invalid (5 minutes). */
8
+ const DEFAULT_REFRESH_BUFFER_MS = 5 * 60 * 1000;
9
+ /**
10
+ * Check whether an OAuth token set is still valid (not expired, with buffer).
11
+ * Provider-agnostic — works with any OAuthTokenSet.
12
+ */
13
+ export function isTokenValid(tokens, bufferMs = DEFAULT_REFRESH_BUFFER_MS) {
14
+ return Date.now() < tokens.expiresAt - bufferMs;
15
+ }
16
+ /**
17
+ * Attempt to open a URL in the user's default browser.
18
+ * Returns true if the command was launched, false on failure (e.g., headless environment).
19
+ */
20
+ export function openBrowser(url) {
21
+ return new Promise((resolve) => {
22
+ const os = platform();
23
+ let cmd;
24
+ if (os === 'darwin') {
25
+ cmd = `open "${url}"`;
26
+ }
27
+ else if (os === 'win32') {
28
+ cmd = `start "" "${url}"`;
29
+ }
30
+ else {
31
+ cmd = `xdg-open "${url}"`;
32
+ }
33
+ exec(cmd, { timeout: 5000 }, (err) => {
34
+ resolve(!err);
35
+ });
36
+ });
37
+ }
38
+ //# sourceMappingURL=utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.js","sourceRoot":"","sources":["../../../../src/core/llm/auth/utils.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,oBAAoB,CAAC;AAC1C,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAGnC,gFAAgF;AAChF,MAAM,yBAAyB,GAAG,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC;AAEhD;;;GAGG;AACH,MAAM,UAAU,YAAY,CAAC,MAAqB,EAAE,QAAQ,GAAG,yBAAyB;IACtF,OAAO,IAAI,CAAC,GAAG,EAAE,GAAG,MAAM,CAAC,SAAS,GAAG,QAAQ,CAAC;AAClD,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,WAAW,CAAC,GAAW;IACrC,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;QAC7B,MAAM,EAAE,GAAG,QAAQ,EAAE,CAAC;QACtB,IAAI,GAAW,CAAC;QAEhB,IAAI,EAAE,KAAK,QAAQ,EAAE,CAAC;YACpB,GAAG,GAAG,SAAS,GAAG,GAAG,CAAC;QACxB,CAAC;aAAM,IAAI,EAAE,KAAK,OAAO,EAAE,CAAC;YAC1B,GAAG,GAAG,aAAa,GAAG,GAAG,CAAC;QAC5B,CAAC;aAAM,CAAC;YACN,GAAG,GAAG,aAAa,GAAG,GAAG,CAAC;QAC5B,CAAC;QAED,IAAI,CAAC,GAAG,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,CAAC,GAAG,EAAE,EAAE;YACnC,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC;QAChB,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@framers/agentos",
3
- "version": "0.1.37",
3
+ "version": "0.1.39",
4
4
  "description": "Modular AgentOS orchestration library",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",