@embeddable.com/sdk-core 4.1.12 → 4.2.0-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.
- package/lib/index.esm.js +24 -17
- package/lib/index.esm.js.map +1 -1
- package/package.json +12 -4
- package/src/push.test.ts +152 -78
- package/src/push.ts +25 -18
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@embeddable.com/sdk-core",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.2.0-next.0",
|
|
4
4
|
"description": "Core Embeddable SDK module responsible for web-components bundling and publishing.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"embeddable",
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
"embeddable": "bin/embeddable"
|
|
37
37
|
},
|
|
38
38
|
"engines": {
|
|
39
|
-
"node": ">=20.
|
|
39
|
+
"node": ">=20.1.0"
|
|
40
40
|
},
|
|
41
41
|
"license": "MIT",
|
|
42
42
|
"dependencies": {
|
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
"@inquirer/prompts": "^7.2.1",
|
|
46
46
|
"@stencil/core": "^4.23.0",
|
|
47
47
|
"@swc-node/register": "^1.10.9",
|
|
48
|
-
"
|
|
48
|
+
"yazl": "^2.5.1",
|
|
49
49
|
"axios": "^1.7.9",
|
|
50
50
|
"chokidar": "^4.0.3",
|
|
51
51
|
"dotenv": "^16.4.7",
|
|
@@ -66,8 +66,16 @@
|
|
|
66
66
|
"prettier --write"
|
|
67
67
|
]
|
|
68
68
|
},
|
|
69
|
+
"peerDependencies": {
|
|
70
|
+
"typescript": ">=5.0.0"
|
|
71
|
+
},
|
|
72
|
+
"peerDependenciesMeta": {
|
|
73
|
+
"typescript": {
|
|
74
|
+
"optional": true
|
|
75
|
+
}
|
|
76
|
+
},
|
|
69
77
|
"devDependencies": {
|
|
70
|
-
"@types/
|
|
78
|
+
"@types/yazl": "^2.4.5",
|
|
71
79
|
"@types/finalhandler": "^1.2.3",
|
|
72
80
|
"@types/minimist": "^1.2.5",
|
|
73
81
|
"@types/serve-static": "^1.15.7",
|
package/src/push.test.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import push, { buildArchive } from "./push";
|
|
2
2
|
import provideConfig from "./provideConfig";
|
|
3
3
|
import { fileFromPath } from "formdata-node/file-from-path";
|
|
4
|
-
import
|
|
4
|
+
import * as path from "path";
|
|
5
|
+
import yazl from "yazl";
|
|
5
6
|
import * as fs from "node:fs/promises";
|
|
6
7
|
import * as fsSync from "node:fs";
|
|
7
8
|
import { findFiles } from "@embeddable.com/sdk-utils";
|
|
@@ -53,6 +54,9 @@ vi.mock("node:fs/promises", () => ({
|
|
|
53
54
|
|
|
54
55
|
vi.mock("node:fs", () => ({
|
|
55
56
|
createWriteStream: vi.fn(),
|
|
57
|
+
readdirSync: vi.fn().mockReturnValue([]),
|
|
58
|
+
statSync: vi.fn().mockReturnValue({ isFile: () => true }),
|
|
59
|
+
existsSync: vi.fn().mockReturnValue(true),
|
|
56
60
|
}));
|
|
57
61
|
|
|
58
62
|
vi.mock("./provideConfig", () => ({
|
|
@@ -73,9 +77,13 @@ vi.mock("@embeddable.com/sdk-utils", () => ({
|
|
|
73
77
|
findFiles: vi.fn(),
|
|
74
78
|
}));
|
|
75
79
|
|
|
76
|
-
vi.
|
|
80
|
+
const { zipRef } = vi.hoisted(() => ({
|
|
81
|
+
zipRef: { current: null as any },
|
|
82
|
+
}));
|
|
83
|
+
|
|
84
|
+
vi.mock("yazl", () => ({
|
|
77
85
|
default: {
|
|
78
|
-
|
|
86
|
+
ZipFile: vi.fn(function () { return zipRef.current; }),
|
|
79
87
|
},
|
|
80
88
|
}));
|
|
81
89
|
|
|
@@ -96,11 +104,10 @@ const config = {
|
|
|
96
104
|
};
|
|
97
105
|
|
|
98
106
|
describe("push", () => {
|
|
99
|
-
const
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
file: vi.fn(),
|
|
107
|
+
const zipMock = {
|
|
108
|
+
addFile: vi.fn(),
|
|
109
|
+
end: vi.fn(),
|
|
110
|
+
outputStream: { pipe: vi.fn() },
|
|
104
111
|
};
|
|
105
112
|
|
|
106
113
|
beforeEach(() => {
|
|
@@ -121,7 +128,9 @@ describe("push", () => {
|
|
|
121
128
|
vi.mocked(fileFromPath).mockReturnValue(
|
|
122
129
|
new Blob([new ArrayBuffer(8)]) as any
|
|
123
130
|
);
|
|
124
|
-
|
|
131
|
+
zipRef.current = zipMock;
|
|
132
|
+
vi.mocked(fsSync.readdirSync).mockReturnValue([]);
|
|
133
|
+
vi.mocked(fsSync.existsSync).mockReturnValue(true);
|
|
125
134
|
|
|
126
135
|
vi.mocked(fsSync.createWriteStream).mockReturnValue({
|
|
127
136
|
on: (event: string, cb: () => void) => {
|
|
@@ -142,19 +151,19 @@ describe("push", () => {
|
|
|
142
151
|
|
|
143
152
|
expect(fs.access).toHaveBeenCalledWith(config.client.buildDir);
|
|
144
153
|
|
|
145
|
-
expect(
|
|
146
|
-
zlib: { level: 9 },
|
|
147
|
-
});
|
|
154
|
+
expect(yazl.ZipFile).toHaveBeenCalled();
|
|
148
155
|
expect(fsSync.createWriteStream).toHaveBeenCalledWith(
|
|
149
156
|
config.client.archiveFile
|
|
150
157
|
);
|
|
151
158
|
|
|
152
|
-
expect(
|
|
153
|
-
expect(
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
expect(
|
|
157
|
-
|
|
159
|
+
expect(zipMock.outputStream.pipe).toHaveBeenCalled();
|
|
160
|
+
expect(zipMock.addFile).toHaveBeenCalledWith(
|
|
161
|
+
"src/custom-canvas.css", "global.css", expect.objectContaining({ compress: true })
|
|
162
|
+
);
|
|
163
|
+
expect(fsSync.readdirSync).toHaveBeenCalledWith(
|
|
164
|
+
"buildDir", expect.objectContaining({ recursive: true })
|
|
165
|
+
);
|
|
166
|
+
expect(zipMock.end).toHaveBeenCalled();
|
|
158
167
|
// after publishing the file gets removed
|
|
159
168
|
expect(fs.rm).toHaveBeenCalledWith(config.client.archiveFile);
|
|
160
169
|
|
|
@@ -230,13 +239,12 @@ describe("push", () => {
|
|
|
230
239
|
});
|
|
231
240
|
|
|
232
241
|
it("should only include component files when pushModels is false", async () => {
|
|
233
|
-
const
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
file: vi.fn(),
|
|
242
|
+
const localZipMock = {
|
|
243
|
+
addFile: vi.fn(),
|
|
244
|
+
end: vi.fn(),
|
|
245
|
+
outputStream: { pipe: vi.fn() },
|
|
238
246
|
};
|
|
239
|
-
|
|
247
|
+
zipRef.current = localZipMock;
|
|
240
248
|
|
|
241
249
|
vi.mocked(provideConfig).mockResolvedValue({
|
|
242
250
|
...config,
|
|
@@ -246,13 +254,14 @@ describe("push", () => {
|
|
|
246
254
|
|
|
247
255
|
await push();
|
|
248
256
|
|
|
249
|
-
// Should
|
|
250
|
-
expect(
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
257
|
+
// Should read component build directory
|
|
258
|
+
expect(fsSync.readdirSync).toHaveBeenCalledWith(
|
|
259
|
+
"buildDir", expect.objectContaining({ recursive: true })
|
|
260
|
+
);
|
|
261
|
+
// Should include global.css and client context files
|
|
262
|
+
expect(localZipMock.addFile).toHaveBeenCalledWith(
|
|
263
|
+
expect.anything(), "global.css", expect.objectContaining({ compress: true })
|
|
264
|
+
);
|
|
256
265
|
});
|
|
257
266
|
});
|
|
258
267
|
|
|
@@ -398,29 +407,24 @@ describe("push", () => {
|
|
|
398
407
|
});
|
|
399
408
|
|
|
400
409
|
describe("buildArchive", () => {
|
|
401
|
-
type
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
file: ReturnType<typeof vi.fn>;
|
|
410
|
+
type MockZip = {
|
|
411
|
+
addFile: ReturnType<typeof vi.fn>;
|
|
412
|
+
end: ReturnType<typeof vi.fn>;
|
|
413
|
+
outputStream: { pipe: ReturnType<typeof vi.fn> };
|
|
406
414
|
};
|
|
407
415
|
|
|
408
|
-
let
|
|
409
|
-
let mockOra: {
|
|
410
|
-
start: ReturnType<typeof vi.fn>;
|
|
411
|
-
succeed: ReturnType<typeof vi.fn>;
|
|
412
|
-
fail: ReturnType<typeof vi.fn>;
|
|
413
|
-
};
|
|
416
|
+
let mockZipLocal: MockZip;
|
|
414
417
|
|
|
415
418
|
beforeEach(() => {
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
file: vi.fn(),
|
|
419
|
+
mockZipLocal = {
|
|
420
|
+
addFile: vi.fn(),
|
|
421
|
+
end: vi.fn(),
|
|
422
|
+
outputStream: { pipe: vi.fn() },
|
|
421
423
|
};
|
|
422
424
|
|
|
423
|
-
|
|
425
|
+
zipRef.current = mockZipLocal;
|
|
426
|
+
vi.mocked(fsSync.readdirSync).mockReturnValue([]);
|
|
427
|
+
vi.mocked(fsSync.existsSync).mockReturnValue(true);
|
|
424
428
|
vi.mocked(findFiles).mockResolvedValue([]);
|
|
425
429
|
});
|
|
426
430
|
|
|
@@ -447,43 +451,38 @@ describe("push", () => {
|
|
|
447
451
|
|
|
448
452
|
await buildArchive(testConfig);
|
|
449
453
|
|
|
450
|
-
// Should
|
|
451
|
-
expect(
|
|
454
|
+
// Should read component build directory
|
|
455
|
+
expect(fsSync.readdirSync).toHaveBeenCalledWith(
|
|
452
456
|
testConfig.client.buildDir,
|
|
453
|
-
|
|
457
|
+
expect.objectContaining({ recursive: true })
|
|
454
458
|
);
|
|
455
459
|
// Should include global.css
|
|
456
|
-
expect(
|
|
460
|
+
expect(mockZipLocal.addFile).toHaveBeenCalledWith(
|
|
457
461
|
testConfig.client.customCanvasCss,
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
}
|
|
462
|
+
"global.css",
|
|
463
|
+
expect.objectContaining({ compress: true })
|
|
461
464
|
);
|
|
462
465
|
// Should include all model files
|
|
463
|
-
expect(
|
|
466
|
+
expect(mockZipLocal.addFile).toHaveBeenCalledWith(
|
|
464
467
|
"/path/to/model1.cube.yml",
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
}
|
|
468
|
+
"model1.cube.yml",
|
|
469
|
+
expect.objectContaining({ compress: true })
|
|
468
470
|
);
|
|
469
|
-
expect(
|
|
471
|
+
expect(mockZipLocal.addFile).toHaveBeenCalledWith(
|
|
470
472
|
"/path/to/model2.cube.yaml",
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
}
|
|
473
|
+
"model2.cube.yaml",
|
|
474
|
+
expect.objectContaining({ compress: true })
|
|
474
475
|
);
|
|
475
476
|
// Should include all preset files
|
|
476
|
-
expect(
|
|
477
|
+
expect(mockZipLocal.addFile).toHaveBeenCalledWith(
|
|
477
478
|
"/path/to/context1.sc.yml",
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
}
|
|
479
|
+
"context1.sc.yml",
|
|
480
|
+
expect.objectContaining({ compress: true })
|
|
481
481
|
);
|
|
482
|
-
expect(
|
|
482
|
+
expect(mockZipLocal.addFile).toHaveBeenCalledWith(
|
|
483
483
|
"/path/to/context2.cc.yml",
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
}
|
|
484
|
+
"context2.cc.yml",
|
|
485
|
+
expect.objectContaining({ compress: true })
|
|
487
486
|
);
|
|
488
487
|
});
|
|
489
488
|
|
|
@@ -500,17 +499,16 @@ describe("push", () => {
|
|
|
500
499
|
|
|
501
500
|
await buildArchive(testConfig);
|
|
502
501
|
|
|
503
|
-
// Should
|
|
504
|
-
expect(
|
|
502
|
+
// Should read component build directory
|
|
503
|
+
expect(fsSync.readdirSync).toHaveBeenCalledWith(
|
|
505
504
|
testConfig.client.buildDir,
|
|
506
|
-
|
|
505
|
+
expect.objectContaining({ recursive: true })
|
|
507
506
|
);
|
|
508
507
|
// Should include global.css
|
|
509
|
-
expect(
|
|
508
|
+
expect(mockZipLocal.addFile).toHaveBeenCalledWith(
|
|
510
509
|
testConfig.client.customCanvasCss,
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
}
|
|
510
|
+
"global.css",
|
|
511
|
+
expect.objectContaining({ compress: true })
|
|
514
512
|
);
|
|
515
513
|
// Should only find client context files
|
|
516
514
|
expect(findFiles).toHaveBeenCalledOnce();
|
|
@@ -541,6 +539,82 @@ describe("push", () => {
|
|
|
541
539
|
);
|
|
542
540
|
});
|
|
543
541
|
|
|
542
|
+
it("should add directory files to zip with correct relative paths", async () => {
|
|
543
|
+
vi.mocked(fsSync.readdirSync).mockReturnValue([
|
|
544
|
+
"index.js",
|
|
545
|
+
"components/widget.js",
|
|
546
|
+
] as any);
|
|
547
|
+
vi.mocked(fsSync.statSync).mockReturnValue({ isFile: () => true } as any);
|
|
548
|
+
|
|
549
|
+
const testConfig = {
|
|
550
|
+
...config,
|
|
551
|
+
pushModels: false,
|
|
552
|
+
pushComponents: true,
|
|
553
|
+
client: {
|
|
554
|
+
...config.client,
|
|
555
|
+
srcDir: "/src",
|
|
556
|
+
},
|
|
557
|
+
} as ResolvedEmbeddableConfig;
|
|
558
|
+
|
|
559
|
+
await buildArchive(testConfig);
|
|
560
|
+
|
|
561
|
+
expect(mockZipLocal.addFile).toHaveBeenCalledWith(
|
|
562
|
+
path.join("buildDir", "index.js"),
|
|
563
|
+
"index.js",
|
|
564
|
+
expect.objectContaining({ compress: true })
|
|
565
|
+
);
|
|
566
|
+
expect(mockZipLocal.addFile).toHaveBeenCalledWith(
|
|
567
|
+
path.join("buildDir", "components/widget.js"),
|
|
568
|
+
"components/widget.js",
|
|
569
|
+
expect.objectContaining({ compress: true })
|
|
570
|
+
);
|
|
571
|
+
});
|
|
572
|
+
|
|
573
|
+
it("should skip directories when adding directory contents to zip", async () => {
|
|
574
|
+
vi.mocked(fsSync.readdirSync).mockReturnValue(["components"] as any);
|
|
575
|
+
vi.mocked(fsSync.statSync).mockReturnValue({ isFile: () => false } as any);
|
|
576
|
+
|
|
577
|
+
const testConfig = {
|
|
578
|
+
...config,
|
|
579
|
+
pushModels: false,
|
|
580
|
+
pushComponents: true,
|
|
581
|
+
client: {
|
|
582
|
+
...config.client,
|
|
583
|
+
srcDir: "/src",
|
|
584
|
+
},
|
|
585
|
+
} as ResolvedEmbeddableConfig;
|
|
586
|
+
|
|
587
|
+
await buildArchive(testConfig);
|
|
588
|
+
|
|
589
|
+
const addFileCalls = mockZipLocal.addFile.mock.calls;
|
|
590
|
+
const dirCall = addFileCalls.find(
|
|
591
|
+
(call: any) => call[1] === "components"
|
|
592
|
+
);
|
|
593
|
+
expect(dirCall).toBeUndefined();
|
|
594
|
+
});
|
|
595
|
+
|
|
596
|
+
it("should skip customCanvasCss when file does not exist", async () => {
|
|
597
|
+
vi.mocked(fsSync.existsSync).mockReturnValue(false);
|
|
598
|
+
|
|
599
|
+
const testConfig = {
|
|
600
|
+
...config,
|
|
601
|
+
pushModels: false,
|
|
602
|
+
pushComponents: true,
|
|
603
|
+
client: {
|
|
604
|
+
...config.client,
|
|
605
|
+
srcDir: "/src",
|
|
606
|
+
},
|
|
607
|
+
} as ResolvedEmbeddableConfig;
|
|
608
|
+
|
|
609
|
+
await buildArchive(testConfig);
|
|
610
|
+
|
|
611
|
+
const addFileCalls = mockZipLocal.addFile.mock.calls;
|
|
612
|
+
const cssCall = addFileCalls.find(
|
|
613
|
+
(call: any) => call[1] === "global.css"
|
|
614
|
+
);
|
|
615
|
+
expect(cssCall).toBeUndefined();
|
|
616
|
+
});
|
|
617
|
+
|
|
544
618
|
it("should use srcDir as fallback when modelsSrc/presetsSrc are not defined", async () => {
|
|
545
619
|
const testConfig = {
|
|
546
620
|
...config,
|
package/src/push.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as fs from "node:fs/promises";
|
|
2
2
|
import * as fsSync from "node:fs";
|
|
3
|
-
import
|
|
3
|
+
import yazl from "yazl";
|
|
4
4
|
import axios, {AxiosResponse} from "axios";
|
|
5
5
|
import ora, { Ora } from "ora";
|
|
6
6
|
import { initLogger, logError } from "./logger";
|
|
@@ -231,34 +231,41 @@ export async function archive(args: {
|
|
|
231
231
|
isDev: boolean;
|
|
232
232
|
}) {
|
|
233
233
|
const { ctx, filesList, isDev } = args;
|
|
234
|
-
const
|
|
234
|
+
const zip = new yazl.ZipFile();
|
|
235
235
|
|
|
236
|
-
const archive = archiver.create("zip", {
|
|
237
|
-
zlib: { level: 9 },
|
|
238
|
-
});
|
|
239
|
-
|
|
240
|
-
archive.pipe(output);
|
|
241
236
|
if (!isDev) {
|
|
242
|
-
|
|
237
|
+
addDirectoryToZip(zip, ctx.client.buildDir);
|
|
243
238
|
// NOTE: for backward compatibility, keep the file name as global.css
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
}
|
|
239
|
+
if (fsSync.existsSync(ctx.client.customCanvasCss)) {
|
|
240
|
+
zip.addFile(ctx.client.customCanvasCss, "global.css", { compress: true });
|
|
241
|
+
}
|
|
247
242
|
}
|
|
248
243
|
|
|
249
|
-
for (const
|
|
250
|
-
|
|
251
|
-
name: fileData[0],
|
|
252
|
-
});
|
|
244
|
+
for (const [name, filePath] of filesList) {
|
|
245
|
+
zip.addFile(filePath, name, { compress: true });
|
|
253
246
|
}
|
|
254
247
|
|
|
255
|
-
|
|
248
|
+
zip.end();
|
|
256
249
|
|
|
257
|
-
return new Promise<void>((resolve
|
|
258
|
-
output
|
|
250
|
+
return new Promise<void>((resolve, reject) => {
|
|
251
|
+
const output = fsSync.createWriteStream(ctx.client.archiveFile);
|
|
252
|
+
zip.outputStream.pipe(output);
|
|
253
|
+
output.on("close", resolve);
|
|
254
|
+
output.on("error", reject);
|
|
259
255
|
});
|
|
260
256
|
}
|
|
261
257
|
|
|
258
|
+
function addDirectoryToZip(zip: yazl.ZipFile, dir: string) {
|
|
259
|
+
const entries = fsSync.readdirSync(dir, { recursive: true });
|
|
260
|
+
for (const entry of entries) {
|
|
261
|
+
const relativePath = String(entry);
|
|
262
|
+
const fullPath = path.join(dir, relativePath);
|
|
263
|
+
if (fsSync.statSync(fullPath).isFile()) {
|
|
264
|
+
zip.addFile(fullPath, relativePath, { compress: true });
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
|
|
262
269
|
export async function createFormData(
|
|
263
270
|
filePath: string,
|
|
264
271
|
metadata: Record<string, any>,
|