@makefully/adaptfully 5.1.0 → 5.1.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,12 @@
2
2
 
3
3
  All notable changes to this project are documented in this file.
4
4
 
5
+ ## 5.1.1 — 2026-11-05
6
+
7
+ ### Added
8
+
9
+ - **`host.onEnvironment()`** — `car-host` forwards Capacitor CarGames `environment` events (`phone`, `android_auto`, `aaos`) and re-queries `getEnvironment()` on activity resume so a game can restore phone UI while Android Auto stays connected.
10
+
5
11
  ## 5.1.0 — 2026-11-05
6
12
 
7
13
  ### Added
package/docs/host.md CHANGED
@@ -18,6 +18,7 @@ host.onPause((paused) => { /* mute / pause gameplay */ });
18
18
  host.onCaptionsMuted?.((muted) => { /* … */ });
19
19
  host.onVolume?.('music', (level) => { /* 0–1 */ });
20
20
  host.onUxRestrictions?.((info) => { /* car only */ });
21
+ host.onEnvironment?.((environment) => { /* car: phone | android_auto | aaos */ });
21
22
 
22
23
  host.setFeatures({ sound: true, captions: true });
23
24
  host.notifyProgress(0.5, { stage: 'assets' });
@@ -77,7 +78,7 @@ Requires Capacitor packager + `platforms.<key>.carGames` (see Wrapfully README
77
78
  1. Pause gameplay **and audio** when `host.onPause(true)` (activity pause, leave car display, or AAOS UX restrictions).
78
79
  2. Do not resume audio until `onPause(false)` / parked again.
79
80
  3. Layout for car aspect ratios (avoid heavy pillarboxing on landscape Auto).
80
- 4. Prefer `host.getEnvironment()` over sniffing user agents when you need Auto vs phone vs AAOS.
81
+ 4. Prefer `host.getEnvironment()` / `host.onEnvironment()` over sniffing user agents when you need Auto vs phone vs AAOS. `onEnvironment` fires when the activity moves between the car display and the phone, including while Android Auto stays connected. Resume also re-queries `getEnvironment()`.
81
82
 
82
83
  Wrapfully patches the Android manifest (`CAR_LAUNCHER`, `appCategory="game"`, optional automotive feature) and installs the Cap plugin. Play Console form-factor opt-in (Android Auto + Automotive OS) remains a manual Console step.
83
84
 
@@ -5,7 +5,7 @@
5
5
  *
6
6
  * Host contract (stable surface games should prefer over raw SpringRoll / Cap plugins):
7
7
  * kind, getEnvironment(), onPause(cb), onCaptionsMuted?(cb), onVolume?(ch, cb),
8
- * onUxRestrictions?(cb), setFeatures(features), notifyLoaded(), notifyProgress(p, detail?),
8
+ * onUxRestrictions?(cb), onEnvironment?(cb), setFeatures(features), notifyLoaded(), notifyProgress(p, detail?),
9
9
  * notifyEndGame?(payload?), send(event, data?)
10
10
  */
11
11
  (function registerHostHelpers(ns) {
@@ -5,6 +5,7 @@
5
5
  * Requires Wrapfully `platforms.<key>.carGames` and `@makefully/capacitor-car-games`.
6
6
  *
7
7
  * Maps Cap App pause/resume + CarGames UX restrictions → onPause.
8
+ * Forwards CarGames `environment` (and re-queries it on resume) → onEnvironment.
8
9
  */
9
10
  (function registerCarHost(ns) {
10
11
  const { helpers } = ns.host;
@@ -38,8 +39,10 @@
38
39
  sfx: [],
39
40
  };
40
41
  const uxListeners = [];
42
+ const environmentListeners = [];
41
43
  let features = null;
42
44
  let paused = false;
45
+ let environment = null;
43
46
  /** @type {Array<() => void>} */
44
47
  const cleanups = [];
45
48
 
@@ -52,13 +55,50 @@
52
55
  helpers.emit(pauseListeners, paused);
53
56
  }
54
57
 
58
+ function emitEnvironment(next) {
59
+ const value = next ? String(next) : 'phone';
60
+ if (value === environment) {
61
+ return;
62
+ }
63
+ environment = value;
64
+ helpers.emit(environmentListeners, value);
65
+ }
66
+
67
+ function readPluginEnvironment(result) {
68
+ if (result && typeof result === 'object' && result.environment) {
69
+ return String(result.environment);
70
+ }
71
+ return String(result || 'phone');
72
+ }
73
+
74
+ function refreshEnvironment() {
75
+ const car = resolveCarGamesPlugin();
76
+ if (!car || typeof car.getEnvironment !== 'function') {
77
+ emitEnvironment('phone');
78
+ return Promise.resolve('phone');
79
+ }
80
+ return Promise.resolve(car.getEnvironment())
81
+ .then((result) => {
82
+ const value = readPluginEnvironment(result);
83
+ emitEnvironment(value);
84
+ return value;
85
+ })
86
+ .catch(() => {
87
+ emitEnvironment('phone');
88
+ return 'phone';
89
+ });
90
+ }
91
+
55
92
  function attachNativeListeners() {
56
93
  const car = resolveCarGamesPlugin();
57
94
  const app = resolveAppPlugin();
58
95
 
59
96
  if (app && typeof app.addListener === 'function') {
60
97
  const pauseHandle = app.addListener('pause', () => setPaused(true));
61
- const resumeHandle = app.addListener('resume', () => setPaused(false));
98
+ const resumeHandle = app.addListener('resume', () => {
99
+ setPaused(false);
100
+ refreshEnvironment();
101
+ });
62
102
  cleanups.push(() => {
63
103
  pauseHandle?.then?.((h) => h?.remove?.());
64
104
  pauseHandle?.remove?.();
@@ -80,6 +120,9 @@
80
120
  setPaused(true);
81
121
  }
82
122
  });
123
+ const environmentHandle = car.addListener('environment', (event) => {
124
+ emitEnvironment(event?.environment || 'phone');
125
+ });
83
126
  cleanups.push(() => {
84
127
  pauseHandle?.then?.((h) => h?.remove?.());
85
128
  pauseHandle?.remove?.();
@@ -88,6 +131,10 @@
88
131
  uxHandle?.then?.((h) => h?.remove?.());
89
132
  uxHandle?.remove?.();
90
133
  });
134
+ cleanups.push(() => {
135
+ environmentHandle?.then?.((h) => h?.remove?.());
136
+ environmentHandle?.remove?.();
137
+ });
91
138
  }
92
139
  }
93
140
 
@@ -129,18 +176,11 @@
129
176
  kind: 'car',
130
177
 
131
178
  getEnvironment() {
132
- const car = resolveCarGamesPlugin();
133
- if (car && typeof car.getEnvironment === 'function') {
134
- return Promise.resolve(car.getEnvironment())
135
- .then((result) => {
136
- if (result && typeof result === 'object' && result.environment) {
137
- return String(result.environment);
138
- }
139
- return String(result || 'phone');
140
- })
141
- .catch(() => 'phone');
142
- }
143
- return Promise.resolve('phone');
179
+ return refreshEnvironment();
180
+ },
181
+
182
+ onEnvironment(cb) {
183
+ return helpers.subscribe(environmentListeners, cb);
144
184
  },
145
185
 
146
186
  onPause(cb) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@makefully/adaptfully",
3
- "version": "5.1.0",
3
+ "version": "5.1.1",
4
4
  "description": "Platform abstraction and Wrapfully deploy client for Makefully games",
5
5
  "type": "module",
6
6
  "main": "./lib/node/index.js",