@fjall/util 3.6.0 → 3.6.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/.minified CHANGED
@@ -1 +1 @@
1
- 88 files minified at 2026-07-19T21:13:09.946Z
1
+ 89 files minified at 2026-07-19T23:39:36.137Z
package/dist/config.d.ts CHANGED
@@ -246,6 +246,12 @@ export declare class Config {
246
246
  private mergeWithDisk;
247
247
  private static readDiskConfigForMerge;
248
248
  static getConfigDirectory(startDir?: string): string | null;
249
+ /**
250
+ * Absolute path of the config file this instance was loaded from, or null
251
+ * when no fjall-config.json was found — the "not inside a fjall project"
252
+ * signal error paths branch on.
253
+ */
254
+ getConfigPath(): string | null;
249
255
  getActiveTarget(): string | undefined;
250
256
  setActiveTarget(name: string): void;
251
257
  clearActiveTarget(): void;
package/dist/config.js CHANGED
@@ -1 +1 @@
1
- var S=Object.defineProperty;var h=(d,e)=>S(d,"name",{value:e,configurable:!0});import*as i from"fs";import*as f from"path";import{z as s}from"zod";import{failure as g,success as w}from"./docker/result.js";import{getErrorMessage as C}from"./errorUtils.js";import{logger as y}from"./logger.js";import{maskSensitiveOutput as u}from"./securityHelpers.js";const v=10,m="fjall-config.json",M=["compliance","governance","none"],N=["enforced","off"],b=["centralised","off"],k=["account","draining","org"],I="managementEvents",L="organisationManagementEvents",U=["active","draining","removed"],J="FjallTrailBucketName",G="FjallTrailKeyArn",W="OrganisationTrailBucketName",E=s.object({name:s.string(),type:s.enum(["apex","delegated"]),parentDomain:s.string().optional(),account:s.string().optional()}).strict(),T=s.object({activeTarget:s.string().optional(),domains:s.array(E).optional()}).strict(),O=s.object({activeTarget:s.string().optional(),domains:s.array(E).optional()});function A(d={}){return JSON.stringify(d,null,2)}h(A,"serialiseRootConfig");const _=T.keyof().options;function x(d,e,t){const n=e[t];n!==void 0&&(d[t]=n)}h(x,"copyDefinedKey");class a{static{h(this,"Config")}rootConfig;configPath=null;loadFailed=!1;clearedKeys=new Set;constructor(e,t){this.rootConfig=e??{},this.configPath=t??null}static findConfigDirectory(e){let t=e!==void 0&&e!==""?e:process.cwd();for(let n=0;n<v;n++){const r=f.join(t,"fjall"),c=f.join(r,m);if(i.existsSync(c))return r;const o=f.join(t,m);if(i.existsSync(o))return t;const l=f.dirname(t);if(l===t)break;t=l}return null}static loadConfigFile(e){try{return i.accessSync(e,i.constants.R_OK),i.readFileSync(e,{encoding:"utf8"})}catch(t){return y.warn("Config",`Config file at ${e} could not be read; using defaults`,{file:e,error:u(C(t))}),null}}static loadConfig(e){const t=a.findConfigDirectory(e);if(!t)return new a;const n=f.join(t,m),r=a.loadConfigFile(n);if(r===null){const o=new a(void 0,n);return o.loadFailed=!0,o}let c;if(r!==""){let o;try{o=JSON.parse(r)}catch(p){throw a.formatZodError(p,m)}const l=T.safeParse(o);if(l.success)c=l.data;else{const p=O.safeParse(o);c=p.success?p.data:{},y.warn("Config","fjall-config.json contains keys this version does not recognise; they were ignored (only activeTarget and domains are read). If this is an old config, regenerate it with `fjall create ...` or re-run `fjall connect`.",{file:n})}}return new a(c,n)}static formatZodError(e,t){if(e instanceof s.ZodError&&e.issues.length>0){const c=e.issues.map(o=>`${o.path.join(".")}: ${o.message}`).join("; ");return new Error(`Failed to parse ${t}: ${c}`)}const r=(e instanceof Error?e.message:String(e)).replace(/\n/g," ").substring(0,500);return new Error(`Failed to parse ${t}: ${r}`)}saveConfig(){let e=this.configPath;if(!e){const o=a.findConfigDirectory()||f.join(process.cwd(),"fjall");e=f.join(o,m)}if(this.loadFailed)return g(new Error(`Refusing to save ${e}: the file exists but could not be read when this config loaded, so saving would replace its contents with state that never included them. Fix the file permissions (e.g. chmod u+rw ${e}) and retry.`));const t=f.dirname(e);try{i.mkdirSync(t,{recursive:!0})}catch(o){return g(new Error(`Cannot create config directory ${t}: ${u(C(o))}`))}const n=a.assertWritable(e,t);if(!n.success)return n;const r=A(this.mergeWithDisk(e)),c=`${e}.tmp-${process.pid}`;try{i.writeFileSync(c,r,{mode:384}),i.renameSync(c,e)}catch(o){return g(new Error(`Failed to save ${e}: ${u(C(o))}`))}return w(void 0)}static assertWritable(e,t){if(i.existsSync(e))try{i.accessSync(e,i.constants.W_OK)}catch{return g(new Error(`Cannot save ${e}: the file is read-only. Make it writable (e.g. chmod u+w ${e}) and retry.`))}try{i.accessSync(t,i.constants.W_OK)}catch{return g(new Error(`Cannot save ${e}: the directory ${t} is not writable. Make it writable (e.g. chmod u+w ${t}) and retry.`))}return w(void 0)}mergeWithDisk(e){const t=a.readDiskConfigForMerge(e);if(t===void 0)return this.rootConfig;const n={...t};for(const r of _)x(n,this.rootConfig,r);for(const r of this.clearedKeys)delete n[r];return n}static readDiskConfigForMerge(e){if(!i.existsSync(e))return;let t;try{t=JSON.parse(i.readFileSync(e,{encoding:"utf8"}))}catch(r){y.warn("Config",`Could not re-read ${e} before saving; writing in-memory state without merging`,{file:e,error:u(C(r))});return}const n=T.safeParse(t);if(!n.success){y.warn("Config",`On-disk ${e} failed validation before saving; writing in-memory state without merging`,{file:e,error:u(n.error.message)});return}return n.data}static getConfigDirectory(e){return a.findConfigDirectory(e)}getActiveTarget(){return this.rootConfig.activeTarget}setActiveTarget(e){this.rootConfig.activeTarget=e,this.clearedKeys.delete("activeTarget")}clearActiveTarget(){this.rootConfig.activeTarget=void 0,this.clearedKeys.add("activeTarget")}getDomains(){return this.rootConfig.domains??[]}setDomains(e){this.rootConfig.domains=e}addDomain(e){this.rootConfig.domains||(this.rootConfig.domains=[]),this.rootConfig.domains.push(e)}getDomain(e){return this.rootConfig.domains?.find(t=>t.name.toLowerCase()===e.toLowerCase())}removeDomain(e){if(!this.rootConfig.domains)return!1;const t=this.rootConfig.domains.findIndex(n=>n.name.toLowerCase()===e.toLowerCase());return t===-1?!1:(this.rootConfig.domains.splice(t,1),!0)}}export{I as ACCOUNT_TRAIL_NAME,U as ACCOUNT_TRAIL_STATES,a as Config,E as DomainConfigSchema,L as ORGANISATION_TRAIL_NAME,W as ORG_TRAIL_BUCKET_OUTPUT_KEY,b as ROOT_ACCESS_MANAGEMENT_MODES,m as ROOT_CONFIG_FILENAME,O as RootConfigReadSchema,T as RootConfigSchema,N as S3_BPA_MODES,J as TRAIL_BUCKET_OUTPUT_KEY,G as TRAIL_KEY_ARN_OUTPUT_KEY,k as TRAIL_LIFECYCLE_STATES,M as VAULT_LOCK_MODES,A as serialiseRootConfig};
1
+ var S=Object.defineProperty;var h=(d,e)=>S(d,"name",{value:e,configurable:!0});import*as i from"fs";import*as f from"path";import{z as s}from"zod";import{failure as g,success as w}from"./docker/result.js";import{getErrorMessage as C}from"./errorUtils.js";import{logger as y}from"./logger.js";import{maskSensitiveOutput as u}from"./securityHelpers.js";const v=10,m="fjall-config.json",M=["compliance","governance","none"],N=["enforced","off"],b=["centralised","off"],k=["account","draining","org"],I="managementEvents",L="organisationManagementEvents",U=["active","draining","removed"],J="FjallTrailBucketName",P="FjallTrailKeyArn",G="OrganisationTrailBucketName",E=s.object({name:s.string(),type:s.enum(["apex","delegated"]),parentDomain:s.string().optional(),account:s.string().optional()}).strict(),T=s.object({activeTarget:s.string().optional(),domains:s.array(E).optional()}).strict(),O=s.object({activeTarget:s.string().optional(),domains:s.array(E).optional()});function A(d={}){return JSON.stringify(d,null,2)}h(A,"serialiseRootConfig");const _=T.keyof().options;function x(d,e,t){const n=e[t];n!==void 0&&(d[t]=n)}h(x,"copyDefinedKey");class a{static{h(this,"Config")}rootConfig;configPath=null;loadFailed=!1;clearedKeys=new Set;constructor(e,t){this.rootConfig=e??{},this.configPath=t??null}static findConfigDirectory(e){let t=e!==void 0&&e!==""?e:process.cwd();for(let n=0;n<v;n++){const r=f.join(t,"fjall"),c=f.join(r,m);if(i.existsSync(c))return r;const o=f.join(t,m);if(i.existsSync(o))return t;const l=f.dirname(t);if(l===t)break;t=l}return null}static loadConfigFile(e){try{return i.accessSync(e,i.constants.R_OK),i.readFileSync(e,{encoding:"utf8"})}catch(t){return y.warn("Config",`Config file at ${e} could not be read; using defaults`,{file:e,error:u(C(t))}),null}}static loadConfig(e){const t=a.findConfigDirectory(e);if(!t)return new a;const n=f.join(t,m),r=a.loadConfigFile(n);if(r===null){const o=new a(void 0,n);return o.loadFailed=!0,o}let c;if(r!==""){let o;try{o=JSON.parse(r)}catch(p){throw a.formatZodError(p,m)}const l=T.safeParse(o);if(l.success)c=l.data;else{const p=O.safeParse(o);c=p.success?p.data:{},y.warn("Config","fjall-config.json contains keys this version does not recognise; they were ignored (only activeTarget and domains are read). If this is an old config, regenerate it with `fjall create ...` or re-run `fjall connect`.",{file:n})}}return new a(c,n)}static formatZodError(e,t){if(e instanceof s.ZodError&&e.issues.length>0){const c=e.issues.map(o=>`${o.path.join(".")}: ${o.message}`).join("; ");return new Error(`Failed to parse ${t}: ${c}`)}const r=(e instanceof Error?e.message:String(e)).replace(/\n/g," ").substring(0,500);return new Error(`Failed to parse ${t}: ${r}`)}saveConfig(){let e=this.configPath;if(!e){const o=a.findConfigDirectory()||f.join(process.cwd(),"fjall");e=f.join(o,m)}if(this.loadFailed)return g(new Error(`Refusing to save ${e}: the file exists but could not be read when this config loaded, so saving would replace its contents with state that never included them. Fix the file permissions (e.g. chmod u+rw ${e}) and retry.`));const t=f.dirname(e);try{i.mkdirSync(t,{recursive:!0})}catch(o){return g(new Error(`Cannot create config directory ${t}: ${u(C(o))}`))}const n=a.assertWritable(e,t);if(!n.success)return n;const r=A(this.mergeWithDisk(e)),c=`${e}.tmp-${process.pid}`;try{i.writeFileSync(c,r,{mode:384}),i.renameSync(c,e)}catch(o){return g(new Error(`Failed to save ${e}: ${u(C(o))}`))}return w(void 0)}static assertWritable(e,t){if(i.existsSync(e))try{i.accessSync(e,i.constants.W_OK)}catch{return g(new Error(`Cannot save ${e}: the file is read-only. Make it writable (e.g. chmod u+w ${e}) and retry.`))}try{i.accessSync(t,i.constants.W_OK)}catch{return g(new Error(`Cannot save ${e}: the directory ${t} is not writable. Make it writable (e.g. chmod u+w ${t}) and retry.`))}return w(void 0)}mergeWithDisk(e){const t=a.readDiskConfigForMerge(e);if(t===void 0)return this.rootConfig;const n={...t};for(const r of _)x(n,this.rootConfig,r);for(const r of this.clearedKeys)delete n[r];return n}static readDiskConfigForMerge(e){if(!i.existsSync(e))return;let t;try{t=JSON.parse(i.readFileSync(e,{encoding:"utf8"}))}catch(r){y.warn("Config",`Could not re-read ${e} before saving; writing in-memory state without merging`,{file:e,error:u(C(r))});return}const n=T.safeParse(t);if(!n.success){y.warn("Config",`On-disk ${e} failed validation before saving; writing in-memory state without merging`,{file:e,error:u(n.error.message)});return}return n.data}static getConfigDirectory(e){return a.findConfigDirectory(e)}getConfigPath(){return this.configPath}getActiveTarget(){return this.rootConfig.activeTarget}setActiveTarget(e){this.rootConfig.activeTarget=e,this.clearedKeys.delete("activeTarget")}clearActiveTarget(){this.rootConfig.activeTarget=void 0,this.clearedKeys.add("activeTarget")}getDomains(){return this.rootConfig.domains??[]}setDomains(e){this.rootConfig.domains=e}addDomain(e){this.rootConfig.domains||(this.rootConfig.domains=[]),this.rootConfig.domains.push(e)}getDomain(e){return this.rootConfig.domains?.find(t=>t.name.toLowerCase()===e.toLowerCase())}removeDomain(e){if(!this.rootConfig.domains)return!1;const t=this.rootConfig.domains.findIndex(n=>n.name.toLowerCase()===e.toLowerCase());return t===-1?!1:(this.rootConfig.domains.splice(t,1),!0)}}export{I as ACCOUNT_TRAIL_NAME,U as ACCOUNT_TRAIL_STATES,a as Config,E as DomainConfigSchema,L as ORGANISATION_TRAIL_NAME,G as ORG_TRAIL_BUCKET_OUTPUT_KEY,b as ROOT_ACCESS_MANAGEMENT_MODES,m as ROOT_CONFIG_FILENAME,O as RootConfigReadSchema,T as RootConfigSchema,N as S3_BPA_MODES,J as TRAIL_BUCKET_OUTPUT_KEY,P as TRAIL_KEY_ARN_OUTPUT_KEY,k as TRAIL_LIFECYCLE_STATES,M as VAULT_LOCK_MODES,A as serialiseRootConfig};
package/dist/fsScan.d.ts CHANGED
@@ -12,4 +12,6 @@
12
12
  */
13
13
  export { scanLocalRepository, type ScanLocalRepositoryResult } from "./repo/scanLocalRepository.js";
14
14
  export { findRepoRoot } from "./repo/findRepoRoot.js";
15
+ export { findProjectsBelow, hasFjallAppLayout, type DiscoveredProject, type FindProjectsBelowOptions } from "./repo/findProjectsBelow.js";
16
+ export { INFRASTRUCTURE_FILE, MARKER_DIRECTORY } from "./repo/findInfrastructurePaths.js";
15
17
  export { type ScanPath } from "./repo/scanTypes.js";
package/dist/fsScan.js CHANGED
@@ -1 +1 @@
1
- import{scanLocalRepository as e}from"./repo/scanLocalRepository.js";import{findRepoRoot as t}from"./repo/findRepoRoot.js";export{t as findRepoRoot,e as scanLocalRepository};
1
+ import{scanLocalRepository as R}from"./repo/scanLocalRepository.js";import{findRepoRoot as p}from"./repo/findRepoRoot.js";import{findProjectsBelow as f,hasFjallAppLayout as a}from"./repo/findProjectsBelow.js";import{INFRASTRUCTURE_FILE as m,MARKER_DIRECTORY as s}from"./repo/findInfrastructurePaths.js";export{m as INFRASTRUCTURE_FILE,s as MARKER_DIRECTORY,f as findProjectsBelow,p as findRepoRoot,a as hasFjallAppLayout,R as scanLocalRepository};
@@ -20,6 +20,7 @@
20
20
  * for the rationale behind extracting this module.
21
21
  */
22
22
  import type { ScanPath } from "./scanTypes.js";
23
+ export declare const INFRASTRUCTURE_FILE = "infrastructure.ts";
23
24
  export declare const MARKER_DIRECTORY = "fjall";
24
25
  export interface MarkerEntry {
25
26
  /** POSIX-style path relative to the repo root. */
@@ -1 +1 @@
1
- var c=Object.defineProperty;var r=(t,n)=>c(t,"name",{value:n,configurable:!0});const s="infrastructure.ts",a="fjall";function P(t,n){const e=n?.excludedPathPrefixes,u=n?.excludedPathSegments,o=[];for(const i of t){if(!l(i.path)||e&&x(i.path,e)||u&&p(i.path,u))continue;const f=h(i.path);f!==null&&o.push({configPath:d(i.path),boundaryPath:f})}return o}r(P,"findInfrastructurePaths");function l(t){return t===s||t.endsWith(`/${s}`)}r(l,"isInfrastructureFile");function h(t){const n=t.split("/");for(let e=0;e<n.length-1;e++)if(n[e]===a)return n.slice(0,e+1).join("/");return null}r(h,"findBoundaryPath");function d(t){return t.slice(0,-`/${s}`.length)}r(d,"toConfigDir");function x(t,n){for(const e of n)if(t.startsWith(e))return!0;return!1}r(x,"hasExcludedPrefix");function p(t,n){const e=t.split("/");for(let u=0;u<e.length-1;u++)if(n.has(e[u]))return!0;return!1}r(p,"hasExcludedSegment");export{a as MARKER_DIRECTORY,h as findBoundaryPath,P as findInfrastructurePaths,l as isInfrastructureFile};
1
+ var c=Object.defineProperty;var r=(t,e)=>c(t,"name",{value:e,configurable:!0});const s="infrastructure.ts",a="fjall";function P(t,e){const n=e?.excludedPathPrefixes,u=e?.excludedPathSegments,o=[];for(const i of t){if(!l(i.path)||n&&x(i.path,n)||u&&p(i.path,u))continue;const f=h(i.path);f!==null&&o.push({configPath:d(i.path),boundaryPath:f})}return o}r(P,"findInfrastructurePaths");function l(t){return t===s||t.endsWith(`/${s}`)}r(l,"isInfrastructureFile");function h(t){const e=t.split("/");for(let n=0;n<e.length-1;n++)if(e[n]===a)return e.slice(0,n+1).join("/");return null}r(h,"findBoundaryPath");function d(t){return t.slice(0,-`/${s}`.length)}r(d,"toConfigDir");function x(t,e){for(const n of e)if(t.startsWith(n))return!0;return!1}r(x,"hasExcludedPrefix");function p(t,e){const n=t.split("/");for(let u=0;u<n.length-1;u++)if(e.has(n[u]))return!0;return!1}r(p,"hasExcludedSegment");export{s as INFRASTRUCTURE_FILE,a as MARKER_DIRECTORY,h as findBoundaryPath,P as findInfrastructurePaths,l as isInfrastructureFile};
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Bounded downward scan for fjall projects in child directories.
3
+ *
4
+ * The complement of `findRepoRoot`: config discovery walks UP from the
5
+ * current directory, so a user sitting one level ABOVE their project (a
6
+ * container directory holding several checkouts) gets no signal that the
7
+ * project they meant is right below them. This scanner powers the
8
+ * "did you mean cd <dir>?" guidance in CLI error messages.
9
+ */
10
+ export interface DiscoveredProject {
11
+ /** Absolute path of the project directory (the one to cd into). */
12
+ projectDir: string;
13
+ /** Absolute path of the project's fjall-config.json. */
14
+ configPath: string;
15
+ /** The config's activeTarget, when the file is readable and carries one. */
16
+ activeTarget: string | undefined;
17
+ /**
18
+ * App directory names carrying an infrastructure.ts marker — direct
19
+ * subdirectories of the config's directory, plus one monorepo container
20
+ * level (`<projectDir>/<container>/fjall/<app>`). Deeper nesting is not
21
+ * enumerated; the list is a sample, not a census.
22
+ */
23
+ apps: string[];
24
+ }
25
+ export interface FindProjectsBelowOptions {
26
+ /** How many levels below startDir to descend (default 3). */
27
+ maxDepth?: number;
28
+ /** Total child directories to inspect before giving up (default 2000). */
29
+ maxDirectories?: number;
30
+ }
31
+ /**
32
+ * Find fjall projects strictly below `startDir`. A project is a directory
33
+ * containing `fjall/fjall-config.json` or a direct `fjall-config.json` —
34
+ * the same two shapes Config.loadConfig discovers when walking upward.
35
+ * Breadth-first with alphabetical siblings, so results are deterministic
36
+ * and shallower projects come first; found projects are not descended into.
37
+ */
38
+ export declare function findProjectsBelow(startDir: string, options?: FindProjectsBelowOptions): Promise<DiscoveredProject[]>;
39
+ /**
40
+ * True when `dir` has the scaffolded app layout `fjall/<app>/infrastructure.ts`
41
+ * — the signal that config creation at `dir/fjall/fjall-config.json` lands in
42
+ * a real project rather than planting a stray file in an unrelated tree.
43
+ */
44
+ export declare function hasFjallAppLayout(dir: string): Promise<boolean>;
@@ -0,0 +1 @@
1
+ var C=Object.defineProperty;var o=(t,r)=>C(t,"name",{value:r,configurable:!0});import{readdir as D,readFile as _,stat as j}from"fs/promises";import{join as a}from"path";import{ROOT_CONFIG_FILENAME as E}from"../config.js";import{getErrorMessage as T}from"../errorUtils.js";import{logger as y}from"../logger.js";import{maskSensitiveOutput as g}from"../securityHelpers.js";import{INFRASTRUCTURE_FILE as x,MARKER_DIRECTORY as s}from"./findInfrastructurePaths.js";import{EXCLUDED_DIRECTORY_NAMES as I}from"./scanLocalRepository.js";const O=3,S=2e3;async function q(t,r={}){const e=r.maxDepth??O,n=r.maxDirectories??S,i=[];let c=[t],l=0;for(let m=0;m<e&&c.length>0;m++){const d=[];for(const A of c){const R=await f(A);for(const w of R){if(l>=n)return i;l++;const h=await v(w);h?i.push(h):d.push(w)}}c=d}return i}o(q,"findProjectsBelow");async function G(t){return(await u(a(t,s))).length>0}o(G,"hasFjallAppLayout");async function v(t){const r=a(t,s,E);if(await p(r))return F(t,r,a(t,s));const e=a(t,E);return await p(e)?F(t,e,t):null}o(v,"inspectForProject");async function F(t,r,e){return{projectDir:t,configPath:r,activeTarget:await b(r),apps:await L(t,e)}}o(F,"buildProject");async function L(t,r){const e=new Set(await u(r));for(const n of await f(t))if(n!==r)for(const i of await u(a(n,s)))e.add(i);return[...e].sort()}o(L,"listProjectApps");async function b(t){try{const r=await _(t,"utf8"),e=JSON.parse(r);if(e!==null&&typeof e=="object"&&"activeTarget"in e){const n=e.activeTarget;if(typeof n=="string"&&n!=="")return n}}catch(r){y.debug("FindProjectsBelow",`Could not read activeTarget from ${t}`,{error:g(T(r))})}}o(b,"readActiveTarget");async function u(t){const r=[];for(const e of await f(t))await p(a(e,x))&&r.push(e.slice(t.length+1));return r}o(u,"listApps");async function f(t){let r;try{r=await D(t,{withFileTypes:!0})}catch(e){return y.debug("FindProjectsBelow",`Could not read directory ${t}`,{error:g(T(e))}),[]}return r.filter(e=>!e.isSymbolicLink()&&e.isDirectory()&&!e.name.startsWith(".")&&!I.has(e.name)).map(e=>e.name).sort().map(e=>a(t,e))}o(f,"listSubdirectories");function p(t){return j(t).then(r=>r.isFile(),()=>!1)}o(p,"fileExists");export{q as findProjectsBelow,G as hasFjallAppLayout};
@@ -18,6 +18,7 @@
18
18
  * .next, .turbo, .vite, .cache.
19
19
  */
20
20
  import type { ScanPath } from "./scanTypes.js";
21
+ export declare const EXCLUDED_DIRECTORY_NAMES: ReadonlySet<string>;
21
22
  export interface ScanLocalRepositoryResult {
22
23
  paths: ScanPath[];
23
24
  }
@@ -1 +1 @@
1
- var f=Object.defineProperty;var r=(t,i)=>f(t,"name",{value:i,configurable:!0});import{readdir as l}from"fs/promises";import{join as m,relative as h,sep as o}from"path";import{findInfrastructurePaths as d,isInfrastructureFile as p}from"./findInfrastructurePaths.js";const c=new Set(["node_modules",".git","dist","build","coverage",".next",".turbo",".vite",".cache"]);async function x(t){const i=[];return await u(t,t,i),{paths:d(i,{excludedPathSegments:c})}}r(x,"scanLocalRepository");async function u(t,i,n){let a;try{a=await l(i,{withFileTypes:!0})}catch{return}for(const e of a){if(e.isSymbolicLink())continue;const s=m(i,e.name);if(e.isDirectory()){if(c.has(e.name))continue;await u(t,s,n);continue}e.isFile()&&p(e.name)&&n.push({path:y(t,s)})}}r(u,"walk");function y(t,i){const n=h(t,i);return o==="/"?n:n.split(o).join("/")}r(y,"toPosixRelative");export{x as scanLocalRepository};
1
+ var f=Object.defineProperty;var r=(t,i)=>f(t,"name",{value:i,configurable:!0});import{readdir as l}from"fs/promises";import{join as m,relative as h,sep as o}from"path";import{findInfrastructurePaths as p,isInfrastructureFile as d}from"./findInfrastructurePaths.js";const c=new Set(["node_modules",".git","dist","build","coverage",".next",".turbo",".vite",".cache"]);async function v(t){const i=[];return await u(t,t,i),{paths:p(i,{excludedPathSegments:c})}}r(v,"scanLocalRepository");async function u(t,i,n){let a;try{a=await l(i,{withFileTypes:!0})}catch{return}for(const e of a){if(e.isSymbolicLink())continue;const s=m(i,e.name);if(e.isDirectory()){if(c.has(e.name))continue;await u(t,s,n);continue}e.isFile()&&d(e.name)&&n.push({path:y(t,s)})}}r(u,"walk");function y(t,i){const n=h(t,i);return o==="/"?n:n.split(o).join("/")}r(y,"toPosixRelative");export{c as EXCLUDED_DIRECTORY_NAMES,v as scanLocalRepository};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fjall/util",
3
- "version": "3.6.0",
3
+ "version": "3.6.1",
4
4
  "description": "Common utility methods",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -134,5 +134,5 @@
134
134
  "engines": {
135
135
  "node": ">=22.0.0"
136
136
  },
137
- "gitHead": "10366db602d7e80669e22825a52071a47e05c3b7"
137
+ "gitHead": "4bf3b77f9ef1472ca7afc6da552a225062ad602c"
138
138
  }