Skip to content

Conversation

@joelhooks
Copy link
Collaborator

@joelhooks joelhooks commented Oct 11, 2025

  • start inngest realtime spike
  • enable realtime

Summary by CodeRabbit

  • New Features
    • Opt-in real-time video upload and live status updates (enabled via a new public feature flag).
    • Client subscriptions for video status with automatic UI refresh on video/transcript events.
  • Improvements
    • Dual-path delivery: realtime publish with graceful fallback to existing broadcast for reliability.
  • Documentation
    • Added migration plan for moving to the realtime approach.
  • Chores
    • Prepared patch releases and updated configuration and related packages across apps.

@vercel
Copy link

vercel bot commented Oct 11, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Comments Updated (UTC)
ai-hero Ready Ready Preview Comment Oct 15, 2025 2:44pm
code-with-antonio Error Error Oct 15, 2025 2:44pm
course-builder-egghead Ready Ready Preview Comment Oct 15, 2025 2:44pm
epic-react-builder Ready Ready Preview Comment Oct 15, 2025 2:44pm
epic-web-builder Ready Ready Preview Comment Oct 15, 2025 2:44pm
epicai-pro Ready Ready Preview Comment Oct 15, 2025 2:44pm

@joelhooks joelhooks requested a review from vojtaholik October 11, 2025 17:16
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 11, 2025

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

Walkthrough

Adds Inngest Realtime support and feature-flagged realtime video events across server and client: middleware wiring, a realtime channel schema, conditional publish paths in core video handlers, client subscription hooks and token action, removal of PartyKit onConnect logic, and dependency bumps (inngest and @inngest/realtime). Adds planning doc and changesets.

Changes

Cohort / File(s) Summary
Changesets & Config
/.changeset/config.json, /.changeset/purple-doors-attend.md
Updated changeset config ignore list to include code-with-antonio. Added new changeset documenting patch releases and note "add inngest realtime".
Env flag for realtime
apps/code-with-antonio/.env.development
Adds NEXT_PUBLIC_ENABLE_REALTIME_VIDEO_UPLOAD="true" development feature flag.
Client realtime integration (code-with-antonio)
apps/code-with-antonio/src/app/(content)/posts/_components/standalone-video-resource-uploader-and-viewer.tsx, apps/code-with-antonio/src/components/content/content-video-resource-field.tsx, apps/code-with-antonio/src/components/party.tsx, apps/code-with-antonio/src/hooks/use-video-realtime.ts, apps/code-with-antonio/src/app/actions/realtime.ts
Replaces socket/onMessage flows with useVideoRealtimeSubscription; adds server action fetchRealtimeVideoToken; subscription uses videoChannel(...).status; components react to subscription.latestData; gated by env flag.
Party server pruning
apps/code-with-antonio/party/index.ts
Removed onConnect and PartyKit/Yjs document loading and snapshot/persist logic; retained message storage and HTTP handling.
Inngest middleware wiring
apps/code-with-antonio/src/inngest/inngest.server.ts, packages/core/src/inngest/create-inngest-middleware.ts
Import and add realtimeMiddleware() to Inngest initialization/middleware stack.
Core video-processing: conditional realtime publish
packages/core/src/inngest/video-processing/functions/video-uploaded.ts, .../video-ready.ts, .../video-processing-error.ts, .../transcript-ready.ts, .../generate-transcript-with-screnshots.ts
Handlers extended to accept publish; build unified payloads and either publish(videoChannel(roomId).status(...)) when realtime enabled/publish available or fallback to partyProvider.broadcastMessage.
Realtime channel schema
packages/core/src/inngest/video-processing/realtime.ts
Adds videoChannel with status topic and Zod-validated payload schema; exports VideoStatusPayload type.
Dependency updates: inngest
apps/*/package.json (ai-hero, astro-party, course-builder-web, craft-of-ui, cursor-pro, egghead, epic-react, epic-web, epicdev-ai, go-local-first), cli/template-app-with-posts/package.json, packages/next/package.json, apps/code-with-antonio/package.json, packages/core/package.json
Bumps inngest from 3.35.0 to 3.44.2 across many apps/packages; adds @inngest/realtime to apps/code-with-antonio and packages/core.
Planning doc
/plans/partykit-to-inngest-realtime.md
Adds migration plan for moving from PartyKit to Inngest realtime with bootstrap, middleware, handler adaptation, client subscription, env/flag scaffolding, testing, rollout, and rollback notes.
Markdown rendering tweak
apps/ai-hero/src/app/(content)/workshops/[module]/page.tsx
Replaced plain paragraph with ReactMarkdown for workshop description rendering.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor U as User (Browser)
  participant C as React Component
  participant H as useVideoRealtimeSubscription
  participant SA as fetchRealtimeVideoToken (server)
  participant RT as Inngest Realtime
  participant IF as Inngest Function(s)

  Note over C,U: Flag: NEXT_PUBLIC_ENABLE_REALTIME_VIDEO_UPLOAD=true
  U->>C: Load page (video resource)
  C->>H: Init subscription (roomId, enabled)
  H->>SA: Request token for roomId
  SA->>RT: getSubscriptionToken(videoChannel(roomId), topics:['status'])
  RT-->>SA: Token
  SA-->>H: Token
  H->>RT: Subscribe to channel topic: status
  par Processing
    IF->>RT: publish(videoChannel(roomId).status(payload))
  and Fallback
    IF->>C: partyProvider.broadcastMessage(payload) (when realtime disabled/unavailable)
  end
  RT-->>H: status event (payload)
  H-->>C: latestData update
  C->>C: React effect handles payload (refetch/refresh/update)
Loading
sequenceDiagram
  autonumber
  participant IF as Inngest Function
  participant RM as realtimeMiddleware
  participant PUB as publish
  participant RT as Inngest Realtime

  IF->>RM: Handler invoked with context
  RM-->>IF: Injects publish()
  IF->>IF: Build payload {name, body, requestId}
  alt realtimeEnabled && publish
    IF->>PUB: videoChannel(roomId).status(payload)
    PUB->>RT: send
  else
    IF->>IF: partyProvider.broadcastMessage(payload)
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested reviewers

  • vojtaholik
  • nicollguarnizo

Poem

"I’m a rabbit on the realtime track,
Hopping tokens, sending back.
Channels bloom and payloads sing,
Flags flipped up—new updates spring.
Sniff, thump, deploy—let messages pack!" 🐇✨

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The title “joel/inngest realtime” references the addition of Inngest realtime functionality, which aligns with the primary change set enabling realtime behavior across the repo. Although the “joel/” prefix is branch-style noise and the phrase could be more polished, it does point to the main change of integrating realtime via Inngest.
Docstring Coverage ✅ Passed No functions found in the changes. Docstring coverage check skipped.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch joel/inngest-realtime

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4676436 and e172dd6.

📒 Files selected for processing (1)
  • apps/ai-hero/src/app/(content)/workshops/[module]/page.tsx (1 hunks)
🧰 Additional context used
📓 Path-based instructions (5)
**/*.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (.cursorrules)

