@nbt-dev/components 0.0.5

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.
Files changed (66) hide show
  1. package/LICENSE +177 -0
  2. package/README.md +10 -0
  3. package/TRADEMARKS.md +49 -0
  4. package/dist/chunk-3ZM6YOA4.js +704 -0
  5. package/dist/chunk-3ZM6YOA4.js.map +7 -0
  6. package/dist/chunk-7B2T5ZNG.js +467 -0
  7. package/dist/chunk-7B2T5ZNG.js.map +7 -0
  8. package/dist/chunk-S7VBQE6Y.js +636 -0
  9. package/dist/chunk-S7VBQE6Y.js.map +7 -0
  10. package/dist/chunk-UPEOXMLZ.js +625 -0
  11. package/dist/chunk-UPEOXMLZ.js.map +7 -0
  12. package/dist/core/auth.d.ts +13 -0
  13. package/dist/core/bulk-decoder.d.ts +13 -0
  14. package/dist/core/config.d.ts +10 -0
  15. package/dist/core/data-store.d.ts +20 -0
  16. package/dist/core/index.d.ts +9 -0
  17. package/dist/core/use-bulk-stream.d.ts +24 -0
  18. package/dist/core/use-cartridge-info.d.ts +14 -0
  19. package/dist/core/utils.d.ts +2 -0
  20. package/dist/editor/index.d.ts +7 -0
  21. package/dist/editor/index.js +16 -0
  22. package/dist/editor/index.js.map +7 -0
  23. package/dist/editor/lsp-client.d.ts +57 -0
  24. package/dist/editor/lsp-extensions.d.ts +4 -0
  25. package/dist/editor/nbt-editor.d.ts +13 -0
  26. package/dist/editor/nbt-language.d.ts +7 -0
  27. package/dist/generated/bulk-protocol.d.ts +36 -0
  28. package/dist/graph/diagram.d.ts +5 -0
  29. package/dist/graph/entity-graph-utils.d.ts +92 -0
  30. package/dist/graph/entity-node.d.ts +9 -0
  31. package/dist/graph/index.d.ts +5 -0
  32. package/dist/graph/index.js +19 -0
  33. package/dist/graph/index.js.map +7 -0
  34. package/dist/index.d.ts +4 -0
  35. package/dist/index.js +134 -0
  36. package/dist/index.js.map +7 -0
  37. package/dist/styles.css +2 -0
  38. package/dist/table/data-table.d.ts +9 -0
  39. package/dist/table/index.d.ts +3 -0
  40. package/dist/table/index.js +11 -0
  41. package/dist/table/index.js.map +7 -0
  42. package/dist/table/value-popover.d.ts +18 -0
  43. package/package.json +77 -0
  44. package/src/core/auth.ts +100 -0
  45. package/src/core/bulk-decoder.ts +178 -0
  46. package/src/core/config.tsx +39 -0
  47. package/src/core/data-store.ts +113 -0
  48. package/src/core/index.ts +34 -0
  49. package/src/core/use-bulk-stream.ts +412 -0
  50. package/src/core/use-cartridge-info.ts +100 -0
  51. package/src/core/utils.ts +6 -0
  52. package/src/editor/index.ts +13 -0
  53. package/src/editor/lsp-client.ts +227 -0
  54. package/src/editor/lsp-extensions.ts +191 -0
  55. package/src/editor/nbt-editor.tsx +142 -0
  56. package/src/editor/nbt-language.ts +151 -0
  57. package/src/generated/bulk-protocol.ts +63 -0
  58. package/src/graph/diagram.tsx +296 -0
  59. package/src/graph/entity-graph-utils.ts +423 -0
  60. package/src/graph/entity-node.tsx +122 -0
  61. package/src/graph/index.ts +19 -0
  62. package/src/index.ts +7 -0
  63. package/src/styles.css +94 -0
  64. package/src/table/data-table.tsx +274 -0
  65. package/src/table/index.ts +5 -0
  66. package/src/table/value-popover.tsx +230 -0
