ts-forge 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +4 -0
- package/README.md +228 -0
- package/dist/constants.d.ts +5 -0
- package/dist/constants.js +4 -0
- package/dist/decorators/resolver.d.ts +20 -0
- package/dist/decorators/resolver.js +26 -0
- package/dist/decorators/resolverFn.d.ts +9 -0
- package/dist/decorators/resolverFn.js +135 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +3 -0
- package/dist/types/forge.d.ts +15 -0
- package/dist/types/forge.js +1 -0
- package/dist/types/index.d.ts +3 -0
- package/dist/types/index.js +3 -0
- package/dist/types/resolver.d.ts +29 -0
- package/dist/types/resolver.js +1 -0
- package/dist/types/utils.d.ts +6 -0
- package/dist/types/utils.js +1 -0
- package/dist/utils/getDefinitionsForClass.d.ts +10 -0
- package/dist/utils/getDefinitionsForClass.js +43 -0
- package/dist/utils/isResolverFnConfig.d.ts +2 -0
- package/dist/utils/isResolverFnConfig.js +6 -0
- package/package.json +35 -0
package/CHANGELOG.md
ADDED
package/README.md
ADDED
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
**Warning:** The first version of this library is ready, however documentation is still in progress
|
|
2
|
+
|
|
3
|
+
## @Resolver
|
|
4
|
+
|
|
5
|
+
```ts
|
|
6
|
+
import { Resolver, ResolverFn } from "ts-forge";
|
|
7
|
+
|
|
8
|
+
@Resolver({
|
|
9
|
+
middlewares: [authMiddleware, adminMiddleware],
|
|
10
|
+
errorHandler: myErrorHandler
|
|
11
|
+
})
|
|
12
|
+
class HelloWorldResolver {}
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
#### Parameters
|
|
16
|
+
|
|
17
|
+
Parameter 1 (Resolver config) - Optional
|
|
18
|
+
|
|
19
|
+
- `errorHandler: (error: any, request: Request) => any | Promise<any>`
|
|
20
|
+
- Optional
|
|
21
|
+
- If an error is thrown in your resolver function or middlewares, this function will be called so that you can handle the error and return a response
|
|
22
|
+
- `middlewares: ((request: Request) => any | Promise<any>)[]`
|
|
23
|
+
- Optional
|
|
24
|
+
- This is an array of middleware functions, each function will be called before the resolver function
|
|
25
|
+
- If you return a value it will be sent to the frontend, pending middlewares and resolver function won't be called
|
|
26
|
+
|
|
27
|
+
## @ResolverFn
|
|
28
|
+
|
|
29
|
+
```ts
|
|
30
|
+
import { Request } from "@forge/resolver";
|
|
31
|
+
import { Resolver, ResolverFn } from "ts-forge";
|
|
32
|
+
|
|
33
|
+
@Resolver()
|
|
34
|
+
class HelloWorldResolver {
|
|
35
|
+
@ResolverFn("my-resolver")
|
|
36
|
+
public async hello(req: Request) {
|
|
37
|
+
return { message: "Hello world!" };
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
#### Parameters
|
|
43
|
+
|
|
44
|
+
**Parameter 1 (Resolver key or resolver function config) - Required**
|
|
45
|
+
|
|
46
|
+
You could use either, a string or an object
|
|
47
|
+
|
|
48
|
+
**Resolver key**
|
|
49
|
+
|
|
50
|
+
- `string`
|
|
51
|
+
- Required
|
|
52
|
+
- This is the resolver key that you will use when you call `invoke()` method in your addon's UI
|
|
53
|
+
|
|
54
|
+
**Resolver function config**
|
|
55
|
+
|
|
56
|
+
- `{ key: string, middlewares?: MiddlewareFn[], errorHandler?: ErrorHandlerFn }`
|
|
57
|
+
- `key: string`
|
|
58
|
+
- Required
|
|
59
|
+
- This is the resolver key that you will use when you call `invoke()` method in your addon's UI
|
|
60
|
+
- `middlewares: ((request: Request) => any | Promise<any>)[]`
|
|
61
|
+
- Optional
|
|
62
|
+
- This is an array of middleware functions, each function will be called before the resolver function
|
|
63
|
+
- If you return a value it will be sent to the frontend, pending middlewares and resolver function won't be called
|
|
64
|
+
- `errorHandler: (error: any, request: Request) => any | Promise<any>`
|
|
65
|
+
- Optional
|
|
66
|
+
- If an error is thrown in your resolver function or middlewares, this function will be called so that you can handle the error and return a response
|
|
67
|
+
|
|
68
|
+
The `@ResolverFn()` decorator takes only one argument, which can be either a string or an object
|
|
69
|
+
If you don't need to define middlewares or an error handler, you could just pass the resolver key
|
|
70
|
+
|
|
71
|
+
```ts
|
|
72
|
+
@Resolver()
|
|
73
|
+
class HelloWorldResolver {
|
|
74
|
+
@ResolverFn("my-resolver")
|
|
75
|
+
async hello(req: Request) {}
|
|
76
|
+
}
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
or, if you need to define middlewares or an error handler for that resolver function, you could pass a config object like this:
|
|
80
|
+
|
|
81
|
+
```ts
|
|
82
|
+
@Resolver()
|
|
83
|
+
class HelloWorldResolver {
|
|
84
|
+
@ResolverFn({
|
|
85
|
+
key: "my-resolver",
|
|
86
|
+
middlewares: [authMiddleware, adminMiddleware],
|
|
87
|
+
errorHandler: myErrorHandler
|
|
88
|
+
})
|
|
89
|
+
async hello(req: Request) {}
|
|
90
|
+
}
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
## getDefinitionsForClass
|
|
94
|
+
|
|
95
|
+
This function is used to get definitions of the resolvers that you created, it uses `@forge/resolver` under the hood to define resolvers then calls `getDefinitions()` method and returns its result
|
|
96
|
+
|
|
97
|
+
```ts
|
|
98
|
+
import { getDefinitionsForClass } from "ts-forge";
|
|
99
|
+
|
|
100
|
+
getDefinitionsForClass({
|
|
101
|
+
resolvers: [HelloWorldResolver, GetJiraProjectResolver],
|
|
102
|
+
errorHandler: ErrorHandlerFn,
|
|
103
|
+
middlewares: MiddlewareFn[]
|
|
104
|
+
});
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
#### Parameters
|
|
108
|
+
|
|
109
|
+
**Parameter 1 (Config) - Required**
|
|
110
|
+
|
|
111
|
+
- `{ resolvers: [], middlewares: MiddlewareFn[], errorHandler: ErrorHandlerFn }`
|
|
112
|
+
- `resolvers`
|
|
113
|
+
- Required
|
|
114
|
+
- This is an array of class instances in which you used the `@Resolver()` decorator
|
|
115
|
+
- Must have at least one element
|
|
116
|
+
- `middlewares: ((request: Request) => any | Promise<any>)[]`
|
|
117
|
+
- Optional
|
|
118
|
+
- This is an array of middleware functions, each function will be called before the resolver function
|
|
119
|
+
- If you return a value it will be sent to the frontend, pending middlewares and resolver function won't be called
|
|
120
|
+
- Those middlewares will be called before each resolver function defined in `resolvers`
|
|
121
|
+
- **Note:** Middlewares defined here will be the last to be called, in case you have defined middlewares in `@Resolver()` or `@ResolverFn()`
|
|
122
|
+
- `errorHandler: (error: any, request: Request) => any | Promise<any>`
|
|
123
|
+
- Optional
|
|
124
|
+
- If an error is thrown in your resolver function or middlewares, this function will be called so that you can handle the error and return a response
|
|
125
|
+
- This function will handle errors for all the resolver functions defined in `resolvers`
|
|
126
|
+
- **Note:** This function will be called only when an error handler was not defined in `@Resolver()` and `@ResolverFn()`
|
|
127
|
+
|
|
128
|
+
## Middlewares
|
|
129
|
+
|
|
130
|
+
You can define middlewares in `@ResolverFn()`, `@Resolver()` and `getDefinitionsForClass()`. It only takes one parameter which is the same request object you have access to in resolver functions
|
|
131
|
+
|
|
132
|
+
Middleware functions have priority depending where they were defined. When a resolver function is invoked, the middlewares will be called in the following order:
|
|
133
|
+
|
|
134
|
+
1. `@ResolverFn()`: Middlewares defined in this decorator's config will be the first to be called
|
|
135
|
+
2. `@Resolver()`: Middlewares defined in this decorator's config will run after `@ResolverFn()`'s middlewares are called. If no middlewares were defined in `@ResolverFn()`, middlewares defined in `@Resolver()` would be the first to be called
|
|
136
|
+
3. `getDefinitionsForClass()`: Middlewares defined in this function will be the last to be called. If no middlewares were defined in `@ResolverFn()` and `@Resolver()`, middlewares defined in `getDefinitionsForClass()` would be the first to be called, this is useful when you want the same middlewares to be called for all of your resolver functions, so that you don't have to define the same middlewares in each `@ResolverFn()` or `@Resolver()`
|
|
137
|
+
|
|
138
|
+
#### Usage
|
|
139
|
+
|
|
140
|
+
This is an example of a middleware function
|
|
141
|
+
|
|
142
|
+
```ts
|
|
143
|
+
import { Request } from "@forge/resolver";
|
|
144
|
+
|
|
145
|
+
// Request is the same object you have access to in your resolver functions
|
|
146
|
+
function verifyUserIsJiraAdmin(request: Request): any | Promise<any> {
|
|
147
|
+
// Verify that the current user is a jira admin ...
|
|
148
|
+
}
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
Then you can use this middleware in `@ResolverFn()`, `@Resolver()` or `getDefinitionsForClass()`
|
|
152
|
+
|
|
153
|
+
In the following example the `verifyUserIsJiraAdmin` middleware is used in `@ResolverFn()`. This is useful when you want certain middleware to be called for some resolver functions
|
|
154
|
+
|
|
155
|
+
```ts
|
|
156
|
+
@Resolver()
|
|
157
|
+
class HelloWorldResolver {
|
|
158
|
+
@ResolverFn({
|
|
159
|
+
key: "hello-world",
|
|
160
|
+
middlewares: [verifyUserIsJiraAdmin]
|
|
161
|
+
})
|
|
162
|
+
async helloWorld() {
|
|
163
|
+
// Do whatever this resolver should do
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// verifyUserIsJiraAdmin won't be called when this resolver function is invoked
|
|
167
|
+
@ResolverFn({
|
|
168
|
+
key: "get-current-user",
|
|
169
|
+
middlewares: []
|
|
170
|
+
})
|
|
171
|
+
async getCurrentUser() {
|
|
172
|
+
// Return current user
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
In this example the `verifyUserIsJiraAdmin` middleware is used in `@Resolver()`. Middlewares defined in this decorator will be called for all resolver functions defined in the class.
|
|
178
|
+
|
|
179
|
+
```ts
|
|
180
|
+
@Resolver({
|
|
181
|
+
// Middlewares defined in this array will be called in each resolver function defined in this class
|
|
182
|
+
middlewares: [verifyUserIsJiraAdmin]
|
|
183
|
+
})
|
|
184
|
+
class HelloWorldResolver {
|
|
185
|
+
// There's no need to add the same middleware in @ResolverFn()
|
|
186
|
+
@ResolverFn("hello-world")
|
|
187
|
+
async helloWorld() {
|
|
188
|
+
// Do whatever this resolver should do
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// verifyUserIsJiraAdmin will also be called before this resolver function
|
|
192
|
+
@ResolverFn("get-current-user")
|
|
193
|
+
async getCurrentUser() {
|
|
194
|
+
// Return current user
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
Last but not least, you can define middlewares in the `getDefinitionsForClass` function. Middlewares defined here will be called in all resolvers that you pass to the `resolvers` array
|
|
200
|
+
|
|
201
|
+
```ts
|
|
202
|
+
@Resolver()
|
|
203
|
+
class HelloWorldResolver {
|
|
204
|
+
@ResolverFn("hello-world")
|
|
205
|
+
helloWorld(request: Request) {
|
|
206
|
+
return { message: "Hello world!" };
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
@Resolver()
|
|
211
|
+
class UserResolver {
|
|
212
|
+
@ResolverFn("get-user")
|
|
213
|
+
getUser(request: Request) {
|
|
214
|
+
return {...};
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
const definitions = getDefinitionsForClass({
|
|
219
|
+
middlewares: [verifyUserIsJiraAdmin],
|
|
220
|
+
// Middlewares will be called before each resolver function, you don't need to add the verifyUserIsJiraAdmin middleware
|
|
221
|
+
// in @Resolver or @ResolverFn decorators
|
|
222
|
+
resolvers: [HelloWorldResolver, UserResolver]
|
|
223
|
+
})
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
## Error handler
|
|
227
|
+
|
|
228
|
+
An error handler is a function that is called when an error is thrown in a resolver function
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { ResolverConfig } from "../types";
|
|
2
|
+
/**
|
|
3
|
+
* Decorator for defining forge resolvers.
|
|
4
|
+
* @param ResolverConfig - Configuration object for the resolver.
|
|
5
|
+
* @param ResolverConfig.middlewares - Array of middleware functions to be applied to the resolver functions.
|
|
6
|
+
* @param ResolverConfig.errorHandler - Custom error handler function for the resolver functions.
|
|
7
|
+
* @returns A modified class with resolver configuration.
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```ts
|
|
11
|
+
* \@Resolver({
|
|
12
|
+
* middlewares: [myMiddleware],
|
|
13
|
+
* errorHandler: myErrorHandler,
|
|
14
|
+
* })
|
|
15
|
+
* class MyResolver{}
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
export declare function Resolver(config?: ResolverConfig): <T extends {
|
|
19
|
+
new (...args: any[]): {};
|
|
20
|
+
}>(constructor: T) => void;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import _ from "../constants";
|
|
2
|
+
/**
|
|
3
|
+
* Decorator for defining forge resolvers.
|
|
4
|
+
* @param ResolverConfig - Configuration object for the resolver.
|
|
5
|
+
* @param ResolverConfig.middlewares - Array of middleware functions to be applied to the resolver functions.
|
|
6
|
+
* @param ResolverConfig.errorHandler - Custom error handler function for the resolver functions.
|
|
7
|
+
* @returns A modified class with resolver configuration.
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```ts
|
|
11
|
+
* \@Resolver({
|
|
12
|
+
* middlewares: [myMiddleware],
|
|
13
|
+
* errorHandler: myErrorHandler,
|
|
14
|
+
* })
|
|
15
|
+
* class MyResolver{}
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
export function Resolver(config) {
|
|
19
|
+
if (config === void 0) { config = { middlewares: [], errorHandler: undefined }; }
|
|
20
|
+
return function (constructor) {
|
|
21
|
+
constructor.prototype[_.RESOLVER_CONFIG] = {
|
|
22
|
+
middlewares: Array.from(config.middlewares || []),
|
|
23
|
+
errorHandler: config.errorHandler
|
|
24
|
+
};
|
|
25
|
+
};
|
|
26
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { ResolverFnConfig } from "../types";
|
|
2
|
+
/**
|
|
3
|
+
* Define a resolver function
|
|
4
|
+
* @param resolverFnConfig - Resolver function config
|
|
5
|
+
* @param resolverFnConfig.middlewares - Array of middleware functions to be applied to this resolver function
|
|
6
|
+
* @param resolverFnConfig.errorHandler - Custom error handler function for this resolver function
|
|
7
|
+
* @returns - Response
|
|
8
|
+
*/
|
|
9
|
+
export declare function ResolverFn(resolverFnConfig: ResolverFnConfig | string): (target: any, propertyKey: string, descriptor: any) => void;
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
11
|
+
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
|
|
12
|
+
return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
13
|
+
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
14
|
+
function step(op) {
|
|
15
|
+
if (f) throw new TypeError("Generator is already executing.");
|
|
16
|
+
while (g && (g = 0, op[0] && (_ = 0)), _) try {
|
|
17
|
+
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;
|
|
18
|
+
if (y = 0, t) op = [op[0] & 2, t.value];
|
|
19
|
+
switch (op[0]) {
|
|
20
|
+
case 0: case 1: t = op; break;
|
|
21
|
+
case 4: _.label++; return { value: op[1], done: false };
|
|
22
|
+
case 5: _.label++; y = op[1]; op = [0]; continue;
|
|
23
|
+
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
|
24
|
+
default:
|
|
25
|
+
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
|
26
|
+
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
|
27
|
+
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
|
28
|
+
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
|
29
|
+
if (t[2]) _.ops.pop();
|
|
30
|
+
_.trys.pop(); continue;
|
|
31
|
+
}
|
|
32
|
+
op = body.call(thisArg, _);
|
|
33
|
+
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
|
34
|
+
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
import isResolverFnConfig from "../utils/isResolverFnConfig";
|
|
38
|
+
import _ from "../constants";
|
|
39
|
+
/**
|
|
40
|
+
* Define a resolver function
|
|
41
|
+
* @param resolverFnConfig - Resolver function config
|
|
42
|
+
* @param resolverFnConfig.middlewares - Array of middleware functions to be applied to this resolver function
|
|
43
|
+
* @param resolverFnConfig.errorHandler - Custom error handler function for this resolver function
|
|
44
|
+
* @returns - Response
|
|
45
|
+
*/
|
|
46
|
+
export function ResolverFn(resolverFnConfig) {
|
|
47
|
+
return function (target, propertyKey, descriptor) {
|
|
48
|
+
// Handle the case where resolverFnConfig is a string
|
|
49
|
+
var config = isResolverFnConfig(resolverFnConfig)
|
|
50
|
+
? resolverFnConfig
|
|
51
|
+
: { key: resolverFnConfig, middlewares: [], errorHandler: undefined };
|
|
52
|
+
// If the middlewares property is not an array, initialize it as an empty array
|
|
53
|
+
if (!Array.isArray(config.middlewares)) {
|
|
54
|
+
config.middlewares = [];
|
|
55
|
+
}
|
|
56
|
+
// Check if the target has the resolverNames property
|
|
57
|
+
if (!target[_.RESOLVER_FUNCTIONS]) {
|
|
58
|
+
target[_.RESOLVER_FUNCTIONS] = [];
|
|
59
|
+
}
|
|
60
|
+
// Add the resolver's data to the target
|
|
61
|
+
target[_.RESOLVER_FUNCTIONS].push({
|
|
62
|
+
config: config,
|
|
63
|
+
methodName: propertyKey
|
|
64
|
+
});
|
|
65
|
+
var method = descriptor.value;
|
|
66
|
+
descriptor.value = function (req) {
|
|
67
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
68
|
+
var targetConfig, middlewares, _i, middlewares_1, middleware, response, error_1, errorHandlerFn, err_1;
|
|
69
|
+
return __generator(this, function (_a) {
|
|
70
|
+
switch (_a.label) {
|
|
71
|
+
case 0:
|
|
72
|
+
targetConfig = this[_.RESOLVER_CONFIG] || {};
|
|
73
|
+
_a.label = 1;
|
|
74
|
+
case 1:
|
|
75
|
+
_a.trys.push([1, 7, , 12]);
|
|
76
|
+
middlewares = Array.from(config.middlewares || []);
|
|
77
|
+
// If there are middlewares defined in the resolver class, add them to the middlewares array
|
|
78
|
+
if (Array.isArray(targetConfig.middlewares)) {
|
|
79
|
+
middlewares.push.apply(middlewares, targetConfig.middlewares);
|
|
80
|
+
}
|
|
81
|
+
// If there are middlewares defined in the getDefinitionsForClass config, add them to the middlewares array
|
|
82
|
+
if (Array.isArray(targetConfig.globalMiddlewares)) {
|
|
83
|
+
middlewares.push.apply(middlewares, targetConfig.globalMiddlewares);
|
|
84
|
+
}
|
|
85
|
+
_i = 0, middlewares_1 = middlewares;
|
|
86
|
+
_a.label = 2;
|
|
87
|
+
case 2:
|
|
88
|
+
if (!(_i < middlewares_1.length)) return [3 /*break*/, 5];
|
|
89
|
+
middleware = middlewares_1[_i];
|
|
90
|
+
return [4 /*yield*/, middleware(req)];
|
|
91
|
+
case 3:
|
|
92
|
+
response = _a.sent();
|
|
93
|
+
// If response is provided, send it to the frontend
|
|
94
|
+
// This means that the resolver or next middleware will not be called
|
|
95
|
+
if (response) {
|
|
96
|
+
return [2 /*return*/, response];
|
|
97
|
+
}
|
|
98
|
+
_a.label = 4;
|
|
99
|
+
case 4:
|
|
100
|
+
_i++;
|
|
101
|
+
return [3 /*break*/, 2];
|
|
102
|
+
case 5: return [4 /*yield*/, method.call(this, req)];
|
|
103
|
+
case 6:
|
|
104
|
+
// Call the original method
|
|
105
|
+
return [2 /*return*/, _a.sent()];
|
|
106
|
+
case 7:
|
|
107
|
+
error_1 = _a.sent();
|
|
108
|
+
errorHandlerFn = config.errorHandler || (targetConfig === null || targetConfig === void 0 ? void 0 : targetConfig.errorHandler) || (targetConfig === null || targetConfig === void 0 ? void 0 : targetConfig.globalErrorHandler);
|
|
109
|
+
if (!errorHandlerFn) return [3 /*break*/, 11];
|
|
110
|
+
_a.label = 8;
|
|
111
|
+
case 8:
|
|
112
|
+
_a.trys.push([8, 10, , 11]);
|
|
113
|
+
req.context.resolver = {
|
|
114
|
+
key: config.key,
|
|
115
|
+
className: target.constructor.name,
|
|
116
|
+
methodName: propertyKey
|
|
117
|
+
};
|
|
118
|
+
return [4 /*yield*/, errorHandlerFn(error_1, req)];
|
|
119
|
+
case 9: return [2 /*return*/, _a.sent()];
|
|
120
|
+
case 10:
|
|
121
|
+
err_1 = _a.sent();
|
|
122
|
+
// If the error handler throws an error, log it and return the original error
|
|
123
|
+
console.error(err_1);
|
|
124
|
+
return [2 /*return*/, error_1];
|
|
125
|
+
case 11:
|
|
126
|
+
// If no error handler is provided, log the error, then return it
|
|
127
|
+
console.error(error_1);
|
|
128
|
+
return [2 /*return*/, error_1];
|
|
129
|
+
case 12: return [2 /*return*/];
|
|
130
|
+
}
|
|
131
|
+
});
|
|
132
|
+
});
|
|
133
|
+
};
|
|
134
|
+
};
|
|
135
|
+
}
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { ResolverFunction, Request } from "@forge/resolver";
|
|
2
|
+
interface InvokePayload {
|
|
3
|
+
call: {
|
|
4
|
+
functionKey: string;
|
|
5
|
+
payload?: {
|
|
6
|
+
[key in number | string]: any;
|
|
7
|
+
};
|
|
8
|
+
jobId?: string;
|
|
9
|
+
};
|
|
10
|
+
context: {
|
|
11
|
+
[key: string]: any;
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
export type DefinitionsHandler = (payload: InvokePayload, backendRuntimePayload?: Request["payload"]) => Promise<ReturnType<ResolverFunction>>;
|
|
15
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { Request } from "@forge/resolver";
|
|
2
|
+
export interface ResolverConfig {
|
|
3
|
+
middlewares?: MiddlewareFn[];
|
|
4
|
+
errorHandler?: ErrorHandlerFn;
|
|
5
|
+
}
|
|
6
|
+
export interface ResolverClassConfig extends ResolverConfig {
|
|
7
|
+
globalMiddlewares?: MiddlewareFn[];
|
|
8
|
+
globalErrorHandler?: ErrorHandlerFn;
|
|
9
|
+
}
|
|
10
|
+
export type MiddlewareFn = (req: Request) => Promise<any> | any;
|
|
11
|
+
export type ErrorHandlerFn = (error: any, req: RequestError) => any;
|
|
12
|
+
export type RequestError = Request & {
|
|
13
|
+
context: Request["context"] & {
|
|
14
|
+
resolver: {
|
|
15
|
+
key: string;
|
|
16
|
+
className: string;
|
|
17
|
+
methodName: string;
|
|
18
|
+
};
|
|
19
|
+
};
|
|
20
|
+
};
|
|
21
|
+
export interface ResolverFnConfig {
|
|
22
|
+
key: string;
|
|
23
|
+
middlewares?: MiddlewareFn[];
|
|
24
|
+
errorHandler?: ErrorHandlerFn;
|
|
25
|
+
}
|
|
26
|
+
export interface TargetResolverFnConfig {
|
|
27
|
+
config: ResolverFnConfig;
|
|
28
|
+
methodName: string;
|
|
29
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { DefinitionsHandler, GetDefinitionsForClassParams } from "@/types";
|
|
2
|
+
/**
|
|
3
|
+
* Get definitions for the provided resolvers
|
|
4
|
+
* @param config - Config
|
|
5
|
+
* @param config.resolvers - Array of resolvers
|
|
6
|
+
* @param config.middlewares - Array of middlewares to be applied to the provided resolvers
|
|
7
|
+
* @param config.errorHandler - Custom error handler to be applied to the provided resolvers
|
|
8
|
+
* @returns - Resolver definitions
|
|
9
|
+
*/
|
|
10
|
+
export declare function getDefinitionsForClass({ resolvers, middlewares, errorHandler }: GetDefinitionsForClassParams): DefinitionsHandler;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import ForgeResolver from "@forge/resolver";
|
|
2
|
+
import _ from "../constants";
|
|
3
|
+
/**
|
|
4
|
+
* Get definitions for the provided resolvers
|
|
5
|
+
* @param config - Config
|
|
6
|
+
* @param config.resolvers - Array of resolvers
|
|
7
|
+
* @param config.middlewares - Array of middlewares to be applied to the provided resolvers
|
|
8
|
+
* @param config.errorHandler - Custom error handler to be applied to the provided resolvers
|
|
9
|
+
* @returns - Resolver definitions
|
|
10
|
+
*/
|
|
11
|
+
export function getDefinitionsForClass(_a) {
|
|
12
|
+
var resolvers = _a.resolvers, _b = _a.middlewares, middlewares = _b === void 0 ? [] : _b, errorHandler = _a.errorHandler;
|
|
13
|
+
var forgeResolver = new ForgeResolver();
|
|
14
|
+
if (!Array.isArray(middlewares)) {
|
|
15
|
+
throw new Error("Middlewares must be an array");
|
|
16
|
+
}
|
|
17
|
+
if (middlewares.length > 0 && !middlewares.every(function (m) { return typeof m === "function"; })) {
|
|
18
|
+
throw new Error("All middlewares must be functions");
|
|
19
|
+
}
|
|
20
|
+
if (errorHandler && typeof errorHandler !== "function") {
|
|
21
|
+
throw new Error("Error handler must be a function");
|
|
22
|
+
}
|
|
23
|
+
for (var _i = 0, resolvers_1 = resolvers; _i < resolvers_1.length; _i++) {
|
|
24
|
+
var instance = resolvers_1[_i];
|
|
25
|
+
if (instance[_.RESOLVER_CONFIG]) {
|
|
26
|
+
// Set global middlewares and error handler for the resolver class
|
|
27
|
+
var instanceConfig = {
|
|
28
|
+
middlewares: Array.from(instance[_.RESOLVER_CONFIG].middlewares || []),
|
|
29
|
+
errorHandler: instance[_.RESOLVER_CONFIG].errorHandler
|
|
30
|
+
};
|
|
31
|
+
instanceConfig.globalMiddlewares = Array.from(middlewares);
|
|
32
|
+
// Set the global error handler
|
|
33
|
+
instanceConfig.globalErrorHandler = errorHandler;
|
|
34
|
+
// Set the updated config on the instance
|
|
35
|
+
instance[_.RESOLVER_CONFIG] = instanceConfig;
|
|
36
|
+
}
|
|
37
|
+
for (var _c = 0, _d = instance[_.RESOLVER_FUNCTIONS]; _c < _d.length; _c++) {
|
|
38
|
+
var resolver = _d[_c];
|
|
39
|
+
forgeResolver.define(resolver.config.key, instance[resolver.methodName].bind(instance));
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return forgeResolver.getDefinitions();
|
|
43
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export default function isResolverFnConfig(config) {
|
|
2
|
+
return (typeof config === "object" &&
|
|
3
|
+
typeof config.key === "string" &&
|
|
4
|
+
(typeof config.middlewares === "undefined" || Array.isArray(config.middlewares)) &&
|
|
5
|
+
(typeof config.errorHandler === "undefined" || typeof config.errorHandler === "function"));
|
|
6
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "ts-forge",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"main": "dist/index.js",
|
|
5
|
+
"scripts": {
|
|
6
|
+
"test": "vitest --run",
|
|
7
|
+
"test:ui": "vitest --ui",
|
|
8
|
+
"test:watch": "vitest",
|
|
9
|
+
"test:coverage": "vitest --run --coverage",
|
|
10
|
+
"dev": "tsc -p ./tsconfig.json --watch",
|
|
11
|
+
"build": "eval $(rm -r dist) && tsc -p ./tsconfig.json",
|
|
12
|
+
"prepublish": "npm run build"
|
|
13
|
+
},
|
|
14
|
+
"repository": {
|
|
15
|
+
"type": "git",
|
|
16
|
+
"url": "https://www.github.com/gustavo0197/ts-forge"
|
|
17
|
+
},
|
|
18
|
+
"keywords": [
|
|
19
|
+
"forge",
|
|
20
|
+
"atlassian",
|
|
21
|
+
"addon"
|
|
22
|
+
],
|
|
23
|
+
"author": "Gustavo Velazquez",
|
|
24
|
+
"license": "ISC",
|
|
25
|
+
"description": "Decorators for creating resolvers in Atlassian's Forge addons",
|
|
26
|
+
"peerDependencies": {
|
|
27
|
+
"@forge/resolver": ">=1.6.0 <2.0.0"
|
|
28
|
+
},
|
|
29
|
+
"devDependencies": {
|
|
30
|
+
"@vitest/coverage-v8": "3.1.4",
|
|
31
|
+
"jsdom": "^26.1.0",
|
|
32
|
+
"typescript": "5.8.3",
|
|
33
|
+
"vitest": "^3.1.4"
|
|
34
|
+
}
|
|
35
|
+
}
|