mikser-io 6.17.0 → 6.21.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/package.json +2 -1
- package/src/engine.js +69 -1
- package/src/journal.js +6 -6
- package/src/plugins/api.js +15 -19
- package/src/plugins/post/pdf.js +1 -1
- package/src/runtime.js +1 -1
- package/src/utils.js +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mikser-io",
|
|
3
|
-
"version": "6.
|
|
3
|
+
"version": "6.21.2",
|
|
4
4
|
"description": "<p align=\"center\"> <img src=\"mikser-lockup-stacked.svg\" alt=\"mikser\" width=\"198\" /> </p>",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -60,6 +60,7 @@
|
|
|
60
60
|
"mikser-io-render-eta": "file:../mikser-io-render-eta",
|
|
61
61
|
"mikser-io-render-liquid": "file:../mikser-io-render-liquid",
|
|
62
62
|
"mikser-io-render-markdown": "file:../mikser-io-render-markdown",
|
|
63
|
+
"mikser-io-vector": "file:../mikser-io-vector",
|
|
63
64
|
"sharp": "^0.34.5"
|
|
64
65
|
},
|
|
65
66
|
"directories": {
|
package/src/engine.js
CHANGED
|
@@ -6,7 +6,7 @@ import { existsSync } from 'fs'
|
|
|
6
6
|
import _ from 'lodash'
|
|
7
7
|
import Piscina from 'piscina'
|
|
8
8
|
import runtime from './runtime.js'
|
|
9
|
-
import { onInitialize, onInitialized, onRender, onCancel, onCancelled, onFinalized, onLoaded, onAfterRender, onBeforePostprocess, onPostprocess, postprocessEntities } from './lifecycle.js'
|
|
9
|
+
import { onInitialize, onInitialized, onLoad, onRender, onCancel, onCancelled, onFinalized, onLoaded, onAfterRender, onBeforePostprocess, onPostprocess, postprocessEntities } from './lifecycle.js'
|
|
10
10
|
import { useJournal, updateEntry } from './journal.js'
|
|
11
11
|
import { globby } from 'globby'
|
|
12
12
|
import { OPERATION, TASKS } from './constants.js'
|
|
@@ -46,6 +46,7 @@ export async function setup(options) {
|
|
|
46
46
|
.option('-d --debug', 'display debug statements')
|
|
47
47
|
.option('-t --trace', 'display trace statements')
|
|
48
48
|
.option('-e --runtime-folder <folder>', 'set mikser runtime folder relative to working folder', 'runtime')
|
|
49
|
+
.option('-s --server [port]', 'start an Express server on the given port (defaults to 3001)')
|
|
49
50
|
|
|
50
51
|
Object.assign(runtime.options, options || runtime.engine.commander.parse(process.argv).opts())
|
|
51
52
|
runtime.options.info = true
|
|
@@ -84,6 +85,73 @@ export async function setup(options) {
|
|
|
84
85
|
}
|
|
85
86
|
}
|
|
86
87
|
await mkdir(runtime.options.runtimeFolder, { recursive: true })
|
|
88
|
+
|
|
89
|
+
// Server bring-up: two paths, controlled by which of these are set.
|
|
90
|
+
//
|
|
91
|
+
// runtime.options.app — pre-supplied Express app (e.g. mikser
|
|
92
|
+
// embedded inside an existing service).
|
|
93
|
+
// The caller owns the listen lifecycle
|
|
94
|
+
// and the static-route policy. Engine
|
|
95
|
+
// stays out of routing/listening so it
|
|
96
|
+
// doesn't clobber their setup; plugins
|
|
97
|
+
// still mount their own routers on it.
|
|
98
|
+
//
|
|
99
|
+
// --server [port] — engine creates the Express app, mounts
|
|
100
|
+
// (runtime.options.server) static for the output folder, and
|
|
101
|
+
// listens on the port. The actual
|
|
102
|
+
// listen() is deferred via the onLoad
|
|
103
|
+
// hook below so it runs LAST in the
|
|
104
|
+
// onLoaded phase — after every plugin
|
|
105
|
+
// has had a chance to register routes.
|
|
106
|
+
//
|
|
107
|
+
// If both are present, the externally-supplied app wins; --server
|
|
108
|
+
// becomes a no-op (the caller is in charge).
|
|
109
|
+
if (runtime.options.app) {
|
|
110
|
+
logger.info('Using externally-supplied Express app on runtime.options.app')
|
|
111
|
+
} else if (runtime.options.server) {
|
|
112
|
+
const { default: express } = await import('express').catch(() => {
|
|
113
|
+
throw new Error('Express is required for --server. Run: npm install express')
|
|
114
|
+
})
|
|
115
|
+
runtime.options.app = express()
|
|
116
|
+
runtime.options.port = runtime.options.server === true
|
|
117
|
+
? 3001
|
|
118
|
+
: Number(runtime.options.server) || 3001
|
|
119
|
+
logger.info('Server starting on port %d', runtime.options.port)
|
|
120
|
+
}
|
|
121
|
+
})
|
|
122
|
+
|
|
123
|
+
// Registered here (inside setup) so it runs AFTER plugins.js's onLoad
|
|
124
|
+
// (which is registered at module-import time). That ordering matters
|
|
125
|
+
// because plugins.js loads user plugins during its onLoad — each plugin
|
|
126
|
+
// factory may register onLoaded handlers that mount routes on
|
|
127
|
+
// runtime.options.app. We want our listen() to run LAST in the
|
|
128
|
+
// onLoaded phase, which is why we register it from inside another
|
|
129
|
+
// onLoad — by then plugins have already appended their handlers.
|
|
130
|
+
onLoad(() => {
|
|
131
|
+
// Only auto-mount static + auto-listen when the engine owns the
|
|
132
|
+
// app (created via --server). When an external app was supplied,
|
|
133
|
+
// `port` is unset and we stay out of the way — the caller manages
|
|
134
|
+
// both routing decisions and the listen lifecycle themselves.
|
|
135
|
+
if (!runtime.options.app || runtime.options.port == null) return
|
|
136
|
+
onLoaded(async () => {
|
|
137
|
+
const logger = useLogger()
|
|
138
|
+
const { default: express } = await import('express')
|
|
139
|
+
|
|
140
|
+
// Serve the output folder as the catch-all static route.
|
|
141
|
+
// Mounted LAST in the middleware chain so plugin routes
|
|
142
|
+
// (e.g. /api/*) match first; anything that didn't match a
|
|
143
|
+
// plugin's router falls through to the static handler and
|
|
144
|
+
// gets served from <outputFolder>.
|
|
145
|
+
runtime.options.app.use(express.static(runtime.options.outputFolder))
|
|
146
|
+
logger.info('Serving %s as /', runtime.options.outputFolder.replace(runtime.options.workingFolder + '/', ''))
|
|
147
|
+
|
|
148
|
+
await new Promise(resolve => {
|
|
149
|
+
runtime.options.app.listen(runtime.options.port, () => {
|
|
150
|
+
logger.info('Server listening on port %d', runtime.options.port)
|
|
151
|
+
resolve()
|
|
152
|
+
})
|
|
153
|
+
})
|
|
154
|
+
})
|
|
87
155
|
})
|
|
88
156
|
|
|
89
157
|
onLoaded(async () => {
|
package/src/journal.js
CHANGED
|
@@ -70,12 +70,12 @@ export async function clearJournal(aborted) {
|
|
|
70
70
|
await journal('operations').del()
|
|
71
71
|
if (!aborted) {
|
|
72
72
|
// Tear down the sqlite connection only when this is genuinely a
|
|
73
|
-
// one-shot run that's about to exit.
|
|
74
|
-
//
|
|
75
|
-
//
|
|
76
|
-
//
|
|
77
|
-
//
|
|
78
|
-
if (runtime.options.watch !== true && runtime.options.
|
|
73
|
+
// one-shot run that's about to exit. The two ways mikser stays
|
|
74
|
+
// alive across cycles are watch mode (chokidar handles keep the
|
|
75
|
+
// event loop ref'd) and an HTTP server (`runtime.options.app`,
|
|
76
|
+
// set either by --server or by a caller passing setup({ app }));
|
|
77
|
+
// both need the journal to survive subsequent cycles.
|
|
78
|
+
if (runtime.options.watch !== true && !runtime.options.app) {
|
|
79
79
|
journal.destroy()
|
|
80
80
|
}
|
|
81
81
|
}
|
package/src/plugins/api.js
CHANGED
|
@@ -73,13 +73,23 @@ export default ({
|
|
|
73
73
|
onLoaded(async () => {
|
|
74
74
|
const logger = useLogger()
|
|
75
75
|
|
|
76
|
+
// The api plugin no longer creates its own Express app. It mounts
|
|
77
|
+
// onto an existing app provided either by --server (engine
|
|
78
|
+
// creates one) or by a caller that programmatically passed
|
|
79
|
+
// setup({ app: ... }). Without an app there's nowhere to mount
|
|
80
|
+
// routes, so fail fast with a message that points at the fix.
|
|
81
|
+
const app = runtime.options.app
|
|
82
|
+
if (!app) {
|
|
83
|
+
throw new Error(
|
|
84
|
+
'API plugin requires runtime.options.app — run mikser with --server, ' +
|
|
85
|
+
'or pass { app: yourExpressInstance } to setup() before loading the api plugin'
|
|
86
|
+
)
|
|
87
|
+
}
|
|
88
|
+
|
|
76
89
|
const { default: express } = await import('express').catch(() => {
|
|
77
|
-
throw new Error('
|
|
90
|
+
throw new Error('Express is required for the api plugin — run: npm install express')
|
|
78
91
|
})
|
|
79
92
|
|
|
80
|
-
const ownApp = !runtime.options.app
|
|
81
|
-
const app = runtime.options.app ?? express()
|
|
82
|
-
|
|
83
93
|
const router = express.Router()
|
|
84
94
|
router.use(express.json())
|
|
85
95
|
|
|
@@ -167,22 +177,8 @@ export default ({
|
|
|
167
177
|
}
|
|
168
178
|
})
|
|
169
179
|
|
|
170
|
-
// The HTTP server keeps the process alive across many process()
|
|
171
|
-
// cycles. Tell the journal layer not to tear down the sqlite
|
|
172
|
-
// connection at the end of each cycle.
|
|
173
|
-
runtime.options.persistent = true
|
|
174
|
-
|
|
175
180
|
const base = runtime.config.api?.base ?? '/api'
|
|
176
181
|
app.use(base, router)
|
|
177
|
-
|
|
178
|
-
if (ownApp) {
|
|
179
|
-
const port = runtime.config.api?.port ?? 3001
|
|
180
|
-
const url = runtime.config.api?.url ?? 'http://localhost'
|
|
181
|
-
app.listen(port, () => {
|
|
182
|
-
logger.info('Api listening: %s:%d%s', url, port, base)
|
|
183
|
-
})
|
|
184
|
-
} else {
|
|
185
|
-
logger.info('Api mounted: %s', base)
|
|
186
|
-
}
|
|
182
|
+
logger.info('Api mounted: %s', base)
|
|
187
183
|
})
|
|
188
184
|
}
|
package/src/plugins/post/pdf.js
CHANGED
|
@@ -14,7 +14,7 @@ export async function setup({ config, logger }) {
|
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
const { default: puppeteer } = await import('puppeteer').catch(() => {
|
|
17
|
-
throw new Error('
|
|
17
|
+
throw new Error('Puppeteer is required for the pdf postprocessor — run: npm install puppeteer')
|
|
18
18
|
})
|
|
19
19
|
browser = await puppeteer.launch({
|
|
20
20
|
headless: true,
|
package/src/runtime.js
CHANGED
package/src/utils.js
CHANGED
|
@@ -55,7 +55,7 @@ export function matchEntity(entity, match) {
|
|
|
55
55
|
}
|
|
56
56
|
}
|
|
57
57
|
else if (typeof match == 'object') return _.isMatch(entity, match)
|
|
58
|
-
throw new Error('
|
|
58
|
+
throw new Error('Invalid match type')
|
|
59
59
|
}
|
|
60
60
|
|
|
61
61
|
export function changeExtension(file, format) {
|