@dudousxd/nestjs-durable 0.39.0 → 0.40.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/index.cjs +135 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +135 -4
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.cjs
CHANGED
|
@@ -45,6 +45,7 @@ __export(index_exports, {
|
|
|
45
45
|
ProxyRunGateway: () => ProxyRunGateway,
|
|
46
46
|
RUN_GATEWAY: () => RUN_GATEWAY,
|
|
47
47
|
RUN_REDIS_WORKER: () => RUN_REDIS_WORKER,
|
|
48
|
+
RunGateway: () => import_nestjs_durable_core15.RunGateway,
|
|
48
49
|
RunRequestResponder: () => RunRequestResponder,
|
|
49
50
|
STEP_INTERCEPTOR_METADATA: () => STEP_INTERCEPTOR_METADATA,
|
|
50
51
|
Step: () => Step,
|
|
@@ -81,9 +82,120 @@ var import_nestjs_durable_core2 = require("@dudousxd/nestjs-durable-core");
|
|
|
81
82
|
// src/decorators.ts
|
|
82
83
|
var import_nestjs_durable_core = require("@dudousxd/nestjs-durable-core");
|
|
83
84
|
var import_reflect_metadata = require("reflect-metadata");
|
|
85
|
+
|
|
86
|
+
// src/origin.ts
|
|
87
|
+
var import_node_fs = require("fs");
|
|
88
|
+
var import_node_path = require("path");
|
|
89
|
+
var import_node_url = require("url");
|
|
90
|
+
var declaringFileByClass = /* @__PURE__ */ new WeakMap();
|
|
91
|
+
var packageNameByDir = /* @__PURE__ */ new Map();
|
|
92
|
+
function declaringFile(boundary) {
|
|
93
|
+
const capture = Error.captureStackTrace;
|
|
94
|
+
if (typeof capture !== "function") return void 0;
|
|
95
|
+
const holder = {};
|
|
96
|
+
capture(holder, boundary);
|
|
97
|
+
return topFrameFile(holder.stack);
|
|
98
|
+
}
|
|
99
|
+
__name(declaringFile, "declaringFile");
|
|
100
|
+
function rememberDeclaringFile(target, file) {
|
|
101
|
+
if (file) declaringFileByClass.set(target, file);
|
|
102
|
+
}
|
|
103
|
+
__name(rememberDeclaringFile, "rememberDeclaringFile");
|
|
104
|
+
function originOfClass(target) {
|
|
105
|
+
for (let ctor = target; typeof ctor === "function" || typeof ctor === "object" && ctor !== null; ctor = Object.getPrototypeOf(ctor)) {
|
|
106
|
+
const file = declaringFileByClass.get(ctor);
|
|
107
|
+
if (file) return packageNameFor(file);
|
|
108
|
+
}
|
|
109
|
+
return void 0;
|
|
110
|
+
}
|
|
111
|
+
__name(originOfClass, "originOfClass");
|
|
112
|
+
function originOfProvider(wrapper) {
|
|
113
|
+
const fromMetatype = originOfClass(wrapper.metatype);
|
|
114
|
+
if (fromMetatype) return fromMetatype;
|
|
115
|
+
const instance = wrapper.instance;
|
|
116
|
+
if (typeof instance !== "object" || instance === null) return void 0;
|
|
117
|
+
return originOfClass(instance.constructor);
|
|
118
|
+
}
|
|
119
|
+
__name(originOfProvider, "originOfProvider");
|
|
120
|
+
function packageNameFor(file) {
|
|
121
|
+
const start = (0, import_node_path.dirname)(file);
|
|
122
|
+
const visited = [];
|
|
123
|
+
let dir = start;
|
|
124
|
+
for (; ; ) {
|
|
125
|
+
if (packageNameByDir.has(dir)) {
|
|
126
|
+
const cached = packageNameByDir.get(dir);
|
|
127
|
+
for (const seen of visited) packageNameByDir.set(seen, cached);
|
|
128
|
+
return cached;
|
|
129
|
+
}
|
|
130
|
+
visited.push(dir);
|
|
131
|
+
const name = readPackageName((0, import_node_path.join)(dir, "package.json"));
|
|
132
|
+
if (name !== void 0) {
|
|
133
|
+
for (const seen of visited) packageNameByDir.set(seen, name);
|
|
134
|
+
return name;
|
|
135
|
+
}
|
|
136
|
+
const parent = (0, import_node_path.dirname)(dir);
|
|
137
|
+
if (parent === dir) {
|
|
138
|
+
for (const seen of visited) packageNameByDir.set(seen, void 0);
|
|
139
|
+
return void 0;
|
|
140
|
+
}
|
|
141
|
+
dir = parent;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
__name(packageNameFor, "packageNameFor");
|
|
145
|
+
function readPackageName(path) {
|
|
146
|
+
let raw;
|
|
147
|
+
try {
|
|
148
|
+
raw = (0, import_node_fs.readFileSync)(path, "utf8");
|
|
149
|
+
} catch {
|
|
150
|
+
return void 0;
|
|
151
|
+
}
|
|
152
|
+
let parsed;
|
|
153
|
+
try {
|
|
154
|
+
parsed = JSON.parse(raw);
|
|
155
|
+
} catch {
|
|
156
|
+
return void 0;
|
|
157
|
+
}
|
|
158
|
+
if (!isRecord(parsed)) return void 0;
|
|
159
|
+
const name = parsed.name;
|
|
160
|
+
return typeof name === "string" && name.length > 0 ? name : void 0;
|
|
161
|
+
}
|
|
162
|
+
__name(readPackageName, "readPackageName");
|
|
163
|
+
function isRecord(value) {
|
|
164
|
+
return typeof value === "object" && value !== null;
|
|
165
|
+
}
|
|
166
|
+
__name(isRecord, "isRecord");
|
|
167
|
+
function topFrameFile(stack) {
|
|
168
|
+
if (typeof stack !== "string") return void 0;
|
|
169
|
+
for (const line of stack.split("\n")) {
|
|
170
|
+
const frame = line.trim();
|
|
171
|
+
if (!frame.startsWith("at ")) continue;
|
|
172
|
+
return fileOfFrame(frame.slice(3));
|
|
173
|
+
}
|
|
174
|
+
return void 0;
|
|
175
|
+
}
|
|
176
|
+
__name(topFrameFile, "topFrameFile");
|
|
177
|
+
function fileOfFrame(frame) {
|
|
178
|
+
const match = /\((.+):\d+:\d+\)$/.exec(frame) ?? /^(.+):\d+:\d+$/.exec(frame);
|
|
179
|
+
const location = match?.[1];
|
|
180
|
+
if (location === void 0) return void 0;
|
|
181
|
+
if (location.startsWith("file://")) {
|
|
182
|
+
try {
|
|
183
|
+
return (0, import_node_url.fileURLToPath)(location);
|
|
184
|
+
} catch {
|
|
185
|
+
return void 0;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
const absolute = location.startsWith("/") || /^[A-Za-z]:[\\/]/.test(location);
|
|
189
|
+
return absolute ? location : void 0;
|
|
190
|
+
}
|
|
191
|
+
__name(fileOfFrame, "fileOfFrame");
|
|
192
|
+
|
|
193
|
+
// src/decorators.ts
|
|
84
194
|
var WORKFLOW_METADATA = Symbol("nestjs-durable:workflow");
|
|
85
195
|
function Workflow(options) {
|
|
196
|
+
const declaredIn = declaringFile(Workflow);
|
|
86
197
|
return (target) => {
|
|
198
|
+
rememberDeclaringFile(target, declaredIn);
|
|
87
199
|
const meta = {
|
|
88
200
|
name: options.name,
|
|
89
201
|
version: options.version ?? "1",
|
|
@@ -312,7 +424,7 @@ function scanWorkflows(discovery, register) {
|
|
|
312
424
|
if (typeof workflow.run !== "function") {
|
|
313
425
|
throw new Error(`@Workflow ${meta.name} must define a run(ctx, input) method`);
|
|
314
426
|
}
|
|
315
|
-
register(meta, workflow);
|
|
427
|
+
register(meta, workflow, originOfProvider(wrapper));
|
|
316
428
|
}
|
|
317
429
|
}
|
|
318
430
|
__name(scanWorkflows, "scanWorkflows");
|
|
@@ -1609,7 +1721,9 @@ var WorkflowRegistrar = class {
|
|
|
1609
1721
|
this.engine.registerEntity(entityMeta.name, entityConfigFor(instance.constructor));
|
|
1610
1722
|
}
|
|
1611
1723
|
}
|
|
1612
|
-
|
|
1724
|
+
const unattributed = [];
|
|
1725
|
+
scanWorkflows(this.discovery, (meta, workflow, origin) => {
|
|
1726
|
+
if (origin === void 0) unattributed.push(meta.name);
|
|
1613
1727
|
const validateInput = meta.validateInput ?? (meta.inputSchema ? classValidatorInput(meta.inputSchema) : void 0);
|
|
1614
1728
|
const eventBatch = meta.debounce ? {
|
|
1615
1729
|
mode: "debounce",
|
|
@@ -1621,6 +1735,10 @@ var WorkflowRegistrar = class {
|
|
|
1621
1735
|
} : void 0;
|
|
1622
1736
|
const workflowCtor = workflow.constructor;
|
|
1623
1737
|
this.engine.register(meta.name, meta.version, (ctx, input) => workflow.run(ctx, input), {
|
|
1738
|
+
// Stamped onto every run this workflow starts (see `WorkflowRun.origin`). Derived from the
|
|
1739
|
+
// class's declaring file, so a lib gets attributed without opting in; `undefined` when it
|
|
1740
|
+
// could not be derived, which the engine records as unknown rather than defaulting.
|
|
1741
|
+
origin,
|
|
1624
1742
|
tags: meta.tags,
|
|
1625
1743
|
singleton: meta.singleton,
|
|
1626
1744
|
executionTimeout: meta.executionTimeout,
|
|
@@ -1653,14 +1771,27 @@ var WorkflowRegistrar = class {
|
|
|
1653
1771
|
}
|
|
1654
1772
|
if (inline) {
|
|
1655
1773
|
const dlqName = `${meta.name}.dlq`;
|
|
1656
|
-
this.engine.register(dlqName, meta.version, inline
|
|
1774
|
+
this.engine.register(dlqName, meta.version, inline, {
|
|
1775
|
+
origin
|
|
1776
|
+
});
|
|
1657
1777
|
deadLetterByWorkflow.set(meta.name, dlqName);
|
|
1658
1778
|
} else if (meta.deadLetterWorkflow) {
|
|
1659
1779
|
deadLetterByWorkflow.set(meta.name, (0, import_nestjs_durable_core12.workflowName)(meta.deadLetterWorkflow));
|
|
1660
1780
|
}
|
|
1661
1781
|
});
|
|
1782
|
+
this.reportUnattributed(unattributed);
|
|
1662
1783
|
this.installDeadLetterRouting(deadLetterByWorkflow);
|
|
1663
1784
|
}
|
|
1785
|
+
/**
|
|
1786
|
+
* Says, once at boot, which workflows could not be attributed to a package — their runs are stamped
|
|
1787
|
+
* with no `origin` at all, so an operator filtering the dashboard by origin will not see them. That
|
|
1788
|
+
* is the deliberate trade (an absent origin over an invented one), but it has to be visible: a
|
|
1789
|
+
* silently-dropped run is indistinguishable from a run that never happened.
|
|
1790
|
+
*/
|
|
1791
|
+
reportUnattributed(names) {
|
|
1792
|
+
if (names.length === 0) return;
|
|
1793
|
+
console.warn(`[nestjs-durable] could not derive an origin (declaring package) for ${names.length} workflow(s): ${names.join(", ")}. Their runs carry no origin and will not match an origin filter.`);
|
|
1794
|
+
}
|
|
1664
1795
|
/** Returns the instance's `@DeadLetter()` method bound to the instance, or undefined if none. */
|
|
1665
1796
|
findDeadLetterHandler(instance) {
|
|
1666
1797
|
const prototype = Object.getPrototypeOf(instance);
|
|
@@ -2195,6 +2326,7 @@ var import_nestjs_durable_core15 = require("@dudousxd/nestjs-durable-core");
|
|
|
2195
2326
|
ProxyRunGateway,
|
|
2196
2327
|
RUN_GATEWAY,
|
|
2197
2328
|
RUN_REDIS_WORKER,
|
|
2329
|
+
RunGateway,
|
|
2198
2330
|
RunRequestResponder,
|
|
2199
2331
|
STEP_INTERCEPTOR_METADATA,
|
|
2200
2332
|
Step,
|