@makefully/adaptfully 3.9.0 → 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 +12 -0
- package/README.md +43 -16
- package/lib/node/config.js +1 -1
- package/lib/node/packagers/base.js +8 -0
- package/lib/node/packagers/capacitor.js +126 -0
- package/lib/node/packagers/index.js +12 -5
- package/lib/node/registrations.js +27 -9
- package/lib/runtime/auth/social-auth.js +313 -0
- 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.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
|
+
|
|
5
17
|
## 3.9.0 — 2026-07-15
|
|
6
18
|
|
|
7
19
|
### Added
|
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
|
-
| `
|
|
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`
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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
|
|
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
|
|
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
|
|
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
|
|
package/lib/node/config.js
CHANGED
|
@@ -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
|
|
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 {
|
|
8
|
-
export {
|
|
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 {
|
|
16
|
-
export {
|
|
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
|
|
343
|
+
const MOBILE_TARGETS = new Set([
|
|
344
344
|
'android', 'android-dev', 'ios', 'ios-dev', 'ios-sim',
|
|
345
345
|
]);
|
|
346
346
|
|
|
@@ -352,8 +352,8 @@ export function resolveFamilyFromTarget(target) {
|
|
|
352
352
|
if (ELECTRON_TARGETS.has(target)) {
|
|
353
353
|
return 'electron';
|
|
354
354
|
}
|
|
355
|
-
if (
|
|
356
|
-
return '
|
|
355
|
+
if (MOBILE_TARGETS.has(target)) {
|
|
356
|
+
return 'capacitor';
|
|
357
357
|
}
|
|
358
358
|
if (target === 'pwa') {
|
|
359
359
|
return 'pwa';
|
|
@@ -379,9 +379,12 @@ export function resolveFamily(targets, packager) {
|
|
|
379
379
|
if (packager === 'electron') {
|
|
380
380
|
return 'electron';
|
|
381
381
|
}
|
|
382
|
-
if (packager === 'cordova'
|
|
382
|
+
if (packager === 'cordova') {
|
|
383
383
|
return 'cordova';
|
|
384
384
|
}
|
|
385
|
+
if (packager === 'capacitor') {
|
|
386
|
+
return 'capacitor';
|
|
387
|
+
}
|
|
385
388
|
|
|
386
389
|
const families = [...new Set(targets.map((target) => resolveFamilyFromTarget(target)).filter(Boolean))];
|
|
387
390
|
|
|
@@ -396,20 +399,35 @@ export function resolveFamily(targets, packager) {
|
|
|
396
399
|
throw new Error(`Cannot resolve builder family for targets [${targets.join(', ')}]`);
|
|
397
400
|
}
|
|
398
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
|
+
|
|
399
413
|
/**
|
|
400
414
|
* @param {string} platformKey
|
|
401
|
-
* @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
|
|
402
416
|
*/
|
|
403
417
|
export function resolveBuildSpec(platformKey, pkg) {
|
|
404
418
|
const platform = pkg.config?.platforms?.[platformKey];
|
|
405
419
|
const builder = platform?.builder ?? (platformKey === 'web' ? 'webapp' : platformKey);
|
|
406
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);
|
|
407
424
|
|
|
408
425
|
return {
|
|
409
426
|
family: resolveFamily(targets, platform?.packager),
|
|
410
427
|
targets,
|
|
411
428
|
platformKey,
|
|
412
429
|
steamworks: platform?.steamworks === true,
|
|
430
|
+
socialLogin,
|
|
413
431
|
deployments: resolveDeploymentsForPlatform(platformKey, pkg),
|
|
414
432
|
};
|
|
415
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));
|