storybooker 0.19.3 → 0.22.0-canary.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/README.md +40 -18
- package/dist/adapters/_internal/queue.d.mts +127 -0
- package/dist/aws-dynamodb.d.mts +22 -0
- package/dist/aws-dynamodb.mjs +118 -0
- package/dist/aws-dynamodb.mjs.map +1 -0
- package/dist/aws-s3.d.mts +20 -0
- package/dist/aws-s3.mjs +96 -0
- package/dist/aws-s3.mjs.map +1 -0
- package/dist/azure-blob-storage.d.mts +20 -0
- package/dist/azure-blob-storage.mjs +126 -0
- package/dist/azure-blob-storage.mjs.map +1 -0
- package/dist/azure-cosmos-db.d.mts +23 -0
- package/dist/azure-cosmos-db.mjs +87 -0
- package/dist/azure-cosmos-db.mjs.map +1 -0
- package/dist/azure-data-tables.d.mts +23 -0
- package/dist/azure-data-tables.mjs +127 -0
- package/dist/azure-data-tables.mjs.map +1 -0
- package/dist/azure-easy-auth.d.mts +50 -0
- package/dist/azure-easy-auth.mjs +88 -0
- package/dist/azure-easy-auth.mjs.map +1 -0
- package/dist/azure-functions.d.mts +62 -0
- package/dist/azure-functions.mjs +147 -0
- package/dist/azure-functions.mjs.map +1 -0
- package/dist/fs.d.mts +37 -0
- package/dist/fs.mjs +240 -0
- package/dist/fs.mjs.map +1 -0
- package/dist/gcp-big-table.d.mts +23 -0
- package/dist/gcp-big-table.mjs +92 -0
- package/dist/gcp-big-table.mjs.map +1 -0
- package/dist/gcp-firestore.d.mts +22 -0
- package/dist/gcp-firestore.mjs +87 -0
- package/dist/gcp-firestore.mjs.map +1 -0
- package/dist/gcp-storage.d.mts +20 -0
- package/dist/gcp-storage.mjs +96 -0
- package/dist/gcp-storage.mjs.map +1 -0
- package/dist/handlers/handle-process-zip.mjs +90 -0
- package/dist/handlers/handle-process-zip.mjs.map +1 -0
- package/dist/handlers/handle-purge.d.mts +12 -0
- package/dist/handlers/handle-purge.mjs +36 -0
- package/dist/handlers/handle-purge.mjs.map +1 -0
- package/dist/handlers/handle-serve-storybook.mjs +94 -0
- package/dist/handlers/handle-serve-storybook.mjs.map +1 -0
- package/dist/index.d.mts +28 -0
- package/dist/index.mjs +62 -0
- package/dist/index.mjs.map +1 -0
- package/dist/models/builds-model.mjs +248 -0
- package/dist/models/builds-model.mjs.map +1 -0
- package/dist/models/builds-schema.d.mts +171 -0
- package/dist/models/builds-schema.mjs +67 -0
- package/dist/models/builds-schema.mjs.map +1 -0
- package/dist/models/projects-model.mjs +122 -0
- package/dist/models/projects-model.mjs.map +1 -0
- package/dist/models/projects-schema.d.mts +70 -0
- package/dist/models/projects-schema.mjs +37 -0
- package/dist/models/projects-schema.mjs.map +1 -0
- package/dist/models/tags-model.mjs +110 -0
- package/dist/models/tags-model.mjs.map +1 -0
- package/dist/models/tags-schema.d.mts +76 -0
- package/dist/models/tags-schema.mjs +34 -0
- package/dist/models/tags-schema.mjs.map +1 -0
- package/dist/models/~model.mjs +43 -0
- package/dist/models/~model.mjs.map +1 -0
- package/dist/models/~shared-schema.d.mts +1 -0
- package/dist/models/~shared-schema.mjs +20 -0
- package/dist/models/~shared-schema.mjs.map +1 -0
- package/dist/mysql.d.mts +39 -0
- package/dist/mysql.mjs +151 -0
- package/dist/mysql.mjs.map +1 -0
- package/dist/redis.d.mts +33 -0
- package/dist/redis.mjs +118 -0
- package/dist/redis.mjs.map +1 -0
- package/dist/routers/account-router.mjs +91 -0
- package/dist/routers/account-router.mjs.map +1 -0
- package/dist/routers/builds-router.mjs +347 -0
- package/dist/routers/builds-router.mjs.map +1 -0
- package/dist/routers/projects-router.mjs +236 -0
- package/dist/routers/projects-router.mjs.map +1 -0
- package/dist/routers/root-router.mjs +108 -0
- package/dist/routers/root-router.mjs.map +1 -0
- package/dist/routers/tags-router.mjs +269 -0
- package/dist/routers/tags-router.mjs.map +1 -0
- package/dist/routers/tasks-router.mjs +71 -0
- package/dist/routers/tasks-router.mjs.map +1 -0
- package/dist/urls.d.mts +47 -0
- package/dist/urls.mjs +208 -0
- package/dist/urls.mjs.map +1 -0
- package/dist/utils/adapter-utils.d.mts +14 -0
- package/dist/utils/adapter-utils.mjs +14 -0
- package/dist/utils/adapter-utils.mjs.map +1 -0
- package/dist/utils/auth.mjs +25 -0
- package/dist/utils/auth.mjs.map +1 -0
- package/dist/utils/error.d.mts +21 -0
- package/dist/utils/error.mjs +109 -0
- package/dist/utils/error.mjs.map +1 -0
- package/dist/utils/file-utils.mjs +16 -0
- package/dist/utils/file-utils.mjs.map +1 -0
- package/dist/utils/openapi-utils.mjs +45 -0
- package/dist/utils/openapi-utils.mjs.map +1 -0
- package/dist/utils/request.mjs +35 -0
- package/dist/utils/request.mjs.map +1 -0
- package/dist/utils/response.mjs +24 -0
- package/dist/utils/response.mjs.map +1 -0
- package/dist/utils/store.mjs +54 -0
- package/dist/utils/store.mjs.map +1 -0
- package/dist/utils/ui-utils.mjs +38 -0
- package/dist/utils/ui-utils.mjs.map +1 -0
- package/dist/utils/url-utils.d.mts +10 -0
- package/dist/utils/url-utils.mjs +54 -0
- package/dist/utils/url-utils.mjs.map +1 -0
- package/dist/~internal/adapter/auth.d.mts +123 -0
- package/dist/~internal/adapter/auth.mjs +20 -0
- package/dist/~internal/adapter/auth.mjs.map +1 -0
- package/dist/~internal/adapter/database.d.mts +240 -0
- package/dist/~internal/adapter/database.mjs +63 -0
- package/dist/~internal/adapter/database.mjs.map +1 -0
- package/dist/~internal/adapter/logger.d.mts +34 -0
- package/dist/~internal/adapter/logger.mjs +13 -0
- package/dist/~internal/adapter/logger.mjs.map +1 -0
- package/dist/~internal/adapter/storage.d.mts +208 -0
- package/dist/~internal/adapter/storage.mjs +63 -0
- package/dist/~internal/adapter/storage.mjs.map +1 -0
- package/dist/~internal/adapter/ui.d.mts +109 -0
- package/dist/~internal/adapter/ui.mjs +1 -0
- package/dist/~internal/adapter.d.mts +8 -0
- package/dist/~internal/adapter.mjs +6 -0
- package/dist/~internal/constants.d.mts +24 -0
- package/dist/~internal/constants.mjs +32 -0
- package/dist/~internal/constants.mjs.map +1 -0
- package/dist/~internal/mimes.d.mts +449 -0
- package/dist/~internal/mimes.mjs +454 -0
- package/dist/~internal/mimes.mjs.map +1 -0
- package/dist/~internal/router.d.mts +1651 -0
- package/dist/~internal/router.mjs +39 -0
- package/dist/~internal/router.mjs.map +1 -0
- package/dist/~internal/types.d.mts +77 -0
- package/dist/~internal/types.mjs +1 -0
- package/dist/~internal/utils.d.mts +4 -0
- package/dist/~internal/utils.mjs +5 -0
- package/openapi.json +3162 -0
- package/package.json +148 -27
- package/src/adapters/_internal/auth.ts +135 -0
- package/src/adapters/_internal/database.ts +241 -0
- package/src/adapters/_internal/index.ts +8 -0
- package/src/adapters/_internal/logger.ts +41 -0
- package/src/adapters/_internal/queue.ts +151 -0
- package/src/adapters/_internal/storage.ts +197 -0
- package/src/adapters/_internal/ui.ts +103 -0
- package/src/adapters/aws-dynamodb.ts +201 -0
- package/src/adapters/aws-s3.ts +160 -0
- package/src/adapters/azure-blob-storage.ts +223 -0
- package/src/adapters/azure-cosmos-db.ts +158 -0
- package/src/adapters/azure-data-tables.ts +223 -0
- package/src/adapters/azure-easy-auth.ts +174 -0
- package/src/adapters/azure-functions.ts +242 -0
- package/src/adapters/fs.ts +398 -0
- package/src/adapters/gcp-big-table.ts +157 -0
- package/src/adapters/gcp-firestore.ts +146 -0
- package/src/adapters/gcp-storage.ts +141 -0
- package/src/adapters/mysql.ts +296 -0
- package/src/adapters/redis.ts +242 -0
- package/src/handlers/handle-process-zip.ts +117 -0
- package/src/handlers/handle-purge.ts +65 -0
- package/src/handlers/handle-serve-storybook.ts +101 -0
- package/src/index.ts +81 -16
- package/src/mocks/mock-auth-service.ts +51 -0
- package/src/mocks/mock-store.ts +26 -0
- package/src/models/builds-model.ts +373 -0
- package/src/models/builds-schema.ts +84 -0
- package/src/models/projects-model.ts +177 -0
- package/src/models/projects-schema.ts +69 -0
- package/src/models/tags-model.ts +138 -0
- package/src/models/tags-schema.ts +45 -0
- package/src/models/~model.ts +79 -0
- package/src/models/~shared-schema.ts +14 -0
- package/src/routers/_app-router.ts +57 -0
- package/src/routers/account-router.ts +136 -0
- package/src/routers/builds-router.ts +464 -0
- package/src/routers/projects-router.ts +309 -0
- package/src/routers/root-router.ts +127 -0
- package/src/routers/tags-router.ts +339 -0
- package/src/routers/tasks-router.ts +75 -0
- package/src/types.ts +107 -0
- package/src/urls.ts +327 -0
- package/src/utils/adapter-utils.ts +26 -0
- package/src/utils/auth.test.ts +71 -0
- package/src/utils/auth.ts +39 -0
- package/src/utils/constants.ts +31 -0
- package/src/utils/date-utils.ts +10 -0
- package/src/utils/error.test.ts +86 -0
- package/src/utils/error.ts +140 -0
- package/src/utils/file-utils.test.ts +65 -0
- package/src/utils/file-utils.ts +43 -0
- package/src/utils/index.ts +3 -0
- package/src/utils/mime-utils.ts +457 -0
- package/src/utils/openapi-utils.ts +49 -0
- package/src/utils/request.ts +97 -0
- package/src/utils/response.ts +20 -0
- package/src/utils/store.ts +85 -0
- package/src/utils/story-utils.ts +42 -0
- package/src/utils/text-utils.ts +10 -0
- package/src/utils/ui-utils.ts +57 -0
- package/src/utils/url-utils.ts +113 -0
- package/dist/index.js +0 -554
- package/src/commands/create.ts +0 -263
- package/src/commands/purge.ts +0 -70
- package/src/commands/test.ts +0 -42
- package/src/service-schema.d.ts +0 -2023
- package/src/utils/auth-utils.ts +0 -31
- package/src/utils/pkg-utils.ts +0 -37
- package/src/utils/sb-build.ts +0 -55
- package/src/utils/sb-test.ts +0 -115
- package/src/utils/schema-utils.ts +0 -123
- package/src/utils/stream-utils.ts +0 -72
- package/src/utils/types.ts +0 -4
- package/src/utils/zip.ts +0 -77
package/dist/urls.mjs
ADDED
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
import { getStore } from "./utils/store.mjs";
|
|
2
|
+
import { linkRoute, urlJoin } from "./utils/url-utils.mjs";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
|
|
5
|
+
//#region src/urls.ts
|
|
6
|
+
/**
|
|
7
|
+
* URL builder for the Storybooks router.
|
|
8
|
+
*/
|
|
9
|
+
var UrlBuilder = class {
|
|
10
|
+
#useStore;
|
|
11
|
+
constructor(useStore) {
|
|
12
|
+
this.#useStore = useStore;
|
|
13
|
+
}
|
|
14
|
+
get #baseUrl() {
|
|
15
|
+
if (!this.#useStore) return "";
|
|
16
|
+
return new URL(getStore().url).origin;
|
|
17
|
+
}
|
|
18
|
+
homepage() {
|
|
19
|
+
return linkRoute((client) => client.index.$url(), { baseUrl: this.#baseUrl });
|
|
20
|
+
}
|
|
21
|
+
openapi() {
|
|
22
|
+
return linkRoute((client) => client.openapi.$url(), { baseUrl: this.#baseUrl });
|
|
23
|
+
}
|
|
24
|
+
staticFile(filepath) {
|
|
25
|
+
return linkRoute((client) => client[":filepath{.+}"].$url({ param: { filepath } }), { baseUrl: this.#baseUrl });
|
|
26
|
+
}
|
|
27
|
+
account() {
|
|
28
|
+
return linkRoute((client) => client.account.$url(), { baseUrl: this.#baseUrl });
|
|
29
|
+
}
|
|
30
|
+
login(redirect) {
|
|
31
|
+
return linkRoute((client) => client.account.login.$url({ query: { redirect } }), { baseUrl: this.#baseUrl });
|
|
32
|
+
}
|
|
33
|
+
logout() {
|
|
34
|
+
return linkRoute((client) => client.account.logout.$url(), { baseUrl: this.#baseUrl });
|
|
35
|
+
}
|
|
36
|
+
projectsList() {
|
|
37
|
+
return linkRoute((client) => client.projects.$url(), { baseUrl: this.#baseUrl });
|
|
38
|
+
}
|
|
39
|
+
projectCreate() {
|
|
40
|
+
return linkRoute((client) => client.projects.create.$url(), { baseUrl: this.#baseUrl });
|
|
41
|
+
}
|
|
42
|
+
projectDetails(projectId) {
|
|
43
|
+
return linkRoute((client) => client.projects[":projectId"].$url({ param: { projectId } }), { baseUrl: this.#baseUrl });
|
|
44
|
+
}
|
|
45
|
+
projectUpdate(projectId) {
|
|
46
|
+
return linkRoute((client) => client.projects[":projectId"].update.$url({ param: { projectId } }), { baseUrl: this.#baseUrl });
|
|
47
|
+
}
|
|
48
|
+
projectDelete(projectId) {
|
|
49
|
+
return linkRoute((client) => client.projects[":projectId"].delete.$url({ param: { projectId } }), { baseUrl: this.#baseUrl });
|
|
50
|
+
}
|
|
51
|
+
buildsList(projectId) {
|
|
52
|
+
return linkRoute((client) => client.projects[":projectId"].builds.$url({ param: { projectId } }), { baseUrl: this.#baseUrl });
|
|
53
|
+
}
|
|
54
|
+
buildDetails(projectId, buildId) {
|
|
55
|
+
return linkRoute((client) => client.projects[":projectId"].builds[":buildId"].$url({ param: {
|
|
56
|
+
buildId,
|
|
57
|
+
projectId
|
|
58
|
+
} }), { baseUrl: this.#baseUrl });
|
|
59
|
+
}
|
|
60
|
+
buildCreate(projectId, tagId) {
|
|
61
|
+
return linkRoute((client) => client.projects[":projectId"].builds.create.$url({
|
|
62
|
+
param: { projectId },
|
|
63
|
+
query: { tagId }
|
|
64
|
+
}), { baseUrl: this.#baseUrl });
|
|
65
|
+
}
|
|
66
|
+
buildDelete(projectId, buildId) {
|
|
67
|
+
return linkRoute((client) => client.projects[":projectId"].builds[":buildId"].delete.$url({ param: {
|
|
68
|
+
projectId,
|
|
69
|
+
buildId
|
|
70
|
+
} }), { baseUrl: this.#baseUrl });
|
|
71
|
+
}
|
|
72
|
+
buildUpdate(projectId, buildId) {
|
|
73
|
+
return linkRoute((client) => client.projects[":projectId"].builds[":buildId"].update.$url({ param: {
|
|
74
|
+
projectId,
|
|
75
|
+
buildId
|
|
76
|
+
} }), { baseUrl: this.#baseUrl });
|
|
77
|
+
}
|
|
78
|
+
buildUpload(projectId, buildId, variant) {
|
|
79
|
+
return linkRoute((client) => client.projects[":projectId"].builds[":buildId"].upload.$url({
|
|
80
|
+
param: {
|
|
81
|
+
buildId,
|
|
82
|
+
projectId
|
|
83
|
+
},
|
|
84
|
+
query: { variant }
|
|
85
|
+
}), { baseUrl: this.#baseUrl });
|
|
86
|
+
}
|
|
87
|
+
tagsList(projectId, type) {
|
|
88
|
+
return linkRoute((client) => client.projects[":projectId"].tags.$url({
|
|
89
|
+
param: { projectId },
|
|
90
|
+
query: { type }
|
|
91
|
+
}), { baseUrl: this.#baseUrl });
|
|
92
|
+
}
|
|
93
|
+
tagCreate(projectId) {
|
|
94
|
+
return linkRoute((client) => client.projects[":projectId"].tags.create.$url({ param: { projectId } }), { baseUrl: this.#baseUrl });
|
|
95
|
+
}
|
|
96
|
+
tagDetails(projectId, tagId) {
|
|
97
|
+
return linkRoute((client) => client.projects[":projectId"].tags[":tagId"].$url({ param: {
|
|
98
|
+
projectId,
|
|
99
|
+
tagId
|
|
100
|
+
} }), { baseUrl: this.#baseUrl });
|
|
101
|
+
}
|
|
102
|
+
tagDelete(projectId, tagId) {
|
|
103
|
+
return linkRoute((client) => client.projects[":projectId"].tags[":tagId"].delete.$url({ param: {
|
|
104
|
+
projectId,
|
|
105
|
+
tagId
|
|
106
|
+
} }), { baseUrl: this.#baseUrl });
|
|
107
|
+
}
|
|
108
|
+
tagUpdate(projectId, tagId) {
|
|
109
|
+
return linkRoute((client) => client.projects[":projectId"].tags[":tagId"].update.$url({ param: {
|
|
110
|
+
projectId,
|
|
111
|
+
tagId
|
|
112
|
+
} }), { baseUrl: this.#baseUrl });
|
|
113
|
+
}
|
|
114
|
+
taskPurge(projectId) {
|
|
115
|
+
return linkRoute((client) => client.tasks.purge.$url({ query: { projectId } }), { baseUrl: this.#baseUrl });
|
|
116
|
+
}
|
|
117
|
+
taskProcessZip(projectId, buildId, variant) {
|
|
118
|
+
return linkRoute((client) => client.tasks["process-zip"].$url({ query: {
|
|
119
|
+
projectId,
|
|
120
|
+
buildId,
|
|
121
|
+
variant
|
|
122
|
+
} }), { baseUrl: this.#baseUrl });
|
|
123
|
+
}
|
|
124
|
+
storybookIndexHtml(projectId, buildId, storyId) {
|
|
125
|
+
return linkRoute((client) => client._[":projectId"][":buildId"][":filepath{.+}"].$url({
|
|
126
|
+
param: {
|
|
127
|
+
projectId,
|
|
128
|
+
buildId,
|
|
129
|
+
filepath: "storybook/index.html"
|
|
130
|
+
},
|
|
131
|
+
query: { path: storyId ? `/story/${storyId}` : void 0 }
|
|
132
|
+
}), { baseUrl: this.#baseUrl });
|
|
133
|
+
}
|
|
134
|
+
storybookIFrameHtml(projectId, buildId, storyId) {
|
|
135
|
+
return linkRoute((client) => client._[":projectId"][":buildId"][":filepath{.+}"].$url({
|
|
136
|
+
param: {
|
|
137
|
+
projectId,
|
|
138
|
+
buildId,
|
|
139
|
+
filepath: "storybook/iframe.html"
|
|
140
|
+
},
|
|
141
|
+
query: {
|
|
142
|
+
id: storyId,
|
|
143
|
+
viewMode: "story"
|
|
144
|
+
}
|
|
145
|
+
}), { baseUrl: this.#baseUrl });
|
|
146
|
+
}
|
|
147
|
+
storybookDownload(projectId, buildId) {
|
|
148
|
+
return linkRoute((client) => client._[":projectId"][":buildId"][":filepath{.+}"].$url({
|
|
149
|
+
param: {
|
|
150
|
+
projectId,
|
|
151
|
+
buildId,
|
|
152
|
+
filepath: "storybook.zip"
|
|
153
|
+
},
|
|
154
|
+
query: {}
|
|
155
|
+
}), { baseUrl: this.#baseUrl });
|
|
156
|
+
}
|
|
157
|
+
storybookTestReport(projectId, buildId) {
|
|
158
|
+
return linkRoute((client) => client._[":projectId"][":buildId"][":filepath{.+}"].$url({
|
|
159
|
+
param: {
|
|
160
|
+
projectId,
|
|
161
|
+
buildId,
|
|
162
|
+
filepath: "testReport/index.html"
|
|
163
|
+
},
|
|
164
|
+
query: {}
|
|
165
|
+
}), { baseUrl: this.#baseUrl });
|
|
166
|
+
}
|
|
167
|
+
storybookCoverage(projectId, buildId) {
|
|
168
|
+
return linkRoute((client) => client._[":projectId"][":buildId"][":filepath{.+}"].$url({
|
|
169
|
+
param: {
|
|
170
|
+
projectId,
|
|
171
|
+
buildId,
|
|
172
|
+
filepath: "coverage/index.html"
|
|
173
|
+
},
|
|
174
|
+
query: {}
|
|
175
|
+
}), { baseUrl: this.#baseUrl });
|
|
176
|
+
}
|
|
177
|
+
storybookScreenshot(projectId, buildId, ...filename) {
|
|
178
|
+
return linkRoute((client) => client._[":projectId"][":buildId"][":filepath{.+}"].$url({
|
|
179
|
+
param: {
|
|
180
|
+
projectId,
|
|
181
|
+
buildId,
|
|
182
|
+
filepath: path.posix.join("screenshots", ...filename)
|
|
183
|
+
},
|
|
184
|
+
query: {}
|
|
185
|
+
}), { baseUrl: this.#baseUrl });
|
|
186
|
+
}
|
|
187
|
+
storybookScreenshotsDownload(projectId, buildId) {
|
|
188
|
+
return linkRoute((client) => client._[":projectId"][":buildId"][":filepath{.+}"].$url({
|
|
189
|
+
param: {
|
|
190
|
+
projectId,
|
|
191
|
+
buildId,
|
|
192
|
+
filepath: "screenshots.zip"
|
|
193
|
+
},
|
|
194
|
+
query: {}
|
|
195
|
+
}), { baseUrl: this.#baseUrl });
|
|
196
|
+
}
|
|
197
|
+
gitHub(gitHubRepo, ...pathnames) {
|
|
198
|
+
return new URL(urlJoin(gitHubRepo, ...pathnames), "https://github.com").toString();
|
|
199
|
+
}
|
|
200
|
+
};
|
|
201
|
+
/** @private */
|
|
202
|
+
const urlBuilder = new UrlBuilder(true);
|
|
203
|
+
/** @private */
|
|
204
|
+
const urlBuilderWithoutStore = new UrlBuilder(false);
|
|
205
|
+
|
|
206
|
+
//#endregion
|
|
207
|
+
export { UrlBuilder, urlBuilder, urlBuilderWithoutStore };
|
|
208
|
+
//# sourceMappingURL=urls.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"urls.mjs","names":["#useStore","#baseUrl","urlBuilder: UrlBuilder","urlBuilderWithoutStore: UrlBuilder"],"sources":["../src/urls.ts"],"sourcesContent":["import path from \"node:path\";\nimport type { BuildUploadVariant } from \"./models/builds-schema.ts\";\nimport type { TagVariant } from \"./models/tags-schema.ts\";\nimport { getStore } from \"./utils/store.ts\";\nimport { linkRoute, urlJoin } from \"./utils/url-utils.ts\";\n\n/**\n * URL builder for the Storybooks router.\n */\nexport class UrlBuilder {\n #useStore: boolean;\n\n constructor(useStore: boolean) {\n this.#useStore = useStore;\n }\n\n get #baseUrl(): string {\n if (!this.#useStore) {\n return \"\";\n }\n\n return new URL(getStore().url).origin;\n }\n\n homepage(): string {\n return linkRoute((client) => client.index.$url(), {\n baseUrl: this.#baseUrl,\n });\n }\n openapi(): string {\n return linkRoute((client) => client.openapi.$url(), {\n baseUrl: this.#baseUrl,\n });\n }\n staticFile(filepath: string): string {\n return linkRoute((client) => client[\":filepath{.+}\"].$url({ param: { filepath } }), {\n baseUrl: this.#baseUrl,\n });\n }\n\n // accounts\n account(): string {\n return linkRoute((client) => client.account.$url(), {\n baseUrl: this.#baseUrl,\n });\n }\n\n login(redirect?: string): string {\n return linkRoute((client) => client.account.login.$url({ query: { redirect } }), {\n baseUrl: this.#baseUrl,\n });\n }\n logout(): string {\n return linkRoute((client) => client.account.logout.$url(), {\n baseUrl: this.#baseUrl,\n });\n }\n\n // projects\n projectsList(): string {\n return linkRoute((client) => client.projects.$url(), {\n baseUrl: this.#baseUrl,\n });\n }\n projectCreate(): string {\n return linkRoute((client) => client.projects.create.$url(), {\n baseUrl: this.#baseUrl,\n });\n }\n projectDetails(projectId: string): string {\n return linkRoute((client) => client.projects[\":projectId\"].$url({ param: { projectId } }), {\n baseUrl: this.#baseUrl,\n });\n }\n projectUpdate(projectId: string): string {\n return linkRoute(\n (client) => client.projects[\":projectId\"].update.$url({ param: { projectId } }),\n { baseUrl: this.#baseUrl },\n );\n }\n projectDelete(projectId: string): string {\n return linkRoute(\n (client) => client.projects[\":projectId\"].delete.$url({ param: { projectId } }),\n { baseUrl: this.#baseUrl },\n );\n }\n\n // builds\n buildsList(projectId: string): string {\n return linkRoute(\n (client) => client.projects[\":projectId\"].builds.$url({ param: { projectId } }),\n { baseUrl: this.#baseUrl },\n );\n }\n buildDetails(projectId: string, buildId: string): string {\n return linkRoute(\n (client) =>\n client.projects[\":projectId\"].builds[\":buildId\"].$url({\n param: { buildId, projectId },\n }),\n { baseUrl: this.#baseUrl },\n );\n }\n buildCreate(projectId: string, tagId?: string): string {\n return linkRoute(\n (client) =>\n client.projects[\":projectId\"].builds.create.$url({\n param: { projectId },\n query: { tagId },\n }),\n { baseUrl: this.#baseUrl },\n );\n }\n buildDelete(projectId: string, buildId: string): string {\n return linkRoute(\n (client) =>\n client.projects[\":projectId\"].builds[\":buildId\"].delete.$url({\n param: { projectId, buildId },\n }),\n { baseUrl: this.#baseUrl },\n );\n }\n buildUpdate(projectId: string, buildId: string): string {\n return linkRoute(\n (client) =>\n client.projects[\":projectId\"].builds[\":buildId\"].update.$url({\n param: { projectId, buildId },\n }),\n { baseUrl: this.#baseUrl },\n );\n }\n buildUpload(projectId: string, buildId: string, variant?: BuildUploadVariant): string {\n return linkRoute(\n (client) =>\n client.projects[\":projectId\"].builds[\":buildId\"].upload.$url({\n param: { buildId, projectId },\n query: { variant },\n }),\n { baseUrl: this.#baseUrl },\n );\n }\n\n // tags\n tagsList(projectId: string, type?: TagVariant): string {\n return linkRoute(\n (client) =>\n client.projects[\":projectId\"].tags.$url({\n param: { projectId },\n query: { type },\n }),\n { baseUrl: this.#baseUrl },\n );\n }\n tagCreate(projectId: string): string {\n return linkRoute(\n (client) =>\n client.projects[\":projectId\"].tags.create.$url({\n param: { projectId },\n }),\n { baseUrl: this.#baseUrl },\n );\n }\n tagDetails(projectId: string, tagId: string): string {\n return linkRoute(\n (client) =>\n client.projects[\":projectId\"].tags[\":tagId\"].$url({\n param: { projectId, tagId },\n }),\n { baseUrl: this.#baseUrl },\n );\n }\n tagDelete(projectId: string, tagId: string): string {\n return linkRoute(\n (client) =>\n client.projects[\":projectId\"].tags[\":tagId\"].delete.$url({\n param: { projectId, tagId },\n }),\n { baseUrl: this.#baseUrl },\n );\n }\n tagUpdate(projectId: string, tagId: string): string {\n return linkRoute(\n (client) =>\n client.projects[\":projectId\"].tags[\":tagId\"].update.$url({\n param: { projectId, tagId },\n }),\n { baseUrl: this.#baseUrl },\n );\n }\n // tagLatest: (projectId: string, tagId: string): string => {\n // return linkRoute((client) =>\n // client.projects[\":projectId\"].tags[\":tagId\"].latest.$url({\n // param: { projectId, tagId },\n // }),\n // );\n // },\n\n // tasks\n taskPurge(projectId?: string): string {\n return linkRoute((client) => client.tasks.purge.$url({ query: { projectId } }), {\n baseUrl: this.#baseUrl,\n });\n }\n taskProcessZip(projectId: string, buildId: string, variant: BuildUploadVariant): string {\n return linkRoute(\n (client) =>\n client.tasks[\"process-zip\"].$url({\n query: { projectId, buildId, variant },\n }),\n { baseUrl: this.#baseUrl },\n );\n }\n\n // serve\n storybookIndexHtml(projectId: string, buildId: string, storyId?: string): string {\n return linkRoute(\n (client) =>\n client._[\":projectId\"][\":buildId\"][\":filepath{.+}\"].$url({\n param: {\n projectId,\n buildId,\n filepath: \"storybook/index.html\",\n },\n query: {\n path: storyId ? `/story/${storyId}` : undefined,\n },\n }),\n { baseUrl: this.#baseUrl },\n );\n }\n storybookIFrameHtml(projectId: string, buildId: string, storyId: string): string {\n return linkRoute(\n (client) =>\n client._[\":projectId\"][\":buildId\"][\":filepath{.+}\"].$url({\n param: {\n projectId,\n buildId,\n filepath: \"storybook/iframe.html\",\n },\n query: { id: storyId, viewMode: \"story\" },\n }),\n { baseUrl: this.#baseUrl },\n );\n }\n storybookDownload(projectId: string, buildId: string): string {\n return linkRoute(\n (client) =>\n client._[\":projectId\"][\":buildId\"][\":filepath{.+}\"].$url({\n param: {\n projectId,\n buildId,\n filepath: \"storybook.zip\",\n },\n query: {},\n }),\n { baseUrl: this.#baseUrl },\n );\n }\n storybookTestReport(projectId: string, buildId: string): string {\n return linkRoute(\n (client) =>\n client._[\":projectId\"][\":buildId\"][\":filepath{.+}\"].$url({\n param: {\n projectId,\n buildId,\n filepath: \"testReport/index.html\",\n },\n query: {},\n }),\n { baseUrl: this.#baseUrl },\n );\n }\n storybookCoverage(projectId: string, buildId: string): string {\n return linkRoute(\n (client) =>\n client._[\":projectId\"][\":buildId\"][\":filepath{.+}\"].$url({\n param: {\n projectId,\n buildId,\n filepath: \"coverage/index.html\",\n },\n query: {},\n }),\n { baseUrl: this.#baseUrl },\n );\n }\n storybookScreenshot(projectId: string, buildId: string, ...filename: string[]): string {\n return linkRoute(\n (client) =>\n client._[\":projectId\"][\":buildId\"][\":filepath{.+}\"].$url({\n param: {\n projectId,\n buildId,\n filepath: path.posix.join(\"screenshots\", ...filename),\n },\n query: {},\n }),\n { baseUrl: this.#baseUrl },\n );\n }\n storybookScreenshotsDownload(projectId: string, buildId: string): string {\n return linkRoute(\n (client) =>\n client._[\":projectId\"][\":buildId\"][\":filepath{.+}\"].$url({\n param: {\n projectId,\n buildId,\n filepath: \"screenshots.zip\",\n },\n query: {},\n }),\n { baseUrl: this.#baseUrl },\n );\n }\n\n // external\n // oxlint-disable-next-line class-methods-use-this\n gitHub(gitHubRepo: string, ...pathnames: string[]): string {\n const url = new URL(urlJoin(gitHubRepo, ...pathnames), \"https://github.com\");\n return url.toString();\n }\n}\n\n/** @private */\nexport const urlBuilder: UrlBuilder = new UrlBuilder(true);\n/** @private */\nexport const urlBuilderWithoutStore: UrlBuilder = new UrlBuilder(false);\n"],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
//#region src/utils/adapter-utils.d.ts
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Metadata information about a StoryBooker adapter.
|
|
5
|
+
*/
|
|
6
|
+
interface StoryBookerAdapterMetadata {
|
|
7
|
+
name: string;
|
|
8
|
+
description?: string;
|
|
9
|
+
version?: string;
|
|
10
|
+
[key: string]: unknown;
|
|
11
|
+
}
|
|
12
|
+
//#endregion
|
|
13
|
+
export { StoryBookerAdapterMetadata };
|
|
14
|
+
//# sourceMappingURL=adapter-utils.d.mts.map
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { SERVICE_NAME } from "../~internal/constants.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/utils/adapter-utils.ts
|
|
4
|
+
function generateDatabaseCollectionId(projectId, suffix) {
|
|
5
|
+
if (!suffix) return `${SERVICE_NAME}-${projectId}`;
|
|
6
|
+
return `${SERVICE_NAME}-${projectId}-${suffix}`;
|
|
7
|
+
}
|
|
8
|
+
function generateStorageContainerId(projectId) {
|
|
9
|
+
return `${SERVICE_NAME}-${projectId}`;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
//#endregion
|
|
13
|
+
export { generateDatabaseCollectionId, generateStorageContainerId };
|
|
14
|
+
//# sourceMappingURL=adapter-utils.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"adapter-utils.mjs","names":[],"sources":["../../src/utils/adapter-utils.ts"],"sourcesContent":["import { SERVICE_NAME } from \"../utils/constants.ts\";\n\nexport function generateDatabaseCollectionId(\n projectId: string,\n suffix: \"Tags\" | \"Builds\" | \"\",\n): string {\n if (!suffix) {\n return `${SERVICE_NAME}-${projectId}`;\n }\n\n return `${SERVICE_NAME}-${projectId}-${suffix}`;\n}\n\nexport function generateStorageContainerId(projectId: string): string {\n return `${SERVICE_NAME}-${projectId}`;\n}\n\n/**\n * Metadata information about a StoryBooker adapter.\n */\nexport interface StoryBookerAdapterMetadata {\n name: string;\n description?: string;\n version?: string;\n [key: string]: unknown;\n}\n"],"mappings":";;;AAEA,SAAgB,6BACd,WACA,QACQ;AACR,KAAI,CAAC,OACH,QAAO,GAAG,aAAa,GAAG;AAG5B,QAAO,GAAG,aAAa,GAAG,UAAU,GAAG;;AAGzC,SAAgB,2BAA2B,WAA2B;AACpE,QAAO,GAAG,aAAa,GAAG"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { getStore } from "./store.mjs";
|
|
2
|
+
import { HTTPException } from "hono/http-exception";
|
|
3
|
+
|
|
4
|
+
//#region src/utils/auth.ts
|
|
5
|
+
function authenticateOrThrow(permission) {
|
|
6
|
+
const { auth, logger, user } = getStore();
|
|
7
|
+
if (!auth) return;
|
|
8
|
+
if (!user) throw new HTTPException(401, { message: "Unauthenticated. Please log in to continue." });
|
|
9
|
+
const key = `${permission.resource}:${permission.action}`;
|
|
10
|
+
logger.debug?.("[Auth] Check authorisation for '%s'", key);
|
|
11
|
+
if (user.permissions[key]) return;
|
|
12
|
+
throw new HTTPException(403, { message: `Permission denied [${key}]` });
|
|
13
|
+
}
|
|
14
|
+
function checkAuthorisation(permission) {
|
|
15
|
+
try {
|
|
16
|
+
authenticateOrThrow(permission);
|
|
17
|
+
return true;
|
|
18
|
+
} catch {
|
|
19
|
+
return false;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
//#endregion
|
|
24
|
+
export { authenticateOrThrow, checkAuthorisation };
|
|
25
|
+
//# sourceMappingURL=auth.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.mjs","names":["key: StoryBookerPermissionKey"],"sources":["../../src/utils/auth.ts"],"sourcesContent":["import { HTTPException } from \"hono/http-exception\";\nimport type {\n StoryBookerPermission,\n StoryBookerPermissionKey,\n} from \"../adapters/_internal/auth.ts\";\nimport { getStore } from \"../utils/store.ts\";\n\nexport function authenticateOrThrow(permission: StoryBookerPermission): void {\n const { auth, logger, user } = getStore();\n if (!auth) {\n // No authentication service configured, allow all actions\n return;\n }\n\n if (!user) {\n throw new HTTPException(401, { message: \"Unauthenticated. Please log in to continue.\" });\n }\n\n const key: StoryBookerPermissionKey = `${permission.resource}:${permission.action}`;\n logger.debug?.(\"[Auth] Check authorisation for '%s'\", key);\n\n // Authorized\n const hasPermission = user.permissions[key];\n\n if (hasPermission) {\n return;\n }\n\n throw new HTTPException(403, { message: `Permission denied [${key}]` });\n}\n\nexport function checkAuthorisation(permission: StoryBookerPermission): boolean {\n try {\n authenticateOrThrow(permission);\n return true;\n } catch {\n return false;\n }\n}\n"],"mappings":";;;;AAOA,SAAgB,oBAAoB,YAAyC;CAC3E,MAAM,EAAE,MAAM,QAAQ,SAAS,UAAU;AACzC,KAAI,CAAC,KAEH;AAGF,KAAI,CAAC,KACH,OAAM,IAAI,cAAc,KAAK,EAAE,SAAS,+CAA+C,CAAC;CAG1F,MAAMA,MAAgC,GAAG,WAAW,SAAS,GAAG,WAAW;AAC3E,QAAO,QAAQ,uCAAuC,IAAI;AAK1D,KAFsB,KAAK,YAAY,KAGrC;AAGF,OAAM,IAAI,cAAc,KAAK,EAAE,SAAS,sBAAsB,IAAI,IAAI,CAAC;;AAGzE,SAAgB,mBAAmB,YAA4C;AAC7E,KAAI;AACF,sBAAoB,WAAW;AAC/B,SAAO;SACD;AACN,SAAO"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import "../~internal/types.mjs";
|
|
2
|
+
import "../~internal/adapter.mjs";
|
|
3
|
+
import { MiddlewareHandler } from "hono";
|
|
4
|
+
|
|
5
|
+
//#region src/utils/error.d.ts
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* A function type for parsing custom errors.
|
|
9
|
+
* Return `undefined` from parser if the service should handle the error.
|
|
10
|
+
*/
|
|
11
|
+
type ErrorParser = (error: unknown) => ParsedError | undefined;
|
|
12
|
+
/** Parsed error information. */
|
|
13
|
+
interface ParsedError {
|
|
14
|
+
errorMessage: string;
|
|
15
|
+
errorStatus?: number;
|
|
16
|
+
errorType: string;
|
|
17
|
+
}
|
|
18
|
+
declare function parseErrorMessage(error: unknown, errorParser?: ErrorParser): ParsedError;
|
|
19
|
+
//#endregion
|
|
20
|
+
export { ErrorParser, ParsedError, parseErrorMessage };
|
|
21
|
+
//# sourceMappingURL=error.d.mts.map
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { createConsoleLoggerAdapter } from "../~internal/adapter/logger.mjs";
|
|
2
|
+
import { DEFAULT_LOCALE } from "../~internal/constants.mjs";
|
|
3
|
+
import { getStoreOrNull } from "./store.mjs";
|
|
4
|
+
import { checkIsHTMLRequest } from "./request.mjs";
|
|
5
|
+
import { uiResultResponse } from "./ui-utils.mjs";
|
|
6
|
+
import { HTTPException } from "hono/http-exception";
|
|
7
|
+
import { z } from "zod";
|
|
8
|
+
|
|
9
|
+
//#region src/utils/error.ts
|
|
10
|
+
function parseErrorMessage(error, errorParser) {
|
|
11
|
+
if (!error) return {
|
|
12
|
+
errorMessage: "",
|
|
13
|
+
errorType: "unknown"
|
|
14
|
+
};
|
|
15
|
+
const customErrorResult = (errorParser ?? getStoreOrNull()?.errorParser)?.(error);
|
|
16
|
+
if (customErrorResult !== void 0) return customErrorResult;
|
|
17
|
+
if (typeof error === "string") return {
|
|
18
|
+
errorMessage: error,
|
|
19
|
+
errorType: "string"
|
|
20
|
+
};
|
|
21
|
+
if (error instanceof HTTPException) {
|
|
22
|
+
const { message, status } = unwrapHttpException(error);
|
|
23
|
+
return {
|
|
24
|
+
errorMessage: message,
|
|
25
|
+
errorStatus: status,
|
|
26
|
+
errorType: "HTTPException"
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
if (error instanceof z.core.$ZodError) return {
|
|
30
|
+
errorMessage: z.prettifyError(error),
|
|
31
|
+
errorStatus: 400,
|
|
32
|
+
errorType: "Zod"
|
|
33
|
+
};
|
|
34
|
+
if (error instanceof Error || error && typeof error === "object" && "message" in error) return {
|
|
35
|
+
errorMessage: String(error.message),
|
|
36
|
+
errorType: "error"
|
|
37
|
+
};
|
|
38
|
+
return {
|
|
39
|
+
errorMessage: String(error),
|
|
40
|
+
errorType: "unknown"
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
const zodValidationErrorSchema = z.object({
|
|
44
|
+
success: z.literal(false),
|
|
45
|
+
error: z.object({
|
|
46
|
+
name: z.literal("ZodError"),
|
|
47
|
+
message: z.string()
|
|
48
|
+
})
|
|
49
|
+
});
|
|
50
|
+
function prettifyZodValidationErrorMiddleware(logger) {
|
|
51
|
+
return async (ctx, next) => {
|
|
52
|
+
await next();
|
|
53
|
+
const resContentType = ctx.res.headers.get("Content-Type") ?? "";
|
|
54
|
+
if (ctx.res.status === 400 && resContentType.startsWith("application/json")) {
|
|
55
|
+
const result = zodValidationErrorSchema.safeParse(await ctx.res.clone().json());
|
|
56
|
+
if (result.success) {
|
|
57
|
+
const issues = JSON.parse(result.data.error.message);
|
|
58
|
+
const message = `Validation error:\n${z.prettifyError({ issues })}`;
|
|
59
|
+
logger.error(`[Zod] ${message}`);
|
|
60
|
+
throw new HTTPException(400, {
|
|
61
|
+
message,
|
|
62
|
+
res: ctx.res
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
function onUnhandledErrorHandler(options) {
|
|
69
|
+
return (error, ctx) => {
|
|
70
|
+
if (error instanceof Response) return error;
|
|
71
|
+
const logger = options.logger ?? createConsoleLoggerAdapter();
|
|
72
|
+
const parsedError = parseErrorMessage(error);
|
|
73
|
+
const { errorMessage, errorStatus, errorType } = parsedError;
|
|
74
|
+
logger.error(`[${errorType}:${errorStatus}] ${errorMessage}`);
|
|
75
|
+
if (options?.ui?.renderErrorPage && checkIsHTMLRequest(false, ctx.req.raw)) return uiResultResponse(ctx, options.ui.renderErrorPage(parsedError, {
|
|
76
|
+
isAuthEnabled: Boolean(options.auth),
|
|
77
|
+
locale: DEFAULT_LOCALE,
|
|
78
|
+
logger,
|
|
79
|
+
url: ctx.req.url,
|
|
80
|
+
user: null,
|
|
81
|
+
adaptersMetadata: {}
|
|
82
|
+
}), { status: errorStatus ?? 500 });
|
|
83
|
+
return new Response(errorMessage, {
|
|
84
|
+
status: errorStatus ?? 500,
|
|
85
|
+
statusText: errorType
|
|
86
|
+
});
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
function unwrapHttpException(error) {
|
|
90
|
+
let causeMessage = "";
|
|
91
|
+
let causeStatus = error.status;
|
|
92
|
+
if (error.cause) if (error.cause instanceof HTTPException) {
|
|
93
|
+
const { message, status } = unwrapHttpException(error.cause);
|
|
94
|
+
causeMessage = message;
|
|
95
|
+
causeStatus = status;
|
|
96
|
+
} else {
|
|
97
|
+
const { errorMessage } = parseErrorMessage(error.cause);
|
|
98
|
+
causeMessage = errorMessage;
|
|
99
|
+
}
|
|
100
|
+
const errorStatus = causeStatus ?? error.status;
|
|
101
|
+
return {
|
|
102
|
+
message: causeMessage ? `${error.message}\n ↳ ${causeMessage}` : error.message,
|
|
103
|
+
status: errorStatus
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
//#endregion
|
|
108
|
+
export { onUnhandledErrorHandler, parseErrorMessage, prettifyZodValidationErrorMiddleware };
|
|
109
|
+
//# sourceMappingURL=error.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"error.mjs","names":["causeStatus: number | undefined"],"sources":["../../src/utils/error.ts"],"sourcesContent":["import type { ErrorHandler, MiddlewareHandler } from \"hono\";\nimport { HTTPException } from \"hono/http-exception\";\nimport type { ServerErrorStatusCode } from \"hono/utils/http-status\";\nimport { z } from \"zod\";\nimport { createConsoleLoggerAdapter, type LoggerAdapter } from \"../adapters/_internal/index.ts\";\nimport type { RouterOptions, StoryBookerUser } from \"../types.ts\";\nimport { getStoreOrNull } from \"../utils/store.ts\";\nimport { DEFAULT_LOCALE } from \"./constants.ts\";\nimport { checkIsHTMLRequest } from \"./request.ts\";\nimport { uiResultResponse } from \"./ui-utils.ts\";\n\n/**\n * A function type for parsing custom errors.\n * Return `undefined` from parser if the service should handle the error.\n */\nexport type ErrorParser = (error: unknown) => ParsedError | undefined;\n/** Parsed error information. */\nexport interface ParsedError {\n errorMessage: string;\n errorStatus?: number;\n errorType: string;\n}\n\nexport function parseErrorMessage(error: unknown, errorParser?: ErrorParser): ParsedError {\n if (!error) {\n return { errorMessage: \"\", errorType: \"unknown\" };\n }\n\n const customErrorParser = errorParser ?? getStoreOrNull()?.errorParser;\n const customErrorResult = customErrorParser?.(error);\n if (customErrorResult !== undefined) {\n return customErrorResult;\n }\n\n if (typeof error === \"string\") {\n return { errorMessage: error, errorType: \"string\" };\n }\n\n if (error instanceof HTTPException) {\n const { message, status } = unwrapHttpException(error);\n return {\n errorMessage: message,\n errorStatus: status,\n errorType: \"HTTPException\",\n };\n }\n\n if (error instanceof z.core.$ZodError) {\n return {\n errorMessage: z.prettifyError(error),\n errorStatus: 400,\n errorType: \"Zod\",\n };\n }\n\n if (error instanceof Error || (error && typeof error === \"object\" && \"message\" in error)) {\n return { errorMessage: String(error.message), errorType: \"error\" };\n }\n\n return { errorMessage: String(error), errorType: \"unknown\" };\n}\n\nconst zodValidationErrorSchema = z.object({\n success: z.literal(false),\n error: z.object({\n name: z.literal(\"ZodError\"),\n message: z.string(),\n }),\n});\nexport function prettifyZodValidationErrorMiddleware(logger: LoggerAdapter): MiddlewareHandler {\n return async (ctx, next) => {\n await next();\n\n const resContentType = ctx.res.headers.get(\"Content-Type\") ?? \"\";\n if (ctx.res.status === 400 && resContentType.startsWith(\"application/json\")) {\n const result = zodValidationErrorSchema.safeParse(await ctx.res.clone().json());\n if (result.success) {\n const issues = JSON.parse(result.data.error.message) as z.core.$ZodIssue[];\n const message = `Validation error:\\n${z.prettifyError({ issues })}`;\n logger.error(`[Zod] ${message}`);\n throw new HTTPException(400, { message, res: ctx.res });\n }\n }\n };\n}\n\nexport function onUnhandledErrorHandler<User extends StoryBookerUser>(\n options: RouterOptions<User>,\n): ErrorHandler {\n return (error, ctx) => {\n if (error instanceof Response) {\n return error;\n }\n const logger = options.logger ?? createConsoleLoggerAdapter();\n\n const parsedError = parseErrorMessage(error);\n const { errorMessage, errorStatus, errorType } = parsedError;\n logger.error(`[${errorType}:${errorStatus}] ${errorMessage}`);\n\n if (options?.ui?.renderErrorPage && checkIsHTMLRequest(false, ctx.req.raw)) {\n const result = options.ui.renderErrorPage(parsedError, {\n isAuthEnabled: Boolean(options.auth),\n locale: DEFAULT_LOCALE,\n logger,\n url: ctx.req.url,\n user: null,\n adaptersMetadata: {},\n });\n\n return uiResultResponse(ctx, result, {\n status: (errorStatus as ServerErrorStatusCode) ?? 500,\n });\n }\n\n return new Response(errorMessage, { status: errorStatus ?? 500, statusText: errorType });\n };\n}\n\nfunction unwrapHttpException(error: HTTPException): {\n message: string;\n status?: number;\n} {\n let causeMessage = \"\";\n let causeStatus: number | undefined = error.status;\n\n if (error.cause) {\n if (error.cause instanceof HTTPException) {\n const { message, status } = unwrapHttpException(error.cause);\n causeMessage = message;\n causeStatus = status;\n } else {\n const { errorMessage } = parseErrorMessage(error.cause);\n causeMessage = errorMessage;\n }\n }\n\n const errorStatus = causeStatus ?? error.status;\n const errorMessage = causeMessage ? `${error.message}\\n ↳ ${causeMessage}` : error.message;\n return { message: errorMessage, status: errorStatus };\n}\n"],"mappings":";;;;;;;;;AAuBA,SAAgB,kBAAkB,OAAgB,aAAwC;AACxF,KAAI,CAAC,MACH,QAAO;EAAE,cAAc;EAAI,WAAW;EAAW;CAInD,MAAM,qBADoB,eAAe,gBAAgB,EAAE,eACb,MAAM;AACpD,KAAI,sBAAsB,OACxB,QAAO;AAGT,KAAI,OAAO,UAAU,SACnB,QAAO;EAAE,cAAc;EAAO,WAAW;EAAU;AAGrD,KAAI,iBAAiB,eAAe;EAClC,MAAM,EAAE,SAAS,WAAW,oBAAoB,MAAM;AACtD,SAAO;GACL,cAAc;GACd,aAAa;GACb,WAAW;GACZ;;AAGH,KAAI,iBAAiB,EAAE,KAAK,UAC1B,QAAO;EACL,cAAc,EAAE,cAAc,MAAM;EACpC,aAAa;EACb,WAAW;EACZ;AAGH,KAAI,iBAAiB,SAAU,SAAS,OAAO,UAAU,YAAY,aAAa,MAChF,QAAO;EAAE,cAAc,OAAO,MAAM,QAAQ;EAAE,WAAW;EAAS;AAGpE,QAAO;EAAE,cAAc,OAAO,MAAM;EAAE,WAAW;EAAW;;AAG9D,MAAM,2BAA2B,EAAE,OAAO;CACxC,SAAS,EAAE,QAAQ,MAAM;CACzB,OAAO,EAAE,OAAO;EACd,MAAM,EAAE,QAAQ,WAAW;EAC3B,SAAS,EAAE,QAAQ;EACpB,CAAC;CACH,CAAC;AACF,SAAgB,qCAAqC,QAA0C;AAC7F,QAAO,OAAO,KAAK,SAAS;AAC1B,QAAM,MAAM;EAEZ,MAAM,iBAAiB,IAAI,IAAI,QAAQ,IAAI,eAAe,IAAI;AAC9D,MAAI,IAAI,IAAI,WAAW,OAAO,eAAe,WAAW,mBAAmB,EAAE;GAC3E,MAAM,SAAS,yBAAyB,UAAU,MAAM,IAAI,IAAI,OAAO,CAAC,MAAM,CAAC;AAC/E,OAAI,OAAO,SAAS;IAClB,MAAM,SAAS,KAAK,MAAM,OAAO,KAAK,MAAM,QAAQ;IACpD,MAAM,UAAU,sBAAsB,EAAE,cAAc,EAAE,QAAQ,CAAC;AACjE,WAAO,MAAM,SAAS,UAAU;AAChC,UAAM,IAAI,cAAc,KAAK;KAAE;KAAS,KAAK,IAAI;KAAK,CAAC;;;;;AAM/D,SAAgB,wBACd,SACc;AACd,SAAQ,OAAO,QAAQ;AACrB,MAAI,iBAAiB,SACnB,QAAO;EAET,MAAM,SAAS,QAAQ,UAAU,4BAA4B;EAE7D,MAAM,cAAc,kBAAkB,MAAM;EAC5C,MAAM,EAAE,cAAc,aAAa,cAAc;AACjD,SAAO,MAAM,IAAI,UAAU,GAAG,YAAY,IAAI,eAAe;AAE7D,MAAI,SAAS,IAAI,mBAAmB,mBAAmB,OAAO,IAAI,IAAI,IAAI,CAUxE,QAAO,iBAAiB,KATT,QAAQ,GAAG,gBAAgB,aAAa;GACrD,eAAe,QAAQ,QAAQ,KAAK;GACpC,QAAQ;GACR;GACA,KAAK,IAAI,IAAI;GACb,MAAM;GACN,kBAAkB,EAAE;GACrB,CAAC,EAEmC,EACnC,QAAS,eAAyC,KACnD,CAAC;AAGJ,SAAO,IAAI,SAAS,cAAc;GAAE,QAAQ,eAAe;GAAK,YAAY;GAAW,CAAC;;;AAI5F,SAAS,oBAAoB,OAG3B;CACA,IAAI,eAAe;CACnB,IAAIA,cAAkC,MAAM;AAE5C,KAAI,MAAM,MACR,KAAI,MAAM,iBAAiB,eAAe;EACxC,MAAM,EAAE,SAAS,WAAW,oBAAoB,MAAM,MAAM;AAC5D,iBAAe;AACf,gBAAc;QACT;EACL,MAAM,EAAE,iBAAiB,kBAAkB,MAAM,MAAM;AACvD,iBAAe;;CAInB,MAAM,cAAc,eAAe,MAAM;AAEzC,QAAO;EAAE,SADY,eAAe,GAAG,MAAM,QAAQ,OAAO,iBAAiB,MAAM;EACnD,QAAQ;EAAa"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { createWriteStream } from "node:fs";
|
|
2
|
+
import { once } from "node:events";
|
|
3
|
+
import { Readable } from "node:stream";
|
|
4
|
+
|
|
5
|
+
//#region src/utils/file-utils.ts
|
|
6
|
+
async function writeStreamToFile(filePath, stream) {
|
|
7
|
+
const writable = createWriteStream(filePath);
|
|
8
|
+
const readable = stream instanceof Readable ? stream : Readable.fromWeb(stream);
|
|
9
|
+
for await (const chunk of readable) if (!writable.write(chunk)) await once(writable, "drain");
|
|
10
|
+
writable.end();
|
|
11
|
+
await once(writable, "finish");
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
//#endregion
|
|
15
|
+
export { writeStreamToFile };
|
|
16
|
+
//# sourceMappingURL=file-utils.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file-utils.mjs","names":[],"sources":["../../src/utils/file-utils.ts"],"sourcesContent":["import { once } from \"node:events\";\nimport { createWriteStream } from \"node:fs\";\nimport { Readable } from \"node:stream\";\nimport type { ReadableStream as WebReadableStream } from \"node:stream/web\";\n\nexport async function writeStreamToFile(\n filePath: string,\n stream: Readable | ReadableStream,\n): Promise<void> {\n const writable = createWriteStream(filePath);\n const readable =\n stream instanceof Readable ? stream : Readable.fromWeb(stream as WebReadableStream);\n for await (const chunk of readable) {\n if (!writable.write(chunk)) {\n // Wait if backpressure is applied\n await once(writable, \"drain\");\n }\n }\n writable.end();\n await once(writable, \"finish\");\n}\n\nexport function writeWebStreamToFile(\n webReadableStream: ReadableStream,\n outputPath: string,\n): Promise<null> {\n // Convert WebReadableStream to Node.js Readable stream\n const nodeReadableStream = Readable.fromWeb(webReadableStream as WebReadableStream);\n\n // Create a writable file stream\n const fileWritableStream = createWriteStream(outputPath);\n\n // Pipe the Node.js readable stream to the writable file stream\n nodeReadableStream.pipe(fileWritableStream);\n\n // Return a promise that resolves when writing is finished\n return new Promise((resolve, reject) => {\n fileWritableStream.on(\"finish\", () => {\n resolve(null);\n });\n fileWritableStream.on(\"error\", reject);\n });\n}\n"],"mappings":";;;;;AAKA,eAAsB,kBACpB,UACA,QACe;CACf,MAAM,WAAW,kBAAkB,SAAS;CAC5C,MAAM,WACJ,kBAAkB,WAAW,SAAS,SAAS,QAAQ,OAA4B;AACrF,YAAW,MAAM,SAAS,SACxB,KAAI,CAAC,SAAS,MAAM,MAAM,CAExB,OAAM,KAAK,UAAU,QAAQ;AAGjC,UAAS,KAAK;AACd,OAAM,KAAK,UAAU,SAAS"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { mimes } from "../~internal/mimes.mjs";
|
|
2
|
+
import { z } from "@hono/zod-openapi";
|
|
3
|
+
|
|
4
|
+
//#region src/utils/openapi-utils.ts
|
|
5
|
+
const openapiResponsesHtml = { [mimes.html]: { schema: z.string().openapi({ example: "<!DOCTYPE html>" }) } };
|
|
6
|
+
function openapiResponseRedirect(description) {
|
|
7
|
+
return {
|
|
8
|
+
description,
|
|
9
|
+
headers: {
|
|
10
|
+
location: {
|
|
11
|
+
description: "Location/URL to redirect.",
|
|
12
|
+
schema: { type: "string" },
|
|
13
|
+
required: true
|
|
14
|
+
},
|
|
15
|
+
"hx-location": {
|
|
16
|
+
description: "Location/URL to redirect using HTMX.",
|
|
17
|
+
schema: { type: "string" },
|
|
18
|
+
required: false
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
const openapiErrorResponseContent = { [mimes.json]: { schema: z.object({ errorMessage: z.string() }).meta({ id: "ResponseError" }) } };
|
|
24
|
+
const openapiCommonErrorResponses = {
|
|
25
|
+
400: {
|
|
26
|
+
content: openapiErrorResponseContent,
|
|
27
|
+
description: "Invalid request data"
|
|
28
|
+
},
|
|
29
|
+
401: {
|
|
30
|
+
content: openapiErrorResponseContent,
|
|
31
|
+
description: "Unauthenticated access"
|
|
32
|
+
},
|
|
33
|
+
403: {
|
|
34
|
+
content: openapiErrorResponseContent,
|
|
35
|
+
description: "Unauthorised access"
|
|
36
|
+
},
|
|
37
|
+
500: {
|
|
38
|
+
content: openapiErrorResponseContent,
|
|
39
|
+
description: "An unexpected server-error occurred."
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
//#endregion
|
|
44
|
+
export { openapiCommonErrorResponses, openapiErrorResponseContent, openapiResponseRedirect, openapiResponsesHtml };
|
|
45
|
+
//# sourceMappingURL=openapi-utils.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openapi-utils.mjs","names":["openapiErrorResponseContent: ZodContentObject","openapiCommonErrorResponses: Record<number | string, ResponseConfig>"],"sources":["../../src/utils/openapi-utils.ts"],"sourcesContent":["import type { ResponseConfig, ZodContentObject } from \"@asteasolutions/zod-to-openapi\";\nimport { z } from \"@hono/zod-openapi\";\nimport { mimes } from \"./mime-utils.ts\";\n\nexport const openapiResponsesHtml = {\n [mimes.html]: { schema: z.string().openapi({ example: \"<!DOCTYPE html>\" }) },\n} as const satisfies ZodContentObject;\n\nexport function openapiResponseRedirect(description: string): ResponseConfig {\n return {\n description,\n headers: {\n location: {\n description: \"Location/URL to redirect.\",\n schema: { type: \"string\" },\n required: true,\n },\n \"hx-location\": {\n description: \"Location/URL to redirect using HTMX.\",\n schema: { type: \"string\" },\n required: false,\n },\n },\n };\n}\n\nexport const openapiErrorResponseContent: ZodContentObject = {\n [mimes.json]: {\n schema: z.object({ errorMessage: z.string() }).meta({ id: \"ResponseError\" }),\n },\n};\nexport const openapiCommonErrorResponses: Record<number | string, ResponseConfig> = {\n 400: {\n content: openapiErrorResponseContent,\n description: \"Invalid request data\",\n },\n 401: {\n content: openapiErrorResponseContent,\n description: \"Unauthenticated access\",\n },\n 403: {\n content: openapiErrorResponseContent,\n description: \"Unauthorised access\",\n },\n 500: {\n content: openapiErrorResponseContent,\n description: \"An unexpected server-error occurred.\",\n },\n};\n"],"mappings":";;;;AAIA,MAAa,uBAAuB,GACjC,MAAM,OAAO,EAAE,QAAQ,EAAE,QAAQ,CAAC,QAAQ,EAAE,SAAS,mBAAmB,CAAC,EAAE,EAC7E;AAED,SAAgB,wBAAwB,aAAqC;AAC3E,QAAO;EACL;EACA,SAAS;GACP,UAAU;IACR,aAAa;IACb,QAAQ,EAAE,MAAM,UAAU;IAC1B,UAAU;IACX;GACD,eAAe;IACb,aAAa;IACb,QAAQ,EAAE,MAAM,UAAU;IAC1B,UAAU;IACX;GACF;EACF;;AAGH,MAAaA,8BAAgD,GAC1D,MAAM,OAAO,EACZ,QAAQ,EAAE,OAAO,EAAE,cAAc,EAAE,QAAQ,EAAE,CAAC,CAAC,KAAK,EAAE,IAAI,iBAAiB,CAAC,EAC7E,EACF;AACD,MAAaC,8BAAuE;CAClF,KAAK;EACH,SAAS;EACT,aAAa;EACd;CACD,KAAK;EACH,SAAS;EACT,aAAa;EACd;CACD,KAAK;EACH,SAAS;EACT,aAAa;EACd;CACD,KAAK;EACH,SAAS;EACT,aAAa;EACd;CACF"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { mimes } from "../~internal/mimes.mjs";
|
|
2
|
+
import { getStore } from "./store.mjs";
|
|
3
|
+
import { SuperHeaders } from "@remix-run/headers";
|
|
4
|
+
|
|
5
|
+
//#region src/utils/request.ts
|
|
6
|
+
function checkIsHXRequest(request) {
|
|
7
|
+
return (request ?? getStore().request).headers.get("hx-request") === "true";
|
|
8
|
+
}
|
|
9
|
+
function checkIsHTMLRequest(checkHX, request) {
|
|
10
|
+
const req = request ?? getStore().request;
|
|
11
|
+
const accept = req.headers.get("accept");
|
|
12
|
+
if (checkHX && checkIsHXRequest(req)) return true;
|
|
13
|
+
return Boolean(accept?.includes(mimes.html));
|
|
14
|
+
}
|
|
15
|
+
function validateBuildUploadZipBody(request) {
|
|
16
|
+
const { headers: storeHeaders } = getStore();
|
|
17
|
+
const { body } = request;
|
|
18
|
+
if (!body) return {
|
|
19
|
+
message: "Request body is required",
|
|
20
|
+
status: 400
|
|
21
|
+
};
|
|
22
|
+
const { contentLength } = request ? new SuperHeaders(request.headers) : storeHeaders;
|
|
23
|
+
if (contentLength === null) return {
|
|
24
|
+
message: "Content-Length header is required",
|
|
25
|
+
status: 411
|
|
26
|
+
};
|
|
27
|
+
if (contentLength === 0) return {
|
|
28
|
+
message: "Content-Length should be greater than 0",
|
|
29
|
+
status: 400
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
//#endregion
|
|
34
|
+
export { checkIsHTMLRequest, checkIsHXRequest, validateBuildUploadZipBody };
|
|
35
|
+
//# sourceMappingURL=request.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"request.mjs","names":[],"sources":["../../src/utils/request.ts"],"sourcesContent":["import { SuperHeaders } from \"@remix-run/headers\";\nimport { getStore } from \"../utils/store.ts\";\nimport { mimes } from \"./mime-utils.ts\";\n\ninterface ErrorObject {\n message: string;\n status: number;\n}\n\nexport function checkIsHXRequest(request?: Request): boolean {\n const req = request ?? getStore().request;\n return req.headers.get(\"hx-request\") === \"true\";\n}\n\nexport function checkIsHTMLRequest(checkHX?: boolean, request?: Request): boolean {\n const req = request ?? getStore().request;\n\n const accept = req.headers.get(\"accept\");\n if (checkHX && checkIsHXRequest(req)) {\n return true;\n }\n return Boolean(accept?.includes(mimes.html));\n}\n\nexport function validateIsFormEncodedRequest(request?: Request): undefined | ErrorObject {\n const store = getStore();\n const { contentType } = request ? new SuperHeaders(request.headers) : store.headers;\n\n if (!contentType) {\n return {\n message: \"Content-Length header is required\",\n status: 400,\n };\n }\n\n if (!contentType.mediaType?.includes(mimes.formEncoded)) {\n return {\n message: `Content-Type header is invalid, Expected: ${mimes.formEncoded}`,\n status: 415,\n };\n }\n\n return undefined;\n}\n\nexport function validateBuildUploadZipBody(request: Request): ErrorObject | undefined {\n const { headers: storeHeaders } = getStore();\n const { body } = request;\n\n if (!body) {\n return {\n message: \"Request body is required\",\n status: 400,\n };\n }\n\n const { contentLength } = request ? new SuperHeaders(request.headers) : storeHeaders;\n\n if (contentLength === null) {\n return {\n message: \"Content-Length header is required\",\n status: 411,\n };\n }\n if (contentLength === 0) {\n return {\n message: \"Content-Length should be greater than 0\",\n status: 400,\n };\n }\n\n return undefined;\n}\n\nexport function parseRequestCookieHeader(\n cookieHeaderOrRequest: string | Request,\n): Record<string, string> {\n const cookieHeader =\n typeof cookieHeaderOrRequest === \"string\"\n ? cookieHeaderOrRequest\n : new Headers(cookieHeaderOrRequest.headers).get(\"cookie\");\n\n const cookies: Record<string, string> = {};\n\n if (!cookieHeader) {\n return cookies;\n }\n\n for (const cookie of cookieHeader.split(\";\")) {\n const [key, value] = cookie.split(\"=\");\n if (key !== undefined && value !== undefined) {\n cookies[decodeURIComponent(key.trim())] = decodeURIComponent(value.trim());\n }\n }\n\n return cookies;\n}\n"],"mappings":";;;;;AASA,SAAgB,iBAAiB,SAA4B;AAE3D,SADY,WAAW,UAAU,CAAC,SACvB,QAAQ,IAAI,aAAa,KAAK;;AAG3C,SAAgB,mBAAmB,SAAmB,SAA4B;CAChF,MAAM,MAAM,WAAW,UAAU,CAAC;CAElC,MAAM,SAAS,IAAI,QAAQ,IAAI,SAAS;AACxC,KAAI,WAAW,iBAAiB,IAAI,CAClC,QAAO;AAET,QAAO,QAAQ,QAAQ,SAAS,MAAM,KAAK,CAAC;;AAwB9C,SAAgB,2BAA2B,SAA2C;CACpF,MAAM,EAAE,SAAS,iBAAiB,UAAU;CAC5C,MAAM,EAAE,SAAS;AAEjB,KAAI,CAAC,KACH,QAAO;EACL,SAAS;EACT,QAAQ;EACT;CAGH,MAAM,EAAE,kBAAkB,UAAU,IAAI,aAAa,QAAQ,QAAQ,GAAG;AAExE,KAAI,kBAAkB,KACpB,QAAO;EACL,SAAS;EACT,QAAQ;EACT;AAEH,KAAI,kBAAkB,EACpB,QAAO;EACL,SAAS;EACT,QAAQ;EACT"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { checkIsHXRequest } from "./request.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/utils/response.ts
|
|
4
|
+
/**
|
|
5
|
+
* Middleware to handle htmx redirects.
|
|
6
|
+
* If the response status is a redirect (3xx) and the request is an htmx request,
|
|
7
|
+
* it sets the "HX-redirect" header with the redirect location and removes the "Location" header.
|
|
8
|
+
*/
|
|
9
|
+
function htmxRedirectResponse() {
|
|
10
|
+
return async (ctx, next) => {
|
|
11
|
+
await next();
|
|
12
|
+
if (ctx.res.status >= 300 && ctx.res.status < 400) {
|
|
13
|
+
const location = ctx.res.headers.get("Location");
|
|
14
|
+
if (location && checkIsHXRequest(ctx.req.raw)) {
|
|
15
|
+
ctx.res.headers.set("HX-redirect", location);
|
|
16
|
+
ctx.res.headers.delete("Location");
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
//#endregion
|
|
23
|
+
export { htmxRedirectResponse };
|
|
24
|
+
//# sourceMappingURL=response.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"response.mjs","names":[],"sources":["../../src/utils/response.ts"],"sourcesContent":["import type { MiddlewareHandler } from \"hono\";\nimport { checkIsHXRequest } from \"../utils/request.ts\";\n\n/**\n * Middleware to handle htmx redirects.\n * If the response status is a redirect (3xx) and the request is an htmx request,\n * it sets the \"HX-redirect\" header with the redirect location and removes the \"Location\" header.\n */\nexport function htmxRedirectResponse(): MiddlewareHandler {\n return async (ctx, next) => {\n await next();\n if (ctx.res.status >= 300 && ctx.res.status < 400) {\n const location = ctx.res.headers.get(\"Location\");\n if (location && checkIsHXRequest(ctx.req.raw)) {\n ctx.res.headers.set(\"HX-redirect\", location);\n ctx.res.headers.delete(\"Location\");\n }\n }\n };\n}\n"],"mappings":";;;;;;;;AAQA,SAAgB,uBAA0C;AACxD,QAAO,OAAO,KAAK,SAAS;AAC1B,QAAM,MAAM;AACZ,MAAI,IAAI,IAAI,UAAU,OAAO,IAAI,IAAI,SAAS,KAAK;GACjD,MAAM,WAAW,IAAI,IAAI,QAAQ,IAAI,WAAW;AAChD,OAAI,YAAY,iBAAiB,IAAI,IAAI,IAAI,EAAE;AAC7C,QAAI,IAAI,QAAQ,IAAI,eAAe,SAAS;AAC5C,QAAI,IAAI,QAAQ,OAAO,WAAW"}
|