@selvajs/server 1.4.1 → 1.5.0-beta.1

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 (81) hide show
  1. package/dist/access/guards.d.ts.map +1 -1
  2. package/dist/access/guards.js +10 -2
  3. package/dist/access/guards.js.map +1 -1
  4. package/dist/api/bodies.d.ts +10 -2
  5. package/dist/api/bodies.d.ts.map +1 -1
  6. package/dist/api/bodies.js +9 -1
  7. package/dist/api/bodies.js.map +1 -1
  8. package/dist/api/deps.d.ts +7 -1
  9. package/dist/api/deps.d.ts.map +1 -1
  10. package/dist/api/deps.js +2 -1
  11. package/dist/api/deps.js.map +1 -1
  12. package/dist/api/errors.d.ts +6 -2
  13. package/dist/api/errors.d.ts.map +1 -1
  14. package/dist/api/errors.js +9 -4
  15. package/dist/api/errors.js.map +1 -1
  16. package/dist/api/index.d.ts +4 -3
  17. package/dist/api/index.d.ts.map +1 -1
  18. package/dist/api/index.js +3 -2
  19. package/dist/api/index.js.map +1 -1
  20. package/dist/api/respond.d.ts +22 -9
  21. package/dist/api/respond.d.ts.map +1 -1
  22. package/dist/api/respond.js +12 -11
  23. package/dist/api/respond.js.map +1 -1
  24. package/dist/api/responses-schema.d.ts +32 -2
  25. package/dist/api/responses-schema.d.ts.map +1 -1
  26. package/dist/api/responses-schema.js +24 -2
  27. package/dist/api/responses-schema.js.map +1 -1
  28. package/dist/api/scope.d.ts +22 -0
  29. package/dist/api/scope.d.ts.map +1 -0
  30. package/dist/api/scope.js +63 -0
  31. package/dist/api/scope.js.map +1 -0
  32. package/dist/definitions/visibility.d.ts.map +1 -1
  33. package/dist/definitions/visibility.js +4 -3
  34. package/dist/definitions/visibility.js.map +1 -1
  35. package/dist/handlers/apiTokens.d.ts +37 -0
  36. package/dist/handlers/apiTokens.d.ts.map +1 -0
  37. package/dist/handlers/apiTokens.js +191 -0
  38. package/dist/handlers/apiTokens.js.map +1 -0
  39. package/dist/handlers/definitions.d.ts.map +1 -1
  40. package/dist/handlers/definitions.js +5 -1
  41. package/dist/handlers/definitions.js.map +1 -1
  42. package/dist/handlers/index.d.ts +1 -0
  43. package/dist/handlers/index.d.ts.map +1 -1
  44. package/dist/handlers/index.js +1 -0
  45. package/dist/handlers/index.js.map +1 -1
  46. package/dist/handlers/orgMembers.d.ts.map +1 -1
  47. package/dist/handlers/orgMembers.js +4 -2
  48. package/dist/handlers/orgMembers.js.map +1 -1
  49. package/dist/handlers/projects.d.ts.map +1 -1
  50. package/dist/handlers/projects.js +3 -2
  51. package/dist/handlers/projects.js.map +1 -1
  52. package/dist/handlers/reclaim.js +2 -2
  53. package/dist/handlers/reclaim.js.map +1 -1
  54. package/dist/http/api-token.d.ts +46 -0
  55. package/dist/http/api-token.d.ts.map +1 -0
  56. package/dist/http/api-token.js +98 -0
  57. package/dist/http/api-token.js.map +1 -0
  58. package/dist/http/index.d.ts +2 -0
  59. package/dist/http/index.d.ts.map +1 -1
  60. package/dist/http/index.js +2 -0
  61. package/dist/http/index.js.map +1 -1
  62. package/dist/http/request-context.d.ts +24 -0
  63. package/dist/http/request-context.d.ts.map +1 -0
  64. package/dist/http/request-context.js +27 -0
  65. package/dist/http/request-context.js.map +1 -0
  66. package/dist/logging/PinoLogger.d.ts.map +1 -1
  67. package/dist/logging/PinoLogger.js +7 -1
  68. package/dist/logging/PinoLogger.js.map +1 -1
  69. package/dist/testing/harness.d.ts +5 -1
  70. package/dist/testing/harness.d.ts.map +1 -1
  71. package/dist/testing/harness.js +5 -9
  72. package/dist/testing/harness.js.map +1 -1
  73. package/dist/tokens/api-token-codec.d.ts +25 -0
  74. package/dist/tokens/api-token-codec.d.ts.map +1 -0
  75. package/dist/tokens/api-token-codec.js +70 -0
  76. package/dist/tokens/api-token-codec.js.map +1 -0
  77. package/dist/tokens/index.d.ts +1 -0
  78. package/dist/tokens/index.d.ts.map +1 -1
  79. package/dist/tokens/index.js +2 -0
  80. package/dist/tokens/index.js.map +1 -1
  81. package/package.json +5 -5
