mynth-logger 2.0.11 → 2.1.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/.ast-grep/rules/strip-braces.yml +106 -0
- package/.github/workflows/CI.yaml +18 -29
- package/.github/workflows/publish.yml +11 -12
- package/biome.json +151 -0
- package/dist/src/format.d.ts +3 -1
- package/dist/src/format.js +14 -9
- package/dist/src/index.d.ts +1 -1
- package/dist/src/index.js +1 -1
- package/dist/src/logging.d.ts +2 -1
- package/dist/src/logging.js +5 -2
- package/dist/src/redact.d.ts +37 -0
- package/dist/src/redact.js +106 -0
- package/dist/src/reporters/discord.d.ts +2 -2
- package/dist/src/reporters/discord.js +1 -1
- package/dist/tests/app.js +8 -3
- package/dist/tests/index.test.js +19 -13
- package/package.json +34 -35
- package/pnpm-workspace.yaml +3 -0
- package/src/discord.ts +2 -2
- package/src/format.ts +15 -7
- package/src/index.ts +1 -1
- package/src/logging.ts +7 -7
- package/src/redact.ts +204 -0
- package/src/reporters/datadog.ts +1 -1
- package/src/reporters/discord.ts +3 -3
- package/src/types/ungap-structured-clone-json.d.ts +10 -0
- package/tests/app.ts +15 -4
- package/tests/index.test.ts +22 -13
- package/tsconfig.json +3 -3
- package/vitest.config.ts +8 -0
- package/.eslintignore +0 -1
- package/.eslintrc.json +0 -69
- package/.prettierignore +0 -2
- package/.prettierrc +0 -8
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
id: drop-if-single-stmt-braces
|
|
2
|
+
language: TypeScript
|
|
3
|
+
rule:
|
|
4
|
+
all:
|
|
5
|
+
- pattern: |
|
|
6
|
+
if ($COND) {
|
|
7
|
+
$STMT
|
|
8
|
+
}
|
|
9
|
+
- not:
|
|
10
|
+
pattern: |
|
|
11
|
+
if ($COND) {
|
|
12
|
+
$STMT
|
|
13
|
+
} else $ALT
|
|
14
|
+
fix: |
|
|
15
|
+
if ($COND)
|
|
16
|
+
$STMT
|
|
17
|
+
---
|
|
18
|
+
id: inline-if-then-keep-else-braces
|
|
19
|
+
language: TypeScript
|
|
20
|
+
rule:
|
|
21
|
+
pattern: |
|
|
22
|
+
if ($COND) {
|
|
23
|
+
$THEN
|
|
24
|
+
} else {
|
|
25
|
+
$ELSE1
|
|
26
|
+
$ELSE2
|
|
27
|
+
$$$ELSE_REST
|
|
28
|
+
}
|
|
29
|
+
fix: |
|
|
30
|
+
if ($COND) $THEN
|
|
31
|
+
else {
|
|
32
|
+
$ELSE1
|
|
33
|
+
$ELSE2
|
|
34
|
+
$$$ELSE_REST
|
|
35
|
+
}
|
|
36
|
+
---
|
|
37
|
+
id: drop-if-else-single-stmt-braces
|
|
38
|
+
language: TypeScript
|
|
39
|
+
rule:
|
|
40
|
+
pattern: |
|
|
41
|
+
if ($COND) {
|
|
42
|
+
$THEN
|
|
43
|
+
} else {
|
|
44
|
+
$ELSE
|
|
45
|
+
}
|
|
46
|
+
fix: |
|
|
47
|
+
if ($COND)
|
|
48
|
+
$THEN
|
|
49
|
+
else
|
|
50
|
+
$ELSE
|
|
51
|
+
---
|
|
52
|
+
id: drop-while-single-stmt-braces
|
|
53
|
+
language: TypeScript
|
|
54
|
+
rule:
|
|
55
|
+
pattern: |
|
|
56
|
+
while ($COND) {
|
|
57
|
+
$STMT
|
|
58
|
+
}
|
|
59
|
+
fix: |
|
|
60
|
+
while ($COND)
|
|
61
|
+
$STMT
|
|
62
|
+
---
|
|
63
|
+
id: drop-for-single-stmt-braces
|
|
64
|
+
language: TypeScript
|
|
65
|
+
rule:
|
|
66
|
+
pattern: |
|
|
67
|
+
for ($INIT; $COND; $UPDATE) {
|
|
68
|
+
$STMT
|
|
69
|
+
}
|
|
70
|
+
fix: |
|
|
71
|
+
for ($INIT; $COND; $UPDATE)
|
|
72
|
+
$STMT
|
|
73
|
+
---
|
|
74
|
+
id: drop-for-of-single-stmt-braces
|
|
75
|
+
language: TypeScript
|
|
76
|
+
rule:
|
|
77
|
+
pattern: |
|
|
78
|
+
for ($LEFT of $RIGHT) {
|
|
79
|
+
$STMT
|
|
80
|
+
}
|
|
81
|
+
fix: |
|
|
82
|
+
for ($LEFT of $RIGHT)
|
|
83
|
+
$STMT
|
|
84
|
+
---
|
|
85
|
+
id: drop-for-in-single-stmt-braces
|
|
86
|
+
language: TypeScript
|
|
87
|
+
rule:
|
|
88
|
+
pattern: |
|
|
89
|
+
for ($LEFT in $RIGHT) {
|
|
90
|
+
$STMT
|
|
91
|
+
}
|
|
92
|
+
fix: |
|
|
93
|
+
for ($LEFT in $RIGHT)
|
|
94
|
+
$STMT
|
|
95
|
+
---
|
|
96
|
+
id: drop-do-while-single-stmt-braces
|
|
97
|
+
language: TypeScript
|
|
98
|
+
rule:
|
|
99
|
+
pattern: |
|
|
100
|
+
do {
|
|
101
|
+
$STMT
|
|
102
|
+
} while ($COND);
|
|
103
|
+
fix: |
|
|
104
|
+
do
|
|
105
|
+
$STMT
|
|
106
|
+
while ($COND);
|
|
@@ -1,9 +1,6 @@
|
|
|
1
1
|
name: CI
|
|
2
2
|
|
|
3
3
|
on:
|
|
4
|
-
push:
|
|
5
|
-
branches:
|
|
6
|
-
- main
|
|
7
4
|
pull_request:
|
|
8
5
|
|
|
9
6
|
jobs:
|
|
@@ -12,19 +9,16 @@ jobs:
|
|
|
12
9
|
timeout-minutes: 10
|
|
13
10
|
steps:
|
|
14
11
|
- name: Checkout repository
|
|
15
|
-
uses: actions/checkout@
|
|
12
|
+
uses: actions/checkout@v6.0.2
|
|
16
13
|
|
|
17
14
|
- name: Set up Node.js
|
|
18
|
-
uses: actions/setup-node@
|
|
15
|
+
uses: actions/setup-node@v6.2.0
|
|
19
16
|
with:
|
|
20
|
-
node-version:
|
|
21
|
-
check-latest: true
|
|
17
|
+
node-version: 24
|
|
22
18
|
|
|
23
|
-
-
|
|
24
|
-
run: npm install -g npm@"<11"
|
|
19
|
+
- uses: pnpm/action-setup@v4
|
|
25
20
|
|
|
26
|
-
-
|
|
27
|
-
run: npm ci --include dev
|
|
21
|
+
- run: pnpm install
|
|
28
22
|
|
|
29
23
|
- name: Run tests
|
|
30
24
|
run: npm run test
|
|
@@ -34,42 +28,37 @@ jobs:
|
|
|
34
28
|
timeout-minutes: 10
|
|
35
29
|
steps:
|
|
36
30
|
- name: Checkout repository
|
|
37
|
-
uses: actions/checkout@
|
|
31
|
+
uses: actions/checkout@v6.0.2
|
|
38
32
|
|
|
39
33
|
- name: Set up Node.js
|
|
40
|
-
uses: actions/setup-node@
|
|
34
|
+
uses: actions/setup-node@v6.2.0
|
|
41
35
|
with:
|
|
42
|
-
node-version:
|
|
43
|
-
check-latest: true
|
|
36
|
+
node-version: 24
|
|
44
37
|
|
|
45
|
-
-
|
|
46
|
-
run: npm install -g npm@"<11"
|
|
38
|
+
- uses: pnpm/action-setup@v4
|
|
47
39
|
|
|
48
|
-
-
|
|
49
|
-
run: npm ci --include dev
|
|
40
|
+
- run: pnpm install
|
|
50
41
|
|
|
51
42
|
- name: Run tests
|
|
52
|
-
run:
|
|
43
|
+
run: pnpm tsx tests/app.ts
|
|
53
44
|
|
|
54
45
|
lint:
|
|
55
46
|
runs-on: ubuntu-latest
|
|
56
47
|
timeout-minutes: 10
|
|
57
48
|
|
|
58
49
|
steps:
|
|
59
|
-
- name: Checkout
|
|
60
|
-
uses: actions/checkout@
|
|
50
|
+
- name: Checkout repository
|
|
51
|
+
uses: actions/checkout@v6.0.2
|
|
61
52
|
|
|
62
53
|
- name: Set up Node.js
|
|
63
|
-
uses: actions/setup-node@
|
|
54
|
+
uses: actions/setup-node@v6.2.0
|
|
64
55
|
with:
|
|
65
|
-
node-version:
|
|
66
|
-
check-latest: true
|
|
56
|
+
node-version: 24
|
|
67
57
|
|
|
68
|
-
-
|
|
69
|
-
run: npm install -g npm@"<11"
|
|
58
|
+
- uses: pnpm/action-setup@v4
|
|
70
59
|
|
|
71
60
|
- name: Install dependencies
|
|
72
|
-
run:
|
|
61
|
+
run: pnpm install
|
|
73
62
|
|
|
74
63
|
- name: Lint
|
|
75
|
-
run:
|
|
64
|
+
run: pnpm lint
|
|
@@ -11,28 +11,29 @@ on:
|
|
|
11
11
|
- patch
|
|
12
12
|
- minor
|
|
13
13
|
|
|
14
|
+
permissions:
|
|
15
|
+
id-token: write
|
|
16
|
+
contents: read
|
|
17
|
+
|
|
14
18
|
jobs:
|
|
15
19
|
publish:
|
|
16
20
|
runs-on: ubuntu-latest
|
|
17
|
-
permissions:
|
|
18
|
-
contents: write
|
|
19
21
|
steps:
|
|
20
22
|
- name: Checkout code
|
|
21
|
-
uses: actions/checkout@
|
|
23
|
+
uses: actions/checkout@v6.0.2
|
|
22
24
|
with:
|
|
23
25
|
ssh-key: ${{ secrets.DEPLOY_KEY }}
|
|
24
26
|
|
|
25
27
|
- name: Set up Node.js
|
|
26
|
-
uses: actions/setup-node@
|
|
28
|
+
uses: actions/setup-node@v6.2.0
|
|
27
29
|
with:
|
|
28
|
-
node-version:
|
|
29
|
-
|
|
30
|
+
node-version: 24
|
|
31
|
+
registry-url: https://registry.npmjs.org
|
|
30
32
|
|
|
31
|
-
-
|
|
32
|
-
run: npm install -g npm@"<11"
|
|
33
|
+
- uses: pnpm/action-setup@v4
|
|
33
34
|
|
|
34
35
|
- name: Install dependencies
|
|
35
|
-
run:
|
|
36
|
+
run: pnpm install
|
|
36
37
|
|
|
37
38
|
- name: Bump version and commit
|
|
38
39
|
run: |
|
|
@@ -41,12 +42,10 @@ jobs:
|
|
|
41
42
|
npm version ${{ github.event.inputs.versionType }} -m "chore(release): bump to %s version"
|
|
42
43
|
|
|
43
44
|
- name: Build
|
|
44
|
-
run:
|
|
45
|
+
run: pnpm build
|
|
45
46
|
|
|
46
47
|
- name: Publish to npm
|
|
47
48
|
run: npm publish
|
|
48
|
-
env:
|
|
49
|
-
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
|
50
49
|
|
|
51
50
|
- name: Push to git repo
|
|
52
51
|
run: git push --follow-tags
|
package/biome.json
ADDED
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://biomejs.dev/schemas/2.4.2/schema.json",
|
|
3
|
+
"vcs": { "enabled": true, "clientKind": "git", "useIgnoreFile": true },
|
|
4
|
+
"files": { "ignoreUnknown": false },
|
|
5
|
+
"formatter": {
|
|
6
|
+
"enabled": true,
|
|
7
|
+
"formatWithErrors": false,
|
|
8
|
+
"indentStyle": "space",
|
|
9
|
+
"indentWidth": 2,
|
|
10
|
+
"lineEnding": "lf",
|
|
11
|
+
"lineWidth": 80,
|
|
12
|
+
"attributePosition": "auto",
|
|
13
|
+
"bracketSameLine": false,
|
|
14
|
+
"bracketSpacing": true,
|
|
15
|
+
"expand": "auto",
|
|
16
|
+
"useEditorconfig": true,
|
|
17
|
+
"includes": ["**", "!**/*.hbs", "!**/*.md", "!**/pnpm-lock.yaml"]
|
|
18
|
+
},
|
|
19
|
+
"linter": {
|
|
20
|
+
"enabled": true,
|
|
21
|
+
"rules": {
|
|
22
|
+
"recommended": false,
|
|
23
|
+
"complexity": {
|
|
24
|
+
"noAdjacentSpacesInRegex": "error",
|
|
25
|
+
"noArguments": "error",
|
|
26
|
+
"noExtraBooleanCast": "error",
|
|
27
|
+
"noUselessCatch": "error",
|
|
28
|
+
"noUselessEscapeInRegex": "error",
|
|
29
|
+
"noUselessTypeConstraint": "error",
|
|
30
|
+
"useArrowFunction": "error"
|
|
31
|
+
},
|
|
32
|
+
"correctness": {
|
|
33
|
+
"noConstantCondition": "error",
|
|
34
|
+
"noConstAssign": "error",
|
|
35
|
+
"noEmptyCharacterClassInRegex": "error",
|
|
36
|
+
"noEmptyPattern": "error",
|
|
37
|
+
"noGlobalObjectCalls": "error",
|
|
38
|
+
"noInvalidBuiltinInstantiation": "error",
|
|
39
|
+
"noInvalidConstructorSuper": "error",
|
|
40
|
+
"noNonoctalDecimalEscape": "error",
|
|
41
|
+
"noPrecisionLoss": "error",
|
|
42
|
+
"noSelfAssign": "error",
|
|
43
|
+
"noSetterReturn": "error",
|
|
44
|
+
"noSwitchDeclarations": "error",
|
|
45
|
+
"noUndeclaredVariables": "error",
|
|
46
|
+
"noUnreachable": "error",
|
|
47
|
+
"noUnreachableSuper": "error",
|
|
48
|
+
"noUnsafeFinally": "error",
|
|
49
|
+
"noUnsafeOptionalChaining": "error",
|
|
50
|
+
"noUnusedImports": "error",
|
|
51
|
+
"noUnusedLabels": "error",
|
|
52
|
+
"noUnusedPrivateClassMembers": "error",
|
|
53
|
+
"noUnusedVariables": "error",
|
|
54
|
+
"useIsNan": "error",
|
|
55
|
+
"useValidForDirection": "error",
|
|
56
|
+
"useValidTypeof": "error",
|
|
57
|
+
"useYield": "error"
|
|
58
|
+
},
|
|
59
|
+
"style": {
|
|
60
|
+
"useConsistentArrowReturn": {
|
|
61
|
+
"level": "error",
|
|
62
|
+
"fix": "safe",
|
|
63
|
+
"options": { "style": "asNeeded" }
|
|
64
|
+
},
|
|
65
|
+
"noCommonJs": "error",
|
|
66
|
+
"noNamespace": "error",
|
|
67
|
+
"useArrayLiterals": "error",
|
|
68
|
+
"useAsConstAssertion": "error",
|
|
69
|
+
"useConst": "error"
|
|
70
|
+
},
|
|
71
|
+
"suspicious": {
|
|
72
|
+
"noAsyncPromiseExecutor": "error",
|
|
73
|
+
"noCatchAssign": "error",
|
|
74
|
+
"noClassAssign": "error",
|
|
75
|
+
"noCompareNegZero": "error",
|
|
76
|
+
"noConstantBinaryExpressions": "error",
|
|
77
|
+
"noControlCharactersInRegex": "error",
|
|
78
|
+
"noDebugger": "error",
|
|
79
|
+
"noDuplicateCase": "error",
|
|
80
|
+
"noDuplicateClassMembers": "error",
|
|
81
|
+
"noDuplicateElseIf": "error",
|
|
82
|
+
"noDuplicateObjectKeys": "error",
|
|
83
|
+
"noDuplicateParameters": "error",
|
|
84
|
+
"noEmptyBlockStatements": "error",
|
|
85
|
+
"noExplicitAny": "error",
|
|
86
|
+
"noExtraNonNullAssertion": "error",
|
|
87
|
+
"noFallthroughSwitchClause": "error",
|
|
88
|
+
"noFunctionAssign": "error",
|
|
89
|
+
"noGlobalAssign": "error",
|
|
90
|
+
"noImportAssign": "error",
|
|
91
|
+
"noIrregularWhitespace": "error",
|
|
92
|
+
"noMisleadingCharacterClass": "error",
|
|
93
|
+
"noMisleadingInstantiator": "error",
|
|
94
|
+
"noNonNullAssertedOptionalChain": "error",
|
|
95
|
+
"noPrototypeBuiltins": "error",
|
|
96
|
+
"noRedeclare": "error",
|
|
97
|
+
"noShadowRestrictedNames": "error",
|
|
98
|
+
"noSparseArray": "error",
|
|
99
|
+
"noUnassignedVariables": "error",
|
|
100
|
+
"noUnsafeDeclarationMerging": "error",
|
|
101
|
+
"noUnsafeNegation": "error",
|
|
102
|
+
"noUselessRegexBackrefs": "error",
|
|
103
|
+
"noVar": "error",
|
|
104
|
+
"noWith": "error",
|
|
105
|
+
"useGetterReturn": "error",
|
|
106
|
+
"useNamespaceKeyword": "error"
|
|
107
|
+
}
|
|
108
|
+
},
|
|
109
|
+
"includes": ["**", "!**/*.js", "!**/vite.config.ts"]
|
|
110
|
+
},
|
|
111
|
+
"javascript": {
|
|
112
|
+
"formatter": {
|
|
113
|
+
"jsxQuoteStyle": "double",
|
|
114
|
+
"quoteProperties": "asNeeded",
|
|
115
|
+
"trailingCommas": "all",
|
|
116
|
+
"semicolons": "always",
|
|
117
|
+
"arrowParentheses": "always",
|
|
118
|
+
"bracketSameLine": false,
|
|
119
|
+
"quoteStyle": "double",
|
|
120
|
+
"attributePosition": "auto",
|
|
121
|
+
"bracketSpacing": true
|
|
122
|
+
},
|
|
123
|
+
"globals": []
|
|
124
|
+
},
|
|
125
|
+
"html": {
|
|
126
|
+
"formatter": {
|
|
127
|
+
"indentScriptAndStyle": false,
|
|
128
|
+
"selfCloseVoidElements": "always"
|
|
129
|
+
}
|
|
130
|
+
},
|
|
131
|
+
"overrides": [
|
|
132
|
+
{ "includes": ["*.yml.j2"] },
|
|
133
|
+
{
|
|
134
|
+
"includes": ["**/*.{ts,tsx,mjs,cjs,js}"],
|
|
135
|
+
"javascript": { "globals": [] },
|
|
136
|
+
"linter": {
|
|
137
|
+
"rules": {
|
|
138
|
+
"correctness": { "noUnusedVariables": "error" },
|
|
139
|
+
"suspicious": {
|
|
140
|
+
"noEmptyBlockStatements": "off",
|
|
141
|
+
"noExplicitAny": "warn"
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
],
|
|
147
|
+
"assist": {
|
|
148
|
+
"enabled": true,
|
|
149
|
+
"actions": { "source": { "organizeImports": "on" } }
|
|
150
|
+
}
|
|
151
|
+
}
|
package/dist/src/format.d.ts
CHANGED
package/dist/src/format.js
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
import { stringify } from "@ungap/structured-clone/json";
|
|
2
2
|
import { type } from "arktype";
|
|
3
|
+
import { createRedact } from "./redact.js";
|
|
4
|
+
const config = {
|
|
5
|
+
redact: createRedact({}),
|
|
6
|
+
};
|
|
7
|
+
const updateConfig = (newConfig) => {
|
|
8
|
+
config.redact = createRedact(newConfig);
|
|
9
|
+
};
|
|
3
10
|
const ErrorType = type({
|
|
4
11
|
message: "string",
|
|
5
12
|
"stack?": "string",
|
|
@@ -9,8 +16,8 @@ const formatItem = (item) => {
|
|
|
9
16
|
return "undefined";
|
|
10
17
|
// Remove colors from strings
|
|
11
18
|
if (typeof item === "string")
|
|
12
|
-
//
|
|
13
|
-
return item.replace(/\x1b\[[0-9;]*m/g, "");
|
|
19
|
+
// biome-ignore lint/suspicious/noControlCharactersInRegex: stripping ANSI escape codes
|
|
20
|
+
return config.redact(item.replace(/\x1b\[[0-9;]*m/g, ""));
|
|
14
21
|
// Check if this is an Error
|
|
15
22
|
const error = ErrorType(item);
|
|
16
23
|
if (!(error instanceof type.errors))
|
|
@@ -23,11 +30,9 @@ const formatItem = (item) => {
|
|
|
23
30
|
return String(item);
|
|
24
31
|
}
|
|
25
32
|
})();
|
|
26
|
-
return stringified.replace(/^'|'$/g, "");
|
|
27
|
-
};
|
|
28
|
-
const format = (items) => {
|
|
29
|
-
return Array.from(items)
|
|
30
|
-
.map((item) => formatItem(item))
|
|
31
|
-
.join(" ");
|
|
33
|
+
return config.redact(stringified.replace(/^'|'$/g, ""));
|
|
32
34
|
};
|
|
33
|
-
|
|
35
|
+
const format = (items) => Array.from(items)
|
|
36
|
+
.map((item) => formatItem(item))
|
|
37
|
+
.join(" ");
|
|
38
|
+
export { format, updateConfig };
|
package/dist/src/index.d.ts
CHANGED
package/dist/src/index.js
CHANGED
package/dist/src/logging.d.ts
CHANGED
package/dist/src/logging.js
CHANGED
|
@@ -1,14 +1,17 @@
|
|
|
1
1
|
import { createConsola } from "consola";
|
|
2
|
+
import { updateConfig } from "./format.js";
|
|
2
3
|
import DatadogReporter from "./reporters/datadog.js";
|
|
3
4
|
import DiscordReporter from "./reporters/discord.js";
|
|
4
|
-
const setupLogging = () => {
|
|
5
|
+
const setupLogging = (config = {}) => {
|
|
6
|
+
updateConfig(config);
|
|
5
7
|
const consola = createConsola({ fancy: true, level: 5 });
|
|
6
8
|
if (process.env.NODE_ENV === "production")
|
|
7
9
|
consola.setReporters([DatadogReporter]);
|
|
8
10
|
// Set Discord reporter as first so it can remove
|
|
9
11
|
// Discord-related config before other reporters process the
|
|
10
12
|
// log
|
|
11
|
-
|
|
13
|
+
else
|
|
14
|
+
consola.setReporters([DiscordReporter, ...consola.options.reporters]);
|
|
12
15
|
consola.wrapConsole();
|
|
13
16
|
return consola;
|
|
14
17
|
};
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Configurable redaction for strings that *look like secrets*:
|
|
3
|
+
* - hex (optionally 0x-prefixed)
|
|
4
|
+
* - base64 blobs
|
|
5
|
+
* - base58 blobs
|
|
6
|
+
* - BIP39 mnemonics (validated)
|
|
7
|
+
*
|
|
8
|
+
* Key idea:
|
|
9
|
+
* Each detector can be given "allow" context rules that prevent redaction when
|
|
10
|
+
* extra surrounding context indicates the value is safe/expected.
|
|
11
|
+
*/
|
|
12
|
+
type ContextRule = {
|
|
13
|
+
/**
|
|
14
|
+
* Test this regex against a slice of the input around the match.
|
|
15
|
+
* If it matches, the match is NOT redacted.
|
|
16
|
+
*/
|
|
17
|
+
re: RegExp;
|
|
18
|
+
/** How many chars to include before the match when building the slice. */
|
|
19
|
+
before?: number;
|
|
20
|
+
/** How many chars to include after the match when building the slice. */
|
|
21
|
+
after?: number;
|
|
22
|
+
};
|
|
23
|
+
type DetectorConfig = {
|
|
24
|
+
/**
|
|
25
|
+
* Any rule match => do not redact that specific match.
|
|
26
|
+
*/
|
|
27
|
+
allow?: ContextRule[];
|
|
28
|
+
};
|
|
29
|
+
type RedactConfig = {
|
|
30
|
+
hex?: DetectorConfig;
|
|
31
|
+
base64?: DetectorConfig;
|
|
32
|
+
base58?: DetectorConfig;
|
|
33
|
+
mnemonic?: DetectorConfig;
|
|
34
|
+
};
|
|
35
|
+
declare const createRedact: (config: RedactConfig) => (text: string) => string;
|
|
36
|
+
export { createRedact };
|
|
37
|
+
export type { RedactConfig };
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { DeepRedact } from "@hackylabs/deep-redact/index.ts";
|
|
2
|
+
import { validateMnemonic } from "@scure/bip39";
|
|
3
|
+
import { wordlist } from "@scure/bip39/wordlists/english.js";
|
|
4
|
+
const replacement = "[REDACTED]";
|
|
5
|
+
const sliceAround = (value, offset, matchLen, rule) => {
|
|
6
|
+
const before = rule.before ?? 10;
|
|
7
|
+
const after = rule.after ?? 0;
|
|
8
|
+
const start = Math.max(0, offset - before);
|
|
9
|
+
const end = Math.min(value.length, offset + matchLen + after);
|
|
10
|
+
return value.slice(start, end);
|
|
11
|
+
};
|
|
12
|
+
const shouldAllowByRules = (value, match, offset, rules) => {
|
|
13
|
+
if (!rules?.length)
|
|
14
|
+
return false;
|
|
15
|
+
for (const rule of rules) {
|
|
16
|
+
const chunk = sliceAround(value, offset, match.length, rule);
|
|
17
|
+
if (rule.re.test(chunk))
|
|
18
|
+
return true;
|
|
19
|
+
}
|
|
20
|
+
return false;
|
|
21
|
+
};
|
|
22
|
+
const getReplaceMeta = (args) => {
|
|
23
|
+
const offset = args.at(-2);
|
|
24
|
+
const whole = args.at(-1);
|
|
25
|
+
if (typeof offset !== "number")
|
|
26
|
+
return null;
|
|
27
|
+
if (typeof whole !== "string")
|
|
28
|
+
return null;
|
|
29
|
+
return { offset, whole };
|
|
30
|
+
};
|
|
31
|
+
const replaceAllMatchesWithContext = (value, pattern, replacement, allow) => value.replace(pattern, (...args) => {
|
|
32
|
+
const match = args[0];
|
|
33
|
+
if (typeof match !== "string")
|
|
34
|
+
return replacement;
|
|
35
|
+
const meta = getReplaceMeta(args);
|
|
36
|
+
if (!meta)
|
|
37
|
+
return replacement;
|
|
38
|
+
if (shouldAllowByRules(meta.whole, match, meta.offset, allow))
|
|
39
|
+
return match;
|
|
40
|
+
return replacement;
|
|
41
|
+
});
|
|
42
|
+
/**
|
|
43
|
+
* BIP39 contextual replacer:
|
|
44
|
+
* - Only redacts if the captured phrase validates as a BIP39 mnemonic
|
|
45
|
+
* - Still supports allow-rules (to suppress redaction in “safe” contexts)
|
|
46
|
+
*/
|
|
47
|
+
const replaceBip39MnemonicMatchesWithContext = (value, pattern, replacement, allow) => value.replace(pattern, (...args) => {
|
|
48
|
+
const match = args[0];
|
|
49
|
+
const phrase = args[1];
|
|
50
|
+
if (typeof match !== "string")
|
|
51
|
+
return replacement;
|
|
52
|
+
if (typeof phrase !== "string")
|
|
53
|
+
return match;
|
|
54
|
+
const meta = getReplaceMeta(args);
|
|
55
|
+
if (!meta)
|
|
56
|
+
return match;
|
|
57
|
+
if (shouldAllowByRules(meta.whole, match, meta.offset, allow))
|
|
58
|
+
return match;
|
|
59
|
+
const normalized = phrase.trim().toLowerCase().replace(/\s+/g, " ");
|
|
60
|
+
if (!validateMnemonic(normalized, wordlist))
|
|
61
|
+
return match;
|
|
62
|
+
return match.replace(phrase, replacement);
|
|
63
|
+
});
|
|
64
|
+
const createRedactor = (config = {}) => {
|
|
65
|
+
const HEX_MIN_LEN = 32;
|
|
66
|
+
const BASE64_MIN_BLOCKS = 8;
|
|
67
|
+
const BASE58_MIN_LEN = 32;
|
|
68
|
+
const HEX = new RegExp(String.raw `\b(?:0x)?[a-fA-F0-9]{${HEX_MIN_LEN},}\b`, "g");
|
|
69
|
+
const hexAllow = config.hex?.allow ?? [];
|
|
70
|
+
const BASE64 = new RegExp(String.raw `\b(?:[A-Za-z0-9+/]{4}){${BASE64_MIN_BLOCKS},}(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?\b`, "g");
|
|
71
|
+
const base64Allow = config.base64?.allow ?? [];
|
|
72
|
+
const BASE58 = new RegExp(String.raw `\b[1-9A-HJ-NP-Za-km-z]{${BASE58_MIN_LEN},}\b`, "g");
|
|
73
|
+
const base58Allow = config.base58?.allow ?? [];
|
|
74
|
+
const WORD = "[a-zA-Z]{2,8}";
|
|
75
|
+
const PHRASE_12_TO_24 = `(?:${WORD}\\s+){11,23}${WORD}`;
|
|
76
|
+
const MNEMONIC = new RegExp(String.raw `\b(${PHRASE_12_TO_24})\b`, "gi");
|
|
77
|
+
const mnemonicAllow = config.mnemonic?.allow ?? [];
|
|
78
|
+
const stringTests = [
|
|
79
|
+
{
|
|
80
|
+
pattern: HEX,
|
|
81
|
+
replacer: (v, p) => replaceAllMatchesWithContext(v, p, replacement, hexAllow),
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
pattern: BASE64,
|
|
85
|
+
replacer: (v, p) => replaceAllMatchesWithContext(v, p, replacement, base64Allow),
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
pattern: BASE58,
|
|
89
|
+
replacer: (v, p) => replaceAllMatchesWithContext(v, p, replacement, base58Allow),
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
pattern: MNEMONIC,
|
|
93
|
+
replacer: (v, p) => replaceBip39MnemonicMatchesWithContext(v, p, replacement, mnemonicAllow),
|
|
94
|
+
},
|
|
95
|
+
];
|
|
96
|
+
return new DeepRedact({
|
|
97
|
+
stringTests,
|
|
98
|
+
replacement,
|
|
99
|
+
serialise: false,
|
|
100
|
+
});
|
|
101
|
+
};
|
|
102
|
+
const createRedact = (config) => {
|
|
103
|
+
const redactor = createRedactor(config);
|
|
104
|
+
return (text) => redactor.redact(text);
|
|
105
|
+
};
|
|
106
|
+
export { createRedact };
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { LogObject } from "consola";
|
|
2
|
-
declare const Discord: import("arktype/internal/
|
|
2
|
+
declare const Discord: import("arktype/internal/variants/object.ts").ObjectType<{
|
|
3
3
|
discord: true;
|
|
4
4
|
color: string;
|
|
5
5
|
title: string;
|
|
6
6
|
webhookUrl?: string | undefined;
|
|
7
7
|
}, {}>;
|
|
8
|
-
declare const ConfigureDiscord: import("arktype/internal/
|
|
8
|
+
declare const ConfigureDiscord: import("arktype/internal/variants/object.ts").ObjectType<{
|
|
9
9
|
discord: true;
|
|
10
10
|
setWebhookUrl: string;
|
|
11
11
|
}, {}>;
|
package/dist/tests/app.js
CHANGED
|
@@ -1,11 +1,16 @@
|
|
|
1
|
-
import { setupLogging } from "
|
|
1
|
+
import { setupLogging } from "../src/index.js";
|
|
2
2
|
const run = async () => {
|
|
3
|
-
setupLogging(
|
|
3
|
+
setupLogging({
|
|
4
|
+
hex: { allow: [{ re: /\b(intent|hash)\b/i }] },
|
|
5
|
+
});
|
|
4
6
|
console.log("Hello, this is a log");
|
|
5
7
|
console.info("Hello, this is an info log");
|
|
6
8
|
console.debug("Hello, this is a debug log");
|
|
7
9
|
console.warn("Hello, this is a warn log");
|
|
8
10
|
console.error("Hello, this is an error log");
|
|
11
|
+
console.log("This is my seed phrase: ordinary quality amount solid fox guess peasant merit midnight noodle final brown pretty stable six fox beef engage waste uniform evoke flat survey crane");
|
|
12
|
+
console.log("This is my private key: 4fa7614bdd07ab15b11d2365466536ba160c06050ade0888a3aa985a5522ab22");
|
|
13
|
+
console.log("This is log for intent c8adcfef7255ad2c117f68111500997ab66de3c923e9ea9e71aaed5829d0acb8 and private key c99960eaeecb17d77d7c88f440383ccbaf93237471236a739185c0ebd62c5741");
|
|
9
14
|
try {
|
|
10
15
|
throw new Error("An Error was thrown");
|
|
11
16
|
}
|
|
@@ -41,7 +46,7 @@ const run = async () => {
|
|
|
41
46
|
console.log("This is MyObject", new MyObject("a", 3));
|
|
42
47
|
console.log(new MyObject("without a prefix", 100));
|
|
43
48
|
try {
|
|
44
|
-
//
|
|
49
|
+
// biome-ignore lint/suspicious/noExplicitAny: ok
|
|
45
50
|
throw MyObject("Error invoking", 1);
|
|
46
51
|
}
|
|
47
52
|
catch (error) {
|