-
Notifications
You must be signed in to change notification settings - Fork 0
fix(ci): golangci-lint v2, SQL injection fix, BFF/dashboard lint cleanup #10
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
Changes from 6 commits
89648be
0fc10a2
203d878
8ae97ca
486f70e
b3fda45
5689f8e
e44aa9d
e31fa48
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,53 +1,45 @@ | ||
| version: "2" | ||
|
|
||
| run: | ||
| timeout: 5m | ||
| modules-download-mode: readonly | ||
|
|
||
| linters: | ||
| default: none | ||
| enable: | ||
| - errcheck | ||
| - govet | ||
| - staticcheck | ||
| - unused | ||
| - gosimple | ||
| - ineffassign | ||
| - typecheck | ||
| - gocritic | ||
| - gosec | ||
| - prealloc | ||
| - bodyclose | ||
| - noctx | ||
| - exhaustive | ||
| disable: | ||
| - depguard | ||
|
|
||
| linters-settings: | ||
| govet: | ||
| enable-all: true | ||
| disable: | ||
| - fieldalignment | ||
| gocritic: | ||
| enabled-tags: | ||
| - diagnostic | ||
| - performance | ||
| disabled-checks: | ||
| - ifElseChain | ||
| - exitAfterDefer | ||
| - hugeParam | ||
| - rangeValCopy | ||
| - sloppyReassign | ||
| - sprintfQuotedString | ||
| gosec: | ||
| excludes: | ||
| - G104 # unhandled errors in deferred calls (noisy) | ||
| - G404 # math/rand is acceptable here for jitter and synthetic test data | ||
| exhaustive: | ||
| default-signifies-exhaustive: true | ||
| settings: | ||
| govet: | ||
| enable-all: true | ||
| disable: | ||
| - fieldalignment | ||
| gocritic: | ||
| enabled-tags: | ||
| - diagnostic | ||
| - performance | ||
| disabled-checks: | ||
| - ifElseChain | ||
| - exitAfterDefer | ||
| - hugeParam | ||
| - rangeValCopy | ||
| - sloppyReassign | ||
| - sprintfQuotedString | ||
| gosec: | ||
| excludes: | ||
| - G104 # unhandled errors in deferred calls (noisy) | ||
| - G404 # math/rand is acceptable here for jitter and synthetic test data | ||
| exhaustive: | ||
| default-signifies-exhaustive: true | ||
|
|
||
| issues: | ||
| exclude-use-default: true | ||
| max-issues-per-linter: 50 | ||
| max-same-issues: 5 | ||
| exclude-dirs: | ||
| - vendor | ||
| - node_modules | ||
| - dist | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -6,6 +6,19 @@ export const es = new Client({ node: ES_URL }); | |
|
|
||
| const DEVICE_INDEX = "grainguard-devices"; | ||
|
|
||
| interface ESHit { | ||
| _source: { | ||
| device_id: string; | ||
| tenant_id: string; | ||
| serial_number: string; | ||
| temperature?: number; | ||
| humidity?: number; | ||
| recorded_at?: string; | ||
| status?: string; | ||
| }; | ||
| _score: number; | ||
| } | ||
|
|
||
| export const search = { | ||
| async searchDevices(query: string, tenantId: string, limit = 20) { | ||
| try { | ||
|
|
@@ -31,11 +44,9 @@ export const search = { | |
| }, | ||
| }, | ||
| }; | ||
| console.log("[ES] searching:", JSON.stringify(params)); | ||
| const result = await (es.search as any)(params); | ||
| console.log("[ES] hits:", result.hits.total); | ||
| const result = await (es.search as (p: typeof params) => Promise<{ hits: { total: unknown; hits: ESHit[] } }>)(params); | ||
|
|
||
| return result.hits.hits.map((hit: any) => ({ | ||
| return result.hits.hits.map((hit: ESHit) => ({ | ||
|
Comment on lines
+47
to
+49
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧹 Nitpick | 🔵 Trivial 🧩 Analysis chain🌐 Web query:
💡 Result: In the Citations:
🏁 Script executed: cat -n apps/bff/src/datasources/elasticsearch.ts | head -60Repository: pahuldeepp/GrainGuard- Length of output: 2220 🏁 Script executed: cat -n apps/bff/src/datasources/elasticsearch.ts | tail -30Repository: pahuldeepp/GrainGuard- Length of output: 1275 🏁 Script executed: rg -l "elasticsearch" apps/bff/src --type ts | head -10Repository: pahuldeepp/GrainGuard- Length of output: 133 🏁 Script executed: rg "searchDevices" apps/bff/src/resolvers.ts -B 3 -A 5Repository: pahuldeepp/GrainGuard- Length of output: 648 🏁 Script executed: rg "BffContext|tenantFilter" apps/bff/src --type ts -B 2 -A 2 | head -50Repository: pahuldeepp/GrainGuard- Length of output: 2639 Refactor to use typed generics for better type safety. The const result = await es.search<ESHit['_source']>({...params});This eliminates the unconventional cast and provides first-class TypeScript type safety without manual assertions. 🤖 Prompt for AI Agents |
||
| deviceId: hit._source.device_id, | ||
| tenantId: hit._source.tenant_id, | ||
| serialNumber: hit._source.serial_number, | ||
|
|
@@ -45,10 +56,10 @@ export const search = { | |
| status: hit._source.status ?? null, | ||
| score: hit._score, | ||
| })); | ||
| } catch (err: any) { | ||
| console.error("[ES] error:", err?.meta?.body?.error || err?.message || err); | ||
| } catch (err: unknown) { | ||
| const e = err as { meta?: { body?: { error?: unknown } }; message?: string }; | ||
| console.error("[ES] error:", e?.meta?.body?.error || e?.message || err); | ||
| return []; | ||
| } | ||
| }, | ||
| }; | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -16,22 +16,41 @@ const pool = new Pool({ | |||||||||||||||||||||||||||||||||||||||||||||
| max: 50, | ||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| type Row = Record<string, unknown>; | ||||||||||||||||||||||||||||||||||||||||||||||
| type QueryResult = import("pg").QueryResult<Row>; | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| // Circuit-breaker-wrapped query helper | ||||||||||||||||||||||||||||||||||||||||||||||
| async function cbQuery(text: string, values?: any[]): Promise<import("pg").QueryResult<any>> { | ||||||||||||||||||||||||||||||||||||||||||||||
| return postgresCircuitBreaker.execute(() => pool.query(text, values)); | ||||||||||||||||||||||||||||||||||||||||||||||
| async function cbQuery(text: string, values?: unknown[]): Promise<QueryResult> { | ||||||||||||||||||||||||||||||||||||||||||||||
| return postgresCircuitBreaker.execute(() => pool.query(text, values as unknown[])); | ||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| // Tenant-scoped query — sets app.current_tenant_id for RLS enforcement | ||||||||||||||||||||||||||||||||||||||||||||||
| export async function tenantQuery( | ||||||||||||||||||||||||||||||||||||||||||||||
| tenantId: string, | ||||||||||||||||||||||||||||||||||||||||||||||
| text: string, | ||||||||||||||||||||||||||||||||||||||||||||||
| values?: any[] | ||||||||||||||||||||||||||||||||||||||||||||||
| ): Promise<import("pg").QueryResult<any>> { | ||||||||||||||||||||||||||||||||||||||||||||||
| values?: unknown[] | ||||||||||||||||||||||||||||||||||||||||||||||
| ): Promise<QueryResult> { | ||||||||||||||||||||||||||||||||||||||||||||||
| return postgresCircuitBreaker.execute(async () => { | ||||||||||||||||||||||||||||||||||||||||||||||
| const client = await pool.connect(); | ||||||||||||||||||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||||||||||||||||||
| await client.query('SET LOCAL app.current_tenant_id = $1', [tenantId]); | ||||||||||||||||||||||||||||||||||||||||||||||
| return await client.query(text, values); | ||||||||||||||||||||||||||||||||||||||||||||||
| await client.query("BEGIN"); | ||||||||||||||||||||||||||||||||||||||||||||||
| await client.query( | ||||||||||||||||||||||||||||||||||||||||||||||
| "SELECT set_config('app.current_tenant_id', $1, true)", | ||||||||||||||||||||||||||||||||||||||||||||||
| [tenantId] | ||||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||||
| const result = await client.query( | ||||||||||||||||||||||||||||||||||||||||||||||
| text, | ||||||||||||||||||||||||||||||||||||||||||||||
| values as unknown[] | undefined | ||||||||||||||||||||||||||||||||||||||||||||||
| ) as QueryResult; | ||||||||||||||||||||||||||||||||||||||||||||||
| await client.query("COMMIT"); | ||||||||||||||||||||||||||||||||||||||||||||||
| return result; | ||||||||||||||||||||||||||||||||||||||||||||||
| } catch (error) { | ||||||||||||||||||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||||||||||||||||||
| await client.query("ROLLBACK"); | ||||||||||||||||||||||||||||||||||||||||||||||
| } catch { | ||||||||||||||||||||||||||||||||||||||||||||||
| // Release the client even if rollback fails. | ||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||
| throw error; | ||||||||||||||||||||||||||||||||||||||||||||||
| } finally { | ||||||||||||||||||||||||||||||||||||||||||||||
| client.release(); | ||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -52,13 +71,13 @@ export const db = { | |||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| async getAllDevices(limit: number = 20) { | ||||||||||||||||||||||||||||||||||||||||||||||
| const cacheKey = `devices:all:${limit}`; | ||||||||||||||||||||||||||||||||||||||||||||||
| const cached = await cache.get<any[]>(cacheKey); | ||||||||||||||||||||||||||||||||||||||||||||||
| const cached = await cache.get<Row[]>(cacheKey); | ||||||||||||||||||||||||||||||||||||||||||||||
| if (cached) return cached; | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| const locked = await cache.acquireLock(cacheKey, 5); | ||||||||||||||||||||||||||||||||||||||||||||||
| if (!locked) { | ||||||||||||||||||||||||||||||||||||||||||||||
| await new Promise(r => setTimeout(r, 100)); | ||||||||||||||||||||||||||||||||||||||||||||||
| return await cache.get<any[]>(cacheKey) || []; | ||||||||||||||||||||||||||||||||||||||||||||||
| return await cache.get<Row[]>(cacheKey) || []; | ||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -88,13 +107,13 @@ export const db = { | |||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| async getAllTelemetry(limit: number = 20, tenantId?: string) { | ||||||||||||||||||||||||||||||||||||||||||||||
| const cacheKey = `telemetry:all:${tenantId || "global"}:${limit}`; | ||||||||||||||||||||||||||||||||||||||||||||||
| const cached = await cache.get<any[]>(cacheKey); | ||||||||||||||||||||||||||||||||||||||||||||||
| const cached = await cache.get<Row[]>(cacheKey); | ||||||||||||||||||||||||||||||||||||||||||||||
| if (cached) return cached; | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| const locked = await cache.acquireLock(cacheKey, 5); | ||||||||||||||||||||||||||||||||||||||||||||||
| if (!locked) { | ||||||||||||||||||||||||||||||||||||||||||||||
| await new Promise(r => setTimeout(r, 100)); | ||||||||||||||||||||||||||||||||||||||||||||||
| return await cache.get<any[]>(cacheKey) || []; | ||||||||||||||||||||||||||||||||||||||||||||||
| return await cache.get<Row[]>(cacheKey) || []; | ||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -148,7 +167,7 @@ export const db = { | |||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| async getTelemetryHistory(deviceId: string, limit = 50, tenantId?: string) { | ||||||||||||||||||||||||||||||||||||||||||||||
| const queryFn = tenantId | ||||||||||||||||||||||||||||||||||||||||||||||
| ? (text: string, values: any[]) => tenantQuery(tenantId, text, values) | ||||||||||||||||||||||||||||||||||||||||||||||
| ? (text: string, values: unknown[]) => tenantQuery(tenantId, text, values) | ||||||||||||||||||||||||||||||||||||||||||||||
| : cbQuery; | ||||||||||||||||||||||||||||||||||||||||||||||
| const result = await queryFn( | ||||||||||||||||||||||||||||||||||||||||||||||
| `SELECT device_id, temperature, humidity, recorded_at | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -158,7 +177,7 @@ export const db = { | |||||||||||||||||||||||||||||||||||||||||||||
| LIMIT $2`, | ||||||||||||||||||||||||||||||||||||||||||||||
| [deviceId, limit] | ||||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||||
| return result.rows.map((r: any) => ({ | ||||||||||||||||||||||||||||||||||||||||||||||
| return result.rows.map((r: Row) => ({ | ||||||||||||||||||||||||||||||||||||||||||||||
| deviceId: r.device_id, | ||||||||||||||||||||||||||||||||||||||||||||||
| temperature: r.temperature, | ||||||||||||||||||||||||||||||||||||||||||||||
| humidity: r.humidity, | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -168,13 +187,13 @@ export const db = { | |||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| async getAllDevicesWithTelemetry(limit: number = 20, tenantId?: string) { | ||||||||||||||||||||||||||||||||||||||||||||||
| const cacheKey = `devices:telemetry:${tenantId || "global"}:${limit}`; | ||||||||||||||||||||||||||||||||||||||||||||||
| const cached = await cache.get<any[]>(cacheKey); | ||||||||||||||||||||||||||||||||||||||||||||||
| const cached = await cache.get<Row[]>(cacheKey); | ||||||||||||||||||||||||||||||||||||||||||||||
| if (cached) return cached; | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| const locked = await cache.acquireLock(cacheKey, 5); | ||||||||||||||||||||||||||||||||||||||||||||||
| if (!locked) { | ||||||||||||||||||||||||||||||||||||||||||||||
| await new Promise(r => setTimeout(r, 100)); | ||||||||||||||||||||||||||||||||||||||||||||||
| return await cache.get<any[]>(cacheKey) || []; | ||||||||||||||||||||||||||||||||||||||||||||||
| return await cache.get<Row[]>(cacheKey) || []; | ||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -222,7 +241,7 @@ export const db = { | |||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| const fetchLimit = first + 1; | ||||||||||||||||||||||||||||||||||||||||||||||
| let rows: any[]; | ||||||||||||||||||||||||||||||||||||||||||||||
| let rows: Row[]; | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| if (tenantId && afterTimestamp) { | ||||||||||||||||||||||||||||||||||||||||||||||
| const result = await cbQuery( | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -270,22 +289,22 @@ export const db = { | |||||||||||||||||||||||||||||||||||||||||||||
| "SELECT COUNT(*) FROM device_projections WHERE tenant_id = $1", | ||||||||||||||||||||||||||||||||||||||||||||||
| [tenantId] | ||||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||||
| totalCount = parseInt(countResult.rows[0].count, 10); | ||||||||||||||||||||||||||||||||||||||||||||||
| totalCount = parseInt(countResult.rows[0].count as string, 10); | ||||||||||||||||||||||||||||||||||||||||||||||
| } else { | ||||||||||||||||||||||||||||||||||||||||||||||
| const countResult = await cbQuery("SELECT COUNT(*) FROM device_projections"); | ||||||||||||||||||||||||||||||||||||||||||||||
| totalCount = parseInt(countResult.rows[0].count, 10); | ||||||||||||||||||||||||||||||||||||||||||||||
| totalCount = parseInt(countResult.rows[0].count as string, 10); | ||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| const edges = items.map((row: any) => ({ | ||||||||||||||||||||||||||||||||||||||||||||||
| cursor: Buffer.from(row.created_at.toISOString()).toString("base64"), | ||||||||||||||||||||||||||||||||||||||||||||||
| const edges = items.map((row: Row) => ({ | ||||||||||||||||||||||||||||||||||||||||||||||
| cursor: Buffer.from((row.created_at as Date).toISOString()).toString("base64"), | ||||||||||||||||||||||||||||||||||||||||||||||
| node: { | ||||||||||||||||||||||||||||||||||||||||||||||
| deviceId: row.device_id, | ||||||||||||||||||||||||||||||||||||||||||||||
| tenantId: row.tenant_id, | ||||||||||||||||||||||||||||||||||||||||||||||
| serialNumber: row.serial_number, | ||||||||||||||||||||||||||||||||||||||||||||||
| createdAt: new Date(row.created_at).toISOString(), | ||||||||||||||||||||||||||||||||||||||||||||||
| createdAt: new Date(row.created_at as string).toISOString(), | ||||||||||||||||||||||||||||||||||||||||||||||
| temperature: row.temperature ?? null, | ||||||||||||||||||||||||||||||||||||||||||||||
| humidity: row.humidity ?? null, | ||||||||||||||||||||||||||||||||||||||||||||||
| recordedAt: row.recorded_at ? new Date(row.recorded_at).toISOString() : null, | ||||||||||||||||||||||||||||||||||||||||||||||
| recordedAt: row.recorded_at ? new Date(row.recorded_at as string).toISOString() : null, | ||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+298
to
+307
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧹 Nitpick | 🔵 Trivial Inconsistent Date handling between cursor and node fields. Line 299 casts ♻️ Suggested consistency fix cursor: Buffer.from((row.created_at as Date).toISOString()).toString("base64"),
node: {
deviceId: row.device_id,
tenantId: row.tenant_id,
serialNumber: row.serial_number,
- createdAt: new Date(row.created_at as string).toISOString(),
+ createdAt: (row.created_at as Date).toISOString(),
temperature: row.temperature ?? null,
humidity: row.humidity ?? null,
- recordedAt: row.recorded_at ? new Date(row.recorded_at as string).toISOString() : null,
+ recordedAt: row.recorded_at ? (row.recorded_at as Date).toISOString() : null,
version: row.version ?? null,
},📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||
| version: row.version ?? null, | ||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||
| })); | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -301,6 +320,7 @@ export const db = { | |||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| async createDevice(input: { serialNumber: string; tenantId: string }) { | ||||||||||||||||||||||||||||||||||||||||||||||
| const result = await cbQuery( | ||||||||||||||||||||||||||||||||||||||||||||||
| `INSERT INTO device_projections (device_id, tenant_id, serial_number, created_at) | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -312,7 +332,7 @@ export const db = { | |||||||||||||||||||||||||||||||||||||||||||||
| deviceId: result.rows[0].device_id, | ||||||||||||||||||||||||||||||||||||||||||||||
| tenantId: result.rows[0].tenant_id, | ||||||||||||||||||||||||||||||||||||||||||||||
| serialNumber: result.rows[0].serial_number, | ||||||||||||||||||||||||||||||||||||||||||||||
| createdAt: new Date(result.rows[0].created_at).toISOString(), | ||||||||||||||||||||||||||||||||||||||||||||||
| createdAt: new Date(result.rows[0].created_at as string).toISOString(), | ||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+335
to
336
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧹 Nitpick | 🔵 Trivial Same inconsistency in createDevice and updateDevice. These also use Also applies to: 351-352 🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -328,7 +348,7 @@ export const db = { | |||||||||||||||||||||||||||||||||||||||||||||
| deviceId: result.rows[0].device_id, | ||||||||||||||||||||||||||||||||||||||||||||||
| tenantId: result.rows[0].tenant_id, | ||||||||||||||||||||||||||||||||||||||||||||||
| serialNumber: result.rows[0].serial_number, | ||||||||||||||||||||||||||||||||||||||||||||||
| createdAt: new Date(result.rows[0].created_at).toISOString(), | ||||||||||||||||||||||||||||||||||||||||||||||
| createdAt: new Date(result.rows[0].created_at as string).toISOString(), | ||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -340,4 +360,3 @@ export const db = { | |||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -27,7 +27,7 @@ export const cache = { | |
| return results.map((r: any) => r ? JSON.parse(r) : null); | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧹 Nitpick | 🔵 Trivial Remaining Line 27 still uses ♻️ Proposed fix- return results.map((r: any) => r ? JSON.parse(r) : null);
+ return results.map((r) => (typeof r === "string" ? JSON.parse(r) : null));🤖 Prompt for AI Agents |
||
| }, | ||
|
|
||
| async set(key: string, value: any, ttlSeconds: number): Promise<void> { | ||
| async set(key: string, value: unknown, ttlSeconds: number): Promise<void> { | ||
| await client.set(key, JSON.stringify(value), { EX: ttlSeconds }); | ||
| }, | ||
|
|
||
|
|
||
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.
🧹 Nitpick | 🔵 Trivial
Consider re-enabling
unusedandgosimplelinters.Setting
default: noneand explicitly enabling linters is clean for v2, butunused(dead code detection) andgosimple(code simplifications) provide valuable feedback that was previously enabled. Their removal may allow technical debt to accumulate undetected.If these were intentionally removed due to noise, consider documenting the rationale in a comment.
🤖 Prompt for AI Agents