duto 0.260906.0 → 0.261001.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.
Files changed (75) hide show
  1. package/README.md +34 -12
  2. package/package.json +9 -3
  3. package/src/cli.ts +10 -7
  4. package/src/commands/new.ts +172 -0
  5. package/src/commands/templates/pages/.editorconfig +21 -0
  6. package/src/commands/templates/pages/README.md +21 -0
  7. package/src/commands/templates/pages/_gitignore +24 -0
  8. package/src/commands/templates/pages/components/locale-select.tsx +59 -0
  9. package/src/commands/templates/pages/components/select.tsx +95 -0
  10. package/src/commands/templates/pages/i18n/en.ts +17 -0
  11. package/src/commands/templates/pages/i18n/index.ts +19 -0
  12. package/src/commands/templates/pages/i18n/pt-br.ts +17 -0
  13. package/src/commands/templates/pages/package.json +22 -0
  14. package/src/commands/templates/pages/pages/404.tsx +12 -0
  15. package/src/commands/templates/pages/pages/index.tsx +16 -0
  16. package/src/commands/templates/pages/pages/layout.tsx +24 -0
  17. package/src/commands/templates/pages/style.css +24 -0
  18. package/src/commands/templates/pages/tsconfig.json +54 -0
  19. package/src/commands/templates/pages/types.ts +8 -0
  20. package/src/commands/templates/server/base/.editorconfig +21 -0
  21. package/src/commands/templates/server/base/.env.dev.example +2 -0
  22. package/src/commands/templates/server/base/.env.prod.example +2 -0
  23. package/src/commands/templates/server/base/README.md +29 -0
  24. package/src/commands/templates/server/base/_gitignore +100 -0
  25. package/src/commands/templates/server/base/actions/blog/index.get.ts +9 -0
  26. package/src/commands/templates/server/base/actions/blog/post/[id].get.ts +9 -0
  27. package/src/commands/templates/server/base/actions/index.get.ts +5 -0
  28. package/src/commands/templates/server/base/configs/duto.ts +11 -0
  29. package/src/commands/templates/server/base/configs/roles.ts +5 -0
  30. package/src/commands/templates/server/base/package.json +24 -0
  31. package/src/commands/templates/server/base/tsconfig.json +42 -0
  32. package/src/commands/templates/server/workerd/wrangler.toml +47 -0
  33. package/src/commands/upgrade.ts +30 -0
  34. package/src/index.ts +7 -2
  35. package/src/pages/{commands → cli/commands}/build.ts +13 -7
  36. package/src/pages/{commands → cli/commands}/dev.ts +19 -6
  37. package/src/pages/{commands → cli/commands}/preview.ts +6 -4
  38. package/src/pages/cli/index.ts +10 -0
  39. package/src/pages/cli/utils.ts +126 -0
  40. package/src/pages/client/app.tsx +27 -74
  41. package/src/pages/client/router.ts +15 -281
  42. package/src/pages/compiler/aliases.ts +2 -8
  43. package/src/pages/compiler/ast.ts +1 -538
  44. package/src/pages/compiler/constants.ts +95 -13
  45. package/src/pages/compiler/file.ts +1 -1
  46. package/src/pages/compiler/index.ts +20 -128
  47. package/src/pages/compiler/meta.ts +39 -228
  48. package/src/pages/compiler/routes.ts +4 -5
  49. package/src/pages/compiler/types.ts +11 -101
  50. package/src/pages/compiler/vite-plugin.ts +90 -69
  51. package/src/pages/i18n/client.ts +19 -7
  52. package/src/pages/i18n/element.ts +1 -1
  53. package/src/pages/i18n/server.ts +22 -7
  54. package/src/pages/index.ts +1 -2
  55. package/src/pages/preact/server.ts +1 -1
  56. package/src/server/app.ts +5 -10
  57. package/src/server/auth/ability.ts +1 -1
  58. package/src/server/auth/token.ts +5 -5
  59. package/src/server/cli/commands/build.ts +2 -2
  60. package/src/server/cli/commands/deploy.ts +1 -2
  61. package/src/server/cli/commands/dev.ts +6 -4
  62. package/src/server/cli/commands/routes.ts +0 -1
  63. package/src/server/cli/utils.ts +2 -8
  64. package/src/server/config.ts +18 -3
  65. package/src/server/entry.ts +3 -3
  66. package/src/server/open-api/register.ts +3 -3
  67. package/src/server/open-api/spec.ts +11 -4
  68. package/src/server/request.ts +46 -14
  69. package/src/server/routes.ts +8 -31
  70. package/src/server/utils.ts +25 -0
  71. package/src/utils.ts +43 -2
  72. package/src/pages/commands/dev-old.ts +0 -213
  73. package/src/pages/compiler/island.ts +0 -108
  74. package/src/pages/compiler/utils.ts +0 -5
  75. package/src/server/http.ts +0 -23
