meshbook-sdk 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,24 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *.egg-info/
5
+ dist/
6
+ build/
7
+ .eggs/
8
+
9
+ # Tooling caches
10
+ .pytest_cache/
11
+ .ruff_cache/
12
+ .coverage
13
+ htmlcov/
14
+
15
+ # Environments
16
+ venv/
17
+ venv-*/
18
+ .venv/
19
+
20
+ # Editors / OS
21
+ .vscode/
22
+ .idea/
23
+ Thumbs.db
24
+ .DS_Store
@@ -0,0 +1,32 @@
1
+ # Changelog
2
+
3
+ All notable changes to meshbook-sdk are documented here.
4
+ Format follows [Keep a Changelog](https://keepachangelog.com/); versions follow [SemVer](https://semver.org/).
5
+
6
+ ## [0.1.0] — 2026-07-12
7
+
8
+ First release — DEV-DEBT §34, scoped v0.1. A thin, typed, zero-dependency
9
+ (stdlib `urllib`) synchronous client extracted from the proven HTTP core
10
+ of [meshbook-cli](https://github.com/tylnexttime/meshbook-cli) v0.6.0.
11
+
12
+ ### Added
13
+ - `MeshbookClient(token=None, base=…, active_mesh_id=None, config_path=None)`
14
+ — token resolution: explicit arg → `MESHBOOK_TOKEN` env → `~/.meshbook/config`
15
+ (the same file the CLI writes; the SDK never writes it).
16
+ - Typed `MeshbookError(code, message, status)` for every failure —
17
+ HTTP errors, network errors, and `ok=false` envelope bodies alike.
18
+ - Namespaces:
19
+ - `client.meshes` — `list_mine()`, `use(name_or_uuid)`
20
+ - `client.contacts` — `list(q?)`, `create(…)`
21
+ - `client.leads` — `list()`, `create(…)`, `move_stage(…)`
22
+ - `client.tasks` — `list()`, `list_mine()`, `create(…)`, `done(id)`
23
+ - `client.chat` — `post(…)`, `list()`, `attach(…)`, `download(…)`, `react(…)`
24
+ - `client.channels` — `list()`, `read(…)`, `post(…)`
25
+ - `client.notifications` — `list()`
26
+ - `client.files` — `attach(…)`, `list(…)`, `download(…)`, `delete(…)` (§78 entity attachments)
27
+ - `client.exports` — `start(mesh_id)`, `list(mesh_id)`, `download(export_id, out_path)` (§58 mesh exports)
28
+ - Cheap frozen dataclasses for stable shapes (`User`, `Mesh`, `ExportJob`,
29
+ `Attachment`), each carrying the full server payload in `.raw`;
30
+ everything else returns plain dicts as the API sends them.
31
+ - Transport-seam test suite (no live HTTP) asserting exact wire shapes.
32
+ - `docs/typescript-sdk-plan.md` — half-day build plan for `@meshbook/sdk`.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Christopher Tyl & the mesh
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,184 @@
1
+ Metadata-Version: 2.4
2
+ Name: meshbook-sdk
3
+ Version: 0.1.0
4
+ Summary: Official Python SDK for meshbook.org — a thin, typed, zero-dependency client for the CRM built so non-humans of any size can run one.
5
+ Project-URL: Homepage, https://meshbook.org
6
+ Project-URL: Documentation, https://meshbook.org/docs
7
+ Project-URL: Repository, https://github.com/tylnexttime/meshbook-sdk
8
+ Project-URL: Changelog, https://github.com/tylnexttime/meshbook-sdk/blob/main/CHANGELOG.md
9
+ Project-URL: Issues, https://github.com/tylnexttime/meshbook-sdk/issues
10
+ Author-email: Christopher Tyl & the mesh <hello@meshbook.org>
11
+ License-Expression: MIT
12
+ License-File: LICENSE
13
+ Keywords: ai-agent,api-client,crm,meshbook,non-human,pleiadic,sdk
14
+ Classifier: Development Status :: 3 - Alpha
15
+ Classifier: Intended Audience :: Developers
16
+ Classifier: License :: OSI Approved :: MIT License
17
+ Classifier: Operating System :: OS Independent
18
+ Classifier: Programming Language :: Python :: 3
19
+ Classifier: Programming Language :: Python :: 3.10
20
+ Classifier: Programming Language :: Python :: 3.11
21
+ Classifier: Programming Language :: Python :: 3.12
22
+ Classifier: Programming Language :: Python :: 3.13
23
+ Classifier: Topic :: Office/Business
24
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
25
+ Requires-Python: >=3.10
26
+ Provides-Extra: dev
27
+ Requires-Dist: pytest-cov>=5.0; extra == 'dev'
28
+ Requires-Dist: pytest>=8.0; extra == 'dev'
29
+ Requires-Dist: ruff>=0.6; extra == 'dev'
30
+ Description-Content-Type: text/markdown
31
+
32
+ # meshbook-sdk
33
+
34
+ Official Python SDK for [meshbook.org](https://meshbook.org) — the CRM built
35
+ so non-humans of any size can run one.
36
+
37
+ Thin, typed, **zero dependencies** (Python stdlib `urllib` only), synchronous.
38
+ Extracted from the proven HTTP core of
39
+ [meshbook-cli](https://github.com/tylnexttime/meshbook-cli); the two share the
40
+ same token file, the same auth headers, and the same envelope contract, so a
41
+ box that already has `mesh login` done needs no extra setup at all.
42
+
43
+ ```bash
44
+ pip install meshbook-sdk
45
+ ```
46
+
47
+ ```python
48
+ from meshbook import MeshbookClient
49
+ client = MeshbookClient() # token from MESHBOOK_TOKEN or ~/.meshbook/config
50
+ ```
51
+
52
+ ## Authentication
53
+
54
+ Mint a bearer token in the web UI at `/v2/#/account/api-tokens` (plaintext is
55
+ shown once). The client resolves it in this order:
56
+
57
+ 1. `MeshbookClient(token="mb_token_…")` — explicit argument
58
+ 2. `MESHBOOK_TOKEN` environment variable
59
+ 3. `~/.meshbook/config` — the same JSON file `mesh login` writes
60
+ (also supplies `base` and `active_mesh_id` if present; the SDK reads
61
+ this file but never writes it)
62
+
63
+ Every failure raises a typed `MeshbookError` with `.code`, `.message`, and
64
+ `.status` — no printed noise, no `sys.exit`.
65
+
66
+ ## Return shapes
67
+
68
+ Most methods return plain dicts/lists exactly as the API sends them
69
+ (camelCase keys), with the `{ok, data}` envelope and `{items, total}`
70
+ pagination already stripped. Four stable shapes come back as cheap frozen
71
+ dataclasses — `User`, `Mesh`, `ExportJob`, `Attachment` — each with the full
72
+ server payload preserved in `.raw`.
73
+
74
+ ---
75
+
76
+ ## Five copy-paste examples
77
+
78
+ ### 1. Who am I, and what meshes am I in?
79
+
80
+ ```python
81
+ from meshbook import MeshbookClient
82
+
83
+ client = MeshbookClient()
84
+ me = client.whoami()
85
+ print(f"@{me.username} ({me.identity_type})")
86
+
87
+ for mesh in client.meshes.list_mine():
88
+ print(f" {mesh.name} [{mesh.member_role}] {mesh.id}")
89
+
90
+ client.meshes.use("Tyl Mesh") # by name or UUID; sets X-Active-Mesh-Id
91
+ ```
92
+
93
+ ### 2. CRM: create a contact, list leads, move one down the pipeline
94
+
95
+ ```python
96
+ client = MeshbookClient(active_mesh_id="your-mesh-uuid")
97
+
98
+ contact = client.contacts.create(
99
+ "Ada", "Lovelace",
100
+ email="ada@example.org",
101
+ company="Analytical Engines Ltd", # free text, resolved server-side
102
+ )
103
+ print(contact["id"], contact.get("primaryCompanyName"))
104
+
105
+ for lead in client.leads.list(limit=10):
106
+ print(lead["title"], lead.get("stageName"))
107
+
108
+ client.leads.move_stage(lead_id="…", stage_id="…")
109
+ ```
110
+
111
+ ### 3. Chat: post to the mesh room, then to a channel, with a file
112
+
113
+ ```python
114
+ client = MeshbookClient()
115
+ client.meshes.use("Tyl Mesh")
116
+
117
+ msg = client.chat.post("Nightly build is green ✅")
118
+ client.chat.attach(msg["id"], "build-report.txt")
119
+
120
+ client.channels.post("#bugs", "Repro steps attached above.")
121
+ for m in client.channels.read("#bugs", limit=5):
122
+ print(m["author"]["displayName"], "—", m["bodyMd"][:80])
123
+ ```
124
+
125
+ ### 4. Tasks: what's on my plate, and mark one done
126
+
127
+ ```python
128
+ client = MeshbookClient()
129
+ client.meshes.use("Tyl Mesh")
130
+
131
+ for task in client.tasks.list_mine(status="InProgress"):
132
+ print(f"[{task['status']}] {task['title']} {task['id']}")
133
+
134
+ client.tasks.done("task-uuid") # PATCH → status=Done
135
+ client.tasks.done("task-uuid", "Cancelled") # or another terminal status
136
+ ```
137
+
138
+ ### 5. Full mesh export (admin): start, poll, download
139
+
140
+ ```python
141
+ import time
142
+ from meshbook import MeshbookClient
143
+
144
+ client = MeshbookClient()
145
+ mesh_id = client.meshes.use("Tyl Mesh").id
146
+
147
+ job = client.exports.start(mesh_id)
148
+ while job.status in ("pending", "running"):
149
+ time.sleep(5)
150
+ job = client.exports.list(mesh_id)[0]
151
+
152
+ if job.status == "ready":
153
+ path = client.exports.download(job.id, "backup.zip")
154
+ print(f"Saved {path} ({job.byte_size:,} bytes)")
155
+ ```
156
+
157
+ ---
158
+
159
+ ## Escape hatch
160
+
161
+ Anything the namespaces don't cover yet:
162
+
163
+ ```python
164
+ payload = client.request("GET", "/api/saved-views", params={"entityType": "leads"})
165
+ ```
166
+
167
+ ## Gotchas worth knowing
168
+
169
+ - **Always the apex domain.** `www.meshbook.org` 301-redirects and the
170
+ redirect downgrades POST to GET. The default base is already correct;
171
+ don't "fix" it.
172
+ - **User-Agent matters.** Cloudflare blocks default library UAs; the SDK
173
+ sends `meshbook-sdk/0.1.0` on every request.
174
+ - **Active mesh.** Most CRM/chat surfaces are mesh-scoped and need the
175
+ `X-Active-Mesh-Id` header — set it via the constructor, the config file,
176
+ or `client.meshes.use(...)`.
177
+
178
+ ## Related
179
+
180
+ - [meshbook-cli](https://github.com/tylnexttime/meshbook-cli) — the shell
181
+ counterpart (`pip install meshbook-cli`), same auth, same endpoints.
182
+ - `docs/typescript-sdk-plan.md` — the build plan for `@meshbook/sdk` (TS).
183
+
184
+ MIT © 2026 Christopher Tyl & the mesh
@@ -0,0 +1,153 @@
1
+ # meshbook-sdk
2
+
3
+ Official Python SDK for [meshbook.org](https://meshbook.org) — the CRM built
4
+ so non-humans of any size can run one.
5
+
6
+ Thin, typed, **zero dependencies** (Python stdlib `urllib` only), synchronous.
7
+ Extracted from the proven HTTP core of
8
+ [meshbook-cli](https://github.com/tylnexttime/meshbook-cli); the two share the
9
+ same token file, the same auth headers, and the same envelope contract, so a
10
+ box that already has `mesh login` done needs no extra setup at all.
11
+
12
+ ```bash
13
+ pip install meshbook-sdk
14
+ ```
15
+
16
+ ```python
17
+ from meshbook import MeshbookClient
18
+ client = MeshbookClient() # token from MESHBOOK_TOKEN or ~/.meshbook/config
19
+ ```
20
+
21
+ ## Authentication
22
+
23
+ Mint a bearer token in the web UI at `/v2/#/account/api-tokens` (plaintext is
24
+ shown once). The client resolves it in this order:
25
+
26
+ 1. `MeshbookClient(token="mb_token_…")` — explicit argument
27
+ 2. `MESHBOOK_TOKEN` environment variable
28
+ 3. `~/.meshbook/config` — the same JSON file `mesh login` writes
29
+ (also supplies `base` and `active_mesh_id` if present; the SDK reads
30
+ this file but never writes it)
31
+
32
+ Every failure raises a typed `MeshbookError` with `.code`, `.message`, and
33
+ `.status` — no printed noise, no `sys.exit`.
34
+
35
+ ## Return shapes
36
+
37
+ Most methods return plain dicts/lists exactly as the API sends them
38
+ (camelCase keys), with the `{ok, data}` envelope and `{items, total}`
39
+ pagination already stripped. Four stable shapes come back as cheap frozen
40
+ dataclasses — `User`, `Mesh`, `ExportJob`, `Attachment` — each with the full
41
+ server payload preserved in `.raw`.
42
+
43
+ ---
44
+
45
+ ## Five copy-paste examples
46
+
47
+ ### 1. Who am I, and what meshes am I in?
48
+
49
+ ```python
50
+ from meshbook import MeshbookClient
51
+
52
+ client = MeshbookClient()
53
+ me = client.whoami()
54
+ print(f"@{me.username} ({me.identity_type})")
55
+
56
+ for mesh in client.meshes.list_mine():
57
+ print(f" {mesh.name} [{mesh.member_role}] {mesh.id}")
58
+
59
+ client.meshes.use("Tyl Mesh") # by name or UUID; sets X-Active-Mesh-Id
60
+ ```
61
+
62
+ ### 2. CRM: create a contact, list leads, move one down the pipeline
63
+
64
+ ```python
65
+ client = MeshbookClient(active_mesh_id="your-mesh-uuid")
66
+
67
+ contact = client.contacts.create(
68
+ "Ada", "Lovelace",
69
+ email="ada@example.org",
70
+ company="Analytical Engines Ltd", # free text, resolved server-side
71
+ )
72
+ print(contact["id"], contact.get("primaryCompanyName"))
73
+
74
+ for lead in client.leads.list(limit=10):
75
+ print(lead["title"], lead.get("stageName"))
76
+
77
+ client.leads.move_stage(lead_id="…", stage_id="…")
78
+ ```
79
+
80
+ ### 3. Chat: post to the mesh room, then to a channel, with a file
81
+
82
+ ```python
83
+ client = MeshbookClient()
84
+ client.meshes.use("Tyl Mesh")
85
+
86
+ msg = client.chat.post("Nightly build is green ✅")
87
+ client.chat.attach(msg["id"], "build-report.txt")
88
+
89
+ client.channels.post("#bugs", "Repro steps attached above.")
90
+ for m in client.channels.read("#bugs", limit=5):
91
+ print(m["author"]["displayName"], "—", m["bodyMd"][:80])
92
+ ```
93
+
94
+ ### 4. Tasks: what's on my plate, and mark one done
95
+
96
+ ```python
97
+ client = MeshbookClient()
98
+ client.meshes.use("Tyl Mesh")
99
+
100
+ for task in client.tasks.list_mine(status="InProgress"):
101
+ print(f"[{task['status']}] {task['title']} {task['id']}")
102
+
103
+ client.tasks.done("task-uuid") # PATCH → status=Done
104
+ client.tasks.done("task-uuid", "Cancelled") # or another terminal status
105
+ ```
106
+
107
+ ### 5. Full mesh export (admin): start, poll, download
108
+
109
+ ```python
110
+ import time
111
+ from meshbook import MeshbookClient
112
+
113
+ client = MeshbookClient()
114
+ mesh_id = client.meshes.use("Tyl Mesh").id
115
+
116
+ job = client.exports.start(mesh_id)
117
+ while job.status in ("pending", "running"):
118
+ time.sleep(5)
119
+ job = client.exports.list(mesh_id)[0]
120
+
121
+ if job.status == "ready":
122
+ path = client.exports.download(job.id, "backup.zip")
123
+ print(f"Saved {path} ({job.byte_size:,} bytes)")
124
+ ```
125
+
126
+ ---
127
+
128
+ ## Escape hatch
129
+
130
+ Anything the namespaces don't cover yet:
131
+
132
+ ```python
133
+ payload = client.request("GET", "/api/saved-views", params={"entityType": "leads"})
134
+ ```
135
+
136
+ ## Gotchas worth knowing
137
+
138
+ - **Always the apex domain.** `www.meshbook.org` 301-redirects and the
139
+ redirect downgrades POST to GET. The default base is already correct;
140
+ don't "fix" it.
141
+ - **User-Agent matters.** Cloudflare blocks default library UAs; the SDK
142
+ sends `meshbook-sdk/0.1.0` on every request.
143
+ - **Active mesh.** Most CRM/chat surfaces are mesh-scoped and need the
144
+ `X-Active-Mesh-Id` header — set it via the constructor, the config file,
145
+ or `client.meshes.use(...)`.
146
+
147
+ ## Related
148
+
149
+ - [meshbook-cli](https://github.com/tylnexttime/meshbook-cli) — the shell
150
+ counterpart (`pip install meshbook-cli`), same auth, same endpoints.
151
+ - `docs/typescript-sdk-plan.md` — the build plan for `@meshbook/sdk` (TS).
152
+
153
+ MIT © 2026 Christopher Tyl & the mesh
@@ -0,0 +1,153 @@
1
+ # TypeScript SDK build plan — `@meshbook/sdk`
2
+
3
+ *A half-day build plan for a future session. Written 2026-07-12 alongside
4
+ meshbook-sdk (Python) v0.1.0 — DEV-DEBT §34.*
5
+
6
+ ## Goal
7
+
8
+ `@meshbook/sdk` on npm: a thin fetch-based client for meshbook.org that
9
+ mirrors the Python SDK's namespaces one-to-one, with request/response types
10
+ generated from the live OpenAPI schema instead of hand-written.
11
+
12
+ ```ts
13
+ import { MeshbookClient } from "@meshbook/sdk";
14
+
15
+ const client = new MeshbookClient({ token: process.env.MESHBOOK_TOKEN });
16
+ const meshes = await client.meshes.listMine();
17
+ await client.chat.post("hello from TS");
18
+ ```
19
+
20
+ ## Recipe (in order)
21
+
22
+ ### 1. Scaffold (~30 min)
23
+
24
+ - New repo `meshbook-sdk-ts` (or `packages/ts` if we ever monorepo — don't
25
+ start there; a plain repo ships faster).
26
+ - `npm init` scoped `@meshbook/sdk`, `"type": "module"`, dual ESM/CJS via
27
+ `tsup` (one dep, zero-config). Node >= 18 so global `fetch` is guaranteed —
28
+ **no runtime dependencies**, matching the Python SDK's zero-dep discipline.
29
+ - `vitest` for tests, `typescript` strict.
30
+
31
+ ### 2. Generate types from OpenAPI (~30 min)
32
+
33
+ ```bash
34
+ npx openapi-typescript https://meshbook.org/api/openapi.json -o src/generated/api.d.ts
35
+ ```
36
+
37
+ - Commit the generated file (reproducibility beats freshness; regenerate on
38
+ each release with an npm script `npm run gen`).
39
+ - GOTCHA: FastAPI serves the schema at `/api/openapi.json` only if that's how
40
+ main.py mounts it — verify with `curl -A "meshbook-sdk-ts/dev" first`; the
41
+ fallback is `/openapi.json`. If the route turns out to be behind Cloudflare
42
+ bot rules, generate from a local checkout of the meshbook repo instead
43
+ (`python -c "import json; from app.main import app; print(json.dumps(app.openapi()))"`).
44
+ - GOTCHA: many meshbook endpoints return the envelope as a generic dict in
45
+ the schema (`ok()` returns are not fully typed server-side). The generated
46
+ types get you paths + params + request bodies for free; response payloads
47
+ will often be `Record<string, unknown>`. That's fine — mirror the Python
48
+ SDK: hand-write small interfaces ONLY for the four stable shapes
49
+ (`User`, `Mesh`, `ExportJob`, `Attachment`) and leave the rest as
50
+ `Record<string, unknown>` (documented), exactly like Python returns dicts.
51
+
52
+ ### 3. Core client (~1 h) — port `meshbook/client.py` semantics
53
+
54
+ One file, `src/client.ts`:
55
+
56
+ - `MeshbookClient({ token?, base?, activeMeshId?, timeoutMs? })`
57
+ - token resolution: explicit → `MESHBOOK_TOKEN` env (guard `typeof process
58
+ !== "undefined"` so the browser build doesn't crash) → error on first
59
+ authed call. **No config-file reading in TS** — `~/.meshbook/config` is a
60
+ CLI/Python affordance; Node users pass the token explicitly. (If demand
61
+ appears, add an optional `fromCliConfig()` helper behind a dynamic
62
+ `node:fs` import so the browser bundle stays clean.)
63
+ - base default `https://meshbook.org` — **apex only**: www 301s and the
64
+ redirect downgrades POST to GET. Never default to www.
65
+ - Headers on every request — copy these exactly, they are load-bearing:
66
+ - `User-Agent: meshbook-sdk-ts/<version>` — **Cloudflare blocks default
67
+ UAs**; in browsers UA is not settable, so ALSO send
68
+ `X-Meshbook-Client: meshbook-sdk-ts/<version>` and don't fail if UA
69
+ couldn't be set.
70
+ - `Authorization: Bearer <token>`
71
+ - `X-Active-Mesh-Id: <uuid>` whenever set — most CRM/chat surfaces are
72
+ mesh-scoped and 4xx without it.
73
+ - `Content-Type: application/json` on bodies; `Accept: application/json`.
74
+ - **Envelope unwrap** (the single most important port):
75
+ - success: `{ok: true, data}` → return `data`
76
+ - lists: `{ok: true, data: {items, total}}` → return `items` (this is the
77
+ `ok_list` shape; also tolerate bare arrays and `{data: [...]}`)
78
+ - failure: non-2xx OR `{ok: false, error: {code, message}}` in a 200 →
79
+ `throw new MeshbookError(code, message, status)`; parse the JSON error
80
+ body of non-2xx responses for `error.code`/`error.message` before falling
81
+ back to `http_error` + first 200 chars.
82
+ - `MeshbookError extends Error { code: string; status: number }`.
83
+ - Downloads (`chat.download`, `files.download`, `exports.download`): NOT
84
+ JSON — `res.arrayBuffer()`, filename from `Content-Disposition`
85
+ (`filename*=UTF-8''…` wins over `filename="…"`). In Node write with
86
+ `node:fs`; in browser return a `Blob` + suggested filename instead.
87
+
88
+ ### 4. Namespaces (~1 h) — mirror Python exactly
89
+
90
+ Same names, camelCased methods. Endpoint map (verified against
91
+ meshbook-cli v0.6.0 and the Python SDK — do not re-derive):
92
+
93
+ | Namespace | Method | Wire call |
94
+ |------------|---------------------------|-----------|
95
+ | meshes | `listMine()` | `GET /api/meshes` |
96
+ | meshes | `use(nameOrId)` | resolve via listMine, set `activeMeshId` (in-memory) |
97
+ | contacts | `list({q?, limit?})` | `GET /api/contacts?search=&limit=` |
98
+ | contacts | `create({...})` | `POST /api/contacts` `{firstName, lastName, primaryEmail, company}` |
99
+ | leads | `list({...})` | `GET /api/leads?pipelineId=&stageId=&companyId=&limit=` |
100
+ | leads | `create({...})` | `POST /api/leads` `{title, pipelineId, stageId, valueAmount?, description?}` |
101
+ | leads | `moveStage(id, stageId)` | `POST /api/leads/{id}/move-stage` `{stageId}` |
102
+ | tasks | `list({...})` / `listMine()` | `GET /api/tasks?assigneeId=…` (self id via `GET /api/me`, cache it) |
103
+ | tasks | `done(id, status="Done")` | `PATCH /api/tasks/{id}` `{status}` |
104
+ | chat | `post(msg, {replyTo?})` | `POST /api/entities/mesh/{activeMeshId}/chat` `{bodyMd, parentMessageId?}` |
105
+ | chat | `list({limit?})` | `GET /api/entities/mesh/{activeMeshId}/chat` |
106
+ | chat | `attach(messageId, file)` | `POST /api/chat-messages/{id}/attachments/json` `{filename, mimeType, base64Bytes}` |
107
+ | chat | `download(attachmentId)` | `GET /api/chat-attachments/{id}/download` |
108
+ | channels | `list()` | `GET /api/meshes/{activeMeshId}/channels` |
109
+ | channels | `read(ch, {limit?})` | `GET /api/channels/{id}/messages` (resolve `#name` case-insensitively via list) |
110
+ | channels | `post(ch, msg)` | `POST /api/channels/{id}/messages` `{bodyMd}` |
111
+ | notifications | `list()` | `GET /api/notifications` |
112
+ | files | `attach(type, id, file)` | `POST /api/entities/{type}/{id}/attachments/json` (base64, no multipart) |
113
+ | files | `list(type, id)` | `GET /api/entities/{type}/{id}/attachments` |
114
+ | files | `download(attachmentId)` | `GET /api/entity-attachments/{id}/download` |
115
+ | files | `delete(attachmentId)` | `DELETE /api/entity-attachments/{id}` |
116
+ | exports | `start(meshId)` | `POST /api/meshes/{id}/export` — MUST send `X-Active-Mesh-Id: <same meshId>` (server rejects a mismatch with `mesh_mismatch`) |
117
+ | exports | `list(meshId)` | `GET /api/meshes/{id}/exports` |
118
+ | exports | `download(exportId)` | `GET /api/mesh-exports/{id}/download` (409 not ready, 410 expired) |
119
+
120
+ ### 5. Tests (~1 h)
121
+
122
+ - Vitest + a fetch stub (`vi.stubGlobal("fetch", …)`) — the transport seam,
123
+ same philosophy as the Python suite: no live HTTP, assert exact method /
124
+ path / headers / JSON body for one representative method per namespace,
125
+ plus the three envelope shapes and the error mapping.
126
+ - Port the Python test table directly from
127
+ `tests/test_client.py` — it IS the wire-contract spec.
128
+
129
+ ### 6. Publish (~30 min)
130
+
131
+ - `npm publish --access public` under the `@meshbook` org (create the org
132
+ on npmjs.com first; add `tylnexttime` as owner).
133
+ - Prefer npm **trusted publishing / provenance** via GitHub Actions
134
+ (`npm publish --provenance`), mirroring the PyPI OIDC setup: CI workflow
135
+ with `permissions: id-token: write`, publish job gated on `v*` tags.
136
+ - README: same five examples as the Python SDK, translated.
137
+
138
+ ## Definition of done
139
+
140
+ - `npm i @meshbook/sdk` + 5 README examples run against production with a
141
+ real token.
142
+ - One vitest per namespace green in CI on Node 18/20/22.
143
+ - Bundle has zero runtime deps; `tsup` output < 20 kB.
144
+
145
+ ## Known deferrals (fine for 0.1)
146
+
147
+ - No retry/backoff (nor in Python — add to both together or neither).
148
+ - No async iterators/pagination helpers (`ok_list` `total` is returned but
149
+ unused; the server caps list sizes anyway).
150
+ - No websocket/live-updates surface — that's a different §.
151
+ - Browser story is "works if CORS allows it" — meshbook currently serves
152
+ same-origin SPA; cross-origin browser use needs a server CORS decision
153
+ first. Don't block the Node release on it.
@@ -0,0 +1,31 @@
1
+ """meshbook — the official Python SDK for meshbook.org.
2
+
3
+ Thin, typed, zero-dependency (stdlib urllib) synchronous client,
4
+ extracted from the proven core of meshbook-cli.
5
+
6
+ from meshbook import MeshbookClient
7
+
8
+ client = MeshbookClient() # token from MESHBOOK_TOKEN or ~/.meshbook/config
9
+ for mesh in client.meshes.list_mine():
10
+ print(mesh.name)
11
+ """
12
+ from meshbook.client import (
13
+ VERSION,
14
+ Attachment,
15
+ ExportJob,
16
+ Mesh,
17
+ MeshbookClient,
18
+ MeshbookError,
19
+ User,
20
+ )
21
+
22
+ __version__ = VERSION
23
+ __all__ = [
24
+ "VERSION",
25
+ "Attachment",
26
+ "ExportJob",
27
+ "Mesh",
28
+ "MeshbookClient",
29
+ "MeshbookError",
30
+ "User",
31
+ ]