-
Notifications
You must be signed in to change notification settings - Fork 110
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: add metadata to hive ui with linked directive support #6517
base: main
Are you sure you want to change the base?
Conversation
This comment was marked as off-topic.
This comment was marked as off-topic.
📚 Storybook DeploymentThe latest changes are available as preview in: https://5f992a99.hive-storybook.pages.dev |
🐋 This PR was built and pushed to the following Docker images: Targets: Platforms: Image Tag: Docker Bake metadata{
"app": {
"buildx.build.provenance": {
"buildType": "https://mobyproject.org/buildkit@v1",
"materials": [
{
"uri": "pkg:docker/[email protected]?platform=linux%2Farm64",
"digest": {
"sha256": "f5a0871ab03b035c58bdb3007c3d177b001c2145c18e81817b71624dcf7d8bff"
}
}
],
"invocation": {
"configSource": {
"entryPoint": "services.dockerfile"
},
"parameters": {
"frontend": "dockerfile.v0",
"args": {
"build-arg:HEALTHCHECK_CMD": "wget --spider -q http://127.0.0.1:${PORT}/api/health",
"build-arg:IMAGE_DESCRIPTION": "The app of the GraphQL Hive project.",
"build-arg:IMAGE_TITLE": "graphql-hive/app",
"build-arg:PORT": "3000",
"build-arg:RELEASE": "6c5c165e29e8253a09fc7b1691a32cd5e8d7c441",
"build-arg:SERVICE_DIR_NAME": "@hive/app",
"context:dist": "local:dist",
"context:shared": "local:shared",
"frontend.caps": "moby.buildkit.frontend.contexts+forward",
"local-sessionid:context": "ob3vzrhz5faabymfqxsubkhg3",
"local-sessionid:dockerfile": "ob3vzrhz5faabymfqxsubkhg3",
"local-sessionid:shared": "ob3vzrhz5faabymfqxsubkhg3"
},
"locals": [
{
"name": "context"
},
{
"name": "dist"
},
{
"name": "dockerfile"
},
{
"name": "shared"
}
]
},
"environment": {
"platform": "linux/arm64"
}
}
},
"buildx.build.ref": "builder-ed970045-9563-45fe-826e-916713cd23dd/builder-ed970045-9563-45fe-826e-916713cd23dd0/oobuvk7syeijo67zyyhytlkkk",
"containerimage.config.digest": "sha256:ba862f1d1aa683f1867e27cf6af19036caa29bd9c7e75315f32b594c0e850907",
"containerimage.descriptor": {
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"digest": "sha256:a2b4eebf56145a3dadd621b241fd5f8c4dc480298af201c26534947b75781a57",
"size": 2075,
"platform": {
"architecture": "arm64",
"os": "linux"
}
},
"containerimage.digest": "sha256:a2b4eebf56145a3dadd621b241fd5f8c4dc480298af201c26534947b75781a57",
"image.name": "ghcr.io/graphql-hive/app:6c5c165e29e8253a09fc7b1691a32cd5e8d7c441-arm64,ghcr.io/graphql-hive/app:hive_metadata-arm64"
},
"buildx.build.warnings": [
{
"vertex": "sha256:94f61d6ac2d67e23827b0f629f7955fa2d16bcccf076f3044bf746b76e24fed1",
"level": 1,
"short": "VW5kZWZpbmVkVmFyOiBVc2FnZSBvZiB1bmRlZmluZWQgdmFyaWFibGUgJyRJTUFHRV9USVRMRScgKGxpbmUgMTIp",
"detail": [
"VmFyaWFibGVzIHNob3VsZCBiZSBkZWZpbmVkIGJlZm9yZSB0aGVpciB1c2U="
],
"url": "https://docs.docker.com/go/dockerfile/rule/undefined-var/",
"sourceInfo": {
"filename": "services.dockerfile",
"data": "RlJPTSBub2RlOjIyLjEzLjAtc2xpbQoKUlVOIGFwdC1nZXQgdXBkYXRlICYmIGFwdC1nZXQgaW5zdGFsbCAteSB3Z2V0IGNhLWNlcnRpZmljYXRlcyAmJiBybSAtcmYgL3Zhci9saWIvYXB0L2xpc3RzLyoKCkFSRyBTRVJWSUNFX0RJUl9OQU1FCldPUktESVIgL3Vzci9zcmMvYXBwLyRTRVJWSUNFX0RJUl9OQU1FCgpDT1BZIC0tZnJvbT1kaXN0IC4gL3Vzci9zcmMvYXBwLyRTRVJWSUNFX0RJUl9OQU1FLwpDT1BZIC0tZnJvbT1zaGFyZWQgLiAvCgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UubGljZW5zZXM9TUlUCkxBQkVMIG9yZy5vcGVuY29udGFpbmVycy5pbWFnZS50aXRsZT0kSU1BR0VfVElUTEUKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLnZlcnNpb249JFJFTEVBU0UKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLmRlc2NyaXB0aW9uPSRJTUFHRV9ERVNDUklQVElPTgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UuYXV0aG9ycz0iVGhlIEd1aWxkIgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UudmVuZG9yPSJLYW1pbCBLaXNpZWxhIgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UudXJsPSJodHRwczovL2dpdGh1Yi5jb20vZ3JhcGhxbC1oaXZlL3BsYXRmb3JtIgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2Uuc291cmNlPSJodHRwczovL2dpdGh1Yi5jb20vZ3JhcGhxbC1oaXZlL3BsYXRmb3JtIgoKRU5WIEVOVklST05NRU5UIHByb2R1Y3Rpb24KRU5WIFJFTEVBU0UgJFJFTEVBU0UKRU5WIFBPUlQgJFBPUlQKCkhFQUxUSENIRUNLIC0taW50ZXJ2YWw9NXMgXAogIC0tdGltZW91dD01cyBcCiAgLS1zdGFydC1wZXJpb2Q9NXMgXAogIC0tcmV0cmllcz02IFwKICBDTUQgJEhFQUxUSENIRUNLX0NNRAoKRU5UUllQT0lOVCBbICIvZW50cnlwb2ludC5zaCIgXQo=",
"language": "Dockerfile"
},
"range": [
{
"start": {
"line": 12
},
"end": {
"line": 12
}
}
]
},
{
"vertex": "sha256:94f61d6ac2d67e23827b0f629f7955fa2d16bcccf076f3044bf746b76e24fed1",
"level": 1,
"short": "VW5kZWZpbmVkVmFyOiBVc2FnZSBvZiB1bmRlZmluZWQgdmFyaWFibGUgJyRJTUFHRV9ERVNDUklQVElPTicgKGxpbmUgMTQp",
"detail": [
"VmFyaWFibGVzIHNob3VsZCBiZSBkZWZpbmVkIGJlZm9yZSB0aGVpciB1c2U="
],
"url": "https://docs.docker.com/go/dockerfile/rule/undefined-var/",
"sourceInfo": {
"filename": "services.dockerfile",
"data": "RlJPTSBub2RlOjIyLjEzLjAtc2xpbQoKUlVOIGFwdC1nZXQgdXBkYXRlICYmIGFwdC1nZXQgaW5zdGFsbCAteSB3Z2V0IGNhLWNlcnRpZmljYXRlcyAmJiBybSAtcmYgL3Zhci9saWIvYXB0L2xpc3RzLyoKCkFSRyBTRVJWSUNFX0RJUl9OQU1FCldPUktESVIgL3Vzci9zcmMvYXBwLyRTRVJWSUNFX0RJUl9OQU1FCgpDT1BZIC0tZnJvbT1kaXN0IC4gL3Vzci9zcmMvYXBwLyRTRVJWSUNFX0RJUl9OQU1FLwpDT1BZIC0tZnJvbT1zaGFyZWQgLiAvCgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UubGljZW5zZXM9TUlUCkxBQkVMIG9yZy5vcGVuY29udGFpbmVycy5pbWFnZS50aXRsZT0kSU1BR0VfVElUTEUKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLnZlcnNpb249JFJFTEVBU0UKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLmRlc2NyaXB0aW9uPSRJTUFHRV9ERVNDUklQVElPTgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UuYXV0aG9ycz0iVGhlIEd1aWxkIgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UudmVuZG9yPSJLYW1pbCBLaXNpZWxhIgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UudXJsPSJodHRwczovL2dpdGh1Yi5jb20vZ3JhcGhxbC1oaXZlL3BsYXRmb3JtIgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2Uuc291cmNlPSJodHRwczovL2dpdGh1Yi5jb20vZ3JhcGhxbC1oaXZlL3BsYXRmb3JtIgoKRU5WIEVOVklST05NRU5UIHByb2R1Y3Rpb24KRU5WIFJFTEVBU0UgJFJFTEVBU0UKRU5WIFBPUlQgJFBPUlQKCkhFQUxUSENIRUNLIC0taW50ZXJ2YWw9NXMgXAogIC0tdGltZW91dD01cyBcCiAgLS1zdGFydC1wZXJpb2Q9NXMgXAogIC0tcmV0cmllcz02IFwKICBDTUQgJEhFQUxUSENIRUNLX0NNRAoKRU5UUllQT0lOVCBbICIvZW50cnlwb2ludC5zaCIgXQo=",
"language": "Dockerfile"
},
"range": [
{
"start": {
"line": 14
},
"end": {
"line": 14
}
}
]
},
{
"vertex": "sha256:94f61d6ac2d67e23827b0f629f7955fa2d16bcccf076f3044bf746b76e24fed1",
"level": 1,
"short": "TGVnYWN5S2V5VmFsdWVGb3JtYXQ6ICJFTlYga2V5PXZhbHVlIiBzaG91bGQgYmUgdXNlZCBpbnN0ZWFkIG9mIGxlZ2FjeSAiRU5WIGtleSB2YWx1ZSIgZm9ybWF0IChsaW5lIDIwKQ==",
"detail": [
"TGVnYWN5IGtleS92YWx1ZSBmb3JtYXQgd2l0aCB3aGl0ZXNwYWNlIHNlcGFyYXRvciBzaG91bGQgbm90IGJlIHVzZWQ="
],
"url": "https://docs.docker.com/go/dockerfile/rule/legacy-key-value-format/",
"sourceInfo": {
"filename": "services.dockerfile",
"data": "RlJPTSBub2RlOjIyLjEzLjAtc2xpbQoKUlVOIGFwdC1nZXQgdXBkYXRlICYmIGFwdC1nZXQgaW5zdGFsbCAteSB3Z2V0IGNhLWNlcnRpZmljYXRlcyAmJiBybSAtcmYgL3Zhci9saWIvYXB0L2xpc3RzLyoKCkFSRyBTRVJWSUNFX0RJUl9OQU1FCldPUktESVIgL3Vzci9zcmMvYXBwLyRTRVJWSUNFX0RJUl9OQU1FCgpDT1BZIC0tZnJvbT1kaXN0IC4gL3Vzci9zcmMvYXBwLyRTRVJWSUNFX0RJUl9OQU1FLwpDT1BZIC0tZnJvbT1zaGFyZWQgLiAvCgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UubGljZW5zZXM9TUlUCkxBQkVMIG9yZy5vcGVuY29udGFpbmVycy5pbWFnZS50aXRsZT0kSU1BR0VfVElUTEUKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLnZlcnNpb249JFJFTEVBU0UKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLmRlc2NyaXB0aW9uPSRJTUFHRV9ERVNDUklQVElPTgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UuYXV0aG9ycz0iVGhlIEd1aWxkIgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UudmVuZG9yPSJLYW1pbCBLaXNpZWxhIgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UudXJsPSJodHRwczovL2dpdGh1Yi5jb20vZ3JhcGhxbC1oaXZlL3BsYXRmb3JtIgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2Uuc291cmNlPSJodHRwczovL2dpdGh1Yi5jb20vZ3JhcGhxbC1oaXZlL3BsYXRmb3JtIgoKRU5WIEVOVklST05NRU5UIHByb2R1Y3Rpb24KRU5WIFJFTEVBU0UgJFJFTEVBU0UKRU5WIFBPUlQgJFBPUlQKCkhFQUxUSENIRUNLIC0taW50ZXJ2YWw9NXMgXAogIC0tdGltZW91dD01cyBcCiAgLS1zdGFydC1wZXJpb2Q9NXMgXAogIC0tcmV0cmllcz02IFwKICBDTUQgJEhFQUxUSENIRUNLX0NNRAoKRU5UUllQT0lOVCBbICIvZW50cnlwb2ludC5zaCIgXQo=",
"language": "Dockerfile"
},
"range": [
{
"start": {
"line": 20
},
"end": {
"line": 20
}
}
]
},
{
"vertex": "sha256:94f61d6ac2d67e23827b0f629f7955fa2d16bcccf076f3044bf746b76e24fed1",
"level": 1,
"short": "VW5kZWZpbmVkVmFyOiBVc2FnZSBvZiB1bmRlZmluZWQgdmFyaWFibGUgJyRQT1JUJyAobGluZSAyMik=",
"detail": [
"VmFyaWFibGVzIHNob3VsZCBiZSBkZWZpbmVkIGJlZm9yZSB0aGVpciB1c2U="
],
"url": "https://docs.docker.com/go/dockerfile/rule/undefined-var/",
"sourceInfo": {
"filename": "services.dockerfile",
"data": "RlJPTSBub2RlOjIyLjEzLjAtc2xpbQoKUlVOIGFwdC1nZXQgdXBkYXRlICYmIGFwdC1nZXQgaW5zdGFsbCAteSB3Z2V0IGNhLWNlcnRpZmljYXRlcyAmJiBybSAtcmYgL3Zhci9saWIvYXB0L2xpc3RzLyoKCkFSRyBTRVJWSUNFX0RJUl9OQU1FCldPUktESVIgL3Vzci9zcmMvYXBwLyRTRVJWSUNFX0RJUl9OQU1FCgpDT1BZIC0tZnJvbT1kaXN0IC4gL3Vzci9zcmMvYXBwLyRTRVJWSUNFX0RJUl9OQU1FLwpDT1BZIC0tZnJvbT1zaGFyZWQgLiAvCgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UubGljZW5zZXM9TUlUCkxBQkVMIG9yZy5vcGVuY29udGFpbmVycy5pbWFnZS50aXRsZT0kSU1BR0VfVElUTEUKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLnZlcnNpb249JFJFTEVBU0UKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLmRlc2NyaXB0aW9uPSRJTUFHRV9ERVNDUklQVElPTgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UuYXV0aG9ycz0iVGhlIEd1aWxkIgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UudmVuZG9yPSJLYW1pbCBLaXNpZWxhIgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UudXJsPSJodHRwczovL2dpdGh1Yi5jb20vZ3JhcGhxbC1oaXZlL3BsYXRmb3JtIgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2Uuc291cmNlPSJodHRwczovL2dpdGh1Yi5jb20vZ3JhcGhxbC1oaXZlL3BsYXRmb3JtIgoKRU5WIEVOVklST05NRU5UIHByb2R1Y3Rpb24KRU5WIFJFTEVBU0UgJFJFTEVBU0UKRU5WIFBPUlQgJFBPUlQKCkhFQUxUSENIRUNLIC0taW50ZXJ2YWw9NXMgXAogIC0tdGltZW91dD01cyBcCiAgLS1zdGFydC1wZXJpb2Q9NXMgXAogIC0tcmV0cmllcz02IFwKICBDTUQgJEhFQUxUSENIRUNLX0NNRAoKRU5UUllQT0lOVCBbICIvZW50cnlwb2ludC5zaCIgXQo=",
"language": "Dockerfile"
},
"range": [
{
"start": {
"line": 22
},
"end": {
"line": 22
}
}
]
},
{
"vertex": "sha256:f566d20768d5de07570a6c8a6f8ff75579add219b415f5f6622ba0876b86001f",
"level": 1,
"short": "TGVnYWN5S2V5VmFsdWVGb3JtYXQ6ICJFTlYga2V5PXZhbHVlIiBzaG91bGQgYmUgdXNlZCBpbnN0ZWFkIG9mIGxlZ2FjeSAiRU5WIGtleSB2YWx1ZSIgZm9ybWF0IChsaW5lIDEwKQ==",
"detail": [
"TGVnYWN5IGtleS92YWx1ZSBmb3JtYXQgd2l0aCB3aGl0ZXNwYWNlIHNlcGFyYXRvciBzaG91bGQgbm90IGJlIHVzZWQ="
],
"url": "https://docs.docker.com/go/dockerfile/rule/legacy-key-value-format/",
"sourceInfo": {
"filename": "migrations.dockerfile",
"data": "RlJPTSBub2RlOjIyLjEzLjAtc2xpbQoKUlVOIGFwdC1nZXQgdXBkYXRlICYmIGFwdC1nZXQgaW5zdGFsbCAteSBjYS1jZXJ0aWZpY2F0ZXMKCldPUktESVIgL3Vzci9zcmMvYXBwCgpDT1BZIC0tZnJvbT1kaXN0IC4gL3Vzci9zcmMvYXBwLwpDT1BZIC0tZnJvbT1zaGFyZWQgLiAvCgpFTlYgRU5WSVJPTk1FTlQgcHJvZHVjdGlvbgpFTlYgTk9ERV9FTlYgcHJvZHVjdGlvbgpFTlYgUkVMRUFTRSAkUkVMRUFTRQoKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLmxpY2Vuc2VzPU1JVApMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UudGl0bGU9JElNQUdFX1RJVExFCkxBQkVMIG9yZy5vcGVuY29udGFpbmVycy5pbWFnZS52ZXJzaW9uPSRSRUxFQVNFCkxBQkVMIG9yZy5vcGVuY29udGFpbmVycy5pbWFnZS5kZXNjcmlwdGlvbj0kSU1BR0VfREVTQ1JJUFRJT04KTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLmF1dGhvcnM9IlRoZSBHdWlsZCIKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLnZlbmRvcj0iS2FtaWwgS2lzaWVsYSIKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLnVybD0iaHR0cHM6Ly9naXRodWIuY29tL2dyYXBocWwtaGl2ZS9wbGF0Zm9ybSIKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLnNvdXJjZT0iaHR0cHM6Ly9naXRodWIuY29tL2dyYXBocWwtaGl2ZS9wbGF0Zm9ybSIKCkVOVFJZUE9JTlQgWyAiL2VudHJ5cG9pbnQuc2giIF0K",
"language": "Dockerfile"
},
"range": [
{
"start": {
"line": 10
},
"end": {
"line": 10
}
}
]
},
{
"vertex": "sha256:f566d20768d5de07570a6c8a6f8ff75579add219b415f5f6622ba0876b86001f",
"level": 1,
"short": "TGVnYWN5S2V5VmFsdWVGb3JtYXQ6ICJFTlYga2V5PXZhbHVlIiBzaG91bGQgYmUgdXNlZCBpbnN0ZWFkIG9mIGxlZ2FjeSAiRU5WIGtleSB2YWx1ZSIgZm9ybWF0IChsaW5lIDExKQ==",
"detail": [
"TGVnYWN5IGtleS92YWx1ZSBmb3JtYXQgd2l0aCB3aGl0ZXNwYWNlIHNlcGFyYXRvciBzaG91bGQgbm90IGJlIHVzZWQ="
],
"url": "https://docs.docker.com/go/dockerfile/rule/legacy-key-value-format/",
"sourceInfo": {
"filename": "migrations.dockerfile",
"data": "RlJPTSBub2RlOjIyLjEzLjAtc2xpbQoKUlVOIGFwdC1nZXQgdXBkYXRlICYmIGFwdC1nZXQgaW5zdGFsbCAteSBjYS1jZXJ0aWZpY2F0ZXMKCldPUktESVIgL3Vzci9zcmMvYXBwCgpDT1BZIC0tZnJvbT1kaXN0IC4gL3Vzci9zcmMvYXBwLwpDT1BZIC0tZnJvbT1zaGFyZWQgLiAvCgpFTlYgRU5WSVJPTk1FTlQgcHJvZHVjdGlvbgpFTlYgTk9ERV9FTlYgcHJvZHVjdGlvbgpFTlYgUkVMRUFTRSAkUkVMRUFTRQoKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLmxpY2Vuc2VzPU1JVApMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UudGl0bGU9JElNQUdFX1RJVExFCkxBQkVMIG9yZy5vcGVuY29udGFpbmVycy5pbWFnZS52ZXJzaW9uPSRSRUxFQVNFCkxBQkVMIG9yZy5vcGVuY29udGFpbmVycy5pbWFnZS5kZXNjcmlwdGlvbj0kSU1BR0VfREVTQ1JJUFRJT04KTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLmF1dGhvcnM9IlRoZSBHdWlsZCIKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLnZlbmRvcj0iS2FtaWwgS2lzaWVsYSIKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLnVybD0iaHR0cHM6Ly9naXRodWIuY29tL2dyYXBocWwtaGl2ZS9wbGF0Zm9ybSIKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLnNvdXJjZT0iaHR0cHM6Ly9naXRodWIuY29tL2dyYXBocWwtaGl2ZS9wbGF0Zm9ybSIKCkVOVFJZUE9JTlQgWyAiL2VudHJ5cG9pbnQuc2giIF0K",
"language": "Dockerfile"
},
"range": [
{
"start": {
"line": 11
},
"end": {
"line": 11
}
}
]
},
{
"vertex": "sha256:f566d20768d5de07570a6c8a6f8ff75579add219b415f5f6622ba0876b86001f",
"level": 1,
"short": "TGVnYWN5S2V5VmFsdWVGb3JtYXQ6ICJFTlYga2V5PXZhbHVlIiBzaG91bGQgYmUgdXNlZCBpbnN0ZWFkIG9mIGxlZ2FjeSAiRU5WIGtleSB2YWx1ZSIgZm9ybWF0IChsaW5lIDEyKQ==",
"detail": [
"TGVnYWN5IGtleS92YWx1ZSBmb3JtYXQgd2l0aCB3aGl0ZXNwYWNlIHNlcGFyYXRvciBzaG91bGQgbm90IGJlIHVzZWQ="
],
"url": "https://docs.docker.com/go/dockerfile/rule/legacy-key-value-format/",
"sourceInfo": {
"filename": "migrations.dockerfile",
"data": "RlJPTSBub2RlOjIyLjEzLjAtc2xpbQoKUlVOIGFwdC1nZXQgdXBkYXRlICYmIGFwdC1nZXQgaW5zdGFsbCAteSBjYS1jZXJ0aWZpY2F0ZXMKCldPUktESVIgL3Vzci9zcmMvYXBwCgpDT1BZIC0tZnJvbT1kaXN0IC4gL3Vzci9zcmMvYXBwLwpDT1BZIC0tZnJvbT1zaGFyZWQgLiAvCgpFTlYgRU5WSVJPTk1FTlQgcHJvZHVjdGlvbgpFTlYgTk9ERV9FTlYgcHJvZHVjdGlvbgpFTlYgUkVMRUFTRSAkUkVMRUFTRQoKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLmxpY2Vuc2VzPU1JVApMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UudGl0bGU9JElNQUdFX1RJVExFCkxBQkVMIG9yZy5vcGVuY29udGFpbmVycy5pbWFnZS52ZXJzaW9uPSRSRUxFQVNFCkxBQkVMIG9yZy5vcGVuY29udGFpbmVycy5pbWFnZS5kZXNjcmlwdGlvbj0kSU1BR0VfREVTQ1JJUFRJT04KTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLmF1dGhvcnM9IlRoZSBHdWlsZCIKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLnZlbmRvcj0iS2FtaWwgS2lzaWVsYSIKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLnVybD0iaHR0cHM6Ly9naXRodWIuY29tL2dyYXBocWwtaGl2ZS9wbGF0Zm9ybSIKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLnNvdXJjZT0iaHR0cHM6Ly9naXRodWIuY29tL2dyYXBocWwtaGl2ZS9wbGF0Zm9ybSIKCkVOVFJZUE9JTlQgWyAiL2VudHJ5cG9pbnQuc2giIF0K",
"language": "Dockerfile"
},
"range": [
{
"start": {
"line": 12
},
"end": {
"line": 12
}
}
]
},
{
"vertex": "sha256:94f61d6ac2d67e23827b0f629f7955fa2d16bcccf076f3044bf746b76e24fed1",
"level": 1,
"short": "VW5kZWZpbmVkVmFyOiBVc2FnZSBvZiB1bmRlZmluZWQgdmFyaWFibGUgJyRSRUxFQVNFJyAobGluZSAxMyk=",
"detail": [
"VmFyaWFibGVzIHNob3VsZCBiZSBkZWZpbmVkIGJlZm9yZSB0aGVpciB1c2U="
],
"url": "https://docs.docker.com/go/dockerfile/rule/undefined-var/",
"sourceInfo": {
"filename": "services.dockerfile",
"data": "RlJPTSBub2RlOjIyLjEzLjAtc2xpbQoKUlVOIGFwdC1nZXQgdXBkYXRlICYmIGFwdC1nZXQgaW5zdGFsbCAteSB3Z2V0IGNhLWNlcnRpZmljYXRlcyAmJiBybSAtcmYgL3Zhci9saWIvYXB0L2xpc3RzLyoKCkFSRyBTRVJWSUNFX0RJUl9OQU1FCldPUktESVIgL3Vzci9zcmMvYXBwLyRTRVJWSUNFX0RJUl9OQU1FCgpDT1BZIC0tZnJvbT1kaXN0IC4gL3Vzci9zcmMvYXBwLyRTRVJWSUNFX0RJUl9OQU1FLwpDT1BZIC0tZnJvbT1zaGFyZWQgLiAvCgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UubGljZW5zZXM9TUlUCkxBQkVMIG9yZy5vcGVuY29udGFpbmVycy5pbWFnZS50aXRsZT0kSU1BR0VfVElUTEUKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLnZlcnNpb249JFJFTEVBU0UKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLmRlc2NyaXB0aW9uPSRJTUFHRV9ERVNDUklQVElPTgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UuYXV0aG9ycz0iVGhlIEd1aWxkIgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UudmVuZG9yPSJLYW1pbCBLaXNpZWxhIgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UudXJsPSJodHRwczovL2dpdGh1Yi5jb20vZ3JhcGhxbC1oaXZlL3BsYXRmb3JtIgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2Uuc291cmNlPSJodHRwczovL2dpdGh1Yi5jb20vZ3JhcGhxbC1oaXZlL3BsYXRmb3JtIgoKRU5WIEVOVklST05NRU5UIHByb2R1Y3Rpb24KRU5WIFJFTEVBU0UgJFJFTEVBU0UKRU5WIFBPUlQgJFBPUlQKCkhFQUxUSENIRUNLIC0taW50ZXJ2YWw9NXMgXAogIC0tdGltZW91dD01cyBcCiAgLS1zdGFydC1wZXJpb2Q9NXMgXAogIC0tcmV0cmllcz02IFwKICBDTUQgJEhFQUxUSENIRUNLX0NNRAoKRU5UUllQT0lOVCBbICIvZW50cnlwb2ludC5zaCIgXQo=",
"language": "Dockerfile"
},
"range": [
{
"start": {
"line": 13
},
"end": {
"line": 13
}
}
]
},
{
"vertex": "sha256:94f61d6ac2d67e23827b0f629f7955fa2d16bcccf076f3044bf746b76e24fed1",
"level": 1,
"short": "VW5kZWZpbmVkVmFyOiBVc2FnZSBvZiB1bmRlZmluZWQgdmFyaWFibGUgJyRSRUxFQVNFJyAobGluZSAyMSk=",
"detail": [
"VmFyaWFibGVzIHNob3VsZCBiZSBkZWZpbmVkIGJlZm9yZSB0aGVpciB1c2U="
],
"url": "https://docs.docker.com/go/dockerfile/rule/undefined-var/",
"sourceInfo": {
"filename": "services.dockerfile",
"data": "RlJPTSBub2RlOjIyLjEzLjAtc2xpbQoKUlVOIGFwdC1nZXQgdXBkYXRlICYmIGFwdC1nZXQgaW5zdGFsbCAteSB3Z2V0IGNhLWNlcnRpZmljYXRlcyAmJiBybSAtcmYgL3Zhci9saWIvYXB0L2xpc3RzLyoKCkFSRyBTRVJWSUNFX0RJUl9OQU1FCldPUktESVIgL3Vzci9zcmMvYXBwLyRTRVJWSUNFX0RJUl9OQU1FCgpDT1BZIC0tZnJvbT1kaXN0IC4gL3Vzci9zcmMvYXBwLyRTRVJWSUNFX0RJUl9OQU1FLwpDT1BZIC0tZnJvbT1zaGFyZWQgLiAvCgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UubGljZW5zZXM9TUlUCkxBQkVMIG9yZy5vcGVuY29udGFpbmVycy5pbWFnZS50aXRsZT0kSU1BR0VfVElUTEUKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLnZlcnNpb249JFJFTEVBU0UKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLmRlc2NyaXB0aW9uPSRJTUFHRV9ERVNDUklQVElPTgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UuYXV0aG9ycz0iVGhlIEd1aWxkIgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UudmVuZG9yPSJLYW1pbCBLaXNpZWxhIgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UudXJsPSJodHRwczovL2dpdGh1Yi5jb20vZ3JhcGhxbC1oaXZlL3BsYXRmb3JtIgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2Uuc291cmNlPSJodHRwczovL2dpdGh1Yi5jb20vZ3JhcGhxbC1oaXZlL3BsYXRmb3JtIgoKRU5WIEVOVklST05NRU5UIHByb2R1Y3Rpb24KRU5WIFJFTEVBU0UgJFJFTEVBU0UKRU5WIFBPUlQgJFBPUlQKCkhFQUxUSENIRUNLIC0taW50ZXJ2YWw9NXMgXAogIC0tdGltZW91dD01cyBcCiAgLS1zdGFydC1wZXJpb2Q9NXMgXAogIC0tcmV0cmllcz02IFwKICBDTUQgJEhFQUxUSENIRUNLX0NNRAoKRU5UUllQT0lOVCBbICIvZW50cnlwb2ludC5zaCIgXQo=",
"language": "Dockerfile"
},
"range": [
{
"start": {
"line": 21
},
"end": {
"line": 21
}
}
]
},
{
"vertex": "sha256:94f61d6ac2d67e23827b0f629f7955fa2d16bcccf076f3044bf746b76e24fed1",
"level": 1,
"short": "TGVnYWN5S2V5VmFsdWVGb3JtYXQ6ICJFTlYga2V5PXZhbHVlIiBzaG91bGQgYmUgdXNlZCBpbnN0ZWFkIG9mIGxlZ2FjeSAiRU5WIGtleSB2YWx1ZSIgZm9ybWF0IChsaW5lIDIxKQ==",
"detail": [
"TGVnYWN5IGtleS92YWx1ZSBmb3JtYXQgd2l0aCB3aGl0ZXNwYWNlIHNlcGFyYXRvciBzaG91bGQgbm90IGJlIHVzZWQ="
],
"url": "https://docs.docker.com/go/dockerfile/rule/legacy-key-value-format/",
"sourceInfo": {
"filename": "services.dockerfile",
"data": "RlJPTSBub2RlOjIyLjEzLjAtc2xpbQoKUlVOIGFwdC1nZXQgdXBkYXRlICYmIGFwdC1nZXQgaW5zdGFsbCAteSB3Z2V0IGNhLWNlcnRpZmljYXRlcyAmJiBybSAtcmYgL3Zhci9saWIvYXB0L2xpc3RzLyoKCkFSRyBTRVJWSUNFX0RJUl9OQU1FCldPUktESVIgL3Vzci9zcmMvYXBwLyRTRVJWSUNFX0RJUl9OQU1FCgpDT1BZIC0tZnJvbT1kaXN0IC4gL3Vzci9zcmMvYXBwLyRTRVJWSUNFX0RJUl9OQU1FLwpDT1BZIC0tZnJvbT1zaGFyZWQgLiAvCgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UubGljZW5zZXM9TUlUCkxBQkVMIG9yZy5vcGVuY29udGFpbmVycy5pbWFnZS50aXRsZT0kSU1BR0VfVElUTEUKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLnZlcnNpb249JFJFTEVBU0UKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLmRlc2NyaXB0aW9uPSRJTUFHRV9ERVNDUklQVElPTgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UuYXV0aG9ycz0iVGhlIEd1aWxkIgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UudmVuZG9yPSJLYW1pbCBLaXNpZWxhIgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UudXJsPSJodHRwczovL2dpdGh1Yi5jb20vZ3JhcGhxbC1oaXZlL3BsYXRmb3JtIgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2Uuc291cmNlPSJodHRwczovL2dpdGh1Yi5jb20vZ3JhcGhxbC1oaXZlL3BsYXRmb3JtIgoKRU5WIEVOVklST05NRU5UIHByb2R1Y3Rpb24KRU5WIFJFTEVBU0UgJFJFTEVBU0UKRU5WIFBPUlQgJFBPUlQKCkhFQUxUSENIRUNLIC0taW50ZXJ2YWw9NXMgXAogIC0tdGltZW91dD01cyBcCiAgLS1zdGFydC1wZXJpb2Q9NXMgXAogIC0tcmV0cmllcz02IFwKICBDTUQgJEhFQUxUSENIRUNLX0NNRAoKRU5UUllQT0lOVCBbICIvZW50cnlwb2ludC5zaCIgXQo=",
"language": "Dockerfile"
},
"range": [
{
"start": {
"line": 21
},
"end": {
"line": 21
}
}
]
},
{
"vertex": "sha256:94f61d6ac2d67e23827b0f629f7955fa2d16bcccf076f3044bf746b76e24fed1",
"level": 1,
"short": "TGVnYWN5S2V5VmFsdWVGb3JtYXQ6ICJFTlYga2V5PXZhbHVlIiBzaG91bGQgYmUgdXNlZCBpbnN0ZWFkIG9mIGxlZ2FjeSAiRU5WIGtleSB2YWx1ZSIgZm9ybWF0IChsaW5lIDIyKQ==",
"detail": [
"TGVnYWN5IGtleS92YWx1ZSBmb3JtYXQgd2l0aCB3aGl0ZXNwYWNlIHNlcGFyYXRvciBzaG91bGQgbm90IGJlIHVzZWQ="
],
"url": "https://docs.docker.com/go/dockerfile/rule/legacy-key-value-format/",
"sourceInfo": {
"filename": "services.dockerfile",
"data": "RlJPTSBub2RlOjIyLjEzLjAtc2xpbQoKUlVOIGFwdC1nZXQgdXBkYXRlICYmIGFwdC1nZXQgaW5zdGFsbCAteSB3Z2V0IGNhLWNlcnRpZmljYXRlcyAmJiBybSAtcmYgL3Zhci9saWIvYXB0L2xpc3RzLyoKCkFSRyBTRVJWSUNFX0RJUl9OQU1FCldPUktESVIgL3Vzci9zcmMvYXBwLyRTRVJWSUNFX0RJUl9OQU1FCgpDT1BZIC0tZnJvbT1kaXN0IC4gL3Vzci9zcmMvYXBwLyRTRVJWSUNFX0RJUl9OQU1FLwpDT1BZIC0tZnJvbT1zaGFyZWQgLiAvCgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UubGljZW5zZXM9TUlUCkxBQkVMIG9yZy5vcGVuY29udGFpbmVycy5pbWFnZS50aXRsZT0kSU1BR0VfVElUTEUKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLnZlcnNpb249JFJFTEVBU0UKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLmRlc2NyaXB0aW9uPSRJTUFHRV9ERVNDUklQVElPTgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UuYXV0aG9ycz0iVGhlIEd1aWxkIgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UudmVuZG9yPSJLYW1pbCBLaXNpZWxhIgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UudXJsPSJodHRwczovL2dpdGh1Yi5jb20vZ3JhcGhxbC1oaXZlL3BsYXRmb3JtIgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2Uuc291cmNlPSJodHRwczovL2dpdGh1Yi5jb20vZ3JhcGhxbC1oaXZlL3BsYXRmb3JtIgoKRU5WIEVOVklST05NRU5UIHByb2R1Y3Rpb24KRU5WIFJFTEVBU0UgJFJFTEVBU0UKRU5WIFBPUlQgJFBPUlQKCkhFQUxUSENIRUNLIC0taW50ZXJ2YWw9NXMgXAogIC0tdGltZW91dD01cyBcCiAgLS1zdGFydC1wZXJpb2Q9NXMgXAogIC0tcmV0cmllcz02IFwKICBDTUQgJEhFQUxUSENIRUNLX0NNRAoKRU5UUllQT0lOVCBbICIvZW50cnlwb2ludC5zaCIgXQo=",
"language": "Dockerfile"
},
"range": [
{
"start": {
"line": 22
},
"end": {
"line": 22
}
}
]
},
{
"vertex": "sha256:f566d20768d5de07570a6c8a6f8ff75579add219b415f5f6622ba0876b86001f",
"level": 1,
"short": "VW5kZWZpbmVkVmFyOiBVc2FnZSBvZiB1bmRlZmluZWQgdmFyaWFibGUgJyRSRUxFQVNFJyAobGluZSAxMik=",
"detail": [
"VmFyaWFibGVzIHNob3VsZCBiZSBkZWZpbmVkIGJlZm9yZSB0aGVpciB1c2U="
],
"url": "https://docs.docker.com/go/dockerfile/rule/undefined-var/",
"sourceInfo": {
"filename": "migrations.dockerfile",
"data": "RlJPTSBub2RlOjIyLjEzLjAtc2xpbQoKUlVOIGFwdC1nZXQgdXBkYXRlICYmIGFwdC1nZXQgaW5zdGFsbCAteSBjYS1jZXJ0aWZpY2F0ZXMKCldPUktESVIgL3Vzci9zcmMvYXBwCgpDT1BZIC0tZnJvbT1kaXN0IC4gL3Vzci9zcmMvYXBwLwpDT1BZIC0tZnJvbT1zaGFyZWQgLiAvCgpFTlYgRU5WSVJPTk1FTlQgcHJvZHVjdGlvbgpFTlYgTk9ERV9FTlYgcHJvZHVjdGlvbgpFTlYgUkVMRUFTRSAkUkVMRUFTRQoKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLmxpY2Vuc2VzPU1JVApMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UudGl0bGU9JElNQUdFX1RJVExFCkxBQkVMIG9yZy5vcGVuY29udGFpbmVycy5pbWFnZS52ZXJzaW9uPSRSRUxFQVNFCkxBQkVMIG9yZy5vcGVuY29udGFpbmVycy5pbWFnZS5kZXNjcmlwdGlvbj0kSU1BR0VfREVTQ1JJUFRJT04KTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLmF1dGhvcnM9IlRoZSBHdWlsZCIKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLnZlbmRvcj0iS2FtaWwgS2lzaWVsYSIKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLnVybD0iaHR0cHM6Ly9naXRodWIuY29tL2dyYXBocWwtaGl2ZS9wbGF0Zm9ybSIKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLnNvdXJjZT0iaHR0cHM6Ly9naXRodWIuY29tL2dyYXBocWwtaGl2ZS9wbGF0Zm9ybSIKCkVOVFJZUE9JTlQgWyAiL2VudHJ5cG9pbnQuc2giIF0K",
"language": "Dockerfile"
},
"range": [
{
"start": {
"line": 12
},
"end": {
"line": 12
}
}
]
},
{
"vertex": "sha256:f566d20768d5de07570a6c8a6f8ff75579add219b415f5f6622ba0876b86001f",
"level": 1,
"short": "VW5kZWZpbmVkVmFyOiBVc2FnZSBvZiB1bmRlZmluZWQgdmFyaWFibGUgJyRJTUFHRV9USVRMRScgKGxpbmUgMTUp",
"detail": [
"VmFyaWFibGVzIHNob3VsZCBiZSBkZWZpbmVkIGJlZm9yZSB0aGVpciB1c2U="
],
"url": "https://docs.docker.com/go/dockerfile/rule/undefined-var/",
"sourceInfo": {
"filename": "migrations.dockerfile",
"data": "RlJPTSBub2RlOjIyLjEzLjAtc2xpbQoKUlVOIGFwdC1nZXQgdXBkYXRlICYmIGFwdC1nZXQgaW5zdGFsbCAteSBjYS1jZXJ0aWZpY2F0ZXMKCldPUktESVIgL3Vzci9zcmMvYXBwCgpDT1BZIC0tZnJvbT1kaXN0IC4gL3Vzci9zcmMvYXBwLwpDT1BZIC0tZnJvbT1zaGFyZWQgLiAvCgpFTlYgRU5WSVJPTk1FTlQgcHJvZHVjdGlvbgpFTlYgTk9ERV9FTlYgcHJvZHVjdGlvbgpFTlYgUkVMRUFTRSAkUkVMRUFTRQoKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLmxpY2Vuc2VzPU1JVApMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UudGl0bGU9JElNQUdFX1RJVExFCkxBQkVMIG9yZy5vcGVuY29udGFpbmVycy5pbWFnZS52ZXJzaW9uPSRSRUxFQVNFCkxBQkVMIG9yZy5vcGVuY29udGFpbmVycy5pbWFnZS5kZXNjcmlwdGlvbj0kSU1BR0VfREVTQ1JJUFRJT04KTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLmF1dGhvcnM9IlRoZSBHdWlsZCIKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLnZlbmRvcj0iS2FtaWwgS2lzaWVsYSIKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLnVybD0iaHR0cHM6Ly9naXRodWIuY29tL2dyYXBocWwtaGl2ZS9wbGF0Zm9ybSIKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLnNvdXJjZT0iaHR0cHM6Ly9naXRodWIuY29tL2dyYXBocWwtaGl2ZS9wbGF0Zm9ybSIKCkVOVFJZUE9JTlQgWyAiL2VudHJ5cG9pbnQuc2giIF0K",
"language": "Dockerfile"
},
"range": [
{
"start": {
"line": 15
},
"end": {
"line": 15
}
}
]
},
{
"vertex": "sha256:f566d20768d5de07570a6c8a6f8ff75579add219b415f5f6622ba0876b86001f",
"level": 1,
"short": "VW5kZWZpbmVkVmFyOiBVc2FnZSBvZiB1bmRlZmluZWQgdmFyaWFibGUgJyRJTUFHRV9ERVNDUklQVElPTicgKGxpbmUgMTcp",
"detail": [
"VmFyaWFibGVzIHNob3VsZCBiZSBkZWZpbmVkIGJlZm9yZSB0aGVpciB1c2U="
],
"url": "https://docs.docker.com/go/dockerfile/rule/undefined-var/",
"sourceInfo": {
"filename": "migrations.dockerfile",
"data": "RlJPTSBub2RlOjIyLjEzLjAtc2xpbQoKUlVOIGFwdC1nZXQgdXBkYXRlICYmIGFwdC1nZXQgaW5zdGFsbCAteSBjYS1jZXJ0aWZpY2F0ZXMKCldPUktESVIgL3Vzci9zcmMvYXBwCgpDT1BZIC0tZnJvbT1kaXN0IC4gL3Vzci9zcmMvYXBwLwpDT1BZIC0tZnJvbT1zaGFyZWQgLiAvCgpFTlYgRU5WSVJPTk1FTlQgcHJvZHVjdGlvbgpFTlYgTk9ERV9FTlYgcHJvZHVjdGlvbgpFTlYgUkVMRUFTRSAkUkVMRUFTRQoKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLmxpY2Vuc2VzPU1JVApMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UudGl0bGU9JElNQUdFX1RJVExFCkxBQkVMIG9yZy5vcGVuY29udGFpbmVycy5pbWFnZS52ZXJzaW9uPSRSRUxFQVNFCkxBQkVMIG9yZy5vcGVuY29udGFpbmVycy5pbWFnZS5kZXNjcmlwdGlvbj0kSU1BR0VfREVTQ1JJUFRJT04KTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLmF1dGhvcnM9IlRoZSBHdWlsZCIKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLnZlbmRvcj0iS2FtaWwgS2lzaWVsYSIKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLnVybD0iaHR0cHM6Ly9naXRodWIuY29tL2dyYXBocWwtaGl2ZS9wbGF0Zm9ybSIKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLnNvdXJjZT0iaHR0cHM6Ly9naXRodWIuY29tL2dyYXBocWwtaGl2ZS9wbGF0Zm9ybSIKCkVOVFJZUE9JTlQgWyAiL2VudHJ5cG9pbnQuc2giIF0K",
"language": "Dockerfile"
},
"range": [
{
"start": {
"line": 17
},
"end": {
"line": 17
}
}
]
}
],
"composition-federation-2": {
"buildx.build.provenance": {
"buildType": "https://mobyproject.org/buildkit@v1",
"materials": [
{
"uri": "pkg:docker/[email protected]?platform=linux%2Farm64",
"digest": {
"sha256": "f5a0871ab03b035c58bdb3007c3d177b001c2145c18e81817b71624dcf7d8bff"
}
}
],
"invocation": {
"configSource": {
"entryPoint": "services.dockerfile"
},
"parameters": {
"frontend": "dockerfile.v0",
"args": {
"build-arg:HEALTHCHECK_CMD": "wget --spider -q http://127.0.0.1:${PORT}/_readiness",
"build-arg:IMAGE_DESCRIPTION": "Federation 2 Composition Service for GraphQL Hive.",
"build-arg:IMAGE_TITLE": "graphql-hive/composition-federation-2",
"build-arg:PORT": "3069",
"build-arg:RELEASE": "6c5c165e29e8253a09fc7b1691a32cd5e8d7c441",
"build-arg:SERVICE_DIR_NAME": "@hive/external-composition",
"context:dist": "local:dist",
"context:shared": "local:shared",
"frontend.caps": "moby.buildkit.frontend.contexts+forward",
"local-sessionid:context": "ob3vzrhz5faabymfqxsubkhg3",
"local-sessionid:dockerfile": "ob3vzrhz5faabymfqxsubkhg3",
"local-sessionid:shared": "ob3vzrhz5faabymfqxsubkhg3"
},
"locals": [
{
"name": "context"
},
{
"name": "dist"
},
{
"name": "dockerfile"
},
{
"name": "shared"
}
]
},
"environment": {
"platform": "linux/arm64"
}
}
},
"buildx.build.ref": "builder-ed970045-9563-45fe-826e-916713cd23dd/builder-ed970045-9563-45fe-826e-916713cd23dd0/j4v2cld0zj2hu70a8dag0t2p6",
"containerimage.config.digest": "sha256:a9bff32df327def290a7fd471056e9cc79d5a6f3ac3ddf036393b3c71b5c26b8",
"containerimage.descriptor": {
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"digest": "sha256:03c5aecb6b0ff55f7a1112c8fc15e946db896229961e68c763d4131aff74fa7c",
"size": 2075,
"platform": {
"architecture": "arm64",
"os": "linux"
}
},
"containerimage.digest": "sha256:03c5aecb6b0ff55f7a1112c8fc15e946db896229961e68c763d4131aff74fa7c",
"image.name": "ghcr.io/graphql-hive/composition-federation-2:6c5c165e29e8253a09fc7b1691a32cd5e8d7c441-arm64,ghcr.io/graphql-hive/composition-federation-2:hive_metadata-arm64"
},
"emails": {
"buildx.build.provenance": {
"buildType": "https://mobyproject.org/buildkit@v1",
"materials": [
{
"uri": "pkg:docker/[email protected]?platform=linux%2Farm64",
"digest": {
"sha256": "f5a0871ab03b035c58bdb3007c3d177b001c2145c18e81817b71624dcf7d8bff"
}
}
],
"invocation": {
"configSource": {
"entryPoint": "services.dockerfile"
},
"parameters": {
"frontend": "dockerfile.v0",
"args": {
"build-arg:HEALTHCHECK_CMD": "wget --spider -q http://127.0.0.1:${PORT}/_readiness",
"build-arg:IMAGE_DESCRIPTION": "The emails service of the GraphQL Hive project.",
"build-arg:IMAGE_TITLE": "graphql-hive/emails",
"build-arg:PORT": "3006",
"build-arg:RELEASE": "6c5c165e29e8253a09fc7b1691a32cd5e8d7c441",
"build-arg:SERVICE_DIR_NAME": "@hive/emails",
"context:dist": "local:dist",
"context:shared": "local:shared",
"frontend.caps": "moby.buildkit.frontend.contexts+forward",
"local-sessionid:context": "ob3vzrhz5faabymfqxsubkhg3",
"local-sessionid:dockerfile": "ob3vzrhz5faabymfqxsubkhg3",
"local-sessionid:shared": "ob3vzrhz5faabymfqxsubkhg3"
},
"locals": [
{
"name": "context"
},
{
"name": "dist"
},
{
"name": "dockerfile"
},
{
"name": "shared"
}
]
},
"environment": {
"platform": "linux/arm64"
}
}
},
"buildx.build.ref": "builder-ed970045-9563-45fe-826e-916713cd23dd/builder-ed970045-9563-45fe-826e-916713cd23dd0/xlj4d9nyb7l7ss6jgnsz9hame",
"containerimage.config.digest": "sha256:b81112d19213fe7030584f65e99e0b4e3eccf94d1e9a7a2cb12405c8798fd128",
"containerimage.descriptor": {
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"digest": "sha256:3fcacfaa02aaebd318d2f16b24106c81194f53862185cff20a9c0a521f4e51ab",
"size": 2075,
"platform": {
"architecture": "arm64",
"os": "linux"
}
},
"containerimage.digest": "sha256:3fcacfaa02aaebd318d2f16b24106c81194f53862185cff20a9c0a521f4e51ab",
"image.name": "ghcr.io/graphql-hive/emails:6c5c165e29e8253a09fc7b1691a32cd5e8d7c441-arm64,ghcr.io/graphql-hive/emails:hive_metadata-arm64"
},
"policy": {
"buildx.build.provenance": {
"buildType": "https://mobyproject.org/buildkit@v1",
"materials": [
{
"uri": "pkg:docker/[email protected]?platform=linux%2Farm64",
"digest": {
"sha256": "f5a0871ab03b035c58bdb3007c3d177b001c2145c18e81817b71624dcf7d8bff"
}
}
],
"invocation": {
"configSource": {
"entryPoint": "services.dockerfile"
},
"parameters": {
"frontend": "dockerfile.v0",
"args": {
"build-arg:HEALTHCHECK_CMD": "wget --spider -q http://127.0.0.1:${PORT}/_readiness",
"build-arg:IMAGE_DESCRIPTION": "The policy service of the GraphQL Hive project.",
"build-arg:IMAGE_TITLE": "graphql-hive/policy",
"build-arg:PORT": "3012",
"build-arg:RELEASE": "6c5c165e29e8253a09fc7b1691a32cd5e8d7c441",
"build-arg:SERVICE_DIR_NAME": "@hive/policy",
"context:dist": "local:dist",
"context:shared": "local:shared",
"frontend.caps": "moby.buildkit.frontend.contexts+forward",
"local-sessionid:context": "ob3vzrhz5faabymfqxsubkhg3",
"local-sessionid:dockerfile": "ob3vzrhz5faabymfqxsubkhg3",
"local-sessionid:shared": "ob3vzrhz5faabymfqxsubkhg3"
},
"locals": [
{
"name": "context"
},
{
"name": "dist"
},
{
"name": "dockerfile"
},
{
"name": "shared"
}
]
},
"environment": {
"platform": "linux/arm64"
}
}
},
"buildx.build.ref": "builder-ed970045-9563-45fe-826e-916713cd23dd/builder-ed970045-9563-45fe-826e-916713cd23dd0/frps5jjy0o686owoahevddj2e",
"containerimage.config.digest": "sha256:d618cd61d988dbbc4458a5118d830d97eea63410c1d9e4e138aebf5339827ad7",
"containerimage.descriptor": {
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"digest": "sha256:22a98746f3b4bcf886436c8964612626e5544cbe481721dc5394bf15360106ad",
"size": 2075,
"platform": {
"architecture": "arm64",
"os": "linux"
}
},
"containerimage.digest": "sha256:22a98746f3b4bcf886436c8964612626e5544cbe481721dc5394bf15360106ad",
"image.name": "ghcr.io/graphql-hive/policy:6c5c165e29e8253a09fc7b1691a32cd5e8d7c441-arm64,ghcr.io/graphql-hive/policy:hive_metadata-arm64"
},
"rate-limit": {
"buildx.build.provenance": {
"buildType": "https://mobyproject.org/buildkit@v1",
"materials": [
{
"uri": "pkg:docker/[email protected]?platform=linux%2Farm64",
"digest": {
"sha256": "f5a0871ab03b035c58bdb3007c3d177b001c2145c18e81817b71624dcf7d8bff"
}
}
],
"invocation": {
"configSource": {
"entryPoint": "services.dockerfile"
},
"parameters": {
"frontend": "dockerfile.v0",
"args": {
"build-arg:HEALTHCHECK_CMD": "wget --spider -q http://127.0.0.1:${PORT}/_readiness",
"build-arg:IMAGE_DESCRIPTION": "The rate limit service of the GraphQL Hive project.",
"build-arg:IMAGE_TITLE": "graphql-hive/rate-limit",
"build-arg:PORT": "3009",
"build-arg:RELEASE": "6c5c165e29e8253a09fc7b1691a32cd5e8d7c441",
"build-arg:SERVICE_DIR_NAME": "@hive/rate-limit",
"context:dist": "local:dist",
"context:shared": "local:shared",
"frontend.caps": "moby.buildkit.frontend.contexts+forward",
"local-sessionid:context": "ob3vzrhz5faabymfqxsubkhg3",
"local-sessionid:dockerfile": "ob3vzrhz5faabymfqxsubkhg3",
"local-sessionid:shared": "ob3vzrhz5faabymfqxsubkhg3"
},
"locals": [
{
"name": "context"
},
{
"name": "dist"
},
{
"name": "dockerfile"
},
{
"name": "shared"
}
]
},
"environment": {
"platform": "linux/arm64"
}
}
},
"buildx.build.ref": "builder-ed970045-9563-45fe-826e-916713cd23dd/builder-ed970045-9563-45fe-826e-916713cd23dd0/xio2nr3lh21vcdvp5dbbykul9",
"containerimage.config.digest": "sha256:dc0762016436ca5e796427ffd823d320c239f956857e8d9ed8a67e97585b889e",
"containerimage.descriptor": {
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"digest": "sha256:ffdd0c80ecf389e36dcc82f29dcf34f16c1edeb1fa0e52adf295244701471ea5",
"size": 2075,
"platform": {
"architecture": "arm64",
"os": "linux"
}
},
"containerimage.digest": "sha256:ffdd0c80ecf389e36dcc82f29dcf34f16c1edeb1fa0e52adf295244701471ea5",
"image.name": "ghcr.io/graphql-hive/rate-limit:6c5c165e29e8253a09fc7b1691a32cd5e8d7c441-arm64,ghcr.io/graphql-hive/rate-limit:hive_metadata-arm64"
},
"schema": {
"buildx.build.provenance": {
"buildType": "https://mobyproject.org/buildkit@v1",
"materials": [
{
"uri": "pkg:docker/[email protected]?platform=linux%2Farm64",
"digest": {
"sha256": "f5a0871ab03b035c58bdb3007c3d177b001c2145c18e81817b71624dcf7d8bff"
}
}
],
"invocation": {
"configSource": {
"entryPoint": "services.dockerfile"
},
"parameters": {
"frontend": "dockerfile.v0",
"args": {
"build-arg:HEALTHCHECK_CMD": "wget --spider -q http://127.0.0.1:${PORT}/_readiness",
"build-arg:IMAGE_DESCRIPTION": "The schema service of the GraphQL Hive project.",
"build-arg:IMAGE_TITLE": "graphql-hive/schema",
"build-arg:PORT": "3002",
"build-arg:RELEASE": "6c5c165e29e8253a09fc7b1691a32cd5e8d7c441",
"build-arg:SERVICE_DIR_NAME": "@hive/schema",
"context:dist": "local:dist",
"context:shared": "local:shared",
"frontend.caps": "moby.buildkit.frontend.contexts+forward",
"local-sessionid:context": "ob3vzrhz5faabymfqxsubkhg3",
"local-sessionid:dockerfile": "ob3vzrhz5faabymfqxsubkhg3",
"local-sessionid:shared": "ob3vzrhz5faabymfqxsubkhg3"
},
"locals": [
{
"name": "context"
},
{
"name": "dist"
},
{
"name": "dockerfile"
},
{
"name": "shared"
}
]
},
"environment": {
"platform": "linux/arm64"
}
}
},
"buildx.build.ref": "builder-ed970045-9563-45fe-826e-916713cd23dd/builder-ed970045-9563-45fe-826e-916713cd23dd0/ilssxw3a9xl28twc6permsas4",
"containerimage.config.digest": "sha256:901fce9fd847c86e9a88876f41e4d4e88077ffdde7055d99578e3d085ce85808",
"containerimage.descriptor": {
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"digest": "sha256:2e35e45c0557fcba3d979c814aac1340300df2f995639dbae5136fa6911f9dee",
"size": 2075,
"platform": {
"architecture": "arm64",
"os": "linux"
}
},
"containerimage.digest": "sha256:2e35e45c0557fcba3d979c814aac1340300df2f995639dbae5136fa6911f9dee",
"image.name": "ghcr.io/graphql-hive/schema:6c5c165e29e8253a09fc7b1691a32cd5e8d7c441-arm64,ghcr.io/graphql-hive/schema:hive_metadata-arm64"
},
"server": {
"buildx.build.provenance": {
"buildType": "https://mobyproject.org/buildkit@v1",
"materials": [
{
"uri": "pkg:docker/[email protected]?platform=linux%2Farm64",
"digest": {
"sha256": "f5a0871ab03b035c58bdb3007c3d177b001c2145c18e81817b71624dcf7d8bff"
}
}
],
"invocation": {
"configSource": {
"entryPoint": "services.dockerfile"
},
"parameters": {
"frontend": "dockerfile.v0",
"args": {
"build-arg:HEALTHCHECK_CMD": "wget --spider -q http://127.0.0.1:${PORT}/_readiness",
"build-arg:IMAGE_DESCRIPTION": "The server service of the GraphQL Hive project.",
"build-arg:IMAGE_TITLE": "graphql-hive/server",
"build-arg:PORT": "3001",
"build-arg:RELEASE": "6c5c165e29e8253a09fc7b1691a32cd5e8d7c441",
"build-arg:SERVICE_DIR_NAME": "@hive/server",
"context:dist": "local:dist",
"context:shared": "local:shared",
"frontend.caps": "moby.buildkit.frontend.contexts+forward",
"local-sessionid:context": "ob3vzrhz5faabymfqxsubkhg3",
"local-sessionid:dockerfile": "ob3vzrhz5faabymfqxsubkhg3",
"local-sessionid:shared": "ob3vzrhz5faabymfqxsubkhg3"
},
"locals": [
{
"name": "context"
},
{
"name": "dist"
},
{
"name": "dockerfile"
},
{
"name": "shared"
}
]
},
"environment": {
"platform": "linux/arm64"
}
}
},
"buildx.build.ref": "builder-ed970045-9563-45fe-826e-916713cd23dd/builder-ed970045-9563-45fe-826e-916713cd23dd0/qwivq5trdecvj0o8jguuaawng",
"containerimage.config.digest": "sha256:765f46069cf683b7674b3490568b98480f0589db569b7f4fd9ceef04477ff8de",
"containerimage.descriptor": {
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"digest": "sha256:f02ec649afe15d0a9b203ded6ee5ad00cfad80e7e393c3b14bab7d9e0a189b34",
"size": 2076,
"platform": {
"architecture": "arm64",
"os": "linux"
}
},
"containerimage.digest": "sha256:f02ec649afe15d0a9b203ded6ee5ad00cfad80e7e393c3b14bab7d9e0a189b34",
"image.name": "ghcr.io/graphql-hive/server:6c5c165e29e8253a09fc7b1691a32cd5e8d7c441-arm64,ghcr.io/graphql-hive/server:hive_metadata-arm64"
},
"storage": {
"buildx.build.provenance": {
"buildType": "https://mobyproject.org/buildkit@v1",
"materials": [
{
"uri": "pkg:docker/[email protected]?platform=linux%2Farm64",
"digest": {
"sha256": "f5a0871ab03b035c58bdb3007c3d177b001c2145c18e81817b71624dcf7d8bff"
}
}
],
"invocation": {
"configSource": {
"entryPoint": "migrations.dockerfile"
},
"parameters": {
"frontend": "dockerfile.v0",
"args": {
"build-arg:IMAGE_DESCRIPTION": "The migrations service of the GraphQL Hive project.",
"build-arg:IMAGE_TITLE": "graphql-hive/storage",
"build-arg:RELEASE": "6c5c165e29e8253a09fc7b1691a32cd5e8d7c441",
"context:dist": "local:dist",
"context:shared": "local:shared",
"frontend.caps": "moby.buildkit.frontend.contexts+forward",
"local-sessionid:context": "ob3vzrhz5faabymfqxsubkhg3",
"local-sessionid:dockerfile": "ob3vzrhz5faabymfqxsubkhg3",
"local-sessionid:shared": "ob3vzrhz5faabymfqxsubkhg3"
},
"locals": [
{
"name": "context"
},
{
"name": "dist"
},
{
"name": "dockerfile"
},
{
"name": "shared"
}
]
},
"environment": {
"platform": "linux/arm64"
}
}
},
"buildx.build.ref": "builder-ed970045-9563-45fe-826e-916713cd23dd/builder-ed970045-9563-45fe-826e-916713cd23dd0/pn4g906tix9ipp1892dt41nb5",
"containerimage.config.digest": "sha256:13d4e9df2de2b109726e94960d24c832cf9ecb0cbc24cdc2b111921a9482ff11",
"containerimage.descriptor": {
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"digest": "sha256:98f97ab335d850ff325cfb2149ed716868178fb1c4934d4caa29156bec515550",
"size": 2075,
"platform": {
"architecture": "arm64",
"os": "linux"
}
},
"containerimage.digest": "sha256:98f97ab335d850ff325cfb2149ed716868178fb1c4934d4caa29156bec515550",
"image.name": "ghcr.io/graphql-hive/storage:6c5c165e29e8253a09fc7b1691a32cd5e8d7c441-arm64,ghcr.io/graphql-hive/storage:hive_metadata-arm64"
},
"stripe-billing": {
"buildx.build.provenance": {
"buildType": "https://mobyproject.org/buildkit@v1",
"materials": [
{
"uri": "pkg:docker/[email protected]?platform=linux%2Farm64",
"digest": {
"sha256": "f5a0871ab03b035c58bdb3007c3d177b001c2145c18e81817b71624dcf7d8bff"
}
}
],
"invocation": {
"configSource": {
"entryPoint": "services.dockerfile"
},
"parameters": {
"frontend": "dockerfile.v0",
"args": {
"build-arg:HEALTHCHECK_CMD": "wget --spider -q http://127.0.0.1:${PORT}/_readiness",
"build-arg:IMAGE_DESCRIPTION": "The stripe billing service of the GraphQL Hive project.",
"build-arg:IMAGE_TITLE": "graphql-hive/stripe-billing",
"build-arg:PORT": "3010",
"build-arg:RELEASE": "6c5c165e29e8253a09fc7b1691a32cd5e8d7c441",
"build-arg:SERVICE_DIR_NAME": "@hive/stripe-billing",
"context:dist": "local:dist",
"context:shared": "local:shared",
"frontend.caps": "moby.buildkit.frontend.contexts+forward",
"local-sessionid:context": "ob3vzrhz5faabymfqxsubkhg3",
"local-sessionid:dockerfile": "ob3vzrhz5faabymfqxsubkhg3",
"local-sessionid:shared": "ob3vzrhz5faabymfqxsubkhg3"
},
"locals": [
{
"name": "context"
},
{
"name": "dist"
},
{
"name": "dockerfile"
},
{
"name": "shared"
}
]
},
"environment": {
"platform": "linux/arm64"
}
}
},
"buildx.build.ref": "builder-ed970045-9563-45fe-826e-916713cd23dd/builder-ed970045-9563-45fe-826e-916713cd23dd0/whh2t1dcamjcpplja9uo3o0r6",
"containerimage.config.digest": "sha256:00041269b7b87e9410137d476cde2083204046310d943f0e5068326d90a52d27",
"containerimage.descriptor": {
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"digest": "sha256:ac44455dfaad5cab11316a7a23c22b3c0fe8d46fe790acb44f096b478a62fafb",
"size": 2075,
"platform": {
"architecture": "arm64",
"os": "linux"
}
},
"containerimage.digest": "sha256:ac44455dfaad5cab11316a7a23c22b3c0fe8d46fe790acb44f096b478a62fafb",
"image.name": "ghcr.io/graphql-hive/stripe-billing:6c5c165e29e8253a09fc7b1691a32cd5e8d7c441-arm64,ghcr.io/graphql-hive/stripe-billing:hive_metadata-arm64"
},
"tokens": {
"buildx.build.provenance": {
"buildType": "https://mobyproject.org/buildkit@v1",
"materials": [
{
"uri": "pkg:docker/[email protected]?platform=linux%2Farm64",
"digest": {
"sha256": "f5a0871ab03b035c58bdb3007c3d177b001c2145c18e81817b71624dcf7d8bff"
}
}
],
"invocation": {
"configSource": {
"entryPoint": "services.dockerfile"
},
"parameters": {
"frontend": "dockerfile.v0",
"args": {
"build-arg:HEALTHCHECK_CMD": "wget --spider -q http://127.0.0.1:${PORT}/_readiness",
"build-arg:IMAGE_DESCRIPTION": "The tokens service of the GraphQL Hive project.",
"build-arg:IMAGE_TITLE": "graphql-hive/tokens",
"build-arg:PORT": "3003",
"build-arg:RELEASE": "6c5c165e29e8253a09fc7b1691a32cd5e8d7c441",
"build-arg:SERVICE_DIR_NAME": "@hive/tokens",
"context:dist": "local:dist",
"context:shared": "local:shared",
"frontend.caps": "moby.buildkit.frontend.contexts+forward",
"local-sessionid:context": "ob3vzrhz5faabymfqxsubkhg3",
"local-sessionid:dockerfile": "ob3vzrhz5faabymfqxsubkhg3",
"local-sessionid:shared": "ob3vzrhz5faabymfqxsubkhg3"
},
"locals": [
{
"name": "context"
},
{
"name": "dist"
},
{
"name": "dockerfile"
},
{
"name": "shared"
}
]
},
"environment": {
"platform": "linux/arm64"
}
}
},
"buildx.build.ref": "builder-ed970045-9563-45fe-826e-916713cd23dd/builder-ed970045-9563-45fe-826e-916713cd23dd0/3zbla3ufq1bfgpor8jvuwexsf",
"containerimage.config.digest": "sha256:66a2a60b93c5df6cb862a05e7fe4d01b4d28d8ab978307d6ca7f38c40ad427ed",
"containerimage.descriptor": {
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"digest": "sha256:2ac579a819ad7539d36792aa50b135931dbf4a888fb7b3c87aaf1e8cd6b700ac",
"size": 2075,
"platform": {
"architecture": "arm64",
"os": "linux"
}
},
"containerimage.digest": "sha256:2ac579a819ad7539d36792aa50b135931dbf4a888fb7b3c87aaf1e8cd6b700ac",
"image.name": "ghcr.io/graphql-hive/tokens:6c5c165e29e8253a09fc7b1691a32cd5e8d7c441-arm64,ghcr.io/graphql-hive/tokens:hive_metadata-arm64"
},
"usage": {
"buildx.build.provenance": {
"buildType": "https://mobyproject.org/buildkit@v1",
"materials": [
{
"uri": "pkg:docker/[email protected]?platform=linux%2Farm64",
"digest": {
"sha256": "f5a0871ab03b035c58bdb3007c3d177b001c2145c18e81817b71624dcf7d8bff"
}
}
],
"invocation": {
"configSource": {
"entryPoint": "services.dockerfile"
},
"parameters": {
"frontend": "dockerfile.v0",
"args": {
"build-arg:HEALTHCHECK_CMD": "wget --spider -q http://127.0.0.1:${PORT}/_readiness",
"build-arg:IMAGE_DESCRIPTION": "The usage ingestor service of the GraphQL Hive project.",
"build-arg:IMAGE_TITLE": "graphql-hive/usage",
"build-arg:PORT": "3006",
"build-arg:RELEASE": "6c5c165e29e8253a09fc7b1691a32cd5e8d7c441",
"build-arg:SERVICE_DIR_NAME": "@hive/usage",
"context:dist": "local:dist",
"context:shared": "local:shared",
"frontend.caps": "moby.buildkit.frontend.contexts+forward",
"local-sessionid:context": "ob3vzrhz5faabymfqxsubkhg3",
"local-sessionid:dockerfile": "ob3vzrhz5faabymfqxsubkhg3",
"local-sessionid:shared": "ob3vzrhz5faabymfqxsubkhg3"
},
"locals": [
{
"name": "context"
},
{
"name": "dist"
},
{
"name": "dockerfile"
},
{
"name": "shared"
}
]
},
"environment": {
"platform": "linux/arm64"
}
}
},
"buildx.build.ref": "builder-ed970045-9563-45fe-826e-916713cd23dd/builder-ed970045-9563-45fe-826e-916713cd23dd0/ehtjdodtvlpb0blsdr12pk09t",
"containerimage.config.digest": "sha256:689f092860f58f859b3a5858bd2a980d51e56d0309064b6e9099ef94884ac768",
"containerimage.descriptor": {
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"digest": "sha256:28494a16c4bb30dced3baeed789500350f0e223be3f0ee536a1c202cb32e34a2",
"size": 2075,
"platform": {
"architecture": "arm64",
"os": "linux"
}
},
"containerimage.digest": "sha256:28494a16c4bb30dced3baeed789500350f0e223be3f0ee536a1c202cb32e34a2",
"image.name": "ghcr.io/graphql-hive/usage:6c5c165e29e8253a09fc7b1691a32cd5e8d7c441-arm64,ghcr.io/graphql-hive/usage:hive_metadata-arm64"
},
"usage-estimator": {
"buildx.build.provenance": {
"buildType": "https://mobyproject.org/buildkit@v1",
"materials": [
{
"uri": "pkg:docker/[email protected]?platform=linux%2Farm64",
"digest": {
"sha256": "f5a0871ab03b035c58bdb3007c3d177b001c2145c18e81817b71624dcf7d8bff"
}
}
],
"invocation": {
"configSource": {
"entryPoint": "services.dockerfile"
},
"parameters": {
"frontend": "dockerfile.v0",
"args": {
"build-arg:HEALTHCHECK_CMD": "wget --spider -q http://127.0.0.1:${PORT}/_readiness",
"build-arg:IMAGE_DESCRIPTION": "The usage estimator service of the GraphQL Hive project.",
"build-arg:IMAGE_TITLE": "graphql-hive/usage-estimator",
"build-arg:PORT": "3008",
"build-arg:RELEASE": "6c5c165e29e8253a09fc7b1691a32cd5e8d7c441",
"build-arg:SERVICE_DIR_NAME": "@hive/usage-estimator",
"context:dist": "local:dist",
"context:shared": "local:shared",
"frontend.caps": "moby.buildkit.frontend.contexts+forward",
"local-sessionid:context": "ob3vzrhz5faabymfqxsubkhg3",
"local-sessionid:dockerfile": "ob3vzrhz5faabymfqxsubkhg3",
"local-sessionid:shared": "ob3vzrhz5faabymfqxsubkhg3"
},
"locals": [
{
"name": "context"
},
{
"name": "dist"
},
{
"name": "dockerfile"
},
{
"name": "shared"
}
]
},
"environment": {
"platform": "linux/arm64"
}
}
},
"buildx.build.ref": "builder-ed970045-9563-45fe-826e-916713cd23dd/builder-ed970045-9563-45fe-826e-916713cd23dd0/x3k3w5eqq51lpmpkdrnwqnp4a",
"containerimage.config.digest": "sha256:732552df508fea1f4346e92b87befd09571d0e3fc435d7f302f41a5f5336718d",
"containerimage.descriptor": {
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"digest": "sha256:39e6e8ef86dd6a7800f8d619a9e6c7ec70b272d73819d8cb18d693f18051e319",
"size": 2075,
"platform": {
"architecture": "arm64",
"os": "linux"
}
},
"containerimage.digest": "sha256:39e6e8ef86dd6a7800f8d619a9e6c7ec70b272d73819d8cb18d693f18051e319",
"image.name": "ghcr.io/graphql-hive/usage-estimator:6c5c165e29e8253a09fc7b1691a32cd5e8d7c441-arm64,ghcr.io/graphql-hive/usage-estimator:hive_metadata-arm64"
},
"usage-ingestor": {
"buildx.build.provenance": {
"buildType": "https://mobyproject.org/buildkit@v1",
"materials": [
{
"uri": "pkg:docker/[email protected]?platform=linux%2Farm64",
"digest": {
"sha256": "f5a0871ab03b035c58bdb3007c3d177b001c2145c18e81817b71624dcf7d8bff"
}
}
],
"invocation": {
"configSource": {
"entryPoint": "services.dockerfile"
},
"parameters": {
"frontend": "dockerfile.v0",
"args": {
"build-arg:HEALTHCHECK_CMD": "wget --spider -q http://127.0.0.1:${PORT}/_readiness",
"build-arg:IMAGE_DESCRIPTION": "The usage ingestor service of the GraphQL Hive project.",
"build-arg:IMAGE_TITLE": "graphql-hive/usage-ingestor",
"build-arg:PORT": "3007",
"build-arg:RELEASE": "6c5c165e29e8253a09fc7b1691a32cd5e8d7c441",
"build-arg:SERVICE_DIR_NAME": "@hive/usage-ingestor",
"context:dist": "local:dist",
"context:shared": "local:shared",
"frontend.caps": "moby.buildkit.frontend.contexts+forward",
"local-sessionid:context": "ob3vzrhz5faabymfqxsubkhg3",
"local-sessionid:dockerfile": "ob3vzrhz5faabymfqxsubkhg3",
"local-sessionid:shared": "ob3vzrhz5faabymfqxsubkhg3"
},
"locals": [
{
"name": "context"
},
{
"name": "dist"
},
{
"name": "dockerfile"
},
{
"name": "shared"
}
]
},
"environment": {
"platform": "linux/arm64"
}
}
},
"buildx.build.ref": "builder-ed970045-9563-45fe-826e-916713cd23dd/builder-ed970045-9563-45fe-826e-916713cd23dd0/iw4w1mco5vqtzwyc45oexea85",
"containerimage.config.digest": "sha256:71644f1c6e17e2a9f8595b4e62cd9b5a12842029e2643df569d3d74acef2caaa",
"containerimage.descriptor": {
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"digest": "sha256:d6e8c895690fedfb7db6a3888d4a6cd2bc5c197fa9a490edc331dc942bba88a3",
"size": 2075,
"platform": {
"architecture": "arm64",
"os": "linux"
}
},
"containerimage.digest": "sha256:d6e8c895690fedfb7db6a3888d4a6cd2bc5c197fa9a490edc331dc942bba88a3",
"image.name": "ghcr.io/graphql-hive/usage-ingestor:6c5c165e29e8253a09fc7b1691a32cd5e8d7c441-arm64,ghcr.io/graphql-hive/usage-ingestor:hive_metadata-arm64"
},
"webhooks": {
"buildx.build.provenance": {
"buildType": "https://mobyproject.org/buildkit@v1",
"materials": [
{
"uri": "pkg:docker/[email protected]?platform=linux%2Farm64",
"digest": {
"sha256": "f5a0871ab03b035c58bdb3007c3d177b001c2145c18e81817b71624dcf7d8bff"
}
}
],
"invocation": {
"configSource": {
"entryPoint": "services.dockerfile"
},
"parameters": {
"frontend": "dockerfile.v0",
"args": {
"build-arg:HEALTHCHECK_CMD": "wget --spider -q http://127.0.0.1:${PORT}/_readiness",
"build-arg:IMAGE_DESCRIPTION": "The webhooks ingestor service of the GraphQL Hive project.",
"build-arg:IMAGE_TITLE": "graphql-hive/webhooks",
"build-arg:PORT": "3005",
"build-arg:RELEASE": "6c5c165e29e8253a09fc7b1691a32cd5e8d7c441",
"build-arg:SERVICE_DIR_NAME": "@hive/webhooks",
"context:dist": "local:dist",
"context:shared": "local:shared",
"frontend.caps": "moby.buildkit.frontend.contexts+forward",
"local-sessionid:context": "ob3vzrhz5faabymfqxsubkhg3",
"local-sessionid:dockerfile": "ob3vzrhz5faabymfqxsubkhg3",
"local-sessionid:shared": "ob3vzrhz5faabymfqxsubkhg3"
},
"locals": [
{
"name": "context"
},
{
"name": "dist"
},
{
"name": "dockerfile"
},
{
"name": "shared"
}
]
},
"environment": {
"platform": "linux/arm64"
}
}
},
"buildx.build.ref": "builder-ed970045-9563-45fe-826e-916713cd23dd/builder-ed970045-9563-45fe-826e-916713cd23dd0/l5z0bcm5625sftpjxkfljonpe",
"containerimage.config.digest": "sha256:30fd796887be06c86d58b5b5883a113cdc0df670b6e048ebafe7e223974f51a9",
"containerimage.descriptor": {
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"digest": "sha256:958f09a6b4e30a48a28720490f1dd7e03959208c73899a75b142804f28074476",
"size": 2075,
"platform": {
"architecture": "arm64",
"os": "linux"
}
},
"containerimage.digest": "sha256:958f09a6b4e30a48a28720490f1dd7e03959208c73899a75b142804f28074476",
"image.name": "ghcr.io/graphql-hive/webhooks:6c5c165e29e8253a09fc7b1691a32cd5e8d7c441-arm64,ghcr.io/graphql-hive/webhooks:hive_metadata-arm64"
}
} |
I've adjusted this to save metadata to a column on the schemaVersion table. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 3
🧹 Nitpick comments (24)
packages/services/schema/src/lib/metadata-extraction.ts (3)
34-37
: Clarify rationale for copying metadata to fields.The comment explains that copying metadata to fields is partly due to inheritance info being lost after composition. Consider adding a reference to where composition discards or complicates inheritance, so future maintainers can easily track why the metadata copy is essential.
77-88
: Deduplicate metadata during merging.The
mergeMetadata
function appends metadata arrays across subgraphs. If subgraphs contain the same metadata entries, duplicates will accumulate. Consider adding a check to filter out duplicates when merging to avoid clutter and keep the metadata clean.+ combined[coordinate] = existing === undefined + ? metadata + : [ + ...existing, + ...metadata.filter( + newItem => !existing.some( + existingItem => + existingItem.name === newItem.name && + existingItem.content === newItem.content + ) + ) + ];
12-75
: Add unit tests for metadata extraction.Although the logic for
extractMetadata
is sound, unit tests can ensure that corner cases (e.g., missing arguments, unknown directive names, unusual AST shapes) are handled properly and do not regress.integration-tests/tests/api/schema/publish.spec.ts (1)
4085-4085
: Consider initializing or describing the new 'schemaMetadata' field.Currently, this property is set to
null
without any accompanying comment or usage. If it's meant to store important data later, consider adding a short comment describing its expected usage or assigning a default non-null value if appropriate, ensuring future clarity around its purpose.packages/services/storage/src/index.ts (1)
4711-4715
: Consider length constraints or additional checks forcontent
.Defining
SchemaMetadataModel
is clear and organized. However, ifcontent
can be very large, you may want to add a max length or sanitization checks to mitigate potential payload bloat or injection concerns.Example optional diff:
const SchemaMetadataModel = zod.object({ name: zod.string(), - content: zod.string(), + content: zod.string().max(2048, "Content length cannot exceed 2048 characters"), });packages/services/schema/src/types.ts (1)
19-19
: Consider enhancing type safety for schema metadata.While the current type is functional, consider these improvements for better type safety and maintainability:
- Define a dedicated interface for the metadata object
- Consider using string literals for known metadata names
- Add JSDoc comments to document the purpose and structure
Example:
/** Metadata object containing name and content pairs */ interface SchemaMetadataItem { /** Name of the metadata entry */ name: string; /** Content of the metadata entry */ content: string; } /** Known metadata names */ type MetadataName = 'description' | 'deprecated' | 'example' | string; /** Schema metadata mapping */ type SchemaMetadataMapping = Record<string, Array<SchemaMetadataItem>>;packages/libraries/federation-link-utils/src/index.ts (1)
52-52
: Simplify the import name resolution.The current implementation can be made more concise using string methods.
- return name.startsWith('@') ? name.substring(1) : name; + return name.replace(/^@/, '');integration-tests/tests/schema/metadata.spec.ts (3)
5-16
: Consider extracting client setup to a shared utility.The TRPC client setup could be reused across other integration tests.
Consider moving this to a shared utility file:
// testkit/utils/trpc.ts export function createSchemaClient() { const host = process.env['SCHEMA_SERVICE_HOST_OVERRIDE'] || (await getServiceHost('schema', 3002).then(r => `http://${r}`)); return createTRPCProxyClient<SchemaBuilderApi>({ links: [ httpLink({ url: host + `/trpc`, fetch, }), ], }); }
18-62
: Enhance test coverage for metadata processing.While the current test verifies basic metadata processing, consider adding tests for:
- Invalid metadata values
- Multiple metadata directives on the same entity
- Metadata inheritance in extended types
63-150
: Consider using explicit assertions instead of snapshots.While snapshots are convenient, explicit assertions would make the test intentions clearer and more maintainable.
Example:
expect(result.supergraph).toMatch(/@meta\(name: "owner", content: "hive-team"\)/); expect(result.supergraph).toMatch(/directive @meta\(name: String!, content: String!\)/);packages/web/app/src/components/target/explorer/super-graph-metadata.tsx (2)
26-32
: Remove redundant fragment.The fragment is unnecessary since it only contains a single mapping operation.
- <> {props.supergraphMetadata.map((m, i) => ( <div key={i}> <span className="font-bold">{m.name}:</span> {m.content} </div> ))} - </>🧰 Tools
🪛 Biome (1.9.4)
[error] 26-32: Avoid using unnecessary Fragment.
A fragment is redundant if it contains only one child, or if it is the child of a html element, and is not a keyed fragment.
Unsafe fix: Remove the Fragment(lint/complexity/noUselessFragments)
35-35
: Extract icon styles to a CSS class.Consider moving the inline styles to a CSS class for better maintainability.
- <MetadataIcon className="my-[5px] cursor-pointer text-white" /> + <MetadataIcon className="metadata-icon" />Add to your CSS:
.metadata-icon { margin-top: 5px; margin-bottom: 5px; cursor: pointer; color: white; }packages/libraries/federation-link-utils/src/link.ts (1)
13-13
: Use type guard for safer type casting.Instead of type assertion, consider using a type guard for safer type casting of the feature value.
- const url = FederatedLinkUrl.fromUrl((feature.value as StringValueNode).value); + if (feature.value.kind === Kind.STRING) { + const url = FederatedLinkUrl.fromUrl(feature.value.value); + return new FederatedLink(url, null, []); + } + return;packages/services/api/src/modules/schema/resolvers/SchemaVersion.ts (1)
88-88
: Track GraphQL resolve info optimization TODO.The TODO comment about using GraphQL resolve info for query optimization should be tracked.
Would you like me to create an issue to track this optimization task?
packages/services/api/src/shared/entities.ts (1)
390-390
: Consider using a more specific type for schema metadata.While the current implementation works, using a Record with 'any' type could make the code harder to maintain. Consider creating a dedicated type for metadata content.
- schemaMetadata: Record<string, Array<{ name: string; content: string }>> | null; + schemaMetadata: Record<string, Array<SchemaMetadataMapper>> | null;packages/services/api/src/modules/schema/providers/models/shared.ts (1)
243-243
: LGTM! Consider adding JSDoc comments.The
schemaMetadata
property is well-typed and properly structured. Consider adding JSDoc comments to document the purpose and structure of the metadata.+ /** + * Metadata associated with schema coordinates. + * @property {string} name - The name of the metadata entry + * @property {string} content - The content of the metadata entry + */ schemaMetadata: null | Record<string, Array<{ name: string; content: string }>>;Also applies to: 290-290
packages/services/api/src/modules/schema/resolvers/SchemaExplorer.ts (1)
63-65
: Consider extracting the commongetFieldMetadata
implementation.The
getFieldMetadata
implementation is duplicated across multiple types. Consider extracting it into a shared utility function to improve maintainability.+ function createFieldMetadataGetter(supergraph: SuperGraphInformation, typeName: string) { + return (fieldName: string) => + supergraph.schemaCoordinateMetadataMappings?.get(`${typeName}.${fieldName}`) ?? null; + } // Usage example: supergraph: supergraph ? { - getFieldMetadata: fieldName => - supergraph.schemaCoordinateMetadataMappings?.get(`${entity.name}.${fieldName}`) ?? null, + getFieldMetadata: createFieldMetadataGetter(supergraph, entity.name), // ... other methods } : null,Also applies to: 81-83, 196-198, 215-217, 325-327, 368-370, 411-413
packages/services/api/src/modules/schema/providers/schema-manager.ts (1)
400-401
: Consider adding validation for schemaMetadata.The new
schemaMetadata
property is correctly added to both success and error cases, but it might benefit from runtime validation to ensure the data structure matches the expected format.Consider adding Zod validation:
const SchemaMetadataRecord = z.record(z.string(), z.array(z.object({ name: z.string(), content: z.string() }))); // Then use it in the union type | { compositeSchemaSDL: null; supergraphSDL: null; schemaCompositionErrors: Array<SchemaCompositionError>; tags: null; schemaMetadata: z.infer<typeof SchemaMetadataRecord> | null; }Also applies to: 407-408
packages/services/api/src/modules/schema/providers/schema-publisher.ts (1)
1320-1321
: Consider adding error handling for schema metadata parsing.The schema metadata is correctly propagated during deletion and publishing, but there's no explicit error handling for metadata parsing failures.
Consider wrapping the metadata handling in a try-catch block:
try { schemaMetadata: publishResult.state?.schemaMetadata ?? null, } catch (error) { this.logger.error('Failed to parse schema metadata', error); schemaMetadata: null, }Also applies to: 1327-1328, 1879-1880, 1889-1890
packages/libraries/cli/examples/federation.reviews.graphql (2)
9-13
: Consider adding documentation for the @meta directive.The
@meta
directive is well-defined but could benefit from documentation explaining its usage and constraints.Add documentation:
""" Metadata directive for annotating schema elements with additional information. @param name The identifier for the metadata entry @param content The value associated with the metadata entry """ directive @meta( name: String! content: String! ) repeatable on SCHEMA | OBJECT | INTERFACE | FIELD_DEFINITION
14-19
: Consider adding validation for reviewsScore.The
reviewsScore
field is marked as shareable and overridden from "products", but there's no validation for the score range.Consider adding a custom directive for validation:
directive @validateScore(min: Float!, max: Float!) on FIELD_DEFINITION type Product implements ProductItf @key(fields: "id") { # ... reviewsScore: Float! @shareable @override(from: "products") @validateScore(min: 0.0, max: 5.0) # ... }packages/libraries/cli/examples/federation.products.graphql (2)
14-17
: Consider consolidating custom directives.The custom directives
@myDirective
and@hello
seem to be utility directives. Consider consolidating them into a more meaningful directive structure.Consider consolidating:
directive @customField( name: String! type: String! options: [String!] ) on FIELD_DEFINITION
23-33
: Consider documenting the inaccessible field.The
hidden
field is marked as@inaccessible
but lacks documentation explaining why it's hidden and when it might be used.Add documentation:
interface ProductItf implements SkuItf @meta(name: "domain", content: "products") { # ... """ Hidden field used internally for product management. This field is marked as @inaccessible and won't be exposed in the public API. """ hidden: String @inaccessible # ... }packages/services/api/package.json (1)
18-18
: Dependency Category Review: Check if @graphql-hive/federation-link-utils belongs in devDependencies.
A new dependency for federation link utilities has been added as a devDependency. Given its role in supporting schema metadata extraction and federation features, please verify that it is not required at runtime. If the functionality it provides is needed in production, consider moving it to the regular dependencies section.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
pnpm-lock.yaml
is excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (36)
integration-tests/tests/api/schema/check.spec.ts
(1 hunks)integration-tests/tests/api/schema/publish.spec.ts
(1 hunks)integration-tests/tests/schema/metadata.spec.ts
(1 hunks)packages/libraries/cli/examples/federation.products.graphql
(1 hunks)packages/libraries/cli/examples/federation.reviews.graphql
(1 hunks)packages/libraries/federation-link-utils/src/index.ts
(1 hunks)packages/libraries/federation-link-utils/src/link.ts
(2 hunks)packages/migrations/src/actions/2025.02.14T00-00-00.schema-versions-metadata.ts
(1 hunks)packages/migrations/src/run-pg-migrations.ts
(1 hunks)packages/migrations/test/2024.07.23T09.36.00.schema-cleanup-tracker.test.ts
(2 hunks)packages/services/api/package.json
(1 hunks)packages/services/api/src/modules/schema/lib/federation-super-graph.ts
(12 hunks)packages/services/api/src/modules/schema/module.graphql.mappers.ts
(4 hunks)packages/services/api/src/modules/schema/module.graphql.ts
(1 hunks)packages/services/api/src/modules/schema/providers/models/composite.ts
(2 hunks)packages/services/api/src/modules/schema/providers/models/shared.ts
(2 hunks)packages/services/api/src/modules/schema/providers/models/single.ts
(1 hunks)packages/services/api/src/modules/schema/providers/registry-checks.ts
(1 hunks)packages/services/api/src/modules/schema/providers/schema-manager.ts
(1 hunks)packages/services/api/src/modules/schema/providers/schema-publisher.ts
(3 hunks)packages/services/api/src/modules/schema/resolvers/GraphQLEnumType.ts
(1 hunks)packages/services/api/src/modules/schema/resolvers/GraphQLField.ts
(1 hunks)packages/services/api/src/modules/schema/resolvers/GraphQLInterfaceType.ts
(1 hunks)packages/services/api/src/modules/schema/resolvers/GraphQLObjectType.ts
(1 hunks)packages/services/api/src/modules/schema/resolvers/SchemaExplorer.ts
(7 hunks)packages/services/api/src/modules/schema/resolvers/SchemaMetadata.ts
(1 hunks)packages/services/api/src/modules/schema/resolvers/SchemaVersion.ts
(4 hunks)packages/services/api/src/modules/schema/utils.ts
(2 hunks)packages/services/api/src/modules/shared/providers/storage.ts
(2 hunks)packages/services/api/src/shared/entities.ts
(1 hunks)packages/services/schema/src/lib/metadata-extraction.ts
(1 hunks)packages/services/schema/src/orchestrators.ts
(12 hunks)packages/services/schema/src/types.ts
(1 hunks)packages/services/storage/src/db/types.ts
(1 hunks)packages/services/storage/src/index.ts
(8 hunks)packages/web/app/src/components/target/explorer/super-graph-metadata.tsx
(5 hunks)
✅ Files skipped from review due to trivial changes (1)
- packages/services/api/src/modules/schema/resolvers/GraphQLEnumType.ts
🧰 Additional context used
📓 Path-based instructions (4)
`packages/services/**`: Microservices written in NodeJS and ...
packages/services/**
: Microservices written in NodeJS and TypeScript. Most of the dirs under this directory are packages and deployed as Docker packages.
Interaction between services is done using tRPC.
We prefer writing code that does input/output validations with Zod.
The directories that ends with-worker
are projects that are built on top of CloudFlare Workers infrastructure and deployed there.
Thecdn-worker
is a special one, it serves a high-available, detached CDN on CloudFlare Workers. This is how our end-users fetches the crucial data from our platform, in a way that does not depend/couple on our main API (served as GraphQL API).
packages/services/api/src/modules/schema/resolvers/GraphQLObjectType.ts
packages/services/api/package.json
packages/services/schema/src/types.ts
packages/services/storage/src/db/types.ts
packages/services/api/src/modules/schema/providers/models/single.ts
packages/services/api/src/modules/schema/resolvers/SchemaMetadata.ts
packages/services/api/src/modules/schema/resolvers/GraphQLField.ts
packages/services/api/src/modules/schema/providers/registry-checks.ts
packages/services/api/src/modules/schema/providers/models/shared.ts
packages/services/api/src/modules/schema/resolvers/GraphQLInterfaceType.ts
packages/services/api/src/shared/entities.ts
packages/services/api/src/modules/schema/providers/models/composite.ts
packages/services/schema/src/lib/metadata-extraction.ts
packages/services/api/src/modules/schema/resolvers/SchemaExplorer.ts
packages/services/api/src/modules/shared/providers/storage.ts
packages/services/api/src/modules/schema/utils.ts
packages/services/api/src/modules/schema/module.graphql.mappers.ts
packages/services/api/src/modules/schema/module.graphql.ts
packages/services/api/src/modules/schema/resolvers/SchemaVersion.ts
packages/services/api/src/modules/schema/providers/schema-publisher.ts
packages/services/api/src/modules/schema/lib/federation-super-graph.ts
packages/services/schema/src/orchestrators.ts
packages/services/storage/src/index.ts
packages/services/api/src/modules/schema/providers/schema-manager.ts
`packages/libraries/**`: Most of the dirs here are NPM packa...
packages/libraries/**
: Most of the dirs here are NPM packages that provides our customers an integration library, in order to get/fetch data from Hive Console API or Hive CDN.
packages/libraries/federation-link-utils/src/index.ts
packages/libraries/federation-link-utils/src/link.ts
packages/libraries/cli/examples/federation.reviews.graphql
packages/libraries/cli/examples/federation.products.graphql
`integration-tests/**`: integration tests for ensuring featu...
integration-tests/**
: integration tests for ensuring features and important flows are running. Usually, changes to thepackages/
directory will affect this. In ideal flow, each PR should include integration tests.
integration-tests/tests/api/schema/check.spec.ts
integration-tests/tests/schema/metadata.spec.ts
integration-tests/tests/api/schema/publish.spec.ts
`packages/libraries/cli/**`: The CLI to interact with Hive C...
packages/libraries/cli/**
: The CLI to interact with Hive Console APIs.
packages/libraries/cli/examples/federation.reviews.graphql
packages/libraries/cli/examples/federation.products.graphql
🪛 Biome (1.9.4)
packages/web/app/src/components/target/explorer/super-graph-metadata.tsx
[error] 26-32: Avoid using unnecessary Fragment.
A fragment is redundant if it contains only one child, or if it is the child of a html element, and is not a keyed fragment.
Unsafe fix: Remove the Fragment
(lint/complexity/noUselessFragments)
⏰ Context from checks skipped due to timeout of 90000ms (4)
- GitHub Check: test / integration (3)
- GitHub Check: test / integration (2)
- GitHub Check: test / integration (1)
- GitHub Check: test / e2e
🔇 Additional comments (37)
packages/services/schema/src/lib/metadata-extraction.ts (1)
19-20
: Consider handling an undefined directive name.The code relies on
resolveImportName('https://specs.graphql-hive.com/hive', '@meta')
to return a valid string. If no link directive exists or the subgraph doesn't match this spec,metaDirectiveName
might be undefined. A small guard or fallback could prevent unexpected runtime errors in edge cases.packages/services/api/src/modules/schema/lib/federation-super-graph.ts (4)
19-19
: Unused metadata mapping field.
schemaCoordinateMetadataMappings
is introduced but never returned or utilized inextractSuperGraphInformation
. If future development will leverage this field, consider returning or referencing it now. Otherwise, remove to avoid confusion.
28-28
: Returned type differs fromSuperGraphInformation
.The function is changed to return only
{ schemaCoordinateServicesMappings }
. Verify if this is intentional, especially sinceSuperGraphInformation
includes the newschemaCoordinateMetadataMappings
. If metadata mappings are needed later, consider including them in the return type to prevent future refactoring.
34-42
: Dynamic resolution of join directives is clear.Using
resolveImportName
instead of hardcoding'@type'
,'@field'
, etc. improves maintainability and reduces risk of naming collisions. This is a good approach.
66-67
: Refactor uses consistent directive naming.All updated references to
joinDirectiveName
are logical and consistent. Great job reducing reliance on string literals for directive names and ensuring uniform usage across node definitions.Also applies to: 140-142, 153-154, 164-165, 189-190, 199-200, 213-214, 239-240, 300-303, 309-310
packages/services/schema/src/orchestrators.ts (4)
172-238
: Validate potential performance impact of copying schema‑level metadata to every field.When a subgraph implements the Hive metadata spec, the code applies schema‑level
@meta
directives to all fields. For very large schemas, this could be expensive. Consider verifying performance on real-world examples or caching repeated metadata objects to mitigate overhead.
281-285
: Graceful handling of metadata extraction errors.Catching metadata extraction errors and proceeding is a reasonable strategy. Logging the warning ensures visibility without breaking the main flow, which is appropriate since metadata is non-critical. This balanced approach is commendable.
431-432
: Good addition ofschemaMetadata
to outputs.Returning
schemaMetadata
alongsidetags
in the orchestrator’s final object ensures consumers have immediate access to aggregated metadata, aligning well with the new functionality introduced in this PR.Also applies to: 447-448
2-2
: Ensure schemaMetadata remains optional but tested.While
schemaMetadata
is accurately typed asnull
or structured data, confirm that any downstream clients consuming this property handle both states. It may be beneficial to add a test confirming that the orchestrator gracefully returnsnull
when no metadata is present.Also applies to: 37-37, 167-168, 300-303
integration-tests/tests/api/schema/check.spec.ts (1)
2188-2188
:❓ Verification inconclusive
Confirm usage of the newly introduced
schemaMetadata
field.Setting
schemaMetadata
tonull
here might be intentional, but ensure it is correct for all use cases ofcreateVersion()
. If this field is meant to store important metadata for referencing or debugging, consider adding corresponding test coverage to ensure the persistent storage logic works as intended.You can run the following script to confirm whether
schemaMetadata
is used elsewhere in the codebase and if further adjustments are needed:
🏁 Script executed:
#!/bin/bash # Description: Search usage and references of schemaMetadata across the repository. ast-grep --pattern $'schemaMetadata: $_'Length of output: 41
Attention: Please verify the usage of the
schemaMetadata
field
- The integration test in integration-tests/tests/api/schema/check.spec.ts (line 2188) currently sets
schemaMetadata
tonull
.- An initial search using an AST grep command did not yield any references to
schemaMetadata
, which makes it unclear whether this field is actively used in other parts of the codebase.- If
schemaMetadata
is meant to support important metadata for functions likecreateVersion()
, please ensure that its usage is correctly implemented and covered by appropriate tests. Manual verification of its usage (for example, by additionally searching withrg "schemaMetadata"
or reviewing the implementation ofcreateVersion()
) is recommended before final approval.packages/services/storage/src/index.ts (6)
2399-2399
: Make sureschemaMetadata
is handled in downstream usage.Adding
schemaMetadata
strengthens the flexibility for metadata handling. Please verify that other parts of the code (like retrieval, serialization, and UI) manage this property consistently, and consider adding corresponding test coverage to confirm correct behavior.
2511-2511
: Confirm consistency with other call sites.The addition of
schemaMetadata
here mirrors the usage in the delete flow. Ensure all references tocreateVersion
pass theschemaMetadata
parameter correctly, and that the property is optional if not always available.
4731-4731
: SchemaVersionModel enhancement looks good.The
schemaMetadata
property is well integrated with nullability and typed validation, boosting clarity in the version model.
4877-4877
: Parameter addition is consistent.The new
schemaMetadata
parameter aligns well with the earlier property usage. This should facilitate streamlined passing of metadata to the insert logic.
4904-4905
: Columns added align with existing patterns.Adding
conditional_breaking_change_metadata
andschema_metadata
columns extends existing schema version tracking fields and follows the established naming conventions. No issues spotted.
4924-4925
: Values properly included in the SQL insert.Referencing both the parsed conditional breaking changes and
schemaMetadata
accommodates the new fields without impacting core functionality, and leverages thejsonify()
helper as intended.packages/migrations/src/actions/2025.02.14T00-00-00.schema-versions-metadata.ts (1)
1-10
: LGTM! Well-structured migration for adding schema metadata.The migration is well-designed:
- Uses JSONB type which is appropriate for flexible metadata storage
- Includes NULL default value making it backward compatible
- Follows the timestamp naming convention
packages/services/api/src/modules/schema/resolvers/GraphQLField.ts (1)
19-25
: LGTM! Clean addition of metadata to supergraphMetadata.The change cleanly adds metadata support while preserving existing functionality and null safety.
packages/libraries/federation-link-utils/src/index.ts (1)
44-46
:❓ Verification inconclusive
Verify if the fix for link/core directive detection is complete.
The comment suggests checking for both
@link
and@core
directives, but the implementation only checks for the presence of links. This might still be incomplete based on the past review comment.
🏁 Script executed:
#!/bin/bash # Search for @core directive usage in the codebase rg -A 5 '@core' --type ts --type graphqlLength of output: 72
Review Directive Detection for Federation v2
It appears that the recent changes in
packages/libraries/federation-link-utils/src/index.ts
(lines 44–46) only check for the presence of@link
directives by determining iflinkByIdentity
has any keys. However, the comment and previous discussions indicate that detection should cover both@link
and@core
directives.
- The current implementation:
only verifies
// Check if any @link or @core features are used. const supportsFederationV2 = Object.keys(linkByIdentity).length > 0;@link
usage.- A search for
@core
in TypeScript files (after adjusting for the graphql file type error) returned no results. This could mean:
- The
@core
usage might not exist in TS files, or- It is handled elsewhere, or
- It’s an oversight if the intention was to detect both kinds.
Please manually verify whether:
- The codebase intentionally excludes a separate check for
@core
directives, or- Additional logic is required to properly detect
@core
usage alongside@link
.Additionally, ensure that any simplification seen at the import name resolution on line 52 aligns with the overall feature detection strategy.
packages/services/api/src/modules/schema/resolvers/GraphQLObjectType.ts (1)
17-20
: LGTM! Consistent metadata handling.The implementation correctly adds metadata support while maintaining the existing functionality.
packages/services/api/src/modules/schema/resolvers/GraphQLInterfaceType.ts (1)
17-20
: LGTM! Consistent metadata handling.The implementation mirrors the object type resolver, ensuring consistent behavior across types.
packages/web/app/src/components/target/explorer/super-graph-metadata.tsx (1)
106-111
: LGTM! Good use of memoization and tooltip configuration.The changes effectively handle metadata display with proper performance optimization through
useMemo
. The tooltip delay duration of 100ms provides a good balance between responsiveness and user experience.Also applies to: 167-167
packages/libraries/federation-link-utils/src/link.ts (1)
85-93
: LGTM! Well-implemented Federation 1 support.The implementation elegantly handles the translation from
@core
to@link
directives, maintaining backward compatibility while following the same patterns as the existing code.packages/migrations/test/2024.07.23T09.36.00.schema-cleanup-tracker.test.ts (1)
96-97
: LGTM! Proper test coverage for schema metadata.The test correctly verifies the schema version creation with the new
schemaMetadata
column while maintaining existing functionality.Also applies to: 116-117
packages/services/api/src/modules/schema/module.graphql.mappers.ts (3)
133-133
: LGTM! Added metadata support to GraphQL fields.The metadata property is correctly typed as nullable array of
SchemaMetadataMapper
.
183-183
: LGTM! Added field metadata retrieval support.The
getFieldMetadata
method is consistently implemented across both object and interface types.Also applies to: 197-197
300-303
: LGTM! Well-structured metadata type definition.The
SchemaMetadataMapper
type is properly defined with required properties for name and content.packages/services/api/src/modules/schema/providers/models/single.ts (1)
330-330
: LGTM! Added schema metadata to publish result.The
schemaMetadata
is correctly derived from the composition check result with proper null handling.packages/migrations/src/run-pg-migrations.ts (1)
161-161
: LGTM!The new schema versions metadata migration is properly added to the list, following the established patterns for naming and dynamic imports.
packages/services/api/src/modules/schema/utils.ts (1)
149-152
: LGTM!The
getFieldMetadata
method is well-implemented, following existing patterns and properly handling null cases.Also applies to: 189-192
packages/services/api/src/modules/schema/resolvers/SchemaExplorer.ts (1)
63-65
: LGTM!The
getFieldMetadata
method is consistently implemented across all GraphQL types.Also applies to: 81-83, 196-198, 215-217, 325-327, 368-370, 411-413
packages/services/api/src/modules/schema/providers/models/composite.ts (1)
515-515
: LGTM! Metadata propagation is correctly implemented.The changes properly propagate schema metadata from composition check results, maintaining null safety through the nullish coalescing operator.
Also applies to: 721-721
packages/services/api/src/modules/shared/providers/storage.ts (1)
416-417
: LGTM! Metadata type is consistently defined.The metadata type is consistently defined across methods with proper nullability and structure:
null | Record<string, Array<{ name: string; content: string }>>Also applies to: 423-424, 464-465
packages/services/api/src/modules/schema/providers/registry-checks.ts (1)
303-303
: LGTM! Metadata extraction is properly implemented.The change correctly extracts schema metadata from the composition result, maintaining null safety through the nullish coalescing operator.
packages/services/api/src/modules/schema/module.graphql.ts (1)
763-763
: LGTM! GraphQL schema types are well-defined.The changes introduce a well-structured
SchemaMetadata
type and correctly integrate it into theSupergraphMetadata
type:
SchemaMetadata
type with non-nullname
andcontent
fields.metadata
field inSupergraphMetadata
as an array ofSchemaMetadata
.Also applies to: 771-774
packages/libraries/cli/examples/federation.reviews.graphql (1)
1-8
: LGTM! Well-structured federation setup with metadata.The schema correctly uses federation directives and metadata annotations. The import statements are properly organized.
packages/libraries/cli/examples/federation.products.graphql (1)
39-54
: LGTM! Well-structured Product type with comprehensive key fields.The
Product
type correctly implements both interfaces and uses multiple@key
directives for flexible entity resolution.
supergraph: { | ||
schemaCoordinateMetadataMappings: version.schemaMetadata | ||
? new Map(Object.entries(version.schemaMetadata)) | ||
: null, | ||
schemaCoordinateServicesMappings: supergraph?.schemaCoordinateServicesMappings ?? new Map(), | ||
}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Extract duplicated metadata mapping logic.
The metadata mapping creation logic is duplicated across three methods. Consider extracting it to a shared helper function.
+ private createSupergraphMappings(version: SchemaVersion, supergraph: SupergraphInfo | null) {
+ return {
+ schemaCoordinateMetadataMappings: version.schemaMetadata
+ ? new Map(Object.entries(version.schemaMetadata))
+ : null,
+ schemaCoordinateServicesMappings: supergraph?.schemaCoordinateServicesMappings ?? new Map(),
+ };
+ }
Then use it in all three methods:
- supergraph: {
- schemaCoordinateMetadataMappings: version.schemaMetadata
- ? new Map(Object.entries(version.schemaMetadata))
- : null,
- schemaCoordinateServicesMappings: supergraph?.schemaCoordinateServicesMappings ?? new Map(),
- },
+ supergraph: this.createSupergraphMappings(version, supergraph),
Also applies to: 144-149, 172-177
@@ -334,6 +334,7 @@ export interface schema_versions { | |||
previous_schema_version_id: string | null; | |||
record_version: string | null; | |||
schema_composition_errors: any | null; | |||
schema_metadata: any | null; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Consider using a more specific type for schema_metadata.
While this file is auto-generated, using any
type for schema_metadata
could lead to type safety issues. Consider:
- Defining a proper type in the database schema
- Using JSON schema validation for the metadata
This will help ensure data consistency and improve type safety throughout the application.
@@ -1,60 +1,74 @@ | |||
enum CURRENCY_CODE { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I assume the prior version was for Federation 1? But I couldn't get the two example schemas working locally. I've opted to update them to Federation 2. Let me know if I should make a new version instead.
import type { SchemaBuilderApi } from '@hive/schema'; | ||
import { createTRPCProxyClient, httpLink } from '@trpc/client'; | ||
|
||
const host = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: should this go somewhere into the test kit? 😄
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
possibly... I dont see anywhere in the codebase where we use SCHEMA_SERVICE_HOST_OVERRIDE
... If anything I assume RUN_AGAINST_LOCAL_SERVICES
is more practical for us to use for overriding the hosts.
I'd be in favor of removing the env var condition in this file and in the contracts.spec.ts
before moving this into the test kit.
packages/migrations/src/actions/2025.02.14T00-00-00.schema-versions-metadata.ts
Show resolved
Hide resolved
79db270
to
69b6d47
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🔭 Outside diff range comments (2)
integration-tests/tests/api/schema/check.spec.ts (1)
2121-2137
: 🛠️ Refactor suggestionConsider security implications of connection string handling.
The
connectionString
function handles sensitive database credentials. Consider:
- Using a secure configuration management system
- Adding input validation for environment variables
- Masking sensitive information in logs
Here's a suggested improvement:
function connectionString() { + const requiredEnvVars = ['POSTGRES_USER', 'POSTGRES_PASSWORD', 'POSTGRES_HOST']; + for (const envVar of requiredEnvVars) { + if (!process.env[envVar]) { + throw new Error(`Missing required environment variable: ${envVar}`); + } + } + const { POSTGRES_USER = 'postgres', POSTGRES_PASSWORD = 'postgres', POSTGRES_HOST = 'localhost', POSTGRES_PORT = 5432, POSTGRES_DB = 'registry', POSTGRES_SSL = null, POSTGRES_CONNECTION_STRING = null, } = process.env; + + // Validate port number + const port = Number(POSTGRES_PORT); + if (isNaN(port) || port <= 0 || port > 65535) { + throw new Error('Invalid POSTGRES_PORT'); + } + return ( POSTGRES_CONNECTION_STRING || `postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@${POSTGRES_HOST}:${POSTGRES_PORT}/${POSTGRES_DB}${ POSTGRES_SSL ? '?sslmode=require' : '?sslmode=disable' }` ); }integration-tests/tests/api/schema/publish.spec.ts (1)
2749-2868
: 🛠️ Refactor suggestionStandardize test cleanup handling.
Make cleanup more consistent by:
- Using beforeAll/afterAll hooks consistently
- Ensuring all resources are properly cleaned up
- Adding cleanup verification
- Handling cleanup failures gracefully
Also applies to: 3991-4115
🧹 Nitpick comments (17)
packages/services/schema/src/lib/metadata-extraction.ts (1)
12-75
: LGTM! The metadata extraction implementation is robust and well-structured.The implementation:
- Correctly resolves the metadata directive name using federation link utils
- Properly handles field-level metadata collection
- Includes validation for directive arguments
- Uses schema coordinates for precise metadata mapping
A good-to-have improvement would be to add error handling for malformed metadata:
if (metaNameArg && metaContentArg) { + try { acc.push({ name: (metaNameArg.value as StringValueNode).value, content: (metaContentArg.value as StringValueNode).value, }); + } catch (error) { + console.warn(`Failed to process metadata: ${error.message}`); + } }integration-tests/tests/schema/metadata.spec.ts (1)
18-62
: Add more test cases for metadata validation.While the current test verifies basic metadata composition, consider adding test cases for:
- Invalid metadata directives
- Multiple metadata entries on the same field
- Metadata inheritance
packages/web/app/src/components/target/explorer/super-graph-metadata.tsx (1)
19-38
: Remove unnecessary Fragment wrapper.The Fragment wrapper in the tooltip content is redundant as it contains only one child.
- <> {props.supergraphMetadata.map((m, i) => ( <div key={i}> <span className="font-bold">{m.name}:</span> {m.content} </div> ))} - </>🧰 Tools
🪛 Biome (1.9.4)
[error] 26-32: Avoid using unnecessary Fragment.
A fragment is redundant if it contains only one child, or if it is the child of a html element, and is not a keyed fragment.
Unsafe fix: Remove the Fragment(lint/complexity/noUselessFragments)
packages/libraries/federation-link-utils/src/link.ts (1)
85-93
: Consider adding version validation for Federation 1 support.While the implementation works, it would be beneficial to validate the Federation version to ensure the core directive is only processed for Federation 1 schemas.
const defCores = definition.directives?.filter(({ name }) => name.value === 'core'); +const isFederation1 = links.some(link => + link.identity.startsWith('https://specs.apollo.dev/federation/v1')); const coreLinks = defCores + ?.filter(() => isFederation1) ?.map(c => linkFromCoreArgs(c.arguments ?? [])) .filter(l => l !== undefined);packages/services/api/src/modules/schema/lib/federation-super-graph.ts (1)
28-28
: Consider updating return type to include metadata mappings.The return type is restricted to only include 'schemaCoordinateServicesMappings' using Pick, but the function might need to return metadata mappings in the future.
Consider updating the return type to include both mappings:
-(documentAst: DocumentNode): Pick<SuperGraphInformation, 'schemaCoordinateServicesMappings'> => { +(documentAst: DocumentNode): Pick<SuperGraphInformation, 'schemaCoordinateServicesMappings' | 'schemaCoordinateMetadataMappings'> => {packages/services/schema/src/orchestrators.ts (1)
281-289
: Consider improving error handling for metadata extraction.The current implementation logs a warning and proceeds when metadata extraction fails. While this is a reasonable approach since metadata isn't critical, consider providing more detailed error information.
Consider enhancing the error handling:
-logger.warn(`Cannot extract metadata from subgraphs because ${e}`); +logger.warn({ + error: e, + subgraphCount: subgraphs.length, + message: 'Cannot extract metadata from subgraphs', +});integration-tests/tests/api/schema/check.spec.ts (1)
1808-1921
: Consider adding edge case tests for context ID validation.While the tests cover basic length validation for context IDs, consider adding tests for:
- Special characters in context IDs
- Unicode characters
- Leading/trailing whitespace
Here's a suggested addition:
+test.concurrent('contextId with special characters is properly handled', async ({ expect }) => { + const { createOrg } = await initSeed().createOwner(); + const { createProject } = await createOrg(); + const { createTargetAccessToken } = await createProject(ProjectType.Single); + + const readToken = await createTargetAccessToken({ + mode: 'readOnly', + }); + + const specialContextIds = [ + 'pr-123!@#$%', + ' pr-123 ', + 'pr-123🚀', + ]; + + for (const contextId of specialContextIds) { + const checkResult = await readToken + .checkSchema( + /* GraphQL */ ` + type Query { + ping: String + } + `, + undefined, + undefined, + contextId, + ) + .then(r => r.expectNoGraphQLErrors()); + + expect(checkResult.schemaCheck.__typename).toBe('SchemaCheckSuccess'); + } +});integration-tests/tests/api/schema/publish.spec.ts (9)
17-42
: Consider adding edge cases for access control testing.The test verifies basic access control for schema publishing, but could be enhanced with additional test cases:
- Test with expired tokens
- Test with tokens having partial permissions
- Test with malformed tokens
302-333
: Add metadata structure validation.The test verifies metadata persistence but doesn't validate the structure of the metadata. Consider:
- Adding schema validation for metadata
- Testing with invalid metadata formats
- Testing with large metadata payloads
291-349
: Enhance CDN access token validation tests.While the tests cover basic scenarios, consider adding:
- Tests for token expiration
- Tests for rate limiting
- Tests for different HTTP methods
- Tests for various content types
2749-2868
: Improve error isolation in composition tests.The composition error tests could be enhanced by:
- Isolating different types of composition errors
- Testing partial composition failures
- Adding timeout scenarios
- Testing recovery from composition failures
547-626
: Reorganize schema change persistence tests.The test suite could be better organized by:
- Grouping related test cases into describe blocks
- Using shared setup code
- Adding test categories for different types of changes
- Improving test case naming for better clarity
3991-4034
: Expand deprecated field validation tests.Consider adding tests for:
- Multiple deprecated fields in the same type
- Deprecated fields with different nullability combinations
- Deprecated fields in interfaces and unions
- Deprecation reason validation
3048-3110
: Enhance service URL validation testing.Add test cases for:
- Invalid URL formats
- URL normalization
- URL encoding/decoding
- URL with query parameters and fragments
370-397
: Improve concurrent publishing test coverage.Enhance race condition testing by:
- Adding delays between operations
- Testing with different timing patterns
- Verifying intermediate states
- Testing conflict resolution
527-543
: Improve database connection handling.Consider enhancing the connection handling:
- Add connection pooling configuration
- Add retry logic for connection failures
- Add connection timeout handling
- Validate connection parameters
packages/libraries/cli/examples/federation.products.graphql (1)
39-54
: Product Type with Composite Keys and MetadataThe
Product
type strongly leverages federation through multiple@key
directives for various lookup patterns—usingid
, a composite ofsku package
, and a nested key involvingsku variation { id }
. The application of both@meta
and@tag
directives on selected fields (e.g.,sku
andid
) stylishly integrates metadata into the type definition.
Consider adding inline comments to clarify the rationale behind the multiple composite keys for future maintainers.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
pnpm-lock.yaml
is excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (36)
integration-tests/tests/api/schema/check.spec.ts
(1 hunks)integration-tests/tests/api/schema/publish.spec.ts
(1 hunks)integration-tests/tests/schema/metadata.spec.ts
(1 hunks)packages/libraries/cli/examples/federation.products.graphql
(1 hunks)packages/libraries/cli/examples/federation.reviews.graphql
(1 hunks)packages/libraries/federation-link-utils/src/index.ts
(1 hunks)packages/libraries/federation-link-utils/src/link.ts
(2 hunks)packages/migrations/src/actions/2025.02.14T00-00-00.schema-versions-metadata.ts
(1 hunks)packages/migrations/src/run-pg-migrations.ts
(1 hunks)packages/migrations/test/2024.07.23T09.36.00.schema-cleanup-tracker.test.ts
(2 hunks)packages/services/api/package.json
(1 hunks)packages/services/api/src/modules/schema/lib/federation-super-graph.ts
(12 hunks)packages/services/api/src/modules/schema/module.graphql.mappers.ts
(4 hunks)packages/services/api/src/modules/schema/module.graphql.ts
(1 hunks)packages/services/api/src/modules/schema/providers/models/composite.ts
(2 hunks)packages/services/api/src/modules/schema/providers/models/shared.ts
(2 hunks)packages/services/api/src/modules/schema/providers/models/single.ts
(1 hunks)packages/services/api/src/modules/schema/providers/registry-checks.ts
(1 hunks)packages/services/api/src/modules/schema/providers/schema-manager.ts
(1 hunks)packages/services/api/src/modules/schema/providers/schema-publisher.ts
(3 hunks)packages/services/api/src/modules/schema/resolvers/GraphQLEnumType.ts
(1 hunks)packages/services/api/src/modules/schema/resolvers/GraphQLField.ts
(1 hunks)packages/services/api/src/modules/schema/resolvers/GraphQLInterfaceType.ts
(1 hunks)packages/services/api/src/modules/schema/resolvers/GraphQLObjectType.ts
(1 hunks)packages/services/api/src/modules/schema/resolvers/SchemaExplorer.ts
(7 hunks)packages/services/api/src/modules/schema/resolvers/SchemaMetadata.ts
(1 hunks)packages/services/api/src/modules/schema/resolvers/SchemaVersion.ts
(4 hunks)packages/services/api/src/modules/schema/utils.ts
(2 hunks)packages/services/api/src/modules/shared/providers/storage.ts
(2 hunks)packages/services/api/src/shared/entities.ts
(1 hunks)packages/services/schema/src/lib/metadata-extraction.ts
(1 hunks)packages/services/schema/src/orchestrators.ts
(12 hunks)packages/services/schema/src/types.ts
(1 hunks)packages/services/storage/src/db/types.ts
(1 hunks)packages/services/storage/src/index.ts
(8 hunks)packages/web/app/src/components/target/explorer/super-graph-metadata.tsx
(5 hunks)
🚧 Files skipped from review as they are similar to previous changes (23)
- packages/services/api/package.json
- packages/services/api/src/modules/schema/providers/registry-checks.ts
- packages/services/schema/src/types.ts
- packages/services/api/src/modules/schema/resolvers/GraphQLEnumType.ts
- packages/services/api/src/modules/schema/resolvers/GraphQLInterfaceType.ts
- packages/services/api/src/modules/schema/resolvers/GraphQLField.ts
- packages/services/storage/src/db/types.ts
- packages/services/api/src/modules/schema/providers/models/single.ts
- packages/services/api/src/shared/entities.ts
- packages/migrations/test/2024.07.23T09.36.00.schema-cleanup-tracker.test.ts
- packages/services/api/src/modules/schema/resolvers/GraphQLObjectType.ts
- packages/migrations/src/actions/2025.02.14T00-00-00.schema-versions-metadata.ts
- packages/services/api/src/modules/schema/resolvers/SchemaExplorer.ts
- packages/libraries/federation-link-utils/src/index.ts
- packages/services/api/src/modules/schema/resolvers/SchemaMetadata.ts
- packages/services/api/src/modules/schema/providers/models/shared.ts
- packages/migrations/src/run-pg-migrations.ts
- packages/services/api/src/modules/schema/providers/models/composite.ts
- packages/services/api/src/modules/shared/providers/storage.ts
- packages/services/api/src/modules/schema/providers/schema-manager.ts
- packages/services/api/src/modules/schema/utils.ts
- packages/services/api/src/modules/schema/resolvers/SchemaVersion.ts
- packages/services/api/src/modules/schema/providers/schema-publisher.ts
🧰 Additional context used
📓 Path-based instructions (4)
`packages/services/**`: Microservices written in NodeJS and ...
packages/services/**
: Microservices written in NodeJS and TypeScript. Most of the dirs under this directory are packages and deployed as Docker packages.
Interaction between services is done using tRPC.
We prefer writing code that does input/output validations with Zod.
The directories that ends with-worker
are projects that are built on top of CloudFlare Workers infrastructure and deployed there.
Thecdn-worker
is a special one, it serves a high-available, detached CDN on CloudFlare Workers. This is how our end-users fetches the crucial data from our platform, in a way that does not depend/couple on our main API (served as GraphQL API).
packages/services/api/src/modules/schema/module.graphql.mappers.ts
packages/services/api/src/modules/schema/module.graphql.ts
packages/services/api/src/modules/schema/lib/federation-super-graph.ts
packages/services/schema/src/orchestrators.ts
packages/services/schema/src/lib/metadata-extraction.ts
packages/services/storage/src/index.ts
`packages/libraries/**`: Most of the dirs here are NPM packa...
packages/libraries/**
: Most of the dirs here are NPM packages that provides our customers an integration library, in order to get/fetch data from Hive Console API or Hive CDN.
packages/libraries/federation-link-utils/src/link.ts
packages/libraries/cli/examples/federation.products.graphql
packages/libraries/cli/examples/federation.reviews.graphql
`integration-tests/**`: integration tests for ensuring featu...
integration-tests/**
: integration tests for ensuring features and important flows are running. Usually, changes to thepackages/
directory will affect this. In ideal flow, each PR should include integration tests.
integration-tests/tests/schema/metadata.spec.ts
integration-tests/tests/api/schema/check.spec.ts
integration-tests/tests/api/schema/publish.spec.ts
`packages/libraries/cli/**`: The CLI to interact with Hive C...
packages/libraries/cli/**
: The CLI to interact with Hive Console APIs.
packages/libraries/cli/examples/federation.products.graphql
packages/libraries/cli/examples/federation.reviews.graphql
🪛 Biome (1.9.4)
packages/web/app/src/components/target/explorer/super-graph-metadata.tsx
[error] 26-32: Avoid using unnecessary Fragment.
A fragment is redundant if it contains only one child, or if it is the child of a html element, and is not a keyed fragment.
Unsafe fix: Remove the Fragment
(lint/complexity/noUselessFragments)
⏰ Context from checks skipped due to timeout of 90000ms (10)
- GitHub Check: alpha / npm / snapshot
- GitHub Check: test / unit
- GitHub Check: typescript / typecheck
- GitHub Check: static-analysis / analyze (typescript)
- GitHub Check: storybook-preview / deployment
- GitHub Check: static-analysis / analyze (javascript)
- GitHub Check: build / dockerize (linux/arm64)
- GitHub Check: code-style / eslint-and-prettier
- GitHub Check: build / dockerize (linux/amd64)
- GitHub Check: alpha / cli-artifacts
🔇 Additional comments (33)
packages/services/schema/src/lib/metadata-extraction.ts (1)
77-88
: LGTM! The metadata merging logic is concise and effective.The implementation correctly handles:
- Multiple subgraph metadata records
- Array concatenation for duplicate coordinates
- Undefined checks
integration-tests/tests/schema/metadata.spec.ts (1)
5-7
: Consider using RUN_AGAINST_LOCAL_SERVICES instead.As discussed in previous reviews,
SCHEMA_SERVICE_HOST_OVERRIDE
is not used elsewhere in the codebase. Consider usingRUN_AGAINST_LOCAL_SERVICES
for consistency.packages/web/app/src/components/target/explorer/super-graph-metadata.tsx (1)
106-111
: LGTM! Effective use of useMemo for metadata rendering.The memoization prevents unnecessary re-renders of the Metadata component when only other props change.
packages/libraries/federation-link-utils/src/link.ts (1)
8-17
: LGTM! Clean implementation of Federation 1 support.The function:
- Correctly handles feature extraction
- Safely type casts string values
- Maintains backward compatibility
packages/services/api/src/modules/schema/module.graphql.mappers.ts (4)
133-133
: LGTM! Added metadata support to GraphQLFieldMapper.The metadata field is correctly typed as an optional array of SchemaMetadataMapper, aligning with the PR's objective of adding metadata support.
183-183
: LGTM! Added metadata retrieval to GraphQLObjectTypeMapper.The getFieldMetadata function is correctly typed to return an optional array of SchemaMetadataMapper for a given field name.
197-197
: LGTM! Added metadata retrieval to GraphQLInterfaceTypeMapper.The getFieldMetadata function matches the implementation in GraphQLObjectTypeMapper, maintaining consistency across type definitions.
300-303
: LGTM! Added SchemaMetadataMapper type.The type definition is clean and simple, containing the essential fields for metadata:
- name: string
- content: string
packages/services/api/src/modules/schema/lib/federation-super-graph.ts (1)
19-19
: LGTM! Added metadata mappings to SuperGraphInformation type.The schemaCoordinateMetadataMappings field is correctly typed as a Map with string keys and metadata arrays as values, allowing for efficient metadata lookup by coordinate.
packages/services/schema/src/orchestrators.ts (1)
180-238
: LGTM! Added metadata extraction from subgraphs.The implementation correctly:
- Extracts metadata from subgraphs implementing the Hive metadata spec
- Copies metadata from schema to fields
- Handles metadata directives appropriately
packages/services/api/src/modules/schema/module.graphql.ts (2)
763-763
: LGTM! Added metadata field to SupergraphMetadata type.The metadata field is correctly typed as a nullable array of non-null SchemaMetadata objects.
771-774
: LGTM! Added SchemaMetadata type.The type definition is clean and matches the mapper implementation:
- name: String! (required)
- content: String! (required)
integration-tests/tests/api/schema/check.spec.ts (1)
764-830
: LGTM! Comprehensive test coverage for schema metadata.The test case thoroughly verifies the persistence and retrieval of schema metadata, including author and commit information. This aligns well with the PR's objective of adding metadata support.
packages/services/storage/src/index.ts (4)
711-714
: LGTM! Well-structured metadata model.The
SchemaMetadataModel
is well-defined using Zod for runtime validation, with a clean and flexible structure for storing metadata.
731-732
: LGTM! Schema version model properly extended.The
schemaMetadata
field is correctly integrated into theSchemaVersionModel
with appropriate nullability and type structure.
2399-2400
: LGTM! Schema version creation properly handles metadata.The
schemaMetadata
field is correctly integrated into the schema version creation process, with proper JSON serialization using thejsonify
helper.Also applies to: 2511-2512
5130-5131
: LGTM! SQL field selection properly updated.The
schemaMetadata
field is correctly added to the SQL field selection with proper aliasing.packages/libraries/cli/examples/federation.reviews.graphql (6)
1-8
: Schema Extension and Federation LinkingThe schema extension is configured to use two external link directives. The Apollo Federation link (v2.3) and the Hive-specific link with the
@meta
directive are clearly set up. Ensure that the imported directives (e.g.,@key
,@shareable
,@override
) remain in sync with your current federation implementation and that the URLs reflect the latest specifications.
9-13
: Directive Definition for @metaThe repeatable
@meta
directive is defined properly with the required arguments and allowed locations. This sets a good foundation for adding metadata to schema elements.
14-20
: Product Type ImplementationThe
Product
type now implementsProductItf
and is annotated with the@key
directive (usingid
) and includes additional fields:reviewsCount
,reviewsScore
(with@shareable
and@override(from: "products")
), andreviews
. The use of the override directive clearly indicates data delegation from theproducts
service.
Ensure that downstream services consuming this type are aware of these metadata annotations.
21-27
: ProductItf Interface DefinitionThe
ProductItf
interface succinctly defines the required fields. Its design supports the concrete implementation in theProduct
type. Confirm that any changes in the interface are propagated to all implementing types.
28-31
: Query Type UpdateThe addition of the
review(id: Int!): Review
query provides a clear endpoint for fetching individual reviews. This enhances the API’s schema while remaining consistent with the overall design.
32-36
: Review Type RefinementThe revised
Review
type now strictly contains anid
and abody
, which simplifies the review data structure. This aligns with the updated requirements and improves clarity.packages/libraries/cli/examples/federation.products.graphql (10)
1-8
: Enhanced Schema Extension and Directive LinkingThe schema extension in this file leverages federation by importing additional directives (
@key
,@shareable
,@inaccessible
, and@tag
) as well as the Hive-specific@meta
. The inclusion of@meta(name: "priority", content: "tier1")
at the schema level indicates an explicit priority configuration. Double-check that the inclusion of directives like@inaccessible
and@tag
meets your current data exposure requirements.
9-13
: Consistent Definition of @meta DirectiveThe
@meta
directive is defined consistently here as in the reviews schema. This reuse enhances uniform metadata annotation across your GraphQL schemas.
14-17
: Additional Directives (@myDirective & @hello) DefinitionBoth
@myDirective
(with a parameter) and the parameterless@hello
directive are properly defined forFIELD_DEFINITION
. Their definitions appear straightforward; ensure that their usage is documented so that schema consumers understand their roles.
18-22
: Query Type EnhancementsThe
Query
type now exposes two endpoints:
allProducts
, which is enhanced with a@meta
annotation specifying the owner as "hive-team", andproduct(id: ID!): ProductItf
.These additions provide more ways to query product data while leveraging the new metadata mechanisms.
23-33
: ProductItf Interface with Implemented InheritanceThe
ProductItf
interface now implementsSkuItf
and is decorated with@meta(name: "domain", content: "products")
. The interface’s field definitions—includinghidden
tagged with@inaccessible
andoldField
marked as deprecated—are clear.
It would be beneficial to ensure that client implementations stop relying on the deprecatedoldField
promptly.
35-37
: SkuItf Interface DeclarationThe
SkuItf
interface is minimal and focused, containing the singularsku
field. This promotes reusability when combined withProductItf
.
56-59
: Enum Declaration: ShippingClassThe
ShippingClass
enum is concise, offering two clear shipping options:STANDARD
andEXPRESS
. This simple declaration is appropriate and complete.
61-65
: ProductVariation Type DefinitionThe
ProductVariation
type, with itsid
and an optionalname
, is defined in a straightforward manner. This aligns well with the interface requirements.
66-70
: ProductDimension Type with Shareable DirectiveThe
ProductDimension
type is marked with the@shareable
directive, allowing it to be reused across services if needed. The fieldssize
andweight
are clear and well-defined.
71-75
: User Type with Key and Shareable FieldThe
User
type is annotated with a@key
that uses thetotalProductsCreated
. This ensures that user data can be federated efficiently.
packages/migrations/test/2024.07.23T09.36.00.schema-cleanup-tracker.test.ts
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's have some tests for this implementation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Covered via the integration test. I'm happy to add unit tests too if preferred.
} catch (e: unknown) { | ||
// warn and proceed because metadata isn't considered critical | ||
logger.warn(`Cannot extract metadata from subgraphs because ${e}`); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What could be thrown there?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a remnant of a previous iteration. Ive removed the try/catch. It shouldn't throw.
// @note Although it can differ from the supergraph's, ignore metadata on contracts. | ||
...subgraph, | ||
typeDefs: filteredSubgraph.typeDefs, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is the reason here for ignoring the metadata?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Metadata will only differ between contracts and supergraph for @shared
fields or entities, where one subgraph could impact another.
I think this is an edge case and the additional complexity of calculating and displaying metadata doesn't provide much benefit to the users.
Could there be a use case where people want to specify meta-data but not have it appear within the supergraph? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Overall, I think the implementation looks solid to me. ✅
I would like some more unit or integration tests around the metadata extraction to have a bit more confidence and make sure we are not breaking something unexpectedly.
I want @kamilkisiela to review this as well before merging things, to double check this covers what our clients need.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (3)
integration-tests/tests/schema/metadata.spec.ts (3)
5-7
: Consider removing environment variable override.Based on the previous discussion in the PR, consider removing the
SCHEMA_SERVICE_HOST_OVERRIDE
environment variable and relying solely ongetServiceHost
from the test kit, as it's more consistently used across the codebase.-const host = - process.env['SCHEMA_SERVICE_HOST_OVERRIDE'] || - (await getServiceHost('schema', 3002).then(r => `http://${r}`)); +const host = await getServiceHost('schema', 3002).then(r => `http://${r}`);
73-73
: Improve test description clarity.The current test description "@meta does not need to be in supergraph" could be more specific about what aspect of the metadata is being verified.
- test('@meta does not need to be in supergraph', () => { + test('supergraph should preserve schema structure without including @meta directive content', () => {
167-213
: Consider adding error scenario test cases.While the happy path is well tested, consider adding test cases for error scenarios such as:
- Invalid metadata content
- Conflicting metadata definitions
- Missing required metadata fields
Would you like me to help generate additional test cases for these scenarios?
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
pnpm-lock.yaml
is excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (2)
integration-tests/tests/schema/metadata.spec.ts
(1 hunks)packages/migrations/test/2024.07.23T09.36.00.schema-cleanup-tracker.test.ts
(2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- packages/migrations/test/2024.07.23T09.36.00.schema-cleanup-tracker.test.ts
🧰 Additional context used
📓 Path-based instructions (1)
`integration-tests/**`: integration tests for ensuring featu...
integration-tests/**
: integration tests for ensuring features and important flows are running. Usually, changes to thepackages/
directory will affect this. In ideal flow, each PR should include integration tests.
integration-tests/tests/schema/metadata.spec.ts
⏰ Context from checks skipped due to timeout of 90000ms (11)
- GitHub Check: alpha / npm / snapshot
- GitHub Check: test / unit
- GitHub Check: static-analysis / analyze (typescript)
- GitHub Check: typescript / typecheck
- GitHub Check: storybook-preview / deployment
- GitHub Check: static-analysis / analyze (javascript)
- GitHub Check: code-style / eslint-and-prettier
- GitHub Check: build / dockerize (linux/arm64)
- GitHub Check: build / dockerize (linux/amd64)
- GitHub Check: alpha / cli-artifacts
- GitHub Check: Mend Security Check
🔇 Additional comments (1)
integration-tests/tests/schema/metadata.spec.ts (1)
26-28
: Ensure consistent federation versions across schemas.The schemas are using different federation versions (v2.3 vs v2.1). While this might work, it's better to maintain consistency to prevent potential compatibility issues.
Consider using the same federation version in both schemas:
- @link(url: "https://specs.apollo.dev/federation/v2.1") + @link(url: "https://specs.apollo.dev/federation/v2.3")Also applies to: 51-53
I've updated the tests to cover more cases and removed the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (1)
packages/services/schema/src/orchestrators.ts (1)
172-238
: Consider extracting nested mapping functions for better maintainability.The metadata application logic is well-implemented but could be more maintainable.
Consider these improvements:
+const HIVE_METADATA_SPEC = 'https://specs.graphql-hive.com/hive'; +const HIVE_METADATA_VERSION = 'v1.0'; + +function applyMetadataToSubgraph(subgraph: { typeDefs: DocumentNode; name: string; url?: string }) { + const { matchesImplementation, resolveImportName } = extractLinkImplementations(subgraph.typeDefs); + if (!matchesImplementation(HIVE_METADATA_SPEC, HIVE_METADATA_VERSION)) { + return subgraph; + } + + const metaDirectiveName = resolveImportName(HIVE_METADATA_SPEC, '@meta'); + return { + ...subgraph, + typeDefs: applyMetadataToFields(subgraph.typeDefs, metaDirectiveName), + }; +} const subgraphs = schemas .map(schema => ({ typeDefs: trimDescriptions(parse(schema.raw)), name: schema.source, url: 'url' in schema && typeof schema.url === 'string' ? schema.url : undefined, })) - .map(subgraph => { - const { matchesImplementation, resolveImportName } = extractLinkImplementations( - subgraph.typeDefs, - ); - if (matchesImplementation('https://specs.graphql-hive.com/hive', 'v1.0')) { - // ... rest of the implementation - } - return subgraph; - }); + .map(applyMetadataToSubgraph);
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
packages/libraries/federation-link-utils/src/link.ts
(2 hunks)packages/services/schema/src/orchestrators.ts
(12 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- packages/libraries/federation-link-utils/src/link.ts
🧰 Additional context used
📓 Path-based instructions (1)
`packages/services/**`: Microservices written in NodeJS and ...
packages/services/**
: Microservices written in NodeJS and TypeScript. Most of the dirs under this directory are packages and deployed as Docker packages.
Interaction between services is done using tRPC.
We prefer writing code that does input/output validations with Zod.
The directories that ends with-worker
are projects that are built on top of CloudFlare Workers infrastructure and deployed there.
Thecdn-worker
is a special one, it serves a high-available, detached CDN on CloudFlare Workers. This is how our end-users fetches the crucial data from our platform, in a way that does not depend/couple on our main API (served as GraphQL API).
packages/services/schema/src/orchestrators.ts
⏰ Context from checks skipped due to timeout of 90000ms (11)
- GitHub Check: alpha / npm / snapshot
- GitHub Check: test / unit
- GitHub Check: typescript / typecheck
- GitHub Check: storybook-preview / deployment
- GitHub Check: static-analysis / analyze (typescript)
- GitHub Check: static-analysis / analyze (javascript)
- GitHub Check: code-style / eslint-and-prettier
- GitHub Check: test / db-migrations
- GitHub Check: build / dockerize (linux/arm64)
- GitHub Check: build / dockerize (linux/amd64)
- GitHub Check: alpha / cli-artifacts
🔇 Additional comments (4)
packages/services/schema/src/orchestrators.ts (4)
2-2
: LGTM! Well-structured type imports and definitions.The new imports and type definitions are properly organized to support the metadata functionality. The
schemaMetadata
type is correctly defined as a nullable record mapping strings to arrays of metadata objects.Also applies to: 37-37, 167-167
281-282
: LGTM! Proper metadata merging implementation.The metadata extraction and merging from subgraphs is implemented correctly using the imported utilities.
345-347
: Verify the impact of ignoring metadata on contracts.The code ignores metadata on contracts as noted in the comment. Based on the PR comments, this is intentional as metadata will only differ between contracts and supergraph for
@shared
fields or entities.Please confirm if there are any edge cases where contract-specific metadata would be valuable for users.
427-442
: LGTM! Comprehensive error handling.The error handling is thorough and consistently sets
schemaMetadata
to null in error cases, including cache timeout errors.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (3)
integration-tests/tests/schema/metadata.spec.ts (3)
18-18
: Enhance test suite description.The current description is too generic. Consider making it more specific to better reflect what aspects of metadata processing are being tested.
-describe('schema service can process metadata', async () => { +describe('schema service - metadata processing and federation composition', async () => {
73-165
: Consider enhancing supergraph validation test.While snapshot testing is useful, consider adding specific assertions for critical aspects of the supergraph composition. This would make the test more maintainable and failures more obvious.
test('validates supergraph composition and @meta directive handling', () => { // Keep snapshot for full validation expect(result.supergraph).toMatchInlineSnapshot(`...`); // Add specific assertions expect(result.supergraph).toContain('@link(url: "https://specs.graphql-hive.com/hive/v1.0"'); expect(result.supergraph).not.toContain('directive @meta'); });
167-212
: Enhance metadata validation test with specific assertions.While the snapshot test is comprehensive, consider adding specific assertions to validate critical metadata relationships and inheritance. This would make the test more resilient to changes and failures more descriptive.
test('validates metadata inheritance and composition from schema, type, and field levels', () => { // Keep snapshot for full validation expect(result.schemaMetadata).toMatchInlineSnapshot(`...`); // Add specific assertions const userNameMetadata = result.schemaMetadata['User.name']; expect(userNameMetadata).toHaveLength(3); // Field, type, and schema level expect(userNameMetadata).toContainEqual({ name: 'field', content: 'User.name' }); expect(userNameMetadata).toContainEqual({ name: 'type', content: 'user' }); });
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
integration-tests/tests/schema/metadata.spec.ts
(1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
`integration-tests/**`: integration tests for ensuring featu...
integration-tests/**
: integration tests for ensuring features and important flows are running. Usually, changes to thepackages/
directory will affect this. In ideal flow, each PR should include integration tests.
integration-tests/tests/schema/metadata.spec.ts
⏰ Context from checks skipped due to timeout of 90000ms (10)
- GitHub Check: alpha / npm / snapshot
- GitHub Check: test / unit
- GitHub Check: static-analysis / analyze (typescript)
- GitHub Check: typescript / typecheck
- GitHub Check: static-analysis / analyze (javascript)
- GitHub Check: storybook-preview / deployment
- GitHub Check: build / dockerize (linux/arm64)
- GitHub Check: build / dockerize (linux/amd64)
- GitHub Check: code-style / eslint-and-prettier
- GitHub Check: alpha / cli-artifacts
🔇 Additional comments (1)
integration-tests/tests/schema/metadata.spec.ts (1)
5-7
: Consider standardizing service host configuration.Based on the previous discussion,
RUN_AGAINST_LOCAL_SERVICES
might be more practical thanSCHEMA_SERVICE_HOST_OVERRIDE
. Consider removing the environment variable condition and using the standard approach for consistency.-const host = - process.env['SCHEMA_SERVICE_HOST_OVERRIDE'] || - (await getServiceHost('schema', 3002).then(r => `http://${r}`)); +const host = await getServiceHost('schema', 3002).then(r => `http://${r}`);
I will review the code tomorrow, but in terms of UI, I think we could pass the metadata to the subgraph badge. If at least two subgraphs share a field and those team add metadata (like slack channel or just the name of the team), a dedicated icon for metadata will fall short. It won't be able to display info about two teams. If we merge it into the subgraph badge, it connects nicely. |
That's an interesting point. I like the idea of linking it to the subgraph, and I agree that fewer icons the better. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🧹 Nitpick comments (4)
packages/services/schema/src/orchestrators.ts (1)
173-239
: Evaluate metadata injection logic in subgraphs.
The block introduces logic to:
- Identify subgraphs implementing the Hive metadata spec.
- Copy schema, type, or interface-level directives to their field nodes for easier downstream usage.
Potential edge case: Input object fields or union types are not addressed here. If metadata is needed on those, you may need additional handling. Otherwise, the approach to replicating metadata at the field level is well-organized for composition.
packages/services/schema/src/lib/metadata-extraction.ts (1)
17-80
: ImplementingextractMetadata
function.
The logic systematically:
- Resolves the
@meta
directive name.- Visits object and interface fields to collect metadata.
- Associates the metadata with each field’s coordinate.
Consider tests for nested or edge cases (e.g., hidden or non-standard fields). The existing integration tests might suffice, but dedicated unit tests can improve clarity and maintainability.
packages/web/app/src/components/target/explorer/super-graph-metadata.tsx (2)
24-36
: Simplify fragment usage and improve accessibility.The tooltip implementation can be improved:
- The fragment wrapping the metadata map is unnecessary.
- Consider adding
aria-label
for better accessibility.Apply this diff:
- content={ - <> - {props.supergraphMetadata.map((m, i) => ( - <div key={i}> - <span className="font-bold">{m.name}:</span> {m.content} - </div> - ))} - </> - } + content={props.supergraphMetadata.map((m, i) => ( + <div key={i}> + <span className="font-bold">{m.name}:</span> {m.content} + </div> + ))} + aria-label="Metadata information"🧰 Tools
🪛 Biome (1.9.4)
[error] 26-32: Avoid using unnecessary Fragment.
A fragment is redundant if it contains only one child, or if it is the child of a html element, and is not a keyed fragment.
Unsafe fix: Remove the Fragment(lint/complexity/noUselessFragments)
194-194
: Consider adjusting tooltip delay duration.The 100ms delay might be too short for a good user experience. Consider increasing it to allow users to intentionally hover over elements.
- <TooltipProvider delayDuration={100}> + <TooltipProvider delayDuration={300}>
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (14)
integration-tests/tests/schema/metadata.spec.ts
(1 hunks)packages/services/api/src/modules/schema/lib/federation-super-graph.ts
(12 hunks)packages/services/api/src/modules/schema/module.graphql.mappers.ts
(4 hunks)packages/services/api/src/modules/schema/module.graphql.ts
(1 hunks)packages/services/api/src/modules/schema/providers/schema-manager.ts
(1 hunks)packages/services/api/src/modules/schema/resolvers/GraphQLField.ts
(1 hunks)packages/services/api/src/modules/schema/resolvers/GraphQLObjectType.ts
(1 hunks)packages/services/api/src/modules/schema/resolvers/SchemaVersion.ts
(4 hunks)packages/services/api/src/modules/shared/providers/storage.ts
(2 hunks)packages/services/schema/src/lib/metadata-extraction.ts
(1 hunks)packages/services/schema/src/orchestrators.ts
(12 hunks)packages/services/schema/src/types.ts
(2 hunks)packages/services/storage/src/index.ts
(8 hunks)packages/web/app/src/components/target/explorer/super-graph-metadata.tsx
(6 hunks)
🚧 Files skipped from review as they are similar to previous changes (6)
- packages/services/api/src/modules/schema/resolvers/GraphQLObjectType.ts
- packages/services/api/src/modules/schema/resolvers/GraphQLField.ts
- integration-tests/tests/schema/metadata.spec.ts
- packages/services/api/src/modules/schema/providers/schema-manager.ts
- packages/services/api/src/modules/schema/resolvers/SchemaVersion.ts
- packages/services/api/src/modules/shared/providers/storage.ts
🧰 Additional context used
📓 Path-based instructions (1)
`packages/services/**`: Microservices written in NodeJS and ...
packages/services/**
: Microservices written in NodeJS and TypeScript. Most of the dirs under this directory are packages and deployed as Docker packages.
Interaction between services is done using tRPC.
We prefer writing code that does input/output validations with Zod.
The directories that ends with-worker
are projects that are built on top of CloudFlare Workers infrastructure and deployed there.
Thecdn-worker
is a special one, it serves a high-available, detached CDN on CloudFlare Workers. This is how our end-users fetches the crucial data from our platform, in a way that does not depend/couple on our main API (served as GraphQL API).
packages/services/schema/src/types.ts
packages/services/schema/src/lib/metadata-extraction.ts
packages/services/api/src/modules/schema/module.graphql.mappers.ts
packages/services/api/src/modules/schema/module.graphql.ts
packages/services/api/src/modules/schema/lib/federation-super-graph.ts
packages/services/schema/src/orchestrators.ts
packages/services/storage/src/index.ts
🪛 Biome (1.9.4)
packages/web/app/src/components/target/explorer/super-graph-metadata.tsx
[error] 26-32: Avoid using unnecessary Fragment.
A fragment is redundant if it contains only one child, or if it is the child of a html element, and is not a keyed fragment.
Unsafe fix: Remove the Fragment
(lint/complexity/noUselessFragments)
[error] 78-78: Missing key property for this element in iterable.
The order of the items may change, and having a key can help React identify which item was moved.
Check the React documentation.
(lint/correctness/useJsxKeyInIterable)
[error] 79-79: Missing key property for this element in iterable.
The order of the items may change, and having a key can help React identify which item was moved.
Check the React documentation.
(lint/correctness/useJsxKeyInIterable)
⏰ Context from checks skipped due to timeout of 90000ms (2)
- GitHub Check: build / dockerize (linux/arm64)
- GitHub Check: build / dockerize (linux/amd64)
🔇 Additional comments (26)
packages/services/storage/src/index.ts (4)
711-715
: LGTM! Well-structured schema metadata model.The
SchemaMetadataModel
is well-defined with appropriate field types and constraints:
name
: Required string for metadata identifiercontent
: Required string for metadata contentsource
: Optional string with null default for metadata origin
732-732
: LGTM! Proper integration of schema metadata into version model.The
schemaMetadata
field is correctly integrated intoSchemaVersionModel
with appropriate nullability and type structure.
878-878
: LGTM! Proper handling of schema metadata in version creation.The
insertSchemaVersion
function correctly:
- Accepts schema metadata as an optional parameter
- Properly serializes it to JSON for storage
- Maintains type safety through the model
Also applies to: 925-926
5132-5132
: LGTM! SQL field mapping for schema metadata.The schema version SQL fields correctly include the
schema_metadata
column with proper field aliasing.packages/services/schema/src/orchestrators.ts (12)
2-2
: No concerns with new type imports.
The added imports fromgraphql
are used consistently within the file.
37-37
: Importing metadata extraction utilities.
These imports seem correct and well-scoped to the new metadata extraction logic.
42-42
: Importing newly introducedMetadata
type.
This ensures strong typing of metadata objects throughout the orchestrator.
168-168
: AddedschemaMetadata
to cached result.
The addition ofschemaMetadata
is consistent with the new metadata approach, allowing the orchestration cache to store structured metadata.
282-285
: Extracting metadata for each subgraph.
This extraction step looks correct. It might be worth verifying if subgraphs without any@meta
directives gracefully return empty mappings.
294-294
: Merging metadata usingObject.fromEntries()
.
This effectively converts the merged metadataMap
to a serializable structure. No issues found.
300-301
: Default assignment ofschemaMetadata: null
in failure scenarios.
This cleanly indicates that no metadata is available.
347-347
: Comment clarifying metadata is ignored for contracts.
This explicit note helps maintainers understand the decision to avoid copying metadata to contract-based compositions.
349-349
: Consistent approach for contract typeDefs.
No issues in continuing to rely on the compositional logic without including metadata.
388-388
: ResettingschemaMetadata
to null on network errors.
This is consistent with marking it unavailable when an error occurs.
427-427
: SurfaceschemaMetadata
in the orchestrator output.
This ensures that downstream processes can consume the entire metadata.
444-444
: Fallback to null in error handling.
Providingnull
remains consistent with other early bail-out scenarios.packages/services/schema/src/types.ts (2)
19-20
: IntroducingschemaMetadata
in output.
Using aRecord
is a convenient approach for serialized data; it keeps the structure simple when returning from orchestrations.
41-48
: Definition of theMetadata
type.
This structured type cleanly captures name, content, and source, aligning with the new subgraph-level metadata system.packages/services/schema/src/lib/metadata-extraction.ts (4)
1-9
: Imports for handling directives and node visitors.
These imports support the metadata extraction logic. No problems identified.
10-10
: Link utilities import.
ImportingextractLinkImplementations
is essential for resolving custom directive import names.
12-16
: NewSubgraphMetadata
type.
Storing an array of metadata objects per coordinate is a clear approach.
82-93
: Merging metadata across subgraphs.
The function merges entries by schema coordinate. Consider verifying that duplicate or conflicting entries merge as intended (e.g., same coordinate, differentcontent
).packages/services/api/src/modules/schema/module.graphql.ts (1)
771-784
: Well-structured schema definition for metadata!The
SchemaMetadata
type is well-defined with clear field descriptions and appropriate nullability constraints. The structure allows for flexible metadata storage with source tracking.packages/services/api/src/modules/schema/module.graphql.mappers.ts (1)
300-304
: Clean and type-safe mapper definition!The
SchemaMetadataMapper
type correctly mirrors the GraphQL schema definition, ensuring type safety throughout the application.packages/services/api/src/modules/schema/lib/federation-super-graph.ts (2)
16-24
: Well-structured metadata mapping in SuperGraphInformation!The metadata mapping structure is well-designed, using a Map for efficient lookups and maintaining consistency with the schema definition.
38-47
: Improved maintainability with directive name resolution!Good refactoring to use
extractLinkImplementations
for resolving directive names instead of hardcoding them. This makes the code more maintainable and less prone to errors.
packages/web/app/src/components/target/explorer/super-graph-metadata.tsx
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (1)
packages/services/api/src/modules/schema/lib/federation-super-graph.ts (1)
16-24
: Consider implementing metadata population.While the type system is prepared for metadata with
schemaCoordinateMetadataMappings
, the implementation doesn't populate this data. Consider:
- Extending
extractSuperGraphInformation
to return both mappings- Implementing metadata extraction logic similar to service mappings
- Adding tests for metadata extraction
This would complete the metadata support outlined in the PR objectives.
Also applies to: 32-32
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (8)
packages/services/api/src/modules/schema/lib/federation-super-graph.ts
(12 hunks)packages/services/api/src/modules/schema/module.graphql.mappers.ts
(4 hunks)packages/services/api/src/modules/schema/providers/models/shared.ts
(2 hunks)packages/services/api/src/modules/schema/providers/schema-manager.ts
(1 hunks)packages/services/api/src/modules/schema/resolvers/GraphQLInterfaceType.ts
(1 hunks)packages/services/api/src/modules/shared/providers/storage.ts
(2 hunks)packages/services/api/src/shared/entities.ts
(1 hunks)packages/services/storage/src/index.ts
(8 hunks)
🚧 Files skipped from review as they are similar to previous changes (5)
- packages/services/api/src/modules/schema/resolvers/GraphQLInterfaceType.ts
- packages/services/api/src/modules/schema/providers/models/shared.ts
- packages/services/api/src/modules/schema/providers/schema-manager.ts
- packages/services/api/src/modules/shared/providers/storage.ts
- packages/services/api/src/shared/entities.ts
🧰 Additional context used
📓 Path-based instructions (1)
`packages/services/**`: Microservices written in NodeJS and ...
packages/services/**
: Microservices written in NodeJS and TypeScript. Most of the dirs under this directory are packages and deployed as Docker packages.
Interaction between services is done using tRPC.
We prefer writing code that does input/output validations with Zod.
The directories that ends with-worker
are projects that are built on top of CloudFlare Workers infrastructure and deployed there.
Thecdn-worker
is a special one, it serves a high-available, detached CDN on CloudFlare Workers. This is how our end-users fetches the crucial data from our platform, in a way that does not depend/couple on our main API (served as GraphQL API).
packages/services/storage/src/index.ts
packages/services/api/src/modules/schema/module.graphql.mappers.ts
packages/services/api/src/modules/schema/lib/federation-super-graph.ts
⏰ Context from checks skipped due to timeout of 90000ms (10)
- GitHub Check: alpha / npm / snapshot
- GitHub Check: test / unit
- GitHub Check: typescript / typecheck
- GitHub Check: static-analysis / analyze (typescript)
- GitHub Check: storybook-preview / deployment
- GitHub Check: static-analysis / analyze (javascript)
- GitHub Check: build / dockerize (linux/arm64)
- GitHub Check: build / dockerize (linux/amd64)
- GitHub Check: code-style / eslint-and-prettier
- GitHub Check: alpha / cli-artifacts
🔇 Additional comments (13)
packages/services/storage/src/index.ts (4)
711-715
: LGTM! Well-structured schema metadata model.The
SchemaMetadataModel
is well-defined with appropriate types and constraints:
name
andcontent
are required stringssource
is an optional nullable string with a default value of null
732-732
: LGTM! Proper integration with SchemaVersionModel.The
schemaMetadata
field is correctly integrated into theSchemaVersionModel
with appropriate typing as a nullable record mapping strings to arrays ofSchemaMetadataModel
.
878-881
: LGTM! Type-safe argument handling in insertSchemaVersion.The
schemaMetadata
argument is properly typed in theinsertSchemaVersion
function parameters, maintaining type safety and consistency with the model definition.
2399-2399
: LGTM! Proper SQL integration for schema metadata.The schema metadata is correctly handled in SQL operations:
- Added to the INSERT statement columns
- Properly jsonified using the helper function
- Included in the RETURNING clause
Also applies to: 2408-2409, 2928-2929
packages/services/api/src/modules/schema/module.graphql.mappers.ts (4)
133-133
: LGTM! Well-structured metadata property.The
schemaMetadata
property is correctly typed as a nullable array of metadata entries, allowing fields to have multiple metadata items or none.
183-183
: LGTM! Well-defined metadata accessor.The
getFieldMetadata
method provides a clean interface for retrieving field-specific metadata in object types.
197-197
: LGTM! Consistent metadata access across types.The
getFieldMetadata
method maintains a consistent interface between object and interface types.
300-304
: LGTM! Well-structured metadata type.The
SchemaMetadataMapper
type effectively captures metadata with:
- A descriptive name
- Content for the metadata value
- Optional source field to track metadata origin
This aligns well with the PR's goal of supporting metadata visualization and the feedback about tracking metadata sources.
packages/services/api/src/modules/schema/lib/federation-super-graph.ts (5)
19-23
: LGTM! Well-structured metadata type definition.The new
schemaCoordinateMetadataMappings
type is well-defined and aligns with the PR's objective of supporting metadata visualization in the Hive UI.
38-46
: LGTM! Improved directive resolution.The use of
extractLinkImplementations
to dynamically resolve directive names is a more maintainable approach than hardcoding them.
48-56
: LGTM! Well-implemented helper function.The
getJoinGraphEnumServiceName
function properly handles edge cases and uses the dynamically resolved directive name.
88-88
: LGTM! Consistent directive name updates.The hardcoded directive names have been consistently replaced with dynamically resolved ones throughout the code, improving maintainability while preserving the core federation logic.
Also applies to: 157-157, 168-168, 193-193, 203-203, 217-217, 243-243
32-32
:❓ Verification inconclusive
Verify the return type change impact.
The function now only returns
schemaCoordinateServicesMappings
despiteSuperGraphInformation
type includingschemaCoordinateMetadataMappings
. This might indicate missing metadata population logic.
🏁 Script executed:
#!/bin/bash # Search for any other files that might be populating the metadata mappings rg -l "schemaCoordinateMetadataMappings" --type tsLength of output: 364
Clarify Metadata Population in SuperGraphInformation
The function now returns only
schemaCoordinateServicesMappings
while the completeSuperGraphInformation
type also includesschemaCoordinateMetadataMappings
. Please verify whether this change is intentional—that is, if metadata mappings are now populated elsewhere (e.g., via logic in files likepackages/services/schema/src/lib/metadata-extraction.ts
orpackages/services/api/src/modules/schema/utils.ts
)—or if additional logic is needed here to extract and include them. If this omission is deliberate, consider documenting the rationale to avoid confusion.
…tadata.tsx Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (3)
packages/web/app/src/components/target/explorer/super-graph-metadata.tsx (3)
19-38
: Define proper TypeScript types for metadata.Consider extracting the metadata type to improve type safety and reusability across components.
+type MetadataItem = { + name: string; + content: string; +}; + -function Metadata(props: { supergraphMetadata: Array<{ name: string; content: string }> }) { +function Metadata(props: { supergraphMetadata: Array<MetadataItem> }) {Also, the fragment wrapper can be simplified:
- <> {props.supergraphMetadata.map((m, i) => ( <div key={i}> <span className="font-bold">{m.name}:</span> {m.content} </div> ))} - </>🧰 Tools
🪛 Biome (1.9.4)
[error] 26-32: Avoid using unnecessary Fragment.
A fragment is redundant if it contains only one child, or if it is the child of a html element, and is not a keyed fragment.
Unsafe fix: Remove the Fragment(lint/complexity/noUselessFragments)
128-185
: Reduce code duplication in service name mapping.The mapping logic for service names is duplicated. Consider extracting it into a reusable function.
+ const renderSubgraphChip = (serviceName: string, index: number, showTooltip: boolean) => { + const meta = supergraphMetadata.metadata?.filter(({ source }) => source === serviceName); + return ( + <SubgraphChip + organizationSlug={props.organizationSlug} + projectSlug={props.projectSlug} + targetSlug={props.targetSlug} + key={`${serviceName}-${index}`} + text={serviceName} + tooltip={showTooltip} + metadata={meta} + /> + ); + }; const items = useMemo(() => { if (supergraphMetadata.ownedByServiceNames == null) { return null; } if (supergraphMetadata.ownedByServiceNames.length <= previewThreshold) { return [ - supergraphMetadata.ownedByServiceNames.map((serviceName, index) => { - const meta = supergraphMetadata.metadata?.filter(({ source }) => source === serviceName); - return ( - <SubgraphChip - organizationSlug={props.organizationSlug} - projectSlug={props.projectSlug} - targetSlug={props.targetSlug} - key={`${serviceName}-${index}`} - text={serviceName} - tooltip - metadata={meta} - /> - ); - }), + supergraphMetadata.ownedByServiceNames.map((serviceName, index) => + renderSubgraphChip(serviceName, index, true) + ), null, ] as const; } return [ supergraphMetadata.ownedByServiceNames .slice(0, previewThreshold) - .map((serviceName, index) => { - const meta = supergraphMetadata.metadata?.filter(({ source }) => source === serviceName); - return ( - <SubgraphChip - organizationSlug={props.organizationSlug} - projectSlug={props.projectSlug} - targetSlug={props.targetSlug} - key={`${serviceName}-${index}`} - text={serviceName} - tooltip - metadata={meta} - /> - ); - }), + .map((serviceName, index) => renderSubgraphChip(serviceName, index, true)), - supergraphMetadata.ownedByServiceNames.map((serviceName, index) => { - const meta = supergraphMetadata.metadata?.filter(({ source }) => source === serviceName); - return ( - <SubgraphChip - organizationSlug={props.organizationSlug} - projectSlug={props.projectSlug} - targetSlug={props.targetSlug} - key={`${serviceName}-${index}`} - text={serviceName} - tooltip={false} - metadata={meta} - /> - ); - }), + supergraphMetadata.ownedByServiceNames.map((serviceName, index) => + renderSubgraphChip(serviceName, index, false) + ), ] as const; }, [supergraphMetadata.ownedByServiceNames]);
120-126
: Consider memoizing metadata filter function.The metadata filtering function could be memoized separately to prevent unnecessary recalculations.
+ const filterNonSubgraphMetadata = useCallback( + (metadata?: Array<{ source?: string }>) => metadata?.filter(m => !m.source), + [] + ); const meta = useMemo(() => { - const nonSubgraphMeta = supergraphMetadata.metadata?.filter(m => !m.source); + const nonSubgraphMeta = filterNonSubgraphMetadata(supergraphMetadata.metadata); if (!nonSubgraphMeta?.length) { return null; } return <Metadata supergraphMetadata={nonSubgraphMeta} />; }, [supergraphMetadata.metadata]);
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
pnpm-lock.yaml
is excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (2)
packages/services/api/package.json
(1 hunks)packages/web/app/src/components/target/explorer/super-graph-metadata.tsx
(6 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- packages/services/api/package.json
🧰 Additional context used
🪛 Biome (1.9.4)
packages/web/app/src/components/target/explorer/super-graph-metadata.tsx
[error] 26-32: Avoid using unnecessary Fragment.
A fragment is redundant if it contains only one child, or if it is the child of a html element, and is not a keyed fragment.
Unsafe fix: Remove the Fragment
(lint/complexity/noUselessFragments)
⏰ Context from checks skipped due to timeout of 90000ms (10)
- GitHub Check: alpha / npm / snapshot
- GitHub Check: test / unit
- GitHub Check: typescript / typecheck
- GitHub Check: static-analysis / analyze (typescript)
- GitHub Check: storybook-preview / deployment
- GitHub Check: static-analysis / analyze (javascript)
- GitHub Check: build / dockerize (linux/arm64)
- GitHub Check: build / dockerize (linux/amd64)
- GitHub Check: code-style / eslint-and-prettier
- GitHub Check: alpha / cli-artifacts
🔇 Additional comments (2)
packages/web/app/src/components/target/explorer/super-graph-metadata.tsx (2)
40-88
: LGTM! Clean implementation of metadata support.The changes to
SubgraphChip
are well-implemented:
- Proper type safety with optional metadata
- Correct key handling in the map function
- Clear visual indicator (*) for items with metadata
90-99
: LGTM! Clear and concise fragment definition.The GraphQL fragment is well-structured and includes all necessary fields for metadata handling.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (4)
packages/web/app/src/components/target/explorer/super-graph-metadata.tsx (4)
19-38
: Improve type safety and remove unnecessary Fragment.Consider these improvements:
- Define a proper type for the metadata item.
- Remove the unnecessary Fragment wrapper.
Apply this diff:
+type MetadataItem = { + name: string; + content: string; +}; -function Metadata(props: { supergraphMetadata: Array<{ name: string; content: string }> }) { +function Metadata(props: { supergraphMetadata: Array<MetadataItem> }) { if (!props.supergraphMetadata.length) { return null; } return ( <Tooltip content={ - <> {props.supergraphMetadata.map((m, i) => ( <div key={i}> <span className="font-bold">{m.name}:</span> {m.content} </div> ))} - </> } > <MetadataIcon className="my-[5px] cursor-pointer text-white" /> </Tooltip> ); }🧰 Tools
🪛 Biome (1.9.4)
[error] 26-32: Avoid using unnecessary Fragment.
A fragment is redundant if it contains only one child, or if it is the child of a html element, and is not a keyed fragment.
Unsafe fix: Remove the Fragment(lint/complexity/noUselessFragments)
76-81
: Improve null handling and simplify Fragment usage.The current implementation has potential issues:
- The null check could be more explicit.
- The Fragment usage could be simplified to a div.
Apply this diff:
- {props.metadata?.map((m, index) => ( - <Fragment key={`${index}`}> - <br /> - <span className="font-bold">{m.content}</span> {m.name} - </Fragment> - )) ?? null} + {props.metadata && props.metadata.length > 0 && ( + <div className="mt-2"> + {props.metadata.map((m, index) => ( + <div key={`metadata-${index}`}> + <span className="font-bold">{m.content}</span> {m.name} + </div> + ))} + </div> + )}
135-169
: Reduce code duplication in mapping functions.The mapping logic is duplicated between the preview and full list rendering. This could be extracted into a reusable function.
Apply this diff:
+ const renderSubgraphChip = useMemo(() => (serviceName: string, index: number, showTooltip = true) => { + const meta = supergraphMetadata.metadata?.filter(({ source }) => source === serviceName); + return ( + <SubgraphChip + organizationSlug={props.organizationSlug} + projectSlug={props.projectSlug} + targetSlug={props.targetSlug} + key={`${serviceName}-${index}`} + text={serviceName} + tooltip={showTooltip} + metadata={meta} + /> + ); + }, [props.organizationSlug, props.projectSlug, props.targetSlug, supergraphMetadata.metadata]); const items = useMemo(() => { if (supergraphMetadata.ownedByServiceNames == null) { return null; } if (supergraphMetadata.ownedByServiceNames.length <= previewThreshold) { return [ - supergraphMetadata.ownedByServiceNames.map((serviceName, index) => { - const meta = supergraphMetadata.metadata?.filter(({ source }) => source === serviceName); - return ( - <SubgraphChip - organizationSlug={props.organizationSlug} - projectSlug={props.projectSlug} - targetSlug={props.targetSlug} - key={`${serviceName}-${index}`} - text={serviceName} - tooltip - metadata={meta} - /> - ); - }), + supergraphMetadata.ownedByServiceNames.map((serviceName, index) => + renderSubgraphChip(serviceName, index) + ), null, ] as const; } return [ supergraphMetadata.ownedByServiceNames .slice(0, previewThreshold) - .map((serviceName, index) => { - const meta = supergraphMetadata.metadata?.filter(({ source }) => source === serviceName); - return ( - <SubgraphChip - organizationSlug={props.organizationSlug} - projectSlug={props.projectSlug} - targetSlug={props.targetSlug} - key={`${serviceName}-${index}`} - text={serviceName} - tooltip - metadata={meta} - /> - ); - }), + .map((serviceName, index) => renderSubgraphChip(serviceName, index)),
194-194
: Consider documenting the delayDuration value.The
delayDuration
prop is set to 100ms without explanation. Consider adding a comment explaining why this specific value was chosen.- <TooltipProvider delayDuration={100}> + {/* 100ms delay provides a good balance between responsiveness and preventing accidental triggers */} + <TooltipProvider delayDuration={100}>
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
packages/web/app/src/components/target/explorer/super-graph-metadata.tsx
(6 hunks)
🧰 Additional context used
🪛 Biome (1.9.4)
packages/web/app/src/components/target/explorer/super-graph-metadata.tsx
[error] 26-32: Avoid using unnecessary Fragment.
A fragment is redundant if it contains only one child, or if it is the child of a html element, and is not a keyed fragment.
Unsafe fix: Remove the Fragment
(lint/complexity/noUselessFragments)
⏰ Context from checks skipped due to timeout of 90000ms (10)
- GitHub Check: alpha / npm / snapshot
- GitHub Check: test / unit
- GitHub Check: typescript / typecheck
- GitHub Check: static-analysis / analyze (typescript)
- GitHub Check: storybook-preview / deployment
- GitHub Check: static-analysis / analyze (javascript)
- GitHub Check: build / dockerize (linux/arm64)
- GitHub Check: code-style / eslint-and-prettier
- GitHub Check: build / dockerize (linux/amd64)
- GitHub Check: alpha / cli-artifacts
🔇 Additional comments (1)
packages/web/app/src/components/target/explorer/super-graph-metadata.tsx (1)
56-57
: Address the TODO comment about routing.There's an unresolved TODO comment about routing. Please clarify if this needs to be addressed in this PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (4)
packages/web/app/src/components/target/explorer/super-graph-metadata.tsx (4)
18-37
: Define TypeScript interface for metadata props.Consider defining a reusable interface for the metadata structure to improve type safety and reusability.
+interface MetadataItem { + name: string; + content: string; +} -function Metadata(props: { supergraphMetadata: Array<{ name: string; content: string }> }) { +function Metadata(props: { supergraphMetadata: Array<MetadataItem> }) {Also, consider using a more stable key for the mapped elements:
- {props.supergraphMetadata.map((m, i) => ( - <div key={i}> + {props.supergraphMetadata.map((m) => ( + <div key={`${m.name}-${m.content}`}>🧰 Tools
🪛 Biome (1.9.4)
[error] 25-31: Avoid using unnecessary Fragment.
A fragment is redundant if it contains only one child, or if it is the child of a html element, and is not a keyed fragment.
Unsafe fix: Remove the Fragment(lint/complexity/noUselessFragments)
25-31
: Remove unnecessary Fragment wrapper.The Fragment wrapper is redundant as it contains only one child element.
- <> {props.supergraphMetadata.map((m, i) => ( <div key={i}> <span className="font-bold">{m.name}:</span> {m.content} </div> ))} - </>🧰 Tools
🪛 Biome (1.9.4)
[error] 25-31: Avoid using unnecessary Fragment.
A fragment is redundant if it contains only one child, or if it is the child of a html element, and is not a keyed fragment.
Unsafe fix: Remove the Fragment(lint/complexity/noUselessFragments)
201-210
: Add ARIA attributes for better accessibility.The scrollable content area should have appropriate ARIA attributes for better screen reader support.
- <div className="absolute inset-0 size-[250px] overflow-y-scroll py-2"> + <div + className="absolute inset-0 size-[250px] overflow-y-scroll py-2" + role="list" + aria-label="All subgraphs" + >
119-125
: Consider extracting metadata filtering logic.The metadata filtering logic could be extracted into a separate utility function for better reusability and testability.
+const getNonSubgraphMetadata = (metadata?: Array<{ name: string; content: string; source?: string }>) => { + return metadata?.filter(m => !m.source) ?? []; +}; const meta = useMemo(() => { - const nonSubgraphMeta = supergraphMetadata.metadata?.filter(m => !m.source); - if (!nonSubgraphMeta?.length) { + const nonSubgraphMeta = getNonSubgraphMetadata(supergraphMetadata.metadata); + if (!nonSubgraphMeta.length) { return null; } return <Metadata supergraphMetadata={nonSubgraphMeta} />; }, [supergraphMetadata.metadata]);
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
pnpm-lock.yaml
is excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (1)
packages/web/app/src/components/target/explorer/super-graph-metadata.tsx
(6 hunks)
🧰 Additional context used
🪛 Biome (1.9.4)
packages/web/app/src/components/target/explorer/super-graph-metadata.tsx
[error] 25-31: Avoid using unnecessary Fragment.
A fragment is redundant if it contains only one child, or if it is the child of a html element, and is not a keyed fragment.
Unsafe fix: Remove the Fragment
(lint/complexity/noUselessFragments)
⏰ Context from checks skipped due to timeout of 90000ms (10)
- GitHub Check: alpha / npm / snapshot
- GitHub Check: test / unit
- GitHub Check: static-analysis / analyze (typescript)
- GitHub Check: typescript / typecheck
- GitHub Check: storybook-preview / deployment
- GitHub Check: static-analysis / analyze (javascript)
- GitHub Check: build / dockerize (linux/arm64)
- GitHub Check: build / dockerize (linux/amd64)
- GitHub Check: alpha / cli-artifacts
- GitHub Check: code-style / eslint-and-prettier
🔇 Additional comments (1)
packages/web/app/src/components/target/explorer/super-graph-metadata.tsx (1)
75-80
: Use more meaningful keys for mapped elements.Using just the index as a key might lead to rendering issues. Consider using a combination of metadata properties for a more stable key.
- <Fragment key={`${index}`}> + <Fragment key={`${m.name}-${m.content}`}>
Background
We need a way to provide and visualize metadata for subgraphs.
#2747
#2818
Description
This adds metadata to fields via a directive.

In this PR, I added a way to view metadata on fields via the explorer. But to close these issues, we will need additional views and behaviors. E.g. filtering the explorer based on metadata, and viewing metadata on a field's insights page.
Checklist