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,248 @@
|
|
|
1
|
+
import { generateDatabaseCollectionId, generateStorageContainerId } from "../utils/adapter-utils.mjs";
|
|
2
|
+
import { mimes } from "../~internal/mimes.mjs";
|
|
3
|
+
import { getStore } from "../utils/store.mjs";
|
|
4
|
+
import { handleProcessZip } from "../handlers/handle-process-zip.mjs";
|
|
5
|
+
import { urlBuilder } from "../urls.mjs";
|
|
6
|
+
import { checkAuthorisation } from "../utils/auth.mjs";
|
|
7
|
+
import { BuildSchema } from "./builds-schema.mjs";
|
|
8
|
+
import { Model } from "./~model.mjs";
|
|
9
|
+
import { TagsModel } from "./tags-model.mjs";
|
|
10
|
+
import { ProjectsModel } from "./projects-model.mjs";
|
|
11
|
+
import { HTTPException } from "hono/http-exception";
|
|
12
|
+
|
|
13
|
+
//#region src/models/builds-model.ts
|
|
14
|
+
var BuildsModel = class extends Model {
|
|
15
|
+
constructor(projectId) {
|
|
16
|
+
super(projectId, generateDatabaseCollectionId(projectId, "Builds"));
|
|
17
|
+
}
|
|
18
|
+
async list(options = {}) {
|
|
19
|
+
if (options) this.log("List builds with options (%o)...", { ...options });
|
|
20
|
+
else this.log("List builds...");
|
|
21
|
+
const items = await this.database.listDocuments(this.collectionId, {
|
|
22
|
+
sort: "latest",
|
|
23
|
+
...options
|
|
24
|
+
}, this.dbOptions);
|
|
25
|
+
return BuildSchema.array().parse(items);
|
|
26
|
+
}
|
|
27
|
+
async create(data) {
|
|
28
|
+
const { tags: parsedTags, id, ...rest } = data;
|
|
29
|
+
this.log("Create build '%s'...", id);
|
|
30
|
+
try {
|
|
31
|
+
if (await this.has(id)) throw new HTTPException(409, { message: `Build '${id}' already exists.` });
|
|
32
|
+
const tags = Array.isArray(parsedTags) ? parsedTags : parsedTags.split(",");
|
|
33
|
+
const tagIds = await Promise.all(tags.filter(Boolean).map(async (tagId) => {
|
|
34
|
+
return await this.#updateOrCreateTag(tagId, id);
|
|
35
|
+
}));
|
|
36
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
37
|
+
const build = {
|
|
38
|
+
...rest,
|
|
39
|
+
createdAt: now,
|
|
40
|
+
coverage: "none",
|
|
41
|
+
screenshots: "none",
|
|
42
|
+
storybook: "none",
|
|
43
|
+
testReport: "none",
|
|
44
|
+
id,
|
|
45
|
+
message: rest.message ?? "",
|
|
46
|
+
tagIds: tagIds.filter(Boolean).join(","),
|
|
47
|
+
updatedAt: now
|
|
48
|
+
};
|
|
49
|
+
await this.database.createDocument(this.collectionId, build, this.dbOptions);
|
|
50
|
+
try {
|
|
51
|
+
const projectsModel = new ProjectsModel();
|
|
52
|
+
const project = await projectsModel.get(this.projectId);
|
|
53
|
+
if (tags.includes(project.gitHubDefaultBranch)) await projectsModel.update(this.projectId, { latestBuildId: id });
|
|
54
|
+
} catch (error) {
|
|
55
|
+
this.error("Error updating project with latest build ID:", error);
|
|
56
|
+
}
|
|
57
|
+
return build;
|
|
58
|
+
} catch (error) {
|
|
59
|
+
throw new HTTPException(500, {
|
|
60
|
+
cause: error,
|
|
61
|
+
message: `Failed to create build '${id}'.`
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
async get(id) {
|
|
66
|
+
this.log("Get build '%s'...", id);
|
|
67
|
+
const item = await this.database.getDocument(this.collectionId, id, this.dbOptions);
|
|
68
|
+
return BuildSchema.parse(item);
|
|
69
|
+
}
|
|
70
|
+
async has(id) {
|
|
71
|
+
this.log("Check build '%s'...", id);
|
|
72
|
+
try {
|
|
73
|
+
return await this.database.hasDocument(this.collectionId, id, this.dbOptions);
|
|
74
|
+
} catch {
|
|
75
|
+
return false;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
async update(id, data) {
|
|
79
|
+
this.log("Update build '%s''...", id);
|
|
80
|
+
await this.database.updateDocument(this.collectionId, id, {
|
|
81
|
+
...data,
|
|
82
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
83
|
+
}, this.dbOptions);
|
|
84
|
+
}
|
|
85
|
+
async delete(buildId, updateTag = true) {
|
|
86
|
+
this.log("Delete build '%s'...", buildId);
|
|
87
|
+
const build = await this.get(buildId);
|
|
88
|
+
this.debug("Delete document '%s'", buildId);
|
|
89
|
+
await this.database.deleteDocument(this.collectionId, buildId, this.dbOptions);
|
|
90
|
+
try {
|
|
91
|
+
this.debug("Delete files '%s'", buildId);
|
|
92
|
+
await this.storage.deleteFiles(generateStorageContainerId(this.projectId), buildId, this.storageOptions);
|
|
93
|
+
} catch (error) {
|
|
94
|
+
this.error("Cannot delete container:", error);
|
|
95
|
+
}
|
|
96
|
+
if (updateTag) {
|
|
97
|
+
this.debug("Update tags for build '%s'", buildId);
|
|
98
|
+
const tagIds = build.tagIds?.split(",") ?? [];
|
|
99
|
+
const tagsModel = new TagsModel(this.projectId);
|
|
100
|
+
await Promise.allSettled(tagIds.map(async (tagId) => {
|
|
101
|
+
const tag = await tagsModel.get(tagId);
|
|
102
|
+
if (tag.latestBuildId === buildId) await tagsModel.update(tagId, {
|
|
103
|
+
buildsCount: Math.max(tag.buildsCount - 1, 0),
|
|
104
|
+
latestBuildId: ""
|
|
105
|
+
});
|
|
106
|
+
}));
|
|
107
|
+
}
|
|
108
|
+
try {
|
|
109
|
+
const projectsModel = new ProjectsModel();
|
|
110
|
+
if ((await projectsModel.get(this.projectId)).latestBuildId === buildId) {
|
|
111
|
+
this.debug("Update project for build '%s'", buildId);
|
|
112
|
+
await projectsModel.update(this.projectId, { latestBuildId: "" });
|
|
113
|
+
}
|
|
114
|
+
} catch (error) {
|
|
115
|
+
this.error("Cannot unset build ID from project:", error);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
async upload(buildId, variant, zipFile) {
|
|
119
|
+
const { config, request } = getStore();
|
|
120
|
+
this.log("Upload build '%s' (%s)...", buildId, variant);
|
|
121
|
+
const variantCopy = variant;
|
|
122
|
+
switch (variant) {
|
|
123
|
+
case "coverage":
|
|
124
|
+
case "testReport":
|
|
125
|
+
case "screenshots":
|
|
126
|
+
case "storybook": {
|
|
127
|
+
const size = await this.#uploadZipFile(buildId, variant, zipFile);
|
|
128
|
+
await this.update(buildId, { [variant]: "uploaded" });
|
|
129
|
+
const { maxInlineUploadProcessingSizeInBytes = 5 * 1024 * 1024, queueLargeZipFileProcessing = false } = config ?? {};
|
|
130
|
+
if (size !== void 0 && size <= maxInlineUploadProcessingSizeInBytes) {
|
|
131
|
+
await handleProcessZip(this.projectId, buildId, variant).catch((error) => {
|
|
132
|
+
this.error("Error processing zip file:", error);
|
|
133
|
+
});
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
if (queueLargeZipFileProcessing) {
|
|
137
|
+
this.log("Queue processing for build '%s' (%s)...", buildId, variant);
|
|
138
|
+
const url = urlBuilder.taskProcessZip(this.projectId, buildId, variant);
|
|
139
|
+
fetch(url, {
|
|
140
|
+
headers: request.headers,
|
|
141
|
+
method: "POST"
|
|
142
|
+
}).catch((error) => {
|
|
143
|
+
this.error("Error queuing zip file processing:", error);
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
default: throw new Error(`Unsupported upload variant: ${variantCopy}`);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
id = (id) => {
|
|
152
|
+
return {
|
|
153
|
+
checkAuth: (action) => checkAuthorisation({
|
|
154
|
+
action,
|
|
155
|
+
projectId: this.projectId,
|
|
156
|
+
resource: "build"
|
|
157
|
+
}),
|
|
158
|
+
delete: this.delete.bind(this, id),
|
|
159
|
+
get: this.get.bind(this, id),
|
|
160
|
+
has: this.has.bind(this, id),
|
|
161
|
+
id,
|
|
162
|
+
update: this.update.bind(this, id)
|
|
163
|
+
};
|
|
164
|
+
};
|
|
165
|
+
checkAuth(action) {
|
|
166
|
+
return checkAuthorisation({
|
|
167
|
+
action,
|
|
168
|
+
projectId: this.projectId,
|
|
169
|
+
resource: "build"
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
async getStories(idOrBuild) {
|
|
173
|
+
const { storybook, id } = typeof idOrBuild === "string" ? await this.get(idOrBuild) : idOrBuild;
|
|
174
|
+
if (storybook !== "ready") return null;
|
|
175
|
+
const { logger } = getStore();
|
|
176
|
+
try {
|
|
177
|
+
this.log("List stories '%s'...", id);
|
|
178
|
+
const buildIndexJsonPath = `${id}/storybook/index.json`;
|
|
179
|
+
const { content } = await this.storage.downloadFile(generateStorageContainerId(this.projectId), buildIndexJsonPath, { logger });
|
|
180
|
+
const data = typeof content === "string" ? JSON.parse(content) : await new Response(content).json();
|
|
181
|
+
if (!data || typeof data !== "object" || !("entries" in data) || !data.entries) return [];
|
|
182
|
+
return Object.values(data.entries);
|
|
183
|
+
} catch (error) {
|
|
184
|
+
this.error("Error getting stories:", error);
|
|
185
|
+
return null;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
async listByTag(tagId) {
|
|
189
|
+
return await this.list({ filter: (item) => item.tagIds ? item.tagIds.split(",").includes(tagId) : false });
|
|
190
|
+
}
|
|
191
|
+
async deleteByTag(tagId, force) {
|
|
192
|
+
const builds = await this.listByTag(tagId);
|
|
193
|
+
this.log("Delete builds by tag: '%s' (%d, force: %s)...", tagId, builds.length, force.valueOf());
|
|
194
|
+
await Promise.allSettled(builds.map(async (build) => {
|
|
195
|
+
const buildTagIds = build.tagIds?.split(",") ?? [];
|
|
196
|
+
if (!force && buildTagIds.length > 1) {
|
|
197
|
+
const newIds = buildTagIds.filter((id) => id !== tagId);
|
|
198
|
+
await this.update(build.id, { tagIds: newIds.join(",") });
|
|
199
|
+
} else await this.delete(build.id, false);
|
|
200
|
+
}));
|
|
201
|
+
}
|
|
202
|
+
async #updateOrCreateTag(tagId, buildId) {
|
|
203
|
+
const tagsModel = new TagsModel(this.projectId);
|
|
204
|
+
const [id = tagId, tagType, tagValue] = tagId.split(";").map((part) => part.trim());
|
|
205
|
+
try {
|
|
206
|
+
const existingTag = await tagsModel.get(id);
|
|
207
|
+
await tagsModel.update(id, {
|
|
208
|
+
buildsCount: existingTag.buildsCount + 1,
|
|
209
|
+
latestBuildId: buildId
|
|
210
|
+
});
|
|
211
|
+
return id;
|
|
212
|
+
} catch {
|
|
213
|
+
try {
|
|
214
|
+
const type = tagType ?? TagsModel.guessType(id);
|
|
215
|
+
const value = tagValue ?? id;
|
|
216
|
+
this.log("A new tag '%s' (%s) is being created.", value, type);
|
|
217
|
+
return (await tagsModel.create({
|
|
218
|
+
latestBuildId: buildId,
|
|
219
|
+
type,
|
|
220
|
+
value
|
|
221
|
+
}, true)).id;
|
|
222
|
+
} catch (error) {
|
|
223
|
+
this.error("Error creating tag:", error);
|
|
224
|
+
return id;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
async #uploadZipFile(buildId, variant, zipFile) {
|
|
229
|
+
const { request } = getStore();
|
|
230
|
+
this.debug("(%s-%s) Uploading zip file", buildId, variant);
|
|
231
|
+
const content = zipFile ? zipFile.stream() : request.body;
|
|
232
|
+
if (!content) throw new Error(`No content found for zip file.`);
|
|
233
|
+
await this.storage.uploadFiles(generateStorageContainerId(this.projectId), [{
|
|
234
|
+
content,
|
|
235
|
+
mimeType: mimes.zip,
|
|
236
|
+
path: `${buildId}/${variant}.zip`
|
|
237
|
+
}], this.storageOptions);
|
|
238
|
+
if (!zipFile) {
|
|
239
|
+
const length = request.headers.get("Content-Length");
|
|
240
|
+
return length ? Number(length) : void 0;
|
|
241
|
+
}
|
|
242
|
+
return zipFile?.size;
|
|
243
|
+
}
|
|
244
|
+
};
|
|
245
|
+
|
|
246
|
+
//#endregion
|
|
247
|
+
export { BuildsModel };
|
|
248
|
+
//# sourceMappingURL=builds-model.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"builds-model.mjs","names":["#updateOrCreateTag","build: BuildType","#uploadZipFile","data: unknown","content: string | Blob | ReadableStream | null"],"sources":["../../src/models/builds-model.ts"],"sourcesContent":["// oxlint-disable switch-case-braces\n\nimport { HTTPException } from \"hono/http-exception\";\nimport type { StoryBookerPermissionAction } from \"../adapters/_internal/auth.ts\";\nimport { handleProcessZip } from \"../handlers/handle-process-zip.ts\";\nimport { urlBuilder } from \"../urls.ts\";\nimport {\n generateDatabaseCollectionId,\n generateStorageContainerId,\n} from \"../utils/adapter-utils.ts\";\nimport { checkAuthorisation } from \"../utils/auth.ts\";\nimport { mimes } from \"../utils/mime-utils.ts\";\nimport { getStore } from \"../utils/store.ts\";\nimport {\n BuildSchema,\n type BuildCreateType,\n type BuildStoryType,\n type BuildType,\n type BuildUpdateType,\n type BuildUploadVariant,\n} from \"./builds-schema.ts\";\nimport { ProjectsModel } from \"./projects-model.ts\";\nimport { TagsModel } from \"./tags-model.ts\";\nimport type { TagVariant } from \"./tags-schema.ts\";\nimport { Model, type BaseModel, type ListOptions } from \"./~model.ts\";\n\nexport class BuildsModel extends Model<BuildType> {\n constructor(projectId: string) {\n super(projectId, generateDatabaseCollectionId(projectId, \"Builds\"));\n }\n\n async list(options: ListOptions<BuildType> = {}): Promise<BuildType[]> {\n if (options) {\n this.log(\"List builds with options (%o)...\", { ...options });\n } else {\n this.log(\"List builds...\");\n }\n\n const items = await this.database.listDocuments(\n this.collectionId,\n { sort: \"latest\", ...options },\n this.dbOptions,\n );\n\n return BuildSchema.array().parse(items);\n }\n\n async create(data: BuildCreateType): Promise<BuildType> {\n const { tags: parsedTags, id, ...rest } = data;\n this.log(\"Create build '%s'...\", id);\n\n try {\n if (await this.has(id)) {\n throw new HTTPException(409, {\n message: `Build '${id}' already exists.`,\n });\n }\n\n const tags = Array.isArray(parsedTags) ? parsedTags : parsedTags.split(\",\");\n const tagIds = await Promise.all(\n tags.filter(Boolean).map(async (tagId) => {\n return await this.#updateOrCreateTag(tagId, id);\n }),\n );\n\n const now = new Date().toISOString();\n // oxlint-disable-next-line sort-keys\n const build: BuildType = {\n ...rest,\n createdAt: now,\n coverage: \"none\",\n screenshots: \"none\",\n storybook: \"none\",\n testReport: \"none\",\n id,\n message: rest.message ?? \"\",\n tagIds: tagIds.filter(Boolean).join(\",\"),\n updatedAt: now,\n };\n await this.database.createDocument(this.collectionId, build, this.dbOptions);\n\n try {\n const projectsModel = new ProjectsModel();\n const project = await projectsModel.get(this.projectId);\n if (tags.includes(project.gitHubDefaultBranch)) {\n await projectsModel.update(this.projectId, { latestBuildId: id });\n }\n } catch (error) {\n this.error(\"Error updating project with latest build ID:\", error);\n }\n\n return build;\n } catch (error) {\n throw new HTTPException(500, {\n cause: error,\n message: `Failed to create build '${id}'.`,\n });\n }\n }\n\n async get(id: string): Promise<BuildType> {\n this.log(\"Get build '%s'...\", id);\n\n const item = await this.database.getDocument(this.collectionId, id, this.dbOptions);\n\n return BuildSchema.parse(item);\n }\n\n async has(id: string): Promise<boolean> {\n this.log(\"Check build '%s'...\", id);\n\n try {\n return await this.database.hasDocument(this.collectionId, id, this.dbOptions);\n } catch {\n return false;\n }\n }\n\n async update(id: string, data: BuildUpdateType): Promise<void> {\n this.log(\"Update build '%s''...\", id);\n\n await this.database.updateDocument(\n this.collectionId,\n id,\n { ...data, updatedAt: new Date().toISOString() },\n this.dbOptions,\n );\n }\n\n async delete(buildId: string, updateTag = true): Promise<void> {\n this.log(\"Delete build '%s'...\", buildId);\n\n const build = await this.get(buildId);\n\n this.debug(\"Delete document '%s'\", buildId);\n await this.database.deleteDocument(this.collectionId, buildId, this.dbOptions);\n\n try {\n this.debug(\"Delete files '%s'\", buildId);\n await this.storage.deleteFiles(\n generateStorageContainerId(this.projectId),\n buildId,\n this.storageOptions,\n );\n } catch (error) {\n this.error(\"Cannot delete container:\", error);\n }\n\n if (updateTag) {\n this.debug(\"Update tags for build '%s'\", buildId);\n const tagIds = build.tagIds?.split(\",\") ?? [];\n const tagsModel = new TagsModel(this.projectId);\n await Promise.allSettled(\n tagIds.map(async (tagId) => {\n const tag = await tagsModel.get(tagId);\n if (tag.latestBuildId === buildId) {\n await tagsModel.update(tagId, {\n buildsCount: Math.max(tag.buildsCount - 1, 0),\n latestBuildId: \"\",\n });\n }\n }),\n );\n }\n\n try {\n const projectsModel = new ProjectsModel();\n const project = await projectsModel.get(this.projectId);\n if (project.latestBuildId === buildId) {\n this.debug(\"Update project for build '%s'\", buildId);\n await projectsModel.update(this.projectId, {\n latestBuildId: \"\",\n });\n }\n } catch (error) {\n this.error(\"Cannot unset build ID from project:\", error);\n }\n }\n\n async upload(buildId: string, variant: BuildUploadVariant, zipFile?: File): Promise<void> {\n const { config, request } = getStore();\n this.log(\"Upload build '%s' (%s)...\", buildId, variant);\n const variantCopy = variant; // for switch fallthrough/default\n\n switch (variant) {\n case \"coverage\":\n case \"testReport\":\n case \"screenshots\":\n case \"storybook\": {\n const size = await this.#uploadZipFile(buildId, variant, zipFile);\n await this.update(buildId, { [variant]: \"uploaded\" });\n\n const {\n maxInlineUploadProcessingSizeInBytes = 5 * 1024 * 1024,\n queueLargeZipFileProcessing = false,\n } = config ?? {};\n\n // Automatically process zip if feature is enabled and size is below limit\n if (size !== undefined && size <= maxInlineUploadProcessingSizeInBytes) {\n await handleProcessZip(this.projectId, buildId, variant).catch((error: unknown) => {\n this.error(\"Error processing zip file:\", error);\n });\n return;\n }\n\n // Otherwise queue processing task if enabled\n if (queueLargeZipFileProcessing) {\n this.log(\"Queue processing for build '%s' (%s)...\", buildId, variant);\n const url = urlBuilder.taskProcessZip(this.projectId, buildId, variant);\n // Do not await fetch to avoid blocking\n fetch(url, { headers: request.headers, method: \"POST\" }).catch((error: unknown) => {\n this.error(\"Error queuing zip file processing:\", error);\n });\n }\n\n return;\n }\n\n default:\n throw new Error(`Unsupported upload variant: ${variantCopy}`);\n }\n }\n\n id: BaseModel<BuildType>[\"id\"] = (id: string) => {\n return {\n checkAuth: (action) =>\n checkAuthorisation({\n action,\n projectId: this.projectId,\n resource: \"build\",\n }),\n delete: this.delete.bind(this, id),\n get: this.get.bind(this, id),\n has: this.has.bind(this, id),\n id,\n update: this.update.bind(this, id),\n };\n };\n\n checkAuth(action: StoryBookerPermissionAction): boolean {\n return checkAuthorisation({\n action,\n projectId: this.projectId,\n resource: \"build\",\n });\n }\n\n async getStories(idOrBuild: string | BuildType): Promise<BuildStoryType[] | null> {\n const { storybook, id } = typeof idOrBuild === \"string\" ? await this.get(idOrBuild) : idOrBuild;\n\n if (storybook !== \"ready\") {\n return null;\n }\n\n const { logger } = getStore();\n\n try {\n this.log(\"List stories '%s'...\", id);\n\n const buildIndexJsonPath = `${id}/storybook/index.json`;\n const { content } = await this.storage.downloadFile(\n generateStorageContainerId(this.projectId),\n buildIndexJsonPath,\n { logger },\n );\n const data: unknown =\n typeof content === \"string\" ? JSON.parse(content) : await new Response(content).json();\n\n if (!data || typeof data !== \"object\" || !(\"entries\" in data) || !data.entries) {\n return [];\n }\n\n return Object.values(data.entries) as BuildStoryType[];\n } catch (error) {\n this.error(\"Error getting stories:\", error);\n return null;\n }\n }\n\n // helpers\n async listByTag(tagId: string): Promise<BuildType[]> {\n const builds = await this.list({\n filter: (item) => (item.tagIds ? item.tagIds.split(\",\").includes(tagId) : false),\n });\n\n return builds;\n }\n\n async deleteByTag(tagId: string, force: boolean): Promise<void> {\n const builds = await this.listByTag(tagId);\n this.log(\n \"Delete builds by tag: '%s' (%d, force: %s)...\",\n tagId,\n builds.length,\n force.valueOf(),\n );\n\n await Promise.allSettled(\n builds.map(async (build): Promise<void> => {\n const buildTagIds = build.tagIds?.split(\",\") ?? [];\n if (!force && buildTagIds.length > 1) {\n const newIds = buildTagIds.filter((id) => id !== tagId);\n await this.update(build.id, { tagIds: newIds.join(\",\") });\n } else {\n await this.delete(build.id, false);\n }\n }),\n );\n }\n\n async #updateOrCreateTag(tagId: string, buildId: string): Promise<string> {\n const tagsModel = new TagsModel(this.projectId);\n // Either \"my-tag\" or \"my-tag;branch\" or \"my-tag;branch;My tag\"\n const [id = tagId, tagType, tagValue] = tagId.split(\";\").map((part) => part.trim());\n\n try {\n const existingTag = await tagsModel.get(id);\n await tagsModel.update(id, {\n buildsCount: existingTag.buildsCount + 1,\n latestBuildId: buildId,\n });\n return id;\n } catch {\n try {\n const type = (tagType as TagVariant) ?? TagsModel.guessType(id);\n const value = tagValue ?? id;\n this.log(\"A new tag '%s' (%s) is being created.\", value, type);\n const tag = await tagsModel.create({ latestBuildId: buildId, type, value }, true);\n\n return tag.id;\n } catch (error) {\n this.error(\"Error creating tag:\", error);\n return id;\n }\n }\n }\n\n async #uploadZipFile(\n buildId: string,\n variant: BuildUploadVariant,\n zipFile?: File,\n ): Promise<number | undefined> {\n const { request } = getStore();\n this.debug(\"(%s-%s) Uploading zip file\", buildId, variant);\n\n const content: string | Blob | ReadableStream | null = zipFile\n ? zipFile.stream()\n : request.body;\n\n if (!content) {\n throw new Error(`No content found for zip file.`);\n }\n\n await this.storage.uploadFiles(\n generateStorageContainerId(this.projectId),\n [\n {\n content,\n mimeType: mimes.zip,\n path: `${buildId}/${variant}.zip`,\n },\n ],\n this.storageOptions,\n );\n\n if (!zipFile) {\n const length = request.headers.get(\"Content-Length\");\n return length ? Number(length) : undefined;\n }\n\n return zipFile?.size;\n }\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
import { buildUploadVariants } from "../~internal/constants.mjs";
|
|
2
|
+
import "./~shared-schema.mjs";
|
|
3
|
+
import { z } from "@hono/zod-openapi";
|
|
4
|
+
|
|
5
|
+
//#region src/models/builds-schema.d.ts
|
|
6
|
+
type BuildType = z.infer<typeof BuildSchema>;
|
|
7
|
+
/** @private */
|
|
8
|
+
declare const BuildSchema: z.ZodObject<{
|
|
9
|
+
authorEmail: z.ZodString;
|
|
10
|
+
authorName: z.ZodString;
|
|
11
|
+
createdAt: z.ZodDefault<z.ZodISODateTime>;
|
|
12
|
+
id: z.ZodString;
|
|
13
|
+
tagIds: z.ZodOptional<z.ZodString>;
|
|
14
|
+
message: z.ZodOptional<z.ZodString>;
|
|
15
|
+
updatedAt: z.ZodDefault<z.ZodISODateTime>;
|
|
16
|
+
coverage: z.ZodEnum<{
|
|
17
|
+
none: "none";
|
|
18
|
+
processing: "processing";
|
|
19
|
+
ready: "ready";
|
|
20
|
+
uploaded: "uploaded";
|
|
21
|
+
}>;
|
|
22
|
+
screenshots: z.ZodEnum<{
|
|
23
|
+
none: "none";
|
|
24
|
+
processing: "processing";
|
|
25
|
+
ready: "ready";
|
|
26
|
+
uploaded: "uploaded";
|
|
27
|
+
}>;
|
|
28
|
+
storybook: z.ZodEnum<{
|
|
29
|
+
none: "none";
|
|
30
|
+
processing: "processing";
|
|
31
|
+
ready: "ready";
|
|
32
|
+
uploaded: "uploaded";
|
|
33
|
+
}>;
|
|
34
|
+
testReport: z.ZodEnum<{
|
|
35
|
+
none: "none";
|
|
36
|
+
processing: "processing";
|
|
37
|
+
ready: "ready";
|
|
38
|
+
uploaded: "uploaded";
|
|
39
|
+
}>;
|
|
40
|
+
}, z.core.$strip>;
|
|
41
|
+
type BuildCreateType = z.infer<typeof BuildCreateSchema>;
|
|
42
|
+
/** @private */
|
|
43
|
+
declare const BuildCreateSchema: z.ZodObject<{
|
|
44
|
+
authorEmail: z.ZodString;
|
|
45
|
+
authorName: z.ZodString;
|
|
46
|
+
id: z.ZodString;
|
|
47
|
+
message: z.ZodOptional<z.ZodString>;
|
|
48
|
+
tags: z.ZodUnion<readonly [z.ZodArray<z.ZodString>, z.ZodString]>;
|
|
49
|
+
}, z.core.$strip>;
|
|
50
|
+
type BuildUpdateType = z.infer<typeof BuildUpdateSchema>;
|
|
51
|
+
declare const BuildUpdateSchema: z.ZodObject<{
|
|
52
|
+
authorEmail: z.ZodOptional<z.ZodString>;
|
|
53
|
+
authorName: z.ZodOptional<z.ZodString>;
|
|
54
|
+
tagIds: z.ZodOptional<z.ZodOptional<z.ZodString>>;
|
|
55
|
+
message: z.ZodOptional<z.ZodOptional<z.ZodString>>;
|
|
56
|
+
coverage: z.ZodOptional<z.ZodEnum<{
|
|
57
|
+
none: "none";
|
|
58
|
+
processing: "processing";
|
|
59
|
+
ready: "ready";
|
|
60
|
+
uploaded: "uploaded";
|
|
61
|
+
}>>;
|
|
62
|
+
screenshots: z.ZodOptional<z.ZodEnum<{
|
|
63
|
+
none: "none";
|
|
64
|
+
processing: "processing";
|
|
65
|
+
ready: "ready";
|
|
66
|
+
uploaded: "uploaded";
|
|
67
|
+
}>>;
|
|
68
|
+
storybook: z.ZodOptional<z.ZodEnum<{
|
|
69
|
+
none: "none";
|
|
70
|
+
processing: "processing";
|
|
71
|
+
ready: "ready";
|
|
72
|
+
uploaded: "uploaded";
|
|
73
|
+
}>>;
|
|
74
|
+
testReport: z.ZodOptional<z.ZodEnum<{
|
|
75
|
+
none: "none";
|
|
76
|
+
processing: "processing";
|
|
77
|
+
ready: "ready";
|
|
78
|
+
uploaded: "uploaded";
|
|
79
|
+
}>>;
|
|
80
|
+
}, z.core.$strip>;
|
|
81
|
+
type BuildUploadVariant = (typeof buildUploadVariants)[number];
|
|
82
|
+
type BuildsListResultType = z.infer<typeof BuildsListResultSchema>;
|
|
83
|
+
declare const BuildsListResultSchema: z.ZodObject<{
|
|
84
|
+
builds: z.ZodArray<z.ZodObject<{
|
|
85
|
+
authorEmail: z.ZodString;
|
|
86
|
+
authorName: z.ZodString;
|
|
87
|
+
createdAt: z.ZodDefault<z.ZodISODateTime>;
|
|
88
|
+
id: z.ZodString;
|
|
89
|
+
tagIds: z.ZodOptional<z.ZodString>;
|
|
90
|
+
message: z.ZodOptional<z.ZodString>;
|
|
91
|
+
updatedAt: z.ZodDefault<z.ZodISODateTime>;
|
|
92
|
+
coverage: z.ZodEnum<{
|
|
93
|
+
none: "none";
|
|
94
|
+
processing: "processing";
|
|
95
|
+
ready: "ready";
|
|
96
|
+
uploaded: "uploaded";
|
|
97
|
+
}>;
|
|
98
|
+
screenshots: z.ZodEnum<{
|
|
99
|
+
none: "none";
|
|
100
|
+
processing: "processing";
|
|
101
|
+
ready: "ready";
|
|
102
|
+
uploaded: "uploaded";
|
|
103
|
+
}>;
|
|
104
|
+
storybook: z.ZodEnum<{
|
|
105
|
+
none: "none";
|
|
106
|
+
processing: "processing";
|
|
107
|
+
ready: "ready";
|
|
108
|
+
uploaded: "uploaded";
|
|
109
|
+
}>;
|
|
110
|
+
testReport: z.ZodEnum<{
|
|
111
|
+
none: "none";
|
|
112
|
+
processing: "processing";
|
|
113
|
+
ready: "ready";
|
|
114
|
+
uploaded: "uploaded";
|
|
115
|
+
}>;
|
|
116
|
+
}, z.core.$strip>>;
|
|
117
|
+
}, z.core.$strip>;
|
|
118
|
+
type BuildsGetResultType = z.infer<typeof BuildsGetResultSchema>;
|
|
119
|
+
declare const BuildsGetResultSchema: z.ZodObject<{
|
|
120
|
+
build: z.ZodObject<{
|
|
121
|
+
authorEmail: z.ZodString;
|
|
122
|
+
authorName: z.ZodString;
|
|
123
|
+
createdAt: z.ZodDefault<z.ZodISODateTime>;
|
|
124
|
+
id: z.ZodString;
|
|
125
|
+
tagIds: z.ZodOptional<z.ZodString>;
|
|
126
|
+
message: z.ZodOptional<z.ZodString>;
|
|
127
|
+
updatedAt: z.ZodDefault<z.ZodISODateTime>;
|
|
128
|
+
coverage: z.ZodEnum<{
|
|
129
|
+
none: "none";
|
|
130
|
+
processing: "processing";
|
|
131
|
+
ready: "ready";
|
|
132
|
+
uploaded: "uploaded";
|
|
133
|
+
}>;
|
|
134
|
+
screenshots: z.ZodEnum<{
|
|
135
|
+
none: "none";
|
|
136
|
+
processing: "processing";
|
|
137
|
+
ready: "ready";
|
|
138
|
+
uploaded: "uploaded";
|
|
139
|
+
}>;
|
|
140
|
+
storybook: z.ZodEnum<{
|
|
141
|
+
none: "none";
|
|
142
|
+
processing: "processing";
|
|
143
|
+
ready: "ready";
|
|
144
|
+
uploaded: "uploaded";
|
|
145
|
+
}>;
|
|
146
|
+
testReport: z.ZodEnum<{
|
|
147
|
+
none: "none";
|
|
148
|
+
processing: "processing";
|
|
149
|
+
ready: "ready";
|
|
150
|
+
uploaded: "uploaded";
|
|
151
|
+
}>;
|
|
152
|
+
}, z.core.$strip>;
|
|
153
|
+
url: z.ZodURL;
|
|
154
|
+
}, z.core.$strip>;
|
|
155
|
+
type BuildStoryType = z.infer<typeof BuildStorySchema>;
|
|
156
|
+
declare const BuildStorySchema: z.ZodObject<{
|
|
157
|
+
id: z.ZodString;
|
|
158
|
+
title: z.ZodString;
|
|
159
|
+
name: z.ZodString;
|
|
160
|
+
importPath: z.ZodString;
|
|
161
|
+
tags: z.ZodArray<z.ZodString>;
|
|
162
|
+
type: z.ZodEnum<{
|
|
163
|
+
docs: "docs";
|
|
164
|
+
story: "story";
|
|
165
|
+
}>;
|
|
166
|
+
componentPath: z.ZodOptional<z.ZodString>;
|
|
167
|
+
storiesImports: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
168
|
+
}, z.core.$strip>;
|
|
169
|
+
//#endregion
|
|
170
|
+
export { BuildCreateType, BuildStoryType, BuildType, BuildUpdateType, BuildUploadVariant, BuildsGetResultType, BuildsListResultType };
|
|
171
|
+
//# sourceMappingURL=builds-schema.d.mts.map
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { buildUploadVariants } from "../~internal/constants.mjs";
|
|
2
|
+
import { BuildIdSchema, TagIdSchema } from "./~shared-schema.mjs";
|
|
3
|
+
import { z } from "@hono/zod-openapi";
|
|
4
|
+
|
|
5
|
+
//#region src/models/builds-schema.ts
|
|
6
|
+
const buildContentAvailabilityOptions = [
|
|
7
|
+
"none",
|
|
8
|
+
"uploaded",
|
|
9
|
+
"processing",
|
|
10
|
+
"ready"
|
|
11
|
+
];
|
|
12
|
+
/** @private */
|
|
13
|
+
const BuildSchema = z.object({
|
|
14
|
+
authorEmail: z.string().refine((val) => val.includes("@"), "Invalid email format").meta({ description: "Email of the author" }),
|
|
15
|
+
authorName: z.string(),
|
|
16
|
+
createdAt: z.iso.datetime().default((/* @__PURE__ */ new Date()).toISOString()),
|
|
17
|
+
id: BuildIdSchema,
|
|
18
|
+
tagIds: z.string().optional(),
|
|
19
|
+
message: z.optional(z.string()),
|
|
20
|
+
updatedAt: z.iso.datetime().default((/* @__PURE__ */ new Date()).toISOString()),
|
|
21
|
+
coverage: z.enum(buildContentAvailabilityOptions),
|
|
22
|
+
screenshots: z.enum(buildContentAvailabilityOptions),
|
|
23
|
+
storybook: z.enum(buildContentAvailabilityOptions),
|
|
24
|
+
testReport: z.enum(buildContentAvailabilityOptions)
|
|
25
|
+
}).meta({
|
|
26
|
+
id: "Build",
|
|
27
|
+
title: "StoryBooker Build"
|
|
28
|
+
});
|
|
29
|
+
/** @private */
|
|
30
|
+
const BuildCreateSchema = BuildSchema.omit({
|
|
31
|
+
createdAt: true,
|
|
32
|
+
coverage: true,
|
|
33
|
+
screenshots: true,
|
|
34
|
+
storybook: true,
|
|
35
|
+
testReport: true,
|
|
36
|
+
tagIds: true,
|
|
37
|
+
updatedAt: true
|
|
38
|
+
}).extend({ tags: z.union([TagIdSchema.array(), TagIdSchema]).meta({ description: "Tag IDs associated with the build. Should be created beforehand." }) });
|
|
39
|
+
const BuildUpdateSchema = BuildSchema.omit({
|
|
40
|
+
createdAt: true,
|
|
41
|
+
id: true,
|
|
42
|
+
updatedAt: true
|
|
43
|
+
}).partial();
|
|
44
|
+
const BuildUploadQueryParamsSchema = z.object({ variant: z.enum(buildUploadVariants).default("storybook") });
|
|
45
|
+
const BuildUploadFormBodySchema = z.object({
|
|
46
|
+
file: z.file().openapi({ type: "object" }),
|
|
47
|
+
variant: z.enum(buildUploadVariants).default("storybook")
|
|
48
|
+
});
|
|
49
|
+
const BuildsListResultSchema = z.object({ builds: BuildSchema.array() });
|
|
50
|
+
const BuildsGetResultSchema = z.object({
|
|
51
|
+
build: BuildSchema,
|
|
52
|
+
url: z.url()
|
|
53
|
+
});
|
|
54
|
+
const BuildStorySchema = z.object({
|
|
55
|
+
id: z.string(),
|
|
56
|
+
title: z.string(),
|
|
57
|
+
name: z.string(),
|
|
58
|
+
importPath: z.string(),
|
|
59
|
+
tags: z.array(z.string()),
|
|
60
|
+
type: z.enum(["docs", "story"]),
|
|
61
|
+
componentPath: z.string().optional(),
|
|
62
|
+
storiesImports: z.array(z.string()).optional()
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
//#endregion
|
|
66
|
+
export { BuildCreateSchema, BuildSchema, BuildUpdateSchema, BuildUploadFormBodySchema, BuildUploadQueryParamsSchema, BuildsGetResultSchema, BuildsListResultSchema };
|
|
67
|
+
//# sourceMappingURL=builds-schema.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"builds-schema.mjs","names":[],"sources":["../../src/models/builds-schema.ts"],"sourcesContent":["// oxlint-disable sort-keys\n\nimport { z } from \"@hono/zod-openapi\";\nimport { buildUploadVariants } from \"../utils/constants.ts\";\nimport { BuildIdSchema, TagIdSchema } from \"./~shared-schema.ts\";\n\nconst buildContentAvailabilityOptions = [\"none\", \"uploaded\", \"processing\", \"ready\"] as const;\n\nexport type BuildType = z.infer<typeof BuildSchema>;\n/** @private */\nexport const BuildSchema = z\n .object({\n authorEmail: z\n .string()\n .refine((val) => val.includes(\"@\"), \"Invalid email format\")\n .meta({ description: \"Email of the author\" }),\n authorName: z.string(),\n createdAt: z.iso.datetime().default(new Date().toISOString()),\n id: BuildIdSchema,\n tagIds: z.string().optional(),\n message: z.optional(z.string()),\n updatedAt: z.iso.datetime().default(new Date().toISOString()),\n coverage: z.enum(buildContentAvailabilityOptions),\n screenshots: z.enum(buildContentAvailabilityOptions),\n storybook: z.enum(buildContentAvailabilityOptions),\n testReport: z.enum(buildContentAvailabilityOptions),\n })\n .meta({ id: \"Build\", title: \"StoryBooker Build\" });\n\nexport type BuildCreateType = z.infer<typeof BuildCreateSchema>;\n/** @private */\nexport const BuildCreateSchema = BuildSchema.omit({\n createdAt: true,\n coverage: true,\n screenshots: true,\n storybook: true,\n testReport: true,\n tagIds: true,\n updatedAt: true,\n}).extend({\n tags: z.union([TagIdSchema.array(), TagIdSchema]).meta({\n description: \"Tag IDs associated with the build. Should be created beforehand.\",\n }),\n});\n\nexport type BuildUpdateType = z.infer<typeof BuildUpdateSchema>;\nexport const BuildUpdateSchema = BuildSchema.omit({\n createdAt: true,\n id: true,\n updatedAt: true,\n}).partial();\n\nexport type BuildUploadVariant = (typeof buildUploadVariants)[number];\nexport const BuildUploadQueryParamsSchema = z.object({\n variant: z.enum(buildUploadVariants).default(\"storybook\"),\n});\nexport const BuildUploadFormBodySchema = z.object({\n file: z.file().openapi({ type: \"object\" }),\n variant: z.enum(buildUploadVariants).default(\"storybook\"),\n});\n\nexport type BuildsListResultType = z.infer<typeof BuildsListResultSchema>;\nexport const BuildsListResultSchema = z.object({\n builds: BuildSchema.array(),\n});\nexport type BuildsGetResultType = z.infer<typeof BuildsGetResultSchema>;\nexport const BuildsGetResultSchema = z.object({\n build: BuildSchema,\n url: z.url(),\n});\n\nexport type BuildStoryType = z.infer<typeof BuildStorySchema>;\nexport const BuildStorySchema = z.object({\n id: z.string(),\n title: z.string(),\n name: z.string(),\n importPath: z.string(),\n tags: z.array(z.string()),\n type: z.enum([\"docs\", \"story\"]),\n componentPath: z.string().optional(),\n storiesImports: z.array(z.string()).optional(),\n});\n\nexport { BuildIdSchema, buildUploadVariants };\n"],"mappings":";;;;;AAMA,MAAM,kCAAkC;CAAC;CAAQ;CAAY;CAAc;CAAQ;;AAInF,MAAa,cAAc,EACxB,OAAO;CACN,aAAa,EACV,QAAQ,CACR,QAAQ,QAAQ,IAAI,SAAS,IAAI,EAAE,uBAAuB,CAC1D,KAAK,EAAE,aAAa,uBAAuB,CAAC;CAC/C,YAAY,EAAE,QAAQ;CACtB,WAAW,EAAE,IAAI,UAAU,CAAC,yBAAQ,IAAI,MAAM,EAAC,aAAa,CAAC;CAC7D,IAAI;CACJ,QAAQ,EAAE,QAAQ,CAAC,UAAU;CAC7B,SAAS,EAAE,SAAS,EAAE,QAAQ,CAAC;CAC/B,WAAW,EAAE,IAAI,UAAU,CAAC,yBAAQ,IAAI,MAAM,EAAC,aAAa,CAAC;CAC7D,UAAU,EAAE,KAAK,gCAAgC;CACjD,aAAa,EAAE,KAAK,gCAAgC;CACpD,WAAW,EAAE,KAAK,gCAAgC;CAClD,YAAY,EAAE,KAAK,gCAAgC;CACpD,CAAC,CACD,KAAK;CAAE,IAAI;CAAS,OAAO;CAAqB,CAAC;;AAIpD,MAAa,oBAAoB,YAAY,KAAK;CAChD,WAAW;CACX,UAAU;CACV,aAAa;CACb,WAAW;CACX,YAAY;CACZ,QAAQ;CACR,WAAW;CACZ,CAAC,CAAC,OAAO,EACR,MAAM,EAAE,MAAM,CAAC,YAAY,OAAO,EAAE,YAAY,CAAC,CAAC,KAAK,EACrD,aAAa,oEACd,CAAC,EACH,CAAC;AAGF,MAAa,oBAAoB,YAAY,KAAK;CAChD,WAAW;CACX,IAAI;CACJ,WAAW;CACZ,CAAC,CAAC,SAAS;AAGZ,MAAa,+BAA+B,EAAE,OAAO,EACnD,SAAS,EAAE,KAAK,oBAAoB,CAAC,QAAQ,YAAY,EAC1D,CAAC;AACF,MAAa,4BAA4B,EAAE,OAAO;CAChD,MAAM,EAAE,MAAM,CAAC,QAAQ,EAAE,MAAM,UAAU,CAAC;CAC1C,SAAS,EAAE,KAAK,oBAAoB,CAAC,QAAQ,YAAY;CAC1D,CAAC;AAGF,MAAa,yBAAyB,EAAE,OAAO,EAC7C,QAAQ,YAAY,OAAO,EAC5B,CAAC;AAEF,MAAa,wBAAwB,EAAE,OAAO;CAC5C,OAAO;CACP,KAAK,EAAE,KAAK;CACb,CAAC;AAGF,MAAa,mBAAmB,EAAE,OAAO;CACvC,IAAI,EAAE,QAAQ;CACd,OAAO,EAAE,QAAQ;CACjB,MAAM,EAAE,QAAQ;CAChB,YAAY,EAAE,QAAQ;CACtB,MAAM,EAAE,MAAM,EAAE,QAAQ,CAAC;CACzB,MAAM,EAAE,KAAK,CAAC,QAAQ,QAAQ,CAAC;CAC/B,eAAe,EAAE,QAAQ,CAAC,UAAU;CACpC,gBAAgB,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC,UAAU;CAC/C,CAAC"}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { generateDatabaseCollectionId, generateStorageContainerId } from "../utils/adapter-utils.mjs";
|
|
2
|
+
import { checkAuthorisation } from "../utils/auth.mjs";
|
|
3
|
+
import { ProjectSchema } from "./projects-schema.mjs";
|
|
4
|
+
import { Model } from "./~model.mjs";
|
|
5
|
+
import { TagsModel } from "./tags-model.mjs";
|
|
6
|
+
import { HTTPException } from "hono/http-exception";
|
|
7
|
+
|
|
8
|
+
//#region src/models/projects-model.ts
|
|
9
|
+
var ProjectsModel = class extends Model {
|
|
10
|
+
constructor() {
|
|
11
|
+
super(null, generateDatabaseCollectionId("Projects", ""));
|
|
12
|
+
}
|
|
13
|
+
async list(options = {}) {
|
|
14
|
+
this.log("List projects...");
|
|
15
|
+
try {
|
|
16
|
+
return await this.database.listDocuments(this.collectionId, options, this.dbOptions);
|
|
17
|
+
} catch (error) {
|
|
18
|
+
this.error("Error listing projects:", error);
|
|
19
|
+
return [];
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
async create(data) {
|
|
23
|
+
this.log("Creating project...");
|
|
24
|
+
const projectId = data.id;
|
|
25
|
+
try {
|
|
26
|
+
if (await this.has(projectId)) throw new HTTPException(409, { message: `Project '${projectId}' already exists.` });
|
|
27
|
+
await this.storage.createContainer(generateStorageContainerId(projectId), this.storageOptions);
|
|
28
|
+
this.debug("Creating project collection");
|
|
29
|
+
await this.database.createCollection(this.collectionId, this.dbOptions).catch((error) => {
|
|
30
|
+
this.error("Error creating projects collection:", error);
|
|
31
|
+
});
|
|
32
|
+
await this.database.createCollection(generateDatabaseCollectionId(projectId, "Builds"), this.dbOptions);
|
|
33
|
+
await this.database.createCollection(generateDatabaseCollectionId(projectId, "Tags"), this.dbOptions);
|
|
34
|
+
this.debug("Creating default branch (%s) tag", data.gitHubDefaultBranch);
|
|
35
|
+
await new TagsModel(projectId).create({
|
|
36
|
+
type: "branch",
|
|
37
|
+
value: data.gitHubDefaultBranch
|
|
38
|
+
}).catch((error) => {
|
|
39
|
+
this.error("Error creating default branch tag:", error);
|
|
40
|
+
});
|
|
41
|
+
this.debug("Creating project entry '%s' in collection", projectId);
|
|
42
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
43
|
+
const project = {
|
|
44
|
+
...data,
|
|
45
|
+
createdAt: now,
|
|
46
|
+
updatedAt: now
|
|
47
|
+
};
|
|
48
|
+
await this.database.createDocument(this.collectionId, project, this.dbOptions);
|
|
49
|
+
return project;
|
|
50
|
+
} catch (error) {
|
|
51
|
+
throw new HTTPException(500, {
|
|
52
|
+
cause: error,
|
|
53
|
+
message: `Failed to create project '${projectId}'.`
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
async get(id) {
|
|
58
|
+
this.log("Get project '%s'...", id);
|
|
59
|
+
const item = await this.database.getDocument(this.collectionId, id, this.dbOptions);
|
|
60
|
+
return ProjectSchema.parse(item);
|
|
61
|
+
}
|
|
62
|
+
async has(id) {
|
|
63
|
+
this.log("Check project '%s'...", id);
|
|
64
|
+
try {
|
|
65
|
+
return await this.database.hasDocument(this.collectionId, id, this.dbOptions);
|
|
66
|
+
} catch {
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
async update(id, data) {
|
|
71
|
+
this.log("Update project '%s'...", id);
|
|
72
|
+
await this.database.updateDocument(this.collectionId, id, {
|
|
73
|
+
...data,
|
|
74
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
75
|
+
}, this.dbOptions);
|
|
76
|
+
if (data.gitHubDefaultBranch) try {
|
|
77
|
+
this.debug("Create default-branch tag '%s'...", data.gitHubDefaultBranch);
|
|
78
|
+
await new TagsModel(id).create({
|
|
79
|
+
type: "branch",
|
|
80
|
+
value: data.gitHubDefaultBranch
|
|
81
|
+
});
|
|
82
|
+
} catch (error) {
|
|
83
|
+
this.error("Error creating default branch tag:", error);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
async delete(id) {
|
|
87
|
+
this.log("Delete project '%s'...", id);
|
|
88
|
+
this.debug("Delete project entry '%s' in collection", id);
|
|
89
|
+
await this.database.deleteDocument(this.collectionId, id, this.dbOptions);
|
|
90
|
+
this.debug("Delete project-builds collection");
|
|
91
|
+
await this.database.deleteCollection(generateDatabaseCollectionId(id, "Builds"), this.dbOptions);
|
|
92
|
+
this.debug("Delete project-tags collection");
|
|
93
|
+
await this.database.deleteCollection(generateDatabaseCollectionId(id, "Tags"), this.dbOptions);
|
|
94
|
+
this.debug("Delete project container");
|
|
95
|
+
await this.storage.deleteContainer(generateStorageContainerId(id), this.storageOptions);
|
|
96
|
+
}
|
|
97
|
+
checkAuth(action, id) {
|
|
98
|
+
return checkAuthorisation({
|
|
99
|
+
action,
|
|
100
|
+
projectId: id ?? (this.projectId || void 0),
|
|
101
|
+
resource: "project"
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
id = (id) => {
|
|
105
|
+
return {
|
|
106
|
+
checkAuth: (action) => checkAuthorisation({
|
|
107
|
+
action,
|
|
108
|
+
projectId: id,
|
|
109
|
+
resource: "project"
|
|
110
|
+
}),
|
|
111
|
+
delete: this.delete.bind(this, id),
|
|
112
|
+
get: this.get.bind(this, id),
|
|
113
|
+
has: this.has.bind(this, id),
|
|
114
|
+
id,
|
|
115
|
+
update: this.update.bind(this, id)
|
|
116
|
+
};
|
|
117
|
+
};
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
//#endregion
|
|
121
|
+
export { ProjectsModel };
|
|
122
|
+
//# sourceMappingURL=projects-model.mjs.map
|