@makefully/adaptfully 2.1.0 → 3.0.1
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/CHANGELOG.md +97 -64
- package/LICENSE +21 -21
- package/README.md +517 -430
- package/bin/adaptfully.js +7 -0
- package/bin/wrapfully-deploy.js +22 -7
- package/lib/node/archive.js +43 -34
- package/lib/node/config.js +42 -42
- package/lib/node/deploy.js +52 -69
- package/lib/node/fs-utils.js +49 -0
- package/lib/node/index.js +20 -18
- package/lib/node/paths.js +18 -0
- package/lib/node/pipeline.js +77 -0
- package/lib/node/prebuild.js +90 -0
- package/lib/node/registrations.js +314 -0
- package/lib/node/report.js +42 -42
- package/lib/runtime/auth/_helpers.js +38 -38
- package/lib/runtime/auth/dev-auth.js +78 -78
- package/lib/runtime/auth/google-auth.js +176 -176
- package/lib/runtime/auth/steam-auth.js +50 -50
- package/lib/runtime/core.js +56 -61
- package/lib/runtime/platform.js +89 -89
- package/package.json +62 -61
- package/lib/node/distribution.js +0 -138
package/bin/wrapfully-deploy.js
CHANGED
|
@@ -1,7 +1,22 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { loadProjectConfig, resolveServerUrl } from '../lib/node/config.js';
|
|
3
|
+
import { runAdaptfullyStage } from '../lib/node/pipeline.js';
|
|
4
|
+
import { resolveCliPlatformAndBuilder } from '../lib/node/registrations.js';
|
|
5
|
+
|
|
6
|
+
const arg = process.argv[2] ?? 'steam';
|
|
7
|
+
const cliServer = process.argv[3];
|
|
8
|
+
const mode = process.argv[4] ?? 'extract';
|
|
9
|
+
|
|
10
|
+
const { pkg, wrapfullyConfig } = await loadProjectConfig();
|
|
11
|
+
const { platformKey, builder } = resolveCliPlatformAndBuilder(arg, pkg);
|
|
12
|
+
|
|
13
|
+
runAdaptfullyStage('deploy', platformKey, {
|
|
14
|
+
pkg,
|
|
15
|
+
deployFolder: pkg.config?.deployFolder || 'deploy',
|
|
16
|
+
server: resolveServerUrl(wrapfullyConfig, cliServer),
|
|
17
|
+
mode,
|
|
18
|
+
builder,
|
|
19
|
+
}).catch((err) => {
|
|
20
|
+
console.error(err.message || err);
|
|
21
|
+
process.exit(1);
|
|
22
|
+
});
|
package/lib/node/archive.js
CHANGED
|
@@ -1,34 +1,43 @@
|
|
|
1
|
-
import archiver from 'archiver';
|
|
2
|
-
import fs from 'node:fs';
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* @param {string} deployFolder
|
|
6
|
-
* @param {string} contents - serialized package.json for the zip
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
}
|
|
1
|
+
import archiver from 'archiver';
|
|
2
|
+
import fs from 'node:fs';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* @param {string} deployFolder
|
|
6
|
+
* @param {string} contents - serialized package.json for the zip
|
|
7
|
+
* @param {{ indexHtml?: string }} [options]
|
|
8
|
+
*/
|
|
9
|
+
export function createArchive(deployFolder, contents, options = {}) {
|
|
10
|
+
const zip = archiver('zip', { zlib: { level: 0 } });
|
|
11
|
+
|
|
12
|
+
zip.on('warning', (err) => {
|
|
13
|
+
if (err.code === 'ENOENT') {
|
|
14
|
+
console.log(err);
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
throw err;
|
|
18
|
+
});
|
|
19
|
+
zip.on('error', (err) => {
|
|
20
|
+
throw err;
|
|
21
|
+
});
|
|
22
|
+
zip.on('close', () => {
|
|
23
|
+
console.log(`Zipped ${zip.pointer()} total bytes`);
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
if (options.indexHtml != null) {
|
|
27
|
+
zip.glob('**/*', {
|
|
28
|
+
cwd: deployFolder,
|
|
29
|
+
ignore: ['index.html'],
|
|
30
|
+
}, { prefix: 'deploy' });
|
|
31
|
+
zip.append(options.indexHtml, { name: 'deploy/index.html' });
|
|
32
|
+
} else {
|
|
33
|
+
zip.directory(`${deployFolder}/`, 'deploy');
|
|
34
|
+
zip.file(`${deployFolder}/index.html`, { name: 'deploy/index.html' });
|
|
35
|
+
}
|
|
36
|
+
if (fs.existsSync('assets/meta/')) {
|
|
37
|
+
zip.directory('assets/meta/', 'meta');
|
|
38
|
+
}
|
|
39
|
+
zip.append(contents, { name: 'package.json' });
|
|
40
|
+
zip.finalize();
|
|
41
|
+
|
|
42
|
+
return zip;
|
|
43
|
+
}
|
package/lib/node/config.js
CHANGED
|
@@ -1,42 +1,42 @@
|
|
|
1
|
-
import fs from 'node:fs/promises';
|
|
2
|
-
|
|
3
|
-
const DEFAULT_SERVER = 'http://localhost:9630/';
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* @param {string} [projectRoot='.']
|
|
7
|
-
*/
|
|
8
|
-
export async function loadProjectConfig(projectRoot = '.') {
|
|
9
|
-
const pkgPath = `${projectRoot}/package.json`;
|
|
10
|
-
const wrapfullyPath = `${projectRoot}/wrapfully.json`;
|
|
11
|
-
|
|
12
|
-
const pkg = JSON.parse(await fs.readFile(pkgPath, 'utf8'));
|
|
13
|
-
let wrapfullyConfig = {};
|
|
14
|
-
|
|
15
|
-
try {
|
|
16
|
-
wrapfullyConfig = JSON.parse(await fs.readFile(wrapfullyPath, 'utf8'));
|
|
17
|
-
} catch (err) {
|
|
18
|
-
if (/** @type {NodeJS.ErrnoException} */ (err).code !== 'ENOENT') {
|
|
19
|
-
throw err;
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
pkg.config = {
|
|
24
|
-
...pkg.config,
|
|
25
|
-
...wrapfullyConfig,
|
|
26
|
-
};
|
|
27
|
-
|
|
28
|
-
return { pkg, wrapfullyConfig };
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* @param {{ server?: string }} wrapfullyConfig
|
|
33
|
-
* @param {string} [cliServer]
|
|
34
|
-
*/
|
|
35
|
-
export function resolveServerUrl(wrapfullyConfig, cliServer) {
|
|
36
|
-
return (
|
|
37
|
-
cliServer
|
|
38
|
-
|| process.env.WRAPFULLY_SERVER
|
|
39
|
-
|| wrapfullyConfig.server
|
|
40
|
-
|| DEFAULT_SERVER
|
|
41
|
-
).replace(/\/?$/, '/');
|
|
42
|
-
}
|
|
1
|
+
import fs from 'node:fs/promises';
|
|
2
|
+
|
|
3
|
+
const DEFAULT_SERVER = 'http://localhost:9630/';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* @param {string} [projectRoot='.']
|
|
7
|
+
*/
|
|
8
|
+
export async function loadProjectConfig(projectRoot = '.') {
|
|
9
|
+
const pkgPath = `${projectRoot}/package.json`;
|
|
10
|
+
const wrapfullyPath = `${projectRoot}/wrapfully.json`;
|
|
11
|
+
|
|
12
|
+
const pkg = JSON.parse(await fs.readFile(pkgPath, 'utf8'));
|
|
13
|
+
let wrapfullyConfig = {};
|
|
14
|
+
|
|
15
|
+
try {
|
|
16
|
+
wrapfullyConfig = JSON.parse(await fs.readFile(wrapfullyPath, 'utf8'));
|
|
17
|
+
} catch (err) {
|
|
18
|
+
if (/** @type {NodeJS.ErrnoException} */ (err).code !== 'ENOENT') {
|
|
19
|
+
throw err;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
pkg.config = {
|
|
24
|
+
...pkg.config,
|
|
25
|
+
...wrapfullyConfig,
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
return { pkg, wrapfullyConfig };
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* @param {{ server?: string }} wrapfullyConfig
|
|
33
|
+
* @param {string} [cliServer]
|
|
34
|
+
*/
|
|
35
|
+
export function resolveServerUrl(wrapfullyConfig, cliServer) {
|
|
36
|
+
return (
|
|
37
|
+
cliServer
|
|
38
|
+
|| process.env.WRAPFULLY_SERVER
|
|
39
|
+
|| wrapfullyConfig.server
|
|
40
|
+
|| DEFAULT_SERVER
|
|
41
|
+
).replace(/\/?$/, '/');
|
|
42
|
+
}
|
package/lib/node/deploy.js
CHANGED
|
@@ -1,69 +1,52 @@
|
|
|
1
|
-
import axios from 'axios';
|
|
2
|
-
import fs from 'node:fs';
|
|
3
|
-
import
|
|
4
|
-
import
|
|
5
|
-
import
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
* @param {string}
|
|
12
|
-
* @param {string}
|
|
13
|
-
* @param {string}
|
|
14
|
-
* @param {string}
|
|
15
|
-
* @param {
|
|
16
|
-
* @param {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
});
|
|
28
|
-
|
|
29
|
-
archiveStream
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
const cliServer = argv[3];
|
|
54
|
-
const mode = argv[4] ?? 'extract';
|
|
55
|
-
|
|
56
|
-
const { pkg, wrapfullyConfig } = await loadProjectConfig();
|
|
57
|
-
const server = resolveServerUrl(wrapfullyConfig, cliServer);
|
|
58
|
-
const deployFolder = pkg.config?.deployFolder || 'deploy';
|
|
59
|
-
|
|
60
|
-
await send(
|
|
61
|
-
`${pkg.name}-${pkg.version}`,
|
|
62
|
-
JSON.stringify(pkg),
|
|
63
|
-
server,
|
|
64
|
-
builder,
|
|
65
|
-
deployFolder,
|
|
66
|
-
pkg,
|
|
67
|
-
mode,
|
|
68
|
-
);
|
|
69
|
-
}
|
|
1
|
+
import axios from 'axios';
|
|
2
|
+
import fs from 'node:fs';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { pipeline } from 'node:stream/promises';
|
|
5
|
+
import unzipper from 'unzip-stream';
|
|
6
|
+
import { createArchive } from './archive.js';
|
|
7
|
+
import { listHtmlFilesRecursive } from './fs-utils.js';
|
|
8
|
+
import { printBuildReport } from './report.js';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* @param {string} gameId
|
|
12
|
+
* @param {string} contents
|
|
13
|
+
* @param {string} server
|
|
14
|
+
* @param {string} builder
|
|
15
|
+
* @param {string} deployFolder - prebuilt deploy directory
|
|
16
|
+
* @param {{ name: string, version: string }} pkg
|
|
17
|
+
* @param {'extract' | string} mode
|
|
18
|
+
* @param {{ log?: (message: string) => void }} [options]
|
|
19
|
+
*/
|
|
20
|
+
export async function send(gameId, contents, server, builder, deployFolder, pkg, mode = 'extract', options = {}) {
|
|
21
|
+
const log = options.log ?? console.log;
|
|
22
|
+
const destination = mode === 'extract'
|
|
23
|
+
? unzipper.Extract({ path: './output/', concurrency: 1 })
|
|
24
|
+
: fs.createWriteStream(`./output/${pkg.name}-${pkg.version}-${builder}.zip`);
|
|
25
|
+
|
|
26
|
+
const htmlFiles = listHtmlFilesRecursive(deployFolder);
|
|
27
|
+
log(`adaptfully: sending ${htmlFiles.length} HTML file(s) from ${path.resolve(deployFolder)}`);
|
|
28
|
+
|
|
29
|
+
const archiveStream = createArchive(deployFolder, contents);
|
|
30
|
+
const { data } = await axios.post(`${server}${builder}/${gameId}`, archiveStream, {
|
|
31
|
+
maxRedirects: 0,
|
|
32
|
+
responseType: 'stream',
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
archiveStream.on('close', () => {
|
|
36
|
+
log('adaptfully: upload complete');
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
try {
|
|
40
|
+
await pipeline(data, destination);
|
|
41
|
+
} catch (err) {
|
|
42
|
+
if (/** @type {NodeJS.ErrnoException} */ (err).code === 'ECONNREFUSED') {
|
|
43
|
+
console.error(`Cannot connect to Wrapfully server "${server}"`);
|
|
44
|
+
process.exit(1);
|
|
45
|
+
}
|
|
46
|
+
throw err;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if (mode === 'extract') {
|
|
50
|
+
printBuildReport(builder, pkg);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* @param {string} src
|
|
6
|
+
* @param {string} dest
|
|
7
|
+
*/
|
|
8
|
+
export function copyRecursiveSync(src, dest) {
|
|
9
|
+
fs.mkdirSync(dest, { recursive: true });
|
|
10
|
+
|
|
11
|
+
for (const entry of fs.readdirSync(src, { withFileTypes: true })) {
|
|
12
|
+
const srcPath = path.join(src, entry.name);
|
|
13
|
+
const destPath = path.join(dest, entry.name);
|
|
14
|
+
|
|
15
|
+
if (entry.isDirectory()) {
|
|
16
|
+
copyRecursiveSync(srcPath, destPath);
|
|
17
|
+
} else {
|
|
18
|
+
fs.copyFileSync(srcPath, destPath);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* @param {string} dir
|
|
25
|
+
* @returns {string[]}
|
|
26
|
+
*/
|
|
27
|
+
export function listHtmlFilesRecursive(dir) {
|
|
28
|
+
/** @type {string[]} */
|
|
29
|
+
const files = [];
|
|
30
|
+
|
|
31
|
+
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
32
|
+
const fullPath = path.join(dir, entry.name);
|
|
33
|
+
if (entry.isDirectory()) {
|
|
34
|
+
files.push(...listHtmlFilesRecursive(fullPath));
|
|
35
|
+
} else if (entry.name.endsWith('.html')) {
|
|
36
|
+
files.push(fullPath);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return files;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* @param {string} dir
|
|
45
|
+
*/
|
|
46
|
+
export function emptyDirSync(dir) {
|
|
47
|
+
fs.rmSync(dir, { recursive: true, force: true });
|
|
48
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
49
|
+
}
|
package/lib/node/index.js
CHANGED
|
@@ -1,18 +1,20 @@
|
|
|
1
|
-
export { createArchive } from './archive.js';
|
|
2
|
-
export { loadProjectConfig, resolveServerUrl } from './config.js';
|
|
3
|
-
export {
|
|
4
|
-
export {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
1
|
+
export { createArchive } from './archive.js';
|
|
2
|
+
export { loadProjectConfig, resolveServerUrl } from './config.js';
|
|
3
|
+
export { send } from './deploy.js';
|
|
4
|
+
export { adaptfullyFromCli, runAdaptfullyStage } from './pipeline.js';
|
|
5
|
+
export { prebuildPlatform, prebuildOutputDir, resolveHtmlInjections } from './prebuild.js';
|
|
6
|
+
export { getPackageRoot, getRuntimeDir, resolveRuntimeScript } from './paths.js';
|
|
7
|
+
export {
|
|
8
|
+
STANDARD_PLUGINS,
|
|
9
|
+
DEFAULT_BUILDER_PLATFORMS,
|
|
10
|
+
adaptfullyInjectionForPlatform,
|
|
11
|
+
buildAdaptfullyInjection,
|
|
12
|
+
collectRegistrationParts,
|
|
13
|
+
injectAdaptfullyRegistrations,
|
|
14
|
+
resolveBuilderForPlatform,
|
|
15
|
+
resolveCliPlatformAndBuilder,
|
|
16
|
+
resolvePlatformKey,
|
|
17
|
+
resolvePlatformRegistrationsByKey,
|
|
18
|
+
resolveRegistrationAssets,
|
|
19
|
+
} from './registrations.js';
|
|
20
|
+
export { printBuildReport } from './report.js';
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { fileURLToPath } from 'node:url';
|
|
3
|
+
|
|
4
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
5
|
+
const PACKAGE_ROOT = path.resolve(__dirname, '..', '..');
|
|
6
|
+
const RUNTIME_DIR = path.join(PACKAGE_ROOT, 'lib', 'runtime');
|
|
7
|
+
|
|
8
|
+
export function getPackageRoot() {
|
|
9
|
+
return PACKAGE_ROOT;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function getRuntimeDir() {
|
|
13
|
+
return RUNTIME_DIR;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function resolveRuntimeScript(relativePath) {
|
|
17
|
+
return path.join(RUNTIME_DIR, relativePath);
|
|
18
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { loadProjectConfig, resolveServerUrl } from './config.js';
|
|
2
|
+
import { send } from './deploy.js';
|
|
3
|
+
import { prebuildPlatform } from './prebuild.js';
|
|
4
|
+
import { resolveBuilderForPlatform } from './registrations.js';
|
|
5
|
+
|
|
6
|
+
/** @typedef {'prebuild' | 'build' | 'deploy'} AdaptfullyStage */
|
|
7
|
+
|
|
8
|
+
const VALID_STAGES = new Set(['prebuild', 'build', 'deploy']);
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* @param {AdaptfullyStage} stage
|
|
12
|
+
* @param {string} platformKey
|
|
13
|
+
* @param {{ pkg: object, deployFolder: string, server?: string, mode?: string, builder?: string, log?: (message: string) => void, outputRoot?: string }} options
|
|
14
|
+
*/
|
|
15
|
+
export async function runAdaptfullyStage(stage, platformKey, options) {
|
|
16
|
+
if (!VALID_STAGES.has(stage)) {
|
|
17
|
+
throw new Error(`Unknown adaptfully stage "${stage}". Expected: prebuild, build, or deploy.`);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const log = options.log ?? console.log;
|
|
21
|
+
const { pkg, deployFolder } = options;
|
|
22
|
+
|
|
23
|
+
const prebuiltDir = prebuildPlatform(deployFolder, platformKey, pkg, {
|
|
24
|
+
log,
|
|
25
|
+
outputRoot: options.outputRoot,
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
if (stage === 'prebuild') {
|
|
29
|
+
return { prebuiltDir, platformKey };
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const builder = options.builder ?? resolveBuilderForPlatform(platformKey, pkg);
|
|
33
|
+
log(`adaptfully: ${stage} ${platformKey} via Wrapfully builder "${builder}"`);
|
|
34
|
+
|
|
35
|
+
await send(
|
|
36
|
+
`${pkg.name}-${pkg.version}`,
|
|
37
|
+
JSON.stringify(pkg),
|
|
38
|
+
options.server,
|
|
39
|
+
builder,
|
|
40
|
+
prebuiltDir,
|
|
41
|
+
pkg,
|
|
42
|
+
options.mode ?? 'extract',
|
|
43
|
+
{ log },
|
|
44
|
+
);
|
|
45
|
+
|
|
46
|
+
return { prebuiltDir, platformKey, builder };
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* @param {string[]} [argv=process.argv]
|
|
51
|
+
*/
|
|
52
|
+
export async function adaptfullyFromCli(argv = process.argv) {
|
|
53
|
+
const stage = argv[2];
|
|
54
|
+
const platformKey = argv[3];
|
|
55
|
+
const cliServer = argv[4];
|
|
56
|
+
const mode = argv[5] ?? 'extract';
|
|
57
|
+
|
|
58
|
+
if (!stage || !platformKey) {
|
|
59
|
+
throw new Error(
|
|
60
|
+
'Usage: adaptfully <prebuild|build|deploy> <platform> [server] [mode]\n'
|
|
61
|
+
+ ' prebuild Copy deploy/ and apply platform registrations → output/<platform>-prebuild/\n'
|
|
62
|
+
+ ' build prebuild + zip and send to Wrapfully\n'
|
|
63
|
+
+ ' deploy build + platform release when credentials are present (via Wrapfully)',
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const { pkg, wrapfullyConfig } = await loadProjectConfig();
|
|
68
|
+
const server = resolveServerUrl(wrapfullyConfig, cliServer);
|
|
69
|
+
const deployFolder = pkg.config?.deployFolder || 'deploy';
|
|
70
|
+
|
|
71
|
+
return runAdaptfullyStage(/** @type {AdaptfullyStage} */ (stage), platformKey, {
|
|
72
|
+
pkg,
|
|
73
|
+
deployFolder,
|
|
74
|
+
server,
|
|
75
|
+
mode,
|
|
76
|
+
});
|
|
77
|
+
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import {
|
|
4
|
+
adaptfullyInjectionForPlatform,
|
|
5
|
+
injectAdaptfullyRegistrations,
|
|
6
|
+
} from './registrations.js';
|
|
7
|
+
import { copyRecursiveSync, emptyDirSync } from './fs-utils.js';
|
|
8
|
+
|
|
9
|
+
/** @typedef {'prebuild' | 'build' | 'deploy'} AdaptfullyStage */
|
|
10
|
+
|
|
11
|
+
const DEFAULT_HTML_INJECTIONS = ['index.html'];
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* @param {{ config?: { htmlInjections?: string[] } }} pkg
|
|
15
|
+
* @returns {string[]}
|
|
16
|
+
*/
|
|
17
|
+
export function resolveHtmlInjections(pkg) {
|
|
18
|
+
const injections = pkg.config?.htmlInjections;
|
|
19
|
+
if (injections === undefined) {
|
|
20
|
+
return DEFAULT_HTML_INJECTIONS;
|
|
21
|
+
}
|
|
22
|
+
if (!Array.isArray(injections) || injections.length === 0) {
|
|
23
|
+
throw new Error('config.htmlInjections must be a non-empty array of paths relative to the deploy folder');
|
|
24
|
+
}
|
|
25
|
+
for (const entry of injections) {
|
|
26
|
+
if (typeof entry !== 'string' || !entry.length) {
|
|
27
|
+
throw new Error('config.htmlInjections entries must be non-empty strings');
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
return injections;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* @param {string} platformKey
|
|
35
|
+
* @param {{ config?: { platforms?: Record<string, unknown>, outputFolder?: string } }} pkg
|
|
36
|
+
* @param {string} [outputRoot='output']
|
|
37
|
+
*/
|
|
38
|
+
export function prebuildOutputDir(platformKey, pkg, outputRoot = 'output') {
|
|
39
|
+
const outputFolder = pkg.config?.outputFolder || outputRoot;
|
|
40
|
+
return path.resolve(outputFolder, `${platformKey}-prebuild`);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* @param {string} htmlPath
|
|
45
|
+
* @param {string} injection
|
|
46
|
+
*/
|
|
47
|
+
export function injectAdaptfullyIntoHtmlFile(htmlPath, injection) {
|
|
48
|
+
const html = fs.readFileSync(htmlPath, 'utf8');
|
|
49
|
+
const updated = injectAdaptfullyRegistrations(html, injection);
|
|
50
|
+
if (updated !== html) {
|
|
51
|
+
fs.writeFileSync(htmlPath, updated);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* @param {string} deployFolder
|
|
57
|
+
* @param {string} platformKey
|
|
58
|
+
* @param {{ config?: { platforms?: Record<string, { registrations?: Record<string, string> }> } }} pkg
|
|
59
|
+
* @param {{ log?: (message: string) => void, outputRoot?: string }} [options]
|
|
60
|
+
* @returns {string} Absolute path to the prebuild output directory
|
|
61
|
+
*/
|
|
62
|
+
export function prebuildPlatform(deployFolder, platformKey, pkg, options = {}) {
|
|
63
|
+
const log = options.log ?? console.log;
|
|
64
|
+
const source = path.resolve(deployFolder);
|
|
65
|
+
|
|
66
|
+
if (!fs.existsSync(source)) {
|
|
67
|
+
throw new Error(`Deploy folder not found: ${source}`);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const dest = prebuildOutputDir(platformKey, pkg, options.outputRoot);
|
|
71
|
+
log(`adaptfully: prebuild ${platformKey} → ${dest}`);
|
|
72
|
+
|
|
73
|
+
emptyDirSync(dest);
|
|
74
|
+
copyRecursiveSync(source, dest);
|
|
75
|
+
|
|
76
|
+
const injection = adaptfullyInjectionForPlatform(platformKey, pkg, { log });
|
|
77
|
+
if (injection) {
|
|
78
|
+
for (const relativePath of resolveHtmlInjections(pkg)) {
|
|
79
|
+
const htmlPath = path.join(dest, relativePath);
|
|
80
|
+
if (!fs.existsSync(htmlPath)) {
|
|
81
|
+
throw new Error(`htmlInjections file not found in deploy output: ${relativePath}`);
|
|
82
|
+
}
|
|
83
|
+
log(`adaptfully: inject ${relativePath}`);
|
|
84
|
+
injectAdaptfullyIntoHtmlFile(htmlPath, injection);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
log(`adaptfully: prebuild complete (${platformKey})`);
|
|
89
|
+
return dest;
|
|
90
|
+
}
|