@prosopo/api-route 2.6.52 → 2.6.53

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,5 +1,5 @@
1
1
 
2
- > @prosopo/api-route@2.6.52 build:cjs
2
+ > @prosopo/api-route@2.6.53 build:cjs
3
3
  > NODE_ENV=${NODE_ENV:-development}; vite build --config vite.cjs.config.ts --mode $NODE_ENV
4
4
 
5
5
  ViteCommonJSConfig: .
@@ -10,14 +10,16 @@ ViteCommonJSConfig: .
10
10
  ]
11
11
  }
12
12
  { externals: [ '@prosopo/logger', '@prosopo/util' ] }
13
- vite v6.4.1 building SSR bundle for production...
13
+ The plugin "vite-tsconfig-paths" is detected. Vite now supports tsconfig paths resolution natively via the resolve.tsconfigPaths option. You can remove the plugin and set resolve.tsconfigPaths: true in your Vite config instead.
14
+ vite v8.1.5 building ssr environment for production...
14
15
  Bundle build started
15
- transforming...
16
- Build end
17
- ✓ 4 modules transformed.
16
+ 
17
+ ✓ 5 modules transformed.
18
18
  rendering chunks...
19
- dist/cjs/.export.cjs 0.01 kB
20
- dist/cjs/endpoint/.export.cjs 0.25 kB
21
- dist/cjs/index.cjs 0.32 kB
22
- dist/cjs/endpoint/apiEndpointResponseStatus.cjs 0.47 kB
23
- ✓ built in 122ms
19
+ computing gzip size...
20
+ dist/cjs/.export.cjs 0.00 kB │ gzip: 0.02 kB
21
+ dist/cjs/endpoint/.export.cjs 0.18 kB │ gzip: 0.09 kB
22
+ dist/cjs/index.cjs 0.26 kB │ gzip: 0.15 kB
23
+ dist/cjs/endpoint/apiEndpointResponseStatus.cjs 0.43 kB │ gzip: 0.19 kB
24
+
25
+ ✓ built in 64ms
@@ -1,20 +1,20 @@
1
1
 
2
- > @prosopo/api-route@2.6.52 build:tsc
2
+ > @prosopo/api-route@2.6.53 build:tsc
3
3
  > tsc --build --verbose
4
4
 
5
- 1:21:07 PM - Projects in this build:
5
+ 8:58:52 PM - Projects in this build:
6
6
  * ../../dev/config/tsconfig.json
7
7
  * ../util/tsconfig.json
8
8
  * ../logger/tsconfig.json
9
9
  * tsconfig.json
10
10
 
11
- 1:21:08 PM - Project '../../dev/config/tsconfig.json' is up to date because newest input '../../dev/config/src/webpack/webpack.config.ts' is older than output '../../dev/config/tsconfig.tsbuildinfo'
11
+ 8:58:52 PM - Project '../../dev/config/tsconfig.json' is up to date because newest input '../../dev/config/src/webpack/webpack.config.ts' is older than output '../../dev/config/tsconfig.tsbuildinfo'
12
12
 
13
- 1:21:08 PM - Project '../util/tsconfig.json' is up to date because newest input '../util/src/url.ts' is older than output '../util/tsconfig.tsbuildinfo'
13
+ 8:58:52 PM - Project '../util/tsconfig.json' is up to date because newest input '../util/src/url.ts' is older than output '../util/tsconfig.tsbuildinfo'
14
14
 
15
- 1:21:08 PM - Project '../logger/tsconfig.json' is up to date because newest input '../logger/src/index.ts' is older than output '../logger/tsconfig.tsbuildinfo'
15
+ 8:58:52 PM - Project '../logger/tsconfig.json' is up to date because newest input '../logger/src/index.ts' is older than output '../logger/tsconfig.tsbuildinfo'
16
16
 
17
- 1:21:08 PM - Project 'tsconfig.json' is out of date because output file 'tsconfig.tsbuildinfo' does not exist
17
+ 8:58:52 PM - Project 'tsconfig.json' is out of date because output file 'tsconfig.tsbuildinfo' does not exist
18
18
 
19
- 1:21:08 PM - Building project '/home/runner/work/captcha/captcha/packages/api-route/tsconfig.json'...
19
+ 8:58:52 PM - Building project '/home/runner/work/captcha/captcha/packages/api-route/tsconfig.json'...
20
20
 
