skeleton-crew-runtime 0.2.0 → 0.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -21
- package/README.md +524 -459
- package/dist/.tsbuildinfo +1 -1
- package/dist/action-engine.d.ts.map +1 -1
- package/dist/action-engine.js +4 -1
- package/dist/action-engine.js.map +1 -1
- package/dist/plugin-loader.d.ts +10 -5
- package/dist/plugin-loader.d.ts.map +1 -1
- package/dist/plugin-loader.js +120 -25
- package/dist/plugin-loader.js.map +1 -1
- package/dist/runtime.d.ts +3 -0
- package/dist/runtime.d.ts.map +1 -1
- package/dist/runtime.js +14 -1
- package/dist/runtime.js.map +1 -1
- package/dist/types.d.ts +2 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -1,459 +1,524 @@
|
|
|
1
|
-
# Skeleton Crew Runtime v0.2.
|
|
2
|
-
|
|
3
|
-
**A minimal plugin runtime for building modular JavaScript applications.**
|
|
4
|
-
|
|
5
|
-
Stop wiring up infrastructure. Start building features.
|
|
6
|
-
|
|
7
|
-
```bash
|
|
8
|
-
npm install skeleton-crew-runtime@^0.2.
|
|
9
|
-
```
|
|
10
|
-
|
|
11
|
-
## What's New in v0.2.
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
###
|
|
20
|
-
|
|
21
|
-
```typescript
|
|
22
|
-
//
|
|
23
|
-
const runtime = new Runtime({
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
- **
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
- **
|
|
80
|
-
- **
|
|
81
|
-
|
|
82
|
-
**
|
|
83
|
-
|
|
84
|
-
- **
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
- **
|
|
88
|
-
- **
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
}
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
}
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
**
|
|
1
|
+
# Skeleton Crew Runtime v0.2.1
|
|
2
|
+
|
|
3
|
+
**A minimal plugin runtime for building modular JavaScript applications.**
|
|
4
|
+
|
|
5
|
+
Stop wiring up infrastructure. Start building features.
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install skeleton-crew-runtime@^0.2.1
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## What's New in v0.2.1
|
|
12
|
+
|
|
13
|
+
🔍 **Plugin Discovery** - Automatic plugin loading from file paths and npm packages
|
|
14
|
+
🔄 **Dependency Resolution** - Automatic topological sorting for correct plugin initialization order
|
|
15
|
+
🛠️ **Enhanced DX** - Better error messages with dependency hints for missing actions
|
|
16
|
+
🚀 **Production Ready** - All critical bugs fixed based on real-world usage feedback
|
|
17
|
+
✅ **Verified Stable** - Tested and validated in production migrations
|
|
18
|
+
|
|
19
|
+
### Plugin Discovery Example
|
|
20
|
+
|
|
21
|
+
```typescript
|
|
22
|
+
// Automatic plugin discovery - no manual registration needed!
|
|
23
|
+
const runtime = new Runtime<MyConfig>({
|
|
24
|
+
config: myConfig,
|
|
25
|
+
|
|
26
|
+
// Load plugins from directories
|
|
27
|
+
pluginPaths: [
|
|
28
|
+
'./plugins', // Load all plugins from directory
|
|
29
|
+
'./custom-plugin.js' // Load specific plugin file
|
|
30
|
+
],
|
|
31
|
+
|
|
32
|
+
// Load plugins from npm packages
|
|
33
|
+
pluginPackages: [
|
|
34
|
+
'@my-org/auth-plugin',
|
|
35
|
+
'my-custom-plugin'
|
|
36
|
+
]
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
await runtime.initialize(); // Plugins auto-loaded and sorted by dependencies!
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
**[→ Complete v0.2.1 Features](CHANGELOG.md#021---2025-01-07)**
|
|
43
|
+
|
|
44
|
+
## What's New in v0.2.0
|
|
45
|
+
|
|
46
|
+
🎯 **Generic Runtime/Context** - Full TypeScript generic support for type-safe configuration
|
|
47
|
+
⚡ **Sync Config Access** - Direct synchronous access to configuration via `ctx.config`
|
|
48
|
+
🔗 **Plugin Dependencies** - Explicit dependency resolution with validation
|
|
49
|
+
📝 **Enhanced Logger** - Logger available on context for all plugins
|
|
50
|
+
🔄 **100% Backward Compatible** - All v0.1.x code continues to work
|
|
51
|
+
|
|
52
|
+
### Quick Migration Example
|
|
53
|
+
|
|
54
|
+
```typescript
|
|
55
|
+
// v0.1.x
|
|
56
|
+
const runtime = new Runtime({
|
|
57
|
+
hostContext: { config: myConfig }
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
// v0.2.0 - Fully typed!
|
|
61
|
+
interface MyConfig { apiUrl: string; }
|
|
62
|
+
const runtime = new Runtime<MyConfig>({
|
|
63
|
+
config: { apiUrl: 'https://api.example.com' }
|
|
64
|
+
});
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
**[→ Complete Migration Guide](docs/guides/v0.1-to-v0.2-migration.md)**
|
|
68
|
+
|
|
69
|
+
---
|
|
70
|
+
## Documentation
|
|
71
|
+
|
|
72
|
+
### Getting Started
|
|
73
|
+
- **[Installation](docs/getting-started/installation.md)** - Install and setup
|
|
74
|
+
- **[API Reference](docs/api/reference.md)** - Complete TypeScript API
|
|
75
|
+
- **[Core Concepts](docs/getting-started/README.md)** - Understand the fundamentals
|
|
76
|
+
- **[Your First Plugin](docs/getting-started/your-first-plugin.md)** - Build your first feature
|
|
77
|
+
|
|
78
|
+
### v0.2.0 Migration & Guides
|
|
79
|
+
- **[v0.1.x → v0.2.0 Migration](docs/guides/v0.1-to-v0.2-migration.md)** - Complete migration walkthrough
|
|
80
|
+
- **[Plugin Dependencies](docs/guides/plugin-dependencies.md)** - Dependency patterns and best practices
|
|
81
|
+
- **[Sync vs Async Patterns](docs/guides/sync-async-patterns.md)** - Configuration and execution patterns
|
|
82
|
+
- **[Real-World Examples](docs/guides/real-world-examples.md)** - Production-ready implementations
|
|
83
|
+
- **[Migration Guide](docs/guides/migration-guide.md)** - Integrate with existing apps
|
|
84
|
+
- **[Examples Guide](docs/guides/EXAMPLES_GUIDE.md)** - Learn through code examples
|
|
85
|
+
|
|
86
|
+
### Use Cases
|
|
87
|
+
- **[Browser Extensions](docs/use-cases/BROWSER_TOOLS.md)** - Build browser tools
|
|
88
|
+
- **[CLI Applications](docs/use-cases/)** - Command-line tools
|
|
89
|
+
- **[Real-Time Apps](docs/use-cases/)** - Collaboration and sync
|
|
90
|
+
|
|
91
|
+
### Advanced
|
|
92
|
+
- **[Architecture](docs/architecture/)** - How it works under the hood
|
|
93
|
+
- **[Troubleshooting](docs/troubleshooting/)** - Common issues and solutions
|
|
94
|
+
|
|
95
|
+
---
|
|
96
|
+
|
|
97
|
+
## What is this?
|
|
98
|
+
|
|
99
|
+
Skeleton Crew Runtime is a lightweight foundation for building applications where features can be added, removed, or replaced without touching existing code. Think VS Code's extension system, but for any JavaScript application.
|
|
100
|
+
|
|
101
|
+
**Core idea:** Your app is a collection of plugins. Each plugin registers actions (business logic), screens (UI definitions), and events (communication). The runtime coordinates everything.
|
|
102
|
+
|
|
103
|
+
**Result:** Add features by dropping in plugins. Remove features by taking them out. No refactoring. No breaking changes.
|
|
104
|
+
|
|
105
|
+
## Why would I use this?
|
|
106
|
+
|
|
107
|
+
You're building something modular and you might know these challenges:
|
|
108
|
+
|
|
109
|
+
- **Wiring up infrastructure** - Event buses, plugin loaders, action registries
|
|
110
|
+
- **Tight coupling** - Changing one feature breaks three others
|
|
111
|
+
- **Testing nightmares** - Can't test features in isolation
|
|
112
|
+
- **Framework lock-in** - Married to React/Vue/whatever forever
|
|
113
|
+
- **Refactoring hell** - Adding features means touching existing code
|
|
114
|
+
|
|
115
|
+
**Skeleton Crew Runtime gives you:**
|
|
116
|
+
|
|
117
|
+
- **Plugin isolation** - Features don't know about each other
|
|
118
|
+
- **Event-driven communication** - Plugins coordinate without coupling
|
|
119
|
+
- **Framework freedom** - Business logic separate from UI
|
|
120
|
+
- **Testability** - Mock what you need, test what matters
|
|
121
|
+
- **Minimal core** - < 5KB, zero dependencies
|
|
122
|
+
|
|
123
|
+
## Show me code
|
|
124
|
+
|
|
125
|
+
Here's a complete plugin that adds a feature to your app:
|
|
126
|
+
|
|
127
|
+
```typescript
|
|
128
|
+
import { Runtime, PluginDefinition, RuntimeContext } from 'skeleton-crew-runtime';
|
|
129
|
+
|
|
130
|
+
// v0.2.0: Define your config interface
|
|
131
|
+
interface AppConfig {
|
|
132
|
+
notifications: {
|
|
133
|
+
apiKey: string;
|
|
134
|
+
defaultTimeout: number;
|
|
135
|
+
};
|
|
136
|
+
features: {
|
|
137
|
+
pushNotifications: boolean;
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// 1. Create typed runtime
|
|
142
|
+
const runtime = new Runtime<AppConfig>({
|
|
143
|
+
config: {
|
|
144
|
+
notifications: {
|
|
145
|
+
apiKey: process.env.NOTIFICATION_API_KEY!,
|
|
146
|
+
defaultTimeout: 5000
|
|
147
|
+
},
|
|
148
|
+
features: {
|
|
149
|
+
pushNotifications: true
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
await runtime.initialize();
|
|
155
|
+
const ctx = runtime.getContext();
|
|
156
|
+
|
|
157
|
+
// 2. Write a plugin (this is a complete feature)
|
|
158
|
+
const notificationsPlugin: PluginDefinition<AppConfig> = {
|
|
159
|
+
name: 'notifications',
|
|
160
|
+
version: '1.0.0',
|
|
161
|
+
dependencies: [], // v0.2.0: Explicit dependencies
|
|
162
|
+
|
|
163
|
+
setup(ctx: RuntimeContext<AppConfig>) {
|
|
164
|
+
// ✅ Fully typed config access
|
|
165
|
+
const { notifications, features } = ctx.config;
|
|
166
|
+
|
|
167
|
+
if (!features.pushNotifications) {
|
|
168
|
+
ctx.logger.info('Push notifications disabled');
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// Register business logic with type safety
|
|
173
|
+
ctx.actions.registerAction<
|
|
174
|
+
{ userId: string; message: string },
|
|
175
|
+
{ success: boolean; messageId: string }
|
|
176
|
+
>({
|
|
177
|
+
id: 'notifications:send',
|
|
178
|
+
handler: async ({ userId, message }, ctx) => {
|
|
179
|
+
// ✅ Typed config access in handlers
|
|
180
|
+
const { apiKey, defaultTimeout } = ctx.config.notifications;
|
|
181
|
+
|
|
182
|
+
// Your logic here
|
|
183
|
+
const messageId = await sendPushNotification(userId, message, {
|
|
184
|
+
apiKey,
|
|
185
|
+
timeout: defaultTimeout
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
// Let other plugins know
|
|
189
|
+
ctx.events.emit('notification:sent', { userId, messageId });
|
|
190
|
+
|
|
191
|
+
return { success: true, messageId };
|
|
192
|
+
},
|
|
193
|
+
timeout: notifications.defaultTimeout
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
// React to other plugins
|
|
197
|
+
ctx.events.on('user:registered', async (user: any) => {
|
|
198
|
+
await ctx.actions.runAction('notifications:send', {
|
|
199
|
+
userId: user.id,
|
|
200
|
+
message: 'Welcome!'
|
|
201
|
+
});
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
ctx.logger.info('Notifications plugin initialized');
|
|
205
|
+
}
|
|
206
|
+
};
|
|
207
|
+
|
|
208
|
+
// 3. Register and use
|
|
209
|
+
ctx.plugins.registerPlugin(notificationsPlugin);
|
|
210
|
+
|
|
211
|
+
// anywhere in your app - fully typed!
|
|
212
|
+
const result = await ctx.actions.runAction('notifications:send', {
|
|
213
|
+
userId: '123',
|
|
214
|
+
message: 'Your order shipped!'
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
console.log(`Message sent: ${result.messageId}`);
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
**That's it.** The plugin is isolated, testable, fully typed, and can be removed without breaking anything.
|
|
221
|
+
|
|
222
|
+
## Core concepts (5 minutes)
|
|
223
|
+
|
|
224
|
+
### 1. Plugin Discovery (v0.2.1): Automatic Loading
|
|
225
|
+
|
|
226
|
+
No more manual plugin registration! The runtime can automatically discover and load plugins:
|
|
227
|
+
|
|
228
|
+
```typescript
|
|
229
|
+
import { Runtime } from 'skeleton-crew-runtime';
|
|
230
|
+
|
|
231
|
+
const runtime = new Runtime<MyConfig>({
|
|
232
|
+
config: myConfig,
|
|
233
|
+
|
|
234
|
+
// Discover plugins from file system
|
|
235
|
+
pluginPaths: [
|
|
236
|
+
'./src/plugins', // Directory: loads all .js/.mjs files
|
|
237
|
+
'./auth-plugin.js', // Single file: loads specific plugin
|
|
238
|
+
'./dist/plugins' // Works with compiled TypeScript too!
|
|
239
|
+
],
|
|
240
|
+
|
|
241
|
+
// Discover plugins from npm packages
|
|
242
|
+
pluginPackages: [
|
|
243
|
+
'@my-org/auth-plugin', // npm package with plugin export
|
|
244
|
+
'my-logging-plugin' // Any package that exports a plugin
|
|
245
|
+
]
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
await runtime.initialize();
|
|
249
|
+
// ✅ All plugins auto-loaded and sorted by dependencies!
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
**Dependency Resolution:** Plugins are automatically sorted by their `dependencies` array, so they initialize in the correct order.
|
|
253
|
+
|
|
254
|
+
### 2. Plugins: Isolated Features
|
|
255
|
+
|
|
256
|
+
### 2. Plugins: Isolated Features
|
|
257
|
+
|
|
258
|
+
A plugin is just an object with a name and a setup function:
|
|
259
|
+
|
|
260
|
+
```typescript
|
|
261
|
+
import type { PluginDefinition, RuntimeContext } from 'skeleton-crew-runtime';
|
|
262
|
+
|
|
263
|
+
// v0.2.0: Define your config type
|
|
264
|
+
interface MyAppConfig {
|
|
265
|
+
apiUrl: string;
|
|
266
|
+
features: { analytics: boolean };
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
export const myPlugin: PluginDefinition<MyAppConfig> = {
|
|
270
|
+
name: 'my-plugin',
|
|
271
|
+
version: '1.0.0',
|
|
272
|
+
dependencies: ['config'], // v0.2.0: Explicit dependencies
|
|
273
|
+
|
|
274
|
+
setup(ctx: RuntimeContext<MyAppConfig>) {
|
|
275
|
+
// ✅ Fully typed config access
|
|
276
|
+
const { apiUrl, features } = ctx.config;
|
|
277
|
+
|
|
278
|
+
if (features.analytics) {
|
|
279
|
+
ctx.logger.info(`Plugin initialized for ${apiUrl}`);
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
// Register your feature here
|
|
283
|
+
},
|
|
284
|
+
|
|
285
|
+
dispose(ctx: RuntimeContext<MyAppConfig>) {
|
|
286
|
+
// Optional: cleanup resources when plugin is removed
|
|
287
|
+
// Use this for: closing connections, clearing timers, releasing memory
|
|
288
|
+
// Event listeners auto-cleanup, so you usually don't need this
|
|
289
|
+
}
|
|
290
|
+
};
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
### 3. Actions: Business Logic
|
|
294
|
+
|
|
295
|
+
Actions are named functions that do work:
|
|
296
|
+
|
|
297
|
+
```typescript
|
|
298
|
+
// v0.2.0: Type-safe action registration
|
|
299
|
+
interface CreateOrderParams {
|
|
300
|
+
customerId: string;
|
|
301
|
+
items: Array<{ id: string; quantity: number }>;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
interface Order {
|
|
305
|
+
id: string;
|
|
306
|
+
customerId: string;
|
|
307
|
+
total: number;
|
|
308
|
+
status: 'pending' | 'confirmed';
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
// Register an action
|
|
312
|
+
ctx.actions.registerAction<CreateOrderParams, Order>({
|
|
313
|
+
id: 'orders:create',
|
|
314
|
+
handler: async (orderData, ctx) => {
|
|
315
|
+
// ✅ Typed config access
|
|
316
|
+
const { apiUrl } = ctx.config;
|
|
317
|
+
|
|
318
|
+
// ✅ Typed parameters
|
|
319
|
+
const { customerId, items } = orderData;
|
|
320
|
+
|
|
321
|
+
const order = await createOrder(customerId, items);
|
|
322
|
+
ctx.events.emit('order:created', order);
|
|
323
|
+
|
|
324
|
+
ctx.logger.info(`Order created: ${order.id}`);
|
|
325
|
+
return order; // ✅ Typed return value
|
|
326
|
+
},
|
|
327
|
+
timeout: 10000 // Optional timeout
|
|
328
|
+
});
|
|
329
|
+
|
|
330
|
+
// Call from anywhere - fully typed!
|
|
331
|
+
const order = await ctx.actions.runAction<CreateOrderParams, Order>(
|
|
332
|
+
'orders:create',
|
|
333
|
+
{ customerId: '123', items: [{ id: 'item1', quantity: 2 }] }
|
|
334
|
+
);
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
### 4. Events: Decouple Features
|
|
338
|
+
|
|
339
|
+
Plugins communicate without knowing about each other:
|
|
340
|
+
|
|
341
|
+
```typescript
|
|
342
|
+
// Plugin A: Emit event
|
|
343
|
+
ctx.events.emit('order:created', order);
|
|
344
|
+
|
|
345
|
+
// Plugin B: React (doesn't know about Plugin A)
|
|
346
|
+
ctx.events.on('order:created', (order) => {
|
|
347
|
+
sendConfirmationEmail(order);
|
|
348
|
+
});
|
|
349
|
+
|
|
350
|
+
// v0.2.0: Async event handling
|
|
351
|
+
await ctx.events.emitAsync('order:created', order); // Wait for all handlers
|
|
352
|
+
```
|
|
353
|
+
|
|
354
|
+
### 5. Configuration: Type-Safe Access (v0.2.0)
|
|
355
|
+
|
|
356
|
+
Direct synchronous access to typed configuration:
|
|
357
|
+
|
|
358
|
+
```typescript
|
|
359
|
+
import { Runtime } from 'skeleton-crew-runtime';
|
|
360
|
+
|
|
361
|
+
interface AppConfig {
|
|
362
|
+
database: { url: string; maxConnections: number };
|
|
363
|
+
api: { baseUrl: string; timeout: number };
|
|
364
|
+
features: { caching: boolean; analytics: boolean };
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
const runtime = new Runtime<AppConfig>({
|
|
368
|
+
config: {
|
|
369
|
+
database: {
|
|
370
|
+
url: process.env.DATABASE_URL!,
|
|
371
|
+
maxConnections: 10
|
|
372
|
+
},
|
|
373
|
+
api: {
|
|
374
|
+
baseUrl: 'https://api.example.com',
|
|
375
|
+
timeout: 5000
|
|
376
|
+
},
|
|
377
|
+
features: {
|
|
378
|
+
caching: true,
|
|
379
|
+
analytics: process.env.NODE_ENV === 'production'
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
});
|
|
383
|
+
|
|
384
|
+
// In plugins: direct typed access
|
|
385
|
+
setup(ctx: RuntimeContext<AppConfig>) {
|
|
386
|
+
// ✅ Fully typed, synchronous access
|
|
387
|
+
const { database, api, features } = ctx.config;
|
|
388
|
+
|
|
389
|
+
if (features.caching) {
|
|
390
|
+
initializeCache();
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
// ✅ Available in action handlers
|
|
394
|
+
ctx.actions.registerAction({
|
|
395
|
+
id: 'api:request',
|
|
396
|
+
handler: async (endpoint: string) => {
|
|
397
|
+
const { baseUrl, timeout } = ctx.config.api;
|
|
398
|
+
return await fetch(`${baseUrl}${endpoint}`, { timeout });
|
|
399
|
+
}
|
|
400
|
+
});
|
|
401
|
+
}
|
|
402
|
+
```
|
|
403
|
+
|
|
404
|
+
### 6. Host Context: Bridge to Existing Code
|
|
405
|
+
|
|
406
|
+
Inject your existing services so plugins can use them:
|
|
407
|
+
|
|
408
|
+
```typescript
|
|
409
|
+
import { Runtime } from 'skeleton-crew-runtime';
|
|
410
|
+
|
|
411
|
+
const runtime = new Runtime<AppConfig>({
|
|
412
|
+
config: myTypedConfig,
|
|
413
|
+
hostContext: {
|
|
414
|
+
// Legacy services
|
|
415
|
+
db: yourDatabase,
|
|
416
|
+
cache: redisClient,
|
|
417
|
+
logger: yourLogger
|
|
418
|
+
}
|
|
419
|
+
});
|
|
420
|
+
|
|
421
|
+
await runtime.initialize();
|
|
422
|
+
const ctx = runtime.getContext();
|
|
423
|
+
|
|
424
|
+
// Plugins access via ctx.host (for legacy integration)
|
|
425
|
+
const { db, logger } = ctx.host;
|
|
426
|
+
```
|
|
427
|
+
|
|
428
|
+
### 7. Screens (Optional): UI Definitions
|
|
429
|
+
|
|
430
|
+
Define screens that any UI framework can render:
|
|
431
|
+
|
|
432
|
+
```typescript
|
|
433
|
+
ctx.screens.registerScreen({
|
|
434
|
+
id: 'orders:list',
|
|
435
|
+
title: 'Orders',
|
|
436
|
+
component: 'OrderListComponent' // string, class, function, or any type
|
|
437
|
+
});
|
|
438
|
+
```
|
|
439
|
+
|
|
440
|
+
---
|
|
441
|
+
|
|
442
|
+
## What can I build?
|
|
443
|
+
|
|
444
|
+
Skeleton Crew works for any modular JavaScript application:
|
|
445
|
+
|
|
446
|
+
### Developer Tools
|
|
447
|
+
- **CLI tools** - Task runners, deployment scripts, dev environments
|
|
448
|
+
- **Browser extensions** - Tab managers, productivity tools, dev tools
|
|
449
|
+
- **Build tools** - Custom bundlers, code generators, linters
|
|
450
|
+
|
|
451
|
+
### Internal Applications
|
|
452
|
+
- **Admin panels** - User management, content moderation, analytics
|
|
453
|
+
- **Dashboards** - Monitoring, reporting, data visualization
|
|
454
|
+
- **Workflow tools** - Approval systems, task management, automation
|
|
455
|
+
|
|
456
|
+
### Real-Time Applications
|
|
457
|
+
- **Collaboration tools** - Shared editing, presence, chat
|
|
458
|
+
- **Live dashboards** - Stock tickers, sports scores, IoT monitoring
|
|
459
|
+
- **Multiplayer features** - Game state sync, player coordination
|
|
460
|
+
|
|
461
|
+
### Modular Systems
|
|
462
|
+
- **Plugin marketplaces** - Let users extend your app
|
|
463
|
+
- **White-label products** - Different features for different customers
|
|
464
|
+
- **Microservices** - Coordinate distributed services
|
|
465
|
+
|
|
466
|
+
**Not ideal for:** Public-facing websites (use Next.js), complex routing (use React Router), heavy state management (use Redux).
|
|
467
|
+
|
|
468
|
+
---
|
|
469
|
+
|
|
470
|
+
## Real examples
|
|
471
|
+
|
|
472
|
+
### CLI Tool (150 lines vs 500+)
|
|
473
|
+
**What you'll see:** Interactive CLI that runs commands, shows output, handles errors. All plugin-based.
|
|
474
|
+
|
|
475
|
+
```bash
|
|
476
|
+
# Build a command palette for Git, npm, and Docker:
|
|
477
|
+
cd demo/dev-launcher
|
|
478
|
+
npm install && npm start
|
|
479
|
+
```
|
|
480
|
+
|
|
481
|
+
### Real-Time Collaboration (130 lines vs 500+)
|
|
482
|
+
**What you'll see:** Multiple clients syncing state in real-time. No Firebase, no Socket.io boilerplate.
|
|
483
|
+
|
|
484
|
+
```bash
|
|
485
|
+
# Build a multi-user sync system:
|
|
486
|
+
cd demo/collab-hub
|
|
487
|
+
npm install && npm run build
|
|
488
|
+
npm run server # Terminal 1
|
|
489
|
+
npm run client # Terminal 2-3
|
|
490
|
+
```
|
|
491
|
+
|
|
492
|
+
**[See all demos →](demo/README.md)**
|
|
493
|
+
|
|
494
|
+
---
|
|
495
|
+
|
|
496
|
+
## FAQ
|
|
497
|
+
|
|
498
|
+
### Do I need to rewrite my app?
|
|
499
|
+
|
|
500
|
+
No. Skeleton Crew runs alongside your existing code. Write new features as plugins, keep old code unchanged.
|
|
501
|
+
|
|
502
|
+
### What if I want to migrate existing features later?
|
|
503
|
+
|
|
504
|
+
You can gradually replace legacy code with plugins using feature flags. Or don't — both approaches work fine.
|
|
505
|
+
|
|
506
|
+
### Does this work with my UI framework?
|
|
507
|
+
|
|
508
|
+
Yes. Skeleton Crew is UI-agnostic. Use React, Vue, Svelte, or no UI at all. The runtime doesn't care.
|
|
509
|
+
|
|
510
|
+
### Is this overkill for small apps?
|
|
511
|
+
|
|
512
|
+
Possibly. If you have a simple app with no legacy code and no plans to grow, you might not need this. But if you're dealing with technical debt or planning for modularity, it's a good fit.
|
|
513
|
+
|
|
514
|
+
### How big is the runtime?
|
|
515
|
+
|
|
516
|
+
Less than 5KB gzipped. Minimal overhead.
|
|
517
|
+
|
|
518
|
+
### Can I use this in production?
|
|
519
|
+
|
|
520
|
+
Yes. The runtime is stable and tested. Start with non-critical features, then expand.
|
|
521
|
+
|
|
522
|
+
---
|
|
523
|
+
|
|
524
|
+
**Built for developers who need to modernize legacy apps without the risk of a full rewrite.**
|