@superblocksteam/sdk 2.0.108-next.0 → 2.0.109-next.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.
@@ -1,4 +1,4 @@
1
1
 
2
- > @superblocksteam/sdk@2.0.108-next.0 build /home/runner/work/superblocks/superblocks/packages/cli/packages/sdk
2
+ > @superblocksteam/sdk@2.0.109-next.0 build /home/runner/work/superblocks/superblocks/packages/cli/packages/sdk
3
3
  > tsc --build
4
4
 
@@ -2,15 +2,9 @@ import type { Plugin } from "vite";
2
2
  /**
3
3
  * Vite plugin that generates a build manifest for the application.
4
4
  *
5
- * This plugin will:
6
- * 1. Read all api.yaml and api.yml files in the application
7
- * 2. Read all scope.ts files in the application
8
- * 3. Generate a build manifest for the application
9
- * 4. Write the build manifest to a file in the build output directory
10
- *
11
- * The build manifest is a JSON object with the following properties:
12
- * - apis: a map of all apis in the application keyed by their file path
13
- * - apiDependencies: an array where each item represents an api and its dependencies
5
+ * Collects all API metadata in buildStart, then serves the real manifest
6
+ * content via the load hook. This ensures Rollup's content hash reflects
7
+ * the actual manifest data rather than the placeholder stub file.
14
8
  *
15
9
  * @param root - The root directory of the application
16
10
  * @returns A Vite plugin that generates a build manifest for the application
@@ -1 +1 @@
1
- {"version":3,"file":"vite-plugin-generate-api-build-manifest.d.mts","sourceRoot":"","sources":["../src/vite-plugin-generate-api-build-manifest.mts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AAqBnC;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,8BAA8B,CAAC,IAAI,EAAE,MAAM,GAuGpD,MAAM,CACZ"}
1
+ {"version":3,"file":"vite-plugin-generate-api-build-manifest.d.mts","sourceRoot":"","sources":["../src/vite-plugin-generate-api-build-manifest.mts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AA+BnC;;;;;;;;;GASG;AACH,wBAAgB,8BAA8B,CAAC,IAAI,EAAE,MAAM,GA0FpD,MAAM,CACZ"}
@@ -9,18 +9,20 @@ import { resolveLanguageSpecificStepContentFromBlocks } from "@superblocksteam/u
9
9
  import { getPageName, getScopeIdFromName, } from "@superblocksteam/vite-plugin-file-sync";
10
10
  import { collectSdkApisFromRegistry } from "./collect-sdk-apis.mjs";
11
11
  import { getLogger } from "./telemetry/logging.js";
12
+ const BUILD_MANIFEST_SUFFIX = path.join("lib", "user-facing", "build-manifest.js");
13
+ // tsdown (library bundler) outputs hashed filenames like build-manifest-BOqMhObV.js
14
+ // in a flattened dist/ directory. Match both the original source path and the
15
+ // hashed dist path so the load hook can replace the placeholder content.
16
+ const BUILD_MANIFEST_HASHED_RE = /[\\/]build-manifest(?:-[A-Za-z0-9]+)?\.js$/;
17
+ function isBuildManifestModule(id) {
18
+ return (id.endsWith(BUILD_MANIFEST_SUFFIX) || BUILD_MANIFEST_HASHED_RE.test(id));
19
+ }
12
20
  /**
13
21
  * Vite plugin that generates a build manifest for the application.
14
22
  *
15
- * This plugin will:
16
- * 1. Read all api.yaml and api.yml files in the application
17
- * 2. Read all scope.ts files in the application
18
- * 3. Generate a build manifest for the application
19
- * 4. Write the build manifest to a file in the build output directory
20
- *
21
- * The build manifest is a JSON object with the following properties:
22
- * - apis: a map of all apis in the application keyed by their file path
23
- * - apiDependencies: an array where each item represents an api and its dependencies
23
+ * Collects all API metadata in buildStart, then serves the real manifest
24
+ * content via the load hook. This ensures Rollup's content hash reflects
25
+ * the actual manifest data rather than the placeholder stub file.
24
26
  *
25
27
  * @param root - The root directory of the application
26
28
  * @returns A Vite plugin that generates a build manifest for the application
@@ -41,28 +43,26 @@ export function generateApiBuildManifestPlugin(root) {
41
43
  viteLogger.clearScreen = () => { };
42
44
  const sdkApiEnabled = isSdkApiTemplate(process.env.SUPERBLOCKS_APP_TEMPLATE_NAME);
43
45
  const apiFiles = {};
44
- let buildManifest = { apis: {}, apiDependencies: [], sdkApis: {} };
46
+ let manifestCode = "export default {};";
45
47
  return {
46
48
  name: "sb-generate-build-manifest",
47
49
  apply: "build",
48
50
  enforce: "pre",
49
51
  async buildStart() {
50
- if (sdkApiEnabled)
51
- return;
52
- const apiDocuments = await fg(["**/api.yaml", "**/api.yml"], {
53
- cwd: root,
54
- });
55
- for (const apiFilePath of apiDocuments) {
56
- const absoluteApiFilePath = path.join(root, apiFilePath);
57
- const document = await fs.readFile(absoluteApiFilePath, "utf-8");
58
- const apiPb = yaml.parse(document);
59
- await resolveLanguageSpecificStepContentFromBlocks(path.dirname(absoluteApiFilePath), apiPb.blocks ?? [], {});
60
- const pageName = getPageName(apiFilePath);
61
- apiPb.metadata.id = apiPb.metadata.name;
62
- apiFiles[apiFilePath] = { apiPb, pageName };
52
+ if (!sdkApiEnabled) {
53
+ const apiDocuments = await fg(["**/api.yaml", "**/api.yml"], {
54
+ cwd: root,
55
+ });
56
+ for (const apiFilePath of apiDocuments) {
57
+ const absoluteApiFilePath = path.join(root, apiFilePath);
58
+ const document = await fs.readFile(absoluteApiFilePath, "utf-8");
59
+ const apiPb = yaml.parse(document);
60
+ await resolveLanguageSpecificStepContentFromBlocks(path.dirname(absoluteApiFilePath), apiPb.blocks ?? [], {});
61
+ const pageName = getPageName(apiFilePath);
62
+ apiPb.metadata.id = apiPb.metadata.name;
63
+ apiFiles[apiFilePath] = { apiPb, pageName };
64
+ }
63
65
  }
64
- },
65
- async generateBundle(_options, bundle) {
66
66
  const allApis = Object.entries(apiFiles).reduce((acc, [id, api]) => {
67
67
  acc[id] = {
68
68
  api,
@@ -76,22 +76,21 @@ export function generateApiBuildManifestPlugin(root) {
76
76
  readFile: (p, enc) => fs.readFile(p, enc),
77
77
  })
78
78
  : {};
79
- buildManifest = {
79
+ manifestCode = `export default ${JSON.stringify({
80
80
  apis: allApis,
81
81
  apiDependencies: [],
82
82
  sdkApis,
83
- };
84
- // Find the existing hashed build-manifest file in the bundle and replace its content
85
- for (const [fileName, chunk] of Object.entries(bundle)) {
86
- // Look for build-manifest files specifically in the assets folder
87
- if (fileName.startsWith("assets/build-manifest") &&
88
- fileName.endsWith(".js")) {
89
- // This is the hashed build-manifest file, replace its content
90
- if (chunk.type === "chunk") {
91
- chunk.code =
92
- `export default ${JSON.stringify(buildManifest)};`;
93
- }
94
- }
83
+ })};`;
84
+ },
85
+ load(id) {
86
+ if (isBuildManifestModule(id)) {
87
+ return manifestCode;
88
+ }
89
+ },
90
+ augmentChunkHash(chunkInfo) {
91
+ const hasBuildManifest = Object.keys(chunkInfo.modules).some(isBuildManifestModule);
92
+ if (hasBuildManifest) {
93
+ return manifestCode;
95
94
  }
96
95
  },
97
96
  };
@@ -1 +1 @@
1
- {"version":3,"file":"vite-plugin-generate-api-build-manifest.mjs","sourceRoot":"","sources":["../src/vite-plugin-generate-api-build-manifest.mts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"vite-plugin-generate-api-build-manifest.mjs","sourceRoot":"","sources":["../src/vite-plugin-generate-api-build-manifest.mts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@superblocksteam/sdk",
3
- "version": "2.0.108-next.0",
3
+ "version": "2.0.109-next.0",
4
4
  "description": "Superblocks JS SDK",
5
5
  "homepage": "https://www.superblocks.com",
6
6
  "license": "Superblocks Community Software License",
@@ -48,11 +48,11 @@
48
48
  "vite-tsconfig-paths": "^6.0.4",
49
49
  "winston": "^3.17.0",
50
50
  "yaml": "^2.7.1",
51
- "@superblocksteam/library-shared": "2.0.108-next.0",
52
- "@superblocksteam/shared": "0.9578.11",
53
- "@superblocksteam/telemetry": "2.0.108-next.0",
54
- "@superblocksteam/util": "2.0.108-next.0",
55
- "@superblocksteam/vite-plugin-file-sync": "2.0.108-next.0"
51
+ "@superblocksteam/library-shared": "2.0.109-next.0",
52
+ "@superblocksteam/shared": "0.9578.12",
53
+ "@superblocksteam/telemetry": "2.0.109-next.0",
54
+ "@superblocksteam/util": "2.0.109-next.0",
55
+ "@superblocksteam/vite-plugin-file-sync": "2.0.109-next.0"
56
56
  },
57
57
  "devDependencies": {
58
58
  "@eslint/js": "^9.39.2",
@@ -18,25 +18,29 @@ import {
18
18
  import { collectSdkApisFromRegistry } from "./collect-sdk-apis.mjs";
19
19
  import { getLogger } from "./telemetry/logging.js";
20
20
 
21
- type ApiDependency = {
22
- apiName: string;
23
- scopeId: string;
24
- params: string[];
25
- dependencies: string[];
26
- };
21
+ const BUILD_MANIFEST_SUFFIX = path.join(
22
+ "lib",
23
+ "user-facing",
24
+ "build-manifest.js",
25
+ );
26
+
27
+ // tsdown (library bundler) outputs hashed filenames like build-manifest-BOqMhObV.js
28
+ // in a flattened dist/ directory. Match both the original source path and the
29
+ // hashed dist path so the load hook can replace the placeholder content.
30
+ const BUILD_MANIFEST_HASHED_RE = /[\\/]build-manifest(?:-[A-Za-z0-9]+)?\.js$/;
31
+
32
+ function isBuildManifestModule(id: string): boolean {
33
+ return (
34
+ id.endsWith(BUILD_MANIFEST_SUFFIX) || BUILD_MANIFEST_HASHED_RE.test(id)
35
+ );
36
+ }
27
37
 
28
38
  /**
29
39
  * Vite plugin that generates a build manifest for the application.
30
40
  *
31
- * This plugin will:
32
- * 1. Read all api.yaml and api.yml files in the application
33
- * 2. Read all scope.ts files in the application
34
- * 3. Generate a build manifest for the application
35
- * 4. Write the build manifest to a file in the build output directory
36
- *
37
- * The build manifest is a JSON object with the following properties:
38
- * - apis: a map of all apis in the application keyed by their file path
39
- * - apiDependencies: an array where each item represents an api and its dependencies
41
+ * Collects all API metadata in buildStart, then serves the real manifest
42
+ * content via the load hook. This ensures Rollup's content hash reflects
43
+ * the actual manifest data rather than the placeholder stub file.
40
44
  *
41
45
  * @param root - The root directory of the application
42
46
  * @returns A Vite plugin that generates a build manifest for the application
@@ -61,18 +65,7 @@ export function generateApiBuildManifestPlugin(root: string) {
61
65
  process.env.SUPERBLOCKS_APP_TEMPLATE_NAME,
62
66
  );
63
67
  const apiFiles: Record<string, DeleteMeLibraryApi> = {};
64
- let buildManifest: {
65
- apis: Record<string, { api: DeleteMeLibraryApi; scopeId: string }>;
66
- apiDependencies: ApiDependency[];
67
- sdkApis: Record<
68
- string,
69
- {
70
- entryPoint: string;
71
- exportName?: string;
72
- integrations?: Array<{ key: string; pluginId: string; id: string }>;
73
- }
74
- >;
75
- } = { apis: {}, apiDependencies: [], sdkApis: {} };
68
+ let manifestCode = "export default {};";
76
69
 
77
70
  return {
78
71
  name: "sb-generate-build-manifest",
@@ -80,31 +73,29 @@ export function generateApiBuildManifestPlugin(root: string) {
80
73
  enforce: "pre",
81
74
 
82
75
  async buildStart() {
83
- if (sdkApiEnabled) return;
84
-
85
- const apiDocuments = await fg(["**/api.yaml", "**/api.yml"], {
86
- cwd: root,
87
- });
88
-
89
- for (const apiFilePath of apiDocuments) {
90
- const absoluteApiFilePath = path.join(root, apiFilePath);
91
-
92
- const document = await fs.readFile(absoluteApiFilePath, "utf-8");
93
- const apiPb = yaml.parse(document);
94
-
95
- await resolveLanguageSpecificStepContentFromBlocks(
96
- path.dirname(absoluteApiFilePath),
97
- apiPb.blocks ?? [],
98
- {},
99
- );
100
-
101
- const pageName = getPageName(apiFilePath);
102
- apiPb.metadata.id = apiPb.metadata.name;
103
- apiFiles[apiFilePath] = { apiPb, pageName };
76
+ if (!sdkApiEnabled) {
77
+ const apiDocuments = await fg(["**/api.yaml", "**/api.yml"], {
78
+ cwd: root,
79
+ });
80
+
81
+ for (const apiFilePath of apiDocuments) {
82
+ const absoluteApiFilePath = path.join(root, apiFilePath);
83
+
84
+ const document = await fs.readFile(absoluteApiFilePath, "utf-8");
85
+ const apiPb = yaml.parse(document);
86
+
87
+ await resolveLanguageSpecificStepContentFromBlocks(
88
+ path.dirname(absoluteApiFilePath),
89
+ apiPb.blocks ?? [],
90
+ {},
91
+ );
92
+
93
+ const pageName = getPageName(apiFilePath);
94
+ apiPb.metadata.id = apiPb.metadata.name;
95
+ apiFiles[apiFilePath] = { apiPb, pageName };
96
+ }
104
97
  }
105
- },
106
98
 
107
- async generateBundle(_options: any, bundle: any) {
108
99
  const allApis = Object.entries(apiFiles).reduce(
109
100
  (acc, [id, api]) => {
110
101
  acc[id] = {
@@ -123,25 +114,25 @@ export function generateApiBuildManifestPlugin(root: string) {
123
114
  })
124
115
  : {};
125
116
 
126
- buildManifest = {
117
+ manifestCode = `export default ${JSON.stringify({
127
118
  apis: allApis,
128
119
  apiDependencies: [],
129
120
  sdkApis,
130
- };
131
-
132
- // Find the existing hashed build-manifest file in the bundle and replace its content
133
- for (const [fileName, chunk] of Object.entries(bundle)) {
134
- // Look for build-manifest files specifically in the assets folder
135
- if (
136
- fileName.startsWith("assets/build-manifest") &&
137
- fileName.endsWith(".js")
138
- ) {
139
- // This is the hashed build-manifest file, replace its content
140
- if ((chunk as any).type === "chunk") {
141
- (chunk as any).code =
142
- `export default ${JSON.stringify(buildManifest)};`;
143
- }
144
- }
121
+ })};`;
122
+ },
123
+
124
+ load(id: string) {
125
+ if (isBuildManifestModule(id)) {
126
+ return manifestCode;
127
+ }
128
+ },
129
+
130
+ augmentChunkHash(chunkInfo: { modules: Record<string, unknown> }) {
131
+ const hasBuildManifest = Object.keys(chunkInfo.modules).some(
132
+ isBuildManifestModule,
133
+ );
134
+ if (hasBuildManifest) {
135
+ return manifestCode;
145
136
  }
146
137
  },
147
138
  } as Plugin;
@@ -0,0 +1,264 @@
1
+ import { beforeEach, describe, expect, it, vi } from "vitest";
2
+
3
+ vi.mock("fs-extra", () => ({
4
+ default: {
5
+ pathExists: vi.fn(),
6
+ readFile: vi.fn(),
7
+ },
8
+ }));
9
+
10
+ vi.mock("fast-glob", () => ({
11
+ default: vi.fn().mockResolvedValue([]),
12
+ }));
13
+
14
+ vi.mock("@superblocksteam/shared", () => ({
15
+ isSdkApiTemplate: vi.fn().mockReturnValue(false),
16
+ }));
17
+
18
+ vi.mock("@superblocksteam/util", () => ({
19
+ resolveLanguageSpecificStepContentFromBlocks: vi.fn(),
20
+ }));
21
+
22
+ vi.mock("@superblocksteam/vite-plugin-file-sync", () => ({
23
+ getPageName: vi.fn().mockReturnValue("App"),
24
+ getScopeIdFromName: vi.fn().mockReturnValue("scope-app"),
25
+ }));
26
+
27
+ vi.mock("../src/collect-sdk-apis.mjs", () => ({
28
+ collectSdkApisFromRegistry: vi.fn().mockResolvedValue({}),
29
+ }));
30
+
31
+ vi.mock("../src/telemetry/logging.js", () => ({
32
+ getLogger: () => ({
33
+ info: vi.fn(),
34
+ warn: vi.fn(),
35
+ error: vi.fn(),
36
+ }),
37
+ }));
38
+
39
+ const { generateApiBuildManifestPlugin } =
40
+ await import("../src/vite-plugin-generate-api-build-manifest.mjs");
41
+ const fg = (await import("fast-glob")).default as unknown as ReturnType<
42
+ typeof vi.fn
43
+ >;
44
+ const fs = (await import("fs-extra")).default;
45
+ const { isSdkApiTemplate } = await import("@superblocksteam/shared");
46
+ const { collectSdkApisFromRegistry } =
47
+ await import("../src/collect-sdk-apis.mjs");
48
+
49
+ describe("generateApiBuildManifestPlugin", () => {
50
+ const ROOT = "/app";
51
+
52
+ beforeEach(() => {
53
+ vi.clearAllMocks();
54
+ vi.mocked(isSdkApiTemplate).mockReturnValue(false);
55
+ });
56
+
57
+ function getPlugin() {
58
+ return generateApiBuildManifestPlugin(ROOT) as any;
59
+ }
60
+
61
+ describe("load hook returns real manifest content so Rollup content-hashes it", () => {
62
+ it("returns manifest JSON for build-manifest.js module IDs", async () => {
63
+ const plugin = getPlugin();
64
+ await plugin.buildStart();
65
+
66
+ const id = "/some/path/lib/user-facing/build-manifest.js";
67
+ const result = plugin.load(id);
68
+
69
+ expect(result).toBeDefined();
70
+ expect(result).toContain("export default ");
71
+ const parsed = JSON.parse(
72
+ result.replace("export default ", "").replace(";", ""),
73
+ );
74
+ expect(parsed).toHaveProperty("apis");
75
+ expect(parsed).toHaveProperty("apiDependencies");
76
+ expect(parsed).toHaveProperty("sdkApis");
77
+ });
78
+
79
+ it("returns manifest JSON for hashed dist build-manifest module IDs", async () => {
80
+ fg.mockResolvedValue(["pages/App/apis/GetUsers/api.yaml"]);
81
+ vi.mocked(fs.readFile as any).mockResolvedValue(
82
+ "metadata:\n name: GetUsers\nblocks: []\n",
83
+ );
84
+
85
+ const plugin = getPlugin();
86
+ await plugin.buildStart();
87
+
88
+ const id =
89
+ "/node_modules/@superblocksteam/library/dist/build-manifest-BOqMhObV.js";
90
+ const result = plugin.load(id);
91
+
92
+ expect(result).toBeDefined();
93
+ expect(result).toContain("export default ");
94
+ const parsed = JSON.parse(
95
+ result.replace("export default ", "").replace(";", ""),
96
+ );
97
+ expect(parsed).toHaveProperty("apis");
98
+ expect(Object.keys(parsed.apis)).toContain(
99
+ "pages/App/apis/GetUsers/api.yaml",
100
+ );
101
+ });
102
+
103
+ it("does not intercept unrelated module IDs", async () => {
104
+ const plugin = getPlugin();
105
+ await plugin.buildStart();
106
+
107
+ expect(plugin.load("/some/other/module.js")).toBeUndefined();
108
+ expect(plugin.load("/foo/bar/manifest.js")).toBeUndefined();
109
+ });
110
+
111
+ it("includes YAML API data in the manifest when YAML files exist", async () => {
112
+ fg.mockResolvedValue(["pages/App/apis/GetUsers/api.yaml"]);
113
+ vi.mocked(fs.readFile as any).mockResolvedValue(
114
+ "metadata:\n name: GetUsers\nblocks: []\n",
115
+ );
116
+
117
+ const plugin = getPlugin();
118
+ await plugin.buildStart();
119
+
120
+ const result = plugin.load(
121
+ "/node_modules/@superblocksteam/library/src/lib/user-facing/build-manifest.js",
122
+ );
123
+ const parsed = JSON.parse(
124
+ result.replace("export default ", "").replace(";", ""),
125
+ );
126
+ expect(Object.keys(parsed.apis)).toContain(
127
+ "pages/App/apis/GetUsers/api.yaml",
128
+ );
129
+ });
130
+
131
+ it("includes SDK API data when SDK template is enabled", async () => {
132
+ vi.mocked(isSdkApiTemplate).mockReturnValue(true);
133
+ vi.mocked(collectSdkApisFromRegistry as any).mockResolvedValue({
134
+ GetUsers: {
135
+ entryPoint: "server/apis/GetUsers/api.ts",
136
+ integrations: [{ key: "db", pluginId: "postgres", id: "pg-1" }],
137
+ },
138
+ });
139
+
140
+ const plugin = getPlugin();
141
+ await plugin.buildStart();
142
+
143
+ const result = plugin.load("/lib/user-facing/build-manifest.js");
144
+ const parsed = JSON.parse(
145
+ result.replace("export default ", "").replace(";", ""),
146
+ );
147
+ expect(parsed.sdkApis).toEqual({
148
+ GetUsers: {
149
+ entryPoint: "server/apis/GetUsers/api.ts",
150
+ integrations: [{ key: "db", pluginId: "postgres", id: "pg-1" }],
151
+ },
152
+ });
153
+ });
154
+ });
155
+
156
+ describe("augmentChunkHash feeds manifest into Rollup content hash", () => {
157
+ it("returns manifestCode for chunks containing the hashed dist build-manifest module", async () => {
158
+ fg.mockResolvedValue(["pages/App/apis/GetUsers/api.yaml"]);
159
+ vi.mocked(fs.readFile as any).mockResolvedValue(
160
+ "metadata:\n name: GetUsers\nblocks: []\n",
161
+ );
162
+
163
+ const plugin = getPlugin();
164
+ await plugin.buildStart();
165
+
166
+ const manifestId =
167
+ "/node_modules/@superblocksteam/library/dist/build-manifest-BOqMhObV.js";
168
+ const chunkInfo = {
169
+ modules: { [manifestId]: { renderedLength: 100 } },
170
+ };
171
+
172
+ const result = plugin.augmentChunkHash(chunkInfo);
173
+ expect(result).toBeDefined();
174
+ expect(result).toContain("GetUsers");
175
+ });
176
+
177
+ it("returns manifestCode for chunks containing the source build-manifest module", async () => {
178
+ const plugin = getPlugin();
179
+ await plugin.buildStart();
180
+
181
+ const manifestId =
182
+ "/node_modules/@superblocksteam/library/src/lib/user-facing/build-manifest.js";
183
+ const chunkInfo = {
184
+ modules: { [manifestId]: { renderedLength: 50 } },
185
+ };
186
+
187
+ const result = plugin.augmentChunkHash(chunkInfo);
188
+ expect(result).toBeDefined();
189
+ });
190
+
191
+ it("returns undefined for chunks without build-manifest", async () => {
192
+ const plugin = getPlugin();
193
+ await plugin.buildStart();
194
+
195
+ const chunkInfo = {
196
+ modules: {
197
+ "/some/other/module.js": { renderedLength: 200 },
198
+ },
199
+ };
200
+
201
+ expect(plugin.augmentChunkHash(chunkInfo)).toBeUndefined();
202
+ });
203
+
204
+ it("different manifests produce different augmentChunkHash values", async () => {
205
+ fg.mockResolvedValue(["pages/App/apis/GetUsers/api.yaml"]);
206
+ vi.mocked(fs.readFile as any).mockResolvedValue(
207
+ "metadata:\n name: GetUsers\nblocks: []\n",
208
+ );
209
+
210
+ const plugin1 = getPlugin();
211
+ await plugin1.buildStart();
212
+ const hash1 = plugin1.augmentChunkHash({
213
+ modules: {
214
+ "/node_modules/@superblocksteam/library/dist/build-manifest-BOqMhObV.js":
215
+ { renderedLength: 100 },
216
+ },
217
+ });
218
+
219
+ vi.clearAllMocks();
220
+ vi.mocked(isSdkApiTemplate).mockReturnValue(false);
221
+ fg.mockResolvedValue(["pages/App/apis/ListOrders/api.yaml"]);
222
+ vi.mocked(fs.readFile as any).mockResolvedValue(
223
+ "metadata:\n name: ListOrders\nblocks: []\n",
224
+ );
225
+
226
+ const plugin2 = getPlugin();
227
+ await plugin2.buildStart();
228
+ const hash2 = plugin2.augmentChunkHash({
229
+ modules: {
230
+ "/node_modules/@superblocksteam/library/dist/build-manifest-BOqMhObV.js":
231
+ { renderedLength: 100 },
232
+ },
233
+ });
234
+
235
+ expect(hash1).not.toEqual(hash2);
236
+ });
237
+ });
238
+
239
+ describe("content changes produce different load output", () => {
240
+ it("different API manifests produce different module content", async () => {
241
+ fg.mockResolvedValue(["pages/App/apis/GetUsers/api.yaml"]);
242
+ vi.mocked(fs.readFile as any).mockResolvedValue(
243
+ "metadata:\n name: GetUsers\nblocks: []\n",
244
+ );
245
+
246
+ const plugin1 = getPlugin();
247
+ await plugin1.buildStart();
248
+ const result1 = plugin1.load("/lib/user-facing/build-manifest.js");
249
+
250
+ vi.clearAllMocks();
251
+ vi.mocked(isSdkApiTemplate).mockReturnValue(false);
252
+ fg.mockResolvedValue(["pages/App/apis/ListOrders/api.yaml"]);
253
+ vi.mocked(fs.readFile as any).mockResolvedValue(
254
+ "metadata:\n name: ListOrders\nblocks: []\n",
255
+ );
256
+
257
+ const plugin2 = getPlugin();
258
+ await plugin2.buildStart();
259
+ const result2 = plugin2.load("/lib/user-facing/build-manifest.js");
260
+
261
+ expect(result1).not.toEqual(result2);
262
+ });
263
+ });
264
+ });