@makefully/adaptfully 4.3.0 → 5.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 CHANGED
@@ -2,6 +2,20 @@
2
2
 
3
3
  All notable changes to this project are documented in this file.
4
4
 
5
+ ## 5.0.1 — 2026-09-17
6
+
7
+ ### Changed
8
+
9
+ - **`google-auth`** requires `config.googleClientId` (no built-in Entanglement client id default).
10
+ - **`social-auth`** no longer falls back to `config.googleClientId` for Capgo `webClientId` — use `platforms.<name>.socialLogin.google.webClientId` only.
11
+ - Docs: browser GIS vs Capacitor Google client ids are documented as separate fan-out surfaces.
12
+
13
+ ## 5.0.0 — 2026-09-11
14
+
15
+ ### Changed
16
+
17
+ - **Breaking:** Wrapfully extracts always land in `output/<platform>/` (including single-platform `build` / `release` / `deploy`). Sequential runs no longer overwrite siblings. Deploy still falls back to a legacy flat `output/` artifact if present.
18
+
5
19
  ## 4.3.0 — 2026-09-11
6
20
 
7
21
  ### Added
package/README.md CHANGED
@@ -30,7 +30,7 @@ adaptfully prebuild web # deploy/ → output/web-prebuild/
30
30
  adaptfully build steam # Yap /yap/wrapfully chore → artifact zip
31
31
  adaptfully deploy web --deployment web-prod # Yap deploy chore
32
32
  adaptfully release android --encrypt # optional envelope encryption
33
- adaptfully release steam,android,ios # sequential platforms; extracts to output/<platform>/
33
+ adaptfully release steam,android,ios # sequential platforms; each → output/<platform>/
34
34
  adaptfully release --platforms steam,android # same, flag form
35
35
  adaptfully steam-publish # one-time: log in with steamcmd → assets/meta/deployments/steam/steam.json
36
36
  ```
@@ -47,7 +47,7 @@ adaptfully steam-publish # one-time: log in with steamcmd
47
47
  | `android-keystore` | One-time local setup: generate debug/release keystores and write `android` `build.json` (also updates `.gitignore`) |
48
48
  | `apple-signing` | One-time local setup: CSR → Apple `.cer` → `.p12` / provisioning profiles under `ios/apple/` (also updates `.gitignore`) |
49
49
 
50
- Comma-separated platforms (or `--platforms`) run **sequentially**. Multi-platform extracts go to `output/<platform>/` so sibling results are not overwritten; only that folder’s prior `artifacts/` / status files are cleared before each extract. A single platform still extracts to `output/` for backward compatibility.
50
+ Comma-separated platforms (or `--platforms`) run **sequentially**. Build/deploy/release extracts always go to `output/<platform>/` so sibling results are not overwritten; only that folder’s prior `artifacts/` / status files are cleared before each extract.
51
51
 
52
52
  **Server** means the Showfully Yap base (`SHOWFULLY_SERVER` / `wrapfully.json` `showfullyServer` or `server`), default `https://make.makefullystudios.com/`. Wrapfully workers claim chores with a separate service token.
53
53
 
@@ -136,7 +136,7 @@ Games should call `adaptfully.has('analytics')` before `get` during rollout if o
136
136
 
137
137
  | Plugin key | Registration | Runtime |
138
138
  |------------|--------------|---------|
