@microwiseai/snapshot 0.5.0 → 0.5.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/dist/commands/install.d.ts.map +1 -1
- package/dist/commands/install.js +195 -34
- package/dist/commands/install.js.map +1 -1
- package/dist/commands/preflight.d.ts +31 -0
- package/dist/commands/preflight.d.ts.map +1 -0
- package/dist/commands/preflight.js +83 -0
- package/dist/commands/preflight.js.map +1 -0
- package/dist/commands/publish.d.ts +4 -0
- package/dist/commands/publish.d.ts.map +1 -1
- package/dist/commands/publish.js +35 -1
- package/dist/commands/publish.js.map +1 -1
- package/dist/index.js +13 -0
- package/dist/index.js.map +1 -1
- package/dist/lib/distkit-closure-bridge.d.ts +102 -0
- package/dist/lib/distkit-closure-bridge.d.ts.map +1 -0
- package/dist/lib/distkit-closure-bridge.js +177 -0
- package/dist/lib/distkit-closure-bridge.js.map +1 -0
- package/dist/lib/distkit-closure-parity.d.ts +110 -0
- package/dist/lib/distkit-closure-parity.d.ts.map +1 -0
- package/dist/lib/distkit-closure-parity.js +134 -0
- package/dist/lib/distkit-closure-parity.js.map +1 -0
- package/dist/lib/distkit-routing-port.d.ts +37 -0
- package/dist/lib/distkit-routing-port.d.ts.map +1 -0
- package/dist/lib/distkit-routing-port.js +72 -0
- package/dist/lib/distkit-routing-port.js.map +1 -0
- package/dist/lib/install-timeline.d.ts +81 -0
- package/dist/lib/install-timeline.d.ts.map +1 -0
- package/dist/lib/install-timeline.js +243 -0
- package/dist/lib/install-timeline.js.map +1 -0
- package/dist/lib/preflight-adapter.d.ts +52 -0
- package/dist/lib/preflight-adapter.d.ts.map +1 -0
- package/dist/lib/preflight-adapter.js +224 -0
- package/dist/lib/preflight-adapter.js.map +1 -0
- package/dist/lib/transitive-resolver.d.ts +121 -0
- package/dist/lib/transitive-resolver.d.ts.map +1 -1
- package/dist/lib/transitive-resolver.js +190 -0
- package/dist/lib/transitive-resolver.js.map +1 -1
- package/node_modules/@gitdot/clone-lib/README.md +117 -0
- package/node_modules/@gitdot/clone-lib/dist/bin/gitdot-resolve.d.ts +9 -0
- package/node_modules/@gitdot/clone-lib/dist/bin/gitdot-resolve.d.ts.map +1 -0
- package/node_modules/@gitdot/clone-lib/dist/bin/gitdot-resolve.js +154 -0
- package/node_modules/@gitdot/clone-lib/dist/bin/gitdot-resolve.js.map +1 -0
- package/node_modules/@gitdot/clone-lib/dist/clone.d.ts +21 -0
- package/node_modules/@gitdot/clone-lib/dist/clone.d.ts.map +1 -0
- package/node_modules/@gitdot/clone-lib/dist/clone.js +228 -0
- package/node_modules/@gitdot/clone-lib/dist/clone.js.map +1 -0
- package/node_modules/@gitdot/clone-lib/dist/dotpath.d.ts +10 -0
- package/node_modules/@gitdot/clone-lib/dist/dotpath.d.ts.map +1 -0
- package/node_modules/@gitdot/clone-lib/dist/dotpath.js +27 -0
- package/node_modules/@gitdot/clone-lib/dist/dotpath.js.map +1 -0
- package/node_modules/@gitdot/clone-lib/dist/git.d.ts +23 -0
- package/node_modules/@gitdot/clone-lib/dist/git.d.ts.map +1 -0
- package/node_modules/@gitdot/clone-lib/dist/git.js +134 -0
- package/node_modules/@gitdot/clone-lib/dist/git.js.map +1 -0
- package/node_modules/@gitdot/clone-lib/dist/index.d.ts +17 -0
- package/node_modules/@gitdot/clone-lib/dist/index.d.ts.map +1 -0
- package/node_modules/@gitdot/clone-lib/dist/index.js +35 -0
- package/node_modules/@gitdot/clone-lib/dist/index.js.map +1 -0
- package/node_modules/@gitdot/clone-lib/dist/lock.d.ts +24 -0
- package/node_modules/@gitdot/clone-lib/dist/lock.d.ts.map +1 -0
- package/node_modules/@gitdot/clone-lib/dist/lock.js +97 -0
- package/node_modules/@gitdot/clone-lib/dist/lock.js.map +1 -0
- package/node_modules/@gitdot/clone-lib/dist/resolve/gitlab.d.ts +15 -0
- package/node_modules/@gitdot/clone-lib/dist/resolve/gitlab.d.ts.map +1 -0
- package/node_modules/@gitdot/clone-lib/dist/resolve/gitlab.js +124 -0
- package/node_modules/@gitdot/clone-lib/dist/resolve/gitlab.js.map +1 -0
- package/node_modules/@gitdot/clone-lib/dist/resolve/index.d.ts +12 -0
- package/node_modules/@gitdot/clone-lib/dist/resolve/index.d.ts.map +1 -0
- package/node_modules/@gitdot/clone-lib/dist/resolve/index.js +31 -0
- package/node_modules/@gitdot/clone-lib/dist/resolve/index.js.map +1 -0
- package/node_modules/@gitdot/clone-lib/dist/resolve/manifest.d.ts +32 -0
- package/node_modules/@gitdot/clone-lib/dist/resolve/manifest.d.ts.map +1 -0
- package/node_modules/@gitdot/clone-lib/dist/resolve/manifest.js +159 -0
- package/node_modules/@gitdot/clone-lib/dist/resolve/manifest.js.map +1 -0
- package/node_modules/@gitdot/clone-lib/dist/resolve/member.d.ts +44 -0
- package/node_modules/@gitdot/clone-lib/dist/resolve/member.d.ts.map +1 -0
- package/node_modules/@gitdot/clone-lib/dist/resolve/member.js +163 -0
- package/node_modules/@gitdot/clone-lib/dist/resolve/member.js.map +1 -0
- package/node_modules/@gitdot/clone-lib/dist/resolve/resolve.d.ts +18 -0
- package/node_modules/@gitdot/clone-lib/dist/resolve/resolve.d.ts.map +1 -0
- package/node_modules/@gitdot/clone-lib/dist/resolve/resolve.js +155 -0
- package/node_modules/@gitdot/clone-lib/dist/resolve/resolve.js.map +1 -0
- package/node_modules/@gitdot/clone-lib/dist/types.d.ts +225 -0
- package/node_modules/@gitdot/clone-lib/dist/types.d.ts.map +1 -0
- package/node_modules/@gitdot/clone-lib/dist/types.js +9 -0
- package/node_modules/@gitdot/clone-lib/dist/types.js.map +1 -0
- package/node_modules/@gitdot/clone-lib/package.json +53 -0
- package/node_modules/@microwiseai/install-preflight/dist/index.d.ts +27 -0
- package/node_modules/@microwiseai/install-preflight/dist/index.d.ts.map +1 -0
- package/node_modules/@microwiseai/install-preflight/dist/index.js +26 -0
- package/node_modules/@microwiseai/install-preflight/dist/index.js.map +1 -0
- package/node_modules/@microwiseai/install-preflight/dist/policy.d.ts +42 -0
- package/node_modules/@microwiseai/install-preflight/dist/policy.d.ts.map +1 -0
- package/node_modules/@microwiseai/install-preflight/dist/policy.js +79 -0
- package/node_modules/@microwiseai/install-preflight/dist/policy.js.map +1 -0
- package/node_modules/@microwiseai/install-preflight/dist/preflight.d.ts +18 -0
- package/node_modules/@microwiseai/install-preflight/dist/preflight.d.ts.map +1 -0
- package/node_modules/@microwiseai/install-preflight/dist/preflight.js +0 -0
- package/node_modules/@microwiseai/install-preflight/dist/preflight.js.map +1 -0
- package/node_modules/@microwiseai/install-preflight/dist/resolvers.d.ts +26 -0
- package/node_modules/@microwiseai/install-preflight/dist/resolvers.d.ts.map +1 -0
- package/node_modules/@microwiseai/install-preflight/dist/resolvers.js +63 -0
- package/node_modules/@microwiseai/install-preflight/dist/resolvers.js.map +1 -0
- package/node_modules/@microwiseai/install-preflight/dist/semver.d.ts +45 -0
- package/node_modules/@microwiseai/install-preflight/dist/semver.d.ts.map +1 -0
- package/node_modules/@microwiseai/install-preflight/dist/semver.js +195 -0
- package/node_modules/@microwiseai/install-preflight/dist/semver.js.map +1 -0
- package/node_modules/@microwiseai/install-preflight/dist/types.d.ts +136 -0
- package/node_modules/@microwiseai/install-preflight/dist/types.d.ts.map +1 -0
- package/node_modules/@microwiseai/install-preflight/dist/types.js +11 -0
- package/node_modules/@microwiseai/install-preflight/dist/types.js.map +1 -0
- package/node_modules/@microwiseai/install-preflight/package.json +49 -0
- package/package.json +12 -4
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ============================================================================
|
|
3
|
+
* Phase-2b §1.2/§1.3 (decision A) — production scope-routing PackumentPort
|
|
4
|
+
* ============================================================================
|
|
5
|
+
*
|
|
6
|
+
* Decision A (owner-confirmed): distkit resolves the npm closure CLIENT-SIDE with
|
|
7
|
+
* PER-SCOPE registry routing. A real closure mixes lanes — PRIVATE roots/deps
|
|
8
|
+
* (`@ist/*`, `@microwiseai/*` … the snapshot's registry scopes) served by our
|
|
9
|
+
* proxy (+ session token), and PUBLIC transitive deps (`semver`, `commander`, …)
|
|
10
|
+
* served by npmjs (token-less). distkit's npm adapter takes ONE PackumentPort, so
|
|
11
|
+
* this port DISPATCHES per package name to the right registry.
|
|
12
|
+
*
|
|
13
|
+
* ★ TOKEN ISOLATION (C1 — the whole point): the two lanes are SEPARATE
|
|
14
|
+
* {@link createFetchPackumentPort} instances. The public port is constructed
|
|
15
|
+
* WITHOUT a token, so `createFetchPackumentPort` never attaches an
|
|
16
|
+
* `Authorization` header to an npmjs read — it is structurally impossible for
|
|
17
|
+
* the license/session token to leak to npmjs. Only the private port carries the
|
|
18
|
+
* Bearer token.
|
|
19
|
+
* ★ FAIL-LOUD (§1.4): each sub-port surfaces a non-2xx as `PackumentResolutionError`
|
|
20
|
+
* (an unentitled private read → 401 → throw). This port adds NO catch — a miss
|
|
21
|
+
* propagates; it NEVER silently degrades to a public read for a private name.
|
|
22
|
+
*/
|
|
23
|
+
import { NPMJS_PUBLIC_REGISTRY_URL } from '@microwiseai/distkit';
|
|
24
|
+
import { createFetchPackumentPort } from '@microwiseai/distkit/adapters';
|
|
25
|
+
/**
|
|
26
|
+
* True iff `name` belongs to one of the PRIVATE scopes (the snapshot's registry
|
|
27
|
+
* scope-map keys, e.g. `@ist`, `@microwiseai`). A private name routes to the
|
|
28
|
+
* proxy (+ token); everything else is PUBLIC (npmjs, token-less).
|
|
29
|
+
*
|
|
30
|
+
* ★ Task-5 / ADR 0003 (ecosystem-neutral identity): `scope` here is an
|
|
31
|
+
* npm-adapter-LOCAL projection — the private/public LANE selector for the npm
|
|
32
|
+
* closure — NOT a core identity axis. It carries no npm privilege: any name not
|
|
33
|
+
* in `privateScopes` (an unscoped-npm public dep AND a pypi-style name alike) is
|
|
34
|
+
* uniformly PUBLIC. The core (group, name) identity is delegated downstream to
|
|
35
|
+
* distkit's `resolveManifestToLock` / `resolvePackageOriginByIdentity`, and the
|
|
36
|
+
* emitted lock keys on (name, group) — never on scope.
|
|
37
|
+
*/
|
|
38
|
+
export function isPrivateScope(name, privateScopes) {
|
|
39
|
+
return privateScopes.some((s) => {
|
|
40
|
+
const scope = s.endsWith('/') ? s.slice(0, -1) : s;
|
|
41
|
+
return name === scope || name.startsWith(`${scope}/`);
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Build a {@link PackumentPort} that routes each `fetchPackument(name)` to the
|
|
46
|
+
* proxy (private, tokened) or npmjs (public, token-less) by scope. Plug into
|
|
47
|
+
* `createNpmAdapter(port)`.
|
|
48
|
+
*/
|
|
49
|
+
export function createScopeRoutingPackumentPort(opts) {
|
|
50
|
+
// PRIVATE lane — proxy + Bearer token (guardrail 1).
|
|
51
|
+
const privatePort = createFetchPackumentPort({
|
|
52
|
+
registryUrl: opts.proxyUrl,
|
|
53
|
+
token: opts.token,
|
|
54
|
+
fetchImpl: opts.fetchImpl,
|
|
55
|
+
timeoutMs: opts.timeoutMs,
|
|
56
|
+
});
|
|
57
|
+
// PUBLIC lane — npmjs, NO token passed (guardrail 2 / C1). Token isolation by
|
|
58
|
+
// construction: this port has no credential to send.
|
|
59
|
+
const publicPort = createFetchPackumentPort({
|
|
60
|
+
registryUrl: opts.npmjsUrl ?? NPMJS_PUBLIC_REGISTRY_URL,
|
|
61
|
+
fetchImpl: opts.fetchImpl,
|
|
62
|
+
timeoutMs: opts.timeoutMs,
|
|
63
|
+
});
|
|
64
|
+
return {
|
|
65
|
+
fetchPackument(name) {
|
|
66
|
+
return isPrivateScope(name, opts.privateScopes)
|
|
67
|
+
? privatePort.fetchPackument(name)
|
|
68
|
+
: publicPort.fetchPackument(name);
|
|
69
|
+
},
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
//# sourceMappingURL=distkit-routing-port.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"distkit-routing-port.js","sourceRoot":"","sources":["../../src/lib/distkit-routing-port.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,OAAO,EAAE,yBAAyB,EAAE,MAAM,sBAAsB,CAAC;AACjE,OAAO,EAAE,wBAAwB,EAAsB,MAAM,+BAA+B,CAAC;AAE7F;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,cAAc,CAAC,IAAY,EAAE,aAAgC;IAC3E,OAAO,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE;QAC9B,MAAM,KAAK,GAAG,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACnD,OAAO,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,KAAK,GAAG,CAAC,CAAC;IACxD,CAAC,CAAC,CAAC;AACL,CAAC;AAkBD;;;;GAIG;AACH,MAAM,UAAU,+BAA+B,CAAC,IAA6B;IAC3E,qDAAqD;IACrD,MAAM,WAAW,GAAG,wBAAwB,CAAC;QAC3C,WAAW,EAAE,IAAI,CAAC,QAAQ;QAC1B,KAAK,EAAE,IAAI,CAAC,KAAK;QACjB,SAAS,EAAE,IAAI,CAAC,SAAS;QACzB,SAAS,EAAE,IAAI,CAAC,SAAS;KAC1B,CAAC,CAAC;IACH,8EAA8E;IAC9E,qDAAqD;IACrD,MAAM,UAAU,GAAG,wBAAwB,CAAC;QAC1C,WAAW,EAAE,IAAI,CAAC,QAAQ,IAAI,yBAAyB;QACvD,SAAS,EAAE,IAAI,CAAC,SAAS;QACzB,SAAS,EAAE,IAAI,CAAC,SAAS;KAC1B,CAAC,CAAC;IAEH,OAAO;QACL,cAAc,CAAC,IAAY;YACzB,OAAO,cAAc,CAAC,IAAI,EAAE,IAAI,CAAC,aAAa,CAAC;gBAC7C,CAAC,CAAC,WAAW,CAAC,cAAc,CAAC,IAAI,CAAC;gBAClC,CAAC,CAAC,UAAU,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC;QACtC,CAAC;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* install-timeline.ts — Install timeline instrumentation (investigation only).
|
|
3
|
+
*
|
|
4
|
+
* Purpose: measure WHY a snapshot install is slow, from the inside, without
|
|
5
|
+
* changing any install behavior. Purely additive: when the opt-in env flag is
|
|
6
|
+
* unset the whole thing is a no-op with negligible overhead — every `start()`
|
|
7
|
+
* returns one shared no-op handle and `finalize()` returns immediately.
|
|
8
|
+
*
|
|
9
|
+
* Opt-in: SNAPSHOT_INSTALL_TIMELINE ∈ {'1','true'} (case-insensitive).
|
|
10
|
+
*
|
|
11
|
+
* Output when enabled:
|
|
12
|
+
* (a) console phase-summary table with relative [+Xs] offsets, per-phase
|
|
13
|
+
* durations, a `◄ dominant` marker on the largest phase, and per-command /
|
|
14
|
+
* per-package rows indented under their phase, then a total line.
|
|
15
|
+
* (b) JSONL file at ~/.ist/logs/snapshot-install-timeline/<ISO>.jsonl —
|
|
16
|
+
* one line per event + a trailing summary line, for cross-run diffing.
|
|
17
|
+
*
|
|
18
|
+
* Security (security-ssot-principle): tokens must NEVER be written. Command
|
|
19
|
+
* strings and meta are sanitized — IST_SESSION_TOKEN, authToken, _authToken=,
|
|
20
|
+
* and Bearer values are replaced with `***` before any record/print/write.
|
|
21
|
+
*/
|
|
22
|
+
export type TimelineCategory = 'phase' | 'command' | 'package';
|
|
23
|
+
export interface TimelineEvent {
|
|
24
|
+
label: string;
|
|
25
|
+
category: TimelineCategory;
|
|
26
|
+
/** Offset from timeline t0, in ms (span start). */
|
|
27
|
+
startOffsetMs: number;
|
|
28
|
+
/** Measured span duration, in ms (performance.now based). */
|
|
29
|
+
durationMs: number;
|
|
30
|
+
/** Wall-clock ISO timestamp of the span start (Date.now based). */
|
|
31
|
+
wallStartIso: string;
|
|
32
|
+
/** Label of the enclosing phase span, if any (for indentation/grouping). */
|
|
33
|
+
parentLabel?: string;
|
|
34
|
+
meta?: Record<string, unknown>;
|
|
35
|
+
}
|
|
36
|
+
export interface SpanHandle {
|
|
37
|
+
/** Close the span, recording its duration. Extra meta is merged in. */
|
|
38
|
+
end(meta?: Record<string, unknown>): void;
|
|
39
|
+
}
|
|
40
|
+
export interface StartOptions {
|
|
41
|
+
category?: TimelineCategory;
|
|
42
|
+
meta?: Record<string, unknown>;
|
|
43
|
+
}
|
|
44
|
+
export interface InstallTimelineOptions {
|
|
45
|
+
/** Force enable/disable. When omitted, decided from env opt-in flag. */
|
|
46
|
+
enabled?: boolean;
|
|
47
|
+
/** Env source (default: process.env). */
|
|
48
|
+
env?: Record<string, string | undefined>;
|
|
49
|
+
/** Monotonic clock in ms (default: performance.now). Injectable for tests. */
|
|
50
|
+
now?: () => number;
|
|
51
|
+
/** Wall clock in ms (default: Date.now). Injectable for tests. */
|
|
52
|
+
wallNow?: () => number;
|
|
53
|
+
/** Directory for JSONL logs (default: ~/.ist/logs/snapshot-install-timeline). */
|
|
54
|
+
logDir?: string;
|
|
55
|
+
/** Console sink (default: console.log). Injectable for tests. */
|
|
56
|
+
logger?: (line: string) => void;
|
|
57
|
+
/** Directory creator (default: mkdirSync -p). Injectable for tests. */
|
|
58
|
+
mkdir?: (dir: string) => void;
|
|
59
|
+
/** File writer (default: writeFileSync). Injectable for tests. */
|
|
60
|
+
writeFile?: (path: string, content: string) => void;
|
|
61
|
+
}
|
|
62
|
+
/** Redact token material from an arbitrary string. */
|
|
63
|
+
export declare function sanitizeString(input: string, env?: Record<string, string | undefined>): string;
|
|
64
|
+
/** Deep-sanitize a meta object: scrub string values and redact suspicious keys. */
|
|
65
|
+
export declare function sanitizeMeta(meta: Record<string, unknown> | undefined, env?: Record<string, string | undefined>): Record<string, unknown> | undefined;
|
|
66
|
+
export interface InstallTimeline {
|
|
67
|
+
readonly enabled: boolean;
|
|
68
|
+
start(label: string, opts?: StartOptions): SpanHandle;
|
|
69
|
+
finalize(): void;
|
|
70
|
+
/** Read recorded events (for tests / introspection). */
|
|
71
|
+
getEvents(): TimelineEvent[];
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Decide enablement from the opt-in env flag (unless explicitly overridden).
|
|
75
|
+
*/
|
|
76
|
+
export declare function isTimelineEnabled(env?: Record<string, string | undefined>): boolean;
|
|
77
|
+
/**
|
|
78
|
+
* Factory: returns an active timeline when opted-in, else a zero-overhead no-op.
|
|
79
|
+
*/
|
|
80
|
+
export declare function createInstallTimeline(opts?: InstallTimelineOptions): InstallTimeline;
|
|
81
|
+
//# sourceMappingURL=install-timeline.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"install-timeline.d.ts","sourceRoot":"","sources":["../../src/lib/install-timeline.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAOH,MAAM,MAAM,gBAAgB,GAAG,OAAO,GAAG,SAAS,GAAG,SAAS,CAAC;AAE/D,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,gBAAgB,CAAC;IAC3B,mDAAmD;IACnD,aAAa,EAAE,MAAM,CAAC;IACtB,6DAA6D;IAC7D,UAAU,EAAE,MAAM,CAAC;IACnB,mEAAmE;IACnE,YAAY,EAAE,MAAM,CAAC;IACrB,4EAA4E;IAC5E,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAChC;AAED,MAAM,WAAW,UAAU;IACzB,uEAAuE;IACvE,GAAG,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;CAC3C;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,EAAE,gBAAgB,CAAC;IAC5B,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAChC;AAED,MAAM,WAAW,sBAAsB;IACrC,wEAAwE;IACxE,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,yCAAyC;IACzC,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;IACzC,8EAA8E;IAC9E,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;IACnB,kEAAkE;IAClE,OAAO,CAAC,EAAE,MAAM,MAAM,CAAC;IACvB,iFAAiF;IACjF,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,iEAAiE;IACjE,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAChC,uEAAuE;IACvE,KAAK,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IAC9B,kEAAkE;IAClE,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;CACrD;AAiBD,sDAAsD;AACtD,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,GAAG,MAAM,CAkB9F;AAED,mFAAmF;AACnF,wBAAgB,YAAY,CAC1B,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,EACzC,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,GACvC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAGrC;AAuBD,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,YAAY,GAAG,UAAU,CAAC;IACtD,QAAQ,IAAI,IAAI,CAAC;IACjB,wDAAwD;IACxD,SAAS,IAAI,aAAa,EAAE,CAAC;CAC9B;AAyLD;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAe,GAAG,OAAO,CAGhG;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,GAAE,sBAA2B,GAAG,eAAe,CAGxF"}
|
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* install-timeline.ts — Install timeline instrumentation (investigation only).
|
|
3
|
+
*
|
|
4
|
+
* Purpose: measure WHY a snapshot install is slow, from the inside, without
|
|
5
|
+
* changing any install behavior. Purely additive: when the opt-in env flag is
|
|
6
|
+
* unset the whole thing is a no-op with negligible overhead — every `start()`
|
|
7
|
+
* returns one shared no-op handle and `finalize()` returns immediately.
|
|
8
|
+
*
|
|
9
|
+
* Opt-in: SNAPSHOT_INSTALL_TIMELINE ∈ {'1','true'} (case-insensitive).
|
|
10
|
+
*
|
|
11
|
+
* Output when enabled:
|
|
12
|
+
* (a) console phase-summary table with relative [+Xs] offsets, per-phase
|
|
13
|
+
* durations, a `◄ dominant` marker on the largest phase, and per-command /
|
|
14
|
+
* per-package rows indented under their phase, then a total line.
|
|
15
|
+
* (b) JSONL file at ~/.ist/logs/snapshot-install-timeline/<ISO>.jsonl —
|
|
16
|
+
* one line per event + a trailing summary line, for cross-run diffing.
|
|
17
|
+
*
|
|
18
|
+
* Security (security-ssot-principle): tokens must NEVER be written. Command
|
|
19
|
+
* strings and meta are sanitized — IST_SESSION_TOKEN, authToken, _authToken=,
|
|
20
|
+
* and Bearer values are replaced with `***` before any record/print/write.
|
|
21
|
+
*/
|
|
22
|
+
import { performance } from 'node:perf_hooks';
|
|
23
|
+
import { homedir } from 'node:os';
|
|
24
|
+
import { join } from 'node:path';
|
|
25
|
+
import { mkdirSync, writeFileSync } from 'node:fs';
|
|
26
|
+
const ENABLE_VALUES = new Set(['1', 'true']);
|
|
27
|
+
/** Shared no-op handle — one allocation, reused for every disabled span. */
|
|
28
|
+
const NOOP_SPAN = { end() { } };
|
|
29
|
+
// ----------------------------------------------------------------------------
|
|
30
|
+
// Sanitization (security-ssot-principle): never emit a real token.
|
|
31
|
+
// ----------------------------------------------------------------------------
|
|
32
|
+
// Keys whose VALUE is credential material and must be redacted wholesale.
|
|
33
|
+
// Deliberately NOT a bare "auth" match: `authType` ('proxy-token'|'anonymous')
|
|
34
|
+
// is a useful, non-secret diagnostic and must survive. `authToken` still matches
|
|
35
|
+
// via "token".
|
|
36
|
+
const SUSPICIOUS_KEY = /(token|secret|password|bearer|credential|apikey)/i;
|
|
37
|
+
/** Redact token material from an arbitrary string. */
|
|
38
|
+
export function sanitizeString(input, env) {
|
|
39
|
+
let out = input;
|
|
40
|
+
// key=value / key: value forms for known token-bearing keys.
|
|
41
|
+
out = out.replace(/(_authToken\s*=\s*)[^\s&'"]+/gi, '$1***');
|
|
42
|
+
out = out.replace(/(authToken["'\s]*[:=]\s*["']?)[^\s,'"&}]+/gi, '$1***');
|
|
43
|
+
out = out.replace(/(IST_SESSION_TOKEN["'\s]*[:=]\s*["']?)[^\s,'"&}]+/gi, '$1***');
|
|
44
|
+
// Bearer <token>
|
|
45
|
+
out = out.replace(/(Bearer\s+)[A-Za-z0-9._\-+/=]+/gi, '$1***');
|
|
46
|
+
// Belt-and-suspenders: scrub any literal occurrence of the actual token value
|
|
47
|
+
// that may have leaked into a command string via env interpolation.
|
|
48
|
+
const literal = (env ?? {})['IST_SESSION_TOKEN'];
|
|
49
|
+
if (literal && literal.length >= 8) {
|
|
50
|
+
out = out.split(literal).join('***');
|
|
51
|
+
}
|
|
52
|
+
return out;
|
|
53
|
+
}
|
|
54
|
+
/** Deep-sanitize a meta object: scrub string values and redact suspicious keys. */
|
|
55
|
+
export function sanitizeMeta(meta, env) {
|
|
56
|
+
if (!meta)
|
|
57
|
+
return undefined;
|
|
58
|
+
return sanitizeValue(meta, env);
|
|
59
|
+
}
|
|
60
|
+
function sanitizeValue(value, env) {
|
|
61
|
+
if (typeof value === 'string')
|
|
62
|
+
return sanitizeString(value, env);
|
|
63
|
+
if (Array.isArray(value))
|
|
64
|
+
return value.map((v) => sanitizeValue(v, env));
|
|
65
|
+
if (value && typeof value === 'object') {
|
|
66
|
+
const out = {};
|
|
67
|
+
for (const [k, v] of Object.entries(value)) {
|
|
68
|
+
if (SUSPICIOUS_KEY.test(k) && typeof v === 'string') {
|
|
69
|
+
out[k] = '***';
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
out[k] = sanitizeValue(v, env);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return out;
|
|
76
|
+
}
|
|
77
|
+
return value;
|
|
78
|
+
}
|
|
79
|
+
class NoopTimeline {
|
|
80
|
+
enabled = false;
|
|
81
|
+
start() {
|
|
82
|
+
return NOOP_SPAN;
|
|
83
|
+
}
|
|
84
|
+
finalize() { }
|
|
85
|
+
getEvents() {
|
|
86
|
+
return [];
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
class ActiveTimeline {
|
|
90
|
+
enabled = true;
|
|
91
|
+
now;
|
|
92
|
+
wallNow;
|
|
93
|
+
env;
|
|
94
|
+
logDir;
|
|
95
|
+
logger;
|
|
96
|
+
mkdir;
|
|
97
|
+
writeFile;
|
|
98
|
+
t0;
|
|
99
|
+
wallT0;
|
|
100
|
+
events = [];
|
|
101
|
+
/** Stack of currently-open phase labels (for parent association). */
|
|
102
|
+
phaseStack = [];
|
|
103
|
+
finalized = false;
|
|
104
|
+
constructor(opts) {
|
|
105
|
+
this.now = opts.now ?? (() => performance.now());
|
|
106
|
+
this.wallNow = opts.wallNow ?? (() => Date.now());
|
|
107
|
+
this.env = opts.env ?? process.env;
|
|
108
|
+
this.logDir =
|
|
109
|
+
opts.logDir ?? join(homedir(), '.ist', 'logs', 'snapshot-install-timeline');
|
|
110
|
+
this.logger = opts.logger ?? ((line) => console.log(line));
|
|
111
|
+
this.mkdir = opts.mkdir ?? ((dir) => mkdirSync(dir, { recursive: true }));
|
|
112
|
+
this.writeFile =
|
|
113
|
+
opts.writeFile ?? ((path, content) => writeFileSync(path, content));
|
|
114
|
+
this.t0 = this.now();
|
|
115
|
+
this.wallT0 = this.wallNow();
|
|
116
|
+
}
|
|
117
|
+
start(label, opts = {}) {
|
|
118
|
+
const category = opts.category ?? 'phase';
|
|
119
|
+
const startMono = this.now();
|
|
120
|
+
const startOffsetMs = startMono - this.t0;
|
|
121
|
+
const wallStartIso = new Date(this.wallT0 + startOffsetMs).toISOString();
|
|
122
|
+
// Parent = innermost currently-open phase (commands/packages nest under it).
|
|
123
|
+
const parentLabel = category === 'phase' ? undefined : this.phaseStack[this.phaseStack.length - 1];
|
|
124
|
+
// Sanitize the label too — callers pass raw command strings as labels
|
|
125
|
+
// (e.g. runCommand), which may embed token material.
|
|
126
|
+
const safeLabel = sanitizeString(label, this.env);
|
|
127
|
+
const event = {
|
|
128
|
+
label: safeLabel,
|
|
129
|
+
category,
|
|
130
|
+
startOffsetMs,
|
|
131
|
+
durationMs: 0,
|
|
132
|
+
wallStartIso,
|
|
133
|
+
parentLabel,
|
|
134
|
+
meta: sanitizeMeta(opts.meta, this.env),
|
|
135
|
+
};
|
|
136
|
+
this.events.push(event);
|
|
137
|
+
if (category === 'phase') {
|
|
138
|
+
this.phaseStack.push(label);
|
|
139
|
+
}
|
|
140
|
+
let ended = false;
|
|
141
|
+
return {
|
|
142
|
+
end: (endMeta) => {
|
|
143
|
+
if (ended)
|
|
144
|
+
return;
|
|
145
|
+
ended = true;
|
|
146
|
+
event.durationMs = this.now() - startMono;
|
|
147
|
+
if (endMeta) {
|
|
148
|
+
const clean = sanitizeMeta(endMeta, this.env);
|
|
149
|
+
event.meta = { ...(event.meta ?? {}), ...(clean ?? {}) };
|
|
150
|
+
}
|
|
151
|
+
if (category === 'phase') {
|
|
152
|
+
// Pop this phase if it is on top; tolerate out-of-order ends.
|
|
153
|
+
const idx = this.phaseStack.lastIndexOf(label);
|
|
154
|
+
if (idx !== -1)
|
|
155
|
+
this.phaseStack.splice(idx, 1);
|
|
156
|
+
}
|
|
157
|
+
},
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
getEvents() {
|
|
161
|
+
return this.events;
|
|
162
|
+
}
|
|
163
|
+
finalize() {
|
|
164
|
+
if (this.finalized)
|
|
165
|
+
return;
|
|
166
|
+
this.finalized = true;
|
|
167
|
+
const phases = this.events.filter((e) => e.category === 'phase');
|
|
168
|
+
const totalMs = phases.reduce((sum, p) => sum + p.durationMs, 0);
|
|
169
|
+
const dominant = phases.reduce((max, p) => (max === null || p.durationMs > max.durationMs ? p : max), null);
|
|
170
|
+
this.printConsole(phases, dominant, totalMs);
|
|
171
|
+
this.writeJsonl(dominant, totalMs);
|
|
172
|
+
}
|
|
173
|
+
printConsole(phases, dominant, totalMs) {
|
|
174
|
+
const log = this.logger;
|
|
175
|
+
log('');
|
|
176
|
+
log('━━━ Install Timeline (SNAPSHOT_INSTALL_TIMELINE) ━━━');
|
|
177
|
+
// Top-level = phases in start order, plus any orphan (parentless) non-phase.
|
|
178
|
+
const orphans = this.events.filter((e) => e.category !== 'phase' && !e.parentLabel);
|
|
179
|
+
const roots = [...phases, ...orphans].sort((a, b) => a.startOffsetMs - b.startOffsetMs);
|
|
180
|
+
const labelWidth = Math.max(20, ...this.events.map((e) => e.label.length + (e.category === 'phase' ? 0 : 2)));
|
|
181
|
+
for (const root of roots) {
|
|
182
|
+
const offset = `[+${(root.startOffsetMs / 1000).toFixed(1)}s]`;
|
|
183
|
+
const dur = `${Math.round(root.durationMs)}ms`;
|
|
184
|
+
const marker = dominant && root === dominant ? ' ◄ dominant' : '';
|
|
185
|
+
log(`${offset} ${root.label.padEnd(labelWidth)} ${dur.padStart(8)}${marker}`);
|
|
186
|
+
if (root.category === 'phase') {
|
|
187
|
+
const children = this.events
|
|
188
|
+
.filter((e) => e.parentLabel === root.label)
|
|
189
|
+
.sort((a, b) => a.startOffsetMs - b.startOffsetMs);
|
|
190
|
+
for (const child of children) {
|
|
191
|
+
const cdur = `${Math.round(child.durationMs)}ms`;
|
|
192
|
+
const tag = `${child.category}: ${child.label}`;
|
|
193
|
+
log(` ${tag.padEnd(labelWidth)} ${cdur.padStart(8)}`);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
log(` ${'total'.padEnd(labelWidth)} ${`${(totalMs / 1000).toFixed(1)}s`.padStart(8)}`);
|
|
198
|
+
log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
|
|
199
|
+
}
|
|
200
|
+
writeJsonl(dominant, totalMs) {
|
|
201
|
+
const wallStartIso = new Date(this.wallT0).toISOString();
|
|
202
|
+
const fileName = `${wallStartIso.replace(/[:.]/g, '-')}.jsonl`;
|
|
203
|
+
const filePath = join(this.logDir, fileName);
|
|
204
|
+
const lines = [];
|
|
205
|
+
for (const e of this.events) {
|
|
206
|
+
lines.push(JSON.stringify({ kind: 'event', ...e }));
|
|
207
|
+
}
|
|
208
|
+
lines.push(JSON.stringify({
|
|
209
|
+
kind: 'summary',
|
|
210
|
+
wallStartIso,
|
|
211
|
+
totalMs: Math.round(totalMs),
|
|
212
|
+
eventCount: this.events.length,
|
|
213
|
+
phaseCount: this.events.filter((e) => e.category === 'phase').length,
|
|
214
|
+
dominantPhase: dominant?.label,
|
|
215
|
+
dominantMs: dominant ? Math.round(dominant.durationMs) : undefined,
|
|
216
|
+
}));
|
|
217
|
+
try {
|
|
218
|
+
this.mkdir(this.logDir);
|
|
219
|
+
this.writeFile(filePath, lines.join('\n') + '\n');
|
|
220
|
+
this.logger(`Timeline written: ${filePath}`);
|
|
221
|
+
}
|
|
222
|
+
catch (err) {
|
|
223
|
+
// Investigation-only: never let logging failure affect the install.
|
|
224
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
225
|
+
this.logger(`Timeline: failed to write JSONL (${msg})`);
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
/**
|
|
230
|
+
* Decide enablement from the opt-in env flag (unless explicitly overridden).
|
|
231
|
+
*/
|
|
232
|
+
export function isTimelineEnabled(env = process.env) {
|
|
233
|
+
const raw = env['SNAPSHOT_INSTALL_TIMELINE'];
|
|
234
|
+
return raw !== undefined && ENABLE_VALUES.has(raw.trim().toLowerCase());
|
|
235
|
+
}
|
|
236
|
+
/**
|
|
237
|
+
* Factory: returns an active timeline when opted-in, else a zero-overhead no-op.
|
|
238
|
+
*/
|
|
239
|
+
export function createInstallTimeline(opts = {}) {
|
|
240
|
+
const enabled = opts.enabled ?? isTimelineEnabled(opts.env ?? process.env);
|
|
241
|
+
return enabled ? new ActiveTimeline(opts) : new NoopTimeline();
|
|
242
|
+
}
|
|
243
|
+
//# sourceMappingURL=install-timeline.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"install-timeline.js","sourceRoot":"","sources":["../../src/lib/install-timeline.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Snapshot ↔ install-preflight adapter (thin).
|
|
3
|
+
*
|
|
4
|
+
* Maps a snapshot.json into the registry-agnostic preflight engine's inputs and
|
|
5
|
+
* runs the gate. The engine (@microwiseai/install-preflight) knows nothing about
|
|
6
|
+
* snapshots; all snapshot-specific knowledge lives here:
|
|
7
|
+
*
|
|
8
|
+
* • install groups (npm-proxy / glpkg / skit) + legacy packages/skits → channels
|
|
9
|
+
* + package requests, all probed ANONYMOUSLY (reproduces a first-time
|
|
10
|
+
* end-user with no token).
|
|
11
|
+
* • transitive closure discovery: uses the publisher's token to expand npm
|
|
12
|
+
* deps via the proxy, then hands the discovered nodes back to the engine to
|
|
13
|
+
* probe anonymously — so a private transitive dep (401 for end-users) is
|
|
14
|
+
* caught even though the publisher can see it.
|
|
15
|
+
* • [B] the snapshot's OWN version must be stable when promoted to `latest`.
|
|
16
|
+
*
|
|
17
|
+
* See architecture/decisions — this is the blocking preflight gate wired into
|
|
18
|
+
* `snapshot publish` and the `snapshot preflight` command.
|
|
19
|
+
*/
|
|
20
|
+
import { formatReport, createNpmPackumentResolver, type PreflightInput, type PreflightReport, type Resolver } from '@microwiseai/install-preflight';
|
|
21
|
+
import type { Snapshot } from './types.js';
|
|
22
|
+
export interface SnapshotPreflightOptions {
|
|
23
|
+
/** Attempt transitive-closure discovery (needs a token). Default: true. */
|
|
24
|
+
includeTransitive?: boolean;
|
|
25
|
+
/** dist-tag this publish targets (default 'latest'). */
|
|
26
|
+
distTag?: string;
|
|
27
|
+
/** Verbose progress logging via the provided sink. */
|
|
28
|
+
log?: (msg: string) => void;
|
|
29
|
+
/** Override the engine's network resolver (tests / custom lanes). */
|
|
30
|
+
resolver?: Resolver;
|
|
31
|
+
}
|
|
32
|
+
export interface SnapshotPreflightResult {
|
|
33
|
+
report: PreflightReport;
|
|
34
|
+
/** Non-fatal warnings (e.g. transitive discovery skipped). Surfaced, never silent. */
|
|
35
|
+
warnings: string[];
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Build the full engine input for a snapshot: anonymous channels + direct pins
|
|
39
|
+
* (+ discovered transitive closure). Exposed for testing/other callers.
|
|
40
|
+
*/
|
|
41
|
+
export declare function buildSnapshotPreflightInput(snapshot: Snapshot, options?: SnapshotPreflightOptions): Promise<{
|
|
42
|
+
input: PreflightInput;
|
|
43
|
+
warnings: string[];
|
|
44
|
+
}>;
|
|
45
|
+
/**
|
|
46
|
+
* Run the blocking preflight gate for a snapshot. Combines:
|
|
47
|
+
* [A] anonymous resolvability of the whole closure (engine), and
|
|
48
|
+
* [B] the snapshot's own version must be stable when promoted to `latest`.
|
|
49
|
+
*/
|
|
50
|
+
export declare function runSnapshotPreflight(snapshot: Snapshot, options?: SnapshotPreflightOptions): Promise<SnapshotPreflightResult>;
|
|
51
|
+
export { formatReport, createNpmPackumentResolver };
|
|
52
|
+
//# sourceMappingURL=preflight-adapter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"preflight-adapter.d.ts","sourceRoot":"","sources":["../../src/lib/preflight-adapter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,EAEL,YAAY,EACZ,0BAA0B,EAE1B,KAAK,cAAc,EACnB,KAAK,eAAe,EAIpB,KAAK,QAAQ,EACd,MAAM,gCAAgC,CAAC;AAIxC,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAK3C,MAAM,WAAW,wBAAwB;IACvC,2EAA2E;IAC3E,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,wDAAwD;IACxD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,sDAAsD;IACtD,GAAG,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IAC5B,qEAAqE;IACrE,QAAQ,CAAC,EAAE,QAAQ,CAAC;CACrB;AAED,MAAM,WAAW,uBAAuB;IACtC,MAAM,EAAE,eAAe,CAAC;IACxB,sFAAsF;IACtF,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AA2KD;;;GAGG;AACH,wBAAsB,2BAA2B,CAC/C,QAAQ,EAAE,QAAQ,EAClB,OAAO,GAAE,wBAA6B,GACrC,OAAO,CAAC;IAAE,KAAK,EAAE,cAAc,CAAC;IAAC,QAAQ,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC,CAqBxD;AAED;;;;GAIG;AACH,wBAAsB,oBAAoB,CACxC,QAAQ,EAAE,QAAQ,EAClB,OAAO,GAAE,wBAA6B,GACrC,OAAO,CAAC,uBAAuB,CAAC,CAsBlC;AAED,OAAO,EAAE,YAAY,EAAE,0BAA0B,EAAE,CAAC"}
|