setsuna-microvm 0.5.1 → 0.5.3
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/LICENSE +32 -202
- package/README.md +2 -1
- package/dist/cli.js +110 -37
- package/package.json +3 -3
package/LICENSE
CHANGED
|
@@ -1,202 +1,32 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
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
|
-
not limited to compiled object code, generated documentation,
|
|
34
|
-
and conversions to other media types.
|
|
35
|
-
|
|
36
|
-
"Work" shall mean the work of authorship, whether in Source or
|
|
37
|
-
Object form, made available under the License, as indicated by a
|
|
38
|
-
copyright notice that is included in or attached to the work
|
|
39
|
-
(an example is provided in the Appendix below).
|
|
40
|
-
|
|
41
|
-
"Derivative Works" shall mean any work, whether in Source or Object
|
|
42
|
-
form, that is based on (or derived from) the Work and for which the
|
|
43
|
-
editorial revisions, annotations, elaborations, or other modifications
|
|
44
|
-
represent, as a whole, an original work of authorship. For the purposes
|
|
45
|
-
of this License, Derivative Works shall not include works that remain
|
|
46
|
-
separable from, or merely link (or bind by name) to the interfaces of,
|
|
47
|
-
the Work and Derivative Works thereof.
|
|
48
|
-
|
|
49
|
-
"Contribution" shall mean any work of authorship, including
|
|
50
|
-
the original version of the Work and any modifications or additions
|
|
51
|
-
to that Work or Derivative Works thereof, that is intentionally
|
|
52
|
-
submitted to Licensor for inclusion in the Work by the copyright owner
|
|
53
|
-
or by an individual or Legal Entity authorized to submit on behalf of
|
|
54
|
-
the copyright owner. For the purposes of this definition, "submitted"
|
|
55
|
-
means any form of electronic, verbal, or written communication sent
|
|
56
|
-
to the Licensor or its representatives, including but not limited to
|
|
57
|
-
communication on electronic mailing lists, source code control systems,
|
|
58
|
-
and issue tracking systems that are managed by, or on behalf of, the
|
|
59
|
-
Licensor for the purpose of discussing and improving the Work, but
|
|
60
|
-
excluding communication that is conspicuously marked or otherwise
|
|
61
|
-
designated in writing by the copyright owner as "Not a Contribution."
|
|
62
|
-
|
|
63
|
-
"Contributor" shall mean Licensor and any individual or Legal Entity
|
|
64
|
-
on behalf of whom a Contribution has been received by Licensor and
|
|
65
|
-
subsequently incorporated within the Work.
|
|
66
|
-
|
|
67
|
-
2. Grant of Copyright License. Subject to the terms and conditions of
|
|
68
|
-
this License, each Contributor hereby grants to You a perpetual,
|
|
69
|
-
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
70
|
-
copyright license to reproduce, prepare Derivative Works of,
|
|
71
|
-
publicly display, publicly perform, sublicense, and distribute the
|
|
72
|
-
Work and such Derivative Works in Source or Object form.
|
|
73
|
-
|
|
74
|
-
3. Grant of Patent License. Subject to the terms and conditions of
|
|
75
|
-
this License, each Contributor hereby grants to You a perpetual,
|
|
76
|
-
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
77
|
-
(except as stated in this section) patent license to make, have made,
|
|
78
|
-
use, offer to sell, sell, import, and otherwise transfer the Work,
|
|
79
|
-
where such license applies only to those patent claims licensable
|
|
80
|
-
by such Contributor that are necessarily infringed by their
|
|
81
|
-
Contribution(s) alone or by combination of their Contribution(s)
|
|
82
|
-
with the Work to which such Contribution(s) was submitted. If You
|
|
83
|
-
institute patent litigation against any entity (including a
|
|
84
|
-
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
|
85
|
-
or a Contribution incorporated within the Work constitutes direct
|
|
86
|
-
or contributory patent infringement, then any patent licenses
|
|
87
|
-
granted to You under this License for that Work shall terminate
|
|
88
|
-
as of the date such litigation is filed.
|
|
89
|
-
|
|
90
|
-
4. Redistribution. You may reproduce and distribute copies of the
|
|
91
|
-
Work or Derivative Works thereof in any medium, with or without
|
|
92
|
-
modifications, and in Source or Object form, provided that You
|
|
93
|
-
meet the following conditions:
|
|
94
|
-
|
|
95
|
-
(a) You must give any other recipients of the Work or
|
|
96
|
-
Derivative Works a copy of this License; and
|
|
97
|
-
|
|
98
|
-
(b) You must cause any modified files to carry prominent notices
|
|
99
|
-
stating that You changed the files; and
|
|
100
|
-
|
|
101
|
-
(c) You must retain, in the Source form of any Derivative Works
|
|
102
|
-
that You distribute, all copyright, patent, trademark, and
|
|
103
|
-
attribution notices from the Source form of the Work,
|
|
104
|
-
excluding those notices that do not pertain to any part of
|
|
105
|
-
the Derivative Works; and
|
|
106
|
-
|
|
107
|
-
(d) If the Work includes a "NOTICE" text file as part of its
|
|
108
|
-
distribution, then any Derivative Works that You distribute must
|
|
109
|
-
include a readable copy of the attribution notices contained
|
|
110
|
-
within such NOTICE file, excluding those notices that do not
|
|
111
|
-
pertain to any part of the Derivative Works, in at least one
|
|
112
|
-
of the following places: within a NOTICE text file distributed
|
|
113
|
-
as part of the Derivative Works; within the Source form or
|
|
114
|
-
documentation, if provided along with the Derivative Works; or,
|
|
115
|
-
within a display generated by the Derivative Works, if and
|
|
116
|
-
wherever such third-party notices normally appear. The contents
|
|
117
|
-
of the NOTICE file are for informational purposes only and
|
|
118
|
-
do not modify the License. You may add Your own attribution
|
|
119
|
-
notices within Derivative Works that You distribute, alongside
|
|
120
|
-
or as an addendum to the NOTICE text from the Work, provided
|
|
121
|
-
that such additional attribution notices cannot be construed
|
|
122
|
-
as modifying the License.
|
|
123
|
-
|
|
124
|
-
You may add Your own copyright statement to Your modifications and
|
|
125
|
-
may provide additional or different license terms and conditions
|
|
126
|
-
for use, reproduction, or distribution of Your modifications, or
|
|
127
|
-
for any such Derivative Works as a whole, provided Your use,
|
|
128
|
-
reproduction, and distribution of the Work otherwise complies with
|
|
129
|
-
the conditions stated in this License.
|
|
130
|
-
|
|
131
|
-
5. Submission of Contributions. Unless You explicitly state otherwise,
|
|
132
|
-
any Contribution intentionally submitted for inclusion in the Work
|
|
133
|
-
by You to the Licensor shall be under the terms and conditions of
|
|
134
|
-
this License, without any additional terms or conditions.
|
|
135
|
-
Notwithstanding the above, nothing herein shall supersede or modify
|
|
136
|
-
the terms of any separate license agreement you may have executed
|
|
137
|
-
with Licensor regarding such Contributions.
|
|
138
|
-
|
|
139
|
-
6. Trademarks. This License does not grant permission to use the trade
|
|
140
|
-
names, trademarks, service marks, or product names of the Licensor,
|
|
141
|
-
except as required for reasonable and customary use in describing the
|
|
142
|
-
origin of the Work and reproducing the content of the NOTICE file.
|
|
143
|
-
|
|
144
|
-
7. Disclaimer of Warranty. Unless required by applicable law or
|
|
145
|
-
agreed to in writing, Licensor provides the Work (and each
|
|
146
|
-
Contributor provides its Contributions) on an "AS IS" BASIS,
|
|
147
|
-
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
148
|
-
implied, including, without limitation, any warranties or conditions
|
|
149
|
-
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
|
150
|
-
PARTICULAR PURPOSE. You are solely responsible for determining the
|
|
151
|
-
appropriateness of using or redistributing the Work and assume any
|
|
152
|
-
risks associated with Your exercise of permissions under this License.
|
|
153
|
-
|
|
154
|
-
8. Limitation of Liability. In no event and under no legal theory,
|
|
155
|
-
whether in tort (including negligence), contract, or otherwise,
|
|
156
|
-
unless required by applicable law (such as deliberate and grossly
|
|
157
|
-
negligent acts) or agreed to in writing, shall any Contributor be
|
|
158
|
-
liable to You for damages, including any direct, indirect, special,
|
|
159
|
-
incidental, or consequential damages of any character arising as a
|
|
160
|
-
result of this License or out of the use or inability to use the
|
|
161
|
-
Work (including but not limited to damages for loss of goodwill,
|
|
162
|
-
work stoppage, computer failure or malfunction, or any and all
|
|
163
|
-
other commercial damages or losses), even if such Contributor
|
|
164
|
-
has been advised of the possibility of such damages.
|
|
165
|
-
|
|
166
|
-
9. Accepting Warranty or Additional Liability. While redistributing
|
|
167
|
-
the Work or Derivative Works thereof, You may choose to offer,
|
|
168
|
-
and charge a fee for, acceptance of support, warranty, indemnity,
|
|
169
|
-
or other liability obligations and/or rights consistent with this
|
|
170
|
-
License. However, in accepting such obligations, You may act only
|
|
171
|
-
on Your own behalf and on Your sole responsibility, not on behalf
|
|
172
|
-
of any other Contributor, and only if You agree to indemnify,
|
|
173
|
-
defend, and hold each Contributor harmless for any liability
|
|
174
|
-
incurred by, or claims asserted against, such Contributor by reason
|
|
175
|
-
of your accepting any such warranty or additional liability.
|
|
176
|
-
|
|
177
|
-
END OF TERMS AND CONDITIONS
|
|
178
|
-
|
|
179
|
-
APPENDIX: How to apply the Apache License to your work.
|
|
180
|
-
|
|
181
|
-
To apply the Apache License to your work, attach the following
|
|
182
|
-
boilerplate notice, with the fields enclosed by brackets "[]"
|
|
183
|
-
replaced with your own identifying information. (Don't include
|
|
184
|
-
the brackets!) The text should be enclosed in the appropriate
|
|
185
|
-
comment syntax for the file format. We also recommend that a
|
|
186
|
-
file or class name and description of purpose be included on the
|
|
187
|
-
same "printed page" as the copyright notice for easier
|
|
188
|
-
identification within third-party archives.
|
|
189
|
-
|
|
190
|
-
Copyright [yyyy] [name of copyright owner]
|
|
191
|
-
|
|
192
|
-
Licensed under the Apache License, Version 2.0 (the "License");
|
|
193
|
-
you may not use this file except in compliance with the License.
|
|
194
|
-
You may obtain a copy of the License at
|
|
195
|
-
|
|
196
|
-
http://www.apache.org/licenses/LICENSE-2.0
|
|
197
|
-
|
|
198
|
-
Unless required by applicable law or agreed to in writing, software
|
|
199
|
-
distributed under the License is distributed on an "AS IS" BASIS,
|
|
200
|
-
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
201
|
-
See the License for the specific language governing permissions and
|
|
202
|
-
limitations under the License.
|
|
1
|
+
SemSwitch Setsuna Research Preview Client License
|
|
2
|
+
|
|
3
|
+
Copyright © 2026 SemSwitch, Inc. All rights reserved.
|
|
4
|
+
|
|
5
|
+
The Setsuna client distributed in this package is proprietary software owned by SemSwitch, Inc.
|
|
6
|
+
("SemSwitch"). It is provided for authorized use with the Setsuna Research Preview.
|
|
7
|
+
|
|
8
|
+
1. Grant. Subject to the SemSwitch Terms of Service (https://semswitch.com/terms) and any
|
|
9
|
+
applicable Order or evaluation agreement, an authorized user receives a limited, non-exclusive
|
|
10
|
+
right to install and use the Setsuna client solely to access or evaluate the Setsuna service
|
|
11
|
+
that the user is authorized to use.
|
|
12
|
+
|
|
13
|
+
2. Ownership. The Setsuna client is licensed, not sold. SemSwitch retains all ownership,
|
|
14
|
+
copyright, and other intellectual property rights in the Setsuna client. This license transfers
|
|
15
|
+
no ownership or other intellectual property rights.
|
|
16
|
+
|
|
17
|
+
3. Restrictions. Except where expressly permitted by an applicable agreement with SemSwitch or by
|
|
18
|
+
non-waivable law, no right is granted to redistribute, sublicense, sell, rent, publish, modify,
|
|
19
|
+
create derivative works from, reverse engineer, decompile, or disassemble the Setsuna client.
|
|
20
|
+
|
|
21
|
+
4. Third-party software. The Setsuna client uses third-party software and components that are not
|
|
22
|
+
owned by SemSwitch. They remain governed by their respective licenses and notices, which this
|
|
23
|
+
license does not modify or replace.
|
|
24
|
+
|
|
25
|
+
5. Term. The right to use the Setsuna client ends when the applicable Setsuna authorization ends.
|
|
26
|
+
|
|
27
|
+
6. Agreements. If an applicable signed Order or separately negotiated agreement with SemSwitch
|
|
28
|
+
expressly conflicts with this license, that Order or agreement controls.
|
|
29
|
+
|
|
30
|
+
7. Warranties, liability, and service terms. Warranties, disclaimers, limitations of liability,
|
|
31
|
+
and the terms of the Setsuna service are governed by the applicable agreement and the SemSwitch
|
|
32
|
+
Terms of Service rather than by this license.
|
package/README.md
CHANGED
|
@@ -46,4 +46,5 @@ system's native secure credential storage, with no plaintext fallback.
|
|
|
46
46
|
This package is distributed as a Research Preview. Features, commands, and service behavior may
|
|
47
47
|
evolve before the stable Setsuna release.
|
|
48
48
|
|
|
49
|
-
Copyright © SemSwitch, Inc.
|
|
49
|
+
Copyright © 2026 SemSwitch, Inc. All rights reserved. Use of this package is subject to the
|
|
50
|
+
included license and the [SemSwitch Terms of Service](https://semswitch.com/terms).
|
package/dist/cli.js
CHANGED
|
@@ -10,6 +10,9 @@ var __export = (target, all) => {
|
|
|
10
10
|
};
|
|
11
11
|
|
|
12
12
|
// ../setsuna/src/tui/customer/prompt.ts
|
|
13
|
+
function readText(text, now) {
|
|
14
|
+
return typeof text === "function" ? text(now) : text;
|
|
15
|
+
}
|
|
13
16
|
var TUI_CANCEL;
|
|
14
17
|
var init_prompt = __esm({
|
|
15
18
|
"../setsuna/src/tui/customer/prompt.ts"() {
|
|
@@ -76,14 +79,13 @@ function adaptPrompts(clack, guide) {
|
|
|
76
79
|
const { confirm, isCancel, select, text } = clack;
|
|
77
80
|
return {
|
|
78
81
|
async select(options, io) {
|
|
79
|
-
const
|
|
80
|
-
|
|
81
|
-
options
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
}
|
|
86
|
-
return isCancel(result) ? TUI_CANCEL : result;
|
|
82
|
+
const redraw = hasTimedText(options) ? setInterval(() => io.output.emit("resize"), 1e3) : void 0;
|
|
83
|
+
try {
|
|
84
|
+
const result = await select(selectOptions(options, guide(options), io));
|
|
85
|
+
return isCancel(result) ? TUI_CANCEL : result;
|
|
86
|
+
} finally {
|
|
87
|
+
if (redraw !== void 0) clearInterval(redraw);
|
|
88
|
+
}
|
|
87
89
|
},
|
|
88
90
|
async text(options, io) {
|
|
89
91
|
const result = await text({
|
|
@@ -106,6 +108,28 @@ function adaptPrompts(clack, guide) {
|
|
|
106
108
|
}
|
|
107
109
|
};
|
|
108
110
|
}
|
|
111
|
+
function selectOptions(options, guide, io) {
|
|
112
|
+
return {
|
|
113
|
+
get message() {
|
|
114
|
+
return readText(options.message, Date.now());
|
|
115
|
+
},
|
|
116
|
+
options: options.options.map((option) => ({
|
|
117
|
+
value: option.value,
|
|
118
|
+
label: option.label,
|
|
119
|
+
get hint() {
|
|
120
|
+
return option.hint === void 0 ? void 0 : readText(option.hint, Date.now());
|
|
121
|
+
}
|
|
122
|
+
})),
|
|
123
|
+
initialValue: options.initialValue,
|
|
124
|
+
signal: options.signal,
|
|
125
|
+
...guide,
|
|
126
|
+
input: io.input,
|
|
127
|
+
output: io.output
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
function hasTimedText(options) {
|
|
131
|
+
return typeof options.message === "function" || options.options.some(({ hint }) => typeof hint === "function");
|
|
132
|
+
}
|
|
109
133
|
function adaptSpinner(clack, io, options, guide) {
|
|
110
134
|
const completion = trackInterruption(clack, io, options.onCancel, guide);
|
|
111
135
|
const spinner = clack.spinner({
|
|
@@ -1248,8 +1272,38 @@ function isRecord(value) {
|
|
|
1248
1272
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1249
1273
|
}
|
|
1250
1274
|
|
|
1275
|
+
// ../setsuna/src/client-affinity.ts
|
|
1276
|
+
var FrontDoorAffinity = class {
|
|
1277
|
+
#origin;
|
|
1278
|
+
#cookies = /* @__PURE__ */ new Map();
|
|
1279
|
+
constructor(serviceUrl) {
|
|
1280
|
+
this.#origin = serviceUrl.origin;
|
|
1281
|
+
}
|
|
1282
|
+
headersFor(url, headers) {
|
|
1283
|
+
if (url.origin !== this.#origin || this.#cookies.size === 0) return headers;
|
|
1284
|
+
const result = new Headers(headers);
|
|
1285
|
+
result.set("cookie", [...this.#cookies].map(([name, value]) => `${name}=${value}`).join("; "));
|
|
1286
|
+
return result;
|
|
1287
|
+
}
|
|
1288
|
+
capture(url, response) {
|
|
1289
|
+
if (url.origin !== this.#origin) return;
|
|
1290
|
+
if (response.url !== "" && new URL(response.url).origin !== this.#origin) return;
|
|
1291
|
+
for (const header of response.headers.getSetCookie()) {
|
|
1292
|
+
const pair = header.split(";", 1)[0]?.trim() ?? "";
|
|
1293
|
+
const match = /^(ASLBSA|ASLBSACORS)=([\x21\x23-\x2B\x2D-\x3A\x3C-\x5B\x5D-\x7E]*)$/u.exec(
|
|
1294
|
+
pair
|
|
1295
|
+
);
|
|
1296
|
+
if (match === null) continue;
|
|
1297
|
+
const [, name, value] = match;
|
|
1298
|
+
if (name === void 0 || value === void 0) continue;
|
|
1299
|
+
if (value === "") this.#cookies.delete(name);
|
|
1300
|
+
else this.#cookies.set(name, value);
|
|
1301
|
+
}
|
|
1302
|
+
}
|
|
1303
|
+
};
|
|
1304
|
+
|
|
1251
1305
|
// ../setsuna/src/client-options.ts
|
|
1252
|
-
var PREVIEW_SERVICE_URL = "https://api.setsuna.semswitch.com/
|
|
1306
|
+
var PREVIEW_SERVICE_URL = "https://api.setsuna.semswitch.com/";
|
|
1253
1307
|
function normalizeServiceUrl(value) {
|
|
1254
1308
|
let url;
|
|
1255
1309
|
try {
|
|
@@ -1359,7 +1413,7 @@ function isLoopbackHostname(hostname) {
|
|
|
1359
1413
|
}
|
|
1360
1414
|
|
|
1361
1415
|
// ../setsuna/src/client-request.ts
|
|
1362
|
-
async function requestJson(serviceUrl, defaultTimeoutMs, getAccessToken, path3, options) {
|
|
1416
|
+
async function requestJson(serviceUrl, defaultTimeoutMs, getAccessToken, path3, options, affinity) {
|
|
1363
1417
|
const requestTimeoutMs = options.requestTimeoutMs === void 0 ? defaultTimeoutMs : positiveMilliseconds(options.requestTimeoutMs, "requestTimeoutMs");
|
|
1364
1418
|
const timeoutSignal = AbortSignal.timeout(requestTimeoutMs);
|
|
1365
1419
|
const signal = options.signal === void 0 ? timeoutSignal : AbortSignal.any([options.signal, timeoutSignal]);
|
|
@@ -1376,7 +1430,8 @@ async function requestJson(serviceUrl, defaultTimeoutMs, getAccessToken, path3,
|
|
|
1376
1430
|
requestTimeoutMs,
|
|
1377
1431
|
timeoutSignal,
|
|
1378
1432
|
signal,
|
|
1379
|
-
accessToken
|
|
1433
|
+
accessToken,
|
|
1434
|
+
affinity
|
|
1380
1435
|
);
|
|
1381
1436
|
const responseBody = response.status === 204 ? void 0 : await parseResponseJson(response);
|
|
1382
1437
|
if (!response.ok) throw brokerResponseError(response, responseBody);
|
|
@@ -1417,14 +1472,17 @@ function settleBeforeAbort(pending, signal) {
|
|
|
1417
1472
|
if (signal.aborted) onAbort();
|
|
1418
1473
|
});
|
|
1419
1474
|
}
|
|
1420
|
-
async function fetchService(url, options, requestTimeoutMs, timeoutSignal, signal, accessToken) {
|
|
1475
|
+
async function fetchService(url, options, requestTimeoutMs, timeoutSignal, signal, accessToken, affinity) {
|
|
1421
1476
|
try {
|
|
1422
|
-
|
|
1477
|
+
const headers = requestHeaders(options.body, accessToken);
|
|
1478
|
+
const response = await fetch(url, {
|
|
1423
1479
|
method: options.method,
|
|
1424
|
-
headers:
|
|
1480
|
+
headers: affinity?.headersFor(url, headers) ?? headers,
|
|
1425
1481
|
body: options.body === void 0 ? void 0 : JSON.stringify(options.body),
|
|
1426
1482
|
signal
|
|
1427
1483
|
});
|
|
1484
|
+
affinity?.capture(url, response);
|
|
1485
|
+
return response;
|
|
1428
1486
|
} catch (error) {
|
|
1429
1487
|
throwCancellationFailure(error, requestTimeoutMs, timeoutSignal, options.signal);
|
|
1430
1488
|
throw new SetsunaError("The local Setsuna service could not be reached.", {
|
|
@@ -1559,13 +1617,14 @@ function parseProcessList(value) {
|
|
|
1559
1617
|
if (!Array.isArray(value)) throw invalidResponse2("process list");
|
|
1560
1618
|
return value.map(parseProcessInfo);
|
|
1561
1619
|
}
|
|
1562
|
-
function attachProcessStream(serviceUrl, path3, options, getAccessToken) {
|
|
1620
|
+
function attachProcessStream(serviceUrl, path3, options, getAccessToken, affinity) {
|
|
1563
1621
|
return {
|
|
1564
1622
|
async *[Symbol.asyncIterator]() {
|
|
1565
1623
|
const response = await fetchProcessStream(
|
|
1566
1624
|
new URL(path3, serviceUrl),
|
|
1567
1625
|
options.signal,
|
|
1568
|
-
getAccessToken
|
|
1626
|
+
getAccessToken,
|
|
1627
|
+
affinity
|
|
1569
1628
|
);
|
|
1570
1629
|
if (response.body === null) throw invalidResponse2("process stream");
|
|
1571
1630
|
yield* decodeFrames(response.body, options.signal);
|
|
@@ -1586,15 +1645,17 @@ function processFrameToJson(frame) {
|
|
|
1586
1645
|
}
|
|
1587
1646
|
return frame;
|
|
1588
1647
|
}
|
|
1589
|
-
async function fetchProcessStream(url, signal, getAccessToken) {
|
|
1648
|
+
async function fetchProcessStream(url, signal, getAccessToken, affinity) {
|
|
1590
1649
|
const accessToken = await processAccessToken(getAccessToken, signal);
|
|
1591
1650
|
let response;
|
|
1592
1651
|
try {
|
|
1652
|
+
const headers = accessToken === void 0 ? void 0 : { authorization: `Bearer ${accessToken}` };
|
|
1593
1653
|
response = await fetch(url, {
|
|
1594
1654
|
method: "GET",
|
|
1595
1655
|
signal,
|
|
1596
|
-
...
|
|
1656
|
+
...headers === void 0 ? {} : { headers: affinity?.headersFor(url, headers) ?? headers }
|
|
1597
1657
|
});
|
|
1658
|
+
affinity?.capture(url, response);
|
|
1598
1659
|
} catch (error) {
|
|
1599
1660
|
throw requestError(error, signal);
|
|
1600
1661
|
}
|
|
@@ -1773,6 +1834,7 @@ var SetsunaClient = class {
|
|
|
1773
1834
|
#serviceUrl;
|
|
1774
1835
|
#requestTimeoutMs;
|
|
1775
1836
|
#getAccessToken;
|
|
1837
|
+
#affinity;
|
|
1776
1838
|
constructor(options = {}) {
|
|
1777
1839
|
if (options.serviceUrl !== void 0 && options.remote !== void 0) {
|
|
1778
1840
|
throw new TypeError("serviceUrl and remote are mutually exclusive.");
|
|
@@ -1786,6 +1848,7 @@ var SetsunaClient = class {
|
|
|
1786
1848
|
}
|
|
1787
1849
|
this.#serviceUrl = new URL(PREVIEW_SERVICE_URL);
|
|
1788
1850
|
this.#getAccessToken = options.remote.getAccessToken;
|
|
1851
|
+
this.#affinity = new FrontDoorAffinity(this.#serviceUrl);
|
|
1789
1852
|
}
|
|
1790
1853
|
this.#requestTimeoutMs = positiveMilliseconds(
|
|
1791
1854
|
options.requestTimeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS,
|
|
@@ -1876,7 +1939,8 @@ var SetsunaClient = class {
|
|
|
1876
1939
|
this.#serviceUrl,
|
|
1877
1940
|
`${processPath(sandboxId)}/${encodeURIComponent(nonEmptyString(processId, "processId"))}/attach${query}`,
|
|
1878
1941
|
options,
|
|
1879
|
-
this.#getAccessToken
|
|
1942
|
+
this.#getAccessToken,
|
|
1943
|
+
this.#affinity
|
|
1880
1944
|
);
|
|
1881
1945
|
}
|
|
1882
1946
|
async writeProcessStdin(sandboxId, processId, data) {
|
|
@@ -1958,7 +2022,8 @@ var SetsunaClient = class {
|
|
|
1958
2022
|
this.#requestTimeoutMs,
|
|
1959
2023
|
this.#getAccessToken,
|
|
1960
2024
|
path3,
|
|
1961
|
-
options
|
|
2025
|
+
options,
|
|
2026
|
+
this.#affinity
|
|
1962
2027
|
);
|
|
1963
2028
|
}
|
|
1964
2029
|
};
|
|
@@ -2081,14 +2146,19 @@ function enterRawMode(input) {
|
|
|
2081
2146
|
const wasPaused = input.isPaused();
|
|
2082
2147
|
input.setRawMode(true);
|
|
2083
2148
|
input.resume();
|
|
2084
|
-
let restored
|
|
2149
|
+
let restored;
|
|
2085
2150
|
return () => {
|
|
2086
|
-
|
|
2087
|
-
restored
|
|
2088
|
-
input.setRawMode?.(wasRaw);
|
|
2089
|
-
if (wasPaused) input.pause();
|
|
2151
|
+
restored ??= restoreInput(input, wasRaw, wasPaused);
|
|
2152
|
+
return restored;
|
|
2090
2153
|
};
|
|
2091
2154
|
}
|
|
2155
|
+
async function restoreInput(input, wasRaw, wasPaused) {
|
|
2156
|
+
if (wasPaused) {
|
|
2157
|
+
input.pause();
|
|
2158
|
+
await new Promise((resolve) => process.nextTick(resolve));
|
|
2159
|
+
}
|
|
2160
|
+
input.setRawMode?.(wasRaw);
|
|
2161
|
+
}
|
|
2092
2162
|
|
|
2093
2163
|
// ../setsuna/src/lease-keeper.ts
|
|
2094
2164
|
var MAX_TIMER_DELAY_MS = 2147483647;
|
|
@@ -2287,6 +2357,7 @@ function createAttachedSession(client, sandboxId, processId, io, terminal, contr
|
|
|
2287
2357
|
let cleaned = false;
|
|
2288
2358
|
let inputQueue = Promise.resolve();
|
|
2289
2359
|
let resizeQueue = Promise.resolve();
|
|
2360
|
+
let restored;
|
|
2290
2361
|
const restoreRawMode = terminal.enterRawMode();
|
|
2291
2362
|
const cleanup = () => {
|
|
2292
2363
|
if (cleaned) return;
|
|
@@ -2294,7 +2365,7 @@ function createAttachedSession(client, sandboxId, processId, io, terminal, contr
|
|
|
2294
2365
|
io.input.off("data", onInput);
|
|
2295
2366
|
terminal.offResize(onResize);
|
|
2296
2367
|
stopLeaseKeeper();
|
|
2297
|
-
restoreRawMode();
|
|
2368
|
+
restored = restoreRawMode();
|
|
2298
2369
|
};
|
|
2299
2370
|
const fail = (error) => {
|
|
2300
2371
|
if (failure === void 0) failure = error;
|
|
@@ -2339,8 +2410,10 @@ function createAttachedSession(client, sandboxId, processId, io, terminal, contr
|
|
|
2339
2410
|
get failure() {
|
|
2340
2411
|
return failure;
|
|
2341
2412
|
},
|
|
2413
|
+
// Everything the session started has finished, including handing the terminal back.
|
|
2342
2414
|
async settle() {
|
|
2343
2415
|
await Promise.allSettled([inputQueue, resizeQueue]);
|
|
2416
|
+
await restored;
|
|
2344
2417
|
}
|
|
2345
2418
|
};
|
|
2346
2419
|
}
|
|
@@ -2468,6 +2541,7 @@ var DEFAULT_SIGNAL_RUNTIME = {
|
|
|
2468
2541
|
|
|
2469
2542
|
// ../setsuna/src/tui/customer/format.ts
|
|
2470
2543
|
var STANDALONE_BOX = { withGuide: false, width: "auto" };
|
|
2544
|
+
var EXIT_MESSAGE = "Sayonara!";
|
|
2471
2545
|
function formatRunPhase(phase) {
|
|
2472
2546
|
switch (phase) {
|
|
2473
2547
|
case "starting-microvm":
|
|
@@ -2634,7 +2708,7 @@ async function ensureSignedIn(io, auth, promptUi, session = {}) {
|
|
|
2634
2708
|
return false;
|
|
2635
2709
|
}
|
|
2636
2710
|
if (choice === "exit") {
|
|
2637
|
-
promptUi.outro(
|
|
2711
|
+
promptUi.outro(EXIT_MESSAGE, io);
|
|
2638
2712
|
return false;
|
|
2639
2713
|
}
|
|
2640
2714
|
status = await signIn(io, auth, promptUi);
|
|
@@ -2779,7 +2853,7 @@ async function promptRunAgain(io, promptUi) {
|
|
|
2779
2853
|
);
|
|
2780
2854
|
if (next === TUI_CANCEL || next === "back") return "back-to-main";
|
|
2781
2855
|
if (next === "exit") {
|
|
2782
|
-
promptUi.outro(
|
|
2856
|
+
promptUi.outro(EXIT_MESSAGE, io);
|
|
2783
2857
|
return "exit-tui";
|
|
2784
2858
|
}
|
|
2785
2859
|
return "prompt-new-command";
|
|
@@ -2876,7 +2950,6 @@ async function activeMicrovmsMenu(io, actions, promptUi) {
|
|
|
2876
2950
|
}
|
|
2877
2951
|
}
|
|
2878
2952
|
async function selectSandbox(io, promptUi, sandboxes) {
|
|
2879
|
-
const now = Date.now();
|
|
2880
2953
|
const selected = await promptUi.select(
|
|
2881
2954
|
{
|
|
2882
2955
|
message: "Active microVMs",
|
|
@@ -2884,7 +2957,7 @@ async function selectSandbox(io, promptUi, sandboxes) {
|
|
|
2884
2957
|
...sandboxes.map((sandbox, index) => ({
|
|
2885
2958
|
value: `sandbox:${index}`,
|
|
2886
2959
|
label: sandbox.sandboxId,
|
|
2887
|
-
hint: formatExpiry(sandbox.expiresAt, now)
|
|
2960
|
+
hint: (now) => formatExpiry(sandbox.expiresAt, now)
|
|
2888
2961
|
})),
|
|
2889
2962
|
{ value: "back", label: "Back" }
|
|
2890
2963
|
]
|
|
@@ -2897,10 +2970,10 @@ async function selectSandbox(io, promptUi, sandboxes) {
|
|
|
2897
2970
|
async function manageSandbox(io, actions, promptUi, initial) {
|
|
2898
2971
|
let microvm = initial;
|
|
2899
2972
|
while (true) {
|
|
2900
|
-
const
|
|
2973
|
+
const { sandboxId, expiresAt } = microvm;
|
|
2901
2974
|
const choice = await promptUi.select(
|
|
2902
2975
|
{
|
|
2903
|
-
message: `Manage microVM ${
|
|
2976
|
+
message: (now) => `Manage microVM ${sandboxId} \xB7 ${formatExpiry(expiresAt, now)}`,
|
|
2904
2977
|
options: [
|
|
2905
2978
|
{ value: "open-terminal", label: "Open terminal" },
|
|
2906
2979
|
{ value: "reattach-terminal", label: "Reattach terminal" },
|
|
@@ -3049,10 +3122,10 @@ async function mainMenu(io, actions, promptUi, session) {
|
|
|
3049
3122
|
{
|
|
3050
3123
|
message: "What would you like to do?",
|
|
3051
3124
|
options: [
|
|
3052
|
-
{ value: "start", label: "
|
|
3053
|
-
{ value: "active", label: "Active microVMs", hint: "
|
|
3054
|
-
{ value: "run", label: "
|
|
3055
|
-
{ value: "account", label: "Account"
|
|
3125
|
+
{ value: "start", label: "New microVM", hint: "For interactive or ongoing work" },
|
|
3126
|
+
{ value: "active", label: "Active microVMs", hint: "Resume or manage your microVMs" },
|
|
3127
|
+
{ value: "run", label: "One-off run", hint: "Isolated single-run workload" },
|
|
3128
|
+
{ value: "account", label: "Account" },
|
|
3056
3129
|
{ value: "exit", label: "Exit" }
|
|
3057
3130
|
],
|
|
3058
3131
|
initialValue: "start",
|
|
@@ -3065,7 +3138,7 @@ async function mainMenu(io, actions, promptUi, session) {
|
|
|
3065
3138
|
return "exit";
|
|
3066
3139
|
}
|
|
3067
3140
|
if (choice === "exit") {
|
|
3068
|
-
promptUi.outro(
|
|
3141
|
+
promptUi.outro(EXIT_MESSAGE, io);
|
|
3069
3142
|
return "exit";
|
|
3070
3143
|
}
|
|
3071
3144
|
try {
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "setsuna-microvm",
|
|
3
|
-
"version": "0.5.
|
|
4
|
-
"description": "
|
|
5
|
-
"license": "
|
|
3
|
+
"version": "0.5.3",
|
|
4
|
+
"description": "Command-line interface for the Setsuna Research Preview.",
|
|
5
|
+
"license": "SEE LICENSE IN LICENSE",
|
|
6
6
|
"homepage": "https://semswitch.com/setsuna",
|
|
7
7
|
"keywords": [
|
|
8
8
|
"setsuna",
|