@elizaos/autonomous 2.0.0-alpha.10

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.
Files changed (241) hide show
  1. package/LICENSE +21 -0
  2. package/package.json +270 -0
  3. package/src/actions/emote.ts +101 -0
  4. package/src/actions/restart.ts +101 -0
  5. package/src/actions/send-message.ts +168 -0
  6. package/src/actions/stream-control.ts +439 -0
  7. package/src/actions/switch-stream-source.ts +126 -0
  8. package/src/actions/terminal.ts +186 -0
  9. package/src/api/agent-admin-routes.ts +178 -0
  10. package/src/api/agent-lifecycle-routes.ts +129 -0
  11. package/src/api/agent-model.ts +143 -0
  12. package/src/api/agent-transfer-routes.ts +211 -0
  13. package/src/api/apps-routes.ts +210 -0
  14. package/src/api/auth-routes.ts +90 -0
  15. package/src/api/bsc-trade.ts +736 -0
  16. package/src/api/bug-report-routes.ts +161 -0
  17. package/src/api/character-routes.ts +421 -0
  18. package/src/api/cloud-billing-routes.ts +598 -0
  19. package/src/api/cloud-compat-routes.ts +192 -0
  20. package/src/api/cloud-routes.ts +529 -0
  21. package/src/api/cloud-status-routes.ts +234 -0
  22. package/src/api/compat-utils.ts +154 -0
  23. package/src/api/connector-health.ts +135 -0
  24. package/src/api/coordinator-wiring.ts +179 -0
  25. package/src/api/credit-detection.ts +47 -0
  26. package/src/api/database.ts +1357 -0
  27. package/src/api/diagnostics-routes.ts +389 -0
  28. package/src/api/drop-service.ts +205 -0
  29. package/src/api/early-logs.ts +111 -0
  30. package/src/api/http-helpers.ts +252 -0
  31. package/src/api/index.ts +85 -0
  32. package/src/api/knowledge-routes.ts +1189 -0
  33. package/src/api/knowledge-service-loader.ts +92 -0
  34. package/src/api/memory-bounds.ts +121 -0
  35. package/src/api/memory-routes.ts +349 -0
  36. package/src/api/merkle-tree.ts +239 -0
  37. package/src/api/models-routes.ts +72 -0
  38. package/src/api/nfa-routes.ts +169 -0
  39. package/src/api/nft-verify.ts +188 -0
  40. package/src/api/og-tracker.ts +72 -0
  41. package/src/api/parse-action-block.ts +145 -0
  42. package/src/api/permissions-routes.ts +222 -0
  43. package/src/api/plugin-validation.ts +355 -0
  44. package/src/api/provider-switch-config.ts +455 -0
  45. package/src/api/registry-routes.ts +165 -0
  46. package/src/api/registry-service.ts +292 -0
  47. package/src/api/route-helpers.ts +21 -0
  48. package/src/api/sandbox-routes.ts +1480 -0
  49. package/src/api/server.ts +17674 -0
  50. package/src/api/signal-routes.ts +265 -0
  51. package/src/api/stream-persistence.ts +297 -0
  52. package/src/api/stream-route-state.ts +48 -0
  53. package/src/api/stream-routes.ts +1046 -0
  54. package/src/api/stream-voice-routes.ts +208 -0
  55. package/src/api/streaming-text.ts +129 -0
  56. package/src/api/streaming-types.ts +23 -0
  57. package/src/api/subscription-routes.ts +283 -0
  58. package/src/api/terminal-run-limits.ts +31 -0
  59. package/src/api/training-backend-check.ts +40 -0
  60. package/src/api/training-routes.ts +314 -0
  61. package/src/api/training-service-like.ts +46 -0
  62. package/src/api/trajectory-routes.ts +714 -0
  63. package/src/api/trigger-routes.ts +438 -0
  64. package/src/api/twitter-verify.ts +226 -0
  65. package/src/api/tx-service.ts +193 -0
  66. package/src/api/wallet-dex-prices.ts +206 -0
  67. package/src/api/wallet-evm-balance.ts +989 -0
  68. package/src/api/wallet-routes.ts +505 -0
  69. package/src/api/wallet-rpc.ts +523 -0
  70. package/src/api/wallet-trading-profile.ts +694 -0
  71. package/src/api/wallet.ts +745 -0
  72. package/src/api/whatsapp-routes.ts +282 -0
  73. package/src/api/zip-utils.ts +130 -0
  74. package/src/auth/anthropic.ts +63 -0
  75. package/src/auth/apply-stealth.ts +38 -0
  76. package/src/auth/claude-code-stealth.ts +141 -0
  77. package/src/auth/credentials.ts +226 -0
  78. package/src/auth/index.ts +18 -0
  79. package/src/auth/openai-codex.ts +94 -0
  80. package/src/auth/types.ts +24 -0
  81. package/src/awareness/registry.ts +220 -0
  82. package/src/bin.ts +10 -0
  83. package/src/cli/index.ts +36 -0
  84. package/src/cli/parse-duration.ts +43 -0
  85. package/src/cloud/auth.test.ts +370 -0
  86. package/src/cloud/auth.ts +176 -0
  87. package/src/cloud/backup.test.ts +150 -0
  88. package/src/cloud/backup.ts +50 -0
  89. package/src/cloud/base-url.ts +45 -0
  90. package/src/cloud/bridge-client.test.ts +481 -0
  91. package/src/cloud/bridge-client.ts +307 -0
  92. package/src/cloud/cloud-manager.test.ts +223 -0
  93. package/src/cloud/cloud-manager.ts +151 -0
  94. package/src/cloud/cloud-proxy.test.ts +122 -0
  95. package/src/cloud/cloud-proxy.ts +52 -0
  96. package/src/cloud/index.ts +23 -0
  97. package/src/cloud/reconnect.test.ts +178 -0
  98. package/src/cloud/reconnect.ts +108 -0
  99. package/src/cloud/validate-url.test.ts +147 -0
  100. package/src/cloud/validate-url.ts +176 -0
  101. package/src/config/character-schema.ts +44 -0
  102. package/src/config/config.ts +149 -0
  103. package/src/config/env-vars.ts +86 -0
  104. package/src/config/includes.ts +196 -0
  105. package/src/config/index.ts +15 -0
  106. package/src/config/object-utils.ts +10 -0
  107. package/src/config/paths.ts +92 -0
  108. package/src/config/plugin-auto-enable.ts +520 -0
  109. package/src/config/schema.ts +1342 -0
  110. package/src/config/telegram-custom-commands.ts +99 -0
  111. package/src/config/types.agent-defaults.ts +342 -0
  112. package/src/config/types.agents.ts +112 -0
  113. package/src/config/types.gateway.ts +243 -0
  114. package/src/config/types.hooks.ts +124 -0
  115. package/src/config/types.messages.ts +201 -0
  116. package/src/config/types.milady.ts +791 -0
  117. package/src/config/types.tools.ts +416 -0
  118. package/src/config/types.ts +7 -0
  119. package/src/config/zod-schema.agent-runtime.ts +777 -0
  120. package/src/config/zod-schema.core.ts +778 -0
  121. package/src/config/zod-schema.hooks.ts +139 -0
  122. package/src/config/zod-schema.providers-core.ts +1126 -0
  123. package/src/config/zod-schema.session.ts +98 -0
  124. package/src/config/zod-schema.ts +865 -0
  125. package/src/contracts/apps.ts +46 -0
  126. package/src/contracts/awareness.ts +56 -0
  127. package/src/contracts/config.ts +172 -0
  128. package/src/contracts/drop.ts +21 -0
  129. package/src/contracts/index.ts +8 -0
  130. package/src/contracts/onboarding.ts +592 -0
  131. package/src/contracts/permissions.ts +52 -0
  132. package/src/contracts/verification.ts +9 -0
  133. package/src/contracts/wallet.ts +503 -0
  134. package/src/diagnostics/integration-observability.ts +132 -0
  135. package/src/emotes/catalog.ts +655 -0
  136. package/src/external-modules.d.ts +7 -0
  137. package/src/hooks/discovery.test.ts +357 -0
  138. package/src/hooks/discovery.ts +231 -0
  139. package/src/hooks/eligibility.ts +146 -0
  140. package/src/hooks/hooks.test.ts +320 -0
  141. package/src/hooks/index.ts +8 -0
  142. package/src/hooks/loader.test.ts +418 -0
  143. package/src/hooks/loader.ts +256 -0
  144. package/src/hooks/registry.test.ts +168 -0
  145. package/src/hooks/registry.ts +74 -0
  146. package/src/hooks/types.ts +121 -0
  147. package/src/index.ts +19 -0
  148. package/src/onboarding-presets.ts +828 -0
  149. package/src/plugins/custom-rtmp/index.ts +40 -0
  150. package/src/providers/admin-trust.ts +76 -0
  151. package/src/providers/session-bridge.ts +143 -0
  152. package/src/providers/session-utils.ts +42 -0
  153. package/src/providers/simple-mode.ts +113 -0
  154. package/src/providers/ui-catalog.ts +135 -0
  155. package/src/providers/workspace-provider.ts +213 -0
  156. package/src/providers/workspace.ts +497 -0
  157. package/src/runtime/agent-event-service.ts +57 -0
  158. package/src/runtime/cloud-onboarding.test.ts +489 -0
  159. package/src/runtime/cloud-onboarding.ts +408 -0
  160. package/src/runtime/core-plugins.ts +53 -0
  161. package/src/runtime/custom-actions.ts +605 -0
  162. package/src/runtime/eliza.ts +4941 -0
  163. package/src/runtime/embedding-presets.ts +73 -0
  164. package/src/runtime/index.ts +8 -0
  165. package/src/runtime/milady-plugin.ts +180 -0
  166. package/src/runtime/onboarding-names.ts +76 -0
  167. package/src/runtime/release-plugin-policy.ts +119 -0
  168. package/src/runtime/restart.ts +59 -0
  169. package/src/runtime/trajectory-persistence.ts +2584 -0
  170. package/src/runtime/version.ts +6 -0
  171. package/src/security/audit-log.ts +222 -0
  172. package/src/security/network-policy.ts +91 -0
  173. package/src/server/index.ts +6 -0
  174. package/src/services/agent-export.ts +976 -0
  175. package/src/services/app-manager.ts +755 -0
  176. package/src/services/browser-capture.ts +215 -0
  177. package/src/services/coding-agent-context.ts +355 -0
  178. package/src/services/fallback-training-service.ts +196 -0
  179. package/src/services/index.ts +17 -0
  180. package/src/services/mcp-marketplace.ts +327 -0
  181. package/src/services/plugin-manager-types.ts +185 -0
  182. package/src/services/privy-wallets.ts +352 -0
  183. package/src/services/registry-client-app-meta.ts +201 -0
  184. package/src/services/registry-client-endpoints.ts +253 -0
  185. package/src/services/registry-client-local.ts +485 -0
  186. package/src/services/registry-client-network.ts +173 -0
  187. package/src/services/registry-client-queries.ts +176 -0
  188. package/src/services/registry-client-types.ts +104 -0
  189. package/src/services/registry-client.ts +366 -0
  190. package/src/services/remote-signing-service.ts +261 -0
  191. package/src/services/sandbox-engine.ts +753 -0
  192. package/src/services/sandbox-manager.ts +503 -0
  193. package/src/services/self-updater.ts +213 -0
  194. package/src/services/signal-pairing.ts +189 -0
  195. package/src/services/signing-policy.ts +230 -0
  196. package/src/services/skill-catalog-client.ts +195 -0
  197. package/src/services/skill-marketplace.ts +909 -0
  198. package/src/services/stream-manager.ts +707 -0
  199. package/src/services/tts-stream-bridge.ts +465 -0
  200. package/src/services/update-checker.ts +163 -0
  201. package/src/services/version-compat.ts +367 -0
  202. package/src/services/whatsapp-pairing.ts +279 -0
  203. package/src/shared/ui-catalog-prompt.ts +1158 -0
  204. package/src/test-support/process-helpers.ts +35 -0
  205. package/src/test-support/route-test-helpers.ts +113 -0
  206. package/src/test-support/test-helpers.ts +304 -0
  207. package/src/testing/index.ts +3 -0
  208. package/src/triggers/action.ts +342 -0
  209. package/src/triggers/runtime.ts +432 -0
  210. package/src/triggers/scheduling.ts +472 -0
  211. package/src/triggers/types.ts +133 -0
  212. package/src/types/app-hyperscape-routes-shim.d.ts +29 -0
  213. package/src/types/external-modules.d.ts +7 -0
  214. package/src/utils/exec-safety.ts +23 -0
  215. package/src/utils/number-parsing.ts +112 -0
  216. package/src/utils/spoken-text.ts +65 -0
  217. package/src/version-resolver.ts +60 -0
  218. package/test/api/agent-admin-routes.test.ts +160 -0
  219. package/test/api/agent-lifecycle-routes.test.ts +164 -0
  220. package/test/api/agent-transfer-routes.test.ts +136 -0
  221. package/test/api/apps-routes.test.ts +140 -0
  222. package/test/api/auth-routes.test.ts +160 -0
  223. package/test/api/bug-report-routes.test.ts +88 -0
  224. package/test/api/knowledge-routes.test.ts +73 -0
  225. package/test/api/lifecycle.test.ts +342 -0
  226. package/test/api/memory-routes.test.ts +74 -0
  227. package/test/api/models-routes.test.ts +112 -0
  228. package/test/api/nfa-routes.test.ts +78 -0
  229. package/test/api/permissions-routes.test.ts +185 -0
  230. package/test/api/registry-routes.test.ts +157 -0
  231. package/test/api/signal-routes.test.ts +113 -0
  232. package/test/api/subscription-routes.test.ts +90 -0
  233. package/test/api/trigger-routes.test.ts +87 -0
  234. package/test/api/wallet-routes.observability.test.ts +191 -0
  235. package/test/api/wallet-routes.test.ts +502 -0
  236. package/test/diagnostics/integration-observability.test.ts +135 -0
  237. package/test/security/audit-log.test.ts +229 -0
  238. package/test/security/network-policy.test.ts +143 -0
  239. package/test/services/version-compat.test.ts +127 -0
  240. package/tsconfig.build.json +21 -0
  241. package/tsconfig.json +19 -0
