@microwiseai/snapshot 0.7.0 → 0.9.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.
Files changed (116) hide show
  1. package/dist/build-info.json +1 -0
  2. package/dist/commands/access.d.ts +25 -9
  3. package/dist/commands/access.d.ts.map +1 -1
  4. package/dist/commands/access.js +101 -47
  5. package/dist/commands/access.js.map +1 -1
  6. package/dist/commands/config.d.ts +3 -0
  7. package/dist/commands/config.d.ts.map +1 -0
  8. package/dist/commands/config.js +37 -0
  9. package/dist/commands/config.js.map +1 -0
  10. package/dist/commands/install.d.ts +54 -0
  11. package/dist/commands/install.d.ts.map +1 -1
  12. package/dist/commands/install.js +480 -65
  13. package/dist/commands/install.js.map +1 -1
  14. package/dist/commands/publish.d.ts +10 -0
  15. package/dist/commands/publish.d.ts.map +1 -1
  16. package/dist/commands/publish.js +94 -12
  17. package/dist/commands/publish.js.map +1 -1
  18. package/dist/index.js +45 -8
  19. package/dist/index.js.map +1 -1
  20. package/dist/lib/access-index.d.ts +81 -0
  21. package/dist/lib/access-index.d.ts.map +1 -0
  22. package/dist/lib/access-index.js +175 -0
  23. package/dist/lib/access-index.js.map +1 -0
  24. package/dist/lib/access-sync.d.ts +66 -17
  25. package/dist/lib/access-sync.d.ts.map +1 -1
  26. package/dist/lib/access-sync.js +391 -213
  27. package/dist/lib/access-sync.js.map +1 -1
  28. package/dist/lib/config.d.ts +12 -0
  29. package/dist/lib/config.d.ts.map +1 -1
  30. package/dist/lib/config.js +38 -5
  31. package/dist/lib/config.js.map +1 -1
  32. package/dist/lib/extends-access.d.ts +34 -0
  33. package/dist/lib/extends-access.d.ts.map +1 -0
  34. package/dist/lib/extends-access.js +82 -0
  35. package/dist/lib/extends-access.js.map +1 -0
  36. package/dist/lib/gitlab-publisher.d.ts +70 -0
  37. package/dist/lib/gitlab-publisher.d.ts.map +1 -0
  38. package/dist/lib/gitlab-publisher.js +165 -0
  39. package/dist/lib/gitlab-publisher.js.map +1 -0
  40. package/dist/lib/gitlab.d.ts +4 -0
  41. package/dist/lib/gitlab.d.ts.map +1 -1
  42. package/dist/lib/gitlab.js +1 -1
  43. package/dist/lib/gitlab.js.map +1 -1
  44. package/dist/lib/grant.d.ts +157 -0
  45. package/dist/lib/grant.d.ts.map +1 -0
  46. package/dist/lib/grant.js +352 -0
  47. package/dist/lib/grant.js.map +1 -0
  48. package/dist/lib/install-verify.d.ts +16 -2
  49. package/dist/lib/install-verify.d.ts.map +1 -1
  50. package/dist/lib/install-verify.js +24 -3
  51. package/dist/lib/install-verify.js.map +1 -1
  52. package/dist/lib/ledger.d.ts +13 -0
  53. package/dist/lib/ledger.d.ts.map +1 -1
  54. package/dist/lib/ledger.js.map +1 -1
  55. package/dist/lib/prerequisites.d.ts.map +1 -1
  56. package/dist/lib/prerequisites.js +4 -1
  57. package/dist/lib/prerequisites.js.map +1 -1
  58. package/dist/lib/proxy-auth-globalconfig.d.ts +55 -0
  59. package/dist/lib/proxy-auth-globalconfig.d.ts.map +1 -0
  60. package/dist/lib/proxy-auth-globalconfig.js +110 -0
  61. package/dist/lib/proxy-auth-globalconfig.js.map +1 -0
  62. package/dist/lib/semver-range.d.ts +32 -0
  63. package/dist/lib/semver-range.d.ts.map +1 -0
  64. package/dist/lib/semver-range.js +243 -0
  65. package/dist/lib/semver-range.js.map +1 -0
  66. package/dist/lib/session.d.ts +5 -0
  67. package/dist/lib/session.d.ts.map +1 -1
  68. package/dist/lib/session.js +9 -0
  69. package/dist/lib/session.js.map +1 -1
  70. package/dist/lib/skit-adapter.d.ts.map +1 -1
  71. package/dist/lib/skit-adapter.js +80 -23
  72. package/dist/lib/skit-adapter.js.map +1 -1
  73. package/dist/lib/timing.d.ts +7 -0
  74. package/dist/lib/timing.d.ts.map +1 -0
  75. package/dist/lib/timing.js +14 -0
  76. package/dist/lib/timing.js.map +1 -0
  77. package/dist/lib/types.d.ts +3 -0
  78. package/dist/lib/types.d.ts.map +1 -1
  79. package/node_modules/@microwiseai/snapshot-downgrade-guard/dist/command-specs.d.ts +25 -0
  80. package/node_modules/@microwiseai/snapshot-downgrade-guard/dist/command-specs.d.ts.map +1 -0
  81. package/node_modules/@microwiseai/snapshot-downgrade-guard/dist/command-specs.js +55 -0
  82. package/node_modules/@microwiseai/snapshot-downgrade-guard/dist/command-specs.js.map +1 -0
  83. package/node_modules/@microwiseai/snapshot-downgrade-guard/dist/config.d.ts +52 -0
  84. package/node_modules/@microwiseai/snapshot-downgrade-guard/dist/config.d.ts.map +1 -0
  85. package/node_modules/@microwiseai/snapshot-downgrade-guard/dist/config.js +62 -0
  86. package/node_modules/@microwiseai/snapshot-downgrade-guard/dist/config.js.map +1 -0
  87. package/node_modules/@microwiseai/snapshot-downgrade-guard/dist/detect.d.ts +30 -0
  88. package/node_modules/@microwiseai/snapshot-downgrade-guard/dist/detect.d.ts.map +1 -0
  89. package/node_modules/@microwiseai/snapshot-downgrade-guard/dist/detect.js +39 -0
  90. package/node_modules/@microwiseai/snapshot-downgrade-guard/dist/detect.js.map +1 -0
  91. package/node_modules/@microwiseai/snapshot-downgrade-guard/dist/index.d.ts +35 -0
  92. package/node_modules/@microwiseai/snapshot-downgrade-guard/dist/index.d.ts.map +1 -0
  93. package/node_modules/@microwiseai/snapshot-downgrade-guard/dist/index.js +31 -0
  94. package/node_modules/@microwiseai/snapshot-downgrade-guard/dist/index.js.map +1 -0
  95. package/node_modules/@microwiseai/snapshot-downgrade-guard/dist/policy.d.ts +42 -0
  96. package/node_modules/@microwiseai/snapshot-downgrade-guard/dist/policy.d.ts.map +1 -0
  97. package/node_modules/@microwiseai/snapshot-downgrade-guard/dist/policy.js +36 -0
  98. package/node_modules/@microwiseai/snapshot-downgrade-guard/dist/policy.js.map +1 -0
  99. package/node_modules/@microwiseai/snapshot-downgrade-guard/dist/report.d.ts +11 -0
  100. package/node_modules/@microwiseai/snapshot-downgrade-guard/dist/report.d.ts.map +1 -0
  101. package/node_modules/@microwiseai/snapshot-downgrade-guard/dist/report.js +46 -0
  102. package/node_modules/@microwiseai/snapshot-downgrade-guard/dist/report.js.map +1 -0
  103. package/node_modules/@microwiseai/snapshot-downgrade-guard/dist/semver.d.ts +11 -0
  104. package/node_modules/@microwiseai/snapshot-downgrade-guard/dist/semver.d.ts.map +1 -0
  105. package/node_modules/@microwiseai/snapshot-downgrade-guard/dist/semver.js +81 -0
  106. package/node_modules/@microwiseai/snapshot-downgrade-guard/dist/semver.js.map +1 -0
  107. package/node_modules/@microwiseai/snapshot-downgrade-guard/dist/types.d.ts +29 -0
  108. package/node_modules/@microwiseai/snapshot-downgrade-guard/dist/types.d.ts.map +1 -0
  109. package/node_modules/@microwiseai/snapshot-downgrade-guard/dist/types.js +6 -0
  110. package/node_modules/@microwiseai/snapshot-downgrade-guard/dist/types.js.map +1 -0
  111. package/node_modules/@microwiseai/snapshot-downgrade-guard/package.json +55 -0
  112. package/package.json +9 -2
  113. package/dist/lib/transitive-resolver.d.ts +0 -89
  114. package/dist/lib/transitive-resolver.d.ts.map +0 -1
  115. package/dist/lib/transitive-resolver.js +0 -436
  116. package/dist/lib/transitive-resolver.js.map +0 -1
