@makefully/adaptfully 5.0.5 → 5.0.7
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 +13 -0
- package/README.md +48 -4
- package/lib/node/publish-credentials.js +2 -0
- package/lib/runtime/auth/google-auth.js +101 -4
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,19 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project are documented in this file.
|
|
4
4
|
|
|
5
|
+
## 5.0.7 — 2026-10-07
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- Gitignore patterns for `assets/meta/deployments/**/s3.json` and `**/showfully.json`.
|
|
10
|
+
- Docs for web deploy via SFTP (atomic `cleanRemote`), AWS S3, and Showfully folder (credential shapes consumed by Wrapfully).
|
|
11
|
+
|
|
12
|
+
## 5.0.6 — 2026-10-07
|
|
13
|
+
|
|
14
|
+
### Changed
|
|
15
|
+
|
|
16
|
+
- **`google-auth`** persists the GIS access token in **`localStorage`** by default (was `sessionStorage`), so web sign-in survives browser restarts until explicit logout or Google silent reauth fails. Opt back into tab-only tokens with `config.googleTokenStorage: 'sessionStorage'`. Existing `sessionStorage` tokens are migrated once on read.
|
|
17
|
+
|
|
5
18
|
## 5.0.5 — 2026-10-06
|
|
6
19
|
|
|
7
20
|
### Changed
|
package/README.md
CHANGED
|
@@ -236,7 +236,8 @@ Optional config keys:
|
|
|
236
236
|
| Key | Default | Purpose |
|
|
237
237
|
|-----|---------|---------|
|
|
238
238
|
| `googleClientId` | *(required)* | Browser GIS OAuth client id |
|
|
239
|
-
| `googleTokenKey` | `adaptfully_google_token` |
|
|
239
|
+
| `googleTokenKey` | `adaptfully_google_token` | Storage key for the GIS access token |
|
|
240
|
+
| `googleTokenStorage` | `localStorage` | `localStorage` (survives browser restart) or `sessionStorage` (tab-only) |
|
|
240
241
|
| `googleScopes` | `openid email profile` | OAuth scopes |
|
|
241
242
|
| `autoLoginStorageKey` | `lastLoggedIn` | Storage key written with the user id on login |
|
|
242
243
|
|
|
@@ -436,11 +437,17 @@ mygame/
|
|
|
436
437
|
│ └── sftp.json
|
|
437
438
|
├── web-prod/
|
|
438
439
|
│ └── sftp.json
|
|
440
|
+
├── web-s3-prod/
|
|
441
|
+
│ ├── manifest.json # { "type": "s3" }
|
|
442
|
+
│ └── s3.json
|
|
443
|
+
├── web-showfully/
|
|
444
|
+
│ ├── manifest.json # { "type": "showfully" }
|
|
445
|
+
│ └── showfully.json
|
|
439
446
|
└── steam/ # default deployment for the `steam` platform
|
|
440
447
|
└── steam.json
|
|
441
448
|
```
|
|
442
449
|
|
|
443
|
-
The selected deployment's folder is shipped as `meta/publish/` in the zip, so per-platform credential file names (`build.json`, `sftp.json`, `steam.json`, `apple.json`, `google.json`, `ms.json`, `android/`, `ms/`) live inside `assets/meta/deployments/<key>/`.
|
|
450
|
+
The selected deployment's folder is shipped as `meta/publish/` in the zip, so per-platform credential file names (`build.json`, `sftp.json`, `s3.json`, `showfully.json`, `steam.json`, `apple.json`, `google.json`, `ms.json`, `android/`, `ms/`) live inside `assets/meta/deployments/<key>/`.
|
|
444
451
|
|
|
445
452
|
Icons (`icon-foreground.png`, `icon-background.png`) are required for mobile, desktop, and Steam builds. If either file is missing from `assets/meta/`, Adaptfully **warns** and ships packaged placeholder icons for that build so Wrapfully can still run.
|
|
446
453
|
|
|
@@ -717,7 +724,9 @@ Release `win` builds can be signed with `assets/meta/deployments/<deployment>/ms
|
|
|
717
724
|
|
|
718
725
|
#### Web (`web` / `webapp`)
|
|
719
726
|
|
|
720
|
-
`adaptfully deploy web` prebuilds and POSTs to the Wrapfully **`webapp`** builder (same conduit as Steam).
|
|
727
|
+
`adaptfully deploy web` prebuilds and POSTs to the Wrapfully **`webapp`** builder (same conduit as Steam). Each web deployment folder under `assets/meta/deployments/<key>/` is zipped as `meta/publish/` for Wrapfully. Set `manifest.json` `"type"` to `sftp`, `s3`, or `showfully` (or rely on the credential filename). The inner settings key stays the builder name (`webapp`).
|
|
728
|
+
|
|
729
|
+
**SFTP** — `sftp.json`:
|
|
721
730
|
|
|
722
731
|
```json
|
|
723
732
|
{
|
|
@@ -735,7 +744,42 @@ Release `win` builds can be signed with `assets/meta/deployments/<deployment>/ms
|
|
|
735
744
|
}
|
|
736
745
|
```
|
|
737
746
|
|
|
738
|
-
|
|
747
|
+
`path` is the remote site root or a longer subfolder path. With `uploadMode: "direct"` and `cleanRemote: true`, Wrapfully uploads to `[path]-temp`, then deletes the live directory and renames temp → `path` (atomic replace). `cleanRemote` is ignored for `versioned` uploads.
|
|
748
|
+
|
|
749
|
+
**AWS S3** — `s3.json` + `manifest.json` `{ "type": "s3" }`:
|
|
750
|
+
|
|
751
|
+
```json
|
|
752
|
+
{
|
|
753
|
+
"webapp": {
|
|
754
|
+
"region": "us-east-1",
|
|
755
|
+
"bucket": "my-games-cdn",
|
|
756
|
+
"prefix": "",
|
|
757
|
+
"uploadMode": "direct",
|
|
758
|
+
"cleanRemote": false,
|
|
759
|
+
"accessKeyId": "(iam access key)",
|
|
760
|
+
"secretAccessKey": "(iam secret)"
|
|
761
|
+
}
|
|
762
|
+
}
|
|
763
|
+
```
|
|
764
|
+
|
|
765
|
+
`prefix: ""` deploys to the bucket root; `"games/mygame"` deploys under that key prefix. `cleanRemote: true` uses an atomic `prefix-temp` swap (refuses empty prefix unless `allowBucketRootWipe: true`).
|
|
766
|
+
|
|
767
|
+
**Showfully folder** — `showfully.json` + `manifest.json` `{ "type": "showfully" }`:
|
|
768
|
+
|
|
769
|
+
```json
|
|
770
|
+
{
|
|
771
|
+
"webapp": {
|
|
772
|
+
"server": "https://make.makefullystudios.com/",
|
|
773
|
+
"folder": "MyGame",
|
|
774
|
+
"path": "",
|
|
775
|
+
"accessToken": "sfpat_…"
|
|
776
|
+
}
|
|
777
|
+
}
|
|
778
|
+
```
|
|
779
|
+
|
|
780
|
+
`folder` is a top-level Showfully folder name. `path: ""` writes at that folder’s root; `"web"` (or nested) prefixes zip entries under a subfolder. `accessToken` is required (Wrapfully workers cannot reuse the Yap submit PAT).
|
|
781
|
+
|
|
782
|
+
See [Wrapfully README](https://github.com/Makefully-Studios/wrapfully-client) for `uploadMode`, `serviceWorker`, `metaWeb`, and deployer details.
|
|
739
783
|
|
|
740
784
|
#### Windows (`win`, `win-dev`, `uwp`)
|
|
741
785
|
|
|
@@ -6,6 +6,8 @@ import { stdin as input, stdout as output } from 'node:process';
|
|
|
6
6
|
/** Patterns that should never be committed from deployment credential folders. */
|
|
7
7
|
export const PUBLISH_CREDENTIAL_GITIGNORE_PATTERNS = [
|
|
8
8
|
'assets/meta/deployments/**/sftp.json',
|
|
9
|
+
'assets/meta/deployments/**/s3.json',
|
|
10
|
+
'assets/meta/deployments/**/showfully.json',
|
|
9
11
|
'assets/meta/deployments/**/steam.json',
|
|
10
12
|
'assets/meta/deployments/**/build.json',
|
|
11
13
|
'assets/meta/deployments/**/google.json',
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/* global google, sessionStorage, window */
|
|
1
|
+
/* global google, localStorage, sessionStorage, window */
|
|
2
2
|
|
|
3
3
|
(function registerGoogleAuth(ns) {
|
|
4
4
|
const { configValue, getStorage } = ns.auth.helpers;
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
const DEFAULT_SCOPES = 'openid email profile';
|
|
7
7
|
const DEFAULT_TOKEN_KEY = 'adaptfully_google_token';
|
|
8
8
|
const DEFAULT_AUTO_LOGIN_KEY = 'lastLoggedIn';
|
|
9
|
+
const DEFAULT_TOKEN_STORAGE = 'localStorage';
|
|
9
10
|
|
|
10
11
|
class GoogleAuthPlugin {
|
|
11
12
|
constructor() {
|
|
@@ -32,6 +33,27 @@
|
|
|
32
33
|
return configValue('googleTokenKey', DEFAULT_TOKEN_KEY);
|
|
33
34
|
}
|
|
34
35
|
|
|
36
|
+
/**
|
|
37
|
+
* Where the GIS access token is persisted.
|
|
38
|
+
* Default `localStorage` so sign-in survives browser restarts until logout
|
|
39
|
+
* (or Google silent reauth fails). Use `sessionStorage` for tab-only tokens.
|
|
40
|
+
*/
|
|
41
|
+
#tokenStorageName() {
|
|
42
|
+
const raw = configValue('googleTokenStorage', DEFAULT_TOKEN_STORAGE);
|
|
43
|
+
return raw === 'sessionStorage' ? 'sessionStorage' : 'localStorage';
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
#tokenStore() {
|
|
47
|
+
try {
|
|
48
|
+
if (this.#tokenStorageName() === 'sessionStorage') {
|
|
49
|
+
return typeof sessionStorage !== 'undefined' ? sessionStorage : null;
|
|
50
|
+
}
|
|
51
|
+
return typeof localStorage !== 'undefined' ? localStorage : null;
|
|
52
|
+
} catch {
|
|
53
|
+
return null;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
35
57
|
/**
|
|
36
58
|
* Browser GIS OAuth client id only (`config.googleClientId`).
|
|
37
59
|
* Capacitor / Capgo builds use `platforms.<name>.socialLogin.google.webClientId` instead.
|
|
@@ -95,16 +117,91 @@
|
|
|
95
117
|
this.authenticated = !!(this.user.id && this.user.email);
|
|
96
118
|
}
|
|
97
119
|
|
|
120
|
+
#readStoredToken() {
|
|
121
|
+
const key = this.#tokenKey(),
|
|
122
|
+
primary = this.#tokenStore();
|
|
123
|
+
let token = '';
|
|
124
|
+
|
|
125
|
+
try {
|
|
126
|
+
token = (primary && primary.getItem(key)) || '';
|
|
127
|
+
} catch {
|
|
128
|
+
token = '';
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// One-time migrate: older builds kept the token in sessionStorage.
|
|
132
|
+
if (!token && this.#tokenStorageName() === 'localStorage') {
|
|
133
|
+
try {
|
|
134
|
+
token = (typeof sessionStorage !== 'undefined' && sessionStorage.getItem(key)) || '';
|
|
135
|
+
if (token && primary) {
|
|
136
|
+
primary.setItem(key, token);
|
|
137
|
+
sessionStorage.removeItem(key);
|
|
138
|
+
}
|
|
139
|
+
} catch {
|
|
140
|
+
/* ignore quota / private-mode */
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
return token;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
#writeStoredToken(token) {
|
|
148
|
+
const key = this.#tokenKey(),
|
|
149
|
+
primary = this.#tokenStore();
|
|
150
|
+
|
|
151
|
+
try {
|
|
152
|
+
if (primary) {
|
|
153
|
+
primary.setItem(key, token);
|
|
154
|
+
}
|
|
155
|
+
} catch {
|
|
156
|
+
/* ignore */
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// Drop the legacy session copy so tab-close cannot leave a stale twin.
|
|
160
|
+
if (this.#tokenStorageName() === 'localStorage') {
|
|
161
|
+
try {
|
|
162
|
+
if (typeof sessionStorage !== 'undefined') {
|
|
163
|
+
sessionStorage.removeItem(key);
|
|
164
|
+
}
|
|
165
|
+
} catch {
|
|
166
|
+
/* ignore */
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
#clearStoredToken() {
|
|
172
|
+
const key = this.#tokenKey();
|
|
173
|
+
|
|
174
|
+
try {
|
|
175
|
+
this.#tokenStore()?.removeItem(key);
|
|
176
|
+
} catch {
|
|
177
|
+
/* ignore */
|
|
178
|
+
}
|
|
179
|
+
try {
|
|
180
|
+
if (typeof sessionStorage !== 'undefined') {
|
|
181
|
+
sessionStorage.removeItem(key);
|
|
182
|
+
}
|
|
183
|
+
} catch {
|
|
184
|
+
/* ignore */
|
|
185
|
+
}
|
|
186
|
+
try {
|
|
187
|
+
if (typeof localStorage !== 'undefined') {
|
|
188
|
+
localStorage.removeItem(key);
|
|
189
|
+
}
|
|
190
|
+
} catch {
|
|
191
|
+
/* ignore */
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
98
195
|
#clearSession() {
|
|
99
196
|
this.accessToken = '';
|
|
100
197
|
this.user = null;
|
|
101
198
|
this.authenticated = false;
|
|
102
|
-
|
|
199
|
+
this.#clearStoredToken();
|
|
103
200
|
}
|
|
104
201
|
|
|
105
202
|
#loadStoredToken() {
|
|
106
203
|
if (!this.accessToken) {
|
|
107
|
-
this.accessToken =
|
|
204
|
+
this.accessToken = this.#readStoredToken();
|
|
108
205
|
}
|
|
109
206
|
}
|
|
110
207
|
|
|
@@ -126,7 +223,7 @@
|
|
|
126
223
|
})
|
|
127
224
|
.then((data) => {
|
|
128
225
|
this.accessToken = token;
|
|
129
|
-
|
|
226
|
+
this.#writeStoredToken(token);
|
|
130
227
|
this.#applyUserInfo(data);
|
|
131
228
|
callback();
|
|
132
229
|
})
|