summaryrefslogtreecommitdiffhomepage
path: root/packages/util
diff options
context:
space:
mode:
authorDax <[email protected]>2026-04-15 10:26:20 -0400
committerGitHub <[email protected]>2026-04-15 14:26:20 +0000
commitbe9432a893dd1662c10ff41c7ab552bcba8f3e1b (patch)
treef49000b3dd9c3bea5247d319e8fcbd4fb879b7b0 /packages/util
parentaf20191d1cd60a7f4a421ad81eca5053f7deace1 (diff)
downloadopencode-be9432a893dd1662c10ff41c7ab552bcba8f3e1b.tar.gz
opencode-be9432a893dd1662c10ff41c7ab552bcba8f3e1b.zip
shared package (#22626)
Diffstat (limited to 'packages/util')
-rw-r--r--packages/util/package.json20
-rw-r--r--packages/util/src/array.ts10
-rw-r--r--packages/util/src/binary.ts41
-rw-r--r--packages/util/src/encode.ts51
-rw-r--r--packages/util/src/error.ts54
-rw-r--r--packages/util/src/fn.ts11
-rw-r--r--packages/util/src/identifier.ts48
-rw-r--r--packages/util/src/iife.ts3
-rw-r--r--packages/util/src/lazy.ts11
-rw-r--r--packages/util/src/module.ts10
-rw-r--r--packages/util/src/path.ts37
-rw-r--r--packages/util/src/retry.ts41
-rw-r--r--packages/util/src/slug.ts74
-rw-r--r--packages/util/sst-env.d.ts10
-rw-r--r--packages/util/tsconfig.json14
15 files changed, 0 insertions, 435 deletions
diff --git a/packages/util/package.json b/packages/util/package.json
deleted file mode 100644
index 35aaa9b7c..000000000
--- a/packages/util/package.json
+++ /dev/null
@@ -1,20 +0,0 @@
-{
- "name": "@opencode-ai/util",
- "version": "1.4.6",
- "private": true,
- "type": "module",
- "license": "MIT",
- "exports": {
- "./*": "./src/*.ts"
- },
- "scripts": {
- "typecheck": "tsc --noEmit"
- },
- "dependencies": {
- "zod": "catalog:"
- },
- "devDependencies": {
- "typescript": "catalog:",
- "@types/bun": "catalog:"
- }
-}
diff --git a/packages/util/src/array.ts b/packages/util/src/array.ts
deleted file mode 100644
index 1fb8ac69e..000000000
--- a/packages/util/src/array.ts
+++ /dev/null
@@ -1,10 +0,0 @@
-export function findLast<T>(
- items: readonly T[],
- predicate: (item: T, index: number, items: readonly T[]) => boolean,
-): T | undefined {
- for (let i = items.length - 1; i >= 0; i -= 1) {
- const item = items[i]
- if (predicate(item, i, items)) return item
- }
- return undefined
-}
diff --git a/packages/util/src/binary.ts b/packages/util/src/binary.ts
deleted file mode 100644
index 3d8f61851..000000000
--- a/packages/util/src/binary.ts
+++ /dev/null
@@ -1,41 +0,0 @@
-export namespace Binary {
- export function search<T>(array: T[], id: string, compare: (item: T) => string): { found: boolean; index: number } {
- let left = 0
- let right = array.length - 1
-
- while (left <= right) {
- const mid = Math.floor((left + right) / 2)
- const midId = compare(array[mid])
-
- if (midId === id) {
- return { found: true, index: mid }
- } else if (midId < id) {
- left = mid + 1
- } else {
- right = mid - 1
- }
- }
-
- return { found: false, index: left }
- }
-
- export function insert<T>(array: T[], item: T, compare: (item: T) => string): T[] {
- const id = compare(item)
- let left = 0
- let right = array.length
-
- while (left < right) {
- const mid = Math.floor((left + right) / 2)
- const midId = compare(array[mid])
-
- if (midId < id) {
- left = mid + 1
- } else {
- right = mid
- }
- }
-
- array.splice(left, 0, item)
- return array
- }
-}
diff --git a/packages/util/src/encode.ts b/packages/util/src/encode.ts
deleted file mode 100644
index e4c6e70ac..000000000
--- a/packages/util/src/encode.ts
+++ /dev/null
@@ -1,51 +0,0 @@
-export function base64Encode(value: string) {
- const bytes = new TextEncoder().encode(value)
- const binary = Array.from(bytes, (b) => String.fromCharCode(b)).join("")
- return btoa(binary).replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "")
-}
-
-export function base64Decode(value: string) {
- const binary = atob(value.replace(/-/g, "+").replace(/_/g, "/"))
- const bytes = Uint8Array.from(binary, (c) => c.charCodeAt(0))
- return new TextDecoder().decode(bytes)
-}
-
-export async function hash(content: string, algorithm = "SHA-256"): Promise<string> {
- const encoder = new TextEncoder()
- const data = encoder.encode(content)
- const hashBuffer = await crypto.subtle.digest(algorithm, data)
- const hashArray = Array.from(new Uint8Array(hashBuffer))
- const hashHex = hashArray.map((b) => b.toString(16).padStart(2, "0")).join("")
- return hashHex
-}
-
-export function checksum(content: string): string | undefined {
- if (!content) return undefined
- let hash = 0x811c9dc5
- for (let i = 0; i < content.length; i++) {
- hash ^= content.charCodeAt(i)
- hash = Math.imul(hash, 0x01000193)
- }
- return (hash >>> 0).toString(36)
-}
-
-export function sampledChecksum(content: string, limit = 500_000): string | undefined {
- if (!content) return undefined
- if (content.length <= limit) return checksum(content)
-
- const size = 4096
- const points = [
- 0,
- Math.floor(content.length * 0.25),
- Math.floor(content.length * 0.5),
- Math.floor(content.length * 0.75),
- content.length - size,
- ]
- const hashes = points
- .map((point) => {
- const start = Math.max(0, Math.min(content.length - size, point - Math.floor(size / 2)))
- return checksum(content.slice(start, start + size)) ?? ""
- })
- .join(":")
- return `${content.length}:${hashes}`
-}
diff --git a/packages/util/src/error.ts b/packages/util/src/error.ts
deleted file mode 100644
index 12c27a0a7..000000000
--- a/packages/util/src/error.ts
+++ /dev/null
@@ -1,54 +0,0 @@
-import z from "zod"
-
-export abstract class NamedError extends Error {
- abstract schema(): z.core.$ZodType
- abstract toObject(): { name: string; data: any }
-
- static create<Name extends string, Data extends z.core.$ZodType>(name: Name, data: Data) {
- const schema = z
- .object({
- name: z.literal(name),
- data,
- })
- .meta({
- ref: name,
- })
- const result = class extends NamedError {
- public static readonly Schema = schema
-
- public override readonly name = name as Name
-
- constructor(
- public readonly data: z.input<Data>,
- options?: ErrorOptions,
- ) {
- super(name, options)
- this.name = name
- }
-
- static isInstance(input: any): input is InstanceType<typeof result> {
- return typeof input === "object" && "name" in input && input.name === name
- }
-
- schema() {
- return schema
- }
-
- toObject() {
- return {
- name: name,
- data: this.data,
- }
- }
- }
- Object.defineProperty(result, "name", { value: name })
- return result
- }
-
- public static readonly Unknown = NamedError.create(
- "UnknownError",
- z.object({
- message: z.string(),
- }),
- )
-}
diff --git a/packages/util/src/fn.ts b/packages/util/src/fn.ts
deleted file mode 100644
index 9efe4622f..000000000
--- a/packages/util/src/fn.ts
+++ /dev/null
@@ -1,11 +0,0 @@
-import { z } from "zod"
-
-export function fn<T extends z.ZodType, Result>(schema: T, cb: (input: z.infer<T>) => Result) {
- const result = (input: z.infer<T>) => {
- const parsed = schema.parse(input)
- return cb(parsed)
- }
- result.force = (input: z.infer<T>) => cb(input)
- result.schema = schema
- return result
-}
diff --git a/packages/util/src/identifier.ts b/packages/util/src/identifier.ts
deleted file mode 100644
index ba28a351b..000000000
--- a/packages/util/src/identifier.ts
+++ /dev/null
@@ -1,48 +0,0 @@
-import { randomBytes } from "crypto"
-
-export namespace Identifier {
- const LENGTH = 26
-
- // State for monotonic ID generation
- let lastTimestamp = 0
- let counter = 0
-
- export function ascending() {
- return create(false)
- }
-
- export function descending() {
- return create(true)
- }
-
- function randomBase62(length: number): string {
- const chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
- let result = ""
- const bytes = randomBytes(length)
- for (let i = 0; i < length; i++) {
- result += chars[bytes[i] % 62]
- }
- return result
- }
-
- export function create(descending: boolean, timestamp?: number): string {
- const currentTimestamp = timestamp ?? Date.now()
-
- if (currentTimestamp !== lastTimestamp) {
- lastTimestamp = currentTimestamp
- counter = 0
- }
- counter++
-
- let now = BigInt(currentTimestamp) * BigInt(0x1000) + BigInt(counter)
-
- now = descending ? ~now : now
-
- const timeBytes = Buffer.alloc(6)
- for (let i = 0; i < 6; i++) {
- timeBytes[i] = Number((now >> BigInt(40 - 8 * i)) & BigInt(0xff))
- }
-
- return timeBytes.toString("hex") + randomBase62(LENGTH - 12)
- }
-}
diff --git a/packages/util/src/iife.ts b/packages/util/src/iife.ts
deleted file mode 100644
index ca9ae6c10..000000000
--- a/packages/util/src/iife.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-export function iife<T>(fn: () => T) {
- return fn()
-}
diff --git a/packages/util/src/lazy.ts b/packages/util/src/lazy.ts
deleted file mode 100644
index 935ebe0f9..000000000
--- a/packages/util/src/lazy.ts
+++ /dev/null
@@ -1,11 +0,0 @@
-export function lazy<T>(fn: () => T) {
- let value: T | undefined
- let loaded = false
-
- return (): T => {
- if (loaded) return value as T
- loaded = true
- value = fn()
- return value as T
- }
-}
diff --git a/packages/util/src/module.ts b/packages/util/src/module.ts
deleted file mode 100644
index 6ed3b23d7..000000000
--- a/packages/util/src/module.ts
+++ /dev/null
@@ -1,10 +0,0 @@
-import { createRequire } from "node:module"
-import path from "node:path"
-
-export namespace Module {
- export function resolve(id: string, dir: string) {
- try {
- return createRequire(path.join(dir, "package.json")).resolve(id)
- } catch {}
- }
-}
diff --git a/packages/util/src/path.ts b/packages/util/src/path.ts
deleted file mode 100644
index bb191f512..000000000
--- a/packages/util/src/path.ts
+++ /dev/null
@@ -1,37 +0,0 @@
-export function getFilename(path: string | undefined) {
- if (!path) return ""
- const trimmed = path.replace(/[\/\\]+$/, "")
- const parts = trimmed.split(/[\/\\]/)
- return parts[parts.length - 1] ?? ""
-}
-
-export function getDirectory(path: string | undefined) {
- if (!path) return ""
- const trimmed = path.replace(/[\/\\]+$/, "")
- const parts = trimmed.split(/[\/\\]/)
- return parts.slice(0, parts.length - 1).join("/") + "/"
-}
-
-export function getFileExtension(path: string | undefined) {
- if (!path) return ""
- const parts = path.split(".")
- return parts[parts.length - 1]
-}
-
-export function getFilenameTruncated(path: string | undefined, maxLength: number = 20) {
- const filename = getFilename(path)
- if (filename.length <= maxLength) return filename
- const lastDot = filename.lastIndexOf(".")
- const ext = lastDot <= 0 ? "" : filename.slice(lastDot)
- const available = maxLength - ext.length - 1 // -1 for ellipsis
- if (available <= 0) return filename.slice(0, maxLength - 1) + "…"
- return filename.slice(0, available) + "…" + ext
-}
-
-export function truncateMiddle(text: string, maxLength: number = 20) {
- if (text.length <= maxLength) return text
- const available = maxLength - 1 // -1 for ellipsis
- const start = Math.ceil(available / 2)
- const end = Math.floor(available / 2)
- return text.slice(0, start) + "…" + text.slice(-end)
-}
diff --git a/packages/util/src/retry.ts b/packages/util/src/retry.ts
deleted file mode 100644
index 0014a604c..000000000
--- a/packages/util/src/retry.ts
+++ /dev/null
@@ -1,41 +0,0 @@
-export interface RetryOptions {
- attempts?: number
- delay?: number
- factor?: number
- maxDelay?: number
- retryIf?: (error: unknown) => boolean
-}
-
-const TRANSIENT_MESSAGES = [
- "load failed",
- "network connection was lost",
- "network request failed",
- "failed to fetch",
- "econnreset",
- "econnrefused",
- "etimedout",
- "socket hang up",
-]
-
-function isTransientError(error: unknown): boolean {
- if (!error) return false
- const message = String(error instanceof Error ? error.message : error).toLowerCase()
- return TRANSIENT_MESSAGES.some((m) => message.includes(m))
-}
-
-export async function retry<T>(fn: () => Promise<T>, options: RetryOptions = {}): Promise<T> {
- const { attempts = 3, delay = 500, factor = 2, maxDelay = 10000, retryIf = isTransientError } = options
-
- let lastError: unknown
- for (let attempt = 0; attempt < attempts; attempt++) {
- try {
- return await fn()
- } catch (error) {
- lastError = error
- if (attempt === attempts - 1 || !retryIf(error)) throw error
- const wait = Math.min(delay * Math.pow(factor, attempt), maxDelay)
- await new Promise((resolve) => setTimeout(resolve, wait))
- }
- }
- throw lastError
-}
diff --git a/packages/util/src/slug.ts b/packages/util/src/slug.ts
deleted file mode 100644
index 62cf0e57b..000000000
--- a/packages/util/src/slug.ts
+++ /dev/null
@@ -1,74 +0,0 @@
-export namespace Slug {
- const ADJECTIVES = [
- "brave",
- "calm",
- "clever",
- "cosmic",
- "crisp",
- "curious",
- "eager",
- "gentle",
- "glowing",
- "happy",
- "hidden",
- "jolly",
- "kind",
- "lucky",
- "mighty",
- "misty",
- "neon",
- "nimble",
- "playful",
- "proud",
- "quick",
- "quiet",
- "shiny",
- "silent",
- "stellar",
- "sunny",
- "swift",
- "tidy",
- "witty",
- ] as const
-
- const NOUNS = [
- "cabin",
- "cactus",
- "canyon",
- "circuit",
- "comet",
- "eagle",
- "engine",
- "falcon",
- "forest",
- "garden",
- "harbor",
- "island",
- "knight",
- "lagoon",
- "meadow",
- "moon",
- "mountain",
- "nebula",
- "orchid",
- "otter",
- "panda",
- "pixel",
- "planet",
- "river",
- "rocket",
- "sailor",
- "squid",
- "star",
- "tiger",
- "wizard",
- "wolf",
- ] as const
-
- export function create() {
- return [
- ADJECTIVES[Math.floor(Math.random() * ADJECTIVES.length)],
- NOUNS[Math.floor(Math.random() * NOUNS.length)],
- ].join("-")
- }
-}
diff --git a/packages/util/sst-env.d.ts b/packages/util/sst-env.d.ts
deleted file mode 100644
index 64441936d..000000000
--- a/packages/util/sst-env.d.ts
+++ /dev/null
@@ -1,10 +0,0 @@
-/* This file is auto-generated by SST. Do not edit. */
-/* tslint:disable */
-/* eslint-disable */
-/* deno-fmt-ignore-file */
-/* biome-ignore-all lint: auto-generated */
-
-/// <reference path="../../sst-env.d.ts" />
-
-import "sst"
-export {} \ No newline at end of file
diff --git a/packages/util/tsconfig.json b/packages/util/tsconfig.json
deleted file mode 100644
index 528dcd91d..000000000
--- a/packages/util/tsconfig.json
+++ /dev/null
@@ -1,14 +0,0 @@
-{
- "compilerOptions": {
- "target": "ESNext",
- "module": "ESNext",
- "moduleResolution": "bundler",
- "skipLibCheck": true,
- "allowSyntheticDefaultImports": true,
- "esModuleInterop": true,
- "allowJs": true,
- "noEmit": true,
- "strict": true,
- "isolatedModules": true
- }
-}