@makefully/adaptfully 3.8.2 → 3.10.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,24 @@
2
2
 
3
3
  All notable changes to this project are documented in this file.
4
4
 
5
+ ## 3.10.0 — 2026-07-17
6
+
7
+ ### Added
8
+
9
+ - **`social-auth`** — Capgo `@capgo/capacitor-social-login` auth plugin for Capacitor platforms. Requires `packager: "capacitor"` and `platforms.<name>.socialLogin` provider config. Prebuild writes `social-login-config.js`; Wrapfully installs the native plugin when `socialLogin` is set on the build spec.
10
+ - **`CapacitorPackager`** CSP/viewport HTML extras and social-auth validation/templates.
11
+
12
+ ### Changed
13
+
14
+ - **Builder family defaults** — `android` / `ios` / `ios-sim` (and `-dev`) resolve to Wrapfully family **`capacitor`**. Explicit `packager: "cordova"` still selects Cordova for that platform. Composite `cordova` / `apple` routes are not used.
15
+ - **`resolveBuildSpec`** includes `socialLogin: boolean`.
16
+
17
+ ## 3.9.0 — 2026-07-15
18
+
19
+ ### Added
20
+
21
+ - **`pwa` Wrapfully family** — `resolveFamilyFromTarget('pwa')` / `resolveBuildSpec` return family `pwa` when `builder: "pwa"`, including with `packager: "web"`.
22
+
5
23
  ## 3.8.2 — 2026-07-14
6
24
 
7
25
  ### Fixed
package/README.md CHANGED
@@ -91,7 +91,8 @@ storage.getObject('currentGame');
91
91
  |------------|--------------|---------|
92
92
  | `google-auth` | `adaptfully.register('auth', adaptfully.auth.Google)` | Web, Android, iOS |
