Skip to content

Add EnsRainbowBeam app with endpoint for submitting labels#2015

Open
djstrong wants to merge 36 commits into
mainfrom
2003-add-new-app-with-endpoint-for-submitting-labels
Open

Add EnsRainbowBeam app with endpoint for submitting labels#2015
djstrong wants to merge 36 commits into
mainfrom
2003-add-new-app-with-endpoint-for-submitting-labels

Conversation

@djstrong

@djstrong djstrong commented Apr 29, 2026

Copy link
Copy Markdown
Member

Lite PR

Tip: Review docs on the ENSNode PR process

Summary

  • Add EnsRainbowBeam (apps/ensrainbowbeam): Hono service with GET /health and POST /api/discover that labelhashes submitted label literals, classifies them against ENSNode’s Omnigraph labels index (unknown_in_index / healed_in_index / absent_from_index), skips unnormalizable labels, and emits one structured JSON line per submission to stdout (sink/storage deferred).
  • Extend ENSApi Omnigraph with Query.labels(by: LabelsByLabelHashesInput!): LabelHash scalar, stricter validation, deduped batch lookup (cap 100 distinct hashes per request), plus codegen/SDK updates (enssdk, ensrainbow-sdk).
  • Ship EnsRainbowBeamClient (@ensnode/ensrainbow-sdk/ensrainbowbeam-client), Docker/Compose (docker/services/ensrainbowbeam.yml), Terraform module (terraform/modules/ensrainbowbeam), broad CORS for browser use, and a Beam-it UI on docs/ensrainbow.io calling beam.ensrainbow.io.

Why

  • External callers need a small HTTP surface to submit label discoveries. Closes #2003.
  • Batch labels lookup in ENSApi keeps Beam’s per-request Omnigraph traffic bounded and typed end-to-end.
  • SDK + marketing-site UI make the endpoint usable from browsers and local dev immediately; JSONL stdout preserves a stable row shape for a future persistent/on-chain pipeline.

Testing

  • pnpm -F ensrainbowbeam test — 27 tests (labels.test.ts, submissions.test.ts: validation, classification, skipped unnormalized labels, Omnigraph timeout/error paths, JSONL logging).

Notes for Reviewer (Optional)

  • No persistence yet—stdout JSONL only; leaderboard/on-chain emission are follow-ups on Add new app with endpoint for submitting labels #2003.
  • Per-request cap: 100 raw labels; each may expand to up to 2 distinct LabelHashes (raw + normalized). Omnigraph chunking uses LABELS_BY_LABELHASH_MAX (100).
  • POST /api/discover body: { labels: string[], callerAddress: Address }; response includes per-label status, label, optional labelHash / normalizedLabel.
  • CORS is origin: "*" (same pattern as other public ENSNode HTTP services)—not an env allowlist.
  • Handler file is still named submissions.ts internally; public route is /api/discover.

Pre-Review Checklist (Blocking)

  • This PR does not introduce significant changes and is low-risk to review quickly.
  • Relevant changesets are included (or are not required)

…ation

- Introduced `apps/ens-labels-collector`, a Hono server that accepts label submissions via `POST /api/submissions`.
- Implemented classification of labels against ENSNode's Omnigraph index, emitting structured JSON logs for each submission.
- Added a new `Query.labels` field in ENSApi for batch lookup of labels by their hashes.
- Included necessary configurations, Dockerfile, and example environment variables for local development.
- Comprehensive tests for submission handling and classification logic.

