@noy-db/in-rest 0.6.0 → 0.7.0-pre.1

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.
@@ -1,6 +1,6 @@
1
1
  import { Router } from 'express';
2
2
  import { NoydbRestHandler } from '../index.js';
3
- import '@noy-db/hub';
3
+ import '@noy-db/hub/to';
4
4
 
5
5
  declare function expressAdapter(handler: NoydbRestHandler): Router;
6
6
 
@@ -1,6 +1,6 @@
1
1
  import { FastifyPluginAsync } from 'fastify';
2
2
  import { NoydbRestHandler } from '../index.js';
3
- import '@noy-db/hub';
3
+ import '@noy-db/hub/to';
4
4
 
5
5
  declare function fastifyPlugin(handler: NoydbRestHandler): FastifyPluginAsync;
6
6
 
@@ -1,6 +1,6 @@
1
1
  import { Hono } from 'hono';
2
2
  import { NoydbRestHandler } from '../index.js';
3
- import '@noy-db/hub';
3
+ import '@noy-db/hub/to';
4
4
 
5
5
  declare function honoAdapter(handler: NoydbRestHandler): Hono;
6
6
 
@@ -1,5 +1,5 @@
1
1
  import { NoydbRestHandler } from '../index.js';
2
- import '@noy-db/hub';
2
+ import '@noy-db/hub/to';
3
3
 
