Skip to content

feat: ENABLE_MINI feature flag + conditional build (#409)#420

Open
ng wants to merge 3 commits intodevfrom
feat/mini-feature-flag
Open

feat: ENABLE_MINI feature flag + conditional build (#409)#420
ng wants to merge 3 commits intodevfrom
feat/mini-feature-flag

Conversation

@ng
Copy link
Copy Markdown
Contributor

@ng ng commented Apr 11, 2026

Summary

  • Wire up ENABLE_MINI env var for the Sleepypod Mini module
  • When unset (default): zero Mini code bundled — webpack resolve alias nulls out pubnub, tRPC Mini router not imported
  • When ENABLE_MINI=true: Mini router dynamically imported and merged into app router
  • Add PubNub SDK as optional dependency (pubnub@10.x)
  • Create stub Mini service files (src/services/mini/) and router (src/server/routers/mini.ts)

Closes #409

Changes since #410

  • Moved pubnub to optionalDependencies per review feedback
  • Used MiniLevel[] instead of string[] for type safety

Test plan

  • pnpm tsc passes
  • pnpm build with ENABLE_MINI unset succeeds
  • ENABLE_MINI=true pnpm build succeeds — Mini routes available

Summary by CodeRabbit

  • New Features

    • Introduced foundational infrastructure for a new "Mini" feature that can be enabled or disabled via environment configuration.
    • Added a new /mini/status API endpoint to check feature availability.
  • Chores

    • Made PubNub an optional dependency.
    • Configured conditional code bundling based on feature flags to reduce bundle size when Mini is disabled.

ng and others added 3 commits April 11, 2026 16:26
Wire up ENABLE_MINI env var for the Sleepypod Mini module. When unset
(default), zero Mini code is bundled: webpack resolve alias nulls out
pubnub, and the tRPC Mini router is not imported. When ENABLE_MINI=true,
the Mini router is dynamically imported and merged into the app router.

Adds PubNub SDK dependency and stub Mini service/router files that will
be implemented in the TS Snoo client step.

Closes #409

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Move pubnub to optionalDependencies and use MiniLevel[] for type safety
@ng ng enabled auto-merge (squash) April 11, 2026 23:28
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Apr 11, 2026

📝 Walkthrough

Walkthrough

Implements a build-time feature flag system for Mini functionality using ENABLE_MINI environment variable. Changes include webpack configuration to conditionally alias PubNub, marking PubNub as optional dependency, conditionally loading Mini routes and services via dynamic imports, and creating stub implementations for Mini client and PubNub manager classes with type definitions.

Changes

Cohort / File(s) Summary
Build & Dependencies
next.config.mjs, package.json
Adds webpack configuration to set pubnub alias to false when ENABLE_MINI is disabled, preventing bundling. Marks PubNub as optionalDependencies instead of required.
Server Router Integration
src/server/routers/app.ts, src/server/routers/mini.ts
Conditionally loads Mini router via dynamic import only when ENABLE_MINI === 'true'. New Mini router exports a status procedure returning { enabled: true } with OpenAPI metadata.
Mini Services
src/services/mini/client.ts, src/services/mini/pubnub.ts, src/services/mini/types.ts, src/services/mini/index.ts
Introduces SnooClient and MiniPubNubManager stub classes with placeholder error messages. Defines TypeScript types for MiniSession, MiniStatus, MiniSettings, MiniLevel, and MiniCommand. Barrel module re-exports all Mini exports.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 A feature flag hops into the fold,
Mini code now dances at your command,
Webpack whispers "pubnub, begone!" when the flag stays cold,
Conditional loads and stubs take their stand,
Bundling shrinks, the pod runs lean and bold!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed Title accurately reflects the main change: introduces ENABLE_MINI feature flag and conditional build system for Mini module.
Linked Issues check ✅ Passed Pull request implements all coding requirements from #409: conditional webpack alias for pubnub, dynamic import of Mini router, optional dependency setup, and stub Mini service files.
Out of Scope Changes check ✅ Passed All changes directly support the ENABLE_MINI feature flag objective. Minor note: CI workflow matrix build not visible in provided code changes, but implementation aligns with stated scope.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/mini-feature-flag
⚔️ Resolve merge conflicts
  • Resolve merge conflict in branch feat/mini-feature-flag

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.

Copy link
Copy Markdown

@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: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@next.config.mjs`:
- Around line 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.

In `@package.json`:
- Around line 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.

In `@src/server/routers/app.ts`:
- Around line 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.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: e79e4e57-ef3b-46f2-a4a8-c603999f9f2c

📥 Commits

Reviewing files that changed from the base of the PR and between 5614552 and 508ff76.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (8)
  • next.config.mjs
  • package.json
  • src/server/routers/app.ts
  • src/server/routers/mini.ts
  • src/services/mini/client.ts
  • src/services/mini/index.ts
  • src/services/mini/pubnub.ts
  • src/services/mini/types.ts

Comment thread next.config.mjs
Comment on lines +33 to +40
// 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,
}
}
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.

Comment thread package.json
Comment on lines +72 to +74
"optionalDependencies": {
"pubnub": "^10.2.9"
},
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.

Comment thread src/server/routers/app.ts
Comment on lines +16 to +21
// 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
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.

@ng ng mentioned this pull request Apr 13, 2026
4 tasks
ng added a commit that referenced this pull request Apr 13, 2026
## Summary

Promotes everything on \`dev\` since the last main release (82 commits,
143 files, +9239/-2699).

### Headlining features
- **Schedule redesign (#303)** — read-only schedule view with explicit
curve management, full-screen \`CurveEditor\` (day picker + bedtime/wake
+ temp range + presets), \`Left | Right | Both\` side selector,
active-curve highlight, atomic \`batchUpdate\` writes, day-conflict
resolution, sparkline cards.
- **Mini feature flag (#420)** — \`ENABLE_MINI\` env var; PubNub moved
to \`optionalDependencies\`; conditional Mini router import.
- **Auto-off on no presence (#301)** — schedule respects bed presence.
- **Auto-unblock internet during update check (#308)**.
- **Schedule batchUpdate cap raised to 1000 (#424)** — fixes AI-curve
apply-to-all-days rejection.

### Operational fixes
- Pod 3 install path (#383, #384, #386, #392)
- Yocto image Python venv (#336)
- DAC socket / Avahi on device startup (#331)
- Free-sleep/sleepypod switch persistence (#337)
- Cross-machine standalone deploys (#308)
- Temperature unit conversion (#333)

### Dependency updates
~20 renovate PRs across React 19.2.5, Next 16.2.3, vitest 4.1.4,
tanstack/react-query 5.97.0, tRPC 11.16, lucide-react 1.x, etc.

### Misc
- ADR 0017 (uv) compiled into deployment wiki
- Snoo pentest methodology + recon plan
- Git hooks + ESLint cleanup (#313)
- CI hardening (#388)

## Test plan
- [x] All unit tests pass on dev (606+ tests)
- [x] Typecheck clean
- [x] Build succeeds (standalone output)
- [x] Deployed to Pod 4 at \`192.168.1.88\` and smoke-tested:
  - schedule on/off
  - create curve from preset
  - edit curve, change days, save
  - day-conflict reassign dialog
  - delete curve
  - side selector left/right/both
  - active-curve highlighting + next set point
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.

chore: feature flag build system for Mini

1 participant