@guuey/state 0.1.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.
@@ -0,0 +1,217 @@
1
+ /**
2
+ * Public types for `@guuey/state`.
3
+ *
4
+ * The library is intentionally narrow — it's a KV scoped per
5
+ * `(user, mcp)`, not a database. See `docs/principles/mcp-hosting-policy.md`
6
+ * for the rationale: scoped primitives let MCPs hold light state
7
+ * (idempotency, counters, small per-user prefs) without making guuey
8
+ * a backend-as-a-service. Hard caps are the product.
9
+ */
10
+ /**
11
+ * Bundle of identifiers that scopes every operation to one
12
+ * `(user, mcp)` namespace. The library never reads these from
13
+ * env or globals at call time; consumers either pass them
14
+ * explicitly to `createGuueyState` or set them via
15
+ * `withGuueyContext` (see `./context`).
16
+ *
17
+ * `userId` is the end-user's guuey identity (Cognito sub, or the
18
+ * platform-derived id for BYO-auth users). `mcpId` is the MCP
19
+ * server's stable identifier (the deploy's app id).
20
+ *
21
+ * **Trust model (spec §3):** the hosted CLIENT binding (`HttpKv`)
22
+ * and the server (`stateApi`, the actual verifier) both ship. The
23
+ * server authenticates the federation-minted Bearer JWT and
24
+ * derives `userId` (the `sub` claim) + `mcpId` (hash of the
25
+ * canonicalized `aud` URL, see `mcpIdFromResourceUrl`)
26
+ * AUTHORITATIVELY server-side — the `context` this package puts on
27
+ * the wire is advisory-must-match, never trusted on its own. An MCP
28
+ * can only present tokens guuey itself issued it, so a compromised
29
+ * MCP's blast radius is its own app's scopes, across its own calling
30
+ * users — never another app's. Tokens minted for guest sessions
31
+ * (`issuerAuthMode: 'anonymous'`) are rejected: guests get no
32
+ * durable scope (mirrors the GuueyFS rule). `ScopeContext` itself
33
+ * stays caller-asserted at the type level — `scopeFromAuthorization`
34
+ * decodes without verifying, same as the in-memory binding always
35
+ * has; verification is the server's job, not this package's.
36
+ */
37
+ export interface ScopeContext {
38
+ readonly userId: string;
39
+ readonly mcpId: string;
40
+ /**
41
+ * The inbound Bearer JWT guuey sent this MCP server (hosted binding
42
+ * only; in-memory ignores it). Obtain via `scopeFromAuthorization`.
43
+ */
44
+ readonly token?: string;
45
+ }
46
+ /**
47
+ * Per-operation options for `set`. TTL is REQUIRED at the type
48
+ * level — there is no "permanent" key in guuey-scoped KV. If
49
+ * the dev wants persistence, they pick a long TTL explicitly.
50
+ * Keeps the platform's storage costs bounded and forces the
51
+ * dev to think about expiry.
52
+ *
53
+ * `ttl` is in seconds. Hard cap: 90 days (60 * 60 * 24 * 90).
54
+ * Longer-lived data should live in the user's own SaaS via
55
+ * mcp-proxy credential brokering — that pattern is preferred
56
+ * for any "meaningful user data" anyway (best privacy posture).
57
+ */
58
+ export interface SetOptions {
59
+ /** TTL in seconds. Max 90 days. */
60
+ readonly ttl: number;
61
+ }
62
+ /**
63
+ * Per-key counter options. Atomic increment is the one
64
+ * "transaction-like" operation the API offers — no MULTI/EXEC,
65
+ * no CAS on arbitrary values. Counters cover the common case
66
+ * (rate limits, generated-id sequences) without opening the door
67
+ * to "build any app on guuey."
68
+ */
69
+ export interface IncrementOptions {
70
+ /** Amount to add (default 1). May be negative. */
71
+ readonly by?: number;
72
+ /** TTL in seconds for the (possibly fresh) counter key. */
73
+ readonly ttl: number;
74
+ }
75
+ /**
76
+ * One page of a `keys()` listing. `cursor` is present when more
77
+ * keys remain — pass it back to `keys()` to continue. Treat it as
78
+ * an opaque token (its format may differ between bindings).
79
+ */
80
+ export interface KeysPage {
81
+ readonly keys: string[];
82
+ readonly cursor?: string;
83
+ }
84
+ /**
85
+ * Snapshot of the current scope's storage usage. Returned by
86
+ * `kv.scope()`. Cheap to call; pulled from the platform on each
87
+ * invocation (no client-side caching) so quota checks before
88
+ * a write reflect the live state.
89
+ */
90
+ export interface ScopeInfo {
91
+ readonly userId: string;
92
+ readonly mcpId: string;
93
+ /**
94
+ * Bytes used in this `(user, mcp)` scope — UTF-8 bytes of every
95
+ * live key PLUS its JSON-encoded value. Keys count because they
96
+ * are storage too: a scope of 1 KiB keys with 1-byte values is
97
+ * not "empty".
98
+ */
99
+ readonly usedBytes: number;
100
+ /** Hard cap for the scope. Today: 1 MiB. */
101
+ readonly limitBytes: number;
102
+ /** Distinct keys in this scope. */
103
+ readonly keyCount: number;
104
+ }
105
+ /**
106
+ * The KV interface every binding implements (in-memory for local
107
+ * dev, HTTP for hosted pods). Consumer code only ever sees this
108
+ * shape — they never touch the underlying transport.
109
+ *
110
+ * All methods are async even when they could be sync — keeps the
111
+ * shape stable across local-vs-hosted bindings and discourages
112
+ * "sync KV in the hot path" patterns that hide latency.
113
+ *
114
+ * Type parameter `T` on `get`/`set`: a structural hint, NOT a
115
+ * runtime check. The library JSON-serializes on write and parses
116
+ * on read. If the read shape doesn't match the type parameter,
117
+ * you get a wrongly-typed value with no warning. Pair with a
118
+ * schema (zod, valibot, …) at the call site if runtime safety
119
+ * matters.
120
+ */
121
+ export interface Kv {
122
+ /** Read a key. Returns `undefined` if absent or expired. */
123
+ get<T = unknown>(key: string): Promise<T | undefined>;
124
+ /**
125
+ * Write a key. TTL is required (no permanent keys).
126
+ *
127
+ * Values must be JSON-serializable: top-level `undefined`,
128
+ * functions, symbols, `BigInt`, and circular structures throw
129
+ * `InvalidArgumentError`. Standard JSON semantics otherwise
130
+ * apply — `NaN`/`Infinity` serialize as `null`, and nested
131
+ * `undefined`/function properties are dropped, exactly as
132
+ * `JSON.stringify` does.
133
+ */
134
+ set<T = unknown>(key: string, value: T, opts: SetOptions): Promise<void>;
135
+ /** Delete a key. No-op if absent. */
136
+ delete(key: string): Promise<void>;
137
+ /** Cheap existence check without deserializing the value. */
138
+ has(key: string): Promise<boolean>;
139
+ /**
140
+ * List keys in this scope, optionally filtered by prefix, in
141
+ * lexicographic order. Pages of up to 1000 keys; pass the
142
+ * returned `cursor` back to continue. Use this for diagnostics
143
+ * and small housekeeping; do NOT use it as a query engine. A
144
+ * scope that needs to "find all keys matching pattern X across
145
+ * millions of entries" wants a real database (Case B in the
146
+ * hosting policy).
147
+ */
148
+ keys(opts?: {
149
+ prefix?: string;
150
+ limit?: number;
151
+ /** Opaque continuation token from a previous page. */
152
+ cursor?: string;
153
+ }): Promise<KeysPage>;
154
+ /**
155
+ * Atomic increment. Creates the key (initialized to 0) if
156
+ * missing, then adds `by` (default 1) and returns the new
157
+ * value. Useful for rate-limit counters, generated-id
158
+ * sequences, simple analytics.
159
+ *
160
+ * Counters are integer-only: `by` must be a safe integer
161
+ * (`InvalidArgumentError` otherwise), and a key holding a
162
+ * non-number value throws `TypeMismatchError`.
163
+ *
164
+ * The TTL is reset on every increment to the value passed —
165
+ * idle counters expire naturally.
166
+ */
167
+ increment(key: string, opts: IncrementOptions): Promise<number>;
168
+ /** Inverse of `increment`. Same semantics. */
169
+ decrement(key: string, opts: IncrementOptions): Promise<number>;
170
+ /**
171
+ * Bulk read. Missing keys map to `undefined`. Cap: 100 keys per
172
+ * call (`InvalidArgumentError` beyond) — batch if you need more.
173
+ */
174
+ mget<T = unknown>(keys: string[]): Promise<Record<string, T | undefined>>;
175
+ /**
176
+ * Snapshot of current scope usage. Use this BEFORE a large
177
+ * write to fail fast if you're near the quota cap rather than
178
+ * eating a `QuotaExceededError` mid-batch.
179
+ */
180
+ scope(): Promise<ScopeInfo>;
181
+ }
182
+ /**
183
+ * Options for `createGuueyState`. Binding selection:
184
+ *
185
+ * 1. If `bindingUrl` (or the `GUUEY_KV_URL` env) is set → the hosted
186
+ * HTTP binding (`HttpKv`). Requires a token — see `authToken`
187
+ * below — or `createGuueyState` throws `InvalidContextError`
188
+ * rather than silently handing back a non-durable in-memory store
189
+ * to a caller who asked for the hosted one.
190
+ * 2. Otherwise → in-memory binding (one-time warning).
191
+ *
192
+ * The in-memory binding is right for unit tests + local development.
193
+ * guuey-hosted and colocated MCP servers get `GUUEY_KV_URL` injected
194
+ * at boot and pick up the hosted binding unchanged; a dev-hosted
195
+ * `external` server sets it itself. No token env var is injected —
196
+ * the auth token is the inbound federation Bearer JWT, obtained per
197
+ * request via `scopeFromAuthorization` (`context.token`).
198
+ */
199
+ export interface CreateGuueyStateOptions {
200
+ /** Scope identity. Required. */
201
+ readonly context: ScopeContext;
202
+ /** Override the binding URL (defaults to `GUUEY_KV_URL` env). */
203
+ readonly bindingUrl?: string;
204
+ /**
205
+ * Override the auth token (defaults to `GUUEY_KV_TOKEN` env, then
206
+ * `context.token`). Normally you never set this: the token is the
207
+ * inbound federation Bearer JWT and arrives via
208
+ * `scopeFromAuthorization` as `context.token`. `GUUEY_KV_TOKEN` /
209
+ * `authToken` are manual escape hatches (scripts, tests) — nothing
210
+ * on the platform injects them. See the `ScopeContext` trust model:
211
+ * the hosted KV API derives the mcp scope from this token
212
+ * server-side rather than trusting the caller's `mcpId`. Overrides
213
+ * `context.token` when both are set.
214
+ */
215
+ readonly authToken?: string;
216
+ }
217
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/dist/types.js ADDED
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Public types for `@guuey/state`.
3
+ *
4
+ * The library is intentionally narrow — it's a KV scoped per
5
+ * `(user, mcp)`, not a database. See `docs/principles/mcp-hosting-policy.md`
6
+ * for the rationale: scoped primitives let MCPs hold light state
7
+ * (idempotency, counters, small per-user prefs) without making guuey
8
+ * a backend-as-a-service. Hard caps are the product.
9
+ */
10
+ export {};
11
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG"}
@@ -0,0 +1,19 @@
1
+ export declare const SCOPE_LIMIT_BYTES: number;
2
+ export declare const VALUE_LIMIT_BYTES: number;
3
+ export declare const KEY_LIMIT_BYTES = 1024;
4
+ export declare const TTL_MAX_SECONDS: number;
5
+ export declare const MGET_LIMIT = 100;
6
+ export declare const VALID_KEY: RegExp;
7
+ export declare function validateKey(key: string): void;
8
+ export declare function validateTtl(ttl: number): void;
9
+ /**
10
+ * JSON-encode a value for storage, converting every serialization
11
+ * failure into the library's typed error. `JSON.stringify` returns
12
+ * the VALUE `undefined` (not a string) for top-level `undefined`,
13
+ * functions, and symbols, and throws natively for circular
14
+ * structures and `BigInt` — none of which may escape as a bare
15
+ * `TypeError` (the error contract promises `GuueyStateError`
16
+ * subclasses from every failable operation).
17
+ */
18
+ export declare function encodeValue(key: string, value: unknown): string;
19
+ //# sourceMappingURL=validate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../src/validate.ts"],"names":[],"mappings":"AAUA,eAAO,MAAM,iBAAiB,QAAkB,CAAC;AACjD,eAAO,MAAM,iBAAiB,QAAY,CAAC;AAC3C,eAAO,MAAM,eAAe,OAAO,CAAC;AACpC,eAAO,MAAM,eAAe,QAAoB,CAAC;AACjD,eAAO,MAAM,UAAU,MAAM,CAAC;AAC9B,eAAO,MAAM,SAAS,QAAyB,CAAC;AAEhD,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAa7C;AAED,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAW7C;AAED;;;;;;;;GAQG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,MAAM,CAiB/D"}
@@ -0,0 +1,60 @@
1
+ /**
2
+ * Shared key/TTL/value validation + cap constants.
3
+ *
4
+ * Both bindings (in-memory, hosted HTTP) enforce the exact same
5
+ * contract on keys/TTLs/values before touching storage — living here
6
+ * once means the two implementations can never drift on what counts
7
+ * as a valid key, TTL, or JSON-serializable value.
8
+ */
9
+ import { InvalidArgumentError, InvalidKeyError, InvalidTtlError } from "./errors.js";
10
+ export const SCOPE_LIMIT_BYTES = 1 * 1024 * 1024; // 1 MiB
11
+ export const VALUE_LIMIT_BYTES = 64 * 1024; // 64 KiB
12
+ export const KEY_LIMIT_BYTES = 1024;
13
+ export const TTL_MAX_SECONDS = 60 * 60 * 24 * 90; // 90 days
14
+ export const MGET_LIMIT = 100;
15
+ export const VALID_KEY = /^[A-Za-z0-9_.:\-/]+$/;
16
+ export function validateKey(key) {
17
+ if (key.length === 0) {
18
+ throw new InvalidKeyError(key, "must be non-empty");
19
+ }
20
+ if (Buffer.byteLength(key, "utf8") > KEY_LIMIT_BYTES) {
21
+ throw new InvalidKeyError(key, `must be <= ${KEY_LIMIT_BYTES} bytes`);
22
+ }
23
+ if (!VALID_KEY.test(key)) {
24
+ throw new InvalidKeyError(key, "may only contain ASCII letters, digits, and `_.:-/`");
25
+ }
26
+ }
27
+ export function validateTtl(ttl) {
28
+ if (!Number.isFinite(ttl) || ttl <= 0) {
29
+ throw new InvalidTtlError(ttl, "must be a positive finite number");
30
+ }
31
+ if (ttl > TTL_MAX_SECONDS) {
32
+ throw new InvalidTtlError(ttl, `must be <= ${TTL_MAX_SECONDS} seconds (90 days). ` +
33
+ `Long-lived data belongs in user-owned storage via mcp-proxy.`);
34
+ }
35
+ }
36
+ /**
37
+ * JSON-encode a value for storage, converting every serialization
38
+ * failure into the library's typed error. `JSON.stringify` returns
39
+ * the VALUE `undefined` (not a string) for top-level `undefined`,
40
+ * functions, and symbols, and throws natively for circular
41
+ * structures and `BigInt` — none of which may escape as a bare
42
+ * `TypeError` (the error contract promises `GuueyStateError`
43
+ * subclasses from every failable operation).
44
+ */
45
+ export function encodeValue(key, value) {
46
+ let json;
47
+ try {
48
+ json = JSON.stringify(value);
49
+ }
50
+ catch (err) {
51
+ throw new InvalidArgumentError(`value for key ${JSON.stringify(key)} is not JSON-serializable ` +
52
+ `(${err instanceof Error ? err.message : String(err)})`);
53
+ }
54
+ if (json === undefined) {
55
+ throw new InvalidArgumentError(`value for key ${JSON.stringify(key)} is not JSON-serializable ` +
56
+ `(top-level undefined, function, or symbol)`);
57
+ }
58
+ return json;
59
+ }
60
+ //# sourceMappingURL=validate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validate.js","sourceRoot":"","sources":["../src/validate.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,EAAE,oBAAoB,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAErF,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,GAAG,IAAI,GAAG,IAAI,CAAC,CAAC,QAAQ;AAC1D,MAAM,CAAC,MAAM,iBAAiB,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,SAAS;AACrD,MAAM,CAAC,MAAM,eAAe,GAAG,IAAI,CAAC;AACpC,MAAM,CAAC,MAAM,eAAe,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,CAAC,UAAU;AAC5D,MAAM,CAAC,MAAM,UAAU,GAAG,GAAG,CAAC;AAC9B,MAAM,CAAC,MAAM,SAAS,GAAG,sBAAsB,CAAC;AAEhD,MAAM,UAAU,WAAW,CAAC,GAAW;IACrC,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACrB,MAAM,IAAI,eAAe,CAAC,GAAG,EAAE,mBAAmB,CAAC,CAAC;IACtD,CAAC;IACD,IAAI,MAAM,CAAC,UAAU,CAAC,GAAG,EAAE,MAAM,CAAC,GAAG,eAAe,EAAE,CAAC;QACrD,MAAM,IAAI,eAAe,CAAC,GAAG,EAAE,cAAc,eAAe,QAAQ,CAAC,CAAC;IACxE,CAAC;IACD,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;QACzB,MAAM,IAAI,eAAe,CACvB,GAAG,EACH,qDAAqD,CACtD,CAAC;IACJ,CAAC;AACH,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,GAAW;IACrC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC,EAAE,CAAC;QACtC,MAAM,IAAI,eAAe,CAAC,GAAG,EAAE,kCAAkC,CAAC,CAAC;IACrE,CAAC;IACD,IAAI,GAAG,GAAG,eAAe,EAAE,CAAC;QAC1B,MAAM,IAAI,eAAe,CACvB,GAAG,EACH,cAAc,eAAe,sBAAsB;YACjD,8DAA8D,CACjE,CAAC;IACJ,CAAC;AACH,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,WAAW,CAAC,GAAW,EAAE,KAAc;IACrD,IAAI,IAAwB,CAAC;IAC7B,IAAI,CAAC;QACH,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;IAC/B,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,IAAI,oBAAoB,CAC5B,iBAAiB,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,4BAA4B;YAC9D,IAAI,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAC1D,CAAC;IACJ,CAAC;IACD,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;QACvB,MAAM,IAAI,oBAAoB,CAC5B,iBAAiB,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,4BAA4B;YAC9D,4CAA4C,CAC/C,CAAC;IACJ,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC"}
package/package.json ADDED
@@ -0,0 +1,73 @@
1
+ {
2
+ "name": "@guuey/state",
3
+ "version": "0.1.0",
4
+ "description": "Open-source KV client for MCP servers hosted on guuey.com. Scoped per (user, mcp). The MCP stays stateless from its own POV while the user retains data ownership. Hard caps are the product.",
5
+ "license": "MIT",
6
+ "type": "module",
7
+ "sideEffects": false,
8
+ "main": "dist/index.js",
9
+ "types": "dist/index.d.ts",
10
+ "files": [
11
+ "dist",
12
+ "README.md"
13
+ ],
14
+ "exports": {
15
+ ".": {
16
+ "types": "./dist/index.d.ts",
17
+ "import": "./dist/index.js"
18
+ },
19
+ "./context": {
20
+ "types": "./dist/context.d.ts",
21
+ "import": "./dist/context.js"
22
+ },
23
+ "./errors": {
24
+ "types": "./dist/errors.d.ts",
25
+ "import": "./dist/errors.js"
26
+ },
27
+ "./testing": {
28
+ "types": "./dist/testing/contract-suite.d.ts",
29
+ "import": "./dist/testing/contract-suite.js"
30
+ }
31
+ },
32
+ "dependencies": {},
33
+ "peerDependencies": {
34
+ "vitest": "^3.0.0"
35
+ },
36
+ "peerDependenciesMeta": {
37
+ "vitest": {
38
+ "optional": true
39
+ }
40
+ },
41
+ "devDependencies": {
42
+ "@types/node": "^22.0.0",
43
+ "typescript": "^5.7.0",
44
+ "vitest": "^3.2.4"
45
+ },
46
+ "publishConfig": {
47
+ "access": "public"
48
+ },
49
+ "keywords": [
50
+ "mcp",
51
+ "model-context-protocol",
52
+ "guuey",
53
+ "kv",
54
+ "key-value",
55
+ "storage"
56
+ ],
57
+ "repository": {
58
+ "type": "git",
59
+ "url": "git+https://github.com/withguuey/guuey-sdks.git",
60
+ "directory": "packages/state"
61
+ },
62
+ "homepage": "https://guuey.com",
63
+ "bugs": {
64
+ "url": "https://github.com/loqu-co/guuey/issues"
65
+ },
66
+ "scripts": {
67
+ "build": "tsc",
68
+ "dev": "tsc --watch",
69
+ "typecheck": "tsc --noEmit",
70
+ "test": "vitest run",
71
+ "test:watch": "vitest"
72
+ }
73
+ }