@@ -0,0 +1,42 @@
1
+ import { type DowngradeMode } from './types.js';
2
+ /**
3
+ * Policy values read from each layer. Any field may be absent (undefined/null)
4
+ * or invalid; invalid values are ignored (treated as absent) so a typo never
5
+ * silently weakens the guard.
6
+ *
7
+ * Precedence (highest wins):
8
+ * (a) override — CLI flag / one-shot env (already mapped to a mode)
9
+ * (b) machine — machine config (~/.config/ist-snapshot/config.json)
10
+ * (c) snapshot — snapshot.json `policy.onDowngrade`
11
+ * (d) default — 'refuse'
12
+ */
13
+ export interface PolicySources {
14
+ override?: DowngradeMode | string | null;
15
+ machine?: DowngradeMode | string | null;
16
+ snapshot?: DowngradeMode | string | null;
17
+ }
18
+ /** The default when no layer specifies a valid mode. */
19
+ export declare const DEFAULT_DOWNGRADE_MODE: DowngradeMode;
20
+ /** Narrow an arbitrary value to a valid DowngradeMode, or null if invalid. */
21
+ export declare function asDowngradeMode(v: unknown): DowngradeMode | null;
22
+ /**
23
+ * Resolve the effective downgrade policy from the layered sources.
24
+ * Pure: first valid value in precedence order (a > b > c), else the default.
25
+ */
26
+ export declare function resolveDowngradePolicy(sources?: PolicySources): DowngradeMode;
27
+ export interface OneShotOverrideInput {
28
+ /** Environment map (e.g. process.env). SNAPSHOT_ALLOW_LOCAL=1 → allow. */
29
+ env?: NodeJS.ProcessEnv | Record<string, string | undefined>;
30
+ /** CLI flag, e.g. --allow-downgrade → allow. */
31
+ allowDowngradeFlag?: boolean;
32
+ }
33
+ /**
34
+ * Map the one-shot escape hatches (CLI `--allow-downgrade` or env
35
+ * `SNAPSHOT_ALLOW_LOCAL=1`) to an override mode.
36
+ *
37
+ * Returns 'allow' when either hatch is engaged, otherwise null (no override).
38
+ * Pure — reads only the injected inputs. Core passes the result as
39
+ * `PolicySources.override`.
40
+ */
41
+ export declare function readOneShotOverride(input?: OneShotOverrideInput): DowngradeMode | null;
42
+ //# sourceMappingURL=policy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"policy.d.ts","sourceRoot":"","sources":["../src/policy.ts"],"names":[],"mappings":"AAAA,OAAO,EAAmB,KAAK,aAAa,EAAE,MAAM,YAAY,CAAC;AAEjE;;;;;;;;;;GAUG;AACH,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,EAAE,aAAa,GAAG,MAAM,GAAG,IAAI,CAAC;IACzC,OAAO,CAAC,EAAE,aAAa,GAAG,MAAM,GAAG,IAAI,CAAC;IACxC,QAAQ,CAAC,EAAE,aAAa,GAAG,MAAM,GAAG,IAAI,CAAC;CAC1C;AAED,wDAAwD;AACxD,eAAO,MAAM,sBAAsB,EAAE,aAAwB,CAAC;AAE9D,8EAA8E;AAC9E,wBAAgB,eAAe,CAAC,CAAC,EAAE,OAAO,GAAG,aAAa,GAAG,IAAI,CAIhE;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,GAAE,aAAkB,GAAG,aAAa,CAOjF;AAED,MAAM,WAAW,oBAAoB;IACnC,0EAA0E;IAC1E,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;IAC7D,gDAAgD;IAChD,kBAAkB,CAAC,EAAE,OAAO,CAAC;CAC9B;AAED;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,GAAE,oBAAyB,GAAG,aAAa,GAAG,IAAI,CAK1F"}
@@ -0,0 +1,36 @@
1
+ import { DOWNGRADE_MODES } from './types.js';
2
+ /** The default when no layer specifies a valid mode. */
3
+ export const DEFAULT_DOWNGRADE_MODE = 'refuse';
4
+ /** Narrow an arbitrary value to a valid DowngradeMode, or null if invalid. */
5
+ export function asDowngradeMode(v) {
6
+ return typeof v === 'string' && DOWNGRADE_MODES.includes(v)
7
+ ? v
8
+ : null;
9
+ }
10
+ /**
11
+ * Resolve the effective downgrade policy from the layered sources.
12
+ * Pure: first valid value in precedence order (a > b > c), else the default.
13
+ */
14
+ export function resolveDowngradePolicy(sources = {}) {
15
+ return (asDowngradeMode(sources.override) ??
16
+ asDowngradeMode(sources.machine) ??
17
+ asDowngradeMode(sources.snapshot) ??
18
+ DEFAULT_DOWNGRADE_MODE);
19
+ }
20
+ /**
21
+ * Map the one-shot escape hatches (CLI `--allow-downgrade` or env
22
+ * `SNAPSHOT_ALLOW_LOCAL=1`) to an override mode.
23
+ *
24
+ * Returns 'allow' when either hatch is engaged, otherwise null (no override).
25
+ * Pure — reads only the injected inputs. Core passes the result as
26
+ * `PolicySources.override`.
27
+ */
28
+ export function readOneShotOverride(input = {}) {
29
+ const env = input.env ?? {};
30
+ if (input.allowDowngradeFlag === true)
31
+ return 'allow';
32
+ if (env.SNAPSHOT_ALLOW_LOCAL === '1')
33
+ return 'allow';
34
+ return null;
35
+ }
36
+ //# sourceMappingURL=policy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"policy.js","sourceRoot":"","sources":["../src/policy.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAsB,MAAM,YAAY,CAAC;AAmBjE,wDAAwD;AACxD,MAAM,CAAC,MAAM,sBAAsB,GAAkB,QAAQ,CAAC;AAE9D,8EAA8E;AAC9E,MAAM,UAAU,eAAe,CAAC,CAAU;IACxC,OAAO,OAAO,CAAC,KAAK,QAAQ,IAAK,eAAqC,CAAC,QAAQ,CAAC,CAAC,CAAC;QAChF,CAAC,CAAE,CAAmB;QACtB,CAAC,CAAC,IAAI,CAAC;AACX,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,sBAAsB,CAAC,UAAyB,EAAE;IAChE,OAAO,CACL,eAAe,CAAC,OAAO,CAAC,QAAQ,CAAC;QACjC,eAAe,CAAC,OAAO,CAAC,OAAO,CAAC;QAChC,eAAe,CAAC,OAAO,CAAC,QAAQ,CAAC;QACjC,sBAAsB,CACvB,CAAC;AACJ,CAAC;AASD;;;;;;;GAOG;AACH,MAAM,UAAU,mBAAmB,CAAC,QAA8B,EAAE;IAClE,MAAM,GAAG,GAAG,KAAK,CAAC,GAAG,IAAI,EAAE,CAAC;IAC5B,IAAI,KAAK,CAAC,kBAAkB,KAAK,IAAI;QAAE,OAAO,OAAO,CAAC;IACtD,IAAI,GAAG,CAAC,oBAAoB,KAAK,GAAG;QAAE,OAAO,OAAO,CAAC;IACrD,OAAO,IAAI,CAAC;AACd,CAAC"}
@@ -0,0 +1,11 @@
1
+ import type { DowngradeMode, Offender } from './types.js';
2
+ /**
3
+ * Build a user-facing message describing the detected downgrades for the given
4
+ * policy mode. Korean + short English.
5
+ *
6
+ * - refuse: block message with the offender list and the three bypass routes.
7
+ * - warn: warning header + offender list, install continues.
8
+ * - allow: minimal note (usually not shown by callers).
9
+ */
10
+ export declare function formatDowngradeReport(offenders: Offender[], mode: DowngradeMode): string;
11
+ //# sourceMappingURL=report.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"report.d.ts","sourceRoot":"","sources":["../src/report.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAM1D;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CAAC,SAAS,EAAE,QAAQ,EAAE,EAAE,IAAI,EAAE,aAAa,GAAG,MAAM,CAqCxF"}
@@ -0,0 +1,46 @@
1
+ function offenderLines(offenders) {
2
+ return offenders.map((o) => ` • ${o.pkg}: ${o.installed} → ${o.pinned}`).join('\n');
3
+ }
4
+ /**
5
+ * Build a user-facing message describing the detected downgrades for the given
6
+ * policy mode. Korean + short English.
7
+ *
8
+ * - refuse: block message with the offender list and the three bypass routes.
9
+ * - warn: warning header + offender list, install continues.
10
+ * - allow: minimal note (usually not shown by callers).
11
+ */
12
+ export function formatDowngradeReport(offenders, mode) {
13
+ if (offenders.length === 0) {
14
+ return '다운그레이드 없음 / No downgrades detected.';
15
+ }
16
+ const list = offenderLines(offenders);
17
+ if (mode === 'refuse') {
18
+ return [
19
+ '스냅샷 설치가 현재 전역 패키지를 다운그레이드하므로 거부되었습니다.',
20
+ 'Refused: this snapshot would downgrade already-installed global packages.',
21
+ '',
22
+ '다운그레이드 대상 / Would downgrade:',
23
+ list,
24
+ '',
25
+ '해결 / How to proceed:',
26
+ ' 1) 깨끗한 Docker 샌드박스에서 실행 (권장) / run in a clean Docker sandbox (recommended)',
27
+ ' 2) 이번 한 번만 강제 / force just this once: --allow-downgrade 또는/or SNAPSHOT_ALLOW_LOCAL=1',
28
+ ' 3) 이 머신에서 항상 허용 / always allow on this machine: snapshot config set install.onDowngrade allow',
29
+ ].join('\n');
30
+ }
31
+ if (mode === 'warn') {
32
+ return [
33
+ '⚠ 경고: 스냅샷 설치가 아래 전역 패키지를 다운그레이드합니다 (계속 진행).',
34
+ '⚠ Warning: this snapshot will downgrade the following global packages (continuing).',
35
+ '',
36
+ list,
37
+ ].join('\n');
38
+ }
39
+ // allow
40
+ return [
41
+ '스냅샷 설치가 아래 패키지를 다운그레이드합니다 (allow 정책으로 진행).',
42
+ 'Proceeding despite downgrades (policy=allow):',
43
+ list,
44
+ ].join('\n');
45
+ }
46
+ //# sourceMappingURL=report.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"report.js","sourceRoot":"","sources":["../src/report.ts"],"names":[],"mappings":"AAEA,SAAS,aAAa,CAAC,SAAqB;IAC1C,OAAO,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,SAAS,MAAM,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACvF,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,qBAAqB,CAAC,SAAqB,EAAE,IAAmB;IAC9E,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC3B,OAAO,qCAAqC,CAAC;IAC/C,CAAC;IAED,MAAM,IAAI,GAAG,aAAa,CAAC,SAAS,CAAC,CAAC;IAEtC,IAAI,IAAI,KAAK,QAAQ,EAAE,CAAC;QACtB,OAAO;YACL,uCAAuC;YACvC,2EAA2E;YAC3E,EAAE;YACF,8BAA8B;YAC9B,IAAI;YACJ,EAAE;YACF,sBAAsB;YACtB,8EAA8E;YAC9E,2FAA2F;YAC3F,kGAAkG;SACnG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACf,CAAC;IAED,IAAI,IAAI,KAAK,MAAM,EAAE,CAAC;QACpB,OAAO;YACL,6CAA6C;YAC7C,qFAAqF;YACrF,EAAE;YACF,IAAI;SACL,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACf,CAAC;IAED,QAAQ;IACR,OAAO;QACL,4CAA4C;QAC5C,+CAA+C;QAC/C,IAAI;KACL,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACf,CAAC"}
@@ -0,0 +1,11 @@
1
+ /** True iff `v` is a single, exact semver (prerelease/build metadata allowed). */
2
+ export declare function isExactSemver(v: unknown): boolean;
3
+ /**
4
+ * Compare two exact semvers by SemVer-spec precedence (build metadata ignored).
5
+ *
6
+ * Returns -1 if a < b, 0 if equal precedence, 1 if a > b, or `null` when EITHER
7
+ * side is not an exact semver (incomparable — caller should skip). Never throws:
8
+ * tolerance is a design requirement.
9
+ */
10
+ export declare function compareExact(a: unknown, b: unknown): -1 | 0 | 1 | null;
11
+ //# sourceMappingURL=semver.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"semver.d.ts","sourceRoot":"","sources":["../src/semver.ts"],"names":[],"mappings":"AAiBA,kFAAkF;AAClF,wBAAgB,aAAa,CAAC,CAAC,EAAE,OAAO,GAAG,OAAO,CAEjD;AAuBD;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO,GAAG,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,IAAI,CAgCtE"}
@@ -0,0 +1,81 @@
1
+ /**
2
+ * Minimal, self-contained exact-semver comparison.
3
+ *
4
+ * This package stays zero-runtime-dependency (no `semver`) on purpose so it is
5
+ * self-sufficient and side-effect-free. We only compare EXACT semvers; anything
6
+ * that is not a single exact version is reported as "incomparable" and the
7
+ * caller skips it (tolerant, same philosophy as the core-floor check).
8
+ *
9
+ * The pattern is the canonical semver.org regex, anchored — it accepts:
10
+ * 0.3.59 (plain)
11
+ * 0.3.70-dev.0 (prerelease)
12
+ * 1.2.3-rc.1+build (prerelease + build metadata)
13
+ * and rejects ranges, `^`/`~`, `v` prefixes, dist-tags, partial versions, etc.
14
+ */
15
+ const EXACT_SEMVER = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$/;
16
+ /** True iff `v` is a single, exact semver (prerelease/build metadata allowed). */
17
+ export function isExactSemver(v) {
18
+ return typeof v === 'string' && EXACT_SEMVER.test(v.trim());
19
+ }
20
+ function parseSemver(v) {
21
+ if (typeof v !== 'string')
22
+ return null;
23
+ const m = EXACT_SEMVER.exec(v.trim());
24
+ if (!m)
25
+ return null;
26
+ const prerelease = [];
27
+ if (m[4]) {
28
+ for (const id of m[4].split('.')) {
29
+ prerelease.push(/^\d+$/.test(id) ? Number(id) : id);
30
+ }
31
+ }
32
+ return { major: Number(m[1]), minor: Number(m[2]), patch: Number(m[3]), prerelease };
33
+ }
34
+ /**
35
+ * Compare two exact semvers by SemVer-spec precedence (build metadata ignored).
36
+ *
37
+ * Returns -1 if a < b, 0 if equal precedence, 1 if a > b, or `null` when EITHER
38
+ * side is not an exact semver (incomparable — caller should skip). Never throws:
39
+ * tolerance is a design requirement.
40
+ */
41
+ export function compareExact(a, b) {
42
+ const pa = parseSemver(a);
43
+ const pb = parseSemver(b);
44
+ if (!pa || !pb)
45
+ return null;
46
+ for (const k of ['major', 'minor', 'patch']) {
47
+ if (pa[k] !== pb[k])
48
+ return pa[k] < pb[k] ? -1 : 1;
49
+ }
50
+ // A version WITHOUT prerelease outranks one WITH (1.0.0 > 1.0.0-rc.1).
51
+ const aPre = pa.prerelease;
52
+ const bPre = pb.prerelease;
53
+ if (aPre.length === 0 && bPre.length === 0)
54
+ return 0;
55
+ if (aPre.length === 0)
56
+ return 1;
57
+ if (bPre.length === 0)
58
+ return -1;
59
+ const len = Math.min(aPre.length, bPre.length);
60
+ for (let i = 0; i < len; i++) {
61
+ const x = aPre[i];
62
+ const y = bPre[i];
63
+ if (x === y)
64
+ continue;
65
+ const xNum = typeof x === 'number';
66
+ const yNum = typeof y === 'number';
67
+ // Numeric identifiers always have lower precedence than non-numeric.
68
+ if (xNum && !yNum)
69
+ return -1;
70
+ if (!xNum && yNum)
71
+ return 1;
72
+ if (xNum && yNum)
73
+ return x < y ? -1 : 1;
74
+ return x < y ? -1 : 1;
75
+ }
76
+ // All shared identifiers equal — the longer prerelease list has higher precedence.
77
+ if (aPre.length === bPre.length)
78
+ return 0;
79
+ return aPre.length < bPre.length ? -1 : 1;
80
+ }
81
+ //# sourceMappingURL=semver.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"semver.js","sourceRoot":"","sources":["../src/semver.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Shared types for @microwiseai/snapshot-downgrade-guard.
3
+ */
4
+ /**
5
+ * Downgrade policy mode.
6
+ * - refuse (default): block the install when a downgrade is detected.
7
+ * - warn: print a warning, then proceed.
8
+ * - allow: proceed silently.
9
+ */
10
+ export type DowngradeMode = 'refuse' | 'warn' | 'allow';
11
+ /** The set of valid policy modes (runtime guard). */
12
+ export declare const DOWNGRADE_MODES: readonly DowngradeMode[];
13
+ /** A single package whose currently-installed version is newer than the pin. */
14
+ export interface Offender {
15
+ /** Package name. */
16
+ pkg: string;
17
+ /** Currently-installed (global) version. */
18
+ installed: string;
19
+ /** Version the snapshot would pin/install (a downgrade relative to `installed`). */
20
+ pinned: string;
21
+ }
22
+ /** Result of {@link detectDowngrades}. */
23
+ export interface DetectResult {
24
+ /** True iff at least one offender was found. */
25
+ wouldDowngrade: boolean;
26
+ /** Packages that would be downgraded (installed > pinned, strict). */
27
+ offenders: Offender[];
28
+ }
29
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH;;;;;GAKG;AACH,MAAM,MAAM,aAAa,GAAG,QAAQ,GAAG,MAAM,GAAG,OAAO,CAAC;AAExD,qDAAqD;AACrD,eAAO,MAAM,eAAe,EAAE,SAAS,aAAa,EAAgC,CAAC;AAErF,gFAAgF;AAChF,MAAM,WAAW,QAAQ;IACvB,oBAAoB;IACpB,GAAG,EAAE,MAAM,CAAC;IACZ,4CAA4C;IAC5C,SAAS,EAAE,MAAM,CAAC;IAClB,oFAAoF;IACpF,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,0CAA0C;AAC1C,MAAM,WAAW,YAAY;IAC3B,gDAAgD;IAChD,cAAc,EAAE,OAAO,CAAC;IACxB,sEAAsE;IACtE,SAAS,EAAE,QAAQ,EAAE,CAAC;CACvB"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Shared types for @microwiseai/snapshot-downgrade-guard.
3
+ */
4
+ /** The set of valid policy modes (runtime guard). */
5
+ export const DOWNGRADE_MODES = ['refuse', 'warn', 'allow'];
6
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAUH,qDAAqD;AACrD,MAAM,CAAC,MAAM,eAAe,GAA6B,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC"}
@@ -0,0 +1,55 @@
1
+ {
2
+ "name": "@microwiseai/snapshot-downgrade-guard",
3
+ "version": "0.1.0",
4
+ "description": "Auto-detects when a snapshot install would downgrade already-installed global tooling, and resolves the layered refuse/warn/allow policy. Pure, dependency-injected, no side effects.",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.js"
12
+ }
13
+ },
14
+ "scripts": {
15
+ "prebuild": "node -e \"require('fs').rmSync('dist',{recursive:true,force:true})\"",
16
+ "build": "tsc -p tsconfig.build.json",
17
+ "dev": "tsc --watch",
18
+ "typecheck": "tsc --noEmit",
19
+ "test": "vitest",
20
+ "test:run": "vitest run",
21
+ "lint": "eslint src",
22
+ "prepublishOnly": "npm run build"
23
+ },
24
+ "files": [
25
+ "dist"
26
+ ],
27
+ "keywords": [
28
+ "snapshot",
29
+ "downgrade",
30
+ "guard",
31
+ "semver",
32
+ "install"
33
+ ],
34
+ "author": "IST Team",
35
+ "license": "MIT",
36
+ "dependencies": {},
37
+ "devDependencies": {
38
+ "@types/node": "^20.11.0",
39
+ "@typescript-eslint/eslint-plugin": "^8.57.0",
40
+ "@typescript-eslint/parser": "^8.57.0",
41
+ "eslint": "^10.0.3",
42
+ "typescript": "^5.7.3",
43
+ "vitest": "^4.0.18"
44
+ },
45
+ "engines": {
46
+ "node": ">=18.0.0"
47
+ },
48
+ "glpkg": {
49
+ "group": "microwiseai"
50
+ },
51
+ "repository": {
52
+ "type": "git",
53
+ "url": "git+https://gitlab.com/microwiseai/snapshot.downgrade-guard.git"
54
+ }
55
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@microwiseai/snapshot",
3
- "version": "0.7.0",
3
+ "version": "0.9.0",
4
4
  "description": "CLI for installing IST Snapshot packages",
