@epsilon-asi/foundation 0.0.1-rc3 → 0.0.2

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.
@@ -0,0 +1,164 @@
1
+ import type { ClassDecoratorDefinition, Constructor, DecoratorRegistry, PropertyDecoratorDefinition, RegistryMetadataSnapshot } from '../factory';
2
+ export type EnvPrimitive = string | number | boolean;
3
+ export type EnvPrimitiveOrUndefined = EnvPrimitive | undefined;
4
+ export type EnvBooleanTrueValue = 'true' | '1' | 'yes' | 'y' | 'on';
5
+ export type EnvBooleanFalseValue = 'false' | '0' | 'no' | 'n' | 'off';
6
+ export type EnvValueKind = 'string' | 'number' | 'boolean';
7
+ export interface EnvConfigMetadata {
8
+ /**
9
+ * Optional prefix applied to every variable lookup.
10
+ *
11
+ * Example:
12
+ * prefix: 'APP_'
13
+ * @EnvVar.string('PORT')
14
+ * final lookup key: APP_PORT
15
+ */
16
+ prefix?: string;
17
+ /** Optional human-readable description for docs/debug output. */
18
+ description?: string;
19
+ }
20
+ export type StringEnvVarMetadata = {
21
+ type: 'string';
22
+ name?: string;
23
+ required?: boolean;
24
+ default?: string;
25
+ description?: string;
26
+ };
27
+ export type NumberEnvVarMetadata = {
28
+ type: 'number';
29
+ name?: string;
30
+ required?: boolean;
31
+ default?: number;
32
+ min?: number;
33
+ max?: number;
34
+ integer?: boolean;
35
+ description?: string;
36
+ };
37
+ export type BooleanEnvVarMetadata = {
38
+ type: 'boolean';
39
+ name?: string;
40
+ required?: boolean;
41
+ default?: boolean;
42
+ description?: string;
43
+ };
44
+ export type EnvVarMetadata = StringEnvVarMetadata | NumberEnvVarMetadata | BooleanEnvVarMetadata;
45
+ export type EnvDecoratorSchema = {
46
+ class: {
47
+ envConfig: ClassDecoratorDefinition<EnvConfigMetadata | undefined>;
48
+ };
49
+ property: {
50
+ envVar: PropertyDecoratorDefinition<EnvVarMetadata, EnvPrimitiveOrUndefined>;
51
+ };
52
+ method: {};
53
+ accessor: {};
54
+ };
55
+ export type EnvSource = Record<string, string | undefined>;
56
+ export interface LoadEnvOptions {
57
+ /**
58
+ * Defaults to globalThis.process.env when available.
59
+ * Pass this in tests to avoid mutating or depending on the real process env.
60
+ */
61
+ source?: EnvSource;
62
+ /**
63
+ * Whether @EnvVar fields must be static.
64
+ *
65
+ * Defaults to true because loadEnv mutates the class constructor in place.
66
+ */
67
+ requireStatic?: boolean;
68
+ /**
69
+ * Whether empty strings and whitespace-only strings should be treated as missing.
70
+ *
71
+ * Defaults to true.
72
+ */
73
+ emptyStringAsMissing?: boolean;
74
+ /**
75
+ * Whether inherited metadata should be loaded.
76
+ *
77
+ * Defaults to true.
78
+ */
79
+ includeInherited?: boolean;
80
+ }
81
+ export interface DescribeEnvOptions {
82
+ /** Defaults to true. */
83
+ includeInherited?: boolean;
84
+ }
85
+ export interface EnvVariableDefinition {
86
+ readonly propertyName: string;
87
+ readonly envName: string;
88
+ readonly static: boolean;
89
+ readonly private: boolean;
90
+ readonly metadata: EnvVarMetadata;
91
+ }
92
+ export interface EnvLoadResult<TClass extends Constructor> {
93
+ readonly target: TClass;
94
+ readonly definitions: readonly EnvVariableDefinition[];
95
+ readonly values: Readonly<Record<string, EnvPrimitiveOrUndefined>>;
96
+ readonly snapshot: RegistryMetadataSnapshot;
97
+ }
98
+ export declare class EnvParseError extends Error {
99
+ readonly envName?: string;
100
+ readonly propertyName?: string;
101
+ constructor(message: string, details?: {
102
+ envName?: string;
103
+ propertyName?: string;
104
+ });
105
+ }
106
+ export interface EnvConfigDecorator {
107
+ (metadata?: EnvConfigMetadata): <TClass extends Constructor>(value: TClass, context: ClassDecoratorContext<TClass>) => void;
108
+ }
109
+ export interface EnvVarDecoratorApi {
110
+ /**
111
+ * Generic form:
112
+ *
113
+ * @EnvVar({ name: 'PORT', type: 'number' })
114
+ * static port: number;
115
+ */
116
+ (metadata: StringEnvVarMetadata): (value: undefined, context: ClassFieldDecoratorContext<any, string | undefined>) => void;
117
+ (metadata: NumberEnvVarMetadata): (value: undefined, context: ClassFieldDecoratorContext<any, number | undefined>) => void;
118
+ (metadata: BooleanEnvVarMetadata): (value: undefined, context: ClassFieldDecoratorContext<any, boolean | undefined>) => void;
119
+ /**
120
+ * @EnvVar.string('API_KEY')
121
+ * static apiKey: string;
122
+ */
123
+ string(name?: string, options?: Omit<StringEnvVarMetadata, 'type' | 'name'>): (value: undefined, context: ClassFieldDecoratorContext<any, string | undefined>) => void;
124
+ /**
125
+ * @EnvVar.number('PORT', { default: 3000, integer: true })
126
+ * static port: number;
127
+ */
128
+ number(name?: string, options?: Omit<NumberEnvVarMetadata, 'type' | 'name'>): (value: undefined, context: ClassFieldDecoratorContext<any, number | undefined>) => void;
129
+ /**
130
+ * @EnvVar.boolean('DEBUG', { default: false })
131
+ * static debug: boolean;
132
+ */
133
+ boolean(name?: string, options?: Omit<BooleanEnvVarMetadata, 'type' | 'name'>): (value: undefined, context: ClassFieldDecoratorContext<any, boolean | undefined>) => void;
134
+ }
135
+ export interface EnvSystem {
136
+ readonly registry: DecoratorRegistry<EnvDecoratorSchema>;
137
+ /** Preferred class decorator name. */
138
+ readonly Env: EnvConfigDecorator;
139
+ /** Alias for Env, for users who prefer a more explicit name. */
140
+ readonly EnvConfig: EnvConfigDecorator;
141
+ readonly EnvVar: EnvVarDecoratorApi;
142
+ /**
143
+ * Mutates the provided class in place by assigning parsed values to static fields.
144
+ */
145
+ loadEnv<TClass extends Constructor>(target: TClass, options?: LoadEnvOptions): EnvLoadResult<TClass>;
146
+ /** Reads env metadata without mutating the class. */
147
+ describeEnv<TClass extends Constructor>(target: TClass, options?: DescribeEnvOptions): readonly EnvVariableDefinition[];
148
+ }
149
+ export declare function createEnvSystem(): EnvSystem;
150
+ export declare function getEnvConfigMetadata(snapshot: RegistryMetadataSnapshot): EnvConfigMetadata | undefined;
151
+ export declare function toEnvKey(propertyName: string): string;
152
+ export declare function parseEnvValue(args: {
153
+ envName: string;
154
+ propertyName: string;
155
+ rawValue: string | undefined;
156
+ metadata: EnvVarMetadata;
157
+ emptyStringAsMissing: boolean;
158
+ }): EnvPrimitiveOrUndefined;
159
+ export declare const envRegistry: DecoratorRegistry<EnvDecoratorSchema>;
160
+ export declare const Env: EnvConfigDecorator;
161
+ export declare const EnvConfig: EnvConfigDecorator;
162
+ export declare const EnvVar: EnvVarDecoratorApi;
163
+ export declare const loadEnv: <TClass extends Constructor>(target: TClass, options?: LoadEnvOptions) => EnvLoadResult<TClass>;
164
+ export declare const describeEnv: <TClass extends Constructor>(target: TClass, options?: DescribeEnvOptions) => readonly EnvVariableDefinition[];
@@ -0,0 +1,223 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.describeEnv = exports.loadEnv = exports.EnvVar = exports.EnvConfig = exports.Env = exports.envRegistry = exports.EnvParseError = void 0;
4
+ exports.createEnvSystem = createEnvSystem;
5
+ exports.getEnvConfigMetadata = getEnvConfigMetadata;
6
+ exports.toEnvKey = toEnvKey;
7
+ exports.parseEnvValue = parseEnvValue;
8
+ const factory_1 = require("../factory");
9
+ class EnvParseError extends Error {
10
+ constructor(message, details = {}) {
11
+ super(message);
12
+ this.name = 'EnvParseError';
13
+ this.envName = details.envName;
14
+ this.propertyName = details.propertyName;
15
+ }
16
+ }
17
+ exports.EnvParseError = EnvParseError;
18
+ function createEnvSystem() {
19
+ const registry = (0, factory_1.createDecoratorRegistry)({
20
+ namespace: 'env',
21
+ });
22
+ const RawEnvConfig = registry.class('envConfig');
23
+ const Env = ((metadata) => {
24
+ return metadata === undefined ? RawEnvConfig() : RawEnvConfig(metadata);
25
+ });
26
+ const EnvConfig = Env;
27
+ /**
28
+ * Broad scoped contract because this system decorates arbitrary env classes.
29
+ * The public EnvVar.string/number/boolean helper return types enforce the actual
30
+ * decorated property type.
31
+ */
32
+ const Scoped = registry.for();
33
+ const RawEnvVar = Scoped.property('envVar');
34
+ const EnvVar = ((metadata) => RawEnvVar(metadata));
35
+ EnvVar.string = (name, options = {}) => {
36
+ return RawEnvVar(Object.assign(Object.assign({}, options), { name, type: 'string' }));
37
+ };
38
+ EnvVar.number = (name, options = {}) => {
39
+ return RawEnvVar(Object.assign(Object.assign({}, options), { name, type: 'number' }));
40
+ };
41
+ EnvVar.boolean = (name, options = {}) => {
42
+ return RawEnvVar(Object.assign(Object.assign({}, options), { name, type: 'boolean' }));
43
+ };
44
+ function describeEnv(target, options = {}) {
45
+ var _a, _b;
46
+ const includeInherited = (_a = options.includeInherited) !== null && _a !== void 0 ? _a : true;
47
+ const snapshot = registry.read(target, { includeInherited });
48
+ const classMetadata = getEnvConfigMetadata(snapshot);
49
+ const prefix = (_b = classMetadata === null || classMetadata === void 0 ? void 0 : classMetadata.prefix) !== null && _b !== void 0 ? _b : '';
50
+ return Object.freeze(snapshot.propertyRecords('envVar').map((record) => {
51
+ var _a;
52
+ if (record.memberName === undefined) {
53
+ throw new EnvParseError('EnvVar metadata record is missing memberName.');
54
+ }
55
+ if (typeof record.memberName === 'symbol') {
56
+ throw new EnvParseError(`EnvVar does not support symbol member keys: ${String(record.memberName)}.`);
57
+ }
58
+ const metadata = record.metadata;
59
+ const propertyName = record.memberName;
60
+ const envName = prefix + ((_a = metadata.name) !== null && _a !== void 0 ? _a : toEnvKey(propertyName));
61
+ return Object.freeze({
62
+ propertyName,
63
+ envName,
64
+ static: record.static,
65
+ private: record.private,
66
+ metadata,
67
+ });
68
+ }));
69
+ }
70
+ function loadEnv(target, options = {}) {
71
+ var _a, _b, _c, _d;
72
+ const source = (_a = options.source) !== null && _a !== void 0 ? _a : getDefaultEnvSource();
73
+ const requireStatic = (_b = options.requireStatic) !== null && _b !== void 0 ? _b : true;
74
+ const emptyStringAsMissing = (_c = options.emptyStringAsMissing) !== null && _c !== void 0 ? _c : true;
75
+ const includeInherited = (_d = options.includeInherited) !== null && _d !== void 0 ? _d : true;
76
+ const snapshot = registry.read(target, { includeInherited });
77
+ const definitions = describeEnv(target, { includeInherited });
78
+ const values = {};
79
+ for (const definition of definitions) {
80
+ if (requireStatic && !definition.static) {
81
+ throw new EnvParseError(`@EnvVar field "${definition.propertyName}" must be static when using loadEnv().`, {
82
+ envName: definition.envName,
83
+ propertyName: definition.propertyName,
84
+ });
85
+ }
86
+ if (definition.private) {
87
+ throw new EnvParseError(`@EnvVar field "${definition.propertyName}" cannot be private.`, {
88
+ envName: definition.envName,
89
+ propertyName: definition.propertyName,
90
+ });
91
+ }
92
+ const rawValue = source[definition.envName];
93
+ const parsedValue = parseEnvValue({
94
+ envName: definition.envName,
95
+ propertyName: definition.propertyName,
96
+ rawValue,
97
+ metadata: definition.metadata,
98
+ emptyStringAsMissing,
99
+ });
100
+ Object.defineProperty(target, definition.propertyName, {
101
+ configurable: true,
102
+ enumerable: true,
103
+ writable: true,
104
+ value: parsedValue,
105
+ });
106
+ values[definition.propertyName] = parsedValue;
107
+ }
108
+ return Object.freeze({
109
+ target,
110
+ definitions,
111
+ values: Object.freeze(Object.assign({}, values)),
112
+ snapshot,
113
+ });
114
+ }
115
+ return Object.freeze({
116
+ registry,
117
+ Env,
118
+ EnvConfig,
119
+ EnvVar,
120
+ loadEnv,
121
+ describeEnv,
122
+ });
123
+ }
124
+ function getEnvConfigMetadata(snapshot) {
125
+ const configRecords = snapshot.classRecords('envConfig');
126
+ const lastRecord = configRecords[configRecords.length - 1];
127
+ return lastRecord === null || lastRecord === void 0 ? void 0 : lastRecord.metadata;
128
+ }
129
+ function toEnvKey(propertyName) {
130
+ return propertyName
131
+ .replace(/([A-Z]+)([A-Z][a-z])/g, '$1_$2')
132
+ .replace(/([a-z0-9])([A-Z])/g, '$1_$2')
133
+ .replace(/[-\s]+/g, '_')
134
+ .toUpperCase();
135
+ }
136
+ function parseEnvValue(args) {
137
+ const { envName, propertyName, rawValue, metadata, emptyStringAsMissing } = args;
138
+ const missing = rawValue === undefined || (emptyStringAsMissing && rawValue.trim() === '');
139
+ if (missing) {
140
+ if ('default' in metadata)
141
+ return metadata.default;
142
+ if (metadata.required === false)
143
+ return undefined;
144
+ throw new EnvParseError(`Missing required environment variable "${envName}".`, {
145
+ envName,
146
+ propertyName,
147
+ });
148
+ }
149
+ switch (metadata.type) {
150
+ case 'string':
151
+ return rawValue;
152
+ case 'number':
153
+ return parseNumberValue({
154
+ envName,
155
+ propertyName,
156
+ rawValue,
157
+ metadata,
158
+ });
159
+ case 'boolean':
160
+ return parseBooleanValue({
161
+ envName,
162
+ propertyName,
163
+ rawValue,
164
+ });
165
+ default:
166
+ return assertNever(metadata);
167
+ }
168
+ }
169
+ function parseNumberValue(args) {
170
+ const { envName, propertyName, rawValue, metadata } = args;
171
+ const value = Number(rawValue);
172
+ if (!Number.isFinite(value)) {
173
+ throw new EnvParseError(`Environment variable "${envName}" must be a finite number. Received "${rawValue}".`, { envName, propertyName });
174
+ }
175
+ if (metadata.integer === true && !Number.isInteger(value)) {
176
+ throw new EnvParseError(`Environment variable "${envName}" must be an integer. Received "${rawValue}".`, { envName, propertyName });
177
+ }
178
+ if (metadata.min !== undefined && value < metadata.min) {
179
+ throw new EnvParseError(`Environment variable "${envName}" must be >= ${metadata.min}. Received "${rawValue}".`, { envName, propertyName });
180
+ }
181
+ if (metadata.max !== undefined && value > metadata.max) {
182
+ throw new EnvParseError(`Environment variable "${envName}" must be <= ${metadata.max}. Received "${rawValue}".`, { envName, propertyName });
183
+ }
184
+ return value;
185
+ }
186
+ function parseBooleanValue(args) {
187
+ const { envName, propertyName, rawValue } = args;
188
+ const normalized = rawValue.trim().toLowerCase();
189
+ if (isTruthyEnvValue(normalized))
190
+ return true;
191
+ if (isFalsyEnvValue(normalized))
192
+ return false;
193
+ throw new EnvParseError(`Environment variable "${envName}" must be a boolean. Received "${rawValue}".`, { envName, propertyName });
194
+ }
195
+ function isTruthyEnvValue(value) {
196
+ return value === 'true'
197
+ || value === '1'
198
+ || value === 'yes'
199
+ || value === 'y'
200
+ || value === 'on';
201
+ }
202
+ function isFalsyEnvValue(value) {
203
+ return value === 'false'
204
+ || value === '0'
205
+ || value === 'no'
206
+ || value === 'n'
207
+ || value === 'off';
208
+ }
209
+ function getDefaultEnvSource() {
210
+ var _a, _b;
211
+ const maybeGlobal = globalThis;
212
+ return (_b = (_a = maybeGlobal.process) === null || _a === void 0 ? void 0 : _a.env) !== null && _b !== void 0 ? _b : {};
213
+ }
214
+ function assertNever(value) {
215
+ throw new EnvParseError(`Unsupported env metadata: ${JSON.stringify(value)}`);
216
+ }
217
+ const defaultEnvSystem = createEnvSystem();
218
+ exports.envRegistry = defaultEnvSystem.registry;
219
+ exports.Env = defaultEnvSystem.Env;
220
+ exports.EnvConfig = defaultEnvSystem.EnvConfig;
221
+ exports.EnvVar = defaultEnvSystem.EnvVar;
222
+ exports.loadEnv = defaultEnvSystem.loadEnv;
223
+ exports.describeEnv = defaultEnvSystem.describeEnv;
@@ -0,0 +1,48 @@
1
+ type Role = 'admin' | 'support' | 'user';
2
+ type AuthorizationDecorators = {
3
+ class: {
4
+ resource: {
5
+ metadata: {
6
+ name: string;
7
+ };
8
+ };
9
+ };
10
+ property: {};
11
+ method: {
12
+ requireRole: {
13
+ metadata: {
14
+ roles: Role[];
15
+ };
16
+ target: (...args: any[]) => Promise<unknown>;
17
+ };
18
+ };
19
+ accessor: {};
20
+ };
21
+ type AccountAdminContract = {
22
+ viewAccount(id: string): Promise<{
23
+ id: string;
24
+ }>;
25
+ suspendAccount(id: string): Promise<{
26
+ id: string;
27
+ suspended: true;
28
+ }>;
29
+ };
30
+ declare const registry: import("../types").DecoratorRegistry<AuthorizationDecorators>;
31
+ declare class AccountAdminController implements AccountAdminContract {
32
+ viewAccount(id: string): Promise<{
33
+ id: string;
34
+ }>;
35
+ suspendAccount(id: string): Promise<{
36
+ id: string;
37
+ suspended: true;
38
+ }>;
39
+ }
40
+ export type AccessPolicy = {
41
+ resource: string;
42
+ permissions: Array<{
43
+ handlerName: string | symbol;
44
+ roles: Role[];
45
+ }>;
46
+ };
47
+ export declare function buildAccessPolicy(): AccessPolicy;
48
+ export { AccountAdminController, registry as authorizationRegistry };
@@ -0,0 +1,113 @@
1
+ "use strict";
2
+ var __runInitializers = (this && this.__runInitializers) || function (thisArg, initializers, value) {
3
+ var useValue = arguments.length > 2;
4
+ for (var i = 0; i < initializers.length; i++) {
5
+ value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg);
6
+ }
7
+ return useValue ? value : void 0;
8
+ };
9
+ var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) {
10
+ function accept(f) { if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); return f; }
11
+ var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value";
12
+ var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null;
13
+ var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {});
14
+ var _, done = false;
15
+ for (var i = decorators.length - 1; i >= 0; i--) {
16
+ var context = {};
17
+ for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p];
18
+ for (var p in contextIn.access) context.access[p] = contextIn.access[p];
19
+ context.addInitializer = function (f) { if (done) throw new TypeError("Cannot add initializers after decoration has completed"); extraInitializers.push(accept(f || null)); };
20
+ var result = (0, decorators[i])(kind === "accessor" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context);
21
+ if (kind === "accessor") {
22
+ if (result === void 0) continue;
23
+ if (result === null || typeof result !== "object") throw new TypeError("Object expected");
24
+ if (_ = accept(result.get)) descriptor.get = _;
25
+ if (_ = accept(result.set)) descriptor.set = _;
26
+ if (_ = accept(result.init)) initializers.unshift(_);
27
+ }
28
+ else if (_ = accept(result)) {
29
+ if (kind === "field") initializers.unshift(_);
30
+ else descriptor[key] = _;
31
+ }
32
+ }
33
+ if (target) Object.defineProperty(target, contextIn.name, descriptor);
34
+ done = true;
35
+ };
36
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
37
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
38
+ return new (P || (P = Promise))(function (resolve, reject) {
39
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
40
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
41
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
42
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
43
+ });
44
+ };
45
+ var __setFunctionName = (this && this.__setFunctionName) || function (f, name, prefix) {
46
+ if (typeof name === "symbol") name = name.description ? "[".concat(name.description, "]") : "";
47
+ return Object.defineProperty(f, "name", { configurable: true, value: prefix ? "".concat(prefix, " ", name) : name });
48
+ };
49
+ Object.defineProperty(exports, "__esModule", { value: true });
50
+ exports.authorizationRegistry = exports.AccountAdminController = void 0;
51
+ exports.buildAccessPolicy = buildAccessPolicy;
52
+ const index_1 = require("../index");
53
+ const registry = (0, index_1.createDecoratorRegistry)({ namespace: 'authorization-example' });
54
+ exports.authorizationRegistry = registry;
55
+ const Account = registry.for();
56
+ const Resource = Account.class('resource');
57
+ const RequireRole = Account.method('requireRole');
58
+ let AccountAdminController = (() => {
59
+ let _classDecorators = [Resource({ name: 'account' })];
60
+ let _classDescriptor;
61
+ let _classExtraInitializers = [];
62
+ let _classThis;
63
+ let _instanceExtraInitializers = [];
64
+ let _viewAccount_decorators;
65
+ let _suspendAccount_decorators;
66
+ var AccountAdminController = _classThis = class {
67
+ viewAccount(id) {
68
+ return __awaiter(this, void 0, void 0, function* () {
69
+ return { id };
70
+ });
71
+ }
72
+ suspendAccount(id) {
73
+ return __awaiter(this, void 0, void 0, function* () {
74
+ return { id, suspended: true };
75
+ });
76
+ }
77
+ constructor() {
78
+ __runInitializers(this, _instanceExtraInitializers);
79
+ }
80
+ };
81
+ __setFunctionName(_classThis, "AccountAdminController");
82
+ (() => {
83
+ const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(null) : void 0;
84
+ _viewAccount_decorators = [RequireRole.on('viewAccount', { roles: ['support', 'admin'] })];
85
+ _suspendAccount_decorators = [RequireRole('suspendAccount', { roles: ['admin'] })];
86
+ __esDecorate(_classThis, null, _viewAccount_decorators, { kind: "method", name: "viewAccount", static: false, private: false, access: { has: obj => "viewAccount" in obj, get: obj => obj.viewAccount }, metadata: _metadata }, null, _instanceExtraInitializers);
87
+ __esDecorate(_classThis, null, _suspendAccount_decorators, { kind: "method", name: "suspendAccount", static: false, private: false, access: { has: obj => "suspendAccount" in obj, get: obj => obj.suspendAccount }, metadata: _metadata }, null, _instanceExtraInitializers);
88
+ __esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers);
89
+ AccountAdminController = _classThis = _classDescriptor.value;
90
+ if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
91
+ __runInitializers(_classThis, _classExtraInitializers);
92
+ })();
93
+ return AccountAdminController = _classThis;
94
+ })();
95
+ exports.AccountAdminController = AccountAdminController;
96
+ function buildAccessPolicy() {
97
+ const snapshot = registry.read(AccountAdminController);
98
+ const resource = snapshot.firstClass('resource');
99
+ if (resource === undefined)
100
+ throw new Error('Missing @Resource metadata.');
101
+ return {
102
+ resource: resource.metadata.name,
103
+ permissions: snapshot.methodRecords('requireRole').map((record) => {
104
+ if (record.memberName === undefined)
105
+ throw new Error('Role record missing member.');
106
+ const metadata = record.metadata;
107
+ return {
108
+ handlerName: record.memberName,
109
+ roles: metadata.roles,
110
+ };
111
+ }),
112
+ };
113
+ }
@@ -1,10 +1,12 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const accessors_1 = require("./accessors");
4
+ const authorization_1 = require("./authorization");
4
5
  const crud_1 = require("./crud");
