JITSU-158: explicit typing + unsafe-any lint gate on config exports - #1441
JITSU-158: explicit typing + unsafe-any lint gate on config exports#1441absorbb wants to merge 5 commits into
Conversation
…U-158 #2) Annotate every paginated findMany in the export endpoints with explicit Prisma GetPayload types. The cursor back-edge previously made inference self-referential and TypeScript silently collapsed the results to any, which is how the 2026-07-30 blank-options typo ({ data_ } for { data: data_ }) compiled. With the annotations the same typo now fails with TS2339 (verified). All Prisma Json column reads now go through tolerant zod parsers (field-level catch drops only the offending field) instead of implicit any. Raw queries and the billing pg query get typed results. object-hash and stable-hash imports are pinned to explicit signatures - their inferred types differ between tsc and the type-aware lint program. getCoreDestinationTypeNonStrict accepts string | undefined - call sites were always able to pass undefined; the signature just could not say so. Behavior deliberately preserved except three crash-to-skip fixes on malformed rows: a domain config without a string name, a classic-mapping without a string value, and a canceled subscription with null period_end no longer throw mid-export. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…TSU-158 #3) Enable @typescript-eslint/no-unsafe-assignment/-member-access/-argument as errors on pages/api/admin/**, type-aware via project tsconfig. The export endpoints pass clean; the eight admin files with pre-existing implicit-any debt carry an explicit file-top exemption header scoped to the rules they actually violate - remove the header when fixing a file, never add new ones. Runs as part of pnpm lint, which is already in the required Lint & Test check. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
There was a problem hiding this comment.
Reviewed the diff from e307cd5 to 6507f93, focusing on admin export serialization paths and the new type-aware lint guard on pages/api/admin/**.
I did not find actionable bugs, security issues, or correctness regressions in this changeset. The refactor appears to preserve existing behavior while hardening unsafe JSON/object handling and null cases.
Connection options in the three connection exports now parse through the destination type's own connectionOptions schema (destinations.tsx) with .passthrough(), falling back to the generic tolerant parse only when the type is unknown or the stored data does not conform (logged at warn). Absent fields therefore materialize to the console defaults - the export emits explicit deduplicate: true, mode: batch, frequency: 60, primaryKey: message_id, ... instead of leaving consumers to re-default absent options themselves, differently and unsafely (JITSU-136). A blank-data row - the 2026-07-30 failure shape - now exports safe defaults rather than nothing. Stored values always win over defaults; unknown keys pass through untouched. Note: one-time optionsHash churn on deploy, and connections that never persisted frequency move from bulker's fast absent-default to the 60m the UI has always shown. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Added a third commit per discussion: connection options now parse through the destination type's own Consequence (deliberate): absent fields materialize to console defaults — the export emits explicit Heads-up for rollout: one-time |
The console default (60m) differs from bulker's absent-option default, so materializing it would silently change the batch cadence of every connection that never persisted a frequency. All other defaults still materialize; frequency exports only when stored (explicit null included). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Back-compat amendment: |
There was a problem hiding this comment.
Reviewed the admin export/type-safety changes across the PR diff, with focus on correctness, runtime behavior, and potential regressions in exported payloads.\n\nI did not find actionable bugs or security/correctness regressions in this changeset. The refactor mostly hardens typing/parsing paths and keeps export behavior aligned while improving failure handling around malformed data.
There was a problem hiding this comment.
Reviewed the admin export/type-safety changes in webapps/console/pages/api/admin/export/[name]/index.ts, the destination type helper update, and the new admin ESLint unsafe-any gate.
I focused on correctness and regression risk in export payload generation, per-entity error handling, and defaulting behavior. I did not find actionable bugs or security regressions in this changeset.
.passthrough() only affects the object it is called on - unknown keys inside nested declared objects were still stripped by the per-type parse. Prod data has real instances (an enabled flag on functions[] entries of 3 live connections) that the old spread-raw-data export preserved. deepPassthrough rebuilds the connectionOptions schema with passthrough on every nested object; defaults and validation semantics are unchanged (verified). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
One more hardening after checking prod data: |
There was a problem hiding this comment.
Reviewed the range e307cd57864f53933dab2dbd39f7b68fccb04be9..461c867a4363ed2e3a0c253645978f64b44649f4, focusing on admin export behavior, sync export correctness, and typed-any hardening changes.
I did not find actionable bugs, security issues, or user-visible regressions in this diff.
Action items 2 and 3 of
JITSU-158(2026-07-30 blank-options postmortem).Item 2 — break the silent-
any(commit 1)Every paginated
findManyinpages/api/admin/export/[name]/index.tsnow carries an explicitPrisma.…GetPayloadannotation. The cursor back-edge (cursor:←lastId←objects[last].id) made inference self-referential, and the checker silently collapsed the result toany— which is how{ data_ }(for{ data: data_ }) compiled on July 30.Verified: re-introducing the exact incident typo now fails with
TS2339: Property 'data_' does not exist on type '{ from: …; to: …; workspace: … }'.Along the way:
Jsoncolumn reads (link.data,object.config,pb.connectionOptions,intermediateStorageCredentials) go through tolerant zod parsers — field-levelcatchdrops only the offending field, non-object roots normalize to{}, so a junk row still can't fail the export (consistent with fix: harden config export/distribution pipeline (JITSU-139 postmortem) #1433's per-entity resilience).$queryRaw/ billingpgPoolqueries get typed results;rpc()backup-connections result is validated as an array instead of trusted asany.object-hash/stable-hashimports pinned to explicit signatures (no shipped types /exportsmap without atypescondition — their inferred type differs between tsc and the type-aware lint program).getCoreDestinationTypeNonStrictacceptsstring | undefined— call sites always could passundefined; the signature just couldn't say so.Behavior preserved, except three crash→skip fixes on malformed rows (domain config without string
name, classic-mapping without stringvalue, canceled subscription with nullperiod_end— each previously threw mid-export).Item 3 — lint gate (commit 2)
@typescript-eslint/no-unsafe-assignment/-member-access/-argumentas errors onpages/api/admin/**, type-aware via the project tsconfig. Runs insidepnpm lint, already part of the required ✨ Lint & Test check — no CI changes needed.The export endpoints pass clean. Eight admin files with pre-existing implicit-
anydebt (261 findings) carry a file-top exemption header scoped to exactly the rules they violate — the ratchet: remove the header when fixing a file, never add new ones.Verification
tsc --noEmit— cleaneslint .— 0 errors (2 pre-existing react-hooks warnings, untouched files)vitest --project unit— 30/30🤖 Generated with Claude Code