@xenon-device-management/xenon 2.15.0 → 2.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +38 -26
- package/lib/package.json +2 -1
- package/lib/public/assets/{AnnotationOverlay-Btq3dZRI.js → AnnotationOverlay-2W4JvEyZ.js} +1 -1
- package/lib/public/assets/{ApiKeyGate-C9OoAgg_.js → ApiKeyGate-GmckX_7r.js} +1 -1
- package/lib/public/assets/{DeviceMosaicView-DBC_xczB.js → DeviceMosaicView-DqODzkyo.js} +1 -1
- package/lib/public/assets/{EmptyState-DqWU2-vM.js → EmptyState-7hETKEWb.js} +1 -1
- package/lib/public/assets/{FieldGroup-CveQ3xrA.js → FieldGroup-GOgssFEP.js} +1 -1
- package/lib/public/assets/{FilterMenu-BfKDSfHz.js → FilterMenu-Yvf6RGMd.js} +1 -1
- package/lib/public/assets/{Menu-CtdCybzA.js → Menu-KrPnfdsf.js} +1 -1
- package/lib/public/assets/{Modal-Bsvj1tm2.js → Modal-C6WjZFeI.js} +1 -1
- package/lib/public/assets/{RecordingPage-CRofOiyx.js → RecordingPage-CSRIhZEh.js} +1 -1
- package/lib/public/assets/{RecordingsPage-jNQHb2IR.js → RecordingsPage-CB8ST3nE.js} +1 -1
- package/lib/public/assets/{SegmentedControl-C8HtTha-.js → SegmentedControl-C9o90KId.js} +1 -1
- package/lib/public/assets/{SettingCard-D8K1LZNo.js → SettingCard-CPm3w9l2.js} +1 -1
- package/lib/public/assets/{Table-zNTX92Pn.js → Table-DwIgERRt.js} +1 -1
- package/lib/public/assets/{activity-CJ8LwZq9.js → activity-DrLbHifn.js} +1 -1
- package/lib/public/assets/{ai-settings-CgxQZqrc.js → ai-settings-DU_Ls06P.js} +1 -1
- package/lib/public/assets/{api-keys-ECpo-zTo.js → api-keys-CWYdEzJ_.js} +1 -1
- package/lib/public/assets/{apps-BjGymyf3.js → apps-BqNVdln7.js} +1 -1
- package/lib/public/assets/{arrow-left-BWfCbeHP.js → arrow-left-BtB0_Jg_.js} +1 -1
- package/lib/public/assets/{arrow-right-DC7UGf_n.js → arrow-right-C8NhdtyN.js} +1 -1
- package/lib/public/assets/{arrow-up-right-BOjwybDk.js → arrow-up-right-gMg0ffvv.js} +1 -1
- package/lib/public/assets/{auth-shell-CxMTo9aH.js → auth-shell-CiYZ3N4M.js} +2 -2
- package/lib/public/assets/{builds-page-DOCm4HkA.js → builds-page-EaaqDmLN.js} +1 -1
- package/lib/public/assets/{button-Cg08-EMT.js → button-DDau4Axv.js} +1 -1
- package/lib/public/assets/{calendar-CA1ikLJs.js → calendar-DQ83B1ed.js} +1 -1
- package/lib/public/assets/{check-BMTaH72W.js → check-K1ovTQam.js} +1 -1
- package/lib/public/assets/{chevron-right-B2QOv9Nx.js → chevron-right-Biq00pMt.js} +1 -1
- package/lib/public/assets/{circle-check-CYXBoUqT.js → circle-check-CBv88cH7.js} +1 -1
- package/lib/public/assets/{circle-x-DTwnSAnl.js → circle-x-Bmltailn.js} +1 -1
- package/lib/public/assets/{clock-C8_HViQP.js → clock-BPrld-3h.js} +1 -1
- package/lib/public/assets/{copy-Be7LNMXV.js → copy-t0QB14JI.js} +1 -1
- package/lib/public/assets/{device-explorer-BOqtfGXz.js → device-explorer-BgGZ8AvV.js} +1 -1
- package/lib/public/assets/{download-B56lwxWP.js → download-BroHxNOh.js} +1 -1
- package/lib/public/assets/{forgot-password-CCU6bzLn.js → forgot-password-Bjmf49i6.js} +1 -1
- package/lib/public/assets/{h264Stream-C-OtmIuk.js → h264Stream-DeD__6wa.js} +1 -1
- package/lib/public/assets/{index-CfxsUslp.js → index-72oF89LJ.js} +1 -1
- package/lib/public/assets/{index-B9KQ6LsY.js → index-B0JeuZbg.js} +1 -1
- package/lib/public/assets/index-B0gQkEg0.js +219 -0
- package/lib/public/assets/{input-CZHFjbSg.js → input-DIc4MSC7.js} +1 -1
- package/lib/public/assets/{line-chart-Gl_Dz3X_.js → line-chart-BcWm2vW8.js} +1 -1
- package/lib/public/assets/{list-checks-CCgjeyGY.js → list-checks-B06IJJad.js} +1 -1
- package/lib/public/assets/{lock-CkOwgDcx.js → lock-pVLvnN30.js} +1 -1
- package/lib/public/assets/{login-D5cc4w7M.js → login-CN77vy--.js} +1 -1
- package/lib/public/assets/{maintenance-settings-t7qr3fvX.js → maintenance-settings-CSdzQSkY.js} +1 -1
- package/lib/public/assets/{monitor-DEJixKQO.js → monitor-BtrN5IkI.js} +1 -1
- package/lib/public/assets/{mouse-pointer-2-CtOrk4M8.js → mouse-pointer-2-CNsQfo6w.js} +1 -1
- package/lib/public/assets/{network-Dii9qdvk.js → network-BSfA8ZxG.js} +1 -1
- package/lib/public/assets/{overview-rolAACrO.js → overview-BfTebCK5.js} +1 -1
- package/lib/public/assets/{page-header-COQZxJfR.js → page-header-D8KUX6Qg.js} +1 -1
- package/lib/public/assets/{play-DrN1Se_R.js → play-Cvc8xzic.js} +1 -1
- package/lib/public/assets/{plus-5aq-9uRx.js → plus-C9Zj84UF.js} +1 -1
- package/lib/public/assets/{profile-page-6i5kY6kF.js → profile-page-Bi27STgs.js} +1 -1
- package/lib/public/assets/{reset-password-sp2IBrc7.js → reset-password-CPsOuwSu.js} +1 -1
- package/lib/public/assets/{runbook-page-DJDjeopU.js → runbook-page-DEQ-DBOX.js} +153 -102
- package/lib/public/assets/{select-Bpyn7rWO.js → select-BWpnhWXj.js} +1 -1
- package/lib/public/assets/{selector-detail-redirect-BH74vmKv.js → selector-detail-redirect-BefSCSpe.js} +1 -1
- package/lib/public/assets/{selector-health-page-Cw_g218H.js → selector-health-page-MSk96Zz7.js} +1 -1
- package/lib/public/assets/session-detail-page-DPyBNef_.js +4 -0
- package/lib/public/assets/{settings-C3uyGhyc.js → settings-V6x-cXwy.js} +1 -1
- package/lib/public/assets/{stat-tile-xVqAKIlI.js → stat-tile-Duex-GZD.js} +1 -1
- package/lib/public/assets/{tablet-BxUScAeO.js → tablet-BBcoqBmL.js} +1 -1
- package/lib/public/assets/{teams-B5ljGkY2.js → teams-ts8p5rEh.js} +1 -1
- package/lib/public/assets/{trash-2-B701i8sy.js → trash-2-CZ2ew6AZ.js} +1 -1
- package/lib/public/assets/{upload-C2gr44RS.js → upload-Dv99y_le.js} +1 -1
- package/lib/public/assets/{use-builds-data-NeQOFEoy.js → use-builds-data-DrYC8JCF.js} +1 -1
- package/lib/public/assets/{use-password-reset-mode-DEzJq5ef.js → use-password-reset-mode-C7QkBNkP.js} +1 -1
- package/lib/public/assets/{users-D_vv_yz4.js → users-D7tKMESH.js} +1 -1
- package/lib/public/assets/{users-MY6eNe6s.js → users-gJ5Y01yo.js} +1 -1
- package/lib/public/assets/{video-off-OK1lNZQn.js → video-off-CqZVuZGs.js} +1 -1
- package/lib/public/assets/{webhook-settings-BU-C9lBf.js → webhook-settings-DI5DSW99.js} +1 -1
- package/lib/public/assets/{zap-DO9ry1iz.js → zap-ClcHFxfo.js} +1 -1
- package/lib/public/index.html +1 -1
- package/lib/schema.json +11 -7
- package/lib/src/InternalHttpClient.js +27 -5
- package/lib/src/XenonCapabilityManager.js +10 -3
- package/lib/src/app/openapi/sessions.yaml +7 -5
- package/lib/src/app/routers/auth.js +2 -1
- package/lib/src/app/routers/users.js +2 -1
- package/lib/src/app/ws/nodeSocketRelay.js +77 -11
- package/lib/src/dashboard/commandLogFields.js +42 -0
- package/lib/src/dashboard/event-manager.js +26 -154
- package/lib/src/dashboard/services/failure-analysis-service.js +8 -86
- package/lib/src/dashboard/services/failureCategories.js +264 -0
- package/lib/src/device-managers/AndroidDeviceManager.js +61 -23
- package/lib/src/device-managers/IOSDeviceManager.js +10 -0
- package/lib/src/device-utils.js +14 -6
- package/lib/src/gateway/forwardToNode.js +4 -11
- package/lib/src/gateway/hubSessionToken.js +27 -4
- package/lib/src/gateway/nodeWebDriverUrl.js +3 -5
- package/lib/src/helpers/outboundProxy.js +219 -0
- package/lib/src/index.js +21 -0
- package/lib/src/interceptors/CommandInterceptor.js +13 -15
- package/lib/src/interceptors/xenonScripts.js +28 -7
- package/lib/src/logger.js +3 -1
- package/lib/src/plugin.js +8 -3
- package/lib/src/scripts/database-check.js +3 -3
- package/lib/src/scripts/initialize-database.js +35 -33
- package/lib/src/scripts/run-migrations.js +1079 -27
- package/lib/src/services/ApiKeyService.js +16 -5
- package/lib/src/services/InterceptorService.js +6 -2
- package/lib/src/services/OrphanSweeper.js +6 -0
- package/lib/src/services/SelectorStateService.js +11 -7
- package/lib/src/services/SelectorVerificationJob.js +6 -2
- package/lib/src/services/SessionLifecycleService.js +32 -18
- package/lib/src/services/SocketClient.js +11 -0
- package/lib/src/services/SocketServer.js +361 -42
- package/lib/src/services/TeamService.js +5 -1
- package/lib/src/services/TracingService.js +171 -60
- package/lib/src/services/UserService.js +14 -3
- package/lib/src/services/UserSessionService.js +16 -4
- package/lib/src/services/healing/HealingOrchestrator.js +3 -1
- package/lib/src/services/identity/identityChanges.js +41 -0
- package/lib/src/services/logcat/SessionDeviceLogs.js +97 -10
- package/lib/src/services/logcat/deviceLogBook.js +5 -4
- package/lib/src/services/logcat/iosDriverLog.js +178 -0
- package/lib/src/services/selector-health/SelectorVisibilityResolver.js +121 -0
- package/lib/src/services/token/JwtKeyService.js +8 -2
- package/lib/src/services/token/mcpTokenTtl.js +27 -0
- package/lib/src/sessions/LocalSession.js +29 -1
- package/lib/src/sessions/RemoteSession.js +12 -2
- package/lib/src/sessions/SessionManager.js +5 -8
- package/lib/test/helpers/driver-log.js +38 -0
- package/lib/test/helpers/fake-http-proxy.js +106 -0
- package/lib/test/helpers/otlp-probe.js +107 -0
- package/lib/test/integration/androidDevices.spec.js +1 -1
- package/lib/test/integration/ios/01iOSSimulator.spec.js +1 -1
- package/lib/test/integration/ios/02iOSDevices.spec.js +1 -1
- package/lib/test/integration/selector-state-flow.spec.js +5 -5
- package/lib/test/unit/XenonCapabilityManager.spec.js +23 -0
- package/lib/test/unit/android-adb-retry.spec.js +112 -0
- package/lib/test/unit/command-log-network-capture.spec.js +191 -0
- package/lib/test/unit/dashboard-events-device-logs.spec.js +59 -11
- package/lib/test/unit/dashboard-events-team-scope.spec.js +6 -3
- package/lib/test/unit/database-check.spec.js +1 -0
- package/lib/test/unit/device-utils.spec.js +13 -4
- package/lib/test/unit/event-log-session-data.spec.js +11 -4
- package/lib/test/unit/failure-analysis.spec.js +22 -8
- package/lib/test/unit/failure-categories.spec.js +24 -22
- package/lib/test/unit/failure-categorization.spec.js +393 -0
- package/lib/test/unit/healing-tier-gate.spec.js +3 -2
- package/lib/test/unit/hub-node-gateway-appium-server.spec.js +72 -1
- package/lib/test/unit/ios-driver-log.spec.js +168 -0
- package/lib/test/unit/ios-simulator-session-readiness.spec.js +187 -0
- package/lib/test/unit/ios-simulator-session-teardown.spec.js +158 -0
- package/lib/test/unit/logcat-ws.spec.js +78 -37
- package/lib/test/unit/logger-json-levels.spec.js +44 -0
- package/lib/test/unit/mcp-token-ttl.spec.js +38 -0
- package/lib/test/unit/observability-example-loki.spec.js +25 -0
- package/lib/test/unit/openapi-for-site.spec.js +80 -0
- package/lib/test/unit/outbound-proxy.spec.js +320 -0
- package/lib/test/unit/port-exhaustion.spec.js +2 -1
- package/lib/test/unit/proxy-option.spec.js +358 -0
- package/lib/test/unit/run-migrations-database.spec.js +807 -0
- package/lib/test/unit/run-migrations-fail-fast.test.js +41 -27
- package/lib/test/unit/run-migrations.test.js +864 -0
- package/lib/test/unit/selector-health-actions.spec.js +3 -1
- package/lib/test/unit/selector-state-service.spec.js +72 -23
- package/lib/test/unit/selector-verification-clean-build.spec.js +1 -1
- package/lib/test/unit/selector-verification-job.spec.js +15 -6
- package/lib/test/unit/selector-verification-missed-regression.spec.js +2 -2
- package/lib/test/unit/selector-visibility-resolver.spec.js +209 -0
- package/lib/test/unit/session-device-logs-ios.spec.js +180 -0
- package/lib/test/unit/session-device-logs.spec.js +11 -2
- package/lib/test/unit/session-end-failure-analysis.spec.js +5 -5
- package/lib/test/unit/session-log-indexes.spec.js +1 -1
- package/lib/test/unit/socket-team-scope.integration.spec.js +749 -0
- package/lib/test/unit/socketServer.scopedEmit.spec.js +237 -5
- package/lib/test/unit/tracing-export-routing.spec.js +137 -0
- package/lib/test/unit/tracing-session-spans.spec.js +337 -0
- package/lib/test/unit/unexpected-shutdown-reason.spec.js +2 -2
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/package.json +2 -1
- package/schema.json +11 -7
- package/scripts/dev/readme-screenshots.js +276 -23
- package/scripts/dev/screenshot-fixtures/logcat.js +157 -0
- package/scripts/dev/screenshot-fixtures/phone-screen.html +469 -0
- package/scripts/dev/screenshot-fixtures/session.js +242 -0
- package/scripts/export-openapi.js +32 -0
- package/scripts/lib/openapi-for-site.js +79 -0
- package/lib/public/assets/index-BOxe43p1.js +0 -219
- package/lib/public/assets/session-detail-page-AZJE6XXE.js +0 -4
- package/lib/src/scripts/prepare-prisma.js +0 -89
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
|
+
};
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.outboundProxyFor = outboundProxyFor;
|
|
16
|
+
exports.envProxyFor = envProxyFor;
|
|
17
|
+
exports.proxyAgentFor = proxyAgentFor;
|
|
18
|
+
exports.socketProxyAgentFor = socketProxyAgentFor;
|
|
19
|
+
exports.axiosProxyConfig = axiosProxyConfig;
|
|
20
|
+
const typedi_1 = require("typedi");
|
|
21
|
+
const http_proxy_agent_1 = require("http-proxy-agent");
|
|
22
|
+
const https_proxy_agent_1 = require("https-proxy-agent");
|
|
23
|
+
const logger_1 = __importDefault(require("../logger"));
|
|
24
|
+
const PluginContext_1 = require("../PluginContext");
|
|
25
|
+
/**
|
|
26
|
+
* The proxy for one of Xenon's own calls to another server (a hub's to its
|
|
27
|
+
* nodes and to a cloud provider, a node's to its hub, and the rest of
|
|
28
|
+
* Xenon's internal calls), one rule whichever client makes the call:
|
|
29
|
+
*
|
|
30
|
+
* 1. None for a host `no_proxy` / `NO_PROXY` names (envProxyFor's list).
|
|
31
|
+
* 2. The `proxy` plugin option when it is set, for http and https alike,
|
|
32
|
+
* except for a loopback host (`localhost`, 127.x, ::1): a proxy elsewhere
|
|
33
|
+
* can't reach this machine's loopback.
|
|
34
|
+
* 3. Else the environment's proxy for the URL's scheme (envProxyFor).
|
|
35
|
+
*
|
|
36
|
+
* Through 2.15 the option reached one call, the create a hub sends to a node
|
|
37
|
+
* or a cloud provider; that session's commands, screenshots and heartbeats,
|
|
38
|
+
* device control, the sockets and a node's calls to its hub took the
|
|
39
|
+
* environment's proxy instead, or none.
|
|
40
|
+
*/
|
|
41
|
+
function outboundProxyFor(target, opts = {}) {
|
|
42
|
+
var _a, _b;
|
|
43
|
+
const url = toUrl(target);
|
|
44
|
+
const scheme = schemeOf(url);
|
|
45
|
+
if (!scheme)
|
|
46
|
+
return undefined;
|
|
47
|
+
const env = (_a = opts.env) !== null && _a !== void 0 ? _a : process.env;
|
|
48
|
+
if (namedByNoProxy(url, env))
|
|
49
|
+
return undefined;
|
|
50
|
+
const option = 'option' in opts ? opts.option : pluginProxyOption();
|
|
51
|
+
const configured = proxyOptionUrl(option, (_b = opts.warn) !== null && _b !== void 0 ? _b : warnOnce);
|
|
52
|
+
if (configured && !isLoopback(url.hostname))
|
|
53
|
+
return configured;
|
|
54
|
+
return schemeProxy(scheme, env);
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* The environment's proxy for a URL, by the rule axios (0.27's http adapter)
|
|
58
|
+
* applies to Xenon's axios calls:
|
|
59
|
+
* - `http_proxy` or `HTTP_PROXY` for an http URL, `https_proxy` or
|
|
60
|
+
* `HTTPS_PROXY` for an https one, the lower-case name first (ws and wss
|
|
61
|
+
* count as http and https);
|
|
62
|
+
* - none when `no_proxy` or `NO_PROXY` (the lower-case name first; a
|
|
63
|
+
* comma-separated list) has `*`, the URL's host name, or a suffix of it
|
|
64
|
+
* starting with a dot (`.lab.example`). An entry is a host name only: one
|
|
65
|
+
* with a port matches nothing, as in axios.
|
|
66
|
+
*
|
|
67
|
+
* Through 2.15 a command forwarded to a node took HTTP_PROXY or HTTPS_PROXY
|
|
68
|
+
* whatever its scheme and ignored NO_PROXY, the live-preview and logcat
|
|
69
|
+
* sockets ignored every proxy, and so did a node fetching its hub's keys.
|
|
70
|
+
*/
|
|
71
|
+
function envProxyFor(target, env = process.env) {
|
|
72
|
+
const url = toUrl(target);
|
|
73
|
+
const scheme = schemeOf(url);
|
|
74
|
+
if (!scheme || namedByNoProxy(url, env))
|
|
75
|
+
return undefined;
|
|
76
|
+
return schemeProxy(scheme, env);
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* An agent sending an HTTP request for `target` through its proxy, or
|
|
80
|
+
* undefined to go straight there: the request in absolute form to the proxy
|
|
81
|
+
* for an http URL, a CONNECT tunnel for an https one.
|
|
82
|
+
*/
|
|
83
|
+
function proxyAgentFor(target, tls = {}) {
|
|
84
|
+
const proxy = outboundProxyFor(target);
|
|
85
|
+
if (!proxy)
|
|
86
|
+
return undefined;
|
|
87
|
+
const url = toUrl(target);
|
|
88
|
+
return url.protocol === 'https:' ? new TunnelAgent(proxy, tls) : new http_proxy_agent_1.HttpProxyAgent(proxy);
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* An agent opening a WebSocket for `target` (ws or wss) through its proxy, or
|
|
92
|
+
* undefined to go straight there. Always a CONNECT tunnel: an upgrade sent to
|
|
93
|
+
* a proxy in absolute form is not reliably passed on.
|
|
94
|
+
*/
|
|
95
|
+
function socketProxyAgentFor(target, tls = {}) {
|
|
96
|
+
const proxy = outboundProxyFor(target);
|
|
97
|
+
return proxy ? new TunnelAgent(proxy, tls) : undefined;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* An axios request's proxy settings for `target`: through its proxy's agent,
|
|
101
|
+
* or none. Either way `proxy: false`, since the decision is made here, by
|
|
102
|
+
* outboundProxyFor; axios's own lookup reads the environment only. With no
|
|
103
|
+
* proxy, the caller's own agents stay.
|
|
104
|
+
*/
|
|
105
|
+
function axiosProxyConfig(target, tls = {}) {
|
|
106
|
+
const agent = proxyAgentFor(target, tls);
|
|
107
|
+
return agent ? { proxy: false, httpAgent: agent, httpsAgent: agent } : { proxy: false };
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* A CONNECT tunnel that checks the server behind it as the caller asked.
|
|
111
|
+
* HttpsProxyAgent's own options are for the connection to the proxy; the
|
|
112
|
+
* tunnelled TLS takes the request's, which axios doesn't fill in. So through
|
|
113
|
+
* 2.15 `tlsRejectUnauthorized` never reached a node or cloud provider that a
|
|
114
|
+
* proxy stood in front of.
|
|
115
|
+
*/
|
|
116
|
+
class TunnelAgent extends https_proxy_agent_1.HttpsProxyAgent {
|
|
117
|
+
constructor(proxy, targetTls) {
|
|
118
|
+
super(proxy);
|
|
119
|
+
this.targetTls = targetTls;
|
|
120
|
+
}
|
|
121
|
+
connect(req, opts) {
|
|
122
|
+
const _super = Object.create(null, {
|
|
123
|
+
connect: { get: () => super.connect }
|
|
124
|
+
});
|
|
125
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
126
|
+
const tls = this.targetTls.rejectUnauthorized === undefined
|
|
127
|
+
? {}
|
|
128
|
+
: { rejectUnauthorized: this.targetTls.rejectUnauthorized };
|
|
129
|
+
return _super.connect.call(this, req, Object.assign(Object.assign({}, opts), tls));
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* The `proxy` option as a proxy URL: a string as it is (http:// added when
|
|
135
|
+
* it names no scheme), or `{ protocol, host, port, auth: { username,
|
|
136
|
+
* password } }` (protocol http by default, credentials escaped). One that
|
|
137
|
+
* names no host is no proxy, said once.
|
|
138
|
+
*/
|
|
139
|
+
function proxyOptionUrl(option, warn) {
|
|
140
|
+
var _a, _b;
|
|
141
|
+
if (option === undefined || option === null || option === '')
|
|
142
|
+
return undefined;
|
|
143
|
+
if (typeof option === 'string') {
|
|
144
|
+
const text = option.trim();
|
|
145
|
+
if (text === '')
|
|
146
|
+
return undefined;
|
|
147
|
+
return hasScheme(text) ? text : `http://${text}`;
|
|
148
|
+
}
|
|
149
|
+
const value = option;
|
|
150
|
+
if (typeof option !== 'object' || typeof value.host !== 'string' || value.host.trim() === '') {
|
|
151
|
+
warn(`The proxy option ${JSON.stringify(option)} names no host, so it is not used: ` +
|
|
152
|
+
"Xenon's calls to other servers take the environment's proxy, if any.");
|
|
153
|
+
return undefined;
|
|
154
|
+
}
|
|
155
|
+
const protocol = typeof value.protocol === 'string' && value.protocol !== ''
|
|
156
|
+
? value.protocol.replace(/:$/, '')
|
|
157
|
+
: 'http';
|
|
158
|
+
const port = value.port === undefined || value.port === null ? '' : `:${value.port}`;
|
|
159
|
+
const username = (_a = value.auth) === null || _a === void 0 ? void 0 : _a.username;
|
|
160
|
+
const password = (_b = value.auth) === null || _b === void 0 ? void 0 : _b.password;
|
|
161
|
+
const credentials = typeof username === 'string' && username !== ''
|
|
162
|
+
? `${encodeURIComponent(username)}${typeof password === 'string' ? `:${encodeURIComponent(password)}` : ''}@`
|
|
163
|
+
: '';
|
|
164
|
+
return `${protocol}://${credentials}${value.host.trim()}${port}`;
|
|
165
|
+
}
|
|
166
|
+
const warned = new Set();
|
|
167
|
+
function warnOnce(message) {
|
|
168
|
+
if (warned.has(message))
|
|
169
|
+
return;
|
|
170
|
+
warned.add(message);
|
|
171
|
+
logger_1.default.warn(message);
|
|
172
|
+
}
|
|
173
|
+
function pluginProxyOption() {
|
|
174
|
+
var _a;
|
|
175
|
+
try {
|
|
176
|
+
return (_a = typedi_1.Container.get(PluginContext_1.PluginContext).pluginArgs) === null || _a === void 0 ? void 0 : _a.proxy;
|
|
177
|
+
}
|
|
178
|
+
catch (_b) {
|
|
179
|
+
return undefined;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
function toUrl(target) {
|
|
183
|
+
return typeof target === 'string' ? new URL(target) : target;
|
|
184
|
+
}
|
|
185
|
+
function schemeOf(url) {
|
|
186
|
+
const scheme = url.protocol.replace(/:$/, '').replace(/^ws(s?)$/, 'http$1');
|
|
187
|
+
return scheme === 'http' || scheme === 'https' ? scheme : undefined;
|
|
188
|
+
}
|
|
189
|
+
function hostOf(url) {
|
|
190
|
+
return url.hostname.replace(/^\[(.*)\]$/, '$1');
|
|
191
|
+
}
|
|
192
|
+
function namedByNoProxy(url, env) {
|
|
193
|
+
const noProxy = env.no_proxy || env.NO_PROXY;
|
|
194
|
+
if (!noProxy)
|
|
195
|
+
return false;
|
|
196
|
+
const host = hostOf(url);
|
|
197
|
+
return noProxy
|
|
198
|
+
.split(',')
|
|
199
|
+
.map((entry) => entry.trim())
|
|
200
|
+
.some((entry) => entry !== '' &&
|
|
201
|
+
(entry === '*' || entry === host || (entry.startsWith('.') && host.endsWith(entry))));
|
|
202
|
+
}
|
|
203
|
+
function schemeProxy(scheme, env) {
|
|
204
|
+
const proxy = env[`${scheme}_proxy`] || env[`${scheme.toUpperCase()}_PROXY`];
|
|
205
|
+
if (!proxy)
|
|
206
|
+
return undefined;
|
|
207
|
+
return hasScheme(proxy) ? proxy : `http://${proxy}`;
|
|
208
|
+
}
|
|
209
|
+
function hasScheme(text) {
|
|
210
|
+
return /^[a-z][a-z0-9+.-]*:\/\//i.test(text);
|
|
211
|
+
}
|
|
212
|
+
function isLoopback(hostname) {
|
|
213
|
+
const host = hostname.replace(/^\[(.*)\]$/, '$1').toLowerCase();
|
|
214
|
+
return (host === 'localhost' ||
|
|
215
|
+
host.endsWith('.localhost') ||
|
|
216
|
+
/^127(\.\d{1,3}){3}$/.test(host) ||
|
|
217
|
+
host === '::1' ||
|
|
218
|
+
host === '0:0:0:0:0:0:0:1');
|
|
219
|
+
}
|
package/lib/src/index.js
CHANGED
|
@@ -68,6 +68,12 @@ const cleanup = () => __awaiter(void 0, void 0, void 0, function* () {
|
|
|
68
68
|
// Bounded so a hung driver can't hold up systemd (default 90s timeout).
|
|
69
69
|
const { ShutdownCoordinator } = yield Promise.resolve().then(() => __importStar(require('./services/ShutdownCoordinator')));
|
|
70
70
|
yield typedi_1.Container.get(ShutdownCoordinator).drain(15000);
|
|
71
|
+
// Telemetry next, as early as it can be: on SIGTERM Appium exits before
|
|
72
|
+
// Phase 2 (see the 'exit' hook below), and placed last it never ran. What
|
|
73
|
+
// the OTel exporters still hold is sent, and the spans of sessions still
|
|
74
|
+
// running on a node or at a cloud provider end, saying so. Lines logged
|
|
75
|
+
// after this aren't exported.
|
|
76
|
+
yield shutDownTelemetry(3000);
|
|
71
77
|
const { default: IOSStreamService } = yield Promise.resolve().then(() => __importStar(require('./device-managers/ios/IOSStreamService')));
|
|
72
78
|
const { default: AndroidStreamService } = yield Promise.resolve().then(() => __importStar(require('./device-managers/android/AndroidStreamService')));
|
|
73
79
|
const { LogcatStreamService } = yield Promise.resolve().then(() => __importStar(require('./device-managers/android/LogcatStreamService')));
|
|
@@ -94,11 +100,26 @@ const cleanup = () => __awaiter(void 0, void 0, void 0, function* () {
|
|
|
94
100
|
logger_1.default.error(`❌ [Xenon] Cleanup failed: ${err.message}`);
|
|
95
101
|
}
|
|
96
102
|
finally {
|
|
103
|
+
// When the drain threw, the telemetry wasn't shut down above. A second
|
|
104
|
+
// call does nothing.
|
|
105
|
+
yield shutDownTelemetry(1000);
|
|
97
106
|
// Principal Delay: Wait 2 seconds before hard-exiting to allow
|
|
98
107
|
// other async handlers (like hub unregistration) to finish.
|
|
99
108
|
setTimeout(() => process.exit(0), 2000);
|
|
100
109
|
}
|
|
101
110
|
});
|
|
111
|
+
function shutDownTelemetry(budgetMs) {
|
|
112
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
113
|
+
var _a;
|
|
114
|
+
try {
|
|
115
|
+
const { TracingService } = yield Promise.resolve().then(() => __importStar(require('./services/TracingService')));
|
|
116
|
+
yield typedi_1.Container.get(TracingService).shutdownWithin(budgetMs);
|
|
117
|
+
}
|
|
118
|
+
catch (err) {
|
|
119
|
+
logger_1.default.warn(`[Xenon] Telemetry shutdown failed: ${(_a = err === null || err === void 0 ? void 0 : err.message) !== null && _a !== void 0 ? _a : err}`);
|
|
120
|
+
}
|
|
121
|
+
});
|
|
122
|
+
}
|
|
102
123
|
process.on('SIGINT', cleanup);
|
|
103
124
|
process.on('SIGTERM', cleanup);
|
|
104
125
|
// Last-resort synchronous net for every long-lived sidecar.
|
|
@@ -118,6 +118,7 @@ let CommandInterceptor = class CommandInterceptor {
|
|
|
118
118
|
return yield next();
|
|
119
119
|
const sessionId = driver.sessionId || args[args.length - 1];
|
|
120
120
|
const tracingService = typedi_1.Container.get(TracingService_1.TracingService);
|
|
121
|
+
const spanId = `${sessionId}:${commandName}`;
|
|
121
122
|
let span;
|
|
122
123
|
if (isHub && sessionId) {
|
|
123
124
|
span = tracingService.startCommandSpan(sessionId, commandName, {
|
|
@@ -130,6 +131,7 @@ let CommandInterceptor = class CommandInterceptor {
|
|
|
130
131
|
// those services having to accept a context parameter.
|
|
131
132
|
const spanCtx = span === null || span === void 0 ? void 0 : span.spanContext();
|
|
132
133
|
const cmdStart = Date.now();
|
|
134
|
+
let failure;
|
|
133
135
|
try {
|
|
134
136
|
return yield sessionContext_1.sessionContext.run({
|
|
135
137
|
sessionId: sessionId || undefined,
|
|
@@ -137,9 +139,16 @@ let CommandInterceptor = class CommandInterceptor {
|
|
|
137
139
|
commandName,
|
|
138
140
|
traceId: spanCtx === null || spanCtx === void 0 ? void 0 : spanCtx.traceId,
|
|
139
141
|
spanId: spanCtx === null || spanCtx === void 0 ? void 0 : spanCtx.spanId,
|
|
140
|
-
}, () => this.handleInContext(next, driver, commandName, args, pluginArgs, isHub, sessionId
|
|
142
|
+
}, () => this.handleInContext(next, driver, commandName, args, pluginArgs, isHub, sessionId));
|
|
143
|
+
}
|
|
144
|
+
catch (error) {
|
|
145
|
+
// What the client gets: a healed find returned an element instead.
|
|
146
|
+
failure = { error };
|
|
147
|
+
throw error;
|
|
141
148
|
}
|
|
142
149
|
finally {
|
|
150
|
+
if (span)
|
|
151
|
+
tracingService.endCommandSpan(spanId, span, failure);
|
|
143
152
|
// Aggregate counter — no per-session label, just fleet-wide throughput
|
|
144
153
|
// so Prom rate() gives commands/sec and the duration sum gives avg
|
|
145
154
|
// latency. Errors still count: a 429-hit dashboard poll is still hub
|
|
@@ -148,7 +157,7 @@ let CommandInterceptor = class CommandInterceptor {
|
|
|
148
157
|
}
|
|
149
158
|
});
|
|
150
159
|
}
|
|
151
|
-
handleInContext(next, driver, commandName, args, pluginArgs, isHub, sessionId
|
|
160
|
+
handleInContext(next, driver, commandName, args, pluginArgs, isHub, sessionId) {
|
|
152
161
|
return __awaiter(this, void 0, void 0, function* () {
|
|
153
162
|
if (commandName === 'createSession' || commandName === 'deleteSession') {
|
|
154
163
|
try {
|
|
@@ -158,8 +167,6 @@ let CommandInterceptor = class CommandInterceptor {
|
|
|
158
167
|
if (commandName === 'deleteSession' && sessionId) {
|
|
159
168
|
typedi_1.Container.get(AutowaitService_1.AutowaitService).clearSession(sessionId);
|
|
160
169
|
}
|
|
161
|
-
if (span)
|
|
162
|
-
tracingService.endSpan(`${sessionId}:${commandName}`);
|
|
163
170
|
}
|
|
164
171
|
}
|
|
165
172
|
try {
|
|
@@ -181,7 +188,7 @@ let CommandInterceptor = class CommandInterceptor {
|
|
|
181
188
|
scriptArgs = {};
|
|
182
189
|
}
|
|
183
190
|
}
|
|
184
|
-
const aiCommand =
|
|
191
|
+
const aiCommand = (0, xenonScripts_1.interceptorScriptName)(script);
|
|
185
192
|
// appium-wait-plugin compatible alias — strip the `plugin:` prefix
|
|
186
193
|
// and map the old camelCase names so existing tests Just Work.
|
|
187
194
|
const legacyWaitCommand = script.replace(/^plugin\s*:\s*/, '').trim();
|
|
@@ -232,12 +239,7 @@ let CommandInterceptor = class CommandInterceptor {
|
|
|
232
239
|
: '';
|
|
233
240
|
return yield typedi_1.Container.get(AICommandService_1.AICommandService).assertVisualState(driver, instruction);
|
|
234
241
|
}
|
|
235
|
-
if (
|
|
236
|
-
aiCommand === 'removeMock' ||
|
|
237
|
-
aiCommand === 'clearMocks' ||
|
|
238
|
-
aiCommand === 'getRequests' ||
|
|
239
|
-
aiCommand === 'getMocks' ||
|
|
240
|
-
aiCommand === 'exportHar') {
|
|
242
|
+
if ((0, xenonScripts_1.isNetworkCaptureScript)(script)) {
|
|
241
243
|
const payload = typeof scriptArgs === 'object' && scriptArgs !== null ? scriptArgs : {};
|
|
242
244
|
const { InterceptorService } = yield Promise.resolve().then(() => __importStar(require('../services/InterceptorService')));
|
|
243
245
|
const interceptor = typedi_1.Container.get(InterceptorService);
|
|
@@ -385,10 +387,6 @@ let CommandInterceptor = class CommandInterceptor {
|
|
|
385
387
|
}
|
|
386
388
|
throw error;
|
|
387
389
|
}
|
|
388
|
-
finally {
|
|
389
|
-
if (isHub && sessionId && span)
|
|
390
|
-
tracingService.endSpan(`${sessionId}:${commandName}`);
|
|
391
|
-
}
|
|
392
390
|
});
|
|
393
391
|
}
|
|
394
392
|
warnUnreadableHealingTiers(driver, sessionId, unreadable) {
|
|
@@ -14,9 +14,26 @@
|
|
|
14
14
|
* - A name Xenon doesn't have fails with `unknown command`.
|
|
15
15
|
*/
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
-
exports.XENON_SCRIPT_NAMES = void 0;
|
|
17
|
+
exports.XENON_SCRIPT_NAMES = exports.NETWORK_CAPTURE_SCRIPTS = void 0;
|
|
18
|
+
exports.interceptorScriptName = interceptorScriptName;
|
|
19
|
+
exports.isNetworkCaptureScript = isNetworkCaptureScript;
|
|
18
20
|
exports.xenonScriptName = xenonScriptName;
|
|
19
21
|
exports.unknownXenonScriptMessage = unknownXenonScriptMessage;
|
|
22
|
+
/**
|
|
23
|
+
* The scripts CommandInterceptor answers from the session's network capture.
|
|
24
|
+
* Their arguments and answers are the capture (requests, HAR, mocks), which
|
|
25
|
+
* REST shows to admins only, so the command log keeps neither (commandLogFields).
|
|
26
|
+
* A new script that answers from the capture goes in this list. A hub hides
|
|
27
|
+
* by its own copy, so it needs the release that adds the script.
|
|
28
|
+
*/
|
|
29
|
+
exports.NETWORK_CAPTURE_SCRIPTS = [
|
|
30
|
+
'addMock',
|
|
31
|
+
'removeMock',
|
|
32
|
+
'clearMocks',
|
|
33
|
+
'getMocks',
|
|
34
|
+
'getRequests',
|
|
35
|
+
'exportHar',
|
|
36
|
+
];
|
|
20
37
|
/** The names CommandInterceptor and the session-details commands answer. Keep in step with both. */
|
|
21
38
|
exports.XENON_SCRIPT_NAMES = [
|
|
22
39
|
'setAutowaitProperties',
|
|
@@ -29,18 +46,22 @@ exports.XENON_SCRIPT_NAMES = [
|
|
|
29
46
|
'analyzeScreen',
|
|
30
47
|
'omniScan',
|
|
31
48
|
'assertVisualState',
|
|
32
|
-
|
|
33
|
-
'removeMock',
|
|
34
|
-
'clearMocks',
|
|
35
|
-
'getMocks',
|
|
36
|
-
'getRequests',
|
|
37
|
-
'exportHar',
|
|
49
|
+
...exports.NETWORK_CAPTURE_SCRIPTS,
|
|
38
50
|
'setSessionName',
|
|
39
51
|
'setSessionStatus',
|
|
40
52
|
'debug',
|
|
41
53
|
'addTag',
|
|
42
54
|
'captureEvidence',
|
|
43
55
|
];
|
|
56
|
+
/** The name CommandInterceptor routes a script by: its `xe:` / `xenon:` prefix, if any, taken off. */
|
|
57
|
+
function interceptorScriptName(script) {
|
|
58
|
+
return script.replace(/^(xe|xenon)\s*:\s*/, '').trim();
|
|
59
|
+
}
|
|
60
|
+
/** Whether CommandInterceptor answers `script` from the session's network capture. */
|
|
61
|
+
function isNetworkCaptureScript(script) {
|
|
62
|
+
return (typeof script === 'string' &&
|
|
63
|
+
exports.NETWORK_CAPTURE_SCRIPTS.includes(interceptorScriptName(script)));
|
|
64
|
+
}
|
|
44
65
|
/** The name in a `xenon: <name>` or `xe: <name>` script, or null for any other script. */
|
|
45
66
|
function xenonScriptName(script) {
|
|
46
67
|
if (typeof script !== 'string')
|
package/lib/src/logger.js
CHANGED
|
@@ -185,7 +185,9 @@ class XenonLogger {
|
|
|
185
185
|
}
|
|
186
186
|
if (redactedArgs.length)
|
|
187
187
|
logEntry.args = redactedArgs;
|
|
188
|
-
|
|
188
|
+
// At its own level, so --log-level filters it and an error reaches
|
|
189
|
+
// stderr, as in text mode.
|
|
190
|
+
this.baseLogger[level](JSON.stringify(logEntry));
|
|
189
191
|
}
|
|
190
192
|
else {
|
|
191
193
|
const ctxPrefix = this.buildTextPrefix(ctx);
|
package/lib/src/plugin.js
CHANGED
|
@@ -112,6 +112,14 @@ class XenonPlugin extends base_plugin_1.default {
|
|
|
112
112
|
const sessionId = driver.sessionId;
|
|
113
113
|
typedi_1.Container.get(LiveSessionOwners_1.LiveSessionOwners).forget(sessionId);
|
|
114
114
|
(0, sessionMemory_1.forgetSessionMemory)(sessionId);
|
|
115
|
+
// With the dashboard on or off: this was the only place a session span
|
|
116
|
+
// ended, and only with the dashboard on.
|
|
117
|
+
if (sessionId) {
|
|
118
|
+
typedi_1.Container.get(TracingService_1.TracingService).endSessionSpan(sessionId, {
|
|
119
|
+
failed: true,
|
|
120
|
+
reason: (0, shutdownReason_1.unexpectedShutdownReason)(cause),
|
|
121
|
+
});
|
|
122
|
+
}
|
|
115
123
|
if (sessionId)
|
|
116
124
|
yield typedi_1.Container.get(SessionMetricsService_1.SessionMetricsService).stop(sessionId);
|
|
117
125
|
// Appium's new-command timeout ends a session here, not in deleteSession:
|
|
@@ -160,9 +168,6 @@ class XenonPlugin extends base_plugin_1.default {
|
|
|
160
168
|
}
|
|
161
169
|
}
|
|
162
170
|
yield event_manager_1.DASHBORD_EVENT_MANAGER.onSessionStopped(sessionId, SessionStatus_1.SessionStatus.FAILED, reason);
|
|
163
|
-
typedi_1.Container.get(TracingService_1.TracingService).endSpan(sessionId, 'ERROR', {
|
|
164
|
-
'xenon.session.stop_reason': 'Unexpected shutdown',
|
|
165
|
-
});
|
|
166
171
|
}
|
|
167
172
|
});
|
|
168
173
|
}
|
|
@@ -93,9 +93,9 @@ function checkDatabase(opts) {
|
|
|
93
93
|
}
|
|
94
94
|
if (configured && configured !== client) {
|
|
95
95
|
return {
|
|
96
|
-
warning: `[Database] databaseProvider is "${configured}",
|
|
97
|
-
`
|
|
98
|
-
`
|
|
96
|
+
warning: `[Database] databaseProvider is "${configured}", which has no effect: this install ` +
|
|
97
|
+
`stores its data in ${clientLabel}, in ${where}, and the database itself decides how ` +
|
|
98
|
+
`its schema is brought up to date. Remove the setting, or set it to "${client}".`,
|
|
99
99
|
};
|
|
100
100
|
}
|
|
101
101
|
return {};
|
|
@@ -14,42 +14,44 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
14
14
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
15
|
const node_child_process_1 = require("node:child_process");
|
|
16
16
|
const config_1 = require("../config");
|
|
17
|
-
const prepare_prisma_1 = require("./prepare-prisma");
|
|
18
17
|
const logger_1 = __importDefault(require("../logger"));
|
|
19
|
-
const
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
18
|
+
const database_check_1 = require("./database-check");
|
|
19
|
+
const run_migrations_1 = require("./run-migrations");
|
|
20
|
+
/**
|
|
21
|
+
* `npm run db:migrate`: bring the database up to date, then regenerate the
|
|
22
|
+
* client.
|
|
23
|
+
*
|
|
24
|
+
* It checks the database URL and uses the rule the server uses at startup
|
|
25
|
+
* (database-check.ts, then run-migrations.ts): the database decides between
|
|
26
|
+
* `migrate deploy` and `db push`, so a database whose migration history
|
|
27
|
+
* matches its tables stays on `migrate deploy`. It runs whatever
|
|
28
|
+
* XENON_AUTO_MIGRATE says, since it is how you update the schema when that is
|
|
29
|
+
* off. Through 2.15.0 it always ran `db push`, and first rewrote
|
|
30
|
+
* prisma/schema.prisma's provider to `databaseProvider`. With `postgresql`,
|
|
31
|
+
* that left a PostgreSQL schema in the checkout that the SQLite file couldn't
|
|
32
|
+
* use.
|
|
33
|
+
*
|
|
34
|
+
* It first warns of changes to prisma/schema.prisma that no migration makes.
|
|
35
|
+
* `npm run db:generate` gives the developer's database a migration history, and
|
|
36
|
+
* from then on it is updated with `migrate deploy`, which never applies them,
|
|
37
|
+
* while the log said the schema was in sync.
|
|
38
|
+
*/
|
|
34
39
|
function main() {
|
|
35
40
|
return __awaiter(this, void 0, void 0, function* () {
|
|
36
|
-
|
|
37
|
-
//
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
logger_1.default.info('[DBInit] Syncing SQLite schema via db push...');
|
|
42
|
-
executeCmd('npx prisma db push --accept-data-loss --skip-generate');
|
|
43
|
-
}
|
|
44
|
-
else {
|
|
45
|
-
// For PostgreSQL, we might not have migrations checked in yet.
|
|
46
|
-
// In "Cellular Architecture", we use db push to ensure the schema is synced
|
|
47
|
-
// without requiring migration history sync across cells.
|
|
48
|
-
logger_1.default.info('[DBInit] Syncing PostgreSQL schema via db push...');
|
|
49
|
-
executeCmd('npx prisma db push --accept-data-loss');
|
|
50
|
-
}
|
|
41
|
+
// A PostgreSQL URL would otherwise reach the history read and fail there,
|
|
42
|
+
// under a message about the file.
|
|
43
|
+
(0, database_check_1.assertSupportedDatabase)();
|
|
44
|
+
(0, run_migrations_1.warnOfUnmigratedSchemaChanges)();
|
|
45
|
+
yield (0, run_migrations_1.syncDatabaseSchema)();
|
|
51
46
|
logger_1.default.info('[DBInit] Generating Prisma Client...');
|
|
52
|
-
|
|
47
|
+
(0, node_child_process_1.execSync)('npx prisma generate', {
|
|
48
|
+
env: Object.assign(Object.assign({}, process.env), { DATABASE_URL: config_1.config.databaseUrl }),
|
|
49
|
+
stdio: 'inherit',
|
|
50
|
+
});
|
|
53
51
|
});
|
|
54
52
|
}
|
|
55
|
-
(() =>
|
|
53
|
+
main().catch((err) => {
|
|
54
|
+
var _a;
|
|
55
|
+
logger_1.default.error(`[DBInit] ${(_a = err === null || err === void 0 ? void 0 : err.message) !== null && _a !== void 0 ? _a : err}`);
|
|
56
|
+
process.exit(1);
|
|
57
|
+
});
|