@egen-civitas/esm-platform 1.1.0 → 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.
@@ -0,0 +1,681 @@
1
+ function _array_like_to_array(arr, len) {
2
+ if (len == null || len > arr.length) len = arr.length;
3
+ for(var i = 0, arr2 = new Array(len); i < len; i++)arr2[i] = arr[i];
4
+ return arr2;
5
+ }
6
+ function _array_without_holes(arr) {
7
+ if (Array.isArray(arr)) return _array_like_to_array(arr);
8
+ }
9
+ function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {
10
+ try {
11
+ var info = gen[key](arg);
12
+ var value = info.value;
13
+ } catch (error) {
14
+ reject(error);
15
+ return;
16
+ }
17
+ if (info.done) {
18
+ resolve(value);
19
+ } else {
20
+ Promise.resolve(value).then(_next, _throw);
21
+ }
22
+ }
23
+ function _async_to_generator(fn) {
24
+ return function() {
25
+ var self = this, args = arguments;
26
+ return new Promise(function(resolve, reject) {
27
+ var gen = fn.apply(self, args);
28
+ function _next(value) {
29
+ asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value);
30
+ }
31
+ function _throw(err) {
32
+ asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err);
33
+ }
34
+ _next(undefined);
35
+ });
36
+ };
37
+ }
38
+ function _iterable_to_array(iter) {
39
+ if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter);
40
+ }
41
+ function _non_iterable_spread() {
42
+ throw new TypeError("Invalid attempt to spread non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
43
+ }
44
+ function _to_consumable_array(arr) {
45
+ return _array_without_holes(arr) || _iterable_to_array(arr) || _unsupported_iterable_to_array(arr) || _non_iterable_spread();
46
+ }
47
+ function _unsupported_iterable_to_array(o, minLen) {
48
+ if (!o) return;
49
+ if (typeof o === "string") return _array_like_to_array(o, minLen);
50
+ var n = Object.prototype.toString.call(o).slice(8, -1);
51
+ if (n === "Object" && o.constructor) n = o.constructor.name;
52
+ if (n === "Map" || n === "Set") return Array.from(n);
53
+ if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _array_like_to_array(o, minLen);
54
+ }
55
+ function _ts_generator(thisArg, body) {
56
+ var f, y, t, _ = {
57
+ label: 0,
58
+ sent: function() {
59
+ if (t[0] & 1) throw t[1];
60
+ return t[1];
61
+ },
62
+ trys: [],
63
+ ops: []
64
+ }, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype), d = Object.defineProperty;
65
+ return d(g, "next", {
66
+ value: verb(0)
67
+ }), d(g, "throw", {
68
+ value: verb(1)
69
+ }), d(g, "return", {
70
+ value: verb(2)
71
+ }), typeof Symbol === "function" && d(g, Symbol.iterator, {
72
+ value: function() {
73
+ return this;
74
+ }
75
+ }), g;
76
+ function verb(n) {
77
+ return function(v) {
78
+ return step([
79
+ n,
80
+ v
81
+ ]);
82
+ };
83
+ }
84
+ function step(op) {
85
+ if (f) throw new TypeError("Generator is already executing.");
86
+ while(g && (g = 0, op[0] && (_ = 0)), _)try {
87
+ 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;
88
+ if (y = 0, t) op = [
89
+ op[0] & 2,
90
+ t.value
91
+ ];
92
+ switch(op[0]){
93
+ case 0:
94
+ case 1:
95
+ t = op;
96
+ break;
97
+ case 4:
98
+ _.label++;
99
+ return {
100
+ value: op[1],
101
+ done: false
102
+ };
103
+ case 5:
104
+ _.label++;
105
+ y = op[1];
106
+ op = [
107
+ 0
108
+ ];
109
+ continue;
110
+ case 7:
111
+ op = _.ops.pop();
112
+ _.trys.pop();
113
+ continue;
114
+ default:
115
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) {
116
+ _ = 0;
117
+ continue;
118
+ }
119
+ if (op[0] === 3 && (!t || op[1] > t[0] && op[1] < t[3])) {
120
+ _.label = op[1];
121
+ break;
122
+ }
123
+ if (op[0] === 6 && _.label < t[1]) {
124
+ _.label = t[1];
125
+ t = op;
126
+ break;
127
+ }
128
+ if (t && _.label < t[2]) {
129
+ _.label = t[2];
130
+ _.ops.push(op);
131
+ break;
132
+ }
133
+ if (t[2]) _.ops.pop();
134
+ _.trys.pop();
135
+ continue;
136
+ }
137
+ op = body.call(thisArg, _);
138
+ } catch (e) {
139
+ op = [
140
+ 6,
141
+ e
142
+ ];
143
+ y = 0;
144
+ } finally{
145
+ f = t = 0;
146
+ }
147
+ if (op[0] & 5) throw op[1];
148
+ return {
149
+ value: op[0] ? op[1] : void 0,
150
+ done: true
151
+ };
152
+ }
153
+ }
154
+ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
155
+ import { getPlatform, registerPlatformCapabilities } from './index';
156
+ import { getCapabilityDefinition, isHostVersionSufficient, isKnownCapability, listCapabilityNames, registerCapability, unregisterCapability } from './registry';
157
+ import { createMockHost, createMockPlatform } from './testing';
158
+ var w = window;
159
+ var V1 = [
160
+ 'session',
161
+ 'secureStorage',
162
+ 'openExternal',
163
+ 'lifecycle',
164
+ 'permissions',
165
+ 'files',
166
+ 'camera',
167
+ 'push',
168
+ 'biometric'
169
+ ];
170
+ function registerFictional() {
171
+ var overrides = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : {};
172
+ var _overrides_web = overrides.web, web = _overrides_web === void 0 ? true : _overrides_web, _overrides_native = overrides.native, native = _overrides_native === void 0 ? true : _overrides_native, _overrides_version = overrides.version, version = _overrides_version === void 0 ? 1 : _overrides_version;
173
+ registerCapability('fictional', {
174
+ version: version,
175
+ methods: {
176
+ ping: 'async',
177
+ onTick: 'subscribe'
178
+ },
179
+ web: web ? function() {
180
+ return {
181
+ ping: function ping(message) {
182
+ return _async_to_generator(function() {
183
+ return _ts_generator(this, function(_state) {
184
+ return [
185
+ 2,
186
+ "web:".concat(message)
187
+ ];
188
+ });
189
+ })();
190
+ }
191
+ };
192
+ } : undefined,
193
+ native: native ? function(client) {
194
+ return {
195
+ ping: function ping(message) {
196
+ return client.call('fictional', 'ping', {
197
+ message: message
198
+ });
199
+ },
200
+ onTick: function onTick(callback) {
201
+ return client.onEvent('fictional.tick', function() {
202
+ return callback();
203
+ });
204
+ }
205
+ };
206
+ } : undefined
207
+ });
208
+ }
209
+ beforeEach(function() {
210
+ delete w.egenTarget;
211
+ });
212
+ afterEach(function() {
213
+ unregisterCapability('fictional');
214
+ delete w.egenTarget;
215
+ delete w.egenHostBridge;
216
+ });
217
+ describe('registre : les 9 capacités v1', function() {
218
+ it('sont toutes enregistrées, avec leur version et leurs méthodes (contrat de l’annexe 2)', function() {
219
+ var _getCapabilityDefinition;
220
+ expect(listCapabilityNames().sort()).toEqual(_to_consumable_array(V1).sort());
221
+ var methods = function methods(name) {
222
+ var _getCapabilityDefinition;
223
+ return (_getCapabilityDefinition = getCapabilityDefinition(name)) === null || _getCapabilityDefinition === void 0 ? void 0 : _getCapabilityDefinition.methods;
224
+ };
225
+ expect(methods('session')).toEqual({
226
+ getAuthorization: 'async',
227
+ setTokens: 'async',
228
+ refresh: 'async',
229
+ clear: 'async'
230
+ });
231
+ expect(methods('secureStorage')).toEqual({
232
+ get: 'async',
233
+ set: 'async',
234
+ remove: 'async'
235
+ });
236
+ expect(methods('lifecycle')).toEqual({
237
+ onResume: 'subscribe',
238
+ onPause: 'subscribe'
239
+ });
240
+ expect(methods('push')).toEqual({
241
+ register: 'async',
242
+ onMessage: 'subscribe'
243
+ });
244
+ var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
245
+ try {
246
+ for(var _iterator = V1[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
247
+ var name = _step.value;
248
+ expect((_getCapabilityDefinition = getCapabilityDefinition(name)) === null || _getCapabilityDefinition === void 0 ? void 0 : _getCapabilityDefinition.version).toBe(1);
249
+ }
250
+ } catch (err) {
251
+ _didIteratorError = true;
252
+ _iteratorError = err;
253
+ } finally{
254
+ try {
255
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
256
+ _iterator.return();
257
+ }
258
+ } finally{
259
+ if (_didIteratorError) {
260
+ throw _iteratorError;
261
+ }
262
+ }
263
+ }
264
+ });
265
+ it('seules les capacités que le navigateur sait fournir ont un adaptateur Web ; aucune n’a d’adaptateur natif (C7)', function() {
266
+ var _getCapabilityDefinition;
267
+ var withWeb = V1.filter(function(name) {
268
+ var _getCapabilityDefinition;
269
+ return (_getCapabilityDefinition = getCapabilityDefinition(name)) === null || _getCapabilityDefinition === void 0 ? void 0 : _getCapabilityDefinition.web;
270
+ });
271
+ expect(withWeb.sort()).toEqual([
272
+ 'camera',
273
+ 'files',
274
+ 'lifecycle',
275
+ 'openExternal',
276
+ 'permissions',
277
+ 'session'
278
+ ]);
279
+ expect(V1.filter(function(name) {
280
+ var _getCapabilityDefinition;
281
+ return (_getCapabilityDefinition = getCapabilityDefinition(name)) === null || _getCapabilityDefinition === void 0 ? void 0 : _getCapabilityDefinition.native;
282
+ })).toEqual([]);
283
+ // Jamais de faux coffre, de push ni de biométrie simulés en Web.
284
+ for(var _i = 0, _iter = [
285
+ 'secureStorage',
286
+ 'push',
287
+ 'biometric'
288
+ ]; _i < _iter.length; _i++){
289
+ var name = _iter[_i];
290
+ expect((_getCapabilityDefinition = getCapabilityDefinition(name)) === null || _getCapabilityDefinition === void 0 ? void 0 : _getCapabilityDefinition.web).toBeUndefined();
291
+ }
292
+ });
293
+ });
294
+ describe('ajouter une capacité fictive : aucun fichier de production modifié', function() {
295
+ it('une capacité absente du registre est inconnue partout', function() {
296
+ expect(isKnownCapability('fictional')).toBe(false);
297
+ expect(Object.keys(getPlatform())).not.toContain('fictional');
298
+ });
299
+ it('gabarit « indisponible » : la capacité existe comme objet, méthodes en UNAVAILABLE (async rejette, abonnement lève)', function() {
300
+ return _async_to_generator(function() {
301
+ var platform;
302
+ return _ts_generator(this, function(_state) {
303
+ switch(_state.label){
304
+ case 0:
305
+ registerFictional({
306
+ web: false,
307
+ native: false
308
+ });
309
+ expect(isKnownCapability('fictional')).toBe(true);
310
+ w.egenTarget = 'android'; // natif sans Host : aucun adaptateur ne s'applique
311
+ platform = getPlatform();
312
+ expect(platform.has('fictional')).toBe(false);
313
+ return [
314
+ 4,
315
+ expect(platform.fictional.ping('x')).rejects.toMatchObject({
316
+ code: 'UNAVAILABLE',
317
+ capability: 'fictional',
318
+ method: 'ping'
319
+ })
320
+ ];
321
+ case 1:
322
+ _state.sent();
323
+ expect(function() {
324
+ return platform.fictional.onTick(function() {});
325
+ }).toThrowError(expect.objectContaining({
326
+ code: 'UNAVAILABLE',
327
+ capability: 'fictional',
328
+ method: 'onTick'
329
+ }));
330
+ return [
331
+ 2
332
+ ];
333
+ }
334
+ });
335
+ })();
336
+ });
337
+ it('Web : l’adaptateur du registre est branché par getPlatform(), has() devient vrai', function() {
338
+ return _async_to_generator(function() {
339
+ var platform;
340
+ return _ts_generator(this, function(_state) {
341
+ switch(_state.label){
342
+ case 0:
343
+ registerFictional();
344
+ platform = getPlatform();
345
+ expect(platform.has('fictional')).toBe(true);
346
+ return [
347
+ 4,
348
+ expect(platform.fictional.ping('salut')).resolves.toBe('web:salut')
349
+ ];
350
+ case 1:
351
+ _state.sent();
352
+ // Une méthode que l'adaptateur ne fournit pas reste UNAVAILABLE (pas de faux succès).
353
+ expect(function() {
354
+ return platform.fictional.onTick(function() {});
355
+ }).toThrowError(expect.objectContaining({
356
+ code: 'UNAVAILABLE'
357
+ }));
358
+ return [
359
+ 2
360
+ ];
361
+ }
362
+ });
363
+ })();
364
+ });
365
+ it('Web : une fabrique qui retourne undefined (navigateur incapable) laisse la capacité absente', function() {
366
+ registerCapability('fictional', {
367
+ version: 1,
368
+ methods: {
369
+ ping: 'async',
370
+ onTick: 'subscribe'
371
+ },
372
+ web: function web() {
373
+ return undefined;
374
+ }
375
+ });
376
+ expect(getPlatform().has('fictional')).toBe(false);
377
+ });
378
+ it('natif : le Host l’annonce et l’adaptateur appelle le pont ; événements relayés', function() {
379
+ return _async_to_generator(function() {
380
+ var host, platform, tick, off;
381
+ return _ts_generator(this, function(_state) {
382
+ switch(_state.label){
383
+ case 0:
384
+ registerFictional();
385
+ w.egenTarget = 'android';
386
+ host = createMockHost({
387
+ capabilities: {
388
+ fictional: {
389
+ v: 1
390
+ }
391
+ },
392
+ handlers: {
393
+ 'fictional.ping': function(args) {
394
+ return "host:".concat(args.message);
395
+ }
396
+ }
397
+ });
398
+ host.install();
399
+ platform = getPlatform();
400
+ return [
401
+ 4,
402
+ platform.ready
403
+ ];
404
+ case 1:
405
+ _state.sent();
406
+ expect(platform.has('fictional')).toBe(true);
407
+ return [
408
+ 4,
409
+ expect(platform.fictional.ping('salut')).resolves.toBe('host:salut')
410
+ ];
411
+ case 2:
412
+ _state.sent();
413
+ tick = vi.fn();
414
+ off = platform.fictional.onTick(tick);
415
+ host.emit('fictional.tick');
416
+ return [
417
+ 4,
418
+ Promise.resolve()
419
+ ];
420
+ case 3:
421
+ _state.sent();
422
+ expect(tick).toHaveBeenCalledTimes(1);
423
+ off();
424
+ return [
425
+ 2
426
+ ];
427
+ }
428
+ });
429
+ })();
430
+ });
431
+ it('natif : une capacité que le Host n’annonce pas reste indisponible, même avec un adaptateur', function() {
432
+ return _async_to_generator(function() {
433
+ var platform;
434
+ return _ts_generator(this, function(_state) {
435
+ switch(_state.label){
436
+ case 0:
437
+ registerFictional();
438
+ w.egenTarget = 'android';
439
+ createMockHost({
440
+ capabilities: {}
441
+ }).install();
442
+ platform = getPlatform();
443
+ return [
444
+ 4,
445
+ platform.ready
446
+ ];
447
+ case 1:
448
+ _state.sent();
449
+ expect(platform.has('fictional')).toBe(false);
450
+ return [
451
+ 4,
452
+ expect(platform.fictional.ping('x')).rejects.toMatchObject({
453
+ code: 'UNAVAILABLE'
454
+ })
455
+ ];
456
+ case 2:
457
+ _state.sent();
458
+ return [
459
+ 2
460
+ ];
461
+ }
462
+ });
463
+ })();
464
+ });
465
+ it('natif : une version de Host INFÉRIEURE à celle du framework rend la capacité indisponible', function() {
466
+ return _async_to_generator(function() {
467
+ var platform;
468
+ return _ts_generator(this, function(_state) {
469
+ switch(_state.label){
470
+ case 0:
471
+ registerFictional({
472
+ version: 2
473
+ });
474
+ w.egenTarget = 'android';
475
+ createMockHost({
476
+ capabilities: {
477
+ fictional: {
478
+ v: 1
479
+ }
480
+ }
481
+ }).install();
482
+ platform = getPlatform();
483
+ return [
484
+ 4,
485
+ platform.ready
486
+ ];
487
+ case 1:
488
+ _state.sent();
489
+ expect(platform.has('fictional')).toBe(false);
490
+ return [
491
+ 2
492
+ ];
493
+ }
494
+ });
495
+ })();
496
+ });
497
+ it('natif : une version de Host égale ou supérieure convient', function() {
498
+ return _async_to_generator(function() {
499
+ var platform;
500
+ return _ts_generator(this, function(_state) {
501
+ switch(_state.label){
502
+ case 0:
503
+ registerFictional({
504
+ version: 2
505
+ });
506
+ w.egenTarget = 'android';
507
+ createMockHost({
508
+ capabilities: {
509
+ fictional: {
510
+ v: 3
511
+ }
512
+ }
513
+ }).install();
514
+ platform = getPlatform();
515
+ return [
516
+ 4,
517
+ platform.ready
518
+ ];
519
+ case 1:
520
+ _state.sent();
521
+ expect(platform.has('fictional')).toBe(true);
522
+ return [
523
+ 2
524
+ ];
525
+ }
526
+ });
527
+ })();
528
+ });
529
+ it('handshake : une capacité fictive annoncée par le Host est retenue ; avant son enregistrement elle était ignorée', function() {
530
+ return _async_to_generator(function() {
531
+ var _ref, _getHostInfo, ignored, getHostInfo;
532
+ return _ts_generator(this, function(_state) {
533
+ switch(_state.label){
534
+ case 0:
535
+ w.egenTarget = 'android';
536
+ createMockHost({
537
+ capabilities: {
538
+ fictional: {
539
+ v: 1
540
+ },
541
+ session: {
542
+ v: 1
543
+ }
544
+ }
545
+ }).install();
546
+ ignored = getPlatform();
547
+ return [
548
+ 4,
549
+ ignored.ready
550
+ ];
551
+ case 1:
552
+ _state.sent();
553
+ return [
554
+ 4,
555
+ import('./index')
556
+ ];
557
+ case 2:
558
+ getHostInfo = _state.sent().getHostInfo;
559
+ expect(Object.keys((_ref = (_getHostInfo = getHostInfo()) === null || _getHostInfo === void 0 ? void 0 : _getHostInfo.capabilities) !== null && _ref !== void 0 ? _ref : {})).toEqual([
560
+ 'session'
561
+ ]);
562
+ return [
563
+ 2
564
+ ];
565
+ }
566
+ });
567
+ })();
568
+ });
569
+ it('mock : createMockPlatform fournit la capacité fictive et laisse le reste UNAVAILABLE', function() {
570
+ return _async_to_generator(function() {
571
+ var platform;
572
+ return _ts_generator(this, function(_state) {
573
+ switch(_state.label){
574
+ case 0:
575
+ registerFictional({
576
+ web: false,
577
+ native: false
578
+ });
579
+ platform = createMockPlatform({
580
+ capabilities: {
581
+ fictional: {
582
+ ping: function ping(m) {
583
+ return _async_to_generator(function() {
584
+ return _ts_generator(this, function(_state) {
585
+ return [
586
+ 2,
587
+ "mock:".concat(m)
588
+ ];
589
+ });
590
+ })();
591
+ }
592
+ }
593
+ }
594
+ });
595
+ expect(platform.has('fictional')).toBe(true);
596
+ return [
597
+ 4,
598
+ expect(platform.fictional.ping('x')).resolves.toBe('mock:x')
599
+ ];
600
+ case 1:
601
+ _state.sent();
602
+ expect(function() {
603
+ return platform.fictional.onTick(function() {});
604
+ }).toThrowError(expect.objectContaining({
605
+ code: 'UNAVAILABLE'
606
+ }));
607
+ return [
608
+ 2
609
+ ];
610
+ }
611
+ });
612
+ })();
613
+ });
614
+ it('filtrage des apps (F2) : requiredCapabilities accepte le nom fictif une fois déclaré', function() {
615
+ return _async_to_generator(function() {
616
+ var name, platform, hasCapability;
617
+ return _ts_generator(this, function(_state) {
618
+ switch(_state.label){
619
+ case 0:
620
+ registerFictional();
621
+ name = 'fictional'; // compile grâce à EgenCapabilityExtensions
622
+ platform = getPlatform();
623
+ return [
624
+ 4,
625
+ registerPlatformCapabilities(platform)
626
+ ];
627
+ case 1:
628
+ _state.sent();
629
+ return [
630
+ 4,
631
+ import('@egen-civitas/esm-globals')
632
+ ];
633
+ case 2:
634
+ hasCapability = _state.sent().hasCapability;
635
+ expect(hasCapability(name)).toBe(true);
636
+ return [
637
+ 2
638
+ ];
639
+ }
640
+ });
641
+ })();
642
+ });
643
+ it('retirer la capacité du registre la fait disparaître partout (aucun état résiduel)', function() {
644
+ registerFictional();
645
+ expect(unregisterCapability('fictional')).toBe(true);
646
+ expect(unregisterCapability('fictional')).toBe(false);
647
+ expect(isKnownCapability('fictional')).toBe(false);
648
+ expect(Object.keys(getPlatform())).not.toContain('fictional');
649
+ });
650
+ });
651
+ describe('isHostVersionSufficient', function() {
652
+ it.each([
653
+ [
654
+ 'session',
655
+ 1,
656
+ true
657
+ ],
658
+ [
659
+ 'session',
660
+ 2,
661
+ true
662
+ ],
663
+ [
664
+ 'session',
665
+ 0,
666
+ false
667
+ ],
668
+ [
669
+ 'session',
670
+ undefined,
671
+ false
672
+ ],
673
+ [
674
+ 'inconnue',
675
+ 1,
676
+ false
677
+ ]
678
+ ])('%s annoncée en version %s → %s', function(name, hostVersion, expected) {
679
+ expect(isHostVersionSufficient(name, hostVersion)).toBe(expected);
680
+ });
681
+ });
@@ -20,3 +20,4 @@ export interface MockPlatformOptions {
20
20
  * @category Platform
21
21
  */
22
22
  export declare function createMockPlatform(options?: MockPlatformOptions): Platform;
23
+ export { createMockHost, type MockHost, type MockHostOptions } from './mock-host.js';
@@ -11,3 +11,4 @@ export function createMockPlatform(options = {}) {
11
11
  const { environment = 'web', capabilities, ready = Promise.resolve() } = options;
12
12
  return assemblePlatform({ environment, capabilities, ready: () => ready });
13
13
  }
14
+ export { createMockHost } from './mock-host.js';