@clubz/sdk 0.1.2
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/dist/bridge/BridgeProvider.d.ts +34 -0
- package/dist/bridge/BridgeProvider.js +155 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/package.json +16 -0
- package/src/bridge/BridgeProvider.ts +138 -0
- package/src/index.ts +1 -0
- package/tsconfig.json +26 -0
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Types de messages supportés par le Bridge.
|
|
3
|
+
*/
|
|
4
|
+
export type BridgeAction = 'VIBRATE' | 'NAVIGATE' | 'GET_USER' | 'STORAGE_SET' | 'STORAGE_GET';
|
|
5
|
+
export interface BridgeRequest<T = any> {
|
|
6
|
+
id: string;
|
|
7
|
+
action: BridgeAction;
|
|
8
|
+
payload?: T;
|
|
9
|
+
}
|
|
10
|
+
export interface BridgeResponse<T = any> {
|
|
11
|
+
id: string;
|
|
12
|
+
success: boolean;
|
|
13
|
+
data?: T;
|
|
14
|
+
error?: string;
|
|
15
|
+
}
|
|
16
|
+
export declare class BridgeProvider {
|
|
17
|
+
private isNative;
|
|
18
|
+
private pendingRequests;
|
|
19
|
+
constructor();
|
|
20
|
+
/**
|
|
21
|
+
* Envoie une commande au système hôte (Mobile ou Simulateur)
|
|
22
|
+
*/
|
|
23
|
+
send<T = any>(action: BridgeAction, payload?: any): Promise<T>;
|
|
24
|
+
getUser(): Promise<{
|
|
25
|
+
id: string;
|
|
26
|
+
name: string;
|
|
27
|
+
}>;
|
|
28
|
+
vibrate(): Promise<void>;
|
|
29
|
+
navigate(route: string): Promise<void>;
|
|
30
|
+
private handleMessage;
|
|
31
|
+
private mockFallback;
|
|
32
|
+
private generateId;
|
|
33
|
+
}
|
|
34
|
+
export declare const bridge: BridgeProvider;
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
var __assign = (this && this.__assign) || function () {
|
|
2
|
+
__assign = Object.assign || function(t) {
|
|
3
|
+
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
|
4
|
+
s = arguments[i];
|
|
5
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
|
|
6
|
+
t[p] = s[p];
|
|
7
|
+
}
|
|
8
|
+
return t;
|
|
9
|
+
};
|
|
10
|
+
return __assign.apply(this, arguments);
|
|
11
|
+
};
|
|
12
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
13
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
14
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
15
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
16
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
17
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
18
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
19
|
+
});
|
|
20
|
+
};
|
|
21
|
+
var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
22
|
+
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
|
|
23
|
+
return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
24
|
+
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
25
|
+
function step(op) {
|
|
26
|
+
if (f) throw new TypeError("Generator is already executing.");
|
|
27
|
+
while (g && (g = 0, op[0] && (_ = 0)), _) try {
|
|
28
|
+
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;
|
|
29
|
+
if (y = 0, t) op = [op[0] & 2, t.value];
|
|
30
|
+
switch (op[0]) {
|
|
31
|
+
case 0: case 1: t = op; break;
|
|
32
|
+
case 4: _.label++; return { value: op[1], done: false };
|
|
33
|
+
case 5: _.label++; y = op[1]; op = [0]; continue;
|
|
34
|
+
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
|
35
|
+
default:
|
|
36
|
+
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
|
37
|
+
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
|
38
|
+
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
|
39
|
+
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
|
40
|
+
if (t[2]) _.ops.pop();
|
|
41
|
+
_.trys.pop(); continue;
|
|
42
|
+
}
|
|
43
|
+
op = body.call(thisArg, _);
|
|
44
|
+
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
|
45
|
+
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
var BridgeProvider = /** @class */ (function () {
|
|
49
|
+
function BridgeProvider() {
|
|
50
|
+
// Détection de l'environnement React Native WebView
|
|
51
|
+
this.isNative = typeof window !== 'undefined' &&
|
|
52
|
+
window.ReactNativeWebView &&
|
|
53
|
+
window.ReactNativeWebView.postMessage;
|
|
54
|
+
this.pendingRequests = new Map();
|
|
55
|
+
// Écoute des réponses (Native ou Simulateur)
|
|
56
|
+
if (typeof window !== 'undefined') {
|
|
57
|
+
window.addEventListener('message', this.handleMessage.bind(this));
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Envoie une commande au système hôte (Mobile ou Simulateur)
|
|
62
|
+
*/
|
|
63
|
+
BridgeProvider.prototype.send = function (action, payload) {
|
|
64
|
+
var _this = this;
|
|
65
|
+
var id = this.generateId();
|
|
66
|
+
return new Promise(function (resolve, reject) {
|
|
67
|
+
// 1. Stocker la promesse pour la résoudre quand la réponse arrive
|
|
68
|
+
_this.pendingRequests.set(id, { resolve: resolve, reject: reject });
|
|
69
|
+
var request = { id: id, action: action, payload: payload };
|
|
70
|
+
if (_this.isNative) {
|
|
71
|
+
// --- MODE NATIF ---
|
|
72
|
+
// Envoi vers iOS/Android via l'interface WebView
|
|
73
|
+
window.ReactNativeWebView.postMessage(JSON.stringify(request));
|
|
74
|
+
}
|
|
75
|
+
else {
|
|
76
|
+
// --- MODE SIMULATEUR (Web) ---
|
|
77
|
+
// Envoi vers le parent (le cadre du simulateur)
|
|
78
|
+
window.parent.postMessage(__assign(__assign({}, request), { source: 'clubz-widget' }), '*');
|
|
79
|
+
// Fallback local si pas dans le simulateur (ex: dev simple)
|
|
80
|
+
if (window === window.parent) {
|
|
81
|
+
_this.mockFallback(action, payload, id);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
};
|
|
86
|
+
/* --- MÉTODES PUBLIQUES (facades) --- */
|
|
87
|
+
BridgeProvider.prototype.getUser = function () {
|
|
88
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
89
|
+
return __generator(this, function (_a) {
|
|
90
|
+
return [2 /*return*/, this.send('GET_USER')];
|
|
91
|
+
});
|
|
92
|
+
});
|
|
93
|
+
};
|
|
94
|
+
BridgeProvider.prototype.vibrate = function () {
|
|
95
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
96
|
+
return __generator(this, function (_a) {
|
|
97
|
+
return [2 /*return*/, this.send('VIBRATE')];
|
|
98
|
+
});
|
|
99
|
+
});
|
|
100
|
+
};
|
|
101
|
+
BridgeProvider.prototype.navigate = function (route) {
|
|
102
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
103
|
+
return __generator(this, function (_a) {
|
|
104
|
+
return [2 /*return*/, this.send('NAVIGATE', { route: route })];
|
|
105
|
+
});
|
|
106
|
+
});
|
|
107
|
+
};
|
|
108
|
+
/* --- INTERNE --- */
|
|
109
|
+
BridgeProvider.prototype.handleMessage = function (event) {
|
|
110
|
+
try {
|
|
111
|
+
// On parse, attention ça peut être une string ou un objet
|
|
112
|
+
var message = typeof event.data === 'string'
|
|
113
|
+
? JSON.parse(event.data)
|
|
114
|
+
: event.data;
|
|
115
|
+
// On vérifie si c'est une réponse à une de nos requêtes
|
|
116
|
+
if (message.id && this.pendingRequests.has(message.id)) {
|
|
117
|
+
var _a = this.pendingRequests.get(message.id), resolve = _a.resolve, reject = _a.reject;
|
|
118
|
+
if (message.success) {
|
|
119
|
+
resolve(message.data);
|
|
120
|
+
}
|
|
121
|
+
else {
|
|
122
|
+
reject(new Error(message.error || 'Bridge Error'));
|
|
123
|
+
}
|
|
124
|
+
this.pendingRequests.delete(message.id);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
catch (e) {
|
|
128
|
+
// Ignorer les messages non-JSON ou étrangers
|
|
129
|
+
}
|
|
130
|
+
};
|
|
131
|
+
BridgeProvider.prototype.mockFallback = function (action, payload, id) {
|
|
132
|
+
console.log("[Bridge Dev] Action: ".concat(action), payload);
|
|
133
|
+
var mockResponses = {
|
|
134
|
+
'GET_USER': { id: 'dev-123', name: 'Developer Mike' },
|
|
135
|
+
'DEFAULT': null
|
|
136
|
+
};
|
|
137
|
+
// Simuler l'asynchronicité
|
|
138
|
+
setTimeout(function () {
|
|
139
|
+
var response = {
|
|
140
|
+
id: id,
|
|
141
|
+
success: true,
|
|
142
|
+
data: mockResponses[action] || mockResponses['DEFAULT']
|
|
143
|
+
};
|
|
144
|
+
// On poste le message à nous-même pour que handleMessage l'attrape
|
|
145
|
+
window.postMessage(response, '*');
|
|
146
|
+
}, 500);
|
|
147
|
+
};
|
|
148
|
+
BridgeProvider.prototype.generateId = function () {
|
|
149
|
+
return Math.random().toString(36).substr(2, 9);
|
|
150
|
+
};
|
|
151
|
+
return BridgeProvider;
|
|
152
|
+
}());
|
|
153
|
+
export { BridgeProvider };
|
|
154
|
+
// Instance singleton
|
|
155
|
+
export var bridge = new BridgeProvider();
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './bridge/BridgeProvider';
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './bridge/BridgeProvider';
|
package/package.json
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@clubz/sdk",
|
|
3
|
+
"version": "0.1.2",
|
|
4
|
+
"main": "dist/index.js",
|
|
5
|
+
"types": "dist/index.d.ts",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"build": "tsc"
|
|
8
|
+
},
|
|
9
|
+
"description": "SDK for building Clubz Widgets",
|
|
10
|
+
"publishConfig": {
|
|
11
|
+
"access": "public"
|
|
12
|
+
},
|
|
13
|
+
"devDependencies": {
|
|
14
|
+
"typescript": "^5.0.0"
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Types de messages supportés par le Bridge.
|
|
3
|
+
*/
|
|
4
|
+
export type BridgeAction =
|
|
5
|
+
| 'VIBRATE'
|
|
6
|
+
| 'NAVIGATE'
|
|
7
|
+
| 'GET_USER'
|
|
8
|
+
| 'STORAGE_SET'
|
|
9
|
+
| 'STORAGE_GET';
|
|
10
|
+
|
|
11
|
+
export interface BridgeRequest<T = any> {
|
|
12
|
+
id: string; // ID unique pour corréler la réponse
|
|
13
|
+
action: BridgeAction;
|
|
14
|
+
payload?: T;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export interface BridgeResponse<T = any> {
|
|
18
|
+
id: string;
|
|
19
|
+
success: boolean;
|
|
20
|
+
data?: T;
|
|
21
|
+
error?: string;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export class BridgeProvider {
|
|
25
|
+
private isNative: boolean;
|
|
26
|
+
private pendingRequests: Map<string, { resolve: Function; reject: Function }>;
|
|
27
|
+
|
|
28
|
+
constructor() {
|
|
29
|
+
// Détection de l'environnement React Native WebView
|
|
30
|
+
this.isNative = typeof window !== 'undefined' &&
|
|
31
|
+
(window as any).ReactNativeWebView &&
|
|
32
|
+
(window as any).ReactNativeWebView.postMessage;
|
|
33
|
+
|
|
34
|
+
this.pendingRequests = new Map();
|
|
35
|
+
|
|
36
|
+
// Écoute des réponses (Native ou Simulateur)
|
|
37
|
+
if (typeof window !== 'undefined') {
|
|
38
|
+
window.addEventListener('message', this.handleMessage.bind(this));
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Envoie une commande au système hôte (Mobile ou Simulateur)
|
|
44
|
+
*/
|
|
45
|
+
public send<T = any>(action: BridgeAction, payload?: any): Promise<T> {
|
|
46
|
+
const id = this.generateId();
|
|
47
|
+
|
|
48
|
+
return new Promise((resolve, reject) => {
|
|
49
|
+
// 1. Stocker la promesse pour la résoudre quand la réponse arrive
|
|
50
|
+
this.pendingRequests.set(id, { resolve, reject });
|
|
51
|
+
|
|
52
|
+
const request: BridgeRequest = { id, action, payload };
|
|
53
|
+
|
|
54
|
+
if (this.isNative) {
|
|
55
|
+
// --- MODE NATIF ---
|
|
56
|
+
// Envoi vers iOS/Android via l'interface WebView
|
|
57
|
+
(window as any).ReactNativeWebView.postMessage(JSON.stringify(request));
|
|
58
|
+
} else {
|
|
59
|
+
// --- MODE SIMULATEUR (Web) ---
|
|
60
|
+
// Envoi vers le parent (le cadre du simulateur)
|
|
61
|
+
window.parent.postMessage({ ...request, source: 'clubz-widget' }, '*');
|
|
62
|
+
|
|
63
|
+
// Fallback local si pas dans le simulateur (ex: dev simple)
|
|
64
|
+
if (window === window.parent) {
|
|
65
|
+
this.mockFallback(action, payload, id);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/* --- MÉTODES PUBLIQUES (facades) --- */
|
|
72
|
+
|
|
73
|
+
public async getUser() {
|
|
74
|
+
return this.send<{ id: string; name: string }>('GET_USER');
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
public async vibrate() {
|
|
78
|
+
return this.send<void>('VIBRATE');
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
public async navigate(route: string) {
|
|
82
|
+
return this.send<void>('NAVIGATE', { route });
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/* --- INTERNE --- */
|
|
86
|
+
|
|
87
|
+
private handleMessage(event: MessageEvent) {
|
|
88
|
+
try {
|
|
89
|
+
// On parse, attention ça peut être une string ou un objet
|
|
90
|
+
const message: BridgeResponse = typeof event.data === 'string'
|
|
91
|
+
? JSON.parse(event.data)
|
|
92
|
+
: event.data;
|
|
93
|
+
|
|
94
|
+
// On vérifie si c'est une réponse à une de nos requêtes
|
|
95
|
+
if (message.id && this.pendingRequests.has(message.id)) {
|
|
96
|
+
const { resolve, reject } = this.pendingRequests.get(message.id)!;
|
|
97
|
+
|
|
98
|
+
if (message.success) {
|
|
99
|
+
resolve(message.data);
|
|
100
|
+
} else {
|
|
101
|
+
reject(new Error(message.error || 'Bridge Error'));
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
this.pendingRequests.delete(message.id);
|
|
105
|
+
}
|
|
106
|
+
} catch (e) {
|
|
107
|
+
// Ignorer les messages non-JSON ou étrangers
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
private mockFallback(action: BridgeAction, payload: any, id: string) {
|
|
112
|
+
console.log(`[Bridge Dev] Action: ${action}`, payload);
|
|
113
|
+
|
|
114
|
+
const mockResponses: Record<string, any> = {
|
|
115
|
+
'GET_USER': { id: 'dev-123', name: 'Developer Mike' },
|
|
116
|
+
'DEFAULT': null
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
// Simuler l'asynchronicité
|
|
120
|
+
setTimeout(() => {
|
|
121
|
+
const response: BridgeResponse = {
|
|
122
|
+
id,
|
|
123
|
+
success: true,
|
|
124
|
+
data: mockResponses[action] || mockResponses['DEFAULT']
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
// On poste le message à nous-même pour que handleMessage l'attrape
|
|
128
|
+
window.postMessage(response, '*');
|
|
129
|
+
}, 500);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
private generateId() {
|
|
133
|
+
return Math.random().toString(36).substr(2, 9);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// Instance singleton
|
|
138
|
+
export const bridge = new BridgeProvider();
|
package/src/index.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './bridge/BridgeProvider';
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "es5",
|
|
4
|
+
"lib": [
|
|
5
|
+
"dom",
|
|
6
|
+
"dom.iterable",
|
|
7
|
+
"esnext"
|
|
8
|
+
],
|
|
9
|
+
"allowJs": true,
|
|
10
|
+
"skipLibCheck": true,
|
|
11
|
+
"strict": true,
|
|
12
|
+
"forceConsistentCasingInFileNames": true,
|
|
13
|
+
"noEmit": false,
|
|
14
|
+
"esModuleInterop": true,
|
|
15
|
+
"module": "esnext",
|
|
16
|
+
"moduleResolution": "node",
|
|
17
|
+
"resolveJsonModule": true,
|
|
18
|
+
"isolatedModules": true,
|
|
19
|
+
"jsx": "react-jsx",
|
|
20
|
+
"declaration": true,
|
|
21
|
+
"outDir": "./dist"
|
|
22
|
+
},
|
|
23
|
+
"include": [
|
|
24
|
+
"src"
|
|
25
|
+
]
|
|
26
|
+
}
|