@momsfriendlydevco/cowboy 1.4.0 → 1.5.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 +1 -0
- package/lib/cowboy.js +89 -24
- package/lib/testkit.js +5 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -10,6 +10,7 @@ Features:
|
|
|
10
10
|
* Built in middleware + request validation via [Joi](https://joi.dev)
|
|
11
11
|
* Built-in debug support for testkits + Wrangler
|
|
12
12
|
* Built-in JSON / Multipart (or FormData) / Plain text decoding and population of `req.body`
|
|
13
|
+
* Scheduled tasks can return promises and they are automatically awaited (no need to do `ctx.waitUntil()`)
|
|
13
14
|
|
|
14
15
|
|
|
15
16
|
Examples
|
package/lib/cowboy.js
CHANGED
|
@@ -25,10 +25,11 @@ export class Cowboy {
|
|
|
25
25
|
* General settings for this Cowboy instance
|
|
26
26
|
*
|
|
27
27
|
* @type {Object}
|
|
28
|
+
* @property {Boolean|'VAR'} scheduler Add a generic `/__scheduled` endpoint to execute any queued scheduler. If value is `'VAR'` this will only apply if the env `COWBOY_SCHEDULER` is set and truthy
|
|
28
29
|
* @property {Function} pathTidy Additional tidyup for server request paths, useful if the API does not live at the server root. Defaults to removing a "/api/:worker/" prefix
|
|
29
30
|
*/
|
|
30
31
|
settings = {
|
|
31
|
-
|
|
32
|
+
scheduler: 'VAR',
|
|
32
33
|
pathTidy(path) {
|
|
33
34
|
return path
|
|
34
35
|
.replace(/^\/api\/\w+/, '/')
|
|
@@ -62,7 +63,7 @@ export class Cowboy {
|
|
|
62
63
|
* Queue up a middleware path
|
|
63
64
|
* All given middleware is called in sequence, if middleware
|
|
64
65
|
*
|
|
65
|
-
* @param {String|Array<String>} methods A method matcher or array of available methods
|
|
66
|
+
* @param {String|Array<String>} methods A method matcher or array of available methods in upper-case
|
|
66
67
|
* @param {String|RegExp|Array<String|RegExp>} paths A prefix path to match
|
|
67
68
|
* @param {CowboyMiddleware...} middleware Middleware to call in sequence
|
|
68
69
|
*
|
|
@@ -118,6 +119,60 @@ export class Cowboy {
|
|
|
118
119
|
if (env.COWBOY_DEBUG)
|
|
119
120
|
debug.enabled = true;
|
|
120
121
|
|
|
122
|
+
if ( // Setup scheduler endpoint if this is the first fetch() hit were we can access the `env` state
|
|
123
|
+
!this._schedulerSetup
|
|
124
|
+
&& (
|
|
125
|
+
this.settings.scheduler === true
|
|
126
|
+
|| (
|
|
127
|
+
this.settings.scheduler == 'VAR'
|
|
128
|
+
&& env.COWBOY_SCHEDULER
|
|
129
|
+
)
|
|
130
|
+
)
|
|
131
|
+
) {
|
|
132
|
+
console.log('Scheduler setup against /__scheduled');
|
|
133
|
+
this._schedulerSetup = true;
|
|
134
|
+
|
|
135
|
+
// Find first GET operation
|
|
136
|
+
let routeIndex = this.routes.findIndex(r => r.methods.some(m => m == 'GET'));
|
|
137
|
+
if (routeIndex < 0) routeIndex = this.routes.length; // If no GETS, assume end position
|
|
138
|
+
|
|
139
|
+
// Splice into position before first GET
|
|
140
|
+
let matcher = compileRoutePaths('/__scheduled');
|
|
141
|
+
this.routes.splice(routeIndex, 0, {
|
|
142
|
+
methods: ['GET'],
|
|
143
|
+
paths: matcher.paths,
|
|
144
|
+
matcher,
|
|
145
|
+
middleware: [
|
|
146
|
+
async (req, res, env) => {
|
|
147
|
+
debug('Executing schedule handler');
|
|
148
|
+
if (!this.schedule.handler) return res.status(404).send('No scheduler installed');
|
|
149
|
+
|
|
150
|
+
try {
|
|
151
|
+
let result = await this.schedule.handler.call(
|
|
152
|
+
this,
|
|
153
|
+
{ // Faked Cloudflare `controller` context
|
|
154
|
+
cron: 'FAKE',
|
|
155
|
+
type: 'scheduled',
|
|
156
|
+
scheduledTime: (new Date()).toISOString(),
|
|
157
|
+
},
|
|
158
|
+
env,
|
|
159
|
+
{ // Faked Cloudflare `ctx` context - we provide a fake waitUntil here
|
|
160
|
+
waitUntil() {
|
|
161
|
+
throw new Error('ctx.waitUntil() functionality is provided natively by Cowboy.schedule(cb:Function) - just return a promise instead of using it');
|
|
162
|
+
},
|
|
163
|
+
},
|
|
164
|
+
);
|
|
165
|
+
debug('Got scheduler response', result);
|
|
166
|
+
return res.send(result);
|
|
167
|
+
} catch (e) {
|
|
168
|
+
return res.status(400).send(`Scheduler threw error: ${e.toString()}`);
|
|
169
|
+
}
|
|
170
|
+
},
|
|
171
|
+
]
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
|
|
121
176
|
// Create basic [req]uest / [res]ponse objects
|
|
122
177
|
let req = new CowboyRequest(cfReq, {
|
|
123
178
|
router: this,
|
|
@@ -167,23 +222,6 @@ export class Cowboy {
|
|
|
167
222
|
}
|
|
168
223
|
|
|
169
224
|
|
|
170
|
-
/**
|
|
171
|
-
* Set up Cloudflare response to "scheduled" call
|
|
172
|
-
* This is really just a map to the last handler we installed to .schedule(cb) - for now
|
|
173
|
-
*
|
|
174
|
-
* @param {CloudflareEvent} event The Cloudflare event context passed
|
|
175
|
-
* @param {Object} env Environment variables
|
|
176
|
-
* @param {CloudflareContext} ctx The Cloudflare context to respond to
|
|
177
|
-
*
|
|
178
|
-
* @returns {Cowboy} This chainable Cowboy router instance
|
|
179
|
-
*/
|
|
180
|
-
scheduled(event, env, ctx) {
|
|
181
|
-
if (!this.schedule.handler) throw new Error('Attemped to access Cowboy.scheduled without first calling .schedule() to set something up!');
|
|
182
|
-
this.schedule.handler.call(this, event, env, ctx);
|
|
183
|
-
return this;
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
|
|
187
225
|
/**
|
|
188
226
|
* Call a router function as if it were invoked directly
|
|
189
227
|
* This function exists as an easier way to remap body contents without
|
|
@@ -295,12 +333,43 @@ export class Cowboy {
|
|
|
295
333
|
* @returns {Cowboy} This chainable Cowboy router instance
|
|
296
334
|
*/
|
|
297
335
|
schedule(handler) {
|
|
298
|
-
|
|
336
|
+
debug('Installed schedule event handler');
|
|
299
337
|
this.schedule.handler = handler;
|
|
300
338
|
return this;
|
|
301
339
|
}
|
|
302
340
|
|
|
303
341
|
|
|
342
|
+
/**
|
|
343
|
+
* Set up Cloudflare response to "scheduled" call
|
|
344
|
+
* This is really just a map to the last handler we installed to .schedule(cb) - for now
|
|
345
|
+
*
|
|
346
|
+
* @param {CloudflareEvent} event The Cloudflare event context passed
|
|
347
|
+
* @param {Object} env Environment variables
|
|
348
|
+
* @param {CloudflareContext} ctx The Cloudflare context to respond to
|
|
349
|
+
*
|
|
350
|
+
* @returns {Cowboy} This chainable Cowboy router instance
|
|
351
|
+
*/
|
|
352
|
+
scheduled(event, env, ctx) {
|
|
353
|
+
if (!this.schedule.handler) throw new Error('Attemped to access Cowboy.scheduled without first calling .schedule() to set something up!');
|
|
354
|
+
|
|
355
|
+
// Wrap all scheduler calls in ctx.waitUntil() so promises are always waited on
|
|
356
|
+
ctx.waitUntil(
|
|
357
|
+
this.schedule.handler.call(
|
|
358
|
+
this,
|
|
359
|
+
event,
|
|
360
|
+
env,
|
|
361
|
+
{
|
|
362
|
+
waitUntil() {
|
|
363
|
+
throw new Error('ctx.waitUntil() functionality is provided natively by Cowboy.schedule(cb:Function) - just return a promise instead of using it');
|
|
364
|
+
},
|
|
365
|
+
},
|
|
366
|
+
)
|
|
367
|
+
);
|
|
368
|
+
|
|
369
|
+
return this;
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
|
|
304
373
|
/**
|
|
305
374
|
* Generial Init() sequence
|
|
306
375
|
* This will be run automatically on setup or the first fetch()
|
|
@@ -310,10 +379,6 @@ export class Cowboy {
|
|
|
310
379
|
if (this.doneInit) return this; // Already completed init
|
|
311
380
|
debug('INIT!');
|
|
312
381
|
|
|
313
|
-
if (this.settings.patchAxios) {
|
|
314
|
-
// TODO: Patch Axios somehow
|
|
315
|
-
// axios.defaults.adapter = axiosFetchAdapter;
|
|
316
|
-
}
|
|
317
382
|
return this;
|
|
318
383
|
}
|
|
319
384
|
}
|
package/lib/testkit.js
CHANGED
|
@@ -19,6 +19,7 @@ export let worker;
|
|
|
19
19
|
* @param {Axios} [options.axios] Axios instance to mutate with the base URL, if specified
|
|
20
20
|
* @param {Boolean} [options.server=true] Initialize a local server - disable this if you're running your own
|
|
21
21
|
* @param {Boolean} [options.debug=false] Force debug as if `DEBUG=cowboy` was set
|
|
22
|
+
* @param {Boolean} [options.scheduler=false] Bind any scedhuler callback to `/__scheduled`
|
|
22
23
|
* @param {Function} [options.logOutput] Function to wrap STDOUT output. Called as `(line:String)`
|
|
23
24
|
* @param {Function} [options.logOutputErr] Function to wrap STDERR output. Called as `(line:String)`
|
|
24
25
|
* @param {String} [options.host='127.0.0.1'] Host to run Wrangler on
|
|
@@ -32,6 +33,7 @@ export function start(options) {
|
|
|
32
33
|
axios: null,
|
|
33
34
|
server: true,
|
|
34
35
|
debug: false,
|
|
36
|
+
scheduler: false,
|
|
35
37
|
logOutput: output => console.log('WRANGLER>', output),
|
|
36
38
|
logOutputErr: output => console.log('WRANGLER!', output),
|
|
37
39
|
host: '127.0.0.1',
|
|
@@ -70,6 +72,9 @@ export function start(options) {
|
|
|
70
72
|
...(debug.enabled ? [
|
|
71
73
|
'--var=COWBOY_DEBUG:1'
|
|
72
74
|
]: []),
|
|
75
|
+
...(settings.scheduler ? [
|
|
76
|
+
'--var=COWBOY_SCHEDULER:1'
|
|
77
|
+
]: []),
|
|
73
78
|
]);
|
|
74
79
|
|
|
75
80
|
worker.stdout.on('data', data => {
|