@majkapp/plugin-kit 3.2.1 → 3.3.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.
@@ -0,0 +1,350 @@
1
+ # Services
2
+
3
+ Services group related functions together for better organization and discovery.
4
+
5
+ ## Basic Service
6
+
7
+ ```typescript
8
+ // src/index.ts
9
+ import { definePlugin } from '@majkapp/plugin-kit';
10
+
11
+ const plugin = definePlugin('my-plugin', 'My Plugin', '1.0.0')
12
+ .pluginRoot(__dirname)
13
+
14
+ // Define functions first
15
+ .function('health', { /* ... */, tags: ['monitoring'] })
16
+ .function('getStats', { /* ... */, tags: ['monitoring'] })
17
+ .function('getMetrics', { /* ... */, tags: ['monitoring'] })
18
+
19
+ // Group into service
20
+ .service('plugin:my-plugin:monitoring', {
21
+ type: '@my-plugin/monitoring',
22
+ metadata: {
23
+ name: 'Monitoring Service',
24
+ description: 'Health checks and system metrics',
25
+ version: '1.0.0'
26
+ },
27
+ discoverable: true // Make service discoverable by other plugins
28
+ })
29
+ .withFunction('health', {
30
+ examples: ['Check plugin health status'],
31
+ tags: ['health', 'status']
32
+ })
33
+ .withFunction('getStats', {
34
+ examples: ['Get system statistics'],
35
+ tags: ['stats', 'metrics']
36
+ })
37
+ .withFunction('getMetrics', {
38
+ examples: ['Get detailed metrics'],
39
+ tags: ['metrics', 'monitoring']
40
+ })
41
+ .endService()
42
+
43
+ .build();
44
+ ```
45
+
46
+ ## Real Example from full-featured
47
+
48
+ ```typescript
49
+ // samples/full-featured/src/index.ts
50
+
51
+ // Define monitoring functions
52
+ .function('health', {
53
+ description: 'Returns plugin health status',
54
+ input: { /* ... */ },
55
+ output: { /* ... */ },
56
+ handler: async (input, ctx) => {
57
+ return {
58
+ status: 'ok',
59
+ timestamp: new Date().toISOString()
60
+ };
61
+ },
62
+ tags: ['monitoring']
63
+ })
64
+
65
+ .function('getStats', {
66
+ description: 'Get plugin statistics',
67
+ input: { /* ... */ },
68
+ output: { /* ... */ },
69
+ handler: async (input, ctx) => {
70
+ const conversations = await ctx.majk.conversations.list();
71
+ const teammates = await ctx.majk.teammates.list();
72
+
73
+ return {
74
+ conversationCount: conversations.length,
75
+ teammateCount: teammates.length,
76
+ timestamp: new Date().toISOString()
77
+ };
78
+ },
79
+ tags: ['monitoring']
80
+ })
81
+
82
+ // Group into service
83
+ .service('plugin:full-featured:monitoring', {
84
+ type: '@full-featured/monitoring',
85
+ metadata: {
86
+ name: 'Full Featured Monitoring',
87
+ description: 'Health checks and statistics for the Full Featured plugin',
88
+ version: '1.0.0',
89
+ author: 'Full Featured Team'
90
+ },
91
+ discoverable: true
92
+ })
93
+ .withFunction('health', {
94
+ examples: [
95
+ 'Get current health status',
96
+ 'Check if plugin is running correctly'
97
+ ],
98
+ tags: ['health', 'status', 'monitoring']
99
+ })
100
+ .withFunction('getStats', {
101
+ examples: [
102
+ 'Get conversation and teammate counts',
103
+ 'View system statistics'
104
+ ],
105
+ tags: ['stats', 'metrics', 'monitoring']
106
+ })
107
+ .endService()
108
+ ```
109
+
110
+ ## Service with Multiple Functions
111
+
112
+ ```typescript
113
+ // Events management service
114
+ .function('getEvents', {
115
+ description: 'Get all logged events from the event bus',
116
+ input: { /* ... */ },
117
+ output: { /* ... */ },
118
+ handler: async (input, ctx) => {
119
+ const events = await ctx.storage.get('events') || [];
120
+ return { events, count: events.length };
121
+ },
122
+ tags: ['events']
123
+ })
124
+
125
+ .function('clearEvents', {
126
+ description: 'Clear the event log',
127
+ input: { /* ... */ },
128
+ output: { /* ... */ },
129
+ handler: async (input, ctx) => {
130
+ const events = await ctx.storage.get('events') || [];
131
+ await ctx.storage.set('events', []);
132
+ return { success: true, clearedCount: events.length };
133
+ },
134
+ tags: ['events', 'mutations']
135
+ })
136
+
137
+ .service('plugin:my-plugin:events', {
138
+ type: '@my-plugin/events',
139
+ metadata: {
140
+ name: 'Event Management',
141
+ description: 'Manage and monitor system events',
142
+ version: '1.0.0'
143
+ }
144
+ })
145
+ .withFunction('getEvents', {
146
+ examples: ['List all logged events', 'View event history'],
147
+ tags: ['read', 'query']
148
+ })
149
+ .withFunction('clearEvents', {
150
+ examples: ['Clear event log', 'Reset event history'],
151
+ tags: ['write', 'mutation']
152
+ })
153
+ .endService()
154
+ ```
155
+
156
+ ## Multiple Services
157
+
158
+ Organize functions into logical groups:
159
+
160
+ ```typescript
161
+ const plugin = definePlugin('my-plugin', 'My Plugin', '1.0.0')
162
+ .pluginRoot(__dirname)
163
+
164
+ // Monitoring functions
165
+ .function('health', { /* ... */, tags: ['monitoring'] })
166
+ .function('getStats', { /* ... */, tags: ['monitoring'] })
167
+
168
+ // Analytics functions
169
+ .function('getAnalytics', { /* ... */, tags: ['analytics'] })
170
+ .function('getChartData', { /* ... */, tags: ['analytics'] })
171
+
172
+ // User management functions
173
+ .function('getUsers', { /* ... */, tags: ['users'] })
174
+ .function('getUserDetail', { /* ... */, tags: ['users'] })
175
+
176
+ // Monitoring service
177
+ .service('plugin:my-plugin:monitoring', {
178
+ type: '@my-plugin/monitoring',
179
+ metadata: {
180
+ name: 'Monitoring Service',
181
+ description: 'Health and statistics',
182
+ version: '1.0.0'
183
+ }
184
+ })
185
+ .withFunction('health')
186
+ .withFunction('getStats')
187
+ .endService()
188
+
189
+ // Analytics service
190
+ .service('plugin:my-plugin:analytics', {
191
+ type: '@my-plugin/analytics',
192
+ metadata: {
193
+ name: 'Analytics Service',
194
+ description: 'Usage analytics and reporting',
195
+ version: '1.0.0'
196
+ }
197
+ })
198
+ .withFunction('getAnalytics')
199
+ .withFunction('getChartData')
200
+ .endService()
201
+
202
+ // User service
203
+ .service('plugin:my-plugin:users', {
204
+ type: '@my-plugin/users',
205
+ metadata: {
206
+ name: 'User Service',
207
+ description: 'User data and management',
208
+ version: '1.0.0'
209
+ }
210
+ })
211
+ .withFunction('getUsers')
212
+ .withFunction('getUserDetail')
213
+ .endService()
214
+
215
+ .build();
216
+ ```
217
+
218
+ ## Service Metadata
219
+
220
+ Service metadata helps with discovery and documentation:
221
+
222
+ ```typescript
223
+ .service('plugin:my-plugin:service-name', {
224
+ type: '@my-plugin/service-type', // Unique type identifier
225
+ metadata: {
226
+ name: 'Human-Readable Service Name',
227
+ description: 'Detailed description of what this service does',
228
+ version: '1.0.0',
229
+ author: 'Team Name', // Optional
230
+ homepage: 'https://docs.example.com/service', // Optional
231
+ tags: ['tag1', 'tag2'] // Optional
232
+ },
233
+ discoverable: true // Allow other plugins to discover this service
234
+ })
235
+ ```
236
+
237
+ ## Function Enrichment
238
+
239
+ Add service-specific metadata to functions:
240
+
241
+ ```typescript
242
+ .withFunction('functionName', {
243
+ examples: [
244
+ 'Example use case 1',
245
+ 'Example use case 2'
246
+ ],
247
+ tags: ['tag1', 'tag2'], // Additional tags for this function in service context
248
+ metadata: { // Optional custom metadata
249
+ rateLimit: 100,
250
+ requiresAuth: true
251
+ }
252
+ })
253
+ ```
254
+
255
+ ## Best Practices
256
+
257
+ ### 1. Organize by Domain
258
+
259
+ ```typescript
260
+ // Good: Functions grouped by business domain
261
+ .service('plugin:my-plugin:analytics', { /* ... */ })
262
+ .withFunction('getAnalytics')
263
+ .withFunction('getChartData')
264
+ .withFunction('exportReport')
265
+ .endService()
266
+
267
+ .service('plugin:my-plugin:notifications', { /* ... */ })
268
+ .withFunction('sendNotification')
269
+ .withFunction('getNotificationHistory')
270
+ .endService()
271
+ ```
272
+
273
+ ### 2. Keep Services Focused
274
+
275
+ ```typescript
276
+ // Good: Focused service with related functions
277
+ .service('plugin:my-plugin:events', { /* ... */ })
278
+ .withFunction('getEvents')
279
+ .withFunction('clearEvents')
280
+ .withFunction('filterEvents')
281
+ .endService()
282
+
283
+ // Bad: Too broad, unrelated functions
284
+ .service('plugin:my-plugin:everything', { /* ... */ })
285
+ .withFunction('getEvents')
286
+ .withFunction('sendEmail') // Unrelated
287
+ .withFunction('calculateTax') // Unrelated
288
+ .endService()
289
+ ```
290
+
291
+ ### 3. Use Descriptive Metadata
292
+
293
+ ```typescript
294
+ .service('plugin:my-plugin:monitoring', {
295
+ type: '@my-plugin/monitoring',
296
+ metadata: {
297
+ name: 'System Monitoring', // Clear name
298
+ description: 'Provides health checks, system statistics, and performance metrics for the plugin', // Detailed description
299
+ version: '1.0.0'
300
+ }
301
+ })
302
+ ```
303
+
304
+ ## Service Naming Convention
305
+
306
+ **Format:** `plugin:{plugin-id}:{service-name}`
307
+
308
+ Examples:
309
+ - `plugin:my-plugin:monitoring`
310
+ - `plugin:my-plugin:analytics`
311
+ - `plugin:my-plugin:data-management`
312
+ - `plugin:full-featured:events`
313
+
314
+ ## Testing Services
315
+
316
+ Services are tested through their functions:
317
+
318
+ ```typescript
319
+ // tests/plugin/functions/unit/monitoring.test.js
320
+ import { test, invoke, mock } from '@majkapp/plugin-test';
321
+ import assert from 'assert';
322
+
323
+ test('monitoring service - health check', async () => {
324
+ const context = mock().build();
325
+ const result = await invoke('health', {}, { context });
326
+
327
+ assert.strictEqual(result.status, 'ok');
328
+ assert.ok(result.timestamp);
329
+ });
330
+
331
+ test('monitoring service - get stats', async () => {
332
+ const context = mock()
333
+ .withMajkData({
334
+ conversations: [{ id: '1' }, { id: '2' }],
335
+ teammates: [{ id: 't1' }]
336
+ })
337
+ .build();
338
+
339
+ const result = await invoke('getStats', {}, { context });
340
+
341
+ assert.strictEqual(result.conversationCount, 2);
342
+ assert.strictEqual(result.teammateCount, 1);
343
+ });
344
+ ```
345
+
346
+ ## Next Steps
347
+
348
+ Run `npx @majkapp/plugin-kit --functions` - Define functions for services
349
+ Run `npx @majkapp/plugin-kit --testing` - Test your services
350
+ Run `npx @majkapp/plugin-kit --lifecycle` - Service initialization with onReady