@@ -1,9 +1,9 @@
1
1
 
2
- > @prosopo/api-route@2.6.52 build
2
+ > @prosopo/api-route@2.6.53 build
3
3
  > npm run build:cross-env -- --mode ${NODE_ENV:-development}
4
4
 
5
5
 
6
- > @prosopo/api-route@2.6.52 build:cross-env
6
+ > @prosopo/api-route@2.6.53 build:cross-env
7
7
  > vite build --config vite.esm.config.ts --mode production
8
8
 
9
9
  ViteEsmConfig: .
@@ -14,14 +14,17 @@ ViteEsmConfig: .
14
14
  ]
15
15
  }
16
16
  { externals: [ '@prosopo/logger', '@prosopo/util' ] }
17
- vite v6.4.1 building SSR bundle for production...
17
+ The plugin "vite-tsconfig-paths" is detected. Vite now supports tsconfig paths resolution natively via the resolve.tsconfigPaths option. You can remove the plugin and set resolve.tsconfigPaths: true in your Vite config instead.
18
+ vite v8.1.5 building ssr environment for production...
18
19
  Bundle build started
19
- transforming...
20
- Build end
21
- ✓ 4 modules transformed.
20
+ 
21
+ ✓ 5 modules transformed.
22
22
  rendering chunks...
23
- dist/.export.js 0.00 kB
24
- dist/endpoint/.export.js 0.12 kB
25
- dist/index.js 0.18 kB
26
- dist/endpoint/apiEndpointResponseStatus.js 0.36 kB
27
- ✓ built in 119ms
23
+ computing gzip size...
24
+ dist/.export.js 0.01 kB │ gzip: 0.03 kB
25
+ dist/_virtual/_rolldown/runtime.js 0.04 kB │ gzip: 0.06 kB
26
+ dist/endpoint/.export.js 0.11 kB │ gzip: 0.08 kB
27
+ dist/index.js 0.16 kB │ gzip: 0.11 kB
28
+ dist/endpoint/apiEndpointResponseStatus.js 0.41 kB │ gzip: 0.19 kB
29
+
30
+ ✓ built in 88ms
package/CHANGELOG.md CHANGED
@@ -1,5 +1,23 @@
1
1
  # @prosopo/api-route
2
2
 
3
+ ## 2.6.53
4
+ ### Patch Changes
5
+
6
+ - a58d007: test(api-route): cover the endpoint contract, and export ApiRouteLimit
7
+
8
+ This package ships exactly one runtime value, so most of its business logic
9
+ lives in its types — notably the conditional signature of
10
+ `ApiEndpoint.processRequest`, which gives an endpoint with a schema its parsed
11
+ arguments and an endpoint without one no arguments at all. Both branches are
12
+ now covered by type tests, alongside runtime tests for the response status enum
13
+ (its strings cross the wire and are compared literally by clients) and for the
14
+ package's export surface.
15
+
16
+ Writing them surfaced a gap: `ApiRouteLimit` was declared but never re-exported,
17
+ so a consumer assembling an `ApiRouteLimits` record entry by entry had no way to
18
+ name what it was building and had to redeclare the shape. It is now exported.
19
+ - @prosopo/logger@2.0.4
20
+
3
21
  ## 2.6.52
4
22
  ### Patch Changes
5
23
 
package/dist/.export.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- export type { ApiRoutes, ApiRoutesProvider, ApiRouteLimits, } from "./apiRoutes.js";
1
+ export type { ApiRoutes, ApiRoutesProvider, ApiRouteLimit, ApiRouteLimits, } from "./apiRoutes.js";
2
2
  //# sourceMappingURL=.export.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":".export.d.ts","sourceRoot":"","sources":["../src/.export.ts"],"names":[],"mappings":"AAcA,YAAY,EACX,SAAS,EACT,iBAAiB,EACjB,cAAc,GACd,MAAM,gBAAgB,CAAC"}
