@egen-civitas/esm-platform 0.0.0-stage → 1.2.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.
Files changed (56) hide show
  1. package/CHANGELOG.md +29 -0
  2. package/README.md +117 -2
  3. package/dist/adapters/web/camera.d.ts +10 -0
  4. package/dist/adapters/web/camera.js +31 -0
  5. package/dist/adapters/web/file-registry.d.ts +7 -0
  6. package/dist/adapters/web/file-registry.js +26 -0
  7. package/dist/adapters/web/files.d.ts +7 -0
  8. package/dist/adapters/web/files.js +22 -0
  9. package/dist/adapters/web/index.d.ts +9 -0
  10. package/dist/adapters/web/index.js +9 -0
  11. package/dist/adapters/web/lifecycle.d.ts +3 -0
  12. package/dist/adapters/web/lifecycle.js +20 -0
  13. package/dist/adapters/web/open-external.d.ts +8 -0
  14. package/dist/adapters/web/open-external.js +32 -0
  15. package/dist/adapters/web/permissions.d.ts +12 -0
  16. package/dist/adapters/web/permissions.js +48 -0
  17. package/dist/adapters/web/pick-files.d.ts +17 -0
  18. package/dist/adapters/web/pick-files.js +49 -0
  19. package/dist/adapters/web/session.d.ts +12 -0
  20. package/dist/adapters/web/session.js +19 -0
  21. package/dist/adapters/web/web-adapter.test.js +1233 -0
  22. package/dist/bridge/client.d.ts +48 -0
  23. package/dist/bridge/client.js +212 -0
  24. package/dist/bridge/client.test.js +1264 -0
  25. package/dist/bridge/index.d.ts +4 -0
  26. package/dist/bridge/index.js +2 -0
  27. package/dist/bridge/protocol.d.ts +72 -0
  28. package/dist/bridge/protocol.js +66 -0
  29. package/dist/bridge/protocol.test.js +215 -0
  30. package/dist/capabilities.d.ts +34 -0
  31. package/dist/capabilities.js +48 -0
  32. package/dist/detect.d.ts +25 -0
  33. package/dist/detect.js +38 -0
  34. package/dist/detect.test.js +23 -0
  35. package/dist/errors.d.ts +27 -0
  36. package/dist/errors.js +27 -0
  37. package/dist/errors.test.js +31 -0
  38. package/dist/index.d.ts +6 -0
  39. package/dist/index.js +14 -0
  40. package/dist/native-platform.test.js +329 -0
  41. package/dist/native.d.ts +24 -0
  42. package/dist/native.js +46 -0
  43. package/dist/platform.d.ts +24 -0
  44. package/dist/platform.js +56 -0
  45. package/dist/platform.test.js +696 -0
  46. package/dist/register-capabilities.test.js +188 -0
  47. package/dist/registry.d.ts +52 -0
  48. package/dist/registry.js +101 -0
  49. package/dist/registry.test.js +681 -0
  50. package/dist/testing/index.d.ts +23 -0
  51. package/dist/testing/index.js +14 -0
  52. package/dist/testing/mock-host.d.ts +49 -0
  53. package/dist/testing/mock-host.js +86 -0
  54. package/dist/types.d.ts +108 -0
  55. package/dist/types.js +1 -0
  56. package/package.json +57 -3
