@harborclient/sdk 1.5.3 → 1.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +11 -0
- package/dist/components/Breadcrumb/CrumbSegment.d.ts.map +1 -1
- package/dist/components/Breadcrumb/CrumbSegment.js +4 -2
- package/dist/components/Breadcrumb/types.d.ts +10 -1
- package/dist/components/Breadcrumb/types.d.ts.map +1 -1
- package/dist/components/MethodSelect/MethodSelectMenu.d.ts +34 -0
- package/dist/components/MethodSelect/MethodSelectMenu.d.ts.map +1 -0
- package/dist/components/MethodSelect/MethodSelectMenu.js +150 -0
- package/dist/components/MethodSelect/MethodSelectOption.d.ts +36 -0
- package/dist/components/MethodSelect/MethodSelectOption.d.ts.map +1 -0
- package/dist/components/MethodSelect/MethodSelectOption.js +15 -0
- package/dist/components/MethodSelect/MethodSelectSeparator.d.ts +10 -0
- package/dist/components/MethodSelect/MethodSelectSeparator.d.ts.map +1 -0
- package/dist/components/MethodSelect/MethodSelectSeparator.js +11 -0
- package/dist/components/MethodSelect/index.d.ts +21 -7
- package/dist/components/MethodSelect/index.d.ts.map +1 -1
- package/dist/components/MethodSelect/index.js +47 -6
- package/dist/components/SidebarItem/sidebarItemClasses.d.ts.map +1 -1
- package/dist/components/SidebarItem/sidebarItemClasses.js +2 -1
- package/dist/components/index.d.ts +1 -1
- package/dist/components/index.d.ts.map +1 -1
- package/dist/runtime/createBridgedPluginContext.js +295 -7
- package/dist/runtime/viewHost.js +6 -0
- package/dist/snippets.d.ts +30 -19
- package/dist/types.d.ts +337 -16
- package/dist/types.d.ts.map +1 -1
- package/dist/ui/tokens.d.ts +1 -0
- package/dist/ui/tokens.d.ts.map +1 -1
- package/dist/ui/tokens.js +4 -2
- package/package.json +1 -1
|
@@ -15,12 +15,41 @@ const commandHandlers = new Map();
|
|
|
15
15
|
/** @type {Map<string, import('../types').ImportHandler>} */
|
|
16
16
|
const importHandlersByRegistrationId = new Map();
|
|
17
17
|
|
|
18
|
+
/**
|
|
19
|
+
* Parse callbacks for custom chat pointers, keyed by registration id.
|
|
20
|
+
*
|
|
21
|
+
* @type {Map<string, NonNullable<import('../types').PluginChatPointerConfig['parse']>>}
|
|
22
|
+
*/
|
|
23
|
+
const chatPointerParseByRegistrationId = new Map();
|
|
24
|
+
|
|
18
25
|
/** Monotonic id generator for import handler registrations within one webview. */
|
|
19
26
|
let importRegistrationCounter = 0;
|
|
20
27
|
|
|
21
28
|
/** Monotonic id generator for MCP server registrations within one webview. */
|
|
22
29
|
let mcpRegistrationCounter = 0;
|
|
23
30
|
let aiChatPointerRegistrationCounter = 0;
|
|
31
|
+
let aiInstructionsRegistrationCounter = 0;
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Before-turn handlers registered via `hc.ai.onBeforeTurn`.
|
|
35
|
+
*
|
|
36
|
+
* @type {Set<(ctx: import('../types').PluginAiBeforeTurnContext) => void | Promise<void>>}
|
|
37
|
+
*/
|
|
38
|
+
const aiBeforeTurnHandlers = new Set();
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* After-turn handlers registered via `hc.ai.onAfterTurn`.
|
|
42
|
+
*
|
|
43
|
+
* @type {Set<(ctx: import('../types').PluginAiAfterTurnContext) => void | Promise<void>>}
|
|
44
|
+
*/
|
|
45
|
+
const aiAfterTurnHandlers = new Set();
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Local instruction texts keyed by registration id (for `hc.ai.instructions.list`).
|
|
49
|
+
*
|
|
50
|
+
* @type {Map<string, string>}
|
|
51
|
+
*/
|
|
52
|
+
const aiInstructionsByRegistrationId = new Map();
|
|
24
53
|
|
|
25
54
|
/** Plugin id prefix for built-in HarborClient host commands executed in the renderer. */
|
|
26
55
|
const HOST_COMMAND_OWNER = 'harborclient';
|
|
@@ -28,6 +57,15 @@ const HOST_COMMAND_OWNER = 'harborclient';
|
|
|
28
57
|
/** Guards repeated import invoke listener installation per webview load. */
|
|
29
58
|
let importInvokeListenerInstalled = false;
|
|
30
59
|
|
|
60
|
+
/** Guards repeated chat-pointer parse listener installation per webview load. */
|
|
61
|
+
let aiParseChatPointerListenerInstalled = false;
|
|
62
|
+
|
|
63
|
+
/** Guards repeated before-turn listener installation per webview load. */
|
|
64
|
+
let aiBeforeTurnListenerInstalled = false;
|
|
65
|
+
|
|
66
|
+
/** Guards repeated after-turn listener installation per webview load. */
|
|
67
|
+
let aiAfterTurnListenerInstalled = false;
|
|
68
|
+
|
|
31
69
|
/**
|
|
32
70
|
* Normalizes a file extension to lowercase with a leading dot.
|
|
33
71
|
*
|
|
@@ -123,6 +161,11 @@ export function installImportInvokeListener() {
|
|
|
123
161
|
export function resetMcpServersForTests() {
|
|
124
162
|
mcpRegistrationCounter = 0;
|
|
125
163
|
aiChatPointerRegistrationCounter = 0;
|
|
164
|
+
aiInstructionsRegistrationCounter = 0;
|
|
165
|
+
chatPointerParseByRegistrationId.clear();
|
|
166
|
+
aiInstructionsByRegistrationId.clear();
|
|
167
|
+
aiBeforeTurnHandlers.clear();
|
|
168
|
+
aiAfterTurnHandlers.clear();
|
|
126
169
|
}
|
|
127
170
|
|
|
128
171
|
/**
|
|
@@ -132,9 +175,183 @@ export function resetImportHandlersForTests() {
|
|
|
132
175
|
importHandlersByRegistrationId.clear();
|
|
133
176
|
importRegistrationCounter = 0;
|
|
134
177
|
importInvokeListenerInstalled = false;
|
|
178
|
+
aiParseChatPointerListenerInstalled = false;
|
|
179
|
+
aiBeforeTurnListenerInstalled = false;
|
|
180
|
+
aiAfterTurnListenerInstalled = false;
|
|
135
181
|
resetMcpServersForTests();
|
|
136
182
|
}
|
|
137
183
|
|
|
184
|
+
/**
|
|
185
|
+
* Serializes a plugin chat-pointer match for the host bridge.
|
|
186
|
+
*
|
|
187
|
+
* @param {RegExp | string} match - Plugin-supplied match.
|
|
188
|
+
* @returns {{ source: string; flags: string }}
|
|
189
|
+
*/
|
|
190
|
+
function serializeChatPointerMatch(match) {
|
|
191
|
+
if (match instanceof RegExp) {
|
|
192
|
+
return { source: match.source, flags: match.flags.replace(/g/g, '') };
|
|
193
|
+
}
|
|
194
|
+
return { source: String(match ?? ''), flags: '' };
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Subscribes to host-initiated chat-pointer parse invocations for the agent webview.
|
|
199
|
+
*
|
|
200
|
+
* Must run once before plugin activation so send/validate can reach registered parsers.
|
|
201
|
+
*/
|
|
202
|
+
export function installAiParseChatPointerListener() {
|
|
203
|
+
if (aiParseChatPointerListenerInstalled) {
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
206
|
+
aiParseChatPointerListenerInstalled = true;
|
|
207
|
+
|
|
208
|
+
bridgeOn('ai.parseChatPointer', async (payload) => {
|
|
209
|
+
const { requestId, registrationId, matchGroups, fullToken, atIndex } = payload ?? {};
|
|
210
|
+
if (requestId == null || registrationId == null) {
|
|
211
|
+
return;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
const parse = chatPointerParseByRegistrationId.get(String(registrationId));
|
|
215
|
+
if (!parse) {
|
|
216
|
+
await bridgeInvoke('ai.parseChatPointerComplete', {
|
|
217
|
+
requestId,
|
|
218
|
+
ok: false,
|
|
219
|
+
error: `Unknown chat pointer parse registration: ${registrationId}`
|
|
220
|
+
});
|
|
221
|
+
return;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
try {
|
|
225
|
+
const groups = Array.isArray(matchGroups)
|
|
226
|
+
? matchGroups.map((g) => (g == null ? undefined : String(g)))
|
|
227
|
+
: [];
|
|
228
|
+
const synthetic = /** @type {RegExpMatchArray} */ (groups);
|
|
229
|
+
synthetic.index = 0;
|
|
230
|
+
synthetic.input = String(fullToken ?? '').replace(/^@/, '');
|
|
231
|
+
const result = parse(synthetic, String(fullToken ?? ''), Number(atIndex) || 0);
|
|
232
|
+
await bridgeInvoke('ai.parseChatPointerComplete', {
|
|
233
|
+
requestId,
|
|
234
|
+
ok: true,
|
|
235
|
+
result: result ?? null
|
|
236
|
+
});
|
|
237
|
+
} catch (error) {
|
|
238
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
239
|
+
await bridgeInvoke('ai.parseChatPointerComplete', {
|
|
240
|
+
requestId,
|
|
241
|
+
ok: false,
|
|
242
|
+
error: message
|
|
243
|
+
});
|
|
244
|
+
}
|
|
245
|
+
});
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* Subscribes to host-initiated before-turn invocations for the agent webview.
|
|
250
|
+
*
|
|
251
|
+
* Must run once before plugin activation so chat sends can reach registered handlers.
|
|
252
|
+
*/
|
|
253
|
+
export function installAiBeforeTurnListener() {
|
|
254
|
+
if (aiBeforeTurnListenerInstalled) {
|
|
255
|
+
return;
|
|
256
|
+
}
|
|
257
|
+
aiBeforeTurnListenerInstalled = true;
|
|
258
|
+
|
|
259
|
+
bridgeOn('ai.beforeTurn', async (payload) => {
|
|
260
|
+
const { requestId, chatId, model, hubId, userMessage, messages } = payload ?? {};
|
|
261
|
+
if (requestId == null) {
|
|
262
|
+
return;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
try {
|
|
266
|
+
const extraInstructions = [];
|
|
267
|
+
let cancelled = false;
|
|
268
|
+
let cancelReason;
|
|
269
|
+
const userMessageState = {
|
|
270
|
+
content: String(userMessage?.content ?? ''),
|
|
271
|
+
...(userMessage?.referenceSnapshots != null
|
|
272
|
+
? { referenceSnapshots: userMessage.referenceSnapshots }
|
|
273
|
+
: {})
|
|
274
|
+
};
|
|
275
|
+
/** @type {import('../types').PluginAiBeforeTurnContext} */
|
|
276
|
+
const ctx = {
|
|
277
|
+
chatId: Number(chatId) || 0,
|
|
278
|
+
model: String(model ?? ''),
|
|
279
|
+
...(hubId != null && String(hubId).trim() !== '' ? { hubId: String(hubId) } : {}),
|
|
280
|
+
userMessage: userMessageState,
|
|
281
|
+
instructions: {
|
|
282
|
+
push: (text) => {
|
|
283
|
+
const trimmed = String(text ?? '').trim();
|
|
284
|
+
if (trimmed) {
|
|
285
|
+
extraInstructions.push(trimmed);
|
|
286
|
+
}
|
|
287
|
+
},
|
|
288
|
+
get list() {
|
|
289
|
+
return [...extraInstructions];
|
|
290
|
+
}
|
|
291
|
+
},
|
|
292
|
+
messages: Array.isArray(messages)
|
|
293
|
+
? messages.map((row) => ({
|
|
294
|
+
role: row?.role ?? 'user',
|
|
295
|
+
content: row?.content ?? null
|
|
296
|
+
}))
|
|
297
|
+
: [],
|
|
298
|
+
cancel: (reason) => {
|
|
299
|
+
cancelled = true;
|
|
300
|
+
if (reason != null && String(reason).trim() !== '') {
|
|
301
|
+
cancelReason = String(reason).trim();
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
};
|
|
305
|
+
|
|
306
|
+
for (const handler of [...aiBeforeTurnHandlers]) {
|
|
307
|
+
await handler(ctx);
|
|
308
|
+
if (cancelled) {
|
|
309
|
+
break;
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
await bridgeInvoke('ai.beforeTurnComplete', {
|
|
314
|
+
requestId,
|
|
315
|
+
ok: true,
|
|
316
|
+
result: {
|
|
317
|
+
cancelled,
|
|
318
|
+
...(cancelReason != null ? { cancelReason } : {}),
|
|
319
|
+
userContent: ctx.userMessage.content,
|
|
320
|
+
extraInstructions
|
|
321
|
+
}
|
|
322
|
+
});
|
|
323
|
+
} catch (error) {
|
|
324
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
325
|
+
await bridgeInvoke('ai.beforeTurnComplete', {
|
|
326
|
+
requestId,
|
|
327
|
+
ok: false,
|
|
328
|
+
error: message
|
|
329
|
+
});
|
|
330
|
+
}
|
|
331
|
+
});
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
/**
|
|
335
|
+
* Subscribes to host-initiated after-turn push events for the agent webview.
|
|
336
|
+
*
|
|
337
|
+
* Must run once before plugin activation.
|
|
338
|
+
*/
|
|
339
|
+
export function installAiAfterTurnListener() {
|
|
340
|
+
if (aiAfterTurnListenerInstalled) {
|
|
341
|
+
return;
|
|
342
|
+
}
|
|
343
|
+
aiAfterTurnListenerInstalled = true;
|
|
344
|
+
|
|
345
|
+
bridgeOn('ai.afterTurn', (payload) => {
|
|
346
|
+
const ctx = /** @type {import('../types').PluginAiAfterTurnContext} */ (payload);
|
|
347
|
+
for (const handler of [...aiAfterTurnHandlers]) {
|
|
348
|
+
void Promise.resolve(handler(ctx)).catch((error) => {
|
|
349
|
+
console.error('Plugin ai.onAfterTurn handler failed:', error);
|
|
350
|
+
});
|
|
351
|
+
}
|
|
352
|
+
});
|
|
353
|
+
}
|
|
354
|
+
|
|
138
355
|
/**
|
|
139
356
|
* Normalizes one MCP header row from plugin registration input.
|
|
140
357
|
*
|
|
@@ -338,6 +555,11 @@ export function createBridgedPluginContext({ pluginId, mode, contributionId, rea
|
|
|
338
555
|
*/
|
|
339
556
|
const assertUi = () => assertPermission('ui');
|
|
340
557
|
|
|
558
|
+
/**
|
|
559
|
+
* Asserts network permission for outbound HTTP via hc.host.fetch.
|
|
560
|
+
*/
|
|
561
|
+
const assertNetwork = () => assertPermission('network');
|
|
562
|
+
|
|
341
563
|
/**
|
|
342
564
|
* Returns whether UI registration should run in this webview role.
|
|
343
565
|
*/
|
|
@@ -1080,9 +1302,9 @@ export function createBridgedPluginContext({ pluginId, mode, contributionId, rea
|
|
|
1080
1302
|
}
|
|
1081
1303
|
});
|
|
1082
1304
|
},
|
|
1083
|
-
|
|
1305
|
+
send: async () => {
|
|
1084
1306
|
assertUi();
|
|
1085
|
-
await bridgeInvoke('host.
|
|
1307
|
+
await bridgeInvoke('host.send');
|
|
1086
1308
|
},
|
|
1087
1309
|
createEnvironmentWithVariables: async (name, variables) => {
|
|
1088
1310
|
assertUi();
|
|
@@ -1254,9 +1476,9 @@ export function createBridgedPluginContext({ pluginId, mode, contributionId, rea
|
|
|
1254
1476
|
assertUi();
|
|
1255
1477
|
await bridgeInvoke('host.logRequestToConsole', { payload });
|
|
1256
1478
|
},
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
return bridgeInvoke('host.
|
|
1479
|
+
fetch: async (input, init) => {
|
|
1480
|
+
assertNetwork();
|
|
1481
|
+
return bridgeInvoke('host.fetch', { input, init });
|
|
1260
1482
|
},
|
|
1261
1483
|
clearResponse: async () => {
|
|
1262
1484
|
assertUi();
|
|
@@ -1408,13 +1630,28 @@ export function createBridgedPluginContext({ pluginId, mode, contributionId, rea
|
|
|
1408
1630
|
if (!/^[a-z][a-z0-9-]*$/.test(pointerId)) {
|
|
1409
1631
|
throw new Error(`Invalid chat pointer id: ${pointerId}`);
|
|
1410
1632
|
}
|
|
1633
|
+
const hasMatch = config?.match != null && config.match !== '';
|
|
1634
|
+
const hasParse = typeof config?.parse === 'function';
|
|
1635
|
+
if (hasMatch !== hasParse) {
|
|
1636
|
+
throw new Error('Chat pointer match and parse must be provided together.');
|
|
1637
|
+
}
|
|
1638
|
+
|
|
1411
1639
|
const registrationId = String(++aiChatPointerRegistrationCounter);
|
|
1640
|
+
/** @type {{ source: string; flags: string } | undefined} */
|
|
1641
|
+
let matchPayload;
|
|
1642
|
+
if (hasMatch) {
|
|
1643
|
+
matchPayload = serializeChatPointerMatch(/** @type {RegExp | string} */ (config.match));
|
|
1644
|
+
chatPointerParseByRegistrationId.set(registrationId, config.parse);
|
|
1645
|
+
}
|
|
1646
|
+
|
|
1412
1647
|
void bridgeInvoke('ai.registerChatPointer', {
|
|
1413
1648
|
registrationId,
|
|
1414
1649
|
pointerId,
|
|
1415
|
-
agentGuidance: config?.agentGuidance
|
|
1650
|
+
agentGuidance: config?.agentGuidance,
|
|
1651
|
+
...(matchPayload != null ? { match: matchPayload } : {})
|
|
1416
1652
|
});
|
|
1417
1653
|
return track(() => {
|
|
1654
|
+
chatPointerParseByRegistrationId.delete(registrationId);
|
|
1418
1655
|
void bridgeInvoke('ai.unregisterChatPointer', { registrationId });
|
|
1419
1656
|
});
|
|
1420
1657
|
},
|
|
@@ -1422,11 +1659,62 @@ export function createBridgedPluginContext({ pluginId, mode, contributionId, rea
|
|
|
1422
1659
|
assertAi();
|
|
1423
1660
|
await bridgeInvoke('ai.copyToChat', {
|
|
1424
1661
|
pointerId: String(input?.pointerId ?? '').trim(),
|
|
1425
|
-
key:
|
|
1662
|
+
key: input?.key != null ? String(input.key).trim() : undefined,
|
|
1663
|
+
token: input?.token != null ? String(input.token).trim() : undefined,
|
|
1426
1664
|
label: String(input?.label ?? '').trim(),
|
|
1427
1665
|
context: String(input?.context ?? ''),
|
|
1428
1666
|
selection: input?.selection
|
|
1429
1667
|
});
|
|
1668
|
+
},
|
|
1669
|
+
instructions: {
|
|
1670
|
+
add: (text) => {
|
|
1671
|
+
assertAi();
|
|
1672
|
+
if (!isAgent) {
|
|
1673
|
+
return noopDisposable();
|
|
1674
|
+
}
|
|
1675
|
+
const trimmed = String(text ?? '').trim();
|
|
1676
|
+
const registrationId = String(++aiInstructionsRegistrationCounter);
|
|
1677
|
+
if (trimmed) {
|
|
1678
|
+
aiInstructionsByRegistrationId.set(registrationId, trimmed);
|
|
1679
|
+
}
|
|
1680
|
+
void bridgeInvoke('ai.registerInstructions', {
|
|
1681
|
+
registrationId,
|
|
1682
|
+
text: trimmed
|
|
1683
|
+
});
|
|
1684
|
+
return track(() => {
|
|
1685
|
+
aiInstructionsByRegistrationId.delete(registrationId);
|
|
1686
|
+
void bridgeInvoke('ai.unregisterInstructions', { registrationId });
|
|
1687
|
+
});
|
|
1688
|
+
},
|
|
1689
|
+
get list() {
|
|
1690
|
+
return [...aiInstructionsByRegistrationId.values()];
|
|
1691
|
+
}
|
|
1692
|
+
},
|
|
1693
|
+
onBeforeTurn: (handler) => {
|
|
1694
|
+
assertAi();
|
|
1695
|
+
if (!isAgent) {
|
|
1696
|
+
return noopDisposable();
|
|
1697
|
+
}
|
|
1698
|
+
if (typeof handler !== 'function') {
|
|
1699
|
+
throw new Error('onBeforeTurn handler must be a function.');
|
|
1700
|
+
}
|
|
1701
|
+
aiBeforeTurnHandlers.add(handler);
|
|
1702
|
+
return track(() => {
|
|
1703
|
+
aiBeforeTurnHandlers.delete(handler);
|
|
1704
|
+
});
|
|
1705
|
+
},
|
|
1706
|
+
onAfterTurn: (handler) => {
|
|
1707
|
+
assertAi();
|
|
1708
|
+
if (!isAgent) {
|
|
1709
|
+
return noopDisposable();
|
|
1710
|
+
}
|
|
1711
|
+
if (typeof handler !== 'function') {
|
|
1712
|
+
throw new Error('onAfterTurn handler must be a function.');
|
|
1713
|
+
}
|
|
1714
|
+
aiAfterTurnHandlers.add(handler);
|
|
1715
|
+
return track(() => {
|
|
1716
|
+
aiAfterTurnHandlers.delete(handler);
|
|
1717
|
+
});
|
|
1430
1718
|
}
|
|
1431
1719
|
},
|
|
1432
1720
|
/**
|
package/dist/runtime/viewHost.js
CHANGED
|
@@ -2,6 +2,9 @@ import { clearContributionRegistry } from './contributionRegistry.js';
|
|
|
2
2
|
import {
|
|
3
3
|
createBridgedPluginContext,
|
|
4
4
|
executeLocalPluginCommand,
|
|
5
|
+
installAiAfterTurnListener,
|
|
6
|
+
installAiBeforeTurnListener,
|
|
7
|
+
installAiParseChatPointerListener,
|
|
5
8
|
installImportInvokeListener,
|
|
6
9
|
mountContributionView,
|
|
7
10
|
parseViewHostRole,
|
|
@@ -72,6 +75,9 @@ export async function bootstrapViewHost(options = {}) {
|
|
|
72
75
|
|
|
73
76
|
if (parsedRole.mode === 'agent') {
|
|
74
77
|
installImportInvokeListener();
|
|
78
|
+
installAiParseChatPointerListener();
|
|
79
|
+
installAiBeforeTurnListener();
|
|
80
|
+
installAiAfterTurnListener();
|
|
75
81
|
}
|
|
76
82
|
|
|
77
83
|
await module.activate(hc);
|
package/dist/snippets.d.ts
CHANGED
|
@@ -246,28 +246,37 @@ interface HcInfoApi {
|
|
|
246
246
|
}
|
|
247
247
|
|
|
248
248
|
/**
|
|
249
|
-
*
|
|
249
|
+
* RequestInit-compatible options accepted by hc.fetch.
|
|
250
250
|
*/
|
|
251
|
-
interface
|
|
251
|
+
interface HcFetchInit {
|
|
252
252
|
method?: string;
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
params?: Array<{ key: string; value: string; enabled?: boolean }>;
|
|
256
|
-
body?: string;
|
|
257
|
-
bodyType?: 'none' | 'json' | 'text' | 'multipart' | 'urlencoded';
|
|
258
|
-
body_type?: 'none' | 'json' | 'text' | 'multipart' | 'urlencoded';
|
|
253
|
+
headers?: Record<string, string> | Array<[string, string]>;
|
|
254
|
+
body?: string | URLSearchParams | null;
|
|
259
255
|
}
|
|
260
256
|
|
|
261
257
|
/**
|
|
262
|
-
*
|
|
258
|
+
* Headers-like facade returned by hc.fetch.
|
|
263
259
|
*/
|
|
264
|
-
interface
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
260
|
+
interface HcFetchHeaders {
|
|
261
|
+
get(name: string): string | null;
|
|
262
|
+
has(name: string): boolean;
|
|
263
|
+
entries(): IterableIterator<[string, string]>;
|
|
264
|
+
keys(): IterableIterator<string>;
|
|
265
|
+
values(): IterableIterator<string>;
|
|
266
|
+
forEach(callback: (value: string, key: string) => void): void;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
/**
|
|
270
|
+
* Response-compatible object returned by hc.fetch.
|
|
271
|
+
*/
|
|
272
|
+
interface HcFetchResponse {
|
|
273
|
+
readonly ok: boolean;
|
|
274
|
+
readonly status: number;
|
|
275
|
+
readonly statusText: string;
|
|
276
|
+
readonly headers: HcFetchHeaders;
|
|
277
|
+
text(): Promise<string>;
|
|
278
|
+
json(): Promise<unknown>;
|
|
279
|
+
arrayBuffer(): Promise<ArrayBuffer>;
|
|
271
280
|
}
|
|
272
281
|
|
|
273
282
|
/**
|
|
@@ -468,12 +477,14 @@ interface HcScriptApi {
|
|
|
468
477
|
/** Read-only metadata about the current script run (Postman pm.info equivalent). */
|
|
469
478
|
info: HcInfoApi;
|
|
470
479
|
/**
|
|
471
|
-
* Sends an outbound HTTP request
|
|
480
|
+
* Sends an outbound HTTP request using the native fetch(input, init?) signature.
|
|
472
481
|
* Requires Settings → General → Allow script network requests.
|
|
473
482
|
*
|
|
474
|
-
* @
|
|
483
|
+
* @param input - URL string, URL, or Request-like `{ url }` object.
|
|
484
|
+
* @param init - Optional RequestInit-compatible options.
|
|
485
|
+
* @throws When the setting is disabled or fetch is unavailable in this context.
|
|
475
486
|
*/
|
|
476
|
-
|
|
487
|
+
fetch(input: string | URL | { url: string }, init?: HcFetchInit): Promise<HcFetchResponse>;
|
|
477
488
|
/**
|
|
478
489
|
* Sends a one-shot prompt to a configured AI model.
|
|
479
490
|
* Includes the current send's request (and response in post-request scripts)
|