JSPM

@zeroin.earth/appwrite-ts

1.0.2
    • ESM via JSPM
    • ES Module Entrypoint
    • Export Map
    • Keywords
    • License
    • Repository URL
    • TypeScript Types
    • README
    • Created
    • Published
    • Downloads 8
    • Score
      100M100P100Q37962F
    • License MIT

    TypeScript Server Plugin + CLI that generates fully typed collections from your Appwrite database schema

    Package Exports

    • @zeroin.earth/appwrite-ts
    • @zeroin.earth/appwrite-ts/plugin

    Readme

    @zeroin.earth/appwrite-ts

    A TypeScript Server Plugin + CLI that generates fully typed collections from your Appwrite database schema. Point it at your appwrite.config.json and get const-typed declarations, then use the exported utility types to build type-safe wrappers for your data layer.

    How It Works

    1. Pull your Appwrite project config using the Appwrite CLI:

      appwrite pull all
      # or just the parts you need:
      appwrite pull collections

      This writes (or updates) appwrite.config.json in your project root, which includes a tables array describing every collection and its columns.

    2. The TSS plugin (or CLI) reads that JSON and generates an appwrite-config.d.ts file with const-typed literal tuples.

    3. You import typeof appwriteConfig and pass it as a Config parameter to the library's utility types — CollectionType, AppwriteDocument, etc. — to get precise, per-collection field types.

    Whenever your Appwrite schema changes, run appwrite pull again. The TSS plugin watches the file and regenerates the declaration automatically; if you're using the CLI, re-run appwrite-ts generate.

    Setup

    bun add @zeroin.earth/appwrite-ts

    Peer dependency: typescript ^5

    TypeScript Server Plugin

    Register the plugin in tsconfig.json so your editor regenerates the declaration file automatically whenever appwrite.config.json changes:

    {
      "compilerOptions": {
        "plugins": [
          {
            "name": "@zeroin.earth/appwrite-ts/plugin",
            "configPath": "./appwrite.config.json",
            "outputPath": "./appwrite-config.d.ts"
          }
        ]
      }
    }
    Option Description Default
    configPath Path to the Appwrite config JSON ./appwrite.config.json
    outputPath Path for the generated .d.ts file ./appwrite-config.d.ts

    VS Code setup: Make sure VS Code is using your workspace TypeScript (not its bundled copy). Add this to .vscode/settings.json:

    {
      "js/ts.tsdk.path": "node_modules/typescript/lib"
    }

    Then select the workspace TypeScript version: open any .ts file, click the TypeScript version in the bottom-right status bar, and choose "Use Workspace Version".

    After initial setup, restart TS Server once (Cmd/Ctrl+Shift+P → "TypeScript: Restart TS Server"). The plugin will then watch for changes automatically — no restart needed after appwrite pull.

    CLI

    You can also generate the declaration file manually or in CI:

    # One-shot generation
    appwrite-ts generate ./appwrite.config.json -o ./appwrite-config.d.ts
    
    # Watch mode — regenerates on every change to the config file
    appwrite-ts watch ./appwrite.config.json -o ./appwrite-config.d.ts

    Exported Types

    CollectionType<Id, Config?>

    Maps a collection $id to an object type of its fields. Pass your literal Config for precise types; omit it for a generic fallback.

    AppwriteDocument<Id, Config?>

    AppwriteMeta & CollectionType<Id, Config> — a fully-typed document including Appwrite system fields.

    AppwriteRow

    AppwriteMeta & { readonly [key: string]: unknown } — an untyped row with an index signature, useful for generic operations like iterating keys or stripping metadata.

    AppwriteMeta

    Appwrite system fields present on every document:

    Field Type
    $id string
    $createdAt string
    $updatedAt string
    $permissions string[]
    $databaseId string
    $tableId string
    $sequence number (optional)

    Column, Table, AppwriteConfig

    Runtime shapes for the config JSON. Used internally by the generator and available for tooling that needs to inspect the schema at runtime.

    Column Type Mapping

    Appwrite column type TypeScript type
    boolean boolean
    integer, double number
    varchar, text, mediumtext, string string
    string with format: "enum" Union of literal element strings
    Any column with array: true T[]
    Any column with required: false T | null

    Usage

    Binding Your Config

    The core pattern: import the generated declaration and pass its type as the Config parameter.

    import type appwriteConfig from './appwrite-config'
    import type { AppwriteDocument, CollectionType } from '@zeroin.earth/appwrite-ts'
    
    // Bind the literal config
    type Config = typeof appwriteConfig
    
    // Extract the union of all collection IDs
    type CollectionId = Config['tables'][number]['$id']
    // → "users" | "posts" | "comments" | ...
    
    // Get precise field types for a specific collection
    type PostFields = CollectionType<'posts', Config>
    // → { title: string; body: string; authorId: string; published: boolean; views: number | null }
    
    // Get a full Appwrite document (system fields + collection fields)
    type PostDoc = AppwriteDocument<'posts', Config>
    // → AppwriteMeta & PostFields

    Building Typed Wrappers

    In practice, you'll want to build a small set of wrapper types in your project that bind Config once and give you convenient aliases for the rest of your codebase. This is where the real value is — you define these once and every data-access function, mapper, and persister gets full type safety for free.

    // types.ts — define once, import everywhere
    import type appwriteConfig from './appwrite-config'
    import type { AppwriteDocument, AppwriteMeta } from '@zeroin.earth/appwrite-ts'
    
    type Config = typeof appwriteConfig
    
    /** Union of all collection $id strings. */
    export type CollectionId = Config['tables'][number]['$id']
    
    /** A fully-typed Appwrite document for a given collection. */
    export type Doc<Id extends CollectionId> = AppwriteDocument<Id, Config>
    
    /** An untyped row with index signature for generic operations (stripping meta, etc). */
    export type UntypedRow = AppwriteMeta & { [key: string]: unknown }

    Now you can use Doc<'posts'>, Doc<'comments'>, etc. throughout your project with zero extra ceremony:

    import type { CollectionId, Doc, UntypedRow } from './types'
    
    // Typed function — knows exactly which fields exist on a post
    function formatPost(doc: Doc<'posts'>): string {
      return `${doc.title} by ${doc.authorId}`  // ← autocomplete + type checking
    }
    
    // Generic function — works with any collection's documents
    function stripMeta(row: UntypedRow): Record<string, unknown> {
      const result: Record<string, unknown> = {}
      for (const [key, value] of Object.entries(row)) {
        if (!key.startsWith('$')) result[key] = value
      }
      return result
    }

    Distinguishing Singletons from Multi-Row Collections

    If your schema has both single-document collections (e.g., user settings, app config) and multi-row collections (e.g., posts, comments), you can encode that distinction:

    type SingletonIds = 'user_settings' | 'app_config'
    
    /** Pulled data shape — singletons are a single doc or undefined, arrays for the rest. */
    export type PulledCollections = {
      [K in CollectionId]: K extends SingletonIds ? Doc<K> | undefined : Doc<K>[]
    }

    This gives you a single type representing an entire pull from Appwrite, with each collection correctly typed as either a document or an array of documents.

    Notes

    • The TSS plugin watches the directory containing appwrite.config.json (not the file itself) so that atomic writes like those from appwrite pull (write tmp → rename) are detected reliably.
    • The plugin uses export = init (CommonJS) as required by the TypeScript Server Plugin API. Your root tsconfig should exclude the plugin's source directory (e.g. packages/*/src) to avoid module format conflicts.
    • Peer dependency: typescript ^5.
    • The CLI uses Commander for argument parsing.

    Development

    bun run build        # Compile with tsc
    bun run dev          # Watch mode
    bun test             # Run tests
    bun run typecheck    # Type-check without emitting
    bun run clean        # Remove dist/