History

Trace source connect and stop typegen from blocking it

Rhys Sullivan committed 8 months ago

Commit 334475b1 parent 3b054b117 files · +1086 −105Browse files

Unified · Split

17 files
  1. TRACING.md +43 −0
  2. bun.lock +118 −0
  3. compose.tracing.yaml +9 −0
  4. package.json +2 −0
  5. packages/control-plane/package.json +2 −2
  6. packages/control-plane/src/runtime/index.ts +2 −5
  7. packages/control-plane/src/runtime/source-adapters/graphql.ts +59 −11
  8. packages/control-plane/src/runtime/source-auth-service.ts +19 −3
  9. packages/control-plane/src/runtime/source-catalog-sync.ts +10 −1
  10. packages/control-plane/src/runtime/source-store.ts +48 −10
  11. packages/control-plane/src/runtime/source-type-declarations.test.ts +48 −1
  12. packages/control-plane/src/runtime/source-type-declarations.ts +561 −69
  13. packages/server/package.json +8 −0
  14. packages/server/src/config.ts +5 −0
  15. packages/server/src/index.ts +36 −3
  16. packages/server/src/tracing.ts +66 −0
  17. personal-notes/otel-tracing-for-source-connect.md +50 −0
TRACING.md+43−0
@@ -0,0 +1,43 @@
1# Local Tracing
2
3Start Jaeger locally:
4
5```bash
6bun run trace:up
7```
8
9Run the web/server dev process with tracing enabled:
10
11```bash
12EXECUTOR_TRACE_ENABLED=1 \
13EXECUTOR_TRACE_SERVICE_NAME=executor-local \
14EXECUTOR_TRACE_OTLP_ENDPOINT=http://127.0.0.1:4317 \
15bun run dev
16```
17
18Then open Jaeger:
19
20- UI: `http://127.0.0.1:16686/search?service=executor-local`
21
22You can also query traces over HTTP:
23
24```bash
25curl "http://127.0.0.1:16686/api/traces?service=executor-local&limit=20"
26```
27
28Useful operations to search for:
29
30- `source.connect.http`
31- `source.catalog.sync`
32- `graphql.syncCatalog`
33- `graphql.introspection.fetch`
34- `graphql.manifest.extract`
35- `graphql.definitions.compile`
36- `graphql.operations.build`
37- `graphql.snapshot.build`
38
39Stop Jaeger:
40
41```bash
42bun run trace:down
43```
bun.lock+118−0
@@ -284,9 +284,17 @@ · 283 unmodified lines
284 "packages/server": {284 "packages/server": {
285 "name": "@executor/server",285 "name": "@executor/server",
286 "dependencies": {286 "dependencies": {
287 "@effect/opentelemetry": "^0.61.0",
287 "@effect/platform": "catalog:",288 "@effect/platform": "catalog:",
288 "@executor/control-plane": "workspace:*",289 "@executor/control-plane": "workspace:*",
289 "@executor/executor-mcp": "workspace:*",290 "@executor/executor-mcp": "workspace:*",
291 "@opentelemetry/api": "^1.9.0",
292 "@opentelemetry/exporter-trace-otlp-grpc": "^0.213.0",
293 "@opentelemetry/exporter-trace-otlp-http": "^0.213.0",
294 "@opentelemetry/resources": "^2.6.0",
295 "@opentelemetry/sdk-trace-base": "^2.6.0",
296 "@opentelemetry/sdk-trace-node": "^2.6.0",
297 "@opentelemetry/semantic-conventions": "^1.40.0",
290 "effect": "catalog:",298 "effect": "catalog:",
291 },299 },
292 "devDependencies": {300 "devDependencies": {
@@ -375,6 +383,8 @@ · 82 unmodified lines
375 383
376 "@effect/experimental": ["@effect/experimental@0.58.0", "", { "dependencies": { "uuid": "^11.0.3" }, "peerDependencies": { "@effect/platform": "^0.94.0", "effect": "^3.19.13", "ioredis": "^5", "lmdb": "^3" }, "optionalPeers": ["ioredis", "lmdb"] }, "sha512-IEP9sapjF6rFy5TkoqDPc86st/fnqUfjT7Xa3pWJrFGr1hzaMXHo+mWsYOZS9LAOVKnpHuVziDK97EP5qsCHVA=="],384 "@effect/experimental": ["@effect/experimental@0.58.0", "", { "dependencies": { "uuid": "^11.0.3" }, "peerDependencies": { "@effect/platform": "^0.94.0", "effect": "^3.19.13", "ioredis": "^5", "lmdb": "^3" }, "optionalPeers": ["ioredis", "lmdb"] }, "sha512-IEP9sapjF6rFy5TkoqDPc86st/fnqUfjT7Xa3pWJrFGr1hzaMXHo+mWsYOZS9LAOVKnpHuVziDK97EP5qsCHVA=="],
377 385
386 "@effect/opentelemetry": ["@effect/opentelemetry@0.61.0", "", { "peerDependencies": { "@effect/platform": "^0.94.2", "@opentelemetry/api": "^1.9", "@opentelemetry/resources": "^2.0.0", "@opentelemetry/sdk-logs": ">=0.203.0 <0.300.0", "@opentelemetry/sdk-metrics": "^2.0.0", "@opentelemetry/sdk-trace-base": "^2.0.0", "@opentelemetry/sdk-trace-node": "^2.0.0", "@opentelemetry/sdk-trace-web": "^2.0.0", "@opentelemetry/semantic-conventions": "^1.33.0", "effect": "^3.19.15" } }, "sha512-aTg4qWzMxGDoUZKSyws/dMZqVNoSCQIvHaPDJnWitUAVuWDAPOXiaiHJDWO39cwDlySBTCSF6rEanm3+nR/2Mg=="],
387
378 "@effect/platform": ["@effect/platform@0.94.5", "", { "dependencies": { "find-my-way-ts": "^0.1.6", "msgpackr": "^1.11.4", "multipasta": "^0.2.7" }, "peerDependencies": { "effect": "^3.19.17" } }, "sha512-z05APUiDDPbodhTkH/RJqOLoCU11bU2IZLfcwLFrld03+ob1VeqRnELQlmueLIYm6NZifHAtjl32V+GRt34y4A=="],388 "@effect/platform": ["@effect/platform@0.94.5", "", { "dependencies": { "find-my-way-ts": "^0.1.6", "msgpackr": "^1.11.4", "multipasta": "^0.2.7" }, "peerDependencies": { "effect": "^3.19.17" } }, "sha512-z05APUiDDPbodhTkH/RJqOLoCU11bU2IZLfcwLFrld03+ob1VeqRnELQlmueLIYm6NZifHAtjl32V+GRt34y4A=="],
379 389
380 "@effect/platform-node": ["@effect/platform-node@0.104.1", "", { "dependencies": { "@effect/platform-node-shared": "^0.57.1", "mime": "^3.0.0", "undici": "^7.10.0", "ws": "^8.18.2" }, "peerDependencies": { "@effect/cluster": "^0.56.1", "@effect/platform": "^0.94.2", "@effect/rpc": "^0.73.0", "@effect/sql": "^0.49.0", "effect": "^3.19.15" } }, "sha512-jT1a/z98niK6fnEU8pWHPPCdJMVDRCIdB65lolcOjse5rsTwVbczMjvKkhVQpF63mNWoOnol7OTRNkw5L54llg=="],390 "@effect/platform-node": ["@effect/platform-node@0.104.1", "", { "dependencies": { "@effect/platform-node-shared": "^0.57.1", "mime": "^3.0.0", "undici": "^7.10.0", "ws": "^8.18.2" }, "peerDependencies": { "@effect/cluster": "^0.56.1", "@effect/platform": "^0.94.2", "@effect/rpc": "^0.73.0", "@effect/sql": "^0.49.0", "effect": "^3.19.15" } }, "sha512-jT1a/z98niK6fnEU8pWHPPCdJMVDRCIdB65lolcOjse5rsTwVbczMjvKkhVQpF63mNWoOnol7OTRNkw5L54llg=="],
@@ -491,6 +501,10 @@ · 110 unmodified lines
491 501
492 "@executor/web": ["@executor/web@workspace:apps/web"],502 "@executor/web": ["@executor/web@workspace:apps/web"],
493 503
504 "@grpc/grpc-js": ["@grpc/grpc-js@1.14.3", "", { "dependencies": { "@grpc/proto-loader": "^0.8.0", "@js-sdsl/ordered-map": "^4.4.2" } }, "sha512-Iq8QQQ/7X3Sac15oB6p0FmUg/klxQvXLeileoqrTRGJYLV+/9tubbr9ipz0GKHjmXVsgFPo/+W+2cA8eNcR+XA=="],
505
506 "@grpc/proto-loader": ["@grpc/proto-loader@0.8.0", "", { "dependencies": { "lodash.camelcase": "^4.3.0", "long": "^5.0.0", "protobufjs": "^7.5.3", "yargs": "^17.7.2" }, "bin": { "proto-loader-gen-types": "build/bin/proto-loader-gen-types.js" } }, "sha512-rc1hOQtjIWGxcxpb9aHAfLpIctjEnsDehj0DAiVfBlmT84uvR0uUtN2hEi/ecvWVjXUGf5qPF4qEgiLOx1YIMQ=="],
507
494 "@hono/node-server": ["@hono/node-server@1.19.11", "", { "peerDependencies": { "hono": "^4" } }, "sha512-dr8/3zEaB+p0D2n/IUrlPF1HZm586qgJNXK1a9fhg/PzdtkK7Ksd5l312tJX2yBuALqDYBlG20QEbayqPyxn+g=="],508 "@hono/node-server": ["@hono/node-server@1.19.11", "", { "peerDependencies": { "hono": "^4" } }, "sha512-dr8/3zEaB+p0D2n/IUrlPF1HZm586qgJNXK1a9fhg/PzdtkK7Ksd5l312tJX2yBuALqDYBlG20QEbayqPyxn+g=="],
495 509
496 "@hono/vite-dev-server": ["@hono/vite-dev-server@0.25.0", "", { "dependencies": { "@hono/node-server": "^1.14.2", "minimatch": "^9.0.3" }, "peerDependencies": { "hono": "*", "miniflare": "*", "wrangler": "*" }, "optionalPeers": ["miniflare", "wrangler"] }, "sha512-4j5rs7yUTOObU2/yCEHeWbf3C8m95SD9lhdUUE6CJ462Emp9vS94yiza2dsA8+ly5pdaIQW0cd4nhNVcwYL5tA=="],510 "@hono/vite-dev-server": ["@hono/vite-dev-server@0.25.0", "", { "dependencies": { "@hono/node-server": "^1.14.2", "minimatch": "^9.0.3" }, "peerDependencies": { "hono": "*", "miniflare": "*", "wrangler": "*" }, "optionalPeers": ["miniflare", "wrangler"] }, "sha512-4j5rs7yUTOObU2/yCEHeWbf3C8m95SD9lhdUUE6CJ462Emp9vS94yiza2dsA8+ly5pdaIQW0cd4nhNVcwYL5tA=="],
@@ -515,6 +529,8 @@ · 18 unmodified lines
515 529
516 "@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.31", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw=="],530 "@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.31", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw=="],
517 531
532 "@js-sdsl/ordered-map": ["@js-sdsl/ordered-map@4.4.2", "", {}, "sha512-iUKgm52T8HOE/makSxjqoWhe95ZJA1/G1sYsGev2JDKUSS14KAgg1LHb+Ba+IPow0xflbnSkOsZcO08C7w1gYw=="],
533
518 "@medv/finder": ["@medv/finder@4.0.2", "", {}, "sha512-RraNY9SCcx4KZV0Dh6BEW6XEW2swkqYca74pkFFRw6hHItSHiy+O/xMnpbofjYbzXj0tSpBGthUF1hHTsr3vIQ=="],534 "@medv/finder": ["@medv/finder@4.0.2", "", {}, "sha512-RraNY9SCcx4KZV0Dh6BEW6XEW2swkqYca74pkFFRw6hHItSHiy+O/xMnpbofjYbzXj0tSpBGthUF1hHTsr3vIQ=="],
519 535
520 "@modelcontextprotocol/sdk": ["@modelcontextprotocol/sdk@1.27.1", "", { "dependencies": { "@hono/node-server": "^1.19.9", "ajv": "^8.17.1", "ajv-formats": "^3.0.1", "content-type": "^1.0.5", "cors": "^2.8.5", "cross-spawn": "^7.0.5", "eventsource": "^3.0.2", "eventsource-parser": "^3.0.0", "express": "^5.2.1", "express-rate-limit": "^8.2.1", "hono": "^4.11.4", "jose": "^6.1.3", "json-schema-typed": "^8.0.2", "pkce-challenge": "^5.0.0", "raw-body": "^3.0.0", "zod": "^3.25 || ^4.0", "zod-to-json-schema": "^3.25.1" }, "peerDependencies": { "@cfworker/json-schema": "^4.1.1" }, "optionalPeers": ["@cfworker/json-schema"] }, "sha512-sr6GbP+4edBwFndLbM60gf07z0FQ79gaExpnsjMGePXqFcSSb7t6iscpjk9DhFhwd+mTEQrzNafGP8/iGGFYaA=="],536 "@modelcontextprotocol/sdk": ["@modelcontextprotocol/sdk@1.27.1", "", { "dependencies": { "@hono/node-server": "^1.19.9", "ajv": "^8.17.1", "ajv-formats": "^3.0.1", "content-type": "^1.0.5", "cors": "^2.8.5", "cross-spawn": "^7.0.5", "eventsource": "^3.0.2", "eventsource-parser": "^3.0.0", "express": "^5.2.1", "express-rate-limit": "^8.2.1", "hono": "^4.11.4", "jose": "^6.1.3", "json-schema-typed": "^8.0.2", "pkce-challenge": "^5.0.0", "raw-body": "^3.0.0", "zod": "^3.25 || ^4.0", "zod-to-json-schema": "^3.25.1" }, "peerDependencies": { "@cfworker/json-schema": "^4.1.1" }, "optionalPeers": ["@cfworker/json-schema"] }, "sha512-sr6GbP+4edBwFndLbM60gf07z0FQ79gaExpnsjMGePXqFcSSb7t6iscpjk9DhFhwd+mTEQrzNafGP8/iGGFYaA=="],
@@ -541,6 +557,36 @@ · 20 unmodified lines
541 557
542 "@opentelemetry/api": ["@opentelemetry/api@1.9.0", "", {}, "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg=="],558 "@opentelemetry/api": ["@opentelemetry/api@1.9.0", "", {}, "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg=="],
543 559
560 "@opentelemetry/api-logs": ["@opentelemetry/api-logs@0.213.0", "", { "dependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-zRM5/Qj6G84Ej3F1yt33xBVY/3tnMxtL1fiDIxYbDWYaZ/eudVw3/PBiZ8G7JwUxXxjW8gU4g6LnOyfGKYHYgw=="],
561
562 "@opentelemetry/context-async-hooks": ["@opentelemetry/context-async-hooks@2.6.0", "", { "peerDependencies": { "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, "sha512-L8UyDwqpTcbkIK5cgwDRDYDoEhQoj8wp8BwsO19w3LB1Z41yEQm2VJyNfAi9DrLP/YTqXqWpKHyZfR9/tFYo1Q=="],
563
564 "@opentelemetry/core": ["@opentelemetry/core@2.6.0", "", { "dependencies": { "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, "sha512-HLM1v2cbZ4TgYN6KEOj+Bbj8rAKriOdkF9Ed3tG25FoprSiQl7kYc+RRT6fUZGOvx0oMi5U67GoFdT+XUn8zEg=="],
565
566 "@opentelemetry/exporter-trace-otlp-grpc": ["@opentelemetry/exporter-trace-otlp-grpc@0.213.0", "", { "dependencies": { "@grpc/grpc-js": "^1.14.3", "@opentelemetry/core": "2.6.0", "@opentelemetry/otlp-exporter-base": "0.213.0", "@opentelemetry/otlp-grpc-exporter-base": "0.213.0", "@opentelemetry/otlp-transformer": "0.213.0", "@opentelemetry/resources": "2.6.0", "@opentelemetry/sdk-trace-base": "2.6.0" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-L8y6piP4jBIIx1Nv7/9hkx25ql6/Cro/kQrs+f9e8bPF0Ar5Dm991v7PnbtubKz6Q4fT872H56QXUWVnz/Cs4Q=="],
567
568 "@opentelemetry/exporter-trace-otlp-http": ["@opentelemetry/exporter-trace-otlp-http@0.213.0", "", { "dependencies": { "@opentelemetry/core": "2.6.0", "@opentelemetry/otlp-exporter-base": "0.213.0", "@opentelemetry/otlp-transformer": "0.213.0", "@opentelemetry/resources": "2.6.0", "@opentelemetry/sdk-trace-base": "2.6.0" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-tnRmJD39aWrE/Sp7F6AbRNAjKHToDkAqBi6i0lESpGWz3G+f4bhVAV6mgSXH2o18lrDVJXo6jf9bAywQw43wRA=="],
569
570 "@opentelemetry/otlp-exporter-base": ["@opentelemetry/otlp-exporter-base@0.213.0", "", { "dependencies": { "@opentelemetry/core": "2.6.0", "@opentelemetry/otlp-transformer": "0.213.0" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-MegxAP1/n09Ob2dQvY5NBDVjAFkZRuKtWKxYev1R2M8hrsgXzQGkaMgoEKeUOyQ0FUyYcO29UOnYdQWmWa0PXg=="],
571
572 "@opentelemetry/otlp-grpc-exporter-base": ["@opentelemetry/otlp-grpc-exporter-base@0.213.0", "", { "dependencies": { "@grpc/grpc-js": "^1.14.3", "@opentelemetry/core": "2.6.0", "@opentelemetry/otlp-exporter-base": "0.213.0", "@opentelemetry/otlp-transformer": "0.213.0" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-XgRGuLE9usFNlnw2lgMIM4HTwpcIyjdU/xPoJ8v3LbBLBfjaDkIugjc9HoWa7ZSJ/9Bhzgvm/aD0bGdYUFgnTw=="],
573
574 "@opentelemetry/otlp-transformer": ["@opentelemetry/otlp-transformer@0.213.0", "", { "dependencies": { "@opentelemetry/api-logs": "0.213.0", "@opentelemetry/core": "2.6.0", "@opentelemetry/resources": "2.6.0", "@opentelemetry/sdk-logs": "0.213.0", "@opentelemetry/sdk-metrics": "2.6.0", "@opentelemetry/sdk-trace-base": "2.6.0", "protobufjs": "^7.0.0" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-RSuAlxFFPjeK4d5Y6ps8L2WhaQI6CXWllIjvo5nkAlBpmq2XdYWEBGiAbOF4nDs8CX4QblJDv5BbMUft3sEfDw=="],
575
576 "@opentelemetry/resources": ["@opentelemetry/resources@2.6.0", "", { "dependencies": { "@opentelemetry/core": "2.6.0", "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.3.0 <1.10.0" } }, "sha512-D4y/+OGe3JSuYUCBxtH5T9DSAWNcvCb/nQWIga8HNtXTVPQn59j0nTBAgaAXxUVBDl40mG3Tc76b46wPlZaiJQ=="],
577
578 "@opentelemetry/sdk-logs": ["@opentelemetry/sdk-logs@0.213.0", "", { "dependencies": { "@opentelemetry/api-logs": "0.213.0", "@opentelemetry/core": "2.6.0", "@opentelemetry/resources": "2.6.0", "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.4.0 <1.10.0" } }, "sha512-00xlU3GZXo3kXKve4DLdrAL0NAFUaZ9appU/mn00S/5kSUdAvyYsORaDUfR04Mp2CLagAOhrzfUvYozY/EZX2g=="],
579
580 "@opentelemetry/sdk-metrics": ["@opentelemetry/sdk-metrics@2.6.0", "", { "dependencies": { "@opentelemetry/core": "2.6.0", "@opentelemetry/resources": "2.6.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.9.0 <1.10.0" } }, "sha512-CicxWZxX6z35HR83jl+PLgtFgUrKRQ9LCXyxgenMnz5A1lgYWfAog7VtdOvGkJYyQgMNPhXQwkYrDLujk7z1Iw=="],
581
582 "@opentelemetry/sdk-trace-base": ["@opentelemetry/sdk-trace-base@2.6.0", "", { "dependencies": { "@opentelemetry/core": "2.6.0", "@opentelemetry/resources": "2.6.0", "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.3.0 <1.10.0" } }, "sha512-g/OZVkqlxllgFM7qMKqbPV9c1DUPhQ7d4n3pgZFcrnrNft9eJXZM2TNHTPYREJBrtNdRytYyvwjgL5geDKl3EQ=="],
583
584 "@opentelemetry/sdk-trace-node": ["@opentelemetry/sdk-trace-node@2.6.0", "", { "dependencies": { "@opentelemetry/context-async-hooks": "2.6.0", "@opentelemetry/core": "2.6.0", "@opentelemetry/sdk-trace-base": "2.6.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, "sha512-YhswtasmsbIGEFvLGvR9p/y3PVRTfFf+mgY8van4Ygpnv4sA3vooAjvh+qAn9PNWxs4/IwGGqiQS0PPsaRJ0vQ=="],
585
586 "@opentelemetry/sdk-trace-web": ["@opentelemetry/sdk-trace-web@2.6.0", "", { "dependencies": { "@opentelemetry/core": "2.6.0", "@opentelemetry/sdk-trace-base": "2.6.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, "sha512-xyYmLFatwUeYnB7NtQ2Ydl9Y8uiblN+EDo5YEjnk7ZRMhGFyt1wgPqb8EYvATLuDiRVtxid1fJsL6RH1fCQMIA=="],
587
588 "@opentelemetry/semantic-conventions": ["@opentelemetry/semantic-conventions@1.40.0", "", {}, "sha512-cifvXDhcqMwwTlTK04GBNeIe7yyo28Mfby85QXFe1Yk8nmi36Ab/5UQwptOx84SsoGNRg+EVSjwzfSZMy6pmlw=="],
589
544 "@oxc-resolver/binding-android-arm-eabi": ["@oxc-resolver/binding-android-arm-eabi@11.19.1", "", { "os": "android", "cpu": "arm" }, "sha512-aUs47y+xyXHUKlbhqHUjBABjvycq6YSD7bpxSW7vplUmdzAlJ93yXY6ZR0c1o1x5A/QKbENCvs3+NlY8IpIVzg=="],590 "@oxc-resolver/binding-android-arm-eabi": ["@oxc-resolver/binding-android-arm-eabi@11.19.1", "", { "os": "android", "cpu": "arm" }, "sha512-aUs47y+xyXHUKlbhqHUjBABjvycq6YSD7bpxSW7vplUmdzAlJ93yXY6ZR0c1o1x5A/QKbENCvs3+NlY8IpIVzg=="],
545 591
546 "@oxc-resolver/binding-android-arm64": ["@oxc-resolver/binding-android-arm64@11.19.1", "", { "os": "android", "cpu": "arm64" }, "sha512-oolbkRX+m7Pq2LNjr/kKgYeC7bRDMVTWPgxBGMjSpZi/+UskVo4jsMU3MLheZV55jL6c3rNelPl4oD60ggYmqA=="],592 "@oxc-resolver/binding-android-arm64": ["@oxc-resolver/binding-android-arm64@11.19.1", "", { "os": "android", "cpu": "arm64" }, "sha512-oolbkRX+m7Pq2LNjr/kKgYeC7bRDMVTWPgxBGMjSpZi/+UskVo4jsMU3MLheZV55jL6c3rNelPl4oD60ggYmqA=="],
@@ -609,6 +655,26 @@ · 62 unmodified lines
609 655
610 "@parcel/watcher-win32-x64": ["@parcel/watcher-win32-x64@2.5.6", "", { "os": "win32", "cpu": "x64" }, "sha512-hbQlYcCq5dlAX9Qx+kFb0FHue6vbjlf0FrNzSKdYK2APUf7tGfGxQCk2ihEREmbR6ZMc0MVAD5RIX/41gpUzTw=="],656 "@parcel/watcher-win32-x64": ["@parcel/watcher-win32-x64@2.5.6", "", { "os": "win32", "cpu": "x64" }, "sha512-hbQlYcCq5dlAX9Qx+kFb0FHue6vbjlf0FrNzSKdYK2APUf7tGfGxQCk2ihEREmbR6ZMc0MVAD5RIX/41gpUzTw=="],
611 657
658 "@protobufjs/aspromise": ["@protobufjs/aspromise@1.1.2", "", {}, "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ=="],
659
660 "@protobufjs/base64": ["@protobufjs/base64@1.1.2", "", {}, "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg=="],
661
662 "@protobufjs/codegen": ["@protobufjs/codegen@2.0.4", "", {}, "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg=="],
663
664 "@protobufjs/eventemitter": ["@protobufjs/eventemitter@1.1.0", "", {}, "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q=="],
665
666 "@protobufjs/fetch": ["@protobufjs/fetch@1.1.0", "", { "dependencies": { "@protobufjs/aspromise": "^1.1.1", "@protobufjs/inquire": "^1.1.0" } }, "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ=="],
667
668 "@protobufjs/float": ["@protobufjs/float@1.0.2", "", {}, "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ=="],
669
670 "@protobufjs/inquire": ["@protobufjs/inquire@1.1.0", "", {}, "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q=="],
671
672 "@protobufjs/path": ["@protobufjs/path@1.1.2", "", {}, "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA=="],
673
674 "@protobufjs/pool": ["@protobufjs/pool@1.1.0", "", {}, "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw=="],
675
676 "@protobufjs/utf8": ["@protobufjs/utf8@1.1.0", "", {}, "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw=="],
677
612 "@react-grab/cli": ["@react-grab/cli@0.1.26", "", { "dependencies": { "@antfu/ni": "^0.23.0", "commander": "^14.0.0", "ignore": "^7.0.5", "jsonc-parser": "^3.3.1", "ora": "^8.2.0", "picocolors": "^1.1.1", "prompts": "^2.4.2", "smol-toml": "^1.6.0" }, "bin": { "react-grab": "dist/cli.js" } }, "sha512-nNOBdrJ2K7jji6L/X9ARCpU1o/CQ33KYZUtW7vAtrfDM2hyvAIA224ps+Syl97FxhS7pO8b59Bnhc7YLG6h3nA=="],678 "@react-grab/cli": ["@react-grab/cli@0.1.26", "", { "dependencies": { "@antfu/ni": "^0.23.0", "commander": "^14.0.0", "ignore": "^7.0.5", "jsonc-parser": "^3.3.1", "ora": "^8.2.0", "picocolors": "^1.1.1", "prompts": "^2.4.2", "smol-toml": "^1.6.0" }, "bin": { "react-grab": "dist/cli.js" } }, "sha512-nNOBdrJ2K7jji6L/X9ARCpU1o/CQ33KYZUtW7vAtrfDM2hyvAIA224ps+Syl97FxhS7pO8b59Bnhc7YLG6h3nA=="],
613 679
614 "@rolldown/pluginutils": ["@rolldown/pluginutils@1.0.0-rc.3", "", {}, "sha512-eybk3TjzzzV97Dlj5c+XrBFW57eTNhzod66y9HrBlzJ6NsCrWCp/2kaPS3K9wJmurBC0Tdw4yPjXKZqlznim3Q=="],680 "@rolldown/pluginutils": ["@rolldown/pluginutils@1.0.0-rc.3", "", {}, "sha512-eybk3TjzzzV97Dlj5c+XrBFW57eTNhzod66y9HrBlzJ6NsCrWCp/2kaPS3K9wJmurBC0Tdw4yPjXKZqlznim3Q=="],
@@ -795,6 +861,8 @@ · 180 unmodified lines
795 861
796 "ansi-regex": ["ansi-regex@6.2.2", "", {}, "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg=="],862 "ansi-regex": ["ansi-regex@6.2.2", "", {}, "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg=="],
797 863
864 "ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="],
865
798 "argparse": ["argparse@2.0.1", "", {}, "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="],866 "argparse": ["argparse@2.0.1", "", {}, "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="],
799 867
800 "assertion-error": ["assertion-error@2.0.1", "", {}, "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA=="],868 "assertion-error": ["assertion-error@2.0.1", "", {}, "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA=="],
@@ -849,8 +917,14 @@ · 48 unmodified lines
849 917
850 "cli-spinners": ["cli-spinners@2.9.2", "", {}, "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg=="],918 "cli-spinners": ["cli-spinners@2.9.2", "", {}, "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg=="],
851 919
920 "cliui": ["cliui@8.0.1", "", { "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.1", "wrap-ansi": "^7.0.0" } }, "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ=="],
921
852 "clsx": ["clsx@2.1.1", "", {}, "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA=="],922 "clsx": ["clsx@2.1.1", "", {}, "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA=="],
853 923
924 "color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="],
925
926 "color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="],
927
854 "comma-separated-tokens": ["comma-separated-tokens@2.0.3", "", {}, "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg=="],928 "comma-separated-tokens": ["comma-separated-tokens@2.0.3", "", {}, "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg=="],
855 929
856 "commander": ["commander@14.0.3", "", {}, "sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw=="],930 "commander": ["commander@14.0.3", "", {}, "sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw=="],
@@ -977,6 +1051,8 @@ · 120 unmodified lines
977 1051
978 "gensync": ["gensync@1.0.0-beta.2", "", {}, "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg=="],1052 "gensync": ["gensync@1.0.0-beta.2", "", {}, "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg=="],
979 1053
1054 "get-caller-file": ["get-caller-file@2.0.5", "", {}, "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg=="],
1055
980 "get-east-asian-width": ["get-east-asian-width@1.5.0", "", {}, "sha512-CQ+bEO+Tva/qlmw24dCejulK5pMzVnUOFOijVogd3KQs07HnRIgp8TGipvCCRT06xeYEbpbgwaCxglFyiuIcmA=="],1056 "get-east-asian-width": ["get-east-asian-width@1.5.0", "", {}, "sha512-CQ+bEO+Tva/qlmw24dCejulK5pMzVnUOFOijVogd3KQs07HnRIgp8TGipvCCRT06xeYEbpbgwaCxglFyiuIcmA=="],
981 1057
982 "get-intrinsic": ["get-intrinsic@1.3.0", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.2", "es-define-property": "^1.0.1", "es-errors": "^1.3.0", "es-object-atoms": "^1.1.1", "function-bind": "^1.1.2", "get-proto": "^1.0.1", "gopd": "^1.2.0", "has-symbols": "^1.1.0", "hasown": "^2.0.2", "math-intrinsics": "^1.1.0" } }, "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ=="],1058 "get-intrinsic": ["get-intrinsic@1.3.0", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.2", "es-define-property": "^1.0.1", "es-errors": "^1.3.0", "es-object-atoms": "^1.1.1", "function-bind": "^1.1.2", "get-proto": "^1.0.1", "gopd": "^1.2.0", "has-symbols": "^1.1.0", "hasown": "^2.0.2", "math-intrinsics": "^1.1.0" } }, "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ=="],
@@ -1049,6 +1125,8 @@ · 66 unmodified lines
1049 1125
1050 "is-extglob": ["is-extglob@2.1.1", "", {}, "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ=="],1126 "is-extglob": ["is-extglob@2.1.1", "", {}, "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ=="],
1051 1127
1128 "is-fullwidth-code-point": ["is-fullwidth-code-point@3.0.0", "", {}, "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="],
1129
1052 "is-glob": ["is-glob@4.0.3", "", { "dependencies": { "is-extglob": "^2.1.1" } }, "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg=="],1130 "is-glob": ["is-glob@4.0.3", "", { "dependencies": { "is-extglob": "^2.1.1" } }, "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg=="],
1053 1131
1054 "is-hexadecimal": ["is-hexadecimal@2.0.1", "", {}, "sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg=="],1132 "is-hexadecimal": ["is-hexadecimal@2.0.1", "", {}, "sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg=="],
@@ -1121,8 +1199,12 @@ · 66 unmodified lines
1121 1199
1122 "lightningcss-win32-x64-msvc": ["lightningcss-win32-x64-msvc@1.31.1", "", { "os": "win32", "cpu": "x64" }, "sha512-I9aiFrbd7oYHwlnQDqr1Roz+fTz61oDDJX7n9tYF9FJymH1cIN1DtKw3iYt6b8WZgEjoNwVSncwF4wx/ZedMhw=="],1200 "lightningcss-win32-x64-msvc": ["lightningcss-win32-x64-msvc@1.31.1", "", { "os": "win32", "cpu": "x64" }, "sha512-I9aiFrbd7oYHwlnQDqr1Roz+fTz61oDDJX7n9tYF9FJymH1cIN1DtKw3iYt6b8WZgEjoNwVSncwF4wx/ZedMhw=="],
1123 1201
1202 "lodash.camelcase": ["lodash.camelcase@4.3.0", "", {}, "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA=="],
1203
1124 "log-symbols": ["log-symbols@6.0.0", "", { "dependencies": { "chalk": "^5.3.0", "is-unicode-supported": "^1.3.0" } }, "sha512-i24m8rpwhmPIS4zscNzK6MSEhk0DUWa/8iYQWxhffV8jkI4Phvs3F+quL5xvS0gdQR0FyTCMMH33Y78dDTzzIw=="],1204 "log-symbols": ["log-symbols@6.0.0", "", { "dependencies": { "chalk": "^5.3.0", "is-unicode-supported": "^1.3.0" } }, "sha512-i24m8rpwhmPIS4zscNzK6MSEhk0DUWa/8iYQWxhffV8jkI4Phvs3F+quL5xvS0gdQR0FyTCMMH33Y78dDTzzIw=="],
1125 1205
1206 "long": ["long@5.3.2", "", {}, "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA=="],
1207
1126 "longest-streak": ["longest-streak@3.1.0", "", {}, "sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g=="],1208 "longest-streak": ["longest-streak@3.1.0", "", {}, "sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g=="],
1127 1209
1128 "loupe": ["loupe@3.2.1", "", {}, "sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ=="],1210 "loupe": ["loupe@3.2.1", "", {}, "sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ=="],
@@ -1309,6 +1391,8 @@ · 180 unmodified lines
1309 1391
1310 "property-information": ["property-information@7.1.0", "", {}, "sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ=="],1392 "property-information": ["property-information@7.1.0", "", {}, "sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ=="],
1311 1393
1394 "protobufjs": ["protobufjs@7.5.4", "", { "dependencies": { "@protobufjs/aspromise": "^1.1.2", "@protobufjs/base64": "^1.1.2", "@protobufjs/codegen": "^2.0.4", "@protobufjs/eventemitter": "^1.1.0", "@protobufjs/fetch": "^1.1.0", "@protobufjs/float": "^1.0.2", "@protobufjs/inquire": "^1.1.0", "@protobufjs/path": "^1.1.2", "@protobufjs/pool": "^1.1.0", "@protobufjs/utf8": "^1.1.0", "@types/node": ">=13.7.0", "long": "^5.0.0" } }, "sha512-CvexbZtbov6jW2eXAvLukXjXUW1TzFaivC46BpWc/3BpcCysb5Vffu+B3XHMm8lVEuy2Mm4XGex8hBSg1yapPg=="],
1395
1312 "proxy-addr": ["proxy-addr@2.0.7", "", { "dependencies": { "forwarded": "0.2.0", "ipaddr.js": "1.9.1" } }, "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg=="],1396 "proxy-addr": ["proxy-addr@2.0.7", "", { "dependencies": { "forwarded": "0.2.0", "ipaddr.js": "1.9.1" } }, "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg=="],
1313 1397
1314 "punycode": ["punycode@2.3.1", "", {}, "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg=="],1398 "punycode": ["punycode@2.3.1", "", {}, "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg=="],
@@ -1357,6 +1441,8 @@ · 42 unmodified lines
1357 1441
1358 "remend": ["remend@1.2.2", "", {}, "sha512-4ZJgIB9EG9fQE41mOJCRHMmnxDTKHWawQoJWZyUbZuj680wVyogu2ihnj8Edqm7vh2mo/TWHyEZpn2kqeDvS7w=="],1442 "remend": ["remend@1.2.2", "", {}, "sha512-4ZJgIB9EG9fQE41mOJCRHMmnxDTKHWawQoJWZyUbZuj680wVyogu2ihnj8Edqm7vh2mo/TWHyEZpn2kqeDvS7w=="],
1359 1443
1444 "require-directory": ["require-directory@2.1.1", "", {}, "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q=="],
1445
1360 "require-from-string": ["require-from-string@2.0.2", "", {}, "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw=="],1446 "require-from-string": ["require-from-string@2.0.2", "", {}, "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw=="],
1361 1447
1362 "restore-cursor": ["restore-cursor@5.1.0", "", { "dependencies": { "onetime": "^7.0.0", "signal-exit": "^4.1.0" } }, "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA=="],1448 "restore-cursor": ["restore-cursor@5.1.0", "", { "dependencies": { "onetime": "^7.0.0", "signal-exit": "^4.1.0" } }, "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA=="],
@@ -1563,6 +1649,8 @@ · 200 unmodified lines
1563 1649
1564 "why-is-node-running": ["why-is-node-running@2.3.0", "", { "dependencies": { "siginfo": "^2.0.0", "stackback": "0.0.2" }, "bin": { "why-is-node-running": "cli.js" } }, "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w=="],1650 "why-is-node-running": ["why-is-node-running@2.3.0", "", { "dependencies": { "siginfo": "^2.0.0", "stackback": "0.0.2" }, "bin": { "why-is-node-running": "cli.js" } }, "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w=="],
1565 1651
1652 "wrap-ansi": ["wrap-ansi@7.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="],
1653
1566 "wrappy": ["wrappy@1.0.2", "", {}, "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="],1654 "wrappy": ["wrappy@1.0.2", "", {}, "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="],
1567 1655
1568 "ws": ["ws@8.19.0", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg=="],1656 "ws": ["ws@8.19.0", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg=="],
@@ -1571,10 +1659,16 @@ · 2 unmodified lines
1571 1659
1572 "xmlchars": ["xmlchars@2.2.0", "", {}, "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw=="],1660 "xmlchars": ["xmlchars@2.2.0", "", {}, "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw=="],
1573 1661
1662 "y18n": ["y18n@5.0.8", "", {}, "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA=="],
1663
1574 "yallist": ["yallist@3.1.1", "", {}, "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="],1664 "yallist": ["yallist@3.1.1", "", {}, "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="],
1575 1665
1576 "yaml": ["yaml@2.8.2", "", { "bin": { "yaml": "bin.mjs" } }, "sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A=="],1666 "yaml": ["yaml@2.8.2", "", { "bin": { "yaml": "bin.mjs" } }, "sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A=="],
1577 1667
1668 "yargs": ["yargs@17.7.2", "", { "dependencies": { "cliui": "^8.0.1", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", "string-width": "^4.2.3", "y18n": "^5.0.5", "yargs-parser": "^21.1.1" } }, "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w=="],
1669
1670 "yargs-parser": ["yargs-parser@21.1.1", "", {}, "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw=="],
1671
1578 "zod": ["zod@4.3.6", "", {}, "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg=="],1672 "zod": ["zod@4.3.6", "", {}, "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg=="],
1579 1673
1580 "zod-to-json-schema": ["zod-to-json-schema@3.25.1", "", { "peerDependencies": { "zod": "^3.25 || ^4" } }, "sha512-pM/SU9d3YAggzi6MtR4h7ruuQlqKtad8e9S0fmxcMi+ueAK5Korys/aWcV9LIIHTVbj01NdzxcnXSN+O74ZIVA=="],1674 "zod-to-json-schema": ["zod-to-json-schema@3.25.1", "", { "peerDependencies": { "zod": "^3.25 || ^4" } }, "sha512-pM/SU9d3YAggzi6MtR4h7ruuQlqKtad8e9S0fmxcMi+ueAK5Korys/aWcV9LIIHTVbj01NdzxcnXSN+O74ZIVA=="],
@@ -1599,6 +1693,10 @@ · 18 unmodified lines
1599 1693
1600 "@tailwindcss/oxide-wasm32-wasi/tslib": ["tslib@2.8.1", "", { "bundled": true }, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],1694 "@tailwindcss/oxide-wasm32-wasi/tslib": ["tslib@2.8.1", "", { "bundled": true }, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
1601 1695
1696 "cliui/string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="],
1697
1698 "cliui/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="],
1699
1602 "log-symbols/is-unicode-supported": ["is-unicode-supported@1.3.0", "", {}, "sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ=="],1700 "log-symbols/is-unicode-supported": ["is-unicode-supported@1.3.0", "", {}, "sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ=="],
1603 1701
1604 "micromatch/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="],1702 "micromatch/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="],
@@ -1609,6 +1707,12 @@ · 4 unmodified lines
1609 1707
1610 "whatwg-encoding/iconv-lite": ["iconv-lite@0.6.3", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw=="],1708 "whatwg-encoding/iconv-lite": ["iconv-lite@0.6.3", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw=="],
1611 1709
1710 "wrap-ansi/string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="],
1711
1712 "wrap-ansi/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="],
1713
1714 "yargs/string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="],
1715
1612 "@streamdown/code/shiki/@shikijs/core": ["@shikijs/core@3.23.0", "", { "dependencies": { "@shikijs/types": "3.23.0", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4", "hast-util-to-html": "^9.0.5" } }, "sha512-NSWQz0riNb67xthdm5br6lAkvpDJRTgB36fxlo37ZzM2yq0PQFFzbd8psqC2XMPgCzo1fW6cVi18+ArJ44wqgA=="],1716 "@streamdown/code/shiki/@shikijs/core": ["@shikijs/core@3.23.0", "", { "dependencies": { "@shikijs/types": "3.23.0", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4", "hast-util-to-html": "^9.0.5" } }, "sha512-NSWQz0riNb67xthdm5br6lAkvpDJRTgB36fxlo37ZzM2yq0PQFFzbd8psqC2XMPgCzo1fW6cVi18+ArJ44wqgA=="],
1613 1717
1614 "@streamdown/code/shiki/@shikijs/engine-javascript": ["@shikijs/engine-javascript@3.23.0", "", { "dependencies": { "@shikijs/types": "3.23.0", "@shikijs/vscode-textmate": "^10.0.2", "oniguruma-to-es": "^4.3.4" } }, "sha512-aHt9eiGFobmWR5uqJUViySI1bHMqrAgamWE1TYSUoftkAeCCAiGawPMwM+VCadylQtF4V3VNOZ5LmfItH5f3yA=="],1718 "@streamdown/code/shiki/@shikijs/engine-javascript": ["@shikijs/engine-javascript@3.23.0", "", { "dependencies": { "@shikijs/types": "3.23.0", "@shikijs/vscode-textmate": "^10.0.2", "oniguruma-to-es": "^4.3.4" } }, "sha512-aHt9eiGFobmWR5uqJUViySI1bHMqrAgamWE1TYSUoftkAeCCAiGawPMwM+VCadylQtF4V3VNOZ5LmfItH5f3yA=="],
@@ -1621,6 +1725,20 @@ · 6 unmodified lines
1621 1725
1622 "@streamdown/code/shiki/@shikijs/types": ["@shikijs/types@3.23.0", "", { "dependencies": { "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-3JZ5HXOZfYjsYSk0yPwBrkupyYSLpAE26Qc0HLghhZNGTZg/SKxXIIgoxOpmmeQP0RRSDJTk1/vPfw9tbw+jSQ=="],1726 "@streamdown/code/shiki/@shikijs/types": ["@shikijs/types@3.23.0", "", { "dependencies": { "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-3JZ5HXOZfYjsYSk0yPwBrkupyYSLpAE26Qc0HLghhZNGTZg/SKxXIIgoxOpmmeQP0RRSDJTk1/vPfw9tbw+jSQ=="],
1623 1727
1728 "cliui/string-width/emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="],
1729
1730 "cliui/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="],
1731
1624 "tough-cookie/tldts/tldts-core": ["tldts-core@6.1.86", "", {}, "sha512-Je6p7pkk+KMzMv2XXKmAE3McmolOQFdxkKw0R8EYNr7sELW46JqnNeTX8ybPiQgvg1ymCoF8LXs5fzFaZvJPTA=="],1732 "tough-cookie/tldts/tldts-core": ["tldts-core@6.1.86", "", {}, "sha512-Je6p7pkk+KMzMv2XXKmAE3McmolOQFdxkKw0R8EYNr7sELW46JqnNeTX8ybPiQgvg1ymCoF8LXs5fzFaZvJPTA=="],
1733
1734 "wrap-ansi/string-width/emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="],
1735
1736 "wrap-ansi/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="],
1737
1738 "yargs/string-width/emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="],
1739
1740 "yargs/string-width/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="],
1741
1742 "yargs/string-width/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="],
1625 }1743 }
1626}1744}
compose.tracing.yaml+9−0
@@ -0,0 +1,9 @@
1services:
2 jaeger:
3 image: jaegertracing/all-in-one:1.65.0
4 ports:
5 - "16686:16686"
6 - "4317:4317"
7 - "4318:4318"
8 environment:
9 COLLECTOR_OTLP_ENABLED: "true"
package.json+2−0
@@ -21,6 +21,8 @@ · 20 unmodified lines
21 },21 },
22 "scripts": {22 "scripts": {
23 "dev": "turbo run dev",23 "dev": "turbo run dev",
24 "trace:up": "docker compose -f compose.tracing.yaml up -d",
25 "trace:down": "docker compose -f compose.tracing.yaml down",
24 "docs:dev": "turbo run dev --filter=@executor/docs",26 "docs:dev": "turbo run dev --filter=@executor/docs",
25 "test": "turbo run test",27 "test": "turbo run test",
26 "executor": "./apps/executor/bin/executor",28 "executor": "./apps/executor/bin/executor",
packages/control-plane/package.json+2−2
@@ -24,10 +24,10 @@ · 23 unmodified lines
24 "@executor/codemode-core": "workspace:*",24 "@executor/codemode-core": "workspace:*",
25 "@executor/codemode-google-discovery": "workspace:*",25 "@executor/codemode-google-discovery": "workspace:*",
26 "@executor/codemode-mcp": "workspace:*",26 "@executor/codemode-mcp": "workspace:*",
27 "@executor/runtime-quickjs": "workspace:*",
28 "@executor/runtime-ses": "workspace:*",
29 "@executor/codemode-openapi": "workspace:*",27 "@executor/codemode-openapi": "workspace:*",
30 "@executor/runtime-deno-subprocess": "workspace:*",28 "@executor/runtime-deno-subprocess": "workspace:*",
29 "@executor/runtime-quickjs": "workspace:*",
30 "@executor/runtime-ses": "workspace:*",
31 "effect": "catalog:",31 "effect": "catalog:",
32 "graphql": "^16.12.0",32 "graphql": "^16.12.0",
33 "jsonc-parser": "3.3.1",33 "jsonc-parser": "3.3.1",
packages/control-plane/src/runtime/index.ts+2−5
@@ -262,16 +262,13 @@ export const createControlPlaneRuntime = ( · 261 unmodified lines
262 liveExecutionManager,262 liveExecutionManager,
263 });263 });
264 const managedRuntime = ManagedRuntime.make(concreteRuntimeLayer);264 const managedRuntime = ManagedRuntime.make(concreteRuntimeLayer);
265 const runtime = yield* managedRuntime.runtimeEffect;265 yield* managedRuntime.runtimeEffect;
266 const runtimeLayer = Layer.succeedContext(
267 runtime.context,
268 ) as RuntimeControlPlaneLayer;
269 266
270 return {267 return {
271 persistence,268 persistence,
272 localInstallation,269 localInstallation,
273 managedRuntime,270 managedRuntime,
274 runtimeLayer: runtimeLayer as RuntimeControlPlaneLayer,271 runtimeLayer: concreteRuntimeLayer as RuntimeControlPlaneLayer,
275 close: () => managedRuntime.dispose().catch(() => {}),272 close: () => managedRuntime.dispose().catch(() => {}),
276 };273 };
277 }).pipe(Effect.provide(NodeFileSystem.layer));274 }).pipe(Effect.provide(NodeFileSystem.layer));
packages/control-plane/src/runtime/source-adapters/graphql.ts+59−11
@@ -270,6 +270,13 @@ export const graphqlSourceAdapter: SourceAdapter = { · 269 unmodified lines
270 bodyValues: auth.bodyValues,270 bodyValues: auth.bodyValues,
271 },271 },
272 ).pipe(272 ).pipe(
273 Effect.withSpan("graphql.introspection.fetch", {
274 kind: "client",
275 attributes: {
276 "executor.source.id": source.id,
277 "executor.source.endpoint": source.endpoint,
278 },
279 }),
273 Effect.mapError(280 Effect.mapError(
274 (cause) =>281 (cause) =>
275 isSourceCredentialRequiredError(cause)282 isSourceCredentialRequiredError(cause)
@@ -284,16 +291,44 @@ export const graphqlSourceAdapter: SourceAdapter = { · 8 unmodified lines
284 source.name,291 source.name,
285 graphqlDocument,292 graphqlDocument,
286 ).pipe(293 ).pipe(
294 Effect.withSpan("graphql.manifest.extract", {
295 attributes: {
296 "executor.source.id": source.id,
297 },
298 }),
287 Effect.mapError((cause) =>299 Effect.mapError((cause) =>
288 cause instanceof Error ? cause : new Error(String(cause)),300 cause instanceof Error ? cause : new Error(String(cause)),
289 ),301 ),
290 );302 );
303 yield* Effect.annotateCurrentSpan("graphql.tool.count", manifest.tools.length);
291 304
292 const definitions = compileGraphqlToolDefinitions(manifest);305 const definitions = yield* Effect.sync(() => compileGraphqlToolDefinitions(manifest)).pipe(
306 Effect.withSpan("graphql.definitions.compile", {
307 attributes: {
308 "executor.source.id": source.id,
309 "graphql.tool.count": manifest.tools.length,
310 },
311 }),
312 );
313 yield* Effect.annotateCurrentSpan("graphql.definition.count", definitions.length);
314 const operations = yield* Effect.sync(() =>
315 definitions.map((definition) =>
316 graphqlCatalogOperationFromDefinition({
317 definition,
318 manifest,
319 })
320 )
321 ).pipe(
322 Effect.withSpan("graphql.operations.build", {
323 attributes: {
324 "executor.source.id": source.id,
325 "graphql.definition.count": definitions.length,
326 },
327 }),
328 );
293 const now = Date.now();329 const now = Date.now();
294 330 const snapshot = yield* Effect.sync(() =>
295 return {331 createGraphqlCatalogSnapshot({
296 snapshot: createGraphqlCatalogSnapshot({
297 source,332 source,
298 documents: [{333 documents: [{
299 documentKind: "graphql_introspection",334 documentKind: "graphql_introspection",
@@ -301,14 +336,27 @@ export const graphqlSourceAdapter: SourceAdapter = { · 1 unmodified line
301 contentText: graphqlDocument,336 contentText: graphqlDocument,
302 fetchedAt: now,337 fetchedAt: now,
303 }],338 }],
304 operations: definitions.map((definition) =>339 operations,
305 graphqlCatalogOperationFromDefinition({340 })
306 definition,341 ).pipe(
307 manifest,342 Effect.withSpan("graphql.snapshot.build", {
308 })343 attributes: {
309 ),344 "executor.source.id": source.id,
345 "graphql.operation.count": operations.length,
346 },
310 }),347 }),
348 );
349
350 return {
351 snapshot,
311 sourceHash: manifest.sourceHash,352 sourceHash: manifest.sourceHash,
312 };353 };
313 }),354 }).pipe(
355 Effect.withSpan("graphql.syncCatalog", {
356 attributes: {
357 "executor.source.id": source.id,
358 "executor.source.endpoint": source.endpoint,
359 },
360 }),
361 ),
314};362};
packages/control-plane/src/runtime/source-auth-service.ts+19−3
@@ -360,7 +360,7 @@ const serializeJson = (value: unknown): string | null => { · 359 unmodified lines
360 return JSON.stringify(value);360 return JSON.stringify(value);
361};361};
362 362
363const updateSourceStatus = (sourceStore: RuntimeSourceStore, source: Source, input: {363const updateSourceStatus = Effect.fn("source.status.update")((sourceStore: RuntimeSourceStore, source: Source, input: {
364 actorAccountId?: AccountId | null;364 actorAccountId?: AccountId | null;
365 status: Source["status"];365 status: Source["status"];
366 lastError?: string | null;366 lastError?: string | null;
@@ -384,7 +384,14 @@ const updateSourceStatus = (sourceStore: RuntimeSourceStore, source: Source, inp · 17 unmodified lines
384 }, {384 }, {
385 actorAccountId: input.actorAccountId,385 actorAccountId: input.actorAccountId,
386 });386 });
387 });387 }).pipe(
388 Effect.withSpan("source.status.update", {
389 attributes: {
390 "executor.source.id": source.id,
391 "executor.source.status": input.status,
392 },
393 }),
394 ));
388 395
389export type ExecutorSourceAddResult =396export type ExecutorSourceAddResult =
390 | {397 | {
@@ -1404,7 +1411,16 @@ const addExecutorHttpSource = (input: { · 1013 unmodified lines
1404 ),1411 ),
1405 ),1412 ),
1406 });1413 });
1407 });1414 }).pipe(
1415 Effect.withSpan("source.connect.http", {
1416 attributes: {
1417 "executor.source.kind": input.sourceInput.kind,
1418 "executor.source.endpoint": input.sourceInput.endpoint,
1419 ...(input.sourceInput.namespace ? { "executor.source.namespace": input.sourceInput.namespace } : {}),
1420 ...(input.sourceInput.name ? { "executor.source.name": input.sourceInput.name } : {}),
1421 },
1422 }),
1423 );
1408 1424
1409const addExecutorGoogleDiscoverySource = (input: {1425const addExecutorGoogleDiscoverySource = (input: {
1410 rows: ControlPlaneStoreShape;1426 rows: ControlPlaneStoreShape;
packages/control-plane/src/runtime/source-catalog-sync.ts+10−1
@@ -174,7 +174,16 @@ const syncSourceCatalogWithDeps = ( · 173 unmodified lines
174 snapshot: syncResult.snapshot,174 snapshot: syncResult.snapshot,
175 });175 });
176 });176 });
177 });177 }).pipe(
178 Effect.withSpan("source.catalog.sync", {
179 attributes: {
180 "executor.source.id": input.source.id,
181 "executor.source.kind": input.source.kind,
182 "executor.source.namespace": input.source.namespace,
183 "executor.source.endpoint": input.source.endpoint,
184 },
185 }),
186 );
178 187
179const persistMcpCatalogSnapshotFromManifestWithDeps = (188const persistMcpCatalogSnapshotFromManifestWithDeps = (
180 deps: RuntimeSourceCatalogSyncDeps,189 deps: RuntimeSourceCatalogSyncDeps,
packages/control-plane/src/runtime/source-store.ts+48−10
@@ -436,7 +436,7 @@ const loadSourcesInWorkspaceWithDeps = ( · 435 unmodified lines
436 Effect.gen(function* () {436 Effect.gen(function* () {
437 const localWorkspace = yield* resolveRuntimeLocalWorkspaceFromDeps(deps, workspaceId);437 const localWorkspace = yield* resolveRuntimeLocalWorkspaceFromDeps(deps, workspaceId);
438 const authArtifacts = yield* deps.rows.authArtifacts.listByWorkspaceId(workspaceId);438 const authArtifacts = yield* deps.rows.authArtifacts.listByWorkspaceId(workspaceId);
439 return yield* Effect.forEach(439 const sources = yield* Effect.forEach(
440 Object.keys(localWorkspace.loadedConfig.config?.sources ?? {}),440 Object.keys(localWorkspace.loadedConfig.config?.sources ?? {}),
441 (sourceId) =>441 (sourceId) =>
442 Effect.map(442 Effect.map(
@@ -451,7 +451,15 @@ const loadSourcesInWorkspaceWithDeps = ( · 8 unmodified lines
451 ({ source }) => source,451 ({ source }) => source,
452 ),452 ),
453 );453 );
454 });454 yield* Effect.annotateCurrentSpan("executor.source.count", sources.length);
455 return sources;
456 }).pipe(
457 Effect.withSpan("source.store.load_workspace", {
458 attributes: {
459 "executor.workspace.id": workspaceId,
460 },
461 }),
462 );
455 463
456const syncWorkspaceSourceTypeDeclarationsWithDeps = (464const syncWorkspaceSourceTypeDeclarationsWithDeps = (
457 deps: RuntimeSourceStoreDeps,465 deps: RuntimeSourceStoreDeps,
@@ -485,7 +493,19 @@ const syncWorkspaceSourceTypeDeclarationsWithDeps = ( · 27 unmodified lines
485 entries: entries.filter((entry): entry is NonNullable<typeof entry> => entry !== null),493 entries: entries.filter((entry): entry is NonNullable<typeof entry> => entry !== null),
486 });494 });
487 });495 });
488 });496 }).pipe(
497 Effect.withSpan("source.types.refresh_workspace.schedule", {
498 attributes: {
499 "executor.workspace.id": workspaceId,
500 },
501 }),
502 );
503
504const shouldRefreshWorkspaceDeclarationsAfterPersist = (source: Source): boolean =>
505 source.enabled === false
506 || source.status === "auth_required"
507 || source.status === "error"
508 || source.status === "draft";
489 509
490export const loadSourcesInWorkspace = (510export const loadSourcesInWorkspace = (
491 rows: ControlPlaneStoreShape,511 rows: ControlPlaneStoreShape,
@@ -621,7 +641,14 @@ const loadSourceByIdWithDeps = (deps: RuntimeSourceStoreDeps, input: { · 129 unmodified lines
621 });641 });
622 642
623 return localSource.source;643 return localSource.source;
624 });644 }).pipe(
645 Effect.withSpan("source.store.load_by_id", {
646 attributes: {
647 "executor.workspace.id": input.workspaceId,
648 "executor.source.id": input.sourceId,
649 },
650 }),
651 );
625 652
626export const loadSourceById = (rows: ControlPlaneStoreShape, input: {653export const loadSourceById = (rows: ControlPlaneStoreShape, input: {
627 workspaceId: WorkspaceId;654 workspaceId: WorkspaceId;
@@ -939,18 +966,29 @@ const persistSourceWithDeps = ( · 311 unmodified lines
939 state: workspaceState,966 state: workspaceState,
940 });967 });
941 968
942 yield* syncWorkspaceSourceTypeDeclarationsWithDeps(969 if (shouldRefreshWorkspaceDeclarationsAfterPersist(nextSource)) {
943 deps,970 yield* syncWorkspaceSourceTypeDeclarationsWithDeps(
944 nextSource.workspaceId,971 deps,
945 options,972 nextSource.workspaceId,
946 );973 options,
974 );
975 }
947 976
948 return yield* loadSourceByIdWithDeps(deps, {977 return yield* loadSourceByIdWithDeps(deps, {
949 workspaceId: nextSource.workspaceId,978 workspaceId: nextSource.workspaceId,
950 sourceId: nextSource.id,979 sourceId: nextSource.id,
951 actorAccountId: options.actorAccountId,980 actorAccountId: options.actorAccountId,
952 });981 });
953 });982 }).pipe(
983 Effect.withSpan("source.store.persist", {
984 attributes: {
985 "executor.workspace.id": source.workspaceId,
986 "executor.source.id": source.id,
987 "executor.source.kind": source.kind,
988 "executor.source.status": source.status,
989 },
990 }),
991 );
954 992
955export const persistSource = (993export const persistSource = (
956 rows: ControlPlaneStoreShape,994 rows: ControlPlaneStoreShape,
packages/control-plane/src/runtime/source-type-declarations.test.ts+48−1
@@ -46,6 +46,8 @@ const createSnapshot = (): ReturnType<typeof createCatalogSnapshotV1> => { · 45 unmodified lines
46 const executableId = ExecutableIdSchema.make("exec_graphql_teams");46 const executableId = ExecutableIdSchema.make("exec_graphql_teams");
47 const capabilityId = CapabilityIdSchema.make("cap_graphql_teams");47 const capabilityId = CapabilityIdSchema.make("cap_graphql_teams");
48 const responseSetId = ResponseSetIdSchema.make("response_set_graphql_teams");48 const responseSetId = ResponseSetIdSchema.make("response_set_graphql_teams");
49 const secondExecutableId = ExecutableIdSchema.make("exec_graphql_teams_search");
50 const secondCapabilityId = CapabilityIdSchema.make("cap_graphql_teams_search");
49 51
50 put(catalog.documents as Record<typeof docId, CatalogV1["documents"][typeof docId]>, docId, {52 put(catalog.documents as Record<typeof docId, CatalogV1["documents"][typeof docId]>, docId, {
51 id: docId,53 id: docId,
@@ -175,6 +177,47 @@ const createSnapshot = (): ReturnType<typeof createCatalogSnapshotV1> => { · 123 unmodified lines
175 provenance: baseProvenance("#/query/teams"),177 provenance: baseProvenance("#/query/teams"),
176 });178 });
177 179
180 put(catalog.capabilities as Record<typeof secondCapabilityId, CatalogV1["capabilities"][typeof secondCapabilityId]>, secondCapabilityId, {
181 id: secondCapabilityId,
182 serviceScopeId: scopeId,
183 surface: {
184 toolPath: ["linear", "teamsSearch"],
185 title: "Teams Search",
186 summary: "Search teams",
187 },
188 semantics: {
189 effect: "read",
190 safe: true,
191 idempotent: true,
192 destructive: false,
193 },
194 auth: { kind: "none" },
195 interaction: {
196 approval: { mayRequire: false },
197 elicitation: { mayRequest: false },
198 resume: { supported: false },
199 },
200 executableIds: [secondExecutableId],
201 preferredExecutableId: secondExecutableId,
202 synthetic: false,
203 provenance: baseProvenance("#/query/teamsSearch"),
204 });
205
206 put(catalog.executables as Record<typeof secondExecutableId, CatalogV1["executables"][typeof secondExecutableId]>, secondExecutableId, {
207 id: secondExecutableId,
208 protocol: "graphql",
209 capabilityId: secondCapabilityId,
210 scopeId,
211 operationType: "query",
212 rootField: "teamsSearch",
213 argumentShapeId: callShapeId,
214 resultShapeId,
215 selectionMode: "fixed",
216 responseSetId,
217 synthetic: false,
218 provenance: baseProvenance("#/query/teamsSearch"),
219 });
220
178 return createCatalogSnapshotV1({221 return createCatalogSnapshotV1({
179 import: {222 import: {
180 sourceKind: "graphql-schema",223 sourceKind: "graphql-schema",
@@ -252,8 +295,12 @@ describe("source-type-declarations", () => { · 71 unmodified lines
252 );295 );
253 296
254 expect(sourceDeclaration).toContain("export interface SourceTools_src_linear");297 expect(sourceDeclaration).toContain("export interface SourceTools_src_linear");
298 expect(sourceDeclaration).toContain("type TeamConnection = {");
299 expect(sourceDeclaration.match(/type TeamFilter =/g)?.length).toBe(1);
300 expect(sourceDeclaration.match(/type Teams_call =/g)?.length).toBe(1);
255 expect(sourceDeclaration).toContain("linear: {");301 expect(sourceDeclaration).toContain("linear: {");
256 expect(sourceDeclaration).toContain("teams: (args?: { filter?: { name?: string } }) => Promise<{ nodes?: { name?: string } }>");302 expect(sourceDeclaration).toContain("teams: (args?: Teams_call) => Promise<TeamConnection>;");
303 expect(sourceDeclaration).toContain("teamsSearch: (args?: Teams_call) => Promise<TeamConnection>;");
257 expect(aggregateDeclaration).toContain('import type { SourceTools_src_linear } from "./sources/src_linear";');304 expect(aggregateDeclaration).toContain('import type { SourceTools_src_linear } from "./sources/src_linear";');
258 expect(aggregateDeclaration).not.toContain("src_hidden");305 expect(aggregateDeclaration).not.toContain("src_hidden");
259 expect(aggregateDeclaration).toContain("declare global {");306 expect(aggregateDeclaration).toContain("declare global {");
packages/control-plane/src/runtime/source-type-declarations.ts+561−69
@@ -1,20 +1,19 @@
1import { join } from "node:path";1import { join } from "node:path";
2import { FileSystem } from "@effect/platform";2import { FileSystem } from "@effect/platform";
3import { NodeFileSystem } from "@effect/platform-node";3import { NodeFileSystem } from "@effect/platform-node";
4import { typeSignatureFromSchemaWithOptions } from "@executor/codemode-core";
5import type { Source } from "#schema";4import type { Source } from "#schema";
5import * as Cause from "effect/Cause";
6import * as Effect from "effect/Effect";6import * as Effect from "effect/Effect";
7import * as Fiber from "effect/Fiber";
7 8
8import { projectCatalogForAgentSdk } from "../ir/catalog";9import { projectCatalogForAgentSdk } from "../ir/catalog";
9import type { CatalogSnapshotV1 } from "../ir/model";10import type { ShapeSymbolId } from "../ir/ids";
11import type { CatalogSnapshotV1, CatalogV1, ShapeNode, ShapeSymbol } from "../ir/model";
10import type { ResolvedLocalWorkspaceContext } from "./local-config";12import type { ResolvedLocalWorkspaceContext } from "./local-config";
11import {13import {
12 LocalFileSystemError,14 LocalFileSystemError,
13 unknownLocalErrorDetails,15 unknownLocalErrorDetails,
14} from "./local-errors";16} from "./local-errors";
15import { shapeToJsonSchema } from "./source-catalog-runtime";
16
17type JsonRecord = Record<string, unknown>;
18 17
19type SourceDeclarationEntry = {18type SourceDeclarationEntry = {
20 source: Source;19 source: Source;
@@ -28,6 +27,11 @@ type ToolMethodNode = { · 7 unmodified lines
28 readonly argsOptional: boolean;27 readonly argsOptional: boolean;
29};28};
30 29
30type SourceDeclarationModel = {
31 readonly methods: readonly ToolMethodNode[];
32 readonly supportingTypes: readonly string[];
33};
34
31type ToolTreeNode = {35type ToolTreeNode = {
32 method: ToolMethodNode | null;36 method: ToolMethodNode | null;
33 children: Map<string, ToolTreeNode>;37 children: Map<string, ToolTreeNode>;
@@ -40,11 +44,6 @@ type SourceDeclarationStub = { · 6 unmodified lines
40const GENERATED_TYPES_DIRECTORY = "types";44const GENERATED_TYPES_DIRECTORY = "types";
41const GENERATED_SOURCE_TYPES_DIRECTORY = "sources";45const GENERATED_SOURCE_TYPES_DIRECTORY = "sources";
42const VALID_IDENTIFIER_PATTERN = /^[A-Za-z_$][A-Za-z0-9_$]*$/;46const VALID_IDENTIFIER_PATTERN = /^[A-Za-z_$][A-Za-z0-9_$]*$/;
43const DECLARATION_RENDER_OPTIONS = {
44 maxLength: Number.POSITIVE_INFINITY,
45 maxDepth: 6,
46 maxProperties: 16,
47} as const;
48 47
49const mapFileSystemError = (path: string, action: string) => (cause: unknown) =>48const mapFileSystemError = (path: string, action: string) => (cause: unknown) =>
50 new LocalFileSystemError({49 new LocalFileSystemError({
@@ -68,19 +67,18 @@ const sourceDeclarationPath = (context: ResolvedLocalWorkspaceContext, sourceId: · 17 unmodified lines
68const aggregateDeclarationPath = (context: ResolvedLocalWorkspaceContext): string =>67const aggregateDeclarationPath = (context: ResolvedLocalWorkspaceContext): string =>
69 join(declarationDirectory(context), "index.d.ts");68 join(declarationDirectory(context), "index.d.ts");
70 69
71const asRecord = (value: unknown): JsonRecord =>
72 typeof value === "object" && value !== null && !Array.isArray(value)
73 ? (value as JsonRecord)
74 : {};
75
76const asStringArray = (value: unknown): string[] =>
77 Array.isArray(value)
78 ? value.filter((entry): entry is string => typeof entry === "string")
79 : [];
80
81const formatPropertyKey = (value: string): string =>70const formatPropertyKey = (value: string): string =>
82 VALID_IDENTIFIER_PATTERN.test(value) ? value : JSON.stringify(value);71 VALID_IDENTIFIER_PATTERN.test(value) ? value : JSON.stringify(value);
83 72
73const formatTypeNameSegment = (value: string): string => {
74 const sanitized = value.replace(/[^A-Za-z0-9_$]+/g, "_").replace(/_+/g, "_").replace(/^_+|_+$/g, "");
75 if (sanitized.length === 0) {
76 return "Type";
77 }
78
79 return /^[A-Za-z_$]/.test(sanitized) ? sanitized : `T_${sanitized}`;
80};
81
84const sourceTypeInterfaceName = (sourceId: string): string =>82const sourceTypeInterfaceName = (sourceId: string): string =>
85 `SourceTools_${sourceId.replace(/[^A-Za-z0-9_$]+/g, "_")}`;83 `SourceTools_${sourceId.replace(/[^A-Za-z0-9_$]+/g, "_")}`;
86 84
@@ -92,15 +90,38 @@ const createToolTreeNode = (): ToolTreeNode => ({ · 5 unmodified lines
92 children: new Map(),90 children: new Map(),
93});91});
94 92
95const schemaAllowsOmittedArgs = (schema: unknown): boolean => {93const primitiveTypeName = (value: string): string => {
96 const root = asRecord(schema);94 switch (value) {
97 if (root.type !== "object" && root.properties === undefined) {95 case "string":
98 return false;96 case "boolean":
97 return value;
98 case "integer":
99 case "number":
100 return "number";
101 case "null":
102 return "null";
103 case "object":
104 return "Record<string, unknown>";
105 case "array":
106 return "Array<unknown>";
107 default:
108 throw new Error(`Unsupported JSON Schema primitive type: ${value}`);
99 }109 }
110};
100 111
101 return asStringArray(root.required).length === 0;112const jsonLiteral = (value: unknown): string => {
113 const serialized = JSON.stringify(value);
114 if (serialized === undefined) {
115 throw new Error(`Unsupported literal value in declaration schema: ${String(value)}`);
116 }
117 return serialized;
102};118};
103 119
120const wrapCompositeType = (value: string): string =>
121 value.includes(" | ") || value.includes(" & ")
122 ? `(${value})`
123 : value;
124
104const objectTypeLiteral = (125const objectTypeLiteral = (
105 lines: readonly string[],126 lines: readonly string[],
106 indent: string,127 indent: string,
@@ -158,45 +179,482 @@ const buildToolTree = (methods: readonly ToolMethodNode[]): ToolTreeNode => { · 51 unmodified lines
158 return root;179 return root;
159};180};
160 181
161const collectToolMethods = (snapshot: CatalogSnapshotV1): ToolMethodNode[] => {182const getShapeSymbol = (catalog: CatalogV1, shapeId: ShapeSymbolId): ShapeSymbol => {
183 const symbol = catalog.symbols[shapeId];
184 if (!symbol || symbol.kind !== "shape") {
185 throw new Error(`Missing shape symbol for ${shapeId}`);
186 }
187
188 return symbol;
189};
190
191const isInlineShapeNode = (node: ShapeNode): boolean =>
192 node.type === "unknown"
193 || node.type === "scalar"
194 || node.type === "const"
195 || node.type === "enum";
196
197const isSyntheticShapeLabel = (value: string): boolean =>
198 /^shape_[a-f0-9_]+$/i.test(value);
199
200const childShapeIds = (node: ShapeNode): ShapeSymbolId[] => {
201 switch (node.type) {
202 case "unknown":
203 case "scalar":
204 case "const":
205 case "enum":
206 return [];
207 case "object":
208 return [
209 ...Object.values(node.fields).map((field) => field.shapeId),
210 ...(typeof node.additionalProperties === "string" ? [node.additionalProperties] : []),
211 ...Object.values(node.patternProperties ?? {}),
212 ];
213 case "array":
214 return [node.itemShapeId];
215 case "tuple":
216 return [
217 ...node.itemShapeIds,
218 ...(typeof node.additionalItems === "string" ? [node.additionalItems] : []),
219 ];
220 case "map":
221 return [node.valueShapeId];
222 case "allOf":
223 case "anyOf":
224 case "oneOf":
225 return [...node.items];
226 case "nullable":
227 return [node.itemShapeId];
228 case "ref":
229 return [node.target];
230 case "not":
231 return [node.itemShapeId];
232 case "conditional":
233 return [
234 node.ifShapeId,
235 ...(node.thenShapeId ? [node.thenShapeId] : []),
236 ...(node.elseShapeId ? [node.elseShapeId] : []),
237 ];
238 case "graphqlInterface":
239 return [
240 ...Object.values(node.fields).map((field) => field.shapeId),
241 ...node.possibleTypeIds,
242 ];
243 case "graphqlUnion":
244 return [...node.memberTypeIds];
245 }
246};
247
248const createCatalogTypeRenderer = (input: {
249 catalog: CatalogV1;
250 rootShapeIds: readonly ShapeSymbolId[];
251}) => {
252 const { catalog, rootShapeIds } = input;
253 const signatureCache = new Map<ShapeSymbolId, string>();
254 const recursiveSignatures = new Set<string>();
255 const shapeIdsBySignature = new Map<string, ShapeSymbolId[]>();
256 const usageCountBySignature = new Map<string, number>();
257 const aliasNameBySignature = new Map<string, string>();
258 const usedAliasNames = new Set<string>();
259 const usedAliasSignatures = new Set<string>();
260
261 const renderInlineShapeNode = (node: ShapeNode): string => {
262 switch (node.type) {
263 case "unknown":
264 return "unknown";
265 case "scalar":
266 return primitiveTypeName(node.scalar);
267 case "const":
268 return jsonLiteral(node.value);
269 case "enum":
270 return node.values.map((value) => jsonLiteral(value)).join(" | ");
271 default:
272 throw new Error(`Cannot inline non-primitive shape node: ${node.type}`);
273 }
274 };
275
276 const shapeSignature = (shapeId: ShapeSymbolId, stack: readonly ShapeSymbolId[] = []): string => {
277 const cached = signatureCache.get(shapeId);
278 if (cached) {
279 return cached;
280 }
281
282 if (stack.includes(shapeId)) {
283 return `cycle:${shapeId}`;
284 }
285
286 const shape = getShapeSymbol(catalog, shapeId);
287 const nextStack = [...stack, shapeId];
288 const childSignatures = (shapeIds: readonly ShapeSymbolId[], sort: boolean): string[] => {
289 const values = shapeIds.map((childShapeId) => shapeSignature(childShapeId, nextStack));
290 return sort ? values.sort((left, right) => left.localeCompare(right)) : values;
291 };
292
293 const signature = (() => {
294 switch (shape.node.type) {
295 case "unknown":
296 return "unknown";
297 case "scalar":
298 return `scalar:${primitiveTypeName(shape.node.scalar)}`;
299 case "const":
300 return `const:${jsonLiteral(shape.node.value)}`;
301 case "enum":
302 return `enum:${shape.node.values.map((value) => jsonLiteral(value)).sort().join("|")}`;
303 case "object": {
304 const required = shape.node.required ?? [];
305 const fields = Object.entries(shape.node.fields)
306 .sort(([left], [right]) => left.localeCompare(right))
307 .map(([key, field]) => `${key}${required.includes(key) ? "!" : "?"}:${shapeSignature(field.shapeId, nextStack)}`)
308 .join(",");
309 const additionalProperties =
310 shape.node.additionalProperties === true
311 ? "unknown"
312 : typeof shape.node.additionalProperties === "string"
313 ? shapeSignature(shape.node.additionalProperties, nextStack)
314 : "none";
315 const patternProperties = Object.entries(shape.node.patternProperties ?? {})
316 .map(([, valueShapeId]) => shapeSignature(valueShapeId, nextStack))
317 .sort((left, right) => left.localeCompare(right))
318 .join("|");
319 return `object:${fields}:index=${additionalProperties}:patterns=${patternProperties}`;
320 }
321 case "array":
322 return `array:${shapeSignature(shape.node.itemShapeId, nextStack)}`;
323 case "tuple":
324 return `tuple:${childSignatures(shape.node.itemShapeIds, false).join(",")}:rest=${
325 shape.node.additionalItems === true
326 ? "unknown"
327 : typeof shape.node.additionalItems === "string"
328 ? shapeSignature(shape.node.additionalItems, nextStack)
329 : "none"
330 }`;
331 case "map":
332 return `map:${shapeSignature(shape.node.valueShapeId, nextStack)}`;
333 case "allOf":
334 return `allOf:${childSignatures(shape.node.items, true).join("&")}`;
335 case "anyOf":
336 return `anyOf:${childSignatures(shape.node.items, true).join("|")}`;
337 case "oneOf":
338 return `oneOf:${childSignatures(shape.node.items, true).join("|")}`;
339 case "nullable":
340 return `nullable:${shapeSignature(shape.node.itemShapeId, nextStack)}`;
341 case "ref":
342 return `ref:${shapeSignature(shape.node.target, nextStack)}`;
343 case "not":
344 return `not:${shapeSignature(shape.node.itemShapeId, nextStack)}`;
345 case "conditional":
346 return `conditional:${shapeSignature(shape.node.ifShapeId, nextStack)}:${
347 shape.node.thenShapeId ? shapeSignature(shape.node.thenShapeId, nextStack) : "none"
348 }:${shape.node.elseShapeId ? shapeSignature(shape.node.elseShapeId, nextStack) : "none"}`;
349 case "graphqlInterface": {
350 const fields = Object.entries(shape.node.fields)
351 .sort(([left], [right]) => left.localeCompare(right))
352 .map(([key, field]) => `${key}:${shapeSignature(field.shapeId, nextStack)}`)
353 .join(",");
354 const possibleTypes = childSignatures(shape.node.possibleTypeIds, true).join("|");
355 return `graphqlInterface:${fields}:possible=${possibleTypes}`;
356 }
357 case "graphqlUnion":
358 return `graphqlUnion:${childSignatures(shape.node.memberTypeIds, true).join("|")}`;
359 }
360 })();
361
362 if (signature.includes("cycle:")) {
363 recursiveSignatures.add(signature);
364 }
365
366 signatureCache.set(shapeId, signature);
367 const group = shapeIdsBySignature.get(signature);
368 if (group) {
369 group.push(shapeId);
370 } else {
371 shapeIdsBySignature.set(signature, [shapeId]);
372 }
373 return signature;
374 };
375
376 const reachableShapeIds = new Set<ShapeSymbolId>();
377 const collectReachableShapes = (shapeId: ShapeSymbolId): void => {
378 if (reachableShapeIds.has(shapeId)) {
379 return;
380 }
381
382 reachableShapeIds.add(shapeId);
383 for (const childShapeId of childShapeIds(getShapeSymbol(catalog, shapeId).node)) {
384 collectReachableShapes(childShapeId);
385 }
386 };
387
388 for (const rootShapeId of rootShapeIds) {
389 collectReachableShapes(rootShapeId);
390 }
391
392 for (const rootShapeId of rootShapeIds) {
393 const rootShape = getShapeSymbol(catalog, rootShapeId);
394 if (isInlineShapeNode(rootShape.node)) {
395 continue;
396 }
397
398 const signature = shapeSignature(rootShapeId);
399 usageCountBySignature.set(signature, (usageCountBySignature.get(signature) ?? 0) + 1);
400 }
401
402 for (const shapeId of reachableShapeIds) {
403 for (const childShapeId of childShapeIds(getShapeSymbol(catalog, shapeId).node)) {
404 const childShape = getShapeSymbol(catalog, childShapeId);
405 if (isInlineShapeNode(childShape.node)) {
406 continue;
407 }
408
409 const signature = shapeSignature(childShapeId);
410 usageCountBySignature.set(signature, (usageCountBySignature.get(signature) ?? 0) + 1);
411 }
412 }
413
414 const representativeShapeIdForSignature = (signature: string): ShapeSymbolId => {
415 const group = shapeIdsBySignature.get(signature);
416 if (!group || group.length === 0) {
417 throw new Error(`Missing representative shape for signature ${signature}`);
418 }
419
420 const sorted = [...group].sort((left, right) => {
421 const leftShape = getShapeSymbol(catalog, left);
422 const rightShape = getShapeSymbol(catalog, right);
423 const leftTitle = leftShape.title ?? leftShape.id;
424 const rightTitle = rightShape.title ?? rightShape.id;
425 const leftSynthetic = isSyntheticShapeLabel(leftTitle) ? 1 : 0;
426 const rightSynthetic = isSyntheticShapeLabel(rightTitle) ? 1 : 0;
427 return leftSynthetic - rightSynthetic || leftTitle.localeCompare(rightTitle);
428 });
429
430 return sorted[0]!;
431 };
432
433 const aliasNameForSignature = (signature: string): string => {
434 const existing = aliasNameBySignature.get(signature);
435 if (existing) {
436 return existing;
437 }
438
439 const representative = getShapeSymbol(catalog, representativeShapeIdForSignature(signature));
440 const baseName = formatTypeNameSegment(representative.title ?? representative.id);
441 let candidate = baseName;
442 let suffix = 2;
443 while (usedAliasNames.has(candidate)) {
444 candidate = `${baseName}_${String(suffix)}`;
445 suffix += 1;
446 }
447
448 aliasNameBySignature.set(signature, candidate);
449 usedAliasNames.add(candidate);
450 return candidate;
451 };
452
453 const shouldAliasSignature = (signature: string): boolean =>
454 recursiveSignatures.has(signature) || (usageCountBySignature.get(signature) ?? 0) > 1;
455
456 const renderShape = (shapeId: ShapeSymbolId, options: {
457 position: "root" | "nested";
458 stack?: readonly ShapeSymbolId[];
459 }): string => {
460 const shape = getShapeSymbol(catalog, shapeId);
461 if (isInlineShapeNode(shape.node)) {
462 return renderInlineShapeNode(shape.node);
463 }
464
465 const signature = shapeSignature(shapeId);
466 if (shouldAliasSignature(signature)) {
467 usedAliasSignatures.add(signature);
468 return aliasNameForSignature(signature);
469 }
470
471 const stack = options.stack ?? [];
472 if (stack.includes(shapeId)) {
473 usedAliasSignatures.add(signature);
474 return aliasNameForSignature(signature);
475 }
476
477 return renderShapeBody(shapeId, [...stack, shapeId]);
478 };
479
480 const renderIndexValueType = (shapeIds: readonly ShapeSymbolId[], allowUnknown: boolean): string => {
481 const members = new Set<string>();
482 if (allowUnknown) {
483 members.add("unknown");
484 }
485
486 for (const shapeId of shapeIds) {
487 members.add(renderShape(shapeId, { position: "nested" }));
488 }
489
490 return [...members].sort((left, right) => left.localeCompare(right)).join(" | ");
491 };
492
493 const renderObjectFields = (
494 node: Extract<ShapeNode, { type: "object" }> | Extract<ShapeNode, { type: "graphqlInterface" }>,
495 stack: readonly ShapeSymbolId[],
496 ): string => {
497 const required = new Set(node.type === "object" ? (node.required ?? []) : []);
498 const lines = Object.keys(node.fields)
499 .sort((left, right) => left.localeCompare(right))
500 .map((key) =>
501 `${formatPropertyKey(key)}${required.has(key) ? "" : "?"}: ${renderShape(node.fields[key]!.shapeId, { position: "nested", stack })};`
502 );
503
504 if (node.type === "object") {
505 const patternShapeIds = Object.values(node.patternProperties ?? {});
506 const hasUnknownIndex = node.additionalProperties === true;
507 const additionalShapeIds = typeof node.additionalProperties === "string"
508 ? [node.additionalProperties]
509 : [];
510 if (hasUnknownIndex || patternShapeIds.length > 0 || additionalShapeIds.length > 0) {
511 lines.push(
512 `[key: string]: ${renderIndexValueType([...patternShapeIds, ...additionalShapeIds], hasUnknownIndex)};`,
513 );
514 }
515 }
516
517 return objectTypeLiteral(lines, " ");
518 };
519
520 const renderShapeBody = (shapeId: ShapeSymbolId, stack: readonly ShapeSymbolId[]): string => {
521 const shape = getShapeSymbol(catalog, shapeId);
522 const node = shape.node;
523
524 switch (node.type) {
525 case "unknown":
526 case "scalar":
527 case "const":
528 case "enum":
529 return renderInlineShapeNode(node);
530 case "object":
531 case "graphqlInterface":
532 return renderObjectFields(node, stack);
533 case "array":
534 return `Array<${wrapCompositeType(renderShape(node.itemShapeId, { position: "nested", stack }))}>`;
535 case "tuple": {
536 const items = node.itemShapeIds.map((itemShapeId) => renderShape(itemShapeId, { position: "nested", stack }));
537 const suffix = node.additionalItems === true
538 ? ", ...unknown[]"
539 : typeof node.additionalItems === "string"
540 ? `, ...Array<${wrapCompositeType(renderShape(node.additionalItems, { position: "nested", stack }))}>`
541 : "";
542 return `[${items.join(", ")}${suffix}]`;
543 }
544 case "map":
545 return `Record<string, ${renderShape(node.valueShapeId, { position: "nested", stack })}>`;
546 case "allOf":
547 return node.items.map((itemShapeId) => wrapCompositeType(renderShape(itemShapeId, { position: "nested", stack }))).join(" & ");
548 case "anyOf":
549 case "oneOf":
550 return node.items.map((itemShapeId) => wrapCompositeType(renderShape(itemShapeId, { position: "nested", stack }))).join(" | ");
551 case "nullable":
552 return `${wrapCompositeType(renderShape(node.itemShapeId, { position: "nested", stack }))} | null`;
553 case "ref":
554 return renderShape(node.target, { position: "nested", stack });
555 case "not":
556 throw new Error(`Unsupported declaration shape node: ${node.type}`);
557 case "conditional":
558 throw new Error(`Unsupported declaration shape node: ${node.type}`);
559 case "graphqlUnion":
560 return node.memberTypeIds
561 .map((memberTypeId) => wrapCompositeType(renderShape(memberTypeId, { position: "nested", stack })))
562 .join(" | ");
563 }
564 };
565
566 const supportingTypes = (): string[] => {
567 const pending = [...usedAliasSignatures];
568 const emitted = new Set<string>();
569
570 while (pending.length > 0) {
571 const signature = pending.pop()!;
572 if (emitted.has(signature)) {
573 continue;
574 }
575
576 emitted.add(signature);
577 const representativeShapeId = representativeShapeIdForSignature(signature);
578 renderShapeBody(representativeShapeId, [representativeShapeId]);
579
580 for (const discoveredSignature of usedAliasSignatures) {
581 if (!emitted.has(discoveredSignature)) {
582 pending.push(discoveredSignature);
583 }
584 }
585 }
586
587 const declarations = [...emitted]
588 .sort((left, right) => aliasNameForSignature(left).localeCompare(aliasNameForSignature(right)))
589 .map((signature) => {
590 const representativeShapeId = representativeShapeIdForSignature(signature);
591 return `type ${aliasNameForSignature(signature)} = ${renderShapeBody(representativeShapeId, [representativeShapeId])};`;
592 });
593
594 return declarations;
595 };
596
597 return {
598 renderShape,
599 supportingTypes,
600 };
601};
602
603const shapeAllowsOmittedArgs = (catalog: CatalogV1, shapeId: ShapeSymbolId): boolean => {
604 const shape = getShapeSymbol(catalog, shapeId);
605
606 switch (shape.node.type) {
607 case "ref":
608 return shapeAllowsOmittedArgs(catalog, shape.node.target);
609 case "object":
610 return (shape.node.required ?? []).length === 0;
611 default:
612 return false;
613 }
614};
615
616const buildSourceDeclarationModel = (snapshot: CatalogSnapshotV1): SourceDeclarationModel => {
162 const projected = projectCatalogForAgentSdk({617 const projected = projectCatalogForAgentSdk({
163 catalog: snapshot.catalog,618 catalog: snapshot.catalog,
164 });619 });
620 const toolDescriptors = Object.values(projected.toolDescriptors)
621 .sort((left, right) => left.toolPath.join(".").localeCompare(right.toolPath.join(".")));
622 const renderer = createCatalogTypeRenderer({
623 catalog: projected.catalog,
624 rootShapeIds: toolDescriptors.flatMap((descriptor) => [
625 descriptor.callShapeId,
626 ...(descriptor.resultShapeId ? [descriptor.resultShapeId] : []),
627 ]),
628 });
165 629
166 return Object.values(projected.toolDescriptors)630 const methods = toolDescriptors
167 .sort((left, right) => left.toolPath.join(".").localeCompare(right.toolPath.join(".")))631 .map((descriptor) => ({
168 .map((descriptor) => {632 segments: descriptor.toolPath,
169 const inputSchema = shapeToJsonSchema(projected.catalog, descriptor.callShapeId);633 inputType: renderer.renderShape(descriptor.callShapeId, { position: "root" }),
170 const outputSchema = descriptor.resultShapeId634 outputType: descriptor.resultShapeId
171 ? shapeToJsonSchema(projected.catalog, descriptor.resultShapeId)635 ? renderer.renderShape(descriptor.resultShapeId, { position: "root" })
172 : undefined;636 : "unknown",
173 637 argsOptional: shapeAllowsOmittedArgs(projected.catalog, descriptor.callShapeId),
174 return {638 }) satisfies ToolMethodNode);
175 segments: descriptor.toolPath,639
176 inputType: typeSignatureFromSchemaWithOptions(640 return {
177 inputSchema,641 methods,
178 "unknown",642 supportingTypes: renderer.supportingTypes(),
179 DECLARATION_RENDER_OPTIONS,643 };
180 ),
181 outputType: typeSignatureFromSchemaWithOptions(
182 outputSchema,
183 "unknown",
184 DECLARATION_RENDER_OPTIONS,
185 ),
186 argsOptional: schemaAllowsOmittedArgs(inputSchema),
187 } satisfies ToolMethodNode;
188 });
189};644};
190 645
191const sourceDeclarationText = (entry: SourceDeclarationEntry): string => {646const sourceDeclarationText = (entry: SourceDeclarationEntry): string => {
192 const interfaceName = sourceTypeInterfaceName(entry.source.id);647 const interfaceName = sourceTypeInterfaceName(entry.source.id);
193 const tree = buildToolTree(collectToolMethods(entry.snapshot));648 const declarationModel = buildSourceDeclarationModel(entry.snapshot);
649 const tree = buildToolTree(declarationModel.methods);
194 const body = renderToolTreeType(tree, 0);650 const body = renderToolTreeType(tree, 0);
195 651
196 return [652 return [
197 "// Generated by executor. Do not edit by hand.",653 "// Generated by executor. Do not edit by hand.",
198 `// Source: ${entry.source.name} (${entry.source.id})`,654 `// Source: ${entry.source.name} (${entry.source.id})`,
199 "",655 "",
656 ...declarationModel.supportingTypes,
657 ...(declarationModel.supportingTypes.length > 0 ? [""] : []),
200 `export interface ${interfaceName} ${body}`,658 `export interface ${interfaceName} ${body}`,
201 "",659 "",
202 `export declare const tools: ${interfaceName};`,660 `export declare const tools: ${interfaceName};`,
@@ -367,25 +825,46 @@ export const syncSourceTypeDeclarationNode = (input: { · 164 unmodified lines
367 syncSourceTypeDeclaration(input).pipe(Effect.provide(NodeFileSystem.layer));825 syncSourceTypeDeclaration(input).pipe(Effect.provide(NodeFileSystem.layer));
368 826
369const logBackgroundDeclarationError = (label: string, cause: unknown): void => {827const logBackgroundDeclarationError = (label: string, cause: unknown): void => {
370 const message = cause instanceof Error ? cause.message : String(cause);828 const message = Cause.isCause(cause)
829 ? Cause.pretty(cause)
830 : cause instanceof Error
831 ? cause.message
832 : String(cause);
371 console.warn(`[source-types] ${label} failed: ${message}`);833 console.warn(`[source-types] ${label} failed: ${message}`);
372};834};
373 835
836const BACKGROUND_DECLARATION_REFRESH_DELAY = "1500 millis";
837const workspaceRefreshFibers = new Map<string, Fiber.RuntimeFiber<void, never>>();
838const sourceRefreshFibers = new Map<string, Fiber.RuntimeFiber<void, never>>();
839
374export const refreshWorkspaceSourceTypeDeclarationsInBackground = (input: {840export const refreshWorkspaceSourceTypeDeclarationsInBackground = (input: {
375 context: ResolvedLocalWorkspaceContext;841 context: ResolvedLocalWorkspaceContext;
376 entries: readonly SourceDeclarationEntry[];842 entries: readonly SourceDeclarationEntry[];
377}): void => {843}): void => {
378 setTimeout(() => {844 const key = input.context.configDirectory;
379 Effect.runFork(845 const existingFiber = workspaceRefreshFibers.get(key);
380 syncWorkspaceSourceTypeDeclarationsNode(input).pipe(846 if (existingFiber) {
381 Effect.catchAll((cause) =>847 Effect.runFork(Fiber.interruptFork(existingFiber));
382 Effect.sync(() => {848 }
383 logBackgroundDeclarationError("workspace declaration refresh", cause);849
384 })850 const fiber = Effect.runFork(
851 Effect.sleep(BACKGROUND_DECLARATION_REFRESH_DELAY).pipe(
852 Effect.zipRight(
853 syncWorkspaceSourceTypeDeclarationsNode(input).pipe(
854 Effect.catchAllCause((cause) =>
855 Effect.sync(() => {
856 logBackgroundDeclarationError("workspace declaration refresh", cause);
857 })
858 ),
385 ),859 ),
386 ),860 ),
387 );861 ),
388 }, 0);862 );
863
864 workspaceRefreshFibers.set(key, fiber);
865 fiber.addObserver(() => {
866 workspaceRefreshFibers.delete(key);
867 });
389};868};
390 869
391export const refreshSourceTypeDeclarationInBackground = (input: {870export const refreshSourceTypeDeclarationInBackground = (input: {
@@ -393,15 +872,28 @@ export const refreshSourceTypeDeclarationInBackground = (input: { · 1 unmodified line
393 source: Source;872 source: Source;
394 snapshot: CatalogSnapshotV1 | null;873 snapshot: CatalogSnapshotV1 | null;
395}): void => {874}): void => {
396 setTimeout(() => {875 const key = `${input.context.configDirectory}:${input.source.id}`;
397 Effect.runFork(876 const existingFiber = sourceRefreshFibers.get(key);
398 syncSourceTypeDeclarationNode(input).pipe(877 if (existingFiber) {
399 Effect.catchAll((cause) =>878 Effect.runFork(Fiber.interruptFork(existingFiber));
400 Effect.sync(() => {879 }
401 logBackgroundDeclarationError(`source ${input.source.id} declaration refresh`, cause);880
402 })881 const fiber = Effect.runFork(
882 Effect.sleep(BACKGROUND_DECLARATION_REFRESH_DELAY).pipe(
883 Effect.zipRight(
884 syncSourceTypeDeclarationNode(input).pipe(
885 Effect.catchAllCause((cause) =>
886 Effect.sync(() => {
887 logBackgroundDeclarationError(`source ${input.source.id} declaration refresh`, cause);
888 })
889 ),
403 ),890 ),
404 ),891 ),
405 );892 ),
406 }, 0);893 );
894
895 sourceRefreshFibers.set(key, fiber);
896 fiber.addObserver(() => {
897 sourceRefreshFibers.delete(key);
898 });
407};899};
packages/server/package.json+8−0
@@ -9,9 +9,17 @@ · 8 unmodified lines
9 "typecheck": "bunx tsc --noEmit -p tsconfig.json"9 "typecheck": "bunx tsc --noEmit -p tsconfig.json"
10 },10 },
11 "dependencies": {11 "dependencies": {
12 "@effect/opentelemetry": "^0.61.0",
12 "@effect/platform": "catalog:",13 "@effect/platform": "catalog:",
13 "@executor/control-plane": "workspace:*",14 "@executor/control-plane": "workspace:*",
14 "@executor/executor-mcp": "workspace:*",15 "@executor/executor-mcp": "workspace:*",
16 "@opentelemetry/api": "^1.9.0",
17 "@opentelemetry/exporter-trace-otlp-grpc": "^0.213.0",
18 "@opentelemetry/exporter-trace-otlp-http": "^0.213.0",
19 "@opentelemetry/resources": "^2.6.0",
20 "@opentelemetry/sdk-trace-base": "^2.6.0",
21 "@opentelemetry/sdk-trace-node": "^2.6.0",
22 "@opentelemetry/semantic-conventions": "^1.40.0",
15 "effect": "catalog:"23 "effect": "catalog:"
16 },24 },
17 "devDependencies": {25 "devDependencies": {
packages/server/src/config.ts+5−0
@@ -11,6 +11,11 @@ export const EXECUTOR_LOCAL_DATA_DIR_ENV = "EXECUTOR_LOCAL_DATA_DIR"; · 10 unmodified lines
11export const EXECUTOR_SERVER_PID_FILE_ENV = "EXECUTOR_SERVER_PID_FILE";11export const EXECUTOR_SERVER_PID_FILE_ENV = "EXECUTOR_SERVER_PID_FILE";
12export const EXECUTOR_SERVER_LOG_FILE_ENV = "EXECUTOR_SERVER_LOG_FILE";12export const EXECUTOR_SERVER_LOG_FILE_ENV = "EXECUTOR_SERVER_LOG_FILE";
13export const EXECUTOR_WEB_ASSETS_DIR_ENV = "EXECUTOR_WEB_ASSETS_DIR";13export const EXECUTOR_WEB_ASSETS_DIR_ENV = "EXECUTOR_WEB_ASSETS_DIR";
14export const EXECUTOR_TRACE_ENABLED_ENV = "EXECUTOR_TRACE_ENABLED";
15export const EXECUTOR_TRACE_OTLP_ENDPOINT_ENV = "EXECUTOR_TRACE_OTLP_ENDPOINT";
16export const EXECUTOR_TRACE_OTLP_HTTP_ENDPOINT_ENV = "EXECUTOR_TRACE_OTLP_HTTP_ENDPOINT";
17export const EXECUTOR_TRACE_SERVICE_NAME_ENV = "EXECUTOR_TRACE_SERVICE_NAME";
18export const EXECUTOR_TRACE_QUERY_BASE_URL_ENV = "EXECUTOR_TRACE_QUERY_BASE_URL";
14 19
15const trim = (value: string | undefined): string | undefined => {20const trim = (value: string | undefined): string | undefined => {
16 const candidate = value?.trim();21 const candidate = value?.trim();
packages/server/src/index.ts+36−3
@@ -30,7 +30,16 @@ import { · 29 unmodified lines
30 DEFAULT_SERVER_PID_FILE,30 DEFAULT_SERVER_PID_FILE,
31 DEFAULT_SERVER_HOST,31 DEFAULT_SERVER_HOST,
32 DEFAULT_SERVER_PORT,32 DEFAULT_SERVER_PORT,
33 EXECUTOR_TRACE_ENABLED_ENV,
34 EXECUTOR_TRACE_OTLP_ENDPOINT_ENV,
35 EXECUTOR_TRACE_OTLP_HTTP_ENDPOINT_ENV,
36 EXECUTOR_TRACE_QUERY_BASE_URL_ENV,
37 EXECUTOR_TRACE_SERVICE_NAME_ENV,
33} from "./config";38} from "./config";
39import {
40 createLocalTracingRuntimeFromEnv,
41 tracingSearchUrl,
42} from "./tracing";
34 43
35export {44export {
36 DEFAULT_EXECUTOR_DATA_DIR,45 DEFAULT_EXECUTOR_DATA_DIR,
@@ -47,6 +56,11 @@ export { · 10 unmodified lines
47 EXECUTOR_SERVER_PID_FILE_ENV,56 EXECUTOR_SERVER_PID_FILE_ENV,
48 EXECUTOR_SERVER_LOG_FILE_ENV,57 EXECUTOR_SERVER_LOG_FILE_ENV,
49 EXECUTOR_WEB_ASSETS_DIR_ENV,58 EXECUTOR_WEB_ASSETS_DIR_ENV,
59 EXECUTOR_TRACE_ENABLED_ENV,
60 EXECUTOR_TRACE_OTLP_ENDPOINT_ENV,
61 EXECUTOR_TRACE_OTLP_HTTP_ENDPOINT_ENV,
62 EXECUTOR_TRACE_QUERY_BASE_URL_ENV,
63 EXECUTOR_TRACE_SERVICE_NAME_ENV,
50 SERVER_POLL_INTERVAL_MS,64 SERVER_POLL_INTERVAL_MS,
51 SERVER_START_TIMEOUT_MS,65 SERVER_START_TIMEOUT_MS,
52} from "./config";66} from "./config";
@@ -205,13 +219,20 @@ const createRuntimeWithLegacyMigration = ( · 152 unmodified lines
205 );219 );
206 });220 });
207 221
208const createControlPlaneWebHandler = (runtime: ControlPlaneRuntime) =>222const createControlPlaneWebHandler = (
223 runtime: ControlPlaneRuntime,
224 tracingRuntime: ReturnType<typeof createLocalTracingRuntimeFromEnv>,
225) =>
209 Effect.acquireRelease(226 Effect.acquireRelease(
210 Effect.sync(() =>227 Effect.sync(() =>
211 HttpApiBuilder.toWebHandler(228 HttpApiBuilder.toWebHandler(
212 Layer.merge(229 Layer.merge(
213 HttpApiBuilder.middlewareOpenApi({ path: "/v1/openapi.json" }).pipe(230 HttpApiBuilder.middlewareOpenApi({ path: "/v1/openapi.json" }).pipe(
214 Layer.provideMerge(createControlPlaneApiLayer(runtime.runtimeLayer))231 Layer.provideMerge(
232 createControlPlaneApiLayer(runtime.runtimeLayer).pipe(
233 Layer.provideMerge(tracingRuntime?.layer ?? Layer.empty),
234 ),
235 )
215 ),236 ),
216 HttpServer.layerContext,237 HttpServer.layerContext,
217 ),238 ),
@@ -390,6 +411,18 @@ export const createLocalExecutorRequestHandler = ( · 172 unmodified lines
390 }411 }
391 412
392 let baseUrlRef: string | undefined;413 let baseUrlRef: string | undefined;
414 const tracingRuntime = createLocalTracingRuntimeFromEnv();
415
416 if (tracingRuntime) {
417 yield* Effect.sync(() => {
418 console.info(
419 `[executor] tracing enabled -> ${tracingSearchUrl({
420 queryBaseUrl: tracingRuntime.queryBaseUrl,
421 serviceName: tracingRuntime.serviceName,
422 })}`,
423 );
424 });
425 }
393 426
394 const runtime = yield* Effect.acquireRelease(427 const runtime = yield* Effect.acquireRelease(
395 createRuntimeWithLegacyMigration(428 createRuntimeWithLegacyMigration(
@@ -401,7 +434,7 @@ export const createLocalExecutorRequestHandler = ( · 5 unmodified lines
401 disposeRuntime,434 disposeRuntime,
402 );435 );
403 436
404 const apiHandler = yield* createControlPlaneWebHandler(runtime);437 const apiHandler = yield* createControlPlaneWebHandler(runtime, tracingRuntime);
405 const mcpHandler = yield* Effect.acquireRelease(438 const mcpHandler = yield* Effect.acquireRelease(
406 Effect.sync(() => createExecutorMcpRequestHandler(runtime)),439 Effect.sync(() => createExecutorMcpRequestHandler(runtime)),
407 (handler: ExecutorMcpHandler) =>440 (handler: ExecutorMcpHandler) =>
packages/server/src/tracing.ts+66−0
@@ -0,0 +1,66 @@
1import * as NodeSdk from "@effect/opentelemetry/NodeSdk";
2import { OTLPTraceExporter } from "@opentelemetry/exporter-trace-otlp-grpc";
3import { SimpleSpanProcessor } from "@opentelemetry/sdk-trace-base";
4import * as Layer from "effect/Layer";
5
6import {
7 EXECUTOR_TRACE_ENABLED_ENV,
8 EXECUTOR_TRACE_OTLP_ENDPOINT_ENV,
9 EXECUTOR_TRACE_OTLP_HTTP_ENDPOINT_ENV,
10 EXECUTOR_TRACE_QUERY_BASE_URL_ENV,
11 EXECUTOR_TRACE_SERVICE_NAME_ENV,
12} from "./config";
13
14const DEFAULT_TRACE_OTLP_ENDPOINT = "http://127.0.0.1:4317";
15const DEFAULT_TRACE_QUERY_BASE_URL = "http://127.0.0.1:16686";
16const DEFAULT_TRACE_SERVICE_NAME = "executor-local";
17
18export type LocalTracingRuntime = {
19 readonly layer: Layer.Layer<never>;
20 readonly otlpEndpoint: string;
21 readonly queryBaseUrl: string;
22 readonly serviceName: string;
23};
24
25const trim = (value: string | undefined): string | undefined => {
26 const candidate = value?.trim();
27 return candidate && candidate.length > 0 ? candidate : undefined;
28};
29
30const envFlag = (value: string | undefined): boolean => {
31 const normalized = value?.trim().toLowerCase();
32 return normalized === "1" || normalized === "true" || normalized === "yes" || normalized === "on";
33};
34
35export const createLocalTracingRuntimeFromEnv = (): LocalTracingRuntime | null => {
36 if (!envFlag(process.env[EXECUTOR_TRACE_ENABLED_ENV])) {
37 return null;
38 }
39
40 const otlpEndpoint =
41 trim(process.env[EXECUTOR_TRACE_OTLP_ENDPOINT_ENV])
42 ?? trim(process.env[EXECUTOR_TRACE_OTLP_HTTP_ENDPOINT_ENV])
43 ?? DEFAULT_TRACE_OTLP_ENDPOINT;
44 const serviceName = trim(process.env[EXECUTOR_TRACE_SERVICE_NAME_ENV]) ?? DEFAULT_TRACE_SERVICE_NAME;
45 const queryBaseUrl = trim(process.env[EXECUTOR_TRACE_QUERY_BASE_URL_ENV]) ?? DEFAULT_TRACE_QUERY_BASE_URL;
46
47 return {
48 layer: NodeSdk.layer(() => ({
49 resource: {
50 serviceName,
51 attributes: {
52 "service.namespace": "executor",
53 },
54 },
55 spanProcessor: [new SimpleSpanProcessor(new OTLPTraceExporter({ url: otlpEndpoint }))],
56 })),
57 otlpEndpoint,
58 queryBaseUrl,
59 serviceName,
60 };
61};
62
63export const tracingSearchUrl = (input: {
64 queryBaseUrl: string;
65 serviceName: string;
66}): string => `${input.queryBaseUrl.replace(/\/$/, "")}/search?service=${encodeURIComponent(input.serviceName)}`;
personal-notes/otel-tracing-for-source-connect.md+50−0
@@ -0,0 +1,50 @@
1# OTel Tracing For Source Connect
2
3## Setup
4
5- Use the Effect-native OTel layer from `@effect/opentelemetry`, not a hand-rolled tracer bridge.
6- Start Jaeger with `bun run trace:up`.
7- Run the dev server with:
8
9```bash
10EXECUTOR_TRACE_ENABLED=1 \
11EXECUTOR_TRACE_SERVICE_NAME=executor-local \
12EXECUTOR_TRACE_OTLP_ENDPOINT=http://127.0.0.1:4317 \
13bun run dev
14```
15
16- Query traces via:
17
18```bash
19curl "http://127.0.0.1:16686/api/traces?service=executor-local&limit=20"
20```
21
22## Useful spans
23
24- `source.connect.http`
25- `source.catalog.sync`
26- `source.store.persist`
27- `source.store.load_by_id`
28- `source.status.update`
29- `graphql.syncCatalog`
30- `graphql.introspection.fetch`
31- `graphql.manifest.extract`
32- `graphql.definitions.compile`
33- `graphql.operations.build`
34- `graphql.snapshot.build`
35
36## What the traces showed
37
38- Raw Linear introspection fetch is fast, around sub-second to about one second.
39- The biggest remaining cost in the GraphQL import path is `graphql.operations.build`, around 5s on Linear.
40- A large earlier regression was not GraphQL import itself. It was declaration refresh churn interfering with the connect flow.
41- The fix was:
42 - keep `.d.ts` generation backgrounded
43 - debounce it with Effect fibers / `Effect.sleep`
44 - avoid scheduling workspace-wide declaration refresh during normal `probing` / `connected` source persists
45
46## Current state
47
48- Fresh Linear `connect` is back down to about 7-8s instead of ~70s.
49- `linear.d.ts` is much smaller now because source-level shared shapes are deduped.
50- The next performance target is `graphql.operations.build`, not tracing or `.d.ts` scheduling.