Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions .eslintrc.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
module.exports = {
root: true,
env: {
es2022: true,
node: true,
},
parser: '@typescript-eslint/parser',
parserOptions: {
ecmaVersion: 'latest',
sourceType: 'module',
},
plugins: ['@typescript-eslint'],
extends: ['prettier'],
ignorePatterns: [
'dist/',
'node_modules/',
'coverage/',
'reports/',
'.stryker-tmp/',
],
rules: {},
overrides: [
{
files: ['*.mjs'],
parser: 'espree',
},
],
};
78 changes: 78 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
name: CI

on:
workflow_dispatch:
schedule:
- cron: '0 2 * * 1'
pull_request:
push:
branches:
- main
- master

jobs:
verify:
name: Verify on Node ${{ matrix.node-version }}
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
node-version: [16.13.0, 18.x, 20.x]

steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
cache: npm

- name: Install dependencies
run: npm ci

- name: Verify
run: npm run verify

mutation:
name: Mutation tests
runs-on: ubuntu-latest
if: github.event_name == 'workflow_dispatch' || github.event_name == 'schedule'

steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: 20.x
cache: npm

- name: Install dependencies
run: npm ci

- name: Run mutation tests
run: npm run test:mutation

audit:
name: Dependency audit
runs-on: ubuntu-latest
continue-on-error: true

steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: 20.x
cache: npm

- name: Install dependencies
run: npm ci

- name: Audit dependencies
run: npm audit --audit-level=high
7 changes: 5 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,13 @@ node_modules
/dist
.DS_Store
.env
/test
/test-output
/temp
/test-repro
.catpaw
.claude/settings.local.json
chrome-test-1
docs
docs/*
coverage/
.stryker-tmp/
reports/mutation/
51 changes: 51 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# AGENTS.md

This file provides guidance to Codex (Codex.ai/code) when working with code in this repository.

## Project Overview

PinMe is a zero-config CLI tool for deploying static sites to IPFS. Built with TypeScript, bundled with esbuild, published to npm as `pinme`. Users run commands like `pinme upload dist` to deploy frontends.

## Build & Dev

```bash
npm run build # Production build (esbuild → dist/index.js)
npm run dev # Dev build
npm run test # Unit/integration tests (Vitest)
npm run test:cli # Real CLI black-box tests against dist/index.js
npm run verify # Full PR gate: lint, typecheck, tests, build, CLI, pack
npm run test:mutation # Slow mutation tests (manual/nightly)
```

Build uses `build.js` (esbuild), NOT `rollup.config.js` (legacy, unused). esbuild reads `.env` via dotenv at build time and injects env vars as `process.env.*` defines.

The output is a single CJS file at `dist/index.js` with a shebang, used as the `pinme` CLI binary.

## Architecture

- `bin/index.ts` — CLI entry point, uses `commander` to register all commands
- `bin/*.ts` — Individual command implementations (upload, save, create, bind, importCar, exportCar, delete, etc.)
- `bin/utils/` — Shared utilities:
- `config.ts` — `APP_CONFIG` singleton, all API base URLs and tuning knobs from env vars
- `apiClient.ts` — Axios client factory (`createPinmeApiClient`, `createCarApiClient`)
- `pinmeApi.ts` — High-level API wrappers (domain binding, wallet, CAR export, etc.)
- `uploadToIpfs.ts` / `uploadToIpfsSplit.ts` — IPFS upload logic (single file vs chunked)
- `webLogin.ts` — Auth token management (reads from `~/.pinme/`)
- `domainValidator.ts` — Domain name validation and DNS vs subdomain detection
- `cliError.ts` — Structured CLI error types
- `bin/services/uploadService.ts` — Upload orchestration (hash encryption, URL generation)
- `skills/` — Codex skill definitions for this project

## Key Patterns

- Auth: AppKey stored locally at `~/.pinme/`. Auth headers injected via `getAuthHeaders()` in `webLogin.ts`.
- API clients: Always use `createPinmeApiClient()` or `createCarApiClient()` from `apiClient.ts`, never raw axios.
- Token expiry: `pinmeApi.ts` has centralized token-expired detection (`isTokenExpired`) — all API calls should go through wrappers there.
- Config: All env-driven config lives in `APP_CONFIG` (`config.ts`). Don't read `process.env` directly elsewhere.
- The `save` command reads `pinme.toml` from project root for full-stack deploy (frontend + Cloudflare Worker + D1).

## Code Style

- Prettier: single quotes, trailing commas, 80 char width
- TypeScript with `strict: false`, target ESNext, module ESNext
- CLI output uses `chalk` for colors, `ora` for spinners, `inquirer` for prompts, `figlet` for banner
7 changes: 5 additions & 2 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,11 @@ PinMe is a zero-config CLI tool for deploying static sites to IPFS. Built with T

```bash
npm run build # Production build (esbuild → dist/index.js)
npm run dev # Dev build (NODE_ENV=development)
node test/build-env.test.js # Run tests (node:test, no framework)
npm run dev # Dev build
npm run test # Unit/integration tests (Vitest)
npm run test:cli # Real CLI black-box tests against dist/index.js
npm run verify # Full PR gate: lint, typecheck, tests, build, CLI, pack
npm run test:mutation # Slow mutation tests (manual/nightly)
```

Build uses `build.js` (esbuild), NOT `rollup.config.js` (legacy, unused). esbuild reads `.env` via dotenv at build time and injects env vars as `process.env.*` defines.
Expand Down
19 changes: 19 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ Website: [https://pinme.eth.limo/](https://pinme.eth.limo/)
- [Authentication and Account Commands](#authentication-and-account-commands)
- [Static Uploads and IPFS Utilities](#static-uploads-and-ipfs-utilities)
- [Command Reference](#command-reference)
- [Development and Testing](#development-and-testing)
- [Limits and Operational Notes](#limits-and-operational-notes)
- [Examples](#examples)
- [Support](#support)
Expand Down Expand Up @@ -340,6 +341,24 @@ pinme rm <value>
| `pinme list` / `pinme ls` | Show upload history |
| `pinme help` | Show CLI help |

## Development and Testing

PinMe uses Vitest for unit/integration tests, real `dist/index.js` CLI smoke tests, npm package checks, and Stryker for slower mutation testing.

```bash
npm run test # Unit and integration tests
npm run test:coverage # Coverage gate for core modules
npm run test:cli # Real CLI black-box tests
npm run test:pack # npm pack/package-shape checks
npm run verify # Full pull-request gate
npm run test:mutation # Slow mutation tests for manual/nightly runs
```

Tests must not call live PinMe/IPFS/CAR services. Use `nock`, local loopback servers, fixtures, and temporary HOME directories for API and CLI scenarios.

For the full testing policy, layout, and mutation-testing guidance, see
[TESTING.md](TESTING.md).

## Limits and Operational Notes

- Default single-file upload limit: `100MB`
Expand Down
Loading
Loading