1
+ {"version":3,"file":".export.d.ts","sourceRoot":"","sources":["../src/.export.ts"],"names":[],"mappings":"AAcA,YAAY,EACX,SAAS,EACT,iBAAiB,EAIjB,aAAa,EACb,cAAc,GACd,MAAM,gBAAgB,CAAC"}
package/dist/.export.js CHANGED
@@ -1 +1 @@
1
-
1
+ export {};
@@ -0,0 +1,3 @@
1
+ import "node:module";
2
+ //#endregion
3
+ export {};
@@ -1 +0,0 @@
1
- "use strict";
@@ -1,4 +1,2 @@
1
- "use strict";
2
- Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
- const apiEndpointResponseStatus = require("./apiEndpointResponseStatus.cjs");
4
- exports.ApiEndpointResponseStatus = apiEndpointResponseStatus.ApiEndpointResponseStatus;
1
+ const require_apiEndpointResponseStatus = require("./apiEndpointResponseStatus.cjs");
2
+ exports.ApiEndpointResponseStatus = require_apiEndpointResponseStatus.ApiEndpointResponseStatus;
@@ -1,9 +1,9 @@
1
- "use strict";
2
- Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
- var ApiEndpointResponseStatus = /* @__PURE__ */ ((ApiEndpointResponseStatus2) => {
4
- ApiEndpointResponseStatus2["SUCCESS"] = "SUCCESS";
5
- ApiEndpointResponseStatus2["FAIL"] = "FAIL";
6
- ApiEndpointResponseStatus2["PROCESSING"] = "PROCESSING";
7
- return ApiEndpointResponseStatus2;
8
- })(ApiEndpointResponseStatus || {});
1
+ //#region src/endpoint/apiEndpointResponseStatus.ts
2
+ var ApiEndpointResponseStatus = /* @__PURE__ */ function(ApiEndpointResponseStatus) {
3
+ ApiEndpointResponseStatus["SUCCESS"] = "SUCCESS";
4
+ ApiEndpointResponseStatus["FAIL"] = "FAIL";
5
+ ApiEndpointResponseStatus["PROCESSING"] = "PROCESSING";
6
+ return ApiEndpointResponseStatus;
7
+ }(ApiEndpointResponseStatus || {});
8
+ //#endregion
9
9
  exports.ApiEndpointResponseStatus = ApiEndpointResponseStatus;
@@ -1,6 +1,3 @@
1
- "use strict";
2
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
- require("./.export.cjs");
4
- require("./endpoint/.export.cjs");
5
- const apiEndpointResponseStatus = require("./endpoint/apiEndpointResponseStatus.cjs");
6
- exports.ApiEndpointResponseStatus = apiEndpointResponseStatus.ApiEndpointResponseStatus;
2
+ const require_apiEndpointResponseStatus = require("./endpoint/apiEndpointResponseStatus.cjs");
3
+ exports.ApiEndpointResponseStatus = require_apiEndpointResponseStatus.ApiEndpointResponseStatus;
@@ -1,4 +1,2 @@
1
1
  import { ApiEndpointResponseStatus } from "./apiEndpointResponseStatus.js";
2
- export {
3
- ApiEndpointResponseStatus
4
- };
2
+ export { ApiEndpointResponseStatus };
@@ -1,9 +1,9 @@
1
- var ApiEndpointResponseStatus = /* @__PURE__ */ ((ApiEndpointResponseStatus2) => {
2
- ApiEndpointResponseStatus2["SUCCESS"] = "SUCCESS";
3
- ApiEndpointResponseStatus2["FAIL"] = "FAIL";
4
- ApiEndpointResponseStatus2["PROCESSING"] = "PROCESSING";
5
- return ApiEndpointResponseStatus2;
6
- })(ApiEndpointResponseStatus || {});
7
- export {
8
- ApiEndpointResponseStatus
9
- };
1
+ //#region src/endpoint/apiEndpointResponseStatus.ts
2
+ var ApiEndpointResponseStatus = /* @__PURE__ */ function(ApiEndpointResponseStatus) {
3
+ ApiEndpointResponseStatus["SUCCESS"] = "SUCCESS";
4
+ ApiEndpointResponseStatus["FAIL"] = "FAIL";
5
+ ApiEndpointResponseStatus["PROCESSING"] = "PROCESSING";
6
+ return ApiEndpointResponseStatus;
7
+ }(ApiEndpointResponseStatus || {});
8
+ //#endregion
9
+ export { ApiEndpointResponseStatus };
package/dist/index.js CHANGED
@@ -1,6 +1,3 @@
1
- import "./.export.js";
2
- import "./endpoint/.export.js";
1
+ import "./_virtual/_rolldown/runtime.js";
3
2
  import { ApiEndpointResponseStatus } from "./endpoint/apiEndpointResponseStatus.js";
