Skip to content

Migrating from applesauce v4 to v5 ​

This guide explains how to migrate an existing applesauce v4 project to v5, with a focus on import changes and the applesauce-common package. It is written for both humans and AI agents (LLMs, code‑mod tools) and favors mechanical “if you see X, replace with Y” style rules.

1. Goals and scope ​

  • What this covers:
    • Moving helpers, models, blueprints, and operations that were previously imported from applesauce-core (and applesauce-factory) to their new homes.
    • Installing and wiring the applesauce-common package.
    • A step‑by‑step algorithm that an AI agent can safely follow to refactor imports.
  • What this does not cover:
    • Non-import behavior changes (runtime semantics, new features).
    • Breaking changes in external deps (nostr-tools, React, etc.).

If you only remember one thing: most NIP‑specific helpers and models moved out of applesauce-core into applesauce-common.


2. Conceptual changes: applesauce-core vs applesauce-common ​

In v4, applesauce-core exposed both protocol‑level primitives and a large set of NIP‑specific helpers and models. In v5, these responsibilities are split:

  • applesauce-core (protocol‑level primitives):
    • EventStore, AsyncEventStore
    • Observables (Observable, Subject, BehaviorSubject, ReplaySubject), promise helpers (firstValueFrom, lastValueFrom, simpleTimeout, TimeoutError)
    • Low‑level event helpers (NostrEvent, UnsignedEvent, VerifiedEvent, kinds, encoding/decoding, pointer utilities, filters, cache)
    • Base models for generic patterns (EventModel, TimelineModel, ProfileModel, etc. in the “core” sense)
    • EventFactory shell in applesauce-core/event-factory
  • applesauce-common (NIP‑specific and app‑level functionality):
    • NIP‑specific helpers for:
      • Threads/comments (NIP‑10, NIP‑22)
      • Groups
      • Streams (NIP‑53)
      • Articles (NIP‑23)
      • Calendar events (NIP‑52)
      • Polls (NIP‑88)
      • Zaps, bookmarks, mutes, highlights, handlers, blossom servers, etc.
    • NIP‑specific models:
      • CommentsModel, ThreadModel, WrappedMessagesModel, LegacyMessages*, CalendarEventsModel, EventZapsModel, ReceivedZapsModel, SentZapsModel, various “group” and “stream” models, etc.
    • EventFactory blueprints and domain‑level operations.

You can see this reflected in the package docs:

  • applesauce-core: packages/core/README.md
  • applesauce-common: packages/common/README.md
  • Packages overview: apps/docs/introduction/packages.md

Rationale: applesauce-core stays small and focused on the Nostr protocol itself, while applesauce-common hosts higher‑level, NIP‑specific building blocks you may or may not want to depend on.


3. Package changes and installation ​

At a high level, v5 projects will usually use:

AreaPackage(s)
Core protocolapplesauce-core
NIP helpersapplesauce-common
Content parsingapplesauce-content
Reactive UIapplesauce-react
Actionsapplesauce-actions
Wallet (NIP‑60)applesauce-wallet
Relaysapplesauce-relay, applesauce-loaders, etc.

3.1. Add applesauce-common ​

If your v4 project did not already use applesauce-common, install it alongside your existing packages:

sh
npm install applesauce-common applesauce-core
# or
yarn add applesauce-common applesauce-core
# or
pnpm add applesauce-common applesauce-core

3.2. Keep applesauce packages on the same major version ​

To avoid subtle breakage:

  • Ensure all applesauce-* packages you use are on a consistent major version (e.g. all ^5.x once v5 is published).
  • Do not mix applesauce-core@4 with applesauce-common@5, etc.

4. Import migration rules (applesauce-core → applesauce-common) ​

This section is designed for AI agents as well as humans. It focuses on patterns, not a complete symbol list.

4.1. Helpers: move NIP‑specific helpers to applesauce-common/helpers ​

Rule:

  • Before (v4): Many NIP‑specific helpers were imported from:
    • applesauce-core/helpers
    • applesauce-core/helpers/<module>
  • After (v5): Those helpers now live under:
    • applesauce-common/helpers
    • applesauce-common/helpers/<module>

