agentsclimarketplace

Zenstack migrate from v2

Skill zenstackhq/skills/skills/zenstack-migrate-from-v2

Upgrade an existing ZenStack V2 project to V3. Use when renaming V2 packages (zenstack, @zenstackhq/runtime), moving access control to the policy plugin, converting future() to post-update/before(), replacing abstract models with types+mixins, updating server adapters (getPrisma → getClient), and migrating client-side TanStack Query hooks.From its SKILL.md

Install
npx -y skills add zenstackhq/skills --skill zenstack-migrate-from-v2

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

2 things to look at

  • 3 stars3 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
  • runs commandsInstructs the agent to run 5 commands, including `npm uninstall zenstack @zenstackhq/runtime` and 4 more.

SKILL.md

5.2 KB, ~1.3k tokens by cl100k_base, as published. Nobody here has run it

Migrating from ZenStack V2 to V3

ZenStack V3 is a major rewrite: the Prisma ORM engine is replaced with ZenStack's own engine built on Kysely, while the ZModel schema stays largely compatible and the query API stays PrismaClient-compatible. Supported databases: PostgreSQL, MySQL, SQLite.

Because V2 was Prisma-based, the migration has two layers: the generic Prisma→ZenStack changes, then the V2-specific deltas below. For general setup/CLI see zenstack-project-setup.

Step 1 — Do the Prisma migration first

V2 ran on Prisma, so start with the zenstack-migrate-from-prisma skill (swap deps, move the schema to zenstack/schema.zmodel, replace the client with ZenStackClient, update generate/migrate scripts). Then apply the V2-specific steps below.

Step 2 — Rename ZenStack packages

npm uninstall zenstack @zenstackhq/runtime
npm install @zenstackhq/schema @zenstackhq/orm
npm install --save-dev @zenstackhq/cli
V2V3
zenstack (CLI)@zenstackhq/cli
@zenstackhq/runtime@zenstackhq/orm
—@zenstackhq/schema (new)

The CLI command moves from zenstack <cmd> to zen <cmd> (e.g. zen generate).

Step 3 — Access control is now a plugin

In V2 access control was built into the runtime (enhance(prisma)). In V3 it's an opt-in plugin.

  1. Install it: npm install @zenstackhq/plugin-policy
  2. Declare it in the schema:
    plugin policy {
        provider = '@zenstackhq/plugin-policy'
    }
    
  3. Wrap the client and bind the user per request:
    import { ZenStackClient } from '@zenstackhq/orm';
    import { PolicyPlugin } from '@zenstackhq/plugin-policy';
    
    export const db = new ZenStackClient(schema, { dialect });
    export const authDb = db.$use(new PolicyPlugin());   // was: enhance(prisma, { user })
    // per request:
    const userDb = authDb.$setAuth(user);                // was: passing { user } to enhance()
    

See zenstack-access-control for the full policy/runtime model.

Step 4 — Post-update policies: future() → post-update + before()

V2 expressed post-update conditions with future() inside an update rule. V3 uses a dedicated post-update operation, where bare field references mean the new values and before() reads the old ones.

// V2
@@deny('update', future().ownerId != ownerId)

// V3
@@deny('post-update', ownerId != before().ownerId)

Step 5 — Abstract models → types + mixins

V2's abstract model + extends becomes a type applied with with (see zenstack-schema-modeling).

// V2
abstract model Timestamped {
    createdAt DateTime @default(now())
    updatedAt DateTime @updatedAt
}
model Post extends Timestamped { title String }

// V3
type Timestamped {
    createdAt DateTime @default(now())
    updatedAt DateTime @updatedAt
}
model Post with Timestamped { title String }

(Note: extends still exists in V3, but for polymorphism via @@delegate, which is a different feature — don't use it as a plain mixin replacement.)

Step 6 — Server adapters

V3 requires you to pass an explicit apiHandler (RPCApiHandler or RestApiHandler), and the client-supplying callback is renamed getPrisma → getClient:

// V2
ZenStackMiddleware({ getPrisma: (req) => enhance(prisma, { user: getUser(req) }) });

// V3
ZenStackMiddleware({
    apiHandler: new RPCApiHandler({ schema }),
    getClient: (req) => authDb.$setAuth(getUser(req)),
});

See zenstack-crud-server for all frameworks and both API styles.

Step 7 — Client-side hooks (TanStack Query)

Flat hook names are replaced by hooks grouped under a client that mirrors the ORM:

// V2
import { useFindManyUser } from '~/hooks';
const { data } = useFindManyUser({ where: { ... } });

// V3
import { useClientQueries } from '@zenstackhq/tanstack-query/react';
import { schema } from '~/zenstack/schema';

const client = useClientQueries(schema);
const { data } = client.user.useFindMany({ where: { ... } });

SWR support was dropped in V3. See zenstack-crud-server for the full TanStack Query setup.

Step 8 — Other plugin/utility migrations

  • Zod: now a utility rather than a plugin (see the zod utility docs).
  • OpenAPI: folded into the automatic CRUD API handlers — generate a spec via apiHandler.generateSpec() (see zenstack-crud-server).
  • Custom plugins: the V3 plugin system is revised; consult the current plugin docs.

After upgrading

Run zen generate, typecheck, and exercise your test suite / app. Confirm access control behaves as expected now that it's an explicit $use(new PolicyPlugin()) + $setAuth() flow rather than V2's implicit enhance().

Reference docs

Full ZenStack documentation for this topic is bundled under references/:

What ships with it: 1 file

33 B alongside SKILL.md

references/

Keep looking

Skills are one crate of 325,949. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.