veryfront 0.1.92 → 0.1.93
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/esm/cli/commands/styles/command-help.d.ts +3 -0
- package/esm/cli/commands/styles/command-help.d.ts.map +1 -0
- package/esm/cli/commands/styles/command-help.js +19 -0
- package/esm/cli/commands/styles/command.d.ts +3 -0
- package/esm/cli/commands/styles/command.d.ts.map +1 -0
- package/esm/cli/commands/styles/command.js +198 -0
- package/esm/cli/commands/styles/handler.d.ts +24 -0
- package/esm/cli/commands/styles/handler.d.ts.map +1 -0
- package/esm/cli/commands/styles/handler.js +17 -0
- package/esm/cli/help/command-definitions.d.ts.map +1 -1
- package/esm/cli/help/command-definitions.js +2 -0
- package/esm/cli/router.d.ts.map +1 -1
- package/esm/cli/router.js +2 -0
- package/esm/deno.d.ts +1 -0
- package/esm/deno.js +2 -1
- package/esm/src/html/styles-builder/css-pregeneration.d.ts +9 -0
- package/esm/src/html/styles-builder/css-pregeneration.d.ts.map +1 -1
- package/esm/src/html/styles-builder/css-pregeneration.js +26 -15
- package/esm/src/jobs/schemas.d.ts +40 -40
- package/esm/src/platform/adapters/veryfront-api-client/client.d.ts +2 -1
- package/esm/src/platform/adapters/veryfront-api-client/client.d.ts.map +1 -1
- package/esm/src/platform/adapters/veryfront-api-client/client.js +3 -0
- package/esm/src/platform/adapters/veryfront-api-client/index.d.ts +1 -1
- package/esm/src/platform/adapters/veryfront-api-client/index.d.ts.map +1 -1
- package/esm/src/platform/adapters/veryfront-api-client/operations.d.ts +11 -2
- package/esm/src/platform/adapters/veryfront-api-client/operations.d.ts.map +1 -1
- package/esm/src/platform/adapters/veryfront-api-client/operations.js +30 -0
- package/esm/src/platform/adapters/veryfront-api-client/schemas/api.schema.d.ts +14 -3
- package/esm/src/platform/adapters/veryfront-api-client/schemas/api.schema.d.ts.map +1 -1
- package/esm/src/platform/adapters/veryfront-api-client/schemas/api.schema.js +8 -1
- package/esm/src/rendering/styles.d.ts +9 -0
- package/esm/src/rendering/styles.d.ts.map +1 -0
- package/esm/src/rendering/styles.js +8 -0
- package/esm/src/sandbox/index.d.ts +1 -1
- package/esm/src/sandbox/index.d.ts.map +1 -1
- package/esm/src/sandbox/sandbox.d.ts +14 -3
- package/esm/src/sandbox/sandbox.d.ts.map +1 -1
- package/esm/src/sandbox/sandbox.js +20 -6
- package/esm/src/security/http/base-handler.d.ts.map +1 -1
- package/esm/src/security/http/base-handler.js +5 -2
- package/esm/src/server/context/request-context.d.ts.map +1 -1
- package/esm/src/server/context/request-context.js +4 -2
- package/esm/src/server/handlers/dev/styles-css.handler.d.ts +2 -0
- package/esm/src/server/handlers/dev/styles-css.handler.d.ts.map +1 -1
- package/esm/src/server/handlers/dev/styles-css.handler.js +23 -0
- package/esm/src/server/handlers/preview/markdown-preview.handler.d.ts.map +1 -1
- package/esm/src/server/handlers/preview/markdown-preview.handler.js +4 -2
- package/esm/src/server/handlers/request/css.handler.d.ts.map +1 -1
- package/esm/src/server/handlers/request/css.handler.js +4 -2
- package/esm/src/server/handlers/request/ssr/ssr.handler.d.ts.map +1 -1
- package/esm/src/server/handlers/request/ssr/ssr.handler.js +4 -2
- package/esm/src/utils/version.d.ts +1 -1
- package/esm/src/utils/version.js +1 -1
- package/package.json +1 -1
- package/src/cli/commands/styles/command-help.ts +21 -0
- package/src/cli/commands/styles/command.ts +296 -0
- package/src/cli/commands/styles/handler.ts +23 -0
- package/src/cli/help/command-definitions.ts +2 -0
- package/src/cli/router.ts +2 -0
- package/src/deno.js +2 -1
- package/src/src/html/styles-builder/css-pregeneration.ts +57 -29
- package/src/src/platform/adapters/veryfront-api-client/client.ts +8 -0
- package/src/src/platform/adapters/veryfront-api-client/index.ts +1 -0
- package/src/src/platform/adapters/veryfront-api-client/operations.ts +48 -2
- package/src/src/platform/adapters/veryfront-api-client/schemas/api.schema.ts +9 -1
- package/src/src/rendering/styles.ts +15 -0
- package/src/src/sandbox/index.ts +1 -0
- package/src/src/sandbox/sandbox.ts +33 -6
- package/src/src/security/http/base-handler.ts +5 -2
- package/src/src/server/context/request-context.ts +4 -2
- package/src/src/server/handlers/dev/styles-css.handler.ts +31 -0
- package/src/src/server/handlers/preview/markdown-preview.handler.ts +4 -2
- package/src/src/server/handlers/request/css.handler.ts +4 -2
- package/src/src/server/handlers/request/ssr/ssr.handler.ts +4 -2
- package/src/src/utils/version.ts +1 -1
|
@@ -2,7 +2,7 @@ import { BaseHandler } from "../../response/base.js";
|
|
|
2
2
|
import { PRIORITY_LOW } from "../../../../utils/constants/index.js";
|
|
3
3
|
import { generateNonce } from "../../../../security/http/response/security-handler.js";
|
|
4
4
|
import { isExtendedFSAdapter } from "../../../../platform/adapters/fs/wrapper.js";
|
|
5
|
-
import {
|
|
5
|
+
import { getHostEnv } from "../../../../platform/compat/process.js";
|
|
6
6
|
import { shouldUseNoCacheHeadersFromHandler } from "../../../context/enriched-context.js";
|
|
7
7
|
import { withSpan } from "../../../../observability/tracing/otlp-setup.js";
|
|
8
8
|
import { serverLogger } from "../../../../utils/index.js";
|
|
@@ -76,7 +76,9 @@ export class SSRHandler extends BaseHandler {
|
|
|
76
76
|
if (ctx.projectSlug && isExtended && fsAdapter.isMultiProjectMode()) {
|
|
77
77
|
const prodMode = isProductionMode(ctx, url);
|
|
78
78
|
const branch = ctx.parsedDomain?.branch ?? null;
|
|
79
|
-
|
|
79
|
+
// Framework-owned token: bypass project env overlay so proxy mode works
|
|
80
|
+
// when a remote project overlay is active.
|
|
81
|
+
const effectiveToken = ctx.proxyToken || getHostEnv("VERYFRONT_API_TOKEN") || "";
|
|
80
82
|
logger.debug("Using multi-project context", {
|
|
81
83
|
projectSlug: ctx.projectSlug,
|
|
82
84
|
productionMode: prodMode,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export declare const VERSION = "0.1.
|
|
1
|
+
export declare const VERSION = "0.1.93";
|
|
2
2
|
export declare function normalizeVeryfrontVersion(version: string | undefined): string | undefined;
|
|
3
3
|
export declare function resolveRuntimeVersion(options?: {
|
|
4
4
|
veryfrontVersion?: string;
|
package/esm/src/utils/version.js
CHANGED
|
@@ -2,7 +2,7 @@ import denoConfig from "../../deno.js";
|
|
|
2
2
|
import { getEnv } from "../platform/compat/process.js";
|
|
3
3
|
// Keep in sync with deno.json version.
|
|
4
4
|
// scripts/release.ts updates this constant during releases.
|
|
5
|
-
export const VERSION = "0.1.
|
|
5
|
+
export const VERSION = "0.1.93";
|
|
6
6
|
export function normalizeVeryfrontVersion(version) {
|
|
7
7
|
if (!version)
|
|
8
8
|
return undefined;
|
package/package.json
CHANGED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { CommandHelp } from "../../help/types.js";
|
|
2
|
+
|
|
3
|
+
export const stylesHelp: CommandHelp = {
|
|
4
|
+
name: "styles",
|
|
5
|
+
description: "Build project CSS artifacts",
|
|
6
|
+
usage: "veryfront styles build-artifact --config <json>",
|
|
7
|
+
options: [
|
|
8
|
+
{
|
|
9
|
+
flag: "--config <json>",
|
|
10
|
+
description: "JSON build config with exactly one selector and an optional style_profile_hash",
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
flag: "--debug",
|
|
14
|
+
description: "Enable debug logging",
|
|
15
|
+
},
|
|
16
|
+
],
|
|
17
|
+
examples: [
|
|
18
|
+
'veryfront styles build-artifact --config \'{"branch":"main"}\'',
|
|
19
|
+
'veryfront styles build-artifact --config \'{"style_profile_hash":"profile-1","environment_name":"Production"}\'',
|
|
20
|
+
],
|
|
21
|
+
};
|
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
import * as dntShim from "../../../_dnt.shims.js";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
import { getConfig } from "../../../src/config/index.js";
|
|
4
|
+
import {
|
|
5
|
+
enhanceAdapterWithFS,
|
|
6
|
+
getEnv,
|
|
7
|
+
isExtendedFSAdapter,
|
|
8
|
+
runtime,
|
|
9
|
+
type VeryfrontApiClient,
|
|
10
|
+
} from "../../../src/platform/index.js";
|
|
11
|
+
import {
|
|
12
|
+
buildPreparedCSSArtifactFromFiles,
|
|
13
|
+
createStyleScopeProfile,
|
|
14
|
+
resolveStyleContentVersion,
|
|
15
|
+
} from "../../../src/rendering/styles.js";
|
|
16
|
+
import { cliLogger, exitProcess } from "../../utils/index.js";
|
|
17
|
+
import type { StylesArgs } from "./handler.js";
|
|
18
|
+
import { writeJobResultIfConfigured } from "../../utils/write-job-result.js";
|
|
19
|
+
|
|
20
|
+
const StyleArtifactBuildConfigSchema = z.object({
|
|
21
|
+
style_profile_hash: z.string().min(1).optional(),
|
|
22
|
+
branch: z.string().min(1).optional(),
|
|
23
|
+
environment_name: z.string().min(1).optional(),
|
|
24
|
+
release_id: z.string().min(1).optional(),
|
|
25
|
+
}).superRefine((value, ctx) => {
|
|
26
|
+
const selectorCount = [value.branch, value.environment_name, value.release_id].filter(Boolean)
|
|
27
|
+
.length;
|
|
28
|
+
if (selectorCount !== 1) {
|
|
29
|
+
ctx.addIssue({
|
|
30
|
+
code: z.ZodIssueCode.custom,
|
|
31
|
+
message: "Exactly one of branch, environment_name, or release_id is required.",
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
type StyleArtifactBuildConfig = z.infer<typeof StyleArtifactBuildConfigSchema>;
|
|
37
|
+
|
|
38
|
+
interface StyleBuildContentContext {
|
|
39
|
+
branch?: string;
|
|
40
|
+
environmentName?: string;
|
|
41
|
+
releaseId?: string;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
interface StyleArtifactBuildResult {
|
|
45
|
+
kind: "style_artifact";
|
|
46
|
+
status: "ready";
|
|
47
|
+
style_profile_hash: string;
|
|
48
|
+
artifact_hash: string;
|
|
49
|
+
asset_path: string;
|
|
50
|
+
content_type: string;
|
|
51
|
+
etag: string;
|
|
52
|
+
selector: {
|
|
53
|
+
type: "branch" | "environment" | "release";
|
|
54
|
+
value: string;
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
type StyleArtifactSelector =
|
|
59
|
+
| { branch: string; environmentName?: never; releaseId?: never; type: "branch"; value: string }
|
|
60
|
+
| {
|
|
61
|
+
branch?: never;
|
|
62
|
+
environmentName: string;
|
|
63
|
+
releaseId?: never;
|
|
64
|
+
type: "environment";
|
|
65
|
+
value: string;
|
|
66
|
+
}
|
|
67
|
+
| { branch?: never; environmentName?: never; releaseId: string; type: "release"; value: string };
|
|
68
|
+
|
|
69
|
+
function parseStyleArtifactBuildConfig(rawConfig: string | undefined): StyleArtifactBuildConfig {
|
|
70
|
+
if (!rawConfig) {
|
|
71
|
+
throw new Error("Missing --config JSON");
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
let parsed: unknown;
|
|
75
|
+
try {
|
|
76
|
+
parsed = JSON.parse(rawConfig);
|
|
77
|
+
} catch {
|
|
78
|
+
throw new Error("Invalid --config JSON");
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
return StyleArtifactBuildConfigSchema.parse(parsed);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function resolveStyleArtifactSelector(
|
|
85
|
+
config: StyleArtifactBuildConfig,
|
|
86
|
+
): StyleArtifactSelector {
|
|
87
|
+
if (config.branch) {
|
|
88
|
+
return {
|
|
89
|
+
branch: config.branch,
|
|
90
|
+
type: "branch",
|
|
91
|
+
value: config.branch,
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
if (config.environment_name) {
|
|
96
|
+
return {
|
|
97
|
+
environmentName: config.environment_name,
|
|
98
|
+
type: "environment",
|
|
99
|
+
value: config.environment_name,
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
return {
|
|
104
|
+
releaseId: config.release_id!,
|
|
105
|
+
type: "release",
|
|
106
|
+
value: config.release_id!,
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
function resolveContentContextSelector(
|
|
111
|
+
selector: StyleArtifactSelector,
|
|
112
|
+
): { type: "branch"; branch: string } | { type: "environment"; name: string } | {
|
|
113
|
+
type: "release";
|
|
114
|
+
releaseId: string;
|
|
115
|
+
} {
|
|
116
|
+
if (selector.type === "branch") {
|
|
117
|
+
return { type: "branch", branch: selector.branch };
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
if (selector.type === "environment") {
|
|
121
|
+
return { type: "environment", name: selector.environmentName };
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
return { type: "release", releaseId: selector.releaseId };
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
function requireEnv(name: string): string {
|
|
128
|
+
const value = getEnv(name)?.trim();
|
|
129
|
+
if (!value) {
|
|
130
|
+
throw new Error(`${name} is required`);
|
|
131
|
+
}
|
|
132
|
+
return value;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
function getUnderlyingVeryfrontClient(adapter: Awaited<ReturnType<typeof enhanceAdapterWithFS>>): {
|
|
136
|
+
client: VeryfrontApiClient;
|
|
137
|
+
contentContext: StyleBuildContentContext | null;
|
|
138
|
+
getAllSourceFiles: () => Promise<Array<{ path: string; content?: string }>>;
|
|
139
|
+
} {
|
|
140
|
+
if (!isExtendedFSAdapter(adapter.fs)) {
|
|
141
|
+
throw new Error("Styles build requires a Veryfront FS adapter");
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
const fsAdapter = adapter.fs.getUnderlyingAdapter() as {
|
|
145
|
+
getAllSourceFiles?: () => Promise<Array<{ path: string; content?: string }>>;
|
|
146
|
+
getContentContext?: () => StyleBuildContentContext | null;
|
|
147
|
+
getClient?: () => VeryfrontApiClient;
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
if (
|
|
151
|
+
typeof fsAdapter.getAllSourceFiles !== "function" ||
|
|
152
|
+
typeof fsAdapter.getClient !== "function"
|
|
153
|
+
) {
|
|
154
|
+
throw new Error("Styles build requires a Veryfront source adapter");
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
return {
|
|
158
|
+
client: fsAdapter.getClient(),
|
|
159
|
+
contentContext: typeof fsAdapter.getContentContext === "function"
|
|
160
|
+
? fsAdapter.getContentContext()
|
|
161
|
+
: null,
|
|
162
|
+
getAllSourceFiles: fsAdapter.getAllSourceFiles,
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
async function markStyleArtifactFailed(
|
|
167
|
+
client: VeryfrontApiClient | null,
|
|
168
|
+
selector: StyleArtifactSelector,
|
|
169
|
+
styleProfileHash: string | null | undefined,
|
|
170
|
+
error: string,
|
|
171
|
+
): Promise<void> {
|
|
172
|
+
if (!client || !styleProfileHash) return;
|
|
173
|
+
|
|
174
|
+
try {
|
|
175
|
+
await client.upsertStyleArtifact({
|
|
176
|
+
...(selector.type === "branch" ? { branch: selector.branch } : {}),
|
|
177
|
+
...(selector.type === "environment" ? { environmentName: selector.environmentName } : {}),
|
|
178
|
+
...(selector.type === "release" ? { releaseId: selector.releaseId } : {}),
|
|
179
|
+
styleProfileHash,
|
|
180
|
+
status: "failed",
|
|
181
|
+
failureReason: error,
|
|
182
|
+
});
|
|
183
|
+
} catch (updateError) {
|
|
184
|
+
cliLogger.warn("Failed to mark style artifact as failed", updateError);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
export async function stylesCommand(options: StylesArgs): Promise<void> {
|
|
189
|
+
const buildConfig = parseStyleArtifactBuildConfig(options.config);
|
|
190
|
+
const selector = resolveStyleArtifactSelector(buildConfig);
|
|
191
|
+
const projectSlug = requireEnv("VERYFRONT_PROJECT_SLUG");
|
|
192
|
+
const apiToken = requireEnv("VERYFRONT_API_TOKEN");
|
|
193
|
+
const apiBaseUrl = requireEnv("VERYFRONT_API_BASE_URL");
|
|
194
|
+
const projectId = getEnv("VERYFRONT_PROJECT_ID")?.trim();
|
|
195
|
+
const projectDir = dntShim.Deno.cwd();
|
|
196
|
+
|
|
197
|
+
const baseAdapter = await runtime.get();
|
|
198
|
+
const adapter = await enhanceAdapterWithFS(
|
|
199
|
+
baseAdapter,
|
|
200
|
+
{
|
|
201
|
+
fs: {
|
|
202
|
+
type: "veryfront-api",
|
|
203
|
+
projectDir,
|
|
204
|
+
veryfront: {
|
|
205
|
+
apiBaseUrl,
|
|
206
|
+
apiToken,
|
|
207
|
+
projectSlug,
|
|
208
|
+
projectId,
|
|
209
|
+
contentSource: resolveContentContextSelector(selector),
|
|
210
|
+
},
|
|
211
|
+
},
|
|
212
|
+
},
|
|
213
|
+
projectDir,
|
|
214
|
+
);
|
|
215
|
+
|
|
216
|
+
let client: VeryfrontApiClient | null = null;
|
|
217
|
+
let resolvedStyleProfileHash: string | null = buildConfig.style_profile_hash ?? null;
|
|
218
|
+
|
|
219
|
+
try {
|
|
220
|
+
const sourceAdapter = getUnderlyingVeryfrontClient(adapter);
|
|
221
|
+
client = sourceAdapter.client;
|
|
222
|
+
const cacheKey = projectId || projectSlug;
|
|
223
|
+
const config = await getConfig(projectDir, adapter, { cacheKey });
|
|
224
|
+
const styleProfile = createStyleScopeProfile(config);
|
|
225
|
+
resolvedStyleProfileHash = styleProfile.hash;
|
|
226
|
+
|
|
227
|
+
if (buildConfig.style_profile_hash && styleProfile.hash !== buildConfig.style_profile_hash) {
|
|
228
|
+
const message =
|
|
229
|
+
`Style profile hash mismatch: expected ${buildConfig.style_profile_hash}, got ${styleProfile.hash}`;
|
|
230
|
+
await markStyleArtifactFailed(client, selector, buildConfig.style_profile_hash, message);
|
|
231
|
+
throw new Error(message);
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
const files = await sourceAdapter.getAllSourceFiles();
|
|
235
|
+
if (files.length === 0) {
|
|
236
|
+
throw new Error("No project files were available to build the style artifact");
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
const projectVersion = resolveStyleContentVersion(null, {
|
|
240
|
+
branch: sourceAdapter.contentContext?.branch ?? null,
|
|
241
|
+
releaseId: sourceAdapter.contentContext?.releaseId ?? null,
|
|
242
|
+
environmentName: sourceAdapter.contentContext?.environmentName ?? null,
|
|
243
|
+
});
|
|
244
|
+
const build = await buildPreparedCSSArtifactFromFiles({
|
|
245
|
+
projectSlug,
|
|
246
|
+
projectVersion,
|
|
247
|
+
projectDir,
|
|
248
|
+
files,
|
|
249
|
+
styleProfile,
|
|
250
|
+
stylesheetPath: config?.tailwind?.stylesheet,
|
|
251
|
+
minify: true,
|
|
252
|
+
environment: "preview",
|
|
253
|
+
buildMode: "production",
|
|
254
|
+
});
|
|
255
|
+
|
|
256
|
+
const resolution = await client.upsertStyleArtifact({
|
|
257
|
+
...(selector.type === "branch" ? { branch: selector.branch } : {}),
|
|
258
|
+
...(selector.type === "environment" ? { environmentName: selector.environmentName } : {}),
|
|
259
|
+
...(selector.type === "release" ? { releaseId: selector.releaseId } : {}),
|
|
260
|
+
styleProfileHash: styleProfile.hash,
|
|
261
|
+
status: "ready",
|
|
262
|
+
artifactHash: build.hash,
|
|
263
|
+
});
|
|
264
|
+
|
|
265
|
+
const result: StyleArtifactBuildResult = {
|
|
266
|
+
kind: "style_artifact",
|
|
267
|
+
status: "ready",
|
|
268
|
+
style_profile_hash: styleProfile.hash,
|
|
269
|
+
artifact_hash: build.hash,
|
|
270
|
+
asset_path: resolution.assetPath ?? `/_vf/css/${build.hash}.css`,
|
|
271
|
+
content_type: resolution.contentType ?? "text/css; charset=utf-8",
|
|
272
|
+
etag: resolution.etag ?? `"${build.hash}"`,
|
|
273
|
+
selector: {
|
|
274
|
+
type: selector.type,
|
|
275
|
+
value: selector.value,
|
|
276
|
+
},
|
|
277
|
+
};
|
|
278
|
+
|
|
279
|
+
await writeJobResultIfConfigured(result);
|
|
280
|
+
cliLogger.info(`Built style artifact ${build.hash}`);
|
|
281
|
+
} catch (error) {
|
|
282
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
283
|
+
await markStyleArtifactFailed(
|
|
284
|
+
client,
|
|
285
|
+
selector,
|
|
286
|
+
resolvedStyleProfileHash ?? buildConfig.style_profile_hash,
|
|
287
|
+
message,
|
|
288
|
+
);
|
|
289
|
+
cliLogger.error(message);
|
|
290
|
+
exitProcess(1);
|
|
291
|
+
} finally {
|
|
292
|
+
if (isExtendedFSAdapter(adapter.fs)) {
|
|
293
|
+
await adapter.fs.shutdown();
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { createArgParser, parseArgsOrThrow } from "../../shared/args.js";
|
|
3
|
+
import type { ParsedArgs } from "../../shared/types.js";
|
|
4
|
+
|
|
5
|
+
const StylesArgsSchema = z.object({
|
|
6
|
+
subcommand: z.literal("build-artifact"),
|
|
7
|
+
config: z.string().optional(),
|
|
8
|
+
debug: z.boolean().default(false),
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
export type StylesArgs = z.infer<typeof StylesArgsSchema>;
|
|
12
|
+
|
|
13
|
+
export const parseStylesArgs = createArgParser(StylesArgsSchema, {
|
|
14
|
+
subcommand: { keys: ["subcommand"], type: "string", positional: 0 },
|
|
15
|
+
config: { keys: ["config"], type: "string" },
|
|
16
|
+
debug: { keys: ["debug"], type: "boolean" },
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
export async function handleStylesCommand(args: ParsedArgs): Promise<void> {
|
|
20
|
+
const opts = parseArgsOrThrow(parseStylesArgs, "styles", args);
|
|
21
|
+
const { stylesCommand } = await import("./command.js");
|
|
22
|
+
await stylesCommand(opts);
|
|
23
|
+
}
|
|
@@ -16,6 +16,7 @@ import { doctorHelp } from "../commands/doctor/command-help.js";
|
|
|
16
16
|
import { cleanHelp } from "../commands/clean/command-help.js";
|
|
17
17
|
import { routesHelp } from "../commands/routes/command-help.js";
|
|
18
18
|
import { studioHelp } from "../commands/studio/command-help.js";
|
|
19
|
+
import { stylesHelp } from "../commands/styles/command-help.js";
|
|
19
20
|
import { lockHelp } from "../commands/lock/command-help.js";
|
|
20
21
|
import { analyzeChunksHelp } from "../commands/analyze-chunks/command-help.js";
|
|
21
22
|
import { generateHelp } from "../commands/generate/command-help.js";
|
|
@@ -51,6 +52,7 @@ export const COMMANDS: CommandRegistry = {
|
|
|
51
52
|
clean: cleanHelp,
|
|
52
53
|
routes: routesHelp,
|
|
53
54
|
studio: studioHelp,
|
|
55
|
+
styles: stylesHelp,
|
|
54
56
|
lock: lockHelp,
|
|
55
57
|
"analyze-chunks": analyzeChunksHelp,
|
|
56
58
|
generate: generateHelp,
|
package/src/cli/router.ts
CHANGED
|
@@ -29,6 +29,7 @@ import { handleRoutesCommand } from "./commands/routes/handler.js";
|
|
|
29
29
|
import { handleServeCommand } from "./commands/serve/handler.js";
|
|
30
30
|
import { handleStartCommand } from "./commands/start/handler.js";
|
|
31
31
|
import { handleStudioCommand } from "./commands/studio/handler.js";
|
|
32
|
+
import { handleStylesCommand } from "./commands/styles/handler.js";
|
|
32
33
|
import { handleUpCommand } from "./commands/up/index.js";
|
|
33
34
|
import { handleTaskCommand } from "./commands/task/handler.js";
|
|
34
35
|
import { handleWorkflowCommand } from "./commands/workflow/handler.js";
|
|
@@ -55,6 +56,7 @@ const commands: Record<string, (args: ParsedArgs) => Promise<void>> = {
|
|
|
55
56
|
"analyze-chunks": handleAnalyzeChunksCommand,
|
|
56
57
|
"routes": handleRoutesCommand,
|
|
57
58
|
"studio": handleStudioCommand,
|
|
59
|
+
"styles": handleStylesCommand,
|
|
58
60
|
"lock": handleLockCommand,
|
|
59
61
|
"generate": handleGenerateCommand,
|
|
60
62
|
"g": handleGenerateCommand,
|
package/src/deno.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export default {
|
|
2
2
|
"name": "veryfront",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.93",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"nodeModulesDir": "auto",
|
|
6
6
|
"exclude": [
|
|
@@ -97,6 +97,7 @@ export default {
|
|
|
97
97
|
"veryfront/config": "./src/config/index.ts",
|
|
98
98
|
"veryfront/build": "./src/build/index.ts",
|
|
99
99
|
"veryfront/rendering": "./src/rendering/index.ts",
|
|
100
|
+
"veryfront/rendering/styles": "./src/rendering/styles.ts",
|
|
100
101
|
"veryfront/cache": "./src/cache/index.ts",
|
|
101
102
|
"veryfront/security": "./src/security/index.ts",
|
|
102
103
|
"veryfront/errors": "./src/errors/index.ts",
|
|
@@ -39,6 +39,60 @@ interface CSSPregenerationOptions {
|
|
|
39
39
|
buildMode?: "development" | "production";
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
+
export interface PreparedCSSArtifactBuildResult {
|
|
43
|
+
css: string;
|
|
44
|
+
hash: string;
|
|
45
|
+
candidateCount: number;
|
|
46
|
+
fromCache: boolean;
|
|
47
|
+
context: ReturnType<typeof createPreparedProjectCSSContext>;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export async function buildPreparedCSSArtifactFromFiles(
|
|
51
|
+
options: CSSPregenerationOptions,
|
|
52
|
+
): Promise<PreparedCSSArtifactBuildResult> {
|
|
53
|
+
const {
|
|
54
|
+
projectSlug,
|
|
55
|
+
projectVersion,
|
|
56
|
+
projectDir,
|
|
57
|
+
files,
|
|
58
|
+
styleProfile,
|
|
59
|
+
stylesheet,
|
|
60
|
+
stylesheetPath,
|
|
61
|
+
minify = true,
|
|
62
|
+
environment = "preview",
|
|
63
|
+
buildMode = "production",
|
|
64
|
+
} = options;
|
|
65
|
+
|
|
66
|
+
const resolvedStylesheet = stylesheet ?? findStylesheetFromFiles(files, stylesheetPath);
|
|
67
|
+
const candidates = extractCandidatesFromFiles(files, {
|
|
68
|
+
projectDir,
|
|
69
|
+
styleProfile,
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
const result = await getProjectCSS(projectSlug, resolvedStylesheet, candidates, {
|
|
73
|
+
minify,
|
|
74
|
+
environment,
|
|
75
|
+
buildMode,
|
|
76
|
+
});
|
|
77
|
+
const context = createPreparedProjectCSSContext(
|
|
78
|
+
projectSlug,
|
|
79
|
+
projectVersion,
|
|
80
|
+
resolvedStylesheet,
|
|
81
|
+
styleProfile.hash,
|
|
82
|
+
{ minify, environment, buildMode },
|
|
83
|
+
);
|
|
84
|
+
|
|
85
|
+
await storePreparedProjectCSS(context, { css: result.css, hash: result.hash });
|
|
86
|
+
|
|
87
|
+
return {
|
|
88
|
+
css: result.css,
|
|
89
|
+
hash: result.hash,
|
|
90
|
+
candidateCount: candidates.size,
|
|
91
|
+
fromCache: result.fromCache,
|
|
92
|
+
context,
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
|
|
42
96
|
/**
|
|
43
97
|
* Pre-generate and cache CSS from file list.
|
|
44
98
|
*
|
|
@@ -57,54 +111,28 @@ export async function pregenerateCSSFromFiles(
|
|
|
57
111
|
const {
|
|
58
112
|
projectSlug,
|
|
59
113
|
projectVersion,
|
|
60
|
-
projectDir,
|
|
61
114
|
files,
|
|
62
115
|
styleProfile,
|
|
63
116
|
stylesheet,
|
|
64
|
-
stylesheetPath,
|
|
65
|
-
minify = true,
|
|
66
|
-
environment = "preview",
|
|
67
|
-
buildMode = "production",
|
|
68
117
|
} = options;
|
|
69
118
|
const startTime = performance.now();
|
|
70
119
|
|
|
71
120
|
try {
|
|
72
|
-
const resolvedStylesheet = stylesheet ?? findStylesheetFromFiles(files, stylesheetPath);
|
|
73
|
-
const candidates = extractCandidatesFromFiles(files, {
|
|
74
|
-
projectDir,
|
|
75
|
-
styleProfile,
|
|
76
|
-
});
|
|
77
|
-
|
|
78
121
|
logger.debug("Starting", {
|
|
79
122
|
projectSlug,
|
|
80
123
|
projectVersion,
|
|
81
124
|
fileCount: files.length,
|
|
82
|
-
|
|
83
|
-
hasStylesheet: Boolean(resolvedStylesheet),
|
|
125
|
+
hasStylesheet: Boolean(stylesheet),
|
|
84
126
|
styleProfileHash: styleProfile.hash,
|
|
85
127
|
});
|
|
86
128
|
|
|
87
|
-
const result = await
|
|
88
|
-
minify,
|
|
89
|
-
environment,
|
|
90
|
-
buildMode,
|
|
91
|
-
});
|
|
92
|
-
await storePreparedProjectCSS(
|
|
93
|
-
createPreparedProjectCSSContext(
|
|
94
|
-
projectSlug,
|
|
95
|
-
projectVersion,
|
|
96
|
-
resolvedStylesheet,
|
|
97
|
-
styleProfile.hash,
|
|
98
|
-
{ minify, environment, buildMode },
|
|
99
|
-
),
|
|
100
|
-
{ css: result.css, hash: result.hash },
|
|
101
|
-
);
|
|
129
|
+
const result = await buildPreparedCSSArtifactFromFiles(options);
|
|
102
130
|
const duration = performance.now() - startTime;
|
|
103
131
|
|
|
104
132
|
logger.debug("Complete", {
|
|
105
133
|
projectSlug,
|
|
106
134
|
projectVersion,
|
|
107
|
-
candidateCount:
|
|
135
|
+
candidateCount: result.candidateCount,
|
|
108
136
|
cssLength: result.css.length,
|
|
109
137
|
cssHash: result.hash,
|
|
110
138
|
fromCache: result.fromCache,
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { logger as baseLogger } from "../../../utils/index.js";
|
|
2
2
|
import {
|
|
3
|
+
type EnsureStyleArtifactBuildInput,
|
|
3
4
|
type FileDetail,
|
|
4
5
|
type FileListResult,
|
|
5
6
|
type ListFilesOptions,
|
|
@@ -350,6 +351,13 @@ export class VeryfrontApiClient {
|
|
|
350
351
|
return this.operations.resolveStyleArtifact(projectRef, input);
|
|
351
352
|
}
|
|
352
353
|
|
|
354
|
+
ensureStyleArtifactBuild(
|
|
355
|
+
input: EnsureStyleArtifactBuildInput,
|
|
356
|
+
projectRef = this.getProjectSlug()!,
|
|
357
|
+
): Promise<ProjectStyleArtifactResolution> {
|
|
358
|
+
return this.operations.ensureStyleArtifactBuild(projectRef, input);
|
|
359
|
+
}
|
|
360
|
+
|
|
353
361
|
upsertStyleArtifact(
|
|
354
362
|
input: UpsertStyleArtifactInput,
|
|
355
363
|
projectRef = this.getProjectSlug()!,
|
|
@@ -64,19 +64,28 @@ export interface ResolveStyleArtifactInput extends StyleArtifactSelector {
|
|
|
64
64
|
styleProfileHash: string;
|
|
65
65
|
}
|
|
66
66
|
|
|
67
|
+
export interface EnsureStyleArtifactBuildInput extends ResolveStyleArtifactInput {
|
|
68
|
+
force?: boolean;
|
|
69
|
+
}
|
|
70
|
+
|
|
67
71
|
export interface UpsertStyleArtifactInput extends ResolveStyleArtifactInput {
|
|
68
|
-
|
|
72
|
+
status?: "building" | "ready" | "failed";
|
|
73
|
+
artifactHash?: string;
|
|
69
74
|
assetPath?: string;
|
|
70
75
|
contentType?: string;
|
|
71
76
|
etag?: string;
|
|
77
|
+
buildJobId?: string;
|
|
78
|
+
failureReason?: string;
|
|
72
79
|
}
|
|
73
80
|
|
|
74
81
|
export interface ProjectStyleArtifactResolution {
|
|
75
|
-
status: "ready" | "missing";
|
|
82
|
+
status: "ready" | "missing" | "building" | "failed";
|
|
76
83
|
artifactHash?: string;
|
|
77
84
|
assetPath?: string;
|
|
78
85
|
etag?: string;
|
|
79
86
|
contentType?: string;
|
|
87
|
+
buildJobId?: string;
|
|
88
|
+
failureReason?: string;
|
|
80
89
|
updatedAt?: string;
|
|
81
90
|
}
|
|
82
91
|
|
|
@@ -128,6 +137,8 @@ function mapStyleArtifactResolution(raw: unknown): ProjectStyleArtifactResolutio
|
|
|
128
137
|
assetPath: response.asset_path,
|
|
129
138
|
etag: response.etag,
|
|
130
139
|
contentType: response.content_type,
|
|
140
|
+
buildJobId: response.build_job_id,
|
|
141
|
+
failureReason: response.failure_reason,
|
|
131
142
|
updatedAt: response.updated_at,
|
|
132
143
|
};
|
|
133
144
|
}
|
|
@@ -491,6 +502,37 @@ export class VeryfrontAPIOperations {
|
|
|
491
502
|
return mapStyleArtifactResolution(await this.request(url));
|
|
492
503
|
}
|
|
493
504
|
|
|
505
|
+
async ensureStyleArtifactBuild(
|
|
506
|
+
projectRef: string,
|
|
507
|
+
input: EnsureStyleArtifactBuildInput,
|
|
508
|
+
): Promise<ProjectStyleArtifactResolution> {
|
|
509
|
+
const url = `/projects/${encodeURIComponent(projectRef)}/style-artifacts/current/builds`;
|
|
510
|
+
logger.debug("ensureStyleArtifactBuild", {
|
|
511
|
+
projectRef,
|
|
512
|
+
branch: input.branch,
|
|
513
|
+
environmentName: input.environmentName,
|
|
514
|
+
releaseId: input.releaseId,
|
|
515
|
+
styleProfileHash: input.styleProfileHash,
|
|
516
|
+
force: input.force ?? false,
|
|
517
|
+
});
|
|
518
|
+
|
|
519
|
+
return mapStyleArtifactResolution(
|
|
520
|
+
await this.request(url, {
|
|
521
|
+
method: "POST",
|
|
522
|
+
headers: {
|
|
523
|
+
"Content-Type": "application/json",
|
|
524
|
+
},
|
|
525
|
+
body: JSON.stringify({
|
|
526
|
+
style_profile_hash: input.styleProfileHash,
|
|
527
|
+
branch: input.branch,
|
|
528
|
+
environment_name: input.environmentName,
|
|
529
|
+
release_id: input.releaseId,
|
|
530
|
+
force: input.force ?? false,
|
|
531
|
+
}),
|
|
532
|
+
}),
|
|
533
|
+
);
|
|
534
|
+
}
|
|
535
|
+
|
|
494
536
|
async upsertStyleArtifact(
|
|
495
537
|
projectRef: string,
|
|
496
538
|
input: UpsertStyleArtifactInput,
|
|
@@ -502,6 +544,7 @@ export class VeryfrontAPIOperations {
|
|
|
502
544
|
environmentName: input.environmentName,
|
|
503
545
|
releaseId: input.releaseId,
|
|
504
546
|
styleProfileHash: input.styleProfileHash,
|
|
547
|
+
status: input.status ?? "ready",
|
|
505
548
|
artifactHash: input.artifactHash,
|
|
506
549
|
});
|
|
507
550
|
|
|
@@ -516,10 +559,13 @@ export class VeryfrontAPIOperations {
|
|
|
516
559
|
branch: input.branch,
|
|
517
560
|
environment_name: input.environmentName,
|
|
518
561
|
release_id: input.releaseId,
|
|
562
|
+
status: input.status ?? "ready",
|
|
519
563
|
artifact_hash: input.artifactHash,
|
|
520
564
|
asset_path: input.assetPath,
|
|
521
565
|
content_type: input.contentType,
|
|
522
566
|
etag: input.etag,
|
|
567
|
+
build_job_id: input.buildJobId,
|
|
568
|
+
failure_reason: input.failureReason,
|
|
523
569
|
}),
|
|
524
570
|
}),
|
|
525
571
|
);
|