Representative mappings (derived from current exports and examples):

  • Identity / profile helpers:
    • getDisplayName, getProfilePicture, getProfileContent, getProfilePointersFromList
    • v4: from applesauce-core/helpers
    • v5: from applesauce-common/helpers
  • Social graph / relay helpers:
    • groupPubkeysByRelay, mergeRelaySets, getSeenRelays, selectOptimalRelays
    • v4: applesauce-core/helpers
    • v5: applesauce-common/helpers
  • Threading and comments:
    • getNip10References, interpretThreadTags, getCommentEventPointer, getCommentReplyPointer, getCommentRootPointer
    • v4: applesauce-core/helpers (threading‑related modules)
    • v5: applesauce-common/helpers
  • Groups:
    • encodeGroupPointer, decodeGroupPointer, groupMessageEvents, group list helpers
    • NIP-29 Group Management helpers (new in v5): CREATE_GROUP_KIND, CREATE_INVITE_KIND, DELETE_GROUP_KIND, EDIT_METADATA_KIND, JOIN_REQUEST_KIND, LEAVE_REQUEST_KIND, PUT_USER_KIND, REMOVE_USER_KIND, and related group management functions
    • v4: applesauce-core/helpers
    • v5: applesauce-common/helpers (or applesauce-common/helpers/groups for group-specific helpers)
  • Articles / highlights / media:
    • getArticleImage, getArticlePublished, getArticleSummary, getArticleTitle
    • Highlight helpers (getHighlightText, getHighlightContext, getHighlightSourceEventPointer, getHighlightSourceAddressPointer, etc.)
    • v4: applesauce-core/helpers
    • v5: applesauce-common/helpers
  • Calendar:
    • Calendar kinds and symbols (CALENDAR_EVENT_RSVP_KIND, DATE_BASED_CALENDAR_EVENT_KIND, TIME_BASED_CALENDAR_EVENT_KIND, etc.)
    • Helpers like getCalendarEventStart/End, getCalendarEventTitle, getCalendarAddressPointers
    • v4: applesauce-core/helpers
    • v5: applesauce-common/helpers
  • Polls:
    • POLL_KIND, POLL_RESPONSE_KIND, poll options / votes / type helpers
    • v4: applesauce-core/helpers
    • v5: applesauce-common/helpers
  • Zaps:
    • getZapAmount, getZapEventPointer, getZapSender, getZapRecipient, getZapRequest, isValidZap, etc.
    • v4: applesauce-core/helpers
    • v5: applesauce-common/helpers
  • Gift wrap, bookmarks, mutes, streams, handlers, blossom servers, etc.:
    • Numerous helpers with names like getGiftWrapRumor, getBookmarks, getMutedThings, getStream*, getHandler*, mergeBookmarks, matchMutes, mergeBlossomServers.
    • v4: applesauce-core/helpers
    • v5: applesauce-common/helpers
  • Lists and relay lists:
    • FAVORITE_RELAYS_KIND, getListTags, getRelaysFromList, getAddressPointersFromList, isEventPointerInList, ReadListTags, and other list-related helpers
    • v4: applesauce-core/helpers/lists
    • v5: applesauce-common/helpers/lists
  • External identifiers (NIP-73):
    • parseExternalPointer, isValidExternalPointer, getExternalPointerFromTag, ExternalIdentifiers, ExternalPointer
    • v4: applesauce-core/helpers/external-id
    • v5: applesauce-common/helpers/external-id

Keep these in applesauce-core/helpers (protocol primitives):

  • Encoding/decoding and core types:
    • NostrEvent, UnsignedEvent, VerifiedEvent, kinds, noteEncode, neventEncode, naddrEncode, npubEncode, nsecEncode
  • Pointers and tags:
    • AddressPointer, EventPointer, ProfilePointer, isEventPointer, low‑level decodeAddressPointer, decodeEventPointer, decodeProfilePointer
    • Note: In v5, pointer decoding helpers (decodeAddressPointer, decodeEventPointer, decodeProfilePointer, parseReplaceableAddress) no longer throw errors on invalid input; they return null instead. Update any code that relied on try/catch around these functions to check for null return values.
  • Generic tag / filter / cache helpers:
    • Filter, matchFilter, matchFilters, mergeFilters, processTags
    • getOrComputeCachedValue, getCachedValue, setCachedValue, LRU
  • URL / bytes helpers:
    • bytesToHex, hexToBytes, ensureHttpURL, ensureWebSocketURL, normalizeURL, etc.

If a helper name is obviously NIP‑specific or app‑level, move it to applesauce-common/helpers. If it is a core protocol helper (encoding, pointers, filters, cache, low‑level URL handling), keep it in applesauce-core/helpers.

4.2. Models: move NIP‑specific models to applesauce-common/models ​

Rule:

  • Before (v4): Most high‑level models (threads, comments, zaps, streams, calendar, bookmarks, mutes, etc.) were exported from:
    • applesauce-core/models
  • After (v5): These models live in:
    • applesauce-common/models

Representative mappings:

  • Threading / comments:
    • ThreadModel, CommentsModel, RepliesModel, WrappedMessagesModel, LegacyMessagesThreads, LegacyMessageReplies, etc.
    • v4: applesauce-core/models
    • v5: applesauce-common/models
  • Zaps:
    • EventZapsModel, ReceivedZapsModel, SentZapsModel
    • v4: applesauce-core/models
    • v5: applesauce-common/models
  • Calendar:
    • CalendarEventsModel, CalendarEventRSVPsModel
    • v4: applesauce-core/models
    • v5: applesauce-common/models
  • Groups and channels:
    • CommentsModel, channel‑related models (e.g. ChannelMessagesModel, ChannelMetadataModel, ChannelHiddenModel, ChannelMutedModel), streams/chat models
    • v4: applesauce-core/models
    • v5: applesauce-common/models
  • Bookmarks, pins, hidden/public variants:
    • UserBookmarkModel, UserHiddenBookmarkModel, UserPublicBookmarkModel, UserPinnedModel, UserBlossomServersModel
    • v4: applesauce-core/models
    • v5: applesauce-common/models

Models that remain “core”:

  • Base models such as EventModel, TimelineModel, ProfileModel, FiltersModel, MailboxesModel, OutboxModel, ReplaceableModel, ContactsModel, HiddenContactsModel, PublicContactsModel are still conceptually part of applesauce-core.
  • However, in v5 these may be re‑exported and/or extended in applesauce-common/models for NIP‑specific use cases.

Relay models moved to applesauce-common:

  • Relay-related models (FavoriteRelaysModel, FavoriteRelaySetsModel, SearchRelaysModel, BlockedRelaysModel) moved from applesauce-core/models to applesauce-common/models:
    • v4: applesauce-core/models (or applesauce-core/models/relays)
    • v5: applesauce-common/models (or applesauce-common/models/relays)

As a migration heuristic:

  • If a *Model name refers to generic protocol concepts (events, timelines, contacts): keep it in applesauce-core/models.
  • If a *Model name refers to relay lists or other NIP-specific concepts: move it to applesauce-common/models.
  • If it refers to a NIP or app concept (comments, polls, streams, bookmarks, mutes, zaps, calendar, wrapped messages): move it to applesauce-common/models.

4.3. Operations and blueprints: move to applesauce-common ​

In v4, many EventFactory operations and blueprints lived either in applesauce-factory or under applesauce-core exports. In v5:

  • EventFactory itself lives in applesauce-core/event-factory.
  • Domain‑specific operations and blueprints live in applesauce-common:
    • applesauce-common/operations
    • applesauce-common/blueprints

