@vex-chat/spire 1.0.2 → 1.0.4

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 (103) hide show
  1. package/CLA.md +38 -0
  2. package/LICENSE-COMMERCIAL +10 -0
  3. package/LICENSING.md +15 -0
  4. package/README.md +3 -2
  5. package/dist/ClientManager.d.ts +5 -0
  6. package/dist/ClientManager.js +5 -0
  7. package/dist/ClientManager.js.map +1 -1
  8. package/dist/Database.d.ts +5 -0
  9. package/dist/Database.js +5 -0
  10. package/dist/Database.js.map +1 -1
  11. package/dist/Spire.d.ts +5 -0
  12. package/dist/Spire.js +22 -12
  13. package/dist/Spire.js.map +1 -1
  14. package/dist/db/schema.d.ts +5 -0
  15. package/dist/db/schema.js +5 -0
  16. package/dist/db/schema.js.map +1 -1
  17. package/dist/index.d.ts +5 -0
  18. package/dist/index.js +5 -0
  19. package/dist/index.js.map +1 -1
  20. package/dist/middleware/validate.d.ts +5 -0
  21. package/dist/middleware/validate.js +5 -0
  22. package/dist/middleware/validate.js.map +1 -1
  23. package/dist/migrations/2026-04-06_initial-schema.d.ts +5 -0
  24. package/dist/migrations/2026-04-06_initial-schema.js +5 -0
  25. package/dist/migrations/2026-04-06_initial-schema.js.map +1 -1
  26. package/dist/migrations/2026-04-14_argon2id-password-hashing.d.ts +5 -0
  27. package/dist/migrations/2026-04-14_argon2id-password-hashing.js +5 -0
  28. package/dist/migrations/2026-04-14_argon2id-password-hashing.js.map +1 -1
  29. package/dist/run.d.ts +5 -0
  30. package/dist/run.js +5 -0
  31. package/dist/run.js.map +1 -1
  32. package/dist/server/avatar.d.ts +5 -0
  33. package/dist/server/avatar.js +5 -0
  34. package/dist/server/avatar.js.map +1 -1
  35. package/dist/server/errors.d.ts +5 -0
  36. package/dist/server/errors.js +5 -0
  37. package/dist/server/errors.js.map +1 -1
  38. package/dist/server/file.d.ts +5 -0
  39. package/dist/server/file.js +5 -0
  40. package/dist/server/file.js.map +1 -1
  41. package/dist/server/index.d.ts +5 -0
  42. package/dist/server/index.js +21 -9
  43. package/dist/server/index.js.map +1 -1
  44. package/dist/server/invite.d.ts +5 -0
  45. package/dist/server/invite.js +5 -0
  46. package/dist/server/invite.js.map +1 -1
  47. package/dist/server/openapi.d.ts +5 -0
  48. package/dist/server/openapi.js +5 -0
  49. package/dist/server/openapi.js.map +1 -1
  50. package/dist/server/permissions.d.ts +5 -0
  51. package/dist/server/permissions.js +5 -0
  52. package/dist/server/permissions.js.map +1 -1
  53. package/dist/server/rateLimit.d.ts +5 -0
  54. package/dist/server/rateLimit.js +5 -0
  55. package/dist/server/rateLimit.js.map +1 -1
  56. package/dist/server/user.d.ts +5 -0
  57. package/dist/server/user.js +5 -0
  58. package/dist/server/user.js.map +1 -1
  59. package/dist/server/utils.d.ts +5 -0
  60. package/dist/server/utils.js +5 -0
  61. package/dist/server/utils.js.map +1 -1
  62. package/dist/types/express.d.ts +5 -0
  63. package/dist/types/express.js +5 -0
  64. package/dist/types/express.js.map +1 -1
  65. package/dist/utils/createUint8UUID.d.ts +5 -0
  66. package/dist/utils/createUint8UUID.js +5 -0
  67. package/dist/utils/createUint8UUID.js.map +1 -1
  68. package/dist/utils/jwtSecret.d.ts +5 -0
  69. package/dist/utils/jwtSecret.js +5 -0
  70. package/dist/utils/jwtSecret.js.map +1 -1
  71. package/dist/utils/loadEnv.d.ts +5 -0
  72. package/dist/utils/loadEnv.js +5 -0
  73. package/dist/utils/loadEnv.js.map +1 -1
  74. package/dist/utils/msgpack.d.ts +5 -0
  75. package/dist/utils/msgpack.js +5 -0
  76. package/dist/utils/msgpack.js.map +1 -1
  77. package/package.json +10 -5
  78. package/src/ClientManager.ts +6 -0
  79. package/src/Database.ts +6 -0
  80. package/src/Spire.ts +29 -14
  81. package/src/__tests__/Database.spec.ts +6 -0
  82. package/src/ambient-modules.d.ts +6 -0
  83. package/src/db/schema.ts +6 -0
  84. package/src/index.ts +6 -0
  85. package/src/middleware/validate.ts +6 -0
  86. package/src/migrations/2026-04-06_initial-schema.ts +6 -0
  87. package/src/migrations/2026-04-14_argon2id-password-hashing.ts +6 -0
  88. package/src/run.ts +6 -0
  89. package/src/server/avatar.ts +6 -0
  90. package/src/server/errors.ts +6 -0
  91. package/src/server/file.ts +6 -0
  92. package/src/server/index.ts +23 -9
  93. package/src/server/invite.ts +6 -0
  94. package/src/server/openapi.ts +6 -0
  95. package/src/server/permissions.ts +6 -0
  96. package/src/server/rateLimit.ts +6 -0
  97. package/src/server/user.ts +6 -0
  98. package/src/server/utils.ts +6 -0
  99. package/src/types/express.ts +6 -0
  100. package/src/utils/createUint8UUID.ts +6 -0
  101. package/src/utils/jwtSecret.ts +6 -0
  102. package/src/utils/loadEnv.ts +6 -0
  103. package/src/utils/msgpack.ts +6 -0
