nitro-web 0.0.98 → 0.0.100

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nitro-web",
3
- "version": "0.0.98",
3
+ "version": "0.0.100",
4
4
  "repository": "github:boycce/nitro-web",
5
5
  "homepage": "https://boycce.github.io/nitro-web/",
6
6
  "description": "Nitro is a battle-tested, modular base project to turbocharge your projects, styled using Tailwind 🚀",
@@ -55,7 +55,8 @@
55
55
  "tailwind-merge": "^2.6.0"
56
56
  },
57
57
  "devDependencies": {
58
- "@types/dateformat": "^5.0.3"
58
+ "@types/dateformat": "^5.0.3",
59
+ "@typescript-eslint/eslint-plugin": "^8.18.1"
59
60
  },
60
61
  "peerDependencies": {
61
62
  "@stripe/stripe-js": "^1.34.0",
package/server/index.js CHANGED
@@ -2,6 +2,11 @@
2
2
  export * from '../util.js'
3
3
  export * as util from '../util.js'
4
4
 
5
+ /**
6
+ * Re-export the MiddlewareConfig type from nitro-web/server
7
+ * @typedef {import('./router.js').MiddlewareConfig} MiddlewareConfig
8
+ */
9
+
5
10
  // Export models
6
11
  import userModel from './models/user.js'
7
12
  import companyModel from './models/company.js'
package/server/router.js CHANGED
@@ -12,9 +12,29 @@ import sortRouteAddressesNodeps from 'sort-route-addresses-nodeps'
12
12
  import { sendEmail } from 'nitro-web/server'
13
13
  import * as util from 'nitro-web/util'
14
14
 
15
+ /**
16
+ * @typedef {express.Request & {
17
+ * version: string,
18
+ * user?: import('types').User,
19
+ * }} Request
20
+ * @typedef {express.Response & {
21
+ * error: (msg?: string | Error | Error[], detail?: string) => void,
22
+ * unauthorized: (msg?: string | Error | Error[]) => void,
23
+ * forbidden: (msg?: string | Error | Error[]) => void,
24
+ * notFound: (msg?: string | Error | Error[]) => void,
25
+ * serverError: (msg?: string | Error | Error[]) => void,
26
+ * }} Response
27
+ * @typedef {{
28
+ * order: string[],
29
+ * [key: string]: ((req: Request, res: Response, next: Function) => void) | string[],
30
+ * }} MiddlewareConfig
31
+ */
32
+
33
+ let configLocal
15
34
  const _dirname = dirname(fileURLToPath(import.meta.url)) + '/'
16
35
 
17
36
  export async function setupRouter (config) {
37
+ configLocal = config
18
38
  const { env, middleware: configMiddleware, version } = config
19
39
  const { componentsDir, distDir, emailTemplateDir } = util.getDirectories(path, config.pwd)
20
40
  const expressApp = express()
@@ -53,8 +73,9 @@ export async function setupRouter (config) {
53
73
 
54
74
  if (routes?.setup) routes.setup.call(routes, allMiddleware, config)
55
75
  if (routes) {
56
- util.each(routes, (_middleware, key) => {
57
- if (!key.match(/\s/)) return
76
+ util.each(routes, (_middleware, _key) => {
77
+ if (!_key.match(/\s/)) return
78
+ const key = _key.replace(/\s+/g, ' ')
58
79
  const match = key.match(new RegExp(`^(${verbs.join('|')})\\s+(.*)$`, 'i'))
59
80
  if (!match) throw new Error(`Invalid verb or path: ${key}`)
60
81
  apiRoutes[key] = {
@@ -297,6 +318,7 @@ function resolveMiddleware (controllers, middleware, route, item) {
297
318
  }
298
319
  }
299
320
 
321
+ /** @type {MiddlewareConfig} */
300
322
  export const middleware = {
301
323
  // Default middleware called before all /api/* routes
302
324
  order: [
@@ -350,39 +372,44 @@ export const middleware = {
350
372
 
351
373
  // --- Custom middleware ----------------------
352
374
 
375
+
353
376
  isAdmin: (req, res, next) => {
354
377
  // Still need to remove cookie matching in favour of uid..
355
378
  // E.g. Cookie matching handy for rare issues, e.g. signout > signin (to a different user on another tab)
356
379
  const user = req.user
357
- let cookieMatch = user && (!req.headers.authid || user._id.toString() == req.headers.authid)
358
- if (cookieMatch && (user.type?.match(/admin/) || user.isAdmin)) next()
380
+ let cookieMatch = user && (!req.headers.authid || user._id?.toString() == req.headers.authid)
381
+ if (cookieMatch && user && (user.type?.match(/admin/) || user.isAdmin)) next()
359
382
  else if (user && (user.type?.match(/admin/) || user.isAdmin)) res.unauthorized('Invalid cookie, please refresh your browser')
360
383
  else if (user) res.unauthorized('You are not authorised to make this request.')
361
384
  else res.unauthorized('Please sign in first.')
362
385
  },
363
- isCompanyOwner: (req, res, next) => {
364
- let user = req.user || { companies: [] }
365
- let cid = req.params.cid
366
- let company = user.companies.find((o) => o._id.toString() == cid)
367
- let companyUser = company?.users?.find((o) => o._id.toString() == user._id.toString())
368
- if (!user._id) return res.unauthorized('Please sign in first.')
369
- else if (!company || !companyUser) res.unauthorized('You are not authorised to make this request.')
370
- else if (companyUser.type != 'owner') res.unauthorized('Only owners can make this request.')
371
- else next()
372
- },
373
- isCompanyUser: (req, res, next) => {
374
- let user = req.user || { companies: [] }
375
- let cid = req.params.cid
376
- let company = user.companies.find((o) => o._id.toString() == cid)
377
- if (!user._id) return res.unauthorized('Please sign in first.')
378
- else if (!company) res.unauthorized('You are not authorised to make this request.')
379
- else next()
380
- },
386
+ // isCompanyOwner: (req, res, next) => {
387
+ // let user = req.user || { companies: [] }
388
+ // let cid = req.params.cid
389
+ // let company = user.companies.find((o) => o._id.toString() == cid)
390
+ // let companyUser = company?.users?.find((o) => o._id.toString() == user._id?.toString())
391
+ // if (!user._id) return res.unauthorized('Please sign in first.')
392
+ // else if (!company || !companyUser) res.unauthorized('You are not authorised to make this request.')
393
+ // else if (companyUser.type != 'owner') res.unauthorized('Only owners can make this request.')
394
+ // else next()
395
+ // },
396
+ // isCompanyUser: (req, res, next) => {
397
+ // let user = req.user || { companies: [] }
398
+ // let cid = req.params.cid
399
+ // let company = user.companies.find((o) => o._id.toString() == cid)
400
+ // if (!user._id) return res.unauthorized('Please sign in first.')
401
+ // else if (!company) res.unauthorized('You are not authorised to make this request.')
402
+ // else next()
403
+ // },
381
404
  isUser: (req, res, next) => {
382
405
  // todo: need to double check that uid is always defined
383
406
  let uid = req.params.uid
384
- if (req.user && (typeof uid == 'undefined' || req.user._id.toString() == uid)) next()
407
+ if (req.user && (typeof uid == 'undefined' || req.user._id?.toString() == uid)) next()
385
408
  else if (req.user) res.unauthorized('You are not authorised to make this request.')
386
409
  else res.unauthorized('Please sign in first.')
387
410
  },
411
+ isDevelopment: (req, res, next) => {
412
+ if (configLocal.env !== 'development') res.error('This API endpoint is only available in development')
413
+ else next()
414
+ },
388
415
  }
@@ -5,6 +5,10 @@ export * as util from "../util.js";
5
5
  export { sendEmail } from "./email/index.js";
6
6
  export { routes as authRoutes } from "../components/auth/auth.api.js";
7
7
  export { routes as stripeRoutes } from "../components/billing/stripe.api.js";
8
+ /**
9
+ * Re-export the MiddlewareConfig type from nitro-web/server
10
+ */
11
+ export type MiddlewareConfig = import("./router.js").MiddlewareConfig;
8
12
  import userModel from './models/user.js';
9
13
  import companyModel from './models/company.js';
10
14
  export function setupDefaultModels(db: any): Promise<void>;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../server/index.js"],"names":[],"mappings":";;;;;;;sBAKsB,kBAAkB;yBACf,qBAAqB;AAC9C,2DAIC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../server/index.js"],"names":[],"mappings":";;;;;;;;;;+BAMa,OAAO,aAAa,EAAE,gBAAgB;sBAI7B,kBAAkB;yBACf,qBAAqB;AAC9C,2DAIC"}
@@ -1,15 +1,21 @@
1
1
  export function setupRouter(config: any): Promise<http.Server<typeof http.IncomingMessage, typeof http.ServerResponse>>;
2
- export namespace middleware {
3
- let order: string[];
4
- function modifyRequest(req: any, res: any, next: any): void;
5
- let parseUrlEncoded: import("connect").NextHandleFunction;
6
- let parseJson: import("connect").NextHandleFunction;
7
- function parseFile(req: any, res: any, next: any): void;
8
- function beforeAPIRoute(req: any, res: any, next: any): void;
9
- function isAdmin(req: any, res: any, next: any): void;
10
- function isCompanyOwner(req: any, res: any, next: any): any;
11
- function isCompanyUser(req: any, res: any, next: any): any;
12
- function isUser(req: any, res: any, next: any): void;
13
- }
2
+ /** @type {MiddlewareConfig} */
3
+ export const middleware: MiddlewareConfig;
4
+ export type Request = express.Request & {
5
+ version: string;
6
+ user?: any;
7
+ };
8
+ export type Response = express.Response & {
9
+ error: (msg?: string | Error | Error[], detail?: string) => void;
10
+ unauthorized: (msg?: string | Error | Error[]) => void;
11
+ forbidden: (msg?: string | Error | Error[]) => void;
12
+ notFound: (msg?: string | Error | Error[]) => void;
13
+ serverError: (msg?: string | Error | Error[]) => void;
14
+ };
15
+ export type MiddlewareConfig = {
16
+ order: string[];
17
+ [key: string]: ((req: Request, res: Response, next: Function) => void) | string[];
18
+ };
14
19
  import http from 'http';
20
+ import express from 'express';
15
21
  //# sourceMappingURL=router.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"router.d.ts","sourceRoot":"","sources":["../../server/router.js"],"names":[],"mappings":"AAgBA,wHA2HC;;;IA6KgB,4DAKd;;;IAoBU,wDAMV;IAEe,6DAGf;IAIQ,sDASR;IACe,4DASf;IACc,2DAOd;IACO,qDAMP;;iBA/Xc,MAAM"}
1
+ {"version":3,"file":"router.d.ts","sourceRoot":"","sources":["../../server/router.js"],"names":[],"mappings":"AAmCA,wHA6HC;AAgKD,+BAA+B;AAC/B,yBADW,gBAAgB,CA8F1B;sBA/YY,OAAO,CAAC,OAAO,GAAG;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,GAAoB,CAAC;CAC7B;uBACS,OAAO,CAAC,QAAQ,GAAG;IAC3B,KAAK,EAAE,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,KAAK,GAAG,KAAK,EAAE,EAAE,MAAM,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;IACjE,YAAY,EAAE,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,KAAK,GAAG,KAAK,EAAE,KAAK,IAAI,CAAC;IACvD,SAAS,EAAE,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,KAAK,GAAG,KAAK,EAAE,KAAK,IAAI,CAAC;IACpD,QAAQ,EAAE,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,KAAK,GAAG,KAAK,EAAE,KAAK,IAAI,CAAC;IACnD,WAAW,EAAE,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,KAAK,GAAG,KAAK,EAAE,KAAK,IAAI,CAAC;CACvD;+BACS;IACR,KAAK,EAAE,MAAM,EAAE,CAAC;IACpB,CAAK,GAAG,EAAE,MAAM,GAAG,CAAC,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,UAAU,KAAK,IAAI,CAAC,GAAG,MAAM,EAAE,CAAC;CACnF;iBA1Ba,MAAM;oBAIH,SAAS"}
package/types.ts CHANGED
@@ -30,6 +30,8 @@ export type User = {
30
30
  lastName?: string
31
31
  name?: string
32
32
  avatar?: MonasteryImage
33
+ isAdmin?: boolean
34
+ type?: string
33
35
  }
34
36
 
35
37
  export type Error = { title: string, detail: string }