@fjall/util 0.96.0 → 0.99.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 +1 -1
- package/dist/Config.d.ts +1 -1
- package/dist/appPath.d.ts +29 -0
- package/dist/appPath.js +1 -0
- package/dist/constructMap.d.ts +9 -13
- package/dist/constructMap.js +1 -1
- package/dist/deriveContentHashTag.d.ts +34 -0
- package/dist/deriveContentHashTag.js +1 -0
- package/dist/docker/DockerCli.build.d.ts +42 -0
- package/dist/docker/DockerCli.build.js +1 -0
- package/dist/docker/DockerCli.d.ts +135 -0
- package/dist/docker/DockerCli.daemon.d.ts +24 -0
- package/dist/docker/DockerCli.daemon.js +1 -0
- package/dist/docker/DockerCli.js +1 -0
- package/dist/docker/DockerCli.registry.d.ts +19 -0
- package/dist/docker/DockerCli.registry.js +3 -0
- package/dist/docker/abortHelpers.d.ts +18 -0
- package/dist/docker/abortHelpers.js +1 -0
- package/dist/docker/buildxArgvBuilder.d.ts +15 -0
- package/dist/docker/buildxArgvBuilder.js +1 -0
- package/dist/docker/dockerCliConstants.d.ts +15 -0
- package/dist/docker/dockerCliConstants.js +1 -0
- package/dist/docker/dockerCliSchemas.d.ts +88 -0
- package/dist/docker/dockerCliSchemas.js +1 -0
- package/dist/docker/index.d.ts +10 -0
- package/dist/docker/index.js +1 -0
- package/dist/docker/metadataFileParser.d.ts +17 -0
- package/dist/docker/metadataFileParser.js +1 -0
- package/dist/docker/projectBuildxResult.d.ts +35 -0
- package/dist/docker/projectBuildxResult.js +1 -0
- package/dist/docker/rawjsonParser.d.ts +56 -0
- package/dist/docker/rawjsonParser.js +1 -0
- package/dist/docker/rawjsonToVertexEvent.d.ts +64 -0
- package/dist/docker/rawjsonToVertexEvent.js +1 -0
- package/dist/docker/result.d.ts +34 -0
- package/dist/docker/result.js +1 -0
- package/dist/errorUtils.d.ts +14 -4
- package/dist/findInfrastructurePaths.d.ts +62 -0
- package/dist/findInfrastructurePaths.js +1 -0
- package/dist/findRepoRoot.d.ts +12 -0
- package/dist/findRepoRoot.js +1 -0
- package/dist/fsHelpers.d.ts +15 -0
- package/dist/fsHelpers.js +1 -1
- package/dist/fsScan.d.ts +15 -0
- package/dist/fsScan.js +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +1 -1
- package/dist/inferContainerFromCandidates.d.ts +23 -0
- package/dist/inferContainerFromCandidates.js +1 -0
- package/dist/manifest/index.d.ts +10 -0
- package/dist/manifest/index.js +1 -0
- package/dist/manifest/io.d.ts +60 -0
- package/dist/manifest/io.js +1 -0
- package/dist/manifest/schemas.d.ts +163 -0
- package/dist/manifest/schemas.js +1 -0
- package/dist/mcpProtocol/index.d.ts +362 -0
- package/dist/mcpProtocol/index.js +1 -0
- package/dist/migration/clickhouseSqlUsers.d.ts +69 -0
- package/dist/migration/clickhouseSqlUsers.js +1 -0
- package/dist/migration/constants.d.ts +34 -0
- package/dist/migration/constants.js +1 -0
- package/dist/migration/index.d.ts +3 -0
- package/dist/migration/index.js +1 -0
- package/dist/migration/pickLatestPrismaMigration.d.ts +10 -0
- package/dist/migration/pickLatestPrismaMigration.js +1 -0
- package/dist/reservedAppNames.d.ts +30 -0
- package/dist/reservedAppNames.js +1 -0
- package/dist/scanLocalRepository.d.ts +24 -0
- package/dist/scanLocalRepository.js +1 -0
- package/dist/scanTypes.d.ts +17 -0
- package/dist/scanTypes.js +0 -0
- package/dist/securityHelpers.d.ts +11 -1
- package/dist/securityHelpers.js +1 -1
- package/dist/tokenScopes.d.ts +11 -0
- package/dist/tokenScopes.js +1 -0
- package/package.json +43 -9
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{readdirSync as n}from"node:fs";import{PRISMA_MIGRATION_DIR_RE as o}from"./constants.js";function d(t){const i=n(t,{withFileTypes:!0}).filter(r=>r.isDirectory()).map(r=>r.name).filter(r=>o.test(r)).sort(),e=i[i.length-1];if(e===void 0)throw new Error(`No Prisma migration directories found under ${t}`);return e}export{d as pickLatestPrismaMigration};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reserved application names (cross-system, application-scoped).
|
|
3
|
+
*
|
|
4
|
+
* Both the CLI scaffold schema (`CreateApplicationSchema` in
|
|
5
|
+
* `@fjall/cli/src/validation/commandSchemas.ts`) and the webapp scaffold
|
|
6
|
+
* schema (`ScaffoldRequestSchema` in `webapp/app/routes/api/github/scaffold.ts`)
|
|
7
|
+
* reject any application name whose **lowercase form** appears in this list.
|
|
8
|
+
*
|
|
9
|
+
* The reserved name `"fjall"` is gated here because it denotes the
|
|
10
|
+
* organisation-tier marker under the `fjall/` marker convention (P1) — a
|
|
11
|
+
* customer-owned application sharing that name would collide structurally
|
|
12
|
+
* with the organisation entry under `[container/]fjall/fjall/infrastructure.ts`.
|
|
13
|
+
*
|
|
14
|
+
* **Boundary with `isReservedSlug`** — `webapp/app/.server/utils/reservedSlugs.ts`
|
|
15
|
+
* guards organisation slugs (URL-scoped, webapp-only). This list is
|
|
16
|
+
* application-scoped and ships from `@fjall/util` for cross-system reuse
|
|
17
|
+
* (CLI + webapp + worker). Both coexist; neither references the other.
|
|
18
|
+
*
|
|
19
|
+
* All entries MUST be lowercase. Membership checks lowercase the input
|
|
20
|
+
* before testing, so `"Fjall"`, `"FJALL"`, and `"fjALL"` all reject
|
|
21
|
+
* identically.
|
|
22
|
+
*/
|
|
23
|
+
export declare const RESERVED_APP_NAMES: readonly ["fjall"];
|
|
24
|
+
export type ReservedAppName = (typeof RESERVED_APP_NAMES)[number];
|
|
25
|
+
/**
|
|
26
|
+
* Case-insensitive membership check. The canonical entrypoint — consumers
|
|
27
|
+
* MUST route through this helper rather than calling `.includes(name.toLowerCase())`
|
|
28
|
+
* inline, so the lowercasing discipline cannot drift across CLI/webapp/worker.
|
|
29
|
+
*/
|
|
30
|
+
export declare function isReservedAppName(name: string): boolean;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
const o=["fjall"];function r(e){return o.includes(e.toLowerCase())}export{o as RESERVED_APP_NAMES,r as isReservedAppName};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Filesystem counterpart to the webapp's `scanInfrastructureFiles`.
|
|
3
|
+
*
|
|
4
|
+
* Walks `repoRoot` recursively, gathers every `infrastructure.ts` file it
|
|
5
|
+
* sees, and hands the resulting iterable to the shared `findInfrastructurePaths`
|
|
6
|
+
* resolver. The resolver owns the marker/boundary rules; this module owns
|
|
7
|
+
* the I/O concerns (symlink loop guard, walk recursion). The exclusion set
|
|
8
|
+
* is declared here but enforced by the shared resolver — `walk()` skips
|
|
9
|
+
* excluded directories at I/O time as an optimisation; the resolver enforces
|
|
10
|
+
* the same set as a defence-in-depth contract.
|
|
11
|
+
*
|
|
12
|
+
* Returns the same `{ paths }` shape as the webapp scan so the helpers are
|
|
13
|
+
* consumer-substitutable (`aiDocs/patterns/cross-system-parity-pattern.md`).
|
|
14
|
+
*
|
|
15
|
+
* Walk discipline:
|
|
16
|
+
* - Symlinks are skipped entirely via `Dirent.isSymbolicLink()` (loop guard).
|
|
17
|
+
* - Excluded directory names: node_modules, .git, dist, build, coverage,
|
|
18
|
+
* .next, .turbo, .vite, .cache.
|
|
19
|
+
*/
|
|
20
|
+
import type { ScanPath } from "./scanTypes.js";
|
|
21
|
+
export interface ScanLocalRepositoryResult {
|
|
22
|
+
paths: ScanPath[];
|
|
23
|
+
}
|
|
24
|
+
export declare function scanLocalRepository(repoRoot: string): Promise<ScanLocalRepositoryResult>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{readdir as u}from"fs/promises";import{join as f,relative as l,sep as s}from"path";import{findInfrastructurePaths as m,isInfrastructureFile as h}from"./findInfrastructurePaths.js";const o=new Set(["node_modules",".git","dist","build","coverage",".next",".turbo",".vite",".cache"]);async function E(t){const i=[];return await c(t,t,i),{paths:m(i,{excludedPathSegments:o})}}async function c(t,i,n){let r;try{r=await u(i,{withFileTypes:!0})}catch{return}for(const e of r){if(e.isSymbolicLink())continue;const a=f(i,e.name);if(e.isDirectory()){if(o.has(e.name))continue;await c(t,a,n);continue}e.isFile()&&h(e.name)&&n.push({path:d(t,a)})}}function d(t,i){const n=l(t,i);return s==="/"?n:n.split(s).join("/")}export{E as scanLocalRepository};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cross-system scan-result types shared by the CLI's `scanLocalRepository`
|
|
3
|
+
* (filesystem) and the webapp's `scanInfrastructureFiles` (GitHub tree API).
|
|
4
|
+
*
|
|
5
|
+
* Both producers MUST emit the same `{ paths }` shape so the helpers are
|
|
6
|
+
* consumer-substitutable. See
|
|
7
|
+
* `aiDocs/patterns/cross-system-parity-pattern.md`.
|
|
8
|
+
*
|
|
9
|
+
* `ScanPath` carries path information only — no name, no kind. The linker
|
|
10
|
+
* is solely responsible for mapping paths to applications and tier kinds.
|
|
11
|
+
*/
|
|
12
|
+
export interface ScanPath {
|
|
13
|
+
/** Folder containing `infrastructure.ts` relative to the repo root. */
|
|
14
|
+
configPath: string;
|
|
15
|
+
/** Path to the nearest `fjall/` ancestor (the boundary). */
|
|
16
|
+
boundaryPath: string;
|
|
17
|
+
}
|
|
File without changes
|
|
@@ -23,11 +23,21 @@ export declare function filterDangerousEnvVars(env: Record<string, string | unde
|
|
|
23
23
|
* Matches the FULL scoped agent token: prefix (16 base32) + separator (.) + secret (40 base32).
|
|
24
24
|
* Base32 alphabet: A-Z2-7. The `.` separator MUST be included or the secret leaks unmasked.
|
|
25
25
|
* Single source of truth — all masking call sites import this.
|
|
26
|
+
*
|
|
27
|
+
* Public form has NO `g` flag — `.test()` consumers must not share `lastIndex` across calls.
|
|
28
|
+
* The global form lives in `SCOPED_TOKEN_GLOBAL_REGEX` below for the iteration site.
|
|
26
29
|
*/
|
|
27
30
|
export declare const SCOPED_TOKEN_REGEX: RegExp;
|
|
28
31
|
/**
|
|
29
32
|
* Mask sensitive information in output strings to prevent credential leakage.
|
|
30
|
-
* Patterns: postgres://user:pass@host, password=xxx, secret=xxx, apikey=xxx
|
|
33
|
+
* Patterns: postgres://user:pass@host, password=xxx, secret=xxx, apikey=xxx,
|
|
34
|
+
* GitHub tokens (ghu_/ghs_/ghp_/gho_/github_pat_), bare AWS access-key IDs
|
|
35
|
+
* (AKIA-prefixed and ASIA-prefixed), AWS secret keys, ARN account IDs,
|
|
36
|
+
* scoped agent tokens.
|
|
37
|
+
*
|
|
38
|
+
* Single source of truth — consumer loggers (CLI, worker, webapp) MUST
|
|
39
|
+
* NOT re-implement these patterns inline. See
|
|
40
|
+
* .claude/rules/security-standards.md § "Masking Patterns Live in @fjall/util".
|
|
31
41
|
*/
|
|
32
42
|
export declare function maskSensitiveOutput(output: string): string;
|
|
33
43
|
/**
|
package/dist/securityHelpers.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
const
|
|
1
|
+
const E=new Set(["NODE_OPTIONS","NODE_PATH","NODE_EXTRA_CA_CERTS","NODE_DEBUG","NODE_PRESERVE_SYMLINKS","LD_PRELOAD","LD_LIBRARY_PATH","LD_AUDIT","LD_BIND_NOW","DYLD_INSERT_LIBRARIES","DYLD_LIBRARY_PATH","DYLD_FRAMEWORK_PATH","PYTHONPATH","PYTHONSTARTUP","PERL5LIB","PERL5OPT","RUBYLIB","RUBYOPT","HOME","XDG_CONFIG_HOME","AWS_SHARED_CREDENTIALS_FILE","AWS_CONFIG_FILE","SHELL","BASH_ENV","ENV","ZDOTDIR"]);function A(e){return Object.fromEntries(Object.entries(e).filter(([s])=>!E.has(s.toUpperCase())))}const c=/fjall_ak_[A-Z2-7]{16}\.[A-Z2-7]{40}/,i=/fjall_ak_[A-Z2-7]{16}\.[A-Z2-7]{40}/g;function o(e){return e.replace(/(\w+:\/\/[^:]+:)[^@]+(@)/gi,"$1***$2").replace(/(?<![a-zA-Z])(password|passwd|secret|api[_-]?key|token|auth|credential)([=:])["']?[^\s"']+/gi,"$1$2***").replace(/\b(ghu_|ghs_|ghp_|gho_|github_pat_)[A-Za-z0-9_]+/g,"$1***").replace(/(?<=Authorization:\s*Bearer\s+)[A-Za-z0-9._~+/=-]+/gi,"***").replace(/\b(AKIA|ASIA)[A-Z0-9]{12,}\b/g,"$1***").replace(/(?<=AWS_SECRET_ACCESS_KEY=|SecretAccessKey[=:]\s*|"secretAccessKey":\s*")[A-Za-z0-9/+=]{40,}/g,"***").replace(/(arn:aws[^:]*:[^:]*:[^:]*:)(\d{12})(:[^\s]*)/g,"$1***$3").replace(/(?<="(aws)?[Ss]essionToken":\s*")[^"]+/g,"***").replace(/(?<="(internal[Aa]piKey|fjallCallbackToken)":\s*")[^"]+/g,"***").replace(i,"fjall_ak_***")}function u(e){const s=[];let r="",t=!1,_=!1,l=!1,n=!1;for(const a of e){if(l){r+=a,l=!1;continue}if(a==="\\"&&!t){l=!0;continue}if(a==="'"&&!_){t=!t,n=!0;continue}if(a==='"'&&!t){_=!_,n=!0;continue}if(a===" "&&!t&&!_){(r||n)&&(s.push(r),r="",n=!1);continue}r+=a}if(t||_)throw new Error(`Unbalanced ${t?"single":"double"} quote in command: ${e.slice(0,80)}`);if(l)throw new Error(`Trailing backslash in command: ${e.slice(0,80)}`);return(r||n)&&s.push(r),s}export{E as DANGEROUS_ENV_VARS,c as SCOPED_TOKEN_REGEX,A as filterDangerousEnvVars,o as maskSensitiveOutput,u as parseShellArgs};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Single source of truth for scoped-token scope values shared across
|
|
3
|
+
* webapp (`/api/tokens` schemas + `scopedAuth.ts`) and CLI (agent output
|
|
4
|
+
* layer's `getRequiredScopes()` lookup).
|
|
5
|
+
*
|
|
6
|
+
* Drift between the two sides previously meant a webapp role granting
|
|
7
|
+
* a scope the CLI did not know how to request, or vice versa. Both
|
|
8
|
+
* consumers now import `SCOPE_VALUES` / `TokenScope` from here.
|
|
9
|
+
*/
|
|
10
|
+
export declare const SCOPE_VALUES: readonly ["read", "write", "deploy", "secrets:read", "secrets:write", "destroy", "admin", "applications:read", "applications:deploy"];
|
|
11
|
+
export type TokenScope = (typeof SCOPE_VALUES)[number];
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
const e=["read","write","deploy","secrets:read","secrets:write","destroy","admin","applications:read","applications:deploy"];export{e as SCOPE_VALUES};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fjall/util",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.99.1",
|
|
4
4
|
"description": "Common utility methods",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -18,6 +18,22 @@
|
|
|
18
18
|
"types": "./dist/constructMap.d.ts",
|
|
19
19
|
"default": "./dist/constructMap.js"
|
|
20
20
|
},
|
|
21
|
+
"./docker": {
|
|
22
|
+
"types": "./dist/docker/index.d.ts",
|
|
23
|
+
"default": "./dist/docker/index.js"
|
|
24
|
+
},
|
|
25
|
+
"./manifest": {
|
|
26
|
+
"types": "./dist/manifest/index.d.ts",
|
|
27
|
+
"default": "./dist/manifest/index.js"
|
|
28
|
+
},
|
|
29
|
+
"./manifest/schemas": {
|
|
30
|
+
"types": "./dist/manifest/schemas.d.ts",
|
|
31
|
+
"default": "./dist/manifest/schemas.js"
|
|
32
|
+
},
|
|
33
|
+
"./manifest/io": {
|
|
34
|
+
"types": "./dist/manifest/io.d.ts",
|
|
35
|
+
"default": "./dist/manifest/io.js"
|
|
36
|
+
},
|
|
21
37
|
"./environments": {
|
|
22
38
|
"types": "./dist/environments.d.ts",
|
|
23
39
|
"default": "./dist/environments.js"
|
|
@@ -26,6 +42,14 @@
|
|
|
26
42
|
"types": "./dist/fsHelpers.d.ts",
|
|
27
43
|
"default": "./dist/fsHelpers.js"
|
|
28
44
|
},
|
|
45
|
+
"./migration": {
|
|
46
|
+
"types": "./dist/migration/index.d.ts",
|
|
47
|
+
"default": "./dist/migration/index.js"
|
|
48
|
+
},
|
|
49
|
+
"./fsScan": {
|
|
50
|
+
"types": "./dist/fsScan.d.ts",
|
|
51
|
+
"default": "./dist/fsScan.js"
|
|
52
|
+
},
|
|
29
53
|
"./targets": {
|
|
30
54
|
"types": "./dist/targets.d.ts",
|
|
31
55
|
"default": "./dist/targets.js"
|
|
@@ -45,6 +69,14 @@
|
|
|
45
69
|
"./insights/computePatternFingerprint": {
|
|
46
70
|
"types": "./dist/insights/computePatternFingerprint.d.ts",
|
|
47
71
|
"default": "./dist/insights/computePatternFingerprint.js"
|
|
72
|
+
},
|
|
73
|
+
"./mcpProtocol": {
|
|
74
|
+
"types": "./dist/mcpProtocol/index.d.ts",
|
|
75
|
+
"default": "./dist/mcpProtocol/index.js"
|
|
76
|
+
},
|
|
77
|
+
"./securityHelpers": {
|
|
78
|
+
"types": "./dist/securityHelpers.d.ts",
|
|
79
|
+
"default": "./dist/securityHelpers.js"
|
|
48
80
|
}
|
|
49
81
|
},
|
|
50
82
|
"files": [
|
|
@@ -58,21 +90,23 @@
|
|
|
58
90
|
"watch:only": "npx tsc-watch",
|
|
59
91
|
"format": "prettier --write \"src/**/*.{ts,tsx,js,jsx,json}\"",
|
|
60
92
|
"format:check": "prettier --check \"src/**/*.{ts,tsx,js,jsx,json}\"",
|
|
93
|
+
"lint": "eslint src/",
|
|
94
|
+
"lint:fix": "eslint src/ --fix",
|
|
61
95
|
"test": "vitest run",
|
|
62
96
|
"typecheck": "npx tsc --noEmit"
|
|
63
97
|
},
|
|
64
98
|
"author": "",
|
|
65
99
|
"license": "SEE LICENSE IN LICENSE",
|
|
66
100
|
"devDependencies": {
|
|
67
|
-
"@types/node": "^
|
|
68
|
-
"prettier": "^3.
|
|
69
|
-
"tsc-watch": "^7.
|
|
70
|
-
"typescript": "^
|
|
71
|
-
"vitest": "^4.1.
|
|
101
|
+
"@types/node": "^25.6.0",
|
|
102
|
+
"prettier": "^3.8.3",
|
|
103
|
+
"tsc-watch": "^7.2.0",
|
|
104
|
+
"typescript": "^6.0.3",
|
|
105
|
+
"vitest": "^4.1.5"
|
|
72
106
|
},
|
|
73
107
|
"dependencies": {
|
|
74
|
-
"@aws-sdk/client-organizations": "^3.
|
|
75
|
-
"zod": "^4.3
|
|
108
|
+
"@aws-sdk/client-organizations": "^3.1038.0",
|
|
109
|
+
"zod": "^4.4.3"
|
|
76
110
|
},
|
|
77
111
|
"overrides": {
|
|
78
112
|
"@smithy/core": "2.5.5"
|
|
@@ -80,5 +114,5 @@
|
|
|
80
114
|
"engines": {
|
|
81
115
|
"node": ">=22.0.0"
|
|
82
116
|
},
|
|
83
|
-
"gitHead": "
|
|
117
|
+
"gitHead": "0b8cc9b7c5017ca126c884da4cb29793dd26c96a"
|
|
84
118
|
}
|