Add JS Doc comments to functions and React components

Files:

  • apps/ai-hero/src/app/(content)/workshops/[module]/page.tsx
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx,js,jsx}: Use single quotes, no semicolons, tabs (width: 2), and an 80 character line limit for code formatting.
Organize imports in the following order: React → Next → 3rd party → internal.
Do NOT use Object.defineProperty(exports, ...) for re-exports. Use standard export patterns instead to avoid conflicts with framework internals.

Files:

  • apps/ai-hero/src/app/(content)/workshops/[module]/page.tsx
apps/**/*

📄 CodeRabbit inference engine (.cursor/rules/monorepo-setup.mdc)

Apps are located in the /apps directory

Files:

  • apps/ai-hero/src/app/(content)/workshops/[module]/page.tsx
apps/ai-hero/**/*.{ts,tsx}

📄 CodeRabbit inference engine (apps/ai-hero/.cursor/rules/analytics.mdc)

apps/ai-hero/**/*.{ts,tsx}: The track function in @/utils/analytics.ts is ONLY for tracking learner/customer activity (such as course progress, video watching, exercise completion, purchase activity, and user preferences). Do NOT use track for internal admin actions, content management, system operations, or backend processes.
Use log from @/server/logger.ts for system operations, content management, error tracking, performance monitoring, and backend processes.
Always include relevant IDs and context in log messages.

Always use kebab-case when naming files

Add JSDoc comments to exported methods and React components in TypeScript files

Files:

  • apps/ai-hero/src/app/(content)/workshops/[module]/page.tsx
apps/ai-hero/**/*.tsx

📄 CodeRabbit inference engine (apps/ai-hero/.cursor/rules/component-system.mdc)

Use base React components from the /packages/ui package when possible

Files:

  • apps/ai-hero/src/app/(content)/workshops/[module]/page.tsx
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (6)
  • GitHub Check: Cursor Bugbot
  • GitHub Check: typecheck
  • GitHub Check: format
  • GitHub Check: lint
  • GitHub Check: build
  • GitHub Check: e2e-node (course-builder-web)
🔇 Additional comments (2)
apps/ai-hero/src/app/(content)/workshops/[module]/page.tsx (2)

32-32: LGTM! Import correctly positioned.

The ReactMarkdown import follows the project's import organization guidelines (React → Next → 3rd party → internal).


227-231: Verify workshop descriptions render correctly

