@brainpilot/backend-core 0.0.1

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 (45) hide show
  1. package/dist/app.d.ts +31 -0
  2. package/dist/app.d.ts.map +1 -0
  3. package/dist/app.js +197 -0
  4. package/dist/app.js.map +1 -0
  5. package/dist/config.d.ts +46 -0
  6. package/dist/config.d.ts.map +1 -0
  7. package/dist/config.js +161 -0
  8. package/dist/config.js.map +1 -0
  9. package/dist/create-orchestrator.d.ts +17 -0
  10. package/dist/create-orchestrator.d.ts.map +1 -0
  11. package/dist/create-orchestrator.js +35 -0
  12. package/dist/create-orchestrator.js.map +1 -0
  13. package/dist/docker-orchestrator.d.ts +75 -0
  14. package/dist/docker-orchestrator.d.ts.map +1 -0
  15. package/dist/docker-orchestrator.js +159 -0
  16. package/dist/docker-orchestrator.js.map +1 -0
  17. package/dist/index.d.ts +27 -0
  18. package/dist/index.d.ts.map +1 -0
  19. package/dist/index.js +17 -0
  20. package/dist/index.js.map +1 -0
  21. package/dist/local-orchestrator.d.ts +74 -0
  22. package/dist/local-orchestrator.d.ts.map +1 -0
  23. package/dist/local-orchestrator.js +225 -0
  24. package/dist/local-orchestrator.js.map +1 -0
  25. package/dist/orchestrator.d.ts +51 -0
  26. package/dist/orchestrator.d.ts.map +1 -0
  27. package/dist/orchestrator.js +39 -0
  28. package/dist/orchestrator.js.map +1 -0
  29. package/dist/runtime-client.d.ts +54 -0
  30. package/dist/runtime-client.d.ts.map +1 -0
  31. package/dist/runtime-client.js +67 -0
  32. package/dist/runtime-client.js.map +1 -0
  33. package/dist/runtime-paths.d.ts +8 -0
  34. package/dist/runtime-paths.d.ts.map +1 -0
  35. package/dist/runtime-paths.js +10 -0
  36. package/dist/runtime-paths.js.map +1 -0
  37. package/dist/server.d.ts +25 -0
  38. package/dist/server.d.ts.map +1 -0
  39. package/dist/server.js +54 -0
  40. package/dist/server.js.map +1 -0
  41. package/dist/static-orchestrator.d.ts +37 -0
  42. package/dist/static-orchestrator.d.ts.map +1 -0
  43. package/dist/static-orchestrator.js +50 -0
  44. package/dist/static-orchestrator.js.map +1 -0
  45. package/package.json +41 -0