5
5
  "publishConfig": {
6
6
  "registry": "https://registry.npmjs.org/",
@@ -25,6 +25,7 @@
25
25
  "scripts": {
26
26
  "prebuild": "node -e \"require('fs').rmSync('dist',{recursive:true,force:true})\"",
27
27
  "build": "tsc -p tsconfig.build.json",
28
+ "postbuild": "node scripts/write-build-info.mjs",
28
29
  "dev": "tsc --watch",
29
30
  "typecheck": "tsc --noEmit",
30
31
  "test": "vitest",
@@ -32,7 +33,7 @@
32
33
  "lint": "eslint src",
33
34
  "prepublishOnly": "npm run build",
34
35
  "publish:npm": "set -a; . ./.env; set +a; npm publish --access public",
35
- "publish:glpkg": "glpkg publish --git-tag false --push false",
36
+ "publish:glpkg": "glpkg publish",
36
37
  "publish:all": "npm run publish:npm && npm run publish:glpkg"
37
38
  },
38
39
  "files": [
@@ -53,6 +54,7 @@
53
54
  "@microwiseai/license": "^0.1.4",
54
55
  "@microwiseai/skit": "^0.1.19",
55
56
  "@microwiseai/snapshot-dedup": "0.2.0",
57
+ "@microwiseai/snapshot-downgrade-guard": "0.1.0",
56
58
  "@microwiseai/snapshot-parallel": "^0.1.0",
57
59
  "chalk": "^5.3.0",
58
60
  "commander": "^12.1.0",
@@ -75,9 +77,14 @@
75
77
  "@microwiseai/license",
76
78
  "@microwiseai/skit",
77
79
  "@microwiseai/snapshot-dedup",
80
+ "@microwiseai/snapshot-downgrade-guard",
78
81
  "@microwiseai/snapshot-parallel"
79
82
  ],
80
83
  "glpkg": {
81
84
  "group": "microwiseai"
85
+ },
86
+ "repository": {
87
+ "type": "git",
88
+ "url": "git+https://gitlab.com/microwiseai/snapshot.git"
82
89
  }
83
90
  }
