Skip to content
Open
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
12 changes: 12 additions & 0 deletions next.config.mjs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
/** @type {import('next').NextConfig} */
const enableMini = process.env.ENABLE_MINI === 'true'

const nextConfig = {
// Source maps for debugging production crashes
productionBrowserSourceMaps: true,
Expand Down Expand Up @@ -27,6 +29,16 @@ const nextConfig = {
test: /\.po$/,
use: ['@lingui/loader'],
})

// When ENABLE_MINI is not set, replace Mini modules with empty stubs
// so zero Mini code (including PubNub SDK) is bundled.
if (!enableMini) {
config.resolve.alias = {
...config.resolve.alias,
pubnub: false,
}
}
Comment on lines +33 to +40
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🌐 Web query:

In Next.js 16.1.6, does next devuse Turbopack by default, and should a package alias configured inwebpack.resolve.aliasalso be duplicated inturbopack.resolveAlias to keep module resolution behavior consistent?

💡 Result:

In Next.js 16.1.6, next dev uses Turbopack by default. Yes, a package alias configured in webpack.resolve.alias should be duplicated in turbopack.resolveAlias to keep module resolution behavior consistent, as Turbopack does not automatically use webpack aliases and has its own resolveAlias configuration in next.config.js under the top-level turbopack key (moved from experimental in Next.js 16). Multiple GitHub discussions and issues confirm users need to explicitly configure resolveAlias for Turbopack to match webpack behavior, especially for custom aliases, symlinks, or fallbacks.

Citations:


Add the pubnub: false alias to turbopack.resolveAlias as well.

The pubnub: false alias is set in the webpack config but missing from turbopack.resolveAlias. Since Next.js 16.1.6 uses Turbopack by default, the Mini-off behavior won't work consistently—Turbopack doesn't inherit webpack aliases and requires the alias to be explicitly configured in its own resolveAlias block to match webpack behavior.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@next.config.mjs` around lines 33 - 40, When enableMini is false, you
currently set config.resolve.alias.pubnub = false for webpack but forgot to
mirror this for Turbopack; add the same alias to
config.experimental?.turbopack?.resolveAlias (or config.turbopack.resolveAlias
if that structure is used) so turbopack.resolveAlias includes pubnub: false
alongside config.resolve.alias; update the conditional that checks enableMini
(the block around config.resolve.alias) to also set turbopack.resolveAlias to
ensure Mini-off behavior is consistent across both bundlers.


return config
},
reactCompiler: false,
Expand Down
3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,9 @@
"zod": "^4.3.6",
"zod-openapi": "^5.4.6"
},
"optionalDependencies": {
"pubnub": "^10.2.9"
},
Comment on lines +72 to +74
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Update pnpm-lock.yaml with the new optional dependency.

CI is already red on pnpm install --frozen-lockfile because the lockfile still has optionalDependencies: {}. Regenerate and commit the lockfile before merging.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@package.json` around lines 72 - 74, package.json now adds an optional
dependency "pubnub" but the pnpm lockfile wasn't updated; run pnpm install (or
pnpm install --lockfile-only) to regenerate pnpm-lock.yaml so it includes the
new optionalDependencies entry, verify the lockfile reflects "pubnub" under
optionalDependencies, and commit the updated pnpm-lock.yaml alongside the
package.json change before merging.

