@teamscala/service-boot 0.23.512 → 0.23.514
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/capability-slug.test.ts +14 -15
- package/src/capability-slug.ts +18 -11
- package/src/mount-orpc-router.test.ts +10 -3
- package/src/mount-orpc-router.ts +7 -8
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.514"
|
|
1192
1191
|
}
|
|
@@ -1,31 +1,30 @@
|
|
|
1
|
-
// @system codegen
|
|
2
|
-
// @status generated
|
|
3
|
-
// @edit change the suite in the owned-suites band, then re-run codegen. Hand-edits are overwritten.
|
|
4
|
-
//
|
|
5
|
-
// This suite's assertions are OWNED by the codegen band: the band module
|
|
6
|
-
// carries them verbatim, this file is the emission, and hand edits here are
|
|
7
|
-
// overwritten on the next run. The rationale each assertion carries moved
|
|
8
|
-
// with it into the band.
|
|
9
|
-
|
|
10
1
|
import { describe, expect, test } from "bun:test";
|
|
11
2
|
import { toCapabilitySlug } from "./capability-slug.ts";
|
|
12
3
|
|
|
13
4
|
describe("toCapabilitySlug", () => {
|
|
14
5
|
test("strips the language+tier suffix from a dev deployable", () => {
|
|
15
|
-
expect(toCapabilitySlug("scala-projects-
|
|
16
|
-
expect(toCapabilitySlug("scala-ai-
|
|
6
|
+
expect(toCapabilitySlug("scala-projects-ts-dev")).toBe("scala-projects");
|
|
7
|
+
expect(toCapabilitySlug("scala-ai-ts-dev")).toBe("scala-ai");
|
|
17
8
|
expect(toCapabilitySlug("scala-image-optimizer-rust-dev")).toBe(
|
|
18
9
|
"scala-image-optimizer",
|
|
19
10
|
);
|
|
20
11
|
});
|
|
21
12
|
|
|
22
13
|
test("strips the language+tier suffix from a prod deployable", () => {
|
|
23
|
-
expect(toCapabilitySlug("scala-projects-
|
|
14
|
+
expect(toCapabilitySlug("scala-projects-ts-prod")).toBe("scala-projects");
|
|
24
15
|
expect(toCapabilitySlug("scala-messaging-service-rust-prod")).toBe(
|
|
25
16
|
"scala-messaging-service",
|
|
26
17
|
);
|
|
27
18
|
});
|
|
28
19
|
|
|
20
|
+
test("strips the retired bun spelling to the same capability", () => {
|
|
21
|
+
// The fleet was renamed under -bun before the operator ruling of
|
|
22
|
+
// 2026-09-08 fixed the language segment at ts; rows or supervised
|
|
23
|
+
// names still carrying it converge rather than fail the join.
|
|
24
|
+
expect(toCapabilitySlug("scala-projects-bun-dev")).toBe("scala-projects");
|
|
25
|
+
expect(toCapabilitySlug("scala-ai-bun-prod")).toBe("scala-ai");
|
|
26
|
+
});
|
|
27
|
+
|
|
29
28
|
test("returns an already-capability slug unchanged", () => {
|
|
30
29
|
// The prod lane is still bare while the tier migration is in flight, so
|
|
31
30
|
// the SAME function must be correct before and after the rename lands.
|
|
@@ -35,11 +34,11 @@ describe("toCapabilitySlug", () => {
|
|
|
35
34
|
|
|
36
35
|
test("both lanes of one application normalize to the same identity", () => {
|
|
37
36
|
// This is the property the page_route join depends on.
|
|
38
|
-
expect(toCapabilitySlug("scala-projects-
|
|
37
|
+
expect(toCapabilitySlug("scala-projects-ts-dev")).toBe(
|
|
39
38
|
toCapabilitySlug("scala-projects"),
|
|
40
39
|
);
|
|
41
|
-
expect(toCapabilitySlug("scala-quiz-
|
|
42
|
-
toCapabilitySlug("scala-quiz-
|
|
40
|
+
expect(toCapabilitySlug("scala-quiz-ts-dev")).toBe(
|
|
41
|
+
toCapabilitySlug("scala-quiz-ts-prod"),
|
|
43
42
|
);
|
|
44
43
|
});
|
|
45
44
|
|
package/src/capability-slug.ts
CHANGED
|
@@ -6,10 +6,12 @@
|
|
|
6
6
|
* Deployable slug -> capability slug.
|
|
7
7
|
*
|
|
8
8
|
* A DEPLOYABLE is named `<capability>-<language>-<tier>`
|
|
9
|
-
* (`deployables-carry-language-and-tier
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
9
|
+
* (`deployables-carry-language-and-tier`, as amended by the operator ruling of
|
|
10
|
+
* 2026-09-08: "so actually the apps are ts, not bun" — the language segment
|
|
11
|
+
* spells the LANGUAGE, so Bun-launched services are `ts`): `scala-projects-ts-dev`
|
|
12
|
+
* and `scala-projects-ts-prod` are two DEPLOYMENTS of one APPLICATION. The
|
|
13
|
+
* ecosystem generator derives that name per lane, so one service arrives here
|
|
14
|
+
* under a DIFFERENT identity in each lane.
|
|
13
15
|
*
|
|
14
16
|
* A `page_route` row describes the APPLICATION url space, which is the same
|
|
15
17
|
* in both lanes, so it carries the CAPABILITY name and there is exactly one
|
|
@@ -26,13 +28,17 @@
|
|
|
26
28
|
* The suffix grammar is a CLOSED SET defined by doctrine and emitted by the
|
|
27
29
|
* generator, so this is a parse of a documented contract rather than a
|
|
28
30
|
* pattern heuristic. A slug that does not end in one is already a capability
|
|
29
|
-
* name and is returned unchanged
|
|
30
|
-
*
|
|
31
|
-
*
|
|
31
|
+
* name and is returned unchanged.
|
|
32
|
+
*
|
|
33
|
+
* `bun` REMAINS IN THE SET AS RETIRED SPELLING TOLERANCE, mirroring the
|
|
34
|
+
* generator side (`ecosystem/deployable_identity.rs capability_of` strips
|
|
35
|
+
* `-ts`, `-bun` and `-rust`): the fleet was renamed under `-bun` and rows or
|
|
36
|
+
* supervised names still carrying it must converge to the same capability
|
|
37
|
+
* rather than fail the join during the migration window.
|
|
32
38
|
*/
|
|
33
39
|
|
|
34
|
-
/** Language segment of a deployable name. */
|
|
35
|
-
const LANGUAGES = ["bun", "rust"] as const;
|
|
40
|
+
/** Language segment of a deployable name. `bun` is the retired spelling. */
|
|
41
|
+
const LANGUAGES = ["ts", "bun", "rust"] as const;
|
|
36
42
|
|
|
37
43
|
/** Tier segment of a deployable name. */
|
|
38
44
|
const TIERS = ["dev", "prod"] as const;
|
|
@@ -43,8 +49,9 @@ type Tier = (typeof TIERS)[number];
|
|
|
43
49
|
/**
|
|
44
50
|
* The capability half of a deployable slug.
|
|
45
51
|
*
|
|
46
|
-
* `scala-projects-
|
|
47
|
-
* `scala-projects-
|
|
52
|
+
* `scala-projects-ts-dev` -> `scala-projects`
|
|
53
|
+
* `scala-projects-ts-prod` -> `scala-projects`
|
|
54
|
+
* `scala-projects-bun-dev` -> `scala-projects` (retired spelling)
|
|
48
55
|
* `scala-projects` -> `scala-projects` (already a capability name)
|
|
49
56
|
*/
|
|
50
57
|
export function toCapabilitySlug(slug: string): string {
|
|
@@ -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
|
});
|