@noy-db/in-rest 0.2.0-pre.30 → 0.2.0-pre.31

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@noy-db/in-rest",
3
- "version": "0.2.0-pre.30",
3
+ "version": "0.2.0-pre.31",
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>",
@@ -17,57 +17,26 @@
17
17
  "sideEffects": false,
18
18
  "exports": {
19
19
  ".": {
20
- "import": {
21
- "types": "./dist/index.d.ts",
22
- "default": "./dist/index.js"
23
- },
24
- "require": {
25
- "types": "./dist/index.d.cts",
26
- "default": "./dist/index.cjs"
27
- }
20
+ "types": "./dist/index.d.ts",
21
+ "default": "./dist/index.js"
28
22
  },
29
23
  "./hono": {
30
- "import": {
31
- "types": "./dist/adapters/hono.d.ts",
32
- "default": "./dist/adapters/hono.js"
33
- },
34
- "require": {
35
- "types": "./dist/adapters/hono.d.cts",
36
- "default": "./dist/adapters/hono.cjs"
37
- }
24
+ "types": "./dist/adapters/hono.d.ts",
25
+ "default": "./dist/adapters/hono.js"
38
26
  },
39
27
  "./express": {
40
- "import": {
41
- "types": "./dist/adapters/express.d.ts",
42
- "default": "./dist/adapters/express.js"
43
- },
44
- "require": {
45
- "types": "./dist/adapters/express.d.cts",
46
- "default": "./dist/adapters/express.cjs"
47
- }
28
+ "types": "./dist/adapters/express.d.ts",
29
+ "default": "./dist/adapters/express.js"
48
30
  },
49
31
  "./fastify": {
50
- "import": {
51
- "types": "./dist/adapters/fastify.d.ts",
52
- "default": "./dist/adapters/fastify.js"
53
- },
54
- "require": {
55
- "types": "./dist/adapters/fastify.d.cts",
56
- "default": "./dist/adapters/fastify.cjs"
57
- }
32
+ "types": "./dist/adapters/fastify.d.ts",
33
+ "default": "./dist/adapters/fastify.js"
58
34
  },
59
35
  "./nitro": {
60
- "import": {
61
- "types": "./dist/adapters/nitro.d.ts",
62
- "default": "./dist/adapters/nitro.js"
63
- },
64
- "require": {
65
- "types": "./dist/adapters/nitro.d.cts",
66
- "default": "./dist/adapters/nitro.cjs"
67
- }
36
+ "types": "./dist/adapters/nitro.d.ts",
37
+ "default": "./dist/adapters/nitro.js"
68
38
  }
69
39
  },
70
- "main": "./dist/index.cjs",
71
40
  "module": "./dist/index.js",
72
41
  "types": "./dist/index.d.ts",
73
42
  "files": [
@@ -76,10 +45,10 @@
76
45
  "LICENSE"
77
46
  ],
78
47
  "engines": {
79
- "node": ">=18.0.0"
48
+ "node": ">=22.0.0"
80
49
  },
81
50
  "peerDependencies": {
82
- "@noy-db/hub": "0.2.0-pre.30"
51
+ "@noy-db/hub": "0.2.0-pre.31"
83
52
  },
