@pipelab/core-node 1.0.0-beta.2 → 1.0.0-beta.21

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 (45) hide show
  1. package/.oxfmtrc.json +1 -1
  2. package/CHANGELOG.md +164 -0
  3. package/dist/config-Bi0ORcTK.mjs +2 -0
  4. package/dist/config-CFgGRD9U.mjs +265 -0
  5. package/dist/config-CFgGRD9U.mjs.map +1 -0
  6. package/dist/index.d.mts +74 -53
  7. package/dist/index.d.mts.map +1 -1
  8. package/dist/index.mjs +1705 -576
  9. package/dist/index.mjs.map +1 -1
  10. package/package.json +9 -5
  11. package/scratch/simulate-updates.ts +120 -0
  12. package/src/config.test.ts +232 -0
  13. package/src/config.ts +111 -50
  14. package/src/context.ts +117 -5
  15. package/src/handler-func.ts +2 -77
  16. package/src/handlers/build-history.ts +60 -90
  17. package/src/handlers/config.ts +265 -55
  18. package/src/handlers/engine.ts +32 -35
  19. package/src/handlers/history.ts +0 -40
  20. package/src/handlers/index.ts +4 -0
  21. package/src/handlers/migration.ts +621 -0
  22. package/src/handlers/plugins.ts +305 -0
  23. package/src/handlers/system.ts +7 -2
  24. package/src/index.ts +9 -2
  25. package/src/plugins-registry.ts +280 -38
  26. package/src/presets/c3toSteam.ts +13 -7
  27. package/src/presets/demo.ts +9 -9
  28. package/src/presets/list.ts +0 -6
  29. package/src/presets/moreToCome.ts +3 -2
  30. package/src/presets/newProject.ts +3 -2
  31. package/src/presets/test-c3-offline.ts +15 -6
  32. package/src/presets/test-c3-unzip.ts +19 -8
  33. package/src/runner.ts +2 -8
  34. package/src/server.ts +45 -4
  35. package/src/types/runner.ts +2 -30
  36. package/src/utils/fs-extras.ts +6 -24
  37. package/src/utils/github.test.ts +211 -0
  38. package/src/utils/github.ts +90 -10
  39. package/src/utils/remote.test.ts +209 -0
  40. package/src/utils/remote.ts +325 -87
  41. package/src/utils/storage.ts +2 -1
  42. package/src/utils.ts +20 -24
  43. package/src/migrations.ts +0 -72
  44. package/src/presets/if.ts +0 -69
  45. package/src/presets/loop.ts +0 -65