Switching to ReactMarkdown (default settings: escapes HTML, parses markdown) may alter how existing descriptions display. Ensure that:

  • No descriptions rely on raw HTML tags (they’ll now render as text)
  • Literal markdown characters (*, _, #, etc.) won’t cause unintended formatting
  • All descriptions have been reviewed or migrated to valid Markdown in the database

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@socket-security
Copy link

socket-security bot commented Oct 11, 2025

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Added@​inngest/​realtime@​0.4.4981007298100
Updatedinngest@​3.35.0 ⏵ 3.44.29710010099100

View full report

@socket-security
Copy link

socket-security bot commented Oct 11, 2025

All alerts resolved. Learn more about Socket for GitHub.

This PR previously contained dependency changes with security issues that have been resolved, removed, or ignored.

View full report

cursor[bot]

This comment was marked as outdated.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 13

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/core/src/inngest/video-processing/functions/generate-transcript-with-screnshots.ts (1)

1-107: Extract duplicated announcement pattern into a shared helper.

The pattern of constructing a payload, checking the realtime flag, and conditionally publishing or broadcasting is duplicated across video-uploaded.ts, video-processing-error.ts, and this file. This violates the DRY principle.

Consider creating a shared helper function in a utilities file:

// packages/core/src/inngest/video-processing/utils/announce-status.ts
import { videoChannel } from '../realtime'
import type { PartyProvider } from '../../types'

const realtimeEnabled =
	process.env.NEXT_PUBLIC_ENABLE_REALTIME_VIDEO_UPLOAD === 'true'

export async function announceVideoStatus(
	params: {
		roomId: string
		payload: {
			name: string
			body: any
			requestId: string
		}
		publish?: any
		partyProvider: PartyProvider
	}
) {
	const { roomId, payload, publish, partyProvider } = params

	if (realtimeEnabled && publish) {
		await publish(videoChannel(roomId).status(payload))
	} else {
		await partyProvider.broadcastMessage({
			body: payload,
			roomId,
		})
	}
}

Then use it in each handler:

await step.run('announce video resource created', async () => {
	await announceVideoStatus({
		roomId: videoResource.id,
		payload: {
			name: 'videoResource.created',
			body: videoResource,
			requestId: videoResource.id,
		},
		publish,
		partyProvider,
	})
})
🧹 Nitpick comments (5)
apps/code-with-antonio/src/app/actions/realtime.ts (2)

3-7: Reorder imports: 3rd‑party before internal

Import order should be React → Next → 3rd party → internal. Move @inngest/realtime above internal paths. As per coding guidelines.

-'use server'
-
-import { inngest } from '@/inngest/inngest.server'
-import { getSubscriptionToken, type Realtime } from '@inngest/realtime'
-
-import { videoChannel } from '@coursebuilder/core/inngest/video-processing/realtime'
+'use server'
+
+import { getSubscriptionToken, type Realtime } from '@inngest/realtime'
+import { inngest } from '@/inngest/inngest.server'
+import { videoChannel } from '@coursebuilder/core/inngest/video-processing/realtime'

10-13: Add JSDoc to exported server action

Document params/return and auth expectation. As per coding guidelines.

+/**
+ * Fetches a scoped realtime subscription token for the given video room.
+ * Requires the caller to be authorized to access the room.
+ * @param roomId string Room identifier (e.g. video ID)
+ * @returns Realtime token scoped to ['status'] topic
+ */
 export async function fetchRealtimeVideoToken(
 	roomId: string,
 ): Promise<VideoRealtimeToken> {
apps/code-with-antonio/src/components/party.tsx (1)

9-11: Add JSDoc to exported component

Per guidelines, document the component and props.

+/**
+ * Subscribes to video realtime updates and refreshes the page on relevant events.
+ * @param room optional room ID used to scope the subscription
+ */
 export function Party({ room }: { room?: string }) {
packages/core/src/inngest/video-processing/functions/video-processing-error.ts (1)

56-63: Eliminate payload restructuring in fallback path.

The payload object is already constructed with the correct structure (lines 46-50), but the fallback path unnecessarily destructures and reconstructs it (lines 58-60).

Apply this diff to pass the payload directly:

 				await partyProvider.broadcastMessage({
-					body: {
-						body: payload.body,
-						requestId: payload.requestId,
-						name: payload.name,
-					},
+					body: payload,
 					roomId,
 				})
packages/core/src/inngest/video-processing/functions/video-uploaded.ts (1)

19-20: Use a server-only env var for realtime video upload in Inngest functions
Replace all instances of process.env.NEXT_PUBLIC_ENABLE_REALTIME_VIDEO_UPLOAD in packages/core/src/inngest/video-processing/functions/* with a non-public variable (e.g. ENABLE_REALTIME_VIDEO_UPLOAD) to decouple backend feature flags from client-exposed prefixes.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f955405 and 4676436.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (32)
  • .changeset/config.json (1 hunks)
  • .changeset/purple-doors-attend.md (1 hunks)
  • apps/ai-hero/package.json (1 hunks)
  • apps/astro-party/package.json (1 hunks)
  • apps/code-with-antonio/.env.development (1 hunks)
  • apps/code-with-antonio/package.json (2 hunks)
  • apps/code-with-antonio/party/index.ts (0 hunks)
  • apps/code-with-antonio/src/app/(content)/posts/_components/standalone-video-resource-uploader-and-viewer.tsx (2 hunks)
  • apps/code-with-antonio/src/app/actions/realtime.ts (1 hunks)
  • apps/code-with-antonio/src/components/content/content-video-resource-field.tsx (2 hunks)
  • apps/code-with-antonio/src/components/party.tsx (1 hunks)
  • apps/code-with-antonio/src/hooks/use-video-realtime.ts (1 hunks)
  • apps/code-with-antonio/src/inngest/inngest.server.ts (2 hunks)
  • apps/course-builder-web/package.json (1 hunks)
  • apps/craft-of-ui/package.json (1 hunks)
  • apps/cursor-pro/package.json (1 hunks)
  • apps/egghead/package.json (1 hunks)
  • apps/epic-react/package.json (1 hunks)
  • apps/epic-web/package.json (1 hunks)
  • apps/epicdev-ai/package.json (1 hunks)
  • apps/go-local-first/package.json (1 hunks)
  • cli/template-app-with-posts/package.json (1 hunks)
  • packages/core/package.json (2 hunks)
  • packages/core/src/inngest/create-inngest-middleware.ts (2 hunks)
  • packages/core/src/inngest/video-processing/functions/generate-transcript-with-screnshots.ts (3 hunks)
  • packages/core/src/inngest/video-processing/functions/transcript-ready.ts (3 hunks)
  • packages/core/src/inngest/video-processing/functions/video-processing-error.ts (3 hunks)
  • packages/core/src/inngest/video-processing/functions/video-ready.ts (3 hunks)
  • packages/core/src/inngest/video-processing/functions/video-uploaded.ts (2 hunks)
  • packages/core/src/inngest/video-processing/realtime.ts (1 hunks)
  • packages/next/package.json (1 hunks)
  • plans/partykit-to-inngest-realtime.md (1 hunks)
💤 Files with no reviewable changes (1)
  • apps/code-with-antonio/party/index.ts
🧰 Additional context used
📓 Path-based instructions (7)
**/*.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (.cursorrules)

Add JS Doc comments to functions and React components

Files:

  • packages/core/src/inngest/video-processing/realtime.ts
  • packages/core/src/inngest/create-inngest-middleware.ts
  • apps/code-with-antonio/src/components/content/content-video-resource-field.tsx
  • packages/core/src/inngest/video-processing/functions/video-uploaded.ts
  • apps/code-with-antonio/src/app/actions/realtime.ts
  • apps/code-with-antonio/src/app/(content)/posts/_components/standalone-video-resource-uploader-and-viewer.tsx
  • apps/code-with-antonio/src/hooks/use-video-realtime.ts
  • packages/core/src/inngest/video-processing/functions/video-ready.ts
  • packages/core/src/inngest/video-processing/functions/video-processing-error.ts
  • apps/code-with-antonio/src/components/party.tsx
  • packages/core/src/inngest/video-processing/functions/transcript-ready.ts
  • packages/core/src/inngest/video-processing/functions/generate-transcript-with-screnshots.ts
  • apps/code-with-antonio/src/inngest/inngest.server.ts
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx,js,jsx}: Use single quotes, no semicolons, tabs (width: 2), and an 80 character line limit for code formatting.
Organize imports in the following order: React → Next → 3rd party → internal.
Do NOT use Object.defineProperty(exports, ...) for re-exports. Use standard export patterns instead to avoid conflicts with framework internals.

Files:

  • packages/core/src/inngest/video-processing/realtime.ts
  • packages/core/src/inngest/create-inngest-middleware.ts
  • apps/code-with-antonio/src/components/content/content-video-resource-field.tsx
  • packages/core/src/inngest/video-processing/functions/video-uploaded.ts
  • apps/code-with-antonio/src/app/actions/realtime.ts
  • apps/code-with-antonio/src/app/(content)/posts/_components/standalone-video-resource-uploader-and-viewer.tsx
  • apps/code-with-antonio/src/hooks/use-video-realtime.ts
  • packages/core/src/inngest/video-processing/functions/video-ready.ts
  • packages/core/src/inngest/video-processing/functions/video-processing-error.ts
  • apps/code-with-antonio/src/components/party.tsx
  • packages/core/src/inngest/video-processing/functions/transcript-ready.ts
  • packages/core/src/inngest/video-processing/functions/generate-transcript-with-screnshots.ts
  • apps/code-with-antonio/src/inngest/inngest.server.ts
packages/**/*

📄 CodeRabbit inference engine (.cursor/rules/monorepo-setup.mdc)

Packages are located in the /packages directory

Files:

  • packages/core/src/inngest/video-processing/realtime.ts
  • packages/core/src/inngest/create-inngest-middleware.ts
  • packages/core/src/inngest/video-processing/functions/video-uploaded.ts
  • packages/core/src/inngest/video-processing/functions/video-ready.ts
  • packages/core/src/inngest/video-processing/functions/video-processing-error.ts
  • packages/core/package.json
  • packages/core/src/inngest/video-processing/functions/transcript-ready.ts
  • packages/core/src/inngest/video-processing/functions/generate-transcript-with-screnshots.ts
  • packages/next/package.json
**/package.json

📄 CodeRabbit inference engine (CLAUDE.md)

**/package.json: When adding dependencies to package.json files, ensure all packages use consistent dependency versions and dependencies are sorted alphabetically.
When updating package.json files to add dependencies, use string replacement to add dependencies and maintain alphabetical order. Do not replace entire sections, just add the new line.

Files:

  • apps/course-builder-web/package.json
  • apps/craft-of-ui/package.json
  • apps/ai-hero/package.json
  • apps/go-local-first/package.json
  • apps/astro-party/package.json
  • apps/epicdev-ai/package.json
  • apps/code-with-antonio/package.json
  • packages/core/package.json
  • apps/epic-react/package.json
  • apps/epic-web/package.json
  • apps/egghead/package.json
  • cli/template-app-with-posts/package.json
  • apps/cursor-pro/package.json
  • packages/next/package.json
apps/**/*

📄 CodeRabbit inference engine (.cursor/rules/monorepo-setup.mdc)

Apps are located in the /apps directory

Files:

  • apps/course-builder-web/package.json
  • apps/craft-of-ui/package.json
  • apps/ai-hero/package.json
  • apps/go-local-first/package.json
  • apps/astro-party/package.json
  • apps/epicdev-ai/package.json
  • apps/code-with-antonio/src/components/content/content-video-resource-field.tsx
  • apps/code-with-antonio/src/app/actions/realtime.ts
  • apps/code-with-antonio/src/app/(content)/posts/_components/standalone-video-resource-uploader-and-viewer.tsx
  • apps/code-with-antonio/src/hooks/use-video-realtime.ts
  • apps/code-with-antonio/package.json
  • apps/epic-react/package.json
  • apps/code-with-antonio/src/components/party.tsx
  • apps/epic-web/package.json
  • apps/egghead/package.json
  • apps/cursor-pro/package.json
  • apps/code-with-antonio/src/inngest/inngest.server.ts
apps/code-with-antonio/**/*.{ts,tsx}

📄 CodeRabbit inference engine (apps/code-with-antonio/.cursor/rules/analytics.mdc)

apps/code-with-antonio/**/*.{ts,tsx}: Only use track from @/utils/analytics.ts for learner/customer activity (course progress, video watching, exercise completion, purchase activity, user preferences)
Do not use track for internal admin actions, content management, system operations, or backend processes

Always use kebab-case when naming TypeScript and TSX files

apps/code-with-antonio/**/*.{ts,tsx}: Add JSDoc comments to exported methods/functions in TypeScript
Add JSDoc comments to exported React components

Files:

  • apps/code-with-antonio/src/components/content/content-video-resource-field.tsx
  • apps/code-with-antonio/src/app/actions/realtime.ts
  • apps/code-with-antonio/src/app/(content)/posts/_components/standalone-video-resource-uploader-and-viewer.tsx
  • apps/code-with-antonio/src/hooks/use-video-realtime.ts
  • apps/code-with-antonio/src/components/party.tsx
  • apps/code-with-antonio/src/inngest/inngest.server.ts
apps/code-with-antonio/**/*.tsx

📄 CodeRabbit inference engine (apps/code-with-antonio/.cursor/rules/component-system.mdc)

apps/code-with-antonio/**/*.tsx: Use base React components from the shared UI library instead of creating custom implementations
Prefer Radix/shadcn-based primitives exposed by /packages/ui (e.g., Dialog, Tooltip, Tabs) rather than importing Radix directly or using raw primitives
Before adding a new component, check /packages/ui for an existing base component to avoid duplication

Files:

  • apps/code-with-antonio/src/components/content/content-video-resource-field.tsx
  • apps/code-with-antonio/src/app/(content)/posts/_components/standalone-video-resource-uploader-and-viewer.tsx
  • apps/code-with-antonio/src/components/party.tsx
🧬 Code graph analysis (10)
apps/code-with-antonio/src/components/content/content-video-resource-field.tsx (2)
apps/code-with-antonio/src/hooks/use-video-realtime.ts (1)
  • useVideoRealtimeSubscription (10-32)
apps/code-with-antonio/src/app/actions/realtime.ts (1)
  • fetchRealtimeVideoToken (10-21)
packages/core/src/inngest/video-processing/functions/video-uploaded.ts (2)
packages/core/src/inngest/create-inngest-middleware.ts (2)
  • CoreInngestTrigger (51-53)
  • CoreInngestHandler (54-54)
packages/core/src/inngest/video-processing/realtime.ts (1)
  • videoChannel (18-20)
apps/code-with-antonio/src/app/actions/realtime.ts (1)
packages/core/src/inngest/video-processing/realtime.ts (1)
  • videoChannel (18-20)
apps/code-with-antonio/src/app/(content)/posts/_components/standalone-video-resource-uploader-and-viewer.tsx (2)
apps/code-with-antonio/src/hooks/use-video-realtime.ts (1)
  • useVideoRealtimeSubscription (10-32)
apps/code-with-antonio/src/app/actions/realtime.ts (1)
  • fetchRealtimeVideoToken (10-21)
apps/code-with-antonio/src/hooks/use-video-realtime.ts (2)
apps/code-with-antonio/src/app/actions/realtime.ts (1)
  • VideoRealtimeToken (8-8)
packages/core/src/inngest/video-processing/realtime.ts (1)
  • videoChannel (18-20)
packages/core/src/inngest/video-processing/functions/video-ready.ts (2)
packages/core/src/inngest/create-inngest-middleware.ts (1)
  • CoreInngestHandler (54-54)
packages/core/src/inngest/video-processing/realtime.ts (1)
  • videoChannel (18-20)
packages/core/src/inngest/video-processing/functions/video-processing-error.ts (2)
packages/core/src/inngest/create-inngest-middleware.ts (1)
  • CoreInngestHandler (54-54)
packages/core/src/inngest/video-processing/realtime.ts (1)
  • videoChannel (18-20)
apps/code-with-antonio/src/components/party.tsx (2)
apps/code-with-antonio/src/hooks/use-video-realtime.ts (1)
  • useVideoRealtimeSubscription (10-32)
apps/code-with-antonio/src/app/actions/realtime.ts (1)
  • fetchRealtimeVideoToken (10-21)
packages/core/src/inngest/video-processing/functions/transcript-ready.ts (2)
packages/core/src/inngest/create-inngest-middleware.ts (1)
  • CoreInngestHandler (54-54)
packages/core/src/inngest/video-processing/realtime.ts (1)
  • videoChannel (18-20)
packages/core/src/inngest/video-processing/functions/generate-transcript-with-screnshots.ts (2)
packages/core/src/inngest/create-inngest-middleware.ts (1)
  • CoreInngestFunctionInput (50-50)
packages/core/src/inngest/video-processing/realtime.ts (1)
  • videoChannel (18-20)
🪛 dotenv-linter (3.3.0)
apps/code-with-antonio/.env.development

[warning] 12-12: [QuoteCharacter] The value has quote characters (', ")

(QuoteCharacter)


[warning] 12-12: [UnorderedKey] The NEXT_PUBLIC_ENABLE_REALTIME_VIDEO_UPLOAD key should go before the NEXT_PUBLIC_PARTNER_FIRST_NAME key

(UnorderedKey)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (6)
  • GitHub Check: format
  • GitHub Check: typecheck
  • GitHub Check: lint
  • GitHub Check: build
  • GitHub Check: e2e-node (course-builder-web)
  • GitHub Check: Cursor Bugbot
🔇 Additional comments (11)
.changeset/config.json (1)

28-29: LGTM!

The addition of "code-with-antonio" to the ignore list is properly formatted and aligns with the PR's realtime integration work.

.changeset/purple-doors-attend.md (1)

1-7: LGTM!

The changeset properly documents the inngest realtime addition with appropriate patch-level version bumps for the affected packages.

apps/go-local-first/package.json (1)

155-155: LGTM!

The inngest version bump to 3.44.2 is consistent with the broader upgrade across the monorepo and maintains alphabetical ordering.

apps/epic-react/package.json (1)

71-71: LGTM!

The inngest version upgrade is consistent with other packages in the monorepo and maintains proper dependency ordering.

packages/core/src/inngest/create-inngest-middleware.ts (2)

88-88: LGTM! Middleware ordering is correct.

The realtime middleware is properly positioned before the custom middleware, which follows the correct initialization order for Inngest middleware composition.


3-3: Approve import of realtimeMiddleware

@inngest/realtime is listed at ^0.4.4 in packages/core/package.json; no further changes needed.

apps/epic-web/package.json (1)

143-143: LGTM!

The inngest dependency update is consistent with the monorepo-wide upgrade to 3.44.2 and maintains alphabetical ordering.

apps/epicdev-ai/package.json (1)

146-146: LGTM!

The inngest version update aligns with the monorepo-wide upgrade and maintains proper dependency ordering.

apps/code-with-antonio/src/inngest/inngest.server.ts (2)

157-157: LGTM! Middleware configuration is correct.

The realtime middleware is properly integrated alongside the existing custom middleware, enabling real-time capabilities for the Inngest client.


46-46: @inngest/realtime dependency verified: version ^0.4.4 is present in apps/code-with-antonio/package.json.

apps/code-with-antonio/src/components/party.tsx (1)

17-21: Verify calling a Server Action from a Client component is supported in your Next version

Importing and invoking a 'use server' action as refreshToken from a Client component should work on modern Next (server actions RPC). If you see bundler/runtime errors, switch to a GET /api/realtime/token route and call that instead.

Run locally and ensure no build/runtime errors are thrown from this import/call. If issues arise, I can provide an /api route version.

Comment on lines +12 to +13
NEXT_PUBLIC_ENABLE_REALTIME_VIDEO_UPLOAD="true"

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Drop quotes and add server flag for consistency

Remove quotes per dotenv best practices, and consider also setting the server flag to keep parity with core handlers.

-NEXT_PUBLIC_ENABLE_REALTIME_VIDEO_UPLOAD="true"
+NEXT_PUBLIC_ENABLE_REALTIME_VIDEO_UPLOAD=true
+# Server-side gate used by Inngest/functions
+# ENABLE_REALTIME_VIDEO_UPLOAD=true

Optional: add INNGEST_REALTIME_SIGNING_KEY placeholder here (do not commit secrets).

📝 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.

Suggested change
NEXT_PUBLIC_ENABLE_REALTIME_VIDEO_UPLOAD="true"
NEXT_PUBLIC_ENABLE_REALTIME_VIDEO_UPLOAD=true
# Server-side gate used by Inngest/functions
# ENABLE_REALTIME_VIDEO_UPLOAD=true
🧰 Tools
🪛 dotenv-linter (3.3.0)

[warning] 12-12: [QuoteCharacter] The value has quote characters (', ")

(QuoteCharacter)


[warning] 12-12: [UnorderedKey] The NEXT_PUBLIC_ENABLE_REALTIME_VIDEO_UPLOAD key should go before the NEXT_PUBLIC_PARTNER_FIRST_NAME key

(UnorderedKey)

🤖 Prompt for AI Agents
In apps/code-with-antonio/.env.development around lines 12-13, remove the
surrounding quotes from NEXT_PUBLIC_ENABLE_REALTIME_VIDEO_UPLOAD so it becomes
an unquoted boolean token per dotenv best practices, add a matching server-side
flag (e.g., NEXT_PUBLIC_ENABLE_REALTIME_VIDEO_UPLOAD_SERVER=true) on the next
line to keep parity with core handlers, and optionally add an
INNGEST_REALTIME_SIGNING_KEY=placeholder line (do not commit secrets).

Comment on lines +10 to +21
export async function fetchRealtimeVideoToken(
roomId: string,
): Promise<VideoRealtimeToken> {
if (!roomId) {
throw new Error('roomId is required to fetch realtime token')
}

return await getSubscriptionToken(inngest, {
channel: videoChannel(roomId),
topics: ['status'],
})
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Add an authorization check for room access before issuing tokens

Any client can request a token for any roomId. Validate the caller is authorized to subscribe to that room (ownership/membership). Otherwise this is a data exposure risk.

Example minimal guard (replace with your auth primitives):

 export async function fetchRealtimeVideoToken(
   roomId: string,
 ): Promise<VideoRealtimeToken> {
   if (!roomId) {
     throw new Error('roomId is required to fetch realtime token')
   }
+  // TODO: replace with your actual auth & authorization checks
+  const user = await getCurrentUser() // e.g. from your auth layer
+  const allowed = user && (await canAccessVideoRoom(user.id, roomId))
+  if (!allowed) {
+    throw new Error('unauthorized')
+  }

   return await getSubscriptionToken(inngest, {
     channel: videoChannel(roomId),
     topics: ['status'],
   })
 }

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In apps/code-with-antonio/src/app/actions/realtime.ts around lines 10 to 21, the
function issues realtime tokens for any roomId without verifying the caller; add
an authorization guard that fetches the current user/session from your auth
context, validate that the user is owner or a member of the room (e.g., DB
lookup on room membership or ownership), and if not authorized throw an
Unauthorized error or return a 403 response; only call getSubscriptionToken
after the membership check passes, and optionally log unauthorized token
requests for auditing.

Comment on lines +23 to +41
useMemo(() => {
if (!realtimeEnabled || !subscription?.latestData) return

const message = subscription.latestData
const name = message.data?.name

const invalidateOn = new Set([
'videoResource.created',
'video.asset.ready',
'transcript.ready',
'ai.tip.draft.completed',
'video.asset.detached',
'video.asset.attached',
])

if (name && invalidateOn.has(name)) {
router.refresh()
}
}, [subscription?.latestData, realtimeEnabled, router])
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Use useEffect for side effects; avoid useMemo here

router.refresh is a side effect. useMemo is not for effects and may be skipped. Use useEffect with the same deps.

- useMemo(() => {
+ useEffect(() => {
   if (!realtimeEnabled || !subscription?.latestData) return

   const message = subscription.latestData
   const name = message.data?.name

   const invalidateOn = new Set([
     'videoResource.created',
     'video.asset.ready',
     'transcript.ready',
     'ai.tip.draft.completed',
     'video.asset.detached',
     'video.asset.attached',
   ])

   if (name && invalidateOn.has(name)) {
     router.refresh()
   }
- }, [subscription?.latestData, realtimeEnabled, router])
+ }, [subscription?.latestData, realtimeEnabled, router])

Optional: hoist invalidateOn Set outside the component to avoid re‑allocations.

📝 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.

Suggested change
useMemo(() => {
if (!realtimeEnabled || !subscription?.latestData) return
const message = subscription.latestData
const name = message.data?.name
const invalidateOn = new Set([
'videoResource.created',
'video.asset.ready',
'transcript.ready',
'ai.tip.draft.completed',
'video.asset.detached',
'video.asset.attached',
])
if (name && invalidateOn.has(name)) {
router.refresh()
}
}, [subscription?.latestData, realtimeEnabled, router])
useEffect(() => {
if (!realtimeEnabled || !subscription?.latestData) return
const message = subscription.latestData
const name = message.data?.name
const invalidateOn = new Set([
'videoResource.created',
'video.asset.ready',
'transcript.ready',
'ai.tip.draft.completed',
'video.asset.detached',
'video.asset.attached',
])
if (name && invalidateOn.has(name)) {
router.refresh()
}
}, [subscription?.latestData, realtimeEnabled, router])
🤖 Prompt for AI Agents
In apps/code-with-antonio/src/components/party.tsx around lines 23 to 41,
replace the useMemo block with a useEffect so router.refresh is executed as a
side effect rather than memoized; keep the same dependency array
([subscription?.latestData, realtimeEnabled, router]), read
subscription.latestData inside the effect, perform the same early return when
realtimeEnabled is false or latestData is missing, check the message.data?.name
against the invalidateOn set and call router.refresh() when matched, and
optionally hoist the invalidateOn Set definition outside the component to avoid
re-allocations on each render.

Comment on lines +10 to +32
export function useVideoRealtimeSubscription({
room,
refreshToken,
enabled,
}: {
room?: string | null
refreshToken: RefreshTokenFn
enabled?: boolean
}) {
const finalRoom = room ?? ''
const realtimeEnabled = enabled && Boolean(finalRoom)

const subscription = useInngestSubscription({
enabled: realtimeEnabled,
refreshToken: async () => {
return refreshToken(finalRoom)
},
channel: () => videoChannel(finalRoom),
topics: ['status'],
})

return subscription
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

Add required JSDoc for exported hook

Per the project coding guidelines, every exported function in TS/TSX files must include a JSDoc block. Please document the hook’s purpose and parameters before the export so we stay compliant.

+/**
+ * Subscribes to realtime video status updates for the given room.
+ *
+ * @param room - Video room identifier used to scope the subscription.
+ * @param refreshToken - Callback that fetches a fresh realtime token for the room.
+ * @param enabled - Optional flag to toggle the subscription.
+ */
 export function useVideoRealtimeSubscription({

As per coding guidelines

📝 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.

Suggested change
export function useVideoRealtimeSubscription({
room,
refreshToken,
enabled,
}: {
room?: string | null
refreshToken: RefreshTokenFn
enabled?: boolean
}) {
const finalRoom = room ?? ''
const realtimeEnabled = enabled && Boolean(finalRoom)
const subscription = useInngestSubscription({
enabled: realtimeEnabled,
refreshToken: async () => {
return refreshToken(finalRoom)
},
channel: () => videoChannel(finalRoom),
topics: ['status'],
})
return subscription
}
/**
* Subscribes to realtime video status updates for the given room.
*
* @param room - Video room identifier used to scope the subscription.
* @param refreshToken - Callback that fetches a fresh realtime token for the room.
* @param enabled - Optional flag to toggle the subscription.
*/
export function useVideoRealtimeSubscription({
room,
refreshToken,
enabled,
}: {
room?: string | null
refreshToken: RefreshTokenFn
enabled?: boolean
}) {
const finalRoom = room ?? ''
const realtimeEnabled = enabled && Boolean(finalRoom)
const subscription = useInngestSubscription({
enabled: realtimeEnabled,
refreshToken: async () => {
return refreshToken(finalRoom)
},
channel: () => videoChannel(finalRoom),
topics: ['status'],
})
return subscription
}
🤖 Prompt for AI Agents
In apps/code-with-antonio/src/hooks/use-video-realtime.ts around lines 10 to 32,
the exported hook is missing the required JSDoc block; add a JSDoc comment
immediately above the export that briefly describes the hook’s purpose,
documents each parameter (room, refreshToken, enabled) including types/behavior
(room can be string|null, refreshToken is a RefreshTokenFn used to fetch a token
for the finalRoom, enabled toggles realtime subscription), and documents the
return value (the subscription object from useInngestSubscription). Keep the
JSDoc concise and follow project style (description line, @param for each param,
and @returns).

Comment on lines 19 to +30
export const generateTranscriptWithScreenshotsHandler: CoreInngestHandler =
async ({ event, step, db, partyProvider }: CoreInngestFunctionInput) => {
async ({
event,
step,
db,
partyProvider,
publish,
}: CoreInngestFunctionInput) => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

Add JSDoc comment to the handler function.

As per coding guidelines, functions should have JSDoc comments.

Apply this diff:

+/**
+ * Generates a transcript with screenshots by merging SRT data with Mux
+ * playback screenshots and announces completion via realtime or broadcast.
+ * 
+ * @param event - SRT ready event data
+ * @param step - Inngest step utilities
+ * @param db - Database adapter
+ * @param partyProvider - Party broadcast provider
+ * @param publish - Optional realtime publish function
+ * @returns Transcript with screenshots data
+ */
 export const generateTranscriptWithScreenshotsHandler: CoreInngestHandler =
 	async ({
🤖 Prompt for AI Agents
In
packages/core/src/inngest/video-processing/functions/generate-transcript-with-screnshots.ts
around lines 23 to 30, the exported handler lacks a JSDoc comment; add a JSDoc
block immediately above the export that briefly describes the purpose of
generateTranscriptWithScreenshotsHandler, its parameters (event, step, db,
partyProvider, publish) with types/expected shapes, and the return value/promise
behavior, following the project's JSDoc style conventions.

Comment on lines +17 to +19
const realtimeEnabled =
process.env.NEXT_PUBLIC_ENABLE_REALTIME_VIDEO_UPLOAD === 'true'

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Use a server-side env flag (not NEXT_PUBLIC_) in server/Inngest code

Relying on NEXT_PUBLIC_* in server functions is brittle; those are intended for client build-time exposure. Switch to ENABLE_REALTIME_VIDEO_UPLOAD (or similar server-only flag) to gate publishing. Matches the migration plan.

-const realtimeEnabled =
-	process.env.NEXT_PUBLIC_ENABLE_REALTIME_VIDEO_UPLOAD === 'true'
+const realtimeEnabled =
+	process.env.ENABLE_REALTIME_VIDEO_UPLOAD === 'true'

Also ensure the flag is set in the Inngest environment. Based on learnings.

📝 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.

Suggested change
const realtimeEnabled =
process.env.NEXT_PUBLIC_ENABLE_REALTIME_VIDEO_UPLOAD === 'true'
const realtimeEnabled =
process.env.ENABLE_REALTIME_VIDEO_UPLOAD === 'true'
🤖 Prompt for AI Agents
In packages/core/src/inngest/video-processing/functions/video-ready.ts around
lines 17 to 19, the code currently reads
NEXT_PUBLIC_ENABLE_REALTIME_VIDEO_UPLOAD which is a client-facing build-time
env; change this to a server-only flag (e.g. ENABLE_REALTIME_VIDEO_UPLOAD) and
update the check to process.env.ENABLE_REALTIME_VIDEO_UPLOAD === 'true' so the
server/Inngest function uses a server-only env var, and ensure this new
ENABLE_REALTIME_VIDEO_UPLOAD flag is added to the Inngest deployment/environment
variables.

Comment on lines 22 to 28
const videoUploadedHandler: CoreInngestHandler = async ({
event,
step,
db,
partyProvider,
publish,
}: CoreInngestFunctionInput) => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

Add JSDoc comment to the handler function.

As per coding guidelines, functions should have JSDoc comments describing their purpose, parameters, and return value.

Apply this diff to add a JSDoc comment:

+/**
+ * Handles video upload events by creating Mux assets, video resources,
+ * and announcing the creation via realtime or broadcast channels.
+ * 
+ * @param event - Video upload event data
+ * @param step - Inngest step utilities
+ * @param db - Database adapter
+ * @param partyProvider - Party broadcast provider
+ * @param publish - Optional realtime publish function
+ * @returns Upload result with video resource and Mux asset details
+ */
 const videoUploadedHandler: CoreInngestHandler = async ({
📝 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.

Suggested change
const videoUploadedHandler: CoreInngestHandler = async ({
event,
step,
db,
partyProvider,
publish,
}: CoreInngestFunctionInput) => {
/**
* Handles video upload events by creating Mux assets, video resources,
* and announcing the creation via realtime or broadcast channels.
*
* @param event - Video upload event data
* @param step - Inngest step utilities
* @param db - Database adapter
* @param partyProvider - Party broadcast provider
* @param publish - Optional realtime publish function
* @returns Upload result with video resource and Mux asset details
*/
const videoUploadedHandler: CoreInngestHandler = async ({
event,
step,
db,
partyProvider,
publish,
}: CoreInngestFunctionInput) => {
🤖 Prompt for AI Agents
In packages/core/src/inngest/video-processing/functions/video-uploaded.ts around
lines 22 to 28, the handler function lacks a JSDoc comment; add a JSDoc block
immediately above the const videoUploadedHandler declaration describing the
function’s purpose, documenting its parameters (event, step, db, partyProvider,
publish) with types/expected shapes and any important behavior, and specifying
the return type (Promise and what it resolves to or void). Keep the comment
concise, use standard JSDoc tags (@param, @returns, and optionally @throws), and
ensure wording follows project style guidelines.

Comment on lines 104 to 125
await step.run('announce video resource created', async () => {
return await partyProvider.broadcastMessage({
body: {
body: videoResource,
requestId: videoResource.id,
name: 'videoResource.created',
},
roomId: videoResource.id,
})
if (realtimeEnabled && publish) {
await publish(
videoChannel(videoResource.id).status({
name: 'videoResource.created',
body: videoResource,
requestId: videoResource.id,
}),
)
}

if (!realtimeEnabled || !publish) {
await partyProvider.broadcastMessage({
body: {
body: videoResource,
requestId: videoResource.id,
name: 'videoResource.created',
},
roomId: videoResource.id,
})
}
})
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

Eliminate payload duplication and clarify conditional logic.

The payload structure is duplicated between the realtime path (lines 107-111) and fallback path (lines 117-121). Additionally, the complementary conditionals would be clearer as a simple if-else.

Apply this diff to construct the payload once and use clearer conditional logic:

 		await step.run('announce video resource created', async () => {
-			if (realtimeEnabled && publish) {
-				await publish(
-					videoChannel(videoResource.id).status({
-						name: 'videoResource.created',
-						body: videoResource,
-						requestId: videoResource.id,
-					}),
-				)
-			}
-
-			if (!realtimeEnabled || !publish) {
-				await partyProvider.broadcastMessage({
-					body: {
-						body: videoResource,
-						requestId: videoResource.id,
-						name: 'videoResource.created',
-					},
-					roomId: videoResource.id,
-				})
-			}
+			const payload = {
+				name: 'videoResource.created' as const,
+				body: videoResource,
+				requestId: videoResource.id,
+			}
+
+			if (realtimeEnabled && publish) {
+				await publish(videoChannel(videoResource.id).status(payload))
+			} else {
+				await partyProvider.broadcastMessage({
+					body: payload,
+					roomId: videoResource.id,
+				})
+			}
 		})
📝 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.

Suggested change
await step.run('announce video resource created', async () => {
return await partyProvider.broadcastMessage({
body: {
body: videoResource,
requestId: videoResource.id,
name: 'videoResource.created',
},
roomId: videoResource.id,
})
if (realtimeEnabled && publish) {
await publish(
videoChannel(videoResource.id).status({
name: 'videoResource.created',
body: videoResource,
requestId: videoResource.id,
}),
)
}
if (!realtimeEnabled || !publish) {
await partyProvider.broadcastMessage({
body: {
body: videoResource,
requestId: videoResource.id,
name: 'videoResource.created',
},
roomId: videoResource.id,
})
}
})
await step.run('announce video resource created', async () => {
const payload = {
name: 'videoResource.created' as const,
body: videoResource,
requestId: videoResource.id,
}
if (realtimeEnabled && publish) {
await publish(videoChannel(videoResource.id).status(payload))
} else {
await partyProvider.broadcastMessage({
body: payload,
roomId: videoResource.id,
})
}
})

Comment on lines +4 to +20
const statusPayloadSchema = z.object({
name: z.enum([
'videoResource.created',
'video.asset.ready',
'video.asset.errored',
'transcript.ready',
'transcriptWithScreenshots.ready',
]),
body: z.any(),
requestId: z.string(),
})

export type VideoStatusPayload = z.infer<typeof statusPayloadSchema>

export const videoChannel = channel(
(videoId: string) => `video:${videoId}`,
).addTopic(topic('status').schema(statusPayloadSchema))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Include all emitted event names in the status schema

Clients (e.g., content-video-resource-field.tsx, Lines 184-213) handle video.asset.attached and video.asset.detached, but the schema forbids them, so any publish with those names will throw a Zod validation error. Please extend the enum to cover every emitted status event before shipping.

 	const statusPayloadSchema = z.object({
 		name: z.enum([
 			'videoResource.created',
 			'video.asset.ready',
 			'video.asset.errored',
+			'video.asset.attached',
+			'video.asset.detached',
 			'transcript.ready',
 			'transcriptWithScreenshots.ready',
 		]),
📝 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.

Suggested change
const statusPayloadSchema = z.object({
name: z.enum([
'videoResource.created',
'video.asset.ready',
'video.asset.errored',
'transcript.ready',
'transcriptWithScreenshots.ready',
]),
body: z.any(),
requestId: z.string(),
})
export type VideoStatusPayload = z.infer<typeof statusPayloadSchema>
export const videoChannel = channel(
(videoId: string) => `video:${videoId}`,
).addTopic(topic('status').schema(statusPayloadSchema))
const statusPayloadSchema = z.object({
name: z.enum([
'videoResource.created',
'video.asset.ready',
'video.asset.errored',
'video.asset.attached',
'video.asset.detached',
'transcript.ready',
'transcriptWithScreenshots.ready',
]),
body: z.any(),
requestId: z.string(),
})
🤖 Prompt for AI Agents
In packages/core/src/inngest/video-processing/realtime.ts around lines 4 to 20,
the statusPayloadSchema enum is missing event names that are emitted elsewhere
(specifically video.asset.attached and video.asset.detached), causing Zod
validation failures; update the enum to include those two event names so the
schema covers every emitted status event, then run tests or a quick publish flow
to confirm no validation errors occur when those events are published.

Comment on lines +37 to +48
### greenfield spike: `apps/code-with-antonio`
1. **bootstrap realtime provider**
- files: `packages/core/providers/realtime.ts`, `packages/core/providers/broadcast.ts`
- create `RealtimeProvider` matching `PartyProviderConfig` interface (`publish({channel,topic,data})`)
- add `multiCastBroadcast({ message, providers })` helper that forwards to both realtime + legacy
2. **wire middleware in greenfield app**
- update `apps/code-with-antonio/src/inngest/inngest.server.ts`
- import `RealtimeProvider` + `LegacyPartyProvider`
- instantiate inngest client with `@inngest/realtime/middleware`
- pass `{ realtimeProvider, partyProvider }` into `createInngestMiddleware`
- gate realtime config behind `process.env.ENABLE_REALTIME_VIDEO_UPLOAD === 'true'`
3. **adapt video pipeline handlers**
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

🧩 Analysis chain

Standardize env flag names: server vs client

The plan uses ENABLE_REALTIME_VIDEO_UPLOAD (server), while code uses NEXT_PUBLIC_ENABLE_REALTIME_VIDEO_UPLOAD in handlers and .env. Align to:

  • Server (Inngest/functions): ENABLE_REALTIME_VIDEO_UPLOAD
  • Client/UI gating: NEXT_PUBLIC_ENABLE_REALTIME_VIDEO_UPLOAD

This avoids server code depending on a client‑scoped variable and matches the plan’s “gate realtime config behind process.env.ENABLE_REALTIME_VIDEO_UPLOAD === 'true'”.

To find mismatches, run:


🏁 Script executed:

#!/bin/bash
rg -n "ENABLE_REALTIME_VIDEO_UPLOAD|NEXT_PUBLIC_ENABLE_REALTIME_VIDEO_UPLOAD" -g '!*dist*' -g '!*build*'

Length of output: 1548


Standardize environment flags for server vs client
Server-side (Inngest) functions should use process.env.ENABLE_REALTIME_VIDEO_UPLOAD (non-public); update all occurrences in packages/core/src/inngest/... accordingly. Retain NEXT_PUBLIC_ENABLE_REALTIME_VIDEO_UPLOAD only in client/UI code.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants