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.
Files changed (215) hide show
  1. package/README.md +40 -18
  2. package/dist/adapters/_internal/queue.d.mts +127 -0
  3. package/dist/aws-dynamodb.d.mts +22 -0
  4. package/dist/aws-dynamodb.mjs +118 -0
  5. package/dist/aws-dynamodb.mjs.map +1 -0
  6. package/dist/aws-s3.d.mts +20 -0
  7. package/dist/aws-s3.mjs +96 -0
  8. package/dist/aws-s3.mjs.map +1 -0
  9. package/dist/azure-blob-storage.d.mts +20 -0
  10. package/dist/azure-blob-storage.mjs +126 -0
  11. package/dist/azure-blob-storage.mjs.map +1 -0
  12. package/dist/azure-cosmos-db.d.mts +23 -0
  13. package/dist/azure-cosmos-db.mjs +87 -0
  14. package/dist/azure-cosmos-db.mjs.map +1 -0
  15. package/dist/azure-data-tables.d.mts +23 -0
  16. package/dist/azure-data-tables.mjs +127 -0
  17. package/dist/azure-data-tables.mjs.map +1 -0
  18. package/dist/azure-easy-auth.d.mts +50 -0
  19. package/dist/azure-easy-auth.mjs +88 -0
  20. package/dist/azure-easy-auth.mjs.map +1 -0
  21. package/dist/azure-functions.d.mts +62 -0
  22. package/dist/azure-functions.mjs +147 -0
  23. package/dist/azure-functions.mjs.map +1 -0
  24. package/dist/fs.d.mts +37 -0
  25. package/dist/fs.mjs +240 -0
  26. package/dist/fs.mjs.map +1 -0
  27. package/dist/gcp-big-table.d.mts +23 -0
  28. package/dist/gcp-big-table.mjs +92 -0
  29. package/dist/gcp-big-table.mjs.map +1 -0
  30. package/dist/gcp-firestore.d.mts +22 -0
  31. package/dist/gcp-firestore.mjs +87 -0
  32. package/dist/gcp-firestore.mjs.map +1 -0
  33. package/dist/gcp-storage.d.mts +20 -0
  34. package/dist/gcp-storage.mjs +96 -0
  35. package/dist/gcp-storage.mjs.map +1 -0
  36. package/dist/handlers/handle-process-zip.mjs +90 -0
  37. package/dist/handlers/handle-process-zip.mjs.map +1 -0
  38. package/dist/handlers/handle-purge.d.mts +12 -0
  39. package/dist/handlers/handle-purge.mjs +36 -0
  40. package/dist/handlers/handle-purge.mjs.map +1 -0
  41. package/dist/handlers/handle-serve-storybook.mjs +94 -0
  42. package/dist/handlers/handle-serve-storybook.mjs.map +1 -0
  43. package/dist/index.d.mts +28 -0
  44. package/dist/index.mjs +62 -0
  45. package/dist/index.mjs.map +1 -0
  46. package/dist/models/builds-model.mjs +248 -0
  47. package/dist/models/builds-model.mjs.map +1 -0
  48. package/dist/models/builds-schema.d.mts +171 -0
  49. package/dist/models/builds-schema.mjs +67 -0
  50. package/dist/models/builds-schema.mjs.map +1 -0
  51. package/dist/models/projects-model.mjs +122 -0
  52. package/dist/models/projects-model.mjs.map +1 -0
  53. package/dist/models/projects-schema.d.mts +70 -0
  54. package/dist/models/projects-schema.mjs +37 -0
  55. package/dist/models/projects-schema.mjs.map +1 -0
  56. package/dist/models/tags-model.mjs +110 -0
  57. package/dist/models/tags-model.mjs.map +1 -0
  58. package/dist/models/tags-schema.d.mts +76 -0
  59. package/dist/models/tags-schema.mjs +34 -0
  60. package/dist/models/tags-schema.mjs.map +1 -0
  61. package/dist/models/~model.mjs +43 -0
  62. package/dist/models/~model.mjs.map +1 -0
  63. package/dist/models/~shared-schema.d.mts +1 -0
  64. package/dist/models/~shared-schema.mjs +20 -0
  65. package/dist/models/~shared-schema.mjs.map +1 -0
  66. package/dist/mysql.d.mts +39 -0
  67. package/dist/mysql.mjs +151 -0
  68. package/dist/mysql.mjs.map +1 -0
  69. package/dist/redis.d.mts +33 -0
  70. package/dist/redis.mjs +118 -0
  71. package/dist/redis.mjs.map +1 -0
  72. package/dist/routers/account-router.mjs +91 -0
  73. package/dist/routers/account-router.mjs.map +1 -0
  74. package/dist/routers/builds-router.mjs +347 -0
  75. package/dist/routers/builds-router.mjs.map +1 -0
  76. package/dist/routers/projects-router.mjs +236 -0
  77. package/dist/routers/projects-router.mjs.map +1 -0
  78. package/dist/routers/root-router.mjs +108 -0
  79. package/dist/routers/root-router.mjs.map +1 -0
  80. package/dist/routers/tags-router.mjs +269 -0
  81. package/dist/routers/tags-router.mjs.map +1 -0
  82. package/dist/routers/tasks-router.mjs +71 -0
  83. package/dist/routers/tasks-router.mjs.map +1 -0
  84. package/dist/urls.d.mts +47 -0
  85. package/dist/urls.mjs +208 -0
  86. package/dist/urls.mjs.map +1 -0
  87. package/dist/utils/adapter-utils.d.mts +14 -0
  88. package/dist/utils/adapter-utils.mjs +14 -0
  89. package/dist/utils/adapter-utils.mjs.map +1 -0
  90. package/dist/utils/auth.mjs +25 -0
  91. package/dist/utils/auth.mjs.map +1 -0
  92. package/dist/utils/error.d.mts +21 -0
  93. package/dist/utils/error.mjs +109 -0
  94. package/dist/utils/error.mjs.map +1 -0
  95. package/dist/utils/file-utils.mjs +16 -0
  96. package/dist/utils/file-utils.mjs.map +1 -0
  97. package/dist/utils/openapi-utils.mjs +45 -0
  98. package/dist/utils/openapi-utils.mjs.map +1 -0
  99. package/dist/utils/request.mjs +35 -0
  100. package/dist/utils/request.mjs.map +1 -0
  101. package/dist/utils/response.mjs +24 -0
  102. package/dist/utils/response.mjs.map +1 -0
  103. package/dist/utils/store.mjs +54 -0
  104. package/dist/utils/store.mjs.map +1 -0
  105. package/dist/utils/ui-utils.mjs +38 -0
  106. package/dist/utils/ui-utils.mjs.map +1 -0
  107. package/dist/utils/url-utils.d.mts +10 -0
  108. package/dist/utils/url-utils.mjs +54 -0
  109. package/dist/utils/url-utils.mjs.map +1 -0
  110. package/dist/~internal/adapter/auth.d.mts +123 -0
  111. package/dist/~internal/adapter/auth.mjs +20 -0
  112. package/dist/~internal/adapter/auth.mjs.map +1 -0
  113. package/dist/~internal/adapter/database.d.mts +240 -0
  114. package/dist/~internal/adapter/database.mjs +63 -0
  115. package/dist/~internal/adapter/database.mjs.map +1 -0
  116. package/dist/~internal/adapter/logger.d.mts +34 -0
  117. package/dist/~internal/adapter/logger.mjs +13 -0
  118. package/dist/~internal/adapter/logger.mjs.map +1 -0
  119. package/dist/~internal/adapter/storage.d.mts +208 -0
  120. package/dist/~internal/adapter/storage.mjs +63 -0
  121. package/dist/~internal/adapter/storage.mjs.map +1 -0
  122. package/dist/~internal/adapter/ui.d.mts +109 -0
  123. package/dist/~internal/adapter/ui.mjs +1 -0
  124. package/dist/~internal/adapter.d.mts +8 -0
  125. package/dist/~internal/adapter.mjs +6 -0
  126. package/dist/~internal/constants.d.mts +24 -0
  127. package/dist/~internal/constants.mjs +32 -0
  128. package/dist/~internal/constants.mjs.map +1 -0
  129. package/dist/~internal/mimes.d.mts +449 -0
  130. package/dist/~internal/mimes.mjs +454 -0
  131. package/dist/~internal/mimes.mjs.map +1 -0
  132. package/dist/~internal/router.d.mts +1651 -0
  133. package/dist/~internal/router.mjs +39 -0
  134. package/dist/~internal/router.mjs.map +1 -0
  135. package/dist/~internal/types.d.mts +77 -0
  136. package/dist/~internal/types.mjs +1 -0
  137. package/dist/~internal/utils.d.mts +4 -0
  138. package/dist/~internal/utils.mjs +5 -0
  139. package/openapi.json +3162 -0
  140. package/package.json +148 -27
  141. package/src/adapters/_internal/auth.ts +135 -0
  142. package/src/adapters/_internal/database.ts +241 -0
  143. package/src/adapters/_internal/index.ts +8 -0
  144. package/src/adapters/_internal/logger.ts +41 -0
  145. package/src/adapters/_internal/queue.ts +151 -0
  146. package/src/adapters/_internal/storage.ts +197 -0
  147. package/src/adapters/_internal/ui.ts +103 -0
  148. package/src/adapters/aws-dynamodb.ts +201 -0
  149. package/src/adapters/aws-s3.ts +160 -0
  150. package/src/adapters/azure-blob-storage.ts +223 -0
  151. package/src/adapters/azure-cosmos-db.ts +158 -0
  152. package/src/adapters/azure-data-tables.ts +223 -0
  153. package/src/adapters/azure-easy-auth.ts +174 -0
  154. package/src/adapters/azure-functions.ts +242 -0
  155. package/src/adapters/fs.ts +398 -0
  156. package/src/adapters/gcp-big-table.ts +157 -0
  157. package/src/adapters/gcp-firestore.ts +146 -0
  158. package/src/adapters/gcp-storage.ts +141 -0
  159. package/src/adapters/mysql.ts +296 -0
  160. package/src/adapters/redis.ts +242 -0
  161. package/src/handlers/handle-process-zip.ts +117 -0
  162. package/src/handlers/handle-purge.ts +65 -0
  163. package/src/handlers/handle-serve-storybook.ts +101 -0
  164. package/src/index.ts +81 -16
  165. package/src/mocks/mock-auth-service.ts +51 -0
  166. package/src/mocks/mock-store.ts +26 -0
  167. package/src/models/builds-model.ts +373 -0
  168. package/src/models/builds-schema.ts +84 -0
  169. package/src/models/projects-model.ts +177 -0
  170. package/src/models/projects-schema.ts +69 -0
  171. package/src/models/tags-model.ts +138 -0
  172. package/src/models/tags-schema.ts +45 -0
  173. package/src/models/~model.ts +79 -0
  174. package/src/models/~shared-schema.ts +14 -0
  175. package/src/routers/_app-router.ts +57 -0
  176. package/src/routers/account-router.ts +136 -0
  177. package/src/routers/builds-router.ts +464 -0
  178. package/src/routers/projects-router.ts +309 -0
  179. package/src/routers/root-router.ts +127 -0
  180. package/src/routers/tags-router.ts +339 -0
  181. package/src/routers/tasks-router.ts +75 -0
  182. package/src/types.ts +107 -0
  183. package/src/urls.ts +327 -0
  184. package/src/utils/adapter-utils.ts +26 -0
  185. package/src/utils/auth.test.ts +71 -0
  186. package/src/utils/auth.ts +39 -0
  187. package/src/utils/constants.ts +31 -0
  188. package/src/utils/date-utils.ts +10 -0
  189. package/src/utils/error.test.ts +86 -0
  190. package/src/utils/error.ts +140 -0
  191. package/src/utils/file-utils.test.ts +65 -0
  192. package/src/utils/file-utils.ts +43 -0
  193. package/src/utils/index.ts +3 -0
  194. package/src/utils/mime-utils.ts +457 -0
  195. package/src/utils/openapi-utils.ts +49 -0
  196. package/src/utils/request.ts +97 -0
  197. package/src/utils/response.ts +20 -0
  198. package/src/utils/store.ts +85 -0
  199. package/src/utils/story-utils.ts +42 -0
  200. package/src/utils/text-utils.ts +10 -0
  201. package/src/utils/ui-utils.ts +57 -0
  202. package/src/utils/url-utils.ts +113 -0
  203. package/dist/index.js +0 -554
  204. package/src/commands/create.ts +0 -263
  205. package/src/commands/purge.ts +0 -70
  206. package/src/commands/test.ts +0 -42
  207. package/src/service-schema.d.ts +0 -2023
  208. package/src/utils/auth-utils.ts +0 -31
  209. package/src/utils/pkg-utils.ts +0 -37
  210. package/src/utils/sb-build.ts +0 -55
  211. package/src/utils/sb-test.ts +0 -115
  212. package/src/utils/schema-utils.ts +0 -123
  213. package/src/utils/stream-utils.ts +0 -72
  214. package/src/utils/types.ts +0 -4
  215. 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"}