@makefully/adaptfully 3.8.1 → 3.9.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/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.9.0 — 2026-07-15
6
+
7
+ ### Added
8
+
9
+ - **`pwa` Wrapfully family** — `resolveFamilyFromTarget('pwa')` / `resolveBuildSpec` return family `pwa` when `builder: "pwa"`, including with `packager: "web"`.
10
+
11
+ ## 3.8.2 — 2026-07-14
12
+
13
+ ### Fixed
14
+
15
+ - **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.
16
+
5
17
  ## 3.8.1 — 2026-07-14
6
18
 
7
19
  ### Fixed
@@ -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 META_DIR = 'assets/meta';
6
- const DEPLOYMENTS_DIRNAME = 'deployments';
7
- const PUBLISH_DIRNAME = 'publish';
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
- if (!fs.existsSync(META_DIR)) {
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(META_DIR, DEPLOYMENTS_DIRNAME);
46
+ const deploymentsRoot = path.join(metaDir, DEPLOYMENTS_DIRNAME);
20
47
 
21
48
  if (!fs.existsSync(deploymentsRoot)) {
22
- zip.directory(`${META_DIR}/`, 'meta');
49
+ appendDirectory(zip, metaDir, 'meta');
23
50
  return;
24
51
  }
25
52
 
26
- for (const entry of fs.readdirSync(META_DIR, { withFileTypes: true })) {
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(META_DIR, entry.name);
58
+ const fullPath = path.join(metaDir, entry.name);
32
59
  if (entry.isDirectory()) {
33
- zip.directory(`${fullPath}/`, `meta/${entry.name}`);
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.directory(`${publishDir}/`, `meta/${PUBLISH_DIRNAME}`);
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
- if (!fs.existsSync(deploymentDir)) {
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(deploymentDir);
50
- zip.directory(`${deploymentDir}/`, `meta/${DEPLOYMENTS_DIRNAME}/${deploymentKey}`);
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 zip = archiver('zip', { zlib: { level: 0 } });
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.directory(`${deployFolder}/`, 'deploy');
79
- zip.file(`${deployFolder}/index.html`, { name: 'deploy/index.html' });
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 zip = archiver('zip', { zlib: { level: 0 } });
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(`${artifactPath}/`, false);
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, {
@@ -1,8 +1,9 @@
1
1
  import fs from 'node:fs';
2
2
  import path from 'node:path';
3
3
 
4
- const MANIFEST_NAME = 'wrapfully-build.json';
5
- const STATUS_NAME = 'wrapfully-status.json';
4
+ const
5
+ MANIFEST_NAME = 'wrapfully-build.json',
6
+ STATUS_NAME = 'wrapfully-status.json';
6
7
 
7
8
  /**
8
9
  * Directory where build responses are extracted (contains wrapfully-build.json).
@@ -67,11 +67,11 @@ export async function send(gameId, contents, server, stage, family, deployFolder
67
67
  if (!options.deploymentKey) {
68
68
  throw new Error('deploy stage requires options.deploymentKey');
69
69
  }
70
- archiveStream = createDeployArchive(options.artifactPath, options.publishDir, contents);
70
+ archiveStream = createDeployArchive(options.artifactPath, options.publishDir, contents, { log });
71
71
  } else if (stage === 'release') {
72
- archiveStream = createReleaseArchive(deployFolder, contents, options.deploymentDirs ?? []);
72
+ archiveStream = createReleaseArchive(deployFolder, contents, options.deploymentDirs ?? [], { log });
73
73
  } else {
74
- archiveStream = createSourceArchive(deployFolder, contents);
74
+ archiveStream = createSourceArchive(deployFolder, contents, { log });
75
75
  }
76
76
 
77
77
  const url = resolveWrapfullyUrl(server, stage, family, gameId, platformKey, options.deploymentKey);
@@ -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
 
@@ -355,6 +355,9 @@ export function resolveFamilyFromTarget(target) {
355
355
  if (CORDOVA_TARGETS.has(target)) {
356
356
  return 'cordova';
357
357
  }
358
+ if (target === 'pwa') {
359
+ return 'pwa';
360
+ }
358
361
  if (target === 'webapp' || target === 'web') {
359
362
  return 'webapp';
360
363
  }
@@ -369,6 +372,10 @@ export function resolveFamilyFromTarget(target) {
369
372
  * @param {string} [packager]
370
373
  */
371
374
  export function resolveFamily(targets, packager) {
375
+ if (targets.length === 1 && targets[0] === 'pwa') {
376
+ return 'pwa';
377
+ }
378
+
372
379
  if (packager === 'electron') {
373
380
  return 'electron';
374
381
  }
@@ -382,7 +389,7 @@ export function resolveFamily(targets, packager) {
382
389
  return families[0];
383
390
  }
384
391
 
385
- if (targets.length === 1 && targets[0] === 'webapp') {
392
+ if (targets.length === 1 && (targets[0] === 'webapp' || targets[0] === 'web')) {
386
393
  return 'webapp';
387
394
  }
388
395
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@makefully/adaptfully",
3
- "version": "3.8.1",
3
+ "version": "3.9.0",
4
4
  "description": "Platform abstraction and Wrapfully deploy client for Makefully games",
5
5
  "type": "module",
6
6
  "main": "./lib/node/index.js",