@ryanatkn/gro 0.179.0 → 0.180.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/dist/build.task.d.ts +2 -0
- package/dist/build.task.d.ts.map +1 -1
- package/dist/build.task.js +14 -10
- package/dist/build_cache.d.ts +3 -3
- package/dist/build_cache.d.ts.map +1 -1
- package/dist/build_cache.js +53 -43
- package/dist/changeset.task.js +9 -9
- package/dist/clean_fs.d.ts +1 -1
- package/dist/clean_fs.d.ts.map +1 -1
- package/dist/clean_fs.js +3 -4
- package/dist/cli.d.ts +4 -4
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +11 -12
- package/dist/deploy.task.d.ts +7 -0
- package/dist/deploy.task.d.ts.map +1 -1
- package/dist/deploy.task.js +27 -14
- package/dist/esbuild_plugin_external_worker.js +1 -1
- package/dist/esbuild_plugin_svelte.js +4 -4
- package/dist/esbuild_plugin_sveltekit_local_imports.js +2 -2
- package/dist/filer.d.ts.map +1 -1
- package/dist/filer.js +103 -52
- package/dist/format_file.js +1 -1
- package/dist/gen.d.ts +1 -1
- package/dist/gen.d.ts.map +1 -1
- package/dist/gen.js +28 -22
- package/dist/gen.task.js +1 -1
- package/dist/gro.config.default.js +1 -1
- package/dist/gro_config.js +2 -2
- package/dist/gro_plugin_gen.js +1 -1
- package/dist/gro_plugin_server.js +2 -2
- package/dist/gro_plugin_sveltekit_app.d.ts.map +1 -1
- package/dist/gro_plugin_sveltekit_app.js +40 -36
- package/dist/gro_plugin_sveltekit_library.js +2 -1
- package/dist/input_path.d.ts +3 -3
- package/dist/input_path.d.ts.map +1 -1
- package/dist/input_path.js +16 -14
- package/dist/invoke_task.js +2 -2
- package/dist/lint.task.js +1 -1
- package/dist/loader.js +1 -1
- package/dist/modules.js +2 -2
- package/dist/package_json.d.ts +4 -4
- package/dist/package_json.d.ts.map +1 -1
- package/dist/package_json.js +12 -14
- package/dist/publish.task.js +6 -6
- package/dist/release.task.js +1 -1
- package/dist/resolve.task.js +2 -2
- package/dist/resolve_specifier.d.ts +1 -1
- package/dist/resolve_specifier.d.ts.map +1 -1
- package/dist/resolve_specifier.js +5 -4
- package/dist/run.task.js +2 -2
- package/dist/run_gen.d.ts.map +1 -1
- package/dist/run_gen.js +9 -8
- package/dist/run_task.js +4 -4
- package/dist/source_json.d.ts +2 -2
- package/dist/source_json.d.ts.map +1 -1
- package/dist/source_json.js +16 -15
- package/dist/sveltekit_helpers.js +3 -3
- package/dist/sveltekit_shim_env.js +1 -1
- package/dist/task.d.ts +1 -1
- package/dist/task.d.ts.map +1 -1
- package/dist/task.js +4 -4
- package/dist/test.task.d.ts.map +1 -1
- package/dist/test.task.js +5 -4
- package/dist/typecheck.task.js +3 -3
- package/dist/upgrade.task.js +4 -4
- package/package.json +5 -5
- package/src/lib/build.task.ts +15 -10
- package/src/lib/build_cache.ts +79 -63
- package/src/lib/changeset.task.ts +10 -10
- package/src/lib/clean_fs.ts +4 -4
- package/src/lib/cli.ts +15 -14
- package/src/lib/deploy.task.ts +30 -13
- package/src/lib/esbuild_plugin_external_worker.ts +1 -1
- package/src/lib/esbuild_plugin_svelte.ts +4 -4
- package/src/lib/esbuild_plugin_sveltekit_local_imports.ts +2 -2
- package/src/lib/filer.ts +111 -52
- package/src/lib/format_file.ts +1 -1
- package/src/lib/gen.task.ts +1 -1
- package/src/lib/gen.ts +52 -46
- package/src/lib/gro.config.default.ts +1 -1
- package/src/lib/gro_config.ts +2 -2
- package/src/lib/gro_plugin_gen.ts +1 -1
- package/src/lib/gro_plugin_server.ts +2 -2
- package/src/lib/gro_plugin_sveltekit_app.ts +43 -39
- package/src/lib/gro_plugin_sveltekit_library.ts +2 -2
- package/src/lib/input_path.ts +20 -21
- package/src/lib/invoke_task.ts +2 -2
- package/src/lib/lint.task.ts +1 -1
- package/src/lib/loader.ts +1 -1
- package/src/lib/modules.ts +2 -2
- package/src/lib/package_json.ts +16 -20
- package/src/lib/publish.task.ts +6 -6
- package/src/lib/release.task.ts +1 -1
- package/src/lib/resolve.task.ts +2 -2
- package/src/lib/resolve_specifier.ts +8 -4
- package/src/lib/run.task.ts +2 -2
- package/src/lib/run_gen.ts +15 -10
- package/src/lib/run_task.ts +4 -4
- package/src/lib/source_json.ts +22 -18
- package/src/lib/sveltekit_helpers.ts +3 -3
- package/src/lib/task.ts +11 -9
- package/src/lib/test.task.ts +4 -3
- package/src/lib/typecheck.task.ts +3 -3
- package/src/lib/upgrade.task.ts +4 -4
- package/dist/search_fs.d.ts +0 -26
- package/dist/search_fs.d.ts.map +0 -1
- package/dist/search_fs.js +0 -52
- package/src/lib/search_fs.ts +0 -100
package/dist/build.task.d.ts
CHANGED
|
@@ -4,6 +4,8 @@ import { type Task } from './task.ts';
|
|
|
4
4
|
export declare const Args: z.ZodObject<{
|
|
5
5
|
sync: z.ZodDefault<z.ZodBoolean>;
|
|
6
6
|
'no-sync': z.ZodDefault<z.ZodBoolean>;
|
|
7
|
+
gen: z.ZodDefault<z.ZodBoolean>;
|
|
8
|
+
'no-gen': z.ZodDefault<z.ZodBoolean>;
|
|
7
9
|
install: z.ZodDefault<z.ZodBoolean>;
|
|
8
10
|
'no-install': z.ZodDefault<z.ZodBoolean>;
|
|
9
11
|
force_build: z.ZodDefault<z.ZodBoolean>;
|
package/dist/build.task.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"build.task.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/build.task.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,CAAC,EAAC,MAAM,KAAK,CAAC;
|
|
1
|
+
{"version":3,"file":"build.task.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/build.task.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,CAAC,EAAC,MAAM,KAAK,CAAC;AAOtB,OAAO,EAAY,KAAK,IAAI,EAAC,MAAM,WAAW,CAAC;AAW/C,cAAc;AACd,eAAO,MAAM,IAAI;;;;;;;;kBAcf,CAAC;AACH,MAAM,MAAM,IAAI,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,IAAI,CAAC,CAAC;AAExC;;GAEG;AACH,eAAO,MAAM,qBAAqB,IAAI,CAAC;AASvC,cAAc;AACd,eAAO,MAAM,IAAI,EAAE,IAAI,CAAC,IAAI,CAqG3B,CAAC"}
|
package/dist/build.task.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import { styleText as st } from 'node:util';
|
|
3
3
|
import { git_check_clean_workspace, git_current_commit_hash } from '@ryanatkn/belt/git.js';
|
|
4
|
-
import {
|
|
4
|
+
import { rm } from 'node:fs/promises';
|
|
5
5
|
import { join } from 'node:path';
|
|
6
|
+
import { fs_exists } from '@ryanatkn/belt/fs.js';
|
|
6
7
|
import { TaskError } from "./task.js";
|
|
7
8
|
import { Plugins } from "./plugin.js";
|
|
8
9
|
import { clean_fs } from "./clean_fs.js";
|
|
@@ -12,6 +13,8 @@ import { paths } from "./paths.js";
|
|
|
12
13
|
export const Args = z.strictObject({
|
|
13
14
|
sync: z.boolean().meta({ description: 'dual of no-sync' }).default(true),
|
|
14
15
|
'no-sync': z.boolean().meta({ description: 'opt out of gro sync' }).default(false),
|
|
16
|
+
gen: z.boolean().meta({ description: 'dual of no-gen' }).default(true),
|
|
17
|
+
'no-gen': z.boolean().meta({ description: 'opt out of gro gen' }).default(false),
|
|
15
18
|
install: z.boolean().meta({ description: 'dual of no-install' }).default(true),
|
|
16
19
|
'no-install': z // convenience, same as `gro build -- gro sync --no-install` but the latter takes precedence
|
|
17
20
|
.boolean()
|
|
@@ -37,11 +40,14 @@ export const task = {
|
|
|
37
40
|
Args,
|
|
38
41
|
run: async (ctx) => {
|
|
39
42
|
const { args, invoke_task, log, config } = ctx;
|
|
40
|
-
const { sync, install, force_build } = args;
|
|
43
|
+
const { sync, gen, install, force_build } = args;
|
|
41
44
|
if (sync || install) {
|
|
42
45
|
if (!sync)
|
|
43
46
|
log.warn('sync is false but install is true, so ignoring the sync option');
|
|
44
|
-
await invoke_task('sync', { install });
|
|
47
|
+
await invoke_task('sync', { install, gen: false });
|
|
48
|
+
}
|
|
49
|
+
if (gen) {
|
|
50
|
+
await invoke_task('gen');
|
|
45
51
|
}
|
|
46
52
|
// Batch git calls upfront for performance (spawning processes is expensive)
|
|
47
53
|
const [workspace_status, initial_commit] = await Promise.all([
|
|
@@ -64,14 +70,12 @@ export const task = {
|
|
|
64
70
|
// Rationale: Uncommitted changes could be reverted, leaving cached outputs from reverted code.
|
|
65
71
|
// This conservative approach prioritizes safety over convenience during development.
|
|
66
72
|
const cache_path = join(paths.build, 'build.json');
|
|
67
|
-
if (
|
|
68
|
-
|
|
73
|
+
if (await fs_exists(cache_path)) {
|
|
74
|
+
await rm(cache_path, { force: true });
|
|
69
75
|
}
|
|
70
76
|
// Delete all build output directories
|
|
71
|
-
build_dirs = discover_build_output_dirs();
|
|
72
|
-
|
|
73
|
-
rmSync(dir, { recursive: true, force: true });
|
|
74
|
-
}
|
|
77
|
+
build_dirs = await discover_build_output_dirs();
|
|
78
|
+
await Promise.all(build_dirs.map((dir) => rm(dir, { recursive: true, force: true })));
|
|
75
79
|
log.info(st('yellow', 'workspace has uncommitted changes - skipping build cache'));
|
|
76
80
|
// Skip clean_fs - already manually cleaned cache and all build outputs above
|
|
77
81
|
}
|
|
@@ -107,7 +111,7 @@ export const task = {
|
|
|
107
111
|
else {
|
|
108
112
|
// Commit is stable - safe to save cache
|
|
109
113
|
const metadata = await create_build_cache_metadata(config, log, initial_commit, build_dirs);
|
|
110
|
-
save_build_cache_metadata(metadata, log);
|
|
114
|
+
await save_build_cache_metadata(metadata, log);
|
|
111
115
|
log.debug('Build cache metadata saved');
|
|
112
116
|
}
|
|
113
117
|
}
|
package/dist/build_cache.d.ts
CHANGED
|
@@ -51,12 +51,12 @@ export declare const compute_build_cache_key: (config: GroConfig, log: Logger, g
|
|
|
51
51
|
* Loads build cache metadata from .gro/ directory.
|
|
52
52
|
* Invalid or corrupted cache files are automatically deleted.
|
|
53
53
|
*/
|
|
54
|
-
export declare const load_build_cache_metadata: () => BuildCacheMetadata | null
|
|
54
|
+
export declare const load_build_cache_metadata: () => Promise<BuildCacheMetadata | null>;
|
|
55
55
|
/**
|
|
56
56
|
* Saves build cache metadata to .gro/ directory.
|
|
57
57
|
* Errors are logged but don't fail the build (cache is optional).
|
|
58
58
|
*/
|
|
59
|
-
export declare const save_build_cache_metadata: (metadata: BuildCacheMetadata, log?: Logger) => void
|
|
59
|
+
export declare const save_build_cache_metadata: (metadata: BuildCacheMetadata, log?: Logger) => Promise<void>;
|
|
60
60
|
/**
|
|
61
61
|
* Validates that a cached build is still valid by checking stats and hashing outputs.
|
|
62
62
|
* Uses size as a fast negative check before expensive hashing.
|
|
@@ -86,7 +86,7 @@ export declare const collect_build_outputs: (build_dirs: Array<string>) => Promi
|
|
|
86
86
|
* Discovers all build output directories in the current working directory.
|
|
87
87
|
* Returns an array of directory names that exist: build/, dist/, dist_*
|
|
88
88
|
*/
|
|
89
|
-
export declare const discover_build_output_dirs: () => Array<string
|
|
89
|
+
export declare const discover_build_output_dirs: () => Promise<Array<string>>;
|
|
90
90
|
/**
|
|
91
91
|
* Creates build cache metadata after a successful build.
|
|
92
92
|
* Automatically discovers all build output directories (build/, dist/, dist_*).
|
|
@@ -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":"AAEA,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,uBAAuB,CAAC;AAKlD,OAAO,EAAC,CAAC,EAAC,MAAM,KAAK,CAAC;AAGtB,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,7 +1,9 @@
|
|
|
1
|
-
import {
|
|
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
4
|
import { git_current_commit_hash } from '@ryanatkn/belt/git.js';
|
|
5
|
+
import { fs_exists } from '@ryanatkn/belt/fs.js';
|
|
6
|
+
import { map_concurrent } from '@ryanatkn/belt/async.js';
|
|
5
7
|
import { z } from 'zod';
|
|
6
8
|
import { to_hash } from "./hash.js";
|
|
7
9
|
import { paths } from "./paths.js";
|
|
@@ -63,13 +65,13 @@ export const compute_build_cache_key = async (config, log, git_commit) => {
|
|
|
63
65
|
* Loads build cache metadata from .gro/ directory.
|
|
64
66
|
* Invalid or corrupted cache files are automatically deleted.
|
|
65
67
|
*/
|
|
66
|
-
export const load_build_cache_metadata = () => {
|
|
68
|
+
export const load_build_cache_metadata = async () => {
|
|
67
69
|
const metadata_path = join(paths.build, BUILD_CACHE_METADATA_FILENAME);
|
|
68
|
-
if (!
|
|
70
|
+
if (!(await fs_exists(metadata_path))) {
|
|
69
71
|
return null;
|
|
70
72
|
}
|
|
71
73
|
try {
|
|
72
|
-
const contents =
|
|
74
|
+
const contents = await readFile(metadata_path, 'utf-8');
|
|
73
75
|
const parsed = JSON.parse(contents);
|
|
74
76
|
// Validate structure with Zod
|
|
75
77
|
const metadata = BuildCacheMetadata.parse(parsed);
|
|
@@ -77,7 +79,7 @@ export const load_build_cache_metadata = () => {
|
|
|
77
79
|
if (metadata.version !== BUILD_CACHE_VERSION) {
|
|
78
80
|
// Clean up stale cache with old schema version
|
|
79
81
|
try {
|
|
80
|
-
|
|
82
|
+
await rm(metadata_path, { force: true });
|
|
81
83
|
}
|
|
82
84
|
catch {
|
|
83
85
|
// Ignore cleanup errors
|
|
@@ -90,7 +92,7 @@ export const load_build_cache_metadata = () => {
|
|
|
90
92
|
// Clean up corrupted/invalid cache file
|
|
91
93
|
// (catches JSON.parse, Zod validation, and version errors)
|
|
92
94
|
try {
|
|
93
|
-
|
|
95
|
+
await rm(metadata_path, { force: true });
|
|
94
96
|
}
|
|
95
97
|
catch {
|
|
96
98
|
// Ignore cleanup errors
|
|
@@ -102,12 +104,12 @@ export const load_build_cache_metadata = () => {
|
|
|
102
104
|
* Saves build cache metadata to .gro/ directory.
|
|
103
105
|
* Errors are logged but don't fail the build (cache is optional).
|
|
104
106
|
*/
|
|
105
|
-
export const save_build_cache_metadata = (metadata, log) => {
|
|
107
|
+
export const save_build_cache_metadata = async (metadata, log) => {
|
|
106
108
|
try {
|
|
107
109
|
// Ensure .gro directory exists
|
|
108
|
-
|
|
110
|
+
await mkdir(paths.build, { recursive: true });
|
|
109
111
|
const metadata_path = join(paths.build, BUILD_CACHE_METADATA_FILENAME);
|
|
110
|
-
|
|
112
|
+
await writeFile(metadata_path, JSON.stringify(metadata, null, '\t'), 'utf-8');
|
|
111
113
|
}
|
|
112
114
|
catch (error) {
|
|
113
115
|
// Cache writes are optional - log warning but don't fail the build
|
|
@@ -121,22 +123,25 @@ export const save_build_cache_metadata = (metadata, log) => {
|
|
|
121
123
|
*/
|
|
122
124
|
export const validate_build_cache = async (metadata) => {
|
|
123
125
|
// Verify all tracked output files exist and have matching size
|
|
126
|
+
// Sequential checks with early return for performance
|
|
124
127
|
for (const output of metadata.outputs) {
|
|
125
|
-
|
|
128
|
+
// eslint-disable-next-line no-await-in-loop
|
|
129
|
+
if (!(await fs_exists(output.path))) {
|
|
126
130
|
return false;
|
|
127
131
|
}
|
|
128
132
|
// Fast negative check: size mismatch = definitely invalid
|
|
129
133
|
// This avoids expensive file reads and hashing for files that have clearly changed
|
|
130
|
-
|
|
134
|
+
// eslint-disable-next-line no-await-in-loop
|
|
135
|
+
const stats = await stat(output.path);
|
|
131
136
|
if (stats.size !== output.size) {
|
|
132
137
|
return false;
|
|
133
138
|
}
|
|
134
139
|
}
|
|
135
140
|
// Size matches for all files - now verify content with cryptographic hashing
|
|
136
|
-
// Hash
|
|
137
|
-
const
|
|
141
|
+
// Hash files with controlled concurrency (could be 10k+ files)
|
|
142
|
+
const results = await map_concurrent(metadata.outputs, async (output) => {
|
|
138
143
|
try {
|
|
139
|
-
const contents =
|
|
144
|
+
const contents = await readFile(output.path);
|
|
140
145
|
const actual_hash = await to_hash(contents);
|
|
141
146
|
return actual_hash === output.hash;
|
|
142
147
|
}
|
|
@@ -144,8 +149,7 @@ export const validate_build_cache = async (metadata) => {
|
|
|
144
149
|
// File deleted/inaccessible between checks = cache invalid
|
|
145
150
|
return false;
|
|
146
151
|
}
|
|
147
|
-
});
|
|
148
|
-
const results = await Promise.all(hash_promises);
|
|
152
|
+
}, 20);
|
|
149
153
|
return results.every((valid) => valid);
|
|
150
154
|
};
|
|
151
155
|
/**
|
|
@@ -158,7 +162,7 @@ export const validate_build_cache = async (metadata) => {
|
|
|
158
162
|
*/
|
|
159
163
|
export const is_build_cache_valid = async (config, log, git_commit) => {
|
|
160
164
|
// Load existing metadata
|
|
161
|
-
const metadata = load_build_cache_metadata();
|
|
165
|
+
const metadata = await load_build_cache_metadata();
|
|
162
166
|
if (!metadata) {
|
|
163
167
|
log.debug('No build cache metadata found');
|
|
164
168
|
return false;
|
|
@@ -195,8 +199,8 @@ export const is_build_cache_valid = async (config, log, git_commit) => {
|
|
|
195
199
|
export const collect_build_outputs = async (build_dirs) => {
|
|
196
200
|
const files_to_hash = [];
|
|
197
201
|
// Recursively collect files
|
|
198
|
-
const collect_files = (dir, relative_base, dir_prefix) => {
|
|
199
|
-
const entries =
|
|
202
|
+
const collect_files = async (dir, relative_base, dir_prefix) => {
|
|
203
|
+
const entries = await readdir(dir, { withFileTypes: true });
|
|
200
204
|
for (const entry of entries) {
|
|
201
205
|
// Skip metadata file itself
|
|
202
206
|
if (entry.name === BUILD_CACHE_METADATA_FILENAME) {
|
|
@@ -206,7 +210,8 @@ export const collect_build_outputs = async (build_dirs) => {
|
|
|
206
210
|
const relative_path = relative_base ? join(relative_base, entry.name) : entry.name;
|
|
207
211
|
const cache_key = join(dir_prefix, relative_path);
|
|
208
212
|
if (entry.isDirectory()) {
|
|
209
|
-
|
|
213
|
+
// eslint-disable-next-line no-await-in-loop
|
|
214
|
+
await collect_files(full_path, relative_path, dir_prefix);
|
|
210
215
|
}
|
|
211
216
|
else if (entry.isFile()) {
|
|
212
217
|
files_to_hash.push({ full_path, cache_key });
|
|
@@ -214,17 +219,19 @@ export const collect_build_outputs = async (build_dirs) => {
|
|
|
214
219
|
// Symlinks are intentionally ignored - we only hash regular files
|
|
215
220
|
}
|
|
216
221
|
};
|
|
217
|
-
// Collect files from all build directories
|
|
222
|
+
// Collect files from all build directories sequentially
|
|
218
223
|
for (const build_dir of build_dirs) {
|
|
219
|
-
|
|
224
|
+
// eslint-disable-next-line no-await-in-loop
|
|
225
|
+
if (!(await fs_exists(build_dir))) {
|
|
220
226
|
continue; // Skip non-existent directories
|
|
221
227
|
}
|
|
222
|
-
|
|
228
|
+
// eslint-disable-next-line no-await-in-loop
|
|
229
|
+
await collect_files(build_dir, '', build_dir);
|
|
223
230
|
}
|
|
224
|
-
// Hash
|
|
225
|
-
|
|
226
|
-
const stats =
|
|
227
|
-
const contents =
|
|
231
|
+
// Hash files with controlled concurrency and collect stats (could be 10k+ files)
|
|
232
|
+
return map_concurrent(files_to_hash, async ({ full_path, cache_key }) => {
|
|
233
|
+
const stats = await stat(full_path);
|
|
234
|
+
const contents = await readFile(full_path);
|
|
228
235
|
const hash = await to_hash(contents);
|
|
229
236
|
return {
|
|
230
237
|
path: cache_key,
|
|
@@ -234,37 +241,40 @@ export const collect_build_outputs = async (build_dirs) => {
|
|
|
234
241
|
ctime: stats.ctimeMs,
|
|
235
242
|
mode: stats.mode,
|
|
236
243
|
};
|
|
237
|
-
});
|
|
238
|
-
return await Promise.all(hash_promises);
|
|
244
|
+
}, 20);
|
|
239
245
|
};
|
|
240
246
|
/**
|
|
241
247
|
* Discovers all build output directories in the current working directory.
|
|
242
248
|
* Returns an array of directory names that exist: build/, dist/, dist_*
|
|
243
249
|
*/
|
|
244
|
-
export const discover_build_output_dirs = () => {
|
|
250
|
+
export const discover_build_output_dirs = async () => {
|
|
245
251
|
const build_dirs = [];
|
|
246
|
-
// Check for SvelteKit app output (build/)
|
|
247
|
-
|
|
252
|
+
// Check for SvelteKit app output (build/) and library output (dist/) in parallel
|
|
253
|
+
const [build_exists, dist_exists] = await Promise.all([
|
|
254
|
+
fs_exists(SVELTEKIT_BUILD_DIRNAME),
|
|
255
|
+
fs_exists(SVELTEKIT_DIST_DIRNAME),
|
|
256
|
+
]);
|
|
257
|
+
if (build_exists) {
|
|
248
258
|
build_dirs.push(SVELTEKIT_BUILD_DIRNAME);
|
|
249
259
|
}
|
|
250
|
-
|
|
251
|
-
if (existsSync(SVELTEKIT_DIST_DIRNAME)) {
|
|
260
|
+
if (dist_exists) {
|
|
252
261
|
build_dirs.push(SVELTEKIT_DIST_DIRNAME);
|
|
253
262
|
}
|
|
254
263
|
// Check for server and other plugin outputs (dist_*)
|
|
255
|
-
const root_entries =
|
|
256
|
-
const
|
|
257
|
-
|
|
258
|
-
|
|
264
|
+
const root_entries = await readdir('.');
|
|
265
|
+
const dist_dir_checks = await Promise.all(root_entries
|
|
266
|
+
.filter((p) => p.startsWith(GRO_DIST_PREFIX))
|
|
267
|
+
.map(async (p) => {
|
|
259
268
|
try {
|
|
260
|
-
|
|
269
|
+
const s = await stat(p);
|
|
270
|
+
return s.isDirectory() ? p : null;
|
|
261
271
|
}
|
|
262
272
|
catch {
|
|
263
273
|
// File was deleted/moved during iteration - skip it
|
|
264
|
-
return
|
|
274
|
+
return null;
|
|
265
275
|
}
|
|
266
|
-
});
|
|
267
|
-
build_dirs.push(...
|
|
276
|
+
}));
|
|
277
|
+
build_dirs.push(...dist_dir_checks.filter((p) => p !== null));
|
|
268
278
|
return build_dirs;
|
|
269
279
|
};
|
|
270
280
|
/**
|
|
@@ -278,7 +288,7 @@ export const discover_build_output_dirs = () => {
|
|
|
278
288
|
*/
|
|
279
289
|
export const create_build_cache_metadata = async (config, log, git_commit, build_dirs) => {
|
|
280
290
|
const cache_key = await compute_build_cache_key(config, log, git_commit);
|
|
281
|
-
const dirs = build_dirs ?? discover_build_output_dirs();
|
|
291
|
+
const dirs = build_dirs ?? (await discover_build_output_dirs());
|
|
282
292
|
const outputs = await collect_build_outputs(dirs);
|
|
283
293
|
return {
|
|
284
294
|
version: BUILD_CACHE_VERSION,
|
package/dist/changeset.task.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import { spawn } from '@ryanatkn/belt/process.js';
|
|
3
3
|
import { styleText as st } from 'node:util';
|
|
4
|
-
import { readFile, writeFile } from 'node:fs/promises';
|
|
4
|
+
import { readdir, readFile, writeFile } from 'node:fs/promises';
|
|
5
5
|
import { join } from 'node:path';
|
|
6
|
-
import {
|
|
6
|
+
import { fs_exists } from '@ryanatkn/belt/fs.js';
|
|
7
7
|
import { GitOrigin, git_check_fully_staged_workspace, git_push_to_create, } from '@ryanatkn/belt/git.js';
|
|
8
8
|
import { TaskError } from "./task.js";
|
|
9
9
|
import { find_cli, spawn_cli } from "./cli.js";
|
|
@@ -57,17 +57,17 @@ export const task = {
|
|
|
57
57
|
if (minor && major)
|
|
58
58
|
throw new TaskError('cannot bump both minor and major');
|
|
59
59
|
const bump = minor ? 'minor' : major ? 'major' : 'patch';
|
|
60
|
-
const found_changeset_cli = find_cli(changeset_cli);
|
|
60
|
+
const found_changeset_cli = await find_cli(changeset_cli);
|
|
61
61
|
if (!found_changeset_cli) {
|
|
62
62
|
throw new TaskError('changeset command not found: install @changesets/cli locally or globally');
|
|
63
63
|
}
|
|
64
|
-
const package_json = load_package_json();
|
|
64
|
+
const package_json = await load_package_json();
|
|
65
65
|
const has_sveltekit_library_result = await has_sveltekit_library(package_json, svelte_config);
|
|
66
66
|
if (!has_sveltekit_library_result.ok) {
|
|
67
67
|
throw new TaskError('Failed to find SvelteKit library: ' + has_sveltekit_library_result.message);
|
|
68
68
|
}
|
|
69
69
|
const path = join(dir, 'config.json');
|
|
70
|
-
const inited =
|
|
70
|
+
const inited = await fs_exists(path);
|
|
71
71
|
if (!inited) {
|
|
72
72
|
await spawn_cli(found_changeset_cli, ['init'], log);
|
|
73
73
|
const access = (access_arg ?? package_json.private)
|
|
@@ -92,7 +92,7 @@ export const task = {
|
|
|
92
92
|
await invoke_task('sync', { install: inited || !dep }); // after installing above, and in all cases
|
|
93
93
|
if (message) {
|
|
94
94
|
// TODO see the helper below, simplify this to CLI flags when support is added to Changesets
|
|
95
|
-
const changeset_adder = create_changeset_adder(package_json.name, dir, message, bump);
|
|
95
|
+
const changeset_adder = await create_changeset_adder(package_json.name, dir, message, bump);
|
|
96
96
|
await spawn_cli(found_changeset_cli, ['add', '--empty'], log);
|
|
97
97
|
await changeset_adder();
|
|
98
98
|
if (!(await git_check_fully_staged_workspace())) {
|
|
@@ -110,10 +110,10 @@ export const task = {
|
|
|
110
110
|
* TODO ideally this wouldn't exist and we'd use CLI flags, but they doesn't exist yet
|
|
111
111
|
* @see https://github.com/changesets/changesets/pull/1121
|
|
112
112
|
*/
|
|
113
|
-
const create_changeset_adder = (repo_name, dir, message, bump) => {
|
|
114
|
-
const filenames_before =
|
|
113
|
+
const create_changeset_adder = async (repo_name, dir, message, bump) => {
|
|
114
|
+
const filenames_before = await readdir(dir);
|
|
115
115
|
return async () => {
|
|
116
|
-
const filenames_after =
|
|
116
|
+
const filenames_after = await readdir(dir);
|
|
117
117
|
const filenames_added = filenames_after.filter((p) => !filenames_before.includes(p));
|
|
118
118
|
if (!filenames_added.length) {
|
|
119
119
|
throw Error('expected to find a new changeset file');
|
package/dist/clean_fs.d.ts
CHANGED
package/dist/clean_fs.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"clean_fs.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/clean_fs.ts"],"names":[],"mappings":"AACA,OAAO,
|
|
1
|
+
{"version":3,"file":"clean_fs.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/clean_fs.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,SAAS,CAAC;AAYvC,eAAO,MAAM,QAAQ,GACpB,2DAMG;IACF,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,WAAW,CAAC,EAAE,OAAO,CAAC;CACtB,EACD,aAAY,SAA0C,KACpD,OAAO,CAAC,IAAI,CAyBd,CAAC"}
|
package/dist/clean_fs.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import { rm } from 'node:fs/promises';
|
|
2
|
-
import { readdirSync } from 'node:fs';
|
|
1
|
+
import { readdir, rm } from 'node:fs/promises';
|
|
3
2
|
import { paths } from "./paths.js";
|
|
4
3
|
import { NODE_MODULES_DIRNAME, GRO_DIST_PREFIX, SVELTEKIT_DEV_DIRNAME, SVELTEKIT_BUILD_DIRNAME, SVELTEKIT_VITE_CACHE_PATH, SVELTEKIT_DIST_DIRNAME, } from "./constants.js";
|
|
5
4
|
export const clean_fs = async ({ build = false, build_dev = false, build_dist = false, sveltekit = false, nodemodules = false, }, rm_options = { force: true, recursive: true }) => {
|
|
@@ -11,8 +10,8 @@ export const clean_fs = async ({ build = false, build_dev = false, build_dist =
|
|
|
11
10
|
promises.push(rm(paths.build_dev, rm_options));
|
|
12
11
|
}
|
|
13
12
|
if (build || build_dist) {
|
|
14
|
-
const
|
|
15
|
-
for (const path of
|
|
13
|
+
const dir_paths = (await readdir('.')).filter((p) => p.startsWith(GRO_DIST_PREFIX));
|
|
14
|
+
for (const path of dir_paths) {
|
|
16
15
|
promises.push(rm(path, rm_options));
|
|
17
16
|
}
|
|
18
17
|
}
|
package/dist/cli.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { SpawnOptions } from 'node:child_process';
|
|
2
2
|
import { type SpawnResult, type SpawnedProcess } from '@ryanatkn/belt/process.js';
|
|
3
3
|
import { type URL } from 'node:url';
|
|
4
4
|
import type { Logger } from '@ryanatkn/belt/log.js';
|
|
@@ -16,7 +16,7 @@ export type Cli = {
|
|
|
16
16
|
* Searches the filesystem for the CLI `name`, first local to the cwd and then globally.
|
|
17
17
|
* @returns `null` if not found locally or globally
|
|
18
18
|
*/
|
|
19
|
-
export declare const find_cli: (name: string, cwd?: string | URL, options?: SpawnOptions) => Cli | null
|
|
19
|
+
export declare const find_cli: (name: string, cwd?: string | URL, options?: SpawnOptions) => Promise<Cli | null>;
|
|
20
20
|
/**
|
|
21
21
|
* Spawns a CLI if available using Belt's `spawn`.
|
|
22
22
|
* If a string is provided for `name_or_cli`, it checks first local to the cwd and then globally.
|
|
@@ -28,7 +28,7 @@ export declare const spawn_cli: (name_or_cli: string | Cli, args?: Array<string>
|
|
|
28
28
|
* If a string is provided for `name_or_cli`, it checks first local to the cwd and then globally.
|
|
29
29
|
* @returns `undefined` if no CLI is found, or the spawn result
|
|
30
30
|
*/
|
|
31
|
-
export declare const spawn_cli_process: (name_or_cli: string | Cli, args?: Array<string>, log?: Logger, options?: SpawnOptions) => SpawnedProcess | undefined
|
|
32
|
-
export declare const resolve_cli: (name_or_cli: string | Cli, args: Array<string> | undefined, cwd: string | URL | undefined, log?: Logger, options?: SpawnOptions) => Cli | undefined
|
|
31
|
+
export declare const spawn_cli_process: (name_or_cli: string | Cli, args?: Array<string>, log?: Logger, options?: SpawnOptions) => Promise<SpawnedProcess | undefined>;
|
|
32
|
+
export declare const resolve_cli: (name_or_cli: string | Cli, args: Array<string> | undefined, cwd: string | URL | undefined, log?: Logger, options?: SpawnOptions) => Promise<Cli | undefined>;
|
|
33
33
|
export declare const to_cli_name: (cli: string | Cli) => string;
|
|
34
34
|
//# sourceMappingURL=cli.d.ts.map
|
package/dist/cli.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/cli.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/cli.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,oBAAoB,CAAC;AACrD,OAAO,EAIN,KAAK,WAAW,EAChB,KAAK,cAAc,EACnB,MAAM,2BAA2B,CAAC;AAGnC,OAAO,EAAgB,KAAK,GAAG,EAAC,MAAM,UAAU,CAAC;AACjD,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,uBAAuB,CAAC;AAClD,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,wBAAwB,CAAC;AAOnD,MAAM,MAAM,GAAG,GACZ;IAAC,IAAI,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAC,GACzC;IAAC,IAAI,EAAE,QAAQ,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAC,CAAC;AAE9C;;;GAGG;AACH,eAAO,MAAM,QAAQ,GACpB,MAAM,MAAM,EACZ,MAAK,MAAM,GAAG,GAAmB,EACjC,UAAU,YAAY,KACpB,OAAO,CAAC,GAAG,GAAG,IAAI,CAUpB,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,SAAS,GACrB,aAAa,MAAM,GAAG,GAAG,EACzB,OAAM,KAAK,CAAC,MAAM,CAAM,EACxB,MAAM,MAAM,EACZ,UAAU,YAAY,KACpB,OAAO,CAAC,WAAW,GAAG,SAAS,CAIjC,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,GAC7B,aAAa,MAAM,GAAG,GAAG,EACzB,OAAM,KAAK,CAAC,MAAM,CAAM,EACxB,MAAM,MAAM,EACZ,UAAU,YAAY,KACpB,OAAO,CAAC,cAAc,GAAG,SAAS,CAIpC,CAAC;AAEF,eAAO,MAAM,WAAW,GACvB,aAAa,MAAM,GAAG,GAAG,EACzB,MAAM,KAAK,CAAC,MAAM,CAAC,YAAK,EACxB,KAAK,MAAM,GAAG,GAAG,GAAG,SAAS,EAC7B,MAAM,MAAM,EACZ,UAAU,YAAY,KACpB,OAAO,CAAC,GAAG,GAAG,SAAS,CAazB,CAAC;AAEF,eAAO,MAAM,WAAW,GAAI,KAAK,MAAM,GAAG,GAAG,KAAG,MACP,CAAC"}
|
package/dist/cli.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { spawn, spawn_process, } from '@ryanatkn/belt/process.js';
|
|
1
|
+
import { spawn, spawn_out, spawn_process, } from '@ryanatkn/belt/process.js';
|
|
3
2
|
import { join } from 'node:path';
|
|
4
|
-
import {
|
|
3
|
+
import { fs_exists } from '@ryanatkn/belt/fs.js';
|
|
5
4
|
import { fileURLToPath } from 'node:url';
|
|
6
5
|
import { NODE_MODULES_DIRNAME } from "./constants.js";
|
|
7
6
|
import { print_command_args } from "./args.js";
|
|
@@ -9,14 +8,14 @@ import { print_command_args } from "./args.js";
|
|
|
9
8
|
* Searches the filesystem for the CLI `name`, first local to the cwd and then globally.
|
|
10
9
|
* @returns `null` if not found locally or globally
|
|
11
10
|
*/
|
|
12
|
-
export const find_cli = (name, cwd = process.cwd(), options) => {
|
|
11
|
+
export const find_cli = async (name, cwd = process.cwd(), options) => {
|
|
13
12
|
const final_cwd = typeof cwd === 'string' ? cwd : fileURLToPath(cwd);
|
|
14
13
|
const local_id = join(final_cwd, NODE_MODULES_DIRNAME, `.bin/${name}`);
|
|
15
|
-
if (
|
|
14
|
+
if (await fs_exists(local_id)) {
|
|
16
15
|
return { name, id: local_id, kind: 'local' };
|
|
17
16
|
}
|
|
18
|
-
const { stdout } =
|
|
19
|
-
const global_id = stdout
|
|
17
|
+
const { stdout } = await spawn_out('which', [name], options);
|
|
18
|
+
const global_id = stdout?.trim();
|
|
20
19
|
if (!global_id)
|
|
21
20
|
return null;
|
|
22
21
|
return { name, id: global_id, kind: 'global' };
|
|
@@ -27,7 +26,7 @@ export const find_cli = (name, cwd = process.cwd(), options) => {
|
|
|
27
26
|
* @returns `undefined` if no CLI is found, or the spawn result
|
|
28
27
|
*/
|
|
29
28
|
export const spawn_cli = async (name_or_cli, args = [], log, options) => {
|
|
30
|
-
const cli = resolve_cli(name_or_cli, args, options?.cwd, log, options);
|
|
29
|
+
const cli = await resolve_cli(name_or_cli, args, options?.cwd, log, options);
|
|
31
30
|
if (!cli)
|
|
32
31
|
return;
|
|
33
32
|
return spawn(cli.id, args, options);
|
|
@@ -37,16 +36,16 @@ export const spawn_cli = async (name_or_cli, args = [], log, options) => {
|
|
|
37
36
|
* If a string is provided for `name_or_cli`, it checks first local to the cwd and then globally.
|
|
38
37
|
* @returns `undefined` if no CLI is found, or the spawn result
|
|
39
38
|
*/
|
|
40
|
-
export const spawn_cli_process = (name_or_cli, args = [], log, options) => {
|
|
41
|
-
const cli = resolve_cli(name_or_cli, args, options?.cwd, log, options);
|
|
39
|
+
export const spawn_cli_process = async (name_or_cli, args = [], log, options) => {
|
|
40
|
+
const cli = await resolve_cli(name_or_cli, args, options?.cwd, log, options);
|
|
42
41
|
if (!cli)
|
|
43
42
|
return;
|
|
44
43
|
return spawn_process(cli.id, args, options);
|
|
45
44
|
};
|
|
46
|
-
export const resolve_cli = (name_or_cli, args = [], cwd, log, options) => {
|
|
45
|
+
export const resolve_cli = async (name_or_cli, args = [], cwd, log, options) => {
|
|
47
46
|
let final_cli;
|
|
48
47
|
if (typeof name_or_cli === 'string') {
|
|
49
|
-
const found = find_cli(name_or_cli, cwd, options);
|
|
48
|
+
const found = await find_cli(name_or_cli, cwd, options);
|
|
50
49
|
if (!found)
|
|
51
50
|
return;
|
|
52
51
|
final_cli = found;
|
package/dist/deploy.task.d.ts
CHANGED
|
@@ -13,6 +13,13 @@ export declare const Args: z.ZodObject<{
|
|
|
13
13
|
reset: z.ZodDefault<z.ZodBoolean>;
|
|
14
14
|
build: z.ZodDefault<z.ZodBoolean>;
|
|
15
15
|
'no-build': z.ZodDefault<z.ZodBoolean>;
|
|
16
|
+
sync: z.ZodDefault<z.ZodBoolean>;
|
|
17
|
+
'no-sync': z.ZodDefault<z.ZodBoolean>;
|
|
18
|
+
gen: z.ZodDefault<z.ZodBoolean>;
|
|
19
|
+
'no-gen': z.ZodDefault<z.ZodBoolean>;
|
|
20
|
+
install: z.ZodDefault<z.ZodBoolean>;
|
|
21
|
+
'no-install': z.ZodDefault<z.ZodBoolean>;
|
|
22
|
+
force_build: z.ZodDefault<z.ZodBoolean>;
|
|
16
23
|
pull: z.ZodDefault<z.ZodBoolean>;
|
|
17
24
|
'no-pull': z.ZodDefault<z.ZodBoolean>;
|
|
18
25
|
}, z.core.$strict>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"deploy.task.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/deploy.task.ts"],"names":[],"mappings":"AAGA,OAAO,EAAC,CAAC,EAAC,MAAM,KAAK,CAAC;
|
|
1
|
+
{"version":3,"file":"deploy.task.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/deploy.task.ts"],"names":[],"mappings":"AAGA,OAAO,EAAC,CAAC,EAAC,MAAM,KAAK,CAAC;AAqBtB,OAAO,EAAY,KAAK,IAAI,EAAC,MAAM,WAAW,CAAC;AAiB/C,cAAc;AACd,eAAO,MAAM,IAAI;;;;;;;;;;;;;;;;;;;;;kBA8Cf,CAAC;AACH,MAAM,MAAM,IAAI,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,IAAI,CAAC,CAAC;AAExC,cAAc;AACd,eAAO,MAAM,IAAI,EAAE,IAAI,CAAC,IAAI,CAkM3B,CAAC"}
|