"devDependencies": {
"@babel/preset-typescript": "^7.28.5",
"@eslint/css": "^1.0.0",
Expand Down
1,736 changes: 1,488 additions & 248 deletions pnpm-lock.yaml

Large diffs are not rendered by default.

8 changes: 8 additions & 0 deletions src/server/routers/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,13 @@ import { waterLevelRouter } from './waterLevel'
import { runOnceRouter } from './runOnce'
import { scheduleGroupsRouter } from './scheduleGroups'

// Mini router — conditional dynamic import, only loaded when ENABLE_MINI=true.
// When disabled: no Mini code is bundled (webpack resolve alias → false),
// no PubNub SDK loaded, no Mini routes registered.
const miniRouter = process.env.ENABLE_MINI === 'true'
? (await import('./mini')).miniRouter
: null
Comment on lines +16 to +21
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# Find build config files
git ls-files | grep -E '(next\.config|webpack|tsconfig|\.env)' | head -20

Repository: sleepypod/core

Length of output: 106


🏁 Script executed:

# Search for ENABLE_MINI references in the codebase
rg 'ENABLE_MINI' --type ts --type js --type json -n

Repository: sleepypod/core

Length of output: 249


🏁 Script executed:

# Check the structure of src/server/routers/
ls -la src/server/routers/ 2>/dev/null || echo "Directory not found"

Repository: sleepypod/core

Length of output: 1152


🏁 Script executed:

# Look for the mini module
fd -type f -path '*mini*' | grep -E '\.(ts|js|tsx|jsx)$' | head -20

Repository: sleepypod/core

Length of output: 228


🏁 Script executed:

# Check next.config.mjs for any aliases or configuration
cat next.config.mjs 2>/dev/null | head -100

Repository: sleepypod/core

Length of output: 1454


🏁 Script executed:

# Read the mini.ts file to see what it contains
cat -n src/server/routers/mini.ts

Repository: sleepypod/core

Length of output: 509


🏁 Script executed:

# Check if there are any other references to the mini router or ENABLE_MINI in app.ts
cat -n src/server/routers/app.ts

Repository: sleepypod/core

Length of output: 2248


🏁 Script executed:

# Search for any build-time webpack plugin or setup for env variable handling
rg 'DefinePlugin|process.env' next.config.mjs webpack.config

Repository: sleepypod/core

Length of output: 199


🏁 Script executed:

# Check if mini.ts has any dependencies on pubnub
rg -A 5 -B 5 'pubnub|pubsub' src/server/routers/mini.ts src/server/trpc.ts 2>/dev/null || echo "No pubnub refs found in mini or trpc"

Repository: sleepypod/core

Length of output: 94


🏁 Script executed:

# Search for any build-time env defines or extra webpack config
rg 'DefinePlugin|ENABLE_MINI' . --type js --type mjs -A 3 -B 3 2>/dev/null | head -50

Repository: sleepypod/core

Length of output: 40


🏁 Script executed:

# Check if there's any documentation about the build exclusion objective
cat README.md 2>/dev/null | grep -i -A 5 -B 5 'mini\|enable_mini\|bundle' | head -40

Repository: sleepypod/core

Length of output: 827


The static import statement creates a dependency edge without explicit build-time exclusion.

The code conditionally imports ./mini at runtime, but relies on Next.js dead-code elimination to remove it from the bundle when ENABLE_MINI=false. However, only pubnub is explicitly aliased to false in webpack config—there is no matching alias for ./mini itself. If build-time exclusion is a release requirement, either:

  1. Add a build-time alias for ./mini (like pubnub) to guarantee it's excluded, or
  2. Verify that the standalone output with ENABLE_MINI=false actually contains no mini code

The inline comment claiming "webpack resolve alias → false" is misleading since the alias only applies to pubnub, not to the mini module itself.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/server/routers/app.ts` around lines 16 - 21, The current conditional
top-level import of './mini' (miniRouter) still creates a static dependency edge
and the inline comment incorrectly implies webpack aliasing removes the module;
either add a build-time alias for './mini' → false in the webpack/next config
(matching how pubnub is aliased) so the module is guaranteed excluded when
ENABLE_MINI='false', or move the import into the runtime branch so you only call
await import('./mini') when process.env.ENABLE_MINI==='true' (ensuring no static
edge), and update the comment to accurately reflect which modules are
aliased/excluded; refer to miniRouter, './mini', ENABLE_MINI and the existing
pubnub alias when making the change.


export const appRouter = router({
healthcheck: publicProcedure
.meta({ openapi: { method: 'GET', path: '/healthcheck', protect: false, tags: ['Health'] } })
Expand All @@ -35,6 +42,7 @@ export const appRouter = router({
waterLevel: waterLevelRouter,
runOnce: runOnceRouter,
scheduleGroups: scheduleGroupsRouter,
...(miniRouter ? { mini: miniRouter } : {}),
})

export type AppRouter = typeof appRouter
12 changes: 12 additions & 0 deletions src/server/routers/mini.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { z } from 'zod'
import { publicProcedure, router } from '@/src/server/trpc'

export const miniRouter = router({
status: publicProcedure
.meta({ openapi: { method: 'GET', path: '/mini/status', protect: false, tags: ['Mini'] } })
.input(z.object({}))
.output(z.object({
enabled: z.boolean(),
}))
.query(() => ({ enabled: true })),
})
11 changes: 11 additions & 0 deletions src/services/mini/client.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/**
* Snoo client — Auth (OAuth PKCE) and data API.
* Stub: implementation comes in the TS Snoo client step.
*/

export class SnooClient {
// OAuth PKCE auth flow to Happiest Baby
async authenticate(): Promise<void> {
throw new Error('Not implemented — awaiting TS Snoo client step')
}
}
3 changes: 3 additions & 0 deletions src/services/mini/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export { SnooClient } from './client'
export { MiniPubNubManager } from './pubnub'
export type { MiniSession, MiniStatus, MiniSettings, MiniLevel, MiniCommand } from './types'
14 changes: 14 additions & 0 deletions src/services/mini/pubnub.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/**
* PubNub subscription manager for real-time Snoo state and commands.
* Stub: implementation comes in the TS Snoo client step.
*/

export class MiniPubNubManager {
async connect(): Promise<void> {
throw new Error('Not implemented — awaiting TS Snoo client step')
}

async disconnect(): Promise<void> {
// no-op until implemented
}
}
29 changes: 29 additions & 0 deletions src/services/mini/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/**
* TypeScript types matching the Snoo data model.
* Populated in the TS Snoo client implementation step.
*/

export interface MiniSession {
sessionId: string
startTime: string
endTime?: string
levels: MiniLevel[]
}

export interface MiniStatus {
isOnline: boolean
babyName?: string
firmwareVersion?: string
lastSSID?: string
}

export interface MiniSettings {
responsiveness: 'low' | 'normal' | 'high'
volume: number
weaning: boolean
motionLimiter: boolean
}

export type MiniLevel = 'baseline' | 'level1' | 'level2' | 'level3' | 'level4'

export type MiniCommand = 'start' | 'stop' | 'level_up' | 'level_down' | 'toggle'
Loading