4
- export {
5
- ApiEndpointResponseStatus
6
- };
3
+ export { ApiEndpointResponseStatus };
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=apiRoute.test-d.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"apiRoute.test-d.d.ts","sourceRoot":"","sources":["../../src/tests/apiRoute.test-d.ts"],"names":[],"mappings":""}
@@ -0,0 +1,126 @@
1
+ import { assertType, describe, expectTypeOf, it } from "vitest";
2
+ import { ApiEndpointResponseStatus } from "../index.js";
3
+ describe("ApiEndpoint.processRequest", () => {
4
+ it("takes the parsed arguments when the endpoint declares a schema", () => {
5
+ expectTypeOf().parameters.toEqualTypeOf();
6
+ });
7
+ it("takes no arguments at all when the schema is undefined", () => {
8
+ expectTypeOf().parameters.toEqualTypeOf();
9
+ });
10
+ it("keeps the logger optional on both branches", () => {
11
+ const withArgs = async () => ({
12
+ status: ApiEndpointResponseStatus.SUCCESS,
13
+ });
14
+ expectTypeOf(withArgs).toBeCallableWith({ siteKey: "abc" });
15
+ const withoutArgs = async () => ({
16
+ status: ApiEndpointResponseStatus.SUCCESS,
17
+ });
18
+ expectTypeOf(withoutArgs).toBeCallableWith();
19
+ });
20
+ it("always resolves to a response, never to void", () => {
21
+ expectTypeOf().returns.toEqualTypeOf();
22
+ expectTypeOf().returns.toEqualTypeOf();
23
+ });
24
+ it("rejects arguments that do not match the declared schema", () => {
25
+ const endpoint = {
26
+ getRequestArgsSchema: () => {
27
+ throw new Error("not called");
28
+ },
29
+ processRequest: async () => ({
30
+ status: ApiEndpointResponseStatus.SUCCESS,
31
+ }),
32
+ };
33
+ endpoint.processRequest({});
34
+ });
35
+ it("rejects an argument-free endpoint being called with arguments", () => {
36
+ const endpoint = {
37
+ getRequestArgsSchema: () => undefined,
38
+ processRequest: async () => ({
39
+ status: ApiEndpointResponseStatus.SUCCESS,
40
+ }),
41
+ };
42
+ endpoint.processRequest({ siteKey: "abc" });
43
+ });
44
+ });
45
+ describe("ApiEndpoint.getRequestArgsSchema", () => {
46
+ it("returns exactly the schema the endpoint was parameterised with", () => {
47
+ expectTypeOf().returns.toEqualTypeOf();
48
+ expectTypeOf().returns.toEqualTypeOf();
49
+ });
50
+ it("takes no arguments", () => {
51
+ expectTypeOf().parameters.toEqualTypeOf();
52
+ });
53
+ });
54
+ describe("ApiEndpointResponse", () => {
55
+ it("requires a status and nothing else", () => {
56
+ assertType({
57
+ status: ApiEndpointResponseStatus.SUCCESS,
58
+ });
59
+ assertType({ data: {} });
60
+ });
61
+ it("keeps data and error independently optional", () => {
62
+ expectTypeOf().toEqualTypeOf();
63
+ expectTypeOf().toEqualTypeOf();
64
+ });
65
+ it("types the status as the enum, not a bare string", () => {
66
+ expectTypeOf().toEqualTypeOf();
67
+ assertType({ status: "OK" });
68
+ });
69
+ it("rejects an error that is not a string", () => {
70
+ assertType({
71
+ status: ApiEndpointResponseStatus.FAIL,
72
+ error: new Error("boom"),
73
+ });
74
+ });
75
+ });
76
+ describe("ApiRoutes", () => {
77
+ it("is keyed by route string and valued by endpoints of any schema", () => {
78
+ expectTypeOf().toEqualTypeOf();
79
+ });
80
+ it("accepts an empty record, for a provider with no endpoints yet", () => {
81
+ assertType({});
82
+ });
83
+ it("rejects a plain function in place of an endpoint", () => {
84
+ assertType({ "/x": async () => { } });
85
+ });
86
+ });
87
+ describe("ApiRoutesProvider", () => {
88
+ it("exposes the routes through a method, not a property", () => {
89
+ expectTypeOf().toEqualTypeOf();
90
+ });
91
+ });
92
+ describe("ApiRouteLimits", () => {
93
+ it("requires a limit for every member of the route enum", () => {
94
+ let Route;
95
+ (function (Route) {
96
+ Route["Verify"] = "verify";
97
+ Route["Submit"] = "submit";
98
+ })(Route || (Route = {}));
99
+ assertType({
100
+ [Route.Verify]: { windowMs: 1000, limit: 5 },
101
+ [Route.Submit]: { windowMs: 1000, limit: 5 },
102
+ });
103
+ assertType({
104
+ [Route.Verify]: { windowMs: 1000, limit: 5 },
105
+ });
106
+ });
107
+ it("requires both the window and the count on each limit", () => {
108
+ assertType({
109
+ verify: { windowMs: 1000 },
110
+ });
111
+ assertType({
112
+ verify: { limit: 5 },
113
+ });
114
+ });
115
+ it("exposes the entry type, so a consumer can name one limit", () => {
116
+ expectTypeOf().toEqualTypeOf();
117
+ assertType({ windowMs: 1000, limit: 5 });
118
+ });
119
+ it("works with a numeric route enum as well as a string one", () => {
120
+ assertType({
121
+ 0: { windowMs: 1000, limit: 5 },
122
+ 1: { windowMs: 1000, limit: 5 },
123
+ });
124
+ });
125
+ });
126
+ //# sourceMappingURL=apiRoute.test-d.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"apiRoute.test-d.js","sourceRoot":"","sources":["../../src/tests/apiRoute.test-d.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=apiRoute.unit.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"apiRoute.unit.test.d.ts","sourceRoot":"","sources":["../../src/tests/apiRoute.unit.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,102 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { z } from "zod";
3
+ import * as api from "../index.js";
4
+ import { ApiEndpointResponseStatus } from "../index.js";
5
+ describe("ApiEndpointResponseStatus", () => {
6
+ it("keeps the exact strings clients compare against", () => {
7
+ expect(ApiEndpointResponseStatus.SUCCESS).toBe("SUCCESS");
8
+ expect(ApiEndpointResponseStatus.FAIL).toBe("FAIL");
9
+ expect(ApiEndpointResponseStatus.PROCESSING).toBe("PROCESSING");
10
+ });
11
+ it("declares exactly three statuses", () => {
12
+ expect(Object.keys(ApiEndpointResponseStatus)).toEqual([
13
+ "SUCCESS",
14
+ "FAIL",
15
+ "PROCESSING",
16
+ ]);
17
+ });
18
+ it("is a string enum, so it has no reverse numeric mapping", () => {
19
+ expect(Object.values(ApiEndpointResponseStatus)).toEqual([
20
+ "SUCCESS",
21
+ "FAIL",
22
+ "PROCESSING",
23
+ ]);
24
+ });
25
+ it("distinguishes failure from a still-running request", () => {
26
+ expect(ApiEndpointResponseStatus.PROCESSING).not.toBe(ApiEndpointResponseStatus.FAIL);
27
+ expect(ApiEndpointResponseStatus.PROCESSING).not.toBe(ApiEndpointResponseStatus.SUCCESS);
28
+ });
29
+ });
30
+ describe("public export surface", () => {
31
+ it("re-exports the status enum from the package root", () => {
32
+ expect(api.ApiEndpointResponseStatus).toBe(ApiEndpointResponseStatus);
33
+ });
34
+ it("ships the enum as its only runtime export", () => {
35
+ expect(Object.keys(api)).toEqual(["ApiEndpointResponseStatus"]);
36
+ });
37
+ });
38
+ describe("endpoint contract", () => {
39
+ const schema = z.object({ siteKey: z.string() });
40
+ const endpointWithArgs = {
41
+ getRequestArgsSchema: () => schema,
42
+ processRequest: async (args) => ({
43
+ status: ApiEndpointResponseStatus.SUCCESS,
44
+ data: { siteKey: args.siteKey },
45
+ }),
46
+ };
47
+ const endpointWithoutArgs = {
48
+ getRequestArgsSchema: () => undefined,
49
+ processRequest: async () => ({
50
+ status: ApiEndpointResponseStatus.SUCCESS,
51
+ }),
52
+ };
53
+ it("lets an implementation validate its own arguments with its schema", () => {
54
+ const parsed = endpointWithArgs
55
+ .getRequestArgsSchema()
56
+ .safeParse({ siteKey: "abc" });
57
+ expect(parsed.success).toBe(true);
58
+ });
59
+ it("rejects arguments the endpoint's own schema does not accept", () => {
60
+ const parsed = endpointWithArgs.getRequestArgsSchema().safeParse({});
61
+ expect(parsed.success).toBe(false);
62
+ });
63
+ it("allows an endpoint that takes no arguments at all", async () => {
64
+ expect(endpointWithoutArgs.getRequestArgsSchema()).toBeUndefined();
65
+ await expect(endpointWithoutArgs.processRequest()).resolves.toEqual({
66
+ status: ApiEndpointResponseStatus.SUCCESS,
67
+ });
68
+ });
69
+ it("carries the request arguments through to the response", async () => {
70
+ await expect(endpointWithArgs.processRequest({ siteKey: "abc" })).resolves.toEqual({
71
+ status: ApiEndpointResponseStatus.SUCCESS,
72
+ data: { siteKey: "abc" },
73
+ });
74
+ });
75
+ it("permits a response with neither data nor error", async () => {
76
+ const response = await endpointWithoutArgs.processRequest();
77
+ expect(response.data).toBeUndefined();
78
+ expect(response.error).toBeUndefined();
79
+ });
80
+ it("holds endpoints with differing schemas in one routes record", () => {
81
+ const routes = {
82
+ "/with": endpointWithArgs,
83
+ "/without": endpointWithoutArgs,
84
+ };
85
+ const provider = { getRoutes: () => routes };
86
+ expect(Object.keys(provider.getRoutes())).toEqual(["/with", "/without"]);
87
+ });
88
+ it("tolerates a provider that exposes no routes", () => {
89
+ const provider = { getRoutes: () => ({}) };
90
+ expect(Object.keys(provider.getRoutes())).toHaveLength(0);
91
+ });
92
+ it("surfaces a rejection rather than swallowing it into a FAIL response", async () => {
93
+ const throwing = {
94
+ getRequestArgsSchema: () => undefined,
95
+ processRequest: async () => {
96
+ throw new Error("boom");
97
+ },
98
+ };
99
+ await expect(throwing.processRequest()).rejects.toThrow("boom");
100
+ });
101
+ });
102
+ //# sourceMappingURL=apiRoute.unit.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"apiRoute.unit.test.js","sourceRoot":"","sources":["../../src/tests/apiRoute.unit.test.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@prosopo/api-route",
3
- "version": "2.6.52",
3
+ "version": "2.6.53",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "type": "module",
@@ -21,16 +21,21 @@
21
21
  "build:cross-env": "vite build --config vite.esm.config.ts",
