npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

zakarya

v1.0.1

Published

Production-grade frontend framework generator for Next.js App Router with TanStack Query and feature-based architecture

Downloads

30

Readme

zakarya

Production-grade frontend framework generator for Next.js (App Router) TanStack Query · Axios · TypeScript Strict · Feature-Based Architecture

  ╔══════════════════════════════════════════╗
  ║                                          ║
  ║    ███████   █████   ██   ██  ██   ██    ║
  ║       ███   ██   ██  ██  ██    ██ ██     ║
  ║      ███    ███████  █████     ███       ║
  ║     ███     ██   ██  ██  ██     ██       ║
  ║    ███████  ██   ██  ██   ██    ██       ║
  ║                                          ║
  ║   Frontend Framework Generator  v1.0.0   ║
  ║   Next.js · TanStack Query · TypeScript  ║
  ╚══════════════════════════════════════════╝

Table of Contents

  1. Philosophy
  2. CLI Architecture
  3. Internal Folder Structure
  4. Installation
  5. Commands
  6. Generated Project Architecture
  7. Generator Engine Design
  8. Complete Generated Feature Example
  9. zakarya.config.json Reference
  10. Plugin System
  11. Safety System
  12. Naming Convention Engine
  13. Dependency Rules
  14. Evolution Roadmap
  15. Direct use

Direct use

Quick, direct examples showing how to run the CLI and what to expect.

  • Create a new project (interactive):
zakarya create my-app
# alias: zakarya init my-app

What happens:

  • Prompts for package manager, API base URL and features (skip with -y).

  • Scaffolds my-app/ with app/, src/shared/, src/features/, config files, and zakarya.config.json.

  • Installs dependencies (npm/yarn/pnpm) unless you opt out; use --yes to skip prompts or --force to overwrite.

  • Generate an isolated feature:

zakarya generate feature sales
# alias: zakarya g feature sales

What happens:

  • Creates src/features/sales/ with types/, services/, queries/, mutations/, hooks/, components/, and index.ts.

  • Registers SALES_BASE in src/shared/api/endpoints.constants.ts and appends export * as salesFeature from './sales'; to src/features/index.ts (idempotent).

  • Use --force to overwrite existing files if needed.

  • Generate a resource (CRUD-ready):

zakarya generate resource products

What happens:

  • Similar to feature generation but includes CRUD scaffolding and domain presets (pagination, filters, etc.).

  • Check project health:

zakarya doctor

What happens:

  • Runs architecture checks (config, shared layer files, cross-feature imports, feature structure, injection markers) and reports errors or warnings.

Quick flags:

  • -y, --yes — skip prompts and accept defaults
  • -f, --force — overwrite existing files without confirmation
  • --root <path> — set project root for generation
  • --plugins <list> — comma-separated plugins to enable (e.g. auth,payments)

Philosophy

zakarya is not a template copier. It is a frontend framework generation system.

It exists to solve the #1 scaling problem in frontend engineering teams: architectural drift.

When five engineers start five features, they produce five different patterns — different folder names, different query strategies, different error handling approaches, different import paths. Three months later, the codebase is an archaeology site.

zakarya enforces a single, opinionated, machine-verified architecture. Every feature generated by zakarya is:

  • Isolated — cannot import from another feature
  • Predictable — identical internal structure, always
  • Consistent — same naming conventions, same query patterns, same service contract
  • Safe — no accidental overwrites, backup before every mutation
  • Extensible — plugins can add new generator types without touching core

CLI Architecture