The common operations/blueprints include (non‑exhaustive):

  • Operations:
    • AppData, Calendar, CalendarEvent, CalendarRsvp, Channel, Comment, FileMetadata, Geohash, GiftWrap, Groups, Hashtags, Highlight, LegacyMessage, List, LiveStream, MediaAttachment, Note, PicturePost, Poll, PollResponse, Reaction, Stream, StreamChat, TagOperations, Torrent, WrappedMessage, Zap
  • Blueprints:
    • AppDataBlueprint, CalendarBlueprint, ChannelMessageBlueprint, ChannelMessageReplyBlueprint, CommentBlueprint, DeleteBlueprint, FileMetadataBlueprint, FollowSetBlueprint, GiftWrapBlueprint, GroupMessageBlueprint, HighlightBlueprint, LegacyMessageBlueprint, LegacyMessageReplyBlueprint, LiveChatMessageBlueprint, NoteBlueprint, NoteReplyBlueprint, PicturePostBlueprint, PollBlueprint, PollResponseBlueprint, ProfileBlueprint, ReactionBlueprint, ShareBlueprint, SingleChoicePollResponseBlueprint, StreamChatMessage, TorrentBlueprint, WrappedMessageBlueprint, WrappedMessageReplyBlueprint
    • NIP-29 Group Management blueprints (new in v5): GroupJoinRequestBlueprint, GroupLeaveRequestBlueprint, GroupCreateBlueprint, GroupDeleteBlueprint, GroupEditMetadataBlueprint, GroupPutUserBlueprint, GroupRemoveUserBlueprint

Migration rules:

  • If an operation or blueprint name clearly corresponds to a NIP or domain:
    • v4 imports from applesauce-core or applesauce-factory
    • v5 imports from:
      • applesauce-common/operations (for operations)
      • applesauce-common/blueprints (for blueprints)
  • EventFactory usage:
    • v4:
      • Often import { EventFactory } from "applesauce-factory";
    • v5:
      • import { EventFactory } from "applesauce-core/event-factory";
      • And blueprints/operations from applesauce-common.

5. AI‑friendly refactor algorithm ​

This section is a mechanical algorithm that an AI agent can follow to refactor imports.

5.1. Search scope ​

Scan all TypeScript/JavaScript files:

  • Look for imports whose module specifier starts with:
    • "applesauce-core"
    • "applesauce-factory" (v4 only)

5.2. Classify imported symbols ​

Define two curated lists (these can be hard‑coded by the agent or configured by the user):

  • Always‑core (keep in applesauce-core):
    • EventStore, AsyncEventStore
    • Observable, Subject, BehaviorSubject, ReplaySubject, TimeoutError, firstValueFrom, lastValueFrom, simpleTimeout
    • EventFactory (but move to applesauce-core/event-factory if previously from applesauce-factory)
    • Protocol types and utilities: NostrEvent, UnsignedEvent, VerifiedEvent, kinds, encoding/decoding helpers, pointer types and basic pointer helpers, Filter, cache helpers, pure URL/byte helpers.
  • Always‑common (move to applesauce-common):
    • Any symbol that is:
      • A NIP or app concept: CommentsModel, ThreadModel, WrappedMessagesModel, LegacyMessagesThreads, LegacyMessageReplies, EventZapsModel, CalendarEventsModel, FavoriteRelaysModel, FavoriteRelaySetsModel, SearchRelaysModel, BlockedRelaysModel, HighlightBlueprint, CommentBlueprint, GroupMessageBlueprint, PollBlueprint, Zap, AppData, Calendar, GiftWrap, Stream, etc.
      • A NIP‑oriented helper, e.g. getNip10References, groupPubkeysByRelay (social graph), getArticle*, getHighlight*, getCalendarEvent*, getZap*, list helpers like getListTags, getRelaysFromList, FAVORITE_RELAYS_KIND.

5.3. Rewrite rules (pseudo‑code) ​

For each import statement:

ts
import { A, B, C } from "applesauce-core/helpers";
// or:
import { X, Y } from "applesauce-core/models";
// or:
import { EventFactory, CommentBlueprint } from "applesauce-factory";

Apply this algorithm:

  1. For each imported symbol S:
    1. If S is in the always‑core list:
      • Keep module as applesauce-core (or update path to applesauce-core/event-factory for EventFactory).
    2. Else if S is in the always‑common list or matches any of these patterns:
      • Name ends with Model and is clearly domain‑specific (CommentsModel, ThreadModel, WrappedMessagesModel, etc.).
      • Name ends with Blueprint.
      • Name is in the known operations list (AppData, Calendar, Comment, Poll, Zap, Stream, etc.).
      • Name is a helper that appears in both v4 applesauce-core/helpers and v5 applesauce-common/helpers.
      • Then:
        • If it is a helper → new module: applesauce-common/helpers (or applesauce-common/helpers/<module>).
        • If it is a model → new module: applesauce-common/models.
        • If it is an operation → new module: applesauce-common/operations.
        • If it is a blueprint → new module: applesauce-common/blueprints.
    3. Else if ambiguous:
      • Prefer applesauce-core if it deals only with low‑level protocol concerns.
      • Prefer applesauce-common if it refers to a NIP, UI feature, or application domain.
  2. Once each symbol is classified, group them by their new target module and emit one import per module.

