@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,188 @@
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 { hasCapability, setCapabilityResolver } from '@egen-civitas/esm-globals';
131
+ import { PlatformError } from './errors';
132
+ import { registerPlatformCapabilities } from './platform';
133
+ describe('registerPlatformCapabilities (F2)', function() {
134
+ afterEach(function() {
135
+ setCapabilityResolver(null);
136
+ delete window.egenTarget;
137
+ delete window.egenHostBridge;
138
+ });
139
+ it('web : expose les capacités du navigateur au reste du framework et se résout', function() {
140
+ return _async_to_generator(function() {
141
+ return _ts_generator(this, function(_state) {
142
+ switch(_state.label){
143
+ case 0:
144
+ return [
145
+ 4,
146
+ expect(registerPlatformCapabilities()).resolves.toBeUndefined()
147
+ ];
148
+ case 1:
149
+ _state.sent();
150
+ expect(hasCapability('openExternal')).toBe(true);
151
+ expect(hasCapability('secureStorage')).toBe(false); // jamais simulé en Web
152
+ expect(hasCapability('biometric')).toBe(false);
153
+ return [
154
+ 2
155
+ ];
156
+ }
157
+ });
158
+ })();
159
+ });
160
+ it("natif sans Host : rejette INCOMPATIBLE mais n'expose AUCUNE capacité", function() {
161
+ return _async_to_generator(function() {
162
+ var error;
163
+ return _ts_generator(this, function(_state) {
164
+ switch(_state.label){
165
+ case 0:
166
+ window.egenTarget = 'android';
167
+ return [
168
+ 4,
169
+ registerPlatformCapabilities().then(function() {
170
+ return null;
171
+ }, function(e) {
172
+ return e;
173
+ })
174
+ ];
175
+ case 1:
176
+ error = _state.sent();
177
+ expect(error).toBeInstanceOf(PlatformError);
178
+ expect(error.code).toBe('INCOMPATIBLE');
179
+ expect(hasCapability('openExternal')).toBe(false);
180
+ expect(hasCapability('session')).toBe(false);
181
+ return [
182
+ 2
183
+ ];
184
+ }
185
+ });
186
+ })();
187
+ });
188
+ });
@@ -0,0 +1,52 @@
1
+ import type { BridgeClient } from './bridge/client.js';
2
+ import type { CapabilityInterfaces } from './types.js';
3
+ /**
4
+ * Registre des capacités : POINT UNIQUE qui décrit chacune d'elles (tâche C6). Tout ce qui énumère des capacités
5
+ * (gabarit « indisponible », handshake avec le Host, adaptateurs Web et natif, mocks) le lit ici au lieu de tenir sa
6
+ * propre liste. Voir la procédure « ajouter une capacité » dans le README du package.
7
+ */
8
+ /**
9
+ * `async` : méthode qui retourne une `Promise` (absente ⇒ rejette `UNAVAILABLE`).
10
+ * `subscribe` : abonnement synchrone qui retourne une fonction de désabonnement (absent ⇒ lève `UNAVAILABLE`,
11
+ * faute de pouvoir rejeter).
12
+ */
13
+ export type MethodKind = 'async' | 'subscribe';
14
+ export interface CapabilityDefinition<T = Record<string, unknown>> {
15
+ /**
16
+ * Version de la capacité implémentée par ce framework. Le Host annonce la sienne au handshake (`{ v }`) : une
17
+ * capacité n'est disponible que si `v` du Host ≥ cette version.
18
+ */
19
+ version: number;
20
+ /** Toutes les méthodes publiques de la capacité. Exhaustif à la compilation : un oubli ne compile pas. */
21
+ methods: {
22
+ [M in keyof T]: MethodKind;
23
+ };
24
+ /**
25
+ * Adaptateur Web : fabrique appelée à chaque `getPlatform()`. Retourne `undefined` si le navigateur ne la supporte
26
+ * pas (la capacité reste alors absente). Ne retourne jamais de simulation de sécurité.
27
+ */
28
+ web?: () => Partial<T> | undefined;
29
+ /** Adaptateur natif : simple APPELANT du pont (aucune logique métier), branché sur le client du Host. */
30
+ native?: (client: BridgeClient) => Partial<T> | undefined;
31
+ }
32
+ /**
33
+ * Enregistre (ou remplace) une capacité. Les 9 capacités de la v1 sont enregistrées plus bas ; une capacité ajoutée
34
+ * ensuite passe par ici, depuis son propre fichier.
35
+ */
36
+ export declare function registerCapability<K extends keyof CapabilityInterfaces>(name: K, definition: CapabilityDefinition<CapabilityInterfaces[K]>): void;
37
+ /** Retire une capacité du registre (réservé aux tests qui en ajoutent une fictive). */
38
+ export declare function unregisterCapability(name: string): boolean;
39
+ export declare function getCapabilityDefinition(name: string): CapabilityDefinition | undefined;
40
+ export declare function listCapabilityNames(): string[];
41
+ /** Le nom est-il celui d'une capacité connue de ce framework ? (un Host peut en annoncer d'autres : elles sont ignorées) */
42
+ export declare function isKnownCapability(name: string): boolean;
43
+ /** Le Host annonce-t-il une version suffisante de cette capacité ? */
44
+ export declare function isHostVersionSufficient(name: string, hostVersion: number | undefined): boolean;
45
+ /** Adaptateurs Web de toutes les capacités du registre dont le navigateur est capable. */
46
+ export declare function createWebCapabilities(): Partial<{
47
+ [K in keyof CapabilityInterfaces]: Partial<CapabilityInterfaces[K]>;
48
+ }>;
49
+ /** Adaptateurs natifs de toutes les capacités du registre, branchés sur le client de pont. */
50
+ export declare function createNativeCapabilitiesFromRegistry(client: BridgeClient): Partial<{
51
+ [K in keyof CapabilityInterfaces]: Partial<CapabilityInterfaces[K]>;
52
+ }>;
@@ -0,0 +1,101 @@
1
+ import { createWebCamera } from './adapters/web/camera.js';
2
+ import { createWebFiles } from './adapters/web/files.js';
3
+ import { createWebLifecycle } from './adapters/web/lifecycle.js';
4
+ import { createWebOpenExternal } from './adapters/web/open-external.js';
5
+ import { createWebPermissions, isWebPermissionsAvailable } from './adapters/web/permissions.js';
6
+ import { createWebSession } from './adapters/web/session.js';
7
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
8
+ const definitions = new Map();
9
+ /**
10
+ * Enregistre (ou remplace) une capacité. Les 9 capacités de la v1 sont enregistrées plus bas ; une capacité ajoutée
11
+ * ensuite passe par ici, depuis son propre fichier.
12
+ */
13
+ export function registerCapability(name, definition) {
14
+ definitions.set(name, definition);
15
+ }
16
+ /** Retire une capacité du registre (réservé aux tests qui en ajoutent une fictive). */
17
+ export function unregisterCapability(name) {
18
+ return definitions.delete(name);
19
+ }
20
+ export function getCapabilityDefinition(name) {
21
+ return definitions.get(name);
22
+ }
23
+ export function listCapabilityNames() {
24
+ return [...definitions.keys()];
25
+ }
26
+ /** Le nom est-il celui d'une capacité connue de ce framework ? (un Host peut en annoncer d'autres : elles sont ignorées) */
27
+ export function isKnownCapability(name) {
28
+ return definitions.has(name);
29
+ }
30
+ /** Le Host annonce-t-il une version suffisante de cette capacité ? */
31
+ export function isHostVersionSufficient(name, hostVersion) {
32
+ const definition = definitions.get(name);
33
+ return definition !== undefined && hostVersion !== undefined && hostVersion >= definition.version;
34
+ }
35
+ /** Adaptateurs Web de toutes les capacités du registre dont le navigateur est capable. */
36
+ export function createWebCapabilities() {
37
+ const capabilities = {};
38
+ for (const [name, definition] of definitions) {
39
+ const adapter = definition.web?.();
40
+ if (adapter) {
41
+ capabilities[name] = adapter;
42
+ }
43
+ }
44
+ return capabilities;
45
+ }
46
+ /** Adaptateurs natifs de toutes les capacités du registre, branchés sur le client de pont. */
47
+ export function createNativeCapabilitiesFromRegistry(client) {
48
+ const capabilities = {};
49
+ for (const [name, definition] of definitions) {
50
+ const adapter = definition.native?.(client);
51
+ if (adapter) {
52
+ capabilities[name] = adapter;
53
+ }
54
+ }
55
+ return capabilities;
56
+ }
57
+ // ── Capacités v1 ─────────────────────────────────────────────────────────────────────────────
58
+ // Les adaptateurs natifs (`native`) sont l'objet de la tâche C7 (une capacité à la fois, quand une app l'utilise, N9).
59
+ registerCapability('session', {
60
+ version: 1,
61
+ methods: { getAuthorization: 'async', setTokens: 'async', refresh: 'async', clear: 'async' },
62
+ web: createWebSession,
63
+ });
64
+ registerCapability('secureStorage', {
65
+ version: 1,
66
+ methods: { get: 'async', set: 'async', remove: 'async' },
67
+ // Pas d'adaptateur Web : jamais de faux coffre dans le navigateur.
68
+ });
69
+ registerCapability('openExternal', {
70
+ version: 1,
71
+ methods: { open: 'async' },
72
+ web: createWebOpenExternal,
73
+ });
74
+ registerCapability('lifecycle', {
75
+ version: 1,
76
+ methods: { onResume: 'subscribe', onPause: 'subscribe' },
77
+ web: createWebLifecycle,
78
+ });
79
+ registerCapability('permissions', {
80
+ version: 1,
81
+ methods: { check: 'async', request: 'async' },
82
+ web: () => (isWebPermissionsAvailable() ? createWebPermissions() : undefined),
83
+ });
84
+ registerCapability('files', {
85
+ version: 1,
86
+ methods: { select: 'async', download: 'async' },
87
+ web: createWebFiles,
88
+ });
89
+ registerCapability('camera', {
90
+ version: 1,
91
+ methods: { capture: 'async' },
92
+ web: createWebCamera,
93
+ });
94
+ registerCapability('push', {
95
+ version: 1,
96
+ methods: { register: 'async', onMessage: 'subscribe' },
97
+ });
98
+ registerCapability('biometric', {
99
+ version: 1,
100
+ methods: { isAvailable: 'async', authenticate: 'async' },
101
+ });