zakarya (CLI entry)
│
├── commands/              ← Commander.js command registrations
│   ├── create.ts          ← zakarya create <n>
│   ├── init.ts            ← zakarya init <n> (alias)
│   ├── generate.ts        ← zakarya generate feature|resource
│   └── doctor.ts          ← zakarya doctor (arch validation)
│
├── generators/            ← Core generation logic
│   ├── project.generator.ts   ← Scaffolds full Next.js project
│   ├── feature.generator.ts   ← Generates isolated feature module
│   └── resource.generator.ts  ← CRUD resource with smart presets
│
├── engine/                ← Generation primitives
│   ├── naming.engine.ts   ← All naming conventions (camel/pascal/kebab/…)
│   ├── template.engine.ts ← {{VAR}} interpolation + #if/#each blocks
│   └── injection.engine.ts← Safe code injection into existing files
│
├── templates/             ← Code templates per layer
│   ├── feature/           ← types/service/queries/mutations/hooks templates
│   └── project/           ← shared layer / app / config templates
│
├── config/
│   ├── config.types.ts    ← ZakaryaConfig interface + DEFAULT_CONFIG
│   └── config.resolver.ts ← Reads & deep-merges zakarya.config.json
│
├── plugins/
│   └── plugin.system.ts   ← Plugin contract, registry, loader
│
├── safety/
│   └── safety.system.ts   ← Backup-before-overwrite, confirm gates
│
└── utils/
    ├── banner.ts           ← ASCII art banner
    └── package.ts          ← Reads CLI version from package.json

How zakarya create works internally

zakarya create my-app
        │
        ▼
createCommand.action()
        │
        ├─ validateProjectName()          ← regex check on project name
        ├─ resolveConfig()                ← read zakarya.config.json (or defaults)
        │
        ▼
