@reactionary/core 0.2.9 → 0.2.11

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.
@@ -1,14 +1,11 @@
1
- import { trace } from "@opentelemetry/api";
1
+ import { SpanStatusCode, trace } from "@opentelemetry/api";
2
+ import { z } from "zod";
2
3
  import { getReactionaryMeter } from "../metrics/metrics.js";
3
4
  import { error, success } from "../schemas/result.js";
4
5
  const TRACER_NAME = "@reactionary";
5
6
  const TRACER_VERSION = "0.0.1";
6
- let globalTracer = null;
7
7
  function getTracer() {
8
- if (!globalTracer) {
9
- globalTracer = trace.getTracer(TRACER_NAME, TRACER_VERSION);
10
- }
11
- return globalTracer;
8
+ return trace.getTracer(TRACER_NAME, TRACER_VERSION);
12
9
  }
13
10
  class ReactionaryDecoratorOptions {
14
11
  constructor() {
@@ -33,6 +30,14 @@ class ReactionaryDecoratorOptions {
33
30
  * given query.
34
31
  */
35
32
  this.cacheTimeToLiveInSeconds = 60;
33
+ /**
34
+ * The schema for the input (query or mutation) type, for validation purposes
35
+ */
36
+ this.inputSchema = z.never();
37
+ /**
38
+ * The schema for the primary output type, for validation purposes
39
+ */
40
+ this.outputSchema = z.never();
36
41
  }
37
42
  }
38
43
  function Reactionary(options) {
@@ -61,37 +66,45 @@ function Reactionary(options) {
61
66
  return input;
62
67
  }
63
68
  const cacheKey = this.generateCacheKeyForQuery(scope, input.value);
64
- const fromCache = await this.cache.get(
65
- cacheKey,
66
- options.inputSchema
67
- );
69
+ let fromCache = null;
70
+ if (options.cache) {
71
+ fromCache = await this.cache.get(
72
+ cacheKey,
73
+ options.outputSchema
74
+ );
75
+ }
68
76
  let result;
69
77
  if (!fromCache) {
70
78
  result = await original.apply(this, [input.value]);
71
79
  const r = result;
72
80
  if (r.success) {
73
81
  const dependencyIds = this.generateDependencyIdsForModel(r.value);
74
- this.cache.put(cacheKey, r.value, {
75
- ttlSeconds: configuration.cacheTimeToLiveInSeconds,
76
- dependencyIds
77
- });
82
+ if (options.cache) {
83
+ this.cache.put(cacheKey, r.value, {
84
+ ttlSeconds: configuration.cacheTimeToLiveInSeconds,
85
+ dependencyIds
86
+ });
87
+ }
78
88
  }
79
89
  } else {
80
90
  result = success(fromCache);
81
91
  cacheStatus = "hit";
82
92
  }
83
- const validatedResult = validateOutput(result, configuration.outputSchema);
93
+ const validatedResult = validateOutput(
94
+ result,
95
+ configuration.outputSchema
96
+ );
84
97
  if (validatedResult.success) {
85
98
  validatedResult.meta.cache.hit = !!fromCache;
86
99
  validatedResult.meta.cache.key = cacheKey;
87
100
  }
88
- return result;
101
+ return validatedResult;
89
102
  } catch (err) {
90
- console.error(err);
91
103
  status = "error";
104
+ trace.getActiveSpan()?.setStatus({ code: SpanStatusCode.ERROR, message: errorToString(err) });
92
105
  const result = error({
93
106
  type: "Generic",
94
- message: "REDACTED"
107
+ message: errorToString(err)
95
108
  });
96
109
  return result;
97
110
  } finally {
@@ -159,9 +172,23 @@ async function traceSpan(name, fn) {
159
172
  }
160
173
  });
161
174
  }
175
+ function errorToString(err) {
176
+ if (err instanceof Error) {
177
+ return err.stack ?? err.message;
178
+ }
179
+ if (typeof err === "string") {
180
+ return err;
181
+ }
182
+ try {
183
+ return JSON.stringify(err);
184
+ } catch {
185
+ return String(err);
186
+ }
187
+ }
162
188
  export {
163
189
  Reactionary,
164
190
  ReactionaryDecoratorOptions,
191
+ errorToString,
165
192
  getTracer,
166
193
  traceSpan,
167
194
  validateInput,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@reactionary/core",
3
- "version": "0.2.9",
3
+ "version": "0.2.11",
4
4
  "main": "index.js",
5
5
  "types": "src/index.d.ts",
6
6
  "dependencies": {
@@ -1,5 +1,5 @@
1
1
  import type { Tracer } from '@opentelemetry/api';
2
- import type { z } from 'zod';
2
+ import { z } from 'zod';
3
3
  import type { BaseProvider } from '../providers/index.js';
4
4
  import { type Result } from '../schemas/result.js';
5
5
  export declare function getTracer(): Tracer;
@@ -32,11 +32,11 @@ export declare class ReactionaryDecoratorOptions {
32
32
  /**
33
33
  * The schema for the input (query or mutation) type, for validation purposes
34
34
  */
35
- inputSchema?: z.ZodType;
35
+ inputSchema: z.ZodType;
36
36
  /**
37
37
  * The schema for the primary output type, for validation purposes
38
38
  */
39
- outputSchema?: z.ZodType;
39
+ outputSchema: z.ZodType;
40
40
  }
41
41
  /**
42
42
  * Decorator for provider functions to provide functionality such as caching, tracing and type-checked
@@ -57,3 +57,8 @@ export declare function validateOutput(output: Result<unknown>, schema: z.ZodTyp
57
57
  * traced span for OTEL handling.
58
58
  */
59
59
  export declare function traceSpan<T>(name: string, fn: () => Promise<T> | T): Promise<T>;
60
+ /**
61
+ * Utility function for converting a caught error to a plain
62
+ * string for reporting back.
63
+ */
64
+ export declare function errorToString(err: unknown): string;
@@ -19,7 +19,9 @@ export type Fail<E> = {
19
19
  trace: string;
20
20
  };
21
21
  };
22
- export type Result<T, E = Error> = Ok<T> | Fail<E>;
22
+ export type Result<T, E = {
23
+ type: string;
24
+ }> = Ok<T> | Fail<E>;
23
25
  /**
24
26
  * Utility function for asserting and unwrapping the value of a success.
25
27
  * It is an assert, so treat it as such (similar to any unwrap, assert or similar function).