@mvanhorn/printing-press-library 0.1.11 → 0.1.13
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 +8 -0
- package/README.md +3 -0
- package/dist/src/cli.js +6 -0
- package/dist/src/cli.js.map +1 -1
- package/dist/src/commands/update.d.ts +11 -1
- package/dist/src/commands/update.js +50 -15
- package/dist/src/commands/update.js.map +1 -1
- package/dist/src/concurrency.d.ts +12 -0
- package/dist/src/concurrency.js +28 -0
- package/dist/src/concurrency.js.map +1 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.1.13
|
|
4
|
+
|
|
5
|
+
- Speed up `update` (and `update` with no name) by refreshing detected CLIs concurrently instead of one at a time. The cost of a bulk update is dominated by per-CLI network round-trips — the go-proxy `@latest` resolution (~1s each, even when nothing changed, because the build cache can't shortcut it) plus the skill fetch — which serialized into ~30s for a dozen CLIs. These are independent, so they now run with bounded concurrency, and the catalog detection sweep (a `which`/`where` probe per catalog entry) is parallelized the same way. Each install's output is buffered and replayed in catalog order (preserving stdout/stderr ordering within each CLI), so concurrent runs don't interleave into scrambled lines. A failed PATH probe degrades to "not installed" instead of aborting the run. No command, flag, or output-shape changes — same behavior, less waiting.
|
|
6
|
+
|
|
7
|
+
## 0.1.12
|
|
8
|
+
|
|
9
|
+
- Add a `reinstall` command as an alias for `update`. `reinstall <name>` rebuilds one CLI's binary from the latest catalog code and re-adds its skill; `reinstall` with no name does the same for every Printing Press CLI already on `PATH`. The mechanics are identical to `update` (both run `go install …@latest` and re-add the skill) — this just exposes the verb users reach for when a binary or skill needs a clean refresh. The shared "no CLIs found on PATH" message is now verb-neutral so it reads correctly under either command.
|
|
10
|
+
|
|
3
11
|
## 0.1.11
|
|
4
12
|
|
|
5
13
|
- When `go install` writes a CLI to a directory that isn't on `PATH`, print the exact, copy-pasteable fix for the detected platform and shell instead of a single Unix-flavored hint. macOS zsh gets a `~/.zshrc` line, macOS bash gets `~/.bash_profile` (login shells don't read `.bashrc`), Linux bash gets `~/.bashrc`, fish gets `fish_add_path`, Windows gets the persistent PowerShell `[Environment]::SetEnvironmentVariable(... "User")` command plus a GUI fallback (and never the truncating `setx` footgun), and Git Bash gets a POSIX-translated path. The previous message printed `$(go env GOPATH)/bin` shell syntax that was wrong on Windows and imprecise on fish.
|
package/README.md
CHANGED
|
@@ -91,11 +91,14 @@ npx -y @mvanhorn/printing-press-library search sports
|
|
|
91
91
|
npx -y @mvanhorn/printing-press-library list --category travel
|
|
92
92
|
npx -y @mvanhorn/printing-press-library list --installed
|
|
93
93
|
npx -y @mvanhorn/printing-press-library update espn
|
|
94
|
+
npx -y @mvanhorn/printing-press-library reinstall espn
|
|
94
95
|
npx -y @mvanhorn/printing-press-library uninstall espn --yes
|
|
95
96
|
```
|
|
96
97
|
|
|
97
98
|
`list` shows the public catalog by default. Use `list --installed` when you only want CLIs already present on your machine.
|
|
98
99
|
|
|
100
|
+
`reinstall` is an alias for `update`: `reinstall <name>` rebuilds one CLI from the latest catalog code and re-adds its skill, while `reinstall` with no name refreshes every Printing Press CLI already on your `PATH`. Reach for it when a binary or skill needs a clean refresh — `install <name>` overwrites in place too, so either works.
|
|
101
|
+
|
|
99
102
|
## Options
|
|
100
103
|
|
|
101
104
|
```bash
|
package/dist/src/cli.js
CHANGED
|
@@ -9,6 +9,10 @@ import { updateCommand } from "./commands/update.js";
|
|
|
9
9
|
const COMMANDS = {
|
|
10
10
|
install: installCommand,
|
|
11
11
|
update: updateCommand,
|
|
12
|
+
// `reinstall` is an alias for `update`: both rebuild the binary from the
|
|
13
|
+
// latest catalog code (`go install …@latest`) and re-add the skill. It exists
|
|
14
|
+
// because "reinstall" is the verb users reach for; the mechanics are identical.
|
|
15
|
+
reinstall: updateCommand,
|
|
12
16
|
list: listCommand,
|
|
13
17
|
search: searchCommand,
|
|
14
18
|
uninstall: uninstallCommand,
|
|
@@ -46,6 +50,7 @@ Usage:
|
|
|
46
50
|
Commands:
|
|
47
51
|
install <name|bundle>... Install one or more Printing Press CLIs (and skills)
|
|
48
52
|
update [name] Refresh one installed CLI, or all installed CLIs
|
|
53
|
+
reinstall [name] Reinstall one CLI (or all installed); alias for update
|
|
49
54
|
list List available Printing Press CLIs
|
|
50
55
|
search <query> Search the Printing Press catalog
|
|
51
56
|
uninstall <name> Remove a Printing Press CLI and skill
|
|
@@ -57,6 +62,7 @@ Examples:
|
|
|
57
62
|
printing-press-library install starter-pack
|
|
58
63
|
printing-press-library install espn linear dub
|
|
59
64
|
printing-press-library install espn --cli-only
|
|
65
|
+
printing-press-library reinstall espn
|
|
60
66
|
printing-press-library list
|
|
61
67
|
printing-press-library search sports
|
|
62
68
|
printing-press-library list --installed
|
package/dist/src/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../../src/cli.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAIrD,MAAM,QAAQ,GAAmC;IAC/C,OAAO,EAAE,cAAc;IACvB,MAAM,EAAE,aAAa;IACrB,IAAI,EAAE,WAAW;IACjB,MAAM,EAAE,aAAa;IACrB,SAAS,EAAE,gBAAgB;CAC5B,CAAC;AAEF,MAAM,CAAC,KAAK,UAAU,IAAI,CAAC,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;IACrD,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,CAAC,CAAC;IAC7B,IAAI,IAAI,KAAK,CAAC,EAAE,CAAC;QACf,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC;IAC1B,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,GAAG,CAAC,IAAc;IACtC,MAAM,CAAC,OAAO,EAAE,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC;IAEhC,IAAI,CAAC,OAAO,IAAI,OAAO,KAAK,IAAI,IAAI,OAAO,KAAK,QAAQ,EAAE,CAAC;QACzD,SAAS,EAAE,CAAC;QACZ,OAAO,CAAC,CAAC;IACX,CAAC;IAED,IAAI,OAAO,KAAK,IAAI,IAAI,OAAO,KAAK,WAAW,EAAE,CAAC;QAChD,OAAO,CAAC,GAAG,CAAC,MAAM,cAAc,EAAE,CAAC,CAAC;QACpC,OAAO,CAAC,CAAC;IACX,CAAC;IAED,MAAM,OAAO,GAAG,QAAQ,CAAC,OAAO,CAAC,CAAC;IAClC,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,OAAO,CAAC,KAAK,CAAC,oBAAoB,OAAO,EAAE,CAAC,CAAC;QAC7C,SAAS,EAAE,CAAC;QACZ,OAAO,CAAC,CAAC;IACX,CAAC;IAED,OAAO,OAAO,CAAC,IAAI,CAAC,CAAC;AACvB,CAAC;AAED,SAAS,SAAS;IAChB,OAAO,CAAC,GAAG,CAAC
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../../src/cli.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,8 +1,18 @@
|
|
|
1
1
|
import { type Registry } from "../registry.js";
|
|
2
|
+
/** Output sinks handed to a single buffered install run. */
|
|
3
|
+
interface InstallIO {
|
|
4
|
+
stdout: (message: string) => void;
|
|
5
|
+
stderr: (message: string) => void;
|
|
6
|
+
}
|
|
2
7
|
interface UpdateDeps {
|
|
3
8
|
fetchRegistry: (url: string) => Promise<Registry>;
|
|
4
9
|
commandOnPath: (binary: string) => Promise<string | null>;
|
|
5
|
-
|
|
10
|
+
/**
|
|
11
|
+
* Build an install command bound to the given output sinks. A factory (rather
|
|
12
|
+
* than a single shared install fn) lets the bulk path give each concurrent run
|
|
13
|
+
* its own buffer, so parallel installs don't interleave their lines.
|
|
14
|
+
*/
|
|
15
|
+
createInstall: (io: InstallIO) => (args: string[]) => Promise<number>;
|
|
6
16
|
stdout: (message: string) => void;
|
|
7
17
|
stderr: (message: string) => void;
|
|
8
18
|
}
|
|
@@ -1,11 +1,19 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { createInstallCommand } from "./install.js";
|
|
2
|
+
import { mapWithConcurrency } from "../concurrency.js";
|
|
2
3
|
import { commandOnPath } from "../process.js";
|
|
3
4
|
import { cliBinaryName, DEFAULT_REGISTRY_URL, fetchRegistry } from "../registry.js";
|
|
5
|
+
// `which`/`where` probes are cheap but the detection sweep covers the whole
|
|
6
|
+
// catalog (hundreds of entries), so cap the fan-out to avoid a process storm.
|
|
7
|
+
const DETECT_CONCURRENCY = 16;
|
|
8
|
+
// Installs are network-bound (go-proxy `@latest` resolution + skill fetch), the
|
|
9
|
+
// dominant cost in a bulk update. Run several at once, but cap to share the
|
|
10
|
+
// proxy politely and bound concurrent global skill writes.
|
|
11
|
+
const INSTALL_CONCURRENCY = 6;
|
|
4
12
|
export function createUpdateCommand(overrides = {}) {
|
|
5
13
|
const deps = {
|
|
6
14
|
fetchRegistry: (url) => fetchRegistry(url),
|
|
7
15
|
commandOnPath: (binary) => commandOnPath(binary),
|
|
8
|
-
|
|
16
|
+
createInstall: (io) => createInstallCommand({ stdout: io.stdout, stderr: io.stderr }),
|
|
9
17
|
stdout: (message) => console.log(message),
|
|
10
18
|
stderr: (message) => console.error(message),
|
|
11
19
|
...overrides,
|
|
@@ -17,26 +25,53 @@ export function createUpdateCommand(overrides = {}) {
|
|
|
17
25
|
return 1;
|
|
18
26
|
}
|
|
19
27
|
if (parsed.name) {
|
|
20
|
-
|
|
28
|
+
// Single target: stream output straight through, no buffering needed.
|
|
29
|
+
const install = deps.createInstall({ stdout: deps.stdout, stderr: deps.stderr });
|
|
30
|
+
return install([parsed.name, ...parsed.installArgs]);
|
|
21
31
|
}
|
|
22
32
|
const registry = await deps.fetchRegistry(parsed.registryUrl);
|
|
23
|
-
const
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
installed.push(entry.name);
|
|
33
|
+
const detected = await mapWithConcurrency(registry.entries, DETECT_CONCURRENCY, async (entry) => {
|
|
34
|
+
try {
|
|
35
|
+
return (await deps.commandOnPath(cliBinaryName(entry))) ? entry.name : null;
|
|
27
36
|
}
|
|
28
|
-
|
|
37
|
+
catch {
|
|
38
|
+
// A failed PATH probe (rare `which`/`where` spawn error) shouldn't abort
|
|
39
|
+
// the whole update — treat the entry as not installed and move on.
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
const installed = detected.filter((name) => name !== null);
|
|
29
44
|
if (installed.length === 0) {
|
|
30
|
-
deps.stdout("
|
|
45
|
+
deps.stdout("No Printing Press CLIs found on PATH to refresh.");
|
|
31
46
|
return 0;
|
|
32
47
|
}
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
48
|
+
// Refresh concurrently, but record each run's output in emission order and
|
|
49
|
+
// replay it per CLI in catalog order — so parallel runs don't interleave into
|
|
50
|
+
// scrambled lines, while stdout/stderr ordering within a CLI is preserved.
|
|
51
|
+
const results = await mapWithConcurrency(installed, INSTALL_CONCURRENCY, async (name) => {
|
|
52
|
+
const lines = [];
|
|
53
|
+
const install = deps.createInstall({
|
|
54
|
+
stdout: (message) => lines.push({ stream: "out", message }),
|
|
55
|
+
stderr: (message) => lines.push({ stream: "err", message }),
|
|
56
|
+
});
|
|
57
|
+
let code;
|
|
58
|
+
try {
|
|
59
|
+
code = await install([name, ...parsed.installArgs]);
|
|
60
|
+
}
|
|
61
|
+
catch (error) {
|
|
62
|
+
// install resolves with an exit code rather than throwing; guard anyway
|
|
63
|
+
// so one unexpected throw can't reject the whole concurrent batch.
|
|
64
|
+
lines.push({ stream: "err", message: error instanceof Error ? error.message : String(error) });
|
|
65
|
+
code = 1;
|
|
66
|
+
}
|
|
67
|
+
return { code, lines };
|
|
68
|
+
});
|
|
69
|
+
for (const { lines } of results) {
|
|
70
|
+
for (const { stream, message } of lines) {
|
|
71
|
+
(stream === "out" ? deps.stdout : deps.stderr)(message);
|
|
38
72
|
}
|
|
39
73
|
}
|
|
74
|
+
const failures = results.filter((result) => result.code !== 0).length;
|
|
40
75
|
return failures === 0 ? 0 : 1;
|
|
41
76
|
};
|
|
42
77
|
}
|
|
@@ -66,7 +101,7 @@ function parseUpdateArgs(args) {
|
|
|
66
101
|
}
|
|
67
102
|
}
|
|
68
103
|
else if (arg.startsWith("-")) {
|
|
69
|
-
return { error: `Unknown
|
|
104
|
+
return { error: `Unknown option: ${arg}` };
|
|
70
105
|
}
|
|
71
106
|
else if (!name) {
|
|
72
107
|
name = arg;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"update.js","sourceRoot":"","sources":["../../../src/commands/update.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"update.js","sourceRoot":"","sources":["../../../src/commands/update.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AACpD,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AACvD,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,EAAE,aAAa,EAAE,oBAAoB,EAAE,aAAa,EAAiB,MAAM,gBAAgB,CAAC;AA2BnG,4EAA4E;AAC5E,8EAA8E;AAC9E,MAAM,kBAAkB,GAAG,EAAE,CAAC;AAC9B,gFAAgF;AAChF,4EAA4E;AAC5E,2DAA2D;AAC3D,MAAM,mBAAmB,GAAG,CAAC,CAAC;AAE9B,MAAM,UAAU,mBAAmB,CAAC,YAAiC,EAAE;IACrE,MAAM,IAAI,GAAe;QACvB,aAAa,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,aAAa,CAAC,GAAG,CAAC;QAC1C,aAAa,EAAE,CAAC,MAAM,EAAE,EAAE,CAAC,aAAa,CAAC,MAAM,CAAC;QAChD,aAAa,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,oBAAoB,CAAC,EAAE,MAAM,EAAE,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,CAAC,MAAM,EAAE,CAAC;QACrF,MAAM,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC;QACzC,MAAM,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC;QAC3C,GAAG,SAAS;KACb,CAAC;IAEF,OAAO,KAAK,UAAU,qBAAqB,CAAC,IAAc;QACxD,MAAM,MAAM,GAAG,eAAe,CAAC,IAAI,CAAC,CAAC;QACrC,IAAI,OAAO,IAAI,MAAM,EAAE,CAAC;YACtB,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YAC1B,OAAO,CAAC,CAAC;QACX,CAAC;QAED,IAAI,MAAM,CAAC,IAAI,EAAE,CAAC;YAChB,sEAAsE;YACtE,MAAM,OAAO,GAAG,IAAI,CAAC,aAAa,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;YACjF,OAAO,OAAO,CAAC,CAAC,MAAM,CAAC,IAAI,EAAE,GAAG,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC;QACvD,CAAC;QAED,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;QAC9D,MAAM,QAAQ,GAAG,MAAM,kBAAkB,CAAC,QAAQ,CAAC,OAAO,EAAE,kBAAkB,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE;YAC9F,IAAI,CAAC;gBACH,OAAO,CAAC,MAAM,IAAI,CAAC,aAAa,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;YAC9E,CAAC;YAAC,MAAM,CAAC;gBACP,yEAAyE;gBACzE,mEAAmE;gBACnE,OAAO,IAAI,CAAC;YACd,CAAC;QACH,CAAC,CAAC,CAAC;QACH,MAAM,SAAS,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,IAAI,EAAkB,EAAE,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC;QAE3E,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC3B,IAAI,CAAC,MAAM,CAAC,kDAAkD,CAAC,CAAC;YAChE,OAAO,CAAC,CAAC;QACX,CAAC;QAED,2EAA2E;QAC3E,8EAA8E;QAC9E,2EAA2E;QAC3E,MAAM,OAAO,GAAG,MAAM,kBAAkB,CAAC,SAAS,EAAE,mBAAmB,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE;YACtF,MAAM,KAAK,GAAmB,EAAE,CAAC;YACjC,MAAM,OAAO,GAAG,IAAI,CAAC,aAAa,CAAC;gBACjC,MAAM,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC;gBAC3D,MAAM,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC;aAC5D,CAAC,CAAC;YACH,IAAI,IAAY,CAAC;YACjB,IAAI,CAAC;gBACH,IAAI,GAAG,MAAM,OAAO,CAAC,CAAC,IAAI,EAAE,GAAG,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC;YACtD,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,wEAAwE;gBACxE,mEAAmE;gBACnE,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;gBAC/F,IAAI,GAAG,CAAC,CAAC;YACX,CAAC;YACD,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;QACzB,CAAC,CAAC,CAAC;QAEH,KAAK,MAAM,EAAE,KAAK,EAAE,IAAI,OAAO,EAAE,CAAC;YAChC,KAAK,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,KAAK,EAAE,CAAC;gBACxC,CAAC,MAAM,KAAK,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC;YAC1D,CAAC;QACH,CAAC;QAED,MAAM,QAAQ,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC;QACtE,OAAO,QAAQ,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAChC,CAAC,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,MAAM,aAAa,GAAG,mBAAmB,EAAE,CAAC;AAEnD,SAAS,eAAe,CAAC,IAAc;IAGrC,IAAI,IAAwB,CAAC;IAC7B,IAAI,WAAW,GAAG,oBAAoB,CAAC;IACvC,MAAM,WAAW,GAAa,EAAE,CAAC;IAEjC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACrC,MAAM,GAAG,GAAG,IAAI,CAAC,CAAC,CAAE,CAAC;QACrB,IAAI,GAAG,KAAK,gBAAgB,EAAE,CAAC;YAC7B,MAAM,KAAK,GAAG,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;YACxB,IAAI,CAAC,KAAK,EAAE,CAAC;gBACX,OAAO,EAAE,KAAK,EAAE,kCAAkC,EAAE,CAAC;YACvD,CAAC;YACD,WAAW,GAAG,KAAK,CAAC;YACpB,WAAW,CAAC,IAAI,CAAC,gBAAgB,EAAE,KAAK,CAAC,CAAC;QAC5C,CAAC;aAAM,IAAI,GAAG,KAAK,QAAQ,IAAI,GAAG,KAAK,SAAS,IAAI,GAAG,KAAK,IAAI,EAAE,CAAC;YACjE,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YACtB,IAAI,GAAG,KAAK,SAAS,IAAI,GAAG,KAAK,IAAI,EAAE,CAAC;gBACtC,MAAM,KAAK,GAAG,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;gBACxB,IAAI,CAAC,KAAK,EAAE,CAAC;oBACX,OAAO,EAAE,KAAK,EAAE,qBAAqB,GAAG,EAAE,EAAE,CAAC;gBAC/C,CAAC;gBACD,WAAW,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAC1B,CAAC;QACH,CAAC;aAAM,IAAI,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;YAC/B,OAAO,EAAE,KAAK,EAAE,mBAAmB,GAAG,EAAE,EAAE,CAAC;QAC7C,CAAC;aAAM,IAAI,CAAC,IAAI,EAAE,CAAC;YACjB,IAAI,GAAG,GAAG,CAAC;QACb,CAAC;aAAM,CAAC;YACN,OAAO,EAAE,KAAK,EAAE,wBAAwB,GAAG,EAAE,EAAE,CAAC;QAClD,CAAC;IACH,CAAC;IAED,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,WAAW,EAAE,CAAC;AAC5C,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Run `fn` over `items` with at most `limit` calls in flight at once, returning
|
|
3
|
+
* results in input order. A worker pool pulls from a shared cursor, so a slow
|
|
4
|
+
* item never blocks the others from starting — wall-clock is bounded by the
|
|
5
|
+
* slowest `limit`-sized window, not the serial sum. `limit` is clamped to
|
|
6
|
+
* `[1, items.length]`.
|
|
7
|
+
*
|
|
8
|
+
* `fn` is expected to resolve (callers that must not abort the batch on a single
|
|
9
|
+
* failure should catch inside `fn` and return a sentinel); a rejection here
|
|
10
|
+
* propagates and rejects the whole call.
|
|
11
|
+
*/
|
|
12
|
+
export declare function mapWithConcurrency<T, R>(items: readonly T[], limit: number, fn: (item: T, index: number) => Promise<R>): Promise<R[]>;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Run `fn` over `items` with at most `limit` calls in flight at once, returning
|
|
3
|
+
* results in input order. A worker pool pulls from a shared cursor, so a slow
|
|
4
|
+
* item never blocks the others from starting — wall-clock is bounded by the
|
|
5
|
+
* slowest `limit`-sized window, not the serial sum. `limit` is clamped to
|
|
6
|
+
* `[1, items.length]`.
|
|
7
|
+
*
|
|
8
|
+
* `fn` is expected to resolve (callers that must not abort the batch on a single
|
|
9
|
+
* failure should catch inside `fn` and return a sentinel); a rejection here
|
|
10
|
+
* propagates and rejects the whole call.
|
|
11
|
+
*/
|
|
12
|
+
export async function mapWithConcurrency(items, limit, fn) {
|
|
13
|
+
const results = new Array(items.length);
|
|
14
|
+
let cursor = 0;
|
|
15
|
+
const worker = async () => {
|
|
16
|
+
while (true) {
|
|
17
|
+
const index = cursor++;
|
|
18
|
+
if (index >= items.length) {
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
results[index] = await fn(items[index], index);
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
const workerCount = Math.min(Math.max(1, limit), items.length);
|
|
25
|
+
await Promise.all(Array.from({ length: workerCount }, worker));
|
|
26
|
+
return results;
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=concurrency.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"concurrency.js","sourceRoot":"","sources":["../../src/concurrency.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,KAAmB,EACnB,KAAa,EACb,EAA0C;IAE1C,MAAM,OAAO,GAAG,IAAI,KAAK,CAAI,KAAK,CAAC,MAAM,CAAC,CAAC;IAC3C,IAAI,MAAM,GAAG,CAAC,CAAC;IAEf,MAAM,MAAM,GAAG,KAAK,IAAmB,EAAE;QACvC,OAAO,IAAI,EAAE,CAAC;YACZ,MAAM,KAAK,GAAG,MAAM,EAAE,CAAC;YACvB,IAAI,KAAK,IAAI,KAAK,CAAC,MAAM,EAAE,CAAC;gBAC1B,OAAO;YACT,CAAC;YACD,OAAO,CAAC,KAAK,CAAC,GAAG,MAAM,EAAE,CAAC,KAAK,CAAC,KAAK,CAAE,EAAE,KAAK,CAAC,CAAC;QAClD,CAAC;IACH,CAAC,CAAC;IAEF,MAAM,WAAW,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IAC/D,MAAM,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,WAAW,EAAE,EAAE,MAAM,CAAC,CAAC,CAAC;IAC/D,OAAO,OAAO,CAAC;AACjB,CAAC"}
|