@@ -0,0 +1,329 @@
1
+ function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {
2
+ try {
3
+ var info = gen[key](arg);
4
+ var value = info.value;
5
+ } catch (error) {
6
+ reject(error);
7
+ return;
8
+ }
9
+ if (info.done) {
10
+ resolve(value);
11
+ } else {
12
+ Promise.resolve(value).then(_next, _throw);
13
+ }
14
+ }
15
+ function _async_to_generator(fn) {
16
+ return function() {
17
+ var self = this, args = arguments;
18
+ return new Promise(function(resolve, reject) {
19
+ var gen = fn.apply(self, args);
20
+ function _next(value) {
21
+ asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value);
22
+ }
23
+ function _throw(err) {
24
+ asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err);
25
+ }
26
+ _next(undefined);
27
+ });
28
+ };
29
+ }
30
+ function _ts_generator(thisArg, body) {
31
+ var f, y, t, _ = {
32
+ label: 0,
33
+ sent: function() {
34
+ if (t[0] & 1) throw t[1];
35
+ return t[1];
36
+ },
37
+ trys: [],
38
+ ops: []
39
+ }, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype), d = Object.defineProperty;
40
+ return d(g, "next", {
41
+ value: verb(0)
42
+ }), d(g, "throw", {
43
+ value: verb(1)
44
+ }), d(g, "return", {
45
+ value: verb(2)
46
+ }), typeof Symbol === "function" && d(g, Symbol.iterator, {
47
+ value: function() {
48
+ return this;
49
+ }
50
+ }), g;
51
+ function verb(n) {
52
+ return function(v) {
53
+ return step([
54
+ n,
55
+ v
56
+ ]);
57
+ };
58
+ }
59
+ function step(op) {
60
+ if (f) throw new TypeError("Generator is already executing.");
61
+ while(g && (g = 0, op[0] && (_ = 0)), _)try {
62
+ if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
63
+ if (y = 0, t) op = [
64
+ op[0] & 2,
65
+ t.value
66
+ ];
67
+ switch(op[0]){
68
+ case 0:
69
+ case 1:
70
+ t = op;
71
+ break;
72
+ case 4:
73
+ _.label++;
74
+ return {
75
+ value: op[1],
76
+ done: false
77
+ };
78
+ case 5:
79
+ _.label++;
80
+ y = op[1];
81
+ op = [
82
+ 0
83
+ ];
84
+ continue;
85
+ case 7:
86
+ op = _.ops.pop();
87
+ _.trys.pop();
88
+ continue;
89
+ default:
90
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) {
91
+ _ = 0;
92
+ continue;
93
+ }
94
+ if (op[0] === 3 && (!t || op[1] > t[0] && op[1] < t[3])) {
95
+ _.label = op[1];
96
+ break;
97
+ }
98
+ if (op[0] === 6 && _.label < t[1]) {
99
+ _.label = t[1];
100
+ t = op;
101
+ break;
102
+ }
103
+ if (t && _.label < t[2]) {
104
+ _.label = t[2];
105
+ _.ops.push(op);
106
+ break;
107
+ }
108
+ if (t[2]) _.ops.pop();
109
+ _.trys.pop();
110
+ continue;
111
+ }
112
+ op = body.call(thisArg, _);
113
+ } catch (e) {
114
+ op = [
115
+ 6,
116
+ e
117
+ ];
118
+ y = 0;
119
+ } finally{
120
+ f = t = 0;
121
+ }
122
+ if (op[0] & 5) throw op[1];
123
+ return {
124
+ value: op[0] ? op[1] : void 0,
125
+ done: true
126
+ };
127
+ }
128
+ }
129
+ import { afterEach, describe, expect, it } from 'vitest';
130
+ import { getHostInfo, getPlatform, registerPlatformCapabilities } from './index';
131
+ import { createMockHost } from './testing';
132
+ afterEach(function() {
133
+ var w = window;
134
+ delete w.egenTarget;
135
+ delete w.egenHostBridge;
136
+ });
137
+ describe('getPlatform() natif — handshake avec le Host', function() {
138
+ it('ready attend le handshake ; getHostInfo() expose ce que le Host a annoncé', function() {
139
+ return _async_to_generator(function() {
140
+ var host;
141
+ return _ts_generator(this, function(_state) {
142
+ switch(_state.label){
143
+ case 0:
144
+ window.egenTarget = 'android';
145
+ host = createMockHost({
146
+ host: '4.2.0',
147
+ capabilities: {
148
+ secureStorage: {
149
+ v: 1
150
+ }
151
+ }
152
+ });
153
+ host.install();
154
+ expect(getHostInfo()).toBeNull(); // pas encore de handshake
155
+ return [
156
+ 4,
157
+ getPlatform().ready
158
+ ];
159
+ case 1:
160
+ _state.sent();
161
+ expect(getHostInfo()).toEqual({
162
+ protocol: 1,
163
+ host: '4.2.0',
164
+ platform: 'android',
165
+ capabilities: {
166
+ secureStorage: {
167
+ v: 1
168
+ }
169
+ }
170
+ });
171
+ return [
172
+ 2
173
+ ];
174
+ }
175
+ });
176
+ })();
177
+ });
178
+ it('plusieurs getPlatform() partagent UN SEUL handshake et UN SEUL abonnement', function() {
179
+ return _async_to_generator(function() {
180
+ var host;
181
+ return _ts_generator(this, function(_state) {
182
+ switch(_state.label){
183
+ case 0:
184
+ window.egenTarget = 'android';
185
+ host = createMockHost();
186
+ host.install();
187
+ return [
188
+ 4,
189
+ Promise.all([
190
+ getPlatform().ready,
191
+ getPlatform().ready,
192
+ getPlatform().ready
193
+ ])
194
+ ];
195
+ case 1:
196
+ _state.sent();
197
+ return [
198
+ 4,
199
+ getPlatform().ready
200
+ ];
201
+ case 2:
202
+ _state.sent();
203
+ expect(host.sent.filter(function(r) {
204
+ return r.m === 'hello';
205
+ })).toHaveLength(1);
206
+ expect(host.subscribeCount).toBe(1);
207
+ return [
208
+ 2
209
+ ];
210
+ }
211
+ });
212
+ })();
213
+ });
214
+ it('Host de version de protocole incompatible ⇒ ready rejette INCOMPATIBLE', function() {
215
+ return _async_to_generator(function() {
216
+ return _ts_generator(this, function(_state) {
217
+ switch(_state.label){
218
+ case 0:
219
+ window.egenTarget = 'ios';
220
+ createMockHost({
221
+ platform: 'ios',
222
+ protocol: 2
223
+ }).install();
224
+ return [
225
+ 4,
226
+ expect(getPlatform().ready).rejects.toMatchObject({
227
+ code: 'INCOMPATIBLE'
228
+ })
229
+ ];
230
+ case 1:
231
+ _state.sent();
232
+ expect(getHostInfo()).toBeNull();
233
+ return [
234
+ 2
235
+ ];
236
+ }
237
+ });
238
+ })();
239
+ });
240
+ it('Host qui annonce une autre plateforme que la cible du build ⇒ INCOMPATIBLE', function() {
241
+ return _async_to_generator(function() {
242
+ return _ts_generator(this, function(_state) {
243
+ switch(_state.label){
244
+ case 0:
245
+ window.egenTarget = 'ios';
246
+ createMockHost({
247
+ platform: 'android'
248
+ }).install();
249
+ return [
250
+ 4,
251
+ expect(getPlatform().ready).rejects.toMatchObject({
252
+ code: 'INCOMPATIBLE'
253
+ })
254
+ ];
255
+ case 1:
256
+ _state.sent();
257
+ return [
258
+ 2
259
+ ];
260
+ }
261
+ });
262
+ })();
263
+ });
264
+ it("tant que les adaptateurs natifs (C7) n'existent pas, aucune capacité n'est disponible — même annoncée par le Host", function() {
265
+ return _async_to_generator(function() {
266
+ var platform;
267
+ return _ts_generator(this, function(_state) {
268
+ switch(_state.label){
269
+ case 0:
270
+ window.egenTarget = 'android';
271
+ createMockHost({
272
+ capabilities: {
273
+ secureStorage: {
274
+ v: 1
275
+ },
276
+ session: {
277
+ v: 1
278
+ }
279
+ }
280
+ }).install();
281
+ platform = getPlatform();
282
+ return [
283
+ 4,
284
+ platform.ready
285
+ ];
286
+ case 1:
287
+ _state.sent();
288
+ expect(platform.has('secureStorage')).toBe(false);
289
+ return [
290
+ 4,
291
+ expect(platform.secureStorage.get('k')).rejects.toMatchObject({
292
+ code: 'UNAVAILABLE'
293
+ })
294
+ ];
295
+ case 2:
296
+ _state.sent();
297
+ return [
298
+ 2
299
+ ];
300
+ }
301
+ });
302
+ })();
303
+ });
304
+ it('registerPlatformCapabilities() attend le handshake natif', function() {
305
+ return _async_to_generator(function() {
306
+ var host;
307
+ return _ts_generator(this, function(_state) {
308
+ switch(_state.label){
309
+ case 0:
310
+ window.egenTarget = 'android';
311
+ host = createMockHost();
312
+ host.install();
313
+ return [
314
+ 4,
315
+ expect(registerPlatformCapabilities()).resolves.toBeUndefined()
316
+ ];
317
+ case 1:
318
+ _state.sent();
319
+ expect(host.sent.some(function(r) {
320
+ return r.m === 'hello';
321
+ })).toBe(true);
322
+ return [
323
+ 2
324
+ ];
325
+ }
326
+ });
327
+ })();
328
+ });
329
+ });
@@ -0,0 +1,24 @@
1
+ import { type BridgeClient, type HostInfo } from './bridge/client.js';
2
+ import type { HostBridge } from './bridge/protocol.js';
3
+ import type { CapabilityOverrides } from './capabilities.js';
4
+ import type { PlatformEnvironment } from './types.js';
5
+ /**
6
+ * Client du pont donné. `getPlatform()` est appelé plusieurs fois (démarrage, apps) : sans ce partage, chaque appel
7
+ * referait un `subscribe` et un handshake. Un seul client par pont ⇒ un seul handshake (`hello()` est mémorisé : une
8
+ * incompatibilité reste rejetée, un échec passager comme un timeout peut être rejoué).
9
+ */
10
+ export declare function getNativeClient(bridge: HostBridge, environment: PlatformEnvironment): BridgeClient;
11
+ /**
12
+ * Capacités natives implémentées par le framework, branchées sur le client de pont : celles dont l'entrée du registre
13
+ * (`registry.ts`) déclare un adaptateur `native`. AUCUNE tant que les adaptateurs natifs (tâche C7) ne sont pas écrits :
14
+ * `has()` reste faux partout, même si le Host annonce la capacité — on ne promet jamais ce que le framework ne sait
15
+ * pas encore appeler.
16
+ */
17
+ export declare function createNativeCapabilities(client: BridgeClient): CapabilityOverrides;
18
+ /**
19
+ * Ce que le Host a annoncé au handshake (version de protocole, version du Host, capacités), ou `null` si le
20
+ * handshake n'a pas (encore) réussi. Utile au diagnostic et à la validation de compatibilité.
21
+ *
22
+ * @category Platform
23
+ */
24
+ export declare function getHostInfo(): HostInfo | null;
package/dist/native.js ADDED
@@ -0,0 +1,46 @@
1
+ import { createBridgeClient } from './bridge/client.js';
2
+ import { getHostBridge } from './detect.js';
3
+ import { createNativeCapabilitiesFromRegistry } from './registry.js';
4
+ /** Un client de pont par pont : ses abonnements et son handshake sont partagés par tous les `getPlatform()` de la page. */
5
+ const clients = new WeakMap();
6
+ function frameworkVersion() {
7
+ try {
8
+ // Remplacé à la compilation par le DefinePlugin du shell ; absent (ReferenceError) hors bundle.
9
+ return process.env.FRAMEWORK_VERSION || undefined;
10
+ }
11
+ catch {
12
+ return undefined;
13
+ }
14
+ }
15
+ /**
16
+ * Client du pont donné. `getPlatform()` est appelé plusieurs fois (démarrage, apps) : sans ce partage, chaque appel
17
+ * referait un `subscribe` et un handshake. Un seul client par pont ⇒ un seul handshake (`hello()` est mémorisé : une
18
+ * incompatibilité reste rejetée, un échec passager comme un timeout peut être rejoué).
19
+ */
20
+ export function getNativeClient(bridge, environment) {
21
+ let client = clients.get(bridge);
22
+ if (!client) {
23
+ client = createBridgeClient({ bridge, environment, framework: frameworkVersion() });
24
+ clients.set(bridge, client);
25
+ }
26
+ return client;
27
+ }
28
+ /**
29
+ * Capacités natives implémentées par le framework, branchées sur le client de pont : celles dont l'entrée du registre
30
+ * (`registry.ts`) déclare un adaptateur `native`. AUCUNE tant que les adaptateurs natifs (tâche C7) ne sont pas écrits :
31
+ * `has()` reste faux partout, même si le Host annonce la capacité — on ne promet jamais ce que le framework ne sait
32
+ * pas encore appeler.
33
+ */
34
+ export function createNativeCapabilities(client) {
35
+ return createNativeCapabilitiesFromRegistry(client);
36
+ }
37
+ /**
38
+ * Ce que le Host a annoncé au handshake (version de protocole, version du Host, capacités), ou `null` si le
39
+ * handshake n'a pas (encore) réussi. Utile au diagnostic et à la validation de compatibilité.
40
+ *
41
+ * @category Platform
42
+ */
43
+ export function getHostInfo() {
44
+ const bridge = getHostBridge();
45
+ return bridge ? (clients.get(bridge)?.hostInfo ?? null) : null;
46
+ }
@@ -0,0 +1,24 @@
1
+ import type { Platform } from './types.js';
2
+ /**
3
+ * Point d'accès unique des apps aux capacités de plateforme.
4
+ *
5
+ * La cible est fixée au build (`window.egenTarget`).
6
+ * - Web : capacités du navigateur (adaptateur C4), rien à attendre.
7
+ * - Natif : le Host DOIT avoir injecté `window.egenHostBridge` avant tout script de la page, sinon `ready` rejette
8
+ * `INCOMPATIBLE` (« Host manquant »). `ready` est le handshake de protocole (version, plateforme, capacités). Une
9
+ * capacité n'est disponible que si le Host l'annonce ET que le framework sait l'appeler : tant que les adaptateurs
10
+ * natifs (C7) ne sont pas écrits, `has()` est faux partout et chaque méthode rejette `UNAVAILABLE`.
11
+ *
12
+ * @category Platform
13
+ */
14
+ export declare function getPlatform(): Platform;
15
+ /**
16
+ * Rend les capacités de la plateforme consultables par le reste du framework (filtrage `requiredCapabilities`
17
+ * des apps, F2) et retourne `platform.ready`.
18
+ *
19
+ * À appeler UNE fois au démarrage, AVANT l'enregistrement des apps. Le résolveur est posé immédiatement : si `ready`
20
+ * rejette (natif sans Host), `has()` reste faux partout — aucune capacité n'est jamais supposée.
21
+ *
22
+ * @category Platform
23
+ */
24
+ export declare function registerPlatformCapabilities(platform?: Platform): Promise<void>;
@@ -0,0 +1,56 @@
1
+ import { setCapabilityResolver } from '@egen-civitas/esm-globals';
2
+ import { assemblePlatform } from './capabilities.js';
3
+ import { getHostBridge, getPlatformEnvironment } from './detect.js';
4
+ import { PlatformError } from './errors.js';
5
+ import { createNativeCapabilities, getNativeClient } from './native.js';
6
+ import { createWebCapabilities, isHostVersionSufficient } from './registry.js';
7
+ function hostMissing(environment) {
8
+ return new PlatformError('INCOMPATIBLE', `Host manquant : la cible "${environment}" exige que l'application hôte injecte window.egenHostBridge avant le chargement de la page.`);
9
+ }
10
+ /**
11
+ * Point d'accès unique des apps aux capacités de plateforme.
12
+ *
13
+ * La cible est fixée au build (`window.egenTarget`).
14
+ * - Web : capacités du navigateur (adaptateur C4), rien à attendre.
15
+ * - Natif : le Host DOIT avoir injecté `window.egenHostBridge` avant tout script de la page, sinon `ready` rejette
16
+ * `INCOMPATIBLE` (« Host manquant »). `ready` est le handshake de protocole (version, plateforme, capacités). Une
17
+ * capacité n'est disponible que si le Host l'annonce ET que le framework sait l'appeler : tant que les adaptateurs
18
+ * natifs (C7) ne sont pas écrits, `has()` est faux partout et chaque méthode rejette `UNAVAILABLE`.
19
+ *
20
+ * @category Platform
21
+ */
22
+ export function getPlatform() {
23
+ const environment = getPlatformEnvironment();
24
+ if (environment === 'web') {
25
+ return assemblePlatform({
26
+ environment,
27
+ capabilities: createWebCapabilities(),
28
+ ready: () => Promise.resolve(),
29
+ });
30
+ }
31
+ const bridge = getHostBridge();
32
+ if (!bridge) {
33
+ return assemblePlatform({ environment, ready: () => Promise.reject(hostMissing(environment)) });
34
+ }
35
+ const client = getNativeClient(bridge, environment);
36
+ return assemblePlatform({
37
+ environment,
38
+ capabilities: createNativeCapabilities(client),
39
+ ready: () => client.hello().then(() => undefined),
40
+ // Annoncée par le Host ET dans une version suffisante pour l'adaptateur de ce framework (registre).
41
+ available: (capability) => isHostVersionSufficient(capability, client.hostInfo?.capabilities[capability]?.v),
42
+ });
43
+ }
44
+ /**
45
+ * Rend les capacités de la plateforme consultables par le reste du framework (filtrage `requiredCapabilities`
46
+ * des apps, F2) et retourne `platform.ready`.
47
+ *
48
+ * À appeler UNE fois au démarrage, AVANT l'enregistrement des apps. Le résolveur est posé immédiatement : si `ready`
49
+ * rejette (natif sans Host), `has()` reste faux partout — aucune capacité n'est jamais supposée.
50
+ *
51
+ * @category Platform
52
+ */
53
+ export function registerPlatformCapabilities(platform = getPlatform()) {
54
+ setCapabilityResolver((capability) => platform.has(capability));
55
+ return platform.ready;
56
+ }