5.4. Handling applesauce-factory ​

If you see imports from "applesauce-factory":

  • EventFactory → import { EventFactory } from "applesauce-core/event-factory";
  • Any blueprints or operations → map to applesauce-common/blueprints or applesauce-common/operations as described above.

5.5. Other packages ​

As you refactor, do not change imports from these packages unless you have a specific reason:

  • applesauce-actions
  • applesauce-wallet
  • applesauce-react
  • applesauce-content
  • applesauce-relay
  • applesauce-loaders

They are already v5‑compatible at their public surface; the main change is that they internally depend on applesauce-common. Your application code usually does not need to adjust imports from these packages.


6. Before/after examples ​

These examples demonstrate common migration patterns.

6.1. Simple helper move (profiles) ​

Before (v4):

ts
import { getDisplayName, getProfilePicture } from "applesauce-core/helpers";

After (v5):

ts
import { getDisplayName, getProfilePicture } from "applesauce-common/helpers";

6.2. Models move (threads and comments) ​

Before (v4):

ts
import { EventStore } from "applesauce-core";
import { ThreadModel, CommentsModel } from "applesauce-core/models";

After (v5):

ts
import { EventStore } from "applesauce-core";
import { ThreadModel, CommentsModel } from "applesauce-common/models";

6.3. Factory + blueprints ​

Before (v4):

ts
import { EventFactory } from "applesauce-factory";
import { CommentBlueprint } from "applesauce-core/operations"; // or applesauce-factory in older code

const factory = new EventFactory({ signer });
const blueprint = CommentBlueprint({ content: "Hello" });

After (v5):

ts
import { EventFactory } from "applesauce-core/event-factory";
import { CommentBlueprint } from "applesauce-common/blueprints";

const factory = new EventFactory({ signer });
const blueprint = CommentBlueprint({ content: "Hello" });

6.4. End‑to‑end example: zap timeline ​

Before (v4) – everything from core:

ts
import { EventStore, mapEventsToStore, mapEventsToTimeline } from "applesauce-core";
import { getZapAmount, getZapEventPointer, getZapSender, isValidZap } from "applesauce-core/helpers";
import { useObservableMemo } from "applesauce-react/hooks";
import { onlyEvents, RelayPool } from "applesauce-relay";

After (v5) – split between core and common:

ts
import { EventStore, mapEventsToStore, mapEventsToTimeline } from "applesauce-core";
import { getZapAmount, getZapEventPointer, getZapSender, isValidZap } from "applesauce-common/helpers";
import { useObservableMemo } from "applesauce-react/hooks";
import { onlyEvents, RelayPool } from "applesauce-relay";

6.5. End‑to‑end example: group threads ​

Before (v4):

ts
import { EventStore, mapEventsToStore, mapEventsToTimeline } from "applesauce-core";
import { getDisplayName, getProfilePicture, getTagValue } from "applesauce-core/helpers";
import { EventFactory } from "applesauce-factory";
import { CommentsModel } from "applesauce-core/models";

After (v5):

ts
import { EventStore, mapEventsToStore, mapEventsToTimeline } from "applesauce-core";
import { getDisplayName, getProfilePicture, getTagValue } from "applesauce-common/helpers";
import { EventFactory } from "applesauce-core/event-factory";
import { CommentsModel } from "applesauce-common/models";

6.6. Lists helpers migration ​

Before (v4):

ts
import { FAVORITE_RELAYS_KIND, getListTags, getRelaysFromList } from "applesauce-core/helpers/lists";
import { FavoriteRelaysModel } from "applesauce-core/models";

