@ayepi/context 0.3.0

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.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Philip Diffenderfer
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.
package/README.md ADDED
@@ -0,0 +1,44 @@
1
+ # @ayepi/context
2
+
3
+ Pull **ayepi's agent context** — the flat agent-reference docs — into your repo with one command.
4
+
5
+ ayepi ships its LLM/agent docs as flat markdown: an `ayepi.md` index that links to a
6
+ per-package `ayepi-<pkg>.md` reference for each `@ayepi/*` package. Those per-package files
7
+ ship inside each installed package (`node_modules/@ayepi/core/ayepi-core.md`, …), and the
8
+ index links to them as flat siblings (`./ayepi-core.md`). This CLI copies the index plus every
9
+ installed package's doc into one flat folder, so the links actually resolve — on GitHub, in
10
+ your editor, and when you point a coding agent at them.
11
+
12
+ ## Usage
13
+
14
+ ```bash
15
+ npx @ayepi/context # → ./docs
16
+ npx @ayepi/context .claude # → any target directory
17
+ npx @ayepi/context docs --prune # de-link index rows for packages you didn't install
18
+ ```
19
+
20
+ Run it from your project root (wherever `node_modules/` lives). Re-run after adding or
21
+ upgrading `@ayepi/*` packages to resync. To wire it into your project:
22
+
23
+ ```jsonc
24
+ // package.json
25
+ "scripts": { "context:sync": "ayepi-context" }
26
+ ```
27
+
28
+ ## What it does
29
+
30
+ 1. Writes the `ayepi.md` index (bundled in this package) to the target folder.
31
+ 2. Scans `node_modules/@ayepi/*` (and pnpm's virtual store) for `ayepi-*.md` files and copies
32
+ each, flat, into the same folder. Deduped by filename; direct dependencies win.
33
+
34
+ Only files are copied — nothing is deleted from the target. With `--prune`, index links whose
35
+ package isn't installed are de-linked (the label stays, the dead link is removed) so you don't
36
+ ship broken links for docs you don't have.
37
+
38
+ ## Options
39
+
40
+ | Arg | Meaning |
41
+ | --- | --- |
42
+ | `[target-dir]` | Where to write the flat docs. Default: `docs`. |
43
+ | `--prune` | De-link index entries for packages not present in `node_modules`. |
44
+ | `--help` | Show usage. |
package/ayepi.md ADDED
@@ -0,0 +1,123 @@
1
+ <!--
2
+ ayepi.md — START HERE. The index / router for the ayepi agent-reference docs.
3
+
4
+ This file explains what ayepi is, the mental model every other doc assumes, and — for whatever
5
+ you're trying to do — which per-package `ayepi-<pkg>.md` reference to open. The `ayepi-*.md` files
6
+ are written to sit **flat** alongside this one, so the `./ayepi-core.md`-style links below resolve.
7
+
8
+ To get that flat layout in your repo, run `npx @ayepi/context` from your project root: it copies this
9
+ index plus every installed `@ayepi/*` package's `ayepi-*.md` into `./docs` (pass another dir, e.g.
10
+ `npx @ayepi/context .claude`; add `--prune` to de-link packages you didn't install). Then point your
11
+ agents/slash commands at it, and re-run after upgrading to keep the docs in sync. (In THIS repo the
12
+ per-package files live nested under `packages/<pkg>/`, so the links below only resolve once
13
+ flattened.)
14
+ -->
15
+
16
+ # ayepi — agent guide
17
+
18
+ **ayepi is a zod-first, fetch-native HTTP + WebSocket API library.** You declare endpoints and
19
+ events once with [zod v4](https://zod.dev) schemas, and from that single source of truth you get a
20
+ typed server, a typed client, OpenAPI 3.1 + AsyncAPI 3.0 docs, and a zod-free runtime manifest the
21
+ browser uses without shipping your schemas. The core is web-standard (`Request`/`Response`/streams),
22
+ so HTTP runs on Node, Bun, Deno, Cloudflare Workers, and Lambda; only WebSocket needs a per-runtime
23
+ adapter. A suite of companion packages (auth, rate, cache, logging, observability, a work engine,
24
+ file storage, plugins, …) builds on the same primitives.
25
+
26
+ ## Mental model (what every doc assumes)
27
+
28
+ ```ts
29
+ const api = spec({ endpoints: { … }, events: { … } }) // zod schemas = the contract
30
+ const impl = implement(api).middleware(def, fn).handlers({ … }) // bind middleware impls + handlers
31
+ const app = server(api, [impl], { broker, cors, docs }) // app.fetch(Request) => Response
32
+ const sdk = client<typeof api>({ baseUrl, manifest, ws }) // typed client; manifest is zod-free
33
+ ```
34
+
35
+ Cross-cutting conventions, true across the whole library:
36
+
37
+ - **One `data` payload.** An endpoint's path params, query, body, and files merge losslessly into a
38
+ single typed `data` object (both directions); kinds are provably disjoint.
39
+ - **HTTP _and_ WebSocket.** Eligible endpoints are callable over either transport; typed item
40
+ streams ride both. Same `io` shape on both sides.
41
+ - **def/impl split.** A middleware (auth, rate, cache, otel, log, …) is a frontend-safe **def** that
42
+ lives in the spec (contributed context + docs, no secrets), and a server-bound **impl**
43
+ (`def.server(...)` / `implement(api).middleware(def, fn)`) that carries the behavior. Specs stay
44
+ shippable to the browser.
45
+ - **Ports, not vendors.** Multi-instance event fanout goes through a `Broker`; concurrency through a
46
+ `Doer`; background work through `Queue`/`Store`/`PubSub`. Swap the in-process default for Redis/SQS
47
+ with no logic change.
48
+ - **zod-free client.** The `@ayepi/core/client` entry ships no zod; the client needs only the
49
+ manifest (a plain routing table). Validation is opt-in.
50
+ - **No `any`** in the public surface; precise inference everywhere a consumer's editor can see.
51
+
52
+ ## Which doc do I open?
53
+
54
+ ### Foundation — almost always start here
55
+ | Doc | Open it when you need to… |
56
+ | --- | --- |
57
+ | [`./ayepi-core.md`](./ayepi-core.md) | define endpoints/events, implement handlers, `server()`, the typed client, OpenAPI/AsyncAPI, the manifest, the `Broker`, streaming, errors, multi-status. |
58
+ | [`./ayepi-core-endpoints.md`](./ayepi-core-endpoints.md) | the details of `endpoint()`, typed `path` templates, the merged `data` kinds (path/query/body/files), raw byte + typed item streaming, SSE, Range/`HEAD`. |
59
+ | [`./ayepi-core-middleware.md`](./ayepi-core-middleware.md) | author middleware: `middleware()` defs, `requires`/`provides`/loaders, `use()`/`.group()`/`.endpoint()`, the `io` object, short-circuiting with a `Response`. |
60
+ | [`./ayepi-core-types.md`](./ayepi-core-types.md) | understand or extend the precise generic/type surface (inference helpers, type-level behavior). |
61
+ | [`./ayepi-core-client.md`](./ayepi-core-client.md) | the zod-free client entry: `sdk.call`/`on`/`url`, the manifest, and resilient `wsTransport`. |
62
+
63
+ ### Run it on a runtime
64
+ | Doc | Open it when you need to… |
65
+ | --- | --- |
66
+ | [`./ayepi-node.md`](./ayepi-node.md) | serve on **Node** (`node:http` + `ws`): `serve()`, mounting on an existing server, client-disconnect → handler `signal`. |
67
+ | [`./ayepi-bun.md`](./ayepi-bun.md) | serve on **Bun** (native fetch + WebSocket, zero deps). |
68
+ | [`./ayepi-deno.md`](./ayepi-deno.md) | serve on **Deno** (native fetch + `Deno.upgradeWebSocket`). |
69
+
70
+ > **Cloudflare Workers / edge** need no adapter for HTTP — `export default { fetch: app.fetch }`. See
71
+ > `./ayepi-core.md` (and the `Broker` for cross-instance WS fanout).
72
+
73
+ ### Middleware & cross-cutting concerns
74
+ | Doc | Open it when you need to… |
75
+ | --- | --- |
76
+ | [`./ayepi-auth.md`](./ayepi-auth.md) | add **Bearer (JWT)** or **Basic** auth; or the standalone `signJwt`/`verifyJwt` crypto. |
77
+ | [`./ayepi-rate.md`](./ayepi-rate.md) · [`./ayepi-rate-stores-doer.md`](./ayepi-rate-stores-doer.md) | **rate-limit** requests (pluggable stores, multiple algorithms) or build a rate-limited `Doer`. |
78
+ | [`./ayepi-cache.md`](./ayepi-cache.md) | **cache responses** (ttl + stale-while-revalidate, per-request `vary`, LRU by bytes/entries). |
79
+ | [`./ayepi-log.md`](./ayepi-log.md) · [`-middleware`](./ayepi-log-middleware.md) · [`-transports`](./ayepi-log-transports.md) · [`-errors-console`](./ayepi-log-errors-console.md) | **structured logging** with `logWith` trace context, redaction/truncation (`sanitize`), `logMaybe`/`toLOG`, console/file transports, console interception. |
80
+ | [`./ayepi-otel.md`](./ayepi-otel.md) | **observability** middleware: request/response logging + trace-context enrichment (works over HTTP and ws). |
81
+
82
+ ### Background work, files, and production backends
83
+ | Doc | Open it when you need to… |
84
+ | --- | --- |
85
+ | [`./ayepi-work.md`](./ayepi-work.md) · [`-ports`](./ayepi-work-ports.md) · [`-deps-schedule`](./ayepi-work-deps-schedule.md) | a typed **work/job engine**: retries, dependencies, scheduling, batching, distributed waits. The `Queue`/`Store`/`PubSub` ports + the bundled in-memory (optionally **file-backed/durable**) backend. |
86
+ | [`./ayepi-files.md`](./ayepi-files.md) | an **S3-like, stream-first file store** with prefix listing + presigned upload/download URLs (filesystem impl + `mountFiles`). |
87
+ | [`./ayepi-redis.md`](./ayepi-redis.md) | **Redis** backends: pub/sub `Broker` (multi-pod fanout) + a `@ayepi/work` `Store`/`PubSub` + a cache store. |
88
+ | [`./ayepi-aws.md`](./ayepi-aws.md) | **AWS** backends: an **SQS** work queue (large payloads offloaded to **S3**) + an **S3** file store/presigner. |
89
+
90
+ ### Tooling & composition
91
+ | Doc | Open it when you need to… |
92
+ | --- | --- |
93
+ | [`./ayepi-mcp.md`](./ayepi-mcp.md) | expose a spec as schema-validated **[MCP](https://modelcontextprotocol.io) tools** executed against your app. |
94
+ | [`./ayepi-mock.md`](./ayepi-mock.md) | stand up a **mock server** that returns schema-valid fake data (deterministic seeding, auto pagination). |
95
+ | [`./ayepi-codec.md`](./ayepi-codec.md) | round-trip rich values (`Date`/`BigInt`/`Map`/`Set`/`Error`/custom) through JSON. |
96
+ | [`./ayepi-updown.md`](./ayepi-updown.md) | orchestrate **graceful startup/shutdown** with dependencies + liveness/readiness probes. |
97
+ | [`./ayepi-plugin.md`](./ayepi-plugin.md) | compose an API from independent **plugins** and **install/uninstall** them into a running server. |
98
+ | [`./ayepi-stress.md`](./ayepi-stress.md) | **load/stress-test** an app: archetype workloads (noop/io/net/cpu), a closed-loop generator, breaking-point search, and server-side instrumentation (event-loop lag, memory, in-flight). |
99
+
100
+ ## Task → doc cheatsheet
101
+
102
+ - **Define an API / add an endpoint or event** → `./ayepi-core.md` (+ `-endpoints` for `data`/streaming).
103
+ - **Write or compose middleware** → `./ayepi-core-middleware.md`.
104
+ - **Add authentication** → `./ayepi-auth.md`.
105
+ - **Rate-limit or cache** → `./ayepi-rate.md` / `./ayepi-cache.md`.
106
+ - **Log with request-scoped context** → `./ayepi-log.md` (+ `./ayepi-otel.md` for request logging).
107
+ - **Emit events to clients across multiple instances** → core `Broker` + `./ayepi-redis.md`.
108
+ - **Run background jobs / a durable queue** → `./ayepi-work.md` (prod backends: `./ayepi-redis.md`, `./ayepi-aws.md`).
109
+ - **Store & serve files** → `./ayepi-files.md` (S3: `./ayepi-aws.md`).
110
+ - **Deploy** → `./ayepi-node.md` / `./ayepi-bun.md` / `./ayepi-deno.md` (Workers/edge: `./ayepi-core.md`).
111
+ - **Expose as MCP tools / mock the API** → `./ayepi-mcp.md` / `./ayepi-mock.md`.
112
+ - **Graceful shutdown / health probes** → `./ayepi-updown.md` (flush logs via `logger.close()`).
113
+ - **Build a modular, hot-pluggable app** → `./ayepi-plugin.md`.
114
+ - **Find the breaking point / load-test / harden under load** → `./ayepi-stress.md`.
115
+
116
+ ## In this repository
117
+
118
+ - Each package also has a human `README.md`; the root [`README.md`](./README.md) has the full
119
+ feature tour, the package table, and the wire protocol.
120
+ - Runnable example apps live in [`examples/`](./examples) (each is three files: shared spec, Node
121
+ server, single-file Vue client), ramping from hello-world up through auth/work/cache/files.
122
+ - When a doc and the code disagree, the code wins — read the package `src/` (every export carries
123
+ TSDoc) and its tests.
@@ -0,0 +1,107 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * ayepi-context — flatten the ayepi agent-reference docs into your repo.
4
+ *
5
+ * The per-package `ayepi-<pkg>.md` files ship flat in each package root
6
+ * (`node_modules/@ayepi/<pkg>/ayepi-<pkg>.md`), and the `ayepi.md` index links to them
7
+ * as flat siblings (`./ayepi-core.md`). This copies the index (bundled in this package)
8
+ * plus every installed package's doc(s) into one flat folder, so the links resolve — on
9
+ * GitHub, in your editor, and when handed to a coding agent.
10
+ *
11
+ * npx @ayepi/context # → ./docs
12
+ * npx @ayepi/context .claude # → ./.claude
13
+ * npx @ayepi/context docs --prune # de-link index entries for packages you didn't install
14
+ *
15
+ * Re-run after upgrading/adding @ayepi packages to resync.
16
+ */
17
+ import { readdirSync, mkdirSync, copyFileSync, existsSync, readFileSync, writeFileSync, statSync } from 'node:fs';
18
+ import { join, dirname } from 'node:path';
19
+ import { fileURLToPath } from 'node:url';
20
+
21
+ const args = process.argv.slice(2);
22
+ if (args.includes('--help') || args.includes('-h')) {
23
+ console.log(`Usage: ayepi-context [target-dir] [--prune]
24
+
25
+ target-dir where to write the flat docs (default: docs)
26
+ --prune de-link index entries whose package isn't installed
27
+ `);
28
+ process.exit(0);
29
+ }
30
+
31
+ const prune = args.includes('--prune');
32
+ const target = args.find((a) => !a.startsWith('-')) ?? 'docs';
33
+ const here = dirname(fileURLToPath(import.meta.url));
34
+ const DOC_RE = /^ayepi-.*\.md$/;
35
+
36
+ /** The canonical index: shipped inside this package, or the repo root when run from source. */
37
+ function resolveIndex() {
38
+ const candidates = [
39
+ join(here, '..', 'ayepi.md'), // published layout: packages/context/ayepi.md
40
+ join(here, '..', '..', '..', 'ayepi.md'), // source layout: repo root
41
+ ];
42
+ return candidates.find((p) => existsSync(p));
43
+ }
44
+
45
+ /** Directories that may contain an installed @ayepi package. Direct deps first (they win on dedup). */
46
+ function scopeDirs() {
47
+ const dirs = [];
48
+ const scope = join('node_modules', '@ayepi');
49
+ if (existsSync(scope)) {
50
+ for (const name of readdirSync(scope)) dirs.push(join(scope, name));
51
+ }
52
+ // pnpm keeps transitive @ayepi deps only under the virtual store.
53
+ const store = join('node_modules', '.pnpm');
54
+ if (existsSync(store)) {
55
+ for (const entry of readdirSync(store)) {
56
+ const nested = join(store, entry, 'node_modules', '@ayepi');
57
+ if (existsSync(nested)) {
58
+ for (const name of readdirSync(nested)) dirs.push(join(nested, name));
59
+ }
60
+ }
61
+ }
62
+ return dirs;
63
+ }
64
+
65
+ const index = resolveIndex();
66
+ if (!index) {
67
+ console.error('ayepi-context: could not locate the bundled ayepi.md index.');
68
+ process.exit(1);
69
+ }
70
+
71
+ // Collect flat docs, deduped by filename (first occurrence — i.e. a direct dep — wins).
72
+ const found = new Map(); // filename -> absolute source path
73
+ for (const dir of scopeDirs()) {
74
+ let files;
75
+ try {
76
+ if (!statSync(dir).isDirectory()) continue;
77
+ files = readdirSync(dir);
78
+ } catch {
79
+ continue;
80
+ }
81
+ for (const f of files) {
82
+ if (DOC_RE.test(f) && !found.has(f)) found.set(f, join(dir, f));
83
+ }
84
+ }
85
+
86
+ mkdirSync(target, { recursive: true });
87
+
88
+ // Write the index — optionally de-linking references to docs we didn't copy.
89
+ let indexText = readFileSync(index, 'utf8');
90
+ let prunedCount = 0;
91
+ if (prune) {
92
+ indexText = indexText.replace(/\[([^\]]+)\]\(\.\/(ayepi-[^)]+\.md)\)/g, (match, label, file) => {
93
+ if (found.has(file)) return match;
94
+ prunedCount++;
95
+ return label; // keep the human-readable label, drop the dead link
96
+ });
97
+ }
98
+ writeFileSync(join(target, 'ayepi.md'), indexText);
99
+
100
+ for (const [name, src] of found) copyFileSync(src, join(target, name));
101
+
102
+ if (found.size === 0) {
103
+ console.warn(`ayepi-docs: no @ayepi/* packages found under node_modules — copied ayepi.md only.`);
104
+ } else {
105
+ console.log(`ayepi-context: synced ayepi.md + ${found.size} package doc(s) → ${target}/`);
106
+ }
107
+ if (prune && prunedCount) console.log(`ayepi-context: de-linked ${prunedCount} index entr${prunedCount === 1 ? 'y' : 'ies'} for uninstalled packages.`);
package/package.json ADDED
@@ -0,0 +1,45 @@
1
+ {
2
+ "name": "@ayepi/context",
3
+ "version": "0.3.0",
4
+ "description": "Pull ayepi's agent context into your repo — flatten ayepi.md + every installed @ayepi/* package's ayepi-*.md into one folder to point a coding agent at.",
5
+ "license": "MIT",
6
+ "publishConfig": {
7
+ "access": "public"
8
+ },
9
+ "repository": {
10
+ "type": "git",
11
+ "url": "git+https://github.com/ClickerMonkey/ayepi.git",
12
+ "directory": "packages/context"
13
+ },
14
+ "homepage": "https://github.com/ClickerMonkey/ayepi/tree/main/packages/context#readme",
15
+ "bugs": {
16
+ "url": "https://github.com/ClickerMonkey/ayepi/issues"
17
+ },
18
+ "type": "module",
19
+ "bin": {
20
+ "ayepi-context": "bin/ayepi-context.mjs"
21
+ },
22
+ "files": [
23
+ "bin",
24
+ "ayepi.md"
25
+ ],
26
+ "engines": {
27
+ "node": ">=18"
28
+ },
29
+ "devDependencies": {
30
+ "publint": "^0.3.0"
31
+ },
32
+ "keywords": [
33
+ "ayepi",
34
+ "context",
35
+ "docs",
36
+ "llm",
37
+ "agent",
38
+ "reference",
39
+ "cli"
40
+ ],
41
+ "scripts": {
42
+ "build": "node scripts/bundle-index.mjs",
43
+ "publint": "publint"
44
+ }
45
+ }