@heysummon/consumer-sdk 0.1.1 → 0.2.6

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/src/types.ts CHANGED
@@ -1,9 +1,9 @@
1
- export interface Provider {
1
+ export interface Expert {
2
2
  name: string;
3
3
  nameLower: string;
4
4
  apiKey: string;
5
- providerId: string;
6
- providerName: string;
5
+ expertId: string;
6
+ expertName: string;
7
7
  addedAt: string;
8
8
  }
9
9
 
@@ -12,18 +12,21 @@ export interface SubmitRequestOptions {
12
12
  messages?: Array<{ role: string; content: string }>;
13
13
  signPublicKey?: string;
14
14
  encryptPublicKey?: string;
15
- providerName?: string;
15
+ expertName?: string;
16
16
  requiresApproval?: boolean;
17
17
  }
18
18
 
19
19
  export interface SubmitRequestResult {
20
- requestId: string;
21
- refCode: string;
22
- status: string;
23
- expiresAt: string;
24
- providerUnavailable?: boolean;
25
- nextAvailableAt?: string;
20
+ requestId?: string;
21
+ refCode?: string;
22
+ status?: string;
23
+ expiresAt?: string;
26
24
  serverPublicKey?: string;
25
+ // Rejection fields (expert unavailable)
26
+ rejected?: boolean;
27
+ reason?: string;
28
+ message?: string;
29
+ nextAvailableAt?: string;
27
30
  }
28
31
 
29
32
  export interface PendingEvent {
@@ -32,11 +35,11 @@ export interface PendingEvent {
32
35
  | "new_message"
33
36
  | "keys_exchanged"
34
37
  | "responded"
35
- | "closed"
38
+ | "closed"
36
39
  | "cancelled";
37
40
  requestId: string;
38
41
  refCode: string | null;
39
- from?: "provider" | "consumer";
42
+ from?: "expert" | "consumer";
40
43
  messageCount?: number;
41
44
  respondedAt?: string | null;
42
45
  latestMessageAt?: string | null;
@@ -49,7 +52,7 @@ export interface PendingEvent {
49
52
 
50
53
  export interface Message {
51
54
  id: string;
52
- from: "provider" | "consumer";
55
+ from: "expert" | "consumer";
53
56
  ciphertext: string;
54
57
  iv: string;
55
58
  authTag: string;
@@ -66,8 +69,9 @@ export interface RequestStatusResponse {
66
69
  response?: string;
67
70
  lastMessage?: string;
68
71
  question?: string;
69
- providerName?: string;
70
- provider?: { id: string; name: string };
72
+ expertName?: string;
73
+ expert?: { id: string; name: string };
74
+ approvalDecision?: string;
71
75
  createdAt?: string;
72
76
  expiresAt?: string;
73
77
  }
@@ -75,17 +79,44 @@ export interface RequestStatusResponse {
75
79
  export interface HeySummonClientOptions {
76
80
  baseUrl: string;
77
81
  apiKey: string;
82
+ /** Enable E2E encryption (default: true). Set to false for plaintext mode. */
83
+ e2e?: boolean;
84
+ }
85
+
86
+ export interface DecryptedMessage {
87
+ id: string;
88
+ from: "expert" | "consumer";
89
+ ciphertext?: string;
90
+ iv?: string;
91
+ authTag?: string;
92
+ signature?: string;
93
+ messageId: string;
94
+ createdAt: string;
95
+ plaintext?: string;
96
+ decryptError?: boolean;
97
+ }
98
+
99
+ export interface MessagesResponse {
100
+ requestId: string;
101
+ refCode: string | null;
102
+ status: string;
103
+ consumerSignPubKey: string | null;
104
+ consumerEncryptPubKey: string | null;
105
+ expertSignPubKey: string | null;
106
+ expertEncryptPubKey: string | null;
107
+ messages: Message[];
108
+ expiresAt: string;
78
109
  }
79
110
 
80
111
  export interface WhoamiResult {
81
112
  keyId: string;
82
113
  keyName: string | null;
83
- provider: {
114
+ expert: {
84
115
  id: string;
85
116
  name: string;
86
117
  isActive: boolean;
87
118
  };
88
- expert: {
119
+ owner: {
89
120
  id: string;
90
121
  name: string | null;
91
122
  };
package/dist/poller.d.ts DELETED
@@ -1,28 +0,0 @@
1
- import type { HeySummonClient } from "./client.js";
2
- import type { PendingEvent } from "./types.js";
3
- export interface PollingWatcherOptions {
4
- client: HeySummonClient;
5
- /** Interval between polls in ms (default: 5000) */
6
- pollIntervalMs?: number;
7
- /** Called for each new event received */
8
- onEvent: (event: PendingEvent) => Promise<void>;
9
- /** Called on network/poll errors — must not throw */
10
- onError?: (err: Error) => void;
11
- }
12
- /**
13
- * Polls /api/v1/events/pending on an interval and fires onEvent for each result.
14
- * Replaces the 286-line platform-watcher.sh with a testable TypeScript class.
15
- *
16
- * Deduplication: tracks seen requestIds in memory to avoid double-processing.
17
- */
18
- export declare class PollingWatcher {
19
- private readonly opts;
20
- private timer;
21
- private seen;
22
- constructor(opts: PollingWatcherOptions);
23
- start(): void;
24
- stop(): void;
25
- isRunning(): boolean;
26
- /** Reset the deduplication set (useful in tests) */
27
- resetSeen(): void;
28
- }
package/dist/poller.js DELETED
@@ -1,57 +0,0 @@
1
- /**
2
- * Polls /api/v1/events/pending on an interval and fires onEvent for each result.
3
- * Replaces the 286-line platform-watcher.sh with a testable TypeScript class.
4
- *
5
- * Deduplication: tracks seen requestIds in memory to avoid double-processing.
6
- */
7
- export class PollingWatcher {
8
- opts;
9
- timer = null;
10
- seen = new Set();
11
- constructor(opts) {
12
- this.opts = opts;
13
- }
14
- start() {
15
- if (this.timer !== null)
16
- return; // already running
17
- const interval = this.opts.pollIntervalMs ?? 5_000;
18
- this.timer = setInterval(async () => {
19
- try {
20
- const { events } = await this.opts.client.getPendingEvents();
21
- for (const event of events) {
22
- const eventKey = `${event.requestId}:${event.type}:${event.latestMessageAt ?? ""}`;
23
- if (this.seen.has(eventKey))
24
- continue;
25
- this.seen.add(eventKey);
26
- try {
27
- await this.opts.onEvent(event);
28
- }
29
- catch (err) {
30
- this.opts.onError?.(err instanceof Error ? err : new Error(String(err)));
31
- }
32
- // Ack the event (best-effort, non-blocking)
33
- if (event.requestId) {
34
- this.opts.client.ackEvent(event.requestId).catch(() => { });
35
- }
36
- }
37
- }
38
- catch (err) {
39
- this.opts.onError?.(err instanceof Error ? err : new Error(String(err)));
40
- }
41
- }, interval);
42
- }
43
- stop() {
44
- if (this.timer !== null) {
45
- clearInterval(this.timer);
46
- this.timer = null;
47
- }
48
- }
49
- isRunning() {
50
- return this.timer !== null;
51
- }
52
- /** Reset the deduplication set (useful in tests) */
53
- resetSeen() {
54
- this.seen.clear();
55
- }
56
- }
57
- //# sourceMappingURL=poller.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"poller.js","sourceRoot":"","sources":["../src/poller.ts"],"names":[],"mappings":"AAaA;;;;;GAKG;AACH,MAAM,OAAO,cAAc;IAII;IAHrB,KAAK,GAA0C,IAAI,CAAC;IACpD,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAEjC,YAA6B,IAA2B;QAA3B,SAAI,GAAJ,IAAI,CAAuB;IAAG,CAAC;IAE5D,KAAK;QACH,IAAI,IAAI,CAAC,KAAK,KAAK,IAAI;YAAE,OAAO,CAAC,kBAAkB;QAEnD,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,cAAc,IAAI,KAAK,CAAC;QAEnD,IAAI,CAAC,KAAK,GAAG,WAAW,CAAC,KAAK,IAAI,EAAE;YAClC,IAAI,CAAC;gBACH,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,gBAAgB,EAAE,CAAC;gBAE7D,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;oBAC3B,MAAM,QAAQ,GAAG,GAAG,KAAK,CAAC,SAAS,IAAI,KAAK,CAAC,IAAI,IAAI,KAAK,CAAC,eAAe,IAAI,EAAE,EAAE,CAAC;oBACnF,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC;wBAAE,SAAS;oBACtC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;oBAExB,IAAI,CAAC;wBACH,MAAM,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;oBACjC,CAAC;oBAAC,OAAO,GAAG,EAAE,CAAC;wBACb,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;oBAC3E,CAAC;oBAED,4CAA4C;oBAC5C,IAAI,KAAK,CAAC,SAAS,EAAE,CAAC;wBACpB,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;oBAC7D,CAAC;gBACH,CAAC;YACH,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;YAC3E,CAAC;QACH,CAAC,EAAE,QAAQ,CAAC,CAAC;IACf,CAAC;IAED,IAAI;QACF,IAAI,IAAI,CAAC,KAAK,KAAK,IAAI,EAAE,CAAC;YACxB,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAC1B,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;QACpB,CAAC;IACH,CAAC;IAED,SAAS;QACP,OAAO,IAAI,CAAC,KAAK,KAAK,IAAI,CAAC;IAC7B,CAAC;IAED,oDAAoD;IACpD,SAAS;QACP,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;IACpB,CAAC;CACF"}
@@ -1,25 +0,0 @@
1
- import type { Provider } from "./types.js";
2
- /**
3
- * Typed replacement for the inline `node -e` JSON manipulation in the bash scripts.
4
- * Reads/writes providers.json with deduplication by API key and case-insensitive name.
5
- */
6
- export declare class ProviderStore {
7
- private readonly filePath;
8
- constructor(filePath: string);
9
- load(): Provider[];
10
- save(providers: Provider[]): void;
11
- /**
12
- * Add or update a provider entry.
13
- * Deduplicates by API key and case-insensitive name (same logic as the bash script).
14
- */
15
- add(entry: Omit<Provider, "addedAt" | "nameLower"> & {
16
- addedAt?: string;
17
- }): Provider;
18
- /** Case-insensitive lookup by name or alias */
19
- findByName(name: string): Provider | undefined;
20
- /** Look up by exact API key */
21
- findByKey(apiKey: string): Provider | undefined;
22
- /** Returns the first provider (default when only one is registered) */
23
- getDefault(): Provider | undefined;
24
- remove(apiKey: string): boolean;
25
- }
@@ -1 +0,0 @@
1
- {"version":3,"file":"provider-store.js","sourceRoot":"","sources":["../src/provider-store.ts"],"names":[],"mappings":"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"}
@@ -1,22 +0,0 @@
1
- interface TrackedRequest {
2
- requestId: string;
3
- refCode: string;
4
- provider?: string;
5
- }
6
- /**
7
- * File-based request tracker. Each request is stored as a file:
8
- * {dir}/{requestId} — contains the refCode
9
- * {dir}/{requestId}.provider — contains the provider name (optional)
10
- *
11
- * Compatible with the existing OpenClaw .requests/ directory format.
12
- */
13
- export declare class RequestTracker {
14
- private readonly dir;
15
- constructor(dir: string);
16
- track(requestId: string, refCode: string, providerName?: string): void;
17
- getRefCode(requestId: string): string | null;
18
- getProvider(requestId: string): string | null;
19
- remove(requestId: string): void;
20
- listActive(): TrackedRequest[];
21
- }
22
- export {};
@@ -1,66 +0,0 @@
1
- import { readFileSync, writeFileSync, existsSync, mkdirSync, unlinkSync, readdirSync } from "node:fs";
2
- import { join } from "node:path";
3
- /**
4
- * File-based request tracker. Each request is stored as a file:
5
- * {dir}/{requestId} — contains the refCode
6
- * {dir}/{requestId}.provider — contains the provider name (optional)
7
- *
8
- * Compatible with the existing OpenClaw .requests/ directory format.
9
- */
10
- export class RequestTracker {
11
- dir;
12
- constructor(dir) {
13
- this.dir = dir;
14
- if (!existsSync(dir)) {
15
- mkdirSync(dir, { recursive: true });
16
- }
17
- }
18
- track(requestId, refCode, providerName) {
19
- writeFileSync(join(this.dir, requestId), refCode);
20
- if (providerName) {
21
- writeFileSync(join(this.dir, `${requestId}.provider`), providerName);
22
- }
23
- }
24
- getRefCode(requestId) {
25
- const file = join(this.dir, requestId);
26
- if (!existsSync(file))
27
- return null;
28
- return readFileSync(file, "utf8").trim();
29
- }
30
- getProvider(requestId) {
31
- const file = join(this.dir, `${requestId}.provider`);
32
- if (!existsSync(file))
33
- return null;
34
- return readFileSync(file, "utf8").trim();
35
- }
36
- remove(requestId) {
37
- const refFile = join(this.dir, requestId);
38
- const provFile = join(this.dir, `${requestId}.provider`);
39
- if (existsSync(refFile))
40
- unlinkSync(refFile);
41
- if (existsSync(provFile))
42
- unlinkSync(provFile);
43
- }
44
- listActive() {
45
- if (!existsSync(this.dir))
46
- return [];
47
- const files = readdirSync(this.dir);
48
- const result = [];
49
- for (const file of files) {
50
- // Skip .provider files, .watcher.pid, hidden files
51
- if (file.includes("."))
52
- continue;
53
- const requestId = file;
54
- const refCode = this.getRefCode(requestId);
55
- if (!refCode)
56
- continue;
57
- result.push({
58
- requestId,
59
- refCode,
60
- provider: this.getProvider(requestId) ?? undefined,
61
- });
62
- }
63
- return result;
64
- }
65
- }
66
- //# sourceMappingURL=request-tracker.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"request-tracker.js","sourceRoot":"","sources":["../src/request-tracker.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,UAAU,EAAE,SAAS,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AACtG,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAQjC;;;;;;GAMG;AACH,MAAM,OAAO,cAAc;IACI;IAA7B,YAA6B,GAAW;QAAX,QAAG,GAAH,GAAG,CAAQ;QACtC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;YACrB,SAAS,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACtC,CAAC;IACH,CAAC;IAED,KAAK,CAAC,SAAiB,EAAE,OAAe,EAAE,YAAqB;QAC7D,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,SAAS,CAAC,EAAE,OAAO,CAAC,CAAC;QAClD,IAAI,YAAY,EAAE,CAAC;YACjB,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,WAAW,CAAC,EAAE,YAAY,CAAC,CAAC;QACvE,CAAC;IACH,CAAC;IAED,UAAU,CAAC,SAAiB;QAC1B,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;QACvC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;YAAE,OAAO,IAAI,CAAC;QACnC,OAAO,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,IAAI,EAAE,CAAC;IAC3C,CAAC;IAED,WAAW,CAAC,SAAiB;QAC3B,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,WAAW,CAAC,CAAC;QACrD,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;YAAE,OAAO,IAAI,CAAC;QACnC,OAAO,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,IAAI,EAAE,CAAC;IAC3C,CAAC;IAED,MAAM,CAAC,SAAiB;QACtB,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;QAC1C,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,WAAW,CAAC,CAAC;QACzD,IAAI,UAAU,CAAC,OAAO,CAAC;YAAE,UAAU,CAAC,OAAO,CAAC,CAAC;QAC7C,IAAI,UAAU,CAAC,QAAQ,CAAC;YAAE,UAAU,CAAC,QAAQ,CAAC,CAAC;IACjD,CAAC;IAED,UAAU;QACR,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC;YAAE,OAAO,EAAE,CAAC;QACrC,MAAM,KAAK,GAAG,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACpC,MAAM,MAAM,GAAqB,EAAE,CAAC;QAEpC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,mDAAmD;YACnD,IAAI,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC;gBAAE,SAAS;YAEjC,MAAM,SAAS,GAAG,IAAI,CAAC;YACvB,MAAM,OAAO,GAAG,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC;YAC3C,IAAI,CAAC,OAAO;gBAAE,SAAS;YAEvB,MAAM,CAAC,IAAI,CAAC;gBACV,SAAS;gBACT,OAAO;gBACP,QAAQ,EAAE,IAAI,CAAC,WAAW,CAAC,SAAS,CAAC,IAAI,SAAS;aACnD,CAAC,CAAC;QACL,CAAC;QAED,OAAO,MAAM,CAAC;IAChB,CAAC;CACF"}
package/src/poller.ts DELETED
@@ -1,72 +0,0 @@
1
- import type { HeySummonClient } from "./client.js";
2
- import type { PendingEvent } from "./types.js";
3
-
4
- export interface PollingWatcherOptions {
5
- client: HeySummonClient;
6
- /** Interval between polls in ms (default: 5000) */
7
- pollIntervalMs?: number;
8
- /** Called for each new event received */
9
- onEvent: (event: PendingEvent) => Promise<void>;
10
- /** Called on network/poll errors — must not throw */
11
- onError?: (err: Error) => void;
12
- }
13
-
14
- /**
15
- * Polls /api/v1/events/pending on an interval and fires onEvent for each result.
16
- * Replaces the 286-line platform-watcher.sh with a testable TypeScript class.
17
- *
18
- * Deduplication: tracks seen requestIds in memory to avoid double-processing.
19
- */
20
- export class PollingWatcher {
21
- private timer: ReturnType<typeof setInterval> | null = null;
22
- private seen = new Set<string>();
23
-
24
- constructor(private readonly opts: PollingWatcherOptions) {}
25
-
26
- start(): void {
27
- if (this.timer !== null) return; // already running
28
-
29
- const interval = this.opts.pollIntervalMs ?? 5_000;
30
-
31
- this.timer = setInterval(async () => {
32
- try {
33
- const { events } = await this.opts.client.getPendingEvents();
34
-
35
- for (const event of events) {
36
- const eventKey = `${event.requestId}:${event.type}:${event.latestMessageAt ?? ""}`;
37
- if (this.seen.has(eventKey)) continue;
38
- this.seen.add(eventKey);
39
-
40
- try {
41
- await this.opts.onEvent(event);
42
- } catch (err) {
43
- this.opts.onError?.(err instanceof Error ? err : new Error(String(err)));
44
- }
45
-
46
- // Ack the event (best-effort, non-blocking)
47
- if (event.requestId) {
48
- this.opts.client.ackEvent(event.requestId).catch(() => {});
49
- }
50
- }
51
- } catch (err) {
52
- this.opts.onError?.(err instanceof Error ? err : new Error(String(err)));
53
- }
54
- }, interval);
55
- }
56
-
57
- stop(): void {
58
- if (this.timer !== null) {
59
- clearInterval(this.timer);
60
- this.timer = null;
61
- }
62
- }
63
-
64
- isRunning(): boolean {
65
- return this.timer !== null;
66
- }
67
-
68
- /** Reset the deduplication set (useful in tests) */
69
- resetSeen(): void {
70
- this.seen.clear();
71
- }
72
- }
@@ -1,72 +0,0 @@
1
- import { readFileSync, writeFileSync, existsSync, mkdirSync, unlinkSync, readdirSync } from "node:fs";
2
- import { join } from "node:path";
3
-
4
- interface TrackedRequest {
5
- requestId: string;
6
- refCode: string;
7
- provider?: string;
8
- }
9
-
10
- /**
11
- * File-based request tracker. Each request is stored as a file:
12
- * {dir}/{requestId} — contains the refCode
13
- * {dir}/{requestId}.provider — contains the provider name (optional)
14
- *
15
- * Compatible with the existing OpenClaw .requests/ directory format.
16
- */
17
- export class RequestTracker {
18
- constructor(private readonly dir: string) {
19
- if (!existsSync(dir)) {
20
- mkdirSync(dir, { recursive: true });
21
- }
22
- }
23
-
24
- track(requestId: string, refCode: string, providerName?: string): void {
25
- writeFileSync(join(this.dir, requestId), refCode);
26
- if (providerName) {
27
- writeFileSync(join(this.dir, `${requestId}.provider`), providerName);
28
- }
29
- }
30
-
31
- getRefCode(requestId: string): string | null {
32
- const file = join(this.dir, requestId);
33
- if (!existsSync(file)) return null;
34
- return readFileSync(file, "utf8").trim();
35
- }
36
-
37
- getProvider(requestId: string): string | null {
38
- const file = join(this.dir, `${requestId}.provider`);
39
- if (!existsSync(file)) return null;
40
- return readFileSync(file, "utf8").trim();
41
- }
42
-
43
- remove(requestId: string): void {
44
- const refFile = join(this.dir, requestId);
45
- const provFile = join(this.dir, `${requestId}.provider`);
46
- if (existsSync(refFile)) unlinkSync(refFile);
47
- if (existsSync(provFile)) unlinkSync(provFile);
48
- }
49
-
50
- listActive(): TrackedRequest[] {
51
- if (!existsSync(this.dir)) return [];
52
- const files = readdirSync(this.dir);
53
- const result: TrackedRequest[] = [];
54
-
55
- for (const file of files) {
56
- // Skip .provider files, .watcher.pid, hidden files
57
- if (file.includes(".")) continue;
58
-
59
- const requestId = file;
60
- const refCode = this.getRefCode(requestId);
61
- if (!refCode) continue;
62
-
63
- result.push({
64
- requestId,
65
- refCode,
66
- provider: this.getProvider(requestId) ?? undefined,
67
- });
68
- }
69
-
70
- return result;
71
- }
72
- }