tina4-nodejs 3.13.141 → 3.13.142

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 (38) hide show
  1. package/CLAUDE.md +2 -2
  2. package/package.json +1 -1
  3. package/packages/cli/dist/bin.js +438 -453
  4. package/packages/cli/src/bin.ts +4 -14
  5. package/packages/cli/src/commands/build.ts +2 -18
  6. package/packages/cli/src/commands/generate.ts +2 -22
  7. package/packages/cli/src/commands/lint.ts +3 -13
  8. package/packages/cli/src/commands/migrate.ts +2 -6
  9. package/packages/cli/src/commands/migrateRollback.ts +2 -6
  10. package/packages/cli/src/commands/migrateStatus.ts +2 -6
  11. package/packages/cli/src/commands/queue.ts +2 -30
  12. package/packages/cli/src/util.ts +90 -0
  13. package/packages/core/dist/index.js +215 -184
  14. package/packages/core/gallery/queue/src/lib/queueDb.ts +11 -0
  15. package/packages/core/gallery/queue/src/routes/api/gallery/queue/consume/post.ts +2 -5
  16. package/packages/core/gallery/queue/src/routes/api/gallery/queue/fail/post.ts +2 -5
  17. package/packages/core/src/devAdmin.ts +3 -12
  18. package/packages/core/src/dispatchPipeline.ts +2 -18
  19. package/packages/core/src/etag.ts +24 -0
  20. package/packages/core/src/feedback.ts +2 -11
  21. package/packages/core/src/session.ts +22 -66
  22. package/packages/core/src/sessionHandlers/respSessionHandler.ts +94 -0
  23. package/packages/core/src/sessionHandlers/valkeyHandler.ts +22 -73
  24. package/packages/core/src/static.ts +1 -13
  25. package/packages/core/src/upstreamResponse.ts +31 -0
  26. package/packages/core/src/websocket.ts +48 -7
  27. package/packages/orm/dist/index.js +215 -184
  28. package/packages/orm/src/graph/adapters/bolt.ts +8 -29
  29. package/packages/orm/src/graph/adapters/rowMapping.ts +57 -0
  30. package/packages/orm/src/graph/adapters/ultipa.ts +8 -30
  31. package/types/cli/src/util.d.ts +28 -0
  32. package/types/core/src/etag.d.ts +9 -0
  33. package/types/core/src/session.d.ts +2 -19
  34. package/types/core/src/sessionHandlers/respSessionHandler.d.ts +52 -0
  35. package/types/core/src/sessionHandlers/valkeyHandler.d.ts +2 -26
  36. package/types/core/src/upstreamResponse.d.ts +10 -0
  37. package/types/core/src/websocket.d.ts +21 -0
  38. package/types/orm/src/graph/adapters/rowMapping.d.ts +26 -0
@@ -10361,6 +10361,21 @@ var init_portTakeover = __esm({
10361
10361
  }
10362
10362
  });
10363
10363
 
