@web-ts-toolkit/access-router 0.31.5 → 0.33.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +101 -37
- package/advanced.d.mts +12 -1444
- package/advanced.d.ts +12 -1444
- package/advanced.js +1167 -269
- package/advanced.mjs +1178 -269
- package/index.d.mts +93 -1264
- package/index.d.ts +93 -1264
- package/index.js +1465 -489
- package/index.mjs +1354 -388
- package/llms.txt +34 -11
- package/package.json +10 -5
- package/parsers-D9B9dS0p.d.mts +1702 -0
- package/parsers-D9B9dS0p.d.ts +1702 -0
- package/processors.d.mts +72 -1
- package/processors.d.ts +72 -1
- package/processors.js +61 -13
- package/processors.mjs +62 -14
package/README.md
CHANGED
|
@@ -25,54 +25,127 @@ Peer dependencies:
|
|
|
25
25
|
## Quick Start
|
|
26
26
|
|
|
27
27
|
```ts
|
|
28
|
-
import
|
|
28
|
+
import express from 'express';
|
|
29
|
+
import mongoose from 'mongoose';
|
|
30
|
+
import acl, { permissionsPlugin } from '@web-ts-toolkit/access-router';
|
|
29
31
|
|
|
32
|
+
// 1. Configure how request permissions are resolved globally.
|
|
30
33
|
acl.setGlobalOptions({
|
|
34
|
+
requestPermissionField: '_permissions',
|
|
31
35
|
globalPermissions(req) {
|
|
32
36
|
return req.headers.user === 'admin' ? ['isAdmin'] : [];
|
|
33
37
|
},
|
|
34
38
|
});
|
|
35
39
|
|
|
40
|
+
// 2. Register a Mongoose model and schema. The schema opts in to the
|
|
41
|
+
// permissions plugin so generated routers can enforce field access.
|
|
42
|
+
const userSchema = new mongoose.Schema({ name: String, role: String, public: Boolean });
|
|
43
|
+
userSchema.plugin(permissionsPlugin, { modelName: 'User' });
|
|
44
|
+
const UserModel = mongoose.model('User', userSchema);
|
|
45
|
+
|
|
46
|
+
// 3. Create routers. Pass either the model name or the mongoose.Model
|
|
47
|
+
// instance. Passing the instance preserves an explicit connection
|
|
48
|
+
// (useful for multi-connection setups) and registers it with the
|
|
49
|
+
// active runtime.
|
|
50
|
+
const userRouter = acl.createRouter('User', {
|
|
51
|
+
basePath: '/users',
|
|
52
|
+
operationAccess: { list: true, create: true, read: true, update: true, delete: true },
|
|
53
|
+
permissionSchema: { name: true, role: 'isAdmin', public: true },
|
|
54
|
+
});
|
|
55
|
+
|
|
36
56
|
const fruitRouter = acl.createDataRouter('fruit', {
|
|
37
57
|
basePath: '/fruit',
|
|
38
58
|
idField: 'id',
|
|
39
59
|
operationAccess: { list: true, read: true },
|
|
40
60
|
data: [{ id: 'apple', name: 'Apple', public: true }],
|
|
41
|
-
permissionSchema: {
|
|
42
|
-
id: true,
|
|
43
|
-
name: 'isAdmin',
|
|
44
|
-
public: true,
|
|
45
|
-
},
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
const userRouter = acl.createRouter('User', {
|
|
49
|
-
basePath: '/users',
|
|
61
|
+
permissionSchema: { id: true, name: 'isAdmin', public: true },
|
|
50
62
|
});
|
|
51
63
|
|
|
52
64
|
const docsRouter = acl.createOpenApiRouter({
|
|
53
65
|
title: 'Example API',
|
|
54
66
|
version: '1.0.0',
|
|
55
67
|
});
|
|
68
|
+
|
|
69
|
+
// 4. Mount routers under an Express app.
|
|
70
|
+
const app = express();
|
|
71
|
+
app.use(express.json());
|
|
72
|
+
app.use(userRouter.routes);
|
|
73
|
+
app.use(fruitRouter.routes);
|
|
74
|
+
app.use(docsRouter);
|
|
75
|
+
|
|
76
|
+
// 5. Connect to MongoDB before accepting traffic. A failed connection throws
|
|
77
|
+
// and exits before the server calls `app.listen`, so the service never
|
|
78
|
+
// publishes routes it cannot serve.
|
|
79
|
+
const port = Number(process.env.PORT ?? 3000);
|
|
80
|
+
const mongoUrl = process.env.MONGODB_URL ?? 'mongodb://localhost:27017/example';
|
|
81
|
+
try {
|
|
82
|
+
await mongoose.connect(mongoUrl);
|
|
83
|
+
} catch (err) {
|
|
84
|
+
console.error(`Failed to connect to MongoDB at ${mongoUrl}:`, err);
|
|
85
|
+
process.exit(1);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
app.listen(port, () => {
|
|
89
|
+
console.log(`API listening on http://localhost:${port}`);
|
|
90
|
+
});
|
|
56
91
|
```
|
|
57
92
|
|
|
58
93
|
## Main Exports
|
|
59
94
|
|
|
60
95
|
Root entrypoint (`@web-ts-toolkit/access-router`):
|
|
61
96
|
|
|
62
|
-
- default export `acl`
|
|
63
|
-
- `createAccessRuntime()`
|
|
64
|
-
- `
|
|
65
|
-
- `
|
|
66
|
-
- `guard(...)`
|
|
67
|
-
- `
|
|
68
|
-
- validation adapters
|
|
97
|
+
- default export `acl` — the default-runtime API (functions bound to the shared `AccessRuntime`)
|
|
98
|
+
- `createAccessRuntime()` — create an isolated runtime with its own options and model registry
|
|
99
|
+
- `AccessRuntime`, `RootRouter`, `ModelRouter`, `DataRouter` — router/runtime classes
|
|
100
|
+
- `registerModelInstance(name, model)`, `hasModelInstance(name)`, `getModelInstance(name)` — explicit runtime-owned model registry helpers
|
|
101
|
+
- `guard(...)` and `GuardModelCondition`, `GuardModelConditionID` types
|
|
102
|
+
- `combineRoutes(...)` and `createOpenApiRouter(runtime, options)` (note: prefer `acl.createOpenApiRouter(options)` for the default runtime)
|
|
103
|
+
- validation adapters: `defineRequestSchema(...)`, `fromZod(...)`, `fromYup(...)`, `fromJoi(...)`, `fromAjv(...)`, `fromStandardSchema(...)`, `fromValibot(...)`, `fromArkType(...)`, `fromIoTs(...)`, `fromSuperstruct(...)`, `fromVine(...)`
|
|
104
|
+
- option helpers: `setGlobalOptions`, `setGlobalOption`, `getGlobalOptions`, `getGlobalOption`, `setModelOptions`, `setModelOption`, `getModelOptions`, `getModelOption`, `getModelNames`, `getModelJsonSchema`, `setDefaultModelOptions`, `setDefaultModelOption`, `getDefaultModelOptions`, `getDefaultModelOption`
|
|
69
105
|
|
|
70
106
|
Subpath entrypoints:
|
|
71
107
|
|
|
72
|
-
- `@web-ts-toolkit/access-router/advanced` — runtime context
|
|
73
|
-
- `@web-ts-toolkit/access-router/processors` —
|
|
108
|
+
- `@web-ts-toolkit/access-router/advanced` — low-level runtime context, symbols (`MIDDLEWARE`, `PERMISSIONS`, ...), enums (`Codes`, `StatusCodes`), internals (`parseBody`, `parseQuery`, request schemas). Does NOT export `acl`, `defaultRuntime`, or router-creation helpers.
|
|
109
|
+
- `@web-ts-toolkit/access-router/processors` — `copyAndDepopulate` and its `ProcessCopy` / `CopyAndDepopulateOptions` types for transforming populated documents.
|
|
110
|
+
|
|
111
|
+
## Default runtime vs. isolated runtime
|
|
112
|
+
|
|
113
|
+
The default export `acl` is bound to a single shared `AccessRuntime`, which is fine for most services.
|
|
114
|
+
For tests, multi-tenant services, or libraries that must avoid global state, create an isolated runtime:
|
|
115
|
+
|
|
116
|
+
```ts
|
|
117
|
+
import { createAccessRuntime } from '@web-ts-toolkit/access-router';
|
|
118
|
+
|
|
119
|
+
const runtime = createAccessRuntime();
|
|
120
|
+
runtime.setGlobalOptions({ globalPermissions: () => [] });
|
|
121
|
+
|
|
122
|
+
// `runtime.createRouter(...)`, `runtime.createDataRouter(...)`,
|
|
123
|
+
// `runtime.createOpenApiRouter(...)`, `runtime.registerModelInstance(...)`, ...
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
Two isolated runtimes with the same model name resolve against their own model registry and options without interference.
|
|
127
|
+
|
|
128
|
+
## createRouter overloads
|
|
129
|
+
|
|
130
|
+
`createRouter(modelName, options)` — accept the Mongoose model name registered with `mongoose.model(name, schema)`.
|
|
131
|
+
|
|
132
|
+
`createRouter(model, options)` — accept a `mongoose.Model` instance directly. The instance is registered with the active runtime's registry, so a model attached to a non-default `mongoose.createConnection()` works without polluting the global registry.
|
|
133
|
+
|
|
134
|
+
```ts
|
|
135
|
+
import mongoose from 'mongoose';
|
|
136
|
+
import acl, { permissionsPlugin } from '@web-ts-toolkit/access-router';
|
|
74
137
|
|
|
75
|
-
|
|
138
|
+
// `uri` is the MongoDB connection string for the non-default connection.
|
|
139
|
+
const uri = process.env.MONGODB_URL_TENANT ?? 'mongodb://localhost:27017/tenant';
|
|
140
|
+
const conn = await mongoose.createConnection(uri).asPromise();
|
|
141
|
+
const schema = new mongoose.Schema({ name: String });
|
|
142
|
+
schema.plugin(permissionsPlugin, { modelName: 'TenantUser' });
|
|
143
|
+
const TenantUser = conn.model('TenantUser', schema);
|
|
144
|
+
|
|
145
|
+
const tenantRouter = acl.createRouter(TenantUser, { basePath: '/tenant-users' });
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
## Import styles
|
|
76
149
|
|
|
77
150
|
The package ships both a default export and named exports:
|
|
78
151
|
|
|
@@ -81,32 +154,23 @@ The package ships both a default export and named exports:
|
|
|
81
154
|
import acl from '@web-ts-toolkit/access-router';
|
|
82
155
|
|
|
83
156
|
// named exports (useful when you only need specific helpers)
|
|
84
|
-
import {
|
|
157
|
+
import { createAccessRuntime, fromZod } from '@web-ts-toolkit/access-router';
|
|
85
158
|
```
|
|
86
159
|
|
|
87
160
|
### Subpath import example
|
|
88
161
|
|
|
89
162
|
```ts
|
|
90
|
-
import { setGlobalOptions } from '@web-ts-toolkit/access-router';
|
|
91
163
|
import { copyAndDepopulate } from '@web-ts-toolkit/access-router/processors';
|
|
92
164
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
},
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
const depopulated = copyAndDepopulate({ items: [{ _id: 'a1', name: 'Apple' }] }, [{ src: 'items', dest: 'items' }]);
|
|
165
|
+
const { items } = copyAndDepopulate(
|
|
166
|
+
{ items: [{ _id: 'a1', name: 'Apple' }] },
|
|
167
|
+
[{ src: 'items', dest: 'itemsSnapshot' }],
|
|
168
|
+
{ mutable: false },
|
|
169
|
+
);
|
|
170
|
+
// `items` is now `['a1']`; `itemsSnapshot` holds the original objects.
|
|
100
171
|
```
|
|
101
172
|
|
|
102
173
|
## Documentation
|
|
103
174
|
|
|
104
|
-
Full package documentation lives in `website/docs/packages/access-router/`.
|
|
105
|
-
|
|
106
175
|
- live docs: https://web-ts-toolkit.pages.dev/docs/packages/access-router
|
|
107
|
-
-
|
|
108
|
-
- routing: `website/docs/packages/access-router/routing.mdx`
|
|
109
|
-
- configuration: `website/docs/packages/access-router/configuration.mdx`
|
|
110
|
-
- hooks: `website/docs/packages/access-router/hooks.mdx`
|
|
111
|
-
- validation: `website/docs/packages/access-router/validation.mdx`
|
|
112
|
-
- OpenAPI: `website/docs/packages/access-router/openapi.mdx`
|
|
176
|
+
- source docs live in the website/docs package of this repository; paths may move as the docs site evolves.
|