@flighthq/lifecycle 0.5.1-edge.799.62ef0c7 → 0.5.1-edge.911.32a089f
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/README.md +2 -2
- package/dist/contract.d.ts +1 -0
- package/dist/contract.d.ts.map +1 -1
- package/dist/contract.js +1 -0
- package/dist/contract.js.map +1 -1
- package/dist/lifecycle.d.ts +3 -1
- package/dist/lifecycle.d.ts.map +1 -1
- package/dist/lifecycle.js +117 -111
- package/dist/lifecycle.js.map +1 -1
- package/package.json +4 -4
- package/src/lifecycle.test.ts +82 -47
package/README.md
CHANGED
|
@@ -13,5 +13,5 @@ Import the supported application-facing API from `@flighthq/lifecycle`. The `@fl
|
|
|
13
13
|
This package is part of the locked-version Flight SDK graph. Applications may instead install and import `@flighthq/sdk` when package-level tree shaking is sufficient.
|
|
14
14
|
|
|
15
15
|
- [Flight project](https://github.com/flighthq/flight)
|
|
16
|
-
- [Source for @flighthq/lifecycle@0.5.1-edge.
|
|
17
|
-
- [License](https://github.com/flighthq/flight/blob/
|
|
16
|
+
- [Source for @flighthq/lifecycle@0.5.1-edge.911.32a089f](https://github.com/flighthq/flight/tree/32a089f1342d08547fc2359dfd5e8fe9f7e3c12e/packages/lifecycle)
|
|
17
|
+
- [License](https://github.com/flighthq/flight/blob/32a089f1342d08547fc2359dfd5e8fe9f7e3c12e/LICENSE.md)
|
package/dist/contract.d.ts
CHANGED
package/dist/contract.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"contract.d.ts","sourceRoot":"","sources":["../src/contract.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC"}
|
|
1
|
+
{"version":3,"file":"contract.d.ts","sourceRoot":"","sources":["../src/contract.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,OAAO,EAAE,sBAAsB,EAAE,6BAA6B,EAAE,MAAM,aAAa,CAAC"}
|
package/dist/contract.js
CHANGED
package/dist/contract.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"contract.js","sourceRoot":"","sources":["../src/contract.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC"}
|
|
1
|
+
{"version":3,"file":"contract.js","sourceRoot":"","sources":["../src/contract.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,OAAO,EAAE,sBAAsB,EAAE,6BAA6B,EAAE,MAAM,aAAa,CAAC"}
|
package/dist/lifecycle.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { BackendOperationExplanation, LifecycleOperation } from '@flighthq/types/contract';
|
|
1
|
+
import type { BackendOperationExplanation, LifecycleOperation, EntityConstruction } from '@flighthq/types/contract';
|
|
2
2
|
import type { AppLaunchKind, HasSystemLifecycle, AppLifecycle, AppLifecycleState, LifecycleBackend } from '@flighthq/types/contract';
|
|
3
3
|
export declare function attachAppLifecycle(host: HasSystemLifecycle, app: AppLifecycle): void;
|
|
4
4
|
export declare function createAppLifecycle(): AppLifecycle;
|
|
@@ -9,6 +9,8 @@ export declare function explainLifecycleOperation(host: HasSystemLifecycle, oper
|
|
|
9
9
|
export declare function getAppLaunchKind(host: HasSystemLifecycle): AppLaunchKind;
|
|
10
10
|
export declare function getAppLifecycleState(host: HasSystemLifecycle): AppLifecycleState;
|
|
11
11
|
export declare function hasLifecycleOperation(host: HasSystemLifecycle, operation: LifecycleOperation): boolean;
|
|
12
|
+
export declare function initializeAppLifecycle(out: EntityConstruction<AppLifecycle>): void;
|
|
13
|
+
export declare function initializeWebLifecycleBackend(out: EntityConstruction<LifecycleBackend>): void;
|
|
12
14
|
export declare function isAppActive(host: HasSystemLifecycle): boolean;
|
|
13
15
|
export declare function isAppBackground(host: HasSystemLifecycle): boolean;
|
|
14
16
|
export declare function isAppInactive(host: HasSystemLifecycle): boolean;
|
package/dist/lifecycle.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lifecycle.d.ts","sourceRoot":"","sources":["../src/lifecycle.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,2BAA2B,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;
|
|
1
|
+
{"version":3,"file":"lifecycle.d.ts","sourceRoot":"","sources":["../src/lifecycle.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,2BAA2B,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AACpH,OAAO,KAAK,EACV,aAAa,EACb,kBAAkB,EAClB,YAAY,EACZ,iBAAiB,EAEjB,gBAAgB,EACjB,MAAM,0BAA0B,CAAC;AAYlC,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,kBAAkB,EAAE,GAAG,EAAE,YAAY,GAAG,IAAI,CAqCpF;AAED,wBAAgB,kBAAkB,IAAI,YAAY,CAIjD;AAED,wBAAgB,yBAAyB,IAAI,gBAAgB,CAI5D;AAGD,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,YAAY,GAAG,IAAI,CAM1D;AAID,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,YAAY,GAAG,IAAI,CAG3D;AAQD,wBAAgB,yBAAyB,CACvC,IAAI,EAAE,kBAAkB,EACxB,SAAS,EAAE,kBAAkB,GAC5B,2BAA2B,CAG7B;AAMD,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,kBAAkB,GAAG,aAAa,CAGxE;AAGD,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,kBAAkB,GAAG,iBAAiB,CAEhF;AAGD,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,kBAAkB,EAAE,SAAS,EAAE,kBAAkB,GAAG,OAAO,CAEtG;AAGD,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,kBAAkB,CAAC,YAAY,CAAC,GAAG,IAAI,CAQlF;AAmBD,wBAAgB,6BAA6B,CAAC,GAAG,EAAE,kBAAkB,CAAC,gBAAgB,CAAC,GAAG,IAAI,CA0E7F;AAGD,wBAAgB,WAAW,CAAC,IAAI,EAAE,kBAAkB,GAAG,OAAO,CAE7D;AAGD,wBAAgB,eAAe,CAAC,IAAI,EAAE,kBAAkB,GAAG,OAAO,CAEjE;AAID,wBAAgB,aAAa,CAAC,IAAI,EAAE,kBAAkB,GAAG,OAAO,CAE/D;AAOD,wBAAgB,cAAc,CAAC,GAAG,EAAE,YAAY,GAAG,OAAO,CAGzD"}
|
package/dist/lifecycle.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { allocateEntity, finishEntity } from '@flighthq/entity/contract';
|
|
2
2
|
import { createSignal, emitSignal } from '@flighthq/signals/contract';
|
|
3
3
|
// Begins delivering lifecycle changes to `app`'s signals by subscribing to the active backend. On
|
|
4
4
|
// each change it reads the current state and emits onStateChange plus onResume when transitioning
|
|
@@ -46,119 +46,15 @@ export function attachAppLifecycle(host, app) {
|
|
|
46
46
|
unsubscribeMemory?.();
|
|
47
47
|
});
|
|
48
48
|
}
|
|
49
|
-
// Allocates an AppLifecycle event entity with inert signals; call attachAppLifecycle to start delivery.
|
|
50
49
|
export function createAppLifecycle() {
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
onPause: createSignal(),
|
|
55
|
-
onBackButton: createSignal(),
|
|
56
|
-
onMemoryWarning: createSignal(),
|
|
57
|
-
onSaveState: createSignal(),
|
|
58
|
-
onRestoreState: createSignal(),
|
|
59
|
-
});
|
|
50
|
+
const out = allocateEntity();
|
|
51
|
+
initializeAppLifecycle(out);
|
|
52
|
+
return finishEntity(out);
|
|
60
53
|
}
|
|
61
|
-
// Builds the default web backend over document visibility, window focus/blur, and pagehide/pageshow
|
|
62
|
-
// events. Produces three states:
|
|
63
|
-
// 'active' — document visible and window focused
|
|
64
|
-
// 'inactive' — document visible but window not focused (app switcher, control-center, other window)
|
|
65
|
-
// 'background' — document.hidden (tab hidden or page unloading)
|
|
66
|
-
// Degrades to state 'active' and a no-op subscription where document/window are absent (SSR/jsdom).
|
|
67
|
-
//
|
|
68
|
-
// getLaunchKind() approximates cold vs. warm using PerformanceNavigationTiming.type:
|
|
69
|
-
// 'back_forward' → 'warm' — page was restored from the bfcache (JS heap was frozen and thawed;
|
|
70
|
-
// the closest web equivalent of a process warm-resume)
|
|
71
|
-
// all others → 'cold' — 'navigate', 'reload', 'prerender' are each a fresh page lifecycle
|
|
72
|
-
// Falls back to 'cold' when the Performance Navigation Timing API is unavailable (SSR/jsdom).
|
|
73
|
-
//
|
|
74
|
-
// subscribeMemoryWarning() wires the experimental 'memory-pressure' window event (Chrome origin
|
|
75
|
-
// trial / behind flags). The event detail carries a 'critical' pressure string; this backend maps
|
|
76
|
-
// it to 'critical' and fires 'normal' on the subsequent resolution event when present. Falls back to
|
|
77
|
-
// no-op unsubscribe when the event is not supported (no standard API is widely deployed as of 2026).
|
|
78
54
|
export function createWebLifecycleBackend() {
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
if (typeof document === 'undefined')
|
|
83
|
-
return 'active';
|
|
84
|
-
if (document.hidden)
|
|
85
|
-
return 'background';
|
|
86
|
-
return _windowFocused ? 'active' : 'inactive';
|
|
87
|
-
},
|
|
88
|
-
subscribe(listener) {
|
|
89
|
-
if (typeof document === 'undefined' || typeof window === 'undefined')
|
|
90
|
-
return () => { };
|
|
91
|
-
// Initialize focus state at subscribe time.
|
|
92
|
-
_windowFocused = document.hasFocus();
|
|
93
|
-
const onFocus = () => {
|
|
94
|
-
_windowFocused = true;
|
|
95
|
-
listener();
|
|
96
|
-
};
|
|
97
|
-
const onBlur = () => {
|
|
98
|
-
_windowFocused = false;
|
|
99
|
-
listener();
|
|
100
|
-
};
|
|
101
|
-
document.addEventListener('visibilitychange', listener);
|
|
102
|
-
window.addEventListener('pagehide', listener);
|
|
103
|
-
window.addEventListener('pageshow', listener);
|
|
104
|
-
window.addEventListener('focus', onFocus);
|
|
105
|
-
window.addEventListener('blur', onBlur);
|
|
106
|
-
return () => {
|
|
107
|
-
document.removeEventListener('visibilitychange', listener);
|
|
108
|
-
window.removeEventListener('pagehide', listener);
|
|
109
|
-
window.removeEventListener('pageshow', listener);
|
|
110
|
-
window.removeEventListener('focus', onFocus);
|
|
111
|
-
window.removeEventListener('blur', onBlur);
|
|
112
|
-
};
|
|
113
|
-
},
|
|
114
|
-
getLaunchKind() {
|
|
115
|
-
// PerformanceNavigationTiming.type === 'back_forward' indicates the page was restored from the
|
|
116
|
-
// browser's back/forward cache (bfcache). The JS heap was frozen and thawed without a fresh
|
|
117
|
-
// process start — the closest analog to a mobile warm-resume. All other navigation types
|
|
118
|
-
// ('navigate', 'reload', 'prerender') are a fresh page lifecycle, i.e. cold.
|
|
119
|
-
if (typeof performance === 'undefined')
|
|
120
|
-
return 'cold';
|
|
121
|
-
const entries = performance.getEntriesByType('navigation');
|
|
122
|
-
if (entries.length > 0 && entries[0].type === 'back_forward')
|
|
123
|
-
return 'warm';
|
|
124
|
-
return 'cold';
|
|
125
|
-
},
|
|
126
|
-
subscribeMemoryWarning(listener) {
|
|
127
|
-
// The 'memory-pressure' window event is an experimental Chrome API (origin trial / behind
|
|
128
|
-
// flags as of 2026). The event carries a detail object with a 'pressure' string. This backend
|
|
129
|
-
// maps 'critical' pressure to AppMemoryPressure 'critical'; a pressure-resolved / 'moderate'
|
|
130
|
-
// event maps to 'moderate'. Falls back to no-op unsubscribe when the event is not supported
|
|
131
|
-
// (no cross-browser API for memory pressure is widely deployed yet).
|
|
132
|
-
if (typeof window === 'undefined')
|
|
133
|
-
return () => { };
|
|
134
|
-
// Feature-detect: attempt to register and immediately remove a passive listener to check
|
|
135
|
-
// whether the event is supported. If addEventListener silently ignores the event type there
|
|
136
|
-
// is nothing we can do — we just return no-op without pretending to be subscribed.
|
|
137
|
-
const onPressure = (e) => {
|
|
138
|
-
const detail = e.detail;
|
|
139
|
-
const pressure = detail?.pressure;
|
|
140
|
-
if (pressure === 'critical') {
|
|
141
|
-
listener('critical');
|
|
142
|
-
}
|
|
143
|
-
else if (pressure === 'moderate') {
|
|
144
|
-
listener('moderate');
|
|
145
|
-
}
|
|
146
|
-
else {
|
|
147
|
-
// Unknown pressure level — treat as moderate rather than silently dropping.
|
|
148
|
-
listener('moderate');
|
|
149
|
-
}
|
|
150
|
-
};
|
|
151
|
-
const onPressureRelieved = () => {
|
|
152
|
-
listener('normal');
|
|
153
|
-
};
|
|
154
|
-
window.addEventListener('memory-pressure', onPressure);
|
|
155
|
-
window.addEventListener('memory-pressure-relieved', onPressureRelieved);
|
|
156
|
-
return () => {
|
|
157
|
-
window.removeEventListener('memory-pressure', onPressure);
|
|
158
|
-
window.removeEventListener('memory-pressure-relieved', onPressureRelieved);
|
|
159
|
-
};
|
|
160
|
-
},
|
|
161
|
-
});
|
|
55
|
+
const out = allocateEntity();
|
|
56
|
+
initializeWebLifecycleBackend(out);
|
|
57
|
+
return finishEntity(out);
|
|
162
58
|
}
|
|
163
59
|
// Stops delivery to `app` and forgets its subscription. Safe to call when not attached.
|
|
164
60
|
export function detachAppLifecycle(app) {
|
|
@@ -200,6 +96,116 @@ export function getAppLifecycleState(host) {
|
|
|
200
96
|
export function hasLifecycleOperation(host, operation) {
|
|
201
97
|
return explainLifecycleOperation(host, operation).implemented;
|
|
202
98
|
}
|
|
99
|
+
// Allocates an AppLifecycle event entity with inert signals; call attachAppLifecycle to start delivery.
|
|
100
|
+
export function initializeAppLifecycle(out) {
|
|
101
|
+
out.onStateChange = createSignal();
|
|
102
|
+
out.onResume = createSignal();
|
|
103
|
+
out.onPause = createSignal();
|
|
104
|
+
out.onBackButton = createSignal();
|
|
105
|
+
out.onMemoryWarning = createSignal();
|
|
106
|
+
out.onSaveState = createSignal();
|
|
107
|
+
out.onRestoreState = createSignal();
|
|
108
|
+
}
|
|
109
|
+
// Builds the default web backend over document visibility, window focus/blur, and pagehide/pageshow
|
|
110
|
+
// events. Produces three states:
|
|
111
|
+
// 'active' — document visible and window focused
|
|
112
|
+
// 'inactive' — document visible but window not focused (app switcher, control-center, other window)
|
|
113
|
+
// 'background' — document.hidden (tab hidden or page unloading)
|
|
114
|
+
// Degrades to state 'active' and a no-op subscription where document/window are absent (SSR/jsdom).
|
|
115
|
+
//
|
|
116
|
+
// getLaunchKind() approximates cold vs. warm using PerformanceNavigationTiming.type:
|
|
117
|
+
// 'back_forward' → 'warm' — page was restored from the bfcache (JS heap was frozen and thawed;
|
|
118
|
+
// the closest web equivalent of a process warm-resume)
|
|
119
|
+
// all others → 'cold' — 'navigate', 'reload', 'prerender' are each a fresh page lifecycle
|
|
120
|
+
// Falls back to 'cold' when the Performance Navigation Timing API is unavailable (SSR/jsdom).
|
|
121
|
+
//
|
|
122
|
+
// subscribeMemoryWarning() wires the experimental 'memory-pressure' window event (Chrome origin
|
|
123
|
+
// trial / behind flags). The event detail carries a 'critical' pressure string; this backend maps
|
|
124
|
+
// it to 'critical' and fires 'normal' on the subsequent resolution event when present. Falls back to
|
|
125
|
+
// no-op unsubscribe when the event is not supported (no standard API is widely deployed as of 2026).
|
|
126
|
+
export function initializeWebLifecycleBackend(out) {
|
|
127
|
+
let _windowFocused = typeof document !== 'undefined';
|
|
128
|
+
out.getState = () => {
|
|
129
|
+
if (typeof document === 'undefined')
|
|
130
|
+
return 'active';
|
|
131
|
+
if (document.hidden)
|
|
132
|
+
return 'background';
|
|
133
|
+
return _windowFocused ? 'active' : 'inactive';
|
|
134
|
+
};
|
|
135
|
+
out.subscribe = (listener) => {
|
|
136
|
+
if (typeof document === 'undefined' || typeof window === 'undefined')
|
|
137
|
+
return () => { };
|
|
138
|
+
// Initialize focus state at subscribe time.
|
|
139
|
+
_windowFocused = document.hasFocus();
|
|
140
|
+
const onFocus = () => {
|
|
141
|
+
_windowFocused = true;
|
|
142
|
+
listener();
|
|
143
|
+
};
|
|
144
|
+
const onBlur = () => {
|
|
145
|
+
_windowFocused = false;
|
|
146
|
+
listener();
|
|
147
|
+
};
|
|
148
|
+
document.addEventListener('visibilitychange', listener);
|
|
149
|
+
window.addEventListener('pagehide', listener);
|
|
150
|
+
window.addEventListener('pageshow', listener);
|
|
151
|
+
window.addEventListener('focus', onFocus);
|
|
152
|
+
window.addEventListener('blur', onBlur);
|
|
153
|
+
return () => {
|
|
154
|
+
document.removeEventListener('visibilitychange', listener);
|
|
155
|
+
window.removeEventListener('pagehide', listener);
|
|
156
|
+
window.removeEventListener('pageshow', listener);
|
|
157
|
+
window.removeEventListener('focus', onFocus);
|
|
158
|
+
window.removeEventListener('blur', onBlur);
|
|
159
|
+
};
|
|
160
|
+
};
|
|
161
|
+
out.getLaunchKind = () => {
|
|
162
|
+
// PerformanceNavigationTiming.type === 'back_forward' indicates the page was restored from the
|
|
163
|
+
// browser's back/forward cache (bfcache). The JS heap was frozen and thawed without a fresh
|
|
164
|
+
// process start — the closest analog to a mobile warm-resume. All other navigation types
|
|
165
|
+
// ('navigate', 'reload', 'prerender') are a fresh page lifecycle, i.e. cold.
|
|
166
|
+
if (typeof performance === 'undefined')
|
|
167
|
+
return 'cold';
|
|
168
|
+
const entries = performance.getEntriesByType('navigation');
|
|
169
|
+
if (entries.length > 0 && entries[0].type === 'back_forward')
|
|
170
|
+
return 'warm';
|
|
171
|
+
return 'cold';
|
|
172
|
+
};
|
|
173
|
+
out.subscribeMemoryWarning = (listener) => {
|
|
174
|
+
// The 'memory-pressure' window event is an experimental Chrome API (origin trial / behind
|
|
175
|
+
// flags as of 2026). The event carries a detail object with a 'pressure' string. This backend
|
|
176
|
+
// maps 'critical' pressure to AppMemoryPressure 'critical'; a pressure-resolved / 'moderate'
|
|
177
|
+
// event maps to 'moderate'. Falls back to no-op unsubscribe when the event is not supported
|
|
178
|
+
// (no cross-browser API for memory pressure is widely deployed yet).
|
|
179
|
+
if (typeof window === 'undefined')
|
|
180
|
+
return () => { };
|
|
181
|
+
// Feature-detect: attempt to register and immediately remove a passive listener to check
|
|
182
|
+
// whether the event is supported. If addEventListener silently ignores the event type there
|
|
183
|
+
// is nothing we can do — we just return no-op without pretending to be subscribed.
|
|
184
|
+
const onPressure = (e) => {
|
|
185
|
+
const detail = e.detail;
|
|
186
|
+
const pressure = detail?.pressure;
|
|
187
|
+
if (pressure === 'critical') {
|
|
188
|
+
listener('critical');
|
|
189
|
+
}
|
|
190
|
+
else if (pressure === 'moderate') {
|
|
191
|
+
listener('moderate');
|
|
192
|
+
}
|
|
193
|
+
else {
|
|
194
|
+
// Unknown pressure level — treat as moderate rather than silently dropping.
|
|
195
|
+
listener('moderate');
|
|
196
|
+
}
|
|
197
|
+
};
|
|
198
|
+
const onPressureRelieved = () => {
|
|
199
|
+
listener('normal');
|
|
200
|
+
};
|
|
201
|
+
window.addEventListener('memory-pressure', onPressure);
|
|
202
|
+
window.addEventListener('memory-pressure-relieved', onPressureRelieved);
|
|
203
|
+
return () => {
|
|
204
|
+
window.removeEventListener('memory-pressure', onPressure);
|
|
205
|
+
window.removeEventListener('memory-pressure-relieved', onPressureRelieved);
|
|
206
|
+
};
|
|
207
|
+
};
|
|
208
|
+
}
|
|
203
209
|
// Returns true when the application is in the 'active' state (visible and focused).
|
|
204
210
|
export function isAppActive(host) {
|
|
205
211
|
return host.system.lifecycle.getState() === 'active';
|
package/dist/lifecycle.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lifecycle.js","sourceRoot":"","sources":["../src/lifecycle.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;
|
|
1
|
+
{"version":3,"file":"lifecycle.js","sourceRoot":"","sources":["../src/lifecycle.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@flighthq/lifecycle",
|
|
3
|
-
"version": "0.5.1-edge.
|
|
3
|
+
"version": "0.5.1-edge.911.32a089f",
|
|
4
4
|
"author": "Joshua Granick and other contributors",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -38,9 +38,9 @@
|
|
|
38
38
|
"clean:dist": "tsx ../../scripts/clean-package-dist.ts"
|
|
39
39
|
},
|
|
40
40
|
"dependencies": {
|
|
41
|
-
"@flighthq/entity": "0.5.1-edge.
|
|
42
|
-
"@flighthq/signals": "0.5.1-edge.
|
|
43
|
-
"@flighthq/types": "0.5.1-edge.
|
|
41
|
+
"@flighthq/entity": "0.5.1-edge.911.32a089f",
|
|
42
|
+
"@flighthq/signals": "0.5.1-edge.911.32a089f",
|
|
43
|
+
"@flighthq/types": "0.5.1-edge.911.32a089f"
|
|
44
44
|
},
|
|
45
45
|
"devDependencies": {
|
|
46
46
|
"typescript": "^5.3.0"
|
package/src/lifecycle.test.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { allocateEntity, finishEntity } from '@flighthq/entity/contract';
|
|
2
2
|
import { cancelSignal, connectSignal } from '@flighthq/signals/contract';
|
|
3
3
|
import type {
|
|
4
4
|
HasSystemLifecycle,
|
|
5
|
+
AppLaunchKind,
|
|
5
6
|
AppLifecycleState,
|
|
6
7
|
AppMemoryPressure,
|
|
7
8
|
Entity,
|
|
@@ -19,6 +20,8 @@ import {
|
|
|
19
20
|
getAppLaunchKind,
|
|
20
21
|
getAppLifecycleState,
|
|
21
22
|
hasLifecycleOperation,
|
|
23
|
+
initializeAppLifecycle,
|
|
24
|
+
initializeWebLifecycleBackend,
|
|
22
25
|
isAppActive,
|
|
23
26
|
isAppBackground,
|
|
24
27
|
isAppInactive,
|
|
@@ -38,30 +41,30 @@ function hostOf(backend: LifecycleBackend): HasSystemLifecycle {
|
|
|
38
41
|
function fakeBackend(): FakeBackend {
|
|
39
42
|
let stateListener: (() => void) | null = null;
|
|
40
43
|
let memoryListener: ((level: AppMemoryPressure) => void) | null = null;
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
44
|
+
const out = allocateEntity<FakeBackend>();
|
|
45
|
+
out.state = 'active' as AppLifecycleState;
|
|
46
|
+
out.getState = () => {
|
|
47
|
+
return out.state;
|
|
48
|
+
};
|
|
49
|
+
out.subscribe = (l: () => void) => {
|
|
50
|
+
stateListener = l;
|
|
51
|
+
return () => {
|
|
52
|
+
stateListener = null;
|
|
53
|
+
};
|
|
54
|
+
};
|
|
55
|
+
out.subscribeMemoryWarning = (l: (level: AppMemoryPressure) => void) => {
|
|
56
|
+
memoryListener = l;
|
|
57
|
+
return () => {
|
|
58
|
+
memoryListener = null;
|
|
59
|
+
};
|
|
60
|
+
};
|
|
61
|
+
out.fire = () => {
|
|
62
|
+
stateListener?.();
|
|
63
|
+
};
|
|
64
|
+
out.fireMemory = (level: AppMemoryPressure) => {
|
|
65
|
+
memoryListener?.(level);
|
|
66
|
+
};
|
|
67
|
+
return finishEntity(out);
|
|
65
68
|
}
|
|
66
69
|
|
|
67
70
|
describe('attachAppLifecycle', () => {
|
|
@@ -456,7 +459,14 @@ describe('explainLifecycleOperation', () => {
|
|
|
456
459
|
});
|
|
457
460
|
|
|
458
461
|
it('reports an operation the host provider omits as unimplemented', () => {
|
|
459
|
-
const host = hostOf(
|
|
462
|
+
const host = hostOf(
|
|
463
|
+
(() => {
|
|
464
|
+
const out = allocateEntity<LifecycleBackend>();
|
|
465
|
+
out.getState = () => 'active' as const;
|
|
466
|
+
out.subscribe = () => () => {};
|
|
467
|
+
return finishEntity(out);
|
|
468
|
+
})(),
|
|
469
|
+
);
|
|
460
470
|
expect(explainLifecycleOperation(host, 'getLaunchKind')).toEqual({
|
|
461
471
|
implemented: false,
|
|
462
472
|
layer: 'sentinel',
|
|
@@ -468,7 +478,14 @@ describe('explainLifecycleOperation', () => {
|
|
|
468
478
|
// process-wide backend answered for every caller.
|
|
469
479
|
it('answers per host rather than process-wide', () => {
|
|
470
480
|
const rich = hostOf(fakeBackend());
|
|
471
|
-
const bare = hostOf(
|
|
481
|
+
const bare = hostOf(
|
|
482
|
+
(() => {
|
|
483
|
+
const out = allocateEntity<LifecycleBackend>();
|
|
484
|
+
out.getState = () => 'active' as const;
|
|
485
|
+
out.subscribe = () => () => {};
|
|
486
|
+
return finishEntity(out);
|
|
487
|
+
})(),
|
|
488
|
+
);
|
|
472
489
|
expect(explainLifecycleOperation(rich, 'subscribeMemoryWarning').implemented).toBe(true);
|
|
473
490
|
expect(explainLifecycleOperation(bare, 'subscribeMemoryWarning').implemented).toBe(false);
|
|
474
491
|
});
|
|
@@ -482,11 +499,11 @@ describe('getAppLaunchKind', () => {
|
|
|
482
499
|
});
|
|
483
500
|
|
|
484
501
|
it('delegates to backend.getLaunchKind when present', () => {
|
|
485
|
-
const
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
502
|
+
const out = allocateEntity<LifecycleBackend>();
|
|
503
|
+
out.getState = () => 'active' as AppLifecycleState;
|
|
504
|
+
out.subscribe = () => () => {};
|
|
505
|
+
out.getLaunchKind = () => 'cold' as AppLaunchKind;
|
|
506
|
+
const backend = finishEntity(out);
|
|
490
507
|
const host = hostOf(backend);
|
|
491
508
|
expect(getAppLaunchKind(host)).toBe('cold');
|
|
492
509
|
});
|
|
@@ -508,11 +525,43 @@ describe('hasLifecycleOperation', () => {
|
|
|
508
525
|
});
|
|
509
526
|
|
|
510
527
|
it('is false for an operation the host provider omits', () => {
|
|
511
|
-
const host = hostOf(
|
|
528
|
+
const host = hostOf(
|
|
529
|
+
(() => {
|
|
530
|
+
const out = allocateEntity<LifecycleBackend>();
|
|
531
|
+
out.getState = () => 'active' as const;
|
|
532
|
+
out.subscribe = () => () => {};
|
|
533
|
+
return finishEntity(out);
|
|
534
|
+
})(),
|
|
535
|
+
);
|
|
512
536
|
expect(hasLifecycleOperation(host, 'getLaunchKind')).toBe(false);
|
|
513
537
|
});
|
|
514
538
|
});
|
|
515
539
|
|
|
540
|
+
describe('initializeAppLifecycle', () => {
|
|
541
|
+
it('is the construction initializer of createAppLifecycle', () => {
|
|
542
|
+
expect(typeof initializeAppLifecycle).toBe('function');
|
|
543
|
+
});
|
|
544
|
+
});
|
|
545
|
+
|
|
546
|
+
describe('initializeWebLifecycleBackend', () => {
|
|
547
|
+
it('is the construction initializer of createWebLifecycleBackend', () => {
|
|
548
|
+
expect(typeof initializeWebLifecycleBackend).toBe('function');
|
|
549
|
+
});
|
|
550
|
+
});
|
|
551
|
+
|
|
552
|
+
// Per-operation availability for LifecycleBackend. The operations below are the ones the interface declares
|
|
553
|
+
// OPTIONAL, so a host that omits them is compliant rather than broken — that is the absence-of-an-export
|
|
554
|
+
// ruling, and this is the query that makes it observable.
|
|
555
|
+
const OPTIONAL_OPERATIONS: readonly LifecycleOperation[] = ['getLaunchKind', 'subscribeMemoryWarning'];
|
|
556
|
+
|
|
557
|
+
// A host implementing only the REQUIRED members — partial support declared by absence.
|
|
558
|
+
function partialBackend(): LifecycleBackend {
|
|
559
|
+
const out = allocateEntity<LifecycleBackend>();
|
|
560
|
+
out.getState = (() => undefined) as never;
|
|
561
|
+
out.subscribe = (() => undefined) as never;
|
|
562
|
+
return finishEntity(out);
|
|
563
|
+
}
|
|
564
|
+
|
|
516
565
|
describe('isAppActive', () => {
|
|
517
566
|
it("returns true when state is 'active'", () => {
|
|
518
567
|
const backend = fakeBackend();
|
|
@@ -551,20 +600,6 @@ describe('isAppBackground', () => {
|
|
|
551
600
|
expect(isAppBackground(host)).toBe(false);
|
|
552
601
|
});
|
|
553
602
|
});
|
|
554
|
-
|
|
555
|
-
// Per-operation availability for LifecycleBackend. The operations below are the ones the interface declares
|
|
556
|
-
// OPTIONAL, so a host that omits them is compliant rather than broken — that is the absence-of-an-export
|
|
557
|
-
// ruling, and this is the query that makes it observable.
|
|
558
|
-
const OPTIONAL_OPERATIONS: readonly LifecycleOperation[] = ['getLaunchKind', 'subscribeMemoryWarning'];
|
|
559
|
-
|
|
560
|
-
// A host implementing only the REQUIRED members — partial support declared by absence.
|
|
561
|
-
function partialBackend(): LifecycleBackend {
|
|
562
|
-
return createEntity({
|
|
563
|
-
getState: (() => undefined) as never,
|
|
564
|
-
subscribe: (() => undefined) as never,
|
|
565
|
-
});
|
|
566
|
-
}
|
|
567
|
-
|
|
568
603
|
describe('isAppInactive', () => {
|
|
569
604
|
it("returns true when state is 'inactive'", () => {
|
|
570
605
|
const backend = fakeBackend();
|