workerdeck 2.7.2 → 2.9.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 +13 -13
- package/build/cli.mjs +56 -29
- package/build/cli.mjs.map +1 -1
- package/build/{guard-CGPVzJ3Q.mjs → guard-C4ybpzbt.mjs} +5 -5
- package/build/guard-C4ybpzbt.mjs.map +1 -0
- package/build/hot-reload-CfP94v9Y.mjs +152 -0
- package/build/hot-reload-CfP94v9Y.mjs.map +1 -0
- package/build/index.d.mts +8 -4
- package/build/index.mjs +2 -2
- package/build/{instance-DP3af4H-.mjs → instance-vQe2VlGq.mjs} +38 -27
- package/build/instance-vQe2VlGq.mjs.map +1 -0
- package/build/reload-command-DAeUzBa1.mjs +74 -0
- package/build/reload-command-DAeUzBa1.mjs.map +1 -0
- package/package.json +8 -8
- package/build/guard-CGPVzJ3Q.mjs.map +0 -1
- package/build/instance-DP3af4H-.mjs.map +0 -1
|
@@ -393,7 +393,7 @@ async function loadApnsKey(keyFile) {
|
|
|
393
393
|
} catch (error) {
|
|
394
394
|
throw new Error(`apns: ${keyFile} is not a private key (${error instanceof Error ? error.message : String(error)})`, { cause: error });
|
|
395
395
|
}
|
|
396
|
-
if (key.asymmetricKeyType !== "ec") throw new Error(`apns: ${keyFile} is a ${key.asymmetricKeyType ?? "unknown"} key, not EC
|
|
396
|
+
if (key.asymmetricKeyType !== "ec") throw new Error(`apns: ${keyFile} is a ${key.asymmetricKeyType ?? "unknown"} key, not EC - an APNs auth key is the .p8 downloaded from Keys in the developer portal, not a certificate`);
|
|
397
397
|
return key;
|
|
398
398
|
}
|
|
399
399
|
function createProviderToken(key, keyId, teamId) {
|
|
@@ -834,10 +834,10 @@ const COLLAPSE_PREFIX = {
|
|
|
834
834
|
};
|
|
835
835
|
function titleFor(notification, name) {
|
|
836
836
|
switch (notification.type) {
|
|
837
|
-
case "permission_requested": return `Approval needed
|
|
838
|
-
case "turn_completed": return notification.result?.isError === true ? `Turn failed
|
|
839
|
-
case "session_error": return `Session error
|
|
840
|
-
case "session_closed": return `Session ended
|
|
837
|
+
case "permission_requested": return `Approval needed - ${name}`;
|
|
838
|
+
case "turn_completed": return notification.result?.isError === true ? `Turn failed - ${name}` : name;
|
|
839
|
+
case "session_error": return `Session error - ${name}`;
|
|
840
|
+
case "session_closed": return `Session ended - ${name}`;
|
|
841
841
|
default: return name;
|
|
842
842
|
}
|
|
843
843
|
}
|
|
@@ -1241,7 +1241,7 @@ async function materializeAuthKey(stateDir, options = {}) {
|
|
|
1241
1241
|
if (key !== null) {
|
|
1242
1242
|
try {
|
|
1243
1243
|
const { mode } = await stat(path);
|
|
1244
|
-
if ((mode & 63) !== 0) warn(`auth key file ${path} is readable by other users (mode ${(mode & 511).toString(8)})
|
|
1244
|
+
if ((mode & 63) !== 0) warn(`auth key file ${path} is readable by other users (mode ${(mode & 511).toString(8)}) - run: chmod 600 ${path}`);
|
|
1245
1245
|
} catch {}
|
|
1246
1246
|
return {
|
|
1247
1247
|
key,
|
|
@@ -1295,7 +1295,7 @@ async function createAuthSessionStore(options) {
|
|
|
1295
1295
|
initial = parseSessions(await readFile(path, "utf8"), now());
|
|
1296
1296
|
try {
|
|
1297
1297
|
const { mode } = await stat(path);
|
|
1298
|
-
if ((mode & 63) !== 0) warn(`session file ${path} is readable by other users (mode ${(mode & 511).toString(8)})
|
|
1298
|
+
if ((mode & 63) !== 0) warn(`session file ${path} is readable by other users (mode ${(mode & 511).toString(8)}) - run: chmod 600 ${path}`);
|
|
1299
1299
|
} catch {}
|
|
1300
1300
|
} catch {
|
|
1301
1301
|
initial = [];
|
|
@@ -1353,7 +1353,7 @@ function sha256(value) {
|
|
|
1353
1353
|
function createCliAuth(options = {}) {
|
|
1354
1354
|
const { secret } = options;
|
|
1355
1355
|
const enabled = secret !== void 0;
|
|
1356
|
-
if (secret !== void 0 && secret.length < MIN_SECRET_LENGTH) throw new Error(`createCliAuth: secret must be at least ${MIN_SECRET_LENGTH} characters
|
|
1356
|
+
if (secret !== void 0 && secret.length < MIN_SECRET_LENGTH) throw new Error(`createCliAuth: secret must be at least ${MIN_SECRET_LENGTH} characters - use a long random value, or leave it unset to run without auth on loopback`);
|
|
1357
1357
|
const cookieName = options.cookieName ?? DEFAULT_COOKIE_NAME;
|
|
1358
1358
|
const ttlMs = options.ttlMs ?? DEFAULT_TTL_MS;
|
|
1359
1359
|
if (!(ttlMs > 0)) throw new Error("createCliAuth: ttlMs must be positive");
|
|
@@ -1666,7 +1666,7 @@ var ConfigError = class extends Error {};
|
|
|
1666
1666
|
function parseDuration(raw, source) {
|
|
1667
1667
|
if (raw === "none" || raw === "never") return null;
|
|
1668
1668
|
const match = /^(\d+(?:\.\d+)?)(ms|s|m|h)?$/.exec(raw);
|
|
1669
|
-
if (!match) throw new ConfigError(`${source}: expected a duration like 300000, 30s, 5m
|
|
1669
|
+
if (!match) throw new ConfigError(`${source}: expected a duration like 300000, 30s, 5m - or 'none'; got: ${raw}`);
|
|
1670
1670
|
const scale = {
|
|
1671
1671
|
ms: 1,
|
|
1672
1672
|
s: 1e3,
|
|
@@ -1803,6 +1803,9 @@ function parseArgs(argv) {
|
|
|
1803
1803
|
case "--open":
|
|
1804
1804
|
flags.open = true;
|
|
1805
1805
|
break;
|
|
1806
|
+
case "--hot-reload":
|
|
1807
|
+
flags.hotReload = true;
|
|
1808
|
+
break;
|
|
1806
1809
|
default: throw new ConfigError(`unknown option: ${arg}`);
|
|
1807
1810
|
}
|
|
1808
1811
|
}
|
|
@@ -1866,7 +1869,7 @@ function normalizeInsecureHost(raw) {
|
|
|
1866
1869
|
} catch {
|
|
1867
1870
|
throw new ConfigError(`not a host name or address in insecureHosts: ${JSON.stringify(raw)}`);
|
|
1868
1871
|
}
|
|
1869
|
-
if (url.port !== "") throw new ConfigError(`insecureHosts entry ${JSON.stringify(raw)} carries a port
|
|
1872
|
+
if (url.port !== "") throw new ConfigError(`insecureHosts entry ${JSON.stringify(raw)} carries a port - name the host alone; the bind host and the Host header are both compared portless`);
|
|
1870
1873
|
return url.hostname.replace(/^\[|\]$/g, "").toLowerCase();
|
|
1871
1874
|
}
|
|
1872
1875
|
function resolveInstanceConfig(flags, loaded, env = process.env, cwd = process.cwd()) {
|
|
@@ -2071,11 +2074,9 @@ function lockCommand(pid) {
|
|
|
2071
2074
|
}
|
|
2072
2075
|
function driveWakeLock(source, lock) {
|
|
2073
2076
|
const sync = () => lock.set(sessionsNeedTheMachine(source.list()));
|
|
2074
|
-
source.observe((runner) => {
|
|
2075
|
-
|
|
2076
|
-
|
|
2077
|
-
}, runner.info().lastSeq);
|
|
2078
|
-
});
|
|
2077
|
+
source.observe((runner) => runner.subscribe((event) => {
|
|
2078
|
+
if (event.type === "status_changed" || event.type === "session_closed" || event.type === "session_error") sync();
|
|
2079
|
+
}, runner.info().lastSeq));
|
|
2079
2080
|
sync();
|
|
2080
2081
|
}
|
|
2081
2082
|
function createWakeLock(options = {}) {
|
|
@@ -2284,8 +2285,8 @@ async function startInstance(config, options = {}) {
|
|
|
2284
2285
|
...authOptions,
|
|
2285
2286
|
sessions
|
|
2286
2287
|
} : authOptions);
|
|
2287
|
-
if (config.allowedHosts === null && !config.hostAuthenticates && !auth.enabled) throw new Error("refusing to serve: the resolved config expects auth but no shared secret was materialized
|
|
2288
|
-
if (config.corsOrigins.length > 0 && !config.hostAuthenticates && !auth.enabled) throw new Error("refusing to serve: corsOrigins is set but this instance has no auth
|
|
2288
|
+
if (config.allowedHosts === null && !config.hostAuthenticates && !auth.enabled) throw new Error("refusing to serve: the resolved config expects auth but no shared secret was materialized - this instance would be open while believing itself authenticated");
|
|
2289
|
+
if (config.corsOrigins.length > 0 && !config.hostAuthenticates && !auth.enabled) throw new Error("refusing to serve: corsOrigins is set but this instance has no auth - a cross-origin page could drive it with no credential. Set --auth-key.");
|
|
2289
2290
|
const hostAllowed = createHostGuard(config.allowedHosts);
|
|
2290
2291
|
const authenticateHost = (req) => hostAllowed(req) ? auth.authenticate(req) : null;
|
|
2291
2292
|
const apns = config.apns === void 0 ? void 0 : await createApnsForwarder({
|
|
@@ -2335,7 +2336,16 @@ async function startInstance(config, options = {}) {
|
|
|
2335
2336
|
target: apns.activity
|
|
2336
2337
|
});
|
|
2337
2338
|
}
|
|
2338
|
-
const
|
|
2339
|
+
const adopted = [];
|
|
2340
|
+
for (const carried of options.carried ?? []) if (server.adoptSession(carried)) adopted.push(carried);
|
|
2341
|
+
let port;
|
|
2342
|
+
try {
|
|
2343
|
+
({port} = await server.listen(config.port, config.host));
|
|
2344
|
+
} catch (error) {
|
|
2345
|
+
for (const carried of adopted) server.releaseSession(carried.runner.id);
|
|
2346
|
+
await server.close();
|
|
2347
|
+
throw error;
|
|
2348
|
+
}
|
|
2339
2349
|
const displayHost = config.host === "0.0.0.0" || config.host === "::" ? "localhost" : config.host;
|
|
2340
2350
|
const url = `http://${displayHost.includes(":") ? `[${displayHost}]` : displayHost}:${port}`;
|
|
2341
2351
|
let resolveClosed = () => {};
|
|
@@ -2349,27 +2359,28 @@ async function startInstance(config, options = {}) {
|
|
|
2349
2359
|
if (config.hostAuthenticates) line(" auth: the config file supplies its own `authenticate`");
|
|
2350
2360
|
else if (generated?.source === "created") {
|
|
2351
2361
|
line(` auth: generated key ${generated.key}`);
|
|
2352
|
-
line(` stored in ${generated.path}
|
|
2362
|
+
line(` stored in ${generated.path} - later starts reuse it without printing it`);
|
|
2353
2363
|
} else if (generated?.source === "ephemeral") {
|
|
2354
2364
|
line(` auth: generated key ${generated.key}`);
|
|
2355
|
-
line(" ephemeral
|
|
2365
|
+
line(" ephemeral - no state dir to keep it, so the next start mints a new one");
|
|
2356
2366
|
} else if (generated?.source === "stored") line(` auth: shared key from ${generated.path}`);
|
|
2357
|
-
else if (auth.enabled) line(" auth: shared key
|
|
2358
|
-
else line(" NO AUTH
|
|
2359
|
-
if (!config.web) line(" dashboard: off
|
|
2360
|
-
if (!config.keepAwake) line(" keep-awake: off
|
|
2367
|
+
else if (auth.enabled) line(" auth: shared key - browsers sign in, services send a header");
|
|
2368
|
+
else line(" NO AUTH - anyone who can reach this port gets a session");
|
|
2369
|
+
if (!config.web) line(" dashboard: off - bare gateway, /v1 and /auth only");
|
|
2370
|
+
if (!config.keepAwake) line(" keep-awake: off - this machine may sleep mid-turn");
|
|
2361
2371
|
if (config.corsOrigins.length) line(` cors: ${config.corsOrigins.join(", ")} may call /v1 (still key-gated)`);
|
|
2362
|
-
line(config.stateDir ? ` parked sessions persist in ${join(config.stateDir, "parked")}` : " parked sessions are in memory only
|
|
2372
|
+
line(config.stateDir ? ` parked sessions persist in ${join(config.stateDir, "parked")}` : " parked sessions are in memory only - a restart drops them");
|
|
2363
2373
|
if (apns) {
|
|
2364
2374
|
const count = apns.deviceCount();
|
|
2365
2375
|
const cards = apns.activity.count();
|
|
2366
|
-
line(` push: APNs forwarder on ${config.apns?.topic}
|
|
2376
|
+
line(` push: APNs forwarder on ${config.apns?.topic} - ${count === 0 ? "no devices registered yet" : `${count} device(s)`}${cards === 0 ? "" : `, ${cards} live card(s)`}`);
|
|
2367
2377
|
}
|
|
2368
2378
|
if (config.configPath) line(` config ${config.configPath}`);
|
|
2369
2379
|
line("");
|
|
2370
2380
|
}
|
|
2371
2381
|
return {
|
|
2372
2382
|
server,
|
|
2383
|
+
adopted: adopted.map((carried) => carried.runner.id),
|
|
2373
2384
|
url,
|
|
2374
2385
|
port,
|
|
2375
2386
|
closed,
|
|
@@ -2389,4 +2400,4 @@ async function startInstance(config, options = {}) {
|
|
|
2389
2400
|
//#endregion
|
|
2390
2401
|
export { createActivityRegistry as C, createDeviceRoute as S, createApnsForwarder as _, ConfigError as a, createApnsRoute as b, isLoopback as c, parseArgs as d, resolveInstanceConfig as f, buildPush as g, materializeAuthKey as h, renderLoginPage as i, isLoopbackHostname as l, createAuthSessionStore as m, resolveWebRoot as n, defaultStateDir as o, createCliAuth as p, startInstance as r, hostnameOf as s, createHostGuard as t, loadConfigFile as u, createApnsClient as v, createActivityRoute as w, createDeviceRegistry as x, loadApnsKey as y };
|
|
2391
2402
|
|
|
2392
|
-
//# sourceMappingURL=instance-
|
|
2403
|
+
//# sourceMappingURL=instance-vQe2VlGq.mjs.map
|