-
Notifications
You must be signed in to change notification settings - Fork 0
feat: update Elysia 1.4 #157
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
Conversation
📝 WalkthroughSummary by CodeRabbit
WalkthroughMigrates backend validation from Elysia t to Zod, consolidates project schemas into a new module, revises error payload shapes, introduces a Wikibase client/registry and a new properties fetch endpoint, adjusts MediaWiki types and requests, adds a DB table, updates API docs plugin, aligns tests and frontend imports with new schemas, and bumps several dependencies. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
participant C as Client
participant API as API Route<br/>POST /wikibase/:instanceId/properties/fetch
participant S as WikibaseService
participant R as WikibaseClient Registry
participant MW as MediaWiki API
participant DB as DuckDB
rect rgba(230,245,255,0.6)
note over API,S: New properties fetch flow
C->>API: Request
API->>S: fetchAllProperties(instanceId, DB)
S->>R: getClient(instanceId)
alt client exists
R-->>S: MediaWikiApiService
else no client
R-->>S: Error (no client)
S-->>API: Throw
API-->>C: 500/404 error
end
loop Pages until no apcontinue
S->>MW: allpages query (namespace=120, continue token)
MW-->>S: Batch of properties
S->>DB: INSERT ... ON CONFLICT DO NOTHING
end
S-->>API: { total, inserted }
API-->>C: 200 { data: { total, inserted } }
end
Estimated code review effort🎯 5 (Critical) | ⏱️ ~120 minutes Possibly related PRs
Pre-merge checks and finishing touches❌ Failed checks (1 inconclusive)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests
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. Comment |
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: 22
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (4)
frontend/src/features/project-management/stores/project-list.store.ts (1)
17-21: Fix type error: pass the full error to showError instead of error.value.
showErrorexpectsExtendedError, butapiError.valueis now a union and not assignable. PassapiErrordirectly in both places.Apply this diff:
- if (apiError) { - showError(apiError.value) + if (apiError) { + showError(apiError) ... - if (apiError?.value) { - showError(apiError.value) + if (apiError?.value) { + showError(apiError) isLoading.value = false return }Also applies to: 31-34
backend/src/api/project/index.ts (2)
94-104: Ensure temp directory exists before writing
Bun.writemay fail if./tempis missing. Create it once before writing.- const fileBuffer = await file.arrayBuffer() + // Ensure temp directory exists + await Bun.$`mkdir -p ./temp` + const fileBuffer = await file.arrayBuffer()
127-141: Leak risk on “table already exists” branch
cleanupProjectis commented out here; on conflict you leave a project row and temp file behind.- if (tableExistsReader.getRows().length > 0) { - // await cleanupProject(db, project.id, tempFilePath) + if (tableExistsReader.getRows().length > 0) { + await cleanupProject(db, project.id, tempFilePath) return status( 500, ApiErrorHandler.dataImportErrorWithData( `Table with name 'project_${project.id}' already exists`, ), )backend/src/api/project/project.wikibase.ts (1)
217-223: Harden schema parsing with Zod validationGracefully validate persisted JSON and fall back to blank only on failure.
-const parseSchemaField = (schema: unknown) => { - try { - return JSON.parse(schema as string) as ItemSchema - } catch { - return blankSchema - } -} +const parseSchemaField = (schema: unknown): ItemSchema => { + try { + const raw = typeof schema === 'string' ? JSON.parse(schema) : schema + const parsed = ItemSchemaMapping.safeParse(raw) + return parsed.success ? parsed.data : blankSchema + } catch { + return blankSchema + } +}
🧹 Nitpick comments (37)
.kiro/steering/code-conventions.md (1)
156-156: Clarify schema tooling and import path.Specify Zod and the alias to remove ambiguity.
- Define schemas in `schemas.ts` files + Define Zod schemas in `schemas.ts` files; import via `@backend/api/<domain>/schemas`..kiro/steering/structure.md (1)
51-51: Name the validator to match the codebase.Call out Zod explicitly for consistency with the migration.
- Schema definitions in `schemas.ts` files + Zod schema definitions in `schemas.ts` filesbackend/src/plugins/database.ts (1)
43-50: Add uniqueness/indexes for queryability and integrity.
idis PK (good). Consider enforcing uniqueness onpageidand indexingtitleto speed lookups.CREATE TABLE IF NOT EXISTS wikibase_properties ( id TEXT PRIMARY KEY, title TEXT NOT NULL, pageid INTEGER NOT NULL, namespace INTEGER NOT NULL DEFAULT 120, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ); + CREATE UNIQUE INDEX IF NOT EXISTS wikibase_properties_pageid_uq + ON wikibase_properties(pageid); + CREATE INDEX IF NOT EXISTS wikibase_properties_title_idx + ON wikibase_properties(title);package.json (1)
23-25: Deps bump looks good; verify Zod v4 and Bun engine compatibility across the repo.
- Zod 4 introduces a default export in many setups; ensure all imports consistently use either
import z from 'zod'orimport { z } from 'zod'project-wide.- Confirm Bun >=1.2.21 in CI and containers.
- Minor: scripts already use
bun run, good. Consider removing duplicatetscalias to avoid drift.Would you like me to scan the repo for mixed Zod import styles and generate a patch?
Also applies to: 31-32, 34-34, 40-40, 53-53
backend/tests/api/project/project.get.test.ts (1)
156-166: Make the 422 assertion resilient; avoid hard-coding the UUID regex string.Matching the entire
patternstring is brittle across validator updates. Assert key fields and use partial matching.Apply:
- expect(error).toHaveProperty('value', [ - { - code: 'invalid_format', - format: 'uuid', - message: 'Invalid UUID', - origin: 'string', - path: ['projectId'], - pattern: - '/^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$/', - }, - ]) + expect(error?.value).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + code: 'invalid_format', + format: 'uuid', + message: expect.stringContaining('Invalid'), + origin: 'string', + path: ['projectId'], + }), + ]), + )Also, consider normalizing error envelopes so 404 and 422 share the same outer shape.
backend/tests/api/project/project.delete.test.ts (1)
74-84: Relax the 422 UUID assertion; don’t assert full regex literal.Mirror the approach from the GET test to reduce brittleness.
Apply:
- expect(error).toHaveProperty('value', [ - { - message: 'Invalid UUID', - code: 'invalid_format', - origin: 'string', - format: 'uuid', - path: ['projectId'], - pattern: - '/^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$/', - }, - ]) + expect(error?.value).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + code: 'invalid_format', + format: 'uuid', + origin: 'string', + path: ['projectId'], + message: expect.stringContaining('Invalid'), + }), + ]), + )backend/src/api/_meta_projects.ts (3)
8-25: Name the schema and type distinctly to avoid shadowing.Use
MetaProjectSchemafor the Zod object andMetaProjectfor the inferred type to improve clarity.Apply:
-const MetaProject = z.object({ +const MetaProjectSchema = z.object({ id: z.string(), name: z.string(), schema_for: z.union([z.string(), z.null()]), schema: z.any(), created_at: z.string(), updated_at: z.string(), wikibase_schema: z.array( z.object({ id: z.string(), wikibase: z.string(), name: z.string(), created_at: z.string(), updated_at: z.string(), }), ), }) -type MetaProject = z.infer<typeof MetaProject> +type MetaProject = z.infer<typeof MetaProjectSchema>
67-75: Safeguard JSON.parse to prevent 500s on malformed rows.A single bad row will throw. Wrap parse in try/catch.
Apply:
- const data = reader.getRowObjectsJson().map((row) => { + const data = reader.getRowObjectsJson().map((row) => { const newRow: Record<string, unknown> = { ...row } jsonColumns.forEach((column) => { if (newRow[column] && typeof newRow[column] === 'string') { - newRow[column] = JSON.parse(newRow[column] as string) + try { + newRow[column] = JSON.parse(newRow[column] as string) + } catch { + // keep original string if not valid JSON + } } }) - return newRow as MetaProject + return newRow as MetaProject })If you adopt the naming change above, also replace the cast with
as MetaProjectaccordingly.
81-83: Response schema uses Zod — ensure OpenAPI generation supports it.If
@elysiajs/openapiisn’t configured for Zod, switch to the project-standard adapter or generate OpenAPI via the Zod plugin.Optionally export
MetaProjectSchemaand reuse it in consumers to avoid drift.backend/src/types/wikibase-schema.ts (2)
9-14: Preferz.enumfor ranks (clearer and marginally faster).Functionally equivalent but terser and intent-revealing.
-export const StatementRank = z.union([ - z.literal('preferred'), - z.literal('normal'), - z.literal('deprecated'), -]) +export const StatementRank = z.enum(['preferred', 'normal', 'deprecated'])
16-28: Considerz.enum(and verify completeness of data types you intend to support).
z.enumimproves readability. Also, confirm whether you need additional Wikibase types (e.g., geo-shape, tabular-data, math, musical-notation, lexeme variants). If you only support a subset, add a comment stating so.-export const WikibaseDataType = z.union([ - z.literal('string'), - z.literal('wikibase-item'), - z.literal('wikibase-property'), - z.literal('quantity'), - z.literal('time'), - z.literal('globe-coordinate'), - z.literal('url'), - z.literal('external-id'), - z.literal('monolingualtext'), - z.literal('commonsMedia'), -]) +export const WikibaseDataType = z.enum([ + 'string', + 'wikibase-item', + 'wikibase-property', + 'quantity', + 'time', + 'globe-coordinate', + 'url', + 'external-id', + 'monolingualtext', + 'commonsMedia', +])backend/src/types/error-schemas.ts (2)
6-20: Optional: convert union of literals toz.enumfor error codes.Cleaner and simpler to extend.
-export const ErrorCodeSchema = z.union([ - z.literal('VALIDATION'), - z.literal('MISSING_FILE_PATH'), - z.literal('MISSING_FILE'), - z.literal('INVALID_FILE_TYPE'), - z.literal('EMPTY_FILE'), - z.literal('FILE_NOT_FOUND'), - z.literal('TABLE_ALREADY_EXISTS'), - z.literal('INTERNAL_SERVER_ERROR'), - z.literal('DATABASE_ERROR'), - z.literal('PROJECT_CREATION_FAILED'), - z.literal('DATA_IMPORT_FAILED'), - z.literal('INVALID_JSON'), - z.literal('NOT_FOUND'), -]) +export const ErrorCodeSchema = z.enum([ + 'VALIDATION', + 'MISSING_FILE_PATH', + 'MISSING_FILE', + 'INVALID_FILE_TYPE', + 'EMPTY_FILE', + 'FILE_NOT_FOUND', + 'TABLE_ALREADY_EXISTS', + 'INTERNAL_SERVER_ERROR', + 'DATABASE_ERROR', + 'PROJECT_CREATION_FAILED', + 'DATA_IMPORT_FAILED', + 'INVALID_JSON', + 'NOT_FOUND', +])
39-41: Docstring mismatch with implementation.Comment says “with data array” but the schema has no
datafield.-/** - * Error response with data array - */ +/** + * Standard error response (array of errors) + */frontend/src/features/project-management/stores/project-list.store.ts (1)
12-24: Reduce loading-state duplication with finally.
Keeps state consistent on early returns and failures.Apply this diff:
- const fetchProjects = async () => { - isLoading.value = true - - const { data, error: apiError } = await api.project.get() - - if (apiError) { - showError(apiError) - } else { - projects.value = data.data - } - - isLoading.value = false - } + const fetchProjects = async () => { + isLoading.value = true + try { + const { data, error: apiError } = await api.project.get() + if (apiError) return showError(apiError) + projects.value = data.data + } finally { + isLoading.value = false + } + } @@ - const deleteProject = async (projectId: string) => { - isLoading.value = true - - const { error: apiError } = await api.project({ projectId }).delete() - - if (apiError?.value) { - showError(apiError) - isLoading.value = false - return - } - - // Remove from local state - projects.value = projects.value.filter((p) => p.id !== projectId) - isLoading.value = false - } + const deleteProject = async (projectId: string) => { + isLoading.value = true + try { + const { error: apiError } = await api.project({ projectId }).delete() + if (apiError?.value) return showError(apiError) + projects.value = projects.value.filter((p) => p.id !== projectId) + } finally { + isLoading.value = false + } + }Also applies to: 26-40
backend/tests/api/project/project.wikibase.test.ts (1)
265-275: Updated error shape assertion is consistent for 404s.
Good shift to{ value: { errors: [...] } }. Note: other tests use a flat array for validation errors—keep that duality documented.Consider a shared
expectApiErrorhelper to handle both shapes (object vs array) to avoid duplication.backend/tests/api/project/project.create.test.ts (1)
49-56: Validation error assertions match the new Zod-driven shape.
Keeps messages specific; good.Extract a reusable matcher for Zod error arrays to DRY up test code across suites.
Also applies to: 67-76
backend/src/services/mediawiki-api.service.ts (1)
39-45: Broaden public param types to match coercionAlign
get/postparams with the new coercion and prevent accidental type widening at call sites.- async get<T = any>(params: Record<string, any>): Promise<ApiResponse<T>> { + async get<T = any>(params: Record<string, string | number | boolean | null | undefined>): Promise<ApiResponse<T>> { return this.request<T>(params, 'GET') } - async post<T = any>(params: Record<string, any>): Promise<ApiResponse<T>> { + async post<T = any>(params: Record<string, string | number | boolean | null | undefined>): Promise<ApiResponse<T>> { return this.request<T>(params, 'POST') }backend/tests/api/project/project.import-file.test.ts (5)
80-93: Avoid asserting on fragile numeric validator codesHard-coding
type: 31etc. is brittle across validator/runtime upgrades. Prefer message/path/schema checks and relax type to a number.- expect(error).toHaveProperty('value', [ - { - errors: [], - message: "Expected kind 'File'", - path: '/file', - schema: { - default: 'File', - format: 'binary', - minSize: 1, - type: 'string', - }, - type: 31, - }, - ]) + expect(error.value).toEqual([ + expect.objectContaining({ + path: '/file', + message: expect.stringContaining("Expected"), + schema: expect.objectContaining({ format: 'binary' }), + type: expect.any(Number), + }), + ])
104-118: Relax expectations for empty-file validation detailsSame concern as above; keep tests resilient to library changes.
- expect(error).toHaveProperty('value', [ - { - errors: [], - path: '/file', - message: "Expected kind 'File'", - schema: { - default: 'File', - format: 'binary', - minSize: 1, - type: 'string', - }, - type: 31, - value: {}, - }, - ]) + expect(error.value).toEqual([ + expect.objectContaining({ + path: '/file', + message: expect.stringContaining('Expected'), + schema: expect.objectContaining({ minSize: 1 }), + type: expect.any(Number), + }), + ])
134-148: Stabilize string-length assertionsAssert on message and limits, not numeric code.
- expect(error).toHaveProperty('value', [ - { - errors: [], - path: '/name', - message: 'Expected string length less or equal to 255', - schema: { - error: 'Project name must be between 1 and 255 characters long if provided', - maxLength: 255, - minLength: 1, - type: 'string', - }, - type: 51, - value: longName, - }, - ]) + expect(error.value).toEqual([ + expect.objectContaining({ + path: '/name', + message: expect.stringContaining('less or equal to 255'), + schema: expect.objectContaining({ maxLength: 255 }), + type: expect.any(Number), + }), + ])
163-177: Same: keep min-length validation robust- expect(error).toHaveProperty('value', [ - { - errors: [], - path: '/name', - message: 'Expected string length greater or equal to 1', - schema: { - error: 'Project name must be between 1 and 255 characters long if provided', - maxLength: 255, - minLength: 1, - type: 'string', - }, - type: 52, - value: '', - }, - ]) + expect(error.value).toEqual([ + expect.objectContaining({ + path: '/name', + message: expect.stringContaining('greater or equal to 1'), + schema: expect.objectContaining({ minLength: 1 }), + type: expect.any(Number), + }), + ])
29-38: Temp directory cleanup may target the wrong path
new URL('../../temp', import.meta.url)resolves tobackend/tests/temp, but the routes write to./temp. Consider aligning paths to prevent leaks.Want a small helper to centralize the temp dir path shared between app and tests?
backend/src/services/wikibase-clients.ts (1)
5-43: Prefer Map over Record for client registryAvoid prototype key collisions and enable O(1) existence/size ops.
-export class WikibaseClient { - private clients: Record<string, MediaWikiApiService> = { - wikidata: new MediaWikiApiService({ +export class WikibaseClient { + private clients = new Map<string, MediaWikiApiService>([ + ['wikidata', new MediaWikiApiService({ endpoint: 'https://www.wikidata.org/w/api.php', userAgent: 'DataForge/1.0 (https://github.com/DaxServer/dataforge)', timeout: 30000, - }), - } + })], + ]) @@ - this.clients[id] = client + this.clients.set(id, client) @@ - const client = this.clients[instanceId] + const client = this.clients.get(instanceId) @@ - return this.clients[instanceId] !== undefined + return this.clients.has(instanceId) @@ - const clientRemoved = this.clients[instanceId] !== undefined - delete this.clients[instanceId] - return clientRemoved + return this.clients.delete(instanceId)backend/src/api/project/index.ts (1)
165-185: DuckDB DDL: transactions + checkpoint — nice; add NOT NULL for clarityPrimary key implies NOT NULL, but being explicit improves pragma introspection consistency.
- ADD COLUMN "${primaryKeyColumnName}" BIGINT DEFAULT nextval('project_${project.id}_${primaryKeyColumnName}_seq'); + ADD COLUMN "${primaryKeyColumnName}" BIGINT NOT NULL DEFAULT nextval('project_${project.id}_${primaryKeyColumnName}_seq');backend/src/api/project/project.wikibase.ts (4)
125-133: Validate timestamp fields as RFC 3339 datetimesStrengthen response contracts for created_at/updated_at.
const WikibaseSchemaResponse = z.object({ id: UUIDPattern, project_id: UUIDPattern, name: SchemaName, wikibase: z.string(), schema: ItemSchemaMapping, - created_at: z.string(), - updated_at: z.string(), + created_at: z.string().datetime(), + updated_at: z.string().datetime(), })
142-150: Avoid duplicate defaults; rely on schema defaults (wikibase)Define default once in the Zod schema and remove handler default for wikibase.
// Body schema - wikibase: z.string().default('wikidata').optional(), + wikibase: z.string().default('wikidata'), // Handler - async ({ db, body: { schemaId = Bun.randomUUIDv7(), projectId, name, wikibase = 'wikidata', schema = blankSchema }, status }) => { + async ({ db, body: { schemaId = Bun.randomUUIDv7(), projectId, name, wikibase, schema = blankSchema }, status }) => {Also applies to: 265-279
266-266: Verify Bun.randomUUIDv7 availability or use crypto.randomUUIDElysia/Bun environments may not have Bun.randomUUIDv7 in all versions.
-async ({ db, body: { schemaId = Bun.randomUUIDv7(), projectId, name, wikibase, schema = blankSchema }, status }) => { +async ({ db, body: { schemaId = (globalThis as any).Bun?.randomUUIDv7?.() ?? crypto.randomUUID(), projectId, name, wikibase, schema = blankSchema }, status }) => {If you target a Bun version that guarantees randomUUIDv7, keep your original line. Otherwise, prefer the fallback.
336-345: created_at/updated_at exist but updated_at is not auto-updated on UPDATEFound: backend/src/plugins/database.ts declares created_at and updated_at with DEFAULT CURRENT_TIMESTAMP (lines ~39–40). No DB trigger or ON UPDATE clause was found. The UPDATE in backend/src/api/project/project.wikibase.ts (lines ~336–345) explicitly sets updated_at. Ensure either every UPDATE path sets updated_at explicitly or add a DB trigger to set updated_at = CURRENT_TIMESTAMP on UPDATE.
backend/src/services/wikibase.service.ts (3)
63-69: Safer property ID extractionTitles in ns=120 are prefixed. Ensure we only strip the leading namespace.
- id: page.title.replace('Property:', ''), + id: page.title.replace(/^Property:/, ''),
105-116: Add formatVersion for consistent fields in wbsearchentitiesAlign with item search and ensure aliases/pageid/title presence.
const searchParams: Record<string, string | number | boolean> = { action: 'wbsearchentities', search: query, type: 'property', language: options.language, uselang: options.language, limit: options.limit, continue: options.offset, format: 'json', + formatVersion: 2, strictlanguage: !languageFallback, }
76-81: “inserted” counts include REPLACE operationsIf you want “inserted” vs “updated”, consider separate counters or use UPSERT metadata if available.
backend/src/api/project/schemas.ts (3)
10-11: Static regex; safe from ReDoS (document to silence tools)Add a note to clarify the pattern is static.
-export const UUID_REGEX_PATTERN = new RegExp(UUID_REGEX, 'i') +export const UUID_REGEX_PATTERN = new RegExp(UUID_REGEX, 'i') // safe: static, bounded pattern
22-25: Constrain pagination to non-negative integersexport const PaginationQuery = z.object({ - offset: z.coerce.number().default(0).optional(), - limit: z.coerce.number().default(25).optional(), + offset: z.coerce.number().int().min(0).default(0).optional(), + limit: z.coerce.number().int().min(1).max(1000).default(25).optional(), })
124-139: Mixing t. and zod: acceptable, but consider unifying*If Elysia 1.4 file validation is stable for zod, consider a zod-based multipart schema for consistency.
backend/src/api/wikibase/schemas.ts (3)
83-96: Model sitelinks with SiteLinkSchemaAvoid z.any for better guarantees.
export const ItemDetailsSchema = z.object({ id: z.string(), pageid: z.number().optional(), ns: z.number().optional(), title: z.string().optional(), lastrevid: z.number().optional(), modified: z.string().optional(), type: z.literal('item'), labels: z.record(z.string(), z.string()).optional(), descriptions: z.record(z.string(), z.string()).optional(), aliases: z.record(z.string(), z.array(z.string())).optional(), claims: z.record(z.string(), z.array(z.any())).optional(), - sitelinks: z.record(z.string(), z.any()).optional(), + sitelinks: z.record(z.string(), SiteLinkSchema).optional(), })
319-327: Coerce query params for item search limit/offsetQuery strings arrive as strings; coerce to numbers.
query: z.object({ q: z.string().describe('Search query for items'), instance: InstanceId.optional(), - limit: z.number().default(10).describe('Maximum number of results').optional(), - offset: z.number().default(0).describe('Offset for pagination').optional(), + limit: z.coerce.number().default(10).describe('Maximum number of results').optional(), + offset: z.coerce.number().default(0).describe('Offset for pagination').optional(), language: z.string().default('en').describe('Language code for search results').optional(), languageFallback: z.boolean().default(true).describe('Enable language fallback').optional(), }),
369-375: Use PropertyId in violation/warning shapesexport const ConstraintViolationSchema = z.object({ constraintType: z.string(), message: z.string(), severity: z.union([z.literal('error'), z.literal('warning')]), - propertyId: z.string(), + propertyId: PropertyId, value: z.optional(z.any()), }) export const ConstraintWarningSchema = z.object({ constraintType: z.string(), message: z.string(), - propertyId: z.string(), + propertyId: PropertyId, })Also applies to: 377-382
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
bun.lockis excluded by!**/*.lock
📒 Files selected for processing (50)
.kiro/steering/code-conventions.md(1 hunks).kiro/steering/structure.md(1 hunks)backend/package.json(1 hunks)backend/src/api/_meta_projects.ts(3 hunks)backend/src/api/project/_schemas.ts(0 hunks)backend/src/api/project/import.ts(2 hunks)backend/src/api/project/index.ts(6 hunks)backend/src/api/project/project.create.ts(0 hunks)backend/src/api/project/project.delete.ts(0 hunks)backend/src/api/project/project.get-all.ts(0 hunks)backend/src/api/project/project.get.ts(0 hunks)backend/src/api/project/project.import-file.ts(0 hunks)backend/src/api/project/project.wikibase.ts(7 hunks)backend/src/api/project/schemas.ts(1 hunks)backend/src/api/wikibase/entities.ts(3 hunks)backend/src/api/wikibase/schemas.ts(12 hunks)backend/src/index.ts(2 hunks)backend/src/plugins/database.ts(1 hunks)backend/src/plugins/error-handler.ts(1 hunks)backend/src/services/mediawiki-api.service.ts(1 hunks)backend/src/services/wikibase-clients.ts(1 hunks)backend/src/services/wikibase.service.ts(6 hunks)backend/src/types/error-handler.ts(0 hunks)backend/src/types/error-schemas.ts(1 hunks)backend/src/types/mediawiki-api.ts(2 hunks)backend/src/types/wikibase-api.ts(1 hunks)backend/src/types/wikibase-schema.ts(1 hunks)backend/src/utils/duckdb-types.ts(1 hunks)backend/tests/api/project/import-file.test.ts(1 hunks)backend/tests/api/project/import.test.ts(0 hunks)backend/tests/api/project/project.create.test.ts(3 hunks)backend/tests/api/project/project.delete.test.ts(2 hunks)backend/tests/api/project/project.get-all.test.ts(0 hunks)backend/tests/api/project/project.get.test.ts(4 hunks)backend/tests/api/project/project.import-file.test.ts(5 hunks)backend/tests/api/project/project.wikibase.test.ts(1 hunks)backend/tests/api/wikibase/entities.test.ts(0 hunks)backend/tests/error-handler.test.ts(0 hunks)frontend/package.json(1 hunks)frontend/src/features/data-processing/composables/__tests__/useColumnGeneration.test.ts(1 hunks)frontend/src/features/data-processing/composables/useColumnGeneration.ts(1 hunks)frontend/src/features/project-management/composables/useProjectCreationComposable.ts(0 hunks)frontend/src/features/project-management/stores/project-list.store.ts(1 hunks)frontend/src/features/project-management/stores/project.store.ts(1 hunks)frontend/src/features/wikibase-schema/composables/__tests__/useSchemaApi.test.ts(0 hunks)frontend/src/features/wikibase-schema/composables/useSchemaApi.ts(0 hunks)frontend/src/features/wikibase-schema/stores/schema.store.ts(0 hunks)frontend/src/shared/types/client-errors.ts(0 hunks)guidelines/reference/TESTING.md(1 hunks)package.json(2 hunks)
💤 Files with no reviewable changes (16)
- frontend/src/features/project-management/composables/useProjectCreationComposable.ts
- backend/tests/api/project/project.get-all.test.ts
- frontend/src/features/wikibase-schema/composables/tests/useSchemaApi.test.ts
- backend/src/api/project/_schemas.ts
- backend/tests/api/wikibase/entities.test.ts
- backend/src/api/project/project.delete.ts
- backend/tests/api/project/import.test.ts
- backend/tests/error-handler.test.ts
- frontend/src/features/wikibase-schema/stores/schema.store.ts
- backend/src/api/project/project.create.ts
- frontend/src/features/wikibase-schema/composables/useSchemaApi.ts
- backend/src/api/project/project.get-all.ts
- frontend/src/shared/types/client-errors.ts
- backend/src/api/project/project.import-file.ts
- backend/src/types/error-handler.ts
- backend/src/api/project/project.get.ts
🧰 Additional context used
📓 Path-based instructions (4)
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (.cursor/rules/use-bun-instead-of-node-vite-npm-pnpm.mdc)
**/*.{ts,tsx,js,jsx}: Usebun <file>instead ofnode <file>orts-node <file>for running TypeScript or JavaScript files
Do not use dotenv; Bun automatically loads .env files
UseBun.serve()for HTTP servers and WebSockets instead ofexpress
Usebun:sqlitefor SQLite instead ofbetter-sqlite3
UseBun.redisfor Redis instead ofioredis
UseBun.sqlfor Postgres instead ofpgorpostgres.js
Use built-inWebSocketinstead ofws
PreferBun.fileovernode:fs's readFile/writeFile
UseBun.$(e.g.,Bun.$ls``) instead of execa for running shell commands
Files:
frontend/src/features/data-processing/composables/__tests__/useColumnGeneration.test.tsbackend/src/plugins/error-handler.tsbackend/src/services/wikibase-clients.tsbackend/tests/api/project/project.wikibase.test.tsbackend/src/types/wikibase-api.tsbackend/src/plugins/database.tsbackend/src/utils/duckdb-types.tsfrontend/src/features/project-management/stores/project.store.tsfrontend/src/features/data-processing/composables/useColumnGeneration.tsbackend/src/types/wikibase-schema.tsbackend/tests/api/project/project.delete.test.tsbackend/tests/api/project/project.get.test.tsfrontend/src/features/project-management/stores/project-list.store.tsbackend/src/index.tsbackend/tests/api/project/import-file.test.tsbackend/src/services/mediawiki-api.service.tsbackend/tests/api/project/project.create.test.tsbackend/src/types/error-schemas.tsbackend/src/api/project/project.wikibase.tsbackend/src/api/_meta_projects.tsbackend/src/api/wikibase/entities.tsbackend/tests/api/project/project.import-file.test.tsbackend/src/types/mediawiki-api.tsbackend/src/api/project/import.tsbackend/src/services/wikibase.service.tsbackend/src/api/project/schemas.tsbackend/src/api/project/index.tsbackend/src/api/wikibase/schemas.ts
**/*.test.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (.cursor/rules/use-bun-instead-of-node-vite-npm-pnpm.mdc)
Use
bun testinstead ofjestfor running tests
Files:
frontend/src/features/data-processing/composables/__tests__/useColumnGeneration.test.tsbackend/tests/api/project/project.wikibase.test.tsbackend/tests/api/project/project.delete.test.tsbackend/tests/api/project/project.get.test.tsbackend/tests/api/project/import-file.test.tsbackend/tests/api/project/project.create.test.tsbackend/tests/api/project/project.import-file.test.ts
**/*.{html,ts,tsx,css}
📄 CodeRabbit inference engine (.cursor/rules/use-bun-instead-of-node-vite-npm-pnpm.mdc)
Use
bun build <file.html|file.ts|file.css>instead ofwebpackoresbuildfor building HTML, TypeScript, or CSS files
Files:
frontend/src/features/data-processing/composables/__tests__/useColumnGeneration.test.tsbackend/src/plugins/error-handler.tsbackend/src/services/wikibase-clients.tsbackend/tests/api/project/project.wikibase.test.tsbackend/src/types/wikibase-api.tsbackend/src/plugins/database.tsbackend/src/utils/duckdb-types.tsfrontend/src/features/project-management/stores/project.store.tsfrontend/src/features/data-processing/composables/useColumnGeneration.tsbackend/src/types/wikibase-schema.tsbackend/tests/api/project/project.delete.test.tsbackend/tests/api/project/project.get.test.tsfrontend/src/features/project-management/stores/project-list.store.tsbackend/src/index.tsbackend/tests/api/project/import-file.test.tsbackend/src/services/mediawiki-api.service.tsbackend/tests/api/project/project.create.test.tsbackend/src/types/error-schemas.tsbackend/src/api/project/project.wikibase.tsbackend/src/api/_meta_projects.tsbackend/src/api/wikibase/entities.tsbackend/tests/api/project/project.import-file.test.tsbackend/src/types/mediawiki-api.tsbackend/src/api/project/import.tsbackend/src/services/wikibase.service.tsbackend/src/api/project/schemas.tsbackend/src/api/project/index.tsbackend/src/api/wikibase/schemas.ts
package.json
📄 CodeRabbit inference engine (.cursor/rules/use-bun-instead-of-node-vite-npm-pnpm.mdc)
package.json: Usebun installinstead ofnpm install,yarn install, orpnpm installfor dependency installation
Usebun run <script>instead ofnpm run <script>,yarn run <script>, orpnpm run <script>for running scripts
Files:
package.json
🧠 Learnings (8)
📚 Learning: 2025-07-20T14:13:40.153Z
Learnt from: CR
PR: DaxServer/dataforge#0
File: .cursor/rules/use-bun-instead-of-node-vite-npm-pnpm.mdc:0-0
Timestamp: 2025-07-20T14:13:40.153Z
Learning: Applies to package.json : Use `bun install` instead of `npm install`, `yarn install`, or `pnpm install` for dependency installation
Applied to files:
package.json
📚 Learning: 2025-07-20T14:13:40.153Z
Learnt from: CR
PR: DaxServer/dataforge#0
File: .cursor/rules/use-bun-instead-of-node-vite-npm-pnpm.mdc:0-0
Timestamp: 2025-07-20T14:13:40.153Z
Learning: For more information, read the official Bun documentation at https://bun.sh/docs or check `node_modules/bun-types/docs/**.md` if available locally
Applied to files:
package.json
📚 Learning: 2025-07-20T14:13:40.153Z
Learnt from: CR
PR: DaxServer/dataforge#0
File: .cursor/rules/use-bun-instead-of-node-vite-npm-pnpm.mdc:0-0
Timestamp: 2025-07-20T14:13:40.153Z
Learning: Applies to package.json : Use `bun run <script>` instead of `npm run <script>`, `yarn run <script>`, or `pnpm run <script>` for running scripts
Applied to files:
package.json
📚 Learning: 2025-07-20T14:13:40.153Z
Learnt from: CR
PR: DaxServer/dataforge#0
File: .cursor/rules/use-bun-instead-of-node-vite-npm-pnpm.mdc:0-0
Timestamp: 2025-07-20T14:13:40.153Z
Learning: Applies to **/*.{html,ts,tsx,css} : Use `bun build <file.html|file.ts|file.css>` instead of `webpack` or `esbuild` for building HTML, TypeScript, or CSS files
Applied to files:
package.json
📚 Learning: 2025-07-20T14:13:40.153Z
Learnt from: CR
PR: DaxServer/dataforge#0
File: .cursor/rules/use-bun-instead-of-node-vite-npm-pnpm.mdc:0-0
Timestamp: 2025-07-20T14:13:40.153Z
Learning: Applies to **/*.{ts,tsx,js,jsx} : Use `bun <file>` instead of `node <file>` or `ts-node <file>` for running TypeScript or JavaScript files
Applied to files:
package.json
📚 Learning: 2025-07-20T14:13:40.153Z
Learnt from: CR
PR: DaxServer/dataforge#0
File: .cursor/rules/use-bun-instead-of-node-vite-npm-pnpm.mdc:0-0
Timestamp: 2025-07-20T14:13:40.153Z
Learning: Applies to **/*.{ts,tsx,js,jsx} : Use `Bun.$` (e.g., `Bun.$`ls``) instead of execa for running shell commands
Applied to files:
package.json
📚 Learning: 2025-07-20T14:13:40.153Z
Learnt from: CR
PR: DaxServer/dataforge#0
File: .cursor/rules/use-bun-instead-of-node-vite-npm-pnpm.mdc:0-0
Timestamp: 2025-07-20T14:13:40.153Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Use `bun test` instead of `jest` for running tests
Applied to files:
package.json
📚 Learning: 2025-07-20T14:13:40.153Z
Learnt from: CR
PR: DaxServer/dataforge#0
File: .cursor/rules/use-bun-instead-of-node-vite-npm-pnpm.mdc:0-0
Timestamp: 2025-07-20T14:13:40.153Z
Learning: Applies to **/*.{ts,tsx,js,jsx} : Use `bun:sqlite` for SQLite instead of `better-sqlite3`
Applied to files:
package.json
🧬 Code graph analysis (10)
backend/src/services/wikibase-clients.ts (2)
backend/src/services/mediawiki-api.service.ts (1)
MediaWikiApiService(3-80)backend/src/types/mediawiki-api.ts (1)
MediaWikiConfig(12-19)
backend/src/services/mediawiki-api.service.ts (1)
backend/src/types/mediawiki-api.ts (1)
ApiResponse(307-314)
backend/src/types/error-schemas.ts (1)
backend/src/types/mediawiki-api.ts (1)
ApiError(295-298)
backend/src/api/project/project.wikibase.ts (3)
backend/src/types/wikibase-schema.ts (8)
PropertyId(6-6)PropertyId(7-7)WikibaseDataType(16-27)WikibaseDataType(28-28)StatementRank(9-13)StatementRank(14-14)ItemId(3-3)ItemId(4-4)backend/src/api/project/schemas.ts (2)
UUIDPattern(11-11)ProjectParams(37-39)backend/src/types/error-schemas.ts (2)
ApiError(41-43)ApiError(49-49)
backend/src/api/wikibase/entities.ts (2)
backend/src/api/wikibase/schemas.ts (1)
WikibasePropertiesFetchSchema(475-491)backend/src/types/error-handler.ts (1)
ApiErrorHandler(6-210)
backend/src/types/mediawiki-api.ts (2)
backend/src/types/wikibase-schema.ts (2)
WikibaseDataType(16-27)WikibaseDataType(28-28)backend/src/api/wikibase/schemas.ts (1)
Term(34-34)
backend/src/services/wikibase.service.ts (3)
backend/src/services/wikibase-clients.ts (1)
WikibaseClient(4-43)backend/src/types/wikibase-api.ts (3)
SearchOptions(121-126)SearchResponse(128-133)PropertySearchResult(84-93)backend/src/api/wikibase/schemas.ts (1)
PropertySearchResult(50-50)
backend/src/api/project/schemas.ts (1)
backend/src/types/error-schemas.ts (2)
ApiError(41-43)ApiError(49-49)
backend/src/api/project/index.ts (1)
backend/src/api/project/schemas.ts (2)
Project(20-20)ProjectParams(37-39)
backend/src/api/wikibase/schemas.ts (3)
backend/src/types/wikibase-schema.ts (6)
WikibaseDataType(16-27)WikibaseDataType(28-28)PropertyId(6-6)PropertyId(7-7)ItemId(3-3)ItemId(4-4)backend/src/types/wikibase-api.ts (1)
PropertySearchResult(84-93)backend/src/types/error-schemas.ts (2)
ApiError(41-43)ApiError(49-49)
🪛 GitHub Actions: Typecheck code
frontend/src/features/project-management/stores/project-list.store.ts
[error] 32-32: TS2345: Argument of type '{ errors: any[]; } | { type: 'validation'; on: string; summary?: string | undefined; message?: string | undefined; found?: unknown; property?: string | undefined; expected?: string | undefined; }' is not assignable to parameter of type 'ExtendedError'.
[error] 32-32: TS2345: Property 'errors' is missing in type '{ type: 'validation'; on: string; summary?: string | undefined; message?: string | undefined; found?: unknown; property?: string | undefined; expected?: string | undefined; }' but required in type 'ExtendedError'.
backend/src/api/project/index.ts
[error] 6-6: TypeScript error TS6133: 'ProjectDeleteSchema' is declared but its value is never read.
[error] 6-6: TypeScript error TS6133: 'ProjectDeleteSchema' is declared but its value is never read.
🪛 ast-grep (0.38.6)
backend/src/api/project/schemas.ts
[warning] 9-9: Regular expression constructed from variable input detected. This can lead to Regular Expression Denial of Service (ReDoS) attacks if the variable contains malicious patterns. Use libraries like 'recheck' to validate regex safety or use static patterns.
Context: new RegExp(UUID_REGEX, 'i')
Note: [CWE-1333] Inefficient Regular Expression Complexity [REFERENCES]
- https://owasp.org/www-community/attacks/Regular_expression_Denial_of_Service_-_ReDoS
- https://cwe.mitre.org/data/definitions/1333.html
(regexp-from-variable)
🔇 Additional comments (34)
backend/package.json (1)
19-24: Catalog mappings verified — Elysia 1.4.x are pinned; zod is caret (^4.0.0).
bun.lock (catalog) shows elysia → 1.4.4; @elysiajs/cors, eden, openapi → 1.4.0; backend/package.json uses "catalog:" tokens; zod → ^4.0.0 — tighten the catalog zod entry to an exact or narrower range if you want to avoid silent drift.frontend/package.json (1)
60-64: LGTM on dev tooling bumps.Minor version bumps for Vite, devtools, and vue-tsc look safe.
backend/src/plugins/error-handler.ts (1)
17-17: Normalize validation error shape; return stable issues arrayFile: backend/src/plugins/error-handler.ts (line 17)
Do not return framework-specific error.valueError; map to an issues[] with a safe fallback.
- return [error.valueError] + const issues = + (error as any)?.valueError?.issues ?? + (error as any)?.cause?.issues ?? + (Array.isArray((error as any)?.errors) ? (error as any).errors : null) + return issues ?? [{ message: 'Validation failed' }]Verification: ran
rg -nC2 -g '!**/node_modules/**' '422|VALIDATION|issues' backend/tests frontend— no matches found. Confirm whether tests or other callers expect an 'issues' array before applying this change.backend/tests/api/project/project.get.test.ts (3)
202-202: No-op reordering of query keys.Key order is irrelevant; keeping a consistent style is fine.
213-213: No-op reordering of query keys.Looks good.
268-268: No-op reordering of query keys.Looks good.
backend/src/api/_meta_projects.ts (2)
5-6: Confirm Zod is registered with Elysia/OpenAPI.If the app isn’t using a Zod adapter,
responseschemas won’t validate or document correctly.Do you want me to add the Zod adapter wiring in
backend/index.tsas a follow-up?
43-45: LGTM — SQL CASE formatting change only.No functional change.
backend/src/types/mediawiki-api.ts (1)
15-16: Making userAgent/timeout optional is fine.Ensure sensible defaults in the service layer.
backend/src/types/wikibase-schema.ts (1)
3-4: Enforce positive-integer Q/P IDs; don’t rely on z.templateLiteral unless Zod v4 is presentpackage.json has no zod entry; cannot assume z.templateLiteral is available — replace with a regex-based string validator (or install zod@^4 and use templateLiteral with z.number().int().min(1)).
File: backend/src/types/wikibase-schema.ts (lines 3-4, 6-7)
export const ItemId = z.string().regex(/^Q[1-9]\d*$/, { message: 'ItemId must be Q followed by a positive integer' }) export type ItemId = z.infer<typeof ItemId> export const PropertyId = z.string().regex(/^P[1-9]\d*$/, { message: 'PropertyId must be P followed by a positive integer' }) export type PropertyId = z.infer<typeof PropertyId>Alternative (only if you add zod@^4):
z.templateLiteral([z.literal('Q'), z.number().int().min(1)]) z.templateLiteral([z.literal('P'), z.number().int().min(1)])backend/src/utils/duckdb-types.ts (1)
1-1: LGTM: import path update aligns with centralized schemas module.frontend/src/features/project-management/stores/project.store.ts (1)
1-1: LGTM: type import switched to centralschemasbarrel.frontend/src/features/data-processing/composables/__tests__/useColumnGeneration.test.ts (1)
1-1: LGTM: test type import tracks backend schema consolidation.frontend/src/features/data-processing/composables/useColumnGeneration.ts (1)
1-1: Import path update looks correct.
Matches the centralized schemas module. No further action.guidelines/reference/TESTING.md (1)
89-89: Doc snippet import path updated correctly.
Aligns with the new centralized module.frontend/src/features/project-management/stores/project-list.store.ts (1)
1-1: TS path alias verified — no action required.
frontend/tsconfig.json maps "@backend/" → "../backend/src/" and backend/src/api/project/schemas.ts exportsexport type Project = ...(so the import is resolvable).backend/src/index.ts (2)
21-31: Double-check OpenAPI scalar config block.
If the plugin expectsscalarat the top level, this is fine; otherwise, adjust per the installed version’s docs.Would you like me to look up the exact option names for your installed version and propose an exact config?
10-10: Confirm @elysiajs/openapi version supportsscalaroptionbackend/package.json reports "@elysiajs/openapi": "catalog:" — no semver found so compatibility can’t be verified. Provide the exact dependency line or a lockfile entry (pnpm-lock.yaml / yarn.lock / package-lock.json), or run
rg -n "@elysiajs/openapi" backendand paste the output so I can confirm whether thescalaroption is supported.backend/tests/api/project/import-file.test.ts (1)
67-81: 422 validation expectation aligned with new flat array error shape.
Looks correct for file validation errors.backend/tests/api/project/project.create.test.ts (1)
2-2: Import path migration to centralized schemas is correct.
No action needed.backend/src/api/project/import.ts (2)
21-25: Revisit comment: Elysia 1.3.x note.
You’re targeting Elysia 1.4; re-validate whether file type validation is still disabled and update the comment accordingly.
10-11: Response 201 asz.null()vs tests expecting empty.
If clients/tests expect empty object, considerz.object({}).strict()to avoidnullvs{}mismatch.I can adjust to
{}and update any dependent tests if desired.backend/src/services/mediawiki-api.service.ts (1)
26-37: Authentication likely needs cookie persistenceNode/Bun fetch typically doesn’t maintain a cookie jar between requests. If
authenticate()is used, you may need explicit cookie handling.Would you like me to add a lightweight cookie jar for Bun (store
Set-Cookieand sendCookieon subsequent calls)?backend/tests/api/project/project.import-file.test.ts (1)
2-2: Import path change looks correctUUID pattern sourced from centralized schemas is consistent with the PR direction.
backend/src/services/wikibase-clients.ts (2)
5-11: Preloaded wikidata client: good defaultSensible defaults and UA. This will benefit consumers immediately.
13-24: Pass-through token is unused downstream
tokenis stored butMediaWikiApiServicedoesn’t apply it to requests. Either wire it into headers or drop it here to avoid confusion.I can wire
Authorizationheader usage if that token is OAuth/Bearer-like. Confirm expected scheme?backend/src/api/wikibase/entities.ts (2)
24-37: New fetch-all-properties endpoint: LGTMClear contract and response shape; leverages db() correctly.
43-58: Guard against empty queries; ensure schema enforces non-empty
q.trim()implies string. EnsurePropertySearchSchemaenforcesz.string().min(1)to avoid runtimetrim()on undefined.If it already does, no change needed. Otherwise, I can update the schema.
backend/src/api/project/index.ts (2)
344-374: Temp file upload helper: looks goodUses Bun APIs correctly and returns a simple payload.
221-257: Confirm default pagination change to 25 — frontend & tests already alignBackend GET /api/project/:projectId sets limit = 25; frontend fetchProject defaults to limit = 25; backend tests expect limit = 25. No callers assuming limit = 0 were found — only the store's initial meta.limit = 0 before any fetch. No change required.
Locations:
- backend/src/api/project/index.ts — GET /:projectId handler (limit = 25)
- frontend/src/features/project-management/stores/project.store.ts — fetchProject(..., limit = 25) and initial meta.limit = 0
- backend/tests/api/project/project.get.test.ts — getExpectedMeta default limit = 25
backend/src/api/project/project.wikibase.ts (1)
162-215: Route schema wiring reads clean and consistentTags, response envelopes, and ApiError alignment look good.
backend/src/services/wikibase.service.ts (1)
33-42: Client resolution design looks goodExtending WikibaseClient and centralizing client management improves cohesion.
backend/src/api/project/schemas.ts (1)
66-79: Centralized schemas and tags look solidGood consolidation and consistent ApiError usage.
backend/src/api/wikibase/schemas.ts (1)
98-141: Overall: Zod migration and route schemas look goodGood consolidation, clearer docs, and consistent ApiError usage.
| @@ -1,12 +1,13 @@ | |||
| import { ApiError } from '@backend/types/error-schemas' | |||
| import { t } from 'elysia' | |||
| import z from 'zod' | |||
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
Prefer named import for Zod.
Use the canonical import { z } from 'zod' to avoid interop pitfalls.
Apply:
-import z from 'zod'
+import { z } from 'zod'📝 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.
| import z from 'zod' | |
| import { z } from 'zod' |
🤖 Prompt for AI Agents
In backend/src/api/project/import.ts around line 3, the file uses a
default-style import "import z from 'zod'" which can cause interop issues;
change it to the canonical named import "import { z } from 'zod'" and update any
references if necessary, then run TypeScript/ESLint to ensure no remaining
import errors.
| GetProjectByIdSchema, | ||
| ProjectCreateSchema, | ||
| ProjectDeleteSchema, | ||
| ProjectImportFileSchema, | ||
| } from '@backend/api/project/project.import-file' | ||
| ProjectParams, | ||
| ProjectsGetAllSchema, | ||
| type Project, | ||
| } from '@backend/api/project/schemas' |
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.
Unused import triggers pipeline failure
ProjectDeleteSchema is imported but not used (TS6133). Remove import or re-enable schema on the DELETE route.
- ProjectCreateSchema,
- ProjectDeleteSchema,
+ ProjectCreateSchema,
@@
- // ProjectDeleteSchema,
+ // ProjectDeleteSchema, // re-enable when DELETE has a schema againOr remove the import entirely:
- ProjectDeleteSchema,📝 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.
| GetProjectByIdSchema, | |
| ProjectCreateSchema, | |
| ProjectDeleteSchema, | |
| ProjectImportFileSchema, | |
| } from '@backend/api/project/project.import-file' | |
| ProjectParams, | |
| ProjectsGetAllSchema, | |
| type Project, | |
| } from '@backend/api/project/schemas' | |
| GetProjectByIdSchema, | |
| ProjectCreateSchema, | |
| ProjectImportFileSchema, | |
| ProjectParams, | |
| ProjectsGetAllSchema, | |
| type Project, | |
| } from '@backend/api/project/schemas' |
🧰 Tools
🪛 GitHub Actions: Typecheck code
[error] 6-6: TypeScript error TS6133: 'ProjectDeleteSchema' is declared but its value is never read.
[error] 6-6: TypeScript error TS6133: 'ProjectDeleteSchema' is declared but its value is never read.
🤖 Prompt for AI Agents
In backend/src/api/project/index.ts around lines 4 to 11, ProjectDeleteSchema is
imported but unused causing a TypeScript TS6133 failure; remove
ProjectDeleteSchema from the import list (or re-add/enable its use on the DELETE
route if that was intended). Update the import statement to only include
actually used symbols (e.g., remove the ProjectDeleteSchema token) and run
TypeScript to confirm the unused-import error is resolved.
| const PropertyReference = z.object({ | ||
| id: PropertyId, | ||
| label: t.Optional(t.String()), | ||
| dataType: t.String(), | ||
| label: z.string().optional(), | ||
| dataType: z.string(), | ||
| }) | ||
|
|
||
| export type PropertyReference = typeof PropertyReference.static | ||
| export type PropertyReference = z.infer<typeof PropertyReference> |
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
Use WikibaseDataType for PropertyReference.dataType
Align with ValueMapping and wikibase types to prevent mismatches.
-const PropertyReference = z.object({
+const PropertyReference = z.object({
id: PropertyId,
- label: z.string().optional(),
- dataType: z.string(),
+ label: z.string().optional(),
+ dataType: WikibaseDataType,
})📝 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.
| const PropertyReference = z.object({ | |
| id: PropertyId, | |
| label: t.Optional(t.String()), | |
| dataType: t.String(), | |
| label: z.string().optional(), | |
| dataType: z.string(), | |
| }) | |
| export type PropertyReference = typeof PropertyReference.static | |
| export type PropertyReference = z.infer<typeof PropertyReference> | |
| const PropertyReference = z.object({ | |
| id: PropertyId, | |
| label: z.string().optional(), | |
| dataType: WikibaseDataType, | |
| }) | |
| export type PropertyReference = z.infer<typeof PropertyReference> |
🤖 Prompt for AI Agents
In backend/src/api/project/project.wikibase.ts around lines 30 to 35, the
PropertyReference schema currently uses z.string() for dataType which can
diverge from your defined Wikibase types; replace z.string() with the existing
WikibaseDataType schema/type (e.g., use WikibaseDataType or
z.nativeEnum(WikibaseDataType) as appropriate), add the necessary import for
WikibaseDataType at the top of the file, and keep the exported type inference
unchanged so PropertyReference.dataType aligns with the ValueMapping/wikibase
types.
| export const ProjectResponseSchema = z.object({ | ||
| id: z.string(), | ||
| name: z.string(), | ||
| created_at: z.string(), | ||
| updated_at: z.string(), | ||
| }) | ||
|
|
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
Use UUIDPattern and datetime validators for stronger contracts
export const ProjectResponseSchema = z.object({
- id: z.string(),
+ id: UUIDPattern,
name: z.string(),
- created_at: z.string(),
- updated_at: z.string(),
+ created_at: z.string().datetime(),
+ updated_at: z.string().datetime(),
})📝 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.
| export const ProjectResponseSchema = z.object({ | |
| id: z.string(), | |
| name: z.string(), | |
| created_at: z.string(), | |
| updated_at: z.string(), | |
| }) | |
| export const ProjectResponseSchema = z.object({ | |
| id: z.string().uuid(), | |
| name: z.string(), | |
| created_at: z.string().datetime(), | |
| updated_at: z.string().datetime(), | |
| }) |
🤖 Prompt for AI Agents
In backend/src/api/project/schemas.ts around lines 13 to 19, the schema
currently uses plain strings for id and timestamps; replace the loose types with
stricter validators by validating id as a UUID and created_at/updated_at as ISO
datetimes (e.g. use z.string().uuid() for id and z.string().datetime() or an
equivalent ISO datetime regex validator for the timestamps) so the contract
enforces correct formats and fails on invalid values.
| export const ProjectCreateSchema = { | ||
| body: z.object({ | ||
| name: z | ||
| .string({ | ||
| error: 'Project name is required and must be at least 1 character long', | ||
| }) | ||
| .trim() | ||
| .min(1), | ||
| }), |
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.
Fix Zod error option; use required_error/min message
The key “error” is not a valid Zod option.
body: z.object({
- name: z
- .string({
- error: 'Project name is required and must be at least 1 character long',
- })
- .trim()
- .min(1),
+ name: z
+ .string({ required_error: 'Project name is required' })
+ .trim()
+ .min(1, 'Project name must be at least 1 character long'),
}),📝 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.
| export const ProjectCreateSchema = { | |
| body: z.object({ | |
| name: z | |
| .string({ | |
| error: 'Project name is required and must be at least 1 character long', | |
| }) | |
| .trim() | |
| .min(1), | |
| }), | |
| export const ProjectCreateSchema = { | |
| body: z.object({ | |
| name: z | |
| .string({ required_error: 'Project name is required' }) | |
| .trim() | |
| .min(1, 'Project name must be at least 1 character long'), | |
| }), |
🤖 Prompt for AI Agents
In backend/src/api/project/schemas.ts around lines 43 to 51, replace the invalid
Zod option "error" on z.string(...) with the proper Zod options and move the min
message into the .min call: use z.string({ required_error: 'Project name is
required and must be at least 1 character long', invalid_type_error: 'Project
name must be a string' }).trim().min(1, { message: 'Project name is required and
must be at least 1 character long' }) so you provide a
required_error/invalid_type_error for the string constructor and a message for
the min validator.
| * @see https://www.mediawiki.org/wiki/API:Main_page | ||
| */ | ||
|
|
||
| import type { Term } from '@backend/api/wikibase/schemas' |
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
Layering issue: types importing from api module.
types/ shouldn’t depend on api/. Move Term to a shared types/ module and import from there.
Apply:
-import type { Term } from '@backend/api/wikibase/schemas'
+import type { Term } from '@backend/types/wikibase-shared'And extract Term to backend/src/types/wikibase-shared.ts for both modules to consume.
Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In backend/src/types/mediawiki-api.ts around line 7 the file imports Term from
@backend/api/wikibase/schemas which creates a layering violation (types
depending on api); extract the Term type into a new shared file
backend/src/types/wikibase-shared.ts, move the Term definition there, then
update this file (and any other modules that currently import Term from
@backend/api/...) to import Term from backend/src/types/wikibase-shared.ts
instead and remove the api dependency.
| title: string | ||
| pageid: number | ||
| datatype: WikibaseDataType | ||
| concepturi: string | ||
| repository: string | ||
| url: string | ||
| display: { | ||
| label?: { | ||
| value: string | ||
| language: string | ||
| } | ||
| description?: { | ||
| value: string | ||
| language: string | ||
| } | ||
| } | ||
| label: string | ||
| description: string | ||
| match: { | ||
| type: Term | ||
| language: string | ||
| text: string | ||
| } | ||
| aliases?: string[] | ||
| } |
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.
WikibaseSearchEntityResult: required fields and datatype now mandatory — this is incorrect for items and mismatched with runtime schema.
datatypeexists for properties, not items. Making it required breaks item results.- Several fields are now required here but optional in
WikibaseSearchEntityResultSchemabelow — type/runtime drift.
Apply one of:
Option A — keep a single interface with optionals:
export interface WikibaseSearchEntityResult<T> {
id: T
- title: string
- pageid: number
- datatype: WikibaseDataType
- concepturi: string
- repository: string
- url: string
+ title?: string
+ pageid?: number
+ datatype?: WikibaseDataType
+ concepturi?: string
+ repository?: string
+ url?: string
display: {
- label?: {
+ label?: {
value: string
language: string
}
description?: {
value: string
language: string
}
}
- label: string
- description: string
+ label?: string
+ description?: string
match: {
type: Term
language: string
text: string
}
aliases?: string[]
}Option B — model a discriminated union for item vs property and update the schema accordingly. I can generate the full union if you prefer.
📝 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.
| title: string | |
| pageid: number | |
| datatype: WikibaseDataType | |
| concepturi: string | |
| repository: string | |
| url: string | |
| display: { | |
| label?: { | |
| value: string | |
| language: string | |
| } | |
| description?: { | |
| value: string | |
| language: string | |
| } | |
| } | |
| label: string | |
| description: string | |
| match: { | |
| type: Term | |
| language: string | |
| text: string | |
| } | |
| aliases?: string[] | |
| } | |
| export interface WikibaseSearchEntityResult<T> { | |
| id: T | |
| title?: string | |
| pageid?: number | |
| datatype?: WikibaseDataType | |
| concepturi?: string | |
| repository?: string | |
| url?: string | |
| display: { | |
| label?: { | |
| value: string | |
| language: string | |
| } | |
| description?: { | |
| value: string | |
| language: string | |
| } | |
| } | |
| label?: string | |
| description?: string | |
| match: { | |
| type: Term | |
| language: string | |
| text: string | |
| } | |
| aliases?: string[] | |
| } |
🤖 Prompt for AI Agents
In backend/src/types/mediawiki-api.ts around lines 329-353, the interface forces
fields (notably datatype) as required which is incorrect for item search results
and diverges from the runtime WikibaseSearchEntityResultSchema; make datatype
optional (datatype?: WikibaseDataType) and relax any other fields to match the
schema OR implement a discriminated union (e.g., PropertySearchEntity vs
ItemSearchEntity) so properties include datatype while items do not, then update
the downstream schema/type usages to the chosen representation to restore
type/runtime parity.
| search: WikibaseSearchEntityResult<T>[] | ||
| searchinfo: { | ||
| search: number | ||
| } |
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
Response shape drift: searchinfo.search is not aligned with the existing schema or API usage here.
Either add searchinfo to WikibaseSearchEntitiesResponseSchema and validate it, or revert the interface to match the current runtime schema.
I can update both the TS interface and the Elysia schema to stay in lockstep.
🤖 Prompt for AI Agents
backend/src/types/mediawiki-api.ts lines 356-359: the TypeScript interface adds
a searchinfo.search field that no longer matches the runtime/Elysia schema;
update the runtime schema to include searchinfo: { search: number } and its
validation in WikibaseSearchEntitiesResponseSchema (or revert the TS interface
to the previous shape) so runtime and types match; ensure the schema export, any
parsing/validation code, and tests are updated to accept and validate
searchinfo.search accordingly.
| limit: number | ||
| offset: number | ||
| language: string | ||
| languageFallback?: boolean |
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.
💡 Verification agent
🧩 Analysis chain
Breaking change: making limit/offset/language required in SearchOptions.
If callers relied on defaults, this will break. Either keep them optional with defaults in the service layer or update all call sites.
Apply:
-export interface SearchOptions {
- limit: number
- offset: number
- language: string
+export interface SearchOptions {
+ limit?: number
+ offset?: number
+ language?: string
languageFallback?: boolean
}🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "1) Find interface declaration(s) for SearchOptions"
rg -n --hidden --no-ignore-vcs -S 'interface\s+SearchOptions\b' -C3 || true
echo
echo "2) All occurrences of 'SearchOptions' (type references/imports/params)"
rg -n --hidden --no-ignore-vcs -S '\bSearchOptions\b' -C3 || true
echo
echo "3) Occurrences of property access '.limit', '.offset', '.language' (context)"
rg -n --hidden --no-ignore-vcs -S '\.limit\b' -C3 || true
rg -n --hidden --no-ignore-vcs -S '\.offset\b' -C3 || true
rg -n --hidden --no-ignore-vcs -S '\.language\b' -C3 || true
echo
echo "4) Object literals with 'limit:', 'offset:', 'language:' (explicit passing sites)"
rg -n --hidden --no-ignore-vcs -S '\blimit\s*:' -C2 || true
rg -n --hidden --no-ignore-vcs -S '\boffset\s*:' -C2 || true
rg -n --hidden --no-ignore-vcs -S '\blanguage\s*:' -C2 || true
echo
echo "5) Parameter destructuring with defaults for 'limit'/'offset'/'language' (in signatures)"
rg -n --hidden --no-ignore-vcs -S '\{\s*[^}]*limit\s*=' -C2 || true
rg -n --hidden --no-ignore-vcs -S '\{\s*[^}]*offset\s*=' -C2 || true
rg -n --hidden --no-ignore-vcs -S '\{\s*[^}]*language\s*=' -C2 || true
echo
echo "6) Functions/methods explicitly typed with SearchOptions"
rg -n --hidden --no-ignore-vcs -S ':\s*SearchOptions\b' -C3 || true
echo
echo "7) Imports of SearchOptions"
rg -n --hidden --no-ignore-vcs -S "import .*SearchOptions" -C2 || trueLength of output: 53604
Revert SearchOptions fields to optional (breaking change otherwise)
SearchOptions currently requires limit/offset/language; callers and the API layer use defaults (zod schemas / route destructuring) and the service uses nullish coalescing — make these optional to avoid TypeScript breakage.
File: backend/src/types/wikibase-api.ts (lines 121–125)
Apply:
-export interface SearchOptions {
- limit: number
- offset: number
- language: string
+export interface SearchOptions {
+ limit?: number
+ offset?: number
+ language?: string
languageFallback?: boolean
}📝 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.
| limit: number | |
| offset: number | |
| language: string | |
| languageFallback?: boolean | |
| export interface SearchOptions { | |
| limit?: number | |
| offset?: number | |
| language?: string | |
| languageFallback?: boolean | |
| } |
🤖 Prompt for AI Agents
In backend/src/types/wikibase-api.ts around lines 122 to 125, the SearchOptions
fields are currently required; change limit, offset and language to be optional
(limit?: number, offset?: number, language?: string) while leaving
languageFallback as optional; update any local usages/types if needed to accept
undefined (e.g., keep nullish coalescing in callers/services) so this is a
non-breaking revert to optional fields.
| const projects = selectReader.getRowObjectsJson() | ||
|
|
||
| expect(projects).toEqual([]) | ||
| expect(projects).toBeArrayOfSize(0) |
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.
Use a built-in matcher; toBeArrayOfSize requires jest-extended.
bun:test doesn’t include toBeArrayOfSize by default. Prefer toHaveLength(0).
Apply:
- expect(projects).toBeArrayOfSize(0)
+ expect(projects).toHaveLength(0)📝 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.
| expect(projects).toBeArrayOfSize(0) | |
| expect(projects).toHaveLength(0) |
🤖 Prompt for AI Agents
In backend/tests/api/project/project.delete.test.ts around line 46, the test
uses the non-standard matcher toBeArrayOfSize(0) (from jest-extended) which
bun:test doesn't provide; replace that call with the built-in matcher
expect(projects).toHaveLength(0) and remove any unnecessary jest-extended
imports/setup in this test file if present.
No description provided.