storybooker 0.19.4 → 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
|
@@ -0,0 +1,339 @@
|
|
|
1
|
+
import { createRoute, OpenAPIHono } from "@hono/zod-openapi";
|
|
2
|
+
import { HTTPException } from "hono/http-exception";
|
|
3
|
+
import { z } from "zod";
|
|
4
|
+
import { BuildsModel } from "../models/builds-model.ts";
|
|
5
|
+
import { ProjectsModel } from "../models/projects-model.ts";
|
|
6
|
+
import { ProjectIdSchema } from "../models/projects-schema.ts";
|
|
7
|
+
import { TagsModel } from "../models/tags-model.ts";
|
|
8
|
+
import {
|
|
9
|
+
TagCreateSchema,
|
|
10
|
+
TagIdSchema,
|
|
11
|
+
TagsGetResultSchema,
|
|
12
|
+
TagsListResultSchema,
|
|
13
|
+
TagTypes,
|
|
14
|
+
TagUpdateSchema,
|
|
15
|
+
} from "../models/tags-schema.ts";
|
|
16
|
+
import { urlBuilder } from "../urls.ts";
|
|
17
|
+
import { authenticateOrThrow } from "../utils/auth.ts";
|
|
18
|
+
import { mimes } from "../utils/mime-utils.ts";
|
|
19
|
+
import {
|
|
20
|
+
openapiCommonErrorResponses,
|
|
21
|
+
openapiErrorResponseContent,
|
|
22
|
+
openapiResponseRedirect,
|
|
23
|
+
openapiResponsesHtml,
|
|
24
|
+
} from "../utils/openapi-utils.ts";
|
|
25
|
+
import { checkIsHTMLRequest } from "../utils/request.ts";
|
|
26
|
+
import { getStore } from "../utils/store.ts";
|
|
27
|
+
import { createUIResultResponse } from "../utils/ui-utils.ts";
|
|
28
|
+
|
|
29
|
+
const tagsTag = "Tags";
|
|
30
|
+
const projectIdPathParams = z.object({ projectId: ProjectIdSchema });
|
|
31
|
+
const tagIdPathParams = z.object({
|
|
32
|
+
projectId: ProjectIdSchema,
|
|
33
|
+
tagId: TagIdSchema,
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* @private
|
|
38
|
+
*/
|
|
39
|
+
export const tagsRouter = new OpenAPIHono()
|
|
40
|
+
.openapi(
|
|
41
|
+
createRoute({
|
|
42
|
+
summary: "List tags",
|
|
43
|
+
method: "get",
|
|
44
|
+
path: "/projects/{projectId}/tags",
|
|
45
|
+
tags: [tagsTag],
|
|
46
|
+
request: {
|
|
47
|
+
params: projectIdPathParams,
|
|
48
|
+
query: z.object({ type: z.union([z.enum(TagTypes), z.literal("")]) }).partial(),
|
|
49
|
+
},
|
|
50
|
+
responses: {
|
|
51
|
+
200: {
|
|
52
|
+
description: "A list of tags in the project.",
|
|
53
|
+
content: {
|
|
54
|
+
[mimes.json]: { schema: TagsListResultSchema },
|
|
55
|
+
...openapiResponsesHtml,
|
|
56
|
+
},
|
|
57
|
+
},
|
|
58
|
+
...openapiCommonErrorResponses,
|
|
59
|
+
},
|
|
60
|
+
}),
|
|
61
|
+
async (context) => {
|
|
62
|
+
const { ui } = getStore();
|
|
63
|
+
const { projectId } = context.req.valid("param");
|
|
64
|
+
|
|
65
|
+
authenticateOrThrow({
|
|
66
|
+
action: "read",
|
|
67
|
+
projectId,
|
|
68
|
+
resource: "tag",
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
const { type } = context.req.valid("query");
|
|
72
|
+
const tags = await new TagsModel(projectId).list();
|
|
73
|
+
const filteredTags = type ? tags.filter((tag) => tag.type === type) : tags;
|
|
74
|
+
|
|
75
|
+
if (ui?.renderTagsListPage && checkIsHTMLRequest()) {
|
|
76
|
+
const project = await new ProjectsModel().get(projectId);
|
|
77
|
+
|
|
78
|
+
return createUIResultResponse(context, ui.renderTagsListPage, {
|
|
79
|
+
project,
|
|
80
|
+
tags: filteredTags,
|
|
81
|
+
defaultType: type,
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
return context.json({ tags: filteredTags });
|
|
86
|
+
},
|
|
87
|
+
)
|
|
88
|
+
.openapi(
|
|
89
|
+
createRoute({
|
|
90
|
+
summary: "Create tag - UI",
|
|
91
|
+
method: "get",
|
|
92
|
+
path: "/projects/{projectId}/tags/create",
|
|
93
|
+
tags: [tagsTag],
|
|
94
|
+
request: { params: projectIdPathParams },
|
|
95
|
+
responses: {
|
|
96
|
+
200: {
|
|
97
|
+
description: "UI to create tag",
|
|
98
|
+
content: openapiResponsesHtml,
|
|
99
|
+
},
|
|
100
|
+
...openapiCommonErrorResponses,
|
|
101
|
+
},
|
|
102
|
+
}),
|
|
103
|
+
async (context) => {
|
|
104
|
+
const { ui } = getStore();
|
|
105
|
+
if (!ui?.renderTagCreatePage) {
|
|
106
|
+
throw new HTTPException(405, { message: "UI not available for this route." });
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
const { projectId } = context.req.valid("param");
|
|
110
|
+
|
|
111
|
+
authenticateOrThrow({
|
|
112
|
+
action: "create",
|
|
113
|
+
projectId,
|
|
114
|
+
resource: "tag",
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
const project = await new ProjectsModel().get(projectId);
|
|
118
|
+
|
|
119
|
+
return createUIResultResponse(context, ui.renderTagCreatePage, { project });
|
|
120
|
+
},
|
|
121
|
+
)
|
|
122
|
+
.openapi(
|
|
123
|
+
createRoute({
|
|
124
|
+
summary: "Create tag - action",
|
|
125
|
+
method: "post",
|
|
126
|
+
path: "/projects/{projectId}/tags/create",
|
|
127
|
+
tags: [tagsTag],
|
|
128
|
+
request: {
|
|
129
|
+
params: projectIdPathParams,
|
|
130
|
+
body: {
|
|
131
|
+
content: { [mimes.formEncoded]: { schema: TagCreateSchema } },
|
|
132
|
+
required: true,
|
|
133
|
+
},
|
|
134
|
+
},
|
|
135
|
+
responses: {
|
|
136
|
+
201: {
|
|
137
|
+
description: "Tag created successfully",
|
|
138
|
+
content: { [mimes.json]: { schema: TagsGetResultSchema } },
|
|
139
|
+
},
|
|
140
|
+
303: openapiResponseRedirect("Redirect to tag."),
|
|
141
|
+
409: {
|
|
142
|
+
content: openapiErrorResponseContent,
|
|
143
|
+
description: "Tag already exists.",
|
|
144
|
+
},
|
|
145
|
+
415: {
|
|
146
|
+
content: openapiErrorResponseContent,
|
|
147
|
+
description: "Unsupported Media Type",
|
|
148
|
+
},
|
|
149
|
+
...openapiCommonErrorResponses,
|
|
150
|
+
},
|
|
151
|
+
}),
|
|
152
|
+
async (context) => {
|
|
153
|
+
const { projectId } = context.req.valid("param");
|
|
154
|
+
|
|
155
|
+
const projectModel = new ProjectsModel().id(projectId);
|
|
156
|
+
if (!(await projectModel.has())) {
|
|
157
|
+
throw new HTTPException(404, { message: `The project '${projectId}' does not exist.` });
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
authenticateOrThrow({
|
|
161
|
+
action: "create",
|
|
162
|
+
projectId,
|
|
163
|
+
resource: "tag",
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
const data = context.req.valid("form");
|
|
167
|
+
const tag = await new TagsModel(projectId).create(data);
|
|
168
|
+
|
|
169
|
+
if (checkIsHTMLRequest(true)) {
|
|
170
|
+
return context.redirect(urlBuilder.tagDetails(projectId, tag.id), 303);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
return context.json({ tag }, 201);
|
|
174
|
+
},
|
|
175
|
+
)
|
|
176
|
+
.openapi(
|
|
177
|
+
createRoute({
|
|
178
|
+
summary: "Tag details",
|
|
179
|
+
method: "get",
|
|
180
|
+
path: "/projects/{projectId}/tags/{tagId}",
|
|
181
|
+
tags: [tagsTag],
|
|
182
|
+
request: { params: tagIdPathParams },
|
|
183
|
+
responses: {
|
|
184
|
+
200: {
|
|
185
|
+
description: "Details of the tag",
|
|
186
|
+
content: {
|
|
187
|
+
[mimes.json]: { schema: TagsGetResultSchema },
|
|
188
|
+
...openapiResponsesHtml,
|
|
189
|
+
},
|
|
190
|
+
},
|
|
191
|
+
404: {
|
|
192
|
+
description: "Matching tag not found.",
|
|
193
|
+
content: openapiErrorResponseContent,
|
|
194
|
+
},
|
|
195
|
+
...openapiCommonErrorResponses,
|
|
196
|
+
},
|
|
197
|
+
}),
|
|
198
|
+
async (context) => {
|
|
199
|
+
const { ui } = getStore();
|
|
200
|
+
const { projectId, tagId } = context.req.valid("param");
|
|
201
|
+
|
|
202
|
+
authenticateOrThrow({
|
|
203
|
+
action: "read",
|
|
204
|
+
projectId,
|
|
205
|
+
resource: "tag",
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
const tag = await new TagsModel(projectId).get(tagId);
|
|
209
|
+
|
|
210
|
+
if (ui?.renderTagDetailsPage && checkIsHTMLRequest()) {
|
|
211
|
+
const project = await new ProjectsModel().get(projectId);
|
|
212
|
+
const builds = await new BuildsModel(projectId).listByTag(tag.id);
|
|
213
|
+
|
|
214
|
+
return createUIResultResponse(context, ui.renderTagDetailsPage, { builds, project, tag });
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
return context.json({ tag });
|
|
218
|
+
},
|
|
219
|
+
)
|
|
220
|
+
.openapi(
|
|
221
|
+
createRoute({
|
|
222
|
+
summary: "Delete tag - action",
|
|
223
|
+
method: "post",
|
|
224
|
+
path: "/projects/{projectId}/tags/{tagId}/delete",
|
|
225
|
+
tags: [tagsTag],
|
|
226
|
+
request: { params: tagIdPathParams },
|
|
227
|
+
responses: {
|
|
228
|
+
204: { description: "Tag deleted successfully." },
|
|
229
|
+
303: openapiResponseRedirect("Redirect to tags list."),
|
|
230
|
+
404: {
|
|
231
|
+
description: "Matching tag not found.",
|
|
232
|
+
content: openapiErrorResponseContent,
|
|
233
|
+
},
|
|
234
|
+
...openapiCommonErrorResponses,
|
|
235
|
+
},
|
|
236
|
+
}),
|
|
237
|
+
async (context) => {
|
|
238
|
+
const { projectId, tagId } = context.req.valid("param");
|
|
239
|
+
authenticateOrThrow({
|
|
240
|
+
action: "delete",
|
|
241
|
+
projectId,
|
|
242
|
+
resource: "tag",
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
await new TagsModel(projectId).delete(tagId);
|
|
246
|
+
|
|
247
|
+
if (checkIsHTMLRequest(true)) {
|
|
248
|
+
return context.redirect(urlBuilder.tagsList(projectId), 303);
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
return new Response(null, { status: 204 });
|
|
252
|
+
},
|
|
253
|
+
)
|
|
254
|
+
.openapi(
|
|
255
|
+
createRoute({
|
|
256
|
+
summary: "Update tag - UI",
|
|
257
|
+
method: "get",
|
|
258
|
+
path: "/projects/{projectId}/tags/{tagId}/update",
|
|
259
|
+
tags: [tagsTag],
|
|
260
|
+
request: { params: tagIdPathParams },
|
|
261
|
+
responses: {
|
|
262
|
+
200: {
|
|
263
|
+
description: "UI to upload tag",
|
|
264
|
+
content: openapiResponsesHtml,
|
|
265
|
+
},
|
|
266
|
+
404: {
|
|
267
|
+
description: "Matching tag not found.",
|
|
268
|
+
content: openapiErrorResponseContent,
|
|
269
|
+
},
|
|
270
|
+
...openapiCommonErrorResponses,
|
|
271
|
+
},
|
|
272
|
+
}),
|
|
273
|
+
async (context) => {
|
|
274
|
+
const { ui } = getStore();
|
|
275
|
+
if (!ui?.renderTagUpdatePage) {
|
|
276
|
+
throw new HTTPException(405, { message: "UI not available for this route." });
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
const { tagId, projectId } = context.req.valid("param");
|
|
280
|
+
|
|
281
|
+
authenticateOrThrow({
|
|
282
|
+
action: "update",
|
|
283
|
+
projectId,
|
|
284
|
+
resource: "tag",
|
|
285
|
+
});
|
|
286
|
+
|
|
287
|
+
const tag = await new TagsModel(projectId).get(tagId);
|
|
288
|
+
const project = await new ProjectsModel().get(projectId);
|
|
289
|
+
|
|
290
|
+
return createUIResultResponse(context, ui.renderTagUpdatePage, { project, tag });
|
|
291
|
+
},
|
|
292
|
+
)
|
|
293
|
+
.openapi(
|
|
294
|
+
createRoute({
|
|
295
|
+
summary: "Update tag - action",
|
|
296
|
+
method: "post",
|
|
297
|
+
path: "/projects/{projectId}/tags/{tagId}/update",
|
|
298
|
+
tags: [tagsTag],
|
|
299
|
+
request: {
|
|
300
|
+
params: tagIdPathParams,
|
|
301
|
+
body: {
|
|
302
|
+
content: { [mimes.formEncoded]: { schema: TagUpdateSchema } },
|
|
303
|
+
required: true,
|
|
304
|
+
},
|
|
305
|
+
},
|
|
306
|
+
responses: {
|
|
307
|
+
202: { description: "Tag updated successfully" },
|
|
308
|
+
303: openapiResponseRedirect("Redirect to tag."),
|
|
309
|
+
404: {
|
|
310
|
+
description: "Matching project or tag not found.",
|
|
311
|
+
content: openapiErrorResponseContent,
|
|
312
|
+
},
|
|
313
|
+
415: {
|
|
314
|
+
content: openapiErrorResponseContent,
|
|
315
|
+
description: "Unsupported Media Type",
|
|
316
|
+
},
|
|
317
|
+
...openapiCommonErrorResponses,
|
|
318
|
+
},
|
|
319
|
+
}),
|
|
320
|
+
async (context) => {
|
|
321
|
+
const { tagId, projectId } = context.req.valid("param");
|
|
322
|
+
|
|
323
|
+
const tagsModel = new TagsModel(projectId);
|
|
324
|
+
authenticateOrThrow({
|
|
325
|
+
action: "update",
|
|
326
|
+
projectId,
|
|
327
|
+
resource: "tag",
|
|
328
|
+
});
|
|
329
|
+
|
|
330
|
+
const data = context.req.valid("form");
|
|
331
|
+
await tagsModel.update(tagId, data);
|
|
332
|
+
|
|
333
|
+
if (checkIsHTMLRequest(true)) {
|
|
334
|
+
return context.redirect(urlBuilder.tagDetails(projectId, tagId), 303);
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
return new Response(null, { status: 202 });
|
|
338
|
+
},
|
|
339
|
+
);
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { createRoute, OpenAPIHono, z } from "@hono/zod-openapi";
|
|
2
|
+
import { HTTPException } from "hono/http-exception";
|
|
3
|
+
import { handleProcessZip } from "../handlers/handle-process-zip.ts";
|
|
4
|
+
import { handlePurge } from "../handlers/handle-purge.ts";
|
|
5
|
+
import { buildUploadVariants } from "../models/builds-schema.ts";
|
|
6
|
+
import { urlBuilder } from "../urls.ts";
|
|
7
|
+
import { authenticateOrThrow } from "../utils/auth.ts";
|
|
8
|
+
import { checkIsHTMLRequest } from "../utils/request.ts";
|
|
9
|
+
|
|
10
|
+
const tasksTag = "Tasks";
|
|
11
|
+
|
|
12
|
+
const processZipSearchParams = z
|
|
13
|
+
.object({
|
|
14
|
+
projectId: z.string(),
|
|
15
|
+
buildId: z.string(),
|
|
16
|
+
variant: z.enum(buildUploadVariants),
|
|
17
|
+
})
|
|
18
|
+
.loose();
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* @private
|
|
22
|
+
*/
|
|
23
|
+
export const tasksRouter = new OpenAPIHono()
|
|
24
|
+
.openapi(
|
|
25
|
+
createRoute({
|
|
26
|
+
summary: "Purge outdated builds",
|
|
27
|
+
method: "post",
|
|
28
|
+
path: "/purge",
|
|
29
|
+
tags: [tasksTag],
|
|
30
|
+
request: { query: z.object({ projectId: z.string() }).partial().loose() },
|
|
31
|
+
responses: { 204: { description: "Purge complete" } },
|
|
32
|
+
}),
|
|
33
|
+
async (context) => {
|
|
34
|
+
const { projectId } = context.req.valid("query");
|
|
35
|
+
|
|
36
|
+
authenticateOrThrow({ action: "update", projectId, resource: "project" });
|
|
37
|
+
authenticateOrThrow({ action: "delete", projectId, resource: "build" });
|
|
38
|
+
authenticateOrThrow({ action: "delete", projectId, resource: "tag" });
|
|
39
|
+
|
|
40
|
+
await handlePurge({ projectId }, { abortSignal: context.req.raw.signal });
|
|
41
|
+
|
|
42
|
+
return new Response(null, { status: 204 });
|
|
43
|
+
},
|
|
44
|
+
)
|
|
45
|
+
.openapi(
|
|
46
|
+
createRoute({
|
|
47
|
+
summary: "Process uploaded zip files",
|
|
48
|
+
method: "post",
|
|
49
|
+
path: "/process-zip",
|
|
50
|
+
tags: [tasksTag],
|
|
51
|
+
request: { query: processZipSearchParams },
|
|
52
|
+
responses: {
|
|
53
|
+
204: { description: "Request to process zip file accepter" },
|
|
54
|
+
},
|
|
55
|
+
}),
|
|
56
|
+
async (context) => {
|
|
57
|
+
const { buildId, projectId, variant } = context.req.valid("query");
|
|
58
|
+
|
|
59
|
+
try {
|
|
60
|
+
await handleProcessZip(projectId, buildId, variant);
|
|
61
|
+
|
|
62
|
+
if (checkIsHTMLRequest(true)) {
|
|
63
|
+
return context.redirect(urlBuilder.buildDetails(projectId, buildId), 303);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
context.status(204);
|
|
67
|
+
return context.res;
|
|
68
|
+
} catch (error) {
|
|
69
|
+
throw new HTTPException(500, {
|
|
70
|
+
cause: error,
|
|
71
|
+
message: "Failed to process uploaded zip file.",
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
},
|
|
75
|
+
);
|
package/src/types.ts
ADDED
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import type { MiddlewareHandler } from "hono";
|
|
2
|
+
import type {
|
|
3
|
+
AuthAdapter,
|
|
4
|
+
DatabaseAdapter,
|
|
5
|
+
LoggerAdapter,
|
|
6
|
+
StorageAdapter,
|
|
7
|
+
StoryBookerUser,
|
|
8
|
+
UIAdapter,
|
|
9
|
+
} from "./adapters/_internal/index.ts";
|
|
10
|
+
import type { ErrorParser } from "./utils/error.ts";
|
|
11
|
+
|
|
12
|
+
export type {
|
|
13
|
+
StoryBookerUser,
|
|
14
|
+
StoryBookerPermissionAction,
|
|
15
|
+
StoryBookerPermissionKey,
|
|
16
|
+
StoryBookerPermissionResource,
|
|
17
|
+
StoryBookerPermissionWithKey,
|
|
18
|
+
} from "./adapters/_internal/auth.ts";
|
|
19
|
+
export type {
|
|
20
|
+
BuildCreateType,
|
|
21
|
+
BuildStoryType,
|
|
22
|
+
BuildType,
|
|
23
|
+
BuildUpdateType,
|
|
24
|
+
BuildUploadVariant,
|
|
25
|
+
BuildsGetResultType,
|
|
26
|
+
BuildsListResultType,
|
|
27
|
+
} from "./models/builds-schema.ts";
|
|
28
|
+
export type {
|
|
29
|
+
ProjectCreateType,
|
|
30
|
+
ProjectGetResultType,
|
|
31
|
+
ProjectUpdateType,
|
|
32
|
+
ProjectType,
|
|
33
|
+
ProjectsListResultType,
|
|
34
|
+
} from "./models/projects-schema.ts";
|
|
35
|
+
export type {
|
|
36
|
+
TagCreateType,
|
|
37
|
+
TagType,
|
|
38
|
+
TagUpdateType,
|
|
39
|
+
TagVariant,
|
|
40
|
+
TagsGetResultType,
|
|
41
|
+
TagsListResultType,
|
|
42
|
+
} from "./models/tags-schema.ts";
|
|
43
|
+
export type { ErrorParser, ParsedError } from "./utils/error.ts";
|
|
44
|
+
export type { UrlBuilder } from "./urls.ts";
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Options for creating a router.
|
|
48
|
+
*/
|
|
49
|
+
export interface RouterOptions<User extends StoryBookerUser> {
|
|
50
|
+
/** Adapter for Auth service. Provides authentication to the service. */
|
|
51
|
+
auth?: AuthAdapter<User>;
|
|
52
|
+
/** Adapter for Database service. Provides access to storing data to the service. */
|
|
53
|
+
database: DatabaseAdapter;
|
|
54
|
+
/** Additional options to configure the router. */
|
|
55
|
+
config?: RouterConfig;
|
|
56
|
+
/** Adapter for Logging service. Provides option to direct the logging of the service. */
|
|
57
|
+
logger?: LoggerAdapter;
|
|
58
|
+
/** Adapter for Storage service. Provides access to storing files to the service. */
|
|
59
|
+
storage: StorageAdapter;
|
|
60
|
+
/** Options to customise StoryBooker UI. */
|
|
61
|
+
ui?: UIAdapter;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Options for creating a purge handler.
|
|
66
|
+
*/
|
|
67
|
+
export interface PurgeHandlerOptions {
|
|
68
|
+
/** Adapter for Database service. Provides access to storing data to the service. */
|
|
69
|
+
database: DatabaseAdapter;
|
|
70
|
+
/**
|
|
71
|
+
* A function for parsing custom errors.
|
|
72
|
+
* Return `undefined` from parser if the service should handle the error.
|
|
73
|
+
*/
|
|
74
|
+
errorParser?: ErrorParser;
|
|
75
|
+
/** Adapter for Logging service. Provides option to direct the logging of the service. */
|
|
76
|
+
logger?: LoggerAdapter;
|
|
77
|
+
/** Adapter for Storage service. Provides access to storing files to the service. */
|
|
78
|
+
storage: StorageAdapter;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/** Additional options to configure the router. */
|
|
82
|
+
export interface RouterConfig {
|
|
83
|
+
/**
|
|
84
|
+
* A function for parsing custom errors.
|
|
85
|
+
* Return `undefined` from parser if the service should handle the error.
|
|
86
|
+
*/
|
|
87
|
+
errorParser?: ErrorParser;
|
|
88
|
+
/**
|
|
89
|
+
* Maximum upload size in bytes for processing zip files while uploading.
|
|
90
|
+
* @default "5 * 1024 * 1024" (5MB)
|
|
91
|
+
*/
|
|
92
|
+
maxInlineUploadProcessingSizeInBytes?: number;
|
|
93
|
+
/**
|
|
94
|
+
* Enable queueing of zip file processing for files larger than the maximum inline upload processing size.
|
|
95
|
+
* Requires QueueAdapter and other setup.
|
|
96
|
+
* @default false
|
|
97
|
+
*/
|
|
98
|
+
queueLargeZipFileProcessing?: boolean;
|
|
99
|
+
/**
|
|
100
|
+
* Convey URL prefix to the service if the router is not hosted on the root.
|
|
101
|
+
*/
|
|
102
|
+
prefix?: string;
|
|
103
|
+
/**
|
|
104
|
+
* Add Hono middlewares to the router before any endpoint is registered/invoked.
|
|
105
|
+
*/
|
|
106
|
+
middlewares?: MiddlewareHandler[];
|
|
107
|
+
}
|