@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
|
-
|
|
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
|
-
|
|
65
|
-
|
|
66
|
-
|
|
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
|
-
|
|
75
|
-
|
|
76
|
-
|
|
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(
|
|
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
|
|
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:
|
|
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,5 +1,5 @@
|
|
|
1
1
|
import type { Tracer } from '@opentelemetry/api';
|
|
2
|
-
import
|
|
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
|
|
35
|
+
inputSchema: z.ZodType;
|
|
36
36
|
/**
|
|
37
37
|
* The schema for the primary output type, for validation purposes
|
|
38
38
|
*/
|
|
39
|
-
outputSchema
|
|
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;
|
package/src/schemas/result.d.ts
CHANGED
|
@@ -19,7 +19,9 @@ export type Fail<E> = {
|
|
|
19
19
|
trace: string;
|
|
20
20
|
};
|
|
21
21
|
};
|
|
22
|
-
export type Result<T, 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).
|