crossbind 2.0.0-beta.64 → 2.0.0-beta.66
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/package.json +6 -1
- package/src/actions/androidDevice.js +77 -0
- package/src/actions/androidGradle.js +121 -0
- package/src/actions/appInstaller.js +174 -0
- package/src/actions/appUpdate.js +68 -0
- package/src/actions/appleSigning.js +96 -0
- package/src/actions/buildApp.js +509 -0
- package/src/actions/buildDependencies.js +4 -3
- package/src/actions/buildExternal.js +3 -3
- package/src/actions/buildLib.js +1 -1
- package/src/actions/buildNode.js +15 -10
- package/src/actions/createInterface.js +1 -2
- package/src/actions/createLib.js +13 -5
- package/src/actions/getCmakeParameters.js +6 -2
- package/src/actions/getDependLibs.js +8 -2
- package/src/actions/getLinkInputs.js +10 -7
- package/src/actions/gradleProject.js +171 -0
- package/src/actions/iosSimulator.js +63 -0
- package/src/actions/licenses.js +189 -14
- package/src/actions/nativeBridges.js +35 -0
- package/src/actions/run.js +3 -3
- package/src/actions/target.js +2 -1
- package/src/actions/windowsSigning.js +96 -0
- package/src/actions/xcodeProject.js +186 -0
- package/src/app/index.d.ts +129 -0
- package/src/app/index.js +184 -0
- package/src/assets/js-runtime/adapters/worker-comlink.js +8 -1
- package/src/assets/toolchain-digests.json +24 -18
- package/src/bin.js +84 -32
- package/src/index.js +7 -0
- package/src/integration/getCrossbindScript.js +15 -1
- package/src/state/index.js +5 -1
- package/src/state/loadConfig.js +2 -0
- package/src/utils/appApiHeader.js +29 -0
- package/src/utils/appIcon.js +174 -0
- package/src/utils/appOptions.js +284 -0
- package/src/utils/appRustCrates.js +3 -1
- package/src/utils/downloadAndExtractFile.js +42 -14
- package/src/utils/embindRsFingerprint.js +10 -3
- package/src/utils/hermes.js +40 -0
- package/src/utils/plist.js +42 -0
- package/src/utils/pullDockerImage.js +9 -3
- package/src/utils/replaceBasePathForDocker.js +8 -0
- package/src/utils/resolveAppHost.js +21 -0
- package/src/utils/selectRunner.js +1 -1
- package/src/utils/systemKeys.js +4 -0
- package/src/utils/targets.js +19 -3
- package/src/utils/writeIfChanged.js +1 -1
- package/vitest.config.js +19 -0
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
// Property lists as Apple's tools read them: XML for an Info.plist, the older text form for an Xcode project.
|
|
2
|
+
|
|
3
|
+
const XML_INDENT = ' ';
|
|
4
|
+
const escapeXml = (text) => String(text).replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');
|
|
5
|
+
|
|
6
|
+
function xmlLines(value, indent) {
|
|
7
|
+
if (typeof value === 'boolean') return [`${indent}<${value}/>`];
|
|
8
|
+
const inner = indent + XML_INDENT;
|
|
9
|
+
if (Array.isArray(value)) return [`${indent}<array>`, ...value.flatMap((item) => xmlLines(item, inner)), `${indent}</array>`];
|
|
10
|
+
if (typeof value === 'object') {
|
|
11
|
+
const entries = Object.entries(value);
|
|
12
|
+
if (entries.length === 0) return [`${indent}<dict/>`];
|
|
13
|
+
return [
|
|
14
|
+
`${indent}<dict>`,
|
|
15
|
+
...entries.flatMap(([key, item]) => [`${inner}<key>${escapeXml(key)}</key>`, ...xmlLines(item, inner)]),
|
|
16
|
+
`${indent}</dict>`,
|
|
17
|
+
];
|
|
18
|
+
}
|
|
19
|
+
return [`${indent}<string>${escapeXml(value)}</string>`];
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function xmlPlist(dict) {
|
|
23
|
+
return '<?xml version="1.0" encoding="UTF-8"?>\n'
|
|
24
|
+
+ '<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">\n'
|
|
25
|
+
+ `<plist version="1.0">\n${xmlLines(dict, '').join('\n')}\n</plist>\n`;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// Every value of the text form is a string, quoted here whatever it holds.
|
|
29
|
+
const quote = (text) => `"${String(text).replace(/\\/g, '\\\\').replace(/"/g, '\\"')}"`;
|
|
30
|
+
|
|
31
|
+
function textValue(value, indent) {
|
|
32
|
+
const inner = `${indent}\t`;
|
|
33
|
+
if (Array.isArray(value)) return `(\n${value.map((item) => `${inner}${textValue(item, inner)},\n`).join('')}${indent})`;
|
|
34
|
+
if (typeof value === 'object') {
|
|
35
|
+
return `{\n${Object.entries(value).map(([key, item]) => `${inner}${quote(key)} = ${textValue(item, inner)};\n`).join('')}${indent}}`;
|
|
36
|
+
}
|
|
37
|
+
return quote(value);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export function textPlist(root) {
|
|
41
|
+
return `// !$*UTF8*$!\n${textValue(root, '')}\n`;
|
|
42
|
+
}
|
|
@@ -8,7 +8,11 @@ const table = createRequire(import.meta.url)('../assets/toolchain-digests.json')
|
|
|
8
8
|
const REGISTRY = table.registry;
|
|
9
9
|
const IMAGE_VERSION = table.version;
|
|
10
10
|
const OVERRIDE_KEYS = {
|
|
11
|
-
web: 'CROSSBIND_IMAGE_WEB',
|
|
11
|
+
web: 'CROSSBIND_IMAGE_WEB',
|
|
12
|
+
android: 'CROSSBIND_IMAGE_ANDROID',
|
|
13
|
+
'android-app': 'CROSSBIND_IMAGE_ANDROID_APP',
|
|
14
|
+
linux: 'CROSSBIND_IMAGE_LINUX',
|
|
15
|
+
windows: 'CROSSBIND_IMAGE_WINDOWS',
|
|
12
16
|
};
|
|
13
17
|
const IMAGES = Object.fromEntries(
|
|
14
18
|
Object.keys(OVERRIDE_KEYS).map((role) => [
|
|
@@ -21,9 +25,11 @@ const IMAGES = Object.fromEntries(
|
|
|
21
25
|
);
|
|
22
26
|
|
|
23
27
|
// Which image a target compiles in: wasm and wasi share the web image, linux and linuxmusl the linux
|
|
24
|
-
// image, ios and darwin never reach docker.
|
|
28
|
+
// image, ios and darwin never reach docker. An Android app builds in android-app, the android image with
|
|
29
|
+
// what packages the app.
|
|
25
30
|
export function imageRoleFor(target) {
|
|
26
|
-
if (target?.platform === 'android'
|
|
31
|
+
if (target?.platform === 'android') return target.runtimeEnv === 'app' ? 'android-app' : 'android';
|
|
32
|
+
if (target?.platform === 'linux') return 'linux';
|
|
27
33
|
if (target?.platform === 'linuxmusl') return 'linux';
|
|
28
34
|
if (target?.platform === 'win32') return 'windows';
|
|
29
35
|
return 'web';
|
|
@@ -1,5 +1,13 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
|
|
1
3
|
export const DOCKER_BASE = '/tmp/crossbind/live';
|
|
2
4
|
|
|
5
|
+
// Whether a container, which sees the project's base alone, sees dir.
|
|
6
|
+
export function isUnderBase(dir, basePath) {
|
|
7
|
+
const relative = path.relative(basePath, path.resolve(dir));
|
|
8
|
+
return !/^\.\.(?:[\\/]|$)/.test(relative) && !path.isAbsolute(relative);
|
|
9
|
+
}
|
|
10
|
+
|
|
3
11
|
export default function replaceBasePathForDocker(data, basePath) {
|
|
4
12
|
if (typeof data === 'string' || data instanceof String) {
|
|
5
13
|
return data.replaceAll(basePath, DOCKER_BASE);
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { createRequire } from 'node:module';
|
|
4
|
+
import createCompanionResolver from './resolveCompanionPackage.js';
|
|
5
|
+
|
|
6
|
+
const PKG = '@crossbind/core-app-host';
|
|
7
|
+
|
|
8
|
+
const resolveAppHostRoot = createCompanionResolver({
|
|
9
|
+
pkg: PKG,
|
|
10
|
+
siblingDir: 'app-host',
|
|
11
|
+
siblingMarker: 'cpp/src/main.cpp',
|
|
12
|
+
missingMessage: `crossbind: apps need ${PKG} - add it to your devDependencies.`,
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
export default resolveAppHostRoot;
|
|
16
|
+
|
|
17
|
+
// The embind runtime ships in @crossbind/core-embind-jsi, a dependency of the app host package.
|
|
18
|
+
export function resolveAppEmbindJsiRoot() {
|
|
19
|
+
const req = createRequire(path.join(resolveAppHostRoot(), 'package.json'));
|
|
20
|
+
return path.dirname(fs.realpathSync(req.resolve('@crossbind/core-embind-jsi/package.json')));
|
|
21
|
+
}
|
|
@@ -7,7 +7,7 @@ const SYSTEM_CONFIG = '~/.crossbind.json';
|
|
|
7
7
|
const SHARED = { key: 'REMOTE_URL', url: 'CROSSBIND_REMOTE_URL', token: 'CROSSBIND_TOKEN' };
|
|
8
8
|
|
|
9
9
|
export const remoteVariables = (role) => {
|
|
10
|
-
const suffix = `_${role.toUpperCase()}`;
|
|
10
|
+
const suffix = `_${role.toUpperCase().replaceAll('-', '_')}`;
|
|
11
11
|
return { key: `${SHARED.key}${suffix}`, url: `${SHARED.url}${suffix}`, token: `${SHARED.token}${suffix}` };
|
|
12
12
|
};
|
|
13
13
|
|
package/src/utils/systemKeys.js
CHANGED
|
@@ -48,6 +48,10 @@ const systemKeys = {
|
|
|
48
48
|
description: 'Image reference used for android builds instead of the pinned one. A reference without the release digest disables the reproducibility guarantee. The CROSSBIND_IMAGE_ANDROID environment variable overrides it.',
|
|
49
49
|
default: '',
|
|
50
50
|
},
|
|
51
|
+
DOCKER_IMAGE_ANDROID_APP: {
|
|
52
|
+
description: 'Image reference used for Android apps instead of the pinned one. A reference without the release digest disables the reproducibility guarantee. The CROSSBIND_IMAGE_ANDROID_APP environment variable overrides it.',
|
|
53
|
+
default: '',
|
|
54
|
+
},
|
|
51
55
|
DOCKER_IMAGE_LINUX: {
|
|
52
56
|
description: 'Image reference used for linux (Node.js addon) builds instead of the pinned one. A reference without the release digest disables the reproducibility guarantee. The CROSSBIND_IMAGE_LINUX environment variable overrides it.',
|
|
53
57
|
default: '',
|
package/src/utils/targets.js
CHANGED
|
@@ -148,12 +148,17 @@ const BASE_TARGETS = [
|
|
|
148
148
|
},
|
|
149
149
|
];
|
|
150
150
|
|
|
151
|
-
// A native executable links the same archives as the Node-API addon of its platform and arch
|
|
151
|
+
// A native executable links the same archives as the Node-API addon of its platform and arch, and so does an app's
|
|
152
|
+
// host on macOS, glibc Linux and Windows. An iOS or Android app links the archives React Native does, one target per
|
|
153
|
+
// SDK or ABI.
|
|
152
154
|
export const TARGETS = [
|
|
153
155
|
...BASE_TARGETS,
|
|
154
156
|
...BASE_TARGETS
|
|
155
157
|
.filter((target) => target.runtimeEnv === 'node' && target.platform !== 'wasm')
|
|
156
158
|
.map((target) => ({ ...target, runtimeEnv: 'native' })),
|
|
159
|
+
...BASE_TARGETS
|
|
160
|
+
.filter((target) => (target.runtimeEnv === 'node' && ['darwin', 'linux', 'win32'].includes(target.platform)) || ['ios', 'android'].includes(target.platform))
|
|
161
|
+
.map((target) => ({ ...target, runtimeEnv: 'app' })),
|
|
157
162
|
];
|
|
158
163
|
|
|
159
164
|
// Built only when named with -p: a plain `crossbind build` keeps producing what it did before
|
|
@@ -163,8 +168,8 @@ export const OPT_IN_PLATFORMS = ['darwin', 'linux', 'linuxmusl', 'win32'];
|
|
|
163
168
|
// Built on the host itself: Apple's linker and SDKs exist in no toolchain image.
|
|
164
169
|
export const HOST_BUILT_PLATFORMS = ['ios', 'darwin'];
|
|
165
170
|
|
|
166
|
-
// The runtime environment names the binary a build makes; android and ios
|
|
167
|
-
//
|
|
171
|
+
// The runtime environment names the binary a build makes; on android and ios React Native links
|
|
172
|
+
// the archives, and the app is the one binary.
|
|
168
173
|
export const runtimeEnvsOf = (platform) => [
|
|
169
174
|
...new Set(TARGETS.filter((target) => target.platform === platform && target.runtimeEnv).map((target) => target.runtimeEnv)),
|
|
170
175
|
];
|
|
@@ -203,6 +208,17 @@ export const wasiNamesOf = (target, projectName) => ({
|
|
|
203
208
|
wasmName: `${projectName}-${targetPathOf(target)}${target.runtimeEnv === 'http' ? '.http' : ''}.wasm`,
|
|
204
209
|
});
|
|
205
210
|
|
|
211
|
+
// One app per platform, arch and build type, and one page runtime per build type for all of them. A macOS app is a
|
|
212
|
+
// bundle; a Linux app a directory; an iOS or Android one what its SDK or ABI brings to the app's Xcode or Gradle
|
|
213
|
+
// project.
|
|
214
|
+
export function appNamesOf(target, projectName) {
|
|
215
|
+
const suffix = target.buildType === 'debug' ? '.debug' : '';
|
|
216
|
+
return {
|
|
217
|
+
appName: `${projectName}.${target.platform}-${target.arch}${suffix}${target.platform === 'darwin' ? '.app' : ''}`,
|
|
218
|
+
appJsName: `${projectName}.app${suffix}.js`,
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
|
|
206
222
|
// One executable per platform, arch and build type, named like the addons it replaces.
|
|
207
223
|
export function nativeCommandNamesOf(target, projectName) {
|
|
208
224
|
const suffix = target.buildType === 'debug' ? '.debug' : '';
|
|
@@ -2,7 +2,7 @@ import fs from 'node:fs';
|
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
|
|
4
4
|
export default function writeIfChanged(file, content) {
|
|
5
|
-
if (fs.existsSync(file) && fs.readFileSync(file
|
|
5
|
+
if (fs.existsSync(file) && fs.readFileSync(file).equals(Buffer.from(content))) return;
|
|
6
6
|
fs.mkdirSync(path.dirname(file), { recursive: true });
|
|
7
7
|
fs.writeFileSync(file, content);
|
|
8
8
|
}
|
package/vitest.config.js
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
|
+
import { fileURLToPath } from 'node:url';
|
|
1
2
|
import { defineConfig } from 'vitest/config';
|
|
2
3
|
|
|
3
4
|
export default defineConfig({
|
|
5
|
+
// The app host package's scripts import crossbind's runtime modules the way buildApp bundles them.
|
|
6
|
+
resolve: {
|
|
7
|
+
alias: [{ find: /^crossbind\/runtime\//, replacement: fileURLToPath(new URL('./src/assets/js-runtime/', import.meta.url)) }],
|
|
8
|
+
},
|
|
4
9
|
// loadJs/loadConfig dynamically import config files written to os.tmpdir()
|
|
5
10
|
// during tests. Vite 6 tightened server.fs.allow and rejects those out-of-root
|
|
6
11
|
// paths ("Does the file exist?"); relax the fs check for the test runner.
|
|
@@ -22,6 +27,20 @@ export default defineConfig({
|
|
|
22
27
|
CROSSBIND_REMOTE_URL_LINUX: '',
|
|
23
28
|
CROSSBIND_REMOTE_URL_WINDOWS: '',
|
|
24
29
|
CROSSBIND_CLOUD_URL: 'http://127.0.0.1:9',
|
|
30
|
+
// Nor their signing keys: a macOS app here is signed ad hoc, and a Windows app not at all, unless a test names
|
|
31
|
+
// a key.
|
|
32
|
+
CROSSBIND_APPLE_SIGNING_IDENTITY: '',
|
|
33
|
+
CROSSBIND_APPLE_API_KEY: '',
|
|
34
|
+
CROSSBIND_APPLE_API_KEY_ID: '',
|
|
35
|
+
CROSSBIND_APPLE_API_ISSUER: '',
|
|
36
|
+
CROSSBIND_WINDOWS_SIGNING_STORETYPE: '',
|
|
37
|
+
CROSSBIND_WINDOWS_SIGNING_KEYSTORE: '',
|
|
38
|
+
CROSSBIND_WINDOWS_SIGNING_ALIAS: '',
|
|
39
|
+
CROSSBIND_WINDOWS_SIGNING_STOREPASS: '',
|
|
40
|
+
CROSSBIND_WINDOWS_SIGNING_KEYPASS: '',
|
|
41
|
+
CROSSBIND_WINDOWS_SIGNING_CERTFILE: '',
|
|
42
|
+
CROSSBIND_WINDOWS_SIGNING_TSAURL: '',
|
|
43
|
+
CROSSBIND_UPDATER_PRIVATE_KEY: '',
|
|
25
44
|
},
|
|
26
45
|
coverage: {
|
|
27
46
|
provider: 'v8',
|