@sapphire/plugin-api 6.1.2-next.fc6b7cf.0 → 7.0.0-next.03b2a90
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/cjs/index.cjs +1 -1
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/cjs/index.d.cts +78 -45
- package/dist/cjs/lib/structures/MediaParser.cjs +4 -8
- package/dist/cjs/lib/structures/MediaParser.cjs.map +1 -1
- package/dist/cjs/lib/structures/Middleware.cjs +1 -4
- package/dist/cjs/lib/structures/Middleware.cjs.map +1 -1
- package/dist/cjs/lib/structures/MiddlewareStore.cjs +6 -14
- package/dist/cjs/lib/structures/MiddlewareStore.cjs.map +1 -1
- package/dist/cjs/lib/structures/Route.cjs +12 -34
- package/dist/cjs/lib/structures/Route.cjs.map +1 -1
- package/dist/cjs/lib/structures/RouteLoaderStrategy.cjs +28 -0
- package/dist/cjs/lib/structures/RouteLoaderStrategy.cjs.map +1 -0
- package/dist/cjs/lib/structures/RouteStore.cjs +13 -20
- package/dist/cjs/lib/structures/RouteStore.cjs.map +1 -1
- package/dist/cjs/lib/structures/api/ApiRequest.cjs +1 -4
- package/dist/cjs/lib/structures/api/ApiRequest.cjs.map +1 -1
- package/dist/cjs/lib/structures/api/ApiResponse.cjs +1 -4
- package/dist/cjs/lib/structures/api/ApiResponse.cjs.map +1 -1
- package/dist/cjs/lib/structures/api/CookieStore.cjs +6 -11
- package/dist/cjs/lib/structures/api/CookieStore.cjs.map +1 -1
- package/dist/cjs/lib/structures/http/Auth.cjs +13 -31
- package/dist/cjs/lib/structures/http/Auth.cjs.map +1 -1
- package/dist/cjs/lib/structures/http/HttpMethods.cjs +37 -6
- package/dist/cjs/lib/structures/http/HttpMethods.cjs.map +1 -1
- package/dist/cjs/lib/structures/http/Server.cjs +1 -4
- package/dist/cjs/lib/structures/http/Server.cjs.map +1 -1
- package/dist/cjs/lib/utils/RouteData.cjs +10 -21
- package/dist/cjs/lib/utils/RouteData.cjs.map +1 -1
- package/dist/cjs/listeners/PluginRouteError.cjs +1 -2
- package/dist/cjs/listeners/PluginRouteError.cjs.map +1 -1
- package/dist/cjs/listeners/PluginServerMatch.cjs +2 -2
- package/dist/cjs/listeners/PluginServerMatch.cjs.map +1 -1
- package/dist/cjs/listeners/PluginServerMiddlewareError.cjs +1 -2
- package/dist/cjs/listeners/PluginServerMiddlewareError.cjs.map +1 -1
- package/dist/cjs/listeners/PluginServerMiddlewareSuccess.cjs +3 -3
- package/dist/cjs/listeners/PluginServerMiddlewareSuccess.cjs.map +1 -1
- package/dist/cjs/listeners/PluginServerNoMatch.cjs +1 -2
- package/dist/cjs/listeners/PluginServerNoMatch.cjs.map +1 -1
- package/dist/cjs/listeners/PluginServerRequest.cjs +5 -5
- package/dist/cjs/listeners/PluginServerRequest.cjs.map +1 -1
- package/dist/cjs/mediaParsers/applicationJson.cjs.map +1 -1
- package/dist/cjs/mediaParsers/textPlain.cjs.map +1 -1
- package/dist/cjs/middlewares/auth.cjs +2 -6
- package/dist/cjs/middlewares/auth.cjs.map +1 -1
- package/dist/cjs/middlewares/body.cjs +3 -8
- package/dist/cjs/middlewares/body.cjs.map +1 -1
- package/dist/cjs/middlewares/cookies.cjs +1 -4
- package/dist/cjs/middlewares/cookies.cjs.map +1 -1
- package/dist/cjs/middlewares/headers.cjs +15 -7
- package/dist/cjs/middlewares/headers.cjs.map +1 -1
- package/dist/cjs/routes/_load.cjs +4 -4
- package/dist/cjs/routes/_load.cjs.map +1 -1
- package/dist/cjs/routes/oauth/{callback.cjs → callback.post.cjs} +5 -10
- package/dist/cjs/routes/oauth/callback.post.cjs.map +1 -0
- package/dist/cjs/routes/oauth/{logout.cjs → logout.post.cjs} +8 -13
- package/dist/cjs/routes/oauth/logout.post.cjs.map +1 -0
- package/dist/esm/chunk-JTFKMR4I.mjs +15 -0
- package/dist/esm/index.d.mts +78 -45
- package/dist/esm/index.mjs +2 -2
- package/dist/esm/index.mjs.map +1 -1
- package/dist/esm/lib/structures/MediaParser.mjs +5 -9
- package/dist/esm/lib/structures/MediaParser.mjs.map +1 -1
- package/dist/esm/lib/structures/MediaParserStore.mjs +1 -1
- package/dist/esm/lib/structures/Middleware.mjs +1 -1
- package/dist/esm/lib/structures/Middleware.mjs.map +1 -1
- package/dist/esm/lib/structures/MiddlewareStore.mjs +6 -11
- package/dist/esm/lib/structures/MiddlewareStore.mjs.map +1 -1
- package/dist/esm/lib/structures/Route.mjs +12 -31
- package/dist/esm/lib/structures/Route.mjs.map +1 -1
- package/dist/esm/lib/structures/RouteLoaderStrategy.mjs +25 -0
- package/dist/esm/lib/structures/RouteLoaderStrategy.mjs.map +1 -0
- package/dist/esm/lib/structures/RouteStore.mjs +13 -17
- package/dist/esm/lib/structures/RouteStore.mjs.map +1 -1
- package/dist/esm/lib/structures/api/ApiRequest.mjs +1 -1
- package/dist/esm/lib/structures/api/ApiResponse.mjs +1 -1
- package/dist/esm/lib/structures/api/CookieStore.mjs +6 -8
- package/dist/esm/lib/structures/api/CookieStore.mjs.map +1 -1
- package/dist/esm/lib/structures/http/Auth.mjs +6 -10
- package/dist/esm/lib/structures/http/Auth.mjs.map +1 -1
- package/dist/esm/lib/structures/http/HttpCodes.mjs +1 -1
- package/dist/esm/lib/structures/http/HttpMethods.mjs +39 -5
- package/dist/esm/lib/structures/http/HttpMethods.mjs.map +1 -1
- package/dist/esm/lib/structures/http/Server.mjs +1 -1
- package/dist/esm/lib/structures/http/Server.mjs.map +1 -1
- package/dist/esm/lib/utils/MimeTypes.mjs +1 -1
- package/dist/esm/lib/utils/RouteData.mjs +10 -18
- package/dist/esm/lib/utils/RouteData.mjs.map +1 -1
- package/dist/esm/listeners/PluginRouteError.mjs +2 -3
- package/dist/esm/listeners/PluginRouteError.mjs.map +1 -1
- package/dist/esm/listeners/PluginServerMatch.mjs +3 -3
- package/dist/esm/listeners/PluginServerMatch.mjs.map +1 -1
- package/dist/esm/listeners/PluginServerMiddlewareError.mjs +2 -3
- package/dist/esm/listeners/PluginServerMiddlewareError.mjs.map +1 -1
- package/dist/esm/listeners/PluginServerMiddlewareSuccess.mjs +4 -4
- package/dist/esm/listeners/PluginServerMiddlewareSuccess.mjs.map +1 -1
- package/dist/esm/listeners/PluginServerNoMatch.mjs +2 -3
- package/dist/esm/listeners/PluginServerNoMatch.mjs.map +1 -1
- package/dist/esm/listeners/PluginServerRequest.mjs +6 -6
- package/dist/esm/listeners/PluginServerRequest.mjs.map +1 -1
- package/dist/esm/listeners/_load.mjs +1 -1
- package/dist/esm/mediaParsers/_load.mjs +1 -1
- package/dist/esm/mediaParsers/applicationFormUrlEncoded.mjs +1 -1
- package/dist/esm/mediaParsers/applicationJson.mjs +1 -1
- package/dist/esm/mediaParsers/applicationJson.mjs.map +1 -1
- package/dist/esm/mediaParsers/textPlain.mjs +1 -1
- package/dist/esm/mediaParsers/textPlain.mjs.map +1 -1
- package/dist/esm/middlewares/_load.mjs +1 -1
- package/dist/esm/middlewares/auth.mjs +2 -3
- package/dist/esm/middlewares/auth.mjs.map +1 -1
- package/dist/esm/middlewares/body.mjs +3 -5
- package/dist/esm/middlewares/body.mjs.map +1 -1
- package/dist/esm/middlewares/cookies.mjs +1 -1
- package/dist/esm/middlewares/cookies.mjs.map +1 -1
- package/dist/esm/middlewares/headers.mjs +15 -4
- package/dist/esm/middlewares/headers.mjs.map +1 -1
- package/dist/esm/register.mjs +1 -1
- package/dist/esm/routes/_load.mjs +3 -3
- package/dist/esm/routes/_load.mjs.map +1 -1
- package/dist/esm/routes/oauth/{callback.mjs → callback.post.mjs} +5 -7
- package/dist/esm/routes/oauth/callback.post.mjs.map +1 -0
- package/dist/esm/routes/oauth/{logout.mjs → logout.post.mjs} +8 -13
- package/dist/esm/routes/oauth/logout.post.mjs.map +1 -0
- package/package.json +7 -7
- package/dist/cjs/routes/oauth/callback.cjs.map +0 -1
- package/dist/cjs/routes/oauth/logout.cjs.map +0 -1
- package/dist/esm/chunk-PYETHG4R.mjs +0 -29
- package/dist/esm/routes/oauth/callback.mjs.map +0 -1
- package/dist/esm/routes/oauth/logout.mjs.map +0 -1
- /package/dist/esm/{chunk-PYETHG4R.mjs.map → chunk-JTFKMR4I.mjs.map} +0 -0
package/dist/cjs/index.cjs
CHANGED
|
@@ -21,7 +21,7 @@ var _load_cjs$2 = require('./middlewares/_load.cjs');
|
|
|
21
21
|
var _load_cjs$3 = require('./routes/_load.cjs');
|
|
22
22
|
|
|
23
23
|
// src/index.ts
|
|
24
|
-
var version = "
|
|
24
|
+
var version = "7.0.0-next.03b2a90";
|
|
25
25
|
|
|
26
26
|
Object.defineProperty(exports, "loadListeners", {
|
|
27
27
|
enumerable: true,
|
package/dist/cjs/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/index.ts"],"names":[],"mappings":";AAKA,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AAEd,SAAS,qBAAqB;AAC9B,SAAS,wBAAwB;AACjC,SAAS,uBAAuB;AAChC,SAAS,kBAAkB;AA+BpB,IAAM,UAAkB","sourcesContent":["import type { Server, ServerOptions } from './lib/structures/http/Server';\nimport type { MediaParserStore } from './lib/structures/MediaParserStore';\nimport type { MiddlewareStore } from './lib/structures/MiddlewareStore';\nimport type { RouteStore } from './lib/structures/RouteStore';\n\nexport * from './lib/structures/api/ApiRequest';\nexport * from './lib/structures/api/ApiResponse';\nexport * from './lib/structures/api/CookieStore';\nexport * from './lib/structures/http/Auth';\nexport * from './lib/structures/http/HttpCodes';\nexport * from './lib/structures/http/HttpMethods';\nexport * from './lib/structures/http/Server';\nexport * from './lib/structures/MediaParser';\nexport * from './lib/structures/MediaParserStore';\nexport * from './lib/structures/Middleware';\nexport * from './lib/structures/MiddlewareStore';\nexport * from './lib/structures/Route';\nexport * from './lib/structures/RouteStore';\nexport * from './lib/utils/MimeTypes';\nexport * from './lib/utils/RouteData';\n\nexport { loadListeners } from './listeners/_load';\nexport { loadMediaParsers } from './mediaParsers/_load';\nexport { loadMiddlewares } from './middlewares/_load';\nexport { loadRoutes } from './routes/_load';\n\ndeclare module 'discord.js' {\n\tinterface Client {\n\t\tserver: Server;\n\t}\n\n\tinterface ClientOptions {\n\t\tapi?: ServerOptions;\n\t}\n}\n\ndeclare module '@sapphire/pieces' {\n\tinterface StoreRegistryEntries {\n\t\troutes: RouteStore;\n\t\tmediaParsers: MediaParserStore;\n\t\tmiddlewares: MiddlewareStore;\n\t}\n\n\tinterface Container {\n\t\tserver: Server;\n\t}\n}\n\n/**\n * The [@sapphire/plugin-api](https://github.com/sapphiredev/plugins/blob/main/packages/api) version that you are currently using.\n * An example use of this is showing it of in a bot information command.\n *\n * Note to Sapphire developers: This needs to explicitly be `string` so it is not typed as the string that gets replaced by esbuild\n */\n// eslint-disable-next-line @typescript-eslint/no-inferrable-types\nexport const version: string = '
|
|
1
|
+
{"version":3,"sources":["../../src/index.ts"],"names":[],"mappings":";AAKA,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AAEd,SAAS,qBAAqB;AAC9B,SAAS,wBAAwB;AACjC,SAAS,uBAAuB;AAChC,SAAS,kBAAkB;AA+BpB,IAAM,UAAkB","sourcesContent":["import type { Server, ServerOptions } from './lib/structures/http/Server';\nimport type { MediaParserStore } from './lib/structures/MediaParserStore';\nimport type { MiddlewareStore } from './lib/structures/MiddlewareStore';\nimport type { RouteStore } from './lib/structures/RouteStore';\n\nexport * from './lib/structures/api/ApiRequest';\nexport * from './lib/structures/api/ApiResponse';\nexport * from './lib/structures/api/CookieStore';\nexport * from './lib/structures/http/Auth';\nexport * from './lib/structures/http/HttpCodes';\nexport * from './lib/structures/http/HttpMethods';\nexport * from './lib/structures/http/Server';\nexport * from './lib/structures/MediaParser';\nexport * from './lib/structures/MediaParserStore';\nexport * from './lib/structures/Middleware';\nexport * from './lib/structures/MiddlewareStore';\nexport * from './lib/structures/Route';\nexport * from './lib/structures/RouteStore';\nexport * from './lib/utils/MimeTypes';\nexport * from './lib/utils/RouteData';\n\nexport { loadListeners } from './listeners/_load';\nexport { loadMediaParsers } from './mediaParsers/_load';\nexport { loadMiddlewares } from './middlewares/_load';\nexport { loadRoutes } from './routes/_load';\n\ndeclare module 'discord.js' {\n\tinterface Client {\n\t\tserver: Server;\n\t}\n\n\tinterface ClientOptions {\n\t\tapi?: ServerOptions;\n\t}\n}\n\ndeclare module '@sapphire/pieces' {\n\tinterface StoreRegistryEntries {\n\t\troutes: RouteStore;\n\t\tmediaParsers: MediaParserStore;\n\t\tmiddlewares: MiddlewareStore;\n\t}\n\n\tinterface Container {\n\t\tserver: Server;\n\t}\n}\n\n/**\n * The [@sapphire/plugin-api](https://github.com/sapphiredev/plugins/blob/main/packages/api) version that you are currently using.\n * An example use of this is showing it of in a bot information command.\n *\n * Note to Sapphire developers: This needs to explicitly be `string` so it is not typed as the string that gets replaced by esbuild\n */\n// eslint-disable-next-line @typescript-eslint/no-inferrable-types\nexport const version: string = '7.0.0-next.03b2a90';\n"]}
|
package/dist/cjs/index.d.cts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { EventEmitter } from 'node:events';
|
|
2
2
|
import { IncomingMessage, ServerResponse, Server as Server$1, ServerOptions as ServerOptions$1 } from 'node:http';
|
|
3
3
|
import { ListenOptions } from 'node:net';
|
|
4
|
-
import {
|
|
4
|
+
import { Piece, Store } from '@sapphire/pieces';
|
|
5
5
|
import { Awaitable } from '@sapphire/utilities';
|
|
6
6
|
import { Gunzip } from 'zlib';
|
|
7
7
|
import { Snowflake, OAuth2Scopes, RESTGetAPICurrentUserResult, RESTGetAPICurrentUserGuildsResult, RESTGetAPICurrentUserConnectionsResult, Collection } from 'discord.js';
|
|
@@ -224,10 +224,6 @@ interface ParsedPart {
|
|
|
224
224
|
type: TypeState;
|
|
225
225
|
}
|
|
226
226
|
|
|
227
|
-
type Methods = 'ACL' | 'BIND' | 'CHECKOUT' | 'CONNECT' | 'COPY' | 'DELETE' | 'GET' | 'HEAD' | 'LINK' | 'LOCK' | 'M-SEARCH' | 'MERGE' | 'MKACTIVITY' | 'MKCALENDAR' | 'MKCOL' | 'MOVE' | 'NOTIFY' | 'OPTIONS' | 'PATCH' | 'POST' | 'PRI' | 'PROPFIND' | 'PROPPATCH' | 'PURGE' | 'PUT' | 'REBIND' | 'REPORT' | 'SEARCH' | 'SOURCE' | 'SUBSCRIBE' | 'TRACE' | 'UNBIND' | 'UNLINK' | 'UNLOCK' | 'UNSUBSCRIBE';
|
|
228
|
-
declare const methods: Record<Methods, symbol>;
|
|
229
|
-
declare const methodEntries: readonly [Methods, symbol][];
|
|
230
|
-
|
|
231
227
|
declare enum MimeTypes {
|
|
232
228
|
ApplicationFormUrlEncoded = "application/x-www-form-urlencoded",
|
|
233
229
|
ApplicationJson = "application/json",
|
|
@@ -354,28 +350,16 @@ declare class ApiResponse<Request extends IncomingMessage = IncomingMessage> ext
|
|
|
354
350
|
setContentType(contentType: MimeTypes): this;
|
|
355
351
|
}
|
|
356
352
|
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
}
|
|
360
|
-
interface RouteMatch {
|
|
361
|
-
route: Route;
|
|
362
|
-
cb: MethodCallback;
|
|
363
|
-
}
|
|
364
|
-
/**
|
|
365
|
-
* @since 1.0.0
|
|
366
|
-
*/
|
|
367
|
-
declare class RouteStore extends Store<Route, 'routes'> {
|
|
368
|
-
readonly table: Collection<Methods, Collection<Route<RouteOptions>, MethodCallback>>;
|
|
369
|
-
constructor();
|
|
370
|
-
match(request: ApiRequest): RouteMatch | null;
|
|
371
|
-
private parseURL;
|
|
372
|
-
}
|
|
353
|
+
type MethodName = (typeof MethodNames)[number];
|
|
354
|
+
declare const MethodNames: readonly ["ACL", "BIND", "CHECKOUT", "CONNECT", "COPY", "DELETE", "GET", "HEAD", "LINK", "LOCK", "M-SEARCH", "MERGE", "MKACTIVITY", "MKCALENDAR", "MKCOL", "MOVE", "NOTIFY", "OPTIONS", "PATCH", "POST", "PROPFIND", "PROPPATCH", "PURGE", "PUT", "REBIND", "REPORT", "SEARCH", "SOURCE", "SUBSCRIBE", "TRACE", "UNBIND", "UNLINK", "UNLOCK", "UNSUBSCRIBE"];
|
|
373
355
|
|
|
374
356
|
interface RouteOptions extends Piece.Options {
|
|
375
357
|
/**
|
|
376
358
|
* The route the piece should represent.
|
|
377
359
|
* @since 1.0.0
|
|
378
|
-
*
|
|
360
|
+
*
|
|
361
|
+
* @defaultValue The filesystem-based path, or the name if the location is virtual.
|
|
362
|
+
*
|
|
379
363
|
* @example
|
|
380
364
|
* ```typescript
|
|
381
365
|
* '/users'
|
|
@@ -383,7 +367,7 @@ interface RouteOptions extends Piece.Options {
|
|
|
383
367
|
* ```
|
|
384
368
|
* @example
|
|
385
369
|
* ```typescript
|
|
386
|
-
* '/guilds
|
|
370
|
+
* '/guilds/[guild]/members/[member]'
|
|
387
371
|
* // request.params -> { guild: '...', member: '...' }
|
|
388
372
|
* ```
|
|
389
373
|
*/
|
|
@@ -391,18 +375,61 @@ interface RouteOptions extends Piece.Options {
|
|
|
391
375
|
/**
|
|
392
376
|
* (RFC 7230 3.3.2) The maximum decimal number of octets.
|
|
393
377
|
* @since 1.0.0
|
|
394
|
-
*
|
|
378
|
+
*
|
|
379
|
+
* @defaultValue this.context.server.options.maximumBodyLength ?? 1024 * 1024 * 50
|
|
395
380
|
*/
|
|
396
381
|
maximumBodyLength?: number;
|
|
397
382
|
/**
|
|
398
383
|
* The accepted content types for this route. If set to null, the route will accept any data.
|
|
399
384
|
* @since 1.3.0
|
|
400
|
-
*
|
|
385
|
+
*
|
|
386
|
+
* @defaultValue this.context.server.options.acceptedContentMimeTypes ?? null
|
|
401
387
|
*/
|
|
402
|
-
acceptedContentMimeTypes?: MimeTypeWithoutParameters[] | null;
|
|
388
|
+
acceptedContentMimeTypes?: readonly MimeTypeWithoutParameters[] | null;
|
|
389
|
+
/**
|
|
390
|
+
* The methods this route accepts.
|
|
391
|
+
* @since 7.0.0
|
|
392
|
+
*
|
|
393
|
+
* @defaultValue The method defined in the piece name, or none if not set.
|
|
394
|
+
*/
|
|
395
|
+
methods?: readonly MethodName[];
|
|
403
396
|
}
|
|
404
397
|
/**
|
|
405
398
|
* @since 1.0.0
|
|
399
|
+
*
|
|
400
|
+
* @example A simple GET route that returns a JSON response:
|
|
401
|
+
* ```typescript
|
|
402
|
+
* // hello.get.ts
|
|
403
|
+
* import { Route } from '@sapphire/plugin-api';
|
|
404
|
+
*
|
|
405
|
+
* export class MyRoute extends Route {
|
|
406
|
+
* public run(request: Route.Request, response: Route.Response) {
|
|
407
|
+
* return response.json({ message: 'Hello, World!' });
|
|
408
|
+
* }
|
|
409
|
+
* }
|
|
410
|
+
* ```
|
|
411
|
+
*
|
|
412
|
+
* ```bash
|
|
413
|
+
* $ curl http://localhost:4000/hello
|
|
414
|
+
* {"message":"Hello, World!"}
|
|
415
|
+
* ```
|
|
416
|
+
*
|
|
417
|
+
* @example A simple POST route that reads the body and returns it:
|
|
418
|
+
* ```typescript
|
|
419
|
+
* // echo.post.ts
|
|
420
|
+
* import { Route } from '@sapphire/plugin-api';
|
|
421
|
+
*
|
|
422
|
+
* export class MyRoute extends Route {
|
|
423
|
+
* public run(request: Route.Request, response: Route.Response) {
|
|
424
|
+
* return response.json(request.params);
|
|
425
|
+
* }
|
|
426
|
+
* }
|
|
427
|
+
* ```
|
|
428
|
+
*
|
|
429
|
+
* ```bash
|
|
430
|
+
* $ curl -X POST -H "Content-Type: application/json" -d '{"hello":"world"}' http://localhost:4000/echo
|
|
431
|
+
* {"hello":"world"}
|
|
432
|
+
* ```
|
|
406
433
|
*/
|
|
407
434
|
declare abstract class Route<Options extends Route.Options = Route.Options> extends Piece<Options, 'routes'> {
|
|
408
435
|
/**
|
|
@@ -420,18 +447,9 @@ declare abstract class Route<Options extends Route.Options = Route.Options> exte
|
|
|
420
447
|
/**
|
|
421
448
|
* The methods this route accepts.
|
|
422
449
|
*/
|
|
423
|
-
readonly methods:
|
|
450
|
+
readonly methods: ReadonlySet<MethodName>;
|
|
424
451
|
constructor(context: Route.LoaderContext, options?: Options);
|
|
425
|
-
|
|
426
|
-
* Per-piece listener that is called when the piece is loaded into the store.
|
|
427
|
-
* Useful to set-up asynchronous initialization tasks.
|
|
428
|
-
*/
|
|
429
|
-
onLoad(): Awaitable<unknown>;
|
|
430
|
-
/**
|
|
431
|
-
* Per-piece listener that is called when the piece is unloaded from the store.
|
|
432
|
-
* Useful to set-up clean-up tasks.
|
|
433
|
-
*/
|
|
434
|
-
onUnload(): Awaitable<unknown>;
|
|
452
|
+
abstract run(request: Route.Request, response: Route.Response): Awaitable<unknown>;
|
|
435
453
|
}
|
|
436
454
|
declare namespace Route {
|
|
437
455
|
/** @deprecated Use {@linkcode LoaderContext} instead. */
|
|
@@ -440,6 +458,8 @@ declare namespace Route {
|
|
|
440
458
|
type Options = RouteOptions;
|
|
441
459
|
type JSON = Piece.JSON;
|
|
442
460
|
type LocationJSON = Piece.LocationJSON;
|
|
461
|
+
type Request = ApiRequest;
|
|
462
|
+
type Response = ApiResponse;
|
|
443
463
|
}
|
|
444
464
|
|
|
445
465
|
/**
|
|
@@ -452,7 +472,7 @@ declare abstract class MediaParser<Options extends MediaParser.Options = MediaPa
|
|
|
452
472
|
* Parses the body data from an API request.
|
|
453
473
|
* @since 1.3.0
|
|
454
474
|
*/
|
|
455
|
-
abstract run(request:
|
|
475
|
+
abstract run(request: MediaParser.Request): Awaitable<unknown>;
|
|
456
476
|
/**
|
|
457
477
|
* Checks if a route accepts the media type from this parser.
|
|
458
478
|
* @since 1.3.0
|
|
@@ -464,19 +484,19 @@ declare abstract class MediaParser<Options extends MediaParser.Options = MediaPa
|
|
|
464
484
|
* @since 1.3.0
|
|
465
485
|
* @param request The request to read the body from.
|
|
466
486
|
*/
|
|
467
|
-
protected readString(request:
|
|
487
|
+
protected readString(request: MediaParser.Request): Promise<string>;
|
|
468
488
|
/**
|
|
469
489
|
* Reads the content body as a buffer, this is useful for parsing/reading binary data.
|
|
470
490
|
* @since 1.3.0
|
|
471
491
|
* @param request The request to read the body from.
|
|
472
492
|
*/
|
|
473
|
-
protected readBuffer(request:
|
|
493
|
+
protected readBuffer(request: MediaParser.Request): Promise<Buffer>;
|
|
474
494
|
/**
|
|
475
495
|
* Reads the content stream from a request, piping the data through a transformer stream.
|
|
476
496
|
* @since 1.3.0
|
|
477
497
|
* @param request The request to read the body from.
|
|
478
498
|
*/
|
|
479
|
-
protected contentStream(request:
|
|
499
|
+
protected contentStream(request: MediaParser.Request): MediaParser.Request | Gunzip | null;
|
|
480
500
|
}
|
|
481
501
|
declare namespace MediaParser {
|
|
482
502
|
/** @deprecated Use {@linkcode LoaderContext} instead. */
|
|
@@ -485,6 +505,7 @@ declare namespace MediaParser {
|
|
|
485
505
|
type Options = Piece.Options;
|
|
486
506
|
type JSON = Piece.JSON;
|
|
487
507
|
type LocationJSON = Piece.LocationJSON;
|
|
508
|
+
type Request = ApiRequest;
|
|
488
509
|
}
|
|
489
510
|
|
|
490
511
|
/**
|
|
@@ -533,7 +554,7 @@ declare abstract class Middleware<Options extends Middleware.Options = Middlewar
|
|
|
533
554
|
* @param response The server's response.
|
|
534
555
|
* @param route The route that matched this request, will be `null` if none matched.
|
|
535
556
|
*/
|
|
536
|
-
abstract run(request:
|
|
557
|
+
abstract run(request: Middleware.Request, response: Middleware.Response, route: Route | null): Awaitable<unknown>;
|
|
537
558
|
}
|
|
538
559
|
declare namespace Middleware {
|
|
539
560
|
/** @deprecated Use {@linkcode LoaderContext} instead. */
|
|
@@ -542,6 +563,8 @@ declare namespace Middleware {
|
|
|
542
563
|
type Options = MiddlewareOptions;
|
|
543
564
|
type JSON = Piece.JSON;
|
|
544
565
|
type LocationJSON = Piece.LocationJSON;
|
|
566
|
+
type Request = ApiRequest;
|
|
567
|
+
type Response = ApiResponse;
|
|
545
568
|
}
|
|
546
569
|
|
|
547
570
|
/**
|
|
@@ -553,12 +576,22 @@ declare class MiddlewareStore extends Store<Middleware, 'middlewares'> {
|
|
|
553
576
|
*/
|
|
554
577
|
readonly sortedMiddlewares: Middleware[];
|
|
555
578
|
constructor();
|
|
556
|
-
run(request:
|
|
579
|
+
run(request: Middleware.Request, response: Middleware.Response, route: Route | null): Promise<void>;
|
|
557
580
|
set(key: string, value: Middleware): this;
|
|
558
581
|
delete(key: string): boolean;
|
|
559
582
|
clear(): void;
|
|
560
583
|
}
|
|
561
584
|
|
|
585
|
+
/**
|
|
586
|
+
* @since 1.0.0
|
|
587
|
+
*/
|
|
588
|
+
declare class RouteStore extends Store<Route, 'routes'> {
|
|
589
|
+
readonly methods: Collection<"ACL" | "BIND" | "CHECKOUT" | "CONNECT" | "COPY" | "DELETE" | "GET" | "HEAD" | "LINK" | "LOCK" | "M-SEARCH" | "MERGE" | "MKACTIVITY" | "MKCALENDAR" | "MKCOL" | "MOVE" | "NOTIFY" | "OPTIONS" | "PATCH" | "POST" | "PROPFIND" | "PROPPATCH" | "PURGE" | "PUT" | "REBIND" | "REPORT" | "SEARCH" | "SOURCE" | "SUBSCRIBE" | "TRACE" | "UNBIND" | "UNLINK" | "UNLOCK" | "UNSUBSCRIBE", Collection<Route<RouteOptions>, RouteData>>;
|
|
590
|
+
constructor();
|
|
591
|
+
match(request: Route.Request): Route | null;
|
|
592
|
+
private parseURL;
|
|
593
|
+
}
|
|
594
|
+
|
|
562
595
|
declare enum ServerEvents {
|
|
563
596
|
Error = "error",
|
|
564
597
|
Request = "request",
|
|
@@ -724,7 +757,7 @@ interface MiddlewareErrorContext {
|
|
|
724
757
|
* The route match.
|
|
725
758
|
* @since 1.2.0
|
|
726
759
|
*/
|
|
727
|
-
|
|
760
|
+
route: Route;
|
|
728
761
|
}
|
|
729
762
|
|
|
730
763
|
declare enum HttpCodes {
|
|
@@ -1139,4 +1172,4 @@ declare module '@sapphire/pieces' {
|
|
|
1139
1172
|
*/
|
|
1140
1173
|
declare const version: string;
|
|
1141
1174
|
|
|
1142
|
-
export { ApiRequest, ApiResponse, Auth, type AuthData, type AuthLessServerOptions, type ContentTypeParameter, type ContentTypeType, CookieStore, HttpCodes, type LoginData, type LoginDataTransformer, type MatchData, MediaParser, MediaParserStore, type
|
|
1175
|
+
export { ApiRequest, ApiResponse, Auth, type AuthData, type AuthLessServerOptions, type ContentTypeParameter, type ContentTypeType, CookieStore, HttpCodes, type LoginData, type LoginDataTransformer, type MatchData, MediaParser, MediaParserStore, type MethodName, MethodNames, Middleware, type MiddlewareErrorContext, type MiddlewareOptions, MiddlewareStore, type MimeType, type MimeTypeWithoutParameters, MimeTypes, type ParsedPart, Route, RouteData, type RouteOptions, RouteStore, type SecureCookieStoreSetOptions, Server, ServerEvents, type ServerOptions, type ServerOptionsAuth, TypeState, loadListeners, loadMediaParsers, loadMiddlewares, loadRoutes, version };
|
|
@@ -24,11 +24,9 @@ var _MediaParser = class _MediaParser extends pieces.Piece {
|
|
|
24
24
|
*/
|
|
25
25
|
async readString(request) {
|
|
26
26
|
const stream = this.contentStream(request);
|
|
27
|
-
if (stream === null)
|
|
28
|
-
return "";
|
|
27
|
+
if (stream === null) return "";
|
|
29
28
|
let body = "";
|
|
30
|
-
for await (const chunk of stream)
|
|
31
|
-
body += chunk;
|
|
29
|
+
for await (const chunk of stream) body += chunk;
|
|
32
30
|
return body;
|
|
33
31
|
}
|
|
34
32
|
/**
|
|
@@ -38,11 +36,9 @@ var _MediaParser = class _MediaParser extends pieces.Piece {
|
|
|
38
36
|
*/
|
|
39
37
|
async readBuffer(request) {
|
|
40
38
|
const stream = this.contentStream(request);
|
|
41
|
-
if (stream === null)
|
|
42
|
-
return Buffer.alloc(0);
|
|
39
|
+
if (stream === null) return Buffer.alloc(0);
|
|
43
40
|
const bodies = [];
|
|
44
|
-
for await (const chunk of stream)
|
|
45
|
-
bodies.push(chunk);
|
|
41
|
+
for await (const chunk of stream) bodies.push(chunk);
|
|
46
42
|
return Buffer.concat(bodies);
|
|
47
43
|
}
|
|
48
44
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/lib/structures/MediaParser.ts"],"names":[],"mappings":";;;;AAAA,SAAS,aAAa;AAEtB,SAAS,wBAAwB,cAAc,qBAAkC;AAS1E,IAAe,eAAf,MAAe,qBAA+E,MAA+B;AAAA,EAC5H,YAAY,SAAoC,UAAmB,CAAC,GAAc;AACxF,UAAM,SAAS,OAAO;AAAA,EACvB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAaO,QAAQ,OAAuB;AACrC,WAAO,MAAM,6BAA6B,QAAQ,MAAM,yBAAyB,SAAS,KAAK,IAAiC;AAAA,EACjI;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAgB,WAAW,
|
|
1
|
+
{"version":3,"sources":["../../../../src/lib/structures/MediaParser.ts"],"names":[],"mappings":";;;;AAAA,SAAS,aAAa;AAEtB,SAAS,wBAAwB,cAAc,qBAAkC;AAS1E,IAAe,eAAf,MAAe,qBAA+E,MAA+B;AAAA,EAC5H,YAAY,SAAoC,UAAmB,CAAC,GAAc;AACxF,UAAM,SAAS,OAAO;AAAA,EACvB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAaO,QAAQ,OAAuB;AACrC,WAAO,MAAM,6BAA6B,QAAQ,MAAM,yBAAyB,SAAS,KAAK,IAAiC;AAAA,EACjI;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAgB,WAAW,SAA+C;AACzE,UAAM,SAAS,KAAK,cAAc,OAAO;AACzC,QAAI,WAAW,KAAM,QAAO;AAE5B,QAAI,OAAO;AACX,qBAAiB,SAAS,OAAQ,SAAQ;AAE1C,WAAO;AAAA,EACR;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAgB,WAAW,SAA+C;AACzE,UAAM,SAAS,KAAK,cAAc,OAAO;AACzC,QAAI,WAAW,KAAM,QAAO,OAAO,MAAM,CAAC;AAE1C,UAAM,SAAmB,CAAC;AAC1B,qBAAiB,SAAS,OAAQ,QAAO,KAAK,KAAK;AAEnD,WAAO,OAAO,OAAO,MAAM;AAAA,EAC5B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOU,cAAc,SAAmE;AAC1F,aAAS,QAAQ,QAAQ,kBAAkB,KAAK,YAAY,YAAY,GAAG;AAAA,MAK1E,KAAK,WAAW;AACf,cAAM,SAAS,cAAc;AAC7B,gBAAQ,KAAK,MAAM;AACnB,eAAO;AAAA,MACR;AAAA,MAMA,KAAK;AAAA,MACL,KAAK,QAAQ;AACZ,cAAM,SAAS,aAAa;AAC5B,gBAAQ,KAAK,MAAM;AACnB,eAAO;AAAA,MACR;AAAA,MAKA,KAAK,MAAM;AACV,cAAM,SAAS,uBAAuB;AACtC,gBAAQ,KAAK,MAAM;AACnB,eAAO;AAAA,MACR;AAAA,MAIA,KAAK,YAAY;AAChB,eAAO;AAAA,MACR;AAAA,IACD;AAEA,WAAO;AAAA,EACR;AACD;AAhGoI;AAA7H,IAAe,cAAf","sourcesContent":["import { Piece } from '@sapphire/pieces';\nimport type { Awaitable } from '@sapphire/utilities';\nimport { createBrotliDecompress, createGunzip, createInflate, type Gunzip } from 'zlib';\nimport type { ApiRequest } from './api/ApiRequest';\nimport type { MimeTypeWithoutParameters } from './http/Server';\nimport type { Route } from './Route';\n\n/**\n * A media parser\n * @since 1.3.0\n */\nexport abstract class MediaParser<Options extends MediaParser.Options = MediaParser.Options> extends Piece<Options, 'mediaParsers'> {\n\tpublic constructor(context: MediaParser.LoaderContext, options: Options = {} as Options) {\n\t\tsuper(context, options);\n\t}\n\n\t/**\n\t * Parses the body data from an API request.\n\t * @since 1.3.0\n\t */\n\tpublic abstract run(request: MediaParser.Request): Awaitable<unknown>;\n\n\t/**\n\t * Checks if a route accepts the media type from this parser.\n\t * @since 1.3.0\n\t * @param route The route to be checked.\n\t */\n\tpublic accepts(route: Route): boolean {\n\t\treturn route.acceptedContentMimeTypes === null || route.acceptedContentMimeTypes.includes(this.name as MimeTypeWithoutParameters);\n\t}\n\n\t/**\n\t * Reads the content body as a string, this is useful for parsing/reading plain-text data.\n\t * @since 1.3.0\n\t * @param request The request to read the body from.\n\t */\n\tprotected async readString(request: MediaParser.Request): Promise<string> {\n\t\tconst stream = this.contentStream(request);\n\t\tif (stream === null) return '';\n\n\t\tlet body = '';\n\t\tfor await (const chunk of stream) body += chunk;\n\n\t\treturn body;\n\t}\n\n\t/**\n\t * Reads the content body as a buffer, this is useful for parsing/reading binary data.\n\t * @since 1.3.0\n\t * @param request The request to read the body from.\n\t */\n\tprotected async readBuffer(request: MediaParser.Request): Promise<Buffer> {\n\t\tconst stream = this.contentStream(request);\n\t\tif (stream === null) return Buffer.alloc(0);\n\n\t\tconst bodies: Buffer[] = [];\n\t\tfor await (const chunk of stream) bodies.push(chunk);\n\n\t\treturn Buffer.concat(bodies);\n\t}\n\n\t/**\n\t * Reads the content stream from a request, piping the data through a transformer stream.\n\t * @since 1.3.0\n\t * @param request The request to read the body from.\n\t */\n\tprotected contentStream(request: MediaParser.Request): MediaParser.Request | Gunzip | null {\n\t\tswitch ((request.headers['content-encoding'] ?? 'identity').toLowerCase()) {\n\t\t\t// RFC 7230 4.2.2:\n\t\t\t//\n\t\t\t// The \"deflate\" coding is a \"zlib\" data format (RFC 1950) containing a \"deflate\" compressed data stream\n\t\t\t// (RFC 1951) that uses a combination of the Lempel-Ziv (LZ77) compression algorithm and Huffman coding.\n\t\t\tcase 'deflate': {\n\t\t\t\tconst stream = createInflate();\n\t\t\t\trequest.pipe(stream);\n\t\t\t\treturn stream;\n\t\t\t}\n\n\t\t\t// RFC 7230 4.2.3\n\t\t\t//\n\t\t\t// The \"gzip\" coding is an LZ77 coding with a 32-bit Cyclic Redundancy Check (CRC) that is commonly produced\n\t\t\t// by the gzip file compression program (RFC 1952).\n\t\t\tcase 'x-gzip':\n\t\t\tcase 'gzip': {\n\t\t\t\tconst stream = createGunzip();\n\t\t\t\trequest.pipe(stream);\n\t\t\t\treturn stream;\n\t\t\t}\n\n\t\t\t// RFC 7932\n\t\t\t//\n\t\t\t// A format using the Brotli algorithm.\n\t\t\tcase 'br': {\n\t\t\t\tconst stream = createBrotliDecompress();\n\t\t\t\trequest.pipe(stream);\n\t\t\t\treturn stream;\n\t\t\t}\n\n\t\t\t// An \"identity\" token is used as a synonym for \"no encoding\" in order to communicate when no encoding is\n\t\t\t// preferred.\n\t\t\tcase 'identity': {\n\t\t\t\treturn request;\n\t\t\t}\n\t\t}\n\n\t\treturn null;\n\t}\n}\n\nexport namespace MediaParser {\n\t/** @deprecated Use {@linkcode LoaderContext} instead. */\n\texport type Context = LoaderContext;\n\texport type LoaderContext = Piece.LoaderContext<'mediaParsers'>;\n\texport type Options = Piece.Options;\n\texport type JSON = Piece.JSON;\n\texport type LocationJSON = Piece.LocationJSON;\n\n\texport type Request = ApiRequest;\n}\n"]}
|
|
@@ -5,10 +5,7 @@ var pieces = require('@sapphire/pieces');
|
|
|
5
5
|
var __defProp = Object.defineProperty;
|
|
6
6
|
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
7
7
|
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
8
|
-
var __publicField = (obj, key, value) =>
|
|
9
|
-
__defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
10
|
-
return value;
|
|
11
|
-
};
|
|
8
|
+
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
12
9
|
var _Middleware = class _Middleware extends pieces.Piece {
|
|
13
10
|
constructor(context, options = {}) {
|
|
14
11
|
super(context, options);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/lib/structures/Middleware.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"sources":["../../../../src/lib/structures/Middleware.ts"],"names":[],"mappings":";;;;;;AAAA,SAAS,aAAa;AASf,IAAe,cAAf,MAAe,oBAA4E,MAA8B;AAAA,EAaxH,YAAY,SAAmC,UAAmB,CAAC,GAAc;AACvF,UAAM,SAAS,OAAO;AAHvB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,wBAAgB;AAIf,SAAK,WAAW,QAAQ,YAAY;AAAA,EACrC;AASD;AAzBgI;AAAzH,IAAe,aAAf","sourcesContent":["import { Piece } from '@sapphire/pieces';\nimport type { Awaitable } from '@sapphire/utilities';\nimport type { Route } from './Route';\nimport type { ApiRequest } from './api/ApiRequest';\nimport type { ApiResponse } from './api/ApiResponse';\n\n/**\n * @since 1.0.0\n */\nexport abstract class Middleware<Options extends Middleware.Options = Middleware.Options> extends Piece<Options, 'middlewares'> {\n\t/**\n\t * The position the middleware has. The {@link MiddlewareStore} will run all middlewares with lower position than\n\t * this one.\n\t *\n\t * The built-in middlewares follow the following positions:\n\t * - headers: 10\n\t * - body: 20\n\t * - cookies: 30\n\t * - auth: 40\n\t */\n\tpublic readonly position: number;\n\n\tpublic constructor(context: Middleware.LoaderContext, options: Options = {} as Options) {\n\t\tsuper(context, options);\n\t\tthis.position = options.position ?? 1000;\n\t}\n\n\t/**\n\t * The method to be overridden by other middlewares.\n\t * @param request The client's request.\n\t * @param response The server's response.\n\t * @param route The route that matched this request, will be `null` if none matched.\n\t */\n\tpublic abstract run(request: Middleware.Request, response: Middleware.Response, route: Route | null): Awaitable<unknown>;\n}\n\n/**\n * The options for all middlewares.\n */\nexport interface MiddlewareOptions extends Piece.Options {\n\t/**\n\t * The position to insert the middleware at.\n\t * @see Middleware#position\n\t * @default 1000\n\t */\n\tposition?: number;\n}\n\nexport namespace Middleware {\n\t/** @deprecated Use {@linkcode LoaderContext} instead. */\n\texport type Context = LoaderContext;\n\texport type LoaderContext = Piece.LoaderContext<'middlewares'>;\n\texport type Options = MiddlewareOptions;\n\texport type JSON = Piece.JSON;\n\texport type LocationJSON = Piece.LocationJSON;\n\n\texport type Request = ApiRequest;\n\texport type Response = ApiResponse;\n}\n"]}
|
|
@@ -6,10 +6,7 @@ var Middleware_cjs = require('./Middleware.cjs');
|
|
|
6
6
|
var __defProp = Object.defineProperty;
|
|
7
7
|
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
8
8
|
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
9
|
-
var __publicField = (obj, key, value) =>
|
|
10
|
-
__defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
11
|
-
return value;
|
|
12
|
-
};
|
|
9
|
+
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
13
10
|
var _MiddlewareStore = class _MiddlewareStore extends pieces.Store {
|
|
14
11
|
constructor() {
|
|
15
12
|
super(Middleware_cjs.Middleware, { name: "middlewares" });
|
|
@@ -20,24 +17,19 @@ var _MiddlewareStore = class _MiddlewareStore extends pieces.Store {
|
|
|
20
17
|
}
|
|
21
18
|
async run(request, response, route) {
|
|
22
19
|
for (const middleware of this.sortedMiddlewares) {
|
|
23
|
-
if (response.writableEnded)
|
|
24
|
-
|
|
25
|
-
if (middleware.enabled)
|
|
26
|
-
await middleware.run(request, response, route);
|
|
20
|
+
if (response.writableEnded) return;
|
|
21
|
+
if (middleware.enabled) await middleware.run(request, response, route);
|
|
27
22
|
}
|
|
28
23
|
}
|
|
29
24
|
set(key, value) {
|
|
30
25
|
const index = this.sortedMiddlewares.findIndex((middleware) => middleware.position >= value.position);
|
|
31
|
-
if (index === -1)
|
|
32
|
-
|
|
33
|
-
else
|
|
34
|
-
this.sortedMiddlewares.splice(index, 0, value);
|
|
26
|
+
if (index === -1) this.sortedMiddlewares.push(value);
|
|
27
|
+
else this.sortedMiddlewares.splice(index, 0, value);
|
|
35
28
|
return super.set(key, value);
|
|
36
29
|
}
|
|
37
30
|
delete(key) {
|
|
38
31
|
const index = this.sortedMiddlewares.findIndex((middleware) => middleware.name === key);
|
|
39
|
-
if (index !== -1)
|
|
40
|
-
this.sortedMiddlewares.splice(index, 1);
|
|
32
|
+
if (index !== -1) this.sortedMiddlewares.splice(index, 1);
|
|
41
33
|
return super.delete(key);
|
|
42
34
|
}
|
|
43
35
|
clear() {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/lib/structures/MiddlewareStore.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"sources":["../../../../src/lib/structures/MiddlewareStore.ts"],"names":[],"mappings":";;;;;;AAAA,SAAS,aAAa;AACtB,SAAS,kBAAkB;AAMpB,IAAM,mBAAN,MAAM,yBAAwB,MAAiC;AAAA,EAM9D,cAAc;AACpB,UAAM,YAAY,EAAE,MAAM,cAAc,CAAC;AAH1C;AAAA;AAAA;AAAA,wBAAgB,qBAAkC,CAAC;AAAA,EAInD;AAAA,EAEA,MAAa,IAAI,SAA6B,UAA+B,OAAoC;AAChH,eAAW,cAAc,KAAK,mBAAmB;AAChD,UAAI,SAAS,cAAe;AAC5B,UAAI,WAAW,QAAS,OAAM,WAAW,IAAI,SAAS,UAAU,KAAK;AAAA,IACtE;AAAA,EACD;AAAA,EAEgB,IAAI,KAAa,OAAyB;AACzD,UAAM,QAAQ,KAAK,kBAAkB,UAAU,CAAC,eAAe,WAAW,YAAY,MAAM,QAAQ;AAGpG,QAAI,UAAU,GAAI,MAAK,kBAAkB,KAAK,KAAK;AAAA,QAC9C,MAAK,kBAAkB,OAAO,OAAO,GAAG,KAAK;AAElD,WAAO,MAAM,IAAI,KAAK,KAAK;AAAA,EAC5B;AAAA,EAEgB,OAAO,KAAsB;AAC5C,UAAM,QAAQ,KAAK,kBAAkB,UAAU,CAAC,eAAe,WAAW,SAAS,GAAG;AAGtF,QAAI,UAAU,GAAI,MAAK,kBAAkB,OAAO,OAAO,CAAC;AAExD,WAAO,MAAM,OAAO,GAAG;AAAA,EACxB;AAAA,EAEgB,QAAc;AAC7B,SAAK,kBAAkB,SAAS;AAChC,WAAO,MAAM,MAAM;AAAA,EACpB;AACD;AAxCsE;AAA/D,IAAM,kBAAN","sourcesContent":["import { Store } from '@sapphire/pieces';\nimport { Middleware } from './Middleware';\nimport type { Route } from './Route';\n\n/**\n * @since 1.0.0\n */\nexport class MiddlewareStore extends Store<Middleware, 'middlewares'> {\n\t/**\n\t * The sorted middlewares, in ascending order of see {@link Middleware.position}.\n\t */\n\tpublic readonly sortedMiddlewares: Middleware[] = [];\n\n\tpublic constructor() {\n\t\tsuper(Middleware, { name: 'middlewares' });\n\t}\n\n\tpublic async run(request: Middleware.Request, response: Middleware.Response, route: Route | null): Promise<void> {\n\t\tfor (const middleware of this.sortedMiddlewares) {\n\t\t\tif (response.writableEnded) return;\n\t\t\tif (middleware.enabled) await middleware.run(request, response, route);\n\t\t}\n\t}\n\n\tpublic override set(key: string, value: Middleware): this {\n\t\tconst index = this.sortedMiddlewares.findIndex((middleware) => middleware.position >= value.position);\n\n\t\t// If a middleware with lower priority wasn't found, push to the end of the array\n\t\tif (index === -1) this.sortedMiddlewares.push(value);\n\t\telse this.sortedMiddlewares.splice(index, 0, value);\n\n\t\treturn super.set(key, value);\n\t}\n\n\tpublic override delete(key: string): boolean {\n\t\tconst index = this.sortedMiddlewares.findIndex((middleware) => middleware.name === key);\n\n\t\t// If the middleware was found, remove it\n\t\tif (index !== -1) this.sortedMiddlewares.splice(index, 1);\n\n\t\treturn super.delete(key);\n\t}\n\n\tpublic override clear(): void {\n\t\tthis.sortedMiddlewares.length = 0;\n\t\treturn super.clear();\n\t}\n}\n"]}
|
|
@@ -1,17 +1,12 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var pieces = require('@sapphire/pieces');
|
|
4
|
-
var discord_js = require('discord.js');
|
|
5
4
|
var RouteData_cjs = require('../utils/RouteData.cjs');
|
|
6
|
-
var HttpMethods_cjs = require('./http/HttpMethods.cjs');
|
|
7
5
|
|
|
8
6
|
var __defProp = Object.defineProperty;
|
|
9
7
|
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
10
8
|
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
11
|
-
var __publicField = (obj, key, value) =>
|
|
12
|
-
__defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
13
|
-
return value;
|
|
14
|
-
};
|
|
9
|
+
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
15
10
|
var _Route = class _Route extends pieces.Piece {
|
|
16
11
|
constructor(context, options = {}) {
|
|
17
12
|
super(context, options);
|
|
@@ -30,39 +25,22 @@ var _Route = class _Route extends pieces.Piece {
|
|
|
30
25
|
/**
|
|
31
26
|
* The methods this route accepts.
|
|
32
27
|
*/
|
|
33
|
-
__publicField(this, "methods"
|
|
28
|
+
__publicField(this, "methods");
|
|
34
29
|
const api = this.container.server.options;
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
30
|
+
const prefix = api.prefix ? api.prefix.endsWith("/") ? api.prefix : `${api.prefix}/` : "";
|
|
31
|
+
let path = options.route ?? (this.location.virtual ? this.name : this.location.directories.concat(this.name).join("/"));
|
|
32
|
+
const methods = new Set(options.methods);
|
|
33
|
+
const methodIndex = path.lastIndexOf(".");
|
|
34
|
+
if (methodIndex !== -1) {
|
|
35
|
+
const method = path.slice(methodIndex + 1).toUpperCase();
|
|
36
|
+
if (!methods.has(method)) methods.add(method);
|
|
37
|
+
path = path.slice(0, methodIndex);
|
|
40
38
|
}
|
|
39
|
+
this.methods = methods;
|
|
40
|
+
this.router = new RouteData_cjs.RouteData(`${prefix}${path}`);
|
|
41
41
|
this.maximumBodyLength = options.maximumBodyLength ?? api.maximumBodyLength ?? 1024 * 1024 * 50;
|
|
42
42
|
this.acceptedContentMimeTypes = options.acceptedContentMimeTypes ?? api.acceptedContentMimeTypes ?? null;
|
|
43
43
|
}
|
|
44
|
-
/**
|
|
45
|
-
* Per-piece listener that is called when the piece is loaded into the store.
|
|
46
|
-
* Useful to set-up asynchronous initialization tasks.
|
|
47
|
-
*/
|
|
48
|
-
onLoad() {
|
|
49
|
-
const store = this.store;
|
|
50
|
-
for (const [method, cb] of this.methods) {
|
|
51
|
-
store.table.get(method).set(this, cb.bind(this));
|
|
52
|
-
}
|
|
53
|
-
return void 0;
|
|
54
|
-
}
|
|
55
|
-
/**
|
|
56
|
-
* Per-piece listener that is called when the piece is unloaded from the store.
|
|
57
|
-
* Useful to set-up clean-up tasks.
|
|
58
|
-
*/
|
|
59
|
-
onUnload() {
|
|
60
|
-
const store = this.store;
|
|
61
|
-
for (const [method] of this.methods) {
|
|
62
|
-
store.table.get(method).delete(this);
|
|
63
|
-
}
|
|
64
|
-
return void 0;
|
|
65
|
-
}
|
|
66
44
|
};
|
|
67
45
|
__name(_Route, "Route");
|
|
68
46
|
var Route = _Route;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/lib/structures/Route.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"sources":["../../../../src/lib/structures/Route.ts"],"names":[],"mappings":";;;;;;AAAA,SAAS,aAAa;AAEtB,SAAS,iBAAiB;AA2CnB,IAAe,SAAf,MAAe,eAA6D,MAAyB;AAAA,EAqBpG,YAAY,SAA8B,UAAmB,CAAC,GAAc;AAClF,UAAM,SAAS,OAAO;AAlBvB;AAAA;AAAA;AAAA,wBAAgB;AAKhB;AAAA;AAAA;AAAA,wBAAgB;AAKhB;AAAA;AAAA;AAAA,wBAAgB;AAKhB;AAAA;AAAA;AAAA,wBAAgB;AAKf,UAAM,MAAM,KAAK,UAAU,OAAO;AAElC,UAAM,SAAS,IAAI,SAAU,IAAI,OAAO,SAAS,GAAG,IAAI,IAAI,SAAS,GAAG,IAAI,MAAM,MAAO;AAIzF,QAAI,OAAO,QAAQ,UAAU,KAAK,SAAS,UAAU,KAAK,OAAO,KAAK,SAAS,YAAY,OAAO,KAAK,IAAI,EAAE,KAAK,GAAG;AAErH,UAAM,UAAU,IAAI,IAAI,QAAQ,OAAO;AAEvC,UAAM,cAAc,KAAK,YAAY,GAAG;AACxC,QAAI,gBAAgB,IAAI;AAEvB,YAAM,SAAS,KAAK,MAAM,cAAc,CAAC,EAAE,YAAY;AACvD,UAAI,CAAC,QAAQ,IAAI,MAAM,EAAG,SAAQ,IAAI,MAAM;AAG5C,aAAO,KAAK,MAAM,GAAG,WAAW;AAAA,IACjC;AAEA,SAAK,UAAU;AACf,SAAK,SAAS,IAAI,UAAU,GAAG,MAAM,GAAG,IAAI,EAAE;AAC9C,SAAK,oBAAoB,QAAQ,qBAAqB,IAAI,qBAAqB,OAAO,OAAO;AAC7F,SAAK,2BAA2B,QAAQ,4BAA4B,IAAI,4BAA4B;AAAA,EACrG;AAGD;AAnD4G;AAArG,IAAe,QAAf","sourcesContent":["import { Piece } from '@sapphire/pieces';\nimport type { Awaitable } from '@sapphire/utilities';\nimport { RouteData } from '../utils/RouteData';\nimport type { ApiRequest } from './api/ApiRequest';\nimport type { ApiResponse } from './api/ApiResponse';\nimport type { MethodName } from './http/HttpMethods';\nimport type { MimeTypeWithoutParameters } from './http/Server';\n\n/**\n * @since 1.0.0\n *\n * @example A simple GET route that returns a JSON response:\n * ```typescript\n * // hello.get.ts\n * import { Route } from '@sapphire/plugin-api';\n *\n * export class MyRoute extends Route {\n * public run(request: Route.Request, response: Route.Response) {\n * return response.json({ message: 'Hello, World!' });\n * }\n * }\n * ```\n *\n * ```bash\n * $ curl http://localhost:4000/hello\n * {\"message\":\"Hello, World!\"}\n * ```\n *\n * @example A simple POST route that reads the body and returns it:\n * ```typescript\n * // echo.post.ts\n * import { Route } from '@sapphire/plugin-api';\n *\n * export class MyRoute extends Route {\n * public run(request: Route.Request, response: Route.Response) {\n * return response.json(request.params);\n * }\n * }\n * ```\n *\n * ```bash\n * $ curl -X POST -H \"Content-Type: application/json\" -d '{\"hello\":\"world\"}' http://localhost:4000/echo\n * {\"hello\":\"world\"}\n * ```\n */\nexport abstract class Route<Options extends Route.Options = Route.Options> extends Piece<Options, 'routes'> {\n\t/**\n\t * (RFC 7230 3.3.2) The maximum decimal number of octets.\n\t */\n\tpublic readonly maximumBodyLength: number;\n\n\t/**\n\t * The accepted content types.\n\t */\n\tpublic readonly acceptedContentMimeTypes: readonly MimeTypeWithoutParameters[] | null;\n\n\t/**\n\t * The route information.\n\t */\n\tpublic readonly router: RouteData;\n\n\t/**\n\t * The methods this route accepts.\n\t */\n\tpublic readonly methods: ReadonlySet<MethodName>;\n\n\tpublic constructor(context: Route.LoaderContext, options: Options = {} as Options) {\n\t\tsuper(context, options);\n\n\t\tconst api = this.container.server.options;\n\t\t// Concat a `/` to the prefix if it does not end with it\n\t\tconst prefix = api.prefix ? (api.prefix.endsWith('/') ? api.prefix : `${api.prefix}/`) : '';\n\t\t// Use the defined route, otherwise:\n\t\t// - If the location is virtual, use the name.\n\t\t// - Otherwise, use the directories and the name.\n\t\tlet path = options.route ?? (this.location.virtual ? this.name : this.location.directories.concat(this.name).join('/'));\n\n\t\tconst methods = new Set(options.methods);\n\t\t// If the path contains a method (e.g. `/users.get`), extract it and add it to the methods set:\n\t\tconst methodIndex = path.lastIndexOf('.');\n\t\tif (methodIndex !== -1) {\n\t\t\t// Extract the method from the path:\n\t\t\tconst method = path.slice(methodIndex + 1).toUpperCase() as MethodName;\n\t\t\tif (!methods.has(method)) methods.add(method);\n\n\t\t\t// Update the path to remove the method:\n\t\t\tpath = path.slice(0, methodIndex);\n\t\t}\n\n\t\tthis.methods = methods;\n\t\tthis.router = new RouteData(`${prefix}${path}`);\n\t\tthis.maximumBodyLength = options.maximumBodyLength ?? api.maximumBodyLength ?? 1024 * 1024 * 50;\n\t\tthis.acceptedContentMimeTypes = options.acceptedContentMimeTypes ?? api.acceptedContentMimeTypes ?? null;\n\t}\n\n\tpublic abstract run(request: Route.Request, response: Route.Response): Awaitable<unknown>;\n}\n\nexport interface RouteOptions extends Piece.Options {\n\t/**\n\t * The route the piece should represent.\n\t * @since 1.0.0\n\t *\n\t * @defaultValue The filesystem-based path, or the name if the location is virtual.\n\t *\n\t * @example\n\t * ```typescript\n\t * '/users'\n\t * // request.params -> {}\n\t * ```\n\t * @example\n\t * ```typescript\n\t * '/guilds/[guild]/members/[member]'\n\t * // request.params -> { guild: '...', member: '...' }\n\t * ```\n\t */\n\troute?: string;\n\n\t/**\n\t * (RFC 7230 3.3.2) The maximum decimal number of octets.\n\t * @since 1.0.0\n\t *\n\t * @defaultValue this.context.server.options.maximumBodyLength ?? 1024 * 1024 * 50\n\t */\n\tmaximumBodyLength?: number;\n\n\t/**\n\t * The accepted content types for this route. If set to null, the route will accept any data.\n\t * @since 1.3.0\n\t *\n\t * @defaultValue this.context.server.options.acceptedContentMimeTypes ?? null\n\t */\n\tacceptedContentMimeTypes?: readonly MimeTypeWithoutParameters[] | null;\n\n\t/**\n\t * The methods this route accepts.\n\t * @since 7.0.0\n\t *\n\t * @defaultValue The method defined in the piece name, or none if not set.\n\t */\n\tmethods?: readonly MethodName[];\n}\n\nexport namespace Route {\n\t/** @deprecated Use {@linkcode LoaderContext} instead. */\n\texport type Context = LoaderContext;\n\texport type LoaderContext = Piece.LoaderContext<'routes'>;\n\texport type Options = RouteOptions;\n\texport type JSON = Piece.JSON;\n\texport type LocationJSON = Piece.LocationJSON;\n\n\texport type Request = ApiRequest;\n\texport type Response = ApiResponse;\n}\n"]}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var pieces = require('@sapphire/pieces');
|
|
4
|
+
var discord_js = require('discord.js');
|
|
5
|
+
|
|
6
|
+
var __defProp = Object.defineProperty;
|
|
7
|
+
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
8
|
+
var _RouteLoaderStrategy = class _RouteLoaderStrategy extends pieces.LoaderStrategy {
|
|
9
|
+
onLoad(store, piece) {
|
|
10
|
+
for (const method of piece.methods) {
|
|
11
|
+
store.methods.ensure(method, () => new discord_js.Collection()).set(piece, piece.router);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
onUnload(store, piece) {
|
|
15
|
+
for (const method of piece.methods) {
|
|
16
|
+
const methods = store.methods.get(method);
|
|
17
|
+
if (typeof methods === "undefined") continue;
|
|
18
|
+
methods.delete(piece);
|
|
19
|
+
if (methods.size === 0) store.methods.delete(method);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
__name(_RouteLoaderStrategy, "RouteLoaderStrategy");
|
|
24
|
+
var RouteLoaderStrategy = _RouteLoaderStrategy;
|
|
25
|
+
|
|
26
|
+
exports.RouteLoaderStrategy = RouteLoaderStrategy;
|
|
27
|
+
//# sourceMappingURL=out.js.map
|
|
28
|
+
//# sourceMappingURL=RouteLoaderStrategy.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../src/lib/structures/RouteLoaderStrategy.ts"],"names":[],"mappings":";;;;AAAA,SAAS,sBAAsB;AAC/B,SAAS,kBAAkB;AAIpB,IAAM,uBAAN,MAAM,6BAA4B,eAAsB;AAAA,EAC9C,OAAO,OAAmB,OAAoB;AAC7D,eAAW,UAAU,MAAM,SAAS;AACnC,YAAM,QAAQ,OAAO,QAAQ,MAAM,IAAI,WAAW,CAAC,EAAE,IAAI,OAAO,MAAM,MAAM;AAAA,IAC7E;AAAA,EACD;AAAA,EAEgB,SAAS,OAAmB,OAAoB;AAC/D,eAAW,UAAU,MAAM,SAAS;AACnC,YAAM,UAAU,MAAM,QAAQ,IAAI,MAAM;AACxC,UAAI,OAAO,YAAY,YAAa;AAEpC,cAAQ,OAAO,KAAK;AACpB,UAAI,QAAQ,SAAS,EAAG,OAAM,QAAQ,OAAO,MAAM;AAAA,IACpD;AAAA,EACD;AACD;AAhB+D;AAAxD,IAAM,sBAAN","sourcesContent":["import { LoaderStrategy } from '@sapphire/pieces';\nimport { Collection } from 'discord.js';\nimport type { Route } from './Route';\nimport type { RouteStore } from './RouteStore';\n\nexport class RouteLoaderStrategy extends LoaderStrategy<Route> {\n\tpublic override onLoad(store: RouteStore, piece: Route): void {\n\t\tfor (const method of piece.methods) {\n\t\t\tstore.methods.ensure(method, () => new Collection()).set(piece, piece.router);\n\t\t}\n\t}\n\n\tpublic override onUnload(store: RouteStore, piece: Route): void {\n\t\tfor (const method of piece.methods) {\n\t\t\tconst methods = store.methods.get(method);\n\t\t\tif (typeof methods === 'undefined') continue;\n\n\t\t\tmethods.delete(piece);\n\t\t\tif (methods.size === 0) store.methods.delete(method);\n\t\t}\n\t}\n}\n"]}
|
|
@@ -1,43 +1,38 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var pieces = require('@sapphire/pieces');
|
|
4
|
+
var utilities = require('@sapphire/utilities');
|
|
4
5
|
var discord_js = require('discord.js');
|
|
5
6
|
var url = require('url');
|
|
6
|
-
var HttpMethods_cjs = require('./http/HttpMethods.cjs');
|
|
7
7
|
var Route_cjs = require('./Route.cjs');
|
|
8
|
+
var RouteLoaderStrategy_cjs = require('./RouteLoaderStrategy.cjs');
|
|
8
9
|
|
|
9
10
|
var __defProp = Object.defineProperty;
|
|
10
11
|
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
11
12
|
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
12
|
-
var __publicField = (obj, key, value) =>
|
|
13
|
-
__defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
14
|
-
return value;
|
|
15
|
-
};
|
|
13
|
+
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
16
14
|
var slash = "/".charCodeAt(0);
|
|
17
15
|
var _RouteStore = class _RouteStore extends pieces.Store {
|
|
18
16
|
constructor() {
|
|
19
|
-
super(Route_cjs.Route, { name: "routes" });
|
|
20
|
-
__publicField(this, "
|
|
21
|
-
for (const [method] of HttpMethods_cjs.methodEntries)
|
|
22
|
-
this.table.set(method, new discord_js.Collection());
|
|
17
|
+
super(Route_cjs.Route, { name: "routes", strategy: new RouteLoaderStrategy_cjs.RouteLoaderStrategy() });
|
|
18
|
+
__publicField(this, "methods", new discord_js.Collection());
|
|
23
19
|
}
|
|
24
20
|
match(request) {
|
|
25
21
|
const { method } = request;
|
|
26
22
|
if (typeof method === "undefined") {
|
|
27
23
|
return null;
|
|
28
24
|
}
|
|
29
|
-
const methodTable = this.
|
|
30
|
-
if (
|
|
25
|
+
const methodTable = this.methods.get(method);
|
|
26
|
+
if (utilities.isNullish(methodTable)) {
|
|
31
27
|
return null;
|
|
32
28
|
}
|
|
33
29
|
const { splits, querystring } = this.parseURL(request.url);
|
|
34
|
-
for (const [route,
|
|
35
|
-
const result =
|
|
36
|
-
if (result === null)
|
|
37
|
-
continue;
|
|
30
|
+
for (const [route, router] of methodTable.entries()) {
|
|
31
|
+
const result = router.match(splits);
|
|
32
|
+
if (result === null) continue;
|
|
38
33
|
request.params = result;
|
|
39
34
|
request.query = Object.fromEntries(new url.URLSearchParams(querystring).entries());
|
|
40
|
-
return
|
|
35
|
+
return route;
|
|
41
36
|
}
|
|
42
37
|
return null;
|
|
43
38
|
}
|
|
@@ -52,10 +47,8 @@ var _RouteStore = class _RouteStore extends pieces.Store {
|
|
|
52
47
|
pathname = url.substring(0, index);
|
|
53
48
|
querystring = url.substring(index + 1);
|
|
54
49
|
}
|
|
55
|
-
if (pathname.charCodeAt(0) === slash)
|
|
56
|
-
|
|
57
|
-
if (pathname.length > 0 && pathname.charCodeAt(pathname.length - 1) === slash)
|
|
58
|
-
pathname = pathname.substring(0, pathname.length - 1);
|
|
50
|
+
if (pathname.charCodeAt(0) === slash) pathname = pathname.substring(1);
|
|
51
|
+
if (pathname.length > 0 && pathname.charCodeAt(pathname.length - 1) === slash) pathname = pathname.substring(0, pathname.length - 1);
|
|
59
52
|
const splits = pathname.split("/");
|
|
60
53
|
return { splits, querystring };
|
|
61
54
|
}
|