@rubytech/create-maxy 1.0.782 → 1.0.784
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/package.json
CHANGED
|
@@ -39,6 +39,10 @@ const RESULT_FILE = args["result-file"] || "/tmp/wifi-provision-result";
|
|
|
39
39
|
const BRAND_JSON = args["brand-json"] || "";
|
|
40
40
|
const HOSTNAME = args.hostname || "maxy";
|
|
41
41
|
const PORTAL_HOST = args["portal-host"] || "";
|
|
42
|
+
// Brand service port (e.g. 19200). Distinct from PORT, which is the
|
|
43
|
+
// captive portal's own listen port (always 80). Used only to render the
|
|
44
|
+
// post-connect URL.
|
|
45
|
+
const DEVICE_PORT = parseInt(args["device-port"] || "19200", 10);
|
|
42
46
|
|
|
43
47
|
// ── Load brand config ─────────────────────────────────────────────────
|
|
44
48
|
// All visual surfaces (colour, font, logo) come from brand.json so the
|
|
@@ -243,9 +247,11 @@ function portalHTML() {
|
|
|
243
247
|
}
|
|
244
248
|
.address-box a {
|
|
245
249
|
color: ${colors.primary};
|
|
246
|
-
text-decoration:
|
|
250
|
+
text-decoration: underline;
|
|
247
251
|
font-size: 16px;
|
|
248
252
|
font-weight: 600;
|
|
253
|
+
display: block;
|
|
254
|
+
-webkit-tap-highlight-color: ${colors.primary};
|
|
249
255
|
}
|
|
250
256
|
.hint { color: #888; font-size: 13px; margin-top: 12px; line-height: 1.5; }
|
|
251
257
|
</style>
|
|
@@ -285,13 +291,13 @@ function portalHTML() {
|
|
|
285
291
|
<div class="card" style="padding:32px 16px">
|
|
286
292
|
<div class="success-icon">✓</div>
|
|
287
293
|
<h1>Connected!</h1>
|
|
288
|
-
<p class="hint">${escapedBrandName} is now online. Redirecting in <span id="redirect-countdown">
|
|
294
|
+
<p class="hint">${escapedBrandName} is now online. Redirecting in <span id="redirect-countdown">15</span>s…</p>
|
|
289
295
|
<div class="address-box">
|
|
290
|
-
<a id="device-link" href="#"
|
|
296
|
+
<a id="device-link" href="#"></a>
|
|
291
297
|
</div>
|
|
292
|
-
<p class="hint" id="
|
|
293
|
-
<div class="address-box" id="
|
|
294
|
-
<
|
|
298
|
+
<p class="hint" id="manual-hint" style="display:none">If your phone doesn't redirect automatically, open this in your normal browser:</p>
|
|
299
|
+
<div class="address-box" id="manual-box" style="display:none">
|
|
300
|
+
<span id="device-link-text" style="user-select:all"></span>
|
|
295
301
|
</div>
|
|
296
302
|
<p class="hint">This access point will close shortly.<br>Your phone will reconnect to your WiFi automatically.</p>
|
|
297
303
|
</div>
|
|
@@ -301,7 +307,10 @@ function portalHTML() {
|
|
|
301
307
|
(function() {
|
|
302
308
|
"use strict";
|
|
303
309
|
var selectedSSID = "";
|
|
304
|
-
|
|
310
|
+
// The brand service port (19200, configurable via --port), NOT the
|
|
311
|
+
// captive portal port (always 80). devicePort is appended to the
|
|
312
|
+
// post-connect URL so the link points at the admin server.
|
|
313
|
+
var devicePort = ${DEVICE_PORT === 80 ? '""' : JSON.stringify(":" + DEVICE_PORT)};
|
|
305
314
|
var deviceHostname = ${JSON.stringify(HOSTNAME)};
|
|
306
315
|
|
|
307
316
|
// Safe text insertion — no innerHTML for user-controlled content
|
|
@@ -410,37 +419,44 @@ function portalHTML() {
|
|
|
410
419
|
? "http://" + data.hostname + ".local" + devicePort
|
|
411
420
|
: null;
|
|
412
421
|
var ipAddr = data.ip ? "http://" + data.ip + devicePort : null;
|
|
413
|
-
//
|
|
414
|
-
//
|
|
415
|
-
//
|
|
416
|
-
//
|
|
417
|
-
var displayAddr = hostnameAddr || ipAddr;
|
|
422
|
+
// Auto-navigate target: prefer the IP because mDNS .local resolution
|
|
423
|
+
// is flaky on Android (notably Brave) and the redirect dead-ends.
|
|
424
|
+
// The displayed link uses the same URL so what the user sees is what
|
|
425
|
+
// they get if they tap.
|
|
418
426
|
var redirectAddr = ipAddr || hostnameAddr;
|
|
419
427
|
var link = document.getElementById("device-link");
|
|
420
|
-
link.href =
|
|
421
|
-
link.textContent =
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
+
link.href = redirectAddr;
|
|
429
|
+
link.textContent = redirectAddr;
|
|
430
|
+
// Always surface a manual fallback line — captive webviews on some
|
|
431
|
+
// phone OSes silently swallow JS navigation, and the user needs to
|
|
432
|
+
// be able to copy-paste the URL into a real browser.
|
|
433
|
+
var manualText = document.getElementById("device-link-text");
|
|
434
|
+
if (manualText) {
|
|
435
|
+
manualText.textContent = redirectAddr;
|
|
436
|
+
document.getElementById("manual-hint").style.display = "block";
|
|
437
|
+
document.getElementById("manual-box").style.display = "block";
|
|
428
438
|
}
|
|
429
439
|
showScreen("success-screen");
|
|
430
|
-
//
|
|
431
|
-
// success result
|
|
432
|
-
// phone then needs ~5s to drop the AP SSID and
|
|
433
|
-
|
|
434
|
-
// when the phone is back on its home network and the device is
|
|
435
|
-
// routable on its new IP.
|
|
436
|
-
var remaining = 20;
|
|
440
|
+
// 15s countdown: the Pi keeps the AP up for ~10s after writing the
|
|
441
|
+
// success result so this poll can land, then tears it down; the
|
|
442
|
+
// phone then needs ~5s to drop the AP SSID and rejoin home WiFi.
|
|
443
|
+
var remaining = 15;
|
|
437
444
|
var countdownEl = document.getElementById("redirect-countdown");
|
|
438
445
|
var ticker = setInterval(function() {
|
|
439
446
|
remaining -= 1;
|
|
440
447
|
if (countdownEl) countdownEl.textContent = String(remaining);
|
|
441
448
|
if (remaining <= 0) {
|
|
442
449
|
clearInterval(ticker);
|
|
443
|
-
|
|
450
|
+
// Try multiple navigation primitives — captive webviews on some
|
|
451
|
+
// platforms ignore one but accept another.
|
|
452
|
+
try { window.location.replace(redirectAddr); } catch(e) {}
|
|
453
|
+
try { window.location.href = redirectAddr; } catch(e) {}
|
|
454
|
+
// Last-resort: synthesise a click on a freshly-built anchor.
|
|
455
|
+
try {
|
|
456
|
+
var a = document.createElement("a");
|
|
457
|
+
a.href = redirectAddr; a.rel = "noopener";
|
|
458
|
+
document.body.appendChild(a); a.click();
|
|
459
|
+
} catch(e) {}
|
|
444
460
|
}
|
|
445
461
|
}, 1000);
|
|
446
462
|
}
|
|
@@ -60,6 +60,24 @@ LOG_FILE="${LOG_DIR}/wifi-provision.log"
|
|
|
60
60
|
|
|
61
61
|
mkdir -p "$LOG_DIR"
|
|
62
62
|
|
|
63
|
+
# Resolve the brand service's public port so the captive portal can render
|
|
64
|
+
# the post-connect URL with the correct port (the captive portal itself
|
|
65
|
+
# runs on :80, but the device's admin URL is on the brand port). Mirrors
|
|
66
|
+
# the same precedence as the installer: ~/{configDir}/.env override, then
|
|
67
|
+
# the systemd unit's Environment=PORT, then the documented default.
|
|
68
|
+
BRAND_PORT="19200"
|
|
69
|
+
if [ -f "${MAXY_DIR}/.env" ]; then
|
|
70
|
+
_p=$(grep -E '^PORT=' "${MAXY_DIR}/.env" 2>/dev/null | tail -1 | cut -d= -f2 | tr -d '"' | tr -d "'")
|
|
71
|
+
[ -n "$_p" ] && BRAND_PORT="$_p"
|
|
72
|
+
fi
|
|
73
|
+
if [ "$BRAND_PORT" = "19200" ]; then
|
|
74
|
+
_svc="${INSTALL_HOME}/.config/systemd/user/${HOSTNAME_NAME}.service"
|
|
75
|
+
if [ -f "$_svc" ]; then
|
|
76
|
+
_p=$(grep -E '^Environment=PORT=' "$_svc" 2>/dev/null | tail -1 | cut -d= -f3)
|
|
77
|
+
[ -n "$_p" ] && BRAND_PORT="$_p"
|
|
78
|
+
fi
|
|
79
|
+
fi
|
|
80
|
+
|
|
63
81
|
# ── Derived constants ────────────────────────────────────────────────
|
|
64
82
|
# SSID: lowercase the product name and replace spaces with hyphens — gives
|
|
65
83
|
# `maxy`, `real-agent`, etc. (kebab-case, no "-Setup" suffix). The user's
|
|
@@ -290,6 +308,7 @@ DNSMASQ_EOF
|
|
|
290
308
|
--brand-json "$BRAND_JSON" \
|
|
291
309
|
--hostname "$HOSTNAME_NAME" \
|
|
292
310
|
--portal-host "$PORTAL_HOST" \
|
|
311
|
+
--device-port "$BRAND_PORT" \
|
|
293
312
|
>> "$LOG_FILE" 2>&1 &
|
|
294
313
|
HTTP_SERVER_PID=$!
|
|
295
314
|
sleep 1
|