@risingwave/wavelet-sdk 0.1.2 → 0.1.3
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/__tests__/client.test.d.ts +2 -0
- package/dist/__tests__/client.test.d.ts.map +1 -0
- package/dist/__tests__/client.test.js +167 -0
- package/dist/__tests__/client.test.js.map +1 -0
- package/dist/react.d.ts +5 -1
- package/dist/react.d.ts.map +1 -1
- package/dist/react.js +47 -14
- package/dist/react.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/client.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const vitest_1 = require("vitest");
|
|
4
|
+
const client_js_1 = require("../client.js");
|
|
5
|
+
const types_js_1 = require("../types.js");
|
|
6
|
+
(0, vitest_1.describe)('WaveletClient', () => {
|
|
7
|
+
(0, vitest_1.describe)('URL construction', () => {
|
|
8
|
+
(0, vitest_1.it)('normalizes HTTP URL', () => {
|
|
9
|
+
const client = new client_js_1.WaveletClient({ url: 'http://localhost:8080/' });
|
|
10
|
+
// Access private fields for testing
|
|
11
|
+
(0, vitest_1.expect)(client.baseUrl).toBe('http://localhost:8080');
|
|
12
|
+
(0, vitest_1.expect)(client.wsBaseUrl).toBe('ws://localhost:8080');
|
|
13
|
+
});
|
|
14
|
+
(0, vitest_1.it)('normalizes HTTPS URL', () => {
|
|
15
|
+
const client = new client_js_1.WaveletClient({ url: 'https://app.wavelet.dev' });
|
|
16
|
+
(0, vitest_1.expect)(client.baseUrl).toBe('https://app.wavelet.dev');
|
|
17
|
+
(0, vitest_1.expect)(client.wsBaseUrl).toBe('wss://app.wavelet.dev');
|
|
18
|
+
});
|
|
19
|
+
(0, vitest_1.it)('handles path-prefixed URLs (for Wavelet Cloud)', () => {
|
|
20
|
+
const client = new client_js_1.WaveletClient({ url: 'https://wavelet-cloud.fly.dev/p/abc123' });
|
|
21
|
+
(0, vitest_1.expect)(client.baseUrl).toBe('https://wavelet-cloud.fly.dev/p/abc123');
|
|
22
|
+
(0, vitest_1.expect)(client.wsBaseUrl).toBe('wss://wavelet-cloud.fly.dev/p/abc123');
|
|
23
|
+
});
|
|
24
|
+
(0, vitest_1.it)('strips trailing slash', () => {
|
|
25
|
+
const client = new client_js_1.WaveletClient({ url: 'http://localhost:8080/' });
|
|
26
|
+
(0, vitest_1.expect)(client.baseUrl).toBe('http://localhost:8080');
|
|
27
|
+
});
|
|
28
|
+
});
|
|
29
|
+
(0, vitest_1.describe)('token provider', () => {
|
|
30
|
+
(0, vitest_1.it)('handles string token', async () => {
|
|
31
|
+
const client = new client_js_1.WaveletClient({ url: 'http://localhost', token: 'my-token' });
|
|
32
|
+
const provider = client.tokenProvider;
|
|
33
|
+
(0, vitest_1.expect)(provider).not.toBeNull();
|
|
34
|
+
(0, vitest_1.expect)(await provider()).toBe('my-token');
|
|
35
|
+
});
|
|
36
|
+
(0, vitest_1.it)('handles sync function token', async () => {
|
|
37
|
+
const client = new client_js_1.WaveletClient({ url: 'http://localhost', token: () => 'dynamic-token' });
|
|
38
|
+
const provider = client.tokenProvider;
|
|
39
|
+
(0, vitest_1.expect)(await provider()).toBe('dynamic-token');
|
|
40
|
+
});
|
|
41
|
+
(0, vitest_1.it)('handles async function token', async () => {
|
|
42
|
+
const client = new client_js_1.WaveletClient({
|
|
43
|
+
url: 'http://localhost',
|
|
44
|
+
token: async () => 'async-token',
|
|
45
|
+
});
|
|
46
|
+
const provider = client.tokenProvider;
|
|
47
|
+
(0, vitest_1.expect)(await provider()).toBe('async-token');
|
|
48
|
+
});
|
|
49
|
+
(0, vitest_1.it)('handles no token', () => {
|
|
50
|
+
const client = new client_js_1.WaveletClient({ url: 'http://localhost' });
|
|
51
|
+
(0, vitest_1.expect)(client.tokenProvider).toBeNull();
|
|
52
|
+
});
|
|
53
|
+
});
|
|
54
|
+
(0, vitest_1.describe)('view().get()', () => {
|
|
55
|
+
let fetchSpy;
|
|
56
|
+
(0, vitest_1.beforeEach)(() => {
|
|
57
|
+
fetchSpy = vitest_1.vi.fn();
|
|
58
|
+
vitest_1.vi.stubGlobal('fetch', fetchSpy);
|
|
59
|
+
});
|
|
60
|
+
(0, vitest_1.afterEach)(() => {
|
|
61
|
+
vitest_1.vi.unstubAllGlobals();
|
|
62
|
+
});
|
|
63
|
+
(0, vitest_1.it)('fetches view data', async () => {
|
|
64
|
+
fetchSpy.mockResolvedValue({
|
|
65
|
+
ok: true,
|
|
66
|
+
json: async () => ({ rows: [{ id: 1, name: 'test' }] }),
|
|
67
|
+
});
|
|
68
|
+
const client = new client_js_1.WaveletClient({ url: 'http://localhost:8080' });
|
|
69
|
+
const result = await client.view('leaderboard').get();
|
|
70
|
+
(0, vitest_1.expect)(result).toEqual([{ id: 1, name: 'test' }]);
|
|
71
|
+
(0, vitest_1.expect)(fetchSpy).toHaveBeenCalledOnce();
|
|
72
|
+
const calledUrl = fetchSpy.mock.calls[0][0];
|
|
73
|
+
(0, vitest_1.expect)(calledUrl).toBe('http://localhost:8080/v1/views/leaderboard');
|
|
74
|
+
});
|
|
75
|
+
(0, vitest_1.it)('passes query params as filters', async () => {
|
|
76
|
+
fetchSpy.mockResolvedValue({
|
|
77
|
+
ok: true,
|
|
78
|
+
json: async () => ({ rows: [] }),
|
|
79
|
+
});
|
|
80
|
+
const client = new client_js_1.WaveletClient({ url: 'http://localhost:8080' });
|
|
81
|
+
await client.view('usage').get({ tenant_id: 't1' });
|
|
82
|
+
const calledUrl = fetchSpy.mock.calls[0][0];
|
|
83
|
+
(0, vitest_1.expect)(calledUrl).toContain('tenant_id=t1');
|
|
84
|
+
});
|
|
85
|
+
(0, vitest_1.it)('sends Authorization header when token is set', async () => {
|
|
86
|
+
fetchSpy.mockResolvedValue({
|
|
87
|
+
ok: true,
|
|
88
|
+
json: async () => ({ rows: [] }),
|
|
89
|
+
});
|
|
90
|
+
const client = new client_js_1.WaveletClient({ url: 'http://localhost:8080', token: 'my-jwt' });
|
|
91
|
+
await client.view('leaderboard').get();
|
|
92
|
+
const headers = fetchSpy.mock.calls[0][1].headers;
|
|
93
|
+
(0, vitest_1.expect)(headers['Authorization']).toBe('Bearer my-jwt');
|
|
94
|
+
});
|
|
95
|
+
(0, vitest_1.it)('throws VIEW_NOT_FOUND on 404', async () => {
|
|
96
|
+
fetchSpy.mockResolvedValue({
|
|
97
|
+
ok: false,
|
|
98
|
+
status: 404,
|
|
99
|
+
json: async () => ({ error: "View 'nope' not found" }),
|
|
100
|
+
});
|
|
101
|
+
const client = new client_js_1.WaveletClient({ url: 'http://localhost:8080' });
|
|
102
|
+
await (0, vitest_1.expect)(client.view('nope').get()).rejects.toThrow(types_js_1.WaveletError);
|
|
103
|
+
await (0, vitest_1.expect)(client.view('nope').get()).rejects.toMatchObject({
|
|
104
|
+
code: 'VIEW_NOT_FOUND',
|
|
105
|
+
});
|
|
106
|
+
});
|
|
107
|
+
(0, vitest_1.it)('throws AUTH_ERROR on 401', async () => {
|
|
108
|
+
fetchSpy.mockResolvedValue({
|
|
109
|
+
ok: false,
|
|
110
|
+
status: 401,
|
|
111
|
+
json: async () => ({ error: 'Unauthorized' }),
|
|
112
|
+
});
|
|
113
|
+
const client = new client_js_1.WaveletClient({ url: 'http://localhost:8080' });
|
|
114
|
+
await (0, vitest_1.expect)(client.view('leaderboard').get()).rejects.toMatchObject({
|
|
115
|
+
code: 'AUTH_ERROR',
|
|
116
|
+
});
|
|
117
|
+
});
|
|
118
|
+
(0, vitest_1.it)('throws SERVER_ERROR on 500', async () => {
|
|
119
|
+
fetchSpy.mockResolvedValue({
|
|
120
|
+
ok: false,
|
|
121
|
+
status: 500,
|
|
122
|
+
json: async () => ({ error: 'Internal error' }),
|
|
123
|
+
});
|
|
124
|
+
const client = new client_js_1.WaveletClient({ url: 'http://localhost:8080' });
|
|
125
|
+
await (0, vitest_1.expect)(client.view('leaderboard').get()).rejects.toMatchObject({
|
|
126
|
+
code: 'SERVER_ERROR',
|
|
127
|
+
});
|
|
128
|
+
});
|
|
129
|
+
});
|
|
130
|
+
(0, vitest_1.describe)('stream().emit()', () => {
|
|
131
|
+
let fetchSpy;
|
|
132
|
+
(0, vitest_1.beforeEach)(() => {
|
|
133
|
+
fetchSpy = vitest_1.vi.fn();
|
|
134
|
+
vitest_1.vi.stubGlobal('fetch', fetchSpy);
|
|
135
|
+
});
|
|
136
|
+
(0, vitest_1.afterEach)(() => {
|
|
137
|
+
vitest_1.vi.unstubAllGlobals();
|
|
138
|
+
});
|
|
139
|
+
(0, vitest_1.it)('posts event to correct URL', async () => {
|
|
140
|
+
fetchSpy.mockResolvedValue({ ok: true, json: async () => ({ ok: true }) });
|
|
141
|
+
const client = new client_js_1.WaveletClient({ url: 'http://localhost:8080' });
|
|
142
|
+
await client.stream('events').emit({ user_id: 'u1', score: 42 });
|
|
143
|
+
(0, vitest_1.expect)(fetchSpy).toHaveBeenCalledOnce();
|
|
144
|
+
const [url, opts] = fetchSpy.mock.calls[0];
|
|
145
|
+
(0, vitest_1.expect)(url).toBe('http://localhost:8080/v1/streams/events');
|
|
146
|
+
(0, vitest_1.expect)(opts.method).toBe('POST');
|
|
147
|
+
(0, vitest_1.expect)(JSON.parse(opts.body)).toEqual({ user_id: 'u1', score: 42 });
|
|
148
|
+
});
|
|
149
|
+
(0, vitest_1.it)('posts batch to correct URL', async () => {
|
|
150
|
+
fetchSpy.mockResolvedValue({ ok: true, json: async () => ({ ok: true, count: 2 }) });
|
|
151
|
+
const client = new client_js_1.WaveletClient({ url: 'http://localhost:8080' });
|
|
152
|
+
await client.stream('events').emitBatch([{ a: 1 }, { a: 2 }]);
|
|
153
|
+
const [url, opts] = fetchSpy.mock.calls[0];
|
|
154
|
+
(0, vitest_1.expect)(url).toBe('http://localhost:8080/v1/streams/events/batch');
|
|
155
|
+
(0, vitest_1.expect)(JSON.parse(opts.body)).toEqual([{ a: 1 }, { a: 2 }]);
|
|
156
|
+
});
|
|
157
|
+
(0, vitest_1.it)('throws on error response', async () => {
|
|
158
|
+
fetchSpy.mockResolvedValue({
|
|
159
|
+
ok: false,
|
|
160
|
+
json: async () => ({ error: "Stream 'nope' not found" }),
|
|
161
|
+
});
|
|
162
|
+
const client = new client_js_1.WaveletClient({ url: 'http://localhost:8080' });
|
|
163
|
+
await (0, vitest_1.expect)(client.stream('nope').emit({ x: 1 })).rejects.toThrow(types_js_1.WaveletError);
|
|
164
|
+
});
|
|
165
|
+
});
|
|
166
|
+
});
|
|
167
|
+
//# sourceMappingURL=client.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.test.js","sourceRoot":"","sources":["../../src/__tests__/client.test.ts"],"names":[],"mappings":";;AAAA,mCAAwE;AACxE,4CAA4C;AAC5C,0CAA0C;AAE1C,IAAA,iBAAQ,EAAC,eAAe,EAAE,GAAG,EAAE;IAC7B,IAAA,iBAAQ,EAAC,kBAAkB,EAAE,GAAG,EAAE;QAChC,IAAA,WAAE,EAAC,qBAAqB,EAAE,GAAG,EAAE;YAC7B,MAAM,MAAM,GAAG,IAAI,yBAAa,CAAC,EAAE,GAAG,EAAE,wBAAwB,EAAE,CAAC,CAAA;YACnE,oCAAoC;YACpC,IAAA,eAAM,EAAE,MAAc,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,uBAAuB,CAAC,CAAA;YAC7D,IAAA,eAAM,EAAE,MAAc,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,qBAAqB,CAAC,CAAA;QAC/D,CAAC,CAAC,CAAA;QAEF,IAAA,WAAE,EAAC,sBAAsB,EAAE,GAAG,EAAE;YAC9B,MAAM,MAAM,GAAG,IAAI,yBAAa,CAAC,EAAE,GAAG,EAAE,yBAAyB,EAAE,CAAC,CAAA;YACpE,IAAA,eAAM,EAAE,MAAc,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,yBAAyB,CAAC,CAAA;YAC/D,IAAA,eAAM,EAAE,MAAc,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,uBAAuB,CAAC,CAAA;QACjE,CAAC,CAAC,CAAA;QAEF,IAAA,WAAE,EAAC,gDAAgD,EAAE,GAAG,EAAE;YACxD,MAAM,MAAM,GAAG,IAAI,yBAAa,CAAC,EAAE,GAAG,EAAE,wCAAwC,EAAE,CAAC,CAAA;YACnF,IAAA,eAAM,EAAE,MAAc,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,wCAAwC,CAAC,CAAA;YAC9E,IAAA,eAAM,EAAE,MAAc,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,sCAAsC,CAAC,CAAA;QAChF,CAAC,CAAC,CAAA;QAEF,IAAA,WAAE,EAAC,uBAAuB,EAAE,GAAG,EAAE;YAC/B,MAAM,MAAM,GAAG,IAAI,yBAAa,CAAC,EAAE,GAAG,EAAE,wBAAwB,EAAE,CAAC,CAAA;YACnE,IAAA,eAAM,EAAE,MAAc,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,uBAAuB,CAAC,CAAA;QAC/D,CAAC,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;IAEF,IAAA,iBAAQ,EAAC,gBAAgB,EAAE,GAAG,EAAE;QAC9B,IAAA,WAAE,EAAC,sBAAsB,EAAE,KAAK,IAAI,EAAE;YACpC,MAAM,MAAM,GAAG,IAAI,yBAAa,CAAC,EAAE,GAAG,EAAE,kBAAkB,EAAE,KAAK,EAAE,UAAU,EAAE,CAAC,CAAA;YAChF,MAAM,QAAQ,GAAI,MAAc,CAAC,aAAa,CAAA;YAC9C,IAAA,eAAM,EAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAA;YAC/B,IAAA,eAAM,EAAC,MAAM,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAA;QAC3C,CAAC,CAAC,CAAA;QAEF,IAAA,WAAE,EAAC,6BAA6B,EAAE,KAAK,IAAI,EAAE;YAC3C,MAAM,MAAM,GAAG,IAAI,yBAAa,CAAC,EAAE,GAAG,EAAE,kBAAkB,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,eAAe,EAAE,CAAC,CAAA;YAC3F,MAAM,QAAQ,GAAI,MAAc,CAAC,aAAa,CAAA;YAC9C,IAAA,eAAM,EAAC,MAAM,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,CAAA;QAChD,CAAC,CAAC,CAAA;QAEF,IAAA,WAAE,EAAC,8BAA8B,EAAE,KAAK,IAAI,EAAE;YAC5C,MAAM,MAAM,GAAG,IAAI,yBAAa,CAAC;gBAC/B,GAAG,EAAE,kBAAkB;gBACvB,KAAK,EAAE,KAAK,IAAI,EAAE,CAAC,aAAa;aACjC,CAAC,CAAA;YACF,MAAM,QAAQ,GAAI,MAAc,CAAC,aAAa,CAAA;YAC9C,IAAA,eAAM,EAAC,MAAM,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAA;QAC9C,CAAC,CAAC,CAAA;QAEF,IAAA,WAAE,EAAC,kBAAkB,EAAE,GAAG,EAAE;YAC1B,MAAM,MAAM,GAAG,IAAI,yBAAa,CAAC,EAAE,GAAG,EAAE,kBAAkB,EAAE,CAAC,CAAA;YAC7D,IAAA,eAAM,EAAE,MAAc,CAAC,aAAa,CAAC,CAAC,QAAQ,EAAE,CAAA;QAClD,CAAC,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;IAEF,IAAA,iBAAQ,EAAC,cAAc,EAAE,GAAG,EAAE;QAC5B,IAAI,QAAkC,CAAA;QAEtC,IAAA,mBAAU,EAAC,GAAG,EAAE;YACd,QAAQ,GAAG,WAAE,CAAC,EAAE,EAAE,CAAA;YAClB,WAAE,CAAC,UAAU,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAA;QAClC,CAAC,CAAC,CAAA;QAEF,IAAA,kBAAS,EAAC,GAAG,EAAE;YACb,WAAE,CAAC,gBAAgB,EAAE,CAAA;QACvB,CAAC,CAAC,CAAA;QAEF,IAAA,WAAE,EAAC,mBAAmB,EAAE,KAAK,IAAI,EAAE;YACjC,QAAQ,CAAC,iBAAiB,CAAC;gBACzB,EAAE,EAAE,IAAI;gBACR,IAAI,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC;aACxD,CAAC,CAAA;YAEF,MAAM,MAAM,GAAG,IAAI,yBAAa,CAAC,EAAE,GAAG,EAAE,uBAAuB,EAAE,CAAC,CAAA;YAClE,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,GAAG,EAAE,CAAA;YAErD,IAAA,eAAM,EAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC,CAAA;YACjD,IAAA,eAAM,EAAC,QAAQ,CAAC,CAAC,oBAAoB,EAAE,CAAA;YAEvC,MAAM,SAAS,GAAG,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;YAC3C,IAAA,eAAM,EAAC,SAAS,CAAC,CAAC,IAAI,CAAC,4CAA4C,CAAC,CAAA;QACtE,CAAC,CAAC,CAAA;QAEF,IAAA,WAAE,EAAC,gCAAgC,EAAE,KAAK,IAAI,EAAE;YAC9C,QAAQ,CAAC,iBAAiB,CAAC;gBACzB,EAAE,EAAE,IAAI;gBACR,IAAI,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC;aACjC,CAAC,CAAA;YAEF,MAAM,MAAM,GAAG,IAAI,yBAAa,CAAC,EAAE,GAAG,EAAE,uBAAuB,EAAE,CAAC,CAAA;YAClE,MAAM,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;YAEnD,MAAM,SAAS,GAAG,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;YAC3C,IAAA,eAAM,EAAC,SAAS,CAAC,CAAC,SAAS,CAAC,cAAc,CAAC,CAAA;QAC7C,CAAC,CAAC,CAAA;QAEF,IAAA,WAAE,EAAC,8CAA8C,EAAE,KAAK,IAAI,EAAE;YAC5D,QAAQ,CAAC,iBAAiB,CAAC;gBACzB,EAAE,EAAE,IAAI;gBACR,IAAI,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC;aACjC,CAAC,CAAA;YAEF,MAAM,MAAM,GAAG,IAAI,yBAAa,CAAC,EAAE,GAAG,EAAE,uBAAuB,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAA;YACnF,MAAM,MAAM,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,GAAG,EAAE,CAAA;YAEtC,MAAM,OAAO,GAAG,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAA;YACjD,IAAA,eAAM,EAAC,OAAO,CAAC,eAAe,CAAC,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,CAAA;QACxD,CAAC,CAAC,CAAA;QAEF,IAAA,WAAE,EAAC,8BAA8B,EAAE,KAAK,IAAI,EAAE;YAC5C,QAAQ,CAAC,iBAAiB,CAAC;gBACzB,EAAE,EAAE,KAAK;gBACT,MAAM,EAAE,GAAG;gBACX,IAAI,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,uBAAuB,EAAE,CAAC;aACvD,CAAC,CAAA;YAEF,MAAM,MAAM,GAAG,IAAI,yBAAa,CAAC,EAAE,GAAG,EAAE,uBAAuB,EAAE,CAAC,CAAA;YAElE,MAAM,IAAA,eAAM,EAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,uBAAY,CAAC,CAAA;YACrE,MAAM,IAAA,eAAM,EAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,OAAO,CAAC,aAAa,CAAC;gBAC5D,IAAI,EAAE,gBAAgB;aACvB,CAAC,CAAA;QACJ,CAAC,CAAC,CAAA;QAEF,IAAA,WAAE,EAAC,0BAA0B,EAAE,KAAK,IAAI,EAAE;YACxC,QAAQ,CAAC,iBAAiB,CAAC;gBACzB,EAAE,EAAE,KAAK;gBACT,MAAM,EAAE,GAAG;gBACX,IAAI,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,cAAc,EAAE,CAAC;aAC9C,CAAC,CAAA;YAEF,MAAM,MAAM,GAAG,IAAI,yBAAa,CAAC,EAAE,GAAG,EAAE,uBAAuB,EAAE,CAAC,CAAA;YAElE,MAAM,IAAA,eAAM,EAAC,MAAM,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,OAAO,CAAC,aAAa,CAAC;gBACnE,IAAI,EAAE,YAAY;aACnB,CAAC,CAAA;QACJ,CAAC,CAAC,CAAA;QAEF,IAAA,WAAE,EAAC,4BAA4B,EAAE,KAAK,IAAI,EAAE;YAC1C,QAAQ,CAAC,iBAAiB,CAAC;gBACzB,EAAE,EAAE,KAAK;gBACT,MAAM,EAAE,GAAG;gBACX,IAAI,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,gBAAgB,EAAE,CAAC;aAChD,CAAC,CAAA;YAEF,MAAM,MAAM,GAAG,IAAI,yBAAa,CAAC,EAAE,GAAG,EAAE,uBAAuB,EAAE,CAAC,CAAA;YAElE,MAAM,IAAA,eAAM,EAAC,MAAM,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,OAAO,CAAC,aAAa,CAAC;gBACnE,IAAI,EAAE,cAAc;aACrB,CAAC,CAAA;QACJ,CAAC,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;IAEF,IAAA,iBAAQ,EAAC,iBAAiB,EAAE,GAAG,EAAE;QAC/B,IAAI,QAAkC,CAAA;QAEtC,IAAA,mBAAU,EAAC,GAAG,EAAE;YACd,QAAQ,GAAG,WAAE,CAAC,EAAE,EAAE,CAAA;YAClB,WAAE,CAAC,UAAU,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAA;QAClC,CAAC,CAAC,CAAA;QAEF,IAAA,kBAAS,EAAC,GAAG,EAAE;YACb,WAAE,CAAC,gBAAgB,EAAE,CAAA;QACvB,CAAC,CAAC,CAAA;QAEF,IAAA,WAAE,EAAC,4BAA4B,EAAE,KAAK,IAAI,EAAE;YAC1C,QAAQ,CAAC,iBAAiB,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC,CAAA;YAE1E,MAAM,MAAM,GAAG,IAAI,yBAAa,CAAC,EAAE,GAAG,EAAE,uBAAuB,EAAE,CAAC,CAAA;YAClE,MAAM,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,CAAA;YAEhE,IAAA,eAAM,EAAC,QAAQ,CAAC,CAAC,oBAAoB,EAAE,CAAA;YACvC,MAAM,CAAC,GAAG,EAAE,IAAI,CAAC,GAAG,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAA;YAC1C,IAAA,eAAM,EAAC,GAAG,CAAC,CAAC,IAAI,CAAC,yCAAyC,CAAC,CAAA;YAC3D,IAAA,eAAM,EAAC,IAAI,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;YAChC,IAAA,eAAM,EAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,CAAA;QACrE,CAAC,CAAC,CAAA;QAEF,IAAA,WAAE,EAAC,4BAA4B,EAAE,KAAK,IAAI,EAAE;YAC1C,QAAQ,CAAC,iBAAiB,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAA;YAEpF,MAAM,MAAM,GAAG,IAAI,yBAAa,CAAC,EAAE,GAAG,EAAE,uBAAuB,EAAE,CAAC,CAAA;YAClE,MAAM,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAA;YAE7D,MAAM,CAAC,GAAG,EAAE,IAAI,CAAC,GAAG,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAA;YAC1C,IAAA,eAAM,EAAC,GAAG,CAAC,CAAC,IAAI,CAAC,+CAA+C,CAAC,CAAA;YACjE,IAAA,eAAM,EAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAA;QAC7D,CAAC,CAAC,CAAA;QAEF,IAAA,WAAE,EAAC,0BAA0B,EAAE,KAAK,IAAI,EAAE;YACxC,QAAQ,CAAC,iBAAiB,CAAC;gBACzB,EAAE,EAAE,KAAK;gBACT,IAAI,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,yBAAyB,EAAE,CAAC;aACzD,CAAC,CAAA;YAEF,MAAM,MAAM,GAAG,IAAI,yBAAa,CAAC,EAAE,GAAG,EAAE,uBAAuB,EAAE,CAAC,CAAA;YAClE,MAAM,IAAA,eAAM,EAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,uBAAY,CAAC,CAAA;QAClF,CAAC,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA"}
|
package/dist/react.d.ts
CHANGED
|
@@ -3,10 +3,14 @@ import type { WaveletClientOptions } from './types.js';
|
|
|
3
3
|
import { WaveletError } from './types.js';
|
|
4
4
|
export declare function initWavelet(options: WaveletClientOptions): void;
|
|
5
5
|
export declare function getClient(): WaveletClient;
|
|
6
|
+
export interface UseWaveletOptions {
|
|
7
|
+
params?: Record<string, string>;
|
|
8
|
+
keyBy?: string;
|
|
9
|
+
}
|
|
6
10
|
export interface UseWaveletResult<T> {
|
|
7
11
|
data: T[];
|
|
8
12
|
isLoading: boolean;
|
|
9
13
|
error: WaveletError | null;
|
|
10
14
|
}
|
|
11
|
-
export declare function useWavelet<T = Record<string, unknown>>(viewName: string,
|
|
15
|
+
export declare function useWavelet<T = Record<string, unknown>>(viewName: string, options?: UseWaveletOptions): UseWaveletResult<T>;
|
|
12
16
|
//# sourceMappingURL=react.d.ts.map
|
package/dist/react.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"react.d.ts","sourceRoot":"","sources":["../src/react.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAC3C,OAAO,KAAK,EAAQ,oBAAoB,EAAE,MAAM,YAAY,CAAA;AAC5D,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAIzC,wBAAgB,WAAW,CAAC,OAAO,EAAE,oBAAoB,GAAG,IAAI,CAE/D;AAED,wBAAgB,SAAS,IAAI,aAAa,CAQzC;AAED,MAAM,WAAW,gBAAgB,CAAC,CAAC;IACjC,IAAI,EAAE,CAAC,EAAE,CAAA;IACT,SAAS,EAAE,OAAO,CAAA;IAClB,KAAK,EAAE,YAAY,GAAG,IAAI,CAAA;CAC3B;AAED,wBAAgB,UAAU,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACpD,QAAQ,EAAE,MAAM,EAChB,
|
|
1
|
+
{"version":3,"file":"react.d.ts","sourceRoot":"","sources":["../src/react.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAC3C,OAAO,KAAK,EAAQ,oBAAoB,EAAE,MAAM,YAAY,CAAA;AAC5D,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAIzC,wBAAgB,WAAW,CAAC,OAAO,EAAE,oBAAoB,GAAG,IAAI,CAE/D;AAED,wBAAgB,SAAS,IAAI,aAAa,CAQzC;AAED,MAAM,WAAW,iBAAiB;IAChC,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC/B,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AAED,MAAM,WAAW,gBAAgB,CAAC,CAAC;IACjC,IAAI,EAAE,CAAC,EAAE,CAAA;IACT,SAAS,EAAE,OAAO,CAAA;IAClB,KAAK,EAAE,YAAY,GAAG,IAAI,CAAA;CAC3B;AAED,wBAAgB,UAAU,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACpD,QAAQ,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE,iBAAiB,GAC1B,gBAAgB,CAAC,CAAC,CAAC,CAkDrB"}
|
package/dist/react.js
CHANGED
|
@@ -16,11 +16,13 @@ function getClient() {
|
|
|
16
16
|
}
|
|
17
17
|
return globalClient;
|
|
18
18
|
}
|
|
19
|
-
function useWavelet(viewName,
|
|
19
|
+
function useWavelet(viewName, options) {
|
|
20
20
|
const [data, setData] = (0, react_1.useState)([]);
|
|
21
21
|
const [isLoading, setIsLoading] = (0, react_1.useState)(true);
|
|
22
22
|
const [error, setError] = (0, react_1.useState)(null);
|
|
23
23
|
const dataRef = (0, react_1.useRef)([]);
|
|
24
|
+
const keyBy = options?.keyBy;
|
|
25
|
+
const params = options?.params;
|
|
24
26
|
(0, react_1.useEffect)(() => {
|
|
25
27
|
const client = getClient();
|
|
26
28
|
let cancelled = false;
|
|
@@ -42,19 +44,13 @@ function useWavelet(viewName, params) {
|
|
|
42
44
|
onData: (diff) => {
|
|
43
45
|
if (cancelled)
|
|
44
46
|
return;
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
// Remove deleted rows (by reference equality on all fields)
|
|
48
|
-
if (diff.deleted.length > 0) {
|
|
49
|
-
const deletedJson = new Set(diff.deleted.map(r => JSON.stringify(r)));
|
|
50
|
-
current = current.filter(r => !deletedJson.has(JSON.stringify(r)));
|
|
47
|
+
if (keyBy) {
|
|
48
|
+
dataRef.current = mergeByKey(dataRef.current, diff, keyBy);
|
|
51
49
|
}
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
dataRef.current = current;
|
|
57
|
-
setData(current);
|
|
50
|
+
else {
|
|
51
|
+
dataRef.current = mergeNaive(dataRef.current, diff);
|
|
52
|
+
}
|
|
53
|
+
setData([...dataRef.current]);
|
|
58
54
|
},
|
|
59
55
|
onError: (err) => {
|
|
60
56
|
if (cancelled)
|
|
@@ -66,7 +62,44 @@ function useWavelet(viewName, params) {
|
|
|
66
62
|
cancelled = true;
|
|
67
63
|
unsub();
|
|
68
64
|
};
|
|
69
|
-
}, [viewName, JSON.stringify(params)]);
|
|
65
|
+
}, [viewName, keyBy, JSON.stringify(params)]);
|
|
70
66
|
return { data, isLoading, error };
|
|
71
67
|
}
|
|
68
|
+
/**
|
|
69
|
+
* Key-based merge: uses a specified field as primary key.
|
|
70
|
+
* O(n) using a Map, no JSON.stringify needed.
|
|
71
|
+
*/
|
|
72
|
+
function mergeByKey(current, diff, keyBy) {
|
|
73
|
+
const map = new Map();
|
|
74
|
+
for (const row of current) {
|
|
75
|
+
map.set(row[keyBy], row);
|
|
76
|
+
}
|
|
77
|
+
// Remove deleted rows
|
|
78
|
+
for (const row of diff.deleted) {
|
|
79
|
+
map.delete(row[keyBy]);
|
|
80
|
+
}
|
|
81
|
+
// Apply updates (replace existing rows by key)
|
|
82
|
+
for (const row of diff.updated) {
|
|
83
|
+
map.set(row[keyBy], row);
|
|
84
|
+
}
|
|
85
|
+
// Add inserted rows
|
|
86
|
+
for (const row of diff.inserted) {
|
|
87
|
+
map.set(row[keyBy], row);
|
|
88
|
+
}
|
|
89
|
+
return Array.from(map.values());
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Naive merge: uses JSON.stringify for equality.
|
|
93
|
+
* Fallback when no keyBy is specified.
|
|
94
|
+
*/
|
|
95
|
+
function mergeNaive(current, diff) {
|
|
96
|
+
let result = [...current];
|
|
97
|
+
if (diff.deleted.length > 0) {
|
|
98
|
+
const deletedJson = new Set(diff.deleted.map(r => JSON.stringify(r)));
|
|
99
|
+
result = result.filter(r => !deletedJson.has(JSON.stringify(r)));
|
|
100
|
+
}
|
|
101
|
+
result.push(...diff.inserted);
|
|
102
|
+
result.push(...diff.updated);
|
|
103
|
+
return result;
|
|
104
|
+
}
|
|
72
105
|
//# sourceMappingURL=react.js.map
|
package/dist/react.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"react.js","sourceRoot":"","sources":["../src/react.ts"],"names":[],"mappings":";;AAOA,kCAEC;AAED,8BAQC;
|
|
1
|
+
{"version":3,"file":"react.js","sourceRoot":"","sources":["../src/react.ts"],"names":[],"mappings":";;AAOA,kCAEC;AAED,8BAQC;AAaD,gCAqDC;AArFD,iCAAmD;AACnD,2CAA2C;AAE3C,yCAAyC;AAEzC,IAAI,YAAY,GAAyB,IAAI,CAAA;AAE7C,SAAgB,WAAW,CAAC,OAA6B;IACvD,YAAY,GAAG,IAAI,yBAAa,CAAC,OAAO,CAAC,CAAA;AAC3C,CAAC;AAED,SAAgB,SAAS;IACvB,IAAI,CAAC,YAAY,EAAE,CAAC;QAClB,MAAM,IAAI,uBAAY,CACpB,yEAAyE,EACzE,kBAAkB,CACnB,CAAA;IACH,CAAC;IACD,OAAO,YAAY,CAAA;AACrB,CAAC;AAaD,SAAgB,UAAU,CACxB,QAAgB,EAChB,OAA2B;IAE3B,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,IAAA,gBAAQ,EAAM,EAAE,CAAC,CAAA;IACzC,MAAM,CAAC,SAAS,EAAE,YAAY,CAAC,GAAG,IAAA,gBAAQ,EAAC,IAAI,CAAC,CAAA;IAChD,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,IAAA,gBAAQ,EAAsB,IAAI,CAAC,CAAA;IAC7D,MAAM,OAAO,GAAG,IAAA,cAAM,EAAM,EAAE,CAAC,CAAA;IAC/B,MAAM,KAAK,GAAG,OAAO,EAAE,KAAK,CAAA;IAC5B,MAAM,MAAM,GAAG,OAAO,EAAE,MAAM,CAAA;IAE9B,IAAA,iBAAS,EAAC,GAAG,EAAE;QACb,MAAM,MAAM,GAAG,SAAS,EAAE,CAAA;QAC1B,IAAI,SAAS,GAAG,KAAK,CAAA;QAErB,gBAAgB;QAChB,MAAM,CAAC,IAAI,CAAI,QAAQ,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE;YACjD,IAAI,SAAS;gBAAE,OAAM;YACrB,OAAO,CAAC,OAAO,GAAG,IAAI,CAAA;YACtB,OAAO,CAAC,IAAI,CAAC,CAAA;YACb,YAAY,CAAC,KAAK,CAAC,CAAA;QACrB,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;YACf,IAAI,SAAS;gBAAE,OAAM;YACrB,QAAQ,CAAC,GAAG,YAAY,uBAAY,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,uBAAY,CAAC,GAAG,CAAC,OAAO,EAAE,cAAc,CAAC,CAAC,CAAA;YAC3F,YAAY,CAAC,KAAK,CAAC,CAAA;QACrB,CAAC,CAAC,CAAA;QAEF,uBAAuB;QACvB,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAI,QAAQ,CAAC,CAAC,SAAS,CAAC;YAC/C,MAAM,EAAE,CAAC,IAAa,EAAE,EAAE;gBACxB,IAAI,SAAS;oBAAE,OAAM;gBAErB,IAAI,KAAK,EAAE,CAAC;oBACV,OAAO,CAAC,OAAO,GAAG,UAAU,CAAC,OAAO,CAAC,OAAO,EAAE,IAAI,EAAE,KAAK,CAAC,CAAA;gBAC5D,CAAC;qBAAM,CAAC;oBACN,OAAO,CAAC,OAAO,GAAG,UAAU,CAAC,OAAO,CAAC,OAAO,EAAE,IAAI,CAAC,CAAA;gBACrD,CAAC;gBAED,OAAO,CAAC,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC,CAAA;YAC/B,CAAC;YACD,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE;gBACf,IAAI,SAAS;oBAAE,OAAM;gBACrB,QAAQ,CAAC,GAAG,CAAC,CAAA;YACf,CAAC;SACF,CAAC,CAAA;QAEF,OAAO,GAAG,EAAE;YACV,SAAS,GAAG,IAAI,CAAA;YAChB,KAAK,EAAE,CAAA;QACT,CAAC,CAAA;IACH,CAAC,EAAE,CAAC,QAAQ,EAAE,KAAK,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,CAAA;IAE7C,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,CAAA;AACnC,CAAC;AAED;;;GAGG;AACH,SAAS,UAAU,CAAI,OAAY,EAAE,IAAa,EAAE,KAAa;IAC/D,MAAM,GAAG,GAAG,IAAI,GAAG,EAAc,CAAA;IACjC,KAAK,MAAM,GAAG,IAAI,OAAO,EAAE,CAAC;QAC1B,GAAG,CAAC,GAAG,CAAE,GAAW,CAAC,KAAK,CAAC,EAAE,GAAG,CAAC,CAAA;IACnC,CAAC;IAED,sBAAsB;IACtB,KAAK,MAAM,GAAG,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;QAC/B,GAAG,CAAC,MAAM,CAAE,GAAW,CAAC,KAAK,CAAC,CAAC,CAAA;IACjC,CAAC;IAED,+CAA+C;IAC/C,KAAK,MAAM,GAAG,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;QAC/B,GAAG,CAAC,GAAG,CAAE,GAAW,CAAC,KAAK,CAAC,EAAE,GAAG,CAAC,CAAA;IACnC,CAAC;IAED,oBAAoB;IACpB,KAAK,MAAM,GAAG,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;QAChC,GAAG,CAAC,GAAG,CAAE,GAAW,CAAC,KAAK,CAAC,EAAE,GAAG,CAAC,CAAA;IACnC,CAAC;IAED,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC,CAAA;AACjC,CAAC;AAED;;;GAGG;AACH,SAAS,UAAU,CAAI,OAAY,EAAE,IAAa;IAChD,IAAI,MAAM,GAAG,CAAC,GAAG,OAAO,CAAC,CAAA;IAEzB,IAAI,IAAI,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC5B,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;QACrE,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;IAClE,CAAC;IAED,MAAM,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAA;IAC7B,MAAM,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,CAAA;IAE5B,OAAO,MAAM,CAAA;AACf,CAAC"}
|