@actiondock/testing 2.0.12 → 2.2.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 +45 -47
- package/dist/cli.d.ts +35 -0
- package/dist/cli.js +151 -0
- package/dist/clock.d.ts +3 -0
- package/dist/clock.js +108 -0
- package/dist/index.d.ts +6 -8
- package/dist/index.js +6 -486
- package/dist/platform.d.ts +48 -0
- package/dist/platform.js +61 -0
- package/dist/process.d.ts +15 -14
- package/dist/process.js +280 -0
- package/dist/runtime.d.ts +85 -14
- package/dist/runtime.js +426 -0
- package/dist/storage.js +16 -0
- package/package.json +6 -6
package/dist/runtime.js
ADDED
|
@@ -0,0 +1,426 @@
|
|
|
1
|
+
import { DefaultExecutionService, InMemoryEventSink, RuntimeConfig, RuntimeStateStore, SystemClock, normalizeActionCollection, } from "@actiondock/core";
|
|
2
|
+
import { FakeClock } from "./clock.js";
|
|
3
|
+
import { MockProcessExecutor } from "./process.js";
|
|
4
|
+
import { MemoryStorage } from "./storage.js";
|
|
5
|
+
/**
|
|
6
|
+
* 基于内存 Map 的只读/可写配置实现,专供单元测试使用。
|
|
7
|
+
*/
|
|
8
|
+
export class MemoryConfig {
|
|
9
|
+
store;
|
|
10
|
+
constructor(initial = {}) {
|
|
11
|
+
this.store = new Map(Object.entries(initial));
|
|
12
|
+
}
|
|
13
|
+
get(key, defaultValue) {
|
|
14
|
+
if (this.store.has(key)) {
|
|
15
|
+
return this.store.get(key);
|
|
16
|
+
}
|
|
17
|
+
return defaultValue;
|
|
18
|
+
}
|
|
19
|
+
has(key) {
|
|
20
|
+
return this.store.has(key);
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* 在测试期间动态更新或插入配置值。
|
|
24
|
+
* @param key 配置键名
|
|
25
|
+
* @param value 配置值
|
|
26
|
+
*/
|
|
27
|
+
set(key, value) {
|
|
28
|
+
this.store.set(key, value);
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* 删除指定配置项。
|
|
32
|
+
* @param key 配置键名
|
|
33
|
+
*/
|
|
34
|
+
delete(key) {
|
|
35
|
+
return this.store.delete(key);
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* 列出所有已存储配置项。
|
|
39
|
+
*/
|
|
40
|
+
list() {
|
|
41
|
+
return Object.fromEntries(this.store.entries());
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
// 状态键编解码能力单一事实源位于 @actiondock/sdk,此处 re-export 维持既有导入路径兼容并供本模块内部复用
|
|
45
|
+
import { decodeStateKey, encodeStateKey, escapeStateSegment, unescapeStateSegment, } from "@actiondock/sdk";
|
|
46
|
+
export { decodeStateKey, encodeStateKey, escapeStateSegment, unescapeStateSegment };
|
|
47
|
+
/**
|
|
48
|
+
* 基于内存 Map 的状态存储实现,支持命名空间隔离与 TTL 自动失效,专供单元测试使用。
|
|
49
|
+
*/
|
|
50
|
+
export class MemoryStateStore {
|
|
51
|
+
store;
|
|
52
|
+
namespace;
|
|
53
|
+
clock;
|
|
54
|
+
constructor(store, namespace = "", clock) {
|
|
55
|
+
this.store = store || new Map();
|
|
56
|
+
this.namespace = namespace;
|
|
57
|
+
this.clock = clock ?? new SystemClock();
|
|
58
|
+
}
|
|
59
|
+
/** 获取注入时钟的当前时间戳(毫秒),TTL 过期判定单一事实入口 */
|
|
60
|
+
nowMs() {
|
|
61
|
+
return this.clock.now().getTime();
|
|
62
|
+
}
|
|
63
|
+
qualify(key) {
|
|
64
|
+
return encodeStateKey(this.namespace, key);
|
|
65
|
+
}
|
|
66
|
+
extractEntry(raw) {
|
|
67
|
+
if (raw !== null &&
|
|
68
|
+
typeof raw === "object" &&
|
|
69
|
+
("__actiondock_entry__" in raw ||
|
|
70
|
+
"expiresAt" in raw)) {
|
|
71
|
+
return raw;
|
|
72
|
+
}
|
|
73
|
+
return { value: raw };
|
|
74
|
+
}
|
|
75
|
+
async get(key) {
|
|
76
|
+
const qKey = this.qualify(key);
|
|
77
|
+
const raw = this.store.get(qKey);
|
|
78
|
+
if (raw === undefined)
|
|
79
|
+
return undefined;
|
|
80
|
+
const entry = this.extractEntry(raw);
|
|
81
|
+
if (entry.expiresAt !== undefined && entry.expiresAt <= this.nowMs()) {
|
|
82
|
+
this.store.delete(qKey);
|
|
83
|
+
return undefined;
|
|
84
|
+
}
|
|
85
|
+
return (entry.value !== undefined ? structuredClone(entry.value) : undefined);
|
|
86
|
+
}
|
|
87
|
+
async set(key, value, ttl) {
|
|
88
|
+
const qKey = this.qualify(key);
|
|
89
|
+
const expiresAt = typeof ttl === "number" && ttl > 0 ? this.nowMs() + ttl * 1000 : undefined;
|
|
90
|
+
const entry = {
|
|
91
|
+
value: structuredClone(value),
|
|
92
|
+
expiresAt,
|
|
93
|
+
};
|
|
94
|
+
entry.__actiondock_entry__ = true;
|
|
95
|
+
this.store.set(qKey, entry);
|
|
96
|
+
}
|
|
97
|
+
async delete(key) {
|
|
98
|
+
const qKey = this.qualify(key);
|
|
99
|
+
return this.store.delete(qKey);
|
|
100
|
+
}
|
|
101
|
+
async clear(prefix = "") {
|
|
102
|
+
const keysToDelete = await this.keys(prefix);
|
|
103
|
+
let count = 0;
|
|
104
|
+
for (const k of keysToDelete) {
|
|
105
|
+
if (this.store.delete(this.qualify(k))) {
|
|
106
|
+
count++;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
return count;
|
|
110
|
+
}
|
|
111
|
+
async keys(prefix = "") {
|
|
112
|
+
const now = this.nowMs();
|
|
113
|
+
const result = [];
|
|
114
|
+
for (const [k, raw] of this.store.entries()) {
|
|
115
|
+
let decoded;
|
|
116
|
+
try {
|
|
117
|
+
decoded = decodeStateKey(k);
|
|
118
|
+
}
|
|
119
|
+
catch {
|
|
120
|
+
continue;
|
|
121
|
+
}
|
|
122
|
+
if (decoded.namespace === this.namespace) {
|
|
123
|
+
if (prefix && !decoded.key.startsWith(prefix)) {
|
|
124
|
+
continue;
|
|
125
|
+
}
|
|
126
|
+
const entry = this.extractEntry(raw);
|
|
127
|
+
if (entry.expiresAt !== undefined && entry.expiresAt <= now) {
|
|
128
|
+
this.store.delete(k);
|
|
129
|
+
continue;
|
|
130
|
+
}
|
|
131
|
+
result.push(decoded.key);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
return result;
|
|
135
|
+
}
|
|
136
|
+
scope(namespace) {
|
|
137
|
+
const nextNs = this.namespace
|
|
138
|
+
? `${this.namespace}:${namespace}`
|
|
139
|
+
: namespace;
|
|
140
|
+
return new MemoryStateStore(this.store, nextNs, this.clock);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* 内存日志记录器实现,将所有日志记录在数组中以便在测试断言中检索。
|
|
145
|
+
*/
|
|
146
|
+
export class MemoryLogger {
|
|
147
|
+
logs = [];
|
|
148
|
+
debug(message, data) {
|
|
149
|
+
this.logs.push({ level: "debug", message, data });
|
|
150
|
+
}
|
|
151
|
+
info(message, data) {
|
|
152
|
+
this.logs.push({ level: "info", message, data });
|
|
153
|
+
}
|
|
154
|
+
warn(message, data) {
|
|
155
|
+
this.logs.push({ level: "warn", message, data });
|
|
156
|
+
}
|
|
157
|
+
error(message, data) {
|
|
158
|
+
this.logs.push({ level: "error", message, data });
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
// 规范化运行时错误类单一事实源位于 @actiondock/sdk,此处 re-export 维持既有导入路径兼容并供本模块内部复用
|
|
162
|
+
import { ActionRuntimeError } from "@actiondock/sdk";
|
|
163
|
+
export { ActionRuntimeError };
|
|
164
|
+
/**
|
|
165
|
+
* 测试配置管理器实现。
|
|
166
|
+
*/
|
|
167
|
+
export class TestConfigStore {
|
|
168
|
+
runtimeConfig;
|
|
169
|
+
storage;
|
|
170
|
+
constructor(storage, projectConfig, overrides) {
|
|
171
|
+
this.storage = storage;
|
|
172
|
+
this.runtimeConfig = new RuntimeConfig(storage, overrides, projectConfig, undefined);
|
|
173
|
+
}
|
|
174
|
+
get(key, defaultValue) {
|
|
175
|
+
return this.runtimeConfig.get(key, defaultValue);
|
|
176
|
+
}
|
|
177
|
+
has(key) {
|
|
178
|
+
return this.runtimeConfig.has(key);
|
|
179
|
+
}
|
|
180
|
+
set(key, value) {
|
|
181
|
+
this.storage.setConfig(key, value);
|
|
182
|
+
}
|
|
183
|
+
delete(key) {
|
|
184
|
+
const res = this.storage.deleteConfig(key);
|
|
185
|
+
return typeof res === "boolean" ? res : true;
|
|
186
|
+
}
|
|
187
|
+
list() {
|
|
188
|
+
return this.storage.listConfig();
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* 测试事件接收器实现。
|
|
193
|
+
* 记录执行期间产生的所有事件并支持历史检索。
|
|
194
|
+
*/
|
|
195
|
+
export class TestEventSink extends InMemoryEventSink {
|
|
196
|
+
allEvents = [];
|
|
197
|
+
sequenceCounter = 0;
|
|
198
|
+
/** 获取下一个单调自增序号 */
|
|
199
|
+
nextSequence() {
|
|
200
|
+
return this.sequenceCounter++;
|
|
201
|
+
}
|
|
202
|
+
emit(event) {
|
|
203
|
+
this.allEvents.push(event);
|
|
204
|
+
super.emit(event);
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* 检索历史事件列表。
|
|
208
|
+
*
|
|
209
|
+
* @param runId 可选运行标识筛选
|
|
210
|
+
*/
|
|
211
|
+
getEvents(runId) {
|
|
212
|
+
if (runId) {
|
|
213
|
+
return this.allEvents.filter((e) => e.runId === runId);
|
|
214
|
+
}
|
|
215
|
+
return [...this.allEvents];
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* 清理所有捕获的事件记录。
|
|
219
|
+
*/
|
|
220
|
+
clearAll() {
|
|
221
|
+
this.allEvents = [];
|
|
222
|
+
this.sequenceCounter = 0;
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
const anonymousTestActions = new WeakMap();
|
|
226
|
+
let anonymousTestActionCounter = 0;
|
|
227
|
+
/** 测试运行时内部持有的匿名 Action 下一次可用序号 */
|
|
228
|
+
function nextAnonymousTestActionId() {
|
|
229
|
+
anonymousTestActionCounter++;
|
|
230
|
+
return `test-action-${anonymousTestActionCounter}`;
|
|
231
|
+
}
|
|
232
|
+
/**
|
|
233
|
+
* 将任意形态的 actions 输入归一化为统一映射表。
|
|
234
|
+
*
|
|
235
|
+
* 直接复用 core 的 normalizeActionCollection 作为归一化单一事实源,
|
|
236
|
+
* 避免在 testing 包内重新实现三形态分支造成逻辑拷贝;
|
|
237
|
+
* 此处无需 actionSpecs 产物,仅取 actionsMap,并额外为不含包前缀的标识补充限定别名。
|
|
238
|
+
*
|
|
239
|
+
* @param rawActions 三形态之一的 Action 集合输入
|
|
240
|
+
* @param packageId 当前 Package 标识,用于补充限定别名
|
|
241
|
+
*/
|
|
242
|
+
function normalizeTestActions(rawActions, packageId) {
|
|
243
|
+
const { actionsMap } = normalizeActionCollection(rawActions);
|
|
244
|
+
for (const [id, act] of [...actionsMap]) {
|
|
245
|
+
if (!id.includes("/")) {
|
|
246
|
+
actionsMap.set(`${packageId}/${id}`, act);
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
return actionsMap;
|
|
250
|
+
}
|
|
251
|
+
/**
|
|
252
|
+
* 测试运行时 Action 注册表。
|
|
253
|
+
* 统一持有本地 actionsMap 与 executionService 双份注册状态,收敛注册、检索与列举入口。
|
|
254
|
+
*/
|
|
255
|
+
class TestActionRegistry {
|
|
256
|
+
actionsMap;
|
|
257
|
+
executionService;
|
|
258
|
+
packageId;
|
|
259
|
+
constructor(actionsMap, executionService, packageId) {
|
|
260
|
+
this.actionsMap = actionsMap;
|
|
261
|
+
this.executionService = executionService;
|
|
262
|
+
this.packageId = packageId;
|
|
263
|
+
}
|
|
264
|
+
/** 双签名注册:字符串标识与定义,或携带 id 的定义对象 */
|
|
265
|
+
register(idOrAction, maybeAction) {
|
|
266
|
+
if (typeof idOrAction === "string") {
|
|
267
|
+
if (!maybeAction) {
|
|
268
|
+
throw new Error(`registerAction(id, action) 调用缺少 action 定义:id=${idOrAction}`);
|
|
269
|
+
}
|
|
270
|
+
this.executionService.registerAction(idOrAction, maybeAction);
|
|
271
|
+
this.actionsMap.set(idOrAction, maybeAction);
|
|
272
|
+
if (!idOrAction.includes("/")) {
|
|
273
|
+
this.actionsMap.set(`${this.packageId}/${idOrAction}`, maybeAction);
|
|
274
|
+
}
|
|
275
|
+
return;
|
|
276
|
+
}
|
|
277
|
+
const actObj = idOrAction;
|
|
278
|
+
const id = actObj.id;
|
|
279
|
+
const act = actObj.action ?? (typeof actObj.run === "function" ? idOrAction : undefined);
|
|
280
|
+
if (id && act) {
|
|
281
|
+
this.actionsMap.set(id, act);
|
|
282
|
+
if (!id.includes("/")) {
|
|
283
|
+
this.actionsMap.set(`${this.packageId}/${id}`, act);
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
this.executionService.registerAction(idOrAction);
|
|
287
|
+
}
|
|
288
|
+
/** 按标识检索已注册定义 */
|
|
289
|
+
get(id) {
|
|
290
|
+
return this.executionService.getAction(id);
|
|
291
|
+
}
|
|
292
|
+
/** 列出已注册的全部定义 */
|
|
293
|
+
list() {
|
|
294
|
+
return this.executionService.listActions();
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
/**
|
|
298
|
+
* 解析 execute 入参的 Action 引用。
|
|
299
|
+
*
|
|
300
|
+
* 字符串直接作为引用;对象则依次尝试自身 id、注册表反查、匿名 WeakMap 映射,
|
|
301
|
+
* 并在首次出现时完成注册。全程不修改调用方传入的对象。
|
|
302
|
+
*
|
|
303
|
+
* @param action Action 定义或已注册标识
|
|
304
|
+
* @param registry 测试运行时 Action 注册表
|
|
305
|
+
* @returns 可用于 executionService 启动执行的引用标识
|
|
306
|
+
*/
|
|
307
|
+
function resolveActionRef(action, registry) {
|
|
308
|
+
if (typeof action === "string") {
|
|
309
|
+
return action;
|
|
310
|
+
}
|
|
311
|
+
const candidateId = action.id;
|
|
312
|
+
if (candidateId) {
|
|
313
|
+
registry.executionService.registerAction(candidateId, action);
|
|
314
|
+
registry.actionsMap.set(candidateId, action);
|
|
315
|
+
return candidateId;
|
|
316
|
+
}
|
|
317
|
+
// 反查注册表:同一对象已注册时复用既有标识
|
|
318
|
+
for (const [registeredId, registeredAct] of registry.actionsMap) {
|
|
319
|
+
if (registeredAct === action) {
|
|
320
|
+
return registeredId;
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
// 匿名对象首次出现:仅记录 WeakMap 映射,不写入调用方对象
|
|
324
|
+
let anonId = anonymousTestActions.get(action);
|
|
325
|
+
if (!anonId) {
|
|
326
|
+
anonId = nextAnonymousTestActionId();
|
|
327
|
+
anonymousTestActions.set(action, anonId);
|
|
328
|
+
}
|
|
329
|
+
registry.executionService.registerAction(anonId, action);
|
|
330
|
+
registry.actionsMap.set(anonId, action);
|
|
331
|
+
return anonId;
|
|
332
|
+
}
|
|
333
|
+
/**
|
|
334
|
+
* 创建全功能测试运行时实例。
|
|
335
|
+
* 基于统一 ExecutionService 协调执行全生命周期,并暴露配置、状态、时钟、进程与事件等调试接口。
|
|
336
|
+
*
|
|
337
|
+
* @param options 测试运行时选项
|
|
338
|
+
*/
|
|
339
|
+
export function createTestRuntime(options = {}) {
|
|
340
|
+
const packageId = options.packageId || "my-pkg";
|
|
341
|
+
const clock = options.clock ??
|
|
342
|
+
(options.platform?.clock instanceof FakeClock ? options.platform.clock : new FakeClock());
|
|
343
|
+
const process = options.process ??
|
|
344
|
+
(options.platform?.process instanceof MockProcessExecutor
|
|
345
|
+
? options.platform.process
|
|
346
|
+
: new MockProcessExecutor());
|
|
347
|
+
const storage = options.storage ??
|
|
348
|
+
(options.platform?.storage
|
|
349
|
+
? options.platform.storage.createStorage(packageId)
|
|
350
|
+
: new MemoryStorage({
|
|
351
|
+
packageId,
|
|
352
|
+
clock,
|
|
353
|
+
}));
|
|
354
|
+
// 初始化配置数据
|
|
355
|
+
if (options.config) {
|
|
356
|
+
for (const [key, val] of Object.entries(options.config)) {
|
|
357
|
+
storage.setConfig(key, val);
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
// 初始化状态数据
|
|
361
|
+
if (options.state) {
|
|
362
|
+
for (const [key, val] of Object.entries(options.state)) {
|
|
363
|
+
storage.setState("", key, val);
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
const events = new TestEventSink();
|
|
367
|
+
const memoryLogger = options.logger instanceof MemoryLogger ? options.logger : new MemoryLogger();
|
|
368
|
+
const actionsMap = normalizeTestActions(options.actions, packageId);
|
|
369
|
+
const executionService = new DefaultExecutionService({
|
|
370
|
+
packageId,
|
|
371
|
+
storage,
|
|
372
|
+
projectConfig: options.projectConfig,
|
|
373
|
+
configOverrides: options.configOverrides,
|
|
374
|
+
actions: actionsMap,
|
|
375
|
+
process,
|
|
376
|
+
clock,
|
|
377
|
+
logger: memoryLogger,
|
|
378
|
+
eventSink: events,
|
|
379
|
+
platform: options.platform,
|
|
380
|
+
});
|
|
381
|
+
const registry = new TestActionRegistry(actionsMap, executionService, packageId);
|
|
382
|
+
const testConfig = new TestConfigStore(storage, options.projectConfig, options.configOverrides);
|
|
383
|
+
const testState = new RuntimeStateStore(storage);
|
|
384
|
+
const registerAction = (idOrAction, maybeAction) => {
|
|
385
|
+
registry.register(idOrAction, maybeAction);
|
|
386
|
+
};
|
|
387
|
+
const execute = async (action, input = {}, execOptions = {}) => {
|
|
388
|
+
const actionRef = resolveActionRef(action, registry);
|
|
389
|
+
const ticket = await executionService.start(actionRef, input, {
|
|
390
|
+
signal: execOptions.signal,
|
|
391
|
+
timeoutMs: execOptions.timeoutMs,
|
|
392
|
+
config: execOptions.configOverrides,
|
|
393
|
+
parentRunId: execOptions.parentRunId,
|
|
394
|
+
rootRunId: execOptions.rootRunId,
|
|
395
|
+
maxCallDepth: execOptions.maxCallDepth,
|
|
396
|
+
logger: execOptions.logger,
|
|
397
|
+
progress: execOptions.progress,
|
|
398
|
+
process: execOptions.process || process,
|
|
399
|
+
});
|
|
400
|
+
const result = (await ticket.result);
|
|
401
|
+
return result;
|
|
402
|
+
};
|
|
403
|
+
const run = async (action, input = {}) => {
|
|
404
|
+
const result = await execute(action, input);
|
|
405
|
+
if (!result.ok) {
|
|
406
|
+
throw new ActionRuntimeError(result.error);
|
|
407
|
+
}
|
|
408
|
+
return result.data;
|
|
409
|
+
};
|
|
410
|
+
return {
|
|
411
|
+
config: testConfig,
|
|
412
|
+
state: testState,
|
|
413
|
+
clock,
|
|
414
|
+
process,
|
|
415
|
+
events,
|
|
416
|
+
logger: memoryLogger,
|
|
417
|
+
storage,
|
|
418
|
+
executionService,
|
|
419
|
+
runner: executionService.runner,
|
|
420
|
+
registerAction,
|
|
421
|
+
getAction: (id) => registry.get(id),
|
|
422
|
+
listActions: () => registry.list(),
|
|
423
|
+
run,
|
|
424
|
+
execute,
|
|
425
|
+
};
|
|
426
|
+
}
|
package/dist/storage.js
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { SqliteRuntimeStorage, } from "@actiondock/core";
|
|
2
|
+
/**
|
|
3
|
+
* 统一内存运行时存储实现。
|
|
4
|
+
* 基于 SqliteRuntimeStorage 构建,默认使用 :memory: 内存数据库并对接虚拟时钟,
|
|
5
|
+
* 确保与生产环境具备完全相同的配置优先级、状态过期契约与运行终态行为。
|
|
6
|
+
*/
|
|
7
|
+
export class MemoryStorage extends SqliteRuntimeStorage {
|
|
8
|
+
constructor(options = {}) {
|
|
9
|
+
super({
|
|
10
|
+
packageId: options.packageId || "test-pkg",
|
|
11
|
+
dbPath: ":memory:",
|
|
12
|
+
driver: options.driver,
|
|
13
|
+
clock: options.clock,
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@actiondock/testing",
|
|
3
|
-
"version": "2.0
|
|
3
|
+
"version": "2.2.0",
|
|
4
4
|
"description": "ActionDock Test Runtime for testing Actions with real Core execution semantics",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -18,19 +18,19 @@
|
|
|
18
18
|
"README.md"
|
|
19
19
|
],
|
|
20
20
|
"engines": {
|
|
21
|
-
"node": ">=
|
|
21
|
+
"node": ">=24.12.0"
|
|
22
22
|
},
|
|
23
23
|
"publishConfig": {
|
|
24
24
|
"access": "public",
|
|
25
25
|
"registry": "https://registry.npmjs.org/"
|
|
26
26
|
},
|
|
27
27
|
"scripts": {
|
|
28
|
-
"build": "
|
|
29
|
-
"test": "
|
|
28
|
+
"build": "node ../../scripts/build.ts",
|
|
29
|
+
"test": "node ../../scripts/run-tests.ts"
|
|
30
30
|
},
|
|
31
31
|
"dependencies": {
|
|
32
|
-
"@actiondock/core": "^2.0
|
|
33
|
-
"@actiondock/sdk": "^2.0
|
|
32
|
+
"@actiondock/core": "^2.2.0",
|
|
33
|
+
"@actiondock/sdk": "^2.2.0"
|
|
34
34
|
},
|
|
35
35
|
"devDependencies": {
|
|
36
36
|
"typescript": "^5.7.0"
|