10364
+ // ../core/src/etag.ts
10365
+ function etagMatches(ifNoneMatch, etag) {
10366
+ const strip = (tag) => tag.trim().replace(/^W\//, "");
10367
+ const target = strip(etag);
10368
+ return ifNoneMatch.split(",").some((candidate) => {
10369
+ const trimmed = candidate.trim();
10370
+ return trimmed === "*" || strip(trimmed) === target;
10371
+ });
10372
+ }
10373
+ var init_etag = __esm({
10374
+ "../core/src/etag.ts"() {
10375
+ "use strict";
10376
+ }
10377
+ });
10378
+
10364
10379
  // ../core/src/sessionHandlers/syncBridge.ts
10365
10380
  import { Worker } from "node:worker_threads";
10366
10381
  function getBridge(key, workerSource, workerData) {
@@ -10642,42 +10657,35 @@ var init_respClient = __esm({
10642
10657
  }
10643
10658
  });
10644
10659
 
10645
- // ../core/src/sessionHandlers/valkeyHandler.ts
10646
- var ValkeySessionHandler;
10647
- var init_valkeyHandler = __esm({
10648
- "../core/src/sessionHandlers/valkeyHandler.ts"() {
10660
+ // ../core/src/sessionHandlers/respSessionHandler.ts
10661
+ var RespSessionHandler;
10662
+ var init_respSessionHandler = __esm({
10663
+ "../core/src/sessionHandlers/respSessionHandler.ts"() {
10649
10664
  "use strict";
10650
10665
  init_respClient();
10651
- ValkeySessionHandler = class {
10652
- host;
10653
- port;
10654
- password;
10655
- prefix;
10656
- db;
10657
- constructor(config) {
10658
- this.host = config?.host ?? process.env.TINA4_SESSION_VALKEY_HOST ?? "127.0.0.1";
10659
- this.port = config?.port ?? (process.env.TINA4_SESSION_VALKEY_PORT ? parseInt(process.env.TINA4_SESSION_VALKEY_PORT, 10) : 6379);
10660
- this.password = config?.password ?? process.env.TINA4_SESSION_VALKEY_PASSWORD ?? "";
10661
- this.prefix = config?.prefix ?? process.env.TINA4_SESSION_VALKEY_PREFIX ?? "tina4:session:";
10662
- this.db = config?.db ?? (process.env.TINA4_SESSION_VALKEY_DB ? parseInt(process.env.TINA4_SESSION_VALKEY_DB, 10) : 0);
10666
+ RespSessionHandler = class {
10667
+ constructor(conn, label) {
10668
+ this.conn = conn;
10669
+ this.label = label;
10663
10670
  }
10671
+ conn;
10672
+ label;
10664
10673
  /**
10665
- * Execute a RESP command synchronously against the live Valkey server.
10674
+ * Execute a RESP command synchronously against the live server.
10666
10675
  *
10667
- * Delegates to the shared {@link respCommandSync} transport: a genuine key miss
10668
- * yields `""`, and a transport/connection FAILURE (server unreachable, rejected
10669
- * AUTH, timeout) THROWS so the Session boundary can distinguish "not found"
10670
- * (silent) from "backend failed" (log-loud + degrade). Backend-failure parity.
10676
+ * Delegates to the shared {@link respCommandSync} transport: a genuine key
10677
+ * miss yields `""`, and a transport/connection FAILURE THROWS so the caller
10678
+ * can distinguish "not found" from "backend failed". Backend-failure parity.
10671
10679
  */
10672
10680
  execSync(args) {
10673
10681
  return respCommandSync(
10674
- { host: this.host, port: this.port, password: this.password, db: this.db },
10682
+ { host: this.conn.host, port: this.conn.port, password: this.conn.password, db: this.conn.db },
10675
10683
  args,
10676
- "Valkey"
10684
+ this.label
10677
10685
  );
10678
10686
  }
10679
10687
  key(sessionId) {
10680
- return `${this.prefix}${sessionId}`;
10688
+ return `${this.conn.prefix}${sessionId}`;
10681
10689
  }
10682
10690
  read(sessionId) {
10683
10691
  const raw = this.execSync(["GET", this.key(sessionId)]);
@@ -10688,7 +10696,7 @@ var init_valkeyHandler = __esm({
10688
10696
  return null;
10689
10697
  }
10690
10698
  }
10691
- write(sessionId, data, ttl) {
10699
+ write(sessionId, data, ttl = 0) {
10692
10700
  const json = JSON.stringify(data);
10693
10701
  if (ttl > 0) {
10694
10702
  this.execSync(["SETEX", this.key(sessionId), String(ttl), json]);
@@ -10703,6 +10711,29 @@ var init_valkeyHandler = __esm({
10703
10711
  }
10704
10712
  });
10705
10713
 
10714
+ // ../core/src/sessionHandlers/valkeyHandler.ts
10715
+ var ValkeySessionHandler;
10716
+ var init_valkeyHandler = __esm({
10717
+ "../core/src/sessionHandlers/valkeyHandler.ts"() {
10718
+ "use strict";
10719
+ init_respSessionHandler();
10720
+ ValkeySessionHandler = class extends RespSessionHandler {
10721
+ constructor(config) {
10722
+ super(
10723
+ {
10724
+ host: config?.host ?? process.env.TINA4_SESSION_VALKEY_HOST ?? "127.0.0.1",
10725
+ port: config?.port ?? (process.env.TINA4_SESSION_VALKEY_PORT ? parseInt(process.env.TINA4_SESSION_VALKEY_PORT, 10) : 6379),
10726
+ password: config?.password ?? process.env.TINA4_SESSION_VALKEY_PASSWORD ?? "",
10727
+ prefix: config?.prefix ?? process.env.TINA4_SESSION_VALKEY_PREFIX ?? "tina4:session:",
10728
+ db: config?.db ?? (process.env.TINA4_SESSION_VALKEY_DB ? parseInt(process.env.TINA4_SESSION_VALKEY_DB, 10) : 0)
10729
+ },
10730
+ "Valkey"
10731
+ );
10732
+ }
10733
+ };
10734
+ }
10735
+ });
10736
+
10706
10737
  // ../core/src/sessionHandlers/memcachedHandler.ts
10707
10738
  import { createHash as createHash4 } from "node:crypto";
10708
10739
  var MAX_KEY_BYTES, MAX_RELATIVE_EXPTIME, MemcachedSessionHandler;
@@ -11768,7 +11799,7 @@ var init_session = __esm({
11768
11799
  "use strict";
11769
11800
  init_logger();
11770
11801
  init_dotenv();
11771
- init_respClient();
11802
+ init_respSessionHandler();
11772
11803
  init_valkeyHandler();
11773
11804
  init_memcachedHandler();
11774
11805
  init_mongoHandler();
@@ -11894,57 +11925,19 @@ var init_session = __esm({
11894
11925
  }
11895
11926
  }
11896
11927
  };
11897
- RedisSessionHandler = class {
11898
- host;
11899
- port;
11900
- password;
11901
- prefix;
11902
- db;
11928
+ RedisSessionHandler = class extends RespSessionHandler {
11903
11929
  constructor(config) {
11904
- this.host = config?.redisHost ?? process.env.TINA4_SESSION_REDIS_HOST ?? "127.0.0.1";
11905
- this.port = config?.redisPort ?? (process.env.TINA4_SESSION_REDIS_PORT ? parseInt(process.env.TINA4_SESSION_REDIS_PORT, 10) : 6379);
11906
- this.password = config?.redisPassword ?? process.env.TINA4_SESSION_REDIS_PASSWORD ?? "";
11907
- this.prefix = config?.redisPrefix ?? process.env.TINA4_SESSION_REDIS_PREFIX ?? "tina4:session:";
11908
- this.db = config?.redisDb ?? (process.env.TINA4_SESSION_REDIS_DB ? parseInt(process.env.TINA4_SESSION_REDIS_DB, 10) : 0);
11909
- }
11910
- /**
11911
- * Execute a Redis command synchronously against the live server.
11912
- *
11913
- * Delegates to the shared {@link respCommandSync} transport: a genuine key miss
11914
- * yields `""`, and a transport/connection FAILURE (server unreachable, rejected
11915
- * AUTH, timeout) THROWS so the Session boundary can distinguish "not found"
11916
- * (silent) from "backend failed" (log-loud + degrade). Backend-failure parity.
11917
- */
11918
- execSync(args) {
11919
- return respCommandSync(
11920
- { host: this.host, port: this.port, password: this.password, db: this.db },
11921
- args,
11930
+ super(
11931
+ {
11932
+ host: config?.redisHost ?? process.env.TINA4_SESSION_REDIS_HOST ?? "127.0.0.1",
11933
+ port: config?.redisPort ?? (process.env.TINA4_SESSION_REDIS_PORT ? parseInt(process.env.TINA4_SESSION_REDIS_PORT, 10) : 6379),
11934
+ password: config?.redisPassword ?? process.env.TINA4_SESSION_REDIS_PASSWORD ?? "",
11935
+ prefix: config?.redisPrefix ?? process.env.TINA4_SESSION_REDIS_PREFIX ?? "tina4:session:",
11936
+ db: config?.redisDb ?? (process.env.TINA4_SESSION_REDIS_DB ? parseInt(process.env.TINA4_SESSION_REDIS_DB, 10) : 0)
11937
+ },
11922
11938
  "Redis"
11923
11939
  );
11924
11940
  }
11925
- key(sessionId) {
11926
- return `${this.prefix}${sessionId}`;
11927
- }
11928
- read(sessionId) {
11929
- const raw = this.execSync(["GET", this.key(sessionId)]);
11930
- if (!raw) return null;
11931
- try {
11932
- return JSON.parse(raw);
11933
- } catch {
11934
- return null;
11935
- }
11936
- }
11937
- write(sessionId, data, ttl = 0) {
11938
- const json = JSON.stringify(data);
11939
- if (ttl > 0) {
11940
- this.execSync(["SETEX", this.key(sessionId), String(ttl), json]);
11941
- } else {
11942
- this.execSync(["SET", this.key(sessionId), json]);
11943
- }
11944
- }
11945
- destroy(sessionId) {
11946
- this.execSync(["DEL", this.key(sessionId)]);
11947
- }
11948
11941
  };
11949
11942
  FLASH_PREFIX = "_flash_";
11950
11943
  Session = class {
@@ -12354,14 +12347,6 @@ function headStripIntercept(rawReq, rawRes) {
12354
12347
  function isCompressibleContentType(contentType) {
12355
12348
  return COMPRESSIBLE_PREFIXES.some((prefix) => contentType.includes(prefix));
12356
12349
  }
12357
- function etagMatchesInm(ifNoneMatch, etag) {
12358
- const strip = (tag) => tag.trim().replace(/^W\//, "");
12359
- const target = strip(etag);
12360
- return ifNoneMatch.split(",").some((candidate) => {
12361
- const trimmed = candidate.trim();
12362
- return trimmed === "*" || strip(trimmed) === target;
12363
- });
12364
- }
12365
12350
  function maybeCompressResponse(body, rawReq, rawRes) {
12366
12351
  const acceptEncoding = String(rawReq.headers["accept-encoding"] ?? "");
12367
12352
  const contentTypeHeader = rawRes.getHeader("content-type");
@@ -12377,7 +12362,7 @@ function maybeCompressResponse(body, rawReq, rawRes) {
12377
12362
  }
12378
12363
  function responseIsNotModified(rawReq, rawRes, etag) {
12379
12364
  const ifNoneMatch = String(rawReq.headers["if-none-match"] ?? "");
12380
- if (ifNoneMatch) return etagMatchesInm(ifNoneMatch, etag);
12365
+ if (ifNoneMatch) return etagMatches(ifNoneMatch, etag);
12381
12366
  const lastModifiedHeader = rawRes.getHeader("last-modified");
12382
12367
  if (typeof lastModifiedHeader !== "string") return false;
12383
12368
  const ifModifiedSince = String(rawReq.headers["if-modified-since"] ?? "");
@@ -12505,6 +12490,7 @@ var init_dispatchPipeline = __esm({
12505
12490
  "../core/src/dispatchPipeline.ts"() {
12506
12491
  "use strict";
12507
12492
  init_logger();
12493
+ init_etag();
12508
12494
  COMPRESSIBLE_PREFIXES = [
12509
12495
  "text/",
12510
12496
  "application/json",
@@ -12600,18 +12586,11 @@ function isNotModified(req2, etag, stat) {
12600
12586
  }
12601
12587
  return false;
12602
12588
  }
12603
- function etagMatches(ifNoneMatch, etag) {
12604
- const strip = (tag) => tag.trim().replace(/^W\//, "");
12605
- const target = strip(etag);
12606
- return ifNoneMatch.split(",").some((candidate) => {
12607
- const trimmed = candidate.trim();
12608
- return trimmed === "*" || strip(trimmed) === target;
12609
- });
12610
- }
12611
12589
  var COMPRESSIBLE_PREFIXES2, MIME_TYPES;
12612
12590
  var init_static = __esm({
12613
12591
  "../core/src/static.ts"() {
12614
12592
  "use strict";
12593
+ init_etag();
12615
12594
  COMPRESSIBLE_PREFIXES2 = [
12616
12595
  "text/",
12617
12596
  "application/json",
@@ -13188,6 +13167,25 @@ Generated by DevMailbox.seed() for development purposes.`,
13188
13167
  }
13189
13168
  });
13190
13169
 
13170
+ // ../core/src/upstreamResponse.ts
13171
+ async function relayUpstreamResponse(res, upstream) {
13172
+ const raw = await upstream.text();
13173
+ const status2 = upstream.status || 200;
13174
+ try {
13175
+ res.json(JSON.parse(raw), status2);
13176
+ } catch {
13177
+ res.raw.writeHead(status2, {
13178
+ "Content-Type": upstream.headers.get("content-type") ?? "text/plain; charset=utf-8"
13179
+ });
13180
+ res.raw.end(raw);
13181
+ }
13182
+ }
13183
+ var init_upstreamResponse = __esm({
13184
+ "../core/src/upstreamResponse.ts"() {
13185
+ "use strict";
13186
+ }
13187
+ });
13188
+
13191
13189
  // ../core/src/metrics.ts
13192
13190
  import * as fs3 from "node:fs";
13193
13191
  import * as path2 from "node:path";
@@ -13403,6 +13401,7 @@ var init_feedback = __esm({
13403
13401
  "use strict";
13404
13402
  init_auth();
13405
13403
  init_devAdmin();
13404
+ init_upstreamResponse();
13406
13405
  RATE_LIMIT_WINDOW_SEC = 3600;
13407
13406
  RATE_LIMIT_MAX = 5;
13408
13407
  _rateLimitHits = /* @__PURE__ */ new Map();
@@ -13449,16 +13448,7 @@ var init_feedback = __esm({
13449
13448
  return;
13450
13449
  }
13451
13450
  clearTimeout(timer);
13452
- const raw = await upstream.text();
13453
- const status2 = upstream.status || 200;
13454
- try {
13455
- res.json(JSON.parse(raw), status2);
13456
- } catch {
13457
- res.raw.writeHead(status2, {
13458
- "Content-Type": upstream.headers.get("content-type") ?? "text/plain; charset=utf-8"
13459
- });
13460
- res.raw.end(raw);
13461
- }
13451
+ await relayUpstreamResponse(res, upstream);
13462
13452
  };
13463
13453
  __feedbackDirname = dirname5(fileURLToPath2(import.meta.url));
13464
13454
  WIDGET_BUNDLE_PATH = resolve5(__feedbackDirname, "__feedback", "widget.js");
@@ -13508,6 +13498,38 @@ var init_version = __esm({
13508
13498
  }
13509
13499
  });
13510
13500
 
13501
+ // ../cli/src/util.ts
13502
+ function parseFlags(args, booleanFlags) {
13503
+ const flags = {};
13504
+ const positional = [];
13505
+ let i = 0;
13506
+ while (i < args.length) {
13507
+ const arg = args[i];
13508
+ if (arg.startsWith("--")) {
13509
+ const key = arg.slice(2);
13510
+ if (booleanFlags?.has(key)) {
13511
+ flags[key] = true;
13512
+ i += 1;
13513
+ } else if (i + 1 < args.length && !args[i + 1].startsWith("--")) {
13514
+ flags[key] = args[i + 1];
13515
+ i += 2;
13516
+ } else {
13517
+ flags[key] = true;
13518
+ i += 1;
13519
+ }
13520
+ } else {
13521
+ positional.push(arg);
13522
+ i += 1;
13523
+ }
13524
+ }
13525
+ return { flags, positional };
13526
+ }
13527
+ var init_util = __esm({
13528
+ "../cli/src/util.ts"() {
13529
+ "use strict";
13530
+ }
13531
+ });
13532
+
13511
13533
  // ../cli/src/commands/generate.ts
13512
13534
  var generate_exports = {};
13513
13535
  __export(generate_exports, {
@@ -13772,28 +13794,7 @@ function parseCliArgs(args) {
13772
13794
  "json",
13773
13795
  "dry-run"
13774
13796
  ]);
13775
- const flags = {};
13776
- const positional = [];
13777
- let i = 0;
13778
- while (i < args.length) {
13779
- if (args[i].startsWith("--")) {
13780
- const key = args[i].slice(2);
13781
- if (booleanFlags.has(key)) {
13782
- flags[key] = true;
13783
- i += 1;
13784
- } else if (i + 1 < args.length && !args[i + 1].startsWith("--")) {
13785
- flags[key] = args[i + 1];
13786
- i += 2;
13787
- } else {
13788
- flags[key] = true;
13789
- i += 1;
13790
- }
13791
- } else {
13792
- positional.push(args[i]);
13793
- i += 1;
13794
- }
13795
- }
13796
- return { flags, positional };
13797
+ return parseFlags(args, booleanFlags);
13797
13798
  }
13798
13799
  function parseEvery(every) {
13799
13800
  if (!every || every === true) return 60;
@@ -15354,6 +15355,7 @@ var FIELD_TYPE_MAP, SQL_RESERVED_TABLE_NAMES, RESOLUTION_ENVELOPE_VERSION, __res
15354
15355
  var init_generate = __esm({
15355
15356
  "../cli/src/commands/generate.ts"() {
15356
15357
  "use strict";
15358
+ init_util();
15357
15359
  FIELD_TYPE_MAP = {
15358
15360
  string: { orm: '"string"', sql: "VARCHAR(255)", defaultVal: "''" },
15359
15361
  str: { orm: '"string"', sql: "VARCHAR(255)", defaultVal: "''" },
@@ -18972,6 +18974,7 @@ __export(websocket_exports, {
18972
18974
  CLOSE_NORMAL: () => CLOSE_NORMAL,
18973
18975
  CLOSE_POLICY_VIOLATION: () => CLOSE_POLICY_VIOLATION,
18974
18976
  CLOSE_PROTOCOL_ERROR: () => CLOSE_PROTOCOL_ERROR,
18977
+ MessageAssembler: () => MessageAssembler,
18975
18978
  OP_BINARY: () => OP_BINARY,
18976
18979
  OP_CLOSE: () => OP_CLOSE,
18977
18980
  OP_CONTINUATION: () => OP_CONTINUATION,
@@ -19229,21 +19232,24 @@ function serveWebSocketRoute(req2, socket, head) {
19229
19232
  state.closed = true;
19230
19233
  void Promise.resolve().then(() => conn._onClose ? conn._onClose() : handler(conn, "close", "")).catch((e) => Log.error(`WebSocket close handler error: ${e.message}`)).finally(() => wsRouteManager.remove(conn.id));
19231
19234
  };
19235
+ const assembler = new MessageAssembler();
19232
19236
  socket.on("data", (chunk) => {
19233
19237
  buffer = Buffer.concat([buffer, chunk]);
19234
19238
  while (buffer.length > 0) {
19235
19239
  const frame = parseFrame(buffer);
19236
19240
  if (!frame) break;
19237
19241
  buffer = buffer.subarray(frame.bytesConsumed);
19238
- switch (frame.opcode) {
19242
+ const whole = assembler.push(frame);
19243
+ if (!whole) continue;
19244
+ switch (whole.opcode) {
19239
19245
  case OP_TEXT: {
19240
- const text = frame.payload.toString("utf-8");
19246
+ const text = whole.payload.toString("utf-8");
19241
19247
  void Promise.resolve().then(() => conn._onMessage ? conn._onMessage(text) : handler(conn, "message", text)).catch((e) => Log.error(`WebSocket message handler error: ${e.message}`));
19242
19248
  break;
19243
19249
  }
19244
19250
  case OP_PING:
19245
19251
  try {
19246
- socket.write(buildFrame(OP_PONG, frame.payload));
19252
+ socket.write(buildFrame(OP_PONG, whole.payload));
19247
19253
  } catch {
19248
19254
  }
19249
19255
  break;
@@ -19262,7 +19268,7 @@ function serveWebSocketRoute(req2, socket, head) {
19262
19268
  socket.on("error", fireClose);
19263
19269
  return true;
19264
19270
  }
19265
- var MAGIC_STRING, OP_CONTINUATION, OP_TEXT, OP_BINARY, OP_CLOSE, OP_PING, OP_PONG, CLOSE_NORMAL, CLOSE_GOING_AWAY, CLOSE_PROTOCOL_ERROR, CLOSE_POLICY_VIOLATION, WebSocketServer, WsRouteManager, wsRouteManager, DevReloadWsManager, devReloadWs;
19271
+ var MAGIC_STRING, OP_CONTINUATION, OP_TEXT, OP_BINARY, OP_CLOSE, OP_PING, OP_PONG, CLOSE_NORMAL, CLOSE_GOING_AWAY, CLOSE_PROTOCOL_ERROR, CLOSE_POLICY_VIOLATION, MessageAssembler, WebSocketServer, WsRouteManager, wsRouteManager, DevReloadWsManager, devReloadWs;
19266
19272
  var init_websocket = __esm({
19267
19273
  "../core/src/websocket.ts"() {
19268
19274
  "use strict";
@@ -19281,6 +19287,30 @@ var init_websocket = __esm({
19281
19287
  CLOSE_GOING_AWAY = 1001;
19282
19288
  CLOSE_PROTOCOL_ERROR = 1002;
19283
19289
  CLOSE_POLICY_VIOLATION = 1008;
19290
+ MessageAssembler = class {
19291
+ parts = [];
19292
+ opcode = 0;
19293
+ push(frame) {
19294
+ if (frame.opcode >= 8) return { opcode: frame.opcode, payload: frame.payload };
19295
+ if (frame.opcode === OP_CONTINUATION) {
19296
+ if (!this.opcode) return null;
19297
+ this.parts.push(frame.payload);
19298
+ if (!frame.fin) return null;
19299
+ const whole = { opcode: this.opcode, payload: Buffer.concat(this.parts) };
19300
+ this.parts = [];
19301
+ this.opcode = 0;
19302
+ return whole;
19303
+ }
19304
+ if (frame.fin) {
19305
+ this.parts = [];
19306
+ this.opcode = 0;
19307
+ return { opcode: frame.opcode, payload: frame.payload };
19308
+ }
19309
+ this.opcode = frame.opcode;
19310
+ this.parts = [frame.payload];
19311
+ return null;
19312
+ }
19313
+ };
19284
19314
  WebSocketServer = class {
19285
19315
  port;
19286
19316
  server = null;
@@ -19723,6 +19753,15 @@ var init_websocket = __esm({
19723
19753
  this.emit("error", err, client);
19724
19754
  });
19725
19755
  }
19756
+ assemblers = /* @__PURE__ */ new WeakMap();
19757
+ assemblerFor(client) {
19758
+ let a = this.assemblers.get(client);
19759
+ if (!a) {
19760
+ a = new MessageAssembler();
19761
+ this.assemblers.set(client, a);
19762
+ }
19763
+ return a;
19764
+ }
19726
19765
  processBuffer(client, buffer, setBuffer) {
19727
19766
  let remaining = buffer;
19728
19767
  while (remaining.length > 0) {
@@ -19730,15 +19769,17 @@ var init_websocket = __esm({
19730
19769
  if (!frame) break;
19731
19770
  remaining = remaining.subarray(frame.bytesConsumed);
19732
19771
  client.lastActivity = Date.now();
19733
- switch (frame.opcode) {
19772
+ const whole = this.assemblerFor(client).push(frame);
19773
+ if (!whole) continue;
19774
+ switch (whole.opcode) {
19734
19775
  case OP_TEXT:
19735
- this.emit("message", client, frame.payload.toString("utf-8"));
19776
+ this.emit("message", client, whole.payload.toString("utf-8"));
19736
19777
  break;
19737
19778
  case OP_BINARY:
19738
- this.emit("message", client, frame.payload);
19779
+ this.emit("message", client, whole.payload);
19739
19780
  break;
19740
19781
  case OP_PING: {
19741
- const pongFrame = buildFrame(OP_PONG, frame.payload);
19782
+ const pongFrame = buildFrame(OP_PONG, whole.payload);
19742
19783
  try {
19743
19784
  client.socket.write(pongFrame);
19744
19785
  } catch {
@@ -24116,16 +24157,7 @@ async function proxyToSupervisor(req2, res, downstreamPath) {
24116
24157
  return;
24117
24158
  }
24118
24159
  clearTimeout(timer);
24119
- const raw = await upstream.text();
24120
- const status2 = upstream.status || 200;
24121
- try {
24122
- res.json(JSON.parse(raw), status2);
24123
- } catch {
24124
- res.raw.writeHead(status2, {
24125
- "Content-Type": upstream.headers.get("content-type") ?? "text/plain; charset=utf-8"
24126
- });
24127
- res.raw.end(raw);
24128
- }
24160
+ await relayUpstreamResponse(res, upstream);
24129
24161
  }
24130
24162
  function resolveDevEnvVar(key) {
24131
24163
  const live = process.env[key];
@@ -24567,6 +24599,7 @@ var init_devAdmin = __esm({
24567
24599
  "../core/src/devAdmin.ts"() {
24568
24600
  "use strict";
24569
24601
  init_devMailbox();
24602
+ init_upstreamResponse();
24570
24603
  init_dotenv();
24571
24604
  init_metrics();
24572
24605
  init_feedback();
@@ -47718,6 +47751,36 @@ var init_shapes = __esm({
47718
47751
  }
47719
47752
  });
47720
47753
 
47754
+ // src/graph/adapters/rowMapping.ts
47755
+ function errorMessage(exc) {
47756
+ if (exc instanceof Error) return exc.message;
47757
+ return String(exc);
47758
+ }
47759
+ function nodeFromRow(row) {
47760
+ if (row === null || row === void 0) return null;
47761
+ return new GraphNode(
47762
+ String(row.id),
47763
+ row.labels ?? [],
47764
+ row.props ?? {}
47765
+ );
47766
+ }
47767
+ function edgeFromRow(row) {
47768
+ if (row === null || row === void 0) return null;
47769
+ return new GraphEdge(
47770
+ String(row.id),
47771
+ String(row.type),
47772
+ String(row.f),
47773
+ String(row.t),
47774
+ row.props ?? {}
47775
+ );
47776
+ }
47777
+ var init_rowMapping = __esm({
47778
+ "src/graph/adapters/rowMapping.ts"() {
47779
+ "use strict";
47780
+ init_shapes();
47781
+ }
47782
+ });
47783
+
47721
47784
  // src/graph/connectTimeout.ts
47722
47785
  function resolveGraphConnectTimeout() {
47723
47786
  const raw = (process.env[GRAPH_CONNECT_TIMEOUT_VARIABLE] ?? "").trim();
@@ -47757,15 +47820,12 @@ function propClause(properties) {
47757
47820
  for (const key of keys) params[`p_${key}`] = props[key];
47758
47821
  return { clause: `{${pairs}}`, params };
47759
47822
  }
47760
- function errorMessage(exc) {
47761
- if (exc instanceof Error) return exc.message;
47762
- return String(exc);
47763
- }
47764
47823
  var DRIVER_PACKAGE2, driver, UltipaClient, UltipaConnectError, UNBOUNDED_CONNECT_SECONDS, UltipaGraphAdapter;
47765
47824
  var init_ultipa = __esm({
47766
47825
  async "src/graph/adapters/ultipa.ts"() {
47767
47826
  "use strict";
47768
47827
  init_shapes();
47828
+ init_rowMapping();
47769
47829
  init_errors();
47770
47830
  init_connectTimeout2();
47771
47831
  DRIVER_PACKAGE2 = "tina4-ultipa";
@@ -47823,12 +47883,7 @@ var init_ultipa = __esm({
47823
47883
  }
47824
47884
  // -- portable node/edge/traverse core (GQL) ----------------------------
47825
47885
  nodeFromRow(row) {
47826
- if (row === null || row === void 0) return null;
47827
- return new GraphNode(
47828
- String(row.id),
47829
- row.labels ?? [],
47830
- row.props ?? {}
47831
- );
47886
+ return nodeFromRow(row);
47832
47887
  }
47833
47888
  async addNode(label, properties = null) {
47834
47889
  const { clause, params } = propClause(properties);
@@ -47842,15 +47897,7 @@ var init_ultipa = __esm({
47842
47897
  params.to_id = toId;
47843
47898
  const gql = `MATCH (a), (b) WHERE id(a) = $from_id AND id(b) = $to_id INSERT (a)-[e:\`${type2}\` ${clause}]->(b) RETURN id(e) AS id, type(e) AS type, id(a) AS f, id(b) AS t, properties(e) AS props`;
47844
47899
  const rows = (await this.run(gql, params, false)).dicts();
47845
- if (rows.length === 0) return null;
47846
- const row = rows[0];
47847
- return new GraphEdge(
47848
- String(row.id),
47849
- String(row.type),
47850
- String(row.f),
47851
- String(row.t),
47852
- row.props ?? {}
47853
- );
47900
+ return edgeFromRow(rows[0]);
47854
47901
  }
47855
47902
  async getNode(nodeId) {
47856
47903
  const gql = `MATCH (n) WHERE id(n) = $id RETURN id(n) AS id, labels(n) AS labels, properties(n) AS props`;
@@ -47915,10 +47962,6 @@ var bolt_exports = {};
47915
47962
  __export(bolt_exports, {
47916
47963
  BoltGraphAdapter: () => BoltGraphAdapter
47917
47964
  });
47918
- function errorMessage2(exc) {
47919
- if (exc instanceof Error) return exc.message;
47920
- return String(exc);
47921
- }
47922
47965
  function boltId(id) {
47923
47966
  const value = Number(id);
47924
47967
  return Number.isNaN(value) ? -1 : value;
@@ -47928,6 +47971,7 @@ var init_bolt = __esm({
47928
47971
  async "src/graph/adapters/bolt.ts"() {
47929
47972
  "use strict";
47930
47973
  init_shapes();
47974
+ init_rowMapping();
47931
47975
  init_errors();
47932
47976
  init_connectTimeout2();
47933
47977
  DRIVER_PACKAGE3 = "neo4j-driver";
@@ -47963,7 +48007,7 @@ var init_bolt = __esm({
47963
48007
  const result = await session.run(cypher, params ?? {});
47964
48008
  return result.records.map((record) => record.toObject());
47965
48009
  } catch (exc) {
47966
- this.lastError = errorMessage2(exc);
48010
+ this.lastError = errorMessage(exc);
47967
48011
  const code = exc?.code ?? "";
47968
48012
  const message = this.lastError.toLowerCase();
47969
48013
  if (code === "ServiceUnavailable" || code === neo4j.error?.SERVICE_UNAVAILABLE || message.includes("timed out") || message.includes("timeout")) {
@@ -47987,12 +48031,7 @@ var init_bolt = __esm({
47987
48031
  }
47988
48032
  // -- portable node/edge/traverse core (Cypher) -------------------------
47989
48033
  nodeFromRow(row) {
47990
- if (row === null || row === void 0) return null;
47991
- return new GraphNode(
47992
- String(row.id),
47993
- row.labels ?? [],
47994
- row.props ?? {}
47995
- );
48034
+ return nodeFromRow(row);
47996
48035
  }
47997
48036
  async addNode(label, properties = null) {
47998
48037
  const cypher = `CREATE (n:\`${label}\` $props) RETURN id(n) AS id, labels(n) AS labels, properties(n) AS props`;
@@ -48006,15 +48045,7 @@ var init_bolt = __esm({
48006
48045
  to_id: boltId(toId),
48007
48046
  props: properties ?? {}
48008
48047
  });
48009
- if (rows.length === 0) return null;
48010
- const row = rows[0];
48011
- return new GraphEdge(
48012
- String(row.id),
48013
- String(row.type),
48014
- String(row.f),
48015
- String(row.t),
48016
- row.props ?? {}
48017
- );
48048
+ return edgeFromRow(rows[0]);
48018
48049
  }
48019
48050
  async getNode(nodeId) {
48020
48051
  const cypher = `MATCH (n) WHERE id(n) = $id RETURN id(n) AS id, labels(n) AS labels, properties(n) AS props`;
@@ -48080,7 +48111,7 @@ function cleanProps(doc) {
48080
48111
  }
48081
48112
  return props;
48082
48113
  }
48083
- function errorMessage3(exc) {
48114
+ function errorMessage2(exc) {
48084
48115
  if (exc instanceof Error) return exc.message;
48085
48116
  return String(exc);
48086
48117
  }
@@ -48119,14 +48150,14 @@ var init_arango = __esm({
48119
48150
  this.db = new ArangoDatabase(config);
48120
48151
  }
48121
48152
  connectOrError(exc) {
48122
- const text = errorMessage3(exc).toLowerCase();
48153
+ const text = errorMessage2(exc).toLowerCase();
48123
48154
  if (text.includes("timed out") || text.includes("timeout") || text.includes("connection") || text.includes("econnrefused") || text.includes("etimedout") || text.includes("max retries")) {
48124
48155
  return new GraphConnectTimeout(
48125
48156
  `Graph connect to ${this.url.host}:${this.url.port} timed out (${GRAPH_CONNECT_TIMEOUT_VARIABLE}). Raise ${GRAPH_CONNECT_TIMEOUT_VARIABLE} if the server is simply slow, or set it to 0 to wait indefinitely.`,
48126
48157
  exc
48127
48158
  );
48128
48159
  }
48129
- return new GraphError(errorMessage3(exc), exc);
48160
+ return new GraphError(errorMessage2(exc), exc);
48130
48161
  }
48131
48162
  async ensureCollections() {
48132
48163
  if (this.ensured) return;
@@ -48137,7 +48168,7 @@ var init_arango = __esm({
48137
48168
  if (!await edges.exists()) await this.db.createEdgeCollection(EDGE_COLLECTION);
48138
48169
  this.ensured = true;
48139
48170
  } catch (exc) {
48140
- this.lastError = errorMessage3(exc);
48171
+ this.lastError = errorMessage2(exc);
48141
48172
  throw this.connectOrError(exc);
48142
48173
  }
48143
48174
  }
@@ -48147,7 +48178,7 @@ var init_arango = __esm({
48147
48178
  const cursor = await this.db.query({ query, bindVars: bind2 ?? {} });
48148
48179
  return await cursor.all();
48149
48180
  } catch (exc) {
48150
- this.lastError = errorMessage3(exc);
48181
+ this.lastError = errorMessage2(exc);
48151
48182
  throw this.connectOrError(exc);
48152
48183
  }
48153
48184
  }