refactor(updater): app update based own server

Signed-off-by: Innei <tukon479@gmail.com>
This commit is contained in:
Innei 2025-11-03 19:51:22 +08:00
parent cff58df175
commit c8c789f4fd
No known key found for this signature in database
GPG Key ID: 0F62D33977F021F7
11 changed files with 933 additions and 1149 deletions

View File

@ -0,0 +1,2 @@
provider: custom
channel: latest

View File

@ -1,10 +1,12 @@
import { env } from "@follow/shared/env.desktop"
import { createDesktopAPIHeaders } from "@follow/utils/headers"
import { FollowClient } from "@follow-app/client-sdk"
import PKG from "@pkg"
import PKG, { mainHash, version as appVersion } from "@pkg"
import { gte } from "semver"
import { BETTER_AUTH_COOKIE_NAME_SESSION_TOKEN } from "~/constants/app"
import { WindowManager } from "~/manager/window"
import { getCurrentRendererManifest } from "~/updater/hot-updater"
import { logger } from "../logger"
@ -20,13 +22,17 @@ export const followClient = new FollowClient({
}),
})
export const followApi = followClient.api
export const apiClient = followClient.api
followClient.addRequestInterceptor(async (ctx) => {
const { options } = ctx
const header = options.headers || {}
const apiHeader = createDesktopAPIHeaders({ version: PKG.version })
const rendererManifest = getCurrentRendererManifest()
const rendererVersion = gte(rendererManifest?.version ?? appVersion, appVersion)
? (rendererManifest?.version ?? appVersion)
: appVersion
// Get cookies for authentication
const window = WindowManager.getMainWindow()
@ -44,10 +50,14 @@ followClient.addRequestInterceptor(async (ctx) => {
...apiHeader,
Cookie: headerCookie,
"User-Agent": userAgent,
"X-Follow-Main-Hash": mainHash,
"X-Follow-Renderer-Version": rendererVersion,
"X-Follow-App-Version": appVersion,
"X-Follow-Platform": process.platform,
}
return ctx
})
followClient.addResponseInterceptor(({ response }) => {
logger.info(`API Response: ${response.status} ${response.statusText}`)
return response
@ -67,14 +77,10 @@ followClient.addResponseInterceptor(async ({ response }) => {
}
try {
const json = await response.clone().json()
logger.error("API Error details:", json)
} catch {
// ignore JSON parsing errors
await response.clone().json()
} catch (error) {
logger.error("API Error details:", error)
}
return response
})
// Legacy export for compatibility
export const apiClient = followApi

View File

@ -0,0 +1,15 @@
import type { GetLatestReleaseQuery, LatestReleasePayload } from "@follow-app/client-sdk"
import { apiClient } from "~/lib/api-client"
let cachedLatestRelease: LatestReleasePayload | null = null
export const getUpdateInfo = async (
query: GetLatestReleaseQuery = {},
): Promise<LatestReleasePayload> => {
const response = await apiClient.updates.getLatestRelease(query)
cachedLatestRelease = response.data
return cachedLatestRelease
}
export const getCachedUpdateInfo = () => cachedLatestRelease

View File

@ -1,413 +0,0 @@
// credits: migrated from https://github.com/toeverything/AFFiNE/blob/a802dc4fd6aa720f7a7a995816c78c0b24c514f5/packages/frontend/electron/src/main/updater/custom-github-provider.ts
import { URL } from "node:url"
import type {
CustomPublishOptions,
GithubOptions,
ReleaseNoteInfo,
XElement,
} from "builder-util-runtime"
import { HttpError, newError, parseXml } from "builder-util-runtime"
import type { AppUpdater, ResolvedUpdateFileInfo, UpdateInfo } from "electron-updater"
import { CancellationToken } from "electron-updater"
import { BaseGitHubProvider } from "electron-updater/out/providers/GitHubProvider"
import type { ProviderRuntimeOptions } from "electron-updater/out/providers/Provider"
import { parseUpdateInfo, resolveFiles } from "electron-updater/out/providers/Provider"
import * as semver from "semver"
import { isWindows } from "../env"
import { githubProviderLogger as logger, logObject } from "./logger"
import { isSquirrelBuild } from "./utils"
interface GithubUpdateInfo extends UpdateInfo {
tag: string
}
interface GithubRelease {
id: number
tag_name: string
target_commitish: string
name: string
draft: boolean
prerelease: boolean
created_at: string
published_at: string
}
const hrefRegExp = /\/tag\/([^/]+)$/
export class CustomGitHubProvider extends BaseGitHubProvider<GithubUpdateInfo> {
constructor(
options: CustomPublishOptions,
private readonly updater: AppUpdater,
runtimeOptions: ProviderRuntimeOptions,
) {
super(options as unknown as GithubOptions, "github.com", runtimeOptions)
}
async getLatestVersion(): Promise<GithubUpdateInfo> {
logger.info("Starting getLatestVersion")
logObject(logger, "Provider Configuration", {
"Base URL": this.baseUrl.href,
"Base Path": this.basePath,
"Current Version": this.updater.currentVersion,
"Allow Prerelease": this.updater.allowPrerelease,
})
const cancellationToken = new CancellationToken()
const feedUrl = newUrlFromBase(`${this.basePath}.atom`, this.baseUrl)
logger.info(`Fetching feed from: ${feedUrl.href}`)
const feedXml = await this.httpRequest(
feedUrl,
{
accept: "application/xml, application/atom+xml, text/xml, */*",
},
cancellationToken,
)
if (!feedXml) {
throw new Error(`Cannot find feed in the remote server (${this.baseUrl.href})`)
}
logger.info(`Feed fetched successfully, length: ${feedXml.length} bytes`)
const feed = parseXml(feedXml)
// noinspection TypeScriptValidateJSTypes
let latestRelease = feed.element("entry", false, `No published versions on GitHub`)
let tag: string | null = null
try {
const currentChannel =
this.options.channel ||
this.updater?.channel ||
(semver.prerelease(this.updater.currentVersion)?.[0] as string) ||
null
logger.info(`Current Channel: ${currentChannel}`)
if (currentChannel === null) {
throw newError(
`Cannot parse channel from version: ${this.updater.currentVersion}`,
"ERR_UPDATER_INVALID_VERSION",
)
}
logger.info(`Fetching latest tag by release API for channel: ${currentChannel}`)
const releaseTag = await this.getLatestTagByRelease(currentChannel, cancellationToken)
logger.info(`Release tag from API: ${releaseTag || "null (will use feed matching)"}`)
logger.info("Iterating through feed entries to find matching release")
let entryCount = 0
for (const element of feed.getElements("entry")) {
entryCount++
// noinspection TypeScriptValidateJSTypes
const href = element.element("link").attribute("href")
const hrefElement = hrefRegExp.exec(href)
// If this is null then something is wrong and skip this release
if (hrefElement === null) {
logger.warn(`Entry #${entryCount}: Invalid href format: ${href}`)
continue
}
// This Release's Tag
const hrefTag = decodeURIComponent(hrefElement[1]!)
logger.debug(`Entry #${entryCount}: Processing tag: ${hrefTag}`)
// Get Channel from this release's tag
// Handle new format: desktop/v1.2.3 or mobile/v1.2.3
let hrefChannel = "stable"
if (hrefTag.startsWith("desktop/")) {
// For desktop tags, extract the version and check if it's a prerelease
const version = hrefTag.replace("desktop/", "")
hrefChannel = (semver.prerelease(version)?.[0] as string) || "stable"
logger.debug(
`Entry #${entryCount}: Desktop tag detected, version: ${version}, channel: ${hrefChannel}`,
)
} else if (hrefTag.startsWith("mobile/")) {
// Skip mobile releases for desktop updater
logger.debug(`Entry #${entryCount}: Skipping mobile tag`)
continue
} else {
// Legacy format: check for prerelease directly
hrefChannel = (semver.prerelease(hrefTag)?.[0] as string) || "stable"
logger.debug(`Entry #${entryCount}: Legacy tag format, channel: ${hrefChannel}`)
}
let isNextPreRelease = false
if (releaseTag) {
isNextPreRelease = releaseTag === hrefTag
logger.debug(`Entry #${entryCount}: Matching by release tag: ${releaseTag === hrefTag}`)
} else {
isNextPreRelease = hrefChannel === currentChannel
logger.debug(
`Entry #${entryCount}: Matching by channel: ${hrefChannel} === ${currentChannel} = ${isNextPreRelease}`,
)
}
if (isNextPreRelease) {
tag = hrefTag
latestRelease = element
logger.info(`✓ Found matching release at entry #${entryCount}: ${hrefTag}`)
break
}
}
logger.info(`Processed ${entryCount} feed entries total`)
} catch (e: any) {
logger.error(`Failed to parse releases feed: ${e.stack || e.message}`)
throw newError(
`Cannot parse releases feed: ${e.stack || e.message},\nXML:\n${feedXml}`,
"ERR_UPDATER_INVALID_RELEASE_FEED",
)
}
if (tag === null || tag === undefined) {
logger.error("No matching published versions found on GitHub")
throw newError(`No published versions on GitHub`, "ERR_UPDATER_NO_PUBLISHED_VERSIONS")
}
let rawData: string | null = null
let channelFile = ""
let channelFileUrl: any = ""
const fetchData = async (channelName: string) => {
channelFile = getChannelFilename(channelName)
channelFileUrl = newUrlFromBase(
this.getBaseDownloadPath(String(tag), channelFile),
this.baseUrl,
)
logger.info(`Fetching channel file: ${channelFile} from ${channelFileUrl}`)
const requestOptions = this.createRequestOptions(channelFileUrl)
try {
const data = await this.executor.request(requestOptions, cancellationToken)
logger.info(`Successfully fetched ${channelFile}`)
return data
} catch (e: any) {
if (e instanceof HttpError && e.statusCode === 404) {
logger.warn(`Channel file not found: ${channelFile} (404)`)
throw newError(
`Cannot find ${channelFile} in the latest release artifacts (${channelFileUrl}): ${
e.stack || e.message
}`,
"ERR_UPDATER_CHANNEL_FILE_NOT_FOUND",
)
}
logger.error(`Failed to fetch channel file: ${e.message}`)
throw e
}
}
try {
const channel = this.updater.allowPrerelease
? this.getCustomChannelName(String(semver.prerelease(tag)?.[0] || "latest"))
: this.getDefaultChannelName()
logger.info(`Attempting to fetch channel: ${channel}`)
rawData = await fetchData(channel)
} catch (e: any) {
if (this.updater.allowPrerelease) {
// Allow fallback to `latest.yml`
logger.info("Falling back to default channel (latest.yml)")
rawData = await fetchData(this.getDefaultChannelName())
} else {
throw e
}
}
const result = parseUpdateInfo(rawData, channelFile, channelFileUrl)
if (result.releaseName == null) {
result.releaseName = latestRelease.elementValueOrEmpty("title")
}
if (result.releaseNotes == null) {
result.releaseNotes = computeReleaseNotes(
this.updater.currentVersion,
this.updater.fullChangelog,
feed,
latestRelease,
)
}
logger.info(`Update info parsed successfully`)
logObject(logger, "Update Result", {
Tag: tag,
Version: result.version,
"Release Name": result.releaseName || "N/A",
"Release Date": result.releaseDate || "N/A",
Files: result.files?.length || 0,
})
return {
tag,
...result,
}
}
private get basePath(): string {
return `/${this.options.owner}/${this.options.repo}/releases`
}
/**
* Use release api to get latest version to filter draft version.
* But this api have low request limit 60-times/1-hour, use this to help, not depend on it
* https://docs.github.com/en/rest/releases/releases?apiVersion=2022-11-28
* https://api.github.com/repos/toeverything/affine/releases
* https://docs.github.com/en/rest/rate-limit/rate-limit?apiVersion=2022-11-28#about-rate-limits
*/
private async getLatestTagByRelease(
currentChannel: string,
cancellationToken: CancellationToken,
) {
try {
const apiUrl = newUrlFromBase(`/repos${this.basePath}`, this.baseApiUrl)
logger.debug(`Fetching releases from GitHub API: ${apiUrl}`)
const releasesStr = await this.httpRequest(
apiUrl,
{
accept: "Accept: application/vnd.github+json",
"X-GitHub-Api-Version": "2022-11-28",
},
cancellationToken,
)
if (!releasesStr) {
logger.warn("GitHub API returned empty response")
return null
}
const releases: GithubRelease[] = JSON.parse(releasesStr)
logger.debug(`Received ${releases.length} releases from GitHub API`)
let checkedCount = 0
for (const release of releases) {
if (release.draft) {
logger.debug(`Skipping draft release: ${release.tag_name}`)
continue
}
checkedCount++
const releaseTag = release.tag_name
// Handle new format: desktop/v1.2.3 or mobile/v1.2.3
let releaseChannel = "stable"
if (releaseTag.startsWith("desktop/")) {
// For desktop tags, extract the version and check if it's a prerelease
const version = releaseTag.replace("desktop/", "")
releaseChannel = (semver.prerelease(version)?.[0] as string) || "stable"
logger.debug(`API Release: ${releaseTag} (desktop, channel: ${releaseChannel})`)
} else if (releaseTag.startsWith("mobile/")) {
// Skip mobile releases for desktop updater
logger.debug(`Skipping mobile release: ${releaseTag}`)
continue
} else {
// Legacy format: check for prerelease directly
releaseChannel = (semver.prerelease(releaseTag)?.[0] as string) || "stable"
logger.debug(`API Release: ${releaseTag} (legacy, channel: ${releaseChannel})`)
}
if (releaseChannel === currentChannel) {
logger.info(`✓ Found matching release via API: ${release.tag_name}`)
return release.tag_name
}
}
logger.info(`No matching release found via API (checked ${checkedCount} non-draft releases)`)
} catch (e: any) {
logger.warn(`Cannot parse release from API: ${e.message}`)
}
return null
}
resolveFiles(updateInfo: GithubUpdateInfo): Array<ResolvedUpdateFileInfo> {
logger.info(`Resolving files for tag: ${updateInfo.tag}`)
logger.debug(`Total files in update info: ${updateInfo.files.length}`)
const filteredUpdateInfo = structuredClone(updateInfo)
// for windows, we need to determine its installer type (nsis or squirrel)
if (isWindows && updateInfo.files.length > 1) {
const isSquirrel = isSquirrelBuild()
logger.info(`Windows build detected, installer type: ${isSquirrel ? "Squirrel" : "NSIS"}`)
// @ts-expect-error we should be able to modify the object
filteredUpdateInfo.files = updateInfo.files.filter((file) =>
isSquirrel ? !file.url.includes("nsis.exe") : file.url.includes("nsis.exe"),
)
logger.debug(
`Filtered to ${filteredUpdateInfo.files.length} files after Windows installer type filtering`,
)
}
// still replace space to - due to backward compatibility
const resolved = resolveFiles(filteredUpdateInfo, this.baseUrl, (p) =>
this.getBaseDownloadPath(filteredUpdateInfo.tag, p.replaceAll(" ", "-")),
)
logger.info(`Resolved ${resolved.length} file(s) for download`)
resolved.forEach((file, index) => {
logger.debug(` File ${index + 1}: ${file.url}`)
})
return resolved
}
private getBaseDownloadPath(tag: string, fileName: string): string {
return `${this.basePath}/download/${tag}/${fileName}`
}
}
export interface CustomGitHubOptions {
channel: string
repo: string
owner: string
releaseType: "release" | "prerelease"
}
function getNoteValue(parent: XElement): string {
const result = parent.elementValueOrEmpty("content")
// GitHub reports empty notes as <content>No content.</content>
return result === "No content." ? "" : result
}
export function computeReleaseNotes(
currentVersion: semver.SemVer,
isFullChangelog: boolean,
feed: XElement,
latestRelease: any,
): string | Array<ReleaseNoteInfo> | null {
if (!isFullChangelog) {
return getNoteValue(latestRelease)
}
const releaseNotes: Array<ReleaseNoteInfo> = []
for (const release of feed.getElements("entry")) {
// noinspection TypeScriptValidateJSTypes
const versionRelease = /\/tag\/v?([^/]+)$/.exec(release.element("link").attribute("href"))?.[1]
if (versionRelease && semver.lt(currentVersion, versionRelease)) {
releaseNotes.push({
version: versionRelease,
note: getNoteValue(release),
})
}
}
return releaseNotes.sort((a, b) => semver.rcompare(a.version, b.version))
}
// addRandomQueryToAvoidCaching is false by default because in most cases URL already contains version number,
// so, it makes sense only for Generic Provider for channel files
function newUrlFromBase(pathname: string, baseUrl: URL, addRandomQueryToAvoidCaching = false): URL {
const result = new URL(pathname, baseUrl)
// search is not propagated (search is an empty string if not specified)
const { search } = baseUrl
if (search != null && search.length > 0) {
result.search = search
} else if (addRandomQueryToAvoidCaching) {
result.search = `noCache=${Date.now().toString(32)}`
}
return result
}
function getChannelFilename(channel: string): string {
return `${channel}.yml`
}

View File

@ -0,0 +1,203 @@
import { URL } from "node:url"
import type {
AppUpdate,
LatestReleasePayload,
PlatformUpdate,
PlatformUpdateFile,
} from "@follow-app/client-sdk"
import type { UpdateFileInfo, UpdateInfo } from "builder-util-runtime"
import { newError } from "builder-util-runtime"
import type { AppUpdater } from "electron-updater"
import type { ProviderRuntimeOptions } from "electron-updater/out/providers/Provider"
import { Provider } from "electron-updater/out/providers/Provider"
import type { ResolvedUpdateFileInfo } from "electron-updater/out/types"
import { logger } from "../logger"
import { getUpdateInfo } from "./api"
interface FollowProviderOptions {
provider: "custom"
}
type FollowProviderContext = {
payload: LatestReleasePayload
platform: PlatformUpdate
}
export class FollowUpdateProvider extends Provider<UpdateInfo> {
private static context: FollowProviderContext | null = null
static setContext(context: FollowProviderContext) {
FollowUpdateProvider.context = context
}
static clearContext() {
FollowUpdateProvider.context = null
}
static getContext() {
return FollowUpdateProvider.context
}
constructor(
_options: FollowProviderOptions,
_updater: AppUpdater,
runtimeOptions: ProviderRuntimeOptions,
) {
super(runtimeOptions)
}
async getLatestVersion(): Promise<UpdateInfo> {
const context = await this.ensureContext()
return this.buildUpdateInfo(context)
}
resolveFiles(updateInfo: UpdateInfo): Array<ResolvedUpdateFileInfo> {
return updateInfo.files.map((file) => ({
info: file,
url: new URL(file.url),
}))
}
private buildUpdateInfo(context: FollowProviderContext): UpdateInfo {
const { payload, platform } = context
const files = this.mapFiles(platform.files)
if (files.length === 0) {
throw newError(
`No downloadable files found for platform ${platform.platform}`,
"ERR_UPDATER_CHANNEL_FILE_NOT_FOUND",
)
}
const primaryFile = files[0]
if (!primaryFile) {
throw newError(
`Platform ${platform.platform} provides no downloadable file`,
"ERR_UPDATER_CHANNEL_FILE_NOT_FOUND",
)
}
let primaryPath = primaryFile.url
const primaryUrl = this.safeParseUrl(primaryFile.url)
if (primaryUrl) {
const filename = primaryUrl.pathname.split("/").pop()
if (filename) {
primaryPath = filename
}
}
const { release } = payload
return {
version: platform.version,
files,
path: primaryPath,
sha512: primaryFile.sha512,
releaseName: release.name,
releaseNotes: release.body,
releaseDate: platform.releaseDate || release.publishedAt || new Date().toISOString(),
}
}
private mapFiles(files: PlatformUpdate["files"]): UpdateFileInfo[] {
if (!files) return []
return files
.map((file) => this.mapFile(file))
.filter((file): file is UpdateFileInfo => file !== null)
}
private mapFile(file: PlatformUpdateFile): UpdateFileInfo | null {
if (!file.downloadUrl || !file.sha512) {
logger.warn("Skip platform file without downloadUrl or sha512", file)
return null
}
const mapped: UpdateFileInfo = {
url: file.downloadUrl,
sha512: file.sha512,
}
if (typeof file.size === "number") {
mapped.size = file.size
}
return mapped
}
private safeParseUrl(value: string): URL | null {
try {
return new URL(value)
} catch (error) {
logger.debug?.("Unable to parse update file URL", error)
return null
}
}
private async ensureContext(): Promise<FollowProviderContext> {
const context = FollowUpdateProvider.getContext()
if (context) return context
const fetched = await this.fetchContext()
FollowUpdateProvider.setContext(fetched)
return fetched
}
private async fetchContext(): Promise<FollowProviderContext> {
const payload = await getUpdateInfo({})
const { decision } = payload
if (!decision || decision.type !== "app" || !decision.app) {
throw newError(
"No app update metadata available from provider",
"ERR_UPDATER_NO_PUBLISHED_VERSIONS",
)
}
const platform = this.pickPlatform(decision.app)
if (!platform) {
throw newError(
`No matching platform update for ${process.platform}/${process.arch}`,
"ERR_UPDATER_CHANNEL_FILE_NOT_FOUND",
)
}
return { payload, platform }
}
private pickPlatform(appDecision: AppUpdate): PlatformUpdate | null {
const platforms = appDecision.platforms ?? []
const selected = appDecision.selectedPlatform
if (selected) {
return selected
}
const candidates = this.resolvePlatformCandidates()
const matched = platforms.find((platform) =>
candidates.includes(platform.platform.toLowerCase()),
)
return matched ?? platforms[0] ?? null
}
private resolvePlatformCandidates(): string[] {
const base = new Set<string>()
base.add(process.platform)
base.add(`${process.platform}-${process.arch}`)
base.add(process.arch)
if (process.platform === "darwin") {
base.add("mac")
base.add("macos")
}
if (process.platform === "win32") {
base.add("windows")
base.add("win")
}
return Array.from(base).map((value) => value.toLowerCase())
}
}

View File

@ -1,271 +1,282 @@
/**
* @description This file handles hot updates for the electron renderer layer
*/
import { existsSync, readFileSync } from "node:fs"
import { mkdir, readdir, rename, rm, stat, writeFile } from "node:fs/promises"
import os from "node:os"
import { callWindowExpose } from "@follow/shared/bridge"
import type { LatestReleasePayload, RendererUpdate } from "@follow-app/client-sdk"
import { mainHash, version as appVersion } from "@pkg"
import log from "electron-log"
import { load } from "js-yaml"
import { dump, load } from "js-yaml"
import path from "pathe"
import { x } from "tar"
import { GITHUB_OWNER, GITHUB_REPO, HOTUPDATE_RENDER_ENTRY_DIR } from "~/constants/app"
import { HOTUPDATE_RENDER_ENTRY_DIR } from "~/constants/app"
import { downloadFileWithProgress } from "~/lib/download"
import { WindowManager } from "~/manager/window"
import { appUpdaterConfig } from "./configs"
const logger = log.scope("hot-updater")
declare const GIT_COMMIT_HASH: string | undefined
const url = `https://github.com/${GITHUB_OWNER}/${GITHUB_REPO}`
const releasesUrl = `${url}/releases`
const releaseApiUrl = `https://api.github.com/repos/${GITHUB_OWNER}/${GITHUB_REPO}/releases`
export type RendererManifest = RendererUpdate & {
downloadUrl: string
downloadedAt?: string
}
const getLatestReleaseTag = async () => {
// First try to get the latest release
try {
const latestRes = await fetch(`${releaseApiUrl}/latest`)
if (latestRes.ok) {
const latestRelease = await latestRes.json()
// Check if the latest release is a desktop release
if (
latestRelease.tag_name &&
latestRelease.tag_name.startsWith("desktop/") &&
!latestRelease.draft
) {
return latestRelease.tag_name
export enum RendererEligibilityStatus {
NoManifest,
RequiresFullAppUpdate,
AlreadyCurrent,
Eligible,
}
export interface RendererEligibilityResult {
status: RendererEligibilityStatus
manifest?: RendererManifest
reason?: string
}
class RendererHotUpdater {
private readonly logger = log.scope("updater:renderer")
private readonly tempDir = path.resolve(os.tmpdir(), "follow-render-update")
private readonly manifestPath = path.resolve(HOTUPDATE_RENDER_ENTRY_DIR, "manifest.yml")
extractManifest(payload: LatestReleasePayload | null): RendererManifest | null {
if (!payload) return null
const { decision } = payload
if (!decision || decision.type !== "renderer") {
return null
}
const { renderer } = decision
if (!renderer) {
this.logger.debug("Renderer decision payload missing renderer field")
return null
}
if (!renderer.downloadUrl) {
this.logger.warn("Renderer decision missing downloadUrl, skip renderer hot update")
return null
}
if (!renderer.filename) {
this.logger.warn("Renderer decision missing filename, skip renderer hot update")
return null
}
if (!renderer.hash) {
this.logger.warn("Renderer decision missing hash, skip renderer hot update")
return null
}
return {
...renderer,
downloadUrl: renderer.downloadUrl,
}
}
evaluateManifest(manifest: RendererManifest | null): RendererEligibilityResult {
if (!manifest) {
return { status: RendererEligibilityStatus.NoManifest }
}
if (manifest.mainHash && manifest.mainHash !== mainHash) {
return {
status: RendererEligibilityStatus.RequiresFullAppUpdate,
manifest,
reason: `Renderer payload requires main hash ${manifest.mainHash}, current main hash is ${mainHash}`,
}
}
} catch (error) {
logger.warn("Failed to fetch latest release, falling back to all releases", error)
if (manifest.version === appVersion) {
return {
status: RendererEligibilityStatus.AlreadyCurrent,
reason: "Renderer version matches current app version",
}
}
if (manifest.commit && GIT_COMMIT_HASH && manifest.commit === GIT_COMMIT_HASH) {
return {
status: RendererEligibilityStatus.AlreadyCurrent,
reason: "Renderer commit matches current main commit",
}
}
const installedManifest = this.getCurrentManifest()
if (installedManifest) {
if (installedManifest.version === manifest.version) {
return {
status: RendererEligibilityStatus.AlreadyCurrent,
reason: "Installed renderer manifest already at target version",
}
}
if (
installedManifest.commit &&
manifest.commit &&
installedManifest.commit === manifest.commit
) {
return {
status: RendererEligibilityStatus.AlreadyCurrent,
reason: "Installed renderer manifest commit matches target commit",
}
}
}
return {
status: RendererEligibilityStatus.Eligible,
manifest,
}
}
// If latest release is not a desktop release or fetch failed, get all releases
const res = await fetch(releaseApiUrl)
async applyManifest(manifest: RendererManifest): Promise<void> {
if (!appUpdaterConfig.enableRenderHotUpdate) {
this.logger.info("Renderer hot update skipped because it is disabled in config")
return
}
if (!res.ok) {
throw new Error(`GitHub API request failed: ${res.status} ${res.statusText}`)
const archivePath = await this.downloadArchive(manifest)
await mkdir(HOTUPDATE_RENDER_ENTRY_DIR, { recursive: true })
this.logger.info(`Extracting renderer bundle to ${HOTUPDATE_RENDER_ENTRY_DIR}`)
await x({
f: archivePath,
cwd: HOTUPDATE_RENDER_ENTRY_DIR,
})
const extractedDir = path.resolve(HOTUPDATE_RENDER_ENTRY_DIR, "renderer")
const targetDir = path.resolve(HOTUPDATE_RENDER_ENTRY_DIR, manifest.version)
const extractedStats = await stat(extractedDir).catch(() => null)
if (!extractedStats) {
throw new Error(`Extracted renderer directory not found at ${extractedDir}`)
}
await rm(targetDir, { recursive: true, force: true })
await rename(extractedDir, targetDir)
await this.writeManifest({ ...manifest, downloadedAt: new Date().toISOString() })
try {
await rm(archivePath, { force: true })
} catch (error) {
this.logger.warn("Failed to clean renderer archive", error)
}
this.logger.info(`Renderer hot update applied successfully: ${manifest.version}`)
const mainWindow = WindowManager.getMainWindow()
if (mainWindow) {
callWindowExpose(mainWindow).readyToUpdate()
}
}
const releases = await res.json()
getCurrentManifest(): RendererManifest | null {
if (!existsSync(this.manifestPath)) {
return null
}
// Check if the response contains an error message
if (releases.message) {
throw new Error(`GitHub API error: ${releases.message}`)
}
try {
const content = readFileSync(this.manifestPath, "utf-8")
const parsed = load(content)
if (parsed && typeof parsed === "object") {
return parsed as RendererManifest
}
} catch (error) {
this.logger.warn("Failed to read renderer manifest from disk", error)
}
// Ensure releases is an array
if (!Array.isArray(releases)) {
throw new TypeError("Invalid response format from GitHub API")
}
// Filter for desktop releases and find the latest one
const desktopReleases = releases.filter(
(release: any) => release.tag_name && release.tag_name.startsWith("desktop/") && !release.draft,
)
if (desktopReleases.length === 0) {
throw new Error("No desktop releases found")
}
// Sort by created_at date in descending order to get the most recent first
desktopReleases.sort((a: any, b: any) => {
return new Date(b.created_at).getTime() - new Date(a.created_at).getTime()
})
// Return the most recent desktop release
return desktopReleases[0].tag_name
}
const getFileDownloadUrl = async (filename: string) => {
const tag = await getLatestReleaseTag()
return `${releasesUrl}/download/${tag}/${filename}`
}
type Manifest = {
/** Render version */
version: string
hash: string
commit: string
filename: string
/** Only electron main hash equal to this value, renderer will can be updated */
mainHash: string
}
const getLatestReleaseManifest = async () => {
const url = await getFileDownloadUrl("manifest.yml")
logger.info(`Fetching manifest from ${url}`)
const res = await fetch(url)
if (!res.ok) {
logger.error(`Failed to fetch manifest: ${res.status} ${res.statusText}`)
return null
}
const text = await res.text()
const manifest = load(text) as Manifest
if (typeof manifest !== "object") {
logger.error("Invalid manifest", text)
return null
}
return manifest
}
const downloadTempDir = path.resolve(os.tmpdir(), "follow-render-update")
export enum CanUpdateRenderState {
// If version is equal, no need to update
NO_NEEDED,
// Can be only update render layer, not fully upgrade app
NEEDED,
// App not support, should trigger app force update
APP_NOT_SUPPORT,
// Network error, can fetch manifest
NETWORK_ERROR,
}
export const canUpdateRender = async (): Promise<[CanUpdateRenderState, Manifest | null]> => {
const manifest = await getLatestReleaseManifest()
logger.info("fetched manifest", manifest)
if (!manifest) return [CanUpdateRenderState.NETWORK_ERROR, null]
const appSupport = mainHash === manifest.mainHash
if (!appSupport) {
logger.info("app not support, should trigger app force update, app version: ", appVersion)
return [CanUpdateRenderState.APP_NOT_SUPPORT, null]
}
const isVersionEqual = appVersion === manifest.version
if (isVersionEqual) {
logger.info("version is equal, skip update")
return [CanUpdateRenderState.NO_NEEDED, null]
}
const isCommitEqual = GIT_COMMIT_HASH === manifest.commit
if (isCommitEqual) {
logger.info("commit is equal, skip update")
return [CanUpdateRenderState.NO_NEEDED, null]
}
const manifestFilePath = path.resolve(HOTUPDATE_RENDER_ENTRY_DIR, "manifest.yml")
const manifestExist = existsSync(manifestFilePath)
const oldManifest: Manifest | null = manifestExist
? (load(readFileSync(manifestFilePath, "utf-8")) as Manifest)
: null
if (oldManifest) {
if (oldManifest.version === manifest.version) {
logger.info("manifest version is equal, skip update")
return [CanUpdateRenderState.NO_NEEDED, null]
async cleanup(): Promise<void> {
const manifest = this.getCurrentManifest()
if (!manifest) {
await rm(HOTUPDATE_RENDER_ENTRY_DIR, { recursive: true, force: true })
return
}
if (oldManifest.commit === manifest.commit) {
logger.info("manifest commit is equal, skip update")
return [CanUpdateRenderState.NO_NEEDED, null]
const keepDir = path.resolve(HOTUPDATE_RENDER_ENTRY_DIR, manifest.version)
let entries: string[] = []
try {
entries = await readdir(HOTUPDATE_RENDER_ENTRY_DIR)
} catch (error) {
this.logger.warn("Failed to read renderer directory for cleanup", error)
return
}
}
return [CanUpdateRenderState.NEEDED, manifest]
}
const downloadRenderAsset = async (manifest: Manifest) => {
const { filename } = manifest
const url = await getFileDownloadUrl(filename)
const filePath = path.resolve(downloadTempDir, filename)
logger.info(`Downloading ${url}, Save to ${filePath}`)
const success = await downloadFileWithProgress({
url,
outputPath: filePath,
expectedHash: manifest.hash,
onLog: (message) => {
logger.info(message)
},
})
if (!success) throw new Error("Download hot update render asset failed")
return filePath
}
export const hotUpdateRender = async (manifest: Manifest) => {
if (!appUpdaterConfig.enableRenderHotUpdate) return false
if (!manifest) return false
const filePath = await downloadRenderAsset(manifest)
logger.info(`Downloaded render asset to ${filePath}`)
if (!filePath) return false
// Extract the tar.gz file
await mkdir(HOTUPDATE_RENDER_ENTRY_DIR, { recursive: true })
logger.info(`Extracting render asset to ${HOTUPDATE_RENDER_ENTRY_DIR}`)
await x({
f: filePath,
cwd: HOTUPDATE_RENDER_ENTRY_DIR,
})
logger.info(
`Extracted render asset to ${HOTUPDATE_RENDER_ENTRY_DIR}, rename to ${manifest.version}`,
)
// Rename `renderer` folder to `manifest.version`
await rename(
path.resolve(HOTUPDATE_RENDER_ENTRY_DIR, "renderer"),
path.resolve(HOTUPDATE_RENDER_ENTRY_DIR, manifest.version),
)
const manifestPath = path.resolve(HOTUPDATE_RENDER_ENTRY_DIR, "manifest.yml")
logger.info(`Write manifest to ${manifestPath}`)
await writeFile(manifestPath, JSON.stringify(manifest))
logger.info(`Hot update render success, update to ${manifest.version}`)
const mainWindow = WindowManager.getMainWindow()
if (!mainWindow) return false
const caller = callWindowExpose(mainWindow)
caller.readyToUpdate()
return true
}
export const getCurrentRenderManifest = () => {
const manifestFilePath = path.resolve(HOTUPDATE_RENDER_ENTRY_DIR, "manifest.yml")
const manifestExist = existsSync(manifestFilePath)
if (!manifestExist) return null
return load(readFileSync(manifestFilePath, "utf-8")) as Manifest
}
export const cleanupOldRender = async () => {
const manifest = getCurrentRenderManifest()
if (!manifest) {
// Empty the directory
await rm(HOTUPDATE_RENDER_ENTRY_DIR, { recursive: true, force: true })
return
await Promise.all(
entries.map(async (entryName) => {
const entryPath = path.resolve(HOTUPDATE_RENDER_ENTRY_DIR, entryName)
const entryStat = await stat(entryPath).catch(() => null)
if (!entryStat?.isDirectory()) return
if (entryPath === keepDir) return
await rm(entryPath, { recursive: true, force: true })
}),
)
}
const currentRenderVersion = manifest.version
// Clean all not current version
const dirs = await readdir(HOTUPDATE_RENDER_ENTRY_DIR)
for (const dir of dirs) {
const isDir = (await stat(path.resolve(HOTUPDATE_RENDER_ENTRY_DIR, dir))).isDirectory()
if (!isDir) continue
if (dir === currentRenderVersion) continue
await rm(path.resolve(HOTUPDATE_RENDER_ENTRY_DIR, dir), { recursive: true, force: true })
loadDynamicEntry() {
if (!appUpdaterConfig.enableRenderHotUpdate) return
const manifest = this.getCurrentManifest()
if (!manifest) return
if (manifest.mainHash && manifest.mainHash !== mainHash) return
const dir = path.resolve(HOTUPDATE_RENDER_ENTRY_DIR, manifest.version)
const entryFile = path.resolve(dir, "index.html")
if (!existsSync(entryFile)) return
return entryFile
}
private async downloadArchive(manifest: RendererManifest) {
const archivePath = path.resolve(this.tempDir, manifest.filename)
this.logger.info(
`Downloading renderer bundle ${manifest.filename} from ${manifest.downloadUrl}`,
)
const success = await downloadFileWithProgress({
url: manifest.downloadUrl,
outputPath: archivePath,
expectedHash: manifest.hash,
onLog: (message) => this.logger.info(message),
})
if (!success) {
throw new Error("Failed to download renderer bundle")
}
return archivePath
}
private async writeManifest(manifest: RendererManifest) {
await writeFile(this.manifestPath, dump(manifest), "utf-8")
}
}
export const loadDynamicRenderEntry = () => {
if (!appUpdaterConfig.enableRenderHotUpdate) return
const manifest = getCurrentRenderManifest()
if (!manifest) return
// check main hash is equal to manifest.mainHash
const appSupport = mainHash === manifest.mainHash
if (!appSupport) return
export const rendererUpdater = new RendererHotUpdater()
const currentRenderVersion = manifest.version
const dir = path.resolve(HOTUPDATE_RENDER_ENTRY_DIR, currentRenderVersion)
const entryFile = path.resolve(dir, "index.html")
const entryFileExists = existsSync(entryFile)
export const extractRendererManifest = (payload: LatestReleasePayload | null) =>
rendererUpdater.extractManifest(payload)
if (!entryFileExists) return
return entryFile
export const evaluateRendererUpdate = (manifest: RendererManifest | null) =>
rendererUpdater.evaluateManifest(manifest)
export const applyRendererUpdate = async (manifest: RendererManifest) => {
await rendererUpdater.applyManifest(manifest)
}
export const getCurrentRendererManifest = () => rendererUpdater.getCurrentManifest()
export const cleanupOldRenderer = async () => {
await rendererUpdater.cleanup()
}
export const cleanupOldRender = cleanupOldRenderer
export const loadDynamicRenderEntry = () => rendererUpdater.loadDynamicEntry()

View File

@ -1,189 +1,352 @@
import { fileURLToPath } from "node:url"
import { callWindowExpose } from "@follow/shared/bridge"
import { DEV } from "@follow/shared/constants"
import type { LatestReleasePayload, PlatformUpdate } from "@follow-app/client-sdk"
import type { AppUpdater } from "electron-updater"
import { autoUpdater as defaultAutoUpdater } from "electron-updater"
import { join } from "pathe"
import { GITHUB_OWNER, GITHUB_REPO } from "~/constants/app"
import { WindowManager } from "~/manager/window"
import { canUpdateRender, CanUpdateRenderState, hotUpdateRender } from "~/updater/hot-updater"
import type { RendererManifest } from "~/updater/hot-updater"
import { RendererEligibilityStatus, rendererUpdater } from "~/updater/hot-updater"
import { channel, isWindows } from "../env"
import { logger } from "../logger"
import { getUpdateInfo } from "./api"
import { appUpdaterConfig } from "./configs"
import { CustomGitHubProvider } from "./custom-github-provider"
import { FollowUpdateProvider } from "./follow-update-provider"
import { WindowsUpdater } from "./windows-updater"
// skip auto update in dev mode
// const disabled = DEV
const disabled = !appUpdaterConfig.enableAppUpdate
const autoUpdater = isWindows ? new WindowsUpdater() : defaultAutoUpdater
export const quitAndInstall = () => {
const mainWindow = WindowManager.getMainWindow()
logger.info("Quit and install update, close main window, ", mainWindow?.id)
WindowManager.destroyMainWindow()
setTimeout(() => {
logger.info("Window is closed, quit and install update")
autoUpdater.quitAndInstall()
}, 1000)
type UpdateCheckOptions = {
refresh?: boolean
}
let downloading = false
let checkingUpdate = false
const checkRenderUpdateAvailable = async () => {
const [state, manifest] = await canUpdateRender()
if (state === CanUpdateRenderState.NEEDED && manifest) {
return true
}
return false
type UpdateCheckResult = {
hasUpdate: boolean
error?: string
}
const upgradeRenderIfNeeded = async () => {
const [state, manifest] = await canUpdateRender()
if (state === CanUpdateRenderState.NO_NEEDED) {
return { upgraded: false }
}
if (state === CanUpdateRenderState.NEEDED && manifest) {
await hotUpdateRender(manifest)
return { upgraded: true }
}
return { upgraded: false }
}
export const checkForAppUpdates = async (): Promise<{ hasUpdate: boolean; error?: string }> => {
if (disabled || checkingUpdate) {
return { hasUpdate: false }
class FollowUpdater {
private readonly disabled: boolean
private checkingUpdate = false
private downloadingUpdate = false
private pollingTimer: NodeJS.Timeout | null = null
constructor(
private readonly autoUpdater: AppUpdater,
private readonly renderer = rendererUpdater,
) {
this.disabled = !appUpdaterConfig.enableAppUpdate
}
checkingUpdate = true
try {
let hasUpdate = false
if (appUpdaterConfig.enableRenderHotUpdate) {
const hasRenderUpdate = await checkRenderUpdateAvailable()
if (hasRenderUpdate) {
hasUpdate = true
// Auto upgrade renderer
upgradeRenderIfNeeded()
return { hasUpdate }
}
register() {
if (this.disabled) {
logger.info("App auto-update disabled; updater not registered")
return
}
// Check for core app updates
if (appUpdaterConfig.enableCoreUpdate) {
const result = await autoUpdater.checkForUpdates()
if (result !== null && result.updateInfo !== null) {
hasUpdate = true
}
this.autoUpdater.autoDownload = false
this.autoUpdater.allowPrerelease = channel !== "stable"
this.autoUpdater.autoInstallOnAppQuit = true
this.autoUpdater.autoRunAppAfterInstall = true
this.autoUpdater.forceDevUpdateConfig = DEV
if (import.meta.env.DEV) {
const __dirname = fileURLToPath(new URL(".", import.meta.url))
this.autoUpdater.updateConfigPath = join(__dirname, "../../dev-only/dev-app-update.yml")
}
return { hasUpdate }
} catch (e) {
logger.error("Error checking for updates", e)
return { hasUpdate: false, error: e instanceof Error ? e.message : "Unknown error" }
} finally {
checkingUpdate = false
}
}
this.autoUpdater.setFeedURL({
provider: "custom",
updateProvider: FollowUpdateProvider,
})
export const downloadAppUpdate = async () => {
if (disabled || downloading) {
return
}
downloading = true
autoUpdater.downloadUpdate().catch((e) => {
downloading = false
logger.error("Failed to download update", e)
})
logger.info("Update available, downloading...")
return
}
this.registerAutoUpdaterEvents()
export const registerUpdater = async () => {
if (disabled) {
return
}
if (appUpdaterConfig.app.autoCheckUpdate) {
void this.checkForUpdates().catch((error) =>
logger.error("Initial update check failed", error),
)
}
// Disable there, control this in event
autoUpdater.autoDownload = false
autoUpdater.allowPrerelease = channel !== "stable"
autoUpdater.autoInstallOnAppQuit = true
autoUpdater.autoRunAppAfterInstall = true
if (this.pollingTimer) {
clearInterval(this.pollingTimer)
}
const feedUrl: Exclude<Parameters<typeof autoUpdater.setFeedURL>[0], string> = {
channel,
// hack for custom provider
provider: "custom" as "github",
repo: GITHUB_REPO,
owner: GITHUB_OWNER,
releaseType: channel === "stable" ? "release" : "prerelease",
// @ts-expect-error hack for custom provider
updateProvider: CustomGitHubProvider,
}
logger.debug("auto-updater feed config", {
...feedUrl,
updateProvider: undefined,
})
autoUpdater.setFeedURL(feedUrl)
// register events for checkForUpdates
autoUpdater.on("checking-for-update", () => {
logger.info("Checking for update")
})
autoUpdater.on("update-available", async (info) => {
logger.info("Update available", info)
// The app hotfix strategy is as follows:
// Determine whether the app should be updated in full or only the renderer layer based on the version number.
// https://www.notion.so/rss3/Follow-Hotfix-Electron-Renderer-layer-RFC-fe2444b9ac194c2cb38f9fa0bb1ef3c1?pvs=4#12e35ea049b480f1b268f1e605d86a62
if (appUpdaterConfig.enableRenderHotUpdate) {
const renderResult = await upgradeRenderIfNeeded()
if (renderResult.upgraded) {
this.pollingTimer = setInterval(() => {
if (!appUpdaterConfig.app.autoCheckUpdate) {
return
}
}
if (appUpdaterConfig.app.autoDownloadUpdate && appUpdaterConfig.enableCoreUpdate) {
downloadAppUpdate().catch((err) => {
logger.error(err)
void this.checkForUpdates().catch((error) => {
logger.error("Scheduled update check failed", error)
})
}
})
autoUpdater.on("update-not-available", (info) => {
logger.info("Update not available", info)
})
autoUpdater.on("download-progress", (e) => {
logger.info(`Download progress: ${e.percent}`)
})
autoUpdater.on("update-downloaded", () => {
downloading = false
logger.info("Update downloaded, ready to install")
}, appUpdaterConfig.app.checkUpdateInterval)
}
async checkForUpdates(options: UpdateCheckOptions = {}): Promise<UpdateCheckResult> {
if (this.disabled) {
return { hasUpdate: false }
}
if (this.checkingUpdate) {
logger.info("Update check already in progress, skipping")
return { hasUpdate: false }
}
this.checkingUpdate = true
try {
const payload = await getUpdateInfo(options.refresh ? { refresh: true } : {})
const { decision } = payload
if (!decision || decision.type === "none") {
logger.info("Update decision: none")
return { hasUpdate: false }
}
if (decision.type === "renderer") {
logger.info("Update decision: renderer")
return await this.handleRendererDecision(payload)
}
if (decision.type === "app") {
logger.info("Update decision: app")
return await this.handleAppDecision(payload)
}
logger.warn("Unknown update decision type", { type: decision.type })
return { hasUpdate: false }
} catch (error) {
logger.error("Failed to check for updates", error)
return { hasUpdate: false, error: error instanceof Error ? error.message : "Unknown error" }
} finally {
this.checkingUpdate = false
}
}
async downloadAppUpdate(): Promise<void> {
if (this.disabled || this.downloadingUpdate) {
return
}
this.downloadingUpdate = true
try {
await this.autoUpdater.downloadUpdate()
logger.info("App update download requested")
} catch (error) {
this.downloadingUpdate = false
logger.error("Failed to download app update", error)
throw error
}
}
quitAndInstall() {
const mainWindow = WindowManager.getMainWindow()
if (!mainWindow) return
const handlers = callWindowExpose(mainWindow)
logger.info("Quit and install triggered", { windowId: mainWindow?.id })
WindowManager.destroyMainWindow()
handlers.updateDownloaded()
})
autoUpdater.on("error", (e) => {
logger.error("Error while updating client", e)
})
autoUpdater.forceDevUpdateConfig = DEV
setTimeout(() => {
logger.info("Main window closed, quitting to install update")
this.autoUpdater.quitAndInstall()
}, 1000)
}
setInterval(() => {
if (appUpdaterConfig.app.autoCheckUpdate) {
checkForAppUpdates().catch((err) => {
logger.error("Error checking for updates", err)
})
private resolvePlatformCandidates() {
const base = new Set<string>()
base.add(process.platform)
base.add(`${process.platform}-${process.arch}`)
base.add(process.arch)
if (process.platform === "darwin") {
base.add("mac")
base.add("macos")
}
}, appUpdaterConfig.app.checkUpdateInterval)
if (appUpdaterConfig.app.autoCheckUpdate) {
checkForAppUpdates().catch((err) => {
logger.error("Error checking for updates", err)
if (process.platform === "win32") {
base.add("windows")
base.add("win")
}
return Array.from(base).map((value) => value.toLowerCase())
}
private pickPlatformUpdate(
platforms: PlatformUpdate[] | null | undefined,
selected?: PlatformUpdate | null,
): PlatformUpdate | null {
if (!platforms || platforms.length === 0) {
return null
}
if (selected) {
return selected
}
const candidates = this.resolvePlatformCandidates()
const matched = platforms.find((platform) =>
candidates.includes(platform.platform.toLowerCase()),
)
return matched ?? platforms[0] ?? null
}
private async handleAppDecision(payload: LatestReleasePayload): Promise<UpdateCheckResult> {
const appDecision = payload.decision.app
if (!appUpdaterConfig.enableCoreUpdate) {
logger.info("Core app update disabled by configuration")
return { hasUpdate: false }
}
if (!appDecision) {
logger.warn("App update decision missing app payload")
return { hasUpdate: false, error: "App update metadata unavailable" }
}
const platformUpdate = this.pickPlatformUpdate(
appDecision.platforms,
appDecision.selectedPlatform,
)
if (!platformUpdate) {
logger.warn("No matching platform update found", {
platform: process.platform,
arch: process.arch,
})
return { hasUpdate: false, error: "No installer available for this platform" }
}
FollowUpdateProvider.setContext({ payload, platform: platformUpdate })
logger.info("FollowUpdateProvider context set", { platform: platformUpdate.platform })
try {
await this.autoUpdater.checkForUpdates()
} catch (error) {
logger.warn(
"autoUpdater.checkForUpdates failed after preparing FollowUpdateProvider context",
error,
)
return {
hasUpdate: false,
error: error instanceof Error ? error.message : "Failed to check app update",
}
} finally {
FollowUpdateProvider.clearContext()
}
return { hasUpdate: true }
}
private async handleRendererDecision(payload: LatestReleasePayload): Promise<UpdateCheckResult> {
if (!appUpdaterConfig.enableRenderHotUpdate) {
logger.info("Renderer hot update disabled; falling back to app decision if present")
if (payload.decision.app) {
return this.handleAppDecision(payload)
}
return { hasUpdate: false }
}
const manifest = this.renderer.extractManifest(payload)
const eligibility = this.renderer.evaluateManifest(manifest)
switch (eligibility.status) {
case RendererEligibilityStatus.NoManifest: {
return { hasUpdate: false, error: eligibility.reason }
}
case RendererEligibilityStatus.AlreadyCurrent: {
if (eligibility.reason) {
logger.info(eligibility.reason)
}
return { hasUpdate: false }
}
case RendererEligibilityStatus.RequiresFullAppUpdate: {
logger.info(
eligibility.reason ||
"Renderer payload requires main process update, delegating to app updater",
)
if (payload.decision.app) {
return this.handleAppDecision(payload)
}
logger.warn("Renderer update requested full app upgrade but no app payload provided")
return { hasUpdate: false, error: "Renderer update requires full app upgrade" }
}
case RendererEligibilityStatus.Eligible: {
const manifestToApply = eligibility.manifest as RendererManifest | undefined
if (!manifestToApply) {
return { hasUpdate: false }
}
try {
await this.renderer.applyManifest(manifestToApply)
return { hasUpdate: true }
} catch (error) {
logger.error("Renderer hot update failed", error)
return {
hasUpdate: false,
error: error instanceof Error ? error.message : "Renderer hot update failed",
}
}
}
default: {
return { hasUpdate: false }
}
}
}
private registerAutoUpdaterEvents() {
this.autoUpdater.on("checking-for-update", () => {
logger.info("autoUpdater: checking for update")
})
this.autoUpdater.on("update-available", (info) => {
logger.info("autoUpdater: update available", info)
if (appUpdaterConfig.app.autoDownloadUpdate && appUpdaterConfig.enableCoreUpdate) {
void this.downloadAppUpdate().catch((error) =>
logger.error("Automatic download failed", error),
)
}
})
this.autoUpdater.on("update-not-available", (info) => {
logger.info("autoUpdater: update not available", info)
})
this.autoUpdater.on("download-progress", (progress) => {
logger.info(`autoUpdater: download progress ${progress.percent.toFixed(2)}%`)
})
this.autoUpdater.on("update-downloaded", () => {
this.downloadingUpdate = false
logger.info("autoUpdater: update downloaded")
const mainWindow = WindowManager.getMainWindow()
if (!mainWindow) return
callWindowExpose(mainWindow).updateDownloaded()
})
this.autoUpdater.on("error", (error) => {
logger.error("autoUpdater: error", error)
})
}
}
const autoUpdater = isWindows ? new WindowsUpdater() : defaultAutoUpdater
const followUpdater = new FollowUpdater(autoUpdater)
export const registerUpdater = () => {
followUpdater.register()
}
export const checkForAppUpdates = (options: UpdateCheckOptions = {}) =>
followUpdater.checkForUpdates(options)
export const quitAndInstall = () => followUpdater.quitAndInstall()

View File

@ -1,91 +0,0 @@
export interface GitHubReleasesItem {
url: string
assets_url: string
upload_url: string
html_url: string
id: number
author: Author
node_id: string
tag_name: string
target_commitish: string
name: string
draft: boolean
prerelease: boolean
created_at: string
published_at: string
assets: AssetsItem[]
tarball_url: string
zipball_url: string
body: string
reactions?: Reactions
mentions_count?: number
}
interface Author {
login: string
id: number
node_id: string
avatar_url: string
gravatar_id: string
url: string
html_url: string
followers_url: string
following_url: string
gists_url: string
starred_url: string
subscriptions_url: string
organizations_url: string
repos_url: string
events_url: string
received_events_url: string
type: string
user_view_type: string
site_admin: boolean
}
interface AssetsItem {
url: string
id: number
node_id: string
name: string
label: string | null
uploader: Uploader
content_type: string
state: string
size: number
download_count: number
created_at: string
updated_at: string
browser_download_url: string
}
interface Uploader {
login: string
id: number
node_id: string
avatar_url: string
gravatar_id: string
url: string
html_url: string
followers_url: string
following_url: string
gists_url: string
starred_url: string
subscriptions_url: string
organizations_url: string
repos_url: string
events_url: string
received_events_url: string
type: string
user_view_type: string
site_admin: boolean
}
interface Reactions {
url: string
total_count: number
"+1": number
"-1": number
laugh: number
hooray: number
confused: number
heart: number
rocket: number
eyes: number
}

View File

@ -1,55 +0,0 @@
import fs from "node:fs"
import { app } from "electron"
import path from "pathe"
import { major, minor } from "semver"
let _isSquirrelBuild: boolean | null = null
export function isSquirrelBuild() {
if (typeof _isSquirrelBuild === "boolean") {
return _isSquirrelBuild
}
// if it is squirrel build, there will be 'squirrel.exe'
// otherwise it is in nsis web mode
const files = fs.readdirSync(path.dirname(app.getPath("exe")))
_isSquirrelBuild = files.some((it) => it.includes("squirrel.exe"))
return _isSquirrelBuild
}
// The following scenario only requires updating the renderer, so the app update is skipped:
// In x.y.z, the update of z will only trigger renderer hotfix, while the update of y requires updating the entire app.
// The hotfix version of x.y.z-beta.0 adds a suffix number. It triggers renderer update. If the main code is modified and the entire app update needs to be triggered, the hotfix version adds a suffix like x.y.z-beta.0.app.
// For subsequent minor versions that require updating the main code, the suffix .app needs to be added.
export const shouldUpdateApp = (currentVersion: string, nextVersion: string) => {
if (nextVersion.includes("app")) {
return true
}
// x.y.z 's y or x not equal, need update app
const [x1, x2] = [safeMajor(currentVersion), safeMajor(nextVersion)]
const [y1, y2] = [safeMinor(currentVersion), safeMinor(nextVersion)]
// Here, it is not determined whether it is a problem of version number downgrade; the updater will handle it automatically.
if (x1 !== x2 || y1 !== y2) {
return true
}
return false
}
const safeMajor = (version: string) => {
try {
return major(version)
} catch {
return "0.0.0"
}
}
const safeMinor = (version: string) => {
try {
return minor(version)
} catch {
return "0.0.0"
}
}

View File

@ -7,8 +7,8 @@ settings:
catalogs:
default:
'@follow-app/client-sdk':
specifier: 0.3.78
version: 0.3.78
specifier: 0.3.79
version: 0.3.79
tailwindcss-uikit-colors:
specifier: 1.0.0
version: 1.0.0
@ -339,7 +339,7 @@ importers:
version: 4.3.0
'@follow-app/client-sdk':
specifier: 'catalog:'
version: 0.3.78(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.5)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.16.0(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5))(react@19.0.0)(utf-8-validate@6.0.5))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5))(react@19.0.0))(hono@4.9.8)(kysely@0.28.8)(pg@8.16.3)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
version: 0.3.79(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.5)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.16.0(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5))(react@19.0.0)(utf-8-validate@6.0.5))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5))(react@19.0.0))(hono@4.9.8)(kysely@0.28.8)(pg@8.16.3)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
'@follow-app/readability':
specifier: workspace:*
version: link:../../../../packages/readability
@ -457,7 +457,7 @@ importers:
version: 3.0.2(electron@38.3.0)
'@follow-app/client-sdk':
specifier: 'catalog:'
version: 0.3.78(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.0)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.0)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.16.0(react-native@0.79.6(@babel/core@7.28.0)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.0)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.0)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(hono@4.9.8)(kysely@0.28.8)(pg@8.16.3)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
version: 0.3.79(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.0)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.0)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.16.0(react-native@0.79.6(@babel/core@7.28.0)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.0)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.0)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(hono@4.9.8)(kysely@0.28.8)(pg@8.16.3)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
'@follow/database':
specifier: workspace:*
version: link:../../../../packages/internal/database
@ -812,7 +812,7 @@ importers:
version: 4.1.1(react@19.0.0)
'@follow-app/client-sdk':
specifier: 'catalog:'
version: 0.3.78(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.4)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.4)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.15.0(react-native@0.79.6(@babel/core@7.28.4)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.4)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.4)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(hono@4.9.8)(kysely@0.28.8)(pg@8.16.3)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
version: 0.3.79(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.4)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.4)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.15.0(react-native@0.79.6(@babel/core@7.28.4)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.4)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.4)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(hono@4.9.8)(kysely@0.28.8)(pg@8.16.3)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
'@follow/components':
specifier: workspace:*
version: link:../../packages/internal/components
@ -1193,7 +1193,7 @@ importers:
version: 6.2.1
'@follow-app/client-sdk':
specifier: 'catalog:'
version: 0.3.78(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.5)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.16.0(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(hono@4.9.8)(kysely@0.28.8)(pg@8.16.3)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
version: 0.3.79(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.5)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.16.0(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(hono@4.9.8)(kysely@0.28.8)(pg@8.16.3)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
'@follow/tracker':
specifier: workspace:*
version: link:../../packages/internal/tracker
@ -1688,7 +1688,7 @@ importers:
dependencies:
'@follow-app/client-sdk':
specifier: 'catalog:'
version: 0.3.78(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.5)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.16.0(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(hono@4.9.8)(kysely@0.28.8)(pg@8.16.3)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
version: 0.3.79(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.5)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.16.0(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(hono@4.9.8)(kysely@0.28.8)(pg@8.16.3)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
'@follow/configs':
specifier: workspace:*
version: link:../../configs
@ -1700,7 +1700,7 @@ importers:
dependencies:
'@follow-app/client-sdk':
specifier: 'catalog:'
version: 0.3.78(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.5)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.16.0(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(hono@4.9.8)(kysely@0.28.8)(pg@8.16.3)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
version: 0.3.79(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.5)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.16.0(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(hono@4.9.8)(kysely@0.28.8)(pg@8.16.3)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
'@follow/constants':
specifier: workspace:*
version: link:../constants
@ -1772,7 +1772,7 @@ importers:
dependencies:
'@follow-app/client-sdk':
specifier: 'catalog:'
version: 0.3.78(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.5)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.16.0(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(hono@4.9.8)(kysely@0.28.8)(pg@8.16.3)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
version: 0.3.79(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.5)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.16.0(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(hono@4.9.8)(kysely@0.28.8)(pg@8.16.3)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
'@follow/constants':
specifier: workspace:*
version: link:../constants
@ -1803,7 +1803,7 @@ importers:
version: 2.0.0(@types/node@24.8.1)
'@follow-app/client-sdk':
specifier: 'catalog:'
version: 0.3.78(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.5)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.16.0(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(hono@4.9.8)(kysely@0.28.8)(pg@8.16.3)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
version: 0.3.79(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.5)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.16.0(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(hono@4.9.8)(kysely@0.28.8)(pg@8.16.3)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
'@folo-services/drizzle':
specifier: 0.1.34
version: 0.1.34(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.5)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.16.0(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(hono@4.9.8)(kysely@0.28.8)
@ -1833,7 +1833,7 @@ importers:
dependencies:
'@follow-app/client-sdk':
specifier: 'catalog:'
version: 0.3.78(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.5)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.16.0(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(hono@4.9.8)(kysely@0.28.8)(pg@8.16.3)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
version: 0.3.79(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.5)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.16.0(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(hono@4.9.8)(kysely@0.28.8)(pg@8.16.3)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
'@follow/configs':
specifier: workspace:*
version: link:../../configs
@ -1882,7 +1882,7 @@ importers:
devDependencies:
'@follow-app/client-sdk':
specifier: 'catalog:'
version: 0.3.78(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.5)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.16.0(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(hono@4.9.8)(kysely@0.28.8)(pg@8.16.3)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
version: 0.3.79(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.5)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.16.0(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(hono@4.9.8)(kysely@0.28.8)(pg@8.16.3)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
'@follow/configs':
specifier: workspace:*
version: link:../../configs
@ -4358,32 +4358,29 @@ packages:
'@floating-ui/utils@0.2.10':
resolution: {integrity: sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==}
'@follow-app/client-sdk@0.3.78':
resolution: {integrity: sha512-I8SPfimOqNcQZrN03wolVxj7IrOje3IuIxA9CA7ulS9i2K0GNhw8k64bhSjTGutkATstdzxTkCJYfS7wn9F0dQ==}
'@follow-app/client-sdk@0.3.79':
resolution: {integrity: sha512-w3EQEPjZMI638vzdB/klrldYvoh1LYWX6+5pMpkeLzC48hARUOfGi7dC8sVBM20/EXgvP/Wjkve637tjB7mKeg==}
'@folo-services/ai-tools@0.2.49':
resolution: {integrity: sha512-QsKTW8N18812Thkdcc7wDTff3QkQxxTYHxHi1RM321jk4DbCq+mHlAr10Krwj0mRtKuULtqFHPm13udmfIv1Bw==}
'@folo-services/constants@0.1.41':
resolution: {integrity: sha512-fXJ5DVWMgc4czW8i9JmVx3WckKhUksiwXkzzOClH0GePEOeS+DQ08o21UfZl1pBvhvhZm0pS+klHLljeBaRb1g==}
'@folo-services/constants@0.1.42':
resolution: {integrity: sha512-GoHKg4Wdr+rGYGQauOhVFz+VyHZSiW1/9AGpIUa173a+HM5btvFN6e+Tu8ZNKl6Mu8J5M5GKIL0ditROp9Xv+A==}
'@folo-services/constants@0.1.43':
resolution: {integrity: sha512-vBauScJcR97H7uus0UdQ+g4rLFksRfWTjzIg8GcV3HDHBJOqISE5fxGUYzqkbEpbD6QqofNguVYQQrcXcIPWfQ==}
'@folo-services/drizzle@0.1.34':
resolution: {integrity: sha512-p6dsveNwXwNxmy+8+FHHKiFjVFXwc7yx7c4902k13hd1vcBihxiWUD4MdCwAcQTAPSJ3dYx1UZojHSdyiXwqnw==}
'@folo-services/drizzle@0.1.35':
resolution: {integrity: sha512-b+5OPwjKW3gnf0lkLj7PuhjLCldD9TItXNWRwIvJrPYmIGlrQmUiKgQIuLR8dsksF9L7w8IcIi4Vt40Qppx7nQ==}
'@folo-services/drizzle@0.1.36':
resolution: {integrity: sha512-7BTGJXDPE7m5cs9mZIiYbpHluqPPrUVV0MtZxxkmbve9BlIWDij1Yga4r43CpiFCOK/a0JqMcmkqmokRJfKVxw==}
'@folo-services/exceptions@0.1.19':
resolution: {integrity: sha512-rXgLssE3r3w2WzC3knCX9nYe0cszHXpYwAllrYOsPpzjQSHWRwJ6LuJyt0xlvdeX/9i8KQ/UYgf4to6Abt2whg==}
'@folo-services/exceptions@0.1.20':
resolution: {integrity: sha512-iuV6F22XI6kvSSVQRTCoS/wfJnPGvI3XQbA3YQGgXa8fT28SE+8LBGCyAj0rqbfnXlXdpxZE/IooXdpJyxkp0Q==}
'@folo-services/exceptions@0.1.21':
resolution: {integrity: sha512-bEgKOFKAf0INIJUMSHqdiOvEE3KV096fYk+DeO5em3YkGfPY/l4Fcy0XeOOKJJZJQbQak4Sry7extFbfSmlb/Q==}
'@folo-services/shared@0.0.34':
resolution: {integrity: sha512-T0gZRBlDVP9WLG0Dg8tLgWdk+TVjbdKfSvRHEyBY+YioQ1LO4vulN8ddCv1oBvMQxl0iESY9mnmB4ua9iGGkyQ==}
'@folo-services/shared@0.0.35':
resolution: {integrity: sha512-pvcuDEg82ZxgaUlwtx16DBV3TRsZuFI4g4DuNaRejnZTLnW8XswG56TZloe+OwsbHUUzh4mOZBVM3PYUVpeayA==}
'@fontsource/sn-pro@5.2.5':
resolution: {integrity: sha512-rBdBv/0ygj6bkO7xDMMFpwobLdSrcQ2Jncb6DIwdeYGoAgeWkQRwVYhGDKasfLjEYCNYxrqr6wsXsM9+aU39RA==}
@ -4926,9 +4923,6 @@ packages:
'@napi-rs/wasm-runtime@0.2.12':
resolution: {integrity: sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==}
'@napi-rs/wasm-runtime@1.0.7':
resolution: {integrity: sha512-SeDnOO0Tk7Okiq6DbXmmBODgOAb9dp9gjlphokTUxmt8U3liIP1ZsozBahH69j/RJv+Rfs6IwUKHTgQYJ/HBAw==}
'@noble/ciphers@2.0.1':
resolution: {integrity: sha512-xHK3XHPUW8DTAobU+G0XT+/w+JLM7/8k1UFdB5xg/zTFPnFCobhftzw8wl4Lw2aq/Rvir5pxfZV5fEazmeCJ2g==}
engines: {node: '>= 20.19.0'}
@ -5272,8 +5266,12 @@ packages:
peerDependencies:
'@opentelemetry/api': ^1.1.0
'@oxc-project/types@0.95.0':
resolution: {integrity: sha512-vACy7vhpMPhjEJhULNxrdR0D943TkA/MigMpJCHmBHvMXxRStRi/dPtTlfQ3uDwWSzRpT8z+7ImjZVf8JWBocQ==}
'@oxc-project/runtime@0.71.0':
resolution: {integrity: sha512-QwoF5WUXIGFQ+hSxWEib4U/aeLoiDN9JlP18MnBgx9LLPRDfn1iICtcow7Jgey6HLH4XFceWXQD5WBJ39dyJcw==}
engines: {node: '>=6.9.0'}
'@oxc-project/types@0.71.0':
resolution: {integrity: sha512-5CwQ4MI+P4MQbjLWXgNurA+igGwu/opNetIE13LBs9+V93R64MLvDKOOLZIXSzEfovU3Zef3q3GjPnMTgJTn2w==}
'@peculiar/asn1-android@2.5.0':
resolution: {integrity: sha512-t8A83hgghWQkcneRsgGs2ebAlRe54ns88p7ouv8PW2tzF1nAW4yHcL4uZKrFpIU+uszIRzTkcCuie37gpkId0A==}
@ -6231,98 +6229,75 @@ packages:
resolution: {integrity: sha512-xBaJish5OeGmniDj9cW5PRa/PtmuVU3ziqrbr5xJj901ZDN4TosrVaNZpEiLZAxdfnhAe7uQ7QFWfjPe9d9K2Q==}
engines: {node: '>= 10'}
'@rolldown/binding-android-arm64@1.0.0-beta.45':
resolution: {integrity: sha512-bfgKYhFiXJALeA/riil908+2vlyWGdwa7Ju5S+JgWZYdR4jtiPOGdM6WLfso1dojCh+4ZWeiTwPeV9IKQEX+4g==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [arm64]
os: [android]
'@rolldown/binding-darwin-arm64@1.0.0-beta.45':
resolution: {integrity: sha512-xjCv4CRVsSnnIxTuyH1RDJl5OEQ1c9JYOwfDAHddjJDxCw46ZX9q80+xq7Eok7KC4bRSZudMJllkvOKv0T9SeA==}
engines: {node: ^20.19.0 || >=22.12.0}
'@rolldown/binding-darwin-arm64@1.0.0-beta.9-commit.d91dfb5':
resolution: {integrity: sha512-Mp0/gqiPdepHjjVm7e0yL1acWvI0rJVVFQEADSezvAjon9sjQ7CEg9JnXICD4B1YrPmN9qV/e7cQZCp87tTV4w==}
cpu: [arm64]
os: [darwin]
'@rolldown/binding-darwin-x64@1.0.0-beta.45':
resolution: {integrity: sha512-ddcO9TD3D/CLUa/l8GO8LHzBOaZqWg5ClMy3jICoxwCuoz47h9dtqPsIeTiB6yR501LQTeDsjA4lIFd7u3Ljfw==}
engines: {node: ^20.19.0 || >=22.12.0}
'@rolldown/binding-darwin-x64@1.0.0-beta.9-commit.d91dfb5':
resolution: {integrity: sha512-40re4rMNrsi57oavRzIOpRGmg3QRlW6Ea8Q3znaqgOuJuKVrrm2bIQInTfkZJG7a4/5YMX7T951d0+toGLTdCA==}
cpu: [x64]
os: [darwin]
'@rolldown/binding-freebsd-x64@1.0.0-beta.45':
resolution: {integrity: sha512-MBTWdrzW9w+UMYDUvnEuh0pQvLENkl2Sis15fHTfHVW7ClbGuez+RWopZudIDEGkpZXdeI4CkRXk+vdIIebrmg==}
engines: {node: ^20.19.0 || >=22.12.0}
'@rolldown/binding-freebsd-x64@1.0.0-beta.9-commit.d91dfb5':
resolution: {integrity: sha512-8BDM939bbMariZupiHp3OmP5N+LXPT4mULA0hZjDaq970PCxv4krZOSMG+HkWUUwmuQROtV+/00xw39EO0P+8g==}
cpu: [x64]
os: [freebsd]
'@rolldown/binding-linux-arm-gnueabihf@1.0.0-beta.45':
resolution: {integrity: sha512-4YgoCFiki1HR6oSg+GxxfzfnVCesQxLF1LEnw9uXS/MpBmuog0EOO2rYfy69rWP4tFZL9IWp6KEfGZLrZ7aUog==}
engines: {node: ^20.19.0 || >=22.12.0}
'@rolldown/binding-linux-arm-gnueabihf@1.0.0-beta.9-commit.d91dfb5':
resolution: {integrity: sha512-sntsPaPgrECpBB/+2xrQzVUt0r493TMPI+4kWRMhvMsmrxOqH1Ep5lM0Wua/ZdbfZNwm1aVa5pcESQfNfM4Fhw==}
cpu: [arm]
os: [linux]
'@rolldown/binding-linux-arm64-gnu@1.0.0-beta.45':
resolution: {integrity: sha512-LE1gjAwQRrbCOorJJ7LFr10s5vqYf5a00V5Ea9wXcT2+56n5YosJkcp8eQ12FxRBv2YX8dsdQJb+ZTtYJwb6XQ==}
engines: {node: ^20.19.0 || >=22.12.0}
'@rolldown/binding-linux-arm64-gnu@1.0.0-beta.9-commit.d91dfb5':
resolution: {integrity: sha512-5clBW/I+er9F2uM1OFjJFWX86y7Lcy0M+NqsN4s3o07W+8467Zk8oQa4B45vdaXoNUF/yqIAgKkA/OEdQDxZqA==}
cpu: [arm64]
os: [linux]
libc: [glibc]
'@rolldown/binding-linux-arm64-musl@1.0.0-beta.45':
resolution: {integrity: sha512-tdy8ThO/fPp40B81v0YK3QC+KODOmzJzSUOO37DinQxzlTJ026gqUSOM8tzlVixRbQJltgVDCTYF8HNPRErQTA==}
engines: {node: ^20.19.0 || >=22.12.0}
'@rolldown/binding-linux-arm64-musl@1.0.0-beta.9-commit.d91dfb5':
resolution: {integrity: sha512-wv+rnAfQDk9p/CheX8/Kmqk2o1WaFa4xhWI9gOyDMk/ljvOX0u0ubeM8nI1Qfox7Tnh71eV5AjzSePXUhFOyOg==}
cpu: [arm64]
os: [linux]
libc: [musl]
'@rolldown/binding-linux-x64-gnu@1.0.0-beta.45':
resolution: {integrity: sha512-lS082ROBWdmOyVY/0YB3JmsiClaWoxvC+dA8/rbhyB9VLkvVEaihLEOr4CYmrMse151C4+S6hCw6oa1iewox7g==}
engines: {node: ^20.19.0 || >=22.12.0}
'@rolldown/binding-linux-x64-gnu@1.0.0-beta.9-commit.d91dfb5':
resolution: {integrity: sha512-gxD0/xhU4Py47IH3bKZbWtvB99tMkUPGPJFRfSc5UB9Osoje0l0j1PPbxpUtXIELurYCqwLBKXIMTQGifox1BQ==}
cpu: [x64]
os: [linux]
libc: [glibc]
'@rolldown/binding-linux-x64-musl@1.0.0-beta.45':
resolution: {integrity: sha512-Hi73aYY0cBkr1/SvNQqH8Cd+rSV6S9RB5izCv0ySBcRnd/Wfn5plguUoGYwBnhHgFbh6cPw9m2dUVBR6BG1gxA==}
engines: {node: ^20.19.0 || >=22.12.0}
'@rolldown/binding-linux-x64-musl@1.0.0-beta.9-commit.d91dfb5':
resolution: {integrity: sha512-HotuVe3XUjDwqqEMbm3o3IRkP9gdm8raY/btd/6KE3JGLF/cv4+3ff1l6nOhAZI8wulWDPEXPtE7v+HQEaTXnA==}
cpu: [x64]
os: [linux]
libc: [musl]
'@rolldown/binding-openharmony-arm64@1.0.0-beta.45':
resolution: {integrity: sha512-fljEqbO7RHHogNDxYtTzr+GNjlfOx21RUyGmF+NrkebZ8emYYiIqzPxsaMZuRx0rgZmVmliOzEp86/CQFDKhJQ==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [arm64]
os: [openharmony]
'@rolldown/binding-wasm32-wasi@1.0.0-beta.45':
resolution: {integrity: sha512-ZJDB7lkuZE9XUnWQSYrBObZxczut+8FZ5pdanm8nNS1DAo8zsrPuvGwn+U3fwU98WaiFsNrA4XHngesCGr8tEQ==}
engines: {node: '>=14.0.0'}
'@rolldown/binding-wasm32-wasi@1.0.0-beta.9-commit.d91dfb5':
resolution: {integrity: sha512-8Cx+ucbd8n2dIr21FqBh6rUvTVL0uTgEtKR7l+MUZ5BgY4dFh1e4mPVX8oqmoYwOxBiXrsD2JIOCz4AyKLKxWA==}
engines: {node: '>=14.21.3'}
cpu: [wasm32]
'@rolldown/binding-win32-arm64-msvc@1.0.0-beta.45':
resolution: {integrity: sha512-zyzAjItHPUmxg6Z8SyRhLdXlJn3/D9KL5b9mObUrBHhWS/GwRH4665xCiFqeuktAhhWutqfc+rOV2LjK4VYQGQ==}
engines: {node: ^20.19.0 || >=22.12.0}
'@rolldown/binding-win32-arm64-msvc@1.0.0-beta.9-commit.d91dfb5':
resolution: {integrity: sha512-Vhq5vikrVDxAa75fxsyqj0c0Y/uti/TwshXI71Xb8IeUQJOBnmLUsn5dgYf5ljpYYkNa0z9BPAvUDIDMmyDi+w==}
cpu: [arm64]
os: [win32]
'@rolldown/binding-win32-ia32-msvc@1.0.0-beta.45':
resolution: {integrity: sha512-wODcGzlfxqS6D7BR0srkJk3drPwXYLu7jPHN27ce2c4PUnVVmJnp9mJzUQGT4LpmHmmVdMZ+P6hKvyTGBzc1CA==}
engines: {node: ^20.19.0 || >=22.12.0}
'@rolldown/binding-win32-ia32-msvc@1.0.0-beta.9-commit.d91dfb5':
resolution: {integrity: sha512-lN7RIg9Iugn08zP2aZN9y/MIdG8iOOCE93M1UrFlrxMTqPf8X+fDzmR/OKhTSd1A2pYNipZHjyTcb5H8kyQSow==}
cpu: [ia32]
os: [win32]
'@rolldown/binding-win32-x64-msvc@1.0.0-beta.45':
resolution: {integrity: sha512-wiU40G1nQo9rtfvF9jLbl79lUgjfaD/LTyUEw2Wg/gdF5OhjzpKMVugZQngO+RNdwYaNj+Fs+kWBWfp4VXPMHA==}
engines: {node: ^20.19.0 || >=22.12.0}
'@rolldown/binding-win32-x64-msvc@1.0.0-beta.9-commit.d91dfb5':
resolution: {integrity: sha512-7/7cLIn48Y+EpQ4CePvf8reFl63F15yPUlg4ZAhl+RXJIfydkdak1WD8Ir3AwAO+bJBXzrfNL+XQbxm0mcQZmw==}
cpu: [x64]
os: [win32]
'@rolldown/pluginutils@1.0.0-beta.38':
resolution: {integrity: sha512-N/ICGKleNhA5nc9XXQG/kkKHJ7S55u0x0XUJbbkmdCnFuoRkM1Il12q9q0eX19+M7KKUEPw/daUPIRnxhcxAIw==}
'@rolldown/pluginutils@1.0.0-beta.45':
resolution: {integrity: sha512-Le9ulGCrD8ggInzWw/k2J8QcbPz7eGIOWqfJ2L+1R0Opm7n6J37s2hiDWlh6LJN0Lk9L5sUzMvRHKW7UxBZsQA==}
'@rolldown/pluginutils@1.0.0-beta.9-commit.d91dfb5':
resolution: {integrity: sha512-8sExkWRK+zVybw3+2/kBkYBFeLnEUWz1fT7BLHplpzmtqkOfTbAQ9gkt4pzwGIIZmg4Qn5US5ACjUBenrhezwQ==}
'@rollup/plugin-babel@5.3.1':
resolution: {integrity: sha512-WFfdLWU/xVWKeRQnKmIAQULUI7Il0gZnBIH/ZFO069wYIfPu+8zrfp/KMW0atmELoRDq8FbiP3VCss9MhCut7Q==}
@ -14840,9 +14815,8 @@ packages:
vue-tsc:
optional: true
rolldown@1.0.0-beta.45:
resolution: {integrity: sha512-iMmuD72XXLf26Tqrv1cryNYLX6NNPLhZ3AmNkSf8+xda0H+yijjGJ+wVT9UdBUHOpKzq9RjKtQKRCWoEKQQBZQ==}
engines: {node: ^20.19.0 || >=22.12.0}
rolldown@1.0.0-beta.9-commit.d91dfb5:
resolution: {integrity: sha512-FHkj6gGEiEgmAXQchglofvUUdwj2Oiw603Rs+zgFAnn9Cb7T7z3fiaEc0DbN3ja4wYkW6sF2rzMEtC1V4BGx/g==}
hasBin: true
rollup@2.79.2:
@ -21348,12 +21322,12 @@ snapshots:
'@floating-ui/utils@0.2.10': {}
'@follow-app/client-sdk@0.3.78(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.0)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.0)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.16.0(react-native@0.79.6(@babel/core@7.28.0)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.0)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.0)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(hono@4.9.8)(kysely@0.28.8)(pg@8.16.3)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)':
'@follow-app/client-sdk@0.3.79(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.0)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.0)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.16.0(react-native@0.79.6(@babel/core@7.28.0)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.0)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.0)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(hono@4.9.8)(kysely@0.28.8)(pg@8.16.3)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)':
dependencies:
'@folo-services/constants': 0.1.42
'@folo-services/drizzle': 0.1.35(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.0)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.0)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.16.0(react-native@0.79.6(@babel/core@7.28.0)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.0)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.0)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(hono@4.9.8)(kysely@0.28.8)
'@folo-services/exceptions': 0.1.20
'@folo-services/shared': 0.0.34(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.0)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.0)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.16.0(react-native@0.79.6(@babel/core@7.28.0)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.0)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.0)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(hono@4.9.8)(kysely@0.28.8)(pg@8.16.3)
'@folo-services/constants': 0.1.43
'@folo-services/drizzle': 0.1.36(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.0)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.0)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.16.0(react-native@0.79.6(@babel/core@7.28.0)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.0)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.0)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(hono@4.9.8)(kysely@0.28.8)
'@folo-services/exceptions': 0.1.21
'@folo-services/shared': 0.0.35(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.0)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.0)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.16.0(react-native@0.79.6(@babel/core@7.28.0)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.0)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.0)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(hono@4.9.8)(kysely@0.28.8)(pg@8.16.3)
better-auth: 1.3.28(better-sqlite3@12.4.1)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
zod: 4.1.12
transitivePeerDependencies:
@ -21397,12 +21371,12 @@ snapshots:
- svelte
- vue
'@follow-app/client-sdk@0.3.78(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.4)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.4)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.15.0(react-native@0.79.6(@babel/core@7.28.4)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.4)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.4)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(hono@4.9.8)(kysely@0.28.8)(pg@8.16.3)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)':
'@follow-app/client-sdk@0.3.79(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.4)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.4)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.15.0(react-native@0.79.6(@babel/core@7.28.4)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.4)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.4)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(hono@4.9.8)(kysely@0.28.8)(pg@8.16.3)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)':
dependencies:
'@folo-services/constants': 0.1.42
'@folo-services/drizzle': 0.1.35(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.4)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.4)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.15.0(react-native@0.79.6(@babel/core@7.28.4)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.4)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.4)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(hono@4.9.8)(kysely@0.28.8)
'@folo-services/exceptions': 0.1.20
'@folo-services/shared': 0.0.34(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.4)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.4)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.15.0(react-native@0.79.6(@babel/core@7.28.4)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.4)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.4)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(hono@4.9.8)(kysely@0.28.8)(pg@8.16.3)
'@folo-services/constants': 0.1.43
'@folo-services/drizzle': 0.1.36(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.4)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.4)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.15.0(react-native@0.79.6(@babel/core@7.28.4)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.4)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.4)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(hono@4.9.8)(kysely@0.28.8)
'@folo-services/exceptions': 0.1.21
'@folo-services/shared': 0.0.35(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.4)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.4)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.15.0(react-native@0.79.6(@babel/core@7.28.4)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.4)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.4)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(hono@4.9.8)(kysely@0.28.8)(pg@8.16.3)
better-auth: 1.3.28(better-sqlite3@12.4.1)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
zod: 4.1.12
transitivePeerDependencies:
@ -21446,12 +21420,12 @@ snapshots:
- svelte
- vue
'@follow-app/client-sdk@0.3.78(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.5)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.16.0(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5))(react@19.0.0)(utf-8-validate@6.0.5))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5))(react@19.0.0))(hono@4.9.8)(kysely@0.28.8)(pg@8.16.3)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)':
'@follow-app/client-sdk@0.3.79(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.5)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.16.0(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5))(react@19.0.0)(utf-8-validate@6.0.5))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5))(react@19.0.0))(hono@4.9.8)(kysely@0.28.8)(pg@8.16.3)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)':
dependencies:
'@folo-services/constants': 0.1.42
'@folo-services/drizzle': 0.1.35(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.5)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.16.0(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5))(react@19.0.0)(utf-8-validate@6.0.5))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5))(react@19.0.0))(hono@4.9.8)(kysely@0.28.8)
'@folo-services/exceptions': 0.1.20
'@folo-services/shared': 0.0.34(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.5)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.16.0(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5))(react@19.0.0)(utf-8-validate@6.0.5))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5))(react@19.0.0))(hono@4.9.8)(kysely@0.28.8)(pg@8.16.3)
'@folo-services/constants': 0.1.43
'@folo-services/drizzle': 0.1.36(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.5)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.16.0(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5))(react@19.0.0)(utf-8-validate@6.0.5))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5))(react@19.0.0))(hono@4.9.8)(kysely@0.28.8)
'@folo-services/exceptions': 0.1.21
'@folo-services/shared': 0.0.35(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.5)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.16.0(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5))(react@19.0.0)(utf-8-validate@6.0.5))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5))(react@19.0.0))(hono@4.9.8)(kysely@0.28.8)(pg@8.16.3)
better-auth: 1.3.28(better-sqlite3@12.4.1)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
zod: 4.1.12
transitivePeerDependencies:
@ -21495,12 +21469,12 @@ snapshots:
- svelte
- vue
'@follow-app/client-sdk@0.3.78(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.5)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.16.0(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(hono@4.9.8)(kysely@0.28.8)(pg@8.16.3)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)':
'@follow-app/client-sdk@0.3.79(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.5)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.16.0(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(hono@4.9.8)(kysely@0.28.8)(pg@8.16.3)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)':
dependencies:
'@folo-services/constants': 0.1.42
'@folo-services/drizzle': 0.1.35(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.5)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.16.0(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(hono@4.9.8)(kysely@0.28.8)
'@folo-services/exceptions': 0.1.20
'@folo-services/shared': 0.0.34(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.5)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.16.0(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(hono@4.9.8)(kysely@0.28.8)(pg@8.16.3)
'@folo-services/constants': 0.1.43
'@folo-services/drizzle': 0.1.36(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.5)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.16.0(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(hono@4.9.8)(kysely@0.28.8)
'@folo-services/exceptions': 0.1.21
'@folo-services/shared': 0.0.35(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.5)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.16.0(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(hono@4.9.8)(kysely@0.28.8)(pg@8.16.3)
better-auth: 1.3.28(better-sqlite3@12.4.1)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
zod: 4.1.12
transitivePeerDependencies:
@ -21584,11 +21558,7 @@ snapshots:
- sql.js
- sqlite3
'@folo-services/constants@0.1.41':
dependencies:
zod: 4.1.12
'@folo-services/constants@0.1.42':
'@folo-services/constants@0.1.43':
dependencies:
zod: 4.1.12
@ -21674,9 +21644,9 @@ snapshots:
- sql.js
- sqlite3
'@folo-services/drizzle@0.1.35(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.0)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.0)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.16.0(react-native@0.79.6(@babel/core@7.28.0)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.0)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.0)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(hono@4.9.8)(kysely@0.28.8)':
'@folo-services/drizzle@0.1.36(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.0)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.0)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.16.0(react-native@0.79.6(@babel/core@7.28.0)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.0)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.0)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(hono@4.9.8)(kysely@0.28.8)':
dependencies:
'@folo-services/exceptions': 0.1.20
'@folo-services/exceptions': 0.1.21
'@hono/zod-openapi': 1.1.4(hono@4.9.8)(zod@4.1.12)
drizzle-orm: 0.44.6(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.0)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.0)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.16.0(react-native@0.79.6(@babel/core@7.28.0)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.0)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.0)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(kysely@0.28.8)(pg@8.16.3)
drizzle-zod: 0.8.3(drizzle-orm@0.44.6(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.0)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.0)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.16.0(react-native@0.79.6(@babel/core@7.28.0)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.0)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.0)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(kysely@0.28.8)(pg@8.16.3))(zod@4.1.12)
@ -21715,9 +21685,9 @@ snapshots:
- sql.js
- sqlite3
'@folo-services/drizzle@0.1.35(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.4)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.4)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.15.0(react-native@0.79.6(@babel/core@7.28.4)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.4)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.4)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(hono@4.9.8)(kysely@0.28.8)':
'@folo-services/drizzle@0.1.36(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.4)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.4)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.15.0(react-native@0.79.6(@babel/core@7.28.4)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.4)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.4)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(hono@4.9.8)(kysely@0.28.8)':
dependencies:
'@folo-services/exceptions': 0.1.20
'@folo-services/exceptions': 0.1.21
'@hono/zod-openapi': 1.1.4(hono@4.9.8)(zod@4.1.12)
drizzle-orm: 0.44.6(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.4)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.4)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.15.0(react-native@0.79.6(@babel/core@7.28.4)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.4)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.4)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(kysely@0.28.8)(pg@8.16.3)
drizzle-zod: 0.8.3(drizzle-orm@0.44.6(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.4)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.4)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.15.0(react-native@0.79.6(@babel/core@7.28.4)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.4)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.4)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(kysely@0.28.8)(pg@8.16.3))(zod@4.1.12)
@ -21756,9 +21726,9 @@ snapshots:
- sql.js
- sqlite3
'@folo-services/drizzle@0.1.35(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.5)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.16.0(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5))(react@19.0.0)(utf-8-validate@6.0.5))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5))(react@19.0.0))(hono@4.9.8)(kysely@0.28.8)':
'@folo-services/drizzle@0.1.36(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.5)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.16.0(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5))(react@19.0.0)(utf-8-validate@6.0.5))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5))(react@19.0.0))(hono@4.9.8)(kysely@0.28.8)':
dependencies:
'@folo-services/exceptions': 0.1.20
'@folo-services/exceptions': 0.1.21
'@hono/zod-openapi': 1.1.4(hono@4.9.8)(zod@4.1.12)
drizzle-orm: 0.44.6(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.5)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.16.0(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5))(react@19.0.0)(utf-8-validate@6.0.5))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5))(react@19.0.0))(kysely@0.28.8)(pg@8.16.3)
drizzle-zod: 0.8.3(drizzle-orm@0.44.6(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.5)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.16.0(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5))(react@19.0.0)(utf-8-validate@6.0.5))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5))(react@19.0.0))(kysely@0.28.8)(pg@8.16.3))(zod@4.1.12)
@ -21797,9 +21767,9 @@ snapshots:
- sql.js
- sqlite3
'@folo-services/drizzle@0.1.35(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.5)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.16.0(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(hono@4.9.8)(kysely@0.28.8)':
'@folo-services/drizzle@0.1.36(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.5)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.16.0(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(hono@4.9.8)(kysely@0.28.8)':
dependencies:
'@folo-services/exceptions': 0.1.20
'@folo-services/exceptions': 0.1.21
'@hono/zod-openapi': 1.1.4(hono@4.9.8)(zod@4.1.12)
drizzle-orm: 0.44.6(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.5)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.16.0(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(kysely@0.28.8)(pg@8.16.3)
drizzle-zod: 0.8.3(drizzle-orm@0.44.6(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.5)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.16.0(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(kysely@0.28.8)(pg@8.16.3))(zod@4.1.12)
@ -21840,12 +21810,12 @@ snapshots:
'@folo-services/exceptions@0.1.19': {}
'@folo-services/exceptions@0.1.20': {}
'@folo-services/exceptions@0.1.21': {}
'@folo-services/shared@0.0.34(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.0)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.0)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.16.0(react-native@0.79.6(@babel/core@7.28.0)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.0)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.0)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(hono@4.9.8)(kysely@0.28.8)(pg@8.16.3)':
'@folo-services/shared@0.0.35(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.0)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.0)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.16.0(react-native@0.79.6(@babel/core@7.28.0)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.0)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.0)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(hono@4.9.8)(kysely@0.28.8)(pg@8.16.3)':
dependencies:
'@folo-services/constants': 0.1.41
'@folo-services/drizzle': 0.1.35(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.0)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.0)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.16.0(react-native@0.79.6(@babel/core@7.28.0)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.0)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.0)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(hono@4.9.8)(kysely@0.28.8)
'@folo-services/constants': 0.1.43
'@folo-services/drizzle': 0.1.36(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.0)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.0)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.16.0(react-native@0.79.6(@babel/core@7.28.0)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.0)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.0)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(hono@4.9.8)(kysely@0.28.8)
'@hono/zod-openapi': 1.1.4(hono@4.9.8)(zod@4.1.12)
drizzle-orm: 0.44.6(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.0)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.0)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.16.0(react-native@0.79.6(@babel/core@7.28.0)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.0)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.0)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(kysely@0.28.8)(pg@8.16.3)
drizzle-zod: 0.8.3(drizzle-orm@0.44.6(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.0)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.0)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.16.0(react-native@0.79.6(@babel/core@7.28.0)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.0)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.0)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(kysely@0.28.8)(pg@8.16.3))(zod@4.1.12)
@ -21883,10 +21853,10 @@ snapshots:
- sql.js
- sqlite3
'@folo-services/shared@0.0.34(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.4)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.4)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.15.0(react-native@0.79.6(@babel/core@7.28.4)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.4)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.4)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(hono@4.9.8)(kysely@0.28.8)(pg@8.16.3)':
'@folo-services/shared@0.0.35(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.4)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.4)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.15.0(react-native@0.79.6(@babel/core@7.28.4)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.4)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.4)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(hono@4.9.8)(kysely@0.28.8)(pg@8.16.3)':
dependencies:
'@folo-services/constants': 0.1.41
'@folo-services/drizzle': 0.1.35(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.4)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.4)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.15.0(react-native@0.79.6(@babel/core@7.28.4)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.4)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.4)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(hono@4.9.8)(kysely@0.28.8)
'@folo-services/constants': 0.1.43
'@folo-services/drizzle': 0.1.36(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.4)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.4)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.15.0(react-native@0.79.6(@babel/core@7.28.4)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.4)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.4)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(hono@4.9.8)(kysely@0.28.8)
'@hono/zod-openapi': 1.1.4(hono@4.9.8)(zod@4.1.12)
drizzle-orm: 0.44.6(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.4)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.4)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.15.0(react-native@0.79.6(@babel/core@7.28.4)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.4)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.4)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(kysely@0.28.8)(pg@8.16.3)
drizzle-zod: 0.8.3(drizzle-orm@0.44.6(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.4)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.4)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.15.0(react-native@0.79.6(@babel/core@7.28.4)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.4)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.4)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(kysely@0.28.8)(pg@8.16.3))(zod@4.1.12)
@ -21924,10 +21894,10 @@ snapshots:
- sql.js
- sqlite3
'@folo-services/shared@0.0.34(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.5)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.16.0(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5))(react@19.0.0)(utf-8-validate@6.0.5))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5))(react@19.0.0))(hono@4.9.8)(kysely@0.28.8)(pg@8.16.3)':
'@folo-services/shared@0.0.35(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.5)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.16.0(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5))(react@19.0.0)(utf-8-validate@6.0.5))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5))(react@19.0.0))(hono@4.9.8)(kysely@0.28.8)(pg@8.16.3)':
dependencies:
'@folo-services/constants': 0.1.41
'@folo-services/drizzle': 0.1.35(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.5)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.16.0(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5))(react@19.0.0)(utf-8-validate@6.0.5))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5))(react@19.0.0))(hono@4.9.8)(kysely@0.28.8)
'@folo-services/constants': 0.1.43
'@folo-services/drizzle': 0.1.36(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.5)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.16.0(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5))(react@19.0.0)(utf-8-validate@6.0.5))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5))(react@19.0.0))(hono@4.9.8)(kysely@0.28.8)
'@hono/zod-openapi': 1.1.4(hono@4.9.8)(zod@4.1.12)
drizzle-orm: 0.44.6(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.5)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.16.0(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5))(react@19.0.0)(utf-8-validate@6.0.5))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5))(react@19.0.0))(kysely@0.28.8)(pg@8.16.3)
drizzle-zod: 0.8.3(drizzle-orm@0.44.6(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.5)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.16.0(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5))(react@19.0.0)(utf-8-validate@6.0.5))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5))(react@19.0.0))(kysely@0.28.8)(pg@8.16.3))(zod@4.1.12)
@ -21965,10 +21935,10 @@ snapshots:
- sql.js
- sqlite3
'@folo-services/shared@0.0.34(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.5)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.16.0(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(hono@4.9.8)(kysely@0.28.8)(pg@8.16.3)':
'@folo-services/shared@0.0.35(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.5)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.16.0(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(hono@4.9.8)(kysely@0.28.8)(pg@8.16.3)':
dependencies:
'@folo-services/constants': 0.1.41
'@folo-services/drizzle': 0.1.35(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.5)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.16.0(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(hono@4.9.8)(kysely@0.28.8)
'@folo-services/constants': 0.1.43
'@folo-services/drizzle': 0.1.36(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.5)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.16.0(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(hono@4.9.8)(kysely@0.28.8)
'@hono/zod-openapi': 1.1.4(hono@4.9.8)(zod@4.1.12)
drizzle-orm: 0.44.6(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.5)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.16.0(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(kysely@0.28.8)(pg@8.16.3)
drizzle-zod: 0.8.3(drizzle-orm@0.44.6(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.5)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.16.0(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(kysely@0.28.8)(pg@8.16.3))(zod@4.1.12)
@ -22732,13 +22702,6 @@ snapshots:
'@tybys/wasm-util': 0.10.1
optional: true
'@napi-rs/wasm-runtime@1.0.7':
dependencies:
'@emnapi/core': 1.6.0
'@emnapi/runtime': 1.6.0
'@tybys/wasm-util': 0.10.1
optional: true
'@noble/ciphers@2.0.1': {}
'@noble/hashes@2.0.1': {}
@ -23212,7 +23175,9 @@ snapshots:
'@opentelemetry/api': 1.9.0
'@opentelemetry/core': 2.1.0(@opentelemetry/api@1.9.0)
'@oxc-project/types@0.95.0': {}
'@oxc-project/runtime@0.71.0': {}
'@oxc-project/types@0.71.0': {}
'@peculiar/asn1-android@2.5.0':
dependencies:
@ -24368,7 +24333,7 @@ snapshots:
debug: 2.6.9
invariant: 2.2.4
metro: 0.82.4(bufferutil@4.0.9)(utf-8-validate@6.0.5)
metro-config: 0.82.4(bufferutil@4.0.9)(utf-8-validate@6.0.5)
metro-config: 0.82.4(bufferutil@4.0.9)
metro-core: 0.82.4
semver: 7.7.3
transitivePeerDependencies:
@ -24535,53 +24500,47 @@ snapshots:
'@resvg/resvg-js-win32-ia32-msvc': 2.6.2
'@resvg/resvg-js-win32-x64-msvc': 2.6.2
'@rolldown/binding-android-arm64@1.0.0-beta.45':
'@rolldown/binding-darwin-arm64@1.0.0-beta.9-commit.d91dfb5':
optional: true
'@rolldown/binding-darwin-arm64@1.0.0-beta.45':
'@rolldown/binding-darwin-x64@1.0.0-beta.9-commit.d91dfb5':
optional: true
'@rolldown/binding-darwin-x64@1.0.0-beta.45':
'@rolldown/binding-freebsd-x64@1.0.0-beta.9-commit.d91dfb5':
optional: true
'@rolldown/binding-freebsd-x64@1.0.0-beta.45':
'@rolldown/binding-linux-arm-gnueabihf@1.0.0-beta.9-commit.d91dfb5':
optional: true
'@rolldown/binding-linux-arm-gnueabihf@1.0.0-beta.45':
'@rolldown/binding-linux-arm64-gnu@1.0.0-beta.9-commit.d91dfb5':
optional: true
'@rolldown/binding-linux-arm64-gnu@1.0.0-beta.45':
'@rolldown/binding-linux-arm64-musl@1.0.0-beta.9-commit.d91dfb5':
optional: true
'@rolldown/binding-linux-arm64-musl@1.0.0-beta.45':
'@rolldown/binding-linux-x64-gnu@1.0.0-beta.9-commit.d91dfb5':
optional: true
'@rolldown/binding-linux-x64-gnu@1.0.0-beta.45':
'@rolldown/binding-linux-x64-musl@1.0.0-beta.9-commit.d91dfb5':
optional: true
'@rolldown/binding-linux-x64-musl@1.0.0-beta.45':
optional: true
'@rolldown/binding-openharmony-arm64@1.0.0-beta.45':
optional: true
'@rolldown/binding-wasm32-wasi@1.0.0-beta.45':
'@rolldown/binding-wasm32-wasi@1.0.0-beta.9-commit.d91dfb5':
dependencies:
'@napi-rs/wasm-runtime': 1.0.7
'@napi-rs/wasm-runtime': 0.2.12
optional: true
'@rolldown/binding-win32-arm64-msvc@1.0.0-beta.45':
'@rolldown/binding-win32-arm64-msvc@1.0.0-beta.9-commit.d91dfb5':
optional: true
'@rolldown/binding-win32-ia32-msvc@1.0.0-beta.45':
'@rolldown/binding-win32-ia32-msvc@1.0.0-beta.9-commit.d91dfb5':
optional: true
'@rolldown/binding-win32-x64-msvc@1.0.0-beta.45':
'@rolldown/binding-win32-x64-msvc@1.0.0-beta.9-commit.d91dfb5':
optional: true
'@rolldown/pluginutils@1.0.0-beta.38': {}
'@rolldown/pluginutils@1.0.0-beta.45': {}
'@rolldown/pluginutils@1.0.0-beta.9-commit.d91dfb5': {}
'@rollup/plugin-babel@5.3.1(@babel/core@7.28.4)(@types/babel__core@7.20.5)(rollup@2.79.2)':
dependencies:
@ -32503,22 +32462,6 @@ snapshots:
- supports-color
- utf-8-validate
metro-config@0.82.4(bufferutil@4.0.9)(utf-8-validate@6.0.5):
dependencies:
connect: 3.7.0
cosmiconfig: 5.2.1
flow-enums-runtime: 0.0.6
jest-validate: 29.7.0
metro: 0.82.4(bufferutil@4.0.9)(utf-8-validate@6.0.5)
metro-cache: 0.82.4
metro-core: 0.82.4
metro-runtime: 0.82.4
transitivePeerDependencies:
- bufferutil
- supports-color
- utf-8-validate
optional: true
metro-core@0.82.4:
dependencies:
flow-enums-runtime: 0.0.6
@ -32704,7 +32647,7 @@ snapshots:
metro-babel-transformer: 0.82.4
metro-cache: 0.82.4
metro-cache-key: 0.82.4
metro-config: 0.82.4(bufferutil@4.0.9)(utf-8-validate@6.0.5)
metro-config: 0.82.4(bufferutil@4.0.9)
metro-core: 0.82.4
metro-file-map: 0.82.4
metro-resolver: 0.82.4
@ -35274,7 +35217,7 @@ snapshots:
sprintf-js: 1.1.3
optional: true
rolldown-plugin-dts@0.16.12(rolldown@1.0.0-beta.45)(typescript@5.9.3):
rolldown-plugin-dts@0.16.12(rolldown@1.0.0-beta.9-commit.d91dfb5)(typescript@5.9.3):
dependencies:
'@babel/generator': 7.28.3
'@babel/parser': 7.28.4
@ -35285,32 +35228,32 @@ snapshots:
dts-resolver: 2.1.2
get-tsconfig: 4.12.0
magic-string: 0.30.19
rolldown: 1.0.0-beta.45
rolldown: 1.0.0-beta.9-commit.d91dfb5
optionalDependencies:
typescript: 5.9.3
transitivePeerDependencies:
- oxc-resolver
- supports-color
rolldown@1.0.0-beta.45:
rolldown@1.0.0-beta.9-commit.d91dfb5:
dependencies:
'@oxc-project/types': 0.95.0
'@rolldown/pluginutils': 1.0.0-beta.45
'@oxc-project/runtime': 0.71.0
'@oxc-project/types': 0.71.0
'@rolldown/pluginutils': 1.0.0-beta.9-commit.d91dfb5
ansis: 4.2.0
optionalDependencies:
'@rolldown/binding-android-arm64': 1.0.0-beta.45
'@rolldown/binding-darwin-arm64': 1.0.0-beta.45
'@rolldown/binding-darwin-x64': 1.0.0-beta.45
'@rolldown/binding-freebsd-x64': 1.0.0-beta.45
'@rolldown/binding-linux-arm-gnueabihf': 1.0.0-beta.45
'@rolldown/binding-linux-arm64-gnu': 1.0.0-beta.45
'@rolldown/binding-linux-arm64-musl': 1.0.0-beta.45
'@rolldown/binding-linux-x64-gnu': 1.0.0-beta.45
'@rolldown/binding-linux-x64-musl': 1.0.0-beta.45
'@rolldown/binding-openharmony-arm64': 1.0.0-beta.45
'@rolldown/binding-wasm32-wasi': 1.0.0-beta.45
'@rolldown/binding-win32-arm64-msvc': 1.0.0-beta.45
'@rolldown/binding-win32-ia32-msvc': 1.0.0-beta.45
'@rolldown/binding-win32-x64-msvc': 1.0.0-beta.45
'@rolldown/binding-darwin-arm64': 1.0.0-beta.9-commit.d91dfb5
'@rolldown/binding-darwin-x64': 1.0.0-beta.9-commit.d91dfb5
'@rolldown/binding-freebsd-x64': 1.0.0-beta.9-commit.d91dfb5
'@rolldown/binding-linux-arm-gnueabihf': 1.0.0-beta.9-commit.d91dfb5
'@rolldown/binding-linux-arm64-gnu': 1.0.0-beta.9-commit.d91dfb5
'@rolldown/binding-linux-arm64-musl': 1.0.0-beta.9-commit.d91dfb5
'@rolldown/binding-linux-x64-gnu': 1.0.0-beta.9-commit.d91dfb5
'@rolldown/binding-linux-x64-musl': 1.0.0-beta.9-commit.d91dfb5
'@rolldown/binding-wasm32-wasi': 1.0.0-beta.9-commit.d91dfb5
'@rolldown/binding-win32-arm64-msvc': 1.0.0-beta.9-commit.d91dfb5
'@rolldown/binding-win32-ia32-msvc': 1.0.0-beta.9-commit.d91dfb5
'@rolldown/binding-win32-x64-msvc': 1.0.0-beta.9-commit.d91dfb5
rollup@2.79.2:
optionalDependencies:
@ -36441,8 +36384,8 @@ snapshots:
diff: 8.0.2
empathic: 2.0.0
hookable: 5.5.3
rolldown: 1.0.0-beta.45
rolldown-plugin-dts: 0.16.12(rolldown@1.0.0-beta.45)(typescript@5.9.3)
rolldown: 1.0.0-beta.9-commit.d91dfb5
rolldown-plugin-dts: 0.16.12(rolldown@1.0.0-beta.9-commit.d91dfb5)(typescript@5.9.3)
semver: 7.7.3
tinyexec: 1.0.1
tinyglobby: 0.2.15

View File

@ -8,7 +8,7 @@ packages:
- "!**/example/**"
catalog:
"@follow-app/client-sdk": 0.3.78
"@follow-app/client-sdk": 0.3.79
tailwindcss-uikit-colors: 1.0.0
typescript: 5.9.3