Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
59 changes: 59 additions & 0 deletions .github/workflows/lint.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
name: Lint

on:
push:
branches: ["main"]
pull_request:
types: [opened, synchronize, reopened]

permissions:
contents: read

concurrency:
group: lint-${{ github.ref }}
cancel-in-progress: true

jobs:
lint:
name: 🧹 Lint
runs-on: ubuntu-latest
steps:
- name: ⬇️ Checkout repo
uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0
with:
persist-credentials: false

- name: 🍞 Setup Bun
uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0
with:
bun-version: 1.3.14

# oxlint and the root workspace (brand, core, web, tools/xss-scan).
- name: 📥 Download root deps
run: bun install --frozen-lockfile

# Type-aware rules and import checks read every package's types, so
# each package with its own lockfile gets its dependencies too.
- name: 📥 Download app deps
working-directory: app
run: bun install --frozen-lockfile

- name: 📥 Download CLI deps
working-directory: atw-cli
run: bun install --frozen-lockfile

- name: 📥 Download infra deps
working-directory: infra
run: bun install --frozen-lockfile

- name: 📥 Download pr-header deps
working-directory: tools/pr-header
run: bun install --frozen-lockfile

# web/src imports the manifest its build writes to web/dist.
- name: 🏗️ Build web
working-directory: web
run: bun run build

- name: 🧹 Lint
run: bun run lint
51 changes: 51 additions & 0 deletions .oxlintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
{
"$schema": "./node_modules/oxlint/configuration_schema.json",
// One rule set for every package. app/ and web/ extend it with their JSX
// plugins in their own .oxlintrc.json.
"plugins": ["typescript", "unicorn", "oxc", "import", "promise"],
"categories": {
"correctness": "error",
"suspicious": "error"
},
"options": {
// Type-aware rules run on oxlint-tsgolint, which follows TypeScript 7.
"typeAware": true,
"denyWarnings": true,
"reportUnusedDisableDirectives": "error"
},
"rules": {
// A micro-optimization that is noisy in tests and Effect code.
"unicorn/consistent-function-scoping": "off",
// Effect's `_tag` and friends are idiomatic.
"eslint/no-underscore-dangle": "off",
// Omitting keys with a rest sibling (`const { a, ...rest } = x`) is how we
// drop fields, so those siblings are used.
"eslint/no-unused-vars": ["error", { "ignoreRestSiblings": true }],
// TypeScript checks namespace members already, and this rule resolves
// conditional exports wrongly (it misses @sentry/nextjs's browser API).
"import/namespace": "off",
"import/no-unassigned-import": [
"error",
{ "allow": ["**/*.css", "server-only"] }
],
// Each of today's casts (most in app/) needs a runtime check to replace
// it. That is its own change; this one keeps behavior as it is.
"typescript/no-unsafe-type-assertion": "off",
// JSX event handlers may be async: React ignores what they return.
"typescript/no-misused-promises": [
"error",
{ "checksVoidReturn": { "attributes": false } }
],
"typescript/only-throw-error": "error",
"typescript/prefer-promise-reject-errors": "error",
"typescript/switch-exhaustiveness-check": "error"
},
"overrides": [
{
// bun-types declares `expect(...).rejects` matchers as returning void,
// but they return promises that must be awaited.
"files": ["**/tests/**"],
"rules": { "typescript/await-thenable": "off" }
}
]
}
31 changes: 31 additions & 0 deletions app/.oxlintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
{
"$schema": "../node_modules/oxlint/configuration_schema.json",
// The root rule set, plus React, Next.js and accessibility checks for this
// Next.js app. A nested config because `overrides` cannot enable categories.
"extends": ["../.oxlintrc.json"],
"plugins": [
"typescript",
"unicorn",
"oxc",
"import",
"promise",
"react",
"nextjs",
"jsx-a11y"
],
"rules": {
// The automatic JSX runtime needs no React in scope.
"react/react-in-jsx-scope": "off",
// These check what the React Compiler can optimize, and this app doesn't
// use it. What they flag here are working effects (syncing form fields on
// selection, subscribing to media queries and carousels); rewriting them
// would change behavior, not fix it.
"react/set-state-in-effect": "off",
"react/immutability": "off",
"react/exhaustive-effect-dependencies": "off",
"react/purity": "off",
// Option text sits three elements deep inside its label.
"jsx-a11y/label-has-associated-control": ["error", { "depth": 3 }],
"jsx-a11y/control-has-associated-label": ["error", { "depth": 3 }]
}
}
2 changes: 1 addition & 1 deletion app/scripts/add-host.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,4 @@ async function main() {
console.log("Done");
}