@@ -1,3 +1,8 @@
1
+ /**
2
+ * Copyright (c) 2020-2026 Vex Heavy Industries LLC
3
+ * Licensed under AGPL-3.0. See LICENSE for details.
4
+ * Commercial licenses available at vex.wtf
5
+ */
1
6
  import { parse as uuidParse } from "uuid";
2
7
  export function createUint8UUID() {
3
8
  return uuidToUint8(crypto.randomUUID());
@@ -1 +1 @@
1
- {"version":3,"file":"createUint8UUID.js","sourceRoot":"","sources":["../../src/utils/createUint8UUID.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,IAAI,SAAS,EAAE,MAAM,MAAM,CAAC;AAE1C,MAAM,UAAU,eAAe;IAC3B,OAAO,WAAW,CAAC,MAAM,CAAC,UAAU,EAAE,CAAC,CAAC;AAC5C,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,IAAY;IACpC,OAAO,IAAI,UAAU,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC;AAC3C,CAAC"}
1
+ {"version":3,"file":"createUint8UUID.js","sourceRoot":"","sources":["../../src/utils/createUint8UUID.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,KAAK,IAAI,SAAS,EAAE,MAAM,MAAM,CAAC;AAE1C,MAAM,UAAU,eAAe;IAC3B,OAAO,WAAW,CAAC,MAAM,CAAC,UAAU,EAAE,CAAC,CAAC;AAC5C,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,IAAY;IACpC,OAAO,IAAI,UAAU,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC;AAC3C,CAAC"}
@@ -1,3 +1,8 @@
1
+ /**
2
+ * Copyright (c) 2020-2026 Vex Heavy Industries LLC
3
+ * Licensed under AGPL-3.0. See LICENSE for details.
4
+ * Commercial licenses available at vex.wtf
5
+ */
1
6
  /**
2
7
  * Returns the dedicated JWT HMAC signing secret.
3
8
  *
@@ -1,3 +1,8 @@
1
+ /**
2
+ * Copyright (c) 2020-2026 Vex Heavy Industries LLC
3
+ * Licensed under AGPL-3.0. See LICENSE for details.
4
+ * Commercial licenses available at vex.wtf
5
+ */
1
6
  /**
2
7
  * Returns the dedicated JWT HMAC signing secret.
3
8
  *
@@ -1 +1 @@
1
- {"version":3,"file":"jwtSecret.js","sourceRoot":"","sources":["../../src/utils/jwtSecret.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,MAAM,UAAU,YAAY;IACxB,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;IACzC,IAAI,CAAC,MAAM,EAAE,CAAC;QACV,MAAM,IAAI,KAAK,CACX,mEAAmE,CACtE,CAAC;IACN,CAAC;IACD,OAAO,MAAM,CAAC;AAClB,CAAC"}
1
+ {"version":3,"file":"jwtSecret.js","sourceRoot":"","sources":["../../src/utils/jwtSecret.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;;;;GAKG;AACH,MAAM,UAAU,YAAY;IACxB,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;IACzC,IAAI,CAAC,MAAM,EAAE,CAAC;QACV,MAAM,IAAI,KAAK,CACX,mEAAmE,CACtE,CAAC;IACN,CAAC;IACD,OAAO,MAAM,CAAC;AAClB,CAAC"}
@@ -1 +1,6 @@
1
+ /**
2
+ * Copyright (c) 2020-2026 Vex Heavy Industries LLC
3
+ * Licensed under AGPL-3.0. See LICENSE for details.
4
+ * Commercial licenses available at vex.wtf
5
+ */
1
6
  export declare function loadEnv(): void;
@@ -1,3 +1,8 @@
1
+ /**
2
+ * Copyright (c) 2020-2026 Vex Heavy Industries LLC
3
+ * Licensed under AGPL-3.0. See LICENSE for details.
4
+ * Commercial licenses available at vex.wtf
5
+ */
1
6
  import { config } from "dotenv";
2
7
  /* Populate process.env with vars from .env and verify required vars are present. */
3
8
  export function loadEnv() {
@@ -1 +1 @@
1
- {"version":3,"file":"loadEnv.js","sourceRoot":"","sources":["../../src/utils/loadEnv.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAEhC,oFAAoF;AACpF,MAAM,UAAU,OAAO;IACnB,MAAM,EAAE,CAAC;IACT,MAAM,eAAe,GAAa,CAAC,SAAS,EAAE,YAAY,EAAE,KAAK,CAAC,CAAC;IACnE,KAAK,MAAM,QAAQ,IAAI,eAAe,EAAE,CAAC;QACrC,IAAI,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,KAAK,SAAS,EAAE,CAAC;YACtC,OAAO,CAAC,MAAM,CAAC,KAAK,CAChB,kCAAkC,QAAQ,4CAA4C,CACzF,CAAC;YACF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACpB,CAAC;IACL,CAAC;AACL,CAAC"}
1
+ {"version":3,"file":"loadEnv.js","sourceRoot":"","sources":["../../src/utils/loadEnv.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAEhC,oFAAoF;AACpF,MAAM,UAAU,OAAO;IACnB,MAAM,EAAE,CAAC;IACT,MAAM,eAAe,GAAa,CAAC,SAAS,EAAE,YAAY,EAAE,KAAK,CAAC,CAAC;IACnE,KAAK,MAAM,QAAQ,IAAI,eAAe,EAAE,CAAC;QACrC,IAAI,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,KAAK,SAAS,EAAE,CAAC;YACtC,OAAO,CAAC,MAAM,CAAC,KAAK,CAChB,kCAAkC,QAAQ,4CAA4C,CACzF,CAAC;YACF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACpB,CAAC;IACL,CAAC;AACL,CAAC"}
@@ -1,2 +1,7 @@
1
+ /**
2
+ * Copyright (c) 2020-2026 Vex Heavy Industries LLC
3
+ * Licensed under AGPL-3.0. See LICENSE for details.
4
+ * Commercial licenses available at vex.wtf
5
+ */
1
6
  import { Packr } from "msgpackr";
2
7
  export declare const msgpack: Packr;
@@ -1,3 +1,8 @@
1
+ /**
2
+ * Copyright (c) 2020-2026 Vex Heavy Industries LLC
3
+ * Licensed under AGPL-3.0. See LICENSE for details.
4
+ * Commercial licenses available at vex.wtf
5
+ */
1
6
  import { Packr } from "msgpackr";
2
7
  // Standard msgpack encoder/decoder configured for broad compatibility.
3
8
  export const msgpack = new Packr({ moreTypes: false, useRecords: false });
@@ -1 +1 @@
1
- {"version":3,"file":"msgpack.js","sourceRoot":"","sources":["../../src/utils/msgpack.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,UAAU,CAAC;AAEjC,uEAAuE;AACvE,MAAM,CAAC,MAAM,OAAO,GAAG,IAAI,KAAK,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE,CAAC,CAAC"}
1
+ {"version":3,"file":"msgpack.js","sourceRoot":"","sources":["../../src/utils/msgpack.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,KAAK,EAAE,MAAM,UAAU,CAAC;AAEjC,uEAAuE;AACvE,MAAM,CAAC,MAAM,OAAO,GAAG,IAAI,KAAK,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE,CAAC,CAAC"}
package/package.json CHANGED
@@ -1,12 +1,15 @@
1
1
  {
2
2
  "name": "@vex-chat/spire",
3
- "version": "1.0.2",
3
+ "version": "1.0.4",
4
4
  "description": "Vex server implementation in NodeJS.",
5
5
  "type": "module",
6
6
  "files": [
7
7
  "dist",
8
8
  "src",
9
- "LICENSE"
9
+ "LICENSE",
10
+ "LICENSE-COMMERCIAL",
11
+ "LICENSING.md",
12
+ "CLA.md"
10
13
  ],
11
14
  "author": "Extra <extrahash@protonmail.com>",
12
15
  "license": "AGPL-3.0-or-later",
@@ -26,6 +29,8 @@
26
29
  "build": "tsc && node scripts/clean-dist-tests.mjs",
27
30
  "format": "prettier --write .",
28
31
  "format:check": "prettier --check .",
32
+ "copyright:check": "node scripts/copyright-headers.mjs --check",
33
+ "copyright:apply": "node scripts/copyright-headers.mjs",
29
34
  "lint": "eslint src/ scripts/stress/",
30
35
  "lint:fix": "eslint src/ scripts/stress/ --fix",
31
36
  "prepare": "husky || true",
@@ -37,7 +42,6 @@
37
42
  "stress:llm-triage": "node --experimental-strip-types scripts/stress/stress-llm-triage.ts",
38
43
  "gen-spk": "node scripts/gen-spk.js",
39
44
  "docs": "node ./scripts/generate-docs.js",
40
- "license:check": "node scripts/fix-license-checker.mjs && npx @onebeyond/license-checker scan --allowOnly MIT MIT-0 ISC BSD-2-Clause BSD-3-Clause Apache-2.0 0BSD MPL-2.0 CC0-1.0 CC-BY-3.0 CC-BY-4.0 Unlicense BlueOak-1.0.0 Python-2.0 Zlib PSF-2.0 Artistic-2.0 AGPL-3.0-or-later WTFPL \"(MIT AND CC-BY-3.0)\" --ignoreRootPackageLicense --disableReport",
41
45
  "service:status-monitor": "node ./services/status-monitor/index.js",
42
46
  "service:status-monitor:clear-history": "node ./services/status-monitor/clear-history.js",
43
47
  "service:deploy-hook": "node ./services/deploy-hook/index.js",
@@ -45,7 +49,7 @@
45
49
  },
46
50
  "devDependencies": {
47
51
  "@changesets/cli": "2.30.0",
48
- "@onebeyond/license-checker": "2.2.0",
52
+ "@socketsecurity/cli": "1.1.84",
49
53
  "@types/better-sqlite3": "7.6.13",
50
54
  "@types/cors": "2.8.19",
51
55
  "@types/express": "5.0.6",
@@ -55,7 +59,7 @@
55
59
  "@types/node": "25.6.0",
56
60
  "@types/uuid": "10.0.0",
57
61
  "@types/ws": "8.18.1",
58
- "@vex-chat/libvex": "5.1.0",
62
+ "@vex-chat/libvex": "5.2.0",
59
63
  "@vitest/eslint-plugin": "1.6.15",
60
64
  "axios": "1.15.0",
61
65
  "eslint": "10.2.0",
@@ -64,6 +68,7 @@
64
68
  "eslint-plugin-perfectionist": "5.8.0",
65
69
  "husky": "9.1.7",
66
70
  "lint-staged": "16.4.0",
71
+ "npm-package-json-lint": "10.2.1",
67
72
  "prettier": "3.8.2",
68
73
  "type-coverage": "2.29.7",
69
74
  "typedoc": "0.28.18",
@@ -1,3 +1,9 @@
1
+ /**
2
+ * Copyright (c) 2020-2026 Vex Heavy Industries LLC
3
+ * Licensed under AGPL-3.0. See LICENSE for details.
4
+ * Commercial licenses available at vex.wtf
5
+ */
6
+
1
7
  import type { Database } from "./Database.ts";
2
8
  import type {
3
9
  BaseMsg,
package/src/Database.ts CHANGED
@@ -1,3 +1,9 @@
1
+ /**
2
+ * Copyright (c) 2020-2026 Vex Heavy Industries LLC
3
+ * Licensed under AGPL-3.0. See LICENSE for details.
4
+ * Commercial licenses available at vex.wtf
5
+ */
6
+
1
7
  import type { ServerDatabase } from "./db/schema.ts";
2
8
  import type { SpireOptions } from "./Spire.ts";
3
9
  import type {
package/src/Spire.ts CHANGED
@@ -1,5 +1,11 @@
1
+ /**
2
+ * Copyright (c) 2020-2026 Vex Heavy Industries LLC
3
+ * Licensed under AGPL-3.0. See LICENSE for details.
4
+ * Commercial licenses available at vex.wtf
5
+ */
6
+
1
7
  import type { ActionToken, BaseMsg, NotifyMsg, User } from "@vex-chat/types";
2
- import type { Server } from "http";
8
+ import type { IncomingMessage, Server } from "http";
3
9
 
4
10
  import { EventEmitter } from "events";
5
11
  import { execSync } from "node:child_process";
@@ -25,6 +31,7 @@ import {
25
31
  } from "@vex-chat/types";
26
32
 
27
33
  import jwt from "jsonwebtoken";
34
+ import morgan from "morgan";
28
35
  import { stringify as uuidStringify } from "uuid";
29
36
  import { WebSocketServer } from "ws";
30
37
  import { z } from "zod/v4";
@@ -42,7 +49,6 @@ export const TOKEN_EXPIRY = 1000 * 60 * 10;
42
49
  export const JWT_EXPIRY = "7d";
43
50
  export const DEVICE_AUTH_JWT_EXPIRY = "1h";
44
51
  const DEVICE_CHALLENGE_EXPIRY = 1000 * 60; // 60 seconds
45
- const STATUS_LATENCY_BUDGET_MS = 250;
46
52
 
47
53
  // 3-19 chars long
48
54
  const usernameRegex = /^(\w{3,19})$/;
@@ -126,6 +132,14 @@ const getCommitSha = (): string => {
126
132
  }
127
133
  };
128
134
 
135
+ /** Hyphenated UUIDs in paths/query — replaced so request logs are less identifying. */
136
+ function redactUuidsForLog(url: string): string {
137
+ return url.replace(
138
+ /[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/gi,
139
+ "[uuid]",
140
+ );
141
+ }
142
+
129
143
  export interface SpireOptions {
130
144
  apiPort?: number;
131
145
  dbType?: "mysql" | "sqlite3" | "sqlite3mem" | "sqlite";
@@ -227,6 +241,14 @@ export class Spire extends EventEmitter {
227
241
  }
228
242
 
229
243
  private init(apiPort: number): void {
244
+ // Request traces (UUIDs redacted in `url` token). Enabled in all envs,
245
+ // including production / Docker — dependency is non-dev.
246
+ morgan.token("url", (req: IncomingMessage) => {
247
+ const r = req as IncomingMessage & { originalUrl?: string };
248
+ return redactUuidsForLog(r.originalUrl ?? r.url ?? "");
249
+ });
250
+ this.api.use(morgan("dev"));
251
+
230
252
  this.api.use((_req, _res, next) => {
231
253
  this.requestsTotal += 1;
232
254
 
@@ -427,12 +449,16 @@ export class Spire extends EventEmitter {
427
449
  res.json({ dbReady: true, ok: true });
428
450
  });
429
451
 
430
- this.api.get("/status", async (_req, res) => {
452
+ this.api.get("/status", async (req, res) => {
431
453
  const started = Date.now();
432
454
  const dbHealthy = this.dbReady ? await this.db.isHealthy() : false;
433
455
  const checkDurationMs = Date.now() - started;
434
456
 
435
457
  const ok = dbHealthy;
458
+ if (!devApiKeySkipsRateLimits(req)) {
459
+ res.json({ ok });
460
+ return;
461
+ }
436
462
  const canaryEnv = process.env["CANARY"]?.trim().toLowerCase();
437
463
  res.json({
438
464
  canary:
@@ -440,20 +466,9 @@ export class Spire extends EventEmitter {
440
466
  canaryEnv === "true" ||
441
467
  canaryEnv === "yes",
442
468
  checkDurationMs,
443
- commitSha: this.commitSha,
444
- dbHealthy,
445
- dbReady: this.dbReady,
446
- latencyBudgetMs: STATUS_LATENCY_BUDGET_MS,
447
- metrics: {
448
- requestsTotal: this.requestsTotal,
449
- },
450
469
  now: new Date(),
451
470
  ok,
452
- startedAt: this.startedAt.toISOString(),
453
- uptimeSeconds: Math.floor(process.uptime()),
454
471
  version: this.version,
455
- withinLatencyBudget:
456
- checkDurationMs <= STATUS_LATENCY_BUDGET_MS,
457
472
  });
458
473
  });
459
474
 
@@ -1,3 +1,9 @@
1
+ /**
2
+ * Copyright (c) 2020-2026 Vex Heavy Industries LLC
3
+ * Licensed under AGPL-3.0. See LICENSE for details.
4
+ * Commercial licenses available at vex.wtf
5
+ */
6
+
1
7
  import type { SpireOptions } from "../Spire.ts";
2
8
  import type { PreKeysWS } from "@vex-chat/types";
3
9
 
@@ -1 +1,7 @@
1
+ /**
2
+ * Copyright (c) 2020-2026 Vex Heavy Industries LLC
3
+ * Licensed under AGPL-3.0. See LICENSE for details.
4
+ * Commercial licenses available at vex.wtf
5
+ */
6
+
1
7
  declare module "ed2curve";
package/src/db/schema.ts CHANGED
@@ -1,3 +1,9 @@
1
+ /**
2
+ * Copyright (c) 2020-2026 Vex Heavy Industries LLC
3
+ * Licensed under AGPL-3.0. See LICENSE for details.
4
+ * Commercial licenses available at vex.wtf
5
+ */
6
+
1
7
  import type { Insertable, Selectable, Updateable } from "kysely";
2
8
 
3
9
  // ── Table interfaces ────────────────────────────────────────────────────
package/src/index.ts CHANGED
@@ -1,3 +1,9 @@
1
+ /**
2
+ * Copyright (c) 2020-2026 Vex Heavy Industries LLC
3
+ * Licensed under AGPL-3.0. See LICENSE for details.
4
+ * Commercial licenses available at vex.wtf
5
+ */
6
+
1
7
  import { Spire } from "./Spire.ts";
2
8
 
3
9
  export { Spire };
@@ -1,3 +1,9 @@
1
+ /**
2
+ * Copyright (c) 2020-2026 Vex Heavy Industries LLC
3
+ * Licensed under AGPL-3.0. See LICENSE for details.
4
+ * Commercial licenses available at vex.wtf
5
+ */
6
+
1
7
  import type { NextFunction, Request, Response } from "express";
2
8
  import type { z } from "zod/v4";
3
9
 
@@ -1,3 +1,9 @@
1
+ /**
2
+ * Copyright (c) 2020-2026 Vex Heavy Industries LLC
3
+ * Licensed under AGPL-3.0. See LICENSE for details.
4
+ * Commercial licenses available at vex.wtf
5
+ */
6
+
1
7
  import { type Kysely, sql } from "kysely";
2
8
 
3
9
  export async function down(db: Kysely<unknown>): Promise<void> {
@@ -1,3 +1,9 @@
1
+ /**
2
+ * Copyright (c) 2020-2026 Vex Heavy Industries LLC
3
+ * Licensed under AGPL-3.0. See LICENSE for details.
4
+ * Commercial licenses available at vex.wtf
5
+ */
6
+
1
7
  import { type Kysely, sql } from "kysely";
2
8
 
3
9
  export async function down(db: Kysely<unknown>): Promise<void> {
package/src/run.ts CHANGED
@@ -1,3 +1,9 @@
1
+ /**
2
+ * Copyright (c) 2020-2026 Vex Heavy Industries LLC
3
+ * Licensed under AGPL-3.0. See LICENSE for details.
4
+ * Commercial licenses available at vex.wtf
5
+ */
6
+
1
7
  import type { SpireOptions } from "./Spire.ts";
2
8
 
3
9
  import { Spire } from "./Spire.ts";
@@ -1,3 +1,9 @@
1
+ /**
2
+ * Copyright (c) 2020-2026 Vex Heavy Industries LLC
3
+ * Licensed under AGPL-3.0. See LICENSE for details.
4
+ * Commercial licenses available at vex.wtf
5
+ */
6
+
1
7
  import * as fs from "node:fs";
2
8
  import * as fsp from "node:fs/promises";
3
9
 
@@ -1,3 +1,9 @@
1
+ /**
2
+ * Copyright (c) 2020-2026 Vex Heavy Industries LLC
3
+ * Licensed under AGPL-3.0. See LICENSE for details.
4
+ * Commercial licenses available at vex.wtf
5
+ */
6
+
1
7
  /**
2
8
  * Centralized HTTP error handling.
3
9
  *
@@ -1,3 +1,9 @@
1
+ /**
2
+ * Copyright (c) 2020-2026 Vex Heavy Industries LLC
3
+ * Licensed under AGPL-3.0. See LICENSE for details.
4
+ * Commercial licenses available at vex.wtf
5
+ */
6
+
1
7
  import type { Database } from "../Database.ts";
2
8
  import type { FileSQL } from "@vex-chat/types";
3
9
 
@@ -1,3 +1,9 @@
1
+ /**
2
+ * Copyright (c) 2020-2026 Vex Heavy Industries LLC
3
+ * Licensed under AGPL-3.0. See LICENSE for details.
4
+ * Commercial licenses available at vex.wtf
5
+ */
6
+
1
7
  import type { Database } from "../Database.ts";
2
8
  import type { Emoji } from "@vex-chat/types";
3
9
 
@@ -192,16 +198,10 @@ export const initApp = (
192
198
  type: "application/msgpack",
193
199
  }),
194
200
  );
195
- api.use(helmet());
196
- api.use(msgpackParser);
197
- api.use(checkAuth);
198
- api.use(checkDevice);
199
201
 
200
- // Browser clients (web, Tauri, Capacitor, etc.) hit Spire from arbitrary
201
- // origins when self-hosted or embedded in third-party apps. libvex uses
202
- // `Authorization: Bearer` only (no cookies), so reflecting `Origin` is the
203
- // usual bearer-API pattern. Set `CORS_ORIGINS` to a comma-separated allowlist
204
- // when an operator wants to restrict which frontends may call the API.
202
+ // CORS before helmet/auth so browser preflight (OPTIONS) and PATCH get
203
+ // Access-Control-* headers. Node clients ignore CORS; browsers do not.
204
+ // Set `CORS_ORIGINS` to a comma-separated allowlist to restrict frontends.
205
205
  const corsRaw = process.env["CORS_ORIGINS"];
206
206
  const corsOrigins = corsRaw
207
207
  ? corsRaw
@@ -212,6 +212,15 @@ export const initApp = (
212
212
  api.use(
213
213
  cors({
214
214
  credentials: true,
215
+ methods: [
216
+ "GET",
217
+ "HEAD",
218
+ "POST",
219
+ "PUT",
220
+ "PATCH",
221
+ "DELETE",
222
+ "OPTIONS",
223
+ ],
215
224
  origin:
216
225
  corsOrigins.length > 0
217
226
  ? corsOrigins
@@ -219,6 +228,11 @@ export const initApp = (
219
228
  }),
220
229
  );
221
230
 
231
+ api.use(helmet());
232
+ api.use(msgpackParser);
233
+ api.use(checkAuth);
234
+ api.use(checkDevice);
235
+
222
236
  api.get("/server/:id", protect, async (req, res) => {
223
237
  const server = await db.retrieveServer(getParam(req, "id"));
224
238
 
@@ -1,3 +1,9 @@
1
+ /**
2
+ * Copyright (c) 2020-2026 Vex Heavy Industries LLC
3
+ * Licensed under AGPL-3.0. See LICENSE for details.
4
+ * Commercial licenses available at vex.wtf
5
+ */
6
+
1
7
  import type { Database } from "../Database.ts";
2
8
  import type { TokenScopes } from "@vex-chat/types";
3
9
 
@@ -1,3 +1,9 @@
1
+ /**
2
+ * Copyright (c) 2020-2026 Vex Heavy Industries LLC
3
+ * Licensed under AGPL-3.0. See LICENSE for details.
4
+ * Commercial licenses available at vex.wtf
5
+ */
6
+
1
7
  /**
2
8
  * API documentation endpoints (development only).
3
9
  *
@@ -1,3 +1,9 @@
1
+ /**
2
+ * Copyright (c) 2020-2026 Vex Heavy Industries LLC
3
+ * Licensed under AGPL-3.0. See LICENSE for details.
4
+ * Commercial licenses available at vex.wtf
5
+ */
6
+
1
7
  import type { Permission } from "@vex-chat/types";
2
8
 
3
9
  /**
@@ -1,3 +1,9 @@
1
+ /**
2
+ * Copyright (c) 2020-2026 Vex Heavy Industries LLC
3
+ * Licensed under AGPL-3.0. See LICENSE for details.
4
+ * Commercial licenses available at vex.wtf
5
+ */
6
+
1
7
  import type { Request } from "express";
2
8
 
3
9
  import { timingSafeEqual } from "node:crypto";
@@ -1,3 +1,9 @@
1
+ /**
2
+ * Copyright (c) 2020-2026 Vex Heavy Industries LLC
3
+ * Licensed under AGPL-3.0. See LICENSE for details.
4
+ * Commercial licenses available at vex.wtf
5
+ */
6
+
1
7
  import type { Database } from "../Database.ts";
2
8
 
3
9
  import express from "express";
@@ -1,3 +1,9 @@
1
+ /**
2
+ * Copyright (c) 2020-2026 Vex Heavy Industries LLC
3
+ * Licensed under AGPL-3.0. See LICENSE for details.
4
+ * Commercial licenses available at vex.wtf
5
+ */
6
+
1
7
  import type { Device, User, UserRecord } from "@vex-chat/types";
2
8
  import type { Request } from "express";
3
9
 
@@ -1,3 +1,9 @@
1
+ /**
2
+ * Copyright (c) 2020-2026 Vex Heavy Industries LLC
3
+ * Licensed under AGPL-3.0. See LICENSE for details.
4
+ * Commercial licenses available at vex.wtf
5
+ */
6
+
1
7
  import type { Device, User } from "@vex-chat/types";
2
8
 
3
9
  /**
@@ -1,3 +1,9 @@
1
+ /**
2
+ * Copyright (c) 2020-2026 Vex Heavy Industries LLC
3
+ * Licensed under AGPL-3.0. See LICENSE for details.
4
+ * Commercial licenses available at vex.wtf
5
+ */
6
+
1
7
  import { parse as uuidParse } from "uuid";
2
8
 
3
9
  export function createUint8UUID(): Uint8Array {
@@ -1,3 +1,9 @@
1
+ /**
2
+ * Copyright (c) 2020-2026 Vex Heavy Industries LLC
3
+ * Licensed under AGPL-3.0. See LICENSE for details.
4
+ * Commercial licenses available at vex.wtf
5
+ */
6
+
1
7
  /**
2
8
  * Returns the dedicated JWT HMAC signing secret.
3
9
  *
@@ -1,3 +1,9 @@
1
+ /**
2
+ * Copyright (c) 2020-2026 Vex Heavy Industries LLC
3
+ * Licensed under AGPL-3.0. See LICENSE for details.
4
+ * Commercial licenses available at vex.wtf
5
+ */
6
+
1
7
  import { config } from "dotenv";
2
8
 
3
9
  /* Populate process.env with vars from .env and verify required vars are present. */
@@ -1,3 +1,9 @@
1
+ /**
2
+ * Copyright (c) 2020-2026 Vex Heavy Industries LLC
3
+ * Licensed under AGPL-3.0. See LICENSE for details.
4
+ * Commercial licenses available at vex.wtf
5
+ */
6
+
1
7
  import { Packr } from "msgpackr";
2
8
 
3
9
  // Standard msgpack encoder/decoder configured for broad compatibility.