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,347 @@
|
|
|
1
|
+
import { QUERY_PARAMS } from "../~internal/constants.mjs";
|
|
2
|
+
import { mimes } from "../~internal/mimes.mjs";
|
|
3
|
+
import { getStore } from "../utils/store.mjs";
|
|
4
|
+
import { urlBuilder } from "../urls.mjs";
|
|
5
|
+
import { authenticateOrThrow } from "../utils/auth.mjs";
|
|
6
|
+
import { BuildIdSchema, ProjectIdSchema } from "../models/~shared-schema.mjs";
|
|
7
|
+
import { BuildCreateSchema, BuildUpdateSchema, BuildUploadFormBodySchema, BuildUploadQueryParamsSchema, BuildsGetResultSchema, BuildsListResultSchema } from "../models/builds-schema.mjs";
|
|
8
|
+
import "../models/projects-schema.mjs";
|
|
9
|
+
import { checkIsHTMLRequest, validateBuildUploadZipBody } from "../utils/request.mjs";
|
|
10
|
+
import { createUIResultResponse } from "../utils/ui-utils.mjs";
|
|
11
|
+
import { ProjectsModel } from "../models/projects-model.mjs";
|
|
12
|
+
import { BuildsModel } from "../models/builds-model.mjs";
|
|
13
|
+
import { openapiCommonErrorResponses, openapiErrorResponseContent, openapiResponseRedirect, openapiResponsesHtml } from "../utils/openapi-utils.mjs";
|
|
14
|
+
import { SuperHeaders } from "@remix-run/headers";
|
|
15
|
+
import { HTTPException } from "hono/http-exception";
|
|
16
|
+
import { OpenAPIHono, createRoute } from "@hono/zod-openapi";
|
|
17
|
+
import { z as z$1 } from "zod";
|
|
18
|
+
|
|
19
|
+
//#region src/routers/builds-router.ts
|
|
20
|
+
const buildTag = "Builds";
|
|
21
|
+
const projectIdPathParams = z$1.object({ projectId: ProjectIdSchema });
|
|
22
|
+
const buildIdPathParams = z$1.object({
|
|
23
|
+
projectId: ProjectIdSchema,
|
|
24
|
+
buildId: BuildIdSchema
|
|
25
|
+
});
|
|
26
|
+
/**
|
|
27
|
+
* @private
|
|
28
|
+
*/
|
|
29
|
+
const buildsRouter = new OpenAPIHono().openapi(createRoute({
|
|
30
|
+
summary: "List builds",
|
|
31
|
+
method: "get",
|
|
32
|
+
path: "/projects/{projectId}/builds",
|
|
33
|
+
tags: [buildTag],
|
|
34
|
+
request: { params: projectIdPathParams },
|
|
35
|
+
responses: {
|
|
36
|
+
200: {
|
|
37
|
+
description: "A list of builds in the project.",
|
|
38
|
+
content: {
|
|
39
|
+
[mimes.json]: { schema: BuildsListResultSchema },
|
|
40
|
+
...openapiResponsesHtml
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
...openapiCommonErrorResponses
|
|
44
|
+
}
|
|
45
|
+
}), async (context) => {
|
|
46
|
+
const { projectId } = context.req.valid("param");
|
|
47
|
+
const { ui } = getStore();
|
|
48
|
+
authenticateOrThrow({
|
|
49
|
+
action: "read",
|
|
50
|
+
projectId,
|
|
51
|
+
resource: "build"
|
|
52
|
+
});
|
|
53
|
+
const builds = await new BuildsModel(projectId).list();
|
|
54
|
+
if (ui?.renderBuildsListPage && checkIsHTMLRequest()) {
|
|
55
|
+
const project = await new ProjectsModel().get(projectId);
|
|
56
|
+
return createUIResultResponse(context, ui.renderBuildsListPage, {
|
|
57
|
+
builds,
|
|
58
|
+
project
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
return context.json({ builds });
|
|
62
|
+
}).openapi(createRoute({
|
|
63
|
+
summary: "Create build - UI",
|
|
64
|
+
method: "get",
|
|
65
|
+
path: "/projects/{projectId}/builds/create",
|
|
66
|
+
tags: [buildTag],
|
|
67
|
+
request: {
|
|
68
|
+
params: projectIdPathParams,
|
|
69
|
+
query: z$1.object({ [QUERY_PARAMS.tagId]: z$1.string().optional() })
|
|
70
|
+
},
|
|
71
|
+
responses: {
|
|
72
|
+
200: {
|
|
73
|
+
description: "UI to create build",
|
|
74
|
+
content: openapiResponsesHtml
|
|
75
|
+
},
|
|
76
|
+
...openapiCommonErrorResponses
|
|
77
|
+
}
|
|
78
|
+
}), async (context) => {
|
|
79
|
+
const { ui } = getStore();
|
|
80
|
+
if (!ui?.renderBuildCreatePage) throw new HTTPException(405, { message: "UI not available for this route." });
|
|
81
|
+
const { projectId } = context.req.valid("param");
|
|
82
|
+
const { tagId } = context.req.valid("query");
|
|
83
|
+
authenticateOrThrow({
|
|
84
|
+
action: "create",
|
|
85
|
+
projectId,
|
|
86
|
+
resource: "build"
|
|
87
|
+
});
|
|
88
|
+
const project = await new ProjectsModel().get(projectId);
|
|
89
|
+
return createUIResultResponse(context, ui.renderBuildCreatePage, {
|
|
90
|
+
project,
|
|
91
|
+
tagId
|
|
92
|
+
});
|
|
93
|
+
}).openapi(createRoute({
|
|
94
|
+
summary: "Create build - action",
|
|
95
|
+
method: "post",
|
|
96
|
+
path: "/projects/{projectId}/builds/create",
|
|
97
|
+
tags: [buildTag],
|
|
98
|
+
request: {
|
|
99
|
+
params: projectIdPathParams,
|
|
100
|
+
body: {
|
|
101
|
+
content: { [mimes.formEncoded]: { schema: BuildCreateSchema } },
|
|
102
|
+
required: true
|
|
103
|
+
}
|
|
104
|
+
},
|
|
105
|
+
responses: {
|
|
106
|
+
201: {
|
|
107
|
+
description: "Build created successfully",
|
|
108
|
+
content: { [mimes.json]: { schema: BuildsGetResultSchema } }
|
|
109
|
+
},
|
|
110
|
+
303: openapiResponseRedirect("Redirect to build."),
|
|
111
|
+
409: {
|
|
112
|
+
content: openapiErrorResponseContent,
|
|
113
|
+
description: "Build already exists."
|
|
114
|
+
},
|
|
115
|
+
415: {
|
|
116
|
+
content: openapiErrorResponseContent,
|
|
117
|
+
description: "Unsupported Media Type"
|
|
118
|
+
},
|
|
119
|
+
...openapiCommonErrorResponses
|
|
120
|
+
}
|
|
121
|
+
}), async (context) => {
|
|
122
|
+
const { projectId } = context.req.valid("param");
|
|
123
|
+
if (!await new ProjectsModel().id(projectId).has()) throw new HTTPException(404, { message: `The project '${projectId}' does not exist.` });
|
|
124
|
+
authenticateOrThrow({
|
|
125
|
+
action: "create",
|
|
126
|
+
projectId,
|
|
127
|
+
resource: "build"
|
|
128
|
+
});
|
|
129
|
+
const data = context.req.valid("form");
|
|
130
|
+
const build = await new BuildsModel(projectId).create(data);
|
|
131
|
+
const url = urlBuilder.buildDetails(projectId, build.id);
|
|
132
|
+
if (checkIsHTMLRequest(true)) return context.redirect(url, 303);
|
|
133
|
+
return context.json({
|
|
134
|
+
build,
|
|
135
|
+
url
|
|
136
|
+
}, 201);
|
|
137
|
+
}).openapi(createRoute({
|
|
138
|
+
summary: "Build details",
|
|
139
|
+
method: "get",
|
|
140
|
+
path: "/projects/{projectId}/builds/{buildId}",
|
|
141
|
+
tags: [buildTag],
|
|
142
|
+
request: { params: buildIdPathParams },
|
|
143
|
+
responses: {
|
|
144
|
+
200: {
|
|
145
|
+
description: "Details of the build",
|
|
146
|
+
content: {
|
|
147
|
+
[mimes.json]: { schema: BuildsGetResultSchema },
|
|
148
|
+
...openapiResponsesHtml
|
|
149
|
+
}
|
|
150
|
+
},
|
|
151
|
+
404: {
|
|
152
|
+
description: "Matching build not found.",
|
|
153
|
+
content: openapiErrorResponseContent
|
|
154
|
+
},
|
|
155
|
+
...openapiCommonErrorResponses
|
|
156
|
+
}
|
|
157
|
+
}), async (context) => {
|
|
158
|
+
const { projectId, buildId } = context.req.valid("param");
|
|
159
|
+
const { ui } = getStore();
|
|
160
|
+
authenticateOrThrow({
|
|
161
|
+
action: "read",
|
|
162
|
+
projectId,
|
|
163
|
+
resource: "build"
|
|
164
|
+
});
|
|
165
|
+
const model = new BuildsModel(projectId);
|
|
166
|
+
const build = await model.get(buildId);
|
|
167
|
+
if (ui?.renderBuildDetailsPage && checkIsHTMLRequest()) {
|
|
168
|
+
const project = await new ProjectsModel().get(projectId);
|
|
169
|
+
const stories = await model.getStories(build);
|
|
170
|
+
return createUIResultResponse(context, ui.renderBuildDetailsPage, {
|
|
171
|
+
build,
|
|
172
|
+
stories,
|
|
173
|
+
project
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
return context.json({
|
|
177
|
+
build,
|
|
178
|
+
url: context.req.url
|
|
179
|
+
});
|
|
180
|
+
}).openapi(createRoute({
|
|
181
|
+
summary: "Delete build - action",
|
|
182
|
+
method: "post",
|
|
183
|
+
path: "/projects/{projectId}/builds/{buildId}/delete",
|
|
184
|
+
tags: [buildTag],
|
|
185
|
+
request: { params: buildIdPathParams },
|
|
186
|
+
responses: {
|
|
187
|
+
204: { description: "Build deleted successfully." },
|
|
188
|
+
303: openapiResponseRedirect("Redirect to builds list."),
|
|
189
|
+
404: {
|
|
190
|
+
description: "Matching build not found.",
|
|
191
|
+
content: openapiErrorResponseContent
|
|
192
|
+
},
|
|
193
|
+
...openapiCommonErrorResponses
|
|
194
|
+
}
|
|
195
|
+
}), async (context) => {
|
|
196
|
+
const { projectId, buildId } = context.req.valid("param");
|
|
197
|
+
authenticateOrThrow({
|
|
198
|
+
action: "delete",
|
|
199
|
+
projectId,
|
|
200
|
+
resource: "build"
|
|
201
|
+
});
|
|
202
|
+
await new BuildsModel(projectId).delete(buildId, true);
|
|
203
|
+
if (checkIsHTMLRequest(true)) return context.redirect(urlBuilder.buildsList(projectId), 303);
|
|
204
|
+
return new Response(null, { status: 204 });
|
|
205
|
+
}).openapi(createRoute({
|
|
206
|
+
summary: "Update build - action",
|
|
207
|
+
method: "post",
|
|
208
|
+
path: "/projects/{projectId}/builds/{buildId}/update",
|
|
209
|
+
tags: [buildTag],
|
|
210
|
+
request: {
|
|
211
|
+
params: buildIdPathParams,
|
|
212
|
+
body: {
|
|
213
|
+
content: { [mimes.formEncoded]: { schema: BuildUpdateSchema } },
|
|
214
|
+
required: true
|
|
215
|
+
}
|
|
216
|
+
},
|
|
217
|
+
responses: {
|
|
218
|
+
202: { description: "Build updated successfully" },
|
|
219
|
+
303: openapiResponseRedirect("Redirect to build."),
|
|
220
|
+
404: {
|
|
221
|
+
description: "Matching project or build not found.",
|
|
222
|
+
content: openapiErrorResponseContent
|
|
223
|
+
},
|
|
224
|
+
415: {
|
|
225
|
+
content: openapiErrorResponseContent,
|
|
226
|
+
description: "Unsupported Media Type"
|
|
227
|
+
},
|
|
228
|
+
...openapiCommonErrorResponses
|
|
229
|
+
}
|
|
230
|
+
}), async (context) => {
|
|
231
|
+
const { buildId, projectId } = context.req.valid("param");
|
|
232
|
+
const buildsModel = new BuildsModel(projectId);
|
|
233
|
+
if (!await buildsModel.has(buildId)) throw new HTTPException(404, { message: `The build '${buildId}' does not exist in project '${projectId}'.` });
|
|
234
|
+
authenticateOrThrow({
|
|
235
|
+
action: "update",
|
|
236
|
+
projectId,
|
|
237
|
+
resource: "build"
|
|
238
|
+
});
|
|
239
|
+
const data = context.req.valid("form");
|
|
240
|
+
await buildsModel.update(buildId, data);
|
|
241
|
+
if (checkIsHTMLRequest(true)) return context.redirect(urlBuilder.buildDetails(projectId, buildId), 303);
|
|
242
|
+
return new Response(null, { status: 202 });
|
|
243
|
+
}).openapi(createRoute({
|
|
244
|
+
summary: "Upload build - UI",
|
|
245
|
+
method: "get",
|
|
246
|
+
path: "/projects/{projectId}/builds/{buildId}/upload",
|
|
247
|
+
tags: [buildTag],
|
|
248
|
+
request: {
|
|
249
|
+
params: buildIdPathParams,
|
|
250
|
+
query: BuildUploadQueryParamsSchema
|
|
251
|
+
},
|
|
252
|
+
responses: {
|
|
253
|
+
200: {
|
|
254
|
+
description: "UI to upload build",
|
|
255
|
+
content: openapiResponsesHtml
|
|
256
|
+
},
|
|
257
|
+
404: {
|
|
258
|
+
description: "Matching build not found.",
|
|
259
|
+
content: openapiErrorResponseContent
|
|
260
|
+
},
|
|
261
|
+
...openapiCommonErrorResponses
|
|
262
|
+
}
|
|
263
|
+
}), async (context) => {
|
|
264
|
+
const { ui } = getStore();
|
|
265
|
+
if (!ui?.renderBuildUploadPage) throw new HTTPException(405, { message: "UI not available for this route." });
|
|
266
|
+
const { buildId, projectId } = context.req.valid("param");
|
|
267
|
+
authenticateOrThrow({
|
|
268
|
+
action: "update",
|
|
269
|
+
projectId,
|
|
270
|
+
resource: "build"
|
|
271
|
+
});
|
|
272
|
+
const build = await new BuildsModel(projectId).get(buildId);
|
|
273
|
+
const project = await new ProjectsModel().get(projectId);
|
|
274
|
+
const { variant: uploadVariant } = context.req.valid("query");
|
|
275
|
+
return createUIResultResponse(context, ui.renderBuildUploadPage, {
|
|
276
|
+
build,
|
|
277
|
+
uploadVariant,
|
|
278
|
+
project
|
|
279
|
+
});
|
|
280
|
+
}).openapi(createRoute({
|
|
281
|
+
summary: "Upload build - action",
|
|
282
|
+
method: "post",
|
|
283
|
+
path: "/projects/{projectId}/builds/{buildId}/upload",
|
|
284
|
+
tags: [buildTag],
|
|
285
|
+
request: {
|
|
286
|
+
params: buildIdPathParams,
|
|
287
|
+
query: BuildUploadQueryParamsSchema,
|
|
288
|
+
body: {
|
|
289
|
+
description: "Compressed zip containing files.",
|
|
290
|
+
content: {
|
|
291
|
+
[mimes.formMultipart]: { schema: BuildUploadFormBodySchema },
|
|
292
|
+
[mimes.zip]: {
|
|
293
|
+
schema: {
|
|
294
|
+
format: "binary",
|
|
295
|
+
type: "string"
|
|
296
|
+
},
|
|
297
|
+
example: "storybook.zip"
|
|
298
|
+
}
|
|
299
|
+
},
|
|
300
|
+
required: true
|
|
301
|
+
}
|
|
302
|
+
},
|
|
303
|
+
responses: {
|
|
304
|
+
204: { description: "File uploaded successfully" },
|
|
305
|
+
303: openapiResponseRedirect("Redirect to project."),
|
|
306
|
+
404: {
|
|
307
|
+
description: "Matching project not found.",
|
|
308
|
+
content: openapiErrorResponseContent
|
|
309
|
+
},
|
|
310
|
+
415: {
|
|
311
|
+
content: openapiErrorResponseContent,
|
|
312
|
+
description: "Unsupported Media Type"
|
|
313
|
+
},
|
|
314
|
+
...openapiCommonErrorResponses
|
|
315
|
+
}
|
|
316
|
+
}), async (context) => {
|
|
317
|
+
const { buildId, projectId } = context.req.valid("param");
|
|
318
|
+
const buildsModel = new BuildsModel(projectId);
|
|
319
|
+
if (!await buildsModel.has(buildId)) throw new HTTPException(404, { message: `The build '${buildId}' does not exist in project '${projectId}'.` });
|
|
320
|
+
authenticateOrThrow({
|
|
321
|
+
action: "update",
|
|
322
|
+
projectId,
|
|
323
|
+
resource: "build"
|
|
324
|
+
});
|
|
325
|
+
const { contentType } = new SuperHeaders(context.req.header());
|
|
326
|
+
if (!contentType.toString()) throw new HTTPException(400, { message: "Content-Type header is required" });
|
|
327
|
+
const redirectUrl = urlBuilder.buildDetails(projectId, buildId);
|
|
328
|
+
if (contentType.mediaType?.startsWith(mimes.formMultipart)) {
|
|
329
|
+
const { file, variant } = BuildUploadFormBodySchema.parse(await context.req.parseBody());
|
|
330
|
+
await buildsModel.upload(buildId, variant, file);
|
|
331
|
+
if (checkIsHTMLRequest(true)) return context.redirect(redirectUrl, 303);
|
|
332
|
+
return new Response(null, { status: 204 });
|
|
333
|
+
}
|
|
334
|
+
if (contentType.mediaType?.startsWith(mimes.zip)) {
|
|
335
|
+
const bodyError = validateBuildUploadZipBody(context.req.raw);
|
|
336
|
+
if (bodyError) throw new HTTPException(bodyError.status, { message: bodyError.message });
|
|
337
|
+
const { variant } = context.req.valid("query");
|
|
338
|
+
await buildsModel.upload(buildId, variant);
|
|
339
|
+
if (checkIsHTMLRequest(true)) return context.redirect(redirectUrl, 303);
|
|
340
|
+
return new Response(null, { status: 204 });
|
|
341
|
+
}
|
|
342
|
+
throw new HTTPException(415, { message: `Invalid content type, expected ${mimes.zip} or ${mimes.formMultipart}.` });
|
|
343
|
+
});
|
|
344
|
+
|
|
345
|
+
//#endregion
|
|
346
|
+
export { buildsRouter };
|
|
347
|
+
//# sourceMappingURL=builds-router.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"builds-router.mjs","names":["z"],"sources":["../../src/routers/builds-router.ts"],"sourcesContent":["import { createRoute, OpenAPIHono } from \"@hono/zod-openapi\";\nimport { SuperHeaders } from \"@remix-run/headers\";\nimport { HTTPException } from \"hono/http-exception\";\nimport type { ContentfulStatusCode } from \"hono/utils/http-status\";\nimport { z } from \"zod\";\nimport { BuildsModel } from \"../models/builds-model.ts\";\nimport {\n BuildCreateSchema,\n BuildIdSchema,\n BuildsGetResultSchema,\n BuildsListResultSchema,\n BuildUpdateSchema,\n BuildUploadFormBodySchema,\n BuildUploadQueryParamsSchema,\n} from \"../models/builds-schema.ts\";\nimport { ProjectsModel } from \"../models/projects-model.ts\";\nimport { ProjectIdSchema } from \"../models/projects-schema.ts\";\nimport { urlBuilder } from \"../urls.ts\";\nimport { authenticateOrThrow } from \"../utils/auth.ts\";\nimport { QUERY_PARAMS } from \"../utils/constants.ts\";\nimport { mimes } from \"../utils/mime-utils.ts\";\nimport {\n openapiCommonErrorResponses,\n openapiErrorResponseContent,\n openapiResponseRedirect,\n openapiResponsesHtml,\n} from \"../utils/openapi-utils.ts\";\nimport { checkIsHTMLRequest, validateBuildUploadZipBody } from \"../utils/request.ts\";\nimport { getStore } from \"../utils/store.ts\";\nimport { createUIResultResponse } from \"../utils/ui-utils.ts\";\n\nconst buildTag = \"Builds\";\nconst projectIdPathParams = z.object({ projectId: ProjectIdSchema });\nconst buildIdPathParams = z.object({\n projectId: ProjectIdSchema,\n buildId: BuildIdSchema,\n});\n\n/**\n * @private\n */\nexport const buildsRouter = new OpenAPIHono()\n .openapi(\n createRoute({\n summary: \"List builds\",\n method: \"get\",\n path: \"/projects/{projectId}/builds\",\n tags: [buildTag],\n request: {\n params: projectIdPathParams,\n },\n responses: {\n 200: {\n description: \"A list of builds in the project.\",\n content: {\n [mimes.json]: { schema: BuildsListResultSchema },\n ...openapiResponsesHtml,\n },\n },\n ...openapiCommonErrorResponses,\n },\n }),\n async (context) => {\n const { projectId } = context.req.valid(\"param\");\n const { ui } = getStore();\n\n authenticateOrThrow({\n action: \"read\",\n projectId,\n resource: \"build\",\n });\n\n const builds = await new BuildsModel(projectId).list();\n\n if (ui?.renderBuildsListPage && checkIsHTMLRequest()) {\n const project = await new ProjectsModel().get(projectId);\n\n return createUIResultResponse(context, ui.renderBuildsListPage, { builds, project });\n }\n\n return context.json({ builds });\n },\n )\n .openapi(\n createRoute({\n summary: \"Create build - UI\",\n method: \"get\",\n path: \"/projects/{projectId}/builds/create\",\n tags: [buildTag],\n request: {\n params: projectIdPathParams,\n query: z.object({ [QUERY_PARAMS.tagId]: z.string().optional() }),\n },\n responses: {\n 200: {\n description: \"UI to create build\",\n content: openapiResponsesHtml,\n },\n ...openapiCommonErrorResponses,\n },\n }),\n async (context) => {\n const { ui } = getStore();\n if (!ui?.renderBuildCreatePage) {\n throw new HTTPException(405, { message: \"UI not available for this route.\" });\n }\n\n const { projectId } = context.req.valid(\"param\");\n const { tagId } = context.req.valid(\"query\");\n\n authenticateOrThrow({\n action: \"create\",\n projectId,\n resource: \"build\",\n });\n\n const project = await new ProjectsModel().get(projectId);\n\n return createUIResultResponse(context, ui.renderBuildCreatePage, { project, tagId });\n },\n )\n .openapi(\n createRoute({\n summary: \"Create build - action\",\n method: \"post\",\n path: \"/projects/{projectId}/builds/create\",\n tags: [buildTag],\n request: {\n params: projectIdPathParams,\n body: {\n content: { [mimes.formEncoded]: { schema: BuildCreateSchema } },\n required: true,\n },\n },\n responses: {\n 201: {\n description: \"Build created successfully\",\n content: { [mimes.json]: { schema: BuildsGetResultSchema } },\n },\n 303: openapiResponseRedirect(\"Redirect to build.\"),\n 409: {\n content: openapiErrorResponseContent,\n description: \"Build already exists.\",\n },\n 415: {\n content: openapiErrorResponseContent,\n description: \"Unsupported Media Type\",\n },\n ...openapiCommonErrorResponses,\n },\n }),\n async (context) => {\n const { projectId } = context.req.valid(\"param\");\n\n const projectModel = new ProjectsModel().id(projectId);\n if (!(await projectModel.has())) {\n throw new HTTPException(404, { message: `The project '${projectId}' does not exist.` });\n }\n\n authenticateOrThrow({\n action: \"create\",\n projectId,\n resource: \"build\",\n });\n\n const data = context.req.valid(\"form\");\n const build = await new BuildsModel(projectId).create(data);\n const url = urlBuilder.buildDetails(projectId, build.id);\n\n if (checkIsHTMLRequest(true)) {\n return context.redirect(url, 303);\n }\n\n return context.json({ build, url }, 201);\n },\n )\n .openapi(\n createRoute({\n summary: \"Build details\",\n method: \"get\",\n path: \"/projects/{projectId}/builds/{buildId}\",\n tags: [buildTag],\n request: { params: buildIdPathParams },\n responses: {\n 200: {\n description: \"Details of the build\",\n content: {\n [mimes.json]: { schema: BuildsGetResultSchema },\n ...openapiResponsesHtml,\n },\n },\n 404: {\n description: \"Matching build not found.\",\n content: openapiErrorResponseContent,\n },\n ...openapiCommonErrorResponses,\n },\n }),\n async (context) => {\n const { projectId, buildId } = context.req.valid(\"param\");\n const { ui } = getStore();\n\n authenticateOrThrow({\n action: \"read\",\n projectId,\n resource: \"build\",\n });\n\n const model = new BuildsModel(projectId);\n const build = await model.get(buildId);\n\n if (ui?.renderBuildDetailsPage && checkIsHTMLRequest()) {\n // const [hasDeletePermission, hasUpdatePermission] = await Promise.all([\n // model.checkAuth(\"delete\"),\n // model.checkAuth(\"update\"),\n // ]);\n // const canDeleteBuild =\n // hasDeletePermission && project.latestBuildId !== build.id;\n\n const project = await new ProjectsModel().get(projectId);\n const stories = await model.getStories(build);\n\n return createUIResultResponse(context, ui.renderBuildDetailsPage, {\n build,\n stories,\n project,\n });\n }\n\n return context.json({ build, url: context.req.url });\n },\n )\n .openapi(\n createRoute({\n summary: \"Delete build - action\",\n method: \"post\",\n path: \"/projects/{projectId}/builds/{buildId}/delete\",\n tags: [buildTag],\n request: { params: buildIdPathParams },\n responses: {\n 204: { description: \"Build deleted successfully.\" },\n 303: openapiResponseRedirect(\"Redirect to builds list.\"),\n 404: {\n description: \"Matching build not found.\",\n content: openapiErrorResponseContent,\n },\n ...openapiCommonErrorResponses,\n },\n }),\n async (context) => {\n const { projectId, buildId } = context.req.valid(\"param\");\n authenticateOrThrow({\n action: \"delete\",\n projectId,\n resource: \"build\",\n });\n\n await new BuildsModel(projectId).delete(buildId, true);\n\n if (checkIsHTMLRequest(true)) {\n return context.redirect(urlBuilder.buildsList(projectId), 303);\n }\n\n return new Response(null, { status: 204 });\n },\n )\n .openapi(\n createRoute({\n summary: \"Update build - action\",\n method: \"post\",\n path: \"/projects/{projectId}/builds/{buildId}/update\",\n tags: [buildTag],\n request: {\n params: buildIdPathParams,\n body: {\n content: { [mimes.formEncoded]: { schema: BuildUpdateSchema } },\n required: true,\n },\n },\n responses: {\n 202: { description: \"Build updated successfully\" },\n 303: openapiResponseRedirect(\"Redirect to build.\"),\n 404: {\n description: \"Matching project or build not found.\",\n content: openapiErrorResponseContent,\n },\n 415: {\n content: openapiErrorResponseContent,\n description: \"Unsupported Media Type\",\n },\n ...openapiCommonErrorResponses,\n },\n }),\n async (context) => {\n const { buildId, projectId } = context.req.valid(\"param\");\n\n const buildsModel = new BuildsModel(projectId);\n\n if (!(await buildsModel.has(buildId))) {\n throw new HTTPException(404, {\n message: `The build '${buildId}' does not exist in project '${projectId}'.`,\n });\n }\n\n authenticateOrThrow({\n action: \"update\",\n projectId,\n resource: \"build\",\n });\n\n const data = context.req.valid(\"form\");\n await buildsModel.update(buildId, data);\n\n if (checkIsHTMLRequest(true)) {\n return context.redirect(urlBuilder.buildDetails(projectId, buildId), 303);\n }\n\n return new Response(null, { status: 202 });\n },\n )\n .openapi(\n createRoute({\n summary: \"Upload build - UI\",\n method: \"get\",\n path: \"/projects/{projectId}/builds/{buildId}/upload\",\n tags: [buildTag],\n request: {\n params: buildIdPathParams,\n query: BuildUploadQueryParamsSchema,\n },\n responses: {\n 200: {\n description: \"UI to upload build\",\n content: openapiResponsesHtml,\n },\n 404: {\n description: \"Matching build not found.\",\n content: openapiErrorResponseContent,\n },\n ...openapiCommonErrorResponses,\n },\n }),\n async (context) => {\n const { ui } = getStore();\n if (!ui?.renderBuildUploadPage) {\n throw new HTTPException(405, { message: \"UI not available for this route.\" });\n }\n\n const { buildId, projectId } = context.req.valid(\"param\");\n\n authenticateOrThrow({\n action: \"update\",\n projectId,\n resource: \"build\",\n });\n\n const build = await new BuildsModel(projectId).get(buildId);\n const project = await new ProjectsModel().get(projectId);\n const { variant: uploadVariant } = context.req.valid(\"query\");\n\n return createUIResultResponse(context, ui.renderBuildUploadPage, {\n build,\n uploadVariant,\n project,\n });\n },\n )\n .openapi(\n createRoute({\n summary: \"Upload build - action\",\n method: \"post\",\n path: \"/projects/{projectId}/builds/{buildId}/upload\",\n tags: [buildTag],\n request: {\n params: buildIdPathParams,\n query: BuildUploadQueryParamsSchema,\n body: {\n description: \"Compressed zip containing files.\",\n content: {\n [mimes.formMultipart]: { schema: BuildUploadFormBodySchema },\n [mimes.zip]: {\n schema: { format: \"binary\", type: \"string\" },\n example: \"storybook.zip\",\n },\n },\n required: true,\n },\n },\n responses: {\n 204: { description: \"File uploaded successfully\" },\n 303: openapiResponseRedirect(\"Redirect to project.\"),\n 404: {\n description: \"Matching project not found.\",\n content: openapiErrorResponseContent,\n },\n 415: {\n content: openapiErrorResponseContent,\n description: \"Unsupported Media Type\",\n },\n ...openapiCommonErrorResponses,\n },\n }),\n async (context) => {\n const { buildId, projectId } = context.req.valid(\"param\");\n\n const buildsModel = new BuildsModel(projectId);\n\n if (!(await buildsModel.has(buildId))) {\n throw new HTTPException(404, {\n message: `The build '${buildId}' does not exist in project '${projectId}'.`,\n });\n }\n\n authenticateOrThrow({\n action: \"update\",\n projectId,\n resource: \"build\",\n });\n\n const { contentType } = new SuperHeaders(context.req.header());\n\n if (!contentType.toString()) {\n throw new HTTPException(400, { message: \"Content-Type header is required\" });\n }\n\n const redirectUrl = urlBuilder.buildDetails(projectId, buildId);\n\n // Form submission\n if (contentType.mediaType?.startsWith(mimes.formMultipart)) {\n const { file, variant } = BuildUploadFormBodySchema.parse(await context.req.parseBody());\n\n await buildsModel.upload(buildId, variant, file);\n\n if (checkIsHTMLRequest(true)) {\n return context.redirect(redirectUrl, 303);\n }\n\n return new Response(null, { status: 204 });\n }\n\n if (contentType.mediaType?.startsWith(mimes.zip)) {\n const bodyError = validateBuildUploadZipBody(context.req.raw);\n if (bodyError) {\n throw new HTTPException(bodyError.status as ContentfulStatusCode, {\n message: bodyError.message,\n });\n }\n\n const { variant } = context.req.valid(\"query\");\n\n await buildsModel.upload(buildId, variant);\n\n if (checkIsHTMLRequest(true)) {\n return context.redirect(redirectUrl, 303);\n }\n\n return new Response(null, { status: 204 });\n }\n\n throw new HTTPException(415, {\n message: `Invalid content type, expected ${mimes.zip} or ${mimes.formMultipart}.`,\n });\n },\n );\n"],"mappings":"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"}
|
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
import { mimes } from "../~internal/mimes.mjs";
|
|
2
|
+
import { getStore } from "../utils/store.mjs";
|
|
3
|
+
import { urlBuilder } from "../urls.mjs";
|
|
4
|
+
import { authenticateOrThrow } from "../utils/auth.mjs";
|
|
5
|
+
import { ProjectIdSchema } from "../models/~shared-schema.mjs";
|
|
6
|
+
import { ProjectCreateSchema, ProjectGetResultSchema, ProjectUpdateSchema, ProjectsListResultSchema } from "../models/projects-schema.mjs";
|
|
7
|
+
import { checkIsHTMLRequest } from "../utils/request.mjs";
|
|
8
|
+
import { createUIResultResponse } from "../utils/ui-utils.mjs";
|
|
9
|
+
import { TagsModel } from "../models/tags-model.mjs";
|
|
10
|
+
import { ProjectsModel } from "../models/projects-model.mjs";
|
|
11
|
+
import { BuildsModel } from "../models/builds-model.mjs";
|
|
12
|
+
import { openapiCommonErrorResponses, openapiErrorResponseContent, openapiResponseRedirect, openapiResponsesHtml } from "../utils/openapi-utils.mjs";
|
|
13
|
+
import { HTTPException } from "hono/http-exception";
|
|
14
|
+
import { OpenAPIHono, createRoute } from "@hono/zod-openapi";
|
|
15
|
+
import { z as z$1 } from "zod";
|
|
16
|
+
|
|
17
|
+
//#region src/routers/projects-router.ts
|
|
18
|
+
const projectTag = "Projects";
|
|
19
|
+
const projectIdPathParams = z$1.object({ projectId: ProjectIdSchema });
|
|
20
|
+
/**
|
|
21
|
+
* @private
|
|
22
|
+
*/
|
|
23
|
+
const projectsRouter = new OpenAPIHono().openapi(createRoute({
|
|
24
|
+
summary: "List projects",
|
|
25
|
+
method: "get",
|
|
26
|
+
path: "/projects",
|
|
27
|
+
tags: [projectTag],
|
|
28
|
+
responses: {
|
|
29
|
+
200: {
|
|
30
|
+
description: "A list of projects.",
|
|
31
|
+
content: {
|
|
32
|
+
[mimes.json]: { schema: ProjectsListResultSchema },
|
|
33
|
+
...openapiResponsesHtml
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
...openapiCommonErrorResponses
|
|
37
|
+
}
|
|
38
|
+
}), async (context) => {
|
|
39
|
+
const { ui } = getStore();
|
|
40
|
+
authenticateOrThrow({
|
|
41
|
+
action: "read",
|
|
42
|
+
projectId: void 0,
|
|
43
|
+
resource: "project"
|
|
44
|
+
});
|
|
45
|
+
const projects = await new ProjectsModel().list();
|
|
46
|
+
if (ui?.renderProjectsListPage && checkIsHTMLRequest()) return createUIResultResponse(context, ui.renderProjectsListPage, { projects });
|
|
47
|
+
return context.json({ projects });
|
|
48
|
+
}).openapi(createRoute({
|
|
49
|
+
summary: "Create project - UI",
|
|
50
|
+
method: "get",
|
|
51
|
+
path: "/projects/create",
|
|
52
|
+
tags: [projectTag],
|
|
53
|
+
responses: {
|
|
54
|
+
200: {
|
|
55
|
+
description: "UI to create project",
|
|
56
|
+
content: openapiResponsesHtml
|
|
57
|
+
},
|
|
58
|
+
...openapiCommonErrorResponses
|
|
59
|
+
}
|
|
60
|
+
}), (context) => {
|
|
61
|
+
const { ui } = getStore();
|
|
62
|
+
if (!ui?.renderProjectCreatePage) throw new HTTPException(405, { message: "UI not available for this route." });
|
|
63
|
+
authenticateOrThrow({
|
|
64
|
+
action: "create",
|
|
65
|
+
projectId: void 0,
|
|
66
|
+
resource: "project"
|
|
67
|
+
});
|
|
68
|
+
return createUIResultResponse(context, ui.renderProjectCreatePage, {});
|
|
69
|
+
}).openapi(createRoute({
|
|
70
|
+
summary: "Create project - action",
|
|
71
|
+
method: "post",
|
|
72
|
+
path: "/projects/create",
|
|
73
|
+
tags: [projectTag],
|
|
74
|
+
request: { body: {
|
|
75
|
+
content: { [mimes.formEncoded]: { schema: ProjectCreateSchema } },
|
|
76
|
+
required: true
|
|
77
|
+
} },
|
|
78
|
+
responses: {
|
|
79
|
+
201: {
|
|
80
|
+
description: "Project created successfully",
|
|
81
|
+
content: { [mimes.json]: { schema: ProjectGetResultSchema } }
|
|
82
|
+
},
|
|
83
|
+
303: openapiResponseRedirect("Redirect to project."),
|
|
84
|
+
409: {
|
|
85
|
+
content: openapiErrorResponseContent,
|
|
86
|
+
description: "Project already exists."
|
|
87
|
+
},
|
|
88
|
+
415: {
|
|
89
|
+
content: openapiErrorResponseContent,
|
|
90
|
+
description: "Unsupported Media Type"
|
|
91
|
+
},
|
|
92
|
+
...openapiCommonErrorResponses
|
|
93
|
+
}
|
|
94
|
+
}), async (context) => {
|
|
95
|
+
authenticateOrThrow({
|
|
96
|
+
action: "create",
|
|
97
|
+
projectId: void 0,
|
|
98
|
+
resource: "project"
|
|
99
|
+
});
|
|
100
|
+
const data = context.req.valid("form");
|
|
101
|
+
const project = await new ProjectsModel().create(data);
|
|
102
|
+
if (checkIsHTMLRequest(true)) return context.redirect(urlBuilder.projectDetails(project.id), 303);
|
|
103
|
+
return context.json({ project });
|
|
104
|
+
}).openapi(createRoute({
|
|
105
|
+
summary: "Project details",
|
|
106
|
+
method: "get",
|
|
107
|
+
path: "/projects/{projectId}",
|
|
108
|
+
tags: [projectTag],
|
|
109
|
+
request: { params: projectIdPathParams },
|
|
110
|
+
responses: {
|
|
111
|
+
200: {
|
|
112
|
+
description: "Details of the project",
|
|
113
|
+
content: {
|
|
114
|
+
[mimes.json]: { schema: ProjectGetResultSchema },
|
|
115
|
+
...openapiResponsesHtml
|
|
116
|
+
}
|
|
117
|
+
},
|
|
118
|
+
404: {
|
|
119
|
+
description: "Matching project not found.",
|
|
120
|
+
content: openapiErrorResponseContent
|
|
121
|
+
},
|
|
122
|
+
...openapiCommonErrorResponses
|
|
123
|
+
}
|
|
124
|
+
}), async (context) => {
|
|
125
|
+
const { ui } = getStore();
|
|
126
|
+
const { projectId } = context.req.valid("param");
|
|
127
|
+
authenticateOrThrow({
|
|
128
|
+
action: "read",
|
|
129
|
+
projectId,
|
|
130
|
+
resource: "project"
|
|
131
|
+
});
|
|
132
|
+
const project = await new ProjectsModel().get(projectId);
|
|
133
|
+
if (ui?.renderProjectDetailsPage && checkIsHTMLRequest()) {
|
|
134
|
+
const recentTags = await new TagsModel(projectId).list({ limit: 10 });
|
|
135
|
+
const recentBuilds = await new BuildsModel(projectId).list({ limit: 10 });
|
|
136
|
+
return createUIResultResponse(context, ui.renderProjectDetailsPage, {
|
|
137
|
+
project,
|
|
138
|
+
recentBuilds,
|
|
139
|
+
recentTags
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
return context.json({ project });
|
|
143
|
+
}).openapi(createRoute({
|
|
144
|
+
summary: "Delete project - action",
|
|
145
|
+
method: "post",
|
|
146
|
+
path: "/projects/{projectId}/delete",
|
|
147
|
+
tags: [projectTag],
|
|
148
|
+
request: { params: projectIdPathParams },
|
|
149
|
+
responses: {
|
|
150
|
+
204: { description: "Project deleted successfully." },
|
|
151
|
+
303: openapiResponseRedirect("Redirect to projects list."),
|
|
152
|
+
404: {
|
|
153
|
+
description: "Matching project not found.",
|
|
154
|
+
content: openapiErrorResponseContent
|
|
155
|
+
},
|
|
156
|
+
...openapiCommonErrorResponses
|
|
157
|
+
}
|
|
158
|
+
}), async (context) => {
|
|
159
|
+
const { projectId } = context.req.valid("param");
|
|
160
|
+
authenticateOrThrow({
|
|
161
|
+
action: "delete",
|
|
162
|
+
projectId,
|
|
163
|
+
resource: "project"
|
|
164
|
+
});
|
|
165
|
+
await new ProjectsModel().delete(projectId);
|
|
166
|
+
if (checkIsHTMLRequest(true)) return context.redirect(urlBuilder.projectsList(), 303);
|
|
167
|
+
return new Response(null, { status: 204 });
|
|
168
|
+
}).openapi(createRoute({
|
|
169
|
+
summary: "Update project - UI",
|
|
170
|
+
method: "get",
|
|
171
|
+
path: "/projects/{projectId}/update",
|
|
172
|
+
tags: [projectTag],
|
|
173
|
+
request: { params: projectIdPathParams },
|
|
174
|
+
responses: {
|
|
175
|
+
200: {
|
|
176
|
+
description: "UI to update project",
|
|
177
|
+
content: openapiResponsesHtml
|
|
178
|
+
},
|
|
179
|
+
404: {
|
|
180
|
+
description: "Matching project not found.",
|
|
181
|
+
content: openapiErrorResponseContent
|
|
182
|
+
},
|
|
183
|
+
...openapiCommonErrorResponses
|
|
184
|
+
}
|
|
185
|
+
}), async (context) => {
|
|
186
|
+
const { ui } = getStore();
|
|
187
|
+
if (!ui?.renderProjectUpdatePage) throw new HTTPException(405, { message: "UI not available for this route." });
|
|
188
|
+
const { projectId } = context.req.valid("param");
|
|
189
|
+
authenticateOrThrow({
|
|
190
|
+
action: "update",
|
|
191
|
+
projectId,
|
|
192
|
+
resource: "project"
|
|
193
|
+
});
|
|
194
|
+
const project = await new ProjectsModel().get(projectId);
|
|
195
|
+
return createUIResultResponse(context, ui.renderProjectUpdatePage, { project });
|
|
196
|
+
}).openapi(createRoute({
|
|
197
|
+
summary: "Update project - action",
|
|
198
|
+
method: "post",
|
|
199
|
+
path: "/projects/{projectId}/update",
|
|
200
|
+
tags: [projectTag],
|
|
201
|
+
request: {
|
|
202
|
+
params: projectIdPathParams,
|
|
203
|
+
body: {
|
|
204
|
+
content: { [mimes.formEncoded]: { schema: ProjectUpdateSchema } },
|
|
205
|
+
required: true
|
|
206
|
+
}
|
|
207
|
+
},
|
|
208
|
+
responses: {
|
|
209
|
+
202: { description: "Project updated successfully" },
|
|
210
|
+
303: openapiResponseRedirect("Redirect to project."),
|
|
211
|
+
404: {
|
|
212
|
+
description: "Matching project not found.",
|
|
213
|
+
content: openapiErrorResponseContent
|
|
214
|
+
},
|
|
215
|
+
415: {
|
|
216
|
+
content: openapiErrorResponseContent,
|
|
217
|
+
description: "Unsupported Media Type"
|
|
218
|
+
},
|
|
219
|
+
...openapiCommonErrorResponses
|
|
220
|
+
}
|
|
221
|
+
}), async (context) => {
|
|
222
|
+
const { projectId } = context.req.valid("param");
|
|
223
|
+
authenticateOrThrow({
|
|
224
|
+
action: "update",
|
|
225
|
+
projectId: void 0,
|
|
226
|
+
resource: "project"
|
|
227
|
+
});
|
|
228
|
+
const data = context.req.valid("form");
|
|
229
|
+
await new ProjectsModel().update(projectId, data);
|
|
230
|
+
if (checkIsHTMLRequest(true)) return context.redirect(urlBuilder.projectDetails(projectId), 303);
|
|
231
|
+
return new Response(null, { status: 202 });
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
//#endregion
|
|
235
|
+
export { projectsRouter };
|
|
236
|
+
//# sourceMappingURL=projects-router.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"projects-router.mjs","names":["z"],"sources":["../../src/routers/projects-router.ts"],"sourcesContent":["import { createRoute, OpenAPIHono } from \"@hono/zod-openapi\";\nimport { HTTPException } from \"hono/http-exception\";\nimport { z } from \"zod\";\nimport { BuildsModel } from \"../models/builds-model.ts\";\nimport { ProjectsModel } from \"../models/projects-model.ts\";\nimport {\n ProjectCreateSchema,\n ProjectGetResultSchema,\n ProjectIdSchema,\n ProjectsListResultSchema,\n ProjectUpdateSchema,\n} from \"../models/projects-schema.ts\";\nimport { TagsModel } from \"../models/tags-model.ts\";\nimport { urlBuilder } from \"../urls.ts\";\nimport { authenticateOrThrow } from \"../utils/auth.ts\";\nimport { mimes } from \"../utils/mime-utils.ts\";\nimport {\n openapiCommonErrorResponses,\n openapiErrorResponseContent,\n openapiResponseRedirect,\n openapiResponsesHtml,\n} from \"../utils/openapi-utils.ts\";\nimport { checkIsHTMLRequest } from \"../utils/request.ts\";\nimport { getStore } from \"../utils/store.ts\";\nimport { createUIResultResponse } from \"../utils/ui-utils.ts\";\n\nconst projectTag = \"Projects\";\nconst projectIdPathParams = z.object({ projectId: ProjectIdSchema });\n\n/**\n * @private\n */\nexport const projectsRouter = new OpenAPIHono()\n .openapi(\n createRoute({\n summary: \"List projects\",\n method: \"get\",\n path: \"/projects\",\n tags: [projectTag],\n responses: {\n 200: {\n description: \"A list of projects.\",\n content: {\n [mimes.json]: { schema: ProjectsListResultSchema },\n ...openapiResponsesHtml,\n },\n },\n ...openapiCommonErrorResponses,\n },\n }),\n async (context) => {\n const { ui } = getStore();\n\n authenticateOrThrow({\n action: \"read\",\n projectId: undefined,\n resource: \"project\",\n });\n\n const projects = await new ProjectsModel().list();\n\n if (ui?.renderProjectsListPage && checkIsHTMLRequest()) {\n return createUIResultResponse(context, ui.renderProjectsListPage, { projects });\n }\n\n return context.json({ projects });\n },\n )\n .openapi(\n createRoute({\n summary: \"Create project - UI\",\n method: \"get\",\n path: \"/projects/create\",\n tags: [projectTag],\n responses: {\n 200: {\n description: \"UI to create project\",\n content: openapiResponsesHtml,\n },\n ...openapiCommonErrorResponses,\n },\n }),\n (context) => {\n const { ui } = getStore();\n if (!ui?.renderProjectCreatePage) {\n throw new HTTPException(405, { message: \"UI not available for this route.\" });\n }\n\n authenticateOrThrow({\n action: \"create\",\n projectId: undefined,\n resource: \"project\",\n });\n\n return createUIResultResponse(context, ui.renderProjectCreatePage, {});\n },\n )\n .openapi(\n createRoute({\n summary: \"Create project - action\",\n method: \"post\",\n path: \"/projects/create\",\n tags: [projectTag],\n request: {\n body: {\n content: { [mimes.formEncoded]: { schema: ProjectCreateSchema } },\n required: true,\n },\n },\n responses: {\n 201: {\n description: \"Project created successfully\",\n content: { [mimes.json]: { schema: ProjectGetResultSchema } },\n },\n 303: openapiResponseRedirect(\"Redirect to project.\"),\n 409: {\n content: openapiErrorResponseContent,\n description: \"Project already exists.\",\n },\n 415: {\n content: openapiErrorResponseContent,\n description: \"Unsupported Media Type\",\n },\n ...openapiCommonErrorResponses,\n },\n }),\n async (context) => {\n authenticateOrThrow({\n action: \"create\",\n projectId: undefined,\n resource: \"project\",\n });\n const data = context.req.valid(\"form\");\n const project = await new ProjectsModel().create(data);\n\n if (checkIsHTMLRequest(true)) {\n return context.redirect(urlBuilder.projectDetails(project.id), 303);\n }\n\n return context.json({ project });\n },\n )\n .openapi(\n createRoute({\n summary: \"Project details\",\n method: \"get\",\n path: \"/projects/{projectId}\",\n tags: [projectTag],\n request: { params: projectIdPathParams },\n responses: {\n 200: {\n description: \"Details of the project\",\n content: {\n [mimes.json]: { schema: ProjectGetResultSchema },\n ...openapiResponsesHtml,\n },\n },\n 404: {\n description: \"Matching project not found.\",\n content: openapiErrorResponseContent,\n },\n ...openapiCommonErrorResponses,\n },\n }),\n async (context) => {\n const { ui } = getStore();\n const { projectId } = context.req.valid(\"param\");\n\n authenticateOrThrow({\n action: \"read\",\n projectId,\n resource: \"project\",\n });\n\n const project = await new ProjectsModel().get(projectId);\n\n if (ui?.renderProjectDetailsPage && checkIsHTMLRequest()) {\n const recentTags = await new TagsModel(projectId).list({ limit: 10 });\n const recentBuilds = await new BuildsModel(projectId).list({\n limit: 10,\n });\n\n return createUIResultResponse(context, ui.renderProjectDetailsPage, {\n project,\n recentBuilds,\n recentTags,\n });\n }\n\n return context.json({ project });\n },\n )\n .openapi(\n createRoute({\n summary: \"Delete project - action\",\n method: \"post\",\n path: \"/projects/{projectId}/delete\",\n tags: [projectTag],\n request: { params: projectIdPathParams },\n responses: {\n 204: { description: \"Project deleted successfully.\" },\n 303: openapiResponseRedirect(\"Redirect to projects list.\"),\n 404: {\n description: \"Matching project not found.\",\n content: openapiErrorResponseContent,\n },\n ...openapiCommonErrorResponses,\n },\n }),\n async (context) => {\n const { projectId } = context.req.valid(\"param\");\n authenticateOrThrow({\n action: \"delete\",\n projectId,\n resource: \"project\",\n });\n\n await new ProjectsModel().delete(projectId);\n\n if (checkIsHTMLRequest(true)) {\n return context.redirect(urlBuilder.projectsList(), 303);\n }\n\n return new Response(null, { status: 204 });\n },\n )\n .openapi(\n createRoute({\n summary: \"Update project - UI\",\n method: \"get\",\n path: \"/projects/{projectId}/update\",\n tags: [projectTag],\n request: { params: projectIdPathParams },\n responses: {\n 200: {\n description: \"UI to update project\",\n content: openapiResponsesHtml,\n },\n 404: {\n description: \"Matching project not found.\",\n content: openapiErrorResponseContent,\n },\n ...openapiCommonErrorResponses,\n },\n }),\n async (context) => {\n const { ui } = getStore();\n if (!ui?.renderProjectUpdatePage) {\n throw new HTTPException(405, { message: \"UI not available for this route.\" });\n }\n\n const { projectId } = context.req.valid(\"param\");\n authenticateOrThrow({\n action: \"update\",\n projectId,\n resource: \"project\",\n });\n\n const project = await new ProjectsModel().get(projectId);\n\n return createUIResultResponse(context, ui.renderProjectUpdatePage, { project });\n },\n )\n .openapi(\n createRoute({\n summary: \"Update project - action\",\n method: \"post\",\n path: \"/projects/{projectId}/update\",\n tags: [projectTag],\n request: {\n params: projectIdPathParams,\n body: {\n content: { [mimes.formEncoded]: { schema: ProjectUpdateSchema } },\n required: true,\n },\n },\n responses: {\n 202: { description: \"Project updated successfully\" },\n 303: openapiResponseRedirect(\"Redirect to project.\"),\n 404: {\n description: \"Matching project not found.\",\n content: openapiErrorResponseContent,\n },\n 415: {\n content: openapiErrorResponseContent,\n description: \"Unsupported Media Type\",\n },\n ...openapiCommonErrorResponses,\n },\n }),\n async (context) => {\n const { projectId } = context.req.valid(\"param\");\n\n authenticateOrThrow({\n action: \"update\",\n projectId: undefined,\n resource: \"project\",\n });\n\n const data = context.req.valid(\"form\");\n await new ProjectsModel().update(projectId, data);\n\n if (checkIsHTMLRequest(true)) {\n return context.redirect(urlBuilder.projectDetails(projectId), 303);\n }\n\n return new Response(null, { status: 202 });\n },\n );\n"],"mappings":";;;;;;;;;;;;;;;;;AA0BA,MAAM,aAAa;AACnB,MAAM,sBAAsBA,IAAE,OAAO,EAAE,WAAW,iBAAiB,CAAC;;;;AAKpE,MAAa,iBAAiB,IAAI,aAAa,CAC5C,QACC,YAAY;CACV,SAAS;CACT,QAAQ;CACR,MAAM;CACN,MAAM,CAAC,WAAW;CAClB,WAAW;EACT,KAAK;GACH,aAAa;GACb,SAAS;KACN,MAAM,OAAO,EAAE,QAAQ,0BAA0B;IAClD,GAAG;IACJ;GACF;EACD,GAAG;EACJ;CACF,CAAC,EACF,OAAO,YAAY;CACjB,MAAM,EAAE,OAAO,UAAU;AAEzB,qBAAoB;EAClB,QAAQ;EACR,WAAW;EACX,UAAU;EACX,CAAC;CAEF,MAAM,WAAW,MAAM,IAAI,eAAe,CAAC,MAAM;AAEjD,KAAI,IAAI,0BAA0B,oBAAoB,CACpD,QAAO,uBAAuB,SAAS,GAAG,wBAAwB,EAAE,UAAU,CAAC;AAGjF,QAAO,QAAQ,KAAK,EAAE,UAAU,CAAC;EAEpC,CACA,QACC,YAAY;CACV,SAAS;CACT,QAAQ;CACR,MAAM;CACN,MAAM,CAAC,WAAW;CAClB,WAAW;EACT,KAAK;GACH,aAAa;GACb,SAAS;GACV;EACD,GAAG;EACJ;CACF,CAAC,GACD,YAAY;CACX,MAAM,EAAE,OAAO,UAAU;AACzB,KAAI,CAAC,IAAI,wBACP,OAAM,IAAI,cAAc,KAAK,EAAE,SAAS,oCAAoC,CAAC;AAG/E,qBAAoB;EAClB,QAAQ;EACR,WAAW;EACX,UAAU;EACX,CAAC;AAEF,QAAO,uBAAuB,SAAS,GAAG,yBAAyB,EAAE,CAAC;EAEzE,CACA,QACC,YAAY;CACV,SAAS;CACT,QAAQ;CACR,MAAM;CACN,MAAM,CAAC,WAAW;CAClB,SAAS,EACP,MAAM;EACJ,SAAS,GAAG,MAAM,cAAc,EAAE,QAAQ,qBAAqB,EAAE;EACjE,UAAU;EACX,EACF;CACD,WAAW;EACT,KAAK;GACH,aAAa;GACb,SAAS,GAAG,MAAM,OAAO,EAAE,QAAQ,wBAAwB,EAAE;GAC9D;EACD,KAAK,wBAAwB,uBAAuB;EACpD,KAAK;GACH,SAAS;GACT,aAAa;GACd;EACD,KAAK;GACH,SAAS;GACT,aAAa;GACd;EACD,GAAG;EACJ;CACF,CAAC,EACF,OAAO,YAAY;AACjB,qBAAoB;EAClB,QAAQ;EACR,WAAW;EACX,UAAU;EACX,CAAC;CACF,MAAM,OAAO,QAAQ,IAAI,MAAM,OAAO;CACtC,MAAM,UAAU,MAAM,IAAI,eAAe,CAAC,OAAO,KAAK;AAEtD,KAAI,mBAAmB,KAAK,CAC1B,QAAO,QAAQ,SAAS,WAAW,eAAe,QAAQ,GAAG,EAAE,IAAI;AAGrE,QAAO,QAAQ,KAAK,EAAE,SAAS,CAAC;EAEnC,CACA,QACC,YAAY;CACV,SAAS;CACT,QAAQ;CACR,MAAM;CACN,MAAM,CAAC,WAAW;CAClB,SAAS,EAAE,QAAQ,qBAAqB;CACxC,WAAW;EACT,KAAK;GACH,aAAa;GACb,SAAS;KACN,MAAM,OAAO,EAAE,QAAQ,wBAAwB;IAChD,GAAG;IACJ;GACF;EACD,KAAK;GACH,aAAa;GACb,SAAS;GACV;EACD,GAAG;EACJ;CACF,CAAC,EACF,OAAO,YAAY;CACjB,MAAM,EAAE,OAAO,UAAU;CACzB,MAAM,EAAE,cAAc,QAAQ,IAAI,MAAM,QAAQ;AAEhD,qBAAoB;EAClB,QAAQ;EACR;EACA,UAAU;EACX,CAAC;CAEF,MAAM,UAAU,MAAM,IAAI,eAAe,CAAC,IAAI,UAAU;AAExD,KAAI,IAAI,4BAA4B,oBAAoB,EAAE;EACxD,MAAM,aAAa,MAAM,IAAI,UAAU,UAAU,CAAC,KAAK,EAAE,OAAO,IAAI,CAAC;EACrE,MAAM,eAAe,MAAM,IAAI,YAAY,UAAU,CAAC,KAAK,EACzD,OAAO,IACR,CAAC;AAEF,SAAO,uBAAuB,SAAS,GAAG,0BAA0B;GAClE;GACA;GACA;GACD,CAAC;;AAGJ,QAAO,QAAQ,KAAK,EAAE,SAAS,CAAC;EAEnC,CACA,QACC,YAAY;CACV,SAAS;CACT,QAAQ;CACR,MAAM;CACN,MAAM,CAAC,WAAW;CAClB,SAAS,EAAE,QAAQ,qBAAqB;CACxC,WAAW;EACT,KAAK,EAAE,aAAa,iCAAiC;EACrD,KAAK,wBAAwB,6BAA6B;EAC1D,KAAK;GACH,aAAa;GACb,SAAS;GACV;EACD,GAAG;EACJ;CACF,CAAC,EACF,OAAO,YAAY;CACjB,MAAM,EAAE,cAAc,QAAQ,IAAI,MAAM,QAAQ;AAChD,qBAAoB;EAClB,QAAQ;EACR;EACA,UAAU;EACX,CAAC;AAEF,OAAM,IAAI,eAAe,CAAC,OAAO,UAAU;AAE3C,KAAI,mBAAmB,KAAK,CAC1B,QAAO,QAAQ,SAAS,WAAW,cAAc,EAAE,IAAI;AAGzD,QAAO,IAAI,SAAS,MAAM,EAAE,QAAQ,KAAK,CAAC;EAE7C,CACA,QACC,YAAY;CACV,SAAS;CACT,QAAQ;CACR,MAAM;CACN,MAAM,CAAC,WAAW;CAClB,SAAS,EAAE,QAAQ,qBAAqB;CACxC,WAAW;EACT,KAAK;GACH,aAAa;GACb,SAAS;GACV;EACD,KAAK;GACH,aAAa;GACb,SAAS;GACV;EACD,GAAG;EACJ;CACF,CAAC,EACF,OAAO,YAAY;CACjB,MAAM,EAAE,OAAO,UAAU;AACzB,KAAI,CAAC,IAAI,wBACP,OAAM,IAAI,cAAc,KAAK,EAAE,SAAS,oCAAoC,CAAC;CAG/E,MAAM,EAAE,cAAc,QAAQ,IAAI,MAAM,QAAQ;AAChD,qBAAoB;EAClB,QAAQ;EACR;EACA,UAAU;EACX,CAAC;CAEF,MAAM,UAAU,MAAM,IAAI,eAAe,CAAC,IAAI,UAAU;AAExD,QAAO,uBAAuB,SAAS,GAAG,yBAAyB,EAAE,SAAS,CAAC;EAElF,CACA,QACC,YAAY;CACV,SAAS;CACT,QAAQ;CACR,MAAM;CACN,MAAM,CAAC,WAAW;CAClB,SAAS;EACP,QAAQ;EACR,MAAM;GACJ,SAAS,GAAG,MAAM,cAAc,EAAE,QAAQ,qBAAqB,EAAE;GACjE,UAAU;GACX;EACF;CACD,WAAW;EACT,KAAK,EAAE,aAAa,gCAAgC;EACpD,KAAK,wBAAwB,uBAAuB;EACpD,KAAK;GACH,aAAa;GACb,SAAS;GACV;EACD,KAAK;GACH,SAAS;GACT,aAAa;GACd;EACD,GAAG;EACJ;CACF,CAAC,EACF,OAAO,YAAY;CACjB,MAAM,EAAE,cAAc,QAAQ,IAAI,MAAM,QAAQ;AAEhD,qBAAoB;EAClB,QAAQ;EACR,WAAW;EACX,UAAU;EACX,CAAC;CAEF,MAAM,OAAO,QAAQ,IAAI,MAAM,OAAO;AACtC,OAAM,IAAI,eAAe,CAAC,OAAO,WAAW,KAAK;AAEjD,KAAI,mBAAmB,KAAK,CAC1B,QAAO,QAAQ,SAAS,WAAW,eAAe,UAAU,EAAE,IAAI;AAGpE,QAAO,IAAI,SAAS,MAAM,EAAE,QAAQ,KAAK,CAAC;EAE7C"}
|