@@ -0,0 +1,70 @@
1
+ import { randomBytes } from 'node:crypto';
2
+ import { crc32 } from 'node:zlib';
3
+ import { createTokenCodec } from './token-codec.js';
4
+ /**
5
+ * API token format: `selva_` + 30 base62 random chars + 6 base62 chars of
6
+ * CRC32 over the random part. 42 chars total.
7
+ *
8
+ * - The prefix is what secret scanners match on; `sk_` was dropped because
9
+ * Stripe and OpenAI keys share it.
10
+ * - 30 base62 chars carry ~178 bits of entropy.
11
+ * - The checksum lets the resolver reject a typo or a truncated paste without
12
+ * a store lookup. It is not a MAC: the HMAC at rest is what authenticates.
13
+ * - CRC32 tops out below 62^6, so 6 chars always fit; shorter values are
14
+ * left-padded with `0`.
15
+ */
16
+ export const API_TOKEN_PREFIX = 'selva_';
17
+ const RANDOM_LENGTH = 30;
18
+ const CHECKSUM_LENGTH = 6;
19
+ const TOKEN_LENGTH = API_TOKEN_PREFIX.length + RANDOM_LENGTH + CHECKSUM_LENGTH;
20
+ const BASE62 = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
21
+ const BODY_PATTERN = /^[0-9A-Za-z]+$/;
22
+ // Bytes at or above 248 (62 * 4) are dropped rather than reduced, so every
23
+ // character is equally likely.
24
+ function randomBase62(length) {
25
+ let out = '';
26
+ while (out.length < length) {
27
+ for (const byte of randomBytes(length * 2)) {
28
+ if (byte < 248)
29
+ out += BASE62[byte % 62];
30
+ if (out.length === length)
31
+ break;
32
+ }
33
+ }
34
+ return out;
35
+ }
36
+ function checksum(random) {
37
+ let n = crc32(random);
38
+ let out = '';
39
+ for (let i = 0; i < CHECKSUM_LENGTH; i++) {
40
+ out = BASE62[n % 62] + out;
41
+ n = Math.floor(n / 62);
42
+ }
43
+ return out;
44
+ }
45
+ /**
46
+ * Shape only, no secret needed. For spotting a key where it must not be, such
47
+ * as a query string, without flagging text that merely starts with `selva_`.
48
+ */
49
+ export function looksLikeApiToken(value) {
50
+ return (value.length === TOKEN_LENGTH &&
51
+ value.startsWith(API_TOKEN_PREFIX) &&
52
+ BODY_PATTERN.test(value.slice(API_TOKEN_PREFIX.length)));
53
+ }
54
+ export function createApiTokenCodec(secret) {
55
+ const base = createTokenCodec({ prefix: API_TOKEN_PREFIX, secret });
56
+ return {
57
+ ...base,
58
+ mintRawToken() {
59
+ const random = randomBase62(RANDOM_LENGTH);
60
+ return API_TOKEN_PREFIX + random + checksum(random);
61
+ },
62
+ hasValidChecksum(raw) {
63
+ if (!looksLikeApiToken(raw))
64
+ return false;
65
+ const body = raw.slice(API_TOKEN_PREFIX.length);
66
+ return checksum(body.slice(0, RANDOM_LENGTH)) === body.slice(RANDOM_LENGTH);
67
+ }
68
+ };
69
+ }
70
+ //# sourceMappingURL=api-token-codec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api-token-codec.js","sourceRoot":"","sources":["../../src/tokens/api-token-codec.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,KAAK,EAAE,MAAM,WAAW,CAAC;AAClC,OAAO,EAAE,gBAAgB,EAAmB,MAAM,kBAAkB,CAAC;AAErE;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,QAAQ,CAAC;AACzC,MAAM,aAAa,GAAG,EAAE,CAAC;AACzB,MAAM,eAAe,GAAG,CAAC,CAAC;AAC1B,MAAM,YAAY,GAAG,gBAAgB,CAAC,MAAM,GAAG,aAAa,GAAG,eAAe,CAAC;AAE/E,MAAM,MAAM,GAAG,gEAAgE,CAAC;AAChF,MAAM,YAAY,GAAG,gBAAgB,CAAC;AAEtC,2EAA2E;AAC3E,+BAA+B;AAC/B,SAAS,YAAY,CAAC,MAAc;IACnC,IAAI,GAAG,GAAG,EAAE,CAAC;IACb,OAAO,GAAG,CAAC,MAAM,GAAG,MAAM,EAAE,CAAC;QAC5B,KAAK,MAAM,IAAI,IAAI,WAAW,CAAC,MAAM,GAAG,CAAC,CAAC,EAAE,CAAC;YAC5C,IAAI,IAAI,GAAG,GAAG;gBAAE,GAAG,IAAI,MAAM,CAAC,IAAI,GAAG,EAAE,CAAC,CAAC;YACzC,IAAI,GAAG,CAAC,MAAM,KAAK,MAAM;gBAAE,MAAM;QAClC,CAAC;IACF,CAAC;IACD,OAAO,GAAG,CAAC;AACZ,CAAC;AAED,SAAS,QAAQ,CAAC,MAAc;IAC/B,IAAI,CAAC,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC;IACtB,IAAI,GAAG,GAAG,EAAE,CAAC;IACb,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,eAAe,EAAE,CAAC,EAAE,EAAE,CAAC;QAC1C,GAAG,GAAG,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,GAAG,GAAG,CAAC;QAC3B,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC;IACxB,CAAC;IACD,OAAO,GAAG,CAAC;AACZ,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,iBAAiB,CAAC,KAAa;IAC9C,OAAO,CACN,KAAK,CAAC,MAAM,KAAK,YAAY;QAC7B,KAAK,CAAC,UAAU,CAAC,gBAAgB,CAAC;QAClC,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,gBAAgB,CAAC,MAAM,CAAC,CAAC,CACvD,CAAC;AACH,CAAC;AAOD,MAAM,UAAU,mBAAmB,CAAC,MAAc;IACjD,MAAM,IAAI,GAAG,gBAAgB,CAAC,EAAE,MAAM,EAAE,gBAAgB,EAAE,MAAM,EAAE,CAAC,CAAC;IACpE,OAAO;QACN,GAAG,IAAI;QACP,YAAY;YACX,MAAM,MAAM,GAAG,YAAY,CAAC,aAAa,CAAC,CAAC;YAC3C,OAAO,gBAAgB,GAAG,MAAM,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC;QACrD,CAAC;QACD,gBAAgB,CAAC,GAAW;YAC3B,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC;gBAAE,OAAO,KAAK,CAAC;YAC1C,MAAM,IAAI,GAAG,GAAG,CAAC,KAAK,CAAC,gBAAgB,CAAC,MAAM,CAAC,CAAC;YAChD,OAAO,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,aAAa,CAAC,CAAC,KAAK,IAAI,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC;QAC7E,CAAC;KACD,CAAC;AACH,CAAC"}
@@ -1,2 +1,3 @@
1
1
  export { createTokenCodec, MIN_TOKEN_SECRET_LENGTH, type TokenCodec, type TokenCodecConfig } from './token-codec.js';
