@makefully/adaptfully 3.8.0 → 3.8.2
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 +12 -0
- package/lib/node/archive.js +68 -24
- package/lib/node/artifacts.js +22 -1
- package/lib/node/deploy.js +12 -5
- package/lib/node/index.js +1 -1
- package/lib/node/pipeline.js +8 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,18 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project are documented in this file.
|
|
4
4
|
|
|
5
|
+
## 3.8.2 — 2026-07-14
|
|
6
|
+
|
|
7
|
+
### Fixed
|
|
8
|
+
|
|
9
|
+
- **Release/deploy zips** resolve `assets/meta` and deployment credential dirs to absolute POSIX paths before `archiver.directory()`, and log which deployments were packaged (or skipped). Prevents empty `meta/deployments` payloads that made Wrapfully skip Steam.
|
|
10
|
+
|
|
11
|
+
## 3.8.1 — 2026-07-14
|
|
12
|
+
|
|
13
|
+
### Fixed
|
|
14
|
+
|
|
15
|
+
- **Extract mode** clears stale `output/artifacts/`, `wrapfully-build.json`, and `wrapfully-status.json` before unpacking a Wrapfully response so nested `artifacts/artifacts` leftovers cannot accumulate across runs.
|
|
16
|
+
|
|
5
17
|
## 3.8.0 — 2026-07-10
|
|
6
18
|
|
|
7
19
|
### Changed
|
package/lib/node/archive.js
CHANGED
|
@@ -2,57 +2,98 @@ import archiver from 'archiver';
|
|
|
2
2
|
import fs from 'node:fs';
|
|
3
3
|
import path from 'node:path';
|
|
4
4
|
|
|
5
|
-
const
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
const
|
|
6
|
+
META_DIR = 'assets/meta',
|
|
7
|
+
DEPLOYMENTS_DIRNAME = 'deployments',
|
|
8
|
+
PUBLISH_DIRNAME = 'publish';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* @param {string} dirPath
|
|
12
|
+
* @returns {string}
|
|
13
|
+
*/
|
|
14
|
+
function toPosixDir(dirPath) {
|
|
15
|
+
return `${path.resolve(dirPath).replace(/\\/g, '/').replace(/\/?$/, '')}/`;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* @param {import('archiver').Archiver} zip
|
|
20
|
+
* @param {string} sourceDir Absolute or relative directory to pack
|
|
21
|
+
* @param {string} zipPrefix Zip entry prefix without trailing slash
|
|
22
|
+
*/
|
|
23
|
+
function appendDirectory(zip, sourceDir, zipPrefix) {
|
|
24
|
+
const
|
|
25
|
+
source = toPosixDir(sourceDir),
|
|
26
|
+
prefix = `${zipPrefix.replace(/\\/g, '/').replace(/\/?$/, '')}/`;
|
|
27
|
+
zip.directory(source, prefix);
|
|
28
|
+
}
|
|
8
29
|
|
|
9
30
|
/**
|
|
10
31
|
* @param {import('archiver').Archiver} zip
|
|
11
32
|
* @param {string} [publishDir] Single deployment folder
|
|
12
33
|
* @param {string[]} [deploymentDirs] Multiple deployment folders for release
|
|
34
|
+
* @param {{ log?: (message: string) => void }} [options]
|
|
13
35
|
*/
|
|
14
|
-
function appendMeta(zip, publishDir, deploymentDirs = []) {
|
|
15
|
-
|
|
36
|
+
function appendMeta(zip, publishDir, deploymentDirs = [], options = {}) {
|
|
37
|
+
const
|
|
38
|
+
log = options.log ?? (() => {}),
|
|
39
|
+
metaDir = path.resolve(META_DIR);
|
|
40
|
+
|
|
41
|
+
if (!fs.existsSync(metaDir)) {
|
|
42
|
+
log(`adaptfully: meta dir missing at ${metaDir}; skipping credentials`);
|
|
16
43
|
return;
|
|
17
44
|
}
|
|
18
45
|
|
|
19
|
-
const deploymentsRoot = path.join(
|
|
46
|
+
const deploymentsRoot = path.join(metaDir, DEPLOYMENTS_DIRNAME);
|
|
20
47
|
|
|
21
48
|
if (!fs.existsSync(deploymentsRoot)) {
|
|
22
|
-
zip
|
|
49
|
+
appendDirectory(zip, metaDir, 'meta');
|
|
23
50
|
return;
|
|
24
51
|
}
|
|
25
52
|
|
|
26
|
-
for (const entry of fs.readdirSync(
|
|
53
|
+
for (const entry of fs.readdirSync(metaDir, { withFileTypes: true })) {
|
|
27
54
|
if (entry.name === DEPLOYMENTS_DIRNAME || entry.name === PUBLISH_DIRNAME) {
|
|
28
55
|
continue;
|
|
29
56
|
}
|
|
30
57
|
|
|
31
|
-
const fullPath = path.join(
|
|
58
|
+
const fullPath = path.join(metaDir, entry.name);
|
|
32
59
|
if (entry.isDirectory()) {
|
|
33
|
-
zip
|
|
60
|
+
appendDirectory(zip, fullPath, `meta/${entry.name}`);
|
|
34
61
|
} else {
|
|
35
62
|
zip.file(fullPath, { name: `meta/${entry.name}` });
|
|
36
63
|
}
|
|
37
64
|
}
|
|
38
65
|
|
|
39
66
|
if (publishDir && fs.existsSync(publishDir)) {
|
|
40
|
-
zip
|
|
67
|
+
appendDirectory(zip, publishDir, `meta/${PUBLISH_DIRNAME}`);
|
|
68
|
+
log(`adaptfully: packaged meta/${PUBLISH_DIRNAME} from ${path.resolve(publishDir)}`);
|
|
41
69
|
return;
|
|
42
70
|
}
|
|
43
71
|
|
|
72
|
+
const packaged = [];
|
|
73
|
+
|
|
44
74
|
for (const deploymentDir of deploymentDirs) {
|
|
45
|
-
|
|
75
|
+
const resolved = path.resolve(deploymentDir);
|
|
76
|
+
if (!fs.existsSync(resolved)) {
|
|
77
|
+
log(`adaptfully: skipping missing deployment dir ${resolved}`);
|
|
46
78
|
continue;
|
|
47
79
|
}
|
|
48
80
|
|
|
49
|
-
const deploymentKey = path.basename(
|
|
50
|
-
zip
|
|
81
|
+
const deploymentKey = path.basename(resolved);
|
|
82
|
+
appendDirectory(zip, resolved, `meta/${DEPLOYMENTS_DIRNAME}/${deploymentKey}`);
|
|
83
|
+
packaged.push(deploymentKey);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
if (packaged.length) {
|
|
87
|
+
log(`adaptfully: packaged deployments: ${packaged.join(', ')}`);
|
|
88
|
+
} else if (deploymentDirs.length) {
|
|
89
|
+
log('adaptfully: WARNING no deployment credential folders were packaged');
|
|
51
90
|
}
|
|
52
91
|
}
|
|
53
92
|
|
|
54
93
|
function createZipStream(deployFolder, contents, options = {}) {
|
|
55
|
-
const
|
|
94
|
+
const
|
|
95
|
+
zip = archiver('zip', { zlib: { level: 0 } }),
|
|
96
|
+
log = options.log ?? console.log;
|
|
56
97
|
|
|
57
98
|
zip.on('warning', (err) => {
|
|
58
99
|
if (err.code === 'ENOENT') {
|
|
@@ -75,11 +116,11 @@ function createZipStream(deployFolder, contents, options = {}) {
|
|
|
75
116
|
}, { prefix: 'deploy' });
|
|
76
117
|
zip.append(options.indexHtml, { name: 'deploy/index.html' });
|
|
77
118
|
} else {
|
|
78
|
-
zip
|
|
79
|
-
zip.file(
|
|
119
|
+
appendDirectory(zip, deployFolder, 'deploy');
|
|
120
|
+
zip.file(path.resolve(deployFolder, 'index.html'), { name: 'deploy/index.html' });
|
|
80
121
|
}
|
|
81
122
|
|
|
82
|
-
appendMeta(zip, options.publishDir, options.deploymentDirs);
|
|
123
|
+
appendMeta(zip, options.publishDir, options.deploymentDirs, { log });
|
|
83
124
|
zip.append(contents, { name: 'package.json' });
|
|
84
125
|
zip.finalize();
|
|
85
126
|
|
|
@@ -91,7 +132,7 @@ function createZipStream(deployFolder, contents, options = {}) {
|
|
|
91
132
|
*
|
|
92
133
|
* @param {string} deployFolder
|
|
93
134
|
* @param {string} contents
|
|
94
|
-
* @param {{ indexHtml?: string, publishDir?: string, deploymentDirs?: string[] }} [options]
|
|
135
|
+
* @param {{ indexHtml?: string, publishDir?: string, deploymentDirs?: string[], log?: (message: string) => void }} [options]
|
|
95
136
|
*/
|
|
96
137
|
export function createSourceArchive(deployFolder, contents, options = {}) {
|
|
97
138
|
return createZipStream(deployFolder, contents, options);
|
|
@@ -110,12 +151,15 @@ export function createArchive(deployFolder, contents, options = {}) {
|
|
|
110
151
|
* @param {string} artifactPath
|
|
111
152
|
* @param {string} publishDir
|
|
112
153
|
* @param {string} [contents]
|
|
154
|
+
* @param {{ log?: (message: string) => void }} [options]
|
|
113
155
|
*/
|
|
114
|
-
export function createDeployArchive(artifactPath, publishDir, contents) {
|
|
115
|
-
const
|
|
156
|
+
export function createDeployArchive(artifactPath, publishDir, contents, options = {}) {
|
|
157
|
+
const
|
|
158
|
+
zip = archiver('zip', { zlib: { level: 0 } }),
|
|
159
|
+
log = options.log ?? console.log;
|
|
116
160
|
|
|
117
|
-
zip.directory(
|
|
118
|
-
appendMeta(zip, publishDir);
|
|
161
|
+
zip.directory(toPosixDir(artifactPath), false);
|
|
162
|
+
appendMeta(zip, publishDir, [], { log });
|
|
119
163
|
|
|
120
164
|
if (contents) {
|
|
121
165
|
zip.append(contents, { name: 'package.json' });
|
|
@@ -131,7 +175,7 @@ export function createDeployArchive(artifactPath, publishDir, contents) {
|
|
|
131
175
|
* @param {string} deployFolder
|
|
132
176
|
* @param {string} contents
|
|
133
177
|
* @param {string[]} deploymentDirs
|
|
134
|
-
* @param {{ indexHtml?: string }} [options]
|
|
178
|
+
* @param {{ indexHtml?: string, log?: (message: string) => void }} [options]
|
|
135
179
|
*/
|
|
136
180
|
export function createReleaseArchive(deployFolder, contents, deploymentDirs, options = {}) {
|
|
137
181
|
return createZipStream(deployFolder, contents, {
|
package/lib/node/artifacts.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
|
|
4
|
-
const
|
|
4
|
+
const
|
|
5
|
+
MANIFEST_NAME = 'wrapfully-build.json',
|
|
6
|
+
STATUS_NAME = 'wrapfully-status.json';
|
|
5
7
|
|
|
6
8
|
/**
|
|
7
9
|
* Directory where build responses are extracted (contains wrapfully-build.json).
|
|
@@ -14,6 +16,25 @@ export function buildOutputDir(pkg, outputRoot = 'output') {
|
|
|
14
16
|
return path.resolve(outputFolder);
|
|
15
17
|
}
|
|
16
18
|
|
|
19
|
+
/**
|
|
20
|
+
* Remove prior Wrapfully extract artifacts so zip responses do not stack
|
|
21
|
+
* nested `artifacts/` directories across runs.
|
|
22
|
+
*
|
|
23
|
+
* @param {string} [outputRoot='output']
|
|
24
|
+
*/
|
|
25
|
+
export function clearStaleBuildExtract(outputRoot = 'output') {
|
|
26
|
+
const root = path.resolve(outputRoot);
|
|
27
|
+
const stalePaths = [
|
|
28
|
+
path.join(root, 'artifacts'),
|
|
29
|
+
path.join(root, MANIFEST_NAME),
|
|
30
|
+
path.join(root, STATUS_NAME),
|
|
31
|
+
];
|
|
32
|
+
|
|
33
|
+
for (const stalePath of stalePaths) {
|
|
34
|
+
fs.rmSync(stalePath, { recursive: true, force: true });
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
17
38
|
/**
|
|
18
39
|
* Resolve the artifact directory from a prior `adaptfully build` (or compatible zip extract).
|
|
19
40
|
*
|
package/lib/node/deploy.js
CHANGED
|
@@ -4,6 +4,7 @@ import path from 'node:path';
|
|
|
4
4
|
import { pipeline } from 'node:stream/promises';
|
|
5
5
|
import unzipper from 'unzip-stream';
|
|
6
6
|
import { createDeployArchive, createReleaseArchive, createSourceArchive } from './archive.js';
|
|
7
|
+
import { clearStaleBuildExtract } from './artifacts.js';
|
|
7
8
|
import { listHtmlFilesRecursive } from './fs-utils.js';
|
|
8
9
|
import { printBuildReport } from './report.js';
|
|
9
10
|
|
|
@@ -47,9 +48,15 @@ function resolveWrapfullyUrl(server, stage, family, gameId, platformKey, deploym
|
|
|
47
48
|
export async function send(gameId, contents, server, stage, family, deployFolder, pkg, mode = 'extract', options = {}) {
|
|
48
49
|
const log = options.log ?? console.log;
|
|
49
50
|
const platformKey = options.platformKey ?? family;
|
|
51
|
+
const outputRoot = pkg.config?.outputFolder || 'output';
|
|
52
|
+
|
|
53
|
+
if (mode === 'extract') {
|
|
54
|
+
clearStaleBuildExtract(outputRoot);
|
|
55
|
+
}
|
|
56
|
+
|
|
50
57
|
const destination = mode === 'extract'
|
|
51
|
-
? unzipper.Extract({ path:
|
|
52
|
-
: fs.createWriteStream(
|
|
58
|
+
? unzipper.Extract({ path: `${outputRoot}/`, concurrency: 1 })
|
|
59
|
+
: fs.createWriteStream(`${outputRoot}/${pkg.name}-${pkg.version}-${stage}-${family}.zip`);
|
|
53
60
|
|
|
54
61
|
let archiveStream;
|
|
55
62
|
|
|
@@ -60,11 +67,11 @@ export async function send(gameId, contents, server, stage, family, deployFolder
|
|
|
60
67
|
if (!options.deploymentKey) {
|
|
61
68
|
throw new Error('deploy stage requires options.deploymentKey');
|
|
62
69
|
}
|
|
63
|
-
archiveStream = createDeployArchive(options.artifactPath, options.publishDir, contents);
|
|
70
|
+
archiveStream = createDeployArchive(options.artifactPath, options.publishDir, contents, { log });
|
|
64
71
|
} else if (stage === 'release') {
|
|
65
|
-
archiveStream = createReleaseArchive(deployFolder, contents, options.deploymentDirs ?? []);
|
|
72
|
+
archiveStream = createReleaseArchive(deployFolder, contents, options.deploymentDirs ?? [], { log });
|
|
66
73
|
} else {
|
|
67
|
-
archiveStream = createSourceArchive(deployFolder, contents);
|
|
74
|
+
archiveStream = createSourceArchive(deployFolder, contents, { log });
|
|
68
75
|
}
|
|
69
76
|
|
|
70
77
|
const url = resolveWrapfullyUrl(server, stage, family, gameId, platformKey, options.deploymentKey);
|
package/lib/node/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { buildOutputDir, resolveBuildArtifactDir } from './artifacts.js';
|
|
1
|
+
export { buildOutputDir, clearStaleBuildExtract, resolveBuildArtifactDir } from './artifacts.js';
|
|
2
2
|
export { createArchive, createDeployArchive, createReleaseArchive, createSourceArchive } from './archive.js';
|
|
3
3
|
export { loadProjectConfig, resolveServerUrl } from './config.js';
|
|
4
4
|
export { send } from './deploy.js';
|
package/lib/node/pipeline.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
1
2
|
import { loadProjectConfig, resolveServerUrl } from './config.js';
|
|
2
3
|
import { send } from './deploy.js';
|
|
3
4
|
import { resolveBuildArtifactDir } from './artifacts.js';
|
|
@@ -73,6 +74,12 @@ export async function runAdaptfullyStage(stage, platformKey, options) {
|
|
|
73
74
|
|
|
74
75
|
log(`adaptfully: ${stage} ${platformKey} → ${buildSpec.family} (${buildSpec.targets.join(', ')})`);
|
|
75
76
|
|
|
77
|
+
log(
|
|
78
|
+
`adaptfully: release deployments → ${
|
|
79
|
+
deploymentDirs.map((dir) => path.resolve(dir)).join(', ') || '(none)'
|
|
80
|
+
}`,
|
|
81
|
+
);
|
|
82
|
+
|
|
76
83
|
await send(
|
|
77
84
|
gameId,
|
|
78
85
|
contents,
|
|
@@ -85,7 +92,7 @@ export async function runAdaptfullyStage(stage, platformKey, options) {
|
|
|
85
92
|
{
|
|
86
93
|
log,
|
|
87
94
|
platformKey,
|
|
88
|
-
deploymentDirs,
|
|
95
|
+
deploymentDirs: deploymentDirs.map((dir) => path.resolve(dir)),
|
|
89
96
|
},
|
|
90
97
|
);
|
|
91
98
|
|