@@ -1,89 +0,0 @@
1
- /**
2
- * Transitive Dependency Resolver
3
- *
4
- * snapshot과 skit을 재귀적으로 탐색하여 모든 npm 패키지를 수집하고
5
- * registry-proxy의 /resolve-deps API를 통해 transitive deps를 해석
6
- */
7
- export interface SkitManifest {
8
- name: string;
9
- version: string;
10
- dependencies?: {
11
- npm?: Record<string, string>;
12
- skit?: Record<string, string>;
13
- cli?: Array<{
14
- name: string;
15
- install: string;
16
- }>;
17
- };
18
- }
19
- export interface ResolvedPackage {
20
- name: string;
21
- version: string;
22
- isDirect: boolean;
23
- source: 'snapshot' | 'skit' | 'transitive';
24
- requestedBy?: string;
25
- }
26
- export interface TransitiveResolutionResult {
27
- /** 수집된 모든 npm 패키지 (직접 + transitive) */
28
- npm: ResolvedPackage[];
29
- /** 수집된 모든 skit 패키지 */
30
- skit: ResolvedPackage[];
31
- /** 에러 발생한 패키지들 */
32
- errors: Array<{
33
- name: string;
34
- error: string;
35
- }>;
36
- /** scope → groupId 매핑 (snapshot registry에서 수집) */
37
- scopeGroups: Record<string, string>;
38
- }
39
- /**
40
- * license-api /resolve-deps 응답 타입 (normalized)
41
- */
42
- export interface LicenseApiResolveDepsResponse {
43
- dependencies: Record<string, string>;
44
- peerDependencies?: Record<string, string>;
45
- }
46
- export interface ResolveOptions {
47
- /** proxy를 통해 transitive deps 해석 */
48
- resolveTransitive?: boolean;
49
- /** transitive 해석 대상 스코프 (defaults to scopes from snapshot.registry) */
50
- scopes?: string[];
51
- /** GitLab group ID */
52
- groupId?: string;
53
- }
54
- /**
55
- * Snapshot의 모든 의존성을 재귀적으로 탐색하고
56
- * npm transitive deps까지 해석
57
- *
58
- * NOTE: scopes는 snapshot.json의 registry 필드에서 동적으로 추출됨
59
- * options.scopes가 지정되면 해당 값 사용, 아니면 수집된 scopeGroups 사용
60
- */
61
- export declare function resolveAllDependencies(snapshotName: string, options?: ResolveOptions): Promise<TransitiveResolutionResult>;
62
- export interface ResolveDepsFromLicenseOptions {
63
- /** Package list to resolve (e.g., ['@microwiseai/foo@1.0.0']) */
64
- packages: string[];
65
- /** GitLab group ID (string) */
66
- groupId: string;
67
- /** Package scopes (e.g., ['@microwiseai']) */
68
- scopes: string[];
69
- /** Include peer dependencies in response (default: true) */
70
- includePeer?: boolean;
71
- }
72
- /**
73
- * license-api의 /resolve-deps API를 호출하여 의존성 해석
74
- *
75
- * @example
76
- * const result = await resolveDepsFromLicenseAPI({
77
- * groupId: 12345,
78
- * scopes: ['@ist', '@microwiseai'],
79
- * includePeer: true,
80
- * });
81
- * // result.dependencies: { "@ist/tda-kit": "^1.0.0" }
82
- * // result.peerDependencies: { "typescript": "^5.0.0" }
83
- */
84
- export declare function resolveDepsFromLicenseAPI(options: ResolveDepsFromLicenseOptions): Promise<LicenseApiResolveDepsResponse>;
85
- /**
86
- * 캐시 클리어
87
- */
88
- export declare function clearTransitiveCache(): void;
89
- //# sourceMappingURL=transitive-resolver.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"transitive-resolver.d.ts","sourceRoot":"","sources":["../../src/lib/transitive-resolver.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAUH,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,CAAC,EAAE;QACb,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAC7B,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAC9B,GAAG,CAAC,EAAE,KAAK,CAAC;YACV,IAAI,EAAE,MAAM,CAAC;YACb,OAAO,EAAE,MAAM,CAAC;SACjB,CAAC,CAAC;KACJ,CAAC;CACH;AAED,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,OAAO,CAAC;IAClB,MAAM,EAAE,UAAU,GAAG,MAAM,GAAG,YAAY,CAAC;IAC3C,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,0BAA0B;IACzC,uCAAuC;IACvC,GAAG,EAAE,eAAe,EAAE,CAAC;IACvB,sBAAsB;IACtB,IAAI,EAAE,eAAe,EAAE,CAAC;IACxB,kBAAkB;IAClB,MAAM,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC/C,kDAAkD;IAClD,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACrC;AAYD;;GAEG;AACH,MAAM,WAAW,6BAA6B;IAC5C,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACrC,gBAAgB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC3C;AAmWD,MAAM,WAAW,cAAc;IAC7B,mCAAmC;IACnC,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,uEAAuE;IACvE,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,sBAAsB;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;;;;;GAMG;AACH,wBAAsB,sBAAsB,CAC1C,YAAY,EAAE,MAAM,EACpB,OAAO,GAAE,cAAmB,GAC3B,OAAO,CAAC,0BAA0B,CAAC,CAqDrC;AAMD,MAAM,WAAW,6BAA6B;IAC5C,iEAAiE;IACjE,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,+BAA+B;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,8CAA8C;IAC9C,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,4DAA4D;IAC5D,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,yBAAyB,CAC7C,OAAO,EAAE,6BAA6B,GACrC,OAAO,CAAC,6BAA6B,CAAC,CAiGxC;AAED;;GAEG;AACH,wBAAgB,oBAAoB,IAAI,IAAI,CAE3C"}