agentsclimarketplace

Maintainx local dev loop

Skill jeremylongshore/claude-code-plugins-plus-skills/plugins/saas-packs/maintainx-pack/skills/maintainx-local-dev-loop

'Set up a local development loop for MaintainX integration development.From its SKILL.md

Install
npx -y skills add jeremylongshore/claude-code-plugins-plus-skills --skill maintainx-local-dev-loop

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

What its file declares

Copied from the file, not written here

The file declares its own license as MIT. That is the author’s claim about this one file, and it is not the same thing as the license GitHub reports for the repository, which is listed with the other numbers below.

SKILL.md

5.9 KB, ~1.4k tokens by cl100k_base, as published. Nobody here has run it

MaintainX Local Dev Loop

Overview

Set up an efficient local development workflow for building and testing MaintainX integrations with hot reload, mock servers, and automated testing.

Prerequisites

  • Completed maintainx-install-auth setup
  • Node.js 18+ installed
  • MAINTAINX_API_KEY environment variable set

Instructions

Step 1: Initialize TypeScript Project

mkdir maintainx-integration && cd maintainx-integration
npm init -y
npm install axios dotenv
npm install -D typescript tsx vitest @types/node
npx tsc --init --target ES2022 --module NodeNext --moduleResolution nodenext --outDir dist

Create tsconfig.json paths:

{
  "compilerOptions": {
    "target": "ES2022",
    "module": "NodeNext",
    "moduleResolution": "nodenext",
    "outDir": "dist",
    "strict": true,
    "esModuleInterop": true
  },
  "include": ["src/**/*"]
}

Step 2: Project Structure

maintainx-integration/
├── src/
│   ├── client.ts          # MaintainX API client (from install-auth)
│   ├── work-orders.ts     # Work order service layer
│   └── sync.ts            # Data sync logic
├── tests/
│   ├── client.test.ts     # Unit tests with mocks
│   └── integration.test.ts # Live API tests
├── .env                   # MAINTAINX_API_KEY=...
├── .env.example           # MAINTAINX_API_KEY=your-key-here
├── package.json
└── tsconfig.json

Step 3: Dev Scripts in package.json

{
  "scripts": {
    "dev": "tsx watch src/index.ts",
    "test": "vitest run",
    "test:watch": "vitest",
    "test:integration": "INTEGRATION=true vitest run tests/integration.test.ts",
    "build": "tsc",
    "repl": "tsx src/repl.ts"
  }
}

Step 4: Write Unit Tests with Mocked API

// tests/client.test.ts
import { describe, it, expect, vi, beforeEach } from 'vitest';
import axios from 'axios';

vi.mock('axios');

describe('MaintainXClient', () => {
  beforeEach(() => {
    vi.resetAllMocks();
    process.env.MAINTAINX_API_KEY = 'test-key-123';
  });

  it('creates a work order', async () => {
    const mockResponse = {
      data: { id: 1, title: 'Test WO', status: 'OPEN' },
    };
    vi.mocked(axios.create).mockReturnValue({
      post: vi.fn().mockResolvedValue(mockResponse),
      interceptors: { response: { use: vi.fn() } },
    } as any);

    const { MaintainXClient } = await import('../src/client');
    const client = new MaintainXClient();
    const result = await client.createWorkOrder({ title: 'Test WO' });

    expect(result.data.title).toBe('Test WO');
    expect(result.data.status).toBe('OPEN');
  });

  it('paginates work orders', async () => {
    const page1 = { data: { workOrders: [{ id: 1 }], cursor: 'abc' } };
    const page2 = { data: { workOrders: [{ id: 2 }], cursor: null } };
    const getMock = vi.fn()
      .mockResolvedValueOnce(page1)
      .mockResolvedValueOnce(page2);

    vi.mocked(axios.create).mockReturnValue({
      get: getMock,
      interceptors: { response: { use: vi.fn() } },
    } as any);

    const { MaintainXClient } = await import('../src/client');
    const client = new MaintainXClient();

    const all = [];
    let cursor: string | undefined;
    do {
      const { data } = await client.getWorkOrders({ cursor });
      all.push(...data.workOrders);
      cursor = data.cursor;
    } while (cursor);

    expect(all).toHaveLength(2);
  });
});

Step 5: Interactive REPL

// src/repl.ts
import * as repl from 'node:repl';
import 'dotenv/config';
import { MaintainXClient } from './client';

const client = new MaintainXClient();
console.log('MaintainX REPL ready. `client` is available.');
console.log('Try: await client.getWorkOrders({ limit: 3 })');

const r = repl.start({ prompt: 'maintainx> ' });
r.context.client = client;
# Start REPL
npm run repl
# maintainx> const { data } = await client.getWorkOrders({ limit: 3 })
# maintainx> data.workOrders.map(wo => wo.title)

Output

  • TypeScript project configured with tsx watch for hot reload
  • Vitest unit tests with mocked MaintainX API responses
  • Interactive REPL for exploring the API
  • .env.example template for team onboarding
  • Dev/test/build scripts in package.json

Error Handling

IssueSolution
MAINTAINX_API_KEY undefinedCopy .env.example to .env and fill in your key
429 Rate Limited during devAdd delays between calls, use mocks for unit tests
TypeScript import errorsEnsure moduleResolution: "nodenext" in tsconfig
tsx not foundInstall with npm i -D tsx

Resources

Next Steps

For SDK patterns and best practices, see maintainx-sdk-patterns.

Examples

Docker-based dev environment:

# Dockerfile.dev
FROM node:20-slim
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
CMD ["npm", "run", "dev"]
# docker-compose.dev.yml
services:
  app:
    build: { dockerfile: Dockerfile.dev }
    env_file: .env
    volumes: ["./src:/app/src"]

Run integration tests against live API:

INTEGRATION=true npm run test:integration

What ships with it: 1 file

8.2 KB alongside SKILL.md

references/

Keep looking

Skills are one crate of 326,144. 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.