@ours.network/fleet 1.2.0-nightly.30 → 1.2.0-nightly.32
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/build-info.json +4 -4
- package/dist/cli.js +48 -16
- package/dist/minimal-setup.d.ts +2 -0
- package/dist/minimal-setup.js +43 -0
- package/dist/web/available-port.d.ts +2 -0
- package/dist/web/available-port.js +23 -0
- package/dist/web/runtime.js +17 -2
- package/dist/web/service.d.ts +5 -0
- package/dist/web/service.js +8 -0
- package/dist/web-app/assets/FleetApp-D58F4xje.css +1 -0
- package/dist/web-app/assets/FleetApp-Gjz3h8uS.js +302 -0
- package/dist/web-app/assets/FleetApp-Gjz3h8uS.js.map +1 -0
- package/dist/web-app/assets/abnfDiagram-VCTEODGH-t4h5V8Cs.js +2 -0
- package/dist/web-app/assets/abnfDiagram-VCTEODGH-t4h5V8Cs.js.map +1 -0
- package/dist/web-app/assets/arc-DbufDTF6.js +2 -0
- package/dist/web-app/assets/arc-DbufDTF6.js.map +1 -0
- package/dist/web-app/assets/architectureDiagram-5GKGNRK7-D6K8jMN5.js +37 -0
- package/dist/web-app/assets/architectureDiagram-5GKGNRK7-D6K8jMN5.js.map +1 -0
- package/dist/web-app/assets/blockDiagram-I7D4REHJ-CWvkET2x.js +130 -0
- package/dist/web-app/assets/blockDiagram-I7D4REHJ-CWvkET2x.js.map +1 -0
- package/dist/web-app/assets/browser-B7y08DsC.js +9 -0
- package/dist/web-app/assets/browser-B7y08DsC.js.map +1 -0
- package/dist/web-app/assets/c4Diagram-7LVT6UL2-RNWA7VnD.js +39 -0
- package/dist/web-app/assets/c4Diagram-7LVT6UL2-RNWA7VnD.js.map +1 -0
- package/dist/web-app/assets/channel-BF3U9sI8.js +2 -0
- package/dist/web-app/assets/channel-BF3U9sI8.js.map +1 -0
- package/dist/web-app/assets/chunk-2Q5K7J3B-pdEuY4vj.js +2 -0
- package/dist/web-app/assets/chunk-2Q5K7J3B-pdEuY4vj.js.map +1 -0
- package/dist/web-app/assets/chunk-5VM5RSS4-DuAUtdUC.js +16 -0
- package/dist/web-app/assets/chunk-5VM5RSS4-DuAUtdUC.js.map +1 -0
- package/dist/web-app/assets/chunk-F27PBJKO-6kpb80Xt.js +2 -0
- package/dist/web-app/assets/chunk-F27PBJKO-6kpb80Xt.js.map +1 -0
- package/dist/web-app/assets/chunk-IMKFNOWR-DWC84P6A.js +232 -0
- package/dist/web-app/assets/chunk-IMKFNOWR-DWC84P6A.js.map +1 -0
- package/dist/web-app/assets/chunk-JWPE2WC7-FHO-M3vi.js +2 -0
- package/dist/web-app/assets/chunk-JWPE2WC7-FHO-M3vi.js.map +1 -0
- package/dist/web-app/assets/chunk-POPQ4Y6H-CjnlKvmR.js +2 -0
- package/dist/web-app/assets/chunk-POPQ4Y6H-CjnlKvmR.js.map +1 -0
- package/dist/web-app/assets/chunk-SVP7TREG-WHYWJ6xq.js +89 -0
- package/dist/web-app/assets/chunk-SVP7TREG-WHYWJ6xq.js.map +1 -0
- package/dist/web-app/assets/chunk-TICWLB2K-POupMpyL.js +207 -0
- package/dist/web-app/assets/chunk-TICWLB2K-POupMpyL.js.map +1 -0
- package/dist/web-app/assets/chunk-XXDRQBXY-Cw5HHqH-.js +2 -0
- package/dist/web-app/assets/chunk-XXDRQBXY-Cw5HHqH-.js.map +1 -0
- package/dist/web-app/assets/classDiagram-ZZMXUADV-1hdMzIme.js +2 -0
- package/dist/web-app/assets/classDiagram-ZZMXUADV-1hdMzIme.js.map +1 -0
- package/dist/web-app/assets/classDiagram-v2-VYDZK3BY-1hdMzIme.js +2 -0
- package/dist/web-app/assets/classDiagram-v2-VYDZK3BY-1hdMzIme.js.map +1 -0
- package/dist/web-app/assets/cose-bilkent-JH36ORCC-Cp6Hjine.js +2 -0
- package/dist/web-app/assets/cose-bilkent-JH36ORCC-Cp6Hjine.js.map +1 -0
- package/dist/web-app/assets/cynefin-OW5HDTMX-DI-DeNUk.js +179 -0
- package/dist/web-app/assets/cynefin-OW5HDTMX-DI-DeNUk.js.map +1 -0
- package/dist/web-app/assets/cynefinDiagram-5FMLGOSQ-todBCANI.js +63 -0
- package/dist/web-app/assets/cynefinDiagram-5FMLGOSQ-todBCANI.js.map +1 -0
- package/dist/web-app/assets/cytoscape.esm-CtNdOvlO.js +332 -0
- package/dist/web-app/assets/cytoscape.esm-CtNdOvlO.js.map +1 -0
- package/dist/web-app/assets/dagre-GXQ25YYZ-BvIVo7eh.js +5 -0
- package/dist/web-app/assets/dagre-GXQ25YYZ-BvIVo7eh.js.map +1 -0
- package/dist/web-app/assets/defaultLocale-DX6XiGOO.js +2 -0
- package/dist/web-app/assets/defaultLocale-DX6XiGOO.js.map +1 -0
- package/dist/web-app/assets/diagram-S7CK7UJ4-k9vDGlB5.js +31 -0
- package/dist/web-app/assets/diagram-S7CK7UJ4-k9vDGlB5.js.map +1 -0
- package/dist/web-app/assets/diagram-UQ7AKVKN-Bv7BT1dE.js +42 -0
- package/dist/web-app/assets/diagram-UQ7AKVKN-Bv7BT1dE.js.map +1 -0
- package/dist/web-app/assets/diagram-VSXAHHWV-m9I9AumX.js +4 -0
- package/dist/web-app/assets/diagram-VSXAHHWV-m9I9AumX.js.map +1 -0
- package/dist/web-app/assets/diagram-VX7I27RA-4VJ2qozS.js +25 -0
- package/dist/web-app/assets/diagram-VX7I27RA-4VJ2qozS.js.map +1 -0
- package/dist/web-app/assets/diagram-Z3DM3KII-CvH8JIEd.js +25 -0
- package/dist/web-app/assets/diagram-Z3DM3KII-CvH8JIEd.js.map +1 -0
- package/dist/web-app/assets/ebnfDiagram-PWID7BFC-DAGs23hd.js +2 -0
- package/dist/web-app/assets/ebnfDiagram-PWID7BFC-DAGs23hd.js.map +1 -0
- package/dist/web-app/assets/erDiagram-RLTQ6QDP-CEMyWKIa.js +100 -0
- package/dist/web-app/assets/erDiagram-RLTQ6QDP-CEMyWKIa.js.map +1 -0
- package/dist/web-app/assets/flowDiagram-HODETNUW-BnraxJTV.js +169 -0
- package/dist/web-app/assets/flowDiagram-HODETNUW-BnraxJTV.js.map +1 -0
- package/dist/web-app/assets/ganttDiagram-EL5Y4UJY-V6d4ICW0.js +293 -0
- package/dist/web-app/assets/ganttDiagram-EL5Y4UJY-V6d4ICW0.js.map +1 -0
- package/dist/web-app/assets/gitGraphDiagram-WWUBYQGX-Bj_gqcba.js +107 -0
- package/dist/web-app/assets/gitGraphDiagram-WWUBYQGX-Bj_gqcba.js.map +1 -0
- package/dist/web-app/assets/index-C4BdeFB9.css +1 -0
- package/dist/web-app/assets/index-i9rKiqYX.js +430 -0
- package/dist/web-app/assets/index-i9rKiqYX.js.map +1 -0
- package/dist/web-app/assets/infoDiagram-27XIBGKW-Dfm89NLl.js +3 -0
- package/dist/web-app/assets/infoDiagram-27XIBGKW-Dfm89NLl.js.map +1 -0
- package/dist/web-app/assets/init-Gi6I4Gst.js +2 -0
- package/dist/web-app/assets/init-Gi6I4Gst.js.map +1 -0
- package/dist/web-app/assets/ishikawaDiagram-5VMMS53U-D-ISiJTS.js +71 -0
- package/dist/web-app/assets/ishikawaDiagram-5VMMS53U-D-ISiJTS.js.map +1 -0
- package/dist/web-app/assets/jetbrains-mono-cyrillic-wght-normal-D73BlboJ.woff2 +0 -0
- package/dist/web-app/assets/jetbrains-mono-greek-wght-normal-Bw9x6K1M.woff2 +0 -0
- package/dist/web-app/assets/jetbrains-mono-latin-ext-wght-normal-DBQx-q_a.woff2 +0 -0
- package/dist/web-app/assets/jetbrains-mono-latin-wght-normal-B9CIFXIH.woff2 +0 -0
- package/dist/web-app/assets/jetbrains-mono-vietnamese-wght-normal-Bt-aOZkq.woff2 +0 -0
- package/dist/web-app/assets/journeyDiagram-3NMN7TZE-TTySrzws.js +140 -0
- package/dist/web-app/assets/journeyDiagram-3NMN7TZE-TTySrzws.js.map +1 -0
- package/dist/web-app/assets/kanban-definition-UXKFOSKX-BxntsBft.js +90 -0
- package/dist/web-app/assets/kanban-definition-UXKFOSKX-BxntsBft.js.map +1 -0
- package/dist/web-app/assets/katex-HP8lGamR.js +258 -0
- package/dist/web-app/assets/katex-HP8lGamR.js.map +1 -0
- package/dist/web-app/assets/layout-0sZak8Ho.js +2 -0
- package/dist/web-app/assets/layout-0sZak8Ho.js.map +1 -0
- package/dist/web-app/assets/linear-D4xk4kUi.js +2 -0
- package/dist/web-app/assets/linear-D4xk4kUi.js.map +1 -0
- package/dist/web-app/assets/mermaid.core-CNKolAgz.js +313 -0
- package/dist/web-app/assets/mermaid.core-CNKolAgz.js.map +1 -0
- package/dist/web-app/assets/mindmap-definition-YA3MSWOX-DLJijY_l.js +97 -0
- package/dist/web-app/assets/mindmap-definition-YA3MSWOX-DLJijY_l.js.map +1 -0
- package/dist/web-app/assets/ordinal-Cboi1Yqb.js +2 -0
- package/dist/web-app/assets/ordinal-Cboi1Yqb.js.map +1 -0
- package/dist/web-app/assets/pegDiagram-XKGWAZYB-xjrh9rBd.js +2 -0
- package/dist/web-app/assets/pegDiagram-XKGWAZYB-xjrh9rBd.js.map +1 -0
- package/dist/web-app/assets/pieDiagram-E7YTZNPT-CHE8ZMXN.js +40 -0
- package/dist/web-app/assets/pieDiagram-E7YTZNPT-CHE8ZMXN.js.map +1 -0
- package/dist/web-app/assets/quadrantDiagram-AXDQQJYC-CDlEe9sg.js +8 -0
- package/dist/web-app/assets/quadrantDiagram-AXDQQJYC-CDlEe9sg.js.map +1 -0
- package/dist/web-app/assets/railroadDiagram-O6MQD6OU-Dv7lFZ_v.js +2 -0
- package/dist/web-app/assets/railroadDiagram-O6MQD6OU-Dv7lFZ_v.js.map +1 -0
- package/dist/web-app/assets/requirementDiagram-BXWQKSXE-BetEel-k.js +85 -0
- package/dist/web-app/assets/requirementDiagram-BXWQKSXE-BetEel-k.js.map +1 -0
- package/dist/web-app/assets/sankeyDiagram-P5KCCOFB-DCQgLfvK.js +41 -0
- package/dist/web-app/assets/sankeyDiagram-P5KCCOFB-DCQgLfvK.js.map +1 -0
- package/dist/web-app/assets/sequenceDiagram-WJ2MYXX4-CsGOoqu_.js +163 -0
- package/dist/web-app/assets/sequenceDiagram-WJ2MYXX4-CsGOoqu_.js.map +1 -0
- package/dist/web-app/assets/sizeCapture-INFHLROL-CLQRMiEc.js +2 -0
- package/dist/web-app/assets/sizeCapture-INFHLROL-CLQRMiEc.js.map +1 -0
- package/dist/web-app/assets/stateDiagram-D77RDMKH-D2MRdC5Q.js +2 -0
- package/dist/web-app/assets/stateDiagram-D77RDMKH-D2MRdC5Q.js.map +1 -0
- package/dist/web-app/assets/stateDiagram-v2-MP3YSRHH-CToAT5fD.js +2 -0
- package/dist/web-app/assets/stateDiagram-v2-MP3YSRHH-CToAT5fD.js.map +1 -0
- package/dist/web-app/assets/swimlanes-42K2YHIH-BGjHfR8x.js +2 -0
- package/dist/web-app/assets/swimlanes-42K2YHIH-BGjHfR8x.js.map +1 -0
- package/dist/web-app/assets/swimlanesDiagram-VR7AAH4N-bLHg88Vk.js +9 -0
- package/dist/web-app/assets/swimlanesDiagram-VR7AAH4N-bLHg88Vk.js.map +1 -0
- package/dist/web-app/assets/timeline-definition-24CTP7MA-DhGtHQ0p.js +121 -0
- package/dist/web-app/assets/timeline-definition-24CTP7MA-DhGtHQ0p.js.map +1 -0
- package/dist/web-app/assets/vennDiagram-4TSXK5OY-Dv5irf00.js +35 -0
- package/dist/web-app/assets/vennDiagram-4TSXK5OY-Dv5irf00.js.map +1 -0
- package/dist/web-app/assets/wardleyDiagram-VM6X3IG4-JGiUTj5x.js +79 -0
- package/dist/web-app/assets/wardleyDiagram-VM6X3IG4-JGiUTj5x.js.map +1 -0
- package/dist/web-app/assets/xychartDiagram-S5SC5T6Z-Dw5ev7_Q.js +8 -0
- package/dist/web-app/assets/xychartDiagram-S5SC5T6Z-Dw5ev7_Q.js.map +1 -0
- package/dist/web-app/fleet-index.html +19 -0
- package/dist/web-app/fleet.webmanifest +37 -0
- package/dist/web-app/icons/apple-touch-icon.png +0 -0
- package/dist/web-app/icons/favicon-16.png +0 -0
- package/dist/web-app/icons/favicon-32.png +0 -0
- package/dist/web-app/icons/icon-192-maskable.png +0 -0
- package/dist/web-app/icons/icon-192.png +0 -0
- package/dist/web-app/icons/icon-512-maskable.png +0 -0
- package/dist/web-app/icons/icon-512.png +0 -0
- package/dist/web-app/index.html +19 -0
- package/dist/web-app/manifest.webmanifest +17 -0
- package/dist/web-app/sw.js +221 -0
- package/dist/web-app/version.json +1 -0
- package/dist/web-app/workspace-install.sh +148 -0
- package/dist/web-app/workspace-tunnel.sh +40 -0
- package/dist/workspace-enrollment.d.ts +3 -0
- package/dist/workspace-enrollment.js +18 -1
- package/package.json +2 -2
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
// build.mjs replaces this stamp on every release so browsers always see
|
|
2
|
+
// different service-worker bytes.
|
|
3
|
+
// This worker deliberately caches no application shell: keeping an old HTML
|
|
4
|
+
// document and hashed JS chunks in Cache Storage can strand an installed PWA
|
|
5
|
+
// on a blank screen during a deployment.
|
|
6
|
+
const SW_BUILD = '21b1610c125e41982803ecc8c389c169dd1252c4';
|
|
7
|
+
function workerBase() {
|
|
8
|
+
try { return new URL(self.registration.scope).pathname; } catch { return '/'; }
|
|
9
|
+
}
|
|
10
|
+
function inWorkerScope(url, origin) {
|
|
11
|
+
try { const parsed = new URL(url); return parsed.origin === origin && parsed.pathname.startsWith(workerBase()); } catch { return false; }
|
|
12
|
+
}
|
|
13
|
+
const FOREGROUND_HEARTBEAT_FRESH_MS = 30_000;
|
|
14
|
+
let lastVisibility = null;
|
|
15
|
+
let lastIOSStandalone = false;
|
|
16
|
+
|
|
17
|
+
// WindowClient.visibilityState is not authoritative on mobile PWAs. Suppress
|
|
18
|
+
// only when a page-owned heartbeat is fresh and explicitly visible. Installed
|
|
19
|
+
// iOS always shows because its service worker can be torn down between events.
|
|
20
|
+
function shouldSuppressNotification(clientList, visibility, now, freshMs, iosStandalone) {
|
|
21
|
+
if (!clientList || clientList.length === 0 || iosStandalone) return false;
|
|
22
|
+
const current = visibility === undefined ? lastVisibility : visibility;
|
|
23
|
+
const time = now === undefined ? Date.now() : now;
|
|
24
|
+
const fresh = freshMs === undefined ? FOREGROUND_HEARTBEAT_FRESH_MS : freshMs;
|
|
25
|
+
return !!current && time - current.ts <= fresh && current.state === 'visible';
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function queryClientsVisible(clientList, timeoutMs) {
|
|
29
|
+
if (!clientList || clientList.length === 0) return Promise.resolve(false);
|
|
30
|
+
const timeout = typeof timeoutMs === 'number' ? timeoutMs : 400;
|
|
31
|
+
return new Promise((resolve) => {
|
|
32
|
+
let replies = 0;
|
|
33
|
+
let visible = false;
|
|
34
|
+
let iosStandalone = false;
|
|
35
|
+
let settled = false;
|
|
36
|
+
const ports = [];
|
|
37
|
+
let timer;
|
|
38
|
+
const finish = () => {
|
|
39
|
+
if (settled) return;
|
|
40
|
+
settled = true;
|
|
41
|
+
clearTimeout(timer);
|
|
42
|
+
for (const port of ports) { try { port.close(); } catch { /* closed */ } }
|
|
43
|
+
resolve(visible && !iosStandalone);
|
|
44
|
+
};
|
|
45
|
+
const replied = (data) => {
|
|
46
|
+
replies++;
|
|
47
|
+
if (data?.iosStandalone === true) iosStandalone = true;
|
|
48
|
+
if (data?.state === 'visible') visible = true;
|
|
49
|
+
if (replies >= clientList.length) finish();
|
|
50
|
+
};
|
|
51
|
+
for (const client of clientList) {
|
|
52
|
+
try {
|
|
53
|
+
const channel = new MessageChannel();
|
|
54
|
+
ports.push(channel.port1);
|
|
55
|
+
channel.port1.onmessage = (event) => replied(event.data);
|
|
56
|
+
client.postMessage({ type: 'ours-visibility-query' }, [channel.port2]);
|
|
57
|
+
} catch {
|
|
58
|
+
replied(null);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
timer = setTimeout(finish, timeout);
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function safeNotificationUrl(value, origin) {
|
|
66
|
+
if (typeof value !== 'string' || !value.startsWith('/') || value.startsWith('//')) return workerBase() + 'chats';
|
|
67
|
+
try {
|
|
68
|
+
const parsed = new URL(value, origin);
|
|
69
|
+
if (parsed.origin !== origin || !parsed.pathname.startsWith('/')) return workerBase() + 'chats';
|
|
70
|
+
const base = workerBase();
|
|
71
|
+
const pathname = base !== '/' && parsed.pathname.startsWith('/chats') ? base + parsed.pathname.slice(1) : parsed.pathname;
|
|
72
|
+
if (!pathname.startsWith(base)) return base + 'chats';
|
|
73
|
+
return pathname + parsed.search + parsed.hash;
|
|
74
|
+
} catch {
|
|
75
|
+
return workerBase() + 'chats';
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function selectClickTarget(clientList, origin, targetUrl) {
|
|
80
|
+
const safe = (clientList || []).filter((client) => {
|
|
81
|
+
return inWorkerScope(client.url, origin);
|
|
82
|
+
});
|
|
83
|
+
if (targetUrl) {
|
|
84
|
+
const target = new URL(targetUrl, origin).href;
|
|
85
|
+
const exact = safe.find((client) => client.url === target);
|
|
86
|
+
if (exact) return exact;
|
|
87
|
+
}
|
|
88
|
+
return safe.find((client) => client.focused) || safe[0] || null;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function selectForegroundClient(clientList, origin) {
|
|
92
|
+
const safe = (clientList || []).filter((client) => {
|
|
93
|
+
return inWorkerScope(client.url, origin);
|
|
94
|
+
});
|
|
95
|
+
return safe.find((client) => client.visibilityState === 'visible') || safe[0] || null;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function safeText(value, fallback, max) {
|
|
99
|
+
return typeof value === 'string' && value.trim() ? value.slice(0, max) : fallback;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// Activate immediately, claim existing windows, and purge every legacy
|
|
103
|
+
// app-shell cache. HTML and hashed bundles then
|
|
104
|
+
// always come from the server's current immutable release.
|
|
105
|
+
self.addEventListener('install', () => {
|
|
106
|
+
self.skipWaiting();
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
self.addEventListener('activate', (event) => {
|
|
110
|
+
event.waitUntil((async () => {
|
|
111
|
+
await self.clients.claim();
|
|
112
|
+
try {
|
|
113
|
+
const keys = await caches.keys();
|
|
114
|
+
await Promise.all(keys.map(async (key) => {
|
|
115
|
+
const cache = await caches.open(key);
|
|
116
|
+
for (const request of await cache.keys()) {
|
|
117
|
+
const url = new URL(request.url), base = workerBase(), path = url.pathname.slice(base.length);
|
|
118
|
+
if (url.origin === self.location.origin && url.pathname.startsWith(base) &&
|
|
119
|
+
(path === '' || path === 'index.html' || path === 'fleet-index.html' || path === 'fleet' || path.startsWith('fleet/') || path.startsWith('assets/')))
|
|
120
|
+
await cache.delete(request);
|
|
121
|
+
}
|
|
122
|
+
}));
|
|
123
|
+
} catch { /* Cache API may be unavailable; nothing to purge. */ }
|
|
124
|
+
try {
|
|
125
|
+
const windows = await self.clients.matchAll({ type: 'window', includeUncontrolled: true });
|
|
126
|
+
for (const client of windows.filter(client => inWorkerScope(client.url, self.location.origin))) client.postMessage({ type: 'ours-sw-activated', build: SW_BUILD });
|
|
127
|
+
} catch { /* no clients */ }
|
|
128
|
+
})());
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
self.addEventListener('message', (event) => {
|
|
132
|
+
const data = event.data;
|
|
133
|
+
if (data?.type === 'SKIP_WAITING') {
|
|
134
|
+
self.skipWaiting();
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
if (data?.type === 'ours-visibility' && (data.state === 'visible' || data.state === 'hidden')) {
|
|
138
|
+
lastVisibility = { state: data.state, ts: typeof data.ts === 'number' ? data.ts : Date.now() };
|
|
139
|
+
lastIOSStandalone = data.iosStandalone === true;
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
if (data?.type === 'ours-clear-notifications') {
|
|
143
|
+
event.waitUntil((async () => {
|
|
144
|
+
const notifications = await self.registration.getNotifications();
|
|
145
|
+
for (const notification of notifications) notification.close();
|
|
146
|
+
if ('clearAppBadge' in self.navigator) await self.navigator.clearAppBadge().catch(() => {});
|
|
147
|
+
})());
|
|
148
|
+
}
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
self.addEventListener('push', (event) => {
|
|
152
|
+
let payload = {};
|
|
153
|
+
try { payload = event.data ? event.data.json() : {}; } catch { payload = {}; }
|
|
154
|
+
if (!payload || typeof payload !== 'object' || Array.isArray(payload)) payload = {};
|
|
155
|
+
const title = safeText(payload.title, 'ours messenger', 160);
|
|
156
|
+
const body = safeText(payload.body, 'Open messenger to view the update.', 512);
|
|
157
|
+
const url = safeNotificationUrl(payload.url, self.location.origin);
|
|
158
|
+
const tag = payload.kind === 'notification' && typeof payload.notification_id === 'string' ? `ours-${payload.notification_id.slice(0, 256)}` : typeof payload.wire_id === 'string' && payload.wire_id
|
|
159
|
+
? `ours-${payload.wire_id.slice(0, 256)}` : undefined;
|
|
160
|
+
event.waitUntil(self.clients.matchAll({ type: 'window', includeUncontrolled: true }).then(async (clientList) => {
|
|
161
|
+
if (payload.kind === 'notification') for (const client of clientList) client.postMessage({ type: 'ours-push-inbox-changed' });
|
|
162
|
+
const suppress = shouldSuppressNotification(clientList, undefined, undefined, undefined, lastIOSStandalone)
|
|
163
|
+
|| await queryClientsVisible(clientList);
|
|
164
|
+
if (suppress) {
|
|
165
|
+
selectForegroundClient(clientList, self.location.origin)?.postMessage({
|
|
166
|
+
type: 'ours-push-foreground', kind: payload.kind,
|
|
167
|
+
contact_id: payload.contact_id, wire_id: payload.wire_id,
|
|
168
|
+
});
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
await self.registration.showNotification(title, {
|
|
172
|
+
body, icon: workerBase() + 'icons/icon-192.png', badge: workerBase() + 'icons/icon-192.png', tag, data: { url },
|
|
173
|
+
});
|
|
174
|
+
if ('setAppBadge' in self.navigator) {
|
|
175
|
+
const notifications = await self.registration.getNotifications();
|
|
176
|
+
await self.navigator.setAppBadge(notifications.length).catch(() => {});
|
|
177
|
+
}
|
|
178
|
+
}));
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
self.addEventListener('pushsubscriptionchange', (event) => {
|
|
182
|
+
event.waitUntil(self.clients.matchAll({ type: 'window', includeUncontrolled: true }).then((clientList) => {
|
|
183
|
+
for (const client of clientList) client.postMessage({ type: 'ours-push-repair-required' });
|
|
184
|
+
}));
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
self.addEventListener('notificationclick', (event) => {
|
|
188
|
+
event.notification.close();
|
|
189
|
+
const url = safeNotificationUrl(event.notification.data?.url, self.location.origin);
|
|
190
|
+
event.waitUntil(self.clients.matchAll({ type: 'window', includeUncontrolled: true }).then(async (clientList) => {
|
|
191
|
+
const target = selectClickTarget(clientList, self.location.origin, url);
|
|
192
|
+
if (target) {
|
|
193
|
+
const desired = new URL(url, self.location.origin).href;
|
|
194
|
+
if (target.url !== desired && 'navigate' in target) await target.navigate(desired);
|
|
195
|
+
return target.focus();
|
|
196
|
+
}
|
|
197
|
+
return self.clients.openWindow(url);
|
|
198
|
+
}));
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
// Credentials are never cached or persisted; separate tunnel origins cannot share them.
|
|
202
|
+
const workspaceCredentials = new Map();
|
|
203
|
+
self.addEventListener('message', event => {
|
|
204
|
+
if (event.data?.type !== 'ours.workspace.credential' || !event.source?.id) return;
|
|
205
|
+
const sourceUrl=new URL(event.source.url);
|
|
206
|
+
if(sourceUrl.origin!==self.location.origin || sourceUrl.searchParams.get('workspace-frame')!=='1')return;
|
|
207
|
+
if (typeof event.data.token === 'string' && event.data.token) workspaceCredentials.set(event.source.id,event.data.token);
|
|
208
|
+
else workspaceCredentials.delete(event.source.id);
|
|
209
|
+
event.ports[0]?.postMessage({ready:true});
|
|
210
|
+
event.waitUntil(self.clients.matchAll({type:'window',includeUncontrolled:true}).then(clients=>{const live=new Set(clients.map(client=>client.id));for(const id of workspaceCredentials.keys())if(!live.has(id))workspaceCredentials.delete(id);}));
|
|
211
|
+
});
|
|
212
|
+
self.addEventListener('fetch', event => {
|
|
213
|
+
const url = new URL(event.request.url);
|
|
214
|
+
if (url.origin !== self.location.origin || !url.pathname.startsWith('/messenger/api/media/')) return;
|
|
215
|
+
const token = workspaceCredentials.get(event.clientId);
|
|
216
|
+
if (!token) return;
|
|
217
|
+
const headers = new Headers(event.request.headers);headers.set('Authorization','Bearer '+token);
|
|
218
|
+
// Native media requests use no-cors, whose header guard strips Authorization.
|
|
219
|
+
// The URL was checked above, so a same-origin worker request can carry it.
|
|
220
|
+
event.respondWith(fetch(new Request(event.request,{headers,mode:'same-origin',cache:'no-store',credentials:'omit'})));
|
|
221
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"sha":"21b1610c125e41982803ecc8c389c169dd1252c4","time":"2026-10-02T08:00:39.873Z"}
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Personalised payload is read from stdin and never logged or passed in argv.
|
|
3
|
+
set -euo pipefail
|
|
4
|
+
umask 077
|
|
5
|
+
set +x
|
|
6
|
+
case "${1:-}" in ''|--check) ;; *) echo 'Unsupported bootstrap option' >&2; exit 2;; esac
|
|
7
|
+
check_only=${1:-}
|
|
8
|
+
if [[ $check_only != --check ]]; then
|
|
9
|
+
IFS= read -r payload
|
|
10
|
+
[[ ${#payload} -le 32768 && $payload =~ ^[A-Za-z0-9_-]+$ ]] || { echo 'Invalid workspace payload' >&2; exit 1; }
|
|
11
|
+
fi
|
|
12
|
+
missing=()
|
|
13
|
+
for binary in node npm curl cloudflared; do
|
|
14
|
+
command -v "$binary" >/dev/null || missing+=("$binary")
|
|
15
|
+
done
|
|
16
|
+
if [[ ${#missing[@]} != 0 ]]; then
|
|
17
|
+
printf 'Missing prerequisites: %s. Install these manually or ask your agent, then retry.\n' "${missing[*]}" >&2
|
|
18
|
+
exit 1
|
|
19
|
+
fi
|
|
20
|
+
node -e 'if(Number(process.versions.node.split(".")[0])<22){console.error("Node.js 22 or newer is required. Install it manually or ask your agent, then retry.");process.exit(1)}'
|
|
21
|
+
cloudflared --version >/dev/null
|
|
22
|
+
if [[ -z ${OURS_CONFIG:-} && ! -e "$HOME/.ours-client/profile.json" && ! -e "$HOME/.ours-network/workspace/installation.json" ]]; then
|
|
23
|
+
if ! command -v docker >/dev/null; then
|
|
24
|
+
echo 'Missing fresh-server prerequisites: docker. Install Docker and Docker Compose 2.35 or newer, configure access for your normal user, then retry.' >&2
|
|
25
|
+
exit 1
|
|
26
|
+
fi
|
|
27
|
+
if ! docker info --format '{{.ServerVersion}}' >/dev/null 2>&1; then
|
|
28
|
+
echo 'Docker is not reachable as your normal user. Start Docker and configure user access, then retry without running this installer as root.' >&2
|
|
29
|
+
exit 1
|
|
30
|
+
fi
|
|
31
|
+
if ! docker compose version --short >/dev/null 2>&1; then
|
|
32
|
+
echo 'Docker Compose plugin is missing. Install Docker Compose 2.35 or newer, then retry.' >&2
|
|
33
|
+
exit 1
|
|
34
|
+
fi
|
|
35
|
+
fi
|
|
36
|
+
# Install only Ours packages in an isolated user prefix. Host prerequisites and
|
|
37
|
+
# existing host CLI installations are never installed or upgraded by this script.
|
|
38
|
+
export NPM_CONFIG_PREFIX="$HOME/.local/share/ours-bootstrap/tools"
|
|
39
|
+
export PATH="$NPM_CONFIG_PREFIX/bin:$HOME/.local/bin:$PATH"
|
|
40
|
+
echo 'Preparing Ours tools…'
|
|
41
|
+
npm install --global --no-audit --no-fund @ours.network/install@1.2.1-nightly.23 @ours.network/fleet@1.2.0-nightly.31
|
|
42
|
+
# Starter configuration only: the browser checks installed/authenticated harnesses
|
|
43
|
+
# and asks for actual model choices before any FleetCoordinator is started.
|
|
44
|
+
fleet_settings="$HOME/.local/share/ours-bootstrap/fleet-init.json"
|
|
45
|
+
mkdir -p "$HOME/.local/share/ours-bootstrap"
|
|
46
|
+
node --input-type=module - "$fleet_settings" <<'OURS_FLEET_SETTINGS'
|
|
47
|
+
import {readFileSync,writeFileSync} from 'node:fs';
|
|
48
|
+
import {join} from 'node:path';
|
|
49
|
+
import {pathToFileURL} from 'node:url';
|
|
50
|
+
const root=join(process.env.NPM_CONFIG_PREFIX,'lib/node_modules/@ours.network/fleet');
|
|
51
|
+
const catalog=JSON.parse(readFileSync(join(root,'presets/brain-catalog.json'),'utf8'));
|
|
52
|
+
const model=catalog.models.find(value=>value.harness==='codex' && value.session==='acp' && value.model==='gpt-6.1-sol');
|
|
53
|
+
if(!model)throw Error('Published Fleet starter model is missing');
|
|
54
|
+
const path=process.argv[2];
|
|
55
|
+
writeFileSync(path,JSON.stringify({subscriptions:['codex'],assignmentStrategy:'one-model',models:{development:model,review:model,coordination:model},reasoning:'balanced'}),{mode:0o600});
|
|
56
|
+
const {readInitSettings}=await import(pathToFileURL(join(root,'dist/init-wizard.js')));
|
|
57
|
+
readInitSettings(path);
|
|
58
|
+
OURS_FLEET_SETTINGS
|
|
59
|
+
cloudflared --version
|
|
60
|
+
ours-fleet workspace-enroll --help >/dev/null
|
|
61
|
+
ours-install --help >/dev/null
|
|
62
|
+
mkdir -p "$HOME/.local/bin"
|
|
63
|
+
# Offer host commands on fresh hosts without replacing an existing CLI.
|
|
64
|
+
offer_host_commands() {
|
|
65
|
+
for binary in ours-install ours-fleet ours; do
|
|
66
|
+
if [[ -x "$NPM_CONFIG_PREFIX/bin/$binary" && ! -e "$HOME/.local/bin/$binary" && ! -L "$HOME/.local/bin/$binary" ]] && ! PATH="${PATH#*:}" command -v "$binary" >/dev/null 2>&1; then
|
|
67
|
+
ln -s "$NPM_CONFIG_PREFIX/bin/$binary" "$HOME/.local/bin/$binary"
|
|
68
|
+
fi
|
|
69
|
+
done
|
|
70
|
+
}
|
|
71
|
+
offer_host_commands
|
|
72
|
+
# Server setup acquires the verified ours client later. Expose it even when a
|
|
73
|
+
# subsequent enrollment step fails, without replacing an existing host command.
|
|
74
|
+
trap 'offer_host_commands' EXIT
|
|
75
|
+
# Use the published installer's own profile validation and recorded-engine preflight.
|
|
76
|
+
# Its disposable capability project runs before redeeming the personal command.
|
|
77
|
+
installation_kind=$(node --input-type=module <<'OURS_HOST_CHECK'
|
|
78
|
+
import {join} from 'node:path';
|
|
79
|
+
import {existsSync} from 'node:fs';
|
|
80
|
+
import {pathToFileURL} from 'node:url';
|
|
81
|
+
const root=join(process.env.NPM_CONFIG_PREFIX,'lib/node_modules/@ours.network/install');
|
|
82
|
+
const {realEffects}=await import(pathToFileURL(join(root,'lib/effects.mjs')));
|
|
83
|
+
const {validateInstallation}=await import(pathToFileURL(join(root,'lib/plan.mjs')));
|
|
84
|
+
const effects=realEffects({out:()=>{},write:()=>{}});
|
|
85
|
+
const managed=effects.readManagedClientProfile();
|
|
86
|
+
if(process.env.OURS_CONFIG || managed){
|
|
87
|
+
if(process.env.OURS_CONFIG && !effects.readProfile(process.env.OURS_CONFIG))throw Error('Existing OURS_CONFIG must select a complete gateway client profile');
|
|
88
|
+
process.stdout.write('existing');
|
|
89
|
+
}else{
|
|
90
|
+
const state=join(effects.home,'.ours-network','workspace');
|
|
91
|
+
const pending=existsSync(join(effects.home,'.ours-client','workspace-setup-pending.json'));
|
|
92
|
+
if(existsSync(join(process.env.OURS_FLEET_HOME || effects.home,'fleet.yaml')) && !pending)throw Error('Existing Fleet configuration needs its gateway client profile; no new root was created');
|
|
93
|
+
const retained=effects.readJson(join(state,'installation.json'));
|
|
94
|
+
if(retained && !pending)throw Error('Existing server needs its gateway client profile; no new root was created');
|
|
95
|
+
// Never construct a new installation over a partial retry. The actual wrapper
|
|
96
|
+
// validates the private pending marker/account before any provisioning.
|
|
97
|
+
const record=retained ? validateInstallation(retained,state) : {mode:'docker',containerEngine:'docker',project:'ours-account-prerequisite-probe'};
|
|
98
|
+
try {
|
|
99
|
+
await effects.serverPreflight(record,'install',{existing:Boolean(retained)});
|
|
100
|
+
} catch (error) {
|
|
101
|
+
const message=String(error?.message || 'Host compatibility check failed');
|
|
102
|
+
if (/systemctl --user is-enabled podman-restart\.service exited \d+: disabled/.test(message)) {
|
|
103
|
+
console.error('Podman reboot recovery is disabled. Run this as your normal user, then retry:');
|
|
104
|
+
console.error(' systemctl --user enable podman-restart.service');
|
|
105
|
+
} else {
|
|
106
|
+
console.error('Your host is not ready for installation: '+message);
|
|
107
|
+
console.error('Use the manual setup Help in your account to resolve this prerequisite, then retry.');
|
|
108
|
+
}
|
|
109
|
+
console.error('Your personal setup code has not been used.');
|
|
110
|
+
process.exit(1);
|
|
111
|
+
}
|
|
112
|
+
process.stdout.write(retained ? (record.containerEngine==='podman' ? 'retry-podman' : 'retry-docker') : 'fresh');
|
|
113
|
+
}
|
|
114
|
+
OURS_HOST_CHECK
|
|
115
|
+
)
|
|
116
|
+
setup_options=()
|
|
117
|
+
if [[ $installation_kind == fresh || $installation_kind == retry-docker ]]; then setup_options=(--mode docker --container-engine docker); fi
|
|
118
|
+
if [[ $installation_kind == retry-podman ]]; then setup_options=(--mode docker --container-engine podman); fi
|
|
119
|
+
if [[ $check_only == --check ]]; then
|
|
120
|
+
echo 'BOOTSTRAP_PREREQUISITES_PASS: Node22+, cloudflared, pinned Ours tools and validated fresh Docker or retained existing profile. Workspace installation not executed.'
|
|
121
|
+
exit 0
|
|
122
|
+
fi
|
|
123
|
+
# Redeem only after prerequisites are available. The capability and response are
|
|
124
|
+
# stdin/body-only, never process arguments, URLs or bootstrap output.
|
|
125
|
+
payload=$(printf '%s\n' "$payload" | node --input-type=module -e '
|
|
126
|
+
import {readFileSync} from "node:fs";
|
|
127
|
+
const stop=message=>{console.error("Ours setup: "+message);process.exit(1);};
|
|
128
|
+
try {
|
|
129
|
+
const input=readFileSync(0,"utf8").trim();
|
|
130
|
+
let value;
|
|
131
|
+
try { value=JSON.parse(Buffer.from(input,"base64url").toString()); } catch { stop("Invalid installation command. Copy a fresh command from your account."); }
|
|
132
|
+
if(value?.version!==2 || !["https://app.ours.network","https://app.ours-tunnel.com"].includes(value.appOrigin) || !/^[A-Za-z0-9_-]{43}$/.test(value.code) || !Number.isSafeInteger(value.expiresAt))stop("Invalid installation command. Copy a fresh command from your account.");
|
|
133
|
+
if(value.expiresAt<=Date.now())stop("This installation command has expired. Open this workspace in your account and copy a fresh command. Your existing installation is preserved.");
|
|
134
|
+
const response=await fetch(value.appOrigin+"/account-api/workspace-install-redeem",{method:"POST",redirect:"error",headers:{"Content-Type":"application/json","Origin":value.appOrigin},body:JSON.stringify({code:value.code}),signal:AbortSignal.timeout(30000)});
|
|
135
|
+
if(response.status===410)stop("This installation command has expired or was already used. Open this workspace in your account and copy a fresh command. Your existing installation is preserved.");
|
|
136
|
+
if(response.status===429)stop("Too many setup attempts. Wait a minute, then retry. Your existing installation is preserved.");
|
|
137
|
+
if(!response.ok)stop("The account service could not prepare your installation. Please try again shortly. Your existing installation is preserved.");
|
|
138
|
+
let result;
|
|
139
|
+
try { result=await response.json(); } catch { stop("The account service returned an invalid response. Please try again shortly."); }
|
|
140
|
+
if(typeof result?.payload!=="string" || !/^[A-Za-z0-9_-]{1,32768}$/.test(result.payload))stop("The account service returned an invalid response. Please try again shortly.");
|
|
141
|
+
process.stdout.write(result.payload);
|
|
142
|
+
} catch {
|
|
143
|
+
stop("Could not reach the account service. Check your internet connection and retry. Your existing installation is preserved.");
|
|
144
|
+
}
|
|
145
|
+
')
|
|
146
|
+
echo 'Installing or connecting Ours to your workspace…'
|
|
147
|
+
printf '%s\n' "$payload" | ours-install --setup-workspace - --fleet-settings "$fleet_settings" ${setup_options[@]+"${setup_options[@]}"}
|
|
148
|
+
unset payload
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Second step only: no installation, role selection or broad provider credentials.
|
|
3
|
+
set -euo pipefail
|
|
4
|
+
umask 077
|
|
5
|
+
set +x
|
|
6
|
+
IFS= read -r payload
|
|
7
|
+
[[ ${#payload} -le 32768 && $payload =~ ^[A-Za-z0-9_-]+$ ]] || { echo 'Invalid tunnel setup payload' >&2; exit 1; }
|
|
8
|
+
for binary in node ours-fleet cloudflared; do
|
|
9
|
+
command -v "$binary" >/dev/null || { echo "Missing tunnel setup prerequisite: $binary" >&2; exit 1; }
|
|
10
|
+
done
|
|
11
|
+
node -e 'if(Number(process.versions.node.split(".")[0])<22){console.error("Node.js 22+ is required");process.exit(1)}'
|
|
12
|
+
ours-fleet setup-tunnel --help >/dev/null
|
|
13
|
+
cloudflared --version >/dev/null
|
|
14
|
+
payload=$(printf '%s\n' "$payload" | node --input-type=module -e '
|
|
15
|
+
import {readFileSync} from "node:fs";
|
|
16
|
+
const stop=message=>{console.error("Ours setup: "+message);process.exit(1);};
|
|
17
|
+
try {
|
|
18
|
+
const input=readFileSync(0,"utf8").trim();
|
|
19
|
+
let value;
|
|
20
|
+
try { value=JSON.parse(Buffer.from(input,"base64url").toString()); } catch { stop("Invalid installation command. Copy a fresh command from your account."); }
|
|
21
|
+
if(value?.version!==2 || !["https://app.ours.network","https://app.ours-tunnel.com"].includes(value.appOrigin) || !/^[A-Za-z0-9_-]{43}$/.test(value.code) || !Number.isSafeInteger(value.expiresAt))stop("Invalid installation command. Copy a fresh command from your account.");
|
|
22
|
+
if(value.expiresAt<=Date.now())stop("This installation command has expired. Open this workspace in your account and copy a fresh command. Your existing installation is preserved.");
|
|
23
|
+
const response=await fetch(value.appOrigin+"/account-api/workspace-install-redeem",{method:"POST",redirect:"error",headers:{"Content-Type":"application/json","Origin":value.appOrigin},body:JSON.stringify({code:value.code}),signal:AbortSignal.timeout(30000)});
|
|
24
|
+
if(response.status===410)stop("This installation command has expired or was already used. Open this workspace in your account and copy a fresh command. Your existing installation is preserved.");
|
|
25
|
+
if(response.status===429)stop("Too many setup attempts. Wait a minute, then retry. Your existing installation is preserved.");
|
|
26
|
+
if(!response.ok)stop("The account service could not prepare your installation. Please try again shortly. Your existing installation is preserved.");
|
|
27
|
+
let result;
|
|
28
|
+
try { result=await response.json(); } catch { stop("The account service returned an invalid response. Please try again shortly."); }
|
|
29
|
+
if(typeof result?.payload!=="string" || !/^[A-Za-z0-9_-]{1,32768}$/.test(result.payload))stop("The account service returned an invalid response. Please try again shortly.");
|
|
30
|
+
process.stdout.write(result.payload);
|
|
31
|
+
} catch {
|
|
32
|
+
stop("Could not reach the account service. Check your internet connection and retry. Your existing installation is preserved.");
|
|
33
|
+
}
|
|
34
|
+
')
|
|
35
|
+
payload_dir=$(mktemp -d "${TMPDIR:-/tmp}/ours-tunnel-XXXXXXXX")
|
|
36
|
+
trap 'rm -f "$payload_dir/payload"; rmdir "$payload_dir"' EXIT
|
|
37
|
+
printf '%s\n' "$payload" > "$payload_dir/payload"
|
|
38
|
+
unset payload
|
|
39
|
+
ours-fleet setup-tunnel --file "$payload_dir/payload"
|
|
40
|
+
echo 'Next: run ours-fleet link-device and paste its private code into the App.'
|
|
@@ -22,4 +22,7 @@ export declare function enrollWorkspace(payload: WorkspacePayload, configuration
|
|
|
22
22
|
}): Promise<{
|
|
23
23
|
origin: string;
|
|
24
24
|
hostWorkspaceId: string;
|
|
25
|
+
rootCid: any;
|
|
25
26
|
}>;
|
|
27
|
+
/** Only the existing signed-root receipt authorizes the scoped tunnel target. */
|
|
28
|
+
export declare function configureWorkspacePort(payload: WorkspacePayload, hostWorkspaceId: string, rootCid: string, port: number): Promise<void>;
|
|
@@ -108,5 +108,22 @@ export async function enrollWorkspace(payload, configuration = defaultConfigPath
|
|
|
108
108
|
replaceFileAtomically(join(dir, 'tunnel.json'), JSON.stringify({ origin, tokenFile: join(dir, 'connector') }) + '\n', 0o600);
|
|
109
109
|
replaceFileAtomically(previousFile, JSON.stringify({ workspaceId: payload.challenge.workspaceId, hostWorkspaceId, appOrigin, serverCid: payload.serverCid.toUpperCase() }) + '\n', 0o600);
|
|
110
110
|
loadConfig(configuration);
|
|
111
|
-
return { origin, hostWorkspaceId };
|
|
111
|
+
return { origin, hostWorkspaceId, rootCid: result.rootCid };
|
|
112
|
+
}
|
|
113
|
+
/** Only the existing signed-root receipt authorizes the scoped tunnel target. */
|
|
114
|
+
export async function configureWorkspacePort(payload, hostWorkspaceId, rootCid, port) {
|
|
115
|
+
const deadline = Date.now() + 15000;
|
|
116
|
+
while (true) {
|
|
117
|
+
const response = await fetch(payload.appOrigin + '/account-api/workspace-tunnel-configure', { method: 'POST', headers: { Origin: payload.appOrigin, 'Content-Type': 'application/json' }, credentials: 'omit', redirect: 'error', signal: AbortSignal.timeout(15000), body: JSON.stringify({ ...payload.challenge, hostWorkspaceId, rootCid, port }) });
|
|
118
|
+
if (!response.ok) {
|
|
119
|
+
await response.body?.cancel();
|
|
120
|
+
throw Error('Workspace tunnel target configuration failed (HTTP ' + response.status + ')');
|
|
121
|
+
}
|
|
122
|
+
const receipt = await response.json();
|
|
123
|
+
if (receipt.configured === true)
|
|
124
|
+
return;
|
|
125
|
+
if (Date.now() >= deadline)
|
|
126
|
+
throw Error('Signed workspace binding is not confirmed; tunnel target was not changed');
|
|
127
|
+
await new Promise(resolve => setTimeout(resolve, 500));
|
|
128
|
+
}
|
|
112
129
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ours.network/fleet",
|
|
3
|
-
"version": "1.2.0-nightly.
|
|
3
|
+
"version": "1.2.0-nightly.32",
|
|
4
4
|
"description": "Harness-agnostic fleet of persistent, identity-bound AI agents. Declarative fleet.yaml, managed native/ACP sessions, supervision, and ours.network messaging.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "FSL-1.1-Apache-2.0",
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
},
|
|
28
28
|
"scripts": {
|
|
29
29
|
"clean": "node -e \"require('node:fs').rmSync('dist',{recursive:true,force:true})\"",
|
|
30
|
-
"build": "npm run clean && tsc -p tsconfig.json && node scripts/build-info.mjs",
|
|
30
|
+
"build": "npm run clean && tsc -p tsconfig.json && node scripts/copy-web.mjs && node scripts/build-info.mjs",
|
|
31
31
|
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
32
32
|
"lint": "npm run typecheck",
|
|
33
33
|
"test": "vitest run",
|