@zhafron/opencode-iflow-auth 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,110 @@
1
+ import { existsSync, readFileSync, writeFileSync, mkdirSync } from 'node:fs';
2
+ import { join, dirname } from 'node:path';
3
+ import { homedir } from 'node:os';
4
+ import { AccountSelectionStrategySchema, IFlowAuthMethodSchema, IFlowConfigSchema, DEFAULT_CONFIG } from './schema.js';
5
+ import * as logger from '../logger.js';
6
+ function getConfigDir() {
7
+ const platform = process.platform;
8
+ if (platform === 'win32') {
9
+ return join(process.env.APPDATA || join(homedir(), 'AppData', 'Roaming'), 'opencode');
10
+ }
11
+ const xdgConfig = process.env.XDG_CONFIG_HOME || join(homedir(), '.config');
12
+ return join(xdgConfig, 'opencode');
13
+ }
14
+ export function getConfigPath() {
15
+ return join(getConfigDir(), 'iflow.json');
16
+ }
17
+ function ensureUserConfigTemplate() {
18
+ const path = getConfigPath();
19
+ if (!existsSync(path)) {
20
+ try {
21
+ mkdirSync(dirname(path), { recursive: true });
22
+ writeFileSync(path, JSON.stringify(DEFAULT_CONFIG, null, 2), 'utf-8');
23
+ logger.log(`Created default config template at ${path}`);
24
+ }
25
+ catch (error) {
26
+ logger.warn(`Failed to create config template at ${path}: ${String(error)}`);
27
+ }
28
+ }
29
+ }
30
+ function loadConfigFile(path) {
31
+ try {
32
+ if (!existsSync(path)) {
33
+ return null;
34
+ }
35
+ const content = readFileSync(path, 'utf-8');
36
+ const rawConfig = JSON.parse(content);
37
+ const result = IFlowConfigSchema.partial().safeParse(rawConfig);
38
+ if (!result.success) {
39
+ const issues = result.error.issues.map((i) => `${i.path.join('.')}: ${i.message}`).join(', ');
40
+ logger.warn(`Config validation error at ${path}: ${issues}`);
41
+ return null;
42
+ }
43
+ return result.data;
44
+ }
45
+ catch (error) {
46
+ if (error instanceof SyntaxError) {
47
+ logger.warn(`Invalid JSON in config file ${path}: ${error.message}`);
48
+ }
49
+ else {
50
+ logger.warn(`Failed to load config file ${path}: ${String(error)}`);
51
+ }
52
+ return null;
53
+ }
54
+ }
55
+ function mergeConfigs(base, override) {
56
+ return {
57
+ ...base,
58
+ ...override
59
+ };
60
+ }
61
+ function parseBooleanEnv(value, fallback) {
62
+ if (value === undefined) {
63
+ return fallback;
64
+ }
65
+ if (value === '1' || value === 'true') {
66
+ return true;
67
+ }
68
+ if (value === '0' || value === 'false') {
69
+ return false;
70
+ }
71
+ return fallback;
72
+ }
73
+ function parseNumberEnv(value, fallback) {
74
+ if (value === undefined) {
75
+ return fallback;
76
+ }
77
+ const parsed = Number(value);
78
+ if (isNaN(parsed)) {
79
+ return fallback;
80
+ }
81
+ return parsed;
82
+ }
83
+ function applyEnvOverrides(config) {
84
+ const env = process.env;
85
+ return {
86
+ ...config,
87
+ default_auth_method: env.IFLOW_DEFAULT_AUTH_METHOD
88
+ ? IFlowAuthMethodSchema.catch('oauth').parse(env.IFLOW_DEFAULT_AUTH_METHOD)
89
+ : config.default_auth_method,
90
+ account_selection_strategy: env.IFLOW_ACCOUNT_SELECTION_STRATEGY
91
+ ? AccountSelectionStrategySchema.catch('round-robin').parse(env.IFLOW_ACCOUNT_SELECTION_STRATEGY)
92
+ : config.account_selection_strategy,
93
+ auth_server_port_start: parseNumberEnv(env.IFLOW_AUTH_SERVER_PORT_START, config.auth_server_port_start),
94
+ auth_server_port_range: parseNumberEnv(env.IFLOW_AUTH_SERVER_PORT_RANGE, config.auth_server_port_range),
95
+ max_request_iterations: parseNumberEnv(env.IFLOW_MAX_REQUEST_ITERATIONS, config.max_request_iterations),
96
+ request_timeout_ms: parseNumberEnv(env.IFLOW_REQUEST_TIMEOUT_MS, config.request_timeout_ms),
97
+ enable_log_api_request: parseBooleanEnv(env.IFLOW_ENABLE_LOG_API_REQUEST, config.enable_log_api_request)
98
+ };
99
+ }
100
+ export function loadConfig() {
101
+ ensureUserConfigTemplate();
102
+ let config = { ...DEFAULT_CONFIG };
103
+ const userConfigPath = getConfigPath();
104
+ const userConfig = loadConfigFile(userConfigPath);
105
+ if (userConfig) {
106
+ config = mergeConfigs(config, userConfig);
107
+ }
108
+ config = applyEnvOverrides(config);
109
+ return config;
110
+ }
@@ -0,0 +1,35 @@
1
+ import { z } from 'zod';
2
+ export declare const AccountSelectionStrategySchema: z.ZodEnum<["sticky", "round-robin"]>;
3
+ export type AccountSelectionStrategy = z.infer<typeof AccountSelectionStrategySchema>;
4
+ export declare const IFlowAuthMethodSchema: z.ZodEnum<["oauth", "apikey"]>;
5
+ export type IFlowAuthMethod = z.infer<typeof IFlowAuthMethodSchema>;
6
+ export declare const IFlowConfigSchema: z.ZodObject<{
7
+ $schema: z.ZodOptional<z.ZodString>;
8
+ default_auth_method: z.ZodDefault<z.ZodEnum<["oauth", "apikey"]>>;
9
+ account_selection_strategy: z.ZodDefault<z.ZodEnum<["sticky", "round-robin"]>>;
10
+ auth_server_port_start: z.ZodDefault<z.ZodNumber>;
11
+ auth_server_port_range: z.ZodDefault<z.ZodNumber>;
12
+ max_request_iterations: z.ZodDefault<z.ZodNumber>;
13
+ request_timeout_ms: z.ZodDefault<z.ZodNumber>;
14
+ enable_log_api_request: z.ZodDefault<z.ZodBoolean>;
15
+ }, "strip", z.ZodTypeAny, {
16
+ default_auth_method: "oauth" | "apikey";
17
+ account_selection_strategy: "sticky" | "round-robin";
18
+ auth_server_port_start: number;
19
+ auth_server_port_range: number;
20
+ max_request_iterations: number;
21
+ request_timeout_ms: number;
22
+ enable_log_api_request: boolean;
23
+ $schema?: string | undefined;
24
+ }, {
25
+ $schema?: string | undefined;
26
+ default_auth_method?: "oauth" | "apikey" | undefined;
27
+ account_selection_strategy?: "sticky" | "round-robin" | undefined;
28
+ auth_server_port_start?: number | undefined;
29
+ auth_server_port_range?: number | undefined;
30
+ max_request_iterations?: number | undefined;
31
+ request_timeout_ms?: number | undefined;
32
+ enable_log_api_request?: boolean | undefined;
33
+ }>;
34
+ export type IFlowConfig = z.infer<typeof IFlowConfigSchema>;
35
+ export declare const DEFAULT_CONFIG: IFlowConfig;
@@ -0,0 +1,22 @@
1
+ import { z } from 'zod';
2
+ export const AccountSelectionStrategySchema = z.enum(['sticky', 'round-robin']);
3
+ export const IFlowAuthMethodSchema = z.enum(['oauth', 'apikey']);
4
+ export const IFlowConfigSchema = z.object({
5
+ $schema: z.string().optional(),
6
+ default_auth_method: IFlowAuthMethodSchema.default('oauth'),
7
+ account_selection_strategy: AccountSelectionStrategySchema.default('round-robin'),
8
+ auth_server_port_start: z.number().min(1024).max(65535).default(8087),
9
+ auth_server_port_range: z.number().min(1).max(100).default(10),
10
+ max_request_iterations: z.number().min(10).max(1000).default(50),
11
+ request_timeout_ms: z.number().min(60000).max(600000).default(300000),
12
+ enable_log_api_request: z.boolean().default(false)
13
+ });
14
+ export const DEFAULT_CONFIG = {
15
+ default_auth_method: 'oauth',
16
+ account_selection_strategy: 'round-robin',
17
+ auth_server_port_start: 8087,
18
+ auth_server_port_range: 10,
19
+ max_request_iterations: 50,
20
+ request_timeout_ms: 300000,
21
+ enable_log_api_request: false
22
+ };
@@ -0,0 +1,14 @@
1
+ export declare class IFlowAuthError extends Error {
2
+ code: string;
3
+ constructor(message: string, code: string);
4
+ }
5
+ export declare class IFlowTokenRefreshError extends IFlowAuthError {
6
+ constructor(message: string);
7
+ }
8
+ export declare class IFlowApiKeyInvalidError extends IFlowAuthError {
9
+ constructor(message: string);
10
+ }
11
+ export declare class IFlowRateLimitError extends IFlowAuthError {
12
+ retryAfter: number;
13
+ constructor(message: string, retryAfter: number);
14
+ }
@@ -0,0 +1,25 @@
1
+ export class IFlowAuthError extends Error {
2
+ code;
3
+ constructor(message, code) {
4
+ super(message);
5
+ this.code = code;
6
+ this.name = 'IFlowAuthError';
7
+ }
8
+ }
9
+ export class IFlowTokenRefreshError extends IFlowAuthError {
10
+ constructor(message) {
11
+ super(message, 'TOKEN_REFRESH_FAILED');
12
+ }
13
+ }
14
+ export class IFlowApiKeyInvalidError extends IFlowAuthError {
15
+ constructor(message) {
16
+ super(message, 'API_KEY_INVALID');
17
+ }
18
+ }
19
+ export class IFlowRateLimitError extends IFlowAuthError {
20
+ retryAfter;
21
+ constructor(message, retryAfter) {
22
+ super(message, 'RATE_LIMIT');
23
+ this.retryAfter = retryAfter;
24
+ }
25
+ }
@@ -0,0 +1,8 @@
1
+ export declare function log(message: string, ...args: unknown[]): void;
2
+ export declare function error(message: string, ...args: unknown[]): void;
3
+ export declare function warn(message: string, ...args: unknown[]): void;
4
+ export declare function debug(message: string, ...args: unknown[]): void;
5
+ export declare function logApiRequest(data: any, timestamp: string): void;
6
+ export declare function logApiResponse(data: any, timestamp: string): void;
7
+ export declare function logApiError(requestData: any, responseData: any, timestamp: string): void;
8
+ export declare function getTimestamp(): string;
@@ -0,0 +1,63 @@
1
+ import { appendFileSync, mkdirSync, writeFileSync } from 'node:fs';
2
+ import { homedir } from 'node:os';
3
+ import { join } from 'node:path';
4
+ const getLogDir = () => {
5
+ const platform = process.platform;
6
+ const base = platform === 'win32'
7
+ ? join(process.env.APPDATA || join(homedir(), 'AppData', 'Roaming'), 'opencode')
8
+ : join(process.env.XDG_CONFIG_HOME || join(homedir(), '.config'), 'opencode');
9
+ return join(base, 'iflow-logs');
10
+ };
11
+ const writeToFile = (level, message, ...args) => {
12
+ try {
13
+ const dir = getLogDir();
14
+ mkdirSync(dir, { recursive: true });
15
+ const path = join(dir, 'plugin.log');
16
+ const timestamp = new Date().toISOString();
17
+ const content = `[${timestamp}] ${level}: ${message} ${args.map((a) => (typeof a === 'object' ? JSON.stringify(a) : String(a))).join(' ')}\n`;
18
+ appendFileSync(path, content);
19
+ }
20
+ catch (e) { }
21
+ };
22
+ const writeApiLog = (type, data, timestamp, isError = false) => {
23
+ try {
24
+ const dir = getLogDir();
25
+ mkdirSync(dir, { recursive: true });
26
+ const prefix = isError ? 'error_' : '';
27
+ const filename = `${prefix}${timestamp}_${type}.json`;
28
+ const path = join(dir, filename);
29
+ const content = JSON.stringify(data, null, 2);
30
+ writeFileSync(path, content);
31
+ }
32
+ catch (e) { }
33
+ };
34
+ export function log(message, ...args) {
35
+ writeToFile('INFO', message, ...args);
36
+ }
37
+ export function error(message, ...args) {
38
+ writeToFile('ERROR', message, ...args);
39
+ }
40
+ export function warn(message, ...args) {
41
+ writeToFile('WARN', message, ...args);
42
+ }
43
+ export function debug(message, ...args) {
44
+ if (process.env.DEBUG) {
45
+ writeToFile('DEBUG', message, ...args);
46
+ }
47
+ }
48
+ export function logApiRequest(data, timestamp) {
49
+ writeApiLog('request', data, timestamp);
50
+ }
51
+ export function logApiResponse(data, timestamp) {
52
+ writeApiLog('response', data, timestamp);
53
+ }
54
+ export function logApiError(requestData, responseData, timestamp) {
55
+ writeApiLog('request', requestData, timestamp, true);
56
+ writeApiLog('response', responseData, timestamp, true);
57
+ const errorType = responseData.status ? `HTTP ${responseData.status}` : 'Network Error';
58
+ const email = requestData.email || 'unknown';
59
+ error(`${errorType} on ${email} - See error_${timestamp}_request.json`);
60
+ }
61
+ export function getTimestamp() {
62
+ return new Date().toISOString().replace(/[:.]/g, '-');
63
+ }
@@ -0,0 +1,7 @@
1
+ import type { IFlowOAuthTokenResult } from '../iflow/oauth';
2
+ export interface OAuthServerResult {
3
+ url: string;
4
+ redirectUri: string;
5
+ waitForAuth: () => Promise<IFlowOAuthTokenResult>;
6
+ }
7
+ export declare function startOAuthServer(authUrl: string, state: string, redirectUri: string, portStart: number, portRange: number): Promise<OAuthServerResult>;
@@ -0,0 +1,98 @@
1
+ import { createServer } from 'node:http';
2
+ import { exchangeOAuthCode } from '../iflow/oauth';
3
+ export async function startOAuthServer(authUrl, state, redirectUri, portStart, portRange) {
4
+ let resolveAuth;
5
+ let rejectAuth;
6
+ let timeoutHandle;
7
+ const authPromise = new Promise((resolve, reject) => {
8
+ resolveAuth = resolve;
9
+ rejectAuth = reject;
10
+ });
11
+ let server = null;
12
+ let actualPort = portStart;
13
+ const handler = async (req, res) => {
14
+ const url = new URL(req.url || '', `http://localhost:${actualPort}`);
15
+ if (url.pathname === '/oauth2callback') {
16
+ const code = url.searchParams.get('code');
17
+ const returnedState = url.searchParams.get('state');
18
+ const error = url.searchParams.get('error');
19
+ if (error) {
20
+ res.writeHead(400, { 'Content-Type': 'text/html; charset=utf-8' });
21
+ res.end(`<html><body><h1>Authorization failed: ${error}</h1></body></html>`);
22
+ clearTimeout(timeoutHandle);
23
+ rejectAuth(new Error(`Authorization failed: ${error}`));
24
+ setTimeout(() => server?.close(), 1000);
25
+ return;
26
+ }
27
+ if (!code || !returnedState) {
28
+ res.writeHead(400, { 'Content-Type': 'text/html; charset=utf-8' });
29
+ res.end('<html><body><h1>Error: Missing code or state</h1></body></html>');
30
+ clearTimeout(timeoutHandle);
31
+ rejectAuth(new Error('Missing code or state in callback'));
32
+ setTimeout(() => server?.close(), 1000);
33
+ return;
34
+ }
35
+ if (returnedState !== state) {
36
+ res.writeHead(400, { 'Content-Type': 'text/html; charset=utf-8' });
37
+ res.end('<html><body><h1>Error: State mismatch</h1></body></html>');
38
+ clearTimeout(timeoutHandle);
39
+ rejectAuth(new Error('State mismatch'));
40
+ setTimeout(() => server?.close(), 1000);
41
+ return;
42
+ }
43
+ try {
44
+ const result = await exchangeOAuthCode(code, redirectUri);
45
+ res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
46
+ res.end(`<html><body><h1>Authentication successful!</h1><p>Account: ${result.email}</p><p>You can close this window.</p></body></html>`);
47
+ clearTimeout(timeoutHandle);
48
+ setTimeout(() => {
49
+ resolveAuth(result);
50
+ setTimeout(() => server?.close(), 1000);
51
+ }, 100);
52
+ }
53
+ catch (error) {
54
+ res.writeHead(500, { 'Content-Type': 'text/html; charset=utf-8' });
55
+ res.end(`<html><body><h1>Error: ${error.message}</h1></body></html>`);
56
+ clearTimeout(timeoutHandle);
57
+ rejectAuth(error);
58
+ setTimeout(() => server?.close(), 1000);
59
+ }
60
+ }
61
+ else {
62
+ res.writeHead(204);
63
+ res.end();
64
+ }
65
+ };
66
+ for (let port = portStart; port < portStart + portRange; port++) {
67
+ try {
68
+ server = createServer(handler);
69
+ await new Promise((resolve, reject) => {
70
+ server.listen(port, '0.0.0.0', () => {
71
+ actualPort = port;
72
+ resolve();
73
+ });
74
+ server.on('error', reject);
75
+ });
76
+ break;
77
+ }
78
+ catch (error) {
79
+ if (error.code !== 'EADDRINUSE' || port === portStart + portRange - 1) {
80
+ throw error;
81
+ }
82
+ }
83
+ }
84
+ if (!server) {
85
+ throw new Error('Failed to start OAuth callback server');
86
+ }
87
+ timeoutHandle = setTimeout(() => {
88
+ if (server?.listening) {
89
+ rejectAuth(new Error('OAuth timeout: No response after 10 minutes'));
90
+ server.close();
91
+ }
92
+ }, 10 * 60 * 1000);
93
+ return {
94
+ url: authUrl,
95
+ redirectUri,
96
+ waitForAuth: () => authPromise
97
+ };
98
+ }
@@ -0,0 +1,4 @@
1
+ import type { AccountStorage } from './types';
2
+ export declare function getStoragePath(): string;
3
+ export declare function loadAccounts(): Promise<AccountStorage>;
4
+ export declare function saveAccounts(storage: AccountStorage): Promise<void>;
@@ -0,0 +1,91 @@
1
+ import { promises as fs } from 'node:fs';
2
+ import { dirname, join } from 'node:path';
3
+ import { randomBytes } from 'node:crypto';
4
+ import { homedir } from 'node:os';
5
+ import lockfile from 'proper-lockfile';
6
+ import * as logger from './logger';
7
+ const LOCK_OPTIONS = {
8
+ stale: 10000,
9
+ retries: { retries: 5, minTimeout: 100, maxTimeout: 1000, factor: 2 }
10
+ };
11
+ function getBaseDir() {
12
+ const platform = process.platform;
13
+ if (platform === 'win32') {
14
+ return join(process.env.APPDATA || join(homedir(), 'AppData', 'Roaming'), 'opencode');
15
+ }
16
+ const xdgConfig = process.env.XDG_CONFIG_HOME || join(homedir(), '.config');
17
+ return join(xdgConfig, 'opencode');
18
+ }
19
+ export function getStoragePath() {
20
+ return join(getBaseDir(), 'iflow-accounts.json');
21
+ }
22
+ async function withLock(path, fn) {
23
+ try {
24
+ await fs.mkdir(dirname(path), { recursive: true });
25
+ }
26
+ catch (error) {
27
+ logger.error(`Failed to create directory ${dirname(path)}`, error);
28
+ throw error;
29
+ }
30
+ try {
31
+ await fs.access(path);
32
+ }
33
+ catch {
34
+ try {
35
+ await fs.writeFile(path, '{}');
36
+ }
37
+ catch (error) {
38
+ logger.error(`Failed to initialize file ${path}`, error);
39
+ throw error;
40
+ }
41
+ }
42
+ let release = null;
43
+ try {
44
+ release = await lockfile.lock(path, LOCK_OPTIONS);
45
+ return await fn();
46
+ }
47
+ catch (error) {
48
+ logger.error(`File lock failed for ${path}`, error);
49
+ throw error;
50
+ }
51
+ finally {
52
+ if (release) {
53
+ try {
54
+ await release();
55
+ }
56
+ catch (error) {
57
+ logger.warn(`Failed to release lock for ${path}`, error);
58
+ }
59
+ }
60
+ }
61
+ }
62
+ export async function loadAccounts() {
63
+ const path = getStoragePath();
64
+ return withLock(path, async () => {
65
+ try {
66
+ const content = await fs.readFile(path, 'utf-8');
67
+ const parsed = JSON.parse(content);
68
+ if (!parsed || !Array.isArray(parsed.accounts)) {
69
+ return { version: 1, accounts: [], activeIndex: -1 };
70
+ }
71
+ return parsed;
72
+ }
73
+ catch {
74
+ return { version: 1, accounts: [], activeIndex: -1 };
75
+ }
76
+ });
77
+ }
78
+ export async function saveAccounts(storage) {
79
+ const path = getStoragePath();
80
+ try {
81
+ await withLock(path, async () => {
82
+ const tmp = `${path}.${randomBytes(6).toString('hex')}.tmp`;
83
+ await fs.writeFile(tmp, JSON.stringify(storage, null, 2));
84
+ await fs.rename(tmp, path);
85
+ });
86
+ }
87
+ catch (error) {
88
+ logger.error(`Failed to save accounts to ${path}`, error);
89
+ throw error;
90
+ }
91
+ }
@@ -0,0 +1,3 @@
1
+ import type { IFlowAuthDetails } from './types';
2
+ export declare function accessTokenExpired(expiresAt: number): boolean;
3
+ export declare function refreshAccessToken(auth: IFlowAuthDetails): Promise<IFlowAuthDetails>;
@@ -0,0 +1,26 @@
1
+ import { refreshOAuthToken } from '../iflow/oauth';
2
+ import { decodeRefreshToken, encodeRefreshToken } from './accounts';
3
+ export function accessTokenExpired(expiresAt) {
4
+ return Date.now() >= expiresAt - 60000;
5
+ }
6
+ export async function refreshAccessToken(auth) {
7
+ if (auth.authMethod === 'apikey') {
8
+ return auth;
9
+ }
10
+ if (auth.authMethod === 'oauth') {
11
+ const parts = decodeRefreshToken(auth.refresh);
12
+ if (!parts.refreshToken) {
13
+ throw new Error('No refresh token available');
14
+ }
15
+ const result = await refreshOAuthToken(parts.refreshToken);
16
+ return {
17
+ refresh: encodeRefreshToken({ refreshToken: result.refreshToken, authMethod: 'oauth' }),
18
+ access: result.accessToken,
19
+ expires: result.expiresAt,
20
+ authMethod: 'oauth',
21
+ apiKey: result.apiKey,
22
+ email: result.email
23
+ };
24
+ }
25
+ throw new Error(`Unknown auth method: ${auth.authMethod}`);
26
+ }
@@ -0,0 +1,55 @@
1
+ export type IFlowAuthMethod = 'oauth' | 'apikey';
2
+ export interface IFlowAuthDetails {
3
+ refresh: string;
4
+ access: string;
5
+ expires: number;
6
+ authMethod: IFlowAuthMethod;
7
+ apiKey: string;
8
+ email?: string;
9
+ }
10
+ export interface RefreshParts {
11
+ refreshToken?: string;
12
+ authMethod: IFlowAuthMethod;
13
+ }
14
+ export interface ManagedAccount {
15
+ id: string;
16
+ email: string;
17
+ authMethod: IFlowAuthMethod;
18
+ refreshToken?: string;
19
+ accessToken?: string;
20
+ expiresAt?: number;
21
+ apiKey: string;
22
+ rateLimitResetTime: number;
23
+ isHealthy: boolean;
24
+ unhealthyReason?: string;
25
+ recoveryTime?: number;
26
+ lastUsed?: number;
27
+ }
28
+ export interface AccountMetadata {
29
+ id: string;
30
+ email: string;
31
+ authMethod: IFlowAuthMethod;
32
+ refreshToken?: string;
33
+ accessToken?: string;
34
+ expiresAt?: number;
35
+ apiKey: string;
36
+ rateLimitResetTime: number;
37
+ isHealthy: boolean;
38
+ unhealthyReason?: string;
39
+ recoveryTime?: number;
40
+ }
41
+ export interface AccountStorage {
42
+ version: 1;
43
+ accounts: AccountMetadata[];
44
+ activeIndex: number;
45
+ }
46
+ export type AccountSelectionStrategy = 'sticky' | 'round-robin';
47
+ export interface IFlowPluginConfig {
48
+ default_auth_method: IFlowAuthMethod;
49
+ account_selection_strategy: AccountSelectionStrategy;
50
+ auth_server_port_start: number;
51
+ auth_server_port_range: number;
52
+ max_request_iterations: number;
53
+ request_timeout_ms: number;
54
+ enable_log_api_request: boolean;
55
+ }
File without changes
@@ -0,0 +1,32 @@
1
+ export declare const createIFlowPlugin: (id: string) => ({ client, directory }: any) => Promise<{
2
+ auth: {
3
+ provider: string;
4
+ loader: (getAuth: any) => Promise<{
5
+ apiKey: string;
6
+ baseURL: string;
7
+ fetch(input: any, init?: any): Promise<Response>;
8
+ }>;
9
+ methods: {
10
+ id: string;
11
+ label: string;
12
+ type: string;
13
+ authorize: (inputs?: any) => Promise<unknown>;
14
+ }[];
15
+ };
16
+ }>;
17
+ export declare const IFlowOAuthPlugin: ({ client, directory }: any) => Promise<{
18
+ auth: {
19
+ provider: string;
20
+ loader: (getAuth: any) => Promise<{
21
+ apiKey: string;
22
+ baseURL: string;
23
+ fetch(input: any, init?: any): Promise<Response>;
24
+ }>;
25
+ methods: {
26
+ id: string;
27
+ label: string;
28
+ type: string;
29
+ authorize: (inputs?: any) => Promise<unknown>;
30
+ }[];
31
+ };
32
+ }>;