This feature addresses issue [#2003](#2003).
- Updated the maximum number of raw labels accepted per `POST /api/submissions` from 50 to 100.
- Adjusted the `LABELS_BY_HASHES_MAX` limit in the ENSApi from 100 to 200 to accommodate larger batch lookups.
- Modified tests to reflect the new limits for both submissions and label hash queries.
- Enhanced documentation to clarify the relationship between submission limits and hash expansions.
Copilot AI review requested due to automatic review settings April 29, 2026 19:41
@vercel

vercel Bot commented Apr 29, 2026

Copy link
Copy Markdown
Contributor

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
admin.ensnode.io Ready Ready Preview, Comment Jun 12, 2026 7:50pm
enskit-react-example.ensnode.io Ready Ready Preview, Comment Jun 12, 2026 7:50pm
ensnode-enskit-react-example Ready Ready Preview, Comment Jun 12, 2026 7:50pm
ensnode.io Ready Ready Preview, Comment Jun 12, 2026 7:50pm
ensrainbow.io Ready Ready Preview, Comment Jun 12, 2026 7:50pm

@changeset-bot

changeset-bot Bot commented Apr 29, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 8ef9b72

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 25 packages
Name Type
ensapi Minor
@ensnode/ensrainbow-sdk Minor
ensrainbowbeam Minor
enssdk Minor
ensindexer Minor
ensrainbow Minor
@docs/ensrainbow Minor
enscli Minor
ensadmin Minor
@docs/ensnode Minor
@ensnode/enskit-react-example Patch
@ensnode/enssdk-example Patch
@ensnode/datasources Minor
@namehash/ens-referrals Minor
@ensnode/ensdb-sdk Minor
enskit Minor
@ensnode/ensnode-sdk Minor
ensskills Minor
@ensnode/integration-test-env Minor
@namehash/namehash-ui Minor
fallback-ensapi Minor
@ensnode/ponder-sdk Minor
@ensnode/ponder-subgraph Minor
@ensnode/shared-configs Minor
@ensnode/ensindexer-perf-testing Minor

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@coderabbitai

coderabbitai Bot commented Apr 29, 2026

Copy link
Copy Markdown
Contributor

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

New ens-labels-collector Hono service accepts POST /api/submissions, hashes and classifies submitted ENS labels via Omnigraph lookups, and emits one structured JSON line per submission to stdout. ENSApi adds Query.labels(by: LabelsByHashesInput!) for batch label lookup by hashes (deduped, capped at 200, omits missing).

Changes

Cohort / File(s) Summary
ens-labels-collector scaffold & metadata
/.changeset/ens-labels-collector-app.md, apps/ens-labels-collector/.env.local.example, apps/ens-labels-collector/Dockerfile, apps/ens-labels-collector/README.md, apps/ens-labels-collector/package.json, apps/ens-labels-collector/tsconfig.json, apps/ens-labels-collector/vitest.config.ts
New app scaffold and metadata: changeset, env example, Dockerfile, README, package manifest, TS and Vitest configs.
app bootstrap & server
apps/ens-labels-collector/src/app.ts, apps/ens-labels-collector/src/index.ts, apps/ens-labels-collector/src/config.ts
Hono app export with routes, global error handler, Zod-validated runtime config, server start/close, graceful shutdown and signal/exception handlers.
HTTP handlers & tests
apps/ens-labels-collector/src/handlers/health.ts, apps/ens-labels-collector/src/handlers/submissions.ts, apps/ens-labels-collector/src/handlers/submissions.test.ts
Adds GET /health and POST /api/submissions with Zod validation, address normalization, max-labels guard, request-id/timestamp, timed Omnigraph lookup using AbortSignal.any, classification, single JSON-line stdout emission; comprehensive tests including error paths and dedupe.
label processing & tests
apps/ens-labels-collector/src/lib/labels.ts, apps/ens-labels-collector/src/lib/labels.test.ts
Label hashing and optional normalization, deduped lookup-hash collection, unhealed-hit detection, classification into unknown_in_index/healed_in_index/absent_from_index; unit tests for hashing, normalization, dedupe, and classification logic.
Omnigraph client
apps/ens-labels-collector/src/lib/omnigraph-client.ts
Typed Omnigraph GraphQL query and lookupLabels against configured ENSNode URL; short-circuits empty input, forwards AbortSignal, surfaces GraphQL errors, returns label hits.
shared helpers
apps/ens-labels-collector/src/lib/error-response.ts
Standardized errorResponse helper mapping ZodError, Error, string, and other shapes to canonical JSON responses with inferred status and optional details.
ENSApi GraphQL additions & tests
apps/ensapi/src/omnigraph-api/schema/label.ts, apps/ensapi/src/omnigraph-api/schema/query.ts, apps/ensapi/src/omnigraph-api/schema/label.integration.test.ts, apps/ensapi/src/omnigraph-api/yoga.ts
Adds LabelsByHashesInput and LABELS_BY_HASHES_MAX (200); new Query.labels(by: LabelsByHashesInput!): [LabelRef!]! resolver that validates batch size, dedups inputs, returns only present labels; integration tests for present/absent/dedup/over-limit cases; conditional Yoga error masking.
misc changeset/config
.changeset/config.json
Includes ens-labels-collector in changeset fixed list.
other runtime tweak
apps/ensrainbow/src/commands/entrypoint-command.ts
Gates readiness marker on buildDbConfig success and adds an additional shutdown/abort check after building DB config.

Sequence Diagram

sequenceDiagram
    participant Client
    participant Collector as "ens-labels-collector\n(Hono)"
    participant Omnigraph as "ENSApi / Omnigraph\n(GraphQL)"
    participant DB as "Label Index DB"

    Client->>Collector: POST /api/submissions { labels, callerAddress }
    activate Collector
    Collector->>Collector: Validate input\nnormalize address, hash labels
    Collector->>Collector: Collect & dedupe lookup hashes
    Collector->>Omnigraph: Query labels(by: { hashes })
    activate Omnigraph
    Omnigraph->>DB: SELECT labels WHERE labelHash IN (...)
    DB-->>Omnigraph: [{ hash, interpreted }]
    Omnigraph-->>Collector: [{ hash, interpreted }]
    deactivate Omnigraph
    Collector->>Collector: Classify labels\n(healed/unknown/absent)
    Collector->>Collector: Emit single JSON log line to stdout
    Collector-->>Client: 200 { submittedAt, callerAddress, results }
    deactivate Collector
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Poem

🐰 Hopping through hashes one by one,

I normalize, dedupe, then run,
I query the graph and log what I find,
One JSON line keeps each submission signed,
A rabbit’s cheer for labels neatly lined.

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 57.14% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ⚠️ Warning The PR title refers to 'EnsRainbowBeam app' but the changeset and all modifications focus on the 'ens-labels-collector' app, not EnsRainbowBeam. Update the title to accurately reflect the main change: 'Add ens-labels-collector app with endpoint for submitting labels' or similar phrasing that references the correct app name.
✅ Passed checks (3 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description check ✅ Passed PR follows the template structure with Summary, Why, Testing, and Notes sections; however, the pre-review checklist items are not marked complete despite requirements being met.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch 2003-add-new-app-with-endpoint-for-submitting-labels

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a new “labels collector” service and the supporting Omnigraph query for batched labelhash lookups, enabling external callers to submit raw labels and have them classified against ENSNode’s indexed label table.

Changes:

  • Add Query.labels(by: { hashes }) to ENSApi Omnigraph schema with a hard cap (200) and integration tests.
  • Add new app apps/ens-labels-collector (Hono) exposing POST /api/submissions + /health, with label hashing/normalization, Omnigraph lookups, and JSONL stdout logging.
  • Regenerate enssdk/omnigraph schema + introspection for the new query/input; update lockfile and add changeset.

Reviewed changes

Copilot reviewed 20 out of 23 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
pnpm-lock.yaml Adds new app importer + lockfile refresh (including patched dependency hashes).
packages/enssdk/src/omnigraph/generated/schema.graphql Adds LabelsByHashesInput and Query.labels to generated schema.
packages/enssdk/src/omnigraph/generated/introspection.ts Updates generated introspection for typed Omnigraph client.
apps/ensapi/src/omnigraph-api/schema/query.ts Implements Query.labels resolver using Drizzle inArray with max-size enforcement.
apps/ensapi/src/omnigraph-api/schema/label.ts Adds LabelsByHashesInput and LABELS_BY_HASHES_MAX.
apps/ensapi/src/omnigraph-api/schema/label.integration.test.ts Integration coverage for Query.labels.
apps/ens-labels-collector/vitest.config.ts Vitest project config for the new app.
apps/ens-labels-collector/tsconfig.json TS config for the new app.
apps/ens-labels-collector/src/lib/omnigraph-client.ts Typed Omnigraph query wrapper + memoized client.
apps/ens-labels-collector/src/lib/labels.ts Hashing + lookup-hash collection + classification logic.
apps/ens-labels-collector/src/lib/labels.test.ts Unit tests for hashing/classification helpers.
apps/ens-labels-collector/src/lib/error-response.ts Standardized { message, details? } error response helper.
apps/ens-labels-collector/src/index.ts Server startup + graceful shutdown wiring.
apps/ens-labels-collector/src/handlers/submissions.ts POST /api/submissions handler: validation, lookup, classification, logging.
apps/ens-labels-collector/src/handlers/submissions.test.ts Handler-level tests with mocked Omnigraph client.
apps/ens-labels-collector/src/handlers/health.ts /health handler.
apps/ens-labels-collector/src/config.ts Env config parsing + memoization.
apps/ens-labels-collector/src/app.ts Route wiring + notFound/onError handling.
apps/ens-labels-collector/package.json New app package manifest and scripts.
apps/ens-labels-collector/README.md App documentation + usage/config.
apps/ens-labels-collector/Dockerfile Containerization for the new service.
apps/ens-labels-collector/.env.local.example Local env template.
.changeset/ens-labels-collector-app.md Changeset for ens-labels-collector, ensapi, and enssdk.
Files not reviewed (1)
  • pnpm-lock.yaml: Language not supported

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +19 to +35
const closeServer = () =>
new Promise<void>((resolve, reject) =>
server.close((err) => {
if (err) reject(err);
else resolve();
}),
);

const gracefulShutdown = async () => {
try {
await closeServer();
process.exit(0);
} catch (error) {
console.error("[ens-labels-collector] shutdown error", error);
process.exit(1);
}
};
Comment on lines +43 to +58
export async function lookupLabels(hashes: readonly string[]): Promise<LabelHit[]> {
if (hashes.length === 0) return [];

const result = await getClient().omnigraph.query({
query: LabelsByHashes,
variables: { hashes: hashes as `0x${string}`[] },
});

if (result.errors && result.errors.length > 0) {
throw new Error(
`Omnigraph labels query returned errors: ${result.errors.map((e) => e.message).join("; ")}`,
);
}

return (result.data?.labels ?? []) as LabelHit[];
}
Comment on lines +86 to +92
it("rejects requests over the maximum allowed hash count", async () => {
// generate (LABELS_BY_HASHES_MAX + 1) distinct labelhashes deterministically
const hashes: LabelHash[] = [];
for (let i = 0; i <= 200; i++) {
const hex = i.toString(16).padStart(64, "0");
hashes.push(`0x${hex}` as LabelHash);
}

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 11

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@apps/ens-labels-collector/Dockerfile`:
- Around line 11-16: The runner stage in the Dockerfile runs as root; update the
runner stage to switch to a non-root user by creating or using an existing
unprivileged user (e.g., "node" or a custom uid/gid), ensure
ownership/permissions of WORKDIR (/app/apps/ens-labels-collector) are set to
that user, and add a USER instruction before the CMD so the container process
launched by CMD ["pnpm","start"] does not run as root; reference the runner
stage, WORKDIR, and CMD when making these changes.
- Around line 14-16: The Dockerfile lacks a HEALTHCHECK so orchestrators can't
detect runtime liveness/readiness; add a HEALTHCHECK instruction after the
EXPOSE 4444 (and before CMD ["pnpm","start"]) that probes the app's health
endpoint (e.g., HTTP GET to localhost:4444/health or the appropriate route) and
configure sensible options (--interval, --timeout, --start-period, --retries) so
failed probes mark the container unhealthy; ensure the probe command exits
non‑zero on failure so Docker/k8s receive correct health signals.

In `@apps/ens-labels-collector/src/app.ts`:
- Around line 15-18: The onError handler currently returns the raw error to
clients via errorResponse in app.onError; change it to log the full error
internally (using console.error or processLogger) but return a generic 500
response body (e.g., { error: "Internal Server Error" } or a minimal error id)
from errorResponse instead of the raw error object; keep the logging call for
app.onError((error, c) => ...) but remove/error-sanitize any exposure of error
when calling errorResponse so implementation details are not leaked to clients.

In `@apps/ens-labels-collector/src/config.ts`:
- Around line 4-8: The PORT schema currently uses Number.parseInt which allows
partial numeric strings like "4444abc"; update the transform for PORT in
config.ts to validate the raw string strictly (e.g. ensure it matches /^\d+$/)
before parsing and return the default 4444 when undefined, and otherwise parse
with Number.parseInt or Number(value); if the string fails the digits-only
check, throw or return a z.ZodError/invalid value so the .pipe(z.number()...)
never receives a truncated number—target the PORT zod schema's .transform
callback to implement this validation.

In `@apps/ens-labels-collector/src/handlers/submissions.test.ts`:
- Around line 33-38: The test suite creates a global console.log spy
(consoleSpy) but never restores it, which can leak a mocked console into other
tests; add an afterAll (or afterEach) teardown that calls
consoleSpy.mockRestore() to restore the original console.log; locate the
consoleSpy declaration and the existing beforeEach block in submissions.test.ts
and add afterAll(() => consoleSpy.mockRestore()) so the spy is removed when the
suite finishes.
- Around line 40-213: Tests in submissions.test.ts use an await-then-expect
pattern for async responses (e.g., calling await res.json() then asserting), and
the reviewer suggests optionally switching to Vitest's await
expect(promise).resolves.* pattern; to apply this refactor, locate the tests
that call app.request and then await res.json() (examples: the "classifies a
healed label correctly..." test, "classifies an unhealed label...", "normalizes
the callerAddress..." and others) and replace the manual await-and-then
assertions with direct promise assertions (e.g., use await
expect(res.json()).resolves.toMatchObject(...) or resolves.toEqual(...) where
appropriate), keeping status assertions either as expect(res.status).toBe(...)
or using await expect(Promise.resolve(res.status)).resolves.toBe(...); this is
optional—apply consistently across the file if you refactor.

In `@apps/ens-labels-collector/src/handlers/submissions.ts`:
- Line 110: The call to lookupLabels() is unbounded and can hang; wrap the
external Omnigraph lookup in a bounded timeout so the handler doesn't block
indefinitely—use a Promise.race (or an AbortController if lookupLabels accepts a
signal) to enforce a maximum wait (e.g., configurable constant) and handle
timeout by returning a clear error or fallback before assigning hits; update the
code around the lookupLabels call (where hits is awaited) to cancel/ignore the
lookup on timeout and log/propagate a timeout-specific error.

In `@apps/ens-labels-collector/src/index.ts`:
- Around line 27-35: The current gracefulShutdown function always exits with 0;
update it to accept an optional exitCode parameter (default 0) and pass that to
process.exit so callers can signal failure; then change the uncaughtException
handler (process.on('uncaughtException', ...)) to call gracefulShutdown(1) (or
invoke a dedicated fatalShutdown that logs the error and calls
gracefulShutdown(1)) so uncaught exceptions exit non‑zero while SIGINT/SIGTERM
continue to call gracefulShutdown() with the default 0. Ensure references to
gracefulShutdown and the uncaughtException handler are updated accordingly.

In `@apps/ens-labels-collector/src/lib/omnigraph-client.ts`:
- Around line 43-49: Change lookupLabels to accept readonly LabelHash[] instead
of readonly string[] and remove the unsafe cast to `0x${string}` in the query
variables; update the function signature for lookupLabels, remove the cast
currently applied to `hashes` when calling getClient().omnigraph.query with
LabelsByHashes, and pass the hashes array directly (ensuring LabelHash is
imported/available). Confirm callers (e.g., collectLookupHashes) already provide
LabelHash[] so no runtime changes are needed.

In `@apps/ensapi/src/omnigraph-api/schema/label.integration.test.ts`:
- Around line 89-91: The test currently hardcodes 200 when building hashes to
trigger the overflow; import the exported constant LABELS_BY_HASHES_MAX and use
it to generate one more than the cap (e.g. loop to <= LABELS_BY_HASHES_MAX) so
the test reliably creates LABELS_BY_HASHES_MAX+1 hashes; add the import for
LABELS_BY_HASHES_MAX and replace the literal 200 in the loop in
label.integration.test.ts (the block that builds hashes) with that constant.
- Around line 34-84: Refactor each test to assert the async request using the
"await expect(...).resolves" pattern instead of awaiting the result then calling
expect: call request<LabelsByHashesResult>(LabelsByHashes, {...}) inside await
expect(...).resolves and use resolves.toHaveLength(), resolves.toEqual(),
resolves.toMatchObject() (for the healed label object) and
resolves.toMatchObject() or resolves.toHaveProperty() for specific fields; for
the dedupe/presence tests use
resolves.toHaveLength()/resolves.toHaveProperty('labels.0.hash',
ETH_LABEL_HASH), and for the "interpreted !== encodeLabelHash" case express the
inequality via a resolves matcher (e.g.,
resolves.toHaveProperty('labels.0.interpreted', expect.not...)) so all
assertions use the resolves chain against the promise returned by request
(references: LabelsByHashes, request, LabelsByHashesResult, ETH_LABEL_HASH,
ABSENT_LABEL_HASH, encodeLabelHash).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: f8a4ec9f-6c70-4113-8141-54936f4f333c

📥 Commits

Reviewing files that changed from the base of the PR and between c29b4c5 and c57108e.

⛔ Files ignored due to path filters (3)
  • packages/enssdk/src/omnigraph/generated/introspection.ts is excluded by !**/generated/**
  • packages/enssdk/src/omnigraph/generated/schema.graphql is excluded by !**/generated/**
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (20)
  • .changeset/ens-labels-collector-app.md
  • apps/ens-labels-collector/.env.local.example
  • apps/ens-labels-collector/Dockerfile
  • apps/ens-labels-collector/README.md
  • apps/ens-labels-collector/package.json
  • apps/ens-labels-collector/src/app.ts
  • apps/ens-labels-collector/src/config.ts
  • apps/ens-labels-collector/src/handlers/health.ts
  • apps/ens-labels-collector/src/handlers/submissions.test.ts
  • apps/ens-labels-collector/src/handlers/submissions.ts
  • apps/ens-labels-collector/src/index.ts
  • apps/ens-labels-collector/src/lib/error-response.ts
  • apps/ens-labels-collector/src/lib/labels.test.ts
  • apps/ens-labels-collector/src/lib/labels.ts
  • apps/ens-labels-collector/src/lib/omnigraph-client.ts
  • apps/ens-labels-collector/tsconfig.json
  • apps/ens-labels-collector/vitest.config.ts
  • apps/ensapi/src/omnigraph-api/schema/label.integration.test.ts
  • apps/ensapi/src/omnigraph-api/schema/label.ts
  • apps/ensapi/src/omnigraph-api/schema/query.ts

Comment on lines +11 to +16
FROM deps AS runner
WORKDIR /app/apps/ens-labels-collector
ENV NODE_ENV=production
EXPOSE 4444

CMD ["pnpm", "start"]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Run the container as a non-root user.
The runner stage currently executes as root, which is an avoidable security risk.

🔧 Proposed fix
 FROM deps AS runner
 WORKDIR /app/apps/ens-labels-collector
 ENV NODE_ENV=production
+USER node
 EXPOSE 4444
 
 CMD ["pnpm", "start"]
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
FROM deps AS runner
WORKDIR /app/apps/ens-labels-collector
ENV NODE_ENV=production
EXPOSE 4444
CMD ["pnpm", "start"]
FROM deps AS runner
WORKDIR /app/apps/ens-labels-collector
ENV NODE_ENV=production
USER node
EXPOSE 4444
CMD ["pnpm", "start"]
🧰 Tools
🪛 Checkov (3.2.525)

[low] 1-16: Ensure that HEALTHCHECK instructions have been added to container images

(CKV_DOCKER_2)


[low] 1-16: Ensure that a user for the container has been created

(CKV_DOCKER_3)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/ens-labels-collector/Dockerfile` around lines 11 - 16, The runner stage
in the Dockerfile runs as root; update the runner stage to switch to a non-root
user by creating or using an existing unprivileged user (e.g., "node" or a
custom uid/gid), ensure ownership/permissions of WORKDIR
(/app/apps/ens-labels-collector) are set to that user, and add a USER
instruction before the CMD so the container process launched by CMD
["pnpm","start"] does not run as root; reference the runner stage, WORKDIR, and
CMD when making these changes.

Comment on lines +14 to +16
EXPOSE 4444

CMD ["pnpm", "start"]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Add a HEALTHCHECK for runtime readiness/liveness.
Without it, orchestrators have weaker signal for unhealthy instances.

🔧 Proposed fix
 ENV NODE_ENV=production
 EXPOSE 4444
+HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \
+  CMD node -e 'fetch("http://127.0.0.1:4444/health").then(r=>process.exit(r.ok?0:1)).catch(()=>process.exit(1))'
 
 CMD ["pnpm", "start"]
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
EXPOSE 4444
CMD ["pnpm", "start"]
EXPOSE 4444
HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \
CMD node -e 'fetch("http://127.0.0.1:4444/health").then(r=>process.exit(r.ok?0:1)).catch(()=>process.exit(1))'
CMD ["pnpm", "start"]
🧰 Tools
🪛 Checkov (3.2.525)

[low] 1-16: Ensure that HEALTHCHECK instructions have been added to container images

(CKV_DOCKER_2)


[low] 1-16: Ensure that a user for the container has been created

(CKV_DOCKER_3)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/ens-labels-collector/Dockerfile` around lines 14 - 16, The Dockerfile
lacks a HEALTHCHECK so orchestrators can't detect runtime liveness/readiness;
add a HEALTHCHECK instruction after the EXPOSE 4444 (and before CMD
["pnpm","start"]) that probes the app's health endpoint (e.g., HTTP GET to
localhost:4444/health or the appropriate route) and configure sensible options
(--interval, --timeout, --start-period, --retries) so failed probes mark the
container unhealthy; ensure the probe command exits non‑zero on failure so
Docker/k8s receive correct health signals.

Comment thread apps/ensrainbowbeam/src/app.ts
Comment thread apps/ens-labels-collector/src/config.ts Outdated
Comment thread apps/ensrainbowbeam/src/handlers/submissions.test.ts
Comment thread apps/ens-labels-collector/src/handlers/submissions.ts Outdated
Comment thread apps/ens-labels-collector/src/index.ts Outdated
Comment thread apps/ens-labels-collector/src/lib/omnigraph-client.ts Outdated
Comment thread apps/ensapi/src/omnigraph-api/schema/label.integration.test.ts
Comment thread apps/ensapi/src/omnigraph-api/schema/label.integration.test.ts Outdated
@vercel vercel Bot temporarily deployed to Preview – admin.ensnode.io April 29, 2026 19:58 Inactive
@vercel vercel Bot temporarily deployed to Preview – ensnode.io April 29, 2026 19:58 Inactive
@vercel vercel Bot temporarily deployed to Preview – ensrainbow.io April 29, 2026 19:58 Inactive
Comment thread apps/ens-labels-collector/src/index.ts Outdated
Comment thread apps/ens-labels-collector/src/config.ts Outdated
Comment thread apps/ensapi/src/omnigraph-api/schema/label.integration.test.ts Outdated
Comment thread apps/ens-labels-collector/src/app.ts Outdated
Comment thread apps/ensrainbowbeam/src/lib/omnigraph-client.ts Outdated
Comment thread apps/ens-labels-collector/src/handlers/submissions.ts Outdated
…r submissions

- Updated error handling in the app to prevent leaking underlying error messages to clients, responding with a generic 500 status instead.
- Introduced a timeout mechanism for the `POST /api/submissions` endpoint to prevent stalled requests from holding resources indefinitely.
- Added a new utility function to handle promise timeouts, ensuring graceful degradation in case of delays during label lookups.
- Updated tests to include new error handling and timeout scenarios.
Copilot AI review requested due to automatic review settings April 29, 2026 20:41
@vercel vercel Bot temporarily deployed to Preview – admin.ensnode.io April 29, 2026 20:41 Inactive
@vercel vercel Bot temporarily deployed to Preview – ensnode.io April 29, 2026 20:41 Inactive
@vercel vercel Bot temporarily deployed to Preview – ensrainbow.io April 29, 2026 20:41 Inactive

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a new labels-submission collector app and extends ENSApi/Omnigraph to support batch label lookups by labelhash, enabling callers to classify submitted labels against the ENSNode index.

Changes:

  • Add apps/ens-labels-collector (Hono server) with POST /api/submissions + stdout JSONL sink and label classification logic.
  • Add Omnigraph Query.labels(by: LabelsByHashesInput!): [Label!]! with a 200-hash cap, plus integration tests.
  • Regenerate enssdk/omnigraph generated schema + introspection to expose the new query to typed clients.

Reviewed changes

Copilot reviewed 21 out of 24 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
pnpm-lock.yaml Adds new app importer deps + bumps esbuild snapshot used by toolchain.
packages/enssdk/src/omnigraph/generated/schema.graphql Adds LabelsByHashesInput + Query.labels to generated schema.
packages/enssdk/src/omnigraph/generated/introspection.ts Updates generated introspection to include new input + query field.
apps/ensapi/src/omnigraph-api/yoga.ts Configures masked GraphQL errors (prod) with dev passthrough behavior.
apps/ensapi/src/omnigraph-api/schema/query.ts Implements Query.labels resolver with dedupe + max hash cap.
apps/ensapi/src/omnigraph-api/schema/label.ts Adds LabelsByHashesInput + LABELS_BY_HASHES_MAX.
apps/ensapi/src/omnigraph-api/schema/label.integration.test.ts Adds integration coverage for Query.labels behavior and limits.
apps/ens-labels-collector/vitest.config.ts Sets up unit-test project config for the new app.
apps/ens-labels-collector/tsconfig.json Adds TS config for the new app with @/* path alias.
apps/ens-labels-collector/src/lib/omnigraph-client.ts Adds typed Omnigraph client + cached client for label lookups.
apps/ens-labels-collector/src/lib/labels.ts Adds hashing + normalization + classification utilities.
apps/ens-labels-collector/src/lib/labels.test.ts Unit tests for label hashing/collection/classification utilities.
apps/ens-labels-collector/src/lib/error-response.ts Standardizes JSON error responses for the new service.
apps/ens-labels-collector/src/index.ts Adds server bootstrap + graceful shutdown handling.
apps/ens-labels-collector/src/handlers/submissions.ts Implements submissions endpoint schema validation, lookup, classification, timeout, and logging.
apps/ens-labels-collector/src/handlers/submissions.test.ts Unit tests for submissions handler validation, behavior, and logging.
apps/ens-labels-collector/src/handlers/health.ts Adds liveness endpoint handler.
apps/ens-labels-collector/src/config.ts Adds env config parsing/memoization for PORT + ENSNODE_URL.
apps/ens-labels-collector/src/app.ts Wires routes + notFound + error handling for the new app.
apps/ens-labels-collector/package.json Declares new workspace app package, scripts, and dependencies.
apps/ens-labels-collector/README.md Documents endpoints, classification logic, and configuration.
apps/ens-labels-collector/Dockerfile Provides container build/run recipe for the new app.
apps/ens-labels-collector/.env.local.example Adds local dev env template.
.changeset/ens-labels-collector-app.md Adds changeset for new app + Omnigraph API + regenerated SDK artifacts.
Files not reviewed (1)
  • pnpm-lock.yaml: Language not supported

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +34 to +42
* Races `promise` against a `setTimeout`-backed timeout, rejecting with `Error(message)` on
* expiry. The underlying promise is NOT cancelled (the Omnigraph SDK does not currently expose
* an `AbortSignal`); we simply stop waiting on it. The unhandled resolution is harmless.
*/
function withTimeout<T>(promise: Promise<T>, ms: number, message: string): Promise<T> {
let timer: ReturnType<typeof setTimeout> | undefined;
const timeout = new Promise<never>((_, reject) => {
timer = setTimeout(() => reject(new Error(message)), ms);
});
Comment thread .changeset/ens-labels-collector-app.md Outdated
Comment on lines +1 to +5
---
"ens-labels-collector": minor
"ensapi": minor
"enssdk": minor
---
Comment on lines +35 to +41
## Configuration

| Env var | Required | Description |
|---------|----------|-------------|
| `PORT` | no (default `4444`) | HTTP listen port. |
| `ENSNODE_URL` | yes | Base URL of an ENSNode (ENSApi) instance with Omnigraph at `/api/omnigraph`. |

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@apps/ens-labels-collector/package.json`:
- Line 23: You added the workspace dependency "@ensnode/ensnode-sdk" to
package.json but did not update the lockfile; run the package manager to
regenerate and commit the lockfile (e.g., run pnpm install to update
pnpm-lock.yaml) so the new workspace dependency is reflected, then include that
updated lockfile commit alongside the package.json change.

In `@apps/ens-labels-collector/src/handlers/submissions.ts`:
- Around line 34-37: The lookupLabels function currently races the Omnigraph SDK
call with withTimeout but does not pass an AbortSignal, so timed-out requests
keep running; update lookupLabels to accept an optional AbortSignal (or
QueryOptions) and pass it into the Omnigraph query call (the SDK supports
AbortSignal via QueryOptions), and change withTimeout usage to create an
AbortController whose signal is passed to the SDK and that is aborted when the
timeout fires; if lookupLabels is called with an existing signal, wire it to
abort the controller (or merge signals) so caller cancellations propagate;
finally update callers of lookupLabels (the HTTP request handler paths around
the earlier call sites) to supply the request's AbortSignal or forward
cancellation so in-flight requests are actually aborted on timeout or client
disconnect.

In `@apps/ensapi/src/omnigraph-api/yoga.ts`:
- Around line 19-28: Replace the custom masking block inside maskedErrors so it
uses Yoga's exported maskError function and the app's Pino logger: instead of
calling console.error and returning raw Error instances, call the Yoga maskError
fallback (maskError) with the error and log the error via the existing Pino
logger (logger) before returning maskError's result; ensure maskError is
imported from Yoga and the logger variable used is the same Pino instance the
app uses.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: a9de560f-e3b8-4c43-9c9b-f3068d0f74f5

📥 Commits

Reviewing files that changed from the base of the PR and between c57108e and 440023c.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (9)
  • apps/ens-labels-collector/package.json
  • apps/ens-labels-collector/src/app.ts
  • apps/ens-labels-collector/src/config.ts
  • apps/ens-labels-collector/src/handlers/submissions.test.ts
  • apps/ens-labels-collector/src/handlers/submissions.ts
  • apps/ens-labels-collector/src/index.ts
  • apps/ens-labels-collector/src/lib/omnigraph-client.ts
  • apps/ensapi/src/omnigraph-api/schema/label.integration.test.ts
  • apps/ensapi/src/omnigraph-api/yoga.ts

Comment thread apps/ensrainbowbeam/package.json
Comment thread apps/ens-labels-collector/src/handlers/submissions.ts Outdated
Comment thread apps/ensapi/src/omnigraph-api/yoga.ts
@vercel vercel Bot temporarily deployed to Preview – ensrainbow.io April 29, 2026 21:03 Inactive
@vercel vercel Bot temporarily deployed to Preview – admin.ensnode.io April 29, 2026 21:03 Inactive
@vercel vercel Bot temporarily deployed to Preview – ensnode.io April 29, 2026 21:03 Inactive
djstrong added 2 commits May 4, 2026 12:56
…or distinct `LabelHash` inputs, update error messages for clarity, and allow duplicate `LabelHashes` within the maximum distinct count. Adjust related tests and documentation to reflect these changes.
…dling for invalid inputs, ensuring clearer error messages. Modify tests to validate mixed-case hex digits and reject uppercase `0X` prefixes for `LabelHash` variables.
Copilot AI review requested due to automatic review settings May 4, 2026 10:58

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 36 out of 39 changed files in this pull request and generated no new comments.

Files not reviewed (1)
  • pnpm-lock.yaml: Language not supported

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

djstrong added 2 commits May 4, 2026 20:55
…` and `discover()` methods, introduce `EnsRainbowBeamHttpError` for error handling, and ensure client-side validation aligns with server expectations. Update exports and configuration for new client integration.
…plement comprehensive unit tests covering validation logic, health checks, and discover functionality, ensuring proper error handling and response validation. Introduce `omnigraph-consts.ts` for server-side limits on label requests.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 44 out of 47 changed files in this pull request and generated no new comments.

Files not reviewed (1)
  • pnpm-lock.yaml: Language not supported

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

djstrong added 2 commits May 5, 2026 14:07
…ent workflows for `ensrainbowbeam`, and enhance configuration with CORS origins. Update Terraform modules for deployment and add new environment variables. Enhance UI components for label submission and results display.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 55 out of 58 changed files in this pull request and generated 4 comments.

Files not reviewed (1)
  • pnpm-lock.yaml: Language not supported

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread terraform/modules/ensrainbowbeam/main.tf
Comment thread docker/services/ensrainbowbeam.yml
Comment thread docs/ensrainbow.io/src/components/organisms/HealUnknownName.tsx Outdated
Comment thread terraform/main.tf
Comment thread terraform/modules/ensrainbowbeam/variables.tf
Comment thread terraform/modules/ensrainbowbeam/variables.tf
Comment thread docs/ensrainbow.io/src/components/organisms/HealUnknownName.tsx Outdated
…alized labels, enhancing the classification logic. Introduce new types for skipped labels and adjust related components to accommodate the changes. Update deployment workflow by removing outdated comments.
Comment thread docker/services/ensrainbowbeam.yml
Comment thread docker/services/ensrainbowbeam.yml
Comment thread docs/ensrainbow.io/src/components/organisms/HealUnknownName.tsx Outdated
Comment thread terraform/modules/ensrainbowbeam/main.tf
djstrong added 2 commits May 6, 2026 15:55
… `.env.local.example` and `README.md` to reflect the removal of `CORS_ORIGINS`. Refactor `config.ts` to eliminate CORS parsing and adjust `app.ts` to remove CORS middleware, streamlining the application setup.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 55 out of 58 changed files in this pull request and generated 5 comments.

Files not reviewed (1)
  • pnpm-lock.yaml: Language not supported

Comment thread apps/ensrainbowbeam/src/lib/labels.ts Outdated
Comment on lines +67 to +71
* True when a submitted label is already normalized under ENSIP-15.
*/
export function isProcessableLabel(rawLabel: LiteralLabel): boolean {
return isNormalizedLabel(rawLabel as unknown as Label);
}
Comment on lines +49 to +53
export type LabelClassification = HashedLabel & {
status: LabelStatus;
};

export type SkippedLabelClassification = {
@@ -11,7 +13,7 @@ LabelRef.implement({
hash: t.field({
description:
"The Label's LabelHash\n(@see https://ensnode.io/docs/reference/terminology#labels-labelhashes-labelhash-function)",
Comment thread docs/ensrainbow.io/src/components/organisms/HealUnknownName.tsx
Comment thread docs/ensrainbow.io/src/components/organisms/HealUnknownName.tsx
@greptile-apps

greptile-apps Bot commented May 6, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR introduces the EnsRainbowBeam service — a Hono HTTP app (POST /api/discover) that accepts label submissions, normalizes them with ENSIP-15, looks up their labelhashes against ENSNode's Omnigraph labels index, and emits per-request JSONL lines to stdout. It also adds the Query.labels(by: LabelsByLabelHashesInput!) GraphQL resolver to ENSApi Omnigraph, ships an EnsRainbowBeamClient in @ensnode/ensrainbow-sdk, and wires up Docker/Compose, Terraform, and a "Beam-it" UI on the ensrainbow.io docs site.

  • New ensrainbowbeam app: validates and classifies batches of up to 100 labels with proper abort-signal chaining (timeout + client disconnect), index-preserving result reconstruction, and clean stdout/stderr separation for the JSONL sink.
  • ENSApi Omnigraph extension: new LabelHash scalar with parseLabelHash validation, LabelsByLabelHashesInput input type, deduplication + LABELS_BY_LABELHASH_MAX cap enforced via createGraphQLError, and drizzle inArray resolver with empty-input guard.
  • SDK + UI: EnsRainbowBeamClient with injected fetch and client-side validation; HealUnknownName React component connects to beam.ensrainbow.io with per-label StatusBadge display.

Confidence Score: 5/5

Safe to merge; the new service, GraphQL extension, and SDK are well-tested and handle edge cases (timeout, client disconnect, deduplication, unnormalizable labels) correctly.

All core paths — normalization, hash deduplication, Omnigraph batching, abort-signal chaining, index-preserving result reconstruction, and JSONL emission — are implemented correctly and covered by 27 unit/integration tests. The graceful-shutdown, CORS, error-masking, and LabelHash scalar additions are straightforward and consistent with existing patterns in the monorepo. The only noteworthy concern is the duplicated boundary constants in the SDK that require manual synchronization with the server, but this is a maintenance note, not a current defect.

No files require special attention; the duplicated ENSRAINBOWBEAM_DISCOVER_MAX_LABELS / ENSRAINBOWBEAM_LABEL_MAX_LENGTH constants in packages/ensrainbow-sdk/src/ensrainbowbeam-client.ts are worth tracking as a future refactor.

Important Files Changed

Filename Overview
apps/ensrainbowbeam/src/handlers/submissions.ts Core POST /api/discover handler: validates input, hashes/normalizes labels, batches Omnigraph lookup with timeout+disconnect cancellation, returns per-label classification and emits JSONL to stdout. Logic is correct; index-preserving result reconstruction, deduplication, and abort-signal chain all work as expected.
apps/ensrainbowbeam/src/lib/labels.ts ENSIP-15 normalization, labelhashing, deduplication, and classification against Omnigraph hits. The normalizedLabel path is live (non-normalized inputs like "VITALIK" produce it), tests confirm correct behavior for healed/unknown/absent/skipped states.
apps/ensrainbowbeam/src/lib/omnigraph-client.ts Wraps the Omnigraph labels query with batching (chunked by OMNIGRAPH_LABELS_BY_LABELHASH_MAX=100) and AbortSignal forwarding. GraphQL partial-error responses are conservatively rejected. Module-level comment says "up to 200 distinct LabelHashes" but actual max is 100 (one normalized hash per label).
apps/ensrainbowbeam/src/index.ts Server entry point with graceful shutdown guarded by a single in-flight promise. Handles SIGINT, SIGTERM, and uncaughtException; unhandledRejection is not registered (flagged in a previous review thread). Exit-code capture via closure is correct for the common single-signal case.
apps/ensapi/src/omnigraph-api/schema/query.ts Adds Query.labels resolver: deduplicates input hashes, enforces LABELS_BY_LABELHASH_MAX cap via createGraphQLError, issues drizzle inArray query. Empty-input early return prevents drizzle's inArray-with-empty-array SQL issue.
apps/ensapi/src/omnigraph-api/schema/scalars.ts Adds LabelHash scalar with parseLabelHash validation and createGraphQLError surfacing for client-facing parse errors. Serialize is identity (value already normalized). Consistent with existing scalar patterns.
packages/ensrainbow-sdk/src/ensrainbowbeam-client.ts Typed HTTP client for EnsRainbowBeam: client-side validation mirrors server constraints via hardcoded constants that must stay in sync manually. throwIfNotOk correctly parses error body. fetch injection and AbortSignal forwarding are clean.
docs/ensrainbow.io/src/components/organisms/HealUnknownName.tsx Beam-it UI: validates params client-side via SDK before fetching, displays per-label StatusBadge results. isSubmitting guard prevents concurrent submissions. Configurable beamUrl defaults to production endpoint.
apps/ensrainbowbeam/src/lib/error-response.ts Consistent error response helper; ZodError flattened to 400, plain Error forwarded, unknown errors produce generic 500. Mirrors monorepo convention.
apps/ensapi/src/omnigraph-api/schema/label.integration.test.ts Integration tests for Query.labels: covers healed/absent labels, duplicate deduplication, mixed-case hex normalization, invalid input rejection, and the LABELS_BY_LABELHASH_MAX cap. Good coverage of the new resolver.

Sequence Diagram

sequenceDiagram
    participant UI as Beam-it UI / SDK Client
    participant Beam as EnsRainbowBeam<br/>(POST /api/discover)
    participant Norm as ENSIP-15 Normalizer<br/>(enssdk)
    participant OG as ENSApi Omnigraph<br/>(Query.labels)
    participant DB as ENSNode DB<br/>(label table)

    UI->>Beam: "POST /api/discover {labels[], callerAddress}"
    Beam->>Beam: Zod validation (max 100 labels, valid address)
    loop each label
        Beam->>Norm: normalizeLabel(rawLabel)
        alt unnormalizable
            Norm-->>Beam: throws → skipped_unnormalized
        else normalized
            Norm-->>Beam: normalizedLabel + labelHash
        end
    end
    Beam->>Beam: collectLookupHashes (dedupe)
    Beam->>OG: "labels(by:{labelHashes:[...]}) + AbortSignal"
    OG->>OG: parseLabelHash + dedupe + cap check
    OG->>DB: SELECT WHERE labelHash IN (...)
    DB-->>OG: Label rows
    OG-->>Beam: "[{hash, interpreted}]"
    Beam->>Beam: classifySubmissions → healed/unknown/absent
    Beam->>Beam: console.log(JSONL to stdout)
    Beam-->>UI: "{callerAddress, results[]}"
Loading

Reviews (6): Last reviewed commit: "docs: update README formatting for envir..." | Re-trigger Greptile

Comment on lines +67 to +70
process.on("uncaughtException", (error) => {
console.error("[ensrainbowbeam] uncaughtException", error);
void gracefulShutdown(1);
});

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 The process registers handlers for SIGINT, SIGTERM, and uncaughtException but not unhandledRejection. Node.js fires unhandledRejection for any Promise that rejects without a .catch() handler, and while Node 15+ terminates on it by default, it bypasses the graceful closeServer() path entirely, so in-flight connections won't be drained and the exit code may be 0 instead of 1.

Suggested change
process.on("uncaughtException", (error) => {
console.error("[ensrainbowbeam] uncaughtException", error);
void gracefulShutdown(1);
});
process.on("uncaughtException", (error) => {
console.error("[ensrainbowbeam] uncaughtException", error);
void gracefulShutdown(1);
});
process.on("unhandledRejection", (reason) => {
console.error("[ensrainbowbeam] unhandledRejection", reason);
void gracefulShutdown(1);
});

Comment thread apps/ensrainbowbeam/src/handlers/submissions.ts Outdated
Comment thread apps/ensrainbowbeam/src/lib/labels.ts Outdated

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 55 out of 58 changed files in this pull request and generated no new comments.

Files not reviewed (1)
  • pnpm-lock.yaml: Language not supported

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 55 out of 58 changed files in this pull request and generated 1 comment.

Files not reviewed (1)
  • pnpm-lock.yaml: Generated file

Comment on lines +60 to +63
maskError(error, message, isDev) {
logger.error(error);
return maskError(error, message, isDev);
},

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 55 out of 58 changed files in this pull request and generated 2 comments.

Files not reviewed (1)
  • pnpm-lock.yaml: Generated file

Comment thread apps/ensrainbowbeam/src/lib/omnigraph-client.ts

const literal = (s: string) => s as LiteralLabel;

describe("hashNormalizedLabel", () => {
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add new app with endpoint for submitting labels

3 participants