@hira-core/sdk 1.0.2 → 1.0.3

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/dist/index.d.ts CHANGED
@@ -1,19 +1,37 @@
1
+ import * as _packages_shared from '@packages/shared';
2
+ import { ProfileOutputValue, IWorkerLogMessage, ProfileStatus, IWorkerOutputMessage } from '@packages/shared';
1
3
  import * as puppeteer from 'puppeteer-core';
2
4
  import { Browser, Page, Frame, ElementHandle } from 'puppeteer-core';
3
5
  import { EventEmitter } from 'events';
4
- import { IWorkerLogMessage, ProfileStatus } from '@packages/shared';
5
6
 
6
- interface IGpmProfile {
7
+ /**
8
+ * Unified profile interface — provider-agnostic.
9
+ * Both GPM and Hidemium (and future providers) map their native profiles to this.
10
+ */
11
+ interface IAntidetectProfile {
12
+ /** Unique ID (GPM: id, Hidemium: uuid) */
7
13
  id: string;
14
+ /** Human-readable profile name */
8
15
  name: string;
16
+ /** Which antidetect provider */
17
+ provider: "gpm" | "hidemium" | "genlogin";
18
+ /** Raw proxy string (format varies per provider) */
9
19
  raw_proxy?: string;
20
+ /** Browser engine */
10
21
  browser_type: "chromium" | "firefox";
22
+ /** Browser version string */
11
23
  browser_version: string;
24
+ /** Group/folder ID (if supported) */
12
25
  group_id?: string;
26
+ /** Local profile data path */
13
27
  profile_path: string;
28
+ /** User note */
14
29
  note: string;
30
+ /** ISO 8601 */
15
31
  created_at: string;
16
32
  }
33
+ /** @deprecated Use IAntidetectProfile instead */
34
+ type IGpmProfile = IAntidetectProfile;
17
35
  type IInputType = "text" | "number" | "boolean" | "select" | "textarea";
18
36
  type InputTypeMap = {
19
37
  text: string;
@@ -34,21 +52,178 @@ interface IInputField {
34
52
  value: string | number;
35
53
  }[];
36
54
  }
55
+ interface IOutputField {
56
+ index: number;
57
+ key: string;
58
+ label: string;
59
+ }
37
60
  interface IFlowConfig {
38
61
  globalInput: readonly IInputField[];
39
62
  profileInput: readonly IInputField[];
63
+ output?: readonly IOutputField[];
40
64
  }
65
+ /**
66
+ * Generic duplicate finder cho string property — duyệt recursive qua array,
67
+ * extract giá trị của property `P` và check xem có xuất hiện > 1 lần không.
68
+ */
69
+ type FindDuplicates<T extends readonly Record<string, any>[], P extends string, Seen extends string = never> = T extends readonly [
70
+ infer Head extends Record<string, any>,
71
+ ...infer Tail extends Record<string, any>[]
72
+ ] ? Head[P] extends string ? Head[P] extends Seen ? Head[P] | FindDuplicates<Tail, P, Seen> : FindDuplicates<Tail, P, Seen | Head[P]> : FindDuplicates<Tail, P, Seen> : never;
73
+ /**
74
+ * Duplicate finder cho number property (dùng cho output index).
75
+ * Convert number → template literal string để so sánh.
76
+ */
77
+ type FindDuplicateNumbers<T extends readonly Record<string, any>[], P extends string, Seen extends number = never> = T extends readonly [
78
+ infer Head extends Record<string, any>,
79
+ ...infer Tail extends Record<string, any>[]
80
+ ] ? Head[P] extends number ? Head[P] extends Seen ? Head[P] | FindDuplicateNumbers<Tail, P, Seen> : FindDuplicateNumbers<Tail, P, Seen | Head[P]> : FindDuplicateNumbers<Tail, P, Seen> : never;
81
+ /**
82
+ * Duplicate finder cho string | number property (dùng cho options value).
83
+ */
84
+ type FindDuplicateValues<T extends readonly Record<string, any>[], P extends string, Seen extends string | number = never> = T extends readonly [
85
+ infer Head extends Record<string, any>,
86
+ ...infer Tail extends Record<string, any>[]
87
+ ] ? Head[P] extends string | number ? Head[P] extends Seen ? Head[P] | FindDuplicateValues<Tail, P, Seen> : FindDuplicateValues<Tail, P, Seen | Head[P]> : FindDuplicateValues<Tail, P, Seen> : never;
88
+ type AssertUniqueKeysAndLabels<T extends readonly {
89
+ key: string;
90
+ label: string;
91
+ }[]> = FindDuplicates<T, "key"> extends never ? FindDuplicates<T, "label"> extends never ? T : readonly [
92
+ `❌ ERROR: Duplicate label(s) found: "${FindDuplicates<T, "label">}"`,
93
+ never
94
+ ] : FindDuplicates<T, "label"> extends never ? readonly [
95
+ `❌ ERROR: Duplicate key(s) found: "${FindDuplicates<T, "key">}"`,
96
+ never
97
+ ] : readonly [
98
+ `❌ ERROR: Duplicate key(s): "${FindDuplicates<T, "key">}" AND duplicate label(s): "${FindDuplicates<T, "label">}"`,
99
+ never
100
+ ];
101
+ type AssertUniqueOutputFields<T extends readonly {
102
+ index: number;
103
+ key: string;
104
+ label: string;
105
+ }[]> = FindDuplicateNumbers<T, "index"> extends never ? AssertUniqueKeysAndLabels<T> : readonly [
106
+ `❌ ERROR: Duplicate index(es) found: ${FindDuplicateNumbers<T, "index">}`,
107
+ never
108
+ ];
109
+ /**
110
+ * Check 1 options array: label unique + value unique.
111
+ * Trả T nếu OK, error tuple nếu duplicate.
112
+ */
113
+ type AssertUniqueOptions<T extends readonly {
114
+ label: string;
115
+ value: string | number;
116
+ }[]> = FindDuplicates<T, "label"> extends never ? FindDuplicateValues<T, "value"> extends never ? T : readonly [
117
+ `❌ ERROR: Duplicate option value(s) found: "${FindDuplicateValues<T, "value">}"`,
118
+ never
119
+ ] : FindDuplicateValues<T, "value"> extends never ? readonly [
120
+ `❌ ERROR: Duplicate option label(s) found: "${FindDuplicates<T, "label">}"`,
121
+ never
122
+ ] : readonly [
123
+ `❌ ERROR: Duplicate option label(s): "${FindDuplicates<T, "label">}" AND duplicate option value(s): "${FindDuplicateValues<T, "value">}"`,
124
+ never
125
+ ];
126
+ /**
127
+ * Map từng field trong input array — nếu field có `options`,
128
+ * validate options[].label + options[].value unique.
129
+ */
130
+ type ValidateInputOptions<T extends readonly IInputField[]> = {
131
+ readonly [I in keyof T]: T[I] extends {
132
+ options: infer O extends readonly {
133
+ label: string;
134
+ value: string | number;
135
+ }[];
136
+ } ? Omit<T[I], "options"> & {
137
+ options: AssertUniqueOptions<O>;
138
+ } : T[I];
139
+ };
140
+ /**
141
+ * Validate unique key + label cho input array.
142
+ * Nếu key/label trùng → trả error tuple, ngược lại → validate options.
143
+ */
144
+ type ValidateInputArray<T extends readonly IInputField[]> = FindDuplicates<T, "key"> extends never ? FindDuplicates<T, "label"> extends never ? ValidateInputOptions<T> : readonly [
145
+ `❌ ERROR: Duplicate label(s) found: "${FindDuplicates<T, "label">}"`,
146
+ never
147
+ ] : FindDuplicates<T, "label"> extends never ? readonly [
148
+ `❌ ERROR: Duplicate key(s) found: "${FindDuplicates<T, "key">}"`,
149
+ never
150
+ ] : readonly [
151
+ `❌ ERROR: Duplicate key(s): "${FindDuplicates<T, "key">}" AND duplicate label(s): "${FindDuplicates<T, "label">}"`,
152
+ never
153
+ ];
154
+ /**
155
+ * StrictFlowConfig — kiểm tra tất cả constraints:
156
+ * - globalInput: unique key + label + options (label, value) per field
157
+ * - profileInput: unique key + label + options (label, value) per field
158
+ * - output: unique key + label + index
159
+ */
160
+ type StrictFlowConfig<T extends IFlowConfig> = {
161
+ globalInput: ValidateInputArray<T["globalInput"]>;
162
+ profileInput: ValidateInputArray<T["profileInput"]>;
163
+ output: T["output"] extends readonly IOutputField[] ? AssertUniqueOutputFields<T["output"]> : T["output"];
164
+ };
165
+ /**
166
+ * Helper function — validate config at type level + return typed config.
167
+ * Dùng thay vì `as const satisfies IFlowConfig` để bắt duplicate key & label.
168
+ *
169
+ * @example
170
+ * ```ts
171
+ * // ✅ OK — không trùng
172
+ * const config = defineFlowConfig({
173
+ * globalInput: [
174
+ * { key: "url", label: "URL", type: "text" },
175
+ * ],
176
+ * profileInput: [
177
+ * { key: "user", label: "User", type: "text" },
178
+ * ],
179
+ * output: [
180
+ * { index: 0, key: "status", label: "Status" },
181
+ * { index: 1, key: "title", label: "Title" },
182
+ * ],
183
+ * });
184
+ *
185
+ * // ❌ TS Error — duplicate key "url" in globalInput
186
+ * const bad = defineFlowConfig({
187
+ * globalInput: [
188
+ * { key: "url", label: "URL 1", type: "text" },
189
+ * { key: "url", label: "URL 2", type: "text" },
190
+ * ],
191
+ * ...
192
+ * });
193
+ *
194
+ * // ❌ TS Error — duplicate label "Status" in output
195
+ * const bad2 = defineFlowConfig({
196
+ * output: [
197
+ * { index: 0, key: "status1", label: "Status" },
198
+ * { index: 1, key: "status2", label: "Status" },
199
+ * ],
200
+ * ...
201
+ * });
202
+ * ```
203
+ */
204
+ declare function defineFlowConfig<const T extends IFlowConfig>(config: T & StrictFlowConfig<T>): T;
41
205
  type InferFields<T extends readonly IInputField[]> = {
42
206
  [K in T[number] as K["key"]]: K["type"] extends keyof InputTypeMap ? InputTypeMap[K["type"]] : unknown;
43
207
  };
44
208
  type InferGlobalInput<T extends IFlowConfig> = InferFields<T["globalInput"]>;
45
209
  type InferProfileInput<T extends IFlowConfig> = InferFields<T["profileInput"]>;
210
+ /** Extract valid output keys từ config output[] — dùng cho type-safety writeOutput */
211
+ type InferOutputKeys<T extends IFlowConfig> = T["output"] extends readonly IOutputField[] ? T["output"][number]["key"] : string;
212
+ /** Extract valid profileInput keys từ config — dùng cho type-safety writeProfileInput */
213
+ type InferProfileInputKeys<T extends IFlowConfig> = T["profileInput"] extends readonly IInputField[] ? T["profileInput"][number]["key"] : string;
214
+ /**
215
+ * Infer output object type từ config output[].
216
+ * Map mỗi key → ProfileOutputValue | null (null nếu chưa ghi).
217
+ * Dùng cho context.output — truy cập trực tiếp output.isLogined, output.titlePage...
218
+ */
219
+ type InferOutput<T extends IFlowConfig> = T["output"] extends readonly IOutputField[] ? {
220
+ [K in T["output"][number]["key"]]: _packages_shared.ProfileOutputValue | null;
221
+ } : Record<string, _packages_shared.ProfileOutputValue | null>;
46
222
  interface IProfileSetting<TProfileInput = Record<string, unknown>> {
47
223
  profileName: string;
48
224
  data?: TProfileInput;
49
225
  }
50
226
  interface IAntidetectConfig<TProfileInput = Record<string, unknown>> {
51
- name: string;
52
227
  profileSettings: IProfileSetting<TProfileInput>[];
53
228
  }
54
229
  interface IExecutionConfig {
@@ -56,6 +231,12 @@ interface IExecutionConfig {
56
231
  delayBetweenProfilesMs?: number;
57
232
  maxRetries?: number;
58
233
  keepOpenOnError?: boolean;
234
+ /**
235
+ * Which antidetect browser to use.
236
+ * ⚠️ Server/Agent only — Agent inject vào global trước khi chạy Worker.
237
+ * Dev mode: dùng constructor `super(AntidetectProvider.GPM, ...)` trong flow class.
238
+ */
239
+ antidetectProvider?: 'gpm' | 'hidemium' | 'genlogin' | 'adspower';
59
240
  }
60
241
  interface IBrowserWindowConfig {
61
242
  width: number;
@@ -67,6 +248,44 @@ interface IFlowRunParams<TConfig extends IFlowConfig = IFlowConfig> {
67
248
  execution: IExecutionConfig;
68
249
  window: IBrowserWindowConfig;
69
250
  globalInput?: InferGlobalInput<TConfig>;
251
+ /** Output definitions từ flow config — dùng để validate writeOutput key */
252
+ outputDefinitions?: IOutputField[];
253
+ /**
254
+ * Existing output entries từ lần chạy trước (lấy từ active output slot trên server).
255
+ * Mỗi entry = 1 profile, `data` chứa cipher/JSON của tất cả output keys.
256
+ * SDK nạp vào context.output để flow script đọc giá trị cũ trực tiếp.
257
+ */
258
+ existingOutputEntries?: _packages_shared.IOutputSlotEntry[];
259
+ }
260
+ interface IEncryptedProfileSetting {
261
+ profileName: string;
262
+ /** AES-256-GCM cipher (base64) chứa toàn bộ profile fields */
263
+ data?: string;
264
+ }
265
+ interface IEncryptedAntidetectConfig {
266
+ name: string;
267
+ profileSettings: IEncryptedProfileSetting[];
268
+ }
269
+ /**
270
+ * Params truyền từ Server → Agent khi dispatch flow.
271
+ * profiles[].data và globalInput đều ở dạng encrypted string.
272
+ * Agent decrypt trước khi chuyển thành IFlowRunParams để pass vào Worker.
273
+ */
274
+ interface IEncryptedFlowRunParams {
275
+ antidetect: IEncryptedAntidetectConfig;
276
+ execution: IExecutionConfig;
277
+ window: IBrowserWindowConfig;
278
+ globalInput?: Record<string, unknown> | {
279
+ data: string;
280
+ };
281
+ /** Output definitions từ flow config — truyền nguyên (không encrypt) */
282
+ outputDefinitions?: IOutputField[];
283
+ /**
284
+ * Existing output entries từ active output slot.
285
+ * Server gửi nguyên bản — mỗi entry = { profileName, data (cipher/JSON) }.
286
+ * Agent decrypt `data` → parse JSON → build context.output.
287
+ */
288
+ existingOutputEntries?: _packages_shared.IOutputSlotEntry[];
70
289
  }
71
290
  type FlowLogLevel = "info" | "warn" | "error" | "debug" | "success";
72
291
  interface IFlowLogEntry {
@@ -85,21 +304,42 @@ interface ILogger {
85
304
  debug(message: string, context?: LogContext): void;
86
305
  success(message: string, context?: LogContext): void;
87
306
  logWithProfile(level: string, message: string, profileName: string, context?: LogContext): void;
307
+ postOutput(outputType: "output" | "profileInput", key: string, value: _packages_shared.ProfileOutputValue, profileName: string, opts?: {
308
+ outputIndex?: number;
309
+ outputLabel?: string;
310
+ }): void;
88
311
  }
89
312
  interface IScriptContext<TConfig extends IFlowConfig = IFlowConfig> {
90
313
  browser: Browser;
91
314
  page: Page;
92
- profile: IGpmProfile;
315
+ profile: IAntidetectProfile;
93
316
  index: number;
94
317
  globalInput: InferGlobalInput<TConfig>;
95
318
  profileInput: InferProfileInput<TConfig>;
319
+ /**
320
+ * Output values cho profile hiện tại.
321
+ * Được pre-populate từ existing output entries (lần chạy trước).
322
+ * Truy cập trực tiếp: output.isLogined, output.titlePage...
323
+ * Giá trị null nếu key chưa được ghi.
324
+ * writeOutput() sẽ cập nhật object này real-time.
325
+ */
326
+ output: InferOutput<TConfig>;
96
327
  logger: ILogger;
97
328
  }
329
+ /**
330
+ * Internal context — extends IScriptContext with SDK-internal fields.
331
+ * Flow developers KHÔNG cần biết fields này.
332
+ * Chỉ dùng nội bộ trong BrowserUtils, BaseFlow.
333
+ */
334
+ interface IScriptContextInternal<TConfig extends IFlowConfig = IFlowConfig> extends IScriptContext<TConfig> {
335
+ /** Output definitions từ flow config — dùng để validate writeOutput key */
336
+ outputDefinitions?: IOutputField[];
337
+ }
98
338
  interface IBrowserAdapter {
99
339
  open(profileName: string, index: number, windowConfig?: IBrowserWindowConfig): Promise<{
100
340
  browser: Browser;
101
341
  page: Page;
102
- profile: IGpmProfile;
342
+ profile: IAntidetectProfile;
103
343
  }>;
104
344
  close(profileId: string): Promise<void>;
105
345
  }
@@ -141,6 +381,83 @@ interface IGpmListProfilesParams {
141
381
  search?: string[];
142
382
  }
143
383
 
384
+ /**
385
+ * Config cho 1 file Excel — dùng cho cả inputFile và outputFile.
386
+ * @template TKeys — union of valid key strings (autocomplete từ flow config)
387
+ */
388
+ interface IExcelFileConfig<TKeys extends string> {
389
+ /** Đường dẫn tuyệt đối hoặc relative (relative → resolve cùng cấp caller) */
390
+ filePath: string;
391
+ /** Sheet index (0-based), mặc định 0 */
392
+ sheetIndex?: number;
393
+ /** Cột chứa tên profile, mặc định "A" */
394
+ profileNameColumn?: string;
395
+ /** Mapping: column letter → key. VD: { "B": "fa2Code", "C": "email" } */
396
+ columns: Record<string, TKeys>;
397
+ }
398
+ /**
399
+ * Config tổng cho ExcelStorage.
400
+ * Có thể chỉ có inputFile, chỉ có outputFile, hoặc cả hai.
401
+ * Nếu 2 file trùng filePath → dùng chung 1 file Excel (chỉ khác cột).
402
+ */
403
+ interface IExcelStorageConfig<TProfileInputKeys extends string = string, TOutputKeys extends string = string> {
404
+ /** File chứa profileInput — đọc bằng parseProfileSettings(), writeProfileInput ghi lại */
405
+ inputFile?: IExcelFileConfig<TProfileInputKeys>;
406
+ /** File chứa output — writeOutput ghi vào đây */
407
+ outputFile?: IExcelFileConfig<TOutputKeys>;
408
+ }
409
+ declare class ExcelStorage<TProfileInputKeys extends string = string, TOutputKeys extends string = string> {
410
+ private readonly config;
411
+ private readonly callerDir;
412
+ constructor(config: IExcelStorageConfig<TProfileInputKeys, TOutputKeys>, callerDir?: string);
413
+ /**
414
+ * Đọc Excel inputFile → trả về IProfileSetting[].
415
+ * Mỗi row = 1 profile, profileName lấy từ cột profileNameColumn,
416
+ * data lấy từ các cột đã mapping.
417
+ */
418
+ parseProfileSettings(): Promise<IProfileSetting[]>;
419
+ /**
420
+ * Ghi output value vào outputFile.
421
+ * Tìm row theo profileName, ghi value vào cột tương ứng với key.
422
+ */
423
+ writeOutputRow(profileName: string, key: TOutputKeys, value: ProfileOutputValue): Promise<void>;
424
+ /**
425
+ * Ghi profileInput value vào inputFile.
426
+ * Tìm row theo profileName, ghi value vào cột tương ứng với key.
427
+ */
428
+ writeProfileInputRow(profileName: string, key: TProfileInputKeys, value: string | number | boolean): Promise<void>;
429
+ /**
430
+ * Đọc tất cả output cho 1 profile → trả về JSON object.
431
+ * Mỗi key trong outputFile.columns → 1 field trong kết quả.
432
+ */
433
+ readOutputForProfile(profileName: string): Promise<Record<TOutputKeys, ProfileOutputValue | null>>;
434
+ get hasOutputFile(): boolean;
435
+ get hasInputFile(): boolean;
436
+ /**
437
+ * Ghi 1 giá trị vào cell Excel.
438
+ * Tìm row theo profileName, nếu không tìm thấy thì tạo row mới.
439
+ */
440
+ private writeCell;
441
+ /**
442
+ * Convert column mapping object → array of { colNumber, key } for easier iteration.
443
+ */
444
+ private buildColumnMap;
445
+ /**
446
+ * Lấy giá trị cell — handle các kiểu ExcelJS cell value.
447
+ */
448
+ private getCellValue;
449
+ /**
450
+ * Serialize ProfileOutputValue → cell value.
451
+ * Array / Object → JSON string, primitive → giữ nguyên.
452
+ */
453
+ private serializeValue;
454
+ /**
455
+ * Lazy load exceljs — tránh crash nếu không install.
456
+ * Handle CJS/ESM interop: dynamic import có thể trả { default: ExcelJS } hoặc ExcelJS trực tiếp.
457
+ */
458
+ private loadExcelJS;
459
+ }
460
+
144
461
  declare abstract class BaseFlow<TConfig extends IFlowConfig = IFlowConfig> {
145
462
  protected logger: ILogger;
146
463
  protected browserAdapter: IBrowserAdapter;
@@ -152,9 +469,17 @@ declare abstract class BaseFlow<TConfig extends IFlowConfig = IFlowConfig> {
152
469
  run(params: IFlowRunParams<TConfig>): Promise<void>;
153
470
  protected processProfileWithRetry(setting: IProfileSetting<Partial<InferProfileInput<TConfig>>>, index: number, params: IFlowRunParams<TConfig>): Promise<void>;
154
471
  private processProfile;
155
- abstract script(context: IScriptContext<TConfig>): Promise<unknown>;
472
+ abstract script(context: IScriptContext<TConfig>): Promise<undefined>;
156
473
  createProfileSetting(profileName: string, data?: Partial<InferProfileInput<TConfig>>): IProfileSetting<Partial<InferProfileInput<TConfig>>>;
157
474
  createRunParams(params: IFlowRunParams<TConfig>): IFlowRunParams<TConfig>;
475
+ /**
476
+ * Tạo ExcelStorage với type-safe column mapping.
477
+ * TS tự gợi ý key values từ config.profileInput và config.output.
478
+ *
479
+ * @param config — inputFile / outputFile config với column mapping
480
+ * @param callerDir — thư mục gốc để resolve relative path (mặc định: cwd)
481
+ */
482
+ createExcelStorage(config: IExcelStorageConfig<InferProfileInputKeys<TConfig>, InferOutputKeys<TConfig>>, callerDir?: string): ExcelStorage<InferProfileInputKeys<TConfig>, InferOutputKeys<TConfig>>;
158
483
  }
159
484
  type FlowRunParams<T extends BaseFlow<any>> = T extends BaseFlow<infer TConfig> ? IFlowRunParams<TConfig> : never;
160
485
  type FlowProfileSetting<T extends BaseFlow<any>> = T extends BaseFlow<infer TConfig> ? IProfileSetting<Partial<InferProfileInput<TConfig>>> : never;
@@ -162,7 +487,8 @@ type FlowProfileSetting<T extends BaseFlow<any>> = T extends BaseFlow<infer TCon
162
487
  declare enum AntidetectProvider {
163
488
  GPM = "gpm",
164
489
  HIDEMIUM = "hidemium",
165
- GENLOGIN = "genlogin"
490
+ GENLOGIN = "genlogin",
491
+ ADSPOWER = "adspower"
166
492
  }
167
493
  declare abstract class AntidetectBaseFlow<TConfig extends IFlowConfig = IFlowConfig> extends BaseFlow<TConfig> {
168
494
  protected provider: AntidetectProvider;
@@ -197,16 +523,85 @@ declare class GpmStandaloneAdapter implements IBrowserAdapter {
197
523
  open(profileName: string, index: number, windowConfig: IBrowserWindowConfig): Promise<{
198
524
  browser: puppeteer.Browser;
199
525
  page: puppeteer.Page;
200
- profile: IGpmProfile;
526
+ profile: IAntidetectProfile;
201
527
  }>;
202
528
  close(profileId: string): Promise<void>;
203
529
  closeAll(delayBetweenMs?: number): Promise<void>;
204
530
  }
205
531
 
206
- declare class BrowserUtils {
532
+ interface IHidemiumProfile {
533
+ uuid: string;
534
+ name: string;
535
+ os: string;
536
+ browser: string;
537
+ version: string;
538
+ proxy: string;
539
+ resolution: string;
540
+ note: string;
541
+ created_at: string;
542
+ }
543
+ interface IHidemiumStartResult {
544
+ remote_port: number;
545
+ web_socket: string;
546
+ profile_path: string;
547
+ uuid: string;
548
+ }
549
+ interface IHidemiumListParams {
550
+ page?: number;
551
+ limit?: number;
552
+ search?: string;
553
+ orderName?: number;
554
+ }
555
+ interface IHidemiumCreateProfileParams {
556
+ name: string;
557
+ os?: "win" | "mac" | "lin" | "android";
558
+ browser?: "chrome" | "brave" | "edge" | "opera";
559
+ version?: string;
560
+ resolution?: string;
561
+ userAgent?: string;
562
+ language?: string;
563
+ }
564
+ declare class HidemiumService {
565
+ private api;
566
+ private apiUrl;
567
+ constructor(apiUrl?: string);
568
+ startProfile(uuid: string, command?: string, proxy?: string, maxRetries?: number, delayMs?: number): Promise<IHidemiumStartResult | null>;
569
+ stopProfile(uuid: string, maxRetries?: number, delayMs?: number): Promise<boolean>;
570
+ getProfiles(params?: IHidemiumListParams, isLocal?: boolean): Promise<IHidemiumProfile[]>;
571
+ createProfile(config: IHidemiumCreateProfileParams, isLocal?: boolean): Promise<any>;
572
+ deleteProfiles(uuids: string[]): Promise<boolean>;
573
+ updateProxy(uuid: string, proxy: string): Promise<boolean>;
574
+ checkHealth(): Promise<boolean>;
575
+ connectToBrowser(wsUrl: string, maxRetries?: number, delayMs?: number): Promise<Browser>;
576
+ }
577
+
578
+ declare class HidemiumStandaloneAdapter implements IBrowserAdapter {
579
+ private apiUrl;
580
+ private screenResolution;
581
+ readonly service: HidemiumService;
582
+ private readonly openedProfiles;
583
+ private readonly pendingProfiles;
584
+ private readonly logger;
585
+ private readonly boundLoggers;
586
+ constructor(logger: ILogger);
587
+ private getBoundLogger;
588
+ open(profileName: string, index: number, windowConfig: IBrowserWindowConfig): Promise<{
589
+ browser: puppeteer.Browser;
590
+ page: puppeteer.Page;
591
+ profile: IAntidetectProfile;
592
+ }>;
593
+ close(profileId: string): Promise<void>;
594
+ closeAll(delayBetweenMs?: number): Promise<void>;
595
+ }
596
+
597
+ declare class BrowserUtils<TConfig extends IFlowConfig = IFlowConfig> {
207
598
  private ctx;
208
599
  private logger;
209
- constructor(context: IScriptContext);
600
+ /** Output definitions từ flow config — dùng để validate writeOutput key */
601
+ private readonly outputDefs;
602
+ /** Set chứa các key hợp lệ — build 1 lần từ outputDefs */
603
+ private readonly validOutputKeys;
604
+ constructor(context: IScriptContext<TConfig>);
210
605
  private checkAbort;
211
606
  sleep(ms: number): Promise<void>;
212
607
  waitForElement(selector: string, timeout?: number, scope?: Frame): Promise<ElementHandle | null>;
@@ -233,9 +628,45 @@ declare class BrowserUtils {
233
628
  switchToTabIndex(index: number): Promise<puppeteer.Page | null>;
234
629
  closeCurrentTab(): Promise<void>;
235
630
  closeOtherTabs(): Promise<void>;
631
+ /**
632
+ * Close ALL tabs (including the current one).
633
+ * Useful for full cleanup before flow ends.
634
+ */
635
+ closeAllTabs(): Promise<void>;
636
+ /**
637
+ * Switch back to the default (initial) page — the page stored in context.
638
+ * Typically used after switchToPopup() to return to the main tab.
639
+ */
640
+ switchToDefault(): Promise<puppeteer.Page>;
236
641
  logConfig(config: Record<string, unknown>, label?: string): Promise<void>;
237
642
  logProfileInput(): Promise<void>;
643
+ /**
644
+ * Log toàn bộ output hiện tại (bao gồm cả giá trị từ lần chạy trước và giá trị mới ghi).
645
+ * Dùng để debug — xem giá trị output hiện tại.
646
+ */
647
+ logProfileOutput(): Promise<void>;
238
648
  logGlobalInput(): Promise<void>;
649
+ /**
650
+ * Ghi kết quả tự do cho profile đang chạy.
651
+ * Gửi qua kênh riêng (type: "profile_output") — không lẫn log.
652
+ * Đồng thời log ra console/UI để flow dev dễ debug.
653
+ *
654
+ * ⚠️ Key phải được định nghĩa trong config.output[] — nếu không sẽ throw Error.
655
+ *
656
+ * value hợp lệ:
657
+ * - string | number | boolean
658
+ * - array tối đa 20 phần tử (primitive)
659
+ * - object 1 cấp tối đa 10 entry (value phải là primitive)
660
+ */
661
+ writeOutput(key: InferOutputKeys<TConfig>, value: ProfileOutputValue): Promise<void>;
662
+ /**
663
+ * Cập nhật lại một field trong profileInput của profile đang chạy.
664
+ * key phải là field đã được định nghĩa trong profileInput schema.
665
+ * Kết quả được gửi về server để update AgentFlowConfig sau khi execution xong.
666
+ */
667
+ writeProfileInput(key: InferProfileInputKeys<TConfig>, value: string | number | boolean): Promise<void>;
668
+ private sanitizeOutputValue;
669
+ private dispatchOutput;
239
670
  private shortSelector;
240
671
  private log;
241
672
  private actionDelay;
@@ -246,6 +677,7 @@ declare class FlowLogger extends EventEmitter implements ILogger {
246
677
  private _context?;
247
678
  private parentPort;
248
679
  private readonly isWorker;
680
+ private excelStorage;
249
681
  constructor(_context?: string | undefined);
250
682
  private serialize;
251
683
  private dispatch;
@@ -259,8 +691,19 @@ declare class FlowLogger extends EventEmitter implements ILogger {
259
691
  debug(message: string, context?: LogContext): void;
260
692
  custom(label: string, message: string, color?: string): void;
261
693
  logWithProfile(level: IWorkerLogMessage["level"], message: string, profileName: string, context?: LogContext): void;
262
- createBoundLogger(profileName: string): ILogger;
694
+ createBoundLogger(profileName: string): ILogger & {
695
+ muted: boolean;
696
+ };
263
697
  profileEvent(profileName: string, message: string, status: ProfileStatus, context?: LogContext): void;
698
+ private buildOutputMsg;
699
+ postOutput(outputType: "output" | "profileInput", key: string, value: IWorkerOutputMessage["value"], profileName: string, opts?: {
700
+ outputIndex?: number;
701
+ outputLabel?: string;
702
+ }): void;
703
+ /**
704
+ * Attach ExcelStorage — FlowLogger sẽ tự ghi Excel khi postOutput (dev mode).
705
+ */
706
+ setExcelStorage(storage: ExcelStorage<any, any>): void;
264
707
  }
265
708
 
266
- export { AntidetectBaseFlow, AntidetectProvider, BaseFlow, BrowserUtils, type FlowLogLevel, FlowLogger, type FlowProfileSetting, type FlowRunParams, GpmStandaloneAdapter, type IAntidetectConfig, type IBrowserAdapter, type IBrowserWindowConfig, type IExecutionConfig, type IFlowConfig, type IFlowLogEntry, type IFlowRunParams, type IGpmListProfilesParams, type IGpmProfile, type IGpmRes, type IGpmResListProfile, type IGpmStartProfileParams, type IInputField, type ILogger, type IProfileSetting, type IResGpmStartProfileData, type IScriptContext, type InferGlobalInput, type InferProfileInput, type LogContext };
709
+ export { AntidetectBaseFlow, AntidetectProvider, BaseFlow, BrowserUtils, ExcelStorage, type FlowLogLevel, FlowLogger, type FlowProfileSetting, type FlowRunParams, GpmStandaloneAdapter, HidemiumService, HidemiumStandaloneAdapter, type IAntidetectConfig, type IAntidetectProfile, type IBrowserAdapter, type IBrowserWindowConfig, type IEncryptedAntidetectConfig, type IEncryptedFlowRunParams, type IEncryptedProfileSetting, type IExcelFileConfig, type IExcelStorageConfig, type IExecutionConfig, type IFlowConfig, type IFlowLogEntry, type IFlowRunParams, type IGpmListProfilesParams, type IGpmProfile, type IGpmRes, type IGpmResListProfile, type IGpmStartProfileParams, type IHidemiumCreateProfileParams, type IHidemiumListParams, type IHidemiumProfile, type IHidemiumStartResult, type IInputField, type ILogger, type IOutputField, type IProfileSetting, type IResGpmStartProfileData, type IScriptContext, type IScriptContextInternal, type InferGlobalInput, type InferOutput, type InferOutputKeys, type InferProfileInput, type InferProfileInputKeys, type LogContext, type StrictFlowConfig, defineFlowConfig };