appduct 0.14.0 → 0.15.1
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/README.md +60 -287
- package/dist/artifact-inspect.d.ts +38 -39
- package/dist/bin.js +45 -3
- package/dist/cli/result-types.d.ts +27 -1
- package/dist/cli/routes/daemon/index.js +32 -1
- package/dist/cli/routes/daemon/run.js +963 -521
- package/dist/cli/routes/daemon/start.js +40 -1
- package/dist/cli/routes/daemon/status.js +41 -1
- package/dist/cli/routes/daemon/stop.js +40 -1
- package/dist/cli/routes/doctor.js +40 -2
- package/dist/cli/routes/events/index.js +32 -1
- package/dist/cli/routes/events/ls.js +40 -1
- package/dist/cli/routes/events/since.js +40 -1
- package/dist/cli/routes/events/tail.js +40 -1
- package/dist/cli/routes/init.js +207 -107
- package/dist/cli/routes/keygen.js +32 -1
- package/dist/cli/routes/mcp.js +135 -24
- package/dist/cli/routes/sessions/index.js +32 -1
- package/dist/cli/routes/sessions/link.js +141 -21
- package/dist/cli/routes/sessions/ls.js +40 -1
- package/dist/cli/routes/sessions/revoke.js +40 -1
- package/dist/cli/routes/tools/call.js +40 -1
- package/dist/cli/routes/tools/describe.js +40 -1
- package/dist/cli/routes/tools/index.js +32 -1
- package/dist/cli/routes/tools/ls.js +40 -1
- package/dist/client/attach-page.d.ts +39 -0
- package/dist/client/bootstrap.d.ts +17 -3
- package/dist/client/index.d.ts +2 -1
- package/dist/client/index.js +287 -112
- package/dist/commands/doctor.d.ts +3 -4
- package/dist/commands/init.d.ts +8 -2
- package/dist/commands/link.d.ts +10 -1
- package/dist/daemon/calls.d.ts +1 -1
- package/dist/daemon/config.d.ts +6 -0
- package/dist/daemon/daemon.d.ts +6 -1
- package/dist/daemon/links.d.ts +9 -5
- package/dist/daemon/listener.d.ts +28 -1
- package/dist/daemon/rpc-errors.d.ts +3 -0
- package/dist/daemon/sessions.d.ts +11 -7
- package/dist/daemon/tls.d.ts +0 -3
- package/dist/devtools-relay/attach-tab.d.ts +33 -0
- package/dist/devtools-relay/index.d.ts +8 -0
- package/dist/devtools-relay/memory-daemon-sockets.d.ts +20 -0
- package/dist/devtools-relay/memory-devtools-browser.d.ts +10 -0
- package/dist/devtools-relay/memory-page-channel.d.ts +16 -0
- package/dist/devtools-relay/node-daemon-socket.d.ts +3 -0
- package/dist/devtools-relay/node-devtools-browser.d.ts +3 -0
- package/dist/devtools-relay/ports.d.ts +48 -0
- package/dist/devtools-relay/relay.d.ts +16 -0
- package/dist/index.js +45 -3
- package/dist/link.d.ts +35 -1
- package/dist/mcp/connect-tool.d.ts +15 -2
- package/dist/native-scheme.d.ts +11 -7
- package/dist/scheme.d.ts +5 -1
- package/package.json +15 -5
|
@@ -24,6 +24,7 @@ var KNOWN_TOP_LEVEL_KEYS = /* @__PURE__ */ new Set([
|
|
|
24
24
|
"daemonLogMaxBytes",
|
|
25
25
|
"eventsLogMaxBytes",
|
|
26
26
|
"policy",
|
|
27
|
+
"webOrigins",
|
|
27
28
|
"advertisedIp",
|
|
28
29
|
"scheme",
|
|
29
30
|
"restartDaemonOnVersionMismatch"
|
|
@@ -84,6 +85,7 @@ var defaultConfig = (paths) => {
|
|
|
84
85
|
daemonLogMaxBytes: DEFAULT_DAEMON_LOG_MAX_BYTES,
|
|
85
86
|
eventsLogMaxBytes: 10 * 1024 * 1024,
|
|
86
87
|
restartDaemonOnVersionMismatch: false,
|
|
88
|
+
webOrigins: [],
|
|
87
89
|
policy: {
|
|
88
90
|
default: "allow",
|
|
89
91
|
destructive: "allow"
|
|
@@ -154,6 +156,12 @@ var loadConfig = async (paths, options = {}) => {
|
|
|
154
156
|
"restartDaemonOnVersionMismatch"
|
|
155
157
|
);
|
|
156
158
|
}
|
|
159
|
+
if (parsed.webOrigins !== void 0) {
|
|
160
|
+
if (!Array.isArray(parsed.webOrigins)) {
|
|
161
|
+
throw configError("webOrigins", "must be an array of origin strings.");
|
|
162
|
+
}
|
|
163
|
+
config.webOrigins = parsed.webOrigins.map((origin) => requireNonEmptyString(origin, "webOrigins"));
|
|
164
|
+
}
|
|
157
165
|
if (parsed.policy !== void 0) {
|
|
158
166
|
if (typeof parsed.policy !== "object" || parsed.policy === null || Array.isArray(parsed.policy)) {
|
|
159
167
|
throw configError("policy", "must be an object.");
|
|
@@ -923,7 +931,7 @@ var EXIT_CODE_BY_ERROR_TYPE = {
|
|
|
923
931
|
// EX_NOINPUT (66): "an input file did not exist or was not readable" — `doctor` throws this for a
|
|
924
932
|
// missing external tool or an unreadable/corrupt artifact, deliberately distinct from every other
|
|
925
933
|
// code here so a release pipeline can't mistake "we couldn't tell" for either a clean pass or an
|
|
926
|
-
// assertion failure
|
|
934
|
+
// assertion failure.
|
|
927
935
|
inspection_error: 66,
|
|
928
936
|
connection_error: 70,
|
|
929
937
|
session_error: 71,
|
|
@@ -1387,6 +1395,36 @@ var renderInvokeData = (colors, data, flags) => {
|
|
|
1387
1395
|
return [colors.green("Result"), formatScalar(data, flags)];
|
|
1388
1396
|
};
|
|
1389
1397
|
var renderLinkData = (colors, data, flags, qr) => {
|
|
1398
|
+
if ("attached" in data) {
|
|
1399
|
+
return [
|
|
1400
|
+
colors.green("Page Attached"),
|
|
1401
|
+
...renderFields(
|
|
1402
|
+
"Page",
|
|
1403
|
+
[
|
|
1404
|
+
["Session", data.sessionId],
|
|
1405
|
+
["Tab", data.targetId],
|
|
1406
|
+
["URL", data.url],
|
|
1407
|
+
["Expires", new Date(data.expiresAt * 1e3).toISOString()]
|
|
1408
|
+
],
|
|
1409
|
+
flags
|
|
1410
|
+
)
|
|
1411
|
+
];
|
|
1412
|
+
}
|
|
1413
|
+
if ("script" in data) {
|
|
1414
|
+
return [
|
|
1415
|
+
colors.green("Link Created"),
|
|
1416
|
+
...renderFields(
|
|
1417
|
+
"Link",
|
|
1418
|
+
[
|
|
1419
|
+
["Session", data.sessionId],
|
|
1420
|
+
["URL", data.url],
|
|
1421
|
+
["Script", data.script],
|
|
1422
|
+
["Expires", new Date(data.expiresAt * 1e3).toISOString()]
|
|
1423
|
+
],
|
|
1424
|
+
flags
|
|
1425
|
+
)
|
|
1426
|
+
];
|
|
1427
|
+
}
|
|
1390
1428
|
const lines = [
|
|
1391
1429
|
colors.green("Link Created"),
|
|
1392
1430
|
...renderFields(
|
|
@@ -1507,6 +1545,7 @@ var renderDaemonStatusData = (colors, data, flags) => {
|
|
|
1507
1545
|
["PID", data.daemon.pid],
|
|
1508
1546
|
["Started at", data.daemon.started_at],
|
|
1509
1547
|
["WSS port", data.daemon.wss_port],
|
|
1548
|
+
["Web port", data.daemon.web_port],
|
|
1510
1549
|
["Pinned keys", data.daemon.pinned_keys.length],
|
|
1511
1550
|
["Sessions", data.daemon.session_count]
|
|
1512
1551
|
],
|
|
@@ -44,6 +44,7 @@ var KNOWN_TOP_LEVEL_KEYS = /* @__PURE__ */ new Set([
|
|
|
44
44
|
"daemonLogMaxBytes",
|
|
45
45
|
"eventsLogMaxBytes",
|
|
46
46
|
"policy",
|
|
47
|
+
"webOrigins",
|
|
47
48
|
"advertisedIp",
|
|
48
49
|
"scheme",
|
|
49
50
|
"restartDaemonOnVersionMismatch"
|
|
@@ -104,6 +105,7 @@ var defaultConfig = (paths) => {
|
|
|
104
105
|
daemonLogMaxBytes: DEFAULT_DAEMON_LOG_MAX_BYTES,
|
|
105
106
|
eventsLogMaxBytes: 10 * 1024 * 1024,
|
|
106
107
|
restartDaemonOnVersionMismatch: false,
|
|
108
|
+
webOrigins: [],
|
|
107
109
|
policy: {
|
|
108
110
|
default: "allow",
|
|
109
111
|
destructive: "allow"
|
|
@@ -174,6 +176,12 @@ var loadConfig = async (paths, options = {}) => {
|
|
|
174
176
|
"restartDaemonOnVersionMismatch"
|
|
175
177
|
);
|
|
176
178
|
}
|
|
179
|
+
if (parsed.webOrigins !== void 0) {
|
|
180
|
+
if (!Array.isArray(parsed.webOrigins)) {
|
|
181
|
+
throw configError("webOrigins", "must be an array of origin strings.");
|
|
182
|
+
}
|
|
183
|
+
config.webOrigins = parsed.webOrigins.map((origin) => requireNonEmptyString(origin, "webOrigins"));
|
|
184
|
+
}
|
|
177
185
|
if (parsed.policy !== void 0) {
|
|
178
186
|
if (typeof parsed.policy !== "object" || parsed.policy === null || Array.isArray(parsed.policy)) {
|
|
179
187
|
throw configError("policy", "must be an object.");
|
|
@@ -1077,7 +1085,7 @@ var EXIT_CODE_BY_ERROR_TYPE = {
|
|
|
1077
1085
|
// EX_NOINPUT (66): "an input file did not exist or was not readable" — `doctor` throws this for a
|
|
1078
1086
|
// missing external tool or an unreadable/corrupt artifact, deliberately distinct from every other
|
|
1079
1087
|
// code here so a release pipeline can't mistake "we couldn't tell" for either a clean pass or an
|
|
1080
|
-
// assertion failure
|
|
1088
|
+
// assertion failure.
|
|
1081
1089
|
inspection_error: 66,
|
|
1082
1090
|
connection_error: 70,
|
|
1083
1091
|
session_error: 71,
|
|
@@ -1575,6 +1583,36 @@ var renderInvokeData = (colors, data, flags) => {
|
|
|
1575
1583
|
return [colors.green("Result"), formatScalar(data, flags)];
|
|
1576
1584
|
};
|
|
1577
1585
|
var renderLinkData = (colors, data, flags, qr) => {
|
|
1586
|
+
if ("attached" in data) {
|
|
1587
|
+
return [
|
|
1588
|
+
colors.green("Page Attached"),
|
|
1589
|
+
...renderFields(
|
|
1590
|
+
"Page",
|
|
1591
|
+
[
|
|
1592
|
+
["Session", data.sessionId],
|
|
1593
|
+
["Tab", data.targetId],
|
|
1594
|
+
["URL", data.url],
|
|
1595
|
+
["Expires", new Date(data.expiresAt * 1e3).toISOString()]
|
|
1596
|
+
],
|
|
1597
|
+
flags
|
|
1598
|
+
)
|
|
1599
|
+
];
|
|
1600
|
+
}
|
|
1601
|
+
if ("script" in data) {
|
|
1602
|
+
return [
|
|
1603
|
+
colors.green("Link Created"),
|
|
1604
|
+
...renderFields(
|
|
1605
|
+
"Link",
|
|
1606
|
+
[
|
|
1607
|
+
["Session", data.sessionId],
|
|
1608
|
+
["URL", data.url],
|
|
1609
|
+
["Script", data.script],
|
|
1610
|
+
["Expires", new Date(data.expiresAt * 1e3).toISOString()]
|
|
1611
|
+
],
|
|
1612
|
+
flags
|
|
1613
|
+
)
|
|
1614
|
+
];
|
|
1615
|
+
}
|
|
1578
1616
|
const lines = [
|
|
1579
1617
|
colors.green("Link Created"),
|
|
1580
1618
|
...renderFields(
|
|
@@ -1695,6 +1733,7 @@ var renderDaemonStatusData = (colors, data, flags) => {
|
|
|
1695
1733
|
["PID", data.daemon.pid],
|
|
1696
1734
|
["Started at", data.daemon.started_at],
|
|
1697
1735
|
["WSS port", data.daemon.wss_port],
|
|
1736
|
+
["Web port", data.daemon.web_port],
|
|
1698
1737
|
["Pinned keys", data.daemon.pinned_keys.length],
|
|
1699
1738
|
["Sessions", data.daemon.session_count]
|
|
1700
1739
|
],
|
|
@@ -24,6 +24,7 @@ var KNOWN_TOP_LEVEL_KEYS = /* @__PURE__ */ new Set([
|
|
|
24
24
|
"daemonLogMaxBytes",
|
|
25
25
|
"eventsLogMaxBytes",
|
|
26
26
|
"policy",
|
|
27
|
+
"webOrigins",
|
|
27
28
|
"advertisedIp",
|
|
28
29
|
"scheme",
|
|
29
30
|
"restartDaemonOnVersionMismatch"
|
|
@@ -84,6 +85,7 @@ var defaultConfig = (paths) => {
|
|
|
84
85
|
daemonLogMaxBytes: DEFAULT_DAEMON_LOG_MAX_BYTES,
|
|
85
86
|
eventsLogMaxBytes: 10 * 1024 * 1024,
|
|
86
87
|
restartDaemonOnVersionMismatch: false,
|
|
88
|
+
webOrigins: [],
|
|
87
89
|
policy: {
|
|
88
90
|
default: "allow",
|
|
89
91
|
destructive: "allow"
|
|
@@ -154,6 +156,12 @@ var loadConfig = async (paths, options = {}) => {
|
|
|
154
156
|
"restartDaemonOnVersionMismatch"
|
|
155
157
|
);
|
|
156
158
|
}
|
|
159
|
+
if (parsed.webOrigins !== void 0) {
|
|
160
|
+
if (!Array.isArray(parsed.webOrigins)) {
|
|
161
|
+
throw configError("webOrigins", "must be an array of origin strings.");
|
|
162
|
+
}
|
|
163
|
+
config.webOrigins = parsed.webOrigins.map((origin) => requireNonEmptyString(origin, "webOrigins"));
|
|
164
|
+
}
|
|
157
165
|
if (parsed.policy !== void 0) {
|
|
158
166
|
if (typeof parsed.policy !== "object" || parsed.policy === null || Array.isArray(parsed.policy)) {
|
|
159
167
|
throw configError("policy", "must be an object.");
|
|
@@ -913,7 +921,7 @@ var EXIT_CODE_BY_ERROR_TYPE = {
|
|
|
913
921
|
// EX_NOINPUT (66): "an input file did not exist or was not readable" — `doctor` throws this for a
|
|
914
922
|
// missing external tool or an unreadable/corrupt artifact, deliberately distinct from every other
|
|
915
923
|
// code here so a release pipeline can't mistake "we couldn't tell" for either a clean pass or an
|
|
916
|
-
// assertion failure
|
|
924
|
+
// assertion failure.
|
|
917
925
|
inspection_error: 66,
|
|
918
926
|
connection_error: 70,
|
|
919
927
|
session_error: 71,
|
|
@@ -1517,6 +1525,36 @@ var renderInvokeData = (colors, data, flags) => {
|
|
|
1517
1525
|
return [colors.green("Result"), formatScalar(data, flags)];
|
|
1518
1526
|
};
|
|
1519
1527
|
var renderLinkData = (colors, data, flags, qr) => {
|
|
1528
|
+
if ("attached" in data) {
|
|
1529
|
+
return [
|
|
1530
|
+
colors.green("Page Attached"),
|
|
1531
|
+
...renderFields(
|
|
1532
|
+
"Page",
|
|
1533
|
+
[
|
|
1534
|
+
["Session", data.sessionId],
|
|
1535
|
+
["Tab", data.targetId],
|
|
1536
|
+
["URL", data.url],
|
|
1537
|
+
["Expires", new Date(data.expiresAt * 1e3).toISOString()]
|
|
1538
|
+
],
|
|
1539
|
+
flags
|
|
1540
|
+
)
|
|
1541
|
+
];
|
|
1542
|
+
}
|
|
1543
|
+
if ("script" in data) {
|
|
1544
|
+
return [
|
|
1545
|
+
colors.green("Link Created"),
|
|
1546
|
+
...renderFields(
|
|
1547
|
+
"Link",
|
|
1548
|
+
[
|
|
1549
|
+
["Session", data.sessionId],
|
|
1550
|
+
["URL", data.url],
|
|
1551
|
+
["Script", data.script],
|
|
1552
|
+
["Expires", new Date(data.expiresAt * 1e3).toISOString()]
|
|
1553
|
+
],
|
|
1554
|
+
flags
|
|
1555
|
+
)
|
|
1556
|
+
];
|
|
1557
|
+
}
|
|
1520
1558
|
const lines = [
|
|
1521
1559
|
colors.green("Link Created"),
|
|
1522
1560
|
...renderFields(
|
|
@@ -1637,6 +1675,7 @@ var renderDaemonStatusData = (colors, data, flags) => {
|
|
|
1637
1675
|
["PID", data.daemon.pid],
|
|
1638
1676
|
["Started at", data.daemon.started_at],
|
|
1639
1677
|
["WSS port", data.daemon.wss_port],
|
|
1678
|
+
["Web port", data.daemon.web_port],
|
|
1640
1679
|
["Pinned keys", data.daemon.pinned_keys.length],
|
|
1641
1680
|
["Sessions", data.daemon.session_count]
|
|
1642
1681
|
],
|
|
@@ -93,7 +93,7 @@ var EXIT_CODE_BY_ERROR_TYPE = {
|
|
|
93
93
|
// EX_NOINPUT (66): "an input file did not exist or was not readable" — `doctor` throws this for a
|
|
94
94
|
// missing external tool or an unreadable/corrupt artifact, deliberately distinct from every other
|
|
95
95
|
// code here so a release pipeline can't mistake "we couldn't tell" for either a clean pass or an
|
|
96
|
-
// assertion failure
|
|
96
|
+
// assertion failure.
|
|
97
97
|
inspection_error: 66,
|
|
98
98
|
connection_error: 70,
|
|
99
99
|
session_error: 71,
|
|
@@ -549,6 +549,36 @@ var renderInvokeData = (colors, data, flags) => {
|
|
|
549
549
|
return [colors.green("Result"), formatScalar(data, flags)];
|
|
550
550
|
};
|
|
551
551
|
var renderLinkData = (colors, data, flags, qr) => {
|
|
552
|
+
if ("attached" in data) {
|
|
553
|
+
return [
|
|
554
|
+
colors.green("Page Attached"),
|
|
555
|
+
...renderFields(
|
|
556
|
+
"Page",
|
|
557
|
+
[
|
|
558
|
+
["Session", data.sessionId],
|
|
559
|
+
["Tab", data.targetId],
|
|
560
|
+
["URL", data.url],
|
|
561
|
+
["Expires", new Date(data.expiresAt * 1e3).toISOString()]
|
|
562
|
+
],
|
|
563
|
+
flags
|
|
564
|
+
)
|
|
565
|
+
];
|
|
566
|
+
}
|
|
567
|
+
if ("script" in data) {
|
|
568
|
+
return [
|
|
569
|
+
colors.green("Link Created"),
|
|
570
|
+
...renderFields(
|
|
571
|
+
"Link",
|
|
572
|
+
[
|
|
573
|
+
["Session", data.sessionId],
|
|
574
|
+
["URL", data.url],
|
|
575
|
+
["Script", data.script],
|
|
576
|
+
["Expires", new Date(data.expiresAt * 1e3).toISOString()]
|
|
577
|
+
],
|
|
578
|
+
flags
|
|
579
|
+
)
|
|
580
|
+
];
|
|
581
|
+
}
|
|
552
582
|
const lines = [
|
|
553
583
|
colors.green("Link Created"),
|
|
554
584
|
...renderFields(
|
|
@@ -669,6 +699,7 @@ var renderDaemonStatusData = (colors, data, flags) => {
|
|
|
669
699
|
["PID", data.daemon.pid],
|
|
670
700
|
["Started at", data.daemon.started_at],
|
|
671
701
|
["WSS port", data.daemon.wss_port],
|
|
702
|
+
["Web port", data.daemon.web_port],
|
|
672
703
|
["Pinned keys", data.daemon.pinned_keys.length],
|
|
673
704
|
["Sessions", data.daemon.session_count]
|
|
674
705
|
],
|
|
@@ -24,6 +24,7 @@ var KNOWN_TOP_LEVEL_KEYS = /* @__PURE__ */ new Set([
|
|
|
24
24
|
"daemonLogMaxBytes",
|
|
25
25
|
"eventsLogMaxBytes",
|
|
26
26
|
"policy",
|
|
27
|
+
"webOrigins",
|
|
27
28
|
"advertisedIp",
|
|
28
29
|
"scheme",
|
|
29
30
|
"restartDaemonOnVersionMismatch"
|
|
@@ -84,6 +85,7 @@ var defaultConfig = (paths) => {
|
|
|
84
85
|
daemonLogMaxBytes: DEFAULT_DAEMON_LOG_MAX_BYTES,
|
|
85
86
|
eventsLogMaxBytes: 10 * 1024 * 1024,
|
|
86
87
|
restartDaemonOnVersionMismatch: false,
|
|
88
|
+
webOrigins: [],
|
|
87
89
|
policy: {
|
|
88
90
|
default: "allow",
|
|
89
91
|
destructive: "allow"
|
|
@@ -154,6 +156,12 @@ var loadConfig = async (paths, options = {}) => {
|
|
|
154
156
|
"restartDaemonOnVersionMismatch"
|
|
155
157
|
);
|
|
156
158
|
}
|
|
159
|
+
if (parsed.webOrigins !== void 0) {
|
|
160
|
+
if (!Array.isArray(parsed.webOrigins)) {
|
|
161
|
+
throw configError("webOrigins", "must be an array of origin strings.");
|
|
162
|
+
}
|
|
163
|
+
config.webOrigins = parsed.webOrigins.map((origin) => requireNonEmptyString(origin, "webOrigins"));
|
|
164
|
+
}
|
|
157
165
|
if (parsed.policy !== void 0) {
|
|
158
166
|
if (typeof parsed.policy !== "object" || parsed.policy === null || Array.isArray(parsed.policy)) {
|
|
159
167
|
throw configError("policy", "must be an object.");
|
|
@@ -913,7 +921,7 @@ var EXIT_CODE_BY_ERROR_TYPE = {
|
|
|
913
921
|
// EX_NOINPUT (66): "an input file did not exist or was not readable" — `doctor` throws this for a
|
|
914
922
|
// missing external tool or an unreadable/corrupt artifact, deliberately distinct from every other
|
|
915
923
|
// code here so a release pipeline can't mistake "we couldn't tell" for either a clean pass or an
|
|
916
|
-
// assertion failure
|
|
924
|
+
// assertion failure.
|
|
917
925
|
inspection_error: 66,
|
|
918
926
|
connection_error: 70,
|
|
919
927
|
session_error: 71,
|
|
@@ -1511,6 +1519,36 @@ var renderInvokeData = (colors, data, flags) => {
|
|
|
1511
1519
|
return [colors.green("Result"), formatScalar(data, flags)];
|
|
1512
1520
|
};
|
|
1513
1521
|
var renderLinkData = (colors, data, flags, qr) => {
|
|
1522
|
+
if ("attached" in data) {
|
|
1523
|
+
return [
|
|
1524
|
+
colors.green("Page Attached"),
|
|
1525
|
+
...renderFields(
|
|
1526
|
+
"Page",
|
|
1527
|
+
[
|
|
1528
|
+
["Session", data.sessionId],
|
|
1529
|
+
["Tab", data.targetId],
|
|
1530
|
+
["URL", data.url],
|
|
1531
|
+
["Expires", new Date(data.expiresAt * 1e3).toISOString()]
|
|
1532
|
+
],
|
|
1533
|
+
flags
|
|
1534
|
+
)
|
|
1535
|
+
];
|
|
1536
|
+
}
|
|
1537
|
+
if ("script" in data) {
|
|
1538
|
+
return [
|
|
1539
|
+
colors.green("Link Created"),
|
|
1540
|
+
...renderFields(
|
|
1541
|
+
"Link",
|
|
1542
|
+
[
|
|
1543
|
+
["Session", data.sessionId],
|
|
1544
|
+
["URL", data.url],
|
|
1545
|
+
["Script", data.script],
|
|
1546
|
+
["Expires", new Date(data.expiresAt * 1e3).toISOString()]
|
|
1547
|
+
],
|
|
1548
|
+
flags
|
|
1549
|
+
)
|
|
1550
|
+
];
|
|
1551
|
+
}
|
|
1514
1552
|
const lines = [
|
|
1515
1553
|
colors.green("Link Created"),
|
|
1516
1554
|
...renderFields(
|
|
@@ -1631,6 +1669,7 @@ var renderDaemonStatusData = (colors, data, flags) => {
|
|
|
1631
1669
|
["PID", data.daemon.pid],
|
|
1632
1670
|
["Started at", data.daemon.started_at],
|
|
1633
1671
|
["WSS port", data.daemon.wss_port],
|
|
1672
|
+
["Web port", data.daemon.web_port],
|
|
1634
1673
|
["Pinned keys", data.daemon.pinned_keys.length],
|
|
1635
1674
|
["Sessions", data.daemon.session_count]
|
|
1636
1675
|
],
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `attachPage()` (issue #177): runs a web page's Appduct session through a Playwright page instead of
|
|
3
|
+
* a socket the page opens itself. The page and the daemon talk through a binding Playwright exposes,
|
|
4
|
+
* so it works on an `https` page with no permission prompt and no debugging port. The binding belongs
|
|
5
|
+
* to the page's target: a popup, or a navigation that creates a new target, is not relayed, and the
|
|
6
|
+
* session stays on the page it was attached to.
|
|
7
|
+
*/
|
|
8
|
+
import { type RelayLink } from "../devtools-relay/index.js";
|
|
9
|
+
/** The part of a Playwright `Page` that `attachPage` uses, so `appduct` has no Playwright dependency. */
|
|
10
|
+
export type AttachablePage = {
|
|
11
|
+
exposeBinding(name: string, callback: (source: {
|
|
12
|
+
frame: unknown;
|
|
13
|
+
}, json: string) => void): Promise<void>;
|
|
14
|
+
addInitScript(script: string): Promise<void>;
|
|
15
|
+
evaluate(expression: string): Promise<unknown>;
|
|
16
|
+
waitForFunction(expression: string): Promise<unknown>;
|
|
17
|
+
mainFrame(): unknown;
|
|
18
|
+
on(event: "close", handler: () => void): unknown;
|
|
19
|
+
};
|
|
20
|
+
export type AttachPageOptions = {
|
|
21
|
+
/** The result of `link({ target: "web", url })` for the page's address. */
|
|
22
|
+
link: RelayLink;
|
|
23
|
+
};
|
|
24
|
+
/**
|
|
25
|
+
* Connects the page, which must already load `@appduct/web`, to the daemon through its Playwright
|
|
26
|
+
* binding. Resolves once the session is claimed. A reload resumes the session over the same binding.
|
|
27
|
+
*
|
|
28
|
+
* Attaching a page that is already attached closes the first link's socket, so the daemon suspends
|
|
29
|
+
* the first session for its grace period and it stays listed as `suspended`. While it is, a
|
|
30
|
+
* `connect()` with no selector finds two sessions and fails with `ambiguous_session`: select the new
|
|
31
|
+
* one with `connect({ selector: link.sessionId })` or `waitForSession`. An invalid `link` rejects
|
|
32
|
+
* before anything is dropped.
|
|
33
|
+
*
|
|
34
|
+
* ```ts
|
|
35
|
+
* await page.goto("https://staging.example.com");
|
|
36
|
+
* await attachPage(page, { link: await link({ target: "web", url: page.url() }) });
|
|
37
|
+
* ```
|
|
38
|
+
*/
|
|
39
|
+
export declare const attachPage: (page: AttachablePage, options: AttachPageOptions) => Promise<void>;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type ExecFn, type OpenTarget } from "../cli/open-target.js";
|
|
2
|
-
import { type MintLinkResult } from "../link.js";
|
|
2
|
+
import { type MintLinkResult, type WebLinkResult } from "../link.js";
|
|
3
3
|
import { type SpawnFn } from "../rpc/client.js";
|
|
4
4
|
import { type AppClient, type ToolMap } from "./app-client.js";
|
|
5
5
|
export type LinkOptions = {
|
|
@@ -32,9 +32,23 @@ export type LinkOptions = {
|
|
|
32
32
|
schemeEnv?: NodeJS.ProcessEnv;
|
|
33
33
|
};
|
|
34
34
|
export type LinkResult = MintLinkResult;
|
|
35
|
+
export type WebLinkOptions = {
|
|
36
|
+
stateDir?: string;
|
|
37
|
+
spawn?: SpawnFn;
|
|
38
|
+
/** Auto-spawn a daemon on a missing connection. Defaults to `true`. */
|
|
39
|
+
autoSpawn?: boolean;
|
|
40
|
+
ttlSeconds?: number;
|
|
41
|
+
target: "web";
|
|
42
|
+
/** The page the link will be opened in. */
|
|
43
|
+
url: string;
|
|
44
|
+
};
|
|
45
|
+
export type { WebLinkResult };
|
|
35
46
|
/** Mints a session link via `link.create` and composes the deep link. With `target` set, delivers
|
|
36
|
-
* it directly to a booted emulator/simulator instead of leaving delivery to the caller.
|
|
37
|
-
|
|
47
|
+
* it directly to a booted emulator/simulator instead of leaving delivery to the caller. With
|
|
48
|
+
* `target: "web"` and the page's `url`, returns `{ url, script }` for a web page instead: `url`
|
|
49
|
+
* with `#appduct=<payload>` appended, and the script that connects an already-open page. */
|
|
50
|
+
export declare function link(options: WebLinkOptions): Promise<WebLinkResult>;
|
|
51
|
+
export declare function link(options?: LinkOptions): Promise<LinkResult>;
|
|
38
52
|
export type WaitForSessionOptions = {
|
|
39
53
|
stateDir?: string;
|
|
40
54
|
spawn?: SpawnFn;
|
package/dist/client/index.d.ts
CHANGED
|
@@ -11,8 +11,9 @@
|
|
|
11
11
|
* await app.close();
|
|
12
12
|
* ```
|
|
13
13
|
*/
|
|
14
|
+
export { attachPage, type AttachablePage, type AttachPageOptions } from "./attach-page.js";
|
|
14
15
|
export { connect, type ConnectOptions } from "./connect.js";
|
|
15
|
-
export { link, waitForSession, type LinkOptions, type LinkResult, type WaitForSessionOptions } from "./bootstrap.js";
|
|
16
|
+
export { link, waitForSession, type LinkOptions, type LinkResult, type WaitForSessionOptions, type WebLinkOptions, type WebLinkResult, } from "./bootstrap.js";
|
|
16
17
|
export { AppductError, type AppductErrorType } from "./errors.js";
|
|
17
18
|
export type { AppClient, AppEvent, CallOptions, EventsOptions, EventsResult, FullAppEvent, FullEventsResult, ToolMap, WaitForEventOptions, } from "./app-client.js";
|
|
18
19
|
export type { TruncatedAppEvent } from "@appduct/shared";
|