AbsoluteJS

@absolutejs/sync-pack-favorites

@absolutejs/sync-pack-favoritesv0.2.4betaData & Sync

Per-actor saved-resources pack for @absolutejs/sync — favorite/unfavorite/pin/list with optional join to host resources

#Installation

BASH
bun add @absolutejs/sync-pack-favorites

#Capabilities

Overview

Per-actor saved-resources pack for @absolutejs/sync. Each actor sees only their own rows; favoriting is idempotent (deterministic row id); optional join collection pairs each favorite with the host's resource row in one live subscription.

Usage

Then from the client:

The pack exposes

Surface — Name — What it does

Collection — favorites — Per-actor list. Optional params.resourceKind filter

Mutation — favorites:favorite — Idempotent insert. Subsequent calls are no-ops

Show 3 more

Mutation — favorites:unfavorite — Idempotent delete. No-op if the row never existed

Mutation — favorites:toggle — Insert if missing, delete if present. Returns { favorited }

Collection — favorites-with-resource (opt) — Join with the host's resource table — see below

Row shape

The deterministic id means the same (actor, kind, resource) triple always maps to the same row — so duplicate favorite calls are idempotent at the storage layer, not just behaviorally.

Optional: favorites-with-resource join

When you set joinResources, the pack additionally registers a join collection that pairs each favorite with the host's resource row (same pattern as comments-with-author from sync-pack-comments).

Inner join — favorites whose resource has been deleted drop out of the join (but stay in the base favorites collection).

Storage

Default: per-instance in-memory store. For a persistent backend, pass a custom store:

Multiple instances

Pass a prefix to coexist with another favorites pack instance (e.g. a "team" set vs a "private" set):

Outcomes

What you can build

Build on the supported package contract

Use @absolutejs/sync-pack-favorites through its supported public entry points.

Hardening checklist

Production guidance

Make every external boundary explicitPin the deployed @absolutejs/sync-pack-favorites version, replace example or memory-backed dependencies with durable implementations, bound external calls, protect credentials, and emit enough evidence to retry or recover safely.

Follow in order

Troubleshooting path

1
Trace from the first failed boundary
Reproduce the smallest canonical @absolutejs/sync-pack-favorites example, confirm the supported entry point and version in the API explorer, then inspect the first boundary that did not produce its documented result.

#@absolutejs/sync-pack-favorites quick start

Partial snippet

# @absolutejs/sync-pack-favorites

BASH
bun add @absolutejs/sync-pack-favorites

#Usage

Partial snippet

Working example for Usage.

TS
import { createSyncEngine } from '@absolutejs/sync/engine';
import { createFavoritesPack } from '@absolutejs/sync-pack-favorites';

const engine = createSyncEngine();
engine.registerPack(
	createFavoritesPack({
		getActorId: (ctx) => ctx.session.userId,
	}),
);

#Usage 2

Partial snippet

Then from the client:

TS
// Toggle is the easy default — one round-trip, returns the new state.
const { favorited } = await store.mutate({
	args: { resourceKind: 'doc', resourceId: 'doc-123' },
	name: 'favorites:toggle',
});

// Or favorite / unfavorite explicitly.
await store.mutate({ args: { resourceKind: 'doc', resourceId: 'doc-123' }, name: 'favorites:favorite' });
await store.mutate({ args: { resourceKind: 'doc', resourceId: 'doc-123' }, name: 'favorites:unfavorite' });

#Row shape

Partial snippet

Working example for Row shape.

TS
type FavoriteRow = {
	id: string;              // `${actorId}:${resourceKind}:${resourceId}`deterministic
	actorId: string;
	resourceKind: string;    // app-level: "doc" | "task" | "issue" | ...
	resourceId: string;
	createdAt: number;
};

#Optional: favorites-with-resource join

Partial snippet

When you set joinResources, the pack additionally registers a join collection that pairs each favorite with the host's resource row (same pattern as comments-with-author from sync-pack-comments).

TS
type DocRow = { id: string; title: string };

engine.registerReader('docs', { all: () => db.docs.list() });
engine.registerPack(
	createFavoritesPack<MyCtx, DocRow>({
		getActorId,
		joinResources: {
			table: 'docs',
			// Default (row) => row.id; override if your resource id key isn't `id`.
			// key: (doc) => doc.docId,
			// Required: host supplies the resource-side hydrate.
			hydrate: () => db.docs.list(),
		},
	}),
);

const view = await engine.subscribe<
	FavoriteRow & { resource: DocRow },
	{ resourceKind?: string }
>({
	collection: 'favorites-with-resource',
	params: { resourceKind: 'doc' },
	ctx,
	onDiff: rerender,
});
// view.initial[0] === { ...favorite, resource: { id, title } }

#Public entry points

Supported entry points declared by this package manifest.

Package entry point declared in package.json.

@absolutejs/sync-pack-favorites@absolutejs/sync-pack-favorites/manifest@absolutejs/sync-pack-favorites/manifest.json

#Package commands

Scripts declared by this package manifest.

bun run buildrm -rf dist && bun build src/index.ts src/manifest.ts --outdir dist --sourcemap --target=bun --external @absolutejs/sync && tsc --project tsconfig.build.json && absolute-manifest emit
bun run formatprettier --write "./**/*.{ts,json,md}"
bun run testbun test
bun run typechecktsc --noEmit

#API reference

Search the declarations exported by the current package type files. Expand a symbol to inspect its source-backed signature.

7 symbols
FavoriteRowtypePermalinkSource

A single favorited resource for a single actor.

TS
type FavoriteRow = {
    /** `${actorId}:${resourceKind}:${resourceId}` — deterministic so toggling is idempotent. */
    id: string;
    actorId: string;
    /** App-level resource type ("doc", "task", "issue", ...). Lets one inbox span multiple kinds. */
    resourceKind: string;
    resourceId: string;
    createdAt: number;
    /**
     * When the actor pinned this favorite, or `null` when unpinned.
     * Clients can sort pinned-first by descending `pinnedAt`. Set by the
     * `favorites:pin` / `favorites:togglePin` mutations.
     */
    pinnedAt: number | null;
};
Exported from @absolutejs/sync-pack-favorites