projectGenerator.generate()
        │
        ├─ promptUser()                   ← inquirer: pm, apiUrl, features
        ├─ createDirectoryStructure()     ← mkdir src/features, src/shared/**
        ├─ writeSharedLayer()             ← apiClient, endpoints, AppError, QueryClient, Providers
        ├─ writeAppFiles()                ← app/layout.tsx, app/page.tsx, globals.css
        ├─ writeConfigFiles()             ← next.config.ts, tsconfig.json, .env.local, package.json
        ├─ writeConfig()                  ← zakarya.config.json
        └─ installDependencies()          ← npm/yarn/pnpm/bun install

How zakarya generate feature works internally

zakarya generate feature sales
        │
        ▼
generateCommand → featureGenerator.generate()
        │
        ├─ namingEngine.derive('sales')
        │     → { pascal: 'Sales', camel: 'sales', kebab: 'sales',
        │          singularPascal: 'Sale', pluralPascal: 'Sales', … }
        │
        ├─ createDirectories()
        │     src/features/sales/{types,services,queries,mutations,hooks,components}/
        │
        ├─ generateFiles()  (for each template)
        │     ├─ templateEngine.render(typeTemplate(), context)
        │     ├─ safety.safeWrite(filePath, content, force)
        │     └─ [repeat for all 8 files]
        │
        ├─ registerEndpoint()
        │     injectionEngine.registerEndpoint(
        │       'src/shared/api/endpoints.constants.ts',
        │       'SALES', '/sales'
        │     )
        │
        └─ updateFeaturesBarrel()
              injectionEngine.appendToBarrel(
                'src/features/index.ts',
                "export * as salesFeature from './sales';"
              )

Internal Folder Structure

zakarya/                         ← CLI package root
├── src/
│   ├── index.ts                 ← Entry point, bootstraps Commander
│   ├── commands/
│   │   ├── create.ts
│   │   ├── init.ts
│   │   ├── generate.ts
│   │   └── doctor.ts
│   ├── generators/
│   │   ├── project.generator.ts
│   │   ├── feature.generator.ts
│   │   └── resource.generator.ts
│   ├── engine/
│   │   ├── naming.engine.ts
│   │   ├── template.engine.ts
│   │   └── injection.engine.ts
│   ├── templates/
│   │   ├── feature/
│   │   │   └── feature.templates.ts   ← all 8 feature file templates
│   │   └── project/
│   │       └── project.templates.ts   ← shared layer + app templates
│   ├── config/
│   │   ├── config.types.ts
│   │   └── config.resolver.ts
│   ├── plugins/
│   │   └── plugin.system.ts
│   ├── safety/
│   │   └── safety.system.ts
│   └── utils/
│       ├── banner.ts
│       └── package.ts
├── dist/                        ← Compiled output (git-ignored)
├── package.json
├── tsconfig.json
└── README.md

Installation

# Global install (recommended)
npm install -g zakarya

# Or use without installing
npx zakarya create my-app

Commands

zakarya create

zakarya create <project-name> [options]
zakarya init <project-name> [options]      # alias

Options:
  -y, --yes              Skip prompts, use defaults
  -f, --force            Overwrite existing files
  --api-url <url>        Override API base URL
  --plugins <list>       Comma-separated plugins (e.g. auth,payments)

Examples:
  zakarya create my-app
  zakarya create my-app --yes --api-url https://api.myapp.com
  zakarya create my-app --plugins auth,payments

What gets created:

my-app/
├── app/
│   ├── layout.tsx           ← RootLayout with QueryProvider
│   ├── page.tsx             ← Welcome page
│   └── globals.css
├── src/
│   ├── features/            ← Feature modules live here
│   │   └── index.ts         ← Features barrel (auto-updated by generator)
│   └── shared/
│       ├── api/
│       │   ├── client.ts            ← Axios singleton + interceptors
│       │   └── endpoints.constants.ts  ← All endpoint paths
│       ├── errors/
│       │   └── app.error.ts         ← Normalized AppError class
│       ├── tanstack/
│       │   ├── query-client.ts      ← Singleton QueryClient
│       │   └── providers.tsx        ← <QueryProvider> wrapper
│       ├── constants/
│       ├── utils/
│       ├── config/
│       └── types/
├── .env.local
├── .env.example
├── .gitignore
├── next.config.ts
├── tsconfig.json
├── package.json
└── zakarya.config.json

zakarya generate feature

zakarya generate feature <name> [options]
zakarya g feature <name>                   # alias

Options:
  -f, --force       Overwrite existing files without confirmation
  --root <path>     Project root (default: cwd)

Examples:
  zakarya generate feature sales
  zakarya generate feature salesOrder
  zakarya generate feature invoice-items
  zakarya g feature products --force

Generated structure:

src/features/sales/
├── types/
│   └── Sale.types.ts            ← Sale, SaleDraft, SaleUpdatePayload, SaleFilters, SalesResponse
├── services/
│   └── sales.service.ts         ← salesService.getAll/getById/create/update/delete
├── queries/
│   ├── sales.keys.ts            ← salesKeys query key factory
│   └── sales.queries.ts         ← salesListQueryOptions, salesDetailQueryOptions
├── mutations/
│   └── sales.mutations.ts       ← useCreateSaleMutation, useUpdateSaleMutation, useDeleteSaleMutation
├── hooks/
│   ├── useSales.ts              ← useSales(filters?) → useQuery(salesListQueryOptions)
│   └── useSale.ts               ← useSale(id) → useQuery(salesDetailQueryOptions)
├── components/                  ← (empty, for feature UI components)
└── index.ts                     ← Public barrel export

Also automatically:

  • Registers SALES_BASE: '/sales' in src/shared/api/endpoints.constants.ts
  • Adds export * as salesFeature from './sales'; to src/features/index.ts

zakarya generate resource

zakarya generate resource <name> [options]
zakarya g resource <name>

Options:
  -f, --force     Overwrite existing files
  --root <path>   Project root

Examples:
  zakarya generate resource products
  zakarya generate resource auth
  zakarya generate resource orders

Resource generation includes smart domain presets for well-known names:

| Resource | Smart additions | |-----------|----------------------------------------------------------| | auth | login / register / reset-password / token-refresh flows | | products| inventory tracking, category filters, search/facets | | sales | pagination, date range filters, status filters | | orders | order status flow, order items, shipping tracking | | users | role management, permission gates, profile management | | (other) | Standard CRUD |


zakarya doctor

zakarya doctor [--root <path>]

Validates your project's architectural health:

  • zakarya.config.json exists
  • ✓ All shared layer files present (client.ts, app.error.ts, etc.)
  • ✓ No cross-feature imports (feature isolation rule)
  • ✓ All features have required sub-directories
  • endpoints.constants.ts has injection marker

Example output:

zakarya doctor — Architecture Health Report
──────────────────────────────────────────

✖ 1 error(s):
  • Cross-feature import violation in src/features/orders/services/orders.service.ts:
    Feature "orders" imports from feature "products".
    Move shared logic to src/shared/ instead.

⚠ 1 warning(s):
  • Feature "invoices" is missing the "mutations/" sub-directory.

  11 of 13 checks passed.

Generated Project Architecture

src/
├── features/                     ← ISOLATED feature modules
│   ├── index.ts                  ← Auto-updated barrel
│   ├── sales/
│   │   ├── types/
│   │   ├── services/
│   │   ├── queries/
│   │   ├── mutations/
│   │   ├── hooks/
│   │   ├── components/
│   │   └── index.ts
│   └── products/
│       └── …
│
└── shared/                       ← GLOBAL infrastructure (no feature imports)
    ├── api/
    │   ├── client.ts             ← Axios singleton
    │   └── endpoints.constants.ts
    ├── errors/
    │   └── app.error.ts
    ├── tanstack/
    │   ├── query-client.ts
    │   └── providers.tsx
    ├── constants/
    ├── utils/
    ├── config/
    └── types/

Architecture Rules (enforced by zakarya doctor):

  1. Features are fully isolated — no feature imports another feature
  2. All API calls go through shared/api/client.ts (Axios singleton)
  3. All errors surface as AppError from shared/errors/app.error.ts
  4. All query configuration flows from shared/tanstack/query-client.ts
  5. Endpoint paths live exclusively in shared/api/endpoints.constants.ts
  6. Components import only hooks from their own feature's hooks/ directory

Generator Engine Design

TemplateEngine

Lightweight {{VARIABLE}} interpolation with conditional and iteration support.

// Supports:
templateEngine.render(`
  export interface {{singularPascal}} {
    id: string;
    // fields…
  }

  {{#if withZod}}
  export const {{camel}}Schema = z.object({ id: z.string() });
  {{/if}}

  {{#each endpoints}}
  // Endpoint: {{item}}
  {{/each}}
`, context);

No external template library dependency — pure regex-based, zero overhead.

NamingEngine

Single source of truth for all identifier casing. Given any input:

namingEngine.derive('sales-order')
// →
{
  raw:            'sales-order',
  camel:          'salesOrder',
  pascal:         'SalesOrder',
  kebab:          'sales-order',
  snake:          'sales_order',
  screamingSnake: 'SALES_ORDER',
  singularCamel:  'salesOrder',  // best-effort English singularization
  singularPascal: 'SalesOrder',
  pluralCamel:    'salesOrders',
  pluralPascal:   'SalesOrders',
}

Derived hook/service names:

engine.hookName(variants, 'Query')        // → useSalesOrderQuery
engine.serviceName(variants)              // → salesOrderService
engine.queryKeysName(variants)            // → salesOrderKeys
engine.mutationName(variants, 'create')   // → createSalesOrderMutation

InjectionEngine

Safe mutation of existing generated files without breaking user code.

// Injects after a marker comment — idempotent
await injectionEngine.injectAtMarker(
  'src/shared/api/endpoints.constants.ts',
  '// [zakarya:inject:endpoints]',
  "  SALES_BASE: '/sales',",
  'SALES_BASE'   // idempotency key — skips if already present
);

// Appends to barrel — skips if export already there
await injectionEngine.appendToBarrel(
  'src/features/index.ts',
  "export * as salesFeature from './sales';"
);

Complete Generated Feature Example

Running zakarya generate feature sales produces:

src/features/sales/types/Sale.types.ts

export interface Sale {
  id: string;
  createdAt: string;
  updatedAt: string;
  // TODO: add your Sale-specific fields here
}

export interface SaleDraft {
  // TODO: fields required to create a new Sale
}

export interface SaleUpdatePayload {
  id: string;
  // TODO: fields allowed to update
}

export interface SaleFilters {
  search?: string;
  page?: number;
  pageSize?: number;
  sortBy?: keyof Sale;
  sortOrder?: 'asc' | 'desc';
}

export interface SalesResponse {
  data: Sale[];
  total: number;
  page: number;
  pageSize: number;
  totalPages: number;
}

src/features/sales/services/sales.service.ts

import { apiClient } from '@/shared/api/client';
import { ENDPOINTS } from '@/shared/api/endpoints.constants';
import type { Sale, SaleDraft, SaleUpdatePayload, SaleFilters, SalesResponse } from '../types/Sale.types';

const BASE = ENDPOINTS.SALES_BASE;

export const salesService = {
  getAll:   async (filters?: SaleFilters): Promise<SalesResponse> => {
    const { data } = await apiClient.get<SalesResponse>(BASE, { params: filters });
    return data;
  },
  getById:  async (id: string): Promise<Sale> => {
    const { data } = await apiClient.get<Sale>(`${BASE}/${id}`);
    return data;
  },
  create:   async (payload: SaleDraft): Promise<Sale> => {
    const { data } = await apiClient.post<Sale>(BASE, payload);
    return data;
  },
  update:   async ({ id, ...payload }: SaleUpdatePayload): Promise<Sale> => {
    const { data } = await apiClient.patch<Sale>(`${BASE}/${id}`, payload);
    return data;
  },
  delete:   async (id: string): Promise<void> => {
    await apiClient.delete(`${BASE}/${id}`);
  },
} as const;

src/features/sales/queries/sales.keys.ts

import type { SaleFilters } from '../types/Sale.types';

export const salesKeys = {
  all:     ['sales'] as const,
  lists:   () => [...salesKeys.all, 'list'] as const,
  list:    (filters?: SaleFilters) => [...salesKeys.lists(), { filters }] as const,
  details: () => [...salesKeys.all, 'detail'] as const,
  detail:  (id: string) => [...salesKeys.details(), id] as const,
} as const;

src/features/sales/queries/sales.queries.ts

import { queryOptions } from '@tanstack/react-query';
import { salesService } from '../services/sales.service';
import { salesKeys } from './sales.keys';
import type { SaleFilters } from '../types/Sale.types';

export const salesListQueryOptions = (filters?: SaleFilters) =>
  queryOptions({
    queryKey: salesKeys.list(filters),
    queryFn:  () => salesService.getAll(filters),
    staleTime: 60_000,
  });

export const salesDetailQueryOptions = (id: string) =>
  queryOptions({
    queryKey: salesKeys.detail(id),
    queryFn:  () => salesService.getById(id),
    enabled:  Boolean(id),
    staleTime: 60_000,
  });

src/features/sales/mutations/sales.mutations.ts

import { useMutation, useQueryClient } from '@tanstack/react-query';
import { salesService } from '../services/sales.service';
import { salesKeys } from '../queries/sales.keys';
import type { SaleDraft, SaleUpdatePayload } from '../types/Sale.types';

export function useCreateSaleMutation() {
  const queryClient = useQueryClient();
  return useMutation({
    mutationFn: (payload: SaleDraft) => salesService.create(payload),
    onSuccess:  () => queryClient.invalidateQueries({ queryKey: salesKeys.lists() }),
  });
}

export function useUpdateSaleMutation() {
  const queryClient = useQueryClient();
  return useMutation({
    mutationFn: (payload: SaleUpdatePayload) => salesService.update(payload),
    onSuccess:  (updated) => {
      queryClient.invalidateQueries({ queryKey: salesKeys.lists() });
      queryClient.setQueryData(salesKeys.detail(updated.id), updated);
    },
  });
}

export function useDeleteSaleMutation() {
  const queryClient = useQueryClient();
  return useMutation({
    mutationFn: (id: string) => salesService.delete(id),
    onSuccess:  (_data, id) => {
      queryClient.invalidateQueries({ queryKey: salesKeys.lists() });
      queryClient.removeQueries({ queryKey: salesKeys.detail(id) });
    },
  });
}

src/features/sales/hooks/useSales.ts

import { useQuery } from '@tanstack/react-query';
import { salesListQueryOptions } from '../queries/sales.queries';
import type { SaleFilters } from '../types/Sale.types';

export function useSales(filters?: SaleFilters) {
  return useQuery(salesListQueryOptions(filters));
}

src/features/sales/hooks/useSale.ts

import { useQuery } from '@tanstack/react-query';
import { salesDetailQueryOptions } from '../queries/sales.queries';

export function useSale(id: string) {
  return useQuery(salesDetailQueryOptions(id));
}

src/features/sales/index.ts

// Types
export type { Sale, SaleDraft, SaleUpdatePayload, SaleFilters, SalesResponse } from './types/Sale.types';

// Hooks (primary interface for components)
export { useSales } from './hooks/useSales';
export { useSale }  from './hooks/useSale';

// Mutations
export { useCreateSaleMutation, useUpdateSaleMutation, useDeleteSaleMutation } from './mutations/sales.mutations';

// Query options (for server-side prefetching)
export { salesListQueryOptions, salesDetailQueryOptions } from './queries/sales.queries';

// Query keys (for targeted invalidation)
export { salesKeys } from './queries/sales.keys';

Component usage (zero boilerplate):

import { useSales, useCreateSaleMutation } from '@/features/sales';

export function SalesTable() {
  const { data, isLoading } = useSales({ page: 1, pageSize: 20 });
  const createSale = useCreateSaleMutation();

  if (isLoading) return <Spinner />;

  return (
    <>
      {data?.data.map(sale => <SaleRow key={sale.id} sale={sale} />)}
      <button onClick={() => createSale.mutate({ /* draft */ })}>New Sale</button>
    </>
  );
}

