@open-norantec/herbal 1.0.2-alpha.1 → 1.0.2-alpha.10

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,18 +1,63 @@
1
1
  #!/usr/bin/env node
2
2
  "use strict";
3
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
4
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
5
+ return new (P || (P = Promise))(function (resolve, reject) {
6
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
7
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
8
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
9
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
10
+ });
11
+ };
12
+ var __generator = (this && this.__generator) || function (thisArg, body) {
13
+ var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
14
+ return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
15
+ function verb(n) { return function (v) { return step([n, v]); }; }
16
+ function step(op) {
17
+ if (f) throw new TypeError("Generator is already executing.");
18
+ while (g && (g = 0, op[0] && (_ = 0)), _) try {
19
+ if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
20
+ if (y = 0, t) op = [op[0] & 2, t.value];
21
+ switch (op[0]) {
22
+ case 0: case 1: t = op; break;
23
+ case 4: _.label++; return { value: op[1], done: false };
24
+ case 5: _.label++; y = op[1]; op = [0]; continue;
25
+ case 7: op = _.ops.pop(); _.trys.pop(); continue;
26
+ default:
27
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
28
+ if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
29
+ if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
30
+ if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
31
+ if (t[2]) _.ops.pop();
32
+ _.trys.pop(); continue;
33
+ }
34
+ op = body.call(thisArg, _);
35
+ } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
36
+ if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
37
+ }
38
+ };
3
39
  Object.defineProperty(exports, "__esModule", { value: true });
4
40
  var commander_1 = require("commander");
5
41
  var forge_1 = require("@open-norantec/forge");
42
+ var utilities_1 = require("../utilities");
43
+ var _ = require("lodash");
44
+ var fs = require("fs-extra");
45
+ var path = require("node:path");
46
+ var attempt_util_class_1 = require("@open-norantec/utilities/dist/attempt-util.class");
6
47
  var command = new commander_1.Command('herbal');
7
48
  var getEntryFileContent = function (_a) {
8
49
  var entryFilePath = _a.entryFilePath;
9
50
  return [
10
51
  "import 'reflect-metadata';",
11
- "import { ModelUtil, NestFactory } from '@open-norantec/herbal';",
52
+ "import { ModelUtil, NestFactory, isApplication } from '@open-norantec/herbal';",
12
53
  "import { LoggerService } from '@open-norantec/herbal/dist/modules/logger/logger.service';",
13
54
  "import { Worker, isMainThread, workerData } from 'node:worker_threads';",
14
55
  "import ENTRY from '".concat(entryFilePath, "';"),
15
56
  '\nasync function bootstrap() {',
57
+ ' if (!isApplication(ENTRY)) {',
58
+ ' console.log(`The entry file must export an application or a function that returns an application.`);',
59
+ ' process.exit(1);',
60
+ ' }',
16
61
  ' const entryOptions = ENTRY?.options;',
17
62
  ' await entryOptions?.onBeforeBootstrap?.();',
18
63
  "\n if (!!workerData?.['__herbal_worker']) {",
@@ -67,42 +112,6 @@ var getEntryFileContent = function (_a) {
67
112
  '\nbootstrap();',
68
113
  ].join('\n');
69
114
  };
70
- var getGenerateClientEntryFileContent = function (_a) {
71
- var entryFilePath = _a.entryFilePath, outputPath = _a.outputPath, options = _a.options;
72
- return [
73
- "import 'reflect-metadata';",
74
- "import ENTRY from '".concat(entryFilePath, "';"),
75
- "import * as fs from 'node:fs';",
76
- "import * as path from 'node:path';",
77
- '\nasync function bootstrap() {',
78
- " const outputDirPath = '".concat(outputPath, "';"),
79
- " const outputFilePath = path.resolve(outputDirPath, '".concat(options.outputName, ".ts');"),
80
- ' await ENTRY?.options?.onBeforeBootstrap?.();',
81
- ' try {',
82
- ' fs.rmSync(outputFilePath, {',
83
- ' recursive: true,',
84
- ' force: true,',
85
- ' });',
86
- ' } catch {}',
87
- ' try {',
88
- ' if (!fs.statSync(path.dirname(outputDirPath)).isDirectory()) {',
89
- ' fs.rmSync(path.dirname(outputDirPath), {',
90
- ' recursive: true,',
91
- ' force: true,',
92
- ' });',
93
- ' }',
94
- ' } catch {}',
95
- ' try {',
96
- ' fs.mkdirSync(outputDirPath, { recursive: true });',
97
- ' } catch {}',
98
- ' fs.writeFileSync(',
99
- ' outputFilePath,',
100
- ' ENTRY?.generateClientSourceFile?.(),',
101
- ' );',
102
- '}',
103
- '\nbootstrap();',
104
- ].join('\n');
105
- };
106
115
  var handleLog = function (level, message) {
107
116
  console.log("[".concat(new Date().toISOString(), "] [").concat(level, "] ").concat(message));
108
117
  switch (level) {
@@ -127,14 +136,45 @@ command
127
136
  mode: 'development',
128
137
  afterEmitAction: 'watch',
129
138
  }).name('watch'))
130
- .addCommand((0, forge_1.createForgeCommand)({
131
- onLog: handleLog,
132
- getEntryFileContent: getGenerateClientEntryFileContent,
133
- hideOptions: ['--after-emit-action', '--ts-compiler', '--mode'],
134
- mode: 'production',
135
- afterEmitAction: 'run-once',
136
- tsCompiler: require.resolve('ts-patch/compiler', {
137
- paths: [__dirname, process.cwd()],
138
- }),
139
- }).name('generate-client'));
139
+ .addCommand((function () {
140
+ var subCommand = new commander_1.Command('generate-client');
141
+ subCommand
142
+ .requiredOption('--entry <entry>', 'The entry file path of the application. It must export an instance generated with `createClient` to default.')
143
+ .requiredOption('--output-file <path>', 'The output file path of the generated client source file.')
144
+ .option('--group <group>', 'The group name of the generated client. It is used to distinguish different clients when there are multiple clients in the same application.')
145
+ .action(function (options) { return __awaiter(void 0, void 0, void 0, function () {
146
+ var clientUtil;
147
+ return __generator(this, function (_a) {
148
+ switch (_a.label) {
149
+ case 0:
150
+ clientUtil = _.attempt(function () {
151
+ return new utilities_1.ClientUtil(options, function (absoluteOutputFile, content) {
152
+ var absoluteOutputDir = path.dirname(absoluteOutputFile);
153
+ if (!fs.existsSync(absoluteOutputDir) || !fs.statSync(absoluteOutputDir).isDirectory()) {
154
+ _.attempt(function () { return fs.removeSync(absoluteOutputDir); });
155
+ _.attempt(function () { return fs.mkdirpSync(absoluteOutputDir); });
156
+ }
157
+ var writeResult = attempt_util_class_1.AttemptUtil.exec(function () {
158
+ return fs.writeFileSync(absoluteOutputFile, content, { encoding: 'utf-8' });
159
+ });
160
+ if (writeResult instanceof Error) {
161
+ handleLog === null || handleLog === void 0 ? void 0 : handleLog('error', "Failed to write client code: ".concat(writeResult.message));
162
+ return;
163
+ }
164
+ handleLog === null || handleLog === void 0 ? void 0 : handleLog('info', "Client code generated successfully at ".concat(absoluteOutputFile));
165
+ }, handleLog);
166
+ });
167
+ if (clientUtil instanceof Error) {
168
+ handleLog('error', "Failed to initialize the client utility: ".concat(clientUtil.message));
169
+ return [2];
170
+ }
171
+ return [4, clientUtil.generateClientCode()];
172
+ case 1:
173
+ _a.sent();
174
+ return [2];
175
+ }
176
+ });
177
+ }); });
178
+ return subCommand;
179
+ })());
140
180
  command.parse(process.argv);
package/dist/create.d.ts CHANGED
@@ -1,11 +1,10 @@
1
1
  import 'reflect-metadata';
2
2
  import { CorsOptions, CorsOptionsDelegate } from '@nestjs/common/interfaces/external/cors-options.interface';
3
3
  import { Constructor } from 'type-fest';
4
- import { GroupsFactory } from './decorators/client-groups.decorator';
5
4
  import { CanActivate, ExceptionFilter, INestApplication, NestApplicationOptions, NestInterceptor, PipeTransform, WebSocketAdapter } from '@nestjs/common';
6
5
  export type Resolver = <T>(Class: Constructor<T>) => Promise<T>;
7
6
  export type TypeCustomizerFn = (dataTypeMapName: string, name: string, genericName: string) => string[];
