tina4js 1.0.6 → 1.0.7
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/TINA4.md +189 -19
- package/dist/api/fetch.d.ts +44 -0
- package/dist/api/fetch.d.ts.map +1 -0
- package/dist/api/index.d.ts +6 -0
- package/dist/api/index.d.ts.map +1 -0
- package/dist/api.cjs.js +1 -1
- package/dist/api.es.js +62 -52
- package/dist/core/component.d.ts +59 -0
- package/dist/core/component.d.ts.map +1 -0
- package/dist/core/html.d.ts +8 -0
- package/dist/core/html.d.ts.map +1 -0
- package/dist/core/index.d.ts +9 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/signal.d.ts +42 -0
- package/dist/core/signal.d.ts.map +1 -0
- package/dist/debug/index.d.ts +17 -0
- package/dist/debug/index.d.ts.map +1 -0
- package/dist/debug/overlay.d.ts +25 -0
- package/dist/debug/overlay.d.ts.map +1 -0
- package/dist/debug/panels/api.d.ts +5 -0
- package/dist/debug/panels/api.d.ts.map +1 -0
- package/dist/debug/panels/components.d.ts +5 -0
- package/dist/debug/panels/components.d.ts.map +1 -0
- package/dist/debug/panels/routes.d.ts +5 -0
- package/dist/debug/panels/routes.d.ts.map +1 -0
- package/dist/debug/panels/signals.d.ts +5 -0
- package/dist/debug/panels/signals.d.ts.map +1 -0
- package/dist/debug/styles.d.ts +5 -0
- package/dist/debug/styles.d.ts.map +1 -0
- package/dist/debug/trackers.d.ts +89 -0
- package/dist/debug/trackers.d.ts.map +1 -0
- package/dist/debug.cjs.js +6 -6
- package/dist/debug.es.js +16 -20
- package/dist/index.d.ts +19 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/pwa/index.d.ts +6 -0
- package/dist/pwa/index.d.ts.map +1 -0
- package/dist/pwa/pwa.d.ts +24 -0
- package/dist/pwa/pwa.d.ts.map +1 -0
- package/dist/router/index.d.ts +6 -0
- package/dist/router/index.d.ts.map +1 -0
- package/dist/router/router.d.ts +42 -0
- package/dist/router/router.d.ts.map +1 -0
- package/dist/signal.cjs.js +1 -1
- package/dist/signal.es.js +60 -45
- package/dist/tina4.cjs.js +1 -1
- package/dist/tina4.es.js +10 -8
- package/dist/ws/index.d.ts +6 -0
- package/dist/ws/index.d.ts.map +1 -0
- package/dist/ws/ws.d.ts +62 -0
- package/dist/ws/ws.d.ts.map +1 -0
- package/dist/ws.cjs.js +1 -0
- package/dist/ws.es.js +89 -0
- package/package.json +8 -3
package/TINA4.md
CHANGED
|
@@ -15,6 +15,8 @@
|
|
|
15
15
|
| Navigate | `navigate('/path')` |
|
|
16
16
|
| API | `await api.get('/path')`, `.post`, `.put`, `.patch`, `.delete` |
|
|
17
17
|
| PWA | `pwa.register({ name, themeColor, cacheStrategy })` |
|
|
18
|
+
| WebSocket | `ws.connect('wss://...', { reconnect: true })` — signals for status/messages |
|
|
19
|
+
| Debug | `import 'tina4js/debug'` — toggle with Ctrl+Shift+D |
|
|
18
20
|
|
|
19
21
|
## File Conventions
|
|
20
22
|
|
|
@@ -36,6 +38,8 @@
|
|
|
36
38
|
8. Use `static props = { name: String }` for component attributes
|
|
37
39
|
9. Use `` static styles = `css` `` for scoped styles (Shadow DOM)
|
|
38
40
|
10. Use `static shadow = false` for light DOM components
|
|
41
|
+
11. `route(pattern, handler)` — pattern is ALWAYS the first argument, handler/config is second
|
|
42
|
+
12. `api.configure()` must be called before any API calls if you need auth or a base URL
|
|
39
43
|
|
|
40
44
|
## Signal Patterns
|
|
41
45
|
|
|
@@ -43,12 +47,18 @@
|
|
|
43
47
|
// Create
|
|
44
48
|
const count = signal(0);
|
|
45
49
|
|
|
50
|
+
// Create with debug label (shows in debug overlay)
|
|
51
|
+
const count = signal(0, 'count');
|
|
52
|
+
|
|
46
53
|
// Read
|
|
47
54
|
count.value; // 0
|
|
48
55
|
|
|
49
56
|
// Write (triggers DOM updates)
|
|
50
57
|
count.value = 5;
|
|
51
58
|
|
|
59
|
+
// Read without subscribing
|
|
60
|
+
count.peek(); // 5
|
|
61
|
+
|
|
52
62
|
// Derived (auto-updates)
|
|
53
63
|
const doubled = computed(() => count.value * 2);
|
|
54
64
|
|
|
@@ -58,6 +68,9 @@ effect(() => console.log(count.value));
|
|
|
58
68
|
// Batch multiple updates
|
|
59
69
|
batch(() => { a.value = 1; b.value = 2; }); // one notification
|
|
60
70
|
|
|
71
|
+
// Check if something is a signal
|
|
72
|
+
isSignal(count); // true
|
|
73
|
+
|
|
61
74
|
// In templates — signals interpolate directly
|
|
62
75
|
html`<span>${count}</span>`; // auto-updates when count changes
|
|
63
76
|
```
|
|
@@ -98,13 +111,32 @@ customElements.define('my-widget', MyWidget);
|
|
|
98
111
|
```ts
|
|
99
112
|
import { route, router, navigate, html } from 'tina4js';
|
|
100
113
|
|
|
114
|
+
// Simple route
|
|
101
115
|
route('/', () => html`<h1>Home</h1>`);
|
|
116
|
+
|
|
117
|
+
// Route with params
|
|
102
118
|
route('/user/{id}', ({ id }) => html`<h1>User ${id}</h1>`);
|
|
103
|
-
|
|
119
|
+
|
|
120
|
+
// Route with guard (returns false to block, or string to redirect)
|
|
121
|
+
route('/admin', {
|
|
122
|
+
guard: () => isLoggedIn() || '/login',
|
|
123
|
+
handler: () => html`<h1>Admin</h1>`
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
// Catch-all (must be last)
|
|
104
127
|
route('*', () => html`<h1>404</h1>`);
|
|
105
128
|
|
|
129
|
+
// Start router — call AFTER all routes are registered
|
|
106
130
|
router.start({ target: '#root', mode: 'hash' }); // or mode: 'history'
|
|
131
|
+
|
|
132
|
+
// Programmatic navigation
|
|
107
133
|
navigate('/user/42');
|
|
134
|
+
navigate('/login', { replace: true }); // replace history entry
|
|
135
|
+
|
|
136
|
+
// Listen for route changes
|
|
137
|
+
router.on('change', (event) => {
|
|
138
|
+
// event: { path, params, pattern, durationMs }
|
|
139
|
+
});
|
|
108
140
|
```
|
|
109
141
|
|
|
110
142
|
## API Pattern (tina4-php/python compatible)
|
|
@@ -112,17 +144,69 @@ navigate('/user/42');
|
|
|
112
144
|
```ts
|
|
113
145
|
import { api } from 'tina4js';
|
|
114
146
|
|
|
115
|
-
|
|
147
|
+
// Configure — call before making requests
|
|
148
|
+
api.configure({
|
|
149
|
+
baseUrl: '/api',
|
|
150
|
+
auth: true, // enables Bearer token + formToken
|
|
151
|
+
tokenKey: 'tina4_token', // localStorage key (default)
|
|
152
|
+
headers: { 'X-API-Key': 'abc' }, // default headers on every request
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
// GET with query params
|
|
156
|
+
const users = await api.get('/users', { params: { page: 1, limit: 20 } });
|
|
157
|
+
// => GET /api/users?page=1&limit=20
|
|
158
|
+
|
|
159
|
+
// GET with custom headers
|
|
160
|
+
const data = await api.get('/data', { headers: { 'Accept-Language': 'en' } });
|
|
116
161
|
|
|
117
|
-
|
|
118
|
-
const user = await api.get('/users/{id}', { id: 42 });
|
|
162
|
+
// POST with body
|
|
119
163
|
await api.post('/users', { name: 'Andre' });
|
|
164
|
+
|
|
165
|
+
// POST with body + custom headers
|
|
166
|
+
await api.post('/upload', formData, { headers: { 'Content-Type': 'multipart/form-data' } });
|
|
167
|
+
|
|
168
|
+
// PUT, PATCH, DELETE
|
|
120
169
|
await api.put('/users/42', { name: 'Updated' });
|
|
170
|
+
await api.patch('/users/42', { active: false });
|
|
121
171
|
await api.delete('/users/42');
|
|
122
172
|
|
|
123
|
-
//
|
|
124
|
-
api.
|
|
125
|
-
|
|
173
|
+
// DELETE with query params
|
|
174
|
+
await api.delete('/users/42', { params: { permanent: true } });
|
|
175
|
+
|
|
176
|
+
// Error handling — non-2xx throws an ApiResponse object
|
|
177
|
+
try {
|
|
178
|
+
await api.get('/protected');
|
|
179
|
+
} catch (err) {
|
|
180
|
+
// err: { status: 401, data: {...}, ok: false, headers: Headers }
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// Interceptors — modify every request/response
|
|
184
|
+
api.intercept('request', (config) => {
|
|
185
|
+
config.headers['X-Custom'] = 'val';
|
|
186
|
+
return config;
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
api.intercept('response', (res) => {
|
|
190
|
+
if (res.status === 401) navigate('/login');
|
|
191
|
+
return res;
|
|
192
|
+
});
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
### RequestOptions
|
|
196
|
+
|
|
197
|
+
All API methods accept an optional `RequestOptions` object:
|
|
198
|
+
|
|
199
|
+
```ts
|
|
200
|
+
interface RequestOptions {
|
|
201
|
+
headers?: Record<string, string>; // per-request headers
|
|
202
|
+
params?: Record<string, string | number | boolean>; // query string params
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
api.get(path, options?)
|
|
206
|
+
api.post(path, body?, options?)
|
|
207
|
+
api.put(path, body?, options?)
|
|
208
|
+
api.patch(path, body?, options?)
|
|
209
|
+
api.delete(path, options?)
|
|
126
210
|
```
|
|
127
211
|
|
|
128
212
|
## Conditional & List Rendering
|
|
@@ -156,6 +240,58 @@ tina4 build --target python
|
|
|
156
240
|
- `formToken` injected into POST/PUT/PATCH/DELETE body
|
|
157
241
|
- Token auto-rotated via `FreshToken` response header
|
|
158
242
|
|
|
243
|
+
## WebSocket (Signal-Driven)
|
|
244
|
+
|
|
245
|
+
```ts
|
|
246
|
+
import { ws } from 'tina4js/ws';
|
|
247
|
+
import { signal } from 'tina4js';
|
|
248
|
+
|
|
249
|
+
// Connect with auto-reconnect
|
|
250
|
+
const socket = ws.connect('wss://api.example.com/live', {
|
|
251
|
+
reconnect: true, // auto-reconnect (default: true)
|
|
252
|
+
reconnectDelay: 1000, // initial delay ms (default: 1000)
|
|
253
|
+
reconnectMaxDelay: 30000, // max backoff ms (default: 30000)
|
|
254
|
+
reconnectAttempts: Infinity, // max attempts (default: Infinity)
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
// Reactive state — all signals
|
|
258
|
+
socket.status.value; // 'connecting' | 'open' | 'closed' | 'reconnecting'
|
|
259
|
+
socket.connected.value; // boolean
|
|
260
|
+
socket.lastMessage.value; // last parsed message
|
|
261
|
+
socket.error.value; // last error or null
|
|
262
|
+
socket.reconnectCount.value; // number of reconnect attempts
|
|
263
|
+
|
|
264
|
+
// Send — objects auto-stringify
|
|
265
|
+
socket.send({ type: 'chat', text: 'hello' });
|
|
266
|
+
socket.send('raw string');
|
|
267
|
+
|
|
268
|
+
// Listen for events
|
|
269
|
+
socket.on('message', (data) => { /* parsed JSON or string */ });
|
|
270
|
+
socket.on('open', () => { });
|
|
271
|
+
socket.on('close', (code, reason) => { });
|
|
272
|
+
socket.on('error', (err) => { });
|
|
273
|
+
|
|
274
|
+
// Pipe messages directly into a signal
|
|
275
|
+
const messages = signal<ChatMessage[]>([]);
|
|
276
|
+
socket.pipe(messages, (msg, current) => [...current, msg as ChatMessage]);
|
|
277
|
+
|
|
278
|
+
// Disconnect (stops reconnect)
|
|
279
|
+
socket.close();
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
### Real-time UI with Signals
|
|
283
|
+
|
|
284
|
+
```ts
|
|
285
|
+
// Chat example — messages auto-render in the template
|
|
286
|
+
const chatLog = signal<{user: string, text: string}[]>([]);
|
|
287
|
+
const socket = ws.connect('wss://chat.example.com');
|
|
288
|
+
socket.pipe(chatLog, (msg, log) => [...log, msg as any]);
|
|
289
|
+
|
|
290
|
+
route('/chat', () => html`
|
|
291
|
+
<ul>${() => chatLog.value.map(m => html`<li><b>${m.user}</b>: ${m.text}</li>`)}</ul>
|
|
292
|
+
`);
|
|
293
|
+
```
|
|
294
|
+
|
|
159
295
|
## Debug Overlay
|
|
160
296
|
|
|
161
297
|
```ts
|
|
@@ -167,18 +303,21 @@ if (import.meta.env.DEV) import('tina4js/debug');
|
|
|
167
303
|
```
|
|
168
304
|
|
|
169
305
|
- Toggle with **Ctrl+Shift+D**
|
|
170
|
-
-
|
|
306
|
+
- Panels: live signal values + subscriber counts, mounted components, route navigation history with timing, API request/response log
|
|
171
307
|
- Zero cost in production when using the `import.meta.env.DEV` guard (tree-shaken by Vite/Rollup)
|
|
308
|
+
- Signals can have debug labels: `signal(0, 'count')` — shows in the signals panel
|
|
172
309
|
|
|
173
310
|
## Framework Size
|
|
174
311
|
|
|
175
312
|
| Module | Gzipped |
|
|
176
313
|
|--------|---------|
|
|
177
|
-
| Core (signals + html + component) |
|
|
178
|
-
| Router |
|
|
179
|
-
| API | 0.
|
|
180
|
-
|
|
|
181
|
-
|
|
|
314
|
+
| Core (signals + html + component) | ~1.5 KB |
|
|
315
|
+
| Router | ~0.12 KB |
|
|
316
|
+
| API | ~0.97 KB |
|
|
317
|
+
| WebSocket | ~0.91 KB |
|
|
318
|
+
| PWA | ~1.16 KB |
|
|
319
|
+
| Debug overlay | ~5.1 KB |
|
|
320
|
+
| **Total (core modules)** | **~4.66 KB** |
|
|
182
321
|
|
|
183
322
|
## Architecture
|
|
184
323
|
|
|
@@ -186,15 +325,46 @@ if (import.meta.env.DEV) import('tina4js/debug');
|
|
|
186
325
|
src/
|
|
187
326
|
core/ signal.ts, html.ts, component.ts — reactive primitives
|
|
188
327
|
router/ router.ts — client-side routing
|
|
189
|
-
api/ fetch.ts — HTTP with auth
|
|
328
|
+
api/ fetch.ts — HTTP with auth + headers
|
|
329
|
+
ws/ ws.ts — WebSocket with auto-reconnect
|
|
190
330
|
pwa/ pwa.ts — service worker + manifest
|
|
331
|
+
debug/ overlay, trackers, panels — dev debug overlay
|
|
191
332
|
index.ts barrel re-export
|
|
192
333
|
```
|
|
193
334
|
|
|
194
|
-
|
|
335
|
+
### Exports Map
|
|
336
|
+
|
|
337
|
+
```ts
|
|
338
|
+
import { signal, html, computed, effect, batch, isSignal, Tina4Element } from 'tina4js';
|
|
339
|
+
import { route, router, navigate } from 'tina4js';
|
|
340
|
+
import { api } from 'tina4js';
|
|
341
|
+
import { pwa } from 'tina4js';
|
|
342
|
+
|
|
343
|
+
// Or import individual modules (tree-shakeable):
|
|
344
|
+
import { signal, html } from 'tina4js/core';
|
|
345
|
+
import { route, router } from 'tina4js/router';
|
|
346
|
+
import { api } from 'tina4js/api';
|
|
347
|
+
import { pwa } from 'tina4js/pwa';
|
|
348
|
+
import { ws } from 'tina4js/ws';
|
|
349
|
+
import 'tina4js/debug';
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
### TypeScript Types
|
|
353
|
+
|
|
195
354
|
```ts
|
|
196
|
-
import {
|
|
197
|
-
import {
|
|
198
|
-
import {
|
|
199
|
-
import {
|
|
355
|
+
import type { Signal, ReadonlySignal } from 'tina4js';
|
|
356
|
+
import type { RouteParams, RouteHandler, RouteGuard, RouteConfig } from 'tina4js';
|
|
357
|
+
import type { ApiConfig, ApiResponse, RequestOptions } from 'tina4js';
|
|
358
|
+
import type { SocketStatus, SocketOptions, ManagedSocket } from 'tina4js';
|
|
359
|
+
import type { PWAConfig } from 'tina4js';
|
|
360
|
+
import type { PropType } from 'tina4js';
|
|
200
361
|
```
|
|
362
|
+
|
|
363
|
+
## Common Mistakes to Avoid
|
|
364
|
+
|
|
365
|
+
1. **Reversed route arguments**: `route('/path', handler)` NOT `route(handler, '/path')`
|
|
366
|
+
2. **Forgetting `.value`**: `count.value++` NOT `count++`
|
|
367
|
+
3. **Calling `router.start()` before routes**: Register all routes first, then start
|
|
368
|
+
4. **Not returning from `render()`**: Always `return html\`...\``
|
|
369
|
+
5. **Missing `api.configure()`**: Must configure before making authenticated requests
|
|
370
|
+
6. **Using `api.get('/users/{id}', { id: 42 })`**: Changed to `api.get('/users/42')` — use params for query strings: `api.get('/users', { params: { id: 42 } })`
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tina4 API — Fetch wrapper with auth token management.
|
|
3
|
+
*
|
|
4
|
+
* Compatible with tina4-php and tina4-python backends:
|
|
5
|
+
* - Sends Authorization: Bearer <token>
|
|
6
|
+
* - Reads FreshToken response header for token rotation
|
|
7
|
+
* - Sends formToken in POST/PUT/PATCH/DELETE bodies
|
|
8
|
+
*/
|
|
9
|
+
export interface ApiConfig {
|
|
10
|
+
baseUrl: string;
|
|
11
|
+
auth: boolean;
|
|
12
|
+
tokenKey: string;
|
|
13
|
+
headers: Record<string, string>;
|
|
14
|
+
}
|
|
15
|
+
export interface ApiResponse<T = unknown> {
|
|
16
|
+
status: number;
|
|
17
|
+
data: T;
|
|
18
|
+
ok: boolean;
|
|
19
|
+
headers: Headers;
|
|
20
|
+
/** @internal Used by debug tracker for request/response correlation. */
|
|
21
|
+
_requestId?: number;
|
|
22
|
+
}
|
|
23
|
+
export type RequestInterceptor = (config: RequestInit & {
|
|
24
|
+
headers: Record<string, string>;
|
|
25
|
+
}) => (RequestInit & {
|
|
26
|
+
headers: Record<string, string>;
|
|
27
|
+
}) | void;
|
|
28
|
+
export type ResponseInterceptor = (response: ApiResponse) => ApiResponse | void;
|
|
29
|
+
export interface RequestOptions {
|
|
30
|
+
headers?: Record<string, string>;
|
|
31
|
+
params?: Record<string, string | number | boolean>;
|
|
32
|
+
}
|
|
33
|
+
export declare const api: {
|
|
34
|
+
configure(c: Partial<ApiConfig>): void;
|
|
35
|
+
get<T = unknown>(path: string, options?: RequestOptions): Promise<T>;
|
|
36
|
+
post<T = unknown>(path: string, body?: unknown, options?: RequestOptions): Promise<T>;
|
|
37
|
+
put<T = unknown>(path: string, body?: unknown, options?: RequestOptions): Promise<T>;
|
|
38
|
+
patch<T = unknown>(path: string, body?: unknown, options?: RequestOptions): Promise<T>;
|
|
39
|
+
delete<T = unknown>(path: string, options?: RequestOptions): Promise<T>;
|
|
40
|
+
intercept(type: "request" | "response", fn: RequestInterceptor | ResponseInterceptor): void;
|
|
41
|
+
/** @internal Reset state (for tests). */
|
|
42
|
+
_reset(): void;
|
|
43
|
+
};
|
|
44
|
+
//# sourceMappingURL=fetch.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fetch.d.ts","sourceRoot":"","sources":["../../src/api/fetch.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,MAAM,WAAW,SAAS;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,OAAO,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACjC;AAED,MAAM,WAAW,WAAW,CAAC,CAAC,GAAG,OAAO;IACtC,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,CAAC,CAAC;IACR,EAAE,EAAE,OAAO,CAAC;IACZ,OAAO,EAAE,OAAO,CAAC;IACjB,wEAAwE;IACxE,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,MAAM,kBAAkB,GAAG,CAAC,MAAM,EAAE,WAAW,GAAG;IAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAAE,KAAK,CAAC,WAAW,GAAG;IAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAAE,CAAC,GAAG,IAAI,CAAC;AAC3J,MAAM,MAAM,mBAAmB,GAAG,CAAC,QAAQ,EAAE,WAAW,KAAK,WAAW,GAAG,IAAI,CAAC;AA+BhF,MAAM,WAAW,cAAc;IAC7B,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,CAAC;CACpD;AA+FD,eAAO,MAAM,GAAG;iBACD,OAAO,CAAC,SAAS,CAAC,GAAG,IAAI;QAIlC,CAAC,kBAAkB,MAAM,YAAY,cAAc,GAAG,OAAO,CAAC,CAAC,CAAC;SAI/D,CAAC,kBAAkB,MAAM,SAAS,OAAO,YAAY,cAAc,GAAG,OAAO,CAAC,CAAC,CAAC;QAIjF,CAAC,kBAAkB,MAAM,SAAS,OAAO,YAAY,cAAc,GAAG,OAAO,CAAC,CAAC,CAAC;UAI9E,CAAC,kBAAkB,MAAM,SAAS,OAAO,YAAY,cAAc,GAAG,OAAO,CAAC,CAAC,CAAC;WAI/E,CAAC,kBAAkB,MAAM,YAAY,cAAc,GAAG,OAAO,CAAC,CAAC,CAAC;oBAIvD,SAAS,GAAG,UAAU,MAAM,kBAAkB,GAAG,mBAAmB,GAAG,IAAI;IAQ3F,yCAAyC;cAC/B,IAAI;CAQf,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/api/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,GAAG,EAAE,MAAM,SAAS,CAAC;AAC9B,YAAY,EAAE,SAAS,EAAE,WAAW,EAAE,cAAc,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,MAAM,SAAS,CAAC"}
|
package/dist/api.cjs.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const s={baseUrl:"",auth:!1,tokenKey:"tina4_token",headers:{}},d=[],h=[];let j=0;function T(){try{return localStorage.getItem(s.tokenKey)}catch{return null}}function I(e){try{localStorage.setItem(s.tokenKey,e)}catch{}}async function i(e,t,n,c){let o={method:e,headers:{"Content-Type":"application/json",...s.headers}};if(s.auth){const r=T();r&&(o.headers.Authorization=`Bearer ${r}`)}if(n!==void 0&&e!=="GET"){let r=typeof n=="object"&&n!==null?{...n}:n;if(s.auth&&typeof r=="object"&&r!==null){const a=T();a&&(r.formToken=a)}o.body=JSON.stringify(r)}if(c!=null&&c.headers&&Object.assign(o.headers,c.headers),c!=null&&c.params){const r=Object.entries(c.params).map(([a,y])=>`${encodeURIComponent(a)}=${encodeURIComponent(String(y))}`).join("&");t+=(t.includes("?")?"&":"?")+r}const g=s.baseUrl+t;o._url=g,o._requestId=++j;for(const r of d){const a=r(o);a&&(o=a)}const u=await fetch(g,o),k=u.headers.get("FreshToken");k&&I(k);const p=u.headers.get("Content-Type")??"";let f;p.includes("json")?f=await u.json():f=await u.text();let l={status:u.status,data:f,ok:u.ok,headers:u.headers,_requestId:o._requestId};for(const r of h){const a=r(l);a&&(l=a)}if(!u.ok)throw l;return l.data}const q={configure(e){Object.assign(s,e)},get(e,t){return i("GET",e,void 0,t)},post(e,t,n){return i("POST",e,t,n)},put(e,t,n){return i("PUT",e,t,n)},patch(e,t,n){return i("PATCH",e,t,n)},delete(e,t){return i("DELETE",e,void 0,t)},intercept(e,t){e==="request"?d.push(t):h.push(t)},_reset(){s.baseUrl="",s.auth=!1,s.tokenKey="tina4_token",s.headers={},d.length=0,h.length=0}};exports.api=q;
|
package/dist/api.es.js
CHANGED
|
@@ -1,90 +1,100 @@
|
|
|
1
|
-
const
|
|
1
|
+
const s = {
|
|
2
2
|
baseUrl: "",
|
|
3
3
|
auth: !1,
|
|
4
|
-
tokenKey: "tina4_token"
|
|
5
|
-
}
|
|
6
|
-
|
|
4
|
+
tokenKey: "tina4_token",
|
|
5
|
+
headers: {}
|
|
6
|
+
}, h = [], d = [];
|
|
7
|
+
let I = 0;
|
|
8
|
+
function T() {
|
|
7
9
|
try {
|
|
8
|
-
return localStorage.getItem(
|
|
10
|
+
return localStorage.getItem(s.tokenKey);
|
|
9
11
|
} catch {
|
|
10
12
|
return null;
|
|
11
13
|
}
|
|
12
14
|
}
|
|
13
|
-
function
|
|
15
|
+
function j(e) {
|
|
14
16
|
try {
|
|
15
|
-
localStorage.setItem(
|
|
17
|
+
localStorage.setItem(s.tokenKey, e);
|
|
16
18
|
} catch {
|
|
17
19
|
}
|
|
18
20
|
}
|
|
19
|
-
async function
|
|
20
|
-
let
|
|
21
|
+
async function l(e, t, r, c) {
|
|
22
|
+
let o = {
|
|
21
23
|
method: e,
|
|
22
24
|
headers: {
|
|
23
|
-
"Content-Type": "application/json"
|
|
25
|
+
"Content-Type": "application/json",
|
|
26
|
+
...s.headers
|
|
24
27
|
}
|
|
25
28
|
};
|
|
26
|
-
if (
|
|
27
|
-
const n =
|
|
28
|
-
n && (
|
|
29
|
+
if (s.auth) {
|
|
30
|
+
const n = T();
|
|
31
|
+
n && (o.headers.Authorization = `Bearer ${n}`);
|
|
29
32
|
}
|
|
30
|
-
if (
|
|
31
|
-
let n = typeof
|
|
32
|
-
if (
|
|
33
|
-
const
|
|
34
|
-
|
|
33
|
+
if (r !== void 0 && e !== "GET") {
|
|
34
|
+
let n = typeof r == "object" && r !== null ? { ...r } : r;
|
|
35
|
+
if (s.auth && typeof n == "object" && n !== null) {
|
|
36
|
+
const a = T();
|
|
37
|
+
a && (n.formToken = a);
|
|
35
38
|
}
|
|
36
|
-
|
|
39
|
+
o.body = JSON.stringify(n);
|
|
37
40
|
}
|
|
38
|
-
|
|
39
|
-
const
|
|
40
|
-
|
|
41
|
+
if (c != null && c.headers && Object.assign(o.headers, c.headers), c != null && c.params) {
|
|
42
|
+
const n = Object.entries(c.params).map(([a, y]) => `${encodeURIComponent(a)}=${encodeURIComponent(String(y))}`).join("&");
|
|
43
|
+
t += (t.includes("?") ? "&" : "?") + n;
|
|
41
44
|
}
|
|
42
|
-
const
|
|
43
|
-
|
|
44
|
-
const T = r.headers.get("Content-Type") ?? "";
|
|
45
|
-
let f;
|
|
46
|
-
T.includes("json") ? f = await r.json() : f = await r.text();
|
|
47
|
-
let u = {
|
|
48
|
-
status: r.status,
|
|
49
|
-
data: f,
|
|
50
|
-
ok: r.ok,
|
|
51
|
-
headers: r.headers
|
|
52
|
-
};
|
|
45
|
+
const g = s.baseUrl + t;
|
|
46
|
+
o._url = g, o._requestId = ++I;
|
|
53
47
|
for (const n of h) {
|
|
54
|
-
const
|
|
55
|
-
|
|
48
|
+
const a = n(o);
|
|
49
|
+
a && (o = a);
|
|
50
|
+
}
|
|
51
|
+
const u = await fetch(g, o), k = u.headers.get("FreshToken");
|
|
52
|
+
k && j(k);
|
|
53
|
+
const p = u.headers.get("Content-Type") ?? "";
|
|
54
|
+
let i;
|
|
55
|
+
p.includes("json") ? i = await u.json() : i = await u.text();
|
|
56
|
+
let f = {
|
|
57
|
+
status: u.status,
|
|
58
|
+
data: i,
|
|
59
|
+
ok: u.ok,
|
|
60
|
+
headers: u.headers,
|
|
61
|
+
_requestId: o._requestId
|
|
62
|
+
};
|
|
63
|
+
for (const n of d) {
|
|
64
|
+
const a = n(f);
|
|
65
|
+
a && (f = a);
|
|
56
66
|
}
|
|
57
|
-
if (!
|
|
58
|
-
throw
|
|
59
|
-
return
|
|
67
|
+
if (!u.ok)
|
|
68
|
+
throw f;
|
|
69
|
+
return f.data;
|
|
60
70
|
}
|
|
61
|
-
const
|
|
71
|
+
const q = {
|
|
62
72
|
configure(e) {
|
|
63
|
-
Object.assign(
|
|
73
|
+
Object.assign(s, e);
|
|
64
74
|
},
|
|
65
75
|
get(e, t) {
|
|
66
|
-
return
|
|
76
|
+
return l("GET", e, void 0, t);
|
|
67
77
|
},
|
|
68
|
-
post(e, t) {
|
|
69
|
-
return
|
|
78
|
+
post(e, t, r) {
|
|
79
|
+
return l("POST", e, t, r);
|
|
70
80
|
},
|
|
71
|
-
put(e, t) {
|
|
72
|
-
return
|
|
81
|
+
put(e, t, r) {
|
|
82
|
+
return l("PUT", e, t, r);
|
|
73
83
|
},
|
|
74
|
-
patch(e, t) {
|
|
75
|
-
return
|
|
84
|
+
patch(e, t, r) {
|
|
85
|
+
return l("PATCH", e, t, r);
|
|
76
86
|
},
|
|
77
|
-
delete(e) {
|
|
78
|
-
return
|
|
87
|
+
delete(e, t) {
|
|
88
|
+
return l("DELETE", e, void 0, t);
|
|
79
89
|
},
|
|
80
90
|
intercept(e, t) {
|
|
81
|
-
e === "request" ?
|
|
91
|
+
e === "request" ? h.push(t) : d.push(t);
|
|
82
92
|
},
|
|
83
93
|
/** @internal Reset state (for tests). */
|
|
84
94
|
_reset() {
|
|
85
|
-
|
|
95
|
+
s.baseUrl = "", s.auth = !1, s.tokenKey = "tina4_token", s.headers = {}, h.length = 0, d.length = 0;
|
|
86
96
|
}
|
|
87
97
|
};
|
|
88
98
|
export {
|
|
89
|
-
|
|
99
|
+
q as api
|
|
90
100
|
};
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tina4 Component — Base class for web components.
|
|
3
|
+
*
|
|
4
|
+
* Extends HTMLElement with reactive props, lifecycle hooks,
|
|
5
|
+
* optional Shadow DOM, and scoped styles.
|
|
6
|
+
*/
|
|
7
|
+
import { type Signal } from './signal';
|
|
8
|
+
/** @internal Called when a Tina4Element is connected to the DOM. */
|
|
9
|
+
export declare let __debugComponentMount: ((el: Tina4Element) => void) | null;
|
|
10
|
+
/** @internal Called when a Tina4Element is disconnected from the DOM. */
|
|
11
|
+
export declare let __debugComponentUnmount: ((el: Tina4Element) => void) | null;
|
|
12
|
+
/** @internal Set the debug hooks. */
|
|
13
|
+
export declare function __setDebugComponentHooks(onMount: typeof __debugComponentMount, onUnmount: typeof __debugComponentUnmount): void;
|
|
14
|
+
export type PropType = typeof String | typeof Number | typeof Boolean;
|
|
15
|
+
export declare abstract class Tina4Element extends HTMLElement {
|
|
16
|
+
/** Declare reactive props and their types. Override in subclass. */
|
|
17
|
+
static props: Record<string, PropType>;
|
|
18
|
+
/** Scoped CSS styles. Override in subclass. */
|
|
19
|
+
static styles: string;
|
|
20
|
+
/** Use Shadow DOM (true) or light DOM (false). Override in subclass. */
|
|
21
|
+
static shadow: boolean;
|
|
22
|
+
/** Internal reactive prop signals. */
|
|
23
|
+
private _props;
|
|
24
|
+
/** The render root (shadow or this). */
|
|
25
|
+
private _root;
|
|
26
|
+
/** Track if we've rendered. */
|
|
27
|
+
private _rendered;
|
|
28
|
+
static get observedAttributes(): string[];
|
|
29
|
+
constructor();
|
|
30
|
+
connectedCallback(): void;
|
|
31
|
+
disconnectedCallback(): void;
|
|
32
|
+
attributeChangedCallback(name: string, _old: string | null, value: string | null): void;
|
|
33
|
+
/**
|
|
34
|
+
* Get a reactive signal for a declared prop.
|
|
35
|
+
*
|
|
36
|
+
* ```ts
|
|
37
|
+
* render() {
|
|
38
|
+
* return html`<span>${this.prop('name')}</span>`;
|
|
39
|
+
* }
|
|
40
|
+
* ```
|
|
41
|
+
*/
|
|
42
|
+
prop<T = unknown>(name: string): Signal<T>;
|
|
43
|
+
/**
|
|
44
|
+
* Dispatch a custom event from this component.
|
|
45
|
+
*
|
|
46
|
+
* ```ts
|
|
47
|
+
* this.emit('activate', { detail: 42 });
|
|
48
|
+
* ```
|
|
49
|
+
*/
|
|
50
|
+
emit(name: string, init?: CustomEventInit): void;
|
|
51
|
+
/** Called after first render. */
|
|
52
|
+
onMount(): void;
|
|
53
|
+
/** Called when removed from DOM. */
|
|
54
|
+
onUnmount(): void;
|
|
55
|
+
/** Return DOM content. Override in subclass. */
|
|
56
|
+
abstract render(): DocumentFragment | Node | null;
|
|
57
|
+
private _coerce;
|
|
58
|
+
}
|
|
59
|
+
//# sourceMappingURL=component.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"component.d.ts","sourceRoot":"","sources":["../../src/core/component.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAU,KAAK,MAAM,EAAE,MAAM,UAAU,CAAC;AAI/C,oEAAoE;AACpE,eAAO,IAAI,qBAAqB,EAAE,CAAC,CAAC,EAAE,EAAE,YAAY,KAAK,IAAI,CAAC,GAAG,IAAW,CAAC;AAC7E,yEAAyE;AACzE,eAAO,IAAI,uBAAuB,EAAE,CAAC,CAAC,EAAE,EAAE,YAAY,KAAK,IAAI,CAAC,GAAG,IAAW,CAAC;AAC/E,qCAAqC;AACrC,wBAAgB,wBAAwB,CACtC,OAAO,EAAE,OAAO,qBAAqB,EACrC,SAAS,EAAE,OAAO,uBAAuB,QAI1C;AAED,MAAM,MAAM,QAAQ,GAAG,OAAO,MAAM,GAAG,OAAO,MAAM,GAAG,OAAO,OAAO,CAAC;AAEtE,8BAAsB,YAAa,SAAQ,WAAW;IACpD,oEAAoE;IACpE,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAM;IAE5C,+CAA+C;IAC/C,MAAM,CAAC,MAAM,EAAE,MAAM,CAAM;IAE3B,wEAAwE;IACxE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAQ;IAE9B,sCAAsC;IACtC,OAAO,CAAC,MAAM,CAAuC;IAErD,wCAAwC;IACxC,OAAO,CAAC,KAAK,CAA2B;IAExC,+BAA+B;IAC/B,OAAO,CAAC,SAAS,CAAS;IAE1B,MAAM,KAAK,kBAAkB,IAAI,MAAM,EAAE,CAExC;;IAaD,iBAAiB,IAAI,IAAI;IAuBzB,oBAAoB,IAAI,IAAI;IAK5B,wBAAwB,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI;IAQvF;;;;;;;;OAQG;IACH,IAAI,CAAC,CAAC,GAAG,OAAO,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC,CAAC,CAAC;IAO1C;;;;;;OAMG;IACH,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,eAAe,GAAG,IAAI;IAUhD,iCAAiC;IACjC,OAAO,IAAI,IAAI;IAEf,oCAAoC;IACpC,SAAS,IAAI,IAAI;IAEjB,gDAAgD;IAChD,QAAQ,CAAC,MAAM,IAAI,gBAAgB,GAAG,IAAI,GAAG,IAAI;IAIjD,OAAO,CAAC,OAAO;CAKhB"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tina4 HTML — Tagged template literal renderer.
|
|
3
|
+
*
|
|
4
|
+
* html`<div>${value}</div>` returns real DOM nodes (DocumentFragment).
|
|
5
|
+
* When a signal is interpolated, the DOM updates surgically — no diffing.
|
|
6
|
+
*/
|
|
7
|
+
export declare function html(strings: TemplateStringsArray, ...values: unknown[]): DocumentFragment;
|
|
8
|
+
//# sourceMappingURL=html.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"html.d.ts","sourceRoot":"","sources":["../../src/core/html.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAYH,wBAAgB,IAAI,CAAC,OAAO,EAAE,oBAAoB,EAAE,GAAG,MAAM,EAAE,OAAO,EAAE,GAAG,gBAAgB,CAiC1F"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* tina4js/core — Reactive primitives, HTML renderer, and web component base.
|
|
3
|
+
*/
|
|
4
|
+
export { signal, computed, effect, batch, isSignal } from './signal';
|
|
5
|
+
export type { Signal, ReadonlySignal } from './signal';
|
|
6
|
+
export { html } from './html';
|
|
7
|
+
export { Tina4Element } from './component';
|
|
8
|
+
export type { PropType } from './component';
|
|
9
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/core/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AACrE,YAAY,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AACvD,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAC9B,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,YAAY,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tina4 Signals — Reactive state primitives.
|
|
3
|
+
*
|
|
4
|
+
* signal(value) — create a reactive value
|
|
5
|
+
* computed(fn) — derive a value that auto-tracks dependencies
|
|
6
|
+
* effect(fn) — run a side-effect that auto-tracks dependencies
|
|
7
|
+
* batch(fn) — batch multiple signal updates into one notification
|
|
8
|
+
*/
|
|
9
|
+
/** @internal Start collecting effect disposers (used by router). */
|
|
10
|
+
export declare function _setEffectCollector(collector: (() => void)[] | null): void;
|
|
11
|
+
/** @internal Read the current effect collector (used by html renderer). */
|
|
12
|
+
export declare function _getEffectCollector(): (() => void)[] | null;
|
|
13
|
+
/** @internal Called when a signal is created. */
|
|
14
|
+
export declare let __debugSignalCreate: ((s: Signal<unknown>, label?: string) => void) | null;
|
|
15
|
+
/** @internal Called when a signal value changes. */
|
|
16
|
+
export declare let __debugSignalUpdate: ((s: Signal<unknown>, oldVal: unknown, newVal: unknown) => void) | null;
|
|
17
|
+
/** @internal Set the debug hooks. */
|
|
18
|
+
export declare function __setDebugSignalHooks(onCreate: typeof __debugSignalCreate, onUpdate: typeof __debugSignalUpdate): void;
|
|
19
|
+
export interface Signal<T> {
|
|
20
|
+
value: T;
|
|
21
|
+
/** @internal */
|
|
22
|
+
readonly _t4: true;
|
|
23
|
+
/** @internal subscribe directly (used by html renderer) */
|
|
24
|
+
_subscribe(fn: () => void): () => void;
|
|
25
|
+
/** @internal read without tracking */
|
|
26
|
+
peek(): T;
|
|
27
|
+
}
|
|
28
|
+
export interface ReadonlySignal<T> {
|
|
29
|
+
readonly value: T;
|
|
30
|
+
/** @internal */
|
|
31
|
+
readonly _t4: true;
|
|
32
|
+
/** @internal */
|
|
33
|
+
_subscribe(fn: () => void): () => void;
|
|
34
|
+
peek(): T;
|
|
35
|
+
}
|
|
36
|
+
export declare function signal<T>(initial: T, label?: string): Signal<T>;
|
|
37
|
+
export declare function computed<T>(fn: () => T): ReadonlySignal<T>;
|
|
38
|
+
export declare function effect(fn: () => void): () => void;
|
|
39
|
+
export declare function batch(fn: () => void): void;
|
|
40
|
+
/** Check if a value is a tina4 signal. */
|
|
41
|
+
export declare function isSignal(value: unknown): value is Signal<unknown>;
|
|
42
|
+
//# sourceMappingURL=signal.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"signal.d.ts","sourceRoot":"","sources":["../../src/core/signal.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAWH,oEAAoE;AACpE,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,CAAC,MAAM,IAAI,CAAC,EAAE,GAAG,IAAI,GAAG,IAAI,CAE1E;AAED,2EAA2E;AAC3E,wBAAgB,mBAAmB,IAAI,CAAC,MAAM,IAAI,CAAC,EAAE,GAAG,IAAI,CAE3D;AAID,iDAAiD;AACjD,eAAO,IAAI,mBAAmB,EAAE,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,OAAO,CAAC,EAAE,KAAK,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC,GAAG,IAAW,CAAC;AAC7F,oDAAoD;AACpD,eAAO,IAAI,mBAAmB,EAAE,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,KAAK,IAAI,CAAC,GAAG,IAAW,CAAC;AAC/G,qCAAqC;AACrC,wBAAgB,qBAAqB,CACnC,QAAQ,EAAE,OAAO,mBAAmB,EACpC,QAAQ,EAAE,OAAO,mBAAmB,QAIrC;AAUD,MAAM,WAAW,MAAM,CAAC,CAAC;IACvB,KAAK,EAAE,CAAC,CAAC;IACT,gBAAgB;IAChB,QAAQ,CAAC,GAAG,EAAE,IAAI,CAAC;IACnB,2DAA2D;IAC3D,UAAU,CAAC,EAAE,EAAE,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC;IACvC,sCAAsC;IACtC,IAAI,IAAI,CAAC,CAAC;CACX;AAED,MAAM,WAAW,cAAc,CAAC,CAAC;IAC/B,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAC;IAClB,gBAAgB;IAChB,QAAQ,CAAC,GAAG,EAAE,IAAI,CAAC;IACnB,gBAAgB;IAChB,UAAU,CAAC,EAAE,EAAE,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC;IACvC,IAAI,IAAI,CAAC,CAAC;CACX;AAED,wBAAgB,MAAM,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC,CAAC,CAAC,CAoD/D;AAID,wBAAgB,QAAQ,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,CAAC,GAAG,cAAc,CAAC,CAAC,CAAC,CA2B1D;AAID,wBAAgB,MAAM,CAAC,EAAE,EAAE,MAAM,IAAI,GAAG,MAAM,IAAI,CAgCjD;AAID,wBAAgB,KAAK,CAAC,EAAE,EAAE,MAAM,IAAI,GAAG,IAAI,CAgB1C;AAID,0CAA0C;AAC1C,wBAAgB,QAAQ,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,MAAM,CAAC,OAAO,CAAC,CAEjE"}
|