@showwhat/openfeature 1.0.1 → 2.1.0
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.
- package/README.md +3 -1
- package/dist/index.d.ts +3 -4
- package/dist/index.js +36 -25
- package/dist/index.js.map +1 -1
- package/package.json +8 -8
package/README.md
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
# @showwhat/openfeature
|
|
2
2
|
|
|
3
|
-
[OpenFeature](https://openfeature.dev/) provider for **showwhat
|
|
3
|
+
[OpenFeature](https://openfeature.dev/) provider for **showwhat**.
|
|
4
|
+
|
|
5
|
+
Bridge showwhat's rule engine to the standard OpenFeature Server SDK. Evaluate flags and config through OpenFeature clients using showwhat definitions.
|
|
4
6
|
|
|
5
7
|
## Installation
|
|
6
8
|
|
package/dist/index.d.ts
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import { Provider, EvaluationContext, ResolutionDetails, JsonValue } from '@openfeature/server-sdk';
|
|
2
|
-
import { DefinitionReader,
|
|
2
|
+
import { ShowWhatOptions, DefinitionReader, Dependencies, Logger, Context } from 'showwhat';
|
|
3
3
|
|
|
4
|
-
type ShowwhatProviderOptions = {
|
|
4
|
+
type ShowwhatProviderOptions = Omit<ShowWhatOptions, "data"> & {
|
|
5
5
|
data: DefinitionReader;
|
|
6
|
-
|
|
7
|
-
logger?: Logger;
|
|
6
|
+
deps?: Dependencies;
|
|
8
7
|
};
|
|
9
8
|
declare class ShowwhatProvider implements Provider {
|
|
10
9
|
#private;
|
package/dist/index.js
CHANGED
|
@@ -76,29 +76,28 @@ function mapShowwhatError(error) {
|
|
|
76
76
|
return { errorCode: ErrorCode.GENERAL, errorMessage: error.message };
|
|
77
77
|
}
|
|
78
78
|
const message = error instanceof Error ? error.message : String(error);
|
|
79
|
-
return {
|
|
79
|
+
return {
|
|
80
|
+
errorCode: ErrorCode.GENERAL,
|
|
81
|
+
errorMessage: message
|
|
82
|
+
};
|
|
80
83
|
}
|
|
81
84
|
|
|
82
85
|
// src/provider.ts
|
|
83
86
|
var ShowwhatProvider = class {
|
|
84
87
|
metadata = { name: "showwhat" };
|
|
85
88
|
runsOn = "server";
|
|
86
|
-
#
|
|
87
|
-
#evaluators;
|
|
88
|
-
#logger;
|
|
89
|
+
#options;
|
|
89
90
|
constructor(options) {
|
|
90
|
-
this.#
|
|
91
|
-
this.#evaluators = options.evaluators;
|
|
92
|
-
this.#logger = options.logger;
|
|
91
|
+
this.#options = options;
|
|
93
92
|
}
|
|
94
93
|
async initialize() {
|
|
95
|
-
if (this.#data.load) {
|
|
96
|
-
await this.#data.load();
|
|
94
|
+
if (this.#options.data.load) {
|
|
95
|
+
await this.#options.data.load();
|
|
97
96
|
}
|
|
98
97
|
}
|
|
99
98
|
async onClose() {
|
|
100
|
-
if (this.#data.close) {
|
|
101
|
-
await this.#data.close();
|
|
99
|
+
if (this.#options.data.close) {
|
|
100
|
+
await this.#options.data.close();
|
|
102
101
|
}
|
|
103
102
|
}
|
|
104
103
|
async resolveBooleanEvaluation(flagKey, defaultValue, context) {
|
|
@@ -124,18 +123,25 @@ var ShowwhatProvider = class {
|
|
|
124
123
|
);
|
|
125
124
|
}
|
|
126
125
|
async #resolve(flagKey, defaultValue, evalCtx, typeGuard) {
|
|
127
|
-
const ctx = toShowwhatContext(evalCtx, this.#logger);
|
|
126
|
+
const ctx = toShowwhatContext(evalCtx, this.#options.logger);
|
|
128
127
|
try {
|
|
129
|
-
const
|
|
130
|
-
|
|
128
|
+
const results = await showwhat({
|
|
129
|
+
keys: [flagKey],
|
|
131
130
|
context: ctx,
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
evaluators: this.#evaluators,
|
|
135
|
-
logger: this.#logger
|
|
136
|
-
}
|
|
131
|
+
deps: this.#options.deps,
|
|
132
|
+
options: this.#options
|
|
137
133
|
});
|
|
138
|
-
const
|
|
134
|
+
const entry = results[flagKey];
|
|
135
|
+
if (!entry.success) {
|
|
136
|
+
const mapped = mapShowwhatError(entry.error);
|
|
137
|
+
return {
|
|
138
|
+
value: defaultValue,
|
|
139
|
+
reason: StandardResolutionReasons.ERROR,
|
|
140
|
+
errorCode: mapped.errorCode,
|
|
141
|
+
errorMessage: mapped.errorMessage
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
const value = entry.value;
|
|
139
145
|
if (!typeGuard(value)) {
|
|
140
146
|
return {
|
|
141
147
|
value: defaultValue,
|
|
@@ -144,10 +150,10 @@ var ShowwhatProvider = class {
|
|
|
144
150
|
errorMessage: `Flag "${flagKey}" resolved to ${typeof value}, expected a compatible type`
|
|
145
151
|
};
|
|
146
152
|
}
|
|
147
|
-
const hasConditions =
|
|
153
|
+
const hasConditions = entry.meta.variation.conditionCount > 0;
|
|
148
154
|
return {
|
|
149
155
|
value,
|
|
150
|
-
variant:
|
|
156
|
+
variant: entry.meta.variation.id ?? String(entry.meta.variation.index),
|
|
151
157
|
reason: hasConditions ? StandardResolutionReasons.TARGETING_MATCH : StandardResolutionReasons.STATIC
|
|
152
158
|
};
|
|
153
159
|
} catch (error) {
|
|
@@ -162,10 +168,15 @@ var ShowwhatProvider = class {
|
|
|
162
168
|
}
|
|
163
169
|
};
|
|
164
170
|
function isJsonValue(value) {
|
|
165
|
-
if (value === null)
|
|
166
|
-
if (typeof value === "string" || typeof value === "number" || typeof value === "boolean")
|
|
171
|
+
if (value === null) {
|
|
167
172
|
return true;
|
|
168
|
-
|
|
173
|
+
}
|
|
174
|
+
if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
|
|
175
|
+
return true;
|
|
176
|
+
}
|
|
177
|
+
if (Array.isArray(value)) {
|
|
178
|
+
return value.every(isJsonValue);
|
|
179
|
+
}
|
|
169
180
|
if (typeof value === "object") {
|
|
170
181
|
return Object.values(value).every(isJsonValue);
|
|
171
182
|
}
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/provider.ts","../src/context.ts","../src/errors.ts"],"sourcesContent":["import type {\n EvaluationContext,\n JsonValue,\n Provider,\n ResolutionDetails,\n} from \"@openfeature/server-sdk\";\nimport { ErrorCode, StandardResolutionReasons } from \"@openfeature/server-sdk\";\nimport type { ConditionEvaluators, DefinitionReader, Logger } from \"showwhat\";\nimport { showwhat } from \"showwhat\";\nimport { toShowwhatContext } from \"./context.js\";\nimport { mapShowwhatError } from \"./errors.js\";\n\nexport type ShowwhatProviderOptions = {\n data: DefinitionReader;\n evaluators?: ConditionEvaluators;\n logger?: Logger;\n};\n\nexport class ShowwhatProvider implements Provider {\n readonly metadata = { name: \"showwhat\" } as const;\n readonly runsOn = \"server\" as const;\n\n #data: DefinitionReader;\n #evaluators: ConditionEvaluators | undefined;\n #logger: Logger | undefined;\n\n constructor(options: ShowwhatProviderOptions) {\n this.#data = options.data;\n this.#evaluators = options.evaluators;\n this.#logger = options.logger;\n }\n\n async initialize(): Promise<void> {\n if (this.#data.load) {\n await this.#data.load();\n }\n }\n\n async onClose(): Promise<void> {\n if (this.#data.close) {\n await this.#data.close();\n }\n }\n\n async resolveBooleanEvaluation(\n flagKey: string,\n defaultValue: boolean,\n context: EvaluationContext,\n ): Promise<ResolutionDetails<boolean>> {\n return this.#resolve(\n flagKey,\n defaultValue,\n context,\n (v): v is boolean => typeof v === \"boolean\",\n );\n }\n\n async resolveStringEvaluation(\n flagKey: string,\n defaultValue: string,\n context: EvaluationContext,\n ): Promise<ResolutionDetails<string>> {\n return this.#resolve(flagKey, defaultValue, context, (v): v is string => typeof v === \"string\");\n }\n\n async resolveNumberEvaluation(\n flagKey: string,\n defaultValue: number,\n context: EvaluationContext,\n ): Promise<ResolutionDetails<number>> {\n return this.#resolve(flagKey, defaultValue, context, (v): v is number => typeof v === \"number\");\n }\n\n async resolveObjectEvaluation<T extends JsonValue>(\n flagKey: string,\n defaultValue: T,\n context: EvaluationContext,\n ): Promise<ResolutionDetails<T>> {\n return this.#resolve(\n flagKey,\n defaultValue,\n context,\n isJsonValue as (value: unknown) => value is T,\n );\n }\n\n async #resolve<T>(\n flagKey: string,\n defaultValue: T,\n evalCtx: EvaluationContext,\n typeGuard: (value: unknown) => value is T,\n ): Promise<ResolutionDetails<T>> {\n const ctx = toShowwhatContext(evalCtx, this.#logger);\n\n try {\n const resolution = await showwhat({\n key: flagKey,\n context: ctx,\n options: {\n data: this.#data,\n evaluators: this.#evaluators,\n logger: this.#logger,\n },\n });\n\n const value = resolution.value;\n\n if (!typeGuard(value)) {\n return {\n value: defaultValue,\n reason: StandardResolutionReasons.ERROR,\n errorCode: ErrorCode.TYPE_MISMATCH,\n errorMessage: `Flag \"${flagKey}\" resolved to ${typeof value}, expected a compatible type`,\n };\n }\n\n const hasConditions = resolution.meta.variation.conditionCount > 0;\n\n return {\n value,\n variant: resolution.meta.variation.id ?? String(resolution.meta.variation.index),\n reason: hasConditions\n ? StandardResolutionReasons.TARGETING_MATCH\n : StandardResolutionReasons.STATIC,\n };\n } catch (error: unknown) {\n const mapped = mapShowwhatError(error);\n return {\n value: defaultValue,\n reason: StandardResolutionReasons.ERROR,\n errorCode: mapped.errorCode,\n errorMessage: mapped.errorMessage,\n };\n }\n }\n}\n\nfunction isJsonValue(value: unknown): value is JsonValue {\n if (value === null) return true;\n if (typeof value === \"string\" || typeof value === \"number\" || typeof value === \"boolean\")\n return true;\n if (Array.isArray(value)) return value.every(isJsonValue);\n if (typeof value === \"object\") {\n return Object.values(value as Record<string, unknown>).every(isJsonValue);\n }\n return false;\n}\n","import type { EvaluationContext, EvaluationContextValue } from \"@openfeature/server-sdk\";\nimport type { Context, ContextValue, Logger } from \"showwhat\";\nimport { noopLogger } from \"showwhat\";\n\n/**\n * Converts an OpenFeature EvaluationContextValue to a showwhat ContextValue.\n *\n * Primitives, primitive arrays, and nested objects of primitives are preserved.\n * Date and null values are not representable in JSON/YAML and are dropped.\n */\nfunction convertValue(value: EvaluationContextValue): ContextValue | undefined {\n if (typeof value === \"string\" || typeof value === \"number\" || typeof value === \"boolean\") {\n return value;\n }\n\n if (Array.isArray(value)) {\n const result: (string | number | boolean)[] = [];\n for (const item of value) {\n if (typeof item === \"string\" || typeof item === \"number\" || typeof item === \"boolean\") {\n result.push(item);\n } else {\n return undefined;\n }\n }\n return result;\n }\n\n if (value !== null && typeof value === \"object\" && !(value instanceof Date)) {\n const result: Record<string, ContextValue> = {};\n for (const [k, v] of Object.entries(value)) {\n const converted = convertValue(v);\n if (converted === undefined) {\n return undefined;\n }\n result[k] = converted;\n }\n return result;\n }\n\n return undefined;\n}\n\n/**\n * Converts an OpenFeature EvaluationContext into a showwhat Context.\n *\n * Primitives, primitive arrays, and nested objects of primitives are preserved.\n * Date and null values are dropped with a warning.\n */\nexport function toShowwhatContext(evalCtx: EvaluationContext, logger?: Logger): Context {\n const log = logger ?? noopLogger;\n const ctx: Context = {};\n\n for (const [key, value] of Object.entries(evalCtx)) {\n const converted = convertValue(value);\n if (converted !== undefined) {\n ctx[key] = converted;\n } else {\n log.warn(\"dropped unsupported context key\", { key });\n }\n }\n\n return ctx;\n}\n","import { ErrorCode } from \"@openfeature/server-sdk\";\nimport {\n DefinitionNotFoundError,\n DefinitionInactiveError,\n VariationNotFoundError,\n ValidationError,\n DataError,\n ShowwhatError,\n} from \"showwhat\";\n\ntype ErrorMapping = {\n errorCode: ErrorCode;\n errorMessage: string;\n};\n\nexport function mapShowwhatError(error: unknown): ErrorMapping {\n if (error instanceof DefinitionNotFoundError) {\n return { errorCode: ErrorCode.FLAG_NOT_FOUND, errorMessage: error.message };\n }\n\n if (error instanceof DefinitionInactiveError) {\n return { errorCode: ErrorCode.FLAG_NOT_FOUND, errorMessage: error.message };\n }\n\n if (error instanceof VariationNotFoundError) {\n return { errorCode: ErrorCode.GENERAL, errorMessage: error.message };\n }\n\n if (error instanceof ValidationError) {\n return { errorCode: ErrorCode.INVALID_CONTEXT, errorMessage: error.message };\n }\n\n if (error instanceof DataError) {\n return { errorCode: ErrorCode.GENERAL, errorMessage: error.message };\n }\n\n if (error instanceof ShowwhatError) {\n return { errorCode: ErrorCode.GENERAL, errorMessage: error.message };\n }\n\n const message = error instanceof Error ? error.message : String(error);\n return { errorCode: ErrorCode.GENERAL, errorMessage: message };\n}\n"],"mappings":"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","names":["ErrorCode","ErrorCode"]}
|
|
1
|
+
{"version":3,"sources":["../src/provider.ts","../src/context.ts","../src/errors.ts"],"sourcesContent":["import type {\n EvaluationContext,\n JsonValue,\n Provider,\n ResolutionDetails,\n} from \"@openfeature/server-sdk\";\nimport { ErrorCode, StandardResolutionReasons } from \"@openfeature/server-sdk\";\nimport type { DefinitionReader, Dependencies, ShowWhatOptions } from \"showwhat\";\nimport { showwhat } from \"showwhat\";\nimport { toShowwhatContext } from \"./context.js\";\nimport { mapShowwhatError } from \"./errors.js\";\n\nexport type ShowwhatProviderOptions = Omit<ShowWhatOptions, \"data\"> & {\n data: DefinitionReader;\n deps?: Dependencies;\n};\n\nexport class ShowwhatProvider implements Provider {\n readonly metadata = { name: \"showwhat\" } as const;\n readonly runsOn = \"server\" as const;\n\n #options: ShowwhatProviderOptions;\n\n constructor(options: ShowwhatProviderOptions) {\n this.#options = options;\n }\n\n async initialize(): Promise<void> {\n if (this.#options.data.load) {\n await this.#options.data.load();\n }\n }\n\n async onClose(): Promise<void> {\n if (this.#options.data.close) {\n await this.#options.data.close();\n }\n }\n\n async resolveBooleanEvaluation(\n flagKey: string,\n defaultValue: boolean,\n context: EvaluationContext,\n ): Promise<ResolutionDetails<boolean>> {\n return this.#resolve(\n flagKey,\n defaultValue,\n context,\n (v): v is boolean => typeof v === \"boolean\",\n );\n }\n\n async resolveStringEvaluation(\n flagKey: string,\n defaultValue: string,\n context: EvaluationContext,\n ): Promise<ResolutionDetails<string>> {\n return this.#resolve(flagKey, defaultValue, context, (v): v is string => typeof v === \"string\");\n }\n\n async resolveNumberEvaluation(\n flagKey: string,\n defaultValue: number,\n context: EvaluationContext,\n ): Promise<ResolutionDetails<number>> {\n return this.#resolve(flagKey, defaultValue, context, (v): v is number => typeof v === \"number\");\n }\n\n async resolveObjectEvaluation<T extends JsonValue>(\n flagKey: string,\n defaultValue: T,\n context: EvaluationContext,\n ): Promise<ResolutionDetails<T>> {\n return this.#resolve(\n flagKey,\n defaultValue,\n context,\n isJsonValue as (value: unknown) => value is T,\n );\n }\n\n async #resolve<T>(\n flagKey: string,\n defaultValue: T,\n evalCtx: EvaluationContext,\n typeGuard: (value: unknown) => value is T,\n ): Promise<ResolutionDetails<T>> {\n const ctx = toShowwhatContext(evalCtx, this.#options.logger);\n\n try {\n const results = await showwhat({\n keys: [flagKey],\n context: ctx,\n deps: this.#options.deps,\n options: this.#options,\n });\n\n const entry = results[flagKey];\n\n if (!entry.success) {\n const mapped = mapShowwhatError(entry.error);\n return {\n value: defaultValue,\n reason: StandardResolutionReasons.ERROR,\n errorCode: mapped.errorCode,\n errorMessage: mapped.errorMessage,\n };\n }\n\n const value = entry.value;\n\n if (!typeGuard(value)) {\n return {\n value: defaultValue,\n reason: StandardResolutionReasons.ERROR,\n errorCode: ErrorCode.TYPE_MISMATCH,\n errorMessage: `Flag \"${flagKey}\" resolved to ${typeof value}, expected a compatible type`,\n };\n }\n\n const hasConditions = entry.meta.variation.conditionCount > 0;\n\n return {\n value,\n variant: entry.meta.variation.id ?? String(entry.meta.variation.index),\n reason: hasConditions\n ? StandardResolutionReasons.TARGETING_MATCH\n : StandardResolutionReasons.STATIC,\n };\n } catch (error: unknown) {\n const mapped = mapShowwhatError(error);\n return {\n value: defaultValue,\n reason: StandardResolutionReasons.ERROR,\n errorCode: mapped.errorCode,\n errorMessage: mapped.errorMessage,\n };\n }\n }\n}\n\nfunction isJsonValue(value: unknown): value is JsonValue {\n if (value === null) {\n return true;\n }\n\n if (typeof value === \"string\" || typeof value === \"number\" || typeof value === \"boolean\") {\n return true;\n }\n\n if (Array.isArray(value)) {\n return value.every(isJsonValue);\n }\n\n if (typeof value === \"object\") {\n return Object.values(value as Record<string, unknown>).every(isJsonValue);\n }\n\n return false;\n}\n","import type { EvaluationContext, EvaluationContextValue } from \"@openfeature/server-sdk\";\nimport type { Context, ContextValue, Logger } from \"showwhat\";\nimport { noopLogger } from \"showwhat\";\n\n/**\n * Converts an OpenFeature EvaluationContextValue to a showwhat ContextValue.\n *\n * Primitives, primitive arrays, and nested objects of primitives are preserved.\n * Date and null values are not representable in JSON/YAML and are dropped.\n */\nfunction convertValue(value: EvaluationContextValue): ContextValue | undefined {\n if (typeof value === \"string\" || typeof value === \"number\" || typeof value === \"boolean\") {\n return value;\n }\n\n if (Array.isArray(value)) {\n const result: (string | number | boolean)[] = [];\n for (const item of value) {\n if (typeof item === \"string\" || typeof item === \"number\" || typeof item === \"boolean\") {\n result.push(item);\n } else {\n return undefined;\n }\n }\n\n return result;\n }\n\n if (value !== null && typeof value === \"object\" && !(value instanceof Date)) {\n const result: Record<string, ContextValue> = {};\n for (const [k, v] of Object.entries(value)) {\n const converted = convertValue(v);\n\n if (converted === undefined) {\n return undefined;\n }\n\n result[k] = converted;\n }\n return result;\n }\n\n return undefined;\n}\n\n/**\n * Converts an OpenFeature EvaluationContext into a showwhat Context.\n *\n * Primitives, primitive arrays, and nested objects of primitives are preserved.\n * Date and null values are dropped with a warning.\n */\nexport function toShowwhatContext(evalCtx: EvaluationContext, logger?: Logger): Context {\n const log = logger ?? noopLogger;\n const ctx: Context = {};\n\n for (const [key, value] of Object.entries(evalCtx)) {\n const converted = convertValue(value);\n\n if (converted !== undefined) {\n ctx[key] = converted;\n } else {\n log.warn(\"dropped unsupported context key\", { key });\n }\n }\n\n return ctx;\n}\n","import { ErrorCode } from \"@openfeature/server-sdk\";\nimport {\n DefinitionNotFoundError,\n DefinitionInactiveError,\n VariationNotFoundError,\n ValidationError,\n DataError,\n ShowwhatError,\n} from \"showwhat\";\n\ntype ErrorMapping = {\n errorCode: ErrorCode;\n errorMessage: string;\n};\n\nexport function mapShowwhatError(error: unknown): ErrorMapping {\n if (error instanceof DefinitionNotFoundError) {\n return { errorCode: ErrorCode.FLAG_NOT_FOUND, errorMessage: error.message };\n }\n\n if (error instanceof DefinitionInactiveError) {\n return { errorCode: ErrorCode.FLAG_NOT_FOUND, errorMessage: error.message };\n }\n\n if (error instanceof VariationNotFoundError) {\n return { errorCode: ErrorCode.GENERAL, errorMessage: error.message };\n }\n\n if (error instanceof ValidationError) {\n return { errorCode: ErrorCode.INVALID_CONTEXT, errorMessage: error.message };\n }\n\n if (error instanceof DataError) {\n return { errorCode: ErrorCode.GENERAL, errorMessage: error.message };\n }\n\n if (error instanceof ShowwhatError) {\n return { errorCode: ErrorCode.GENERAL, errorMessage: error.message };\n }\n\n const message = error instanceof Error ? error.message : String(error);\n\n return {\n errorCode: ErrorCode.GENERAL,\n errorMessage: message,\n };\n}\n"],"mappings":"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","names":["ErrorCode","ErrorCode"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@showwhat/openfeature",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "2.1.0",
|
|
4
4
|
"description": "OpenFeature provider for showwhat library",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"feature-flags",
|
|
@@ -35,18 +35,18 @@
|
|
|
35
35
|
"dist"
|
|
36
36
|
],
|
|
37
37
|
"dependencies": {
|
|
38
|
-
"showwhat": "1.0
|
|
38
|
+
"showwhat": "2.1.0"
|
|
39
39
|
},
|
|
40
40
|
"peerDependencies": {
|
|
41
41
|
"@openfeature/server-sdk": "^1.0.0"
|
|
42
42
|
},
|
|
43
43
|
"devDependencies": {
|
|
44
|
-
"@openfeature/server-sdk": "^1.20.
|
|
45
|
-
"@types/node": "^25.
|
|
46
|
-
"@vitest/coverage-v8": "^4.
|
|
47
|
-
"tsup": "^8.
|
|
48
|
-
"typescript": "^5.
|
|
49
|
-
"vitest": "^4.
|
|
44
|
+
"@openfeature/server-sdk": "^1.20.2",
|
|
45
|
+
"@types/node": "^25.5.0",
|
|
46
|
+
"@vitest/coverage-v8": "^4.1.4",
|
|
47
|
+
"tsup": "^8.5.1",
|
|
48
|
+
"typescript": "^5.9.3",
|
|
49
|
+
"vitest": "^4.1.4"
|
|
50
50
|
},
|
|
51
51
|
"scripts": {
|
|
52
52
|
"build": "tsup",
|