veryfront 0.1.90 → 0.1.92
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/deno.js +1 -1
- package/esm/src/config/environment-config.js +1 -1
- package/esm/src/jobs/schemas.d.ts +44 -44
- package/esm/src/jobs/schemas.js +3 -3
- package/esm/src/observability/metrics/manager.js +2 -2
- package/esm/src/observability/tracing/otlp-setup.js +2 -2
- package/esm/src/platform/adapters/fs/veryfront/adapter.d.ts +1 -0
- package/esm/src/platform/adapters/fs/veryfront/adapter.d.ts.map +1 -1
- package/esm/src/platform/adapters/fs/veryfront/adapter.js +11 -5
- package/esm/src/platform/adapters/veryfront-api-client/client.d.ts +3 -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 +6 -0
- package/esm/src/platform/adapters/veryfront-api-client/index.d.ts +2 -2
- package/esm/src/platform/adapters/veryfront-api-client/index.d.ts.map +1 -1
- package/esm/src/platform/adapters/veryfront-api-client/index.js +1 -1
- package/esm/src/platform/adapters/veryfront-api-client/operations.d.ts +24 -0
- package/esm/src/platform/adapters/veryfront-api-client/operations.d.ts.map +1 -1
- package/esm/src/platform/adapters/veryfront-api-client/operations.js +65 -3
- package/esm/src/platform/adapters/veryfront-api-client/schemas/api.schema.d.ts +28 -0
- 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 +13 -0
- package/esm/src/platform/adapters/veryfront-api-client/schemas/index.d.ts +1 -1
- package/esm/src/platform/adapters/veryfront-api-client/schemas/index.d.ts.map +1 -1
- package/esm/src/platform/adapters/veryfront-api-client/schemas/index.js +1 -1
- package/esm/src/proxy/logger.d.ts.map +1 -1
- package/esm/src/proxy/logger.js +2 -6
- package/esm/src/proxy/tracing.d.ts.map +1 -1
- package/esm/src/proxy/tracing.js +2 -5
- package/esm/src/proxy/version.d.ts +2 -0
- package/esm/src/proxy/version.d.ts.map +1 -0
- package/esm/src/proxy/version.js +18 -0
- package/esm/src/sandbox/index.d.ts +1 -1
- package/esm/src/sandbox/index.d.ts.map +1 -1
- package/esm/src/sandbox/index.js +1 -1
- package/esm/src/sandbox/sandbox.d.ts +58 -0
- package/esm/src/sandbox/sandbox.d.ts.map +1 -1
- package/esm/src/sandbox/sandbox.js +111 -0
- package/esm/src/server/handlers/dev/styles-css.handler.d.ts +5 -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 +121 -1
- package/esm/src/server/handlers/monitoring/health.handler.js +2 -2
- package/esm/src/utils/logger/logger.js +2 -2
- package/esm/src/utils/version.d.ts +9 -1
- package/esm/src/utils/version.d.ts.map +1 -1
- package/esm/src/utils/version.js +29 -2
- package/package.json +1 -1
- package/src/deno.js +1 -1
- package/src/src/config/environment-config.ts +1 -1
- package/src/src/jobs/schemas.ts +3 -3
- package/src/src/observability/metrics/manager.ts +2 -2
- package/src/src/observability/tracing/otlp-setup.ts +2 -2
- package/src/src/platform/adapters/fs/veryfront/adapter.ts +12 -5
- package/src/src/platform/adapters/veryfront-api-client/client.ts +17 -0
- package/src/src/platform/adapters/veryfront-api-client/index.ts +6 -0
- package/src/src/platform/adapters/veryfront-api-client/operations.ts +110 -3
- package/src/src/platform/adapters/veryfront-api-client/schemas/api.schema.ts +16 -0
- package/src/src/platform/adapters/veryfront-api-client/schemas/index.ts +2 -0
- package/src/src/proxy/logger.ts +2 -8
- package/src/src/proxy/tracing.ts +2 -6
- package/src/src/proxy/version.ts +21 -0
- package/src/src/sandbox/index.ts +13 -1
- package/src/src/sandbox/sandbox.ts +183 -0
- package/src/src/server/handlers/dev/styles-css.handler.ts +179 -1
- package/src/src/server/handlers/monitoring/health.handler.ts +2 -2
- package/src/src/utils/logger/logger.ts +2 -2
- package/src/src/utils/version.ts +37 -2
package/src/src/proxy/tracing.ts
CHANGED
|
@@ -6,13 +6,9 @@ import * as dntShim from "../../_dnt.shims.js";
|
|
|
6
6
|
|
|
7
7
|
|
|
8
8
|
import type { Context, Span, Tracer } from "@opentelemetry/api";
|
|
9
|
-
import denoConfig from "../../deno.js";
|
|
10
9
|
import { getEnv } from "./env.js";
|
|
11
10
|
import { proxyLogger } from "./logger.js";
|
|
12
|
-
|
|
13
|
-
// Get version from environment variable or root deno.json
|
|
14
|
-
const VERYFRONT_VERSION: string = getEnv("VERYFRONT_VERSION") ??
|
|
15
|
-
(typeof denoConfig.version === "string" ? denoConfig.version : "0.0.0");
|
|
11
|
+
import { PROXY_RUNTIME_VERSION } from "./version.js";
|
|
16
12
|
|
|
17
13
|
let initialized = false;
|
|
18
14
|
let tracerProvider: { shutdown: () => Promise<void> } | null = null;
|
|
@@ -100,7 +96,7 @@ export async function initializeOTLPWithApis(): Promise<void> {
|
|
|
100
96
|
const resourceAttrs = parseResourceAttributes(getEnv("OTEL_RESOURCE_ATTRIBUTES"));
|
|
101
97
|
const resource = new Resource({
|
|
102
98
|
[ATTR_SERVICE_NAME]: config.serviceName,
|
|
103
|
-
[ATTR_SERVICE_VERSION]:
|
|
99
|
+
[ATTR_SERVICE_VERSION]: PROXY_RUNTIME_VERSION,
|
|
104
100
|
...resourceAttrs,
|
|
105
101
|
});
|
|
106
102
|
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import denoConfig from "../../deno.js";
|
|
2
|
+
import { getEnv } from "./env.js";
|
|
3
|
+
|
|
4
|
+
function normalizeVersion(version: string | undefined): string | undefined {
|
|
5
|
+
if (!version) return undefined;
|
|
6
|
+
return version.replace(/^v(?=\d)/, "");
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
function getVersionEnv(name: string): string | undefined {
|
|
10
|
+
try {
|
|
11
|
+
return getEnv(name);
|
|
12
|
+
} catch {
|
|
13
|
+
return undefined;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export const PROXY_RUNTIME_VERSION = normalizeVersion(
|
|
18
|
+
getVersionEnv("VERYFRONT_VERSION") ?? getVersionEnv("RELEASE_VERSION"),
|
|
19
|
+
) ??
|
|
20
|
+
normalizeVersion(typeof denoConfig.version === "string" ? denoConfig.version : undefined) ??
|
|
21
|
+
"0.0.0";
|
package/src/src/sandbox/index.ts
CHANGED
|
@@ -19,4 +19,16 @@
|
|
|
19
19
|
import "../../_dnt.polyfills.js";
|
|
20
20
|
|
|
21
21
|
|
|
22
|
-
export {
|
|
22
|
+
export {
|
|
23
|
+
type CommandJob,
|
|
24
|
+
type CommandJobHeartbeatStatus,
|
|
25
|
+
type CommandJobOutput,
|
|
26
|
+
type CommandJobStatus,
|
|
27
|
+
type ExecResult,
|
|
28
|
+
type ExecStreamEvent,
|
|
29
|
+
Sandbox,
|
|
30
|
+
type SandboxListOptions,
|
|
31
|
+
type SandboxListResult,
|
|
32
|
+
type SandboxOptions,
|
|
33
|
+
type SandboxSession,
|
|
34
|
+
} from "./sandbox.js";
|
|
@@ -41,6 +41,60 @@ export interface ExecStreamEvent {
|
|
|
41
41
|
exitCode?: number;
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
+
/** Status of an async command job. */
|
|
45
|
+
export type CommandJobStatus = "running" | "completed" | "failed" | "canceled";
|
|
46
|
+
|
|
47
|
+
/** Heartbeat health status for a command job. */
|
|
48
|
+
export type CommandJobHeartbeatStatus = "disabled" | "healthy" | "degraded";
|
|
49
|
+
|
|
50
|
+
/** An async command job running in a sandbox. */
|
|
51
|
+
export interface CommandJob {
|
|
52
|
+
id: string;
|
|
53
|
+
status: CommandJobStatus;
|
|
54
|
+
exitCode: number | null;
|
|
55
|
+
signal: string | null;
|
|
56
|
+
startedAt: string;
|
|
57
|
+
finishedAt: string | null;
|
|
58
|
+
heartbeatStatus: CommandJobHeartbeatStatus;
|
|
59
|
+
lastHeartbeatAt: string | null;
|
|
60
|
+
lastHeartbeatError: string | null;
|
|
61
|
+
heartbeatFailureCount: number;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/** A command job with its captured output. */
|
|
65
|
+
export interface CommandJobOutput extends CommandJob {
|
|
66
|
+
stdout: string;
|
|
67
|
+
stderr: string;
|
|
68
|
+
stdoutTruncated: boolean;
|
|
69
|
+
stderrTruncated: boolean;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/** A sandbox session summary returned by list. */
|
|
73
|
+
export interface SandboxSession {
|
|
74
|
+
id: string;
|
|
75
|
+
shortId: string;
|
|
76
|
+
endpoint: string;
|
|
77
|
+
status: string;
|
|
78
|
+
createdAt: string;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/** Options for listing sandbox sessions. */
|
|
82
|
+
export interface SandboxListOptions extends SandboxOptions {
|
|
83
|
+
cursor?: string;
|
|
84
|
+
limit?: number;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/** Paginated result of sandbox sessions. */
|
|
88
|
+
export interface SandboxListResult {
|
|
89
|
+
data: SandboxSession[];
|
|
90
|
+
pageInfo: {
|
|
91
|
+
self: string | null;
|
|
92
|
+
first: null;
|
|
93
|
+
next: string | null;
|
|
94
|
+
prev: string | null;
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
|
|
44
98
|
/** Client for isolated ephemeral compute environments with command execution and file I/O. */
|
|
45
99
|
export class Sandbox {
|
|
46
100
|
private constructor(
|
|
@@ -117,6 +171,47 @@ export class Sandbox {
|
|
|
117
171
|
return new Sandbox(endpoint, id, authToken, apiUrl);
|
|
118
172
|
}
|
|
119
173
|
|
|
174
|
+
/** List sandbox sessions with optional pagination. */
|
|
175
|
+
static async list(options: SandboxListOptions = {}): Promise<SandboxListResult> {
|
|
176
|
+
const apiUrl = Sandbox.resolveApiUrl(options);
|
|
177
|
+
const authToken = Sandbox.resolveAuthToken(options);
|
|
178
|
+
|
|
179
|
+
const params = new URLSearchParams();
|
|
180
|
+
if (options.cursor) params.set("cursor", options.cursor);
|
|
181
|
+
if (options.limit !== undefined) params.set("limit", String(options.limit));
|
|
182
|
+
|
|
183
|
+
const query = params.toString();
|
|
184
|
+
const url = `${apiUrl}/sandbox-sessions${query ? `?${query}` : ""}`;
|
|
185
|
+
|
|
186
|
+
const res = await dntShim.fetch(url, {
|
|
187
|
+
headers: { Authorization: `Bearer ${authToken}` },
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
if (!res.ok) {
|
|
191
|
+
throw REQUEST_ERROR.create({
|
|
192
|
+
detail: `Failed to list sandboxes: ${res.status} ${await res.text()}`,
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
const json = await res.json();
|
|
197
|
+
|
|
198
|
+
return {
|
|
199
|
+
data: json.data.map((s: Record<string, unknown>) => ({
|
|
200
|
+
id: s.id,
|
|
201
|
+
shortId: s.short_id,
|
|
202
|
+
endpoint: s.endpoint,
|
|
203
|
+
status: s.status,
|
|
204
|
+
createdAt: s.created_at,
|
|
205
|
+
})),
|
|
206
|
+
pageInfo: {
|
|
207
|
+
self: json.page_info?.self ?? null,
|
|
208
|
+
first: null,
|
|
209
|
+
next: json.page_info?.next ?? null,
|
|
210
|
+
prev: json.page_info?.prev ?? null,
|
|
211
|
+
},
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
|
|
120
215
|
private static async waitForReady(
|
|
121
216
|
apiUrl: string,
|
|
122
217
|
id: string,
|
|
@@ -247,6 +342,94 @@ export class Sandbox {
|
|
|
247
342
|
}
|
|
248
343
|
}
|
|
249
344
|
|
|
345
|
+
/** Start an async command job in the sandbox. */
|
|
346
|
+
async startCommandJob(command: string): Promise<CommandJob> {
|
|
347
|
+
const res = await dntShim.fetch(`${this.endpoint}/exec/jobs`, {
|
|
348
|
+
method: "POST",
|
|
349
|
+
headers: {
|
|
350
|
+
Authorization: `Bearer ${this.authToken}`,
|
|
351
|
+
"Content-Type": "application/json",
|
|
352
|
+
},
|
|
353
|
+
body: JSON.stringify({ command }),
|
|
354
|
+
});
|
|
355
|
+
|
|
356
|
+
if (!res.ok) {
|
|
357
|
+
throw REQUEST_ERROR.create({
|
|
358
|
+
detail: `Start command job failed: ${res.status} ${await res.text()}`,
|
|
359
|
+
});
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
return Sandbox.mapCommandJob(await res.json());
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
/** Get the status of an async command job. */
|
|
366
|
+
async getCommandJob(jobId: string): Promise<CommandJob> {
|
|
367
|
+
const res = await dntShim.fetch(`${this.endpoint}/exec/jobs/${jobId}`, {
|
|
368
|
+
headers: { Authorization: `Bearer ${this.authToken}` },
|
|
369
|
+
});
|
|
370
|
+
|
|
371
|
+
if (!res.ok) {
|
|
372
|
+
throw REQUEST_ERROR.create({
|
|
373
|
+
detail: `Get command job failed: ${res.status} ${await res.text()}`,
|
|
374
|
+
});
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
return Sandbox.mapCommandJob(await res.json());
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
/** Get the output of an async command job. */
|
|
381
|
+
async getCommandJobOutput(jobId: string): Promise<CommandJobOutput> {
|
|
382
|
+
const res = await dntShim.fetch(`${this.endpoint}/exec/jobs/${jobId}/output`, {
|
|
383
|
+
headers: { Authorization: `Bearer ${this.authToken}` },
|
|
384
|
+
});
|
|
385
|
+
|
|
386
|
+
if (!res.ok) {
|
|
387
|
+
throw REQUEST_ERROR.create({
|
|
388
|
+
detail: `Get command job output failed: ${res.status} ${await res.text()}`,
|
|
389
|
+
});
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
const json = await res.json();
|
|
393
|
+
return {
|
|
394
|
+
...Sandbox.mapCommandJob(json),
|
|
395
|
+
stdout: json.stdout,
|
|
396
|
+
stderr: json.stderr,
|
|
397
|
+
stdoutTruncated: json.stdout_truncated,
|
|
398
|
+
stderrTruncated: json.stderr_truncated,
|
|
399
|
+
};
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
/** Cancel an async command job. */
|
|
403
|
+
async cancelCommandJob(jobId: string): Promise<CommandJob> {
|
|
404
|
+
const res = await dntShim.fetch(`${this.endpoint}/exec/jobs/${jobId}/cancel`, {
|
|
405
|
+
method: "POST",
|
|
406
|
+
headers: { Authorization: `Bearer ${this.authToken}` },
|
|
407
|
+
});
|
|
408
|
+
|
|
409
|
+
if (!res.ok) {
|
|
410
|
+
throw REQUEST_ERROR.create({
|
|
411
|
+
detail: `Cancel command job failed: ${res.status} ${await res.text()}`,
|
|
412
|
+
});
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
return Sandbox.mapCommandJob(await res.json());
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
private static mapCommandJob(json: Record<string, unknown>): CommandJob {
|
|
419
|
+
return {
|
|
420
|
+
id: json.id as string,
|
|
421
|
+
status: json.status as CommandJobStatus,
|
|
422
|
+
exitCode: json.exit_code as number | null,
|
|
423
|
+
signal: json.signal as string | null,
|
|
424
|
+
startedAt: json.started_at as string,
|
|
425
|
+
finishedAt: json.finished_at as string | null,
|
|
426
|
+
heartbeatStatus: json.heartbeat_status as CommandJobHeartbeatStatus,
|
|
427
|
+
lastHeartbeatAt: json.last_heartbeat_at as string | null,
|
|
428
|
+
lastHeartbeatError: json.last_heartbeat_error as string | null,
|
|
429
|
+
heartbeatFailureCount: json.heartbeat_failure_count as number,
|
|
430
|
+
};
|
|
431
|
+
}
|
|
432
|
+
|
|
250
433
|
/** Send a heartbeat to prevent idle timeout. */
|
|
251
434
|
async heartbeat(): Promise<void> {
|
|
252
435
|
await dntShim.fetch(`${this.apiUrl}/sandbox-sessions/${this.sessionId}/heartbeat`, {
|
|
@@ -11,22 +11,33 @@ import { BaseHandler } from "../response/base.js";
|
|
|
11
11
|
import type { HandlerContext, HandlerMetadata, HandlerPriority, HandlerResult } from "../types.js";
|
|
12
12
|
import { HTTP_OK, PRIORITY_HIGH_DEV } from "../../../utils/constants/index.js";
|
|
13
13
|
import { joinPath } from "../../../utils/path-utils.js";
|
|
14
|
-
import {
|
|
14
|
+
import {
|
|
15
|
+
formatCSSError,
|
|
16
|
+
getCSSByHashAsync,
|
|
17
|
+
getProjectCSS,
|
|
18
|
+
regenerateCSSByHash,
|
|
19
|
+
} from "../../../html/styles-builder/tailwind-compiler.js";
|
|
15
20
|
import { DEFAULT_STYLESHEET } from "../../../html/styles-builder/css-hash-cache.js";
|
|
16
21
|
import { resolveStyleContentVersion } from "../../../html/styles-builder/content-version.js";
|
|
17
22
|
import {
|
|
18
23
|
createPreparedProjectCSSContext,
|
|
24
|
+
type PreparedProjectCSSRequestContext,
|
|
19
25
|
storePreparedProjectCSS,
|
|
20
26
|
tryGetPreparedProjectCSS,
|
|
21
27
|
} from "../../../html/styles-builder/prepared-project-css-cache.js";
|
|
22
28
|
import { createStyleScopeProfile } from "../../../html/styles-builder/style-scope-profile.js";
|
|
23
29
|
import { serverLogger } from "../../../utils/index.js";
|
|
24
30
|
import type { ResolvedContentContext } from "../../../platform/adapters/fs/veryfront/types.js";
|
|
31
|
+
import type {
|
|
32
|
+
ResolveStyleArtifactInput,
|
|
33
|
+
VeryfrontApiClient,
|
|
34
|
+
} from "../../../platform/adapters/veryfront-api-client/index.js";
|
|
25
35
|
import { extractProjectCandidates } from "./styles-candidate-scanner.js";
|
|
26
36
|
|
|
27
37
|
const logger = serverLogger.component("styles-css-handler");
|
|
28
38
|
|
|
29
39
|
type GeneratedStylesResult = Awaited<ReturnType<typeof getProjectCSS>>;
|
|
40
|
+
type StyleArtifactSelectorContext = Omit<ResolveStyleArtifactInput, "styleProfileHash">;
|
|
30
41
|
|
|
31
42
|
export class StylesCSSHandler extends BaseHandler {
|
|
32
43
|
metadata: HandlerMetadata = {
|
|
@@ -78,6 +89,25 @@ export class StylesCSSHandler extends BaseHandler {
|
|
|
78
89
|
}
|
|
79
90
|
}
|
|
80
91
|
|
|
92
|
+
const remotePrepared = await this.tryResolveRemotePreparedCSS(
|
|
93
|
+
ctx,
|
|
94
|
+
projectScope,
|
|
95
|
+
styleProfile.hash,
|
|
96
|
+
contentContext,
|
|
97
|
+
preparedContext,
|
|
98
|
+
);
|
|
99
|
+
if (remotePrepared) {
|
|
100
|
+
logger.debug("Prepared CSS resolved via style artifact metadata", {
|
|
101
|
+
projectScope,
|
|
102
|
+
styleProfileHash: styleProfile.hash,
|
|
103
|
+
cssHash: remotePrepared.hash,
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
return this.respond(
|
|
107
|
+
responseBuilder.withContentType("text/css; charset=utf-8", remotePrepared.css, HTTP_OK),
|
|
108
|
+
);
|
|
109
|
+
}
|
|
110
|
+
|
|
81
111
|
let candidates: Set<string>;
|
|
82
112
|
try {
|
|
83
113
|
candidates = await extractProjectCandidates(ctx);
|
|
@@ -148,6 +178,15 @@ body::before {
|
|
|
148
178
|
});
|
|
149
179
|
}
|
|
150
180
|
|
|
181
|
+
if ("hash" in result) {
|
|
182
|
+
await this.registerPreparedCSSArtifact(
|
|
183
|
+
ctx,
|
|
184
|
+
styleProfile.hash,
|
|
185
|
+
contentContext,
|
|
186
|
+
result.hash,
|
|
187
|
+
);
|
|
188
|
+
}
|
|
189
|
+
|
|
151
190
|
return this.respond(
|
|
152
191
|
responseBuilder.withContentType("text/css; charset=utf-8", result.css, HTTP_OK),
|
|
153
192
|
);
|
|
@@ -212,6 +251,17 @@ body::before {
|
|
|
212
251
|
return typeof fsAdapter.getContentContext === "function" ? fsAdapter.getContentContext() : null;
|
|
213
252
|
}
|
|
214
253
|
|
|
254
|
+
private getVeryfrontApiClient(ctx: HandlerContext): VeryfrontApiClient | null {
|
|
255
|
+
const wrappedFs = ctx.adapter.fs as { getUnderlyingAdapter?: () => unknown };
|
|
256
|
+
if (typeof wrappedFs.getUnderlyingAdapter !== "function") return null;
|
|
257
|
+
|
|
258
|
+
const fsAdapter = wrappedFs.getUnderlyingAdapter() as {
|
|
259
|
+
getClient?: () => VeryfrontApiClient;
|
|
260
|
+
};
|
|
261
|
+
|
|
262
|
+
return typeof fsAdapter.getClient === "function" ? fsAdapter.getClient() : null;
|
|
263
|
+
}
|
|
264
|
+
|
|
215
265
|
private createPreparedCSSContext(
|
|
216
266
|
projectScope: string | undefined,
|
|
217
267
|
rawCss: string,
|
|
@@ -237,4 +287,132 @@ body::before {
|
|
|
237
287
|
},
|
|
238
288
|
);
|
|
239
289
|
}
|
|
290
|
+
|
|
291
|
+
private resolveStyleArtifactSelector(
|
|
292
|
+
contentContext: ResolvedContentContext | null,
|
|
293
|
+
ctx: HandlerContext,
|
|
294
|
+
): StyleArtifactSelectorContext | null {
|
|
295
|
+
if (contentContext?.sourceType === "branch" && contentContext.branch) {
|
|
296
|
+
return {
|
|
297
|
+
branch: contentContext.branch,
|
|
298
|
+
};
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
if (contentContext?.sourceType === "environment" && contentContext.environmentName) {
|
|
302
|
+
return {
|
|
303
|
+
environmentName: contentContext.environmentName,
|
|
304
|
+
};
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
if (contentContext?.sourceType === "release" && contentContext.releaseId) {
|
|
308
|
+
return {
|
|
309
|
+
releaseId: contentContext.releaseId,
|
|
310
|
+
};
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
if (ctx.parsedDomain?.branch) {
|
|
314
|
+
return {
|
|
315
|
+
branch: ctx.parsedDomain.branch,
|
|
316
|
+
};
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
if (ctx.environmentName) {
|
|
320
|
+
return {
|
|
321
|
+
environmentName: ctx.environmentName,
|
|
322
|
+
};
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
if (ctx.releaseId) {
|
|
326
|
+
return {
|
|
327
|
+
releaseId: ctx.releaseId,
|
|
328
|
+
};
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
return null;
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
private async tryResolveRemotePreparedCSS(
|
|
335
|
+
ctx: HandlerContext,
|
|
336
|
+
projectScope: string | undefined,
|
|
337
|
+
styleProfileHash: string,
|
|
338
|
+
contentContext: ResolvedContentContext | null,
|
|
339
|
+
preparedContext?: PreparedProjectCSSRequestContext,
|
|
340
|
+
): Promise<{ css: string; hash: string } | undefined> {
|
|
341
|
+
if (!projectScope) return undefined;
|
|
342
|
+
|
|
343
|
+
const selector = this.resolveStyleArtifactSelector(contentContext, ctx);
|
|
344
|
+
if (!selector) return undefined;
|
|
345
|
+
|
|
346
|
+
const client = this.getVeryfrontApiClient(ctx);
|
|
347
|
+
if (!client) return undefined;
|
|
348
|
+
|
|
349
|
+
try {
|
|
350
|
+
const resolved = await client.resolveStyleArtifact({
|
|
351
|
+
...selector,
|
|
352
|
+
styleProfileHash,
|
|
353
|
+
});
|
|
354
|
+
|
|
355
|
+
if (resolved.status !== "ready" || !resolved.artifactHash) {
|
|
356
|
+
return undefined;
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
const css = await this.getPreparedCSSByHash(resolved.artifactHash, projectScope);
|
|
360
|
+
if (!css) return undefined;
|
|
361
|
+
|
|
362
|
+
if (preparedContext) {
|
|
363
|
+
await storePreparedProjectCSS(preparedContext, {
|
|
364
|
+
css,
|
|
365
|
+
hash: resolved.artifactHash,
|
|
366
|
+
});
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
return {
|
|
370
|
+
css,
|
|
371
|
+
hash: resolved.artifactHash,
|
|
372
|
+
};
|
|
373
|
+
} catch (error) {
|
|
374
|
+
logger.debug("Failed to resolve prepared CSS via style artifact metadata", {
|
|
375
|
+
projectScope,
|
|
376
|
+
styleProfileHash,
|
|
377
|
+
error: error instanceof Error ? error.message : String(error),
|
|
378
|
+
});
|
|
379
|
+
return undefined;
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
private async getPreparedCSSByHash(
|
|
384
|
+
cssHash: string,
|
|
385
|
+
projectScope: string,
|
|
386
|
+
): Promise<string | undefined> {
|
|
387
|
+
const cached = await getCSSByHashAsync(cssHash);
|
|
388
|
+
if (cached) return cached;
|
|
389
|
+
return regenerateCSSByHash(cssHash, projectScope);
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
private async registerPreparedCSSArtifact(
|
|
393
|
+
ctx: HandlerContext,
|
|
394
|
+
styleProfileHash: string,
|
|
395
|
+
contentContext: ResolvedContentContext | null,
|
|
396
|
+
cssHash: string,
|
|
397
|
+
): Promise<void> {
|
|
398
|
+
const selector = this.resolveStyleArtifactSelector(contentContext, ctx);
|
|
399
|
+
if (!selector) return;
|
|
400
|
+
|
|
401
|
+
const client = this.getVeryfrontApiClient(ctx);
|
|
402
|
+
if (!client) return;
|
|
403
|
+
|
|
404
|
+
try {
|
|
405
|
+
await client.upsertStyleArtifact({
|
|
406
|
+
...selector,
|
|
407
|
+
styleProfileHash,
|
|
408
|
+
artifactHash: cssHash,
|
|
409
|
+
});
|
|
410
|
+
} catch (error) {
|
|
411
|
+
logger.debug("Failed to register prepared CSS artifact", {
|
|
412
|
+
cssHash,
|
|
413
|
+
styleProfileHash,
|
|
414
|
+
error: error instanceof Error ? error.message : String(error),
|
|
415
|
+
});
|
|
416
|
+
}
|
|
417
|
+
}
|
|
240
418
|
}
|
|
@@ -4,7 +4,7 @@ import type { HandlerContext, HandlerMetadata, HandlerPriority, HandlerResult }
|
|
|
4
4
|
import { joinPath } from "../../../utils/path-utils.js";
|
|
5
5
|
import { HTTP_OK, HTTP_UNAVAILABLE, PRIORITY_HIGH } from "../../../utils/constants/index.js";
|
|
6
6
|
import { isTracingDegraded, isTracingEnabled } from "../../../observability/tracing/index.js";
|
|
7
|
-
import {
|
|
7
|
+
import { RUNTIME_VERSION } from "../../../utils/version.js";
|
|
8
8
|
|
|
9
9
|
let serverInitialized = false;
|
|
10
10
|
|
|
@@ -74,7 +74,7 @@ export class HealthHandler extends BaseHandler {
|
|
|
74
74
|
status: tracingDegraded ? "degraded" : "ok",
|
|
75
75
|
timestamp: new Date().toISOString(),
|
|
76
76
|
mode: hasStaticBuild ? "static+ssr" : "ssr",
|
|
77
|
-
version:
|
|
77
|
+
version: RUNTIME_VERSION,
|
|
78
78
|
tracing: {
|
|
79
79
|
enabled: isTracingEnabled(),
|
|
80
80
|
degraded: tracingDegraded,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as dntShim from "../../../_dnt.shims.js";
|
|
2
2
|
import { getEnv } from "../../platform/compat/process.js";
|
|
3
3
|
import { hasDenoRuntime, hasNodeProcess } from "../runtime-guards.js";
|
|
4
|
-
import {
|
|
4
|
+
import { RUNTIME_VERSION } from "../version.js";
|
|
5
5
|
import {
|
|
6
6
|
ANSI,
|
|
7
7
|
colorize,
|
|
@@ -287,7 +287,7 @@ class ConsoleLogger implements Logger {
|
|
|
287
287
|
timestamp: new Date().toISOString(),
|
|
288
288
|
level,
|
|
289
289
|
service: this.prefix.toLowerCase(),
|
|
290
|
-
veryfrontVersion:
|
|
290
|
+
veryfrontVersion: RUNTIME_VERSION,
|
|
291
291
|
message,
|
|
292
292
|
};
|
|
293
293
|
|
package/src/src/utils/version.ts
CHANGED
|
@@ -1,6 +1,41 @@
|
|
|
1
|
+
import denoConfig from "../../deno.js";
|
|
2
|
+
import { getEnv } from "../platform/compat/process.js";
|
|
3
|
+
|
|
1
4
|
// Keep in sync with deno.json version.
|
|
2
5
|
// scripts/release.ts updates this constant during releases.
|
|
3
|
-
export const VERSION = "0.1.
|
|
6
|
+
export const VERSION = "0.1.92";
|
|
7
|
+
|
|
8
|
+
export function normalizeVeryfrontVersion(version: string | undefined): string | undefined {
|
|
9
|
+
if (!version) return undefined;
|
|
10
|
+
return version.replace(/^v(?=\d)/, "");
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function getVersionEnv(name: string): string | undefined {
|
|
14
|
+
try {
|
|
15
|
+
return getEnv(name);
|
|
16
|
+
} catch {
|
|
17
|
+
return undefined;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function resolveRuntimeVersion(options: {
|
|
22
|
+
veryfrontVersion?: string;
|
|
23
|
+
releaseVersion?: string;
|
|
24
|
+
denoVersion?: string;
|
|
25
|
+
fallbackVersion?: string;
|
|
26
|
+
} = {}): string {
|
|
27
|
+
return normalizeVeryfrontVersion(options.veryfrontVersion ?? options.releaseVersion) ??
|
|
28
|
+
normalizeVeryfrontVersion(options.denoVersion) ??
|
|
29
|
+
options.fallbackVersion ??
|
|
30
|
+
VERSION;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export const RUNTIME_VERSION = resolveRuntimeVersion({
|
|
34
|
+
veryfrontVersion: getVersionEnv("VERYFRONT_VERSION"),
|
|
35
|
+
releaseVersion: getVersionEnv("RELEASE_VERSION"),
|
|
36
|
+
denoVersion: typeof denoConfig.version === "string" ? denoConfig.version : undefined,
|
|
37
|
+
fallbackVersion: VERSION,
|
|
38
|
+
});
|
|
4
39
|
|
|
5
40
|
export const SERVER_START_TIME: number = Date.now();
|
|
6
41
|
|
|
@@ -12,7 +47,7 @@ export interface BuildVersion {
|
|
|
12
47
|
|
|
13
48
|
export function createBuildVersion(projectUpdatedAt?: string): BuildVersion {
|
|
14
49
|
return {
|
|
15
|
-
framework:
|
|
50
|
+
framework: RUNTIME_VERSION,
|
|
16
51
|
serverStart: SERVER_START_TIME,
|
|
17
52
|
projectUpdated: projectUpdatedAt,
|
|
18
53
|
};
|