@ontrails/trails 1.0.0-beta.29 → 1.0.0-beta.30
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 +21 -0
- package/package.json +16 -16
- package/src/release/native-bun-registry.ts +173 -32
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,26 @@
|
|
|
1
1
|
# trails
|
|
2
2
|
|
|
3
|
+
## 1.0.0-beta.30
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 5510807: Treat npm `ETARGET` exact-version probes as unpublished target versions during registry readiness checks.
|
|
8
|
+
- b0ff8b9: Teach the registry preflight to verify first-time package publishes when npm's package summary lags behind dist-tags and tarball availability.
|
|
9
|
+
- @ontrails/commander@1.0.0-beta.30
|
|
10
|
+
- @ontrails/adapter-kit@1.0.0-beta.30
|
|
11
|
+
- @ontrails/cli@1.0.0-beta.30
|
|
12
|
+
- @ontrails/config@1.0.0-beta.30
|
|
13
|
+
- @ontrails/core@1.0.0-beta.30
|
|
14
|
+
- @ontrails/http@1.0.0-beta.30
|
|
15
|
+
- @ontrails/mcp@1.0.0-beta.30
|
|
16
|
+
- @ontrails/observe@1.0.0-beta.30
|
|
17
|
+
- @ontrails/permits@1.0.0-beta.30
|
|
18
|
+
- @ontrails/regrade@1.0.0-beta.30
|
|
19
|
+
- @ontrails/topographer@1.0.0-beta.30
|
|
20
|
+
- @ontrails/tracing@1.0.0-beta.30
|
|
21
|
+
- @ontrails/warden@1.0.0-beta.30
|
|
22
|
+
- @ontrails/wayfinder@1.0.0-beta.30
|
|
23
|
+
|
|
3
24
|
## 1.0.0-beta.29
|
|
4
25
|
|
|
5
26
|
### Patch Changes
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ontrails/trails",
|
|
3
|
-
"version": "1.0.0-beta.
|
|
3
|
+
"version": "1.0.0-beta.30",
|
|
4
4
|
"bin": {
|
|
5
5
|
"trails": "./bin/trails.ts"
|
|
6
6
|
},
|
|
@@ -27,25 +27,25 @@
|
|
|
27
27
|
},
|
|
28
28
|
"dependencies": {
|
|
29
29
|
"@clack/prompts": "^1.1.0",
|
|
30
|
-
"@ontrails/adapter-kit": "^1.0.0-beta.
|
|
31
|
-
"@ontrails/cli": "^1.0.0-beta.
|
|
32
|
-
"@ontrails/commander": "^1.0.0-beta.
|
|
33
|
-
"@ontrails/config": "^1.0.0-beta.
|
|
34
|
-
"@ontrails/core": "^1.0.0-beta.
|
|
35
|
-
"@ontrails/http": "^1.0.0-beta.
|
|
36
|
-
"@ontrails/mcp": "^1.0.0-beta.
|
|
37
|
-
"@ontrails/observe": "^1.0.0-beta.
|
|
38
|
-
"@ontrails/permits": "^1.0.0-beta.
|
|
39
|
-
"@ontrails/regrade": "^1.0.0-beta.
|
|
40
|
-
"@ontrails/topographer": "^1.0.0-beta.
|
|
41
|
-
"@ontrails/tracing": "^1.0.0-beta.
|
|
42
|
-
"@ontrails/warden": "^1.0.0-beta.
|
|
43
|
-
"@ontrails/wayfinder": "^1.0.0-beta.
|
|
30
|
+
"@ontrails/adapter-kit": "^1.0.0-beta.30",
|
|
31
|
+
"@ontrails/cli": "^1.0.0-beta.30",
|
|
32
|
+
"@ontrails/commander": "^1.0.0-beta.30",
|
|
33
|
+
"@ontrails/config": "^1.0.0-beta.30",
|
|
34
|
+
"@ontrails/core": "^1.0.0-beta.30",
|
|
35
|
+
"@ontrails/http": "^1.0.0-beta.30",
|
|
36
|
+
"@ontrails/mcp": "^1.0.0-beta.30",
|
|
37
|
+
"@ontrails/observe": "^1.0.0-beta.30",
|
|
38
|
+
"@ontrails/permits": "^1.0.0-beta.30",
|
|
39
|
+
"@ontrails/regrade": "^1.0.0-beta.30",
|
|
40
|
+
"@ontrails/topographer": "^1.0.0-beta.30",
|
|
41
|
+
"@ontrails/tracing": "^1.0.0-beta.30",
|
|
42
|
+
"@ontrails/warden": "^1.0.0-beta.30",
|
|
43
|
+
"@ontrails/wayfinder": "^1.0.0-beta.30",
|
|
44
44
|
"commander": "^14.0.3",
|
|
45
45
|
"typescript": "^5.9.3",
|
|
46
46
|
"zod": "^4.3.5"
|
|
47
47
|
},
|
|
48
48
|
"devDependencies": {
|
|
49
|
-
"@ontrails/testing": "^1.0.0-beta.
|
|
49
|
+
"@ontrails/testing": "^1.0.0-beta.30"
|
|
50
50
|
}
|
|
51
51
|
}
|
|
@@ -304,27 +304,143 @@ export const discoverRegistryWorkspaces = async (
|
|
|
304
304
|
|
|
305
305
|
export type RegistryView = (name: string) => Promise<NpmView | null>;
|
|
306
306
|
|
|
307
|
-
export
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
307
|
+
export interface NpmCommandResult {
|
|
308
|
+
readonly exitCode: number;
|
|
309
|
+
readonly stderr: string;
|
|
310
|
+
readonly stdout: string;
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
export type NpmCommandRunner = (
|
|
314
|
+
args: readonly string[]
|
|
315
|
+
) => Promise<NpmCommandResult>;
|
|
316
|
+
|
|
317
|
+
const readSpawnResult = async (
|
|
318
|
+
proc: Bun.Subprocess<'ignore', 'pipe', 'pipe'>
|
|
319
|
+
): Promise<NpmCommandResult> => {
|
|
312
320
|
const [stdout, stderr, exitCode] = await Promise.all([
|
|
313
321
|
new Response(proc.stdout).text(),
|
|
314
322
|
new Response(proc.stderr).text(),
|
|
315
323
|
proc.exited,
|
|
316
324
|
]);
|
|
325
|
+
return { exitCode, stderr, stdout };
|
|
326
|
+
};
|
|
317
327
|
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
328
|
+
const runNpmCommand: NpmCommandRunner = async (args) =>
|
|
329
|
+
readSpawnResult(
|
|
330
|
+
Bun.spawn(['npm', ...args], {
|
|
331
|
+
stderr: 'pipe',
|
|
332
|
+
stdin: 'ignore',
|
|
333
|
+
stdout: 'pipe',
|
|
334
|
+
})
|
|
335
|
+
);
|
|
336
|
+
|
|
337
|
+
const isNpmNotFoundOutput = (stdout: string, stderr: string): boolean => {
|
|
321
338
|
const combined = `${stdout}\n${stderr}`;
|
|
322
|
-
|
|
339
|
+
return combined.includes('E404') || combined.includes('404 Not Found');
|
|
340
|
+
};
|
|
341
|
+
|
|
342
|
+
const isNpmExactVersionMissingOutput = (
|
|
343
|
+
stdout: string,
|
|
344
|
+
stderr: string
|
|
345
|
+
): boolean => {
|
|
346
|
+
const combined = `${stdout}\n${stderr}`;
|
|
347
|
+
return (
|
|
348
|
+
combined.includes('ETARGET') ||
|
|
349
|
+
combined.includes('No matching version found')
|
|
350
|
+
);
|
|
351
|
+
};
|
|
352
|
+
|
|
353
|
+
export const parseNpmDistTagListOutput = (
|
|
354
|
+
stdout: string
|
|
355
|
+
): Record<string, string> => {
|
|
356
|
+
const distTags: Record<string, string> = {};
|
|
357
|
+
for (const line of stdout.split(/\r?\n/)) {
|
|
358
|
+
const trimmed = line.trim();
|
|
359
|
+
if (trimmed.length === 0) {
|
|
360
|
+
continue;
|
|
361
|
+
}
|
|
362
|
+
const separator = trimmed.indexOf(':');
|
|
363
|
+
if (separator < 1) {
|
|
364
|
+
continue;
|
|
365
|
+
}
|
|
366
|
+
const tag = trimmed.slice(0, separator).trim();
|
|
367
|
+
const version = trimmed.slice(separator + 1).trim();
|
|
368
|
+
if (tag.length > 0 && version.length > 0) {
|
|
369
|
+
distTags[tag] = version;
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
return distTags;
|
|
373
|
+
};
|
|
374
|
+
|
|
375
|
+
export const parseNpmPackDryRunPublishedVersion = (
|
|
376
|
+
stdout: string,
|
|
377
|
+
name: string,
|
|
378
|
+
version: string
|
|
379
|
+
): boolean => {
|
|
380
|
+
const parsed = JSON.parse(stdout.trim()) as unknown;
|
|
381
|
+
if (!Array.isArray(parsed)) {
|
|
382
|
+
return false;
|
|
383
|
+
}
|
|
384
|
+
return parsed.some((entry) => {
|
|
385
|
+
if (typeof entry !== 'object' || entry === null) {
|
|
386
|
+
return false;
|
|
387
|
+
}
|
|
388
|
+
const candidate = entry as {
|
|
389
|
+
readonly id?: unknown;
|
|
390
|
+
readonly name?: unknown;
|
|
391
|
+
readonly version?: unknown;
|
|
392
|
+
};
|
|
393
|
+
return (
|
|
394
|
+
candidate.id === `${name}@${version}` ||
|
|
395
|
+
(candidate.name === name && candidate.version === version)
|
|
396
|
+
);
|
|
397
|
+
});
|
|
398
|
+
};
|
|
399
|
+
|
|
400
|
+
const npmDistTagRegistryView = async (
|
|
401
|
+
name: string,
|
|
402
|
+
runNpm: NpmCommandRunner
|
|
403
|
+
): Promise<NpmView | null> => {
|
|
404
|
+
const { exitCode, stderr, stdout } = await runNpm(['dist-tag', 'ls', name]);
|
|
405
|
+
if (exitCode !== 0) {
|
|
406
|
+
if (isNpmNotFoundOutput(stdout, stderr)) {
|
|
407
|
+
return null;
|
|
408
|
+
}
|
|
409
|
+
throw new Error(stderr.trim() || `npm dist-tag ls failed for ${name}`);
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
const distTags = parseNpmDistTagListOutput(stdout);
|
|
413
|
+
const version =
|
|
414
|
+
distTags['latest'] ?? distTags['beta'] ?? Object.values(distTags)[0];
|
|
415
|
+
if (version === undefined) {
|
|
323
416
|
return null;
|
|
324
417
|
}
|
|
325
|
-
|
|
418
|
+
return { 'dist-tags': distTags, name, version };
|
|
326
419
|
};
|
|
327
420
|
|
|
421
|
+
export const createNpmRegistryView =
|
|
422
|
+
(runNpm: NpmCommandRunner = runNpmCommand): RegistryView =>
|
|
423
|
+
async (name) => {
|
|
424
|
+
const { exitCode, stderr, stdout } = await runNpm([
|
|
425
|
+
'view',
|
|
426
|
+
name,
|
|
427
|
+
'name',
|
|
428
|
+
'version',
|
|
429
|
+
'dist-tags',
|
|
430
|
+
'--json',
|
|
431
|
+
]);
|
|
432
|
+
|
|
433
|
+
if (exitCode === 0) {
|
|
434
|
+
return JSON.parse(stdout) as NpmView;
|
|
435
|
+
}
|
|
436
|
+
if (isNpmNotFoundOutput(stdout, stderr)) {
|
|
437
|
+
return npmDistTagRegistryView(name, runNpm);
|
|
438
|
+
}
|
|
439
|
+
throw new Error(stderr.trim() || `npm view failed for ${name}`);
|
|
440
|
+
};
|
|
441
|
+
|
|
442
|
+
export const npmRegistryView: RegistryView = createNpmRegistryView();
|
|
443
|
+
|
|
328
444
|
/** Probe whether an exact `name@version` is published. The missing fact that
|
|
329
445
|
* a tag/version summary alone cannot answer. */
|
|
330
446
|
export type RegistryVersionView = (
|
|
@@ -336,29 +452,54 @@ const UNKNOWN_REGISTRY_VERSION_STATE: { readonly published?: boolean } = {};
|
|
|
336
452
|
const unknownRegistryVersionView: RegistryVersionView = async () =>
|
|
337
453
|
UNKNOWN_REGISTRY_VERSION_STATE.published;
|
|
338
454
|
|
|
339
|
-
export const
|
|
340
|
-
|
|
341
|
-
version
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
455
|
+
export const createNpmRegistryVersionView =
|
|
456
|
+
(runNpm: NpmCommandRunner = runNpmCommand): RegistryVersionView =>
|
|
457
|
+
async (name, version) => {
|
|
458
|
+
const { exitCode, stderr, stdout } = await runNpm([
|
|
459
|
+
'view',
|
|
460
|
+
`${name}@${version}`,
|
|
461
|
+
'version',
|
|
462
|
+
'--json',
|
|
463
|
+
]);
|
|
464
|
+
|
|
465
|
+
if (exitCode === 0) {
|
|
466
|
+
return JSON.parse(stdout.trim()) === version;
|
|
467
|
+
}
|
|
468
|
+
if (isNpmExactVersionMissingOutput(stdout, stderr)) {
|
|
469
|
+
return false;
|
|
470
|
+
}
|
|
471
|
+
if (!isNpmNotFoundOutput(stdout, stderr)) {
|
|
472
|
+
throw new Error(
|
|
473
|
+
stderr.trim() || `npm view failed for ${name}@${version}`
|
|
474
|
+
);
|
|
475
|
+
}
|
|
352
476
|
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
477
|
+
const packResult = await runNpm([
|
|
478
|
+
'pack',
|
|
479
|
+
`${name}@${version}`,
|
|
480
|
+
'--dry-run',
|
|
481
|
+
'--json',
|
|
482
|
+
]);
|
|
483
|
+
if (packResult.exitCode === 0) {
|
|
484
|
+
return parseNpmPackDryRunPublishedVersion(
|
|
485
|
+
packResult.stdout,
|
|
486
|
+
name,
|
|
487
|
+
version
|
|
488
|
+
);
|
|
489
|
+
}
|
|
490
|
+
if (isNpmExactVersionMissingOutput(packResult.stdout, packResult.stderr)) {
|
|
491
|
+
return false;
|
|
492
|
+
}
|
|
493
|
+
if (isNpmNotFoundOutput(packResult.stdout, packResult.stderr)) {
|
|
494
|
+
return false;
|
|
495
|
+
}
|
|
496
|
+
throw new Error(
|
|
497
|
+
packResult.stderr.trim() || `npm pack failed for ${name}@${version}`
|
|
498
|
+
);
|
|
499
|
+
};
|
|
500
|
+
|
|
501
|
+
export const npmRegistryVersionView: RegistryVersionView =
|
|
502
|
+
createNpmRegistryVersionView();
|
|
362
503
|
|
|
363
504
|
/** Run async tasks with a bounded number in flight, preserving input order. */
|
|
364
505
|
const mapBounded = async <T, R>(
|