22
22
  "build:tsc": "tsc --build --verbose",
23
23
  "build:cjs": "NODE_ENV=${NODE_ENV:-development}; vite build --config vite.cjs.config.ts --mode $NODE_ENV",
24
- "typecheck": "tsc --project tsconfig.types.json"
24
+ "typecheck": "tsc --project tsconfig.types.json",
25
+ "test": "NODE_ENV=${NODE_ENV:-test}; npx vitest run --config ./vite.test.config.ts",
26
+ "test:watch": "NODE_ENV=${NODE_ENV:-test}; npx vitest watch --config ./vite.test.config.ts"
25
27
  },
26
28
  "dependencies": {
27
- "@prosopo/logger": "2.0.3",
29
+ "@prosopo/logger": "2.0.4",
28
30
  "zod": "3.23.8"
29
31
  },
30
32
  "devDependencies": {
31
- "@prosopo/config": "3.3.4",
33
+ "@prosopo/config": "3.3.5",
32
34
  "@types/node": "22.10.2",
33
- "del-cli": "6.0.0"
35
+ "@vitest/coverage-v8": "4.1.10",
36
+ "del-cli": "6.0.0",
37
+ "vite": "8.1.5",
38
+ "vitest": "4.1.10"
34
39
  },
35
40
  "author": "PROSOPO LIMITED <info@prosopo.io>",
36
41
  "license": "Apache-2.0",
package/src/.export.ts CHANGED
@@ -15,5 +15,9 @@
15
15
  export type {
16
16
  ApiRoutes,
17
17
  ApiRoutesProvider,
18
+ // ApiRouteLimit is the value type of an ApiRouteLimits record: without it,
19
+ // a consumer building one entry at a time has no way to name what it is
20
+ // building, and has to redeclare the shape.
21
+ ApiRouteLimit,
18
22
  ApiRouteLimits,
19
23
  } from "./apiRoutes.js";