@indigoai-us/hq-cli 5.132.0 → 5.133.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 +36 -0
- package/dist/commands/lanes.d.ts +2 -2
- package/dist/commands/lanes.js +98 -20
- package/dist/commands/mesh.js +4 -1
- package/dist/lib/lanes/constants.d.ts +3 -0
- package/dist/lib/lanes/constants.js +3 -0
- package/dist/lib/lanes/index.d.ts +1 -0
- package/dist/lib/lanes/index.js +1 -0
- package/dist/lib/lanes/quota.d.ts +6 -3
- package/dist/lib/lanes/quota.js +65 -15
- package/dist/lib/lanes/reconcile.d.ts +5 -2
- package/dist/lib/lanes/reconcile.js +94 -2
- package/dist/lib/lanes/types.d.ts +2 -0
- package/dist/lib/lanes/types.js +2 -1
- package/dist/lib/mesh/live/daemon/doctor.d.ts +6 -0
- package/dist/lib/mesh/live/daemon/doctor.js +11 -0
- package/dist/lib/mesh/live/daemon/install.d.ts +7 -0
- package/dist/lib/mesh/live/daemon/install.js +16 -6
- package/dist/lib/mesh/live/daemon/legacy-listen.d.ts +43 -0
- package/dist/lib/mesh/live/daemon/legacy-listen.js +89 -0
- package/dist/lib/mesh/live/daemon/live-cache.d.ts +26 -0
- package/dist/lib/mesh/live/daemon/live-cache.js +116 -0
- package/dist/lib/mesh/live/daemon/presence.d.ts +7 -3
- package/dist/lib/mesh/live/daemon/presence.js +10 -9
- package/dist/lib/mesh/live/daemon/run.d.ts +13 -0
- package/dist/lib/mesh/live/daemon/run.js +51 -2
- package/dist/lib/mesh/live/daemon/work-subscribe.d.ts +31 -0
- package/dist/lib/mesh/live/daemon/work-subscribe.js +124 -0
- package/package.json +2 -2
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Contract-2 subscriber for the personal work topic.
|
|
3
|
+
* Owns live-cache.json writes. Presence publish stays on PresenceClient.
|
|
4
|
+
*/
|
|
5
|
+
import type { IClientOptions } from "mqtt";
|
|
6
|
+
import { type PersonalCredentialsFetcher } from "./credentials.js";
|
|
7
|
+
export interface WorkCacheMqtt {
|
|
8
|
+
on(event: string, handler: (...args: any[]) => void): unknown;
|
|
9
|
+
subscribe(topic: string, opts: {
|
|
10
|
+
qos: 0 | 1;
|
|
11
|
+
}, cb?: (err?: Error | null) => void): unknown;
|
|
12
|
+
end(force?: boolean, cb?: () => void): unknown;
|
|
13
|
+
}
|
|
14
|
+
export interface WorkCacheSubscriber {
|
|
15
|
+
stop: () => Promise<void>;
|
|
16
|
+
}
|
|
17
|
+
export declare function startWorkCacheSubscriber(opts: {
|
|
18
|
+
meshRoot: string;
|
|
19
|
+
fetchCredentials?: PersonalCredentialsFetcher;
|
|
20
|
+
token?: () => Promise<string>;
|
|
21
|
+
baseUrl?: string;
|
|
22
|
+
mqttConnect: (url: string, options: IClientOptions) => WorkCacheMqtt;
|
|
23
|
+
now?: () => Date;
|
|
24
|
+
timers?: {
|
|
25
|
+
setTimeout: (fn: () => void, ms: number) => unknown;
|
|
26
|
+
clearTimeout: (handle: unknown) => void;
|
|
27
|
+
};
|
|
28
|
+
onInfo?: (message: string) => void;
|
|
29
|
+
random?: () => number;
|
|
30
|
+
}): Promise<WorkCacheSubscriber>;
|
|
31
|
+
//# sourceMappingURL=work-subscribe.d.ts.map
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Contract-2 subscriber for the personal work topic.
|
|
3
|
+
* Owns live-cache.json writes. Presence publish stays on PresenceClient.
|
|
4
|
+
*/
|
|
5
|
+
import { createPersonalRealtimeFetcher, } from "./credentials.js";
|
|
6
|
+
import { presignIotWssUrl } from "./presign.js";
|
|
7
|
+
import { applyProjectViewPush, parseProjectViewPush } from "./live-cache.js";
|
|
8
|
+
import { backoffDelayMs, RECONNECT_MIN_DELAY_MS } from "./presence.js";
|
|
9
|
+
export async function startWorkCacheSubscriber(opts) {
|
|
10
|
+
const fetchCredentials = opts.fetchCredentials ??
|
|
11
|
+
(opts.token
|
|
12
|
+
? createPersonalRealtimeFetcher({
|
|
13
|
+
token: await opts.token(),
|
|
14
|
+
baseUrl: opts.baseUrl,
|
|
15
|
+
})
|
|
16
|
+
: null);
|
|
17
|
+
if (!fetchCredentials) {
|
|
18
|
+
throw new Error("work cache subscriber needs credentials");
|
|
19
|
+
}
|
|
20
|
+
const now = opts.now ?? (() => new Date());
|
|
21
|
+
const timers = opts.timers ?? {
|
|
22
|
+
setTimeout: (fn, ms) => setTimeout(fn, ms),
|
|
23
|
+
clearTimeout: (handle) => clearTimeout(handle),
|
|
24
|
+
};
|
|
25
|
+
const random = opts.random ?? Math.random;
|
|
26
|
+
let stopped = false;
|
|
27
|
+
let client = null;
|
|
28
|
+
let reconnectLogged = false;
|
|
29
|
+
let attempt = 0;
|
|
30
|
+
let timer = null;
|
|
31
|
+
let generation = 0;
|
|
32
|
+
const connect = async () => {
|
|
33
|
+
if (stopped)
|
|
34
|
+
return;
|
|
35
|
+
const gen = ++generation;
|
|
36
|
+
let bundle;
|
|
37
|
+
try {
|
|
38
|
+
bundle = await fetchCredentials();
|
|
39
|
+
}
|
|
40
|
+
catch (err) {
|
|
41
|
+
schedule(err);
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
if (stopped || gen !== generation)
|
|
45
|
+
return;
|
|
46
|
+
const topic = bundle.topics.work;
|
|
47
|
+
if (!topic) {
|
|
48
|
+
opts.onInfo?.("work cache subscribe skipped: credentials have no work topic");
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
const url = presignIotWssUrl(bundle.credentials, bundle.iotEndpoint, bundle.region, now());
|
|
52
|
+
const next = opts.mqttConnect(url, {
|
|
53
|
+
clientId: `${bundle.clientId}-work`,
|
|
54
|
+
clean: true,
|
|
55
|
+
reconnectPeriod: 0,
|
|
56
|
+
protocolVersion: 4,
|
|
57
|
+
});
|
|
58
|
+
client = next;
|
|
59
|
+
next.on("connect", () => {
|
|
60
|
+
if (stopped || gen !== generation)
|
|
61
|
+
return;
|
|
62
|
+
reconnectLogged = false;
|
|
63
|
+
attempt = 0;
|
|
64
|
+
next.subscribe(topic, { qos: 1 }, () => undefined);
|
|
65
|
+
});
|
|
66
|
+
next.on("message", (_topic, payload) => {
|
|
67
|
+
if (stopped || gen !== generation)
|
|
68
|
+
return;
|
|
69
|
+
if (_topic !== topic)
|
|
70
|
+
return;
|
|
71
|
+
const push = parseProjectViewPush(payload);
|
|
72
|
+
if (!push)
|
|
73
|
+
return;
|
|
74
|
+
const result = applyProjectViewPush(opts.meshRoot, push, now().toISOString());
|
|
75
|
+
if (result.applied) {
|
|
76
|
+
opts.onInfo?.(`project-view cache cursor=${result.cursor} ${push.companyUid}/${push.projectId}`);
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
next.on("close", () => {
|
|
80
|
+
if (stopped || gen !== generation)
|
|
81
|
+
return;
|
|
82
|
+
schedule();
|
|
83
|
+
});
|
|
84
|
+
};
|
|
85
|
+
const schedule = (err) => {
|
|
86
|
+
if (stopped)
|
|
87
|
+
return;
|
|
88
|
+
if (!reconnectLogged) {
|
|
89
|
+
reconnectLogged = true;
|
|
90
|
+
const detail = err instanceof Error ? `: ${err.message}` : "";
|
|
91
|
+
opts.onInfo?.(`work cache mqtt reconnecting${detail}`.slice(0, 200));
|
|
92
|
+
}
|
|
93
|
+
if (timer !== null)
|
|
94
|
+
timers.clearTimeout(timer);
|
|
95
|
+
const delay = backoffDelayMs(attempt, 1000, 60_000, random, 0, RECONNECT_MIN_DELAY_MS);
|
|
96
|
+
attempt += 1;
|
|
97
|
+
timer = timers.setTimeout(() => {
|
|
98
|
+
timer = null;
|
|
99
|
+
void connect();
|
|
100
|
+
}, delay);
|
|
101
|
+
};
|
|
102
|
+
await connect();
|
|
103
|
+
return {
|
|
104
|
+
stop: async () => {
|
|
105
|
+
stopped = true;
|
|
106
|
+
generation += 1;
|
|
107
|
+
if (timer !== null)
|
|
108
|
+
timers.clearTimeout(timer);
|
|
109
|
+
const current = client;
|
|
110
|
+
client = null;
|
|
111
|
+
if (!current)
|
|
112
|
+
return;
|
|
113
|
+
await new Promise((resolve) => {
|
|
114
|
+
try {
|
|
115
|
+
current.end(true, () => resolve());
|
|
116
|
+
}
|
|
117
|
+
catch {
|
|
118
|
+
resolve();
|
|
119
|
+
}
|
|
120
|
+
});
|
|
121
|
+
},
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
//# sourceMappingURL=work-subscribe.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@indigoai-us/hq-cli",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.133.0",
|
|
4
4
|
"description": "HQ by Indigo management CLI \u2014 modules and cloud sync",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
"dependencies": {
|
|
40
40
|
"@aws-sdk/client-iot-data-plane": "^3.1096.0",
|
|
41
41
|
"@aws-sdk/client-s3": "^3.1049.0",
|
|
42
|
-
"@indigoai-us/hq-cloud": "~6.16.
|
|
42
|
+
"@indigoai-us/hq-cloud": "~6.16.74",
|
|
43
43
|
"@indigoai-us/hq-flags-client": "^0.1.2",
|
|
44
44
|
"@sentry/node": "^10.49.0",
|
|
45
45
|
"@tobilu/qmd": "2.5.3",
|