@superblocksteam/sdk 2.0.131 → 2.0.132
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/.turbo/turbo-build.log +1 -1
- package/dist/cli-replacement/dev-s3-restore.test.mjs +327 -24
- package/dist/cli-replacement/dev-s3-restore.test.mjs.map +1 -1
- package/dist/cli-replacement/dev-startup-git-before-dbfs-order.test.mjs +0 -1
- package/dist/cli-replacement/dev-startup-git-before-dbfs-order.test.mjs.map +1 -1
- package/dist/cli-replacement/dev.d.mts.map +1 -1
- package/dist/cli-replacement/dev.mjs +140 -68
- package/dist/cli-replacement/dev.mjs.map +1 -1
- package/dist/dbfs/client.d.ts.map +1 -1
- package/dist/dbfs/client.js +58 -16
- package/dist/dbfs/client.js.map +1 -1
- package/dist/dbfs/client.test.js +67 -7
- package/dist/dbfs/client.test.js.map +1 -1
- package/dist/dev-utils/dev-server.mjs +3 -1
- package/dist/dev-utils/dev-server.mjs.map +1 -1
- package/package.json +6 -6
- package/src/cli-replacement/dev-s3-restore.test.mts +465 -28
- package/src/cli-replacement/dev-startup-git-before-dbfs-order.test.mts +0 -1
- package/src/cli-replacement/dev.mts +174 -87
- package/src/dbfs/client.test.ts +115 -7
- package/src/dbfs/client.ts +75 -21
- package/src/dev-utils/dev-server.mts +3 -3
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -115,7 +115,6 @@ vi.mock("@superblocksteam/util", () => ({
|
|
|
115
115
|
vi.mock("@superblocksteam/vite-plugin-file-sync/ai-service", () => ({
|
|
116
116
|
AiService: class {
|
|
117
117
|
initialize = vi.fn(async () => undefined);
|
|
118
|
-
notifyMigrationAppArtifactsReady = vi.fn();
|
|
119
118
|
removeIntegrationCache = vi.fn(async () => undefined);
|
|
120
119
|
chatSessionStore = { invalidateCache: vi.fn() };
|
|
121
120
|
// `dev.mts` reads this at startup for two paths: `syncHomeNpmrc`
|
|
@@ -655,7 +654,7 @@ describe("dev startup after S3 workspace restore", () => {
|
|
|
655
654
|
}
|
|
656
655
|
});
|
|
657
656
|
|
|
658
|
-
it("keeps forced npm install when unchanged restore inputs
|
|
657
|
+
it("keeps forced npm install when unchanged restore inputs need private registry validation without a stamp", async () => {
|
|
659
658
|
mockAiServiceState.npmRegistryClient = {
|
|
660
659
|
getConfig: vi.fn(async () => ({
|
|
661
660
|
source: "configured",
|
|
@@ -680,47 +679,450 @@ describe("dev startup after S3 workspace restore", () => {
|
|
|
680
679
|
expect(mockLogger.info).toHaveBeenCalledWith(
|
|
681
680
|
"Package install decision",
|
|
682
681
|
expect.objectContaining({
|
|
683
|
-
|
|
682
|
+
packageInstallRequired: true,
|
|
683
|
+
forcePackageInstall: false,
|
|
684
684
|
forcePackageInstallRequested: true,
|
|
685
685
|
packageJsonRequiresInstall: false,
|
|
686
|
+
privateRegistryRequiresInstallValidation: true,
|
|
686
687
|
}),
|
|
687
688
|
);
|
|
688
689
|
});
|
|
689
690
|
|
|
690
|
-
it("
|
|
691
|
+
it("skips private registry validation install when lockfile already resolves through the configured registry", async () => {
|
|
692
|
+
const tmpDir = await fs.mkdtemp(
|
|
693
|
+
path.join(os.tmpdir(), "sdk-dev-private-registry-"),
|
|
694
|
+
);
|
|
691
695
|
mockAiServiceState.npmRegistryClient = {
|
|
692
696
|
getConfig: vi.fn(async () => ({
|
|
693
697
|
source: "configured",
|
|
694
|
-
config: {
|
|
698
|
+
config: {
|
|
699
|
+
configured: true,
|
|
700
|
+
default: { url: "https://registry.example.com/npm/" },
|
|
701
|
+
},
|
|
702
|
+
})),
|
|
703
|
+
};
|
|
704
|
+
const unchangedPackageJson = {
|
|
705
|
+
name: "test-app",
|
|
706
|
+
dependencies: { leftpad: "1.0.0" },
|
|
707
|
+
};
|
|
708
|
+
const privateRegistryLockfile = {
|
|
709
|
+
name: "test-app",
|
|
710
|
+
lockfileVersion: 3,
|
|
711
|
+
packages: {
|
|
712
|
+
"node_modules/leftpad": {
|
|
713
|
+
version: "1.0.0",
|
|
714
|
+
resolved:
|
|
715
|
+
"https://registry.example.com/npm/leftpad/-/leftpad-1.0.0.tgz",
|
|
716
|
+
},
|
|
717
|
+
},
|
|
718
|
+
};
|
|
719
|
+
|
|
720
|
+
try {
|
|
721
|
+
await fs.writeFile(
|
|
722
|
+
path.join(tmpDir, "package.json"),
|
|
723
|
+
JSON.stringify(unchangedPackageJson, null, 2),
|
|
724
|
+
);
|
|
725
|
+
await fs.writeFile(
|
|
726
|
+
path.join(tmpDir, "package-lock.json"),
|
|
727
|
+
JSON.stringify(privateRegistryLockfile, null, 2),
|
|
728
|
+
);
|
|
729
|
+
await fs.mkdir(path.join(tmpDir, "node_modules"));
|
|
730
|
+
await fs.writeFile(
|
|
731
|
+
path.join(tmpDir, "node_modules", ".package-lock.json"),
|
|
732
|
+
JSON.stringify(privateRegistryLockfile, null, 2),
|
|
733
|
+
);
|
|
734
|
+
const { readPackage } = await import("read-pkg");
|
|
735
|
+
(readPackage as Mock).mockImplementation(async ({ cwd }) =>
|
|
736
|
+
JSON.parse(await fs.readFile(path.join(cwd, "package.json"), "utf-8")),
|
|
737
|
+
);
|
|
738
|
+
const { dev } = await import("./dev.mjs");
|
|
739
|
+
|
|
740
|
+
await dev(
|
|
741
|
+
buildDevOptions({
|
|
742
|
+
cwd: tmpDir,
|
|
743
|
+
forcePackageInstall: false,
|
|
744
|
+
packageJsonSnapshotBeforeRestore:
|
|
745
|
+
packageJsonSnapshot(unchangedPackageJson),
|
|
746
|
+
}) as any,
|
|
747
|
+
);
|
|
748
|
+
|
|
749
|
+
expect(execMock).not.toHaveBeenCalled();
|
|
750
|
+
expect(mockLogger.info).toHaveBeenCalledWith(
|
|
751
|
+
"Package install decision",
|
|
752
|
+
expect.objectContaining({
|
|
753
|
+
packageInstallRequired: false,
|
|
754
|
+
forcePackageInstall: false,
|
|
755
|
+
forcePackageInstallRequested: false,
|
|
756
|
+
packageJsonRequiresInstall: false,
|
|
757
|
+
privateRegistryRequiresInstallValidation: true,
|
|
758
|
+
lockfileAlreadyResolvesThroughRegistry: true,
|
|
759
|
+
}),
|
|
760
|
+
);
|
|
761
|
+
} finally {
|
|
762
|
+
await fs.rm(tmpDir, { recursive: true, force: true });
|
|
763
|
+
}
|
|
764
|
+
});
|
|
765
|
+
|
|
766
|
+
it("skips private registry validation install when scoped lockfile already resolves through the scoped registry", async () => {
|
|
767
|
+
const tmpDir = await fs.mkdtemp(
|
|
768
|
+
path.join(os.tmpdir(), "sdk-dev-private-registry-"),
|
|
769
|
+
);
|
|
770
|
+
mockAiServiceState.npmRegistryClient = {
|
|
771
|
+
getConfig: vi.fn(async () => ({
|
|
772
|
+
source: "configured",
|
|
773
|
+
config: {
|
|
774
|
+
configured: true,
|
|
775
|
+
scopes: {
|
|
776
|
+
"@superblocksteam": {
|
|
777
|
+
url: "https://scoped-registry.example.com/npm/",
|
|
778
|
+
},
|
|
779
|
+
},
|
|
780
|
+
},
|
|
695
781
|
})),
|
|
696
782
|
};
|
|
697
783
|
const unchangedPackageJson = {
|
|
698
784
|
name: "test-app",
|
|
699
785
|
dependencies: { "@superblocksteam/library": "1.0.0" },
|
|
700
786
|
};
|
|
701
|
-
const
|
|
787
|
+
const privateRegistryLockfile = {
|
|
788
|
+
name: "test-app",
|
|
789
|
+
lockfileVersion: 3,
|
|
790
|
+
packages: {
|
|
791
|
+
"node_modules/@superblocksteam/library": {
|
|
792
|
+
version: "1.0.0",
|
|
793
|
+
resolved:
|
|
794
|
+
"https://scoped-registry.example.com/npm/@superblocksteam/library/-/library-1.0.0.tgz",
|
|
795
|
+
},
|
|
796
|
+
},
|
|
797
|
+
};
|
|
702
798
|
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
799
|
+
try {
|
|
800
|
+
await fs.writeFile(
|
|
801
|
+
path.join(tmpDir, "package.json"),
|
|
802
|
+
JSON.stringify(unchangedPackageJson, null, 2),
|
|
803
|
+
);
|
|
804
|
+
await fs.writeFile(
|
|
805
|
+
path.join(tmpDir, "package-lock.json"),
|
|
806
|
+
JSON.stringify(privateRegistryLockfile, null, 2),
|
|
807
|
+
);
|
|
808
|
+
await fs.mkdir(path.join(tmpDir, "node_modules"));
|
|
809
|
+
await fs.writeFile(
|
|
810
|
+
path.join(tmpDir, "node_modules", ".package-lock.json"),
|
|
811
|
+
JSON.stringify(privateRegistryLockfile, null, 2),
|
|
812
|
+
);
|
|
813
|
+
const { readPackage } = await import("read-pkg");
|
|
814
|
+
(readPackage as Mock).mockImplementation(async ({ cwd }) =>
|
|
815
|
+
JSON.parse(await fs.readFile(path.join(cwd, "package.json"), "utf-8")),
|
|
816
|
+
);
|
|
817
|
+
const { dev } = await import("./dev.mjs");
|
|
818
|
+
|
|
819
|
+
await dev(
|
|
820
|
+
buildDevOptions({
|
|
821
|
+
cwd: tmpDir,
|
|
822
|
+
forcePackageInstall: false,
|
|
823
|
+
packageJsonSnapshotBeforeRestore:
|
|
824
|
+
packageJsonSnapshot(unchangedPackageJson),
|
|
825
|
+
}) as any,
|
|
826
|
+
);
|
|
827
|
+
|
|
828
|
+
expect(execMock).not.toHaveBeenCalled();
|
|
829
|
+
expect(mockLogger.info).toHaveBeenCalledWith(
|
|
830
|
+
"Package install decision",
|
|
831
|
+
expect.objectContaining({
|
|
832
|
+
packageInstallRequired: false,
|
|
833
|
+
privateRegistryRequiresInstallValidation: true,
|
|
834
|
+
lockfileAlreadyResolvesThroughRegistry: true,
|
|
835
|
+
}),
|
|
836
|
+
);
|
|
837
|
+
} finally {
|
|
838
|
+
await fs.rm(tmpDir, { recursive: true, force: true });
|
|
839
|
+
}
|
|
840
|
+
});
|
|
841
|
+
|
|
842
|
+
it("skips private registry validation install when scoped-only config has public unscoped dependencies", async () => {
|
|
843
|
+
const tmpDir = await fs.mkdtemp(
|
|
844
|
+
path.join(os.tmpdir(), "sdk-dev-private-registry-"),
|
|
709
845
|
);
|
|
846
|
+
mockAiServiceState.npmRegistryClient = {
|
|
847
|
+
getConfig: vi.fn(async () => ({
|
|
848
|
+
source: "configured",
|
|
849
|
+
config: {
|
|
850
|
+
configured: true,
|
|
851
|
+
scopes: {
|
|
852
|
+
"@superblocksteam": {
|
|
853
|
+
url: "https://scoped-registry.example.com/npm/",
|
|
854
|
+
},
|
|
855
|
+
},
|
|
856
|
+
},
|
|
857
|
+
})),
|
|
858
|
+
};
|
|
859
|
+
const unchangedPackageJson = {
|
|
860
|
+
name: "test-app",
|
|
861
|
+
dependencies: {
|
|
862
|
+
"@superblocksteam/library": "1.0.0",
|
|
863
|
+
leftpad: "1.0.0",
|
|
864
|
+
},
|
|
865
|
+
};
|
|
866
|
+
const mixedLockfile = {
|
|
867
|
+
name: "test-app",
|
|
868
|
+
lockfileVersion: 3,
|
|
869
|
+
packages: {
|
|
870
|
+
"node_modules/@superblocksteam/library": {
|
|
871
|
+
version: "1.0.0",
|
|
872
|
+
resolved:
|
|
873
|
+
"https://scoped-registry.example.com/npm/@superblocksteam/library/-/library-1.0.0.tgz",
|
|
874
|
+
},
|
|
875
|
+
"node_modules/leftpad": {
|
|
876
|
+
version: "1.0.0",
|
|
877
|
+
resolved: "https://registry.npmjs.org/leftpad/-/leftpad-1.0.0.tgz",
|
|
878
|
+
},
|
|
879
|
+
},
|
|
880
|
+
};
|
|
710
881
|
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
882
|
+
try {
|
|
883
|
+
await fs.writeFile(
|
|
884
|
+
path.join(tmpDir, "package.json"),
|
|
885
|
+
JSON.stringify(unchangedPackageJson, null, 2),
|
|
886
|
+
);
|
|
887
|
+
await fs.writeFile(
|
|
888
|
+
path.join(tmpDir, "package-lock.json"),
|
|
889
|
+
JSON.stringify(mixedLockfile, null, 2),
|
|
890
|
+
);
|
|
891
|
+
await fs.mkdir(path.join(tmpDir, "node_modules"));
|
|
892
|
+
await fs.writeFile(
|
|
893
|
+
path.join(tmpDir, "node_modules", ".package-lock.json"),
|
|
894
|
+
JSON.stringify(mixedLockfile, null, 2),
|
|
895
|
+
);
|
|
896
|
+
const { readPackage } = await import("read-pkg");
|
|
897
|
+
(readPackage as Mock).mockImplementation(async ({ cwd }) =>
|
|
898
|
+
JSON.parse(await fs.readFile(path.join(cwd, "package.json"), "utf-8")),
|
|
899
|
+
);
|
|
900
|
+
const { dev } = await import("./dev.mjs");
|
|
901
|
+
|
|
902
|
+
await dev(
|
|
903
|
+
buildDevOptions({
|
|
904
|
+
cwd: tmpDir,
|
|
905
|
+
forcePackageInstall: false,
|
|
906
|
+
packageJsonSnapshotBeforeRestore:
|
|
907
|
+
packageJsonSnapshot(unchangedPackageJson),
|
|
908
|
+
}) as any,
|
|
909
|
+
);
|
|
910
|
+
|
|
911
|
+
expect(execMock).not.toHaveBeenCalled();
|
|
912
|
+
expect(mockLogger.info).toHaveBeenCalledWith(
|
|
913
|
+
"Package install decision",
|
|
914
|
+
expect.objectContaining({
|
|
915
|
+
packageInstallRequired: false,
|
|
916
|
+
privateRegistryRequiresInstallValidation: true,
|
|
917
|
+
lockfileAlreadyResolvesThroughRegistry: true,
|
|
918
|
+
}),
|
|
919
|
+
);
|
|
920
|
+
} finally {
|
|
921
|
+
await fs.rm(tmpDir, { recursive: true, force: true });
|
|
922
|
+
}
|
|
923
|
+
});
|
|
924
|
+
|
|
925
|
+
it("runs private registry validation install when scoped lockfile resolves outside the scoped registry", async () => {
|
|
926
|
+
const tmpDir = await fs.mkdtemp(
|
|
927
|
+
path.join(os.tmpdir(), "sdk-dev-private-registry-"),
|
|
720
928
|
);
|
|
929
|
+
mockAiServiceState.npmRegistryClient = {
|
|
930
|
+
getConfig: vi.fn(async () => ({
|
|
931
|
+
source: "configured",
|
|
932
|
+
config: {
|
|
933
|
+
configured: true,
|
|
934
|
+
scopes: {
|
|
935
|
+
"@superblocksteam": {
|
|
936
|
+
url: "https://scoped-registry.example.com/npm/",
|
|
937
|
+
},
|
|
938
|
+
},
|
|
939
|
+
},
|
|
940
|
+
})),
|
|
941
|
+
};
|
|
942
|
+
const unchangedPackageJson = {
|
|
943
|
+
name: "test-app",
|
|
944
|
+
dependencies: { "@superblocksteam/library": "1.0.0" },
|
|
945
|
+
};
|
|
946
|
+
const publicRegistryLockfile = {
|
|
947
|
+
name: "test-app",
|
|
948
|
+
lockfileVersion: 3,
|
|
949
|
+
packages: {
|
|
950
|
+
"node_modules/@superblocksteam/library": {
|
|
951
|
+
version: "1.0.0",
|
|
952
|
+
resolved:
|
|
953
|
+
"https://registry.npmjs.org/@superblocksteam/library/-/library-1.0.0.tgz",
|
|
954
|
+
},
|
|
955
|
+
},
|
|
956
|
+
};
|
|
957
|
+
|
|
958
|
+
try {
|
|
959
|
+
await fs.writeFile(
|
|
960
|
+
path.join(tmpDir, "package.json"),
|
|
961
|
+
JSON.stringify(unchangedPackageJson, null, 2),
|
|
962
|
+
);
|
|
963
|
+
await fs.writeFile(
|
|
964
|
+
path.join(tmpDir, "package-lock.json"),
|
|
965
|
+
JSON.stringify(publicRegistryLockfile, null, 2),
|
|
966
|
+
);
|
|
967
|
+
await fs.mkdir(path.join(tmpDir, "node_modules"));
|
|
968
|
+
await fs.writeFile(
|
|
969
|
+
path.join(tmpDir, "node_modules", ".package-lock.json"),
|
|
970
|
+
JSON.stringify(publicRegistryLockfile, null, 2),
|
|
971
|
+
);
|
|
972
|
+
const { readPackage } = await import("read-pkg");
|
|
973
|
+
(readPackage as Mock).mockImplementation(async ({ cwd }) =>
|
|
974
|
+
JSON.parse(await fs.readFile(path.join(cwd, "package.json"), "utf-8")),
|
|
975
|
+
);
|
|
976
|
+
const { dev } = await import("./dev.mjs");
|
|
977
|
+
|
|
978
|
+
await dev(
|
|
979
|
+
buildDevOptions({
|
|
980
|
+
cwd: tmpDir,
|
|
981
|
+
forcePackageInstall: false,
|
|
982
|
+
packageJsonSnapshotBeforeRestore:
|
|
983
|
+
packageJsonSnapshot(unchangedPackageJson),
|
|
984
|
+
}) as any,
|
|
985
|
+
);
|
|
986
|
+
|
|
987
|
+
expectInstallToHaveRun();
|
|
988
|
+
expect(mockLogger.info).toHaveBeenCalledWith(
|
|
989
|
+
"Package install decision",
|
|
990
|
+
expect.objectContaining({
|
|
991
|
+
packageInstallRequired: true,
|
|
992
|
+
privateRegistryRequiresInstallValidation: true,
|
|
993
|
+
lockfileAlreadyResolvesThroughRegistry: false,
|
|
994
|
+
}),
|
|
995
|
+
);
|
|
996
|
+
} finally {
|
|
997
|
+
await fs.rm(tmpDir, { recursive: true, force: true });
|
|
998
|
+
}
|
|
721
999
|
});
|
|
722
1000
|
|
|
723
|
-
it("
|
|
1001
|
+
it("runs private registry validation install when node_modules lockfile is missing", async () => {
|
|
1002
|
+
const tmpDir = await fs.mkdtemp(
|
|
1003
|
+
path.join(os.tmpdir(), "sdk-dev-private-registry-"),
|
|
1004
|
+
);
|
|
1005
|
+
mockAiServiceState.npmRegistryClient = {
|
|
1006
|
+
getConfig: vi.fn(async () => ({
|
|
1007
|
+
source: "configured",
|
|
1008
|
+
config: {
|
|
1009
|
+
configured: true,
|
|
1010
|
+
default: { url: "https://registry.example.com/npm/" },
|
|
1011
|
+
},
|
|
1012
|
+
})),
|
|
1013
|
+
};
|
|
1014
|
+
const unchangedPackageJson = {
|
|
1015
|
+
name: "test-app",
|
|
1016
|
+
dependencies: { leftpad: "1.0.0" },
|
|
1017
|
+
};
|
|
1018
|
+
const privateRegistryLockfile = {
|
|
1019
|
+
name: "test-app",
|
|
1020
|
+
lockfileVersion: 3,
|
|
1021
|
+
packages: {
|
|
1022
|
+
"node_modules/leftpad": {
|
|
1023
|
+
version: "1.0.0",
|
|
1024
|
+
resolved:
|
|
1025
|
+
"https://registry.example.com/npm/leftpad/-/leftpad-1.0.0.tgz",
|
|
1026
|
+
},
|
|
1027
|
+
},
|
|
1028
|
+
};
|
|
1029
|
+
|
|
1030
|
+
try {
|
|
1031
|
+
await fs.writeFile(
|
|
1032
|
+
path.join(tmpDir, "package.json"),
|
|
1033
|
+
JSON.stringify(unchangedPackageJson, null, 2),
|
|
1034
|
+
);
|
|
1035
|
+
await fs.writeFile(
|
|
1036
|
+
path.join(tmpDir, "package-lock.json"),
|
|
1037
|
+
JSON.stringify(privateRegistryLockfile, null, 2),
|
|
1038
|
+
);
|
|
1039
|
+
const { readPackage } = await import("read-pkg");
|
|
1040
|
+
(readPackage as Mock).mockImplementation(async ({ cwd }) =>
|
|
1041
|
+
JSON.parse(await fs.readFile(path.join(cwd, "package.json"), "utf-8")),
|
|
1042
|
+
);
|
|
1043
|
+
const { dev } = await import("./dev.mjs");
|
|
1044
|
+
|
|
1045
|
+
await dev(
|
|
1046
|
+
buildDevOptions({
|
|
1047
|
+
cwd: tmpDir,
|
|
1048
|
+
forcePackageInstall: false,
|
|
1049
|
+
packageJsonSnapshotBeforeRestore:
|
|
1050
|
+
packageJsonSnapshot(unchangedPackageJson),
|
|
1051
|
+
}) as any,
|
|
1052
|
+
);
|
|
1053
|
+
|
|
1054
|
+
expectInstallToHaveRun();
|
|
1055
|
+
expect(mockLogger.info).toHaveBeenCalledWith(
|
|
1056
|
+
"Package install decision",
|
|
1057
|
+
expect.objectContaining({
|
|
1058
|
+
packageInstallRequired: true,
|
|
1059
|
+
forcePackageInstall: false,
|
|
1060
|
+
forcePackageInstallRequested: false,
|
|
1061
|
+
packageJsonRequiresInstall: false,
|
|
1062
|
+
privateRegistryRequiresInstallValidation: true,
|
|
1063
|
+
lockfileAlreadyResolvesThroughRegistry: false,
|
|
1064
|
+
}),
|
|
1065
|
+
);
|
|
1066
|
+
} finally {
|
|
1067
|
+
await fs.rm(tmpDir, { recursive: true, force: true });
|
|
1068
|
+
}
|
|
1069
|
+
});
|
|
1070
|
+
|
|
1071
|
+
it("runs private registry validation install and warns when lockfile registry proof is malformed", async () => {
|
|
1072
|
+
const tmpDir = await fs.mkdtemp(
|
|
1073
|
+
path.join(os.tmpdir(), "sdk-dev-private-registry-"),
|
|
1074
|
+
);
|
|
1075
|
+
mockAiServiceState.npmRegistryClient = {
|
|
1076
|
+
getConfig: vi.fn(async () => ({
|
|
1077
|
+
source: "configured",
|
|
1078
|
+
config: {
|
|
1079
|
+
configured: true,
|
|
1080
|
+
default: { url: "https://registry.example.com/npm/" },
|
|
1081
|
+
},
|
|
1082
|
+
})),
|
|
1083
|
+
};
|
|
1084
|
+
const unchangedPackageJson = {
|
|
1085
|
+
name: "test-app",
|
|
1086
|
+
dependencies: { leftpad: "1.0.0" },
|
|
1087
|
+
};
|
|
1088
|
+
|
|
1089
|
+
try {
|
|
1090
|
+
await fs.writeFile(
|
|
1091
|
+
path.join(tmpDir, "package.json"),
|
|
1092
|
+
JSON.stringify(unchangedPackageJson, null, 2),
|
|
1093
|
+
);
|
|
1094
|
+
await fs.writeFile(path.join(tmpDir, "package-lock.json"), "{");
|
|
1095
|
+
await fs.mkdir(path.join(tmpDir, "node_modules"));
|
|
1096
|
+
await fs.writeFile(
|
|
1097
|
+
path.join(tmpDir, "node_modules", ".package-lock.json"),
|
|
1098
|
+
"{",
|
|
1099
|
+
);
|
|
1100
|
+
const { readPackage } = await import("read-pkg");
|
|
1101
|
+
(readPackage as Mock).mockImplementation(async ({ cwd }) =>
|
|
1102
|
+
JSON.parse(await fs.readFile(path.join(cwd, "package.json"), "utf-8")),
|
|
1103
|
+
);
|
|
1104
|
+
const { dev } = await import("./dev.mjs");
|
|
1105
|
+
|
|
1106
|
+
await dev(
|
|
1107
|
+
buildDevOptions({
|
|
1108
|
+
cwd: tmpDir,
|
|
1109
|
+
forcePackageInstall: false,
|
|
1110
|
+
packageJsonSnapshotBeforeRestore:
|
|
1111
|
+
packageJsonSnapshot(unchangedPackageJson),
|
|
1112
|
+
}) as any,
|
|
1113
|
+
);
|
|
1114
|
+
|
|
1115
|
+
expectInstallToHaveRun();
|
|
1116
|
+
expect(mockLogger.warn).toHaveBeenCalledWith(
|
|
1117
|
+
"Failed to parse package-lock.json for private registry skip check; falling back to install",
|
|
1118
|
+
expect.any(Object),
|
|
1119
|
+
);
|
|
1120
|
+
} finally {
|
|
1121
|
+
await fs.rm(tmpDir, { recursive: true, force: true });
|
|
1122
|
+
}
|
|
1123
|
+
});
|
|
1124
|
+
|
|
1125
|
+
it("runs npm install when private registry validation is the only trigger without registry-resolved lockfile entries", async () => {
|
|
724
1126
|
const tmpDir = await fs.mkdtemp(
|
|
725
1127
|
path.join(os.tmpdir(), "sdk-dev-private-registry-"),
|
|
726
1128
|
);
|
|
@@ -747,7 +1149,10 @@ describe("dev startup after S3 workspace restore", () => {
|
|
|
747
1149
|
mockAiServiceState.npmRegistryClient = {
|
|
748
1150
|
getConfig: vi.fn(async () => ({
|
|
749
1151
|
source: "configured",
|
|
750
|
-
config: {
|
|
1152
|
+
config: {
|
|
1153
|
+
configured: true,
|
|
1154
|
+
default: { url: "https://registry.example.com/" },
|
|
1155
|
+
},
|
|
751
1156
|
})),
|
|
752
1157
|
};
|
|
753
1158
|
const { dev } = await import("./dev.mjs");
|
|
@@ -769,7 +1174,7 @@ describe("dev startup after S3 workspace restore", () => {
|
|
|
769
1174
|
}
|
|
770
1175
|
});
|
|
771
1176
|
|
|
772
|
-
it("does
|
|
1177
|
+
it("does not upload package state when private registry validation only rewrites `resolved` URLs", async () => {
|
|
773
1178
|
// The exact churn cycle flagged in review: `stripResolvedFromLockfile`
|
|
774
1179
|
// removes every `resolved` URL before the install and npm writes them
|
|
775
1180
|
// back, so a byte-level comparison would flag "changed" on EVERY
|
|
@@ -820,7 +1225,10 @@ describe("dev startup after S3 workspace restore", () => {
|
|
|
820
1225
|
mockAiServiceState.npmRegistryClient = {
|
|
821
1226
|
getConfig: vi.fn(async () => ({
|
|
822
1227
|
source: "configured",
|
|
823
|
-
config: {
|
|
1228
|
+
config: {
|
|
1229
|
+
configured: true,
|
|
1230
|
+
default: { url: "https://registry.example.com/" },
|
|
1231
|
+
},
|
|
824
1232
|
})),
|
|
825
1233
|
};
|
|
826
1234
|
execMock.mockImplementation(
|
|
@@ -837,6 +1245,12 @@ describe("dev startup after S3 workspace restore", () => {
|
|
|
837
1245
|
path.join(cwd ?? tmpDir, "package-lock.json"),
|
|
838
1246
|
JSON.stringify(rewrittenLockfile, null, 2),
|
|
839
1247
|
)
|
|
1248
|
+
.then(() =>
|
|
1249
|
+
fs.writeFile(
|
|
1250
|
+
path.join(cwd ?? tmpDir, "node_modules", ".package-lock.json"),
|
|
1251
|
+
JSON.stringify(rewrittenLockfile, null, 2),
|
|
1252
|
+
),
|
|
1253
|
+
)
|
|
840
1254
|
.then(() => {
|
|
841
1255
|
if (typeof opts === "function") {
|
|
842
1256
|
opts(null, { stdout: "installed" });
|
|
@@ -860,15 +1274,34 @@ describe("dev startup after S3 workspace restore", () => {
|
|
|
860
1274
|
expectInstallToHaveRun();
|
|
861
1275
|
expect(mockSyncService.uploadDirectory).not.toHaveBeenCalled();
|
|
862
1276
|
expect(mockSyncService.uploadDirectoryNowIfNeeded).not.toHaveBeenCalled();
|
|
1277
|
+
|
|
1278
|
+
execMock.mockClear();
|
|
1279
|
+
vi.resetModules();
|
|
1280
|
+
const { dev: devAfterRestart } = await import("./dev.mjs");
|
|
1281
|
+
await devAfterRestart(
|
|
1282
|
+
buildDevOptions({
|
|
1283
|
+
cwd: tmpDir,
|
|
1284
|
+
forcePackageInstall: false,
|
|
1285
|
+
packageJsonSnapshotBeforeRestore:
|
|
1286
|
+
packageJsonSnapshot(unchangedPackageJson),
|
|
1287
|
+
}) as any,
|
|
1288
|
+
);
|
|
1289
|
+
|
|
1290
|
+
expect(execMock).not.toHaveBeenCalled();
|
|
863
1291
|
} finally {
|
|
864
1292
|
await fs.rm(tmpDir, { recursive: true, force: true });
|
|
865
1293
|
}
|
|
866
1294
|
});
|
|
867
1295
|
|
|
868
|
-
it("uploads package state when private registry validation
|
|
1296
|
+
it("uploads package state when private registry validation rewrites the lockfile during a required install", async () => {
|
|
869
1297
|
const tmpDir = await fs.mkdtemp(
|
|
870
1298
|
path.join(os.tmpdir(), "sdk-dev-private-registry-"),
|
|
871
1299
|
);
|
|
1300
|
+
const previousPackageJson = {
|
|
1301
|
+
name: "test-app",
|
|
1302
|
+
packageManager: "npm@10.0.0",
|
|
1303
|
+
dependencies: { "@superblocksteam/library": "0.9.0" },
|
|
1304
|
+
};
|
|
872
1305
|
const unchangedPackageJson = {
|
|
873
1306
|
name: "test-app",
|
|
874
1307
|
packageManager: "npm@10.0.0",
|
|
@@ -929,7 +1362,7 @@ describe("dev startup after S3 workspace restore", () => {
|
|
|
929
1362
|
cwd: tmpDir,
|
|
930
1363
|
forcePackageInstall: false,
|
|
931
1364
|
packageJsonSnapshotBeforeRestore:
|
|
932
|
-
packageJsonSnapshot(
|
|
1365
|
+
packageJsonSnapshot(previousPackageJson),
|
|
933
1366
|
}) as any,
|
|
934
1367
|
);
|
|
935
1368
|
|
|
@@ -1242,9 +1675,13 @@ describe("dev background package install join semantics", () => {
|
|
|
1242
1675
|
// catch wrongly swallowed the rejection. A rejecting upgrade promise
|
|
1243
1676
|
// surfaces a generic Error (not InitialInstallFailed), so the local catch
|
|
1244
1677
|
// must rethrow.
|
|
1678
|
+
const upgradeFailure = Promise.reject(
|
|
1679
|
+
new Error("simulated upgrade failure"),
|
|
1680
|
+
);
|
|
1681
|
+
upgradeFailure.catch(() => undefined);
|
|
1245
1682
|
mockCheckVersions.mockResolvedValue({
|
|
1246
1683
|
cliUpdated: true,
|
|
1247
|
-
upgradePromises: [
|
|
1684
|
+
upgradePromises: [upgradeFailure],
|
|
1248
1685
|
});
|
|
1249
1686
|
|
|
1250
1687
|
const originalExit = process.exit;
|
|
@@ -115,7 +115,6 @@ vi.mock("@superblocksteam/util", () => ({
|
|
|
115
115
|
vi.mock("@superblocksteam/vite-plugin-file-sync/ai-service", () => ({
|
|
116
116
|
AiService: class {
|
|
117
117
|
initialize = vi.fn(async () => undefined);
|
|
118
|
-
notifyMigrationAppArtifactsReady = vi.fn();
|
|
119
118
|
removeIntegrationCache = vi.fn(async () => undefined);
|
|
120
119
|
chatSessionStore = { invalidateCache: vi.fn() };
|
|
121
120
|
getNpmRegistryClient = vi.fn(() => undefined);
|