zakarya.config.json Reference

{
  "version": "1",
  "api": {
    "baseUrl": "http://localhost:3001/api",   // Written to shared/api/client.ts
    "timeout": 10000,                          // Axios timeout (ms)
    "withAuth": true                           // Include auth interceptor
  },
  "query": {
    "staleTime": 60000,                        // Default query staleTime (ms)
    "gcTime": 300000,                          // Default garbage collection time
    "retry": 1,                                // Retry count (false to disable)
    "refetchOnWindowFocus": false              // Global refetch on focus
  },
  "folders": {
    "srcDir": "src",                           // Source root
    "featuresDir": "features",                 // Features directory name
    "sharedDir": "shared"                      // Shared directory name
  },
  "features": {
    "zustand": false,          // Include Zustand
    "zod": true,               // Include Zod schemas
    "reactHookForm": true,     // Include React Hook Form
    "i18n": false,             // Include i18n setup
    "storybook": false,        // Include Storybook
    "playwright": false,       // Include Playwright e2e
    "vitest": true             // Include Vitest unit tests
  },
  "plugins": [
    { "name": "auth" },
    { "name": "payments", "options": { "provider": "stripe" } }
  ]
}

Plugin System

Plugins extend zakarya without touching core.

Plugin Contract

export interface ZakaryaPlugin {
  name: string;
  version: string;
  setup(ctx: PluginContext): void | Promise<void>;
  hooks?: {
    beforeProjectCreated?(ctx: PluginContext): Promise<void>;
    afterProjectCreated?(ctx: PluginContext): Promise<void>;
    beforeFeatureGenerated?(featureName: string, ctx: PluginContext): Promise<void>;
    afterFeatureGenerated?(featureName: string, ctx: PluginContext): Promise<void>;
  };
}

