scp-next 1.0.19 → 1.1.2
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/CHANGELOG.md +12 -1
- package/README.md +91 -35
- package/dist/cli/index.js +479 -71
- package/dist/cli/index.js.map +1 -1
- package/dist/index.cjs +391 -32
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +49 -5
- package/dist/index.d.ts +49 -5
- package/dist/index.js +390 -32
- package/dist/index.js.map +1 -1
- package/{docs → guides}/ARCHITECTURE.md +21 -4
- package/guides/mazey-candidates.md +364 -0
- package/guides/release-notes/introducing-scp-next-v1.0.19-en.md +347 -0
- package/{docs → guides}/release-notes/introducing-scp-next-v1.0.19-zh.md +3 -3
- package/package.json +9 -4
- /package/{docs → guides}/release-notes/introducing-scp-next-v1.0.14.md +0 -0
- /package/{docs → guides}/release-notes/introducing-scp-next-v1.0.2.md +0 -0
|
@@ -0,0 +1,364 @@
|
|
|
1
|
+
# Reusable Utility Candidates
|
|
2
|
+
|
|
3
|
+
## Summary
|
|
4
|
+
|
|
5
|
+
- **Strong candidates:** 3
|
|
6
|
+
- **Possible candidates:** 3
|
|
7
|
+
- **Main overlap:** integer parsing, positive-number validation, test streams, and path
|
|
8
|
+
resolution have smaller duplicated variants.
|
|
9
|
+
- **Intentionally excluded:** SFTP transfer orchestration, CLI operand policy, configuration
|
|
10
|
+
precedence, typed `scp-next` errors, and local-versus-remote path policy.
|
|
11
|
+
|
|
12
|
+
The ranking favors low coupling and clear behavior. Security-sensitive candidates remain
|
|
13
|
+
conditional on stronger specifications and tests.
|
|
14
|
+
|
|
15
|
+
## 1. `restoreMsysConvertedPosixPath`
|
|
16
|
+
|
|
17
|
+
**Priority:** Strong candidate
|
|
18
|
+
**Current location:** `src/paths/remote-path.ts` as `restoreMsysConvertedRemotePath`
|
|
19
|
+
|
|
20
|
+
### Purpose
|
|
21
|
+
|
|
22
|
+
Restores POSIX-like arguments that Git Bash/MSYS has rewritten into Windows Git installation
|
|
23
|
+
paths, while leaving ordinary inputs unchanged.
|
|
24
|
+
|
|
25
|
+
### Why it is reusable
|
|
26
|
+
|
|
27
|
+
Container, cloud-storage, archive, deployment, and remote-execution CLIs often accept POSIX
|
|
28
|
+
paths that cross an MSYS process boundary and encounter the same unwanted argument conversion.
|
|
29
|
+
|
|
30
|
+
### Duplication or overlap
|
|
31
|
+
|
|
32
|
+
There is no duplicate helper. It has strong independent reuse value and protects both upload
|
|
33
|
+
destinations and download sources through configuration resolution.
|
|
34
|
+
|
|
35
|
+
### Proposed API
|
|
36
|
+
|
|
37
|
+
```ts
|
|
38
|
+
export interface MsysPathRestoreOptions {
|
|
39
|
+
installationPrefixes?: readonly string[];
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export function restoreMsysConvertedPosixPath(
|
|
43
|
+
value: string,
|
|
44
|
+
options?: MsysPathRestoreOptions
|
|
45
|
+
): string;
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### Generalization required
|
|
49
|
+
|
|
50
|
+
- Remove remote-transfer terminology from the name and documentation.
|
|
51
|
+
- Make recognized Git/MSYS installation prefixes configurable while retaining safe defaults.
|
|
52
|
+
- Specify slash preservation and whether drive-letter matching is case-insensitive.
|
|
53
|
+
|
|
54
|
+
### Risks and limitations
|
|
55
|
+
|
|
56
|
+
- The heuristic can misclassify a legitimate Windows path beneath a matching installation
|
|
57
|
+
directory.
|
|
58
|
+
- Git installations in uncommon directories require caller configuration.
|
|
59
|
+
- This helper should restore arguments only; it must not perform general path normalization.
|
|
60
|
+
|
|
61
|
+
## 2. `isDirectlyExecuted`
|
|
62
|
+
|
|
63
|
+
**Priority:** Strong candidate
|
|
64
|
+
**Current location:** `src/cli/index.ts` as `isCliEntrypoint`
|
|
65
|
+
|
|
66
|
+
### Purpose
|
|
67
|
+
|
|
68
|
+
Determines whether an ESM module is the process entrypoint by resolving both the module URL and
|
|
69
|
+
the executed file to real paths. It correctly recognizes symlinked npm binaries and returns
|
|
70
|
+
`false` when either path cannot be resolved.
|
|
71
|
+
|
|
72
|
+
### Why it is reusable
|
|
73
|
+
|
|
74
|
+
Any Node.js ESM package that exposes both importable functions and an executable entrypoint needs
|
|
75
|
+
a reliable direct-execution check that works through package-manager-created symlinks.
|
|
76
|
+
|
|
77
|
+
### Duplication or overlap
|
|
78
|
+
|
|
79
|
+
The same simpler URL-versus-argv comparison appears in `scripts/build-pages.js`, but that variant
|
|
80
|
+
does not resolve symlinks. A shared helper would replace this behavioral overlap.
|
|
81
|
+
|
|
82
|
+
### Proposed API
|
|
83
|
+
|
|
84
|
+
```ts
|
|
85
|
+
export function isDirectlyExecuted(moduleUrl: string, argv?: readonly string[]): boolean;
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### Generalization required
|
|
89
|
+
|
|
90
|
+
- Rename the helper to remove `scp-next` CLI terminology.
|
|
91
|
+
- Accept a readonly argv input while defaulting to `process.argv`.
|
|
92
|
+
- Preserve the current fail-closed behavior for missing files and invalid URLs.
|
|
93
|
+
|
|
94
|
+
### Risks and limitations
|
|
95
|
+
|
|
96
|
+
- Node.js-only: it depends on file URLs and synchronous realpath resolution.
|
|
97
|
+
- Filesystem access occurs during module initialization when callers use it at top level.
|
|
98
|
+
- Non-file module URLs must return `false`, not throw.
|
|
99
|
+
|
|
100
|
+
## 3. `redactSensitiveValues`
|
|
101
|
+
|
|
102
|
+
**Priority:** Strong candidate
|
|
103
|
+
**Current location:** `src/security/redact.ts`
|
|
104
|
+
|
|
105
|
+
### Purpose
|
|
106
|
+
|
|
107
|
+
Recursively redacts sensitive object fields and private-key blocks, then removes known secret
|
|
108
|
+
values and recognizable secret options or assignments from text.
|
|
109
|
+
|
|
110
|
+
### Why it is reusable
|
|
111
|
+
|
|
112
|
+
CLI tools, configuration loaders, deployment systems, and structured loggers all need to
|
|
113
|
+
sanitize nested diagnostic context and free-form error or command output before displaying it.
|
|
114
|
+
|
|
115
|
+
### Duplication or overlap
|
|
116
|
+
|
|
117
|
+
The module already consolidates several overlapping redaction mechanisms: key matching, recursive
|
|
118
|
+
value transformation, private-key block removal, known-value replacement, CLI option matching,
|
|
119
|
+
and environment-style assignment matching. It is reused across errors, CLI output, transport
|
|
120
|
+
errors, and remote-command results.
|
|
121
|
+
|
|
122
|
+
### Proposed API
|
|
123
|
+
|
|
124
|
+
```ts
|
|
125
|
+
export interface RedactionOptions {
|
|
126
|
+
replacement?: string;
|
|
127
|
+
sensitiveKeys?: readonly (string | RegExp)[];
|
|
128
|
+
sensitiveTextPatterns?: readonly RegExp[];
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
export function redactSensitiveValues(
|
|
132
|
+
value: unknown,
|
|
133
|
+
options?: RedactionOptions
|
|
134
|
+
): unknown;
|
|
135
|
+
|
|
136
|
+
export function redactKnownSensitiveValues(
|
|
137
|
+
text: string,
|
|
138
|
+
source: unknown,
|
|
139
|
+
options?: RedactionOptions
|
|
140
|
+
): string;
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
### Generalization required
|
|
144
|
+
|
|
145
|
+
- Parameterize sensitive keys, replacement text, and text patterns.
|
|
146
|
+
- Separate Node-specific `Buffer` handling from universal recursive redaction.
|
|
147
|
+
- Define behavior for cycles, symbol keys, non-enumerable properties, dates, maps, and sets.
|
|
148
|
+
- Expand tests for mutation, repeated references, quoted values, empty secrets, and overlapping
|
|
149
|
+
secret values.
|
|
150
|
+
|
|
151
|
+
### Risks and limitations
|
|
152
|
+
|
|
153
|
+
- This is defense in depth, not a guarantee that arbitrary output is secret-free.
|
|
154
|
+
- Broad key substring matching can produce false positives; narrow patterns can miss secrets.
|
|
155
|
+
- The current recursive implementation does not handle cyclic objects.
|
|
156
|
+
- Security defaults must remain conservative and versioned carefully.
|
|
157
|
+
|
|
158
|
+
## 4. `collectDualStreamOutput`
|
|
159
|
+
|
|
160
|
+
**Priority:** Possible candidate
|
|
161
|
+
**Current location:** `src/client/command-executor.ts` as `collectCommandResult`
|
|
162
|
+
|
|
163
|
+
### Purpose
|
|
164
|
+
|
|
165
|
+
Collects stdout and stderr from a two-stream channel, enforces a combined byte limit and optional
|
|
166
|
+
timeout, normalizes a missing exit status, closes on failure, and removes listeners when settled.
|
|
167
|
+
|
|
168
|
+
### Why it is reusable
|
|
169
|
+
|
|
170
|
+
SSH clients, subprocess adapters, terminal gateways, and remote-execution libraries frequently
|
|
171
|
+
need bounded output collection with deterministic cleanup and partial-output error reporting.
|
|
172
|
+
|
|
173
|
+
### Duplication or overlap
|
|
174
|
+
|
|
175
|
+
There is no exact duplicate. It combines resource-lifecycle operations that otherwise tend to be
|
|
176
|
+
reimplemented around event emitters: settled-state guarding, timer cleanup, listener cleanup,
|
|
177
|
+
stream closure, byte accounting, and exit-result shaping.
|
|
178
|
+
|
|
179
|
+
### Proposed API
|
|
180
|
+
|
|
181
|
+
```ts
|
|
182
|
+
export interface DualOutputChannel extends NodeJS.ReadableStream {
|
|
183
|
+
stderr: NodeJS.ReadableStream;
|
|
184
|
+
close(): void;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
export interface CollectDualStreamOptions {
|
|
188
|
+
timeoutMs?: number;
|
|
189
|
+
maxBytes?: number;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
export interface CollectedOutput {
|
|
193
|
+
stdout: string;
|
|
194
|
+
stderr: string;
|
|
195
|
+
exitCode: number | null;
|
|
196
|
+
signal?: string;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
export function collectDualStreamOutput(
|
|
200
|
+
channel: DualOutputChannel,
|
|
201
|
+
options?: CollectDualStreamOptions
|
|
202
|
+
): Promise<CollectedOutput>;
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
### Generalization required
|
|
206
|
+
|
|
207
|
+
- Remove `RemoteCommandError`, command text, and `ssh2` channel types from the core collector.
|
|
208
|
+
- Define a generic close-event adapter or a minimal channel protocol.
|
|
209
|
+
- Expose typed failure details containing partial output and a failure reason.
|
|
210
|
+
- Specify text encoding and combined-versus-per-stream buffer accounting.
|
|
211
|
+
|
|
212
|
+
### Risks and limitations
|
|
213
|
+
|
|
214
|
+
- Node stream event ordering and close signatures vary between dependencies.
|
|
215
|
+
- String conversion and `Buffer.byteLength()` must not undercount split multibyte input.
|
|
216
|
+
- Cleanup must remain idempotent under timeout, stream error, and close races.
|
|
217
|
+
|
|
218
|
+
## 5. `normalizeSshSha256Fingerprint`
|
|
219
|
+
|
|
220
|
+
**Priority:** Possible candidate
|
|
221
|
+
**Current location:** `src/security/host-verification.ts`
|
|
222
|
+
|
|
223
|
+
### Purpose
|
|
224
|
+
|
|
225
|
+
Normalizes OpenSSH-style SHA-256 fingerprints, derives hex and unpadded base64 representations,
|
|
226
|
+
matches case-insensitive hexadecimal forms, and constructs an allow-list verifier.
|
|
227
|
+
|
|
228
|
+
### Why it is reusable
|
|
229
|
+
|
|
230
|
+
Other SSH clients, deployment agents, and host-key inspection tools need to compare fingerprints
|
|
231
|
+
received in different encodings without weakening host verification.
|
|
232
|
+
|
|
233
|
+
### Duplication or overlap
|
|
234
|
+
|
|
235
|
+
Normalization is repeated before comparison and candidate generation. Hex and base64 digest
|
|
236
|
+
generation also appears in the host-verification tests. Mazey's public `sha256Hex` overlaps only
|
|
237
|
+
the asynchronous hex digest; it does not provide base64 output, OpenSSH normalization, or
|
|
238
|
+
matching.
|
|
239
|
+
|
|
240
|
+
### Proposed API
|
|
241
|
+
|
|
242
|
+
```ts
|
|
243
|
+
export interface SshSha256Fingerprints {
|
|
244
|
+
hex: string;
|
|
245
|
+
base64: string;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
export function normalizeSshSha256Fingerprint(value: string): string;
|
|
249
|
+
|
|
250
|
+
export function deriveSshSha256Fingerprints(publicKey: Uint8Array): SshSha256Fingerprints;
|
|
251
|
+
|
|
252
|
+
export function createSshFingerprintMatcher(
|
|
253
|
+
allowed: Iterable<string>
|
|
254
|
+
): (actual: string) => boolean;
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
### Generalization required
|
|
258
|
+
|
|
259
|
+
- Separate pure normalization and matching from known-hosts filesystem access.
|
|
260
|
+
- Use runtime-neutral byte input and isolate the Node `crypto` implementation behind an adapter.
|
|
261
|
+
- Specify accepted encodings strictly instead of relying on permissive base64 decoding.
|
|
262
|
+
- Keep host selection and `known_hosts` parsing in an SSH-specific layer.
|
|
263
|
+
|
|
264
|
+
### Risks and limitations
|
|
265
|
+
|
|
266
|
+
- Security-sensitive parsing must reject malformed or ambiguous values predictably.
|
|
267
|
+
- Host fingerprints are not passwords, but comparison and allow-list behavior still define a
|
|
268
|
+
trust boundary.
|
|
269
|
+
- The current known-hosts parser supports exact plain hosts only, not hashed hosts or all OpenSSH
|
|
270
|
+
marker behavior.
|
|
271
|
+
|
|
272
|
+
## 6. `validateLocalMarkdownLinks`
|
|
273
|
+
|
|
274
|
+
**Priority:** Possible candidate
|
|
275
|
+
**Current location:** `scripts/validate-doc-links.js`
|
|
276
|
+
|
|
277
|
+
### Purpose
|
|
278
|
+
|
|
279
|
+
Discovers Markdown files, ignores fenced and inline code, extracts local links, validates
|
|
280
|
+
repository boundaries and target existence, and checks Markdown heading fragments.
|
|
281
|
+
|
|
282
|
+
### Why it is reusable
|
|
283
|
+
|
|
284
|
+
Documentation-heavy repositories can use the same zero-service validation in local development
|
|
285
|
+
and CI without requiring a full static-site build.
|
|
286
|
+
|
|
287
|
+
### Duplication or overlap
|
|
288
|
+
|
|
289
|
+
Code stripping and link extraction use overlapping transformations inside the script. There is
|
|
290
|
+
no production duplicate, but the complete validation pipeline has credible reuse across project
|
|
291
|
+
documentation tooling.
|
|
292
|
+
|
|
293
|
+
### Proposed API
|
|
294
|
+
|
|
295
|
+
```ts
|
|
296
|
+
export interface MarkdownLinkIssue {
|
|
297
|
+
file: string;
|
|
298
|
+
target?: string;
|
|
299
|
+
message: string;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
export interface MarkdownLinkValidationOptions {
|
|
303
|
+
rootDirectory: string;
|
|
304
|
+
files: readonly string[];
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
export function validateLocalMarkdownLinks(
|
|
308
|
+
options: MarkdownLinkValidationOptions
|
|
309
|
+
): MarkdownLinkIssue[];
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
### Generalization required
|
|
313
|
+
|
|
314
|
+
- Separate pure Markdown target and heading parsing from filesystem traversal.
|
|
315
|
+
- Make repository-boundary, generated-directory, and source-file policies caller-controlled.
|
|
316
|
+
- Add fixtures for reference links, encoded paths, duplicate headings, Unicode, code blocks,
|
|
317
|
+
images, and malformed Markdown.
|
|
318
|
+
|
|
319
|
+
### Risks and limitations
|
|
320
|
+
|
|
321
|
+
- Regex extraction is not a complete CommonMark parser.
|
|
322
|
+
- Heading-slug behavior varies between GitHub, documentation generators, and static-site tools.
|
|
323
|
+
- Symlinks can complicate repository-boundary checks based only on resolved path strings.
|
|
324
|
+
|
|
325
|
+
## Existing Dependency Matches
|
|
326
|
+
|
|
327
|
+
The installed version is `mazey@5.5.0`. Two former candidates now have exact public Mazey APIs
|
|
328
|
+
and are reused by the project:
|
|
329
|
+
|
|
330
|
+
| Current logic | Location | Existing API | Recommendation |
|
|
331
|
+
| ------------------------------- | ------------------------------ | ------------------------ | ----------------------------------------------------------------------------------------------------------------------------- |
|
|
332
|
+
| Defined-only shallow assignment | `src/config/resolve-config.ts` | `assignDefined` | Reuse the public Mazey API; it preserves precedence, mutation, and falsy-value behavior. |
|
|
333
|
+
| Binary byte-size formatting | `src/cli/output.ts` | `formatByteSize` | Reuse the public Mazey API with its default 1024 base and one fractional digit. |
|
|
334
|
+
| IIFE global-name normalization | `scripts/rollup.config.mjs` | `toJavaScriptGlobalName` | Use the public Mazey API if this legacy build configuration remains; verify the intentional behavior change for scoped names. |
|
|
335
|
+
|
|
336
|
+
`sha256Hex`, `parseJsonSafe`, `throttle`, `waitTime`, `isNumber`, and `isUdfOrNul` were
|
|
337
|
+
reviewed but do not fully match the remaining ranked helpers' behavior.
|
|
338
|
+
|
|
339
|
+
## Reviewed but Excluded
|
|
340
|
+
|
|
341
|
+
| Helper or area | Location | Reason |
|
|
342
|
+
| ---------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------- |
|
|
343
|
+
| Integer parsing | `src/config/environment.ts`, `src/cli/commands/shared.ts` | Exact duplication exists around `Number.parseInt`, but the logic is too small and its error policy belongs to each caller. |
|
|
344
|
+
| Positive-number validation | `src/config/validation.ts`, `src/client/client.ts` | Behavior overlaps for timeouts and buffer limits, but each rule has distinct ranges, integer requirements, and typed errors. |
|
|
345
|
+
| Configuration resolution | `src/config/resolve-config.ts` | The precedence order, profile/job selection, and path interpretation are `scp-next` policy. |
|
|
346
|
+
| Post-upload command guards | `src/config/post-upload-commands.ts`, `src/config/load-config.ts`, `src/cli/commands/shared.ts` | Behavioral overlap exists, but the rule is application-specific and the primitive checks are trivial. |
|
|
347
|
+
| Remote path wrappers | `src/paths/remote-path.ts` | `path.posix` already provides the general operations; validation and MSYS restoration carry project policy. |
|
|
348
|
+
| Home expansion and local path resolution | `src/paths/local-path.ts` | Useful but small, Node-specific, and intentionally limited to `~` rather than user-home lookup. |
|
|
349
|
+
| Progress percentage and reporter | `src/client/client.ts`, `src/cli/output.ts` | Percentage math is trivial; the reporter is coupled to transfer fields, terminal wording, and CLI throttling policy. |
|
|
350
|
+
| Error conversion and host-failure classification | `src/errors/index.ts`, `src/client/transport.ts` | Keyword rules map directly to the public `scp-next` error hierarchy and fail-closed SSH behavior. |
|
|
351
|
+
| Local and remote file walking | `src/client/walk.ts` | Traversal is coupled to transfer entry types, SFTP transport behavior, and local/remote path distinctions. |
|
|
352
|
+
| Destination and overwrite resolution | `src/client/client.ts` | Some inline blocks overlap, but they encode `cp`/`scp`-style transfer semantics and typed failures. |
|
|
353
|
+
| `fileExists`, `collectValues`, package-version reading, and `_resolve` | `src/config/load-config.ts`, `src/cli/commands/shared.ts`, `src/cli/index.ts`, `scripts/*` | One-off or one-line native wrappers lack enough independent value. |
|
|
354
|
+
| `MemoryStream`, temp-directory builders, and mocks | `tests/**` | Minor test duplication exists, but these fixtures are short and tied to Vitest or project interfaces. |
|
|
355
|
+
| Release helper deep import | `scripts/release.js` | It consumes an undocumented Mazey path and should not define a new general-purpose extraction. |
|
|
356
|
+
|
|
357
|
+
## Recommended Extraction Order
|
|
358
|
+
|
|
359
|
+
1. `restoreMsysConvertedPosixPath`
|
|
360
|
+
2. `isDirectlyExecuted`
|
|
361
|
+
3. `redactSensitiveValues`
|
|
362
|
+
4. `collectDualStreamOutput`
|
|
363
|
+
5. `normalizeSshSha256Fingerprint`
|
|
364
|
+
6. `validateLocalMarkdownLinks`
|