@pipelab/shared 1.0.0-beta.7 → 1.0.0-beta.9

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.7",
3
+ "version": "1.0.0-beta.9",
4
4
  "private": false,
5
5
  "description": "Shared logic and types for the Pipelab ecosystem",
6
6
  "license": "FSL-1.1-MIT",
@@ -37,13 +37,13 @@
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.7"
40
+ "@pipelab/migration": "1.0.0-beta.9"
41
41
  },
42
42
  "devDependencies": {
43
43
  "esbuild-plugin-wasm": "1.1.0",
44
44
  "tsdown": "0.21.2",
45
45
  "typescript": "5.9.3",
46
- "@pipelab/tsconfig": "1.0.0-beta.7"
46
+ "@pipelab/tsconfig": "1.0.0-beta.9"
47
47
  },
48
48
  "scripts": {
49
49
  "build": "tsdown",
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
@@ -174,6 +163,43 @@ export type IpcDefinition = {
174
163
  "agent:version:get": [void, EndEvent<{ version: string }>];
175
164
  "startup:progress": [void, { type: "progress"; data: { message: string } } | { type: "ready" }];
176
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
+ ];
177
203
  };
178
204
 
179
205
  export type Channels = keyof IpcDefinition;
@@ -16,17 +16,47 @@ import {
16
16
  AppConfigV5,
17
17
  AppConfigV6,
18
18
  AppConfigV7,
19
+ AppConfigV8,
19
20
  } from "../config.schema";
21
+
22
+ const DEFAULT_PLUGINS: AppConfigV8["plugins"] = [
23
+ {
24
+ name: "@pipelab/plugin-construct",
25
+ enabled: true,
26
+ description: "Construct 3 export & packaging",
27
+ },
28
+ { name: "@pipelab/plugin-filesystem", enabled: true, description: "Filesystem utilities" },
29
+ { name: "@pipelab/plugin-system", enabled: true, description: "System & shell commands" },
30
+ { name: "@pipelab/plugin-steam", enabled: true, description: "Steam publishing" },
31
+ { name: "@pipelab/plugin-itch", enabled: true, description: "Itch.io publishing" },
32
+ { name: "@pipelab/plugin-electron", enabled: true, description: "Electron packaging" },
33
+ { name: "@pipelab/plugin-discord", enabled: true, description: "Discord Rich Presence" },
34
+ { name: "@pipelab/plugin-poki", enabled: true, description: "Poki publishing" },
35
+ { name: "@pipelab/plugin-nvpatch", enabled: true, description: "NW.js patching" },
36
+ { name: "@pipelab/plugin-tauri", enabled: true, description: "Tauri packaging" },
37
+ { name: "@pipelab/plugin-minify", enabled: true, description: "Asset minification" },
38
+ { name: "@pipelab/plugin-netlify", enabled: true, description: "Netlify deployment" },
39
+ ];
20
40
  import { FileRepoV1, FileRepoV2, FileRepo } from "./projects-types";
21
- import { SavedFileV1, SavedFileV2, SavedFileV3, SavedFileV4, SavedFile } from "../model";
41
+ import {
42
+ SavedFileV1,
43
+ SavedFileV2,
44
+ SavedFileV3,
45
+ SavedFileV4,
46
+ SavedFileV5,
47
+ SavedFile,
48
+ } from "../model";
22
49
 
23
50
  // --- Types ---
24
51
 
25
52
  export type Additive<T, P> = OmitVersion<T> & OmitVersion<P>;
26
53
 
54
+ type DistributiveOmit<T, K extends keyof any> = T extends any ? Omit<T, K> : never;
55
+ type DistributiveOmitVersion<T> = DistributiveOmit<T, keyof MigrationSchema>;
56
+
27
57
  const createMigration = <From extends MigrationSchema, To extends MigrationSchema>(config: {
28
58
  version: SemVer;
29
- up: (state: OmitVersion<From>, targetVersion: string) => Awaitable<Additive<To, From>>;
59
+ up: (state: OmitVersion<From>, targetVersion: string) => Awaitable<OmitVersion<To>>;
30
60
  }) => createMigrationBase<From, To>(config);
31
61
 
