bajo 2.22.0 → 2.24.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/.jsdoc.conf.json +2 -1
- package/class/app.js +220 -107
- package/class/bajo.js +258 -177
- package/class/base.js +85 -24
- package/class/cache.js +8 -16
- package/class/err.js +31 -10
- package/class/log.js +46 -38
- package/class/plugin.js +53 -30
- package/class/print.js +18 -15
- package/class/tools.js +6 -5
- package/docs/App.html +51 -1
- package/docs/Bajo.html +1 -1
- package/docs/Base.html +34 -1
- package/docs/Cache.html +1 -1
- package/docs/Err.html +2 -2
- package/docs/Log.html +2 -2
- package/docs/Main.html +3 -0
- package/docs/Plugin.html +1 -1
- package/docs/Print.html +1 -1
- package/docs/Tools.html +1 -1
- package/docs/class_app.js.html +222 -109
- package/docs/class_bajo.js.html +260 -179
- package/docs/class_base.js.html +87 -26
- package/docs/class_cache.js.html +10 -18
- package/docs/class_err.js.html +33 -12
- package/docs/class_log.js.html +48 -40
- package/docs/class_plugin.js.html +55 -32
- package/docs/class_print.js.html +20 -17
- package/docs/class_tools.js.html +8 -7
- package/docs/data/search.json +1 -1
- package/docs/extend_bajo_hook.js.html +289 -0
- package/docs/global.html +22 -1
- package/docs/index.html +1 -1
- package/docs/index.js.html +53 -16
- package/docs/lib_applet-hook.js.html +328 -0
- package/docs/lib_config.js.html +167 -0
- package/docs/lib_helper.js.html +186 -192
- package/docs/module-Applet.html +3 -0
- package/docs/module-Helper-Main.html +3 -0
- package/docs/module-Helper.html +1 -8
- package/docs/module-Hook.html +1 -1
- package/docs/tutorial-01_WELCOME.html +3 -0
- package/docs/tutorial-02_GETTING_STARTED.html +125 -0
- package/docs/tutorial-03_USER_GUIDE.html +54 -0
- package/docs/tutorial-04_DEV_GUIDE.html +178 -0
- package/docs/tutorial-05_ECOSYSTEM.html +3 -0
- package/extend/bajo/intl/en-US.json +2 -1
- package/extend/bajo/intl/id.json +2 -1
- package/index.js +51 -14
- package/lib/applet-hook.js +325 -0
- package/lib/config.js +164 -0
- package/lib/helper.js +184 -190
- package/package.json +6 -2
- package/test/00-global-hooks.test.js +44 -0
- package/test/e2e/_run.js +19 -0
- package/test/e2e/e2e-applet-process.test.js +66 -0
- package/test/e2e/e2e-boot-process.test.js +62 -0
- package/test/e2e/e2e-hooks-process.test.js +68 -0
- package/test/integration/_setup.js +55 -0
- package/test/integration/aspect-01-boot-instance.test.js +24 -0
- package/test/integration/aspect-02-plugin-loading.test.js +24 -0
- package/test/integration/aspect-03-config-merge.test.js +27 -0
- package/test/integration/aspect-04-intl-loading.test.js +29 -0
- package/test/integration/aspect-05-cache-roundtrip.test.js +26 -0
- package/test/integration/aspect-06-log-file-save.test.js +28 -0
- package/test/integration/aspect-07-plugin-data-dir.test.js +25 -0
- package/test/integration/aspect-08-plugin-lookup.test.js +25 -0
- package/test/integration/aspect-09-config-formats.test.js +26 -0
- package/test/integration/aspect-10-hooks.test.js +38 -0
- package/test/unit/app.test.js +115 -0
- package/test/unit/applet-hook.test.js +10 -0
- package/test/unit/bajo.test.js +151 -0
- package/test/unit/base.test.js +90 -0
- package/test/unit/cache.test.js +89 -0
- package/test/unit/config.test.js +14 -0
- package/test/unit/err.test.js +57 -0
- package/test/unit/helper.test.js +116 -0
- package/test/unit/index.test.js +40 -0
- package/test/unit/log.test.js +84 -0
- package/test/unit/plugin.test.js +95 -0
- package/test/unit/print.test.js +72 -0
- package/test/unit/tools.test.js +29 -0
- package/wiki/CHANGES.md +9 -0
- package/wiki/tutorials/01_WELCOME.md +18 -0
- package/wiki/tutorials/02_GETTING_STARTED.md +366 -0
- package/wiki/tutorials/03_USER_GUIDE.md +262 -0
- package/wiki/tutorials/04_DEV_GUIDE.md +386 -0
- package/wiki/tutorials/05_ECOSYSTEM.md +95 -0
- package/wiki/tutorials/tutorials.json +17 -0
- package/lib/hook.js +0 -228
- package/test/app.test.js +0 -183
- package/test/bajo.test.js +0 -124
- package/test/base.test.js +0 -75
- package/test/cache.test.js +0 -94
- package/test/e2e.test.js +0 -137
- package/test/err.test.js +0 -73
- package/test/helper.test.js +0 -39
- package/test/import-module.test.js +0 -138
- package/test/integration.test.js +0 -218
- package/test/log.test.js +0 -119
- package/test/plugin.test.js +0 -116
- package/test/print.test.js +0 -100
- package/test/tools.test.js +0 -38
- package/wiki/CONFIG.md +0 -36
- package/wiki/DEV_GUIDE.md +0 -3
- package/wiki/ECOSYSTEM.md +0 -93
- package/wiki/GETTING-STARTED.md +0 -356
- package/wiki/USER-GUIDE.md +0 -256
|
@@ -0,0 +1,386 @@
|
|
|
1
|
+
# Developer Guide
|
|
2
|
+
|
|
3
|
+
This guide is intended for developers who want to create plugins for the Bajo framework. It provides an overview of the core classes, their relationships, and how to extend the framework with custom plugins.
|
|
4
|
+
|
|
5
|
+
Plugins are the building blocks of Bajo. They can be created to add new features, extend existing functionality, or integrate with external services. This guide will walk you through the process of creating a plugin, understanding the class hierarchy, and best practices for plugin development.
|
|
6
|
+
|
|
7
|
+
Finished plugins can be used in your own projects or shared with the community by publishing them to npm or other package managers. If you decide to share your plugin, please let us know so we can include it in our list of community plugins. We're more than happy to help you promote your plugin and make it available to other developers.
|
|
8
|
+
|
|
9
|
+
## Class Hierarchy
|
|
10
|
+
|
|
11
|
+
The core of Bajo is built around a few classes that form the foundation of the framework. The following diagram illustrates the class hierarchy and their relationships:
|
|
12
|
+
|
|
13
|
+
```
|
|
14
|
+
+-----------+ +-----------+ +-----------+ +-----------+
|
|
15
|
+
| Plugin | | Tools | | App | | Log |
|
|
16
|
+
+-----+-----+ +-----+-----+ +-----------+ +-----------+
|
|
17
|
+
| |
|
|
18
|
+
+----------------+ +----------------+
|
|
19
|
+
| | | |
|
|
20
|
+
+-----+-----+ +-----+-----+ +-----+-----+ +-----+-----+
|
|
21
|
+
| Bajo | | Base | | Err | | Print |
|
|
22
|
+
+-----------+ +-----+-----+ +-----------+ +-----------+
|
|
23
|
+
|
|
|
24
|
+
+----------------+----------------+-------------------+
|
|
25
|
+
| | | |
|
|
26
|
+
+-----+-----+ +-----+-----+ +-----+-----+ +-----+-----+
|
|
27
|
+
| Main | | Dobo | | Waibu | ... | MyPlugin |
|
|
28
|
+
+-----------+ +-----------+ +-----------+ +-----------+
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
All plugins in Bajo are derived from the {@link Base} class (derived in turn from the abstract class {@link Plugin}), which provides the basic structure and functionality for all plugins. The {@link Tools} class provides utility functions that can be used by plugins, while the {@link App} class represents the main application and manages the lifecycle of plugins.
|
|
32
|
+
|
|
33
|
+
Meanwhile, the {@link Log} class provides logging capabilities for debugging and monitoring.
|
|
34
|
+
|
|
35
|
+
Since every plugin is derived from the `Base` class, it inherits a reference to the main application instance through the `this.app` property, which allows plugins to access the application's inner properties and methods. And since all plugins are dynamically attached to the app instance as `this.app.pluginName` properties, they can also access other plugins' properties and methods. This allows easy communication and collaboration between plugins.
|
|
36
|
+
|
|
37
|
+
Example:
|
|
38
|
+
```javascript
|
|
39
|
+
// In your plugin class
|
|
40
|
+
...
|
|
41
|
+
async myMethod (params) {
|
|
42
|
+
const { getModel } = this.app.dobo
|
|
43
|
+
const model = await getModel('CdbCountry') // get `CdbCountry` model from `bajoCommonDatabase` plugin
|
|
44
|
+
const query = { id: { $in: ['ID', 'MY', 'AU' ] } } // define your query here
|
|
45
|
+
const limit = 10 // define your limit
|
|
46
|
+
const sort = { name: 1 } // define your sort order
|
|
47
|
+
|
|
48
|
+
const countries = await model.findRecord({ query, limit, sort }, { dataOnly: true }) // find records from the model
|
|
49
|
+
console.log(countries) // log the result
|
|
50
|
+
}
|
|
51
|
+
...
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Anatomy of a Plugin
|
|
55
|
+
|
|
56
|
+
A plugin is a normal JavaScript package with a `package.json` file and an entry point file (usually `index.js`) that exports a factory function. The factory function acts as a registration mechanism to the framework and is called by the Bajo at boot time.
|
|
57
|
+
|
|
58
|
+
The factory function must return a class that extends the {@link Base} class.
|
|
59
|
+
|
|
60
|
+
### Directory Structure
|
|
61
|
+
|
|
62
|
+
Shown below is a typical directory structure of a plugin:
|
|
63
|
+
|
|
64
|
+
```
|
|
65
|
+
.
|
|
66
|
+
├── asset
|
|
67
|
+
│ └── logo.png
|
|
68
|
+
├── extend
|
|
69
|
+
│ ├── bajo
|
|
70
|
+
│ ├── intl
|
|
71
|
+
│ │ ├── en-US.json
|
|
72
|
+
│ │ └── id.json
|
|
73
|
+
│ ├── hook
|
|
74
|
+
│ │ └── ...
|
|
75
|
+
│ └── ...
|
|
76
|
+
├── lib
|
|
77
|
+
│ └── ...
|
|
78
|
+
├── package.json
|
|
79
|
+
└── index.js
|
|
80
|
+
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
While the above structure is a common convention, it is not mandatory. A plugin can have any structure as long as it has a valid `package.json` file and an entry point file that exports a factory function explained below. However, following the conventions outlined in this guide will help ensure consistency and maintainability across plugins.
|
|
84
|
+
|
|
85
|
+
### package.json
|
|
86
|
+
|
|
87
|
+
{@link Base.package·json|package.json} file must be a valid npm package with a unique name in ES6 module format. It must include a `bajo` property with at least `type` set to `plugin` to be recognized as a plugin by the Bajo framework, e.g.:
|
|
88
|
+
|
|
89
|
+
```json
|
|
90
|
+
{
|
|
91
|
+
"name": "my-plugin",
|
|
92
|
+
"version": "1.0.0",
|
|
93
|
+
"type": "module",
|
|
94
|
+
"bajo": {
|
|
95
|
+
"type": "plugin",
|
|
96
|
+
"alias": "myplugin",
|
|
97
|
+
"dependencies": ["dobo", "dobo-common-database"]
|
|
98
|
+
},
|
|
99
|
+
"main": "index.js",
|
|
100
|
+
...
|
|
101
|
+
}
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
Please note that the `alias` property is optional and can be used to define a custom name for the plugin when it is attached to the app instance. If not provided, the plugin will be attached using its kebab cased plugin namespace.
|
|
105
|
+
|
|
106
|
+
If the plugin has dependencies on other plugins, they must be listed in the `dependencies` array. The Bajo framework will automatically load the required plugins before loading the current plugin.
|
|
107
|
+
|
|
108
|
+
{@link Base.package·json|Click here} for details.
|
|
109
|
+
|
|
110
|
+
### Boot File
|
|
111
|
+
|
|
112
|
+
Boot file (usually `index.js`) must export a factory function with one single parameter named `pkgName` and returns a class extending the {@link Base} class, e.g.:
|
|
113
|
+
|
|
114
|
+
```javascript
|
|
115
|
+
// index.js
|
|
116
|
+
async function factory (pkgName) {
|
|
117
|
+
const { Base } = this.app.baseClass
|
|
118
|
+
const me = this
|
|
119
|
+
return class MyPlugin extends Base {
|
|
120
|
+
constructor () {
|
|
121
|
+
super(pkgName, me.app)
|
|
122
|
+
this.config = {
|
|
123
|
+
key: {
|
|
124
|
+
subKey: 'value'
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
async init () {
|
|
130
|
+
// Initialization code here
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
export default factory
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
### Other Files and Directories
|
|
139
|
+
|
|
140
|
+
While the above two files are mandatory, a plugin can also include other files and directories as needed, such as assets, or additional modules. The inner structure of the plugin is flexible and can be organized according to the developer's preferences. Bajo class offers a set of methods, conventions, and best practices for organizing plugin files, which should be followed to ensure consistency and maintainability. Some conventions you could follow are:
|
|
141
|
+
- `asset/` directory: a plugin should have its own transparent png logo. If you have one, place it here with the name `logo.png`. This logo will be used in the Bajo framework's UI to represent your plugin. Other than the logo, you can also include other assets in this directory, such as images, icons, or other media files that your plugin may require.
|
|
142
|
+
- `lib/` directory: this is where you can place your plugin's libraries or modules. You can organize your code into multiple files and directories within this folder, following a structure that makes sense for your plugin's functionality.
|
|
143
|
+
- `extend/{otherPluginNs}` directory: if your plugin extends functionalities of other plugins, you can place the resource required for the extension here. This could include additional modules, configuration files, or other assets needed to properly extend the functionality of the other plugins. More on this in the **Extending Other Plugins** section below.
|
|
144
|
+
- Use kebab case for file and directory names. This is a common convention in the JavaScript ecosystem and helps maintain consistency across your plugin's structure.
|
|
145
|
+
|
|
146
|
+
### Configuration object
|
|
147
|
+
|
|
148
|
+
A plugin should use a {@link TConfig|configuration object} to define its configurable options as much as possible. This allows users to easily customize the behavior of the plugin without modifying its code directly.
|
|
149
|
+
|
|
150
|
+
More on this see [this.config](#this.config) section below.
|
|
151
|
+
|
|
152
|
+
## Class Properties and Methods
|
|
153
|
+
|
|
154
|
+
Since all plugins are derived from the {@link Base} class, they inherit a set of properties and methods that can be used to interact with the Bajo framework and other plugins. Some of the most commonly used properties and methods include:
|
|
155
|
+
|
|
156
|
+
### _this.app_
|
|
157
|
+
|
|
158
|
+
A reference to the main {@link App|app} instance. This is may be the most used property in a plugin, as it allows you to interact with the rest of the Bajo framework and other plugins. You can use this property to access other plugins, call their methods, or retrieve their configuration:
|
|
159
|
+
- `this.app.{pluginNs}`: access to other plugins' properties and methods. For example, if you want to access the `dobo` plugin, you can use `this.app.dobo`.
|
|
160
|
+
- `this.app.lib`: access to the most commonly used libraries in Bajo, such as `_` (lodash), `fs`, `fastGlob`, `dayjs`, etc.
|
|
161
|
+
- `this.app.baseClass`: access to the base class definition of Bajo, such as `Base`, `Dobo`, `Waibu`, etc.
|
|
162
|
+
- `this.app.getAllNs()`: retrieves an array of all plugin namespaces loaded in the app
|
|
163
|
+
- and many more. See {@link App} for a complete list of properties and methods available in the app instance.
|
|
164
|
+
|
|
165
|
+
### _this.config_
|
|
166
|
+
|
|
167
|
+
The default configuration object, which can be overridden by environment variables, command line arguments, or configuration files. If this property is missing, Bajo will assign an empty object to it.
|
|
168
|
+
|
|
169
|
+
You are **strongly** recommended to define a default configuration object in your plugin class, as it allows users to easily customize the behavior of the plugin without modifying its code directly.
|
|
170
|
+
|
|
171
|
+
The default configuration object defined here can later be overridden by a set of methods listed below in the order of priority:
|
|
172
|
+
- {@link App#envVars|Environment variables}: a plugin's configuration can be overridden by names starting with `{PLUGIN_NAMESPACE}.{KEY}` (e.g., `MY_PLUGIN.KEY__SUB_KEY`).
|
|
173
|
+
- {@link App#argv|Command line arguments}: a plugin's configuration can be overridden by names starting with `--{pluginNs}:{key}` (e.g., `--myPlugin:key-subKey`).
|
|
174
|
+
- Configuration files with env: a plugin's configuration can be overridden by editing `{dataDir}/config/{pluginNs}-{env}.{ext}` file, where `{env}` is the environment and `{ext}` is the file extension of your choice.
|
|
175
|
+
- Default configuration file: a plugin's configuration can be overridden by editing `{dataDir}/config/{pluginNs}.{ext}` file, where `{ext}` is the file extension of your choice.
|
|
176
|
+
- If none are provided, the plugin will use its default configuration object defined in the plugin class.
|
|
177
|
+
|
|
178
|
+
> **Warning**: It is important to note that only values that are defined in the default configuration object can be overridden. If a key is not present in the default configuration object, it will be ignored even if it is provided in the environment variables, command line arguments, or configuration files. If you leave it empty, users will not be able to override any configuration options for your plugin.
|
|
179
|
+
|
|
180
|
+
### _this.init()_
|
|
181
|
+
|
|
182
|
+
After a plugin is successfully instantiated and loaded, the `init()` method is called. This is where you can perform any setup or initialization tasks for your plugin, or even modify the configuration object that has been overridden by the user.
|
|
183
|
+
|
|
184
|
+
This is where you can sanitize the configuration object, validate its values, or set up any necessary resources for your plugin.
|
|
185
|
+
|
|
186
|
+
### _this.start()_
|
|
187
|
+
|
|
188
|
+
After all plugins (including yours) have been loaded and initialized, Bajo begins to start the plugin one by one in the same order determined by the boot process. Your plugin's `start()` method is then called.
|
|
189
|
+
|
|
190
|
+
This is where you can safely perform your plugin's main tasks, such as starting servers, connecting to databases, etc.
|
|
191
|
+
|
|
192
|
+
After this method is called, the plugin is considered to be fully loaded and ready to use. `this.config` will be frozen and cannot be modified.
|
|
193
|
+
|
|
194
|
+
### _this.exit()_
|
|
195
|
+
|
|
196
|
+
When the app is exiting gracefully (e.g. by pressing `Ctrl+C`), the `exit()` method is called for each plugin in the reverse order of the boot process. This is where you can perform any cleanup tasks for your plugin, such as closing database connections, stopping servers, or releasing resources.
|
|
197
|
+
|
|
198
|
+
This method won't be called if the app is terminated abruptly (e.g. by calling `this.fatal()` method or `this.app.exit(true)` or by killing the process). In such cases, the app will exit immediately without giving the plugin a chance to clean up.
|
|
199
|
+
|
|
200
|
+
### Own Members
|
|
201
|
+
|
|
202
|
+
You can define your own properties and methods in your plugin class as needed. These properties and methods can then be used to implement the functionality of your plugin, and can be accessed by other plugins through the `this.app.{pluginNs}` property.
|
|
203
|
+
|
|
204
|
+
It is advisable to always use anonymous functions for your methods to avoid issues with `this` binding. This is especially important because `this` may not refer to the plugin instance when the method is called as a callback or event handler. Even if your class becomes big and to overcome this complexity you must import your methods from other files, you should still force bind these functions to `this` to the plugin instance.
|
|
205
|
+
|
|
206
|
+
You can do this manually by using `bind(this)` or using the inherited `this.bindThis()` method, as shown in the example below:
|
|
207
|
+
|
|
208
|
+
```javascript
|
|
209
|
+
import { myMethod1, myMethod2, myMethod3 } from './lib/methods.js'
|
|
210
|
+
|
|
211
|
+
async function factory (pkgName) {
|
|
212
|
+
const { Base } = this.app.baseClass
|
|
213
|
+
const me = this
|
|
214
|
+
return class MyPlugin extends Base {
|
|
215
|
+
constructor () {
|
|
216
|
+
super(pkgName, me.app)
|
|
217
|
+
this.config = {
|
|
218
|
+
key: {
|
|
219
|
+
subKey: 'value'
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
this.bindThis(myMethod1, myMethod2, myMethod3) // bind all methods to this plugin instance
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
> **Note**: It is recommended to always put your methods in the same file as your plugin class, unless the method becomes too big. Putting your methods in the same file as your plugin class will make it easier to read and understand the code, and will also make it easier to maintain and debug. It is also important to note that having too many imported methods from other files can impact the load time and performance.
|
|
230
|
+
|
|
231
|
+
## Extending Other Plugins
|
|
232
|
+
|
|
233
|
+
The beauty of Bajo is that it allows you to extend other plugins without modifying their code. By convention, this is done by placing your extension files in the `extend/{otherPluginNs}` directory, where `{otherPluginNs}` is the namespace of the plugin you want to extend.
|
|
234
|
+
|
|
235
|
+
There are no strict rules on how other plugins can be extended because it is up to the plugin developer to decide how they want to expose their plugin's functionality for extension. For this reason, it is important to read the documentation of the plugin you want to extend to understand how to properly extend it.
|
|
236
|
+
|
|
237
|
+
Core `bajo` itself is a plugin and offers a set of extension points to extend its own functionality. Shown below are some of the most commonly used extension points in Bajo:
|
|
238
|
+
|
|
239
|
+
### Translation
|
|
240
|
+
|
|
241
|
+
Your plugin is i18n-ready by default and you should use it extensively by providing translation files in the `extend/bajo/intl` directory. The translation files should be named using the locale code (e.g., `en-US.json`, `id.json`, etc.) and should contain key-value pairs for the translations.
|
|
242
|
+
|
|
243
|
+
Example:
|
|
244
|
+
- Your english translation file in `extend/bajo/intl/en-US.json`:
|
|
245
|
+
```json
|
|
246
|
+
{
|
|
247
|
+
"hello%s": "Hello %s, welcome to Bajo!",
|
|
248
|
+
"goodbye%s": "Goodbye %s, see you later!"
|
|
249
|
+
}
|
|
250
|
+
```
|
|
251
|
+
- Your indonesian translation file in `extend/bajo/intl/id.json`:
|
|
252
|
+
```json
|
|
253
|
+
{
|
|
254
|
+
"hello%s": "Halo %s, selamat datang di Bajo!",
|
|
255
|
+
"goodbye%s": "Sampai jumpa %s, sampai bertemu lagi!"
|
|
256
|
+
}
|
|
257
|
+
```
|
|
258
|
+
- Somewhere in your plugin or module:
|
|
259
|
+
```javascript
|
|
260
|
+
// Assuming the current locale is set to 'en-US'
|
|
261
|
+
const greeting = this.t('hello%s', 'John') // returns "Hello John, welcome to Bajo!"
|
|
262
|
+
const farewell = this.t('goodbye%s', 'John') // returns "Goodbye John, see you later!"
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
Text translation always begins using your own translation file. If the key is not found, it will be looked in all other plugins, including the core Bajo's translation files. If none is found, it will return the key itself; interpolated with the provided arguments if any.
|
|
266
|
+
|
|
267
|
+
It is advisable to always look for the key in core Bajo or other plugins first before adding your own translation key to minimize duplication and maintain consistency. Unless you intend to override it, in which case you should use the same key as the original translation.
|
|
268
|
+
|
|
269
|
+
> **Note**: Even though Bajo supports multiple formats, only JSON format is allowed for translation files. The reason is that JSON parsing is very fast and needs lower overhead compared to other formats. This is important for performance, especially when dealing with large translation files.
|
|
270
|
+
|
|
271
|
+
### Hook
|
|
272
|
+
|
|
273
|
+
A hook is a way to extend the functionality of a plugin by allowing other plugins to register their own functions to be called at specific points in the plugin's lifecycle. This allows for a high degree of flexibility and customization, as other plugins can modify the behavior of the plugin without modifying its code.
|
|
274
|
+
|
|
275
|
+
As a plugin developer, you can define your own insertion points in your plugin by using the Bajo's `runHook()` method. And as a plugin user, you can create your own functions to be called at those insertion points as shown below:
|
|
276
|
+
|
|
277
|
+
- Insertion points within your plugin:
|
|
278
|
+
```javascript
|
|
279
|
+
...
|
|
280
|
+
doSomething = async (filter, options = {}) => {
|
|
281
|
+
const { getModel } = this.app.dobo
|
|
282
|
+
const model = await getModel('CdbCountry') // get `CdbCountry` model from `bajoCommonDatabase` plugin
|
|
283
|
+
return await model.findRecord(filter, options) // find records from the model
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
start = async () => {
|
|
287
|
+
const { runHook } = this.app.bajo
|
|
288
|
+
await runHook('myPlugin:beforeDoSomething', filter, options) // first insertion point
|
|
289
|
+
const result = await this.doSomething(filter, options) // your plugin's main function
|
|
290
|
+
await runHook('myPlugin:afterDoSomething', filter, result, options) // second insertion point
|
|
291
|
+
}
|
|
292
|
+
...
|
|
293
|
+
```
|
|
294
|
+
- Hook listeners in other plugins (or even in the same plugin), using one `hook.js` file:
|
|
295
|
+
```javascript
|
|
296
|
+
// create a hook listener in `/extend/myPlugin/hook.js` file
|
|
297
|
+
const hooks = [
|
|
298
|
+
{
|
|
299
|
+
name: 'myPlugin:beforeDoSomething',
|
|
300
|
+
handler: async (filter, options) => {
|
|
301
|
+
// do something before the main function is called
|
|
302
|
+
console.log('Before doing something:', filter, options)
|
|
303
|
+
}
|
|
304
|
+
},
|
|
305
|
+
{
|
|
306
|
+
name: 'myPlugin:afterDoSomething',
|
|
307
|
+
handler: async (filter, result, options) => {
|
|
308
|
+
// do something after the main function is called
|
|
309
|
+
console.log('After doing something:', filter, result, options)
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
]
|
|
313
|
+
|
|
314
|
+
export default hooks
|
|
315
|
+
```
|
|
316
|
+
- Hook listeners using multiple files per hook:
|
|
317
|
+
```javascript
|
|
318
|
+
// create the first listener in `/extend/myPlugin/hook/my-plugin@before-do-something.js` file
|
|
319
|
+
async function beforeDoSomething (param, options) {
|
|
320
|
+
// do something before the main function is called
|
|
321
|
+
console.log('Before doing something:', param, options)
|
|
322
|
+
}
|
|
323
|
+
export default beforeDoSomething
|
|
324
|
+
|
|
325
|
+
// and the second listener in `/extend/myPlugin/hook/my-plugin@after-do-something.js` file
|
|
326
|
+
async function afterDoSomething (param, result, options) {
|
|
327
|
+
// do something after the main function is called
|
|
328
|
+
console.log('After doing something:', param, result, options)
|
|
329
|
+
}
|
|
330
|
+
export default afterDoSomething
|
|
331
|
+
|
|
332
|
+
> **Warning**: Even though hooks are a powerful feature, they should be used sparingly and only when necessary. Overusing hooks can lead to code that is difficult to understand and maintain. It is important to carefully consider whether a hook is the best solution for a given problem before implementing it.
|
|
333
|
+
|
|
334
|
+
## Creating Extendable Plugins
|
|
335
|
+
|
|
336
|
+
There are no clear rules on how to create extendable plugins because it is up to the plugin developer to decide how they want to expose their plugin's functionality for extension. However, there are some best practices that can be followed to make your plugin more extendable and easier to use by other developers.
|
|
337
|
+
|
|
338
|
+
Let's take an example on how [Dobo](https://ardhi.github.io/dobo) was created.
|
|
339
|
+
|
|
340
|
+
### Case Study: Dobo Models
|
|
341
|
+
|
|
342
|
+
As you might already know, Dobo is a plugin that provides a set of tools for working with databases. It is designed to be extendable so that other plugins can add their own functionality to it. And it becomes the sub-framework of its own, which is used by many other plugins to provide database-related functionality.
|
|
343
|
+
|
|
344
|
+
Dobo grew out of the need to have a common set of tools for working with databases in Bajo. It supposed to be:
|
|
345
|
+
- A plugin that provides a set of tools for working with databases, such as models, queries, and migrations
|
|
346
|
+
- A plugin that supports many adapters for many different databases, be it SQL or NoSQL, relational or non-relational, and even in-memory databases
|
|
347
|
+
- A plugin that provides one common interface for CRUD operations, including database queries, regardless of the underlying database technology
|
|
348
|
+
|
|
349
|
+
How do we solve this problem?
|
|
350
|
+
|
|
351
|
+
We could make a whole book about this, but let's dive on one particular problem and make a case study: how do we make Dobo collect and manage database models from other plugins. This is done as follows:
|
|
352
|
+
|
|
353
|
+
1. Create a directory `extend/dobo/model` in your plugin directory. This is where your table schemas will be placed.
|
|
354
|
+
2. Create a schema file in it with the name `{table-name}.{js|json|yml}` where `{table-name}` is the name of the table. You can use any format supported by App's config handler, but we recommend using JSON format for consistency and performance reasons. This results a model named `{Alias}{TableName}` where `{Alias}` is the alias of the plugin that provides the model, and `{TableName}` is the name of the table in PascalCase format. For example, if your plugin alias is `myplugin` and you create a schema file named `country.json` it will result a model named `MypluginCountry`.
|
|
355
|
+
3. The model schema file should contain the table schema in a specific format. Please refer to the [Dobo documentation](https://ardhi.github.io/dobo) for the more details. In short, it should contain the fields, and their types, as well as any other relevant information such as indexes etc.
|
|
356
|
+
|
|
357
|
+
Now comes the tricky part: how do we make Dobo collect all those schemas and turned into a database model so that it can be used anywhere? By using Bajo's {@link Bajo#eachPlugins|eachPlugins()} method.
|
|
358
|
+
|
|
359
|
+
`eachPlugins(callback, options)` method is a powerful method that allows you to iterate over all plugins loaded in the app. It takes a callback function as its first parameter, which will be called for each iteration and an `options` object as its second parameter to control the operation
|
|
360
|
+
|
|
361
|
+
To make things clear, let's take a look at the code below taken directly from Dobo's source code and reformatted for better readability:
|
|
362
|
+
|
|
363
|
+
```javascript
|
|
364
|
+
...
|
|
365
|
+
init = async () => {
|
|
366
|
+
const { eachPlugins } = this.app.bajo
|
|
367
|
+
const { dobo } = this.app
|
|
368
|
+
// options parameter
|
|
369
|
+
const options = {
|
|
370
|
+
prefix: dobo.ns, // read all files started from `extend/dobo` directory
|
|
371
|
+
glob: ['model/*.*', 'model.*'] // read all files in `model` directory or its parent that match with `model.*` pattern
|
|
372
|
+
}
|
|
373
|
+
// callback function
|
|
374
|
+
async function callback ({ file }) {
|
|
375
|
+
// 'this' is always the calling plugin instance, in this case is your plugin instance
|
|
376
|
+
// `file` is the file name, in absolute path, e.g. `/path/to/your/plugin/extend/dobo/model/country.json`
|
|
377
|
+
const model = await dobo.createModelFromSchema(file) // fictitious method to create model from schema file
|
|
378
|
+
dobo.models.push(model) // add the model to the list of models in Dobo
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
// now read all schema files from all plugins and create models from them
|
|
382
|
+
await eachPlugins(callback, options)
|
|
383
|
+
// by now all models from all plugins have been collected and added to Dobo's model list, and can be used anywhere
|
|
384
|
+
}
|
|
385
|
+
...
|
|
386
|
+
```
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
# Ecosystem
|
|
2
|
+
|
|
3
|
+
Bajo is a modular framework, and its ecosystem is growing rapidly. The following are the main plugins that are part of the Bajo ecosystem. Each plugin has its own documentation and can be installed separately
|
|
4
|
+
|
|
5
|
+
## Bajo Plugins
|
|
6
|
+
|
|
7
|
+
| Package | Docs | Description |
|
|
8
|
+
| ------- | ---- | ----------- |
|
|
9
|
+
| [bajo-cache](https://github.com/ardhi/bajo-cache) | [Docs](https://ardhi.github.io/bajo-cache) | Universal cache system. Support db result sets and generic caching, in-memory and persistent storage |
|
|
10
|
+
| [bajo-cli](https://github.com/ardhi/bajo-cli) | [Docs](https://ardhi.github.io/bajo-cli) | Command line interface and tools including project scaffolding, task running, and more |
|
|
11
|
+
| [bajo-common-db](https://github.com/ardhi/bajo-common-db) | [Docs](https://ardhi.github.io/bajo-common-db) | Commonly used database and utility functions |
|
|
12
|
+
| [bajo-config](https://github.com/ardhi/bajo-config) | [Docs](https://ardhi.github.io/bajo-config) | TOML support, command line converter through applets |
|
|
13
|
+
| [bajo-extra](https://github.com/ardhi/bajo-extra) | [Docs](https://ardhi.github.io/bajo-extra) | Extra utilities and class methods for everyday use |
|
|
14
|
+
| [bajo-markdown](https://github.com/ardhi/bajo-markdown) | [Docs](https://ardhi.github.io/bajo-markdown) | Markdown support including parsing, rendering and front matter |
|
|
15
|
+
| [bajo-spatial](https://github.com/ardhi/bajo-spatial) | [Docs](https://ardhi.github.io/bajo-spatial) | Spatial support including geospatial queries and indexing|
|
|
16
|
+
| [bajo-sysinfo](https://github.com/ardhi/bajo-sysinfo) | [Docs](https://ardhi.github.io/bajo-sysinfo) | System information including hardware and software details. Super useful for system diagnostics |
|
|
17
|
+
| [bajo-template](https://github.com/ardhi/bajo-template) | [Docs](https://ardhi.github.io/bajo-template) | Official templating engine for Bajo |
|
|
18
|
+
|
|
19
|
+
## Dobo DBMS Plugins
|
|
20
|
+
|
|
21
|
+
| Package | Docs | Description |
|
|
22
|
+
| ------- | ---- | ----------- |
|
|
23
|
+
| [dobo](https://github.com/ardhi/dobo) | [Docs](https://ardhi.github.io/dobo) | Dobo DBMS framework. Features include model management, built-in memory adapter, connection manager and more |
|
|
24
|
+
| [dobo-extra](https://github.com/ardhi/dobo-extra) | [Docs](https://ardhi.github.io/dobo-extra) | Dobo extra tools and utilities including import/export from/to file with various formats |
|
|
25
|
+
| [dobo-couchdb](https://github.com/ardhi/dobo-couchdb) | [Docs](https://ardhi.github.io/dobo-couchdb) | CouchDB adapter for Dobo DBMS |
|
|
26
|
+
| [dobo-elasticsearch](https://github.com/ardhi/dobo-elasticsearch) | [Docs](https://ardhi.github.io/dobo-elasticsearch) | Elasticsearch adapter for Dobo DBMS |
|
|
27
|
+
| [dobo-knex](https://github.com/ardhi/dobo-knex) | [Docs](https://ardhi.github.io/dobo-knex) | Knex based SQL abstraction layer. You must use one of the SQL adapters (e.g., dobo-mysql, dobo-sqlite3, etc) because it doesn't work standalone |
|
|
28
|
+
| [dobo-mysql](https://github.com/ardhi/dobo-mysql) | [Docs](https://ardhi.github.io/dobo-mysql) | MySQL/Mariadb adapter for Dobo DBMS |
|
|
29
|
+
| [dobo-sqlite3](https://github.com/ardhi/dobo-sqlite3) | [Docs](https://ardhi.github.io/dobo-sqlite3) | SQLite3 adapter for Dobo DBMS |
|
|
30
|
+
| [dobo-postgresql](https://github.com/ardhi/dobo-postgresql) | [Docs](https://ardhi.github.io/dobo-postgresql) | PostgreSQL/CockroachDB/Redshift adapter for Dobo DBMS |
|
|
31
|
+
| [dobo-clickhouse](https://github.com/ardhi/dobo-clickhouse) | [Docs](https://ardhi.github.io/dobo-clickhouse) | ClickHouse adapter for Dobo DBMS |
|
|
32
|
+
| [dobo-mongodb](https://github.com/ardhi/dobo-mongodb) | [Docs](https://ardhi.github.io/dobo-mongodb) | MongoDB adapter for Dobo DBMS |
|
|
33
|
+
| [dobo-redis](https://github.com/ardhi/dobo-redis) | [Docs](https://ardhi.github.io/dobo-redis) | Redis adapter for Dobo DBMS |
|
|
34
|
+
| [dobo-restproxy](https://github.com/ardhi/dobo-restproxy) | [Docs](https://ardhi.github.io/dobo-restproxy) | Restproxy adapter for Dobo DBMS |
|
|
35
|
+
| [dobo-restproxy-jsonserver](https://github.com/ardhi/dobo-restproxy-jsonserver) | [Docs](https://ardhi.github.io/dobo-restproxy-jsonserver) | JsonServer support for doboRestproxy |
|
|
36
|
+
|
|
37
|
+
## Waibu Web Framework Plugins
|
|
38
|
+
|
|
39
|
+
| Package | Docs | Description |
|
|
40
|
+
| ------- | ---- | ----------- |
|
|
41
|
+
| [waibu](https://github.com/ardhi/waibu) | [Docs](https://ardhi.github.io/waibu) | Waibu web framework for Bajo. Based on Fastify, a fast and low-overhead web framework for Node.js |
|
|
42
|
+
| [waibu-admin](https://github.com/ardhi/waibu-admin) | [Docs](https://ardhi.github.io/waibu-admin) | Admin interface to manage the Waibu framework, including automatic support for CRUD operations |
|
|
43
|
+
| [waibu-alpinejs](https://github.com/ardhi/waibu-alpinejs) | [Docs](https://ardhi.github.io/waibu-alpinejs) | Alpine.js support needed by Bootstrap's components & widgets |
|
|
44
|
+
| [waibu-blu](https://github.com/ardhi/waibu-blu) | [Docs](https://ardhi.github.io/waibu-blu) | Blu theme |
|
|
45
|
+
| [waibu-bootstrap](https://github.com/ardhi/waibu-bootstrap) | [Docs](https://ardhi.github.io/waibu-bootstrap) | Bootstrap support for Waibu framework. Offers a plethora of widgets and utilities |
|
|
46
|
+
| [waibu-bootstrap-icons](https://github.com/ardhi/waibu-bootstrap-icons) | [Docs](https://ardhi.github.io/waibu-bootstrap-icons) | Bootstrap Icons support for Waibu framework |
|
|
47
|
+
| [waibu-bootswatch](https://github.com/ardhi/waibu-bootswatch) | [Docs](https://ardhi.github.io/waibu-bootswatch) | Bootswatch theme |
|
|
48
|
+
| [waibu-db](https://github.com/ardhi/waibu-db) | [Docs](https://ardhi.github.io/waibu-db) | Dobo DBMS utilities for Waibu framework. Provides seamless integration with Waibu's data layer |
|
|
49
|
+
| [waibu-extra](https://github.com/ardhi/waibu-extra) | [Docs](https://ardhi.github.io/waibu-extra) | Most used 3rd party libs including jquery, masonry layout, echarts, highlightjs and more |
|
|
50
|
+
| [waibu-maps](https://github.com/ardhi/waibu-maps) | [Docs](https://ardhi.github.io/waibu-maps) | Web maps support based on Maplibrejs offers everything you would need for interactive maps |
|
|
51
|
+
| [waibu-mpa](https://github.com/ardhi/waibu-mpa) | [Docs](https://ardhi.github.io/waibu-mpa) | Multi pages app architecture sub framework for Waibu. Features including page routing, theme management, iconset, and more. |
|
|
52
|
+
| [waibu-phosphor](https://github.com/ardhi/waibu-phosphor) | [Docs](https://ardhi.github.io/waibu-phosphor) | Phosphor Icons support |
|
|
53
|
+
| [waibu-rest-api](https://github.com/ardhi/waibu-rest-api) | [Docs](https://ardhi.github.io/waibu-rest-api) | Rest API sub framework offers everything you need to build and serve RESTful APIs |
|
|
54
|
+
| [waibu-static](https://github.com/ardhi/waibu-static) | [Docs](https://ardhi.github.io/waibu-static) | Static asset management for Waibu framework |
|
|
55
|
+
| [waibu-swagger](https://github.com/ardhi/waibu-swagger) | [Docs](https://ardhi.github.io/waibu-swagger) | Rest API Documentation support |
|
|
56
|
+
|
|
57
|
+
## Masohi Messaging Plugins
|
|
58
|
+
|
|
59
|
+
| Package | Docs | Description |
|
|
60
|
+
| ------- | ---- | ----------- |
|
|
61
|
+
| [masohi](https://github.com/ardhi/masohi) | [Docs](https://ardhi.github.io/masohi) | Masohi messaging framework for Bajo. Features various connectors and codecs and built-in queue engine |
|
|
62
|
+
| [masohi-codec](https://github.com/ardhi/masohi-codec) | [Docs](https://ardhi.github.io/masohi-codec) | Basic codecs for Masohi messaging framework |
|
|
63
|
+
| [masohi-codec-ais](https://github.com/ardhi/masohi-codec-ais) | [Docs](https://ardhi.github.io/masohi-codec-ais) | AIS Codec |
|
|
64
|
+
| [masohi-mail](https://github.com/ardhi/masohi-mail) | [Docs](https://ardhi.github.io/masohi-mail) | Mail Connector for Masohi messaging framework |
|
|
65
|
+
| [masohi-mqtt](https://github.com/ardhi/masohi-mqtt) | [Docs](https://ardhi.github.io/masohi-mqtt) | MQTT Connector for Masohi messaging framework |
|
|
66
|
+
| [masohi-serialport](https://github.com/ardhi/masohi-serialport) | [Docs](https://ardhi.github.io/masohi-serialport) | Serialport Connector for Masohi messaging framework |
|
|
67
|
+
| [masohi-socket.io](https://github.com/ardhi/masohi-socket.io) | [Docs](https://ardhi.github.io/masohi-socket.io) | Socket.io Connector for Masohi messaging framework |
|
|
68
|
+
|
|
69
|
+
## Sumba Biz Suite Plugins
|
|
70
|
+
|
|
71
|
+
| Package | Docs | Description |
|
|
72
|
+
| ------- | ---- | ----------- |
|
|
73
|
+
| [sumba](https://github.com/ardhi/sumba) | [Docs](https://ardhi.github.io/sumba) | Sumba Biz Suite. Features site, user, team management, including authentication, authorization, and more |
|
|
74
|
+
| [sumba-cms](https://github.com/ardhi/sumba-cms) | [Docs](https://ardhi.github.io/sumba-cms) | Sumba CMS for content management within the Sumba Biz Suite |
|
|
75
|
+
| [sumba-geonames](https://github.com/ardhi/sumba-geonames) | [Docs](https://ardhi.github.io/sumba-geonames) | Sumba Geonames support |
|
|
76
|
+
| [sumba-nominatim](https://github.com/ardhi/sumba-nominatim) | [Docs](https://ardhi.github.io/sumba-nominatim) | Sumba OSM Nominatim support |
|
|
77
|
+
| [sumba-oauth](https://github.com/ardhi/sumba-oauth) | [Docs](https://ardhi.github.io/sumba-oauth) | Extends Sumba Biz Suite with OAuth providers |
|
|
78
|
+
|
|
79
|
+
## Sumba Biz Suite Premium Plugins
|
|
80
|
+
|
|
81
|
+
| Package | Docs | Description |
|
|
82
|
+
| ------- | ---- | ----------- |
|
|
83
|
+
| [@sumba/geofence](https://bajo.app/premium-plugins/sumba-geofence) | [Docs](https://ardhi.github.io/sumba-geofence) | Sumba Geofence management & support |
|
|
84
|
+
| [@sumba/maps](https://bajo.app/premium-plugins/sumba-maps) | [Docs](https://ardhi.github.io/sumba-maps) | Sumba maps, extends Waibu maps to the next level, with support including various widgets and more |
|
|
85
|
+
| [@sumba/proxy](https://bajo.app/premium-plugins/sumba-proxy) | [Docs](https://ardhi.github.io/sumba-proxy) | Sumba Proxy: transparently cache any web resources to your users |
|
|
86
|
+
| [@sumba/seatrack](https://bajo.app/premium-plugins/sumba-seatrack) | [Docs](https://ardhi.github.io/sumba-seatrack) | Sumba Seatrack: Everything you need to build a maritime tracking system |
|
|
87
|
+
| [@sumba/seatrack-global](https://bajo.app/premium-plugins/sumba-seatrack-global) | [Docs](https://ardhi.github.io/sumba-seatrack-global) | Sumba Seatrack Global: AIS tracking support with Rapp.id Datahub API |
|
|
88
|
+
| [@sumba/seatrack-vts](https://bajo.app/premium-plugins/sumba-seatrack-vts) | [Docs](https://ardhi.github.io/sumba-seatrack-vts) | Sumba Seatrack VTS: VTS/VMS Support for Sumba Seatrack |
|
|
89
|
+
| [@sumba/seatrack-wpi](https://bajo.app/premium-plugins/sumba-seatrack-wpi) | [Docs](https://ardhi.github.io/sumba-seatrack-wpi) | Sumba Seatrack WPI: WPI (World Port Index) Support for Sumba Seatrack |
|
|
90
|
+
| [@sumba/skytrack](https://bajo.app/premium-plugins/sumba-skytrack) | [Docs](https://ardhi.github.io/sumba-skytrack) | Sumba Skytrack: Everything you need to build an aerial tracking system |
|
|
91
|
+
| [@sumba/skytrack-global](https://bajo.app/premium-plugins/sumba-skytrack-global) | [Docs](https://ardhi.github.io/sumba-skytrack-global) | Sumba Skytrack Global: ADSB tracking support with Rapp.id Datahub API |
|
|
92
|
+
| [@sumba/store](https://bajo.app/premium-plugins/sumba-store) | [Docs](https://ardhi.github.io/sumba-store) | Sumba Store: E-Commerce & online stores management |
|
|
93
|
+
| [@sumba/subscription](https://bajo.app/premium-plugins/sumba-subscription) | [Docs](https://ardhi.github.io/sumba-subscription) | Sumba Subscription: Member subscription system |
|
|
94
|
+
| [@sumba/weather](https://bajo.app/premium-plugins/sumba-weather) | [Docs](https://ardhi.github.io/sumba-weather) | Sumba Weather support with Rapp.id Datahub API |
|
|
95
|
+
| [@sumba/webstat](https://bajo.app/premium-plugins/sumba-webstat) | [Docs](https://ardhi.github.io/sumba-webstat) | Sumba Web Statistic |
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"01_WELCOME": {
|
|
3
|
+
"title": "Welcome"
|
|
4
|
+
},
|
|
5
|
+
"02_GETTING_STARTED": {
|
|
6
|
+
"title": "Getting Started"
|
|
7
|
+
},
|
|
8
|
+
"03_USER_GUIDE": {
|
|
9
|
+
"title": "User Guide"
|
|
10
|
+
},
|
|
11
|
+
"04_DEV_GUIDE": {
|
|
12
|
+
"title": "Developer Guide"
|
|
13
|
+
},
|
|
14
|
+
"05_ECOSYSTEM": {
|
|
15
|
+
"title": "Ecosystem"
|
|
16
|
+
}
|
|
17
|
+
}
|