8
- export interface CreateOptions {
7
+ export interface CreateApplicationOptions {
9
8
  Module: Constructor<any>;
10
9
  cors?: CorsOptions | CorsOptionsDelegate<any> | false;
11
10
  factoryOptions?: NestApplicationOptions;
@@ -16,12 +15,30 @@ export interface CreateOptions {
16
15
  uses?: any[];
17
16
  websocketAdapter?: WebSocketAdapter;
18
17
  getListenPort: (resolver: Resolver) => number | Promise<number>;
19
- allowedClientGroupsFactory?: GroupsFactory;
20
18
  callback?: (listenPort: number, app: INestApplication<any>) => void | Promise<void>;
21
19
  onBeforeBootstrap?: () => void | Promise<void>;
22
20
  worker?: (resolver: Resolver, listenPort: number) => any;
23
21
  }
24
- export declare function create(options: CreateOptions): {
25
- options: CreateOptions;
26
- generateClientSourceFile: () => string;
27
- };
22
+ export interface CreateClientOptions {
23
+ Module: Constructor<any>;
24
+ allowedClientGroupsFactory?: (currentGroup: string | undefined, defaultGroupName: string) => string[] | null | undefined;
25
+ }
26
+ declare class Application {
27
+ readonly options: CreateApplicationOptions;
28
+ constructor(options: CreateApplicationOptions);
29
+ }
30
+ export declare function isApplication(input: any): boolean;
31
+ export declare function createApplication(options: CreateApplicationOptions): Application;
32
+ export declare abstract class Client {
33
+ readonly options: CreateClientOptions;
34
+ constructor(options: CreateClientOptions);
35
+ abstract generateClientSourceFile(currentGroup?: string): string;
36
+ }
37
+ declare class TypeScriptClient extends Client implements Client {
38
+ readonly options: CreateClientOptions;
39
+ constructor(options: CreateClientOptions);
40
+ generateClientSourceFile(currentGroup?: string): string;
41
+ }
42
+ export declare function isClient(input: any): boolean;
43
+ export declare function createTypeScriptClient(options: CreateClientOptions): TypeScriptClient;
44
+ export {};
package/dist/create.js CHANGED
@@ -1,6 +1,21 @@
1
1
  "use strict";
2
+ var __extends = (this && this.__extends) || (function () {
3
+ var extendStatics = function (d, b) {
4
+ extendStatics = Object.setPrototypeOf ||
5
+ ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
6
+ function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
7
+ return extendStatics(d, b);
8
+ };
9
+ return function (d, b) {
10
+ if (typeof b !== "function" && b !== null)
11
+ throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
12
+ extendStatics(d, b);
13
+ function __() { this.constructor = d; }
14
+ d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
15
+ };
16
+ })();
2
17
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.create = void 0;
18
+ exports.createTypeScriptClient = exports.isClient = exports.Client = exports.createApplication = exports.isApplication = void 0;
4
19
  require("reflect-metadata");
5
20
  var _ = require("lodash");
6
21
  var nest_util_class_1 = require("./utilities/nest-util.class");
@@ -8,147 +23,183 @@ var string_util_class_1 = require("@open-norantec/utilities/dist/string-util.cla
8
23
  var reflect_declaration_1 = require("./transformers/reflect-declaration");
9
24
  var client_groups_decorator_1 = require("./decorators/client-groups.decorator");
10
25
  var controller_util_class_1 = require("./utilities/controller-util.class");
11
- function create(options) {
12
- return {
13
- options: options,
14
- generateClientSourceFile: function () {
15
- if (!(options === null || options === void 0 ? void 0 : options.Module))
16
- throw new Error("Parameter 'Module' must be specified");
17
- var METHOD_TYPE_MAP_NAME = 'MethodTypeMap';
18
- var METHOD_TYPE_MAP_KEYS_NAME = 'MethodTypeMapKeys';
19
- var RESPONSE_CALLBACK_DATA_NAME = 'ResponseCallbackData';
20
- var REQUEST_OPTIONS_NAME = 'RequestOptions';
21
- var RESULT_TYPE_NAME = 'Result';
22
- var HTTP_RESPONSE_BODY_TYPE_NAME = 'HttpResponseBody';
23
- var REQUEST_METHOD_MAP_NAME = 'REQUEST_METHOD_MAP';
24
- var RESPONSE_CACHE_MAP_NAME = 'RESPONSE_CACHE_MAP';
25
- var REQUEST_BODY_TYPE_ANNOTATION = "".concat(METHOD_TYPE_MAP_NAME, "[T]['request']");
26
- var RESULT_TYPE_ANNOTATION = "".concat(RESULT_TYPE_NAME, "<").concat(HTTP_RESPONSE_BODY_TYPE_NAME, "<").concat(METHOD_TYPE_MAP_NAME, "[T]['response']>>");
27
- var methodTypeMapCodeLines = nest_util_class_1.NestUtil.getControllerClasses(options.Module)
28
- .reduce(function (result, Class) {
29
- if (string_util_class_1.StringUtil.isFalsyString(Class === null || Class === void 0 ? void 0 : Class.name))
30
- return result;
31
- var controllerName = _.camelCase(Class.name.replace(/Controller$/g, ''));
32
- if (string_util_class_1.StringUtil.isFalsyString(controllerName) || !(0, controller_util_class_1.isHerbalController)(Class)) {
26
+ var Application = (function () {
27
+ function Application(options) {
28
+ this.options = options;
29
+ }
30
+ return Application;
31
+ }());
32
+ function isApplication(input) {
33
+ return input instanceof Application;
34
+ }
35
+ exports.isApplication = isApplication;
36
+ function createApplication(options) {
37
+ return new Application(options);
38
+ }
39
+ exports.createApplication = createApplication;
40
+ var Client = (function () {
41
+ function Client(options) {
42
+ this.options = options;
43
+ }
44
+ return Client;
45
+ }());
46
+ exports.Client = Client;
47
+ var TypeScriptClient = (function (_super) {
48
+ __extends(TypeScriptClient, _super);
49
+ function TypeScriptClient(options) {
50
+ var _this = _super.call(this, options) || this;
51
+ _this.options = options;
52
+ return _this;
53
+ }
54
+ TypeScriptClient.prototype.generateClientSourceFile = function (currentGroup) {
55
+ var options = this.options;
56
+ if (!(options === null || options === void 0 ? void 0 : options.Module))
57
+ throw new Error("Parameter 'Module' must be specified");
58
+ var METHOD_TYPE_MAP_NAME = 'MethodTypeMap';
59
+ var METHOD_TYPE_MAP_KEYS_NAME = 'MethodTypeMapKeys';
60
+ var RESPONSE_CALLBACK_DATA_NAME = 'ResponseCallbackData';
61
+ var REQUEST_OPTIONS_NAME = 'RequestOptions';
62
+ var RESULT_TYPE_NAME = 'Result';
63
+ var HTTP_RESPONSE_BODY_TYPE_NAME = 'HttpResponseBody';
64
+ var REQUEST_METHOD_MAP_NAME = 'REQUEST_METHOD_MAP';
65
+ var RESPONSE_CACHE_MAP_NAME = 'RESPONSE_CACHE_MAP';
66
+ var REQUEST_BODY_TYPE_ANNOTATION = "".concat(METHOD_TYPE_MAP_NAME, "[T]['request']");
67
+ var RESULT_TYPE_ANNOTATION = "".concat(RESULT_TYPE_NAME, "<").concat(HTTP_RESPONSE_BODY_TYPE_NAME, "<").concat(METHOD_TYPE_MAP_NAME, "[T]['response']>>");
68
+ var methodTypeMapCodeLines = nest_util_class_1.NestUtil.getControllerClasses(options.Module)
69
+ .reduce(function (result, Class) {
70
+ if (string_util_class_1.StringUtil.isFalsyString(Class === null || Class === void 0 ? void 0 : Class.name))
71
+ return result;
72
+ var controllerName = _.camelCase(Class.name.replace(/Controller$/g, ''));
73
+ if (string_util_class_1.StringUtil.isFalsyString(controllerName) || !(0, controller_util_class_1.isHerbalController)(Class)) {
74
+ return result;
75
+ }
76
+ var metadataNames = Reflect.getMetadataKeys(Class.prototype).filter(function (metadataName) { return !string_util_class_1.StringUtil.isFalsyString(metadataName); });
77
+ return result.concat(metadataNames.reduce(function (result, metadataName) {
78
+ var methodName = metadataName.slice(reflect_declaration_1.DECORATOR_NAME_PREFIX.length);
79
+ if (string_util_class_1.StringUtil.isFalsyString(metadataName) ||
80
+ !metadataName.startsWith(reflect_declaration_1.DECORATOR_NAME_PREFIX) ||
81
+ !client_groups_decorator_1.ClientGroups.shouldShowInClient(Class, methodName, function (defaultGroupName) {
82
+ var _a;
83
+ return (_a = options.allowedClientGroupsFactory) === null || _a === void 0 ? void 0 : _a.call(options, currentGroup, defaultGroupName);
84
+ })) {
33
85
  return result;
34
86
  }
35
- var metadataNames = Reflect.getMetadataKeys(Class.prototype).filter(function (metadataName) { return !string_util_class_1.StringUtil.isFalsyString(metadataName); });
36
- return result.concat(metadataNames.reduce(function (result, metadataName) {
37
- var methodName = metadataName.slice(reflect_declaration_1.DECORATOR_NAME_PREFIX.length);
38
- if (string_util_class_1.StringUtil.isFalsyString(metadataName) ||
39
- !metadataName.startsWith(reflect_declaration_1.DECORATOR_NAME_PREFIX) ||
40
- !client_groups_decorator_1.ClientGroups.shouldShowInClient(Class, methodName, options === null || options === void 0 ? void 0 : options.allowedClientGroupsFactory)) {
41
- return result;
42
- }
43
- var scopeIdentifier = "/".concat(controllerName, "/").concat(methodName);
44
- return result.concat(["'".concat(scopeIdentifier, "'"), "".concat(Reflect.getMetadata(metadataName, Class.prototype), ";")].join(': '));
45
- }, []));
46
- }, [])
47
- .map(function (line) { return " ".concat(line); });
48
- methodTypeMapCodeLines.unshift("export interface ".concat(METHOD_TYPE_MAP_NAME, " {"));
49
- methodTypeMapCodeLines.push('}');
50
- return [
51
- "import * as hash from 'object-hash';",
52
- "import * as _ from 'lodash';",
53
- "\n".concat(methodTypeMapCodeLines.join('\n')),
54
- "\ntype ".concat(METHOD_TYPE_MAP_KEYS_NAME, " = keyof ").concat(METHOD_TYPE_MAP_NAME, ";"),
55
- "\ntype ".concat(RESPONSE_CALLBACK_DATA_NAME, "<K extends ").concat(METHOD_TYPE_MAP_KEYS_NAME, "> = {"),
56
- ' url: K;',
57
- " result: ".concat(RESULT_TYPE_NAME, "<").concat(HTTP_RESPONSE_BODY_TYPE_NAME, "<").concat(METHOD_TYPE_MAP_NAME, "[K]['response']>>;"),
58
- '};',
59
- "\nexport type ".concat(HTTP_RESPONSE_BODY_TYPE_NAME, "<T> = {"),
60
- ' data: T;',
61
- ' token: string | null;',
62
- '};',
63
- "\nexport interface ".concat(REQUEST_OPTIONS_NAME, " extends RequestInit {"),
64
- ' headers?: Record<string, any>;',
65
- ' ignoreCache?: boolean;',
66
- ' prefix?: string;',
67
- ' timeout?: number;',
68
- ' getAuthorizationCredential?: () => string;',
69
- " onRequest?: (context: { cached: boolean; id: string; options: Omit<".concat(REQUEST_OPTIONS_NAME, ", 'getAuthorizationCredential' | 'onRequest' | 'onResponse'>; prefix: string | undefined; requestBody: string; url: string; }) => void | Promise<void>;"),
70
- " onResponse?: <K extends ".concat(METHOD_TYPE_MAP_KEYS_NAME, ">(response: ").concat(RESPONSE_CALLBACK_DATA_NAME, "<K>, id: string) => void | Promise<void>;"),
71
- '}',
72
- "\nexport interface ".concat(RESULT_TYPE_NAME, "<T> {"),
73
- ' error: Error | null;',
74
- " response: T | null;",
75
- ' status: number;',
76
- ' statusText: string;',
77
- ' headers?: Record<string, any>;',
78
- '}',
79
- '\nexport class Client {',
80
- " public constructor(private readonly options: ".concat(REQUEST_OPTIONS_NAME, " = {}) {}"),
81
- "\n protected readonly ".concat(REQUEST_METHOD_MAP_NAME, " = new Map<keyof ").concat(METHOD_TYPE_MAP_NAME, ", (...params: any[]) => Promise<unknown>>();"),
82
- "\n protected readonly ".concat(RESPONSE_CACHE_MAP_NAME, " = new Map<string, ").concat(RESULT_TYPE_NAME, "<unknown>>();"),
83
- "\n public createRequest<T extends keyof ".concat(METHOD_TYPE_MAP_NAME, ">(url: T): (requestBody?: ").concat(REQUEST_BODY_TYPE_ANNOTATION, ", options?: ").concat(REQUEST_OPTIONS_NAME, ") => Promise<").concat(RESULT_TYPE_ANNOTATION, "> {"),
84
- " if (typeof this.".concat(REQUEST_METHOD_MAP_NAME, ".get(url) !== 'function') {"),
85
- " this.".concat(REQUEST_METHOD_MAP_NAME, ".set(url, (requestBody?: ").concat(REQUEST_BODY_TYPE_ANNOTATION, ", options?: ").concat(REQUEST_OPTIONS_NAME, ") => this.request.call(this, url, requestBody, options));"),
86
- ' }',
87
- " return this.".concat(REQUEST_METHOD_MAP_NAME, ".get(url) as (requestBody?: ").concat(REQUEST_BODY_TYPE_ANNOTATION, ", options?: ").concat(REQUEST_OPTIONS_NAME, ") => Promise<").concat(RESULT_TYPE_ANNOTATION, ">;"),
88
- ' }',
89
- "\n public async request<T extends keyof ".concat(METHOD_TYPE_MAP_NAME, ">(url: T, requestBody?: ").concat(REQUEST_BODY_TYPE_ANNOTATION, ", options?: Omit<").concat(REQUEST_OPTIONS_NAME, ", 'getAuthorizationCredential' | 'onRequest' | 'onResponse'>): Promise<").concat(RESULT_TYPE_ANNOTATION, "> {"),
90
- ' const id = `${Math.random().toString(32).slice(2)}${Date.now().toString(16)}`;',
91
- ' const requestHash = hash(requestBody ?? null);',
92
- ' const requestBodyString = JSON.stringify(requestBody);',
93
- " const finalOptions = _.merge({}, this?.options, _.omit(options, ['getAuthorizationCredential', 'onRequest', 'onResponse']));",
94
- " const onRequestOptions = _.omit(finalOptions, ['getAuthorizationCredential', 'onRequest', 'onResponse']);",
95
- ' const { getAuthorizationCredential, onResponse, onRequest, ignoreCache, timeout, prefix, ...requestOptions } = finalOptions;',
96
- " if (this.".concat(RESPONSE_CACHE_MAP_NAME, ".has(requestHash) && !ignoreCache) {"),
97
- ' onRequest?.({',
98
- ' prefix,',
99
- ' url,',
100
- ' requestBody: requestBodyString,',
101
- ' cached: true,',
102
- ' options: onRequestOptions,',
103
- ' id,',
104
- ' });',
105
- " return this.".concat(RESPONSE_CACHE_MAP_NAME, ".get(requestHash) as ").concat(RESULT_TYPE_ANNOTATION, ";"),
106
- ' }',
107
- ' onRequest?.({',
108
- ' prefix,',
109
- ' url,',
110
- ' id,',
111
- ' requestBody: requestBodyString,',
112
- ' cached: false,',
113
- ' options: onRequestOptions,',
114
- ' });',
115
- ' const credential = getAuthorizationCredential?.();',
116
- ' const abortController = new AbortController();',
117
- ' if (timeout! > 0) {',
118
- ' setTimeout(() => {',
119
- ' abortController.abort();',
120
- ' }, timeout);',
121
- ' }',
122
- " const result: ".concat(RESULT_TYPE_ANNOTATION, " = await fetch((prefix ?? '') + url, {"),
123
- ' ...requestOptions,',
124
- ' body: JSON.stringify(requestBody),',
125
- " method: 'POST',",
126
- ' signal: abortController.signal,',
127
- ' headers: {',
128
- ' ...requestOptions?.headers,',
129
- " 'Content-Type': 'application/json',",
130
- " Authorization: (typeof credential === 'string' && credential.length > 0) ? credential : finalOptions?.headers?.Authorization,",
131
- ' },',
132
- ' }).then((response) => {',
133
- ' const status = response?.status;',
134
- ' const statusText = response?.statusText;',
135
- ' const headers = Array.from(response?.headers?.entries?.() ?? []).reduce((result, [key, value]) => {',
136
- " if (typeof key !== 'string' || key.length === 0) return result;",
137
- ' result[key] = value;',
138
- ' return result;',
139
- ' }, {});',
140
- ' if (!response?.ok) {',
141
- ' return response.text().then((errorText) => ({ error: new Error(errorText), response: null, headers, status, statusText }));',
142
- ' }',
143
- " return response.json().then((response) => ({ error: null, response, headers, status, statusText } as ".concat(RESULT_TYPE_ANNOTATION, "));"),
144
- " }).catch((error) => Promise.resolve({ error, response: null, headers: {}, status: 0, statusText: '' }));",
145
- " onResponse?.({ url, result }, id);",
146
- " this.".concat(RESPONSE_CACHE_MAP_NAME, ".set(requestHash, result);"),
147
- ' return result;',
148
- ' }',
149
- '}\n',
150
- ].join('\n');
151
- },
87
+ var scopeIdentifier = "/".concat(controllerName, "/").concat(methodName);
88
+ return result.concat(["'".concat(scopeIdentifier, "'"), "".concat(Reflect.getMetadata(metadataName, Class.prototype), ";")].join(': '));
89
+ }, []));
90
+ }, [])
91
+ .map(function (line) { return " ".concat(line); });
92
+ methodTypeMapCodeLines.unshift("export interface ".concat(METHOD_TYPE_MAP_NAME, " {"));
93
+ methodTypeMapCodeLines.push('}');
94
+ return [
95
+ "import * as hash from 'object-hash';",
96
+ "import * as _ from 'lodash';",
97
+ "\n".concat(methodTypeMapCodeLines.join('\n')),
98
+ "\ntype ".concat(METHOD_TYPE_MAP_KEYS_NAME, " = keyof ").concat(METHOD_TYPE_MAP_NAME, ";"),
99
+ "\ntype ".concat(RESPONSE_CALLBACK_DATA_NAME, "<K extends ").concat(METHOD_TYPE_MAP_KEYS_NAME, "> = {"),
100
+ ' url: K;',
101
+ " result: ".concat(RESULT_TYPE_NAME, "<").concat(HTTP_RESPONSE_BODY_TYPE_NAME, "<").concat(METHOD_TYPE_MAP_NAME, "[K]['response']>>;"),
102
+ '};',
103
+ "\nexport type ".concat(HTTP_RESPONSE_BODY_TYPE_NAME, "<T> = {"),
104
+ ' data: T;',
105
+ ' token: string | null;',
106
+ '};',
107
+ "\nexport interface ".concat(REQUEST_OPTIONS_NAME, " extends RequestInit {"),
108
+ ' headers?: Record<string, any>;',
109
+ ' ignoreCache?: boolean;',
110
+ ' prefix?: string;',
111
+ ' timeout?: number;',
112
+ ' getAuthorizationCredential?: () => string;',
113
+ " onRequest?: (context: { cached: boolean; id: string; options: Omit<".concat(REQUEST_OPTIONS_NAME, ", 'getAuthorizationCredential' | 'onRequest' | 'onResponse'>; prefix: string | undefined; requestBody: string; url: string; }) => void | Promise<void>;"),
114
+ " onResponse?: <K extends ".concat(METHOD_TYPE_MAP_KEYS_NAME, ">(response: ").concat(RESPONSE_CALLBACK_DATA_NAME, "<K>, id: string) => void | Promise<void>;"),
115
+ '}',
116
+ "\nexport interface ".concat(RESULT_TYPE_NAME, "<T> {"),
117
+ ' error: Error | null;',
118
+ " response: T | null;",
119
+ ' status: number;',
120
+ ' statusText: string;',
121
+ ' headers?: Record<string, any>;',
122
+ '}',
123
+ '\nexport class Client {',
124
+ " public constructor(private readonly options: ".concat(REQUEST_OPTIONS_NAME, " = {}) {}"),
125
+ "\n protected readonly ".concat(REQUEST_METHOD_MAP_NAME, " = new Map<keyof ").concat(METHOD_TYPE_MAP_NAME, ", (...params: any[]) => Promise<unknown>>();"),
126
+ "\n protected readonly ".concat(RESPONSE_CACHE_MAP_NAME, " = new Map<string, ").concat(RESULT_TYPE_NAME, "<unknown>>();"),
127
+ "\n public createRequest<T extends keyof ".concat(METHOD_TYPE_MAP_NAME, ">(url: T): (requestBody?: ").concat(REQUEST_BODY_TYPE_ANNOTATION, ", options?: ").concat(REQUEST_OPTIONS_NAME, ") => Promise<").concat(RESULT_TYPE_ANNOTATION, "> {"),
128
+ " if (typeof this.".concat(REQUEST_METHOD_MAP_NAME, ".get(url) !== 'function') {"),
129
+ " this.".concat(REQUEST_METHOD_MAP_NAME, ".set(url, (requestBody?: ").concat(REQUEST_BODY_TYPE_ANNOTATION, ", options?: ").concat(REQUEST_OPTIONS_NAME, ") => this.request.call(this, url, requestBody, options));"),
130
+ ' }',
131
+ " return this.".concat(REQUEST_METHOD_MAP_NAME, ".get(url) as (requestBody?: ").concat(REQUEST_BODY_TYPE_ANNOTATION, ", options?: ").concat(REQUEST_OPTIONS_NAME, ") => Promise<").concat(RESULT_TYPE_ANNOTATION, ">;"),
132
+ ' }',
133
+ "\n public async request<T extends keyof ".concat(METHOD_TYPE_MAP_NAME, ">(url: T, requestBody?: ").concat(REQUEST_BODY_TYPE_ANNOTATION, ", options?: Omit<").concat(REQUEST_OPTIONS_NAME, ", 'getAuthorizationCredential' | 'onRequest' | 'onResponse'>): Promise<").concat(RESULT_TYPE_ANNOTATION, "> {"),
134
+ ' const id = `${Math.random().toString(32).slice(2)}${Date.now().toString(16)}`;',
135
+ ' const requestHash = hash(requestBody ?? null);',
136
+ ' const requestBodyString = JSON.stringify(requestBody);',
137
+ " const finalOptions = _.merge({}, this?.options, _.omit(options, ['getAuthorizationCredential', 'onRequest', 'onResponse']));",
138
+ " const onRequestOptions = _.omit(finalOptions, ['getAuthorizationCredential', 'onRequest', 'onResponse']);",
139
+ ' const { getAuthorizationCredential, onResponse, onRequest, ignoreCache, timeout, prefix, ...requestOptions } = finalOptions;',
140
+ " if (this.".concat(RESPONSE_CACHE_MAP_NAME, ".has(requestHash) && !ignoreCache) {"),
141
+ ' onRequest?.({',
142
+ ' prefix,',
143
+ ' url,',
144
+ ' requestBody: requestBodyString,',
145
+ ' cached: true,',
146
+ ' options: onRequestOptions,',
147
+ ' id,',
148
+ ' });',
149
+ " return this.".concat(RESPONSE_CACHE_MAP_NAME, ".get(requestHash) as ").concat(RESULT_TYPE_ANNOTATION, ";"),
150
+ ' }',
151
+ ' onRequest?.({',
152
+ ' prefix,',
153
+ ' url,',
154
+ ' id,',
155
+ ' requestBody: requestBodyString,',
156
+ ' cached: false,',
157
+ ' options: onRequestOptions,',
158
+ ' });',
159
+ ' const credential = getAuthorizationCredential?.();',
160
+ ' const abortController = new AbortController();',
161
+ ' if (timeout! > 0) {',
162
+ ' setTimeout(() => {',
163
+ ' abortController.abort();',
164
+ ' }, timeout);',
165
+ ' }',
166
+ " const result: ".concat(RESULT_TYPE_ANNOTATION, " = await fetch((prefix ?? '') + url, {"),
167
+ ' ...requestOptions,',
168
+ ' body: JSON.stringify(requestBody),',
169
+ " method: 'POST',",
170
+ ' signal: abortController.signal,',
171
+ ' headers: {',
172
+ ' ...requestOptions?.headers,',
173
+ " 'Content-Type': 'application/json',",
174
+ " Authorization: (typeof credential === 'string' && credential.length > 0) ? credential : finalOptions?.headers?.Authorization,",
175
+ ' },',
176
+ ' }).then((response) => {',
177
+ ' const status = response?.status;',
178
+ ' const statusText = response?.statusText;',
179
+ ' const headers = Array.from(response?.headers?.entries?.() ?? []).reduce((result, [key, value]) => {',
180
+ " if (typeof key !== 'string' || key.length === 0) return result;",
181
+ ' result[key] = value;',
182
+ ' return result;',
183
+ ' }, {});',
184
+ ' if (!response?.ok) {',
185
+ ' return response.text().then((errorText) => ({ error: new Error(errorText), response: null, headers, status, statusText }));',
186
+ ' }',
187
+ " return response.json().then((response) => ({ error: null, response, headers, status, statusText } as ".concat(RESULT_TYPE_ANNOTATION, "));"),
188
+ " }).catch((error) => Promise.resolve({ error, response: null, headers: {}, status: 0, statusText: '' }));",
189
+ " onResponse?.({ url, result }, id);",
190
+ " this.".concat(RESPONSE_CACHE_MAP_NAME, ".set(requestHash, result);"),
191
+ ' return result;',
192
+ ' }',
193
+ '}\n',
194
+ ].join('\n');
152
195
  };
196
+ return TypeScriptClient;
197
+ }(Client));
198
+ function isClient(input) {
199
+ return input instanceof Client;
200
+ }
201
+ exports.isClient = isClient;
202
+ function createTypeScriptClient(options) {
203
+ return new TypeScriptClient(options);
153
204
  }
154
- exports.create = create;
205
+ exports.createTypeScriptClient = createTypeScriptClient;
@@ -1,2 +1,3 @@
1
1
  export * from './auth-adapter.decorator';
2
2
  export * from './client-groups.decorator';
3
+ export * from './no-transaction.decorator';
@@ -16,3 +16,4 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
17
  __exportStar(require("./auth-adapter.decorator"), exports);
18
18
  __exportStar(require("./client-groups.decorator"), exports);
19
+ __exportStar(require("./no-transaction.decorator"), exports);
@@ -0,0 +1,5 @@
1
+ import 'reflect-metadata';
2
+ export declare function NoTransaction(): PropertyDecorator;
3
+ export declare namespace NoTransaction {
4
+ var isDisabled: (target: object, propertyKey: string) => boolean;
5
+ }
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.NoTransaction = void 0;
4
+ require("reflect-metadata");
5
+ var _ = require("lodash");
6
+ var TRANSACTION_DISABLED = Symbol();
7
+ function NoTransaction() {
8
+ return function (target, propertyKey) {
9
+ Reflect.defineMetadata(TRANSACTION_DISABLED, true, target, propertyKey);
10
+ };
11
+ }
12
+ exports.NoTransaction = NoTransaction;
13
+ NoTransaction.isDisabled = function (target, propertyKey) {
14
+ var result = _.attempt(function () { return Reflect.getMetadata(TRANSACTION_DISABLED, target, propertyKey); });
15
+ return result === true;
16
+ };
@@ -1,7 +1,10 @@
1
- import { BelongsToOptions, ModelAttributeColumnOptions } from 'sequelize';
2
- import { Model, TableOptions, ModelClassGetter } from 'sequelize-typescript';
1
+ import { BelongsToOptions, IndexesOptions, ModelAttributeColumnOptions } from 'sequelize';
2
+ import { Model, TableOptions as SequelizeTableOptions, ModelClassGetter } from 'sequelize-typescript';
3
3
  import { Constructor } from 'type-fest';
4
4
  export * from 'sequelize-typescript';
5
- export declare function Table<M extends Model = Model>(options: TableOptions<M>): (target: Constructor<M>) => void;
5
+ export interface TableOptions<M extends Model = Model> extends Omit<SequelizeTableOptions<M>, 'indexes'> {
6
+ indexes?: Array<IndexesOptions | string>;
7
+ }
8
+ export declare function Table<M extends Model = Model>({ indexes, ...options }: TableOptions<M>): (target: Constructor<M>) => void;
6
9
  export declare function BelongsTo(associatedClassGetter: ModelClassGetter<{}, {}>, options?: BelongsToOptions): Function;
7
10
  export declare function DateColumn(options: Partial<ModelAttributeColumnOptions>): Function;
@@ -24,16 +24,35 @@ var __createBinding = (this && this.__createBinding) || (Object.create ? (functi
24
24
  var __exportStar = (this && this.__exportStar) || function(m, exports) {
25
25
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
26
26
  };
27
+ var __rest = (this && this.__rest) || function (s, e) {
28
+ var t = {};
29
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
30
+ t[p] = s[p];
31
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
32
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
33
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
34
+ t[p[i]] = s[p[i]];
35
+ }
36
+ return t;
37
+ };
27
38
  Object.defineProperty(exports, "__esModule", { value: true });
28
39
  exports.DateColumn = exports.BelongsTo = exports.Table = void 0;
29
40
  var sequelize_typescript_1 = require("sequelize-typescript");
30
41
  __exportStar(require("sequelize-typescript"), exports);
31
- function Table(options) {
42
+ function Table(_a) {
43
+ var indexes = _a.indexes, options = __rest(_a, ["indexes"]);
32
44
  return function (target) {
33
45
  var newOptions = !options ? {} : options;
34
- if (!Array.isArray(newOptions === null || newOptions === void 0 ? void 0 : newOptions.indexes))
35
- newOptions.indexes = [];
36
- newOptions.indexes = Array.from(newOptions.indexes).concat({
46
+ newOptions.indexes = [];
47
+ newOptions.indexes = Array.from(Array.isArray(indexes) ? indexes : []).map(function (item, index) {
48
+ if (typeof item === 'string') {
49
+ return {
50
+ name: "sidx__".concat(index),
51
+ fields: [item],
52
+ };
53
+ }
54
+ return item;
55
+ }).concat({
37
56
  name: 'pagination',
38
57
  fields: ['id', 'created_at'],
39
58
  });
@@ -0,0 +1,28 @@
1
+ import { Schema } from '@open-norantec/utilities/dist/schema-util.class';
2
+ import { z } from 'zod';
3
+ declare const OPTIONS_SCHEMA: z.ZodObject<{
4
+ entry: z.ZodString;
5
+ outputFile: z.ZodString;
6
+ group: z.ZodOptional<z.ZodString>;
7
+ }, "strip", z.ZodTypeAny, {
8
+ entry: string;
9
+ outputFile: string;
10
+ group?: string | undefined;
11
+ }, {
12
+ entry: string;
13
+ outputFile: string;
14
+ group?: string | undefined;
15
+ }>;
16
+ export declare class ClientUtil {
17
+ private readonly inputOptions;
18
+ private readonly onFile;
19
+ private readonly onLog;
20
+ constructor(inputOptions: z.infer<typeof OPTIONS_SCHEMA>, onFile: (filePath: string, content: string) => void, onLog: (level: Schema.LogLevel, message?: string) => void);
21
+ protected readonly options: {
22
+ entry: string;
23
+ outputFile: string;
24
+ group?: string | undefined;
25
+ };
26
+ generateClientCode(): Promise<void>;
27
+ }
28
+ export {};
@@ -0,0 +1,190 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ var __generator = (this && this.__generator) || function (thisArg, body) {
12
+ var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
13
+ return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
14
+ function verb(n) { return function (v) { return step([n, v]); }; }
15
+ function step(op) {
16
+ if (f) throw new TypeError("Generator is already executing.");
17
+ while (g && (g = 0, op[0] && (_ = 0)), _) try {
18
+ if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
19
+ if (y = 0, t) op = [op[0] & 2, t.value];
20
+ switch (op[0]) {
21
+ case 0: case 1: t = op; break;
22
+ case 4: _.label++; return { value: op[1], done: false };
23
+ case 5: _.label++; y = op[1]; op = [0]; continue;
24
+ case 7: op = _.ops.pop(); _.trys.pop(); continue;
25
+ default:
26
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
27
+ if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
28
+ if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
29
+ if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
30
+ if (t[2]) _.ops.pop();
31
+ _.trys.pop(); continue;
32
+ }
33
+ op = body.call(thisArg, _);
34
+ } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
35
+ if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
36
+ }
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.ClientUtil = void 0;
40
+ var ts = require("typescript");
41
+ var path = require("node:path");
42
+ var _ = require("lodash");
43
+ var reflect_declaration_1 = require("../transformers/reflect-declaration");
44
+ var esbuild = require("esbuild");
45
+ var requireFromString = require("require-from-string");
46
+ var utilities_1 = require("@open-norantec/utilities");
47
+ var create_1 = require("../create");
48
+ var zod_1 = require("zod");
49
+ var OPTIONS_SCHEMA = zod_1.z.object({
50
+ entry: zod_1.z.string(),
51
+ outputFile: zod_1.z.string(),
52
+ group: zod_1.z.string().optional(),
53
+ });
54
+ var ClientUtil = (function () {
55
+ function ClientUtil(inputOptions, onFile, onLog) {
56
+ this.inputOptions = inputOptions;
57
+ this.onFile = onFile;
58
+ this.onLog = onLog;
59
+ this.options = OPTIONS_SCHEMA.parse(this.inputOptions);
60
+ }
61
+ ClientUtil.prototype.generateClientCode = function () {
62
+ var _a, _b, _c, _d, _e;
63
+ return __awaiter(this, void 0, void 0, function () {
64
+ var configPath, configFile, parsed, program, outputMap, outputFile, esbuildResult, text, client, requireResult, clientCode, absoluteOutputFile;
65
+ var _this = this;
66
+ return __generator(this, function (_f) {
67
+ switch (_f.label) {
68
+ case 0:
69
+ configPath = ts.findConfigFile('.', ts.sys.fileExists, 'tsconfig.json');
70
+ configFile = ts.readConfigFile(configPath, ts.sys.readFile);
71
+ parsed = ts.parseJsonConfigFileContent(configFile.config, ts.sys, path.dirname(configPath));
72
+ parsed.options.configFilePath = configPath;
73
+ program = ts.createProgram({ rootNames: parsed.fileNames, options: parsed.options });
74
+ outputMap = new Map();
75
+ outputFile = _.attempt(function () {
76
+ return ts
77
+ .getOutputFileNames(parsed, path.relative(process.cwd(), path.resolve(_this.options.entry)), false)
78
+ .find(function (filePath) { return filePath.endsWith('.js'); });
79
+ });
80
+ if (outputFile instanceof Error) {
81
+ (_a = this.onLog) === null || _a === void 0 ? void 0 : _a.call(this, 'error', "Failed to determine output file: ".concat(outputFile.message));
82
+ return [2];
83
+ }
84
+ if (typeof outputFile === 'undefined') {
85
+ (_b = this.onLog) === null || _b === void 0 ? void 0 : _b.call(this, 'error', 'Failed to determine output file: No .js output file found');
86
+ return [2];
87
+ }
88
+ program.emit(undefined, function (fileName, data) {
89
+ var _a;
90
+ var absolutePath = path.resolve(fileName);
91
+ outputMap.set(absolutePath, data);
92
+ (_a = _this.onLog) === null || _a === void 0 ? void 0 : _a.call(_this, 'info', "Compiled ".concat(absolutePath));
93
+ }, undefined, false, {
94
+ before: [(0, reflect_declaration_1.default)(program)],
95
+ });
96
+ return [4, utilities_1.AttemptUtil.execPromise(esbuild.build({
97
+ entryPoints: [path.resolve(outputFile)],
98
+ bundle: true,
99
+ platform: 'node',
100
+ format: 'cjs',
101
+ write: false,
102
+ plugins: [
103
+ {
104
+ name: 'tsconfig-paths',
105
+ setup: function (build) {
106
+ build.onResolve({ filter: /.*/ }, function (args) {
107
+ var _a, _b;
108
+ var hasMatchingPath = Object.keys(((_a = parsed.options) === null || _a === void 0 ? void 0 : _a.paths) || {}).some(function (path) {
109
+ return new RegExp(path.replace('*', '\\w*')).test(args.path);
110
+ });
111
+ if (!hasMatchingPath) {
112
+ return null;
113
+ }
114
+ var resolvedModule = ts.nodeModuleNameResolver(args.path, args.importer, parsed.options || {}, ts.sys).resolvedModule;
115
+ if (!resolvedModule) {
116
+ return null;
117
+ }
118
+ var resolvedFileName = resolvedModule.resolvedFileName;
119
+ if (!resolvedFileName || resolvedFileName.endsWith('.d.ts')) {
120
+ return null;
121
+ }
122
+ var resolved = ts.sys.resolvePath(resolvedFileName);
123
+ (_b = _this.onLog) === null || _b === void 0 ? void 0 : _b.call(_this, 'info', "Resolved file using TypeScript paths: ".concat(args.path, " -> ").concat(resolved, ")"));
124
+ return {
125
+ path: resolved,
126
+ };
127
+ });
128
+ },
129
+ },
130
+ {
131
+ name: 'vfs',
132
+ setup: function (build) {
133
+ build.onResolve({ filter: /.*/ }, function (args) {
134
+ var fullPath = path.resolve(path.dirname(args.importer), args.path);
135
+ if (!fullPath.endsWith('.js'))
136
+ fullPath += '.js';
137
+ if (outputMap.has(fullPath)) {
138
+ return { path: fullPath, namespace: 'vfs' };
139
+ }
140
+ return { path: args.path, external: true };
141
+ });
142
+ build.onLoad({ filter: /.*/, namespace: 'vfs' }, function (args) {
143
+ var contents = outputMap.get(args.path);
144
+ return {
145
+ contents: contents,
146
+ loader: 'js',
147
+ };
148
+ });
149
+ },
150
+ },
151
+ ],
152
+ }))];
153
+ case 1:
154
+ esbuildResult = _f.sent();
155
+ if (esbuildResult instanceof Error) {
156
+ (_c = this.onLog) === null || _c === void 0 ? void 0 : _c.call(this, 'error', "Failed to build client code: ".concat(esbuildResult.message));
157
+ return [2];
158
+ }
159
+ if (esbuildResult.errors.length > 0) {
160
+ this.onLog('error', "Builder built with error: ".concat(esbuildResult.errors[0].text));
161
+ return [2];
162
+ }
163
+ text = esbuildResult.outputFiles[0].text;
164
+ client = undefined;
165
+ try {
166
+ requireResult = requireFromString(text, { appendPaths: [path.resolve(process.cwd())] });
167
+ client = requireResult;
168
+ if (!(client instanceof create_1.Client))
169
+ client = client === null || client === void 0 ? void 0 : client.default;
170
+ }
171
+ catch (_g) { }
172
+ if (!(client instanceof create_1.Client)) {
173
+ (_d = this.onLog) === null || _d === void 0 ? void 0 : _d.call(this, 'error', 'Failed to load client code');
174
+ return [2];
175
+ }
176
+ clientCode = _.attempt(function () { return client.generateClientSourceFile(_this.options.group); });
177
+ if (clientCode instanceof Error) {
178
+ (_e = this.onLog) === null || _e === void 0 ? void 0 : _e.call(this, 'error', "Failed to generate client code: ".concat(clientCode.message));
179
+ return [2];
180
+ }
181
+ absoluteOutputFile = path.resolve(this.options.outputFile);
182
+ this.onFile(absoluteOutputFile, clientCode);
183
+ return [2];
184
+ }
185
+ });
186
+ });
187
+ };
188
+ return ClientUtil;
189
+ }());
190
+ exports.ClientUtil = ClientUtil;
@@ -77,8 +77,8 @@ require("reflect-metadata");
77
77
  var common_1 = require("@nestjs/common");
78
78
  var _ = require("lodash");
79
79
  var string_util_class_1 = require("@open-norantec/utilities/dist/string-util.class");
80
+ var uuid_util_class_1 = require("@open-norantec/utilities/dist/uuid-util.class");
80
81
  var common_2 = require("@nestjs/common");
81
- var uuid_1 = require("uuid");
82
82
  var headers_constant_1 = require("../constants/headers.constant");
83
83
  var core_1 = require("@nestjs/core");
84
84
  var auth_adapter_decorator_1 = require("../decorators/auth-adapter.decorator");
@@ -86,6 +86,7 @@ var rxjs_1 = require("rxjs");
86
86
  var operators_1 = require("rxjs/operators");
87
87
  var logger_service_1 = require("../modules/logger/logger.service");
88
88
  var sequelize_typescript_1 = require("sequelize-typescript");
89
+ var decorators_1 = require("../decorators");
89
90
  var IS_CONTROLLER = Symbol();
90
91
  function isHerbalController(target) {
91
92
  return _.attempt(function () { return Reflect.getMetadata(IS_CONTROLLER, target.prototype); }) === true;
@@ -102,9 +103,6 @@ var ControllerInterceptor = (function () {
102
103
  _.attempt(function () {
103
104
  _this.getLogger().log("[trace:".concat(request === null || request === void 0 ? void 0 : request.traceId, ":response:url] ").concat(request === null || request === void 0 ? void 0 : request.originalUrl));
104
105
  });
105
- _.attempt(function () {
106
- return _this.getLogger().log("[trace:".concat(request === null || request === void 0 ? void 0 : request.traceId, ":request:body] ").concat(JSON.stringify(request === null || request === void 0 ? void 0 : request.body)));
107
- });
108
106
  _.attempt(function () {
109
107
  return _this.getLogger().log("[trace:".concat(request === null || request === void 0 ? void 0 : request.traceId, ":request:headers] ").concat(JSON.stringify(request === null || request === void 0 ? void 0 : request.headers)));
110
108
  });
@@ -139,6 +137,7 @@ var ControllerInterceptor = (function () {
139
137
  _.attempt(function () {
140
138
  _this.getLogger().error("[trace:".concat(request === null || request === void 0 ? void 0 : request.traceId, ":response:error:stack] ").concat(error === null || error === void 0 ? void 0 : error.stack));
141
139
  });
140
+ _this.getLogger().error("Got error when handling route in interceptor: ".concat(error === null || error === void 0 ? void 0 : error.message, " ").concat(error === null || error === void 0 ? void 0 : error.stack));
142
141
  _.attempt(function () { var _a, _b, _c, _d; return (_d = (_c = (_b = (_a = request === null || request === void 0 ? void 0 : request.transaction) === null || _a === void 0 ? void 0 : _a.rollback) === null || _b === void 0 ? void 0 : _b.call(_a)) === null || _c === void 0 ? void 0 : _c.catch) === null || _d === void 0 ? void 0 : _d.call(_c, function () { }); });
143
142
  return (0, rxjs_1.throwError)(function () { return error; });
144
143
  }));
@@ -156,72 +155,67 @@ function HerbalGuard(options) {
156
155
  }
157
156
  HerbalGuardMixin.prototype.canActivate = function (context) {
158
157
  var _a, e_1, _b, _c;
159
- var _d, _e, _f, _g, _h;
158
+ var _d, _e, _f, _g, _h, _j, _k;
160
159
  return __awaiter(this, void 0, void 0, function () {
161
- var sequelizeInstance, transaction, request, response, traceId, chunks, _j, request_1, request_1_1, chunk, e_1_1, _k, parsedBody, authAdapters, _i, authAdapters_1, AuthAdapterClass, adapter, authenticateResult, error_1, _l;
160
+ var sequelizeInstance, transaction, request, response, traceId, chunks, _l, request_1, request_1_1, chunk, e_1_1, _m, parsedBody, rawHandlerName, handlerPropertype, handlerName, authAdapters, error_1, _i, authAdapters_1, AuthAdapterClass, adapter, authenticateResult, error_2, _o;
162
161
  var _this = this;
163
- return __generator(this, function (_m) {
164
- switch (_m.label) {
162
+ return __generator(this, function (_p) {
163
+ switch (_p.label) {
165
164
  case 0:
166
165
  sequelizeInstance = _.attempt(function () { return _this.ref.get(sequelize_typescript_1.Sequelize, { strict: false }); });
167
166
  transaction = undefined;
168
- if (!!(sequelizeInstance instanceof Error)) return [3, 2];
169
- return [4, ((_e = (_d = sequelizeInstance === null || sequelizeInstance === void 0 ? void 0 : sequelizeInstance.transaction) === null || _d === void 0 ? void 0 : _d.call(sequelizeInstance)) === null || _e === void 0 ? void 0 : _e.catch(function () { return Promise.resolve(undefined); }))];
170
- case 1:
171
- transaction = _m.sent();
172
- _m.label = 2;
173
- case 2:
174
167
  request = context.switchToHttp().getRequest();
175
168
  response = context.switchToHttp().getResponse();
176
- traceId = typeof (options === null || options === void 0 ? void 0 : options.getTraceId) === 'function' ? _.attempt(function () { return options.getTraceId(request); }) : (0, uuid_1.v4)();
177
- if (traceId instanceof Error)
178
- traceId = (0, uuid_1.v4)();
169
+ traceId = typeof (options === null || options === void 0 ? void 0 : options.getTraceId) === 'function'
170
+ ? _.attempt(function () { return options.getTraceId(request); })
171
+ : uuid_util_class_1.UUIDUtil.generateV4();
172
+ if (traceId instanceof Error || string_util_class_1.StringUtil.isFalsyString(traceId))
173
+ traceId = uuid_util_class_1.UUIDUtil.generateV4();
179
174
  request.traceId = traceId;
180
175
  request.methodName = request.url.split('/').pop();
181
- request.transaction = transaction;
182
176
  response.setHeader(headers_constant_1.HEADERS.TRACE_ID, traceId);
183
177
  chunks = [];
184
- _m.label = 3;
185
- case 3:
186
- _m.trys.push([3, 16, , 17]);
187
- _m.label = 4;
178
+ _p.label = 1;
179
+ case 1:
180
+ _p.trys.push([1, 14, , 15]);
181
+ _p.label = 2;
182
+ case 2:
183
+ _p.trys.push([2, 7, 8, 13]);
184
+ _l = true, request_1 = __asyncValues(request);
185
+ _p.label = 3;
186
+ case 3: return [4, request_1.next()];
188
187
  case 4:
189
- _m.trys.push([4, 9, 10, 15]);
190
- _j = true, request_1 = __asyncValues(request);
191
- _m.label = 5;
192
- case 5: return [4, request_1.next()];
193
- case 6:
194
- if (!(request_1_1 = _m.sent(), _a = request_1_1.done, !_a)) return [3, 8];
188
+ if (!(request_1_1 = _p.sent(), _a = request_1_1.done, !_a)) return [3, 6];
195
189
  _c = request_1_1.value;
196
- _j = false;
190
+ _l = false;
197
191
  chunk = _c;
198
192
  chunks.push(chunk);
199
- _m.label = 7;
193
+ _p.label = 5;
194
+ case 5:
195
+ _l = true;
196
+ return [3, 3];
197
+ case 6: return [3, 13];
200
198
  case 7:
201
- _j = true;
202
- return [3, 5];
203
- case 8: return [3, 15];
204
- case 9:
205
- e_1_1 = _m.sent();
199
+ e_1_1 = _p.sent();
206
200
  e_1 = { error: e_1_1 };
207
- return [3, 15];
208
- case 10:
209
- _m.trys.push([10, , 13, 14]);
210
- if (!(!_j && !_a && (_b = request_1.return))) return [3, 12];
201
+ return [3, 13];
202
+ case 8:
203
+ _p.trys.push([8, , 11, 12]);
204
+ if (!(!_l && !_a && (_b = request_1.return))) return [3, 10];
211
205
  return [4, _b.call(request_1)];
206
+ case 9:
207
+ _p.sent();
208
+ _p.label = 10;
209
+ case 10: return [3, 12];
212
210
  case 11:
213
- _m.sent();
214
- _m.label = 12;
215
- case 12: return [3, 14];
216
- case 13:
217
211
  if (e_1) throw e_1.error;
218
212
  return [7];
219
- case 14: return [7];
220
- case 15: return [3, 17];
221
- case 16:
222
- _k = _m.sent();
223
- return [3, 17];
224
- case 17:
213
+ case 12: return [7];
214
+ case 13: return [3, 15];
215
+ case 14:
216
+ _m = _p.sent();
217
+ return [3, 15];
218
+ case 15:
225
219
  parsedBody = _.attempt(function () { return Buffer.concat(chunks).toString('utf8'); });
226
220
  if (!(parsedBody instanceof Error)) {
227
221
  request.rawBody = parsedBody;
@@ -229,49 +223,87 @@ function HerbalGuard(options) {
229
223
  else {
230
224
  request.rawBody = null;
231
225
  }
232
- authAdapters = auth_adapter_decorator_1.AuthAdapters.getAdapters((_g = (_f = context === null || context === void 0 ? void 0 : context.getClass) === null || _f === void 0 ? void 0 : _f.call(context)) === null || _g === void 0 ? void 0 : _g.prototype, request.methodName);
233
- _m.label = 18;
226
+ _.attempt(function () { return _this.getLogger().log("[trace:".concat(request === null || request === void 0 ? void 0 : request.traceId, ":request:body] ").concat(request.rawBody)); });
227
+ rawHandlerName = (_e = (_d = context === null || context === void 0 ? void 0 : context.getHandler) === null || _d === void 0 ? void 0 : _d.call(context)) === null || _e === void 0 ? void 0 : _e.name;
228
+ handlerPropertype = (_g = (_f = context === null || context === void 0 ? void 0 : context.getClass) === null || _f === void 0 ? void 0 : _f.call(context)) === null || _g === void 0 ? void 0 : _g.prototype;
229
+ handlerName = string_util_class_1.StringUtil.isFalsyString(rawHandlerName) ? request.methodName : rawHandlerName;
230
+ authAdapters = auth_adapter_decorator_1.AuthAdapters.getAdapters(handlerPropertype, handlerName);
231
+ if (!(!(sequelizeInstance instanceof Error) && !decorators_1.NoTransaction.isDisabled(handlerPropertype, handlerName))) return [3, 20];
232
+ _p.label = 16;
233
+ case 16:
234
+ _p.trys.push([16, 18, , 19]);
235
+ return [4, ((_j = (_h = sequelizeInstance === null || sequelizeInstance === void 0 ? void 0 : sequelizeInstance.transaction) === null || _h === void 0 ? void 0 : _h.call(sequelizeInstance)) === null || _j === void 0 ? void 0 : _j.catch(function () { return Promise.resolve(undefined); }))];
236
+ case 17:
237
+ transaction = _p.sent();
238
+ request.transaction = transaction;
239
+ this.getLogger().log("[trace:".concat(request === null || request === void 0 ? void 0 : request.traceId, ":transaction] Started transaction for route: ").concat(handlerName));
240
+ return [3, 19];
234
241
  case 18:
235
- _m.trys.push([18, 24, , 29]);
236
- if (!(Array.isArray(authAdapters) && authAdapters.length > 0)) return [3, 23];
242
+ error_1 = _p.sent();
243
+ if (error_1 instanceof Error) {
244
+ this.getLogger().error("[trace:".concat(request === null || request === void 0 ? void 0 : request.traceId, ":transaction] Failed to start transaction: ").concat(error_1 === null || error_1 === void 0 ? void 0 : error_1.message, "\n").concat(error_1 === null || error_1 === void 0 ? void 0 : error_1.stack));
245
+ }
246
+ return [3, 19];
247
+ case 19: return [3, 21];
248
+ case 20:
249
+ if (decorators_1.NoTransaction.isDisabled(handlerPropertype, handlerName)) {
250
+ this.getLogger().log("[trace:".concat(request === null || request === void 0 ? void 0 : request.traceId, ":transaction] Transaction is disabled for this route: ").concat(handlerName));
251
+ }
252
+ _p.label = 21;
253
+ case 21:
254
+ _p.trys.push([21, 27, , 32]);
255
+ if (!(Array.isArray(authAdapters) && authAdapters.length > 0)) return [3, 26];
237
256
  _i = 0, authAdapters_1 = authAdapters;
238
- _m.label = 19;
239
- case 19:
240
- if (!(_i < authAdapters_1.length)) return [3, 22];
257
+ _p.label = 22;
258
+ case 22:
259
+ if (!(_i < authAdapters_1.length)) return [3, 25];
241
260
  AuthAdapterClass = authAdapters_1[_i];
242
261
  adapter = new AuthAdapterClass(request, this.ref);
243
262
  if (!adapter.match())
244
- return [3, 21];
263
+ return [3, 24];
245
264
  return [4, adapter.authenticate(transaction)];
246
- case 20:
247
- authenticateResult = _m.sent();
265
+ case 23:
266
+ authenticateResult = _p.sent();
248
267
  if (!authenticateResult)
249
- return [3, 22];
268
+ return [3, 25];
250
269
  request.authenticateResult = __assign({ AuthenticatorClass: AuthAdapterClass }, authenticateResult);
251
270
  return [2, true];
252
- case 21:
253
- _i++;
254
- return [3, 19];
255
- case 22: throw new common_2.UnauthorizedException();
256
- case 23: return [3, 29];
257
271
  case 24:
258
- error_1 = _m.sent();
259
- _m.label = 25;
260
- case 25:
261
- _m.trys.push([25, 27, , 28]);
262
- return [4, ((_h = transaction === null || transaction === void 0 ? void 0 : transaction.rollback) === null || _h === void 0 ? void 0 : _h.call(transaction))];
263
- case 26:
264
- _m.sent();
265
- return [3, 28];
272
+ _i++;
273
+ return [3, 22];
274
+ case 25: throw new common_2.UnauthorizedException();
275
+ case 26: return [3, 32];
266
276
  case 27:
267
- _l = _m.sent();
268
- return [3, 28];
269
- case 28: throw error_1;
270
- case 29: return [2, true];
277
+ error_2 = _p.sent();
278
+ _p.label = 28;
279
+ case 28:
280
+ _p.trys.push([28, 30, , 31]);
281
+ if (error_2 instanceof Error) {
282
+ this.getLogger().error("Got error when handling route: ".concat(error_2 === null || error_2 === void 0 ? void 0 : error_2.message, " ").concat(error_2 === null || error_2 === void 0 ? void 0 : error_2.stack));
283
+ }
284
+ return [4, ((_k = transaction === null || transaction === void 0 ? void 0 : transaction.rollback) === null || _k === void 0 ? void 0 : _k.call(transaction))];
285
+ case 29:
286
+ _p.sent();
287
+ return [3, 31];
288
+ case 30:
289
+ _o = _p.sent();
290
+ return [3, 31];
291
+ case 31: throw error_2;
292
+ case 32: return [2, true];
271
293
  }
272
294
  });
273
295
  });
274
296
  };
297
+ HerbalGuardMixin.prototype.getLogger = function () {
298
+ var loggerService = this.ref.get(logger_service_1.LoggerService, { strict: false });
299
+ if (!(loggerService instanceof logger_service_1.LoggerService)) {
300
+ return {
301
+ log: function () { },
302
+ error: function () { },
303
+ };
304
+ }
305
+ return loggerService;
306
+ };
275
307
  HerbalGuardMixin = __decorate([
276
308
  (0, common_2.Injectable)(),
277
309
  __metadata("design:paramtypes", [core_1.ModuleRef])
@@ -286,12 +318,13 @@ var ControllerUtil = (function () {
286
318
  ControllerUtil.create = function (createOptions) {
287
319
  function Controller(options) {
288
320
  return function (target) {
321
+ var _a;
289
322
  var finalPrefix = string_util_class_1.StringUtil.isFalsyString(options === null || options === void 0 ? void 0 : options.prefix)
290
323
  ? string_util_class_1.StringUtil.isFalsyString(createOptions === null || createOptions === void 0 ? void 0 : createOptions.prefix)
291
324
  ? ''
292
325
  : createOptions.prefix
293
326
  : options.prefix;
294
- finalPrefix += "/".concat(_.camelCase(target.name.replace(/Controller$/g, '')));
327
+ finalPrefix += "".concat(((_a = finalPrefix === null || finalPrefix === void 0 ? void 0 : finalPrefix.endsWith) === null || _a === void 0 ? void 0 : _a.call(finalPrefix, '/')) ? '' : '/').concat(_.camelCase(target.name.replace(/Controller$/g, '')));
295
328
  if (!finalPrefix.startsWith('/'))
296
329
  finalPrefix = "/".concat(finalPrefix);
297
330
  Reflect.defineMetadata(IS_CONTROLLER, true, target.prototype);
@@ -1,3 +1,4 @@
1
1
  export * from './controller-util.class';
2
2
  export * from './model-util.class';
3
3
  export * from './nest-util.class';
4
+ export * from './client-util.class';
@@ -17,3 +17,4 @@ Object.defineProperty(exports, "__esModule", { value: true });
17
17
  __exportStar(require("./controller-util.class"), exports);
18
18
  __exportStar(require("./model-util.class"), exports);
19
19
  __exportStar(require("./nest-util.class"), exports);
20
+ __exportStar(require("./client-util.class"), exports);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@open-norantec/herbal",
3
- "version": "1.0.2-alpha.1",
3
+ "version": "1.0.2-alpha.10",
4
4
  "description": "Herbal is a builder and toolchain for Nest.js applications",
5
5
  "main": "dist/index.js",
6
6
  "scripts": {
@@ -41,24 +41,30 @@
41
41
  "@open-norantec/forge": "latest",
42
42
  "@open-norantec/utilities": "latest",
43
43
  "commander": "^12.1.0",
44
+ "esbuild": "^0.28.0",
45
+ "fs-extra": "^11.3.4",
44
46
  "lodash": "^4.17.21",
45
47
  "nest-winston": "^1.10.2",
46
48
  "nj-request-scope": "^1.0.10",
47
49
  "patch-package": "^8.0.1",
48
50
  "reflect-metadata": "^0.2.2",
51
+ "require-from-string": "^2.0.2",
49
52
  "rxjs": "^7.8.2",
50
53
  "sequelize": "6.37.7",
51
54
  "sequelize-typescript": "^2.1.5",
52
55
  "ts-patch": "^3.3.0",
53
56
  "type-fest": "^4.41.0",
57
+ "typescript": ">=5.1.0 <5.2.0",
54
58
  "uuid": "^11.1.0",
55
59
  "zod": "^3.25.67"
56
60
  },
57
61
  "devDependencies": {
58
62
  "@stylistic/eslint-plugin": "^2.12.1",
59
63
  "@types/express": "^5.0.3",
64
+ "@types/fs-extra": "^11.0.4",
60
65
  "@types/lodash": "^4.17.16",
61
66
  "@types/node": "18.11.18",
67
+ "@types/require-from-string": "^1.2.3",
62
68
  "@typescript-eslint/eslint-plugin": "^8.0.0",
63
69
  "@typescript-eslint/parser": "^8.0.0",
64
70
  "cross-env": "^7.0.3",
@@ -68,7 +74,6 @@
68
74
  "express": "^4.21.2",
69
75
  "prettier": "^3.0.0",
70
76
  "rimraf": "^6.0.1",
71
- "ts-node": "^10.0.0",
72
- "typescript": "~5.1.3"
77
+ "ts-node": "^10.0.0"
73
78
  }
74
79
  }