@vibe-agent-toolkit/utils 0.2.0-rc.2 → 0.2.0-rc.4
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/README.md +26 -15
- package/dist/compare-code-units.d.ts +28 -0
- package/dist/compare-code-units.d.ts.map +1 -0
- package/dist/compare-code-units.js +33 -0
- package/dist/compare-code-units.js.map +1 -0
- package/dist/crawl-timing.d.ts +657 -0
- package/dist/crawl-timing.d.ts.map +1 -0
- package/dist/crawl-timing.js +765 -0
- package/dist/crawl-timing.js.map +1 -0
- package/dist/crawl.d.ts +2 -4
- package/dist/crawl.d.ts.map +1 -1
- package/dist/crawl.js +2 -4
- package/dist/crawl.js.map +1 -1
- package/dist/file-crawler.d.ts +22 -0
- package/dist/file-crawler.d.ts.map +1 -1
- package/dist/file-crawler.js +31 -7
- package/dist/file-crawler.js.map +1 -1
- package/dist/fs-utils.d.ts +17 -0
- package/dist/fs-utils.d.ts.map +1 -1
- package/dist/fs-utils.js +69 -0
- package/dist/fs-utils.js.map +1 -1
- package/dist/fs.d.ts +3 -1
- package/dist/fs.d.ts.map +1 -1
- package/dist/fs.js +5 -1
- package/dist/fs.js.map +1 -1
- package/dist/git-run.d.ts +167 -0
- package/dist/git-run.d.ts.map +1 -0
- package/dist/git-run.js +154 -0
- package/dist/git-run.js.map +1 -0
- package/dist/git-snapshot.d.ts +181 -0
- package/dist/git-snapshot.d.ts.map +1 -0
- package/dist/git-snapshot.js +232 -0
- package/dist/git-snapshot.js.map +1 -0
- package/dist/git-tracker.d.ts +94 -1
- package/dist/git-tracker.d.ts.map +1 -1
- package/dist/git-tracker.js +135 -3
- package/dist/git-tracker.js.map +1 -1
- package/dist/git-utils.d.ts +38 -0
- package/dist/git-utils.d.ts.map +1 -1
- package/dist/git-utils.js +103 -80
- package/dist/git-utils.js.map +1 -1
- package/dist/git.d.ts +12 -4
- package/dist/git.d.ts.map +1 -1
- package/dist/git.js +12 -4
- package/dist/git.js.map +1 -1
- package/dist/gitignore-checker.d.ts.map +1 -1
- package/dist/gitignore-checker.js +6 -3
- package/dist/gitignore-checker.js.map +1 -1
- package/dist/index.d.ts +24 -18
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +49 -30
- package/dist/index.js.map +1 -1
- package/dist/path-core.d.ts +1 -1
- package/dist/path-core.js +1 -1
- package/dist/project-utils.d.ts.map +1 -1
- package/dist/project-utils.js +6 -3
- package/dist/project-utils.js.map +1 -1
- package/dist/project.d.ts +7 -5
- package/dist/project.d.ts.map +1 -1
- package/dist/project.js +7 -5
- package/dist/project.js.map +1 -1
- package/dist/safe-exec.d.ts +38 -10
- package/dist/safe-exec.d.ts.map +1 -1
- package/dist/safe-exec.js +88 -19
- package/dist/safe-exec.js.map +1 -1
- package/dist/skill-test/index.d.ts +1 -1
- package/dist/skill-test/index.d.ts.map +1 -1
- package/dist/skill-test/index.js +1 -1
- package/dist/skill-test/index.js.map +1 -1
- package/dist/skill-test/spawn-claude.d.ts +28 -0
- package/dist/skill-test/spawn-claude.d.ts.map +1 -1
- package/dist/skill-test/spawn-claude.js +51 -2
- package/dist/skill-test/spawn-claude.js.map +1 -1
- package/dist/skill-test/transcript.d.ts +41 -2
- package/dist/skill-test/transcript.d.ts.map +1 -1
- package/dist/skill-test/transcript.js +47 -3
- package/dist/skill-test/transcript.js.map +1 -1
- package/dist/test-helpers.d.ts +185 -13
- package/dist/test-helpers.d.ts.map +1 -1
- package/dist/test-helpers.js +274 -27
- package/dist/test-helpers.js.map +1 -1
- package/dist/testing.d.ts +73 -3
- package/dist/testing.d.ts.map +1 -1
- package/dist/testing.js +93 -3
- package/dist/testing.js.map +1 -1
- package/dist/text-content.d.ts +197 -0
- package/dist/text-content.d.ts.map +1 -0
- package/dist/text-content.js +348 -0
- package/dist/text-content.js.map +1 -0
- package/dist/text-file.d.ts +45 -0
- package/dist/text-file.d.ts.map +1 -0
- package/dist/text-file.js +53 -0
- package/dist/text-file.js.map +1 -0
- package/dist/text.d.ts +16 -0
- package/dist/text.d.ts.map +1 -0
- package/dist/text.js +16 -0
- package/dist/text.js.map +1 -0
- package/dist/timing-dump.d.ts +136 -0
- package/dist/timing-dump.d.ts.map +1 -0
- package/dist/timing-dump.js +230 -0
- package/dist/timing-dump.js.map +1 -0
- package/eslint/README.md +105 -3
- package/eslint/index.cjs +50 -0
- package/eslint/index.d.cts +14 -4
- package/eslint/rules/no-bare-symlink-in-tests.cjs +200 -0
- package/eslint/rules/no-process-exit-in-phase.cjs +117 -0
- package/eslint/rules/no-raw-text-decode.cjs +296 -0
- package/eslint/rules/no-self-package-import.cjs +157 -0
- package/package.json +13 -8
- package/dist/link-auth/build-headers.d.ts +0 -34
- package/dist/link-auth/build-headers.d.ts.map +0 -1
- package/dist/link-auth/build-headers.js +0 -58
- package/dist/link-auth/build-headers.js.map +0 -1
- package/dist/link-auth/expand-macro.d.ts +0 -38
- package/dist/link-auth/expand-macro.d.ts.map +0 -1
- package/dist/link-auth/expand-macro.js +0 -133
- package/dist/link-auth/expand-macro.js.map +0 -1
- package/dist/link-auth/macros.yaml +0 -50
- package/dist/link-auth/resolve-token.d.ts +0 -83
- package/dist/link-auth/resolve-token.d.ts.map +0 -1
- package/dist/link-auth/resolve-token.js +0 -101
- package/dist/link-auth/resolve-token.js.map +0 -1
- package/dist/link-auth/resolve.d.ts +0 -102
- package/dist/link-auth/resolve.d.ts.map +0 -1
- package/dist/link-auth/resolve.js +0 -66
- package/dist/link-auth/resolve.js.map +0 -1
- package/dist/link-auth/rewrite.d.ts +0 -52
- package/dist/link-auth/rewrite.d.ts.map +0 -1
- package/dist/link-auth/rewrite.js +0 -102
- package/dist/link-auth/rewrite.js.map +0 -1
- package/dist/link-auth/select-provider.d.ts +0 -30
- package/dist/link-auth/select-provider.d.ts.map +0 -1
- package/dist/link-auth/select-provider.js +0 -55
- package/dist/link-auth/select-provider.js.map +0 -1
- package/dist/link-auth/template.d.ts +0 -40
- package/dist/link-auth/template.d.ts.map +0 -1
- package/dist/link-auth/template.js +0 -89
- package/dist/link-auth/template.js.map +0 -1
- package/dist/link-auth/transforms.d.ts +0 -46
- package/dist/link-auth/transforms.d.ts.map +0 -1
- package/dist/link-auth/transforms.js +0 -52
- package/dist/link-auth/transforms.js.map +0 -1
- package/dist/template-entry.d.ts +0 -10
- package/dist/template-entry.d.ts.map +0 -1
- package/dist/template-entry.js +0 -10
- package/dist/template-entry.js.map +0 -1
- package/dist/template.d.ts +0 -7
- package/dist/template.d.ts.map +0 -1
- package/dist/template.js +0 -18
- package/dist/template.js.map +0 -1
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ESLint rule: no-self-package-import
|
|
3
|
+
*
|
|
4
|
+
* Disallow a file importing the package it already lives in **by that package's
|
|
5
|
+
* own name**. Inside `packages/foo/src`, write `./types.js`, never
|
|
6
|
+
* `@scope/foo`.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* // ❌ BAD — packages/agent-runtime/src/session/file-session-store.ts
|
|
10
|
+
* import type { SessionStore } from '@vibe-agent-toolkit/agent-runtime';
|
|
11
|
+
*
|
|
12
|
+
* // ✅ GOOD
|
|
13
|
+
* import type { SessionStore } from './types.js';
|
|
14
|
+
*
|
|
15
|
+
* ## Why this is a build-breaker and not a style preference
|
|
16
|
+
*
|
|
17
|
+
* A self-import resolves out through `node_modules` to the package's OWN
|
|
18
|
+
* `package.json`, whose `types`/`exports` point at `./dist/index.d.ts` — a file
|
|
19
|
+
* the compiler is in the middle of producing. It appears to work only because of
|
|
20
|
+
* a TypeScript courtesy: while `dist` IS the running project's output path,
|
|
21
|
+
* `dist/index.d.ts` is recognised as this project's own declaration output and
|
|
22
|
+
* the import is redirected back to `src`, so it resolves with no `dist/` on disk
|
|
23
|
+
* at all.
|
|
24
|
+
*
|
|
25
|
+
* That courtesy is conditional, and every condition is one a build script may
|
|
26
|
+
* legitimately change. Compile the package with `--outDir` pointed anywhere else
|
|
27
|
+
* — a staging directory used to make emit atomic, for instance — and `dist` is
|
|
28
|
+
* no longer this program's output, the redirect is gone, tsc looks for a literal
|
|
29
|
+
* `dist/index.d.ts`, and a tree that has never been built has none:
|
|
30
|
+
*
|
|
31
|
+
* error TS2307: Cannot find module '@scope/foo' or its corresponding type
|
|
32
|
+
* declarations.
|
|
33
|
+
*
|
|
34
|
+
* Knock-on `TS2339`s follow wherever a local type extended one of the now
|
|
35
|
+
* unresolved imports, which is what makes the failure read as a type bug in
|
|
36
|
+
* code nobody touched.
|
|
37
|
+
*
|
|
38
|
+
* ## Why the compiler cannot be trusted to find these
|
|
39
|
+
*
|
|
40
|
+
* The failure is invisible on any machine that has built the package before:
|
|
41
|
+
* a stale `dist/` satisfies the literal lookup, so the build passes — by
|
|
42
|
+
* typechecking the package against its PREVIOUS build's declarations. Worse, in
|
|
43
|
+
* a monorepo whose worktrees live inside the main checkout, module resolution
|
|
44
|
+
* walks up past the worktree into the parent checkout's `node_modules` and
|
|
45
|
+
* resolves against a DIFFERENT checkout's `dist/`. Both are green locally and
|
|
46
|
+
* red in CI, which is the only place the tree is genuinely pristine.
|
|
47
|
+
*
|
|
48
|
+
* So a self-import is latent by construction: it costs nothing until the day a
|
|
49
|
+
* build script changes `outDir`, and then it fails somewhere nobody can
|
|
50
|
+
* reproduce. Lint is the only stage that sees it on the author's machine.
|
|
51
|
+
*
|
|
52
|
+
* ## `packageName` is required, and the rule reads no files to get it
|
|
53
|
+
*
|
|
54
|
+
* The obvious implementation walks up from the linted file to the nearest
|
|
55
|
+
* `package.json` and reads its `name`. This rule deliberately does NOT: every
|
|
56
|
+
* module on the `./eslint` subpath is plain data that requires nothing — not
|
|
57
|
+
* `eslint`, not a third-party package, not even a Node builtin — which is what
|
|
58
|
+
* lets the pack ship as a subpath of a runtime package, keeps `eslint` an
|
|
59
|
+
* OPTIONAL peer dependency, and keeps the other subpaths resolving in a tree with
|
|
60
|
+
* no ESLint installed. `test/eslint/subpath-purity.test.ts` enforces that as an
|
|
61
|
+
* empty-set assertion. One `require('node:fs')` here would be the first crack in
|
|
62
|
+
* it, for a convenience the config layer can supply for free.
|
|
63
|
+
*
|
|
64
|
+
* So the caller names the package, and the caller is a config file that already
|
|
65
|
+
* runs in full Node and can read every manifest it likes. See the generated
|
|
66
|
+
* per-package blocks in this repo's `eslint.config.js`.
|
|
67
|
+
*
|
|
68
|
+
* Scoping is the caller's job for the same reason: only files a package actually
|
|
69
|
+
* COMPILES can break the build, and test and example trees commonly import their
|
|
70
|
+
* own package by name ON PURPOSE, to exercise the public entry point exactly as a
|
|
71
|
+
* consumer would.
|
|
72
|
+
*/
|
|
73
|
+
|
|
74
|
+
'use strict';
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Whether `specifier` names `packageName` itself or one of its subpaths.
|
|
78
|
+
*
|
|
79
|
+
* The subpath check is anchored on `/` so `@scope/foo-bar` is not read as a
|
|
80
|
+
* subpath of `@scope/foo`.
|
|
81
|
+
*
|
|
82
|
+
* @param {string} specifier - The import specifier as written.
|
|
83
|
+
* @param {string} packageName - The enclosing package's name.
|
|
84
|
+
* @returns {boolean}
|
|
85
|
+
*/
|
|
86
|
+
function isSelfReference(specifier, packageName) {
|
|
87
|
+
return specifier === packageName || specifier.startsWith(`${packageName}/`);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
module.exports = {
|
|
91
|
+
meta: {
|
|
92
|
+
type: 'problem',
|
|
93
|
+
docs: {
|
|
94
|
+
description:
|
|
95
|
+
"Disallow importing the enclosing package by its own name; use a relative path so the import does not depend on the package's built `dist/`.",
|
|
96
|
+
category: 'Build correctness',
|
|
97
|
+
recommended: true,
|
|
98
|
+
},
|
|
99
|
+
messages: {
|
|
100
|
+
useRelativeImport:
|
|
101
|
+
"Do not import '{{specifier}}' — this file is already inside '{{packageName}}'. That resolves through the package's own `dist/`, which only works while `dist` is the running compiler's output path; change `outDir` (or build a tree that has never been built) and it fails with TS2307. Import the defining module by relative path instead.",
|
|
102
|
+
},
|
|
103
|
+
schema: [
|
|
104
|
+
{
|
|
105
|
+
type: 'object',
|
|
106
|
+
properties: {
|
|
107
|
+
packageName: { type: 'string', minLength: 1 },
|
|
108
|
+
},
|
|
109
|
+
required: ['packageName'],
|
|
110
|
+
additionalProperties: false,
|
|
111
|
+
},
|
|
112
|
+
],
|
|
113
|
+
},
|
|
114
|
+
|
|
115
|
+
create(context) {
|
|
116
|
+
const { packageName } = context.options[0];
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* @param {{ type: string, value?: unknown } | null | undefined} source - A node in source position.
|
|
120
|
+
*/
|
|
121
|
+
const check = (source) => {
|
|
122
|
+
if (!source || source.type !== 'Literal') return;
|
|
123
|
+
const specifier = source.value;
|
|
124
|
+
if (typeof specifier !== 'string') return;
|
|
125
|
+
if (!isSelfReference(specifier, packageName)) return;
|
|
126
|
+
context.report({
|
|
127
|
+
node: source,
|
|
128
|
+
messageId: 'useRelativeImport',
|
|
129
|
+
data: { specifier, packageName },
|
|
130
|
+
});
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
return {
|
|
134
|
+
// `import … from 'x'` and `import type … from 'x'`
|
|
135
|
+
ImportDeclaration: (node) => check(node.source),
|
|
136
|
+
// `export … from 'x'` and `export * from 'x'` — a barrel re-exporting
|
|
137
|
+
// through its own package name is the same resolution, one step removed.
|
|
138
|
+
ExportNamedDeclaration: (node) => check(node.source),
|
|
139
|
+
ExportAllDeclaration: (node) => check(node.source),
|
|
140
|
+
// `await import('x')`
|
|
141
|
+
ImportExpression: (node) => check(node.source),
|
|
142
|
+
// `import('x')` in TYPE position, which no other visitor above reaches.
|
|
143
|
+
// The specifier hangs off `source`; typescript-eslint has called this
|
|
144
|
+
// property `parameter` and `argument` in earlier majors, and reading the
|
|
145
|
+
// wrong one costs nothing at lint time — the visitor simply never fires.
|
|
146
|
+
// The `import() in TYPE position` case in `rules.test.ts` is what turns
|
|
147
|
+
// that silence into a red test if a future parser renames it again.
|
|
148
|
+
TSImportType: (node) => check(node.source),
|
|
149
|
+
// `require('x')` in the `.cts`/`.cjs` files this pack also lints.
|
|
150
|
+
CallExpression: (node) => {
|
|
151
|
+
if (node.callee.type !== 'Identifier' || node.callee.name !== 'require') return;
|
|
152
|
+
if (node.arguments.length !== 1) return;
|
|
153
|
+
check(node.arguments[0]);
|
|
154
|
+
},
|
|
155
|
+
};
|
|
156
|
+
},
|
|
157
|
+
};
|
package/package.json
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vibe-agent-toolkit/utils",
|
|
3
|
-
"version": "0.2.0-rc.
|
|
3
|
+
"version": "0.2.0-rc.4",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Core utility functions shared across the vibe-agent-toolkit packages",
|
|
6
|
-
"sideEffects":
|
|
6
|
+
"sideEffects": [
|
|
7
|
+
"./dist/crawl-timing.js"
|
|
8
|
+
],
|
|
7
9
|
"keywords": [
|
|
8
10
|
"typescript",
|
|
9
11
|
"utilities",
|
|
@@ -32,6 +34,10 @@
|
|
|
32
34
|
"types": "./dist/fs.d.ts",
|
|
33
35
|
"import": "./dist/fs.js"
|
|
34
36
|
},
|
|
37
|
+
"./text": {
|
|
38
|
+
"types": "./dist/text.d.ts",
|
|
39
|
+
"import": "./dist/text.js"
|
|
40
|
+
},
|
|
35
41
|
"./process": {
|
|
36
42
|
"types": "./dist/process.d.ts",
|
|
37
43
|
"import": "./dist/process.js"
|
|
@@ -48,9 +54,9 @@
|
|
|
48
54
|
"types": "./dist/zod.d.ts",
|
|
49
55
|
"import": "./dist/zod.js"
|
|
50
56
|
},
|
|
51
|
-
"./
|
|
52
|
-
"types": "./dist/
|
|
53
|
-
"import": "./dist/
|
|
57
|
+
"./skill-test": {
|
|
58
|
+
"types": "./dist/skill-test/index.d.ts",
|
|
59
|
+
"import": "./dist/skill-test/index.js"
|
|
54
60
|
},
|
|
55
61
|
"./yaml": {
|
|
56
62
|
"types": "./dist/yaml.d.ts",
|
|
@@ -84,16 +90,15 @@
|
|
|
84
90
|
"README.md"
|
|
85
91
|
],
|
|
86
92
|
"scripts": {
|
|
87
|
-
"build": "rimraf --glob dist \"*.tsbuildinfo\" && tsc
|
|
93
|
+
"build": "rimraf --glob dist \"*.tsbuildinfo\" && tsc",
|
|
88
94
|
"test:unit": "vitest run",
|
|
89
95
|
"test:integration": "vitest run --config vitest.integration.config.ts",
|
|
90
|
-
"test:system": "vitest run --config vitest.system.config.ts",
|
|
91
96
|
"test:watch": "vitest",
|
|
92
97
|
"typecheck": "tsc --noEmit",
|
|
93
98
|
"clean": "rimraf dist *.tsbuildinfo"
|
|
94
99
|
},
|
|
95
100
|
"dependencies": {
|
|
96
|
-
"
|
|
101
|
+
"@vibe-validate/git": "0.20.1",
|
|
97
102
|
"ignore": "^7.0.5",
|
|
98
103
|
"picomatch": "^4.0.3",
|
|
99
104
|
"which": "^5.0.0",
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Render auth-header templates with rendered values, and a structural
|
|
3
|
-
* redaction helper for serialization.
|
|
4
|
-
*
|
|
5
|
-
* `buildHeaders` renders each header value template against a context that
|
|
6
|
-
* carries `${token}` plus any named captures / vars from the rewrite step.
|
|
7
|
-
* `redactHeaders` masks `Authorization` values for any caller that needs to
|
|
8
|
-
* serialize headers into logs, errors, or cache entries — the design's §8
|
|
9
|
-
* "tokens never leak" claim depends on every such site routing through this.
|
|
10
|
-
*
|
|
11
|
-
* Per design issue #113 §4 (auth.headers vocabulary) and §8 (redaction is
|
|
12
|
-
* structural; Authorization values never appear in serialized output).
|
|
13
|
-
*/
|
|
14
|
-
export declare const REDACTED_VALUE = "<redacted>";
|
|
15
|
-
/**
|
|
16
|
-
* Render a map of header templates into a map of concrete header values.
|
|
17
|
-
*
|
|
18
|
-
* @throws {TemplateMissingVarError} if a header template references an
|
|
19
|
-
* unknown context key
|
|
20
|
-
* @throws {TemplateSyntaxError} from a malformed template expression
|
|
21
|
-
* @throws {UnknownTransformError} from a template calling an unknown transform
|
|
22
|
-
*/
|
|
23
|
-
export declare function buildHeaders(templates: Record<string, string>, context: Record<string, string>): Record<string, string>;
|
|
24
|
-
/**
|
|
25
|
-
* Return a copy of `headers` with sensitive values replaced by `REDACTED_VALUE`.
|
|
26
|
-
* Header-name matching is case-insensitive but exact (no prefix matching) — a
|
|
27
|
-
* header like `X-Authorization-Foo` is NOT considered sensitive.
|
|
28
|
-
*
|
|
29
|
-
* **Input must be a plain key-value object.** A `Headers` instance (Web Fetch
|
|
30
|
-
* API) or a `Map` yields `[]` from `Object.entries` and would silently no-op
|
|
31
|
-
* redaction — converting to a plain object is the caller's responsibility.
|
|
32
|
-
*/
|
|
33
|
-
export declare function redactHeaders(headers: Record<string, string>): Record<string, string>;
|
|
34
|
-
//# sourceMappingURL=build-headers.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"build-headers.d.ts","sourceRoot":"","sources":["../../src/link-auth/build-headers.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAIH,eAAO,MAAM,cAAc,eAAe,CAAC;AAc3C;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAC1B,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EACjC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC9B,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAMxB;AAED;;;;;;;;GAQG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAMrF"}
|
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Render auth-header templates with rendered values, and a structural
|
|
3
|
-
* redaction helper for serialization.
|
|
4
|
-
*
|
|
5
|
-
* `buildHeaders` renders each header value template against a context that
|
|
6
|
-
* carries `${token}` plus any named captures / vars from the rewrite step.
|
|
7
|
-
* `redactHeaders` masks `Authorization` values for any caller that needs to
|
|
8
|
-
* serialize headers into logs, errors, or cache entries — the design's §8
|
|
9
|
-
* "tokens never leak" claim depends on every such site routing through this.
|
|
10
|
-
*
|
|
11
|
-
* Per design issue #113 §4 (auth.headers vocabulary) and §8 (redaction is
|
|
12
|
-
* structural; Authorization values never appear in serialized output).
|
|
13
|
-
*/
|
|
14
|
-
import { renderTemplate } from './template.js';
|
|
15
|
-
export const REDACTED_VALUE = '<redacted>';
|
|
16
|
-
/**
|
|
17
|
-
* Header names whose values must be masked when serialized.
|
|
18
|
-
*
|
|
19
|
-
* v1 ships only `authorization` because that is the only secret-bearing
|
|
20
|
-
* header the current macros emit. **Omission is the security risk** — any
|
|
21
|
-
* future macro that emits a header carrying a secret (`Cookie`,
|
|
22
|
-
* `Proxy-Authorization`, `X-API-Key`, custom bearer-style headers) must add
|
|
23
|
-
* that name here, or the token will silently leak through serialization.
|
|
24
|
-
* Extending the set is not the dangerous edit; forgetting to extend it is.
|
|
25
|
-
*/
|
|
26
|
-
const SENSITIVE_HEADER_NAMES = new Set(['authorization']);
|
|
27
|
-
/**
|
|
28
|
-
* Render a map of header templates into a map of concrete header values.
|
|
29
|
-
*
|
|
30
|
-
* @throws {TemplateMissingVarError} if a header template references an
|
|
31
|
-
* unknown context key
|
|
32
|
-
* @throws {TemplateSyntaxError} from a malformed template expression
|
|
33
|
-
* @throws {UnknownTransformError} from a template calling an unknown transform
|
|
34
|
-
*/
|
|
35
|
-
export function buildHeaders(templates, context) {
|
|
36
|
-
const headers = Object.create(null);
|
|
37
|
-
for (const [name, template] of Object.entries(templates)) {
|
|
38
|
-
headers[name] = renderTemplate(template, context);
|
|
39
|
-
}
|
|
40
|
-
return headers;
|
|
41
|
-
}
|
|
42
|
-
/**
|
|
43
|
-
* Return a copy of `headers` with sensitive values replaced by `REDACTED_VALUE`.
|
|
44
|
-
* Header-name matching is case-insensitive but exact (no prefix matching) — a
|
|
45
|
-
* header like `X-Authorization-Foo` is NOT considered sensitive.
|
|
46
|
-
*
|
|
47
|
-
* **Input must be a plain key-value object.** A `Headers` instance (Web Fetch
|
|
48
|
-
* API) or a `Map` yields `[]` from `Object.entries` and would silently no-op
|
|
49
|
-
* redaction — converting to a plain object is the caller's responsibility.
|
|
50
|
-
*/
|
|
51
|
-
export function redactHeaders(headers) {
|
|
52
|
-
const redacted = Object.create(null);
|
|
53
|
-
for (const [name, value] of Object.entries(headers)) {
|
|
54
|
-
redacted[name] = SENSITIVE_HEADER_NAMES.has(name.toLowerCase()) ? REDACTED_VALUE : value;
|
|
55
|
-
}
|
|
56
|
-
return redacted;
|
|
57
|
-
}
|
|
58
|
-
//# sourceMappingURL=build-headers.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"build-headers.js","sourceRoot":"","sources":["../../src/link-auth/build-headers.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAE/C,MAAM,CAAC,MAAM,cAAc,GAAG,YAAY,CAAC;AAE3C;;;;;;;;;GASG;AACH,MAAM,sBAAsB,GAAwB,IAAI,GAAG,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC;AAE/E;;;;;;;GAOG;AACH,MAAM,UAAU,YAAY,CAC1B,SAAiC,EACjC,OAA+B;IAE/B,MAAM,OAAO,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,CAA2B,CAAC;IAC9D,KAAK,MAAM,CAAC,IAAI,EAAE,QAAQ,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,CAAC;QACzD,OAAO,CAAC,IAAI,CAAC,GAAG,cAAc,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IACpD,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,aAAa,CAAC,OAA+B;IAC3D,MAAM,QAAQ,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,CAA2B,CAAC;IAC/D,KAAK,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;QACpD,QAAQ,CAAC,IAAI,CAAC,GAAG,sBAAsB,CAAC,GAAG,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,KAAK,CAAC;IAC3F,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC"}
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Macro loader + expander.
|
|
3
|
-
*
|
|
4
|
-
* Loads the bundled `macros.yaml` once at module init and exposes
|
|
5
|
-
* `expandMacro(name, overrides?)` which deep-merges the named macro with any
|
|
6
|
-
* adopter overrides. The merge is "adopter wins": objects merge recursively,
|
|
7
|
-
* arrays and primitives are replaced wholesale (no element-wise array merge).
|
|
8
|
-
*
|
|
9
|
-
* The shipped macro file is at `link-auth/macros.yaml`, copied into the dist
|
|
10
|
-
* tree by `packages/dev-tools/src/copy-yaml-assets.ts` during build so the
|
|
11
|
-
* runtime `fs.readFileSync(new URL('./macros.yaml', import.meta.url))`
|
|
12
|
-
* resolves in both source-mode (vitest) and built-mode (dist).
|
|
13
|
-
*
|
|
14
|
-
* Per design issue #113 §5 (macros are config, not a privileged code path).
|
|
15
|
-
*/
|
|
16
|
-
/**
|
|
17
|
-
* Thrown when a `use: <name>` references a macro not in the shipped set.
|
|
18
|
-
* Message lists the available macros so a typo surfaces clearly.
|
|
19
|
-
*/
|
|
20
|
-
export declare class UnknownMacroError extends Error {
|
|
21
|
-
constructor(name: string, available: readonly string[]);
|
|
22
|
-
}
|
|
23
|
-
/**
|
|
24
|
-
* Look up a macro by name and deep-merge optional adopter overrides on top.
|
|
25
|
-
*
|
|
26
|
-
* Merge semantics:
|
|
27
|
-
* - Plain objects merge recursively (sibling keys preserved).
|
|
28
|
-
* - Arrays are replaced wholesale (override's array wins; no concat).
|
|
29
|
-
* - Primitives are replaced.
|
|
30
|
-
* - `undefined` in an override is treated as "not provided" (base wins).
|
|
31
|
-
*
|
|
32
|
-
* The returned object and all nested plain objects use null prototypes so
|
|
33
|
-
* `__proto__` / `constructor` keys can never poison consumers.
|
|
34
|
-
*
|
|
35
|
-
* @throws {UnknownMacroError} if `name` is not in the shipped macro set
|
|
36
|
-
*/
|
|
37
|
-
export declare function expandMacro(name: string, overrides?: Record<string, unknown>): Record<string, unknown>;
|
|
38
|
-
//# sourceMappingURL=expand-macro.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"expand-macro.d.ts","sourceRoot":"","sources":["../../src/link-auth/expand-macro.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAyCH;;;GAGG;AACH,qBAAa,iBAAkB,SAAQ,KAAK;gBAC9B,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,SAAS,MAAM,EAAE;CAIvD;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,WAAW,CACzB,IAAI,EAAE,MAAM,EACZ,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAClC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAYzB"}
|
|
@@ -1,133 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Macro loader + expander.
|
|
3
|
-
*
|
|
4
|
-
* Loads the bundled `macros.yaml` once at module init and exposes
|
|
5
|
-
* `expandMacro(name, overrides?)` which deep-merges the named macro with any
|
|
6
|
-
* adopter overrides. The merge is "adopter wins": objects merge recursively,
|
|
7
|
-
* arrays and primitives are replaced wholesale (no element-wise array merge).
|
|
8
|
-
*
|
|
9
|
-
* The shipped macro file is at `link-auth/macros.yaml`, copied into the dist
|
|
10
|
-
* tree by `packages/dev-tools/src/copy-yaml-assets.ts` during build so the
|
|
11
|
-
* runtime `fs.readFileSync(new URL('./macros.yaml', import.meta.url))`
|
|
12
|
-
* resolves in both source-mode (vitest) and built-mode (dist).
|
|
13
|
-
*
|
|
14
|
-
* Per design issue #113 §5 (macros are config, not a privileged code path).
|
|
15
|
-
*/
|
|
16
|
-
import { readFileSync } from 'node:fs';
|
|
17
|
-
import { fileURLToPath } from 'node:url';
|
|
18
|
-
import { parse as parseYaml } from 'yaml';
|
|
19
|
-
let macrosCache;
|
|
20
|
-
/**
|
|
21
|
-
* Load macros lazily on first use rather than at module init.
|
|
22
|
-
*
|
|
23
|
-
* Why lazy: vitest tests elsewhere in the repo mock `node:fs` (replacing
|
|
24
|
-
* `readFileSync` with `vi.fn()` that returns `undefined`). If we eagerly read
|
|
25
|
-
* at module load, any unrelated test that imports `@vibe-agent-toolkit/utils`
|
|
26
|
-
* and mocks fs crashes inside `parseYaml(undefined)` — module-init code runs
|
|
27
|
-
* unconditionally, before the mock-setup intent reaches our file.
|
|
28
|
-
*
|
|
29
|
-
* Lazy load makes module import side-effect-free; only callers of
|
|
30
|
-
* `expandMacro` pay the fs cost. `macrosPath` is also computed here (not at
|
|
31
|
-
* module top level) so that merely importing this module leaves no `new URL()`
|
|
32
|
-
* reference for bundler static analysis to trip over.
|
|
33
|
-
*/
|
|
34
|
-
function getMacros() {
|
|
35
|
-
if (macrosCache !== undefined)
|
|
36
|
-
return macrosCache;
|
|
37
|
-
// Path is derived from `import.meta.url`, not user input — points at the
|
|
38
|
-
// shipped macros.yaml asset next to this module in both src and dist trees.
|
|
39
|
-
const macrosPath = fileURLToPath(new URL('./macros.yaml', import.meta.url));
|
|
40
|
-
// eslint-disable-next-line security/detect-non-literal-fs-filename
|
|
41
|
-
const macrosFileContent = readFileSync(macrosPath, 'utf8');
|
|
42
|
-
const parsed = parseYaml(macrosFileContent);
|
|
43
|
-
if (!isPlainObject(parsed)) {
|
|
44
|
-
throw new Error('macros.yaml: expected top-level object mapping macro name → provider config.');
|
|
45
|
-
}
|
|
46
|
-
macrosCache = freezeMacros(parsed);
|
|
47
|
-
return macrosCache;
|
|
48
|
-
}
|
|
49
|
-
/**
|
|
50
|
-
* Thrown when a `use: <name>` references a macro not in the shipped set.
|
|
51
|
-
* Message lists the available macros so a typo surfaces clearly.
|
|
52
|
-
*/
|
|
53
|
-
export class UnknownMacroError extends Error {
|
|
54
|
-
constructor(name, available) {
|
|
55
|
-
super(`Unknown macro "${name}". Available: ${available.join(', ')}.`);
|
|
56
|
-
this.name = 'UnknownMacroError';
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
/**
|
|
60
|
-
* Look up a macro by name and deep-merge optional adopter overrides on top.
|
|
61
|
-
*
|
|
62
|
-
* Merge semantics:
|
|
63
|
-
* - Plain objects merge recursively (sibling keys preserved).
|
|
64
|
-
* - Arrays are replaced wholesale (override's array wins; no concat).
|
|
65
|
-
* - Primitives are replaced.
|
|
66
|
-
* - `undefined` in an override is treated as "not provided" (base wins).
|
|
67
|
-
*
|
|
68
|
-
* The returned object and all nested plain objects use null prototypes so
|
|
69
|
-
* `__proto__` / `constructor` keys can never poison consumers.
|
|
70
|
-
*
|
|
71
|
-
* @throws {UnknownMacroError} if `name` is not in the shipped macro set
|
|
72
|
-
*/
|
|
73
|
-
export function expandMacro(name, overrides) {
|
|
74
|
-
const macros = getMacros();
|
|
75
|
-
const base = macros[name];
|
|
76
|
-
if (base === undefined) {
|
|
77
|
-
throw new UnknownMacroError(name, Object.keys(macros));
|
|
78
|
-
}
|
|
79
|
-
if (overrides === undefined) {
|
|
80
|
-
return cloneWithNullProto(base);
|
|
81
|
-
}
|
|
82
|
-
const merged = deepMerge(base, overrides);
|
|
83
|
-
// Top-level result is guaranteed object here because base is.
|
|
84
|
-
return merged;
|
|
85
|
-
}
|
|
86
|
-
function deepMerge(base, override) {
|
|
87
|
-
if (override === undefined)
|
|
88
|
-
return base;
|
|
89
|
-
if (!isPlainObject(base) || !isPlainObject(override))
|
|
90
|
-
return cloneValue(override);
|
|
91
|
-
const result = Object.create(null);
|
|
92
|
-
for (const [key, value] of Object.entries(base)) {
|
|
93
|
-
result[key] = cloneValue(value);
|
|
94
|
-
}
|
|
95
|
-
for (const [key, value] of Object.entries(override)) {
|
|
96
|
-
const existing = Object.hasOwn(result, key) ? result[key] : undefined;
|
|
97
|
-
if (isPlainObject(existing) && isPlainObject(value)) {
|
|
98
|
-
result[key] = deepMerge(existing, value);
|
|
99
|
-
}
|
|
100
|
-
else {
|
|
101
|
-
result[key] = cloneValue(value);
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
return result;
|
|
105
|
-
}
|
|
106
|
-
function cloneValue(value) {
|
|
107
|
-
if (Array.isArray(value))
|
|
108
|
-
return value.map(cloneValue);
|
|
109
|
-
if (isPlainObject(value))
|
|
110
|
-
return cloneWithNullProto(value);
|
|
111
|
-
return value;
|
|
112
|
-
}
|
|
113
|
-
function cloneWithNullProto(obj) {
|
|
114
|
-
const cloned = Object.create(null);
|
|
115
|
-
for (const [key, value] of Object.entries(obj)) {
|
|
116
|
-
cloned[key] = cloneValue(value);
|
|
117
|
-
}
|
|
118
|
-
return cloned;
|
|
119
|
-
}
|
|
120
|
-
function freezeMacros(parsed) {
|
|
121
|
-
const frozen = Object.create(null);
|
|
122
|
-
for (const [name, value] of Object.entries(parsed)) {
|
|
123
|
-
if (!isPlainObject(value)) {
|
|
124
|
-
throw new Error(`macros.yaml: macro "${name}" is not an object.`);
|
|
125
|
-
}
|
|
126
|
-
frozen[name] = cloneWithNullProto(value);
|
|
127
|
-
}
|
|
128
|
-
return frozen;
|
|
129
|
-
}
|
|
130
|
-
function isPlainObject(v) {
|
|
131
|
-
return typeof v === 'object' && v !== null && !Array.isArray(v);
|
|
132
|
-
}
|
|
133
|
-
//# sourceMappingURL=expand-macro.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"expand-macro.js","sourceRoot":"","sources":["../../src/link-auth/expand-macro.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
# linkAuth provider macros — shipped defaults referenced by `use: <name>` in
|
|
2
|
-
# adopter `vibe-agent-toolkit.config.yaml` files.
|
|
3
|
-
#
|
|
4
|
-
# Each entry is a full provider config in the §4 vocabulary (match, rewrite,
|
|
5
|
-
# auth, token, check). Adopters reference a macro by name and may deep-merge
|
|
6
|
-
# overrides on top — see design issue #113 §5.
|
|
7
|
-
#
|
|
8
|
-
# Adding a new host is intended to be a config-only PR: append an entry here
|
|
9
|
-
# and add unit tests. Only `vocabulary` changes (e.g. a new transform) require
|
|
10
|
-
# engine code.
|
|
11
|
-
|
|
12
|
-
github:
|
|
13
|
-
match:
|
|
14
|
-
host: github.com
|
|
15
|
-
rewrite:
|
|
16
|
-
- when: '^https://github\.com/(?<owner>[^/]+)/(?<repo>[^/]+)/(?:blob|tree)/(?<ref>[^/]+)/(?<path>.+)$'
|
|
17
|
-
to: 'https://api.github.com/repos/${owner}/${repo}/contents/${path}?ref=${ref}'
|
|
18
|
-
auth:
|
|
19
|
-
headers:
|
|
20
|
-
Authorization: 'Bearer ${token}'
|
|
21
|
-
Accept: application/vnd.github+json
|
|
22
|
-
token:
|
|
23
|
-
- command: gh auth token
|
|
24
|
-
- env: GITHUB_TOKEN
|
|
25
|
-
check:
|
|
26
|
-
method: GET
|
|
27
|
-
aliveStatus: [200]
|
|
28
|
-
notFoundMeaning: ambiguous
|
|
29
|
-
|
|
30
|
-
sharepoint:
|
|
31
|
-
match:
|
|
32
|
-
host: '*.sharepoint.com'
|
|
33
|
-
excludeHost:
|
|
34
|
-
- '*-my.sharepoint.com'
|
|
35
|
-
rewrite:
|
|
36
|
-
- when: '^(?<u>https://.+)$'
|
|
37
|
-
vars:
|
|
38
|
-
shareId: 'u!${base64url(u)}'
|
|
39
|
-
to: 'https://graph.microsoft.com/v1.0/shares/${shareId}/driveItem'
|
|
40
|
-
auth:
|
|
41
|
-
headers:
|
|
42
|
-
Authorization: 'Bearer ${token}'
|
|
43
|
-
# SharePoint has no zero-config token source (design §5.1 note): a SharePoint-
|
|
44
|
-
# scoped token requires an Entra app registration; the stock `az` token does
|
|
45
|
-
# not work. Adopter must supply their own token command.
|
|
46
|
-
token: []
|
|
47
|
-
check:
|
|
48
|
-
method: GET
|
|
49
|
-
aliveStatus: [200]
|
|
50
|
-
notFoundMeaning: dead
|
|
@@ -1,83 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Token resolution — ordered, first-non-empty-wins.
|
|
3
|
-
*
|
|
4
|
-
* Iterates a provider's `token` source list and returns the first source that
|
|
5
|
-
* yields a non-empty value. Two source shapes:
|
|
6
|
-
* - `{ env: "NAME" }` — read from process env (no trimming)
|
|
7
|
-
* - `{ command: argv }` — run a command, return trimmed stdout
|
|
8
|
-
* - `{ command: "gh auth token" }` — convenience: whitespace-tokenized into
|
|
9
|
-
* argv. **Not** passed through a shell — operators (`|`, `&&`, `$(...)`)
|
|
10
|
-
* become literal argv elements, per the design's §6.1 sharp-edge note.
|
|
11
|
-
*
|
|
12
|
-
* Command sources can be disabled at runtime with `VAT_LINKAUTH_ALLOW_COMMAND=0`
|
|
13
|
-
* (or by passing `allowCommand: false` in deps). Useful in security-sensitive
|
|
14
|
-
* environments where arbitrary command execution is undesirable.
|
|
15
|
-
*
|
|
16
|
-
* Returns `undefined` if every source fails or yields an empty/whitespace
|
|
17
|
-
* value — the caller's `resolveAuthenticatedUrl` translates that to the
|
|
18
|
-
* `unverified` outcome (surfaced as `LINK_AUTH_UNVERIFIED` by the validator).
|
|
19
|
-
*
|
|
20
|
-
* Per design issue #113 §4 (token vocabulary) and §6.1 (command execution,
|
|
21
|
-
* `safeExecSync`-backed, `shell: false`).
|
|
22
|
-
*/
|
|
23
|
-
export type TokenSource = {
|
|
24
|
-
readonly env: string;
|
|
25
|
-
} | {
|
|
26
|
-
readonly command: string | readonly string[];
|
|
27
|
-
};
|
|
28
|
-
export interface TokenResolutionDeps {
|
|
29
|
-
/**
|
|
30
|
-
* Environment lookup map. Defaults to `process.env`. Injectable for tests so
|
|
31
|
-
* unit tests don't depend on ambient environment state.
|
|
32
|
-
*/
|
|
33
|
-
readonly env: Record<string, string | undefined>;
|
|
34
|
-
/**
|
|
35
|
-
* Command runner. Defaults to `safeExecResult`-wrapped invocation. Injectable
|
|
36
|
-
* for tests. Receives argv; returns `success` + `stdout`. Should NOT throw
|
|
37
|
-
* for normal exec failures (return `success: false` instead). Throws are
|
|
38
|
-
* propagated by `resolveToken` — they indicate operator-level bugs.
|
|
39
|
-
*/
|
|
40
|
-
readonly runCommand: (argv: readonly string[]) => {
|
|
41
|
-
success: boolean;
|
|
42
|
-
stdout: string;
|
|
43
|
-
};
|
|
44
|
-
/**
|
|
45
|
-
* Whether `{ command: ... }` sources are allowed. Defaults to reading
|
|
46
|
-
* `VAT_LINKAUTH_ALLOW_COMMAND` from the resolved `env` map (not ambient
|
|
47
|
-
* `process.env`), so a caller supplying a curated `deps.env` can control the
|
|
48
|
-
* flag without touching real process state. Set to `false` (or set
|
|
49
|
-
* `VAT_LINKAUTH_ALLOW_COMMAND=0` in the env) to skip all command sources and
|
|
50
|
-
* rely solely on env-var sources — useful in locked-down CI or security reviews.
|
|
51
|
-
*/
|
|
52
|
-
readonly allowCommand: boolean;
|
|
53
|
-
}
|
|
54
|
-
/**
|
|
55
|
-
* Return a copy of the given env with all `GIT_*` keys removed. Case-insensitive
|
|
56
|
-
* on the key so Windows env vars (which are case-insensitive at the OS level,
|
|
57
|
-
* though `process.env` preserves original case) can't sneak through as e.g.
|
|
58
|
-
* `Git_Dir`.
|
|
59
|
-
*
|
|
60
|
-
* Exported for unit testing and for callers assembling their own `runCommand`
|
|
61
|
-
* who want the exact same scrub `defaultRunCommand` applies.
|
|
62
|
-
*
|
|
63
|
-
* Rationale: `vat resources validate` is often invoked from git pre-commit
|
|
64
|
-
* hooks, which pre-set `GIT_DIR` / `GIT_WORK_TREE` / `GIT_INDEX_FILE`. These
|
|
65
|
-
* poison any nested tool that shells out to git, notably `gh auth token`.
|
|
66
|
-
*/
|
|
67
|
-
export declare function scrubGitEnv(source: NodeJS.ProcessEnv): NodeJS.ProcessEnv;
|
|
68
|
-
/**
|
|
69
|
-
* Default `runCommand` implementation — exported so callers that want to
|
|
70
|
-
* memoize per-validate-run can wrap it without duplicating the spawn logic.
|
|
71
|
-
* Forwards to `safeExecResult` (no shell, argv-based), with `GIT_*` vars
|
|
72
|
-
* stripped from the child env — see {@link scrubGitEnv}.
|
|
73
|
-
*/
|
|
74
|
-
export declare const defaultRunCommand: TokenResolutionDeps['runCommand'];
|
|
75
|
-
/**
|
|
76
|
-
* Resolve a token from an ordered list of sources.
|
|
77
|
-
*
|
|
78
|
-
* @returns the first non-empty value, or `undefined` if every source failed.
|
|
79
|
-
* @throws whatever the injected `runCommand` throws (operator-level bug; not
|
|
80
|
-
* swallowed). Standard `safeExecResult` does not throw under normal use.
|
|
81
|
-
*/
|
|
82
|
-
export declare function resolveToken(sources: readonly TokenSource[], deps?: Partial<TokenResolutionDeps>): string | undefined;
|
|
83
|
-
//# sourceMappingURL=resolve-token.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"resolve-token.d.ts","sourceRoot":"","sources":["../../src/link-auth/resolve-token.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAIH,MAAM,MAAM,WAAW,GAAG;IAAE,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,CAAA;CAAE,CAAC;AAEtG,MAAM,WAAW,mBAAmB;IAClC;;;OAGG;IACH,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;IAEjD;;;;;OAKG;IACH,QAAQ,CAAC,UAAU,EAAE,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,KAAK;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IAEvF;;;;;;;OAOG;IACH,QAAQ,CAAC,YAAY,EAAE,OAAO,CAAC;CAChC;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,UAAU,GAAG,MAAM,CAAC,UAAU,CAIxE;AAED;;;;;GAKG;AACH,eAAO,MAAM,iBAAiB,EAAE,mBAAmB,CAAC,YAAY,CAO/D,CAAC;AAEF;;;;;;GAMG;AACH,wBAAgB,YAAY,CAC1B,OAAO,EAAE,SAAS,WAAW,EAAE,EAC/B,IAAI,CAAC,EAAE,OAAO,CAAC,mBAAmB,CAAC,GAClC,MAAM,GAAG,SAAS,CAWpB"}
|