toyon 0.11.0 → 0.13.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 +1 -1
- package/dist/bridge.js +1 -1
- package/dist/cli.js +481 -2129
- package/dist/daemon.js +3384 -1769
- package/dist/helper-stub +0 -0
- package/dist/shell/assets/{Editor-Cs_OeWSx.js → Editor-CUcgZuoM.js} +3 -3
- package/dist/shell/assets/{XTerm-Dc6Bk52B.js → XTerm-V6sBDIe-.js} +1 -1
- package/dist/shell/assets/{cssMode-D8uDYrHJ.js → cssMode-CSyiAvIn.js} +1 -1
- package/dist/shell/assets/{freemarker2-DlU9uDzS.js → freemarker2-C4-FNK3V.js} +1 -1
- package/dist/shell/assets/{grammar-BSzyJU-q.js → grammar-DzHb7e7O.js} +1 -1
- package/dist/shell/assets/{handlebars-B66kGi_7.js → handlebars-DcjVaOCM.js} +1 -1
- package/dist/shell/assets/{html-D6juOeyd.js → html-Csl8cogA.js} +1 -1
- package/dist/shell/assets/{htmlMode-CbTT-4ZV.js → htmlMode-rewe9UaO.js} +1 -1
- package/dist/shell/assets/index-Bkn7zNFw.js +267 -0
- package/dist/shell/assets/index-iVaPr_If.css +1 -0
- package/dist/shell/assets/{javascript-CHwG4FvH.js → javascript--pKV-E-G.js} +1 -1
- package/dist/shell/assets/{jsonMode-DzTEiaKX.js → jsonMode-zPVc0E6l.js} +1 -1
- package/dist/shell/assets/{liquid-wddZX4zw.js → liquid-jZT5xQG-.js} +1 -1
- package/dist/shell/assets/{lspLanguageFeatures-BlqDZ6dO.js → lspLanguageFeatures-BuiqKs90.js} +1 -1
- package/dist/shell/assets/{mdx-Dlz2LIv9.js → mdx-DwnR-ia2.js} +1 -1
- package/dist/shell/assets/{python-DvkArqZY.js → python-DU3pl9Zu.js} +1 -1
- package/dist/shell/assets/{razor-bDLQ0jQf.js → razor-BzVUPqHs.js} +1 -1
- package/dist/shell/assets/{tsMode-B_NomV_y.js → tsMode-ONmZhHHZ.js} +1 -1
- package/dist/shell/assets/{xml-CBYJrQiV.js → xml-BXW7X3BT.js} +1 -1
- package/dist/shell/assets/{yaml-DnmVK8S2.js → yaml-DFE79ex1.js} +1 -1
- package/dist/shell/index.html +20 -37
- package/dist/shell/manifest.json +1 -1
- package/dist/shell/offline.html +219 -0
- package/dist/shell/sw.js +32 -3
- package/package.json +1 -1
- package/dist/shell/assets/index-B4KJ--q9.css +0 -1
- package/dist/shell/assets/index-Cj-6Xixu.js +0 -268
package/dist/cli.js
CHANGED
|
@@ -2,40 +2,105 @@
|
|
|
2
2
|
// @bun
|
|
3
3
|
|
|
4
4
|
// src/cli.ts
|
|
5
|
-
import { existsSync as
|
|
5
|
+
import { existsSync as existsSync11, statSync as statSync4 } from "fs";
|
|
6
6
|
import { join as join7, resolve } from "path";
|
|
7
|
+
// package.json
|
|
8
|
+
var package_default = {
|
|
9
|
+
name: "toyon",
|
|
10
|
+
version: "0.13.0",
|
|
11
|
+
description: "Toyon is where coding agents work on your web app while you check each change by using it. Every chat gets its own running copy with a live preview.",
|
|
12
|
+
license: "MIT",
|
|
13
|
+
type: "module",
|
|
14
|
+
homepage: "https://toyon.dev",
|
|
15
|
+
repository: {
|
|
16
|
+
type: "git",
|
|
17
|
+
url: "git+https://github.com/toyon-dev/toyon.git"
|
|
18
|
+
},
|
|
19
|
+
bugs: "https://github.com/toyon-dev/toyon/issues",
|
|
20
|
+
keywords: [
|
|
21
|
+
"ai",
|
|
22
|
+
"agents",
|
|
23
|
+
"claude-code",
|
|
24
|
+
"codex",
|
|
25
|
+
"opencode",
|
|
26
|
+
"git",
|
|
27
|
+
"worktree",
|
|
28
|
+
"preview",
|
|
29
|
+
"dev-server"
|
|
30
|
+
],
|
|
31
|
+
bin: {
|
|
32
|
+
toyon: "bin/toyon.js"
|
|
33
|
+
},
|
|
34
|
+
files: [
|
|
35
|
+
"bin",
|
|
36
|
+
"dist",
|
|
37
|
+
"cloud"
|
|
38
|
+
],
|
|
39
|
+
engines: {
|
|
40
|
+
node: ">=18"
|
|
41
|
+
},
|
|
42
|
+
os: [
|
|
43
|
+
"darwin",
|
|
44
|
+
"linux"
|
|
45
|
+
],
|
|
46
|
+
scripts: {
|
|
47
|
+
prepublishOnly: "bun ../../scripts/pack.ts"
|
|
48
|
+
},
|
|
49
|
+
dependencies: {
|
|
50
|
+
bun: "1.4.2",
|
|
51
|
+
"bun-pty": "0.4.10"
|
|
52
|
+
},
|
|
53
|
+
devDependencies: {
|
|
54
|
+
"@toyon/shared": "workspace:*"
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
// src/app.ts
|
|
59
|
+
import { spawn as spawn3, spawnSync } from "child_process";
|
|
60
|
+
import { existsSync as existsSync3, mkdirSync as mkdirSync2, readdirSync, readFileSync as readFileSync2, writeFileSync } from "fs";
|
|
61
|
+
import { homedir as homedir2 } from "os";
|
|
62
|
+
import { join as join3 } from "path";
|
|
63
|
+
|
|
64
|
+
// src/daemon.ts
|
|
65
|
+
import { spawn } from "child_process";
|
|
66
|
+
import { existsSync as existsSync2, mkdirSync, openSync, readFileSync } from "fs";
|
|
67
|
+
import { homedir } from "os";
|
|
68
|
+
import { join as join2 } from "path";
|
|
7
69
|
|
|
8
|
-
// ../shared/src/
|
|
70
|
+
// ../shared/src/knock.ts
|
|
71
|
+
var KNOCK_TTL_MS = 5 * 60000;
|
|
72
|
+
var machineLink = (host) => `https://${host}/`;
|
|
9
73
|
var isTailnetName = (host) => host.endsWith(".ts.net");
|
|
10
|
-
var listed = (names) => names.length < 2 ? names[0] ?? "" : `${names.slice(0, -1).join(", ")} and ${names.at(-1)}`;
|
|
11
|
-
function tailnetLine(phones) {
|
|
12
|
-
if (phones === null)
|
|
13
|
-
return { ok: true, text: "Your phone needs Tailscale on, signed in to the same tailnet." };
|
|
14
|
-
if (phones.length === 0) {
|
|
15
|
-
return {
|
|
16
|
-
ok: false,
|
|
17
|
-
text: "No phone has joined your tailnet. Install Tailscale on it and sign in to the same account first."
|
|
18
|
-
};
|
|
19
|
-
}
|
|
20
|
-
const on = phones.filter((p) => p.online).map((p) => p.name);
|
|
21
|
-
if (on.length > 0)
|
|
22
|
-
return { ok: true, text: `${listed(on)} ${on.length > 1 ? "are" : "is"} on your tailnet.` };
|
|
23
|
-
const off = phones.map((p) => p.name);
|
|
24
|
-
return {
|
|
25
|
-
ok: false,
|
|
26
|
-
text: `${listed(off)} ${off.length > 1 ? "are" : "is"} not answering on your tailnet. Check Tailscale is on there.`
|
|
27
|
-
};
|
|
28
|
-
}
|
|
29
74
|
|
|
30
75
|
// ../shared/src/daemon.ts
|
|
76
|
+
var APP_SCHEME = "toyon";
|
|
77
|
+
var START_LINK = `${APP_SCHEME}://start`;
|
|
78
|
+
var LSREGISTER = "/System/Library/Frameworks/CoreServices.framework/Frameworks/LaunchServices.framework/Support/lsregister";
|
|
31
79
|
var DAEMON_FILES = {
|
|
32
80
|
token: "token",
|
|
81
|
+
helper: "Toyon.app",
|
|
82
|
+
launcherLog: "launcher.log",
|
|
33
83
|
pid: "daemon.pid",
|
|
34
84
|
state: "state.json",
|
|
35
85
|
drafts: "drafts.json",
|
|
36
86
|
log: "daemon.log",
|
|
37
87
|
remote: "remote.json"
|
|
38
88
|
};
|
|
89
|
+
function previewsLine(r) {
|
|
90
|
+
return addressedByPort(r.previews) ? `previews on ports ${PREVIEW_PORTS.from}-${PREVIEW_PORTS.to}` : `previews at ${r.previews}`;
|
|
91
|
+
}
|
|
92
|
+
function acceptRemote(view, policy) {
|
|
93
|
+
if (policy.remote === "off")
|
|
94
|
+
return "remote access is turned off by your organization's policy";
|
|
95
|
+
const host = view.host.toLowerCase();
|
|
96
|
+
if (!isRemoteHost(host))
|
|
97
|
+
return `${view.host} is not a name a front can answer for`;
|
|
98
|
+
if (policy.remote === "tailscale" && !isTailnetName(host)) {
|
|
99
|
+
return "your organization's policy allows remote access over Tailscale only";
|
|
100
|
+
}
|
|
101
|
+
const why = checkPreviews(view.previews, host);
|
|
102
|
+
return why ?? { host, previews: view.previews };
|
|
103
|
+
}
|
|
39
104
|
var PREVIEW_PORTS = { from: 10001, to: 10008 };
|
|
40
105
|
var DNS_NAME = /^(?=.{1,253}$)[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?(\.[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?)+$/;
|
|
41
106
|
function isRemoteHost(name) {
|
|
@@ -83,10 +148,6 @@ function parseRemote(text) {
|
|
|
83
148
|
}
|
|
84
149
|
var WS_CLOSE_UNAUTHORIZED = 4401;
|
|
85
150
|
|
|
86
|
-
// ../shared/src/launcher.ts
|
|
87
|
-
var LAUNCHER_ORIGIN = "https://toyon.cloud";
|
|
88
|
-
var launcherAddLink = (machineOrigin) => `${LAUNCHER_ORIGIN}/#add=${encodeURIComponent(machineOrigin)}`;
|
|
89
|
-
|
|
90
151
|
// ../../node_modules/.bun/zod@4.5.4/node_modules/zod/v4/core/util.js
|
|
91
152
|
function getEnumValues(entries) {
|
|
92
153
|
const numericValues = Object.values(entries).filter((v) => typeof v === "number");
|
|
@@ -5187,68 +5248,6 @@ function parseVersion(v) {
|
|
|
5187
5248
|
return null;
|
|
5188
5249
|
return { nums: [Number(m[1]), Number(m[2]), Number(m[3])], pre: m[4] ?? null };
|
|
5189
5250
|
}
|
|
5190
|
-
// package.json
|
|
5191
|
-
var package_default = {
|
|
5192
|
-
name: "toyon",
|
|
5193
|
-
version: "0.11.0",
|
|
5194
|
-
description: "Toyon is where coding agents work on your web app while you check each change by using it. Every chat gets its own running copy with a live preview.",
|
|
5195
|
-
license: "MIT",
|
|
5196
|
-
type: "module",
|
|
5197
|
-
homepage: "https://toyon.dev",
|
|
5198
|
-
repository: {
|
|
5199
|
-
type: "git",
|
|
5200
|
-
url: "git+https://github.com/toyon-dev/toyon.git"
|
|
5201
|
-
},
|
|
5202
|
-
bugs: "https://github.com/toyon-dev/toyon/issues",
|
|
5203
|
-
keywords: [
|
|
5204
|
-
"ai",
|
|
5205
|
-
"agents",
|
|
5206
|
-
"claude-code",
|
|
5207
|
-
"codex",
|
|
5208
|
-
"opencode",
|
|
5209
|
-
"git",
|
|
5210
|
-
"worktree",
|
|
5211
|
-
"preview",
|
|
5212
|
-
"dev-server"
|
|
5213
|
-
],
|
|
5214
|
-
bin: {
|
|
5215
|
-
toyon: "bin/toyon.js"
|
|
5216
|
-
},
|
|
5217
|
-
files: [
|
|
5218
|
-
"bin",
|
|
5219
|
-
"dist",
|
|
5220
|
-
"cloud"
|
|
5221
|
-
],
|
|
5222
|
-
engines: {
|
|
5223
|
-
node: ">=18"
|
|
5224
|
-
},
|
|
5225
|
-
os: [
|
|
5226
|
-
"darwin",
|
|
5227
|
-
"linux"
|
|
5228
|
-
],
|
|
5229
|
-
scripts: {
|
|
5230
|
-
prepublishOnly: "bun ../../scripts/pack.ts"
|
|
5231
|
-
},
|
|
5232
|
-
dependencies: {
|
|
5233
|
-
bun: "1.4.2",
|
|
5234
|
-
"bun-pty": "0.4.10"
|
|
5235
|
-
},
|
|
5236
|
-
devDependencies: {
|
|
5237
|
-
"@toyon/shared": "workspace:*"
|
|
5238
|
-
}
|
|
5239
|
-
};
|
|
5240
|
-
|
|
5241
|
-
// src/app.ts
|
|
5242
|
-
import { spawn as spawn2, spawnSync } from "child_process";
|
|
5243
|
-
import { chmodSync, existsSync as existsSync3, mkdirSync as mkdirSync2, readdirSync, readFileSync as readFileSync2, rmSync, writeFileSync } from "fs";
|
|
5244
|
-
import { homedir as homedir2 } from "os";
|
|
5245
|
-
import { join as join3 } from "path";
|
|
5246
|
-
|
|
5247
|
-
// src/daemon.ts
|
|
5248
|
-
import { spawn } from "child_process";
|
|
5249
|
-
import { existsSync as existsSync2, mkdirSync, openSync, readFileSync } from "fs";
|
|
5250
|
-
import { homedir } from "os";
|
|
5251
|
-
import { join as join2 } from "path";
|
|
5252
5251
|
|
|
5253
5252
|
// src/layout.ts
|
|
5254
5253
|
import { existsSync, realpathSync } from "fs";
|
|
@@ -5272,7 +5271,6 @@ function installOnPath() {
|
|
|
5272
5271
|
}
|
|
5273
5272
|
var restartCmd = restartCommand(method, package_default.version, method === "npx" ? installOnPath() : "none", process.env.npm_config_registry ?? null);
|
|
5274
5273
|
var daemonEntry = packaged ? join(here, "daemon.js") : join(here, "../../daemon/src/index.ts");
|
|
5275
|
-
var iconSvg = packaged ? join(here, "shell", "icon.svg") : join(here, "../../shell/public/icon.svg");
|
|
5276
5274
|
|
|
5277
5275
|
// src/daemon.ts
|
|
5278
5276
|
var port = Number(process.env.TOYON_PORT ?? DAEMON_DEFAULT_PORT);
|
|
@@ -5292,6 +5290,23 @@ async function health() {
|
|
|
5292
5290
|
return null;
|
|
5293
5291
|
}
|
|
5294
5292
|
}
|
|
5293
|
+
async function daemonFetch(path, init = {}) {
|
|
5294
|
+
const token = readToken();
|
|
5295
|
+
if (!token)
|
|
5296
|
+
return null;
|
|
5297
|
+
try {
|
|
5298
|
+
return await fetch(`${base}${path}`, {
|
|
5299
|
+
method: init.method ?? (init.body === undefined ? "GET" : "POST"),
|
|
5300
|
+
headers: {
|
|
5301
|
+
authorization: `Bearer ${token}`,
|
|
5302
|
+
...init.body === undefined ? {} : { "content-type": "application/json" }
|
|
5303
|
+
},
|
|
5304
|
+
body: init.body === undefined ? undefined : JSON.stringify(init.body)
|
|
5305
|
+
});
|
|
5306
|
+
} catch {
|
|
5307
|
+
return null;
|
|
5308
|
+
}
|
|
5309
|
+
}
|
|
5295
5310
|
function readToken() {
|
|
5296
5311
|
if (!existsSync2(tokenFile))
|
|
5297
5312
|
return null;
|
|
@@ -5329,63 +5344,46 @@ async function startDaemon() {
|
|
|
5329
5344
|
}
|
|
5330
5345
|
return await health() !== null;
|
|
5331
5346
|
}
|
|
5347
|
+
function behind(daemonVersion) {
|
|
5348
|
+
return daemonVersion === undefined || newer(package_default.version, daemonVersion);
|
|
5349
|
+
}
|
|
5350
|
+
async function ensureDaemon() {
|
|
5351
|
+
let running = await health();
|
|
5352
|
+
if (!running) {
|
|
5353
|
+
console.log("starting Toyon daemon\u2026");
|
|
5354
|
+
running = await startDaemon() ? await health() : null;
|
|
5355
|
+
if (!running) {
|
|
5356
|
+
console.error(`daemon failed to start; \`toyon logs\` shows why (${logFile})`);
|
|
5357
|
+
return null;
|
|
5358
|
+
}
|
|
5359
|
+
} else if (behind(running.version)) {
|
|
5360
|
+
console.log(`toyon: the running daemon is ${running.version ?? "older"}; \`${restartCmd}\` starts ${package_default.version}`);
|
|
5361
|
+
}
|
|
5362
|
+
const token = readToken();
|
|
5363
|
+
if (!token) {
|
|
5364
|
+
console.error("daemon token missing; `toyon doctor` says where it looked");
|
|
5365
|
+
return null;
|
|
5366
|
+
}
|
|
5367
|
+
return { token, url: shellUrl(token, running.branded === true), remote: running.remote ?? null };
|
|
5368
|
+
}
|
|
5369
|
+
function post(route, token, body) {
|
|
5370
|
+
return fetch(`${base}${route}`, {
|
|
5371
|
+
method: "POST",
|
|
5372
|
+
headers: { authorization: `Bearer ${token}`, "content-type": "application/json" },
|
|
5373
|
+
body: JSON.stringify(body)
|
|
5374
|
+
});
|
|
5375
|
+
}
|
|
5332
5376
|
function shellUrl(token, branded) {
|
|
5333
5377
|
return branded ? `http://toyon.localhost/#token=${token}` : `http://toyon.localhost:${port}/#token=${token}`;
|
|
5334
5378
|
}
|
|
5335
5379
|
|
|
5336
|
-
// src/
|
|
5337
|
-
|
|
5338
|
-
|
|
5339
|
-
|
|
5340
|
-
|
|
5341
|
-
|
|
5342
|
-
// before the finish-launching one, which is why the paths are collected first and the exec waits
|
|
5343
|
-
// for the second. With nothing dropped the script runs with no arguments.
|
|
5344
|
-
//
|
|
5345
|
-
// Read into the CLI as text (app.ts) and compiled at \`toyon --install-app\` on the machine itself.
|
|
5346
|
-
#import <Cocoa/Cocoa.h>
|
|
5347
|
-
#include <libgen.h>
|
|
5348
|
-
#include <mach-o/dyld.h>
|
|
5349
|
-
#include <stdlib.h>
|
|
5350
|
-
#include <unistd.h>
|
|
5351
|
-
|
|
5352
|
-
@interface Launcher : NSObject <NSApplicationDelegate>
|
|
5353
|
-
@property(strong) NSMutableArray<NSString *> *paths;
|
|
5354
|
-
@end
|
|
5355
|
-
|
|
5356
|
-
@implementation Launcher
|
|
5357
|
-
- (void)application:(NSApplication *)app openFiles:(NSArray<NSString *> *)files {
|
|
5358
|
-
[self.paths addObjectsFromArray:files];
|
|
5359
|
-
[app replyToOpenOrPrint:NSApplicationDelegateReplySuccess];
|
|
5360
|
-
}
|
|
5361
|
-
- (BOOL)applicationSupportsSecureRestorableState:(NSApplication *)app {
|
|
5362
|
-
return YES;
|
|
5363
|
-
}
|
|
5364
|
-
- (void)applicationDidFinishLaunching:(NSNotification *)note {
|
|
5365
|
-
char self_[4096];
|
|
5366
|
-
uint32_t n = sizeof(self_);
|
|
5367
|
-
if (_NSGetExecutablePath(self_, &n) != 0) exit(1);
|
|
5368
|
-
NSString *script = [NSString stringWithFormat:@"%s/../Resources/launch.sh", dirname(self_)];
|
|
5369
|
-
NSMutableArray<NSString *> *argv = [NSMutableArray arrayWithObjects:@"bash", script, nil];
|
|
5370
|
-
[argv addObjectsFromArray:self.paths];
|
|
5371
|
-
const char **cargv = calloc(argv.count + 1, sizeof(char *));
|
|
5372
|
-
for (NSUInteger i = 0; i < argv.count; i++) cargv[i] = [argv[i] fileSystemRepresentation];
|
|
5373
|
-
execv("/bin/bash", (char *const *)cargv);
|
|
5374
|
-
exit(1);
|
|
5375
|
-
}
|
|
5376
|
-
@end
|
|
5377
|
-
|
|
5378
|
-
int main(void) {
|
|
5379
|
-
@autoreleasepool {
|
|
5380
|
-
NSApplication *app = [NSApplication sharedApplication];
|
|
5381
|
-
Launcher *launcher = [Launcher new];
|
|
5382
|
-
launcher.paths = [NSMutableArray new];
|
|
5383
|
-
app.delegate = launcher;
|
|
5384
|
-
[app run];
|
|
5385
|
-
}
|
|
5386
|
-
return 0;
|
|
5380
|
+
// src/openUrl.ts
|
|
5381
|
+
import { spawn as spawn2 } from "child_process";
|
|
5382
|
+
function openUrl(url) {
|
|
5383
|
+
const child = spawn2(process.platform === "darwin" ? "open" : "xdg-open", [url], { stdio: "ignore" });
|
|
5384
|
+
child.on("error", () => {});
|
|
5385
|
+
child.unref();
|
|
5387
5386
|
}
|
|
5388
|
-
`;
|
|
5389
5387
|
|
|
5390
5388
|
// src/app.ts
|
|
5391
5389
|
var CHROMIUMS = ["Google Chrome", "Arc", "Brave Browser", "Microsoft Edge", "Chromium"];
|
|
@@ -5431,13 +5429,21 @@ function findPwaId(browser, manifestId) {
|
|
|
5431
5429
|
}
|
|
5432
5430
|
return null;
|
|
5433
5431
|
}
|
|
5432
|
+
function showAppWindow(daemon) {
|
|
5433
|
+
const appUrl = shellUrl(daemon.token, false);
|
|
5434
|
+
console.log(`toyon: app window (${appUrl.split("#")[0]})`);
|
|
5435
|
+
if (openAppWindow(appUrl))
|
|
5436
|
+
return;
|
|
5437
|
+
console.log("no Chromium browser found; opening in default browser");
|
|
5438
|
+
openUrl(daemon.url);
|
|
5439
|
+
}
|
|
5434
5440
|
function openAppWindow(appUrl) {
|
|
5435
5441
|
const manifestId = new URL("/", appUrl).href;
|
|
5436
5442
|
for (const app of CHROMIUMS) {
|
|
5437
5443
|
if (spawnSync("open", ["-Ra", app]).status === 0) {
|
|
5438
5444
|
const id = findPwaId(app, manifestId);
|
|
5439
5445
|
const flag = id ? `--app-id=${id}` : `--app=${appUrl}`;
|
|
5440
|
-
|
|
5446
|
+
spawn3("open", ["-na", app, "--args", flag], { stdio: "ignore" }).unref();
|
|
5441
5447
|
if (!id) {
|
|
5442
5448
|
console.log(`tip: install Toyon as an app (browser menu, then Install, or the install button in the top bar when opened in a tab)`);
|
|
5443
5449
|
console.log(` once installed, it gets a native-style title bar; \`toyon --app\` then launches the installed app`);
|
|
@@ -5447,145 +5453,11 @@ function openAppWindow(appUrl) {
|
|
|
5447
5453
|
}
|
|
5448
5454
|
return false;
|
|
5449
5455
|
}
|
|
5450
|
-
function installApp(appUrl) {
|
|
5451
|
-
const manifestId = new URL("/", appUrl).href;
|
|
5452
|
-
const appDir = join3(homedir2(), "Applications", "Toyon.app");
|
|
5453
|
-
const macos = join3(appDir, "Contents", "MacOS");
|
|
5454
|
-
const resources = join3(appDir, "Contents", "Resources");
|
|
5455
|
-
rmSync(appDir, { recursive: true, force: true });
|
|
5456
|
-
mkdirSync2(macos, { recursive: true });
|
|
5457
|
-
mkdirSync2(resources, { recursive: true });
|
|
5458
|
-
writeFileSync(join3(appDir, "Contents", "Info.plist"), `<?xml version="1.0" encoding="UTF-8"?>
|
|
5459
|
-
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
5460
|
-
<plist version="1.0"><dict>
|
|
5461
|
-
<key>CFBundleName</key><string>Toyon</string>
|
|
5462
|
-
<key>CFBundleDisplayName</key><string>Toyon</string>
|
|
5463
|
-
<key>CFBundleIdentifier</key><string>dev.toyon.app</string>
|
|
5464
|
-
<key>CFBundleVersion</key><string>0.0.1</string>
|
|
5465
|
-
<key>CFBundlePackageType</key><string>APPL</string>
|
|
5466
|
-
<key>CFBundleExecutable</key><string>Toyon</string>
|
|
5467
|
-
<key>CFBundleIconFile</key><string>AppIcon</string>
|
|
5468
|
-
<!-- takes any file or folder dropped on it, without becoming the default opener for anything -->
|
|
5469
|
-
<key>CFBundleDocumentTypes</key>
|
|
5470
|
-
<array>
|
|
5471
|
-
<dict>
|
|
5472
|
-
<key>CFBundleTypeName</key><string>Anything</string>
|
|
5473
|
-
<key>CFBundleTypeRole</key><string>Editor</string>
|
|
5474
|
-
<key>LSHandlerRank</key><string>Alternate</string>
|
|
5475
|
-
<key>LSItemContentTypes</key>
|
|
5476
|
-
<array>
|
|
5477
|
-
<string>public.item</string>
|
|
5478
|
-
<string>public.folder</string>
|
|
5479
|
-
</array>
|
|
5480
|
-
</dict>
|
|
5481
|
-
</array>
|
|
5482
|
-
</dict></plist>
|
|
5483
|
-
`);
|
|
5484
|
-
const launcher = join3(resources, "launch.sh");
|
|
5485
|
-
writeFileSync(launcher, `#!/bin/bash
|
|
5486
|
-
# Finder launches get a minimal PATH; find bun ourselves
|
|
5487
|
-
BUN=""
|
|
5488
|
-
for CAND in "$HOME/.bun/bin/bun" /opt/homebrew/bin/bun /usr/local/bin/bun; do
|
|
5489
|
-
[ -x "$CAND" ] && BUN="$CAND" && break
|
|
5490
|
-
done
|
|
5491
|
-
|
|
5492
|
-
# start the daemon if it isn't running
|
|
5493
|
-
if ! curl -s --max-time 1 http://127.0.0.1:${port}/health >/dev/null 2>&1; then
|
|
5494
|
-
if [ -n "$BUN" ] && [ -f "${daemonEntry}" ]; then
|
|
5495
|
-
nohup "$BUN" run "${daemonEntry}" >> "$HOME/.toyon/daemon.log" 2>&1 &
|
|
5496
|
-
for _ in $(seq 1 40); do
|
|
5497
|
-
curl -s --max-time 1 http://127.0.0.1:${port}/health >/dev/null 2>&1 && break
|
|
5498
|
-
sleep 0.25
|
|
5499
|
-
done
|
|
5500
|
-
fi
|
|
5501
|
-
fi
|
|
5502
|
-
|
|
5503
|
-
TOKEN=$(cat "$HOME/.toyon/token" 2>/dev/null)
|
|
5504
|
-
|
|
5505
|
-
# what was dropped on the icon, or opened with it: each path goes to the daemon, which opens a
|
|
5506
|
-
# project, a file in one, or a file on its own, and holds it for the window opened below. A
|
|
5507
|
-
# refusal is logged in the daemon's words, since nothing here has a screen (the daemon says it in
|
|
5508
|
-
# the shell too); a success is logged as its status alone, since the reply carries the file's text.
|
|
5509
|
-
for P in "$@"; do
|
|
5510
|
-
BODY=$("$BUN" -e 'console.log(JSON.stringify({ path: process.argv[1] }))' "$P" 2>/dev/null) || continue
|
|
5511
|
-
REPLY=$(curl -s -o /dev/null -w '%{http_code}' -X POST -H "Authorization: Bearer $TOKEN" \\
|
|
5512
|
-
-H "content-type: application/json" --data "$BODY" http://127.0.0.1:${port}/open 2>/dev/null)
|
|
5513
|
-
if [ "$REPLY" != "200" ]; then
|
|
5514
|
-
REPLY="$REPLY $(curl -s -X POST -H "Authorization: Bearer $TOKEN" -H "content-type: application/json" \\
|
|
5515
|
-
--data "$BODY" http://127.0.0.1:${port}/open 2>&1 | head -c 300)"
|
|
5516
|
-
fi
|
|
5517
|
-
echo "$(date '+%Y-%m-%d %H:%M:%S') open $P: $REPLY" >> "$HOME/.toyon/launcher.log"
|
|
5518
|
-
done
|
|
5519
|
-
|
|
5520
|
-
URL="http://toyon.localhost:${port}/#token=$TOKEN"
|
|
5521
|
-
MANIFEST_ID="${manifestId}"
|
|
5522
|
-
CACHE_DIR="$HOME/.toyon/pwa"
|
|
5523
|
-
# installed PWA (native-style title bar) if any profile has it, else a plain app window.
|
|
5524
|
-
# The app id lives in the browser's sync DB right before the manifest id; cache it once found.
|
|
5525
|
-
find_pwa_id() { # $1 = data dir, $2 = cache file
|
|
5526
|
-
local root="$HOME/Library/Application Support/$1" id p f
|
|
5527
|
-
if [ -f "$2" ]; then
|
|
5528
|
-
id=$(tr -d '[:space:]' < "$2")
|
|
5529
|
-
for p in "$root"/*/; do [ -d "$p/Web Applications/Manifest Resources/$id" ] && { echo "$id"; return; }; done
|
|
5530
|
-
fi
|
|
5531
|
-
for p in "$root"/*/; do
|
|
5532
|
-
for f in "$p/Sync Data/LevelDB/"*.log "$p/Sync Data/LevelDB/"*.ldb; do
|
|
5533
|
-
[ -f "$f" ] || continue
|
|
5534
|
-
# the record straddles newline bytes, so flatten before the line-based grep
|
|
5535
|
-
id=$(LC_ALL=C tr '\\n\\0' ' ' < "$f" | LC_ALL=C grep -aoE "web_apps-dt-[a-p]{32}.{0,16}$MANIFEST_ID" 2>/dev/null | head -1 | LC_ALL=C sed -E 's/^web_apps-dt-([a-p]{32}).*/\\1/')
|
|
5536
|
-
if [ -n "$id" ] && [ -d "$p/Web Applications/Manifest Resources/$id" ]; then
|
|
5537
|
-
mkdir -p "$CACHE_DIR" && printf '%s' "$id" > "$2"; echo "$id"; return
|
|
5538
|
-
fi
|
|
5539
|
-
done
|
|
5540
|
-
done
|
|
5541
|
-
}
|
|
5542
|
-
launch() { # $1 = browser name, $2 = data dir
|
|
5543
|
-
local id; id=$(find_pwa_id "$2" "$CACHE_DIR/$(echo "$1" | tr -c 'A-Za-z0-9
|
|
5544
|
-
' '-').id")
|
|
5545
|
-
if [ -n "$id" ]; then exec open -na "$1" --args --app-id="$id"; fi
|
|
5546
|
-
exec open -na "$1" --args --app="$URL"
|
|
5547
|
-
}
|
|
5548
|
-
${CHROMIUMS.map((a) => `if open -Ra "${a}" 2>/dev/null; then launch "${a}" "${DATA_DIRS[a]}"; fi`).join(`
|
|
5549
|
-
`)}
|
|
5550
|
-
exec open "$URL"
|
|
5551
|
-
`);
|
|
5552
|
-
chmodSync(launcher, 493);
|
|
5553
|
-
const stub = join3(macos, "Toyon");
|
|
5554
|
-
const src = join3(home, "launcher.m");
|
|
5555
|
-
writeFileSync(src, launcher_default);
|
|
5556
|
-
const cc = spawnSync("clang", ["-O2", "-fobjc-arc", "-framework", "Cocoa", "-o", stub, src], { stdio: "ignore" });
|
|
5557
|
-
if (cc.status !== 0) {
|
|
5558
|
-
writeFileSync(stub, `#!/bin/bash
|
|
5559
|
-
exec /bin/bash "$(dirname "$0")/../Resources/launch.sh"
|
|
5560
|
-
`);
|
|
5561
|
-
chmodSync(stub, 493);
|
|
5562
|
-
}
|
|
5563
|
-
try {
|
|
5564
|
-
const svg = iconSvg;
|
|
5565
|
-
const tmp = join3(home, "iconset.tmp");
|
|
5566
|
-
const iconset = join3(tmp, "AppIcon.iconset");
|
|
5567
|
-
mkdirSync2(iconset, { recursive: true });
|
|
5568
|
-
spawnSync("qlmanage", ["-t", "-s", "1024", "-o", tmp, svg], { stdio: "ignore" });
|
|
5569
|
-
const big = join3(tmp, "icon.svg.png");
|
|
5570
|
-
if (existsSync3(big)) {
|
|
5571
|
-
for (const size of [16, 32, 64, 128, 256, 512, 1024]) {
|
|
5572
|
-
spawnSync("sips", ["-z", String(size), String(size), big, "--out", join3(iconset, `icon_${size}x${size}.png`)], {
|
|
5573
|
-
stdio: "ignore"
|
|
5574
|
-
});
|
|
5575
|
-
}
|
|
5576
|
-
spawnSync("iconutil", ["-c", "icns", iconset, "-o", join3(resources, "AppIcon.icns")], { stdio: "ignore" });
|
|
5577
|
-
}
|
|
5578
|
-
} catch {}
|
|
5579
|
-
spawnSync("xattr", ["-cr", appDir], { stdio: "ignore" });
|
|
5580
|
-
const signed = spawnSync("codesign", ["--force", "--deep", "-s", "-", appDir], { stdio: "ignore" }).status === 0;
|
|
5581
|
-
if (!signed)
|
|
5582
|
-
console.warn("warning: could not codesign the app bundle; macOS may refuse to open it");
|
|
5583
|
-
console.log(`installed ${appDir}; launch "Toyon" from Spotlight or drag it to the Dock`);
|
|
5584
|
-
spawn2("open", ["-a", appDir], { stdio: "ignore" }).unref();
|
|
5585
|
-
}
|
|
5586
5456
|
|
|
5587
5457
|
// src/args.ts
|
|
5588
5458
|
var VERBS = new Set([
|
|
5459
|
+
"start",
|
|
5460
|
+
"helper",
|
|
5589
5461
|
"stop",
|
|
5590
5462
|
"restart",
|
|
5591
5463
|
"update",
|
|
@@ -5607,6 +5479,9 @@ function parseArgs(argv) {
|
|
|
5607
5479
|
const [first, ...rest] = argv;
|
|
5608
5480
|
if (first !== undefined && VERBS.has(first)) {
|
|
5609
5481
|
switch (first) {
|
|
5482
|
+
case "helper":
|
|
5483
|
+
return { kind: "helper", args: rest };
|
|
5484
|
+
case "start":
|
|
5610
5485
|
case "stop":
|
|
5611
5486
|
case "restart":
|
|
5612
5487
|
case "update":
|
|
@@ -5658,12 +5533,9 @@ function parseArgs(argv) {
|
|
|
5658
5533
|
}
|
|
5659
5534
|
let path = null;
|
|
5660
5535
|
let app = false;
|
|
5661
|
-
let installApp = false;
|
|
5662
5536
|
for (const a of argv) {
|
|
5663
5537
|
if (a === "--app" || a === "--pwa")
|
|
5664
5538
|
app = true;
|
|
5665
|
-
else if (a === "--install-app")
|
|
5666
|
-
installApp = true;
|
|
5667
5539
|
else if (a.startsWith("-"))
|
|
5668
5540
|
return { kind: "error", message: `unknown option ${a}` };
|
|
5669
5541
|
else if (path !== null)
|
|
@@ -5671,7 +5543,7 @@ function parseArgs(argv) {
|
|
|
5671
5543
|
else
|
|
5672
5544
|
path = a;
|
|
5673
5545
|
}
|
|
5674
|
-
return { kind: "open", path, app
|
|
5546
|
+
return { kind: "open", path, app };
|
|
5675
5547
|
}
|
|
5676
5548
|
function parseLogs(rest) {
|
|
5677
5549
|
let follow = false;
|
|
@@ -5739,6 +5611,7 @@ usage
|
|
|
5739
5611
|
toyon [path] start the daemon if it is not running, register the repo at path
|
|
5740
5612
|
(or open the file at path: in its project, or on its own)
|
|
5741
5613
|
(default: the current directory) and open the shell
|
|
5614
|
+
toyon start start the daemon if it is not running, and open nothing
|
|
5742
5615
|
toyon stop stop the daemon and every dev server and agent it runs
|
|
5743
5616
|
toyon restart stop the daemon and start it again from what is installed now; every
|
|
5744
5617
|
shell reconnects on its own
|
|
@@ -5757,9 +5630,9 @@ usage
|
|
|
5757
5630
|
toyon remote --tailscale
|
|
5758
5631
|
open the shell from your tailnet at this machine's Tailscale name:
|
|
5759
5632
|
sets up tailscale serve for Toyon and ports 10001-10008
|
|
5760
|
-
toyon pair
|
|
5761
|
-
|
|
5762
|
-
|
|
5633
|
+
toyon pair show this machine's address as a QR code for your phone, and let in
|
|
5634
|
+
each device that opens it, from this terminal; Toyon's window asks
|
|
5635
|
+
the same question when one is open
|
|
5763
5636
|
toyon deploy fly up <name> [--region code] [--repo url]
|
|
5764
5637
|
run Toyon on your own Fly account at https://name.fly.dev with your own
|
|
5765
5638
|
keys; --repo clones that repository onto it the first time
|
|
@@ -5770,7 +5643,6 @@ usage
|
|
|
5770
5643
|
|
|
5771
5644
|
options for toyon [path]
|
|
5772
5645
|
--app open a Chromium app window (the installed Toyon app when there is one)
|
|
5773
|
-
--install-app write ~/Applications/Toyon.app and open it
|
|
5774
5646
|
|
|
5775
5647
|
environment
|
|
5776
5648
|
TOYON_HOME where state lives (default ~/.toyon)
|
|
@@ -5786,7 +5658,7 @@ policy
|
|
|
5786
5658
|
// src/deploy/fly.ts
|
|
5787
5659
|
import { randomBytes } from "crypto";
|
|
5788
5660
|
import { Resolver } from "dns/promises";
|
|
5789
|
-
import { existsSync as existsSync5, mkdirSync as mkdirSync4, mkdtempSync, readFileSync as readFileSync4, rmSync
|
|
5661
|
+
import { existsSync as existsSync5, mkdirSync as mkdirSync4, mkdtempSync, readFileSync as readFileSync4, rmSync, writeFileSync as writeFileSync3 } from "fs";
|
|
5790
5662
|
import { tmpdir } from "os";
|
|
5791
5663
|
import { join as join5 } from "path";
|
|
5792
5664
|
|
|
@@ -5839,14 +5711,6 @@ function safeUser() {
|
|
|
5839
5711
|
}
|
|
5840
5712
|
}
|
|
5841
5713
|
|
|
5842
|
-
// src/openUrl.ts
|
|
5843
|
-
import { spawn as spawn3 } from "child_process";
|
|
5844
|
-
function openUrl(url) {
|
|
5845
|
-
const child = spawn3(process.platform === "darwin" ? "open" : "xdg-open", [url], { stdio: "ignore" });
|
|
5846
|
-
child.on("error", () => {});
|
|
5847
|
-
child.unref();
|
|
5848
|
-
}
|
|
5849
|
-
|
|
5850
5714
|
// src/policy.ts
|
|
5851
5715
|
function refusedByPolicy(verb, m) {
|
|
5852
5716
|
console.error(`toyon: ${verb} is turned off by your organization's policy (${m.source ?? "policy"})`);
|
|
@@ -6075,7 +5939,7 @@ async function up(cmd, bin) {
|
|
|
6075
5939
|
throw new DeployError("the deploy failed; flyctl's output above says why");
|
|
6076
5940
|
}
|
|
6077
5941
|
} finally {
|
|
6078
|
-
|
|
5942
|
+
rmSync(ctx, { recursive: true, force: true });
|
|
6079
5943
|
}
|
|
6080
5944
|
console.log("waiting for the machine to answer");
|
|
6081
5945
|
let up = false;
|
|
@@ -6088,15 +5952,20 @@ async function up(cmd, bin) {
|
|
|
6088
5952
|
}
|
|
6089
5953
|
if (!up)
|
|
6090
5954
|
console.log(`it has not answered yet; \`fly logs -a ${cmd.name}\` shows what it is doing`);
|
|
6091
|
-
printLinks(cmd.name, token);
|
|
5955
|
+
await printLinks(cmd.name, token);
|
|
6092
5956
|
console.log("the volume holds the only copy of anything not pushed to a remote");
|
|
6093
|
-
openUrl(launcherAddLink(`https://${cmd.name}.fly.dev`));
|
|
6094
5957
|
}
|
|
6095
|
-
function printLinks(app, token) {
|
|
5958
|
+
async function printLinks(app, token) {
|
|
5959
|
+
const origin = `https://${app}.fly.dev`;
|
|
5960
|
+
const handed = (await daemonFetch("/machines", { body: { origin, token } }))?.ok === true;
|
|
5961
|
+
if (handed) {
|
|
5962
|
+
console.log(`
|
|
5963
|
+
toyon: ${app}.fly.dev is in your list; open Toyon here to use it, and pair your phone from there`);
|
|
5964
|
+
return;
|
|
5965
|
+
}
|
|
6096
5966
|
console.log(`
|
|
6097
|
-
toyon:
|
|
5967
|
+
toyon: ${origin}/#token=${token}`);
|
|
6098
5968
|
console.log("the link grants a shell on that machine; keep it to yourself");
|
|
6099
|
-
console.log(`add it to your list at toyon.cloud: ${launcherAddLink(`https://${app}.fly.dev`)}`);
|
|
6100
5969
|
}
|
|
6101
5970
|
async function destroy(cmd, bin) {
|
|
6102
5971
|
if (!cmd.yes) {
|
|
@@ -6114,7 +5983,7 @@ async function destroy(cmd, bin) {
|
|
|
6114
5983
|
}
|
|
6115
5984
|
}
|
|
6116
5985
|
must(await capture(bin, ["apps", "destroy", cmd.name, "--yes"]), "could not delete the app");
|
|
6117
|
-
|
|
5986
|
+
rmSync(tokenFile2(cmd.name), { force: true });
|
|
6118
5987
|
console.log(`deleted ${cmd.name}`);
|
|
6119
5988
|
return 0;
|
|
6120
5989
|
}
|
|
@@ -6133,7 +6002,7 @@ async function deploy(cmd) {
|
|
|
6133
6002
|
else if (cmd.action === "destroy")
|
|
6134
6003
|
return await destroy(cmd, bin);
|
|
6135
6004
|
else if (existsSync5(tokenFile2(cmd.name))) {
|
|
6136
|
-
printLinks(cmd.name, readFileSync4(tokenFile2(cmd.name), "utf8").trim());
|
|
6005
|
+
await printLinks(cmd.name, readFileSync4(tokenFile2(cmd.name), "utf8").trim());
|
|
6137
6006
|
} else {
|
|
6138
6007
|
throw new DeployError(`${cmd.name} was not deployed from this machine; its token is not in ${cloudDir}`);
|
|
6139
6008
|
}
|
|
@@ -6318,6 +6187,41 @@ async function doctor() {
|
|
|
6318
6187
|
return lines.every((l) => l.ok) ? 0 : 1;
|
|
6319
6188
|
}
|
|
6320
6189
|
|
|
6190
|
+
// src/helper.ts
|
|
6191
|
+
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
6192
|
+
function planHelper(args) {
|
|
6193
|
+
if (args.some((a) => a.startsWith(`${APP_SCHEME}:`)))
|
|
6194
|
+
return { kind: "start" };
|
|
6195
|
+
const paths = [];
|
|
6196
|
+
for (const a of args) {
|
|
6197
|
+
if (a.startsWith("file:")) {
|
|
6198
|
+
try {
|
|
6199
|
+
const p = fileURLToPath2(a);
|
|
6200
|
+
if (p !== "" && p !== "/")
|
|
6201
|
+
paths.push(p);
|
|
6202
|
+
} catch {}
|
|
6203
|
+
} else if (a !== "")
|
|
6204
|
+
paths.push(a);
|
|
6205
|
+
}
|
|
6206
|
+
return paths.length === 0 ? { kind: "start" } : { kind: "open", paths };
|
|
6207
|
+
}
|
|
6208
|
+
async function helper(args) {
|
|
6209
|
+
const plan = planHelper(args);
|
|
6210
|
+
console.log(`toyon helper: ${args.length > 0 ? args.join(" ") : "(nothing)"}`);
|
|
6211
|
+
const daemon = await ensureDaemon();
|
|
6212
|
+
if (!daemon)
|
|
6213
|
+
return 1;
|
|
6214
|
+
if (plan.kind === "start")
|
|
6215
|
+
return 0;
|
|
6216
|
+
for (const path of plan.paths) {
|
|
6217
|
+
const res = await post("/open", daemon.token, { path });
|
|
6218
|
+
if (!res.ok)
|
|
6219
|
+
console.error(`could not open ${path}: ${await res.text()}`);
|
|
6220
|
+
}
|
|
6221
|
+
showAppWindow(daemon);
|
|
6222
|
+
return 0;
|
|
6223
|
+
}
|
|
6224
|
+
|
|
6321
6225
|
// src/logs.ts
|
|
6322
6226
|
import { existsSync as existsSync7, readFileSync as readFileSync6, statSync as statSync3 } from "fs";
|
|
6323
6227
|
async function logs(opts) {
|
|
@@ -6353,1685 +6257,36 @@ async function logs(opts) {
|
|
|
6353
6257
|
}
|
|
6354
6258
|
}
|
|
6355
6259
|
|
|
6356
|
-
//
|
|
6357
|
-
|
|
6358
|
-
|
|
6359
|
-
|
|
6360
|
-
|
|
6361
|
-
|
|
6362
|
-
|
|
6363
|
-
|
|
6364
|
-
|
|
6365
|
-
|
|
6366
|
-
|
|
6367
|
-
|
|
6368
|
-
|
|
6369
|
-
|
|
6370
|
-
|
|
6371
|
-
|
|
6372
|
-
|
|
6373
|
-
|
|
6374
|
-
|
|
6375
|
-
|
|
6376
|
-
|
|
6377
|
-
|
|
6378
|
-
|
|
6379
|
-
|
|
6380
|
-
|
|
6381
|
-
|
|
6382
|
-
|
|
6383
|
-
|
|
6384
|
-
|
|
6385
|
-
|
|
6386
|
-
setupTypeNumber(test);
|
|
6387
|
-
}
|
|
6388
|
-
if (_dataCache == null) {
|
|
6389
|
-
_dataCache = createData(_typeNumber, _errorCorrectionLevel, _dataList);
|
|
6390
|
-
}
|
|
6391
|
-
mapData(_dataCache, maskPattern);
|
|
6392
|
-
};
|
|
6393
|
-
const setupPositionProbePattern = function(row, col) {
|
|
6394
|
-
for (let r = -1;r <= 7; r += 1) {
|
|
6395
|
-
if (row + r <= -1 || _moduleCount <= row + r)
|
|
6396
|
-
continue;
|
|
6397
|
-
for (let c = -1;c <= 7; c += 1) {
|
|
6398
|
-
if (col + c <= -1 || _moduleCount <= col + c)
|
|
6399
|
-
continue;
|
|
6400
|
-
if (0 <= r && r <= 6 && (c == 0 || c == 6) || 0 <= c && c <= 6 && (r == 0 || r == 6) || 2 <= r && r <= 4 && 2 <= c && c <= 4) {
|
|
6401
|
-
_modules[row + r][col + c] = true;
|
|
6402
|
-
} else {
|
|
6403
|
-
_modules[row + r][col + c] = false;
|
|
6404
|
-
}
|
|
6405
|
-
}
|
|
6406
|
-
}
|
|
6407
|
-
};
|
|
6408
|
-
const getBestMaskPattern = function() {
|
|
6409
|
-
let minLostPoint = 0;
|
|
6410
|
-
let pattern = 0;
|
|
6411
|
-
for (let i = 0;i < 8; i += 1) {
|
|
6412
|
-
makeImpl(true, i);
|
|
6413
|
-
const lostPoint = QRUtil.getLostPoint(_this);
|
|
6414
|
-
if (i == 0 || minLostPoint > lostPoint) {
|
|
6415
|
-
minLostPoint = lostPoint;
|
|
6416
|
-
pattern = i;
|
|
6417
|
-
}
|
|
6418
|
-
}
|
|
6419
|
-
return pattern;
|
|
6420
|
-
};
|
|
6421
|
-
const setupTimingPattern = function() {
|
|
6422
|
-
for (let r = 8;r < _moduleCount - 8; r += 1) {
|
|
6423
|
-
if (_modules[r][6] != null) {
|
|
6424
|
-
continue;
|
|
6425
|
-
}
|
|
6426
|
-
_modules[r][6] = r % 2 == 0;
|
|
6427
|
-
}
|
|
6428
|
-
for (let c = 8;c < _moduleCount - 8; c += 1) {
|
|
6429
|
-
if (_modules[6][c] != null) {
|
|
6430
|
-
continue;
|
|
6431
|
-
}
|
|
6432
|
-
_modules[6][c] = c % 2 == 0;
|
|
6433
|
-
}
|
|
6434
|
-
};
|
|
6435
|
-
const setupPositionAdjustPattern = function() {
|
|
6436
|
-
const pos = QRUtil.getPatternPosition(_typeNumber);
|
|
6437
|
-
for (let i = 0;i < pos.length; i += 1) {
|
|
6438
|
-
for (let j = 0;j < pos.length; j += 1) {
|
|
6439
|
-
const row = pos[i];
|
|
6440
|
-
const col = pos[j];
|
|
6441
|
-
if (_modules[row][col] != null) {
|
|
6442
|
-
continue;
|
|
6443
|
-
}
|
|
6444
|
-
for (let r = -2;r <= 2; r += 1) {
|
|
6445
|
-
for (let c = -2;c <= 2; c += 1) {
|
|
6446
|
-
if (r == -2 || r == 2 || c == -2 || c == 2 || r == 0 && c == 0) {
|
|
6447
|
-
_modules[row + r][col + c] = true;
|
|
6448
|
-
} else {
|
|
6449
|
-
_modules[row + r][col + c] = false;
|
|
6450
|
-
}
|
|
6451
|
-
}
|
|
6452
|
-
}
|
|
6453
|
-
}
|
|
6454
|
-
}
|
|
6455
|
-
};
|
|
6456
|
-
const setupTypeNumber = function(test) {
|
|
6457
|
-
const bits = QRUtil.getBCHTypeNumber(_typeNumber);
|
|
6458
|
-
for (let i = 0;i < 18; i += 1) {
|
|
6459
|
-
const mod = !test && (bits >> i & 1) == 1;
|
|
6460
|
-
_modules[Math.floor(i / 3)][i % 3 + _moduleCount - 8 - 3] = mod;
|
|
6461
|
-
}
|
|
6462
|
-
for (let i = 0;i < 18; i += 1) {
|
|
6463
|
-
const mod = !test && (bits >> i & 1) == 1;
|
|
6464
|
-
_modules[i % 3 + _moduleCount - 8 - 3][Math.floor(i / 3)] = mod;
|
|
6465
|
-
}
|
|
6466
|
-
};
|
|
6467
|
-
const setupTypeInfo = function(test, maskPattern) {
|
|
6468
|
-
const data = _errorCorrectionLevel << 3 | maskPattern;
|
|
6469
|
-
const bits = QRUtil.getBCHTypeInfo(data);
|
|
6470
|
-
for (let i = 0;i < 15; i += 1) {
|
|
6471
|
-
const mod = !test && (bits >> i & 1) == 1;
|
|
6472
|
-
if (i < 6) {
|
|
6473
|
-
_modules[i][8] = mod;
|
|
6474
|
-
} else if (i < 8) {
|
|
6475
|
-
_modules[i + 1][8] = mod;
|
|
6476
|
-
} else {
|
|
6477
|
-
_modules[_moduleCount - 15 + i][8] = mod;
|
|
6478
|
-
}
|
|
6479
|
-
}
|
|
6480
|
-
for (let i = 0;i < 15; i += 1) {
|
|
6481
|
-
const mod = !test && (bits >> i & 1) == 1;
|
|
6482
|
-
if (i < 8) {
|
|
6483
|
-
_modules[8][_moduleCount - i - 1] = mod;
|
|
6484
|
-
} else if (i < 9) {
|
|
6485
|
-
_modules[8][15 - i - 1 + 1] = mod;
|
|
6486
|
-
} else {
|
|
6487
|
-
_modules[8][15 - i - 1] = mod;
|
|
6488
|
-
}
|
|
6489
|
-
}
|
|
6490
|
-
_modules[_moduleCount - 8][8] = !test;
|
|
6491
|
-
};
|
|
6492
|
-
const mapData = function(data, maskPattern) {
|
|
6493
|
-
let inc = -1;
|
|
6494
|
-
let row = _moduleCount - 1;
|
|
6495
|
-
let bitIndex = 7;
|
|
6496
|
-
let byteIndex = 0;
|
|
6497
|
-
const maskFunc = QRUtil.getMaskFunction(maskPattern);
|
|
6498
|
-
for (let col = _moduleCount - 1;col > 0; col -= 2) {
|
|
6499
|
-
if (col == 6)
|
|
6500
|
-
col -= 1;
|
|
6501
|
-
while (true) {
|
|
6502
|
-
for (let c = 0;c < 2; c += 1) {
|
|
6503
|
-
if (_modules[row][col - c] == null) {
|
|
6504
|
-
let dark = false;
|
|
6505
|
-
if (byteIndex < data.length) {
|
|
6506
|
-
dark = (data[byteIndex] >>> bitIndex & 1) == 1;
|
|
6507
|
-
}
|
|
6508
|
-
const mask = maskFunc(row, col - c);
|
|
6509
|
-
if (mask) {
|
|
6510
|
-
dark = !dark;
|
|
6511
|
-
}
|
|
6512
|
-
_modules[row][col - c] = dark;
|
|
6513
|
-
bitIndex -= 1;
|
|
6514
|
-
if (bitIndex == -1) {
|
|
6515
|
-
byteIndex += 1;
|
|
6516
|
-
bitIndex = 7;
|
|
6517
|
-
}
|
|
6518
|
-
}
|
|
6519
|
-
}
|
|
6520
|
-
row += inc;
|
|
6521
|
-
if (row < 0 || _moduleCount <= row) {
|
|
6522
|
-
row -= inc;
|
|
6523
|
-
inc = -inc;
|
|
6524
|
-
break;
|
|
6525
|
-
}
|
|
6526
|
-
}
|
|
6527
|
-
}
|
|
6528
|
-
};
|
|
6529
|
-
const createBytes = function(buffer, rsBlocks) {
|
|
6530
|
-
let offset = 0;
|
|
6531
|
-
let maxDcCount = 0;
|
|
6532
|
-
let maxEcCount = 0;
|
|
6533
|
-
const dcdata = new Array(rsBlocks.length);
|
|
6534
|
-
const ecdata = new Array(rsBlocks.length);
|
|
6535
|
-
for (let r = 0;r < rsBlocks.length; r += 1) {
|
|
6536
|
-
const dcCount = rsBlocks[r].dataCount;
|
|
6537
|
-
const ecCount = rsBlocks[r].totalCount - dcCount;
|
|
6538
|
-
maxDcCount = Math.max(maxDcCount, dcCount);
|
|
6539
|
-
maxEcCount = Math.max(maxEcCount, ecCount);
|
|
6540
|
-
dcdata[r] = new Array(dcCount);
|
|
6541
|
-
for (let i = 0;i < dcdata[r].length; i += 1) {
|
|
6542
|
-
dcdata[r][i] = 255 & buffer.getBuffer()[i + offset];
|
|
6543
|
-
}
|
|
6544
|
-
offset += dcCount;
|
|
6545
|
-
const rsPoly = QRUtil.getErrorCorrectPolynomial(ecCount);
|
|
6546
|
-
const rawPoly = qrPolynomial(dcdata[r], rsPoly.getLength() - 1);
|
|
6547
|
-
const modPoly = rawPoly.mod(rsPoly);
|
|
6548
|
-
ecdata[r] = new Array(rsPoly.getLength() - 1);
|
|
6549
|
-
for (let i = 0;i < ecdata[r].length; i += 1) {
|
|
6550
|
-
const modIndex = i + modPoly.getLength() - ecdata[r].length;
|
|
6551
|
-
ecdata[r][i] = modIndex >= 0 ? modPoly.getAt(modIndex) : 0;
|
|
6552
|
-
}
|
|
6553
|
-
}
|
|
6554
|
-
let totalCodeCount = 0;
|
|
6555
|
-
for (let i = 0;i < rsBlocks.length; i += 1) {
|
|
6556
|
-
totalCodeCount += rsBlocks[i].totalCount;
|
|
6557
|
-
}
|
|
6558
|
-
const data = new Array(totalCodeCount);
|
|
6559
|
-
let index = 0;
|
|
6560
|
-
for (let i = 0;i < maxDcCount; i += 1) {
|
|
6561
|
-
for (let r = 0;r < rsBlocks.length; r += 1) {
|
|
6562
|
-
if (i < dcdata[r].length) {
|
|
6563
|
-
data[index] = dcdata[r][i];
|
|
6564
|
-
index += 1;
|
|
6565
|
-
}
|
|
6566
|
-
}
|
|
6567
|
-
}
|
|
6568
|
-
for (let i = 0;i < maxEcCount; i += 1) {
|
|
6569
|
-
for (let r = 0;r < rsBlocks.length; r += 1) {
|
|
6570
|
-
if (i < ecdata[r].length) {
|
|
6571
|
-
data[index] = ecdata[r][i];
|
|
6572
|
-
index += 1;
|
|
6573
|
-
}
|
|
6574
|
-
}
|
|
6575
|
-
}
|
|
6576
|
-
return data;
|
|
6577
|
-
};
|
|
6578
|
-
const createData = function(typeNumber, errorCorrectionLevel, dataList) {
|
|
6579
|
-
const rsBlocks = QRRSBlock.getRSBlocks(typeNumber, errorCorrectionLevel);
|
|
6580
|
-
const buffer = qrBitBuffer();
|
|
6581
|
-
for (let i = 0;i < dataList.length; i += 1) {
|
|
6582
|
-
const data = dataList[i];
|
|
6583
|
-
buffer.put(data.getMode(), 4);
|
|
6584
|
-
buffer.put(data.getLength(), QRUtil.getLengthInBits(data.getMode(), typeNumber));
|
|
6585
|
-
data.write(buffer);
|
|
6586
|
-
}
|
|
6587
|
-
let totalDataCount = 0;
|
|
6588
|
-
for (let i = 0;i < rsBlocks.length; i += 1) {
|
|
6589
|
-
totalDataCount += rsBlocks[i].dataCount;
|
|
6590
|
-
}
|
|
6591
|
-
if (buffer.getLengthInBits() > totalDataCount * 8) {
|
|
6592
|
-
throw "code length overflow. (" + buffer.getLengthInBits() + ">" + totalDataCount * 8 + ")";
|
|
6593
|
-
}
|
|
6594
|
-
if (buffer.getLengthInBits() + 4 <= totalDataCount * 8) {
|
|
6595
|
-
buffer.put(0, 4);
|
|
6596
|
-
}
|
|
6597
|
-
while (buffer.getLengthInBits() % 8 != 0) {
|
|
6598
|
-
buffer.putBit(false);
|
|
6599
|
-
}
|
|
6600
|
-
while (true) {
|
|
6601
|
-
if (buffer.getLengthInBits() >= totalDataCount * 8) {
|
|
6602
|
-
break;
|
|
6603
|
-
}
|
|
6604
|
-
buffer.put(PAD0, 8);
|
|
6605
|
-
if (buffer.getLengthInBits() >= totalDataCount * 8) {
|
|
6606
|
-
break;
|
|
6607
|
-
}
|
|
6608
|
-
buffer.put(PAD1, 8);
|
|
6609
|
-
}
|
|
6610
|
-
return createBytes(buffer, rsBlocks);
|
|
6611
|
-
};
|
|
6612
|
-
_this.addData = function(data, mode) {
|
|
6613
|
-
mode = mode || "Byte";
|
|
6614
|
-
let newData = null;
|
|
6615
|
-
switch (mode) {
|
|
6616
|
-
case "Numeric":
|
|
6617
|
-
newData = qrNumber(data);
|
|
6618
|
-
break;
|
|
6619
|
-
case "Alphanumeric":
|
|
6620
|
-
newData = qrAlphaNum(data);
|
|
6621
|
-
break;
|
|
6622
|
-
case "Byte":
|
|
6623
|
-
newData = qr8BitByte(data);
|
|
6624
|
-
break;
|
|
6625
|
-
case "Kanji":
|
|
6626
|
-
newData = qrKanji(data);
|
|
6627
|
-
break;
|
|
6628
|
-
default:
|
|
6629
|
-
throw "mode:" + mode;
|
|
6630
|
-
}
|
|
6631
|
-
_dataList.push(newData);
|
|
6632
|
-
_dataCache = null;
|
|
6633
|
-
};
|
|
6634
|
-
_this.isDark = function(row, col) {
|
|
6635
|
-
if (row < 0 || _moduleCount <= row || col < 0 || _moduleCount <= col) {
|
|
6636
|
-
throw row + "," + col;
|
|
6637
|
-
}
|
|
6638
|
-
return _modules[row][col];
|
|
6639
|
-
};
|
|
6640
|
-
_this.getModuleCount = function() {
|
|
6641
|
-
return _moduleCount;
|
|
6642
|
-
};
|
|
6643
|
-
_this.make = function() {
|
|
6644
|
-
if (_typeNumber < 1) {
|
|
6645
|
-
let typeNumber = 1;
|
|
6646
|
-
for (;typeNumber < 40; typeNumber++) {
|
|
6647
|
-
const rsBlocks = QRRSBlock.getRSBlocks(typeNumber, _errorCorrectionLevel);
|
|
6648
|
-
const buffer = qrBitBuffer();
|
|
6649
|
-
for (let i = 0;i < _dataList.length; i++) {
|
|
6650
|
-
const data = _dataList[i];
|
|
6651
|
-
buffer.put(data.getMode(), 4);
|
|
6652
|
-
buffer.put(data.getLength(), QRUtil.getLengthInBits(data.getMode(), typeNumber));
|
|
6653
|
-
data.write(buffer);
|
|
6654
|
-
}
|
|
6655
|
-
let totalDataCount = 0;
|
|
6656
|
-
for (let i = 0;i < rsBlocks.length; i++) {
|
|
6657
|
-
totalDataCount += rsBlocks[i].dataCount;
|
|
6658
|
-
}
|
|
6659
|
-
if (buffer.getLengthInBits() <= totalDataCount * 8) {
|
|
6660
|
-
break;
|
|
6661
|
-
}
|
|
6662
|
-
}
|
|
6663
|
-
_typeNumber = typeNumber;
|
|
6664
|
-
}
|
|
6665
|
-
makeImpl(false, getBestMaskPattern());
|
|
6666
|
-
};
|
|
6667
|
-
_this.createTableTag = function(cellSize, margin) {
|
|
6668
|
-
cellSize = cellSize || 2;
|
|
6669
|
-
margin = typeof margin == "undefined" ? cellSize * 4 : margin;
|
|
6670
|
-
let qrHtml = "";
|
|
6671
|
-
qrHtml += '<table style="';
|
|
6672
|
-
qrHtml += " border-width: 0px; border-style: none;";
|
|
6673
|
-
qrHtml += " border-collapse: collapse;";
|
|
6674
|
-
qrHtml += " padding: 0px; margin: " + margin + "px;";
|
|
6675
|
-
qrHtml += '">';
|
|
6676
|
-
qrHtml += "<tbody>";
|
|
6677
|
-
for (let r = 0;r < _this.getModuleCount(); r += 1) {
|
|
6678
|
-
qrHtml += "<tr>";
|
|
6679
|
-
for (let c = 0;c < _this.getModuleCount(); c += 1) {
|
|
6680
|
-
qrHtml += '<td style="';
|
|
6681
|
-
qrHtml += " border-width: 0px; border-style: none;";
|
|
6682
|
-
qrHtml += " border-collapse: collapse;";
|
|
6683
|
-
qrHtml += " padding: 0px; margin: 0px;";
|
|
6684
|
-
qrHtml += " width: " + cellSize + "px;";
|
|
6685
|
-
qrHtml += " height: " + cellSize + "px;";
|
|
6686
|
-
qrHtml += " background-color: ";
|
|
6687
|
-
qrHtml += _this.isDark(r, c) ? "#000000" : "#ffffff";
|
|
6688
|
-
qrHtml += ";";
|
|
6689
|
-
qrHtml += '"/>';
|
|
6690
|
-
}
|
|
6691
|
-
qrHtml += "</tr>";
|
|
6692
|
-
}
|
|
6693
|
-
qrHtml += "</tbody>";
|
|
6694
|
-
qrHtml += "</table>";
|
|
6695
|
-
return qrHtml;
|
|
6696
|
-
};
|
|
6697
|
-
_this.createSvgTag = function(cellSize, margin, alt, title) {
|
|
6698
|
-
let opts = {};
|
|
6699
|
-
if (typeof arguments[0] == "object") {
|
|
6700
|
-
opts = arguments[0];
|
|
6701
|
-
cellSize = opts.cellSize;
|
|
6702
|
-
margin = opts.margin;
|
|
6703
|
-
alt = opts.alt;
|
|
6704
|
-
title = opts.title;
|
|
6705
|
-
}
|
|
6706
|
-
cellSize = cellSize || 2;
|
|
6707
|
-
margin = typeof margin == "undefined" ? cellSize * 4 : margin;
|
|
6708
|
-
alt = typeof alt === "string" ? { text: alt } : alt || {};
|
|
6709
|
-
alt.text = alt.text || null;
|
|
6710
|
-
alt.id = alt.text ? alt.id || "qrcode-description" : null;
|
|
6711
|
-
title = typeof title === "string" ? { text: title } : title || {};
|
|
6712
|
-
title.text = title.text || null;
|
|
6713
|
-
title.id = title.text ? title.id || "qrcode-title" : null;
|
|
6714
|
-
const size = _this.getModuleCount() * cellSize + margin * 2;
|
|
6715
|
-
let c, mc, r, mr, qrSvg = "", rect;
|
|
6716
|
-
rect = "l" + cellSize + ",0 0," + cellSize + " -" + cellSize + ",0 0,-" + cellSize + "z ";
|
|
6717
|
-
qrSvg += '<svg version="1.1" xmlns="http://www.w3.org/2000/svg"';
|
|
6718
|
-
qrSvg += !opts.scalable ? ' width="' + size + 'px" height="' + size + 'px"' : "";
|
|
6719
|
-
qrSvg += ' viewBox="0 0 ' + size + " " + size + '" ';
|
|
6720
|
-
qrSvg += ' preserveAspectRatio="xMinYMin meet"';
|
|
6721
|
-
qrSvg += title.text || alt.text ? ' role="img" aria-labelledby="' + escapeXml([title.id, alt.id].join(" ").trim()) + '"' : "";
|
|
6722
|
-
qrSvg += ">";
|
|
6723
|
-
qrSvg += title.text ? '<title id="' + escapeXml(title.id) + '">' + escapeXml(title.text) + "</title>" : "";
|
|
6724
|
-
qrSvg += alt.text ? '<description id="' + escapeXml(alt.id) + '">' + escapeXml(alt.text) + "</description>" : "";
|
|
6725
|
-
qrSvg += '<rect width="100%" height="100%" fill="white" cx="0" cy="0"/>';
|
|
6726
|
-
qrSvg += '<path d="';
|
|
6727
|
-
for (r = 0;r < _this.getModuleCount(); r += 1) {
|
|
6728
|
-
mr = r * cellSize + margin;
|
|
6729
|
-
for (c = 0;c < _this.getModuleCount(); c += 1) {
|
|
6730
|
-
if (_this.isDark(r, c)) {
|
|
6731
|
-
mc = c * cellSize + margin;
|
|
6732
|
-
qrSvg += "M" + mc + "," + mr + rect;
|
|
6733
|
-
}
|
|
6734
|
-
}
|
|
6735
|
-
}
|
|
6736
|
-
qrSvg += '" stroke="transparent" fill="black"/>';
|
|
6737
|
-
qrSvg += "</svg>";
|
|
6738
|
-
return qrSvg;
|
|
6739
|
-
};
|
|
6740
|
-
_this.createDataURL = function(cellSize, margin) {
|
|
6741
|
-
cellSize = cellSize || 2;
|
|
6742
|
-
margin = typeof margin == "undefined" ? cellSize * 4 : margin;
|
|
6743
|
-
const size = _this.getModuleCount() * cellSize + margin * 2;
|
|
6744
|
-
const min = margin;
|
|
6745
|
-
const max = size - margin;
|
|
6746
|
-
return createDataURL(size, size, function(x, y) {
|
|
6747
|
-
if (min <= x && x < max && min <= y && y < max) {
|
|
6748
|
-
const c = Math.floor((x - min) / cellSize);
|
|
6749
|
-
const r = Math.floor((y - min) / cellSize);
|
|
6750
|
-
return _this.isDark(r, c) ? 0 : 1;
|
|
6751
|
-
} else {
|
|
6752
|
-
return 1;
|
|
6753
|
-
}
|
|
6754
|
-
});
|
|
6755
|
-
};
|
|
6756
|
-
_this.createImgTag = function(cellSize, margin, alt) {
|
|
6757
|
-
cellSize = cellSize || 2;
|
|
6758
|
-
margin = typeof margin == "undefined" ? cellSize * 4 : margin;
|
|
6759
|
-
const size = _this.getModuleCount() * cellSize + margin * 2;
|
|
6760
|
-
let img = "";
|
|
6761
|
-
img += "<img";
|
|
6762
|
-
img += ' src="';
|
|
6763
|
-
img += _this.createDataURL(cellSize, margin);
|
|
6764
|
-
img += '"';
|
|
6765
|
-
img += ' width="';
|
|
6766
|
-
img += size;
|
|
6767
|
-
img += '"';
|
|
6768
|
-
img += ' height="';
|
|
6769
|
-
img += size;
|
|
6770
|
-
img += '"';
|
|
6771
|
-
if (alt) {
|
|
6772
|
-
img += ' alt="';
|
|
6773
|
-
img += escapeXml(alt);
|
|
6774
|
-
img += '"';
|
|
6775
|
-
}
|
|
6776
|
-
img += "/>";
|
|
6777
|
-
return img;
|
|
6778
|
-
};
|
|
6779
|
-
const escapeXml = function(s) {
|
|
6780
|
-
let escaped = "";
|
|
6781
|
-
for (let i = 0;i < s.length; i += 1) {
|
|
6782
|
-
const c = s.charAt(i);
|
|
6783
|
-
switch (c) {
|
|
6784
|
-
case "<":
|
|
6785
|
-
escaped += "<";
|
|
6786
|
-
break;
|
|
6787
|
-
case ">":
|
|
6788
|
-
escaped += ">";
|
|
6789
|
-
break;
|
|
6790
|
-
case "&":
|
|
6791
|
-
escaped += "&";
|
|
6792
|
-
break;
|
|
6793
|
-
case '"':
|
|
6794
|
-
escaped += """;
|
|
6795
|
-
break;
|
|
6796
|
-
default:
|
|
6797
|
-
escaped += c;
|
|
6798
|
-
break;
|
|
6799
|
-
}
|
|
6800
|
-
}
|
|
6801
|
-
return escaped;
|
|
6802
|
-
};
|
|
6803
|
-
const _createHalfASCII = function(margin) {
|
|
6804
|
-
const cellSize = 1;
|
|
6805
|
-
margin = typeof margin == "undefined" ? cellSize * 2 : margin;
|
|
6806
|
-
const size = _this.getModuleCount() * cellSize + margin * 2;
|
|
6807
|
-
const min = margin;
|
|
6808
|
-
const max = size - margin;
|
|
6809
|
-
let y, x, r1, r2, p;
|
|
6810
|
-
const blocks = {
|
|
6811
|
-
"\u2588\u2588": "\u2588",
|
|
6812
|
-
"\u2588 ": "\u2580",
|
|
6813
|
-
" \u2588": "\u2584",
|
|
6814
|
-
" ": " "
|
|
6815
|
-
};
|
|
6816
|
-
const blocksLastLineNoMargin = {
|
|
6817
|
-
"\u2588\u2588": "\u2580",
|
|
6818
|
-
"\u2588 ": "\u2580",
|
|
6819
|
-
" \u2588": " ",
|
|
6820
|
-
" ": " "
|
|
6821
|
-
};
|
|
6822
|
-
let ascii = "";
|
|
6823
|
-
for (y = 0;y < size; y += 2) {
|
|
6824
|
-
r1 = Math.floor((y - min) / cellSize);
|
|
6825
|
-
r2 = Math.floor((y + 1 - min) / cellSize);
|
|
6826
|
-
for (x = 0;x < size; x += 1) {
|
|
6827
|
-
p = "\u2588";
|
|
6828
|
-
if (min <= x && x < max && min <= y && y < max && _this.isDark(r1, Math.floor((x - min) / cellSize))) {
|
|
6829
|
-
p = " ";
|
|
6830
|
-
}
|
|
6831
|
-
if (min <= x && x < max && min <= y + 1 && y + 1 < max && _this.isDark(r2, Math.floor((x - min) / cellSize))) {
|
|
6832
|
-
p += " ";
|
|
6833
|
-
} else {
|
|
6834
|
-
p += "\u2588";
|
|
6835
|
-
}
|
|
6836
|
-
ascii += margin < 1 && y + 1 >= max ? blocksLastLineNoMargin[p] : blocks[p];
|
|
6837
|
-
}
|
|
6838
|
-
ascii += `
|
|
6839
|
-
`;
|
|
6840
|
-
}
|
|
6841
|
-
if (size % 2 && margin > 0) {
|
|
6842
|
-
return ascii.substring(0, ascii.length - size - 1) + Array(size + 1).join("\u2580");
|
|
6843
|
-
}
|
|
6844
|
-
return ascii.substring(0, ascii.length - 1);
|
|
6845
|
-
};
|
|
6846
|
-
_this.createASCII = function(cellSize, margin) {
|
|
6847
|
-
cellSize = cellSize || 1;
|
|
6848
|
-
if (cellSize < 2) {
|
|
6849
|
-
return _createHalfASCII(margin);
|
|
6850
|
-
}
|
|
6851
|
-
cellSize -= 1;
|
|
6852
|
-
margin = typeof margin == "undefined" ? cellSize * 2 : margin;
|
|
6853
|
-
const size = _this.getModuleCount() * cellSize + margin * 2;
|
|
6854
|
-
const min = margin;
|
|
6855
|
-
const max = size - margin;
|
|
6856
|
-
let y, x, r, p;
|
|
6857
|
-
const white = Array(cellSize + 1).join("\u2588\u2588");
|
|
6858
|
-
const black = Array(cellSize + 1).join(" ");
|
|
6859
|
-
let ascii = "";
|
|
6860
|
-
let line = "";
|
|
6861
|
-
for (y = 0;y < size; y += 1) {
|
|
6862
|
-
r = Math.floor((y - min) / cellSize);
|
|
6863
|
-
line = "";
|
|
6864
|
-
for (x = 0;x < size; x += 1) {
|
|
6865
|
-
p = 1;
|
|
6866
|
-
if (min <= x && x < max && min <= y && y < max && _this.isDark(r, Math.floor((x - min) / cellSize))) {
|
|
6867
|
-
p = 0;
|
|
6868
|
-
}
|
|
6869
|
-
line += p ? white : black;
|
|
6870
|
-
}
|
|
6871
|
-
for (r = 0;r < cellSize; r += 1) {
|
|
6872
|
-
ascii += line + `
|
|
6873
|
-
`;
|
|
6874
|
-
}
|
|
6875
|
-
}
|
|
6876
|
-
return ascii.substring(0, ascii.length - 1);
|
|
6877
|
-
};
|
|
6878
|
-
_this.renderTo2dContext = function(context, cellSize) {
|
|
6879
|
-
cellSize = cellSize || 2;
|
|
6880
|
-
const length = _this.getModuleCount();
|
|
6881
|
-
for (let row = 0;row < length; row++) {
|
|
6882
|
-
for (let col = 0;col < length; col++) {
|
|
6883
|
-
context.fillStyle = _this.isDark(row, col) ? "black" : "white";
|
|
6884
|
-
context.fillRect(col * cellSize, row * cellSize, cellSize, cellSize);
|
|
6885
|
-
}
|
|
6886
|
-
}
|
|
6887
|
-
};
|
|
6888
|
-
return _this;
|
|
6889
|
-
};
|
|
6890
|
-
qrcode.stringToBytes = function(s) {
|
|
6891
|
-
const bytes = [];
|
|
6892
|
-
for (let i = 0;i < s.length; i += 1) {
|
|
6893
|
-
const c = s.charCodeAt(i);
|
|
6894
|
-
bytes.push(c & 255);
|
|
6895
|
-
}
|
|
6896
|
-
return bytes;
|
|
6897
|
-
};
|
|
6898
|
-
qrcode.createStringToBytes = function(unicodeData, numChars) {
|
|
6899
|
-
const unicodeMap = function() {
|
|
6900
|
-
const bin = base64DecodeInputStream(unicodeData);
|
|
6901
|
-
const read = function() {
|
|
6902
|
-
const b = bin.read();
|
|
6903
|
-
if (b == -1)
|
|
6904
|
-
throw "eof";
|
|
6905
|
-
return b;
|
|
6906
|
-
};
|
|
6907
|
-
let count = 0;
|
|
6908
|
-
const unicodeMap = {};
|
|
6909
|
-
while (true) {
|
|
6910
|
-
const b0 = bin.read();
|
|
6911
|
-
if (b0 == -1)
|
|
6912
|
-
break;
|
|
6913
|
-
const b1 = read();
|
|
6914
|
-
const b2 = read();
|
|
6915
|
-
const b3 = read();
|
|
6916
|
-
const k = String.fromCharCode(b0 << 8 | b1);
|
|
6917
|
-
const v = b2 << 8 | b3;
|
|
6918
|
-
unicodeMap[k] = v;
|
|
6919
|
-
count += 1;
|
|
6920
|
-
}
|
|
6921
|
-
if (count != numChars) {
|
|
6922
|
-
throw count + " != " + numChars;
|
|
6923
|
-
}
|
|
6924
|
-
return unicodeMap;
|
|
6925
|
-
}();
|
|
6926
|
-
const unknownChar = 63;
|
|
6927
|
-
return function(s) {
|
|
6928
|
-
const bytes = [];
|
|
6929
|
-
for (let i = 0;i < s.length; i += 1) {
|
|
6930
|
-
const c = s.charCodeAt(i);
|
|
6931
|
-
if (c < 128) {
|
|
6932
|
-
bytes.push(c);
|
|
6933
|
-
} else {
|
|
6934
|
-
const b = unicodeMap[s.charAt(i)];
|
|
6935
|
-
if (typeof b == "number") {
|
|
6936
|
-
if ((b & 255) == b) {
|
|
6937
|
-
bytes.push(b);
|
|
6938
|
-
} else {
|
|
6939
|
-
bytes.push(b >>> 8);
|
|
6940
|
-
bytes.push(b & 255);
|
|
6941
|
-
}
|
|
6942
|
-
} else {
|
|
6943
|
-
bytes.push(unknownChar);
|
|
6944
|
-
}
|
|
6945
|
-
}
|
|
6946
|
-
}
|
|
6947
|
-
return bytes;
|
|
6948
|
-
};
|
|
6949
|
-
};
|
|
6950
|
-
var QRMode = {
|
|
6951
|
-
MODE_NUMBER: 1 << 0,
|
|
6952
|
-
MODE_ALPHA_NUM: 1 << 1,
|
|
6953
|
-
MODE_8BIT_BYTE: 1 << 2,
|
|
6954
|
-
MODE_KANJI: 1 << 3
|
|
6955
|
-
};
|
|
6956
|
-
var QRErrorCorrectionLevel = {
|
|
6957
|
-
L: 1,
|
|
6958
|
-
M: 0,
|
|
6959
|
-
Q: 3,
|
|
6960
|
-
H: 2
|
|
6961
|
-
};
|
|
6962
|
-
var QRMaskPattern = {
|
|
6963
|
-
PATTERN000: 0,
|
|
6964
|
-
PATTERN001: 1,
|
|
6965
|
-
PATTERN010: 2,
|
|
6966
|
-
PATTERN011: 3,
|
|
6967
|
-
PATTERN100: 4,
|
|
6968
|
-
PATTERN101: 5,
|
|
6969
|
-
PATTERN110: 6,
|
|
6970
|
-
PATTERN111: 7
|
|
6971
|
-
};
|
|
6972
|
-
var QRUtil = function() {
|
|
6973
|
-
const PATTERN_POSITION_TABLE = [
|
|
6974
|
-
[],
|
|
6975
|
-
[6, 18],
|
|
6976
|
-
[6, 22],
|
|
6977
|
-
[6, 26],
|
|
6978
|
-
[6, 30],
|
|
6979
|
-
[6, 34],
|
|
6980
|
-
[6, 22, 38],
|
|
6981
|
-
[6, 24, 42],
|
|
6982
|
-
[6, 26, 46],
|
|
6983
|
-
[6, 28, 50],
|
|
6984
|
-
[6, 30, 54],
|
|
6985
|
-
[6, 32, 58],
|
|
6986
|
-
[6, 34, 62],
|
|
6987
|
-
[6, 26, 46, 66],
|
|
6988
|
-
[6, 26, 48, 70],
|
|
6989
|
-
[6, 26, 50, 74],
|
|
6990
|
-
[6, 30, 54, 78],
|
|
6991
|
-
[6, 30, 56, 82],
|
|
6992
|
-
[6, 30, 58, 86],
|
|
6993
|
-
[6, 34, 62, 90],
|
|
6994
|
-
[6, 28, 50, 72, 94],
|
|
6995
|
-
[6, 26, 50, 74, 98],
|
|
6996
|
-
[6, 30, 54, 78, 102],
|
|
6997
|
-
[6, 28, 54, 80, 106],
|
|
6998
|
-
[6, 32, 58, 84, 110],
|
|
6999
|
-
[6, 30, 58, 86, 114],
|
|
7000
|
-
[6, 34, 62, 90, 118],
|
|
7001
|
-
[6, 26, 50, 74, 98, 122],
|
|
7002
|
-
[6, 30, 54, 78, 102, 126],
|
|
7003
|
-
[6, 26, 52, 78, 104, 130],
|
|
7004
|
-
[6, 30, 56, 82, 108, 134],
|
|
7005
|
-
[6, 34, 60, 86, 112, 138],
|
|
7006
|
-
[6, 30, 58, 86, 114, 142],
|
|
7007
|
-
[6, 34, 62, 90, 118, 146],
|
|
7008
|
-
[6, 30, 54, 78, 102, 126, 150],
|
|
7009
|
-
[6, 24, 50, 76, 102, 128, 154],
|
|
7010
|
-
[6, 28, 54, 80, 106, 132, 158],
|
|
7011
|
-
[6, 32, 58, 84, 110, 136, 162],
|
|
7012
|
-
[6, 26, 54, 82, 110, 138, 166],
|
|
7013
|
-
[6, 30, 58, 86, 114, 142, 170]
|
|
7014
|
-
];
|
|
7015
|
-
const G15 = 1 << 10 | 1 << 8 | 1 << 5 | 1 << 4 | 1 << 2 | 1 << 1 | 1 << 0;
|
|
7016
|
-
const G18 = 1 << 12 | 1 << 11 | 1 << 10 | 1 << 9 | 1 << 8 | 1 << 5 | 1 << 2 | 1 << 0;
|
|
7017
|
-
const G15_MASK = 1 << 14 | 1 << 12 | 1 << 10 | 1 << 4 | 1 << 1;
|
|
7018
|
-
const _this = {};
|
|
7019
|
-
const getBCHDigit = function(data) {
|
|
7020
|
-
let digit = 0;
|
|
7021
|
-
while (data != 0) {
|
|
7022
|
-
digit += 1;
|
|
7023
|
-
data >>>= 1;
|
|
7024
|
-
}
|
|
7025
|
-
return digit;
|
|
7026
|
-
};
|
|
7027
|
-
_this.getBCHTypeInfo = function(data) {
|
|
7028
|
-
let d = data << 10;
|
|
7029
|
-
while (getBCHDigit(d) - getBCHDigit(G15) >= 0) {
|
|
7030
|
-
d ^= G15 << getBCHDigit(d) - getBCHDigit(G15);
|
|
7031
|
-
}
|
|
7032
|
-
return (data << 10 | d) ^ G15_MASK;
|
|
7033
|
-
};
|
|
7034
|
-
_this.getBCHTypeNumber = function(data) {
|
|
7035
|
-
let d = data << 12;
|
|
7036
|
-
while (getBCHDigit(d) - getBCHDigit(G18) >= 0) {
|
|
7037
|
-
d ^= G18 << getBCHDigit(d) - getBCHDigit(G18);
|
|
7038
|
-
}
|
|
7039
|
-
return data << 12 | d;
|
|
7040
|
-
};
|
|
7041
|
-
_this.getPatternPosition = function(typeNumber) {
|
|
7042
|
-
return PATTERN_POSITION_TABLE[typeNumber - 1];
|
|
7043
|
-
};
|
|
7044
|
-
_this.getMaskFunction = function(maskPattern) {
|
|
7045
|
-
switch (maskPattern) {
|
|
7046
|
-
case QRMaskPattern.PATTERN000:
|
|
7047
|
-
return function(i, j) {
|
|
7048
|
-
return (i + j) % 2 == 0;
|
|
7049
|
-
};
|
|
7050
|
-
case QRMaskPattern.PATTERN001:
|
|
7051
|
-
return function(i, j) {
|
|
7052
|
-
return i % 2 == 0;
|
|
7053
|
-
};
|
|
7054
|
-
case QRMaskPattern.PATTERN010:
|
|
7055
|
-
return function(i, j) {
|
|
7056
|
-
return j % 3 == 0;
|
|
7057
|
-
};
|
|
7058
|
-
case QRMaskPattern.PATTERN011:
|
|
7059
|
-
return function(i, j) {
|
|
7060
|
-
return (i + j) % 3 == 0;
|
|
7061
|
-
};
|
|
7062
|
-
case QRMaskPattern.PATTERN100:
|
|
7063
|
-
return function(i, j) {
|
|
7064
|
-
return (Math.floor(i / 2) + Math.floor(j / 3)) % 2 == 0;
|
|
7065
|
-
};
|
|
7066
|
-
case QRMaskPattern.PATTERN101:
|
|
7067
|
-
return function(i, j) {
|
|
7068
|
-
return i * j % 2 + i * j % 3 == 0;
|
|
7069
|
-
};
|
|
7070
|
-
case QRMaskPattern.PATTERN110:
|
|
7071
|
-
return function(i, j) {
|
|
7072
|
-
return (i * j % 2 + i * j % 3) % 2 == 0;
|
|
7073
|
-
};
|
|
7074
|
-
case QRMaskPattern.PATTERN111:
|
|
7075
|
-
return function(i, j) {
|
|
7076
|
-
return (i * j % 3 + (i + j) % 2) % 2 == 0;
|
|
7077
|
-
};
|
|
7078
|
-
default:
|
|
7079
|
-
throw "bad maskPattern:" + maskPattern;
|
|
7080
|
-
}
|
|
7081
|
-
};
|
|
7082
|
-
_this.getErrorCorrectPolynomial = function(errorCorrectLength) {
|
|
7083
|
-
let a = qrPolynomial([1], 0);
|
|
7084
|
-
for (let i = 0;i < errorCorrectLength; i += 1) {
|
|
7085
|
-
a = a.multiply(qrPolynomial([1, QRMath.gexp(i)], 0));
|
|
7086
|
-
}
|
|
7087
|
-
return a;
|
|
7088
|
-
};
|
|
7089
|
-
_this.getLengthInBits = function(mode, type) {
|
|
7090
|
-
if (1 <= type && type < 10) {
|
|
7091
|
-
switch (mode) {
|
|
7092
|
-
case QRMode.MODE_NUMBER:
|
|
7093
|
-
return 10;
|
|
7094
|
-
case QRMode.MODE_ALPHA_NUM:
|
|
7095
|
-
return 9;
|
|
7096
|
-
case QRMode.MODE_8BIT_BYTE:
|
|
7097
|
-
return 8;
|
|
7098
|
-
case QRMode.MODE_KANJI:
|
|
7099
|
-
return 8;
|
|
7100
|
-
default:
|
|
7101
|
-
throw "mode:" + mode;
|
|
7102
|
-
}
|
|
7103
|
-
} else if (type < 27) {
|
|
7104
|
-
switch (mode) {
|
|
7105
|
-
case QRMode.MODE_NUMBER:
|
|
7106
|
-
return 12;
|
|
7107
|
-
case QRMode.MODE_ALPHA_NUM:
|
|
7108
|
-
return 11;
|
|
7109
|
-
case QRMode.MODE_8BIT_BYTE:
|
|
7110
|
-
return 16;
|
|
7111
|
-
case QRMode.MODE_KANJI:
|
|
7112
|
-
return 10;
|
|
7113
|
-
default:
|
|
7114
|
-
throw "mode:" + mode;
|
|
7115
|
-
}
|
|
7116
|
-
} else if (type < 41) {
|
|
7117
|
-
switch (mode) {
|
|
7118
|
-
case QRMode.MODE_NUMBER:
|
|
7119
|
-
return 14;
|
|
7120
|
-
case QRMode.MODE_ALPHA_NUM:
|
|
7121
|
-
return 13;
|
|
7122
|
-
case QRMode.MODE_8BIT_BYTE:
|
|
7123
|
-
return 16;
|
|
7124
|
-
case QRMode.MODE_KANJI:
|
|
7125
|
-
return 12;
|
|
7126
|
-
default:
|
|
7127
|
-
throw "mode:" + mode;
|
|
7128
|
-
}
|
|
7129
|
-
} else {
|
|
7130
|
-
throw "type:" + type;
|
|
7131
|
-
}
|
|
7132
|
-
};
|
|
7133
|
-
_this.getLostPoint = function(qrcode) {
|
|
7134
|
-
const moduleCount = qrcode.getModuleCount();
|
|
7135
|
-
let lostPoint = 0;
|
|
7136
|
-
for (let row = 0;row < moduleCount; row += 1) {
|
|
7137
|
-
for (let col = 0;col < moduleCount; col += 1) {
|
|
7138
|
-
let sameCount = 0;
|
|
7139
|
-
const dark = qrcode.isDark(row, col);
|
|
7140
|
-
for (let r = -1;r <= 1; r += 1) {
|
|
7141
|
-
if (row + r < 0 || moduleCount <= row + r) {
|
|
7142
|
-
continue;
|
|
7143
|
-
}
|
|
7144
|
-
for (let c = -1;c <= 1; c += 1) {
|
|
7145
|
-
if (col + c < 0 || moduleCount <= col + c) {
|
|
7146
|
-
continue;
|
|
7147
|
-
}
|
|
7148
|
-
if (r == 0 && c == 0) {
|
|
7149
|
-
continue;
|
|
7150
|
-
}
|
|
7151
|
-
if (dark == qrcode.isDark(row + r, col + c)) {
|
|
7152
|
-
sameCount += 1;
|
|
7153
|
-
}
|
|
7154
|
-
}
|
|
7155
|
-
}
|
|
7156
|
-
if (sameCount > 5) {
|
|
7157
|
-
lostPoint += 3 + sameCount - 5;
|
|
7158
|
-
}
|
|
7159
|
-
}
|
|
7160
|
-
}
|
|
7161
|
-
for (let row = 0;row < moduleCount - 1; row += 1) {
|
|
7162
|
-
for (let col = 0;col < moduleCount - 1; col += 1) {
|
|
7163
|
-
let count = 0;
|
|
7164
|
-
if (qrcode.isDark(row, col))
|
|
7165
|
-
count += 1;
|
|
7166
|
-
if (qrcode.isDark(row + 1, col))
|
|
7167
|
-
count += 1;
|
|
7168
|
-
if (qrcode.isDark(row, col + 1))
|
|
7169
|
-
count += 1;
|
|
7170
|
-
if (qrcode.isDark(row + 1, col + 1))
|
|
7171
|
-
count += 1;
|
|
7172
|
-
if (count == 0 || count == 4) {
|
|
7173
|
-
lostPoint += 3;
|
|
7174
|
-
}
|
|
7175
|
-
}
|
|
7176
|
-
}
|
|
7177
|
-
for (let row = 0;row < moduleCount; row += 1) {
|
|
7178
|
-
for (let col = 0;col < moduleCount - 6; col += 1) {
|
|
7179
|
-
if (qrcode.isDark(row, col) && !qrcode.isDark(row, col + 1) && qrcode.isDark(row, col + 2) && qrcode.isDark(row, col + 3) && qrcode.isDark(row, col + 4) && !qrcode.isDark(row, col + 5) && qrcode.isDark(row, col + 6)) {
|
|
7180
|
-
lostPoint += 40;
|
|
7181
|
-
}
|
|
7182
|
-
}
|
|
7183
|
-
}
|
|
7184
|
-
for (let col = 0;col < moduleCount; col += 1) {
|
|
7185
|
-
for (let row = 0;row < moduleCount - 6; row += 1) {
|
|
7186
|
-
if (qrcode.isDark(row, col) && !qrcode.isDark(row + 1, col) && qrcode.isDark(row + 2, col) && qrcode.isDark(row + 3, col) && qrcode.isDark(row + 4, col) && !qrcode.isDark(row + 5, col) && qrcode.isDark(row + 6, col)) {
|
|
7187
|
-
lostPoint += 40;
|
|
7188
|
-
}
|
|
7189
|
-
}
|
|
7190
|
-
}
|
|
7191
|
-
let darkCount = 0;
|
|
7192
|
-
for (let col = 0;col < moduleCount; col += 1) {
|
|
7193
|
-
for (let row = 0;row < moduleCount; row += 1) {
|
|
7194
|
-
if (qrcode.isDark(row, col)) {
|
|
7195
|
-
darkCount += 1;
|
|
7196
|
-
}
|
|
7197
|
-
}
|
|
7198
|
-
}
|
|
7199
|
-
const ratio = Math.abs(100 * darkCount / moduleCount / moduleCount - 50) / 5;
|
|
7200
|
-
lostPoint += ratio * 10;
|
|
7201
|
-
return lostPoint;
|
|
7202
|
-
};
|
|
7203
|
-
return _this;
|
|
7204
|
-
}();
|
|
7205
|
-
var QRMath = function() {
|
|
7206
|
-
const EXP_TABLE = new Array(256);
|
|
7207
|
-
const LOG_TABLE = new Array(256);
|
|
7208
|
-
for (let i = 0;i < 8; i += 1) {
|
|
7209
|
-
EXP_TABLE[i] = 1 << i;
|
|
7210
|
-
}
|
|
7211
|
-
for (let i = 8;i < 256; i += 1) {
|
|
7212
|
-
EXP_TABLE[i] = EXP_TABLE[i - 4] ^ EXP_TABLE[i - 5] ^ EXP_TABLE[i - 6] ^ EXP_TABLE[i - 8];
|
|
7213
|
-
}
|
|
7214
|
-
for (let i = 0;i < 255; i += 1) {
|
|
7215
|
-
LOG_TABLE[EXP_TABLE[i]] = i;
|
|
7216
|
-
}
|
|
7217
|
-
const _this = {};
|
|
7218
|
-
_this.glog = function(n) {
|
|
7219
|
-
if (n < 1) {
|
|
7220
|
-
throw "glog(" + n + ")";
|
|
7221
|
-
}
|
|
7222
|
-
return LOG_TABLE[n];
|
|
7223
|
-
};
|
|
7224
|
-
_this.gexp = function(n) {
|
|
7225
|
-
while (n < 0) {
|
|
7226
|
-
n += 255;
|
|
7227
|
-
}
|
|
7228
|
-
while (n >= 256) {
|
|
7229
|
-
n -= 255;
|
|
7230
|
-
}
|
|
7231
|
-
return EXP_TABLE[n];
|
|
7232
|
-
};
|
|
7233
|
-
return _this;
|
|
7234
|
-
}();
|
|
7235
|
-
var qrPolynomial = function(num, shift) {
|
|
7236
|
-
if (typeof num.length == "undefined") {
|
|
7237
|
-
throw num.length + "/" + shift;
|
|
7238
|
-
}
|
|
7239
|
-
const _num = function() {
|
|
7240
|
-
let offset = 0;
|
|
7241
|
-
while (offset < num.length && num[offset] == 0) {
|
|
7242
|
-
offset += 1;
|
|
7243
|
-
}
|
|
7244
|
-
const _num = new Array(num.length - offset + shift);
|
|
7245
|
-
for (let i = 0;i < num.length - offset; i += 1) {
|
|
7246
|
-
_num[i] = num[i + offset];
|
|
7247
|
-
}
|
|
7248
|
-
return _num;
|
|
7249
|
-
}();
|
|
7250
|
-
const _this = {};
|
|
7251
|
-
_this.getAt = function(index) {
|
|
7252
|
-
return _num[index];
|
|
7253
|
-
};
|
|
7254
|
-
_this.getLength = function() {
|
|
7255
|
-
return _num.length;
|
|
7256
|
-
};
|
|
7257
|
-
_this.multiply = function(e) {
|
|
7258
|
-
const num = new Array(_this.getLength() + e.getLength() - 1);
|
|
7259
|
-
for (let i = 0;i < _this.getLength(); i += 1) {
|
|
7260
|
-
for (let j = 0;j < e.getLength(); j += 1) {
|
|
7261
|
-
num[i + j] ^= QRMath.gexp(QRMath.glog(_this.getAt(i)) + QRMath.glog(e.getAt(j)));
|
|
7262
|
-
}
|
|
7263
|
-
}
|
|
7264
|
-
return qrPolynomial(num, 0);
|
|
7265
|
-
};
|
|
7266
|
-
_this.mod = function(e) {
|
|
7267
|
-
if (_this.getLength() - e.getLength() < 0) {
|
|
7268
|
-
return _this;
|
|
7269
|
-
}
|
|
7270
|
-
const ratio = QRMath.glog(_this.getAt(0)) - QRMath.glog(e.getAt(0));
|
|
7271
|
-
const num = new Array(_this.getLength());
|
|
7272
|
-
for (let i = 0;i < _this.getLength(); i += 1) {
|
|
7273
|
-
num[i] = _this.getAt(i);
|
|
7274
|
-
}
|
|
7275
|
-
for (let i = 0;i < e.getLength(); i += 1) {
|
|
7276
|
-
num[i] ^= QRMath.gexp(QRMath.glog(e.getAt(i)) + ratio);
|
|
7277
|
-
}
|
|
7278
|
-
return qrPolynomial(num, 0).mod(e);
|
|
7279
|
-
};
|
|
7280
|
-
return _this;
|
|
7281
|
-
};
|
|
7282
|
-
var QRRSBlock = function() {
|
|
7283
|
-
const RS_BLOCK_TABLE = [
|
|
7284
|
-
[1, 26, 19],
|
|
7285
|
-
[1, 26, 16],
|
|
7286
|
-
[1, 26, 13],
|
|
7287
|
-
[1, 26, 9],
|
|
7288
|
-
[1, 44, 34],
|
|
7289
|
-
[1, 44, 28],
|
|
7290
|
-
[1, 44, 22],
|
|
7291
|
-
[1, 44, 16],
|
|
7292
|
-
[1, 70, 55],
|
|
7293
|
-
[1, 70, 44],
|
|
7294
|
-
[2, 35, 17],
|
|
7295
|
-
[2, 35, 13],
|
|
7296
|
-
[1, 100, 80],
|
|
7297
|
-
[2, 50, 32],
|
|
7298
|
-
[2, 50, 24],
|
|
7299
|
-
[4, 25, 9],
|
|
7300
|
-
[1, 134, 108],
|
|
7301
|
-
[2, 67, 43],
|
|
7302
|
-
[2, 33, 15, 2, 34, 16],
|
|
7303
|
-
[2, 33, 11, 2, 34, 12],
|
|
7304
|
-
[2, 86, 68],
|
|
7305
|
-
[4, 43, 27],
|
|
7306
|
-
[4, 43, 19],
|
|
7307
|
-
[4, 43, 15],
|
|
7308
|
-
[2, 98, 78],
|
|
7309
|
-
[4, 49, 31],
|
|
7310
|
-
[2, 32, 14, 4, 33, 15],
|
|
7311
|
-
[4, 39, 13, 1, 40, 14],
|
|
7312
|
-
[2, 121, 97],
|
|
7313
|
-
[2, 60, 38, 2, 61, 39],
|
|
7314
|
-
[4, 40, 18, 2, 41, 19],
|
|
7315
|
-
[4, 40, 14, 2, 41, 15],
|
|
7316
|
-
[2, 146, 116],
|
|
7317
|
-
[3, 58, 36, 2, 59, 37],
|
|
7318
|
-
[4, 36, 16, 4, 37, 17],
|
|
7319
|
-
[4, 36, 12, 4, 37, 13],
|
|
7320
|
-
[2, 86, 68, 2, 87, 69],
|
|
7321
|
-
[4, 69, 43, 1, 70, 44],
|
|
7322
|
-
[6, 43, 19, 2, 44, 20],
|
|
7323
|
-
[6, 43, 15, 2, 44, 16],
|
|
7324
|
-
[4, 101, 81],
|
|
7325
|
-
[1, 80, 50, 4, 81, 51],
|
|
7326
|
-
[4, 50, 22, 4, 51, 23],
|
|
7327
|
-
[3, 36, 12, 8, 37, 13],
|
|
7328
|
-
[2, 116, 92, 2, 117, 93],
|
|
7329
|
-
[6, 58, 36, 2, 59, 37],
|
|
7330
|
-
[4, 46, 20, 6, 47, 21],
|
|
7331
|
-
[7, 42, 14, 4, 43, 15],
|
|
7332
|
-
[4, 133, 107],
|
|
7333
|
-
[8, 59, 37, 1, 60, 38],
|
|
7334
|
-
[8, 44, 20, 4, 45, 21],
|
|
7335
|
-
[12, 33, 11, 4, 34, 12],
|
|
7336
|
-
[3, 145, 115, 1, 146, 116],
|
|
7337
|
-
[4, 64, 40, 5, 65, 41],
|
|
7338
|
-
[11, 36, 16, 5, 37, 17],
|
|
7339
|
-
[11, 36, 12, 5, 37, 13],
|
|
7340
|
-
[5, 109, 87, 1, 110, 88],
|
|
7341
|
-
[5, 65, 41, 5, 66, 42],
|
|
7342
|
-
[5, 54, 24, 7, 55, 25],
|
|
7343
|
-
[11, 36, 12, 7, 37, 13],
|
|
7344
|
-
[5, 122, 98, 1, 123, 99],
|
|
7345
|
-
[7, 73, 45, 3, 74, 46],
|
|
7346
|
-
[15, 43, 19, 2, 44, 20],
|
|
7347
|
-
[3, 45, 15, 13, 46, 16],
|
|
7348
|
-
[1, 135, 107, 5, 136, 108],
|
|
7349
|
-
[10, 74, 46, 1, 75, 47],
|
|
7350
|
-
[1, 50, 22, 15, 51, 23],
|
|
7351
|
-
[2, 42, 14, 17, 43, 15],
|
|
7352
|
-
[5, 150, 120, 1, 151, 121],
|
|
7353
|
-
[9, 69, 43, 4, 70, 44],
|
|
7354
|
-
[17, 50, 22, 1, 51, 23],
|
|
7355
|
-
[2, 42, 14, 19, 43, 15],
|
|
7356
|
-
[3, 141, 113, 4, 142, 114],
|
|
7357
|
-
[3, 70, 44, 11, 71, 45],
|
|
7358
|
-
[17, 47, 21, 4, 48, 22],
|
|
7359
|
-
[9, 39, 13, 16, 40, 14],
|
|
7360
|
-
[3, 135, 107, 5, 136, 108],
|
|
7361
|
-
[3, 67, 41, 13, 68, 42],
|
|
7362
|
-
[15, 54, 24, 5, 55, 25],
|
|
7363
|
-
[15, 43, 15, 10, 44, 16],
|
|
7364
|
-
[4, 144, 116, 4, 145, 117],
|
|
7365
|
-
[17, 68, 42],
|
|
7366
|
-
[17, 50, 22, 6, 51, 23],
|
|
7367
|
-
[19, 46, 16, 6, 47, 17],
|
|
7368
|
-
[2, 139, 111, 7, 140, 112],
|
|
7369
|
-
[17, 74, 46],
|
|
7370
|
-
[7, 54, 24, 16, 55, 25],
|
|
7371
|
-
[34, 37, 13],
|
|
7372
|
-
[4, 151, 121, 5, 152, 122],
|
|
7373
|
-
[4, 75, 47, 14, 76, 48],
|
|
7374
|
-
[11, 54, 24, 14, 55, 25],
|
|
7375
|
-
[16, 45, 15, 14, 46, 16],
|
|
7376
|
-
[6, 147, 117, 4, 148, 118],
|
|
7377
|
-
[6, 73, 45, 14, 74, 46],
|
|
7378
|
-
[11, 54, 24, 16, 55, 25],
|
|
7379
|
-
[30, 46, 16, 2, 47, 17],
|
|
7380
|
-
[8, 132, 106, 4, 133, 107],
|
|
7381
|
-
[8, 75, 47, 13, 76, 48],
|
|
7382
|
-
[7, 54, 24, 22, 55, 25],
|
|
7383
|
-
[22, 45, 15, 13, 46, 16],
|
|
7384
|
-
[10, 142, 114, 2, 143, 115],
|
|
7385
|
-
[19, 74, 46, 4, 75, 47],
|
|
7386
|
-
[28, 50, 22, 6, 51, 23],
|
|
7387
|
-
[33, 46, 16, 4, 47, 17],
|
|
7388
|
-
[8, 152, 122, 4, 153, 123],
|
|
7389
|
-
[22, 73, 45, 3, 74, 46],
|
|
7390
|
-
[8, 53, 23, 26, 54, 24],
|
|
7391
|
-
[12, 45, 15, 28, 46, 16],
|
|
7392
|
-
[3, 147, 117, 10, 148, 118],
|
|
7393
|
-
[3, 73, 45, 23, 74, 46],
|
|
7394
|
-
[4, 54, 24, 31, 55, 25],
|
|
7395
|
-
[11, 45, 15, 31, 46, 16],
|
|
7396
|
-
[7, 146, 116, 7, 147, 117],
|
|
7397
|
-
[21, 73, 45, 7, 74, 46],
|
|
7398
|
-
[1, 53, 23, 37, 54, 24],
|
|
7399
|
-
[19, 45, 15, 26, 46, 16],
|
|
7400
|
-
[5, 145, 115, 10, 146, 116],
|
|
7401
|
-
[19, 75, 47, 10, 76, 48],
|
|
7402
|
-
[15, 54, 24, 25, 55, 25],
|
|
7403
|
-
[23, 45, 15, 25, 46, 16],
|
|
7404
|
-
[13, 145, 115, 3, 146, 116],
|
|
7405
|
-
[2, 74, 46, 29, 75, 47],
|
|
7406
|
-
[42, 54, 24, 1, 55, 25],
|
|
7407
|
-
[23, 45, 15, 28, 46, 16],
|
|
7408
|
-
[17, 145, 115],
|
|
7409
|
-
[10, 74, 46, 23, 75, 47],
|
|
7410
|
-
[10, 54, 24, 35, 55, 25],
|
|
7411
|
-
[19, 45, 15, 35, 46, 16],
|
|
7412
|
-
[17, 145, 115, 1, 146, 116],
|
|
7413
|
-
[14, 74, 46, 21, 75, 47],
|
|
7414
|
-
[29, 54, 24, 19, 55, 25],
|
|
7415
|
-
[11, 45, 15, 46, 46, 16],
|
|
7416
|
-
[13, 145, 115, 6, 146, 116],
|
|
7417
|
-
[14, 74, 46, 23, 75, 47],
|
|
7418
|
-
[44, 54, 24, 7, 55, 25],
|
|
7419
|
-
[59, 46, 16, 1, 47, 17],
|
|
7420
|
-
[12, 151, 121, 7, 152, 122],
|
|
7421
|
-
[12, 75, 47, 26, 76, 48],
|
|
7422
|
-
[39, 54, 24, 14, 55, 25],
|
|
7423
|
-
[22, 45, 15, 41, 46, 16],
|
|
7424
|
-
[6, 151, 121, 14, 152, 122],
|
|
7425
|
-
[6, 75, 47, 34, 76, 48],
|
|
7426
|
-
[46, 54, 24, 10, 55, 25],
|
|
7427
|
-
[2, 45, 15, 64, 46, 16],
|
|
7428
|
-
[17, 152, 122, 4, 153, 123],
|
|
7429
|
-
[29, 74, 46, 14, 75, 47],
|
|
7430
|
-
[49, 54, 24, 10, 55, 25],
|
|
7431
|
-
[24, 45, 15, 46, 46, 16],
|
|
7432
|
-
[4, 152, 122, 18, 153, 123],
|
|
7433
|
-
[13, 74, 46, 32, 75, 47],
|
|
7434
|
-
[48, 54, 24, 14, 55, 25],
|
|
7435
|
-
[42, 45, 15, 32, 46, 16],
|
|
7436
|
-
[20, 147, 117, 4, 148, 118],
|
|
7437
|
-
[40, 75, 47, 7, 76, 48],
|
|
7438
|
-
[43, 54, 24, 22, 55, 25],
|
|
7439
|
-
[10, 45, 15, 67, 46, 16],
|
|
7440
|
-
[19, 148, 118, 6, 149, 119],
|
|
7441
|
-
[18, 75, 47, 31, 76, 48],
|
|
7442
|
-
[34, 54, 24, 34, 55, 25],
|
|
7443
|
-
[20, 45, 15, 61, 46, 16]
|
|
7444
|
-
];
|
|
7445
|
-
const qrRSBlock = function(totalCount, dataCount) {
|
|
7446
|
-
const _this = {};
|
|
7447
|
-
_this.totalCount = totalCount;
|
|
7448
|
-
_this.dataCount = dataCount;
|
|
7449
|
-
return _this;
|
|
7450
|
-
};
|
|
7451
|
-
const _this = {};
|
|
7452
|
-
const getRsBlockTable = function(typeNumber, errorCorrectionLevel) {
|
|
7453
|
-
switch (errorCorrectionLevel) {
|
|
7454
|
-
case QRErrorCorrectionLevel.L:
|
|
7455
|
-
return RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 0];
|
|
7456
|
-
case QRErrorCorrectionLevel.M:
|
|
7457
|
-
return RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 1];
|
|
7458
|
-
case QRErrorCorrectionLevel.Q:
|
|
7459
|
-
return RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 2];
|
|
7460
|
-
case QRErrorCorrectionLevel.H:
|
|
7461
|
-
return RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 3];
|
|
7462
|
-
default:
|
|
7463
|
-
return;
|
|
7464
|
-
}
|
|
7465
|
-
};
|
|
7466
|
-
_this.getRSBlocks = function(typeNumber, errorCorrectionLevel) {
|
|
7467
|
-
const rsBlock = getRsBlockTable(typeNumber, errorCorrectionLevel);
|
|
7468
|
-
if (typeof rsBlock == "undefined") {
|
|
7469
|
-
throw "bad rs block @ typeNumber:" + typeNumber + "/errorCorrectionLevel:" + errorCorrectionLevel;
|
|
7470
|
-
}
|
|
7471
|
-
const length = rsBlock.length / 3;
|
|
7472
|
-
const list = [];
|
|
7473
|
-
for (let i = 0;i < length; i += 1) {
|
|
7474
|
-
const count = rsBlock[i * 3 + 0];
|
|
7475
|
-
const totalCount = rsBlock[i * 3 + 1];
|
|
7476
|
-
const dataCount = rsBlock[i * 3 + 2];
|
|
7477
|
-
for (let j = 0;j < count; j += 1) {
|
|
7478
|
-
list.push(qrRSBlock(totalCount, dataCount));
|
|
7479
|
-
}
|
|
7480
|
-
}
|
|
7481
|
-
return list;
|
|
7482
|
-
};
|
|
7483
|
-
return _this;
|
|
7484
|
-
}();
|
|
7485
|
-
var qrBitBuffer = function() {
|
|
7486
|
-
const _buffer = [];
|
|
7487
|
-
let _length = 0;
|
|
7488
|
-
const _this = {};
|
|
7489
|
-
_this.getBuffer = function() {
|
|
7490
|
-
return _buffer;
|
|
7491
|
-
};
|
|
7492
|
-
_this.getAt = function(index) {
|
|
7493
|
-
const bufIndex = Math.floor(index / 8);
|
|
7494
|
-
return (_buffer[bufIndex] >>> 7 - index % 8 & 1) == 1;
|
|
7495
|
-
};
|
|
7496
|
-
_this.put = function(num, length) {
|
|
7497
|
-
for (let i = 0;i < length; i += 1) {
|
|
7498
|
-
_this.putBit((num >>> length - i - 1 & 1) == 1);
|
|
7499
|
-
}
|
|
7500
|
-
};
|
|
7501
|
-
_this.getLengthInBits = function() {
|
|
7502
|
-
return _length;
|
|
7503
|
-
};
|
|
7504
|
-
_this.putBit = function(bit) {
|
|
7505
|
-
const bufIndex = Math.floor(_length / 8);
|
|
7506
|
-
if (_buffer.length <= bufIndex) {
|
|
7507
|
-
_buffer.push(0);
|
|
7508
|
-
}
|
|
7509
|
-
if (bit) {
|
|
7510
|
-
_buffer[bufIndex] |= 128 >>> _length % 8;
|
|
7511
|
-
}
|
|
7512
|
-
_length += 1;
|
|
7513
|
-
};
|
|
7514
|
-
return _this;
|
|
7515
|
-
};
|
|
7516
|
-
var qrNumber = function(data) {
|
|
7517
|
-
const _mode = QRMode.MODE_NUMBER;
|
|
7518
|
-
const _data = data;
|
|
7519
|
-
const _this = {};
|
|
7520
|
-
_this.getMode = function() {
|
|
7521
|
-
return _mode;
|
|
7522
|
-
};
|
|
7523
|
-
_this.getLength = function(buffer) {
|
|
7524
|
-
return _data.length;
|
|
7525
|
-
};
|
|
7526
|
-
_this.write = function(buffer) {
|
|
7527
|
-
const data = _data;
|
|
7528
|
-
let i = 0;
|
|
7529
|
-
while (i + 2 < data.length) {
|
|
7530
|
-
buffer.put(strToNum(data.substring(i, i + 3)), 10);
|
|
7531
|
-
i += 3;
|
|
7532
|
-
}
|
|
7533
|
-
if (i < data.length) {
|
|
7534
|
-
if (data.length - i == 1) {
|
|
7535
|
-
buffer.put(strToNum(data.substring(i, i + 1)), 4);
|
|
7536
|
-
} else if (data.length - i == 2) {
|
|
7537
|
-
buffer.put(strToNum(data.substring(i, i + 2)), 7);
|
|
7538
|
-
}
|
|
7539
|
-
}
|
|
7540
|
-
};
|
|
7541
|
-
const strToNum = function(s) {
|
|
7542
|
-
let num = 0;
|
|
7543
|
-
for (let i = 0;i < s.length; i += 1) {
|
|
7544
|
-
num = num * 10 + chatToNum(s.charAt(i));
|
|
7545
|
-
}
|
|
7546
|
-
return num;
|
|
7547
|
-
};
|
|
7548
|
-
const chatToNum = function(c) {
|
|
7549
|
-
if ("0" <= c && c <= "9") {
|
|
7550
|
-
return c.charCodeAt(0) - 48;
|
|
7551
|
-
}
|
|
7552
|
-
throw "illegal char :" + c;
|
|
7553
|
-
};
|
|
7554
|
-
return _this;
|
|
7555
|
-
};
|
|
7556
|
-
var qrAlphaNum = function(data) {
|
|
7557
|
-
const _mode = QRMode.MODE_ALPHA_NUM;
|
|
7558
|
-
const _data = data;
|
|
7559
|
-
const _this = {};
|
|
7560
|
-
_this.getMode = function() {
|
|
7561
|
-
return _mode;
|
|
7562
|
-
};
|
|
7563
|
-
_this.getLength = function(buffer) {
|
|
7564
|
-
return _data.length;
|
|
7565
|
-
};
|
|
7566
|
-
_this.write = function(buffer) {
|
|
7567
|
-
const s = _data;
|
|
7568
|
-
let i = 0;
|
|
7569
|
-
while (i + 1 < s.length) {
|
|
7570
|
-
buffer.put(getCode(s.charAt(i)) * 45 + getCode(s.charAt(i + 1)), 11);
|
|
7571
|
-
i += 2;
|
|
7572
|
-
}
|
|
7573
|
-
if (i < s.length) {
|
|
7574
|
-
buffer.put(getCode(s.charAt(i)), 6);
|
|
7575
|
-
}
|
|
7576
|
-
};
|
|
7577
|
-
const getCode = function(c) {
|
|
7578
|
-
if ("0" <= c && c <= "9") {
|
|
7579
|
-
return c.charCodeAt(0) - 48;
|
|
7580
|
-
} else if ("A" <= c && c <= "Z") {
|
|
7581
|
-
return c.charCodeAt(0) - 65 + 10;
|
|
7582
|
-
} else {
|
|
7583
|
-
switch (c) {
|
|
7584
|
-
case " ":
|
|
7585
|
-
return 36;
|
|
7586
|
-
case "$":
|
|
7587
|
-
return 37;
|
|
7588
|
-
case "%":
|
|
7589
|
-
return 38;
|
|
7590
|
-
case "*":
|
|
7591
|
-
return 39;
|
|
7592
|
-
case "+":
|
|
7593
|
-
return 40;
|
|
7594
|
-
case "-":
|
|
7595
|
-
return 41;
|
|
7596
|
-
case ".":
|
|
7597
|
-
return 42;
|
|
7598
|
-
case "/":
|
|
7599
|
-
return 43;
|
|
7600
|
-
case ":":
|
|
7601
|
-
return 44;
|
|
7602
|
-
default:
|
|
7603
|
-
throw "illegal char :" + c;
|
|
7604
|
-
}
|
|
7605
|
-
}
|
|
7606
|
-
};
|
|
7607
|
-
return _this;
|
|
7608
|
-
};
|
|
7609
|
-
var qr8BitByte = function(data) {
|
|
7610
|
-
const _mode = QRMode.MODE_8BIT_BYTE;
|
|
7611
|
-
const _data = data;
|
|
7612
|
-
const _bytes = qrcode.stringToBytes(data);
|
|
7613
|
-
const _this = {};
|
|
7614
|
-
_this.getMode = function() {
|
|
7615
|
-
return _mode;
|
|
7616
|
-
};
|
|
7617
|
-
_this.getLength = function(buffer) {
|
|
7618
|
-
return _bytes.length;
|
|
7619
|
-
};
|
|
7620
|
-
_this.write = function(buffer) {
|
|
7621
|
-
for (let i = 0;i < _bytes.length; i += 1) {
|
|
7622
|
-
buffer.put(_bytes[i], 8);
|
|
7623
|
-
}
|
|
7624
|
-
};
|
|
7625
|
-
return _this;
|
|
7626
|
-
};
|
|
7627
|
-
var qrKanji = function(data) {
|
|
7628
|
-
const _mode = QRMode.MODE_KANJI;
|
|
7629
|
-
const _data = data;
|
|
7630
|
-
const stringToBytes = qrcode.stringToBytes;
|
|
7631
|
-
(function(c, code) {
|
|
7632
|
-
const test = stringToBytes(c);
|
|
7633
|
-
if (test.length != 2 || (test[0] << 8 | test[1]) != code) {
|
|
7634
|
-
throw "sjis not supported.";
|
|
7635
|
-
}
|
|
7636
|
-
})("\u53CB", 38726);
|
|
7637
|
-
const _bytes = stringToBytes(data);
|
|
7638
|
-
const _this = {};
|
|
7639
|
-
_this.getMode = function() {
|
|
7640
|
-
return _mode;
|
|
7641
|
-
};
|
|
7642
|
-
_this.getLength = function(buffer) {
|
|
7643
|
-
return ~~(_bytes.length / 2);
|
|
7644
|
-
};
|
|
7645
|
-
_this.write = function(buffer) {
|
|
7646
|
-
const data = _bytes;
|
|
7647
|
-
let i = 0;
|
|
7648
|
-
while (i + 1 < data.length) {
|
|
7649
|
-
let c = (255 & data[i]) << 8 | 255 & data[i + 1];
|
|
7650
|
-
if (33088 <= c && c <= 40956) {
|
|
7651
|
-
c -= 33088;
|
|
7652
|
-
} else if (57408 <= c && c <= 60351) {
|
|
7653
|
-
c -= 49472;
|
|
7654
|
-
} else {
|
|
7655
|
-
throw "illegal char at " + (i + 1) + "/" + c;
|
|
7656
|
-
}
|
|
7657
|
-
c = (c >>> 8 & 255) * 192 + (c & 255);
|
|
7658
|
-
buffer.put(c, 13);
|
|
7659
|
-
i += 2;
|
|
7660
|
-
}
|
|
7661
|
-
if (i < data.length) {
|
|
7662
|
-
throw "illegal char at " + (i + 1);
|
|
7663
|
-
}
|
|
7664
|
-
};
|
|
7665
|
-
return _this;
|
|
7666
|
-
};
|
|
7667
|
-
var byteArrayOutputStream = function() {
|
|
7668
|
-
const _bytes = [];
|
|
7669
|
-
const _this = {};
|
|
7670
|
-
_this.writeByte = function(b) {
|
|
7671
|
-
_bytes.push(b & 255);
|
|
7672
|
-
};
|
|
7673
|
-
_this.writeShort = function(i) {
|
|
7674
|
-
_this.writeByte(i);
|
|
7675
|
-
_this.writeByte(i >>> 8);
|
|
7676
|
-
};
|
|
7677
|
-
_this.writeBytes = function(b, off, len) {
|
|
7678
|
-
off = off || 0;
|
|
7679
|
-
len = len || b.length;
|
|
7680
|
-
for (let i = 0;i < len; i += 1) {
|
|
7681
|
-
_this.writeByte(b[i + off]);
|
|
7682
|
-
}
|
|
7683
|
-
};
|
|
7684
|
-
_this.writeString = function(s) {
|
|
7685
|
-
for (let i = 0;i < s.length; i += 1) {
|
|
7686
|
-
_this.writeByte(s.charCodeAt(i));
|
|
7687
|
-
}
|
|
7688
|
-
};
|
|
7689
|
-
_this.toByteArray = function() {
|
|
7690
|
-
return _bytes;
|
|
7691
|
-
};
|
|
7692
|
-
_this.toString = function() {
|
|
7693
|
-
let s = "";
|
|
7694
|
-
s += "[";
|
|
7695
|
-
for (let i = 0;i < _bytes.length; i += 1) {
|
|
7696
|
-
if (i > 0) {
|
|
7697
|
-
s += ",";
|
|
7698
|
-
}
|
|
7699
|
-
s += _bytes[i];
|
|
7700
|
-
}
|
|
7701
|
-
s += "]";
|
|
7702
|
-
return s;
|
|
7703
|
-
};
|
|
7704
|
-
return _this;
|
|
7705
|
-
};
|
|
7706
|
-
var base64EncodeOutputStream = function() {
|
|
7707
|
-
let _buffer = 0;
|
|
7708
|
-
let _buflen = 0;
|
|
7709
|
-
let _length = 0;
|
|
7710
|
-
let _base64 = "";
|
|
7711
|
-
const _this = {};
|
|
7712
|
-
const writeEncoded = function(b) {
|
|
7713
|
-
_base64 += String.fromCharCode(encode(b & 63));
|
|
7714
|
-
};
|
|
7715
|
-
const encode = function(n) {
|
|
7716
|
-
if (n < 0) {
|
|
7717
|
-
throw "n:" + n;
|
|
7718
|
-
} else if (n < 26) {
|
|
7719
|
-
return 65 + n;
|
|
7720
|
-
} else if (n < 52) {
|
|
7721
|
-
return 97 + (n - 26);
|
|
7722
|
-
} else if (n < 62) {
|
|
7723
|
-
return 48 + (n - 52);
|
|
7724
|
-
} else if (n == 62) {
|
|
7725
|
-
return 43;
|
|
7726
|
-
} else if (n == 63) {
|
|
7727
|
-
return 47;
|
|
7728
|
-
} else {
|
|
7729
|
-
throw "n:" + n;
|
|
7730
|
-
}
|
|
7731
|
-
};
|
|
7732
|
-
_this.writeByte = function(n) {
|
|
7733
|
-
_buffer = _buffer << 8 | n & 255;
|
|
7734
|
-
_buflen += 8;
|
|
7735
|
-
_length += 1;
|
|
7736
|
-
while (_buflen >= 6) {
|
|
7737
|
-
writeEncoded(_buffer >>> _buflen - 6);
|
|
7738
|
-
_buflen -= 6;
|
|
7739
|
-
}
|
|
7740
|
-
};
|
|
7741
|
-
_this.flush = function() {
|
|
7742
|
-
if (_buflen > 0) {
|
|
7743
|
-
writeEncoded(_buffer << 6 - _buflen);
|
|
7744
|
-
_buffer = 0;
|
|
7745
|
-
_buflen = 0;
|
|
7746
|
-
}
|
|
7747
|
-
if (_length % 3 != 0) {
|
|
7748
|
-
const padlen = 3 - _length % 3;
|
|
7749
|
-
for (let i = 0;i < padlen; i += 1) {
|
|
7750
|
-
_base64 += "=";
|
|
7751
|
-
}
|
|
7752
|
-
}
|
|
7753
|
-
};
|
|
7754
|
-
_this.toString = function() {
|
|
7755
|
-
return _base64;
|
|
7756
|
-
};
|
|
7757
|
-
return _this;
|
|
7758
|
-
};
|
|
7759
|
-
var base64DecodeInputStream = function(str) {
|
|
7760
|
-
const _str = str;
|
|
7761
|
-
let _pos = 0;
|
|
7762
|
-
let _buffer = 0;
|
|
7763
|
-
let _buflen = 0;
|
|
7764
|
-
const _this = {};
|
|
7765
|
-
_this.read = function() {
|
|
7766
|
-
while (_buflen < 8) {
|
|
7767
|
-
if (_pos >= _str.length) {
|
|
7768
|
-
if (_buflen == 0) {
|
|
7769
|
-
return -1;
|
|
7770
|
-
}
|
|
7771
|
-
throw "unexpected end of file./" + _buflen;
|
|
7772
|
-
}
|
|
7773
|
-
const c = _str.charAt(_pos);
|
|
7774
|
-
_pos += 1;
|
|
7775
|
-
if (c == "=") {
|
|
7776
|
-
_buflen = 0;
|
|
7777
|
-
return -1;
|
|
7778
|
-
} else if (c.match(/^\s$/)) {
|
|
7779
|
-
continue;
|
|
7780
|
-
}
|
|
7781
|
-
_buffer = _buffer << 6 | decode(c.charCodeAt(0));
|
|
7782
|
-
_buflen += 6;
|
|
7783
|
-
}
|
|
7784
|
-
const n = _buffer >>> _buflen - 8 & 255;
|
|
7785
|
-
_buflen -= 8;
|
|
7786
|
-
return n;
|
|
7787
|
-
};
|
|
7788
|
-
const decode = function(c) {
|
|
7789
|
-
if (65 <= c && c <= 90) {
|
|
7790
|
-
return c - 65;
|
|
7791
|
-
} else if (97 <= c && c <= 122) {
|
|
7792
|
-
return c - 97 + 26;
|
|
7793
|
-
} else if (48 <= c && c <= 57) {
|
|
7794
|
-
return c - 48 + 52;
|
|
7795
|
-
} else if (c == 43) {
|
|
7796
|
-
return 62;
|
|
7797
|
-
} else if (c == 47) {
|
|
7798
|
-
return 63;
|
|
7799
|
-
} else {
|
|
7800
|
-
throw "c:" + c;
|
|
7801
|
-
}
|
|
7802
|
-
};
|
|
7803
|
-
return _this;
|
|
7804
|
-
};
|
|
7805
|
-
var gifImage = function(width, height) {
|
|
7806
|
-
const _width = width;
|
|
7807
|
-
const _height = height;
|
|
7808
|
-
const _data = new Array(width * height);
|
|
7809
|
-
const _this = {};
|
|
7810
|
-
_this.setPixel = function(x, y, pixel) {
|
|
7811
|
-
_data[y * _width + x] = pixel;
|
|
7812
|
-
};
|
|
7813
|
-
_this.write = function(out) {
|
|
7814
|
-
out.writeString("GIF87a");
|
|
7815
|
-
out.writeShort(_width);
|
|
7816
|
-
out.writeShort(_height);
|
|
7817
|
-
out.writeByte(128);
|
|
7818
|
-
out.writeByte(0);
|
|
7819
|
-
out.writeByte(0);
|
|
7820
|
-
out.writeByte(0);
|
|
7821
|
-
out.writeByte(0);
|
|
7822
|
-
out.writeByte(0);
|
|
7823
|
-
out.writeByte(255);
|
|
7824
|
-
out.writeByte(255);
|
|
7825
|
-
out.writeByte(255);
|
|
7826
|
-
out.writeString(",");
|
|
7827
|
-
out.writeShort(0);
|
|
7828
|
-
out.writeShort(0);
|
|
7829
|
-
out.writeShort(_width);
|
|
7830
|
-
out.writeShort(_height);
|
|
7831
|
-
out.writeByte(0);
|
|
7832
|
-
const lzwMinCodeSize = 2;
|
|
7833
|
-
const raster = getLZWRaster(lzwMinCodeSize);
|
|
7834
|
-
out.writeByte(lzwMinCodeSize);
|
|
7835
|
-
let offset = 0;
|
|
7836
|
-
while (raster.length - offset > 255) {
|
|
7837
|
-
out.writeByte(255);
|
|
7838
|
-
out.writeBytes(raster, offset, 255);
|
|
7839
|
-
offset += 255;
|
|
7840
|
-
}
|
|
7841
|
-
out.writeByte(raster.length - offset);
|
|
7842
|
-
out.writeBytes(raster, offset, raster.length - offset);
|
|
7843
|
-
out.writeByte(0);
|
|
7844
|
-
out.writeString(";");
|
|
7845
|
-
};
|
|
7846
|
-
const bitOutputStream = function(out) {
|
|
7847
|
-
const _out = out;
|
|
7848
|
-
let _bitLength = 0;
|
|
7849
|
-
let _bitBuffer = 0;
|
|
7850
|
-
const _this = {};
|
|
7851
|
-
_this.write = function(data, length) {
|
|
7852
|
-
if (data >>> length != 0) {
|
|
7853
|
-
throw "length over";
|
|
7854
|
-
}
|
|
7855
|
-
while (_bitLength + length >= 8) {
|
|
7856
|
-
_out.writeByte(255 & (data << _bitLength | _bitBuffer));
|
|
7857
|
-
length -= 8 - _bitLength;
|
|
7858
|
-
data >>>= 8 - _bitLength;
|
|
7859
|
-
_bitBuffer = 0;
|
|
7860
|
-
_bitLength = 0;
|
|
7861
|
-
}
|
|
7862
|
-
_bitBuffer = data << _bitLength | _bitBuffer;
|
|
7863
|
-
_bitLength = _bitLength + length;
|
|
7864
|
-
};
|
|
7865
|
-
_this.flush = function() {
|
|
7866
|
-
if (_bitLength > 0) {
|
|
7867
|
-
_out.writeByte(_bitBuffer);
|
|
7868
|
-
}
|
|
7869
|
-
};
|
|
7870
|
-
return _this;
|
|
7871
|
-
};
|
|
7872
|
-
const getLZWRaster = function(lzwMinCodeSize) {
|
|
7873
|
-
const clearCode = 1 << lzwMinCodeSize;
|
|
7874
|
-
const endCode = (1 << lzwMinCodeSize) + 1;
|
|
7875
|
-
let bitLength = lzwMinCodeSize + 1;
|
|
7876
|
-
const table = lzwTable();
|
|
7877
|
-
for (let i = 0;i < clearCode; i += 1) {
|
|
7878
|
-
table.add(String.fromCharCode(i));
|
|
7879
|
-
}
|
|
7880
|
-
table.add(String.fromCharCode(clearCode));
|
|
7881
|
-
table.add(String.fromCharCode(endCode));
|
|
7882
|
-
const byteOut = byteArrayOutputStream();
|
|
7883
|
-
const bitOut = bitOutputStream(byteOut);
|
|
7884
|
-
bitOut.write(clearCode, bitLength);
|
|
7885
|
-
let dataIndex = 0;
|
|
7886
|
-
let s = String.fromCharCode(_data[dataIndex]);
|
|
7887
|
-
dataIndex += 1;
|
|
7888
|
-
while (dataIndex < _data.length) {
|
|
7889
|
-
const c = String.fromCharCode(_data[dataIndex]);
|
|
7890
|
-
dataIndex += 1;
|
|
7891
|
-
if (table.contains(s + c)) {
|
|
7892
|
-
s = s + c;
|
|
7893
|
-
} else {
|
|
7894
|
-
bitOut.write(table.indexOf(s), bitLength);
|
|
7895
|
-
if (table.size() < 4095) {
|
|
7896
|
-
if (table.size() == 1 << bitLength) {
|
|
7897
|
-
bitLength += 1;
|
|
7898
|
-
}
|
|
7899
|
-
table.add(s + c);
|
|
7900
|
-
}
|
|
7901
|
-
s = c;
|
|
7902
|
-
}
|
|
7903
|
-
}
|
|
7904
|
-
bitOut.write(table.indexOf(s), bitLength);
|
|
7905
|
-
bitOut.write(endCode, bitLength);
|
|
7906
|
-
bitOut.flush();
|
|
7907
|
-
return byteOut.toByteArray();
|
|
7908
|
-
};
|
|
7909
|
-
const lzwTable = function() {
|
|
7910
|
-
const _map = {};
|
|
7911
|
-
let _size = 0;
|
|
7912
|
-
const _this = {};
|
|
7913
|
-
_this.add = function(key) {
|
|
7914
|
-
if (_this.contains(key)) {
|
|
7915
|
-
throw "dup key:" + key;
|
|
7916
|
-
}
|
|
7917
|
-
_map[key] = _size;
|
|
7918
|
-
_size += 1;
|
|
7919
|
-
};
|
|
7920
|
-
_this.size = function() {
|
|
7921
|
-
return _size;
|
|
7922
|
-
};
|
|
7923
|
-
_this.indexOf = function(key) {
|
|
7924
|
-
return _map[key];
|
|
7925
|
-
};
|
|
7926
|
-
_this.contains = function(key) {
|
|
7927
|
-
return typeof _map[key] != "undefined";
|
|
7928
|
-
};
|
|
7929
|
-
return _this;
|
|
7930
|
-
};
|
|
7931
|
-
return _this;
|
|
7932
|
-
};
|
|
7933
|
-
var createDataURL = function(width, height, getPixel) {
|
|
7934
|
-
const gif = gifImage(width, height);
|
|
7935
|
-
for (let y = 0;y < height; y += 1) {
|
|
7936
|
-
for (let x = 0;x < width; x += 1) {
|
|
7937
|
-
gif.setPixel(x, y, getPixel(x, y));
|
|
7938
|
-
}
|
|
7939
|
-
}
|
|
7940
|
-
const b = byteArrayOutputStream();
|
|
7941
|
-
gif.write(b);
|
|
7942
|
-
const base64 = base64EncodeOutputStream();
|
|
7943
|
-
const bytes = b.toByteArray();
|
|
7944
|
-
for (let i = 0;i < bytes.length; i += 1) {
|
|
7945
|
-
base64.writeByte(bytes[i]);
|
|
7946
|
-
}
|
|
7947
|
-
base64.flush();
|
|
7948
|
-
return "data:image/gif;base64," + base64;
|
|
7949
|
-
};
|
|
7950
|
-
var qrcode_default = qrcode;
|
|
7951
|
-
var stringToBytes = qrcode.stringToBytes;
|
|
7952
|
-
|
|
7953
|
-
// ../shared/src/qr.ts
|
|
7954
|
-
function qrModules(text) {
|
|
7955
|
-
const qr = qrcode_default(0, "M");
|
|
7956
|
-
qr.addData(text, "Byte");
|
|
7957
|
-
qr.make();
|
|
7958
|
-
const n = qr.getModuleCount();
|
|
7959
|
-
return Array.from({ length: n }, (_, r) => Array.from({ length: n }, (_, c) => qr.isDark(r, c)));
|
|
7960
|
-
}
|
|
7961
|
-
function qrText(modules, margin = 2) {
|
|
7962
|
-
const n = modules.length + margin * 2;
|
|
7963
|
-
const light = (r, c) => {
|
|
7964
|
-
const row = modules[r - margin];
|
|
7965
|
-
const v = row?.[c - margin];
|
|
7966
|
-
return v === undefined ? true : !v;
|
|
7967
|
-
};
|
|
7968
|
-
const lines = [];
|
|
7969
|
-
for (let r = 0;r < n; r += 2) {
|
|
7970
|
-
let line = "";
|
|
7971
|
-
for (let c = 0;c < n; c++) {
|
|
7972
|
-
const top = light(r, c);
|
|
7973
|
-
const bottom = r + 1 < n ? light(r + 1, c) : true;
|
|
7974
|
-
line += top && bottom ? "\u2588" : top ? "\u2580" : bottom ? "\u2584" : " ";
|
|
7975
|
-
}
|
|
7976
|
-
lines.push(line);
|
|
7977
|
-
}
|
|
7978
|
-
return lines.join(`
|
|
7979
|
-
`);
|
|
7980
|
-
}
|
|
7981
|
-
|
|
7982
|
-
// src/pair.ts
|
|
7983
|
-
async function printPairCode() {
|
|
7984
|
-
const token = readToken();
|
|
7985
|
-
if (!token)
|
|
7986
|
-
return "daemon token missing; `toyon doctor` says where it looked";
|
|
7987
|
-
let res;
|
|
7988
|
-
try {
|
|
7989
|
-
res = await fetch(`${base}/pair`, { method: "POST", headers: { authorization: `Bearer ${token}` } });
|
|
7990
|
-
} catch {
|
|
7991
|
-
return "Toyon is not running. Start it with `toyon`, then run `toyon pair`.";
|
|
7992
|
-
}
|
|
7993
|
-
if (!res.ok)
|
|
7994
|
-
return await res.text() || `the daemon refused a pairing code (${res.status})`;
|
|
7995
|
-
const mint = await res.json();
|
|
7996
|
-
console.log(`
|
|
7997
|
-
${qrText(qrModules(mint.url))}
|
|
7998
|
-
`);
|
|
7999
|
-
console.log("Scan with your phone's camera. The code works once and lasts 2 minutes.");
|
|
8000
|
-
console.log(mint.url);
|
|
8001
|
-
if (isTailnetName(new URL(mint.url).hostname)) {
|
|
8002
|
-
const r = await fetch(`${base}/pair/phones`, { headers: { authorization: `Bearer ${token}` } }).catch(() => null);
|
|
8003
|
-
const phones = r?.ok ? await r.json() : null;
|
|
8004
|
-
console.log(tailnetLine(phones).text);
|
|
8005
|
-
}
|
|
8006
|
-
return null;
|
|
8007
|
-
}
|
|
8008
|
-
async function pair() {
|
|
8009
|
-
if (!await health()) {
|
|
8010
|
-
console.error("toyon: Toyon is not running. Start it with `toyon`, then run `toyon pair`.");
|
|
8011
|
-
return 1;
|
|
8012
|
-
}
|
|
8013
|
-
const refused = await printPairCode();
|
|
8014
|
-
if (refused) {
|
|
8015
|
-
console.error(`toyon: ${refused}`);
|
|
8016
|
-
return 1;
|
|
8017
|
-
}
|
|
8018
|
-
return 0;
|
|
8019
|
-
}
|
|
8020
|
-
|
|
8021
|
-
// src/remote.ts
|
|
8022
|
-
import { existsSync as existsSync8, mkdirSync as mkdirSync5, readFileSync as readFileSync7, rmSync as rmSync3, writeFileSync as writeFileSync4 } from "fs";
|
|
8023
|
-
|
|
8024
|
-
// src/tailscale.ts
|
|
8025
|
-
class TailscaleError extends Error {
|
|
8026
|
-
}
|
|
8027
|
-
function tailscaleCli(bin = Bun.which("tailscale")) {
|
|
8028
|
-
return async (args) => {
|
|
8029
|
-
if (bin === null) {
|
|
8030
|
-
throw new TailscaleError("Tailscale is not installed here (no tailscale on PATH); https://tailscale.com/download");
|
|
8031
|
-
}
|
|
8032
|
-
const p = Bun.spawn([bin, ...args], { stdin: "ignore", stdout: "pipe", stderr: "pipe" });
|
|
8033
|
-
const [out, err] = await Promise.all([new Response(p.stdout).text(), new Response(p.stderr).text()]);
|
|
8034
|
-
return { ok: await p.exited === 0, out, err };
|
|
6260
|
+
// src/prompt.ts
|
|
6261
|
+
function confirm(question) {
|
|
6262
|
+
process.stdout.write(`${question} [y/N] `);
|
|
6263
|
+
return new Promise((resolve) => {
|
|
6264
|
+
process.stdin.once("data", (chunk) => resolve(String(chunk).trim().toLowerCase().startsWith("y")));
|
|
6265
|
+
process.stdin.once("end", () => resolve(false));
|
|
6266
|
+
});
|
|
6267
|
+
}
|
|
6268
|
+
|
|
6269
|
+
// src/remote.ts
|
|
6270
|
+
import { existsSync as existsSync9, mkdirSync as mkdirSync5, readFileSync as readFileSync7, writeFileSync as writeFileSync5 } from "fs";
|
|
6271
|
+
|
|
6272
|
+
// ../shared/src/tailscale.ts
|
|
6273
|
+
import { existsSync as existsSync8, rmSync as rmSync2, writeFileSync as writeFileSync4 } from "fs";
|
|
6274
|
+
var dnsName = (raw) => (raw ?? "").replace(/\.$/, "").toLowerCase();
|
|
6275
|
+
|
|
6276
|
+
class TailscaleError extends Error {
|
|
6277
|
+
}
|
|
6278
|
+
var MAC_APP_CLI = "/Applications/Tailscale.app/Contents/MacOS/Tailscale";
|
|
6279
|
+
function findTailscale() {
|
|
6280
|
+
return Bun.which("tailscale") ?? (existsSync8(MAC_APP_CLI) ? MAC_APP_CLI : null);
|
|
6281
|
+
}
|
|
6282
|
+
var NOT_INSTALLED = "Tailscale is not installed here (no tailscale on PATH); https://tailscale.com/download";
|
|
6283
|
+
function tailscaleCli(bin = findTailscale()) {
|
|
6284
|
+
return async (args) => {
|
|
6285
|
+
if (bin === null)
|
|
6286
|
+
throw new TailscaleError(NOT_INSTALLED);
|
|
6287
|
+
const p = Bun.spawn([bin, ...args], { stdin: "ignore", stdout: "pipe", stderr: "pipe", timeout: 5000 });
|
|
6288
|
+
const [out, err] = await Promise.all([new Response(p.stdout).text(), new Response(p.stderr).text()]);
|
|
6289
|
+
return { ok: await p.exited === 0, out, err };
|
|
8035
6290
|
};
|
|
8036
6291
|
}
|
|
8037
6292
|
function entries(daemonPort) {
|
|
@@ -8046,33 +6301,66 @@ var lastLine = (r) => (r.err.trim() || r.out.trim()).split(`
|
|
|
8046
6301
|
`).at(-1) ?? "tailscale failed";
|
|
8047
6302
|
var notRunning = (text) => /failed to connect|is Tailscale running/i.test(text);
|
|
8048
6303
|
var NOT_RUNNING = "Tailscale is not running here; start the Tailscale app or the tailscaled service, then run `tailscale up`";
|
|
8049
|
-
function
|
|
6304
|
+
function readinessOf(json) {
|
|
8050
6305
|
let st;
|
|
8051
6306
|
try {
|
|
8052
6307
|
st = JSON.parse(json);
|
|
8053
6308
|
} catch {
|
|
8054
|
-
|
|
6309
|
+
return {
|
|
6310
|
+
state: "not-running",
|
|
6311
|
+
name: null,
|
|
6312
|
+
line: notRunning(json) ? NOT_RUNNING : "tailscale status --json printed nothing Toyon can read"
|
|
6313
|
+
};
|
|
8055
6314
|
}
|
|
6315
|
+
const name = dnsName(st.Self?.DNSName) || null;
|
|
8056
6316
|
switch (st.BackendState) {
|
|
8057
6317
|
case "Running":
|
|
8058
6318
|
break;
|
|
8059
6319
|
case "NeedsLogin":
|
|
8060
|
-
|
|
6320
|
+
return { state: "signed-out", name, line: "Tailscale is signed out; run `tailscale up`, then this again" };
|
|
8061
6321
|
case "NeedsMachineAuth":
|
|
8062
|
-
|
|
6322
|
+
return {
|
|
6323
|
+
state: "needs-approval",
|
|
6324
|
+
name,
|
|
6325
|
+
line: "this machine is waiting to be approved in the Tailscale admin console"
|
|
6326
|
+
};
|
|
8063
6327
|
case "Stopped":
|
|
8064
|
-
|
|
6328
|
+
return { state: "disconnected", name, line: "Tailscale is disconnected; run `tailscale up`, then this again" };
|
|
8065
6329
|
default:
|
|
8066
|
-
|
|
6330
|
+
return {
|
|
6331
|
+
state: "not-running",
|
|
6332
|
+
name,
|
|
6333
|
+
line: `Tailscale is not connected yet (${st.BackendState ?? "no state"}); try again shortly`
|
|
6334
|
+
};
|
|
8067
6335
|
}
|
|
8068
|
-
const name = (st.Self?.DNSName ?? "").replace(/\.$/, "").toLowerCase();
|
|
8069
6336
|
if (!name || st.CurrentTailnet?.MagicDNSEnabled === false) {
|
|
8070
|
-
|
|
6337
|
+
return {
|
|
6338
|
+
state: "magicdns-off",
|
|
6339
|
+
name,
|
|
6340
|
+
line: "MagicDNS is off for this tailnet; turn it on under DNS in the Tailscale admin console"
|
|
6341
|
+
};
|
|
8071
6342
|
}
|
|
8072
6343
|
if (!(st.CertDomains ?? []).some((d) => d.toLowerCase() === name)) {
|
|
8073
|
-
|
|
6344
|
+
return {
|
|
6345
|
+
state: "https-off",
|
|
6346
|
+
name,
|
|
6347
|
+
line: "HTTPS certificates are off for this tailnet; turn them on under DNS in the Tailscale admin console"
|
|
6348
|
+
};
|
|
8074
6349
|
}
|
|
8075
|
-
return name;
|
|
6350
|
+
return { state: "ready", name, line: `this machine is ${name} on your tailnet` };
|
|
6351
|
+
}
|
|
6352
|
+
async function readiness(ts) {
|
|
6353
|
+
let st;
|
|
6354
|
+
try {
|
|
6355
|
+
st = await ts(["status", "--json"]);
|
|
6356
|
+
} catch (e) {
|
|
6357
|
+
if (e instanceof TailscaleError)
|
|
6358
|
+
return { state: "not-installed", name: null, line: e.message };
|
|
6359
|
+
throw e;
|
|
6360
|
+
}
|
|
6361
|
+
if (!st.ok && notRunning(st.err + st.out))
|
|
6362
|
+
return { state: "not-running", name: null, line: NOT_RUNNING };
|
|
6363
|
+
return readinessOf(st.out || st.err);
|
|
8076
6364
|
}
|
|
8077
6365
|
function parseServeConfig(json) {
|
|
8078
6366
|
const text = json.trim();
|
|
@@ -8107,10 +6395,10 @@ async function readConfig(ts) {
|
|
|
8107
6395
|
return parseServeConfig(r.out);
|
|
8108
6396
|
}
|
|
8109
6397
|
async function serveTailnet(ts, daemonPort) {
|
|
8110
|
-
const
|
|
8111
|
-
if (
|
|
8112
|
-
throw new TailscaleError(
|
|
8113
|
-
const name =
|
|
6398
|
+
const r = await readiness(ts);
|
|
6399
|
+
if (r.state !== "ready" || r.name === null)
|
|
6400
|
+
throw new TailscaleError(r.line);
|
|
6401
|
+
const name = r.name;
|
|
8114
6402
|
const config = await readConfig(ts);
|
|
8115
6403
|
const want = entries(daemonPort).map((e) => ({ e, h: holder(config, name, e) }));
|
|
8116
6404
|
const taken = want.flatMap(({ e, h }) => h.kind === "other" ? [`https ${e.port} (${h.what})`] : []);
|
|
@@ -8140,25 +6428,44 @@ async function unserveTailnet(ts, daemonPort) {
|
|
|
8140
6428
|
}
|
|
8141
6429
|
return removed;
|
|
8142
6430
|
}
|
|
6431
|
+
async function turnTailnetOn(ts, daemonPort, file) {
|
|
6432
|
+
const host = await serveTailnet(ts, daemonPort);
|
|
6433
|
+
const view = { host, previews: portPreviews(host) };
|
|
6434
|
+
writeFileSync4(file, `${JSON.stringify(view, null, 2)}
|
|
6435
|
+
`);
|
|
6436
|
+
return view;
|
|
6437
|
+
}
|
|
6438
|
+
async function turnRemoteOff(ts, daemonPort, file, was) {
|
|
6439
|
+
rmSync2(file, { force: true });
|
|
6440
|
+
if (was && isTailnetName(was.host))
|
|
6441
|
+
await unserveTailnet(ts, daemonPort);
|
|
6442
|
+
}
|
|
8143
6443
|
|
|
8144
6444
|
// src/remote.ts
|
|
8145
6445
|
function saved() {
|
|
8146
|
-
if (!
|
|
6446
|
+
if (!existsSync9(remoteFile))
|
|
8147
6447
|
return null;
|
|
8148
6448
|
return parseRemote(readFileSync7(remoteFile, "utf8"));
|
|
8149
6449
|
}
|
|
8150
|
-
var same = (a, b) => (a?.host ?? null) === (b?.host ?? null) && (a?.previews ?? null) === (b?.previews ?? null);
|
|
8151
6450
|
var ports = `${PREVIEW_PORTS.from}-${PREVIEW_PORTS.to}`;
|
|
8152
|
-
|
|
8153
|
-
|
|
8154
|
-
|
|
6451
|
+
var describe2 = (r) => `remote access: https://${r.host}/, ${previewsLine(r)}`;
|
|
6452
|
+
async function switchRemote(body) {
|
|
6453
|
+
const res = await daemonFetch("/remote", { body });
|
|
6454
|
+
if (!res)
|
|
6455
|
+
return "Toyon is not answering";
|
|
6456
|
+
if (!res.ok)
|
|
6457
|
+
return await res.text() || `the daemon refused (${res.status})`;
|
|
6458
|
+
return await res.json();
|
|
8155
6459
|
}
|
|
8156
|
-
function
|
|
8157
|
-
|
|
8158
|
-
|
|
8159
|
-
`);
|
|
8160
|
-
|
|
6460
|
+
async function switched(body) {
|
|
6461
|
+
const r = await switchRemote(body);
|
|
6462
|
+
if (typeof r === "string") {
|
|
6463
|
+
console.error(`toyon: ${r}`);
|
|
6464
|
+
return false;
|
|
6465
|
+
}
|
|
6466
|
+
return r.remote;
|
|
8161
6467
|
}
|
|
6468
|
+
var HOW_TO_OPEN = 'open it on your phone from the phone button in Toyon, or pick this machine under "your devices"';
|
|
8162
6469
|
async function remote(cmd) {
|
|
8163
6470
|
const managed = await loadManaged();
|
|
8164
6471
|
if (managed.policy.remote === "off")
|
|
@@ -8169,83 +6476,157 @@ async function remote(cmd) {
|
|
|
8169
6476
|
}
|
|
8170
6477
|
const h = await health();
|
|
8171
6478
|
if (cmd.to === null && !cmd.tailscale) {
|
|
8172
|
-
const r = saved();
|
|
8173
|
-
console.log(r ? describe2(r) : "remote access is off; `toyon remote
|
|
8174
|
-
|
|
8175
|
-
|
|
6479
|
+
const r = h ? h.remote ?? null : saved();
|
|
6480
|
+
console.log(r ? describe2(r) : "remote access is off; `toyon remote --tailscale` turns it on");
|
|
6481
|
+
const ts = h?.tailscale ?? await readiness(tailscaleCli());
|
|
6482
|
+
if (ts && !(r && ts.state === "ready"))
|
|
6483
|
+
console.log(ts.line);
|
|
8176
6484
|
return 0;
|
|
8177
6485
|
}
|
|
8178
|
-
let r = null;
|
|
8179
6486
|
if (cmd.tailscale) {
|
|
8180
|
-
|
|
8181
|
-
|
|
8182
|
-
|
|
8183
|
-
|
|
8184
|
-
if (
|
|
8185
|
-
|
|
8186
|
-
|
|
8187
|
-
|
|
6487
|
+
if (h) {
|
|
6488
|
+
const now = await switched({ tailscale: true });
|
|
6489
|
+
if (now === false)
|
|
6490
|
+
return 1;
|
|
6491
|
+
if (now)
|
|
6492
|
+
console.log(describe2(now));
|
|
6493
|
+
} else {
|
|
6494
|
+
let r;
|
|
6495
|
+
try {
|
|
6496
|
+
mkdirSync5(home, { recursive: true });
|
|
6497
|
+
r = await turnTailnetOn(tailscaleCli(), port, remoteFile);
|
|
6498
|
+
} catch (e) {
|
|
6499
|
+
if (!(e instanceof TailscaleError))
|
|
6500
|
+
throw e;
|
|
6501
|
+
console.error(`toyon: ${e.message}`);
|
|
6502
|
+
return 1;
|
|
6503
|
+
}
|
|
6504
|
+
console.log(`${describe2(r)}; Toyon reads it when it starts`);
|
|
8188
6505
|
}
|
|
8189
|
-
|
|
8190
|
-
|
|
8191
|
-
|
|
8192
|
-
|
|
8193
|
-
|
|
8194
|
-
|
|
8195
|
-
|
|
8196
|
-
|
|
8197
|
-
|
|
8198
|
-
|
|
8199
|
-
|
|
8200
|
-
|
|
8201
|
-
|
|
8202
|
-
if (!(e instanceof TailscaleError))
|
|
8203
|
-
throw e;
|
|
8204
|
-
if (was && isTailnetName(was.host))
|
|
6506
|
+
console.log(HOW_TO_OPEN);
|
|
6507
|
+
return 0;
|
|
6508
|
+
}
|
|
6509
|
+
if (cmd.to === "off") {
|
|
6510
|
+
if (h) {
|
|
6511
|
+
if (await switched({ off: true }) === false)
|
|
6512
|
+
return 1;
|
|
6513
|
+
} else {
|
|
6514
|
+
try {
|
|
6515
|
+
await turnRemoteOff(tailscaleCli(), port, remoteFile, saved());
|
|
6516
|
+
} catch (e) {
|
|
6517
|
+
if (!(e instanceof TailscaleError))
|
|
6518
|
+
throw e;
|
|
8205
6519
|
console.error(`toyon: could not remove tailscale serve entries: ${e.message}`);
|
|
6520
|
+
}
|
|
8206
6521
|
}
|
|
8207
|
-
|
|
8208
|
-
|
|
8209
|
-
|
|
8210
|
-
|
|
8211
|
-
|
|
8212
|
-
|
|
8213
|
-
|
|
8214
|
-
|
|
6522
|
+
console.log("remote access is off");
|
|
6523
|
+
return 0;
|
|
6524
|
+
}
|
|
6525
|
+
const to = cmd.to;
|
|
6526
|
+
const view = acceptRemote({ host: to, previews: cmd.ports ? portPreviews(to) : hostPreviews(to) }, managed.policy);
|
|
6527
|
+
if (typeof view === "string") {
|
|
6528
|
+
console.error(`toyon: ${view}`);
|
|
6529
|
+
return 1;
|
|
6530
|
+
}
|
|
6531
|
+
if (h) {
|
|
6532
|
+
if (await switched(view) === false)
|
|
6533
|
+
return 1;
|
|
6534
|
+
} else {
|
|
6535
|
+
mkdirSync5(home, { recursive: true });
|
|
6536
|
+
writeFileSync5(remoteFile, `${JSON.stringify(view, null, 2)}
|
|
6537
|
+
`);
|
|
6538
|
+
}
|
|
6539
|
+
console.log(describe2(view));
|
|
6540
|
+
if (addressedByPort(view.previews)) {
|
|
6541
|
+
console.log(`point a TLS front for ${view.host} at 127.0.0.1:${port} on 443, and each of ports ${ports} at`);
|
|
6542
|
+
console.log("the same port on 127.0.0.1");
|
|
6543
|
+
} else {
|
|
6544
|
+
console.log(`point a TLS front for ${view.host} and *.${view.host} at 127.0.0.1:${port}. With Caddy:
|
|
8215
6545
|
`);
|
|
8216
|
-
|
|
6546
|
+
console.log(` ${view.host}, *.${view.host} {
|
|
8217
6547
|
reverse_proxy 127.0.0.1:${port}
|
|
8218
6548
|
}
|
|
8219
6549
|
`);
|
|
8220
|
-
|
|
6550
|
+
console.log("the wildcard certificate needs Caddy's DNS challenge, through your DNS provider's module");
|
|
6551
|
+
}
|
|
6552
|
+
console.log("Toyon refuses the name over plain http; a device that opens it asks to be let in");
|
|
6553
|
+
if (!h)
|
|
6554
|
+
console.log("Toyon reads this when it starts");
|
|
6555
|
+
return 0;
|
|
6556
|
+
}
|
|
6557
|
+
|
|
6558
|
+
// src/pair.ts
|
|
6559
|
+
var POLL_MS = 2000;
|
|
6560
|
+
function tailnetLines(view) {
|
|
6561
|
+
if (view === null)
|
|
6562
|
+
return ["Your phone needs Tailscale on, signed in to the same tailnet."];
|
|
6563
|
+
const lines = [` this machine: ${view.here ? "connected" : "not connected"}`];
|
|
6564
|
+
for (const d of view.devices) {
|
|
6565
|
+
lines.push(` ${d.toyon?.machine ?? d.name}: ${d.reached ? "on your tailnet" : "not answering"}`);
|
|
6566
|
+
}
|
|
6567
|
+
if (!view.devices.some((d) => d.kind === "phone")) {
|
|
6568
|
+
lines.push("No phone has joined your tailnet. Install Tailscale on it and sign in to the same account.");
|
|
6569
|
+
}
|
|
6570
|
+
return lines;
|
|
6571
|
+
}
|
|
6572
|
+
async function waiting() {
|
|
6573
|
+
const r = await daemonFetch("/knocks");
|
|
6574
|
+
return r?.ok ? await r.json() : [];
|
|
6575
|
+
}
|
|
6576
|
+
async function pair() {
|
|
6577
|
+
const h = await health();
|
|
6578
|
+
if (!h) {
|
|
6579
|
+
console.error("toyon: Toyon is not running. Start it with `toyon`, then run `toyon pair`.");
|
|
6580
|
+
return 1;
|
|
6581
|
+
}
|
|
6582
|
+
let remote = h.remote ?? null;
|
|
6583
|
+
if (!remote) {
|
|
6584
|
+
const r = await switchRemote({ tailscale: true });
|
|
6585
|
+
if (typeof r === "string") {
|
|
6586
|
+
console.error(`toyon: ${r}`);
|
|
6587
|
+
return 1;
|
|
8221
6588
|
}
|
|
8222
|
-
|
|
6589
|
+
remote = r.remote;
|
|
8223
6590
|
}
|
|
8224
|
-
if (
|
|
8225
|
-
|
|
8226
|
-
|
|
8227
|
-
openUrl(add);
|
|
6591
|
+
if (!remote) {
|
|
6592
|
+
console.error("toyon: remote access did not come on; `toyon remote` says what Tailscale is missing");
|
|
6593
|
+
return 1;
|
|
8228
6594
|
}
|
|
8229
|
-
|
|
8230
|
-
|
|
8231
|
-
|
|
8232
|
-
|
|
8233
|
-
|
|
8234
|
-
const
|
|
8235
|
-
|
|
8236
|
-
|
|
6595
|
+
console.log(machineLink(remote.host));
|
|
6596
|
+
console.log(HOW_TO_OPEN);
|
|
6597
|
+
if (isTailnetName(remote.host)) {
|
|
6598
|
+
const r = await daemonFetch("/tailnet");
|
|
6599
|
+
const view = r?.ok ? await r.json() : null;
|
|
6600
|
+
for (const line of tailnetLines(view))
|
|
6601
|
+
console.log(line);
|
|
6602
|
+
}
|
|
6603
|
+
console.log("waiting for a device; ctrl-c to stop");
|
|
6604
|
+
const asked = new Set;
|
|
6605
|
+
for (;; ) {
|
|
6606
|
+
for (const k of await waiting()) {
|
|
6607
|
+
if (asked.has(k.id))
|
|
6608
|
+
continue;
|
|
6609
|
+
asked.add(k.id);
|
|
6610
|
+
const from = k.from === null ? "a device that opened the address" : `a Toyon page at ${new URL(k.from).host}`;
|
|
6611
|
+
const yes = await confirm(`${k.word} wants in (${from}). Let it in?`);
|
|
6612
|
+
const r = await daemonFetch(`/knock/${k.id}/answer`, { body: { letIn: yes } });
|
|
6613
|
+
if (!r?.ok)
|
|
6614
|
+
console.log(`${k.word} stopped waiting`);
|
|
6615
|
+
else
|
|
6616
|
+
console.log(yes ? `${k.word} is in` : `${k.word} turned away`);
|
|
6617
|
+
}
|
|
6618
|
+
await Bun.sleep(POLL_MS);
|
|
8237
6619
|
}
|
|
8238
|
-
return 0;
|
|
8239
6620
|
}
|
|
8240
6621
|
|
|
8241
6622
|
// src/stop.ts
|
|
8242
|
-
import { rmSync as
|
|
6623
|
+
import { rmSync as rmSync3 } from "fs";
|
|
8243
6624
|
var WAIT_MS = 1e4;
|
|
8244
6625
|
async function stop() {
|
|
8245
6626
|
const h = await health();
|
|
8246
6627
|
let pid = h?.pid ?? readPid();
|
|
8247
6628
|
if (pid !== null && !alive(pid)) {
|
|
8248
|
-
|
|
6629
|
+
rmSync3(pidFile, { force: true });
|
|
8249
6630
|
pid = null;
|
|
8250
6631
|
}
|
|
8251
6632
|
if (pid === null) {
|
|
@@ -8264,7 +6645,7 @@ async function stop() {
|
|
|
8264
6645
|
if (alive(pid)) {
|
|
8265
6646
|
process.kill(pid, "SIGKILL");
|
|
8266
6647
|
console.error(`daemon (pid ${pid}) did not exit in ${WAIT_MS / 1000}s; killed. Dev servers it ran may still be up.`);
|
|
8267
|
-
|
|
6648
|
+
rmSync3(pidFile, { force: true });
|
|
8268
6649
|
return 1;
|
|
8269
6650
|
}
|
|
8270
6651
|
console.log(`stopped Toyon (pid ${pid})`);
|
|
@@ -8291,12 +6672,11 @@ async function restart() {
|
|
|
8291
6672
|
}
|
|
8292
6673
|
|
|
8293
6674
|
// src/uninstall.ts
|
|
8294
|
-
import { existsSync as
|
|
8295
|
-
import { homedir as homedir3 } from "os";
|
|
6675
|
+
import { existsSync as existsSync10, readFileSync as readFileSync8, rmSync as rmSync4 } from "fs";
|
|
8296
6676
|
import { join as join6 } from "path";
|
|
8297
6677
|
function readState() {
|
|
8298
6678
|
const file = join6(home, DAEMON_FILES.state);
|
|
8299
|
-
if (!
|
|
6679
|
+
if (!existsSync10(file))
|
|
8300
6680
|
return {};
|
|
8301
6681
|
try {
|
|
8302
6682
|
return JSON.parse(readFileSync8(file, "utf8"));
|
|
@@ -8313,18 +6693,11 @@ async function git(cwd, ...args) {
|
|
|
8313
6693
|
return false;
|
|
8314
6694
|
}
|
|
8315
6695
|
}
|
|
8316
|
-
function confirm(question) {
|
|
8317
|
-
process.stdout.write(`${question} [y/N] `);
|
|
8318
|
-
return new Promise((resolve) => {
|
|
8319
|
-
process.stdin.once("data", (chunk) => resolve(String(chunk).trim().toLowerCase().startsWith("y")));
|
|
8320
|
-
process.stdin.once("end", () => resolve(false));
|
|
8321
|
-
});
|
|
8322
|
-
}
|
|
8323
6696
|
async function uninstall(opts) {
|
|
8324
6697
|
const state = readState();
|
|
8325
6698
|
const repos = state.repos ?? [];
|
|
8326
6699
|
const worktrees = (state.worktrees ?? []).filter((w) => w.kind !== "main");
|
|
8327
|
-
const
|
|
6700
|
+
const helper = join6(home, DAEMON_FILES.helper);
|
|
8328
6701
|
const branches = worktrees.map((w) => w.branch).filter((b) => !!b && b.startsWith("toyon/"));
|
|
8329
6702
|
console.log("toyon uninstall removes:");
|
|
8330
6703
|
console.log(` ${home} (state, transcripts, agent adapters, ${worktrees.length} worktree director${worktrees.length === 1 ? "y" : "ies"})`);
|
|
@@ -8332,8 +6705,8 @@ async function uninstall(opts) {
|
|
|
8332
6705
|
const repo = repos.find((r) => r.id === w.repoId);
|
|
8333
6706
|
console.log(` ${w.path} (worktree of ${repo?.path ?? "?"})`);
|
|
8334
6707
|
}
|
|
8335
|
-
if (
|
|
8336
|
-
console.log(` ${app
|
|
6708
|
+
if (existsSync10(helper))
|
|
6709
|
+
console.log(` ${helper} (the hidden helper that starts Toyon from the Dock app)`);
|
|
8337
6710
|
console.log("and stops the daemon if it is running.");
|
|
8338
6711
|
console.log("it keeps: your repos, every branch Toyon made" + (branches.length ? ` (${branches.length} under toyon/)` : "") + ", and Toyon's settings in each repo (.toyon/ or toyon.json).");
|
|
8339
6712
|
if (!opts.yes && !await confirm("continue?")) {
|
|
@@ -8344,18 +6717,21 @@ async function uninstall(opts) {
|
|
|
8344
6717
|
await stop();
|
|
8345
6718
|
for (const w of worktrees) {
|
|
8346
6719
|
const repo = repos.find((r) => r.id === w.repoId);
|
|
8347
|
-
if (repo &&
|
|
6720
|
+
if (repo && existsSync10(repo.path)) {
|
|
8348
6721
|
const ok = await git(repo.path, "worktree", "remove", "--force", w.path);
|
|
8349
|
-
if (!ok &&
|
|
8350
|
-
|
|
6722
|
+
if (!ok && existsSync10(w.path))
|
|
6723
|
+
rmSync4(w.path, { recursive: true, force: true });
|
|
8351
6724
|
await git(repo.path, "worktree", "prune");
|
|
8352
|
-
} else if (
|
|
8353
|
-
|
|
6725
|
+
} else if (existsSync10(w.path)) {
|
|
6726
|
+
rmSync4(w.path, { recursive: true, force: true });
|
|
8354
6727
|
}
|
|
8355
6728
|
}
|
|
8356
|
-
|
|
8357
|
-
|
|
8358
|
-
|
|
6729
|
+
if (existsSync10(helper)) {
|
|
6730
|
+
try {
|
|
6731
|
+
await Bun.spawn([LSREGISTER, "-u", helper], { stdout: "ignore", stderr: "ignore" }).exited;
|
|
6732
|
+
} catch {}
|
|
6733
|
+
}
|
|
6734
|
+
rmSync4(home, { recursive: true, force: true });
|
|
8359
6735
|
console.log("removed. `npm uninstall -g toyon` removes the command itself.");
|
|
8360
6736
|
return 0;
|
|
8361
6737
|
}
|
|
@@ -8445,13 +6821,10 @@ async function restartOnto(version) {
|
|
|
8445
6821
|
}
|
|
8446
6822
|
|
|
8447
6823
|
// src/cli.ts
|
|
8448
|
-
function behind(daemonVersion) {
|
|
8449
|
-
return daemonVersion === undefined || newer(package_default.version, daemonVersion);
|
|
8450
|
-
}
|
|
8451
6824
|
async function open2(cmd) {
|
|
8452
6825
|
const explicit = cmd.path !== null;
|
|
8453
6826
|
const target = resolve(cmd.path ?? process.cwd());
|
|
8454
|
-
const register = explicit ||
|
|
6827
|
+
const register = explicit || existsSync11(join7(target, ".git"));
|
|
8455
6828
|
if (process.platform === "linux") {
|
|
8456
6829
|
const missing = missingSandboxTools();
|
|
8457
6830
|
const blocked = missing.length === 0 ? bwrapStartError() : null;
|
|
@@ -8460,28 +6833,12 @@ async function open2(cmd) {
|
|
|
8460
6833
|
else if (blocked)
|
|
8461
6834
|
console.log(bwrapBlockedAdvice(blocked, userNamespacesRestricted()));
|
|
8462
6835
|
}
|
|
8463
|
-
const
|
|
8464
|
-
if (!
|
|
8465
|
-
console.log("starting Toyon daemon\u2026");
|
|
8466
|
-
if (!await startDaemon()) {
|
|
8467
|
-
console.error(`daemon failed to start; \`toyon logs\` shows why (${logFile})`);
|
|
8468
|
-
return 1;
|
|
8469
|
-
}
|
|
8470
|
-
} else if (behind(running.version)) {
|
|
8471
|
-
console.log(`toyon: the running daemon is ${running.version ?? "older"}; \`${restartCmd}\` starts ${package_default.version}`);
|
|
8472
|
-
}
|
|
8473
|
-
const token = readToken();
|
|
8474
|
-
if (!token) {
|
|
8475
|
-
console.error("daemon token missing; `toyon doctor` says where it looked");
|
|
6836
|
+
const daemon = await ensureDaemon();
|
|
6837
|
+
if (!daemon)
|
|
8476
6838
|
return 1;
|
|
8477
|
-
|
|
8478
|
-
const file = explicit && existsSync10(target) && statSync4(target).isFile();
|
|
6839
|
+
const file = explicit && existsSync11(target) && statSync4(target).isFile();
|
|
8479
6840
|
if (file) {
|
|
8480
|
-
const res = await
|
|
8481
|
-
method: "POST",
|
|
8482
|
-
headers: { authorization: `Bearer ${token}`, "content-type": "application/json" },
|
|
8483
|
-
body: JSON.stringify({ path: target })
|
|
8484
|
-
});
|
|
6841
|
+
const res = await post("/open", daemon.token, { path: target });
|
|
8485
6842
|
if (!res.ok) {
|
|
8486
6843
|
console.error(`could not open ${target}: ${await res.text()}`);
|
|
8487
6844
|
return 1;
|
|
@@ -8489,39 +6846,34 @@ async function open2(cmd) {
|
|
|
8489
6846
|
const opened = await res.json();
|
|
8490
6847
|
console.log(opened.kind === "file" ? `toyon: opening ${target} in its project` : `toyon: opening ${target}`);
|
|
8491
6848
|
} else if (register) {
|
|
8492
|
-
const res = await
|
|
8493
|
-
method: "POST",
|
|
8494
|
-
headers: { authorization: `Bearer ${token}`, "content-type": "application/json" },
|
|
8495
|
-
body: JSON.stringify({ path: target })
|
|
8496
|
-
});
|
|
6849
|
+
const res = await post("/register", daemon.token, { path: target });
|
|
8497
6850
|
if (!res.ok) {
|
|
8498
6851
|
console.error(`could not open ${target}: ${await res.text()}`);
|
|
8499
|
-
if (explicit || !cmd.app
|
|
6852
|
+
if (explicit || !cmd.app)
|
|
8500
6853
|
return 1;
|
|
8501
6854
|
}
|
|
8502
6855
|
}
|
|
8503
|
-
|
|
8504
|
-
|
|
8505
|
-
|
|
8506
|
-
|
|
8507
|
-
|
|
8508
|
-
} else if (cmd.app) {
|
|
8509
|
-
console.log(`toyon: app window (${appUrl.split("#")[0]})`);
|
|
8510
|
-
if (!openAppWindow(appUrl)) {
|
|
8511
|
-
console.log("no Chromium browser found; opening in default browser");
|
|
8512
|
-
openUrl(url);
|
|
8513
|
-
}
|
|
8514
|
-
} else {
|
|
8515
|
-
console.log(`toyon: ${url}`);
|
|
8516
|
-
openUrl(url);
|
|
6856
|
+
if (cmd.app)
|
|
6857
|
+
showAppWindow(daemon);
|
|
6858
|
+
else {
|
|
6859
|
+
console.log(`toyon: ${daemon.url}`);
|
|
6860
|
+
openUrl(daemon.url);
|
|
8517
6861
|
}
|
|
8518
|
-
|
|
8519
|
-
|
|
8520
|
-
|
|
6862
|
+
return 0;
|
|
6863
|
+
}
|
|
6864
|
+
async function start() {
|
|
6865
|
+
const daemon = await ensureDaemon();
|
|
6866
|
+
if (!daemon)
|
|
6867
|
+
return 1;
|
|
6868
|
+
console.log(`toyon: ${daemon.url}`);
|
|
8521
6869
|
return 0;
|
|
8522
6870
|
}
|
|
8523
6871
|
async function run(cmd) {
|
|
8524
6872
|
switch (cmd.kind) {
|
|
6873
|
+
case "start":
|
|
6874
|
+
return start();
|
|
6875
|
+
case "helper":
|
|
6876
|
+
return helper(cmd.args);
|
|
8525
6877
|
case "help":
|
|
8526
6878
|
process.stdout.write(HELP);
|
|
8527
6879
|
return 0;
|