@qlever-llc/trellis 0.5.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 (118) hide show
  1. package/README.md +9 -0
  2. package/esm/_dnt.polyfills.d.ts +7 -0
  3. package/esm/_dnt.polyfills.d.ts.map +1 -0
  4. package/esm/_dnt.polyfills.js +1 -0
  5. package/esm/package.json +3 -0
  6. package/esm/trellis/browser.d.ts +11 -0
  7. package/esm/trellis/browser.d.ts.map +1 -0
  8. package/esm/trellis/browser.js +10 -0
  9. package/esm/trellis/client.d.ts +31 -0
  10. package/esm/trellis/client.d.ts.map +1 -0
  11. package/esm/trellis/client.js +13 -0
  12. package/esm/trellis/codec.d.ts +12 -0
  13. package/esm/trellis/codec.d.ts.map +1 -0
  14. package/esm/trellis/codec.js +60 -0
  15. package/esm/trellis/env.d.ts +2 -0
  16. package/esm/trellis/env.d.ts.map +1 -0
  17. package/esm/trellis/env.js +1 -0
  18. package/esm/trellis/errors/AuthError.d.ts +30 -0
  19. package/esm/trellis/errors/AuthError.d.ts.map +1 -0
  20. package/esm/trellis/errors/AuthError.js +65 -0
  21. package/esm/trellis/errors/KVError.d.ts +31 -0
  22. package/esm/trellis/errors/KVError.d.ts.map +1 -0
  23. package/esm/trellis/errors/KVError.js +46 -0
  24. package/esm/trellis/errors/RemoteError.d.ts +47 -0
  25. package/esm/trellis/errors/RemoteError.d.ts.map +1 -0
  26. package/esm/trellis/errors/RemoteError.js +80 -0
  27. package/esm/trellis/errors/TrellisError.d.ts +16 -0
  28. package/esm/trellis/errors/TrellisError.d.ts.map +1 -0
  29. package/esm/trellis/errors/TrellisError.js +15 -0
  30. package/esm/trellis/errors/ValidationError.d.ts +51 -0
  31. package/esm/trellis/errors/ValidationError.d.ts.map +1 -0
  32. package/esm/trellis/errors/ValidationError.js +77 -0
  33. package/esm/trellis/errors/index.d.ts +38 -0
  34. package/esm/trellis/errors/index.d.ts.map +1 -0
  35. package/esm/trellis/errors/index.js +26 -0
  36. package/esm/trellis/globals.d.ts +2 -0
  37. package/esm/trellis/globals.d.ts.map +1 -0
  38. package/esm/trellis/globals.js +8 -0
  39. package/esm/trellis/helpers.d.ts +12 -0
  40. package/esm/trellis/helpers.d.ts.map +1 -0
  41. package/esm/trellis/helpers.js +47 -0
  42. package/esm/trellis/index.d.ts +11 -0
  43. package/esm/trellis/index.d.ts.map +1 -0
  44. package/esm/trellis/index.js +6 -0
  45. package/esm/trellis/kv.d.ts +67 -0
  46. package/esm/trellis/kv.d.ts.map +1 -0
  47. package/esm/trellis/kv.js +326 -0
  48. package/esm/trellis/models/trellis/TrellisError.d.ts +43 -0
  49. package/esm/trellis/models/trellis/TrellisError.d.ts.map +1 -0
  50. package/esm/trellis/models/trellis/TrellisError.js +16 -0
  51. package/esm/trellis/tasks.d.ts +11 -0
  52. package/esm/trellis/tasks.d.ts.map +1 -0
  53. package/esm/trellis/tasks.js +41 -0
  54. package/esm/trellis/tracing.d.ts +5 -0
  55. package/esm/trellis/tracing.d.ts.map +1 -0
  56. package/esm/trellis/tracing.js +7 -0
  57. package/esm/trellis/trellis.d.ts +117 -0
  58. package/esm/trellis/trellis.d.ts.map +1 -0
  59. package/esm/trellis/trellis.js +710 -0
  60. package/package.json +49 -0
  61. package/script/_dnt.polyfills.d.ts +7 -0
  62. package/script/_dnt.polyfills.d.ts.map +1 -0
  63. package/script/_dnt.polyfills.js +2 -0
  64. package/script/package.json +3 -0
  65. package/script/trellis/browser.d.ts +11 -0
  66. package/script/trellis/browser.d.ts.map +1 -0
  67. package/script/trellis/browser.js +21 -0
  68. package/script/trellis/client.d.ts +31 -0
  69. package/script/trellis/client.d.ts.map +1 -0
  70. package/script/trellis/client.js +16 -0
  71. package/script/trellis/codec.d.ts +12 -0
  72. package/script/trellis/codec.d.ts.map +1 -0
  73. package/script/trellis/codec.js +66 -0
  74. package/script/trellis/env.d.ts +2 -0
  75. package/script/trellis/env.d.ts.map +1 -0
  76. package/script/trellis/env.js +5 -0
  77. package/script/trellis/errors/AuthError.d.ts +30 -0
  78. package/script/trellis/errors/AuthError.d.ts.map +1 -0
  79. package/script/trellis/errors/AuthError.js +72 -0
  80. package/script/trellis/errors/KVError.d.ts +31 -0
  81. package/script/trellis/errors/KVError.d.ts.map +1 -0
  82. package/script/trellis/errors/KVError.js +53 -0
  83. package/script/trellis/errors/RemoteError.d.ts +47 -0
  84. package/script/trellis/errors/RemoteError.d.ts.map +1 -0
  85. package/script/trellis/errors/RemoteError.js +87 -0
  86. package/script/trellis/errors/TrellisError.d.ts +16 -0
  87. package/script/trellis/errors/TrellisError.d.ts.map +1 -0
  88. package/script/trellis/errors/TrellisError.js +19 -0
  89. package/script/trellis/errors/ValidationError.d.ts +51 -0
  90. package/script/trellis/errors/ValidationError.d.ts.map +1 -0
  91. package/script/trellis/errors/ValidationError.js +84 -0
  92. package/script/trellis/errors/index.d.ts +38 -0
  93. package/script/trellis/errors/index.d.ts.map +1 -0
  94. package/script/trellis/errors/index.js +40 -0
  95. package/script/trellis/globals.d.ts +2 -0
  96. package/script/trellis/globals.d.ts.map +1 -0
  97. package/script/trellis/globals.js +11 -0
  98. package/script/trellis/helpers.d.ts +12 -0
  99. package/script/trellis/helpers.d.ts.map +1 -0
  100. package/script/trellis/helpers.js +54 -0
  101. package/script/trellis/index.d.ts +11 -0
  102. package/script/trellis/index.d.ts.map +1 -0
  103. package/script/trellis/index.js +24 -0
  104. package/script/trellis/kv.d.ts +67 -0
  105. package/script/trellis/kv.d.ts.map +1 -0
  106. package/script/trellis/kv.js +354 -0
  107. package/script/trellis/models/trellis/TrellisError.d.ts +43 -0
  108. package/script/trellis/models/trellis/TrellisError.d.ts.map +1 -0
  109. package/script/trellis/models/trellis/TrellisError.js +22 -0
  110. package/script/trellis/tasks.d.ts +11 -0
  111. package/script/trellis/tasks.d.ts.map +1 -0
  112. package/script/trellis/tasks.js +45 -0
  113. package/script/trellis/tracing.d.ts +5 -0
  114. package/script/trellis/tracing.d.ts.map +1 -0
  115. package/script/trellis/tracing.js +49 -0
  116. package/script/trellis/trellis.d.ts +117 -0
  117. package/script/trellis/trellis.d.ts.map +1 -0
  118. package/script/trellis/trellis.js +715 -0
