@capuchoo/cli 0.2.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 +351 -0
- package/bin/dev.cmd +3 -0
- package/bin/dev.js +5 -0
- package/bin/run.cmd +3 -0
- package/bin/run.js +5 -0
- package/dist/base-command.d.ts +15 -0
- package/dist/base-command.d.ts.map +1 -0
- package/dist/base-command.js +61 -0
- package/dist/base-command.js.map +1 -0
- package/dist/commands/auth/login.d.ts +19 -0
- package/dist/commands/auth/login.d.ts.map +1 -0
- package/dist/commands/auth/login.js +74 -0
- package/dist/commands/auth/login.js.map +1 -0
- package/dist/commands/auth/logout.d.ts +6 -0
- package/dist/commands/auth/logout.d.ts.map +1 -0
- package/dist/commands/auth/logout.js +22 -0
- package/dist/commands/auth/logout.js.map +1 -0
- package/dist/commands/auth/whoami.d.ts +9 -0
- package/dist/commands/auth/whoami.d.ts.map +1 -0
- package/dist/commands/auth/whoami.js +77 -0
- package/dist/commands/auth/whoami.js.map +1 -0
- package/dist/commands/channel/list.d.ts +9 -0
- package/dist/commands/channel/list.d.ts.map +1 -0
- package/dist/commands/channel/list.js +47 -0
- package/dist/commands/channel/list.js.map +1 -0
- package/dist/commands/config/list.d.ts +9 -0
- package/dist/commands/config/list.d.ts.map +1 -0
- package/dist/commands/config/list.js +116 -0
- package/dist/commands/config/list.js.map +1 -0
- package/dist/commands/config/set.d.ts +11 -0
- package/dist/commands/config/set.d.ts.map +1 -0
- package/dist/commands/config/set.js +44 -0
- package/dist/commands/config/set.js.map +1 -0
- package/dist/commands/deploy/native.d.ts +23 -0
- package/dist/commands/deploy/native.d.ts.map +1 -0
- package/dist/commands/deploy/native.js +39 -0
- package/dist/commands/deploy/native.js.map +1 -0
- package/dist/commands/deploy/ota.d.ts +20 -0
- package/dist/commands/deploy/ota.d.ts.map +1 -0
- package/dist/commands/deploy/ota.js +20 -0
- package/dist/commands/deploy/ota.js.map +1 -0
- package/dist/commands/init.d.ts +17 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +232 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/version/bump.d.ts +13 -0
- package/dist/commands/version/bump.d.ts.map +1 -0
- package/dist/commands/version/bump.js +52 -0
- package/dist/commands/version/bump.js.map +1 -0
- package/dist/commands/version/sync.d.ts +12 -0
- package/dist/commands/version/sync.d.ts.map +1 -0
- package/dist/commands/version/sync.js +81 -0
- package/dist/commands/version/sync.js.map +1 -0
- package/dist/deploy/execute.d.ts +48 -0
- package/dist/deploy/execute.d.ts.map +1 -0
- package/dist/deploy/execute.js +280 -0
- package/dist/deploy/execute.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -0
- package/dist/pipeline/android.d.ts +37 -0
- package/dist/pipeline/android.d.ts.map +1 -0
- package/dist/pipeline/android.js +96 -0
- package/dist/pipeline/android.js.map +1 -0
- package/dist/pipeline/build.d.ts +69 -0
- package/dist/pipeline/build.d.ts.map +1 -0
- package/dist/pipeline/build.js +138 -0
- package/dist/pipeline/build.js.map +1 -0
- package/dist/pipeline/deploy.d.ts +74 -0
- package/dist/pipeline/deploy.d.ts.map +1 -0
- package/dist/pipeline/deploy.js +198 -0
- package/dist/pipeline/deploy.js.map +1 -0
- package/dist/pipeline/flavour.d.ts +66 -0
- package/dist/pipeline/flavour.d.ts.map +1 -0
- package/dist/pipeline/flavour.js +120 -0
- package/dist/pipeline/flavour.js.map +1 -0
- package/dist/pipeline/native-config.d.ts +43 -0
- package/dist/pipeline/native-config.d.ts.map +1 -0
- package/dist/pipeline/native-config.js +127 -0
- package/dist/pipeline/native-config.js.map +1 -0
- package/dist/pipeline/toolchain.d.ts +80 -0
- package/dist/pipeline/toolchain.d.ts.map +1 -0
- package/dist/pipeline/toolchain.js +146 -0
- package/dist/pipeline/toolchain.js.map +1 -0
- package/dist/pipeline/zip.d.ts +22 -0
- package/dist/pipeline/zip.d.ts.map +1 -0
- package/dist/pipeline/zip.js +188 -0
- package/dist/pipeline/zip.js.map +1 -0
- package/dist/services/cloud.d.ts +58 -0
- package/dist/services/cloud.d.ts.map +1 -0
- package/dist/services/cloud.js +89 -0
- package/dist/services/cloud.js.map +1 -0
- package/dist/utils/config.d.ts +52 -0
- package/dist/utils/config.d.ts.map +1 -0
- package/dist/utils/config.js +144 -0
- package/dist/utils/config.js.map +1 -0
- package/dist/utils/exec.d.ts +44 -0
- package/dist/utils/exec.d.ts.map +1 -0
- package/dist/utils/exec.js +136 -0
- package/dist/utils/exec.js.map +1 -0
- package/dist/utils/http.d.ts +37 -0
- package/dist/utils/http.d.ts.map +1 -0
- package/dist/utils/http.js +137 -0
- package/dist/utils/http.js.map +1 -0
- package/dist/utils/reporter.d.ts +48 -0
- package/dist/utils/reporter.d.ts.map +1 -0
- package/dist/utils/reporter.js +108 -0
- package/dist/utils/reporter.js.map +1 -0
- package/oclif.manifest.json +568 -0
- package/package.json +81 -0
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { type RunOptions } from "../utils/exec.js";
|
|
2
|
+
import type { ResolvedFlavour } from "./flavour.js";
|
|
3
|
+
/**
|
|
4
|
+
* Applies a flavour's identity and version to the native projects.
|
|
5
|
+
*
|
|
6
|
+
* The old pipeline ran `pnpm trapeze:<env>` and died if that script did not
|
|
7
|
+
* exist or Trapeze was not installed - which is the single most common way a
|
|
8
|
+
* deploy failed on a fresh checkout. Here Trapeze is *preferred* but optional:
|
|
9
|
+
*
|
|
10
|
+
* 1. Trapeze installed and a config exists for the flavour -> run Trapeze, so
|
|
11
|
+
* the app's own YAML stays authoritative (permissions, plist entries, and
|
|
12
|
+
* everything else this file does not model).
|
|
13
|
+
* 2. Otherwise -> apply the identity and version directly. That is the subset
|
|
14
|
+
* every flavour needs, and it is enough for a correct build.
|
|
15
|
+
*
|
|
16
|
+
* Either way the deploy proceeds, and the CLI says which path it took.
|
|
17
|
+
*/
|
|
18
|
+
export type NativeConfigMethod = "trapeze" | "builtin";
|
|
19
|
+
export interface NativeConfigResult {
|
|
20
|
+
method: NativeConfigMethod;
|
|
21
|
+
/** Files the built-in path rewrote. Empty when Trapeze ran. */
|
|
22
|
+
changed: string[];
|
|
23
|
+
/** Why the built-in path was used, when it was. */
|
|
24
|
+
reason?: string;
|
|
25
|
+
}
|
|
26
|
+
export interface NativeConfigInput {
|
|
27
|
+
appDir: string;
|
|
28
|
+
androidDir: string;
|
|
29
|
+
iosDir: string;
|
|
30
|
+
flavour: ResolvedFlavour;
|
|
31
|
+
/** Environment for Trapeze's `vars:` block and for the built-in patcher. */
|
|
32
|
+
env: Record<string, string>;
|
|
33
|
+
platform: "android" | "ios";
|
|
34
|
+
runOptions: Omit<RunOptions, "cwd" | "env">;
|
|
35
|
+
}
|
|
36
|
+
export declare function applyNativeConfig(input: NativeConfigInput): Promise<NativeConfigResult>;
|
|
37
|
+
/**
|
|
38
|
+
* The bundle identifier iOS builds from lives in `project.pbxproj`, which is
|
|
39
|
+
* not safely editable with a regex. Trapeze does it properly, so the built-in
|
|
40
|
+
* path reports the limitation instead of pretending to have handled it.
|
|
41
|
+
*/
|
|
42
|
+
export declare function builtinConfigLimitations(platform: "android" | "ios"): string[];
|
|
43
|
+
//# sourceMappingURL=native-config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"native-config.d.ts","sourceRoot":"","sources":["../../src/pipeline/native-config.ts"],"names":[],"mappings":"AAEA,OAAO,EAAO,KAAK,UAAU,EAAE,MAAM,kBAAkB,CAAC;AACxD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAGpD;;;;;;;;;;;;;;GAcG;AAEH,MAAM,MAAM,kBAAkB,GAAG,SAAS,GAAG,SAAS,CAAC;AAEvD,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,kBAAkB,CAAC;IAC3B,+DAA+D;IAC/D,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,mDAAmD;IACnD,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,eAAe,CAAC;IACzB,4EAA4E;IAC5E,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC5B,QAAQ,EAAE,SAAS,GAAG,KAAK,CAAC;IAC5B,UAAU,EAAE,IAAI,CAAC,UAAU,EAAE,KAAK,GAAG,KAAK,CAAC,CAAC;CAC7C;AAED,wBAAsB,iBAAiB,CAAC,KAAK,EAAE,iBAAiB,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAmB7F;AA+GD;;;;GAIG;AACH,wBAAgB,wBAAwB,CAAC,QAAQ,EAAE,SAAS,GAAG,KAAK,GAAG,MAAM,EAAE,CAK9E"}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { run } from "../utils/exec.js";
|
|
4
|
+
import { resolveBin } from "./toolchain.js";
|
|
5
|
+
export async function applyNativeConfig(input) {
|
|
6
|
+
const trapezeBin = resolveBin("trapeze", input.appDir);
|
|
7
|
+
if (trapezeBin && input.flavour.trapezeConfig) {
|
|
8
|
+
// `-y` accepts the diff Trapeze prints; without it the command waits for
|
|
9
|
+
// input forever in CI.
|
|
10
|
+
await run(trapezeBin, ["run", input.flavour.trapezeConfig, "-y"], {
|
|
11
|
+
...input.runOptions,
|
|
12
|
+
cwd: input.appDir,
|
|
13
|
+
env: input.env,
|
|
14
|
+
});
|
|
15
|
+
return { method: "trapeze", changed: [] };
|
|
16
|
+
}
|
|
17
|
+
const reason = !trapezeBin
|
|
18
|
+
? "@trapezedev/configure is not installed"
|
|
19
|
+
: `no Trapeze config at ${input.flavour.config.trapezeConfig}`;
|
|
20
|
+
return { ...applyBuiltinConfig(input), reason };
|
|
21
|
+
}
|
|
22
|
+
function applyBuiltinConfig(input) {
|
|
23
|
+
const changed = [];
|
|
24
|
+
if (input.platform === "android") {
|
|
25
|
+
changed.push(...patchAndroid(input));
|
|
26
|
+
}
|
|
27
|
+
else {
|
|
28
|
+
changed.push(...patchIos(input));
|
|
29
|
+
}
|
|
30
|
+
return { method: "builtin", changed };
|
|
31
|
+
}
|
|
32
|
+
function readEnv(env, key) {
|
|
33
|
+
const value = env[key];
|
|
34
|
+
return value && value.length > 0 ? value : undefined;
|
|
35
|
+
}
|
|
36
|
+
function patchAndroid(input) {
|
|
37
|
+
const androidRoot = path.resolve(input.appDir, input.androidDir);
|
|
38
|
+
if (!fs.existsSync(androidRoot))
|
|
39
|
+
return [];
|
|
40
|
+
const appId = readEnv(input.env, "VITE_APP_ID");
|
|
41
|
+
const appName = readEnv(input.env, "VITE_APP_NAME");
|
|
42
|
+
const version = readEnv(input.env, "VITE_APP_VERSION");
|
|
43
|
+
const versionCode = readEnv(input.env, "VERSION_CODE");
|
|
44
|
+
const changed = [];
|
|
45
|
+
const gradleFile = path.join(androidRoot, "app", "build.gradle");
|
|
46
|
+
if (fs.existsSync(gradleFile)) {
|
|
47
|
+
let gradle = fs.readFileSync(gradleFile, "utf8");
|
|
48
|
+
const before = gradle;
|
|
49
|
+
if (appId) {
|
|
50
|
+
// Both forms appear in a Capacitor project: `namespace = "..."` and
|
|
51
|
+
// `applicationId "..."`. Quote style varies, so match either.
|
|
52
|
+
gradle = gradle.replace(/(\bnamespace\s*=\s*)["'][^"']*["']/, `$1"${appId}"`);
|
|
53
|
+
gradle = gradle.replace(/(\bapplicationId\s*=?\s*)["'][^"']*["']/, `$1"${appId}"`);
|
|
54
|
+
}
|
|
55
|
+
if (version) {
|
|
56
|
+
gradle = gradle.replace(/(\bversionName\s*=?\s*)["'][^"']*["']/, `$1"${version}"`);
|
|
57
|
+
}
|
|
58
|
+
if (versionCode) {
|
|
59
|
+
gradle = gradle.replace(/(\bversionCode\s*=?\s*)\d+/, `$1${versionCode}`);
|
|
60
|
+
}
|
|
61
|
+
if (gradle !== before) {
|
|
62
|
+
fs.writeFileSync(gradleFile, gradle);
|
|
63
|
+
changed.push(path.relative(input.appDir, gradleFile));
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
const stringsFile = path.join(androidRoot, "app", "src", "main", "res", "values", "strings.xml");
|
|
67
|
+
if (fs.existsSync(stringsFile)) {
|
|
68
|
+
let strings = fs.readFileSync(stringsFile, "utf8");
|
|
69
|
+
const before = strings;
|
|
70
|
+
if (appName) {
|
|
71
|
+
strings = replaceStringResource(strings, "app_name", appName);
|
|
72
|
+
strings = replaceStringResource(strings, "title_activity_main", appName);
|
|
73
|
+
}
|
|
74
|
+
if (appId) {
|
|
75
|
+
strings = replaceStringResource(strings, "package_name", appId);
|
|
76
|
+
strings = replaceStringResource(strings, "custom_url_scheme", appId);
|
|
77
|
+
}
|
|
78
|
+
if (strings !== before) {
|
|
79
|
+
fs.writeFileSync(stringsFile, strings);
|
|
80
|
+
changed.push(path.relative(input.appDir, stringsFile));
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
return changed;
|
|
84
|
+
}
|
|
85
|
+
/** Replaces one `<string name="x">…</string>` value, escaping XML metacharacters. */
|
|
86
|
+
function replaceStringResource(xml, name, value) {
|
|
87
|
+
const escaped = value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">");
|
|
88
|
+
const pattern = new RegExp(`(<string\\s+name=(?:"|')${name}(?:"|')\\s*>)([\\s\\S]*?)(</string>)`);
|
|
89
|
+
return xml.replace(pattern, `$1${escaped}$3`);
|
|
90
|
+
}
|
|
91
|
+
function patchIos(input) {
|
|
92
|
+
const iosRoot = path.resolve(input.appDir, input.iosDir);
|
|
93
|
+
const plist = path.join(iosRoot, "App", "App", "Info.plist");
|
|
94
|
+
if (!fs.existsSync(plist))
|
|
95
|
+
return [];
|
|
96
|
+
const appName = readEnv(input.env, "VITE_APP_NAME");
|
|
97
|
+
const version = readEnv(input.env, "VITE_APP_VERSION");
|
|
98
|
+
const build = readEnv(input.env, "BUILD_NUMBER");
|
|
99
|
+
let contents = fs.readFileSync(plist, "utf8");
|
|
100
|
+
const before = contents;
|
|
101
|
+
if (version)
|
|
102
|
+
contents = replacePlistString(contents, "CFBundleShortVersionString", version);
|
|
103
|
+
if (build)
|
|
104
|
+
contents = replacePlistString(contents, "CFBundleVersion", build);
|
|
105
|
+
if (appName)
|
|
106
|
+
contents = replacePlistString(contents, "CFBundleDisplayName", appName);
|
|
107
|
+
if (contents === before)
|
|
108
|
+
return [];
|
|
109
|
+
fs.writeFileSync(plist, contents);
|
|
110
|
+
return [path.relative(input.appDir, plist)];
|
|
111
|
+
}
|
|
112
|
+
function replacePlistString(xml, key, value) {
|
|
113
|
+
const pattern = new RegExp(`(<key>${key}</key>\\s*<string>)([\\s\\S]*?)(</string>)`);
|
|
114
|
+
return xml.replace(pattern, `$1${value}$3`);
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* The bundle identifier iOS builds from lives in `project.pbxproj`, which is
|
|
118
|
+
* not safely editable with a regex. Trapeze does it properly, so the built-in
|
|
119
|
+
* path reports the limitation instead of pretending to have handled it.
|
|
120
|
+
*/
|
|
121
|
+
export function builtinConfigLimitations(platform) {
|
|
122
|
+
if (platform === "ios") {
|
|
123
|
+
return ["the iOS bundle identifier in project.pbxproj is not changed without Trapeze"];
|
|
124
|
+
}
|
|
125
|
+
return ["AndroidManifest permissions declared only in a Trapeze config are not applied"];
|
|
126
|
+
}
|
|
127
|
+
//# sourceMappingURL=native-config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"native-config.js","sourceRoot":"","sources":["../../src/pipeline/native-config.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Locates the tools the deploy pipeline needs.
|
|
3
|
+
*
|
|
4
|
+
* The old pipeline assumed a great deal: that pnpm was the package manager,
|
|
5
|
+
* that the application defined scripts called `assets:<env>`, `build:<env>` and
|
|
6
|
+
* `trapeze:<env>`, and that `@capgo/cli` could be fetched from the network
|
|
7
|
+
* mid-deploy. Any of those being false failed the deploy halfway through, after
|
|
8
|
+
* the version had already been bumped.
|
|
9
|
+
*
|
|
10
|
+
* Nothing here shells out to a package manager to find a tool. A dependency's
|
|
11
|
+
* executable already lives in `node_modules/.bin`, and in a workspace it lives
|
|
12
|
+
* in the *root* `node_modules/.bin` too - so walking up from the app directory
|
|
13
|
+
* finds it whether the app is standalone or a workspace member.
|
|
14
|
+
*/
|
|
15
|
+
export type PackageManager = "pnpm" | "npm" | "yarn" | "bun";
|
|
16
|
+
export interface Toolchain {
|
|
17
|
+
/** Directory the application lives in. */
|
|
18
|
+
appDir: string;
|
|
19
|
+
/** Workspace root, or `appDir` when the app is standalone. */
|
|
20
|
+
workspaceRoot: string;
|
|
21
|
+
packageManager: PackageManager;
|
|
22
|
+
/** True when Vite+ drives this workspace. */
|
|
23
|
+
hasVitePlus: boolean;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Resolves a dependency executable to an absolute path.
|
|
27
|
+
*
|
|
28
|
+
* On Windows the runnable file is `<name>.cmd` (or `.exe`), not `<name>`, so
|
|
29
|
+
* both are probed. Returns null when the tool is not installed - callers decide
|
|
30
|
+
* whether that is fatal or a reason to skip a step.
|
|
31
|
+
*/
|
|
32
|
+
export declare function resolveBin(name: string, from: string): string | null;
|
|
33
|
+
/**
|
|
34
|
+
* Detects the workspace root and package manager.
|
|
35
|
+
*
|
|
36
|
+
* Lockfile detection is deliberately last: a `packageManager` field is an
|
|
37
|
+
* explicit declaration, a lockfile is an artefact. When nothing is declared the
|
|
38
|
+
* fallback is npm, which every Node installation has.
|
|
39
|
+
*/
|
|
40
|
+
export declare function detectToolchain(appDir: string): Toolchain;
|
|
41
|
+
/** Reads a script out of the application's package.json. */
|
|
42
|
+
export declare function readScript(appDir: string, name: string): string | null;
|
|
43
|
+
/** The argv for running a package.json script with the detected manager. */
|
|
44
|
+
export declare function scriptCommand(toolchain: Toolchain, script: string): {
|
|
45
|
+
file: string;
|
|
46
|
+
args: string[];
|
|
47
|
+
};
|
|
48
|
+
export interface ToolLookup {
|
|
49
|
+
/** Absolute path to the executable, when it is installed. */
|
|
50
|
+
bin: string | null;
|
|
51
|
+
/** Package that provides it, for the "not installed" message. */
|
|
52
|
+
packageName: string;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Tools the pipeline can use. Every one of them is optional: a missing tool
|
|
56
|
+
* makes the CLI skip or substitute that step, never abort the deploy.
|
|
57
|
+
*/
|
|
58
|
+
export declare function lookupTools(appDir: string): {
|
|
59
|
+
vite: {
|
|
60
|
+
bin: string | null;
|
|
61
|
+
packageName: string;
|
|
62
|
+
};
|
|
63
|
+
vp: {
|
|
64
|
+
bin: string | null;
|
|
65
|
+
packageName: string;
|
|
66
|
+
};
|
|
67
|
+
capacitor: {
|
|
68
|
+
bin: string | null;
|
|
69
|
+
packageName: string;
|
|
70
|
+
};
|
|
71
|
+
assets: {
|
|
72
|
+
bin: string | null;
|
|
73
|
+
packageName: string;
|
|
74
|
+
};
|
|
75
|
+
trapeze: {
|
|
76
|
+
bin: string | null;
|
|
77
|
+
packageName: string;
|
|
78
|
+
};
|
|
79
|
+
};
|
|
80
|
+
//# sourceMappingURL=toolchain.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"toolchain.d.ts","sourceRoot":"","sources":["../../src/pipeline/toolchain.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;GAaG;AAEH,MAAM,MAAM,cAAc,GAAG,MAAM,GAAG,KAAK,GAAG,MAAM,GAAG,KAAK,CAAC;AAE7D,MAAM,WAAW,SAAS;IACxB,0CAA0C;IAC1C,MAAM,EAAE,MAAM,CAAC;IACf,8DAA8D;IAC9D,aAAa,EAAE,MAAM,CAAC;IACtB,cAAc,EAAE,cAAc,CAAC;IAC/B,6CAA6C;IAC7C,WAAW,EAAE,OAAO,CAAC;CACtB;AAmBD;;;;;;GAMG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAWpE;AAgBD;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAoCzD;AA8BD,4DAA4D;AAC5D,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAYtE;AAED,4EAA4E;AAC5E,wBAAgB,aAAa,CAC3B,SAAS,EAAE,SAAS,EACpB,MAAM,EAAE,MAAM,GACb;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,EAAE,CAAA;CAAE,CAElC;AAED,MAAM,WAAW,UAAU;IACzB,6DAA6D;IAC7D,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACnB,iEAAiE;IACjE,WAAW,EAAE,MAAM,CAAC;CACrB;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM;;;;;;;;;;;;;;;;;;;;;EAczC"}
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
const BIN_DIR = path.join("node_modules", ".bin");
|
|
4
|
+
/** Directories that could hold a dependency executable, nearest first. */
|
|
5
|
+
function binDirs(from) {
|
|
6
|
+
const dirs = [];
|
|
7
|
+
let current = path.resolve(from);
|
|
8
|
+
for (;;) {
|
|
9
|
+
dirs.push(path.join(current, BIN_DIR));
|
|
10
|
+
const parent = path.dirname(current);
|
|
11
|
+
if (parent === current)
|
|
12
|
+
break;
|
|
13
|
+
current = parent;
|
|
14
|
+
}
|
|
15
|
+
return dirs;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Resolves a dependency executable to an absolute path.
|
|
19
|
+
*
|
|
20
|
+
* On Windows the runnable file is `<name>.cmd` (or `.exe`), not `<name>`, so
|
|
21
|
+
* both are probed. Returns null when the tool is not installed - callers decide
|
|
22
|
+
* whether that is fatal or a reason to skip a step.
|
|
23
|
+
*/
|
|
24
|
+
export function resolveBin(name, from) {
|
|
25
|
+
const candidates = process.platform === "win32" ? [`${name}.cmd`, `${name}.exe`, name] : [name];
|
|
26
|
+
for (const dir of binDirs(from)) {
|
|
27
|
+
for (const candidate of candidates) {
|
|
28
|
+
const full = path.join(dir, candidate);
|
|
29
|
+
if (fs.existsSync(full))
|
|
30
|
+
return full;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
/** Finds the nearest ancestor containing any of `markers`. */
|
|
36
|
+
function findUp(from, markers) {
|
|
37
|
+
let current = path.resolve(from);
|
|
38
|
+
for (;;) {
|
|
39
|
+
if (markers.some((marker) => fs.existsSync(path.join(current, marker)))) {
|
|
40
|
+
return current;
|
|
41
|
+
}
|
|
42
|
+
const parent = path.dirname(current);
|
|
43
|
+
if (parent === current)
|
|
44
|
+
return null;
|
|
45
|
+
current = parent;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Detects the workspace root and package manager.
|
|
50
|
+
*
|
|
51
|
+
* Lockfile detection is deliberately last: a `packageManager` field is an
|
|
52
|
+
* explicit declaration, a lockfile is an artefact. When nothing is declared the
|
|
53
|
+
* fallback is npm, which every Node installation has.
|
|
54
|
+
*/
|
|
55
|
+
export function detectToolchain(appDir) {
|
|
56
|
+
const workspaceRoot = findUp(appDir, [
|
|
57
|
+
"pnpm-workspace.yaml",
|
|
58
|
+
"pnpm-lock.yaml",
|
|
59
|
+
"yarn.lock",
|
|
60
|
+
"bun.lock",
|
|
61
|
+
"bun.lockb",
|
|
62
|
+
"package-lock.json",
|
|
63
|
+
]) ?? appDir;
|
|
64
|
+
let packageManager = "npm";
|
|
65
|
+
const declared = readPackageManagerField(workspaceRoot);
|
|
66
|
+
if (declared) {
|
|
67
|
+
packageManager = declared;
|
|
68
|
+
}
|
|
69
|
+
else if (fs.existsSync(path.join(workspaceRoot, "pnpm-lock.yaml")) ||
|
|
70
|
+
fs.existsSync(path.join(workspaceRoot, "pnpm-workspace.yaml"))) {
|
|
71
|
+
packageManager = "pnpm";
|
|
72
|
+
}
|
|
73
|
+
else if (fs.existsSync(path.join(workspaceRoot, "yarn.lock"))) {
|
|
74
|
+
packageManager = "yarn";
|
|
75
|
+
}
|
|
76
|
+
else if (fs.existsSync(path.join(workspaceRoot, "bun.lock")) ||
|
|
77
|
+
fs.existsSync(path.join(workspaceRoot, "bun.lockb"))) {
|
|
78
|
+
packageManager = "bun";
|
|
79
|
+
}
|
|
80
|
+
return {
|
|
81
|
+
appDir,
|
|
82
|
+
workspaceRoot,
|
|
83
|
+
packageManager,
|
|
84
|
+
hasVitePlus: resolveBin("vp", appDir) !== null,
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
function readPackageManagerField(root) {
|
|
88
|
+
const file = path.join(root, "package.json");
|
|
89
|
+
if (!fs.existsSync(file))
|
|
90
|
+
return null;
|
|
91
|
+
try {
|
|
92
|
+
const pkg = JSON.parse(fs.readFileSync(file, "utf8"));
|
|
93
|
+
const fromField = pkg.packageManager?.split("@")[0];
|
|
94
|
+
if (isPackageManager(fromField))
|
|
95
|
+
return fromField;
|
|
96
|
+
const declared = pkg.devEngines?.packageManager;
|
|
97
|
+
const name = Array.isArray(declared) ? declared[0]?.name : declared?.name;
|
|
98
|
+
if (isPackageManager(name))
|
|
99
|
+
return name;
|
|
100
|
+
}
|
|
101
|
+
catch {
|
|
102
|
+
// A malformed package.json is the app's problem, not a reason to crash
|
|
103
|
+
// during tool detection.
|
|
104
|
+
}
|
|
105
|
+
return null;
|
|
106
|
+
}
|
|
107
|
+
function isPackageManager(value) {
|
|
108
|
+
return value === "pnpm" || value === "npm" || value === "yarn" || value === "bun";
|
|
109
|
+
}
|
|
110
|
+
/** Reads a script out of the application's package.json. */
|
|
111
|
+
export function readScript(appDir, name) {
|
|
112
|
+
const file = path.join(appDir, "package.json");
|
|
113
|
+
if (!fs.existsSync(file))
|
|
114
|
+
return null;
|
|
115
|
+
try {
|
|
116
|
+
const pkg = JSON.parse(fs.readFileSync(file, "utf8"));
|
|
117
|
+
return pkg.scripts?.[name] ?? null;
|
|
118
|
+
}
|
|
119
|
+
catch {
|
|
120
|
+
return null;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
/** The argv for running a package.json script with the detected manager. */
|
|
124
|
+
export function scriptCommand(toolchain, script) {
|
|
125
|
+
return { file: toolchain.packageManager, args: ["run", script] };
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Tools the pipeline can use. Every one of them is optional: a missing tool
|
|
129
|
+
* makes the CLI skip or substitute that step, never abort the deploy.
|
|
130
|
+
*/
|
|
131
|
+
export function lookupTools(appDir) {
|
|
132
|
+
return {
|
|
133
|
+
vite: { bin: resolveBin("vite", appDir), packageName: "vite" },
|
|
134
|
+
vp: { bin: resolveBin("vp", appDir), packageName: "vite-plus" },
|
|
135
|
+
capacitor: { bin: resolveBin("cap", appDir), packageName: "@capacitor/cli" },
|
|
136
|
+
assets: {
|
|
137
|
+
bin: resolveBin("capacitor-assets", appDir),
|
|
138
|
+
packageName: "@capacitor/assets",
|
|
139
|
+
},
|
|
140
|
+
trapeze: {
|
|
141
|
+
bin: resolveBin("trapeze", appDir),
|
|
142
|
+
packageName: "@trapezedev/configure",
|
|
143
|
+
},
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
//# sourceMappingURL=toolchain.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"toolchain.js","sourceRoot":"","sources":["../../src/pipeline/toolchain.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AA6B7B,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE,MAAM,CAAC,CAAC;AAElD,0EAA0E;AAC1E,SAAS,OAAO,CAAC,IAAY;IAC3B,MAAM,IAAI,GAAa,EAAE,CAAC;IAC1B,IAAI,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IAEjC,SAAS,CAAC;QACR,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC;QACvC,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;QACrC,IAAI,MAAM,KAAK,OAAO;YAAE,MAAM;QAC9B,OAAO,GAAG,MAAM,CAAC;IACnB,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,UAAU,CAAC,IAAY,EAAE,IAAY;IACnD,MAAM,UAAU,GAAG,OAAO,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,MAAM,EAAE,GAAG,IAAI,MAAM,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;IAEhG,KAAK,MAAM,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;QAChC,KAAK,MAAM,SAAS,IAAI,UAAU,EAAE,CAAC;YACnC,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;YACvC,IAAI,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC;gBAAE,OAAO,IAAI,CAAC;QACvC,CAAC;IACH,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAED,8DAA8D;AAC9D,SAAS,MAAM,CAAC,IAAY,EAAE,OAAiB;IAC7C,IAAI,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IAEjC,SAAS,CAAC;QACR,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC;YACxE,OAAO,OAAO,CAAC;QACjB,CAAC;QACD,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;QACrC,IAAI,MAAM,KAAK,OAAO;YAAE,OAAO,IAAI,CAAC;QACpC,OAAO,GAAG,MAAM,CAAC;IACnB,CAAC;AACH,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,eAAe,CAAC,MAAc;IAC5C,MAAM,aAAa,GACjB,MAAM,CAAC,MAAM,EAAE;QACb,qBAAqB;QACrB,gBAAgB;QAChB,WAAW;QACX,UAAU;QACV,WAAW;QACX,mBAAmB;KACpB,CAAC,IAAI,MAAM,CAAC;IAEf,IAAI,cAAc,GAAmB,KAAK,CAAC;IAE3C,MAAM,QAAQ,GAAG,uBAAuB,CAAC,aAAa,CAAC,CAAC;IACxD,IAAI,QAAQ,EAAE,CAAC;QACb,cAAc,GAAG,QAAQ,CAAC;IAC5B,CAAC;SAAM,IACL,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,gBAAgB,CAAC,CAAC;QACzD,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,qBAAqB,CAAC,CAAC,EAC9D,CAAC;QACD,cAAc,GAAG,MAAM,CAAC;IAC1B,CAAC;SAAM,IAAI,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,WAAW,CAAC,CAAC,EAAE,CAAC;QAChE,cAAc,GAAG,MAAM,CAAC;IAC1B,CAAC;SAAM,IACL,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,UAAU,CAAC,CAAC;QACnD,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,WAAW,CAAC,CAAC,EACpD,CAAC;QACD,cAAc,GAAG,KAAK,CAAC;IACzB,CAAC;IAED,OAAO;QACL,MAAM;QACN,aAAa;QACb,cAAc;QACd,WAAW,EAAE,UAAU,CAAC,IAAI,EAAE,MAAM,CAAC,KAAK,IAAI;KAC/C,CAAC;AACJ,CAAC;AAED,SAAS,uBAAuB,CAAC,IAAY;IAC3C,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,cAAc,CAAC,CAAC;IAC7C,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC;IAEtC,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAGnD,CAAC;QAEF,MAAM,SAAS,GAAG,GAAG,CAAC,cAAc,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;QACpD,IAAI,gBAAgB,CAAC,SAAS,CAAC;YAAE,OAAO,SAAS,CAAC;QAElD,MAAM,QAAQ,GAAG,GAAG,CAAC,UAAU,EAAE,cAAc,CAAC;QAChD,MAAM,IAAI,GAAG,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC,QAAQ,EAAE,IAAI,CAAC;QAC1E,IAAI,gBAAgB,CAAC,IAAI,CAAC;YAAE,OAAO,IAAI,CAAC;IAC1C,CAAC;IAAC,MAAM,CAAC;QACP,uEAAuE;QACvE,yBAAyB;IAC3B,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAED,SAAS,gBAAgB,CAAC,KAAyB;IACjD,OAAO,KAAK,KAAK,MAAM,IAAI,KAAK,KAAK,KAAK,IAAI,KAAK,KAAK,MAAM,IAAI,KAAK,KAAK,KAAK,CAAC;AACpF,CAAC;AAED,4DAA4D;AAC5D,MAAM,UAAU,UAAU,CAAC,MAAc,EAAE,IAAY;IACrD,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;IAC/C,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC;IAEtC,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAEnD,CAAC;QACF,OAAO,GAAG,CAAC,OAAO,EAAE,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC;IACrC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,4EAA4E;AAC5E,MAAM,UAAU,aAAa,CAC3B,SAAoB,EACpB,MAAc;IAEd,OAAO,EAAE,IAAI,EAAE,SAAS,CAAC,cAAc,EAAE,IAAI,EAAE,CAAC,KAAK,EAAE,MAAM,CAAC,EAAE,CAAC;AACnE,CAAC;AASD;;;GAGG;AACH,MAAM,UAAU,WAAW,CAAC,MAAc;IACxC,OAAO;QACL,IAAI,EAAE,EAAE,GAAG,EAAE,UAAU,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,WAAW,EAAE,MAAM,EAAE;QAC9D,EAAE,EAAE,EAAE,GAAG,EAAE,UAAU,CAAC,IAAI,EAAE,MAAM,CAAC,EAAE,WAAW,EAAE,WAAW,EAAE;QAC/D,SAAS,EAAE,EAAE,GAAG,EAAE,UAAU,CAAC,KAAK,EAAE,MAAM,CAAC,EAAE,WAAW,EAAE,gBAAgB,EAAE;QAC5E,MAAM,EAAE;YACN,GAAG,EAAE,UAAU,CAAC,kBAAkB,EAAE,MAAM,CAAC;YAC3C,WAAW,EAAE,mBAAmB;SACjC;QACD,OAAO,EAAE;YACP,GAAG,EAAE,UAAU,CAAC,SAAS,EAAE,MAAM,CAAC;YAClC,WAAW,EAAE,uBAAuB;SACrC;KACmC,CAAC;AACzC,CAAC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export interface BundleResult {
|
|
2
|
+
zipPath: string;
|
|
3
|
+
fileCount: number;
|
|
4
|
+
byteSize: number;
|
|
5
|
+
}
|
|
6
|
+
export interface BundleOptions {
|
|
7
|
+
/** Directory whose *contents* become the archive root. */
|
|
8
|
+
webDir: string;
|
|
9
|
+
/** Where to write the archive. */
|
|
10
|
+
outFile: string;
|
|
11
|
+
/** Fixed modification time, for reproducible archives. */
|
|
12
|
+
mtime?: Date;
|
|
13
|
+
}
|
|
14
|
+
/** Builds the OTA archive from a built web directory. */
|
|
15
|
+
export declare function createBundleZip(options: BundleOptions): BundleResult;
|
|
16
|
+
/**
|
|
17
|
+
* Names the archive after the app and version rather than dropping a bare
|
|
18
|
+
* `<version>.zip` in the project root, so a stray archive is identifiable and
|
|
19
|
+
* the gitignore rule can match it.
|
|
20
|
+
*/
|
|
21
|
+
export declare function bundleFileName(appId: string, version: string): string;
|
|
22
|
+
//# sourceMappingURL=zip.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"zip.d.ts","sourceRoot":"","sources":["../../src/pipeline/zip.ts"],"names":[],"mappings":"AAgHA,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,aAAa;IAC5B,0DAA0D;IAC1D,MAAM,EAAE,MAAM,CAAC;IACf,kCAAkC;IAClC,OAAO,EAAE,MAAM,CAAC;IAChB,0DAA0D;IAC1D,KAAK,CAAC,EAAE,IAAI,CAAC;CACd;AAED,yDAAyD;AACzD,wBAAgB,eAAe,CAAC,OAAO,EAAE,aAAa,GAAG,YAAY,CAsGpE;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAGrE"}
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import zlib from "node:zlib";
|
|
4
|
+
/**
|
|
5
|
+
* Writes the OTA bundle archive.
|
|
6
|
+
*
|
|
7
|
+
* The pipeline used to run `npx @capgo/cli bundle zip <appId> --json` for this,
|
|
8
|
+
* which meant a deploy could not run offline, depended on a third-party CLI
|
|
9
|
+
* resolved at deploy time, and dropped the archive somewhere in the project
|
|
10
|
+
* root - after which `findLatestZip` picked *the newest .zip in the directory*,
|
|
11
|
+
* whatever it was, and deleted it on success.
|
|
12
|
+
*
|
|
13
|
+
* The archive format is dictated by `@capgo/capacitor-updater`, which unpacks
|
|
14
|
+
* it on the device. Two of its rules are easy to break and fail only on a real
|
|
15
|
+
* phone:
|
|
16
|
+
*
|
|
17
|
+
* 1. Entry names must use forward slashes. The Android unzip rejects any entry
|
|
18
|
+
* containing a backslash outright ("Windows path not supported"), so a
|
|
19
|
+
* naive `path.join` on Windows produces an archive that installs nowhere.
|
|
20
|
+
* 2. After unpacking, if the extracted directory holds exactly one entry and
|
|
21
|
+
* that entry is not `index.html`, the plugin treats it as a wrapper and
|
|
22
|
+
* descends into it. Writing the web assets at the archive root - which is
|
|
23
|
+
* what this does - keeps that logic out of the picture entirely.
|
|
24
|
+
*
|
|
25
|
+
* The plugin also validates that `index.html` exists at the bundle root, so
|
|
26
|
+
* that is checked before anything is written.
|
|
27
|
+
*/
|
|
28
|
+
const LOCAL_HEADER = 0x04_03_4b_50;
|
|
29
|
+
const CENTRAL_HEADER = 0x02_01_4b_50;
|
|
30
|
+
const END_OF_CENTRAL_DIR = 0x06_05_4b_50;
|
|
31
|
+
const ZIP_VERSION = 20; // 2.0 - deflate
|
|
32
|
+
const DEFLATED = 8;
|
|
33
|
+
const MAX_ZIP_SIZE = 0xff_ff_ff_ff; // 4 GiB - beyond this ZIP64 is required.
|
|
34
|
+
/** Files that must never reach a device. */
|
|
35
|
+
const EXCLUDED = new Set([".DS_Store", "Thumbs.db", ".gitkeep", "capuchoo-deploy.log"]);
|
|
36
|
+
const CRC_TABLE = buildCrcTable();
|
|
37
|
+
function buildCrcTable() {
|
|
38
|
+
const table = new Int32Array(256);
|
|
39
|
+
for (let i = 0; i < 256; i++) {
|
|
40
|
+
let c = i;
|
|
41
|
+
for (let k = 0; k < 8; k++) {
|
|
42
|
+
c = c & 1 ? 0xed_b8_83_20 ^ (c >>> 1) : c >>> 1;
|
|
43
|
+
}
|
|
44
|
+
table[i] = c;
|
|
45
|
+
}
|
|
46
|
+
return table;
|
|
47
|
+
}
|
|
48
|
+
function crc32(buffer) {
|
|
49
|
+
let crc = -1;
|
|
50
|
+
for (const byte of buffer) {
|
|
51
|
+
crc = (crc >>> 8) ^ CRC_TABLE[(crc ^ byte) & 0xff];
|
|
52
|
+
}
|
|
53
|
+
return (crc ^ -1) >>> 0;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Encodes a timestamp as MS-DOS date and time.
|
|
57
|
+
*
|
|
58
|
+
* A fixed timestamp keeps the archive byte-for-byte reproducible: rebuilding
|
|
59
|
+
* the same bundle twice produces the same checksum, so the backend can tell a
|
|
60
|
+
* genuine change from a rebuild.
|
|
61
|
+
*/
|
|
62
|
+
function dosDateTime(date) {
|
|
63
|
+
const time = (Math.floor(date.getSeconds() / 2) & 0x1f) |
|
|
64
|
+
((date.getMinutes() & 0x3f) << 5) |
|
|
65
|
+
((date.getHours() & 0x1f) << 11);
|
|
66
|
+
const day = (date.getDate() & 0x1f) |
|
|
67
|
+
(((date.getMonth() + 1) & 0x0f) << 5) |
|
|
68
|
+
(((date.getFullYear() - 1980) & 0x7f) << 9);
|
|
69
|
+
return { time, date: day };
|
|
70
|
+
}
|
|
71
|
+
/** Collects files under `root`, depth first, with forward-slash names. */
|
|
72
|
+
function collect(root, prefix = "") {
|
|
73
|
+
const entries = [];
|
|
74
|
+
for (const item of fs
|
|
75
|
+
.readdirSync(root, { withFileTypes: true })
|
|
76
|
+
.sort((a, b) => (a.name < b.name ? -1 : a.name > b.name ? 1 : 0))) {
|
|
77
|
+
if (EXCLUDED.has(item.name))
|
|
78
|
+
continue;
|
|
79
|
+
const absolute = path.join(root, item.name);
|
|
80
|
+
// Built with "/" explicitly rather than path.join, which would emit "\"
|
|
81
|
+
// on Windows and produce an archive the Android plugin refuses.
|
|
82
|
+
const name = prefix ? `${prefix}/${item.name}` : item.name;
|
|
83
|
+
if (item.isDirectory()) {
|
|
84
|
+
entries.push(...collect(absolute, name));
|
|
85
|
+
}
|
|
86
|
+
else if (item.isFile()) {
|
|
87
|
+
entries.push({ name, source: absolute });
|
|
88
|
+
}
|
|
89
|
+
// Symlinks are skipped: the plugin has no way to reproduce them and
|
|
90
|
+
// following one could pull in files from outside the web directory.
|
|
91
|
+
}
|
|
92
|
+
return entries;
|
|
93
|
+
}
|
|
94
|
+
/** Builds the OTA archive from a built web directory. */
|
|
95
|
+
export function createBundleZip(options) {
|
|
96
|
+
const { webDir, outFile } = options;
|
|
97
|
+
if (!fs.existsSync(webDir)) {
|
|
98
|
+
throw new Error(`Web directory "${webDir}" does not exist. The build step produced nothing to publish.`);
|
|
99
|
+
}
|
|
100
|
+
if (!fs.existsSync(path.join(webDir, "index.html"))) {
|
|
101
|
+
throw new Error(`"${webDir}" has no index.html at its root. ` +
|
|
102
|
+
"@capgo/capacitor-updater rejects a bundle without one, so this archive " +
|
|
103
|
+
"would download on every device and then fail to apply.");
|
|
104
|
+
}
|
|
105
|
+
const entries = collect(webDir);
|
|
106
|
+
if (entries.length === 0) {
|
|
107
|
+
throw new Error(`"${webDir}" is empty, so there is nothing to publish.`);
|
|
108
|
+
}
|
|
109
|
+
// 1980-01-01, the earliest representable MS-DOS timestamp.
|
|
110
|
+
const stamp = dosDateTime(options.mtime ?? new Date(Date.UTC(1980, 0, 1)));
|
|
111
|
+
const localParts = [];
|
|
112
|
+
const centralParts = [];
|
|
113
|
+
let offset = 0;
|
|
114
|
+
for (const entry of entries) {
|
|
115
|
+
const contents = fs.readFileSync(entry.source);
|
|
116
|
+
const compressed = zlib.deflateRawSync(contents, { level: 9 });
|
|
117
|
+
const nameBytes = Buffer.from(entry.name, "utf8");
|
|
118
|
+
const crc = crc32(contents);
|
|
119
|
+
const local = Buffer.alloc(30);
|
|
120
|
+
local.writeUInt32LE(LOCAL_HEADER, 0);
|
|
121
|
+
local.writeUInt16LE(ZIP_VERSION, 4);
|
|
122
|
+
// Bit 11 marks the name as UTF-8, which matters for non-ASCII asset names.
|
|
123
|
+
local.writeUInt16LE(0x08_00, 6);
|
|
124
|
+
local.writeUInt16LE(DEFLATED, 8);
|
|
125
|
+
local.writeUInt16LE(stamp.time, 10);
|
|
126
|
+
local.writeUInt16LE(stamp.date, 12);
|
|
127
|
+
local.writeUInt32LE(crc, 14);
|
|
128
|
+
local.writeUInt32LE(compressed.length, 18);
|
|
129
|
+
local.writeUInt32LE(contents.length, 22);
|
|
130
|
+
local.writeUInt16LE(nameBytes.length, 26);
|
|
131
|
+
local.writeUInt16LE(0, 28);
|
|
132
|
+
localParts.push(local, nameBytes, compressed);
|
|
133
|
+
const central = Buffer.alloc(46);
|
|
134
|
+
central.writeUInt32LE(CENTRAL_HEADER, 0);
|
|
135
|
+
central.writeUInt16LE(ZIP_VERSION, 4);
|
|
136
|
+
central.writeUInt16LE(ZIP_VERSION, 6);
|
|
137
|
+
central.writeUInt16LE(0x08_00, 8);
|
|
138
|
+
central.writeUInt16LE(DEFLATED, 10);
|
|
139
|
+
central.writeUInt16LE(stamp.time, 12);
|
|
140
|
+
central.writeUInt16LE(stamp.date, 14);
|
|
141
|
+
central.writeUInt32LE(crc, 16);
|
|
142
|
+
central.writeUInt32LE(compressed.length, 20);
|
|
143
|
+
central.writeUInt32LE(contents.length, 24);
|
|
144
|
+
central.writeUInt16LE(nameBytes.length, 28);
|
|
145
|
+
central.writeUInt16LE(0, 30); // extra
|
|
146
|
+
central.writeUInt16LE(0, 32); // comment
|
|
147
|
+
central.writeUInt16LE(0, 34); // disk number
|
|
148
|
+
central.writeUInt16LE(0, 36); // internal attributes
|
|
149
|
+
// Regular file, mode 0644, in the high word where Unix permissions live.
|
|
150
|
+
// `>>> 0` is required: the shift alone overflows into a negative int32,
|
|
151
|
+
// which writeUInt32LE rejects.
|
|
152
|
+
central.writeUInt32LE((0o10_0644 << 16) >>> 0, 38);
|
|
153
|
+
central.writeUInt32LE(offset, 42);
|
|
154
|
+
centralParts.push(central, nameBytes);
|
|
155
|
+
offset += local.length + nameBytes.length + compressed.length;
|
|
156
|
+
if (offset > MAX_ZIP_SIZE) {
|
|
157
|
+
throw new Error("The web bundle exceeds 4 GiB, which needs ZIP64. Reduce the bundle size.");
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
const centralDirectory = Buffer.concat(centralParts);
|
|
161
|
+
const end = Buffer.alloc(22);
|
|
162
|
+
end.writeUInt32LE(END_OF_CENTRAL_DIR, 0);
|
|
163
|
+
end.writeUInt16LE(0, 4); // this disk
|
|
164
|
+
end.writeUInt16LE(0, 6); // disk with central directory
|
|
165
|
+
end.writeUInt16LE(entries.length, 8);
|
|
166
|
+
end.writeUInt16LE(entries.length, 10);
|
|
167
|
+
end.writeUInt32LE(centralDirectory.length, 12);
|
|
168
|
+
end.writeUInt32LE(offset, 16);
|
|
169
|
+
end.writeUInt16LE(0, 20); // comment length
|
|
170
|
+
const archive = Buffer.concat([...localParts, centralDirectory, end]);
|
|
171
|
+
fs.mkdirSync(path.dirname(outFile), { recursive: true });
|
|
172
|
+
fs.writeFileSync(outFile, archive);
|
|
173
|
+
return {
|
|
174
|
+
zipPath: outFile,
|
|
175
|
+
fileCount: entries.length,
|
|
176
|
+
byteSize: archive.length,
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Names the archive after the app and version rather than dropping a bare
|
|
181
|
+
* `<version>.zip` in the project root, so a stray archive is identifiable and
|
|
182
|
+
* the gitignore rule can match it.
|
|
183
|
+
*/
|
|
184
|
+
export function bundleFileName(appId, version) {
|
|
185
|
+
const safe = `${appId}-${version}`.replaceAll(/[^\w.-]/g, "-");
|
|
186
|
+
return `capuchoo-bundle-${safe}.zip`;
|
|
187
|
+
}
|
|
188
|
+
//# sourceMappingURL=zip.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"zip.js","sourceRoot":"","sources":["../../src/pipeline/zip.ts"],"names":[],"mappings":"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"}
|