@pitininja/envious-typebox 6.0.0-beta4
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 +58 -0
- package/dist/common/error.d.ts +21 -0
- package/dist/common/error.js +26 -0
- package/dist/common/error.js.map +1 -0
- package/dist/resolvers/typebox/src/index.d.ts +11 -0
- package/dist/resolvers/typebox/src/index.js +100 -0
- package/dist/resolvers/typebox/src/index.js.map +1 -0
- package/package.json +22 -0
package/README.md
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# Envious Typebox resolver
|
|
2
|
+
|
|
3
|
+
[](https://badge.fury.io/js/@pitininja%2Fenvious-typebox)
|
|
4
|
+
|
|
5
|
+
> Only Typebox v1 or superior is supported
|
|
6
|
+
|
|
7
|
+
- [Install](#install)
|
|
8
|
+
- [Usage](#usage)
|
|
9
|
+
- [Formats](#formats)
|
|
10
|
+
|
|
11
|
+
## Install
|
|
12
|
+
|
|
13
|
+
```shell
|
|
14
|
+
npm i @pitininja/envious-typebox
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Usage
|
|
18
|
+
|
|
19
|
+
```typescript
|
|
20
|
+
import { envious } from '@pitininja/envious';
|
|
21
|
+
import { typeboxResolver } from '@pitininja/envious-typebox';
|
|
22
|
+
import { Type } from '@sinclair/typebox';
|
|
23
|
+
|
|
24
|
+
const env = envious({
|
|
25
|
+
resolver: typeboxResolver({
|
|
26
|
+
schema: Type.Object({
|
|
27
|
+
STRING_VAR: Type.String(),
|
|
28
|
+
NUMBER_VAR: Type.Integer(),
|
|
29
|
+
BOOLEAN_VAR_WITH_DEFAULT: Type.Boolean({ default: false }),
|
|
30
|
+
OPTIONAL_VAR: Type.Optional(Type.String())
|
|
31
|
+
})
|
|
32
|
+
})
|
|
33
|
+
});
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Formats
|
|
37
|
+
|
|
38
|
+
String formats can be loaded in the `formats` property of the Typebox resolver options, as an object with the format name as key and a regex or a validation function as value.
|
|
39
|
+
|
|
40
|
+
```typescript
|
|
41
|
+
import { envious } from '@pitininja/envious';
|
|
42
|
+
import { typeboxResolver } from '@pitininja/envious-typebox';
|
|
43
|
+
import { Type } from '@sinclair/typebox';
|
|
44
|
+
import dayjs from 'dayjs';
|
|
45
|
+
|
|
46
|
+
const env = envious({
|
|
47
|
+
resolver: typeboxResolver({
|
|
48
|
+
schema: Type.Object({
|
|
49
|
+
EXAMPLE_URI: Type.String({ format: 'uri' }),
|
|
50
|
+
EXAMPLE_DATE: Type.String({ format: 'date' })
|
|
51
|
+
}),
|
|
52
|
+
formats: {
|
|
53
|
+
uri: /^(?:[a-z][a-z0-9+\-.]*:)(?:\/?\/)?[^\s]*$/i,
|
|
54
|
+
date: (val) => dayjs(val).isValid()
|
|
55
|
+
}
|
|
56
|
+
})
|
|
57
|
+
});
|
|
58
|
+
```
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export type EnviousErrorVariable = {
|
|
2
|
+
name: string;
|
|
3
|
+
messages: string[];
|
|
4
|
+
};
|
|
5
|
+
type EnviousErrorOptions = {
|
|
6
|
+
message?: string;
|
|
7
|
+
variables?: EnviousErrorVariable[];
|
|
8
|
+
};
|
|
9
|
+
export declare class EnviousError extends Error {
|
|
10
|
+
variables: EnviousErrorVariable[];
|
|
11
|
+
constructor({ message, variables }: EnviousErrorOptions);
|
|
12
|
+
}
|
|
13
|
+
type ResolverErrorsToEnviousErrorsOptions<T> = {
|
|
14
|
+
transform: (resolverError: T) => {
|
|
15
|
+
name: string;
|
|
16
|
+
message: string;
|
|
17
|
+
};
|
|
18
|
+
resolverErrors: T[];
|
|
19
|
+
};
|
|
20
|
+
export declare const resolverErrorsToEnviousErrors: <T>({ transform, resolverErrors }: ResolverErrorsToEnviousErrorsOptions<T>) => EnviousErrorVariable[];
|
|
21
|
+
export {};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.resolverErrorsToEnviousErrors = exports.EnviousError = void 0;
|
|
4
|
+
class EnviousError extends Error {
|
|
5
|
+
variables;
|
|
6
|
+
constructor({ message = 'Invalid environment variables', variables = [] }) {
|
|
7
|
+
super(message);
|
|
8
|
+
this.variables = variables;
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
exports.EnviousError = EnviousError;
|
|
12
|
+
const resolverErrorsToEnviousErrors = ({ transform, resolverErrors }) => {
|
|
13
|
+
const enviousErrors = [];
|
|
14
|
+
const validationErrorsMap = new Map();
|
|
15
|
+
for (const resolverError of resolverErrors) {
|
|
16
|
+
const { name, message } = transform(resolverError);
|
|
17
|
+
const errorMessages = validationErrorsMap.get(name);
|
|
18
|
+
validationErrorsMap.set(name, [...(errorMessages ?? []), message]);
|
|
19
|
+
}
|
|
20
|
+
for (const [name, messages] of validationErrorsMap.entries()) {
|
|
21
|
+
enviousErrors.push({ name, messages });
|
|
22
|
+
}
|
|
23
|
+
return enviousErrors;
|
|
24
|
+
};
|
|
25
|
+
exports.resolverErrorsToEnviousErrors = resolverErrorsToEnviousErrors;
|
|
26
|
+
//# sourceMappingURL=error.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"error.js","sourceRoot":"","sources":["../../../../common/error.ts"],"names":[],"mappings":";;;AAUA,kBAA0B,SAAQ,KAAK;IACnC,SAAS,CAAyB;IAClC,YAAY,EACR,OAAO,GAAG,+BAA+B,EACzC,SAAS,GAAG,EAAE,EACI,EAAE;QACpB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;IAAA,CAC9B;CACJ;;AAUM,MAAM,6BAA6B,GAAG,CAAI,EAC7C,SAAS,EACT,cAAc,EACwB,EAAE,EAAE,CAAC;IAC3C,MAAM,aAAa,GAA2B,EAAE,CAAC;IACjD,MAAM,mBAAmB,GAAG,IAAI,GAAG,EAAoB,CAAC;IACxD,KAAK,MAAM,aAAa,IAAI,cAAc,EAAE,CAAC;QACzC,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,SAAS,CAAC,aAAa,CAAC,CAAC;QACnD,MAAM,aAAa,GAAG,mBAAmB,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACpD,mBAAmB,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,aAAa,IAAI,EAAE,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC;IACvE,CAAC;IACD,KAAK,MAAM,CAAC,IAAI,EAAE,QAAQ,CAAC,IAAI,mBAAmB,CAAC,OAAO,EAAE,EAAE,CAAC;QAC3D,aAAa,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAC;IAC3C,CAAC;IACD,OAAO,aAAa,CAAC;AAAA,CACxB,CAAC;AAfW,QAAA,6BAA6B,GAA7B,6BAA6B,CAexC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { Static, TObject } from 'typebox';
|
|
2
|
+
type EnviousTypeboxResolver<T extends TObject> = (env: NodeJS.ProcessEnv) => Static<T>;
|
|
3
|
+
export type EnviousTypeboxFormats = {
|
|
4
|
+
[name: string]: RegExp | ((val: unknown) => boolean);
|
|
5
|
+
};
|
|
6
|
+
export type EnviousTypeboxResolverOptions<T extends TObject> = {
|
|
7
|
+
schema: T;
|
|
8
|
+
formats?: EnviousTypeboxFormats;
|
|
9
|
+
};
|
|
10
|
+
export declare const typeboxResolver: <T extends TObject<import("typebox", { with: { "resolution-mode": "import" } }).TProperties>>({ schema, formats }: EnviousTypeboxResolverOptions<T>) => EnviousTypeboxResolver<T>;
|
|
11
|
+
export {};
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
+
};
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
exports.typeboxResolver = void 0;
|
|
40
|
+
const format_1 = __importDefault(require("typebox/format"));
|
|
41
|
+
const value_1 = __importStar(require("typebox/value"));
|
|
42
|
+
const error_1 = require("../../../common/error");
|
|
43
|
+
const setTypeboxFormats = (formats) => {
|
|
44
|
+
for (const [name, format] of Object.entries(formats)) {
|
|
45
|
+
format_1.default.Set(name, format instanceof RegExp ? (val) => format.test(val) : format);
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
const typeboxErrorsToEnviousErrors = (typeboxErrors) => {
|
|
49
|
+
return (0, error_1.resolverErrorsToEnviousErrors)({
|
|
50
|
+
resolverErrors: typeboxErrors,
|
|
51
|
+
transform: (typeboxError) => {
|
|
52
|
+
const { instancePath, message } = typeboxError;
|
|
53
|
+
return { name: instancePath.replace(/^\//, ''), message };
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
};
|
|
57
|
+
function checkIfObject(val) {
|
|
58
|
+
if (!val || typeof val !== 'object') {
|
|
59
|
+
throw new error_1.EnviousError({
|
|
60
|
+
message: 'Could not parse environment variables'
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
const typeboxResolver = ({ schema, formats }) => {
|
|
65
|
+
return (env) => {
|
|
66
|
+
try {
|
|
67
|
+
if (formats) {
|
|
68
|
+
setTypeboxFormats(formats);
|
|
69
|
+
}
|
|
70
|
+
const clonedEnv = value_1.default.Clone(env);
|
|
71
|
+
// Below we use object assertion and spread because Clean / Default / Convert functions return unknown referenced objects
|
|
72
|
+
const cleaned = value_1.default.Clean(schema, clonedEnv);
|
|
73
|
+
checkIfObject(cleaned);
|
|
74
|
+
const defaulted = value_1.default.Default(schema, { ...cleaned });
|
|
75
|
+
checkIfObject(defaulted);
|
|
76
|
+
const converted = value_1.default.Convert(schema, { ...defaulted });
|
|
77
|
+
checkIfObject(converted);
|
|
78
|
+
const errors = value_1.default.Errors(schema, { ...converted });
|
|
79
|
+
if (errors.length) {
|
|
80
|
+
throw new error_1.EnviousError({
|
|
81
|
+
variables: typeboxErrorsToEnviousErrors(errors)
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
return value_1.default.Repair({
|
|
85
|
+
...schema,
|
|
86
|
+
additionalProperties: false
|
|
87
|
+
}, converted);
|
|
88
|
+
}
|
|
89
|
+
catch (err) {
|
|
90
|
+
if (err instanceof value_1.AssertError) {
|
|
91
|
+
throw new error_1.EnviousError({
|
|
92
|
+
variables: typeboxErrorsToEnviousErrors(err.cause.errors)
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
throw err;
|
|
96
|
+
}
|
|
97
|
+
};
|
|
98
|
+
};
|
|
99
|
+
exports.typeboxResolver = typeboxResolver;
|
|
100
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/index.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@pitininja/envious-typebox",
|
|
3
|
+
"version": "6.0.0-beta4",
|
|
4
|
+
"license": "AGPL-3.0-or-later",
|
|
5
|
+
"homepage": "https://codeberg.org/pitininja/envious",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "https://codeberg.org/pitininja/envious"
|
|
9
|
+
},
|
|
10
|
+
"files": [
|
|
11
|
+
"./dist",
|
|
12
|
+
"./package.json"
|
|
13
|
+
],
|
|
14
|
+
"main": "./dist/index.js",
|
|
15
|
+
"types": "./dist/index.d.ts",
|
|
16
|
+
"scripts": {
|
|
17
|
+
"build": "npx tsgo --build --clean tsconfig.json && npx tsgo -b ./tsconfig.json"
|
|
18
|
+
},
|
|
19
|
+
"dependencies": {
|
|
20
|
+
"typebox": "^1.0.24"
|
|
21
|
+
}
|
|
22
|
+
}
|