Writing a Plugin

// zakarya-plugin-auth/index.ts
import type { ZakaryaPlugin, PluginContext } from 'zakarya/plugin';

const authPlugin: ZakaryaPlugin = {
  name: 'auth',
  version: '1.0.0',

  async setup(ctx: PluginContext) {
    ctx.log('Setting up auth plugin...');

    // Register a custom generator command
    ctx.registerGenerator('login-flow', {
      description: 'Generates complete login form + auth feature',
      async generate(opts) {
        // Generation logic here
      },
    });
  },

  hooks: {
    async afterProjectCreated(ctx) {
      // Auto-generate auth feature after project creation
      ctx.log('Auto-generating auth feature...');
    },
  },
};

export default authPlugin;

Plugin Discovery Chain

1. ./zakarya-plugins/<n>/index.ts    ← local monorepo plugin
2. node_modules/zakarya-plugin-<n>   ← npm package
3. node_modules/@zakarya/<n>         ← scoped npm package

Usage

zakarya create my-app --plugins auth,payments

Safety System

Every destructive operation is guarded:

SafetySystem
├── backup(filePath)           → creates file.ts.1234567890.zakarya-backup
├── confirm(message)           → interactive y/n prompt
├── safeWrite(path, content)   → ask before overwrite + auto-backup
└── cleanupBackups(rootDir)    → removes all .zakarya-backup files after successful run

