@guren/server 0.2.0-alpha.7 → 1.0.0-rc.9
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/dist/Application-DtWDHXr1.d.ts +2110 -0
- package/dist/BroadcastManager-AkIWUGJo.d.ts +466 -0
- package/dist/CacheManager-BkvHEOZX.d.ts +244 -0
- package/dist/ConsoleKernel-CqCVrdZs.d.ts +207 -0
- package/dist/EventManager-CmIoLt7r.d.ts +207 -0
- package/dist/Gate-CNkBYf8m.d.ts +268 -0
- package/dist/HealthManager-DUyMIzsZ.d.ts +141 -0
- package/dist/I18nManager-Dtgzsf5n.d.ts +270 -0
- package/dist/LogManager-7mxnkaPM.d.ts +256 -0
- package/dist/MailManager-DpMvYiP9.d.ts +292 -0
- package/dist/Scheduler-BstvSca7.d.ts +469 -0
- package/dist/StorageManager-oZTHqaza.d.ts +337 -0
- package/dist/api-token-JOif2CtG.d.ts +1792 -0
- package/dist/app-key-CsBfRC_Q.d.ts +214 -0
- package/dist/auth/index.d.ts +418 -0
- package/dist/auth/index.js +6742 -0
- package/dist/authorization/index.d.ts +129 -0
- package/dist/authorization/index.js +621 -0
- package/dist/broadcasting/index.d.ts +233 -0
- package/dist/broadcasting/index.js +907 -0
- package/dist/cache/index.d.ts +233 -0
- package/dist/cache/index.js +817 -0
- package/dist/encryption/index.d.ts +222 -0
- package/dist/encryption/index.js +602 -0
- package/dist/events/index.d.ts +155 -0
- package/dist/events/index.js +330 -0
- package/dist/health/index.d.ts +185 -0
- package/dist/health/index.js +379 -0
- package/dist/i18n/index.d.ts +101 -0
- package/dist/i18n/index.js +597 -0
- package/dist/index-9_Jzj5jo.d.ts +7 -0
- package/dist/index.d.ts +2628 -619
- package/dist/index.js +22229 -3116
- package/dist/lambda/index.d.ts +156 -0
- package/dist/lambda/index.js +91 -0
- package/dist/logging/index.d.ts +50 -0
- package/dist/logging/index.js +557 -0
- package/dist/mail/index.d.ts +288 -0
- package/dist/mail/index.js +695 -0
- package/dist/mcp/index.d.ts +139 -0
- package/dist/mcp/index.js +382 -0
- package/dist/notifications/index.d.ts +271 -0
- package/dist/notifications/index.js +741 -0
- package/dist/queue/index.d.ts +423 -0
- package/dist/queue/index.js +958 -0
- package/dist/runtime/index.d.ts +93 -0
- package/dist/runtime/index.js +834 -0
- package/dist/scheduling/index.d.ts +41 -0
- package/dist/scheduling/index.js +836 -0
- package/dist/storage/index.d.ts +196 -0
- package/dist/storage/index.js +832 -0
- package/dist/vite/index.js +203 -3
- package/package.json +93 -6
- package/dist/chunk-FK2XQSBF.js +0 -160
|
@@ -0,0 +1,621 @@
|
|
|
1
|
+
// src/errors/HttpException.ts
|
|
2
|
+
var HttpException = class _HttpException extends Error {
|
|
3
|
+
/**
|
|
4
|
+
* HTTP status code.
|
|
5
|
+
*/
|
|
6
|
+
statusCode;
|
|
7
|
+
/**
|
|
8
|
+
* Validation or field-specific errors.
|
|
9
|
+
*/
|
|
10
|
+
errors;
|
|
11
|
+
/**
|
|
12
|
+
* Additional error data.
|
|
13
|
+
*/
|
|
14
|
+
data;
|
|
15
|
+
constructor(statusCode, message, errors, data) {
|
|
16
|
+
super(message);
|
|
17
|
+
this.name = this.constructor.name;
|
|
18
|
+
this.statusCode = statusCode;
|
|
19
|
+
this.errors = errors;
|
|
20
|
+
this.data = data;
|
|
21
|
+
if (Error.captureStackTrace) {
|
|
22
|
+
Error.captureStackTrace(this, this.constructor);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Convert to response format.
|
|
27
|
+
*/
|
|
28
|
+
toResponse(debug = false) {
|
|
29
|
+
const body = {
|
|
30
|
+
message: this.message
|
|
31
|
+
};
|
|
32
|
+
if (this.errors) {
|
|
33
|
+
body.errors = this.errors;
|
|
34
|
+
}
|
|
35
|
+
if (debug) {
|
|
36
|
+
body.exception = this.name;
|
|
37
|
+
body.stack = this.stack;
|
|
38
|
+
}
|
|
39
|
+
return {
|
|
40
|
+
status: this.statusCode,
|
|
41
|
+
body
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Convert to JSON.
|
|
46
|
+
*/
|
|
47
|
+
toJSON() {
|
|
48
|
+
return {
|
|
49
|
+
name: this.name,
|
|
50
|
+
message: this.message,
|
|
51
|
+
statusCode: this.statusCode,
|
|
52
|
+
errors: this.errors,
|
|
53
|
+
data: this.data
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
// Factory methods
|
|
57
|
+
/**
|
|
58
|
+
* Create a 400 Bad Request exception.
|
|
59
|
+
*/
|
|
60
|
+
static badRequest(message = "Bad Request") {
|
|
61
|
+
return new _HttpException(400, message);
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Create a 401 Unauthorized exception.
|
|
65
|
+
*/
|
|
66
|
+
static unauthorized(message = "Unauthorized") {
|
|
67
|
+
return new _HttpException(401, message);
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Create a 403 Forbidden exception.
|
|
71
|
+
*/
|
|
72
|
+
static forbidden(message = "Forbidden") {
|
|
73
|
+
return new _HttpException(403, message);
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Create a 404 Not Found exception.
|
|
77
|
+
*/
|
|
78
|
+
static notFound(message = "Not Found") {
|
|
79
|
+
return new _HttpException(404, message);
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Create a 405 Method Not Allowed exception.
|
|
83
|
+
*/
|
|
84
|
+
static methodNotAllowed(message = "Method Not Allowed") {
|
|
85
|
+
return new _HttpException(405, message);
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Create a 409 Conflict exception.
|
|
89
|
+
*/
|
|
90
|
+
static conflict(message = "Conflict") {
|
|
91
|
+
return new _HttpException(409, message);
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Create a 410 Gone exception.
|
|
95
|
+
*/
|
|
96
|
+
static gone(message = "Gone") {
|
|
97
|
+
return new _HttpException(410, message);
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Create a 422 Unprocessable Entity exception.
|
|
101
|
+
*/
|
|
102
|
+
static unprocessable(message = "Unprocessable Entity", errors) {
|
|
103
|
+
return new _HttpException(422, message, errors);
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Create a 429 Too Many Requests exception.
|
|
107
|
+
*/
|
|
108
|
+
static tooManyRequests(message = "Too Many Requests") {
|
|
109
|
+
return new _HttpException(429, message);
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Create a 500 Internal Server Error exception.
|
|
113
|
+
*/
|
|
114
|
+
static internal(message = "Internal Server Error") {
|
|
115
|
+
return new _HttpException(500, message);
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Create a 501 Not Implemented exception.
|
|
119
|
+
*/
|
|
120
|
+
static notImplemented(message = "Not Implemented") {
|
|
121
|
+
return new _HttpException(501, message);
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Create a 502 Bad Gateway exception.
|
|
125
|
+
*/
|
|
126
|
+
static badGateway(message = "Bad Gateway") {
|
|
127
|
+
return new _HttpException(502, message);
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Create a 503 Service Unavailable exception.
|
|
131
|
+
*/
|
|
132
|
+
static serviceUnavailable(message = "Service Unavailable") {
|
|
133
|
+
return new _HttpException(503, message);
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Create a 504 Gateway Timeout exception.
|
|
137
|
+
*/
|
|
138
|
+
static gatewayTimeout(message = "Gateway Timeout") {
|
|
139
|
+
return new _HttpException(504, message);
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Check if an error is an HTTP exception.
|
|
143
|
+
*/
|
|
144
|
+
static isHttpException(error) {
|
|
145
|
+
return error instanceof _HttpException || typeof error === "object" && error !== null && "statusCode" in error && typeof error.statusCode === "number" && "toResponse" in error && typeof error.toResponse === "function";
|
|
146
|
+
}
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
// src/errors/exceptions/AuthorizationException.ts
|
|
150
|
+
var AuthorizationException = class _AuthorizationException extends HttpException {
|
|
151
|
+
/**
|
|
152
|
+
* The action that was attempted.
|
|
153
|
+
*/
|
|
154
|
+
action;
|
|
155
|
+
/**
|
|
156
|
+
* The resource that was being accessed.
|
|
157
|
+
*/
|
|
158
|
+
resource;
|
|
159
|
+
constructor(message = "This action is unauthorized.", action, resource) {
|
|
160
|
+
super(403, message);
|
|
161
|
+
this.name = "AuthorizationException";
|
|
162
|
+
this.action = action;
|
|
163
|
+
this.resource = resource;
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Create exception for a specific action and resource.
|
|
167
|
+
*/
|
|
168
|
+
static forAction(action, resource) {
|
|
169
|
+
const message = resource ? `You are not authorized to ${action} this ${resource}.` : `You are not authorized to ${action}.`;
|
|
170
|
+
return new _AuthorizationException(message, action, resource);
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Deny access to a resource.
|
|
174
|
+
*/
|
|
175
|
+
static deny(resource) {
|
|
176
|
+
const message = resource ? `Access to ${resource} denied.` : "Access denied.";
|
|
177
|
+
return new _AuthorizationException(message, "access", resource);
|
|
178
|
+
}
|
|
179
|
+
};
|
|
180
|
+
|
|
181
|
+
// src/authorization/Gate.ts
|
|
182
|
+
var Response = {
|
|
183
|
+
allow(message) {
|
|
184
|
+
return { allowed: true, message };
|
|
185
|
+
},
|
|
186
|
+
deny(message, code) {
|
|
187
|
+
return { allowed: false, message: message ?? "This action is unauthorized.", code };
|
|
188
|
+
},
|
|
189
|
+
denyWithStatus(status, message) {
|
|
190
|
+
return { allowed: false, message: message ?? "This action is unauthorized.", status };
|
|
191
|
+
},
|
|
192
|
+
denyAsNotFound(message) {
|
|
193
|
+
return { allowed: false, message: message ?? "Not found.", status: 404 };
|
|
194
|
+
}
|
|
195
|
+
};
|
|
196
|
+
var Gate = class {
|
|
197
|
+
/**
|
|
198
|
+
* Defined gates.
|
|
199
|
+
*/
|
|
200
|
+
gates = /* @__PURE__ */ new Map();
|
|
201
|
+
/**
|
|
202
|
+
* Registered policies.
|
|
203
|
+
*/
|
|
204
|
+
policies = /* @__PURE__ */ new Map();
|
|
205
|
+
/**
|
|
206
|
+
* Policy instances cache.
|
|
207
|
+
*/
|
|
208
|
+
policyInstances = /* @__PURE__ */ new Map();
|
|
209
|
+
/**
|
|
210
|
+
* Before callbacks.
|
|
211
|
+
*/
|
|
212
|
+
beforeCallbacks = [];
|
|
213
|
+
/**
|
|
214
|
+
* After callbacks.
|
|
215
|
+
*/
|
|
216
|
+
afterCallbacks = [];
|
|
217
|
+
/**
|
|
218
|
+
* User resolver function.
|
|
219
|
+
*/
|
|
220
|
+
userResolver;
|
|
221
|
+
/**
|
|
222
|
+
* Current user for checks.
|
|
223
|
+
*/
|
|
224
|
+
currentUser = null;
|
|
225
|
+
constructor(options = {}) {
|
|
226
|
+
this.userResolver = options.userResolver;
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* Define a new gate.
|
|
230
|
+
*/
|
|
231
|
+
define(ability, callback) {
|
|
232
|
+
this.gates.set(ability, { callback });
|
|
233
|
+
return this;
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* Register a policy for a model class.
|
|
237
|
+
*/
|
|
238
|
+
policy(modelClass, policyClass) {
|
|
239
|
+
this.policies.set(modelClass, policyClass);
|
|
240
|
+
return this;
|
|
241
|
+
}
|
|
242
|
+
/**
|
|
243
|
+
* Register a before callback.
|
|
244
|
+
* Return true to allow, false to deny, undefined to continue.
|
|
245
|
+
*/
|
|
246
|
+
before(callback) {
|
|
247
|
+
this.beforeCallbacks.push(callback);
|
|
248
|
+
return this;
|
|
249
|
+
}
|
|
250
|
+
/**
|
|
251
|
+
* Register an after callback.
|
|
252
|
+
*/
|
|
253
|
+
after(callback) {
|
|
254
|
+
this.afterCallbacks.push(callback);
|
|
255
|
+
return this;
|
|
256
|
+
}
|
|
257
|
+
/**
|
|
258
|
+
* Set the current user for authorization checks.
|
|
259
|
+
*/
|
|
260
|
+
forUser(user) {
|
|
261
|
+
const clone = Object.assign(
|
|
262
|
+
Object.create(Object.getPrototypeOf(this)),
|
|
263
|
+
this
|
|
264
|
+
);
|
|
265
|
+
clone.currentUser = user;
|
|
266
|
+
return clone;
|
|
267
|
+
}
|
|
268
|
+
/**
|
|
269
|
+
* Resolve the user from context.
|
|
270
|
+
*/
|
|
271
|
+
async resolveUser(ctx) {
|
|
272
|
+
if (this.currentUser !== null) {
|
|
273
|
+
return this.currentUser;
|
|
274
|
+
}
|
|
275
|
+
if (this.userResolver) {
|
|
276
|
+
return this.userResolver(ctx);
|
|
277
|
+
}
|
|
278
|
+
const user = ctx.get("user");
|
|
279
|
+
return user ?? null;
|
|
280
|
+
}
|
|
281
|
+
/**
|
|
282
|
+
* Check if the user has the given ability.
|
|
283
|
+
*/
|
|
284
|
+
async allows(ability, ...args) {
|
|
285
|
+
return this.check(ability, this.currentUser, ...args);
|
|
286
|
+
}
|
|
287
|
+
/**
|
|
288
|
+
* Check if the user doesn't have the given ability.
|
|
289
|
+
*/
|
|
290
|
+
async denies(ability, ...args) {
|
|
291
|
+
return !await this.allows(ability, ...args);
|
|
292
|
+
}
|
|
293
|
+
/**
|
|
294
|
+
* Check if the user has any of the given abilities.
|
|
295
|
+
*/
|
|
296
|
+
async any(abilities, ...args) {
|
|
297
|
+
for (const ability of abilities) {
|
|
298
|
+
if (await this.allows(ability, ...args)) {
|
|
299
|
+
return true;
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
return false;
|
|
303
|
+
}
|
|
304
|
+
/**
|
|
305
|
+
* Check if the user has all of the given abilities.
|
|
306
|
+
*/
|
|
307
|
+
async all(abilities, ...args) {
|
|
308
|
+
for (const ability of abilities) {
|
|
309
|
+
if (!await this.allows(ability, ...args)) {
|
|
310
|
+
return false;
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
return true;
|
|
314
|
+
}
|
|
315
|
+
/**
|
|
316
|
+
* Check if the user has none of the given abilities.
|
|
317
|
+
*/
|
|
318
|
+
async none(abilities, ...args) {
|
|
319
|
+
return !await this.any(abilities, ...args);
|
|
320
|
+
}
|
|
321
|
+
/**
|
|
322
|
+
* Authorize the ability or throw an exception.
|
|
323
|
+
*/
|
|
324
|
+
async authorize(ability, ...args) {
|
|
325
|
+
const allowed = await this.allows(ability, ...args);
|
|
326
|
+
if (!allowed) {
|
|
327
|
+
throw new AuthorizationException(`This action is unauthorized.`);
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
/**
|
|
331
|
+
* Get the authorization response.
|
|
332
|
+
*/
|
|
333
|
+
async inspect(ability, ...args) {
|
|
334
|
+
const allowed = await this.check(ability, this.currentUser, ...args);
|
|
335
|
+
return allowed ? Response.allow() : Response.deny();
|
|
336
|
+
}
|
|
337
|
+
/**
|
|
338
|
+
* Check the ability with a specific user.
|
|
339
|
+
*/
|
|
340
|
+
async check(ability, user, ...args) {
|
|
341
|
+
for (const beforeCallback of this.beforeCallbacks) {
|
|
342
|
+
const result = await beforeCallback(user, ability, ...args);
|
|
343
|
+
if (typeof result === "boolean") {
|
|
344
|
+
await this.runAfterCallbacks(user, ability, result, args);
|
|
345
|
+
return result;
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
const model = args[0];
|
|
349
|
+
if (model !== void 0 && model !== null) {
|
|
350
|
+
const policyResult = await this.checkPolicy(ability, user, model, args.slice(1));
|
|
351
|
+
if (policyResult !== void 0) {
|
|
352
|
+
await this.runAfterCallbacks(user, ability, policyResult, args);
|
|
353
|
+
return policyResult;
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
const gate = this.gates.get(ability);
|
|
357
|
+
if (gate) {
|
|
358
|
+
const result = await gate.callback(user, ...args);
|
|
359
|
+
await this.runAfterCallbacks(user, ability, result, args);
|
|
360
|
+
return result;
|
|
361
|
+
}
|
|
362
|
+
await this.runAfterCallbacks(user, ability, false, args);
|
|
363
|
+
return false;
|
|
364
|
+
}
|
|
365
|
+
/**
|
|
366
|
+
* Check a policy for the given ability.
|
|
367
|
+
*/
|
|
368
|
+
async checkPolicy(ability, user, model, additionalArgs) {
|
|
369
|
+
const modelConstructor = model?.constructor;
|
|
370
|
+
if (!modelConstructor) {
|
|
371
|
+
return void 0;
|
|
372
|
+
}
|
|
373
|
+
const policyClass = this.policies.get(modelConstructor);
|
|
374
|
+
if (!policyClass) {
|
|
375
|
+
return void 0;
|
|
376
|
+
}
|
|
377
|
+
const policy = this.getPolicyInstance(policyClass);
|
|
378
|
+
if (policy.before) {
|
|
379
|
+
const beforeResult = await policy.before(user, ability);
|
|
380
|
+
if (typeof beforeResult === "boolean") {
|
|
381
|
+
return beforeResult;
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
const method = policy[ability];
|
|
385
|
+
if (typeof method === "function") {
|
|
386
|
+
return method.call(policy, user, model, ...additionalArgs);
|
|
387
|
+
}
|
|
388
|
+
return void 0;
|
|
389
|
+
}
|
|
390
|
+
/**
|
|
391
|
+
* Get or create a policy instance.
|
|
392
|
+
*/
|
|
393
|
+
getPolicyInstance(policyClass) {
|
|
394
|
+
let instance = this.policyInstances.get(policyClass);
|
|
395
|
+
if (!instance) {
|
|
396
|
+
instance = new policyClass();
|
|
397
|
+
this.policyInstances.set(policyClass, instance);
|
|
398
|
+
}
|
|
399
|
+
return instance;
|
|
400
|
+
}
|
|
401
|
+
/**
|
|
402
|
+
* Run after callbacks.
|
|
403
|
+
*/
|
|
404
|
+
async runAfterCallbacks(user, ability, result, args) {
|
|
405
|
+
for (const afterCallback of this.afterCallbacks) {
|
|
406
|
+
await afterCallback(user, ability, result, args);
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
/**
|
|
410
|
+
* Get all defined abilities.
|
|
411
|
+
*/
|
|
412
|
+
abilities() {
|
|
413
|
+
return Array.from(this.gates.keys());
|
|
414
|
+
}
|
|
415
|
+
/**
|
|
416
|
+
* Check if an ability is defined.
|
|
417
|
+
*/
|
|
418
|
+
has(ability) {
|
|
419
|
+
return this.gates.has(ability);
|
|
420
|
+
}
|
|
421
|
+
/**
|
|
422
|
+
* Get the policy for a model.
|
|
423
|
+
*/
|
|
424
|
+
getPolicyFor(model) {
|
|
425
|
+
const modelConstructor = model?.constructor;
|
|
426
|
+
if (!modelConstructor) {
|
|
427
|
+
return void 0;
|
|
428
|
+
}
|
|
429
|
+
const policyClass = this.policies.get(modelConstructor);
|
|
430
|
+
if (!policyClass) {
|
|
431
|
+
return void 0;
|
|
432
|
+
}
|
|
433
|
+
return this.getPolicyInstance(policyClass);
|
|
434
|
+
}
|
|
435
|
+
};
|
|
436
|
+
var globalGate = null;
|
|
437
|
+
function createGate(options) {
|
|
438
|
+
return new Gate(options);
|
|
439
|
+
}
|
|
440
|
+
function setGate(gate) {
|
|
441
|
+
globalGate = gate;
|
|
442
|
+
}
|
|
443
|
+
function getGate() {
|
|
444
|
+
if (!globalGate) {
|
|
445
|
+
throw new Error("Gate not initialized. Call setGate() first.");
|
|
446
|
+
}
|
|
447
|
+
return globalGate;
|
|
448
|
+
}
|
|
449
|
+
function defineGate(ability, callback) {
|
|
450
|
+
getGate().define(ability, callback);
|
|
451
|
+
}
|
|
452
|
+
async function can(ability, ...args) {
|
|
453
|
+
return getGate().allows(ability, ...args);
|
|
454
|
+
}
|
|
455
|
+
async function cannot(ability, ...args) {
|
|
456
|
+
return getGate().denies(ability, ...args);
|
|
457
|
+
}
|
|
458
|
+
async function authorize(ability, ...args) {
|
|
459
|
+
return getGate().authorize(ability, ...args);
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
// src/authorization/Policy.ts
|
|
463
|
+
var Policy = class {
|
|
464
|
+
/**
|
|
465
|
+
* Allow the action.
|
|
466
|
+
*/
|
|
467
|
+
allow(message) {
|
|
468
|
+
return Response.allow(message);
|
|
469
|
+
}
|
|
470
|
+
/**
|
|
471
|
+
* Deny the action.
|
|
472
|
+
*/
|
|
473
|
+
deny(message, code) {
|
|
474
|
+
return Response.deny(message, code);
|
|
475
|
+
}
|
|
476
|
+
/**
|
|
477
|
+
* Deny with a specific HTTP status.
|
|
478
|
+
*/
|
|
479
|
+
denyWithStatus(status, message) {
|
|
480
|
+
return Response.denyWithStatus(status, message);
|
|
481
|
+
}
|
|
482
|
+
/**
|
|
483
|
+
* Deny as not found (404).
|
|
484
|
+
*/
|
|
485
|
+
denyAsNotFound(message) {
|
|
486
|
+
return Response.denyAsNotFound(message);
|
|
487
|
+
}
|
|
488
|
+
};
|
|
489
|
+
function definePolicy(definition) {
|
|
490
|
+
return class extends Policy {
|
|
491
|
+
before = definition.before;
|
|
492
|
+
viewAny(user) {
|
|
493
|
+
return definition.viewAny?.(user) ?? false;
|
|
494
|
+
}
|
|
495
|
+
view(user, model) {
|
|
496
|
+
return definition.view?.(user, model) ?? false;
|
|
497
|
+
}
|
|
498
|
+
create(user) {
|
|
499
|
+
return definition.create?.(user) ?? false;
|
|
500
|
+
}
|
|
501
|
+
update(user, model) {
|
|
502
|
+
return definition.update?.(user, model) ?? false;
|
|
503
|
+
}
|
|
504
|
+
delete(user, model) {
|
|
505
|
+
return definition.delete?.(user, model) ?? false;
|
|
506
|
+
}
|
|
507
|
+
restore(user, model) {
|
|
508
|
+
return definition.restore?.(user, model) ?? false;
|
|
509
|
+
}
|
|
510
|
+
forceDelete(user, model) {
|
|
511
|
+
return definition.forceDelete?.(user, model) ?? false;
|
|
512
|
+
}
|
|
513
|
+
};
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
// src/authorization/middleware.ts
|
|
517
|
+
function authorizeMiddleware(ability, modelResolver, options = {}) {
|
|
518
|
+
return async (ctx, next) => {
|
|
519
|
+
const gate = getGate();
|
|
520
|
+
const user = await gate.resolveUser(ctx);
|
|
521
|
+
const gateForUser = gate.forUser(user);
|
|
522
|
+
const abilities = Array.isArray(ability) ? ability : [ability];
|
|
523
|
+
const model = modelResolver ? await modelResolver(ctx) : void 0;
|
|
524
|
+
let authorized = false;
|
|
525
|
+
if (Array.isArray(ability)) {
|
|
526
|
+
authorized = await gateForUser.any(abilities, model);
|
|
527
|
+
} else {
|
|
528
|
+
authorized = await gateForUser.allows(ability, model);
|
|
529
|
+
}
|
|
530
|
+
if (!authorized) {
|
|
531
|
+
throw new AuthorizationException(
|
|
532
|
+
options.message ?? "This action is unauthorized."
|
|
533
|
+
);
|
|
534
|
+
}
|
|
535
|
+
await next();
|
|
536
|
+
};
|
|
537
|
+
}
|
|
538
|
+
function authorizeAllMiddleware(abilities, modelResolver, options = {}) {
|
|
539
|
+
return async (ctx, next) => {
|
|
540
|
+
const gate = getGate();
|
|
541
|
+
const user = await gate.resolveUser(ctx);
|
|
542
|
+
const gateForUser = gate.forUser(user);
|
|
543
|
+
const model = modelResolver ? await modelResolver(ctx) : void 0;
|
|
544
|
+
const authorized = await gateForUser.all(abilities, model);
|
|
545
|
+
if (!authorized) {
|
|
546
|
+
throw new AuthorizationException(
|
|
547
|
+
options.message ?? "This action is unauthorized."
|
|
548
|
+
);
|
|
549
|
+
}
|
|
550
|
+
await next();
|
|
551
|
+
};
|
|
552
|
+
}
|
|
553
|
+
function authorizeResourceMiddleware(modelResolver, options = {}) {
|
|
554
|
+
return async (ctx, next) => {
|
|
555
|
+
const method = ctx.req.method.toUpperCase();
|
|
556
|
+
let ability;
|
|
557
|
+
switch (method) {
|
|
558
|
+
case "GET":
|
|
559
|
+
case "HEAD":
|
|
560
|
+
ability = "view";
|
|
561
|
+
break;
|
|
562
|
+
case "POST":
|
|
563
|
+
ability = "create";
|
|
564
|
+
break;
|
|
565
|
+
case "PUT":
|
|
566
|
+
case "PATCH":
|
|
567
|
+
ability = "update";
|
|
568
|
+
break;
|
|
569
|
+
case "DELETE":
|
|
570
|
+
ability = "delete";
|
|
571
|
+
break;
|
|
572
|
+
default:
|
|
573
|
+
ability = "view";
|
|
574
|
+
}
|
|
575
|
+
const gate = getGate();
|
|
576
|
+
const user = await gate.resolveUser(ctx);
|
|
577
|
+
const gateForUser = gate.forUser(user);
|
|
578
|
+
const model = await modelResolver(ctx);
|
|
579
|
+
const authorized = await gateForUser.allows(ability, model);
|
|
580
|
+
if (!authorized) {
|
|
581
|
+
throw new AuthorizationException(
|
|
582
|
+
options.message ?? "This action is unauthorized."
|
|
583
|
+
);
|
|
584
|
+
}
|
|
585
|
+
await next();
|
|
586
|
+
};
|
|
587
|
+
}
|
|
588
|
+
function withAuthorization(gate) {
|
|
589
|
+
return async (ctx, next) => {
|
|
590
|
+
const user = await gate.resolveUser(ctx);
|
|
591
|
+
const gateForUser = gate.forUser(user);
|
|
592
|
+
ctx.set("gate", gateForUser);
|
|
593
|
+
ctx.set("can", async (ability, ...args) => {
|
|
594
|
+
return gateForUser.allows(ability, ...args);
|
|
595
|
+
});
|
|
596
|
+
ctx.set("cannot", async (ability, ...args) => {
|
|
597
|
+
return gateForUser.denies(ability, ...args);
|
|
598
|
+
});
|
|
599
|
+
ctx.set("authorize", async (ability, ...args) => {
|
|
600
|
+
return gateForUser.authorize(ability, ...args);
|
|
601
|
+
});
|
|
602
|
+
await next();
|
|
603
|
+
};
|
|
604
|
+
}
|
|
605
|
+
export {
|
|
606
|
+
Gate,
|
|
607
|
+
Policy,
|
|
608
|
+
Response,
|
|
609
|
+
authorize,
|
|
610
|
+
authorizeAllMiddleware,
|
|
611
|
+
authorizeMiddleware,
|
|
612
|
+
authorizeResourceMiddleware,
|
|
613
|
+
can,
|
|
614
|
+
cannot,
|
|
615
|
+
createGate,
|
|
616
|
+
defineGate,
|
|
617
|
+
definePolicy,
|
|
618
|
+
getGate,
|
|
619
|
+
setGate,
|
|
620
|
+
withAuthorization
|
|
621
|
+
};
|