duto 0.260808.0 → 0.260915.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +2 -2
- package/README.md +35 -13
- package/package.json +54 -13
- package/src/cli.ts +45 -0
- package/src/commands/new.ts +147 -0
- package/src/commands/templates/base/.editorconfig +21 -0
- package/src/commands/templates/base/.env.dev.example +2 -0
- package/src/commands/templates/base/.env.prod.example +2 -0
- package/src/commands/templates/base/README.md +29 -0
- package/src/commands/templates/base/_gitignore +100 -0
- package/src/commands/templates/base/actions/blog/index.get.ts +9 -0
- package/src/commands/templates/base/actions/blog/post/[id].get.ts +9 -0
- package/src/commands/templates/base/actions/index.get.ts +5 -0
- package/src/commands/templates/base/configs/duto.ts +11 -0
- package/src/commands/templates/base/configs/roles.ts +5 -0
- package/src/commands/templates/base/package.json +24 -0
- package/src/commands/templates/base/tsconfig.json +42 -0
- package/src/commands/templates/workerd/wrangler.toml +47 -0
- package/src/commands/upgrade.ts +30 -0
- package/src/enum.ts +2 -0
- package/src/index.d.ts +61 -0
- package/src/index.ts +19 -23
- package/src/middleware.ts +2 -0
- package/src/{cli → pages/cli}/commands/build.ts +13 -7
- package/src/{cli → pages/cli}/commands/dev.ts +11 -4
- package/src/{cli → pages/cli}/commands/preview.ts +6 -4
- package/src/pages/cli/index.ts +10 -0
- package/src/{cli → pages/cli}/utils.ts +4 -5
- package/src/{client → pages/client}/app.tsx +1 -1
- package/src/{client → pages/client}/router.ts +1 -1
- package/src/{compiler → pages/compiler}/file.ts +1 -1
- package/src/{compiler → pages/compiler}/index.ts +2 -4
- package/src/{compiler → pages/compiler}/meta.ts +2 -2
- package/src/{compiler → pages/compiler}/routes.ts +1 -1
- package/src/{compiler → pages/compiler}/types.ts +10 -0
- package/src/{compiler → pages/compiler}/vite-plugin.ts +20 -45
- package/src/{i18n → pages/i18n}/client.ts +2 -2
- package/src/{i18n → pages/i18n}/element.ts +1 -1
- package/src/{i18n → pages/i18n}/server.ts +1 -1
- package/src/pages/index.ts +28 -0
- package/src/{preact → pages/preact}/server.ts +1 -1
- package/src/server/adapter/aws.ts +4 -0
- package/src/server/adapter/workerd.ts +4 -0
- package/src/server/app.ts +91 -0
- package/src/server/auth/ability.ts +72 -0
- package/src/server/auth/authnz.ts +86 -0
- package/src/server/auth/index.ts +5 -0
- package/src/server/auth/token.ts +147 -0
- package/src/server/auth/types.ts +2 -0
- package/src/server/cli/commands/build.ts +41 -0
- package/src/server/cli/commands/deploy.ts +81 -0
- package/src/server/cli/commands/dev.ts +279 -0
- package/src/server/cli/commands/make.ts +98 -0
- package/src/server/cli/commands/migrate.ts +93 -0
- package/src/server/cli/commands/routes.ts +78 -0
- package/src/server/cli/index.ts +27 -0
- package/src/server/cli/stubs.ts +39 -0
- package/src/server/cli/types.ts +3 -0
- package/src/server/cli/utils.ts +437 -0
- package/src/server/config.ts +19 -0
- package/src/server/db/d1.d.ts +1 -0
- package/src/server/db/d1.ts +1 -0
- package/src/server/db/dynamodb.d.ts +1 -0
- package/src/server/db/dynamodb.ts +1 -0
- package/src/server/db/index.ts +1 -0
- package/src/server/entry.ts +19 -0
- package/src/server/handle.ts +30 -0
- package/src/server/middlewares/auth.ts +40 -0
- package/src/server/middlewares/logger.ts +30 -0
- package/src/server/open-api/register.ts +29 -0
- package/src/server/open-api/spec.ts +114 -0
- package/src/server/request.ts +265 -0
- package/src/server/response.ts +142 -0
- package/src/server/routes.ts +473 -0
- package/src/server/types.ts +142 -0
- package/src/server/utils/environment.ts +17 -0
- package/src/server/utils.ts +71 -0
- package/src/server/validator.ts +70 -0
- package/src/utils.ts +15 -0
- package/src/cli/commands/dev-old.ts +0 -213
- package/src/cli/index.ts +0 -28
- package/src/compiler/utils.ts +0 -5
- /package/src/{client → pages/client}/hmr.ts +0 -0
- /package/src/{client → pages/client}/island.ts +0 -0
- /package/src/{client → pages/client}/link.ts +0 -0
- /package/src/{client → pages/client}/storage.ts +0 -0
- /package/src/{compiler → pages/compiler}/aliases.ts +0 -0
- /package/src/{compiler → pages/compiler}/assets.ts +0 -0
- /package/src/{compiler → pages/compiler}/ast.ts +0 -0
- /package/src/{compiler → pages/compiler}/constants.ts +0 -0
- /package/src/{compiler → pages/compiler}/island.ts +0 -0
- /package/src/{components → pages/components}/link.tsx +0 -0
- /package/src/{preact → pages/preact}/client-dev.ts +0 -0
- /package/src/{preact → pages/preact}/client.ts +0 -0
- /package/src/{preact → pages/preact}/context.ts +0 -0
- /package/src/{preact → pages/preact}/signals.ts +0 -0
- /package/src/{preact → pages/preact}/static-html.ts +0 -0
- /package/src/{preact → pages/preact}/types.ts +0 -0
|
@@ -8,7 +8,7 @@ import { getContext, incrementIslandId } from './context'
|
|
|
8
8
|
import { restoreSignalsOnProps, serializeSignals } from './signals'
|
|
9
9
|
import StaticHtml from './static-html'
|
|
10
10
|
import type { IslandAttrs } from './types'
|
|
11
|
-
import type { IslandMeta } from '
|
|
11
|
+
import type { IslandMeta } from '#/compiler/types'
|
|
12
12
|
// import type { AstroPreactAttrs, RendererContext } from './types.js'
|
|
13
13
|
// import { createFilter } from '@astrojs/internal-helpers/create-filter'
|
|
14
14
|
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { Hono } from 'hono'
|
|
2
|
+
import type {
|
|
3
|
+
Env, Context, Next,
|
|
4
|
+
HTTPResponseError,
|
|
5
|
+
ServerOptions, Route
|
|
6
|
+
} from './types'
|
|
7
|
+
import request from './request'
|
|
8
|
+
import response from './response'
|
|
9
|
+
import { isDev } from './utils/environment'
|
|
10
|
+
import { getVerb } from './utils'
|
|
11
|
+
import { registerMiddleware, resolveHandle, resolveMw } from './handle'
|
|
12
|
+
|
|
13
|
+
async function EHandler(e: Error | HTTPResponseError) {
|
|
14
|
+
console.error(e)
|
|
15
|
+
|
|
16
|
+
switch (true) {
|
|
17
|
+
// case 'status' in e && e.status === 401:
|
|
18
|
+
case e?.status === 401:
|
|
19
|
+
return response.unauthorized()
|
|
20
|
+
|
|
21
|
+
// case 'status' in e && e.status === 400: // @ts-ignore
|
|
22
|
+
case e?.status === 400:
|
|
23
|
+
return response.badRequest(null, e?.message)
|
|
24
|
+
|
|
25
|
+
default:
|
|
26
|
+
return response.internalError(
|
|
27
|
+
// @ts-ignore
|
|
28
|
+
isDev() // TODO: remover ou migrar para um middleware / melhorar
|
|
29
|
+
? e.stack?.split('\n').map(line =>
|
|
30
|
+
line.replace(
|
|
31
|
+
/at (.+ )?\(?([^)]+)\)?/g,
|
|
32
|
+
(match, method, path) => {
|
|
33
|
+
if (!path) return match
|
|
34
|
+
|
|
35
|
+
const nodeModulesIndex = path.indexOf('node_modules')
|
|
36
|
+
if (nodeModulesIndex > -1)
|
|
37
|
+
return `${method || ''}(node_modules${path.slice(nodeModulesIndex + 'node_modules'.length)})`
|
|
38
|
+
|
|
39
|
+
const projectRoot = process.cwd()
|
|
40
|
+
const relativePath = path.startsWith(projectRoot) ? path.slice(projectRoot.length + 1) : path
|
|
41
|
+
return `${method || ''}(${relativePath})`
|
|
42
|
+
}
|
|
43
|
+
).trim()
|
|
44
|
+
)
|
|
45
|
+
: undefined,
|
|
46
|
+
e.message || 'Internal Error'
|
|
47
|
+
)
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// return json.internalError(
|
|
51
|
+
// // @ts-ignore
|
|
52
|
+
// isDev() ? e.stack?.split('\n at ').map() : undefined,
|
|
53
|
+
// e.message || 'Internal Error'
|
|
54
|
+
// )
|
|
55
|
+
// error: e.message,
|
|
56
|
+
// cause: e.cause || '???',
|
|
57
|
+
// stack: isDev (? e.stack : undefined
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export default function createApp<E extends Env>(options?: ServerOptions<E>) {
|
|
61
|
+
// const root = options?.root ?? '/'
|
|
62
|
+
const app = options?.app ?? new Hono<E>()
|
|
63
|
+
|
|
64
|
+
app.use(async (c: Context, next: Next) => {
|
|
65
|
+
await request.toContext(c)
|
|
66
|
+
await next()
|
|
67
|
+
})
|
|
68
|
+
|
|
69
|
+
const middlewares = options?.middlewares || []
|
|
70
|
+
for (const mw of middlewares) { // @ts-ignore
|
|
71
|
+
registerMiddleware(mw[2], mw[1]) // @ts-ignore
|
|
72
|
+
mw[0] ? app.use(String(mw[0]), resolveMw(mw[1])) : app.use(resolveMw(mw[1]))
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// @ts-ignore
|
|
76
|
+
app.onError(options?.onError || EHandler)
|
|
77
|
+
app.notFound(options?.notFound || response.notFound)
|
|
78
|
+
|
|
79
|
+
if (options?.init) options.init(app)
|
|
80
|
+
|
|
81
|
+
const routes = options?.routes || [] // @ts-ignore
|
|
82
|
+
const routeRegister = options?.routeRegister ? options.routeRegister : (_: Hono, route: Route) => {
|
|
83
|
+
// @ts-ignore
|
|
84
|
+
_[getVerb[route[0]]](route[1], ...resolveHandle(route[2], route[3], route[4]))
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
for (const route of routes)
|
|
88
|
+
routeRegister(app, route)
|
|
89
|
+
|
|
90
|
+
return app
|
|
91
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { verbAlias } from '$/utils'
|
|
2
|
+
import type { IRequest, Routes } from '$/types'
|
|
3
|
+
import type { Roles, Abilities } from './types'
|
|
4
|
+
|
|
5
|
+
export class Ability {
|
|
6
|
+
static #roles: Roles = {}
|
|
7
|
+
static #abilities: Abilities = []
|
|
8
|
+
static #actions: Record<string, string> = {}
|
|
9
|
+
|
|
10
|
+
static empty() {
|
|
11
|
+
this.#roles = {}
|
|
12
|
+
this.#abilities = []
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
static fromRoutes(routes: Routes) {
|
|
16
|
+
if (!routes?.length) return
|
|
17
|
+
|
|
18
|
+
const actions: Record<string, string> = {}
|
|
19
|
+
const abilities = new Set()
|
|
20
|
+
for (const route of routes) {
|
|
21
|
+
const isArr = Array.isArray(route)
|
|
22
|
+
const name = isArr ? route[route.length-1] : route.name
|
|
23
|
+
if (!name || abilities.has(name)) continue
|
|
24
|
+
|
|
25
|
+
abilities.add(name)
|
|
26
|
+
actions[(isArr ? route[1] : route.path) +'$'+ verbAlias[isArr ? route[0] : route.method]] = name
|
|
27
|
+
const formatted = this.format(name)
|
|
28
|
+
|
|
29
|
+
if (formatted)
|
|
30
|
+
this.#abilities.push(formatted)
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
this.#actions = actions
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
static fromRequest(req: IRequest) {
|
|
37
|
+
const ability = this.#actions[`${req.routePath}$` + verbAlias[req.method.toLowerCase()]]
|
|
38
|
+
return ability ? this.format(ability) : ''
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
static fromAction(target: any): string {
|
|
42
|
+
return !target ? '' : this.format(typeof target === 'string' ? target : (target.name.length > 3 ? target.name : (target?.p || '')))
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
static format(path: string) {
|
|
46
|
+
return path === '/'
|
|
47
|
+
? 'index'
|
|
48
|
+
: path.normalize('NFD')
|
|
49
|
+
.replace(/[\u0300-\u036f]/g, '')
|
|
50
|
+
.replace(/^\/*/, '')
|
|
51
|
+
.replace(/([a-z])([A-Z])/g, '$1-$2')
|
|
52
|
+
.replace(/[^a-zA-Z0-9/]|[\s\-.]/g, '_')
|
|
53
|
+
.replace(/_+/g, '_')
|
|
54
|
+
.replace(/\//g, '.')
|
|
55
|
+
.replace(/\._/g, '.')
|
|
56
|
+
.replace(/^[._-]+/, '')
|
|
57
|
+
.replace(/[._-]+$/, '')
|
|
58
|
+
.toLowerCase()
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
static get abilities() {
|
|
62
|
+
return this.#abilities
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
static get roles() {
|
|
66
|
+
return this.#roles
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
static set roles(roles: Roles) {
|
|
70
|
+
this.#roles = roles
|
|
71
|
+
}
|
|
72
|
+
}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { Ability } from './ability'
|
|
2
|
+
import type { Token } from 'cripta/token'
|
|
3
|
+
|
|
4
|
+
export class Authnz<T extends object> {
|
|
5
|
+
#abilities: string[]
|
|
6
|
+
#roles: string[]
|
|
7
|
+
#data: T
|
|
8
|
+
#token: Token
|
|
9
|
+
|
|
10
|
+
constructor(token: Token, data: T, abilities: string[], roles: string[]) {
|
|
11
|
+
this.#abilities = abilities
|
|
12
|
+
this.#roles = roles
|
|
13
|
+
this.#token = token
|
|
14
|
+
this.#data = data
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
can(...abilities: string[]): boolean {
|
|
18
|
+
if (this.#abilities.includes('*')) return true
|
|
19
|
+
|
|
20
|
+
return abilities.flat().every(ability => {
|
|
21
|
+
if (this.#roles.includes(ability)) return true
|
|
22
|
+
return this.#abilities.some(rule => this.#match(rule, ability))
|
|
23
|
+
})
|
|
24
|
+
}
|
|
25
|
+
cant(...abilities: string[]): boolean {
|
|
26
|
+
return !this.can(...abilities)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
hasRole(...roles: string[]): boolean {
|
|
30
|
+
return roles.flat().every(role => this.#roles.includes(role))
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// has(prop: string, value: any = null): boolean {
|
|
34
|
+
// return this.#token?.hasValue(prop, value) || false
|
|
35
|
+
// }
|
|
36
|
+
// hasValue(prop: string, value: any = null): boolean {
|
|
37
|
+
// return this.has(prop, value)
|
|
38
|
+
// }
|
|
39
|
+
|
|
40
|
+
static fromToken<T extends object>(token: Token): Authnz<T> | null {
|
|
41
|
+
if (!token || !token?.valid) return null
|
|
42
|
+
const user = token.body
|
|
43
|
+
const roles = [...(user?.role ? [user.role] : []), ...(user?.roles ?? [])]
|
|
44
|
+
|
|
45
|
+
const combined = [...(user?.perms ?? []), ...roles.flatMap(role => {
|
|
46
|
+
const perms = Ability.roles[role]
|
|
47
|
+
if (!perms) return []
|
|
48
|
+
return perms === '*' ? ['*'] : perms
|
|
49
|
+
})]
|
|
50
|
+
|
|
51
|
+
const abilities = combined.includes('*') ? ['*'] : Array.from(new Set(combined))
|
|
52
|
+
|
|
53
|
+
return new Authnz<T>(token, user, abilities, roles)
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
#match(rule: string, ability: string): boolean {
|
|
57
|
+
if (rule === ability) return true
|
|
58
|
+
if (
|
|
59
|
+
this.#wildcardMatch(rule, ability, '_*')
|
|
60
|
+
|| this.#wildcardMatch(rule, ability, '-*')
|
|
61
|
+
|| this.#wildcardMatch(rule, ability, '.*')
|
|
62
|
+
) return true
|
|
63
|
+
|
|
64
|
+
return false
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
#wildcardMatch(rule: string, ability: string, suffix: string) {
|
|
68
|
+
return rule.endsWith(suffix)
|
|
69
|
+
&& (ability.startsWith(rule.slice(0, -2) + suffix[0]) || ability === rule.slice(0, -2))
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
get abilities() {
|
|
73
|
+
return this.#abilities
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
get roles() {
|
|
77
|
+
return this.#roles
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
get data() {
|
|
81
|
+
return this.#data
|
|
82
|
+
}
|
|
83
|
+
get user() {
|
|
84
|
+
return this.#data
|
|
85
|
+
}
|
|
86
|
+
}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import { bytesToHex, getEnv, parseUA } from 't0n'
|
|
2
|
+
import { sha256, type Config } from 'cripta'
|
|
3
|
+
import { config, create, parse } from 'cripta/token'
|
|
4
|
+
import type { IRequest } from '$/types'
|
|
5
|
+
|
|
6
|
+
const STABLE_HEADERS = [
|
|
7
|
+
'host',
|
|
8
|
+
'connection',
|
|
9
|
+
'sec-ch-ua',
|
|
10
|
+
'sec-ch-ua-mobile',
|
|
11
|
+
'sec-ch-ua-platform',
|
|
12
|
+
'upgrade-insecure-requests',
|
|
13
|
+
'user-agent',
|
|
14
|
+
'accept',
|
|
15
|
+
'sec-fetch-site',
|
|
16
|
+
'sec-fetch-mode',
|
|
17
|
+
'sec-fetch-user',
|
|
18
|
+
'sec-fetch-dest',
|
|
19
|
+
'accept-encoding',
|
|
20
|
+
'accept-language',
|
|
21
|
+
]
|
|
22
|
+
|
|
23
|
+
function headerOrdering(headers: Record<string, string>) {
|
|
24
|
+
const order: string[] = []
|
|
25
|
+
|
|
26
|
+
for (const name in headers) {
|
|
27
|
+
const key = name.toLowerCase()
|
|
28
|
+
|
|
29
|
+
if (STABLE_HEADERS.includes(key))
|
|
30
|
+
order.push(key)
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
return order
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export class Token {
|
|
37
|
+
static #cookieName: string = '__auth_'
|
|
38
|
+
static #name: string = 'Authorization'
|
|
39
|
+
static #prefix: string = 'bearer'
|
|
40
|
+
static #cripta: Config
|
|
41
|
+
|
|
42
|
+
static async fromRequest(req: IRequest) {
|
|
43
|
+
const token = this.fromCookie(req) || this.fromHeader(req)
|
|
44
|
+
return token ? await this.parse(req, token) : null
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
static fromHeader(req: IRequest): string | null {
|
|
48
|
+
const header = req.header(this.#name) || req.header('HTTP_AUTHORIZATION') || req.header('REDIRECT_HTTP_AUTHORIZATION') || null
|
|
49
|
+
|
|
50
|
+
if (header) {
|
|
51
|
+
const pos = header.toLowerCase().indexOf(this.#prefix.toLowerCase())
|
|
52
|
+
if (pos < 0) return header
|
|
53
|
+
|
|
54
|
+
let token = header.slice(pos + this.#prefix.length).trim()
|
|
55
|
+
const commaPos = token.indexOf(',')
|
|
56
|
+
if (commaPos > -1) token = token.slice(0, commaPos).trim()
|
|
57
|
+
|
|
58
|
+
return token
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return null
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
static fromCookie(req: IRequest): string | null {
|
|
65
|
+
const uid = req.header('uid')
|
|
66
|
+
|
|
67
|
+
if (uid) {
|
|
68
|
+
const auth = req.cookie.get(this.#cookieName + uid)
|
|
69
|
+
return auth ? auth : null
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
return null
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
static async cripta() {
|
|
76
|
+
if (this.#cripta)
|
|
77
|
+
return this.#cripta
|
|
78
|
+
|
|
79
|
+
return this.#cripta = await config({ key: getEnv('KEY') })
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
static async parse(req: IRequest, token: string) {
|
|
83
|
+
const host = this.host(req)
|
|
84
|
+
const serveHost = getEnv('FLOW_SERVER', host) as string
|
|
85
|
+
|
|
86
|
+
return parse(await this.cripta(), token, {
|
|
87
|
+
iss: serveHost,
|
|
88
|
+
aud: [host],
|
|
89
|
+
'_': await this.fingerprint(req),
|
|
90
|
+
})
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
static async create(req: IRequest, user: any, exp: number = 7200) {
|
|
94
|
+
const time = Math.floor(Date.now() / 1000)
|
|
95
|
+
const host = this.host(req)
|
|
96
|
+
|
|
97
|
+
return create(await this.cripta(), user, {
|
|
98
|
+
iss: host,
|
|
99
|
+
aud: [host],
|
|
100
|
+
iat: time,
|
|
101
|
+
exp: time + exp,
|
|
102
|
+
'_': await this.fingerprint(req),
|
|
103
|
+
})
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
static setPrefix(prefix: string): void {
|
|
107
|
+
this.#prefix = prefix
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
static setName(name: string): void {
|
|
111
|
+
this.#name = name
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
static host(req: IRequest): string {
|
|
115
|
+
const url = req.url || req.header('host')
|
|
116
|
+
if (!url) return ''
|
|
117
|
+
|
|
118
|
+
let formattedUrl = String(url)
|
|
119
|
+
if (!formattedUrl.startsWith('http'))
|
|
120
|
+
formattedUrl = 'http://' + formattedUrl
|
|
121
|
+
|
|
122
|
+
try {
|
|
123
|
+
const parsedUrl = new URL(formattedUrl)
|
|
124
|
+
return parsedUrl.host
|
|
125
|
+
} catch {
|
|
126
|
+
return ''
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
static async fingerprint(req: IRequest) {
|
|
131
|
+
const ua = parseUA(req.header('user-agent'))
|
|
132
|
+
|
|
133
|
+
const id = bytesToHex(await sha256(
|
|
134
|
+
// (req.header('accept-language') || '')
|
|
135
|
+
this.ip(req)
|
|
136
|
+
+ ua.browser.name + ua.browser.version.split('.')[0]
|
|
137
|
+
+ ua.os.type + ua.os.name
|
|
138
|
+
+ headerOrdering(req.header()).join('')
|
|
139
|
+
))
|
|
140
|
+
|
|
141
|
+
return id.substring(0, 8) + id.substring(56, 64)
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
static ip(req: IRequest) {
|
|
145
|
+
return req?.ip || 0
|
|
146
|
+
}
|
|
147
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { getEnv } from 't0n'
|
|
2
|
+
import { command } from 't0n/cli'
|
|
3
|
+
import { gray } from 't0n/color'
|
|
4
|
+
import { wait, error, rn } from 't0n/log'
|
|
5
|
+
import { platforms, build, normalizePlatform, platformError } from '../utils'
|
|
6
|
+
|
|
7
|
+
export default command({
|
|
8
|
+
meta: {
|
|
9
|
+
name: 'build',
|
|
10
|
+
description: '🗂️ Perform the build\n',
|
|
11
|
+
},
|
|
12
|
+
args: {
|
|
13
|
+
platform: {
|
|
14
|
+
alias: 'p',
|
|
15
|
+
description: 'Environment platform',
|
|
16
|
+
type: 'enum',
|
|
17
|
+
options: platforms,
|
|
18
|
+
},
|
|
19
|
+
minify: {
|
|
20
|
+
description: 'Minify the result',
|
|
21
|
+
type: 'boolean',
|
|
22
|
+
default: true,
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
async run({ args }) {
|
|
26
|
+
const platform = normalizePlatform(args.p || args.platform || getEnv('duto.platform') || args._[0] || 'node')
|
|
27
|
+
if (!platform)
|
|
28
|
+
return platformError()
|
|
29
|
+
|
|
30
|
+
wait('Building for platform: '+ gray(platform))
|
|
31
|
+
|
|
32
|
+
try { // @ts-ignore
|
|
33
|
+
await build({ platform, minify: args.minify })
|
|
34
|
+
} catch (e: any) {
|
|
35
|
+
error('Build failed:\n\n', e)
|
|
36
|
+
process.exit(0)
|
|
37
|
+
} finally {
|
|
38
|
+
rn()
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
})
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { spawn } from 'node:child_process'
|
|
2
|
+
import { command } from 't0n/cli'
|
|
3
|
+
import { error } from 't0n/log'
|
|
4
|
+
import { getRuntime } from 't0n/cli'
|
|
5
|
+
|
|
6
|
+
import { build, platforms, normalizePlatform, platformError } from '../utils'
|
|
7
|
+
import { _root } from '@/utils'
|
|
8
|
+
|
|
9
|
+
// import build from './build'
|
|
10
|
+
|
|
11
|
+
export default command({
|
|
12
|
+
meta: {
|
|
13
|
+
name: 'deploy',
|
|
14
|
+
description: '☁️ Perform the build and execute deploy\n',
|
|
15
|
+
},
|
|
16
|
+
args: {
|
|
17
|
+
platform: {
|
|
18
|
+
alias: 'p',
|
|
19
|
+
description: 'Environment platform',
|
|
20
|
+
type: 'enum',
|
|
21
|
+
options: platforms,
|
|
22
|
+
},
|
|
23
|
+
minify: {
|
|
24
|
+
description: 'Minify the result',
|
|
25
|
+
type: 'boolean',
|
|
26
|
+
default: true,
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
async run({ args }) { // @ts-ignore
|
|
30
|
+
const platform = normalizePlatform(args.p || args.platform || args._[0] || getEnv('duto.platform'))
|
|
31
|
+
if (!platform)
|
|
32
|
+
return platformError()
|
|
33
|
+
|
|
34
|
+
// @ts-ignore
|
|
35
|
+
await build({ platform, minify: args.minify })
|
|
36
|
+
const isBun = getRuntime() === 'bun'
|
|
37
|
+
|
|
38
|
+
switch (platform) {
|
|
39
|
+
case 'aws':
|
|
40
|
+
// TODO: perform aws deploy
|
|
41
|
+
return error('Platform not yet implemented, contact the webmaster')
|
|
42
|
+
case 'workerd':
|
|
43
|
+
const child = spawn(
|
|
44
|
+
isBun ? 'bunx' : 'npx',
|
|
45
|
+
['wrangler', 'deploy'],
|
|
46
|
+
{
|
|
47
|
+
stdio: 'inherit',
|
|
48
|
+
cwd: _root,
|
|
49
|
+
}
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
child.on('exit', code => process.exit(code ?? 0))
|
|
53
|
+
.on('message', msg => {
|
|
54
|
+
process.send && process.send(msg)
|
|
55
|
+
}).on('disconnect', () => {
|
|
56
|
+
process.disconnect && process.disconnect()
|
|
57
|
+
})
|
|
58
|
+
|
|
59
|
+
return
|
|
60
|
+
case 'vercel':
|
|
61
|
+
return error('Platform not yet implemented, contact the webmaster')
|
|
62
|
+
const vchild = spawn(
|
|
63
|
+
isBun ? 'bunx' : 'npx',
|
|
64
|
+
['vercel', 'deploy'],
|
|
65
|
+
{
|
|
66
|
+
stdio: 'inherit',
|
|
67
|
+
cwd: _root,
|
|
68
|
+
}
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
vchild.on('exit', code => process.exit(code ?? 0))
|
|
72
|
+
.on('message', msg => {
|
|
73
|
+
process.send && process.send(msg)
|
|
74
|
+
}).on('disconnect', () => {
|
|
75
|
+
process.disconnect && process.disconnect()
|
|
76
|
+
})
|
|
77
|
+
|
|
78
|
+
return
|
|
79
|
+
}
|
|
80
|
+
},
|
|
81
|
+
})
|