Skip to content
Merged
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
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ using [`@emulators/core`](https://www.npmjs.com/package/@emulators/core).
| `tosspayments` | 4002 | Payment confirm/lookup/cancel, order lookup, checkout simulation, webhooks |
| `firebase` | 4003 | Auth (Identity Toolkit REST), Secure Token, FCM v1 |
| `supabase` | 4004 | GoTrue Auth (signup/token/user), PostgREST table CRUD + filters |
| `linear` | 4005 | Linear GraphQL API (read-only): issues, projects, teams, users, orgs, labels, workflow states, Relay pagination |

## Getting started

Expand Down Expand Up @@ -111,6 +112,7 @@ packages/
toss-payments/ # @pleaseai/emulate-toss-payments
firebase/ # @pleaseai/emulate-firebase
supabase/ # @pleaseai/emulate-supabase
linear/ # @pleaseai/emulate-linear
docs/
EMULATOR-CONVENTIONS.md # guide for adding new emulators
```
Expand Down
17 changes: 17 additions & 0 deletions bun.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions packages/emulate/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
"tosspayments",
"firebase",
"supabase",
"linear",
"oauth",
"testing",
"ci",
Expand Down Expand Up @@ -55,6 +56,7 @@
"@emulators/core": "^0.6.0",
"@pleaseai/emulate-firebase": "workspace:*",
"@pleaseai/emulate-kakao": "workspace:*",
"@pleaseai/emulate-linear": "workspace:*",
"@pleaseai/emulate-naver": "workspace:*",
"@pleaseai/emulate-supabase": "workspace:*",
"@pleaseai/emulate-toss-payments": "workspace:*",
Expand Down
28 changes: 27 additions & 1 deletion packages/emulate/src/registry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export interface ServiceEntry {
initConfig: Record<string, unknown>
}

const SERVICE_NAME_LIST = ['kakao', 'naver', 'tosspayments', 'firebase', 'supabase'] as const
const SERVICE_NAME_LIST = ['kakao', 'naver', 'tosspayments', 'firebase', 'supabase', 'linear'] as const
export type ServiceName = (typeof SERVICE_NAME_LIST)[number]
export const SERVICE_NAMES: readonly ServiceName[] = SERVICE_NAME_LIST

Expand Down Expand Up @@ -173,4 +173,30 @@ export const SERVICE_REGISTRY: Record<ServiceName, ServiceEntry> = {
},
},
},

linear: {
label: 'Linear GraphQL API emulator',
endpoints:
'GraphQL queries for issues, projects, teams, users, organizations, labels, workflow states with Relay-style pagination',
async load() {
const mod = await import('@pleaseai/emulate-linear')
return { plugin: mod.linearPlugin, seedFromConfig: widenSeed(mod.seedFromConfig) }
},
defaultFallback() {
return { login: 'linear-admin', id: 1, scopes: ['read'] }
},
initConfig: {
linear: {
api_keys: ['lin_api_test'],
organizations: [{ id: 'org-1', name: 'My Org' }],
teams: [{ id: 'team-1', name: 'Engineering', key: 'ENG', organization: 'org-1' }],
users: [{ id: 'user-1', name: 'Developer', email: 'dev@example.com', organization: 'org-1' }],
workflow_states: [
{ id: 'ws-1', name: 'Todo', type: 'unstarted', team: 'team-1' },
{ id: 'ws-2', name: 'In Progress', type: 'started', team: 'team-1' },
],
issues: [{ id: 'issue-1', title: 'First issue', team: 'team-1', state: 'ws-1', assignee: 'user-1' }],
},
},
},
}
69 changes: 69 additions & 0 deletions packages/linear/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
# @pleaseai/emulate-linear

Linear GraphQL API emulator for local development and CI.

This package is Phase 1. It includes `POST /graphql`, schema introspection, PAT authentication, read only query resolvers, and Relay style pagination for issues, projects, teams, users, organizations, labels, and workflow states.

Mutations, webhooks, OAuth 2.0, and an inspector UI are follow up work.

## Install

```bash
npm install @pleaseai/emulate-linear
```

Usually you do not install this directly — run it through the `@pleaseai/emulate` CLI.

## Start

```bash
# Through the emulate CLI
npx @pleaseai/emulate --service linear

# From the monorepo (after `bun install && bun run build`)
bun packages/emulate/dist/index.js --service linear
```

A single service starts on the base port (default `4000`); use `-p <port>` to change it.

## Auth

Use the raw Linear PAT header:

```bash
curl http://localhost:4000/graphql \
-H "Authorization: lin_api_test" \
-H "Content-Type: application/json" \
-d '{"query":"{ issues { nodes { id title } } }"}'
```

## Seed Config

```yaml
linear:
api_keys: [lin_api_test]
organizations:
- id: org-1
name: My Org
teams:
- id: team-1
name: Engineering
key: ENG
organization: org-1
workflow_states:
- id: ws-1
name: Todo
type: unstarted
team: team-1
users:
- id: user-1
name: Developer
email: dev@example.com
organization: org-1
issues:
- id: issue-1
title: First issue
team: team-1
state: ws-1
assignee: user-1
```
41 changes: 41 additions & 0 deletions packages/linear/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
{
"name": "@pleaseai/emulate-linear",
"type": "module",
"version": "0.1.0",
"license": "Apache-2.0",
"repository": {
"type": "git",
"url": "https://github.com/pleaseai/emulate.git",
"directory": "packages/linear"
},
"exports": {
".": {
"bun": "./src/index.ts",
"types": "./dist/index.d.ts",
"import": "./dist/index.js"
}
},
"main": "./dist/index.js",
"types": "./dist/index.d.ts",
"publishConfig": {
"access": "public"
},
"files": [
"dist"
],
"scripts": {
"build": "tsup --clean",
"dev": "tsup --watch",
"test": "bun test",
"clean": "rm -rf dist .turbo",
"type-check": "tsgo --noEmit"
},
"dependencies": {
"@emulators/core": "^0.6.0",
"graphql": "^16.13.2"
},
"devDependencies": {
"tsup": "^8",
"typescript": "^6"
}
}
Loading