@@ -1,5 +1,5 @@
1
- import { Envir, parseUA } from 't0n'
2
- import { sha256, toString, type Config } from 'cripta'
1
+ import { bytesToHex, getEnv, parseUA } from 't0n'
2
+ import { sha256, type Config } from 'cripta'
3
3
  import { config, create, parse } from 'cripta/token'
4
4
  import type { IRequest } from '$/types'
5
5
 
@@ -76,12 +76,12 @@ export class Token {
76
76
  if (this.#cripta)
77
77
  return this.#cripta
78
78
 
79
- return this.#cripta = await config({ key: Envir.get<string>('KEY') })
79
+ return this.#cripta = await config({ key: getEnv('KEY') })
80
80
  }
81
81
 
82
82
  static async parse(req: IRequest, token: string) {
83
83
  const host = this.host(req)
84
- const serveHost = Envir.get('FLOW_SERVER', host) as string
84
+ const serveHost = getEnv('FLOW_SERVER', host) as string
85
85
 
86
86
  return parse(await this.cripta(), token, {
87
87
  iss: serveHost,
@@ -130,7 +130,7 @@ export class Token {
130
130
  static async fingerprint(req: IRequest) {
131
131
  const ua = parseUA(req.header('user-agent'))
132
132
 
133
- const id = toString(await sha256(
133
+ const id = bytesToHex(await sha256(
134
134
  // (req.header('accept-language') || '')
135
135
  this.ip(req)
136
136
  + ua.browser.name + ua.browser.version.split('.')[0]
@@ -1,4 +1,4 @@
1
- import { Envir } from 't0n'
1
+ import { getEnv } from 't0n'
2
2
  import { command } from 't0n/cli'
3
3
  import { gray } from 't0n/color'
4
4
  import { wait, error, rn } from 't0n/log'
@@ -23,7 +23,7 @@ export default command({
23
23
  },
24
24
  },
25
25
  async run({ args }) {
26
- const platform = normalizePlatform(args.p || args.platform || Envir.get('duto.platform') || args._[0] || 'node')
26
+ const platform = normalizePlatform(args.p || args.platform || getEnv('duto.platform') || args._[0] || 'node')
27
27
  if (!platform)
28
28
  return platformError()
29
29
 
@@ -1,5 +1,4 @@
1
1
  import { spawn } from 'node:child_process'
2
- import { Envir } from 't0n'
3
2
  import { command } from 't0n/cli'
4
3
  import { error } from 't0n/log'
5
4
  import { getRuntime } from 't0n/cli'
@@ -28,7 +27,7 @@ export default command({
28
27
  },
29
28
  },
30
29
  async run({ args }) { // @ts-ignore
31
- const platform = normalizePlatform(args.p || args.platform || args._[0] || Envir.get('duto.platform'))
30
+ const platform = normalizePlatform(args.p || args.platform || args._[0] || getEnv('duto.platform'))
32
31
  if (!platform)
33
32
  return platformError()
34
33
 
@@ -16,7 +16,7 @@ import {
16
16
  } from '../utils'
17
17
  import { _root } from '@/utils'
18
18
  import { withPort } from 't0n/port'
19
- import { Envir } from 't0n'
19
+ import { getEnv } from 't0n'
20
20
  import { $dev, setEnv } from '$/utils/environment'
21
21
 
22
22
  export default command({
@@ -50,13 +50,15 @@ export default command({
50
50
  },
51
51
  async run({ args }) {
52
52
  setEnv($dev)
53
- const duto = Envir.get('duto', {})
53
+ const duto = getEnv('duto', {})
54
54
  const platform = normalizePlatform(args.p || args.platform || duto.platform || args._[0] || 'node')
55
55
  if (!platform)
56
56
  return platformError()
57
57
 
58
- const desiredPort = args.port ? Number(args.port) : duto?.dev?.port || 3000
59
- const host = args.host ? String(args.host) : duto?.dev?.host || 'localhost'
58
+ const desiredPort = Number(args.port || duto?.dev?.port || 3000)
59
+ const host = String(args.host || duto?.dev?.host || 'localhost')
60
+ // const desiredPort = args.port ? Number(args.port) : duto?.dev?.port || 3000
61
+ // const host = args.host ? String(args.host) : duto?.dev?.host || 'localhost'
60
62
 
61
63
  let isBuilding = false
62
64
  const startApp = async (start: Function, stop: Function|undefined = undefined, building: boolean = true) => {
@@ -1,6 +1,5 @@
1
1
  import { command } from 't0n/cli'
2
2
  import { rn } from 't0n/log'
3
- import { _duto } from '@/utils'
4
3
  import { highlightedURI, highlightedMethod } from '../utils'
5
4
  import { getRoutes } from '$/routes'
6
5
 
@@ -4,7 +4,6 @@ import { mkdirSync, existsSync, statSync, readdirSync, rmSync, unlinkSync, copyF
4
4
  import { stat } from 'node:fs/promises'
5
5
  import { basename, dirname, join } from 'pathe'
6
6
  import { createHash, createHmac } from 'node:crypto'
7
- import { filesize } from 'filesize'
8
7
 
9
8
  import { findWranglerConfig, parseWranglerConfig, WRANGLER_CONFIG_FILES } from 'localflare-core'
10
9
  import type { WranglerConfig, LocalflareManifest } from 'localflare-core'
@@ -13,7 +12,7 @@ import { gray, bold, italic, purple, yellow, red } from 't0n/color'
13
12
  import { substep, event, error, warn } from 't0n/log'
14
13
 
15
14
  import { cacheRoutes } from '$/routes'
16
- import { _duto, _root } from '@/utils'
15
+ import { _root, _server, filesize } from '@/utils'
17
16
 
18
17
  import type { Platform } from './types'
19
18
 
@@ -137,17 +136,12 @@ export const build = async ({
137
136
  if (!silent) event('Routes cached')
138
137
 
139
138
  const result = await Bun.build({
140
- entrypoints: [join(_duto, 'server', 'adapter', `${platform}.ts`)],
139
+ entrypoints: [join(_server, 'adapter', `${platform}.ts`)],
141
140
  outdir,
142
141
  format: 'esm',
143
142
  target: 'bun',
144
143
  conditions: isWorkerd ? ['worker', 'browser'] : [],
145
144
  minify: !!minify,
146
- // minify: {
147
- // whitespace: true,
148
- // syntax: true,
149
- // identifiers: true,
150
- // },
151
145
 
152
146
  treeShaking: true,
153
147
  legalComments: 'none',
@@ -1,4 +1,19 @@
1
- import { DataBag } from 't0n'
2
1
 
3
- const Config = new DataBag()
4
- export default Config
2
+ import { get, set } from 't0n'
3
+
4
+ const obj: Record<string, unknown> = {}
5
+
6
+ export function getConfig<T = unknown>(key: string, defaultValue: T): T
7
+ export function getConfig<T = unknown>(key: string, defaultValue?: T): T | undefined
8
+ export function getConfig<T = unknown>(key: string, defaultValue?: T) {
9
+ return get<T>(obj, key, defaultValue)
10
+ }
11
+ export const setConfig = (key: string, val: unknown) => set(obj, key, val)
12
+ export function addConfig<T = unknown>(data: Record<string, T>) {
13
+ Object.assign(obj, data)
14
+ }
15
+ // export const getConfig = <T = unknown>(key: string, defaultValue?: T) => get<T>(obj, key, defaultValue)
16
+ // import { DataBag } from 't0n'
17
+
18
+ // const Config = new DataBag()
19
+ // export default Config
@@ -1,4 +1,4 @@
1
- import Config from '$/config'
1
+ import { getConfig } from '$/config'
2
2
  import { registerOpenAPI } from '$/open-api/register'
3
3
  import { Ability } from '$/auth'
4
4
  import $ from '$/app'
@@ -10,10 +10,10 @@ import { routes, middlewares } from '.duto/imports.mjs'
10
10
 
11
11
  // @ts-ignore
12
12
  Ability.fromRoutes(routes)
13
- Ability.roles = Config.get('roles', {})
13
+ Ability.roles = getConfig('roles', {})
14
14
 
15
15
  // @ts-ignore
16
16
  const app = $({ routes, middlewares })
17
- registerOpenAPI(app, Config.get('duto.docs', {}))
17
+ registerOpenAPI(app, getConfig('duto.docs', {}))
18
18
 
19
19
  export { app }
@@ -1,6 +1,6 @@
1
1
  import { basicAuth } from 'hono/basic-auth'
2
2
  import response from '$/response'
3
- import Config from '$/config'
3
+ import { getConfig } from '$/config'
4
4
  import type { Hono } from '$/types'
5
5
 
6
6
  export function registerOpenAPI(app: Hono, opts: any) {
@@ -24,6 +24,6 @@ export function registerOpenAPI(app: Hono, opts: any) {
24
24
  })
25
25
  }
26
26
 
27
- app.get(opts.path, async () => response.html(Config.get('DUTO_OAC')))
28
- app.get(opts.path +'/openapi', async () => response.raw(200, Config.get('DUTO_OAS'), 'application/json'))
27
+ app.get(opts.path, async () => response.html(getConfig('DUTO_OAC')))
28
+ app.get(opts.path +'/openapi', async () => response.raw(200, getConfig('DUTO_OAS'), 'application/json'))
29
29
  }
@@ -1,7 +1,7 @@
1
1
  import { STATUS_CODES } from 'node:http'
2
2
  import { generateSpecs, resolver } from 'hono-openapi'
3
3
  import { array, object, string } from 'zod/mini'
4
- import { Envir } from 't0n'
4
+ import { getEnv } from 't0n'
5
5
  import { Scalar } from '@scalar/hono-api-reference'
6
6
  import { minify } from '@minify-html/node'
7
7
  import type { Hono } from '$/types'
@@ -14,8 +14,8 @@ export function openAPIConfig(opts: any) {
14
14
  agent = false,
15
15
  name = '',
16
16
  title = '',
17
- version = Envir.get('APP_VERSION') || Envir.get('VERSION_HASH') || '1.0.0',
18
- description = Envir.get('APP_DESCRIPTION', ''),
17
+ version = getEnv('APP_VERSION') || getEnv('VERSION_HASH') || '1.0.0',
18
+ description = getEnv('APP_DESCRIPTION', ''),
19
19
  auth = {},
20
20
  ...docs
21
21
  } = opts?.docs ?? {}
@@ -25,7 +25,7 @@ export function openAPIConfig(opts: any) {
25
25
  path,
26
26
  auth,
27
27
  agent: !!agent,
28
- name: name || title || Envir.get('APP_NAME', 'API Docs'),
28
+ name: name || title || getEnv('APP_NAME', 'API Docs'),
29
29
  version,
30
30
  desc: description,
31
31
  ...docs,
@@ -91,6 +91,13 @@ export async function generateOpenAPIClient(app: Hono, opts?: any) {
91
91
  // onLoaded: () => document?.querySelectorAll('[href="https://www.scalar.com"]')?.forEach(el => el.remove()),
92
92
  // favicon: 'https://example.com/favicon.png',
93
93
  // hideDownloadButton: true,
94
+ defaultHttpClient: {
95
+ targetKey: 'shell',
96
+ clientKey: 'curl',
97
+ },
98
+ hiddenClients: [
99
+ 'c', 'clojure', 'csharp', 'dart', 'fsharp', 'go', 'http', 'java', 'julia', 'kotlin', 'node', 'objc', 'ocaml', 'php', 'python', 'powershell', 'r', 'ruby', 'rust', 'swift'
100
+ ],
94
101
  })
95
102
  )
96
103
 
@@ -1,7 +1,7 @@
1
1
  import { getCookie, getSignedCookie, setCookie, setSignedCookie, deleteCookie } from 'hono/cookie'
2
2
  import { HTTPException } from 'hono/http-exception'
3
3
  import { Authnz, Token } from './auth'
4
- import { Envir } from 't0n'
4
+ import { addEnv } from 't0n'
5
5
 
6
6
  import type { Context } from 'hono'
7
7
  import { routePath, matchedRoutes } from 'hono/route'
@@ -10,21 +10,52 @@ import type { CookieOptions, CookiePrefixOptions } from 'hono/utils/cookie'
10
10
  import type { CustomHeader, RequestHeader } from 'hono/utils/headers'
11
11
  import type { BodyData, ParseBodyOptions } from 'hono/utils/body'
12
12
 
13
- const cookieWrapper = (c: Context) => ({
14
- all: () => getCookie(c),
15
- allSigned: (secret: string) => getSignedCookie(c, secret),
16
- get: (name: string, prefixOptions?: CookiePrefixOptions) => prefixOptions ? getCookie(c, name, prefixOptions) : getCookie(c, name),
17
- getSigned: (secret: string, name: string, prefixOptions?: CookiePrefixOptions) => prefixOptions ? getSignedCookie(c, secret, name, prefixOptions) : getSignedCookie(c, secret, name),
18
- set: (name: string, value: string, opt?: CookieOptions) => setCookie(c, name, value, opt),
19
- setSigned: (name: string, value: string, secret: string, opt?: CookieOptions) => setSignedCookie(c, name, value, secret, opt),
20
- delete: (name: string, opt?: CookieOptions) => deleteCookie(c, name, opt)
21
- })
13
+ // function cookieWrapper(c: Context) {
14
+ // return {
15
+ // all: () => getCookie(c),
16
+ // allSigned: (secret: string) => getSignedCookie(c, secret),
17
+ // get: (name: string, prefixOptions?: CookiePrefixOptions) => prefixOptions ? getCookie(c, name, prefixOptions) : getCookie(c, name),
18
+ // getSigned: (secret: string, name: string, prefixOptions?: CookiePrefixOptions) => prefixOptions ? getSignedCookie(c, secret, name, prefixOptions) : getSignedCookie(c, secret, name),
19
+ // set: (name: string, value: string, opt?: CookieOptions) => setCookie(c, name, value, opt),
20
+ // setSigned: (name: string, value: string, secret: string, opt?: CookieOptions) => setSignedCookie(c, name, value, secret, opt),
21
+ // delete: (name: string, opt?: CookieOptions) => deleteCookie(c, name, opt)
22
+ // }
23
+ // }
24
+ class $Cookie {
25
+ #c!: Context
26
+ constructor(c: Context) {
27
+ this.#c = c
28
+ }
29
+
30
+ all() {
31
+ return getCookie(this.#c)
32
+ }
33
+ allSigned(secret: string) {
34
+ return getSignedCookie(this.#c, secret)
35
+ }
36
+ get(name: string, prefixOptions?: CookiePrefixOptions) {
37
+ return prefixOptions ? getCookie(this.#c, name, prefixOptions) : getCookie(this.#c, name)
38
+ }
39
+ getSigned(secret: string, name: string, prefixOptions?: CookiePrefixOptions) {
40
+ return prefixOptions ? getSignedCookie(this.#c, secret, name, prefixOptions) : getSignedCookie(this.#c, secret, name)
41
+ }
42
+ set(name: string, value: string, opt?: CookieOptions) {
43
+ setCookie(this.#c, name, value, opt)
44
+ }
45
+ setSigned(name: string, value: string, secret: string, opt?: CookieOptions) {
46
+ setSignedCookie(this.#c, name, value, secret, opt)
47
+ }
48
+ delete(name: string, opt?: CookieOptions) {
49
+ deleteCookie(this.#c, name, opt)
50
+ }
51
+ }
22
52
 
23
53
  export const GET_REQUEST: unique symbol = Symbol()
24
54
 
25
55
  export default class $Request {
26
56
  #c!: Context
27
- #cookie: ReturnType<typeof cookieWrapper>
57
+ #cookie: $Cookie
58
+ // #cookie: ReturnType<typeof cookieWrapper>
28
59
  #u: Authnz<any> | null = null
29
60
 
30
61
  #host: string
@@ -34,7 +65,8 @@ export default class $Request {
34
65
 
35
66
  constructor(c: Context) {
36
67
  this.#c = c
37
- this.#cookie = cookieWrapper(c)
68
+ this.#cookie = new $Cookie(c)
69
+ // this.#cookie = cookieWrapper(c)
38
70
 
39
71
  const url = new URL(c.req.raw.url)
40
72
  this.#host = url.protocol +'//'+ url.host
@@ -47,11 +79,11 @@ export default class $Request {
47
79
  const req = new $Request(c)
48
80
  await req.setAuth()
49
81
  c.set(GET_REQUEST as unknown as string, req)
50
- if (c.env) Envir.add(c.env)
82
+ if (c.env) addEnv(c.env)
51
83
  }
52
84
 
53
85
  async setAuth() {
54
- this.#u = Authnz.fromToken(Token.fromRequest(this))
86
+ this.#u = Authnz.fromToken(await Token.fromRequest(this))
55
87
  }
56
88
 
57
89
  get user() {
@@ -1,4 +1,4 @@
1
- import { Glob, file, write } from 'bun'
1
+ import { file, write } from 'bun'
2
2
 
3
3
  import { copyFileSync } from 'node:fs'
4
4
  import { join, relative } from 'pathe'
@@ -12,38 +12,15 @@ import { STATUS_CODES } from 'node:http'
12
12
  import $ from './app'
13
13
  import _response from './response'
14
14
  import _validator from './validator'
15
- import { _root, _duto } from '@/utils'
16
- import { getLastCommitHash, ensureDir, nextId } from './utils'
15
+ import { _root, _server, scan } from '@/utils'
16
+ import { getLastCommitHash, ensureDir, nextId, verbAlias } from './utils'
17
17
  import { generateOpenAPI, generateOpenAPIClient, openAPIConfig } from './open-api/spec'
18
- import { verbAlias } from './http'
19
18
  import { highlightedMethod, highlightedURI } from './cli/utils'
20
19
 
21
20
  import type { Routes, Rule, StandardSchemaV1 } from './types'
22
21
  import { autorizedPath } from './middlewares/auth'
23
22
  import { isDev } from './utils/environment'
24
23
 
25
- export async function* scan(
26
- dir: string | string[],
27
- ext: string | string[],
28
- ignore: string[] = ['*.d.*'],
29
- cwd?: string,
30
- ): AsyncGenerator<[string, string, any]> {
31
- if (typeof dir !== 'string')
32
- dir = ext.length === 1 ? dir[0] : `{${dir.join(',')}}`
33
-
34
- if (typeof ext !== 'string')
35
- ext = ext.length === 1 ? ext[0] : `{${ext.join(',')}}`
36
-
37
- cwd ??= _root
38
- for await (const file of new Glob(dir +'/**/*.'+ ext).scan({
39
- cwd,
40
- absolute: true,
41
- onlyFiles: true, // @ts-ignore
42
- ignore,
43
- })) {
44
- yield [file, file.split(cwd as string)[1], await IMPORT(file)]
45
- }
46
- }
47
24
 
48
25
  const importName = (name: string | undefined, dirs: string[]) => (name || nextId()).replace(/\.ts$/, '')
49
26
 
@@ -406,12 +383,12 @@ export async function cacheRoutes() {
406
383
  const configs = await getConfigs()
407
384
  const middlewares = await getMiddlewares()
408
385
  if (isDev()) {
409
- const _file = join(_duto, 'server', 'middlewares', 'logger.ts')
386
+ const _file = join(_server, 'middlewares', 'logger.ts')
410
387
  const _mod = await IMPORT(_file) // @ts-ignore
411
- middlewares.unshift({
388
+ middlewares.unshift({ // @ts-ignore
412
389
  path: _mod?.path || '*',
413
390
  name: 'dev_logger',
414
- file: _file,
391
+ file: _file, // @ts-ignore
415
392
  handle: _mod.handle,
416
393
  })
417
394
  }
@@ -447,8 +424,8 @@ export async function cacheRoutes() {
447
424
  const _dutoDir = await dependencyPath('duto')
448
425
 
449
426
  await write(iPath, `// AUTO-GENERATED FILE - DO NOT EDIT
450
- ${env?.length ? `import { Envir } from '${await dependencyPath('t0n')}/src/envir'\nEnvir.add(${JSJSON(Object.fromEntries(env))})` : ''}
451
- ${Object.entries(configs)?.length ? `import Config from '${_dutoDir}/src/server/config'\nConfig.add(${JSJSON(configs)})` : ''}
427
+ ${env?.length ? `import { addEnv } from '${await dependencyPath('t0n')}/src/env'\naddEnv(${JSJSON(Object.fromEntries(env))})` : ''}
428
+ ${Object.entries(configs)?.length ? `import { addConfig } from '${_dutoDir}/src/server/config'\naddConfig(${JSJSON(configs)})` : ''}
452
429
 
453
430
  ${middlewares.map(r => `import { handle as MW${r.name} } from '../${normalizeImportPath(r.file)}'`).join('\n')}
454
431
  export const middlewares = [[${middlewares.map(mw => [
@@ -44,3 +44,28 @@ export const nextId = () => {
44
44
 
45
45
  return id = 'a' + chars.join('')
46
46
  }
47
+
48
+ export const verbAlias = {
49
+ get: 0,
50
+ post: 1,
51
+ put: 2,
52
+ patch: 3,
53
+ delete: 4,
54
+ head: 5,
55
+ options: 6,
56
+ connect: 7,
57
+ trace: 8,
58
+ } as Record<string, number>
59
+
60
+ export const getVerb = [
61
+ 'get',
62
+ 'post',
63
+ 'put',
64
+ 'patch',
65
+ 'delete',
66
+ 'head',
67
+ 'options',
68
+ 'connect',
69
+ 'trace',
70
+ ]
71
+
package/src/utils.ts CHANGED
@@ -1,5 +1,46 @@
1
- import { Envir } from 't0n'
1
+ import { IMPORT } from 't0n'
2
2
  import { dirname, join } from 'pathe'
3
3
 
4
4
  export const _duto = dirname(new URL(import.meta.url).pathname)
5
- export const _root = Envir.get('npm_config_local_prefix') || Envir.get('PWD') || join(_duto, '../../')
5
+ export const _pages = join(_duto, 'pages')
6
+ export const _server = join(_duto, 'server') //@ts-ignore
7
+ export const _root = process.env?.npm_config_local_prefix || process.env?.PWD || process.stdin?.path || process.cwd() // || join(_duto, '../../')s
8
+
9
+ const UNITS = ['B', 'kB', 'MB', 'GB']
10
+ export function filesize(bytes: number, decimals = 2) {
11
+ if (!Number.isFinite(bytes) || bytes <= 0) return '0 B'
12
+
13
+ const i = Math.min(Math.floor(Math.log(bytes) / Math.log(1024)), UNITS.length - 1)
14
+ return `${parseFloat((bytes / 1024 ** i).toFixed(decimals))} ${UNITS[i]}`
15
+ }
16
+
17
+ export const formatTime = (ms: number) => {
18
+ if (ms < 0.001) return `${(ms * 1_000_000).toFixed(2)}ns`
19
+ if (ms < 1) return `${(ms * 1000).toFixed(2)}µs`
20
+ if (ms < 1000) return `${ms.toFixed(2)}ms`
21
+ if (ms < 60000) return `${(ms / 1000).toFixed(2)}s`
22
+ return `${Math.floor(ms / 60000)}m ${((ms % 60000) / 1000).toFixed(1)}s`
23
+ }
24
+
25
+ export async function* scan(
26
+ dir: string | string[],
27
+ ext: string | string[],
28
+ ignore: string[] = ['*.d.*'],
29
+ cwd?: string,
30
+ ): AsyncGenerator<[string, string, any]> {
31
+ if (typeof dir !== 'string')
32
+ dir = ext.length === 1 ? dir[0] : `{${dir.join(',')}}`
33
+
34
+ if (typeof ext !== 'string')
35
+ ext = ext.length === 1 ? ext[0] : `{${ext.join(',')}}`
36
+
37
+ cwd ??= _root
38
+ for await (const file of new Bun.Glob(dir +'/**/*.'+ ext).scan({
39
+ cwd,
40
+ absolute: true,
41
+ onlyFiles: true, // @ts-ignore
42
+ ignore,
43
+ })) {
44
+ yield [file, file.split(cwd as string)[1], await IMPORT(file)]
45
+ }
46
+ }