From 39514b9a4043401605bc3952585f558bcca69d2a Mon Sep 17 00:00:00 2001 From: Adam Spofford Date: Wed, 20 May 2026 14:10:57 -0700 Subject: [PATCH 1/4] Allow specifying PIC server version --- packages/pic/postinstall.mjs | 44 ++++++++++++++++++++++++++++++++---- 1 file changed, 39 insertions(+), 5 deletions(-) diff --git a/packages/pic/postinstall.mjs b/packages/pic/postinstall.mjs index abbab7f..ac1e075 100644 --- a/packages/pic/postinstall.mjs +++ b/packages/pic/postinstall.mjs @@ -1,5 +1,5 @@ -import { chmodSync, createWriteStream } from 'node:fs'; -import { resolve, dirname } from 'node:path'; +import { chmodSync, createWriteStream, readFileSync } from 'node:fs'; +import { resolve, dirname, join } from 'node:path'; import { pipeline } from 'node:stream/promises'; import { createGunzip } from 'node:zlib'; import { fileURLToPath } from 'node:url'; @@ -9,13 +9,47 @@ const __dirname = dirname(__filename); const IS_LINUX = process.platform === 'linux'; const PLATFORM = IS_LINUX ? 'x86_64-linux' : 'x86_64-darwin'; -const VERSION = '13.0.0'; -const DOWNLOAD_PATH = `https://github.com/dfinity/pocketic/releases/download/${VERSION}/pocket-ic-${PLATFORM}.gz`; +const DEFAULT_VERSION = 'package:13.0.0'; const TARGET_PATH = resolve(__dirname, 'pocket-ic'); +function resolveDownloadUrl() { + // INIT_CWD is set by npm/pnpm/yarn to the directory where install was invoked, + // i.e. the dependent project root where .pocket-ic-version would live. + const projectRoot = process.env.INIT_CWD ?? process.cwd(); + const versionFilePath = join(projectRoot, '.pocket-ic-version'); + + let versionSpec = DEFAULT_VERSION; + try { + versionSpec = readFileSync(versionFilePath, 'utf8').trim(); + } catch { + // No version file; use default. + } + + const colonIdx = versionSpec.indexOf(':'); + if (colonIdx === -1) { + throw new Error( + `.pocket-ic-version: invalid format "${versionSpec}". Expected "package:" or "ic:".`, + ); + } + + const source = versionSpec.slice(0, colonIdx); + const version = versionSpec.slice(colonIdx + 1); + + if (source === 'package') { + return `https://github.com/dfinity/pocketic/releases/download/${version}/pocket-ic-${PLATFORM}.gz`; + } else if (source === 'ic') { + return `https://github.com/dfinity/ic/releases/download/${version}/pocket-ic-${PLATFORM}.gz`; + } else { + throw new Error( + `.pocket-ic-version: unknown source "${source}". Expected "package" or "ic".`, + ); + } +} + async function downloadPicBinary() { - const response = await fetch(DOWNLOAD_PATH); + const downloadUrl = resolveDownloadUrl(); + const response = await fetch(downloadUrl); await pipeline(response.body, createGunzip(), createWriteStream(TARGET_PATH)); From ff05bd90a4731b010a76ebffdeea2f045afd9bb2 Mon Sep 17 00:00:00 2001 From: Adam Spofford <93943719+adamspofford-dfinity@users.noreply.github.com> Date: Thu, 21 May 2026 08:39:13 -0700 Subject: [PATCH 2/4] Rethrow errors Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- packages/pic/postinstall.mjs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/pic/postinstall.mjs b/packages/pic/postinstall.mjs index ac1e075..a6450a1 100644 --- a/packages/pic/postinstall.mjs +++ b/packages/pic/postinstall.mjs @@ -22,7 +22,10 @@ function resolveDownloadUrl() { let versionSpec = DEFAULT_VERSION; try { versionSpec = readFileSync(versionFilePath, 'utf8').trim(); - } catch { + } catch (error) { + if (error?.code !== 'ENOENT') { + throw error; + } // No version file; use default. } From 7c3a4c561a940d8758fb27bbb60f1a576493d5e1 Mon Sep 17 00:00:00 2001 From: Adam Spofford <93943719+adamspofford-dfinity@users.noreply.github.com> Date: Thu, 21 May 2026 08:40:59 -0700 Subject: [PATCH 3/4] handle fetch failing Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- packages/pic/postinstall.mjs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/packages/pic/postinstall.mjs b/packages/pic/postinstall.mjs index a6450a1..80fde29 100644 --- a/packages/pic/postinstall.mjs +++ b/packages/pic/postinstall.mjs @@ -54,6 +54,18 @@ async function downloadPicBinary() { const downloadUrl = resolveDownloadUrl(); const response = await fetch(downloadUrl); + if (!response.ok) { + throw new Error( + `Failed to download pocket-ic from ${downloadUrl}: HTTP ${response.status} ${response.statusText}`, + ); + } + + if (!response.body) { + throw new Error( + `Failed to download pocket-ic from ${downloadUrl}: response body is empty`, + ); + } + await pipeline(response.body, createGunzip(), createWriteStream(TARGET_PATH)); chmodSync(TARGET_PATH, 0o700); From 71e14b62766de14430263435c277fa25b13419a2 Mon Sep 17 00:00:00 2001 From: Adam Spofford Date: Fri, 5 Jun 2026 10:43:47 -0700 Subject: [PATCH 4/4] guard against empty --- packages/pic/postinstall.mjs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/packages/pic/postinstall.mjs b/packages/pic/postinstall.mjs index 80fde29..6267656 100644 --- a/packages/pic/postinstall.mjs +++ b/packages/pic/postinstall.mjs @@ -37,7 +37,13 @@ function resolveDownloadUrl() { } const source = versionSpec.slice(0, colonIdx); - const version = versionSpec.slice(colonIdx + 1); + const version = versionSpec.slice(colonIdx + 1).trim(); + + if (!version) { + throw new Error( + `.pocket-ic-version: missing version in "${versionSpec}". Expected "package:" or "ic:".`, + ); + } if (source === 'package') { return `https://github.com/dfinity/pocketic/releases/download/${version}/pocket-ic-${PLATFORM}.gz`;