84
53
  "peerDependenciesMeta": {
85
54
  "hono": {
@@ -101,7 +70,7 @@
101
70
  "fastify": "^5.0.0",
102
71
  "h3": "^1.13.0",
103
72
  "hono": "^4.0.0",
104
- "@noy-db/hub": "0.2.0-pre.30"
73
+ "@noy-db/hub": "0.2.0-pre.31"
105
74
  },
106
75
  "keywords": [
107
76
  "noy-db",
@@ -1,82 +0,0 @@
1
- "use strict";
2
- var __create = Object.create;
3
- var __defProp = Object.defineProperty;
4
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
- var __getOwnPropNames = Object.getOwnPropertyNames;
6
- var __getProtoOf = Object.getPrototypeOf;
7
- var __hasOwnProp = Object.prototype.hasOwnProperty;
8
- var __export = (target, all) => {
9
- for (var name in all)
10
- __defProp(target, name, { get: all[name], enumerable: true });
11
- };
12
- var __copyProps = (to, from, except, desc) => {
13
- if (from && typeof from === "object" || typeof from === "function") {
14
- for (let key of __getOwnPropNames(from))
15
- if (!__hasOwnProp.call(to, key) && key !== except)
16
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
- }
18
- return to;
19
- };
20
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
- // If the importer is in node compatibility mode or this is not an ESM
22
- // file that has been converted to a CommonJS file using a Babel-
23
- // compatible transform (i.e. "__esModule" has not been set), then set
24
- // "default" to the CommonJS "module.exports" for node compatibility.
25
- isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
- mod
27
- ));
28
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
-
30
- // src/adapters/express.ts
31
- var express_exports = {};
32
- __export(express_exports, {
33
- expressAdapter: () => expressAdapter
34
- });
35
- module.exports = __toCommonJS(express_exports);
36
- var import_express = __toESM(require("express"), 1);
37
- function expressAdapter(handler) {
38
- const router = import_express.default.Router();
39
- router.use(async (req, res, next) => {
40
- const headers = {};
41
- for (const [k, v] of Object.entries(req.headers)) {
42
- if (typeof v === "string") headers[k] = v;
43
- }
44
- const url = new URL(req.path, "http://localhost");
45
- for (const [k, v] of Object.entries(req.query)) {
46
- if (typeof v === "string") url.searchParams.append(k, v);
47
- }
48
- let bodyCache;
49
- let bodyRead = false;
50
- const restReq = {
51
- method: req.method,
52
- pathname: req.path,
53
- searchParams: url.searchParams,
54
- headers,
55
- json: () => {
56
- if (!bodyRead) {
57
- bodyCache = req.body;
58
- bodyRead = true;
59
- }
60
- return Promise.resolve(bodyCache);
61
- }
62
- };
63
- try {
64
- const restRes = await handler.handle(restReq);
65
- res.status(restRes.status);
66
- for (const [k, v] of Object.entries(restRes.headers)) res.setHeader(k, v);
67
- if (restRes.body !== null) {
68
- res.end(restRes.body);
69
- } else {
70
- res.end();
71
- }
72
- } catch (err) {
73
- next(err);
74
- }
75
- });
76
- return router;
77
- }
78
- // Annotate the CommonJS export names for ESM import in node:
79
- 0 && (module.exports = {
80
- expressAdapter
81
- });
82
- //# sourceMappingURL=express.cjs.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../src/adapters/express.ts"],"sourcesContent":["import express from 'express'\nimport type { Router as ExpressRouter } from 'express'\nimport type { NoydbRestHandler, RestRequest } from '../index.js'\n\nexport function expressAdapter(handler: NoydbRestHandler): ExpressRouter {\n const router = express.Router()\n\n // Express 5 dropped support for bare `*` as a wildcard path — use router.use()\n // which runs for all methods and paths without needing path-to-regexp.\n router.use(async (req, res, next) => {\n const headers: Record<string, string> = {}\n for (const [k, v] of Object.entries(req.headers)) {\n if (typeof v === 'string') headers[k] = v\n }\n\n const url = new URL(req.path, 'http://localhost')\n for (const [k, v] of Object.entries(req.query)) {\n if (typeof v === 'string') url.searchParams.append(k, v)\n }\n\n let bodyCache: unknown\n let bodyRead = false\n\n const restReq: RestRequest = {\n method: req.method,\n pathname: req.path,\n searchParams: url.searchParams,\n headers,\n json: () => {\n if (!bodyRead) { bodyCache = req.body; bodyRead = true }\n return Promise.resolve(bodyCache)\n },\n }\n\n // Express 5 awaits returned promises from middleware, BUT throwing\n // inside `async` middleware only reaches the default error handler\n // when the adapter forwards the rejection via `next(err)`. Unlike\n // the fastify / hono / nitro adapters (whose frameworks hoist any\n // thrown error to their own 500 path automatically), Express needs\n // the explicit try/catch.\n try {\n const restRes = await handler.handle(restReq)\n res.status(restRes.status)\n for (const [k, v] of Object.entries(restRes.headers)) res.setHeader(k, v)\n if (restRes.body !== null) {\n res.end(restRes.body)\n } else {\n res.end()\n }\n } catch (err) {\n next(err)\n }\n })\n\n return router\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,qBAAoB;AAIb,SAAS,eAAe,SAA0C;AACvE,QAAM,SAAS,eAAAA,QAAQ,OAAO;AAI9B,SAAO,IAAI,OAAO,KAAK,KAAK,SAAS;AACnC,UAAM,UAAkC,CAAC;AACzC,eAAW,CAAC,GAAG,CAAC,KAAK,OAAO,QAAQ,IAAI,OAAO,GAAG;AAChD,UAAI,OAAO,MAAM,SAAU,SAAQ,CAAC,IAAI;AAAA,IAC1C;AAEA,UAAM,MAAM,IAAI,IAAI,IAAI,MAAM,kBAAkB;AAChD,eAAW,CAAC,GAAG,CAAC,KAAK,OAAO,QAAQ,IAAI,KAAK,GAAG;AAC9C,UAAI,OAAO,MAAM,SAAU,KAAI,aAAa,OAAO,GAAG,CAAC;AAAA,IACzD;AAEA,QAAI;AACJ,QAAI,WAAW;AAEf,UAAM,UAAuB;AAAA,MAC3B,QAAQ,IAAI;AAAA,MACZ,UAAU,IAAI;AAAA,MACd,cAAc,IAAI;AAAA,MAClB;AAAA,MACA,MAAM,MAAM;AACV,YAAI,CAAC,UAAU;AAAE,sBAAY,IAAI;AAAM,qBAAW;AAAA,QAAK;AACvD,eAAO,QAAQ,QAAQ,SAAS;AAAA,MAClC;AAAA,IACF;AAQA,QAAI;AACF,YAAM,UAAU,MAAM,QAAQ,OAAO,OAAO;AAC5C,UAAI,OAAO,QAAQ,MAAM;AACzB,iBAAW,CAAC,GAAG,CAAC,KAAK,OAAO,QAAQ,QAAQ,OAAO,EAAG,KAAI,UAAU,GAAG,CAAC;AACxE,UAAI,QAAQ,SAAS,MAAM;AACzB,YAAI,IAAI,QAAQ,IAAI;AAAA,MACtB,OAAO;AACL,YAAI,IAAI;AAAA,MACV;AAAA,IACF,SAAS,KAAK;AACZ,WAAK,GAAG;AAAA,IACV;AAAA,EACF,CAAC;AAED,SAAO;AACT;","names":["express"]}
@@ -1,7 +0,0 @@
1
- import { Router } from 'express';
2
- import { NoydbRestHandler } from '../index.cjs';
3
- import '@noy-db/hub';
4
-
5
- declare function expressAdapter(handler: NoydbRestHandler): Router;
6
-
7
- export { expressAdapter };
@@ -1,65 +0,0 @@
1
- "use strict";
2
- var __defProp = Object.defineProperty;
3
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
- var __getOwnPropNames = Object.getOwnPropertyNames;
5
- var __hasOwnProp = Object.prototype.hasOwnProperty;
6
- var __export = (target, all) => {
7
- for (var name in all)
8
- __defProp(target, name, { get: all[name], enumerable: true });
9
- };
10
- var __copyProps = (to, from, except, desc) => {
11
- if (from && typeof from === "object" || typeof from === "function") {
12
- for (let key of __getOwnPropNames(from))
13
- if (!__hasOwnProp.call(to, key) && key !== except)
14
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
- }
16
- return to;
17
- };
18
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
-
20
- // src/adapters/fastify.ts
21
- var fastify_exports = {};
22
- __export(fastify_exports, {
23
- fastifyPlugin: () => fastifyPlugin
24
- });
25
- module.exports = __toCommonJS(fastify_exports);
26
- function fastifyPlugin(handler) {
27
- return async function plugin(fastify) {
28
- fastify.all("/*", async (request, reply) => {
29
- const headers = {};
30
- for (const [k, v] of Object.entries(request.headers)) {
31
- if (typeof v === "string") headers[k] = v;
32
- }
33
- const url = new URL(request.url, "http://localhost");
34
- let bodyCache;
35
- let bodyRead = false;
36
- const restReq = {
37
- method: request.method,
38
- pathname: url.pathname,
39
- searchParams: url.searchParams,
40
- headers,
41
- json: () => {
42
- if (!bodyRead) {
43
- bodyCache = request.body;
44
- bodyRead = true;
45
- }
46
- return Promise.resolve(bodyCache);
47
- }
48
- };
49
- const restRes = await handler.handle(restReq);
50
- reply.status(restRes.status);
51
- for (const [k, v] of Object.entries(restRes.headers)) {
52
- reply.header(k, v);
53
- }
54
- if (restRes.body !== null) {
55
- return reply.send(restRes.body);
56
- }
57
- return reply.send();
58
- });
59
- };
60
- }
61
- // Annotate the CommonJS export names for ESM import in node:
62
- 0 && (module.exports = {
63
- fastifyPlugin
64
- });
65
- //# sourceMappingURL=fastify.cjs.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../src/adapters/fastify.ts"],"sourcesContent":["import type { FastifyPluginAsync } from 'fastify'\nimport type { NoydbRestHandler, RestRequest } from '../index.js'\n\nexport function fastifyPlugin(handler: NoydbRestHandler): FastifyPluginAsync {\n return async function plugin(fastify) {\n // Use '/*' — Fastify v5 / find-my-way requires the leading slash on wildcards\n // No explicit try/catch — Fastify v5 awaits the handler and routes\n // any rejection to its default error handler (which sends a 500).\n // Contrast with the Express adapter, which needs `next(err)`.\n fastify.all('/*', async (request, reply) => {\n const headers: Record<string, string> = {}\n for (const [k, v] of Object.entries(request.headers)) {\n if (typeof v === 'string') headers[k] = v\n }\n\n const url = new URL(request.url, 'http://localhost')\n\n let bodyCache: unknown\n let bodyRead = false\n\n const restReq: RestRequest = {\n method: request.method,\n pathname: url.pathname,\n searchParams: url.searchParams,\n headers,\n json: () => {\n if (!bodyRead) { bodyCache = request.body; bodyRead = true }\n return Promise.resolve(bodyCache)\n },\n }\n\n const restRes = await handler.handle(restReq)\n reply.status(restRes.status)\n for (const [k, v] of Object.entries(restRes.headers)) {\n reply.header(k, v)\n }\n if (restRes.body !== null) {\n return reply.send(restRes.body)\n }\n return reply.send()\n })\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAGO,SAAS,cAAc,SAA+C;AAC3E,SAAO,eAAe,OAAO,SAAS;AAKpC,YAAQ,IAAI,MAAM,OAAO,SAAS,UAAU;AAC1C,YAAM,UAAkC,CAAC;AACzC,iBAAW,CAAC,GAAG,CAAC,KAAK,OAAO,QAAQ,QAAQ,OAAO,GAAG;AACpD,YAAI,OAAO,MAAM,SAAU,SAAQ,CAAC,IAAI;AAAA,MAC1C;AAEA,YAAM,MAAM,IAAI,IAAI,QAAQ,KAAK,kBAAkB;AAEnD,UAAI;AACJ,UAAI,WAAW;AAEf,YAAM,UAAuB;AAAA,QAC3B,QAAQ,QAAQ;AAAA,QAChB,UAAU,IAAI;AAAA,QACd,cAAc,IAAI;AAAA,QAClB;AAAA,QACA,MAAM,MAAM;AACV,cAAI,CAAC,UAAU;AAAE,wBAAY,QAAQ;AAAM,uBAAW;AAAA,UAAK;AAC3D,iBAAO,QAAQ,QAAQ,SAAS;AAAA,QAClC;AAAA,MACF;AAEA,YAAM,UAAU,MAAM,QAAQ,OAAO,OAAO;AAC5C,YAAM,OAAO,QAAQ,MAAM;AAC3B,iBAAW,CAAC,GAAG,CAAC,KAAK,OAAO,QAAQ,QAAQ,OAAO,GAAG;AACpD,cAAM,OAAO,GAAG,CAAC;AAAA,MACnB;AACA,UAAI,QAAQ,SAAS,MAAM;AACzB,eAAO,MAAM,KAAK,QAAQ,IAAI;AAAA,MAChC;AACA,aAAO,MAAM,KAAK;AAAA,IACpB,CAAC;AAAA,EACH;AACF;","names":[]}
@@ -1,7 +0,0 @@
1
- import { FastifyPluginAsync } from 'fastify';
2
- import { NoydbRestHandler } from '../index.cjs';
3
- import '@noy-db/hub';
4
-
5
- declare function fastifyPlugin(handler: NoydbRestHandler): FastifyPluginAsync;
6
-
7
- export { fastifyPlugin };
@@ -1,54 +0,0 @@
1
- "use strict";
2
- var __defProp = Object.defineProperty;
3
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
- var __getOwnPropNames = Object.getOwnPropertyNames;
5
- var __hasOwnProp = Object.prototype.hasOwnProperty;
6
- var __export = (target, all) => {
7
- for (var name in all)
8
- __defProp(target, name, { get: all[name], enumerable: true });
9
- };
10
- var __copyProps = (to, from, except, desc) => {
11
- if (from && typeof from === "object" || typeof from === "function") {
12
- for (let key of __getOwnPropNames(from))
13
- if (!__hasOwnProp.call(to, key) && key !== except)
14
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
- }
16
- return to;
17
- };
18
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
-
20
- // src/adapters/hono.ts
21
- var hono_exports = {};
22
- __export(hono_exports, {
23
- honoAdapter: () => honoAdapter
24
- });
25
- module.exports = __toCommonJS(hono_exports);
26
- var import_hono = require("hono");
27
- function honoAdapter(handler) {
28
- const app = new import_hono.Hono();
29
- app.all("*", async (c) => {
30
- const headers = {};
31
- c.req.raw.headers.forEach((v, k) => {
32
- headers[k] = v;
33
- });
34
- const url = new URL(c.req.url);
35
- const restReq = {
36
- method: c.req.method,
37
- pathname: url.pathname,
38
- searchParams: url.searchParams,
39
- headers,
40
- json: () => c.req.json()
41
- };
42
- const res = await handler.handle(restReq);
43
- return new Response(res.body, {
44
- status: res.status,
45
- headers: res.headers
46
- });
47
- });
48
- return app;
49
- }
50
- // Annotate the CommonJS export names for ESM import in node:
51
- 0 && (module.exports = {
52
- honoAdapter
53
- });
54
- //# sourceMappingURL=hono.cjs.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../src/adapters/hono.ts"],"sourcesContent":["import { Hono } from 'hono'\nimport type { NoydbRestHandler, RestRequest } from '../index.js'\n\nexport function honoAdapter(handler: NoydbRestHandler): Hono {\n const app = new Hono()\n\n // No explicit try/catch — Hono's router surfaces any thrown error to\n // its `onError` handler (or the default 500 response) automatically.\n // Contrast with the Express adapter, which needs `next(err)`.\n app.all('*', async (c) => {\n const headers: Record<string, string> = {}\n c.req.raw.headers.forEach((v, k) => { headers[k] = v })\n\n const url = new URL(c.req.url)\n const restReq: RestRequest = {\n method: c.req.method,\n pathname: url.pathname,\n searchParams: url.searchParams,\n headers,\n json: () => c.req.json<unknown>(),\n }\n\n const res = await handler.handle(restReq)\n // `RestResponse.body` is `string | Uint8Array | null`, all valid BodyInit.\n return new Response(res.body as BodyInit | null, {\n status: res.status,\n headers: res.headers,\n })\n })\n\n return app\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,kBAAqB;AAGd,SAAS,YAAY,SAAiC;AAC3D,QAAM,MAAM,IAAI,iBAAK;AAKrB,MAAI,IAAI,KAAK,OAAO,MAAM;AACxB,UAAM,UAAkC,CAAC;AACzC,MAAE,IAAI,IAAI,QAAQ,QAAQ,CAAC,GAAG,MAAM;AAAE,cAAQ,CAAC,IAAI;AAAA,IAAE,CAAC;AAEtD,UAAM,MAAM,IAAI,IAAI,EAAE,IAAI,GAAG;AAC7B,UAAM,UAAuB;AAAA,MAC3B,QAAQ,EAAE,IAAI;AAAA,MACd,UAAU,IAAI;AAAA,MACd,cAAc,IAAI;AAAA,MAClB;AAAA,MACA,MAAM,MAAM,EAAE,IAAI,KAAc;AAAA,IAClC;AAEA,UAAM,MAAM,MAAM,QAAQ,OAAO,OAAO;AAExC,WAAO,IAAI,SAAS,IAAI,MAAyB;AAAA,MAC/C,QAAQ,IAAI;AAAA,MACZ,SAAS,IAAI;AAAA,IACf,CAAC;AAAA,EACH,CAAC;AAED,SAAO;AACT;","names":[]}
@@ -1,7 +0,0 @@
1
- import { Hono } from 'hono';
2
- import { NoydbRestHandler } from '../index.cjs';
3
- import '@noy-db/hub';
4
-
5
- declare function honoAdapter(handler: NoydbRestHandler): Hono;
6
-
7
- export { honoAdapter };
@@ -1,65 +0,0 @@
1
- "use strict";
2
- var __defProp = Object.defineProperty;
3
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
- var __getOwnPropNames = Object.getOwnPropertyNames;
5
- var __hasOwnProp = Object.prototype.hasOwnProperty;
6
- var __export = (target, all) => {
7
- for (var name in all)
8
- __defProp(target, name, { get: all[name], enumerable: true });
9
- };
10
- var __copyProps = (to, from, except, desc) => {
11
- if (from && typeof from === "object" || typeof from === "function") {
12
- for (let key of __getOwnPropNames(from))
13
- if (!__hasOwnProp.call(to, key) && key !== except)
14
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
- }
16
- return to;
17
- };
18
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
-
20
- // src/adapters/nitro.ts
21
- var nitro_exports = {};
22
- __export(nitro_exports, {
23
- nitroAdapter: () => nitroAdapter
24
- });
25
- module.exports = __toCommonJS(nitro_exports);
26
- function nitroAdapter(handler) {
27
- return async function eventHandler(event) {
28
- const headers = {};
29
- if (event.headers instanceof Headers) {
30
- event.headers.forEach((v, k) => {
31
- headers[k.toLowerCase()] = v;
32
- });
33
- } else {
34
- for (const [k, v] of Object.entries(event.headers)) {
35
- headers[k.toLowerCase()] = v;
36
- }
37
- }
38
- const url = new URL(event.path, "http://localhost");
39
- let bodyCache;
40
- let bodyRead = false;
41
- const restReq = {
42
- method: event.method,
43
- pathname: url.pathname,
44
- searchParams: url.searchParams,
45
- headers,
46
- async json() {
47
- if (!bodyRead) {
48
- bodyCache = event._body ?? null;
49
- bodyRead = true;
50
- }
51
- return bodyCache;
52
- }
53
- };
54
- const res = await handler.handle(restReq);
55
- return new Response(res.body, {
56
- status: res.status,
57
- headers: res.headers
58
- });
59
- };
60
- }
61
- // Annotate the CommonJS export names for ESM import in node:
62
- 0 && (module.exports = {
63
- nitroAdapter
64
- });
65
- //# sourceMappingURL=nitro.cjs.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../src/adapters/nitro.ts"],"sourcesContent":["import type { NoydbRestHandler, RestRequest } from '../index.js'\n\ninterface H3Event {\n method: string\n path: string\n headers: Headers | Record<string, string>\n _body?: unknown\n}\n\n/**\n * Nitro / H3 adapter. Returns a Fetch-spec `Response` — both h3 v1 and v2\n * relay a returned `Response` to the underlying HTTP layer, preserving\n * status, headers, and body (including `Uint8Array`). Returning the raw\n * `RestResponse` shape would be JSON-stringified by h3 and the status\n * would default to 200, which is wrong.\n */\nexport function nitroAdapter(handler: NoydbRestHandler) {\n // No explicit try/catch — Nitro's `defineEventHandler` wraps the\n // returned function and converts any thrown error into a 500 via\n // h3's `createError` path. Contrast with the Express adapter, which\n // needs `next(err)`.\n return async function eventHandler(event: H3Event): Promise<Response> {\n // Normalize headers to lowercase — consistent with Hono / Express /\n // Fastify and with Node's IncomingMessage.headers convention.\n const headers: Record<string, string> = {}\n if (event.headers instanceof Headers) {\n event.headers.forEach((v, k) => { headers[k.toLowerCase()] = v })\n } else {\n for (const [k, v] of Object.entries(event.headers)) {\n headers[k.toLowerCase()] = v\n }\n }\n\n const url = new URL(event.path, 'http://localhost')\n let bodyCache: unknown\n let bodyRead = false\n\n const restReq: RestRequest = {\n method: event.method,\n pathname: url.pathname,\n searchParams: url.searchParams,\n headers,\n async json() {\n if (!bodyRead) { bodyCache = event._body ?? null; bodyRead = true }\n return bodyCache\n },\n }\n\n const res = await handler.handle(restReq)\n // `RestResponse.body` is `string | Uint8Array | null`, all of which are\n // valid `BodyInit`. TS's generic-parameter drift on Uint8Array under\n // lib.es5 requires the cast; the runtime assignment is safe.\n return new Response(res.body as BodyInit | null, {\n status: res.status,\n headers: res.headers,\n })\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAgBO,SAAS,aAAa,SAA2B;AAKtD,SAAO,eAAe,aAAa,OAAmC;AAGpE,UAAM,UAAkC,CAAC;AACzC,QAAI,MAAM,mBAAmB,SAAS;AACpC,YAAM,QAAQ,QAAQ,CAAC,GAAG,MAAM;AAAE,gBAAQ,EAAE,YAAY,CAAC,IAAI;AAAA,MAAE,CAAC;AAAA,IAClE,OAAO;AACL,iBAAW,CAAC,GAAG,CAAC,KAAK,OAAO,QAAQ,MAAM,OAAO,GAAG;AAClD,gBAAQ,EAAE,YAAY,CAAC,IAAI;AAAA,MAC7B;AAAA,IACF;AAEA,UAAM,MAAM,IAAI,IAAI,MAAM,MAAM,kBAAkB;AAClD,QAAI;AACJ,QAAI,WAAW;AAEf,UAAM,UAAuB;AAAA,MAC3B,QAAQ,MAAM;AAAA,MACd,UAAU,IAAI;AAAA,MACd,cAAc,IAAI;AAAA,MAClB;AAAA,MACA,MAAM,OAAO;AACX,YAAI,CAAC,UAAU;AAAE,sBAAY,MAAM,SAAS;AAAM,qBAAW;AAAA,QAAK;AAClE,eAAO;AAAA,MACT;AAAA,IACF;AAEA,UAAM,MAAM,MAAM,QAAQ,OAAO,OAAO;AAIxC,WAAO,IAAI,SAAS,IAAI,MAAyB;AAAA,MAC/C,QAAQ,IAAI;AAAA,MACZ,SAAS,IAAI;AAAA,IACf,CAAC;AAAA,EACH;AACF;","names":[]}
@@ -1,19 +0,0 @@
1
- import { NoydbRestHandler } from '../index.cjs';
2
- import '@noy-db/hub';
3
-
4
- interface H3Event {
5
- method: string;
6
- path: string;
7
- headers: Headers | Record<string, string>;
8
- _body?: unknown;
9
- }
10
- /**
11
- * Nitro / H3 adapter. Returns a Fetch-spec `Response` — both h3 v1 and v2
12
- * relay a returned `Response` to the underlying HTTP layer, preserving
13
- * status, headers, and body (including `Uint8Array`). Returning the raw
14
- * `RestResponse` shape would be JSON-stringified by h3 and the status
15
- * would default to 200, which is wrong.
16
- */
17
- declare function nitroAdapter(handler: NoydbRestHandler): (event: H3Event) => Promise<Response>;
18
-
19
- export { nitroAdapter };
package/dist/index.cjs DELETED
@@ -1,341 +0,0 @@
1
- "use strict";
2
- var __defProp = Object.defineProperty;
3
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
- var __getOwnPropNames = Object.getOwnPropertyNames;
5
- var __hasOwnProp = Object.prototype.hasOwnProperty;
6
- var __export = (target, all) => {
7
- for (var name in all)
8
- __defProp(target, name, { get: all[name], enumerable: true });
9
- };
10
- var __copyProps = (to, from, except, desc) => {
11
- if (from && typeof from === "object" || typeof from === "function") {
12
- for (let key of __getOwnPropNames(from))
13
- if (!__hasOwnProp.call(to, key) && key !== except)
14
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
- }
16
- return to;
17
- };
18
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
-
20
- // src/index.ts
21
- var index_exports = {};
22
- __export(index_exports, {
23
- createRestHandler: () => createRestHandler
24
- });
25
- module.exports = __toCommonJS(index_exports);
26
-
27
- // src/sessions.ts
28
- var DEFAULT_SWEEP_INTERVAL_MS = 5 * 60 * 1e3;
29
- var SessionStore = class {
30
- sessions = /* @__PURE__ */ new Map();
31
- ttlMs;
32
- sweepTimer;
33
- constructor(ttlSeconds, options = {}) {
34
- this.ttlMs = ttlSeconds * 1e3;
35
- const sweepMs = options.sweepIntervalMs ?? DEFAULT_SWEEP_INTERVAL_MS;
36
- if (sweepMs > 0) {
37
- const timer = setInterval(() => this.sweep(), sweepMs);
38
- if (typeof timer.unref === "function") {
39
- timer.unref();
40
- }
41
- this.sweepTimer = timer;
42
- } else {
43
- this.sweepTimer = null;
44
- }
45
- }
46
- create(db) {
47
- const token = crypto.randomUUID();
48
- this.sessions.set(token, { db, expiresAt: Date.now() + this.ttlMs });
49
- return token;
50
- }
51
- /**
52
- * Look up a session and refresh its sliding-window TTL. Call from
53
- * auth-guarded routes that are treated as "activity".
54
- */
55
- get(token) {
56
- const session = this.sessions.get(token);
57
- if (!session) return null;
58
- if (Date.now() > session.expiresAt) {
59
- this.sessions.delete(token);
60
- return null;
61
- }
62
- session.expiresAt = Date.now() + this.ttlMs;
63
- return session.db;
64
- }
65
- delete(token) {
66
- this.sessions.delete(token);
67
- }
68
- /**
69
- * Non-refreshing existence check. Used by polling endpoints like
70
- * `GET /sessions/current` that should not extend the session merely
71
- * by being queried.
72
- */
73
- peek(token) {
74
- const session = this.sessions.get(token);
75
- if (!session) return false;
76
- if (Date.now() > session.expiresAt) {
77
- this.sessions.delete(token);
78
- return false;
79
- }
80
- return true;
81
- }
82
- /**
83
- * Drop every session whose TTL has elapsed. Called automatically by
84
- * the internal interval timer; exposed so tests can deterministically
85
- * trigger the sweep without waiting. Returns the count of entries
86
- * removed — useful for logging / metrics hooks.
87
- */
88
- sweep() {
89
- const now = Date.now();
90
- let removed = 0;
91
- for (const [token, session] of this.sessions) {
92
- if (now > session.expiresAt) {
93
- this.sessions.delete(token);
94
- removed++;
95
- }
96
- }
97
- return removed;
98
- }
99
- /**
100
- * Current number of tracked sessions (expired or not). Primarily for
101
- * tests that verify the sweep is working; operators wanting live
102
- * metrics should wrap the store or emit their own counters.
103
- */
104
- size() {
105
- return this.sessions.size;
106
- }
107
- /**
108
- * Stop the background sweep timer and drop every session. Call this
109
- * on shutdown to allow the event loop to exit cleanly — `unref()`
110
- * handles most cases, but explicit cleanup is cheaper than relying
111
- * on finalization.
112
- */
113
- close() {
114
- if (this.sweepTimer !== null) clearInterval(this.sweepTimer);
115
- this.sessions.clear();
116
- }
117
- };
118
-
119
- // src/router.ts
120
- var import_hub = require("@noy-db/hub");
121
-
122
- // src/query-params.ts
123
- var OP_MAP = {
124
- eq: "==",
125
- neq: "!=",
126
- gt: ">",
127
- gte: ">=",
128
- lt: "<",
129
- lte: "<="
130
- };
131
- function parseQueryParams(searchParams) {
132
- const wheres = searchParams.getAll("where");
133
- const orderByParam = searchParams.get("orderBy");
134
- const limitParam = searchParams.get("limit");
135
- const whereClauses = [];
136
- for (const clause of wheres) {
137
- const parts = clause.split(":");
138
- if (parts.length < 3) {
139
- return {
140
- error: { error: "invalid_where", op: clause },
141
- apply: (q) => q,
142
- limit: null
143
- };
144
- }
145
- const field = parts[0];
146
- const opStr = parts[1];
147
- const value = parts.slice(2).join(":");
148
- const op = OP_MAP[opStr];
149
- if (!op) {
150
- return {
151
- error: { error: "invalid_op", op: opStr },
152
- apply: (q) => q,
153
- limit: null
154
- };
155
- }
156
- whereClauses.push({ field, op, value: coerce(value) });
157
- }
158
- let orderBy = null;
159
- if (orderByParam) {
160
- const obParts = orderByParam.split(":");
161
- const obField = obParts[0];
162
- const obDir = obParts[1];
163
- orderBy = { field: obField, dir: obDir === "desc" ? "desc" : "asc" };
164
- }
165
- const limit = limitParam ? parseInt(limitParam, 10) : null;
166
- return {
167
- apply(q) {
168
- let result = q;
169
- for (const { field, op, value } of whereClauses) {
170
- result = result.where(field, op, value);
171
- }
172
- if (orderBy) {
173
- result = result.orderBy(orderBy.field, orderBy.dir);
174
- }
175
- return result;
176
- },
177
- limit
178
- };
179
- }
180
- function coerce(raw) {
181
- if (raw === "true") return true;
182
- if (raw === "false") return false;
183
- const n = Number(raw);
184
- if (!isNaN(n) && raw.trim() !== "") return n;
185
- return raw;
186
- }
187
-
188
- // src/router.ts
189
- function json(status, body) {
190
- return {
191
- status,
192
- headers: { "content-type": "application/json" },
193
- body: JSON.stringify(body)
194
- };
195
- }
196
- function extractToken(req) {
197
- const auth = req.headers["authorization"] ?? req.headers["Authorization"];
198
- if (!auth?.startsWith("Bearer ")) return null;
199
- return auth.slice(7);
200
- }
201
- function buildRouter(store, user, sessions, basePath) {
202
- function stripBase(pathname) {
203
- if (!basePath) return pathname;
204
- if (pathname === basePath) return "/";
205
- if (pathname.startsWith(basePath + "/")) return pathname.slice(basePath.length);
206
- return pathname;
207
- }
208
- return async function route(req) {
209
- const path = stripBase(req.pathname);
210
- const method = req.method.toUpperCase();
211
- if (method === "POST" && path === "/sessions/unlock/passphrase") {
212
- let body;
213
- try {
214
- body = await req.json();
215
- } catch {
216
- return json(400, { error: "invalid_json" });
217
- }
218
- const passphrase = body?.passphrase;
219
- if (typeof passphrase !== "string" || !passphrase) {
220
- return json(400, { error: "passphrase_required" });
221
- }
222
- try {
223
- const db2 = await (0, import_hub.createNoydb)({ store, user, secret: passphrase });
224
- const token2 = sessions.create(db2);
225
- return json(200, { token: token2 });
226
- } catch (err) {
227
- if (err instanceof import_hub.ValidationError) {
228
- return json(400, { error: "weak_passphrase", message: err.message });
229
- }
230
- return json(401, { error: "invalid_passphrase" });
231
- }
232
- }
233
- if (method === "GET" && path === "/sessions/current") {
234
- const token2 = extractToken(req);
235
- const active = token2 !== null && sessions.peek(token2);
236
- return json(200, { active });
237
- }
238
- if (method === "DELETE" && path === "/sessions/current") {
239
- const token2 = extractToken(req);
240
- if (!token2 || !sessions.peek(token2)) return json(401, { error: "unauthorized" });
241
- sessions.delete(token2);
242
- return { status: 204, headers: {}, body: null };
243
- }
244
- const token = extractToken(req);
245
- const db = token ? sessions.get(token) : null;
246
- if (!db) return json(401, { error: "unauthorized" });
247
- if (method === "GET" && path === "/vaults") {
248
- try {
249
- if (typeof store.listVaults === "function") {
250
- const vaults = await db.listAccessibleVaults();
251
- return json(200, vaults.map((v) => v.id));
252
- }
253
- return json(200, []);
254
- } catch {
255
- return json(200, []);
256
- }
257
- }
258
- const recordMatch = path.match(/^\/vaults\/([^/]+)\/collections\/([^/]+)\/([^/]+)$/);
259
- if (recordMatch) {
260
- const vaultName = recordMatch[1];
261
- const collName = recordMatch[2];
262
- const id = recordMatch[3];
263
- if (vaultName === void 0 || collName === void 0 || id === void 0) {
264
- return json(500, { error: "internal_error" });
265
- }
266
- try {
267
- const vault = await db.openVault(vaultName);
268
- const coll = vault.collection(collName);
269
- if (method === "GET") {
270
- const record = await coll.get(id);
271
- if (!record) return json(404, { error: "not_found" });
272
- return json(200, record);
273
- }
274
- if (method === "POST") {
275
- let body;
276
- try {
277
- body = await req.json();
278
- } catch {
279
- return json(400, { error: "invalid_json" });
280
- }
281
- await coll.put(id, body);
282
- return json(200, { ok: true });
283
- }
284
- if (method === "DELETE") {
285
- await coll.delete(id);
286
- return json(200, { ok: true });
287
- }
288
- return {
289
- status: 405,
290
- headers: { "content-type": "application/json", allow: "GET, POST, DELETE" },
291
- body: JSON.stringify({ error: "method_not_allowed" })
292
- };
293
- } catch (err) {
294
- if (err instanceof import_hub.PermissionDeniedError) return json(403, { error: "forbidden" });
295
- if (err instanceof import_hub.NotFoundError) return json(404, { error: "not_found" });
296
- if (err instanceof import_hub.ConflictError) return json(409, { error: "conflict" });
297
- return json(500, { error: "internal_error" });
298
- }
299
- }
300
- const collMatch = path.match(/^\/vaults\/([^/]+)\/collections\/([^/]+)$/);
301
- if (collMatch) {
302
- if (method !== "GET") {
303
- return {
304
- status: 405,
305
- headers: { "content-type": "application/json", allow: "GET" },
306
- body: JSON.stringify({ error: "method_not_allowed" })
307
- };
308
- }
309
- const vaultName = collMatch[1];
310
- const collName = collMatch[2];
311
- if (vaultName === void 0 || collName === void 0) {
312
- return json(500, { error: "internal_error" });
313
- }
314
- const params = parseQueryParams(req.searchParams);
315
- if (params.error) return json(400, params.error);
316
- try {
317
- const vault = await db.openVault(vaultName);
318
- const coll = vault.collection(collName);
319
- let results = params.apply(coll.query()).toArray();
320
- if (params.limit !== null) results = results.slice(0, params.limit);
321
- return json(200, results);
322
- } catch (err) {
323
- if (err instanceof import_hub.PermissionDeniedError) return json(403, { error: "forbidden" });
324
- return json(500, { error: "internal_error" });
325
- }
326
- }
327
- return json(404, { error: "not_found" });
328
- };
329
- }
330
-
331
- // src/index.ts
332
- function createRestHandler(options) {
333
- const sessions = new SessionStore(options.ttlSeconds ?? 900);
334
- const route = buildRouter(options.store, options.user, sessions, options.basePath ?? "");
335
- return { handle: route };
336
- }
337
- // Annotate the CommonJS export names for ESM import in node:
338
- 0 && (module.exports = {
339
- createRestHandler
340
- });
341
- //# sourceMappingURL=index.cjs.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/index.ts","../src/sessions.ts","../src/router.ts","../src/query-params.ts"],"sourcesContent":["/**\n * **@noy-db/in-rest** — Framework-neutral REST API integration for noy-db.\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({ store, user: 'api' })\n * app.route('/api/noydb', honoAdapter(handler))\n * ```\n *\n * @packageDocumentation\n */\n\nimport type { NoydbStore } from '@noy-db/hub'\nimport { SessionStore } from './sessions.js'\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 readonly user: string\n readonly ttlSeconds?: number\n readonly basePath?: string\n}\n\nexport function createRestHandler(options: RestHandlerOptions): NoydbRestHandler {\n const sessions = new SessionStore(options.ttlSeconds ?? 900)\n const route = buildRouter(options.store, options.user, sessions, options.basePath ?? '')\n return { handle: route }\n}\n","import type { Noydb } from '@noy-db/hub'\n\ninterface Session {\n db: Noydb\n expiresAt: number\n}\n\n/**\n * Options for `SessionStore`.\n *\n * `sweepIntervalMs` controls the periodic background sweep that drops\n * expired sessions from the map. Without it, expired\n * tokens only clear when a matching `get()` / `peek()` call happens —\n * a long-running process with many short-lived sessions accumulates\n * dead entries unbounded. Default is 5 minutes; pass `0` to disable\n * the sweep (appropriate for tests or very short-lived CLI processes).\n */\nexport interface SessionStoreOptions {\n sweepIntervalMs?: number\n}\n\nconst DEFAULT_SWEEP_INTERVAL_MS = 5 * 60 * 1000\n\nexport class SessionStore {\n private readonly sessions = new Map<string, Session>()\n private readonly ttlMs: number\n private readonly sweepTimer: ReturnType<typeof setInterval> | null\n\n constructor(ttlSeconds: number, options: SessionStoreOptions = {}) {\n this.ttlMs = ttlSeconds * 1000\n const sweepMs = options.sweepIntervalMs ?? DEFAULT_SWEEP_INTERVAL_MS\n if (sweepMs > 0) {\n // Node's setInterval returns a Timeout whose `.unref()` prevents\n // the timer from keeping the event loop alive. That matters in\n // CLI / serverless contexts where the Node process should exit\n // cleanly once the request cycle ends.\n const timer = setInterval(() => this.sweep(), sweepMs)\n if (typeof (timer as { unref?: () => void }).unref === 'function') {\n (timer as { unref: () => void }).unref()\n }\n this.sweepTimer = timer\n } else {\n this.sweepTimer = null\n }\n }\n\n create(db: Noydb): string {\n const token = crypto.randomUUID()\n this.sessions.set(token, { db, expiresAt: Date.now() + this.ttlMs })\n return token\n }\n\n /**\n * Look up a session and refresh its sliding-window TTL. Call from\n * auth-guarded routes that are treated as \"activity\".\n */\n get(token: string): Noydb | null {\n const session = this.sessions.get(token)\n if (!session) return null\n if (Date.now() > session.expiresAt) {\n this.sessions.delete(token)\n return null\n }\n session.expiresAt = Date.now() + this.ttlMs\n return session.db\n }\n\n delete(token: string): void {\n this.sessions.delete(token)\n }\n\n /**\n * Non-refreshing existence check. Used by polling endpoints like\n * `GET /sessions/current` that should not extend the session merely\n * by being queried.\n */\n peek(token: string): boolean {\n const session = this.sessions.get(token)\n if (!session) return false\n if (Date.now() > session.expiresAt) {\n this.sessions.delete(token)\n return false\n }\n return true\n }\n\n /**\n * Drop every session whose TTL has elapsed. Called automatically by\n * the internal interval timer; exposed so tests can deterministically\n * trigger the sweep without waiting. Returns the count of entries\n * removed — useful for logging / metrics hooks.\n */\n sweep(): number {\n const now = Date.now()\n let removed = 0\n for (const [token, session] of this.sessions) {\n if (now > session.expiresAt) {\n this.sessions.delete(token)\n removed++\n }\n }\n return removed\n }\n\n /**\n * Current number of tracked sessions (expired or not). Primarily for\n * tests that verify the sweep is working; operators wanting live\n * metrics should wrap the store or emit their own counters.\n */\n size(): number {\n return this.sessions.size\n }\n\n /**\n * Stop the background sweep timer and drop every session. Call this\n * on shutdown to allow the event loop to exit cleanly — `unref()`\n * handles most cases, but explicit cleanup is cheaper than relying\n * on finalization.\n */\n close(): void {\n if (this.sweepTimer !== null) clearInterval(this.sweepTimer)\n this.sessions.clear()\n }\n}\n","import { createNoydb, PermissionDeniedError, NotFoundError, ConflictError, ValidationError } from '@noy-db/hub'\nimport type { NoydbStore } from '@noy-db/hub'\nimport type { RestRequest, RestResponse } from './index.js'\nimport type { SessionStore } from './sessions.js'\nimport { parseQueryParams } from './query-params.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\nfunction extractToken(req: RestRequest): string | null {\n // HTTP headers are case-insensitive; check both common casings.\n const auth = req.headers['authorization'] ?? req.headers['Authorization']\n if (!auth?.startsWith('Bearer ')) return null\n return auth.slice(7)\n}\n\nexport function buildRouter(store: NoydbStore, user: string, sessions: SessionStore, basePath: string) {\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 // ── Session routes (no auth required) ─────────────────────────\n\n if (method === 'POST' && path === '/sessions/unlock/passphrase') {\n let body: unknown\n try { body = await req.json() } catch { return json(400, { error: 'invalid_json' }) }\n const passphrase = (body as Record<string, unknown>)?.passphrase\n if (typeof passphrase !== 'string' || !passphrase) {\n return json(400, { error: 'passphrase_required' })\n }\n try {\n const db = await createNoydb({ store, user, secret: passphrase })\n const token = sessions.create(db)\n return json(200, { token })\n } catch (err) {\n if (err instanceof ValidationError) {\n return json(400, { error: 'weak_passphrase', message: err.message })\n }\n return json(401, { error: 'invalid_passphrase' })\n }\n }\n\n if (method === 'GET' && path === '/sessions/current') {\n const token = extractToken(req)\n const active = token !== null && sessions.peek(token)\n return json(200, { active })\n }\n\n if (method === 'DELETE' && path === '/sessions/current') {\n const token = extractToken(req)\n if (!token || !sessions.peek(token)) return json(401, { error: 'unauthorized' })\n sessions.delete(token)\n return { status: 204, headers: {}, body: null }\n }\n\n // ── Auth guard ────────────────────────────────────────────────\n\n const token = extractToken(req)\n const db = token ? sessions.get(token) : null\n if (!db) return json(401, { error: 'unauthorized' })\n\n // ── Vault routes ──────────────────────────────────────────────\n\n if (method === 'GET' && path === '/vaults') {\n try {\n if (typeof store.listVaults === 'function') {\n const vaults = await db.listAccessibleVaults()\n return json(200, vaults.map(v => v.id))\n }\n return json(200, [])\n } catch {\n return json(200, [])\n }\n }\n\n // Match /vaults/:vault/collections/:collection/:id\n const recordMatch = path.match(/^\\/vaults\\/([^/]+)\\/collections\\/([^/]+)\\/([^/]+)$/)\n if (recordMatch) {\n const vaultName = recordMatch[1]\n const collName = recordMatch[2]\n const id = recordMatch[3]\n if (vaultName === undefined || collName === undefined || id === undefined) {\n return json(500, { error: 'internal_error' })\n }\n try {\n const vault = await db.openVault(vaultName)\n const coll = vault.collection<Record<string, unknown>>(collName)\n\n if (method === 'GET') {\n const record = await coll.get(id)\n if (!record) return json(404, { error: 'not_found' })\n return json(200, record)\n }\n\n if (method === 'POST') {\n let body: unknown\n try { body = await req.json() } catch { return json(400, { error: 'invalid_json' }) }\n await coll.put(id, body as Record<string, unknown>)\n return json(200, { ok: true })\n }\n\n if (method === 'DELETE') {\n await coll.delete(id)\n return json(200, { ok: true })\n }\n\n return {\n status: 405,\n headers: { 'content-type': 'application/json', allow: 'GET, POST, DELETE' },\n body: JSON.stringify({ error: 'method_not_allowed' }),\n }\n } catch (err) {\n if (err instanceof PermissionDeniedError) return json(403, { error: 'forbidden' })\n if (err instanceof NotFoundError) return json(404, { error: 'not_found' })\n if (err instanceof ConflictError) return json(409, { error: 'conflict' })\n return json(500, { error: 'internal_error' })\n }\n }\n\n // Match /vaults/:vault/collections/:collection (list)\n const collMatch = path.match(/^\\/vaults\\/([^/]+)\\/collections\\/([^/]+)$/)\n if (collMatch) {\n if (method !== 'GET') {\n return {\n status: 405,\n headers: { 'content-type': 'application/json', allow: 'GET' },\n body: JSON.stringify({ error: 'method_not_allowed' }),\n }\n }\n const vaultName = collMatch[1]\n const collName = collMatch[2]\n if (vaultName === undefined || collName === undefined) {\n return json(500, { error: 'internal_error' })\n }\n const params = parseQueryParams(req.searchParams)\n if (params.error) return json(400, params.error)\n try {\n const vault = await db.openVault(vaultName)\n const coll = vault.collection<Record<string, unknown>>(collName)\n let results = params.apply(coll.query()).toArray()\n if (params.limit !== null) results = results.slice(0, params.limit)\n return json(200, results)\n } catch (err) {\n if (err instanceof PermissionDeniedError) return json(403, { error: 'forbidden' })\n return json(500, { error: 'internal_error' })\n }\n }\n\n return json(404, { error: 'not_found' })\n }\n}\n","import type { Query } from '@noy-db/hub'\n\ntype QueryOp = '==' | '!=' | '>' | '>=' | '<' | '<='\n\nconst OP_MAP: Record<string, QueryOp> = {\n eq: '==',\n neq: '!=',\n gt: '>',\n gte: '>=',\n lt: '<',\n lte: '<=',\n}\n\nexport interface ParsedQueryParams {\n error?: { error: string; op?: string }\n apply<T>(q: Query<T>): Query<T>\n limit: number | null\n}\n\nexport function parseQueryParams(searchParams: URLSearchParams): ParsedQueryParams {\n const wheres = searchParams.getAll('where')\n const orderByParam = searchParams.get('orderBy')\n const limitParam = searchParams.get('limit')\n\n const whereClauses: Array<{ field: string; op: QueryOp; value: unknown }> = []\n\n for (const clause of wheres) {\n const parts = clause.split(':')\n if (parts.length < 3) {\n return {\n error: { error: 'invalid_where', op: clause },\n apply: (q) => q,\n limit: null,\n }\n }\n const field = parts[0] as string\n const opStr = parts[1] as string\n const value = parts.slice(2).join(':')\n const op = OP_MAP[opStr]\n if (!op) {\n return {\n error: { error: 'invalid_op', op: opStr },\n apply: (q) => q,\n limit: null,\n }\n }\n whereClauses.push({ field, op, value: coerce(value) })\n }\n\n let orderBy: { field: string; dir: 'asc' | 'desc' } | null = null\n if (orderByParam) {\n const obParts = orderByParam.split(':')\n const obField = obParts[0] as string\n const obDir = obParts[1]\n orderBy = { field: obField, dir: obDir === 'desc' ? 'desc' : 'asc' }\n }\n\n const limit = limitParam ? parseInt(limitParam, 10) : null\n\n return {\n apply<T>(q: Query<T>): Query<T> {\n let result = q\n for (const { field, op, value } of whereClauses) {\n result = result.where(field, op, value as T[keyof T & string])\n }\n if (orderBy) {\n result = result.orderBy(orderBy.field, orderBy.dir)\n }\n return result\n },\n limit,\n }\n}\n\nfunction coerce(raw: string): unknown {\n if (raw === 'true') return true\n if (raw === 'false') return false\n const n = Number(raw)\n if (!isNaN(n) && raw.trim() !== '') return n\n return raw\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACqBA,IAAM,4BAA4B,IAAI,KAAK;AAEpC,IAAM,eAAN,MAAmB;AAAA,EACP,WAAW,oBAAI,IAAqB;AAAA,EACpC;AAAA,EACA;AAAA,EAEjB,YAAY,YAAoB,UAA+B,CAAC,GAAG;AACjE,SAAK,QAAQ,aAAa;AAC1B,UAAM,UAAU,QAAQ,mBAAmB;AAC3C,QAAI,UAAU,GAAG;AAKf,YAAM,QAAQ,YAAY,MAAM,KAAK,MAAM,GAAG,OAAO;AACrD,UAAI,OAAQ,MAAiC,UAAU,YAAY;AACjE,QAAC,MAAgC,MAAM;AAAA,MACzC;AACA,WAAK,aAAa;AAAA,IACpB,OAAO;AACL,WAAK,aAAa;AAAA,IACpB;AAAA,EACF;AAAA,EAEA,OAAO,IAAmB;AACxB,UAAM,QAAQ,OAAO,WAAW;AAChC,SAAK,SAAS,IAAI,OAAO,EAAE,IAAI,WAAW,KAAK,IAAI,IAAI,KAAK,MAAM,CAAC;AACnE,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,IAAI,OAA6B;AAC/B,UAAM,UAAU,KAAK,SAAS,IAAI,KAAK;AACvC,QAAI,CAAC,QAAS,QAAO;AACrB,QAAI,KAAK,IAAI,IAAI,QAAQ,WAAW;AAClC,WAAK,SAAS,OAAO,KAAK;AAC1B,aAAO;AAAA,IACT;AACA,YAAQ,YAAY,KAAK,IAAI,IAAI,KAAK;AACtC,WAAO,QAAQ;AAAA,EACjB;AAAA,EAEA,OAAO,OAAqB;AAC1B,SAAK,SAAS,OAAO,KAAK;AAAA,EAC5B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,KAAK,OAAwB;AAC3B,UAAM,UAAU,KAAK,SAAS,IAAI,KAAK;AACvC,QAAI,CAAC,QAAS,QAAO;AACrB,QAAI,KAAK,IAAI,IAAI,QAAQ,WAAW;AAClC,WAAK,SAAS,OAAO,KAAK;AAC1B,aAAO;AAAA,IACT;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,QAAgB;AACd,UAAM,MAAM,KAAK,IAAI;AACrB,QAAI,UAAU;AACd,eAAW,CAAC,OAAO,OAAO,KAAK,KAAK,UAAU;AAC5C,UAAI,MAAM,QAAQ,WAAW;AAC3B,aAAK,SAAS,OAAO,KAAK;AAC1B;AAAA,MACF;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,OAAe;AACb,WAAO,KAAK,SAAS;AAAA,EACvB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,QAAc;AACZ,QAAI,KAAK,eAAe,KAAM,eAAc,KAAK,UAAU;AAC3D,SAAK,SAAS,MAAM;AAAA,EACtB;AACF;;;AC3HA,iBAAkG;;;ACIlG,IAAM,SAAkC;AAAA,EACtC,IAAI;AAAA,EACJ,KAAK;AAAA,EACL,IAAI;AAAA,EACJ,KAAK;AAAA,EACL,IAAI;AAAA,EACJ,KAAK;AACP;AAQO,SAAS,iBAAiB,cAAkD;AACjF,QAAM,SAAS,aAAa,OAAO,OAAO;AAC1C,QAAM,eAAe,aAAa,IAAI,SAAS;AAC/C,QAAM,aAAa,aAAa,IAAI,OAAO;AAE3C,QAAM,eAAsE,CAAC;AAE7E,aAAW,UAAU,QAAQ;AAC3B,UAAM,QAAQ,OAAO,MAAM,GAAG;AAC9B,QAAI,MAAM,SAAS,GAAG;AACpB,aAAO;AAAA,QACL,OAAO,EAAE,OAAO,iBAAiB,IAAI,OAAO;AAAA,QAC5C,OAAO,CAAC,MAAM;AAAA,QACd,OAAO;AAAA,MACT;AAAA,IACF;AACA,UAAM,QAAQ,MAAM,CAAC;AACrB,UAAM,QAAQ,MAAM,CAAC;AACrB,UAAM,QAAQ,MAAM,MAAM,CAAC,EAAE,KAAK,GAAG;AACrC,UAAM,KAAK,OAAO,KAAK;AACvB,QAAI,CAAC,IAAI;AACP,aAAO;AAAA,QACL,OAAO,EAAE,OAAO,cAAc,IAAI,MAAM;AAAA,QACxC,OAAO,CAAC,MAAM;AAAA,QACd,OAAO;AAAA,MACT;AAAA,IACF;AACA,iBAAa,KAAK,EAAE,OAAO,IAAI,OAAO,OAAO,KAAK,EAAE,CAAC;AAAA,EACvD;AAEA,MAAI,UAAyD;AAC7D,MAAI,cAAc;AAChB,UAAM,UAAU,aAAa,MAAM,GAAG;AACtC,UAAM,UAAU,QAAQ,CAAC;AACzB,UAAM,QAAQ,QAAQ,CAAC;AACvB,cAAU,EAAE,OAAO,SAAS,KAAK,UAAU,SAAS,SAAS,MAAM;AAAA,EACrE;AAEA,QAAM,QAAQ,aAAa,SAAS,YAAY,EAAE,IAAI;AAEtD,SAAO;AAAA,IACL,MAAS,GAAuB;AAC9B,UAAI,SAAS;AACb,iBAAW,EAAE,OAAO,IAAI,MAAM,KAAK,cAAc;AAC/C,iBAAS,OAAO,MAAM,OAAO,IAAI,KAA4B;AAAA,MAC/D;AACA,UAAI,SAAS;AACX,iBAAS,OAAO,QAAQ,QAAQ,OAAO,QAAQ,GAAG;AAAA,MACpD;AACA,aAAO;AAAA,IACT;AAAA,IACA;AAAA,EACF;AACF;AAEA,SAAS,OAAO,KAAsB;AACpC,MAAI,QAAQ,OAAQ,QAAO;AAC3B,MAAI,QAAQ,QAAS,QAAO;AAC5B,QAAM,IAAI,OAAO,GAAG;AACpB,MAAI,CAAC,MAAM,CAAC,KAAK,IAAI,KAAK,MAAM,GAAI,QAAO;AAC3C,SAAO;AACT;;;AD1EA,SAAS,KAAK,QAAgB,MAA6B;AACzD,SAAO;AAAA,IACL;AAAA,IACA,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,IAC9C,MAAM,KAAK,UAAU,IAAI;AAAA,EAC3B;AACF;AAEA,SAAS,aAAa,KAAiC;AAErD,QAAM,OAAO,IAAI,QAAQ,eAAe,KAAK,IAAI,QAAQ,eAAe;AACxE,MAAI,CAAC,MAAM,WAAW,SAAS,EAAG,QAAO;AACzC,SAAO,KAAK,MAAM,CAAC;AACrB;AAEO,SAAS,YAAY,OAAmB,MAAc,UAAwB,UAAkB;AACrG,WAAS,UAAU,UAA0B;AAG3C,QAAI,CAAC,SAAU,QAAO;AACtB,QAAI,aAAa,SAAU,QAAO;AAClC,QAAI,SAAS,WAAW,WAAW,GAAG,EAAG,QAAO,SAAS,MAAM,SAAS,MAAM;AAC9E,WAAO;AAAA,EACT;AAEA,SAAO,eAAe,MAAM,KAAyC;AACnE,UAAM,OAAO,UAAU,IAAI,QAAQ;AACnC,UAAM,SAAS,IAAI,OAAO,YAAY;AAItC,QAAI,WAAW,UAAU,SAAS,+BAA+B;AAC/D,UAAI;AACJ,UAAI;AAAE,eAAO,MAAM,IAAI,KAAK;AAAA,MAAE,QAAQ;AAAE,eAAO,KAAK,KAAK,EAAE,OAAO,eAAe,CAAC;AAAA,MAAE;AACpF,YAAM,aAAc,MAAkC;AACtD,UAAI,OAAO,eAAe,YAAY,CAAC,YAAY;AACjD,eAAO,KAAK,KAAK,EAAE,OAAO,sBAAsB,CAAC;AAAA,MACnD;AACA,UAAI;AACF,cAAMA,MAAK,UAAM,wBAAY,EAAE,OAAO,MAAM,QAAQ,WAAW,CAAC;AAChE,cAAMC,SAAQ,SAAS,OAAOD,GAAE;AAChC,eAAO,KAAK,KAAK,EAAE,OAAAC,OAAM,CAAC;AAAA,MAC5B,SAAS,KAAK;AACZ,YAAI,eAAe,4BAAiB;AAClC,iBAAO,KAAK,KAAK,EAAE,OAAO,mBAAmB,SAAS,IAAI,QAAQ,CAAC;AAAA,QACrE;AACA,eAAO,KAAK,KAAK,EAAE,OAAO,qBAAqB,CAAC;AAAA,MAClD;AAAA,IACF;AAEA,QAAI,WAAW,SAAS,SAAS,qBAAqB;AACpD,YAAMA,SAAQ,aAAa,GAAG;AAC9B,YAAM,SAASA,WAAU,QAAQ,SAAS,KAAKA,MAAK;AACpD,aAAO,KAAK,KAAK,EAAE,OAAO,CAAC;AAAA,IAC7B;AAEA,QAAI,WAAW,YAAY,SAAS,qBAAqB;AACvD,YAAMA,SAAQ,aAAa,GAAG;AAC9B,UAAI,CAACA,UAAS,CAAC,SAAS,KAAKA,MAAK,EAAG,QAAO,KAAK,KAAK,EAAE,OAAO,eAAe,CAAC;AAC/E,eAAS,OAAOA,MAAK;AACrB,aAAO,EAAE,QAAQ,KAAK,SAAS,CAAC,GAAG,MAAM,KAAK;AAAA,IAChD;AAIA,UAAM,QAAQ,aAAa,GAAG;AAC9B,UAAM,KAAK,QAAQ,SAAS,IAAI,KAAK,IAAI;AACzC,QAAI,CAAC,GAAI,QAAO,KAAK,KAAK,EAAE,OAAO,eAAe,CAAC;AAInD,QAAI,WAAW,SAAS,SAAS,WAAW;AAC1C,UAAI;AACF,YAAI,OAAO,MAAM,eAAe,YAAY;AAC1C,gBAAM,SAAS,MAAM,GAAG,qBAAqB;AAC7C,iBAAO,KAAK,KAAK,OAAO,IAAI,OAAK,EAAE,EAAE,CAAC;AAAA,QACxC;AACA,eAAO,KAAK,KAAK,CAAC,CAAC;AAAA,MACrB,QAAQ;AACN,eAAO,KAAK,KAAK,CAAC,CAAC;AAAA,MACrB;AAAA,IACF;AAGA,UAAM,cAAc,KAAK,MAAM,oDAAoD;AACnF,QAAI,aAAa;AACf,YAAM,YAAY,YAAY,CAAC;AAC/B,YAAM,WAAW,YAAY,CAAC;AAC9B,YAAM,KAAK,YAAY,CAAC;AACxB,UAAI,cAAc,UAAa,aAAa,UAAa,OAAO,QAAW;AACzE,eAAO,KAAK,KAAK,EAAE,OAAO,iBAAiB,CAAC;AAAA,MAC9C;AACA,UAAI;AACF,cAAM,QAAQ,MAAM,GAAG,UAAU,SAAS;AAC1C,cAAM,OAAO,MAAM,WAAoC,QAAQ;AAE/D,YAAI,WAAW,OAAO;AACpB,gBAAM,SAAS,MAAM,KAAK,IAAI,EAAE;AAChC,cAAI,CAAC,OAAQ,QAAO,KAAK,KAAK,EAAE,OAAO,YAAY,CAAC;AACpD,iBAAO,KAAK,KAAK,MAAM;AAAA,QACzB;AAEA,YAAI,WAAW,QAAQ;AACrB,cAAI;AACJ,cAAI;AAAE,mBAAO,MAAM,IAAI,KAAK;AAAA,UAAE,QAAQ;AAAE,mBAAO,KAAK,KAAK,EAAE,OAAO,eAAe,CAAC;AAAA,UAAE;AACpF,gBAAM,KAAK,IAAI,IAAI,IAA+B;AAClD,iBAAO,KAAK,KAAK,EAAE,IAAI,KAAK,CAAC;AAAA,QAC/B;AAEA,YAAI,WAAW,UAAU;AACvB,gBAAM,KAAK,OAAO,EAAE;AACpB,iBAAO,KAAK,KAAK,EAAE,IAAI,KAAK,CAAC;AAAA,QAC/B;AAEA,eAAO;AAAA,UACL,QAAQ;AAAA,UACR,SAAS,EAAE,gBAAgB,oBAAoB,OAAO,oBAAoB;AAAA,UAC1E,MAAM,KAAK,UAAU,EAAE,OAAO,qBAAqB,CAAC;AAAA,QACtD;AAAA,MACF,SAAS,KAAK;AACZ,YAAI,eAAe,iCAAuB,QAAO,KAAK,KAAK,EAAE,OAAO,YAAY,CAAC;AACjF,YAAI,eAAe,yBAAe,QAAO,KAAK,KAAK,EAAE,OAAO,YAAY,CAAC;AACzE,YAAI,eAAe,yBAAe,QAAO,KAAK,KAAK,EAAE,OAAO,WAAW,CAAC;AACxE,eAAO,KAAK,KAAK,EAAE,OAAO,iBAAiB,CAAC;AAAA,MAC9C;AAAA,IACF;AAGA,UAAM,YAAY,KAAK,MAAM,2CAA2C;AACxE,QAAI,WAAW;AACb,UAAI,WAAW,OAAO;AACpB,eAAO;AAAA,UACL,QAAQ;AAAA,UACR,SAAS,EAAE,gBAAgB,oBAAoB,OAAO,MAAM;AAAA,UAC5D,MAAM,KAAK,UAAU,EAAE,OAAO,qBAAqB,CAAC;AAAA,QACtD;AAAA,MACF;AACA,YAAM,YAAY,UAAU,CAAC;AAC7B,YAAM,WAAW,UAAU,CAAC;AAC5B,UAAI,cAAc,UAAa,aAAa,QAAW;AACrD,eAAO,KAAK,KAAK,EAAE,OAAO,iBAAiB,CAAC;AAAA,MAC9C;AACA,YAAM,SAAS,iBAAiB,IAAI,YAAY;AAChD,UAAI,OAAO,MAAO,QAAO,KAAK,KAAK,OAAO,KAAK;AAC/C,UAAI;AACF,cAAM,QAAQ,MAAM,GAAG,UAAU,SAAS;AAC1C,cAAM,OAAO,MAAM,WAAoC,QAAQ;AAC/D,YAAI,UAAU,OAAO,MAAM,KAAK,MAAM,CAAC,EAAE,QAAQ;AACjD,YAAI,OAAO,UAAU,KAAM,WAAU,QAAQ,MAAM,GAAG,OAAO,KAAK;AAClE,eAAO,KAAK,KAAK,OAAO;AAAA,MAC1B,SAAS,KAAK;AACZ,YAAI,eAAe,iCAAuB,QAAO,KAAK,KAAK,EAAE,OAAO,YAAY,CAAC;AACjF,eAAO,KAAK,KAAK,EAAE,OAAO,iBAAiB,CAAC;AAAA,MAC9C;AAAA,IACF;AAEA,WAAO,KAAK,KAAK,EAAE,OAAO,YAAY,CAAC;AAAA,EACzC;AACF;;;AFxHO,SAAS,kBAAkB,SAA+C;AAC/E,QAAM,WAAW,IAAI,aAAa,QAAQ,cAAc,GAAG;AAC3D,QAAM,QAAQ,YAAY,QAAQ,OAAO,QAAQ,MAAM,UAAU,QAAQ,YAAY,EAAE;AACvF,SAAO,EAAE,QAAQ,MAAM;AACzB;","names":["db","token"]}
package/dist/index.d.cts DELETED
@@ -1,41 +0,0 @@
1
- import { NoydbStore } from '@noy-db/hub';
2
-
3
- /**
4
- * **@noy-db/in-rest** — Framework-neutral REST API integration for noy-db.
5
- *
6
- * @example
7
- * ```ts
8
- * import { createRestHandler } from '@noy-db/in-rest'
9
- * import { honoAdapter } from '@noy-db/in-rest/hono'
10
- *
11
- * const handler = createRestHandler({ store, user: 'api' })
12
- * app.route('/api/noydb', honoAdapter(handler))
13
- * ```
14
- *
15
- * @packageDocumentation
16
- */
17
-
18
- interface RestRequest {
19
- readonly method: string;
20
- readonly pathname: string;
21
- readonly searchParams: URLSearchParams;
22
- readonly headers: Record<string, string>;
23
- json(): Promise<unknown>;
24
- }
25
- interface RestResponse {
26
- readonly status: number;
27
- readonly headers: Record<string, string>;
28
- readonly body: string | Uint8Array | null;
29
- }
30
- interface NoydbRestHandler {
31
- handle(req: RestRequest): Promise<RestResponse>;
32
- }
33
- interface RestHandlerOptions {
34
- readonly store: NoydbStore;
35
- readonly user: string;
36
- readonly ttlSeconds?: number;
37
- readonly basePath?: string;
38
- }
39
- declare function createRestHandler(options: RestHandlerOptions): NoydbRestHandler;
40
-
41
- export { type NoydbRestHandler, type RestHandlerOptions, type RestRequest, type RestResponse, createRestHandler };