@@ -0,0 +1,35 @@
1
+ import type { ChildProcess } from "node:child_process";
2
+ import { EventEmitter } from "node:events";
3
+
4
+ type MockSpawnOptions = {
5
+ exitCode: number;
6
+ stderrOutput?: string;
7
+ emitError?: Error;
8
+ };
9
+
10
+ /**
11
+ * Create a lightweight mocked ChildProcess that emits either an error event
12
+ * or a close event (with optional stderr output) on the next tick.
13
+ */
14
+ export function createMockChildProcess(
15
+ options: MockSpawnOptions,
16
+ ): ChildProcess {
17
+ const child = new EventEmitter() as ChildProcess;
18
+ const stderrEmitter = new EventEmitter();
19
+ Object.defineProperty(child, "stderr", { value: stderrEmitter });
20
+ Object.defineProperty(child, "stdin", { value: null });
21
+ Object.defineProperty(child, "stdout", { value: null });
22
+
23
+ process.nextTick(() => {
24
+ if (options.emitError) {
25
+ child.emit("error", options.emitError);
26
+ return;
27
+ }
28
+ if (options.stderrOutput) {
29
+ stderrEmitter.emit("data", Buffer.from(options.stderrOutput));
30
+ }
31
+ child.emit("close", options.exitCode);
32
+ });
33
+
34
+ return child;
35
+ }
@@ -0,0 +1,113 @@
1
+ import type { IncomingMessage, ServerResponse } from "node:http";
2
+ import { createMockHttpResponse } from "./test-helpers";
3
+
4
+ export type RouteBody = Record<string, unknown>;
5
+
6
+ export type RouteInvocationResult<TPayload = unknown> = {
7
+ handled: boolean;
8
+ status: number;
9
+ payload: TPayload;
10
+ };
11
+
12
+ export type RouteInvokeArgs<TBody = RouteBody, TRuntime = unknown> = {
13
+ method: string;
14
+ pathname: string;
15
+ url?: string;
16
+ body?: TBody | null;
17
+ runtimeOverride?: TRuntime;
18
+ headers?: { host?: string };
19
+ };
20
+
21
+ export type RouteRequestContext<TBody, TRuntime> = {
22
+ req: IncomingMessage;
23
+ res: ServerResponse;
24
+ method: string;
25
+ pathname: string;
26
+ runtime: TRuntime;
27
+ readJsonBody: () => Promise<TBody | null>;
28
+ json: (_res: ServerResponse, data: unknown, status?: number) => void;
29
+ error: (_res: ServerResponse, message: string, status?: number) => void;
30
+ };
31
+
32
+ type RouteInvokerOptions<TRuntime = unknown> =
33
+ | {
34
+ runtime: TRuntime;
35
+ runtimeProvider?: undefined;
36
+ }
37
+ | {
38
+ runtime?: undefined;
39
+ runtimeProvider: () => TRuntime;
40
+ };
41
+
42
+ export function createRouteInvoker<
43
+ TBody = RouteBody,
44
+ TRuntime = unknown,
45
+ TPayload = unknown,
46
+ >(
47
+ handler: (ctx: RouteRequestContext<TBody, TRuntime>) => Promise<boolean>,
48
+ options: RouteInvokerOptions<TRuntime>,
49
+ ): (
50
+ args: RouteInvokeArgs<TBody, TRuntime>,
51
+ ) => Promise<RouteInvocationResult<TPayload>> {
52
+ return async (args) => {
53
+ const capturedRuntime =
54
+ options.runtimeProvider === undefined
55
+ ? options.runtime
56
+ : options.runtimeProvider();
57
+
58
+ const status = 200;
59
+ const payload = {} as TPayload;
60
+
61
+ const response = {
62
+ hasPayload: false,
63
+ status,
64
+ payload,
65
+ };
66
+
67
+ const { res, getStatus, getJson } = createMockHttpResponse<TPayload>();
68
+
69
+ const req = {
70
+ url: args.url ?? args.pathname,
71
+ headers: { host: args.headers?.host ?? "localhost:2138" },
72
+ } as IncomingMessage;
73
+
74
+ const runtime =
75
+ args.runtimeOverride === undefined
76
+ ? capturedRuntime
77
+ : args.runtimeOverride;
78
+
79
+ const handled = await handler({
80
+ req,
81
+ res,
82
+ method: args.method,
83
+ pathname: args.pathname,
84
+ runtime: runtime as TRuntime,
85
+ readJsonBody: async () => {
86
+ const body = args.body ?? null;
87
+ return (body as TBody | null) ?? null;
88
+ },
89
+ json: (_response, data, status = 200) => {
90
+ response.hasPayload = true;
91
+ response.status = status;
92
+ response.payload = data as TPayload;
93
+ },
94
+ error: (_response, message, status = 400) => {
95
+ response.hasPayload = true;
96
+ response.status = status;
97
+ response.payload = { error: message } as TPayload;
98
+ },
99
+ });
100
+
101
+ if (!response.hasPayload) {
102
+ response.status = getStatus();
103
+ response.payload = getJson();
104
+ response.hasPayload = true;
105
+ }
106
+
107
+ return {
108
+ handled,
109
+ status: response.status,
110
+ payload: response.payload,
111
+ };
112
+ };
113
+ }
@@ -0,0 +1,304 @@
1
+ import { EventEmitter } from "node:events";
2
+ import { existsSync } from "node:fs";
3
+ import type http from "node:http";
4
+ import { createRequire } from "node:module";
5
+ import path from "node:path";
6
+ import { fileURLToPath, pathToFileURL } from "node:url";
7
+ import { vi } from "vitest";
8
+
9
+ /**
10
+ * Test helper utilities shared across unit tests.
11
+ */
12
+
13
+ const OPTIONAL_IMPORT_ERROR_MARKERS = [
14
+ "Cannot find module",
15
+ "Cannot find package",
16
+ "ERR_MODULE_NOT_FOUND",
17
+ "MODULE_NOT_FOUND",
18
+ "Dynamic require of",
19
+ "native addon module",
20
+ "Failed to resolve entry",
21
+ "tfjs_binding",
22
+ "NAPI_MODULE_NOT_FOUND",
23
+ "spec not found",
24
+ ];
25
+
26
+ /** Standardized test result for mocked updater checks. */
27
+ export type MockUpdateCheckResult = {
28
+ updateAvailable: boolean;
29
+ currentVersion: string;
30
+ latestVersion: string | null;
31
+ channel: string;
32
+ distTag: string;
33
+ cached: boolean;
34
+ error: string | null;
35
+ };
36
+
37
+ /** Snapshot and restore the configured environment variables around a test. */
38
+ export function createEnvSandbox(keys: readonly string[]) {
39
+ const backup: Record<string, string | undefined> = {};
40
+
41
+ function clear(): void {
42
+ for (const key of keys) {
43
+ backup[key] = process.env[key];
44
+ delete process.env[key];
45
+ }
46
+ }
47
+
48
+ function restore(): void {
49
+ for (const key of keys) {
50
+ if (backup[key] === undefined) {
51
+ delete process.env[key];
52
+ } else {
53
+ process.env[key] = backup[key];
54
+ }
55
+ }
56
+ }
57
+
58
+ return { clear, restore };
59
+ }
60
+
61
+ export type PluginModuleShape = {
62
+ [key: string]: unknown;
63
+ default?: unknown;
64
+ plugin?: unknown;
65
+ };
66
+
67
+ /** Loose plugin-shape predicate used in dynamic test imports across suites. */
68
+ export function looksLikePlugin(value: unknown): value is { name: string } {
69
+ return (
70
+ value != null &&
71
+ typeof value === "object" &&
72
+ typeof (value as Record<string, unknown>).name === "string"
73
+ );
74
+ }
75
+
76
+ /** Extract a plugin-like object from a dynamic module export shape. */
77
+ export function extractPlugin(mod: PluginModuleShape): { name: string } | null {
78
+ if (looksLikePlugin(mod.default)) return mod.default;
79
+ if (looksLikePlugin(mod.plugin)) return mod.plugin;
80
+ if (looksLikePlugin(mod)) return mod;
81
+ for (const key of Object.keys(mod)) {
82
+ if (key === "default" || key === "plugin") continue;
83
+ if (looksLikePlugin(mod[key])) return mod[key] as { name: string };
84
+ }
85
+ return null;
86
+ }
87
+
88
+ /** Check whether a package name can be resolved for dynamic import. */
89
+ export function isPackageImportResolvable(packageName: string): boolean {
90
+ const require = createRequire(import.meta.url);
91
+ try {
92
+ require.resolve(packageName);
93
+ return true;
94
+ } catch {
95
+ return false;
96
+ }
97
+ }
98
+
99
+ /** Check whether a dependency specifier should be treated as a workspace-local version. */
100
+ export function isWorkspaceDependency(version: string | undefined): boolean {
101
+ return (
102
+ typeof version === "string" &&
103
+ (version.startsWith(".") || version.startsWith("workspace:"))
104
+ );
105
+ }
106
+
107
+ const DISCORD_PLUGIN_PACKAGE_NAME = "@elizaos/plugin-discord";
108
+ const DISCORD_PLUGIN_LOCAL_ENTRY_CANDIDATES = [
109
+ "../plugins/plugin-discord/typescript/dist/index",
110
+ "../plugins/plugin-discord/dist/index",
111
+ ] as const;
112
+
113
+ /**
114
+ * Resolve the Discord plugin import specifier.
115
+ * Prefers package resolution, then falls back to local plugin checkout paths.
116
+ */
117
+ export function resolveDiscordPluginImportSpecifier(): string | null {
118
+ if (isPackageImportResolvable(DISCORD_PLUGIN_PACKAGE_NAME)) {
119
+ return DISCORD_PLUGIN_PACKAGE_NAME;
120
+ }
121
+
122
+ const helperDir = path.dirname(fileURLToPath(import.meta.url));
123
+ const packageRoot = path.resolve(helperDir, "..", "..");
124
+
125
+ for (const relativeEntryPath of DISCORD_PLUGIN_LOCAL_ENTRY_CANDIDATES) {
126
+ const absoluteEntryPath = path.resolve(packageRoot, relativeEntryPath);
127
+ if (existsSync(absoluteEntryPath)) {
128
+ return pathToFileURL(absoluteEntryPath).href;
129
+ }
130
+ }
131
+
132
+ return null;
133
+ }
134
+
135
+ /** Build a mock update check result with deterministic defaults. */
136
+ export function buildMockUpdateCheckResult(
137
+ overrides: Partial<MockUpdateCheckResult> = {},
138
+ ): MockUpdateCheckResult {
139
+ return {
140
+ updateAvailable: false,
141
+ currentVersion: "2.0.0",
142
+ latestVersion: "2.0.0",
143
+ channel: "stable",
144
+ distTag: "latest",
145
+ cached: false,
146
+ error: null,
147
+ ...overrides,
148
+ };
149
+ }
150
+
151
+ /** Small utility to wait for asynchronous side-effects in tests. */
152
+ export function waitMs(ms: number): Promise<void> {
153
+ return new Promise((resolve) => setTimeout(resolve, ms));
154
+ }
155
+
156
+ type MockResponsePayload<T> = {
157
+ res: http.ServerResponse & {
158
+ _status: number;
159
+ _body: string;
160
+ writeHead: (statusCode: number) => void;
161
+ };
162
+ getStatus: () => number;
163
+ getJson: () => T;
164
+ };
165
+
166
+ type MockBodyChunk = string | Buffer;
167
+
168
+ export type MockRequestOptions = {
169
+ method?: string;
170
+ url?: string;
171
+ headers?: Record<string, string>;
172
+ body?: unknown;
173
+ bodyChunks?: MockBodyChunk[];
174
+ json?: boolean;
175
+ };
176
+
177
+ /** Create a lightweight mocked HTTP response used by handler tests. */
178
+ export function createMockHttpResponse<T = unknown>(): MockResponsePayload<T> {
179
+ let statusCode = 200;
180
+ let legacyStatus = 0;
181
+ let payload = "";
182
+
183
+ const res = {
184
+ set statusCode(value: number) {
185
+ statusCode = value;
186
+ legacyStatus = value;
187
+ },
188
+ get statusCode() {
189
+ return statusCode;
190
+ },
191
+ _status: legacyStatus,
192
+ _body: payload,
193
+ setHeader: () => undefined,
194
+ writeHead: (value: number) => {
195
+ statusCode = value;
196
+ legacyStatus = value;
197
+ },
198
+ end: (chunk?: string | Buffer) => {
199
+ payload = chunk ? chunk.toString() : "";
200
+ res._body = payload;
201
+ legacyStatus = statusCode;
202
+ res._status = legacyStatus;
203
+ },
204
+ } as unknown as http.ServerResponse & {
205
+ _status: number;
206
+ _body: string;
207
+ writeHead: (statusCode: number) => void;
208
+ };
209
+
210
+ return {
211
+ res,
212
+ getStatus: () => statusCode,
213
+ getJson: () => (payload ? (JSON.parse(payload) as T) : (null as T)),
214
+ };
215
+ }
216
+
217
+ export function createMockHeadersRequest(
218
+ headers: Record<string, string> = {},
219
+ options: Omit<MockRequestOptions, "headers" | "body"> = {},
220
+ ): http.IncomingMessage & { destroy: () => void } {
221
+ return createMockIncomingMessage({
222
+ ...options,
223
+ headers,
224
+ });
225
+ }
226
+
227
+ export function createMockIncomingMessage({
228
+ method = "GET",
229
+ url = "/",
230
+ headers = { host: "localhost:2138" },
231
+ body,
232
+ bodyChunks,
233
+ json = false,
234
+ }: MockRequestOptions): http.IncomingMessage & { destroy: () => void } {
235
+ const req = new EventEmitter() as http.IncomingMessage &
236
+ EventEmitter & { destroy: () => void };
237
+
238
+ req.method = method;
239
+ req.url = url;
240
+ req.headers = headers;
241
+ req.destroy = vi.fn();
242
+
243
+ const chunks: Buffer[] = [];
244
+
245
+ if (bodyChunks !== undefined) {
246
+ for (const chunk of bodyChunks) {
247
+ chunks.push(
248
+ typeof chunk === "string" ? Buffer.from(chunk, "utf-8") : chunk,
249
+ );
250
+ }
251
+ } else if (body !== undefined) {
252
+ const encoded =
253
+ typeof body === "string"
254
+ ? Buffer.from(body, "utf-8")
255
+ : body instanceof Buffer
256
+ ? body
257
+ : json
258
+ ? Buffer.from(JSON.stringify(body), "utf-8")
259
+ : Buffer.from(String(body), "utf-8");
260
+ chunks.push(encoded);
261
+ }
262
+
263
+ for (const chunk of chunks) {
264
+ queueMicrotask(() => req.emit("data", chunk));
265
+ }
266
+ queueMicrotask(() => req.emit("end"));
267
+
268
+ return req;
269
+ }
270
+
271
+ export function createMockJsonRequest(
272
+ body: unknown,
273
+ options: Omit<MockRequestOptions, "body" | "json"> = {},
274
+ ): http.IncomingMessage & { destroy: () => void } {
275
+ return createMockIncomingMessage({
276
+ ...options,
277
+ body,
278
+ json: true,
279
+ });
280
+ }
281
+
282
+ /** Return true when optional plugin imports are intentionally unavailable in this env. */
283
+ export function isOptionalImportError(
284
+ error: unknown,
285
+ extraMarkers: readonly string[] = [],
286
+ ): boolean {
287
+ const message = error instanceof Error ? error.message : String(error);
288
+ return OPTIONAL_IMPORT_ERROR_MARKERS.concat(extraMarkers).some((marker) =>
289
+ message.includes(marker),
290
+ );
291
+ }
292
+
293
+ /** Safely import optional plugin modules while allowing hard failures to bubble. */
294
+ export async function tryOptionalDynamicImport<T>(
295
+ moduleName: string,
296
+ markers?: readonly string[],
297
+ ): Promise<T | null> {
298
+ try {
299
+ return (await import(moduleName)) as T;
300
+ } catch (error) {
301
+ if (isOptionalImportError(error, markers)) return null;
302
+ throw error;
303
+ }
304
+ }
@@ -0,0 +1,3 @@
1
+ export * from "../test-support/process-helpers";
2
+ export * from "../test-support/route-test-helpers";
3
+ export * from "../test-support/test-helpers";