@pipelab/shared 1.0.0-beta.1 → 1.0.0-beta.11

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pipelab/shared",
3
- "version": "1.0.0-beta.1",
3
+ "version": "1.0.0-beta.11",
4
4
  "private": false,
5
5
  "description": "Shared logic and types for the Pipelab ecosystem",
6
6
  "license": "FSL-1.1-MIT",
@@ -37,17 +37,21 @@
37
37
  "tslog": "4.9.3",
38
38
  "type-fest": "4.26.1",
39
39
  "valibot": "0.42.1",
40
- "@pipelab/migration": "1.0.0-beta.1"
40
+ "@pipelab/constants": "1.0.0-beta.13",
41
+ "@pipelab/migration": "1.0.0-beta.11"
41
42
  },
42
43
  "devDependencies": {
43
44
  "esbuild-plugin-wasm": "1.1.0",
44
45
  "tsdown": "0.21.2",
45
46
  "typescript": "5.9.3",
46
- "@pipelab/tsconfig": "1.0.0-beta.1"
47
+ "vitest": "3.1.4",
48
+ "@pipelab/tsconfig": "1.0.0-beta.11"
47
49
  },
48
50
  "scripts": {
49
51
  "build": "tsdown",
50
52
  "format": "oxfmt .",
51
- "lint": "oxlint ."
53
+ "lint": "oxlint .",
54
+ "typecheck": "tsc -b",
55
+ "test": "vitest run"
52
56
  }
53
57
  }
package/src/apis.ts CHANGED
@@ -98,24 +98,13 @@ export type IpcDefinition = {
98
98
  | EndEvent<{ outputs: Record<string, unknown>; tmp: string }>
99
99
  ),
100
100
  ];
101
- "condition:execute": [
102
- {
103
- pluginId: string;
104
- nodeId: string;
105
- params: any;
106
- steps: Steps;
107
- },
108
- (
109
- | Event<"progress", unknown>
110
- | Event<"progress", unknown>
111
- | EndEvent<{ outputs: Record<string, unknown>; value: boolean }>
112
- ),
113
- ];
101
+
114
102
  "constants:get": [void, EndEvent<{ result: { userData: string } }>];
115
103
 
116
104
  "config:load": [{ config: string }, EndEvent<{ result: any }>];
117
105
  "config:save": [{ data: any; config: string }, EndEvent<{ result: "ok" }>];
118
106
  "config:reset": [{ config: string; key: string }, EndEvent<{ result: "ok" }>];
107
+ "config:delete": [{ config: string }, EndEvent<{ result: "ok" }>];
119
108
  "action:cancel": [void, EndEvent<{ result: "ok" | "ko" }>];
120
109
 
121
110
  // Build History APIs
@@ -173,6 +162,44 @@ export type IpcDefinition = {
173
162
  ];
174
163
  "agent:version:get": [void, EndEvent<{ version: string }>];
175
164
  "startup:progress": [void, { type: "progress"; data: { message: string } } | { type: "ready" }];
165
+ "plugin:loaded": [void, { plugin: RendererPluginDefinition }];
166
+ "plugin:search": [
167
+ { query: string },
168
+ EndEvent<{
169
+ results: Array<{
170
+ name: string;
171
+ version: string;
172
+ description?: string;
173
+ keywords?: string[];
174
+ date?: string;
175
+ }>;
176
+ }>,
177
+ ];
178
+ "plugin:get-details": [
179
+ { packageName: string },
180
+ EndEvent<{
181
+ name: string;
182
+ latestVersion: string;
183
+ versions: string[];
184
+ description?: string;
185
+ }>,
186
+ ];
187
+ "plugin:install": [{ packageName: string; version: string }, EndEvent<{ result: "ok" }>];
188
+ "plugin:uninstall": [{ packageName: string }, EndEvent<{ result: "ok" }>];
189
+ "plugin:list-installed": [
190
+ void,
191
+ EndEvent<{
192
+ installed: Array<{
193
+ name: string;
194
+ version: string;
195
+ description?: string;
196
+ }>;
197
+ }>,
198
+ ];
199
+ "plugin:ensure-loaded": [
200
+ { plugins: Record<string, string> },
201
+ EndEvent<{ loaded: string[]; failed: string[] }>,
202
+ ];
176
203
  };
