@asterflow/plugin 1.0.9 → 1.1.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/README.md +31 -116
- package/dist/cjs/index.cjs +28 -28
- package/dist/mjs/index.js +16 -16
- package/dist/types/controllers/Plugin.d.ts +34 -19
- package/dist/types/types/plugin.d.ts +26 -9
- package/dist/types/types/utils.d.ts +6 -0
- package/package.json +20 -4
package/README.md
CHANGED
|
@@ -4,148 +4,63 @@
|
|
|
4
4
|
|
|
5
5
|

|
|
6
6
|

|
|
7
|
-

|
|
8
8
|
|
|
9
9
|

|
|
10
10
|
|
|
11
11
|
</div>
|
|
12
12
|
|
|
13
|
-
>
|
|
13
|
+
> The plugin-authoring system used to build AsterFlow plugins - a typed builder for context, config and lifecycle hooks.
|
|
14
14
|
|
|
15
15
|
## 📦 Installation
|
|
16
16
|
|
|
17
17
|
```bash
|
|
18
|
-
npm install @asterflow/plugin
|
|
19
|
-
# or
|
|
20
18
|
bun install @asterflow/plugin
|
|
21
19
|
```
|
|
22
20
|
|
|
23
|
-
|
|
21
|
+
### ✨ Features
|
|
24
22
|
|
|
25
|
-
|
|
23
|
+
- **Fluent builder:** chain `.config()`, `.decorate()`, `.derive()`, `.extends()` and `.on()` off a single `Plugin.create({ name })` call.
|
|
24
|
+
- **Typed config with defaults:** `.config()` sets the plugin's default config and infers its shape.
|
|
25
|
+
- **Static and derived context:** `.decorate()` injects a fixed value; `.derive()` computes a value from the config and context already built, lazily, when the plugin is registered.
|
|
26
|
+
- **Instance extensions:** `.extends()` adds new properties/methods to the AsterFlow instance, computed from the app and the plugin's context.
|
|
27
|
+
- **Lifecycle hooks:** `.on()` registers handlers for `beforeInitialize`, `afterInitialize`, `onRequest` and `onResponse`.
|
|
28
|
+
- **Type inference end-to-end:** every chained call narrows a single `Props` type, so config, context and extensions stay typed without manual generics.
|
|
26
29
|
|
|
27
|
-
##
|
|
30
|
+
## ❓ How to Use
|
|
28
31
|
|
|
29
|
-
|
|
30
|
-
- **Dynamic Context:** Inject static values into the plugin's context (`decorate`) or derive complex properties based on configuration and existing context (`derive`).
|
|
31
|
-
- **Lifecycle Hooks:** Register handlers for specific AsterFlow application events (such as `beforeInitialize`, `afterInitialize`, `onRequest`, and `onResponse`) to extend behavior at different stages.
|
|
32
|
-
- **Typed Configuration:** Define the plugin's configuration structure and its default values, with automatic type inference.
|
|
33
|
-
- **Type Safety:** Full TypeScript support to ensure your plugin's context, configuration, and hooks are type-safe.
|
|
34
|
-
- **Runtime Optimization:** Hooks are efficiently invoked only when the plugin is registered, allowing for performance optimizations.
|
|
32
|
+
Build a plugin with `Plugin.create`, then chain the pieces it needs. This one adds a config option and exposes a method on the AsterFlow instance:
|
|
35
33
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
`@asterflow/plugin` enables the creation of plugins that extend `AsterFlow` in a modular and type-safe manner. Below are examples of how to create and use plugins.
|
|
39
|
-
|
|
40
|
-
### Creating a Basic Plugin
|
|
41
|
-
|
|
42
|
-
```typescript
|
|
43
|
-
import { Plugin } from '@asterflow/plugin'
|
|
44
|
-
|
|
45
|
-
const myPlugin = Plugin.create({ name: 'my-first-plugin' })
|
|
46
|
-
.decorate('appName', 'My AsterFlow Application') // Adds a static value to the plugin's context
|
|
47
|
-
.on('beforeInitialize', (app, context) => {
|
|
48
|
-
console.log(`Initializing ${context.appName}...`)
|
|
49
|
-
// app is the AsterFlow instance
|
|
50
|
-
})
|
|
51
|
-
.on('afterInitialize', (app, context) => {
|
|
52
|
-
console.log(`${context.appName} has been initialized!`)
|
|
53
|
-
})
|
|
54
|
-
|
|
55
|
-
// This plugin can now be registered with `app.use(myPlugin)`
|
|
56
|
-
```
|
|
57
|
-
|
|
58
|
-
### Using Configuration and Derivation
|
|
59
|
-
|
|
60
|
-
Plugins can be configured and can derive values based on their configuration or existing context.
|
|
61
|
-
|
|
62
|
-
```typescript
|
|
34
|
+
```ts
|
|
63
35
|
import { Plugin } from '@asterflow/plugin'
|
|
64
36
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
featureName: 'Awesome Feature'
|
|
74
|
-
})
|
|
75
|
-
.derive('statusMessage', (context) => {
|
|
76
|
-
return context.featureEnabled
|
|
77
|
-
? `${context.featureName} is enabled.`
|
|
78
|
-
: `${context.featureName} is disabled.`
|
|
79
|
-
})
|
|
80
|
-
.on('beforeInitialize', (app, context) => {
|
|
81
|
-
console.log(context.statusMessage) // "Awesome Feature is enabled."
|
|
82
|
-
})
|
|
83
|
-
|
|
84
|
-
// This plugin can be configured when registered:
|
|
85
|
-
// app.use(featureTogglePlugin, { featureEnabled: false })
|
|
37
|
+
export const fsRoutingPlugin = Plugin.create({ name: 'fs-routing' })
|
|
38
|
+
.config({ routes: [] as unknown[] })
|
|
39
|
+
.extends((instance, context) => ({
|
|
40
|
+
registerRoutes() {
|
|
41
|
+
for (const route of context.routes) instance.controller(route)
|
|
42
|
+
}
|
|
43
|
+
}))
|
|
44
|
+
.on('beforeInitialize', (instance, context) => instance.registerRoutes())
|
|
86
45
|
```
|
|
87
46
|
|
|
88
|
-
|
|
47
|
+
`.decorate()` and `.derive()` build up the plugin's context the same way - `decorate` for a static value, `derive` for one computed from config/context:
|
|
89
48
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
import { Response } from '@asterflow/response'
|
|
96
|
-
|
|
97
|
-
const loggerPlugin = Plugin.create({ name: 'logger-plugin' })
|
|
98
|
-
.on('onRequest', (request, response, context) => {
|
|
99
|
-
// Logs request details
|
|
100
|
-
console.log(`[REQ] ${request.getMethod()} ${request.getPathname()}`)
|
|
101
|
-
})
|
|
102
|
-
.on('onResponse', (request, response, context) => {
|
|
103
|
-
// Logs response details
|
|
104
|
-
console.log(`[RES] ${response.getStatus()} ${request.getPathname()}`)
|
|
105
|
-
})
|
|
106
|
-
|
|
107
|
-
// Register this plugin for global logging
|
|
108
|
-
// app.use(loggerPlugin)
|
|
49
|
+
```ts
|
|
50
|
+
const withGreeting = Plugin.create({ name: 'greeting' })
|
|
51
|
+
.decorate('appName', 'My App')
|
|
52
|
+
.derive('greeting', (context) => `Hello, ${context.appName}!`)
|
|
53
|
+
.on('afterInitialize', (_app, context) => console.log(context.greeting))
|
|
109
54
|
```
|
|
110
55
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
To use the created plugins, you register them with the `AsterFlow` instance.
|
|
114
|
-
|
|
115
|
-
```typescript
|
|
116
|
-
import { AsterFlow } from 'asterflow'
|
|
117
|
-
import { adapters } from '@asterflow/adapter'
|
|
118
|
-
import fastify from 'fastify'
|
|
119
|
-
// Import your plugins here
|
|
120
|
-
// import { myPlugin, featureTogglePlugin, loggerPlugin } from './your-plugins'
|
|
121
|
-
|
|
122
|
-
const server = fastify()
|
|
123
|
-
const app = new AsterFlow({
|
|
124
|
-
driver: adapters.fastify
|
|
125
|
-
})
|
|
126
|
-
|
|
127
|
-
// Example plugin registration
|
|
128
|
-
app.use(myPlugin) // No additional configuration
|
|
129
|
-
app.use(featureTogglePlugin, { featureEnabled: false }) // With overridden configuration
|
|
130
|
-
app.use(loggerPlugin)
|
|
131
|
-
|
|
132
|
-
app.listen(server, { port: 3000 }, (err) => {
|
|
133
|
-
if (err) {
|
|
134
|
-
console.error(err)
|
|
135
|
-
process.exit(1)
|
|
136
|
-
}
|
|
137
|
-
console.log('AsterFlow server with plugins listening on port 3000!')
|
|
138
|
-
})
|
|
139
|
-
```
|
|
56
|
+
The finished plugin is registered on an app with `app.use(fsRoutingPlugin, { routes: [...] })`.
|
|
140
57
|
|
|
141
58
|
## 🔗 Related Packages
|
|
142
59
|
|
|
143
|
-
-
|
|
144
|
-
-
|
|
145
|
-
-
|
|
146
|
-
- [@asterflow/request](https://www.npmjs.com/package/@asterflow/request) - Unified HTTP request system.
|
|
147
|
-
- [@asterflow/response](https://www.npmjs.com/package/@asterflow/response) - Type-safe HTTP response system.
|
|
60
|
+
- Depended on by [asterflow](https://www.npmjs.com/package/asterflow) - the core framework consumes plugin instances and their types to power `app.use()`.
|
|
61
|
+
- Depended on by [@asterflow/multipart](https://www.npmjs.com/package/@asterflow/multipart) - built as a plugin with `Plugin.create()`.
|
|
62
|
+
- Depended on by `@asterflow/fs` - built as a plugin with `Plugin.create()`.
|
|
148
63
|
|
|
149
64
|
## 📄 License
|
|
150
65
|
|
|
151
|
-
|
|
66
|
+
This project is licensed under the [MIT License](../../LICENSE).
|
package/dist/cjs/index.cjs
CHANGED
|
@@ -1,34 +1,34 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var
|
|
3
|
-
var
|
|
4
|
-
var
|
|
2
|
+
var i = Object.defineProperty;
|
|
3
|
+
var c = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var l = Object.getOwnPropertyNames;
|
|
5
5
|
var d = Object.prototype.hasOwnProperty;
|
|
6
|
-
var
|
|
6
|
+
var f = (t, e) => {
|
|
7
7
|
for (var n in e)
|
|
8
|
-
|
|
9
|
-
},
|
|
8
|
+
i(t, n, { get: e[n], enumerable: !0 });
|
|
9
|
+
}, u = (t, e, n, o) => {
|
|
10
10
|
if (e && typeof e == "object" || typeof e == "function")
|
|
11
|
-
for (let s of
|
|
12
|
-
!d.call(
|
|
13
|
-
return
|
|
11
|
+
for (let s of l(e))
|
|
12
|
+
!d.call(t, s) && s !== n && i(t, s, { get: () => e[s], enumerable: !(o = c(e, s)) || o.enumerable });
|
|
13
|
+
return t;
|
|
14
14
|
};
|
|
15
|
-
var
|
|
15
|
+
var g = (t) => u(i({}, "__esModule", { value: !0 }), t);
|
|
16
16
|
// packages/plugin/src/index.ts
|
|
17
|
-
var
|
|
18
|
-
|
|
17
|
+
var h = {};
|
|
18
|
+
f(h, {
|
|
19
19
|
Plugin: () => a
|
|
20
20
|
});
|
|
21
|
-
module.exports =
|
|
21
|
+
module.exports = g(h);
|
|
22
22
|
// packages/plugin/src/controllers/Plugin.ts
|
|
23
|
-
var a = class
|
|
23
|
+
var a = class t {
|
|
24
24
|
name;
|
|
25
25
|
resolvers;
|
|
26
26
|
defaultConfig;
|
|
27
27
|
hooks = {};
|
|
28
28
|
instance;
|
|
29
29
|
_extensionFn;
|
|
30
|
-
constructor(e, n,
|
|
31
|
-
this.name = e, this.resolvers = n, this.hooks =
|
|
30
|
+
constructor(e, n, o, s, r) {
|
|
31
|
+
this.name = e, this.resolvers = n, this.hooks = o, this.defaultConfig = s, this._extensionFn = r;
|
|
32
32
|
}
|
|
33
33
|
config(e) {
|
|
34
34
|
return this.defaultConfig = {
|
|
@@ -40,32 +40,32 @@ var a = class o {
|
|
|
40
40
|
return this.instance = e, this;
|
|
41
41
|
}
|
|
42
42
|
decorate(e, n) {
|
|
43
|
-
let
|
|
44
|
-
...
|
|
43
|
+
let o = async (s, r) => ({
|
|
44
|
+
...r,
|
|
45
45
|
[e]: n
|
|
46
46
|
});
|
|
47
|
-
return this.resolvers = [...this.resolvers,
|
|
47
|
+
return this.resolvers = [...this.resolvers, o], this;
|
|
48
48
|
}
|
|
49
49
|
derive(e, n) {
|
|
50
|
-
let
|
|
51
|
-
let
|
|
50
|
+
let o = async (s, r) => {
|
|
51
|
+
let P = { ...r, ...s }, p = await n(P);
|
|
52
52
|
return {
|
|
53
|
-
...
|
|
54
|
-
[e]:
|
|
53
|
+
...r,
|
|
54
|
+
[e]: p
|
|
55
55
|
};
|
|
56
56
|
};
|
|
57
|
-
return this.resolvers = [...this.resolvers,
|
|
57
|
+
return this.resolvers = [...this.resolvers, o], this;
|
|
58
58
|
}
|
|
59
59
|
on(e, n) {
|
|
60
|
-
let
|
|
60
|
+
let o = this.hooks[e] || [];
|
|
61
61
|
return this.hooks = {
|
|
62
62
|
...this.hooks,
|
|
63
|
-
[e]: [...
|
|
63
|
+
[e]: [...o, n]
|
|
64
64
|
}, this;
|
|
65
65
|
}
|
|
66
66
|
extends(e) {
|
|
67
67
|
let n = this._extensionFn;
|
|
68
|
-
return this._extensionFn = (
|
|
68
|
+
return this._extensionFn = (o, s) => ({ ...n ? n(o, s) : {}, ...e(o, s) }), this;
|
|
69
69
|
}
|
|
70
70
|
_build(e) {
|
|
71
71
|
let n = { ...this.defaultConfig, ...e };
|
|
@@ -78,7 +78,7 @@ var a = class o {
|
|
|
78
78
|
};
|
|
79
79
|
}
|
|
80
80
|
static create(e) {
|
|
81
|
-
return new
|
|
81
|
+
return new t(e.name, [], {}, {}, void 0);
|
|
82
82
|
}
|
|
83
83
|
};
|
|
84
84
|
0 && (module.exports = {
|
package/dist/mjs/index.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
// packages/plugin/src/controllers/Plugin.ts
|
|
2
|
-
var
|
|
2
|
+
var r = class i {
|
|
3
3
|
name;
|
|
4
4
|
resolvers;
|
|
5
5
|
defaultConfig;
|
|
6
6
|
hooks = {};
|
|
7
7
|
instance;
|
|
8
8
|
_extensionFn;
|
|
9
|
-
constructor(e, n,
|
|
10
|
-
this.name = e, this.resolvers = n, this.hooks =
|
|
9
|
+
constructor(e, n, o, s, t) {
|
|
10
|
+
this.name = e, this.resolvers = n, this.hooks = o, this.defaultConfig = s, this._extensionFn = t;
|
|
11
11
|
}
|
|
12
12
|
config(e) {
|
|
13
13
|
return this.defaultConfig = {
|
|
@@ -19,32 +19,32 @@ var i = class r {
|
|
|
19
19
|
return this.instance = e, this;
|
|
20
20
|
}
|
|
21
21
|
decorate(e, n) {
|
|
22
|
-
let
|
|
23
|
-
...
|
|
22
|
+
let o = async (s, t) => ({
|
|
23
|
+
...t,
|
|
24
24
|
[e]: n
|
|
25
25
|
});
|
|
26
|
-
return this.resolvers = [...this.resolvers,
|
|
26
|
+
return this.resolvers = [...this.resolvers, o], this;
|
|
27
27
|
}
|
|
28
28
|
derive(e, n) {
|
|
29
|
-
let
|
|
30
|
-
let a = { ...
|
|
29
|
+
let o = async (s, t) => {
|
|
30
|
+
let a = { ...t, ...s }, P = await n(a);
|
|
31
31
|
return {
|
|
32
|
-
...
|
|
33
|
-
[e]:
|
|
32
|
+
...t,
|
|
33
|
+
[e]: P
|
|
34
34
|
};
|
|
35
35
|
};
|
|
36
|
-
return this.resolvers = [...this.resolvers,
|
|
36
|
+
return this.resolvers = [...this.resolvers, o], this;
|
|
37
37
|
}
|
|
38
38
|
on(e, n) {
|
|
39
|
-
let
|
|
39
|
+
let o = this.hooks[e] || [];
|
|
40
40
|
return this.hooks = {
|
|
41
41
|
...this.hooks,
|
|
42
|
-
[e]: [...
|
|
42
|
+
[e]: [...o, n]
|
|
43
43
|
}, this;
|
|
44
44
|
}
|
|
45
45
|
extends(e) {
|
|
46
46
|
let n = this._extensionFn;
|
|
47
|
-
return this._extensionFn = (
|
|
47
|
+
return this._extensionFn = (o, s) => ({ ...n ? n(o, s) : {}, ...e(o, s) }), this;
|
|
48
48
|
}
|
|
49
49
|
_build(e) {
|
|
50
50
|
let n = { ...this.defaultConfig, ...e };
|
|
@@ -57,9 +57,9 @@ var i = class r {
|
|
|
57
57
|
};
|
|
58
58
|
}
|
|
59
59
|
static create(e) {
|
|
60
|
-
return new
|
|
60
|
+
return new i(e.name, [], {}, {}, void 0);
|
|
61
61
|
}
|
|
62
62
|
};
|
|
63
63
|
export {
|
|
64
|
-
|
|
64
|
+
r as Plugin
|
|
65
65
|
};
|
|
@@ -1,20 +1,22 @@
|
|
|
1
1
|
import type { AnyAsterflow, ExtendedAsterflow } from 'asterflow';
|
|
2
|
-
import type { PluginHooks, Resolver } from '../types/plugin';
|
|
3
|
-
import type { Prettify, UnionToIntersection } from '../types/utils';
|
|
4
|
-
export declare class Plugin<
|
|
5
|
-
readonly name:
|
|
2
|
+
import type { DefaultPluginProps, PluginHooks, PluginProps, Resolver } from '../types/plugin';
|
|
3
|
+
import type { MergeProps, Prettify, UnionToIntersection } from '../types/utils';
|
|
4
|
+
export declare class Plugin<const Props extends PluginProps = DefaultPluginProps> {
|
|
5
|
+
readonly name: Props['path'];
|
|
6
6
|
resolvers: Resolver[];
|
|
7
|
-
defaultConfig: Partial<
|
|
8
|
-
hooks: PluginHooks<any,
|
|
9
|
-
instance:
|
|
7
|
+
defaultConfig: Partial<Props['config']>;
|
|
8
|
+
hooks: PluginHooks<any, Props['decorate'], any>;
|
|
9
|
+
instance: Props['instance'];
|
|
10
10
|
private _extensionFn?;
|
|
11
11
|
private constructor();
|
|
12
12
|
/**
|
|
13
13
|
* Defines the shape of the configuration and its default values for this plugin.
|
|
14
14
|
*/
|
|
15
|
-
config<C extends Record<string, any>>(defaultConfig: C): Plugin<
|
|
16
|
-
|
|
17
|
-
|
|
15
|
+
config<C extends Record<string, any>>(defaultConfig: C): Plugin<MergeProps<Props, {
|
|
16
|
+
config: Prettify<UnionToIntersection<{
|
|
17
|
+
defaultConfig: C;
|
|
18
|
+
} | C | Props["config"]>>;
|
|
19
|
+
}>>;
|
|
18
20
|
/**
|
|
19
21
|
* O `defineInstance` agora é mais simples. Ele não precisa mais re-tipar
|
|
20
22
|
* a classe inteira. Ele só serve para passar o `this` para o `_build`.
|
|
@@ -23,12 +25,16 @@ export declare class Plugin<Path extends string = string, Instance extends AnyAs
|
|
|
23
25
|
/**
|
|
24
26
|
* Adds a new static value to the plugin's context (decoration).
|
|
25
27
|
*/
|
|
26
|
-
decorate<Key extends string, Value>(key: Key, value: Value): Plugin<
|
|
28
|
+
decorate<Key extends string, Value>(key: Key, value: Value): Plugin<MergeProps<Props, {
|
|
29
|
+
decorate: Prettify<UnionToIntersection<Props["decorate"] | { [K in Key]: Value; }>>;
|
|
30
|
+
}>>;
|
|
27
31
|
/**
|
|
28
32
|
* Adds a new property to the context that is derived from the configuration and the existing context.
|
|
29
33
|
* The resolver function is executed lazily when the plugin is registered via `app.use()`.
|
|
30
34
|
*/
|
|
31
|
-
derive<Key extends string, Value>(key: Key, resolverFn: (context:
|
|
35
|
+
derive<Key extends string, Value>(key: Key, resolverFn: (context: Props['derive'] & Props['config'] & Props['decorate']) => Value | Promise<Value>): Plugin<MergeProps<Props, {
|
|
36
|
+
derive: Prettify<UnionToIntersection<Props["derive"] | { [K in Key]: Awaited<Value>; }>>;
|
|
37
|
+
}>>;
|
|
32
38
|
/**
|
|
33
39
|
* Registers a handler for a specific lifecycle event.
|
|
34
40
|
* Adding a hook makes the plugin "runtime-aware". AsterFlow can optimize by only
|
|
@@ -39,21 +45,23 @@ export declare class Plugin<Path extends string = string, Instance extends AnyAs
|
|
|
39
45
|
* .on('beforeInitialize', (app, context) => { })
|
|
40
46
|
* .on('beforeInitialize', (app, context) => { });
|
|
41
47
|
*/
|
|
42
|
-
on<Event extends keyof PluginHooks<ExtendedAsterflow<
|
|
48
|
+
on<Event extends keyof PluginHooks<ExtendedAsterflow<Props['instance']>, Prettify<UnionToIntersection<Props['derive'] | Props['config'] | Props['decorate']>>, Props['extension']>>(event: Event, handler: NonNullable<PluginHooks<ExtendedAsterflow<Props['instance']>, Prettify<UnionToIntersection<Props['derive'] | Props['config'] | Props['decorate']>>, Props['extension']>[Event]>[number]): this;
|
|
43
49
|
/**
|
|
44
50
|
* Defines new properties or methods to be added to the AsterFlow instance.
|
|
45
51
|
* A função recebe a instância do app e o contexto do plugin, e deve retornar um objeto
|
|
46
52
|
* com as novas propriedades.
|
|
47
53
|
*/
|
|
48
|
-
extends<E extends Record<string, any>>(extensionFn: (app:
|
|
54
|
+
extends<E extends Record<string, any>>(extensionFn: (app: Props['instance'], context: Prettify<UnionToIntersection<Props['config'] | Props['derive'] | Props['decorate']>>) => E): Plugin<MergeProps<Props, {
|
|
55
|
+
extension: Prettify<UnionToIntersection<Props["extension"] & E>>;
|
|
56
|
+
}>>;
|
|
49
57
|
/**
|
|
50
58
|
* Builds the final context and hooks from the provided configuration.
|
|
51
59
|
*/
|
|
52
60
|
_build(config: any): {
|
|
53
|
-
name:
|
|
54
|
-
context:
|
|
55
|
-
hooks: PluginHooks<any,
|
|
56
|
-
_extensionFn: ((app:
|
|
61
|
+
name: Props["path"];
|
|
62
|
+
context: Props["config"] & Props["derive"] & Props["decorate"];
|
|
63
|
+
hooks: PluginHooks<any, Props["decorate"], any>;
|
|
64
|
+
_extensionFn: ((app: Props["instance"], context: Prettify<UnionToIntersection<Props["config"] & Props["decorate"] & Props["derive"]>>) => Props["extension"]) | undefined;
|
|
57
65
|
resolvers: Resolver[];
|
|
58
66
|
};
|
|
59
67
|
/**
|
|
@@ -61,5 +69,12 @@ export declare class Plugin<Path extends string = string, Instance extends AnyAs
|
|
|
61
69
|
*/
|
|
62
70
|
static create<Path extends string, Asterflow extends AnyAsterflow>(options: {
|
|
63
71
|
name: Path;
|
|
64
|
-
}): Plugin<
|
|
72
|
+
}): Plugin<{
|
|
73
|
+
path: Path;
|
|
74
|
+
instance: Asterflow;
|
|
75
|
+
config: {};
|
|
76
|
+
decorate: {};
|
|
77
|
+
derive: {};
|
|
78
|
+
extension: {};
|
|
79
|
+
}>;
|
|
65
80
|
}
|
|
@@ -5,26 +5,43 @@ import type { AnyRouter } from '@asterflow/router';
|
|
|
5
5
|
import type { AnyAsterflow, ExtendedAsterflow, RouteEntry } from 'asterflow';
|
|
6
6
|
import type { Plugin } from '../controllers/Plugin';
|
|
7
7
|
import type { AnyRecord, UnionToIntersection } from './utils';
|
|
8
|
+
/** `Plugin`'s single generic parameter - the fields it needs to type a plugin. */
|
|
9
|
+
export interface PluginProps {
|
|
10
|
+
path: string;
|
|
11
|
+
instance: AnyAsterflow;
|
|
12
|
+
config: Record<string, any>;
|
|
13
|
+
decorate: Record<string, any>;
|
|
14
|
+
derive: Record<string, any>;
|
|
15
|
+
extension: Record<string, any>;
|
|
16
|
+
}
|
|
17
|
+
export type DefaultPluginProps = {
|
|
18
|
+
path: string;
|
|
19
|
+
instance: AnyAsterflow;
|
|
20
|
+
config: {};
|
|
21
|
+
decorate: {};
|
|
22
|
+
derive: {};
|
|
23
|
+
extension: {};
|
|
24
|
+
};
|
|
8
25
|
export type AnyPluginHooks = PluginHooks<AnyAsterflow, AnyRecord, AnyRecord>;
|
|
9
|
-
export type AnyPlugin = Plugin<
|
|
26
|
+
export type AnyPlugin = Plugin<any>;
|
|
10
27
|
export type AnyPlugins = Record<string, ResolvedPlugin<AnyPlugin>>;
|
|
11
28
|
export type AnyPluginInstance = ResolvedPlugin<AnyPlugin> & {
|
|
12
29
|
hooks: AnyPluginHooks;
|
|
13
30
|
};
|
|
14
|
-
export type InferPluginExtension<P> = P extends Plugin<
|
|
15
|
-
export type InferPluginContext<P> = P extends Plugin<
|
|
16
|
-
export type ResolvedPlugin<P extends Plugin<any
|
|
17
|
-
name:
|
|
18
|
-
context:
|
|
19
|
-
hooks: PluginHooks<any,
|
|
20
|
-
_extensionFn?: (app: any, context:
|
|
31
|
+
export type InferPluginExtension<P> = P extends Plugin<infer Props extends PluginProps> ? Props['extension'] : {};
|
|
32
|
+
export type InferPluginContext<P> = P extends Plugin<infer Props extends PluginProps> ? Prettify<UnionToIntersection<Props['config'] | Props['decorate'] | Props['derive']>> : {};
|
|
33
|
+
export type ResolvedPlugin<P extends Plugin<any>> = P extends Plugin<infer Props extends PluginProps> ? {
|
|
34
|
+
name: Props['path'];
|
|
35
|
+
context: InferPluginContext<P>;
|
|
36
|
+
hooks: PluginHooks<any, InferPluginContext<P>, Props['extension']>;
|
|
37
|
+
_extensionFn?: (app: any, context: InferPluginContext<P>) => Props['extension'];
|
|
21
38
|
resolvers: Resolver[];
|
|
22
39
|
} : never;
|
|
23
40
|
/**
|
|
24
41
|
* Tipo para extrair o objeto de configuração de um plugin.
|
|
25
42
|
* Ele torna as propriedades com valores padrão opcionais.
|
|
26
43
|
*/
|
|
27
|
-
export type InferConfigArgument<P extends Plugin<any
|
|
44
|
+
export type InferConfigArgument<P extends Plugin<any>> = P extends Plugin<infer Props extends PluginProps> ? Omit<Props['config'], keyof P['defaultConfig']> & Partial<Pick<Props['config'], keyof P['defaultConfig'] & keyof Props['config']>> : never;
|
|
28
45
|
/**
|
|
29
46
|
* Defines the available lifecycle hooks a plugin can register.
|
|
30
47
|
*/
|
|
@@ -3,3 +3,9 @@ export type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) ex
|
|
|
3
3
|
export type Prettify<T> = {
|
|
4
4
|
[K in keyof T]: T[K];
|
|
5
5
|
} & {};
|
|
6
|
+
/**
|
|
7
|
+
* Produces a new `Props` object type equal to `Props` with `Patch`'s keys
|
|
8
|
+
* overridden. Lets a fluent builder method name only the field(s) actually
|
|
9
|
+
* changing instead of respelling every unchanged generic slot.
|
|
10
|
+
*/
|
|
11
|
+
export type MergeProps<Props, Patch> = Prettify<Omit<Props, keyof Patch> & Patch>;
|
package/package.json
CHANGED
|
@@ -1,12 +1,28 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@asterflow/plugin",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.1.0",
|
|
4
|
+
"description": "The plugin-authoring system used to build AsterFlow plugins - a typed builder for context, config and lifecycle hooks.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"asterflow",
|
|
7
|
+
"plugin",
|
|
8
|
+
"plugin-system",
|
|
9
|
+
"typescript"
|
|
10
|
+
],
|
|
4
11
|
"main": "dist/cjs/index.cjs",
|
|
5
12
|
"module": "dist/mjs/index.js",
|
|
6
13
|
"types": "dist/types/index.d.ts",
|
|
7
14
|
"typings": "dist/types/index.d.ts",
|
|
8
15
|
"type": "module",
|
|
9
16
|
"license": "MIT",
|
|
17
|
+
"author": "Ashu11-A",
|
|
18
|
+
"repository": {
|
|
19
|
+
"type": "git",
|
|
20
|
+
"url": "git+https://github.com/AsterFlow/AsterFlow.git"
|
|
21
|
+
},
|
|
22
|
+
"bugs": {
|
|
23
|
+
"url": "https://github.com/AsterFlow/AsterFlow/issues"
|
|
24
|
+
},
|
|
25
|
+
"homepage": "https://github.com/AsterFlow/AsterFlow",
|
|
10
26
|
"exports": {
|
|
11
27
|
".": {
|
|
12
28
|
"types": "./dist/types/index.d.ts",
|
|
@@ -18,9 +34,9 @@
|
|
|
18
34
|
"node": ">=20"
|
|
19
35
|
},
|
|
20
36
|
"devDependencies": {
|
|
21
|
-
"asterflow": "0.0
|
|
22
|
-
"@asterflow/response": "1.0.10",
|
|
23
|
-
"@asterflow/request": "1.0.13"
|
|
37
|
+
"asterflow": "^1.0.0",
|
|
38
|
+
"@asterflow/response": "^1.0.10",
|
|
39
|
+
"@asterflow/request": "^1.0.13"
|
|
24
40
|
},
|
|
25
41
|
"peerDependencies": {
|
|
26
42
|
"typescript": "^5.8.3"
|