@ryanatkn/gro 0.189.3 → 0.190.1
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/dist/build_cache.d.ts +1 -1
- package/dist/build_cache.d.ts.map +1 -1
- package/dist/build_cache.js +7 -7
- package/dist/dev.task.d.ts +1 -1
- package/dist/dev.task.d.ts.map +1 -1
- package/dist/filer.d.ts.map +1 -1
- package/dist/filer.js +2 -2
- package/dist/gro_config.d.ts +11 -0
- package/dist/gro_config.d.ts.map +1 -1
- package/dist/gro_config.js +8 -4
- package/dist/invoke_task.js +1 -1
- package/package.json +8 -8
- package/src/lib/build_cache.ts +8 -8
- package/src/lib/dev.task.ts +1 -1
- package/src/lib/filer.ts +2 -2
- package/src/lib/gro_config.ts +19 -3
- package/src/lib/invoke_task.ts +1 -1
- package/dist/hash.d.ts +0 -11
- package/dist/hash.d.ts.map +0 -1
- package/dist/hash.js +0 -21
- package/src/lib/hash.ts +0 -26
package/dist/build_cache.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type { Logger } from '@fuzdev/fuz_util/log.js';
|
|
2
1
|
import { z } from 'zod';
|
|
2
|
+
import type { Logger } from '@fuzdev/fuz_util/log.js';
|
|
3
3
|
import type { GroConfig } from './gro_config.ts';
|
|
4
4
|
export declare const BUILD_CACHE_METADATA_FILENAME = "build.json";
|
|
5
5
|
export declare const BUILD_CACHE_VERSION = "1";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"build_cache.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/build_cache.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"build_cache.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/build_cache.ts"],"names":[],"mappings":"AAGA,OAAO,EAAC,CAAC,EAAC,MAAM,KAAK,CAAC;AACtB,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,yBAAyB,CAAC;AAMpD,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,iBAAiB,CAAC;AAI/C,eAAO,MAAM,6BAA6B,eAAe,CAAC;AAC1D,eAAO,MAAM,mBAAmB,MAAM,CAAC;AAEvC;;;GAGG;AACH,eAAO,MAAM,gBAAgB;;;;;;;kBAW3B,CAAC;AACH,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAEhE;;;GAGG;AACH,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;kBAU7B,CAAC;AACH,MAAM,MAAM,kBAAkB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAEpE;;;;;;;GAOG;AACH,eAAO,MAAM,uBAAuB,GACnC,QAAQ,SAAS,EACjB,KAAK,MAAM,EACX,aAAa,MAAM,GAAG,IAAI,KACxB,OAAO,CAAC;IACV,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,uBAAuB,EAAE,MAAM,CAAC;CAChC,CAYA,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,yBAAyB,QAAa,OAAO,CAAC,kBAAkB,GAAG,IAAI,CAoCnF,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,yBAAyB,GACrC,UAAU,kBAAkB,EAC5B,MAAM,MAAM,KACV,OAAO,CAAC,IAAI,CAcd,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,oBAAoB,GAAU,UAAU,kBAAkB,KAAG,OAAO,CAAC,OAAO,CAmCxF,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,oBAAoB,GAChC,QAAQ,SAAS,EACjB,KAAK,MAAM,EACX,aAAa,MAAM,GAAG,IAAI,KACxB,OAAO,CAAC,OAAO,CA+BjB,CAAC;AAEF;;;;;;;;GAQG;AACH,eAAO,MAAM,qBAAqB,GACjC,YAAY,KAAK,CAAC,MAAM,CAAC,KACvB,OAAO,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAkEjC,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,0BAA0B,QAAa,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,CAkCxE,CAAC;AAEF;;;;;;;;GAQG;AACH,eAAO,MAAM,2BAA2B,GACvC,QAAQ,SAAS,EACjB,KAAK,MAAM,EACX,aAAa,MAAM,GAAG,IAAI,EAC1B,aAAa,KAAK,CAAC,MAAM,CAAC,KACxB,OAAO,CAAC,kBAAkB,CAW5B,CAAC"}
|
package/dist/build_cache.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { mkdir, readdir, readFile, rm, stat, writeFile } from 'node:fs/promises';
|
|
2
2
|
import { join } from 'node:path';
|
|
3
3
|
import { styleText as st } from 'node:util';
|
|
4
|
+
import { z } from 'zod';
|
|
4
5
|
import { git_current_commit_hash } from '@fuzdev/fuz_util/git.js';
|
|
5
6
|
import { fs_exists } from '@fuzdev/fuz_util/fs.js';
|
|
6
7
|
import { map_concurrent } from '@fuzdev/fuz_util/async.js';
|
|
7
|
-
import {
|
|
8
|
-
import { to_hash } from "./hash.js";
|
|
8
|
+
import { hash_secure } from '@fuzdev/fuz_util/hash.js';
|
|
9
9
|
import { paths } from "./paths.js";
|
|
10
10
|
import { SVELTEKIT_BUILD_DIRNAME, SVELTEKIT_DIST_DIRNAME, GRO_DIST_PREFIX } from "./constants.js";
|
|
11
11
|
export const BUILD_CACHE_METADATA_FILENAME = 'build.json';
|
|
@@ -142,7 +142,7 @@ export const validate_build_cache = async (metadata) => {
|
|
|
142
142
|
const results = await map_concurrent(metadata.outputs, async (output) => {
|
|
143
143
|
try {
|
|
144
144
|
const contents = await readFile(output.path);
|
|
145
|
-
const actual_hash = await
|
|
145
|
+
const actual_hash = await hash_secure(contents);
|
|
146
146
|
return actual_hash === output.hash;
|
|
147
147
|
}
|
|
148
148
|
catch {
|
|
@@ -197,7 +197,7 @@ export const is_build_cache_valid = async (config, log, git_commit) => {
|
|
|
197
197
|
* @param build_dirs Array of output directories to scan (e.g., ['build', 'dist', 'dist_server'])
|
|
198
198
|
*/
|
|
199
199
|
export const collect_build_outputs = async (build_dirs) => {
|
|
200
|
-
const
|
|
200
|
+
const files_hash_secure = [];
|
|
201
201
|
// Recursively collect files
|
|
202
202
|
const collect_files = async (dir, relative_base, dir_prefix) => {
|
|
203
203
|
const entries = await readdir(dir, { withFileTypes: true });
|
|
@@ -214,7 +214,7 @@ export const collect_build_outputs = async (build_dirs) => {
|
|
|
214
214
|
await collect_files(full_path, relative_path, dir_prefix);
|
|
215
215
|
}
|
|
216
216
|
else if (entry.isFile()) {
|
|
217
|
-
|
|
217
|
+
files_hash_secure.push({ full_path, cache_key });
|
|
218
218
|
}
|
|
219
219
|
// Symlinks are intentionally ignored - we only hash regular files
|
|
220
220
|
}
|
|
@@ -229,10 +229,10 @@ export const collect_build_outputs = async (build_dirs) => {
|
|
|
229
229
|
await collect_files(build_dir, '', build_dir);
|
|
230
230
|
}
|
|
231
231
|
// Hash files with controlled concurrency and collect stats (could be 10k+ files)
|
|
232
|
-
return map_concurrent(
|
|
232
|
+
return map_concurrent(files_hash_secure, async ({ full_path, cache_key }) => {
|
|
233
233
|
const stats = await stat(full_path);
|
|
234
234
|
const contents = await readFile(full_path);
|
|
235
|
-
const hash = await
|
|
235
|
+
const hash = await hash_secure(contents);
|
|
236
236
|
return {
|
|
237
237
|
path: cache_key,
|
|
238
238
|
hash,
|
package/dist/dev.task.d.ts
CHANGED
|
@@ -10,7 +10,7 @@ export declare const Args: z.ZodObject<{
|
|
|
10
10
|
install: z.ZodDefault<z.ZodBoolean>;
|
|
11
11
|
}, z.core.$strict>;
|
|
12
12
|
export type Args = z.infer<typeof Args>;
|
|
13
|
-
export type
|
|
13
|
+
export type DevTaskContext = PluginContext<Args>;
|
|
14
14
|
/** @nodocs */
|
|
15
15
|
export declare const task: Task<Args>;
|
|
16
16
|
//# sourceMappingURL=dev.task.d.ts.map
|
package/dist/dev.task.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dev.task.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/dev.task.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,CAAC,EAAC,MAAM,KAAK,CAAC;AAEtB,OAAO,KAAK,EAAC,IAAI,EAAC,MAAM,WAAW,CAAC;AACpC,OAAO,EAAU,KAAK,aAAa,EAAC,MAAM,aAAa,CAAC;AAGxD,cAAc;AACd,eAAO,MAAM,IAAI;;;;;;kBAWf,CAAC;AACH,MAAM,MAAM,IAAI,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,IAAI,CAAC,CAAC;AAExC,MAAM,MAAM,
|
|
1
|
+
{"version":3,"file":"dev.task.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/dev.task.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,CAAC,EAAC,MAAM,KAAK,CAAC;AAEtB,OAAO,KAAK,EAAC,IAAI,EAAC,MAAM,WAAW,CAAC;AACpC,OAAO,EAAU,KAAK,aAAa,EAAC,MAAM,aAAa,CAAC;AAGxD,cAAc;AACd,eAAO,MAAM,IAAI;;;;;;kBAWf,CAAC;AACH,MAAM,MAAM,IAAI,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,IAAI,CAAC,CAAC;AAExC,MAAM,MAAM,cAAc,GAAG,aAAa,CAAC,IAAI,CAAC,CAAC;AAEjD,cAAc;AACd,eAAO,MAAM,IAAI,EAAE,IAAI,CAAC,IAAI,CA2B3B,CAAC"}
|
package/dist/filer.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"filer.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/filer.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,2BAA2B,CAAC;AAI1D,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,yBAAyB,CAAC;AACpD,OAAO,KAAK,EAAC,WAAW,EAAC,MAAM,kCAAkC,CAAC;AAClE,OAAO,KAAK,EAAC,UAAU,EAAE,MAAM,EAAC,MAAM,0BAA0B,CAAC;
|
|
1
|
+
{"version":3,"file":"filer.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/filer.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,2BAA2B,CAAC;AAI1D,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,yBAAyB,CAAC;AACpD,OAAO,KAAK,EAAC,WAAW,EAAC,MAAM,kCAAkC,CAAC;AAClE,OAAO,KAAK,EAAC,UAAU,EAAE,MAAM,EAAC,MAAM,0BAA0B,CAAC;AAGjE,OAAO,EACN,SAAS,EAET,KAAK,aAAa,EAClB,KAAK,eAAe,EAEpB,MAAM,gBAAgB,CAAC;AAOxB,OAAO,KAAK,EAAC,QAAQ,EAAC,MAAM,eAAe,CAAC;AAI5C,MAAM,MAAM,aAAa,GAAG,CAAC,MAAM,EAAE,aAAa,EAAE,QAAQ,EAAE,QAAQ,KAAK,IAAI,CAAC;AAEhF,MAAM,WAAW,YAAY;IAC5B,SAAS,CAAC,EAAE,OAAO,SAAS,CAAC;IAC7B,iBAAiB,CAAC,EAAE,OAAO,CAAC,UAAU,CAAC,eAAe,EAAE,WAAW,CAAC,CAAC,CAAC;IACtE,kBAAkB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;IACjD,GAAG,CAAC,EAAE,MAAM,CAAC;CACb;AAED,qBAAa,KAAK;;IACjB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAG1B,QAAQ,CAAC,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAa;gBAetC,OAAO,GAAE,YAA2B;IAUhD,IAAI,MAAM,IAAI,OAAO,CAEpB;IAED,SAAS,GAAI,IAAI,MAAM,KAAG,QAAQ,GAAG,SAAS,CAE5C;IAEF,aAAa,GAAI,IAAI,MAAM,KAAG,QAAQ,CAqBpC;IAEF,MAAM,CAAC,SAAS,EAAE,CAAC,QAAQ,EAAE,QAAQ,KAAK,OAAO,GAAG,KAAK,CAAC,QAAQ,CAAC,GAAG,IAAI;IAU1E;;;;OAIG;IACG,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAsDrB,KAAK,CAAC,QAAQ,EAAE,aAAa,GAAG,OAAO,CAAC,MAAM,IAAI,CAAC;IAmBzD,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CA8OtB;AAGD,eAAO,MAAM,iBAAiB,GAC7B,UAAU,QAAQ,EAClB,WAAW,CAAC,EAAE,EAAE,MAAM,KAAK,QAAQ,GAAG,SAAS,EAC/C,SAAS,UAAU,EACnB,UAAS,GAAG,CAAC,MAAM,CAAa,EAChC,WAAU,GAAG,CAAC,MAAM,CAAa,EACjC,MAAM,MAAM,KACV,GAAG,CAAC,MAAM,CAuBZ,CAAC"}
|
package/dist/filer.js
CHANGED
|
@@ -4,6 +4,7 @@ import { dirname, resolve } from 'node:path';
|
|
|
4
4
|
import { isBuiltin } from 'node:module';
|
|
5
5
|
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
6
6
|
import { UnreachableError } from '@fuzdev/fuz_util/error.js';
|
|
7
|
+
import { hash_secure } from '@fuzdev/fuz_util/hash.js';
|
|
7
8
|
import { watch_dir, } from "./watch_dir.js";
|
|
8
9
|
import { paths } from "./paths.js";
|
|
9
10
|
import { parse_imports } from "./parse_imports.js";
|
|
@@ -11,7 +12,6 @@ import { resolve_specifier } from "./resolve_specifier.js";
|
|
|
11
12
|
import { default_svelte_config } from "./svelte_config.js";
|
|
12
13
|
import { map_sveltekit_aliases } from "./sveltekit_helpers.js";
|
|
13
14
|
import { SVELTEKIT_GLOBAL_SPECIFIER } from "./constants.js";
|
|
14
|
-
import { to_hash } from "./hash.js";
|
|
15
15
|
const aliases = Object.entries(default_svelte_config.alias);
|
|
16
16
|
export class Filer {
|
|
17
17
|
root_dir;
|
|
@@ -201,7 +201,7 @@ export class Filer {
|
|
|
201
201
|
}
|
|
202
202
|
}
|
|
203
203
|
// Compute hash for new contents
|
|
204
|
-
const new_hash = new_contents !== null ? await
|
|
204
|
+
const new_hash = new_contents !== null ? await hash_secure(new_contents) : null;
|
|
205
205
|
file.ctime = stats?.ctimeMs ?? null;
|
|
206
206
|
file.mtime = stats?.mtimeMs ?? null;
|
|
207
207
|
// Use hash comparison for change detection (content-based, not mtime-based)
|
package/dist/gro_config.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ import type { PathFilter, PathId } from '@fuzdev/fuz_util/path.js';
|
|
|
2
2
|
import type { PluginsCreateConfig } from './plugin.ts';
|
|
3
3
|
import type { PackageJsonMapper } from './package_json.ts';
|
|
4
4
|
import type { ParsedSvelteConfig } from './svelte_config.ts';
|
|
5
|
+
import type { FilerOptions } from './filer.ts';
|
|
5
6
|
/**
|
|
6
7
|
* SHA-256 hash of empty string, used for configs without build_cache_config.
|
|
7
8
|
* This ensures consistent cache behavior when no custom config is provided.
|
|
@@ -50,6 +51,11 @@ export interface GroConfig extends RawGroConfig {
|
|
|
50
51
|
* @see RawGroConfig.build_cache_config
|
|
51
52
|
*/
|
|
52
53
|
build_cache_config_hash: string;
|
|
54
|
+
/**
|
|
55
|
+
* Options passed to the `Filer` for file watching and import resolution.
|
|
56
|
+
* @see FilerOptions
|
|
57
|
+
*/
|
|
58
|
+
filer_options: Partial<FilerOptions> | null;
|
|
53
59
|
}
|
|
54
60
|
/**
|
|
55
61
|
* The relaxed variant of `GroConfig` that users can provide via `gro.config.ts`.
|
|
@@ -79,6 +85,11 @@ export interface RawGroConfig {
|
|
|
79
85
|
* during config normalization. The raw value is never logged or persisted.
|
|
80
86
|
*/
|
|
81
87
|
build_cache_config?: Record<string, unknown> | (() => Record<string, unknown> | Promise<Record<string, unknown>>);
|
|
88
|
+
/**
|
|
89
|
+
* Options passed to the `Filer` for file watching and import resolution.
|
|
90
|
+
* @see FilerOptions
|
|
91
|
+
*/
|
|
92
|
+
filer_options?: Partial<FilerOptions> | null;
|
|
82
93
|
}
|
|
83
94
|
export type CreateGroConfig = (base_config: GroConfig, svelte_config?: ParsedSvelteConfig) => RawGroConfig | Promise<RawGroConfig>;
|
|
84
95
|
export declare const create_empty_gro_config: () => GroConfig;
|
package/dist/gro_config.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gro_config.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/gro_config.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAC,UAAU,EAAE,MAAM,EAAC,MAAM,0BAA0B,CAAC;
|
|
1
|
+
{"version":3,"file":"gro_config.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/gro_config.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAC,UAAU,EAAE,MAAM,EAAC,MAAM,0BAA0B,CAAC;AAejE,OAAO,KAAK,EAAC,mBAAmB,EAAC,MAAM,aAAa,CAAC;AACrD,OAAO,KAAK,EAAC,iBAAiB,EAAC,MAAM,mBAAmB,CAAC;AACzD,OAAO,KAAK,EAAC,kBAAkB,EAAC,MAAM,oBAAoB,CAAC;AAC3D,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,YAAY,CAAC;AAE7C;;;GAGG;AACH,eAAO,MAAM,6BAA6B,qEACyB,CAAC;AAEpE;;;;GAIG;AACH,MAAM,WAAW,SAAU,SAAQ,YAAY;IAC9C;;OAEG;IACH,OAAO,EAAE,mBAAmB,CAAC;IAC7B;;;;OAIG;IACH,gBAAgB,EAAE,iBAAiB,GAAG,IAAI,CAAC;IAC3C;;;OAGG;IACH,cAAc,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IAC9B;;;OAGG;IACH,cAAc,EAAE,KAAK,CAAC,UAAU,CAAC,CAAC;IAClC;;OAEG;IACH,MAAM,EAAE,MAAM,CAAC;IACf;;OAEG;IACH,MAAM,EAAE,MAAM,CAAC;IACf,sCAAsC;IACtC,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC;;;;;OAKG;IACH,uBAAuB,EAAE,MAAM,CAAC;IAChC;;;OAGG;IACH,aAAa,EAAE,OAAO,CAAC,YAAY,CAAC,GAAG,IAAI,CAAC;CAC5C;AAED;;;;GAIG;AACH,MAAM,WAAW,YAAY;IAC5B,OAAO,CAAC,EAAE,mBAAmB,CAAC;IAC9B,gBAAgB,CAAC,EAAE,iBAAiB,GAAG,IAAI,CAAC;IAC5C,cAAc,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IAC/B,cAAc,CAAC,EAAE,UAAU,GAAG,KAAK,CAAC,UAAU,CAAC,GAAG,IAAI,CAAC;IACvD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;;;;;;;;;;;;OAcG;IACH,kBAAkB,CAAC,EAChB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GACvB,CAAC,MAAM,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC;IACtE;;;OAGG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,GAAG,IAAI,CAAC;CAC7C;AAED,MAAM,MAAM,eAAe,GAAG,CAC7B,WAAW,EAAE,SAAS,EACtB,aAAa,CAAC,EAAE,kBAAkB,KAC9B,YAAY,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC;AAE1C,eAAO,MAAM,uBAAuB,QAAO,SAczC,CAAC;AAEH;;;;;GAKG;AACH,eAAO,MAAM,uBAAuB,QAYnC,CAAC;AAEF,eAAO,MAAM,wBAAwB,QAA+C,CAAC;AAErF;;;;GAIG;AACH,eAAO,MAAM,eAAe,GAAU,YAAY,YAAY,KAAG,OAAO,CAAC,SAAS,CA+CjF,CAAC;AAEF,MAAM,WAAW,eAAe;IAC/B,QAAQ,CAAC,OAAO,EAAE,YAAY,GAAG,eAAe,CAAC;CACjD;AAED,eAAO,MAAM,eAAe,GAAU,YAAgB,KAAG,OAAO,CAAC,SAAS,CAqBzE,CAAC;AAEF,eAAO,MAAM,0BAA0B,EAAE,CACxC,aAAa,EAAE,GAAG,EAClB,WAAW,EAAE,MAAM,KACf,OAAO,CAAC,aAAa,IAAI,eAS7B,CAAC"}
|
package/dist/gro_config.js
CHANGED
|
@@ -10,10 +10,10 @@ import { join, resolve } from 'node:path';
|
|
|
10
10
|
import { fs_exists } from '@fuzdev/fuz_util/fs.js';
|
|
11
11
|
import { identity } from '@fuzdev/fuz_util/function.js';
|
|
12
12
|
import { json_stringify_deterministic } from '@fuzdev/fuz_util/json.js';
|
|
13
|
+
import { hash_secure } from '@fuzdev/fuz_util/hash.js';
|
|
13
14
|
import { GRO_DIST_DIR, IS_THIS_GRO, paths } from "./paths.js";
|
|
14
15
|
import { GRO_CONFIG_FILENAME, JS_CLI_DEFAULT, NODE_MODULES_DIRNAME, PM_CLI_DEFAULT, SERVER_DIST_PATH, SVELTEKIT_BUILD_DIRNAME, SVELTEKIT_DIST_DIRNAME, } from "./constants.js";
|
|
15
16
|
import create_default_config from "./gro.config.default.js";
|
|
16
|
-
import { to_hash } from "./hash.js";
|
|
17
17
|
/**
|
|
18
18
|
* SHA-256 hash of empty string, used for configs without build_cache_config.
|
|
19
19
|
* This ensures consistent cache behavior when no custom config is provided.
|
|
@@ -32,6 +32,7 @@ export const create_empty_gro_config = () => ({
|
|
|
32
32
|
js_cli: JS_CLI_DEFAULT,
|
|
33
33
|
pm_cli: PM_CLI_DEFAULT,
|
|
34
34
|
build_cache_config_hash: EMPTY_BUILD_CACHE_CONFIG_HASH,
|
|
35
|
+
filer_options: null,
|
|
35
36
|
});
|
|
36
37
|
/**
|
|
37
38
|
* The regexp used by default to exclude directories and files
|
|
@@ -44,7 +45,9 @@ export const SEARCH_EXCLUDER_DEFAULT = new RegExp(`(${'(^|/)\\.[^/]+' + // exclu
|
|
|
44
45
|
`|(^|/)${NODE_MODULES_DIRNAME}(?!/(@[^/]+/)?gro/${SVELTEKIT_DIST_DIRNAME})` + // exclude `node_modules` unless it's to the Gro directory
|
|
45
46
|
`|(^|/)${SVELTEKIT_BUILD_DIRNAME}` + // exclude the SvelteKit build directory
|
|
46
47
|
`|(^|/)(?<!(^|/)gro/)${SVELTEKIT_DIST_DIRNAME}` + // exclude the SvelteKit dist directory unless it's in the Gro directory
|
|
47
|
-
`|(^|/)${SERVER_DIST_PATH}` // exclude the Gro server plugin dist directory
|
|
48
|
+
`|(^|/)${SERVER_DIST_PATH}` + // exclude the Gro server plugin dist directory
|
|
49
|
+
'|(^|/)test' + // exclude test directories
|
|
50
|
+
'|(^|/)benchmark' // exclude benchmark directories
|
|
48
51
|
})($|/)`, 'u');
|
|
49
52
|
export const EXPORTS_EXCLUDER_DEFAULT = /(\.md|\.(test|ignore)\.|\/(test|ignore)\/)/;
|
|
50
53
|
/**
|
|
@@ -56,7 +59,7 @@ export const cook_gro_config = async (raw_config) => {
|
|
|
56
59
|
const empty_config = create_empty_gro_config();
|
|
57
60
|
// All of the raw config properties are optional,
|
|
58
61
|
// so fall back to the empty values when `undefined`.
|
|
59
|
-
const { plugins = empty_config.plugins, map_package_json = empty_config.map_package_json, task_root_dirs = empty_config.task_root_dirs, search_filters = empty_config.search_filters, js_cli = empty_config.js_cli, pm_cli = empty_config.pm_cli, build_cache_config, } = raw_config;
|
|
62
|
+
const { plugins = empty_config.plugins, map_package_json = empty_config.map_package_json, task_root_dirs = empty_config.task_root_dirs, search_filters = empty_config.search_filters, js_cli = empty_config.js_cli, pm_cli = empty_config.pm_cli, build_cache_config, filer_options = empty_config.filer_options, } = raw_config;
|
|
60
63
|
// Hash build_cache_config and delete the raw value
|
|
61
64
|
// IMPORTANT: Raw value may contain secrets - hash it and delete immediately
|
|
62
65
|
let build_cache_config_hash;
|
|
@@ -67,7 +70,7 @@ export const cook_gro_config = async (raw_config) => {
|
|
|
67
70
|
// Resolve if it's a function
|
|
68
71
|
const resolved = typeof build_cache_config === 'function' ? await build_cache_config() : build_cache_config;
|
|
69
72
|
// Hash the JSON representation with deterministic key ordering
|
|
70
|
-
build_cache_config_hash = await
|
|
73
|
+
build_cache_config_hash = await hash_secure(json_stringify_deterministic(resolved));
|
|
71
74
|
}
|
|
72
75
|
// Delete the raw value to ensure it doesn't persist in memory
|
|
73
76
|
delete raw_config.build_cache_config;
|
|
@@ -83,6 +86,7 @@ export const cook_gro_config = async (raw_config) => {
|
|
|
83
86
|
js_cli,
|
|
84
87
|
pm_cli,
|
|
85
88
|
build_cache_config_hash,
|
|
89
|
+
filer_options: filer_options ?? null,
|
|
86
90
|
};
|
|
87
91
|
};
|
|
88
92
|
export const load_gro_config = async (dir = paths.root) => {
|
package/dist/invoke_task.js
CHANGED
|
@@ -38,7 +38,7 @@ export const invoke_task = async (task_name, args, config, initial_filer, initia
|
|
|
38
38
|
log.info('invoking', task_name ? st('cyan', task_name) : 'gro');
|
|
39
39
|
// track if we created the filer
|
|
40
40
|
const owns_filer = !initial_filer;
|
|
41
|
-
const filer = initial_filer ?? new Filer({ log: log.child('filer') });
|
|
41
|
+
const filer = initial_filer ?? new Filer({ log: log.child('filer'), ...config.filer_options });
|
|
42
42
|
const owns_timings = !initial_timings;
|
|
43
43
|
const timings = initial_timings ?? new Timings();
|
|
44
44
|
const total_timing = create_stopwatch();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ryanatkn/gro",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.190.1",
|
|
4
4
|
"description": "task runner and toolkit extending SvelteKit",
|
|
5
5
|
"motto": "generate, run, optimize",
|
|
6
6
|
"glyph": "🌰",
|
|
@@ -59,7 +59,7 @@
|
|
|
59
59
|
"zod": "^4.1.13"
|
|
60
60
|
},
|
|
61
61
|
"peerDependencies": {
|
|
62
|
-
"@fuzdev/fuz_util": ">=0.48.
|
|
62
|
+
"@fuzdev/fuz_util": ">=0.48.3",
|
|
63
63
|
"@sveltejs/kit": "^2",
|
|
64
64
|
"esbuild": "^0.27.0",
|
|
65
65
|
"svelte": "^5",
|
|
@@ -80,10 +80,10 @@
|
|
|
80
80
|
"devDependencies": {
|
|
81
81
|
"@changesets/changelog-git": "^0.2.1",
|
|
82
82
|
"@changesets/types": "^6.1.0",
|
|
83
|
-
"@fuzdev/fuz_code": "^0.
|
|
84
|
-
"@fuzdev/fuz_css": "^0.
|
|
85
|
-
"@fuzdev/fuz_ui": "^0.
|
|
86
|
-
"@fuzdev/fuz_util": "^0.48.
|
|
83
|
+
"@fuzdev/fuz_code": "^0.41.0",
|
|
84
|
+
"@fuzdev/fuz_css": "^0.47.0",
|
|
85
|
+
"@fuzdev/fuz_ui": "^0.181.1",
|
|
86
|
+
"@fuzdev/fuz_util": "^0.48.3",
|
|
87
87
|
"@ryanatkn/eslint-config": "^0.9.0",
|
|
88
88
|
"@sveltejs/adapter-static": "^3.0.10",
|
|
89
89
|
"@sveltejs/kit": "^2.50.1",
|
|
@@ -94,8 +94,8 @@
|
|
|
94
94
|
"esbuild": "^0.27.1",
|
|
95
95
|
"eslint": "^9.39.1",
|
|
96
96
|
"eslint-plugin-svelte": "^3.13.1",
|
|
97
|
-
"svelte": "^5.
|
|
98
|
-
"svelte-check": "^4.3.
|
|
97
|
+
"svelte": "^5.49.1",
|
|
98
|
+
"svelte-check": "^4.3.6",
|
|
99
99
|
"typescript": "^5.9.3",
|
|
100
100
|
"typescript-eslint": "^8.48.1",
|
|
101
101
|
"vitest": "^4.0.15"
|
package/src/lib/build_cache.ts
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import {mkdir, readdir, readFile, rm, stat, writeFile} from 'node:fs/promises';
|
|
2
2
|
import {join} from 'node:path';
|
|
3
|
-
import type {Logger} from '@fuzdev/fuz_util/log.js';
|
|
4
3
|
import {styleText as st} from 'node:util';
|
|
4
|
+
import {z} from 'zod';
|
|
5
|
+
import type {Logger} from '@fuzdev/fuz_util/log.js';
|
|
5
6
|
import {git_current_commit_hash} from '@fuzdev/fuz_util/git.js';
|
|
6
7
|
import {fs_exists} from '@fuzdev/fuz_util/fs.js';
|
|
7
8
|
import {map_concurrent} from '@fuzdev/fuz_util/async.js';
|
|
8
|
-
import {
|
|
9
|
+
import {hash_secure} from '@fuzdev/fuz_util/hash.js';
|
|
9
10
|
|
|
10
|
-
import {to_hash} from './hash.ts';
|
|
11
11
|
import type {GroConfig} from './gro_config.ts';
|
|
12
12
|
import {paths} from './paths.ts';
|
|
13
13
|
import {SVELTEKIT_BUILD_DIRNAME, SVELTEKIT_DIST_DIRNAME, GRO_DIST_PREFIX} from './constants.ts';
|
|
@@ -174,7 +174,7 @@ export const validate_build_cache = async (metadata: BuildCacheMetadata): Promis
|
|
|
174
174
|
async (output) => {
|
|
175
175
|
try {
|
|
176
176
|
const contents = await readFile(output.path);
|
|
177
|
-
const actual_hash = await
|
|
177
|
+
const actual_hash = await hash_secure(contents);
|
|
178
178
|
return actual_hash === output.hash;
|
|
179
179
|
} catch {
|
|
180
180
|
// File deleted/inaccessible between checks = cache invalid
|
|
@@ -249,7 +249,7 @@ export const collect_build_outputs = async (
|
|
|
249
249
|
cache_key: string;
|
|
250
250
|
}
|
|
251
251
|
|
|
252
|
-
const
|
|
252
|
+
const files_hash_secure: Array<FileEntry> = [];
|
|
253
253
|
|
|
254
254
|
// Recursively collect files
|
|
255
255
|
const collect_files = async (
|
|
@@ -273,7 +273,7 @@ export const collect_build_outputs = async (
|
|
|
273
273
|
// eslint-disable-next-line no-await-in-loop
|
|
274
274
|
await collect_files(full_path, relative_path, dir_prefix);
|
|
275
275
|
} else if (entry.isFile()) {
|
|
276
|
-
|
|
276
|
+
files_hash_secure.push({full_path, cache_key});
|
|
277
277
|
}
|
|
278
278
|
// Symlinks are intentionally ignored - we only hash regular files
|
|
279
279
|
}
|
|
@@ -291,11 +291,11 @@ export const collect_build_outputs = async (
|
|
|
291
291
|
|
|
292
292
|
// Hash files with controlled concurrency and collect stats (could be 10k+ files)
|
|
293
293
|
return map_concurrent(
|
|
294
|
-
|
|
294
|
+
files_hash_secure,
|
|
295
295
|
async ({full_path, cache_key}): Promise<BuildOutputEntry> => {
|
|
296
296
|
const stats = await stat(full_path);
|
|
297
297
|
const contents = await readFile(full_path);
|
|
298
|
-
const hash = await
|
|
298
|
+
const hash = await hash_secure(contents);
|
|
299
299
|
|
|
300
300
|
return {
|
|
301
301
|
path: cache_key,
|
package/src/lib/dev.task.ts
CHANGED
package/src/lib/filer.ts
CHANGED
|
@@ -8,6 +8,7 @@ import {UnreachableError} from '@fuzdev/fuz_util/error.js';
|
|
|
8
8
|
import type {Logger} from '@fuzdev/fuz_util/log.js';
|
|
9
9
|
import type {PackageJson} from '@fuzdev/fuz_util/package_json.js';
|
|
10
10
|
import type {FileFilter, PathId} from '@fuzdev/fuz_util/path.js';
|
|
11
|
+
import {hash_secure} from '@fuzdev/fuz_util/hash.js';
|
|
11
12
|
|
|
12
13
|
import {
|
|
13
14
|
watch_dir,
|
|
@@ -23,7 +24,6 @@ import {default_svelte_config} from './svelte_config.ts';
|
|
|
23
24
|
import {map_sveltekit_aliases} from './sveltekit_helpers.ts';
|
|
24
25
|
import {SVELTEKIT_GLOBAL_SPECIFIER} from './constants.ts';
|
|
25
26
|
import type {Disknode} from './disknode.ts';
|
|
26
|
-
import {to_hash} from './hash.ts';
|
|
27
27
|
|
|
28
28
|
const aliases = Object.entries(default_svelte_config.alias);
|
|
29
29
|
|
|
@@ -245,7 +245,7 @@ export class Filer {
|
|
|
245
245
|
}
|
|
246
246
|
|
|
247
247
|
// Compute hash for new contents
|
|
248
|
-
const new_hash = new_contents !== null ? await
|
|
248
|
+
const new_hash = new_contents !== null ? await hash_secure(new_contents) : null;
|
|
249
249
|
|
|
250
250
|
file.ctime = stats?.ctimeMs ?? null;
|
|
251
251
|
file.mtime = stats?.mtimeMs ?? null;
|
package/src/lib/gro_config.ts
CHANGED
|
@@ -3,6 +3,7 @@ import {fs_exists} from '@fuzdev/fuz_util/fs.js';
|
|
|
3
3
|
import {identity} from '@fuzdev/fuz_util/function.js';
|
|
4
4
|
import type {PathFilter, PathId} from '@fuzdev/fuz_util/path.js';
|
|
5
5
|
import {json_stringify_deterministic} from '@fuzdev/fuz_util/json.js';
|
|
6
|
+
import {hash_secure} from '@fuzdev/fuz_util/hash.js';
|
|
6
7
|
|
|
7
8
|
import {GRO_DIST_DIR, IS_THIS_GRO, paths} from './paths.ts';
|
|
8
9
|
import {
|
|
@@ -18,7 +19,7 @@ import create_default_config from './gro.config.default.ts';
|
|
|
18
19
|
import type {PluginsCreateConfig} from './plugin.ts';
|
|
19
20
|
import type {PackageJsonMapper} from './package_json.ts';
|
|
20
21
|
import type {ParsedSvelteConfig} from './svelte_config.ts';
|
|
21
|
-
import {
|
|
22
|
+
import type {FilerOptions} from './filer.ts';
|
|
22
23
|
|
|
23
24
|
/**
|
|
24
25
|
* SHA-256 hash of empty string, used for configs without build_cache_config.
|
|
@@ -70,6 +71,11 @@ export interface GroConfig extends RawGroConfig {
|
|
|
70
71
|
* @see RawGroConfig.build_cache_config
|
|
71
72
|
*/
|
|
72
73
|
build_cache_config_hash: string;
|
|
74
|
+
/**
|
|
75
|
+
* Options passed to the `Filer` for file watching and import resolution.
|
|
76
|
+
* @see FilerOptions
|
|
77
|
+
*/
|
|
78
|
+
filer_options: Partial<FilerOptions> | null;
|
|
73
79
|
}
|
|
74
80
|
|
|
75
81
|
/**
|
|
@@ -102,6 +108,11 @@ export interface RawGroConfig {
|
|
|
102
108
|
build_cache_config?:
|
|
103
109
|
| Record<string, unknown>
|
|
104
110
|
| (() => Record<string, unknown> | Promise<Record<string, unknown>>);
|
|
111
|
+
/**
|
|
112
|
+
* Options passed to the `Filer` for file watching and import resolution.
|
|
113
|
+
* @see FilerOptions
|
|
114
|
+
*/
|
|
115
|
+
filer_options?: Partial<FilerOptions> | null;
|
|
105
116
|
}
|
|
106
117
|
|
|
107
118
|
export type CreateGroConfig = (
|
|
@@ -122,6 +133,7 @@ export const create_empty_gro_config = (): GroConfig => ({
|
|
|
122
133
|
js_cli: JS_CLI_DEFAULT,
|
|
123
134
|
pm_cli: PM_CLI_DEFAULT,
|
|
124
135
|
build_cache_config_hash: EMPTY_BUILD_CACHE_CONFIG_HASH,
|
|
136
|
+
filer_options: null,
|
|
125
137
|
});
|
|
126
138
|
|
|
127
139
|
/**
|
|
@@ -137,7 +149,9 @@ export const SEARCH_EXCLUDER_DEFAULT = new RegExp(
|
|
|
137
149
|
`|(^|/)${NODE_MODULES_DIRNAME}(?!/(@[^/]+/)?gro/${SVELTEKIT_DIST_DIRNAME})` + // exclude `node_modules` unless it's to the Gro directory
|
|
138
150
|
`|(^|/)${SVELTEKIT_BUILD_DIRNAME}` + // exclude the SvelteKit build directory
|
|
139
151
|
`|(^|/)(?<!(^|/)gro/)${SVELTEKIT_DIST_DIRNAME}` + // exclude the SvelteKit dist directory unless it's in the Gro directory
|
|
140
|
-
`|(^|/)${SERVER_DIST_PATH}` // exclude the Gro server plugin dist directory
|
|
152
|
+
`|(^|/)${SERVER_DIST_PATH}` + // exclude the Gro server plugin dist directory
|
|
153
|
+
'|(^|/)test' + // exclude test directories
|
|
154
|
+
'|(^|/)benchmark' // exclude benchmark directories
|
|
141
155
|
})($|/)`,
|
|
142
156
|
'u',
|
|
143
157
|
);
|
|
@@ -162,6 +176,7 @@ export const cook_gro_config = async (raw_config: RawGroConfig): Promise<GroConf
|
|
|
162
176
|
js_cli = empty_config.js_cli,
|
|
163
177
|
pm_cli = empty_config.pm_cli,
|
|
164
178
|
build_cache_config,
|
|
179
|
+
filer_options = empty_config.filer_options,
|
|
165
180
|
} = raw_config;
|
|
166
181
|
|
|
167
182
|
// Hash build_cache_config and delete the raw value
|
|
@@ -175,7 +190,7 @@ export const cook_gro_config = async (raw_config: RawGroConfig): Promise<GroConf
|
|
|
175
190
|
typeof build_cache_config === 'function' ? await build_cache_config() : build_cache_config;
|
|
176
191
|
|
|
177
192
|
// Hash the JSON representation with deterministic key ordering
|
|
178
|
-
build_cache_config_hash = await
|
|
193
|
+
build_cache_config_hash = await hash_secure(json_stringify_deterministic(resolved));
|
|
179
194
|
}
|
|
180
195
|
|
|
181
196
|
// Delete the raw value to ensure it doesn't persist in memory
|
|
@@ -193,6 +208,7 @@ export const cook_gro_config = async (raw_config: RawGroConfig): Promise<GroConf
|
|
|
193
208
|
js_cli,
|
|
194
209
|
pm_cli,
|
|
195
210
|
build_cache_config_hash,
|
|
211
|
+
filer_options: filer_options ?? null,
|
|
196
212
|
};
|
|
197
213
|
};
|
|
198
214
|
|
package/src/lib/invoke_task.ts
CHANGED
|
@@ -50,7 +50,7 @@ export const invoke_task = async (
|
|
|
50
50
|
|
|
51
51
|
// track if we created the filer
|
|
52
52
|
const owns_filer = !initial_filer;
|
|
53
|
-
const filer = initial_filer ?? new Filer({log: log.child('filer')});
|
|
53
|
+
const filer = initial_filer ?? new Filer({log: log.child('filer'), ...config.filer_options});
|
|
54
54
|
|
|
55
55
|
const owns_timings = !initial_timings;
|
|
56
56
|
const timings = initial_timings ?? new Timings();
|
package/dist/hash.d.ts
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Computes a cryptographic hash of the given data.
|
|
3
|
-
*
|
|
4
|
-
* @param data - String or binary data to hash. Strings are UTF-8 encoded internally.
|
|
5
|
-
* @param algorithm - Hash algorithm to use. Defaults to SHA-256.
|
|
6
|
-
* @returns Hexadecimal hash string.
|
|
7
|
-
*
|
|
8
|
-
* @see https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto
|
|
9
|
-
*/
|
|
10
|
-
export declare const to_hash: (data: BufferSource | string, algorithm?: "SHA-1" | "SHA-256" | "SHA-384" | "SHA-512") => Promise<string>;
|
|
11
|
-
//# sourceMappingURL=hash.d.ts.map
|
package/dist/hash.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"hash.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/hash.ts"],"names":[],"mappings":"AAIA;;;;;;;;GAQG;AACH,eAAO,MAAM,OAAO,GACnB,MAAM,YAAY,GAAG,MAAM,EAC3B,YAAW,OAAO,GAAG,SAAS,GAAG,SAAS,GAAG,SAAqB,KAChE,OAAO,CAAC,MAAM,CAShB,CAAC"}
|
package/dist/hash.js
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
const { subtle } = globalThis.crypto;
|
|
2
|
-
const encoder = new TextEncoder();
|
|
3
|
-
/**
|
|
4
|
-
* Computes a cryptographic hash of the given data.
|
|
5
|
-
*
|
|
6
|
-
* @param data - String or binary data to hash. Strings are UTF-8 encoded internally.
|
|
7
|
-
* @param algorithm - Hash algorithm to use. Defaults to SHA-256.
|
|
8
|
-
* @returns Hexadecimal hash string.
|
|
9
|
-
*
|
|
10
|
-
* @see https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto
|
|
11
|
-
*/
|
|
12
|
-
export const to_hash = async (data, algorithm = 'SHA-256') => {
|
|
13
|
-
const buffer = typeof data === 'string' ? encoder.encode(data) : data;
|
|
14
|
-
const digested = await subtle.digest(algorithm, buffer);
|
|
15
|
-
const bytes = Array.from(new Uint8Array(digested));
|
|
16
|
-
let hex = '';
|
|
17
|
-
for (const h of bytes) {
|
|
18
|
-
hex += h.toString(16).padStart(2, '0');
|
|
19
|
-
}
|
|
20
|
-
return hex;
|
|
21
|
-
};
|
package/src/lib/hash.ts
DELETED
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
const {subtle} = globalThis.crypto;
|
|
2
|
-
|
|
3
|
-
const encoder = new TextEncoder();
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Computes a cryptographic hash of the given data.
|
|
7
|
-
*
|
|
8
|
-
* @param data - String or binary data to hash. Strings are UTF-8 encoded internally.
|
|
9
|
-
* @param algorithm - Hash algorithm to use. Defaults to SHA-256.
|
|
10
|
-
* @returns Hexadecimal hash string.
|
|
11
|
-
*
|
|
12
|
-
* @see https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto
|
|
13
|
-
*/
|
|
14
|
-
export const to_hash = async (
|
|
15
|
-
data: BufferSource | string,
|
|
16
|
-
algorithm: 'SHA-1' | 'SHA-256' | 'SHA-384' | 'SHA-512' = 'SHA-256',
|
|
17
|
-
): Promise<string> => {
|
|
18
|
-
const buffer = typeof data === 'string' ? encoder.encode(data) : data;
|
|
19
|
-
const digested = await subtle.digest(algorithm, buffer);
|
|
20
|
-
const bytes = Array.from(new Uint8Array(digested));
|
|
21
|
-
let hex = '';
|
|
22
|
-
for (const h of bytes) {
|
|
23
|
-
hex += h.toString(16).padStart(2, '0');
|
|
24
|
-
}
|
|
25
|
-
return hex;
|
|
26
|
-
};
|