32
62
  export interface Migrator<T> {
@@ -41,7 +71,7 @@ const settingsMigratorInternal = createMigrator<AppConfigV1, AppConfig>();
41
71
  export const defaultAppSettings = settingsMigratorInternal.createDefault({
42
72
  locale: "en-US",
43
73
  theme: "light",
44
- version: "7.0.0",
74
+ version: "8.0.0",
45
75
  autosave: true,
46
76
  agents: [],
47
77
  tours: {
@@ -61,6 +91,8 @@ export const defaultAppSettings = settingsMigratorInternal.createDefault({
61
91
  maxAge: 30,
62
92
  },
63
93
  },
94
+ plugins: DEFAULT_PLUGINS,
95
+ isInternalMigrationBannerClosed: false,
64
96
  });
65
97
 
66
98
  export const appSettingsMigrator = settingsMigratorInternal.createMigrations({
@@ -109,13 +141,12 @@ export const appSettingsMigrator = settingsMigratorInternal.createMigrations({
109
141
  autosave: true,
110
142
  }),
111
143
  }),
112
- createMigration<AppConfigV6, AppConfigV7>({
144
+ createMigration<AppConfigV6, AppConfigV8>({
113
145
  version: "6.0.0" as SemVer,
114
146
  up: (state) => {
115
- // Upgrades V6 to V7: Add agents, add buildHistory.
116
- // (Additive only - keeping cacheFolder and clearTemporaryFoldersOnPipelineEnd)
147
+ const { cacheFolder: _, clearTemporaryFoldersOnPipelineEnd: __, ...rest } = state;
117
148
  return {
118
- ...state,
149
+ ...rest,
119
150
  agents: [],
120
151
  buildHistory: {
121
152
  retentionPolicy: {
@@ -124,11 +155,13 @@ export const appSettingsMigrator = settingsMigratorInternal.createMigrations({
124
155
  maxAge: 30,
125
156
  },
126
157
  },
158
+ plugins: DEFAULT_PLUGINS,
159
+ isInternalMigrationBannerClosed: false,
127
160
  };
128
161
  },
129
162
  }),
130
- createMigration<AppConfigV7, never>({
131
- version: "7.0.0" as SemVer,
163
+ createMigration<AppConfigV8, never>({
164
+ version: "8.0.0" as SemVer,
132
165
  up: finalVersion,
133
166
  }),
134
167
  ],
@@ -196,8 +229,7 @@ const savedFileDefaultValue = savedFileMigratorInternal.createDefault({
196
229
  description: "",
197
230
  name: "",
198
231
  variables: [],
199
- type: "default",
200
- version: "4.0.0",
232
+ version: "5.0.0",
201
233
  });
202
234
 
203
235
  export const savedFileMigrator = savedFileMigratorInternal.createMigrations({
@@ -275,13 +307,129 @@ export const savedFileMigrator = savedFileMigratorInternal.createMigrations({
275
307
  type: "default",
276
308
  }),
277
309
  }),
278
- createMigration<SavedFileV4, never>({
310
+ createMigration<SavedFileV4, SavedFileV5>({
279
311
  version: "4.0.0" as SemVer,
312
+ up: (_state) => {
313
+ const state = _state as DistributiveOmitVersion<SavedFileV4>;
314
+ if (state.type === "simple") {
315
+ return {
316
+ name: state.name,
317
+ description: state.description,
318
+ canvas: {
319
+ blocks: [],
320
+ triggers: [],
321
+ },
322
+ variables: [],
323
+ };
324
+ }
325
+
326
+ const migrateBlock = (block: any, pluginsMap: Record<string, string>) => {
327
+ if (!block) return;
328
+ if (block.origin?.pluginId) {
329
+ block.origin.pluginId = getStrictPluginId(block.origin.pluginId);
330
+ // Stamp the version from the old top-level plugins map, falling back to "latest"
331
+ block.origin.version = pluginsMap[block.origin.pluginId] ?? "latest";
332
+ }
333
+ };
334
+
335
+ // Normalise the old plugins map's keys first so lookups are consistent
336
+ const normalizedPlugins: Record<string, string> = {};
337
+ if (state.plugins) {
338
+ for (const [key, val] of Object.entries(state.plugins)) {
339
+ normalizedPlugins[getStrictPluginId(key)] = val;
340
+ }
341
+ }
342
+
343
+ // Stamp origin.version on every block and trigger
344
+ if (state.canvas) {
345
+ for (const block of state.canvas.blocks ?? []) {
346
+ migrateBlock(block, normalizedPlugins);
347
+ }
348
+ for (const trigger of state.canvas.triggers ?? []) {
349
+ migrateBlock(trigger, normalizedPlugins);
350
+ }
351
+ }
352
+
353
+ // Drop the top-level plugins map — version is now per-block. Omit type.
354
+ const { plugins: _dropped, type: _type, ...rest } = state;
355
+ return rest;
356
+ },
357
+ }),
358
+ createMigration<SavedFileV5, never>({
359
+ version: "5.0.0" as SemVer,
280
360
  up: finalVersion,
281
361
  }),
282
362
  ],
283
363
  });
284
364
 
365
+ const LEGACY_ID_MAP: Record<string, string> = {
366
+ construct: "@pipelab/plugin-construct",
367
+ filesystem: "@pipelab/plugin-filesystem",
368
+ system: "@pipelab/plugin-system",
369
+ steam: "@pipelab/plugin-steam",
370
+ itch: "@pipelab/plugin-itch",
371
+ electron: "@pipelab/plugin-electron",
372
+ discord: "@pipelab/plugin-discord",
373
+ dicord: "@pipelab/plugin-discord",
374
+ "@pipelab/plugin-dicord": "@pipelab/plugin-discord",
375
+ poki: "@pipelab/plugin-poki",
376
+ nvpatch: "@pipelab/plugin-nvpatch",
377
+ tauri: "@pipelab/plugin-tauri",
378
+ minify: "@pipelab/plugin-minify",
379
+ netlify: "@pipelab/plugin-netlify",
380
+ };
381
+
382
+ export const getStrictPluginId = (pluginId: string): string => {
383
+ if (!pluginId) return pluginId;
384
+ if (LEGACY_ID_MAP[pluginId]) {
385
+ return LEGACY_ID_MAP[pluginId];
386
+ }
387
+ if (
388
+ pluginId.startsWith("@") ||
389
+ pluginId.includes("/") ||
390
+ pluginId.startsWith("pipelab-plugin-")
391
+ ) {
392
+ return pluginId;
393
+ }
394
+ const prefixed = `@pipelab/plugin-${pluginId}`;
395
+ return LEGACY_ID_MAP[prefixed] || prefixed;
396
+ };
397
+
398
+ const normalizeBlockPluginId = (block: any): boolean => {
399
+ if (!block) return false;
400
+ let changed = false;
401
+ if (block.origin?.pluginId) {
402
+ const strictId = getStrictPluginId(block.origin.pluginId);
403
+ if (block.origin.pluginId !== strictId) {
404
+ block.origin.pluginId = strictId;
405
+ changed = true;
406
+ }
407
+ }
408
+ return changed;
409
+ };
410
+
411
+ export const normalizePipelineConfig = (state: any): boolean => {
412
+ if (!state) return false;
413
+ let changed = false;
414
+
415
+ // Normalise plugin IDs in block and trigger origins (pluginId field only;
416
+ // version strings don't need normalisation)
417
+ if (state.type === "default" && state.canvas) {
418
+ if (Array.isArray(state.canvas.blocks)) {
419
+ for (const block of state.canvas.blocks) {
420
+ if (normalizeBlockPluginId(block)) changed = true;
421
+ }
422
+ }
423
+ if (Array.isArray(state.canvas.triggers)) {
424
+ for (const trigger of state.canvas.triggers) {
425
+ if (normalizeBlockPluginId(trigger)) changed = true;
426
+ }
427
+ }
428
+ }
429
+
430
+ return changed;
431
+ };
432
+
285
433
  // --- Registry ---
286
434
 
287
435
  export const configRegistry: Record<string, Migrator<any>> = {
@@ -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
  };
@@ -8,6 +8,7 @@ import {
8
8
  number,
9
9
  array,
10
10
  GenericSchema,
11
+ optional,
11
12
  } from "valibot";
12
13
 
13
14
  export const createVersionSchema = <T extends GenericSchema<any, any>>(schema: T) => schema;
@@ -135,6 +136,54 @@ export const AppSettingsValidatorV7 = object({
135
136
  }),
136
137
  });
137
138
 
139
+ export const AppSettingsValidatorV8 = object({
140
+ theme: union([literal("light"), literal("dark")]),
141
+ version: literal("8.0.0"),
142
+ locale: union([
143
+ literal("en-US"),
144
+ literal("fr-FR"),
145
+ literal("pt-BR"),
146
+ literal("zh-CN"),
147
+ literal("es-ES"),
148
+ literal("de-DE"),
149
+ ]),
150
+ tours: object({
151
+ dashboard: object({
152
+ step: number(),
153
+ completed: boolean(),
154
+ }),
155
+ editor: object({
156
+ step: number(),
157
+ completed: boolean(),
158
+ }),
159
+ }),
160
+ autosave: boolean(),
161
+ agents: array(
162
+ object({
163
+ id: string(),
164
+ name: string(),
165
+ url: string(),
166
+ }),
167
+ ),
168
+ buildHistory: object({
169
+ retentionPolicy: object({
170
+ enabled: boolean(),
171
+ maxEntries: number(), // Maximum number of entries per pipeline
172
+ maxAge: number(), // Maximum age of entries in days
173
+ }),
174
+ }),
175
+ // Metadata list of plugins the user has enabled (official + community).
176
+ // No binaries are stored here — versions are resolved JIT at node-add time.
177
+ plugins: array(
178
+ object({
179
+ name: string(),
180
+ enabled: boolean(),
181
+ description: string(),
182
+ }),
183
+ ),
184
+ isInternalMigrationBannerClosed: optional(boolean(), false),
185
+ });
186
+
138
187
  export type AppConfigV1 = InferInput<typeof AppSettingsValidatorV1>;
139
188
  export type AppConfigV2 = InferInput<typeof AppSettingsValidatorV2>;
140
189
  export type AppConfigV3 = InferInput<typeof AppSettingsValidatorV3>;
@@ -142,6 +191,7 @@ export type AppConfigV4 = InferInput<typeof AppSettingsValidatorV4>;
142
191
  export type AppConfigV5 = InferInput<typeof AppSettingsValidatorV5>;
143
192
  export type AppConfigV6 = InferInput<typeof AppSettingsValidatorV6>;
144
193
  export type AppConfigV7 = InferInput<typeof AppSettingsValidatorV7>;
194
+ export type AppConfigV8 = InferInput<typeof AppSettingsValidatorV8>;
145
195
 
146
- export type AppConfig = AppConfigV7;
147
- export const AppSettingsValidator = AppSettingsValidatorV7;
196
+ export type AppConfig = AppConfigV8;
197
+ export const AppSettingsValidator = AppSettingsValidatorV8;
package/src/graph.ts CHANGED
@@ -42,7 +42,7 @@ export const processGraph = async (options: {
42
42
  node: Block,
43
43
  params: Record<string, string>,
44
44
  steps: Steps,
45
- ) => Promise<End<"condition:execute"> | End<"action:execute">>;
45
+ ) => Promise<End<"action:execute">>;
46
46
  onNodeEnter: (node: Block) => void;
47
47
  onNodeExit: (node: Block) => void;
48
48
  abortSignal?: AbortSignal;
@@ -68,47 +68,7 @@ export const processGraph = async (options: {
68
68
  options.definitions,
69
69
  );
70
70
 
71
- /* if (rawNode.type === 'condition') {
72
- options.onNodeEnter(rawNode)
73
-
74
- const newParams = await makeResolvedParams({
75
- params: rawNode.params,
76
- variables: options.variables,
77
- steps: options.steps,
78
- context: options.context
79
- })
80
-
81
- const result = await options.onExecuteItem(node, newParams, options.steps) as End<'condition:execute'>
82
-
83
- if ('result' in result) {
84
- logger().error(result.result)
85
- options.onNodeExit(rawNode)
86
- throw new Error('Condition error')
87
- } else {
88
- const { value, outputs } = result
89
- if (!options.steps[rawNode.uid]) {
90
- options.steps[rawNode.uid] = {
91
- outputs: {}
92
- }
93
- }
94
- options.steps[rawNode.uid].outputs = outputs
95
-
96
- if (value === true) {
97
- await processGraph({
98
- graph: rawNode.branchTrue,
99
- ...options,
100
- abortSignal: options.abortSignal
101
- })
102
- } else {
103
- await processGraph({
104
- graph: rawNode.branchFalse,
105
- ...options,
106
- abortSignal: options.abortSignal
107
- })
108
- }
109
- }
110
- options.onNodeExit(rawNode)
111
- } else */ if (rawNode.type === "action") {
71
+ if (rawNode.type === "action") {
112
72
  if (rawNode.disabled === true) {
113
73
  console.warn(
114
74
  `Node ${rawNode.uid} (${rawNode.origin.pluginId}::${rawNode.origin.nodeId}) is disabled`,
@@ -163,34 +123,6 @@ export const processGraph = async (options: {
163
123
  options.steps[rawNode.uid].outputs = result.result.outputs;
164
124
  }
165
125
  options.onNodeExit(rawNode);
166
- } else if (rawNode.type === "loop") {
167
- options.onNodeEnter(rawNode);
168
-
169
- // const context = {}
170
-
171
- // const arrayToLoopOn = await evaluate(rawNode.params.value, context)
172
-
173
- // element is the value of the element at loopindex
174
- // let loopindex = 0
175
- // for (const _element of arrayToLoopOn) {
176
- // await processGraph(rawNode.children, definitions, variables, steps, {
177
- // ...context,
178
- // loopindex
179
- // })
180
-
181
- // loopindex += 1
182
- // }
183
-
184
- // continue after loop
185
-
186
- // TODO: process loop
187
- // const result = await api.execute('node:execute', {
188
- // nodeId: rawNode.origin.nodeId,
189
- // pluginId: rawNode.origin.pluginId,
190
- // params: rawNode.params
191
- // })
192
- // console.log('result', result)
193
- options.onNodeExit(rawNode);
194
126
  } else if (rawNode.type === "comment") {
195
127
  // pass
196
128
  } else if (rawNode.type === "event") {
@@ -15,7 +15,10 @@
15
15
  "storage": "Storage",
16
16
  "integrations": "Integrations",
17
17
  "advanced": "Advanced",
18
- "billing": "Billing"
18
+ "billing": "Billing",
19
+ "plugins": "Plugins",
20
+ "core-plugins": "Core-Plugins",
21
+ "community-plugins": "Community-Plugins"
19
22
  },
20
23
  "clearTempFolders": "Automatically clean up temporary files",
21
24
  "clearTempFoldersDescription": "Wenn aktiviert, werden alle temporären Dateien, die während der Pipeline-Ausführung erstellt wurden, automatisch gelöscht, nachdem die Pipeline abgeschlossen ist. Dies hilft, Speicherplatz auf der Festplatte zu sparen, aber möglicherweise müssen Sie selbst Artefakte kopieren, um sie zu bewahren.",
@@ -17,7 +17,10 @@
17
17
  "storage": "Storage",
18
18
  "integrations": "Integrations",
19
19
  "advanced": "Advanced",
20
- "billing": "Billing"
20
+ "billing": "Billing",
21
+ "plugins": "Plugins",
22
+ "core-plugins": "Core Plugins",
23
+ "community-plugins": "Community Plugins"
21
24
  },
22
25
  "pipeline-cache-folder": "Pipeline Cache Folder:",
23
26
  "enter-or-browse-for-a-folder": "Enter or browse for a folder",
@@ -83,7 +86,14 @@
83
86
  "your-project-has-be-saved-successfully": "Your project has be saved successfully",
84
87
  "view-history": "History",
85
88
  "add-plugin": "Add plugin",
86
- "display-advanced-nodes": "Display advanced nodes"
89
+ "display-advanced-nodes": "Display advanced nodes",
90
+ "project-settings": "Pipeline Settings",
91
+ "jit-loading-title": "Installing Required Plugins",
92
+ "jit-loading-subtitle": "Please wait while Pipelab fetches and prepares the necessary nodes for this pipeline.",
93
+ "jit-loading-status": "Downloading and building plugin packages…",
94
+ "validation-failed": "Validation Failed",
95
+ "validation-plugin-disabled-or-missing": "Plugin \"{pluginId}\" is disabled or not installed (required by \"{nodeName}\").",
96
+ "validation-missing-param": "Block \"{nodeName}\": missing required parameter \"{paramName}\"."
87
97
  },
88
98
  "home": {
89
99
  "invalid-preset": "Invalid preset",
@@ -129,7 +139,11 @@
129
139
  "confirm-migration-message": "Are you sure you want to migrate this pipeline to internal storage? This will create a copy in the internal storage managed by Pipelab.",
130
140
  "migrate-pipeline": "Migrate Pipeline",
131
141
  "migration-success": "Pipeline migrated successfully",
132
- "migrate-to-internal": "Migrate to Internal"
142
+ "migrate-to-internal": "Migrate to Internal",
143
+ "only-internal-supported-notice": "Pipelab now stores pipelines internally. External pipeline files are deprecated. You can still import external files as internal pipelines.",
144
+ "import-pipeline": "Import Pipeline",
145
+ "import-success": "Pipeline imported successfully",
146
+ "failed-to-read-file": "Failed to read the selected file"
133
147
  },
134
148
  "scenarios": {
135
149
  "scenarios": "Scenarios"
@@ -15,7 +15,10 @@
15
15
  "storage": "Storage",
16
16
  "integrations": "Integrations",
17
17
  "advanced": "Advanced",
18
- "billing": "Billing"
18
+ "billing": "Billing",
19
+ "plugins": "Plugins",
20
+ "core-plugins": "Complementos principales",
21
+ "community-plugins": "Complementos de la comunidad"
19
22
  },
20
23
  "clearTempFolders": "Automatically clean up temporary files",
21
24
  "clearTempFoldersDescription": "Cuando está habilitado, todos los archivos temporales creados durante la ejecución del pipeline se eliminarán automáticamente después de que el pipeline se complete. Esto ayuda a ahorrar espacio en el disco, pero puede que necesite copiar los artefactos usted mismo para preservarlos.",
@@ -15,7 +15,10 @@
15
15
  "storage": "Stockage",
16
16
  "integrations": "Intégrations",
17
17
  "advanced": "Avancé",
18
- "billing": "Facturation"
18
+ "billing": "Facturation",
19
+ "plugins": "Plugins",
20
+ "core-plugins": "Plugins de base",
21
+ "community-plugins": "Plugins de la communauté"
19
22
  },
20
23
  "clearTempFolders": "Nettoyer automatiquement les fichiers temporaires",
21
24
  "clearTempFoldersDescription": "Lorsque cette option est activée, tous les fichiers temporaires créés lors de l'exécution du pipeline seront automatiquement supprimés une fois le pipeline terminé. Cela permet d'économiser de l'espace disque, mais vous devrez peut-être copier vous-même des artefacts pour les préserver.",
@@ -15,7 +15,10 @@
15
15
  "storage": "Armazenagem",
16
16
  "integrations": "Integrações",
17
17
  "advanced": "Avançado",
18
- "billing": "Pagamento"
18
+ "billing": "Pagamento",
19
+ "plugins": "Plugins",
20
+ "core-plugins": "Plugins nativos",
21
+ "community-plugins": "Plugins da comunidade"
19
22
  },
20
23
  "clearTempFolders": "Automatically clean up temporary files",
21
24
  "clearTempFoldersDescription": "When enabled, all temporary files created during pipeline execution will be automatically deleted after the pipeline completes. This helps save disk space but you may need to copy artifacts yourself to preserve them.",
@@ -15,7 +15,10 @@
15
15
  "storage": "Storage",
16
16
  "integrations": "Integrations",
17
17
  "advanced": "Advanced",
18
- "billing": "Billing"
18
+ "billing": "Billing",
19
+ "plugins": "Plugins",
20
+ "core-plugins": "核心插件",
21
+ "community-plugins": "社区插件"
19
22
  },
20
23
  "clearTempFolders": "Automatically clean up temporary files",
21
24
  "clearTempFoldersDescription": "When enabled, all temporary files created during pipeline execution will be automatically deleted after the pipeline completes. This helps save disk space but you may need to copy artifacts yourself to preserve them.",
package/src/index.ts CHANGED
@@ -6,6 +6,7 @@ import {
6
6
  defaultFileRepo as _defaultFileRepo,
7
7
  savedFileMigrator as _savedFileMigrator,
8
8
  configRegistry as _configRegistry,
9
+ normalizePipelineConfig as _normalizePipelineConfig,
9
10
  } from "./config/migrators";
10
11
 
11
12
  export const appSettingsMigrator = _appSettingsMigrator;
@@ -14,6 +15,7 @@ export const fileRepoMigrations = _fileRepoMigrations;
14
15
  export const defaultFileRepo = _defaultFileRepo;
15
16
  export const savedFileMigrator = _savedFileMigrator;
16
17
  export const configRegistry = _configRegistry;
18
+ export const normalizePipelineConfig = _normalizePipelineConfig;
17
19
 
18
20
  // 2. Types
19
21
  export type { Migrator } from "./config/migrators";