Migration Guide: 0.19 to 0.20+

Version 0.20 reorganizes Svelte components into their domain packages and consolidates browser-ai into smrt-svelte. This guide covers all breaking changes through 0.20.44.

Component Import Changes

Domain-specific components have moved from @happyvertical/smrt-svelte to their respective package's /svelte subpath. Core UI components (forms, layout, feedback, themes) remain in smrt-svelte.

Users

typescript
// Before
import { UserCard, UserAvatar, UserList } from '@happyvertical/smrt-svelte';

// After
import { UserCard, UserAvatar, UserList } from '@happyvertical/smrt-users/svelte';

Commerce

typescript
// Before
import { InvoiceCard, InvoiceLineItems } from '@happyvertical/smrt-svelte';

// After
import { InvoiceCard, InvoiceLineItems } from '@happyvertical/smrt-commerce/svelte';

Tenancy

typescript
// Before
import { TenantSwitcher, TenantCard } from '@happyvertical/smrt-svelte';

// After
import { TenantSwitcher, TenantCard } from '@happyvertical/smrt-tenancy/svelte';

Jobs

typescript
// Before
import { JobDashboard, JobList } from '@happyvertical/smrt-svelte';

// After
import { JobDashboard, JobList } from '@happyvertical/smrt-jobs/svelte';

Agents

typescript
// Before
import { AgentDashboard, AgentRunHistory } from '@happyvertical/smrt-svelte';

// After
import { AgentDashboard, AgentRunHistory } from '@happyvertical/smrt-agents/svelte';

Content

typescript
// Before
import { ArticleCard, ArticleList } from '@happyvertical/smrt-svelte';

// After
import { ArticleCard, ArticleList } from '@happyvertical/smrt-content/svelte';

Events

typescript
// Before
import { MeetingView } from '@happyvertical/smrt-svelte';

// After
import { MeetingView } from '@happyvertical/smrt-events/svelte';

Projects

typescript
// Before
import { TimeEntryCard, ApprovalActions } from '@happyvertical/smrt-svelte';

// After
import { TimeEntryCard, ApprovalActions } from '@happyvertical/smrt-projects/svelte';

What stays in smrt-svelte

These categories remain in @happyvertical/smrt-svelte:

  • Forms (TextInput, Select, DateTime, etc.)
  • Layout (PageHeader, Grid, EmptyState, etc.)
  • Feedback (Modal, ConfirmDialog, ProgressBar)
  • Navigation (Tabs, FilterChips)
  • Display (StatusBadge, CurrencyDisplay, DateDisplay)
  • Themes (ThemeSwitcher, ColorSchemeToggle)
  • AI components (VoiceInput, DownloadProgress, AILoadingOverlay)
  • Hooks (useSTT, useTTS, useLLM, useAuth, useSocket)
  • Provider, permissions, roles, memberships

browser-ai Consolidated

The standalone @happyvertical/browser-ai package has been merged into @happyvertical/smrt-svelte. Remove the browser-ai dependency and update imports:

typescript
// Before
import { BrowserAI } from '@happyvertical/browser-ai';
import type { STTAdapter, TTSAdapter } from '@happyvertical/browser-ai';

// After — use hooks instead
import { useSTT, useTTS, useLLM } from '@happyvertical/smrt-svelte';

TenantSwitcher API Change

The TenantSwitcher component now accepts a Map of tenants and a separate memberships array, and uses onchange instead of onswitch:

svelte
// Before
<TenantSwitcher
  tenants={tenantsArray}
  currentTenantId={id}
  onswitch={handleSwitch}
/>

// After
<TenantSwitcher
  tenants={tenantsMap}
  memberships={memberships}
  currentTenantId={id}
  onchange={handleSwitch}
/>

MembershipCard / MembershipList API Change

These components now accept separate tenant and role props instead of embedding them in the membership object:

svelte
// Before
<MembershipCard membership={membershipWithEverything} />

// After
<MembershipCard {membership} {tenant} {role} />

// MembershipList uses MembershipWithContext objects
<MembershipList memberships={[
  { membership, tenant, role },
  ...
]} />

PermissionCheck API Change

PermissionCheck now requires an explicit userPermissions array and uses a Snippet for fallback content:

svelte
// Before
<PermissionCheck permission="users.edit" fallback="No access">
  <button>Edit</button>
</PermissionCheck>

// After
<PermissionCheck permission="users.edit" userPermissions={currentPermissions}>
  {#snippet fallback()}<span>No access</span>{/snippet}
  <button>Edit</button>
</PermissionCheck>

Profiles: Tenancy Peer Dependency

@happyvertical/smrt-profiles now lists @happyvertical/smrt-tenancy as a peer dependency. Install it if you use multi-tenant features:

bash
pnpm add @happyvertical/smrt-tenancy

CSS Custom Properties

All theme tokens now use the --smrt-color-* prefix following Material Design 3 naming. If you were using older token names, update to the new prefix:

css
/* New token format */
--smrt-color-primary
--smrt-color-on-primary
--smrt-color-primary-container
--smrt-color-surface
--smrt-color-surface-variant
--smrt-color-outline

Post-0.20.0 Changes (through 0.20.44)

CLI Migration Commands

Migration commands have been updated. The old smrt migrations generate syntax is replaced:

bash
# Generate migration from schema changes
smrt db:diff --generate

# Check pending schema changes
smrt db:status

# Apply migrations
smrt db:migrate

# Rollback migrations
smrt db:rollback

Config Shape

The smrt.config.ts top-level keys have been reorganized. Replace old database/api/cli/mcp keys with the new structure:

typescript
import { defineConfig } from '@happyvertical/smrt-config';

// Before (old shape - no longer valid)
export default defineConfig({
  database: { type: 'postgresql', host: '...' },
  api: { enabled: true, port: 3000 },
  cli: { enabled: true },
  mcp: { enabled: true, port: 3100 }
});

// After (current shape)
export default defineConfig({
  smrt: {
    logLevel: 'info',
    environment: 'production',
    embeddings: { provider: 'local' }
  },
  modules: {
    'my-agent': { cronSchedule: '0 2 * * *' }
  },
  packages: {
    ai: { defaultModel: 'gpt-4o' }
  }
});

Agent Signal Handling

Agents now automatically register SIGTERM/SIGINT handlers during initialize() for graceful shutdown. If you had custom signal handling, it is now built-in. Always call super.shutdown() to clean up signal handlers.

Relationship Decorators

Relationship fields (foreignKey, oneToMany, manyToMany) are now decorators, not plain assignment helpers:

typescript
// Before (plain assignment - no longer valid)
class Order extends SmrtObject {
  customerId = foreignKey(Customer);
  items = oneToMany(OrderItem);
}

// After (decorators)
class Order extends SmrtObject {
  @foreignKey(Customer)
  customerId: string = '';

  @oneToMany(OrderItem)
  items: OrderItem[] = [];
}

Collection _itemClass

The _itemClass static property must now be readonly:

typescript
// Before
class MyCollection extends SmrtCollection<MyObject> {
  static itemClass = MyObject;
}

// After
class MyCollection extends SmrtCollection<MyObject> {
  static readonly _itemClass = MyObject;
}