All backups are cleaned up after a successful generation. On failure, backups remain so you can restore.


Naming Convention Engine

Strict, automatic, consistent — no manual naming decisions needed.

| Input | camel | pascal | kebab | snake | screamingSnake | |-------|-------|--------|-------|-------|----------------| | sales | sales | Sales | sales | sales | SALES | | salesOrder | salesOrder | SalesOrder | sales-order | sales_order | SALES_ORDER | | invoice-item | invoiceItem | InvoiceItem | invoice-item | invoice_item | INVOICE_ITEM | | product_category | productCategory | ProductCategory | product-category | product_category | PRODUCT_CATEGORY |


Dependency Rules

┌─────────────────────────────────┐
│           Components            │  import from hooks/ only
├─────────────────────────────────┤
│             Hooks               │  import from queries/ + mutations/
├─────────────────────────────────┤
│      Queries / Mutations        │  import from services/ + keys/
├─────────────────────────────────┤
│            Services             │  import from shared/api ONLY
├─────────────────────────────────┤
│          shared/api             │  no feature imports
│          shared/errors          │
│          shared/tanstack        │
└─────────────────────────────────┘

FORBIDDEN:
  features/sales → features/products   ✖
  shared/api     → features/sales      ✖
  services/      → hooks/              ✖

Evolution Roadmap