@@ -0,0 +1,209 @@
1
+ import { describe, test, expect, beforeEach, afterEach, vi } from "vitest";
2
+ import { isOnline, fetchPackage, fetchPipelabPlugin } from "./remote";
3
+ import dns from "node:dns/promises";
4
+ import pacote from "pacote";
5
+ import { vol } from "memfs";
6
+ import { PipelabContext } from "../context";
7
+ import fs from "node:fs/promises";
8
+ import path from "node:path";
9
+ import { existsSync } from "node:fs";
10
+
11
+ vi.mock("node:dns/promises", () => ({
12
+ default: {
13
+ lookup: vi.fn(),
14
+ },
15
+ }));
16
+
17
+ vi.mock("node:fs", async () => {
18
+ const memfs = await import("memfs");
19
+ return {
20
+ ...memfs.fs,
21
+ default: memfs.fs,
22
+ existsSync: (p: string) => memfs.fs.existsSync(p),
23
+ };
24
+ });
25
+
26
+ vi.mock("node:fs/promises", async () => {
27
+ const memfs = await import("memfs");
28
+ return {
29
+ ...memfs.fs.promises,
30
+ default: memfs.fs.promises,
31
+ };
32
+ });
33
+
34
+ vi.mock("pacote", () => ({
35
+ default: {
36
+ packument: vi.fn(),
37
+ extract: vi.fn(),
38
+ },
39
+ }));
40
+
41
+ describe("remote utilities & offline mode", () => {
42
+ beforeEach(() => {
43
+ vi.useFakeTimers();
44
+ vol.reset();
45
+ vi.restoreAllMocks();
46
+ });
47
+
48
+ afterEach(() => {
49
+ vi.useRealTimers();
50
+ });
51
+
52
+ test("isOnline returns true when dns.lookup succeeds", async () => {
53
+ vi.spyOn(dns, "lookup").mockResolvedValue({ address: "1.2.3.4", family: 4 } as any);
54
+ const online = await isOnline();
55
+ expect(online).toBe(true);
56
+ });
57
+
58
+ test("isOnline returns false when dns.lookup throws", async () => {
59
+ vi.advanceTimersByTime(11000); // Bypass 10s caching
60
+ vi.spyOn(dns, "lookup").mockRejectedValue(new Error("ENOTFOUND"));
61
+ const online = await isOnline();
62
+ expect(online).toBe(false);
63
+ });
64
+
65
+ test("fetchPackage falls back to local packages when offline", async () => {
66
+ // 1. Force offline status
67
+ vi.advanceTimersByTime(11000); // Bypass 10s caching
68
+ vi.spyOn(dns, "lookup").mockRejectedValue(new Error("Offline"));
69
+
70
+ const context = new PipelabContext({ userDataPath: "/tmp/pipelab-test-remote" });
71
+ const packageName = "my-plugin";
72
+ const packageBaseDir = context.getPackagesPath(packageName);
73
+ const cachedVersionDir = path.join(packageBaseDir, "1.0.0");
74
+
75
+ await fs.mkdir(cachedVersionDir, { recursive: true });
76
+ await fs.writeFile(
77
+ path.join(cachedVersionDir, "package.json"),
78
+ JSON.stringify({
79
+ name: packageName,
80
+ version: "1.0.0",
81
+ main: "index.mjs",
82
+ }),
83
+ );
84
+
85
+ // 2. Call fetchPackage
86
+ const result = await fetchPackage(packageName, "latest", { context });
87
+
88
+ // 3. Verify it resolved to local cached version without calling pacote
89
+ expect(result.resolvedVersion).toBe("1.0.0");
90
+ expect(result.packageDir).toBe(cachedVersionDir);
91
+ expect(pacote.packument).not.toHaveBeenCalled();
92
+ });
93
+
94
+ test("fetchPipelabPlugin maps latest to releaseTag for official plugins", async () => {
95
+ vi.advanceTimersByTime(30000); // Bypass 10s caching
96
+ const context = new PipelabContext({
97
+ userDataPath: "/tmp/pipelab-test-remote",
98
+ releaseTag: "beta",
99
+ });
100
+ const pluginName = "@pipelab/plugin-poki";
101
+ const packageBaseDir = context.getPackagesPath(pluginName);
102
+ const cachedVersionDir = path.join(packageBaseDir, "1.0.0-beta.15");
103
+
104
+ vi.spyOn(dns, "lookup").mockResolvedValue({ address: "1.2.3.4", family: 4 } as any);
105
+
106
+ vi.mocked(pacote.packument).mockResolvedValue({
107
+ name: pluginName,
108
+ versions: {
109
+ "1.0.0-beta.15": {},
110
+ },
111
+ "dist-tags": {
112
+ beta: "1.0.0-beta.15",
113
+ },
114
+ } as any);
115
+
116
+ await fs.mkdir(cachedVersionDir, { recursive: true });
117
+ await fs.writeFile(
118
+ path.join(cachedVersionDir, "package.json"),
119
+ JSON.stringify({
120
+ name: pluginName,
121
+ version: "1.0.0-beta.15",
122
+ main: "dist/index.mjs",
123
+ }),
124
+ );
125
+
126
+ const result = await fetchPipelabPlugin(pluginName, "latest", { context });
127
+
128
+ expect(pacote.packument).toHaveBeenCalledWith(pluginName, expect.any(Object));
129
+ expect(result.packageDir).toBe(cachedVersionDir);
130
+ });
131
+
132
+ test("fetchPipelabPlugin maps latest to releaseTag for custom plugins and falls back to latest if tag is missing", async () => {
133
+ vi.advanceTimersByTime(40000); // Bypass 10s caching
134
+ const context = new PipelabContext({
135
+ userDataPath: "/tmp/pipelab-test-remote-custom",
136
+ releaseTag: "beta",
137
+ });
138
+ const pluginName = "custom-cool-plugin";
139
+ const packageBaseDir = context.getPackagesPath(pluginName);
140
+ const cachedVersionDir = path.join(packageBaseDir, "2.0.0");
141
+
142
+ vi.spyOn(dns, "lookup").mockResolvedValue({ address: "1.2.3.4", family: 4 } as any);
143
+
144
+ vi.mocked(pacote.packument).mockResolvedValue({
145
+ name: pluginName,
146
+ versions: {
147
+ "2.0.0": {},
148
+ },
149
+ "dist-tags": {
150
+ latest: "2.0.0",
151
+ },
152
+ } as any);
153
+
154
+ await fs.mkdir(cachedVersionDir, { recursive: true });
155
+ await fs.writeFile(
156
+ path.join(cachedVersionDir, "package.json"),
157
+ JSON.stringify({
158
+ name: pluginName,
159
+ version: "2.0.0",
160
+ main: "dist/index.mjs",
161
+ }),
162
+ );
163
+
164
+ const result = await fetchPipelabPlugin(pluginName, "latest", { context });
165
+
166
+ expect(pacote.packument).toHaveBeenCalledWith(pluginName, expect.any(Object));
167
+ expect(result.packageDir).toBe(cachedVersionDir);
168
+ });
169
+
170
+ test("fetchPipelabPlugin maps latest to releaseTag for custom plugins and falls back to latest if beta is stale", async () => {
171
+ vi.advanceTimersByTime(50000); // Bypass 10s caching
172
+ const context = new PipelabContext({
173
+ userDataPath: "/tmp/pipelab-test-remote-stale",
174
+ releaseTag: "beta",
175
+ });
176
+ const pluginName = "stale-beta-plugin";
177
+ const packageBaseDir = context.getPackagesPath(pluginName);
178
+ const cachedVersionDir = path.join(packageBaseDir, "2.0.0");
179
+
180
+ vi.spyOn(dns, "lookup").mockResolvedValue({ address: "1.2.3.4", family: 4 } as any);
181
+
182
+ vi.mocked(pacote.packument).mockResolvedValue({
183
+ name: pluginName,
184
+ versions: {
185
+ "1.0.0-beta.1": {},
186
+ "2.0.0": {},
187
+ },
188
+ "dist-tags": {
189
+ beta: "1.0.0-beta.1",
190
+ latest: "2.0.0",
191
+ },
192
+ } as any);
193
+
194
+ await fs.mkdir(cachedVersionDir, { recursive: true });
195
+ await fs.writeFile(
196
+ path.join(cachedVersionDir, "package.json"),
197
+ JSON.stringify({
198
+ name: pluginName,
199
+ version: "2.0.0",
200
+ main: "dist/index.mjs",
201
+ }),
202
+ );
203
+
204
+ const result = await fetchPipelabPlugin(pluginName, "latest", { context });
205
+
206
+ expect(pacote.packument).toHaveBeenCalledWith(pluginName, expect.any(Object));
207
+ expect(result.packageDir).toBe(cachedVersionDir);
208
+ });
209
+ });