@monimesl/dot-cli 0.1.0-alpha.21 → 0.1.0-alpha.24
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/dist/cli.js +42 -25
- package/dist/cli.js.map +1 -1
- package/dist/{server-B9-F93mS.js → server-DMnWDdJ6.js} +47 -34
- package/dist/{server-B9-F93mS.js.map → server-DMnWDdJ6.js.map} +1 -1
- package/dist/templates/showcase/dot.ts +9 -1
- package/dist/templates/showcase/pages/basics/bars/controller.ts +13 -2
- package/dist/templates/showcase/pages/basics/bars/state.ts +1 -0
- package/dist/templates/showcase/pages/basics/bars/view.dml +8 -0
- package/dist/templates/showcase/pages/basics/colors/controller.ts +112 -0
- package/dist/templates/showcase/pages/basics/colors/state.ts +17 -0
- package/dist/templates/showcase/pages/basics/colors/view.dml +142 -0
- package/dist/templates/showcase/pages/basics/concert/controller.ts +16 -0
- package/dist/templates/showcase/pages/basics/concert/state.ts +7 -0
- package/dist/templates/showcase/pages/basics/concert/view.dml +20 -0
- package/dist/templates/showcase/pages/basics/pick-genre/controller.ts +7 -1
- package/dist/templates/showcase/pages/basics/pick-genre/view.dml +1 -0
- package/dist/templates/showcase/pages/basics/share/concerts.ts +31 -0
- package/dist/templates/showcase/pages/basics/share/controller.ts +12 -0
- package/dist/templates/showcase/pages/basics/share/state.ts +5 -0
- package/dist/templates/showcase/pages/basics/share/view.dml +21 -0
- package/dist/templates/showcase/pages/components/styles/view.dml +1 -1
- package/dist/templates/showcase/pages/dash/account/controller.ts +23 -0
- package/dist/templates/showcase/pages/dash/account/state.ts +7 -0
- package/dist/templates/showcase/pages/dash/account/view.dml +23 -0
- package/dist/templates/showcase/pages/dash/cache/controller.ts +2 -2
- package/dist/templates/showcase/pages/dash/cache/view.dml +1 -1
- package/dist/templates/showcase/pages/dash/calls/controller.ts +14 -0
- package/dist/templates/showcase/pages/dash/calls/state.ts +3 -0
- package/dist/templates/showcase/pages/dash/calls/view.dml +17 -1
- package/dist/templates/showcase/pages/dash/crypto/controller.ts +38 -0
- package/dist/templates/showcase/pages/dash/crypto/state.ts +10 -0
- package/dist/templates/showcase/pages/dash/crypto/view.dml +48 -0
- package/dist/templates/showcase/pages/dash/files/controller.ts +0 -20
- package/dist/templates/showcase/pages/dash/files/state.ts +1 -2
- package/dist/templates/showcase/pages/dash/files/view.dml +4 -5
- package/dist/templates/showcase/pages/dash/media/controller.ts +29 -0
- package/dist/templates/showcase/pages/dash/media/state.ts +4 -0
- package/dist/templates/showcase/pages/dash/media/view.dml +20 -1
- package/dist/templates/showcase/pages/dash/secrets/view.dml +1 -1
- package/dist/templates/showcase/pages/dash/system/controller.ts +3 -3
- package/dist/templates/showcase/pages/dash/system/state.ts +2 -2
- package/dist/templates/showcase/pages/dash/system/view.dml +1 -2
- package/dist/templates/showcase/pages/index/state.ts +29 -4
- package/package.json +6 -6
package/dist/cli.js
CHANGED
|
@@ -8,7 +8,7 @@ import { existsSync, readFileSync, readdirSync, watch } from "node:fs";
|
|
|
8
8
|
import { cp, mkdir, readFile, readdir, writeFile } from "node:fs/promises";
|
|
9
9
|
import { DmlParseError } from "@monimesl/dot-dml-parser";
|
|
10
10
|
import { ScriptParseError, parseDotModule } from "@monimesl/dot-script-parser";
|
|
11
|
-
import { isPageId } from "@monimesl/dot-core";
|
|
11
|
+
import { DEFAULT_DASH_API_VERSION, isPageId } from "@monimesl/dot-core";
|
|
12
12
|
import { renderUnicodeCompact } from "uqr";
|
|
13
13
|
import { createHash, createHmac, createPrivateKey, createPublicKey, randomBytes, sign, timingSafeEqual } from "node:crypto";
|
|
14
14
|
import { homedir, networkInterfaces } from "node:os";
|
|
@@ -61,6 +61,9 @@ function findDotRoot(dir) {
|
|
|
61
61
|
function resolveOutDir(root, outDir) {
|
|
62
62
|
return resolve(root, outDir ?? "dist");
|
|
63
63
|
}
|
|
64
|
+
function isOneOf(values, name) {
|
|
65
|
+
return values.includes(name);
|
|
66
|
+
}
|
|
64
67
|
//#endregion
|
|
65
68
|
//#region src/create/template.ts
|
|
66
69
|
const TEMPLATES = ["starter", "showcase"];
|
|
@@ -69,7 +72,7 @@ const TEMPLATE_HINTS = {
|
|
|
69
72
|
showcase: "a page for each feature, to learn from"
|
|
70
73
|
};
|
|
71
74
|
function isTemplate(name) {
|
|
72
|
-
return TEMPLATES
|
|
75
|
+
return isOneOf(TEMPLATES, name);
|
|
73
76
|
}
|
|
74
77
|
const PAGE_FILES = {
|
|
75
78
|
"view.dml": "<View>\n <Text>My new page</Text>\n</View>\n",
|
|
@@ -150,6 +153,7 @@ function dotJson({ name, dotPackage, template }) {
|
|
|
150
153
|
};
|
|
151
154
|
if (template === "showcase") {
|
|
152
155
|
dot.permissions = {
|
|
156
|
+
account: "Show your name on your concert ticket",
|
|
153
157
|
camera: "Take a photo for your concert ticket, or scan a ticket's QR code",
|
|
154
158
|
photoLibrary: "Choose a photo for your concert ticket",
|
|
155
159
|
files: "Attach your concert ticket",
|
|
@@ -161,6 +165,7 @@ function dotJson({ name, dotPackage, template }) {
|
|
|
161
165
|
"httpbin.org"
|
|
162
166
|
] };
|
|
163
167
|
}
|
|
168
|
+
dot.dash = { minApiVersion: DEFAULT_DASH_API_VERSION };
|
|
164
169
|
return formatJson(dot);
|
|
165
170
|
}
|
|
166
171
|
const TEMPLATE_READMES = {
|
|
@@ -206,10 +211,11 @@ other host fail. Your editor can complete the other fields from the schema the f
|
|
|
206
211
|
|
|
207
212
|
## Which Dash opens it
|
|
208
213
|
|
|
209
|
-
|
|
210
|
-
the
|
|
211
|
-
|
|
212
|
-
|
|
214
|
+
\`dash.minApiVersion\` in \`dot.json\` is the Dash API version the dot needs, such as \`1.0\`. Dash
|
|
215
|
+
opens the dot when it offers that version, or a newer minor of the same major. Each Dash call's docs
|
|
216
|
+
say which version it came in, after \`@since\`. To use a newer call and still open on older Dash,
|
|
217
|
+
keep \`minApiVersion\` and check \`this.dash.supports('contacts.pickPhone')\` before the call.
|
|
218
|
+
\`dotctl dev\` warns when the dot makes a newer call without checking.
|
|
213
219
|
|
|
214
220
|
## .env
|
|
215
221
|
|
|
@@ -268,7 +274,8 @@ function isInDotWorkspace(dir) {
|
|
|
268
274
|
}
|
|
269
275
|
function templateDir(template) {
|
|
270
276
|
const example = join(cliRoot(), "../../examples", template);
|
|
271
|
-
|
|
277
|
+
if (existsSync(example)) return example;
|
|
278
|
+
return join(cliRoot(), "dist/templates", template);
|
|
272
279
|
}
|
|
273
280
|
function cliVersion() {
|
|
274
281
|
return readPackageJson(join(cliRoot(), "package.json")).version;
|
|
@@ -346,7 +353,7 @@ const PACKAGE_MANAGERS = [
|
|
|
346
353
|
"bun"
|
|
347
354
|
];
|
|
348
355
|
function isPackageManager(name) {
|
|
349
|
-
return PACKAGE_MANAGERS
|
|
356
|
+
return isOneOf(PACKAGE_MANAGERS, name);
|
|
350
357
|
}
|
|
351
358
|
function launchedBy(userAgent = process.env.npm_config_user_agent ?? "") {
|
|
352
359
|
return PACKAGE_MANAGERS.find((name) => userAgent.startsWith(`${name}/`)) ?? "npm";
|
|
@@ -476,7 +483,7 @@ var LocalDeviceServer = class {
|
|
|
476
483
|
this.#announce();
|
|
477
484
|
}
|
|
478
485
|
close() {
|
|
479
|
-
|
|
486
|
+
this.#wakeWaitingDevices();
|
|
480
487
|
return new Promise((resolve) => {
|
|
481
488
|
this.#server.close(() => resolve());
|
|
482
489
|
this.#server.closeAllConnections();
|
|
@@ -484,6 +491,9 @@ var LocalDeviceServer = class {
|
|
|
484
491
|
}
|
|
485
492
|
#announce() {
|
|
486
493
|
this.#generation += 1;
|
|
494
|
+
this.#wakeWaitingDevices();
|
|
495
|
+
}
|
|
496
|
+
#wakeWaitingDevices() {
|
|
487
497
|
for (const wake of this.#waiting) wake();
|
|
488
498
|
}
|
|
489
499
|
#handle(request, response) {
|
|
@@ -548,20 +558,20 @@ var LocalDeviceServer = class {
|
|
|
548
558
|
sendJson(response, { generation: this.#generation });
|
|
549
559
|
return;
|
|
550
560
|
}
|
|
551
|
-
const
|
|
561
|
+
const stopWaiting = () => {
|
|
552
562
|
clearTimeout(timer);
|
|
553
563
|
this.#waiting.delete(wake);
|
|
564
|
+
};
|
|
565
|
+
const wake = () => {
|
|
566
|
+
stopWaiting();
|
|
554
567
|
sendJson(response, { generation: this.#generation });
|
|
555
568
|
};
|
|
556
569
|
const timer = setTimeout(() => {
|
|
557
|
-
|
|
570
|
+
stopWaiting();
|
|
558
571
|
response.writeHead(204).end();
|
|
559
572
|
}, WAIT_MS);
|
|
560
573
|
this.#waiting.add(wake);
|
|
561
|
-
response.on("close",
|
|
562
|
-
clearTimeout(timer);
|
|
563
|
-
this.#waiting.delete(wake);
|
|
564
|
-
});
|
|
574
|
+
response.on("close", stopWaiting);
|
|
565
575
|
}
|
|
566
576
|
#receiveLog(request, response, from) {
|
|
567
577
|
readLogText(request).then((text) => {
|
|
@@ -607,7 +617,8 @@ function buildFileName(path) {
|
|
|
607
617
|
function isAuthorized(request, token) {
|
|
608
618
|
const given = Buffer.from(request.headers.authorization ?? "");
|
|
609
619
|
const expected = Buffer.from(`Bearer ${token}`);
|
|
610
|
-
|
|
620
|
+
if (given.length !== expected.length) return false;
|
|
621
|
+
return timingSafeEqual(given, expected);
|
|
611
622
|
}
|
|
612
623
|
function sendJson(response, body) {
|
|
613
624
|
response.writeHead(200, { "content-type": "application/json" }).end(JSON.stringify(body));
|
|
@@ -616,9 +627,10 @@ async function readLogText(request) {
|
|
|
616
627
|
const chunks = [];
|
|
617
628
|
let size = 0;
|
|
618
629
|
for await (const chunk of request) {
|
|
619
|
-
|
|
630
|
+
const bytes = chunk;
|
|
631
|
+
size += bytes.length;
|
|
620
632
|
if (size > MAX_LOG_BYTES) throw new Error(`A device sent more than ${MAX_LOG_BYTES} bytes of log at once`);
|
|
621
|
-
chunks.push(
|
|
633
|
+
chunks.push(bytes);
|
|
622
634
|
}
|
|
623
635
|
return Buffer.concat(chunks).toString("utf8");
|
|
624
636
|
}
|
|
@@ -774,7 +786,8 @@ const HIDE_CURSOR = "\x1B[?25l";
|
|
|
774
786
|
const SHOW_CURSOR = "\x1B[?25h";
|
|
775
787
|
async function select(question, choices, fallback, { input, output } = TERMINAL) {
|
|
776
788
|
if (!input.isTTY) return fallback;
|
|
777
|
-
let selectedIndex =
|
|
789
|
+
let selectedIndex = choices.findIndex((choice) => choice.value === fallback);
|
|
790
|
+
if (selectedIndex < 0) selectedIndex = 0;
|
|
778
791
|
let valueWidth = 0;
|
|
779
792
|
if (choices.some((choice) => choice.hint)) valueWidth = Math.max(...choices.map((choice) => choice.value.length));
|
|
780
793
|
const formatChoice = (choice, index) => {
|
|
@@ -786,7 +799,8 @@ async function select(question, choices, fallback, { input, output } = TERMINAL)
|
|
|
786
799
|
};
|
|
787
800
|
let drawnLines = 0;
|
|
788
801
|
const draw = (lines) => {
|
|
789
|
-
|
|
802
|
+
let moveUp = "";
|
|
803
|
+
if (drawnLines > 0) moveUp = cursorUp(drawnLines);
|
|
790
804
|
output.write(`${moveUp}${ERASE_BELOW}${lines.join("\n")}\n`);
|
|
791
805
|
drawnLines = lines.length;
|
|
792
806
|
};
|
|
@@ -837,7 +851,9 @@ async function ask(question, fallback, hint, { input, output } = TERMINAL) {
|
|
|
837
851
|
output
|
|
838
852
|
});
|
|
839
853
|
try {
|
|
840
|
-
|
|
854
|
+
const trimmedAnswer = (await readline.question(`${styleText("bold", question)}${hintText}${defaultMark}: `)).trim();
|
|
855
|
+
if (trimmedAnswer === "") return fallback;
|
|
856
|
+
return trimmedAnswer;
|
|
841
857
|
} catch (error) {
|
|
842
858
|
if (error.name === "AbortError") return;
|
|
843
859
|
throw error;
|
|
@@ -938,7 +954,7 @@ async function main(argv) {
|
|
|
938
954
|
return runBuild(options);
|
|
939
955
|
}
|
|
940
956
|
async function serveLanguageServer() {
|
|
941
|
-
const { serveStdio } = await import("./server-
|
|
957
|
+
const { serveStdio } = await import("./server-DMnWDdJ6.js");
|
|
942
958
|
serveStdio();
|
|
943
959
|
return new Promise(() => {});
|
|
944
960
|
}
|
|
@@ -1043,7 +1059,8 @@ async function createDot(dir, flags) {
|
|
|
1043
1059
|
dotPackage,
|
|
1044
1060
|
template
|
|
1045
1061
|
});
|
|
1046
|
-
|
|
1062
|
+
let path = relative(process.cwd(), root);
|
|
1063
|
+
if (path === "") path = ".";
|
|
1047
1064
|
console.log(`\nCreated ${name} in ${path}`);
|
|
1048
1065
|
if (workspace) console.log("It is inside the Dot repository, so it uses the workspace packages.");
|
|
1049
1066
|
let packageManager;
|
|
@@ -1059,14 +1076,14 @@ async function createDot(dir, flags) {
|
|
|
1059
1076
|
return 0;
|
|
1060
1077
|
}
|
|
1061
1078
|
function runCommand(command, args, cwd) {
|
|
1062
|
-
return new Promise((
|
|
1079
|
+
return new Promise((resolve, reject) => {
|
|
1063
1080
|
const child = spawn(command, args, {
|
|
1064
1081
|
cwd,
|
|
1065
1082
|
stdio: "inherit",
|
|
1066
1083
|
shell: process.platform === "win32"
|
|
1067
1084
|
});
|
|
1068
1085
|
child.on("error", reject);
|
|
1069
|
-
child.on("exit", (
|
|
1086
|
+
child.on("exit", (exitCode) => resolve(exitCode ?? 1));
|
|
1070
1087
|
});
|
|
1071
1088
|
}
|
|
1072
1089
|
async function askDotPackage(suggested) {
|