@hira-core/sdk 1.0.3 → 1.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +349 -243
- package/dist/index.d.ts +11 -2
- package/dist/index.js +77 -19
- package/package.json +6 -1
package/README.md
CHANGED
|
@@ -1,243 +1,349 @@
|
|
|
1
|
-
# @hira-core/sdk
|
|
2
|
-
|
|
3
|
-
SDK for building **Hira** automation flows with TypeScript. Provides type-safe base classes, browser utilities, and logger for running flows inside the Hira Agent sandbox.
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
### `
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
|
156
|
-
|
|
|
157
|
-
| `
|
|
158
|
-
| `
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
```
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
```
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
1
|
+
# @hira-core/sdk
|
|
2
|
+
|
|
3
|
+
SDK for building **Hira** automation flows with TypeScript. Provides type-safe base classes, browser utilities, and logger for running flows inside the Hira Agent sandbox.
|
|
4
|
+
|
|
5
|
+
📖 **[Full Documentation](https://hira-sdk.vercel.app/)** — Guides, API reference, and examples.
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install @hira-core/sdk
|
|
11
|
+
# or
|
|
12
|
+
pnpm add @hira-core/sdk
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
> **Peer dependency:** Requires `puppeteer-core` to be available at runtime (provided by the Hira Agent).
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## Quick Start
|
|
20
|
+
|
|
21
|
+
### 1. Define your Flow Config
|
|
22
|
+
|
|
23
|
+
```typescript
|
|
24
|
+
import {
|
|
25
|
+
AntidetectBaseFlow,
|
|
26
|
+
AntidetectProvider,
|
|
27
|
+
defineFlowConfig,
|
|
28
|
+
IScriptContext,
|
|
29
|
+
BrowserUtils,
|
|
30
|
+
FlowLogger,
|
|
31
|
+
} from "@hira-core/sdk";
|
|
32
|
+
|
|
33
|
+
const config = defineFlowConfig({
|
|
34
|
+
globalInput: [
|
|
35
|
+
{
|
|
36
|
+
key: "targetUrl",
|
|
37
|
+
label: "Target URL",
|
|
38
|
+
type: "text" as const,
|
|
39
|
+
required: true,
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
key: "delay",
|
|
43
|
+
label: "Delay (ms)",
|
|
44
|
+
type: "number" as const,
|
|
45
|
+
defaultValue: 2000,
|
|
46
|
+
},
|
|
47
|
+
],
|
|
48
|
+
profileInput: [
|
|
49
|
+
{ key: "username", label: "Username", type: "text" as const },
|
|
50
|
+
{ key: "password", label: "Password", type: "text" as const },
|
|
51
|
+
],
|
|
52
|
+
output: [
|
|
53
|
+
{ index: 0, key: "isLoggedIn", label: "Login Status" },
|
|
54
|
+
{ index: 1, key: "pageTitle", label: "Page Title" },
|
|
55
|
+
],
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
type MyConfig = typeof config;
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
> **`defineFlowConfig()`** validates for **duplicate keys, labels, and output indices** at compile time — providing instant TS errors if any field is duplicated.
|
|
62
|
+
|
|
63
|
+
### 2. Implement your Flow class
|
|
64
|
+
|
|
65
|
+
```typescript
|
|
66
|
+
export class MyFlow extends AntidetectBaseFlow<MyConfig> {
|
|
67
|
+
constructor() {
|
|
68
|
+
super(AntidetectProvider.GPM, new FlowLogger(MyFlow.name), config);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
async script(context: IScriptContext<MyConfig>): Promise<void> {
|
|
72
|
+
const { page, logger, globalInput, profileInput, output } = context;
|
|
73
|
+
const utils = new BrowserUtils(context);
|
|
74
|
+
|
|
75
|
+
await utils.goto(globalInput.targetUrl);
|
|
76
|
+
logger.info(`Logging in as: ${profileInput.username}`);
|
|
77
|
+
|
|
78
|
+
await utils.type("#username", profileInput.username);
|
|
79
|
+
await utils.type("#password", profileInput.password);
|
|
80
|
+
await utils.click("#login-btn");
|
|
81
|
+
|
|
82
|
+
const title = await page.title();
|
|
83
|
+
|
|
84
|
+
// Write typed output (validated against config.output keys)
|
|
85
|
+
await utils.writeOutput("isLoggedIn", true);
|
|
86
|
+
await utils.writeOutput("pageTitle", title);
|
|
87
|
+
|
|
88
|
+
logger.success(`✅ Done — page: ${title}`);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export default MyFlow;
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### 3. Run locally (for development)
|
|
96
|
+
|
|
97
|
+
```typescript
|
|
98
|
+
import MyFlow from "./index";
|
|
99
|
+
|
|
100
|
+
const flow = new MyFlow();
|
|
101
|
+
|
|
102
|
+
await flow.run(
|
|
103
|
+
flow.createRunParams({
|
|
104
|
+
antidetect: {
|
|
105
|
+
profileSettings: [
|
|
106
|
+
flow.createProfileSetting("ProfileA", {
|
|
107
|
+
username: "user1",
|
|
108
|
+
password: "pass1",
|
|
109
|
+
}),
|
|
110
|
+
],
|
|
111
|
+
},
|
|
112
|
+
execution: { concurrency: 2, maxRetries: 1 },
|
|
113
|
+
globalInput: { targetUrl: "https://example.com", delay: 2000 },
|
|
114
|
+
window: { width: 1280, height: 720, scale: 1 },
|
|
115
|
+
}),
|
|
116
|
+
);
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
---
|
|
120
|
+
|
|
121
|
+
## API Reference
|
|
122
|
+
|
|
123
|
+
### `AntidetectBaseFlow<TConfig>`
|
|
124
|
+
|
|
125
|
+
Abstract base class for browser automation flows.
|
|
126
|
+
|
|
127
|
+
| Method / Property | Description |
|
|
128
|
+
| ----------------------------------- | ------------------------------------------------ |
|
|
129
|
+
| `abstract script(context)` | Your automation logic — implement this |
|
|
130
|
+
| `run(params)` | Start the flow (called by Hira Agent) |
|
|
131
|
+
| `createRunParams(params)` | Type-safe helper to build run params |
|
|
132
|
+
| `createProfileSetting(name, data?)` | Type-safe helper to build profile settings |
|
|
133
|
+
| `flowConfig` | The declared config schema (embedded in `.hira`) |
|
|
134
|
+
|
|
135
|
+
### `AntidetectProvider`
|
|
136
|
+
|
|
137
|
+
```typescript
|
|
138
|
+
enum AntidetectProvider {
|
|
139
|
+
GPM = "gpm", // GPM Login antidetect browser
|
|
140
|
+
HIDEMIUM = "hidemium", // Hidemium antidetect browser
|
|
141
|
+
GENLOGIN = "genlogin", // coming soon
|
|
142
|
+
}
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
### `IScriptContext<TConfig>`
|
|
146
|
+
|
|
147
|
+
Injected into `script()` by the runtime:
|
|
148
|
+
|
|
149
|
+
| Field | Type | Description |
|
|
150
|
+
| -------------- | ---------------------------- | ---------------------------------------------------- |
|
|
151
|
+
| `browser` | `Browser` | Puppeteer browser instance |
|
|
152
|
+
| `page` | `Page` | Active page |
|
|
153
|
+
| `profile` | `IAntidetectProfile` | Current profile info (unified across providers) |
|
|
154
|
+
| `index` | `number` | Profile index in the batch |
|
|
155
|
+
| `globalInput` | `InferGlobalInput<TConfig>` | Typed global inputs |
|
|
156
|
+
| `profileInput` | `InferProfileInput<TConfig>` | Typed per-profile inputs |
|
|
157
|
+
| `output` | `InferOutput<TConfig>` | Current output values (pre-populated from last run) |
|
|
158
|
+
| `logger` | `ILogger` | Bound logger (auto-tagged with profile name) |
|
|
159
|
+
|
|
160
|
+
### `IAntidetectProfile`
|
|
161
|
+
|
|
162
|
+
Unified profile interface — works across all providers (GPM, Hidemium, etc.):
|
|
163
|
+
|
|
164
|
+
```typescript
|
|
165
|
+
interface IAntidetectProfile {
|
|
166
|
+
id: string; // Unique ID
|
|
167
|
+
name: string; // Human-readable name
|
|
168
|
+
provider: "gpm" | "hidemium" | "genlogin";
|
|
169
|
+
raw_proxy?: string; // Proxy string
|
|
170
|
+
browser_type: "chromium" | "firefox";
|
|
171
|
+
browser_version: string;
|
|
172
|
+
group_id?: string;
|
|
173
|
+
profile_path: string;
|
|
174
|
+
note: string;
|
|
175
|
+
created_at: string; // ISO 8601
|
|
176
|
+
}
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
> **Note:** `IGpmProfile` is deprecated — use `IAntidetectProfile` instead.
|
|
180
|
+
|
|
181
|
+
### `BrowserUtils`
|
|
182
|
+
|
|
183
|
+
Helper class for common browser actions. All methods auto-log and respect the abort signal.
|
|
184
|
+
|
|
185
|
+
```typescript
|
|
186
|
+
const utils = new BrowserUtils(context);
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
#### Navigation & Interaction
|
|
190
|
+
|
|
191
|
+
| Method | Description |
|
|
192
|
+
| ------------------------------------------ | ----------------------------- |
|
|
193
|
+
| `utils.goto(url)` | Navigate to URL |
|
|
194
|
+
| `utils.click(selector)` | Wait + scroll + click |
|
|
195
|
+
| `utils.type(selector, text)` | Wait + clear + type |
|
|
196
|
+
| `utils.getText(selector)` | Get text content |
|
|
197
|
+
| `utils.exists(selector, timeout?)` | Check element exists |
|
|
198
|
+
| `utils.waitForElement(selector, timeout?)` | Wait for element |
|
|
199
|
+
| `utils.waitForNavigation()` | Wait for page navigation |
|
|
200
|
+
| `utils.screenshot(path?)` | Take screenshot |
|
|
201
|
+
| `utils.sleep(ms)` | Delay (respects abort signal) |
|
|
202
|
+
|
|
203
|
+
#### Tab Management
|
|
204
|
+
|
|
205
|
+
| Method | Description |
|
|
206
|
+
| --------------------------------- | ------------------------ |
|
|
207
|
+
| `utils.switchToPopup(matcher)` | Switch to popup tab |
|
|
208
|
+
| `utils.switchToTabIndex(index)` | Switch to tab by index |
|
|
209
|
+
| `utils.closeCurrentTab()` | Close current tab |
|
|
210
|
+
| `utils.closeOtherTabs()` | Close all other tabs |
|
|
211
|
+
|
|
212
|
+
#### Output & Data
|
|
213
|
+
|
|
214
|
+
| Method | Description |
|
|
215
|
+
| ------------------------------------ | ------------------------------------------------ |
|
|
216
|
+
| `utils.writeOutput(key, value)` | Write output value (type-safe against config) |
|
|
217
|
+
| `utils.writeProfileInput(key, val)` | Update profile input value for next run |
|
|
218
|
+
| `utils.logGlobalInput()` | Log all global inputs |
|
|
219
|
+
| `utils.logProfileInput()` | Log all profile inputs |
|
|
220
|
+
|
|
221
|
+
### `FlowLogger`
|
|
222
|
+
|
|
223
|
+
Logger that works both in standalone mode (console) and inside Hira Agent worker (postMessage).
|
|
224
|
+
|
|
225
|
+
```typescript
|
|
226
|
+
const logger = new FlowLogger("MyFlow");
|
|
227
|
+
|
|
228
|
+
logger.info("message");
|
|
229
|
+
logger.success("done");
|
|
230
|
+
logger.warn("warning");
|
|
231
|
+
logger.error("error");
|
|
232
|
+
logger.debug("debug");
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
### `IFlowConfig`
|
|
236
|
+
|
|
237
|
+
Schema declaration for your flow's inputs and outputs:
|
|
238
|
+
|
|
239
|
+
```typescript
|
|
240
|
+
interface IFlowConfig {
|
|
241
|
+
globalInput: readonly IInputField[]; // shared across all profiles
|
|
242
|
+
profileInput: readonly IInputField[]; // per-profile data
|
|
243
|
+
output?: readonly IOutputField[]; // output fields per profile
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
interface IInputField {
|
|
247
|
+
key: string;
|
|
248
|
+
label: string;
|
|
249
|
+
type: "text" | "number" | "boolean" | "select" | "textarea";
|
|
250
|
+
required?: boolean;
|
|
251
|
+
defaultValue?: string | number | boolean;
|
|
252
|
+
placeholder?: string;
|
|
253
|
+
options?: { label: string; value: string | number }[];
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
interface IOutputField {
|
|
257
|
+
index: number; // display order
|
|
258
|
+
key: string; // unique key for writeOutput()
|
|
259
|
+
label: string; // human-readable label
|
|
260
|
+
}
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
### `defineFlowConfig()`
|
|
264
|
+
|
|
265
|
+
Helper function that validates your config at compile time — catches duplicate keys, labels, indices, and option values:
|
|
266
|
+
|
|
267
|
+
```typescript
|
|
268
|
+
// ✅ OK
|
|
269
|
+
const config = defineFlowConfig({
|
|
270
|
+
globalInput: [
|
|
271
|
+
{ key: "url", label: "URL", type: "text" },
|
|
272
|
+
],
|
|
273
|
+
profileInput: [
|
|
274
|
+
{ key: "user", label: "User", type: "text" },
|
|
275
|
+
],
|
|
276
|
+
output: [
|
|
277
|
+
{ index: 0, key: "status", label: "Status" },
|
|
278
|
+
{ index: 1, key: "title", label: "Title" },
|
|
279
|
+
],
|
|
280
|
+
});
|
|
281
|
+
|
|
282
|
+
// ❌ TS Error — duplicate key "url" in globalInput
|
|
283
|
+
const bad = defineFlowConfig({
|
|
284
|
+
globalInput: [
|
|
285
|
+
{ key: "url", label: "URL 1", type: "text" },
|
|
286
|
+
{ key: "url", label: "URL 2", type: "text" }, // Error!
|
|
287
|
+
],
|
|
288
|
+
profileInput: [],
|
|
289
|
+
});
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
### `ExcelStorage`
|
|
293
|
+
|
|
294
|
+
Read profile data from Excel files and write output back:
|
|
295
|
+
|
|
296
|
+
```typescript
|
|
297
|
+
import { ExcelStorage } from "@hira-core/sdk";
|
|
298
|
+
|
|
299
|
+
const storage = new ExcelStorage("data.xlsx");
|
|
300
|
+
|
|
301
|
+
// Read rows from a sheet
|
|
302
|
+
const rows = await storage.readRows("Sheet1");
|
|
303
|
+
|
|
304
|
+
// Write output rows
|
|
305
|
+
await storage.writeRows("Output", outputData);
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
---
|
|
309
|
+
|
|
310
|
+
## Type Inference
|
|
311
|
+
|
|
312
|
+
The SDK automatically infers TypeScript types from your config at compile time:
|
|
313
|
+
|
|
314
|
+
```typescript
|
|
315
|
+
const config = defineFlowConfig({
|
|
316
|
+
globalInput: [
|
|
317
|
+
{ key: "url", type: "text" as const, label: "URL" },
|
|
318
|
+
{ key: "count", type: "number" as const, label: "Count" },
|
|
319
|
+
],
|
|
320
|
+
profileInput: [
|
|
321
|
+
{ key: "username", type: "text" as const, label: "Username" },
|
|
322
|
+
],
|
|
323
|
+
output: [
|
|
324
|
+
{ index: 0, key: "isLoggedIn", label: "Logged In" },
|
|
325
|
+
],
|
|
326
|
+
});
|
|
327
|
+
|
|
328
|
+
// Inside script():
|
|
329
|
+
// globalInput.url → string ✅
|
|
330
|
+
// globalInput.count → number ✅
|
|
331
|
+
// profileInput.username → string ✅
|
|
332
|
+
// output.isLoggedIn → ProfileOutputValue | null ✅
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
---
|
|
336
|
+
|
|
337
|
+
## Building & Publishing a Flow
|
|
338
|
+
|
|
339
|
+
Use [`@hira-core/cli`](https://www.npmjs.com/package/@hira-core/cli) to package your flow:
|
|
340
|
+
|
|
341
|
+
```bash
|
|
342
|
+
npx @hira-core/cli build
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
---
|
|
346
|
+
|
|
347
|
+
## License
|
|
348
|
+
|
|
349
|
+
ISC
|
package/dist/index.d.ts
CHANGED
|
@@ -541,9 +541,12 @@ interface IHidemiumProfile {
|
|
|
541
541
|
created_at: string;
|
|
542
542
|
}
|
|
543
543
|
interface IHidemiumStartResult {
|
|
544
|
+
status: boolean;
|
|
544
545
|
remote_port: number;
|
|
545
|
-
web_socket
|
|
546
|
+
web_socket?: string;
|
|
546
547
|
profile_path: string;
|
|
548
|
+
execute_path: string;
|
|
549
|
+
profile_name?: string;
|
|
547
550
|
uuid: string;
|
|
548
551
|
}
|
|
549
552
|
interface IHidemiumListParams {
|
|
@@ -572,7 +575,13 @@ declare class HidemiumService {
|
|
|
572
575
|
deleteProfiles(uuids: string[]): Promise<boolean>;
|
|
573
576
|
updateProxy(uuid: string, proxy: string): Promise<boolean>;
|
|
574
577
|
checkHealth(): Promise<boolean>;
|
|
575
|
-
|
|
578
|
+
/**
|
|
579
|
+
* Kết nối browser — thử theo thứ tự:
|
|
580
|
+
* 1. web_socket (nếu API trả)
|
|
581
|
+
* 2. browserURL via remote_port (nếu API trả)
|
|
582
|
+
* 3. Fallback: quét default port 9222 (Hidemium mặc định)
|
|
583
|
+
*/
|
|
584
|
+
connectToBrowser(startResult: IHidemiumStartResult, maxRetries?: number, delayMs?: number): Promise<Browser>;
|
|
576
585
|
}
|
|
577
586
|
|
|
578
587
|
declare class HidemiumStandaloneAdapter implements IBrowserAdapter {
|
package/dist/index.js
CHANGED
|
@@ -12535,6 +12535,26 @@ var WindowManager = class {
|
|
|
12535
12535
|
const y = Math.floor(row * itemHeight);
|
|
12536
12536
|
return { x, y };
|
|
12537
12537
|
}
|
|
12538
|
+
/**
|
|
12539
|
+
* Tính vị trí cửa sổ cho Hidemium (--force-device-scale-factor)
|
|
12540
|
+
* Khác GPM: scale ảnh hưởng kích thước thực tế của window
|
|
12541
|
+
* → dùng effectiveWidth/Height cho cả grid lẫn vị trí
|
|
12542
|
+
*/
|
|
12543
|
+
static calculatePositionScaled(index, screen, itemWidth, itemHeight, scale = 1) {
|
|
12544
|
+
const screenWidth = screen.width;
|
|
12545
|
+
const screenHeight = screen.height;
|
|
12546
|
+
const scaledWidth = Math.floor((itemWidth > 0 ? itemWidth : 800) * scale);
|
|
12547
|
+
const scaledHeight = Math.floor((itemHeight > 0 ? itemHeight : 600) * scale);
|
|
12548
|
+
const cols = Math.floor(screenWidth / scaledWidth) || 1;
|
|
12549
|
+
const rows = Math.floor(screenHeight / scaledHeight) || 1;
|
|
12550
|
+
const itemsPerScreen = cols * rows;
|
|
12551
|
+
const visualIndex = index % itemsPerScreen;
|
|
12552
|
+
const row = Math.floor(visualIndex / cols);
|
|
12553
|
+
const col = visualIndex % cols;
|
|
12554
|
+
const x = col * scaledWidth;
|
|
12555
|
+
const y = row * scaledHeight;
|
|
12556
|
+
return { x, y, scaledWidth, scaledHeight };
|
|
12557
|
+
}
|
|
12538
12558
|
};
|
|
12539
12559
|
|
|
12540
12560
|
// ../../node_modules/.pnpm/axios@1.13.4/node_modules/axios/lib/helpers/bind.js
|
|
@@ -16480,7 +16500,7 @@ var HidemiumService = class {
|
|
|
16480
16500
|
}
|
|
16481
16501
|
return false;
|
|
16482
16502
|
}
|
|
16483
|
-
async getProfiles(params, isLocal
|
|
16503
|
+
async getProfiles(params, isLocal) {
|
|
16484
16504
|
var _a, _b;
|
|
16485
16505
|
const response = await this.api.post(
|
|
16486
16506
|
"/v1/browser/list",
|
|
@@ -16490,7 +16510,8 @@ var HidemiumService = class {
|
|
|
16490
16510
|
search: (params == null ? void 0 : params.search) || "",
|
|
16491
16511
|
orderName: (params == null ? void 0 : params.orderName) || 0
|
|
16492
16512
|
},
|
|
16493
|
-
|
|
16513
|
+
// Chỉ truyền is_local nếu caller chỉ định — mặc định lấy tất cả
|
|
16514
|
+
isLocal !== void 0 ? { params: { is_local: isLocal } } : void 0
|
|
16494
16515
|
);
|
|
16495
16516
|
return ((_b = (_a = response.data) == null ? void 0 : _a.data) == null ? void 0 : _b.content) || [];
|
|
16496
16517
|
}
|
|
@@ -16520,24 +16541,49 @@ var HidemiumService = class {
|
|
|
16520
16541
|
return false;
|
|
16521
16542
|
}
|
|
16522
16543
|
}
|
|
16523
|
-
|
|
16544
|
+
/**
|
|
16545
|
+
* Kết nối browser — thử theo thứ tự:
|
|
16546
|
+
* 1. web_socket (nếu API trả)
|
|
16547
|
+
* 2. browserURL via remote_port (nếu API trả)
|
|
16548
|
+
* 3. Fallback: quét default port 9222 (Hidemium mặc định)
|
|
16549
|
+
*/
|
|
16550
|
+
async connectToBrowser(startResult, maxRetries = 5, delayMs = 1e3) {
|
|
16524
16551
|
let lastError;
|
|
16525
|
-
|
|
16526
|
-
|
|
16527
|
-
|
|
16528
|
-
|
|
16529
|
-
|
|
16530
|
-
|
|
16531
|
-
|
|
16532
|
-
|
|
16533
|
-
|
|
16534
|
-
|
|
16535
|
-
|
|
16552
|
+
if (startResult.web_socket) {
|
|
16553
|
+
for (let attempt = 1; attempt <= maxRetries; attempt++) {
|
|
16554
|
+
try {
|
|
16555
|
+
const browser = await import_puppeteer_core2.default.connect({
|
|
16556
|
+
browserWSEndpoint: startResult.web_socket,
|
|
16557
|
+
defaultViewport: null
|
|
16558
|
+
});
|
|
16559
|
+
return browser;
|
|
16560
|
+
} catch (error) {
|
|
16561
|
+
lastError = error;
|
|
16562
|
+
if (attempt < maxRetries) {
|
|
16563
|
+
await new Promise((r) => setTimeout(r, delayMs));
|
|
16564
|
+
}
|
|
16565
|
+
}
|
|
16566
|
+
}
|
|
16567
|
+
}
|
|
16568
|
+
if (startResult.remote_port) {
|
|
16569
|
+
const browserURL = `http://127.0.0.1:${startResult.remote_port}`;
|
|
16570
|
+
for (let attempt = 1; attempt <= maxRetries; attempt++) {
|
|
16571
|
+
try {
|
|
16572
|
+
const browser = await import_puppeteer_core2.default.connect({
|
|
16573
|
+
browserURL,
|
|
16574
|
+
defaultViewport: null
|
|
16575
|
+
});
|
|
16576
|
+
return browser;
|
|
16577
|
+
} catch (error) {
|
|
16578
|
+
lastError = error;
|
|
16579
|
+
if (attempt < maxRetries) {
|
|
16580
|
+
await new Promise((r) => setTimeout(r, delayMs));
|
|
16581
|
+
}
|
|
16536
16582
|
}
|
|
16537
16583
|
}
|
|
16538
16584
|
}
|
|
16539
16585
|
throw new Error(
|
|
16540
|
-
`Failed to connect to browser
|
|
16586
|
+
`Failed to connect to Hidemium browser after ${maxRetries} attempts. Last error: ${lastError == null ? void 0 : lastError.message}`
|
|
16541
16587
|
);
|
|
16542
16588
|
}
|
|
16543
16589
|
};
|
|
@@ -16599,7 +16645,16 @@ var HidemiumStandaloneAdapter = class {
|
|
|
16599
16645
|
windowConfig.height,
|
|
16600
16646
|
windowConfig.scale
|
|
16601
16647
|
);
|
|
16602
|
-
const command =
|
|
16648
|
+
const command = [
|
|
16649
|
+
`--window-position=${x},${y}`,
|
|
16650
|
+
`--window-size=${windowConfig.width},${windowConfig.height}`,
|
|
16651
|
+
`--force-device-scale-factor=${windowConfig.scale}`
|
|
16652
|
+
].join(" ");
|
|
16653
|
+
try {
|
|
16654
|
+
await this.service.stopProfile(targetProfile.uuid);
|
|
16655
|
+
await new Promise((r) => setTimeout(r, 2e3));
|
|
16656
|
+
} catch {
|
|
16657
|
+
}
|
|
16603
16658
|
const startResult = await this.service.startProfile(
|
|
16604
16659
|
targetProfile.uuid,
|
|
16605
16660
|
command
|
|
@@ -16607,9 +16662,12 @@ var HidemiumStandaloneAdapter = class {
|
|
|
16607
16662
|
if (!startResult) {
|
|
16608
16663
|
throw new Error(`Failed to start profile: ${profileName}`);
|
|
16609
16664
|
}
|
|
16610
|
-
|
|
16611
|
-
|
|
16612
|
-
|
|
16665
|
+
if (!startResult.web_socket && !startResult.remote_port) {
|
|
16666
|
+
throw new Error(
|
|
16667
|
+
`Hidemium openProfile did not return web_socket or remote_port for "${profileName}". Please ensure the profile is not already opened in another session.`
|
|
16668
|
+
);
|
|
16669
|
+
}
|
|
16670
|
+
const browser = await this.service.connectToBrowser(startResult);
|
|
16613
16671
|
const pages = await browser.pages();
|
|
16614
16672
|
const page = pages.length > 0 ? pages[0] : await browser.newPage();
|
|
16615
16673
|
this.openedProfiles.set(profileName, targetProfile.uuid);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hira-core/sdk",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.5",
|
|
4
4
|
"description": "SDK for building Hira automation flows with TypeScript",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -25,6 +25,11 @@
|
|
|
25
25
|
"puppeteer"
|
|
26
26
|
],
|
|
27
27
|
"author": "tttKiet",
|
|
28
|
+
"homepage": "https://hira-sdk.vercel.app/",
|
|
29
|
+
"repository": {
|
|
30
|
+
"type": "git",
|
|
31
|
+
"url": "https://github.com/tttKiet/hira-automation"
|
|
32
|
+
},
|
|
28
33
|
"license": "ISC",
|
|
29
34
|
"engines": {
|
|
30
35
|
"node": ">=18.0.0"
|