@songsid/agend 2.3.3-beta.9 → 2.3.4-beta.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 +3 -3
- package/README.zh-TW.md +3 -3
- package/dist/agent-cli-instructions.md +1 -1
- package/dist/auth-api.d.ts +16 -3
- package/dist/auth-api.js +22 -6
- package/dist/auth-api.js.map +1 -1
- package/dist/authority/web-authority.d.ts +15 -1
- package/dist/authority/web-authority.js +27 -10
- package/dist/authority/web-authority.js.map +1 -1
- package/dist/backend/claude-code.js +11 -1
- package/dist/backend/claude-code.js.map +1 -1
- package/dist/backend/codex.js +12 -0
- package/dist/backend/codex.js.map +1 -1
- package/dist/backend/types.d.ts +7 -0
- package/dist/backend/types.js.map +1 -1
- package/dist/config-validator.js +18 -1
- package/dist/config-validator.js.map +1 -1
- package/dist/daemon.js +8 -1
- package/dist/daemon.js.map +1 -1
- package/dist/env-file.d.ts +2 -0
- package/dist/env-file.js +13 -8
- package/dist/env-file.js.map +1 -1
- package/dist/fleet-manager.d.ts +41 -1
- package/dist/fleet-manager.js +179 -22
- package/dist/fleet-manager.js.map +1 -1
- package/dist/general-knowledge/skills/cross-instance-messaging/SKILL.md +1 -1
- package/dist/general-knowledge/skills/web-dashboard/SKILL.md +4 -0
- package/dist/general-knowledge/skills/worker-collaboration/SKILL.md +1 -1
- package/dist/instance-config-impact.js +1 -0
- package/dist/instance-config-impact.js.map +1 -1
- package/dist/instance-lifecycle.d.ts +2 -0
- package/dist/instance-lifecycle.js +23 -7
- package/dist/instance-lifecycle.js.map +1 -1
- package/dist/instructions.d.ts +1 -1
- package/dist/instructions.js +1 -1
- package/dist/instructions.js.map +1 -1
- package/dist/interaction-observation.d.ts +1 -0
- package/dist/interaction-observation.js +1 -1
- package/dist/interaction-observation.js.map +1 -1
- package/dist/locale.js +56 -2
- package/dist/locale.js.map +1 -1
- package/dist/next-steps.d.ts +12 -2
- package/dist/next-steps.js +19 -3
- package/dist/next-steps.js.map +1 -1
- package/dist/office-share-service.d.ts +57 -0
- package/dist/office-share-service.js +76 -11
- package/dist/office-share-service.js.map +1 -1
- package/dist/office-share.d.ts +8 -0
- package/dist/office-share.js +34 -0
- package/dist/office-share.js.map +1 -1
- package/dist/outbound-schemas.js +1 -1
- package/dist/outbound-schemas.js.map +1 -1
- package/dist/page-share.d.ts +122 -0
- package/dist/page-share.js +199 -0
- package/dist/page-share.js.map +1 -0
- package/dist/public-link-progress.d.ts +5 -2
- package/dist/public-link-progress.js +4 -3
- package/dist/public-link-progress.js.map +1 -1
- package/dist/public-preview.d.ts +4 -0
- package/dist/public-preview.js +5 -4
- package/dist/public-preview.js.map +1 -1
- package/dist/public-web-gateway.js +5 -0
- package/dist/public-web-gateway.js.map +1 -1
- package/dist/public-web-link.d.ts +10 -0
- package/dist/public-web-link.js +24 -5
- package/dist/public-web-link.js.map +1 -1
- package/dist/quickstart-api.d.ts +5 -0
- package/dist/quickstart-api.js +1 -1
- package/dist/quickstart-api.js.map +1 -1
- package/dist/quickstart.d.ts +40 -0
- package/dist/quickstart.js +174 -28
- package/dist/quickstart.js.map +1 -1
- package/dist/remote-card-answer.js +2 -0
- package/dist/remote-card-answer.js.map +1 -1
- package/dist/remote-card-prompt.js +4 -2
- package/dist/remote-card-prompt.js.map +1 -1
- package/dist/selection-card.d.ts +21 -0
- package/dist/selection-card.js +129 -0
- package/dist/selection-card.js.map +1 -0
- package/dist/settings-api.d.ts +10 -0
- package/dist/settings-api.js +45 -0
- package/dist/settings-api.js.map +1 -1
- package/dist/settings-change.js +5 -0
- package/dist/settings-change.js.map +1 -1
- package/dist/settings-effect.js +2 -0
- package/dist/settings-effect.js.map +1 -1
- package/dist/setup-host.js +2 -2
- package/dist/setup-host.js.map +1 -1
- package/dist/setup-wizard.js +2 -2
- package/dist/setup-wizard.js.map +1 -1
- package/dist/tunnel/cloudflared.d.ts +5 -0
- package/dist/tunnel/cloudflared.js +32 -1
- package/dist/tunnel/cloudflared.js.map +1 -1
- package/dist/tunnel/named-diagnostics.d.ts +2 -1
- package/dist/tunnel/named-diagnostics.js +4 -1
- package/dist/tunnel/named-diagnostics.js.map +1 -1
- package/dist/tunnel/named-link-test.d.ts +90 -0
- package/dist/tunnel/named-link-test.js +270 -0
- package/dist/tunnel/named-link-test.js.map +1 -0
- package/dist/tunnel/purpose-lane.d.ts +3 -1
- package/dist/tunnel/purpose-lane.js +2 -0
- package/dist/tunnel/purpose-lane.js.map +1 -1
- package/dist/types.d.ts +10 -0
- package/dist/ui/chat-store.js +8 -1
- package/dist/ui/chat-strings.js +36 -0
- package/dist/ui/page-share-dialog.js +191 -0
- package/dist/ui/panel-chat.js +14 -0
- package/dist/ui/panel-notices.js +98 -0
- package/dist/ui/panel-settings.js +14 -5
- package/dist/ui/preview-pages.js +41 -0
- package/dist/ui/preview-panel-actions.js +161 -0
- package/dist/ui/preview-panel.js +209 -28
- package/dist/ui/preview-versions.js +155 -0
- package/dist/ui/preview.js +88 -3
- package/dist/ui/settings-named-test.js +144 -0
- package/dist/ui/settings-registry.js +1 -0
- package/dist/ui/settings-strings.js +10 -6
- package/dist/ui/shared/app-i18n.js +2 -2
- package/dist/ui/shared/app-route.js +4 -0
- package/dist/ui/shared/app-shell.js +5 -3
- package/dist/ui/shared/app-store.js +71 -1
- package/dist/ui/shared/app-stream.js +1 -1
- package/dist/ui/shared/app.css +50 -1
- package/dist/ui/shared/app.js +22 -1
- package/dist/ui/shared/signin.js +12 -1
- package/dist/ui/shared/ui-icons.js +3 -0
- package/dist/ui/shared/web-authorize.js +5 -3
- package/dist/web-api.d.ts +26 -0
- package/dist/web-api.js +180 -1
- package/dist/web-api.js.map +1 -1
- package/dist/web-auth.js +7 -1
- package/dist/web-auth.js.map +1 -1
- package/dist/web-login.d.ts +2 -0
- package/dist/web-login.js +3 -1
- package/dist/web-login.js.map +1 -1
- package/dist/web-notices.d.ts +51 -0
- package/dist/web-notices.js +118 -0
- package/dist/web-notices.js.map +1 -0
- package/dist/web-only-fleet.d.ts +22 -0
- package/dist/web-only-fleet.js +13 -0
- package/dist/web-only-fleet.js.map +1 -0
- package/dist/web-preview.d.ts +32 -3
- package/dist/web-preview.js +52 -19
- package/dist/web-preview.js.map +1 -1
- package/dist/web-session.d.ts +7 -0
- package/dist/web-session.js +2 -0
- package/dist/web-session.js.map +1 -1
- package/dist/web-settings-patch.d.ts +3 -1
- package/dist/web-settings-patch.js +4 -1
- package/dist/web-settings-patch.js.map +1 -1
- package/dist/web-shell-routes.d.ts +2 -0
- package/dist/web-shell-routes.js +3 -0
- package/dist/web-shell-routes.js.map +1 -1
- package/package.json +1 -1
|
@@ -3,7 +3,8 @@ export declare const NAMED_TUNNEL_FAILURE_MESSAGES: {
|
|
|
3
3
|
readonly "named-route-missing": "The named hostname did not reach a published application; check this tunnel's hostname, DNS and published application route.";
|
|
4
4
|
readonly "named-hostname-mismatch": "The named hostname answered with a different page; check that its published application points to AgEnD's origin URL.";
|
|
5
5
|
readonly "named-origin-unreachable": "Cloudflare could not reach the local origin; check the published application's origin URL and port.";
|
|
6
|
-
readonly "named-connection-failed": "The named tunnel could not connect to Cloudflare; check network
|
|
6
|
+
readonly "named-connection-failed": "The named tunnel could not connect to Cloudflare; check that this machine's network allows outbound connections to Cloudflare, or try protocol http2.";
|
|
7
|
+
readonly "named-self-unreachable": "The named tunnel is connected to Cloudflare, but this machine could not open its own address; this machine's network may block the hostname or its DNS.";
|
|
7
8
|
};
|
|
8
9
|
export type NamedTunnelFailureKind = keyof typeof NAMED_TUNNEL_FAILURE_MESSAGES;
|
|
9
10
|
export declare function namedTunnelFailureMessage(kind: string): string | undefined;
|
|
@@ -5,7 +5,10 @@ export const NAMED_TUNNEL_FAILURE_MESSAGES = {
|
|
|
5
5
|
"named-route-missing": "The named hostname did not reach a published application; check this tunnel's hostname, DNS and published application route.",
|
|
6
6
|
"named-hostname-mismatch": "The named hostname answered with a different page; check that its published application points to AgEnD's origin URL.",
|
|
7
7
|
"named-origin-unreachable": "Cloudflare could not reach the local origin; check the published application's origin URL and port.",
|
|
8
|
-
"named-connection-failed": "The named tunnel could not connect to Cloudflare; check network
|
|
8
|
+
"named-connection-failed": "The named tunnel could not connect to Cloudflare; check that this machine's network allows outbound connections to Cloudflare, or try protocol http2.",
|
|
9
|
+
// The connector registered, but this machine's own HTTPS request to the hostname was reset or timed out: the tunnel
|
|
10
|
+
// is up; this machine's network does not open its own address (from elsewhere it may work).
|
|
11
|
+
"named-self-unreachable": "The named tunnel is connected to Cloudflare, but this machine could not open its own address; this machine's network may block the hostname or its DNS.",
|
|
9
12
|
};
|
|
10
13
|
export function namedTunnelFailureMessage(kind) {
|
|
11
14
|
return Object.hasOwn(NAMED_TUNNEL_FAILURE_MESSAGES, kind) ? NAMED_TUNNEL_FAILURE_MESSAGES[kind] : undefined;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"named-diagnostics.js","sourceRoot":"","sources":["../../src/tunnel/named-diagnostics.ts"],"names":[],"mappings":"AAAA,4FAA4F;AAC5F,OAAO,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AAE/D,MAAM,CAAC,MAAM,6BAA6B,GAAG;IAC3C,mBAAmB,EAAE,wGAAwG;IAC7H,qBAAqB,EAAE,8HAA8H;IACrJ,yBAAyB,EAAE,uHAAuH;IAClJ,0BAA0B,EAAE,qGAAqG;IACjI,yBAAyB,EAAE,
|
|
1
|
+
{"version":3,"file":"named-diagnostics.js","sourceRoot":"","sources":["../../src/tunnel/named-diagnostics.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { type CloudflaredOptions, type CloudflaredProtocol } from "./cloudflared.js";
|
|
2
|
+
import { type ProbeResponse } from "./public-fetch.js";
|
|
3
|
+
import type { TunnelPurposeLane } from "./purpose-lane.js";
|
|
4
|
+
import type { TunnelProvider } from "./types.js";
|
|
5
|
+
export type NamedTestStep = "values" | "origin" | "tunnel" | "dns" | "reach";
|
|
6
|
+
export declare const NAMED_TEST_STEPS: readonly NamedTestStep[];
|
|
7
|
+
/** What each step found; the page words each one (and what to do next) in the person's language. */
|
|
8
|
+
export type NamedTestCode = "ok" | "live" | "timeout" | "cancelled" | "bad-hostname" | "bad-port" | "no-token" | "bad-token" | "dashboard-port" | "port-in-use" | "origin-failed" | "link-open-other" | "tunnel-busy" | "auth" | "network" | "stopped" | "no-binary" | "dns-missing" | "dns-failed" | "wrong-service" | "other-page" | "route-missing" | "self-unreachable" | "reach-failed";
|
|
9
|
+
export interface NamedTestStepResult {
|
|
10
|
+
step: NamedTestStep;
|
|
11
|
+
ok: boolean;
|
|
12
|
+
code: NamedTestCode;
|
|
13
|
+
}
|
|
14
|
+
export interface NamedTestResult {
|
|
15
|
+
steps: NamedTestStepResult[];
|
|
16
|
+
hostname: string | null;
|
|
17
|
+
port: number | null;
|
|
18
|
+
/** The test connector's stop could not be proven: it may still run (the lane stays held until it is resolved). */
|
|
19
|
+
cleanup?: "unconfirmed";
|
|
20
|
+
}
|
|
21
|
+
export interface NamedTestInput {
|
|
22
|
+
hostname: unknown;
|
|
23
|
+
port: unknown;
|
|
24
|
+
protocol: unknown;
|
|
25
|
+
token: string | null | undefined;
|
|
26
|
+
}
|
|
27
|
+
export declare const NAMED_TEST_REGISTER_MS = 20000;
|
|
28
|
+
export declare const NAMED_TEST_REACH_MS = 20000;
|
|
29
|
+
/** The whole test before cleanup, whatever happens. */
|
|
30
|
+
export declare const NAMED_TEST_HARD_MS = 60000;
|
|
31
|
+
/** Cleanup's own allowance after the deadline: the managed stop (TERM, proof, KILL, proof) and closing the stand-in. */
|
|
32
|
+
export declare const NAMED_TEST_CLEANUP_MS = 15000;
|
|
33
|
+
/** The test connector's lane: started through the managed tunnel, given back only on a proven stop. */
|
|
34
|
+
export interface NamedTestLane {
|
|
35
|
+
start(input: {
|
|
36
|
+
binary: string;
|
|
37
|
+
hostname: string;
|
|
38
|
+
token: string;
|
|
39
|
+
protocol: CloudflaredProtocol;
|
|
40
|
+
origin: URL;
|
|
41
|
+
signal: AbortSignal;
|
|
42
|
+
}): Promise<{
|
|
43
|
+
ok: true;
|
|
44
|
+
} | {
|
|
45
|
+
ok: false;
|
|
46
|
+
kind: string;
|
|
47
|
+
}>;
|
|
48
|
+
stop(): Promise<{
|
|
49
|
+
confirmed: boolean;
|
|
50
|
+
}>;
|
|
51
|
+
/** Nothing was started: give the lane back. */
|
|
52
|
+
releaseUnused(): void;
|
|
53
|
+
}
|
|
54
|
+
export interface NamedLinkTestDeps {
|
|
55
|
+
/** The dashboard's own port: never the tunnel's origin. */
|
|
56
|
+
healthPort: number;
|
|
57
|
+
/** The bundled cloudflared's path (may fetch the pinned copy). */
|
|
58
|
+
ensureBinary(signal: AbortSignal): Promise<string>;
|
|
59
|
+
/** The open link on exactly these values: its page's readiness marker. Null: none (or other values). */
|
|
60
|
+
liveMarker(values: {
|
|
61
|
+
hostname: string;
|
|
62
|
+
port: number;
|
|
63
|
+
token: string;
|
|
64
|
+
protocol: CloudflaredProtocol;
|
|
65
|
+
}): string | null;
|
|
66
|
+
/** Holds the one tunnel lane for the test, or says who holds it. */
|
|
67
|
+
reserve(): NamedTestLane | {
|
|
68
|
+
busy: "link-open" | "other";
|
|
69
|
+
};
|
|
70
|
+
/** The admin who asked is still signed in (checked before anything is started). */
|
|
71
|
+
current?(): boolean;
|
|
72
|
+
/** Test seams. */
|
|
73
|
+
resolve4?: (host: string) => Promise<string[]>;
|
|
74
|
+
systemLookup?: (host: string) => Promise<unknown>;
|
|
75
|
+
fetchPage?: (url: string, signal: AbortSignal) => Promise<ProbeResponse>;
|
|
76
|
+
bindHost?: string;
|
|
77
|
+
hardMs?: number;
|
|
78
|
+
cleanupMs?: number;
|
|
79
|
+
reachMs?: number;
|
|
80
|
+
retryMs?: number;
|
|
81
|
+
}
|
|
82
|
+
export declare function runNamedLinkTest(input: NamedTestInput, deps: NamedLinkTestDeps, outer?: AbortSignal): Promise<NamedTestResult>;
|
|
83
|
+
/**
|
|
84
|
+
* The production lane: the one tunnel lane's reservation, the connector started by its managed start (lease, proven
|
|
85
|
+
* stop) as a CloudflaredProvider that is ready once registered. `provider` is a test seam.
|
|
86
|
+
*/
|
|
87
|
+
export declare function namedTestLane(lane: TunnelPurposeLane, opts?: {
|
|
88
|
+
registerMs?: number;
|
|
89
|
+
provider?: (o: CloudflaredOptions) => TunnelProvider;
|
|
90
|
+
}): NamedLinkTestDeps["reserve"];
|
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The fixed-address "Test connection" (Settings → Access; the user, 2026-11-01): checks the named-tunnel values as
|
|
3
|
+
* filled in, step by step, and says for each ✗ what the person can do next.
|
|
4
|
+
*
|
|
5
|
+
* ① values the hostname, the origin port and the connector token are well-formed
|
|
6
|
+
* ② origin a stand-in answers on 127.0.0.1:<port> for this test (what Cloudflare's route must point to)
|
|
7
|
+
* ③ tunnel a test connector (the bundled cloudflared, the token in its environment) registers with Cloudflare
|
|
8
|
+
* ④ dns the hostname resolves through a public resolver
|
|
9
|
+
* ⑤ reach an HTTPS request to the hostname comes back with this test's nonce (so it reached THIS AgEnD)
|
|
10
|
+
*
|
|
11
|
+
* With the admin's link already open on exactly these values (protocol included), nothing is started: ② and ③ are
|
|
12
|
+
* the open link's own, and ⑤ looks for its page's readiness marker instead (the open link is never stopped, replaced
|
|
13
|
+
* or shared).
|
|
14
|
+
*
|
|
15
|
+
* #2907 review: the connector is started through the one tunnel lane's managed start (the lease a crash leaves
|
|
16
|
+
* recoverable, a stop proven by the process's fingerprint); the lane is given back only on a confirmed stop — an
|
|
17
|
+
* unproven one is reported (`cleanup: "unconfirmed"`) and the lane stays held. Every stage races the hard deadline,
|
|
18
|
+
* and nothing is started once it (or the admin's session) is gone. Only closed step codes leave this module: the
|
|
19
|
+
* token goes into the connector's environment, never argv, and its output is read for a closed classification only.
|
|
20
|
+
*/
|
|
21
|
+
import { createServer } from "node:http";
|
|
22
|
+
import { randomBytes } from "node:crypto";
|
|
23
|
+
import { lookup, Resolver } from "node:dns/promises";
|
|
24
|
+
import { publicTunnelHostname, normalizePublicTunnelToken } from "../public-tunnel-config.js";
|
|
25
|
+
import { CloudflaredProvider } from "./cloudflared.js";
|
|
26
|
+
import { classifyNamedTunnelProbeError } from "./named-diagnostics.js";
|
|
27
|
+
import { fetchViaPublicResolver, fetchViaSystemResolver, isPublicIPv4, PUBLIC_RESOLVERS } from "./public-fetch.js";
|
|
28
|
+
export const NAMED_TEST_STEPS = ["values", "origin", "tunnel", "dns", "reach"];
|
|
29
|
+
/** Cloudflare's own "no connector / origin unreachable" answers (502 Bad gateway, 503, 530 incl. error 1033). */
|
|
30
|
+
const WRONG_SERVICE_STATUSES = new Set([502, 503, 504, 530]);
|
|
31
|
+
export const NAMED_TEST_REGISTER_MS = 20_000;
|
|
32
|
+
export const NAMED_TEST_REACH_MS = 20_000;
|
|
33
|
+
/** The whole test before cleanup, whatever happens. */
|
|
34
|
+
export const NAMED_TEST_HARD_MS = 60_000;
|
|
35
|
+
/** Cleanup's own allowance after the deadline: the managed stop (TERM, proof, KILL, proof) and closing the stand-in. */
|
|
36
|
+
export const NAMED_TEST_CLEANUP_MS = 15_000;
|
|
37
|
+
const DEADLINE = Symbol("deadline");
|
|
38
|
+
/** A step that threw (not a closed answer): its own closed failure. */
|
|
39
|
+
const UNEXPECTED = { values: "bad-token", origin: "origin-failed", tunnel: "stopped", dns: "dns-failed", reach: "reach-failed" };
|
|
40
|
+
/** `p`, unless the signal fires first (then DEADLINE); `p` itself is left to settle on its own. */
|
|
41
|
+
function within(p, signal) {
|
|
42
|
+
if (signal.aborted) {
|
|
43
|
+
p.catch(() => { });
|
|
44
|
+
return Promise.reject(DEADLINE);
|
|
45
|
+
}
|
|
46
|
+
return new Promise((resolve, reject) => {
|
|
47
|
+
const stop = () => reject(DEADLINE);
|
|
48
|
+
signal.addEventListener("abort", stop, { once: true });
|
|
49
|
+
p.then(v => { signal.removeEventListener("abort", stop); resolve(v); }, e => { signal.removeEventListener("abort", stop); reject(e); });
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
const settleWithin = (p, ms) => Promise.race([p, new Promise(r => setTimeout(() => r(DEADLINE), ms).unref?.())]);
|
|
53
|
+
export async function runNamedLinkTest(input, deps, outer) {
|
|
54
|
+
const steps = [];
|
|
55
|
+
const pass = (step, code = "ok") => { steps.push({ step, ok: true, code }); };
|
|
56
|
+
const fail = (step, code) => { steps.push({ step, ok: false, code }); return { steps, hostname, port }; };
|
|
57
|
+
// ① values — nothing runs on a value that could not be used.
|
|
58
|
+
const hostname = publicTunnelHostname(typeof input.hostname === "string" ? input.hostname.trim() : input.hostname);
|
|
59
|
+
const portRaw = typeof input.port === "string" && input.port.trim() !== "" ? Number(input.port) : input.port;
|
|
60
|
+
const port = Number.isInteger(portRaw) && portRaw >= 1024 && portRaw <= 65535 ? portRaw : null;
|
|
61
|
+
if (!hostname)
|
|
62
|
+
return fail("values", "bad-hostname");
|
|
63
|
+
if (port === null)
|
|
64
|
+
return fail("values", "bad-port");
|
|
65
|
+
if (!input.token)
|
|
66
|
+
return fail("values", "no-token");
|
|
67
|
+
const token = normalizePublicTunnelToken(input.token);
|
|
68
|
+
if (!token)
|
|
69
|
+
return fail("values", "bad-token");
|
|
70
|
+
pass("values");
|
|
71
|
+
const protocol = input.protocol === "quic" || input.protocol === "auto" ? input.protocol : "http2";
|
|
72
|
+
const abort = new AbortController();
|
|
73
|
+
const hard = setTimeout(() => abort.abort(), deps.hardMs ?? NAMED_TEST_HARD_MS);
|
|
74
|
+
const onOuter = () => abort.abort();
|
|
75
|
+
outer?.addEventListener("abort", onOuter, { once: true });
|
|
76
|
+
const signal = abort.signal;
|
|
77
|
+
/** Before anything is started: the deadline has not passed and the admin who asked is still signed in. */
|
|
78
|
+
const gone = () => signal.aborted ? "timeout" : deps.current && !deps.current() ? "cancelled" : null;
|
|
79
|
+
let server = null, lane = null, started = false;
|
|
80
|
+
let result;
|
|
81
|
+
let step = "origin";
|
|
82
|
+
try {
|
|
83
|
+
result = await (async () => {
|
|
84
|
+
// The admin's link is open on exactly these values: test it as it is.
|
|
85
|
+
const marker = deps.liveMarker({ hostname, port, token, protocol });
|
|
86
|
+
if (marker) {
|
|
87
|
+
pass("origin", "live");
|
|
88
|
+
pass("tunnel", "live");
|
|
89
|
+
step = "dns";
|
|
90
|
+
const dns = await within(resolveStep(hostname, deps), signal);
|
|
91
|
+
if (dns !== "ok")
|
|
92
|
+
return fail("dns", dns);
|
|
93
|
+
pass("dns");
|
|
94
|
+
step = "reach";
|
|
95
|
+
const reach = await within(reachStep(`https://${hostname}/signin`, marker, true, deps, signal), signal);
|
|
96
|
+
return reach === "ok" ? (pass("reach"), { steps, hostname, port }) : fail("reach", reach);
|
|
97
|
+
}
|
|
98
|
+
if (port === deps.healthPort)
|
|
99
|
+
return fail("origin", "dashboard-port");
|
|
100
|
+
const stop = gone();
|
|
101
|
+
if (stop)
|
|
102
|
+
return fail("origin", stop);
|
|
103
|
+
const held = deps.reserve();
|
|
104
|
+
if ("busy" in held)
|
|
105
|
+
return fail("origin", held.busy === "link-open" ? "link-open-other" : "tunnel-busy");
|
|
106
|
+
lane = held;
|
|
107
|
+
// ② origin — a stand-in that answers every request with this test's nonce, and nothing else.
|
|
108
|
+
const nonce = randomBytes(16).toString("hex");
|
|
109
|
+
const page = `<!doctype html><title>AgEnD</title><p>agend-named-test ${nonce}</p>`;
|
|
110
|
+
const stand = createServer((req, res) => { res.writeHead(200, { "Content-Type": "text/html; charset=utf-8", "Cache-Control": "no-store" }); res.end(req.method === "HEAD" ? undefined : page); });
|
|
111
|
+
server = stand;
|
|
112
|
+
const bound = await within(new Promise(resolve => {
|
|
113
|
+
stand.once("error", (err) => resolve(err?.code === "EADDRINUSE" || err?.code === "EACCES" ? "port-in-use" : "origin-failed"));
|
|
114
|
+
stand.listen(port, deps.bindHost ?? "127.0.0.1", () => resolve("ok"));
|
|
115
|
+
}), signal);
|
|
116
|
+
if (bound !== "ok") {
|
|
117
|
+
server = null;
|
|
118
|
+
return fail("origin", bound);
|
|
119
|
+
}
|
|
120
|
+
pass("origin");
|
|
121
|
+
// ③ tunnel — a test connector of the same tunnel, through the lane's managed start.
|
|
122
|
+
step = "tunnel";
|
|
123
|
+
let binary;
|
|
124
|
+
try {
|
|
125
|
+
binary = await within(deps.ensureBinary(signal), signal);
|
|
126
|
+
}
|
|
127
|
+
catch (err) {
|
|
128
|
+
if (err === DEADLINE)
|
|
129
|
+
throw err;
|
|
130
|
+
return fail("tunnel", "no-binary");
|
|
131
|
+
}
|
|
132
|
+
const late = gone();
|
|
133
|
+
if (late)
|
|
134
|
+
return fail("tunnel", late);
|
|
135
|
+
started = true;
|
|
136
|
+
const connector = await within(lane.start({ binary, hostname, token, protocol, origin: new URL(`http://127.0.0.1:${port}`), signal }), signal);
|
|
137
|
+
if (!connector.ok)
|
|
138
|
+
return fail("tunnel", tunnelCode(connector.kind, signal));
|
|
139
|
+
pass("tunnel");
|
|
140
|
+
// ④ dns, ⑤ reach — through a public resolver, as a phone elsewhere would.
|
|
141
|
+
step = "dns";
|
|
142
|
+
const dns = await within(resolveStep(hostname, deps), signal);
|
|
143
|
+
if (dns !== "ok")
|
|
144
|
+
return fail("dns", dns);
|
|
145
|
+
pass("dns");
|
|
146
|
+
step = "reach";
|
|
147
|
+
const reach = await within(reachStep(`https://${hostname}/agend-named-test-${nonce.slice(0, 8)}`, `agend-named-test ${nonce}`, false, deps, signal), signal);
|
|
148
|
+
return reach === "ok" ? (pass("reach"), { steps, hostname, port }) : fail("reach", reach);
|
|
149
|
+
})();
|
|
150
|
+
}
|
|
151
|
+
catch (err) {
|
|
152
|
+
// #2907 review (r2): nothing thrown escapes before the cleanup below — the deadline is "timeout" (or "cancelled"),
|
|
153
|
+
// anything else (a lease write refused, an unexpected error) is the step's closed failure; never a raw error.
|
|
154
|
+
result = fail(step, err === DEADLINE ? (outer?.aborted ? "cancelled" : "timeout") : UNEXPECTED[step]);
|
|
155
|
+
}
|
|
156
|
+
finally {
|
|
157
|
+
clearTimeout(hard);
|
|
158
|
+
outer?.removeEventListener("abort", onOuter);
|
|
159
|
+
// Cleanup, unconditionally and with its own allowance: what was started goes through the lane's managed stop
|
|
160
|
+
// (which gives the lane back only on a proven stop); the stand-in closes on every outcome.
|
|
161
|
+
const cleanupMs = deps.cleanupMs ?? NAMED_TEST_CLEANUP_MS;
|
|
162
|
+
let unconfirmed = false;
|
|
163
|
+
if (lane) {
|
|
164
|
+
const held = lane;
|
|
165
|
+
if (started) {
|
|
166
|
+
const stopped = await settleWithin(held.stop().catch(() => ({ confirmed: false })), cleanupMs);
|
|
167
|
+
unconfirmed = stopped === DEADLINE || !stopped.confirmed;
|
|
168
|
+
}
|
|
169
|
+
else
|
|
170
|
+
held.releaseUnused();
|
|
171
|
+
}
|
|
172
|
+
if (server) {
|
|
173
|
+
const stand = server;
|
|
174
|
+
await settleWithin(new Promise(r => { stand.close(() => r()); stand.closeAllConnections?.(); }), cleanupMs);
|
|
175
|
+
}
|
|
176
|
+
if (unconfirmed)
|
|
177
|
+
result.cleanup = "unconfirmed";
|
|
178
|
+
}
|
|
179
|
+
return result;
|
|
180
|
+
}
|
|
181
|
+
/** ③'s closed codes from the managed start's error kinds. */
|
|
182
|
+
function tunnelCode(kind, signal) {
|
|
183
|
+
switch (kind) {
|
|
184
|
+
case "named-auth-failed": return "auth";
|
|
185
|
+
case "named-connection-failed":
|
|
186
|
+
case "timeout": return "network";
|
|
187
|
+
case "cancelled": return signal.aborted ? "timeout" : "stopped";
|
|
188
|
+
case "lease-held": return "tunnel-busy";
|
|
189
|
+
case "binary-missing":
|
|
190
|
+
case "binary-not-executable": return "no-binary";
|
|
191
|
+
default: return "stopped";
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
/** ④: a public resolver's answer (what a phone elsewhere gets); the system's only when the public one cannot answer. */
|
|
195
|
+
async function resolveStep(hostname, deps) {
|
|
196
|
+
try {
|
|
197
|
+
const resolve4 = deps.resolve4 ?? ((h) => { const r = new Resolver({ timeout: 3_000, tries: 2 }); r.setServers([...PUBLIC_RESOLVERS]); return r.resolve4(h); });
|
|
198
|
+
const addresses = await resolve4(hostname);
|
|
199
|
+
return addresses.some(isPublicIPv4) ? "ok" : "dns-missing";
|
|
200
|
+
}
|
|
201
|
+
catch (err) {
|
|
202
|
+
const code = err?.code;
|
|
203
|
+
if (code === "ENOTFOUND" || code === "ENODATA")
|
|
204
|
+
return "dns-missing";
|
|
205
|
+
}
|
|
206
|
+
try {
|
|
207
|
+
await (deps.systemLookup ?? ((h) => lookup(h)))(hostname);
|
|
208
|
+
return "ok";
|
|
209
|
+
}
|
|
210
|
+
catch (err) {
|
|
211
|
+
return err?.code === "ENOTFOUND" ? "dns-missing" : "dns-failed";
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
/** ⑤: retried until the budget ends (the edge takes a moment to learn a new connector); the last answer decides. */
|
|
215
|
+
async function reachStep(url, expected, live, deps, signal) {
|
|
216
|
+
const fetchPage = deps.fetchPage ?? ((u, s) => fetchViaPublicResolver(u, s, { fallback: (v, t) => fetchViaSystemResolver(v, t) }));
|
|
217
|
+
const deadline = performance.now() + (deps.reachMs ?? NAMED_TEST_REACH_MS);
|
|
218
|
+
let last = "reach-failed";
|
|
219
|
+
while (!signal.aborted && performance.now() < deadline) {
|
|
220
|
+
const attempt = new AbortController();
|
|
221
|
+
const stop = () => attempt.abort();
|
|
222
|
+
signal.addEventListener("abort", stop, { once: true });
|
|
223
|
+
const timer = setTimeout(stop, Math.max(1, Math.min(5_000, deadline - performance.now())));
|
|
224
|
+
try {
|
|
225
|
+
const res = await within(fetchPage(url, attempt.signal), attempt.signal);
|
|
226
|
+
if (res.status === 200 && res.body.includes(expected))
|
|
227
|
+
return "ok";
|
|
228
|
+
last = res.status === 200 ? "other-page" : res.status === 404 ? "route-missing" : WRONG_SERVICE_STATUSES.has(res.status) ? "wrong-service" : "reach-failed";
|
|
229
|
+
// The open link's page may be served by another of the tunnel's connectors; any 200 there is its page.
|
|
230
|
+
if (live && res.status === 200)
|
|
231
|
+
return "other-page";
|
|
232
|
+
}
|
|
233
|
+
catch (err) {
|
|
234
|
+
if (err !== DEADLINE) {
|
|
235
|
+
const kind = classifyNamedTunnelProbeError(err, "");
|
|
236
|
+
last = kind === "named-route-missing" ? "route-missing" : kind === "named-connection-failed" ? "self-unreachable" : "reach-failed";
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
finally {
|
|
240
|
+
clearTimeout(timer);
|
|
241
|
+
signal.removeEventListener("abort", stop);
|
|
242
|
+
}
|
|
243
|
+
await new Promise(r => setTimeout(r, deps.retryMs ?? 1_000));
|
|
244
|
+
}
|
|
245
|
+
return last;
|
|
246
|
+
}
|
|
247
|
+
/**
|
|
248
|
+
* The production lane: the one tunnel lane's reservation, the connector started by its managed start (lease, proven
|
|
249
|
+
* stop) as a CloudflaredProvider that is ready once registered. `provider` is a test seam.
|
|
250
|
+
*/
|
|
251
|
+
export function namedTestLane(lane, opts = {}) {
|
|
252
|
+
return () => {
|
|
253
|
+
const id = `named-test-${randomBytes(6).toString("hex")}`;
|
|
254
|
+
const reservation = lane.reserve("named-test", id);
|
|
255
|
+
if (!reservation)
|
|
256
|
+
return { busy: lane.holder() === "dashboard" ? "link-open" : "other" };
|
|
257
|
+
return {
|
|
258
|
+
async start(i) {
|
|
259
|
+
const provider = (opts.provider ?? (o => new CloudflaredProvider(o)))({ binaryName: i.binary, protocol: i.protocol,
|
|
260
|
+
named: { hostname: i.hostname, token: i.token }, registeredOnly: true, deadlineMs: opts.registerMs ?? NAMED_TEST_REGISTER_MS });
|
|
261
|
+
const result = await reservation.start(provider, { sid: id, origin: i.origin, pagePath: "/", readinessMarker: id,
|
|
262
|
+
expiresAt: Date.now() + NAMED_TEST_HARD_MS, signal: i.signal });
|
|
263
|
+
return result.ok ? { ok: true } : { ok: false, kind: result.errorKind };
|
|
264
|
+
},
|
|
265
|
+
async stop() { return { confirmed: (await reservation.stop("named link test done")).confirmed }; },
|
|
266
|
+
releaseUnused() { reservation.releaseUnused(); },
|
|
267
|
+
};
|
|
268
|
+
};
|
|
269
|
+
}
|
|
270
|
+
//# sourceMappingURL=named-link-test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"named-link-test.js","sourceRoot":"","sources":["../../src/tunnel/named-link-test.ts"],"names":[],"mappings":"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"}
|
|
@@ -14,5 +14,7 @@ export declare class TunnelPurposeLane {
|
|
|
14
14
|
private readonly manager;
|
|
15
15
|
private owner;
|
|
16
16
|
constructor(manager: Pick<ManagedTunnel, "start" | "stop">);
|
|
17
|
-
|
|
17
|
+
/** #2906: who holds the lane now (the fixed address's Test connection says which), or null. */
|
|
18
|
+
holder(): string | null;
|
|
19
|
+
reserve(purpose: "login" | "dashboard" | "named-test", id: string): TunnelReservation | null;
|
|
18
20
|
}
|
|
@@ -6,6 +6,8 @@ export class TunnelPurposeLane {
|
|
|
6
6
|
constructor(manager) {
|
|
7
7
|
this.manager = manager;
|
|
8
8
|
}
|
|
9
|
+
/** #2906: who holds the lane now (the fixed address's Test connection says which), or null. */
|
|
10
|
+
holder() { return this.owner?.purpose ?? null; }
|
|
9
11
|
reserve(purpose, id) {
|
|
10
12
|
if (this.owner)
|
|
11
13
|
return this.owner.purpose === purpose && this.owner.id === id ? this.owner.reservation : null;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"purpose-lane.js","sourceRoot":"","sources":["../../src/tunnel/purpose-lane.ts"],"names":[],"mappings":"AAYA,MAAM,QAAQ,GAAG,GAAqB,EAAE,CAAC,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,EAAE,aAAa,EAAE,GAAG,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC;AAClH,kGAAkG;AAClG,MAAM,OAAO,iBAAiB;IAEC,OAAO;IAD5B,KAAK,GAA2E,IAAI,CAAC;IAC7F,YAA6B,OAA8C;uBAA9C,OAAO;IAA0C,CAAC;IAC/E,OAAO,CAAC,
|
|
1
|
+
{"version":3,"file":"purpose-lane.js","sourceRoot":"","sources":["../../src/tunnel/purpose-lane.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
CHANGED
|
@@ -434,6 +434,11 @@ export interface WebConfig {
|
|
|
434
434
|
enabled?: boolean;
|
|
435
435
|
max_hours?: number;
|
|
436
436
|
};
|
|
437
|
+
/** #2911: page share links — one agent page, read-only, for a limited time, on the Office share's tunnel (default on; 24 h at most). */
|
|
438
|
+
page_share?: {
|
|
439
|
+
enabled?: boolean;
|
|
440
|
+
max_hours?: number;
|
|
441
|
+
};
|
|
437
442
|
/** Expose provider API-key verify/apply endpoints (default false until dark-shipped). */
|
|
438
443
|
provider_secrets?: boolean;
|
|
439
444
|
/**
|
|
@@ -484,6 +489,11 @@ export interface WebConfig {
|
|
|
484
489
|
* instead of it; web.preview: false turns previews off everywhere.
|
|
485
490
|
*/
|
|
486
491
|
preview_on_public_link?: boolean;
|
|
492
|
+
/**
|
|
493
|
+
* #2911 (7): previews may load libraries from cdnjs (/ajax/libs/) and jsDelivr (/npm/) — scripts, styles and fonts
|
|
494
|
+
* only (connect-src stays 'none'). Default false. Those requests leave this machine.
|
|
495
|
+
*/
|
|
496
|
+
preview_cdn?: boolean;
|
|
487
497
|
/**
|
|
488
498
|
* #1629: agents' own web themes and effects. `agent_edit` (default true): false refuses every agent appearance write,
|
|
489
499
|
* fleet-wide; what is stored stays, and people can still reset and lock.
|
package/dist/ui/chat-store.js
CHANGED
|
@@ -456,6 +456,13 @@ export function createChatStore(deps) {
|
|
|
456
456
|
const isPasted = (f) => pastedTexts.has(f);
|
|
457
457
|
/** Typing stays local. */
|
|
458
458
|
function setDraft(target, value) { s.drafts[target] = value; }
|
|
459
|
+
/** #2911: a line added to the composer for the person to edit (after what is typed, on its own line; never twice). */
|
|
460
|
+
function addToDraft(target, line) {
|
|
461
|
+
const d = s.drafts[target] || "";
|
|
462
|
+
if (!target || !line || d.split("\n").includes(line)) return;
|
|
463
|
+
s.drafts[target] = d ? `${d.replace(/\n+$/, "")}\n${line}` : line;
|
|
464
|
+
changed(target);
|
|
465
|
+
}
|
|
459
466
|
/**
|
|
460
467
|
* #2272: reply to a message of this chat — what the bar above the composer shows (its sender and first words); only
|
|
461
468
|
* its row is sent. One at a time per chat: a new one replaces it.
|
|
@@ -575,7 +582,7 @@ export function createChatStore(deps) {
|
|
|
575
582
|
onPrompt, applyPrompts, resolvePrompt, answerPrompt, answerByNonce, holdPrompt, releasePrompt, promptsFor,
|
|
576
583
|
applyReplyButtons, clickReplyButton,
|
|
577
584
|
uploadFile, send, retryOutgoing, deleteOutgoing, putBackOutgoing, threadRows, addFiles, removeFile, attachPastedText, fileBackAsText, isPasted, setDraft,
|
|
578
|
-
startReply, clearReply, findQuoted,
|
|
585
|
+
startReply, clearReply, findQuoted, addToDraft,
|
|
579
586
|
cancelReply, isUser, runCommand, dismissCommand, commandFree,
|
|
580
587
|
allHidden: (name) => s.allHidden.has(name),
|
|
581
588
|
};
|
package/dist/ui/chat-strings.js
CHANGED
|
@@ -56,6 +56,25 @@ register("chat", {
|
|
|
56
56
|
pvOpenPanel: "Open in panel", pvInPanel: "Shown in the panel.", pvPanel: "HTML preview", pvSource: "From {0}, {1} — show the message",
|
|
57
57
|
pvPage: "Page", pvCode: "Code", pvReload: "Reload", pvClose: "Close the panel", pvBack: "Back to the chat", pvResize: "Resize the preview panel",
|
|
58
58
|
pvNewer: "A newer version is in the reply from {0}.", pvNewerShow: "Show it", pvPanelIdle: "Click Preview to run it here.",
|
|
59
|
+
// #2911 (M-2216): the panel's versions and their changes.
|
|
60
|
+
pvVersions: "Versions", pvVer: "v{0}/{1}", pvVerLong: "Version {0} of {1}", pvVerPrev: "Previous version", pvVerNext: "Next version",
|
|
61
|
+
pvChanges: "Changes", pvChangesFrom: "Changes from v{0}", pvChangesNone: "No changes from v{0}.",
|
|
62
|
+
pvPagesCount: "Pages ({0})", pvPagesTitle: "Every page in this conversation", pvPagesUntitled: "Untitled page", pvPagesVersions: "{0} versions",
|
|
63
|
+
pvWidth: "Width the page is shown at", pvWidthFull: "Full width", pvWidthTablet: "Tablet · 768", pvWidthPhone: "Phone · 390",
|
|
64
|
+
pvFs: "Full screen", pvFsExit: "Leave full screen (Esc)",
|
|
65
|
+
pvChangesBig: "These versions are too large or too different to compare here. Download both to compare them.", pvChangesCut: "showing the first {0} lines",
|
|
66
|
+
// #2911 (M-2217): the preview's feedback actions.
|
|
67
|
+
pvFbReply: "Reply about this page", pvFbReplyTitle: "Reply to the message this page came in, naming the page — you write what to change",
|
|
68
|
+
pvFbAboutNamed: "About the page “{0}”: ", pvFbAboutThis: "About this page: ",
|
|
69
|
+
pvFbErrOne: "error", pvFbErrMany: "errors", pvFbErrTitle: "The page reported errors: put them in the message box, quoted, for you to check and send. Their text is the page's",
|
|
70
|
+
pvFbErrHeadOne: "The preview reported 1 error (text from the page):", pvFbErrHead: "The preview reported {0} errors (text from the page):",
|
|
71
|
+
pvFbErrRejection: "Unhandled rejection: ", pvFbErrAt: "line {0}:{1}", pvFbErrMore: "…and {0} more.",
|
|
72
|
+
// #2911 (7, M-2216): CDN libraries in previews.
|
|
73
|
+
pvCdnBlocked: "Blocked by the preview: ",
|
|
74
|
+
pvCdnNote: "This page loads a library from {0}, which previews block unless Settings → Web dashboard → “HTML previews may load libraries from cdnjs / jsDelivr” is on.",
|
|
75
|
+
pvFbPick: "Point at it", pvFbPickTitle: "Click an element in the page to say what to change about it",
|
|
76
|
+
pvFbPickCancel: "Cancel pointing", pvFbPickCancelTitle: "Stop pointing — the page takes clicks again",
|
|
77
|
+
pvFbPickWords: "On `{0}` (“{1}”, text from the page): ", pvFbPickAt: "On `{0}` (from the page): ",
|
|
59
78
|
lbLabel: "Image: {0}", lbLabelNoName: "Image", lbClose: "Close", lbOpenOriginal: "Open original", lbPrev: "Previous image", lbNext: "Next image", lbCount: "{0} / {1}",
|
|
60
79
|
// #2333: zoom in the lightbox.
|
|
61
80
|
lbZoomIn: "Zoom in (+)", lbZoomOut: "Zoom out (−)", lbZoomLevel: "{0}% — click for fit or actual size (0 / 1)", lbFitWidth: "Fit width (W)",
|
|
@@ -180,6 +199,23 @@ register("chat", {
|
|
|
180
199
|
pvOpenPanel: "在面板中開啟", pvInPanel: "已在面板中顯示。", pvPanel: "HTML 預覽", pvSource: "來自 {0},{1}——顯示該訊息",
|
|
181
200
|
pvPage: "頁面", pvCode: "程式碼", pvReload: "重新載入", pvClose: "關閉面板", pvBack: "回到對話", pvResize: "調整預覽面板寬度",
|
|
182
201
|
pvNewer: "{0} 的回覆裡有較新的版本。", pvNewerShow: "顯示", pvPanelIdle: "按「預覽」在這裡執行。",
|
|
202
|
+
pvVersions: "版本", pvVer: "v{0}/{1}", pvVerLong: "第 {0} 版,共 {1} 版", pvVerPrev: "上一版", pvVerNext: "下一版",
|
|
203
|
+
pvChanges: "變更", pvChangesFrom: "與第 {0} 版相比的變更", pvChangesNone: "與第 {0} 版相比沒有變更。",
|
|
204
|
+
pvPagesCount: "頁面({0})", pvPagesTitle: "這段對話中的所有頁面", pvPagesUntitled: "未命名頁面", pvPagesVersions: "{0} 個版本",
|
|
205
|
+
pvWidth: "頁面顯示寬度", pvWidthFull: "完整寬度", pvWidthTablet: "平板 · 768", pvWidthPhone: "手機 · 390",
|
|
206
|
+
pvFs: "全螢幕", pvFsExit: "離開全螢幕(Esc)",
|
|
207
|
+
pvChangesBig: "這兩版太大或差異太多,無法在這裡比較。請下載兩版後再比較。", pvChangesCut: "只顯示前 {0} 行",
|
|
208
|
+
// #2911 (M-2217): 預覽的回饋動作。
|
|
209
|
+
pvFbReply: "回覆這個頁面", pvFbReplyTitle: "回覆這個頁面所在的訊息並註明頁面——要改什麼由你來寫",
|
|
210
|
+
pvFbAboutNamed: "關於頁面「{0}」:", pvFbAboutThis: "關於這個頁面:",
|
|
211
|
+
pvFbErrOne: "個錯誤", pvFbErrMany: "個錯誤", pvFbErrTitle: "頁面回報了錯誤:以引用的方式放進輸入框,由你確認後送出。錯誤文字來自頁面本身",
|
|
212
|
+
pvFbErrHeadOne: "預覽回報了 1 個錯誤(文字來自頁面):", pvFbErrHead: "預覽回報了 {0} 個錯誤(文字來自頁面):",
|
|
213
|
+
pvFbErrRejection: "未處理的 rejection:", pvFbErrAt: "第 {0} 行第 {1} 欄", pvFbErrMore: "……還有 {0} 個。",
|
|
214
|
+
pvCdnBlocked: "被預覽封鎖:",
|
|
215
|
+
pvCdnNote: "這個頁面要從 {0} 載入函式庫,但預覽會封鎖它,除非開啟 設定 → 網頁儀表板 中的「HTML 預覽可從 cdnjs / jsDelivr 載入函式庫」。",
|
|
216
|
+
pvFbPick: "指出位置", pvFbPickTitle: "在頁面上點一個元素,說明要怎麼改",
|
|
217
|
+
pvFbPickCancel: "取消指出", pvFbPickCancelTitle: "停止指出——頁面恢復接收點擊",
|
|
218
|
+
pvFbPickWords: "在 `{0}`(「{1}」,文字來自頁面):", pvFbPickAt: "在 `{0}`(來自頁面):",
|
|
183
219
|
lbLabel: "圖片:{0}", lbLabelNoName: "圖片", lbClose: "關閉", lbOpenOriginal: "開啟原圖", lbPrev: "上一張", lbNext: "下一張", lbCount: "{0} / {1}",
|
|
184
220
|
lbZoomIn: "放大(+)", lbZoomOut: "縮小(−)", lbZoomLevel: "{0}%:點一下切換「符合視窗」與「實際大小」(0 / 1)", lbFitWidth: "符合寬度(W)",
|
|
185
221
|
pvWhyOptin: "還沒允許 HTML 預覽。可從這張卡片的 ⋯ 選單或「設定 → 偏好設定」允許。",
|