portweave 0.1.0
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/LICENSE +21 -0
- package/README.md +535 -0
- package/dist/allocator/allocate.concurrent.d.ts +3 -0
- package/dist/allocator/allocate.concurrent.d.ts.map +1 -0
- package/dist/allocator/allocate.concurrent.js +10 -0
- package/dist/allocator/allocate.concurrent.js.map +1 -0
- package/dist/allocator/allocate.d.ts +20 -0
- package/dist/allocator/allocate.d.ts.map +1 -0
- package/dist/allocator/allocate.js +106 -0
- package/dist/allocator/allocate.js.map +1 -0
- package/dist/allocator/cross-project.d.ts +2 -0
- package/dist/allocator/cross-project.d.ts.map +1 -0
- package/dist/allocator/cross-project.js +9 -0
- package/dist/allocator/cross-project.js.map +1 -0
- package/dist/allocator/order.d.ts +2 -0
- package/dist/allocator/order.d.ts.map +1 -0
- package/dist/allocator/order.js +8 -0
- package/dist/allocator/order.js.map +1 -0
- package/dist/allocator/pool.d.ts +35 -0
- package/dist/allocator/pool.d.ts.map +1 -0
- package/dist/allocator/pool.js +74 -0
- package/dist/allocator/pool.js.map +1 -0
- package/dist/allocator/probe.d.ts +22 -0
- package/dist/allocator/probe.d.ts.map +1 -0
- package/dist/allocator/probe.js +40 -0
- package/dist/allocator/probe.js.map +1 -0
- package/dist/cli/banner.d.ts +25 -0
- package/dist/cli/banner.d.ts.map +1 -0
- package/dist/cli/banner.js +61 -0
- package/dist/cli/banner.js.map +1 -0
- package/dist/cli/run.d.ts +15 -0
- package/dist/cli/run.d.ts.map +1 -0
- package/dist/cli/run.js +156 -0
- package/dist/cli/run.js.map +1 -0
- package/dist/cli/show.d.ts +21 -0
- package/dist/cli/show.d.ts.map +1 -0
- package/dist/cli/show.js +141 -0
- package/dist/cli/show.js.map +1 -0
- package/dist/cli/spawn.d.ts +30 -0
- package/dist/cli/spawn.d.ts.map +1 -0
- package/dist/cli/spawn.js +85 -0
- package/dist/cli/spawn.js.map +1 -0
- package/dist/cli.d.ts +5 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +52 -0
- package/dist/cli.js.map +1 -0
- package/dist/config/anonymous.d.ts +5 -0
- package/dist/config/anonymous.d.ts.map +1 -0
- package/dist/config/anonymous.js +21 -0
- package/dist/config/anonymous.js.map +1 -0
- package/dist/config/index.d.ts +4 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +4 -0
- package/dist/config/index.js.map +1 -0
- package/dist/config/loader.d.ts +8 -0
- package/dist/config/loader.d.ts.map +1 -0
- package/dist/config/loader.js +59 -0
- package/dist/config/loader.js.map +1 -0
- package/dist/config/schema.d.ts +21 -0
- package/dist/config/schema.d.ts.map +1 -0
- package/dist/config/schema.js +125 -0
- package/dist/config/schema.js.map +1 -0
- package/dist/env/build.d.ts +4 -0
- package/dist/env/build.d.ts.map +1 -0
- package/dist/env/build.js +17 -0
- package/dist/env/build.js.map +1 -0
- package/dist/env/dotenv-merge.d.ts +5 -0
- package/dist/env/dotenv-merge.d.ts.map +1 -0
- package/dist/env/dotenv-merge.js +73 -0
- package/dist/env/dotenv-merge.js.map +1 -0
- package/dist/env/index.d.ts +4 -0
- package/dist/env/index.d.ts.map +1 -0
- package/dist/env/index.js +4 -0
- package/dist/env/index.js.map +1 -0
- package/dist/env/resolve.d.ts +11 -0
- package/dist/env/resolve.d.ts.map +1 -0
- package/dist/env/resolve.js +29 -0
- package/dist/env/resolve.js.map +1 -0
- package/dist/env/templates.d.ts +2 -0
- package/dist/env/templates.d.ts.map +1 -0
- package/dist/env/templates.js +11 -0
- package/dist/env/templates.js.map +1 -0
- package/dist/env/writer.d.ts +6 -0
- package/dist/env/writer.d.ts.map +1 -0
- package/dist/env/writer.js +68 -0
- package/dist/env/writer.js.map +1 -0
- package/dist/errors.d.ts +22 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +32 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +11 -0
- package/dist/index.js.map +1 -0
- package/dist/registry/atomic-write.d.ts +3 -0
- package/dist/registry/atomic-write.d.ts.map +1 -0
- package/dist/registry/atomic-write.js +43 -0
- package/dist/registry/atomic-write.js.map +1 -0
- package/dist/registry/lock.d.ts +4 -0
- package/dist/registry/lock.d.ts.map +1 -0
- package/dist/registry/lock.js +86 -0
- package/dist/registry/lock.js.map +1 -0
- package/dist/registry/paths.d.ts +7 -0
- package/dist/registry/paths.d.ts.map +1 -0
- package/dist/registry/paths.js +13 -0
- package/dist/registry/paths.js.map +1 -0
- package/dist/registry/prune.d.ts +3 -0
- package/dist/registry/prune.d.ts.map +1 -0
- package/dist/registry/prune.js +24 -0
- package/dist/registry/prune.js.map +1 -0
- package/dist/registry/serialize.d.ts +6 -0
- package/dist/registry/serialize.d.ts.map +1 -0
- package/dist/registry/serialize.js +134 -0
- package/dist/registry/serialize.js.map +1 -0
- package/dist/registry/storage.concurrent.d.ts +3 -0
- package/dist/registry/storage.concurrent.d.ts.map +1 -0
- package/dist/registry/storage.concurrent.js +10 -0
- package/dist/registry/storage.concurrent.js.map +1 -0
- package/dist/registry/storage.d.ts +11 -0
- package/dist/registry/storage.d.ts.map +1 -0
- package/dist/registry/storage.js +101 -0
- package/dist/registry/storage.js.map +1 -0
- package/dist/registry/types.d.ts +14 -0
- package/dist/registry/types.d.ts.map +1 -0
- package/dist/registry/types.js +2 -0
- package/dist/registry/types.js.map +1 -0
- package/dist/result.d.ts +11 -0
- package/dist/result.d.ts.map +1 -0
- package/dist/result.js +6 -0
- package/dist/result.js.map +1 -0
- package/dist/runtime/error-passthrough.d.ts +20 -0
- package/dist/runtime/error-passthrough.d.ts.map +1 -0
- package/dist/runtime/error-passthrough.js +20 -0
- package/dist/runtime/error-passthrough.js.map +1 -0
- package/dist/runtime/exports-smoke.d.ts +4 -0
- package/dist/runtime/exports-smoke.d.ts.map +1 -0
- package/dist/runtime/exports-smoke.js +36 -0
- package/dist/runtime/exports-smoke.js.map +1 -0
- package/dist/runtime/index.d.ts +15 -0
- package/dist/runtime/index.d.ts.map +1 -0
- package/dist/runtime/index.js +99 -0
- package/dist/runtime/index.js.map +1 -0
- package/dist/runtime/upward-walk.d.ts +14 -0
- package/dist/runtime/upward-walk.d.ts.map +1 -0
- package/dist/runtime/upward-walk.js +39 -0
- package/dist/runtime/upward-walk.js.map +1 -0
- package/dist/worktree/git.d.ts +13 -0
- package/dist/worktree/git.d.ts.map +1 -0
- package/dist/worktree/git.js +66 -0
- package/dist/worktree/git.js.map +1 -0
- package/dist/worktree/key.d.ts +10 -0
- package/dist/worktree/key.d.ts.map +1 -0
- package/dist/worktree/key.js +38 -0
- package/dist/worktree/key.js.map +1 -0
- package/dist/worktree/namespace.d.ts +8 -0
- package/dist/worktree/namespace.d.ts.map +1 -0
- package/dist/worktree/namespace.js +58 -0
- package/dist/worktree/namespace.js.map +1 -0
- package/package.json +109 -0
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { mkdir, rm, stat } from 'node:fs/promises';
|
|
2
|
+
import { PortweaveError, PW_ERROR_CODES } from "../errors.js";
|
|
3
|
+
import { err, ok } from "../result.js";
|
|
4
|
+
const LOCK_RETRY_COUNT_DEFAULT = 100;
|
|
5
|
+
const LOCK_RETRY_DELAY_MS = 25;
|
|
6
|
+
const STALE_LOCK_MS = 30_000;
|
|
7
|
+
function getErrorCode(value) {
|
|
8
|
+
if (typeof value !== 'object' || value === null || !('code' in value)) {
|
|
9
|
+
return undefined;
|
|
10
|
+
}
|
|
11
|
+
const code = value.code;
|
|
12
|
+
return typeof code === 'string' ? code : undefined;
|
|
13
|
+
}
|
|
14
|
+
function sleep(ms) {
|
|
15
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
16
|
+
}
|
|
17
|
+
function resolveLockConfig() {
|
|
18
|
+
const raw = process.env.PORTWEAVE_LOCK_TIMEOUT_MS;
|
|
19
|
+
if (raw === undefined || raw.length === 0) {
|
|
20
|
+
return {
|
|
21
|
+
retryCount: LOCK_RETRY_COUNT_DEFAULT,
|
|
22
|
+
retryDelayMs: LOCK_RETRY_DELAY_MS,
|
|
23
|
+
staleMs: STALE_LOCK_MS,
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
const parsed = Number.parseInt(raw, 10);
|
|
27
|
+
if (!Number.isFinite(parsed) || parsed <= 0) {
|
|
28
|
+
return {
|
|
29
|
+
retryCount: LOCK_RETRY_COUNT_DEFAULT,
|
|
30
|
+
retryDelayMs: LOCK_RETRY_DELAY_MS,
|
|
31
|
+
staleMs: STALE_LOCK_MS,
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
return {
|
|
35
|
+
retryCount: Math.max(1, Math.ceil(parsed / LOCK_RETRY_DELAY_MS)),
|
|
36
|
+
retryDelayMs: LOCK_RETRY_DELAY_MS,
|
|
37
|
+
staleMs: STALE_LOCK_MS,
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
async function tryRemoveStaleLock(lockDir, staleMs) {
|
|
41
|
+
try {
|
|
42
|
+
const info = await stat(lockDir);
|
|
43
|
+
if (Date.now() - info.mtimeMs > staleMs) {
|
|
44
|
+
await rm(lockDir, { force: true, recursive: true });
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
catch (caught) {
|
|
48
|
+
// pw-allow-swallow: ENOENT means the lock vanished concurrently — no action needed.
|
|
49
|
+
// Any other error is unexpected; remove forcefully as best-effort and let the
|
|
50
|
+
// retry loop surface the failure.
|
|
51
|
+
if (getErrorCode(caught) !== 'ENOENT') {
|
|
52
|
+
await rm(lockDir, { force: true, recursive: true });
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
async function tryAcquire(lockDir) {
|
|
57
|
+
try {
|
|
58
|
+
await mkdir(lockDir);
|
|
59
|
+
return true;
|
|
60
|
+
}
|
|
61
|
+
catch (caught) {
|
|
62
|
+
if (getErrorCode(caught) === 'EEXIST') {
|
|
63
|
+
return false;
|
|
64
|
+
}
|
|
65
|
+
throw caught;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
export async function withLock(lockDir, fn) {
|
|
69
|
+
const config = resolveLockConfig();
|
|
70
|
+
for (let attempt = 0; attempt < config.retryCount; attempt++) {
|
|
71
|
+
const acquired = await tryAcquire(lockDir);
|
|
72
|
+
if (acquired) {
|
|
73
|
+
try {
|
|
74
|
+
const value = await fn();
|
|
75
|
+
return ok(value);
|
|
76
|
+
}
|
|
77
|
+
finally {
|
|
78
|
+
await rm(lockDir, { force: true, recursive: true });
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
await tryRemoveStaleLock(lockDir, config.staleMs);
|
|
82
|
+
await sleep(config.retryDelayMs);
|
|
83
|
+
}
|
|
84
|
+
return err(new PortweaveError(PW_ERROR_CODES.REGISTRY_LOCKED, `timed out acquiring registry lock at ${lockDir} after ${config.retryCount.toString()} retries`));
|
|
85
|
+
}
|
|
86
|
+
//# sourceMappingURL=lock.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lock.js","sourceRoot":"","sources":["../../src/registry/lock.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../../src/registry/paths.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;IAC5B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAA;CAC9B;AAED,wBAAgB,mBAAmB,CACjC,GAAG,GAAE,MAAM,CAAC,UAAwB,GACnC,aAAa,CAUf"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { homedir } from 'node:os';
|
|
2
|
+
import { isAbsolute, join } from 'node:path';
|
|
3
|
+
export function resolveRegistryPath(env = process.env) {
|
|
4
|
+
const xdg = env.XDG_CONFIG_HOME;
|
|
5
|
+
const configHome = xdg && xdg.length > 0 && isAbsolute(xdg) ? xdg : join(homedir(), '.config');
|
|
6
|
+
const registryDir = join(configHome, 'portweave');
|
|
7
|
+
return {
|
|
8
|
+
lockDir: join(registryDir, 'registry.lock'),
|
|
9
|
+
registryDir,
|
|
10
|
+
registryFile: join(registryDir, 'registry.json'),
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=paths.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"paths.js","sourceRoot":"","sources":["../../src/registry/paths.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAA;AACjC,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAQ5C,MAAM,UAAU,mBAAmB,CACjC,MAAyB,OAAO,CAAC,GAAG;IAEpC,MAAM,GAAG,GAAG,GAAG,CAAC,eAAe,CAAA;IAC/B,MAAM,UAAU,GACd,GAAG,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,SAAS,CAAC,CAAA;IAC7E,MAAM,WAAW,GAAG,IAAI,CAAC,UAAU,EAAE,WAAW,CAAC,CAAA;IACjD,OAAO;QACL,OAAO,EAAE,IAAI,CAAC,WAAW,EAAE,eAAe,CAAC;QAC3C,WAAW;QACX,YAAY,EAAE,IAAI,CAAC,WAAW,EAAE,eAAe,CAAC;KACjD,CAAA;AACH,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prune.d.ts","sourceRoot":"","sources":["../../src/registry/prune.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAe/C,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,SAAS,aAAa,EAAE,EACjC,QAAQ,GAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAgC,GAC3D,aAAa,EAAE,CAQjB"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { existsSync, statSync } from 'node:fs';
|
|
2
|
+
function defaultDirectoryExists(path) {
|
|
3
|
+
if (!existsSync(path)) {
|
|
4
|
+
return false;
|
|
5
|
+
}
|
|
6
|
+
try {
|
|
7
|
+
return statSync(path).isDirectory();
|
|
8
|
+
}
|
|
9
|
+
catch {
|
|
10
|
+
// pw-allow-swallow: statSync failure after existsSync succeeds means the path
|
|
11
|
+
// was removed between the two calls. Treat as non-existent.
|
|
12
|
+
return false;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
export function pruneStaleEntries(entries, fsExists = defaultDirectoryExists) {
|
|
16
|
+
const kept = [];
|
|
17
|
+
for (const entry of entries) {
|
|
18
|
+
if (fsExists(entry.key.worktreeRoot)) {
|
|
19
|
+
kept.push(entry);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
return kept;
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=prune.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prune.js","sourceRoot":"","sources":["../../src/registry/prune.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAA;AAG9C,SAAS,sBAAsB,CAAC,IAAY;IAC1C,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;QACtB,OAAO,KAAK,CAAA;IACd,CAAC;IACD,IAAI,CAAC;QACH,OAAO,QAAQ,CAAC,IAAI,CAAC,CAAC,WAAW,EAAE,CAAA;IACrC,CAAC;IAAC,MAAM,CAAC;QACP,8EAA8E;QAC9E,4DAA4D;QAC5D,OAAO,KAAK,CAAA;IACd,CAAC;AACH,CAAC;AAED,MAAM,UAAU,iBAAiB,CAC/B,OAAiC,EACjC,WAAsC,sBAAsB;IAE5D,MAAM,IAAI,GAAoB,EAAE,CAAA;IAChC,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,IAAI,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,YAAY,CAAC,EAAE,CAAC;YACrC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;QAClB,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAA;AACb,CAAC"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { PortweaveError } from '../errors.ts';
|
|
2
|
+
import { type Result } from '../result.ts';
|
|
3
|
+
import { type RegistryFile } from './types.ts';
|
|
4
|
+
export declare function loadRegistryFile(path: string): Promise<Result<RegistryFile, PortweaveError>>;
|
|
5
|
+
export declare function serializeRegistry(file: RegistryFile): string;
|
|
6
|
+
//# sourceMappingURL=serialize.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"serialize.d.ts","sourceRoot":"","sources":["../../src/registry/serialize.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAkB,MAAM,cAAc,CAAA;AAC7D,OAAO,EAAW,KAAK,MAAM,EAAE,MAAM,cAAc,CAAA;AACnD,OAAO,EAIL,KAAK,YAAY,EAClB,MAAM,YAAY,CAAA;AA0FnB,wBAAsB,gBAAgB,CACpC,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,MAAM,CAAC,YAAY,EAAE,cAAc,CAAC,CAAC,CA4C/C;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,YAAY,GAAG,MAAM,CAoB5D"}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import { readFile } from 'node:fs/promises';
|
|
2
|
+
import { PortweaveError, PW_ERROR_CODES } from "../errors.js";
|
|
3
|
+
import { err, ok } from "../result.js";
|
|
4
|
+
import { REGISTRY_VERSION, } from "./types.js";
|
|
5
|
+
function isRecord(value) {
|
|
6
|
+
return typeof value === 'object' && value !== null;
|
|
7
|
+
}
|
|
8
|
+
function isIsoDateString(value) {
|
|
9
|
+
if (typeof value !== 'string') {
|
|
10
|
+
return false;
|
|
11
|
+
}
|
|
12
|
+
const parsed = Date.parse(value);
|
|
13
|
+
return !Number.isNaN(parsed);
|
|
14
|
+
}
|
|
15
|
+
function parseKey(raw) {
|
|
16
|
+
if (!isRecord(raw)) {
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
const { gitCommonDir, namespace, worktreeRoot } = raw;
|
|
20
|
+
if (typeof worktreeRoot !== 'string' || typeof namespace !== 'string') {
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
if (gitCommonDir !== null && typeof gitCommonDir !== 'string') {
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
// offsetOverride is not persisted — always null on deserialization
|
|
27
|
+
return { gitCommonDir, namespace, offsetOverride: null, worktreeRoot };
|
|
28
|
+
}
|
|
29
|
+
function parsePorts(raw) {
|
|
30
|
+
if (!isRecord(raw)) {
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
const ports = {};
|
|
34
|
+
for (const [name, port] of Object.entries(raw)) {
|
|
35
|
+
if (typeof port !== 'number' || !Number.isInteger(port)) {
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
ports[name] = port;
|
|
39
|
+
}
|
|
40
|
+
return ports;
|
|
41
|
+
}
|
|
42
|
+
function parseEntry(raw) {
|
|
43
|
+
if (!isRecord(raw)) {
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
const key = parseKey(raw.key);
|
|
47
|
+
if (key === null) {
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
50
|
+
const ports = parsePorts(raw.ports);
|
|
51
|
+
if (ports === null) {
|
|
52
|
+
return null;
|
|
53
|
+
}
|
|
54
|
+
if (!isIsoDateString(raw.lastUsedAt)) {
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
if (typeof raw.namespace !== 'string') {
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
return {
|
|
61
|
+
key,
|
|
62
|
+
lastUsedAt: raw.lastUsedAt,
|
|
63
|
+
namespace: raw.namespace,
|
|
64
|
+
ports,
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
function parseRegistry(raw) {
|
|
68
|
+
if (!isRecord(raw)) {
|
|
69
|
+
return null;
|
|
70
|
+
}
|
|
71
|
+
if (raw.version !== REGISTRY_VERSION) {
|
|
72
|
+
return null;
|
|
73
|
+
}
|
|
74
|
+
if (!Array.isArray(raw.entries)) {
|
|
75
|
+
return null;
|
|
76
|
+
}
|
|
77
|
+
const entries = [];
|
|
78
|
+
for (const item of raw.entries) {
|
|
79
|
+
const entry = parseEntry(item);
|
|
80
|
+
if (entry === null) {
|
|
81
|
+
return null;
|
|
82
|
+
}
|
|
83
|
+
entries.push(entry);
|
|
84
|
+
}
|
|
85
|
+
return { entries, version: REGISTRY_VERSION };
|
|
86
|
+
}
|
|
87
|
+
export async function loadRegistryFile(path) {
|
|
88
|
+
let text;
|
|
89
|
+
try {
|
|
90
|
+
text = await readFile(path, 'utf-8');
|
|
91
|
+
}
|
|
92
|
+
catch (caught) {
|
|
93
|
+
if (isRecord(caught) &&
|
|
94
|
+
typeof caught.code === 'string' &&
|
|
95
|
+
caught.code === 'ENOENT') {
|
|
96
|
+
return ok({ entries: [], version: REGISTRY_VERSION });
|
|
97
|
+
}
|
|
98
|
+
const message = caught instanceof Error ? caught.message : 'unknown error';
|
|
99
|
+
return err(new PortweaveError(PW_ERROR_CODES.REGISTRY_CORRUPT, `failed to read registry file at ${path}: ${message}`));
|
|
100
|
+
}
|
|
101
|
+
let parsed;
|
|
102
|
+
try {
|
|
103
|
+
parsed = JSON.parse(text);
|
|
104
|
+
}
|
|
105
|
+
catch (caught) {
|
|
106
|
+
const message = caught instanceof Error ? caught.message : 'invalid JSON';
|
|
107
|
+
return err(new PortweaveError(PW_ERROR_CODES.REGISTRY_CORRUPT, `registry file at ${path} is not valid JSON: ${message}`));
|
|
108
|
+
}
|
|
109
|
+
const file = parseRegistry(parsed);
|
|
110
|
+
if (file === null) {
|
|
111
|
+
return err(new PortweaveError(PW_ERROR_CODES.REGISTRY_CORRUPT, `registry file at ${path} failed schema validation`));
|
|
112
|
+
}
|
|
113
|
+
return ok(file);
|
|
114
|
+
}
|
|
115
|
+
export function serializeRegistry(file) {
|
|
116
|
+
const sorted = [...file.entries].sort((a, b) => {
|
|
117
|
+
if (a.key.worktreeRoot !== b.key.worktreeRoot) {
|
|
118
|
+
return a.key.worktreeRoot < b.key.worktreeRoot ? -1 : 1;
|
|
119
|
+
}
|
|
120
|
+
return a.key.namespace < b.key.namespace ? -1 : 1;
|
|
121
|
+
});
|
|
122
|
+
const normalized = sorted.map((entry) => ({
|
|
123
|
+
key: {
|
|
124
|
+
gitCommonDir: entry.key.gitCommonDir,
|
|
125
|
+
namespace: entry.key.namespace,
|
|
126
|
+
worktreeRoot: entry.key.worktreeRoot,
|
|
127
|
+
},
|
|
128
|
+
lastUsedAt: entry.lastUsedAt,
|
|
129
|
+
namespace: entry.namespace,
|
|
130
|
+
ports: Object.fromEntries(Object.entries(entry.ports).sort(([a], [b]) => (a < b ? -1 : 1))),
|
|
131
|
+
}));
|
|
132
|
+
return `${JSON.stringify({ entries: normalized, version: file.version }, null, 2)}\n`;
|
|
133
|
+
}
|
|
134
|
+
//# sourceMappingURL=serialize.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"serialize.js","sourceRoot":"","sources":["../../src/registry/serialize.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"storage.concurrent.d.ts","sourceRoot":"","sources":["../../src/registry/storage.concurrent.ts"],"names":[],"mappings":"AAaA,eAAO,MAAM,sBAAsB,EAAE,MAAmC,CAAA;AACxE,eAAO,MAAM,uBAAuB,EAAG,CAAU,CAAA"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
// Concurrency test surface — kept separate from storage.ts so the path
|
|
2
|
+
// helpers and constants used by the concurrent integration test live next
|
|
3
|
+
// to the test rather than polluting the runtime module. Imported only from
|
|
4
|
+
// __tests__/storage.concurrent.test.ts; structure-check requires that a
|
|
5
|
+
// .test.ts file has a sibling source module at this location.
|
|
6
|
+
import { fileURLToPath } from 'node:url';
|
|
7
|
+
const FIXTURE_URL = new URL('./__tests__/fixtures/concurrent-writer.ts', import.meta.url);
|
|
8
|
+
export const CONCURRENT_WRITER_PATH = fileURLToPath(FIXTURE_URL);
|
|
9
|
+
export const CONCURRENT_WRITER_COUNT = 8;
|
|
10
|
+
//# sourceMappingURL=storage.concurrent.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"storage.concurrent.js","sourceRoot":"","sources":["../../src/registry/storage.concurrent.ts"],"names":[],"mappings":"AAAA,uEAAuE;AACvE,0EAA0E;AAC1E,2EAA2E;AAC3E,wEAAwE;AACxE,8DAA8D;AAE9D,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AAExC,MAAM,WAAW,GAAG,IAAI,GAAG,CACzB,2CAA2C,EAC3C,MAAM,CAAC,IAAI,CAAC,GAAG,CAChB,CAAA;AAED,MAAM,CAAC,MAAM,sBAAsB,GAAW,aAAa,CAAC,WAAW,CAAC,CAAA;AACxE,MAAM,CAAC,MAAM,uBAAuB,GAAG,CAAU,CAAA"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { PortweaveError } from '../errors.ts';
|
|
2
|
+
import { type Result } from '../result.ts';
|
|
3
|
+
import { type AllocationKey, type RegistryEntry } from './types.ts';
|
|
4
|
+
export interface WithRegistryHandle {
|
|
5
|
+
readonly entries: readonly RegistryEntry[];
|
|
6
|
+
remove: (key: AllocationKey) => void;
|
|
7
|
+
touch: (key: AllocationKey) => void;
|
|
8
|
+
upsert: (entry: RegistryEntry) => void;
|
|
9
|
+
}
|
|
10
|
+
export declare function withRegistry<T>(fn: (handle: WithRegistryHandle) => Promise<T> | T, env?: NodeJS.ProcessEnv): Promise<Result<T, PortweaveError>>;
|
|
11
|
+
//# sourceMappingURL=storage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../../src/registry/storage.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAA;AAC7C,OAAO,EAAO,KAAK,MAAM,EAAE,MAAM,cAAc,CAAA;AAM/C,OAAO,EACL,KAAK,aAAa,EAElB,KAAK,aAAa,EAEnB,MAAM,YAAY,CAAA;AAEnB,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,OAAO,EAAE,SAAS,aAAa,EAAE,CAAA;IAC1C,MAAM,EAAE,CAAC,GAAG,EAAE,aAAa,KAAK,IAAI,CAAA;IACpC,KAAK,EAAE,CAAC,GAAG,EAAE,aAAa,KAAK,IAAI,CAAA;IACnC,MAAM,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAA;CACvC;AAsED,wBAAsB,YAAY,CAAC,CAAC,EAClC,EAAE,EAAE,CAAC,MAAM,EAAE,kBAAkB,KAAK,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,EAClD,GAAG,GAAE,MAAM,CAAC,UAAwB,GACnC,OAAO,CAAC,MAAM,CAAC,CAAC,EAAE,cAAc,CAAC,CAAC,CA2CpC"}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { mkdir } from 'node:fs/promises';
|
|
2
|
+
import { PortweaveError } from "../errors.js";
|
|
3
|
+
import { err } from "../result.js";
|
|
4
|
+
import { atomicWriteRegistry, pruneStaleTempFiles } from "./atomic-write.js";
|
|
5
|
+
import { withLock } from "./lock.js";
|
|
6
|
+
import { resolveRegistryPath } from "./paths.js";
|
|
7
|
+
import { pruneStaleEntries } from "./prune.js";
|
|
8
|
+
import { loadRegistryFile, serializeRegistry } from "./serialize.js";
|
|
9
|
+
import { REGISTRY_VERSION, } from "./types.js";
|
|
10
|
+
function keysEqual(a, b) {
|
|
11
|
+
return (a.worktreeRoot === b.worktreeRoot &&
|
|
12
|
+
a.namespace === b.namespace &&
|
|
13
|
+
a.gitCommonDir === b.gitCommonDir);
|
|
14
|
+
}
|
|
15
|
+
function buildHandle(state) {
|
|
16
|
+
return {
|
|
17
|
+
/** Insertion-ordered, not sort-ordered. Callers that need sorted order must sort themselves. */
|
|
18
|
+
get entries() {
|
|
19
|
+
return state.entries;
|
|
20
|
+
},
|
|
21
|
+
remove(key) {
|
|
22
|
+
const before = state.entries.length;
|
|
23
|
+
state.entries = state.entries.filter((e) => !keysEqual(e.key, key));
|
|
24
|
+
if (state.entries.length !== before) {
|
|
25
|
+
state.mutated = true;
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
touch(key) {
|
|
29
|
+
const idx = state.entries.findIndex((e) => keysEqual(e.key, key));
|
|
30
|
+
if (idx === -1) {
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
const existing = state.entries[idx];
|
|
34
|
+
const next = {
|
|
35
|
+
key: existing.key,
|
|
36
|
+
lastUsedAt: new Date().toISOString(),
|
|
37
|
+
namespace: existing.namespace,
|
|
38
|
+
ports: existing.ports,
|
|
39
|
+
};
|
|
40
|
+
state.entries = [
|
|
41
|
+
...state.entries.slice(0, idx),
|
|
42
|
+
next,
|
|
43
|
+
...state.entries.slice(idx + 1),
|
|
44
|
+
];
|
|
45
|
+
state.mutated = true;
|
|
46
|
+
},
|
|
47
|
+
upsert(entry) {
|
|
48
|
+
const idx = state.entries.findIndex((e) => keysEqual(e.key, entry.key));
|
|
49
|
+
if (idx === -1) {
|
|
50
|
+
state.entries = [...state.entries, entry];
|
|
51
|
+
}
|
|
52
|
+
else {
|
|
53
|
+
state.entries = [
|
|
54
|
+
...state.entries.slice(0, idx),
|
|
55
|
+
entry,
|
|
56
|
+
...state.entries.slice(idx + 1),
|
|
57
|
+
];
|
|
58
|
+
}
|
|
59
|
+
state.mutated = true;
|
|
60
|
+
},
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
const LOAD_ERROR_KIND = 'load-error';
|
|
64
|
+
const OK_KIND = 'ok';
|
|
65
|
+
export async function withRegistry(fn, env = process.env) {
|
|
66
|
+
const paths = resolveRegistryPath(env);
|
|
67
|
+
await mkdir(paths.registryDir, { mode: 0o700, recursive: true });
|
|
68
|
+
const lockResult = await withLock(paths.lockDir, async () => {
|
|
69
|
+
await pruneStaleTempFiles(paths.registryFile);
|
|
70
|
+
const loaded = await loadRegistryFile(paths.registryFile);
|
|
71
|
+
if (!loaded.ok) {
|
|
72
|
+
return { error: loaded.error, kind: LOAD_ERROR_KIND };
|
|
73
|
+
}
|
|
74
|
+
const fileBefore = loaded.value;
|
|
75
|
+
const prunedEntries = pruneStaleEntries(fileBefore.entries);
|
|
76
|
+
const initialMutated = prunedEntries.length !== fileBefore.entries.length;
|
|
77
|
+
const state = {
|
|
78
|
+
entries: prunedEntries,
|
|
79
|
+
mutated: initialMutated,
|
|
80
|
+
};
|
|
81
|
+
const handle = buildHandle(state);
|
|
82
|
+
const value = await fn(handle);
|
|
83
|
+
if (state.mutated) {
|
|
84
|
+
const nextFile = {
|
|
85
|
+
entries: state.entries,
|
|
86
|
+
version: REGISTRY_VERSION,
|
|
87
|
+
};
|
|
88
|
+
await atomicWriteRegistry(paths.registryFile, serializeRegistry(nextFile));
|
|
89
|
+
}
|
|
90
|
+
return { kind: OK_KIND, value };
|
|
91
|
+
});
|
|
92
|
+
if (!lockResult.ok) {
|
|
93
|
+
return lockResult;
|
|
94
|
+
}
|
|
95
|
+
const inner = lockResult.value;
|
|
96
|
+
if (inner.kind === LOAD_ERROR_KIND) {
|
|
97
|
+
return err(inner.error);
|
|
98
|
+
}
|
|
99
|
+
return { ok: true, value: inner.value };
|
|
100
|
+
}
|
|
101
|
+
//# sourceMappingURL=storage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"storage.js","sourceRoot":"","sources":["../../src/registry/storage.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { AllocationKey } from '../worktree/key.ts';
|
|
2
|
+
export type { AllocationKey };
|
|
3
|
+
export interface RegistryEntry {
|
|
4
|
+
readonly key: AllocationKey;
|
|
5
|
+
readonly lastUsedAt: string;
|
|
6
|
+
readonly namespace: string;
|
|
7
|
+
readonly ports: Readonly<Record<string, number>>;
|
|
8
|
+
}
|
|
9
|
+
export interface RegistryFile {
|
|
10
|
+
readonly entries: readonly RegistryEntry[];
|
|
11
|
+
readonly version: 1;
|
|
12
|
+
}
|
|
13
|
+
export declare const REGISTRY_VERSION: 1;
|
|
14
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/registry/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AAEvD,YAAY,EAAE,aAAa,EAAE,CAAA;AAE7B,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,GAAG,EAAE,aAAa,CAAA;IAC3B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;IAC3B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAA;CACjD;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,OAAO,EAAE,SAAS,aAAa,EAAE,CAAA;IAC1C,QAAQ,CAAC,OAAO,EAAE,CAAC,CAAA;CACpB;AAED,eAAO,MAAM,gBAAgB,EAAG,CAAU,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/registry/types.ts"],"names":[],"mappings":"AAgBA,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAU,CAAA"}
|
package/dist/result.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export declare function andThen<T, U, E>(result: Result<T, E>, fn: (value: T) => Result<U, E>): Result<U, E>;
|
|
2
|
+
export declare const err: <E>(error: E) => Result<never, E>;
|
|
3
|
+
export declare const ok: <T>(value: T) => Result<T, never>;
|
|
4
|
+
export type Result<T, E> = {
|
|
5
|
+
error: E;
|
|
6
|
+
ok: false;
|
|
7
|
+
} | {
|
|
8
|
+
ok: true;
|
|
9
|
+
value: T;
|
|
10
|
+
};
|
|
11
|
+
//# sourceMappingURL=result.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"result.d.ts","sourceRoot":"","sources":["../src/result.ts"],"names":[],"mappings":"AAAA,wBAAgB,OAAO,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAC7B,MAAM,EAAE,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,EACpB,EAAE,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,GAC7B,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,CAEd;AAED,eAAO,MAAM,GAAG,GAAI,CAAC,EAAE,OAAO,CAAC,KAAG,MAAM,CAAC,KAAK,EAAE,CAAC,CAA2B,CAAA;AAE5E,eAAO,MAAM,EAAE,GAAI,CAAC,EAAE,OAAO,CAAC,KAAG,MAAM,CAAC,CAAC,EAAE,KAAK,CAA0B,CAAA;AAE1E,MAAM,MAAM,MAAM,CAAC,CAAC,EAAE,CAAC,IAAI;IAAE,KAAK,EAAE,CAAC,CAAC;IAAC,EAAE,EAAE,KAAK,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,KAAK,EAAE,CAAC,CAAA;CAAE,CAAA"}
|
package/dist/result.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"result.js","sourceRoot":"","sources":["../src/result.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,OAAO,CACrB,MAAoB,EACpB,EAA8B;IAE9B,OAAO,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAA;AAC9C,CAAC;AAED,MAAM,CAAC,MAAM,GAAG,GAAG,CAAI,KAAQ,EAAoB,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC,CAAA;AAE5E,MAAM,CAAC,MAAM,EAAE,GAAG,CAAI,KAAQ,EAAoB,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAA"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Error passthrough contract for the runtime library.
|
|
3
|
+
*
|
|
4
|
+
* The runtime functions pass upstream errors through to the caller unchanged —
|
|
5
|
+
* the `code` and `message` from the originating module reach the top-level
|
|
6
|
+
* `Result.error` without wrapping. This module documents and re-exports the
|
|
7
|
+
* error codes the runtime can surface, so callers can dispatch on them.
|
|
8
|
+
*
|
|
9
|
+
* See .ai/specs/library-runtime/library-runtime.md §Error handling for the
|
|
10
|
+
* full error table.
|
|
11
|
+
*
|
|
12
|
+
* Module note: structure:check pairs every `*.test.ts` with a sibling source
|
|
13
|
+
* file. `error-passthrough.test.ts` (which asserts the passthrough contract)
|
|
14
|
+
* pairs with this file. The re-exports are intentionally thin — the canonical
|
|
15
|
+
* definitions live in `../errors.ts`. This module is listed in `knip.json`'s
|
|
16
|
+
* `ignoreExportsUsedInFile` because its exports are only consumed by the
|
|
17
|
+
* sibling test.
|
|
18
|
+
*/
|
|
19
|
+
export { PortweaveError, type PortweaveErrorCode, PW_ERROR_CODES, } from '../errors.ts';
|
|
20
|
+
//# sourceMappingURL=error-passthrough.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"error-passthrough.d.ts","sourceRoot":"","sources":["../../src/runtime/error-passthrough.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AACH,OAAO,EACL,cAAc,EACd,KAAK,kBAAkB,EACvB,cAAc,GACf,MAAM,cAAc,CAAA"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Error passthrough contract for the runtime library.
|
|
3
|
+
*
|
|
4
|
+
* The runtime functions pass upstream errors through to the caller unchanged —
|
|
5
|
+
* the `code` and `message` from the originating module reach the top-level
|
|
6
|
+
* `Result.error` without wrapping. This module documents and re-exports the
|
|
7
|
+
* error codes the runtime can surface, so callers can dispatch on them.
|
|
8
|
+
*
|
|
9
|
+
* See .ai/specs/library-runtime/library-runtime.md §Error handling for the
|
|
10
|
+
* full error table.
|
|
11
|
+
*
|
|
12
|
+
* Module note: structure:check pairs every `*.test.ts` with a sibling source
|
|
13
|
+
* file. `error-passthrough.test.ts` (which asserts the passthrough contract)
|
|
14
|
+
* pairs with this file. The re-exports are intentionally thin — the canonical
|
|
15
|
+
* definitions live in `../errors.ts`. This module is listed in `knip.json`'s
|
|
16
|
+
* `ignoreExportsUsedInFile` because its exports are only consumed by the
|
|
17
|
+
* sibling test.
|
|
18
|
+
*/
|
|
19
|
+
export { PortweaveError, PW_ERROR_CODES, } from "../errors.js";
|
|
20
|
+
//# sourceMappingURL=error-passthrough.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"error-passthrough.js","sourceRoot":"","sources":["../../src/runtime/error-passthrough.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AACH,OAAO,EACL,cAAc,EAEd,cAAc,GACf,MAAM,cAAc,CAAA"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export declare const FIXTURE_CONSUMER_CONFIG: string;
|
|
2
|
+
export declare function makeConsumerProject(consumerDir: string, packFile: string): Promise<void>;
|
|
3
|
+
export declare function makeTmpSmokeDir(label: string): Promise<string>;
|
|
4
|
+
//# sourceMappingURL=exports-smoke.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"exports-smoke.d.ts","sourceRoot":"","sources":["../../src/runtime/exports-smoke.ts"],"names":[],"mappings":"AAgBA,eAAO,MAAM,uBAAuB,QAElC,CAAA;AAEF,wBAAsB,mBAAmB,CACvC,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,IAAI,CAAC,CAkBf;AAED,wBAAsB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAIpE"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Utilities for the exports smoke test. These helpers create a minimal
|
|
3
|
+
* consumer project that installs portweave from a local pack file, then
|
|
4
|
+
* verifies that `import { ports } from 'portweave/runtime'` resolves correctly.
|
|
5
|
+
*
|
|
6
|
+
* Kept as a named module so the structure:check tooling can pair it with
|
|
7
|
+
* `exports-smoke.test.ts`.
|
|
8
|
+
*/
|
|
9
|
+
import { execFile } from 'node:child_process';
|
|
10
|
+
import { mkdtemp, writeFile } from 'node:fs/promises';
|
|
11
|
+
import { tmpdir } from 'node:os';
|
|
12
|
+
import { join } from 'node:path';
|
|
13
|
+
import { promisify } from 'node:util';
|
|
14
|
+
const execFileAsync = promisify(execFile);
|
|
15
|
+
export const FIXTURE_CONSUMER_CONFIG = JSON.stringify({
|
|
16
|
+
services: { api: { envVar: 'API_PORT' } },
|
|
17
|
+
});
|
|
18
|
+
export async function makeConsumerProject(consumerDir, packFile) {
|
|
19
|
+
await writeFile(join(consumerDir, 'package.json'), JSON.stringify({
|
|
20
|
+
dependencies: { portweave: `file:${packFile}` },
|
|
21
|
+
name: 'smoke-consumer',
|
|
22
|
+
type: 'module',
|
|
23
|
+
version: '0.0.0',
|
|
24
|
+
}));
|
|
25
|
+
await execFileAsync('npm', ['install', '--prefer-offline', '--no-audit'], {
|
|
26
|
+
cwd: consumerDir,
|
|
27
|
+
env: { ...process.env, NODE_ENV: 'test' },
|
|
28
|
+
});
|
|
29
|
+
await writeFile(join(consumerDir, 'portweave.config.json'), FIXTURE_CONSUMER_CONFIG);
|
|
30
|
+
}
|
|
31
|
+
export async function makeTmpSmokeDir(label) {
|
|
32
|
+
// Use mkdtemp to guarantee uniqueness; pid + Date.now() leaves a theoretical
|
|
33
|
+
// collision window under concurrent runs.
|
|
34
|
+
return mkdtemp(join(tmpdir(), `portweave-smoke-${label}-`));
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=exports-smoke.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"exports-smoke.js","sourceRoot":"","sources":["../../src/runtime/exports-smoke.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAA;AAC7C,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAA;AACrD,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAA;AAChC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAChC,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAA;AAErC,MAAM,aAAa,GAAG,SAAS,CAAC,QAAQ,CAAC,CAAA;AAEzC,MAAM,CAAC,MAAM,uBAAuB,GAAG,IAAI,CAAC,SAAS,CAAC;IACpD,QAAQ,EAAE,EAAE,GAAG,EAAE,EAAE,MAAM,EAAE,UAAU,EAAE,EAAE;CAC1C,CAAC,CAAA;AAEF,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,WAAmB,EACnB,QAAgB;IAEhB,MAAM,SAAS,CACb,IAAI,CAAC,WAAW,EAAE,cAAc,CAAC,EACjC,IAAI,CAAC,SAAS,CAAC;QACb,YAAY,EAAE,EAAE,SAAS,EAAE,QAAQ,QAAQ,EAAE,EAAE;QAC/C,IAAI,EAAE,gBAAgB;QACtB,IAAI,EAAE,QAAQ;QACd,OAAO,EAAE,OAAO;KACjB,CAAC,CACH,CAAA;IACD,MAAM,aAAa,CAAC,KAAK,EAAE,CAAC,SAAS,EAAE,kBAAkB,EAAE,YAAY,CAAC,EAAE;QACxE,GAAG,EAAE,WAAW;QAChB,GAAG,EAAE,EAAE,GAAG,OAAO,CAAC,GAAG,EAAE,QAAQ,EAAE,MAAM,EAAE;KAC1C,CAAC,CAAA;IACF,MAAM,SAAS,CACb,IAAI,CAAC,WAAW,EAAE,uBAAuB,CAAC,EAC1C,uBAAuB,CACxB,CAAA;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,KAAa;IACjD,6EAA6E;IAC7E,0CAA0C;IAC1C,OAAO,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,mBAAmB,KAAK,GAAG,CAAC,CAAC,CAAA;AAC7D,CAAC"}
|