177
204
 
178
205
  export type Channels = keyof IpcDefinition;
@@ -1,4 +1,5 @@
1
1
  // Build History Storage Types and Interfaces
2
+ import { SandboxFolder } from "@pipelab/constants";
2
3
 
3
4
  export interface ExecutionStep {
4
5
  id: string;
@@ -86,6 +87,7 @@ export interface IBuildHistoryStorage {
86
87
  total: number;
87
88
  free: number;
88
89
  pipelab: number;
90
+ folders: Array<{ name: SandboxFolder; label: string; size: number }>;
89
91
  };
90
92
  }>;
91
93
  }
@@ -0,0 +1,3 @@
1
+ import type { ConnectionsConfig, ConnectionsConfigV1, Connection } from "../config.schema";
2
+
3
+ export type { ConnectionsConfig, ConnectionsConfigV1, Connection };
@@ -1,10 +1,11 @@
1
1
  import {
2
- createMigration,
2
+ createMigration as createMigrationBase,
3
3
  createMigrator,
4
4
  finalVersion,
5
- initialVersion,
6
5
  OmitVersion,
7
6
  SemVer,
7
+ Awaitable,
8
+ MigrationSchema,
8
9
  } from "@pipelab/migration";
9
10
  import {
10
11
  AppConfig,
@@ -15,12 +16,51 @@ import {
15
16
  AppConfigV5,
16
17
  AppConfigV6,
17
18
  AppConfigV7,
19
+ AppConfigV8,
20
+ ConnectionsConfig,
21
+ ConnectionsConfigV1,
18
22
  } from "../config.schema";
23
+
24
+ const DEFAULT_PLUGINS: AppConfigV8["plugins"] = [
25
+ {
26
+ name: "@pipelab/plugin-construct",
27
+ enabled: true,
28
+ description: "Construct 3 export & packaging",
29
+ },
30
+ { name: "@pipelab/plugin-filesystem", enabled: true, description: "Filesystem utilities" },
31
+ { name: "@pipelab/plugin-system", enabled: true, description: "System & shell commands" },
32
+ { name: "@pipelab/plugin-steam", enabled: true, description: "Steam publishing" },
33
+ { name: "@pipelab/plugin-itch", enabled: true, description: "Itch.io publishing" },
34
+ { name: "@pipelab/plugin-electron", enabled: true, description: "Electron packaging" },
35
+ { name: "@pipelab/plugin-discord", enabled: true, description: "Discord Rich Presence" },
36
+ { name: "@pipelab/plugin-poki", enabled: true, description: "Poki publishing" },
37
+ { name: "@pipelab/plugin-nvpatch", enabled: true, description: "NW.js patching" },
38
+ { name: "@pipelab/plugin-tauri", enabled: true, description: "Tauri packaging" },
39
+ { name: "@pipelab/plugin-minify", enabled: true, description: "Asset minification" },
40
+ { name: "@pipelab/plugin-netlify", enabled: true, description: "Netlify deployment" },
41
+ ];
19
42
  import { FileRepoV1, FileRepoV2, FileRepo } from "./projects-types";
20
- import { SavedFileV1, SavedFileV2, SavedFileV3, SavedFileV4, SavedFile } from "../model";
43
+ import {
44
+ SavedFileV1,
45
+ SavedFileV2,
46
+ SavedFileV3,
47
+ SavedFileV4,
48
+ SavedFileV5,
49
+ SavedFile,
50
+ } from "../model";
21
51
 
22
52
  // --- Types ---
23
53
 
54
+ export type Additive<T, P> = OmitVersion<T> & OmitVersion<P>;
55
+
56
+ type DistributiveOmit<T, K extends keyof any> = T extends any ? Omit<T, K> : never;
57
+ type DistributiveOmitVersion<T> = DistributiveOmit<T, keyof MigrationSchema>;
58
+
59
+ const createMigration = <From extends MigrationSchema, To extends MigrationSchema>(config: {
60
+ version: SemVer;
61
+ up: (state: OmitVersion<From>, targetVersion: string) => Awaitable<OmitVersion<To>>;
62
+ }) => createMigrationBase<From, To>(config);
63
+
24
64
  export interface Migrator<T> {
25
65
  migrate: (data: any, options?: any) => Promise<T>;
26
66
  defaultValue: T;
@@ -31,11 +71,9 @@ export interface Migrator<T> {
31
71
  const settingsMigratorInternal = createMigrator<AppConfigV1, AppConfig>();
32
72
 
33
73
  export const defaultAppSettings = settingsMigratorInternal.createDefault({
34
- cacheFolder: "",
35
- clearTemporaryFoldersOnPipelineEnd: false,
36
74
  locale: "en-US",
37
75
  theme: "light",
38
- version: "7.0.0" as SemVer,
76
+ version: "8.0.0",
39
77
  autosave: true,
40
78
  agents: [],
41
79
  tours: {
@@ -48,40 +86,41 @@ export const defaultAppSettings = settingsMigratorInternal.createDefault({
48
86
  completed: false,
49
87
  },
50
88
  },
89
+ buildHistory: {
90
+ retentionPolicy: {
91
+ enabled: false,
92
+ maxEntries: 50,
93
+ maxAge: 30,
94
+ },
95
+ },
96
+ plugins: DEFAULT_PLUGINS,
97
+ isInternalMigrationBannerClosed: false,
51
98
  });
52
99
 
53
100
  export const appSettingsMigrator = settingsMigratorInternal.createMigrations({
54
101
  defaultValue: defaultAppSettings,
55
102
  migrations: [
56
- createMigration<never, AppConfigV1, AppConfigV2>({
103
+ createMigration<AppConfigV1, AppConfigV2>({
57
104
  version: "1.0.0" as SemVer,
58
- up: (state) => state satisfies OmitVersion<AppConfigV2>,
59
- down: initialVersion,
105
+ up: (state) => state,
60
106
  }),
61
- createMigration<AppConfigV1, AppConfigV2, AppConfigV3>({
107
+ createMigration<AppConfigV2, AppConfigV3>({
62
108
  version: "2.0.0" as SemVer,
63
109
  up: (state) => {
64
110
  return {
65
111
  ...state,
66
112
  clearTemporaryFoldersOnPipelineEnd: false,
67
- } satisfies OmitVersion<AppConfigV3>;
68
- },
69
- down: () => {
70
- throw new Error("Can't migrate down from 2.0.0");
113
+ };
71
114
  },
72
115
  }),
73
- createMigration<AppConfigV2, AppConfigV3, AppConfigV4>({
116
+ createMigration<AppConfigV3, AppConfigV4>({
74
117
  version: "3.0.0" as SemVer,
75
118
  up: (state) => ({
76
119
  ...state,
77
120
  locale: "en-US" as const,
78
121
  }),
79
- down: (state) => {
80
- const { locale, ...rest } = state as AppConfigV4;
81
- return rest as unknown as AppConfigV3;
82
- },
83
122
  }),
84
- createMigration<AppConfigV3, AppConfigV4, AppConfigV5>({
123
+ createMigration<AppConfigV4, AppConfigV5>({
85
124
  version: "4.0.0" as SemVer,
86
125
  up: (state) => ({
87
126
  ...state,
@@ -96,39 +135,55 @@ export const appSettingsMigrator = settingsMigratorInternal.createMigrations({
96
135
  },
97
136
  },
98
137
  }),
99
- down: (state) => {
100
- const { tours, ...rest } = state as AppConfigV5;
101
- return rest as unknown as AppConfigV4;
102
- },
103
138
  }),
104
- createMigration<AppConfigV4, AppConfigV5, AppConfigV6>({
139
+ createMigration<AppConfigV5, AppConfigV6>({
105
140
  version: "5.0.0" as SemVer,
106
141
  up: (state) => ({
107
142
  ...state,
108
143
  autosave: true,
109
144
  }),
110
- down: (state) => {
111
- const { autosave, ...rest } = state as AppConfigV6;
112
- return rest as unknown as AppConfigV5;
113
- },
114
145
  }),
115
- createMigration<AppConfigV5, AppConfigV6, AppConfigV7>({
146
+ createMigration<AppConfigV6, AppConfigV8>({
116
147
  version: "6.0.0" as SemVer,
117
- up: (state) => ({
118
- ...state,
119
- agents: [],
120
- }),
121
- down: (state) => {
122
- const { agents, ...rest } = state as AppConfigV7;
123
- return rest as unknown as AppConfigV6;
148
+ up: (state) => {
149
+ const { cacheFolder: _, clearTemporaryFoldersOnPipelineEnd: __, ...rest } = state;
150
+ return {
151
+ ...rest,
152
+ agents: [],
153
+ buildHistory: {
154
+ retentionPolicy: {
155
+ enabled: false,
156
+ maxEntries: 50,
157
+ maxAge: 30,
158
+ },
159
+ },
160
+ plugins: DEFAULT_PLUGINS,
161
+ isInternalMigrationBannerClosed: false,
162
+ };
124
163
  },
125
164
  }),
126
- createMigration<AppConfigV6, AppConfigV7, never>({
127
- version: "7.0.0" as SemVer,
165
+ createMigration<AppConfigV8, never>({
166
+ version: "8.0.0" as SemVer,
167
+ up: finalVersion,
168
+ }),
169
+ ],
170
+ });
171
+
172
+ // --- Connections Migrator ---
173
+
174
+ const connectionsMigratorInternal = createMigrator<ConnectionsConfigV1, ConnectionsConfig>();
175
+
176
+ export const defaultConnections = connectionsMigratorInternal.createDefault({
177
+ version: "1.0.0",
178
+ connections: [],
179
+ });
180
+
181
+ export const connectionsMigrator = connectionsMigratorInternal.createMigrations({
182
+ defaultValue: defaultConnections,
183
+ migrations: [
184
+ createMigration<ConnectionsConfigV1, never>({
185
+ version: "1.0.0" as SemVer,
128
186
  up: finalVersion,
129
- down: () => {
130
- throw new Error("Can't migrate down from 7.0.0");
131
- },
132
187
  }),
133
188
  ],
134
189
  });
@@ -147,13 +202,12 @@ export const defaultFileRepo = fileRepoMigratorInternal.createDefault({
147
202
  },
148
203
  ],
149
204
  pipelines: [],
150
- proxies: [],
151
205
  });
152
206
 
153
207
  export const fileRepoMigrations = fileRepoMigratorInternal.createMigrations({
154
208
  defaultValue: defaultFileRepo,
155
209
  migrations: [
156
- createMigration<never, FileRepoV1, FileRepoV2>({
210
+ createMigration<FileRepoV1, FileRepoV2>({
157
211
  version: "1.0.0",
158
212
  up: (state) => {
159
213
  const pipelines: FileRepoV2["pipelines"] = Object.entries(state.data || {}).map(
@@ -166,7 +220,7 @@ export const fileRepoMigrations = fileRepoMigratorInternal.createMigrations({
166
220
  },
167
221
  );
168
222
  return {
169
- version: "2.0.0",
223
+ ...state,
170
224
  projects: [
171
225
  {
172
226
  id: "main",
@@ -175,17 +229,12 @@ export const fileRepoMigrations = fileRepoMigratorInternal.createMigrations({
175
229
  },
176
230
  ],
177
231
  pipelines: pipelines,
178
- proxies: [],
179
- } as any;
232
+ };
180
233
  },
181
- down: initialVersion,
182
234
  }),
183
- createMigration<FileRepoV1, FileRepoV2, never>({
235
+ createMigration<FileRepoV2, never>({
184
236
  version: "2.0.0",
185
237
  up: finalVersion,
186
- down: (state) => {
187
- throw new Error("Cannot downgrade to version 1.0.0");
188
- },
189
238
  }),
190
239
  ],
191
240
  });
@@ -201,20 +250,19 @@ const savedFileDefaultValue = savedFileMigratorInternal.createDefault({
201
250
  description: "",
202
251
  name: "",
203
252
  variables: [],
204
- type: "default",
205
- version: "4.0.0" as SemVer,
253
+ version: "5.0.0",
206
254
  });
207
255
 
208
256
  export const savedFileMigrator = savedFileMigratorInternal.createMigrations({
209
257
  defaultValue: savedFileDefaultValue,
210
258
  migrations: [
211
- createMigration<never, SavedFileV1, SavedFileV2>({
259
+ createMigration<SavedFileV1, SavedFileV2>({
212
260
  version: "1.0.0" as SemVer,
213
261
  up: (state) => {
214
262
  const blocks = state.canvas.blocks;
215
263
 
216
- const triggers: any[] = [];
217
- const newBlocks: any[] = [];
264
+ const triggers: SavedFileV2["canvas"]["triggers"] = [];
265
+ const newBlocks: SavedFileV2["canvas"]["blocks"] = [];
218
266
 
219
267
  for (const block of blocks) {
220
268
  if (block.type === "event") {
@@ -225,27 +273,25 @@ export const savedFileMigrator = savedFileMigratorInternal.createMigrations({
225
273
  }
226
274
 
227
275
  return {
276
+ ...state,
228
277
  canvas: {
278
+ ...state.canvas,
229
279
  blocks: newBlocks,
230
280
  triggers: triggers,
231
281
  },
232
- description: state.description,
233
- name: state.name,
234
- variables: state.variables,
235
- } as any;
282
+ };
236
283
  },
237
- down: initialVersion,
238
284
  }),
239
- createMigration<SavedFileV1, SavedFileV2, SavedFileV3>({
285
+ createMigration<SavedFileV2, SavedFileV3>({
240
286
  version: "2.0.0" as SemVer,
241
287
  up: (state) => {
242
- const { canvas, ...rest } = state;
288
+ const { canvas } = state;
243
289
  const { blocks, triggers } = canvas;
244
290
 
245
- const newBlocks: any[] = [];
291
+ const newBlocks: SavedFileV3["canvas"]["blocks"] = [];
246
292
 
247
293
  for (const block of blocks) {
248
- const newParams: any = {};
294
+ const newParams: SavedFileV3["canvas"]["blocks"][number]["params"] = {};
249
295
 
250
296
  for (const data of Object.entries(block.params)) {
251
297
  if (data === undefined) {
@@ -266,43 +312,139 @@ export const savedFileMigrator = savedFileMigratorInternal.createMigrations({
266
312
  }
267
313
 
268
314
  return {
269
- ...rest,
315
+ ...state,
270
316
  canvas: {
317
+ ...canvas,
271
318
  triggers,
272
319
  blocks: newBlocks,
273
320
  },
274
- } as any;
275
- },
276
- down: () => {
277
- throw new Error("Migration down not implemented");
321
+ };
278
322
  },
279
323
  }),
280
- createMigration<SavedFileV2, SavedFileV3, SavedFileV4>({
324
+ createMigration<SavedFileV3, SavedFileV4>({
281
325
  version: "3.0.0" as SemVer,
282
- up: (state) => {
283
- return {
284
- ...state,
285
- type: "default",
286
- } as any;
287
- },
288
- down: () => {
289
- throw new Error("Migration down not implemented");
290
- },
326
+ up: (state) => ({
327
+ ...state,
328
+ type: "default",
329
+ }),
291
330
  }),
292
- createMigration<SavedFileV3, SavedFileV4, SavedFileV4>({
331
+ createMigration<SavedFileV4, SavedFileV5>({
293
332
  version: "4.0.0" as SemVer,
294
- up: finalVersion,
295
- down: () => {
296
- throw new Error("Migration down not implemented");
333
+ up: (_state) => {
334
+ const state = _state as DistributiveOmitVersion<SavedFileV4>;
335
+ if (state.type === "simple") {
336
+ return {
337
+ name: state.name,
338
+ description: state.description,
339
+ canvas: {
340
+ blocks: [],
341
+ triggers: [],
342
+ },
343
+ variables: [],
344
+ };
345
+ }
346
+
347
+ const migrateBlock = (block: any, pluginsMap: Record<string, string>) => {
348
+ if (!block) return;
349
+ if (block.origin?.pluginId) {
350
+ block.origin.pluginId = getStrictPluginId(block.origin.pluginId);
351
+ // Stamp the version from the old top-level plugins map, falling back to "latest"
352
+ block.origin.version = pluginsMap[block.origin.pluginId] ?? "latest";
353
+ }
354
+ };
355
+
356
+ // Normalise the old plugins map's keys first so lookups are consistent
357
+ const normalizedPlugins: Record<string, string> = {};
358
+ if (state.plugins) {
359
+ for (const [key, val] of Object.entries(state.plugins)) {
360
+ normalizedPlugins[getStrictPluginId(key)] = val;
361
+ }
362
+ }
363
+
364
+ // Stamp origin.version on every block and trigger
365
+ if (state.canvas) {
366
+ for (const block of state.canvas.blocks ?? []) {
367
+ migrateBlock(block, normalizedPlugins);
368
+ }
369
+ for (const trigger of state.canvas.triggers ?? []) {
370
+ migrateBlock(trigger, normalizedPlugins);
371
+ }
372
+ }
373
+
374
+ // Drop the top-level plugins map — version is now per-block. Omit type.
375
+ const { plugins: _dropped, type: _type, ...rest } = state;
376
+ return rest;
297
377
  },
298
378
  }),
379
+ createMigration<SavedFileV5, never>({
380
+ version: "5.0.0" as SemVer,
381
+ up: finalVersion,
382
+ }),
299
383
  ],
300
384
  });
301
385
 
386
+ const LEGACY_ID_MAP: Record<string, string> = {
387
+ construct: "@pipelab/plugin-construct",
388
+ filesystem: "@pipelab/plugin-filesystem",
389
+ system: "@pipelab/plugin-system",
390
+ steam: "@pipelab/plugin-steam",
391
+ itch: "@pipelab/plugin-itch",
392
+ electron: "@pipelab/plugin-electron",
393
+ discord: "@pipelab/plugin-discord",
394
+ dicord: "@pipelab/plugin-discord",
395
+ "@pipelab/plugin-dicord": "@pipelab/plugin-discord",
396
+ poki: "@pipelab/plugin-poki",
397
+ nvpatch: "@pipelab/plugin-nvpatch",
398
+ tauri: "@pipelab/plugin-tauri",
399
+ minify: "@pipelab/plugin-minify",
400
+ netlify: "@pipelab/plugin-netlify",
401
+ };
402
+
403
+ export const getStrictPluginId = (pluginId: string): string => {
404
+ if (!pluginId) return pluginId;
405
+ return LEGACY_ID_MAP[pluginId] || pluginId;
406
+ };
407
+
408
+ const normalizeBlockPluginId = (block: any): boolean => {
409
+ if (!block) return false;
410
+ let changed = false;
411
+ if (block.origin?.pluginId) {
412
+ const strictId = getStrictPluginId(block.origin.pluginId);
413
+ if (block.origin.pluginId !== strictId) {
414
+ block.origin.pluginId = strictId;
415
+ changed = true;
416
+ }
417
+ }
418
+ return changed;
419
+ };
420
+
421
+ export const normalizePipelineConfig = (state: any): boolean => {
422
+ if (!state) return false;
423
+ let changed = false;
424
+
425
+ // Normalise plugin IDs in block and trigger origins (pluginId field only;
426
+ // version strings don't need normalisation)
427
+ if (state.type === "default" && state.canvas) {
428
+ if (Array.isArray(state.canvas.blocks)) {
429
+ for (const block of state.canvas.blocks) {
430
+ if (normalizeBlockPluginId(block)) changed = true;
431
+ }
432
+ }
433
+ if (Array.isArray(state.canvas.triggers)) {
434
+ for (const trigger of state.canvas.triggers) {
435
+ if (normalizeBlockPluginId(trigger)) changed = true;
436
+ }
437
+ }
438
+ }
439
+
440
+ return changed;
441
+ };
442
+
302
443
  // --- Registry ---
303
444
 
304
445
  export const configRegistry: Record<string, Migrator<any>> = {
305
446
  settings: appSettingsMigrator,
306
447
  projects: fileRepoMigrations,
307
448
  pipeline: savedFileMigrator,
449
+ connections: connectionsMigrator,
308
450
  };
@@ -7,6 +7,7 @@ import type {
7
7
  AppConfigV5,
8
8
  AppConfigV6,
9
9
  AppConfigV7,
10
+ AppConfigV8,
10
11
  } from "../config.schema";
11
12
 
12
13
  export type {
@@ -18,4 +19,5 @@ export type {
18
19
  AppConfigV5,
19
20
  AppConfigV6,
20
21
  AppConfigV7,
22
+ AppConfigV8,
21
23
  };