@thewhateverapp/tile-sdk 0.1.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.
- package/LICENSE +21 -0
- package/README.md +582 -0
- package/dist/bridge/TileBridge.d.ts +100 -0
- package/dist/bridge/TileBridge.d.ts.map +1 -0
- package/dist/bridge/TileBridge.js +362 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +11 -0
- package/dist/react/TileContainer.d.ts +4 -0
- package/dist/react/TileContainer.d.ts.map +1 -0
- package/dist/react/TileContainer.js +14 -0
- package/dist/react/TileProvider.d.ts +33 -0
- package/dist/react/TileProvider.d.ts.map +1 -0
- package/dist/react/TileProvider.js +45 -0
- package/dist/react/index.d.ts +5 -0
- package/dist/react/index.d.ts.map +1 -0
- package/dist/react/index.js +4 -0
- package/dist/react/useTile.d.ts +3 -0
- package/dist/react/useTile.d.ts.map +1 -0
- package/dist/react/useTile.js +9 -0
- package/dist/react/withTile.d.ts +6 -0
- package/dist/react/withTile.d.ts.map +1 -0
- package/dist/react/withTile.js +8 -0
- package/dist/tools/index.d.ts +6 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +6 -0
- package/dist/types.d.ts +61 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +1 -0
- package/package.json +55 -0
|
@@ -0,0 +1,362 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Secure message bridge for tile-parent communication
|
|
3
|
+
* This runs inside the iframe (tile side)
|
|
4
|
+
*/
|
|
5
|
+
export class TileBridge {
|
|
6
|
+
constructor(expectedOrigin = 'https://thewhatever.app') {
|
|
7
|
+
this.config = null;
|
|
8
|
+
this.messageQueue = [];
|
|
9
|
+
this.responseHandlers = new Map();
|
|
10
|
+
this.eventHandlers = new Map();
|
|
11
|
+
this.ready = false;
|
|
12
|
+
this.parentOrigin = expectedOrigin;
|
|
13
|
+
// In development, allow localhost
|
|
14
|
+
if (typeof window !== 'undefined' && window.location.hostname === 'localhost') {
|
|
15
|
+
this.parentOrigin = 'http://localhost:3000';
|
|
16
|
+
}
|
|
17
|
+
this.initialize();
|
|
18
|
+
}
|
|
19
|
+
initialize() {
|
|
20
|
+
if (typeof window === 'undefined')
|
|
21
|
+
return;
|
|
22
|
+
// Listen for messages from parent
|
|
23
|
+
window.addEventListener('message', this.handleMessage.bind(this));
|
|
24
|
+
// Send ready signal to parent
|
|
25
|
+
this.sendToParent({ type: 'tile:ready' });
|
|
26
|
+
// Request configuration from parent
|
|
27
|
+
this.sendToParent({ type: 'tile:request-config' });
|
|
28
|
+
}
|
|
29
|
+
handleMessage(event) {
|
|
30
|
+
// Validate origin
|
|
31
|
+
if (event.origin !== this.parentOrigin && !this.isDevelopment()) {
|
|
32
|
+
console.warn('Received message from untrusted origin:', event.origin);
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
const message = event.data;
|
|
36
|
+
// Handle system messages
|
|
37
|
+
switch (message.type) {
|
|
38
|
+
case 'parent:config':
|
|
39
|
+
this.handleConfig(message.payload);
|
|
40
|
+
break;
|
|
41
|
+
case 'parent:response':
|
|
42
|
+
this.handleResponse(message);
|
|
43
|
+
break;
|
|
44
|
+
case 'parent:event':
|
|
45
|
+
this.handleEvent(message);
|
|
46
|
+
break;
|
|
47
|
+
default:
|
|
48
|
+
// Handle custom messages
|
|
49
|
+
this.emitEvent(message.type, message.payload);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
handleConfig(config) {
|
|
53
|
+
this.config = config;
|
|
54
|
+
this.ready = true;
|
|
55
|
+
// Process queued messages
|
|
56
|
+
while (this.messageQueue.length > 0) {
|
|
57
|
+
const message = this.messageQueue.shift();
|
|
58
|
+
if (message) {
|
|
59
|
+
this.sendToParent(message);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
// Emit config ready event
|
|
63
|
+
this.emitEvent('config:ready', config);
|
|
64
|
+
}
|
|
65
|
+
handleResponse(message) {
|
|
66
|
+
if (message.id) {
|
|
67
|
+
const handler = this.responseHandlers.get(message.id);
|
|
68
|
+
if (handler) {
|
|
69
|
+
handler(message.payload);
|
|
70
|
+
this.responseHandlers.delete(message.id);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
handleEvent(message) {
|
|
75
|
+
this.emitEvent(message.payload?.type, message.payload?.data);
|
|
76
|
+
}
|
|
77
|
+
sendToParent(message) {
|
|
78
|
+
if (typeof window === 'undefined' || !window.parent)
|
|
79
|
+
return;
|
|
80
|
+
// Add metadata
|
|
81
|
+
const fullMessage = {
|
|
82
|
+
...message,
|
|
83
|
+
timestamp: Date.now(),
|
|
84
|
+
id: message.id || this.generateId(),
|
|
85
|
+
};
|
|
86
|
+
// Queue if not ready
|
|
87
|
+
if (!this.ready && message.type !== 'tile:ready' && message.type !== 'tile:request-config') {
|
|
88
|
+
this.messageQueue.push(fullMessage);
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
// Send to parent
|
|
92
|
+
window.parent.postMessage(fullMessage, this.parentOrigin);
|
|
93
|
+
}
|
|
94
|
+
// Public API
|
|
95
|
+
/**
|
|
96
|
+
* Request to navigate to full page view
|
|
97
|
+
*/
|
|
98
|
+
navigateToPage() {
|
|
99
|
+
this.sendToParent({
|
|
100
|
+
type: 'tile:navigate',
|
|
101
|
+
payload: { target: 'page' },
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Request to open a URL (with user confirmation)
|
|
106
|
+
*/
|
|
107
|
+
openUrl(url, target = '_blank') {
|
|
108
|
+
this.sendToParent({
|
|
109
|
+
type: 'tile:open-url',
|
|
110
|
+
payload: { url, target },
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Send analytics event
|
|
115
|
+
*/
|
|
116
|
+
trackEvent(eventName, data) {
|
|
117
|
+
this.sendToParent({
|
|
118
|
+
type: 'tile:track',
|
|
119
|
+
payload: { event: eventName, data },
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Request clipboard write (requires user permission)
|
|
124
|
+
*/
|
|
125
|
+
async writeToClipboard(text) {
|
|
126
|
+
return new Promise((resolve, reject) => {
|
|
127
|
+
const id = this.generateId();
|
|
128
|
+
this.responseHandlers.set(id, (response) => {
|
|
129
|
+
if (response.success) {
|
|
130
|
+
resolve();
|
|
131
|
+
}
|
|
132
|
+
else {
|
|
133
|
+
reject(new Error(response.error || 'Clipboard write failed'));
|
|
134
|
+
}
|
|
135
|
+
});
|
|
136
|
+
this.sendToParent({
|
|
137
|
+
type: 'tile:clipboard-write',
|
|
138
|
+
payload: { text },
|
|
139
|
+
id,
|
|
140
|
+
});
|
|
141
|
+
// Timeout after 5 seconds
|
|
142
|
+
setTimeout(() => {
|
|
143
|
+
if (this.responseHandlers.has(id)) {
|
|
144
|
+
this.responseHandlers.delete(id);
|
|
145
|
+
reject(new Error('Request timeout'));
|
|
146
|
+
}
|
|
147
|
+
}, 5000);
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Store data in parent's storage (limited to 100KB per tile)
|
|
152
|
+
*/
|
|
153
|
+
async setStorage(key, value) {
|
|
154
|
+
return new Promise((resolve, reject) => {
|
|
155
|
+
const id = this.generateId();
|
|
156
|
+
// Check size limit
|
|
157
|
+
const serialized = JSON.stringify(value);
|
|
158
|
+
if (serialized.length > 100 * 1024) {
|
|
159
|
+
reject(new Error('Storage value exceeds 100KB limit'));
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
this.responseHandlers.set(id, (response) => {
|
|
163
|
+
if (response.success) {
|
|
164
|
+
resolve();
|
|
165
|
+
}
|
|
166
|
+
else {
|
|
167
|
+
reject(new Error(response.error || 'Storage write failed'));
|
|
168
|
+
}
|
|
169
|
+
});
|
|
170
|
+
this.sendToParent({
|
|
171
|
+
type: 'tile:storage-set',
|
|
172
|
+
payload: { key, value },
|
|
173
|
+
id,
|
|
174
|
+
});
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Get data from parent's storage
|
|
179
|
+
*/
|
|
180
|
+
async getStorage(key) {
|
|
181
|
+
return new Promise((resolve, reject) => {
|
|
182
|
+
const id = this.generateId();
|
|
183
|
+
this.responseHandlers.set(id, (response) => {
|
|
184
|
+
if (response.success) {
|
|
185
|
+
resolve(response.value);
|
|
186
|
+
}
|
|
187
|
+
else {
|
|
188
|
+
reject(new Error(response.error || 'Storage read failed'));
|
|
189
|
+
}
|
|
190
|
+
});
|
|
191
|
+
this.sendToParent({
|
|
192
|
+
type: 'tile:storage-get',
|
|
193
|
+
payload: { key },
|
|
194
|
+
id,
|
|
195
|
+
});
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* Request resize (within limits)
|
|
200
|
+
*/
|
|
201
|
+
requestResize(width, height) {
|
|
202
|
+
// Limit to max 512x512 for tiles
|
|
203
|
+
const constrainedWidth = Math.min(width, 512);
|
|
204
|
+
const constrainedHeight = Math.min(height, 512);
|
|
205
|
+
this.sendToParent({
|
|
206
|
+
type: 'tile:resize',
|
|
207
|
+
payload: { width: constrainedWidth, height: constrainedHeight },
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* Request user authentication with specific scopes
|
|
212
|
+
*/
|
|
213
|
+
async getUser(options) {
|
|
214
|
+
return new Promise((resolve, reject) => {
|
|
215
|
+
const id = this.generateId();
|
|
216
|
+
this.responseHandlers.set(id, (response) => {
|
|
217
|
+
if (response.success && response.user) {
|
|
218
|
+
resolve(response.user);
|
|
219
|
+
}
|
|
220
|
+
else if (response.denied) {
|
|
221
|
+
resolve(null); // User denied permission
|
|
222
|
+
}
|
|
223
|
+
else {
|
|
224
|
+
reject(new Error(response.error || 'Authentication failed'));
|
|
225
|
+
}
|
|
226
|
+
});
|
|
227
|
+
this.sendToParent({
|
|
228
|
+
type: 'tile:auth-request',
|
|
229
|
+
payload: {
|
|
230
|
+
scopes: options?.scopes || ['id'],
|
|
231
|
+
reason: options?.reason,
|
|
232
|
+
},
|
|
233
|
+
id,
|
|
234
|
+
});
|
|
235
|
+
// Timeout after 30 seconds
|
|
236
|
+
setTimeout(() => {
|
|
237
|
+
if (this.responseHandlers.has(id)) {
|
|
238
|
+
this.responseHandlers.delete(id);
|
|
239
|
+
reject(new Error('Authentication request timeout'));
|
|
240
|
+
}
|
|
241
|
+
}, 30000);
|
|
242
|
+
});
|
|
243
|
+
}
|
|
244
|
+
/**
|
|
245
|
+
* Request additional permission scopes
|
|
246
|
+
*/
|
|
247
|
+
async requestScopes(scopes) {
|
|
248
|
+
return new Promise((resolve, reject) => {
|
|
249
|
+
const id = this.generateId();
|
|
250
|
+
this.responseHandlers.set(id, (response) => {
|
|
251
|
+
if (response.success) {
|
|
252
|
+
resolve(true);
|
|
253
|
+
}
|
|
254
|
+
else if (response.denied) {
|
|
255
|
+
resolve(false);
|
|
256
|
+
}
|
|
257
|
+
else {
|
|
258
|
+
reject(new Error(response.error || 'Permission request failed'));
|
|
259
|
+
}
|
|
260
|
+
});
|
|
261
|
+
this.sendToParent({
|
|
262
|
+
type: 'tile:auth-request-scopes',
|
|
263
|
+
payload: { scopes },
|
|
264
|
+
id,
|
|
265
|
+
});
|
|
266
|
+
// Timeout after 30 seconds
|
|
267
|
+
setTimeout(() => {
|
|
268
|
+
if (this.responseHandlers.has(id)) {
|
|
269
|
+
this.responseHandlers.delete(id);
|
|
270
|
+
reject(new Error('Permission request timeout'));
|
|
271
|
+
}
|
|
272
|
+
}, 30000);
|
|
273
|
+
});
|
|
274
|
+
}
|
|
275
|
+
/**
|
|
276
|
+
* Get current authenticated user (if available)
|
|
277
|
+
*/
|
|
278
|
+
async getCurrentUser() {
|
|
279
|
+
return new Promise((resolve) => {
|
|
280
|
+
const id = this.generateId();
|
|
281
|
+
this.responseHandlers.set(id, (response) => {
|
|
282
|
+
resolve(response.user || null);
|
|
283
|
+
});
|
|
284
|
+
this.sendToParent({
|
|
285
|
+
type: 'tile:auth-get-current',
|
|
286
|
+
id,
|
|
287
|
+
});
|
|
288
|
+
// Timeout after 5 seconds, return null if no response
|
|
289
|
+
setTimeout(() => {
|
|
290
|
+
if (this.responseHandlers.has(id)) {
|
|
291
|
+
this.responseHandlers.delete(id);
|
|
292
|
+
resolve(null);
|
|
293
|
+
}
|
|
294
|
+
}, 5000);
|
|
295
|
+
});
|
|
296
|
+
}
|
|
297
|
+
/**
|
|
298
|
+
* Subscribe to events from parent
|
|
299
|
+
*/
|
|
300
|
+
on(event, handler) {
|
|
301
|
+
if (!this.eventHandlers.has(event)) {
|
|
302
|
+
this.eventHandlers.set(event, new Set());
|
|
303
|
+
}
|
|
304
|
+
this.eventHandlers.get(event).add(handler);
|
|
305
|
+
// Return unsubscribe function
|
|
306
|
+
return () => {
|
|
307
|
+
const handlers = this.eventHandlers.get(event);
|
|
308
|
+
if (handlers) {
|
|
309
|
+
handlers.delete(handler);
|
|
310
|
+
}
|
|
311
|
+
};
|
|
312
|
+
}
|
|
313
|
+
/**
|
|
314
|
+
* Get tile configuration
|
|
315
|
+
*/
|
|
316
|
+
getConfig() {
|
|
317
|
+
return this.config;
|
|
318
|
+
}
|
|
319
|
+
/**
|
|
320
|
+
* Check if ready
|
|
321
|
+
*/
|
|
322
|
+
isReady() {
|
|
323
|
+
return this.ready;
|
|
324
|
+
}
|
|
325
|
+
/**
|
|
326
|
+
* Wait for ready state
|
|
327
|
+
*/
|
|
328
|
+
async waitForReady() {
|
|
329
|
+
if (this.ready && this.config) {
|
|
330
|
+
return this.config;
|
|
331
|
+
}
|
|
332
|
+
return new Promise((resolve) => {
|
|
333
|
+
const unsubscribe = this.on('config:ready', (config) => {
|
|
334
|
+
unsubscribe();
|
|
335
|
+
resolve(config);
|
|
336
|
+
});
|
|
337
|
+
});
|
|
338
|
+
}
|
|
339
|
+
// Private helpers
|
|
340
|
+
emitEvent(event, data) {
|
|
341
|
+
const handlers = this.eventHandlers.get(event);
|
|
342
|
+
if (handlers) {
|
|
343
|
+
handlers.forEach(handler => handler(data));
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
generateId() {
|
|
347
|
+
return `${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
|
|
348
|
+
}
|
|
349
|
+
isDevelopment() {
|
|
350
|
+
return typeof window !== 'undefined' &&
|
|
351
|
+
(window.location.hostname === 'localhost' ||
|
|
352
|
+
window.location.hostname === '127.0.0.1');
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
// Singleton instance
|
|
356
|
+
let bridgeInstance = null;
|
|
357
|
+
export function getTileBridge() {
|
|
358
|
+
if (!bridgeInstance) {
|
|
359
|
+
bridgeInstance = new TileBridge();
|
|
360
|
+
}
|
|
361
|
+
return bridgeInstance;
|
|
362
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export { TileProvider } from './react/TileProvider';
|
|
2
|
+
export { useTile } from './react/useTile';
|
|
3
|
+
export { TileContainer } from './react/TileContainer';
|
|
4
|
+
export { withTile } from './react/withTile';
|
|
5
|
+
export { getTileBridge, TileBridge } from './bridge/TileBridge';
|
|
6
|
+
export type { TileMessage, TileConfig } from './bridge/TileBridge';
|
|
7
|
+
export * from './tools';
|
|
8
|
+
export * from './types';
|
|
9
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACpD,OAAO,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AACtD,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAG5C,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAChE,YAAY,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAGnE,cAAc,SAAS,CAAC;AAGxB,cAAc,SAAS,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
// React components and hooks
|
|
2
|
+
export { TileProvider } from './react/TileProvider';
|
|
3
|
+
export { useTile } from './react/useTile';
|
|
4
|
+
export { TileContainer } from './react/TileContainer';
|
|
5
|
+
export { withTile } from './react/withTile';
|
|
6
|
+
// Bridge for secure communication
|
|
7
|
+
export { getTileBridge, TileBridge } from './bridge/TileBridge';
|
|
8
|
+
// Domain-specific tools
|
|
9
|
+
export * from './tools';
|
|
10
|
+
// Types
|
|
11
|
+
export * from './types';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TileContainer.d.ts","sourceRoot":"","sources":["../../src/react/TileContainer.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAErC,wBAAgB,aAAa,CAAC,EAC5B,KAAW,EACX,MAAY,EACZ,SAAc,EACd,QAAQ,EACT,EAAE,SAAS,qBAmBX"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
export function TileContainer({ width = 512, height = 512, className = '', children }) {
|
|
3
|
+
return (React.createElement("div", { className: `tile-container ${className}`, style: {
|
|
4
|
+
width: `${width}px`,
|
|
5
|
+
height: `${height}px`,
|
|
6
|
+
overflow: 'hidden',
|
|
7
|
+
position: 'relative',
|
|
8
|
+
display: 'flex',
|
|
9
|
+
flexDirection: 'column',
|
|
10
|
+
alignItems: 'center',
|
|
11
|
+
justifyContent: 'center',
|
|
12
|
+
boxSizing: 'border-box',
|
|
13
|
+
} }, children));
|
|
14
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { TileBridge, TileConfig } from '../bridge/TileBridge';
|
|
3
|
+
export interface TileContextValue {
|
|
4
|
+
config: TileConfig | null;
|
|
5
|
+
bridge: TileBridge;
|
|
6
|
+
isReady: boolean;
|
|
7
|
+
navigateToPage: () => void;
|
|
8
|
+
openUrl: (url: string, target?: '_blank' | '_self') => void;
|
|
9
|
+
trackEvent: (eventName: string, data?: any) => void;
|
|
10
|
+
storage: {
|
|
11
|
+
get: (key: string) => Promise<any>;
|
|
12
|
+
set: (key: string, value: any) => Promise<void>;
|
|
13
|
+
};
|
|
14
|
+
clipboard: {
|
|
15
|
+
write: (text: string) => Promise<void>;
|
|
16
|
+
};
|
|
17
|
+
auth: {
|
|
18
|
+
getUser: (options?: {
|
|
19
|
+
scopes?: string[];
|
|
20
|
+
reason?: string;
|
|
21
|
+
}) => Promise<any>;
|
|
22
|
+
requestScopes: (scopes: string[]) => Promise<boolean>;
|
|
23
|
+
getCurrentUser: () => Promise<any>;
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
export declare const TileContext: React.Context<TileContextValue | null>;
|
|
27
|
+
interface TileProviderProps {
|
|
28
|
+
children: React.ReactNode;
|
|
29
|
+
fallback?: React.ReactNode;
|
|
30
|
+
}
|
|
31
|
+
export declare function TileProvider({ children, fallback }: TileProviderProps): React.JSX.Element;
|
|
32
|
+
export {};
|
|
33
|
+
//# sourceMappingURL=TileProvider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TileProvider.d.ts","sourceRoot":"","sources":["../../src/react/TileProvider.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA0D,MAAM,OAAO,CAAC;AAC/E,OAAO,EAAiB,UAAU,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAE7E,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,UAAU,GAAG,IAAI,CAAC;IAC1B,MAAM,EAAE,UAAU,CAAC;IACnB,OAAO,EAAE,OAAO,CAAC;IACjB,cAAc,EAAE,MAAM,IAAI,CAAC;IAC3B,OAAO,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,QAAQ,GAAG,OAAO,KAAK,IAAI,CAAC;IAC5D,UAAU,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,GAAG,KAAK,IAAI,CAAC;IACpD,OAAO,EAAE;QACP,GAAG,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,GAAG,CAAC,CAAC;QACnC,GAAG,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;KACjD,CAAC;IACF,SAAS,EAAE;QACT,KAAK,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;KACxC,CAAC;IACF,IAAI,EAAE;QACJ,OAAO,EAAE,CAAC,OAAO,CAAC,EAAE;YAAE,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;YAAC,MAAM,CAAC,EAAE,MAAM,CAAA;SAAE,KAAK,OAAO,CAAC,GAAG,CAAC,CAAC;QAC5E,aAAa,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;QACtD,cAAc,EAAE,MAAM,OAAO,CAAC,GAAG,CAAC,CAAC;KACpC,CAAC;CACH;AAED,eAAO,MAAM,WAAW,wCAA+C,CAAC;AAExE,UAAU,iBAAiB;IACzB,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;CAC5B;AAED,wBAAgB,YAAY,CAAC,EAAE,QAAQ,EAAE,QAAQ,EAAE,EAAE,iBAAiB,qBAmDrE"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import React, { createContext, useEffect, useState } from 'react';
|
|
2
|
+
import { getTileBridge } from '../bridge/TileBridge';
|
|
3
|
+
export const TileContext = createContext(null);
|
|
4
|
+
export function TileProvider({ children, fallback }) {
|
|
5
|
+
const [config, setConfig] = useState(null);
|
|
6
|
+
const [isReady, setIsReady] = useState(false);
|
|
7
|
+
const bridge = getTileBridge();
|
|
8
|
+
useEffect(() => {
|
|
9
|
+
// Wait for bridge to be ready and config to be received
|
|
10
|
+
bridge.waitForReady().then((receivedConfig) => {
|
|
11
|
+
setConfig(receivedConfig);
|
|
12
|
+
setIsReady(true);
|
|
13
|
+
});
|
|
14
|
+
// Listen for config updates
|
|
15
|
+
const unsubscribe = bridge.on('config:update', (updatedConfig) => {
|
|
16
|
+
setConfig(updatedConfig);
|
|
17
|
+
});
|
|
18
|
+
return unsubscribe;
|
|
19
|
+
}, [bridge]);
|
|
20
|
+
const contextValue = {
|
|
21
|
+
config,
|
|
22
|
+
bridge,
|
|
23
|
+
isReady,
|
|
24
|
+
navigateToPage: () => bridge.navigateToPage(),
|
|
25
|
+
openUrl: (url, target) => bridge.openUrl(url, target),
|
|
26
|
+
trackEvent: (eventName, data) => bridge.trackEvent(eventName, data),
|
|
27
|
+
storage: {
|
|
28
|
+
get: (key) => bridge.getStorage(key),
|
|
29
|
+
set: (key, value) => bridge.setStorage(key, value),
|
|
30
|
+
},
|
|
31
|
+
clipboard: {
|
|
32
|
+
write: (text) => bridge.writeToClipboard(text),
|
|
33
|
+
},
|
|
34
|
+
auth: {
|
|
35
|
+
getUser: (options) => bridge.getUser(options),
|
|
36
|
+
requestScopes: (scopes) => bridge.requestScopes(scopes),
|
|
37
|
+
getCurrentUser: () => bridge.getCurrentUser(),
|
|
38
|
+
},
|
|
39
|
+
};
|
|
40
|
+
// Show fallback while loading
|
|
41
|
+
if (!isReady && fallback) {
|
|
42
|
+
return React.createElement(React.Fragment, null, fallback);
|
|
43
|
+
}
|
|
44
|
+
return (React.createElement(TileContext.Provider, { value: contextValue }, children));
|
|
45
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/react/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useTile.d.ts","sourceRoot":"","sources":["../../src/react/useTile.ts"],"names":[],"mappings":"AACA,OAAO,EAAe,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAE/D,wBAAgB,OAAO,IAAI,gBAAgB,CAQ1C"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { useContext } from 'react';
|
|
2
|
+
import { TileContext } from './TileProvider';
|
|
3
|
+
export function useTile() {
|
|
4
|
+
const context = useContext(TileContext);
|
|
5
|
+
if (!context) {
|
|
6
|
+
throw new Error('useTile must be used within a TileProvider');
|
|
7
|
+
}
|
|
8
|
+
return context;
|
|
9
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import type { TileContextValue } from './TileProvider';
|
|
3
|
+
export declare function withTile<P extends object>(Component: React.ComponentType<P & {
|
|
4
|
+
tile: TileContextValue;
|
|
5
|
+
}>): React.ComponentType<P>;
|
|
6
|
+
//# sourceMappingURL=withTile.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"withTile.d.ts","sourceRoot":"","sources":["../../src/react/withTile.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAEvD,wBAAgB,QAAQ,CAAC,CAAC,SAAS,MAAM,EACvC,SAAS,EAAE,KAAK,CAAC,aAAa,CAAC,CAAC,GAAG;IAAE,IAAI,EAAE,gBAAgB,CAAA;CAAE,CAAC,GAC7D,KAAK,CAAC,aAAa,CAAC,CAAC,CAAC,CAKxB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,eAAO,MAAM,KAAK,IAAK,CAAC"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* App manifest structure
|
|
3
|
+
*/
|
|
4
|
+
export interface AppManifest {
|
|
5
|
+
id: string;
|
|
6
|
+
name: string;
|
|
7
|
+
description: string;
|
|
8
|
+
version: string;
|
|
9
|
+
owner: string;
|
|
10
|
+
createdAt: string;
|
|
11
|
+
updatedAt: string;
|
|
12
|
+
components: {
|
|
13
|
+
tile: {
|
|
14
|
+
entrypoint: string;
|
|
15
|
+
assets: string[];
|
|
16
|
+
};
|
|
17
|
+
page?: {
|
|
18
|
+
entrypoint: string;
|
|
19
|
+
assets: string[];
|
|
20
|
+
};
|
|
21
|
+
worker?: {
|
|
22
|
+
entrypoint: string;
|
|
23
|
+
routes: string[];
|
|
24
|
+
};
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
export interface TileContext {
|
|
28
|
+
appId: string;
|
|
29
|
+
manifest: AppManifest;
|
|
30
|
+
position: {
|
|
31
|
+
row: number;
|
|
32
|
+
col: number;
|
|
33
|
+
};
|
|
34
|
+
isFullscreen: boolean;
|
|
35
|
+
navigateToPage: () => void;
|
|
36
|
+
sendMessage: (type: string, data: any) => void;
|
|
37
|
+
onMessage: (handler: (type: string, data: any) => void) => void;
|
|
38
|
+
storage: {
|
|
39
|
+
get: (key: string) => Promise<any>;
|
|
40
|
+
set: (key: string, value: any) => Promise<void>;
|
|
41
|
+
delete: (key: string) => Promise<void>;
|
|
42
|
+
};
|
|
43
|
+
api: {
|
|
44
|
+
call: (endpoint: string, options?: RequestInit) => Promise<Response>;
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
export interface TileProps {
|
|
48
|
+
width?: number;
|
|
49
|
+
height?: number;
|
|
50
|
+
className?: string;
|
|
51
|
+
children: React.ReactNode;
|
|
52
|
+
}
|
|
53
|
+
export interface TileConfig {
|
|
54
|
+
id: string;
|
|
55
|
+
name: string;
|
|
56
|
+
version: string;
|
|
57
|
+
entrypoint: string;
|
|
58
|
+
permissions?: string[];
|
|
59
|
+
capabilities?: string[];
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE;QACV,IAAI,EAAE;YACJ,UAAU,EAAE,MAAM,CAAC;YACnB,MAAM,EAAE,MAAM,EAAE,CAAC;SAClB,CAAC;QACF,IAAI,CAAC,EAAE;YACL,UAAU,EAAE,MAAM,CAAC;YACnB,MAAM,EAAE,MAAM,EAAE,CAAC;SAClB,CAAC;QACF,MAAM,CAAC,EAAE;YACP,UAAU,EAAE,MAAM,CAAC;YACnB,MAAM,EAAE,MAAM,EAAE,CAAC;SAClB,CAAC;KACH,CAAC;CACH;AAED,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,WAAW,CAAC;IACtB,QAAQ,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC;IACvC,YAAY,EAAE,OAAO,CAAC;IACtB,cAAc,EAAE,MAAM,IAAI,CAAC;IAC3B,WAAW,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,KAAK,IAAI,CAAC;IAC/C,SAAS,EAAE,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,KAAK,IAAI,KAAK,IAAI,CAAC;IAChE,OAAO,EAAE;QACP,GAAG,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,GAAG,CAAC,CAAC;QACnC,GAAG,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;QAChD,MAAM,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;KACxC,CAAC;IACF,GAAG,EAAE;QACH,IAAI,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;KACtE,CAAC;CACH;AAED,MAAM,WAAW,SAAS;IACxB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;CAC3B;AAED,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;CACzB"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|