toyon 0.11.0 → 0.12.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/cli.js +468 -2110
- package/dist/daemon.js +2091 -703
- package/dist/helper-stub +0 -0
- package/dist/shell/assets/{Editor-Cs_OeWSx.js → Editor-ofBOHWJt.js} +3 -3
- package/dist/shell/assets/{XTerm-Dc6Bk52B.js → XTerm-C_Gv5uo2.js} +1 -1
- package/dist/shell/assets/{cssMode-D8uDYrHJ.js → cssMode-LqxC-sXw.js} +1 -1
- package/dist/shell/assets/{freemarker2-DlU9uDzS.js → freemarker2-DUqPZFAL.js} +1 -1
- package/dist/shell/assets/{grammar-BSzyJU-q.js → grammar-CFa79rtH.js} +1 -1
- package/dist/shell/assets/{handlebars-B66kGi_7.js → handlebars-CF9us5mA.js} +1 -1
- package/dist/shell/assets/{html-D6juOeyd.js → html-SO575qLW.js} +1 -1
- package/dist/shell/assets/{htmlMode-CbTT-4ZV.js → htmlMode-XUsZRqmU.js} +1 -1
- package/dist/shell/assets/index-BYJYiHrs.css +1 -0
- package/dist/shell/assets/index-Brx-QOIQ.js +266 -0
- package/dist/shell/assets/{javascript-CHwG4FvH.js → javascript-4ER2NhcO.js} +1 -1
- package/dist/shell/assets/{jsonMode-DzTEiaKX.js → jsonMode-D-UOjsYN.js} +1 -1
- package/dist/shell/assets/{liquid-wddZX4zw.js → liquid-CMXc0SdF.js} +1 -1
- package/dist/shell/assets/{lspLanguageFeatures-BlqDZ6dO.js → lspLanguageFeatures-D4Z0LyWk.js} +1 -1
- package/dist/shell/assets/{mdx-Dlz2LIv9.js → mdx-Dc4E4gPJ.js} +1 -1
- package/dist/shell/assets/{python-DvkArqZY.js → python-DhCnlsga.js} +1 -1
- package/dist/shell/assets/{razor-bDLQ0jQf.js → razor-CGRu_Zyc.js} +1 -1
- package/dist/shell/assets/{tsMode-B_NomV_y.js → tsMode-BoDg-EAl.js} +1 -1
- package/dist/shell/assets/{xml-CBYJrQiV.js → xml-Dl50xhA0.js} +1 -1
- package/dist/shell/assets/{yaml-DnmVK8S2.js → yaml-CoqiVhBi.js} +1 -1
- package/dist/shell/index.html +5 -29
- 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,10 +2,74 @@
|
|
|
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.12.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
74
|
var listed = (names) => names.length < 2 ? names[0] ?? "" : `${names.slice(0, -1).join(", ")} and ${names.at(-1)}`;
|
|
11
75
|
function tailnetLine(phones) {
|
|
@@ -28,14 +92,34 @@ function tailnetLine(phones) {
|
|
|
28
92
|
}
|
|
29
93
|
|
|
30
94
|
// ../shared/src/daemon.ts
|
|
95
|
+
var APP_SCHEME = "toyon";
|
|
96
|
+
var START_LINK = `${APP_SCHEME}://start`;
|
|
97
|
+
var LSREGISTER = "/System/Library/Frameworks/CoreServices.framework/Frameworks/LaunchServices.framework/Support/lsregister";
|
|
31
98
|
var DAEMON_FILES = {
|
|
32
99
|
token: "token",
|
|
100
|
+
helper: "Toyon.app",
|
|
101
|
+
launcherLog: "launcher.log",
|
|
33
102
|
pid: "daemon.pid",
|
|
34
103
|
state: "state.json",
|
|
35
104
|
drafts: "drafts.json",
|
|
36
105
|
log: "daemon.log",
|
|
37
106
|
remote: "remote.json"
|
|
38
107
|
};
|
|
108
|
+
function previewsLine(r) {
|
|
109
|
+
return addressedByPort(r.previews) ? `previews on ports ${PREVIEW_PORTS.from}-${PREVIEW_PORTS.to}` : `previews at ${r.previews}`;
|
|
110
|
+
}
|
|
111
|
+
function acceptRemote(view, policy) {
|
|
112
|
+
if (policy.remote === "off")
|
|
113
|
+
return "remote access is turned off by your organization's policy";
|
|
114
|
+
const host = view.host.toLowerCase();
|
|
115
|
+
if (!isRemoteHost(host))
|
|
116
|
+
return `${view.host} is not a name a front can answer for`;
|
|
117
|
+
if (policy.remote === "tailscale" && !isTailnetName(host)) {
|
|
118
|
+
return "your organization's policy allows remote access over Tailscale only";
|
|
119
|
+
}
|
|
120
|
+
const why = checkPreviews(view.previews, host);
|
|
121
|
+
return why ?? { host, previews: view.previews };
|
|
122
|
+
}
|
|
39
123
|
var PREVIEW_PORTS = { from: 10001, to: 10008 };
|
|
40
124
|
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
125
|
function isRemoteHost(name) {
|
|
@@ -83,10 +167,6 @@ function parseRemote(text) {
|
|
|
83
167
|
}
|
|
84
168
|
var WS_CLOSE_UNAUTHORIZED = 4401;
|
|
85
169
|
|
|
86
|
-
// ../shared/src/launcher.ts
|
|
87
|
-
var LAUNCHER_ORIGIN = "https://toyon.cloud";
|
|
88
|
-
var launcherAddLink = (machineOrigin) => `${LAUNCHER_ORIGIN}/#add=${encodeURIComponent(machineOrigin)}`;
|
|
89
|
-
|
|
90
170
|
// ../../node_modules/.bun/zod@4.5.4/node_modules/zod/v4/core/util.js
|
|
91
171
|
function getEnumValues(entries) {
|
|
92
172
|
const numericValues = Object.values(entries).filter((v) => typeof v === "number");
|
|
@@ -5187,68 +5267,6 @@ function parseVersion(v) {
|
|
|
5187
5267
|
return null;
|
|
5188
5268
|
return { nums: [Number(m[1]), Number(m[2]), Number(m[3])], pre: m[4] ?? null };
|
|
5189
5269
|
}
|
|
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
5270
|
|
|
5253
5271
|
// src/layout.ts
|
|
5254
5272
|
import { existsSync, realpathSync } from "fs";
|
|
@@ -5272,7 +5290,6 @@ function installOnPath() {
|
|
|
5272
5290
|
}
|
|
5273
5291
|
var restartCmd = restartCommand(method, package_default.version, method === "npx" ? installOnPath() : "none", process.env.npm_config_registry ?? null);
|
|
5274
5292
|
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
5293
|
|
|
5277
5294
|
// src/daemon.ts
|
|
5278
5295
|
var port = Number(process.env.TOYON_PORT ?? DAEMON_DEFAULT_PORT);
|
|
@@ -5292,6 +5309,23 @@ async function health() {
|
|
|
5292
5309
|
return null;
|
|
5293
5310
|
}
|
|
5294
5311
|
}
|
|
5312
|
+
async function daemonFetch(path, init = {}) {
|
|
5313
|
+
const token = readToken();
|
|
5314
|
+
if (!token)
|
|
5315
|
+
return null;
|
|
5316
|
+
try {
|
|
5317
|
+
return await fetch(`${base}${path}`, {
|
|
5318
|
+
method: init.method ?? (init.body === undefined ? "GET" : "POST"),
|
|
5319
|
+
headers: {
|
|
5320
|
+
authorization: `Bearer ${token}`,
|
|
5321
|
+
...init.body === undefined ? {} : { "content-type": "application/json" }
|
|
5322
|
+
},
|
|
5323
|
+
body: init.body === undefined ? undefined : JSON.stringify(init.body)
|
|
5324
|
+
});
|
|
5325
|
+
} catch {
|
|
5326
|
+
return null;
|
|
5327
|
+
}
|
|
5328
|
+
}
|
|
5295
5329
|
function readToken() {
|
|
5296
5330
|
if (!existsSync2(tokenFile))
|
|
5297
5331
|
return null;
|
|
@@ -5329,63 +5363,46 @@ async function startDaemon() {
|
|
|
5329
5363
|
}
|
|
5330
5364
|
return await health() !== null;
|
|
5331
5365
|
}
|
|
5366
|
+
function behind(daemonVersion) {
|
|
5367
|
+
return daemonVersion === undefined || newer(package_default.version, daemonVersion);
|
|
5368
|
+
}
|
|
5369
|
+
async function ensureDaemon() {
|
|
5370
|
+
let running = await health();
|
|
5371
|
+
if (!running) {
|
|
5372
|
+
console.log("starting Toyon daemon\u2026");
|
|
5373
|
+
running = await startDaemon() ? await health() : null;
|
|
5374
|
+
if (!running) {
|
|
5375
|
+
console.error(`daemon failed to start; \`toyon logs\` shows why (${logFile})`);
|
|
5376
|
+
return null;
|
|
5377
|
+
}
|
|
5378
|
+
} else if (behind(running.version)) {
|
|
5379
|
+
console.log(`toyon: the running daemon is ${running.version ?? "older"}; \`${restartCmd}\` starts ${package_default.version}`);
|
|
5380
|
+
}
|
|
5381
|
+
const token = readToken();
|
|
5382
|
+
if (!token) {
|
|
5383
|
+
console.error("daemon token missing; `toyon doctor` says where it looked");
|
|
5384
|
+
return null;
|
|
5385
|
+
}
|
|
5386
|
+
return { token, url: shellUrl(token, running.branded === true), remote: running.remote ?? null };
|
|
5387
|
+
}
|
|
5388
|
+
function post(route, token, body) {
|
|
5389
|
+
return fetch(`${base}${route}`, {
|
|
5390
|
+
method: "POST",
|
|
5391
|
+
headers: { authorization: `Bearer ${token}`, "content-type": "application/json" },
|
|
5392
|
+
body: JSON.stringify(body)
|
|
5393
|
+
});
|
|
5394
|
+
}
|
|
5332
5395
|
function shellUrl(token, branded) {
|
|
5333
5396
|
return branded ? `http://toyon.localhost/#token=${token}` : `http://toyon.localhost:${port}/#token=${token}`;
|
|
5334
5397
|
}
|
|
5335
5398
|
|
|
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;
|
|
5399
|
+
// src/openUrl.ts
|
|
5400
|
+
import { spawn as spawn2 } from "child_process";
|
|
5401
|
+
function openUrl(url) {
|
|
5402
|
+
const child = spawn2(process.platform === "darwin" ? "open" : "xdg-open", [url], { stdio: "ignore" });
|
|
5403
|
+
child.on("error", () => {});
|
|
5404
|
+
child.unref();
|
|
5387
5405
|
}
|
|
5388
|
-
`;
|
|
5389
5406
|
|
|
5390
5407
|
// src/app.ts
|
|
5391
5408
|
var CHROMIUMS = ["Google Chrome", "Arc", "Brave Browser", "Microsoft Edge", "Chromium"];
|
|
@@ -5431,13 +5448,21 @@ function findPwaId(browser, manifestId) {
|
|
|
5431
5448
|
}
|
|
5432
5449
|
return null;
|
|
5433
5450
|
}
|
|
5451
|
+
function showAppWindow(daemon) {
|
|
5452
|
+
const appUrl = shellUrl(daemon.token, false);
|
|
5453
|
+
console.log(`toyon: app window (${appUrl.split("#")[0]})`);
|
|
5454
|
+
if (openAppWindow(appUrl))
|
|
5455
|
+
return;
|
|
5456
|
+
console.log("no Chromium browser found; opening in default browser");
|
|
5457
|
+
openUrl(daemon.url);
|
|
5458
|
+
}
|
|
5434
5459
|
function openAppWindow(appUrl) {
|
|
5435
5460
|
const manifestId = new URL("/", appUrl).href;
|
|
5436
5461
|
for (const app of CHROMIUMS) {
|
|
5437
5462
|
if (spawnSync("open", ["-Ra", app]).status === 0) {
|
|
5438
5463
|
const id = findPwaId(app, manifestId);
|
|
5439
5464
|
const flag = id ? `--app-id=${id}` : `--app=${appUrl}`;
|
|
5440
|
-
|
|
5465
|
+
spawn3("open", ["-na", app, "--args", flag], { stdio: "ignore" }).unref();
|
|
5441
5466
|
if (!id) {
|
|
5442
5467
|
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
5468
|
console.log(` once installed, it gets a native-style title bar; \`toyon --app\` then launches the installed app`);
|
|
@@ -5447,145 +5472,11 @@ function openAppWindow(appUrl) {
|
|
|
5447
5472
|
}
|
|
5448
5473
|
return false;
|
|
5449
5474
|
}
|
|
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
5475
|
|
|
5587
5476
|
// src/args.ts
|
|
5588
5477
|
var VERBS = new Set([
|
|
5478
|
+
"start",
|
|
5479
|
+
"helper",
|
|
5589
5480
|
"stop",
|
|
5590
5481
|
"restart",
|
|
5591
5482
|
"update",
|
|
@@ -5607,6 +5498,9 @@ function parseArgs(argv) {
|
|
|
5607
5498
|
const [first, ...rest] = argv;
|
|
5608
5499
|
if (first !== undefined && VERBS.has(first)) {
|
|
5609
5500
|
switch (first) {
|
|
5501
|
+
case "helper":
|
|
5502
|
+
return { kind: "helper", args: rest };
|
|
5503
|
+
case "start":
|
|
5610
5504
|
case "stop":
|
|
5611
5505
|
case "restart":
|
|
5612
5506
|
case "update":
|
|
@@ -5658,12 +5552,9 @@ function parseArgs(argv) {
|
|
|
5658
5552
|
}
|
|
5659
5553
|
let path = null;
|
|
5660
5554
|
let app = false;
|
|
5661
|
-
let installApp = false;
|
|
5662
5555
|
for (const a of argv) {
|
|
5663
5556
|
if (a === "--app" || a === "--pwa")
|
|
5664
5557
|
app = true;
|
|
5665
|
-
else if (a === "--install-app")
|
|
5666
|
-
installApp = true;
|
|
5667
5558
|
else if (a.startsWith("-"))
|
|
5668
5559
|
return { kind: "error", message: `unknown option ${a}` };
|
|
5669
5560
|
else if (path !== null)
|
|
@@ -5671,7 +5562,7 @@ function parseArgs(argv) {
|
|
|
5671
5562
|
else
|
|
5672
5563
|
path = a;
|
|
5673
5564
|
}
|
|
5674
|
-
return { kind: "open", path, app
|
|
5565
|
+
return { kind: "open", path, app };
|
|
5675
5566
|
}
|
|
5676
5567
|
function parseLogs(rest) {
|
|
5677
5568
|
let follow = false;
|
|
@@ -5739,6 +5630,7 @@ usage
|
|
|
5739
5630
|
toyon [path] start the daemon if it is not running, register the repo at path
|
|
5740
5631
|
(or open the file at path: in its project, or on its own)
|
|
5741
5632
|
(default: the current directory) and open the shell
|
|
5633
|
+
toyon start start the daemon if it is not running, and open nothing
|
|
5742
5634
|
toyon stop stop the daemon and every dev server and agent it runs
|
|
5743
5635
|
toyon restart stop the daemon and start it again from what is installed now; every
|
|
5744
5636
|
shell reconnects on its own
|
|
@@ -5757,9 +5649,9 @@ usage
|
|
|
5757
5649
|
toyon remote --tailscale
|
|
5758
5650
|
open the shell from your tailnet at this machine's Tailscale name:
|
|
5759
5651
|
sets up tailscale serve for Toyon and ports 10001-10008
|
|
5760
|
-
toyon pair
|
|
5761
|
-
|
|
5762
|
-
|
|
5652
|
+
toyon pair show this machine's address as a QR code for your phone, and let in
|
|
5653
|
+
each device that opens it, from this terminal; Toyon's window asks
|
|
5654
|
+
the same question when one is open
|
|
5763
5655
|
toyon deploy fly up <name> [--region code] [--repo url]
|
|
5764
5656
|
run Toyon on your own Fly account at https://name.fly.dev with your own
|
|
5765
5657
|
keys; --repo clones that repository onto it the first time
|
|
@@ -5770,7 +5662,6 @@ usage
|
|
|
5770
5662
|
|
|
5771
5663
|
options for toyon [path]
|
|
5772
5664
|
--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
5665
|
|
|
5775
5666
|
environment
|
|
5776
5667
|
TOYON_HOME where state lives (default ~/.toyon)
|
|
@@ -5786,7 +5677,7 @@ policy
|
|
|
5786
5677
|
// src/deploy/fly.ts
|
|
5787
5678
|
import { randomBytes } from "crypto";
|
|
5788
5679
|
import { Resolver } from "dns/promises";
|
|
5789
|
-
import { existsSync as existsSync5, mkdirSync as mkdirSync4, mkdtempSync, readFileSync as readFileSync4, rmSync
|
|
5680
|
+
import { existsSync as existsSync5, mkdirSync as mkdirSync4, mkdtempSync, readFileSync as readFileSync4, rmSync, writeFileSync as writeFileSync3 } from "fs";
|
|
5790
5681
|
import { tmpdir } from "os";
|
|
5791
5682
|
import { join as join5 } from "path";
|
|
5792
5683
|
|
|
@@ -5839,14 +5730,6 @@ function safeUser() {
|
|
|
5839
5730
|
}
|
|
5840
5731
|
}
|
|
5841
5732
|
|
|
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
5733
|
// src/policy.ts
|
|
5851
5734
|
function refusedByPolicy(verb, m) {
|
|
5852
5735
|
console.error(`toyon: ${verb} is turned off by your organization's policy (${m.source ?? "policy"})`);
|
|
@@ -6075,7 +5958,7 @@ async function up(cmd, bin) {
|
|
|
6075
5958
|
throw new DeployError("the deploy failed; flyctl's output above says why");
|
|
6076
5959
|
}
|
|
6077
5960
|
} finally {
|
|
6078
|
-
|
|
5961
|
+
rmSync(ctx, { recursive: true, force: true });
|
|
6079
5962
|
}
|
|
6080
5963
|
console.log("waiting for the machine to answer");
|
|
6081
5964
|
let up = false;
|
|
@@ -6088,15 +5971,20 @@ async function up(cmd, bin) {
|
|
|
6088
5971
|
}
|
|
6089
5972
|
if (!up)
|
|
6090
5973
|
console.log(`it has not answered yet; \`fly logs -a ${cmd.name}\` shows what it is doing`);
|
|
6091
|
-
printLinks(cmd.name, token);
|
|
5974
|
+
await printLinks(cmd.name, token);
|
|
6092
5975
|
console.log("the volume holds the only copy of anything not pushed to a remote");
|
|
6093
|
-
openUrl(launcherAddLink(`https://${cmd.name}.fly.dev`));
|
|
6094
5976
|
}
|
|
6095
|
-
function printLinks(app, token) {
|
|
5977
|
+
async function printLinks(app, token) {
|
|
5978
|
+
const origin = `https://${app}.fly.dev`;
|
|
5979
|
+
const handed = (await daemonFetch("/machines", { body: { origin, token } }))?.ok === true;
|
|
5980
|
+
if (handed) {
|
|
5981
|
+
console.log(`
|
|
5982
|
+
toyon: ${app}.fly.dev is in your list; open Toyon here to use it, and pair your phone from there`);
|
|
5983
|
+
return;
|
|
5984
|
+
}
|
|
6096
5985
|
console.log(`
|
|
6097
|
-
toyon:
|
|
5986
|
+
toyon: ${origin}/#token=${token}`);
|
|
6098
5987
|
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
5988
|
}
|
|
6101
5989
|
async function destroy(cmd, bin) {
|
|
6102
5990
|
if (!cmd.yes) {
|
|
@@ -6114,7 +6002,7 @@ async function destroy(cmd, bin) {
|
|
|
6114
6002
|
}
|
|
6115
6003
|
}
|
|
6116
6004
|
must(await capture(bin, ["apps", "destroy", cmd.name, "--yes"]), "could not delete the app");
|
|
6117
|
-
|
|
6005
|
+
rmSync(tokenFile2(cmd.name), { force: true });
|
|
6118
6006
|
console.log(`deleted ${cmd.name}`);
|
|
6119
6007
|
return 0;
|
|
6120
6008
|
}
|
|
@@ -6133,7 +6021,7 @@ async function deploy(cmd) {
|
|
|
6133
6021
|
else if (cmd.action === "destroy")
|
|
6134
6022
|
return await destroy(cmd, bin);
|
|
6135
6023
|
else if (existsSync5(tokenFile2(cmd.name))) {
|
|
6136
|
-
printLinks(cmd.name, readFileSync4(tokenFile2(cmd.name), "utf8").trim());
|
|
6024
|
+
await printLinks(cmd.name, readFileSync4(tokenFile2(cmd.name), "utf8").trim());
|
|
6137
6025
|
} else {
|
|
6138
6026
|
throw new DeployError(`${cmd.name} was not deployed from this machine; its token is not in ${cloudDir}`);
|
|
6139
6027
|
}
|
|
@@ -6318,6 +6206,41 @@ async function doctor() {
|
|
|
6318
6206
|
return lines.every((l) => l.ok) ? 0 : 1;
|
|
6319
6207
|
}
|
|
6320
6208
|
|
|
6209
|
+
// src/helper.ts
|
|
6210
|
+
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
6211
|
+
function planHelper(args) {
|
|
6212
|
+
if (args.some((a) => a.startsWith(`${APP_SCHEME}:`)))
|
|
6213
|
+
return { kind: "start" };
|
|
6214
|
+
const paths = [];
|
|
6215
|
+
for (const a of args) {
|
|
6216
|
+
if (a.startsWith("file:")) {
|
|
6217
|
+
try {
|
|
6218
|
+
const p = fileURLToPath2(a);
|
|
6219
|
+
if (p !== "" && p !== "/")
|
|
6220
|
+
paths.push(p);
|
|
6221
|
+
} catch {}
|
|
6222
|
+
} else if (a !== "")
|
|
6223
|
+
paths.push(a);
|
|
6224
|
+
}
|
|
6225
|
+
return paths.length === 0 ? { kind: "start" } : { kind: "open", paths };
|
|
6226
|
+
}
|
|
6227
|
+
async function helper(args) {
|
|
6228
|
+
const plan = planHelper(args);
|
|
6229
|
+
console.log(`toyon helper: ${args.length > 0 ? args.join(" ") : "(nothing)"}`);
|
|
6230
|
+
const daemon = await ensureDaemon();
|
|
6231
|
+
if (!daemon)
|
|
6232
|
+
return 1;
|
|
6233
|
+
if (plan.kind === "start")
|
|
6234
|
+
return 0;
|
|
6235
|
+
for (const path of plan.paths) {
|
|
6236
|
+
const res = await post("/open", daemon.token, { path });
|
|
6237
|
+
if (!res.ok)
|
|
6238
|
+
console.error(`could not open ${path}: ${await res.text()}`);
|
|
6239
|
+
}
|
|
6240
|
+
showAppWindow(daemon);
|
|
6241
|
+
return 0;
|
|
6242
|
+
}
|
|
6243
|
+
|
|
6321
6244
|
// src/logs.ts
|
|
6322
6245
|
import { existsSync as existsSync7, readFileSync as readFileSync6, statSync as statSync3 } from "fs";
|
|
6323
6246
|
async function logs(opts) {
|
|
@@ -6353,1685 +6276,36 @@ async function logs(opts) {
|
|
|
6353
6276
|
}
|
|
6354
6277
|
}
|
|
6355
6278
|
|
|
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 };
|
|
6279
|
+
// src/prompt.ts
|
|
6280
|
+
function confirm(question) {
|
|
6281
|
+
process.stdout.write(`${question} [y/N] `);
|
|
6282
|
+
return new Promise((resolve) => {
|
|
6283
|
+
process.stdin.once("data", (chunk) => resolve(String(chunk).trim().toLowerCase().startsWith("y")));
|
|
6284
|
+
process.stdin.once("end", () => resolve(false));
|
|
6285
|
+
});
|
|
6286
|
+
}
|
|
6287
|
+
|
|
6288
|
+
// src/remote.ts
|
|
6289
|
+
import { existsSync as existsSync9, mkdirSync as mkdirSync5, readFileSync as readFileSync7, writeFileSync as writeFileSync5 } from "fs";
|
|
6290
|
+
|
|
6291
|
+
// ../shared/src/tailscale.ts
|
|
6292
|
+
import { existsSync as existsSync8, rmSync as rmSync2, writeFileSync as writeFileSync4 } from "fs";
|
|
6293
|
+
var dnsName = (raw) => (raw ?? "").replace(/\.$/, "").toLowerCase();
|
|
6294
|
+
|
|
6295
|
+
class TailscaleError extends Error {
|
|
6296
|
+
}
|
|
6297
|
+
var MAC_APP_CLI = "/Applications/Tailscale.app/Contents/MacOS/Tailscale";
|
|
6298
|
+
function findTailscale() {
|
|
6299
|
+
return Bun.which("tailscale") ?? (existsSync8(MAC_APP_CLI) ? MAC_APP_CLI : null);
|
|
6300
|
+
}
|
|
6301
|
+
var NOT_INSTALLED = "Tailscale is not installed here (no tailscale on PATH); https://tailscale.com/download";
|
|
6302
|
+
function tailscaleCli(bin = findTailscale()) {
|
|
6303
|
+
return async (args) => {
|
|
6304
|
+
if (bin === null)
|
|
6305
|
+
throw new TailscaleError(NOT_INSTALLED);
|
|
6306
|
+
const p = Bun.spawn([bin, ...args], { stdin: "ignore", stdout: "pipe", stderr: "pipe", timeout: 5000 });
|
|
6307
|
+
const [out, err] = await Promise.all([new Response(p.stdout).text(), new Response(p.stderr).text()]);
|
|
6308
|
+
return { ok: await p.exited === 0, out, err };
|
|
8035
6309
|
};
|
|
8036
6310
|
}
|
|
8037
6311
|
function entries(daemonPort) {
|
|
@@ -8046,33 +6320,66 @@ var lastLine = (r) => (r.err.trim() || r.out.trim()).split(`
|
|
|
8046
6320
|
`).at(-1) ?? "tailscale failed";
|
|
8047
6321
|
var notRunning = (text) => /failed to connect|is Tailscale running/i.test(text);
|
|
8048
6322
|
var NOT_RUNNING = "Tailscale is not running here; start the Tailscale app or the tailscaled service, then run `tailscale up`";
|
|
8049
|
-
function
|
|
6323
|
+
function readinessOf(json) {
|
|
8050
6324
|
let st;
|
|
8051
6325
|
try {
|
|
8052
6326
|
st = JSON.parse(json);
|
|
8053
6327
|
} catch {
|
|
8054
|
-
|
|
6328
|
+
return {
|
|
6329
|
+
state: "not-running",
|
|
6330
|
+
name: null,
|
|
6331
|
+
line: notRunning(json) ? NOT_RUNNING : "tailscale status --json printed nothing Toyon can read"
|
|
6332
|
+
};
|
|
8055
6333
|
}
|
|
6334
|
+
const name = dnsName(st.Self?.DNSName) || null;
|
|
8056
6335
|
switch (st.BackendState) {
|
|
8057
6336
|
case "Running":
|
|
8058
6337
|
break;
|
|
8059
6338
|
case "NeedsLogin":
|
|
8060
|
-
|
|
6339
|
+
return { state: "signed-out", name, line: "Tailscale is signed out; run `tailscale up`, then this again" };
|
|
8061
6340
|
case "NeedsMachineAuth":
|
|
8062
|
-
|
|
6341
|
+
return {
|
|
6342
|
+
state: "needs-approval",
|
|
6343
|
+
name,
|
|
6344
|
+
line: "this machine is waiting to be approved in the Tailscale admin console"
|
|
6345
|
+
};
|
|
8063
6346
|
case "Stopped":
|
|
8064
|
-
|
|
6347
|
+
return { state: "signed-out", name, line: "Tailscale is disconnected; run `tailscale up`, then this again" };
|
|
8065
6348
|
default:
|
|
8066
|
-
|
|
6349
|
+
return {
|
|
6350
|
+
state: "not-running",
|
|
6351
|
+
name,
|
|
6352
|
+
line: `Tailscale is not connected yet (${st.BackendState ?? "no state"}); try again shortly`
|
|
6353
|
+
};
|
|
8067
6354
|
}
|
|
8068
|
-
const name = (st.Self?.DNSName ?? "").replace(/\.$/, "").toLowerCase();
|
|
8069
6355
|
if (!name || st.CurrentTailnet?.MagicDNSEnabled === false) {
|
|
8070
|
-
|
|
6356
|
+
return {
|
|
6357
|
+
state: "magicdns-off",
|
|
6358
|
+
name,
|
|
6359
|
+
line: "MagicDNS is off for this tailnet; turn it on under DNS in the Tailscale admin console"
|
|
6360
|
+
};
|
|
8071
6361
|
}
|
|
8072
6362
|
if (!(st.CertDomains ?? []).some((d) => d.toLowerCase() === name)) {
|
|
8073
|
-
|
|
6363
|
+
return {
|
|
6364
|
+
state: "https-off",
|
|
6365
|
+
name,
|
|
6366
|
+
line: "HTTPS certificates are off for this tailnet; turn them on under DNS in the Tailscale admin console"
|
|
6367
|
+
};
|
|
8074
6368
|
}
|
|
8075
|
-
return name;
|
|
6369
|
+
return { state: "ready", name, line: `this machine is ${name} on your tailnet` };
|
|
6370
|
+
}
|
|
6371
|
+
async function readiness(ts) {
|
|
6372
|
+
let st;
|
|
6373
|
+
try {
|
|
6374
|
+
st = await ts(["status", "--json"]);
|
|
6375
|
+
} catch (e) {
|
|
6376
|
+
if (e instanceof TailscaleError)
|
|
6377
|
+
return { state: "not-installed", name: null, line: e.message };
|
|
6378
|
+
throw e;
|
|
6379
|
+
}
|
|
6380
|
+
if (!st.ok && notRunning(st.err + st.out))
|
|
6381
|
+
return { state: "not-running", name: null, line: NOT_RUNNING };
|
|
6382
|
+
return readinessOf(st.out || st.err);
|
|
8076
6383
|
}
|
|
8077
6384
|
function parseServeConfig(json) {
|
|
8078
6385
|
const text = json.trim();
|
|
@@ -8107,10 +6414,10 @@ async function readConfig(ts) {
|
|
|
8107
6414
|
return parseServeConfig(r.out);
|
|
8108
6415
|
}
|
|
8109
6416
|
async function serveTailnet(ts, daemonPort) {
|
|
8110
|
-
const
|
|
8111
|
-
if (
|
|
8112
|
-
throw new TailscaleError(
|
|
8113
|
-
const name =
|
|
6417
|
+
const r = await readiness(ts);
|
|
6418
|
+
if (r.state !== "ready" || r.name === null)
|
|
6419
|
+
throw new TailscaleError(r.line);
|
|
6420
|
+
const name = r.name;
|
|
8114
6421
|
const config = await readConfig(ts);
|
|
8115
6422
|
const want = entries(daemonPort).map((e) => ({ e, h: holder(config, name, e) }));
|
|
8116
6423
|
const taken = want.flatMap(({ e, h }) => h.kind === "other" ? [`https ${e.port} (${h.what})`] : []);
|
|
@@ -8140,25 +6447,44 @@ async function unserveTailnet(ts, daemonPort) {
|
|
|
8140
6447
|
}
|
|
8141
6448
|
return removed;
|
|
8142
6449
|
}
|
|
6450
|
+
async function turnTailnetOn(ts, daemonPort, file) {
|
|
6451
|
+
const host = await serveTailnet(ts, daemonPort);
|
|
6452
|
+
const view = { host, previews: portPreviews(host) };
|
|
6453
|
+
writeFileSync4(file, `${JSON.stringify(view, null, 2)}
|
|
6454
|
+
`);
|
|
6455
|
+
return view;
|
|
6456
|
+
}
|
|
6457
|
+
async function turnRemoteOff(ts, daemonPort, file, was) {
|
|
6458
|
+
rmSync2(file, { force: true });
|
|
6459
|
+
if (was && isTailnetName(was.host))
|
|
6460
|
+
await unserveTailnet(ts, daemonPort);
|
|
6461
|
+
}
|
|
8143
6462
|
|
|
8144
6463
|
// src/remote.ts
|
|
8145
6464
|
function saved() {
|
|
8146
|
-
if (!
|
|
6465
|
+
if (!existsSync9(remoteFile))
|
|
8147
6466
|
return null;
|
|
8148
6467
|
return parseRemote(readFileSync7(remoteFile, "utf8"));
|
|
8149
6468
|
}
|
|
8150
|
-
var same = (a, b) => (a?.host ?? null) === (b?.host ?? null) && (a?.previews ?? null) === (b?.previews ?? null);
|
|
8151
6469
|
var ports = `${PREVIEW_PORTS.from}-${PREVIEW_PORTS.to}`;
|
|
8152
|
-
|
|
8153
|
-
|
|
8154
|
-
|
|
6470
|
+
var describe2 = (r) => `remote access: https://${r.host}/, ${previewsLine(r)}`;
|
|
6471
|
+
async function switchRemote(body) {
|
|
6472
|
+
const res = await daemonFetch("/remote", { body });
|
|
6473
|
+
if (!res)
|
|
6474
|
+
return "Toyon is not answering";
|
|
6475
|
+
if (!res.ok)
|
|
6476
|
+
return await res.text() || `the daemon refused (${res.status})`;
|
|
6477
|
+
return await res.json();
|
|
8155
6478
|
}
|
|
8156
|
-
function
|
|
8157
|
-
|
|
8158
|
-
|
|
8159
|
-
`);
|
|
8160
|
-
|
|
6479
|
+
async function switched(body) {
|
|
6480
|
+
const r = await switchRemote(body);
|
|
6481
|
+
if (typeof r === "string") {
|
|
6482
|
+
console.error(`toyon: ${r}`);
|
|
6483
|
+
return false;
|
|
6484
|
+
}
|
|
6485
|
+
return r.remote;
|
|
8161
6486
|
}
|
|
6487
|
+
var HOW_TO_OPEN = 'open it on your phone from the phone button in Toyon, or pick this machine under "add a machine"';
|
|
8162
6488
|
async function remote(cmd) {
|
|
8163
6489
|
const managed = await loadManaged();
|
|
8164
6490
|
if (managed.policy.remote === "off")
|
|
@@ -8169,83 +6495,144 @@ async function remote(cmd) {
|
|
|
8169
6495
|
}
|
|
8170
6496
|
const h = await health();
|
|
8171
6497
|
if (cmd.to === null && !cmd.tailscale) {
|
|
8172
|
-
const r = saved();
|
|
8173
|
-
console.log(r ? describe2(r) : "remote access is off; `toyon remote
|
|
8174
|
-
|
|
8175
|
-
|
|
6498
|
+
const r = h ? h.remote ?? null : saved();
|
|
6499
|
+
console.log(r ? describe2(r) : "remote access is off; `toyon remote --tailscale` turns it on");
|
|
6500
|
+
const ts = h?.tailscale ?? await readiness(tailscaleCli());
|
|
6501
|
+
if (ts && !(r && ts.state === "ready"))
|
|
6502
|
+
console.log(ts.line);
|
|
8176
6503
|
return 0;
|
|
8177
6504
|
}
|
|
8178
|
-
let r = null;
|
|
8179
6505
|
if (cmd.tailscale) {
|
|
8180
|
-
|
|
8181
|
-
|
|
8182
|
-
|
|
8183
|
-
|
|
8184
|
-
if (
|
|
8185
|
-
|
|
8186
|
-
|
|
8187
|
-
|
|
6506
|
+
if (h) {
|
|
6507
|
+
const now = await switched({ tailscale: true });
|
|
6508
|
+
if (now === false)
|
|
6509
|
+
return 1;
|
|
6510
|
+
if (now)
|
|
6511
|
+
console.log(describe2(now));
|
|
6512
|
+
} else {
|
|
6513
|
+
let r;
|
|
6514
|
+
try {
|
|
6515
|
+
mkdirSync5(home, { recursive: true });
|
|
6516
|
+
r = await turnTailnetOn(tailscaleCli(), port, remoteFile);
|
|
6517
|
+
} catch (e) {
|
|
6518
|
+
if (!(e instanceof TailscaleError))
|
|
6519
|
+
throw e;
|
|
6520
|
+
console.error(`toyon: ${e.message}`);
|
|
6521
|
+
return 1;
|
|
6522
|
+
}
|
|
6523
|
+
console.log(`${describe2(r)}; Toyon reads it when it starts`);
|
|
8188
6524
|
}
|
|
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))
|
|
6525
|
+
console.log(HOW_TO_OPEN);
|
|
6526
|
+
return 0;
|
|
6527
|
+
}
|
|
6528
|
+
if (cmd.to === "off") {
|
|
6529
|
+
if (h) {
|
|
6530
|
+
if (await switched({ off: true }) === false)
|
|
6531
|
+
return 1;
|
|
6532
|
+
} else {
|
|
6533
|
+
try {
|
|
6534
|
+
await turnRemoteOff(tailscaleCli(), port, remoteFile, saved());
|
|
6535
|
+
} catch (e) {
|
|
6536
|
+
if (!(e instanceof TailscaleError))
|
|
6537
|
+
throw e;
|
|
8205
6538
|
console.error(`toyon: could not remove tailscale serve entries: ${e.message}`);
|
|
6539
|
+
}
|
|
8206
6540
|
}
|
|
8207
|
-
|
|
8208
|
-
|
|
8209
|
-
|
|
8210
|
-
|
|
8211
|
-
|
|
8212
|
-
|
|
8213
|
-
|
|
8214
|
-
|
|
6541
|
+
console.log("remote access is off");
|
|
6542
|
+
return 0;
|
|
6543
|
+
}
|
|
6544
|
+
const to = cmd.to;
|
|
6545
|
+
const view = acceptRemote({ host: to, previews: cmd.ports ? portPreviews(to) : hostPreviews(to) }, managed.policy);
|
|
6546
|
+
if (typeof view === "string") {
|
|
6547
|
+
console.error(`toyon: ${view}`);
|
|
6548
|
+
return 1;
|
|
6549
|
+
}
|
|
6550
|
+
if (h) {
|
|
6551
|
+
if (await switched(view) === false)
|
|
6552
|
+
return 1;
|
|
6553
|
+
} else {
|
|
6554
|
+
mkdirSync5(home, { recursive: true });
|
|
6555
|
+
writeFileSync5(remoteFile, `${JSON.stringify(view, null, 2)}
|
|
6556
|
+
`);
|
|
6557
|
+
}
|
|
6558
|
+
console.log(describe2(view));
|
|
6559
|
+
if (addressedByPort(view.previews)) {
|
|
6560
|
+
console.log(`point a TLS front for ${view.host} at 127.0.0.1:${port} on 443, and each of ports ${ports} at`);
|
|
6561
|
+
console.log("the same port on 127.0.0.1");
|
|
6562
|
+
} else {
|
|
6563
|
+
console.log(`point a TLS front for ${view.host} and *.${view.host} at 127.0.0.1:${port}. With Caddy:
|
|
8215
6564
|
`);
|
|
8216
|
-
|
|
6565
|
+
console.log(` ${view.host}, *.${view.host} {
|
|
8217
6566
|
reverse_proxy 127.0.0.1:${port}
|
|
8218
6567
|
}
|
|
8219
6568
|
`);
|
|
8220
|
-
|
|
6569
|
+
console.log("the wildcard certificate needs Caddy's DNS challenge, through your DNS provider's module");
|
|
6570
|
+
}
|
|
6571
|
+
console.log("Toyon refuses the name over plain http; a device that opens it asks to be let in");
|
|
6572
|
+
if (!h)
|
|
6573
|
+
console.log("Toyon reads this when it starts");
|
|
6574
|
+
return 0;
|
|
6575
|
+
}
|
|
6576
|
+
|
|
6577
|
+
// src/pair.ts
|
|
6578
|
+
var POLL_MS = 2000;
|
|
6579
|
+
async function waiting() {
|
|
6580
|
+
const r = await daemonFetch("/knocks");
|
|
6581
|
+
return r?.ok ? await r.json() : [];
|
|
6582
|
+
}
|
|
6583
|
+
async function pair() {
|
|
6584
|
+
const h = await health();
|
|
6585
|
+
if (!h) {
|
|
6586
|
+
console.error("toyon: Toyon is not running. Start it with `toyon`, then run `toyon pair`.");
|
|
6587
|
+
return 1;
|
|
6588
|
+
}
|
|
6589
|
+
let remote = h.remote ?? null;
|
|
6590
|
+
if (!remote) {
|
|
6591
|
+
const r = await switchRemote({ tailscale: true });
|
|
6592
|
+
if (typeof r === "string") {
|
|
6593
|
+
console.error(`toyon: ${r}`);
|
|
6594
|
+
return 1;
|
|
8221
6595
|
}
|
|
8222
|
-
|
|
6596
|
+
remote = r.remote;
|
|
8223
6597
|
}
|
|
8224
|
-
if (
|
|
8225
|
-
|
|
8226
|
-
|
|
8227
|
-
openUrl(add);
|
|
6598
|
+
if (!remote) {
|
|
6599
|
+
console.error("toyon: remote access did not come on; `toyon remote` says what Tailscale is missing");
|
|
6600
|
+
return 1;
|
|
8228
6601
|
}
|
|
8229
|
-
|
|
8230
|
-
|
|
8231
|
-
|
|
8232
|
-
|
|
8233
|
-
|
|
8234
|
-
|
|
8235
|
-
|
|
8236
|
-
|
|
6602
|
+
console.log(machineLink(remote.host));
|
|
6603
|
+
console.log(HOW_TO_OPEN);
|
|
6604
|
+
if (isTailnetName(remote.host)) {
|
|
6605
|
+
const r = await daemonFetch("/phones");
|
|
6606
|
+
const phones = r?.ok ? await r.json() : null;
|
|
6607
|
+
console.log(tailnetLine(phones).text);
|
|
6608
|
+
}
|
|
6609
|
+
console.log("waiting for a device; ctrl-c to stop");
|
|
6610
|
+
const asked = new Set;
|
|
6611
|
+
for (;; ) {
|
|
6612
|
+
for (const k of await waiting()) {
|
|
6613
|
+
if (asked.has(k.id))
|
|
6614
|
+
continue;
|
|
6615
|
+
asked.add(k.id);
|
|
6616
|
+
const from = k.from === null ? "a device that opened the address" : `a Toyon page at ${new URL(k.from).host}`;
|
|
6617
|
+
const yes = await confirm(`${k.word} wants in (${from}). Let it in?`);
|
|
6618
|
+
const r = await daemonFetch(`/knock/${k.id}/answer`, { body: { letIn: yes } });
|
|
6619
|
+
if (!r?.ok)
|
|
6620
|
+
console.log(`${k.word} stopped waiting`);
|
|
6621
|
+
else
|
|
6622
|
+
console.log(yes ? `${k.word} is in` : `${k.word} turned away`);
|
|
6623
|
+
}
|
|
6624
|
+
await Bun.sleep(POLL_MS);
|
|
8237
6625
|
}
|
|
8238
|
-
return 0;
|
|
8239
6626
|
}
|
|
8240
6627
|
|
|
8241
6628
|
// src/stop.ts
|
|
8242
|
-
import { rmSync as
|
|
6629
|
+
import { rmSync as rmSync3 } from "fs";
|
|
8243
6630
|
var WAIT_MS = 1e4;
|
|
8244
6631
|
async function stop() {
|
|
8245
6632
|
const h = await health();
|
|
8246
6633
|
let pid = h?.pid ?? readPid();
|
|
8247
6634
|
if (pid !== null && !alive(pid)) {
|
|
8248
|
-
|
|
6635
|
+
rmSync3(pidFile, { force: true });
|
|
8249
6636
|
pid = null;
|
|
8250
6637
|
}
|
|
8251
6638
|
if (pid === null) {
|
|
@@ -8264,7 +6651,7 @@ async function stop() {
|
|
|
8264
6651
|
if (alive(pid)) {
|
|
8265
6652
|
process.kill(pid, "SIGKILL");
|
|
8266
6653
|
console.error(`daemon (pid ${pid}) did not exit in ${WAIT_MS / 1000}s; killed. Dev servers it ran may still be up.`);
|
|
8267
|
-
|
|
6654
|
+
rmSync3(pidFile, { force: true });
|
|
8268
6655
|
return 1;
|
|
8269
6656
|
}
|
|
8270
6657
|
console.log(`stopped Toyon (pid ${pid})`);
|
|
@@ -8291,12 +6678,11 @@ async function restart() {
|
|
|
8291
6678
|
}
|
|
8292
6679
|
|
|
8293
6680
|
// src/uninstall.ts
|
|
8294
|
-
import { existsSync as
|
|
8295
|
-
import { homedir as homedir3 } from "os";
|
|
6681
|
+
import { existsSync as existsSync10, readFileSync as readFileSync8, rmSync as rmSync4 } from "fs";
|
|
8296
6682
|
import { join as join6 } from "path";
|
|
8297
6683
|
function readState() {
|
|
8298
6684
|
const file = join6(home, DAEMON_FILES.state);
|
|
8299
|
-
if (!
|
|
6685
|
+
if (!existsSync10(file))
|
|
8300
6686
|
return {};
|
|
8301
6687
|
try {
|
|
8302
6688
|
return JSON.parse(readFileSync8(file, "utf8"));
|
|
@@ -8313,18 +6699,11 @@ async function git(cwd, ...args) {
|
|
|
8313
6699
|
return false;
|
|
8314
6700
|
}
|
|
8315
6701
|
}
|
|
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
6702
|
async function uninstall(opts) {
|
|
8324
6703
|
const state = readState();
|
|
8325
6704
|
const repos = state.repos ?? [];
|
|
8326
6705
|
const worktrees = (state.worktrees ?? []).filter((w) => w.kind !== "main");
|
|
8327
|
-
const
|
|
6706
|
+
const helper = join6(home, DAEMON_FILES.helper);
|
|
8328
6707
|
const branches = worktrees.map((w) => w.branch).filter((b) => !!b && b.startsWith("toyon/"));
|
|
8329
6708
|
console.log("toyon uninstall removes:");
|
|
8330
6709
|
console.log(` ${home} (state, transcripts, agent adapters, ${worktrees.length} worktree director${worktrees.length === 1 ? "y" : "ies"})`);
|
|
@@ -8332,8 +6711,8 @@ async function uninstall(opts) {
|
|
|
8332
6711
|
const repo = repos.find((r) => r.id === w.repoId);
|
|
8333
6712
|
console.log(` ${w.path} (worktree of ${repo?.path ?? "?"})`);
|
|
8334
6713
|
}
|
|
8335
|
-
if (
|
|
8336
|
-
console.log(` ${app
|
|
6714
|
+
if (existsSync10(helper))
|
|
6715
|
+
console.log(` ${helper} (the hidden helper that starts Toyon from the Dock app)`);
|
|
8337
6716
|
console.log("and stops the daemon if it is running.");
|
|
8338
6717
|
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
6718
|
if (!opts.yes && !await confirm("continue?")) {
|
|
@@ -8344,18 +6723,21 @@ async function uninstall(opts) {
|
|
|
8344
6723
|
await stop();
|
|
8345
6724
|
for (const w of worktrees) {
|
|
8346
6725
|
const repo = repos.find((r) => r.id === w.repoId);
|
|
8347
|
-
if (repo &&
|
|
6726
|
+
if (repo && existsSync10(repo.path)) {
|
|
8348
6727
|
const ok = await git(repo.path, "worktree", "remove", "--force", w.path);
|
|
8349
|
-
if (!ok &&
|
|
8350
|
-
|
|
6728
|
+
if (!ok && existsSync10(w.path))
|
|
6729
|
+
rmSync4(w.path, { recursive: true, force: true });
|
|
8351
6730
|
await git(repo.path, "worktree", "prune");
|
|
8352
|
-
} else if (
|
|
8353
|
-
|
|
6731
|
+
} else if (existsSync10(w.path)) {
|
|
6732
|
+
rmSync4(w.path, { recursive: true, force: true });
|
|
8354
6733
|
}
|
|
8355
6734
|
}
|
|
8356
|
-
|
|
8357
|
-
|
|
8358
|
-
|
|
6735
|
+
if (existsSync10(helper)) {
|
|
6736
|
+
try {
|
|
6737
|
+
await Bun.spawn([LSREGISTER, "-u", helper], { stdout: "ignore", stderr: "ignore" }).exited;
|
|
6738
|
+
} catch {}
|
|
6739
|
+
}
|
|
6740
|
+
rmSync4(home, { recursive: true, force: true });
|
|
8359
6741
|
console.log("removed. `npm uninstall -g toyon` removes the command itself.");
|
|
8360
6742
|
return 0;
|
|
8361
6743
|
}
|
|
@@ -8445,13 +6827,10 @@ async function restartOnto(version) {
|
|
|
8445
6827
|
}
|
|
8446
6828
|
|
|
8447
6829
|
// src/cli.ts
|
|
8448
|
-
function behind(daemonVersion) {
|
|
8449
|
-
return daemonVersion === undefined || newer(package_default.version, daemonVersion);
|
|
8450
|
-
}
|
|
8451
6830
|
async function open2(cmd) {
|
|
8452
6831
|
const explicit = cmd.path !== null;
|
|
8453
6832
|
const target = resolve(cmd.path ?? process.cwd());
|
|
8454
|
-
const register = explicit ||
|
|
6833
|
+
const register = explicit || existsSync11(join7(target, ".git"));
|
|
8455
6834
|
if (process.platform === "linux") {
|
|
8456
6835
|
const missing = missingSandboxTools();
|
|
8457
6836
|
const blocked = missing.length === 0 ? bwrapStartError() : null;
|
|
@@ -8460,28 +6839,12 @@ async function open2(cmd) {
|
|
|
8460
6839
|
else if (blocked)
|
|
8461
6840
|
console.log(bwrapBlockedAdvice(blocked, userNamespacesRestricted()));
|
|
8462
6841
|
}
|
|
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");
|
|
6842
|
+
const daemon = await ensureDaemon();
|
|
6843
|
+
if (!daemon)
|
|
8476
6844
|
return 1;
|
|
8477
|
-
|
|
8478
|
-
const file = explicit && existsSync10(target) && statSync4(target).isFile();
|
|
6845
|
+
const file = explicit && existsSync11(target) && statSync4(target).isFile();
|
|
8479
6846
|
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
|
-
});
|
|
6847
|
+
const res = await post("/open", daemon.token, { path: target });
|
|
8485
6848
|
if (!res.ok) {
|
|
8486
6849
|
console.error(`could not open ${target}: ${await res.text()}`);
|
|
8487
6850
|
return 1;
|
|
@@ -8489,39 +6852,34 @@ async function open2(cmd) {
|
|
|
8489
6852
|
const opened = await res.json();
|
|
8490
6853
|
console.log(opened.kind === "file" ? `toyon: opening ${target} in its project` : `toyon: opening ${target}`);
|
|
8491
6854
|
} 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
|
-
});
|
|
6855
|
+
const res = await post("/register", daemon.token, { path: target });
|
|
8497
6856
|
if (!res.ok) {
|
|
8498
6857
|
console.error(`could not open ${target}: ${await res.text()}`);
|
|
8499
|
-
if (explicit || !cmd.app
|
|
6858
|
+
if (explicit || !cmd.app)
|
|
8500
6859
|
return 1;
|
|
8501
6860
|
}
|
|
8502
6861
|
}
|
|
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);
|
|
6862
|
+
if (cmd.app)
|
|
6863
|
+
showAppWindow(daemon);
|
|
6864
|
+
else {
|
|
6865
|
+
console.log(`toyon: ${daemon.url}`);
|
|
6866
|
+
openUrl(daemon.url);
|
|
8517
6867
|
}
|
|
8518
|
-
|
|
8519
|
-
|
|
8520
|
-
|
|
6868
|
+
return 0;
|
|
6869
|
+
}
|
|
6870
|
+
async function start() {
|
|
6871
|
+
const daemon = await ensureDaemon();
|
|
6872
|
+
if (!daemon)
|
|
6873
|
+
return 1;
|
|
6874
|
+
console.log(`toyon: ${daemon.url}`);
|
|
8521
6875
|
return 0;
|
|
8522
6876
|
}
|
|
8523
6877
|
async function run(cmd) {
|
|
8524
6878
|
switch (cmd.kind) {
|
|
6879
|
+
case "start":
|
|
6880
|
+
return start();
|
|
6881
|
+
case "helper":
|
|
6882
|
+
return helper(cmd.args);
|
|
8525
6883
|
case "help":
|
|
8526
6884
|
process.stdout.write(HELP);
|
|
8527
6885
|
return 0;
|