139
- | `google-auth` | `adaptfully.register('auth', adaptfully.auth.Google)` | Web, Android, iOS |
139
+ | `google-auth` | `adaptfully.register('auth', adaptfully.auth.Google)` | Web (Google Identity Services) |
140
140
  | `steam-auth` | `adaptfully.register('auth', adaptfully.auth.Steam)` | Steam / Electron (via [steamworks.js](https://github.com/ceifa/steamworks.js)) |
141
141
  | `social-auth` | `adaptfully.register('auth', adaptfully.auth.Social)` | Capacitor (via [@capgo/capacitor-social-login](https://github.com/Cap-go/capacitor-social-login)) |
142
142
  | `dev-auth` | `adaptfully.register('auth', adaptfully.auth.Dev)` | Local / testing |
@@ -188,6 +188,13 @@ Android/iOS Wrapfully builds use the **`capacitor`** builder family. Cordova/Pho
188
188
 
189
189
  **`social-auth` requires `packager: "capacitor"`** and `platforms.<name>.socialLogin` (Capgo provider client IDs). Wrapfully installs `@capgo/capacitor-social-login` when building.
190
190
 
191
+ Google client IDs are **not** interchangeable across plugins:
192
+
193
+ | Surface | Config | Notes |
194
+ |---------|--------|--------|
195
+ | Browser GIS (`google-auth`) | `config.googleClientId` (via your config registration / bridge) | OAuth **Web** client whose authorized JavaScript origins include the site origin |
196
+ | Capacitor Capgo (`social-auth`) | `platforms.<name>.socialLogin.google.webClientId` | Server / web client id for native Google Sign-In — do **not** put this in `googleClientId` |
197
+
191
198
  ```json
192
199
  {
193
200
  "config": {
@@ -220,6 +227,19 @@ Android/iOS Wrapfully builds use the **`capacitor`** builder family. Cordova/Pho
220
227
  }
221
228
  ```
222
229
 
230
+ #### Google auth (`google-auth`)
231
+
232
+ Browser-only plugin using [Google Identity Services](https://developers.google.com/identity/oauth2/web/guides/overview) (`accounts.google.com/gsi/client`). Requires `config.googleClientId` — there is no built-in default. GIS authorized origins are **per OAuth client**; reusing `socialLogin.google.webClientId` here is a common failure mode when mobile and web need different clients.
233
+
234
+ Optional config keys:
235
+
236
+ | Key | Default | Purpose |
237
+ |-----|---------|---------|
238
+ | `googleClientId` | *(required)* | Browser GIS OAuth client id |
239
+ | `googleTokenKey` | `adaptfully_google_token` | `sessionStorage` key for the access token |
240
+ | `googleScopes` | `openid email profile` | OAuth scopes |
241
+ | `autoLoginStorageKey` | `lastLoggedIn` | Storage key written with the user id on login |
242
+
223
243
  #### Steam auth (`steam-auth`)
224
244
 
225
245
  When `steam-auth` is registered on an **`electron`** platform, Adaptfully prebuild writes:
@@ -242,6 +262,8 @@ The runtime plugin calls Capgo `SocialLogin.initialize` / `login` / `logout` / `
242
262
 
243
263
  **Apple-only iOS** (`providers.google: false`, `providers.apple: true`) is supported — Google `webClientId` is not required. On iOS, if `apple.clientId` is omitted, Adaptfully defaults it to the platform `packageName` (Capgo uses this as a plugin label on native iOS, not an Apple Services ID). On Android, Apple Sign-In still requires `apple.clientId`. At runtime, an empty Apple `clientId` also falls back to `window.gameConfig.packageName`.
244
264
 
265
+ Google Sign-In on Capacitor reads **`socialLogin.google.webClientId` only** (via `social-login-config.js`). It does not fall back to `config.googleClientId`.
266
+
245
267
  Optional config keys:
246
268
 
247
269
  | Key | Default | Purpose |
@@ -283,7 +305,7 @@ import {
283
305
 
284
306
  ## Wrapfully deploy
285
307
 
286
- After prebuild, the build and deploy stages zip `output/<platform>-prebuild/` and POST it to a Wrapfully build server. Artifacts are saved to `./output/`.
308
+ After prebuild, the build and deploy stages zip `output/<platform>-prebuild/` and POST it to a Wrapfully build server. Artifacts are saved to `./output/<platform>/`.
287
309
 
288
310
  ## Quick start
289
311
 
@@ -322,7 +344,7 @@ npx adaptfully apple-publish [--deployment ios] [--category C] [--identity I] [-
322
344
  |----------|---------|-------------|
323
345
  | `platform` | — | Platform key from `config.platforms` (`web`, `steam`, etc.) |
324
346
  | `server` | see below | Wrapfully server base URL (`build` and `deploy` only) |
325
- | `mode` | `extract` | `extract` unpacks the response zip into `./output/`; any other value saves `./output/{name}-{version}-{builder}.zip` |
347
+ | `mode` | `extract` | `extract` unpacks the response zip into `./output/<platform>/`; any other value saves `./output/<platform>/{name}-{version}-{builder}.zip` |
326
348
 
327
349
  Examples:
328
350
 
@@ -402,7 +424,9 @@ mygame/
402
424
  │ └── index.html
403
425
  ├── output/
404
426
  │ ├── web-prebuild/ # after adaptfully prebuild web
405
- │ └── steam-prebuild/ # after adaptfully prebuild steam
427
+ │ ├── steam-prebuild/ # after adaptfully prebuild steam
428
+ │ ├── web/ # after adaptfully build/release web
429
+ │ └── steam/ # after adaptfully build/release steam
406
430
  └── assets/
407
431
  └── meta/ # shared files packaged as meta/ in the zip
408
432
  ├── icon-foreground.png
@@ -727,7 +751,7 @@ To sign the app, place your certificate at `assets/meta/deployments/<deployment>
727
751
 
728
752
  ## Response
729
753
 
730
- 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.
754
+ 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/<platform>/`. Use a non-`extract` mode value to save the raw response zip instead.
731
755
 
732
756
  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.
733
757
 
@@ -17,18 +17,17 @@ export function buildOutputDir(pkg, outputRoot = 'output') {
17
17
  }
18
18
 
19
19
  /**
20
- * Where a platform's Wrapfully zip is extracted.
21
- * Multi-platform runs use `output/<platformKey>/` so siblings are not overwritten.
22
- * Single-platform runs keep `output/` for backward compatibility.
20
+ * Where a platform's Wrapfully zip is extracted: always `output/<platformKey>/`
21
+ * so sequential single-platform and multi-platform runs share one layout.
22
+ * Without a platform key, falls back to `outputRoot`.
23
23
  *
24
24
  * @param {string} outputRoot
25
25
  * @param {string} [platformKey]
26
- * @param {{ multiPlatform?: boolean }} [options]
27
26
  * @returns {string}
28
27
  */
29
- export function resolveExtractRoot(outputRoot, platformKey, options = {}) {
28
+ export function resolveExtractRoot(outputRoot, platformKey) {
30
29
  const root = path.resolve(outputRoot);
31
- if (options.multiPlatform && platformKey) {
30
+ if (platformKey) {
32
31
  return path.join(root, platformKey);
33
32
  }
34
33
  return root;
@@ -55,9 +54,10 @@ export function clearStaleBuildExtract(extractRoot = 'output') {
55
54
 
56
55
  /**
57
56
  * Resolve the artifact directory from a prior `adaptfully build` (or compatible zip extract).
57
+ * Prefers `output/<platform>/`; still accepts a legacy flat `output/` extract.
58
58
  *
59
59
  * @param {{ name: string, version: string, config?: { outputFolder?: string } }} pkg
60
- * @param {{ outputRoot?: string, platformKey?: string, multiPlatform?: boolean }} [options]
60
+ * @param {{ outputRoot?: string, platformKey?: string }} [options]
61
61
  * @returns {string}
62
62
  */
63
63
  export function resolveBuildArtifactDir(pkg, options = {}) {
@@ -65,7 +65,7 @@ export function resolveBuildArtifactDir(pkg, options = {}) {
65
65
  const candidates = [];
66
66
 
67
67
  if (options.platformKey) {
68
- candidates.push(resolveExtractRoot(outputRoot, options.platformKey, { multiPlatform: true }));
68
+ candidates.push(resolveExtractRoot(outputRoot, options.platformKey));
69
69
  }
70
70
  candidates.push(outputRoot);
71
71
 
@@ -49,7 +49,7 @@ export function resolveWrapfullyRoute(buildSpec) {
49
49
  /**
50
50
  * @param {AdaptfullyStage} stage
51
51
  * @param {string} platformKey
52
- * @param {{ pkg: object, deployFolder: string, server?: string, mode?: string, deployment?: string, artifactPath?: string, log?: (message: string) => void, outputRoot?: string, accessToken?: string, encrypt?: boolean, encryptPublicKey?: string, wrapfullyConfig?: object, extractRoot?: string, multiPlatform?: boolean }} options
52
+ * @param {{ pkg: object, deployFolder: string, server?: string, mode?: string, deployment?: string, artifactPath?: string, log?: (message: string) => void, outputRoot?: string, accessToken?: string, encrypt?: boolean, encryptPublicKey?: string, wrapfullyConfig?: object, extractRoot?: string }} options
53
53
  */
54
54
  export async function runAdaptfullyStage(stage, platformKey, options) {
55
55
  if (!VALID_STAGES.has(stage)) {
@@ -62,7 +62,7 @@ export async function runAdaptfullyStage(stage, platformKey, options) {
62
62
  let deployments = resolveDeploymentsForPlatform(platformKey, pkg);
63
63
  const outputRoot = buildOutputDir(pkg, options.outputRoot);
64
64
  const extractRoot = options.extractRoot
65
- ?? resolveExtractRoot(outputRoot, platformKey, { multiPlatform: options.multiPlatform === true });
65
+ ?? resolveExtractRoot(outputRoot, platformKey);
66
66
 
67
67
  if (options.deployment) {
68
68
  if (!deployments.includes(options.deployment)) {
@@ -85,7 +85,6 @@ export async function runAdaptfullyStage(stage, platformKey, options) {
85
85
  artifactPath = resolveBuildArtifactDir(pkg, {
86
86
  outputRoot: options.outputRoot,
87
87
  platformKey,
88
- multiPlatform: options.multiPlatform,
89
88
  });
90
89
  }
91
90
 
@@ -198,7 +197,7 @@ export async function runAdaptfullyStage(stage, platformKey, options) {
198
197
 
199
198
  /**
200
199
  * Run a stage for one or more platforms sequentially.
201
- * Multi-platform extracts land in `output/<platformKey>/` so outputs do not overwrite.
200
+ * Each platform extracts to `output/<platformKey>/`.
202
201
  *
203
202
  * @param {AdaptfullyStage} stage
204
203
  * @param {string[]} platformKeys
@@ -206,21 +205,17 @@ export async function runAdaptfullyStage(stage, platformKey, options) {
206
205
  */
207
206
  export async function runAdaptfullyStages(stage, platformKeys, options) {
208
207
  const log = options.log ?? console.log;
209
- const multiPlatform = platformKeys.length > 1;
210
208
  /** @type {{ platformKey: string, ok: boolean, result?: object, error?: Error }[]} */
211
209
  const results = [];
212
210
 
213
- if (multiPlatform) {
211
+ if (platformKeys.length > 1) {
214
212
  log(`adaptfully: sequential ${stage} for ${platformKeys.join(', ')}`);
215
213
  }
216
214
 
217
215
  for (const platformKey of platformKeys) {
218
216
  log(`adaptfully: ——— ${stage} ${platformKey} ———`);
219
217
  try {
220
- const result = await runAdaptfullyStage(stage, platformKey, {
221
- ...options,
222
- multiPlatform,
223
- });
218
+ const result = await runAdaptfullyStage(stage, platformKey, options);
224
219
  results.push({ platformKey, ok: true, result });
225
220
  } catch (err) {
226
221
  const error = err instanceof Error ? err : new Error(String(err));
@@ -286,10 +281,10 @@ export async function adaptfullyFromCli(argv = process.argv) {
286
281
  + ' release Yap release chore (build + configured deployments)\n'
287
282
  + '\n'
288
283
  + ' Multiple platforms (comma-separated or --platforms) run sequentially.\n'
289
- + ' Multi-platform extracts go to output/<platform>/ so siblings are preserved.\n'
284
+ + ' Extracts always go to output/<platform>/ so siblings are preserved.\n'
290
285
  + '\n'
291
286
  + ' --deployment <key> Target a single named deployment.\n'
292
- + ' --artifact <path> Prior build artifact directory (deploy only; default: ./output/ after build).\n'
287
+ + ' --artifact <path> Prior build artifact directory (deploy only; default: ./output/<platform>/ after build).\n'
293
288
  + ' --encrypt Envelope-encrypt chore to Wrapfully (optional; default key embedded).\n'
294
289
  + ' --encrypt-public-key <pem|path> Override Wrapfully public key when encrypting.\n'
295
290
  + '\n'
@@ -3,7 +3,6 @@
3
3
  (function registerGoogleAuth(ns) {
4
4
  const { configValue, getStorage } = ns.auth.helpers;
5
5
 
6
- const DEFAULT_CLIENT_ID = '225754014403.apps.googleusercontent.com';
7
6
  const DEFAULT_SCOPES = 'openid email profile';
8
7
  const DEFAULT_TOKEN_KEY = 'adaptfully_google_token';
9
8
  const DEFAULT_AUTO_LOGIN_KEY = 'lastLoggedIn';
@@ -33,8 +32,13 @@
33
32
  return configValue('googleTokenKey', DEFAULT_TOKEN_KEY);
34
33
  }
35
34
 
35
+ /**
36
+ * Browser GIS OAuth client id only (`config.googleClientId`).
37
+ * Capacitor / Capgo builds use `platforms.<name>.socialLogin.google.webClientId` instead.
38
+ */
36
39
  #clientId() {
37
- return configValue('googleClientId', DEFAULT_CLIENT_ID);
40
+ const clientId = configValue('googleClientId', '');
41
+ return typeof clientId === 'string' ? clientId.trim() : '';
38
42
  }
39
43
 
40
44
  #scopes() {
@@ -47,8 +51,17 @@
47
51
 
48
52
  whenReady(done) {
49
53
  const setup = () => {
54
+ const clientId = this.#clientId();
55
+ if (!clientId) {
56
+ console.error(
57
+ 'google-auth: config.googleClientId is required '
58
+ + '(browser GIS OAuth client; do not reuse socialLogin.google.webClientId).',
59
+ );
60
+ done({ error: 'google-auth: config.googleClientId is required' });
61
+ return;
62
+ }
50
63
  this.tokenClient = google.accounts.oauth2.initTokenClient({
51
- client_id: this.#clientId(),
64
+ client_id: clientId,
52
65
  scope: this.#scopes(),
53
66
  callback: () => {},
54
67
  });
@@ -107,9 +107,11 @@
107
107
  const options = {};
108
108
 
109
109
  if (config.providers?.google !== false) {
110
+ // Capgo webClientId comes only from platforms.<name>.socialLogin
111
+ // (written to __ADAPTFULLY_SOCIAL_LOGIN__). Do not fall back to
112
+ // config.googleClientId — that key is for browser google-auth / GIS.
110
113
  options.google = {
111
- webClientId: config.google?.webClientId
112
- || configValue('googleClientId', ''),
114
+ webClientId: config.google?.webClientId || '',
113
115
  iOSClientId: config.google?.iOSClientId,
114
116
  iOSServerClientId: config.google?.iOSServerClientId
115
117
  || config.google?.webClientId,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@makefully/adaptfully",
3
- "version": "4.3.0",
3
+ "version": "5.0.1",
4
4
  "description": "Platform abstraction and Wrapfully deploy client for Makefully games",
5
5
  "type": "module",
6
6
  "main": "./lib/node/index.js",