Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 2 additions & 7 deletions src/agent/input/human-input.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { defineSchema } from "#veryfront/schemas/index.ts";
import { AGENT_ERROR, AGENT_TIMEOUT } from "#veryfront/errors";
import { sleep } from "#veryfront/utils";
import type {
InferInput,
InferSchema,
Expand Down Expand Up @@ -314,7 +315,7 @@ export async function waitForDurableHumanInputResolution<TSnapshot>(
return result;
}

await delay(options.pollIntervalMs);
await sleep(options.pollIntervalMs);
}

throw AGENT_TIMEOUT.create({
Expand Down Expand Up @@ -371,9 +372,3 @@ function submitHumanInputResumeValue(
// or the ephemeral session has been finalized.
}
}

function delay(ms: number): Promise<void> {
return new Promise((resolve) => {
setTimeout(resolve, ms);
});
}
7 changes: 1 addition & 6 deletions src/agent/service/detached-run-tracker.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { RunResumeSessionManager } from "../runtime/resume-session.ts";
import { AGENT_TIMEOUT } from "#veryfront/errors";
import { sleep } from "#veryfront/utils";

/** Result returned from detached run drain. */
export interface DetachedRunDrainResult {
Expand Down Expand Up @@ -51,12 +52,6 @@ const DEFAULT_DETACHED_RUN_DRAIN_TIMEOUT_MS = 15_000;
const DETACHED_RUN_DRAIN_TIMEOUT_MESSAGE =
"Detached durable runs did not drain before shutdown timeout";

function sleep(ms: number): Promise<void> {
return new Promise((resolve) => {
setTimeout(resolve, ms);
});
}

/** Create detached run tracker. */
export function createDetachedRunTracker<TResumeValue = unknown>(
options: DetachedRunTrackerOptions<TResumeValue> = {},
Expand Down
7 changes: 2 additions & 5 deletions src/agent/service/registration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import type { Schema, SchemaValidator } from "#veryfront/extensions/schema/index
import { defineSchema } from "../../schemas/define.ts";
import { lazySchema } from "../../schemas/lazy.ts";
import { CONFIG_INVALID, NETWORK_ERROR } from "#veryfront/errors";
import { computeHash } from "#veryfront/utils";

/** Public API contract for agent service registration mode. */
export type AgentServiceRegistrationMode = "auto" | "enabled" | "disabled";
Expand Down Expand Up @@ -242,11 +243,7 @@ async function stableServiceKey(input: {
input.baseUrl,
input.podIdentity ?? "no-pod-identity",
].join("|");
const digest = await crypto.subtle.digest("SHA-256", new TextEncoder().encode(keySource));
const hash = Array.from(new Uint8Array(digest))
.map((byte) => byte.toString(16).padStart(2, "0"))
.join("")
.slice(0, 32);
const hash = (await computeHash(keySource)).slice(0, 32);
return `${input.serviceName}:${hash}`.slice(0, 128);
}

Expand Down
6 changes: 2 additions & 4 deletions src/build/bundler/code-splitter/manifest-builder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { join, relative } from "#veryfront/compat/path/index.ts";
import { createFileSystem } from "#veryfront/platform/compat/fs.ts";
import type { ChunkInfo, ChunkManifest, MetafileOutput } from "./types.ts";
import { createError, toError } from "#veryfront/errors";
import { computeHashBytes } from "#veryfront/utils";

const fs = createFileSystem();

Expand Down Expand Up @@ -43,10 +44,7 @@ export function extractChunkName(file: string): string {

/** Calculates SHA-256 hash of file content (returns first 8 hex chars) */
export async function calculateFileHash(content: Uint8Array): Promise<string> {
const hashBuffer = await crypto.subtle.digest("SHA-256", content.slice());
return Array.from(new Uint8Array(hashBuffer), (b) => b.toString(16).padStart(2, "0"))
.join("")
.slice(0, 8);
return (await computeHashBytes(content.slice())).slice(0, 8);
}

/** Determines which imports are critical and should be preloaded */
Expand Down
4 changes: 2 additions & 2 deletions src/build/production-build/local-release-assets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import {
type ReleaseAssetTransform,
} from "#veryfront/release-assets/build-executor.ts";
import type { ReleaseAssetManifest } from "#veryfront/release-assets/manifest-schema.ts";
import { sha256HexBytes } from "#veryfront/release-assets/hash.ts";
import { computeHashBytes } from "#veryfront/utils";
import { resolveProjectReactVersion } from "#veryfront/transforms/esm/package-registry.ts";
import { VERSION } from "#veryfront/utils/version.ts";
import type { VeryfrontConfig } from "#veryfront/config";
Expand Down Expand Up @@ -90,7 +90,7 @@ export async function generateLocalReleaseAssetManifest(
assetsByHash.set(asset.contentHash, asset);
}
const gaps = [...cached.gaps, ...built.gaps, ...framework.gaps];
const sourceContentHash = await sha256HexBytes(
const sourceContentHash = await computeHashBytes(
new TextEncoder().encode(
[
options.projectDir,
Expand Down
8 changes: 2 additions & 6 deletions src/build/vendor-cache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
* Provides per-project vendor bundle management with automatic invalidation.
**************************************************/

import { computeHash } from "#veryfront/utils";
import { createCacheNamespace } from "#veryfront/utils/cache-namespace.ts";

function buildVendorCacheConfig(
Expand Down Expand Up @@ -38,12 +39,7 @@ export async function generateVendorCacheKey(
...buildVendorCacheConfig(reactVersion, dependencies),
});

const data = new TextEncoder().encode(configStr);
const hashBuffer = await crypto.subtle.digest("SHA-256", data);
const hash = Array.from(new Uint8Array(hashBuffer))
.map((b) => b.toString(16).padStart(2, "0"))
.join("")
.slice(0, 16);
const hash = (await computeHash(configStr)).slice(0, 16);

return `vendor:${projectId}:${hash}`;
}
20 changes: 4 additions & 16 deletions src/discovery/transpiler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { ensureDefaultBundlerContracts } from "#veryfront/extensions/bundler/def
import { isDeno, isDenoCompiled } from "#veryfront/platform/compat/runtime.ts";
import { createFileSystem } from "#veryfront/platform/compat/fs.ts";
import * as pathHelper from "#veryfront/compat/path";
import { computeHash } from "#veryfront/utils";
import { getEsbuildLoader } from "#veryfront/utils/path-utils.ts";
import type { FileSystemAdapter } from "#veryfront/platform/adapters/base.ts";
import type { FileDiscoveryContext } from "./types.ts";
Expand All @@ -29,19 +30,6 @@ type TranspileCacheEntry = {
// still match (see findCachedModuleWithFreshDeps).
const transpileCache = new Map<string, TranspileCacheEntry[]>();

const textEncoder = new TextEncoder();

async function hashSource(source: string): Promise<string> {
const digest = await crypto.subtle.digest(
"SHA-256",
textEncoder.encode(source),
);
return Array.from(
new Uint8Array(digest),
(byte) => byte.toString(16).padStart(2, "0"),
).join("");
}

/**
* Returns the first cached module whose recorded bundled-dependency contents
* still match what the current adapter serves. esbuild inlines relative
Expand All @@ -63,7 +51,7 @@ async function findCachedModuleWithFreshDeps(
const content = context.fsAdapter
? await context.fsAdapter.readFile(dep.path)
: await createFileSystem().readTextFile(dep.path);
hash = await hashSource(content);
hash = await computeHash(content);
} catch {
hash = undefined;
}
Expand Down Expand Up @@ -214,7 +202,7 @@ export async function importModule(
// another project's discovery. The entry hash alone is still not enough —
// bundled relative imports are inlined into the module — so cached entries
// are only served after their recorded dependency contents re-verify.
const cacheKey = `${file} ${await hashSource(source)}`;
const cacheKey = `${file} ${await computeHash(source)}`;
const cachedEntries = transpileCache.get(cacheKey);
if (cachedEntries) {
const cached = await findCachedModuleWithFreshDeps(cachedEntries, context);
Expand Down Expand Up @@ -308,7 +296,7 @@ export async function importModule(
moduleUrl.searchParams.set("v", String(Date.now()));
const module = await import(moduleUrl.href);
const deps = await Promise.all(
bundledDeps.map(async ({ path, content }) => ({ path, hash: await hashSource(content) })),
bundledDeps.map(async ({ path, content }) => ({ path, hash: await computeHash(content) })),
);
const entries = transpileCache.get(cacheKey) ?? [];
entries.push({ deps, module });
Expand Down
7 changes: 1 addition & 6 deletions src/eval/agent-service/durable-run-canaries/runner.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { defineSchema } from "#veryfront/schemas/index.ts";
import { API_CLIENT_ERROR, TIMEOUT_ERROR } from "#veryfront/errors";
import { sleep } from "#veryfront/utils";
import { ensureBuiltinSchemaValidator } from "#veryfront/extensions/builtin-extensions.ts";
import type { InferSchema } from "#veryfront/extensions/schema/index.ts";

Expand Down Expand Up @@ -462,12 +463,6 @@ function collectReferencedChildConversationIds(messages: DurableRunCanaryMessage
return [...childConversationIds];
}

function sleep(ms: number): Promise<void> {
return new Promise((resolve) => {
setTimeout(resolve, ms);
});
}

function isTerminalRunStatus(status: string): boolean {
return status === "completed" || status === "failed" || status === "cancelled";
}
Expand Down
7 changes: 3 additions & 4 deletions src/eval/agent-service/live-evals/api-client.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { ensureBuiltinSchemaValidator } from "#veryfront/extensions/builtin-extensions.ts";
import { API_CLIENT_ERROR, INVALID_ARGUMENT, TIMEOUT_ERROR } from "#veryfront/errors";
import { sleep } from "#veryfront/utils";
import type { InferSchema } from "#veryfront/extensions/schema/index.ts";
import { defineSchema } from "#veryfront/schemas/index.ts";
import type { LiveEvalProjectFile } from "./runner.ts";
Expand Down Expand Up @@ -218,10 +219,8 @@ function getResponseText(response: Response): Promise<string> {
return response.text();
}

async function wait(input: { ms: number }): Promise<void> {
await new Promise((resolve) => {
setTimeout(resolve, input.ms);
});
function wait(input: { ms: number }): Promise<void> {
return sleep(input.ms);
}

async function waitForProjectUploadFixture(
Expand Down
18 changes: 3 additions & 15 deletions src/eval/provenance.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { join } from "@std/path";
import { computeHash, computeHashBytes } from "#veryfront/utils";
import { VERSION } from "#veryfront/utils/version-constant.ts";
import type { EvalRunProvenance } from "./types.ts";

Expand Down Expand Up @@ -185,19 +186,6 @@ async function runGit(
}
}

async function sha256Hex(value: string): Promise<string> {
return sha256Bytes(new TextEncoder().encode(value));
}

async function sha256Bytes(value: Uint8Array): Promise<string> {
const bytes = new Uint8Array(value.byteLength);
bytes.set(value);
const hash = await crypto.subtle.digest("SHA-256", bytes.buffer);
return Array.from(new Uint8Array(hash))
.map((byte) => byte.toString(16).padStart(2, "0"))
.join("");
}

function parseNullSeparated(value: string | undefined): string[] {
if (!value) return [];
return value.split("\0").filter(Boolean).sort();
Expand All @@ -212,7 +200,7 @@ async function hashUntrackedFiles(
for (const relativePath of paths) {
try {
const content = await readFile(join(projectDir, relativePath));
entries.push(`${relativePath}\0${await sha256Bytes(content)}`);
entries.push(`${relativePath}\0${await computeHashBytes(new Uint8Array(content))}`);
} catch {
entries.push(`${relativePath}\0unreadable`);
}
Expand Down Expand Up @@ -250,7 +238,7 @@ async function resolveGitProvenance(
...(branch ? { branch } : {}),
...(dirty !== undefined ? { dirty } : {}),
...(dirty
? { dirtyHash: await sha256Hex(`${status ?? ""}\n${diff ?? ""}\n${untrackedHashInput}`) }
? { dirtyHash: await computeHash(`${status ?? ""}\n${diff ?? ""}\n${untrackedHashInput}`) }
: {}),
};
}
Expand Down
10 changes: 2 additions & 8 deletions src/eval/report.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import type {
EvalReportSummary,
EvalUsageSummary,
} from "./types.ts";
import { computeHash } from "#veryfront/utils";

/** Additive eval report contract version written by new reports and summary artifacts. */
export const EVAL_REPORT_SCHEMA_VERSION = 2;
Expand Down Expand Up @@ -54,13 +55,6 @@ function stableStringify(value: unknown): string {
return JSON.stringify(sortJsonValue(value));
}

async function sha256Hex(value: string): Promise<string> {
const digest = await crypto.subtle.digest("SHA-256", new TextEncoder().encode(value));
return Array.from(new Uint8Array(digest))
.map((byte) => byte.toString(16).padStart(2, "0"))
.join("");
}

function createDatasetHashInput(dataset: EvalDataset, examples: EvalExample[]) {
return {
kind: dataset.kind,
Expand All @@ -83,7 +77,7 @@ export async function createEvalDatasetMetadata(
kind: dataset.kind,
...(dataset.path ? { path: dataset.path } : {}),
examples: examples.length,
hash: `sha256:${await sha256Hex(stableStringify(hashInput))}`,
hash: `sha256:${await computeHash(stableStringify(hashInput))}`,
};
}

Expand Down
21 changes: 2 additions & 19 deletions src/html/styles-builder/plugin-loader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
* @module html/styles-builder/plugin-loader
*/

import { serverLogger } from "#veryfront/utils";
import { encodeBase64, serverLogger } from "#veryfront/utils";
import {
type ErrorSlug,
getErrorBySlug,
Expand Down Expand Up @@ -73,23 +73,6 @@ try {
// by the `@veryfront/ext-css-tailwind` extension's `setup()` hook — they depend on
// tailwindcss imports that live in the extension package, not in core.

function encodeToBase64(source: string): string {
const bufferCtor = (globalThis as {
Buffer?: {
from: (input: string, encoding: string) => { toString: (encoding: string) => string };
};
}).Buffer;

if (bufferCtor?.from) {
return bufferCtor.from(source, "utf8").toString("base64");
}

const bytes = new TextEncoder().encode(source);
let binary = "";
for (const byte of bytes) binary += String.fromCharCode(byte);
return btoa(binary);
}

/**
* esm.sh bundles can contain root-relative nested imports. Once the bundle is
* written to a temp file, Deno resolves those as local file paths unless they
Expand All @@ -116,7 +99,7 @@ export function rewriteEsmShRootRelativeImports(code: string): string {

async function importBundledModule(code: string): Promise<unknown> {
if (!isDeno) {
const dataUrl = `data:text/javascript;base64,${encodeToBase64(code)}`;
const dataUrl = `data:text/javascript;base64,${encodeBase64(code)}`;
Comment thread
kojiwakayama marked this conversation as resolved.
return await import(dataUrl);
}

Expand Down
6 changes: 2 additions & 4 deletions src/knowledge/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

import { ragStore } from "#veryfront/embedding/index.ts";
import { INPUT_VALIDATION_FAILED } from "#veryfront/errors";
import { base64urlEncodeBytes } from "#veryfront/utils";
import type {
RagSearchOptions,
RagSearchResult,
Expand Down Expand Up @@ -469,10 +470,7 @@ function createLookupItem(
}

function encodeCursor(state: ProjectKnowledgeLookupCursorState): string {
const bytes = new TextEncoder().encode(JSON.stringify(state));
let binary = "";
for (const byte of bytes) binary += String.fromCharCode(byte);
return btoa(binary).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
return base64urlEncodeBytes(new TextEncoder().encode(JSON.stringify(state)));
}

function decodeCursor(cursor: string): ProjectKnowledgeLookupCursorState {
Expand Down
3 changes: 2 additions & 1 deletion src/metrics/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import {
} from "#veryfront/observability";
import { getCurrentRequestContext } from "#veryfront/platform/adapters/fs/veryfront/request-context.ts";
import { getEnv, getHostEnv } from "#veryfront/platform/compat/process.ts";
import { encodeBase64 } from "#veryfront/utils";
import { isProjectEnvActive } from "#veryfront/server/project-env/storage.ts";

export type MetricAttributeValue = string | number | boolean | null | undefined;
Expand Down Expand Up @@ -196,7 +197,7 @@ function resolveInternalMetricsUrl(): string | null {

function buildBasicAuth(username: string, password: string): string {
const credentials = `${username}:${password}`;
return `Basic ${globalThis.btoa(credentials)}`;
return `Basic ${encodeBase64(credentials)}`;
}

function parseHeaders(headerInput: string | undefined): Record<string, string> {
Expand Down
8 changes: 2 additions & 6 deletions src/oauth/providers/base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import type {
} from "../types.ts";
import { getEnv } from "#veryfront/platform/compat/process.ts";
import { INVALID_ARGUMENT, TOKEN_STORAGE_ERROR } from "#veryfront/errors";
import { logger as baseLogger } from "#veryfront/utils";
import { base64urlEncodeBytes, logger as baseLogger } from "#veryfront/utils";

const logger = baseLogger.component("o-auth");

Expand All @@ -36,11 +36,7 @@ function generateCodeVerifier(): string {

async function generateCodeChallenge(verifier: string): Promise<string> {
const data = new TextEncoder().encode(verifier);
const hash = await crypto.subtle.digest("SHA-256", data);
return btoa(String.fromCharCode(...new Uint8Array(hash)))
.replace(/\+/g, "-")
.replace(/\//g, "_")
.replace(/=+$/, "");
return base64urlEncodeBytes(new Uint8Array(await crypto.subtle.digest("SHA-256", data)));
}

/** Implement oauth provider. */
Expand Down
Loading