@noodleseed/one 0.122.0 → 0.124.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/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +3 -0
- package/dist/cli.js.map +1 -1
- package/dist/commands/catalog-data-hosted-observability.d.ts.map +1 -1
- package/dist/commands/catalog-data-hosted-observability.js +33 -0
- package/dist/commands/catalog-data-hosted-observability.js.map +1 -1
- package/dist/commands/deploy-version-resolution.js +1 -1
- package/dist/commands/deploy-version-resolution.js.map +1 -1
- package/dist/commands/knowledge.d.ts +7 -0
- package/dist/commands/knowledge.d.ts.map +1 -0
- package/dist/commands/knowledge.js +129 -0
- package/dist/commands/knowledge.js.map +1 -0
- package/dist/deploy.d.ts.map +1 -1
- package/dist/deploy.js +19 -2
- package/dist/deploy.js.map +1 -1
- package/node_modules/@noodle-borg/agent-kit/dist/curated/command-groups.d.ts.map +1 -1
- package/node_modules/@noodle-borg/agent-kit/dist/curated/command-groups.js +4 -0
- package/node_modules/@noodle-borg/agent-kit/dist/curated/command-groups.js.map +1 -1
- package/node_modules/@noodle-borg/agent-kit/dist/generated/example-files.js +3 -3
- package/node_modules/@noodle-borg/agent-kit/dist/generated/example-files.js.map +1 -1
- package/node_modules/@noodle-borg/agent-kit/dist/generated/surface.d.ts.map +1 -1
- package/node_modules/@noodle-borg/agent-kit/dist/generated/surface.js +1 -0
- package/node_modules/@noodle-borg/agent-kit/dist/generated/surface.js.map +1 -1
- package/node_modules/@noodle-borg/agent-kit/dist/skill-authoring-refs.d.ts.map +1 -1
- package/node_modules/@noodle-borg/agent-kit/dist/skill-authoring-refs.js +2 -0
- package/node_modules/@noodle-borg/agent-kit/dist/skill-authoring-refs.js.map +1 -1
- package/node_modules/@noodle-borg/agent-kit/package.json +1 -1
- package/node_modules/@noodle-borg/assistant-gateway/dist/artifact-projection.d.ts +1 -1
- package/node_modules/@noodle-borg/assistant-gateway/dist/artifact-projection.d.ts.map +1 -1
- package/node_modules/@noodle-borg/assistant-gateway/dist/artifact-projection.js +7 -1
- package/node_modules/@noodle-borg/assistant-gateway/dist/artifact-projection.js.map +1 -1
- package/node_modules/@noodle-borg/{service → assistant-gateway}/dist/assistant-interactive.d.ts +1 -1
- package/node_modules/@noodle-borg/{service → assistant-gateway}/dist/assistant-interactive.d.ts.map +1 -1
- package/node_modules/@noodle-borg/{service → assistant-gateway}/dist/assistant-interactive.js.map +1 -1
- package/node_modules/@noodle-borg/{service → assistant-gateway}/dist/assistant-presentation.d.ts.map +1 -1
- package/node_modules/@noodle-borg/{service → assistant-gateway}/dist/assistant-presentation.js +1 -1
- package/node_modules/@noodle-borg/{service → assistant-gateway}/dist/assistant-presentation.js.map +1 -1
- package/node_modules/@noodle-borg/assistant-gateway/dist/index.d.ts +2 -0
- package/node_modules/@noodle-borg/assistant-gateway/dist/index.d.ts.map +1 -1
- package/node_modules/@noodle-borg/assistant-gateway/dist/index.js +2 -0
- package/node_modules/@noodle-borg/assistant-gateway/dist/index.js.map +1 -1
- package/node_modules/@noodle-borg/assistant-gateway/package.json +3 -1
- package/node_modules/@noodle-borg/deploy-client/dist/deploy-knowledge.d.ts +21 -0
- package/node_modules/@noodle-borg/deploy-client/dist/deploy-knowledge.d.ts.map +1 -0
- package/node_modules/@noodle-borg/deploy-client/dist/deploy-knowledge.js +115 -0
- package/node_modules/@noodle-borg/deploy-client/dist/deploy-knowledge.js.map +1 -0
- package/node_modules/@noodle-borg/deploy-client/dist/index.d.ts +4 -0
- package/node_modules/@noodle-borg/deploy-client/dist/index.d.ts.map +1 -0
- package/node_modules/@noodle-borg/deploy-client/dist/index.js +4 -0
- package/node_modules/@noodle-borg/deploy-client/dist/index.js.map +1 -0
- package/node_modules/@noodle-borg/deploy-client/package.json +34 -0
- package/node_modules/@noodle-borg/knowledge/dist/bm25.d.ts.map +1 -1
- package/node_modules/@noodle-borg/knowledge/dist/bm25.js +4 -0
- package/node_modules/@noodle-borg/knowledge/dist/bm25.js.map +1 -1
- package/node_modules/@noodle-borg/knowledge/dist/google-agent-search.d.ts +4 -0
- package/node_modules/@noodle-borg/knowledge/dist/google-agent-search.d.ts.map +1 -1
- package/node_modules/@noodle-borg/knowledge/dist/google-agent-search.js +28 -20
- package/node_modules/@noodle-borg/knowledge/dist/google-agent-search.js.map +1 -1
- package/node_modules/@noodle-borg/knowledge/dist/postgres-revision-store.d.ts +2 -1
- package/node_modules/@noodle-borg/knowledge/dist/postgres-revision-store.d.ts.map +1 -1
- package/node_modules/@noodle-borg/knowledge/dist/postgres-revision-store.js +53 -28
- package/node_modules/@noodle-borg/knowledge/dist/postgres-revision-store.js.map +1 -1
- package/node_modules/@noodle-borg/knowledge/dist/revision-store.d.ts +9 -5
- package/node_modules/@noodle-borg/knowledge/dist/revision-store.d.ts.map +1 -1
- package/node_modules/@noodle-borg/knowledge/dist/revision-store.js +38 -21
- package/node_modules/@noodle-borg/knowledge/dist/revision-store.js.map +1 -1
- package/node_modules/@noodle-borg/knowledge/package.json +4 -0
- package/node_modules/@noodle-borg/knowledge-operations/dist/codec.d.ts +12 -0
- package/node_modules/@noodle-borg/knowledge-operations/dist/codec.d.ts.map +1 -0
- package/node_modules/@noodle-borg/knowledge-operations/dist/codec.js +7 -0
- package/node_modules/@noodle-borg/knowledge-operations/dist/codec.js.map +1 -0
- package/node_modules/@noodle-borg/knowledge-operations/dist/dispatch.d.ts +16 -0
- package/node_modules/@noodle-borg/knowledge-operations/dist/dispatch.d.ts.map +1 -0
- package/node_modules/@noodle-borg/knowledge-operations/dist/dispatch.js +41 -0
- package/node_modules/@noodle-borg/knowledge-operations/dist/dispatch.js.map +1 -0
- package/node_modules/@noodle-borg/knowledge-operations/dist/executor.d.ts +40 -0
- package/node_modules/@noodle-borg/knowledge-operations/dist/executor.d.ts.map +1 -0
- package/node_modules/@noodle-borg/knowledge-operations/dist/executor.js +54 -0
- package/node_modules/@noodle-borg/knowledge-operations/dist/executor.js.map +1 -0
- package/node_modules/@noodle-borg/knowledge-operations/dist/google-identity.d.ts +15 -0
- package/node_modules/@noodle-borg/knowledge-operations/dist/google-identity.d.ts.map +1 -0
- package/node_modules/@noodle-borg/knowledge-operations/dist/google-identity.js +50 -0
- package/node_modules/@noodle-borg/knowledge-operations/dist/google-identity.js.map +1 -0
- package/node_modules/@noodle-borg/knowledge-operations/dist/http.d.ts +16 -0
- package/node_modules/@noodle-borg/knowledge-operations/dist/http.d.ts.map +1 -0
- package/node_modules/@noodle-borg/knowledge-operations/dist/http.js +18 -0
- package/node_modules/@noodle-borg/knowledge-operations/dist/http.js.map +1 -0
- package/node_modules/@noodle-borg/knowledge-operations/dist/index.d.ts +18 -0
- package/node_modules/@noodle-borg/knowledge-operations/dist/index.d.ts.map +1 -0
- package/node_modules/@noodle-borg/knowledge-operations/dist/index.js +18 -0
- package/node_modules/@noodle-borg/knowledge-operations/dist/index.js.map +1 -0
- package/node_modules/@noodle-borg/knowledge-operations/dist/managed-google.d.ts +29 -0
- package/node_modules/@noodle-borg/knowledge-operations/dist/managed-google.d.ts.map +1 -0
- package/node_modules/@noodle-borg/knowledge-operations/dist/managed-google.js +53 -0
- package/node_modules/@noodle-borg/knowledge-operations/dist/managed-google.js.map +1 -0
- package/node_modules/@noodle-borg/knowledge-operations/dist/paths.d.ts +21 -0
- package/node_modules/@noodle-borg/knowledge-operations/dist/paths.d.ts.map +1 -0
- package/node_modules/@noodle-borg/knowledge-operations/dist/paths.js +28 -0
- package/node_modules/@noodle-borg/knowledge-operations/dist/paths.js.map +1 -0
- package/node_modules/@noodle-borg/knowledge-operations/dist/publication.d.ts +60 -0
- package/node_modules/@noodle-borg/knowledge-operations/dist/publication.d.ts.map +1 -0
- package/node_modules/@noodle-borg/knowledge-operations/dist/publication.js +230 -0
- package/node_modules/@noodle-borg/knowledge-operations/dist/publication.js.map +1 -0
- package/node_modules/@noodle-borg/knowledge-operations/dist/routes.d.ts +38 -0
- package/node_modules/@noodle-borg/knowledge-operations/dist/routes.d.ts.map +1 -0
- package/node_modules/@noodle-borg/knowledge-operations/dist/routes.js +100 -0
- package/node_modules/@noodle-borg/knowledge-operations/dist/routes.js.map +1 -0
- package/node_modules/@noodle-borg/knowledge-operations/dist/search-port.d.ts +31 -0
- package/node_modules/@noodle-borg/knowledge-operations/dist/search-port.d.ts.map +1 -0
- package/node_modules/@noodle-borg/knowledge-operations/dist/search-port.js +36 -0
- package/node_modules/@noodle-borg/knowledge-operations/dist/search-port.js.map +1 -0
- package/node_modules/@noodle-borg/knowledge-operations/dist/service-wiring.d.ts +56 -0
- package/node_modules/@noodle-borg/knowledge-operations/dist/service-wiring.d.ts.map +1 -0
- package/node_modules/@noodle-borg/knowledge-operations/dist/service-wiring.js +129 -0
- package/node_modules/@noodle-borg/knowledge-operations/dist/service-wiring.js.map +1 -0
- package/node_modules/@noodle-borg/knowledge-operations/dist/staging-store.d.ts +38 -0
- package/node_modules/@noodle-borg/knowledge-operations/dist/staging-store.d.ts.map +1 -0
- package/node_modules/@noodle-borg/knowledge-operations/dist/staging-store.js +77 -0
- package/node_modules/@noodle-borg/knowledge-operations/dist/staging-store.js.map +1 -0
- package/node_modules/@noodle-borg/knowledge-operations/dist/status-routes.d.ts +28 -0
- package/node_modules/@noodle-borg/knowledge-operations/dist/status-routes.d.ts.map +1 -0
- package/node_modules/@noodle-borg/knowledge-operations/dist/status-routes.js +66 -0
- package/node_modules/@noodle-borg/knowledge-operations/dist/status-routes.js.map +1 -0
- package/node_modules/@noodle-borg/knowledge-operations/package.json +34 -0
- package/node_modules/@noodle-borg/protocol/dist/context-tool.d.ts.map +1 -1
- package/node_modules/@noodle-borg/protocol/dist/context-tool.js +15 -1
- package/node_modules/@noodle-borg/protocol/dist/context-tool.js.map +1 -1
- package/node_modules/@noodle-borg/protocol/dist/handlers/tools.d.ts.map +1 -1
- package/node_modules/@noodle-borg/protocol/dist/handlers/tools.js +22 -1
- package/node_modules/@noodle-borg/protocol/dist/handlers/tools.js.map +1 -1
- package/node_modules/@noodle-borg/protocol/dist/knowledge-tool.d.ts +28 -0
- package/node_modules/@noodle-borg/protocol/dist/knowledge-tool.d.ts.map +1 -0
- package/node_modules/@noodle-borg/protocol/dist/knowledge-tool.js +26 -0
- package/node_modules/@noodle-borg/protocol/dist/knowledge-tool.js.map +1 -0
- package/node_modules/@noodle-borg/protocol/dist/mapping.d.ts +5 -1
- package/node_modules/@noodle-borg/protocol/dist/mapping.d.ts.map +1 -1
- package/node_modules/@noodle-borg/protocol/dist/mapping.js +12 -1
- package/node_modules/@noodle-borg/protocol/dist/mapping.js.map +1 -1
- package/node_modules/@noodle-borg/protocol/dist/v2/server.d.ts.map +1 -1
- package/node_modules/@noodle-borg/protocol/dist/v2/server.js +23 -2
- package/node_modules/@noodle-borg/protocol/dist/v2/server.js.map +1 -1
- package/node_modules/@noodle-borg/runtime/dist/execute.d.ts +28 -0
- package/node_modules/@noodle-borg/runtime/dist/execute.d.ts.map +1 -1
- package/node_modules/@noodle-borg/runtime/dist/execute.js.map +1 -1
- package/node_modules/@noodle-borg/runtime/dist/index.d.ts +2 -2
- package/node_modules/@noodle-borg/runtime/dist/index.d.ts.map +1 -1
- package/node_modules/@noodle-borg/runtime/dist/index.js.map +1 -1
- package/node_modules/@noodle-borg/runtime/dist/invocation-context.d.ts +12 -0
- package/node_modules/@noodle-borg/runtime/dist/invocation-context.d.ts.map +1 -1
- package/node_modules/@noodle-borg/service/dist/invocation-context.d.ts +2 -1
- package/node_modules/@noodle-borg/service/dist/invocation-context.d.ts.map +1 -1
- package/node_modules/@noodle-borg/service/dist/invocation-context.js +19 -6
- package/node_modules/@noodle-borg/service/dist/invocation-context.js.map +1 -1
- package/node_modules/@noodle-borg/service/dist/options.d.ts +3 -0
- package/node_modules/@noodle-borg/service/dist/options.d.ts.map +1 -1
- package/node_modules/@noodle-borg/service/dist/registry-compile.d.ts +2 -0
- package/node_modules/@noodle-borg/service/dist/registry-compile.d.ts.map +1 -1
- package/node_modules/@noodle-borg/service/dist/registry-compile.js +6 -0
- package/node_modules/@noodle-borg/service/dist/registry-compile.js.map +1 -1
- package/node_modules/@noodle-borg/service/dist/registry-recover.d.ts +26 -0
- package/node_modules/@noodle-borg/service/dist/registry-recover.d.ts.map +1 -0
- package/node_modules/@noodle-borg/service/dist/registry-recover.js +58 -0
- package/node_modules/@noodle-borg/service/dist/registry-recover.js.map +1 -0
- package/node_modules/@noodle-borg/service/dist/registry-rollback.d.ts +10 -0
- package/node_modules/@noodle-borg/service/dist/registry-rollback.d.ts.map +1 -1
- package/node_modules/@noodle-borg/service/dist/registry-rollback.js +25 -0
- package/node_modules/@noodle-borg/service/dist/registry-rollback.js.map +1 -1
- package/node_modules/@noodle-borg/service/dist/registry.d.ts +5 -0
- package/node_modules/@noodle-borg/service/dist/registry.d.ts.map +1 -1
- package/node_modules/@noodle-borg/service/dist/registry.js +36 -78
- package/node_modules/@noodle-borg/service/dist/registry.js.map +1 -1
- package/node_modules/@noodle-borg/service/dist/routes/assistant-agent.d.ts.map +1 -1
- package/node_modules/@noodle-borg/service/dist/routes/assistant-agent.js +38 -14
- package/node_modules/@noodle-borg/service/dist/routes/assistant-agent.js.map +1 -1
- package/node_modules/@noodle-borg/service/dist/routes/assistant-interaction-replay.d.ts.map +1 -1
- package/node_modules/@noodle-borg/service/dist/routes/assistant-interaction-replay.js +1 -1
- package/node_modules/@noodle-borg/service/dist/routes/assistant-interaction-replay.js.map +1 -1
- package/node_modules/@noodle-borg/service/dist/routes/assistant-interaction-stream.d.ts.map +1 -1
- package/node_modules/@noodle-borg/service/dist/routes/assistant-interaction-stream.js +1 -1
- package/node_modules/@noodle-borg/service/dist/routes/assistant-interaction-stream.js.map +1 -1
- package/node_modules/@noodle-borg/service/dist/routes/assistant-interactions.d.ts.map +1 -1
- package/node_modules/@noodle-borg/service/dist/routes/assistant-interactions.js +1 -3
- package/node_modules/@noodle-borg/service/dist/routes/assistant-interactions.js.map +1 -1
- package/node_modules/@noodle-borg/service/dist/routes/assistant-knowledge.d.ts +32 -0
- package/node_modules/@noodle-borg/service/dist/routes/assistant-knowledge.d.ts.map +1 -0
- package/node_modules/@noodle-borg/service/dist/routes/assistant-knowledge.js +42 -0
- package/node_modules/@noodle-borg/service/dist/routes/assistant-knowledge.js.map +1 -0
- package/node_modules/@noodle-borg/service/dist/routes/assistant.d.ts.map +1 -1
- package/node_modules/@noodle-borg/service/dist/routes/assistant.js +11 -3
- package/node_modules/@noodle-borg/service/dist/routes/assistant.js.map +1 -1
- package/node_modules/@noodle-borg/service/dist/serve.d.ts.map +1 -1
- package/node_modules/@noodle-borg/service/dist/serve.js +4 -0
- package/node_modules/@noodle-borg/service/dist/serve.js.map +1 -1
- package/node_modules/@noodle-borg/service/dist/service.d.ts.map +1 -1
- package/node_modules/@noodle-borg/service/dist/service.js +11 -1
- package/node_modules/@noodle-borg/service/dist/service.js.map +1 -1
- package/node_modules/@noodle-borg/service/package.json +3 -1
- package/node_modules/@noodle-borg/transport-http/dist/handler.d.ts +13 -0
- package/node_modules/@noodle-borg/transport-http/dist/handler.d.ts.map +1 -1
- package/node_modules/@noodle-borg/transport-http/dist/handler.js.map +1 -1
- package/node_modules/@noodle-borg/transport-http/dist/index.d.ts +1 -1
- package/node_modules/@noodle-borg/transport-http/dist/index.d.ts.map +1 -1
- package/node_modules/@noodle-borg/transport-http/dist/index.js.map +1 -1
- package/node_modules/@noodle-borg/transport-http/dist/invocation-client-hints.d.ts +7 -0
- package/node_modules/@noodle-borg/transport-http/dist/invocation-client-hints.d.ts.map +1 -0
- package/node_modules/@noodle-borg/transport-http/dist/invocation-client-hints.js +86 -0
- package/node_modules/@noodle-borg/transport-http/dist/invocation-client-hints.js.map +1 -0
- package/node_modules/@noodle-borg/transport-http/dist/serve-request.d.ts.map +1 -1
- package/node_modules/@noodle-borg/transport-http/dist/serve-request.js +3 -0
- package/node_modules/@noodle-borg/transport-http/dist/serve-request.js.map +1 -1
- package/node_modules/@noodle-borg/wire-contracts/dist/index.d.ts +1 -0
- package/node_modules/@noodle-borg/wire-contracts/dist/index.d.ts.map +1 -1
- package/node_modules/@noodle-borg/wire-contracts/dist/index.js +1 -0
- package/node_modules/@noodle-borg/wire-contracts/dist/index.js.map +1 -1
- package/node_modules/@noodle-borg/wire-contracts/dist/knowledge.d.ts +134 -0
- package/node_modules/@noodle-borg/wire-contracts/dist/knowledge.d.ts.map +1 -0
- package/node_modules/@noodle-borg/wire-contracts/dist/knowledge.js +101 -0
- package/node_modules/@noodle-borg/wire-contracts/dist/knowledge.js.map +1 -0
- package/node_modules/@noodle-borg/wire-contracts/package.json +1 -0
- package/node_modules/@noodleseed/assistant/package.json +1 -1
- package/package.json +7 -2
- /package/node_modules/@noodle-borg/{service → assistant-gateway}/dist/assistant-interactive.js +0 -0
- /package/node_modules/@noodle-borg/{service → assistant-gateway}/dist/assistant-presentation.d.ts +0 -0
- /package/{dist → node_modules/@noodle-borg/deploy-client/dist}/deploy-payload-size.d.ts +0 -0
- /package/{dist → node_modules/@noodle-borg/deploy-client/dist}/deploy-payload-size.d.ts.map +0 -0
- /package/{dist → node_modules/@noodle-borg/deploy-client/dist}/deploy-payload-size.js +0 -0
- /package/{dist → node_modules/@noodle-borg/deploy-client/dist}/deploy-payload-size.js.map +0 -0
- /package/{dist → node_modules/@noodle-borg/deploy-client/dist}/deploy-version.d.ts +0 -0
- /package/{dist → node_modules/@noodle-borg/deploy-client/dist}/deploy-version.d.ts.map +0 -0
- /package/{dist → node_modules/@noodle-borg/deploy-client/dist}/deploy-version.js +0 -0
- /package/{dist → node_modules/@noodle-borg/deploy-client/dist}/deploy-version.js.map +0 -0
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Noodle-side Google identities for the managed knowledge tier (ADR 0202 as amended): the
|
|
3
|
+
* Cloud Run runtime's ADC token impersonates the three least-privilege service accounts
|
|
4
|
+
* (provisioning is operator-only and never wired here; publication and search are). REST only —
|
|
5
|
+
* Apache packages never depend on `@google-cloud/*` — and tokens are cached until near expiry.
|
|
6
|
+
*/
|
|
7
|
+
import type { GoogleAccessTokenProvider } from '@noodle-borg/knowledge';
|
|
8
|
+
/** The Cloud Run / GCE runtime identity via the metadata server (ADC). */
|
|
9
|
+
export declare function metadataServiceTokenProvider(fetchImpl?: typeof fetch): GoogleAccessTokenProvider;
|
|
10
|
+
/**
|
|
11
|
+
* Impersonate one least-privilege service account from a base identity that holds
|
|
12
|
+
* `roles/iam.serviceAccountTokenCreator` on it.
|
|
13
|
+
*/
|
|
14
|
+
export declare function impersonatedTokenProvider(base: GoogleAccessTokenProvider, serviceAccountEmail: string, fetchImpl?: typeof fetch): GoogleAccessTokenProvider;
|
|
15
|
+
//# sourceMappingURL=google-identity.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"google-identity.d.ts","sourceRoot":"","sources":["../src/google-identity.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,wBAAwB,CAAC;AAYxE,0EAA0E;AAC1E,wBAAgB,4BAA4B,CAC1C,SAAS,GAAE,OAAO,KAAa,GAC9B,yBAAyB,CAgB3B;AAED;;;GAGG;AACH,wBAAgB,yBAAyB,CACvC,IAAI,EAAE,yBAAyB,EAC/B,mBAAmB,EAAE,MAAM,EAC3B,SAAS,GAAE,OAAO,KAAa,GAC9B,yBAAyB,CA0B3B"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
const METADATA_TOKEN_URL = 'http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/token';
|
|
2
|
+
const IAM_CREDENTIALS_ROOT = 'https://iamcredentials.googleapis.com/v1';
|
|
3
|
+
const EXPIRY_SKEW_MS = 5 * 60 * 1000;
|
|
4
|
+
/** The Cloud Run / GCE runtime identity via the metadata server (ADC). */
|
|
5
|
+
export function metadataServiceTokenProvider(fetchImpl = fetch) {
|
|
6
|
+
let cached;
|
|
7
|
+
return async () => {
|
|
8
|
+
if (cached !== undefined && Date.now() < cached.expiresAt - EXPIRY_SKEW_MS) {
|
|
9
|
+
return cached.token;
|
|
10
|
+
}
|
|
11
|
+
const response = await fetchImpl(METADATA_TOKEN_URL, {
|
|
12
|
+
headers: { 'Metadata-Flavor': 'Google' },
|
|
13
|
+
});
|
|
14
|
+
if (!response.ok) {
|
|
15
|
+
throw new Error(`metadata token request returned HTTP ${response.status}`);
|
|
16
|
+
}
|
|
17
|
+
const body = (await response.json());
|
|
18
|
+
cached = { token: body.access_token, expiresAt: Date.now() + body.expires_in * 1000 };
|
|
19
|
+
return cached.token;
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Impersonate one least-privilege service account from a base identity that holds
|
|
24
|
+
* `roles/iam.serviceAccountTokenCreator` on it.
|
|
25
|
+
*/
|
|
26
|
+
export function impersonatedTokenProvider(base, serviceAccountEmail, fetchImpl = fetch) {
|
|
27
|
+
let cached;
|
|
28
|
+
return async () => {
|
|
29
|
+
if (cached !== undefined && Date.now() < cached.expiresAt - EXPIRY_SKEW_MS) {
|
|
30
|
+
return cached.token;
|
|
31
|
+
}
|
|
32
|
+
const baseToken = await base();
|
|
33
|
+
const response = await fetchImpl(`${IAM_CREDENTIALS_ROOT}/projects/-/serviceAccounts/${encodeURIComponent(serviceAccountEmail)}:generateAccessToken`, {
|
|
34
|
+
method: 'POST',
|
|
35
|
+
headers: {
|
|
36
|
+
authorization: `Bearer ${baseToken}`,
|
|
37
|
+
'content-type': 'application/json',
|
|
38
|
+
},
|
|
39
|
+
body: JSON.stringify({ scope: ['https://www.googleapis.com/auth/cloud-platform'] }),
|
|
40
|
+
});
|
|
41
|
+
if (!response.ok) {
|
|
42
|
+
// Attributable without detail: the account and status only, never a response body.
|
|
43
|
+
throw new Error(`impersonation of ${serviceAccountEmail} returned HTTP ${response.status}`);
|
|
44
|
+
}
|
|
45
|
+
const body = (await response.json());
|
|
46
|
+
cached = { token: body.accessToken, expiresAt: Date.parse(body.expireTime) };
|
|
47
|
+
return cached.token;
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=google-identity.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"google-identity.js","sourceRoot":"","sources":["../src/google-identity.ts"],"names":[],"mappings":"AAQA,MAAM,kBAAkB,GACtB,4FAA4F,CAAC;AAC/F,MAAM,oBAAoB,GAAG,0CAA0C,CAAC;AACxE,MAAM,cAAc,GAAG,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC;AAOrC,0EAA0E;AAC1E,MAAM,UAAU,4BAA4B,CAC1C,YAA0B,KAAK;IAE/B,IAAI,MAA+B,CAAC;IACpC,OAAO,KAAK,IAAI,EAAE;QAChB,IAAI,MAAM,KAAK,SAAS,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,MAAM,CAAC,SAAS,GAAG,cAAc,EAAE,CAAC;YAC3E,OAAO,MAAM,CAAC,KAAK,CAAC;QACtB,CAAC;QACD,MAAM,QAAQ,GAAG,MAAM,SAAS,CAAC,kBAAkB,EAAE;YACnD,OAAO,EAAE,EAAE,iBAAiB,EAAE,QAAQ,EAAE;SACzC,CAAC,CAAC;QACH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YACjB,MAAM,IAAI,KAAK,CAAC,wCAAwC,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;QAC7E,CAAC;QACD,MAAM,IAAI,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAiD,CAAC;QACrF,MAAM,GAAG,EAAE,KAAK,EAAE,IAAI,CAAC,YAAY,EAAE,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,UAAU,GAAG,IAAI,EAAE,CAAC;QACtF,OAAO,MAAM,CAAC,KAAK,CAAC;IACtB,CAAC,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,yBAAyB,CACvC,IAA+B,EAC/B,mBAA2B,EAC3B,YAA0B,KAAK;IAE/B,IAAI,MAA+B,CAAC;IACpC,OAAO,KAAK,IAAI,EAAE;QAChB,IAAI,MAAM,KAAK,SAAS,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,MAAM,CAAC,SAAS,GAAG,cAAc,EAAE,CAAC;YAC3E,OAAO,MAAM,CAAC,KAAK,CAAC;QACtB,CAAC;QACD,MAAM,SAAS,GAAG,MAAM,IAAI,EAAE,CAAC;QAC/B,MAAM,QAAQ,GAAG,MAAM,SAAS,CAC9B,GAAG,oBAAoB,+BAA+B,kBAAkB,CAAC,mBAAmB,CAAC,sBAAsB,EACnH;YACE,MAAM,EAAE,MAAM;YACd,OAAO,EAAE;gBACP,aAAa,EAAE,UAAU,SAAS,EAAE;gBACpC,cAAc,EAAE,kBAAkB;aACnC;YACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,CAAC,gDAAgD,CAAC,EAAE,CAAC;SACpF,CACF,CAAC;QACF,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YACjB,mFAAmF;YACnF,MAAM,IAAI,KAAK,CAAC,oBAAoB,mBAAmB,kBAAkB,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;QAC9F,CAAC;QACD,MAAM,IAAI,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAgD,CAAC;QACpF,MAAM,GAAG,EAAE,KAAK,EAAE,IAAI,CAAC,WAAW,EAAE,SAAS,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC;QAC7E,OAAO,MAAM,CAAC,KAAK,CAAC;IACtB,CAAC,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Minimal HTTP plumbing for knowledge route handlers. Byte-compatible with the service's
|
|
3
|
+
* wire behavior but deliberately independent of it — a module package never imports the
|
|
4
|
+
* service (the feedback-operations precedent).
|
|
5
|
+
*/
|
|
6
|
+
import type { IncomingMessage, ServerResponse } from 'node:http';
|
|
7
|
+
export declare function sendJson(res: ServerResponse, status: number, body: unknown): void;
|
|
8
|
+
export declare function readBody(req: IncomingMessage, maxBytes: number): Promise<{
|
|
9
|
+
ok: true;
|
|
10
|
+
body: Buffer;
|
|
11
|
+
} | {
|
|
12
|
+
ok: false;
|
|
13
|
+
status: number;
|
|
14
|
+
error: string;
|
|
15
|
+
}>;
|
|
16
|
+
//# sourceMappingURL=http.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../src/http.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAEjE,wBAAgB,QAAQ,CAAC,GAAG,EAAE,cAAc,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,IAAI,CAGjF;AAED,wBAAsB,QAAQ,CAC5B,GAAG,EAAE,eAAe,EACpB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,CAYpF"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export function sendJson(res, status, body) {
|
|
2
|
+
res.writeHead(status, { 'content-type': 'application/json; charset=utf-8' });
|
|
3
|
+
res.end(JSON.stringify(body));
|
|
4
|
+
}
|
|
5
|
+
export async function readBody(req, maxBytes) {
|
|
6
|
+
const chunks = [];
|
|
7
|
+
let total = 0;
|
|
8
|
+
for await (const chunk of req) {
|
|
9
|
+
const buffer = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
|
|
10
|
+
total += buffer.length;
|
|
11
|
+
if (total > maxBytes) {
|
|
12
|
+
return { ok: false, status: 413, error: `request body exceeds ${maxBytes} bytes` };
|
|
13
|
+
}
|
|
14
|
+
chunks.push(buffer);
|
|
15
|
+
}
|
|
16
|
+
return { ok: true, body: Buffer.concat(chunks) };
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=http.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"http.js","sourceRoot":"","sources":["../src/http.ts"],"names":[],"mappings":"AAOA,MAAM,UAAU,QAAQ,CAAC,GAAmB,EAAE,MAAc,EAAE,IAAa;IACzE,GAAG,CAAC,SAAS,CAAC,MAAM,EAAE,EAAE,cAAc,EAAE,iCAAiC,EAAE,CAAC,CAAC;IAC7E,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC;AAChC,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,QAAQ,CAC5B,GAAoB,EACpB,QAAgB;IAEhB,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,IAAI,KAAK,EAAE,MAAM,KAAK,IAAI,GAAG,EAAE,CAAC;QAC9B,MAAM,MAAM,GAAG,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,KAAe,CAAC,CAAC;QAC7E,KAAK,IAAI,MAAM,CAAC,MAAM,CAAC;QACvB,IAAI,KAAK,GAAG,QAAQ,EAAE,CAAC;YACrB,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,KAAK,EAAE,wBAAwB,QAAQ,QAAQ,EAAE,CAAC;QACrF,CAAC;QACD,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACtB,CAAC;IACD,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC;AACnD,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Knowledge control-plane orchestration (ADR 0202 as amended). The service composes these
|
|
3
|
+
* behind its thin dispatch; the CLI never imports this package.
|
|
4
|
+
*/
|
|
5
|
+
export { type StringSecretBox, secretBoxDocumentCodec } from './codec.js';
|
|
6
|
+
export { dispatchKnowledgeRequest, type KnowledgeDispatchDeps } from './dispatch.js';
|
|
7
|
+
export { createKnowledgeSearchExecutor, type KnowledgeSearchComponent, type KnowledgeSearchExecutor, type KnowledgeSearchExecutorDeps, type KnowledgeSearchRequest, } from './executor.js';
|
|
8
|
+
export { impersonatedTokenProvider, metadataServiceTokenProvider, } from './google-identity.js';
|
|
9
|
+
export { readBody, sendJson } from './http.js';
|
|
10
|
+
export { type ManagedGoogleKnowledge, managedGoogleFromEnv, managedSiteProvisioned, managedSiteSearchFor, } from './managed-google.js';
|
|
11
|
+
export { type KnowledgeRouteRef, parseKnowledgePath } from './paths.js';
|
|
12
|
+
export { createKnowledgeDeployHooks, type KnowledgeDeployFailure, type KnowledgeDeployHooks, KnowledgePublicationError, type KnowledgePublicationPlan, withKnowledgePublication, } from './publication.js';
|
|
13
|
+
export { handleKnowledgeDocumentUpload, handleKnowledgePreflight, type KnowledgeRouteDeps, type KnowledgeTenantRef, knowledgeEnableCommand, knowledgeTenantKey, } from './routes.js';
|
|
14
|
+
export { type BoundKnowledgeSearchPort, bindKnowledgeSearchPort, type KnowledgeSearchPortFactory, knowledgeSearchPortFactory, } from './search-port.js';
|
|
15
|
+
export { budgetCeilingsResolver, buildKnowledgeRouteDeps, createPostgresKnowledgeStores, defaultKnowledgeStores, type KnowledgeServiceStores, wireKnowledge, } from './service-wiring.js';
|
|
16
|
+
export { InMemoryKnowledgeStagingStore, type KnowledgeStagingStore, PostgresKnowledgeStagingStore, STAGING_TTL_MS, } from './staging-store.js';
|
|
17
|
+
export { handleKnowledgeList, handleKnowledgeStatus, type KnowledgeStatusDeps, } from './status-routes.js';
|
|
18
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,KAAK,eAAe,EAAE,sBAAsB,EAAE,MAAM,YAAY,CAAC;AAC1E,OAAO,EAAE,wBAAwB,EAAE,KAAK,qBAAqB,EAAE,MAAM,eAAe,CAAC;AACrF,OAAO,EACL,6BAA6B,EAC7B,KAAK,wBAAwB,EAC7B,KAAK,uBAAuB,EAC5B,KAAK,2BAA2B,EAChC,KAAK,sBAAsB,GAC5B,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,yBAAyB,EACzB,4BAA4B,GAC7B,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAC/C,OAAO,EACL,KAAK,sBAAsB,EAC3B,oBAAoB,EACpB,sBAAsB,EACtB,oBAAoB,GACrB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,KAAK,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AACxE,OAAO,EACL,0BAA0B,EAC1B,KAAK,sBAAsB,EAC3B,KAAK,oBAAoB,EACzB,yBAAyB,EACzB,KAAK,wBAAwB,EAC7B,wBAAwB,GACzB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,6BAA6B,EAC7B,wBAAwB,EACxB,KAAK,kBAAkB,EACvB,KAAK,kBAAkB,EACvB,sBAAsB,EACtB,kBAAkB,GACnB,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,KAAK,wBAAwB,EAC7B,uBAAuB,EACvB,KAAK,0BAA0B,EAC/B,0BAA0B,GAC3B,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,sBAAsB,EACtB,uBAAuB,EACvB,6BAA6B,EAC7B,sBAAsB,EACtB,KAAK,sBAAsB,EAC3B,aAAa,GACd,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EACL,6BAA6B,EAC7B,KAAK,qBAAqB,EAC1B,6BAA6B,EAC7B,cAAc,GACf,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,mBAAmB,EACnB,qBAAqB,EACrB,KAAK,mBAAmB,GACzB,MAAM,oBAAoB,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Knowledge control-plane orchestration (ADR 0202 as amended). The service composes these
|
|
3
|
+
* behind its thin dispatch; the CLI never imports this package.
|
|
4
|
+
*/
|
|
5
|
+
export { secretBoxDocumentCodec } from './codec.js';
|
|
6
|
+
export { dispatchKnowledgeRequest } from './dispatch.js';
|
|
7
|
+
export { createKnowledgeSearchExecutor, } from './executor.js';
|
|
8
|
+
export { impersonatedTokenProvider, metadataServiceTokenProvider, } from './google-identity.js';
|
|
9
|
+
export { readBody, sendJson } from './http.js';
|
|
10
|
+
export { managedGoogleFromEnv, managedSiteProvisioned, managedSiteSearchFor, } from './managed-google.js';
|
|
11
|
+
export { parseKnowledgePath } from './paths.js';
|
|
12
|
+
export { createKnowledgeDeployHooks, KnowledgePublicationError, withKnowledgePublication, } from './publication.js';
|
|
13
|
+
export { handleKnowledgeDocumentUpload, handleKnowledgePreflight, knowledgeEnableCommand, knowledgeTenantKey, } from './routes.js';
|
|
14
|
+
export { bindKnowledgeSearchPort, knowledgeSearchPortFactory, } from './search-port.js';
|
|
15
|
+
export { budgetCeilingsResolver, buildKnowledgeRouteDeps, createPostgresKnowledgeStores, defaultKnowledgeStores, wireKnowledge, } from './service-wiring.js';
|
|
16
|
+
export { InMemoryKnowledgeStagingStore, PostgresKnowledgeStagingStore, STAGING_TTL_MS, } from './staging-store.js';
|
|
17
|
+
export { handleKnowledgeList, handleKnowledgeStatus, } from './status-routes.js';
|
|
18
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAwB,sBAAsB,EAAE,MAAM,YAAY,CAAC;AAC1E,OAAO,EAAE,wBAAwB,EAA8B,MAAM,eAAe,CAAC;AACrF,OAAO,EACL,6BAA6B,GAK9B,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,yBAAyB,EACzB,4BAA4B,GAC7B,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAC/C,OAAO,EAEL,oBAAoB,EACpB,sBAAsB,EACtB,oBAAoB,GACrB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAA0B,kBAAkB,EAAE,MAAM,YAAY,CAAC;AACxE,OAAO,EACL,0BAA0B,EAG1B,yBAAyB,EAEzB,wBAAwB,GACzB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,6BAA6B,EAC7B,wBAAwB,EAGxB,sBAAsB,EACtB,kBAAkB,GACnB,MAAM,aAAa,CAAC;AACrB,OAAO,EAEL,uBAAuB,EAEvB,0BAA0B,GAC3B,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,sBAAsB,EACtB,uBAAuB,EACvB,6BAA6B,EAC7B,sBAAsB,EAEtB,aAAa,GACd,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EACL,6BAA6B,EAE7B,6BAA6B,EAC7B,cAAc,GACf,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,mBAAmB,EACnB,qBAAqB,GAEtB,MAAM,oBAAoB,CAAC"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Managed-bundled Google wiring (ADR 0202 as amended): resolve the Noodle-owned project and the
|
|
3
|
+
* two runtime-reachable identities (publication, search) from service environment, bind the
|
|
4
|
+
* sites-half adapter per tenant scope, and answer the honest site-provisioning question. The
|
|
5
|
+
* provisioning identity is deliberately unreachable from here — it exists only for the
|
|
6
|
+
* operator-run `scripts/knowledge-gcp-provision.mjs`.
|
|
7
|
+
*/
|
|
8
|
+
import { type GoogleAccessTokenProvider, type SiteSearch } from '@noodle-borg/knowledge';
|
|
9
|
+
import type { KnowledgeTenantRef } from './routes.js';
|
|
10
|
+
export interface ManagedGoogleKnowledge {
|
|
11
|
+
readonly project: string;
|
|
12
|
+
readonly location: string;
|
|
13
|
+
/** Reaches the deploy path only. */
|
|
14
|
+
readonly publicationTokens: GoogleAccessTokenProvider;
|
|
15
|
+
/** The only identity runtime execution may reach (ADR 0202 D9). */
|
|
16
|
+
readonly searchTokens: GoogleAccessTokenProvider;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Environment contract (set on the hosted service):
|
|
20
|
+
* `NOODLE_KNOWLEDGE_GCP_PROJECT` (required to enable the managed sites tier),
|
|
21
|
+
* `NOODLE_KNOWLEDGE_GCP_LOCATION` (default `global`),
|
|
22
|
+
* `NOODLE_KNOWLEDGE_PUBLICATION_SA` / `NOODLE_KNOWLEDGE_SEARCH_SA` (default the
|
|
23
|
+
* `knowledge-publication@` / `knowledge-search@` accounts in the project).
|
|
24
|
+
*/
|
|
25
|
+
export declare function managedGoogleFromEnv(env: NodeJS.ProcessEnv, fetchImpl?: typeof fetch): ManagedGoogleKnowledge | undefined;
|
|
26
|
+
export declare function managedSiteSearchFor(google: ManagedGoogleKnowledge, tenant: KnowledgeTenantRef): SiteSearch;
|
|
27
|
+
/** Does the tenant's WEBSITE data store exist? Read with the search identity (viewer). */
|
|
28
|
+
export declare function managedSiteProvisioned(google: ManagedGoogleKnowledge, tenant: KnowledgeTenantRef, fetchImpl?: typeof fetch): Promise<boolean>;
|
|
29
|
+
//# sourceMappingURL=managed-google.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"managed-google.d.ts","sourceRoot":"","sources":["../src/managed-google.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EAEL,KAAK,yBAAyB,EAG9B,KAAK,UAAU,EAChB,MAAM,wBAAwB,CAAC;AAEhC,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAEtD,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,oCAAoC;IACpC,QAAQ,CAAC,iBAAiB,EAAE,yBAAyB,CAAC;IACtD,mEAAmE;IACnE,QAAQ,CAAC,YAAY,EAAE,yBAAyB,CAAC;CAClD;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAClC,GAAG,EAAE,MAAM,CAAC,UAAU,EACtB,SAAS,GAAE,OAAO,KAAa,GAC9B,sBAAsB,GAAG,SAAS,CAgBpC;AAED,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,sBAAsB,EAC9B,MAAM,EAAE,kBAAkB,GACzB,UAAU,CAOZ;AAED,0FAA0F;AAC1F,wBAAsB,sBAAsB,CAC1C,MAAM,EAAE,sBAAsB,EAC9B,MAAM,EAAE,kBAAkB,EAC1B,SAAS,GAAE,OAAO,KAAa,GAC9B,OAAO,CAAC,OAAO,CAAC,CAelB"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Managed-bundled Google wiring (ADR 0202 as amended): resolve the Noodle-owned project and the
|
|
3
|
+
* two runtime-reachable identities (publication, search) from service environment, bind the
|
|
4
|
+
* sites-half adapter per tenant scope, and answer the honest site-provisioning question. The
|
|
5
|
+
* provisioning identity is deliberately unreachable from here — it exists only for the
|
|
6
|
+
* operator-run `scripts/knowledge-gcp-provision.mjs`.
|
|
7
|
+
*/
|
|
8
|
+
import { GOOGLE_SITE_COMPONENT, GoogleAgentSearchSites, googleDataStoreId, } from '@noodle-borg/knowledge';
|
|
9
|
+
import { impersonatedTokenProvider, metadataServiceTokenProvider } from './google-identity.js';
|
|
10
|
+
/**
|
|
11
|
+
* Environment contract (set on the hosted service):
|
|
12
|
+
* `NOODLE_KNOWLEDGE_GCP_PROJECT` (required to enable the managed sites tier),
|
|
13
|
+
* `NOODLE_KNOWLEDGE_GCP_LOCATION` (default `global`),
|
|
14
|
+
* `NOODLE_KNOWLEDGE_PUBLICATION_SA` / `NOODLE_KNOWLEDGE_SEARCH_SA` (default the
|
|
15
|
+
* `knowledge-publication@` / `knowledge-search@` accounts in the project).
|
|
16
|
+
*/
|
|
17
|
+
export function managedGoogleFromEnv(env, fetchImpl = fetch) {
|
|
18
|
+
const project = env.NOODLE_KNOWLEDGE_GCP_PROJECT;
|
|
19
|
+
if (project === undefined || project === '')
|
|
20
|
+
return undefined;
|
|
21
|
+
const location = env.NOODLE_KNOWLEDGE_GCP_LOCATION ?? 'global';
|
|
22
|
+
const base = metadataServiceTokenProvider(fetchImpl);
|
|
23
|
+
const publication = env.NOODLE_KNOWLEDGE_PUBLICATION_SA ??
|
|
24
|
+
`knowledge-publication@${project}.iam.gserviceaccount.com`;
|
|
25
|
+
const search = env.NOODLE_KNOWLEDGE_SEARCH_SA ?? `knowledge-search@${project}.iam.gserviceaccount.com`;
|
|
26
|
+
return {
|
|
27
|
+
project,
|
|
28
|
+
location,
|
|
29
|
+
publicationTokens: impersonatedTokenProvider(base, publication, fetchImpl),
|
|
30
|
+
searchTokens: impersonatedTokenProvider(base, search, fetchImpl),
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
export function managedSiteSearchFor(google, tenant) {
|
|
34
|
+
return new GoogleAgentSearchSites({
|
|
35
|
+
project: google.project,
|
|
36
|
+
location: google.location,
|
|
37
|
+
tokenProvider: google.searchTokens,
|
|
38
|
+
scope: { org: tenant.org, app: tenant.app, env: tenant.env },
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
/** Does the tenant's WEBSITE data store exist? Read with the search identity (viewer). */
|
|
42
|
+
export async function managedSiteProvisioned(google, tenant, fetchImpl = fetch) {
|
|
43
|
+
const id = googleDataStoreId({ org: tenant.org, app: tenant.app, env: tenant.env }, GOOGLE_SITE_COMPONENT);
|
|
44
|
+
const token = await google.searchTokens();
|
|
45
|
+
const response = await fetchImpl(`https://discoveryengine.googleapis.com/v1/projects/${google.project}/locations/${google.location}/collections/default_collection/dataStores/${id}`, { headers: { authorization: `Bearer ${token}` } });
|
|
46
|
+
if (response.status === 404)
|
|
47
|
+
return false;
|
|
48
|
+
if (!response.ok) {
|
|
49
|
+
throw new Error(`site datastore check for ${id} returned HTTP ${response.status}`);
|
|
50
|
+
}
|
|
51
|
+
return true;
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=managed-google.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"managed-google.js","sourceRoot":"","sources":["../src/managed-google.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EACL,qBAAqB,EAErB,sBAAsB,EACtB,iBAAiB,GAElB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,yBAAyB,EAAE,4BAA4B,EAAE,MAAM,sBAAsB,CAAC;AAY/F;;;;;;GAMG;AACH,MAAM,UAAU,oBAAoB,CAClC,GAAsB,EACtB,YAA0B,KAAK;IAE/B,MAAM,OAAO,GAAG,GAAG,CAAC,4BAA4B,CAAC;IACjD,IAAI,OAAO,KAAK,SAAS,IAAI,OAAO,KAAK,EAAE;QAAE,OAAO,SAAS,CAAC;IAC9D,MAAM,QAAQ,GAAG,GAAG,CAAC,6BAA6B,IAAI,QAAQ,CAAC;IAC/D,MAAM,IAAI,GAAG,4BAA4B,CAAC,SAAS,CAAC,CAAC;IACrD,MAAM,WAAW,GACf,GAAG,CAAC,+BAA+B;QACnC,yBAAyB,OAAO,0BAA0B,CAAC;IAC7D,MAAM,MAAM,GACV,GAAG,CAAC,0BAA0B,IAAI,oBAAoB,OAAO,0BAA0B,CAAC;IAC1F,OAAO;QACL,OAAO;QACP,QAAQ;QACR,iBAAiB,EAAE,yBAAyB,CAAC,IAAI,EAAE,WAAW,EAAE,SAAS,CAAC;QAC1E,YAAY,EAAE,yBAAyB,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,CAAC;KACjE,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,oBAAoB,CAClC,MAA8B,EAC9B,MAA0B;IAE1B,OAAO,IAAI,sBAAsB,CAAC;QAChC,OAAO,EAAE,MAAM,CAAC,OAAO;QACvB,QAAQ,EAAE,MAAM,CAAC,QAAQ;QACzB,aAAa,EAAE,MAAM,CAAC,YAAY;QAClC,KAAK,EAAE,EAAE,GAAG,EAAE,MAAM,CAAC,GAAG,EAAE,GAAG,EAAE,MAAM,CAAC,GAAG,EAAE,GAAG,EAAE,MAAM,CAAC,GAAG,EAAE;KAC7D,CAAC,CAAC;AACL,CAAC;AAED,0FAA0F;AAC1F,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAC1C,MAA8B,EAC9B,MAA0B,EAC1B,YAA0B,KAAK;IAE/B,MAAM,EAAE,GAAG,iBAAiB,CAC1B,EAAE,GAAG,EAAE,MAAM,CAAC,GAAG,EAAE,GAAG,EAAE,MAAM,CAAC,GAAG,EAAE,GAAG,EAAE,MAAM,CAAC,GAAG,EAAE,EACrD,qBAAqB,CACtB,CAAC;IACF,MAAM,KAAK,GAAG,MAAM,MAAM,CAAC,YAAY,EAAE,CAAC;IAC1C,MAAM,QAAQ,GAAG,MAAM,SAAS,CAC9B,sDAAsD,MAAM,CAAC,OAAO,cAAc,MAAM,CAAC,QAAQ,8CAA8C,EAAE,EAAE,EACnJ,EAAE,OAAO,EAAE,EAAE,aAAa,EAAE,UAAU,KAAK,EAAE,EAAE,EAAE,CAClD,CAAC;IACF,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG;QAAE,OAAO,KAAK,CAAC;IAC1C,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;QACjB,MAAM,IAAI,KAAK,CAAC,4BAA4B,EAAE,kBAAkB,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;IACrF,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Knowledge route path parsing, owned here so the service keeps only a thin dispatch.
|
|
3
|
+
*/
|
|
4
|
+
import type { KnowledgeTenantRef } from './routes.js';
|
|
5
|
+
export type KnowledgeRouteRef = {
|
|
6
|
+
readonly kind: 'preflight';
|
|
7
|
+
readonly tenant: KnowledgeTenantRef;
|
|
8
|
+
} | {
|
|
9
|
+
readonly kind: 'document';
|
|
10
|
+
readonly tenant: KnowledgeTenantRef;
|
|
11
|
+
readonly sha256: string;
|
|
12
|
+
} | {
|
|
13
|
+
readonly kind: 'list';
|
|
14
|
+
readonly tenant: KnowledgeTenantRef;
|
|
15
|
+
} | {
|
|
16
|
+
readonly kind: 'status';
|
|
17
|
+
readonly tenant: KnowledgeTenantRef;
|
|
18
|
+
readonly component: string;
|
|
19
|
+
};
|
|
20
|
+
export declare function parseKnowledgePath(pathname: string): KnowledgeRouteRef | undefined;
|
|
21
|
+
//# sourceMappingURL=paths.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../src/paths.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAEtD,MAAM,MAAM,iBAAiB,GACzB;IAAE,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,kBAAkB,CAAA;CAAE,GACnE;IAAE,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,kBAAkB,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAC3F;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,kBAAkB,CAAA;CAAE,GAC9D;IAAE,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,kBAAkB,CAAC;IAAC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAAC;AAQjG,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,GAAG,iBAAiB,GAAG,SAAS,CAkClF"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
const PREFLIGHT = /^\/v1\/orgs\/([^/]+)\/apps\/([^/]+)\/envs\/([^/]+)\/knowledge\/preflight$/;
|
|
2
|
+
const DOCUMENT = /^\/v1\/orgs\/([^/]+)\/apps\/([^/]+)\/envs\/([^/]+)\/knowledge\/documents\/([^/]+)$/;
|
|
3
|
+
const LIST = /^\/v1\/orgs\/([^/]+)\/apps\/([^/]+)\/envs\/([^/]+)\/knowledge$/;
|
|
4
|
+
const STATUS = /^\/v1\/orgs\/([^/]+)\/apps\/([^/]+)\/envs\/([^/]+)\/knowledge\/([^/]+)\/status$/;
|
|
5
|
+
export function parseKnowledgePath(pathname) {
|
|
6
|
+
const preflight = PREFLIGHT.exec(pathname);
|
|
7
|
+
if (preflight !== null) {
|
|
8
|
+
const [, org, app, env] = preflight;
|
|
9
|
+
return { kind: 'preflight', tenant: { org, app, env } };
|
|
10
|
+
}
|
|
11
|
+
const list = LIST.exec(pathname);
|
|
12
|
+
if (list !== null) {
|
|
13
|
+
const [, org, app, env] = list;
|
|
14
|
+
return { kind: 'list', tenant: { org, app, env } };
|
|
15
|
+
}
|
|
16
|
+
const status = STATUS.exec(pathname);
|
|
17
|
+
if (status !== null) {
|
|
18
|
+
const [, org, app, env, component] = status;
|
|
19
|
+
return { kind: 'status', tenant: { org, app, env }, component };
|
|
20
|
+
}
|
|
21
|
+
const document = DOCUMENT.exec(pathname);
|
|
22
|
+
if (document !== null) {
|
|
23
|
+
const [, org, app, env, sha256] = document;
|
|
24
|
+
return { kind: 'document', tenant: { org, app, env }, sha256 };
|
|
25
|
+
}
|
|
26
|
+
return undefined;
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=paths.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"paths.js","sourceRoot":"","sources":["../src/paths.ts"],"names":[],"mappings":"AAWA,MAAM,SAAS,GAAG,2EAA2E,CAAC;AAC9F,MAAM,QAAQ,GACZ,oFAAoF,CAAC;AACvF,MAAM,IAAI,GAAG,gEAAgE,CAAC;AAC9E,MAAM,MAAM,GAAG,iFAAiF,CAAC;AAEjG,MAAM,UAAU,kBAAkB,CAAC,QAAgB;IACjD,MAAM,SAAS,GAAG,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IAC3C,IAAI,SAAS,KAAK,IAAI,EAAE,CAAC;QACvB,MAAM,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,GAAG,SAAwD,CAAC;QACnF,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE,CAAC;IAC1D,CAAC;IACD,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IACjC,IAAI,IAAI,KAAK,IAAI,EAAE,CAAC;QAClB,MAAM,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,GAAG,IAAmD,CAAC;QAC9E,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE,CAAC;IACrD,CAAC;IACD,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IACrC,IAAI,MAAM,KAAK,IAAI,EAAE,CAAC;QACpB,MAAM,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,SAAS,CAAC,GAAG,MAMpC,CAAC;QACF,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE,SAAS,EAAE,CAAC;IAClE,CAAC;IACD,MAAM,QAAQ,GAAG,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IACzC,IAAI,QAAQ,KAAK,IAAI,EAAE,CAAC;QACtB,MAAM,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,MAAM,CAAC,GAAG,QAMjC,CAAC;QACF,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE,MAAM,EAAE,CAAC;IACjE,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The deploy-coupled knowledge publication transaction (ADR 0202): lease → resolve bytes or
|
|
3
|
+
* reuse → stage (bundled index + revision + durable sealed text) → verify a positive filtered
|
|
4
|
+
* query → activate + pin, paired with the caller's artifact persistence. Any failure retains
|
|
5
|
+
* the previous artifact + revision pair; retry is idempotent by content hash.
|
|
6
|
+
*/
|
|
7
|
+
import { type CompiledKnowledgeComponent, type KnowledgeScope, type SearchHit, type SearchRequest } from '@noodle-borg/knowledge';
|
|
8
|
+
import { type KnowledgeTenantRef } from './routes.js';
|
|
9
|
+
import type { KnowledgeServiceStores } from './service-wiring.js';
|
|
10
|
+
export interface KnowledgeDeployFailure {
|
|
11
|
+
readonly code: string;
|
|
12
|
+
readonly path: string;
|
|
13
|
+
readonly message: string;
|
|
14
|
+
}
|
|
15
|
+
/** Structured publication failure the registry maps onto its deploy error shape. */
|
|
16
|
+
export declare class KnowledgePublicationError extends Error {
|
|
17
|
+
readonly errors: readonly KnowledgeDeployFailure[];
|
|
18
|
+
constructor(errors: readonly KnowledgeDeployFailure[]);
|
|
19
|
+
}
|
|
20
|
+
interface PlannedComponent {
|
|
21
|
+
readonly component: CompiledKnowledgeComponent;
|
|
22
|
+
readonly scope: KnowledgeScope;
|
|
23
|
+
readonly revisionId: string;
|
|
24
|
+
readonly previousRevisionId?: string;
|
|
25
|
+
readonly lease: {
|
|
26
|
+
readonly scopeKey: string;
|
|
27
|
+
readonly leaseId: string;
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
export interface KnowledgePublicationPlan {
|
|
31
|
+
readonly components: readonly PlannedComponent[];
|
|
32
|
+
}
|
|
33
|
+
export interface KnowledgeDeployHooks {
|
|
34
|
+
publish(tenant: KnowledgeTenantRef, deploymentId: string, components: readonly CompiledKnowledgeComponent[]): Promise<KnowledgePublicationPlan>;
|
|
35
|
+
activate(plan: KnowledgePublicationPlan, deploymentId: string): Promise<void>;
|
|
36
|
+
/** Re-activate the previous revisions after a persistence failure. */
|
|
37
|
+
compensate(plan: KnowledgePublicationPlan, deploymentId: string): Promise<void>;
|
|
38
|
+
/** Release leases; always runs, success or failure. */
|
|
39
|
+
finish(plan: KnowledgePublicationPlan): Promise<void>;
|
|
40
|
+
/** Reselect every revision the deployment pinned; the bundled index rebuilds lazily. */
|
|
41
|
+
rollback(deploymentId: string): Promise<void>;
|
|
42
|
+
/** Search the active document revision, rebuilding the bundled index when stale. */
|
|
43
|
+
searchDocuments(scope: KnowledgeScope, componentName: string, request: SearchRequest): Promise<readonly SearchHit[]>;
|
|
44
|
+
/** Throttled GC: expired staging entries and unreferenced revisions. */
|
|
45
|
+
sweep(): Promise<void>;
|
|
46
|
+
}
|
|
47
|
+
export declare function createKnowledgeDeployHooks(stores: KnowledgeServiceStores, options: {
|
|
48
|
+
readonly knowledgeEnabled: (tenant: KnowledgeTenantRef) => Promise<boolean>;
|
|
49
|
+
/** Managed site datastore existence; when bound, a site() deploy fails before activation. */
|
|
50
|
+
readonly siteProvisioned?: (tenant: KnowledgeTenantRef) => Promise<boolean>;
|
|
51
|
+
readonly now?: () => Date;
|
|
52
|
+
}): KnowledgeDeployHooks;
|
|
53
|
+
/**
|
|
54
|
+
* Wrap the caller's persistence step in the full publication transaction. The order is the
|
|
55
|
+
* ADR 0202 pairing: stage + verify + activate the revision, persist the artifact, and on a
|
|
56
|
+
* persistence failure re-activate the previous revision so the retained pair stays coherent.
|
|
57
|
+
*/
|
|
58
|
+
export declare function withKnowledgePublication<T>(hooks: KnowledgeDeployHooks | undefined, tenant: KnowledgeTenantRef, deploymentId: string, components: readonly CompiledKnowledgeComponent[] | undefined, persist: () => Promise<T>): Promise<T>;
|
|
59
|
+
export {};
|
|
60
|
+
//# sourceMappingURL=publication.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"publication.d.ts","sourceRoot":"","sources":["../src/publication.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAEL,KAAK,0BAA0B,EAK/B,KAAK,cAAc,EACnB,KAAK,SAAS,EACd,KAAK,aAAa,EAEnB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,KAAK,kBAAkB,EAA8C,MAAM,aAAa,CAAC;AAClG,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAC;AAElE,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AAED,oFAAoF;AACpF,qBAAa,yBAA0B,SAAQ,KAAK;IAClD,QAAQ,CAAC,MAAM,EAAE,SAAS,sBAAsB,EAAE,CAAC;gBAEvC,MAAM,EAAE,SAAS,sBAAsB,EAAE;CAKtD;AAED,UAAU,gBAAgB;IACxB,QAAQ,CAAC,SAAS,EAAE,0BAA0B,CAAC;IAC/C,QAAQ,CAAC,KAAK,EAAE,cAAc,CAAC;IAC/B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IACrC,QAAQ,CAAC,KAAK,EAAE;QAAE,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;CACzE;AAED,MAAM,WAAW,wBAAwB;IACvC,QAAQ,CAAC,UAAU,EAAE,SAAS,gBAAgB,EAAE,CAAC;CAClD;AAED,MAAM,WAAW,oBAAoB;IACnC,OAAO,CACL,MAAM,EAAE,kBAAkB,EAC1B,YAAY,EAAE,MAAM,EACpB,UAAU,EAAE,SAAS,0BAA0B,EAAE,GAChD,OAAO,CAAC,wBAAwB,CAAC,CAAC;IACrC,QAAQ,CAAC,IAAI,EAAE,wBAAwB,EAAE,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9E,sEAAsE;IACtE,UAAU,CAAC,IAAI,EAAE,wBAAwB,EAAE,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAChF,uDAAuD;IACvD,MAAM,CAAC,IAAI,EAAE,wBAAwB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACtD,wFAAwF;IACxF,QAAQ,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9C,oFAAoF;IACpF,eAAe,CACb,KAAK,EAAE,cAAc,EACrB,aAAa,EAAE,MAAM,EACrB,OAAO,EAAE,aAAa,GACrB,OAAO,CAAC,SAAS,SAAS,EAAE,CAAC,CAAC;IACjC,wEAAwE;IACxE,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB;AAOD,wBAAgB,0BAA0B,CACxC,MAAM,EAAE,sBAAsB,EAC9B,OAAO,EAAE;IACP,QAAQ,CAAC,gBAAgB,EAAE,CAAC,MAAM,EAAE,kBAAkB,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IAC5E,6FAA6F;IAC7F,QAAQ,CAAC,eAAe,CAAC,EAAE,CAAC,MAAM,EAAE,kBAAkB,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IAC5E,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,IAAI,CAAC;CAC3B,GACA,oBAAoB,CAyNtB;AAMD;;;;GAIG;AACH,wBAAsB,wBAAwB,CAAC,CAAC,EAC9C,KAAK,EAAE,oBAAoB,GAAG,SAAS,EACvC,MAAM,EAAE,kBAAkB,EAC1B,YAAY,EAAE,MAAM,EACpB,UAAU,EAAE,SAAS,0BAA0B,EAAE,GAAG,SAAS,EAC7D,OAAO,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GACxB,OAAO,CAAC,CAAC,CAAC,CAgBZ"}
|
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The deploy-coupled knowledge publication transaction (ADR 0202): lease → resolve bytes or
|
|
3
|
+
* reuse → stage (bundled index + revision + durable sealed text) → verify a positive filtered
|
|
4
|
+
* query → activate + pin, paired with the caller's artifact persistence. Any failure retains
|
|
5
|
+
* the previous artifact + revision pair; retry is idempotent by content hash.
|
|
6
|
+
*/
|
|
7
|
+
import { Bm25KnowledgeIndex, documentsContentHash, identityDocumentTextCodec, KnowledgeError, } from '@noodle-borg/knowledge';
|
|
8
|
+
import { knowledgeEnableCommand, knowledgeTenantKey } from './routes.js';
|
|
9
|
+
/** Structured publication failure the registry maps onto its deploy error shape. */
|
|
10
|
+
export class KnowledgePublicationError extends Error {
|
|
11
|
+
errors;
|
|
12
|
+
constructor(errors) {
|
|
13
|
+
super(errors[0]?.message ?? 'knowledge publication failed');
|
|
14
|
+
this.name = 'KnowledgePublicationError';
|
|
15
|
+
this.errors = errors;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
/** How long a cached active-revision check may serve before re-reading the durable store. */
|
|
19
|
+
const ACTIVE_REVISION_TTL_MS = 5_000;
|
|
20
|
+
/** Deploy-piggybacked GC cadence (the archive-sweeper pattern). */
|
|
21
|
+
const SWEEP_INTERVAL_MS = 10 * 60 * 1000;
|
|
22
|
+
export function createKnowledgeDeployHooks(stores, options) {
|
|
23
|
+
const index = new Bm25KnowledgeIndex();
|
|
24
|
+
const codec = stores.codec ?? identityDocumentTextCodec;
|
|
25
|
+
const now = options.now ?? (() => new Date());
|
|
26
|
+
const activeChecks = new Map();
|
|
27
|
+
let lastSweep = 0;
|
|
28
|
+
/** Staged text for a component, from durable revision text or transient staging. */
|
|
29
|
+
async function resolveDocuments(tenant, component, existingRevisionId) {
|
|
30
|
+
if (existingRevisionId !== undefined) {
|
|
31
|
+
try {
|
|
32
|
+
return [...(await stores.revisionStore.documents(existingRevisionId))];
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
// Reused revision without durable text (staged pre-migration or interrupted) — fall
|
|
36
|
+
// back to transient staging below.
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
const tenantKey = knowledgeTenantKey(tenant);
|
|
40
|
+
const documents = [];
|
|
41
|
+
for (const descriptor of component.documents) {
|
|
42
|
+
const sealed = await stores.staging.get(tenantKey, descriptor.sha256);
|
|
43
|
+
if (sealed === undefined) {
|
|
44
|
+
throw new KnowledgePublicationError([
|
|
45
|
+
{
|
|
46
|
+
code: 'knowledge_documents_missing',
|
|
47
|
+
path: `knowledge.${component.name}.${descriptor.path}`,
|
|
48
|
+
message: `knowledge document ${descriptor.path} has no staged bytes; ` +
|
|
49
|
+
`run noodle deploy again to re-upload (retry is idempotent)`,
|
|
50
|
+
},
|
|
51
|
+
]);
|
|
52
|
+
}
|
|
53
|
+
documents.push({
|
|
54
|
+
descriptor: {
|
|
55
|
+
path: descriptor.path,
|
|
56
|
+
title: descriptor.title,
|
|
57
|
+
...(descriptor.sourceUrl !== undefined ? { sourceUrl: descriptor.sourceUrl } : {}),
|
|
58
|
+
sha256: descriptor.sha256,
|
|
59
|
+
bytes: descriptor.bytes,
|
|
60
|
+
},
|
|
61
|
+
text: (await codec.open(sealed)).toString('utf8'),
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
return documents;
|
|
65
|
+
}
|
|
66
|
+
/** Make sure the in-process index holds and activates the given revision. */
|
|
67
|
+
async function rebuildIndex(scope, componentName, revisionId) {
|
|
68
|
+
const current = await index.activeRevision(scope, componentName);
|
|
69
|
+
if (current?.revisionId === revisionId)
|
|
70
|
+
return;
|
|
71
|
+
const documents = await stores.revisionStore.documents(revisionId);
|
|
72
|
+
const staged = await index.stage(scope, componentName, documents);
|
|
73
|
+
if (staged.revisionId !== revisionId) {
|
|
74
|
+
throw new KnowledgeError('store', `rebuilt index revision ${staged.revisionId} does not match stored ${revisionId}`);
|
|
75
|
+
}
|
|
76
|
+
await index.activate(revisionId);
|
|
77
|
+
}
|
|
78
|
+
const hooks = {
|
|
79
|
+
async publish(tenant, deploymentId, components) {
|
|
80
|
+
const withDocuments = components.filter((component) => component.documents.length > 0);
|
|
81
|
+
if (components.length > 0 && !(await options.knowledgeEnabled(tenant))) {
|
|
82
|
+
throw new KnowledgePublicationError([
|
|
83
|
+
{
|
|
84
|
+
code: 'knowledge_not_enabled',
|
|
85
|
+
path: 'knowledge',
|
|
86
|
+
message: `knowledge is not enabled for this org/app/env; run: ${knowledgeEnableCommand(tenant)}`,
|
|
87
|
+
},
|
|
88
|
+
]);
|
|
89
|
+
}
|
|
90
|
+
const withSites = components.filter((component) => component.sites.length > 0);
|
|
91
|
+
if (withSites.length > 0 && options.siteProvisioned !== undefined) {
|
|
92
|
+
if (!(await options.siteProvisioned(tenant))) {
|
|
93
|
+
throw new KnowledgePublicationError(withSites.map((component) => ({
|
|
94
|
+
code: 'knowledge_site_not_provisioned',
|
|
95
|
+
path: `knowledge.${component.name}`,
|
|
96
|
+
message: `the managed site datastore for this tenant does not exist yet; an operator must ` +
|
|
97
|
+
`run scripts/knowledge-gcp-provision.mjs --tenant ${tenant.org}/${tenant.app}/${tenant.env}, ` +
|
|
98
|
+
`then check noodle knowledge status ${component.name}`,
|
|
99
|
+
})));
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
const planned = [];
|
|
103
|
+
try {
|
|
104
|
+
for (const component of withDocuments) {
|
|
105
|
+
const scope = { org: tenant.org, app: tenant.app, env: tenant.env };
|
|
106
|
+
const lease = await stores.revisionStore.acquireLease(scope, component.name, deploymentId);
|
|
107
|
+
const contentHash = documentsContentHash(component.documents.map((document) => document.sha256));
|
|
108
|
+
const previous = await stores.revisionStore.active(scope, component.name);
|
|
109
|
+
const reused = await stores.revisionStore.findByContentHash(scope, component.name, contentHash);
|
|
110
|
+
const documents = await resolveDocuments(tenant, component, reused?.revisionId);
|
|
111
|
+
const staged = await index.stage(scope, component.name, documents);
|
|
112
|
+
const revision = reused ?? staged;
|
|
113
|
+
await stores.revisionStore.stage({
|
|
114
|
+
scope,
|
|
115
|
+
componentName: component.name,
|
|
116
|
+
contentHash,
|
|
117
|
+
revision,
|
|
118
|
+
});
|
|
119
|
+
const verified = await index.verify(staged.revisionId, {
|
|
120
|
+
audience: 'public',
|
|
121
|
+
revision: staged.revisionId,
|
|
122
|
+
});
|
|
123
|
+
if (!verified) {
|
|
124
|
+
throw new KnowledgePublicationError([
|
|
125
|
+
{
|
|
126
|
+
code: 'knowledge_verification_failed',
|
|
127
|
+
path: `knowledge.${component.name}`,
|
|
128
|
+
message: `knowledge component ${component.name} failed its positive filtered verification query`,
|
|
129
|
+
},
|
|
130
|
+
]);
|
|
131
|
+
}
|
|
132
|
+
await stores.revisionStore.stageDocuments(revision.revisionId, documents);
|
|
133
|
+
planned.push({
|
|
134
|
+
component,
|
|
135
|
+
scope,
|
|
136
|
+
revisionId: revision.revisionId,
|
|
137
|
+
...(previous !== undefined ? { previousRevisionId: previous.revisionId } : {}),
|
|
138
|
+
lease,
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
catch (error) {
|
|
143
|
+
await hooks.finish({ components: planned });
|
|
144
|
+
throw error;
|
|
145
|
+
}
|
|
146
|
+
return { components: planned };
|
|
147
|
+
},
|
|
148
|
+
async activate(plan, deploymentId) {
|
|
149
|
+
for (const planned of plan.components) {
|
|
150
|
+
await stores.revisionStore.activate(planned.scope, planned.component.name, planned.revisionId, deploymentId);
|
|
151
|
+
await rebuildIndex(planned.scope, planned.component.name, planned.revisionId);
|
|
152
|
+
activeChecks.delete(knowledgeScopeCacheKey(planned.scope, planned.component.name));
|
|
153
|
+
}
|
|
154
|
+
},
|
|
155
|
+
async compensate(plan, deploymentId) {
|
|
156
|
+
for (const planned of plan.components) {
|
|
157
|
+
if (planned.previousRevisionId === undefined)
|
|
158
|
+
continue;
|
|
159
|
+
// Pinning the previous revision to the failed deployment id is harmless: the record
|
|
160
|
+
// never persisted, and the pin only widens GC protection of the retained revision.
|
|
161
|
+
await stores.revisionStore.activate(planned.scope, planned.component.name, planned.previousRevisionId, deploymentId);
|
|
162
|
+
activeChecks.delete(knowledgeScopeCacheKey(planned.scope, planned.component.name));
|
|
163
|
+
}
|
|
164
|
+
},
|
|
165
|
+
async finish(plan) {
|
|
166
|
+
for (const planned of plan.components) {
|
|
167
|
+
await stores.revisionStore.releaseLease(planned.lease);
|
|
168
|
+
}
|
|
169
|
+
},
|
|
170
|
+
async rollback(deploymentId) {
|
|
171
|
+
const restored = await stores.revisionStore.rollback(deploymentId);
|
|
172
|
+
for (const revision of restored) {
|
|
173
|
+
activeChecks.delete(knowledgeScopeCacheKey(revision.scope, revision.componentName));
|
|
174
|
+
}
|
|
175
|
+
},
|
|
176
|
+
async searchDocuments(scope, componentName, request) {
|
|
177
|
+
const cacheKey = knowledgeScopeCacheKey(scope, componentName);
|
|
178
|
+
const cached = activeChecks.get(cacheKey);
|
|
179
|
+
let revisionId;
|
|
180
|
+
if (cached !== undefined && now().getTime() - cached.checkedAt <= ACTIVE_REVISION_TTL_MS) {
|
|
181
|
+
revisionId = cached.revisionId;
|
|
182
|
+
}
|
|
183
|
+
else {
|
|
184
|
+
revisionId = (await stores.revisionStore.active(scope, componentName))?.revisionId;
|
|
185
|
+
activeChecks.set(cacheKey, { revisionId, checkedAt: now().getTime() });
|
|
186
|
+
}
|
|
187
|
+
if (revisionId === undefined)
|
|
188
|
+
return [];
|
|
189
|
+
await rebuildIndex(scope, componentName, revisionId);
|
|
190
|
+
return index.search(scope, componentName, request);
|
|
191
|
+
},
|
|
192
|
+
async sweep() {
|
|
193
|
+
const at = now().getTime();
|
|
194
|
+
if (at - lastSweep < SWEEP_INTERVAL_MS)
|
|
195
|
+
return;
|
|
196
|
+
lastSweep = at;
|
|
197
|
+
await stores.staging.sweepExpired();
|
|
198
|
+
await stores.revisionStore.collectGarbage();
|
|
199
|
+
},
|
|
200
|
+
};
|
|
201
|
+
return hooks;
|
|
202
|
+
}
|
|
203
|
+
function knowledgeScopeCacheKey(scope, componentName) {
|
|
204
|
+
return `${scope.org}/${scope.app}/${scope.env}#${componentName}`;
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* Wrap the caller's persistence step in the full publication transaction. The order is the
|
|
208
|
+
* ADR 0202 pairing: stage + verify + activate the revision, persist the artifact, and on a
|
|
209
|
+
* persistence failure re-activate the previous revision so the retained pair stays coherent.
|
|
210
|
+
*/
|
|
211
|
+
export async function withKnowledgePublication(hooks, tenant, deploymentId, components, persist) {
|
|
212
|
+
if (hooks === undefined || components === undefined || components.length === 0) {
|
|
213
|
+
return persist();
|
|
214
|
+
}
|
|
215
|
+
const plan = await hooks.publish(tenant, deploymentId, components);
|
|
216
|
+
try {
|
|
217
|
+
await hooks.activate(plan, deploymentId);
|
|
218
|
+
const result = await persist();
|
|
219
|
+
void hooks.sweep().catch(() => undefined);
|
|
220
|
+
return result;
|
|
221
|
+
}
|
|
222
|
+
catch (error) {
|
|
223
|
+
await hooks.compensate(plan, deploymentId).catch(() => undefined);
|
|
224
|
+
throw error;
|
|
225
|
+
}
|
|
226
|
+
finally {
|
|
227
|
+
await hooks.finish(plan);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
//# sourceMappingURL=publication.js.map
|