@flink-app/management-actions-plugin 0.12.1-alpha.9 → 0.13.1
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/.flink/generatedHandlers.ts +8 -0
- package/.flink/generatedJobs.ts +5 -0
- package/.flink/generatedRepos.ts +5 -0
- package/.flink/schemas/schemas.json +5 -0
- package/.flink/schemas/schemas.ts +1 -0
- package/.flink/start.ts +6 -0
- package/CHANGELOG.md +13 -0
- package/dist/handlers/Get.js +2 -2
- package/dist/handlers/PostById.js +2 -2
- package/package.json +26 -29
- package/readme.md +363 -44
- package/tsconfig.json +1 -1
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
// Generated Sat Jan 10 2026 11:13:33 GMT+0100 (Central European Standard Time)
|
|
2
|
+
import { autoRegisteredHandlers, HttpMethod } from "@flink-app/flink";
|
|
3
|
+
import * as Get_0 from "../src/handlers/Get";
|
|
4
|
+
import * as PostById_0 from "../src/handlers/PostById";
|
|
5
|
+
|
|
6
|
+
export const handlers = [];
|
|
7
|
+
autoRegisteredHandlers.push(...handlers);
|
|
8
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
// Generated Sat Jan 10 2026 11:13:33 GMT+0100 (Central European Standard Time)
|
package/.flink/start.ts
ADDED
package/CHANGELOG.md
ADDED
package/dist/handlers/Get.js
CHANGED
|
@@ -9,8 +9,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
9
9
|
});
|
|
10
10
|
};
|
|
11
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 =
|
|
12
|
+
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);
|
|
13
|
+
return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
14
14
|
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
15
15
|
function step(op) {
|
|
16
16
|
if (f) throw new TypeError("Generator is already executing.");
|
|
@@ -9,8 +9,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
9
9
|
});
|
|
10
10
|
};
|
|
11
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 =
|
|
12
|
+
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);
|
|
13
|
+
return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
14
14
|
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
15
15
|
function step(op) {
|
|
16
16
|
if (f) throw new TypeError("Generator is already executing.");
|
package/package.json
CHANGED
|
@@ -1,30 +1,27 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
"
|
|
15
|
-
"
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
},
|
|
29
|
-
"gitHead": "3007ad036607014176930446fde56203bde8d6f5"
|
|
30
|
-
}
|
|
2
|
+
"name": "@flink-app/management-actions-plugin",
|
|
3
|
+
"version": "0.13.1",
|
|
4
|
+
"description": "Flink plugin that makes it possible create actions that can be run trought the management-api",
|
|
5
|
+
"author": "johan@frost.se",
|
|
6
|
+
"publishConfig": {
|
|
7
|
+
"access": "public"
|
|
8
|
+
},
|
|
9
|
+
"license": "MIT",
|
|
10
|
+
"types": "dist/index.d.ts",
|
|
11
|
+
"main": "dist/index.js",
|
|
12
|
+
"dependencies": {
|
|
13
|
+
"node-color-log": "^5.3.1",
|
|
14
|
+
"@flink-app/flink": "0.13.0",
|
|
15
|
+
"@flink-app/management-api-plugin": "0.13.0"
|
|
16
|
+
},
|
|
17
|
+
"devDependencies": {
|
|
18
|
+
"@types/node": "22.13.10",
|
|
19
|
+
"ts-node": "^10.9.2"
|
|
20
|
+
},
|
|
21
|
+
"gitHead": "4243e3b3cd6d4e1ca001a61baa8436bf2bbe4113",
|
|
22
|
+
"scripts": {
|
|
23
|
+
"test": "echo \"Error: no test specified\"",
|
|
24
|
+
"build": "flink build",
|
|
25
|
+
"clean": "rimraf dist .flink"
|
|
26
|
+
}
|
|
27
|
+
}
|
package/readme.md
CHANGED
|
@@ -1,66 +1,385 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @flink-app/management-actions-plugin
|
|
2
2
|
|
|
3
|
-
A
|
|
3
|
+
A Flink management API module that enables you to create and execute custom actions through the management API. This plugin integrates with `@flink-app/management-api-plugin` to expose server-side actions that can be triggered via HTTP requests.
|
|
4
4
|
|
|
5
|
-
##
|
|
6
|
-
Flink management-api-plugin must be installed and configured to your project.
|
|
5
|
+
## Features
|
|
7
6
|
|
|
8
|
-
|
|
7
|
+
- Define custom server-side actions with arguments
|
|
8
|
+
- Execute actions through the management API
|
|
9
|
+
- Type-safe argument handling
|
|
10
|
+
- Built-in UI support for management interfaces
|
|
11
|
+
- Flexible response handling with success/error states
|
|
12
|
+
- List all available actions via API
|
|
9
13
|
|
|
10
|
-
|
|
14
|
+
## Prerequisites
|
|
11
15
|
|
|
12
|
-
|
|
13
|
-
|
|
16
|
+
This plugin requires `@flink-app/management-api-plugin` to be installed and configured in your Flink application.
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
npm install @flink-app/management-api-plugin
|
|
14
20
|
```
|
|
15
21
|
|
|
16
|
-
|
|
22
|
+
## Installation
|
|
17
23
|
|
|
24
|
+
```bash
|
|
25
|
+
npm install @flink-app/management-actions-plugin
|
|
18
26
|
```
|
|
19
|
-
import { GetManagementModule as GetActionsManagmenetModule } from '@flink-app/management-actions-plugin'
|
|
20
27
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
28
|
+
## Usage
|
|
29
|
+
|
|
30
|
+
### Basic Setup
|
|
31
|
+
|
|
32
|
+
```typescript
|
|
33
|
+
import { FlinkApp } from "@flink-app/flink";
|
|
34
|
+
import { managementApiPlugin } from "@flink-app/management-api-plugin";
|
|
35
|
+
import {
|
|
36
|
+
GetManagementModule,
|
|
37
|
+
ActionArugmentType,
|
|
38
|
+
ActionReturnStatus,
|
|
39
|
+
} from "@flink-app/management-actions-plugin";
|
|
40
|
+
|
|
41
|
+
const actionsModule = GetManagementModule({
|
|
42
|
+
ui: true,
|
|
43
|
+
uiSettings: {
|
|
44
|
+
title: "Actions",
|
|
45
|
+
},
|
|
46
|
+
actions: [
|
|
47
|
+
{
|
|
48
|
+
id: "hello-world",
|
|
49
|
+
description: "Greets you with a personalized message",
|
|
50
|
+
arguments: [
|
|
51
|
+
{
|
|
52
|
+
id: "name",
|
|
53
|
+
type: ActionArugmentType.text,
|
|
54
|
+
required: true,
|
|
45
55
|
},
|
|
56
|
+
],
|
|
57
|
+
async handler(ctx, args) {
|
|
58
|
+
return {
|
|
59
|
+
data: {
|
|
60
|
+
message: "Hello " + args.name,
|
|
61
|
+
},
|
|
62
|
+
status: ActionReturnStatus.success,
|
|
63
|
+
};
|
|
64
|
+
},
|
|
46
65
|
},
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
})
|
|
50
|
-
|
|
66
|
+
],
|
|
67
|
+
});
|
|
51
68
|
|
|
52
69
|
function start() {
|
|
53
70
|
new FlinkApp<AppContext>({
|
|
54
71
|
name: "My app",
|
|
55
72
|
plugins: [
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
})
|
|
73
|
+
managementApiPlugin({
|
|
74
|
+
token: "SECRET_TOKEN",
|
|
75
|
+
jwtSecret: "JWT_SECRET",
|
|
76
|
+
modules: [actionsModule],
|
|
77
|
+
}),
|
|
62
78
|
],
|
|
63
79
|
}).start();
|
|
64
80
|
}
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## Action Definition
|
|
84
|
+
|
|
85
|
+
Each action requires the following properties:
|
|
86
|
+
|
|
87
|
+
### Action Interface
|
|
88
|
+
|
|
89
|
+
```typescript
|
|
90
|
+
interface Action {
|
|
91
|
+
id: string; // Unique identifier for the action
|
|
92
|
+
description?: string; // Human-readable description
|
|
93
|
+
arguments: ActionArguments[]; // Array of input arguments
|
|
94
|
+
handler: (ctx: FlinkContext<any>, args: ActionArgumentsValues) => Promise<ActionResponse>;
|
|
95
|
+
}
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### Action Arguments
|
|
99
|
+
|
|
100
|
+
```typescript
|
|
101
|
+
interface ActionArguments {
|
|
102
|
+
id: string; // Argument identifier
|
|
103
|
+
required: boolean; // Whether the argument is required
|
|
104
|
+
type: ActionArugmentType; // Argument type
|
|
105
|
+
default?: string; // Optional default value
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
enum ActionArugmentType {
|
|
109
|
+
text = "TEXT",
|
|
110
|
+
}
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### Action Response
|
|
114
|
+
|
|
115
|
+
```typescript
|
|
116
|
+
interface ActionResponse {
|
|
117
|
+
status: ActionReturnStatus; // SUCCESS or ERROR
|
|
118
|
+
error?: string; // Error message (if status is ERROR)
|
|
119
|
+
data?: {
|
|
120
|
+
[key: string]: any; // Response data (if status is SUCCESS)
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
enum ActionReturnStatus {
|
|
125
|
+
success = "SUCCESS",
|
|
126
|
+
error = "ERROR",
|
|
127
|
+
}
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
## API Endpoints
|
|
131
|
+
|
|
132
|
+
The plugin exposes two endpoints for each actions module:
|
|
133
|
+
|
|
134
|
+
### List Actions
|
|
135
|
+
|
|
136
|
+
```
|
|
137
|
+
GET /managementapi/{pluginId}
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
Returns a list of all available actions with their configurations.
|
|
141
|
+
|
|
142
|
+
**Response:**
|
|
143
|
+
```json
|
|
144
|
+
[
|
|
145
|
+
{
|
|
146
|
+
"id": "hello-world",
|
|
147
|
+
"description": "Greets you with a personalized message",
|
|
148
|
+
"arguments": [
|
|
149
|
+
{
|
|
150
|
+
"id": "name",
|
|
151
|
+
"type": "TEXT",
|
|
152
|
+
"required": true
|
|
153
|
+
}
|
|
154
|
+
]
|
|
155
|
+
}
|
|
156
|
+
]
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
### Execute Action
|
|
160
|
+
|
|
161
|
+
```
|
|
162
|
+
POST /managementapi/{pluginId}/{actionId}
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
Executes a specific action with provided arguments.
|
|
166
|
+
|
|
167
|
+
**Headers:**
|
|
168
|
+
```
|
|
169
|
+
management-token: YOUR_TOKEN_OR_JWT
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
**Request Body:**
|
|
173
|
+
```json
|
|
174
|
+
{
|
|
175
|
+
"name": "World"
|
|
176
|
+
}
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
**Response:**
|
|
180
|
+
```json
|
|
181
|
+
{
|
|
182
|
+
"status": "SUCCESS",
|
|
183
|
+
"data": {
|
|
184
|
+
"message": "Hello World"
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
## Advanced Examples
|
|
190
|
+
|
|
191
|
+
### Action with Multiple Arguments
|
|
192
|
+
|
|
193
|
+
```typescript
|
|
194
|
+
{
|
|
195
|
+
id: "create-user",
|
|
196
|
+
description: "Creates a new user in the system",
|
|
197
|
+
arguments: [
|
|
198
|
+
{
|
|
199
|
+
id: "username",
|
|
200
|
+
type: ActionArugmentType.text,
|
|
201
|
+
required: true,
|
|
202
|
+
},
|
|
203
|
+
{
|
|
204
|
+
id: "email",
|
|
205
|
+
type: ActionArugmentType.text,
|
|
206
|
+
required: true,
|
|
207
|
+
},
|
|
208
|
+
{
|
|
209
|
+
id: "role",
|
|
210
|
+
type: ActionArugmentType.text,
|
|
211
|
+
required: false,
|
|
212
|
+
default: "user",
|
|
213
|
+
},
|
|
214
|
+
],
|
|
215
|
+
async handler(ctx, args) {
|
|
216
|
+
try {
|
|
217
|
+
const user = await ctx.repos.userRepo.create({
|
|
218
|
+
username: args.username,
|
|
219
|
+
email: args.email,
|
|
220
|
+
role: args.role,
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
return {
|
|
224
|
+
status: ActionReturnStatus.success,
|
|
225
|
+
data: { userId: user._id },
|
|
226
|
+
};
|
|
227
|
+
} catch (error) {
|
|
228
|
+
return {
|
|
229
|
+
status: ActionReturnStatus.error,
|
|
230
|
+
error: error.message,
|
|
231
|
+
};
|
|
232
|
+
}
|
|
233
|
+
},
|
|
234
|
+
}
|
|
235
|
+
```
|
|
65
236
|
|
|
237
|
+
### Action with Database Access
|
|
238
|
+
|
|
239
|
+
```typescript
|
|
240
|
+
{
|
|
241
|
+
id: "cleanup-old-records",
|
|
242
|
+
description: "Removes records older than 30 days",
|
|
243
|
+
arguments: [],
|
|
244
|
+
async handler(ctx, args) {
|
|
245
|
+
try {
|
|
246
|
+
const cutoffDate = new Date();
|
|
247
|
+
cutoffDate.setDate(cutoffDate.getDate() - 30);
|
|
248
|
+
|
|
249
|
+
const result = await ctx.repos.recordRepo.deleteMany({
|
|
250
|
+
createdAt: { $lt: cutoffDate },
|
|
251
|
+
});
|
|
252
|
+
|
|
253
|
+
return {
|
|
254
|
+
status: ActionReturnStatus.success,
|
|
255
|
+
data: {
|
|
256
|
+
deletedCount: result.deletedCount,
|
|
257
|
+
message: `Removed ${result.deletedCount} old records`,
|
|
258
|
+
},
|
|
259
|
+
};
|
|
260
|
+
} catch (error) {
|
|
261
|
+
return {
|
|
262
|
+
status: ActionReturnStatus.error,
|
|
263
|
+
error: `Failed to cleanup records: ${error.message}`,
|
|
264
|
+
};
|
|
265
|
+
}
|
|
266
|
+
},
|
|
267
|
+
}
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
### Action with External API Call
|
|
271
|
+
|
|
272
|
+
```typescript
|
|
273
|
+
{
|
|
274
|
+
id: "sync-data",
|
|
275
|
+
description: "Syncs data from external service",
|
|
276
|
+
arguments: [
|
|
277
|
+
{
|
|
278
|
+
id: "service",
|
|
279
|
+
type: ActionArugmentType.text,
|
|
280
|
+
required: true,
|
|
281
|
+
},
|
|
282
|
+
],
|
|
283
|
+
async handler(ctx, args) {
|
|
284
|
+
try {
|
|
285
|
+
const response = await fetch(`https://api.example.com/${args.service}`);
|
|
286
|
+
const data = await response.json();
|
|
287
|
+
|
|
288
|
+
// Process and store data
|
|
289
|
+
await ctx.repos.dataRepo.create(data);
|
|
290
|
+
|
|
291
|
+
return {
|
|
292
|
+
status: ActionReturnStatus.success,
|
|
293
|
+
data: {
|
|
294
|
+
recordsImported: data.length,
|
|
295
|
+
service: args.service,
|
|
296
|
+
},
|
|
297
|
+
};
|
|
298
|
+
} catch (error) {
|
|
299
|
+
return {
|
|
300
|
+
status: ActionReturnStatus.error,
|
|
301
|
+
error: `Sync failed: ${error.message}`,
|
|
302
|
+
};
|
|
303
|
+
}
|
|
304
|
+
},
|
|
305
|
+
}
|
|
66
306
|
```
|
|
307
|
+
|
|
308
|
+
## Configuration Options
|
|
309
|
+
|
|
310
|
+
### GetManagementModule Options
|
|
311
|
+
|
|
312
|
+
```typescript
|
|
313
|
+
interface GetManagementModuleConfig {
|
|
314
|
+
pluginId?: string; // Custom plugin ID (defaults to "managementActionsApi")
|
|
315
|
+
ui: boolean; // Enable UI features
|
|
316
|
+
uiSettings?: {
|
|
317
|
+
title: string; // Display title in management UI
|
|
318
|
+
};
|
|
319
|
+
actions: Action[]; // Array of actions to register
|
|
320
|
+
}
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
## Context Access
|
|
324
|
+
|
|
325
|
+
Action handlers receive the full Flink context, providing access to:
|
|
326
|
+
|
|
327
|
+
- `ctx.repos` - All registered repositories
|
|
328
|
+
- `ctx.db` - MongoDB database connection
|
|
329
|
+
- `ctx.plugins` - All plugin contexts
|
|
330
|
+
- Any other context properties from your application
|
|
331
|
+
|
|
332
|
+
## Security
|
|
333
|
+
|
|
334
|
+
All action endpoints are protected by the management API authentication system. Ensure you:
|
|
335
|
+
|
|
336
|
+
- Use the management token header for all requests
|
|
337
|
+
- Validate and sanitize action arguments
|
|
338
|
+
- Implement proper error handling
|
|
339
|
+
- Avoid exposing sensitive data in responses
|
|
340
|
+
- Log action executions for audit purposes
|
|
341
|
+
|
|
342
|
+
## Testing Actions
|
|
343
|
+
|
|
344
|
+
You can test your actions using curl or any HTTP client:
|
|
345
|
+
|
|
346
|
+
```bash
|
|
347
|
+
# Get list of actions
|
|
348
|
+
curl 'https://your-api.com/managementapi/managementActionsApi' \
|
|
349
|
+
-H 'management-token: YOUR_TOKEN'
|
|
350
|
+
|
|
351
|
+
# Execute an action
|
|
352
|
+
curl -X POST 'https://your-api.com/managementapi/managementActionsApi/hello-world' \
|
|
353
|
+
-H 'management-token: YOUR_TOKEN' \
|
|
354
|
+
-H 'Content-Type: application/json' \
|
|
355
|
+
-d '{"name":"World"}'
|
|
356
|
+
```
|
|
357
|
+
|
|
358
|
+
## TypeScript Support
|
|
359
|
+
|
|
360
|
+
The plugin is written in TypeScript and provides full type definitions for all interfaces and enums.
|
|
361
|
+
|
|
362
|
+
## Error Handling
|
|
363
|
+
|
|
364
|
+
Always return proper error responses from action handlers:
|
|
365
|
+
|
|
366
|
+
```typescript
|
|
367
|
+
async handler(ctx, args) {
|
|
368
|
+
try {
|
|
369
|
+
// Your action logic
|
|
370
|
+
return {
|
|
371
|
+
status: ActionReturnStatus.success,
|
|
372
|
+
data: { /* your data */ },
|
|
373
|
+
};
|
|
374
|
+
} catch (error) {
|
|
375
|
+
return {
|
|
376
|
+
status: ActionReturnStatus.error,
|
|
377
|
+
error: error instanceof Error ? error.message : "Unknown error",
|
|
378
|
+
};
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
```
|
|
382
|
+
|
|
383
|
+
## License
|
|
384
|
+
|
|
385
|
+
MIT
|