@teamscala/service-boot 0.23.511 → 0.23.513
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/package.json +14 -15
- package/src/mount-orpc-router.test.ts +10 -3
- package/src/mount-orpc-router.ts +7 -8
- package/src/pg-boss-mount.test.ts +4 -3
- package/src/pg-boss-mount.ts +10 -4
package/package.json
CHANGED
|
@@ -5,14 +5,14 @@
|
|
|
5
5
|
"edit": "edit src/ — dependencies and exports derive from imports; everything else preserved"
|
|
6
6
|
},
|
|
7
7
|
"dependencies": {
|
|
8
|
-
"@orpc/server": "1.15.
|
|
8
|
+
"@orpc/server": "1.15.1",
|
|
9
9
|
"@teamscala/agreement-generation": "1.0.17",
|
|
10
|
-
"@teamscala/assessment": "0.0.
|
|
11
|
-
"@teamscala/auth": "1.102.
|
|
10
|
+
"@teamscala/assessment": "0.0.22",
|
|
11
|
+
"@teamscala/auth": "1.102.11",
|
|
12
12
|
"@teamscala/cache": "1.0.79",
|
|
13
|
-
"@teamscala/chat-completion": "0.0.
|
|
14
|
-
"@teamscala/db": "1.21.
|
|
15
|
-
"@teamscala/db-validation": "0.1.
|
|
13
|
+
"@teamscala/chat-completion": "0.0.469",
|
|
14
|
+
"@teamscala/db": "1.21.43752",
|
|
15
|
+
"@teamscala/db-validation": "0.1.344",
|
|
16
16
|
"@teamscala/document-signing": "1.0.5",
|
|
17
17
|
"@teamscala/email-client": "0.1.4",
|
|
18
18
|
"@teamscala/encryption": "0.3.98",
|
|
@@ -21,25 +21,24 @@
|
|
|
21
21
|
"@teamscala/formatters": "0.2.95",
|
|
22
22
|
"@teamscala/generic-registry": "1.0.12",
|
|
23
23
|
"@teamscala/hono-boundary": "0.0.1",
|
|
24
|
-
"@teamscala/host-command-bus": "0.1.1",
|
|
25
24
|
"@teamscala/http": "2.1.105",
|
|
26
25
|
"@teamscala/logger": "1.1.203",
|
|
27
26
|
"@teamscala/mcp-multi-session": "1.3.147",
|
|
28
27
|
"@teamscala/object-storage": "1.2.201",
|
|
29
28
|
"@teamscala/orpc": "2.6.118",
|
|
30
|
-
"@teamscala/os": "1.15.
|
|
29
|
+
"@teamscala/os": "1.15.264",
|
|
31
30
|
"@teamscala/publish-registry": "0.1.3",
|
|
32
|
-
"@teamscala/resolver-engine": "1.1.
|
|
31
|
+
"@teamscala/resolver-engine": "1.1.208",
|
|
33
32
|
"@teamscala/timing": "1.0.51",
|
|
34
|
-
"@teamscala/tool-executor": "4.1.
|
|
33
|
+
"@teamscala/tool-executor": "4.1.166",
|
|
35
34
|
"@teamscala/watchdog": "1.0.53",
|
|
36
|
-
"hono": "4.13.
|
|
37
|
-
"pg-boss": "12.
|
|
35
|
+
"hono": "4.13.8",
|
|
36
|
+
"pg-boss": "12.33.1",
|
|
38
37
|
"tailwindcss": "4.3.3",
|
|
39
|
-
"valibot": "1.
|
|
38
|
+
"valibot": "1.5.0"
|
|
40
39
|
},
|
|
41
40
|
"devDependencies": {
|
|
42
|
-
"@happy-dom/global-registrator": "20.14.
|
|
41
|
+
"@happy-dom/global-registrator": "20.14.5",
|
|
43
42
|
"@testing-library/react": "16.3.3",
|
|
44
43
|
"bun-types": "1.4.2"
|
|
45
44
|
},
|
|
@@ -1188,5 +1187,5 @@
|
|
|
1188
1187
|
"repository": "https://github.com/teamgbg/service-boot",
|
|
1189
1188
|
"sideEffects": false,
|
|
1190
1189
|
"type": "module",
|
|
1191
|
-
"version": "0.23.
|
|
1190
|
+
"version": "0.23.513"
|
|
1192
1191
|
}
|
|
@@ -43,11 +43,15 @@ describe("mountOrpcRouter generated-artifact seam", () => {
|
|
|
43
43
|
);
|
|
44
44
|
});
|
|
45
45
|
|
|
46
|
-
test("the
|
|
46
|
+
test("the mount injects only the live collaborators — the retired injections stay retired", async () => {
|
|
47
47
|
// The retired MCP_GATEWAY_URL env name and its injector are gone: the
|
|
48
48
|
// sdk-mcp-forwarder resolves the SDK execution host from the
|
|
49
49
|
// mcp_server/scala-mcp registry row via loadRegistryConfig. A missing
|
|
50
50
|
// row refuses at the boundary (assertSdkHostResolved), never via env.
|
|
51
|
+
// The @teamscala/host-command-bus invoker injection retired with the
|
|
52
|
+
// bus (2026-09-19): the mount passes caller identity + secret
|
|
53
|
+
// decryption only, and host_command tools execute through the native
|
|
54
|
+
// in-process coding path inside tool-executor.
|
|
51
55
|
const service = await mkdtemp(join(tmpdir(), "mount-orpc-router-test-"));
|
|
52
56
|
tempDirs.push(service);
|
|
53
57
|
await mkdir(join(service, "prisma/generated/orpc/routers"), {
|
|
@@ -64,8 +68,8 @@ describe("mountOrpcRouter generated-artifact seam", () => {
|
|
|
64
68
|
process.chdir(service);
|
|
65
69
|
|
|
66
70
|
// Stub the collaborators the mount reaches BEFORE configureToolExecutor
|
|
67
|
-
// — the point is to capture the opts object and assert the
|
|
68
|
-
// absent.
|
|
71
|
+
// — the point is to capture the opts object and assert the retired
|
|
72
|
+
// injectors are absent.
|
|
69
73
|
let seenKeys: Array<string> = [];
|
|
70
74
|
mock.module("@teamscala/orpc/app-router", () => ({
|
|
71
75
|
getAppRouter: async () => ({
|
|
@@ -85,6 +89,9 @@ describe("mountOrpcRouter generated-artifact seam", () => {
|
|
|
85
89
|
await mountOrpcRouter(app as never, "scala-mcp");
|
|
86
90
|
|
|
87
91
|
expect(seenKeys).not.toContain("getMcpGatewayUrl");
|
|
92
|
+
expect(seenKeys).not.toContain("createHostCommandInvoker");
|
|
93
|
+
expect(seenKeys).toContain("getCallerContext");
|
|
94
|
+
expect(seenKeys).toContain("decryptSecretConfig");
|
|
88
95
|
});
|
|
89
96
|
});
|
|
90
97
|
|
package/src/mount-orpc-router.ts
CHANGED
|
@@ -165,22 +165,21 @@ export async function mountOrpcRouter(
|
|
|
165
165
|
const { configure: configureToolExecutor } = await import(
|
|
166
166
|
"@teamscala/tool-executor/configure"
|
|
167
167
|
);
|
|
168
|
-
// The
|
|
169
|
-
// tool-executor cannot import its tier-2 siblings statically
|
|
168
|
+
// The caller-identity and secret collaborators arrive here (the boot
|
|
169
|
+
// layer) — tool-executor cannot import its tier-2 siblings statically
|
|
170
170
|
// (vertical-dependency-only: a same-tier edge). Resolved eagerly at
|
|
171
|
-
// mount so the injected factories stay synchronous
|
|
172
|
-
//
|
|
173
|
-
//
|
|
174
|
-
|
|
171
|
+
// mount so the injected factories stay synchronous. The retired
|
|
172
|
+
// @teamscala/host-command-bus invoker injection no longer happens: the
|
|
173
|
+
// bus is retired, and host_command tools execute through the native
|
|
174
|
+
// in-process coding path inside tool-executor.
|
|
175
|
+
const [{ getCallerContext }, { decryptSecretConfig }] =
|
|
175
176
|
await Promise.all([
|
|
176
|
-
import("@teamscala/host-command-bus/invoker"),
|
|
177
177
|
import("@teamscala/mcp-multi-session/caller-context"),
|
|
178
178
|
import("@teamscala/encryption/crypto/secret-config"),
|
|
179
179
|
]);
|
|
180
180
|
configureToolExecutor({
|
|
181
181
|
getAppRouter: () => getAppRouter(),
|
|
182
182
|
getPrisma: () => getConfiguredPrisma(),
|
|
183
|
-
createHostCommandInvoker: (config) => createHostCommandInvoker(config as never),
|
|
184
183
|
getCallerContext: () => getCallerContext(),
|
|
185
184
|
decryptSecretConfig: (raw) => decryptSecretConfig(raw as never),
|
|
186
185
|
});
|
|
@@ -82,7 +82,8 @@ describe("mountPgBoss poll-only contract", () => {
|
|
|
82
82
|
packages: ["@teamscala/sync-worker"],
|
|
83
83
|
});
|
|
84
84
|
|
|
85
|
-
const
|
|
85
|
+
const capturedOpts = captured as unknown as CapturedOpts | undefined;
|
|
86
|
+
const connectionString = capturedOpts?.connectionString ?? "";
|
|
86
87
|
// The transaction pooler, exactly as injected — the mount adds no
|
|
87
88
|
// endpoint derivation.
|
|
88
89
|
expect(connectionString).toContain(":6543");
|
|
@@ -93,8 +94,8 @@ describe("mountPgBoss poll-only contract", () => {
|
|
|
93
94
|
// The pg sslmode dialect rewrite still applies.
|
|
94
95
|
expect(connectionString).toContain("sslmode=no-verify");
|
|
95
96
|
// Poll-only, spelled: no LISTEN dependency, now and after a bump.
|
|
96
|
-
expect(
|
|
97
|
+
expect(capturedOpts?.useListenNotify).toBe(false);
|
|
97
98
|
// pg-boss stays a single sibling connection (pool sizing doctrine).
|
|
98
|
-
expect(
|
|
99
|
+
expect(capturedOpts?.max).toBe(1);
|
|
99
100
|
});
|
|
100
101
|
});
|
package/src/pg-boss-mount.ts
CHANGED
|
@@ -196,10 +196,15 @@ export async function mountPgBoss(
|
|
|
196
196
|
// unavailable" (logged + event-log row), NEVER a boot-crash. A bare
|
|
197
197
|
// pg-boss assert reaching boot is the violation.
|
|
198
198
|
let config: ScheduledJobConfig;
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
199
|
+
// validateRow returns a RESULT WRAPPER ({ok:true,value}|{ok:false,issues}),
|
|
200
|
+
// never the config itself — measured 2026-09-16: assigning the wrapper as
|
|
201
|
+
// the config left queue_name/handler_slug undefined and silently skipped
|
|
202
|
+
// EVERY row on services holding db-validation 0.1.289+.
|
|
203
|
+
const validated = validateRow("scheduled_job", entry.config);
|
|
204
|
+
if (!validated.ok) {
|
|
205
|
+
const reason = validated.issues
|
|
206
|
+
.map((i) => `${String(i.path?.map((p) => String(p.key)).join(".") ?? "")}: ${i.message}`)
|
|
207
|
+
.join("; ");
|
|
203
208
|
log.error(
|
|
204
209
|
`[pg-boss-mount:${ctx.serviceSlug}] scheduled_job "${entry.slug}" failed schema validation — skipping`,
|
|
205
210
|
{ reason },
|
|
@@ -210,6 +215,7 @@ export async function mountPgBoss(
|
|
|
210
215
|
});
|
|
211
216
|
continue;
|
|
212
217
|
}
|
|
218
|
+
config = validated.value as ScheduledJobConfig;
|
|
213
219
|
if (!config.queue_name || !config.handler_slug) {
|
|
214
220
|
log.error(
|
|
215
221
|
`[pg-boss-mount:${ctx.serviceSlug}] scheduled_job "${entry.slug}" missing queue_name or handler_slug — skipping`,
|