main();
await main();
2 changes: 1 addition & 1 deletion app/scripts/add-images.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,4 @@ async function main() {
}
}

main();
await main();
2 changes: 1 addition & 1 deletion app/scripts/add-talk.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,4 @@ async function main() {
console.log("Done");
}

main();
await main();
2 changes: 1 addition & 1 deletion app/scripts/add-user-to-admins.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,4 @@ async function main() {
}
}

main();
await main();
2 changes: 1 addition & 1 deletion app/scripts/create-event.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,4 @@ async function main() {
console.log(res);
}

main();
await main();
2 changes: 1 addition & 1 deletion app/scripts/create-host.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,4 @@ async function main() {
console.log(createdHost.id);
}

main();
await main();
2 changes: 1 addition & 1 deletion app/scripts/create-profile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,4 @@ async function main() {
console.log(createdProfile.id);
}

main();
await main();
2 changes: 1 addition & 1 deletion app/scripts/create-talk.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,4 @@ async function main() {
console.log(speakers);
}

main();
await main();
2 changes: 1 addition & 1 deletion app/scripts/delete-image.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,4 @@ async function main() {
}
}

main();
await main();
4 changes: 2 additions & 2 deletions app/scripts/delete-profile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ async function main() {
console.log(`Name: ${profile.name}`);
console.log(`Type: ${profile.profileType}`);
console.log(`Title: ${profile.title}`);
console.log(`Created: ${profile.createdAt}`);
console.log(`Created: ${String(profile.createdAt)}`);
if (profile.image) {
console.log(`Image ID: ${profile.image}`);
}
Expand Down Expand Up @@ -99,5 +99,5 @@ async function main() {

// Only run if this script is executed directly
if (import.meta.main) {
main();
await main();
}
2 changes: 1 addition & 1 deletion app/scripts/find-profile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,4 @@ async function main() {
console.log(profile);
}

main();
await main();
5 changes: 2 additions & 3 deletions app/scripts/find-talks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,11 @@ import { findTalksBySpeakerName } from "./functions";
const speakerName = "Ted Nyman";

async function main() {
const { speaker, talks, talkEvents } =
await findTalksBySpeakerName(speakerName);
const { talks, talkEvents } = await findTalksBySpeakerName(speakerName);
if (talkEvents) {
console.log(talkEvents);
}
console.log(talks);
}

main();
await main();
9 changes: 6 additions & 3 deletions app/scripts/functions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import {
removeStoredObject,
} from "../src/lib/media-store";
import { profilePhotoKey } from "../src/lib/profile-photos/ingest";
import { mainConfig } from "../src/lib/config";
import {
eventImagesTable,
eventHostsTable,
Expand Down Expand Up @@ -471,7 +470,7 @@ export async function deleteEventImages(imageUrls: string[]) {
const ids = await getImgIdsForUrls(imageUrls);

const results = [];
for await (const id of ids) {
for (const id of ids) {
const image = await db
.select()
.from(imagesTable)
Expand Down Expand Up @@ -525,6 +524,7 @@ export async function deleteOrphanedImage(imageUrl: string) {
// PostgreSQL foreign key constraint violation
throw new Error(
`Image ${imageUrl} is not orphaned - it is still referenced by other records (foreign key constraint)`,
{ cause: error },
);
}
// Re-throw other errors
Expand All @@ -545,6 +545,7 @@ export async function deleteOrphanedImage(imageUrl: string) {
} catch (error) {
throw new Error(
`Failed to delete orphaned image from storage: ${error instanceof Error ? error.message : "Unknown error"}`,
{ cause: error },
);
}
}
Expand All @@ -562,7 +563,7 @@ export async function addImagesToEvent(
const filePaths = fileNames.map((fn) => join(imagesDir, fn));

const results = [];
for await (const entry of filePaths) {
for (const entry of filePaths) {
const uuid = randomUUID();

// Process image using our new utility
Expand Down Expand Up @@ -690,6 +691,7 @@ export async function getLumaEvent(eventId: string) {
console.error(`Failed to fetch Luma event ${eventId}:`, error);
throw new Error(
`Failed to fetch Luma event: ${error instanceof Error ? error.message : String(error)}`,
{ cause: error },
);
}
}
Expand Down Expand Up @@ -803,6 +805,7 @@ export async function deleteProfile(profileId: string) {
console.error("❌ Error during deletion process:", error);
throw new Error(
`Deletion failed: ${error instanceof Error ? error.message : String(error)}`,
{ cause: error },
);
}
}
2 changes: 1 addition & 1 deletion app/scripts/get-event.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,4 @@ async function main() {
console.log(event);
}

main();
await main();
2 changes: 1 addition & 1 deletion app/scripts/get-image-ids.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,4 @@ async function main() {
console.log(ids);
}

main();
await main();
2 changes: 1 addition & 1 deletion app/scripts/get-luma-event.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,4 @@ async function main() {
}
}

main();
await main();
2 changes: 1 addition & 1 deletion app/scripts/list-admins.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,4 @@ async function main() {
}
}

main();
await main();
6 changes: 3 additions & 3 deletions app/scripts/mcp-server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -527,10 +527,10 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {

// Tool execution handler
server.setRequestHandler(CallToolRequestSchema, async (request) => {
const { name, arguments: args } = request.params;
const { name: toolName, arguments: args } = request.params;

try {
switch (name) {
switch (toolName) {
// Event tools
case "create_event": {
const { event } = args as { event: any };
Expand Down Expand Up @@ -862,7 +862,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
}

default:
throw new Error(`Unknown tool: ${name}`);
throw new Error(`Unknown tool: ${toolName}`);
}
} catch (error) {
return {
Expand Down
2 changes: 1 addition & 1 deletion app/scripts/remove-talk.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,4 @@ async function main() {
console.log(`Deleted ${result.length} talk(s) from event`);
}

main();
await main();
2 changes: 1 addition & 1 deletion app/scripts/remove-user-from-admins.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,4 @@ async function main() {
}
}

main();
await main();
2 changes: 1 addition & 1 deletion app/scripts/update-event.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,4 @@ async function main() {
console.log(res);
}

main();
await main();
8 changes: 4 additions & 4 deletions app/src/app/2025-06-02-nextdevfm-live/page.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { notFound } from "next/navigation";
import { Metadata } from "next";
import Link from "next/link";
import { getExpandedEventBySlug } from "@/lib/expanded-events";
import { getExpandedEventBySlug, type Speaker } from "@/lib/expanded-events";
import { isEventInPast } from "@/lib/events";
import { mainConfig } from "@/lib/config";
import {
Expand Down Expand Up @@ -123,8 +123,8 @@ function LivePodcastSection({
guest,
showEventImageSection,
}: {
hosts: (any | null)[];
guest: any | null;
hosts: (Speaker | null)[];
guest: Speaker | null;
showEventImageSection: boolean;
}) {
return (
Expand Down Expand Up @@ -163,7 +163,7 @@ function LivePodcastSection({
<h3 className="text-xl font-semibold mb-2">Hosts</h3>
<div className="flex flex-col md:flex-row gap-6 w-full items-center md:items-stretch">
{hosts.map(
(host, i) =>
(host) =>
host && (
<Card
key={host.id}
Expand Down
Loading
Loading