rajt 0.0.17 → 0.0.19
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 +8 -5
- package/src/action.ts +29 -11
- package/src/auth/ability.ts +51 -0
- package/src/auth/auth.ts +72 -0
- package/src/auth/index.ts +5 -0
- package/src/auth/token.ts +73 -0
- package/src/auth/types.ts +2 -0
- package/src/create-app.ts +10 -4
- package/src/dev.ts +8 -2
- package/src/dynamodb/client.ts +13 -10
- package/src/dynamodb/compact.ts +3 -3
- package/src/dynamodb/model.ts +116 -87
- package/src/dynamodb/query-builder.ts +16 -16
- package/src/http.ts +46 -19
- package/src/middleware.ts +1 -1
- package/src/prod.ts +7 -3
- package/src/register.ts +6 -0
- package/src/response.ts +11 -11
- package/src/routes.ts +68 -12
- package/src/scripts/cache-routes.ts +11 -2
- package/src/utils/json-import.ts +16 -0
- package/src/utils/merge-middleware.ts +9 -0
- package/src/utils/resolve.ts +23 -1
package/src/dynamodb/model.ts
CHANGED
|
@@ -1,4 +1,14 @@
|
|
|
1
|
-
import
|
|
1
|
+
import {
|
|
2
|
+
DynamoDBDocumentClient,
|
|
3
|
+
BatchGetCommand,
|
|
4
|
+
BatchWriteCommand,
|
|
5
|
+
DeleteCommand,
|
|
6
|
+
GetCommand,
|
|
7
|
+
PutCommand,
|
|
8
|
+
QueryCommand,
|
|
9
|
+
ScanCommand,
|
|
10
|
+
UpdateCommand,
|
|
11
|
+
} from '@aws-sdk/lib-dynamodb'
|
|
2
12
|
import type { ModelMetadata, Keys, Model, Filter } from './types'
|
|
3
13
|
import { getModelMetadata } from './decorators'
|
|
4
14
|
import QueryBuilder from './query-builder'
|
|
@@ -6,18 +16,25 @@ import Compact from './compact'
|
|
|
6
16
|
import getLength from '../utils/lenght'
|
|
7
17
|
|
|
8
18
|
export default class AbstractModel<T extends object> {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
19
|
+
#meta: ModelMetadata
|
|
20
|
+
#cls!: Model<T>
|
|
21
|
+
lastKey?: Record<string, any>
|
|
22
|
+
#db: DynamoDBDocumentClient
|
|
23
|
+
#queryBuilder?: QueryBuilder
|
|
24
|
+
#model?: AbstractModel<T>
|
|
12
25
|
|
|
13
26
|
constructor(
|
|
14
27
|
cls: Model<T> | ModelMetadata,
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
28
|
+
db: DynamoDBDocumentClient,
|
|
29
|
+
queryBuilder?: QueryBuilder,
|
|
30
|
+
model?: AbstractModel<T>
|
|
18
31
|
) {
|
|
32
|
+
this.#db = db
|
|
33
|
+
this.#queryBuilder = queryBuilder
|
|
34
|
+
this.#model = model
|
|
35
|
+
|
|
19
36
|
if (typeof (cls as ModelMetadata).table === 'string') {
|
|
20
|
-
this
|
|
37
|
+
this.#meta = cls as ModelMetadata
|
|
21
38
|
return
|
|
22
39
|
}
|
|
23
40
|
|
|
@@ -25,21 +42,21 @@ export default class AbstractModel<T extends object> {
|
|
|
25
42
|
if (!meta)
|
|
26
43
|
throw new Error('Missing model metadata')
|
|
27
44
|
|
|
28
|
-
this
|
|
29
|
-
this
|
|
45
|
+
this.#meta = meta
|
|
46
|
+
this.#cls = cls as Model<T>
|
|
30
47
|
}
|
|
31
48
|
|
|
32
49
|
get table(): string {
|
|
33
|
-
return this
|
|
50
|
+
return this.#meta.table
|
|
34
51
|
}
|
|
35
52
|
|
|
36
53
|
get keySchema() {
|
|
37
|
-
return this
|
|
54
|
+
return this.#meta.keys
|
|
38
55
|
}
|
|
39
56
|
|
|
40
57
|
set lastEvaluatedKey(val: Record<string, any> | undefined) {
|
|
41
|
-
if (this
|
|
42
|
-
this
|
|
58
|
+
if (this.#model) {
|
|
59
|
+
this.#model.lastKey = val
|
|
43
60
|
} else {
|
|
44
61
|
this.lastKey = val
|
|
45
62
|
}
|
|
@@ -51,52 +68,61 @@ export default class AbstractModel<T extends object> {
|
|
|
51
68
|
where(builderFn: (q: QueryBuilder) => void) {
|
|
52
69
|
const qb = new QueryBuilder()
|
|
53
70
|
builderFn(qb)
|
|
54
|
-
return new AbstractModel<T>(this
|
|
71
|
+
return new AbstractModel<T>(this.#meta, this.#db, qb, this)
|
|
55
72
|
}
|
|
56
73
|
|
|
57
74
|
async scan(filterFn?: Filter<T>) {
|
|
58
|
-
const result = await this
|
|
75
|
+
const result = await this.#db.send(new ScanCommand({
|
|
76
|
+
TableName: this.table,
|
|
77
|
+
...this.#queryBuilder?.filters,
|
|
78
|
+
}))
|
|
59
79
|
|
|
60
80
|
this.lastEvaluatedKey = result.LastEvaluatedKey
|
|
61
|
-
return this
|
|
81
|
+
return this.#processItems(result.Items, filterFn)
|
|
62
82
|
}
|
|
63
83
|
|
|
64
84
|
async query(filterFn?: Filter<T>) {
|
|
65
|
-
const result = await this
|
|
85
|
+
const result = await this.#db.send(new QueryCommand({
|
|
86
|
+
TableName: this.table,
|
|
87
|
+
...this.#queryBuilder?.conditions,
|
|
88
|
+
}))
|
|
66
89
|
|
|
67
90
|
this.lastEvaluatedKey = result.LastEvaluatedKey
|
|
68
|
-
return this
|
|
91
|
+
return this.#processItems(result.Items, filterFn)
|
|
69
92
|
}
|
|
70
93
|
|
|
71
94
|
async get(key: Keys, sk?: string) {
|
|
72
|
-
const result = await this
|
|
73
|
-
|
|
95
|
+
const result = await this.#db.send(new GetCommand({
|
|
96
|
+
TableName: this.table,
|
|
97
|
+
Key: this.#key(key, sk),
|
|
98
|
+
}))
|
|
99
|
+
return result.Item ? this.#processItem(result.Item) : undefined
|
|
74
100
|
}
|
|
75
101
|
|
|
76
102
|
async put(item: Partial<T>, key: Keys) {
|
|
77
103
|
let keys
|
|
78
|
-
if (this
|
|
79
|
-
keys = this
|
|
80
|
-
this
|
|
104
|
+
if (this.#meta.zip) {
|
|
105
|
+
keys = this.#getItemKey(item, key)
|
|
106
|
+
this.#validateKeys(keys)
|
|
81
107
|
// @ts-ignore
|
|
82
|
-
item = { ...keys, V: Compact.encode(this.getItemWithoutKeys(item), this.meta.fields)}
|
|
108
|
+
item = { ...keys, V: Compact.encode(this.getItemWithoutKeys(item), this.meta.fields) }
|
|
83
109
|
} else {
|
|
84
|
-
this
|
|
110
|
+
this.#validateKeys(item)
|
|
85
111
|
}
|
|
86
112
|
|
|
87
|
-
await this
|
|
88
|
-
return this
|
|
113
|
+
await this.#db.send(new PutCommand({ TableName: this.table, Item: item }))
|
|
114
|
+
return this.#processItem(item, keys)
|
|
89
115
|
}
|
|
90
116
|
|
|
91
117
|
async update(attrs: Partial<T>, key: Keys) {
|
|
92
118
|
let keys
|
|
93
|
-
if (this
|
|
94
|
-
keys = this
|
|
95
|
-
this
|
|
119
|
+
if (this.#meta.zip) {
|
|
120
|
+
keys = this.#getItemKey(attrs, key)
|
|
121
|
+
this.#validateKeys(keys)
|
|
96
122
|
// @ts-ignore
|
|
97
|
-
attrs = { V: Compact.encode(this.getItemWithoutKeys(attrs), this.meta.fields)}
|
|
123
|
+
attrs = { V: Compact.encode(this.getItemWithoutKeys(attrs), this.meta.fields) }
|
|
98
124
|
} else {
|
|
99
|
-
this
|
|
125
|
+
this.#validateKeys(attrs)
|
|
100
126
|
}
|
|
101
127
|
|
|
102
128
|
const UpdateExpressionParts: string[] = []
|
|
@@ -108,26 +134,29 @@ export default class AbstractModel<T extends object> {
|
|
|
108
134
|
const UpdateExpression = 'SET ' + UpdateExpressionParts.join(', ')
|
|
109
135
|
const ExpressionAttributeNames = Object.fromEntries(Object.keys(attrs).map(k => [`#${k}`, k]))
|
|
110
136
|
|
|
111
|
-
await this
|
|
137
|
+
await this.#db.send(new UpdateCommand({
|
|
112
138
|
TableName: this.table,
|
|
113
|
-
Key: this
|
|
139
|
+
Key: this.#key(key),
|
|
114
140
|
UpdateExpression,
|
|
115
141
|
ExpressionAttributeValues,
|
|
116
|
-
ExpressionAttributeNames
|
|
117
|
-
})
|
|
142
|
+
ExpressionAttributeNames,
|
|
143
|
+
}))
|
|
118
144
|
|
|
119
|
-
return this
|
|
145
|
+
return this.#processItem(attrs, keys)
|
|
120
146
|
}
|
|
121
147
|
|
|
122
148
|
async delete(key: Keys, sk?: string) {
|
|
123
|
-
return this
|
|
149
|
+
return this.#db.send(new DeleteCommand({
|
|
150
|
+
TableName: this.table,
|
|
151
|
+
Key: this.#key(key, sk),
|
|
152
|
+
}))
|
|
124
153
|
}
|
|
125
154
|
|
|
126
155
|
async batchGet(keys: Array<Keys>) {
|
|
127
|
-
const result = await this
|
|
128
|
-
[this.table]: { Keys: keys.map(key => this
|
|
129
|
-
}
|
|
130
|
-
return (result.Responses?.[this.table] as T[] || []).map(item => this
|
|
156
|
+
const result = await this.#db.send(new BatchGetCommand({
|
|
157
|
+
RequestItems: { [this.table]: { Keys: keys.map(key => this.#key(key)) } },
|
|
158
|
+
}))
|
|
159
|
+
return (result.Responses?.[this.table] as T[] || []).map(item => this.#processItem(item))
|
|
131
160
|
}
|
|
132
161
|
|
|
133
162
|
async batchWrite(items: Array<{ put?: Partial<T>, delete?: Keys }>) {
|
|
@@ -135,12 +164,12 @@ export default class AbstractModel<T extends object> {
|
|
|
135
164
|
if (i.put) {
|
|
136
165
|
return { PutRequest: { Item: i.put } }
|
|
137
166
|
} else if (i.delete) {
|
|
138
|
-
return { DeleteRequest: { Key: this
|
|
167
|
+
return { DeleteRequest: { Key: this.#key(i.delete) } }
|
|
139
168
|
}
|
|
140
169
|
return null
|
|
141
|
-
}).filter(Boolean)
|
|
170
|
+
}).filter(Boolean) as any[]
|
|
142
171
|
|
|
143
|
-
return this
|
|
172
|
+
return this.#db.send(new BatchWriteCommand({ RequestItems: { [this.table]: WriteRequests } }))
|
|
144
173
|
}
|
|
145
174
|
|
|
146
175
|
async deleteMany(keys: Array<Keys>) {
|
|
@@ -151,8 +180,8 @@ export default class AbstractModel<T extends object> {
|
|
|
151
180
|
return this.batchWrite(items.map(item => ({ put: item })))
|
|
152
181
|
}
|
|
153
182
|
|
|
154
|
-
|
|
155
|
-
if (!this
|
|
183
|
+
#key(key: Keys, sk?: string) {
|
|
184
|
+
if (!this.#meta.keys) return {}
|
|
156
185
|
|
|
157
186
|
let pk: string
|
|
158
187
|
let skValue: string | undefined
|
|
@@ -164,100 +193,100 @@ export default class AbstractModel<T extends object> {
|
|
|
164
193
|
skValue = sk
|
|
165
194
|
}
|
|
166
195
|
|
|
167
|
-
const keys = { [this
|
|
196
|
+
const keys = { [this.#meta.keys.PK]: pk }
|
|
168
197
|
|
|
169
|
-
if (this
|
|
198
|
+
if (this.#meta.keys?.SK) {
|
|
170
199
|
if (skValue) {
|
|
171
|
-
keys[this
|
|
172
|
-
} else if (this
|
|
173
|
-
keys[this
|
|
200
|
+
keys[this.#meta.keys.SK] = skValue
|
|
201
|
+
} else if (this.#meta.defaultSK) {
|
|
202
|
+
keys[this.#meta.keys.SK] = this.#meta.defaultSK
|
|
174
203
|
}
|
|
175
204
|
}
|
|
176
205
|
|
|
177
206
|
return keys
|
|
178
207
|
}
|
|
179
208
|
|
|
180
|
-
|
|
181
|
-
if (!this
|
|
209
|
+
#getItemKey(item: Partial<T>, key?: Keys): Record<string, string> {
|
|
210
|
+
if (!this.#meta.keys) return {}
|
|
182
211
|
|
|
183
212
|
const keys: Record<string, string> = {}
|
|
184
213
|
if (key)
|
|
185
|
-
this
|
|
214
|
+
this.#processExplicitKey(keys, key)
|
|
186
215
|
else if (getLength(item) > 0)
|
|
187
|
-
this
|
|
216
|
+
this.#processItemKeys(keys, item)
|
|
188
217
|
|
|
189
218
|
return keys
|
|
190
219
|
}
|
|
191
220
|
|
|
192
|
-
|
|
193
|
-
if (!this
|
|
221
|
+
#processExplicitKey(keys: Record<string, string>, key: Keys): void {
|
|
222
|
+
if (!this.#meta.keys) return
|
|
194
223
|
if (Array.isArray(key)) {
|
|
195
|
-
keys[this
|
|
224
|
+
keys[this.#meta.keys.PK] = key[0]
|
|
196
225
|
|
|
197
|
-
if (this
|
|
226
|
+
if (this.#meta.keys?.SK) {
|
|
198
227
|
if (key.length > 1)
|
|
199
228
|
// @ts-ignore
|
|
200
229
|
keys[this.meta.keys.SK] = key[1]
|
|
201
|
-
else if (this
|
|
202
|
-
keys[this
|
|
230
|
+
else if (this.#meta.defaultSK)
|
|
231
|
+
keys[this.#meta.keys.SK] = this.#meta.defaultSK
|
|
203
232
|
}
|
|
204
233
|
} else {
|
|
205
|
-
keys[this
|
|
234
|
+
keys[this.#meta.keys.PK] = String(key)
|
|
206
235
|
}
|
|
207
236
|
}
|
|
208
237
|
|
|
209
|
-
|
|
210
|
-
if (!this
|
|
238
|
+
#processItemKeys(keys: Record<string, string>, item: Partial<T>): void {
|
|
239
|
+
if (!this.#meta.keys) return
|
|
211
240
|
|
|
212
|
-
const pkValue = item[this
|
|
241
|
+
const pkValue = item[this.#meta.keys.PK as keyof Partial<T>]
|
|
213
242
|
if (pkValue !== undefined)
|
|
214
|
-
keys[this
|
|
243
|
+
keys[this.#meta.keys.PK] = String(pkValue)
|
|
215
244
|
|
|
216
|
-
if (this
|
|
217
|
-
const skValue = item[this
|
|
245
|
+
if (this.#meta.keys?.SK) {
|
|
246
|
+
const skValue = item[this.#meta.keys.SK as keyof Partial<T>]
|
|
218
247
|
if (skValue !== undefined)
|
|
219
|
-
keys[this
|
|
220
|
-
else if (this
|
|
221
|
-
keys[this
|
|
248
|
+
keys[this.#meta.keys.SK] = String(skValue)
|
|
249
|
+
else if (this.#meta.defaultSK)
|
|
250
|
+
keys[this.#meta.keys.SK] = this.#meta.defaultSK
|
|
222
251
|
}
|
|
223
252
|
}
|
|
224
253
|
|
|
225
|
-
|
|
226
|
-
if (!this
|
|
254
|
+
#validateKeys(keys: Record<string, any>) {
|
|
255
|
+
if (!this.#meta.keys)
|
|
227
256
|
throw new Error(`Missing keys of table "${this.table}"`)
|
|
228
257
|
|
|
229
|
-
if (!(this
|
|
258
|
+
if (!(this.#meta.keys.PK in keys))
|
|
230
259
|
throw new Error(`Missing partition key of table "${this.table}" `)
|
|
231
260
|
|
|
232
|
-
if (this
|
|
261
|
+
if (this.#meta.keys?.SK && !(this.#meta.keys.SK in keys))
|
|
233
262
|
throw new Error(`Missing sort key of table "${this.table}"`)
|
|
234
263
|
}
|
|
235
264
|
|
|
236
|
-
|
|
237
|
-
if (!this
|
|
265
|
+
#getItemWithoutKeys(item: Partial<T>): Partial<T> {
|
|
266
|
+
if (!this.#meta.keys || !item) return { ...item }
|
|
238
267
|
|
|
239
|
-
const { PK, SK } = this
|
|
268
|
+
const { PK, SK } = this.#meta.keys
|
|
240
269
|
const { [PK as keyof T]: _, [SK as keyof T]: __, ...rest } = item
|
|
241
270
|
|
|
242
271
|
return rest as Partial<T>
|
|
243
272
|
}
|
|
244
273
|
|
|
245
|
-
|
|
274
|
+
#processItems(items: any[] | undefined, filterFn?: Filter<T>): T[] {
|
|
246
275
|
if (!items) return []
|
|
247
276
|
|
|
248
|
-
items = this
|
|
277
|
+
items = this.#meta.zip ? Compact.smartDecode<T[]>(items, this.#meta.fields) : items as T[]
|
|
249
278
|
return filterFn ? items.filter(filterFn) : items
|
|
250
279
|
}
|
|
251
280
|
|
|
252
|
-
|
|
253
|
-
if (this
|
|
254
|
-
const model = new this
|
|
255
|
-
if (!keys) keys = this
|
|
281
|
+
#processItem(item: any, keys?: Record<string, string>): T {
|
|
282
|
+
if (this.#meta.zip && item?.V) {
|
|
283
|
+
const model = new this.#cls(Compact.decode(item.V, this.#meta.fields))
|
|
284
|
+
if (!keys) keys = this.#getItemKey(item)
|
|
256
285
|
|
|
257
286
|
// @ts-ignore
|
|
258
287
|
return model.withKey(keys[this.meta.keys.PK], keys[this.meta.keys.SK] || undefined)
|
|
259
288
|
}
|
|
260
289
|
|
|
261
|
-
return new this
|
|
290
|
+
return new this.#cls(item)
|
|
262
291
|
}
|
|
263
292
|
}
|
|
@@ -1,34 +1,34 @@
|
|
|
1
1
|
import type { Condition, Operator } from './types'
|
|
2
2
|
|
|
3
3
|
export default class QueryBuilder {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
4
|
+
#conditions: Condition[] = []
|
|
5
|
+
#limit?: number
|
|
6
|
+
#startKey?: Record<string, any>
|
|
7
|
+
#index?: string
|
|
8
8
|
|
|
9
9
|
filter(field: string, operator: Operator, value: any = null) {
|
|
10
|
-
this.
|
|
10
|
+
this.#conditions.push({ type: 'filter', field, operator, value })
|
|
11
11
|
return this
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
keyCondition(field: string, operator: Operator | any, value?: any) {
|
|
15
15
|
const noVal = value === undefined
|
|
16
|
-
this.
|
|
16
|
+
this.#conditions.push({ type: 'keyCondition', field, operator: noVal ? '=' : operator, value: noVal ? operator : value })
|
|
17
17
|
return this
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
limit(n: number) {
|
|
21
|
-
this
|
|
21
|
+
this.#limit = n
|
|
22
22
|
return this
|
|
23
23
|
}
|
|
24
24
|
|
|
25
25
|
exclusiveStartKey(key: Record<string, any>) {
|
|
26
|
-
this
|
|
26
|
+
this.#startKey = key
|
|
27
27
|
return this
|
|
28
28
|
}
|
|
29
29
|
|
|
30
30
|
index(name: string) {
|
|
31
|
-
this
|
|
31
|
+
this.#index = name
|
|
32
32
|
return this
|
|
33
33
|
}
|
|
34
34
|
|
|
@@ -38,7 +38,7 @@ export default class QueryBuilder {
|
|
|
38
38
|
const names: Record<string, string> = {}
|
|
39
39
|
|
|
40
40
|
let i = 0
|
|
41
|
-
for (const cond of this.
|
|
41
|
+
for (const cond of this.#conditions.filter(c => c.type === type)) {
|
|
42
42
|
const attr = `#attr${i}`
|
|
43
43
|
const val = `:val${i}`
|
|
44
44
|
names[attr] = cond.field
|
|
@@ -107,11 +107,11 @@ export default class QueryBuilder {
|
|
|
107
107
|
const filter = this.buildExpression('filter')
|
|
108
108
|
const params: any = {}
|
|
109
109
|
|
|
110
|
-
if (this
|
|
111
|
-
params.Limit = this
|
|
110
|
+
if (this.#limit)
|
|
111
|
+
params.Limit = this.#limit
|
|
112
112
|
|
|
113
|
-
if (this
|
|
114
|
-
params.ExclusiveStartKey = this
|
|
113
|
+
if (this.#startKey)
|
|
114
|
+
params.ExclusiveStartKey = this.#startKey
|
|
115
115
|
|
|
116
116
|
if (filter.expression)
|
|
117
117
|
params.FilterExpression = filter.expression
|
|
@@ -131,8 +131,8 @@ export default class QueryBuilder {
|
|
|
131
131
|
|
|
132
132
|
const params: any = { ...filters }
|
|
133
133
|
|
|
134
|
-
if (this
|
|
135
|
-
params.IndexName = this
|
|
134
|
+
if (this.#index)
|
|
135
|
+
params.IndexName = this.#index
|
|
136
136
|
|
|
137
137
|
if (keys.expression)
|
|
138
138
|
params.KeyConditionExpression = keys.expression
|
package/src/http.ts
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import
|
|
1
|
+
import type { Context, Next } from 'hono'
|
|
2
|
+
import { MiddlewareType } from './middleware'
|
|
3
|
+
import JsonResponse from './response'
|
|
4
|
+
import { Ability, Authnz, Token } from './auth'
|
|
5
|
+
import { registerGlobalMiddleware } from './register'
|
|
6
|
+
import mergeMiddleware from './utils/merge-middleware'
|
|
3
7
|
|
|
4
8
|
function method(method: string, path = '/') {
|
|
5
9
|
return function (target: any) {
|
|
@@ -31,27 +35,50 @@ export function Delete(path = '/') {
|
|
|
31
35
|
|
|
32
36
|
export function Middleware(...handlers: MiddlewareType[]) {
|
|
33
37
|
return function (target: any) {
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
38
|
+
mergeMiddleware(target, ...handlers)
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
export function Middlewares(...handlers: MiddlewareType[]) {
|
|
42
|
+
return Middleware(...handlers)
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
type MiddlewareOpt = string | RegExp
|
|
46
|
+
export function GlobalMiddleware(): ClassDecorator
|
|
47
|
+
export function GlobalMiddleware(target: Function): void
|
|
48
|
+
export function GlobalMiddleware(opt?: MiddlewareOpt): ClassDecorator
|
|
49
|
+
export function GlobalMiddleware(...args: any[]): void | ClassDecorator {
|
|
50
|
+
if (typeof args[0] === 'function')
|
|
51
|
+
return _globalmw(args[0])
|
|
52
|
+
|
|
53
|
+
return (target: any) => _globalmw(target, ...args)
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export function Auth(target: Function): void
|
|
57
|
+
export function Auth(): ClassDecorator
|
|
58
|
+
export function Auth(...args: any[]): void | ClassDecorator {
|
|
59
|
+
if (args.length === 1 && typeof args[0] === 'function')
|
|
60
|
+
return _auth(args[0])
|
|
37
61
|
|
|
38
|
-
|
|
39
|
-
|
|
62
|
+
return (target: any) => _auth(target)
|
|
63
|
+
}
|
|
40
64
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
}
|
|
65
|
+
function _auth(target: Function | any) {
|
|
66
|
+
mergeMiddleware(target, async (c: Context, next: Next) => {
|
|
67
|
+
const unauthorized = JsonResponse.unauthorized()
|
|
45
68
|
|
|
46
|
-
|
|
47
|
-
|
|
69
|
+
const auth = Authnz.fromToken(Token.fromRequest(c))
|
|
70
|
+
const ability = Ability.fromAction(target)
|
|
48
71
|
|
|
49
|
-
|
|
50
|
-
|
|
72
|
+
if (!auth || !ability || auth.cant(ability))
|
|
73
|
+
return unauthorized
|
|
51
74
|
|
|
52
|
-
|
|
53
|
-
|
|
75
|
+
c.set('#auth', auth)
|
|
76
|
+
await next()
|
|
77
|
+
})
|
|
54
78
|
}
|
|
55
|
-
|
|
56
|
-
|
|
79
|
+
|
|
80
|
+
function _globalmw(target: Function | any, path?: string) {
|
|
81
|
+
target.gmw = true
|
|
82
|
+
target.p = path
|
|
83
|
+
registerGlobalMiddleware(target)
|
|
57
84
|
}
|
package/src/middleware.ts
CHANGED
|
@@ -5,7 +5,7 @@ export type IMiddleware = {
|
|
|
5
5
|
}
|
|
6
6
|
|
|
7
7
|
export default abstract class Middleware implements IMiddleware {
|
|
8
|
-
|
|
8
|
+
abstract handle(c: Context, next: Next): Promise<void> | void
|
|
9
9
|
}
|
|
10
10
|
|
|
11
11
|
// export type MiddlewareHandler = (c: Context, next: Next) => Promise<void> | void
|
package/src/prod.ts
CHANGED
|
@@ -1,14 +1,18 @@
|
|
|
1
|
-
import { config } from 'dotenv'
|
|
2
1
|
import { handle } from 'hono/aws-lambda'
|
|
3
2
|
import createApp from './create-app'
|
|
4
|
-
|
|
5
|
-
config({ path: '../../.env.prod' })
|
|
3
|
+
import { Ability } from './auth'
|
|
6
4
|
|
|
7
5
|
// @ts-ignore
|
|
8
6
|
await import('../../../tmp/import-routes.mjs')
|
|
9
7
|
|
|
10
8
|
// @ts-ignore
|
|
11
9
|
const routes = (await import('../../../tmp/routes.json')).default
|
|
10
|
+
|
|
11
|
+
// @ts-ignore
|
|
12
|
+
Ability.roles = (await import('../../../roles.json')).default
|
|
13
|
+
// @ts-ignore
|
|
14
|
+
Ability.fromRoutes(routes)
|
|
15
|
+
|
|
12
16
|
// @ts-ignore
|
|
13
17
|
const app = createApp({ routes })
|
|
14
18
|
|
package/src/register.ts
CHANGED
|
@@ -23,3 +23,9 @@ export function getHandler(id: string): Function {
|
|
|
23
23
|
if (!handler) throw new Error(`Handler ${id} not registered`)
|
|
24
24
|
return handler
|
|
25
25
|
}
|
|
26
|
+
|
|
27
|
+
export const _mw: Function[] = []
|
|
28
|
+
export const getGlobalMiddlewares = () => _mw
|
|
29
|
+
export function registerGlobalMiddleware(handler: any) {
|
|
30
|
+
_mw.push(handler)
|
|
31
|
+
}
|
package/src/response.ts
CHANGED
|
@@ -25,19 +25,19 @@ class NullContext {
|
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
export default class JsonResponse {
|
|
28
|
-
|
|
28
|
+
static #c?: Context
|
|
29
29
|
|
|
30
30
|
static setContext(c: Context) {
|
|
31
|
-
this
|
|
31
|
+
this.#c = c
|
|
32
32
|
return this
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
-
|
|
36
|
-
return this
|
|
35
|
+
static #context(): Context | NullContext {
|
|
36
|
+
return this.#c ?? new NullContext()
|
|
37
37
|
}
|
|
38
38
|
|
|
39
39
|
static raw(status?: StatusCode, body?: string) {
|
|
40
|
-
return this
|
|
40
|
+
return this.#context().newResponse(body ? body : null, { status })
|
|
41
41
|
}
|
|
42
42
|
|
|
43
43
|
static ok(): Response
|
|
@@ -46,7 +46,7 @@ export default class JsonResponse {
|
|
|
46
46
|
if (data === undefined)
|
|
47
47
|
return this.raw(200)
|
|
48
48
|
|
|
49
|
-
return this
|
|
49
|
+
return this.#context().json(data, 200)
|
|
50
50
|
}
|
|
51
51
|
|
|
52
52
|
static created(): Response
|
|
@@ -55,7 +55,7 @@ export default class JsonResponse {
|
|
|
55
55
|
if (data === undefined)
|
|
56
56
|
return this.raw(201)
|
|
57
57
|
|
|
58
|
-
return this
|
|
58
|
+
return this.#context().json(data, 201)
|
|
59
59
|
}
|
|
60
60
|
|
|
61
61
|
static accepted(): Response
|
|
@@ -64,7 +64,7 @@ export default class JsonResponse {
|
|
|
64
64
|
if (data === undefined)
|
|
65
65
|
return this.raw(202)
|
|
66
66
|
|
|
67
|
-
return this
|
|
67
|
+
return this.#context().json(data, 202)
|
|
68
68
|
}
|
|
69
69
|
|
|
70
70
|
static deleted(): Response
|
|
@@ -88,7 +88,7 @@ export default class JsonResponse {
|
|
|
88
88
|
if (data === undefined)
|
|
89
89
|
return this.raw(401)
|
|
90
90
|
|
|
91
|
-
return this
|
|
91
|
+
return this.#context().json(data, 401)
|
|
92
92
|
}
|
|
93
93
|
|
|
94
94
|
static forbidden(): Response
|
|
@@ -97,7 +97,7 @@ export default class JsonResponse {
|
|
|
97
97
|
if (data === undefined)
|
|
98
98
|
return this.raw(403)
|
|
99
99
|
|
|
100
|
-
return this
|
|
100
|
+
return this.#context().json(data, 403)
|
|
101
101
|
}
|
|
102
102
|
|
|
103
103
|
static notFound(): Response
|
|
@@ -122,7 +122,7 @@ export default class JsonResponse {
|
|
|
122
122
|
}
|
|
123
123
|
|
|
124
124
|
static error(errors?: Errors, msg?: string, status?: ContentfulStatusCode) {
|
|
125
|
-
const context = this
|
|
125
|
+
const context = this.#context()
|
|
126
126
|
status ??= 500
|
|
127
127
|
|
|
128
128
|
if (!errors && !msg)
|