Build on the supported package contract
Use @absolutejs/sync-pack-utils through its supported public entry points.
@absolutejs/sync-pack-utilsv0.1.3betaData & SyncShared helpers for @absolutejs/sync packs — resolveActor, requireRowOwner/Moderator, createInMemoryStore, and other patterns extracted from the official packs
bun add @absolutejs/sync-pack-utilsShared helpers for @absolutejs/sync packs. Each helper closes one repeated pattern that showed up across the six official packs (presence, comments, digest, notifications, favorites, counters). The goal: make new packs — first- or third-party — cheaper to write and consistent with what's already shipped.
Actor resolution
Permission builders
requireRowOwner and requireOwnerOrModerator are higher-order — call them once at pack-build time to receive the per-row predicate the engine expects. Both reject when getActorId(ctx) is undefined (anonymous callers can't own a row).
In-memory store
createInMemoryStore<Row>() returns:
reader: TableReader<CollectionContext> — all() returns [...rows.values()]
writer: TableWriter<Row> — upsert-by-id; delete removes by row.id
getById(id) — point lookup
rows: Map — direct access (treat as read-only)
Every official pack uses this as its default backing store and exposes a store?: ... config field so consumers can swap in a Postgres / Drizzle / Redis implementation when they need persistence.
prefixed(prefix, ...): just use template literals.
${prefix} is fine.
defineActorPack(...): a Convex-style abstraction that wraps
defineSyncPack with permission defaults. Decided against — it'd hide the engine surface, which is the thing pack authors learn first.
Validators / Zod adapters: out of scope; sync's field helper +
schema is the validation layer.
Pack tests typically pair with @absolutejs/sync/testing (added in sync 1.9.2):
This package stays 0.x indefinitely while the ecosystem settles. When the six official packs are stable, the helpers will follow.
Outcomes
Use @absolutejs/sync-pack-utils through its supported public entry points.
Hardening checklist
Follow in order
# @absolutejs/sync-pack-utils
bun add @absolutejs/sync-pack-utilsWorking example for Actor resolution.
import {
defaultGetActorId,
resolveActor,
} from '@absolutejs/sync-pack-utils';
// (ctx) => ctx.userId — the conventional default.
const getActorId = config.getActorId ?? defaultGetActorId<MyCtx>();
// Inside a mutation handler: throws UnauthorizedError if no actor id.
// The context string ends up in the error message so logs name the op.
const actorId = resolveActor(getActorId, ctx, 'mypack:create');Working example for Permission builders.
import {
requireRowOwner,
requireOwnerOrModerator,
} from '@absolutejs/sync-pack-utils';
permissions: {
[table]: {
read: ...,
// Owner-only writes — uses row.actorId by default; override the
// field name for packs that use authorId, userId, etc.
insert: requireRowOwner(getActorId, 'actorId'),
update: requireRowOwner(getActorId, 'actorId'),
// Owner OR moderator delete. Falls back to store.getById when
// actions.delete supplied only the row key (the common case).
delete: requireOwnerOrModerator({
actorIdField: 'actorId',
canModerate, // optional
getActorId,
store, // { getById }
}),
},
},Supported entry points declared by this package manifest.
Package entry point declared in package.json.
Scripts declared by this package manifest.
Search the declarations exported by the current package type files. Expand a symbol to inspect its source-backed signature.