@bitmagic/cli 0.1.53-dev.1 → 0.1.53-dev.11
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 +140 -36
- package/dist/assets/revoxelize.d.ts +61 -1
- package/dist/assets/revoxelize.js +157 -13
- package/dist/assets/revoxelize.js.map +1 -1
- package/dist/cli.d.ts +35 -1
- package/dist/cli.js +18 -1
- package/dist/cli.js.map +1 -1
- package/dist/commands/assets.js +3 -2
- package/dist/commands/assets.js.map +1 -1
- package/dist/commands/build.d.ts +4 -0
- package/dist/commands/build.js +7 -1
- package/dist/commands/build.js.map +1 -1
- package/dist/commands/cover.d.ts +5 -0
- package/dist/commands/cover.js +3 -0
- package/dist/commands/cover.js.map +1 -1
- package/dist/commands/dev.js +1 -2
- package/dist/commands/dev.js.map +1 -1
- package/dist/commands/forge.d.ts +4 -0
- package/dist/commands/forge.js +9 -0
- package/dist/commands/forge.js.map +1 -1
- package/dist/commands/generate.d.ts +25 -0
- package/dist/commands/generate.js +80 -8
- package/dist/commands/generate.js.map +1 -1
- package/dist/commands/init.d.ts +4 -0
- package/dist/commands/init.js +12 -1
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/publish.d.ts +39 -5
- package/dist/commands/publish.js +102 -21
- package/dist/commands/publish.js.map +1 -1
- package/dist/commands/reload.js +1 -3
- package/dist/commands/reload.js.map +1 -1
- package/dist/commands/reset-account.js +25 -8
- package/dist/commands/reset-account.js.map +1 -1
- package/dist/commands/self-update.d.ts +67 -0
- package/dist/commands/self-update.js +196 -0
- package/dist/commands/self-update.js.map +1 -0
- package/dist/commands/upgrade.js +5 -2
- package/dist/commands/upgrade.js.map +1 -1
- package/dist/editor/asset-detail-panel.d.ts +2 -2
- package/dist/editor/asset-detail-panel.js +5 -2
- package/dist/editor/asset-detail-panel.js.map +1 -1
- package/dist/editor/cli-update.d.ts +32 -0
- package/dist/editor/cli-update.js +67 -0
- package/dist/editor/cli-update.js.map +1 -0
- package/dist/editor/publish-panel.d.ts +31 -0
- package/dist/editor/publish-panel.js +69 -0
- package/dist/editor/publish-panel.js.map +1 -0
- package/dist/editor/server.js +43 -1
- package/dist/editor/server.js.map +1 -1
- package/dist/editor/shell-page.js +249 -8
- package/dist/editor/shell-page.js.map +1 -1
- package/dist/forge/upload-proxy.d.ts +14 -0
- package/dist/forge/upload-proxy.js +28 -1
- package/dist/forge/upload-proxy.js.map +1 -1
- package/dist/generate/model.d.ts +7 -0
- package/dist/generate/model.js +13 -3
- package/dist/generate/model.js.map +1 -1
- package/dist/generate/prop.d.ts +20 -0
- package/dist/generate/prop.js +22 -2
- package/dist/generate/prop.js.map +1 -1
- package/dist/generate/vehicle.d.ts +2 -0
- package/dist/generate/vehicle.js +1 -0
- package/dist/generate/vehicle.js.map +1 -1
- package/dist/project/dev-handle.d.ts +28 -0
- package/dist/project/dev-handle.js +43 -0
- package/dist/project/dev-handle.js.map +1 -1
- package/dist/project/jobs.js +11 -9
- package/dist/project/jobs.js.map +1 -1
- package/dist/publish/bundle.d.ts +35 -8
- package/dist/publish/bundle.js +41 -13
- package/dist/publish/bundle.js.map +1 -1
- package/dist/publish/client.d.ts +13 -2
- package/dist/publish/client.js.map +1 -1
- package/dist/publish/record.d.ts +22 -0
- package/dist/publish/record.js +62 -0
- package/dist/publish/record.js.map +1 -0
- package/dist/render/qr-output.d.ts +44 -0
- package/dist/render/qr-output.js +71 -0
- package/dist/render/qr-output.js.map +1 -0
- package/dist/render/qr-png.d.ts +37 -0
- package/dist/render/qr-png.js +111 -0
- package/dist/render/qr-png.js.map +1 -0
- package/dist/render/qr-terminal.d.ts +63 -0
- package/dist/render/qr-terminal.js +142 -0
- package/dist/render/qr-terminal.js.map +1 -0
- package/dist/render/qr.d.ts +51 -0
- package/dist/render/qr.js +516 -0
- package/dist/render/qr.js.map +1 -0
- package/dist/scaffold/project-files.d.ts +42 -9
- package/dist/scaffold/project-files.js +242 -43
- package/dist/scaffold/project-files.js.map +1 -1
- package/dist/scaffold/project.js +2 -1
- package/dist/scaffold/project.js.map +1 -1
- package/dist/scaffold/suggest-template.d.ts +2 -0
- package/dist/scaffold/suggest-template.js +2 -1
- package/dist/scaffold/suggest-template.js.map +1 -1
- package/dist/telemetry/command-context.d.ts +12 -0
- package/dist/telemetry/command-context.js +7 -0
- package/dist/telemetry/command-context.js.map +1 -1
- package/dist/telemetry/creator-prompt.d.ts +35 -0
- package/dist/telemetry/creator-prompt.js +45 -0
- package/dist/telemetry/creator-prompt.js.map +1 -0
- package/dist/update/check.js +2 -1
- package/dist/update/check.js.map +1 -1
- package/dist/update/notice.d.ts +31 -1
- package/dist/update/notice.js +39 -5
- package/dist/update/notice.js.map +1 -1
- package/dist/update/self-install.d.ts +175 -0
- package/dist/update/self-install.js +335 -0
- package/dist/update/self-install.js.map +1 -0
- package/package.json +4 -4
package/dist/publish/bundle.d.ts
CHANGED
|
@@ -1,5 +1,14 @@
|
|
|
1
|
-
/**
|
|
1
|
+
/**
|
|
2
|
+
* The configs the scaffold vendors alongside `engine/`, one per bundle mode.
|
|
3
|
+
*
|
|
4
|
+
* The default leaves three.js, Rapier and the rest of the import map's packages to the CDN, which
|
|
5
|
+
* is what every production publish from the Creator does. The standalone one inlines them, for a
|
|
6
|
+
* game that has to run with no network at all.
|
|
7
|
+
*/
|
|
2
8
|
export declare const VITE_PUBLISH_CONFIG = "vite.publish.config.js";
|
|
9
|
+
export declare const VITE_PUBLISH_STANDALONE_CONFIG = "vite.publish-standalone.config.js";
|
|
10
|
+
/** The vendored config a build of this mode loads. */
|
|
11
|
+
export declare function publishConfigFor(singleFile: boolean): string;
|
|
3
12
|
/**
|
|
4
13
|
* What was built, and from what.
|
|
5
14
|
*
|
|
@@ -9,6 +18,15 @@ export declare const VITE_PUBLISH_CONFIG = "vite.publish.config.js";
|
|
|
9
18
|
export interface BuildManifest {
|
|
10
19
|
engineVersion: string;
|
|
11
20
|
fingerprint: string;
|
|
21
|
+
/**
|
|
22
|
+
* Whether this bundle inlines the CDN packages (`--single-file`) or leaves them external.
|
|
23
|
+
*
|
|
24
|
+
* Recorded because nothing else can tell the two apart. The mode changes no file on disk, so it
|
|
25
|
+
* does not move the fingerprint — and `publish` reuses a build on the fingerprint alone. Without
|
|
26
|
+
* this field, `bitmagic publish --single-file` straight after a default build would happily ship
|
|
27
|
+
* the external one, and the reverse.
|
|
28
|
+
*/
|
|
29
|
+
singleFile: boolean;
|
|
12
30
|
bytes: number;
|
|
13
31
|
/** Recorded for the publish audit trail. The server stores it; it cannot verify it. */
|
|
14
32
|
sha256: string;
|
|
@@ -23,15 +41,24 @@ export declare function writeBuildManifest(root: string, manifest: BuildManifest
|
|
|
23
41
|
/** The last build's manifest, or null if there is none to trust — same contract as readVerifyRecord. */
|
|
24
42
|
export declare function readBuildManifest(root: string): BuildManifest | null;
|
|
25
43
|
/**
|
|
26
|
-
* Compile and bundle the project into one
|
|
44
|
+
* Compile and bundle the project into one HTML file, and record what was built.
|
|
45
|
+
*
|
|
46
|
+
* One file either way — `bitmagic publish` PUTs a single object and api-server range-reads that
|
|
47
|
+
* same object to confirm the meta block, so there is nowhere for a second file to go. What the
|
|
48
|
+
* mode changes is what is INSIDE it: by default the engine, the game and its data are inlined
|
|
49
|
+
* while three.js, Rapier and the other CDN packages are fetched at runtime, matching what the
|
|
50
|
+
* Creator publishes; `singleFile` inlines those too, for a game that must run with no network.
|
|
27
51
|
*
|
|
28
52
|
* Exit code 1 on failure, matching the table in the spec: a build failure is the creator's own
|
|
29
53
|
* code, and the compiler's output has already been printed.
|
|
30
54
|
*
|
|
31
|
-
* The pre-flight below runs BEFORE `tsc`, not after: a project scaffolded before
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
55
|
+
* The pre-flight below runs BEFORE `tsc`, not after: a project scaffolded before the config it
|
|
56
|
+
* needs existed has none for vite to load, and without this check the creator pays a full
|
|
57
|
+
* type-check and then reads a raw vite "config not found" that names no remedy. `bitmagic upgrade`
|
|
58
|
+
* is the remedy — it vendors the file without touching game code — so the error says so. It names
|
|
59
|
+
* the config for the mode actually asked for, since a project can easily have one and not the
|
|
60
|
+
* other: the standalone config was added later than the default one.
|
|
36
61
|
*/
|
|
37
|
-
export declare function runBuild(root: string, engineVersion: string
|
|
62
|
+
export declare function runBuild(root: string, engineVersion: string, options?: {
|
|
63
|
+
singleFile?: boolean;
|
|
64
|
+
}): BuildManifest;
|
package/dist/publish/bundle.js
CHANGED
|
@@ -5,8 +5,19 @@ import * as path from 'path';
|
|
|
5
5
|
import { CliError } from '../errors.js';
|
|
6
6
|
import { projectBin } from '../project/context.js';
|
|
7
7
|
import { computeFingerprint } from './fingerprint.js';
|
|
8
|
-
/**
|
|
8
|
+
/**
|
|
9
|
+
* The configs the scaffold vendors alongside `engine/`, one per bundle mode.
|
|
10
|
+
*
|
|
11
|
+
* The default leaves three.js, Rapier and the rest of the import map's packages to the CDN, which
|
|
12
|
+
* is what every production publish from the Creator does. The standalone one inlines them, for a
|
|
13
|
+
* game that has to run with no network at all.
|
|
14
|
+
*/
|
|
9
15
|
export const VITE_PUBLISH_CONFIG = 'vite.publish.config.js';
|
|
16
|
+
export const VITE_PUBLISH_STANDALONE_CONFIG = 'vite.publish-standalone.config.js';
|
|
17
|
+
/** The vendored config a build of this mode loads. */
|
|
18
|
+
export function publishConfigFor(singleFile) {
|
|
19
|
+
return singleFile ? VITE_PUBLISH_STANDALONE_CONFIG : VITE_PUBLISH_CONFIG;
|
|
20
|
+
}
|
|
10
21
|
export function buildBundlePaths(root) {
|
|
11
22
|
const dir = path.join(root, '.bitmagic', 'build');
|
|
12
23
|
return { dir, htmlPath: path.join(dir, 'index.html'), manifestPath: path.join(dir, 'manifest.json') };
|
|
@@ -20,6 +31,11 @@ function isManifest(value) {
|
|
|
20
31
|
if (typeof value !== 'object' || value === null)
|
|
21
32
|
return false;
|
|
22
33
|
const m = value;
|
|
34
|
+
// `singleFile` is deliberately NOT required. A manifest written before the flag existed has no
|
|
35
|
+
// such field, and rejecting those outright would force a rebuild on every project's first
|
|
36
|
+
// publish after upgrading. The reader below defaults it to `false`, which is the safe direction:
|
|
37
|
+
// the config now on disk is the external one, so at worst this costs one rebuild — it can never
|
|
38
|
+
// reuse a bundle built in the other mode, because there was no other mode.
|
|
23
39
|
return (typeof m.engineVersion === 'string'
|
|
24
40
|
&& typeof m.fingerprint === 'string'
|
|
25
41
|
&& typeof m.bytes === 'number'
|
|
@@ -30,27 +46,38 @@ function isManifest(value) {
|
|
|
30
46
|
export function readBuildManifest(root) {
|
|
31
47
|
try {
|
|
32
48
|
const parsed = JSON.parse(fs.readFileSync(buildBundlePaths(root).manifestPath, 'utf-8'));
|
|
33
|
-
|
|
49
|
+
if (!isManifest(parsed))
|
|
50
|
+
return null;
|
|
51
|
+
return { ...parsed, singleFile: parsed.singleFile === true };
|
|
34
52
|
}
|
|
35
53
|
catch {
|
|
36
54
|
return null;
|
|
37
55
|
}
|
|
38
56
|
}
|
|
39
57
|
/**
|
|
40
|
-
* Compile and bundle the project into one
|
|
58
|
+
* Compile and bundle the project into one HTML file, and record what was built.
|
|
59
|
+
*
|
|
60
|
+
* One file either way — `bitmagic publish` PUTs a single object and api-server range-reads that
|
|
61
|
+
* same object to confirm the meta block, so there is nowhere for a second file to go. What the
|
|
62
|
+
* mode changes is what is INSIDE it: by default the engine, the game and its data are inlined
|
|
63
|
+
* while three.js, Rapier and the other CDN packages are fetched at runtime, matching what the
|
|
64
|
+
* Creator publishes; `singleFile` inlines those too, for a game that must run with no network.
|
|
41
65
|
*
|
|
42
66
|
* Exit code 1 on failure, matching the table in the spec: a build failure is the creator's own
|
|
43
67
|
* code, and the compiler's output has already been printed.
|
|
44
68
|
*
|
|
45
|
-
* The pre-flight below runs BEFORE `tsc`, not after: a project scaffolded before
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
*
|
|
69
|
+
* The pre-flight below runs BEFORE `tsc`, not after: a project scaffolded before the config it
|
|
70
|
+
* needs existed has none for vite to load, and without this check the creator pays a full
|
|
71
|
+
* type-check and then reads a raw vite "config not found" that names no remedy. `bitmagic upgrade`
|
|
72
|
+
* is the remedy — it vendors the file without touching game code — so the error says so. It names
|
|
73
|
+
* the config for the mode actually asked for, since a project can easily have one and not the
|
|
74
|
+
* other: the standalone config was added later than the default one.
|
|
50
75
|
*/
|
|
51
|
-
export function runBuild(root, engineVersion) {
|
|
52
|
-
|
|
53
|
-
|
|
76
|
+
export function runBuild(root, engineVersion, options = {}) {
|
|
77
|
+
const singleFile = options.singleFile === true;
|
|
78
|
+
const configFile = publishConfigFor(singleFile);
|
|
79
|
+
if (!fs.existsSync(path.join(root, configFile))) {
|
|
80
|
+
throw new CliError(`This project has no ${configFile}, which \`bitmagic build\` needs to bundle it. ` +
|
|
54
81
|
'It was added to the scaffold after this project was created — run `bitmagic upgrade` to ' +
|
|
55
82
|
'vendor it (your game code is not touched), then build again.', 1);
|
|
56
83
|
}
|
|
@@ -63,7 +90,7 @@ export function runBuild(root, engineVersion) {
|
|
|
63
90
|
const { dir, htmlPath } = buildBundlePaths(root);
|
|
64
91
|
fs.mkdirSync(dir, { recursive: true });
|
|
65
92
|
const vite = projectBin(root, 'vite');
|
|
66
|
-
const bundle = spawnSync(vite, ['build', '--config',
|
|
93
|
+
const bundle = spawnSync(vite, ['build', '--config', configFile, '--outDir', dir, '--emptyOutDir'], {
|
|
67
94
|
cwd: root,
|
|
68
95
|
stdio: 'inherit',
|
|
69
96
|
});
|
|
@@ -72,12 +99,13 @@ export function runBuild(root, engineVersion) {
|
|
|
72
99
|
if (bundle.status !== 0)
|
|
73
100
|
throw new CliError('Build failed: the bundle did not complete.', 1);
|
|
74
101
|
if (!fs.existsSync(htmlPath)) {
|
|
75
|
-
throw new CliError(`Build produced no ${path.relative(root, htmlPath)}. Check ${
|
|
102
|
+
throw new CliError(`Build produced no ${path.relative(root, htmlPath)}. Check ${configFile}.`, 1);
|
|
76
103
|
}
|
|
77
104
|
const contents = fs.readFileSync(htmlPath);
|
|
78
105
|
const manifest = {
|
|
79
106
|
engineVersion,
|
|
80
107
|
fingerprint: computeFingerprint(root),
|
|
108
|
+
singleFile,
|
|
81
109
|
bytes: contents.byteLength,
|
|
82
110
|
sha256: createHash('sha256').update(contents).digest('hex'),
|
|
83
111
|
builtAt: new Date().toISOString(),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bundle.js","sourceRoot":"","sources":["../../src/publish/bundle.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AACpC,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAC1C,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AACzB,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAC7B,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AACxC,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AACnD,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAEtD
|
|
1
|
+
{"version":3,"file":"bundle.js","sourceRoot":"","sources":["../../src/publish/bundle.ts"],"names":[],"mappings":"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"}
|
package/dist/publish/client.d.ts
CHANGED
|
@@ -14,7 +14,9 @@ export declare function publishExitCode(status: number, body: {
|
|
|
14
14
|
}): number;
|
|
15
15
|
export interface BeginPublishRequest {
|
|
16
16
|
gameId: string;
|
|
17
|
-
|
|
17
|
+
/** Omitted entirely to keep the game's stored visibility — see commands/publish.ts's
|
|
18
|
+
* resolveVisibility. Sending 'private' and omitting the field are DIFFERENT messages. */
|
|
19
|
+
visibility?: 'public' | 'private';
|
|
18
20
|
name?: string;
|
|
19
21
|
description?: string;
|
|
20
22
|
engineVersion: string;
|
|
@@ -77,7 +79,9 @@ export interface CompletePublishRequest {
|
|
|
77
79
|
gameId: string;
|
|
78
80
|
key: string;
|
|
79
81
|
publishVersion: number;
|
|
80
|
-
visibility
|
|
82
|
+
/** Omitted in exactly the same case as `BeginPublishRequest.visibility`, and for the same
|
|
83
|
+
* reason — the pair must agree, since `complete` re-authorizes from its own body. */
|
|
84
|
+
visibility?: 'public' | 'private';
|
|
81
85
|
name?: string;
|
|
82
86
|
description?: string;
|
|
83
87
|
thumbnailUrl: string;
|
|
@@ -141,7 +145,14 @@ export interface SourceCheckResult {
|
|
|
141
145
|
export interface CompletePublishResponse {
|
|
142
146
|
url: string;
|
|
143
147
|
publishVersion: number;
|
|
148
|
+
/** The EFFECTIVE visibility the publish landed on — set even when the request omitted it. */
|
|
144
149
|
visibility: 'public' | 'private';
|
|
150
|
+
/**
|
|
151
|
+
* Where the creator manages this game on the portal: visibility, and withdrawing it. Comes
|
|
152
|
+
* from the server (`PORTAL_URL` is its to know — see subscribe-flow.ts's `subscribeUrl`), and
|
|
153
|
+
* is absent from an older server, in which case the CLI simply prints no line for it.
|
|
154
|
+
*/
|
|
155
|
+
manageUrl?: string;
|
|
145
156
|
/** Absent from an older server; the CLI then prints nothing. */
|
|
146
157
|
sourceChecks?: SourceCheckResult;
|
|
147
158
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/publish/client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAExC,OAAO,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAC;AACnE,OAAO,EAAE,YAAY,IAAI,kBAAkB,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAW/F;;;GAGG;AACH,MAAM,wBAAwB,GAAG,CAAC,CAAC;AAEnC,SAAS,YAAY,CACnB,GAAW,EACX,IAAyB,EACzB,OAA+B,EAC/B,IAAa;IAEb,OAAO,kBAAkB,CAAC,GAAG,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,QAAQ,EAAE,wBAAwB,EAAE,CAAC,CAAC;AAC9F,CAAC;AAED,SAAS,QAAQ,CAAC,KAAc;IAC9B,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;AAC9E,CAAC;AAED,SAAS,WAAW,CAAC,KAAc;IACjC,OAAO,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC;AACvD,CAAC;AAED,KAAK,UAAU,YAAY,CAAC,QAAuB;IACjD,IAAI,CAAC;QACH,MAAM,MAAM,GAAY,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;QAC9C,OAAO,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC;IACxC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,eAAe,CAAC,MAAc,EAAE,IAAuB;IACrE,IAAI,MAAM,KAAK,GAAG;QAAE,OAAO,CAAC,CAAC;IAC7B,IAAI,MAAM,KAAK,GAAG;QAAE,OAAO,CAAC,CAAC;IAC7B,IAAI,MAAM,KAAK,GAAG,IAAI,IAAI,CAAC,IAAI,KAAK,oBAAoB;QAAE,OAAO,CAAC,CAAC;IACnE,6FAA6F;IAC7F,gGAAgG;IAChG,+FAA+F;IAC/F,6FAA6F;IAC7F,IAAI,MAAM,KAAK,GAAG,IAAI,IAAI,CAAC,IAAI,KAAK,qBAAqB;QAAE,OAAO,CAAC,CAAC;IACpE,OAAO,CAAC,CAAC;AACX,CAAC;AAED;;;;GAIG;AACH,KAAK,UAAU,QAAQ,CACrB,GAAW,EACX,WAAmB,EACnB,IAAa,EACb,IAAa;IAEb,IAAI,QAAuB,CAAC;IAC5B,IAAI,CAAC;QACH,QAAQ,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,GAAG,EAAE;YAC/B,MAAM,EAAE,MAAM;YACd,OAAO,EAAE;gBACP,GAAG,gBAAgB,EAAE;gBACrB,aAAa,EAAE,UAAU,WAAW,EAAE;gBACtC,MAAM,EAAE,kBAAkB;gBAC1B,cAAc,EAAE,kBAAkB;aACnC;YACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC;SAC3B,CAAC,CAAC;IACL,CAAC;IAAC,MAAM,CAAC;QACP,gFAAgF;QAChF,MAAM,IAAI,QAAQ,CAAC,8BAA8B,GAAG,GAAG,EAAE,CAAC,EAAE,aAAa,CAAC,CAAC;IAC7E,CAAC;IAED,4FAA4F;IAC5F,+FAA+F;IAC/F,4FAA4F;IAC5F,8FAA8F;IAC9F,6FAA6F;IAC7F,iCAAiC;IACjC,IAAI,QAAQ,CAAC,EAAE,EAAE,CAAC;QAChB,IAAI,MAAe,CAAC;QACpB,IAAI,CAAC;YACH,MAAM,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;QACjC,CAAC;QAAC,MAAM,CAAC;YACP,MAAM,IAAI,QAAQ,CAChB,yBAAyB,QAAQ,CAAC,MAAM,SAAS,GAAG,sCAAsC,EAC1F,CAAC,CACF,CAAC;QACJ,CAAC;QACD,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;YACtB,MAAM,IAAI,QAAQ,CAAC,yDAAyD,GAAG,GAAG,EAAE,CAAC,CAAC,CAAC;QACzF,CAAC;QACD,OAAO,MAAW,CAAC;IACrB,CAAC;IAED,yFAAyF;IACzF,iFAAiF;IACjF,MAAM,WAAW,GAAG,MAAM,YAAY,CAAC,QAAQ,CAAC,CAAC;IACjD,MAAM,IAAI,GAAG,WAAW,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC;IAC3C,MAAM,OAAO,GAAG,WAAW,CAAC,WAAW,CAAC,KAAK,CAAC,IAAI,4BAA4B,QAAQ,CAAC,MAAM,QAAQ,GAAG,GAAG,CAAC;IAC5G,MAAM,IAAI,QAAQ,CAAC,OAAO,EAAE,eAAe,CAAC,QAAQ,CAAC,MAAM,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;AAC1E,CAAC;
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/publish/client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export declare function publishRecordPath(root: string): string;
|
|
2
|
+
export interface PublishRecord {
|
|
3
|
+
/** The public URL of the game, exactly as api-server issued it. */
|
|
4
|
+
url: string;
|
|
5
|
+
visibility: string;
|
|
6
|
+
publishVersion: number;
|
|
7
|
+
gameId: string;
|
|
8
|
+
/** ISO 8601, so a reader can say how long ago without a second field. */
|
|
9
|
+
at: string;
|
|
10
|
+
/** The My games page. Absent against an older api-server that does not send one. */
|
|
11
|
+
manageUrl?: string;
|
|
12
|
+
/** The name this publish shipped under, when the publish knew it. */
|
|
13
|
+
name?: string;
|
|
14
|
+
}
|
|
15
|
+
export declare function writePublishRecord(root: string, record: PublishRecord): void;
|
|
16
|
+
/**
|
|
17
|
+
* The last publish, or null when there has not been one this reader can trust.
|
|
18
|
+
*
|
|
19
|
+
* Every field is checked rather than assumed: this file survives across CLI versions, and a reader
|
|
20
|
+
* that trusted a half-written or older-shaped record would put a broken link in front of a creator.
|
|
21
|
+
*/
|
|
22
|
+
export declare function readPublishRecord(root: string): PublishRecord | null;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The on-disk record of the last successful `bitmagic publish`.
|
|
3
|
+
*
|
|
4
|
+
* Publishing used to print the game's URL and forget it. That was fine while the terminal was the
|
|
5
|
+
* only place the URL was ever wanted, and stopped being fine as soon as anything else needed to
|
|
6
|
+
* answer "where is this game?" — the `bitmagic dev` view being the first, since it is the window
|
|
7
|
+
* the creator already has open while they work.
|
|
8
|
+
*
|
|
9
|
+
* Lives at `.bitmagic/publish/last.json`, beside `source.zip`, which is where the rest of a
|
|
10
|
+
* publish's local artifacts already are. Inside `.bitmagic` means gitignored and excluded from the
|
|
11
|
+
* publish fingerprint (`EXCLUDED_DIRS` in `@bitmagic/asset-core/publish-source`), so recording a
|
|
12
|
+
* publish cannot invalidate the verify that gated it — the same reason the QR image lives there.
|
|
13
|
+
*
|
|
14
|
+
* Written only after `complete`, so its presence means the game really is live at that URL. It is
|
|
15
|
+
* NOT a cache and nothing gates on it: a missing or unreadable record costs a link in a panel, and
|
|
16
|
+
* every reader here treats that as normal rather than as an error.
|
|
17
|
+
*/
|
|
18
|
+
import * as fs from 'fs';
|
|
19
|
+
import * as path from 'path';
|
|
20
|
+
const PUBLISH_RECORD_FILE = path.join('.bitmagic', 'publish', 'last.json');
|
|
21
|
+
export function publishRecordPath(root) {
|
|
22
|
+
return path.join(root, PUBLISH_RECORD_FILE);
|
|
23
|
+
}
|
|
24
|
+
export function writePublishRecord(root, record) {
|
|
25
|
+
fs.mkdirSync(path.dirname(publishRecordPath(root)), { recursive: true });
|
|
26
|
+
fs.writeFileSync(publishRecordPath(root), `${JSON.stringify(record, null, 2)}\n`);
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* The last publish, or null when there has not been one this reader can trust.
|
|
30
|
+
*
|
|
31
|
+
* Every field is checked rather than assumed: this file survives across CLI versions, and a reader
|
|
32
|
+
* that trusted a half-written or older-shaped record would put a broken link in front of a creator.
|
|
33
|
+
*/
|
|
34
|
+
export function readPublishRecord(root) {
|
|
35
|
+
let parsed;
|
|
36
|
+
try {
|
|
37
|
+
parsed = JSON.parse(fs.readFileSync(publishRecordPath(root), 'utf-8'));
|
|
38
|
+
}
|
|
39
|
+
catch {
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
if (typeof parsed !== 'object' || parsed === null)
|
|
43
|
+
return null;
|
|
44
|
+
const record = parsed;
|
|
45
|
+
if (typeof record.url !== 'string'
|
|
46
|
+
|| typeof record.visibility !== 'string'
|
|
47
|
+
|| typeof record.publishVersion !== 'number'
|
|
48
|
+
|| typeof record.gameId !== 'string'
|
|
49
|
+
|| typeof record.at !== 'string') {
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
52
|
+
return {
|
|
53
|
+
url: record.url,
|
|
54
|
+
visibility: record.visibility,
|
|
55
|
+
publishVersion: record.publishVersion,
|
|
56
|
+
gameId: record.gameId,
|
|
57
|
+
at: record.at,
|
|
58
|
+
...(typeof record.manageUrl === 'string' ? { manageUrl: record.manageUrl } : {}),
|
|
59
|
+
...(typeof record.name === 'string' ? { name: record.name } : {}),
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=record.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"record.js","sourceRoot":"","sources":["../../src/publish/record.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AACH,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AACzB,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAE7B,MAAM,mBAAmB,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,SAAS,EAAE,WAAW,CAAC,CAAC;AAE3E,MAAM,UAAU,iBAAiB,CAAC,IAAY;IAC5C,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,mBAAmB,CAAC,CAAC;AAC9C,CAAC;AAgBD,MAAM,UAAU,kBAAkB,CAAC,IAAY,EAAE,MAAqB;IACpE,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,iBAAiB,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACzE,EAAE,CAAC,aAAa,CAAC,iBAAiB,CAAC,IAAI,CAAC,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC;AACpF,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,iBAAiB,CAAC,IAAY;IAC5C,IAAI,MAAe,CAAC;IACpB,IAAI,CAAC;QACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,CAAC,iBAAiB,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC;IACzE,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;IACD,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IAC/D,MAAM,MAAM,GAAG,MAAiC,CAAC;IACjD,IACE,OAAO,MAAM,CAAC,GAAG,KAAK,QAAQ;WAC3B,OAAO,MAAM,CAAC,UAAU,KAAK,QAAQ;WACrC,OAAO,MAAM,CAAC,cAAc,KAAK,QAAQ;WACzC,OAAO,MAAM,CAAC,MAAM,KAAK,QAAQ;WACjC,OAAO,MAAM,CAAC,EAAE,KAAK,QAAQ,EAChC,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IACD,OAAO;QACL,GAAG,EAAE,MAAM,CAAC,GAAG;QACf,UAAU,EAAE,MAAM,CAAC,UAAU;QAC7B,cAAc,EAAE,MAAM,CAAC,cAAc;QACrC,MAAM,EAAE,MAAM,CAAC,MAAM;QACrB,EAAE,EAAE,MAAM,CAAC,EAAE;QACb,GAAG,CAAC,OAAO,MAAM,CAAC,SAAS,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,MAAM,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAChF,GAAG,CAAC,OAAO,MAAM,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAClE,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Where a publish's QR code goes: the terminal when someone is looking at it, a file when nobody
|
|
3
|
+
* is.
|
|
4
|
+
*
|
|
5
|
+
* This module exists because the two are one decision, not two. `qr-terminal.ts` refuses a
|
|
6
|
+
* non-TTY for a good reason — escape sequences in a captured stream are noise — but refusing to
|
|
7
|
+
* DRAW is not the same as having nothing to offer, and for this CLI the captured stream is the
|
|
8
|
+
* common case. The pro lane is driven by an agent, so stdout is a pipe on almost every real
|
|
9
|
+
* publish, and the creator who would scan the code never sees the terminal at all. Gating the
|
|
10
|
+
* feature on `isTTY` alone turned it off exactly where the URL is most worth handing over.
|
|
11
|
+
*
|
|
12
|
+
* So: draw it if it can be drawn, and write `.bitmagic/publish-qr.png` whenever it cannot. That
|
|
13
|
+
* covers the pipe, and also the two smaller cases with the same shape — `TERM=dumb`, and a
|
|
14
|
+
* terminal too narrow to hold the code unwrapped — where a person is present but still has nothing
|
|
15
|
+
* to scan. A terminal that draws successfully writes no file: it already did the job.
|
|
16
|
+
*
|
|
17
|
+
* `.bitmagic/` is excluded from the publish fingerprint (`EXCLUDED_DIRS` in
|
|
18
|
+
* `@bitmagic/asset-core/publish-source`), so writing here cannot invalidate the verify the gate
|
|
19
|
+
* just checked.
|
|
20
|
+
*/
|
|
21
|
+
import { type TerminalQrEnv } from './qr-terminal.js';
|
|
22
|
+
/** Where a publish leaves its QR image. One per project, overwritten each publish. */
|
|
23
|
+
export declare function publishQrPath(root: string): string;
|
|
24
|
+
export interface EmitQrOptions {
|
|
25
|
+
/** The project root. The image lands in its `.bitmagic/`. */
|
|
26
|
+
root: string;
|
|
27
|
+
/** `--json`: stdout carries exactly one document, so nothing is ever drawn. */
|
|
28
|
+
json: boolean;
|
|
29
|
+
/** `--no-qr`. Suppresses the drawing AND the file — it means "not this time", not "not here". */
|
|
30
|
+
disabled: boolean;
|
|
31
|
+
env?: TerminalQrEnv;
|
|
32
|
+
isTTY?: boolean;
|
|
33
|
+
columns?: number | undefined;
|
|
34
|
+
write?: (chunk: string) => void;
|
|
35
|
+
/** Seam for the test; production writes to disk. */
|
|
36
|
+
writeFile?: (file: string, bytes: Buffer) => void;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Show `url` as a QR code however this run can, and return the image path when one was written.
|
|
40
|
+
*
|
|
41
|
+
* Never throws and never reports failure as an error: the caller has already printed the URL, and
|
|
42
|
+
* a code that could not be produced costs the creator a retype, not a publish.
|
|
43
|
+
*/
|
|
44
|
+
export declare function emitQr(url: string, options: EmitQrOptions): string | null;
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Where a publish's QR code goes: the terminal when someone is looking at it, a file when nobody
|
|
3
|
+
* is.
|
|
4
|
+
*
|
|
5
|
+
* This module exists because the two are one decision, not two. `qr-terminal.ts` refuses a
|
|
6
|
+
* non-TTY for a good reason — escape sequences in a captured stream are noise — but refusing to
|
|
7
|
+
* DRAW is not the same as having nothing to offer, and for this CLI the captured stream is the
|
|
8
|
+
* common case. The pro lane is driven by an agent, so stdout is a pipe on almost every real
|
|
9
|
+
* publish, and the creator who would scan the code never sees the terminal at all. Gating the
|
|
10
|
+
* feature on `isTTY` alone turned it off exactly where the URL is most worth handing over.
|
|
11
|
+
*
|
|
12
|
+
* So: draw it if it can be drawn, and write `.bitmagic/publish-qr.png` whenever it cannot. That
|
|
13
|
+
* covers the pipe, and also the two smaller cases with the same shape — `TERM=dumb`, and a
|
|
14
|
+
* terminal too narrow to hold the code unwrapped — where a person is present but still has nothing
|
|
15
|
+
* to scan. A terminal that draws successfully writes no file: it already did the job.
|
|
16
|
+
*
|
|
17
|
+
* `.bitmagic/` is excluded from the publish fingerprint (`EXCLUDED_DIRS` in
|
|
18
|
+
* `@bitmagic/asset-core/publish-source`), so writing here cannot invalidate the verify the gate
|
|
19
|
+
* just checked.
|
|
20
|
+
*/
|
|
21
|
+
import * as fs from 'fs';
|
|
22
|
+
import * as path from 'path';
|
|
23
|
+
import { encodeQr } from './qr.js';
|
|
24
|
+
import { encodeQrPng } from './qr-png.js';
|
|
25
|
+
import { renderTerminalQr } from './qr-terminal.js';
|
|
26
|
+
/** Where a publish leaves its QR image. One per project, overwritten each publish. */
|
|
27
|
+
export function publishQrPath(root) {
|
|
28
|
+
return path.join(root, '.bitmagic', 'publish-qr.png');
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Show `url` as a QR code however this run can, and return the image path when one was written.
|
|
32
|
+
*
|
|
33
|
+
* Never throws and never reports failure as an error: the caller has already printed the URL, and
|
|
34
|
+
* a code that could not be produced costs the creator a retype, not a publish.
|
|
35
|
+
*/
|
|
36
|
+
export function emitQr(url, options) {
|
|
37
|
+
const env = options.env ?? process.env;
|
|
38
|
+
if (options.disabled || env.BITMAGIC_NO_QR)
|
|
39
|
+
return null;
|
|
40
|
+
// Drawing is tried first and, when it works, is the whole answer — a file nobody opens is
|
|
41
|
+
// clutter in a directory the creator does read.
|
|
42
|
+
if (!options.json) {
|
|
43
|
+
const drawn = renderTerminalQr(url, {
|
|
44
|
+
env,
|
|
45
|
+
...(options.isTTY === undefined ? {} : { isTTY: options.isTTY }),
|
|
46
|
+
columns: options.columns,
|
|
47
|
+
...(options.write === undefined ? {} : { write: options.write }),
|
|
48
|
+
});
|
|
49
|
+
if (drawn)
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
52
|
+
const matrix = encodeQr(url);
|
|
53
|
+
if (matrix === null)
|
|
54
|
+
return null;
|
|
55
|
+
const file = publishQrPath(options.root);
|
|
56
|
+
try {
|
|
57
|
+
if (options.writeFile) {
|
|
58
|
+
options.writeFile(file, encodeQrPng(matrix));
|
|
59
|
+
}
|
|
60
|
+
else {
|
|
61
|
+
fs.mkdirSync(path.dirname(file), { recursive: true });
|
|
62
|
+
fs.writeFileSync(file, encodeQrPng(matrix));
|
|
63
|
+
}
|
|
64
|
+
return file;
|
|
65
|
+
}
|
|
66
|
+
catch {
|
|
67
|
+
// A read-only or full disk is not worth failing a successful publish over.
|
|
68
|
+
return null;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
//# sourceMappingURL=qr-output.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"qr-output.js","sourceRoot":"","sources":["../../src/render/qr-output.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AACzB,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAC7B,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACnC,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,gBAAgB,EAAsB,MAAM,kBAAkB,CAAC;AAExE,sFAAsF;AACtF,MAAM,UAAU,aAAa,CAAC,IAAY;IACxC,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,WAAW,EAAE,gBAAgB,CAAC,CAAC;AACxD,CAAC;AAiBD;;;;;GAKG;AACH,MAAM,UAAU,MAAM,CAAC,GAAW,EAAE,OAAsB;IACxD,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,CAAC;IACvC,IAAI,OAAO,CAAC,QAAQ,IAAI,GAAG,CAAC,cAAc;QAAE,OAAO,IAAI,CAAC;IAExD,0FAA0F;IAC1F,gDAAgD;IAChD,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;QAClB,MAAM,KAAK,GAAG,gBAAgB,CAAC,GAAG,EAAE;YAClC,GAAG;YACH,GAAG,CAAC,OAAO,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,CAAC;YAChE,OAAO,EAAE,OAAO,CAAC,OAAO;YACxB,GAAG,CAAC,OAAO,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,CAAC;SACjE,CAAC,CAAC;QACH,IAAI,KAAK;YAAE,OAAO,IAAI,CAAC;IACzB,CAAC;IAED,MAAM,MAAM,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC;IAC7B,IAAI,MAAM,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IAEjC,MAAM,IAAI,GAAG,aAAa,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IACzC,IAAI,CAAC;QACH,IAAI,OAAO,CAAC,SAAS,EAAE,CAAC;YACtB,OAAO,CAAC,SAAS,CAAC,IAAI,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC;QAC/C,CAAC;aAAM,CAAC;YACN,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;YACtD,EAAE,CAAC,aAAa,CAAC,IAAI,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC;QAC9C,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,2EAA2E;QAC3E,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A QR code as PNG bytes, for the creator who cannot scan the terminal.
|
|
3
|
+
*
|
|
4
|
+
* `qr-terminal.ts` covers the case where a person is looking at the output. That is not the common
|
|
5
|
+
* case for this CLI: the pro lane is driven by an agent, so stdout is a pipe, and the human who
|
|
6
|
+
* would do the scanning is on the far side of it. A file crosses that boundary where escape
|
|
7
|
+
* sequences cannot — an agent can hand an image to its creator, and cannot hand them a repainted
|
|
8
|
+
* terminal.
|
|
9
|
+
*
|
|
10
|
+
* Greyscale, one byte per pixel. A QR carries one bit per module, so colour would be three bytes of
|
|
11
|
+
* nothing; and at this size the whole image deflates to a few hundred bytes either way. The
|
|
12
|
+
* encoder is hand-rolled for the same reason `qr.ts` is — `@bitmagic/cli` ships four runtime
|
|
13
|
+
* dependencies on purpose, and node's own `zlib` (already used in `publish/` and `assets/`) does
|
|
14
|
+
* the only part that is genuinely hard.
|
|
15
|
+
*
|
|
16
|
+
* Two other hand-rolled PNG encoders exist in this repo — `world-forger-internal`'s vehicle atlas
|
|
17
|
+
* and `game-play-agent`'s solid-colour tile — and neither is reachable from here: the first is in a
|
|
18
|
+
* `private: true` package the CLI does not depend on, the second is server code. A shared home
|
|
19
|
+
* would have to be `@bitmagic/asset-core`; that is worth doing when something needs the third copy,
|
|
20
|
+
* not for the second.
|
|
21
|
+
*/
|
|
22
|
+
import { Buffer } from 'buffer';
|
|
23
|
+
export interface QrPngOptions {
|
|
24
|
+
/** Pixels per module. Defaults to `MODULE_PIXELS`. */
|
|
25
|
+
scale?: number;
|
|
26
|
+
/** Quiet zone in modules. Defaults to `QUIET_MODULES`. */
|
|
27
|
+
quietZone?: number;
|
|
28
|
+
}
|
|
29
|
+
/** The pixel width (and height) `encodeQrPng` produces for a matrix of this size. */
|
|
30
|
+
export declare function qrPngDimension(matrix: boolean[][], options?: QrPngOptions): number;
|
|
31
|
+
/**
|
|
32
|
+
* Encode a module matrix as a greyscale PNG: dark modules black, everything else white.
|
|
33
|
+
*
|
|
34
|
+
* White is 0xff and dark is 0x00, never inverted — a scanner wants dark on light, and unlike the
|
|
35
|
+
* terminal there is no theme here to fight about it.
|
|
36
|
+
*/
|
|
37
|
+
export declare function encodeQrPng(matrix: boolean[][], options?: QrPngOptions): Buffer;
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A QR code as PNG bytes, for the creator who cannot scan the terminal.
|
|
3
|
+
*
|
|
4
|
+
* `qr-terminal.ts` covers the case where a person is looking at the output. That is not the common
|
|
5
|
+
* case for this CLI: the pro lane is driven by an agent, so stdout is a pipe, and the human who
|
|
6
|
+
* would do the scanning is on the far side of it. A file crosses that boundary where escape
|
|
7
|
+
* sequences cannot — an agent can hand an image to its creator, and cannot hand them a repainted
|
|
8
|
+
* terminal.
|
|
9
|
+
*
|
|
10
|
+
* Greyscale, one byte per pixel. A QR carries one bit per module, so colour would be three bytes of
|
|
11
|
+
* nothing; and at this size the whole image deflates to a few hundred bytes either way. The
|
|
12
|
+
* encoder is hand-rolled for the same reason `qr.ts` is — `@bitmagic/cli` ships four runtime
|
|
13
|
+
* dependencies on purpose, and node's own `zlib` (already used in `publish/` and `assets/`) does
|
|
14
|
+
* the only part that is genuinely hard.
|
|
15
|
+
*
|
|
16
|
+
* Two other hand-rolled PNG encoders exist in this repo — `world-forger-internal`'s vehicle atlas
|
|
17
|
+
* and `game-play-agent`'s solid-colour tile — and neither is reachable from here: the first is in a
|
|
18
|
+
* `private: true` package the CLI does not depend on, the second is server code. A shared home
|
|
19
|
+
* would have to be `@bitmagic/asset-core`; that is worth doing when something needs the third copy,
|
|
20
|
+
* not for the second.
|
|
21
|
+
*/
|
|
22
|
+
import { Buffer } from 'buffer';
|
|
23
|
+
import * as zlib from 'zlib';
|
|
24
|
+
/** Pixels per QR module. Large enough that a phone camera reads it off a normal screen. */
|
|
25
|
+
const MODULE_PIXELS = 8;
|
|
26
|
+
/**
|
|
27
|
+
* Quiet zone in modules. Four, the value the spec asks for, rather than the two `qr-terminal.ts`
|
|
28
|
+
* uses — that one is trading margin for terminal columns, and a file has no such constraint.
|
|
29
|
+
*/
|
|
30
|
+
const QUIET_MODULES = 4;
|
|
31
|
+
const PNG_SIGNATURE = Buffer.from([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a]);
|
|
32
|
+
/** The standard CRC-32 table (PNG spec annex D), built once. */
|
|
33
|
+
function buildCrcTable() {
|
|
34
|
+
const table = new Uint32Array(256);
|
|
35
|
+
for (let n = 0; n < 256; n += 1) {
|
|
36
|
+
let c = n;
|
|
37
|
+
for (let k = 0; k < 8; k += 1) {
|
|
38
|
+
c = (c & 1) !== 0 ? 0xedb88320 ^ (c >>> 1) : c >>> 1;
|
|
39
|
+
}
|
|
40
|
+
table[n] = c >>> 0;
|
|
41
|
+
}
|
|
42
|
+
return table;
|
|
43
|
+
}
|
|
44
|
+
const CRC_TABLE = buildCrcTable();
|
|
45
|
+
function crc32(bytes) {
|
|
46
|
+
let crc = 0xffffffff;
|
|
47
|
+
for (const byte of bytes) {
|
|
48
|
+
crc = CRC_TABLE[(crc ^ byte) & 0xff] ^ (crc >>> 8);
|
|
49
|
+
}
|
|
50
|
+
return (crc ^ 0xffffffff) >>> 0;
|
|
51
|
+
}
|
|
52
|
+
/** One PNG chunk: length, type, data, and the CRC over type+data (never over the length). */
|
|
53
|
+
function chunk(type, data) {
|
|
54
|
+
const length = Buffer.alloc(4);
|
|
55
|
+
length.writeUInt32BE(data.length, 0);
|
|
56
|
+
const typeAndData = Buffer.concat([Buffer.from(type, 'ascii'), data]);
|
|
57
|
+
const crc = Buffer.alloc(4);
|
|
58
|
+
crc.writeUInt32BE(crc32(typeAndData), 0);
|
|
59
|
+
return Buffer.concat([length, typeAndData, crc]);
|
|
60
|
+
}
|
|
61
|
+
/** The pixel width (and height) `encodeQrPng` produces for a matrix of this size. */
|
|
62
|
+
export function qrPngDimension(matrix, options = {}) {
|
|
63
|
+
const scale = options.scale ?? MODULE_PIXELS;
|
|
64
|
+
const quiet = options.quietZone ?? QUIET_MODULES;
|
|
65
|
+
return (matrix.length + quiet * 2) * scale;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Encode a module matrix as a greyscale PNG: dark modules black, everything else white.
|
|
69
|
+
*
|
|
70
|
+
* White is 0xff and dark is 0x00, never inverted — a scanner wants dark on light, and unlike the
|
|
71
|
+
* terminal there is no theme here to fight about it.
|
|
72
|
+
*/
|
|
73
|
+
export function encodeQrPng(matrix, options = {}) {
|
|
74
|
+
const scale = options.scale ?? MODULE_PIXELS;
|
|
75
|
+
const quiet = options.quietZone ?? QUIET_MODULES;
|
|
76
|
+
const dimension = qrPngDimension(matrix, options);
|
|
77
|
+
// One filter byte per scanline (0 = None: a QR is flat colour, so the other filters buy nothing
|
|
78
|
+
// that deflate does not already get from the runs), then one byte per pixel.
|
|
79
|
+
const raw = Buffer.alloc(dimension * (dimension + 1), 0xff);
|
|
80
|
+
for (let y = 0; y < dimension; y += 1) {
|
|
81
|
+
const rowStart = y * (dimension + 1);
|
|
82
|
+
raw[rowStart] = 0;
|
|
83
|
+
const moduleRow = Math.floor(y / scale) - quiet;
|
|
84
|
+
if (moduleRow < 0 || moduleRow >= matrix.length)
|
|
85
|
+
continue;
|
|
86
|
+
for (let x = 0; x < dimension; x += 1) {
|
|
87
|
+
const moduleCol = Math.floor(x / scale) - quiet;
|
|
88
|
+
if (moduleCol < 0 || moduleCol >= matrix.length)
|
|
89
|
+
continue;
|
|
90
|
+
if (matrix[moduleRow][moduleCol])
|
|
91
|
+
raw[rowStart + 1 + x] = 0x00;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
const ihdr = Buffer.alloc(13);
|
|
95
|
+
ihdr.writeUInt32BE(dimension, 0);
|
|
96
|
+
ihdr.writeUInt32BE(dimension, 4);
|
|
97
|
+
ihdr[8] = 8; // bit depth
|
|
98
|
+
ihdr[9] = 0; // colour type 0 — greyscale
|
|
99
|
+
ihdr[10] = 0; // compression: deflate, the only value PNG defines
|
|
100
|
+
ihdr[11] = 0; // filter method: adaptive, the only value PNG defines
|
|
101
|
+
ihdr[12] = 0; // interlace: none
|
|
102
|
+
return Buffer.concat([
|
|
103
|
+
PNG_SIGNATURE,
|
|
104
|
+
chunk('IHDR', ihdr),
|
|
105
|
+
// deflateSync, not fflate's — fflate's `deflateSync` emits RAW deflate with no zlib header,
|
|
106
|
+
// and an IDAT must carry the zlib wrapper. (fflate's `zlibSync` would also do.)
|
|
107
|
+
chunk('IDAT', zlib.deflateSync(raw)),
|
|
108
|
+
chunk('IEND', Buffer.alloc(0)),
|
|
109
|
+
]);
|
|
110
|
+
}
|
|
111
|
+
//# sourceMappingURL=qr-png.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"qr-png.js","sourceRoot":"","sources":["../../src/render/qr-png.ts"],"names":[],"mappings":"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"}
|