hotpipe 0.1.0 → 0.10.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/README.md +3 -0
- package/dist/client/connection.d.ts +79 -9
- package/dist/client/connection.d.ts.map +1 -1
- package/dist/client/connection.js +191 -39
- package/dist/client/connection.js.map +1 -1
- package/dist/client/index.d.ts +23 -19
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +80 -68
- package/dist/client/index.js.map +1 -1
- package/dist/constants.d.ts +8 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +8 -0
- package/dist/constants.js.map +1 -0
- package/dist/server/index.d.ts +114 -33
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +196 -56
- package/dist/server/index.js.map +1 -1
- package/dist/server/parse-secret.d.ts +5 -0
- package/dist/server/parse-secret.d.ts.map +1 -0
- package/dist/server/parse-secret.js +8 -0
- package/dist/server/parse-secret.js.map +1 -0
- package/dist/version.d.ts +2 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +2 -0
- package/dist/version.js.map +1 -0
- package/package.json +6 -6
package/dist/client/index.js
CHANGED
|
@@ -1,124 +1,136 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
3
|
import { createContext, useCallback, useContext, useEffect, useRef, useState } from 'react';
|
|
4
|
-
import { ConnectionManager } from './connection';
|
|
5
|
-
const
|
|
4
|
+
import { ConnectionManager, } from './connection';
|
|
5
|
+
const DEFAULT_API_URL = 'wss://api.hotpipe.dev';
|
|
6
|
+
const DEFAULT_BASE_PATH = '/api/realtime';
|
|
7
|
+
const globalCache = globalThis;
|
|
6
8
|
/**
|
|
7
9
|
* Creates a typed real-time client bound to your event schemas.
|
|
8
10
|
*
|
|
9
11
|
* Usage:
|
|
10
12
|
* ```ts
|
|
11
|
-
* const {
|
|
13
|
+
* const { PipeProvider, usePipe } = createPipeClient({
|
|
12
14
|
* events: realtimeEvents,
|
|
13
|
-
* auth: { endpoint: '/api/realtime/auth' },
|
|
14
15
|
* });
|
|
15
16
|
* ```
|
|
16
17
|
*/
|
|
17
|
-
export function
|
|
18
|
-
const
|
|
18
|
+
export function createPipeClient(config) {
|
|
19
|
+
const apiUrl = config.apiUrl ?? DEFAULT_API_URL;
|
|
20
|
+
const authEndpoint = `${config.basePath ?? DEFAULT_BASE_PATH}/auth`;
|
|
21
|
+
const connectionConfig = {
|
|
22
|
+
apiUrl,
|
|
23
|
+
authEndpoint,
|
|
24
|
+
authHeaders: config.authHeaders,
|
|
25
|
+
onPipeRevoked: config.onPipeRevoked,
|
|
26
|
+
onAllPipesRevoked: config.onAllPipesRevoked,
|
|
27
|
+
};
|
|
28
|
+
// Reuse existing manager in dev to survive HMR module re-evaluation
|
|
29
|
+
const cacheKey = `__hotpipe_${apiUrl}_${authEndpoint}`;
|
|
30
|
+
let manager;
|
|
31
|
+
if (globalCache[cacheKey]) {
|
|
32
|
+
manager = globalCache[cacheKey];
|
|
33
|
+
manager.updateConfig(connectionConfig);
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
manager = new ConnectionManager(connectionConfig);
|
|
37
|
+
}
|
|
38
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
39
|
+
globalCache[cacheKey] = manager;
|
|
40
|
+
}
|
|
41
|
+
const PipeContext = createContext(null);
|
|
19
42
|
function useManager() {
|
|
20
|
-
const
|
|
21
|
-
if (!
|
|
22
|
-
throw new Error('hotpipe:
|
|
43
|
+
const ctx = useContext(PipeContext);
|
|
44
|
+
if (!ctx) {
|
|
45
|
+
throw new Error('hotpipe: usePipe must be used within <PipeProvider>');
|
|
23
46
|
}
|
|
24
|
-
return
|
|
47
|
+
return ctx;
|
|
25
48
|
}
|
|
26
49
|
/**
|
|
27
50
|
* Wrap your app (or a subtree) with this provider to establish the
|
|
28
|
-
* WebSocket connection to the
|
|
51
|
+
* WebSocket connection to the hotpipe API.
|
|
29
52
|
*/
|
|
30
|
-
function
|
|
31
|
-
const managerRef = useRef(null);
|
|
32
|
-
if (!managerRef.current) {
|
|
33
|
-
managerRef.current = new ConnectionManager({
|
|
34
|
-
brokerUrl: config.brokerUrl ?? DEFAULT_BROKER_URL,
|
|
35
|
-
authEndpoint: config.auth.endpoint,
|
|
36
|
-
});
|
|
37
|
-
}
|
|
53
|
+
function PipeProvider({ children }) {
|
|
38
54
|
useEffect(() => {
|
|
39
|
-
|
|
40
|
-
|
|
55
|
+
manager.retain();
|
|
56
|
+
if (process.env.NODE_ENV !== 'production' && manager.getProviderRefCount() > 1) {
|
|
57
|
+
console.warn('[hotpipe] Multiple <PipeProvider> instances detected. ' +
|
|
58
|
+
'Use a single provider at the root of your app to avoid redundant connections.');
|
|
59
|
+
}
|
|
60
|
+
return () => manager.release();
|
|
41
61
|
}, []);
|
|
42
|
-
return
|
|
62
|
+
return _jsx(PipeContext.Provider, { value: manager, children: children });
|
|
43
63
|
}
|
|
44
64
|
/**
|
|
45
|
-
* Subscribe to events on a
|
|
65
|
+
* Subscribe to events on a pipe. Returns connection status and a
|
|
46
66
|
* typed publish function.
|
|
47
67
|
*
|
|
48
68
|
* ```tsx
|
|
49
|
-
* const { status, publish } =
|
|
69
|
+
* const { status, publish } = usePipe('global', {
|
|
50
70
|
* 'message.created': (data) => addMessage(data),
|
|
51
71
|
* });
|
|
52
72
|
* ```
|
|
53
73
|
*/
|
|
54
|
-
function
|
|
74
|
+
function usePipe(pipe, handlers, options) {
|
|
55
75
|
const manager = useManager();
|
|
56
76
|
const handlersRef = useRef(handlers);
|
|
57
77
|
handlersRef.current = handlers;
|
|
78
|
+
const serverMsgRef = useRef(options?.onServerMessage);
|
|
79
|
+
serverMsgRef.current = options?.onServerMessage;
|
|
58
80
|
const [status, setStatus] = useState(manager.getStatus());
|
|
59
81
|
useEffect(() => {
|
|
60
82
|
return manager.onStatusChange(setStatus);
|
|
61
83
|
}, [manager]);
|
|
62
84
|
useEffect(() => {
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
85
|
+
if (!serverMsgRef.current)
|
|
86
|
+
return;
|
|
87
|
+
return manager.onServerMessage((msg) => {
|
|
88
|
+
serverMsgRef.current?.(msg);
|
|
89
|
+
});
|
|
90
|
+
}, [manager]);
|
|
91
|
+
useEffect(() => {
|
|
92
|
+
const listener = (event, data, metadata) => {
|
|
93
|
+
const handler = handlersRef.current?.[event];
|
|
94
|
+
if (!handler)
|
|
95
|
+
return;
|
|
96
|
+
const schema = config.events[event];
|
|
97
|
+
if (schema) {
|
|
98
|
+
const result = schema.safeParse(data);
|
|
99
|
+
if (!result.success)
|
|
100
|
+
return;
|
|
67
101
|
}
|
|
102
|
+
handler(data, metadata);
|
|
68
103
|
};
|
|
69
|
-
manager.
|
|
70
|
-
manager.subscribe(
|
|
104
|
+
manager.addPipeListener(pipe, listener);
|
|
105
|
+
manager.subscribe(pipe);
|
|
71
106
|
return () => {
|
|
72
|
-
manager.unsubscribe(
|
|
73
|
-
manager.
|
|
107
|
+
manager.unsubscribe(pipe);
|
|
108
|
+
manager.removePipeListener(pipe, listener);
|
|
74
109
|
};
|
|
75
|
-
}, [
|
|
110
|
+
}, [pipe, manager]);
|
|
76
111
|
const publish = useCallback((event, data) => {
|
|
77
|
-
// Validate against schema before sending
|
|
78
112
|
const schema = config.events[event];
|
|
79
113
|
if (schema) {
|
|
80
114
|
const result = schema.safeParse(data);
|
|
81
115
|
if (!result.success) {
|
|
82
|
-
|
|
83
|
-
console.error(`[hotpipe] Invalid data for "${event}":`, result.error.format());
|
|
84
|
-
}
|
|
85
|
-
return;
|
|
116
|
+
throw new Error(`[hotpipe] Invalid data for "${event}": ${JSON.stringify(result.error.format())}`);
|
|
86
117
|
}
|
|
87
118
|
}
|
|
88
|
-
manager.publish(
|
|
89
|
-
}, [
|
|
119
|
+
return manager.publish(pipe, event, data);
|
|
120
|
+
}, [pipe, manager]);
|
|
90
121
|
return { status, publish };
|
|
91
122
|
}
|
|
92
123
|
/**
|
|
93
|
-
*
|
|
124
|
+
* Trigger a mid-session token refresh. Call this when a user's permissions
|
|
125
|
+
* change (e.g., they join a new chat room) and the connection should update
|
|
126
|
+
* in place without disconnecting.
|
|
94
127
|
*
|
|
95
|
-
*
|
|
96
|
-
*
|
|
97
|
-
* ```
|
|
128
|
+
* Callable from anywhere — event handlers, server action callbacks, etc.
|
|
129
|
+
* Does not require React context.
|
|
98
130
|
*/
|
|
99
|
-
function
|
|
100
|
-
|
|
101
|
-
const handlerRef = useRef(handler);
|
|
102
|
-
handlerRef.current = handler;
|
|
103
|
-
const [status, setStatus] = useState(manager.getStatus());
|
|
104
|
-
useEffect(() => {
|
|
105
|
-
return manager.onStatusChange(setStatus);
|
|
106
|
-
}, [manager]);
|
|
107
|
-
useEffect(() => {
|
|
108
|
-
const listener = (evt, data) => {
|
|
109
|
-
if (evt === event) {
|
|
110
|
-
handlerRef.current(data);
|
|
111
|
-
}
|
|
112
|
-
};
|
|
113
|
-
manager.addChannelListener(channel, listener);
|
|
114
|
-
manager.subscribe(channel);
|
|
115
|
-
return () => {
|
|
116
|
-
manager.unsubscribe(channel);
|
|
117
|
-
manager.removeChannelListener(channel, listener);
|
|
118
|
-
};
|
|
119
|
-
}, [channel, event, manager]);
|
|
120
|
-
return { status };
|
|
131
|
+
function refreshPipeAuth() {
|
|
132
|
+
return manager.refreshToken();
|
|
121
133
|
}
|
|
122
|
-
return {
|
|
134
|
+
return { PipeProvider, usePipe, refreshPipeAuth };
|
|
123
135
|
}
|
|
124
136
|
//# sourceMappingURL=index.js.map
|
package/dist/client/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/client/index.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AAEb,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAG5F,OAAO,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/client/index.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Default JWT token expiry in seconds. Used by createPipeHandler for token
|
|
3
|
+
* generation and by createPipeAdmin for revocation TTL defaults.
|
|
4
|
+
*
|
|
5
|
+
* Must stay in sync with the API-side constant (apps/hotpipe-api/src/constants.ts).
|
|
6
|
+
*/
|
|
7
|
+
export declare const DEFAULT_TOKEN_EXPIRY_SECONDS = 3600;
|
|
8
|
+
//# sourceMappingURL=constants.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,eAAO,MAAM,4BAA4B,OAAO,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Default JWT token expiry in seconds. Used by createPipeHandler for token
|
|
3
|
+
* generation and by createPipeAdmin for revocation TTL defaults.
|
|
4
|
+
*
|
|
5
|
+
* Must stay in sync with the API-side constant (apps/hotpipe-api/src/constants.ts).
|
|
6
|
+
*/
|
|
7
|
+
export const DEFAULT_TOKEN_EXPIRY_SECONDS = 3600;
|
|
8
|
+
//# sourceMappingURL=constants.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,MAAM,CAAC,MAAM,4BAA4B,GAAG,IAAI,CAAC"}
|
package/dist/server/index.d.ts
CHANGED
|
@@ -1,71 +1,152 @@
|
|
|
1
1
|
import type { z } from 'zod';
|
|
2
2
|
type EventMap = Record<string, z.ZodType>;
|
|
3
|
+
/**
|
|
4
|
+
* Pipe permissions — which operations a user can perform.
|
|
5
|
+
*/
|
|
6
|
+
interface PipePermissions {
|
|
7
|
+
subscribe?: boolean;
|
|
8
|
+
publish?: boolean;
|
|
9
|
+
}
|
|
3
10
|
/**
|
|
4
11
|
* The shape returned by your authorize function.
|
|
5
12
|
*/
|
|
6
13
|
interface AuthResult {
|
|
7
14
|
userId: string;
|
|
8
|
-
|
|
15
|
+
pipes: Record<string, PipePermissions>;
|
|
9
16
|
}
|
|
10
17
|
/**
|
|
11
|
-
*
|
|
18
|
+
* Options for server-side publish calls.
|
|
19
|
+
*/
|
|
20
|
+
interface PublishOptions {
|
|
21
|
+
/**
|
|
22
|
+
* An optional sender identity to attach to this event. Receiving clients
|
|
23
|
+
* see this in `metadata.sender`. When omitted, `sender` is `null`,
|
|
24
|
+
* indicating the event originated from the server with no specific user.
|
|
25
|
+
*/
|
|
26
|
+
sender?: string;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Creates a typed server-side publisher for emitting events to the hotpipe API
|
|
12
30
|
* from API routes, server actions, webhooks, cron jobs, etc.
|
|
13
31
|
*
|
|
14
32
|
* ```ts
|
|
15
|
-
* const realtime =
|
|
16
|
-
*
|
|
33
|
+
* const realtime = createPipePublisher({
|
|
34
|
+
* secret: process.env.HOTPIPE_SECRET!,
|
|
17
35
|
* events: realtimeEvents,
|
|
18
36
|
* });
|
|
19
37
|
*
|
|
20
|
-
*
|
|
38
|
+
* const teamChat = realtime.pipe('team-chat');
|
|
39
|
+
* await teamChat.publish('message.created', { ... });
|
|
21
40
|
* ```
|
|
22
41
|
*/
|
|
23
|
-
export declare function
|
|
24
|
-
|
|
42
|
+
export declare function createPipePublisher<T extends EventMap>(config: {
|
|
43
|
+
secret: string;
|
|
25
44
|
events: T;
|
|
26
|
-
/** Override the
|
|
27
|
-
|
|
45
|
+
/** @internal Override the API URL for local development. */
|
|
46
|
+
apiUrl?: string;
|
|
28
47
|
}): {
|
|
29
48
|
/**
|
|
30
|
-
*
|
|
49
|
+
* Get a reference to a pipe. Returns a `{ publish }` object with
|
|
50
|
+
* the same signature as the client-side `usePipe` publish function.
|
|
51
|
+
*
|
|
52
|
+
* ```ts
|
|
53
|
+
* const teamChat = realtime.pipe('team-chat');
|
|
54
|
+
* await teamChat.publish('message.created', { ... });
|
|
55
|
+
* ```
|
|
31
56
|
*/
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
*/
|
|
36
|
-
publishBatch(events: Array<{
|
|
37
|
-
channel: string;
|
|
38
|
-
event: keyof T & string;
|
|
39
|
-
data: unknown;
|
|
40
|
-
}>): Promise<void>;
|
|
57
|
+
pipe(pipe: string): {
|
|
58
|
+
publish<E extends keyof T & string>(event: E, data: z.infer<T[E]>, options?: PublishOptions): Promise<void>;
|
|
59
|
+
};
|
|
41
60
|
};
|
|
42
61
|
/**
|
|
43
|
-
* Creates a Next.js-compatible route handler for
|
|
44
|
-
*
|
|
45
|
-
*
|
|
62
|
+
* Creates a Next.js-compatible catch-all route handler for hotpipe.
|
|
63
|
+
* Mount this at `app/api/realtime/[...all]/route.ts` and the SDK
|
|
64
|
+
* handles the rest.
|
|
46
65
|
*
|
|
47
66
|
* ```ts
|
|
48
|
-
* // app/api/realtime/
|
|
49
|
-
* export const POST =
|
|
50
|
-
* secret: process.env.
|
|
67
|
+
* // app/api/realtime/[...all]/route.ts
|
|
68
|
+
* export const { POST } = createPipeHandler({
|
|
69
|
+
* secret: process.env.HOTPIPE_SECRET!,
|
|
51
70
|
* authorize: async (req) => {
|
|
52
|
-
* const session = await
|
|
71
|
+
* const { session } = await getAuth(req);
|
|
53
72
|
* if (!session) return null;
|
|
54
73
|
* return {
|
|
55
|
-
* userId: session.
|
|
56
|
-
*
|
|
57
|
-
*
|
|
58
|
-
* [`user-${session.
|
|
74
|
+
* userId: session.userId,
|
|
75
|
+
* pipes: {
|
|
76
|
+
* global: { subscribe: true, publish: true },
|
|
77
|
+
* [`user-${session.userId}`]: { subscribe: true },
|
|
59
78
|
* },
|
|
60
79
|
* };
|
|
61
80
|
* },
|
|
62
81
|
* });
|
|
63
82
|
* ```
|
|
64
83
|
*/
|
|
65
|
-
export declare function
|
|
84
|
+
export declare function createPipeHandler(handlerConfig: {
|
|
66
85
|
secret: string;
|
|
67
86
|
authorize: (req: Request) => Promise<AuthResult | null>;
|
|
68
87
|
tokenExpiry?: number;
|
|
69
|
-
}):
|
|
70
|
-
|
|
88
|
+
}): {
|
|
89
|
+
POST: (req: Request) => Promise<Response>;
|
|
90
|
+
};
|
|
91
|
+
/**
|
|
92
|
+
* Options for revocation methods.
|
|
93
|
+
*/
|
|
94
|
+
interface RevokeOptions {
|
|
95
|
+
/** TTL in seconds for the revocation entry. Defaults to the API's token expiry. */
|
|
96
|
+
ttl?: number;
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* A single revocation target for batch operations.
|
|
100
|
+
*/
|
|
101
|
+
interface RevocationEntry {
|
|
102
|
+
userId: string;
|
|
103
|
+
pipe: string;
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Creates a server-side admin client for revoking pipe access.
|
|
107
|
+
*
|
|
108
|
+
* ```ts
|
|
109
|
+
* const pipeAdmin = createPipeAdmin({
|
|
110
|
+
* secret: process.env.HOTPIPE_SECRET!,
|
|
111
|
+
* });
|
|
112
|
+
*
|
|
113
|
+
* await pipeAdmin.revoke('user-123', 'room-xyz');
|
|
114
|
+
* await pipeAdmin.revokeAll('user-123');
|
|
115
|
+
* ```
|
|
116
|
+
*/
|
|
117
|
+
export declare function createPipeAdmin(config: {
|
|
118
|
+
secret: string;
|
|
119
|
+
/** @internal Override the API URL for local development. */
|
|
120
|
+
apiUrl?: string;
|
|
121
|
+
}): {
|
|
122
|
+
/**
|
|
123
|
+
* Revoke access to one or more pipes for a user.
|
|
124
|
+
*
|
|
125
|
+
* ```ts
|
|
126
|
+
* await pipeAdmin.revoke('user-123', 'room-xyz');
|
|
127
|
+
* await pipeAdmin.revoke('user-123', ['room-xyz', 'room-abc']);
|
|
128
|
+
* ```
|
|
129
|
+
*/
|
|
130
|
+
revoke(userId: string, pipe: string | string[], options?: RevokeOptions): Promise<void>;
|
|
131
|
+
/**
|
|
132
|
+
* Revoke all pipe access for a user (e.g., account suspension).
|
|
133
|
+
*
|
|
134
|
+
* ```ts
|
|
135
|
+
* await pipeAdmin.revokeAll('user-123');
|
|
136
|
+
* ```
|
|
137
|
+
*/
|
|
138
|
+
revokeAll(userId: string, options?: RevokeOptions): Promise<void>;
|
|
139
|
+
/**
|
|
140
|
+
* Batch-revoke access for multiple user/pipe combinations.
|
|
141
|
+
*
|
|
142
|
+
* ```ts
|
|
143
|
+
* await pipeAdmin.revokeBatch([
|
|
144
|
+
* { userId: 'user-123', pipe: 'room-xyz' },
|
|
145
|
+
* { userId: 'user-456', pipe: 'room-xyz' },
|
|
146
|
+
* ]);
|
|
147
|
+
* ```
|
|
148
|
+
*/
|
|
149
|
+
revokeBatch(revocations: RevocationEntry[], options?: RevokeOptions): Promise<void>;
|
|
150
|
+
};
|
|
151
|
+
export type { AuthResult, EventMap, PipePermissions, PublishOptions, RevokeOptions };
|
|
71
152
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAM7B,KAAK,QAAQ,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC;AAE1C;;GAEG;AACH,UAAU,eAAe;IACvB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED;;GAEG;AACH,UAAU,UAAU;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;CACxC;AAED;;GAEG;AACH,UAAU,cAAc;IACtB;;;;OAIG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAwBD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,mBAAmB,CAAC,CAAC,SAAS,QAAQ,EAAE,MAAM,EAAE;IAC9D,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,CAAC,CAAC;IACV,4DAA4D;IAC5D,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;IAgDG;;;;;;;;OAQG;eACQ,MAAM;gBAEC,CAAC,SAAS,MAAM,CAAC,GAAG,MAAM,SAC/B,CAAC,QACF,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,YACT,cAAc,GACvB,OAAO,CAAC,IAAI,CAAC;;EAMvB;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,iBAAiB,CAAC,aAAa,EAAE;IAC/C,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CAAC;IACxD,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;gBAyC6B,OAAO,KAAG,OAAO,CAAC,QAAQ,CAAC;EAWxD;AAED;;GAEG;AACH,UAAU,aAAa;IACrB,mFAAmF;IACnF,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED;;GAEG;AACH,UAAU,eAAe;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE;IACtC,MAAM,EAAE,MAAM,CAAC;IACf,4DAA4D;IAC5D,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;IA2CG;;;;;;;OAOG;mBACkB,MAAM,QAAQ,MAAM,GAAG,MAAM,EAAE,YAAY,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC;IAS7F;;;;;;OAMG;sBACqB,MAAM,YAAY,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC;IAIvE;;;;;;;;;OASG;6BAC4B,eAAe,EAAE,YAAY,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC;EAI5F;AAED,YAAY,EAAE,UAAU,EAAE,QAAQ,EAAE,eAAe,EAAE,cAAc,EAAE,aAAa,EAAE,CAAC"}
|