stratal 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/README.md +8 -8
- package/dist/{base-email.provider-DypUAfWm.mjs → base-email.provider-mjynzewK.mjs} +1 -1
- package/dist/{base-email.provider-DypUAfWm.mjs.map → base-email.provider-mjynzewK.mjs.map} +1 -1
- package/dist/bin/cloudflare-workers-loader.mjs +33 -1
- package/dist/bin/cloudflare-workers-loader.mjs.map +1 -1
- package/dist/bin/quarry.mjs +169 -7
- package/dist/bin/quarry.mjs.map +1 -1
- package/dist/cache/index.d.mts +3 -2
- package/dist/cache/index.d.mts.map +1 -1
- package/dist/cache/index.mjs +3 -10
- package/dist/cache/index.mjs.map +1 -1
- package/dist/{colors-Y7WIFXs7.mjs → colors-DJaRDXoS.mjs} +1 -1
- package/dist/{colors-Y7WIFXs7.mjs.map → colors-DJaRDXoS.mjs.map} +1 -1
- package/dist/{command-B1CPgsrU.mjs → command-BgSlsS4M.mjs} +3 -3
- package/dist/command-BgSlsS4M.mjs.map +1 -0
- package/dist/{command-TnkPYWta.d.mts → command-DsQq56Lp.d.mts} +2 -2
- package/dist/{command-TnkPYWta.d.mts.map → command-DsQq56Lp.d.mts.map} +1 -1
- package/dist/config/index.d.mts +81 -37
- package/dist/config/index.d.mts.map +1 -1
- package/dist/config/index.mjs +135 -61
- package/dist/config/index.mjs.map +1 -1
- package/dist/{consumer-registry-Bymm6ff4.d.mts → consumer-registry-Doom7BEh.d.mts} +1 -1
- package/dist/{consumer-registry-Bymm6ff4.d.mts.map → consumer-registry-Doom7BEh.d.mts.map} +1 -1
- package/dist/controller.decorator-LZY9aHYG.mjs +66 -0
- package/dist/controller.decorator-LZY9aHYG.mjs.map +1 -0
- package/dist/cron/index.d.mts +4 -3
- package/dist/cron/index.d.mts.map +1 -1
- package/dist/cron/index.mjs +1 -3
- package/dist/{cron-manager-CFBamKKk.mjs → cron-manager-C30t9UZM.mjs} +29 -19
- package/dist/cron-manager-C30t9UZM.mjs.map +1 -0
- package/dist/{cron-manager-D7imGwUT.d.mts → cron-manager-RuPtFVLy.d.mts} +28 -14
- package/dist/cron-manager-RuPtFVLy.d.mts.map +1 -0
- package/dist/di/index.d.mts +2 -2
- package/dist/di/index.mjs +3 -3
- package/dist/email/index.d.mts +3 -3
- package/dist/email/index.mjs +87 -18
- package/dist/email/index.mjs.map +1 -1
- package/dist/{en-DaewN8hc.mjs → en-rHmW6vD9.mjs} +14 -31
- package/dist/en-rHmW6vD9.mjs.map +1 -0
- package/dist/env-CamWD-U1.d.mts +25 -0
- package/dist/env-CamWD-U1.d.mts.map +1 -0
- package/dist/errors/index.d.mts +2 -2
- package/dist/errors/index.mjs +2 -3
- package/dist/errors-B4pYgYON.mjs +1714 -0
- package/dist/errors-B4pYgYON.mjs.map +1 -0
- package/dist/{errors-DuAR5Wke.mjs → errors-BUyUfr2Z.mjs} +14 -7
- package/dist/errors-BUyUfr2Z.mjs.map +1 -0
- package/dist/events/index.d.mts +2 -2
- package/dist/events/index.mjs +1 -2
- package/dist/{events-CvUSgEuN.mjs → events-COKixqnG.mjs} +2 -2
- package/dist/{events-CvUSgEuN.mjs.map → events-COKixqnG.mjs.map} +1 -1
- package/dist/{gateway-context-CNOLkLUC.mjs → gateway-context-cqZ8wMoi.mjs} +4 -9
- package/dist/gateway-context-cqZ8wMoi.mjs.map +1 -0
- package/dist/guards/index.d.mts +14 -5
- package/dist/guards/index.d.mts.map +1 -1
- package/dist/guards/index.mjs +1 -1
- package/dist/{guards-DUk_Kzst.mjs → guards-DMbsAxSX.mjs} +1 -1
- package/dist/guards-DMbsAxSX.mjs.map +1 -0
- package/dist/http-method.decorator-BT3ufnz8.mjs +96 -0
- package/dist/http-method.decorator-BT3ufnz8.mjs.map +1 -0
- package/dist/i18n/index.d.mts +3 -3
- package/dist/i18n/index.mjs +3 -16
- package/dist/i18n/messages/en/index.d.mts +1 -1
- package/dist/i18n/messages/en/index.mjs +1 -1
- package/dist/i18n/utils/index.d.mts +30 -0
- package/dist/i18n/utils/index.d.mts.map +1 -0
- package/dist/i18n/utils/index.mjs +2 -0
- package/dist/i18n/validation/index.d.mts +1 -1
- package/dist/i18n/validation/index.mjs +1 -1
- package/dist/i18n.module-CI_prYFD.mjs +2340 -0
- package/dist/i18n.module-CI_prYFD.mjs.map +1 -0
- package/dist/{index-NGxg-KP_.d.mts → index-B437eK7p.d.mts} +59 -16
- package/dist/index-B437eK7p.d.mts.map +1 -0
- package/dist/{index-Dp6A5ywM.d.mts → index-CWRS7Ri3.d.mts} +1 -1
- package/dist/{index-Dp6A5ywM.d.mts.map → index-CWRS7Ri3.d.mts.map} +1 -1
- package/dist/{index-D_w_Rmtd.d.mts → index-DFhEeFfC.d.mts} +13 -30
- package/dist/{index-D_w_Rmtd.d.mts.map → index-DFhEeFfC.d.mts.map} +1 -1
- package/dist/index-DPFqRs8L.d.mts +4318 -0
- package/dist/index-DPFqRs8L.d.mts.map +1 -0
- package/dist/{index-DGRe6Yoa.d.mts → index-Dnqm9ZB6.d.mts} +5 -4
- package/dist/index-Dnqm9ZB6.d.mts.map +1 -0
- package/dist/index-SHx31sBJ.d.mts +101 -0
- package/dist/index-SHx31sBJ.d.mts.map +1 -0
- package/dist/index.d.mts +5 -3
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +1 -20
- package/dist/{is-command-DJVI6wEJ.mjs → is-command-C6a7WTPw.mjs} +2 -2
- package/dist/{is-command-DJVI6wEJ.mjs.map → is-command-C6a7WTPw.mjs.map} +1 -1
- package/dist/{is-seeder-D5MIEcdz.mjs → is-seeder-CebjZCDn.mjs} +1 -1
- package/dist/{is-seeder-D5MIEcdz.mjs.map → is-seeder-CebjZCDn.mjs.map} +1 -1
- package/dist/logger/index.d.mts +1 -1
- package/dist/logger/index.mjs +1 -1
- package/dist/{logger-CGT91VY6.mjs → logger-V6Ms3QnQ.mjs} +63 -45
- package/dist/logger-V6Ms3QnQ.mjs.map +1 -0
- package/dist/macroable/index.d.mts +2 -0
- package/dist/macroable/index.mjs +2 -0
- package/dist/macroable-BmufBshB.mjs +122 -0
- package/dist/macroable-BmufBshB.mjs.map +1 -0
- package/dist/module/index.d.mts +3 -4
- package/dist/module/index.d.mts.map +1 -1
- package/dist/module/index.mjs +1 -10
- package/dist/module-qGE_1duv.mjs +732 -0
- package/dist/module-qGE_1duv.mjs.map +1 -0
- package/dist/openapi/index.d.mts +3 -3
- package/dist/openapi/index.mjs +2 -15
- package/dist/{openapi-tools.service-B3TxYKoQ.mjs → openapi-tools.service-CYWGuhue.mjs} +4 -1
- package/dist/{openapi-tools.service-B3TxYKoQ.mjs.map → openapi-tools.service-CYWGuhue.mjs.map} +1 -1
- package/dist/{openapi.service-DGnX3Fc4.d.mts → openapi.service-Bv_NioM9.d.mts} +9 -17
- package/dist/openapi.service-Bv_NioM9.d.mts.map +1 -0
- package/dist/quarry/index.d.mts +26 -12
- package/dist/quarry/index.d.mts.map +1 -1
- package/dist/quarry/index.mjs +4 -8
- package/dist/{quarry-registry-B2rkO-JS.mjs → quarry-registry-DFfRRkA7.mjs} +45 -40
- package/dist/quarry-registry-DFfRRkA7.mjs.map +1 -0
- package/dist/queue/index.d.mts +2 -2
- package/dist/queue/index.mjs +3 -13
- package/dist/queue/index.mjs.map +1 -1
- package/dist/{queue.module-BtI8f4Jo.mjs → queue.module-P-G-nCYz.mjs} +39 -42
- package/dist/queue.module-P-G-nCYz.mjs.map +1 -0
- package/dist/r2-storage.provider-LdzK9tfG.mjs +244 -0
- package/dist/r2-storage.provider-LdzK9tfG.mjs.map +1 -0
- package/dist/{resend.provider-bXMEkdRJ.mjs → resend.provider-bwILp0WI.mjs} +2 -4
- package/dist/{resend.provider-bXMEkdRJ.mjs.map → resend.provider-bwILp0WI.mjs.map} +1 -1
- package/dist/router/index.d.mts +2 -2
- package/dist/router/index.mjs +7 -16
- package/dist/seeder/index.d.mts +3 -4
- package/dist/seeder/index.d.mts.map +1 -1
- package/dist/seeder/index.mjs +2 -6
- package/dist/{seeder-R7RXJC35.mjs → seeder-BcqIFa2X.mjs} +5 -5
- package/dist/{seeder-R7RXJC35.mjs.map → seeder-BcqIFa2X.mjs.map} +1 -1
- package/dist/setup-CtekcwuO.mjs +37 -0
- package/dist/setup-CtekcwuO.mjs.map +1 -0
- package/dist/signed-url-COX7cCWR.mjs +74 -0
- package/dist/signed-url-COX7cCWR.mjs.map +1 -0
- package/dist/{smtp.provider-DrbHQztF.mjs → smtp.provider-B07yuARi.mjs} +2 -4
- package/dist/{smtp.provider-DrbHQztF.mjs.map → smtp.provider-B07yuARi.mjs.map} +1 -1
- package/dist/storage/index.d.mts +39 -17
- package/dist/storage/index.d.mts.map +1 -1
- package/dist/storage/index.mjs +3 -14
- package/dist/storage/providers/index.d.mts +30 -69
- package/dist/storage/providers/index.d.mts.map +1 -1
- package/dist/storage/providers/index.mjs +2 -5
- package/dist/{storage-CZKHOhci.mjs → storage-P6X4h9So.mjs} +102 -29
- package/dist/storage-P6X4h9So.mjs.map +1 -0
- package/dist/{storage-provider.interface-0IqcdhBf.d.mts → storage-provider.interface-CC1nniHk.d.mts} +20 -15
- package/dist/storage-provider.interface-CC1nniHk.d.mts.map +1 -0
- package/dist/stratal-BCiwCFN9.mjs +533 -0
- package/dist/stratal-BCiwCFN9.mjs.map +1 -0
- package/dist/{types-DahElfUw.d.mts → types-DIWemRad.d.mts} +2 -2
- package/dist/types-DIWemRad.d.mts.map +1 -0
- package/dist/{usage-generator-CVIsENuE.mjs → usage-generator-MBcRo0Q2.mjs} +2 -2
- package/dist/{usage-generator-CVIsENuE.mjs.map → usage-generator-MBcRo0Q2.mjs.map} +1 -1
- package/dist/{validation-DQTC259A.mjs → validation-Dbg3ehdP.mjs} +2 -2
- package/dist/{validation-DQTC259A.mjs.map → validation-Dbg3ehdP.mjs.map} +1 -1
- package/dist/websocket/index.d.mts +3 -3
- package/dist/websocket/index.d.mts.map +1 -1
- package/dist/websocket/index.mjs +1 -4
- package/dist/workers/index.d.mts +2 -1
- package/dist/workers/index.d.mts.map +1 -1
- package/dist/workers/index.mjs +2 -20
- package/dist/workers/index.mjs.map +1 -1
- package/package.json +41 -50
- package/dist/application-DfPtIzxF.d.mts +0 -177
- package/dist/application-DfPtIzxF.d.mts.map +0 -1
- package/dist/command-B1CPgsrU.mjs.map +0 -1
- package/dist/cron-manager-CFBamKKk.mjs.map +0 -1
- package/dist/cron-manager-D7imGwUT.d.mts.map +0 -1
- package/dist/en-DaewN8hc.mjs.map +0 -1
- package/dist/errors-DSKapqD8.mjs +0 -707
- package/dist/errors-DSKapqD8.mjs.map +0 -1
- package/dist/errors-DuAR5Wke.mjs.map +0 -1
- package/dist/gateway-context-CNOLkLUC.mjs.map +0 -1
- package/dist/guards-DUk_Kzst.mjs.map +0 -1
- package/dist/i18n.module-Dn9SrFdS.mjs +0 -1841
- package/dist/i18n.module-Dn9SrFdS.mjs.map +0 -1
- package/dist/index-BFCxSp_f.d.mts +0 -2625
- package/dist/index-BFCxSp_f.d.mts.map +0 -1
- package/dist/index-DGRe6Yoa.d.mts.map +0 -1
- package/dist/index-NGxg-KP_.d.mts.map +0 -1
- package/dist/logger-CGT91VY6.mjs.map +0 -1
- package/dist/middleware/index.d.mts +0 -2
- package/dist/middleware/index.mjs +0 -5
- package/dist/middleware-Bl-b5pkt.mjs +0 -362
- package/dist/middleware-Bl-b5pkt.mjs.map +0 -1
- package/dist/module-registry-CmjBX6ol.d.mts +0 -121
- package/dist/module-registry-CmjBX6ol.d.mts.map +0 -1
- package/dist/module-tUtyVJ5E.mjs +0 -371
- package/dist/module-tUtyVJ5E.mjs.map +0 -1
- package/dist/openapi.service-DGnX3Fc4.d.mts.map +0 -1
- package/dist/quarry-registry-B2rkO-JS.mjs.map +0 -1
- package/dist/queue.module-BtI8f4Jo.mjs.map +0 -1
- package/dist/router-context-D9R1v2Ac.mjs +0 -267
- package/dist/router-context-D9R1v2Ac.mjs.map +0 -1
- package/dist/s3-storage.provider-CttzNnDR.mjs +0 -335
- package/dist/s3-storage.provider-CttzNnDR.mjs.map +0 -1
- package/dist/storage-CZKHOhci.mjs.map +0 -1
- package/dist/storage-provider.interface-0IqcdhBf.d.mts.map +0 -1
- package/dist/stratal-D5smIU1y.mjs +0 -315
- package/dist/stratal-D5smIU1y.mjs.map +0 -1
- package/dist/types-DahElfUw.d.mts.map +0 -1
|
@@ -1,267 +0,0 @@
|
|
|
1
|
-
import { n as RequestContainerNotInitializedError } from "./errors-DSKapqD8.mjs";
|
|
2
|
-
import { stream, streamSSE, streamText } from "hono/streaming";
|
|
3
|
-
//#region src/router/constants.ts
|
|
4
|
-
/**
|
|
5
|
-
* Type-safe context keys for Hono router variables
|
|
6
|
-
* Using symbols to avoid string collisions
|
|
7
|
-
*/
|
|
8
|
-
const ROUTER_CONTEXT_KEYS = {
|
|
9
|
-
REQUEST_CONTAINER: "requestContainer",
|
|
10
|
-
LOCALE: "locale"
|
|
11
|
-
};
|
|
12
|
-
/**
|
|
13
|
-
* Metadata keys for storing route and controller configuration
|
|
14
|
-
* Using symbols to avoid collisions with other decorators
|
|
15
|
-
*/
|
|
16
|
-
const ROUTE_METADATA_KEYS = {
|
|
17
|
-
CONTROLLER_ROUTE: Symbol.for("stratal:controller:route"),
|
|
18
|
-
CONTROLLER_OPTIONS: Symbol.for("stratal:controller:options"),
|
|
19
|
-
CONTROLLER_MIDDLEWARES: Symbol.for("stratal:controller:middlewares"),
|
|
20
|
-
ROUTE_CONFIG: Symbol.for("stratal:route:config"),
|
|
21
|
-
DECORATED_METHODS: Symbol.for("stratal:decorated:methods"),
|
|
22
|
-
HTTP_ROUTE_CONFIG: Symbol.for("stratal:http-route:config"),
|
|
23
|
-
HTTP_DECORATED_METHODS: Symbol.for("stratal:http-decorated:methods"),
|
|
24
|
-
AUTH_GUARD: Symbol.for("stratal:auth:guard"),
|
|
25
|
-
GATEWAY_MARKER: Symbol.for("stratal:gateway:marker"),
|
|
26
|
-
WS_ON_MESSAGE: Symbol.for("stratal:ws:on-message"),
|
|
27
|
-
WS_ON_CLOSE: Symbol.for("stratal:ws:on-close"),
|
|
28
|
-
WS_ON_ERROR: Symbol.for("stratal:ws:on-error")
|
|
29
|
-
};
|
|
30
|
-
/**
|
|
31
|
-
* Security scheme identifiers for OpenAPI
|
|
32
|
-
* These reference the security scheme definitions in security.schemas.ts
|
|
33
|
-
*/
|
|
34
|
-
const SECURITY_SCHEMES = {
|
|
35
|
-
BEARER_AUTH: "bearerAuth",
|
|
36
|
-
API_KEY: "apiKey",
|
|
37
|
-
SESSION_COOKIE: "sessionCookie"
|
|
38
|
-
};
|
|
39
|
-
/**
|
|
40
|
-
* HTTP method mapping for RESTful controller methods
|
|
41
|
-
* Maps controller method names to HTTP verbs and path patterns
|
|
42
|
-
*/
|
|
43
|
-
const HTTP_METHODS = {
|
|
44
|
-
index: {
|
|
45
|
-
method: "get",
|
|
46
|
-
path: ""
|
|
47
|
-
},
|
|
48
|
-
show: {
|
|
49
|
-
method: "get",
|
|
50
|
-
path: "/:id"
|
|
51
|
-
},
|
|
52
|
-
create: {
|
|
53
|
-
method: "post",
|
|
54
|
-
path: ""
|
|
55
|
-
},
|
|
56
|
-
update: {
|
|
57
|
-
method: "put",
|
|
58
|
-
path: "/:id"
|
|
59
|
-
},
|
|
60
|
-
patch: {
|
|
61
|
-
method: "patch",
|
|
62
|
-
path: "/:id"
|
|
63
|
-
},
|
|
64
|
-
destroy: {
|
|
65
|
-
method: "delete",
|
|
66
|
-
path: "/:id"
|
|
67
|
-
}
|
|
68
|
-
};
|
|
69
|
-
/**
|
|
70
|
-
* Default success status codes for RESTful controller methods
|
|
71
|
-
* Used by @Route() decorator to auto-derive response status
|
|
72
|
-
*/
|
|
73
|
-
const METHOD_STATUS_CODES = {
|
|
74
|
-
index: 200,
|
|
75
|
-
show: 200,
|
|
76
|
-
create: 201,
|
|
77
|
-
update: 200,
|
|
78
|
-
patch: 200,
|
|
79
|
-
destroy: 200
|
|
80
|
-
};
|
|
81
|
-
/**
|
|
82
|
-
* Sentinel symbol to opt a controller out of versioning.
|
|
83
|
-
* When used as the version, no prefix is applied even when defaultVersion is set.
|
|
84
|
-
*/
|
|
85
|
-
const VERSION_NEUTRAL = Symbol.for("stratal:version:neutral");
|
|
86
|
-
/**
|
|
87
|
-
* Default content type for request bodies and responses
|
|
88
|
-
*/
|
|
89
|
-
const DEFAULT_CONTENT_TYPE = "application/json";
|
|
90
|
-
//#endregion
|
|
91
|
-
//#region src/router/router-context.ts
|
|
92
|
-
/**
|
|
93
|
-
* Router context wrapper with helper methods
|
|
94
|
-
*
|
|
95
|
-
* Provides convenient access to Hono's context and common request/response operations.
|
|
96
|
-
* The native Hono context is available via the `c` property for advanced use cases.
|
|
97
|
-
*
|
|
98
|
-
* @example
|
|
99
|
-
* ```typescript
|
|
100
|
-
* async index(ctx: RouterContext): Promise<Response> {
|
|
101
|
-
* // Use helper methods
|
|
102
|
-
* const users = await this.service.findAll()
|
|
103
|
-
* return ctx.json(users)
|
|
104
|
-
* }
|
|
105
|
-
*
|
|
106
|
-
* async show(ctx: RouterContext): Promise<Response> {
|
|
107
|
-
* // Access route params
|
|
108
|
-
* const id = ctx.param('id')
|
|
109
|
-
* const user = await this.service.findById(id)
|
|
110
|
-
* return ctx.json(user)
|
|
111
|
-
* }
|
|
112
|
-
*
|
|
113
|
-
* async create(ctx: RouterContext): Promise<Response> {
|
|
114
|
-
* // Parse request body
|
|
115
|
-
* const body = await ctx.body<CreateUserInput>()
|
|
116
|
-
* const user = await this.service.create(body)
|
|
117
|
-
* return ctx.json(user, 201)
|
|
118
|
-
* }
|
|
119
|
-
* ```
|
|
120
|
-
*/
|
|
121
|
-
var RouterContext = class {
|
|
122
|
-
/**
|
|
123
|
-
* Native Hono context
|
|
124
|
-
* Access for advanced use cases not covered by helper methods
|
|
125
|
-
*/
|
|
126
|
-
constructor(c) {
|
|
127
|
-
this.c = c;
|
|
128
|
-
}
|
|
129
|
-
/**
|
|
130
|
-
* Get request-scoped DI container
|
|
131
|
-
* Contains request-specific services and context (AuthContext)
|
|
132
|
-
*
|
|
133
|
-
* @throws Error if container not initialized
|
|
134
|
-
*/
|
|
135
|
-
getContainer() {
|
|
136
|
-
const container = this.c.get(ROUTER_CONTEXT_KEYS.REQUEST_CONTAINER);
|
|
137
|
-
if (!container) throw new RequestContainerNotInitializedError();
|
|
138
|
-
return container;
|
|
139
|
-
}
|
|
140
|
-
/**
|
|
141
|
-
* Set locale for the current request
|
|
142
|
-
* Locale is determined by X-Locale header or defaults to config
|
|
143
|
-
*
|
|
144
|
-
* @param locale - Locale code (e.g., 'en', 'fr')
|
|
145
|
-
*/
|
|
146
|
-
setLocale(locale) {
|
|
147
|
-
this.c.set(ROUTER_CONTEXT_KEYS.LOCALE, locale);
|
|
148
|
-
}
|
|
149
|
-
/**
|
|
150
|
-
* Get locale for the current request
|
|
151
|
-
*
|
|
152
|
-
* @returns Current locale code
|
|
153
|
-
*/
|
|
154
|
-
getLocale() {
|
|
155
|
-
return this.c.get(ROUTER_CONTEXT_KEYS.LOCALE) || "en";
|
|
156
|
-
}
|
|
157
|
-
/**
|
|
158
|
-
* Return JSON response
|
|
159
|
-
*
|
|
160
|
-
* When data is null, automatically returns 204 No Content (configurable via status param).
|
|
161
|
-
*
|
|
162
|
-
* @param data - Data to serialize as JSON, or null for 204
|
|
163
|
-
* @param status - HTTP status code (default: 200, or 204 when data is null)
|
|
164
|
-
*/
|
|
165
|
-
json(data, status) {
|
|
166
|
-
if (data === null) return this.c.body(null, status ?? 204);
|
|
167
|
-
return this.c.json(data, status);
|
|
168
|
-
}
|
|
169
|
-
/**
|
|
170
|
-
* Get route parameter value
|
|
171
|
-
*
|
|
172
|
-
* @param key - Parameter name (e.g., 'id' for /users/:id)
|
|
173
|
-
*/
|
|
174
|
-
param(key) {
|
|
175
|
-
return this.c.req.valid("param")[key];
|
|
176
|
-
}
|
|
177
|
-
/**
|
|
178
|
-
* Get query parameter value
|
|
179
|
-
*
|
|
180
|
-
* @param key - Query parameter name
|
|
181
|
-
*/
|
|
182
|
-
query(key) {
|
|
183
|
-
const validated = this.c.req.valid("query");
|
|
184
|
-
return key ? validated[key] : validated;
|
|
185
|
-
}
|
|
186
|
-
/**
|
|
187
|
-
* Get request header value
|
|
188
|
-
*
|
|
189
|
-
* @param name - Header name (case-insensitive)
|
|
190
|
-
*/
|
|
191
|
-
header(name) {
|
|
192
|
-
return this.c.req.header(name);
|
|
193
|
-
}
|
|
194
|
-
/**
|
|
195
|
-
* Get validated request body from OpenAPI route
|
|
196
|
-
* Returns pre-validated data that has passed schema validation
|
|
197
|
-
*
|
|
198
|
-
* @returns Validated JSON body
|
|
199
|
-
*/
|
|
200
|
-
body() {
|
|
201
|
-
return this.c.req.valid("json");
|
|
202
|
-
}
|
|
203
|
-
/**
|
|
204
|
-
* Return text response
|
|
205
|
-
*
|
|
206
|
-
* @param text - Text content
|
|
207
|
-
* @param status - HTTP status code (default: 200)
|
|
208
|
-
*/
|
|
209
|
-
text(text, status) {
|
|
210
|
-
return this.c.text(text, status);
|
|
211
|
-
}
|
|
212
|
-
/**
|
|
213
|
-
* Return HTML response
|
|
214
|
-
*
|
|
215
|
-
* @param html - HTML content
|
|
216
|
-
* @param status - HTTP status code (default: 200)
|
|
217
|
-
*/
|
|
218
|
-
html(html, status) {
|
|
219
|
-
return this.c.html(html, status);
|
|
220
|
-
}
|
|
221
|
-
/**
|
|
222
|
-
* Redirect to another URL
|
|
223
|
-
*
|
|
224
|
-
* @param url - Target URL
|
|
225
|
-
* @param status - HTTP status code (default: 302)
|
|
226
|
-
*/
|
|
227
|
-
redirect(url, status) {
|
|
228
|
-
return this.c.redirect(url, status);
|
|
229
|
-
}
|
|
230
|
-
/**
|
|
231
|
-
* Return a streaming response (binary/generic)
|
|
232
|
-
*
|
|
233
|
-
* @param callback - Async function that writes to the stream
|
|
234
|
-
* @param onError - Optional error handler called if an error occurs during streaming
|
|
235
|
-
*/
|
|
236
|
-
stream(callback, onError) {
|
|
237
|
-
return stream(this.c, callback, onError);
|
|
238
|
-
}
|
|
239
|
-
/**
|
|
240
|
-
* Return a streaming text response
|
|
241
|
-
*
|
|
242
|
-
* Automatically sets `Content-Encoding: Identity` for Cloudflare Workers compatibility.
|
|
243
|
-
*
|
|
244
|
-
* @param callback - Async function that writes text to the stream
|
|
245
|
-
* @param onError - Optional error handler called if an error occurs during streaming
|
|
246
|
-
*/
|
|
247
|
-
streamText(callback, onError) {
|
|
248
|
-
this.c.header("Content-Encoding", "Identity");
|
|
249
|
-
return streamText(this.c, callback, onError);
|
|
250
|
-
}
|
|
251
|
-
/**
|
|
252
|
-
* Return a Server-Sent Events (SSE) streaming response
|
|
253
|
-
*
|
|
254
|
-
* Automatically sets `Content-Encoding: Identity` for Cloudflare Workers compatibility.
|
|
255
|
-
*
|
|
256
|
-
* @param callback - Async function that writes SSE events to the stream
|
|
257
|
-
* @param onError - Optional error handler called if an error occurs during streaming
|
|
258
|
-
*/
|
|
259
|
-
streamSSE(callback, onError) {
|
|
260
|
-
this.c.header("Content-Encoding", "Identity");
|
|
261
|
-
return streamSSE(this.c, callback, onError);
|
|
262
|
-
}
|
|
263
|
-
};
|
|
264
|
-
//#endregion
|
|
265
|
-
export { ROUTER_CONTEXT_KEYS as a, VERSION_NEUTRAL as c, METHOD_STATUS_CODES as i, DEFAULT_CONTENT_TYPE as n, ROUTE_METADATA_KEYS as o, HTTP_METHODS as r, SECURITY_SCHEMES as s, RouterContext as t };
|
|
266
|
-
|
|
267
|
-
//# sourceMappingURL=router-context-D9R1v2Ac.mjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"router-context-D9R1v2Ac.mjs","names":["honoStream","honoStreamText","honoStreamSSE"],"sources":["../src/router/constants.ts","../src/router/router-context.ts"],"sourcesContent":["/**\n * Type-safe context keys for Hono router variables\n * Using symbols to avoid string collisions\n */\nexport const ROUTER_CONTEXT_KEYS = {\n REQUEST_CONTAINER: 'requestContainer',\n LOCALE: 'locale'\n} as const satisfies Record<string, string>\n\n/**\n * Metadata keys for storing route and controller configuration\n * Using symbols to avoid collisions with other decorators\n */\nexport const ROUTE_METADATA_KEYS = {\n CONTROLLER_ROUTE: Symbol.for('stratal:controller:route'),\n CONTROLLER_OPTIONS: Symbol.for('stratal:controller:options'),\n CONTROLLER_MIDDLEWARES: Symbol.for('stratal:controller:middlewares'),\n ROUTE_CONFIG: Symbol.for('stratal:route:config'),\n DECORATED_METHODS: Symbol.for('stratal:decorated:methods'),\n HTTP_ROUTE_CONFIG: Symbol.for('stratal:http-route:config'),\n HTTP_DECORATED_METHODS: Symbol.for('stratal:http-decorated:methods'),\n AUTH_GUARD: Symbol.for('stratal:auth:guard'),\n GATEWAY_MARKER: Symbol.for('stratal:gateway:marker'),\n WS_ON_MESSAGE: Symbol.for('stratal:ws:on-message'),\n WS_ON_CLOSE: Symbol.for('stratal:ws:on-close'),\n WS_ON_ERROR: Symbol.for('stratal:ws:on-error'),\n} as const\n\n/**\n * Security scheme identifiers for OpenAPI\n * These reference the security scheme definitions in security.schemas.ts\n */\nexport const SECURITY_SCHEMES = {\n BEARER_AUTH: 'bearerAuth',\n API_KEY: 'apiKey',\n SESSION_COOKIE: 'sessionCookie'\n} as const\n\n/**\n * HTTP method mapping for RESTful controller methods\n * Maps controller method names to HTTP verbs and path patterns\n */\nexport const HTTP_METHODS = {\n index: { method: 'get', path: '' } as const,\n show: { method: 'get', path: '/:id' } as const,\n create: { method: 'post', path: '' } as const,\n update: { method: 'put', path: '/:id' } as const,\n patch: { method: 'patch', path: '/:id' } as const,\n destroy: { method: 'delete', path: '/:id' } as const\n} as const\n\n/**\n * Default success status codes for RESTful controller methods\n * Used by @Route() decorator to auto-derive response status\n */\nexport const METHOD_STATUS_CODES = {\n index: 200,\n show: 200,\n create: 201,\n update: 200,\n patch: 200,\n destroy: 200\n} as const\n\n/**\n * Sentinel symbol to opt a controller out of versioning.\n * When used as the version, no prefix is applied even when defaultVersion is set.\n */\nexport const VERSION_NEUTRAL = Symbol.for('stratal:version:neutral')\n\n/**\n * Default content type for request bodies and responses\n */\nexport const DEFAULT_CONTENT_TYPE = 'application/json'\n","import type { Context } from 'hono'\nimport type { SSEStreamingApi } from 'hono/streaming'\nimport { stream as honoStream, streamSSE as honoStreamSSE, streamText as honoStreamText } from 'hono/streaming'\nimport type { ContentfulStatusCode, RedirectStatusCode } from 'hono/utils/http-status'\nimport type { StreamingApi } from 'hono/utils/stream'\nimport type { Container } from '../di/container'\nimport { RequestContainerNotInitializedError } from '../errors'\nimport { ROUTER_CONTEXT_KEYS } from './constants'\nimport type { RouterEnv } from './types'\n\nexport type ContextQueryResult<R extends Record<string, unknown> | undefined, K extends string | undefined> = K extends string ? string : R extends undefined ? Record<string, unknown> : R\n\n/**\n * Router context wrapper with helper methods\n *\n * Provides convenient access to Hono's context and common request/response operations.\n * The native Hono context is available via the `c` property for advanced use cases.\n *\n * @example\n * ```typescript\n * async index(ctx: RouterContext): Promise<Response> {\n * // Use helper methods\n * const users = await this.service.findAll()\n * return ctx.json(users)\n * }\n *\n * async show(ctx: RouterContext): Promise<Response> {\n * // Access route params\n * const id = ctx.param('id')\n * const user = await this.service.findById(id)\n * return ctx.json(user)\n * }\n *\n * async create(ctx: RouterContext): Promise<Response> {\n * // Parse request body\n * const body = await ctx.body<CreateUserInput>()\n * const user = await this.service.create(body)\n * return ctx.json(user, 201)\n * }\n * ```\n */\nexport class RouterContext<T extends RouterEnv = RouterEnv> {\n /**\n * Native Hono context\n * Access for advanced use cases not covered by helper methods\n */\n constructor(\n public readonly c: Context<T>\n ) { }\n\n /**\n * Get request-scoped DI container\n * Contains request-specific services and context (AuthContext)\n *\n * @throws Error if container not initialized\n */\n getContainer(): Container {\n const container = this.c.get(ROUTER_CONTEXT_KEYS.REQUEST_CONTAINER)\n if (!container) {\n throw new RequestContainerNotInitializedError()\n }\n return container as Container\n }\n\n /**\n * Set locale for the current request\n * Locale is determined by X-Locale header or defaults to config\n *\n * @param locale - Locale code (e.g., 'en', 'fr')\n */\n setLocale(locale: string): void {\n this.c.set(ROUTER_CONTEXT_KEYS.LOCALE, locale)\n }\n\n /**\n * Get locale for the current request\n *\n * @returns Current locale code\n */\n getLocale(): string {\n const locale = this.c.get(ROUTER_CONTEXT_KEYS.LOCALE)\n return (locale as string) || 'en'\n }\n\n /**\n * Return JSON response\n *\n * When data is null, automatically returns 204 No Content (configurable via status param).\n *\n * @param data - Data to serialize as JSON, or null for 204\n * @param status - HTTP status code (default: 200, or 204 when data is null)\n */\n json(data: object | null, status?: ContentfulStatusCode): Response {\n if (data === null) {\n return this.c.body(null, status ?? 204)\n }\n return this.c.json(data, status)\n }\n\n /**\n * Get route parameter value\n *\n * @param key - Parameter name (e.g., 'id' for /users/:id)\n */\n param(key: string): string {\n return (this.c.req as unknown as { valid(target: 'param'): Record<string, string> }).valid('param')[key]\n }\n\n /**\n * Get query parameter value\n *\n * @param key - Query parameter name\n */\n query<R extends Record<string, unknown> | undefined = undefined, K extends string | undefined = undefined>(key?: K): ContextQueryResult<R, K> {\n const validated = (this.c.req as unknown as { valid(target: 'query'): Record<string, unknown> }).valid('query')\n return key ? validated[key] as ContextQueryResult<R, K> : validated as ContextQueryResult<R, K>\n }\n\n /**\n * Get request header value\n *\n * @param name - Header name (case-insensitive)\n */\n header(name: string): string | undefined {\n return this.c.req.header(name)\n }\n\n /**\n * Get validated request body from OpenAPI route\n * Returns pre-validated data that has passed schema validation\n *\n * @returns Validated JSON body\n */\n body<T>(): Promise<T> {\n // Type assertion needed because req.valid() is type-safe per route\n // but this is a generic helper method that works across all routes\n return (this.c.req as unknown as { valid(target: 'json'): Promise<T> }).valid('json')\n }\n\n /**\n * Return text response\n *\n * @param text - Text content\n * @param status - HTTP status code (default: 200)\n */\n text(text: string, status?: ContentfulStatusCode): Response {\n return this.c.text(text, status)\n }\n\n /**\n * Return HTML response\n *\n * @param html - HTML content\n * @param status - HTTP status code (default: 200)\n */\n html(html: string, status?: ContentfulStatusCode): Response {\n return this.c.html(html, status)\n }\n\n /**\n * Redirect to another URL\n *\n * @param url - Target URL\n * @param status - HTTP status code (default: 302)\n */\n redirect(url: string, status?: RedirectStatusCode): Response {\n return this.c.redirect(url, status)\n }\n\n /**\n * Return a streaming response (binary/generic)\n *\n * @param callback - Async function that writes to the stream\n * @param onError - Optional error handler called if an error occurs during streaming\n */\n stream(callback: (stream: StreamingApi) => Promise<void>, onError?: (err: Error, stream: StreamingApi) => Promise<void>): Response {\n return honoStream(this.c, callback, onError)\n }\n\n /**\n * Return a streaming text response\n *\n * Automatically sets `Content-Encoding: Identity` for Cloudflare Workers compatibility.\n *\n * @param callback - Async function that writes text to the stream\n * @param onError - Optional error handler called if an error occurs during streaming\n */\n streamText(callback: (stream: StreamingApi) => Promise<void>, onError?: (err: Error, stream: StreamingApi) => Promise<void>): Response {\n this.c.header('Content-Encoding', 'Identity')\n return honoStreamText(this.c, callback, onError)\n }\n\n /**\n * Return a Server-Sent Events (SSE) streaming response\n *\n * Automatically sets `Content-Encoding: Identity` for Cloudflare Workers compatibility.\n *\n * @param callback - Async function that writes SSE events to the stream\n * @param onError - Optional error handler called if an error occurs during streaming\n */\n streamSSE(callback: (stream: SSEStreamingApi) => Promise<void>, onError?: (err: Error, stream: SSEStreamingApi) => Promise<void>): Response {\n this.c.header('Content-Encoding', 'Identity')\n return honoStreamSSE(this.c, callback, onError)\n }\n}\n"],"mappings":"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"}
|
|
@@ -1,335 +0,0 @@
|
|
|
1
|
-
import { t as __exportAll } from "./chunk-D1SwGrFN.mjs";
|
|
2
|
-
import { t as StorageResponseBodyMissingError } from "./errors-DuAR5Wke.mjs";
|
|
3
|
-
import { DOMParser } from "@xmldom/xmldom";
|
|
4
|
-
import { AbortMultipartUploadCommand, CompleteMultipartUploadCommand, CreateMultipartUploadCommand, DeleteObjectCommand, DeleteObjectsCommand, GetObjectCommand, HeadObjectCommand, ListMultipartUploadsCommand, ListPartsCommand, PutObjectCommand, S3Client, UploadPartCommand } from "@aws-sdk/client-s3";
|
|
5
|
-
import { Upload } from "@aws-sdk/lib-storage";
|
|
6
|
-
import { getSignedUrl } from "@aws-sdk/s3-request-presigner";
|
|
7
|
-
//#region src/storage/dom.polyfill.ts
|
|
8
|
-
/**
|
|
9
|
-
* DOM polyfills for Cloudflare Workers
|
|
10
|
-
*
|
|
11
|
-
* AWS SDK v3 uses DOMParser and Node for XML parsing, which are not available in Workers.
|
|
12
|
-
* This module must be imported BEFORE any AWS SDK imports (including transitive).
|
|
13
|
-
*
|
|
14
|
-
* @see https://github.com/aws/aws-sdk-js-v3/issues/7375
|
|
15
|
-
*/
|
|
16
|
-
globalThis.DOMParser = DOMParser;
|
|
17
|
-
if (typeof globalThis.Node === "undefined") globalThis.Node = {
|
|
18
|
-
ELEMENT_NODE: 1,
|
|
19
|
-
ATTRIBUTE_NODE: 2,
|
|
20
|
-
TEXT_NODE: 3,
|
|
21
|
-
CDATA_SECTION_NODE: 4,
|
|
22
|
-
ENTITY_REFERENCE_NODE: 5,
|
|
23
|
-
ENTITY_NODE: 6,
|
|
24
|
-
PROCESSING_INSTRUCTION_NODE: 7,
|
|
25
|
-
COMMENT_NODE: 8,
|
|
26
|
-
DOCUMENT_NODE: 9,
|
|
27
|
-
DOCUMENT_TYPE_NODE: 10,
|
|
28
|
-
DOCUMENT_FRAGMENT_NODE: 11,
|
|
29
|
-
NOTATION_NODE: 12
|
|
30
|
-
};
|
|
31
|
-
//#endregion
|
|
32
|
-
//#region src/storage/providers/s3-storage.provider.ts
|
|
33
|
-
var s3_storage_provider_exports = /* @__PURE__ */ __exportAll({ S3StorageProvider: () => S3StorageProvider });
|
|
34
|
-
/**
|
|
35
|
-
* S3 Storage Provider
|
|
36
|
-
* Implements storage operations using AWS SDK for S3-compatible storage
|
|
37
|
-
* Works with AWS S3, Cloudflare R2, MinIO, and other S3-compatible services
|
|
38
|
-
*
|
|
39
|
-
* Implements IS3MultipartProvider for multipart upload support needed by TUS
|
|
40
|
-
*/
|
|
41
|
-
var S3StorageProvider = class {
|
|
42
|
-
client;
|
|
43
|
-
bucket;
|
|
44
|
-
disk;
|
|
45
|
-
constructor(config) {
|
|
46
|
-
this.client = new S3Client({
|
|
47
|
-
region: config.region || "auto",
|
|
48
|
-
endpoint: config.endpoint,
|
|
49
|
-
credentials: {
|
|
50
|
-
accessKeyId: config.accessKeyId,
|
|
51
|
-
secretAccessKey: config.secretAccessKey
|
|
52
|
-
},
|
|
53
|
-
forcePathStyle: true
|
|
54
|
-
});
|
|
55
|
-
this.bucket = config.bucket;
|
|
56
|
-
this.disk = config.disk;
|
|
57
|
-
}
|
|
58
|
-
async upload(body, path, options) {
|
|
59
|
-
const command = new PutObjectCommand({
|
|
60
|
-
Bucket: this.bucket,
|
|
61
|
-
Key: path,
|
|
62
|
-
Body: body,
|
|
63
|
-
ContentType: options.mimeType,
|
|
64
|
-
ContentLength: options.size,
|
|
65
|
-
Metadata: options.metadata,
|
|
66
|
-
Tagging: options.tagging
|
|
67
|
-
});
|
|
68
|
-
await this.client.send(command);
|
|
69
|
-
return {
|
|
70
|
-
path,
|
|
71
|
-
disk: this.disk,
|
|
72
|
-
fullPath: `${this.bucket}/${path}`,
|
|
73
|
-
size: options.size,
|
|
74
|
-
mimeType: options.mimeType ?? "application/octet-stream",
|
|
75
|
-
uploadedAt: /* @__PURE__ */ new Date()
|
|
76
|
-
};
|
|
77
|
-
}
|
|
78
|
-
async download(path) {
|
|
79
|
-
const command = new GetObjectCommand({
|
|
80
|
-
Bucket: this.bucket,
|
|
81
|
-
Key: path
|
|
82
|
-
});
|
|
83
|
-
const response = await this.client.send(command);
|
|
84
|
-
if (!response.Body) throw new StorageResponseBodyMissingError(path);
|
|
85
|
-
return {
|
|
86
|
-
toStream: () => response.Body?.transformToWebStream(),
|
|
87
|
-
contentType: response.ContentType ?? "application/octet-stream",
|
|
88
|
-
size: response.ContentLength ?? 0,
|
|
89
|
-
metadata: response.Metadata,
|
|
90
|
-
toString: () => response.Body?.transformToString(),
|
|
91
|
-
toArrayBuffer: () => response.Body?.transformToByteArray()
|
|
92
|
-
};
|
|
93
|
-
}
|
|
94
|
-
async delete(path) {
|
|
95
|
-
const command = new DeleteObjectCommand({
|
|
96
|
-
Bucket: this.bucket,
|
|
97
|
-
Key: path
|
|
98
|
-
});
|
|
99
|
-
await this.client.send(command);
|
|
100
|
-
}
|
|
101
|
-
async exists(path) {
|
|
102
|
-
try {
|
|
103
|
-
const command = new HeadObjectCommand({
|
|
104
|
-
Bucket: this.bucket,
|
|
105
|
-
Key: path
|
|
106
|
-
});
|
|
107
|
-
await this.client.send(command);
|
|
108
|
-
return true;
|
|
109
|
-
} catch {
|
|
110
|
-
return false;
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
async getPresignedUrl(path, method, expiresIn) {
|
|
114
|
-
let command;
|
|
115
|
-
switch (method) {
|
|
116
|
-
case "GET":
|
|
117
|
-
command = new GetObjectCommand({
|
|
118
|
-
Bucket: this.bucket,
|
|
119
|
-
Key: path
|
|
120
|
-
});
|
|
121
|
-
break;
|
|
122
|
-
case "PUT":
|
|
123
|
-
command = new PutObjectCommand({
|
|
124
|
-
Bucket: this.bucket,
|
|
125
|
-
Key: path
|
|
126
|
-
});
|
|
127
|
-
break;
|
|
128
|
-
case "DELETE":
|
|
129
|
-
command = new DeleteObjectCommand({
|
|
130
|
-
Bucket: this.bucket,
|
|
131
|
-
Key: path
|
|
132
|
-
});
|
|
133
|
-
break;
|
|
134
|
-
case "HEAD":
|
|
135
|
-
command = new HeadObjectCommand({
|
|
136
|
-
Bucket: this.bucket,
|
|
137
|
-
Key: path
|
|
138
|
-
});
|
|
139
|
-
break;
|
|
140
|
-
}
|
|
141
|
-
return {
|
|
142
|
-
url: await getSignedUrl(this.client, command, { expiresIn }),
|
|
143
|
-
expiresIn,
|
|
144
|
-
expiresAt: new Date(Date.now() + expiresIn * 1e3),
|
|
145
|
-
method
|
|
146
|
-
};
|
|
147
|
-
}
|
|
148
|
-
/**
|
|
149
|
-
* Chunked upload for streaming data without known size
|
|
150
|
-
* Uses @aws-sdk/lib-storage for multipart upload handling
|
|
151
|
-
*
|
|
152
|
-
* Benefits:
|
|
153
|
-
* - Handles unknown Content-Length automatically
|
|
154
|
-
* - Automatic retry on transient failures
|
|
155
|
-
* - Cleanup of partial uploads on error
|
|
156
|
-
* - Works with S3-compatible storage (R2, MinIO, RustFS)
|
|
157
|
-
*
|
|
158
|
-
* @param body - Content to upload (stream or buffer)
|
|
159
|
-
* @param path - Full path including disk root
|
|
160
|
-
* @param options - Upload options (mimeType required, size optional)
|
|
161
|
-
* @returns Upload result with metadata
|
|
162
|
-
*/
|
|
163
|
-
async chunkedUpload(body, path, options) {
|
|
164
|
-
await new Upload({
|
|
165
|
-
client: this.client,
|
|
166
|
-
params: {
|
|
167
|
-
Bucket: this.bucket,
|
|
168
|
-
Key: path,
|
|
169
|
-
Body: body,
|
|
170
|
-
ContentType: options.mimeType
|
|
171
|
-
},
|
|
172
|
-
queueSize: 4,
|
|
173
|
-
partSize: 5 * 1024 * 1024,
|
|
174
|
-
leavePartsOnError: false
|
|
175
|
-
}).done();
|
|
176
|
-
const headResponse = await this.client.send(new HeadObjectCommand({
|
|
177
|
-
Bucket: this.bucket,
|
|
178
|
-
Key: path
|
|
179
|
-
}));
|
|
180
|
-
return {
|
|
181
|
-
path,
|
|
182
|
-
disk: this.disk,
|
|
183
|
-
fullPath: `${this.bucket}/${path}`,
|
|
184
|
-
size: headResponse.ContentLength ?? options.size ?? 0,
|
|
185
|
-
mimeType: options.mimeType ?? "application/octet-stream",
|
|
186
|
-
uploadedAt: /* @__PURE__ */ new Date()
|
|
187
|
-
};
|
|
188
|
-
}
|
|
189
|
-
/**
|
|
190
|
-
* Get the bucket name
|
|
191
|
-
*/
|
|
192
|
-
getBucket() {
|
|
193
|
-
return this.bucket;
|
|
194
|
-
}
|
|
195
|
-
/**
|
|
196
|
-
* Get object metadata without downloading the body
|
|
197
|
-
*/
|
|
198
|
-
async headObject(key) {
|
|
199
|
-
const response = await this.client.send(new HeadObjectCommand({
|
|
200
|
-
Bucket: this.bucket,
|
|
201
|
-
Key: key
|
|
202
|
-
}));
|
|
203
|
-
return {
|
|
204
|
-
size: response.ContentLength ?? 0,
|
|
205
|
-
contentType: response.ContentType,
|
|
206
|
-
metadata: response.Metadata
|
|
207
|
-
};
|
|
208
|
-
}
|
|
209
|
-
/**
|
|
210
|
-
* Delete multiple objects in a single request
|
|
211
|
-
*/
|
|
212
|
-
async deleteObjects(keys) {
|
|
213
|
-
if (keys.length === 0) return {
|
|
214
|
-
deleted: 0,
|
|
215
|
-
errors: []
|
|
216
|
-
};
|
|
217
|
-
const response = await this.client.send(new DeleteObjectsCommand({
|
|
218
|
-
Bucket: this.bucket,
|
|
219
|
-
Delete: { Objects: keys.map((key) => ({ Key: key })) }
|
|
220
|
-
}));
|
|
221
|
-
return {
|
|
222
|
-
deleted: response.Deleted?.length ?? 0,
|
|
223
|
-
errors: (response.Errors ?? []).map((e) => ({
|
|
224
|
-
key: e.Key ?? "",
|
|
225
|
-
code: e.Code ?? "Unknown",
|
|
226
|
-
message: e.Message ?? "Unknown error"
|
|
227
|
-
}))
|
|
228
|
-
};
|
|
229
|
-
}
|
|
230
|
-
/**
|
|
231
|
-
* Create a multipart upload
|
|
232
|
-
*/
|
|
233
|
-
async createMultipartUpload(key, options) {
|
|
234
|
-
const response = await this.client.send(new CreateMultipartUploadCommand({
|
|
235
|
-
Bucket: this.bucket,
|
|
236
|
-
Key: key,
|
|
237
|
-
ContentType: options?.contentType,
|
|
238
|
-
CacheControl: options?.cacheControl,
|
|
239
|
-
Metadata: options?.metadata,
|
|
240
|
-
Tagging: options?.tagging
|
|
241
|
-
}));
|
|
242
|
-
return {
|
|
243
|
-
uploadId: response.UploadId ?? "",
|
|
244
|
-
key: response.Key ?? ""
|
|
245
|
-
};
|
|
246
|
-
}
|
|
247
|
-
/**
|
|
248
|
-
* Upload a part to an existing multipart upload
|
|
249
|
-
*/
|
|
250
|
-
async uploadPart(key, uploadId, partNumber, body) {
|
|
251
|
-
return {
|
|
252
|
-
etag: (await this.client.send(new UploadPartCommand({
|
|
253
|
-
Bucket: this.bucket,
|
|
254
|
-
Key: key,
|
|
255
|
-
UploadId: uploadId,
|
|
256
|
-
PartNumber: partNumber,
|
|
257
|
-
Body: body,
|
|
258
|
-
ContentLength: body.length
|
|
259
|
-
}))).ETag ?? "",
|
|
260
|
-
partNumber
|
|
261
|
-
};
|
|
262
|
-
}
|
|
263
|
-
/**
|
|
264
|
-
* Complete a multipart upload
|
|
265
|
-
*/
|
|
266
|
-
async completeMultipartUpload(key, uploadId, parts) {
|
|
267
|
-
const response = await this.client.send(new CompleteMultipartUploadCommand({
|
|
268
|
-
Bucket: this.bucket,
|
|
269
|
-
Key: key,
|
|
270
|
-
UploadId: uploadId,
|
|
271
|
-
MultipartUpload: { Parts: parts.map((p) => ({
|
|
272
|
-
ETag: p.etag,
|
|
273
|
-
PartNumber: p.partNumber
|
|
274
|
-
})) }
|
|
275
|
-
}));
|
|
276
|
-
return {
|
|
277
|
-
location: response.Location,
|
|
278
|
-
key: response.Key ?? ""
|
|
279
|
-
};
|
|
280
|
-
}
|
|
281
|
-
/**
|
|
282
|
-
* Abort a multipart upload
|
|
283
|
-
*/
|
|
284
|
-
async abortMultipartUpload(key, uploadId) {
|
|
285
|
-
await this.client.send(new AbortMultipartUploadCommand({
|
|
286
|
-
Bucket: this.bucket,
|
|
287
|
-
Key: key,
|
|
288
|
-
UploadId: uploadId
|
|
289
|
-
}));
|
|
290
|
-
}
|
|
291
|
-
/**
|
|
292
|
-
* List parts of a multipart upload
|
|
293
|
-
*/
|
|
294
|
-
async listParts(key, uploadId, partNumberMarker) {
|
|
295
|
-
const response = await this.client.send(new ListPartsCommand({
|
|
296
|
-
Bucket: this.bucket,
|
|
297
|
-
Key: key,
|
|
298
|
-
UploadId: uploadId,
|
|
299
|
-
PartNumberMarker: partNumberMarker
|
|
300
|
-
}));
|
|
301
|
-
return {
|
|
302
|
-
parts: (response.Parts ?? []).map((p) => ({
|
|
303
|
-
partNumber: p.PartNumber ?? 0,
|
|
304
|
-
etag: p.ETag ?? "",
|
|
305
|
-
size: p.Size ?? 0
|
|
306
|
-
})),
|
|
307
|
-
isTruncated: response.IsTruncated ?? false,
|
|
308
|
-
nextPartNumberMarker: response.NextPartNumberMarker?.toString()
|
|
309
|
-
};
|
|
310
|
-
}
|
|
311
|
-
/**
|
|
312
|
-
* List all in-progress multipart uploads
|
|
313
|
-
*/
|
|
314
|
-
async listMultipartUploads(keyMarker, uploadIdMarker) {
|
|
315
|
-
const response = await this.client.send(new ListMultipartUploadsCommand({
|
|
316
|
-
Bucket: this.bucket,
|
|
317
|
-
KeyMarker: keyMarker,
|
|
318
|
-
UploadIdMarker: uploadIdMarker
|
|
319
|
-
}));
|
|
320
|
-
return {
|
|
321
|
-
uploads: (response.Uploads ?? []).map((u) => ({
|
|
322
|
-
key: u.Key ?? "",
|
|
323
|
-
uploadId: u.UploadId ?? "",
|
|
324
|
-
initiated: u.Initiated
|
|
325
|
-
})),
|
|
326
|
-
isTruncated: response.IsTruncated ?? false,
|
|
327
|
-
nextKeyMarker: response.NextKeyMarker,
|
|
328
|
-
nextUploadIdMarker: response.NextUploadIdMarker
|
|
329
|
-
};
|
|
330
|
-
}
|
|
331
|
-
};
|
|
332
|
-
//#endregion
|
|
333
|
-
export { s3_storage_provider_exports as n, S3StorageProvider as t };
|
|
334
|
-
|
|
335
|
-
//# sourceMappingURL=s3-storage.provider-CttzNnDR.mjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"s3-storage.provider-CttzNnDR.mjs","names":[],"sources":["../src/storage/dom.polyfill.ts","../src/storage/providers/s3-storage.provider.ts"],"sourcesContent":["/**\n * DOM polyfills for Cloudflare Workers\n *\n * AWS SDK v3 uses DOMParser and Node for XML parsing, which are not available in Workers.\n * This module must be imported BEFORE any AWS SDK imports (including transitive).\n *\n * @see https://github.com/aws/aws-sdk-js-v3/issues/7375\n */\nimport { DOMParser } from '@xmldom/xmldom'\n\n// DOMParser polyfill for XML response parsing\nglobalThis.DOMParser = DOMParser\n\n// Node interface polyfill with DOM node type constants\n// Required by AWS SDK for XML response parsing\nif (typeof globalThis.Node === 'undefined') {\n globalThis.Node = {\n ELEMENT_NODE: 1,\n ATTRIBUTE_NODE: 2,\n TEXT_NODE: 3,\n CDATA_SECTION_NODE: 4,\n ENTITY_REFERENCE_NODE: 5,\n ENTITY_NODE: 6,\n PROCESSING_INSTRUCTION_NODE: 7,\n COMMENT_NODE: 8,\n DOCUMENT_NODE: 9,\n DOCUMENT_TYPE_NODE: 10,\n DOCUMENT_FRAGMENT_NODE: 11,\n NOTATION_NODE: 12,\n } as unknown as typeof Node\n}\n","import '../dom.polyfill'\n\nimport {\n AbortMultipartUploadCommand,\n CompleteMultipartUploadCommand,\n CreateMultipartUploadCommand,\n DeleteObjectCommand,\n DeleteObjectsCommand,\n GetObjectCommand,\n HeadObjectCommand,\n ListMultipartUploadsCommand,\n ListPartsCommand,\n PutObjectCommand,\n S3Client,\n UploadPartCommand\n} from '@aws-sdk/client-s3'\nimport { Upload } from '@aws-sdk/lib-storage'\nimport { getSignedUrl } from '@aws-sdk/s3-request-presigner'\nimport type { StorageEntry } from '../types'\nimport type { DownloadResult, PresignedUrlResult, UploadOptions, UploadResult } from '../contracts'\nimport { StorageResponseBodyMissingError } from '../errors'\nimport type {\n CompletedPart,\n CompleteMultipartResult,\n CreateMultipartOptions,\n CreateMultipartResult,\n DeleteObjectsResult,\n HeadObjectResult,\n IS3MultipartProvider,\n ListMultipartUploadsResult,\n ListPartsResult,\n UploadPartResult,\n} from './s3-multipart-provider.interface'\nimport type { StreamingBlobPayloadInputTypes } from './storage-provider.interface'\n\n/**\n * S3 Storage Provider\n * Implements storage operations using AWS SDK for S3-compatible storage\n * Works with AWS S3, Cloudflare R2, MinIO, and other S3-compatible services\n *\n * Implements IS3MultipartProvider for multipart upload support needed by TUS\n */\nexport class S3StorageProvider implements IS3MultipartProvider {\n private readonly client: S3Client\n private readonly bucket: string\n private readonly disk: string\n\n constructor(config: StorageEntry) {\n // Configure S3Client for S3-compatible storage\n this.client = new S3Client({\n region: config.region || 'auto',\n endpoint: config.endpoint,\n credentials: {\n accessKeyId: config.accessKeyId,\n secretAccessKey: config.secretAccessKey,\n },\n forcePathStyle: true,\n })\n\n this.bucket = config.bucket\n this.disk = config.disk\n }\n\n async upload(\n body: StreamingBlobPayloadInputTypes,\n path: string,\n options: UploadOptions\n ): Promise<UploadResult> {\n const command = new PutObjectCommand({\n Bucket: this.bucket,\n Key: path,\n Body: body,\n ContentType: options.mimeType,\n ContentLength: options.size,\n Metadata: options.metadata,\n Tagging: options.tagging,\n })\n\n await this.client.send(command)\n\n return {\n path,\n disk: this.disk,\n fullPath: `${this.bucket}/${path}`,\n size: options.size,\n mimeType: options.mimeType ?? 'application/octet-stream',\n uploadedAt: new Date(),\n }\n }\n\n async download(path: string): Promise<DownloadResult> {\n const command = new GetObjectCommand({\n Bucket: this.bucket,\n Key: path,\n })\n\n const response = await this.client.send(command)\n\n if (!response.Body) {\n throw new StorageResponseBodyMissingError(path)\n }\n\n return {\n toStream: () => response.Body?.transformToWebStream(),\n contentType: response.ContentType ?? 'application/octet-stream',\n size: response.ContentLength ?? 0,\n metadata: response.Metadata,\n toString: () => response.Body?.transformToString(),\n toArrayBuffer: () => response.Body?.transformToByteArray(),\n }\n }\n\n async delete(path: string): Promise<void> {\n const command = new DeleteObjectCommand({\n Bucket: this.bucket,\n Key: path,\n })\n\n await this.client.send(command)\n }\n\n async exists(path: string): Promise<boolean> {\n try {\n const command = new HeadObjectCommand({\n Bucket: this.bucket,\n Key: path,\n })\n\n await this.client.send(command)\n return true\n } catch {\n // HeadObject throws error if file doesn't exist\n return false\n }\n }\n\n async getPresignedUrl(\n path: string,\n method: 'GET' | 'PUT' | 'DELETE' | 'HEAD',\n expiresIn: number\n ): Promise<PresignedUrlResult> {\n // Select appropriate command based on method\n let command\n switch (method) {\n case 'GET':\n command = new GetObjectCommand({ Bucket: this.bucket, Key: path })\n break\n case 'PUT':\n command = new PutObjectCommand({ Bucket: this.bucket, Key: path })\n break\n case 'DELETE':\n command = new DeleteObjectCommand({ Bucket: this.bucket, Key: path })\n break\n case 'HEAD':\n command = new HeadObjectCommand({ Bucket: this.bucket, Key: path })\n break\n }\n\n const url = await getSignedUrl(this.client, command as GetObjectCommand, { expiresIn })\n\n return {\n url,\n expiresIn,\n expiresAt: new Date(Date.now() + expiresIn * 1000),\n method,\n }\n }\n\n /**\n * Chunked upload for streaming data without known size\n * Uses @aws-sdk/lib-storage for multipart upload handling\n *\n * Benefits:\n * - Handles unknown Content-Length automatically\n * - Automatic retry on transient failures\n * - Cleanup of partial uploads on error\n * - Works with S3-compatible storage (R2, MinIO, RustFS)\n *\n * @param body - Content to upload (stream or buffer)\n * @param path - Full path including disk root\n * @param options - Upload options (mimeType required, size optional)\n * @returns Upload result with metadata\n */\n async chunkedUpload(\n body: StreamingBlobPayloadInputTypes,\n path: string,\n options: Omit<UploadOptions, 'size'> & { size?: number }\n ): Promise<UploadResult> {\n const upload = new Upload({\n client: this.client,\n params: {\n Bucket: this.bucket,\n Key: path,\n Body: body,\n ContentType: options.mimeType,\n },\n // Concurrency configuration\n queueSize: 4,\n // Part size: 5MB minimum for S3\n partSize: 5 * 1024 * 1024,\n // Don't leave orphaned parts on error\n leavePartsOnError: false,\n })\n\n await upload.done()\n\n // Get the actual uploaded size via HeadObject\n const headResponse = await this.client.send(\n new HeadObjectCommand({\n Bucket: this.bucket,\n Key: path,\n })\n )\n\n return {\n path,\n disk: this.disk,\n fullPath: `${this.bucket}/${path}`,\n size: headResponse.ContentLength ?? options.size ?? 0,\n mimeType: options.mimeType ?? 'application/octet-stream',\n uploadedAt: new Date(),\n }\n }\n\n // ============================================\n // IS3MultipartProvider - Multipart upload methods\n // ============================================\n\n /**\n * Get the bucket name\n */\n getBucket(): string {\n return this.bucket\n }\n\n /**\n * Get object metadata without downloading the body\n */\n async headObject(key: string): Promise<HeadObjectResult | null> {\n const response = await this.client.send(\n new HeadObjectCommand({\n Bucket: this.bucket,\n Key: key,\n })\n )\n return {\n size: response.ContentLength ?? 0,\n contentType: response.ContentType,\n metadata: response.Metadata,\n }\n }\n\n /**\n * Delete multiple objects in a single request\n */\n async deleteObjects(keys: string[]): Promise<DeleteObjectsResult> {\n if (keys.length === 0) {\n return { deleted: 0, errors: [] }\n }\n\n const response = await this.client.send(\n new DeleteObjectsCommand({\n Bucket: this.bucket,\n Delete: {\n Objects: keys.map((key) => ({ Key: key })),\n },\n })\n )\n\n return {\n deleted: response.Deleted?.length ?? 0,\n errors: (response.Errors ?? []).map((e) => ({\n key: e.Key ?? '',\n code: e.Code ?? 'Unknown',\n message: e.Message ?? 'Unknown error',\n })),\n }\n }\n\n /**\n * Create a multipart upload\n */\n async createMultipartUpload(\n key: string,\n options?: CreateMultipartOptions\n ): Promise<CreateMultipartResult> {\n const response = await this.client.send(\n new CreateMultipartUploadCommand({\n Bucket: this.bucket,\n Key: key,\n ContentType: options?.contentType,\n CacheControl: options?.cacheControl,\n Metadata: options?.metadata,\n Tagging: options?.tagging,\n })\n )\n\n return {\n uploadId: response.UploadId ?? '',\n key: response.Key ?? '',\n }\n }\n\n /**\n * Upload a part to an existing multipart upload\n */\n async uploadPart(\n key: string,\n uploadId: string,\n partNumber: number,\n body: Uint8Array\n ): Promise<UploadPartResult> {\n const response = await this.client.send(\n new UploadPartCommand({\n Bucket: this.bucket,\n Key: key,\n UploadId: uploadId,\n PartNumber: partNumber,\n Body: body,\n ContentLength: body.length,\n })\n )\n\n return {\n etag: response.ETag ?? '',\n partNumber,\n }\n }\n\n /**\n * Complete a multipart upload\n */\n async completeMultipartUpload(\n key: string,\n uploadId: string,\n parts: CompletedPart[]\n ): Promise<CompleteMultipartResult> {\n const response = await this.client.send(\n new CompleteMultipartUploadCommand({\n Bucket: this.bucket,\n Key: key,\n UploadId: uploadId,\n MultipartUpload: {\n Parts: parts.map((p) => ({\n ETag: p.etag,\n PartNumber: p.partNumber,\n })),\n },\n })\n )\n\n return {\n location: response.Location,\n key: response.Key ?? '',\n }\n }\n\n /**\n * Abort a multipart upload\n */\n async abortMultipartUpload(key: string, uploadId: string): Promise<void> {\n await this.client.send(\n new AbortMultipartUploadCommand({\n Bucket: this.bucket,\n Key: key,\n UploadId: uploadId,\n })\n )\n }\n\n /**\n * List parts of a multipart upload\n */\n async listParts(\n key: string,\n uploadId: string,\n partNumberMarker?: string\n ): Promise<ListPartsResult> {\n const response = await this.client.send(\n new ListPartsCommand({\n Bucket: this.bucket,\n Key: key,\n UploadId: uploadId,\n PartNumberMarker: partNumberMarker,\n })\n )\n\n return {\n parts: (response.Parts ?? []).map((p) => ({\n partNumber: p.PartNumber ?? 0,\n etag: p.ETag ?? '',\n size: p.Size ?? 0,\n })),\n isTruncated: response.IsTruncated ?? false,\n nextPartNumberMarker: response.NextPartNumberMarker?.toString(),\n }\n }\n\n /**\n * List all in-progress multipart uploads\n */\n async listMultipartUploads(\n keyMarker?: string,\n uploadIdMarker?: string\n ): Promise<ListMultipartUploadsResult> {\n const response = await this.client.send(\n new ListMultipartUploadsCommand({\n Bucket: this.bucket,\n KeyMarker: keyMarker,\n UploadIdMarker: uploadIdMarker,\n })\n )\n\n return {\n uploads: (response.Uploads ?? []).map((u) => ({\n key: u.Key ?? '',\n uploadId: u.UploadId ?? '',\n initiated: u.Initiated,\n })),\n isTruncated: response.IsTruncated ?? false,\n nextKeyMarker: response.NextKeyMarker,\n nextUploadIdMarker: response.NextUploadIdMarker,\n }\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;AAWA,WAAW,YAAY;AAIvB,IAAI,OAAO,WAAW,SAAS,YAC7B,YAAW,OAAO;CAChB,cAAc;CACd,gBAAgB;CAChB,WAAW;CACX,oBAAoB;CACpB,uBAAuB;CACvB,aAAa;CACb,6BAA6B;CAC7B,cAAc;CACd,eAAe;CACf,oBAAoB;CACpB,wBAAwB;CACxB,eAAe;CAChB;;;;;;;;;;;ACaH,IAAa,oBAAb,MAA+D;CAC7D;CACA;CACA;CAEA,YAAY,QAAsB;AAEhC,OAAK,SAAS,IAAI,SAAS;GACzB,QAAQ,OAAO,UAAU;GACzB,UAAU,OAAO;GACjB,aAAa;IACX,aAAa,OAAO;IACpB,iBAAiB,OAAO;IACzB;GACD,gBAAgB;GACjB,CAAC;AAEF,OAAK,SAAS,OAAO;AACrB,OAAK,OAAO,OAAO;;CAGrB,MAAM,OACJ,MACA,MACA,SACuB;EACvB,MAAM,UAAU,IAAI,iBAAiB;GACnC,QAAQ,KAAK;GACb,KAAK;GACL,MAAM;GACN,aAAa,QAAQ;GACrB,eAAe,QAAQ;GACvB,UAAU,QAAQ;GAClB,SAAS,QAAQ;GAClB,CAAC;AAEF,QAAM,KAAK,OAAO,KAAK,QAAQ;AAE/B,SAAO;GACL;GACA,MAAM,KAAK;GACX,UAAU,GAAG,KAAK,OAAO,GAAG;GAC5B,MAAM,QAAQ;GACd,UAAU,QAAQ,YAAY;GAC9B,4BAAY,IAAI,MAAM;GACvB;;CAGH,MAAM,SAAS,MAAuC;EACpD,MAAM,UAAU,IAAI,iBAAiB;GACnC,QAAQ,KAAK;GACb,KAAK;GACN,CAAC;EAEF,MAAM,WAAW,MAAM,KAAK,OAAO,KAAK,QAAQ;AAEhD,MAAI,CAAC,SAAS,KACZ,OAAM,IAAI,gCAAgC,KAAK;AAGjD,SAAO;GACL,gBAAgB,SAAS,MAAM,sBAAsB;GACrD,aAAa,SAAS,eAAe;GACrC,MAAM,SAAS,iBAAiB;GAChC,UAAU,SAAS;GACnB,gBAAgB,SAAS,MAAM,mBAAmB;GAClD,qBAAqB,SAAS,MAAM,sBAAsB;GAC3D;;CAGH,MAAM,OAAO,MAA6B;EACxC,MAAM,UAAU,IAAI,oBAAoB;GACtC,QAAQ,KAAK;GACb,KAAK;GACN,CAAC;AAEF,QAAM,KAAK,OAAO,KAAK,QAAQ;;CAGjC,MAAM,OAAO,MAAgC;AAC3C,MAAI;GACF,MAAM,UAAU,IAAI,kBAAkB;IACpC,QAAQ,KAAK;IACb,KAAK;IACN,CAAC;AAEF,SAAM,KAAK,OAAO,KAAK,QAAQ;AAC/B,UAAO;UACD;AAEN,UAAO;;;CAIX,MAAM,gBACJ,MACA,QACA,WAC6B;EAE7B,IAAI;AACJ,UAAQ,QAAR;GACE,KAAK;AACH,cAAU,IAAI,iBAAiB;KAAE,QAAQ,KAAK;KAAQ,KAAK;KAAM,CAAC;AAClE;GACF,KAAK;AACH,cAAU,IAAI,iBAAiB;KAAE,QAAQ,KAAK;KAAQ,KAAK;KAAM,CAAC;AAClE;GACF,KAAK;AACH,cAAU,IAAI,oBAAoB;KAAE,QAAQ,KAAK;KAAQ,KAAK;KAAM,CAAC;AACrE;GACF,KAAK;AACH,cAAU,IAAI,kBAAkB;KAAE,QAAQ,KAAK;KAAQ,KAAK;KAAM,CAAC;AACnE;;AAKJ,SAAO;GACL,KAHU,MAAM,aAAa,KAAK,QAAQ,SAA6B,EAAE,WAAW,CAAC;GAIrF;GACA,WAAW,IAAI,KAAK,KAAK,KAAK,GAAG,YAAY,IAAK;GAClD;GACD;;;;;;;;;;;;;;;;;CAkBH,MAAM,cACJ,MACA,MACA,SACuB;AAiBvB,QAhBe,IAAI,OAAO;GACxB,QAAQ,KAAK;GACb,QAAQ;IACN,QAAQ,KAAK;IACb,KAAK;IACL,MAAM;IACN,aAAa,QAAQ;IACtB;GAED,WAAW;GAEX,UAAU,IAAI,OAAO;GAErB,mBAAmB;GACpB,CAAC,CAEW,MAAM;EAGnB,MAAM,eAAe,MAAM,KAAK,OAAO,KACrC,IAAI,kBAAkB;GACpB,QAAQ,KAAK;GACb,KAAK;GACN,CAAC,CACH;AAED,SAAO;GACL;GACA,MAAM,KAAK;GACX,UAAU,GAAG,KAAK,OAAO,GAAG;GAC5B,MAAM,aAAa,iBAAiB,QAAQ,QAAQ;GACpD,UAAU,QAAQ,YAAY;GAC9B,4BAAY,IAAI,MAAM;GACvB;;;;;CAUH,YAAoB;AAClB,SAAO,KAAK;;;;;CAMd,MAAM,WAAW,KAA+C;EAC9D,MAAM,WAAW,MAAM,KAAK,OAAO,KACjC,IAAI,kBAAkB;GACpB,QAAQ,KAAK;GACb,KAAK;GACN,CAAC,CACH;AACD,SAAO;GACL,MAAM,SAAS,iBAAiB;GAChC,aAAa,SAAS;GACtB,UAAU,SAAS;GACpB;;;;;CAMH,MAAM,cAAc,MAA8C;AAChE,MAAI,KAAK,WAAW,EAClB,QAAO;GAAE,SAAS;GAAG,QAAQ,EAAE;GAAE;EAGnC,MAAM,WAAW,MAAM,KAAK,OAAO,KACjC,IAAI,qBAAqB;GACvB,QAAQ,KAAK;GACb,QAAQ,EACN,SAAS,KAAK,KAAK,SAAS,EAAE,KAAK,KAAK,EAAE,EAC3C;GACF,CAAC,CACH;AAED,SAAO;GACL,SAAS,SAAS,SAAS,UAAU;GACrC,SAAS,SAAS,UAAU,EAAE,EAAE,KAAK,OAAO;IAC1C,KAAK,EAAE,OAAO;IACd,MAAM,EAAE,QAAQ;IAChB,SAAS,EAAE,WAAW;IACvB,EAAE;GACJ;;;;;CAMH,MAAM,sBACJ,KACA,SACgC;EAChC,MAAM,WAAW,MAAM,KAAK,OAAO,KACjC,IAAI,6BAA6B;GAC/B,QAAQ,KAAK;GACb,KAAK;GACL,aAAa,SAAS;GACtB,cAAc,SAAS;GACvB,UAAU,SAAS;GACnB,SAAS,SAAS;GACnB,CAAC,CACH;AAED,SAAO;GACL,UAAU,SAAS,YAAY;GAC/B,KAAK,SAAS,OAAO;GACtB;;;;;CAMH,MAAM,WACJ,KACA,UACA,YACA,MAC2B;AAY3B,SAAO;GACL,OAZe,MAAM,KAAK,OAAO,KACjC,IAAI,kBAAkB;IACpB,QAAQ,KAAK;IACb,KAAK;IACL,UAAU;IACV,YAAY;IACZ,MAAM;IACN,eAAe,KAAK;IACrB,CAAC,CACH,EAGgB,QAAQ;GACvB;GACD;;;;;CAMH,MAAM,wBACJ,KACA,UACA,OACkC;EAClC,MAAM,WAAW,MAAM,KAAK,OAAO,KACjC,IAAI,+BAA+B;GACjC,QAAQ,KAAK;GACb,KAAK;GACL,UAAU;GACV,iBAAiB,EACf,OAAO,MAAM,KAAK,OAAO;IACvB,MAAM,EAAE;IACR,YAAY,EAAE;IACf,EAAE,EACJ;GACF,CAAC,CACH;AAED,SAAO;GACL,UAAU,SAAS;GACnB,KAAK,SAAS,OAAO;GACtB;;;;;CAMH,MAAM,qBAAqB,KAAa,UAAiC;AACvE,QAAM,KAAK,OAAO,KAChB,IAAI,4BAA4B;GAC9B,QAAQ,KAAK;GACb,KAAK;GACL,UAAU;GACX,CAAC,CACH;;;;;CAMH,MAAM,UACJ,KACA,UACA,kBAC0B;EAC1B,MAAM,WAAW,MAAM,KAAK,OAAO,KACjC,IAAI,iBAAiB;GACnB,QAAQ,KAAK;GACb,KAAK;GACL,UAAU;GACV,kBAAkB;GACnB,CAAC,CACH;AAED,SAAO;GACL,QAAQ,SAAS,SAAS,EAAE,EAAE,KAAK,OAAO;IACxC,YAAY,EAAE,cAAc;IAC5B,MAAM,EAAE,QAAQ;IAChB,MAAM,EAAE,QAAQ;IACjB,EAAE;GACH,aAAa,SAAS,eAAe;GACrC,sBAAsB,SAAS,sBAAsB,UAAU;GAChE;;;;;CAMH,MAAM,qBACJ,WACA,gBACqC;EACrC,MAAM,WAAW,MAAM,KAAK,OAAO,KACjC,IAAI,4BAA4B;GAC9B,QAAQ,KAAK;GACb,WAAW;GACX,gBAAgB;GACjB,CAAC,CACH;AAED,SAAO;GACL,UAAU,SAAS,WAAW,EAAE,EAAE,KAAK,OAAO;IAC5C,KAAK,EAAE,OAAO;IACd,UAAU,EAAE,YAAY;IACxB,WAAW,EAAE;IACd,EAAE;GACH,aAAa,SAAS,eAAe;GACrC,eAAe,SAAS;GACxB,oBAAoB,SAAS;GAC9B"}
|