v1.1 — Generator Completions

  • zakarya generate component <Feature> <ComponentName>
  • zakarya generate schema <n> (Zod schema generator)
  • zakarya generate store <n> (Zustand store generator)

v1.2 — API Contract Sync

  • zakarya sync --openapi ./openapi.json
  • Auto-generate types and services from OpenAPI/Swagger spec
  • Validate existing types against updated spec

v1.3 — Plugin Ecosystem

  • zakarya-plugin-auth (complete auth flows)
  • zakarya-plugin-payments (Stripe integration)
  • zakarya-plugin-i18n (next-intl setup)
  • zakarya-plugin-storybook (Storybook scaffolding)
  • Plugin registry at registry.zakarya.dev

v2.0 — Multi-Framework Support

  • Config flag: --framework react-vite | --framework next | --framework remix
  • Shared engine, framework-specific adapters
  • Same CLI, multiple output targets

v2.1 — AI-Assisted Generation

  • zakarya generate feature sales --from-description "Sales feature with order tracking, filtering by date and status"
  • LLM generates types based on plain-English descriptions
  • Human reviews generated types → service/queries auto-follow

v3.0 — Full Ecosystem

  • zakarya dev — watches for new files, validates architecture in real-time
  • zakarya migrate — upgrades generated code between zakarya versions
  • VS Code extension for inline architecture validation
  • CI/CD integration: zakarya doctor --ci (exits 1 on violations)