After (v5):

ts
import { FAVORITE_RELAYS_KIND, getListTags, getRelaysFromList } from "applesauce-common/helpers/lists";
import { FavoriteRelaysModel } from "applesauce-common/models";

6.7. Pointer helpers behavior change ​

Before (v4) - relying on thrown errors:

ts
import { decodeEventPointer } from "applesauce-core/helpers/pointers";

try {
  const pointer = decodeEventPointer(encoded);
  // use pointer
} catch (e) {
  // handle error
}

After (v5) - checking for null:

ts
import { decodeEventPointer } from "applesauce-core/helpers/pointers";

const pointer = decodeEventPointer(encoded);
if (pointer) {
  // use pointer
} else {
  // handle invalid input
}

7. Notes on other packages ​

7.1. applesauce-actions ​

  • Public exports are stable in v5:
    • Root index exports: ActionRunner, Actions.
    • applesauce-actions/actions exposes individual actions such as BookmarkEvent, FollowUser, MuteUser, SendWrappedMessage, etc.
  • You do not generally need to change your imports:
    • import { ActionRunner } from "applesauce-actions";
    • import { FollowUser } from "applesauce-actions/actions";

Breaking changes in v5:

  • Actions are now async-only: All actions must return Promise<void>. Actions can no longer be synchronous functions or async generators.
  • Removed async generator support: The ActionRunner no longer supports actions that are async generators (async function*).
  • ActionContext methods are async: Both publish and run methods in ActionContext now return Promise<void>.

Migration example:

ts
// v4 - could be sync or async generator
export function MyAction(): Action {
  return async function* (context) {
    // generator code
    yield event1;
    yield event2;
  };
}

// v5 - must be async function returning Promise<void>
export function MyAction(): Action {
  return async (context) => {
    // async code
    await context.publish(event1);
    await context.publish(event2);
  };
}

If you have custom actions that used async generators, convert them to async functions that call context.publish() for each event.

7.2. applesauce-wallet ​

  • Public exports are also stable:
    • Root index exports: Actions, Blueprints, Helpers, Models, Operations.
    • applesauce-wallet/actions exports wallet‑specific actions like CreateWallet, UnlockWallet, NutzapProfile, etc.
  • Migration work here is mostly indirect:
    • Ensure applesauce-common is installed so any shared helpers/models used by wallet internals resolve correctly.

7.3. applesauce-react ​

  • Root exports are unchanged:
    • AccountsContext, AccountsProvider
    • ActionsContext, ActionsProvider
    • EventStoreContext, EventStoreProvider
    • FactoryContext, FactoryProvider
    • Helpers, Hooks
  • Hooks and providers still import from:
    • "applesauce-react/hooks"
    • "applesauce-react/providers"
  • New in v5: The use$ hook is available from "applesauce-react/hooks":
    • A utility hook that combines useObservableState and useMemo for easier observable usage
    • Supports BehaviorSubject, Observable, and factory functions with dependency arrays
    • Example: const value = use$(observable); or const value = use$(() => createObservable(), [deps]);
  • Your migration work is mostly in how you feed models and helpers into your React components (via the import rules above).

7.4. applesauce-content ​

  • The content package’s top‑level exports (Helpers, Text, Markdown, Nast) are unchanged between v4 and v5.
  • Some examples in the docs now combine applesauce-content (for parsing text/markdown) with models and helpers from applesauce-common.

7.5. Loaders, relay, signers, accounts, etc. ​

  • applesauce-loaders, applesauce-relay, applesauce-signers, applesauce-accounts are largely unaffected at the import level.
  • Just ensure you keep them on a consistent major version with applesauce-core/applesauce-common.
Loader attachment to EventStore ​
  • In v4, there were multiple experimental loader properties on EventStore (eventLoader, replaceableLoader, addressableLoader).
  • In v5, these are replaced by a single unified eventLoader. Apps should:
    • Prefer the Unified Event Loader (createUnifiedEventLoader) when setting up loaders.
    • Or, more commonly, use createEventLoaderForStore(eventStore, pool, options) from applesauce-loaders/loaders to attach the unified loader to an EventStore in one step.