2
+ export { createApiTokenCodec, API_TOKEN_PREFIX, looksLikeApiToken, type ApiTokenCodec } from './api-token-codec.js';
2
3
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/tokens/index.ts"],"names":[],"mappings":"AAEA,OAAO,EACN,gBAAgB,EAChB,uBAAuB,EACvB,KAAK,UAAU,EACf,KAAK,gBAAgB,EACrB,MAAM,kBAAkB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/tokens/index.ts"],"names":[],"mappings":"AAEA,OAAO,EACN,gBAAgB,EAChB,uBAAuB,EACvB,KAAK,UAAU,EACf,KAAK,gBAAgB,EACrB,MAAM,kBAAkB,CAAC;AAG1B,OAAO,EACN,mBAAmB,EACnB,gBAAgB,EAChB,iBAAiB,EACjB,KAAK,aAAa,EAClB,MAAM,sBAAsB,CAAC"}
@@ -1,3 +1,5 @@
1
1
  // HMAC token codec for capability-URL tokens (share links, invites, …).
2
2
  export { createTokenCodec, MIN_TOKEN_SECRET_LENGTH } from './token-codec.js';
3
+ // API tokens (`selva_`): the same HMAC-at-rest scheme, plus a checksum.
4
+ export { createApiTokenCodec, API_TOKEN_PREFIX, looksLikeApiToken } from './api-token-codec.js';
3
5
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/tokens/index.ts"],"names":[],"mappings":"AAAA,wEAAwE;AAExE,OAAO,EACN,gBAAgB,EAChB,uBAAuB,EAGvB,MAAM,kBAAkB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/tokens/index.ts"],"names":[],"mappings":"AAAA,wEAAwE;AAExE,OAAO,EACN,gBAAgB,EAChB,uBAAuB,EAGvB,MAAM,kBAAkB,CAAC;AAE1B,wEAAwE;AACxE,OAAO,EACN,mBAAmB,EACnB,gBAAgB,EAChB,iBAAiB,EAEjB,MAAM,sBAAsB,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@selvajs/server",
3
- "version": "1.4.1",
3
+ "version": "1.5.0-beta.1",
4
4
  "description": "Transport-agnostic server building blocks for apps built on the Selva engine (limits, rate limiting, SSRF guard, remote-definition fetch, definition service + render loader); the solve core lives in @selvajs/solve/server",
5
5
  "license": "MIT",
6
6
  "author": "VektorNode",
@@ -111,9 +111,9 @@
111
111
  "dependencies": {
112
112
  "zod": "^4.6.5",
113
113
  "@selvajs/compute": "^4.2.1",
114
- "@selvajs/notifications": "^0.2.1",
115
- "@selvajs/platform": "^0.20.1",
116
- "@selvajs/schemas": "^5.1.1"
114
+ "@selvajs/notifications": "^0.3.0-beta.1",
115
+ "@selvajs/schemas": "^5.2.0",
116
+ "@selvajs/platform": "^0.21.0-beta.1"
117
117
  },
118
118
  "peerDependencies": {
119
119
  "@sentry/node": ">=8",
@@ -138,7 +138,7 @@
138
138
  "typescript": "~6.0.3",
139
139
  "vitest": "^5.0.2",
140
140
  "@selvajs/config": "0.0.4",
141
- "@selvajs/local-provider": "0.15.3"
141
+ "@selvajs/local-provider": "0.16.0-beta.0"
142
142
  },
143
143
  "scripts": {
144
144
  "build": "tsc",