5
6
  const orm_1 = require("./orm");
6
7
  const routing_1 = require("./routing");
7
8
  const serialization_1 = require("./serialization");
9
+ const validation_1 = require("./validation");
8
10
  function stable(value) {
9
11
  return JSON.stringify(value, (_key, innerValue) => {
10
12
  if (typeof innerValue === 'symbol')
@@ -18,5 +20,7 @@ const outputs = {
18
20
  serialization: (0, serialization_1.serializeUser)(),
19
21
  crud: (0, crud_1.buildCrudSummary)(),
20
22
  accessors: (0, accessors_1.readAccessorMetadata)(),
23
+ validation: (0, validation_1.buildValidationSchema)(),
24
+ authorization: (0, authorization_1.buildAccessPolicy)(),
21
25
  };
22
26
  console.log(stable(outputs));
@@ -0,0 +1,49 @@
1
+ type ValidationDecorators = {
2
+ class: {
3
+ schema: {
4
+ metadata: {
5
+ name: string;
6
+ };
7
+ };
8
+ };
9
+ property: {
10
+ field: {
11
+ metadata: {
12
+ type: 'string' | 'number' | 'email';
13
+ minLength?: number;
14
+ min?: number;
15
+ };
16
+ target: unknown;
17
+ };
18
+ required: {
19
+ metadata: undefined;
20
+ target: unknown;
21
+ };
22
+ };
23
+ method: {};
24
+ accessor: {};
25
+ };
26
+ type SignupInputContract = {
27
+ email: string;
28
+ displayName: string;
29
+ age: number;
30
+ };
31
+ declare const registry: import("../types").DecoratorRegistry<ValidationDecorators>;
32
+ declare class SignupInput implements SignupInputContract {
33
+ email: string;
34
+ displayName: string;
35
+ age: number;
36
+ }
37
+ export type ValidationField = {
38
+ name: string | symbol;
39
+ type: 'string' | 'number' | 'email';
40
+ required: boolean;
41
+ minLength?: number;
42
+ min?: number;
43
+ };
44
+ export type ValidationSchema = {
45
+ name: string;
46
+ fields: ValidationField[];
47
+ };
48
+ export declare function buildValidationSchema(): ValidationSchema;
49
+ export { SignupInput, registry as validationRegistry };