@genomic/utils 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2025 Constructive <developers@constructive.io>
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,109 @@
1
+ # @genomic/utils
2
+
3
+ CLI lifecycle utilities for building command-line applications.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @genomic/utils
9
+ ```
10
+
11
+ ## Features
12
+
13
+ ### extractFirst
14
+
15
+ Extracts the first positional argument from argv for command routing:
16
+
17
+ ```typescript
18
+ import { extractFirst } from '@genomic/utils';
19
+
20
+ const { first, newArgv } = extractFirst(argv);
21
+ // first = 'init' (the subcommand)
22
+ // newArgv = remaining arguments with first positional removed
23
+ ```
24
+
25
+ ### cliExitWithError
26
+
27
+ Exits the CLI with an error message and optional cleanup:
28
+
29
+ ```typescript
30
+ import { cliExitWithError } from '@genomic/utils';
31
+
32
+ await cliExitWithError(error, {
33
+ beforeExit: async () => {
34
+ await closeConnections();
35
+ }
36
+ });
37
+ ```
38
+
39
+ ### checkForUpdates
40
+
41
+ Checks for package updates with caching:
42
+
43
+ ```typescript
44
+ import { checkForUpdates } from '@genomic/utils';
45
+
46
+ const result = await checkForUpdates({
47
+ pkgName: '@my/cli',
48
+ pkgVersion: '1.0.0',
49
+ registryBaseUrl: 'https://registry.npmjs.org'
50
+ });
51
+
52
+ if (result.hasUpdate) {
53
+ console.log(result.message);
54
+ }
55
+ ```
56
+
57
+ ### getSelfPackageJson
58
+
59
+ Gets the package.json for the current package:
60
+
61
+ ```typescript
62
+ import { getSelfPackageJson, getSelfVersion, getSelfName } from '@genomic/utils';
63
+
64
+ const pkg = getSelfPackageJson(__dirname);
65
+ const version = getSelfVersion(__dirname);
66
+ const name = getSelfName(__dirname);
67
+ ```
68
+
69
+ ## License
70
+
71
+ MIT
72
+
73
+ ---
74
+
75
+ ## Development
76
+
77
+ ### Setup
78
+
79
+ 1. Clone the repository:
80
+
81
+ ```bash
82
+ git clone https://github.com/constructive-io/dev-utils.git
83
+ ```
84
+
85
+ 2. Install dependencies:
86
+
87
+ ```bash
88
+ cd dev-utils
89
+ pnpm install
90
+ pnpm build
91
+ ```
92
+
93
+ 3. Test the package of interest:
94
+
95
+ ```bash
96
+ cd packages/<packagename>
97
+ pnpm test:watch
98
+ ```
99
+
100
+ ## Credits
101
+
102
+ Built for developers, with developers.
103
+ 👉 https://launchql.com | https://hyperweb.io
104
+
105
+ ## Disclaimer
106
+
107
+ AS DESCRIBED IN THE LICENSES, THE SOFTWARE IS PROVIDED "AS IS", AT YOUR OWN RISK, AND WITHOUT WARRANTIES OF ANY KIND.
108
+
109
+ No developer or entity involved in creating this software will be liable for any claims or damages whatsoever associated with your use, inability to use, or your interaction with other users of the code, including any direct, indirect, incidental, special, exemplary, punitive or consequential damages, or loss of profits, cryptocurrencies, tokens, or anything else of value.
package/argv.d.ts ADDED
@@ -0,0 +1,13 @@
1
+ import { ParsedArgs } from 'minimist';
2
+ /**
3
+ * Extracts the first positional argument from argv and returns it along with the remaining argv.
4
+ * This is useful for command routing in CLI applications where the first argument is a subcommand.
5
+ */
6
+ export declare const extractFirst: (argv: Partial<ParsedArgs>) => {
7
+ first: string;
8
+ newArgv: {
9
+ _: string[];
10
+ "--"?: string[] | undefined;
11
+ };
12
+ };
13
+ export type { ParsedArgs } from 'minimist';
package/argv.js ADDED
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.extractFirst = void 0;
4
+ /**
5
+ * Extracts the first positional argument from argv and returns it along with the remaining argv.
6
+ * This is useful for command routing in CLI applications where the first argument is a subcommand.
7
+ */
8
+ const extractFirst = (argv) => {
9
+ const first = argv._?.[0];
10
+ const newArgv = {
11
+ ...argv,
12
+ _: argv._?.slice(1) ?? []
13
+ };
14
+ return { first, newArgv };
15
+ };
16
+ exports.extractFirst = extractFirst;
package/cli-error.d.ts ADDED
@@ -0,0 +1,14 @@
1
+ export interface CliExitOptions {
2
+ context?: Record<string, any>;
3
+ beforeExit?: () => Promise<void>;
4
+ logger?: {
5
+ error: (message: string, ...args: any[]) => void;
6
+ debug: (message: string, ...args: any[]) => void;
7
+ warn: (message: string, ...args: any[]) => void;
8
+ };
9
+ }
10
+ /**
11
+ * Exits the CLI with an error message and optional cleanup.
12
+ * Supports a beforeExit hook for cleanup operations (e.g., closing database connections).
13
+ */
14
+ export declare const cliExitWithError: (error: Error | string, options?: CliExitOptions) => Promise<never>;
package/cli-error.js ADDED
@@ -0,0 +1,33 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.cliExitWithError = void 0;
4
+ /**
5
+ * Exits the CLI with an error message and optional cleanup.
6
+ * Supports a beforeExit hook for cleanup operations (e.g., closing database connections).
7
+ */
8
+ const cliExitWithError = async (error, options = {}) => {
9
+ const { context, beforeExit, logger = console } = options;
10
+ if (error instanceof Error) {
11
+ logger.error(`Error: ${error.message}`);
12
+ if (context) {
13
+ logger.debug('Context:', context);
14
+ }
15
+ }
16
+ else if (typeof error === 'string') {
17
+ logger.error(`Error: ${error}`);
18
+ if (context) {
19
+ logger.debug('Context:', context);
20
+ }
21
+ }
22
+ if (beforeExit) {
23
+ try {
24
+ await beforeExit();
25
+ logger.debug('Cleanup completed');
26
+ }
27
+ catch (cleanupError) {
28
+ logger.warn('Failed to complete cleanup:', cleanupError);
29
+ }
30
+ }
31
+ process.exit(1);
32
+ };
33
+ exports.cliExitWithError = cliExitWithError;
package/esm/argv.d.ts ADDED
@@ -0,0 +1,13 @@
1
+ import { ParsedArgs } from 'minimist';
2
+ /**
3
+ * Extracts the first positional argument from argv and returns it along with the remaining argv.
4
+ * This is useful for command routing in CLI applications where the first argument is a subcommand.
5
+ */
6
+ export declare const extractFirst: (argv: Partial<ParsedArgs>) => {
7
+ first: string;
8
+ newArgv: {
9
+ _: string[];
10
+ "--"?: string[] | undefined;
11
+ };
12
+ };
13
+ export type { ParsedArgs } from 'minimist';
package/esm/argv.js ADDED
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Extracts the first positional argument from argv and returns it along with the remaining argv.
3
+ * This is useful for command routing in CLI applications where the first argument is a subcommand.
4
+ */
5
+ export const extractFirst = (argv) => {
6
+ const first = argv._?.[0];
7
+ const newArgv = {
8
+ ...argv,
9
+ _: argv._?.slice(1) ?? []
10
+ };
11
+ return { first, newArgv };
12
+ };
@@ -0,0 +1,14 @@
1
+ export interface CliExitOptions {
2
+ context?: Record<string, any>;
3
+ beforeExit?: () => Promise<void>;
4
+ logger?: {
5
+ error: (message: string, ...args: any[]) => void;
6
+ debug: (message: string, ...args: any[]) => void;
7
+ warn: (message: string, ...args: any[]) => void;
8
+ };
9
+ }
10
+ /**
11
+ * Exits the CLI with an error message and optional cleanup.
12
+ * Supports a beforeExit hook for cleanup operations (e.g., closing database connections).
13
+ */
14
+ export declare const cliExitWithError: (error: Error | string, options?: CliExitOptions) => Promise<never>;
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Exits the CLI with an error message and optional cleanup.
3
+ * Supports a beforeExit hook for cleanup operations (e.g., closing database connections).
4
+ */
5
+ export const cliExitWithError = async (error, options = {}) => {
6
+ const { context, beforeExit, logger = console } = options;
7
+ if (error instanceof Error) {
8
+ logger.error(`Error: ${error.message}`);
9
+ if (context) {
10
+ logger.debug('Context:', context);
11
+ }
12
+ }
13
+ else if (typeof error === 'string') {
14
+ logger.error(`Error: ${error}`);
15
+ if (context) {
16
+ logger.debug('Context:', context);
17
+ }
18
+ }
19
+ if (beforeExit) {
20
+ try {
21
+ await beforeExit();
22
+ logger.debug('Cleanup completed');
23
+ }
24
+ catch (cleanupError) {
25
+ logger.warn('Failed to complete cleanup:', cleanupError);
26
+ }
27
+ }
28
+ process.exit(1);
29
+ };
package/esm/index.d.ts ADDED
@@ -0,0 +1,8 @@
1
+ export { extractFirst } from './argv';
2
+ export type { ParsedArgs } from './argv';
3
+ export { cliExitWithError } from './cli-error';
4
+ export type { CliExitOptions } from './cli-error';
5
+ export { checkForUpdates } from './update-check';
6
+ export type { UpdateCheckOptions, UpdateCheckResult } from './update-check';
7
+ export { getSelfPackageJson, getSelfVersion, getSelfName } from './package-json';
8
+ export type { PackageJsonInfo } from './package-json';
package/esm/index.js ADDED
@@ -0,0 +1,8 @@
1
+ // Argv utilities
2
+ export { extractFirst } from './argv';
3
+ // CLI error handling
4
+ export { cliExitWithError } from './cli-error';
5
+ // Update checking
6
+ export { checkForUpdates } from './update-check';
7
+ // Package.json utilities
8
+ export { getSelfPackageJson, getSelfVersion, getSelfName } from './package-json';
@@ -0,0 +1,18 @@
1
+ export interface PackageJsonInfo {
2
+ name: string;
3
+ version: string;
4
+ [key: string]: any;
5
+ }
6
+ /**
7
+ * Gets the package.json for the current package by searching up from the given directory.
8
+ * This is useful for CLIs to get their own version information.
9
+ */
10
+ export declare const getSelfPackageJson: (dirname: string) => PackageJsonInfo;
11
+ /**
12
+ * Gets the version from the package.json for the current package.
13
+ */
14
+ export declare const getSelfVersion: (dirname: string) => string;
15
+ /**
16
+ * Gets the name from the package.json for the current package.
17
+ */
18
+ export declare const getSelfName: (dirname: string) => string;
@@ -0,0 +1,20 @@
1
+ import { findAndRequirePackageJson } from 'find-and-require-package-json';
2
+ /**
3
+ * Gets the package.json for the current package by searching up from the given directory.
4
+ * This is useful for CLIs to get their own version information.
5
+ */
6
+ export const getSelfPackageJson = (dirname) => {
7
+ return findAndRequirePackageJson(dirname);
8
+ };
9
+ /**
10
+ * Gets the version from the package.json for the current package.
11
+ */
12
+ export const getSelfVersion = (dirname) => {
13
+ return getSelfPackageJson(dirname).version;
14
+ };
15
+ /**
16
+ * Gets the name from the package.json for the current package.
17
+ */
18
+ export const getSelfName = (dirname) => {
19
+ return getSelfPackageJson(dirname).name;
20
+ };
@@ -0,0 +1,18 @@
1
+ export interface UpdateCheckOptions {
2
+ pkgName: string;
3
+ pkgVersion: string;
4
+ registryBaseUrl?: string;
5
+ toolName?: string;
6
+ ttl?: number;
7
+ }
8
+ export interface UpdateCheckResult {
9
+ hasUpdate: boolean;
10
+ currentVersion: string;
11
+ latestVersion: string | null;
12
+ message: string | null;
13
+ }
14
+ /**
15
+ * Checks for updates to a package and caches the result.
16
+ * Uses appstash for configuration storage.
17
+ */
18
+ export declare const checkForUpdates: (options: UpdateCheckOptions) => Promise<UpdateCheckResult>;
@@ -0,0 +1,76 @@
1
+ import { appstash } from 'appstash';
2
+ import * as fs from 'fs';
3
+ import * as path from 'path';
4
+ const DEFAULT_TTL = 24 * 60 * 60 * 1000; // 24 hours
5
+ const DEFAULT_REGISTRY = 'https://registry.npmjs.org';
6
+ /**
7
+ * Checks for updates to a package and caches the result.
8
+ * Uses appstash for configuration storage.
9
+ */
10
+ export const checkForUpdates = async (options) => {
11
+ const { pkgName, pkgVersion, registryBaseUrl = DEFAULT_REGISTRY, toolName = pkgName, ttl = DEFAULT_TTL } = options;
12
+ const dirs = appstash(toolName);
13
+ const cacheFile = path.join(dirs.cache, 'update-check.json');
14
+ // Check cache first
15
+ try {
16
+ if (fs.existsSync(cacheFile)) {
17
+ const cached = JSON.parse(fs.readFileSync(cacheFile, 'utf-8'));
18
+ if (Date.now() - cached.timestamp < ttl) {
19
+ return {
20
+ hasUpdate: cached.latestVersion !== pkgVersion && cached.latestVersion > pkgVersion,
21
+ currentVersion: pkgVersion,
22
+ latestVersion: cached.latestVersion,
23
+ message: cached.latestVersion > pkgVersion
24
+ ? `Update available: ${pkgVersion} -> ${cached.latestVersion}`
25
+ : null
26
+ };
27
+ }
28
+ }
29
+ }
30
+ catch {
31
+ // Cache read failed, continue to fetch
32
+ }
33
+ // Fetch latest version from registry
34
+ try {
35
+ const response = await fetch(`${registryBaseUrl}/${pkgName}/latest`);
36
+ if (!response.ok) {
37
+ return {
38
+ hasUpdate: false,
39
+ currentVersion: pkgVersion,
40
+ latestVersion: null,
41
+ message: null
42
+ };
43
+ }
44
+ const data = await response.json();
45
+ const latestVersion = data.version;
46
+ // Cache the result
47
+ try {
48
+ if (!fs.existsSync(dirs.cache)) {
49
+ fs.mkdirSync(dirs.cache, { recursive: true });
50
+ }
51
+ fs.writeFileSync(cacheFile, JSON.stringify({
52
+ latestVersion,
53
+ timestamp: Date.now()
54
+ }));
55
+ }
56
+ catch {
57
+ // Cache write failed, continue anyway
58
+ }
59
+ return {
60
+ hasUpdate: latestVersion !== pkgVersion && latestVersion > pkgVersion,
61
+ currentVersion: pkgVersion,
62
+ latestVersion,
63
+ message: latestVersion > pkgVersion
64
+ ? `Update available: ${pkgVersion} -> ${latestVersion}`
65
+ : null
66
+ };
67
+ }
68
+ catch {
69
+ return {
70
+ hasUpdate: false,
71
+ currentVersion: pkgVersion,
72
+ latestVersion: null,
73
+ message: null
74
+ };
75
+ }
76
+ };
package/index.d.ts ADDED
@@ -0,0 +1,8 @@
1
+ export { extractFirst } from './argv';
2
+ export type { ParsedArgs } from './argv';
3
+ export { cliExitWithError } from './cli-error';
4
+ export type { CliExitOptions } from './cli-error';
5
+ export { checkForUpdates } from './update-check';
6
+ export type { UpdateCheckOptions, UpdateCheckResult } from './update-check';
7
+ export { getSelfPackageJson, getSelfVersion, getSelfName } from './package-json';
8
+ export type { PackageJsonInfo } from './package-json';
package/index.js ADDED
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getSelfName = exports.getSelfVersion = exports.getSelfPackageJson = exports.checkForUpdates = exports.cliExitWithError = exports.extractFirst = void 0;
4
+ // Argv utilities
5
+ var argv_1 = require("./argv");
6
+ Object.defineProperty(exports, "extractFirst", { enumerable: true, get: function () { return argv_1.extractFirst; } });
7
+ // CLI error handling
8
+ var cli_error_1 = require("./cli-error");
9
+ Object.defineProperty(exports, "cliExitWithError", { enumerable: true, get: function () { return cli_error_1.cliExitWithError; } });
10
+ // Update checking
11
+ var update_check_1 = require("./update-check");
12
+ Object.defineProperty(exports, "checkForUpdates", { enumerable: true, get: function () { return update_check_1.checkForUpdates; } });
13
+ // Package.json utilities
14
+ var package_json_1 = require("./package-json");
15
+ Object.defineProperty(exports, "getSelfPackageJson", { enumerable: true, get: function () { return package_json_1.getSelfPackageJson; } });
16
+ Object.defineProperty(exports, "getSelfVersion", { enumerable: true, get: function () { return package_json_1.getSelfVersion; } });
17
+ Object.defineProperty(exports, "getSelfName", { enumerable: true, get: function () { return package_json_1.getSelfName; } });
@@ -0,0 +1,18 @@
1
+ export interface PackageJsonInfo {
2
+ name: string;
3
+ version: string;
4
+ [key: string]: any;
5
+ }
6
+ /**
7
+ * Gets the package.json for the current package by searching up from the given directory.
8
+ * This is useful for CLIs to get their own version information.
9
+ */
10
+ export declare const getSelfPackageJson: (dirname: string) => PackageJsonInfo;
11
+ /**
12
+ * Gets the version from the package.json for the current package.
13
+ */
14
+ export declare const getSelfVersion: (dirname: string) => string;
15
+ /**
16
+ * Gets the name from the package.json for the current package.
17
+ */
18
+ export declare const getSelfName: (dirname: string) => string;
@@ -0,0 +1,26 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getSelfName = exports.getSelfVersion = exports.getSelfPackageJson = void 0;
4
+ const find_and_require_package_json_1 = require("find-and-require-package-json");
5
+ /**
6
+ * Gets the package.json for the current package by searching up from the given directory.
7
+ * This is useful for CLIs to get their own version information.
8
+ */
9
+ const getSelfPackageJson = (dirname) => {
10
+ return (0, find_and_require_package_json_1.findAndRequirePackageJson)(dirname);
11
+ };
12
+ exports.getSelfPackageJson = getSelfPackageJson;
13
+ /**
14
+ * Gets the version from the package.json for the current package.
15
+ */
16
+ const getSelfVersion = (dirname) => {
17
+ return (0, exports.getSelfPackageJson)(dirname).version;
18
+ };
19
+ exports.getSelfVersion = getSelfVersion;
20
+ /**
21
+ * Gets the name from the package.json for the current package.
22
+ */
23
+ const getSelfName = (dirname) => {
24
+ return (0, exports.getSelfPackageJson)(dirname).name;
25
+ };
26
+ exports.getSelfName = getSelfName;
package/package.json ADDED
@@ -0,0 +1,41 @@
1
+ {
2
+ "name": "@genomic/utils",
3
+ "version": "2.0.0",
4
+ "author": "Constructive <developers@constructive.io>",
5
+ "description": "CLI lifecycle utilities for building command-line applications",
6
+ "main": "index.js",
7
+ "module": "esm/index.js",
8
+ "types": "index.d.ts",
9
+ "homepage": "https://github.com/constructive-io/dev-utils",
10
+ "license": "MIT",
11
+ "publishConfig": {
12
+ "access": "public",
13
+ "directory": "dist"
14
+ },
15
+ "repository": {
16
+ "type": "git",
17
+ "url": "https://github.com/constructive-io/dev-utils"
18
+ },
19
+ "bugs": {
20
+ "url": "https://github.com/constructive-io/dev-utils/issues"
21
+ },
22
+ "scripts": {
23
+ "copy": "makage assets",
24
+ "clean": "makage clean",
25
+ "prepublishOnly": "npm run build",
26
+ "build": "makage build",
27
+ "test": "jest --passWithNoTests",
28
+ "test:watch": "jest --watch"
29
+ },
30
+ "dependencies": {
31
+ "appstash": "0.2.6",
32
+ "find-and-require-package-json": "0.8.2",
33
+ "minimist": "^1.2.8"
34
+ },
35
+ "devDependencies": {
36
+ "@types/minimist": "^1.2.5",
37
+ "makage": "0.1.8"
38
+ },
39
+ "keywords": [],
40
+ "gitHead": "59317e6ae9ba291aebdee3098e456d4ef4e1a5dc"
41
+ }
@@ -0,0 +1,18 @@
1
+ export interface UpdateCheckOptions {
2
+ pkgName: string;
3
+ pkgVersion: string;
4
+ registryBaseUrl?: string;
5
+ toolName?: string;
6
+ ttl?: number;
7
+ }
8
+ export interface UpdateCheckResult {
9
+ hasUpdate: boolean;
10
+ currentVersion: string;
11
+ latestVersion: string | null;
12
+ message: string | null;
13
+ }
14
+ /**
15
+ * Checks for updates to a package and caches the result.
16
+ * Uses appstash for configuration storage.
17
+ */
18
+ export declare const checkForUpdates: (options: UpdateCheckOptions) => Promise<UpdateCheckResult>;
@@ -0,0 +1,113 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.checkForUpdates = void 0;
37
+ const appstash_1 = require("appstash");
38
+ const fs = __importStar(require("fs"));
39
+ const path = __importStar(require("path"));
40
+ const DEFAULT_TTL = 24 * 60 * 60 * 1000; // 24 hours
41
+ const DEFAULT_REGISTRY = 'https://registry.npmjs.org';
42
+ /**
43
+ * Checks for updates to a package and caches the result.
44
+ * Uses appstash for configuration storage.
45
+ */
46
+ const checkForUpdates = async (options) => {
47
+ const { pkgName, pkgVersion, registryBaseUrl = DEFAULT_REGISTRY, toolName = pkgName, ttl = DEFAULT_TTL } = options;
48
+ const dirs = (0, appstash_1.appstash)(toolName);
49
+ const cacheFile = path.join(dirs.cache, 'update-check.json');
50
+ // Check cache first
51
+ try {
52
+ if (fs.existsSync(cacheFile)) {
53
+ const cached = JSON.parse(fs.readFileSync(cacheFile, 'utf-8'));
54
+ if (Date.now() - cached.timestamp < ttl) {
55
+ return {
56
+ hasUpdate: cached.latestVersion !== pkgVersion && cached.latestVersion > pkgVersion,
57
+ currentVersion: pkgVersion,
58
+ latestVersion: cached.latestVersion,
59
+ message: cached.latestVersion > pkgVersion
60
+ ? `Update available: ${pkgVersion} -> ${cached.latestVersion}`
61
+ : null
62
+ };
63
+ }
64
+ }
65
+ }
66
+ catch {
67
+ // Cache read failed, continue to fetch
68
+ }
69
+ // Fetch latest version from registry
70
+ try {
71
+ const response = await fetch(`${registryBaseUrl}/${pkgName}/latest`);
72
+ if (!response.ok) {
73
+ return {
74
+ hasUpdate: false,
75
+ currentVersion: pkgVersion,
76
+ latestVersion: null,
77
+ message: null
78
+ };
79
+ }
80
+ const data = await response.json();
81
+ const latestVersion = data.version;
82
+ // Cache the result
83
+ try {
84
+ if (!fs.existsSync(dirs.cache)) {
85
+ fs.mkdirSync(dirs.cache, { recursive: true });
86
+ }
87
+ fs.writeFileSync(cacheFile, JSON.stringify({
88
+ latestVersion,
89
+ timestamp: Date.now()
90
+ }));
91
+ }
92
+ catch {
93
+ // Cache write failed, continue anyway
94
+ }
95
+ return {
96
+ hasUpdate: latestVersion !== pkgVersion && latestVersion > pkgVersion,
97
+ currentVersion: pkgVersion,
98
+ latestVersion,
99
+ message: latestVersion > pkgVersion
100
+ ? `Update available: ${pkgVersion} -> ${latestVersion}`
101
+ : null
102
+ };
103
+ }
104
+ catch {
105
+ return {
106
+ hasUpdate: false,
107
+ currentVersion: pkgVersion,
108
+ latestVersion: null,
109
+ message: null
110
+ };
111
+ }
112
+ };
113
+ exports.checkForUpdates = checkForUpdates;