sails-hook-quest 0.0.4 → 0.0.6
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/CHANGELOG.md +27 -0
- package/CONTRACT.md +97 -0
- package/README.md +14 -1
- package/lib/core/child-result.js +80 -0
- package/lib/core/execution-child.js +14 -0
- package/lib/core/executor.js +346 -143
- package/lib/core/global-sails.js +16 -0
- package/lib/core/job-control.js +130 -34
- package/lib/core/loader.js +60 -28
- package/lib/core/result.js +91 -0
- package/lib/core/runtime.js +240 -0
- package/lib/core/scheduler.js +95 -46
- package/lib/index.js +94 -17
- package/lib/types.js +301 -0
- package/package.json +16 -2
- package/.claude/settings.local.json +0 -7
- package/.commitlintrc.js +0 -1
- package/.github/FUNDING.yml +0 -1
- package/.github/workflows/prettier.yml +0 -22
- package/.husky/pre-commit +0 -1
- package/.prettierrc.js +0 -5
- package/sails-hook-quest-0.0.0.tgz +0 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 0.0.6
|
|
4
|
+
|
|
5
|
+
Quest now exposes the resident execution contract required by job-management integrations while keeping schedules in application source.
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- Process-local runtime identity and capability probes, sanitized input/schema metadata, effective scheduled input previews, running counts, pause state and actual registered timer targets.
|
|
10
|
+
- Stable run identity and manual/scheduled provenance on lifecycle events and receipts. Terminal outcomes preserve numeric process exit codes and observed termination signals separately from machine business exits.
|
|
11
|
+
- Actual machine business results over a dedicated bounded channel, independent of stdout/stderr. Null, false and zero remain values; unsupported, oversized and nonserializable results are reported explicitly. Bounded diagnostic tails include warnings from successful jobs.
|
|
12
|
+
- Bounded schedule registration/validation diagnostics, effective cron timezone precedence and memory-only restart semantics.
|
|
13
|
+
|
|
14
|
+
### Fixed
|
|
15
|
+
|
|
16
|
+
- Invalid inputs for source-loaded jobs reject before child launch with `E_QUEST_ADMISSION_REJECTED`, preserving the original Sails validation code. Loaded empty schemas reject unknown inputs; dynamic jobs without metadata keep child-side validation.
|
|
17
|
+
- Quest initialization completes only after ORM readiness, jobs and automatic schedules are loaded, and `sails.quest` is published. Successful loaded/ready events and lift callbacks can use the API immediately. Initialization failures reject Sails loading/lifting.
|
|
18
|
+
- Owned Sails CLI job children suppress their own automatic Quest schedules after source configuration loads. The resident retains scheduler authority and the child retains application hooks/context.
|
|
19
|
+
- Unsafe zero/negative/non-finite/out-of-range recurring intervals and invalid dates/timeouts register no timer. Numeric timeouts must be nonnegative; zero remains an immediate one-shot. These are intentional changes for invalid configuration. Valid expired dates and exhausted cron ranges report no future run rather than invalid configuration.
|
|
20
|
+
- Source config aliases preserve original script/schema identity. Allowed overlap state lasts until the final active child completes, and intermediate long-delay timers retain their original target.
|
|
21
|
+
- JSON/ref CLI inputs use schema-aware JSON encoding, including ordinary strings, `001` and empty text, while ordinary string inputs keep their literal semantics. Invalid schedules do not prevent an independent manual run with valid business inputs.
|
|
22
|
+
|
|
23
|
+
### Compatibility and limits
|
|
24
|
+
|
|
25
|
+
Existing public job-control methods and lifecycle event names remain. New metadata, receipt and event fields are additive. Input precedence remains `job.inputs < scriptInputs < manual inputs`. Pause does not terminate active children; stopping removes future scheduling. All resident scheduling, diagnostics, runtime identity and consumed state are memory-only. Relative intervals/timeouts restart from registration; missed runs are not replayed.
|
|
26
|
+
|
|
27
|
+
There is no cancellation API, durable execution ledger, distributed lock, workflow builder, second scheduler, automatic retry or transport server. Consumers own transport, authorization, persistence and recovery. See [CONTRACT.md](CONTRACT.md) for exact shapes, bounds and capability gating.
|
package/CONTRACT.md
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
# Resident Quest contract (v1)
|
|
2
|
+
|
|
3
|
+
This contract is introduced in Quest 0.0.6 for upstream issue [#13](https://github.com/sailscastshq/sails-hook-quest/issues/13), based on the previous v0.0.5 source (`3588713`). Probe `getRuntime().contractVersion` and capabilities; released v0.0.5 has none of these new APIs.
|
|
4
|
+
|
|
5
|
+
## Resident metadata
|
|
6
|
+
|
|
7
|
+
`getRuntime()` returns a runtime UUID, `contractVersion: 1`, `scope: 'process'`, and capabilities for input metadata, business results, run identity, and resident state, plus explicit childSchedulerSuppression/triggerProvenance/terminalExitCode/terminalSignal probes. Cancellation and durable history are explicitly false.
|
|
8
|
+
|
|
9
|
+
`metadata()` returns the current registered jobs; `metadata(name)` returns one job or undefined. Each job includes name, original script identity, friendly name/description, `inputMetadataAvailable`, sanitized keyed machine input schema, source-owned schedule, paused/withoutOverlapping flags, active running count, actual timer registration, timer target ISO timestamp (`nextRunAt`, otherwise null), and runtime UUID. Reading metadata neither schedules nor invokes jobs. Pausing blocks new admission and leaves active runs untouched. Timers can stay registered while paused. Stopping removes scheduling, rather than cancelling a child. Pause and scheduling state are process-local and reset when the resident application restarts.
|
|
10
|
+
|
|
11
|
+
The input schema contains safe JSON constraints, defaults, and examples. Functions are omitted; `customValidation` indicates a custom rule without executing it. Protected/sensitive fields and credential-like names omit defaults/examples. Schema metadata is descriptive, not a substitute for machine validation. `inputMetadataAvailable` is true for source-loaded schemas, including a genuinely empty schema, and false for dynamically added/unloaded definitions without one. In the latter case `inputs: {}` does not claim that the script takes no inputs or supports preflight; typed invocation consumers must gate on the per-job flag. Loaded empty schemas still reject unknown supplied inputs before spawning.
|
|
12
|
+
|
|
13
|
+
`getRuntime().capabilities.scheduleDiagnostics` signals parser-backed schedule assessments. Each job's additive `scheduleState` is:
|
|
14
|
+
|
|
15
|
+
```js
|
|
16
|
+
{
|
|
17
|
+
registration: 'not_attempted', // registered | not_registered | stopped | consumed | failed
|
|
18
|
+
validation: 'not_checked', // valid | invalid
|
|
19
|
+
validationErrors: [], // at most one {code, message}, fixed messages under 256 bytes total
|
|
20
|
+
reason: null, // no_schedule | no_future_run
|
|
21
|
+
lastAttemptAt: null, // ISO timestamp of last registration attempt
|
|
22
|
+
restart: {
|
|
23
|
+
persistence: 'memory_only',
|
|
24
|
+
timing: 'relative_to_registration', // wall_clock | none
|
|
25
|
+
oneShot: false,
|
|
26
|
+
missedRuns: 'not_replayed'
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Assessments are recorded during registration, not invented by metadata reads. `not_checked` with an empty error list does not mean valid. Stopping or consuming a timer retains the last validation assessment; a missing timer alone never means invalid. A valid past date or exhausted cron range reports `valid` with `no_future_run`. No schedule reports `not_checked` with `no_schedule`. Invalid registrations return no timer with one of `E_SCHEDULE_CRON`, `E_SCHEDULE_INTERVAL`, `E_SCHEDULE_TIMEOUT`, or `E_SCHEDULE_DATE`; the existing date/timeout conflict still rejects `start()` and records `E_SCHEDULE_CONFLICT`. Errors use fixed messages without raw parser output. Parser validation concerns schedules only: it does not validate scheduled business inputs or prevent an independent manual run.
|
|
32
|
+
|
|
33
|
+
Numeric intervals must be finite, strictly positive, and produce a finite future date. Invalid, zero, negative, infinite, or out-of-range recurring intervals now register no timer instead of risking immediate recursion or an overflow timer. Numeric timeouts must be finite and nonnegative; zero remains an immediate one-shot. Invalid date objects and unsupported date/timeout values register no timer. These are intentional safety changes for malformed configurations. Existing valid schedules, source ownership, overlap guards, pause behavior and manual invocation remain.
|
|
34
|
+
|
|
35
|
+
Intervals and delay timeouts start their relative clock on each registration, including resident restart. Cron, absolute dates and supported wall-clock text schedules keep wall-clock semantics. A one-shot delay may run again after restart when source `autoStart` registers it anew; it is not persisted as consumed. Expired absolute dates do not replay. Scheduling, pause, registration diagnostics and consumed state are memory-only. `nextRunAt` always comes from an actual registered timer, including long-delay intermediate timers.
|
|
36
|
+
|
|
37
|
+
For cron jobs, `schedule.timezone` reports the effective parser timezone: explicit `cronOptions.tz` overrides the job timezone, then hook timezone. An explicit empty/undefined `tz` override or missing timezone is `null`, meaning the parser's local default. `cronOptions` is preserved as bounded source metadata. `cronOptions.timezone` is not a recognized override. DST follows cron-parser in the effective zone; consumers must use the resident's registered `nextRunAt`, rather than calculate another schedule.
|
|
38
|
+
|
|
39
|
+
Config aliases use `{name: 'index-from-config', script: 'rebuild-search-index', interval: 10000, inputs: {count: 3}}`. Their schema/defaults come from the original script; events, schedules and overlap guards use the alias's job name. Two aliases intentionally have separate per-job guards, not a script-wide lock.
|
|
40
|
+
|
|
41
|
+
`scheduledInputs` is separate from schema and manual overrides:
|
|
42
|
+
|
|
43
|
+
```js
|
|
44
|
+
{
|
|
45
|
+
values: {count: 0, enabled: false, payload: null},
|
|
46
|
+
fields: {
|
|
47
|
+
count: {source: 'script_input', sensitive: false, available: true, missingRequired: false},
|
|
48
|
+
requiredValue: {source: 'omitted', sensitive: false, available: false, missingRequired: true},
|
|
49
|
+
secretToken: {source: 'script_input', sensitive: true, available: false, missingRequired: false, reason: 'sensitive'}
|
|
50
|
+
},
|
|
51
|
+
validation: 'not_checked',
|
|
52
|
+
limitBytes: 65536
|
|
53
|
+
}
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
These are raw effective scheduled values under the existing precedence `job.inputs < scriptInputs < manual inputs`. Machine schema defaults apply when a value is omitted; `schema_default` describes that fallback. `job_input` and `omitted` are the other source markers. Manual inputs do not change configured scheduled values. No sensitive values are included. Non-JSON, oversized, or budget-limited metadata reports `serialization_error`, `too_large`, or `metadata_limit` instead of a preview. Value previews are capped at 4 KiB per field and 64 KiB total. `missingRequired` flags omitted required values; `validation: 'not_checked'` deliberately does not claim custom/type validation passed.
|
|
57
|
+
|
|
58
|
+
## Execution and events
|
|
59
|
+
|
|
60
|
+
The existing signature remains `await sails.quest.run('job-name', inputs)` and returns a receipt array. Multiple names and omitted names retain their existing behavior. Admission checks pause/overlap, validates bounded JSON input and loaded machine schemas without executing business logic, and starts the owned `sails run` child. For source-loaded registered jobs, required/type/custom/unknown-key failures reject before the synchronous start event and before any child is spawned. Ad-hoc scripts or dynamically added jobs lacking loaded schema retain child-side validation; they must not be advertised as supporting full preflight admission. The child's installed Sails/whelk machine runner also validates before invoking the script, using exact typed input through a dedicated pipe. Actual machine output, including named exits, crosses another pipe; stdout is never parsed as a result.
|
|
61
|
+
|
|
62
|
+
Subscribe to `quest:job:start` before calling `run` to capture the synchronous admission run ID before the child starts. Existing start/complete/error event names and payload fields remain. They gain `runId`, `runtimeId`, `sequence`, `startedAt`, and `trigger: 'manual' | 'scheduled'`; `manual` means public/programmatic `run()`, not an actor or a dashboard attribution; both timer paths supply `scheduled` explicitly. Skips, rejected errors and receipts carry the same trigger; terminal events gain `finishedAt`. Sequence increases across this resident runtime. Skips have a new `quest:job:skip` event and an identified receipt. Admission/validation failures return a rejected Promise (the public `run()` does not synchronously throw), with `error.code: 'E_QUEST_ADMISSION_REJECTED'`, `admission: 'rejected_before_start'`, and `phase: 'validation'`. The original Sails code, such as `E_INVALID_ARGINS`, is retained as `validationCode`. They reject without spawning and have no start event; the error event carries the same admission marker and `error.admissionCode`/`validationCode`. A transport error without this verified marker must not be inferred to be preflight rejection.
|
|
63
|
+
|
|
64
|
+
A normal terminal receipt looks like:
|
|
65
|
+
|
|
66
|
+
```js
|
|
67
|
+
{
|
|
68
|
+
success: true, duration: 172,
|
|
69
|
+
runId: '...', runtimeId: '...', sequence: 2,
|
|
70
|
+
startedAt: new Date(), finishedAt: new Date(),
|
|
71
|
+
result: {status: 'available', value: {count: 0}},
|
|
72
|
+
logs: {stdout: '...', stderr: 'successful warning',
|
|
73
|
+
stdoutTruncated: false, stderrTruncated: false, limitBytes: 65536}
|
|
74
|
+
}
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
`result.status` can be `available`, `undefined`, `unsupported`, `too_large`, or `serialization_error`. Null, false, zero, arrays, and plain JSON objects retain their values. Cycles, getters, non-finite numbers, BigInt, Date/class instances, undefined nested properties, and other non-JSON values are not silently coerced. Depth/node limits also bound traversal. Missing, corrupt, or mismatched envelopes report unsupported with a reason. A successful process does not establish business success.
|
|
78
|
+
|
|
79
|
+
Sails/whelk deliberately exits process 0 for named machine exits. Preserve that process receipt and expose the actual exit separately: `{success: true, result: {status: 'available', value: 'bad', exit: 'invalid'}}`. A named exit with undefined or unrepresentable data still includes its exit beside the appropriate result status. Errors and non-zero processes reject; their error/event retains bounded diagnostics, identity, duration, and separate log tails. Terminal events, receipts and rejected Errors include `exitCode` as the actual numeric child close code or null when no numeric close code exists. Legacy terminal `event.error.code` remains numeric/null. A generated non-zero rejected Error has no `code`; a native spawn Error retains its string `code` (for example ENOENT) and has `exitCode: null`. Pre-spawn admission rejection has the dedicated string code and no exitCode, because no child existed.
|
|
80
|
+
|
|
81
|
+
`resultBytes`, `inputBytes`, and `logBytes` each default to 64 KiB and have a 1 MiB hard cap. Logs are independent stdout/stderr tails, with truncation flags; live console output and failure diagnostic tails are retained. No per-run live log-stream API is added.
|
|
82
|
+
|
|
83
|
+
## Reliability boundary
|
|
84
|
+
|
|
85
|
+
There is no upstream `readRun`, persisted ledger, event replay, cancellation, distributed lock, second scheduler, workflow builder, or automatic retry. Consumers own their transport, access controls, run correlation, durable retention and reconnection. After resident restart or delivery loss they must label missing evidence as unknown/interrupted rather than fabricate a completed run or retry work. A receipt with missing result transport reports unavailability honestly.
|
|
86
|
+
|
|
87
|
+
The result transport uses a narrowly scoped CommonJS preload in the owned Sails CLI process, matching only this script's machine completion. The preload marks only this process as an owned execution child. After source config is loaded, its Quest hook sets effective `autoStart: false`, keeping hooks and script context available while registering no automatic schedules. The authoritative resident's source `autoStart` and timers remain intact, and the marker is not inherited by other processes. Other application helpers and script implementations keep their behavior. A custom non-Node runner may complete successfully with unsupported result transport. Validate against each supported Sails/Node version before release; the tests include real Sails CLI, resident Sails/ORM, named exits, and two independent resident processes.
|
|
88
|
+
|
|
89
|
+
## Local verification
|
|
90
|
+
|
|
91
|
+
Run `npm ci`, `npm test`, `npm run typecheck`, and `npm run lint`. Tests execute synthetic disposable jobs only. The benchmark is `QUEST_BASELINE_PATH=/absolute/path/to/released/lib/core/executor.js node bench/runtime-contract.js`; it alternates release/current CLI executions for quiet, 2 MiB log, and error cases, then measures bounded serialization/diagnostic copying. Benchmark numbers are samples of this machine, not distributed throughput or exact zero-regression guarantees.
|
|
92
|
+
|
|
93
|
+
`getRuntime().capabilities.terminalSignal` indicates observed Node child-process signals. Terminal complete/error events, success receipts and rejected terminal errors carry `signal: string | null` alongside `exitCode: number | null`. A normal numeric exit or native spawn failure has `signal: null`; an observed `SIGTERM` termination has `exitCode: null, signal: 'SIGTERM'`. Pre-admission rejections and skips have neither terminal field. Named machine exits remain business `result.exit`, independent of the process exit/signal. The signal is the actual owned child's `close` signal; it does not imply who sent it, requested cancellation, or successful cancellation. Cancellation capability remains false.
|
|
94
|
+
|
|
95
|
+
Quest's async `initialize()` completes only after ORM has loaded, jobs have loaded, source auto-start scheduling has completed, and `sails.quest` has been published. The hook's loaded event, Sails `ready` event and successful full-lift callback can therefore consume the API without a delay or retry. Initialization failures reject Sails loading/lifting instead of escaping through an async event listener or publishing a partial API. Lower cleanup is installed before dependency waiting; owned child auto-start suppression still occurs after source configuration loads.
|
|
96
|
+
|
|
97
|
+
For source-loaded schemas, JSON/ref inputs use JSON-encoded CLI values even when the supplied value is a string (`'001'`, empty text, or ordinary text). This satisfies whelk's JSON syntax check before its machine invocation; the dedicated input channel still restores exact values for native machine validation. Ordinary string input CLI text is unchanged. Schema-unavailable calls retain their existing CLI behavior and child-side validation. An invalid source schedule does not block an independent manual invocation with valid business inputs.
|
package/README.md
CHANGED
|
@@ -79,6 +79,9 @@ module.exports.quest = {
|
|
|
79
79
|
// Run jobs in console environment (minimal Sails lift)
|
|
80
80
|
environment: 'console',
|
|
81
81
|
|
|
82
|
+
// Retain the final 64 KiB of child output when a job fails
|
|
83
|
+
diagnosticTailBytes: 64 * 1024,
|
|
84
|
+
|
|
82
85
|
// Define additional jobs in config
|
|
83
86
|
jobs: [
|
|
84
87
|
{
|
|
@@ -215,10 +218,20 @@ Each event includes:
|
|
|
215
218
|
inputs: { /* job inputs */ },
|
|
216
219
|
timestamp: Date,
|
|
217
220
|
duration: 1234, // milliseconds (complete/error only)
|
|
218
|
-
error: {
|
|
221
|
+
error: {
|
|
222
|
+
message: 'Job "job-name" exited with code 1',
|
|
223
|
+
code: 1,
|
|
224
|
+
stack: 'Error: Job "job-name" exited with code 1\\n...',
|
|
225
|
+
diagnostic: 'The final bounded section of the child process output'
|
|
226
|
+
}
|
|
219
227
|
}
|
|
220
228
|
```
|
|
221
229
|
|
|
230
|
+
Job output still streams live to the parent process. On failure, Quest also
|
|
231
|
+
includes a bounded diagnostic tail and a parent stack in the error event so
|
|
232
|
+
observability tools can preserve the useful failure context without buffering
|
|
233
|
+
the complete job log.
|
|
234
|
+
|
|
222
235
|
## Console Environment
|
|
223
236
|
|
|
224
237
|
Quest can run jobs in a minimal 'console' environment that skips unnecessary hooks for better performance:
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
// Loaded only into the owned CLI child, never into the resident application.
|
|
3
|
+
const fs = require('node:fs')
|
|
4
|
+
const Module = /** @type {any} */ (require('node:module'))
|
|
5
|
+
const path = require('node:path')
|
|
6
|
+
const { encodeResult, byteLimit } = require('./result')
|
|
7
|
+
const scriptPath = process.env.QUEST_SCRIPT_PATH
|
|
8
|
+
const runId = process.env.QUEST_RUN_ID
|
|
9
|
+
const limit = byteLimit(Number(process.env.QUEST_RESULT_BYTES))
|
|
10
|
+
|
|
11
|
+
if (scriptPath && runId) {
|
|
12
|
+
const inputs = JSON.parse(fs.readFileSync(4, 'utf8'))
|
|
13
|
+
require('./execution-child').markExecutionChild()
|
|
14
|
+
// Avoid propagating the contract to grandchildren that do not own these fds.
|
|
15
|
+
delete process.env.QUEST_SCRIPT_PATH
|
|
16
|
+
delete process.env.QUEST_RUN_ID
|
|
17
|
+
delete process.env.QUEST_RESULT_BYTES
|
|
18
|
+
const wrappedFns = new Set()
|
|
19
|
+
let sent = false
|
|
20
|
+
function capture(value, exit) {
|
|
21
|
+
if (sent) return
|
|
22
|
+
sent = true
|
|
23
|
+
const result = encodeResult(value, limit)
|
|
24
|
+
delete result.json
|
|
25
|
+
if (exit) result.exit = exit
|
|
26
|
+
const envelope = JSON.stringify({ version: 1, runId, result })
|
|
27
|
+
// Synchronous write prevents whelk's process.exit from discarding the result.
|
|
28
|
+
const buffer = Buffer.from(envelope)
|
|
29
|
+
let offset = 0
|
|
30
|
+
while (offset < buffer.length)
|
|
31
|
+
offset += fs.writeSync(3, buffer, offset, buffer.length - offset)
|
|
32
|
+
}
|
|
33
|
+
const originalLoad = Module._load
|
|
34
|
+
Module._load = function (request, parent, isMain) {
|
|
35
|
+
const exported = originalLoad.apply(this, arguments)
|
|
36
|
+
if (request === 'machine' && exported.buildWithCustomUsage) {
|
|
37
|
+
return Object.assign({}, exported, {
|
|
38
|
+
buildWithCustomUsage(options, omen) {
|
|
39
|
+
const wet = exported.buildWithCustomUsage(options, omen)
|
|
40
|
+
if (!wrappedFns.has(options.def.fn)) return wet
|
|
41
|
+
// Keep whelk lifecycle/validation but supply exact JSON values instead
|
|
42
|
+
// of letting CLI parsing turn null/false/0/string values into guesses.
|
|
43
|
+
const configured = function () {
|
|
44
|
+
const deferred = wet(inputs)
|
|
45
|
+
const originalExec = deferred.exec
|
|
46
|
+
deferred.exec = function (callback) {
|
|
47
|
+
return originalExec.call(this, function (error, result) {
|
|
48
|
+
if (!error) capture(result)
|
|
49
|
+
else if (
|
|
50
|
+
error.name === 'Exception' &&
|
|
51
|
+
typeof error.exit === 'string'
|
|
52
|
+
)
|
|
53
|
+
capture(error.raw, error.exit)
|
|
54
|
+
return callback.apply(this, arguments)
|
|
55
|
+
})
|
|
56
|
+
}
|
|
57
|
+
return deferred
|
|
58
|
+
}
|
|
59
|
+
Object.setPrototypeOf(configured, wet)
|
|
60
|
+
return configured
|
|
61
|
+
}
|
|
62
|
+
})
|
|
63
|
+
}
|
|
64
|
+
if (!request.endsWith(path.basename(scriptPath))) return exported
|
|
65
|
+
let resolved
|
|
66
|
+
try {
|
|
67
|
+
resolved = Module._resolveFilename(request, parent)
|
|
68
|
+
} catch {
|
|
69
|
+
return exported
|
|
70
|
+
}
|
|
71
|
+
if (
|
|
72
|
+
resolved !== scriptPath ||
|
|
73
|
+
!exported ||
|
|
74
|
+
typeof exported.fn !== 'function'
|
|
75
|
+
)
|
|
76
|
+
return exported
|
|
77
|
+
wrappedFns.add(exported.fn)
|
|
78
|
+
return exported
|
|
79
|
+
}
|
|
80
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
// This state exists only in this Node process. It is never put in the child
|
|
3
|
+
// environment, so an unrelated grandchild does not inherit scheduler authority.
|
|
4
|
+
let executionChild = false
|
|
5
|
+
|
|
6
|
+
function markExecutionChild() {
|
|
7
|
+
executionChild = true
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
function isExecutionChild() {
|
|
11
|
+
return executionChild
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
module.exports = { markExecutionChild, isExecutionChild }
|