@makefully/adaptfully 2.1.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 ADDED
@@ -0,0 +1,64 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project are documented in this file.
4
+
5
+ ## 2.1.0 — 2026-06-15
6
+
7
+ ### Changed
8
+
9
+ - Node tooling is now full ESM (`import`/`export`) with no `.cjs` / `.mjs` split.
10
+ - Deploy logic split into focused modules: `archive.js`, `config.js`, `deploy.js`, `report.js`.
11
+ - Runtime uses ES classes, private fields, optional chaining, and shared `auth/_helpers.js`.
12
+ - Minimum Node version raised to 18; dependencies updated (`archiver` 7, `axios` 1.7).
13
+
14
+ ## 2.0.0 — 2026-06-15
15
+
16
+ ### Added
17
+
18
+ - **Adaptfully** runtime library: `adaptfully.register()` / `adaptfully.get()` for platform services.
19
+ - Auth plugins: Google (`adaptfully.auth.Google`), Steam (`adaptfully.auth.Steam`), and dev (`adaptfully.auth.Dev`).
20
+ - `Platform` wrapper for uniform auth API across deployment channels.
21
+ - Node build helpers: `getAuthScriptsForChannel()`, `authRegistrationScript()`, `filterIncludesForBuildChannel()`, and related exports.
22
+ - Programmatic deploy API exported from `lib/node/deploy.js`.
23
+
24
+ ### Changed
25
+
26
+ - Package renamed from `@makefully/wrapfully-client` to `@makefully/adaptfully`.
27
+ - Deploy CLI moved to `bin/wrapfully-deploy.js`; root `deploy.js` remains as a compatibility shim.
28
+
29
+ ## 1.2.0 — 2026-06-11
30
+
31
+ ### Added
32
+
33
+ - Documentation for Electron debug builders: `win-dev`, `mac-dev`, `linux-dev`, and `steam-dev`.
34
+
35
+ ## 1.1.2 — 2026-06-12
36
+
37
+ ### Fixed
38
+
39
+ - npm trusted publishing workflow: upgrade npm explicitly, unset stale `NODE_AUTH_TOKEN`, and use `https://` repository URL format required by OIDC.
40
+
41
+ ## 1.1.1 — 2026-06-11
42
+
43
+ ### Added
44
+
45
+ - npm trusted publishing workflow (`.github/workflows/publish.yml`) with OIDC — no `NPM_TOKEN` required.
46
+ - `PUBLISHING.md` maintainer guide; publishes automatically on version bumps to `main`.
47
+
48
+ ## 1.1.0 — 2026-06-11
49
+
50
+ ### Added
51
+
52
+ - Reads `wrapfully-status.json` from `./output/` after extraction and prints build events to the console.
53
+ - Exits with code 1 when the server reports build errors, so CI and scripts can detect failures.
54
+ - Icons documentation in README (1536×1536 layered PNG requirements).
55
+ - Documentation for Steam cross-platform routing and credential relay between build servers.
56
+
57
+ ### Changed
58
+
59
+ - Deploy waits for the response stream to finish before reporting build status.
60
+ - Legacy `{name}-{version}-{builder}.txt` status files are still printed when `wrapfully-status.json` is absent.
61
+
62
+ ## 1.0.1
63
+
64
+ Initial published client with zip-and-post deploy flow.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) Makefully Studios
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,430 @@
1
+ # Adaptfully
2
+
3
+ Platform abstraction and Wrapfully deploy client for Makefully games.
4
+
5
+ - **Adaptfully runtime** — shared auth and platform services via `adaptfully.register()` / `adaptfully.get()`
6
+ - **Wrapfully deploy** — zip-and-post CLI for building desktop, mobile, and Steam packages
7
+
8
+ ## Install
9
+
10
+ ```bash
11
+ npm install @makefully/adaptfully
12
+ ```
13
+
14
+ Maintainers: see [PUBLISHING.md](PUBLISHING.md) for npm trusted publishing setup.
15
+
16
+ ## Adaptfully runtime
17
+
18
+ Games register platform services before load and retrieve them in-game. Auth is selected at **build time** by the game's build tooling — the game never chooses Google vs Steam directly.
19
+
20
+ ```javascript
21
+ // Set by the build (before account.js loads):
22
+ adaptfully.register('auth', adaptfully.auth.Google);
23
+
24
+ // In-game:
25
+ var platform = adaptfully.get('auth');
26
+ platform.login(function (result) { /* ... */ });
27
+ ```
28
+
29
+ ### Auth plugins
30
+
31
+ | Plugin | Registration | Used for |
32
+ |--------|--------------|----------|
33
+ | `adaptfully.auth.Google` | `adaptfully.register('auth', adaptfully.auth.Google)` | Web, Android, iOS |
34
+ | `adaptfully.auth.Steam` | `adaptfully.register('auth', adaptfully.auth.Steam)` | Steam / Electron |
35
+ | `adaptfully.auth.Dev` | `adaptfully.register('auth', adaptfully.auth.Dev)` | Local dev (test user) |
36
+
37
+ Games can register shared dependencies before auth:
38
+
39
+ ```javascript
40
+ adaptfully.register('storage', myStorage);
41
+ adaptfully.register('config', {
42
+ googleClientId: '...',
43
+ googleTokenKey: 'mygame_google_token',
44
+ apiBase: 'https://api.example.com/',
45
+ });
46
+ ```
47
+
48
+ ### Node build helpers
49
+
50
+ ```javascript
51
+ import {
52
+ getAuthScriptsForChannel,
53
+ authRegistrationScript,
54
+ filterIncludesForBuildChannel,
55
+ extScriptsForBuildChannel,
56
+ } from '@makefully/adaptfully';
57
+ ```
58
+
59
+ `getAuthScriptsForChannel('web')` returns ordered runtime script paths. `authRegistrationScript('steam')` returns the inline registration snippet for that channel.
60
+
61
+ ---
62
+
63
+ ## Wrapfully deploy
64
+
65
+ Zips your web build and configuration, POSTs them to a Wrapfully build server, and saves the platform build artifacts it returns to `./output/`.
66
+
67
+ ## Quick start
68
+
69
+ 1. Build your web app into a deploy folder (default: `./deploy/`, must include `index.html`).
70
+ 2. Add build configuration to `package.json` (see [Configuration](#configuration)).
71
+ 3. Add icons and any signing credentials under `./assets/meta/`.
72
+ 4. Deploy to your build server:
73
+
74
+ ```bash
75
+ npx wrapfully-deploy android http://build.example.com:9630/
76
+ ```
77
+
78
+ Build artifacts are written to `./output/`.
79
+
80
+ ## Usage
81
+
82
+ Run from your project root:
83
+
84
+ ```bash
85
+ npx wrapfully-deploy [builder] [server] [mode]
86
+ ```
87
+
88
+ | Argument | Default | Description |
89
+ |----------|---------|-------------|
90
+ | `builder` | `all` | Build target (see [Builders](#builders)). **Must be a valid builder name** — `all` is not a valid endpoint; always pass a platform. |
91
+ | `server` | see below | Base URL of the build server |
92
+ | `mode` | `extract` | `extract` unpacks the response zip into `./output/`; any other value saves `./output/{name}-{version}-{builder}.zip` |
93
+
94
+ Examples:
95
+
96
+ ```bash
97
+ # Android release build
98
+ npx wrapfully-deploy android http://build.example.com:9630/
99
+
100
+ # Mac build using server from environment variable
101
+ export WRAPFULLY_SERVER=http://build.example.com:9630/
102
+ npx wrapfully-deploy mac
103
+
104
+ # Save the response as a zip instead of extracting
105
+ npx wrapfully-deploy win http://build.example.com:9630/ zip
106
+ ```
107
+
108
+ Add scripts to your project's `package.json`:
109
+
110
+ ```json
111
+ {
112
+ "scripts": {
113
+ "deploy:android": "wrapfully-deploy android",
114
+ "deploy:mac": "wrapfully-deploy mac"
115
+ }
116
+ }
117
+ ```
118
+
119
+ Set `WRAPFULLY_SERVER` or a `server` field in `wrapfully.json` so scripts do not need the address on every invocation.
120
+
121
+ ### Server address
122
+
123
+ The server URL is resolved in this order:
124
+
125
+ 1. CLI argument
126
+ 2. `WRAPFULLY_SERVER` environment variable
127
+ 3. `server` field in `wrapfully.json`
128
+ 4. `http://localhost:9630/`
129
+
130
+ Keep server addresses and credentials out of version control — use environment variables or a gitignored `wrapfully.json`.
131
+
132
+ ## What gets sent
133
+
134
+ The client POSTs a zip stream to:
135
+
136
+ ```
137
+ {server}{builder}/{name}-{version}
138
+ ```
139
+
140
+ For example, a project named `mygame` at version `1.2.0` with builder `android`:
141
+
142
+ ```
143
+ http://build.example.com:9630/android/mygame-1.2.0
144
+ ```
145
+
146
+ The server extracts the zip, reads the embedded `package.json`, runs the build for that platform, and streams a zip of artifacts back to the client.
147
+
148
+ ### Zip contents
149
+
150
+ | Archive path | Source on disk | Purpose |
151
+ |--------------|----------------|---------|
152
+ | `deploy/` | `{deployFolder}/` (default `./deploy/`) | Built web app (HTML, JS, assets) |
153
+ | `deploy/index.html` | `{deployFolder}/index.html` | Entry point (also included via the directory) |
154
+ | `meta/` | `./assets/meta/` (if present) | Icons, signing keys, and publish credentials |
155
+ | `package.json` | project root | Merged `package.json` + `wrapfully.json` config |
156
+
157
+ ### Project layout
158
+
159
+ ```
160
+ mygame/
161
+ ├── package.json # npm metadata + config block (see below)
162
+ ├── wrapfully.json # optional — merged into config
163
+ ├── deploy/ # built web app (or set deployFolder in config)
164
+ │ └── index.html
165
+ └── assets/
166
+ └── meta/ # packaged as meta/ in the zip
167
+ ├── icon-foreground.png
168
+ ├── icon-background.png
169
+ └── publish/ # platform signing & deploy credentials
170
+ ├── build.json
171
+ ├── android/
172
+ ├── apple.json
173
+ └── ...
174
+ ```
175
+
176
+ Icons (`icon-foreground.png`, `icon-background.png`) are required for mobile, desktop, and Steam builds.
177
+
178
+ ### Icons
179
+
180
+ Place two layered PNG files in `./assets/meta/` (packaged as `meta/` in the zip):
181
+
182
+ | File | Purpose |
183
+ |------|---------|
184
+ | `icon-foreground.png` | Foreground layer (typically the character or subject) |
185
+ | `icon-background.png` | Background layer (typically the scene or environment) |
186
+
187
+ The build server composites the foreground over the background, applies a binding/logo overlay, and generates the icon sizes each platform needs.
188
+
189
+ **Recommended format:** 1536×1536 pixel square PNGs for both files. Images with other dimensions are scaled to 1536×1536 automatically, but matching the target size produces the sharpest results.
190
+
191
+ ## Configuration
192
+
193
+ Build settings are read from `package.json`. The client merges any `wrapfully.json` fields into `package.json`'s `config` object before sending.
194
+
195
+ ### `package.json`
196
+
197
+ Standard npm fields (`name`, `version`, `description`) are used directly. Add a `config` block:
198
+
199
+ ```json
200
+ {
201
+ "name": "mygame",
202
+ "version": "1.2.0",
203
+ "description": "My game",
204
+ "config": {
205
+ "title": "My Game",
206
+ "packageName": "com.example.mygame",
207
+ "publisherDisplayName": "Example Games",
208
+ "publisherFullName": "Example Games LLC",
209
+ "publisherWebsite": "https://example.com",
210
+ "publisherEmailAddress": "hello@example.com",
211
+ "scope": "https://example.com/games/",
212
+ "themeColor": "#1a1a2e",
213
+ "twitterId": "@examplegames",
214
+ "steamId": 1234567,
215
+ "properties": [
216
+ { "tag": "plugin", "name": "cordova-plugin-inappbrowser" },
217
+ { "tag": "allow-navigation", "href": "*" }
218
+ ]
219
+ }
220
+ }
221
+ ```
222
+
223
+ | Field | Used by | Description |
224
+ |-------|---------|-------------|
225
+ | `title` | All | Display name shown in stores and app shells |
226
+ | `packageName` | Cordova, Electron, UWP | Reverse-DNS identifier (`com.company.game`) |
227
+ | `publisherDisplayName` | Cordova, Electron, web | Short publisher name |
228
+ | `publisherFullName` | Electron | Legal entity name for copyright |
229
+ | `publisherWebsite` | Cordova, web | Company URL |
230
+ | `publisherEmailAddress` | Cordova | Contact email |
231
+ | `scope` | Web/PWA | Base URL scope for the web app |
232
+ | `themeColor` | Cordova, UWP, web | Loading screen / theme color |
233
+ | `twitterId` | Web | Twitter handle for meta tags |
234
+ | `steamId` | Steam | Steam app ID |
235
+ | `properties` | Cordova | Cordova config.xml entries (plugins, allow-navigation, etc.) |
236
+ | `deployFolder` | Client | Deploy directory name (default: `deploy`) |
237
+
238
+ ### `wrapfully.json`
239
+
240
+ Optional. Fields are shallow-merged into `package.json`'s `config`:
241
+
242
+ ```json
243
+ {
244
+ "deployFolder": "dist",
245
+ "server": "http://build.example.com:9630/",
246
+ "title": "My Game",
247
+ "packageName": "com.example.mygame"
248
+ }
249
+ ```
250
+
251
+ Use this to set the server address or override config per environment without editing `package.json`.
252
+
253
+ ## Builders
254
+
255
+ Each builder name becomes a path segment on the server. Some builds require a specific host OS on the server side; composite builders fan out to multiple platforms automatically.
256
+
257
+ | Builder | Output |
258
+ |---------|--------|
259
+ | `android` | Release Android (.aab) |
260
+ | `android-dev` | Debug Android (.apk) |
261
+ | `ios` | Release iOS (.ipa) |
262
+ | `ios-dev` | Debug iOS (.ipa) |
263
+ | `ios-sim` | iOS Simulator (.app) |
264
+ | `mac` | Release Mac (.app) |
265
+ | `mac-dev` | Debug Mac (.app) with DevTools |
266
+ | `win` | Windows portable (.exe) |
267
+ | `win-dev` | Debug Windows portable with DevTools |
268
+ | `linux` | Linux build |
269
+ | `linux-dev` | Debug Linux build with DevTools |
270
+ | `uwp` | Universal Windows Package |
271
+ | `webapp` | Service-worker web app (optionally SFTP deploy) |
272
+ | `steam` | Windows + Mac + Linux, uploads to Steam |
273
+ | `steam-dev` | Debug Windows + Mac + Linux, no Steam upload |
274
+ | `cordova` | Release Android + iOS |
275
+ | `cordova-dev` | Debug Android + iOS |
276
+ | `apple` | Release Mac + iOS |
277
+ | `apple-dev` | Release Mac + debug iOS |
278
+
279
+ For a single platform, pass the specific builder name rather than a composite.
280
+
281
+ ### Platform package requirements
282
+
283
+ Signing keys, provisioning profiles, and store credentials go in `./assets/meta/publish/` on disk (sent as `meta/publish/` in the zip). **These files contain secrets** — add them to `.gitignore` and never commit them to a public repository.
284
+
285
+ #### Android (`android`, `android-dev`)
286
+
287
+ Place keystore files in `assets/meta/publish/android/`. Include `assets/meta/publish/build.json`:
288
+
289
+ ```json
290
+ {
291
+ "android": {
292
+ "debug": {
293
+ "keystore": "./android/debug.keystore",
294
+ "packageType": "apk",
295
+ "storePassword": "android",
296
+ "alias": "androiddebugkey",
297
+ "password": "android",
298
+ "keystoreType": ""
299
+ },
300
+ "release": {
301
+ "keystore": "./android/release.keystore",
302
+ "packageType": "bundle",
303
+ "storePassword": "(your store password)",
304
+ "alias": "(your alias)",
305
+ "password": "(your password)",
306
+ "keystoreType": ""
307
+ }
308
+ }
309
+ }
310
+ ```
311
+
312
+ To deploy to Google Play, also include `assets/meta/publish/google.json`:
313
+
314
+ ```json
315
+ {
316
+ "type": "service_account",
317
+ "project_id": "(your project id)",
318
+ "private_key_id": "(your private key id)",
319
+ "private_key": "(your private key)",
320
+ "client_email": "(your service account email)",
321
+ "client_id": "(your client id)",
322
+ "auth_uri": "https://accounts.google.com/o/oauth2/auth",
323
+ "token_uri": "https://oauth2.googleapis.com/token",
324
+ "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
325
+ "client_x509_cert_url": "(your service account cert URL)"
326
+ }
327
+ ```
328
+
329
+ #### Apple (`ios`, `ios-dev`, `ios-sim`, `mac`, `apple`, `apple-dev`)
330
+
331
+ Include `assets/meta/publish/build.json` with iOS signing settings:
332
+
333
+ ```json
334
+ {
335
+ "ios": {
336
+ "debug": {
337
+ "codeSignIdentity": "iPhone Development",
338
+ "provisioningProfile": "(your development provisioning profile id)",
339
+ "developmentTeam": "(your team id)",
340
+ "packageType": "development",
341
+ "automaticProvisioning": false
342
+ },
343
+ "release": {
344
+ "codeSignIdentity": "iPhone Distribution",
345
+ "provisioningProfile": "(your distribution provisioning profile id)",
346
+ "developmentTeam": "(your team id)",
347
+ "packageType": "app-store",
348
+ "automaticProvisioning": false
349
+ }
350
+ }
351
+ }
352
+ ```
353
+
354
+ To deploy to the App Store, include `assets/meta/publish/apple.json`:
355
+
356
+ ```json
357
+ {
358
+ "category": "(your app's category)",
359
+ "identity": "(your team identity)",
360
+ "username": "(your username)",
361
+ "password": "(your password)"
362
+ }
363
+ ```
364
+
365
+ #### Cordova (`cordova`, `cordova-dev`)
366
+
367
+ Requires the Android and Apple package requirements above.
368
+
369
+ #### Steam (`steam`, `steam-dev`)
370
+
371
+ `steam-dev` builds debug Electron binaries for Windows, Mac, and Linux without uploading to Steam. No `steam.json` credentials are required.
372
+
373
+ For release uploads, include `assets/meta/publish/steam.json`:
374
+
375
+ ```json
376
+ {
377
+ "username": "(your username)",
378
+ "password": "(your password)"
379
+ }
380
+ ```
381
+
382
+ Also set `steamId` in your `config` block.
383
+
384
+ Steam builds can run on either the Windows or Mac server. The server that receives the request builds its own platforms and requests the rest from the other server (Windows builds `win` and requests `mac`/`linux`; Mac builds `mac`/`linux` and requests `win`). Install the Steamworks SDK ContentBuilder on any server that will upload to Steam.
385
+
386
+ When builds relay between servers, `meta/publish/` credentials travel in the zip with the game payload.
387
+
388
+ #### Electron (`win`, `win-dev`, `mac`, `mac-dev`, `linux`, `linux-dev`, `steam`, `steam-dev`)
389
+
390
+ `-dev` builders produce debug Electron apps with DevTools enabled and the application menu visible. Dev builds skip code signing, notarization, and Steam upload. No publish credentials are required for dev builds.
391
+
392
+ Release `win` builds can be signed with `assets/meta/publish/ms.json` (see Windows below). Release `mac` builds can use `assets/meta/publish/apple.json` for signing and notarization (see Apple above).
393
+
394
+ #### Web app (`webapp`)
395
+
396
+ To deploy via SFTP, include `assets/meta/publish/sftp.json`:
397
+
398
+ ```json
399
+ {
400
+ "webapp": {
401
+ "host": "(your sftp host)",
402
+ "port": 22,
403
+ "user": "(your username)",
404
+ "password": "(your password)",
405
+ "path": "(the sftp subdirectory in which to publish the app)"
406
+ }
407
+ }
408
+ ```
409
+
410
+ #### Windows (`win`, `win-dev`, `uwp`)
411
+
412
+ To sign the app, place your certificate at `assets/meta/publish/ms/packcert.pfx` and include `assets/meta/publish/ms.json`:
413
+
414
+ ```json
415
+ {
416
+ "publisherName": "CN=(your publisher id)",
417
+ "certificateFile": "./ms/packcert.pfx",
418
+ "password": "(your password)"
419
+ }
420
+ ```
421
+
422
+ ## Response
423
+
424
+ The server responds with a zip stream containing build artifacts (`.apk`, `.aab`, `.ipa`, `.app`, `.exe`, etc.) and optional status files. By default the client extracts this into `./output/`. Use a non-`extract` mode value to save the raw response zip instead.
425
+
426
+ Every build also includes `wrapfully-status.json` with structured `success`, `warn`, and `error` events. The client prints these after extraction and exits with code 1 if any errors were reported, so build failures do not crash the server silently.
427
+
428
+ ## License
429
+
430
+ MIT
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env node
2
+ import { deployFromCli } from '../lib/node/deploy.js';
3
+
4
+ deployFromCli().catch((err) => {
5
+ console.error(err);
6
+ process.exit(1);
7
+ });
@@ -0,0 +1,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
+ */
8
+ export function createArchive(deployFolder, contents) {
9
+ const zip = archiver('zip', { zlib: { level: 0 } });
10
+
11
+ zip.on('warning', (err) => {
12
+ if (err.code === 'ENOENT') {
13
+ console.log(err);
14
+ return;
15
+ }
16
+ throw err;
17
+ });
18
+ zip.on('error', (err) => {
19
+ throw err;
20
+ });
21
+ zip.on('close', () => {
22
+ console.log(`Zipped ${zip.pointer()} total bytes`);
23
+ });
24
+
25
+ zip.directory(`${deployFolder}/`, 'deploy');
26
+ zip.file(`${deployFolder}/index.html`, { name: 'deploy/index.html' });
27
+ if (fs.existsSync('assets/meta/')) {
28
+ zip.directory('assets/meta/', 'meta');
29
+ }
30
+ zip.append(contents, { name: 'package.json' });
31
+ zip.finalize();
32
+
33
+ return zip;
34
+ }
@@ -0,0 +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
+ }
@@ -0,0 +1,69 @@
1
+ import axios from 'axios';
2
+ import fs from 'node:fs';
3
+ import { pipeline } from 'node:stream/promises';
4
+ import unzipper from 'unzip-stream';
5
+ import { createArchive } from './archive.js';
6
+ import { loadProjectConfig, resolveServerUrl } from './config.js';
7
+ import { printBuildReport } from './report.js';
8
+
9
+ /**
10
+ * @param {string} gameId
11
+ * @param {string} contents
12
+ * @param {string} server
13
+ * @param {string} builder
14
+ * @param {string} deployFolder
15
+ * @param {{ name: string, version: string }} pkg
16
+ * @param {'extract' | string} mode
17
+ */
18
+ export async function send(gameId, contents, server, builder, deployFolder, pkg, mode = 'extract') {
19
+ const destination = mode === 'extract'
20
+ ? unzipper.Extract({ path: './output/', concurrency: 1 })
21
+ : fs.createWriteStream(`./output/${pkg.name}-${pkg.version}-${builder}.zip`);
22
+
23
+ const archiveStream = createArchive(deployFolder, contents);
24
+ const { data } = await axios.post(`${server}${builder}/${gameId}`, archiveStream, {
25
+ maxRedirects: 0,
26
+ responseType: 'stream',
27
+ });
28
+
29
+ archiveStream.on('close', () => {
30
+ console.log('completed send');
31
+ });
32
+
33
+ try {
34
+ await pipeline(data, destination);
35
+ } catch (err) {
36
+ if (/** @type {NodeJS.ErrnoException} */ (err).code === 'ECONNREFUSED') {
37
+ console.error(`Cannot connect to Wrapfully server "${server}"`);
38
+ process.exit(1);
39
+ }
40
+ throw err;
41
+ }
42
+
43
+ if (mode === 'extract') {
44
+ printBuildReport(builder, pkg);
45
+ }
46
+ }
47
+
48
+ /**
49
+ * @param {string[]} [argv=process.argv]
50
+ */
51
+ export async function deployFromCli(argv = process.argv) {
52
+ const builder = argv[2] ?? 'all';
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
+ }