@bushizhanghan/dsh-publish-gate 0.8.0 → 0.8.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/CHANGELOG.md CHANGED
@@ -1,5 +1,12 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.8.1
4
+
5
+ - `publish_gate_verify` gained `waitMs` (capped at 90 s) and reports `waitedMs`. npm answers 202 and keeps
6
+ the version invisible for 60–180 s after a publish, so the single-shot check reported "not on the registry"
7
+ for releases that had already succeeded — it happened on this plugin own 0.8.0 publish, which stayed
8
+ invisible for over three minutes. `waitForPublished()` polls until the shasum appears; `waitMs: 0` keeps
9
+ the old single-shot behaviour, and a real mismatch stops the poll immediately.
3
10
  ## 0.8.0
4
11
 
5
12
  - `tool-input-throws` (error): `publish_gate_tools` gained `fuzz` and `skip`. With `fuzz: true` it drives
package/README.md CHANGED
@@ -215,7 +215,7 @@ dsh plugin --profile desktop add @bushizhanghan/dsh-publish-gate
215
215
  ## 开发
216
216
 
217
217
  ```sh
218
- node --test # 90 个引擎单测
218
+ node --test # 92 个引擎单测
219
219
  node test/integration.test.mjs # 27 条集成断言(9 个真实插件作 fixture)
220
220
  ```
221
221
 
package/lib/engine.js CHANGED
@@ -1916,6 +1916,29 @@ export async function checkPublishedMatches(name, version, localPack, { registry
1916
1916
  return out
1917
1917
  }
1918
1918
 
1919
+ /**
1920
+ * Poll the registry until the published bytes show up.
1921
+ *
1922
+ * npm answers 202 and keeps the version invisible for 60–180 s, so a single
1923
+ * shot right after `npm publish` reports "not on the registry" for a release
1924
+ * that already succeeded — the most common false alarm this plugin produces,
1925
+ * including on its own publishes. `probe` is injectable so the loop tests
1926
+ * without the network.
1927
+ */
1928
+ export async function waitForPublished(name, version, localPack, opts = {}) {
1929
+ const waitMs = Math.max(0, Number(opts.waitMs) || 0)
1930
+ const intervalMs = Math.max(1000, Number(opts.intervalMs) || 10_000)
1931
+ const probe = opts.probe || ((o) => checkPublishedMatches(name, version, localPack, o))
1932
+ const net = { registry: opts.registry, timeoutMs: opts.timeoutMs }
1933
+ const started = Date.now()
1934
+ let findings = await probe(net)
1935
+ while (!findings.some((f) => f.rule === 'publish-served') && Date.now() - started < waitMs) {
1936
+ await new Promise((r) => setTimeout(r, Math.min(intervalMs, waitMs - (Date.now() - started))))
1937
+ findings = await probe(net)
1938
+ }
1939
+ return { findings, waitedMs: Date.now() - started }
1940
+ }
1941
+
1919
1942
  /** The async half of the gate: everything that needs a subprocess or the network. */
1920
1943
  export async function runArtifactChecks(dir, opts = {}) {
1921
1944
  const packResult = opts.skipPack ? { findings: [], pack: null } : await checkPack(dir, opts)
package/lib/index.js CHANGED
@@ -24,6 +24,7 @@ import {
24
24
  checkClientRuntime,
25
25
  checkPublishIdentity,
26
26
  checkVersionTaken,
27
+ waitForPublished,
27
28
  compareVersions,
28
29
  latestPublished,
29
30
  renderReport,
@@ -189,12 +190,17 @@ export function apply(ctx, config = {}) {
189
190
  {
190
191
  name: 'publish_gate_verify',
191
192
  description:
192
- 'Check that the tarball on the npm registry is the one in this directory. Runs `npm pack --dry-run` and compares its shasum with the registry dist.shasum — an exact comparison, not a version-number guess, so it catches "I bumped and forgot to publish" and "I published, then edited lib/". Reports publish-served (match), publish-served-mismatch (the version is spent and the registry holds different bytes), or publish-not-served (not published, or still inside the registry\'s one-minute 202-then-404 window). Run it after `npm publish`. Returns {ok, name, version, published, shasumMatch, localShasum, unpackedSize, files, findings, report}.',
193
+ 'Check that the tarball on the npm registry is the one in this directory. Runs `npm pack --dry-run` and compares its shasum with the registry dist.shasum — an exact comparison, not a version-number guess, so it catches "I bumped and forgot to publish" and "I published, then edited lib/". Reports publish-served (match), publish-served-mismatch (the version is spent and the registry holds different bytes), or publish-not-served (not published, or still inside the registry\'s 202-then-404 window — pass waitMs to poll through that window instead of concluding too early). Run it right after `npm publish`. Returns {ok, name, version, published, shasumMatch, localShasum, unpackedSize, files, waitedMs, findings, report}.',
193
194
  parameters: {
194
195
  type: 'object',
195
196
  properties: {
196
197
  dir: { type: 'string', description: 'Plugin directory.' },
197
198
  version: { type: 'string', description: 'Version to verify (defaults to package.json version).' },
199
+ waitMs: {
200
+ type: 'number',
201
+ description:
202
+ 'Poll until the registry serves the bytes, up to this many milliseconds (capped at 90000). npm returns 202 and keeps the version invisible for 60-180 s after a publish, so a single shot reports "not published" on a release that already succeeded.',
203
+ },
198
204
  },
199
205
  },
200
206
  async execute(args) {
@@ -205,7 +211,12 @@ export function apply(ctx, config = {}) {
205
211
  const version = args.version || json.version
206
212
  const { pack, findings: packFindings } = await checkPack(dir)
207
213
  if (!pack) return { ok: false, error: `npm pack --dry-run did not run, so there is nothing to compare: ${packFindings.map((f) => f.title).join('; ')}` }
208
- const findings = await checkPublishedMatches(json.name, version, pack, { registry: cfg.registry, timeoutMs: cfg.networkTimeoutMs })
214
+ const waitMs = Math.min(Math.max(0, Number(args.waitMs) || 0), 90_000)
215
+ const { findings, waitedMs } = await waitForPublished(json.name, version, pack, {
216
+ registry: cfg.registry,
217
+ timeoutMs: cfg.networkTimeoutMs,
218
+ waitMs,
219
+ })
209
220
  const served = findings.some((f) => f.rule === 'publish-served')
210
221
  return {
211
222
  ok: true,
@@ -216,6 +227,7 @@ export function apply(ctx, config = {}) {
216
227
  localShasum: pack.shasum,
217
228
  unpackedSize: pack.unpackedSize,
218
229
  files: (pack.files || []).length,
230
+ waitedMs,
219
231
  findings,
220
232
  report: renderReport(findings, { title: `publish verify · ${json.name}@${version}` }),
221
233
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bushizhanghan/dsh-publish-gate",
3
- "version": "0.8.0",
3
+ "version": "0.8.1",
4
4
  "description": "Pre-publish gate for DSH plugins: manifest, dependencies, artifact, runtime, browser half, traceability and market readiness — plus an input fuzzer that drives every declared parameter with the wrong type. 发布前的七层门禁 + 入参模糊测试。",
5
5
  "type": "module",
6
6
  "main": "lib/index.js",