• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

senecajs / seneca / 9393166293

06 Jun 2024 12:33AM UTC coverage: 89.926% (-0.4%) from 90.358%
9393166293

push

github

rjrodger
remove-most-3-legacy-opts

27 of 29 new or added lines in 7 files covered. (93.1%)

71 existing lines in 6 files now uncovered.

5240 of 5827 relevant lines covered (89.93%)

6604.48 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

91.95
/lib/plugin.js
1
/* Copyright © 2020-2023 Richard Rodger and other contributors, MIT License. */
14✔
2
/* $lab:coverage:off$ */
14✔
3
'use strict';
14✔
4
var __importDefault = (this && this.__importDefault) || function (mod) {
14✔
5
    return (mod && mod.__esModule) ? mod : { "default": mod };
14✔
6
};
14✔
7
Object.defineProperty(exports, "__esModule", { value: true });
14✔
8
exports.Plugin = void 0;
14✔
9
// TODO: replace `seneca-` prefix with `plugin-` for unnamed plugins
14✔
10
const Uniq = require('lodash.uniq');
14✔
11
const Eraro = require('eraro');
14✔
12
const nua_1 = __importDefault(require("nua"));
14✔
13
const ordu_1 = require("ordu");
14✔
14
// TODO: refactor: use.js->plugin.js and contain *_plugin api methods too
14✔
15
const Common = require('./common');
14✔
16
const { Print } = require('./print');
14✔
17
/* $lab:coverage:on$ */
14✔
18
const intern = make_intern();
14✔
19
function api_use(callpoint, opts) {
14✔
20
    const tasks = make_tasks();
5,236✔
21
    const ordu = new ordu_1.Ordu({ debug: opts.debug });
5,236✔
22
    ordu.operator('seneca_plugin', intern.op.seneca_plugin);
5,236✔
23
    ordu.operator('seneca_export', intern.op.seneca_export);
5,236✔
24
    ordu.operator('seneca_options', intern.op.seneca_options);
5,236✔
25
    ordu.operator('seneca_complete', intern.op.seneca_complete);
5,236✔
26
    // TODO: restructure in seneca 4.x
14✔
27
    ordu.add([
5,236✔
28
        tasks.args,
14✔
29
        tasks.load,
14✔
30
        tasks.normalize,
14✔
31
        {
14✔
32
            name: 'pre_options', exec: (spec) => {
14✔
33
                if ('function' === typeof spec.data.plugin.define.preload) {
14✔
34
                    return tasks.options(spec);
658✔
35
                }
14✔
36
            }
14✔
37
        },
14✔
38
        tasks.preload,
14✔
39
        { name: 'pre_meta', exec: tasks.meta },
14✔
40
        { name: 'pre_legacy_extend', exec: tasks.legacy_extend },
14✔
41
        tasks.delegate,
14✔
42
        tasks.call_define,
14✔
43
        tasks.options,
14✔
44
        tasks.define,
14✔
45
        { name: 'post_meta', exec: tasks.meta },
14✔
46
        { name: 'post_legacy_extend', exec: tasks.legacy_extend },
14✔
47
        tasks.call_prepare,
14✔
48
        tasks.complete,
14✔
49
    ]);
14✔
50
    return {
5,236✔
51
        use: make_use(ordu, callpoint),
14✔
52
        ordu,
14✔
53
        tasks,
14✔
54
    };
14✔
55
}
14✔
56
function make_use(ordu, callpoint) {
14✔
57
    let seq = { index: 0 };
5,236✔
58
    return function use() {
5,236✔
59
        let self = this;
14✔
60
        let args = [...arguments];
2,926✔
61
        if (0 === args.length) {
2,926✔
62
            throw self.error('use_no_args');
14✔
63
        }
14✔
64
        let ctx = {
2,912✔
65
            seq: seq,
14✔
66
            args: args,
14✔
67
            seneca: this,
14✔
68
            callpoint: callpoint(true)
14✔
69
        };
14✔
70
        let data = {
2,912✔
71
            seq: -1,
14✔
72
            args: [],
14✔
73
            plugin: null,
14✔
74
            meta: null,
14✔
75
            delegate: null,
14✔
76
            plugin_done: null,
14✔
77
            exports: {},
14✔
78
            prepare: {},
14✔
79
        };
14✔
80
        async function run() {
14✔
81
            await ordu.exec(ctx, data, {
2,912✔
82
                done: function (res) {
14✔
83
                    if (res.err) {
14✔
84
                        var err = res.err.seneca ? res.err :
154✔
85
                            self.private$.error(res.err, res.err.code);
14✔
86
                        err.plugin = err.plugin ||
×
87
                            (data.plugin ? (data.plugin.fullname || data.plugin.name) :
×
88
                                args.join(' '));
×
89
                        err.plugin_callpoint = err.plugin_callpoint || ctx.callpoint;
×
90
                        self.die(err);
154✔
91
                    }
14✔
92
                }
14✔
93
            });
14✔
94
        }
14✔
95
        // NOTE: don't wait for result!
14✔
96
        run();
2,912✔
97
        return self;
2,912✔
98
    };
14✔
99
}
14✔
100
function make_tasks() {
14✔
101
    return {
5,236✔
102
        // TODO: args validation?
14✔
103
        args: (spec) => {
14✔
104
            let args = [...spec.ctx.args];
14✔
105
            // Plugin definition function is under property `define`.
14✔
106
            // `init` is deprecated from 4.x
14✔
107
            // TODO: use-plugin expects `init` - update use-plugin to make this customizable
14✔
108
            if (null != args[0] && 'object' === typeof args[0]) {
2,982✔
109
                args[0].init = args[0].define || args[0].init;
476✔
110
            }
14✔
111
            return {
2,982✔
112
                op: 'merge',
14✔
113
                out: { plugin: { args } }
14✔
114
            };
14✔
115
        },
14✔
116
        load: (spec) => {
14✔
117
            let args = spec.data.plugin.args;
14✔
118
            let seneca = spec.ctx.seneca;
2,912✔
119
            let private$ = seneca.private$;
2,912✔
120
            // Special cases for short plugin names
14✔
121
            // TODO: plugin loading should check for @seneca and seneca first!
14✔
122
            // 1. Avoid conflict with the OG request module!
14✔
123
            if ('request' === args[0]) {
×
124
                args[0] = '@seneca/request';
×
125
            }
14✔
126
            // TODO: use-plugin needs better error message for malformed plugin desc
14✔
127
            let desc = private$.use.build_plugin_desc(...args);
2,912✔
128
            desc.callpoint = spec.ctx.callpoint;
2,884✔
129
            if (private$.ignore_plugins[desc.full]) {
2,884✔
130
                seneca.log.info({
84✔
131
                    kind: 'plugin',
14✔
132
                    case: 'ignore',
14✔
133
                    plugin_full: desc.full,
14✔
134
                    plugin_name: desc.name,
14✔
135
                    plugin_tag: desc.tag,
14✔
136
                });
14✔
137
                return {
84✔
138
                    op: 'stop',
14✔
139
                    why: 'ignore'
14✔
140
                };
14✔
141
            }
14✔
142
            else {
14✔
143
                let plugin = private$.use.use_plugin_desc(desc);
2,800✔
144
                return {
2,772✔
145
                    op: 'merge',
14✔
146
                    out: {
14✔
147
                        plugin
14✔
148
                    }
14✔
149
                };
14✔
150
            }
14✔
151
        },
14✔
152
        normalize: (spec) => {
14✔
153
            let plugin = spec.data.plugin;
14✔
154
            let modify = {};
2,772✔
155
            // NOTE: `define` is the property for the plugin definition action.
14✔
156
            // The property `init` will be deprecated in 4.x
14✔
157
            modify.define = plugin.define || plugin.init;
2,772✔
158
            modify.fullname = Common.make_plugin_key(plugin);
2,772✔
159
            modify.loading = true;
2,772✔
160
            return {
2,772✔
161
                op: 'merge',
14✔
162
                out: { plugin: modify }
14✔
163
            };
14✔
164
        },
14✔
165
        preload: (spec) => {
14✔
166
            let seneca = spec.ctx.seneca;
14✔
167
            let plugin = spec.data.plugin;
2,772✔
168
            let so = seneca.options();
2,772✔
169
            // Don't reload plugins if load_once true.
14✔
170
            if (so.system.plugin.load_once) {
×
171
                if (seneca.has_plugin(plugin)) {
×
172
                    return {
×
173
                        op: 'stop',
14✔
174
                        why: 'already-loaded',
14✔
175
                        out: {
14✔
176
                            plugin: {
14✔
177
                                loading: false
14✔
178
                            }
14✔
179
                        }
14✔
180
                    };
14✔
181
                }
14✔
182
            }
14✔
183
            let meta = {};
2,772✔
184
            if ('function' === typeof plugin.define.preload) {
2,772✔
185
                // TODO: need to capture errors
14✔
186
                meta = plugin.define.preload.call(seneca, plugin) || {};
×
187
            }
14✔
188
            let name = meta.name || plugin.name;
2,772✔
189
            let fullname = Common.make_plugin_key(name, plugin.tag);
2,772✔
190
            return {
2,772✔
191
                op: 'seneca_plugin',
14✔
192
                out: {
14✔
193
                    merge: {
14✔
194
                        meta,
14✔
195
                        plugin: {
14✔
196
                            name,
14✔
197
                            fullname
14✔
198
                        }
14✔
199
                    },
14✔
200
                    plugin
14✔
201
                }
14✔
202
            };
14✔
203
        },
14✔
204
        // Handle plugin meta data returned by plugin define function
14✔
205
        meta: (spec) => {
14✔
206
            let seneca = spec.ctx.seneca;
14✔
207
            let plugin = spec.data.plugin;
5,446✔
208
            let meta = spec.data.meta;
5,446✔
209
            let exports = {};
5,446✔
210
            exports[plugin.name] = meta.export || plugin;
5,446✔
211
            exports[plugin.fullname] = meta.export || plugin;
5,446✔
212
            let exportmap = meta.exportmap || meta.exports || {};
5,446✔
213
            Object.keys(exportmap).forEach(k => {
5,446✔
214
                let v = exportmap[k];
14✔
215
                if (void 0 !== v) {
×
216
                    let exportfullname = plugin.fullname + '/' + k;
2,786✔
217
                    exports[exportfullname] = v;
2,786✔
218
                    // Also provide exports on untagged plugin name. This is the
14✔
219
                    // standard name that other plugins use
14✔
220
                    let exportname = plugin.name + '/' + k;
2,786✔
221
                    exports[exportname] = v;
2,786✔
222
                }
14✔
223
            });
14✔
224
            if (meta.order) {
5,446✔
225
                if (meta.order.plugin) {
28✔
226
                    let tasks = Array.isArray(meta.order.plugin) ? meta.order.plugin :
×
227
                        [meta.order.plugin];
×
228
                    seneca.order.plugin.add(tasks);
14✔
229
                    delete meta.order.plugin;
14✔
230
                }
14✔
231
            }
14✔
232
            return {
5,446✔
233
                op: 'seneca_export',
14✔
234
                out: {
14✔
235
                    exports
14✔
236
                }
14✔
237
            };
14✔
238
        },
14✔
239
        // NOTE: mutates spec.ctx.seneca
14✔
240
        legacy_extend: (spec) => {
14✔
241
            let seneca = spec.ctx.seneca;
14✔
242
            // let plugin: any = spec.data.plugin
14✔
243
            let meta = spec.data.meta;
5,446✔
244
            if (meta.extend && 'object' === typeof meta.extend) {
×
245
                if ('function' === typeof meta.extend.action_modifier) {
28✔
246
                    seneca.private$.action_modifiers.push(meta.extend.action_modifier);
14✔
247
                }
14✔
248
                // FIX: needs to use logging.load_logger
14✔
249
                if ('function' === typeof meta.extend.logger) {
28✔
250
                    if (!meta.extend.logger.replace &&
×
251
                        'function' === typeof seneca.private$.logger.add) {
×
252
                        seneca.private$.logger.add(meta.extend.logger);
×
253
                    }
14✔
254
                    else {
14✔
255
                        seneca.private$.logger = meta.extend.logger;
14✔
256
                    }
14✔
257
                }
14✔
258
            }
14✔
259
        },
14✔
260
        delegate: (spec) => {
14✔
261
            let seneca = spec.ctx.seneca;
14✔
262
            let plugin = spec.data.plugin;
2,996✔
263
            // Adjust Seneca API to be plugin specific.
14✔
264
            let delegate = seneca.delegate({
2,996✔
265
                plugin$: {
14✔
266
                    name: plugin.name,
14✔
267
                    tag: plugin.tag,
14✔
268
                },
14✔
269
                fatal$: true,
14✔
270
            });
14✔
271
            // Shared plugin resources.
14✔
272
            plugin.shared = Object.create(null);
2,996✔
273
            delegate.shared = plugin.shared;
2,996✔
274
            delegate.plugin = plugin;
2,996✔
275
            delegate.private$ = Object.create(seneca.private$);
2,996✔
276
            delegate.private$.ge = delegate.private$.ge.gate();
2,996✔
277
            delegate.die = Common.makedie(delegate, {
2,996✔
278
                type: 'plugin',
14✔
279
                plugin: plugin.name,
14✔
280
            });
14✔
281
            let actdeflist = [];
2,996✔
282
            delegate.add = function plugin_add() {
2,996✔
283
                let argsarr = [...arguments];
14✔
284
                // TODO: this is very brittle.
14✔
285
                // Instead pass in plugin details using a directive.
14✔
286
                let actdef = argsarr[argsarr.length - 1] || {};
×
287
                if ('function' === typeof actdef) {
7,980✔
288
                    actdef = {};
7,966✔
289
                    argsarr.push(actdef);
7,966✔
290
                }
14✔
291
                if (null != actdef && 'object' === typeof actdef) {
×
292
                    actdef.plugin_name = plugin.name || '-';
×
293
                    actdef.plugin_tag = plugin.tag || '-';
7,966✔
294
                    actdef.plugin_fullname = plugin.fullname;
7,966✔
295
                    // TODO: is this necessary?
14✔
296
                    actdef.log = delegate.log;
7,966✔
297
                    actdeflist.push(actdef);
7,966✔
298
                }
14✔
299
                seneca.add.apply(delegate, argsarr);
7,980✔
300
                return this;
7,966✔
301
            };
14✔
302
            delegate.__update_plugin__ = function (plugin) {
2,996✔
303
                delegate.context.name = plugin.name || '-';
×
304
                delegate.context.tag = plugin.tag || '-';
2,674✔
305
                delegate.context.full = plugin.fullname || '-';
×
306
                actdeflist.forEach(function (actdef) {
2,674✔
307
                    actdef.plugin_name = plugin.name || actdef.plugin_name || '-';
×
308
                    actdef.plugin_tag = plugin.tag || actdef.plugin_tag || '-';
×
309
                    actdef.plugin_fullname = plugin.fullname || actdef.plugin_fullname || '-';
×
310
                });
14✔
311
            };
14✔
312
            delegate.init = function (init) {
2,996✔
313
                // TODO: validate init_action is function
14✔
314
                let pat = {
14✔
315
                    role: 'seneca',
14✔
316
                    plugin: 'init',
14✔
317
                    init: plugin.name,
14✔
318
                };
14✔
319
                if (null != plugin.tag && '-' != plugin.tag) {
×
320
                    pat.tag = plugin.tag;
×
321
                }
14✔
322
                delegate.add(pat, function (_, reply) {
406✔
323
                    init.call(this, reply);
14✔
324
                });
14✔
325
            };
14✔
326
            delegate.context.plugin = plugin;
2,996✔
327
            delegate.context.plugin.mark = Math.random();
2,996✔
328
            return {
2,996✔
329
                op: 'merge',
14✔
330
                out: {
14✔
331
                    delegate
14✔
332
                }
14✔
333
            };
14✔
334
        },
14✔
335
        call_define: (spec) => {
14✔
336
            let plugin = spec.data.plugin;
14✔
337
            let delegate = spec.data.delegate;
2,772✔
338
            // FIX: mutating context!!!
14✔
339
            let seq = spec.ctx.seq.index++;
2,772✔
340
            let plugin_define_pattern = {
2,772✔
341
                role: 'seneca',
14✔
342
                plugin: 'define',
14✔
343
                name: plugin.name,
14✔
344
                seq: seq,
14✔
345
            };
14✔
346
            if (plugin.tag !== null) {
×
347
                plugin_define_pattern.tag = plugin.tag;
2,772✔
348
            }
14✔
349
            return new Promise(resolve => {
2,772✔
350
                // seneca
14✔
351
                delegate.add(plugin_define_pattern, (_, reply) => {
14✔
352
                    resolve({
14✔
353
                        op: 'merge',
14✔
354
                        out: { seq, plugin_done: reply }
14✔
355
                    });
14✔
356
                });
14✔
357
                delegate.act({
2,772✔
358
                    role: 'seneca',
14✔
359
                    plugin: 'define',
14✔
360
                    name: plugin.name,
14✔
361
                    tag: plugin.tag,
14✔
362
                    seq: seq,
14✔
363
                    default$: {},
14✔
364
                    fatal$: true,
14✔
365
                    local$: true,
14✔
366
                });
14✔
367
            });
14✔
368
        },
14✔
369
        options: (spec) => {
14✔
370
            let plugin = spec.data.plugin;
14✔
371
            let delegate = spec.data.delegate ||
3,430✔
372
                spec.ctx.seneca; // for preload
14✔
373
            let so = delegate.options();
3,430✔
374
            let fullname = plugin.fullname;
3,430✔
375
            let defaults = plugin.defaults;
3,430✔
376
            let fullname_options = Object.assign({}, so.plugin[fullname], so.plugin[fullname + '$' + plugin.tag]);
3,430✔
377
            let shortname = fullname !== plugin.name ? plugin.name : null;
3,430✔
378
            if (!shortname && fullname.indexOf('seneca-') === 0) {
3,430✔
379
                shortname = fullname.substring('seneca-'.length);
266✔
380
            }
14✔
381
            let shortname_options = Object.assign({}, so.plugin[shortname], so.plugin[shortname + '$' + plugin.tag]);
3,430✔
382
            let base = {};
3,430✔
383
            // NOTE: plugin error codes are in their own namespaces
14✔
384
            // TODO: test this!!!
14✔
385
            let errors = plugin.errors || (plugin.define && plugin.define.errors);
×
386
            if (errors) {
3,430✔
387
                base.errors = errors;
70✔
388
            }
14✔
389
            // TODO: these should deep merge
14✔
390
            let fullopts = Object.assign(base, shortname_options, fullname_options, plugin.options || {});
×
391
            let resolved_options = {};
3,430✔
392
            let valid = delegate.valid; // Gubu validator: https://github.com/rjrodger/gubu
3,430✔
393
            let err = void 0;
3,430✔
394
            let joi_schema = null;
3,430✔
395
            let Joi = delegate.util.Joi;
3,430✔
396
            let defaults_values = ('function' === typeof (defaults) && !defaults.gubu) ?
3,430✔
397
                defaults({ valid, Joi }) : defaults;
14✔
398
            if (null == defaults_values ||
×
399
                0 === Object.keys(defaults_values).length ||
14✔
400
                !so.valid.active ||
14✔
401
                !so.valid.plugin) {
14✔
402
                resolved_options = fullopts;
2,058✔
403
            }
14✔
404
            else {
14✔
NEW
405
                if (!defaults_values.$_root // check for legacy Joi schema
×
406
                ) {
14✔
407
                    // TODO: use Gubu.isShape
14✔
408
                    let isShape = defaults_values.gubu && defaults_values.gubu.gubu$;
1,372✔
409
                    // TODO: when Gubu supports merge, also merge if isShape
14✔
410
                    if (!isShape && null == defaults_values.errors && null != errors) {
×
411
                        defaults_values.errors = {};
28✔
412
                    }
14✔
413
                    let optionShape = isShape ? defaults_values : delegate.valid(defaults_values);
1,372✔
414
                    let shapeErrors = [];
1,372✔
415
                    resolved_options = optionShape(fullopts, { err: shapeErrors });
1,372✔
416
                    if (0 < shapeErrors.length) {
1,372✔
417
                        err = delegate.error('invalid_plugin_option', {
14✔
418
                            name: fullname,
14✔
419
                            err_msg: shapeErrors.map((se) => se.t).join('; '),
14✔
420
                            options: fullopts,
14✔
421
                        });
14✔
422
                    }
14✔
423
                }
14✔
424
                else {
14✔
UNCOV
425
                    resolved_options = delegate.util.deep(defaults_values, fullopts);
×
426
                    /* TODO: move to seneca-joi
14✔
427
                    let joi_schema: any = intern.prepare_spec(
14✔
428
                      Joi,
14✔
429
                      defaults_values,
14✔
430
                      { allow_unknown: true },
14✔
431
                      {}
14✔
432
                    )
14✔
433
          
14✔
434
                    let joi_out = joi_schema.validate(fullopts)
14✔
435
          
14✔
436
                    if (joi_out.error) {
14✔
437
                      err = delegate.error('invalid_plugin_option', {
14✔
438
                        name: fullname,
14✔
439
                        err_msg: joi_out.error.message,
14✔
440
                        options: fullopts,
14✔
441
                      })
14✔
442
                    }
14✔
443
                    else {
14✔
444
                      resolved_options = joi_out.value
14✔
445
                    }
14✔
446
                    */
14✔
447
                }
14✔
448
            }
14✔
449
            return {
3,430✔
450
                op: 'seneca_options',
14✔
451
                err: err,
14✔
452
                out: {
14✔
453
                    plugin: {
14✔
454
                        options: resolved_options,
14✔
455
                        options_schema: joi_schema
14✔
456
                    }
14✔
457
                }
14✔
458
            };
14✔
459
        },
14✔
460
        // TODO: move data modification to returned operation
14✔
461
        define: (spec) => {
14✔
462
            let seneca = spec.ctx.seneca;
14✔
463
            let plugin = spec.data.plugin;
2,758✔
464
            let delegate = spec.data.delegate;
2,758✔
465
            let plugin_options = spec.data.plugin.options;
2,758✔
466
            delegate.log.debug({
2,758✔
467
                kind: 'plugin',
14✔
468
                case: 'DEFINE',
14✔
469
                name: plugin.name,
14✔
470
                tag: plugin.tag,
14✔
471
                options: plugin_options,
14✔
472
                callpoint: spec.ctx.callpoint,
14✔
473
            });
14✔
474
            let meta;
2,758✔
475
            meta = intern.define_plugin(delegate, plugin, seneca.util.clean(plugin_options));
2,758✔
476
            if (meta instanceof Promise) {
2,688✔
477
                return meta.then(finalize_meta);
126✔
478
            }
14✔
479
            return finalize_meta(meta);
2,562✔
480
            function finalize_meta(meta) {
14✔
481
                plugin.meta = meta;
2,674✔
482
                // legacy api for service function
14✔
483
                if ('function' === typeof meta) {
×
484
                    meta = { service: meta };
×
485
                }
14✔
486
                // Plugin may have changed its own name dynamically
14✔
487
                plugin.name = meta.name || plugin.name;
2,674✔
488
                plugin.tag =
2,674✔
489
                    meta.tag || plugin.tag || (plugin.options && plugin.options.tag$);
×
490
                plugin.fullname = Common.make_plugin_key(plugin);
2,674✔
491
                plugin.service = meta.service || plugin.service;
×
492
                delegate.__update_plugin__(plugin);
2,674✔
493
                seneca.private$.plugins[plugin.fullname] = plugin;
2,674✔
494
                seneca.private$.plugin_order.byname.push(plugin.name);
2,674✔
495
                seneca.private$.plugin_order.byname = Uniq(seneca.private$.plugin_order.byname);
2,674✔
496
                seneca.private$.plugin_order.byref.push(plugin.fullname);
2,674✔
497
                // // 3.x Backwards compatibility - REMOVE in 4.x
14✔
498
                // if ('amqp-transport' === plugin.name) {
14✔
499
                //   seneca.options({ legacy: { meta: true } })
14✔
500
                // }
14✔
501
                if ('function' === typeof plugin_options.defined$) {
×
502
                    plugin_options.defined$(plugin);
×
503
                }
14✔
504
                // TODO: test this, with preload, explicitly
14✔
505
                return {
2,674✔
506
                    op: 'merge',
14✔
507
                    out: {
14✔
508
                        meta,
14✔
509
                    }
14✔
510
                };
14✔
511
            }
14✔
512
        },
14✔
513
        call_prepare: (spec) => {
14✔
514
            let plugin = spec.data.plugin;
14✔
515
            let plugin_options = spec.data.plugin.options;
2,674✔
516
            let delegate = spec.data.delegate;
2,674✔
517
            // If init$ option false, do not execute init action.
14✔
518
            if (false === plugin_options.init$) {
×
519
                return;
×
520
            }
14✔
521
            let exports = spec.data.exports;
2,674✔
522
            delegate.log.debug({
2,674✔
523
                kind: 'plugin',
14✔
524
                case: 'INIT',
14✔
525
                name: plugin.name,
14✔
526
                tag: plugin.tag,
14✔
527
                exports: exports,
14✔
528
            });
14✔
529
            return new Promise(resolve => {
2,674✔
530
                delegate.act({
14✔
531
                    role: 'seneca',
14✔
532
                    plugin: 'init',
14✔
533
                    seq: spec.data.seq,
14✔
534
                    init: plugin.name,
14✔
535
                    tag: plugin.tag,
14✔
536
                    default$: {},
14✔
537
                    fatal$: true,
14✔
538
                    local$: true,
14✔
539
                }, function (err, res) {
14✔
540
                    resolve({
14✔
541
                        op: 'merge',
14✔
542
                        out: {
14✔
543
                            prepare: {
14✔
544
                                err,
14✔
545
                                res
14✔
546
                            }
14✔
547
                        }
14✔
548
                    });
14✔
549
                });
14✔
550
            });
14✔
551
        },
14✔
552
        complete: (spec) => {
14✔
553
            let prepare = spec.data.prepare;
14✔
554
            let plugin = spec.data.plugin;
2,674✔
555
            let plugin_done = spec.data.plugin_done;
2,674✔
556
            let plugin_options = spec.data.plugin.options;
2,674✔
557
            let delegate = spec.data.delegate;
2,674✔
558
            let so = delegate.options();
2,674✔
559
            if (prepare) {
×
560
                if (prepare.err) {
2,674✔
561
                    let plugin_out = {};
28✔
562
                    plugin_out.err_code = 'plugin_init';
28✔
563
                    plugin_out.plugin_error = prepare.err.message;
28✔
564
                    if (prepare.err.code === 'action-timeout') {
×
565
                        plugin_out.err_code = 'plugin_init_timeout';
×
566
                        plugin_out.timeout = so.timeout;
×
567
                    }
14✔
568
                    return {
28✔
569
                        op: 'seneca_complete',
14✔
570
                        out: {
14✔
571
                            plugin: plugin_out
14✔
572
                        }
14✔
573
                    };
14✔
574
                }
14✔
575
                let fullname = plugin.name + (plugin.tag ? '$' + plugin.tag : '');
2,646✔
576
                if (so.debug.print && so.debug.print.options) {
×
577
                    Print.plugin_options(delegate, fullname, plugin_options);
×
578
                }
14✔
579
                delegate.log.info({
2,646✔
580
                    kind: 'plugin',
14✔
581
                    case: 'READY',
14✔
582
                    name: plugin.name,
14✔
583
                    tag: plugin.tag,
14✔
584
                });
14✔
585
                if ('function' === typeof plugin_options.inited$) {
×
586
                    plugin_options.inited$(plugin);
×
587
                }
14✔
588
            }
14✔
589
            plugin_done();
2,646✔
590
            return {
2,646✔
591
                op: 'seneca_complete',
14✔
592
                out: {
14✔
593
                    plugin: {
14✔
594
                        loading: false
14✔
595
                    }
14✔
596
                }
14✔
597
            };
14✔
598
        }
14✔
599
    };
14✔
600
}
14✔
601
function make_intern() {
14✔
602
    return {
14✔
603
        // TODO: explicit tests for these operators
14✔
604
        op: {
14✔
605
            seneca_plugin: (tr, ctx, data) => {
14✔
606
                (0, nua_1.default)(data, tr.out.merge, { preserve: true });
14✔
607
                ctx.seneca.private$.plugins[data.plugin.fullname] = tr.out.plugin;
2,772✔
608
                return { stop: false };
2,772✔
609
            },
14✔
610
            seneca_export: (tr, ctx, data) => {
14✔
611
                // NOTE/plugin/774a: when loading multiple tagged plugins,
14✔
612
                // last plugin wins the plugin name on the exports. This is
14✔
613
                // consistent with general Seneca principal that plugin load
14✔
614
                // order is significant, as later plugins override earlier
14✔
615
                // action patterns. Thus later plugins override exports too.
14✔
616
                Object.assign(data.exports, tr.out.exports);
14✔
617
                Object.assign(ctx.seneca.private$.exports, tr.out.exports);
5,446✔
618
                return { stop: false };
5,446✔
619
            },
14✔
620
            seneca_options: (tr, ctx, data) => {
14✔
621
                (0, nua_1.default)(data.plugin, tr.out.plugin, { preserve: true });
14✔
622
                let plugin_fullname = data.plugin.fullname;
3,416✔
623
                let plugin_options = data.plugin.options;
3,416✔
624
                let plugin_options_update = { plugin: {} };
3,416✔
625
                plugin_options_update.plugin[plugin_fullname] = plugin_options;
3,416✔
626
                ctx.seneca.options(plugin_options_update);
3,416✔
627
                return { stop: false };
3,416✔
628
            },
14✔
629
            seneca_complete: (tr, _ctx, data) => {
14✔
630
                (0, nua_1.default)(data.plugin, tr.out.plugin, { preserve: true });
14✔
631
                if (data.prepare.err) {
2,674✔
632
                    data.delegate.die(data.delegate.error(data.prepare.err, data.plugin.err_code, data.plugin));
28✔
633
                }
14✔
634
                return { stop: true };
2,674✔
635
            },
14✔
636
        },
14✔
637
        define_plugin: function (delegate, plugin, options) {
14✔
638
            // legacy plugins
14✔
639
            if (plugin.define.length > 1) {
14✔
640
                let fnstr = plugin.define.toString();
14✔
641
                plugin.init_func_sig = (fnstr.match(/^(.*)\r*\n/) || [])[1];
×
642
                let ex = delegate.error('unsupported_legacy_plugin', plugin);
14✔
643
                throw ex;
14✔
644
            }
14✔
645
            if (options.errors) {
2,744✔
646
                plugin.eraro = Eraro({
70✔
647
                    package: 'seneca',
14✔
648
                    msgmap: options.errors,
14✔
649
                    override: true,
14✔
650
                });
14✔
651
            }
14✔
652
            let meta;
2,744✔
653
            try {
2,744✔
654
                meta = plugin.define.call(delegate, options) || {};
2,744✔
655
            }
14✔
656
            catch (e) {
14✔
657
                Common.wrap_error(e, 'plugin_define_failed', {
56✔
658
                    fullname: plugin.fullname,
14✔
659
                    message: (e.message + (' (' + e.stack.match(/\n.*?\n/)).replace(/\n.*\//g, '')).replace(/\n/g, ''),
14✔
660
                    options: options,
14✔
661
                    repo: plugin.repo ? ' ' + plugin.repo + '/issues' : '',
×
662
                });
14✔
663
            }
14✔
664
            if (meta instanceof Promise) {
2,688✔
665
                return meta.then(finalize_meta);
126✔
666
            }
14✔
667
            return finalize_meta(meta);
2,562✔
668
            function finalize_meta(base_meta) {
14✔
669
                const meta = 'string' === typeof base_meta
×
670
                    ? { name: base_meta }
×
671
                    : base_meta;
14✔
672
                meta.options = meta.options || options;
×
673
                return meta;
2,674✔
674
            }
14✔
675
        },
14✔
676
    };
14✔
677
}
14✔
678
const Plugin = {
14✔
679
    api_use,
14✔
680
    intern,
14✔
681
};
14✔
682
exports.Plugin = Plugin;
14✔
683
//# sourceMappingURL=plugin.js.map
14✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc