s3db.js 10.0.19 → 11.0.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/dist/s3db.cjs.js +606 -206
- package/dist/s3db.cjs.js.map +1 -1
- package/dist/s3db.es.js +606 -206
- package/dist/s3db.es.js.map +1 -1
- package/package.json +1 -1
- package/src/concerns/plugin-storage.js +443 -0
- package/src/database.class.js +48 -15
- package/src/plugins/audit.plugin.js +1 -1
- package/src/plugins/backup.plugin.js +1 -1
- package/src/plugins/cache.plugin.js +2 -6
- package/src/plugins/eventual-consistency/analytics.js +16 -4
- package/src/plugins/eventual-consistency/consolidation.js +18 -1
- package/src/plugins/eventual-consistency/index.js +4 -4
- package/src/plugins/eventual-consistency/{setup.js → install.js} +7 -6
- package/src/plugins/fulltext.plugin.js +3 -4
- package/src/plugins/metrics.plugin.js +10 -11
- package/src/plugins/plugin.class.js +79 -9
- package/src/plugins/queue-consumer.plugin.js +4 -3
- package/src/plugins/replicator.plugin.js +11 -13
- package/src/plugins/s3-queue.plugin.js +1 -1
- package/src/plugins/scheduler.plugin.js +8 -9
- package/src/plugins/state-machine.plugin.js +3 -4
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
* @module eventual-consistency/
|
|
2
|
+
* Install logic for EventualConsistencyPlugin
|
|
3
|
+
* @module eventual-consistency/install
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import tryFn from "../../concerns/try-fn.js";
|
|
@@ -11,14 +11,14 @@ import { startConsolidationTimer } from "./consolidation.js";
|
|
|
11
11
|
import { startGarbageCollectionTimer } from "./garbage-collection.js";
|
|
12
12
|
|
|
13
13
|
/**
|
|
14
|
-
*
|
|
14
|
+
* Install plugin for all configured resources
|
|
15
15
|
*
|
|
16
16
|
* @param {Object} database - Database instance
|
|
17
17
|
* @param {Map} fieldHandlers - Field handlers map
|
|
18
|
-
* @param {Function} completeFieldSetupFn - Function to complete setup for a field
|
|
18
|
+
* @param {Function} completeFieldSetupFn - Function to complete field setup for a field
|
|
19
19
|
* @param {Function} watchForResourceFn - Function to watch for resource creation
|
|
20
20
|
*/
|
|
21
|
-
export async function
|
|
21
|
+
export async function onInstall(database, fieldHandlers, completeFieldSetupFn, watchForResourceFn) {
|
|
22
22
|
// Iterate over all resource/field combinations
|
|
23
23
|
for (const [resourceName, resourceHandlers] of fieldHandlers) {
|
|
24
24
|
const targetResource = database.resources[resourceName];
|
|
@@ -70,7 +70,7 @@ export function watchForResource(resourceName, database, fieldHandlers, complete
|
|
|
70
70
|
}
|
|
71
71
|
|
|
72
72
|
/**
|
|
73
|
-
* Complete setup for a single field handler
|
|
73
|
+
* Complete field setup for a single field handler
|
|
74
74
|
*
|
|
75
75
|
* @param {Object} handler - Field handler
|
|
76
76
|
* @param {Object} database - Database instance
|
|
@@ -174,6 +174,7 @@ async function createAnalyticsResource(handler, database, resourceName, fieldNam
|
|
|
174
174
|
name: analyticsResourceName,
|
|
175
175
|
attributes: {
|
|
176
176
|
id: 'string|required',
|
|
177
|
+
field: 'string|required',
|
|
177
178
|
period: 'string|required',
|
|
178
179
|
cohort: 'string|required',
|
|
179
180
|
transactionCount: 'number|required',
|
|
@@ -13,11 +13,10 @@ export class FullTextPlugin extends Plugin {
|
|
|
13
13
|
this.indexes = new Map(); // In-memory index for simplicity
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
-
async
|
|
17
|
-
this.database = database;
|
|
16
|
+
async onInstall() {
|
|
18
17
|
|
|
19
18
|
// Create index resource if it doesn't exist
|
|
20
|
-
const [ok, err, indexResource] = await tryFn(() => database.createResource({
|
|
19
|
+
const [ok, err, indexResource] = await tryFn(() => this.database.createResource({
|
|
21
20
|
name: 'plg_fulltext_indexes',
|
|
22
21
|
attributes: {
|
|
23
22
|
id: 'string|required',
|
|
@@ -29,7 +28,7 @@ export class FullTextPlugin extends Plugin {
|
|
|
29
28
|
lastUpdated: 'string|required'
|
|
30
29
|
}
|
|
31
30
|
}));
|
|
32
|
-
this.indexResource = ok ? indexResource : database.resources.fulltext_indexes;
|
|
31
|
+
this.indexResource = ok ? indexResource : this.database.resources.fulltext_indexes;
|
|
33
32
|
|
|
34
33
|
// Load existing indexes
|
|
35
34
|
await this.loadIndexes();
|
|
@@ -31,12 +31,11 @@ export class MetricsPlugin extends Plugin {
|
|
|
31
31
|
this.flushTimer = null;
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
-
async
|
|
35
|
-
this.database = database;
|
|
34
|
+
async onInstall() {
|
|
36
35
|
if (typeof process !== 'undefined' && process.env.NODE_ENV === 'test') return;
|
|
37
36
|
|
|
38
37
|
const [ok, err] = await tryFn(async () => {
|
|
39
|
-
const [ok1, err1, metricsResource] = await tryFn(() => database.createResource({
|
|
38
|
+
const [ok1, err1, metricsResource] = await tryFn(() => this.database.createResource({
|
|
40
39
|
name: 'plg_metrics',
|
|
41
40
|
attributes: {
|
|
42
41
|
id: 'string|required',
|
|
@@ -51,9 +50,9 @@ export class MetricsPlugin extends Plugin {
|
|
|
51
50
|
metadata: 'json'
|
|
52
51
|
}
|
|
53
52
|
}));
|
|
54
|
-
this.metricsResource = ok1 ? metricsResource : database.resources.plg_metrics;
|
|
53
|
+
this.metricsResource = ok1 ? metricsResource : this.database.resources.plg_metrics;
|
|
55
54
|
|
|
56
|
-
const [ok2, err2, errorsResource] = await tryFn(() => database.createResource({
|
|
55
|
+
const [ok2, err2, errorsResource] = await tryFn(() => this.database.createResource({
|
|
57
56
|
name: 'plg_error_logs',
|
|
58
57
|
attributes: {
|
|
59
58
|
id: 'string|required',
|
|
@@ -64,9 +63,9 @@ export class MetricsPlugin extends Plugin {
|
|
|
64
63
|
metadata: 'json'
|
|
65
64
|
}
|
|
66
65
|
}));
|
|
67
|
-
this.errorsResource = ok2 ? errorsResource : database.resources.plg_error_logs;
|
|
66
|
+
this.errorsResource = ok2 ? errorsResource : this.database.resources.plg_error_logs;
|
|
68
67
|
|
|
69
|
-
const [ok3, err3, performanceResource] = await tryFn(() => database.createResource({
|
|
68
|
+
const [ok3, err3, performanceResource] = await tryFn(() => this.database.createResource({
|
|
70
69
|
name: 'plg_performance_logs',
|
|
71
70
|
attributes: {
|
|
72
71
|
id: 'string|required',
|
|
@@ -77,13 +76,13 @@ export class MetricsPlugin extends Plugin {
|
|
|
77
76
|
metadata: 'json'
|
|
78
77
|
}
|
|
79
78
|
}));
|
|
80
|
-
this.performanceResource = ok3 ? performanceResource : database.resources.plg_performance_logs;
|
|
79
|
+
this.performanceResource = ok3 ? performanceResource : this.database.resources.plg_performance_logs;
|
|
81
80
|
});
|
|
82
81
|
if (!ok) {
|
|
83
82
|
// Resources might already exist
|
|
84
|
-
this.metricsResource = database.resources.plg_metrics;
|
|
85
|
-
this.errorsResource = database.resources.plg_error_logs;
|
|
86
|
-
this.performanceResource = database.resources.plg_performance_logs;
|
|
83
|
+
this.metricsResource = this.database.resources.plg_metrics;
|
|
84
|
+
this.errorsResource = this.database.resources.plg_error_logs;
|
|
85
|
+
this.performanceResource = this.database.resources.plg_performance_logs;
|
|
87
86
|
}
|
|
88
87
|
|
|
89
88
|
// Use database hooks for automatic resource discovery
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import EventEmitter from "events";
|
|
2
|
+
import { PluginStorage } from "../concerns/plugin-storage.js";
|
|
2
3
|
|
|
3
4
|
export class Plugin extends EventEmitter {
|
|
4
5
|
constructor(options = {}) {
|
|
@@ -6,13 +7,50 @@ export class Plugin extends EventEmitter {
|
|
|
6
7
|
this.name = this.constructor.name;
|
|
7
8
|
this.options = options;
|
|
8
9
|
this.hooks = new Map();
|
|
10
|
+
|
|
11
|
+
// Auto-generate slug from class name (CamelCase -> kebab-case)
|
|
12
|
+
// e.g., EventualConsistencyPlugin -> eventual-consistency-plugin
|
|
13
|
+
this.slug = options.slug || this._generateSlug();
|
|
14
|
+
|
|
15
|
+
// Storage instance (lazy-loaded)
|
|
16
|
+
this._storage = null;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Generate kebab-case slug from class name
|
|
21
|
+
* @private
|
|
22
|
+
* @returns {string}
|
|
23
|
+
*/
|
|
24
|
+
_generateSlug() {
|
|
25
|
+
return this.name
|
|
26
|
+
.replace(/Plugin$/, '') // Remove "Plugin" suffix
|
|
27
|
+
.replace(/([a-z])([A-Z])/g, '$1-$2') // CamelCase -> kebab-case
|
|
28
|
+
.toLowerCase();
|
|
9
29
|
}
|
|
10
30
|
|
|
11
|
-
|
|
31
|
+
/**
|
|
32
|
+
* Get PluginStorage instance (lazy-loaded)
|
|
33
|
+
* @returns {PluginStorage}
|
|
34
|
+
*/
|
|
35
|
+
getStorage() {
|
|
36
|
+
if (!this._storage) {
|
|
37
|
+
if (!this.database || !this.database.client) {
|
|
38
|
+
throw new Error('Plugin must be installed before accessing storage');
|
|
39
|
+
}
|
|
40
|
+
this._storage = new PluginStorage(this.database.client, this.slug);
|
|
41
|
+
}
|
|
42
|
+
return this._storage;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Install plugin
|
|
47
|
+
* @param {Database} database - Database instance
|
|
48
|
+
*/
|
|
49
|
+
async install(database) {
|
|
12
50
|
this.database = database;
|
|
13
|
-
this.
|
|
14
|
-
await this.
|
|
15
|
-
this.
|
|
51
|
+
this.beforeInstall();
|
|
52
|
+
await this.onInstall();
|
|
53
|
+
this.afterInstall();
|
|
16
54
|
}
|
|
17
55
|
|
|
18
56
|
async start() {
|
|
@@ -27,8 +65,28 @@ export class Plugin extends EventEmitter {
|
|
|
27
65
|
this.afterStop();
|
|
28
66
|
}
|
|
29
67
|
|
|
68
|
+
/**
|
|
69
|
+
* Uninstall plugin and cleanup all data
|
|
70
|
+
* @param {Object} options - Uninstall options
|
|
71
|
+
* @param {boolean} options.purgeData - Delete all plugin data from S3 (default: false)
|
|
72
|
+
*/
|
|
73
|
+
async uninstall(options = {}) {
|
|
74
|
+
const { purgeData = false } = options;
|
|
75
|
+
|
|
76
|
+
this.beforeUninstall();
|
|
77
|
+
await this.onUninstall(options);
|
|
78
|
+
|
|
79
|
+
// Purge all plugin data if requested
|
|
80
|
+
if (purgeData && this._storage) {
|
|
81
|
+
const deleted = await this._storage.deleteAll();
|
|
82
|
+
this.emit('plugin.dataPurged', { deleted });
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
this.afterUninstall();
|
|
86
|
+
}
|
|
87
|
+
|
|
30
88
|
// Override these methods in subclasses
|
|
31
|
-
async
|
|
89
|
+
async onInstall() {
|
|
32
90
|
// Override in subclasses
|
|
33
91
|
}
|
|
34
92
|
|
|
@@ -40,6 +98,10 @@ export class Plugin extends EventEmitter {
|
|
|
40
98
|
// Override in subclasses
|
|
41
99
|
}
|
|
42
100
|
|
|
101
|
+
async onUninstall(options) {
|
|
102
|
+
// Override in subclasses
|
|
103
|
+
}
|
|
104
|
+
|
|
43
105
|
// Hook management methods
|
|
44
106
|
addHook(resource, event, handler) {
|
|
45
107
|
if (!this.hooks.has(resource)) {
|
|
@@ -182,12 +244,12 @@ export class Plugin extends EventEmitter {
|
|
|
182
244
|
}
|
|
183
245
|
|
|
184
246
|
// Event emission methods
|
|
185
|
-
|
|
186
|
-
this.emit("plugin.
|
|
247
|
+
beforeInstall() {
|
|
248
|
+
this.emit("plugin.beforeInstall", new Date());
|
|
187
249
|
}
|
|
188
250
|
|
|
189
|
-
|
|
190
|
-
this.emit("plugin.
|
|
251
|
+
afterInstall() {
|
|
252
|
+
this.emit("plugin.afterInstall", new Date());
|
|
191
253
|
}
|
|
192
254
|
|
|
193
255
|
beforeStart() {
|
|
@@ -205,6 +267,14 @@ export class Plugin extends EventEmitter {
|
|
|
205
267
|
afterStop() {
|
|
206
268
|
this.emit("plugin.afterStop", new Date());
|
|
207
269
|
}
|
|
270
|
+
|
|
271
|
+
beforeUninstall() {
|
|
272
|
+
this.emit("plugin.beforeUninstall", new Date());
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
afterUninstall() {
|
|
276
|
+
this.emit("plugin.afterUninstall", new Date());
|
|
277
|
+
}
|
|
208
278
|
}
|
|
209
279
|
|
|
210
280
|
export default Plugin;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { Plugin } from './plugin.class.js';
|
|
1
2
|
import { createConsumer } from './consumers/index.js';
|
|
2
3
|
import tryFn from "../concerns/try-fn.js";
|
|
3
4
|
|
|
@@ -20,16 +21,16 @@ import tryFn from "../concerns/try-fn.js";
|
|
|
20
21
|
// reconnectInterval: 2000,
|
|
21
22
|
// });
|
|
22
23
|
|
|
23
|
-
export class QueueConsumerPlugin {
|
|
24
|
+
export class QueueConsumerPlugin extends Plugin {
|
|
24
25
|
constructor(options = {}) {
|
|
26
|
+
super(options);
|
|
25
27
|
this.options = options;
|
|
26
28
|
// New pattern: consumers = [{ driver, config, consumers: [{ queueUrl, resources, ... }] }]
|
|
27
29
|
this.driversConfig = Array.isArray(options.consumers) ? options.consumers : [];
|
|
28
30
|
this.consumers = [];
|
|
29
31
|
}
|
|
30
32
|
|
|
31
|
-
async
|
|
32
|
-
this.database = database;
|
|
33
|
+
async onInstall() {
|
|
33
34
|
|
|
34
35
|
for (const driverDef of this.driversConfig) {
|
|
35
36
|
const { driver, config: driverConfig = {}, consumers: consumerDefs = [] } = driverDef;
|
|
@@ -236,12 +236,10 @@ export class ReplicatorPlugin extends Plugin {
|
|
|
236
236
|
this.eventListenersInstalled.add(resource.name);
|
|
237
237
|
}
|
|
238
238
|
|
|
239
|
-
async
|
|
240
|
-
this.database = database;
|
|
241
|
-
|
|
239
|
+
async onInstall() {
|
|
242
240
|
// Create replicator log resource if enabled
|
|
243
241
|
if (this.config.persistReplicatorLog) {
|
|
244
|
-
const [ok, err, logResource] = await tryFn(() => database.createResource({
|
|
242
|
+
const [ok, err, logResource] = await tryFn(() => this.database.createResource({
|
|
245
243
|
name: this.config.replicatorLogResource || 'plg_replicator_logs',
|
|
246
244
|
attributes: {
|
|
247
245
|
id: 'string|required',
|
|
@@ -253,24 +251,24 @@ export class ReplicatorPlugin extends Plugin {
|
|
|
253
251
|
},
|
|
254
252
|
behavior: 'truncate-data'
|
|
255
253
|
}));
|
|
256
|
-
|
|
254
|
+
|
|
257
255
|
if (ok) {
|
|
258
256
|
this.replicatorLogResource = logResource;
|
|
259
257
|
} else {
|
|
260
|
-
this.replicatorLogResource = database.resources[this.config.replicatorLogResource || 'plg_replicator_logs'];
|
|
258
|
+
this.replicatorLogResource = this.database.resources[this.config.replicatorLogResource || 'plg_replicator_logs'];
|
|
261
259
|
}
|
|
262
260
|
}
|
|
263
261
|
|
|
264
262
|
// Initialize replicators
|
|
265
|
-
await this.initializeReplicators(database);
|
|
266
|
-
|
|
263
|
+
await this.initializeReplicators(this.database);
|
|
264
|
+
|
|
267
265
|
// Use database hooks for automatic resource discovery
|
|
268
266
|
this.installDatabaseHooks();
|
|
269
|
-
|
|
267
|
+
|
|
270
268
|
// Install event listeners for existing resources
|
|
271
|
-
for (const resource of Object.values(database.resources)) {
|
|
269
|
+
for (const resource of Object.values(this.database.resources)) {
|
|
272
270
|
if (resource.name !== (this.config.replicatorLogResource || 'plg_replicator_logs')) {
|
|
273
|
-
this.installEventListeners(resource, database, this);
|
|
271
|
+
this.installEventListeners(resource, this.database, this);
|
|
274
272
|
}
|
|
275
273
|
}
|
|
276
274
|
}
|
|
@@ -334,8 +332,8 @@ export class ReplicatorPlugin extends Plugin {
|
|
|
334
332
|
}
|
|
335
333
|
|
|
336
334
|
async uploadMetadataFile(database) {
|
|
337
|
-
if (typeof database.uploadMetadataFile === 'function') {
|
|
338
|
-
await database.uploadMetadataFile();
|
|
335
|
+
if (typeof this.database.uploadMetadataFile === 'function') {
|
|
336
|
+
await this.database.uploadMetadataFile();
|
|
339
337
|
}
|
|
340
338
|
}
|
|
341
339
|
|
|
@@ -97,7 +97,7 @@ export class S3QueuePlugin extends Plugin {
|
|
|
97
97
|
this.lockCleanupInterval = null;
|
|
98
98
|
}
|
|
99
99
|
|
|
100
|
-
async
|
|
100
|
+
async onInstall() {
|
|
101
101
|
// Get target resource
|
|
102
102
|
this.targetResource = this.database.resources[this.config.resource];
|
|
103
103
|
if (!this.targetResource) {
|
|
@@ -29,11 +29,11 @@ import { idGenerator } from "../concerns/id.js";
|
|
|
29
29
|
* schedule: '0 3 * * *',
|
|
30
30
|
* description: 'Clean up expired records',
|
|
31
31
|
* action: async (database, context) => {
|
|
32
|
-
* const expired = await database.resource('sessions')
|
|
32
|
+
* const expired = await this.database.resource('sessions')
|
|
33
33
|
* .list({ where: { expiresAt: { $lt: new Date() } } });
|
|
34
34
|
*
|
|
35
35
|
* for (const record of expired) {
|
|
36
|
-
* await database.resource('sessions').delete(record.id);
|
|
36
|
+
* await this.database.resource('sessions').delete(record.id);
|
|
37
37
|
* }
|
|
38
38
|
*
|
|
39
39
|
* return { deleted: expired.length };
|
|
@@ -48,8 +48,8 @@ import { idGenerator } from "../concerns/id.js";
|
|
|
48
48
|
* schedule: '0 9 * * MON',
|
|
49
49
|
* description: 'Generate weekly analytics report',
|
|
50
50
|
* action: async (database, context) => {
|
|
51
|
-
* const users = await database.resource('users').count();
|
|
52
|
-
* const orders = await database.resource('orders').count({
|
|
51
|
+
* const users = await this.database.resource('users').count();
|
|
52
|
+
* const orders = await this.database.resource('orders').count({
|
|
53
53
|
* where: {
|
|
54
54
|
* createdAt: {
|
|
55
55
|
* $gte: new Date(Date.now() - 7 * 24 * 60 * 60 * 1000)
|
|
@@ -64,7 +64,7 @@ import { idGenerator } from "../concerns/id.js";
|
|
|
64
64
|
* createdAt: new Date().toISOString()
|
|
65
65
|
* };
|
|
66
66
|
*
|
|
67
|
-
* await database.resource('reports').insert(report);
|
|
67
|
+
* await this.database.resource('reports').insert(report);
|
|
68
68
|
* return report;
|
|
69
69
|
* }
|
|
70
70
|
* },
|
|
@@ -106,7 +106,7 @@ import { idGenerator } from "../concerns/id.js";
|
|
|
106
106
|
* const hourAgo = new Date(now.getTime() - 60 * 60 * 1000);
|
|
107
107
|
*
|
|
108
108
|
* // Aggregate metrics from the last hour
|
|
109
|
-
* const events = await database.resource('events').list({
|
|
109
|
+
* const events = await this.database.resource('events').list({
|
|
110
110
|
* where: {
|
|
111
111
|
* timestamp: {
|
|
112
112
|
* $gte: hourAgo.getTime(),
|
|
@@ -120,7 +120,7 @@ import { idGenerator } from "../concerns/id.js";
|
|
|
120
120
|
* return acc;
|
|
121
121
|
* }, {});
|
|
122
122
|
*
|
|
123
|
-
* await database.resource('hourly_metrics').insert({
|
|
123
|
+
* await this.database.resource('hourly_metrics').insert({
|
|
124
124
|
* hour: hourAgo.toISOString().slice(0, 13),
|
|
125
125
|
* metrics: aggregated,
|
|
126
126
|
* total: events.length,
|
|
@@ -217,8 +217,7 @@ export class SchedulerPlugin extends Plugin {
|
|
|
217
217
|
return true; // Simplified validation
|
|
218
218
|
}
|
|
219
219
|
|
|
220
|
-
async
|
|
221
|
-
this.database = database;
|
|
220
|
+
async onInstall() {
|
|
222
221
|
|
|
223
222
|
// Create lock resource for distributed locking
|
|
224
223
|
await this._createLockResource();
|
|
@@ -61,7 +61,7 @@ import tryFn from "../concerns/try-fn.js";
|
|
|
61
61
|
*
|
|
62
62
|
* actions: {
|
|
63
63
|
* onConfirmed: async (context, event, machine) => {
|
|
64
|
-
* await machine.database.resource('inventory').update(context.productId, {
|
|
64
|
+
* await machine.this.database.resource('inventory').update(context.productId, {
|
|
65
65
|
* quantity: { $decrement: context.quantity }
|
|
66
66
|
* });
|
|
67
67
|
* await machine.sendNotification(context.customerEmail, 'order_confirmed');
|
|
@@ -73,7 +73,7 @@ import tryFn from "../concerns/try-fn.js";
|
|
|
73
73
|
*
|
|
74
74
|
* guards: {
|
|
75
75
|
* canShip: async (context, event, machine) => {
|
|
76
|
-
* const inventory = await machine.database.resource('inventory').get(context.productId);
|
|
76
|
+
* const inventory = await machine.this.database.resource('inventory').get(context.productId);
|
|
77
77
|
* return inventory.quantity >= context.quantity;
|
|
78
78
|
* }
|
|
79
79
|
* },
|
|
@@ -138,8 +138,7 @@ export class StateMachinePlugin extends Plugin {
|
|
|
138
138
|
}
|
|
139
139
|
}
|
|
140
140
|
|
|
141
|
-
async
|
|
142
|
-
this.database = database;
|
|
141
|
+
async onInstall() {
|
|
143
142
|
|
|
144
143
|
// Create state storage resource if persistence is enabled
|
|
145
144
|
if (this.config.persistTransitions) {
|