93
93
  | `steam-auth` | `adaptfully.register('auth', adaptfully.auth.Steam)` | Steam / Electron (via [steamworks.js](https://github.com/ceifa/steamworks.js)) |
94
- | `dev-auth` | `adaptfully.register('auth', adaptfully.auth.Dev)` | Local dev (test user) |
94
+ | `social-auth` | `adaptfully.register('auth', adaptfully.auth.Social)` | Capacitor (via [@capgo/capacitor-social-login](https://github.com/Cap-go/capacitor-social-login)) |
95
+ | `dev-auth` | `adaptfully.register('auth', adaptfully.auth.Dev)` | Local / testing |
95
96
 
96
97
  Use plugin keys in `config.platforms.<platform>.registrations`. Custom deploy scripts use a path relative to the deploy folder instead:
97
98
 
@@ -133,10 +134,14 @@ Each platform entry may set a **`packager`** (`web`, `electron`, `cordova`, or `
133
134
  | `web` | `game-config.js` for **`uwp`** platform prebuilds |
134
135
  | `electron` | `main.js` (Electron shell); `preload.js` when **`steam-auth`** is registered |
135
136
  | `cordova` | `cordova.js` stub, `game-config.js`, CSP/viewport HTML extras |
136
- | `capacitor` | `game-config.js` (more Capacitor-specific output planned) |
137
+ | `capacitor` | `game-config.js`, Capacitor CSP/viewport; `social-login-config.js` when **`social-auth`** is registered |
138
+
139
+ Android/iOS Wrapfully builds default to the **`capacitor`** builder family. Set `packager: "cordova"` on a platform to use Cordova for that target.
137
140
 
138
141
  **`steam-auth` requires `packager: "electron"`** and `platforms.<name>.steamId` (Steamworks app ID for the client preload). Steam **upload** app IDs live separately in each Steam deployment’s `manifest.json` — see Wrapfully docs.
139
142
 
143
+ **`social-auth` requires `packager: "capacitor"`** and `platforms.<name>.socialLogin` (Capgo provider client IDs). Wrapfully installs `@capgo/capacitor-social-login` when building.
144
+
140
145
  ```json
141
146
  {
142
147
  "config": {
@@ -149,6 +154,20 @@ Each platform entry may set a **`packager`** (`web`, `electron`, `cordova`, or `
149
154
  "packager": "electron",
150
155
  "steamId": 1234567,
151
156
  "registrations": { "auth": "steam-auth" }
157
+ },
158
+ "android": {
159
+ "packager": "capacitor",
160
+ "registrations": { "auth": "social-auth", "storage": "localStorage" },
161
+ "socialLogin": {
162
+ "providers": { "google": true, "apple": true },
163
+ "google": {
164
+ "webClientId": "….apps.googleusercontent.com",
165
+ "iOSClientId": "….apps.googleusercontent.com"
166
+ },
167
+ "apple": {
168
+ "clientId": "com.example.service"
169
+ }
170
+ }
152
171
  }
153
172
  }
154
173
  }
@@ -169,6 +188,17 @@ The renderer `steam-auth` plugin reads the Steam ID from that bridge. When Steam
169
188
  | `autoLoginStorageKey` | `lastLoggedIn` | Storage key written with the Steam ID on login |
170
189
  | `steamReadyTimeoutMs` | `10000` | Max wait when a bridge exists but identity is not yet ready |
171
190
 
191
+ #### Social auth (`social-auth`)
192
+
193
+ When `social-auth` is registered on a **`capacitor`** platform, Adaptfully prebuild writes **`social-login-config.js`** (`window.__ADAPTFULLY_SOCIAL_LOGIN__`) from `platforms.<name>.socialLogin`. Wrapfully installs [`@capgo/capacitor-social-login`](https://github.com/Cap-go/capacitor-social-login) and syncs it into the native project (same role as `steamworks.js` for Electron).
194
+
195
+ The runtime plugin calls Capgo `SocialLogin.initialize` / `login` / `logout` / `isLoggedIn`. Default provider is `google` on Android and `apple` on iOS when both are enabled (override with `socialLogin.defaultProvider`). Optional config keys:
196
+
197
+ | Key | Default | Purpose |
198
+ |-----|---------|---------|
199
+ | `autoLoginStorageKey` | `lastLoggedIn` | Storage key written with the user id on login |
200
+ | `socialReadyTimeoutMs` | `10000` | Max wait for the Capgo plugin bridge |
201
+
172
202
  ### Node API
173
203
 
174
204
  ```javascript
@@ -211,7 +241,7 @@ After prebuild, the build and deploy stages zip `output/<platform>-prebuild/` an
211
241
 
212
242
  ```bash
213
243
  npx adaptfully prebuild web
214
- npx adaptfully deploy steam http://build.example.com:9630/
244
+ npx adaptfully deploy steam http://build.example.com:9633/
215
245
  ```
216
246
 
217
247
  For web-only hosting (no Wrapfully), stop after prebuild and upload `output/web-prebuild/` yourself.
@@ -246,10 +276,10 @@ Examples:
246
276
  npx adaptfully prebuild web
247
277
 
248
278
  # Build for Steam via Wrapfully
249
- npx adaptfully build steam http://build.example.com:9630/
279
+ npx adaptfully build steam http://build.example.com:9633/
250
280
 
251
281
  # Full Steam deploy (build + upload when steam.json credentials are present)
252
- npx adaptfully deploy steam http://build.example.com:9630/
282
+ npx adaptfully deploy steam http://build.example.com:9633/
253
283
  ```
254
284
 
255
285
  Add scripts to your project's `package.json`:
@@ -278,7 +308,7 @@ The server URL is resolved in this order:
278
308
  1. CLI argument
279
309
  2. `WRAPFULLY_SERVER` environment variable
280
310
  3. `server` field in `wrapfully.json`
281
- 4. `http://localhost:9630/`
311
+ 4. `http://localhost:9633/`
282
312
 
283
313
  Keep server addresses and credentials out of version control — use environment variables or a gitignored `wrapfully.json`.
284
314
 
@@ -293,7 +323,7 @@ The client POSTs a zip stream built from `output/<platform>-prebuild/` to:
293
323
  For example, a project named `mygame` at version `1.2.0` with builder `android`:
294
324
 
295
325
  ```
296
- http://build.example.com:9630/android/mygame-1.2.0
326
+ http://build.example.com:9633/android/mygame-1.2.0
297
327
  ```
298
328
 
299
329
  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.
@@ -415,6 +445,7 @@ Standard npm fields (`name`, `version`, `description`) are used directly. Add a
415
445
  | `platforms.<name>.builders` | wrapfully-deploy | Map additional Wrapfully builder names to a platform |
416
446
  | `platforms.<name>.packager` | Prebuild | `web` (default), `electron`, `cordova`, or `capacitor` — selects the packager class that adds platform-specific files during prebuild |
417
447
  | `platforms.<name>.steamId` | Electron + steam-auth | Steamworks app ID baked into `preload.js` (client). Upload app IDs belong in the Steam deployment `manifest.json` |
448
+ | `platforms.<name>.socialLogin` | Capacitor + social-auth | Capgo provider config (`providers`, `google.webClientId`, `apple.clientId`, optional `defaultProvider`) |
418
449
  | `properties` | Cordova | Cordova config.xml entries (plugins, allow-navigation, etc.) |
419
450
 
420
451
  ### `wrapfully.json`
@@ -424,7 +455,7 @@ Optional. Fields are shallow-merged into `package.json`'s `config`:
424
455
  ```json
425
456
  {
426
457
  "deployFolder": "dist",
427
- "server": "http://build.example.com:9630/",
458
+ "server": "http://build.example.com:9633/",
428
459
  "title": "My Game",
429
460
  "packageName": "com.example.mygame"
430
461
  }
@@ -453,12 +484,8 @@ Each builder name becomes a path segment on the server. Some builds require a sp
453
484
  | `webapp` | Service-worker web app (optionally SFTP deploy) |
454
485
  | `steam` | Windows + Mac + Linux, uploads to Steam |
455
486
  | `steam-dev` | Debug Windows + Mac + Linux, no Steam upload |
456
- | `cordova` | Release Android + iOS |
457
- | `cordova-dev` | Debug Android + iOS |
458
- | `apple` | Release Mac + iOS |
459
- | `apple-dev` | Release Mac + debug iOS |
460
487
 
461
- For a single platform, pass the specific builder name rather than a composite.
488
+ For a single platform, pass the specific builder name.
462
489
 
463
490
  ### Platform package requirements
464
491
 
@@ -508,7 +535,7 @@ To deploy to Google Play, also include `assets/meta/deployments/<deployment>/goo
508
535
  }
509
536
  ```
510
537
 
511
- #### Apple (`ios`, `ios-dev`, `ios-sim`, `mac`, `apple`, `apple-dev`)
538
+ #### Apple (`ios`, `ios-dev`, `ios-sim`, `mac`)
512
539
 
513
540
  Include `assets/meta/deployments/<deployment>/build.json` with iOS signing settings:
514
541
 
@@ -544,9 +571,9 @@ To deploy to the App Store, include `assets/meta/deployments/<deployment>/apple.
544
571
  }
545
572
  ```
546
573
 
547
- #### Cordova (`cordova`, `cordova-dev`)
574
+ #### Cordova
548
575
 
549
- Requires the Android and Apple package requirements above.
576
+ Set `packager: "cordova"` on an `android` or `ios` platform to use Cordova instead of Capacitor. Requires the Android and Apple package requirements above.
550
577
 
551
578
  #### Steam (`steam`, `steam-dev`)
552
579
 
@@ -1,6 +1,6 @@
1
1
  import fs from 'node:fs/promises';
2
2
 
3
- const DEFAULT_SERVER = 'http://localhost:9630/';
3
+ const DEFAULT_SERVER = 'http://localhost:9633/';
4
4
 
5
5
  /**
6
6
  * @param {string} [projectRoot='.']
@@ -223,6 +223,14 @@ export class Packager {
223
223
  + `Set config.platforms.${platformLabel}.packager to "electron".`,
224
224
  );
225
225
  }
226
+
227
+ if (this.usesPlugin('social-auth', { scope: 'all' }) && this.name !== 'capacitor') {
228
+ const platformLabel = this.platformKey ?? this.platforms[0] ?? 'unknown';
229
+ throw new Error(
230
+ `Platform "${platformLabel}" uses social-auth but packager is "${this.name}". `
231
+ + `Set config.platforms.${platformLabel}.packager to "capacitor".`,
232
+ );
233
+ }
226
234
  }
227
235
 
228
236
  needsGameConfig() {
@@ -1,5 +1,81 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
1
3
  import { Packager } from './base.js';
2
4
 
5
+ const CAPACITOR_CSP = '<meta http-equiv="Content-Security-Policy" content="default-src * \'self\' data: blob: \'unsafe-inline\' \'unsafe-eval\'; style-src * \'self\' \'unsafe-inline\'; script-src * \'self\' \'unsafe-inline\' \'unsafe-eval\'; connect-src *; img-src * data: blob:; media-src * data: blob:; frame-src *;" />';
6
+
7
+ const CAPACITOR_VIEWPORT = '<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover" />';
8
+
9
+ /**
10
+ * @param {string | null | undefined} platformKey
11
+ * @param {{ config?: { platforms?: Record<string, { socialLogin?: object }> } }} pkg
12
+ */
13
+ export function resolvePlatformSocialLogin(platformKey, pkg) {
14
+ if (!platformKey) {
15
+ return undefined;
16
+ }
17
+ return pkg.config?.platforms?.[platformKey]?.socialLogin;
18
+ }
19
+
20
+ /**
21
+ * @param {object} socialLogin
22
+ * @param {string} platformKey
23
+ */
24
+ function normalizeSocialLoginConfig(socialLogin = {}, platformKey) {
25
+ const providers = socialLogin.providers ?? { google: true, apple: true };
26
+ const googleEnabled = providers.google !== false;
27
+ const appleEnabled = providers.apple !== false;
28
+
29
+ let defaultProvider = socialLogin.defaultProvider;
30
+ if (!defaultProvider) {
31
+ if (platformKey === 'ios' || platformKey === 'ios-dev' || platformKey === 'ios-sim') {
32
+ defaultProvider = appleEnabled ? 'apple' : 'google';
33
+ } else {
34
+ defaultProvider = googleEnabled ? 'google' : 'apple';
35
+ }
36
+ }
37
+
38
+ return {
39
+ providers: {
40
+ google: googleEnabled,
41
+ apple: appleEnabled,
42
+ facebook: providers.facebook === true,
43
+ twitter: providers.twitter === true,
44
+ },
45
+ google: socialLogin.google ?? {},
46
+ apple: socialLogin.apple ?? {},
47
+ defaultProvider,
48
+ platform: platformKey,
49
+ };
50
+ }
51
+
52
+ /**
53
+ * @param {object} config
54
+ */
55
+ function validateSocialLoginConfig(config) {
56
+ const { providers, google, apple } = config;
57
+
58
+ if (!providers.google && !providers.apple) {
59
+ throw new Error('social-auth requires at least one of socialLogin.providers.google or .apple');
60
+ }
61
+
62
+ if (providers.google) {
63
+ if (!google?.webClientId) {
64
+ throw new Error(
65
+ 'social-auth with Google requires platforms.<key>.socialLogin.google.webClientId',
66
+ );
67
+ }
68
+ }
69
+
70
+ if (providers.apple && config.platform?.startsWith('android')) {
71
+ if (!apple?.clientId) {
72
+ throw new Error(
73
+ 'social-auth with Apple on Android requires platforms.<key>.socialLogin.apple.clientId',
74
+ );
75
+ }
76
+ }
77
+ }
78
+
3
79
  export class CapacitorPackager extends Packager {
4
80
  /** @type {'capacitor'} */
5
81
  static id = 'capacitor';
@@ -7,7 +83,57 @@ export class CapacitorPackager extends Packager {
7
83
  /** @type {string[]} */
8
84
  static defaultPlatforms = ['ios', 'android'];
9
85
 
86
+ validate() {
87
+ super.validate();
88
+
89
+ if (this.usesPlugin('social-auth')) {
90
+ const socialLogin = resolvePlatformSocialLogin(this.platformKey, this.pkg);
91
+ if (!socialLogin && !this.pkg.config?.socialLogin) {
92
+ const platformLabel = this.platformKey ?? this.platforms.join(', ');
93
+ throw new Error(
94
+ `Platform "${platformLabel}" uses social-auth but platforms.${platformLabel}.socialLogin is not set.`,
95
+ );
96
+ }
97
+
98
+ const config = normalizeSocialLoginConfig(
99
+ socialLogin ?? this.pkg.config?.socialLogin,
100
+ this.platformKey ?? 'android',
101
+ );
102
+ validateSocialLoginConfig(config);
103
+ }
104
+ }
105
+
10
106
  needsGameConfig() {
11
107
  return true;
12
108
  }
109
+
110
+ /** @param {string} dest */
111
+ applyTemplates(dest) {
112
+ if (this.usesPlugin('social-auth') && this.platformKey) {
113
+ const socialLogin = resolvePlatformSocialLogin(this.platformKey, this.pkg)
114
+ ?? this.pkg.config?.socialLogin
115
+ ?? {};
116
+ const config = normalizeSocialLoginConfig(socialLogin, this.platformKey);
117
+ const content = `window.__ADAPTFULLY_SOCIAL_LOGIN__ = ${JSON.stringify(config, null, 4)};\n`;
118
+ fs.writeFileSync(path.join(dest, 'social-login-config.js'), content);
119
+ this.log('adaptfully: write social-login-config.js (social-auth)');
120
+ }
121
+
122
+ super.applyTemplates(dest);
123
+ }
124
+
125
+ buildHtmlInjection() {
126
+ const headExtras = [CAPACITOR_CSP, CAPACITOR_VIEWPORT];
127
+ const bodyScripts = [];
128
+
129
+ if (this.usesPlugin('social-auth')) {
130
+ bodyScripts.push('<script src="social-login-config.js"></script>');
131
+ }
132
+
133
+ if (this.needsGameConfig()) {
134
+ bodyScripts.push('<script src="game-config.js"></script>');
135
+ }
136
+
137
+ return this.formatHtmlInjection(headExtras, bodyScripts);
138
+ }
13
139
  }
@@ -1,19 +1,19 @@
1
1
  import { CapacitorPackager } from './capacitor.js';
2
2
  import { CordovaPackager } from './cordova.js';
3
- import { ElectronPackager, buildElectronMain, buildElectronPreload } from './electron.js';
3
+ import { ElectronPackager } from './electron.js';
4
4
  import { Packager, VALID_PACKAGERS } from './base.js';
5
5
  import { WebPackager } from './web.js';
6
6
 
7
- export { Packager, VALID_PACKAGERS } from './base.js';
8
- export { WebPackager } from './web.js';
7
+ export { CapacitorPackager, resolvePlatformSocialLogin } from './capacitor.js';
8
+ export { CordovaPackager } from './cordova.js';
9
9
  export {
10
10
  ElectronPackager,
11
11
  buildElectronMain,
12
12
  buildElectronPreload,
13
13
  resolvePlatformSteamId,
14
14
  } from './electron.js';
15
- export { CordovaPackager } from './cordova.js';
16
- export { CapacitorPackager } from './capacitor.js';
15
+ export { Packager, VALID_PACKAGERS } from './base.js';
16
+ export { WebPackager } from './web.js';
17
17
 
18
18
  /** @typedef {import('./base.js').PackagerName} PackagerName */
19
19
 
@@ -72,6 +72,13 @@ export function usesSteamAuth(registrations) {
72
72
  return Object.values(registrations).includes('steam-auth');
73
73
  }
74
74
 
75
+ /**
76
+ * @param {Record<string, string>} registrations
77
+ */
78
+ export function usesSocialAuth(registrations) {
79
+ return Object.values(registrations).includes('social-auth');
80
+ }
81
+
75
82
  /**
76
83
  * @param {string} dest
77
84
  * @param {string} platformKey
@@ -22,6 +22,10 @@ export const STANDARD_PLUGINS = {
22
22
  scripts: ['core.js', 'platform.js', 'auth/_helpers.js', 'auth/steam-auth.js'],
23
23
  registration: (key) => `adaptfully.register('${key}', adaptfully.auth.Steam);`,
24
24
  },
25
+ 'social-auth': {
26
+ scripts: ['core.js', 'platform.js', 'auth/_helpers.js', 'auth/social-auth.js'],
27
+ registration: (key) => `adaptfully.register('${key}', adaptfully.auth.Social);`,
28
+ },
25
29
  'dev-auth': {
26
30
  scripts: ['core.js', 'platform.js', 'auth/_helpers.js', 'auth/dev-auth.js'],
27
31
  registration: (key) => `adaptfully.register('${key}', adaptfully.auth.Dev);`,
@@ -52,10 +56,6 @@ export const DEFAULT_BUILDER_PLATFORMS = {
52
56
  'ios-dev': 'ios',
53
57
  'ios-sim': 'ios',
54
58
  webapp: 'web',
55
- cordova: 'cordova',
56
- 'cordova-dev': 'cordova',
57
- apple: 'apple',
58
- 'apple-dev': 'apple',
59
59
  uwp: 'uwp',
60
60
  };
61
61
 
@@ -340,7 +340,7 @@ export function resolvePublishDir(deploymentKey, metaDir = 'assets/meta') {
340
340
  const ELECTRON_TARGETS = new Set([
341
341
  'win', 'win-dev', 'mac', 'mac-dev', 'linux', 'linux-dev',
342
342
  ]);
343
- const CORDOVA_TARGETS = new Set([
343
+ const MOBILE_TARGETS = new Set([
344
344
  'android', 'android-dev', 'ios', 'ios-dev', 'ios-sim',
345
345
  ]);
346
346
 
@@ -352,8 +352,11 @@ export function resolveFamilyFromTarget(target) {
352
352
  if (ELECTRON_TARGETS.has(target)) {
353
353
  return 'electron';
354
354
  }
355
- if (CORDOVA_TARGETS.has(target)) {
356
- return 'cordova';
355
+ if (MOBILE_TARGETS.has(target)) {
356
+ return 'capacitor';
357
+ }
358
+ if (target === 'pwa') {
359
+ return 'pwa';
357
360
  }
358
361
  if (target === 'webapp' || target === 'web') {
359
362
  return 'webapp';
@@ -369,12 +372,19 @@ 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
  }
375
- if (packager === 'cordova' || packager === 'capacitor') {
382
+ if (packager === 'cordova') {
376
383
  return 'cordova';
377
384
  }
385
+ if (packager === 'capacitor') {
386
+ return 'capacitor';
387
+ }
378
388
 
379
389
  const families = [...new Set(targets.map((target) => resolveFamilyFromTarget(target)).filter(Boolean))];
380
390
 
@@ -382,27 +392,42 @@ export function resolveFamily(targets, packager) {
382
392
  return families[0];
383
393
  }
384
394
 
385
- if (targets.length === 1 && targets[0] === 'webapp') {
395
+ if (targets.length === 1 && (targets[0] === 'webapp' || targets[0] === 'web')) {
386
396
  return 'webapp';
387
397
  }
388
398
 
389
399
  throw new Error(`Cannot resolve builder family for targets [${targets.join(', ')}]`);
390
400
  }
391
401
 
402
+ /**
403
+ * @param {object | undefined} platform
404
+ * @returns {boolean}
405
+ */
406
+ function platformUsesSocialAuth(platform) {
407
+ if (!platform?.registrations) {
408
+ return false;
409
+ }
410
+ return Object.values(platform.registrations).includes('social-auth');
411
+ }
412
+
392
413
  /**
393
414
  * @param {string} platformKey
394
- * @param {{ config?: { platforms?: Record<string, { builder?: string | string[], packager?: string, steamworks?: boolean, deployments?: string[] }> } }} pkg
415
+ * @param {{ config?: { platforms?: Record<string, { builder?: string | string[], packager?: string, steamworks?: boolean, socialLogin?: boolean | object, registrations?: Record<string, string>, deployments?: string[] }> } }} pkg
395
416
  */
396
417
  export function resolveBuildSpec(platformKey, pkg) {
397
418
  const platform = pkg.config?.platforms?.[platformKey];
398
419
  const builder = platform?.builder ?? (platformKey === 'web' ? 'webapp' : platformKey);
399
420
  const targets = Array.isArray(builder) ? [...builder] : [builder];
421
+ const socialLogin = platform?.socialLogin === true
422
+ || (typeof platform?.socialLogin === 'object' && platform.socialLogin != null)
423
+ || platformUsesSocialAuth(platform);
400
424
 
401
425
  return {
402
426
  family: resolveFamily(targets, platform?.packager),
403
427
  targets,
404
428
  platformKey,
405
429
  steamworks: platform?.steamworks === true,
430
+ socialLogin,
406
431
  deployments: resolveDeploymentsForPlatform(platformKey, pkg),
407
432
  };
408
433
  }
@@ -0,0 +1,313 @@
1
+ /* global window */
2
+
3
+ /**
4
+ * Social auth via @capgo/capacitor-social-login.
5
+ * Adaptfully prebuild writes social-login-config.js and Wrapfully installs the Capgo plugin
6
+ * when packager is "capacitor" and registrations.auth is "social-auth".
7
+ */
8
+ (function registerSocialAuth(ns) {
9
+ const { configValue, getStorage } = ns.auth.helpers;
10
+
11
+ const DEFAULT_AUTO_LOGIN_KEY = 'lastLoggedIn';
12
+ const READY_POLL_MS = 50;
13
+ const READY_TIMEOUT_MS = 10000;
14
+
15
+ function readSocialLoginConfig() {
16
+ return window.__ADAPTFULLY_SOCIAL_LOGIN__ || {};
17
+ }
18
+
19
+ function resolveSocialLoginPlugin() {
20
+ const plugins = window.Capacitor?.Plugins;
21
+ if (plugins?.SocialLogin) {
22
+ return plugins.SocialLogin;
23
+ }
24
+ if (window.SocialLogin) {
25
+ return window.SocialLogin;
26
+ }
27
+ return null;
28
+ }
29
+
30
+ function mapLoginResult(result) {
31
+ const resultResult = result?.result ?? result;
32
+ const profile = resultResult?.profile
33
+ || resultResult?.user
34
+ || resultResult
35
+ || {};
36
+ const id = String(
37
+ profile.id
38
+ || profile.user
39
+ || profile.sub
40
+ || resultResult?.accessToken?.userId
41
+ || resultResult?.idToken
42
+ || '',
43
+ );
44
+ const email = String(profile.email || '');
45
+
46
+ if (!id && !email) {
47
+ return null;
48
+ }
49
+
50
+ return {
51
+ id: id || email,
52
+ email,
53
+ displayName: profile.name || profile.givenName || '',
54
+ };
55
+ }
56
+
57
+ class SocialAuthPlugin {
58
+ constructor() {
59
+ this.name = 'social';
60
+ this.user = null;
61
+ this.authenticated = false;
62
+ this.online = false;
63
+ this.#plugin = null;
64
+ this.#provider = null;
65
+ }
66
+
67
+ /** @type {object | null} */
68
+ #plugin;
69
+
70
+ /** @type {string | null} */
71
+ #provider;
72
+
73
+ supportsAutoLogin() {
74
+ return true;
75
+ }
76
+
77
+ #autoLoginStorageKey() {
78
+ return configValue('autoLoginStorageKey', DEFAULT_AUTO_LOGIN_KEY);
79
+ }
80
+
81
+ #config() {
82
+ return readSocialLoginConfig();
83
+ }
84
+
85
+ #resolveDefaultProvider() {
86
+ const config = this.#config();
87
+ if (config.defaultProvider) {
88
+ return config.defaultProvider;
89
+ }
90
+ const platform = config.platform || window.gameConfig?.platform || '';
91
+ if (String(platform).startsWith('ios')) {
92
+ return config.providers?.apple === false ? 'google' : 'apple';
93
+ }
94
+ return config.providers?.google === false ? 'apple' : 'google';
95
+ }
96
+
97
+ #buildInitializeOptions() {
98
+ const config = this.#config();
99
+ const options = {};
100
+
101
+ if (config.providers?.google !== false) {
102
+ options.google = {
103
+ webClientId: config.google?.webClientId
104
+ || configValue('googleClientId', ''),
105
+ iOSClientId: config.google?.iOSClientId,
106
+ iOSServerClientId: config.google?.iOSServerClientId
107
+ || config.google?.webClientId,
108
+ mode: config.google?.mode || 'online',
109
+ };
110
+ }
111
+
112
+ if (config.providers?.apple !== false) {
113
+ options.apple = {
114
+ clientId: config.apple?.clientId || '',
115
+ redirectUrl: config.apple?.redirectUrl,
116
+ useProperTokenExchange: config.apple?.useProperTokenExchange !== false,
117
+ useBroadcastChannel: config.apple?.useBroadcastChannel !== false,
118
+ };
119
+ }
120
+
121
+ return options;
122
+ }
123
+
124
+ #persistLogin(user) {
125
+ const storage = getStorage();
126
+ storage?.set(this.#autoLoginStorageKey(), user.id);
127
+ }
128
+
129
+ #applyIdentity(identity) {
130
+ if (!identity?.id) {
131
+ this.user = null;
132
+ this.authenticated = false;
133
+ this.online = false;
134
+ return false;
135
+ }
136
+
137
+ this.user = {
138
+ id: identity.id,
139
+ email: identity.email || '',
140
+ displayName: identity.displayName || '',
141
+ };
142
+ this.authenticated = true;
143
+ this.online = true;
144
+ this.#persistLogin(this.user);
145
+ return true;
146
+ }
147
+
148
+ #complete(callback) {
149
+ callback({
150
+ authenticated: this.authenticated,
151
+ user: this.getUser(),
152
+ });
153
+ }
154
+
155
+ whenReady(done) {
156
+ const started = Date.now();
157
+ const timeoutMs = Number(configValue('socialReadyTimeoutMs', READY_TIMEOUT_MS))
158
+ || READY_TIMEOUT_MS;
159
+
160
+ const finish = async () => {
161
+ const plugin = resolveSocialLoginPlugin();
162
+ if (!plugin) {
163
+ if (Date.now() - started >= timeoutMs) {
164
+ console.warn('[adaptfully social-auth] Capgo SocialLogin plugin not available');
165
+ this.online = false;
166
+ done({ error: 'SocialLogin plugin not available' });
167
+ return;
168
+ }
169
+ window.setTimeout(finish, READY_POLL_MS);
170
+ return;
171
+ }
172
+
173
+ this.#plugin = plugin;
174
+ this.#provider = this.#resolveDefaultProvider();
175
+
176
+ try {
177
+ await plugin.initialize(this.#buildInitializeOptions());
178
+ this.online = true;
179
+ done();
180
+ } catch (err) {
181
+ console.error('[adaptfully social-auth] initialize failed:', err);
182
+ this.online = false;
183
+ done({ error: err?.message || 'SocialLogin initialize failed' });
184
+ }
185
+ };
186
+
187
+ finish();
188
+ }
189
+
190
+ login(callback) {
191
+ const plugin = this.#plugin ?? resolveSocialLoginPlugin();
192
+ const provider = this.#provider ?? this.#resolveDefaultProvider();
193
+
194
+ if (!plugin) {
195
+ console.warn('[adaptfully social-auth] login: plugin missing');
196
+ this.#complete(callback);
197
+ return;
198
+ }
199
+
200
+ plugin.login({
201
+ provider,
202
+ options: {
203
+ scopes: provider === 'google'
204
+ ? ['email', 'profile']
205
+ : ['email', 'name'],
206
+ },
207
+ })
208
+ .then((result) => {
209
+ if (!this.#applyIdentity(mapLoginResult(result))) {
210
+ console.warn('[adaptfully social-auth] login: could not map identity', result);
211
+ }
212
+ this.#complete(callback);
213
+ })
214
+ .catch((err) => {
215
+ console.error('[adaptfully social-auth] login failed:', err);
216
+ this.user = null;
217
+ this.authenticated = false;
218
+ this.online = false;
219
+ this.#complete(callback);
220
+ });
221
+ }
222
+
223
+ autoLogin(callback) {
224
+ const plugin = this.#plugin ?? resolveSocialLoginPlugin();
225
+ const provider = this.#provider ?? this.#resolveDefaultProvider();
226
+ const storage = getStorage();
227
+ const lastId = storage?.get?.(this.#autoLoginStorageKey());
228
+
229
+ if (!plugin || typeof plugin.isLoggedIn !== 'function') {
230
+ if (lastId) {
231
+ this.#applyIdentity({ id: String(lastId), email: '' });
232
+ }
233
+ this.#complete(callback);
234
+ return;
235
+ }
236
+
237
+ plugin.isLoggedIn({ provider })
238
+ .then(async (status) => {
239
+ if (!status?.isLoggedIn) {
240
+ this.user = null;
241
+ this.authenticated = false;
242
+ this.#complete(callback);
243
+ return;
244
+ }
245
+
246
+ if (typeof plugin.getAuthorizationCode === 'function') {
247
+ try {
248
+ const auth = await plugin.getAuthorizationCode({ provider });
249
+ const identity = mapLoginResult(auth) || (lastId
250
+ ? { id: String(lastId), email: '' }
251
+ : null);
252
+ this.#applyIdentity(identity);
253
+ this.#complete(callback);
254
+ return;
255
+ } catch {
256
+ // fall through to lastId
257
+ }
258
+ }
259
+
260
+ if (lastId) {
261
+ this.#applyIdentity({ id: String(lastId), email: '' });
262
+ }
263
+ this.#complete(callback);
264
+ })
265
+ .catch((err) => {
266
+ console.warn('[adaptfully social-auth] autoLogin failed:', err);
267
+ this.#complete(callback);
268
+ });
269
+ }
270
+
271
+ logout(callback) {
272
+ const plugin = this.#plugin ?? resolveSocialLoginPlugin();
273
+ const provider = this.#provider ?? this.#resolveDefaultProvider();
274
+ const storage = getStorage();
275
+
276
+ const clear = () => {
277
+ this.user = null;
278
+ this.authenticated = false;
279
+ this.online = false;
280
+ storage?.remove(this.#autoLoginStorageKey());
281
+ callback();
282
+ };
283
+
284
+ if (!plugin || typeof plugin.logout !== 'function') {
285
+ clear();
286
+ return;
287
+ }
288
+
289
+ plugin.logout({ provider })
290
+ .then(clear)
291
+ .catch((err) => {
292
+ console.warn('[adaptfully social-auth] logout failed:', err);
293
+ clear();
294
+ });
295
+ }
296
+
297
+ getUser() {
298
+ if (!this.authenticated || !this.user) {
299
+ return null;
300
+ }
301
+ return {
302
+ id: this.user.id,
303
+ email: this.user.email || '',
304
+ };
305
+ }
306
+
307
+ isAuthenticated() {
308
+ return !!this.authenticated;
309
+ }
310
+ }
311
+
312
+ ns.auth.Social = () => new SocialAuthPlugin();
313
+ }(window.adaptfully));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@makefully/adaptfully",
3
- "version": "3.8.2",
3
+ "version": "3.10.0",
4
4
  "description": "Platform abstraction and Wrapfully deploy client for Makefully games",
5
5
  "type": "module",
6
6
  "main": "./lib/node/index.js",