@@ -0,0 +1,54 @@
1
+ /**
2
+ * RuntimeClient — thin typed HTTP client over `RUNTIME_ROUTES`
3
+ * (TS_PI_REFACTOR_DESIGN §15.4). Two responsibilities:
4
+ *
5
+ * 1. REST forwarding — build the runtime URL from a route name + params and
6
+ * forward method/headers/body. Per 修正4, the backend is a byte-level
7
+ * passthrough: we do NOT re-validate runtime responses, we return them as
8
+ * they are. Protocol schemas only TYPE the calls.
9
+ *
10
+ * 2. SSE passthrough — open the runtime's event stream and hand back the raw
11
+ * `Response` whose `body` is a byte `ReadableStream`. The caller pipes
12
+ * those bytes straight to the browser without parsing (no state held).
13
+ */
14
+ import { type RuntimeRouteName } from "@brainpilot/protocol";
15
+ export interface RuntimeClientOptions {
16
+ /** Runtime base URL, e.g. http://127.0.0.1:8081. No trailing slash. */
17
+ baseUrl: string;
18
+ /** Injectable fetch (for tests). Defaults to global fetch. */
19
+ fetchFn?: typeof fetch;
20
+ }
21
+ /** Fill `:param` placeholders in a route path template. */
22
+ export declare function buildPath(template: string, params?: Record<string, string>): string;
23
+ export interface ForwardOptions {
24
+ params?: Record<string, string>;
25
+ /** Raw, already-serialized request body to forward. */
26
+ body?: string | null;
27
+ headers?: Record<string, string>;
28
+ /** Query string to append (without leading `?`). */
29
+ query?: string;
30
+ signal?: AbortSignal;
31
+ }
32
+ export declare class RuntimeClient {
33
+ private readonly baseUrl;
34
+ private readonly fetchFn;
35
+ constructor(options: RuntimeClientOptions);
36
+ /** Resolve a route name to a concrete URL. */
37
+ urlFor(route: RuntimeRouteName, params?: Record<string, string>, query?: string): string;
38
+ /**
39
+ * Forward a REST call to the runtime and return the raw `Response`. The body
40
+ * is NOT parsed or validated here (修正4); callers stream/relay it as-is.
41
+ */
42
+ forward(route: RuntimeRouteName, opts?: ForwardOptions): Promise<Response>;
43
+ /**
44
+ * Open the runtime SSE stream for a session. Returns the raw `Response`;
45
+ * `response.body` is a byte `ReadableStream` the caller pipes to the client.
46
+ * Defaults to the canonical `/sse/:id` route (§15.4).
47
+ */
48
+ openSse(sessionId: string, opts?: {
49
+ route?: RuntimeRouteName;
50
+ query?: string;
51
+ signal?: AbortSignal;
52
+ }): Promise<Response>;
53
+ }
54
+ //# sourceMappingURL=runtime-client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runtime-client.d.ts","sourceRoot":"","sources":["../src/runtime-client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,OAAO,EAAkB,KAAK,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAE7E,MAAM,WAAW,oBAAoB;IACnC,uEAAuE;IACvE,OAAO,EAAE,MAAM,CAAC;IAChB,8DAA8D;IAC9D,OAAO,CAAC,EAAE,OAAO,KAAK,CAAC;CACxB;AAED,2DAA2D;AAC3D,wBAAgB,SAAS,CACvB,QAAQ,EAAE,MAAM,EAChB,MAAM,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAM,GAClC,MAAM,CAQR;AAED,MAAM,WAAW,cAAc;IAC7B,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,uDAAuD;IACvD,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,oDAAoD;IACpD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB;AAED,qBAAa,aAAa;IACxB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAe;gBAE3B,OAAO,EAAE,oBAAoB;IAKzC,8CAA8C;IAC9C,MAAM,CAAC,KAAK,EAAE,gBAAgB,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM;IAMxF;;;OAGG;IACG,OAAO,CAAC,KAAK,EAAE,gBAAgB,EAAE,IAAI,GAAE,cAAmB,GAAG,OAAO,CAAC,QAAQ,CAAC;IAWpF;;;;OAIG;IACG,OAAO,CACX,SAAS,EAAE,MAAM,EACjB,IAAI,GAAE;QAAE,KAAK,CAAC,EAAE,gBAAgB,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,WAAW,CAAA;KAAO,GAC5E,OAAO,CAAC,QAAQ,CAAC;CASrB"}
@@ -0,0 +1,67 @@
1
+ /**
2
+ * RuntimeClient — thin typed HTTP client over `RUNTIME_ROUTES`
3
+ * (TS_PI_REFACTOR_DESIGN §15.4). Two responsibilities:
4
+ *
5
+ * 1. REST forwarding — build the runtime URL from a route name + params and
6
+ * forward method/headers/body. Per 修正4, the backend is a byte-level
7
+ * passthrough: we do NOT re-validate runtime responses, we return them as
8
+ * they are. Protocol schemas only TYPE the calls.
9
+ *
10
+ * 2. SSE passthrough — open the runtime's event stream and hand back the raw
11
+ * `Response` whose `body` is a byte `ReadableStream`. The caller pipes
12
+ * those bytes straight to the browser without parsing (no state held).
13
+ */
14
+ import { RUNTIME_ROUTES } from "@brainpilot/protocol";
15
+ /** Fill `:param` placeholders in a route path template. */
16
+ export function buildPath(template, params = {}) {
17
+ return template.replace(/:([A-Za-z0-9_]+)/g, (_m, key) => {
18
+ const value = params[key];
19
+ if (value === undefined) {
20
+ throw new Error(`missing path param ":${key}" for "${template}"`);
21
+ }
22
+ return encodeURIComponent(value);
23
+ });
24
+ }
25
+ export class RuntimeClient {
26
+ baseUrl;
27
+ fetchFn;
28
+ constructor(options) {
29
+ this.baseUrl = options.baseUrl.replace(/\/+$/, "");
30
+ this.fetchFn = options.fetchFn ?? fetch;
31
+ }
32
+ /** Resolve a route name to a concrete URL. */
33
+ urlFor(route, params, query) {
34
+ const def = RUNTIME_ROUTES[route];
35
+ const path = buildPath(def.path, params);
36
+ return `${this.baseUrl}${path}${query ? `?${query}` : ""}`;
37
+ }
38
+ /**
39
+ * Forward a REST call to the runtime and return the raw `Response`. The body
40
+ * is NOT parsed or validated here (修正4); callers stream/relay it as-is.
41
+ */
42
+ async forward(route, opts = {}) {
43
+ const def = RUNTIME_ROUTES[route];
44
+ const url = this.urlFor(route, opts.params, opts.query);
45
+ return this.fetchFn(url, {
46
+ method: def.method,
47
+ headers: opts.headers,
48
+ body: opts.body ?? undefined,
49
+ signal: opts.signal,
50
+ });
51
+ }
52
+ /**
53
+ * Open the runtime SSE stream for a session. Returns the raw `Response`;
54
+ * `response.body` is a byte `ReadableStream` the caller pipes to the client.
55
+ * Defaults to the canonical `/sse/:id` route (§15.4).
56
+ */
57
+ async openSse(sessionId, opts = {}) {
58
+ const route = opts.route ?? "sessionEvents";
59
+ const url = this.urlFor(route, { id: sessionId, sessionId }, opts.query);
60
+ return this.fetchFn(url, {
61
+ method: "GET",
62
+ headers: { accept: "text/event-stream" },
63
+ signal: opts.signal,
64
+ });
65
+ }
66
+ }
67
+ //# sourceMappingURL=runtime-client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runtime-client.js","sourceRoot":"","sources":["../src/runtime-client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,OAAO,EAAE,cAAc,EAAyB,MAAM,sBAAsB,CAAC;AAS7E,2DAA2D;AAC3D,MAAM,UAAU,SAAS,CACvB,QAAgB,EAChB,SAAiC,EAAE;IAEnC,OAAO,QAAQ,CAAC,OAAO,CAAC,mBAAmB,EAAE,CAAC,EAAE,EAAE,GAAW,EAAE,EAAE;QAC/D,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;QAC1B,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;YACxB,MAAM,IAAI,KAAK,CAAC,wBAAwB,GAAG,UAAU,QAAQ,GAAG,CAAC,CAAC;QACpE,CAAC;QACD,OAAO,kBAAkB,CAAC,KAAK,CAAC,CAAC;IACnC,CAAC,CAAC,CAAC;AACL,CAAC;AAYD,MAAM,OAAO,aAAa;IACP,OAAO,CAAS;IAChB,OAAO,CAAe;IAEvC,YAAY,OAA6B;QACvC,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;QACnD,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI,KAAK,CAAC;IAC1C,CAAC;IAED,8CAA8C;IAC9C,MAAM,CAAC,KAAuB,EAAE,MAA+B,EAAE,KAAc;QAC7E,MAAM,GAAG,GAAG,cAAc,CAAC,KAAK,CAAC,CAAC;QAClC,MAAM,IAAI,GAAG,SAAS,CAAC,GAAG,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QACzC,OAAO,GAAG,IAAI,CAAC,OAAO,GAAG,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,IAAI,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;IAC7D,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,OAAO,CAAC,KAAuB,EAAE,OAAuB,EAAE;QAC9D,MAAM,GAAG,GAAG,cAAc,CAAC,KAAK,CAAC,CAAC;QAClC,MAAM,GAAG,GAAG,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC;QACxD,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE;YACvB,MAAM,EAAE,GAAG,CAAC,MAAM;YAClB,OAAO,EAAE,IAAI,CAAC,OAAO;YACrB,IAAI,EAAE,IAAI,CAAC,IAAI,IAAI,SAAS;YAC5B,MAAM,EAAE,IAAI,CAAC,MAAM;SACpB,CAAC,CAAC;IACL,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,OAAO,CACX,SAAiB,EACjB,OAA2E,EAAE;QAE7E,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,IAAI,eAAe,CAAC;QAC5C,MAAM,GAAG,GAAG,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,EAAE,EAAE,EAAE,SAAS,EAAE,SAAS,EAAE,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC;QACzE,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE;YACvB,MAAM,EAAE,KAAK;YACb,OAAO,EAAE,EAAE,MAAM,EAAE,mBAAmB,EAAE;YACxC,MAAM,EAAE,IAAI,CAAC,MAAM;SACpB,CAAC,CAAC;IACL,CAAC;CACF"}
@@ -0,0 +1,8 @@
1
+ export interface RuntimeArtifactPaths {
2
+ /** Where the runtime child's stdout/stderr is appended. */
3
+ runtimeLog: string;
4
+ /** Where the runtime child's pid is written. */
5
+ runtimePid: string;
6
+ }
7
+ export declare function runtimeArtifactPaths(dataDir: string): RuntimeArtifactPaths;
8
+ //# sourceMappingURL=runtime-paths.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runtime-paths.d.ts","sourceRoot":"","sources":["../src/runtime-paths.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,oBAAoB;IACnC,2DAA2D;IAC3D,UAAU,EAAE,MAAM,CAAC;IACnB,gDAAgD;IAChD,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,GAAG,oBAAoB,CAM1E"}
@@ -0,0 +1,10 @@
1
+ // Mirrors cli/paths.ts dataPaths(); inlined here to avoid a cli→backend-core import cycle.
2
+ import { join } from "node:path";
3
+ export function runtimeArtifactPaths(dataDir) {
4
+ const runtimeDir = join(dataDir, ".runtime");
5
+ return {
6
+ runtimeLog: join(runtimeDir, "logs", "runtime.log"),
7
+ runtimePid: join(runtimeDir, "runtime.pid"),
8
+ };
9
+ }
10
+ //# sourceMappingURL=runtime-paths.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runtime-paths.js","sourceRoot":"","sources":["../src/runtime-paths.ts"],"names":[],"mappings":"AAAA,2FAA2F;AAC3F,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AASjC,MAAM,UAAU,oBAAoB,CAAC,OAAe;IAClD,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC;IAC7C,OAAO;QACL,UAAU,EAAE,IAAI,CAAC,UAAU,EAAE,MAAM,EAAE,aAAa,CAAC;QACnD,UAAU,EAAE,IAAI,CAAC,UAAU,EAAE,aAAa,CAAC;KAC5C,CAAC;AACJ,CAAC"}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * server.ts — boots the Hono app via @hono/node-server (§11A.3 / §11A.4 step 4).
3
+ * Exported via the package's `./server` entry. The orchestrator's runtime is
4
+ * started lazily on the first request that needs it; graceful shutdown stops it.
5
+ */
6
+ import { type ServerType } from "@hono/node-server";
7
+ import { type CreateAppOptions } from "./app.js";
8
+ import type { Orchestrator } from "./orchestrator.js";
9
+ export interface StartServerOptions extends Partial<CreateAppOptions> {
10
+ /** Backend port. Default 9001 (§11A.5 决策 D). */
11
+ port?: number;
12
+ hostname?: string;
13
+ /** Provide a pre-built orchestrator; otherwise one is created from env. */
14
+ orchestrator?: Orchestrator;
15
+ /** Eagerly ensure the runtime at boot (default false — lazy on first use). */
16
+ eager?: boolean;
17
+ }
18
+ export interface RunningServer {
19
+ server: ServerType;
20
+ orchestrator: Orchestrator;
21
+ port: number;
22
+ stop: () => Promise<void>;
23
+ }
24
+ export declare function startServer(options?: StartServerOptions): Promise<RunningServer>;
25
+ //# sourceMappingURL=server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAS,KAAK,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC3D,OAAO,EAAa,KAAK,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAE5D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAEtD,MAAM,WAAW,kBAAmB,SAAQ,OAAO,CAAC,gBAAgB,CAAC;IACnE,gDAAgD;IAChD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,2EAA2E;IAC3E,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B,8EAA8E;IAC9E,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,UAAU,CAAC;IACnB,YAAY,EAAE,YAAY,CAAC;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC3B;AAED,wBAAsB,WAAW,CAC/B,OAAO,GAAE,kBAAuB,GAC/B,OAAO,CAAC,aAAa,CAAC,CAqCxB"}
package/dist/server.js ADDED
@@ -0,0 +1,54 @@
1
+ /**
2
+ * server.ts — boots the Hono app via @hono/node-server (§11A.3 / §11A.4 step 4).
3
+ * Exported via the package's `./server` entry. The orchestrator's runtime is
4
+ * started lazily on the first request that needs it; graceful shutdown stops it.
5
+ */
6
+ import { serve } from "@hono/node-server";
7
+ import { createApp } from "./app.js";
8
+ import { createOrchestrator } from "./create-orchestrator.js";
9
+ export async function startServer(options = {}) {
10
+ const port = options.port ?? Number(process.env.PORT ?? 9001);
11
+ // 127.0.0.1 is the safe default for local/CLI use; containers set BP_HOST=0.0.0.0
12
+ // so the published port (DNAT'd to the container IP) can reach the server.
13
+ const hostname = options.hostname ?? process.env.BP_HOST ?? "127.0.0.1";
14
+ const orchestrator = options.orchestrator ?? createOrchestrator();
15
+ const app = createApp({
16
+ orchestrator,
17
+ dataDir: options.dataDir,
18
+ webRoot: options.webRoot,
19
+ fetchFn: options.fetchFn,
20
+ serveWeb: options.serveWeb,
21
+ env: options.env,
22
+ });
23
+ if (options.eager) {
24
+ await orchestrator.ensureRuntime();
25
+ }
26
+ const server = serve({ fetch: app.fetch, port, hostname });
27
+ const stop = async () => {
28
+ await new Promise((resolve) => {
29
+ server.close(() => resolve());
30
+ });
31
+ await orchestrator.stopRuntime();
32
+ };
33
+ // Graceful shutdown on signals (best-effort; CLI/PM2 may also manage this).
34
+ const onSignal = () => {
35
+ void stop().finally(() => process.exit(0));
36
+ };
37
+ process.once("SIGINT", onSignal);
38
+ process.once("SIGTERM", onSignal);
39
+ return { server, orchestrator, port, stop };
40
+ }
41
+ // Allow `node dist/server.js` to boot directly.
42
+ const isMain = typeof process.argv[1] === "string" &&
43
+ import.meta.url === `file://${process.argv[1]}`;
44
+ if (isMain) {
45
+ startServer().then((s) => {
46
+ // eslint-disable-next-line no-console
47
+ console.log(`[backend-core] listening on port ${s.port}`);
48
+ }, (err) => {
49
+ // eslint-disable-next-line no-console
50
+ console.error("[backend-core] failed to start:", err);
51
+ process.exit(1);
52
+ });
53
+ }
54
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,KAAK,EAAmB,MAAM,mBAAmB,CAAC;AAC3D,OAAO,EAAE,SAAS,EAAyB,MAAM,UAAU,CAAC;AAC5D,OAAO,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAoB9D,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,UAA8B,EAAE;IAEhC,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,IAAI,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI,IAAI,CAAC,CAAC;IAC9D,kFAAkF;IAClF,2EAA2E;IAC3E,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,IAAI,OAAO,CAAC,GAAG,CAAC,OAAO,IAAI,WAAW,CAAC;IACxE,MAAM,YAAY,GAAG,OAAO,CAAC,YAAY,IAAI,kBAAkB,EAAE,CAAC;IAElE,MAAM,GAAG,GAAG,SAAS,CAAC;QACpB,YAAY;QACZ,OAAO,EAAE,OAAO,CAAC,OAAO;QACxB,OAAO,EAAE,OAAO,CAAC,OAAO;QACxB,OAAO,EAAE,OAAO,CAAC,OAAO;QACxB,QAAQ,EAAE,OAAO,CAAC,QAAQ;QAC1B,GAAG,EAAE,OAAO,CAAC,GAAG;KACjB,CAAC,CAAC;IAEH,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;QAClB,MAAM,YAAY,CAAC,aAAa,EAAE,CAAC;IACrC,CAAC;IAED,MAAM,MAAM,GAAG,KAAK,CAAC,EAAE,KAAK,EAAE,GAAG,CAAC,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAC;IAE3D,MAAM,IAAI,GAAG,KAAK,IAAmB,EAAE;QACrC,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE;YAClC,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,OAAO,EAAE,CAAC,CAAC;QAChC,CAAC,CAAC,CAAC;QACH,MAAM,YAAY,CAAC,WAAW,EAAE,CAAC;IACnC,CAAC,CAAC;IAEF,4EAA4E;IAC5E,MAAM,QAAQ,GAAG,GAAS,EAAE;QAC1B,KAAK,IAAI,EAAE,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;IAC7C,CAAC,CAAC;IACF,OAAO,CAAC,IAAI,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;IACjC,OAAO,CAAC,IAAI,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;IAElC,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;AAC9C,CAAC;AAED,gDAAgD;AAChD,MAAM,MAAM,GACV,OAAO,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,QAAQ;IACnC,MAAM,CAAC,IAAI,CAAC,GAAG,KAAK,UAAU,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;AAClD,IAAI,MAAM,EAAE,CAAC;IACX,WAAW,EAAE,CAAC,IAAI,CAChB,CAAC,CAAC,EAAE,EAAE;QACJ,sCAAsC;QACtC,OAAO,CAAC,GAAG,CAAC,oCAAoC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;IAC5D,CAAC,EACD,CAAC,GAAG,EAAE,EAAE;QACN,sCAAsC;QACtC,OAAO,CAAC,KAAK,CAAC,iCAAiC,EAAE,GAAG,CAAC,CAAC;QACtD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,CACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,37 @@
1
+ /**
2
+ * StaticRuntimeOrchestrator — static sandbox 模式 (docker-deploy spec §4.1).
3
+ *
4
+ * The runtime container is started by docker-compose, NOT by the backend. This
5
+ * orchestrator therefore creates nothing: it only health-probes a pre-provisioned
6
+ * `BP_RUNTIME_URL` and hands the backend that URL. `stopRuntime` is a no-op —
7
+ * compose owns the container lifecycle.
8
+ *
9
+ * Same `Orchestrator` surface as Local/Docker so app.ts / runtime-client are
10
+ * agnostic to deployment mode.
11
+ */
12
+ import type { EnsureRuntimeOptions, Orchestrator, RuntimeHandle } from "./orchestrator.js";
13
+ export interface StaticOrchestratorOptions {
14
+ /** Pre-provisioned runtime URL (BP_RUNTIME_URL). Trailing slash is stripped. */
15
+ baseUrl: string;
16
+ /** Injectable health probe (for tests). Defaults to fetch GET /health. */
17
+ healthProbe?: (baseUrl: string) => Promise<boolean>;
18
+ /** Max ms to wait for the runtime to become healthy. Default 30_000. */
19
+ healthTimeoutMs?: number;
20
+ /** Poll interval in ms. Default 250. */
21
+ pollMs?: number;
22
+ /** Injectable sleep (for tests). */
23
+ sleep?: (ms: number) => Promise<void>;
24
+ }
25
+ export declare class StaticRuntimeOrchestrator implements Orchestrator {
26
+ private readonly url;
27
+ private readonly healthProbe;
28
+ private readonly healthTimeoutMs;
29
+ private readonly pollMs;
30
+ private readonly sleep;
31
+ constructor(options: StaticOrchestratorOptions);
32
+ get baseUrl(): string;
33
+ ensureRuntime(_opts?: EnsureRuntimeOptions): Promise<RuntimeHandle>;
34
+ health(): Promise<boolean>;
35
+ stopRuntime(): Promise<void>;
36
+ }
37
+ //# sourceMappingURL=static-orchestrator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"static-orchestrator.d.ts","sourceRoot":"","sources":["../src/static-orchestrator.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,KAAK,EACV,oBAAoB,EACpB,YAAY,EACZ,aAAa,EACd,MAAM,mBAAmB,CAAC;AAc3B,MAAM,WAAW,yBAAyB;IACxC,gFAAgF;IAChF,OAAO,EAAE,MAAM,CAAC;IAChB,0EAA0E;IAC1E,WAAW,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IACpD,wEAAwE;IACxE,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,wCAAwC;IACxC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,oCAAoC;IACpC,KAAK,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CACvC;AAED,qBAAa,yBAA0B,YAAW,YAAY;IAC5D,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAS;IAC7B,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAwC;IACpE,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAS;IACzC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAgC;gBAE1C,OAAO,EAAE,yBAAyB;IAW9C,IAAI,OAAO,IAAI,MAAM,CAEpB;IAEK,aAAa,CAAC,KAAK,CAAC,EAAE,oBAAoB,GAAG,OAAO,CAAC,aAAa,CAAC;IAenE,MAAM,IAAI,OAAO,CAAC,OAAO,CAAC;IAI1B,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC;CAGnC"}
@@ -0,0 +1,50 @@
1
+ async function defaultHealthProbe(baseUrl) {
2
+ try {
3
+ const res = await fetch(`${baseUrl}/health`);
4
+ return res.ok;
5
+ }
6
+ catch {
7
+ return false;
8
+ }
9
+ }
10
+ const sleepDefault = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
11
+ export class StaticRuntimeOrchestrator {
12
+ url;
13
+ healthProbe;
14
+ healthTimeoutMs;
15
+ pollMs;
16
+ sleep;
17
+ constructor(options) {
18
+ if (!options.baseUrl || options.baseUrl.trim() === "") {
19
+ throw new Error("StaticRuntimeOrchestrator: baseUrl is required");
20
+ }
21
+ this.url = options.baseUrl.replace(/\/+$/, "");
22
+ this.healthProbe = options.healthProbe ?? defaultHealthProbe;
23
+ this.healthTimeoutMs = options.healthTimeoutMs ?? 30_000;
24
+ this.pollMs = options.pollMs ?? 250;
25
+ this.sleep = options.sleep ?? sleepDefault;
26
+ }
27
+ get baseUrl() {
28
+ return this.url;
29
+ }
30
+ async ensureRuntime(_opts) {
31
+ const deadline = Date.now() + this.healthTimeoutMs;
32
+ for (;;) {
33
+ if (await this.healthProbe(this.url))
34
+ return { baseUrl: this.url };
35
+ if (Date.now() >= deadline) {
36
+ throw new Error(`static runtime did not become healthy at ${this.url} within ` +
37
+ `${this.healthTimeoutMs}ms — is the sandbox container up? ` +
38
+ `(check \`docker compose logs sandbox\` and BP_RUNTIME_URL)`);
39
+ }
40
+ await this.sleep(this.pollMs);
41
+ }
42
+ }
43
+ async health() {
44
+ return this.healthProbe(this.url);
45
+ }
46
+ async stopRuntime() {
47
+ // No-op: the sandbox container is owned by docker-compose.
48
+ }
49
+ }
50
+ //# sourceMappingURL=static-orchestrator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"static-orchestrator.js","sourceRoot":"","sources":["../src/static-orchestrator.ts"],"names":[],"mappings":"AAiBA,KAAK,UAAU,kBAAkB,CAAC,OAAe;IAC/C,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,OAAO,SAAS,CAAC,CAAC;QAC7C,OAAO,GAAG,CAAC,EAAE,CAAC;IAChB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,MAAM,YAAY,GAAG,CAAC,EAAU,EAAiB,EAAE,CACjD,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC;AAepD,MAAM,OAAO,yBAAyB;IACnB,GAAG,CAAS;IACZ,WAAW,CAAwC;IACnD,eAAe,CAAS;IACxB,MAAM,CAAS;IACf,KAAK,CAAgC;IAEtD,YAAY,OAAkC;QAC5C,IAAI,CAAC,OAAO,CAAC,OAAO,IAAI,OAAO,CAAC,OAAO,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;YACtD,MAAM,IAAI,KAAK,CAAC,gDAAgD,CAAC,CAAC;QACpE,CAAC;QACD,IAAI,CAAC,GAAG,GAAG,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;QAC/C,IAAI,CAAC,WAAW,GAAG,OAAO,CAAC,WAAW,IAAI,kBAAkB,CAAC;QAC7D,IAAI,CAAC,eAAe,GAAG,OAAO,CAAC,eAAe,IAAI,MAAM,CAAC;QACzD,IAAI,CAAC,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,GAAG,CAAC;QACpC,IAAI,CAAC,KAAK,GAAG,OAAO,CAAC,KAAK,IAAI,YAAY,CAAC;IAC7C,CAAC;IAED,IAAI,OAAO;QACT,OAAO,IAAI,CAAC,GAAG,CAAC;IAClB,CAAC;IAED,KAAK,CAAC,aAAa,CAAC,KAA4B;QAC9C,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,eAAe,CAAC;QACnD,SAAS,CAAC;YACR,IAAI,MAAM,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC;gBAAE,OAAO,EAAE,OAAO,EAAE,IAAI,CAAC,GAAG,EAAE,CAAC;YACnE,IAAI,IAAI,CAAC,GAAG,EAAE,IAAI,QAAQ,EAAE,CAAC;gBAC3B,MAAM,IAAI,KAAK,CACb,4CAA4C,IAAI,CAAC,GAAG,UAAU;oBAC5D,GAAG,IAAI,CAAC,eAAe,oCAAoC;oBAC3D,4DAA4D,CAC/D,CAAC;YACJ,CAAC;YACD,MAAM,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAChC,CAAC;IACH,CAAC;IAED,KAAK,CAAC,MAAM;QACV,OAAO,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACpC,CAAC;IAED,KAAK,CAAC,WAAW;QACf,2DAA2D;IAC7D,CAAC;CACF"}
package/package.json ADDED
@@ -0,0 +1,41 @@
1
+ {
2
+ "name": "@brainpilot/backend-core",
3
+ "version": "0.0.1",
4
+ "license": "Apache-2.0",
5
+ "type": "module",
6
+ "description": "BrainPilot Backend — Hono REST+SSE proxy, serve web, Orchestrator abstraction (Docker/Local)",
7
+ "main": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "files": ["dist"],
10
+ "repository": {
11
+ "type": "git",
12
+ "url": "git+https://github.com/NeuroAIHub/BrainPilot.git",
13
+ "directory": "packages/backend-core"
14
+ },
15
+ "publishConfig": { "access": "public" },
16
+ "exports": {
17
+ ".": {
18
+ "types": "./dist/index.d.ts",
19
+ "default": "./dist/index.js"
20
+ },
21
+ "./server": {
22
+ "types": "./dist/server.d.ts",
23
+ "default": "./dist/server.js"
24
+ }
25
+ },
26
+ "scripts": {
27
+ "build": "tsc -b",
28
+ "typecheck": "tsc -b",
29
+ "test": "vitest run",
30
+ "start": "node ./dist/server.js"
31
+ },
32
+ "dependencies": {
33
+ "@brainpilot/protocol": "^0.0.1",
34
+ "@brainpilot/runtime": "^0.0.1",
35
+ "@hono/node-server": "^1.13.0",
36
+ "hono": "^4.6.0"
37
+ },
38
+ "devDependencies": {
39
+ "@types/dockerode": "^3.3.0"
40
+ }
41
+ }