@@ -0,0 +1,77 @@
1
+ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
2
+ if (kind === "m") throw new TypeError("Private method is not writable");
3
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
4
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
5
+ return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
6
+ };
7
+ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
8
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
9
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
10
+ return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
11
+ };
12
+ var _ValidationError_normalizedErrors;
13
+ import Type from "typebox";
14
+ import { TrellisError } from "./TrellisError.js";
15
+ function normalizeError(e) {
16
+ if ("schemaPath" in e) {
17
+ return { schemaPath: e.schemaPath, message: e.message ?? "Invalid value" };
18
+ }
19
+ return { schemaPath: e.path, message: e.message };
20
+ }
21
+ /**
22
+ * Schema for validation issue in ValidationError.
23
+ */
24
+ export const ValidationIssueSchema = Type.Object({
25
+ path: Type.String(),
26
+ message: Type.String(),
27
+ });
28
+ /**
29
+ * Schema for ValidationError serialization.
30
+ */
31
+ export const ValidationErrorDataSchema = Type.Object({
32
+ id: Type.String(),
33
+ type: Type.Literal("ValidationError"),
34
+ message: Type.String(),
35
+ issues: Type.Array(ValidationIssueSchema),
36
+ context: Type.Optional(Type.Record(Type.String(), Type.Unknown())),
37
+ traceId: Type.Optional(Type.String()),
38
+ });
39
+ /**
40
+ * Error for data validation failures.
41
+ * Includes schema validation and missing required data.
42
+ */
43
+ export class ValidationError extends TrellisError {
44
+ constructor(options) {
45
+ const { errors: rawErrors, ...baseOptions } = options;
46
+ const errors = [...rawErrors].map(normalizeError);
47
+ const msg = errors
48
+ .map((e) => `Validation failed. ${e.schemaPath}: ${e.message}.`)
49
+ .join("\n");
50
+ super(msg.length ? msg : "Data validation failed.", baseOptions);
51
+ Object.defineProperty(this, "name", {
52
+ enumerable: true,
53
+ configurable: true,
54
+ writable: true,
55
+ value: "ValidationError"
56
+ });
57
+ _ValidationError_normalizedErrors.set(this, void 0);
58
+ __classPrivateFieldSet(this, _ValidationError_normalizedErrors, errors, "f");
59
+ }
60
+ /**
61
+ * Serializes error to a plain object.
62
+ * Transforms internal errors array to issues array for serialization.
63
+ *
64
+ * @returns Plain object representation of the error
65
+ */
66
+ toSerializable() {
67
+ return {
68
+ ...this.baseSerializable(),
69
+ type: this.name,
70
+ issues: __classPrivateFieldGet(this, _ValidationError_normalizedErrors, "f").map((e) => ({
71
+ path: e.schemaPath,
72
+ message: e.message,
73
+ })),
74
+ };
75
+ }
76
+ }
77
+ _ValidationError_normalizedErrors = new WeakMap();
@@ -0,0 +1,38 @@
1
+ import { AuthError } from "./AuthError.js";
2
+ import { ValidationError } from "./ValidationError.js";
3
+ import { RemoteError } from "./RemoteError.js";
4
+ import { KVError } from "./KVError.js";
5
+ export { UnexpectedError } from "@qlever-llc/trellis-result";
6
+ export { TrellisError } from "./TrellisError.js";
7
+ export { AuthError } from "./AuthError.js";
8
+ export { ValidationError } from "./ValidationError.js";
9
+ export { RemoteError } from "./RemoteError.js";
10
+ export { KVError } from "./KVError.js";
11
+ export { type AuthErrorData, AuthErrorDataSchema } from "./AuthError.js";
12
+ export { type ValidationErrorData, ValidationErrorDataSchema, type ValidationIssue, ValidationIssueSchema, } from "./ValidationError.js";
13
+ export { type RemoteErrorData, RemoteErrorDataSchema } from "./RemoteError.js";
14
+ export { type KVErrorData, KVErrorDataSchema } from "./KVError.js";
15
+ /**
16
+ * Single source of truth for all Trellis errors.
17
+ * This object is used for compile-time type inference.
18
+ */
19
+ declare const TRELLIS_ERRORS: {
20
+ readonly UnexpectedError: any;
21
+ readonly AuthError: typeof AuthError;
22
+ readonly ValidationError: typeof ValidationError;
23
+ readonly RemoteError: typeof RemoteError;
24
+ readonly KVError: typeof KVError;
25
+ };
26
+ /**
27
+ * Compile-time mapping from error names to their instance types.
28
+ * Derived from TRELLIS_ERRORS to ensure types stay in sync with runtime.
29
+ */
30
+ export type TrellisErrorMap = {
31
+ [K in keyof typeof TRELLIS_ERRORS]: InstanceType<(typeof TRELLIS_ERRORS)[K]>;
32
+ };
33
+ export type TrellisErrorName = keyof TrellisErrorMap;
34
+ export type TrellisErrorInstance = TrellisErrorMap[TrellisErrorName];
35
+ export type MapErrorNamesToTypes<T extends readonly TrellisErrorName[]> = {
36
+ [K in keyof T]: T[K] extends TrellisErrorName ? TrellisErrorMap[T[K]] : never;
37
+ }[number];
38
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/trellis/errors/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAEvC,OAAO,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAC7D,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAEvC,OAAO,EAAE,KAAK,aAAa,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AACzE,OAAO,EACL,KAAK,mBAAmB,EACxB,yBAAyB,EACzB,KAAK,eAAe,EACpB,qBAAqB,GACtB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,KAAK,eAAe,EAAE,qBAAqB,EAAE,MAAM,kBAAkB,CAAC;AAC/E,OAAO,EAAE,KAAK,WAAW,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAEnE;;;GAGG;AACH,QAAA,MAAM,cAAc;;;;;;CAMV,CAAC;AAEX;;;GAGG;AACH,MAAM,MAAM,eAAe,GAAG;KAC3B,CAAC,IAAI,MAAM,OAAO,cAAc,GAAG,YAAY,CAAC,CAAC,OAAO,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC;CAC7E,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG,MAAM,eAAe,CAAC;AACrD,MAAM,MAAM,oBAAoB,GAAG,eAAe,CAAC,gBAAgB,CAAC,CAAC;AACrE,MAAM,MAAM,oBAAoB,CAAC,CAAC,SAAS,SAAS,gBAAgB,EAAE,IAAI;KACvE,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,gBAAgB,GAAG,eAAe,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,KAAK;CAC9E,CAAC,MAAM,CAAC,CAAC"}
@@ -0,0 +1,26 @@
1
+ import { UnexpectedError } from "@qlever-llc/trellis-result";
2
+ import { AuthError } from "./AuthError.js";
3
+ import { ValidationError } from "./ValidationError.js";
4
+ import { RemoteError } from "./RemoteError.js";
5
+ import { KVError } from "./KVError.js";
6
+ export { UnexpectedError } from "@qlever-llc/trellis-result";
7
+ export { TrellisError } from "./TrellisError.js";
8
+ export { AuthError } from "./AuthError.js";
9
+ export { ValidationError } from "./ValidationError.js";
10
+ export { RemoteError } from "./RemoteError.js";
11
+ export { KVError } from "./KVError.js";
12
+ export { AuthErrorDataSchema } from "./AuthError.js";
13
+ export { ValidationErrorDataSchema, ValidationIssueSchema, } from "./ValidationError.js";
14
+ export { RemoteErrorDataSchema } from "./RemoteError.js";
15
+ export { KVErrorDataSchema } from "./KVError.js";
16
+ /**
17
+ * Single source of truth for all Trellis errors.
18
+ * This object is used for compile-time type inference.
19
+ */
20
+ const TRELLIS_ERRORS = {
21
+ UnexpectedError,
22
+ AuthError,
23
+ ValidationError,
24
+ RemoteError,
25
+ KVError,
26
+ };
@@ -0,0 +1,2 @@
1
+ export declare const logger: import("pino").Logger<never, boolean>;
2
+ //# sourceMappingURL=globals.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"globals.d.ts","sourceRoot":"","sources":["../../src/trellis/globals.ts"],"names":[],"mappings":"AAMA,eAAO,MAAM,MAAM,uCAGjB,CAAC"}
@@ -0,0 +1,8 @@
1
+ import { pino } from "pino";
2
+ import { getEnv } from "./env.js";
3
+ // Support Deno and browser (+ Svelte's strict TS rules)
4
+ const level = getEnv("PINO_LEVEL") || "info";
5
+ export const logger = pino({
6
+ level,
7
+ base: { library: "@qlever-llc/trellis" },
8
+ });
@@ -0,0 +1,12 @@
1
+ import type { Paginated } from "@qlever-llc/trellis-contracts";
2
+ /**
3
+ * Compute the subject template from the message itself
4
+ */
5
+ export declare function template(template: string, data: Record<string, string | number | boolean>, opts?: {
6
+ allowWildcards: boolean;
7
+ }): string;
8
+ export declare function escapeNats(token: string): string;
9
+ export declare function escapeKvKey(key: string): string;
10
+ export declare function decodeSubject(token: string): string;
11
+ export declare function makePaginated(offset: number, limit: number, count: number): Paginated;
12
+ //# sourceMappingURL=helpers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../../src/trellis/helpers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,+BAA+B,CAAC;AAG/D;;GAEG;AACH,wBAAgB,QAAQ,CACtB,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,EAC/C,IAAI,GAAE;IAAE,cAAc,EAAE,OAAO,CAAA;CAA8B,GAC5D,MAAM,CAWR;AAGD,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAYhD;AAGD,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAW/C;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAUnD;AAED,wBAAgB,aAAa,CAC3B,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,MAAM,GACZ,SAAS,CAQX"}
@@ -0,0 +1,47 @@
1
+ import { Pointer } from "typebox/value";
2
+ /**
3
+ * Compute the subject template from the message itself
4
+ */
5
+ export function template(template, data, opts = { allowWildcards: false }) {
6
+ return template.replace(/\{([^}]+)\}/g, (_, key) => {
7
+ const token = Pointer.Get(data, key);
8
+ const v = token ? escapeNats(`${token}`) : "*";
9
+ if (!opts.allowWildcards && v === "*") {
10
+ throw new Error("All option templates must have values at runtime.");
11
+ }
12
+ return v;
13
+ });
14
+ }
15
+ const NATS_SUBJECT_TOKEN_FORBIDDEN = /[\u0000\s.*>~]/gu;
16
+ export function escapeNats(token) {
17
+ const out = token.replace(NATS_SUBJECT_TOKEN_FORBIDDEN, (ch) => `~${ch.codePointAt(0).toString(16).toUpperCase()}~`);
18
+ // Protect start with $ due to NATS internal use of it
19
+ if (out.length === 0 || out.startsWith("$")) {
20
+ return `_${out}`;
21
+ }
22
+ return out;
23
+ }
24
+ const NATS_KV_KEY_FORBIDDEN = /[\u0000\s*>~]/gu;
25
+ export function escapeKvKey(key) {
26
+ const out = key.replace(NATS_KV_KEY_FORBIDDEN, (ch) => `~${ch.codePointAt(0).toString(16).toUpperCase()}~`);
27
+ if (out.length === 0 || out.startsWith("$")) {
28
+ return `_${out}`;
29
+ }
30
+ return out;
31
+ }
32
+ export function decodeSubject(token) {
33
+ const out = token.replace(/~([0-9A-F]{1,6})~/g, (_, hex) => String.fromCodePoint(Number.parseInt(hex, 16)));
34
+ if (out.startsWith("_$")) {
35
+ return out.slice(1);
36
+ }
37
+ return out;
38
+ }
39
+ export function makePaginated(offset, limit, count) {
40
+ return {
41
+ count,
42
+ offset,
43
+ limit,
44
+ next: offset + limit >= count ? undefined : offset + limit,
45
+ prev: offset - limit <= 0 ? undefined : offset - limit,
46
+ };
47
+ }
@@ -0,0 +1,11 @@
1
+ import "../_dnt.polyfills.js";
2
+ export type { TrellisAPI } from "@qlever-llc/trellis-contracts";
3
+ export { err, isErr, isOk, ok, Result } from "@qlever-llc/trellis-result";
4
+ export type { ClientOpts } from "./client.js";
5
+ export { createClient } from "./client.js";
6
+ export type { TrellisErrorInstance } from "./errors/index.js";
7
+ export { AuthError, KVError, RemoteError, TrellisError, UnexpectedError, ValidationError, } from "./errors/index.js";
8
+ export { TypedKV } from "./kv.js";
9
+ export type { TrellisAuth, TrellisSigner } from "./trellis.js";
10
+ export { Trellis, TrellisServer } from "./trellis.js";
11
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/trellis/index.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;AAC9B,YAAY,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAC;AAChE,OAAO,EAAE,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,4BAA4B,CAAC;AAC1E,YAAY,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,YAAY,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AAC9D,OAAO,EACL,SAAS,EACT,OAAO,EACP,WAAW,EACX,YAAY,EACZ,eAAe,EACf,eAAe,GAChB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,YAAY,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC/D,OAAO,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC"}
@@ -0,0 +1,6 @@
1
+ import "../_dnt.polyfills.js";
2
+ export { err, isErr, isOk, ok, Result } from "@qlever-llc/trellis-result";
3
+ export { createClient } from "./client.js";
4
+ export { AuthError, KVError, RemoteError, TrellisError, UnexpectedError, ValidationError, } from "./errors/index.js";
5
+ export { TypedKV } from "./kv.js";
6
+ export { Trellis, TrellisServer } from "./trellis.js";
@@ -0,0 +1,67 @@
1
+ import { type KV, type KvEntry } from "@nats-io/kv";
2
+ import type { NatsConnection } from "@nats-io/nats-core/internal";
3
+ import { Result } from "@qlever-llc/trellis-result";
4
+ import type { StaticDecode, TSchema } from "typebox";
5
+ import { KVError, ValidationError } from "./errors/index.js";
6
+ /**
7
+ * Represents a watch event emitted when a KV entry changes.
8
+ */
9
+ export type WatchEvent<S extends TSchema> = {
10
+ /** The type of change: "update" for new/modified values, "delete" for deletions */
11
+ type: "update" | "delete";
12
+ /** The key that changed */
13
+ key: string;
14
+ /** The new value (only present for update events) */
15
+ value?: StaticDecode<S>;
16
+ /** The revision number of this change */
17
+ revision: number;
18
+ /** The timestamp when this change occurred */
19
+ timestamp: Date;
20
+ };
21
+ /**
22
+ * Options for the watch() method.
23
+ */
24
+ export type WatchOptions = {
25
+ /** If true, include delete events in the watch stream. Defaults to false. */
26
+ includeDeletes?: boolean;
27
+ };
28
+ export declare class TypedKV<S extends TSchema> {
29
+ readonly schema: S;
30
+ readonly kv: KV;
31
+ private constructor();
32
+ static open<S extends TSchema>(nats: NatsConnection, name: string, schema: S, options: {
33
+ history?: number;
34
+ ttl?: number;
35
+ bindOnly?: boolean;
36
+ maxValueBytes?: number;
37
+ }): Promise<Result<TypedKV<S>, KVError>>;
38
+ get(key: string): Promise<Result<TypedKVEntry<S>, KVError | ValidationError>>;
39
+ create(key: string, value: StaticDecode<S>): Promise<Result<void, KVError>>;
40
+ put(key: string, value: StaticDecode<S>): Promise<Result<void, KVError>>;
41
+ delete(key: string): Promise<Result<void, KVError>>;
42
+ keys(filter?: string | string[]): Promise<Result<AsyncIterable<string>, KVError>>;
43
+ status(): Promise<Result<{
44
+ values: number;
45
+ }, KVError>>;
46
+ }
47
+ export declare class TypedKVEntry<S extends TSchema> {
48
+ private schema;
49
+ private kv;
50
+ private entry;
51
+ readonly value: StaticDecode<S>;
52
+ constructor(schema: S, kv: KV, entry: KvEntry, value: StaticDecode<S>);
53
+ static create<S extends TSchema>(schema: S, kv: KV, entry: KvEntry): Promise<Result<TypedKVEntry<S>, ValidationError>>;
54
+ get key(): string;
55
+ /**
56
+ * Watch this KV entry for changes.
57
+ *
58
+ * @param callback - Function called when the entry changes
59
+ * @param opts - Watch options (e.g., includeDeletes)
60
+ * @returns A function to stop watching
61
+ */
62
+ watch(callback: (event: WatchEvent<S>) => void, opts?: WatchOptions): Promise<() => void>;
63
+ merge(value: Partial<StaticDecode<S>>, vcc?: boolean): Promise<Result<void, KVError | ValidationError>>;
64
+ put(value: StaticDecode<S>, vcc?: boolean): Promise<Result<void, KVError>>;
65
+ delete(vcc?: boolean): Promise<Result<void, KVError>>;
66
+ }
67
+ //# sourceMappingURL=kv.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"kv.d.ts","sourceRoot":"","sources":["../../src/trellis/kv.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,326 @@
1
+ // @ts-nocheck -- svelte-check hits pathological generic instantiation in this file
2
+ import { Kvm } from "@nats-io/kv";
3
+ import { Result } from "@qlever-llc/trellis-result";
4
+ import { merge } from "ts-deepmerge";
5
+ import Value, { ParseError } from "typebox/value";
6
+ import { KVError, ValidationError } from "./errors/index.js";
7
+ import { decodeSubject, escapeKvKey } from "./helpers.js";
8
+ function externalizeValue(value) {
9
+ if (value instanceof Date) {
10
+ return value.toISOString();
11
+ }
12
+ if (Array.isArray(value)) {
13
+ return value.map(externalizeValue);
14
+ }
15
+ if (value !== null && typeof value === "object") {
16
+ const out = {};
17
+ for (const [key, entry] of Object.entries(value)) {
18
+ if (entry !== undefined) {
19
+ out[key] = externalizeValue(entry);
20
+ }
21
+ }
22
+ return out;
23
+ }
24
+ return value;
25
+ }
26
+ function parseExternalValue(schema, value) {
27
+ if (Value.HasCodec(schema)) {
28
+ return Value.Decode(schema, value);
29
+ }
30
+ return Value.Parse(schema, value);
31
+ }
32
+ function serializeValue(schema, value) {
33
+ return JSON.stringify(Value.Parse(schema, externalizeValue(value)));
34
+ }
35
+ function serializeExternalValue(schema, value) {
36
+ return serializeValue(schema, value);
37
+ }
38
+ export class TypedKV {
39
+ constructor(schema, kv) {
40
+ Object.defineProperty(this, "schema", {
41
+ enumerable: true,
42
+ configurable: true,
43
+ writable: true,
44
+ value: schema
45
+ });
46
+ Object.defineProperty(this, "kv", {
47
+ enumerable: true,
48
+ configurable: true,
49
+ writable: true,
50
+ value: kv
51
+ });
52
+ }
53
+ static async open(nats, name, schema, options) {
54
+ try {
55
+ const kvm = new Kvm(nats);
56
+ const kv = options.bindOnly
57
+ ? await kvm.open(name)
58
+ : await kvm.create(name, {
59
+ history: options.history ?? 1,
60
+ ttl: options.ttl ?? 0,
61
+ ...(options.maxValueBytes ? { maxValueSize: options.maxValueBytes } : {}),
62
+ });
63
+ const typedKv = new TypedKV(schema, kv);
64
+ return Result.ok(typedKv);
65
+ }
66
+ catch (cause) {
67
+ return Result.err(new KVError({ operation: "open", cause }));
68
+ }
69
+ }
70
+ async get(key) {
71
+ let s;
72
+ try {
73
+ s = await this.kv.get(escapeKvKey(key));
74
+ }
75
+ catch (cause) {
76
+ return Result.err(new KVError({ operation: "get", cause, context: { key } }));
77
+ }
78
+ if (!s) {
79
+ return Result.err(new KVError({
80
+ operation: "get",
81
+ context: { key, reason: "not found" },
82
+ }));
83
+ }
84
+ return await createTypedKvEntry(this.schema, this.kv, s);
85
+ }
86
+ async create(key, value) {
87
+ const schema = this.schema;
88
+ const rawValue = value;
89
+ // @ts-expect-error svelte-check hits excessive type instantiation here
90
+ const serialized = serializeExternalValue(schema, rawValue);
91
+ try {
92
+ await this.kv.create(escapeKvKey(key), serialized);
93
+ return Result.ok(undefined);
94
+ }
95
+ catch (cause) {
96
+ return Result.err(new KVError({ operation: "create", cause, context: { key } }));
97
+ }
98
+ }
99
+ async put(key, value) {
100
+ const schema = this.schema;
101
+ const rawValue = value;
102
+ // @ts-expect-error svelte-check hits excessive type instantiation here
103
+ const serialized = serializeExternalValue(schema, rawValue);
104
+ try {
105
+ await this.kv.put(escapeKvKey(key), serialized);
106
+ return Result.ok(undefined);
107
+ }
108
+ catch (cause) {
109
+ return Result.err(new KVError({ operation: "put", cause, context: { key } }));
110
+ }
111
+ }
112
+ async delete(key) {
113
+ try {
114
+ await this.kv.delete(escapeKvKey(key));
115
+ return Result.ok(undefined);
116
+ }
117
+ catch (cause) {
118
+ return Result.err(new KVError({ operation: "delete", cause, context: { key } }));
119
+ }
120
+ }
121
+ async keys(filter = ">") {
122
+ try {
123
+ return Result.ok(await this.kv.keys(filter));
124
+ }
125
+ catch (cause) {
126
+ return Result.err(new KVError({ operation: "keys", cause, context: { filter } }));
127
+ }
128
+ }
129
+ async status() {
130
+ try {
131
+ const status = await this.kv.status();
132
+ return Result.ok({ values: status.values });
133
+ }
134
+ catch (cause) {
135
+ return Result.err(new KVError({ operation: "status", cause }));
136
+ }
137
+ }
138
+ }
139
+ export class TypedKVEntry {
140
+ constructor(schema, kv, entry, value) {
141
+ Object.defineProperty(this, "schema", {
142
+ enumerable: true,
143
+ configurable: true,
144
+ writable: true,
145
+ value: schema
146
+ });
147
+ Object.defineProperty(this, "kv", {
148
+ enumerable: true,
149
+ configurable: true,
150
+ writable: true,
151
+ value: kv
152
+ });
153
+ Object.defineProperty(this, "entry", {
154
+ enumerable: true,
155
+ configurable: true,
156
+ writable: true,
157
+ value: entry
158
+ });
159
+ Object.defineProperty(this, "value", {
160
+ enumerable: true,
161
+ configurable: true,
162
+ writable: true,
163
+ value: void 0
164
+ });
165
+ // @ts-expect-error svelte-check hits excessive type instantiation on assignment
166
+ this.value = value;
167
+ }
168
+ static async create(schema, kv, entry) {
169
+ return await createTypedKvEntry(schema, kv, entry);
170
+ }
171
+ get key() {
172
+ return decodeSubject(this.entry.key);
173
+ }
174
+ /**
175
+ * Watch this KV entry for changes.
176
+ *
177
+ * @param callback - Function called when the entry changes
178
+ * @param opts - Watch options (e.g., includeDeletes)
179
+ * @returns A function to stop watching
180
+ */
181
+ async watch(callback, opts) {
182
+ const watcher = await this.kv.watch({
183
+ key: this.entry.key,
184
+ include: opts?.includeDeletes ? "history" : "updates",
185
+ });
186
+ const abortController = new AbortController();
187
+ // Start the async iteration in the background
188
+ (async () => {
189
+ for await (const entry of watcher) {
190
+ if (abortController.signal.aborted)
191
+ break;
192
+ if (entry.operation === "DEL" || entry.operation === "PURGE") {
193
+ if (opts?.includeDeletes) {
194
+ callback({
195
+ type: "delete",
196
+ key: decodeSubject(entry.key),
197
+ revision: entry.revision,
198
+ timestamp: entry.created,
199
+ });
200
+ }
201
+ }
202
+ else {
203
+ let validated;
204
+ try {
205
+ const json = entry.json();
206
+ validated = parseExternalValue(this.schema, json);
207
+ }
208
+ catch {
209
+ try {
210
+ await this.kv.delete(entry.key, {
211
+ previousSeq: entry.revision,
212
+ });
213
+ }
214
+ catch {
215
+ // Best-effort cleanup of invalid entries.
216
+ }
217
+ continue;
218
+ }
219
+ callback({
220
+ type: "update",
221
+ key: decodeSubject(entry.key),
222
+ value: validated,
223
+ revision: entry.revision,
224
+ timestamp: entry.created,
225
+ });
226
+ }
227
+ }
228
+ })();
229
+ return () => {
230
+ abortController.abort();
231
+ watcher.stop();
232
+ };
233
+ }
234
+ async merge(value, vcc) {
235
+ // @ts-expect-error svelte-check hits excessive type instantiation here
236
+ const mergedData = merge(this.value, value);
237
+ const schema = this.schema;
238
+ const mergedRawValue = mergedData;
239
+ // @ts-expect-error svelte-check hits excessive type instantiation here
240
+ const mergeResult = Result.try(() => serializeExternalValue(schema, mergedRawValue));
241
+ if (mergeResult.isErr()) {
242
+ const cause = mergeResult.error.cause;
243
+ if (cause instanceof ParseError) {
244
+ const errors = Value.Errors(schema, externalizeValue(mergedData));
245
+ return Result.err(new ValidationError({ errors, cause }));
246
+ }
247
+ return Result.err(new KVError({ operation: "merge", cause: mergeResult.error, context: { key: this.key } }));
248
+ }
249
+ return this.put(mergedData, vcc);
250
+ }
251
+ async put(value, vcc) {
252
+ const schema = this.schema;
253
+ const serialized = serializeValue(schema, value);
254
+ try {
255
+ await this.kv.put(this.entry.key, serialized, {
256
+ previousSeq: vcc ? this.entry.revision : undefined,
257
+ });
258
+ return Result.ok(undefined);
259
+ }
260
+ catch (cause) {
261
+ return Result.err(new KVError({ operation: "put", cause, context: { key: this.key } }));
262
+ }
263
+ }
264
+ async delete(vcc) {
265
+ try {
266
+ await this.kv.delete(this.entry.key, {
267
+ previousSeq: vcc ? this.entry.revision : undefined,
268
+ });
269
+ return Result.ok(undefined);
270
+ }
271
+ catch (cause) {
272
+ return Result.err(new KVError({ operation: "delete", cause, context: { key: this.key } }));
273
+ }
274
+ }
275
+ }
276
+ async function createTypedKvEntry(schema, kv, entry) {
277
+ async function deleteInvalidEntry(reason) {
278
+ try {
279
+ await kv.delete(entry.key, {
280
+ previousSeq: entry.revision,
281
+ });
282
+ return {
283
+ key: decodeSubject(entry.key),
284
+ revision: entry.revision,
285
+ invalidEntryDeleted: true,
286
+ invalidEntryReason: reason,
287
+ };
288
+ }
289
+ catch (cause) {
290
+ return {
291
+ key: decodeSubject(entry.key),
292
+ revision: entry.revision,
293
+ invalidEntryDeleted: false,
294
+ invalidEntryDeleteError: cause instanceof Error ? cause.message : String(cause),
295
+ invalidEntryReason: reason,
296
+ };
297
+ }
298
+ }
299
+ const jsonResult = Result.try(() => entry.json());
300
+ if (jsonResult.isErr()) {
301
+ const context = await deleteInvalidEntry(`decode failed: ${jsonResult.error.message}`);
302
+ return Result.err(new ValidationError({
303
+ errors: [{ path: "", message: `Failed to decode KV value: ${jsonResult.error.message}` }],
304
+ cause: jsonResult.error,
305
+ context,
306
+ }));
307
+ }
308
+ const json = jsonResult.take();
309
+ const parseResult = Result.try(() => parseExternalValue(schema, json));
310
+ if (parseResult.isErr()) {
311
+ const cause = parseResult.error.cause;
312
+ if (cause instanceof ParseError) {
313
+ const errors = Value.Errors(schema, json);
314
+ const context = await deleteInvalidEntry("schema parse failed");
315
+ return Result.err(new ValidationError({ errors, cause, context }));
316
+ }
317
+ const context = await deleteInvalidEntry(parseResult.error.message);
318
+ return Result.err(new ValidationError({
319
+ errors: [{ path: "", message: parseResult.error.message }],
320
+ cause: parseResult.error,
321
+ context,
322
+ }));
323
+ }
324
+ const typedEntry = new TypedKVEntry(schema, kv, entry, parseResult.take());
325
+ return Result.ok(typedEntry);
326
+ }