RelayPool behavior changes ​
  • RelayPool ignores offline relays by default: The request(), subscription(), publish(), and sync() methods in RelayPool now ignore unreachable (ready=false) relays by default. This is controlled by the ignoreOffline property (default: true). Manual methods like req() and event() still include offline relays.
  • New retry configuration options: Relay and RelayPool constructors now accept subscriptionRetry, requestRetry, and publishRetry options for configuring default retry limits. These replace the previous approach.

Migration note: If your v4 code relied on offline relays being included in automatic methods (request(), subscription(), publish(), sync()), you may need to:

  • Set ignoreOffline: false on your RelayPool instance, or
  • Use the manual req() and event() methods which always include offline relays.

8. Verification and troubleshooting checklist ​

After applying the import migration, use this checklist:

  • 1. Install dependencies
    • Ensure applesauce-common is installed.
    • Align all applesauce-* packages to the same major version.
  • 2. Compile and typecheck
    • Run your project’s build/test commands (for this monorepo, pnpm build / pnpm test).
    • Fix any remaining import‑not‑found errors by moving the symbol to applesauce-common as per the rules above.
  • 3. Runtime smoke tests
    • Open key screens: threads/comments, group chat, highlight/article pages, zap timelines, calendar views.
    • Verify that models populate and helpers behave as before.
  • 4. Diff‑based validation (for AI agents)
    • Confirm that any removed imports from "applesauce-core/helpers" or "applesauce-core/models":
      • Either moved to "applesauce-common/helpers" / "applesauce-common/models" / "applesauce-common/operations" / "applesauce-common/blueprints", or
      • Were intentionally deleted because they are unused.
  • 5. Ambiguous symbols
    • When in doubt, prefer:
      • applesauce-core for protocol‑level primitives and generic utilities.
      • applesauce-common for NIP‑specific or app‑level behavior.

Once this checklist passes, your project should be functionally equivalent to the v4 version while taking full advantage of the v5 applesauce-common split.


9. New features in v5 ​

This section documents new features and APIs introduced in v5 that are not migration concerns but may be useful to know about.

9.1. Event Casting System ​

v5 introduces a type-safe event casting system in applesauce-common/casts for working with Nostr events in a more structured way.

Location: applesauce-common/casts or applesauce-common/Casts

Key exports:

  • cast() function and Cast base class
  • Specific cast classes: NoteCast, ProfileCast, ZapCast, CommentCast, MailboxesCast, StreamCast

Usage example:

ts
import { cast, NoteCast } from "applesauce-common/casts";

// Cast an event to a NoteCast for type-safe access to note-specific properties
const note = cast(event, NoteCast);
// Now you can use note-specific methods and properties

This is a new API for v5 and does not require migration from v4 code.

9.2. Observable Utilities ​

v5 adds new observable utilities in applesauce-common/observable:

Location: applesauce-common/observable or applesauce-common/Observable

Key exports:

  • chainable - Chainable observable utilities for building reactive pipelines
  • cast-event - Event casting observables
  • filter-timeline-by-mutes - Timeline filtering utilities for muting

These are new utilities for v5 and do not require migration from v4 code.

9.3. NIP-29 Group Management ​

v5 adds comprehensive support for NIP-29 group management:

Helpers: applesauce-common/helpers/groups

  • Group management constants: CREATE_GROUP_KIND, CREATE_INVITE_KIND, DELETE_GROUP_KIND, EDIT_METADATA_KIND, JOIN_REQUEST_KIND, LEAVE_REQUEST_KIND, PUT_USER_KIND, REMOVE_USER_KIND
  • Group management helper functions

Blueprints: applesauce-common/blueprints

  • GroupJoinRequestBlueprint - Create a join request for a group
  • GroupLeaveRequestBlueprint - Create a leave request for a group
  • GroupCreateBlueprint - Create a new group
  • GroupDeleteBlueprint - Delete a group
  • GroupEditMetadataBlueprint - Edit group metadata
  • GroupPutUserBlueprint - Add or update a user in a group
  • GroupRemoveUserBlueprint - Remove a user from a group

This is a new feature for v5 and does not require migration from v4 code.