Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
88bb979
fix: split form typings in `Input`/`Output` and call `parse` on form …
Bentroen Jan 3, 2026
c451be0
chore: add setting to use project's TypeScript version instead of bun…
Bentroen Jan 4, 2026
757b729
chore: replace root `tsconfig.json` with `references` field
Bentroen Jan 4, 2026
2720e25
chore: enable `composite` in package-inherited root TS config
Bentroen Jan 4, 2026
16d85c8
chore: rename `tsconfig.build.json` to `tsconfig.json`
Bentroen Jan 4, 2026
b5216a0
chore: review base TS settings in global `tsconfig.base.json`
Bentroen Jan 4, 2026
3c8beda
chore: review base TS settings for packages in `tsconfig.package.json`
Bentroen Jan 4, 2026
01e0984
chore: merge `tsconfig.build.json` into `tsconfig.json` for packages
Bentroen Jan 4, 2026
d5f531d
fix: remove `@database` path alias in database package
Bentroen Jan 4, 2026
2186717
chore: remove `build:types` script from packages and replace with `ts…
Bentroen Jan 4, 2026
bcf7af3
chore: add `typecheck` command to workspace root
Bentroen Jan 4, 2026
2b0eeff
chore: make backend and frontend TS projects `composite` (following r…
Bentroen Jan 4, 2026
67daa09
chore: clean up frontend's `tsconfig.json`
Bentroen Jan 4, 2026
dc7f599
chore: clean up backend's `tsconfig.json`
Bentroen Jan 4, 2026
710d79e
style: add comments and line breaks to frontend/backend tsconfig
Bentroen Jan 4, 2026
b5e6023
style: fully comment settings in base and package `tsconfig.json`
Bentroen Jan 4, 2026
f508b89
chore: add type checking workflow on push and pull request
Bentroen Jan 4, 2026
a011504
chore: add `eslint-import-resolver-typescript` dependency
Bentroen Jan 5, 2026
06dbb5c
chore: add separate TS config for ESLint
Bentroen Jan 5, 2026
2b3c4a7
chore: add `baseUrl` and `@nbw` path alias to root TS config
Bentroen Jan 5, 2026
9faf154
chore: ensure that orchestrator TS config doesn't emit types
Bentroen Jan 5, 2026
79f2bf9
chore: remove `outDir` from base TS config
Bentroen Jan 6, 2026
8498c2f
fix: add `baseUrl` to app TS configs
Bentroen Jan 5, 2026
f85b959
fix: ensure types are emitted in `configs` package through `rootDir` …
Bentroen Jan 5, 2026
ab269fc
fix: enforce `src -> dist` output structure for all packages
Bentroen Jan 5, 2026
4eab8c9
build: re-introduce separate `js` and `types` steps in database build
Bentroen Jan 6, 2026
774326d
chore: ensure TS build cache files are output to `dist`
Bentroen Jan 6, 2026
d148680
chore: let TS infer build cache output location as `dist/`
Bentroen Jan 6, 2026
3dbd11f
fix: incorrect import alias in `database` package
Bentroen Jan 6, 2026
0ca8c47
fix: `thumbnail` package using removed `build:types` script
Bentroen Jan 6, 2026
5d94120
chore: remove `composite` from frontend and backend packages
Bentroen Jan 6, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions .github/workflows/typecheck.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
name: Type Check

on:
push:
branches:
- develop
- main
pull_request:
branches:
- develop
- main

jobs:
typecheck:
runs-on: ubuntu-latest
env:
THUMBNAIL_URL: ${{ vars.THUMBNAIL_URL }}

steps:
- name: Checkout
uses: actions/checkout@v4

- name: Install bun
uses: oven-sh/setup-bun@v2
with:
bun-version: latest

- name: Install dependencies
run: bun install

- name: Type check (project references)
run: bun run typecheck
4 changes: 3 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,7 @@
"files.associations": {
".css": "tailwindcss",
"*.scss": "tailwindcss"
}
},
"typescript.tsdk": "./node_modules/typescript/lib",
"typescript.enablePromptUseWorkspaceTsdk": true
}
4 changes: 0 additions & 4 deletions apps/backend/tsconfig.build.json

This file was deleted.

13 changes: 3 additions & 10 deletions apps/backend/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,13 @@
"removeComments": true,
"allowSyntheticDefaultImports": true,
"sourceMap": true,
"outDir": "./dist",
"baseUrl": "./",
"emitDecoratorMetadata": true,
// Relaxed strict settings for backend
"strictNullChecks": false,
"noImplicitAny": false,
"strictBindCallApply": false,
"forceConsistentCasingInFileNames": false,
"noFallthroughCasesInSwitch": false,

// Path mapping
"baseUrl": ".",
"paths": {
"@server/*": ["src/*"]
}
},
"include": ["src/**/*.ts", "src/**/*.d.ts"],
"exclude": ["node_modules", "dist", "e2e/**/*", "test/**/*"]
"include": ["src", "scripts"]
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,16 @@ import { parseSongFromBuffer, type SongFileType } from '@nbw/song';
import axiosInstance from '@web/lib/axios';
import { getTokenLocal } from '@web/lib/axios/token.utils';
import {
EditSongForm,
EditSongFormInput,
EditSongFormOutput,
editSongFormSchema,
} from '@web/modules/song/components/client/SongForm.zod';

export type useEditSongProviderType = {
formMethods: UseFormReturn<EditSongForm>;
formMethods: UseFormReturn<EditSongFormInput>;
submitSong: () => void;
register: UseFormRegister<EditSongForm>;
errors: FieldErrors<EditSongForm>;
register: UseFormRegister<EditSongFormInput>;
errors: FieldErrors<EditSongFormInput>;
song: SongFileType | null;
instrumentSounds: string[];
setInstrumentSound: (index: number, value: string) => void;
Expand All @@ -45,7 +46,7 @@ export const EditSongProvider = ({
}: {
children: React.ReactNode;
}) => {
const formMethods = useForm<EditSongForm>({
const formMethods = useForm<EditSongFormInput>({
resolver: zodResolver(editSongFormSchema),
mode: 'onBlur',
});
Expand All @@ -67,23 +68,26 @@ export const EditSongProvider = ({
return false;
}

const rawValues = formMethods.getValues();
const parsedValues: EditSongFormOutput =
editSongFormSchema.parse(rawValues);

const formValues = {
allowDownload: formMethods.getValues().allowDownload,
visibility: formMethods.getValues().visibility,
title: formMethods.getValues().title,
originalAuthor: formMethods.getValues().originalAuthor,
description: formMethods.getValues().description,
allowDownload: parsedValues.allowDownload,
visibility: parsedValues.visibility,
title: parsedValues.title,
originalAuthor: parsedValues.originalAuthor,
description: parsedValues.description,
thumbnailData: {
zoomLevel: formMethods.getValues().thumbnailData.zoomLevel,
startTick: formMethods.getValues().thumbnailData.startTick,
startLayer: formMethods.getValues().thumbnailData.startLayer,
backgroundColor:
formMethods.getValues().thumbnailData.backgroundColor,
zoomLevel: parsedValues.thumbnailData.zoomLevel,
startTick: parsedValues.thumbnailData.startTick,
startLayer: parsedValues.thumbnailData.startLayer,
backgroundColor: parsedValues.thumbnailData.backgroundColor,
},
artist: formMethods.getValues().author,
customInstruments: formMethods.getValues().customInstruments,
license: formMethods.getValues().license,
category: formMethods.getValues().category,
artist: parsedValues.author,
customInstruments: parsedValues.customInstruments,
license: parsedValues.license,
category: parsedValues.category,
};

const comparisons = [
Expand Down Expand Up @@ -123,23 +127,26 @@ export const EditSongProvider = ({
);

const submitSong = async (): Promise<void> => {
const rawValues = formMethods.getValues();
const parsedValues: EditSongFormOutput =
editSongFormSchema.parse(rawValues);

// Build form data
const formValues: UploadSongDto = {
allowDownload: formMethods.getValues().allowDownload,
visibility: formMethods.getValues()
.visibility as UploadSongDto['visibility'],
title: formMethods.getValues().title,
originalAuthor: formMethods.getValues().originalAuthor,
description: formMethods.getValues().description,
allowDownload: parsedValues.allowDownload,
visibility: parsedValues.visibility as UploadSongDto['visibility'],
title: parsedValues.title,
originalAuthor: parsedValues.originalAuthor,
description: parsedValues.description,
thumbnailData: {
zoomLevel: formMethods.getValues().thumbnailData.zoomLevel,
startTick: formMethods.getValues().thumbnailData.startTick,
startLayer: formMethods.getValues().thumbnailData.startLayer,
backgroundColor: formMethods.getValues().thumbnailData.backgroundColor,
zoomLevel: parsedValues.thumbnailData.zoomLevel,
startTick: parsedValues.thumbnailData.startTick,
startLayer: parsedValues.thumbnailData.startLayer,
backgroundColor: parsedValues.thumbnailData.backgroundColor,
},
customInstruments: formMethods.getValues().customInstruments,
license: formMethods.getValues().license as UploadSongDto['license'],
category: formMethods.getValues().category as UploadSongDto['category'],
customInstruments: parsedValues.customInstruments,
license: parsedValues.license as UploadSongDto['license'],
category: parsedValues.category as UploadSongDto['category'],
file: zodUndefined,
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ import { parseSongFromBuffer, type SongFileType } from '@nbw/song';
import axiosInstance from '@web/lib/axios';
import { InvalidTokenError, getTokenLocal } from '@web/lib/axios/token.utils';
import {
UploadSongForm,
UploadSongFormInput,
UploadSongFormOutput,
uploadSongFormSchema,
} from '@web/modules/song/components/client/SongForm.zod';

Expand Down Expand Up @@ -76,9 +77,9 @@ export const useUploadSongStore = create<UploadSongStore>((set, get) => ({

// Context for form methods (React Hook Form needs to be initialized in a component)
interface UploadSongFormContextType {
formMethods: UseFormReturn<UploadSongForm>;
register: UseFormRegister<UploadSongForm>;
errors: FieldErrors<UploadSongForm>;
formMethods: UseFormReturn<UploadSongFormInput>;
register: UseFormRegister<UploadSongFormInput>;
errors: FieldErrors<UploadSongFormInput>;
setFile: (file: File | null) => Promise<void>;
setInstrumentSound: (index: number, value: string) => void;
submitSong: () => Promise<void>;
Expand All @@ -94,10 +95,10 @@ export type useUploadSongProviderType = {
setFile: (file: File | null) => void;
instrumentSounds: string[];
setInstrumentSound: (index: number, value: string) => void;
formMethods: UseFormReturn<UploadSongForm>;
formMethods: UseFormReturn<UploadSongFormInput>;
submitSong: () => void;
register: UseFormRegister<UploadSongForm>;
errors: FieldErrors<UploadSongForm>;
register: UseFormRegister<UploadSongFormInput>;
errors: FieldErrors<UploadSongFormInput>;
sendError: string | null;
isSubmitting: boolean;
isUploadComplete: boolean;
Expand Down Expand Up @@ -128,7 +129,7 @@ export const UploadSongProvider = ({
setUploadedSongId,
} = store;

const formMethods = useForm<UploadSongForm>({
const formMethods = useForm<UploadSongFormInput>({
resolver: zodResolver(uploadSongFormSchema),
mode: 'onBlur',
// Prevents values from appearing empty on first render
Expand Down Expand Up @@ -164,7 +165,12 @@ export const UploadSongProvider = ({
// Build form data
const formData = new FormData();
formData.append('file', blob, filename || 'song.nbs');
const formValues = formMethods.getValues();

// Parse and normalize values
const rawValues = formMethods.getValues();

const formValues: UploadSongFormOutput =
uploadSongFormSchema.parse(rawValues);

Object.entries(formValues)
.filter(
Expand Down
12 changes: 8 additions & 4 deletions apps/frontend/src/modules/song/components/client/SongForm.zod.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,12 @@ export const editSongFormSchema = SongFormSchema.extend({
id: zod.string(),
});

export type ThumbnailDataForm = zod.infer<typeof thumbnailDataSchema>;
// forms
export type ThumbnailDataFormInput = zod.input<typeof thumbnailDataSchema>;
export type UploadSongFormInput = zod.input<typeof uploadSongFormSchema>;
export type EditSongFormInput = zod.input<typeof editSongFormSchema>;

export type UploadSongForm = zod.infer<typeof uploadSongFormSchema>;

export type EditSongForm = zod.infer<typeof editSongFormSchema>;
// parsed data
export type ThumbnailDataFormOutput = zod.infer<typeof thumbnailDataSchema>;
export type UploadSongFormOutput = zod.output<typeof uploadSongFormSchema>;
export type EditSongFormOutput = zod.output<typeof editSongFormSchema>;
16 changes: 6 additions & 10 deletions apps/frontend/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,22 +13,23 @@
"esModuleInterop": true,
"resolveJsonModule": true,
"isolatedModules": true,

// Override base strict settings for Next.js compatibility
"strict": true,
"strictNullChecks": true,
"noImplicitAny": true,
"strictBindCallApply": true,
"strictPropertyInitialization": false,

// Next.js plugins and types
"plugins": [
{
"name": "next"
}
],
"types": ["mdx"],

// Path mapping
"baseUrl": ".",
"paths": {
"@web/*": ["./src/*"]
"@web/*": ["src/*"]
}
},
"include": [
Expand All @@ -37,10 +38,5 @@
"**/*.tsx",
"**/*.mdx",
".next/types/**/*.ts"
],
"types": ["mdx"],
// Path mapping
"paths": {
"@web/*": ["./src/*"]
}
]
}
Loading
Loading