4
4
  interface H3Event {
5
5
  method: string;
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { NoydbStore } from '@noy-db/hub';
1
+ import { NoydbStore } from '@noy-db/hub/to';
2
2
 
3
3
  /**
4
4
  * **@noy-db/in-rest** — Framework-neutral REST API integration for noy-db.
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/router.ts","../src/index.ts"],"sourcesContent":["import { isConflictError } from '@noy-db/hub'\nimport type { NoydbStore, EncryptedEnvelope, VaultSnapshot } from '@noy-db/hub'\nimport type { RestRequest, RestResponse, RestHandlerOptions } from './index.js'\n\nfunction json(status: number, body: unknown): RestResponse {\n return {\n status,\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify(body),\n }\n}\n\n/**\n * The 6 required `NoydbStore` methods plus the optional sync/pagination\n * extensions — the exact set `by-peer`'s `servePeerStore` exposes. The\n * router never decrypts or interprets an argument; it forwards the\n * positional tuple straight to `store.*` and returns the raw result.\n */\nconst CORE_METHODS = new Set<string>([\n 'get',\n 'put',\n 'delete',\n 'list',\n 'loadAll',\n 'saveAll',\n 'ping',\n 'listSince',\n 'listPage',\n 'listVaults',\n])\n\nclass UnknownMethodError extends Error {}\nclass UnsupportedMethodError extends Error {}\n\nasync function dispatch(store: NoydbStore, method: string, args: readonly unknown[]): Promise<unknown> {\n switch (method) {\n case 'get': {\n const [vault, collection, id] = args as [string, string, string]\n return store.get(vault, collection, id)\n }\n case 'put': {\n const [vault, collection, id, envelope, expectedVersion] = args as [\n string,\n string,\n string,\n EncryptedEnvelope,\n number | undefined,\n ]\n await store.put(vault, collection, id, envelope, expectedVersion)\n return null\n }\n case 'delete': {\n const [vault, collection, id] = args as [string, string, string]\n await store.delete(vault, collection, id)\n return null\n }\n case 'list': {\n const [vault, collection] = args as [string, string]\n return store.list(vault, collection)\n }\n case 'loadAll': {\n const [vault] = args as [string]\n return store.loadAll(vault)\n }\n case 'saveAll': {\n const [vault, data] = args as [string, VaultSnapshot]\n await store.saveAll(vault, data)\n return null\n }\n case 'ping': {\n if (!store.ping) return true\n return store.ping()\n }\n case 'listSince': {\n if (!store.listSince) throw new UnsupportedMethodError('listSince not supported by this store')\n const [vault, collection, since] = args as [string, string, string]\n return store.listSince(vault, collection, since)\n }\n case 'listPage': {\n if (!store.listPage) throw new UnsupportedMethodError('listPage not supported by this store')\n const [vault, collection, cursor, limit] = args as [\n string,\n string,\n string | undefined,\n number | undefined,\n ]\n return store.listPage(vault, collection, cursor, limit)\n }\n case 'listVaults': {\n if (!store.listVaults) throw new UnsupportedMethodError('listVaults not supported by this store')\n return store.listVaults()\n }\n }\n /* istanbul ignore next — CORE_METHODS gate makes this unreachable */\n throw new UnknownMethodError(`Unhandled method: ${method}`)\n}\n\nexport function buildRouter(opts: RestHandlerOptions) {\n const { store, authorize, allow } = opts\n const basePath = opts.basePath ?? ''\n\n function stripBase(pathname: string): string {\n // Segment-aware prefix match: basePath '/api' matches '/api' or '/api/...'\n // but NOT '/apifoo' or '/api-other/...'.\n if (!basePath) return pathname\n if (pathname === basePath) return '/'\n if (pathname.startsWith(basePath + '/')) return pathname.slice(basePath.length)\n return pathname\n }\n\n return async function route(req: RestRequest): Promise<RestResponse> {\n const path = stripBase(req.pathname)\n const method = req.method.toUpperCase()\n\n if (method !== 'POST' || path !== '/rpc') {\n return json(404, { error: { name: 'NotFound', message: 'no such route' } })\n }\n\n // Auth first, and fail-closed: an omitted authorizer denies every\n // request. The caller MUST supply one to accept any traffic. A throwing\n // authorizer also fails closed — a structured 500 with no leaked detail,\n // never an open request or an uncaught rejection out of handle().\n let authorized: boolean\n try {\n authorized = authorize ? await authorize(req) : false\n } catch {\n return json(500, { error: { name: 'Error', message: 'authorization failed' } })\n }\n if (!authorized) {\n return json(401, { error: { name: 'Unauthorized', message: 'unauthorized' } })\n }\n\n let body: unknown\n try {\n body = await req.json()\n } catch {\n return json(400, { error: { name: 'BadRequest', message: 'invalid JSON body' } })\n }\n const rpcMethod = (body as Record<string, unknown> | null)?.method\n const rpcArgs = (body as Record<string, unknown> | null)?.args\n if (typeof rpcMethod !== 'string' || !Array.isArray(rpcArgs)) {\n return json(400, { error: { name: 'BadRequest', message: 'body must be { method: string, args: unknown[] }' } })\n }\n\n if (!CORE_METHODS.has(rpcMethod)) {\n return json(400, { error: { name: 'BadRequest', message: `unknown method: ${rpcMethod}` } })\n }\n if (allow && !allow.has(rpcMethod)) {\n return json(403, { error: { name: 'Forbidden', message: `method not allowed: ${rpcMethod}` } })\n }\n\n try {\n const result = await dispatch(store, rpcMethod, rpcArgs)\n return json(200, result ?? null)\n } catch (err) {\n if (isConflictError(err)) {\n return json(409, { error: { name: 'ConflictError', message: err.message, version: err.version } })\n }\n if (err instanceof UnsupportedMethodError) {\n // The request was well-formed; the backing store just lacks this\n // optional method. 501 (not 400) lets a client feature-detect.\n return json(501, { error: { name: 'NotImplemented', message: err.message } })\n }\n // Preserve the error NAME so a client can branch / re-hydrate, but do\n // NOT echo the raw store message — it may embed operational internals\n // (connection strings, paths). Operators read the detail from logs.\n const e = err as Error\n return json(500, { error: { name: e.name ?? 'Error', message: 'store error' } })\n }\n }\n}\n","/**\n * **@noy-db/in-rest** — Framework-neutral REST API integration for noy-db.\n *\n * A thin RPC dispatcher — the HTTP twin of `@noy-db/by-peer`'s\n * `servePeerStore` — that forwards the 6 `NoydbStore` methods straight to\n * the caller's ciphertext store. The server NEVER sees a secret, never\n * calls `createNoydb`/`openVault`, and never decrypts anything: every\n * request/response body is an `EncryptedEnvelope` (or a plain id/list of\n * one) round-tripped as-is.\n *\n * @example\n * ```ts\n * import { createRestHandler } from '@noy-db/in-rest'\n * import { honoAdapter } from '@noy-db/in-rest/hono'\n *\n * const handler = createRestHandler({\n * store,\n * authorize: (req) => req.headers['authorization'] === `Bearer ${API_KEY}`,\n * })\n * app.route('/api/noydb', honoAdapter(handler))\n * ```\n *\n * @packageDocumentation\n */\n\nimport type { NoydbStore } from '@noy-db/hub'\nimport { buildRouter } from './router.js'\n\nexport interface RestRequest {\n readonly method: string\n readonly pathname: string\n readonly searchParams: URLSearchParams\n readonly headers: Record<string, string>\n json(): Promise<unknown>\n}\n\nexport interface RestResponse {\n readonly status: number\n readonly headers: Record<string, string>\n readonly body: string | Uint8Array | null\n}\n\nexport interface NoydbRestHandler {\n handle(req: RestRequest): Promise<RestResponse>\n}\n\nexport interface RestHandlerOptions {\n readonly store: NoydbStore\n /**\n * Authorize each request. Return `true` to allow. If OMITTED, the\n * handler is FAIL-CLOSED — every `/rpc` request is rejected with 401.\n * The caller MUST supply an authorizer to accept any traffic.\n */\n readonly authorize?: (req: RestRequest) => boolean | Promise<boolean>\n /**\n * Optional method allowlist (e.g. a read-only relay). When set, a\n * method not in the set is rejected with 403.\n */\n readonly allow?: ReadonlySet<string>\n readonly basePath?: string\n}\n\nexport function createRestHandler(options: RestHandlerOptions): NoydbRestHandler {\n const route = buildRouter(options)\n return { handle: route }\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/router.ts","../src/index.ts"],"sourcesContent":["import { isConflictError } from '@noy-db/hub'\nimport type { NoydbStore, EncryptedEnvelope, VaultSnapshot } from '@noy-db/hub/to'\nimport type { RestRequest, RestResponse, RestHandlerOptions } from './index.js'\n\nfunction json(status: number, body: unknown): RestResponse {\n return {\n status,\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify(body),\n }\n}\n\n/**\n * The 6 required `NoydbStore` methods plus the optional sync/pagination\n * extensions — the exact set `by-peer`'s `servePeerStore` exposes. The\n * router never decrypts or interprets an argument; it forwards the\n * positional tuple straight to `store.*` and returns the raw result.\n */\nconst CORE_METHODS = new Set<string>([\n 'get',\n 'put',\n 'delete',\n 'list',\n 'loadAll',\n 'saveAll',\n 'ping',\n 'listSince',\n 'listPage',\n 'listVaults',\n])\n\nclass UnknownMethodError extends Error {}\nclass UnsupportedMethodError extends Error {}\n\nasync function dispatch(store: NoydbStore, method: string, args: readonly unknown[]): Promise<unknown> {\n switch (method) {\n case 'get': {\n const [vault, collection, id] = args as [string, string, string]\n return store.get(vault, collection, id)\n }\n case 'put': {\n const [vault, collection, id, envelope, expectedVersion] = args as [\n string,\n string,\n string,\n EncryptedEnvelope,\n number | undefined,\n ]\n await store.put(vault, collection, id, envelope, expectedVersion)\n return null\n }\n case 'delete': {\n const [vault, collection, id] = args as [string, string, string]\n await store.delete(vault, collection, id)\n return null\n }\n case 'list': {\n const [vault, collection] = args as [string, string]\n return store.list(vault, collection)\n }\n case 'loadAll': {\n const [vault] = args as [string]\n return store.loadAll(vault)\n }\n case 'saveAll': {\n const [vault, data] = args as [string, VaultSnapshot]\n await store.saveAll(vault, data)\n return null\n }\n case 'ping': {\n if (!store.ping) return true\n return store.ping()\n }\n case 'listSince': {\n if (!store.listSince) throw new UnsupportedMethodError('listSince not supported by this store')\n const [vault, collection, since] = args as [string, string, string]\n return store.listSince(vault, collection, since)\n }\n case 'listPage': {\n if (!store.listPage) throw new UnsupportedMethodError('listPage not supported by this store')\n const [vault, collection, cursor, limit] = args as [\n string,\n string,\n string | undefined,\n number | undefined,\n ]\n return store.listPage(vault, collection, cursor, limit)\n }\n case 'listVaults': {\n if (!store.listVaults) throw new UnsupportedMethodError('listVaults not supported by this store')\n return store.listVaults()\n }\n }\n /* istanbul ignore next — CORE_METHODS gate makes this unreachable */\n throw new UnknownMethodError(`Unhandled method: ${method}`)\n}\n\nexport function buildRouter(opts: RestHandlerOptions) {\n const { store, authorize, allow } = opts\n const basePath = opts.basePath ?? ''\n\n function stripBase(pathname: string): string {\n // Segment-aware prefix match: basePath '/api' matches '/api' or '/api/...'\n // but NOT '/apifoo' or '/api-other/...'.\n if (!basePath) return pathname\n if (pathname === basePath) return '/'\n if (pathname.startsWith(basePath + '/')) return pathname.slice(basePath.length)\n return pathname\n }\n\n return async function route(req: RestRequest): Promise<RestResponse> {\n const path = stripBase(req.pathname)\n const method = req.method.toUpperCase()\n\n if (method !== 'POST' || path !== '/rpc') {\n return json(404, { error: { name: 'NotFound', message: 'no such route' } })\n }\n\n // Auth first, and fail-closed: an omitted authorizer denies every\n // request. The caller MUST supply one to accept any traffic. A throwing\n // authorizer also fails closed — a structured 500 with no leaked detail,\n // never an open request or an uncaught rejection out of handle().\n let authorized: boolean\n try {\n authorized = authorize ? await authorize(req) : false\n } catch {\n return json(500, { error: { name: 'Error', message: 'authorization failed' } })\n }\n if (!authorized) {\n return json(401, { error: { name: 'Unauthorized', message: 'unauthorized' } })\n }\n\n let body: unknown\n try {\n body = await req.json()\n } catch {\n return json(400, { error: { name: 'BadRequest', message: 'invalid JSON body' } })\n }\n const rpcMethod = (body as Record<string, unknown> | null)?.method\n const rpcArgs = (body as Record<string, unknown> | null)?.args\n if (typeof rpcMethod !== 'string' || !Array.isArray(rpcArgs)) {\n return json(400, { error: { name: 'BadRequest', message: 'body must be { method: string, args: unknown[] }' } })\n }\n\n if (!CORE_METHODS.has(rpcMethod)) {\n return json(400, { error: { name: 'BadRequest', message: `unknown method: ${rpcMethod}` } })\n }\n if (allow && !allow.has(rpcMethod)) {\n return json(403, { error: { name: 'Forbidden', message: `method not allowed: ${rpcMethod}` } })\n }\n\n try {\n const result = await dispatch(store, rpcMethod, rpcArgs)\n return json(200, result ?? null)\n } catch (err) {\n if (isConflictError(err)) {\n return json(409, { error: { name: 'ConflictError', message: err.message, version: err.version } })\n }\n if (err instanceof UnsupportedMethodError) {\n // The request was well-formed; the backing store just lacks this\n // optional method. 501 (not 400) lets a client feature-detect.\n return json(501, { error: { name: 'NotImplemented', message: err.message } })\n }\n // Preserve the error NAME so a client can branch / re-hydrate, but do\n // NOT echo the raw store message — it may embed operational internals\n // (connection strings, paths). Operators read the detail from logs.\n const e = err as Error\n return json(500, { error: { name: e.name ?? 'Error', message: 'store error' } })\n }\n }\n}\n","/**\n * **@noy-db/in-rest** — Framework-neutral REST API integration for noy-db.\n *\n * A thin RPC dispatcher — the HTTP twin of `@noy-db/by-peer`'s\n * `servePeerStore` — that forwards the 6 `NoydbStore` methods straight to\n * the caller's ciphertext store. The server NEVER sees a secret, never\n * calls `createNoydb`/`openVault`, and never decrypts anything: every\n * request/response body is an `EncryptedEnvelope` (or a plain id/list of\n * one) round-tripped as-is.\n *\n * @example\n * ```ts\n * import { createRestHandler } from '@noy-db/in-rest'\n * import { honoAdapter } from '@noy-db/in-rest/hono'\n *\n * const handler = createRestHandler({\n * store,\n * authorize: (req) => req.headers['authorization'] === `Bearer ${API_KEY}`,\n * })\n * app.route('/api/noydb', honoAdapter(handler))\n * ```\n *\n * @packageDocumentation\n */\n\nimport type { NoydbStore } from '@noy-db/hub/to'\nimport { buildRouter } from './router.js'\n\nexport interface RestRequest {\n readonly method: string\n readonly pathname: string\n readonly searchParams: URLSearchParams\n readonly headers: Record<string, string>\n json(): Promise<unknown>\n}\n\nexport interface RestResponse {\n readonly status: number\n readonly headers: Record<string, string>\n readonly body: string | Uint8Array | null\n}\n\nexport interface NoydbRestHandler {\n handle(req: RestRequest): Promise<RestResponse>\n}\n\nexport interface RestHandlerOptions {\n readonly store: NoydbStore\n /**\n * Authorize each request. Return `true` to allow. If OMITTED, the\n * handler is FAIL-CLOSED — every `/rpc` request is rejected with 401.\n * The caller MUST supply an authorizer to accept any traffic.\n */\n readonly authorize?: (req: RestRequest) => boolean | Promise<boolean>\n /**\n * Optional method allowlist (e.g. a read-only relay). When set, a\n * method not in the set is rejected with 403.\n */\n readonly allow?: ReadonlySet<string>\n readonly basePath?: string\n}\n\nexport function createRestHandler(options: RestHandlerOptions): NoydbRestHandler {\n const route = buildRouter(options)\n return { handle: route }\n}\n"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@noy-db/in-rest",
3
- "version": "0.6.0",
3
+ "version": "0.7.0-pre.1",
4
4
  "description": "Framework-neutral REST API integration for noy-db — createRestHandler with Hono, Express, Fastify, and Nitro subpath adapters.",
5
5
  "license": "MIT",
6
6
  "author": "vLannaAi <vicio@lanna.ai>",
@@ -48,7 +48,7 @@
48
48
  "node": ">=22.0.0"
49
49
  },
50
50
  "peerDependencies": {
51
- "@noy-db/hub": "0.6.0"
51
+ "@noy-db/hub": "0.7.0-pre.1"
52
52
  },
53
53
  "peerDependenciesMeta": {
54
54
  "hono": {
@@ -70,7 +70,7 @@
70
70
  "fastify": "^5.0.0",
71
71
  "h3": "^1.13.0",
72
72
  "hono": "^4.0.0",
73
- "@noy-db/hub": "0.6.0"
73
+ "@noy-db/hub": "0.7.0-pre.1"
74
74
  },
75
75
  "keywords": [
76
76
  "noy-db",