From ffde8e07dbf37509bd5722c92962919dbfe4a7e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Iv=C3=A1n=20Vieitez=20Parra?= <3857362+corrideat@users.noreply.github.com> Date: Thu, 2 Apr 2026 18:45:42 +0000 Subject: [PATCH 01/13] Report version from manifest --- src/pin.ts | 19 ++++++++++--------- src/serve/server.ts | 19 +++++++++++++++---- 2 files changed, 25 insertions(+), 13 deletions(-) diff --git a/src/pin.ts b/src/pin.ts index 20c40e5..4f8f69a 100644 --- a/src/pin.ts +++ b/src/pin.ts @@ -36,8 +36,8 @@ export async function pin (args: ArgumentsCamelCase): Promise { exit(`Manifest file not found: ${manifestPath}`) } - const { contractName, contractFiles, manifestVersion } = await parseManifest(fullManifestPath) - console.log(colors.blue(`Contract name: ${contractName}`)) + const { contractName, fullContractName, contractFiles, manifestVersion } = await parseManifest(fullManifestPath) + console.log(colors.blue(`Contract name: ${fullContractName}`)) console.log(colors.blue(`Manifest version: ${manifestVersion}`)) if (version) { @@ -50,31 +50,31 @@ export async function pin (args: ArgumentsCamelCase): Promise { console.log(colors.green(`✅ Version validation passed: ${version}`)) } - const currentPinnedVersion = cheloniaConfig.contracts[contractName]?.version + const currentPinnedVersion = cheloniaConfig.contracts[fullContractName]?.version if (currentPinnedVersion === manifestVersion) { - console.log(colors.yellow(`✨ Contract ${contractName} is already pinned to version ${manifestVersion} - no action needed`)) + console.log(colors.yellow(`✨ Contract ${fullContractName} is already pinned to version ${manifestVersion} - no action needed`)) return } if (currentPinnedVersion) { - console.log(colors.cyan(`📌 Updating ${contractName} from version ${currentPinnedVersion} to ${manifestVersion}`)) + console.log(colors.cyan(`📌 Updating ${fullContractName} from version ${currentPinnedVersion} to ${manifestVersion}`)) } else { - console.log(colors.cyan(`📌 Pinning ${contractName} to version ${manifestVersion} (first time)`)) + console.log(colors.cyan(`📌 Pinning ${fullContractName} to version ${manifestVersion} (first time)`)) } const contractVersionDir = join(projectRoot, 'contracts', contractName, manifestVersion) if (existsSync(contractVersionDir)) { if (!args.overwrite) { - exit(`Version ${manifestVersion} already exists for contract ${contractName}. Use --overwrite to replace it.`) + exit(`Version ${manifestVersion} already exists for contract ${fullContractName}. Use --overwrite to replace it.`) } - console.log(colors.yellow(`Version ${manifestVersion} already exists for ${contractName} - checking files...`)) + console.log(colors.yellow(`Version ${manifestVersion} already exists for ${fullContractName} - checking files...`)) } else { await createVersionDirectory(contractName, manifestVersion) } await copyContractFiles(contractFiles, manifestPath, contractName, manifestVersion, args) - await updateCheloniaConfig(contractName, manifestVersion, manifestPath) + await updateCheloniaConfig(fullContractName, manifestVersion, manifestPath) console.log(colors.green(`✅ Successfully pinned ${contractName} to version ${version}`)) console.log(colors.gray(`Location: contracts/${contractName}/${manifestVersion}/`)) @@ -103,6 +103,7 @@ async function parseManifest (manifestPath: string) { return { contractName, manifestVersion, + fullContractName, contractFiles: { main: mainFile, slim: slimFile diff --git a/src/serve/server.ts b/src/serve/server.ts index b46e64d..0127ecb 100644 --- a/src/serve/server.ts +++ b/src/serve/server.ts @@ -34,6 +34,16 @@ import { addChannelToSubscription, deleteChannelFromSubscription, postEvent, pus // @deno-types="npm:@types/nconf" import nconf from 'npm:nconf' +const cheloniaAppManifest = await (async () => { + try { + return await import(join(process.cwd(), 'chelonia.json'), { + with: { type: 'json' } + }) + } catch { + console.warn('`chelonia.json` not found. Version information will be unavailable.') + } +})() + const ARCHIVE_MODE = nconf.get('server:archiveMode') if (CREDITS_WORKER_TASK_TIME_INTERVAL && OWNER_SIZE_TOTAL_WORKER_TASK_TIME_INTERVAL > CREDITS_WORKER_TASK_TIME_INTERVAL) { @@ -49,8 +59,6 @@ const creditsWorker = ARCHIVE_MODE || !CREDITS_WORKER_TASK_TIME_INTERVAL ? undefined : createWorker(join(import.meta.dirname || '.', import.meta.workerDir || '.', 'creditsWorker.js')) -const { CONTRACTS_VERSION, GI_VERSION } = process.env - // Dynamic runtime import to bypass bundling issues with npm: specifier const hapi = new Hapi.Server({ // debug: false, // <- Hapi v16 was outputing too many unnecessary debug statements @@ -426,8 +434,11 @@ sbp('okTurtles.data/set', PUBSUB_INSTANCE, createServer(hapi.listener, { serverHandlers: { connection (socket) { const versionInfo = { - GI_VERSION: GI_VERSION || null, - CONTRACTS_VERSION: CONTRACTS_VERSION || null + appVersion: cheloniaAppManifest?.appVersion || null, + contractsVersion: Object.fromEntries( + Object.entries(cheloniaAppManifest?.contracts || {}) + .map(([k, v]) => [k, (v as Record).version]) + ) } socket.send(createNotification(NOTIFICATION_TYPE.VERSION_INFO, versionInfo)) } From cbee166efad2a4450f29dac2e7f56b88d29d1521 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Iv=C3=A1n=20Vieitez=20Parra?= <3857362+corrideat@users.noreply.github.com> Date: Thu, 2 Apr 2026 18:59:14 +0000 Subject: [PATCH 02/13] Updates --- src/serve/server.ts | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/serve/server.ts b/src/serve/server.ts index 0127ecb..ae5b29e 100644 --- a/src/serve/server.ts +++ b/src/serve/server.ts @@ -31,14 +31,15 @@ import { type WSS } from './pubsub.ts' import { addChannelToSubscription, deleteChannelFromSubscription, postEvent, pushServerActionhandlers, subscriptionInfoWrapper } from './push.ts' +import { pathToFileURL } from 'node:url' // @deno-types="npm:@types/nconf" import nconf from 'npm:nconf' const cheloniaAppManifest = await (async () => { try { - return await import(join(process.cwd(), 'chelonia.json'), { + return (await import(pathToFileURL(join(process.cwd(), 'chelonia.json')).toString(), { with: { type: 'json' } - }) + })).default } catch { console.warn('`chelonia.json` not found. Version information will be unavailable.') } @@ -435,10 +436,10 @@ sbp('okTurtles.data/set', PUBSUB_INSTANCE, createServer(hapi.listener, { connection (socket) { const versionInfo = { appVersion: cheloniaAppManifest?.appVersion || null, - contractsVersion: Object.fromEntries( - Object.entries(cheloniaAppManifest?.contracts || {}) + contractsVersion: cheloniaAppManifest?.contracts ? Object.fromEntries( + Object.entries(cheloniaAppManifest?.contracts) .map(([k, v]) => [k, (v as Record).version]) - ) + ) : null } socket.send(createNotification(NOTIFICATION_TYPE.VERSION_INFO, versionInfo)) } From 93eba67b8894ba818520056d6e83ee8a74f74507 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Iv=C3=A1n=20Vieitez=20Parra?= <3857362+corrideat@users.noreply.github.com> Date: Mon, 13 Apr 2026 12:47:41 -0400 Subject: [PATCH 03/13] build --- build/main.js | 51 ++++++++++++++++++----------- build/serve/creditsWorker.js | 4 +-- build/serve/ownerSizeTotalWorker.js | 4 +-- 3 files changed, 35 insertions(+), 24 deletions(-) diff --git a/build/main.js b/build/main.js index b00c4b7..2cf0783 100644 --- a/build/main.js +++ b/build/main.js @@ -1,6 +1,6 @@ #!/usr/bin/env -S deno run --allow-net --allow-read=. --allow-write=. --allow-sys --allow-env -import { createRequire as __deno_internal_createRequire } from "node:module"; -var __require = __deno_internal_createRequire(import.meta.url); +import { createRequire } from "node:module"; +var __require = createRequire(import.meta.url); // build/main.js-tmp @@ -3094,6 +3094,7 @@ import path6 from "node:path"; import process9 from "node:process"; import { join as join72 } from "node:path"; import process10 from "node:process"; +import { pathToFileURL } from "node:url"; import process11 from "node:process"; import process13 from "node:process"; @@ -87653,7 +87654,7 @@ var require_thread_stream = __commonJS({ var { EventEmitter } = __require2("events"); var { Worker: Worker2 } = __require2("worker_threads"); var { join: join92 } = __require2("path"); - var { pathToFileURL } = __require2("url"); + var { pathToFileURL: pathToFileURL2 } = __require2("url"); var { wait } = require_wait2(); var { WRITE_INDEX, @@ -87693,7 +87694,7 @@ var require_thread_stream = __commonJS({ ...opts.workerOpts, trackUnmanagedFds: false, workerData: { - filename: filename.indexOf("file://") === 0 ? filename : pathToFileURL(filename).href, + filename: filename.indexOf("file://") === 0 ? filename : pathToFileURL2(filename).href, dataBuf: stream[kImpl].dataBuf, stateBuf: stream[kImpl].stateBuf, workerData: { @@ -108555,15 +108556,14 @@ var Hapi2; var import_inert2; var import_npm_chalk3; var import_npm_nconf6; +var cheloniaAppManifest; var ARCHIVE_MODE2; var ownerSizeTotalWorker; var creditsWorker; -var CONTRACTS_VERSION; -var GI_VERSION; var hapi; var appendToOrphanedNamesIndex; var init_server = __esm({ - "src/serve/server.ts"() { + async "src/serve/server.ts"() { "use strict"; init_SPMessage(); init_chelonia(); @@ -108585,6 +108585,15 @@ var init_server = __esm({ init_pubsub2(); init_push(); import_npm_nconf6 = __toESM(require_nconf()); + cheloniaAppManifest = await (async () => { + try { + return (await import(pathToFileURL(join72(process10.cwd(), "chelonia.json")).toString(), { + with: { type: "json" } + })).default; + } catch { + console.warn("`chelonia.json` not found. Version information will be unavailable."); + } + })(); ARCHIVE_MODE2 = import_npm_nconf6.default.get("server:archiveMode"); if (CREDITS_WORKER_TASK_TIME_INTERVAL && OWNER_SIZE_TOTAL_WORKER_TASK_TIME_INTERVAL > CREDITS_WORKER_TASK_TIME_INTERVAL) { process10.stderr.write("The size calculation worker must run more frequently than the credits worker for accurate billing"); @@ -108592,7 +108601,6 @@ var init_server = __esm({ } ownerSizeTotalWorker = ARCHIVE_MODE2 || !OWNER_SIZE_TOTAL_WORKER_TASK_TIME_INTERVAL ? void 0 : createWorker_default(join72(import.meta.dirname || ".", "serve", "ownerSizeTotalWorker.js")); creditsWorker = ARCHIVE_MODE2 || !CREDITS_WORKER_TASK_TIME_INTERVAL ? void 0 : createWorker_default(join72(import.meta.dirname || ".", "serve", "creditsWorker.js")); - ({ CONTRACTS_VERSION, GI_VERSION } = process10.env); hapi = new Hapi2.Server({ // debug: false, // <- Hapi v16 was outputing too many unnecessary debug statements // // v17 doesn't seem to do this anymore so I've re-enabled the logging @@ -108874,8 +108882,10 @@ var init_server = __esm({ serverHandlers: { connection(socket) { const versionInfo = { - GI_VERSION: GI_VERSION || null, - CONTRACTS_VERSION: CONTRACTS_VERSION || null + appVersion: cheloniaAppManifest?.appVersion || null, + contractsVersion: cheloniaAppManifest?.contracts ? Object.fromEntries( + Object.entries(cheloniaAppManifest?.contracts).map(([k, v2]) => [k, v2.version]) + ) : null }; socket.send(createNotification(NOTIFICATION_TYPE.VERSION_INFO, versionInfo)); } @@ -109074,7 +109084,7 @@ var init_serve = __esm({ console.info(import_npm_chalk4.default.bold("backend startup sequence complete.")); resolve82(); }); - Promise.resolve().then(() => (init_server(), server_exports)).catch(reject); + init_server().then(() => server_exports).catch(reject); }); esm_default("okTurtles.events/once", SERVER_EXITING, () => { esm_default("okTurtles.data/apply", PUBSUB_INSTANCE, function(pubsub) { @@ -110628,8 +110638,8 @@ async function pin(args) { if (!existsSync(fullManifestPath)) { exit(`Manifest file not found: ${manifestPath}`); } - const { contractName, contractFiles, manifestVersion } = await parseManifest(fullManifestPath); - console.log(blue(`Contract name: ${contractName}`)); + const { contractName, fullContractName, contractFiles, manifestVersion } = await parseManifest(fullManifestPath); + console.log(blue(`Contract name: ${fullContractName}`)); console.log(blue(`Manifest version: ${manifestVersion}`)); if (version3) { if (version3 !== manifestVersion) { @@ -110639,27 +110649,27 @@ async function pin(args) { } console.log(green(`\u2705 Version validation passed: ${version3}`)); } - const currentPinnedVersion = cheloniaConfig.contracts[contractName]?.version; + const currentPinnedVersion = cheloniaConfig.contracts[fullContractName]?.version; if (currentPinnedVersion === manifestVersion) { - console.log(yellow(`\u2728 Contract ${contractName} is already pinned to version ${manifestVersion} - no action needed`)); + console.log(yellow(`\u2728 Contract ${fullContractName} is already pinned to version ${manifestVersion} - no action needed`)); return; } if (currentPinnedVersion) { - console.log(cyan(`\u{1F4CC} Updating ${contractName} from version ${currentPinnedVersion} to ${manifestVersion}`)); + console.log(cyan(`\u{1F4CC} Updating ${fullContractName} from version ${currentPinnedVersion} to ${manifestVersion}`)); } else { - console.log(cyan(`\u{1F4CC} Pinning ${contractName} to version ${manifestVersion} (first time)`)); + console.log(cyan(`\u{1F4CC} Pinning ${fullContractName} to version ${manifestVersion} (first time)`)); } const contractVersionDir = join62(projectRoot, "contracts", contractName, manifestVersion); if (existsSync(contractVersionDir)) { if (!args.overwrite) { - exit(`Version ${manifestVersion} already exists for contract ${contractName}. Use --overwrite to replace it.`); + exit(`Version ${manifestVersion} already exists for contract ${fullContractName}. Use --overwrite to replace it.`); } - console.log(yellow(`Version ${manifestVersion} already exists for ${contractName} - checking files...`)); + console.log(yellow(`Version ${manifestVersion} already exists for ${fullContractName} - checking files...`)); } else { await createVersionDirectory(contractName, manifestVersion); } await copyContractFiles(contractFiles, manifestPath, contractName, manifestVersion, args); - await updateCheloniaConfig(contractName, manifestVersion, manifestPath); + await updateCheloniaConfig(fullContractName, manifestVersion, manifestPath); console.log(green(`\u2705 Successfully pinned ${contractName} to version ${version3}`)); console.log(gray(`Location: contracts/${contractName}/${manifestVersion}/`)); } catch (error2) { @@ -110682,6 +110692,7 @@ async function parseManifest(manifestPath) { return { contractName, manifestVersion, + fullContractName, contractFiles: { main: mainFile, slim: slimFile diff --git a/build/serve/creditsWorker.js b/build/serve/creditsWorker.js index 814a512..7b2d5ed 100644 --- a/build/serve/creditsWorker.js +++ b/build/serve/creditsWorker.js @@ -1,5 +1,5 @@ -import { createRequire as __deno_internal_createRequire } from "node:module"; -var __require = __deno_internal_createRequire(import.meta.url); +import { createRequire } from "node:module"; +var __require = createRequire(import.meta.url); // build/serve/creditsWorker.js-tmp diff --git a/build/serve/ownerSizeTotalWorker.js b/build/serve/ownerSizeTotalWorker.js index deaef25..ec3e39a 100644 --- a/build/serve/ownerSizeTotalWorker.js +++ b/build/serve/ownerSizeTotalWorker.js @@ -1,5 +1,5 @@ -import { createRequire as __deno_internal_createRequire } from "node:module"; -var __require = __deno_internal_createRequire(import.meta.url); +import { createRequire } from "node:module"; +var __require = createRequire(import.meta.url); // build/serve/ownerSizeTotalWorker.js-tmp From 1f4a5285e12294458e79196f8cfc72c476ea0399 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Iv=C3=A1n=20Vieitez=20Parra?= <3857362+corrideat@users.noreply.github.com> Date: Wed, 15 Apr 2026 21:35:06 -0400 Subject: [PATCH 04/13] Feedback --- src/pin.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/pin.ts b/src/pin.ts index 4f8f69a..e7acd2a 100644 --- a/src/pin.ts +++ b/src/pin.ts @@ -74,9 +74,9 @@ export async function pin (args: ArgumentsCamelCase): Promise { } await copyContractFiles(contractFiles, manifestPath, contractName, manifestVersion, args) - await updateCheloniaConfig(fullContractName, manifestVersion, manifestPath) + await updateCheloniaConfig(fullContractName, contractName, manifestVersion, manifestPath) - console.log(colors.green(`✅ Successfully pinned ${contractName} to version ${version}`)) + console.log(colors.green(`✅ Successfully pinned ${contractName} to version ${manifestVersion}`)) console.log(colors.gray(`Location: contracts/${contractName}/${manifestVersion}/`)) } catch (error) { exit(error) @@ -196,11 +196,11 @@ async function loadCheloniaConfig () { } } -async function updateCheloniaConfig (contractName: string, version: string, manifestPath: string) { +async function updateCheloniaConfig (fullContractName: string, contractName: string, version: string, manifestPath: string) { const manifestFileName = basename(manifestPath) const pinnedManifestPath = `contracts/${contractName}/${version}/${manifestFileName}` - cheloniaConfig.contracts[contractName] = { + cheloniaConfig.contracts[fullContractName] = { version, path: pinnedManifestPath } From 4ad9ee80ff88ce7b637c97789b56219f596d6d74 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Iv=C3=A1n=20Vieitez=20Parra?= <3857362+corrideat@users.noreply.github.com> Date: Wed, 15 Apr 2026 21:39:05 -0400 Subject: [PATCH 05/13] Updates --- build/main.js | 18 +++++++++++------- build/serve/creditsWorker.js | 4 ++-- build/serve/ownerSizeTotalWorker.js | 4 ++-- src/pin.ts | 9 ++++++++- 4 files changed, 23 insertions(+), 12 deletions(-) diff --git a/build/main.js b/build/main.js index 2cf0783..9284657 100644 --- a/build/main.js +++ b/build/main.js @@ -1,6 +1,6 @@ #!/usr/bin/env -S deno run --allow-net --allow-read=. --allow-write=. --allow-sys --allow-env -import { createRequire } from "node:module"; -var __require = createRequire(import.meta.url); +import { createRequire as __deno_internal_createRequire } from "node:module"; +var __require = __deno_internal_createRequire(import.meta.url); // build/main.js-tmp @@ -110617,10 +110617,11 @@ var module9 = { return migrate(argv); } }; +var RESERVED_FILE_CHARS = /[/\\:*?"<>|]/g; var projectRoot; var cheloniaConfig; function sanitizeContractName(contractName) { - return contractName.replace(/[/\\:*?"<>|]/g, "_").replace(/\.\./g, "__"); + return contractName.replace(RESERVED_FILE_CHARS, "_").replace(/\.\./g, "__"); } async function pin(args) { const version3 = args["manifest-version"]; @@ -110639,6 +110640,9 @@ async function pin(args) { exit(`Manifest file not found: ${manifestPath}`); } const { contractName, fullContractName, contractFiles, manifestVersion } = await parseManifest(fullManifestPath); + if (RESERVED_FILE_CHARS.test(manifestVersion)) { + exit(`Invalid manifest version: ${manifestVersion}`); + } console.log(blue(`Contract name: ${fullContractName}`)); console.log(blue(`Manifest version: ${manifestVersion}`)); if (version3) { @@ -110669,8 +110673,8 @@ async function pin(args) { await createVersionDirectory(contractName, manifestVersion); } await copyContractFiles(contractFiles, manifestPath, contractName, manifestVersion, args); - await updateCheloniaConfig(fullContractName, manifestVersion, manifestPath); - console.log(green(`\u2705 Successfully pinned ${contractName} to version ${version3}`)); + await updateCheloniaConfig(fullContractName, contractName, manifestVersion, manifestPath); + console.log(green(`\u2705 Successfully pinned ${contractName} to version ${manifestVersion}`)); console.log(gray(`Location: contracts/${contractName}/${manifestVersion}/`)); } catch (error2) { exit(error2); @@ -110757,10 +110761,10 @@ async function loadCheloniaConfig() { cheloniaConfig.contracts = {}; } } -async function updateCheloniaConfig(contractName, version3, manifestPath) { +async function updateCheloniaConfig(fullContractName, contractName, version3, manifestPath) { const manifestFileName = basename42(manifestPath); const pinnedManifestPath = `contracts/${contractName}/${version3}/${manifestFileName}`; - cheloniaConfig.contracts[contractName] = { + cheloniaConfig.contracts[fullContractName] = { version: version3, path: pinnedManifestPath }; diff --git a/build/serve/creditsWorker.js b/build/serve/creditsWorker.js index 7b2d5ed..814a512 100644 --- a/build/serve/creditsWorker.js +++ b/build/serve/creditsWorker.js @@ -1,5 +1,5 @@ -import { createRequire } from "node:module"; -var __require = createRequire(import.meta.url); +import { createRequire as __deno_internal_createRequire } from "node:module"; +var __require = __deno_internal_createRequire(import.meta.url); // build/serve/creditsWorker.js-tmp diff --git a/build/serve/ownerSizeTotalWorker.js b/build/serve/ownerSizeTotalWorker.js index ec3e39a..deaef25 100644 --- a/build/serve/ownerSizeTotalWorker.js +++ b/build/serve/ownerSizeTotalWorker.js @@ -1,5 +1,5 @@ -import { createRequire } from "node:module"; -var __require = createRequire(import.meta.url); +import { createRequire as __deno_internal_createRequire } from "node:module"; +var __require = __deno_internal_createRequire(import.meta.url); // build/serve/ownerSizeTotalWorker.js-tmp diff --git a/src/pin.ts b/src/pin.ts index e7acd2a..b2e778b 100644 --- a/src/pin.ts +++ b/src/pin.ts @@ -6,13 +6,15 @@ import process from 'node:process' import type { ArgumentsCamelCase, CommandModule } from './commands.ts' import { exit } from './utils.ts' +const RESERVED_FILE_CHARS = /[/\\:*?"<>|]/g + type Params = { overwrite: boolean, 'dir'?: string, 'manifest-version'?: string, manifest: string } let projectRoot: string let cheloniaConfig: { contracts: Record } function sanitizeContractName (contractName: string): string { - return contractName.replace(/[/\\:*?"<>|]/g, '_').replace(/\.\./g, '__') + return contractName.replace(RESERVED_FILE_CHARS, '_').replace(/\.\./g, '__') } export async function pin (args: ArgumentsCamelCase): Promise { @@ -37,6 +39,11 @@ export async function pin (args: ArgumentsCamelCase): Promise { } const { contractName, fullContractName, contractFiles, manifestVersion } = await parseManifest(fullManifestPath) + + if (RESERVED_FILE_CHARS.test(manifestVersion)) { + exit(`Invalid manifest version: ${manifestVersion}`) + } + console.log(colors.blue(`Contract name: ${fullContractName}`)) console.log(colors.blue(`Manifest version: ${manifestVersion}`)) From c8a92094551d0362c73be0665c0f6cb2c87322f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Iv=C3=A1n=20Vieitez=20Parra?= <3857362+corrideat@users.noreply.github.com> Date: Wed, 15 Apr 2026 21:55:23 -0400 Subject: [PATCH 06/13] Avoid `/g` for clarity --- src/pin.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pin.ts b/src/pin.ts index b2e778b..e28be09 100644 --- a/src/pin.ts +++ b/src/pin.ts @@ -6,7 +6,7 @@ import process from 'node:process' import type { ArgumentsCamelCase, CommandModule } from './commands.ts' import { exit } from './utils.ts' -const RESERVED_FILE_CHARS = /[/\\:*?"<>|]/g +const RESERVED_FILE_CHARS = /[/\\:*?"<>|]/ type Params = { overwrite: boolean, 'dir'?: string, 'manifest-version'?: string, manifest: string } @@ -14,7 +14,7 @@ let projectRoot: string let cheloniaConfig: { contracts: Record } function sanitizeContractName (contractName: string): string { - return contractName.replace(RESERVED_FILE_CHARS, '_').replace(/\.\./g, '__') + return contractName.replaceAll(RESERVED_FILE_CHARS, '_').replace(/\.\./g, '__') } export async function pin (args: ArgumentsCamelCase): Promise { From 5239115dc0229555648a05b770ba7f15b380ef06 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Iv=C3=A1n=20Vieitez=20Parra?= <3857362+corrideat@users.noreply.github.com> Date: Wed, 15 Apr 2026 22:08:14 -0400 Subject: [PATCH 07/13] Updates --- build/main.js | 6 +++--- src/serve/server.ts | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/build/main.js b/build/main.js index 9284657..be2daaa 100644 --- a/build/main.js +++ b/build/main.js @@ -108591,7 +108591,7 @@ var init_server = __esm({ with: { type: "json" } })).default; } catch { - console.warn("`chelonia.json` not found. Version information will be unavailable."); + console.warn("`chelonia.json` unparsable or not found. Version information will be unavailable."); } })(); ARCHIVE_MODE2 = import_npm_nconf6.default.get("server:archiveMode"); @@ -110617,11 +110617,11 @@ var module9 = { return migrate(argv); } }; -var RESERVED_FILE_CHARS = /[/\\:*?"<>|]/g; +var RESERVED_FILE_CHARS = /[/\\:*?"<>|]/; var projectRoot; var cheloniaConfig; function sanitizeContractName(contractName) { - return contractName.replace(RESERVED_FILE_CHARS, "_").replace(/\.\./g, "__"); + return contractName.replaceAll(RESERVED_FILE_CHARS, "_").replace(/\.\./g, "__"); } async function pin(args) { const version3 = args["manifest-version"]; diff --git a/src/serve/server.ts b/src/serve/server.ts index ae5b29e..37a38dd 100644 --- a/src/serve/server.ts +++ b/src/serve/server.ts @@ -41,7 +41,7 @@ const cheloniaAppManifest = await (async () => { with: { type: 'json' } })).default } catch { - console.warn('`chelonia.json` not found. Version information will be unavailable.') + console.warn('`chelonia.json` unparsable or not found. Version information will be unavailable.') } })() @@ -438,7 +438,7 @@ sbp('okTurtles.data/set', PUBSUB_INSTANCE, createServer(hapi.listener, { appVersion: cheloniaAppManifest?.appVersion || null, contractsVersion: cheloniaAppManifest?.contracts ? Object.fromEntries( Object.entries(cheloniaAppManifest?.contracts) - .map(([k, v]) => [k, (v as Record).version]) + .map(([k, v]) => [k, (v as { version: string }).version]) ) : null } socket.send(createNotification(NOTIFICATION_TYPE.VERSION_INFO, versionInfo)) From 9a84046f6e675a70fa9f1d2c1e7374fbd6a0b3a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Iv=C3=A1n=20Vieitez=20Parra?= <3857362+corrideat@users.noreply.github.com> Date: Wed, 15 Apr 2026 23:30:08 -0400 Subject: [PATCH 08/13] Use separate regexes --- build/main.js | 3 ++- src/pin.ts | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/build/main.js b/build/main.js index be2daaa..5ba947c 100644 --- a/build/main.js +++ b/build/main.js @@ -110618,10 +110618,11 @@ var module9 = { } }; var RESERVED_FILE_CHARS = /[/\\:*?"<>|]/; +var RESERVED_FILE_CHARS_REPLACE = /[/\\:*?"<>|]/g; var projectRoot; var cheloniaConfig; function sanitizeContractName(contractName) { - return contractName.replaceAll(RESERVED_FILE_CHARS, "_").replace(/\.\./g, "__"); + return contractName.replace(RESERVED_FILE_CHARS_REPLACE, "_").replace(/\.\./g, "__"); } async function pin(args) { const version3 = args["manifest-version"]; diff --git a/src/pin.ts b/src/pin.ts index e28be09..78e1b8d 100644 --- a/src/pin.ts +++ b/src/pin.ts @@ -7,6 +7,7 @@ import type { ArgumentsCamelCase, CommandModule } from './commands.ts' import { exit } from './utils.ts' const RESERVED_FILE_CHARS = /[/\\:*?"<>|]/ +const RESERVED_FILE_CHARS_REPLACE = /[/\\:*?"<>|]/g type Params = { overwrite: boolean, 'dir'?: string, 'manifest-version'?: string, manifest: string } @@ -14,7 +15,7 @@ let projectRoot: string let cheloniaConfig: { contracts: Record } function sanitizeContractName (contractName: string): string { - return contractName.replaceAll(RESERVED_FILE_CHARS, '_').replace(/\.\./g, '__') + return contractName.replace(RESERVED_FILE_CHARS_REPLACE, '_').replace(/\.\./g, '__') } export async function pin (args: ArgumentsCamelCase): Promise { From ede943fb897d328183141d9ee0b71bddfd209231 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Iv=C3=A1n=20Vieitez=20Parra?= <3857362+corrideat@users.noreply.github.com> Date: Sat, 18 Apr 2026 02:51:44 +0000 Subject: [PATCH 09/13] Change name for consistency --- src/pin.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pin.ts b/src/pin.ts index 78e1b8d..dc2cafe 100644 --- a/src/pin.ts +++ b/src/pin.ts @@ -84,7 +84,7 @@ export async function pin (args: ArgumentsCamelCase): Promise { await copyContractFiles(contractFiles, manifestPath, contractName, manifestVersion, args) await updateCheloniaConfig(fullContractName, contractName, manifestVersion, manifestPath) - console.log(colors.green(`✅ Successfully pinned ${contractName} to version ${manifestVersion}`)) + console.log(colors.green(`✅ Successfully pinned ${fullContractName} to version ${manifestVersion}`)) console.log(colors.gray(`Location: contracts/${contractName}/${manifestVersion}/`)) } catch (error) { exit(error) From 6a40a04f8c2f5bdc5c99b2228e7634af8b38b577 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Iv=C3=A1n=20Vieitez=20Parra?= <3857362+corrideat@users.noreply.github.com> Date: Sat, 18 Apr 2026 17:24:00 +0000 Subject: [PATCH 10/13] Update README.md --- README.md | 71 +++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 69 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 9d88ca5..c018d76 100644 --- a/README.md +++ b/README.md @@ -58,12 +58,12 @@ chel pin 2.0.0 dist/contracts/2.0.0/group.2.0.0.manifest.json **Configuration (`chelonia.json`):** ```json { - "contracts": { + "gi.contracts/chatroom": { "chatroom": { "version": "2.0.6", "path": "contracts/gi.contracts_chatroom/2.0.6/chatroom.2.0.6.manifest.json" }, - "group": { + "gi.contracts/group": { "version": "2.0.0", "path": "contracts/gi.contracts_group/2.0.0/group.2.0.0.manifest.json" } @@ -278,6 +278,73 @@ chel migrate --from sqlite --to redis --to-config redis.toml chel migrate --from sqlite --from-config sqlite.toml --to redis --to-config redis.toml ``` +## Configuration Files + +The project uses two separate configuration files for different purposes: + +### `chel.toml` — Runtime CLI Configuration + +`chel.toml` configures the `chel` command itself at runtime. It is read by `nconf` with priority: CLI arguments > environment variables > `chel.toml` > defaults. It controls things like server host/port, database backend selection, and other operational settings. + +```toml +# Example chel.toml +[server] +host = "0.0.0.0" +port = 8000 +dashboardPort = 8888 + +[database] +backend = "sqlite" +``` + +### `chelonia.json` — App Properties + +`chelonia.json` is an **app-level properties file** that describes which +contracts make up the application and their pinned versions. It is **not** +runtime configuration for `chel`. Instead, it is: + +- **Created and updated** by `chel pin` when pinning contracts to specific + versions. +- **Read by the server** (`chel serve`) at startup to provide version + information and other app-specific settings to clients. + +The file contains a `contracts` object keyed by the full contract name +(e.g. `gi.contracts/chatroom`), where each entry has: + +| Field | Description | +|-------|-------------| +| `version` | The pinned version string for this contract | +| `path` | Relative path to the manifest file in the `contracts/` directory | + +It may also contain an `appVersion` field for the overall application version. + +**Example:** +```json +{ + "appVersion": "2.0.0", + "contracts": { + "gi.contracts/chatroom": { + "version": "2.0.6", + "path": "contracts/gi.contracts_chatroom/2.0.6/chatroom.2.0.6.manifest.json" + }, + "gi.contracts/group": { + "version": "2.0.0", + "path": "contracts/gi.contracts_group/2.0.0/group.2.0.0.manifest.json" + } + } +} +``` + +**Summary of differences:** + +| | `chel.toml` | `chelonia.json` | +|---|---|---| +| **Purpose** | Runtime configuration of the `chel` CLI | App properties (e.g., contract versions) | +| **Managed by** | Manually by the developer / system administrator | Automatically by `chel pin` | +| **Read by** | `chel` commands (via `nconf`) | The server (at startup), values exposed to clients | +| **Format** | TOML | JSON | +| **Example content** | Database configuration | Contract versions | + ## History See [HISTORY.md](HISTORY.md) From 7e432ec9e70be8fa74501f6df91c56c4a76a6732 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Iv=C3=A1n=20Vieitez=20Parra?= <3857362+corrideat@users.noreply.github.com> Date: Sat, 18 Apr 2026 18:51:02 +0000 Subject: [PATCH 11/13] Fix example --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index c018d76..b4c7b3f 100644 --- a/README.md +++ b/README.md @@ -58,8 +58,8 @@ chel pin 2.0.0 dist/contracts/2.0.0/group.2.0.0.manifest.json **Configuration (`chelonia.json`):** ```json { - "gi.contracts/chatroom": { - "chatroom": { + "contracts": { + "gi.contracts/chatroom": { "version": "2.0.6", "path": "contracts/gi.contracts_chatroom/2.0.6/chatroom.2.0.6.manifest.json" }, From 740ec9b6e1f22c9f91d692fd01bfb93c26389b43 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Iv=C3=A1n=20Vieitez=20Parra?= <3857362+corrideat@users.noreply.github.com> Date: Sat, 18 Apr 2026 19:22:54 +0000 Subject: [PATCH 12/13] Fixes --- build/main.js | 8 ++++---- src/pin.ts | 7 ++++--- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/build/main.js b/build/main.js index 5ba947c..bad5562 100644 --- a/build/main.js +++ b/build/main.js @@ -110617,8 +110617,8 @@ var module9 = { return migrate(argv); } }; -var RESERVED_FILE_CHARS = /[/\\:*?"<>|]/; -var RESERVED_FILE_CHARS_REPLACE = /[/\\:*?"<>|]/g; +var VALID_VERSION = /^[a-zA-Z0-9_+-][a-zA-Z0-9._+-]*[a-zA-Z0-9_+-]?$/; +var RESERVED_FILE_CHARS_REPLACE = /[\x00/\\:*?"<>|]/g; var projectRoot; var cheloniaConfig; function sanitizeContractName(contractName) { @@ -110641,7 +110641,7 @@ async function pin(args) { exit(`Manifest file not found: ${manifestPath}`); } const { contractName, fullContractName, contractFiles, manifestVersion } = await parseManifest(fullManifestPath); - if (RESERVED_FILE_CHARS.test(manifestVersion)) { + if (!manifestVersion || !VALID_VERSION.test(manifestVersion)) { exit(`Invalid manifest version: ${manifestVersion}`); } console.log(blue(`Contract name: ${fullContractName}`)); @@ -110675,7 +110675,7 @@ async function pin(args) { } await copyContractFiles(contractFiles, manifestPath, contractName, manifestVersion, args); await updateCheloniaConfig(fullContractName, contractName, manifestVersion, manifestPath); - console.log(green(`\u2705 Successfully pinned ${contractName} to version ${manifestVersion}`)); + console.log(green(`\u2705 Successfully pinned ${fullContractName} to version ${manifestVersion}`)); console.log(gray(`Location: contracts/${contractName}/${manifestVersion}/`)); } catch (error2) { exit(error2); diff --git a/src/pin.ts b/src/pin.ts index dc2cafe..51baf52 100644 --- a/src/pin.ts +++ b/src/pin.ts @@ -6,8 +6,9 @@ import process from 'node:process' import type { ArgumentsCamelCase, CommandModule } from './commands.ts' import { exit } from './utils.ts' -const RESERVED_FILE_CHARS = /[/\\:*?"<>|]/ -const RESERVED_FILE_CHARS_REPLACE = /[/\\:*?"<>|]/g +const VALID_VERSION = /^[a-zA-Z0-9_+-][a-zA-Z0-9._+-]*[a-zA-Z0-9_+-]?$/ +// deno-lint-ignore no-control-regex +const RESERVED_FILE_CHARS_REPLACE = /[\x00/\\:*?"<>|]/g type Params = { overwrite: boolean, 'dir'?: string, 'manifest-version'?: string, manifest: string } @@ -41,7 +42,7 @@ export async function pin (args: ArgumentsCamelCase): Promise { const { contractName, fullContractName, contractFiles, manifestVersion } = await parseManifest(fullManifestPath) - if (RESERVED_FILE_CHARS.test(manifestVersion)) { + if (!manifestVersion || !VALID_VERSION.test(manifestVersion)) { exit(`Invalid manifest version: ${manifestVersion}`) } From 3e8454808031e49e8c06ea6e928313e7abd6eec0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Iv=C3=A1n=20Vieitez=20Parra?= <3857362+corrideat@users.noreply.github.com> Date: Sun, 19 Apr 2026 22:09:26 +0000 Subject: [PATCH 13/13] Add missing join --- build/main.js | 98 +++++++++++++++++++++++---------------------- src/serve/server.ts | 4 +- 2 files changed, 53 insertions(+), 49 deletions(-) diff --git a/build/main.js b/build/main.js index 0c62689..a5d65b0 100644 --- a/build/main.js +++ b/build/main.js @@ -14,7 +14,7 @@ import { Buffer as Buffer8 } from "node:buffer"; import { Buffer as Buffer9 } from "node:buffer"; import { randomBytes as randomBytes2, timingSafeEqual } from "node:crypto"; import { mkdir, readdir, readFile, rm, unlink, writeFile } from "node:fs/promises"; -import { basename as basename9, dirname as dirname9, join as join22, normalize as normalize8, resolve as resolve9 } from "node:path"; +import { basename as basename9, dirname as dirname9, join as join9, normalize as normalize8, resolve as resolve9 } from "node:path"; import { Buffer as Buffer10 } from "node:buffer"; // deno:https://jsr.io/@db/sqlite/0.13.0/deno.json @@ -484,7 +484,7 @@ function normalize3(path) { } // deno:https://jsr.io/@std/path/1.1.3/posix/join.ts -function join4(path, ...paths) { +function join3(path, ...paths) { if (path === void 0) return "."; if (path instanceof URL) { path = fromFileUrl4(path); @@ -579,7 +579,7 @@ function normalize4(path) { } // deno:https://jsr.io/@std/path/1.1.3/windows/join.ts -function join5(path, ...paths) { +function join4(path, ...paths) { if (path instanceof URL) { path = fromFileUrl5(path); } @@ -619,8 +619,8 @@ function join5(path, ...paths) { } // deno:https://jsr.io/@std/path/1.1.3/join.ts -function join6(path, ...paths) { - return isWindows2 ? join5(path, ...paths) : join4(path, ...paths); +function join5(path, ...paths) { + return isWindows2 ? join4(path, ...paths) : join3(path, ...paths); } // deno:https://jsr.io/@std/path/1.1.3/normalize.ts @@ -967,7 +967,7 @@ function baseUrlToFilename(url2) { default: throw new TypeError(`Don't know how to create cache name for protocol: ${protocol}`); } - return join6(...out); + return join5(...out); } function stringToURL(url2) { return url2.startsWith("file://") || url2.startsWith("http://") || url2.startsWith("https://") ? new URL(url2) : toFileUrl5(resolve5(url2)); @@ -978,7 +978,7 @@ async function hash(value) { async function urlToFilename(url2) { const cacheFilename = baseUrlToFilename(url2); const hashedFilename = await hash(url2.pathname + url2.search); - return join6(cacheFilename, hashedFilename); + return join5(cacheFilename, hashedFilename); } async function isFile(filePath) { try { @@ -1012,7 +1012,7 @@ function cacheDir() { if (Deno.build.os === "darwin") { const home = homeDir(); if (home) { - return join6(home, "Library/Caches"); + return join5(home, "Library/Caches"); } } else if (Deno.build.os === "windows") { return Deno.env.get("LOCALAPPDATA"); @@ -1023,7 +1023,7 @@ function cacheDir() { } else { const home = homeDir(); if (home) { - return join6(home, ".cache"); + return join5(home, ".cache"); } } } @@ -1032,15 +1032,15 @@ function denoCacheDir() { const dd = Deno.env.get("DENO_DIR"); let root; if (dd) { - root = normalize5(isAbsolute5(dd) ? dd : join6(Deno.cwd(), dd)); + root = normalize5(isAbsolute5(dd) ? dd : join5(Deno.cwd(), dd)); } else { const cd = cacheDir(); if (cd) { - root = join6(cd, "deno"); + root = join5(cd, "deno"); } else { const hd = homeDir(); if (hd) { - root = join6(hd, ".deno"); + root = join5(hd, ".deno"); } } } @@ -1157,15 +1157,15 @@ async function ensureCacheLocation(location = "deno") { if (dir === void 0) { throw new Error("Could not get the deno cache directory, try using another CacheLocation in the plug options."); } - location = join6(dir, "plug"); + location = join5(dir, "plug"); } else if (location === "cache") { const dir = cacheDir(); if (dir === void 0) { throw new Error("Could not get the cache directory, try using another CacheLocation in the plug options."); } - location = join6(dir, "plug"); + location = join5(dir, "plug"); } else if (location === "cwd") { - location = join6(Deno.cwd(), "plug"); + location = join5(Deno.cwd(), "plug"); } else if (location === "tmp") { location = await Deno.makeTempDir({ prefix: "plug" @@ -1187,7 +1187,7 @@ async function download(options2) { const setting = (typeof options2 === "object" && "cache" in options2 ? options2.cache : void 0) ?? "use"; const url2 = createDownloadURL(options2); const directory = await ensureCacheLocation(location); - const cacheBasePath = join6(directory, await urlToFilename(url2)); + const cacheBasePath = join5(directory, await urlToFilename(url2)); const cacheFilePath = `${cacheBasePath}${extname5(url2.pathname)}`; const cacheMetaPath = `${cacheBasePath}.metadata.json`; const cached2 = setting === "use" ? await isFile(cacheFilePath) : setting === "only" || setting !== "reloadAll"; @@ -3077,7 +3077,7 @@ var wrapTransaction = (fn, db2, { begin, commit, rollback, savepoint, release, r // build/main.js-tmp import { Buffer as Buffer11 } from "node:buffer"; import { mkdir as mkdir2 } from "node:fs/promises"; -import { basename as basename22, dirname as dirname22, join as join32, resolve as resolve22 } from "node:path"; +import { basename as basename22, dirname as dirname22, join as join22, resolve as resolve22 } from "node:path"; import process2 from "node:process"; import { Readable } from "node:stream"; import path5 from "node:path"; @@ -3092,6 +3092,7 @@ import { Buffer as Buffer15 } from "node:buffer"; import { isIP } from "node:net"; import path6 from "node:path"; import process9 from "node:process"; +import { join as join72 } from "node:path"; import process10 from "node:process"; import { pathToFileURL } from "node:url"; import process11 from "node:process"; @@ -3423,7 +3424,7 @@ function normalize6(path) { } // deno:https://jsr.io/@std/path/1.1.1/posix/join.ts -function join7(path, ...paths) { +function join6(path, ...paths) { if (path === void 0) return "."; if (path instanceof URL) { path = fromFileUrl7(path); @@ -3518,7 +3519,7 @@ function normalize7(path) { } // deno:https://jsr.io/@std/path/1.1.1/windows/join.ts -function join8(path, ...paths) { +function join7(path, ...paths) { if (path instanceof URL) { path = fromFileUrl8(path); } @@ -3558,8 +3559,8 @@ function join8(path, ...paths) { } // deno:https://jsr.io/@std/path/1.1.1/join.ts -function join9(path, ...paths) { - return isWindows2 ? join8(path, ...paths) : join7(path, ...paths); +function join8(path, ...paths) { + return isWindows2 ? join7(path, ...paths) : join6(path, ...paths); } // deno:https://jsr.io/@std/path/1.1.1/posix/parse.ts @@ -4022,7 +4023,7 @@ function resolve8(...pathSegments) { // build/main.js-tmp import { Buffer as Buffer12 } from "node:buffer"; -import { join as join42 } from "node:path"; +import { join as join32 } from "node:path"; // deno:https://jsr.io/@std/encoding/1.0.10/_common64.ts var padding = "=".charCodeAt(0); @@ -4111,7 +4112,7 @@ import { readFile as readFile2 } from "node:fs/promises"; import process3 from "node:process"; import { existsSync } from "node:fs"; import { copyFile, mkdir as mkdir3, readFile as readFile3, writeFile as writeFile2 } from "node:fs/promises"; -import { basename as basename42, dirname as dirname42, join as join72 } from "node:path"; +import { basename as basename42, dirname as dirname42, join as join62 } from "node:path"; import process4 from "node:process"; import process12 from "node:process"; import { notStrictEqual, strictEqual } from "node:assert"; @@ -32424,9 +32425,9 @@ var init_database_fs = __esm({ // Maps a given key to a real path on the filesystem. mapKey(key) { if (basename9(normalize8(key)) !== key) throw new TypeError("Invalid key"); - if (!this.depth) return join22(this.dataFolder, key); + if (!this.depth) return join9(this.dataFolder, key); const keyChunks = splitAndGroup(key, this.keyChunkLength, this.depth); - return join22(this.dataFolder, ...keyChunks, key); + return join9(this.dataFolder, ...keyChunks, key); } async init() { await mkdir(this.dataFolder, { mode: 488, recursive: true }); @@ -32436,7 +32437,7 @@ var init_database_fs = __esm({ } async clear() { const names = await readdir(this.dataFolder); - const paths = names.map((name) => join22(this.dataFolder, name)); + const paths = names.map((name) => join9(this.dataFolder, name)); await Promise.all( paths.map((p) => rm(p, { recursive: true })) ); @@ -58077,7 +58078,7 @@ var init_database_sqlite = __esm({ if (this.db) { throw new Error(`The ${filename} SQLite database is already open.`); } - this.db = new Database(join32(dataFolder, filename)); + this.db = new Database(join22(dataFolder, filename)); this.run("CREATE TABLE IF NOT EXISTS Data(key TEXT NOT NULL PRIMARY KEY, value TEXT NOT NULL)"); console.info(`Connected to the ${filename} SQLite database.`); this.readStatement = this.db.prepare("SELECT CAST(value AS BLOB) value FROM Data WHERE key = ?"); @@ -108600,7 +108601,8 @@ var init_server = __esm({ import_npm_nconf6 = __toESM(require_nconf()); cheloniaAppManifest = await (async () => { try { - return (await import(pathToFileURL(join(process10.cwd(), "chelonia.json")).toString(), { + const appDir2 = import_npm_nconf6.default.get("server:appDir") || process10.cwd(); + return (await import(pathToFileURL(join72(appDir2, "chelonia.json")).toString(), { with: { type: "json" } })).default; } catch { @@ -110054,7 +110056,7 @@ var findManifestFiles = async (path8) => { const entries = Deno.readDir(path9); const manifests = /* @__PURE__ */ new Set(); for await (const entry of entries) { - const realPath2 = await Deno.realPath(join42(path9, entry.name)); + const realPath2 = await Deno.realPath(join32(path9, entry.name)); const info = await Deno.lstat(realPath2); if (info.isDirectory) { const subitems = await internal(realPath2); @@ -110062,7 +110064,7 @@ var findManifestFiles = async (path8) => { manifests.add(item); } } else if (entry.name.toLowerCase().endsWith(".manifest.json")) { - manifests.add(join42(path9, entry.name)); + manifests.add(join32(path9, entry.name)); } } return manifests; @@ -110178,9 +110180,9 @@ async function deploy(args) { const json = JSON.parse(manifestText); const body = ContractBodySchema.parse(JSON.parse(json.body)); const dirname72 = dirname8(manifestPath); - toUpload.push(CONTRACT_TEXT_PREFIX + join9(dirname72, body.contract.file)); + toUpload.push(CONTRACT_TEXT_PREFIX + join8(dirname72, body.contract.file)); if (body.contractSlim) { - toUpload.push(CONTRACT_TEXT_PREFIX + join9(dirname72, body.contractSlim.file)); + toUpload.push(CONTRACT_TEXT_PREFIX + join8(dirname72, body.contractSlim.file)); } toUpload.push(CONTRACT_MANIFEST_PREFIX + manifestPath); } @@ -110399,7 +110401,7 @@ async function manifest(args) { const name = args.name || contractFileName; const version3 = args.contractVersion || "x"; const slim = args.slim; - const outFile = args.out || join9(contractDir, `${contractFileName}.${version3}.manifest.json`); + const outFile = args.out || join8(contractDir, `${contractFileName}.${version3}.manifest.json`); if (!keyFile) exit("Missing signing key file"); const signingKeyDescriptorRaw = await readJsonFile(keyFile); if (!isSigningKeyDescriptor(signingKeyDescriptorRaw)) { @@ -110670,7 +110672,7 @@ async function pin(args) { console.log(cyan(`\u{1F4CC} Requesting pin to version: ${version3}`)); console.log(gray(`Manifest: ${manifestPath}`)); await loadCheloniaConfig(); - const fullManifestPath = join72(projectRoot, manifestPath); + const fullManifestPath = join62(projectRoot, manifestPath); if (!existsSync(fullManifestPath)) { exit(`Manifest file not found: ${manifestPath}`); } @@ -110698,7 +110700,7 @@ async function pin(args) { } else { console.log(cyan(`\u{1F4CC} Pinning ${fullContractName} to version ${manifestVersion} (first time)`)); } - const contractVersionDir = join72(projectRoot, "contracts", contractName, manifestVersion); + const contractVersionDir = join62(projectRoot, "contracts", contractName, manifestVersion); if (existsSync(contractVersionDir)) { if (!args.overwrite) { exit(`Version ${manifestVersion} already exists for contract ${fullContractName}. Use --overwrite to replace it.`); @@ -110739,20 +110741,20 @@ async function parseManifest(manifestPath) { }; } async function createVersionDirectory(contractName, version3) { - const versionDir = join72(projectRoot, "contracts", contractName, version3); + const versionDir = join62(projectRoot, "contracts", contractName, version3); console.log(blue(`\u{1F4C1} Creating directory: contracts/${contractName}/${version3}/`)); await mkdir3(versionDir, { recursive: true }); } async function copyContractFiles(contractFiles, manifestPath, contractName, version3, args) { - const sourceDir = dirname42(join72(projectRoot, manifestPath)); - const targetDir = join72(projectRoot, "contracts", contractName, version3); + const sourceDir = dirname42(join62(projectRoot, manifestPath)); + const targetDir = join62(projectRoot, "contracts", contractName, version3); console.log(gray(`\u{1F4CB} Copying files from manifest: ${contractFiles.main}${contractFiles.slim ? `, ${contractFiles.slim}` : ""}, manifest`)); - const mainSource = join72(sourceDir, contractFiles.main); - const mainTarget = join72(targetDir, contractFiles.main); + const mainSource = join62(sourceDir, contractFiles.main); + const mainTarget = join62(targetDir, contractFiles.main); await copyFileIfNeeded(mainSource, mainTarget, contractFiles.main, args); if (contractFiles.slim) { - const slimSource = join72(sourceDir, contractFiles.slim); - const slimTarget = join72(targetDir, contractFiles.slim); + const slimSource = join62(sourceDir, contractFiles.slim); + const slimTarget = join62(targetDir, contractFiles.slim); try { await copyFileIfNeeded(slimSource, slimTarget, contractFiles.slim, args); } catch (error2) { @@ -110760,8 +110762,8 @@ async function copyContractFiles(contractFiles, manifestPath, contractName, vers console.error(yellow(`\u26A0\uFE0F Could not copy slim file: ${errorMessage}`)); } } - const manifestSource = join72(projectRoot, manifestPath); - const manifestTarget = join72(targetDir, basename42(manifestPath)); + const manifestSource = join62(projectRoot, manifestPath); + const manifestTarget = join62(targetDir, basename42(manifestPath)); await copyFileIfNeeded(manifestSource, manifestTarget, basename42(manifestPath), args); } async function copyFileIfNeeded(sourcePath, targetPath, fileName, args) { @@ -110779,7 +110781,7 @@ async function copyFileIfNeeded(sourcePath, targetPath, fileName, args) { await copyFile(sourcePath, targetPath); } async function loadCheloniaConfig() { - const configPath = join72(projectRoot, "chelonia.json"); + const configPath = join62(projectRoot, "chelonia.json"); cheloniaConfig = { contracts: {} }; if (existsSync(configPath)) { try { @@ -110803,7 +110805,7 @@ async function updateCheloniaConfig(fullContractName, contractName, version3, ma version: version3, path: pinnedManifestPath }; - const configPath = join72(projectRoot, "chelonia.json"); + const configPath = join62(projectRoot, "chelonia.json"); const configContent = JSON.stringify(cheloniaConfig, null, 2) + "\n"; await writeFile2(configPath, configContent, "utf8"); console.log(green("\u2705 Saved chelonia.json")); @@ -111031,12 +111033,12 @@ var verifySignature2 = async (args, internal = false) => { if (!body.contract?.file) { exit("Invalid manifest: no contract file", internal); } - const computedHash = await hash22({ ...args, filename: join9(parsedFilepath.dir, body.contract.file) }, multicodes.SHELTER_CONTRACT_TEXT, true); + const computedHash = await hash22({ ...args, filename: join8(parsedFilepath.dir, body.contract.file) }, multicodes.SHELTER_CONTRACT_TEXT, true); if (computedHash !== body.contract.hash) { exit(`Invalid contract file hash. Expected ${body.contract.hash} but got ${computedHash}`, internal); } if (body.contractSlim) { - const computedHash2 = await hash22({ ...args, filename: join9(parsedFilepath.dir, body.contractSlim.file) }, multicodes.SHELTER_CONTRACT_TEXT, true); + const computedHash2 = await hash22({ ...args, filename: join8(parsedFilepath.dir, body.contractSlim.file) }, multicodes.SHELTER_CONTRACT_TEXT, true); if (computedHash2 !== body.contractSlim.hash) { exit(`Invalid slim contract file hash. Expected ${body.contractSlim.hash} but got ${computedHash2}`, internal); } diff --git a/src/serve/server.ts b/src/serve/server.ts index 0a855c9..2424de1 100644 --- a/src/serve/server.ts +++ b/src/serve/server.ts @@ -13,6 +13,7 @@ import chalk from 'npm:chalk' import type { ImportMeta } from '../types/build.d.ts' import createWorker from './createWorker.ts' // import type { SubMessage, UnsubMessage } from './pubsub.ts' // TODO: Use for type checking +import { join } from 'node:path' import process from 'node:process' import authPlugin from './auth.ts' import { CREDITS_WORKER_TASK_TIME_INTERVAL, OWNER_SIZE_TOTAL_WORKER_TASK_TIME_INTERVAL } from './constants.ts' @@ -37,7 +38,8 @@ import nconf from 'npm:nconf' const cheloniaAppManifest = await (async () => { try { - return (await import(pathToFileURL(join(process.cwd(), 'chelonia.json')).toString(), { + const appDir = nconf.get('server:appDir') || process.cwd() + return (await import(pathToFileURL(join(appDir, 'chelonia.json')).toString(), { with: { type: 'json' } })).default } catch {