@@ -0,0 +1,704 @@
1
+ "use client";
2
+
3
+ // src/core/config.tsx
4
+ import React from "react";
5
+ import { jsx } from "react/jsx-runtime";
6
+ var DevToolsConfigContext = React.createContext({
7
+ apiBaseUrl: ""
8
+ });
9
+ var DevToolsConfigProvider = ({ apiBaseUrl = "", children }) => {
10
+ const value = React.useMemo(() => ({ apiBaseUrl }), [apiBaseUrl]);
11
+ return /* @__PURE__ */ jsx(DevToolsConfigContext.Provider, { value, children });
12
+ };
13
+ function useDevToolsConfig() {
14
+ return React.useContext(DevToolsConfigContext);
15
+ }
16
+ function wsBaseFrom(apiBaseUrl) {
17
+ if (!apiBaseUrl) {
18
+ const loc = window.location;
19
+ const proto = loc.protocol === "https:" ? "wss:" : "ws:";
20
+ return `${proto}//${loc.host}`;
21
+ }
22
+ return apiBaseUrl.replace(/^http(s?):/, "ws$1:");
23
+ }
24
+
25
+ // src/core/auth.ts
26
+ var TOKEN_KEY = "nbt_devtools_token";
27
+ function getDevToolsToken() {
28
+ try {
29
+ return localStorage.getItem(TOKEN_KEY);
30
+ } catch {
31
+ return null;
32
+ }
33
+ }
34
+ function setDevToolsToken(token) {
35
+ try {
36
+ localStorage.setItem(TOKEN_KEY, token);
37
+ } catch {
38
+ }
39
+ }
40
+ function clearDevToolsToken() {
41
+ try {
42
+ localStorage.removeItem(TOKEN_KEY);
43
+ } catch {
44
+ }
45
+ }
46
+ function authHeaders(base) {
47
+ const h = { ...base ?? {} };
48
+ const t = getDevToolsToken();
49
+ if (t) h["Authorization"] = `Bearer ${t}`;
50
+ return h;
51
+ }
52
+ async function fetchWhoAmI(apiBaseUrl, signal) {
53
+ const r = await fetch(`${apiBaseUrl}/_console/whoami`, {
54
+ signal,
55
+ credentials: "include",
56
+ headers: authHeaders()
57
+ });
58
+ if (!r.ok) throw new Error(`HTTP ${r.status}`);
59
+ return await r.json();
60
+ }
61
+ async function devToolsSignIn(apiBaseUrl, email, password) {
62
+ const r = await fetch(`${apiBaseUrl}/api/auth/user/signin`, {
63
+ method: "POST",
64
+ credentials: "include",
65
+ headers: { "content-type": "application/json" },
66
+ body: JSON.stringify({ email, password })
67
+ });
68
+ if (!r.ok) {
69
+ throw new Error(r.status === 401 ? "Invalid email or password" : `Sign-in failed (HTTP ${r.status})`);
70
+ }
71
+ const j = await r.json();
72
+ if (!j.token) throw new Error("Sign-in returned no token");
73
+ setDevToolsToken(j.token);
74
+ }
75
+ function devToolsSignOut() {
76
+ clearDevToolsToken();
77
+ }
78
+ function base64UrlEncode(value) {
79
+ if (typeof btoa === "function") {
80
+ return btoa(value).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/g, "");
81
+ }
82
+ throw new Error("No base64 encoder available for WS auth");
83
+ }
84
+ function wsAuthProtocols(name) {
85
+ const t = getDevToolsToken();
86
+ return t ? [name, `auth-${base64UrlEncode(t)}`] : [name];
87
+ }
88
+
89
+ // src/core/use-bulk-stream.ts
90
+ import React2, {
91
+ createContext,
92
+ useContext,
93
+ useEffect,
94
+ useRef,
95
+ useState
96
+ } from "react";
97
+
98
+ // src/generated/bulk-protocol.ts
99
+ var FRAME_SCHEMA = 1;
100
+ var FRAME_DATA = 2;
101
+ var FRAME_DATA_END = 3;
102
+ var FRAME_DELTA_INS = 4;
103
+ var FRAME_DELTA_UPD = 5;
104
+ var FRAME_DELTA_DEL = 6;
105
+ var FRAME_ERROR = 255;
106
+ var TYPE_U8 = 1;
107
+ var TYPE_U16 = 2;
108
+ var TYPE_U32 = 3;
109
+ var TYPE_U64 = 4;
110
+ var TYPE_S8 = 5;
111
+ var TYPE_S16 = 6;
112
+ var TYPE_S32 = 7;
113
+ var TYPE_S64 = 8;
114
+ var TYPE_BOOL = 9;
115
+ var TYPE_FLOAT32 = 10;
116
+ var TYPE_FLOAT64 = 11;
117
+ var TYPE_STRING = 12;
118
+ var TYPE_DATETIME = 13;
119
+ var TYPE_DOCUMENT = 14;
120
+ function fixedSizeForType(type) {
121
+ switch (type) {
122
+ case TYPE_U8:
123
+ return 1;
124
+ case TYPE_U16:
125
+ return 2;
126
+ case TYPE_U32:
127
+ return 4;
128
+ case TYPE_U64:
129
+ return 8;
130
+ case TYPE_S8:
131
+ return 1;
132
+ case TYPE_S16:
133
+ return 2;
134
+ case TYPE_S32:
135
+ return 4;
136
+ case TYPE_S64:
137
+ return 8;
138
+ case TYPE_BOOL:
139
+ return 1;
140
+ case TYPE_FLOAT32:
141
+ return 4;
142
+ case TYPE_FLOAT64:
143
+ return 8;
144
+ case TYPE_STRING:
145
+ return 0;
146
+ case TYPE_DATETIME:
147
+ return 8;
148
+ case TYPE_DOCUMENT:
149
+ return 0;
150
+ default:
151
+ return 0;
152
+ }
153
+ }
154
+
155
+ // src/core/data-store.ts
156
+ var BulkDataStore = class {
157
+ constructor() {
158
+ this.columns = [];
159
+ this.rows = [];
160
+ this.totalRows = 0;
161
+ this.searchActive = false;
162
+ this._fullRows = [];
163
+ this._fullTotalRows = 0;
164
+ this._idColIndex = -1;
165
+ this._query = "";
166
+ }
167
+ applySchema(schema) {
168
+ this.columns = schema.columns;
169
+ this.totalRows = schema.totalRows;
170
+ this.rows = [];
171
+ this._fullRows = [];
172
+ this._fullTotalRows = schema.totalRows;
173
+ this.searchActive = false;
174
+ this._query = "";
175
+ this._idColIndex = schema.columns.findIndex((c) => c.name === "id");
176
+ }
177
+ appendChunk(chunk) {
178
+ for (let i = 0; i < chunk.length; i++) {
179
+ const row = chunk[i];
180
+ this._fullRows.push(row);
181
+ if (!this.searchActive) this.rows.push(row);
182
+ }
183
+ }
184
+ applyDelta(delta) {
185
+ const target = this._fullRows;
186
+ if (delta.op === FRAME_DELTA_INS && delta.rowData) {
187
+ target.push(delta.rowData);
188
+ this._fullTotalRows++;
189
+ this.totalRows++;
190
+ if (!this.searchActive) this.rows = this._fullRows;
191
+ else this._applySearch();
192
+ return;
193
+ }
194
+ if (delta.op === FRAME_DELTA_UPD && delta.rowData) {
195
+ const idx = this._findRowById(target, delta.rowData);
196
+ if (idx >= 0) target[idx] = delta.rowData;
197
+ if (this.searchActive) this._applySearch();
198
+ return;
199
+ }
200
+ if (delta.op === FRAME_DELTA_DEL && delta.id !== void 0) {
201
+ const idStr = String(delta.id);
202
+ const idx = this._findRowByIdStr(target, idStr);
203
+ if (idx >= 0) {
204
+ target.splice(idx, 1);
205
+ this._fullTotalRows--;
206
+ this.totalRows--;
207
+ if (!this.searchActive) this.rows = this._fullRows;
208
+ else this._applySearch();
209
+ }
210
+ return;
211
+ }
212
+ }
213
+ search(query) {
214
+ const q = query.trim().toLowerCase();
215
+ if (!q) {
216
+ this.exitSearch();
217
+ return;
218
+ }
219
+ this.searchActive = true;
220
+ this._query = q;
221
+ this._applySearch();
222
+ }
223
+ exitSearch() {
224
+ if (!this.searchActive) return;
225
+ this.rows = this._fullRows;
226
+ this.totalRows = this._fullTotalRows;
227
+ this.searchActive = false;
228
+ this._query = "";
229
+ }
230
+ getRowCount() {
231
+ return this.rows.length;
232
+ }
233
+ _findRowById(rows, rowData) {
234
+ if (this._idColIndex < 0) return -1;
235
+ const id = rowData[this._idColIndex];
236
+ for (let i = 0; i < rows.length; i++) {
237
+ if (rows[i][this._idColIndex] === id) return i;
238
+ }
239
+ return -1;
240
+ }
241
+ _findRowByIdStr(rows, idStr) {
242
+ if (this._idColIndex < 0) return -1;
243
+ for (let i = 0; i < rows.length; i++) {
244
+ if (rows[i][this._idColIndex] === idStr) return i;
245
+ }
246
+ return -1;
247
+ }
248
+ _applySearch() {
249
+ this.rows = this._fullRows.filter(
250
+ (row) => row.some((value) => value.toLowerCase().includes(this._query))
251
+ );
252
+ this.totalRows = this.rows.length;
253
+ }
254
+ };
255
+
256
+ // src/core/bulk-decoder.ts
257
+ var textDecoder = new TextDecoder();
258
+ var SID_BYTES = 2;
259
+ var HEAD = 1 + SID_BYTES;
260
+ function epochToDate(epoch) {
261
+ const abs = Math.abs(epoch);
262
+ if (abs < 1e10) return new Date(epoch * 1e3);
263
+ if (abs < 1e13) return new Date(epoch);
264
+ if (abs < 1e16) return new Date(epoch / 1e3);
265
+ return new Date(epoch / 1e6);
266
+ }
267
+ function formatCellValue(view, offset, col) {
268
+ switch (col.type) {
269
+ case TYPE_U8:
270
+ return [String(view.getUint8(offset)), 1];
271
+ case TYPE_S8:
272
+ return [String(view.getInt8(offset)), 1];
273
+ case TYPE_BOOL:
274
+ return [view.getUint8(offset) ? "true" : "false", 1];
275
+ case TYPE_U16:
276
+ return [String(view.getUint16(offset, true)), 2];
277
+ case TYPE_S16:
278
+ return [String(view.getInt16(offset, true)), 2];
279
+ case TYPE_U32:
280
+ return [String(view.getUint32(offset, true)), 4];
281
+ case TYPE_S32:
282
+ return [String(view.getInt32(offset, true)), 4];
283
+ case TYPE_FLOAT32:
284
+ return [String(view.getFloat32(offset, true)), 4];
285
+ case TYPE_U64:
286
+ return [String(view.getBigUint64(offset, true)), 8];
287
+ case TYPE_S64:
288
+ return [String(view.getBigInt64(offset, true)), 8];
289
+ case TYPE_FLOAT64:
290
+ return [String(view.getFloat64(offset, true)), 8];
291
+ case TYPE_DATETIME: {
292
+ const epoch = Number(view.getBigInt64(offset, true));
293
+ if (epoch === 0) return ["", 8];
294
+ return [epochToDate(epoch).toISOString(), 8];
295
+ }
296
+ case TYPE_STRING:
297
+ case TYPE_DOCUMENT: {
298
+ const len = view.getUint32(offset, true);
299
+ const bytes = new Uint8Array(view.buffer, view.byteOffset + offset + 4, len);
300
+ return [textDecoder.decode(bytes), 4 + len];
301
+ }
302
+ default:
303
+ return ["", 0];
304
+ }
305
+ }
306
+ function getFrameType(buf) {
307
+ return new DataView(buf).getUint8(0);
308
+ }
309
+ function getFrameSid(buf) {
310
+ return new DataView(buf).getUint16(1, true);
311
+ }
312
+ function parseSchema(buf) {
313
+ const view = new DataView(buf);
314
+ let offset = 0;
315
+ const frameType = view.getUint8(offset);
316
+ offset += 1;
317
+ if (frameType !== FRAME_SCHEMA) {
318
+ throw new Error(`Expected SCHEMA frame (0x01), got 0x${frameType.toString(16)}`);
319
+ }
320
+ offset += SID_BYTES;
321
+ const totalRows = view.getUint32(offset, true);
322
+ offset += 4;
323
+ const columnCount = view.getUint16(offset, true);
324
+ offset += 2;
325
+ const columns = [];
326
+ for (let i = 0; i < columnCount; i++) {
327
+ const type = view.getUint8(offset);
328
+ offset += 1;
329
+ const nameLen = view.getUint16(offset, true);
330
+ offset += 2;
331
+ const nameBytes = new Uint8Array(buf, offset, nameLen);
332
+ const name = textDecoder.decode(nameBytes);
333
+ offset += nameLen;
334
+ columns.push({ name, type, fixedSize: fixedSizeForType(type) });
335
+ }
336
+ return { totalRows, columns };
337
+ }
338
+ function parseDataChunk(buf, columns) {
339
+ const view = new DataView(buf);
340
+ let offset = 0;
341
+ const frameType = view.getUint8(offset);
342
+ offset += 1;
343
+ if (frameType !== FRAME_DATA) {
344
+ throw new Error(`Expected DATA frame, got 0x${frameType.toString(16)}`);
345
+ }
346
+ offset += SID_BYTES;
347
+ const rowCount = view.getUint16(offset, true);
348
+ offset += 2;
349
+ const rows = [];
350
+ for (let r = 0; r < rowCount; r++) {
351
+ const row = [];
352
+ for (let c = 0; c < columns.length; c++) {
353
+ const [value, bytesRead] = formatCellValue(view, offset, columns[c]);
354
+ row.push(value);
355
+ offset += bytesRead;
356
+ }
357
+ rows.push(row);
358
+ }
359
+ return rows;
360
+ }
361
+ function parseDelta(buf, columns) {
362
+ const view = new DataView(buf);
363
+ let offset = 0;
364
+ const op = view.getUint8(offset);
365
+ offset += 1;
366
+ offset += SID_BYTES;
367
+ if (op === FRAME_DELTA_DEL) {
368
+ const len = view.getUint16(offset, true);
369
+ offset += 2;
370
+ const bytes = new Uint8Array(buf, offset, len);
371
+ return { op, id: textDecoder.decode(bytes) };
372
+ }
373
+ if (op === FRAME_DELTA_INS || op === FRAME_DELTA_UPD) {
374
+ const rowData = [];
375
+ for (let c = 0; c < columns.length; c++) {
376
+ const [value, bytesRead] = formatCellValue(view, offset, columns[c]);
377
+ rowData.push(value);
378
+ offset += bytesRead;
379
+ }
380
+ return { op, rowData };
381
+ }
382
+ throw new Error(`Unknown delta op 0x${op.toString(16)}`);
383
+ }
384
+ function parseError(buf) {
385
+ const view = new DataView(buf);
386
+ const len = view.getUint16(HEAD, true);
387
+ const bytes = new Uint8Array(buf, HEAD + 2, len);
388
+ return textDecoder.decode(bytes);
389
+ }
390
+ function encodeStreamCmd(sid, cart, entity, opts) {
391
+ return JSON.stringify({ cmd: "sub", sid, cart, entity, ...opts });
392
+ }
393
+
394
+ // src/core/use-bulk-stream.ts
395
+ var BulkStreamContext = createContext(null);
396
+ function base64UrlEncode2(value) {
397
+ if (typeof btoa === "function") {
398
+ return btoa(value).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/g, "");
399
+ }
400
+ throw new Error("No base64 encoder available for bulk WS auth");
401
+ }
402
+ function bulkAuthProtocols(token) {
403
+ return ["nimbit-bulk", `auth-${base64UrlEncode2(token)}`];
404
+ }
405
+ var _wsTokenCache = null;
406
+ var WS_TOKEN_TTL_MS = 6e4;
407
+ async function fetchWsToken(signal, apiBaseUrl) {
408
+ const own = getDevToolsToken();
409
+ if (own) return own;
410
+ const now = Date.now();
411
+ if (_wsTokenCache?.apiBaseUrl === apiBaseUrl && now - _wsTokenCache.at < WS_TOKEN_TTL_MS) {
412
+ return _wsTokenCache.token;
413
+ }
414
+ const r = await fetch(`${apiBaseUrl}/api/auth/session/current`, {
415
+ method: "POST",
416
+ signal,
417
+ credentials: "include",
418
+ headers: { "content-type": "application/json" }
419
+ });
420
+ if (!r.ok) return null;
421
+ const j = await r.json();
422
+ const token = j.session?.token;
423
+ if (!token) return null;
424
+ _wsTokenCache = { apiBaseUrl, token, at: now };
425
+ return token;
426
+ }
427
+ function invalidateWsToken() {
428
+ _wsTokenCache = null;
429
+ }
430
+ function notify(view) {
431
+ view.listeners.forEach((cb) => cb());
432
+ }
433
+ function BulkStreamProvider({ registry, children }) {
434
+ const { apiBaseUrl } = useDevToolsConfig();
435
+ const wsRef = useRef(null);
436
+ const sendQueueRef = useRef([]);
437
+ const sidCounterRef = useRef(1);
438
+ const viewsBySidRef = useRef(/* @__PURE__ */ new Map());
439
+ const viewsByKeyRef = useRef(/* @__PURE__ */ new Map());
440
+ const preloadedRef = useRef(false);
441
+ const [connected, setConnected] = useState(false);
442
+ const [error, setError] = useState(null);
443
+ const sendCmd = (cmd) => {
444
+ const ws = wsRef.current;
445
+ if (ws && ws.readyState === WebSocket.OPEN) ws.send(cmd);
446
+ else sendQueueRef.current.push(cmd);
447
+ };
448
+ const flushQueue = () => {
449
+ const ws = wsRef.current;
450
+ if (!ws || ws.readyState !== WebSocket.OPEN) return;
451
+ const q = sendQueueRef.current;
452
+ sendQueueRef.current = [];
453
+ for (const cmd of q) ws.send(cmd);
454
+ };
455
+ const getView = (cart, entity) => {
456
+ const entLower = entity.toLowerCase();
457
+ const key = `${cart}/${entLower}`;
458
+ const existing = viewsByKeyRef.current.get(key);
459
+ if (existing) return existing;
460
+ const sid = sidCounterRef.current++;
461
+ const view = {
462
+ sid,
463
+ cart,
464
+ entity: entLower,
465
+ store: new BulkDataStore(),
466
+ columns: [],
467
+ totalRows: 0,
468
+ loadedRows: 0,
469
+ streaming: false,
470
+ error: null,
471
+ streamRequested: false,
472
+ onRender: null,
473
+ listeners: /* @__PURE__ */ new Set()
474
+ };
475
+ viewsByKeyRef.current.set(key, view);
476
+ viewsBySidRef.current.set(sid, view);
477
+ return view;
478
+ };
479
+ const ensureStreamed = (view) => {
480
+ if (view.streamRequested) return;
481
+ view.streamRequested = true;
482
+ sendCmd(encodeStreamCmd(view.sid, view.cart, view.entity));
483
+ };
484
+ const handleMessage = (ev) => {
485
+ const buf = ev.data;
486
+ const sid = getFrameSid(buf);
487
+ const view = viewsBySidRef.current.get(sid);
488
+ if (!view) return;
489
+ const ft = getFrameType(buf);
490
+ const store = view.store;
491
+ switch (ft) {
492
+ case FRAME_SCHEMA: {
493
+ const schema = parseSchema(buf);
494
+ store.applySchema(schema);
495
+ view.columns = schema.columns;
496
+ view.totalRows = schema.totalRows;
497
+ view.loadedRows = 0;
498
+ view.streaming = true;
499
+ notify(view);
500
+ break;
501
+ }
502
+ case FRAME_DATA: {
503
+ const rows = parseDataChunk(buf, store.columns);
504
+ store.appendChunk(rows);
505
+ view.loadedRows = store.getRowCount();
506
+ view.onRender?.();
507
+ break;
508
+ }
509
+ case FRAME_DATA_END:
510
+ view.streaming = false;
511
+ notify(view);
512
+ break;
513
+ case FRAME_DELTA_INS:
514
+ case FRAME_DELTA_UPD:
515
+ case FRAME_DELTA_DEL: {
516
+ const delta = parseDelta(buf, store.columns);
517
+ store.applyDelta(delta);
518
+ view.totalRows = store.totalRows;
519
+ view.loadedRows = store.getRowCount();
520
+ view.onRender?.();
521
+ notify(view);
522
+ break;
523
+ }
524
+ case FRAME_ERROR:
525
+ view.error = parseError(buf);
526
+ view.streaming = false;
527
+ notify(view);
528
+ break;
529
+ }
530
+ };
531
+ useEffect(() => {
532
+ const ac = new AbortController();
533
+ let cancelled = false;
534
+ let opened = false;
535
+ let ws = null;
536
+ sendQueueRef.current = [];
537
+ sidCounterRef.current = 1;
538
+ viewsBySidRef.current.clear();
539
+ viewsByKeyRef.current.clear();
540
+ preloadedRef.current = false;
541
+ setConnected(false);
542
+ setError(null);
543
+ (async () => {
544
+ let token = null;
545
+ try {
546
+ token = await fetchWsToken(ac.signal, apiBaseUrl);
547
+ } catch {
548
+ }
549
+ if (cancelled) return;
550
+ ws = token ? new WebSocket(`${wsBaseFrom(apiBaseUrl)}/_ws/bulk`, bulkAuthProtocols(token)) : new WebSocket(`${wsBaseFrom(apiBaseUrl)}/_ws/bulk`, ["nimbit-bulk"]);
551
+ ws.binaryType = "arraybuffer";
552
+ wsRef.current = ws;
553
+ ws.onopen = () => {
554
+ if (cancelled || wsRef.current !== ws) return;
555
+ opened = true;
556
+ setConnected(true);
557
+ setError(null);
558
+ flushQueue();
559
+ };
560
+ ws.onmessage = handleMessage;
561
+ ws.onerror = () => {
562
+ };
563
+ ws.onclose = () => {
564
+ if (cancelled || wsRef.current !== ws) return;
565
+ setConnected(false);
566
+ wsRef.current = null;
567
+ if (!opened) {
568
+ invalidateWsToken();
569
+ setError("WebSocket connection closed");
570
+ }
571
+ };
572
+ })();
573
+ return () => {
574
+ cancelled = true;
575
+ ac.abort();
576
+ if (ws) {
577
+ ws.onopen = ws.onmessage = ws.onerror = ws.onclose = null;
578
+ try {
579
+ ws.close();
580
+ } catch {
581
+ }
582
+ if (wsRef.current === ws) wsRef.current = null;
583
+ }
584
+ };
585
+ }, [apiBaseUrl]);
586
+ useEffect(() => {
587
+ if (!connected) return;
588
+ if (preloadedRef.current) return;
589
+ const keys = Object.keys(registry);
590
+ if (keys.length === 0) return;
591
+ preloadedRef.current = true;
592
+ for (const cart of keys) {
593
+ for (const ent of registry[cart] ?? []) {
594
+ const view = getView(cart, ent.name);
595
+ ensureStreamed(view);
596
+ }
597
+ }
598
+ }, [connected, registry]);
599
+ const search = (view, query) => {
600
+ view.store.search(query);
601
+ view.totalRows = view.store.totalRows;
602
+ view.loadedRows = view.store.getRowCount();
603
+ notify(view);
604
+ view.onRender?.();
605
+ };
606
+ const clearSearch = (view) => {
607
+ view.store.exitSearch();
608
+ view.totalRows = view.store.totalRows;
609
+ view.loadedRows = view.store.getRowCount();
610
+ notify(view);
611
+ view.onRender?.();
612
+ };
613
+ const subscribe = (view, cb) => {
614
+ view.listeners.add(cb);
615
+ return () => {
616
+ view.listeners.delete(cb);
617
+ };
618
+ };
619
+ const ctx = {
620
+ getView,
621
+ ensureStreamed,
622
+ search,
623
+ clearSearch,
624
+ subscribe,
625
+ connected,
626
+ error
627
+ };
628
+ return React2.createElement(BulkStreamContext.Provider, { value: ctx }, children);
629
+ }
630
+ function useBulkRowCounts(registry) {
631
+ const ctx = useContext(BulkStreamContext);
632
+ if (!ctx) throw new Error("useBulkRowCounts must be used within BulkStreamProvider");
633
+ const [, force] = useState(0);
634
+ const pairs = [];
635
+ for (const cart of Object.keys(registry)) {
636
+ for (const ent of registry[cart] ?? []) {
637
+ pairs.push({ id: `${cart}:${ent.name}`, view: ctx.getView(cart, ent.name) });
638
+ }
639
+ }
640
+ const key = pairs.map((p) => p.id).join("|");
641
+ useEffect(() => {
642
+ const unsubs = pairs.map((p) => ctx.subscribe(p.view, () => force((n) => n + 1)));
643
+ return () => unsubs.forEach((u) => u());
644
+ }, [key]);
645
+ const counts = {};
646
+ for (const p of pairs) counts[p.id] = p.view.totalRows;
647
+ return counts;
648
+ }
649
+ function useBulkSubscription(cart, entity) {
650
+ const ctx = useContext(BulkStreamContext);
651
+ if (!ctx) throw new Error("useBulkSubscription must be used within BulkStreamProvider");
652
+ const view = ctx.getView(cart, entity);
653
+ const [, force] = useState(0);
654
+ useEffect(() => {
655
+ const unsub = ctx.subscribe(view, () => force((n) => n + 1));
656
+ ctx.ensureStreamed(view);
657
+ return unsub;
658
+ }, [view]);
659
+ return {
660
+ store: view.store,
661
+ connected: ctx.connected,
662
+ streaming: view.streaming,
663
+ error: view.error ?? ctx.error,
664
+ columns: view.columns,
665
+ totalRows: view.totalRows,
666
+ loadedRows: view.loadedRows,
667
+ search: (q) => ctx.search(view, q),
668
+ clearSearch: () => ctx.clearSearch(view),
669
+ setOnRender: (fn) => {
670
+ view.onRender = fn;
671
+ }
672
+ };
673
+ }
674
+
675
+ export {
676
+ DevToolsConfigProvider,
677
+ useDevToolsConfig,
678
+ wsBaseFrom,
679
+ TYPE_U8,
680
+ TYPE_U16,
681
+ TYPE_U32,
682
+ TYPE_U64,
683
+ TYPE_S8,
684
+ TYPE_S16,
685
+ TYPE_S32,
686
+ TYPE_S64,
687
+ TYPE_BOOL,
688
+ TYPE_FLOAT32,
689
+ TYPE_FLOAT64,
690
+ TYPE_DATETIME,
691
+ TYPE_DOCUMENT,
692
+ getDevToolsToken,
693
+ setDevToolsToken,
694
+ clearDevToolsToken,
695
+ authHeaders,
696
+ fetchWhoAmI,
697
+ devToolsSignIn,
698
+ devToolsSignOut,
699
+ wsAuthProtocols,
700
+ BulkStreamProvider,
701
+ useBulkRowCounts,
702
+ useBulkSubscription
703
+ };
704
+ //# sourceMappingURL=chunk-3ZM6YOA4.js.map