@uploadista/server 0.0.11 → 0.0.13-beta.1

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.
@@ -7,10 +7,10 @@
7
7
  import { Layer } from "effect";
8
8
  import { describe, expect, it } from "vitest";
9
9
  import {
10
- extractServiceIdentifiers,
11
- formatPluginValidationError,
12
- validatePluginRequirements,
13
- validatePluginsOrThrow,
10
+ extractServiceIdentifiers,
11
+ formatPluginValidationError,
12
+ validatePluginRequirements,
13
+ validatePluginsOrThrow,
14
14
  } from "../plugin-validation";
15
15
 
16
16
  // ============================================================================
@@ -18,24 +18,24 @@ import {
18
18
  // ============================================================================
19
19
 
20
20
  class TestImagePlugin {
21
- readonly _tag = "ImagePlugin";
22
- resize(data: Buffer, width: number): Buffer {
23
- return data;
24
- }
21
+ readonly _tag = "ImagePlugin";
22
+ resize(data: Buffer, width: number): Buffer {
23
+ return data;
24
+ }
25
25
  }
26
26
 
27
27
  class TestZipPlugin {
28
- readonly _tag = "ZipPlugin";
29
- compress(files: Buffer[]): Buffer {
30
- return Buffer.from([]);
31
- }
28
+ readonly _tag = "ZipPlugin";
29
+ compress(files: Buffer[]): Buffer {
30
+ return Buffer.from([]);
31
+ }
32
32
  }
33
33
 
34
34
  class TestVideoPlugin {
35
- readonly _tag = "VideoPlugin";
36
- transcode(data: Buffer): Buffer {
37
- return data;
38
- }
35
+ readonly _tag = "VideoPlugin";
36
+ transcode(data: Buffer): Buffer {
37
+ return data;
38
+ }
39
39
  }
40
40
 
41
41
  const imagePluginLayer = Layer.succeed(TestImagePlugin, new TestImagePlugin());
@@ -47,29 +47,29 @@ const videoPluginLayer = Layer.succeed(TestVideoPlugin, new TestVideoPlugin());
47
47
  // ============================================================================
48
48
 
49
49
  describe("extractServiceIdentifiers", () => {
50
- it("should extract identifiers from plugin array", () => {
51
- const plugins = [imagePluginLayer, zipPluginLayer];
52
- const identifiers = extractServiceIdentifiers(plugins);
50
+ it("should extract identifiers from plugin array", () => {
51
+ const plugins = [imagePluginLayer, zipPluginLayer];
52
+ const identifiers = extractServiceIdentifiers(plugins);
53
53
 
54
- // Should return array of strings (exact values depend on Effect internals)
55
- expect(Array.isArray(identifiers)).toBe(true);
56
- expect(identifiers.length).toBeGreaterThanOrEqual(0);
57
- });
54
+ // Should return array of strings (exact values depend on Effect internals)
55
+ expect(Array.isArray(identifiers)).toBe(true);
56
+ expect(identifiers.length).toBeGreaterThanOrEqual(0);
57
+ });
58
58
 
59
- it("should handle empty plugin array", () => {
60
- const plugins: never[] = [];
61
- const identifiers = extractServiceIdentifiers(plugins);
59
+ it("should handle empty plugin array", () => {
60
+ const plugins: never[] = [];
61
+ const identifiers = extractServiceIdentifiers(plugins);
62
62
 
63
- expect(Array.isArray(identifiers)).toBe(true);
64
- expect(identifiers).toHaveLength(0);
65
- });
63
+ expect(Array.isArray(identifiers)).toBe(true);
64
+ expect(identifiers).toHaveLength(0);
65
+ });
66
66
 
67
- it("should handle single plugin", () => {
68
- const plugins = [imagePluginLayer];
69
- const identifiers = extractServiceIdentifiers(plugins);
67
+ it("should handle single plugin", () => {
68
+ const plugins = [imagePluginLayer];
69
+ const identifiers = extractServiceIdentifiers(plugins);
70
70
 
71
- expect(Array.isArray(identifiers)).toBe(true);
72
- });
71
+ expect(Array.isArray(identifiers)).toBe(true);
72
+ });
73
73
  });
74
74
 
75
75
  // ============================================================================
@@ -77,97 +77,97 @@ describe("extractServiceIdentifiers", () => {
77
77
  // ============================================================================
78
78
 
79
79
  describe("validatePluginRequirements", () => {
80
- it("should return success when no services are expected", () => {
81
- const result = validatePluginRequirements({
82
- plugins: [imagePluginLayer],
83
- expectedServices: [],
84
- });
85
-
86
- expect(result.success).toBe(true);
87
- });
88
-
89
- it("should return success when expected services is undefined", () => {
90
- const result = validatePluginRequirements({
91
- plugins: [imagePluginLayer],
92
- });
93
-
94
- expect(result.success).toBe(true);
95
- });
96
-
97
- it("should detect missing services", () => {
98
- const result = validatePluginRequirements({
99
- plugins: [],
100
- expectedServices: ["ImagePlugin", "ZipPlugin"],
101
- });
102
-
103
- expect(result.success).toBe(false);
104
- if (!result.success) {
105
- expect(result.missing).toEqual(["ImagePlugin", "ZipPlugin"]);
106
- expect(result.required).toEqual(["ImagePlugin", "ZipPlugin"]);
107
- expect(result.provided).toEqual([]);
108
- }
109
- });
110
-
111
- it("should detect partially missing services", () => {
112
- const result = validatePluginRequirements({
113
- plugins: [imagePluginLayer],
114
- expectedServices: ["ImagePlugin", "ZipPlugin"],
115
- });
116
-
117
- // Since we can't reliably extract service identifiers from Effect layers,
118
- // this test verifies the validation logic structure
119
- expect(result).toHaveProperty("success");
120
- });
121
-
122
- it("should generate suggestions for known plugins", () => {
123
- const result = validatePluginRequirements({
124
- plugins: [],
125
- expectedServices: ["ImagePlugin"],
126
- });
127
-
128
- expect(result.success).toBe(false);
129
- if (!result.success) {
130
- expect(result.suggestions.length).toBeGreaterThan(0);
131
- const suggestion = result.suggestions[0];
132
- expect(suggestion).toHaveProperty("name");
133
- expect(suggestion).toHaveProperty("packageName");
134
- expect(suggestion).toHaveProperty("importStatement");
135
- expect(suggestion.name).toBe("ImagePlugin");
136
- }
137
- });
138
-
139
- it("should handle unknown plugin services", () => {
140
- const result = validatePluginRequirements({
141
- plugins: [],
142
- expectedServices: ["UnknownPlugin"],
143
- });
144
-
145
- expect(result.success).toBe(false);
146
- if (!result.success) {
147
- expect(result.missing).toContain("UnknownPlugin");
148
- // Should not generate suggestion for unknown plugins
149
- const unknownSuggestion = result.suggestions.find(
150
- (s) => s.name === "UnknownPlugin",
151
- );
152
- expect(unknownSuggestion).toBeUndefined();
153
- }
154
- });
155
-
156
- it("should handle multiple known plugins", () => {
157
- const result = validatePluginRequirements({
158
- plugins: [],
159
- expectedServices: ["ImagePlugin", "ZipPlugin"],
160
- });
161
-
162
- expect(result.success).toBe(false);
163
- if (!result.success) {
164
- expect(result.suggestions.length).toBe(2);
165
- expect(result.suggestions.map((s) => s.name)).toEqual([
166
- "ImagePlugin",
167
- "ZipPlugin",
168
- ]);
169
- }
170
- });
80
+ it("should return success when no services are expected", () => {
81
+ const result = validatePluginRequirements({
82
+ plugins: [imagePluginLayer],
83
+ expectedServices: [],
84
+ });
85
+
86
+ expect(result.success).toBe(true);
87
+ });
88
+
89
+ it("should return success when expected services is undefined", () => {
90
+ const result = validatePluginRequirements({
91
+ plugins: [imagePluginLayer],
92
+ });
93
+
94
+ expect(result.success).toBe(true);
95
+ });
96
+
97
+ it("should detect missing services", () => {
98
+ const result = validatePluginRequirements({
99
+ plugins: [],
100
+ expectedServices: ["ImagePlugin", "ZipPlugin"],
101
+ });
102
+
103
+ expect(result.success).toBe(false);
104
+ if (!result.success) {
105
+ expect(result.missing).toEqual(["ImagePlugin", "ZipPlugin"]);
106
+ expect(result.required).toEqual(["ImagePlugin", "ZipPlugin"]);
107
+ expect(result.provided).toEqual([]);
108
+ }
109
+ });
110
+
111
+ it("should detect partially missing services", () => {
112
+ const result = validatePluginRequirements({
113
+ plugins: [imagePluginLayer],
114
+ expectedServices: ["ImagePlugin", "ZipPlugin"],
115
+ });
116
+
117
+ // Since we can't reliably extract service identifiers from Effect layers,
118
+ // this test verifies the validation logic structure
119
+ expect(result).toHaveProperty("success");
120
+ });
121
+
122
+ it("should generate suggestions for known plugins", () => {
123
+ const result = validatePluginRequirements({
124
+ plugins: [],
125
+ expectedServices: ["ImagePlugin"],
126
+ });
127
+
128
+ expect(result.success).toBe(false);
129
+ if (!result.success) {
130
+ expect(result.suggestions.length).toBeGreaterThan(0);
131
+ const suggestion = result.suggestions[0];
132
+ expect(suggestion).toHaveProperty("name");
133
+ expect(suggestion).toHaveProperty("packageName");
134
+ expect(suggestion).toHaveProperty("importStatement");
135
+ expect(suggestion.name).toBe("ImagePlugin");
136
+ }
137
+ });
138
+
139
+ it("should handle unknown plugin services", () => {
140
+ const result = validatePluginRequirements({
141
+ plugins: [],
142
+ expectedServices: ["UnknownPlugin"],
143
+ });
144
+
145
+ expect(result.success).toBe(false);
146
+ if (!result.success) {
147
+ expect(result.missing).toContain("UnknownPlugin");
148
+ // Should not generate suggestion for unknown plugins
149
+ const unknownSuggestion = result.suggestions.find(
150
+ (s) => s.name === "UnknownPlugin",
151
+ );
152
+ expect(unknownSuggestion).toBeUndefined();
153
+ }
154
+ });
155
+
156
+ it("should handle multiple known plugins", () => {
157
+ const result = validatePluginRequirements({
158
+ plugins: [],
159
+ expectedServices: ["ImagePlugin", "ZipPlugin"],
160
+ });
161
+
162
+ expect(result.success).toBe(false);
163
+ if (!result.success) {
164
+ expect(result.suggestions.length).toBe(2);
165
+ expect(result.suggestions.map((s) => s.name)).toEqual([
166
+ "ImagePlugin",
167
+ "ZipPlugin",
168
+ ]);
169
+ }
170
+ });
171
171
  });
172
172
 
173
173
  // ============================================================================
@@ -175,88 +175,88 @@ describe("validatePluginRequirements", () => {
175
175
  // ============================================================================
176
176
 
177
177
  describe("formatPluginValidationError", () => {
178
- it("should format error message with suggestions", () => {
179
- const result = validatePluginRequirements({
180
- plugins: [],
181
- expectedServices: ["ImagePlugin", "ZipPlugin"],
182
- });
183
-
184
- expect(result.success).toBe(false);
185
- if (!result.success) {
186
- const message = formatPluginValidationError(result);
187
-
188
- expect(message).toContain("Server initialization failed");
189
- expect(message).toContain("Missing required plugins");
190
- expect(message).toContain("ImagePlugin");
191
- expect(message).toContain("ZipPlugin");
192
- expect(message).toContain("Required:");
193
- expect(message).toContain("Missing:");
194
- }
195
- });
196
-
197
- it("should include import statements in error message", () => {
198
- const result = validatePluginRequirements({
199
- plugins: [],
200
- expectedServices: ["ImagePlugin"],
201
- });
202
-
203
- expect(result.success).toBe(false);
204
- if (!result.success) {
205
- const message = formatPluginValidationError(result);
206
-
207
- expect(message).toContain("import");
208
- expect(message).toContain("@uploadista/flow-images-sharp");
209
- expect(message).toContain("sharpImagePlugin");
210
- }
211
- });
212
-
213
- it("should include example server configuration", () => {
214
- const result = validatePluginRequirements({
215
- plugins: [],
216
- expectedServices: ["ImagePlugin"],
217
- });
218
-
219
- expect(result.success).toBe(false);
220
- if (!result.success) {
221
- const message = formatPluginValidationError(result);
222
-
223
- expect(message).toContain("createUploadistaServer");
224
- expect(message).toContain("plugins:");
225
- }
226
- });
227
-
228
- it("should handle missing suggestions gracefully", () => {
229
- const result = validatePluginRequirements({
230
- plugins: [],
231
- expectedServices: ["UnknownPlugin"],
232
- });
233
-
234
- expect(result.success).toBe(false);
235
- if (!result.success) {
236
- const message = formatPluginValidationError(result);
237
-
238
- expect(message).toContain("Server initialization failed");
239
- expect(message).toContain("UnknownPlugin");
240
- expect(message).toContain(
241
- "Could not determine package names for missing plugins",
242
- );
243
- }
244
- });
245
-
246
- it("should show provided services when some are present", () => {
247
- const result = validatePluginRequirements({
248
- plugins: [imagePluginLayer],
249
- expectedServices: ["ImagePlugin", "ZipPlugin"],
250
- });
251
-
252
- expect(result.success).toBe(false);
253
- if (!result.success) {
254
- const message = formatPluginValidationError(result);
255
-
256
- expect(message).toContain("Provided:");
257
- // The exact provided services depend on Effect's internal representation
258
- }
259
- });
178
+ it("should format error message with suggestions", () => {
179
+ const result = validatePluginRequirements({
180
+ plugins: [],
181
+ expectedServices: ["ImagePlugin", "ZipPlugin"],
182
+ });
183
+
184
+ expect(result.success).toBe(false);
185
+ if (!result.success) {
186
+ const message = formatPluginValidationError(result);
187
+
188
+ expect(message).toContain("Server initialization failed");
189
+ expect(message).toContain("Missing required plugins");
190
+ expect(message).toContain("ImagePlugin");
191
+ expect(message).toContain("ZipPlugin");
192
+ expect(message).toContain("Required:");
193
+ expect(message).toContain("Missing:");
194
+ }
195
+ });
196
+
197
+ it("should include import statements in error message", () => {
198
+ const result = validatePluginRequirements({
199
+ plugins: [],
200
+ expectedServices: ["ImagePlugin"],
201
+ });
202
+
203
+ expect(result.success).toBe(false);
204
+ if (!result.success) {
205
+ const message = formatPluginValidationError(result);
206
+
207
+ expect(message).toContain("import");
208
+ expect(message).toContain("@uploadista/flow-images-sharp");
209
+ expect(message).toContain("sharpImagePlugin");
210
+ }
211
+ });
212
+
213
+ it("should include example server configuration", () => {
214
+ const result = validatePluginRequirements({
215
+ plugins: [],
216
+ expectedServices: ["ImagePlugin"],
217
+ });
218
+
219
+ expect(result.success).toBe(false);
220
+ if (!result.success) {
221
+ const message = formatPluginValidationError(result);
222
+
223
+ expect(message).toContain("createUploadistaServer");
224
+ expect(message).toContain("plugins:");
225
+ }
226
+ });
227
+
228
+ it("should handle missing suggestions gracefully", () => {
229
+ const result = validatePluginRequirements({
230
+ plugins: [],
231
+ expectedServices: ["UnknownPlugin"],
232
+ });
233
+
234
+ expect(result.success).toBe(false);
235
+ if (!result.success) {
236
+ const message = formatPluginValidationError(result);
237
+
238
+ expect(message).toContain("Server initialization failed");
239
+ expect(message).toContain("UnknownPlugin");
240
+ expect(message).toContain(
241
+ "Could not determine package names for missing plugins",
242
+ );
243
+ }
244
+ });
245
+
246
+ it("should show provided services when some are present", () => {
247
+ const result = validatePluginRequirements({
248
+ plugins: [imagePluginLayer],
249
+ expectedServices: ["ImagePlugin", "ZipPlugin"],
250
+ });
251
+
252
+ expect(result.success).toBe(false);
253
+ if (!result.success) {
254
+ const message = formatPluginValidationError(result);
255
+
256
+ expect(message).toContain("Provided:");
257
+ // The exact provided services depend on Effect's internal representation
258
+ }
259
+ });
260
260
  });
261
261
 
262
262
  // ============================================================================
@@ -264,48 +264,48 @@ describe("formatPluginValidationError", () => {
264
264
  // ============================================================================
265
265
 
266
266
  describe("validatePluginsOrThrow", () => {
267
- it("should not throw when validation passes", () => {
268
- expect(() => {
269
- validatePluginsOrThrow({
270
- plugins: [imagePluginLayer],
271
- expectedServices: [],
272
- });
273
- }).not.toThrow();
274
- });
275
-
276
- it("should throw when validation fails", () => {
277
- expect(() => {
278
- validatePluginsOrThrow({
279
- plugins: [],
280
- expectedServices: ["ImagePlugin"],
281
- });
282
- }).toThrow("Server initialization failed");
283
- });
284
-
285
- it("should throw error with detailed message", () => {
286
- expect(() => {
287
- validatePluginsOrThrow({
288
- plugins: [],
289
- expectedServices: ["ImagePlugin", "ZipPlugin"],
290
- });
291
- }).toThrow(/Missing required plugins/);
292
- });
293
-
294
- it("should include plugin names in error", () => {
295
- try {
296
- validatePluginsOrThrow({
297
- plugins: [],
298
- expectedServices: ["ImagePlugin", "ZipPlugin"],
299
- });
300
- expect.fail("Should have thrown");
301
- } catch (error) {
302
- expect(error).toBeInstanceOf(Error);
303
- if (error instanceof Error) {
304
- expect(error.message).toContain("ImagePlugin");
305
- expect(error.message).toContain("ZipPlugin");
306
- }
307
- }
308
- });
267
+ it("should not throw when validation passes", () => {
268
+ expect(() => {
269
+ validatePluginsOrThrow({
270
+ plugins: [imagePluginLayer],
271
+ expectedServices: [],
272
+ });
273
+ }).not.toThrow();
274
+ });
275
+
276
+ it("should throw when validation fails", () => {
277
+ expect(() => {
278
+ validatePluginsOrThrow({
279
+ plugins: [],
280
+ expectedServices: ["ImagePlugin"],
281
+ });
282
+ }).toThrow("Server initialization failed");
283
+ });
284
+
285
+ it("should throw error with detailed message", () => {
286
+ expect(() => {
287
+ validatePluginsOrThrow({
288
+ plugins: [],
289
+ expectedServices: ["ImagePlugin", "ZipPlugin"],
290
+ });
291
+ }).toThrow(/Missing required plugins/);
292
+ });
293
+
294
+ it("should include plugin names in error", () => {
295
+ try {
296
+ validatePluginsOrThrow({
297
+ plugins: [],
298
+ expectedServices: ["ImagePlugin", "ZipPlugin"],
299
+ });
300
+ expect.fail("Should have thrown");
301
+ } catch (error) {
302
+ expect(error).toBeInstanceOf(Error);
303
+ if (error instanceof Error) {
304
+ expect(error.message).toContain("ImagePlugin");
305
+ expect(error.message).toContain("ZipPlugin");
306
+ }
307
+ }
308
+ });
309
309
  });
310
310
 
311
311
  // ============================================================================
@@ -313,61 +313,61 @@ describe("validatePluginsOrThrow", () => {
313
313
  // ============================================================================
314
314
 
315
315
  describe("Plugin Validation Integration", () => {
316
- it("should handle realistic server configuration scenario", () => {
317
- // Scenario: Server configured with image plugin, but flow needs both image and zip
318
- const result = validatePluginRequirements({
319
- plugins: [imagePluginLayer],
320
- expectedServices: ["ImagePlugin", "ZipPlugin"],
321
- });
322
-
323
- if (!result.success) {
324
- const message = formatPluginValidationError(result);
325
-
326
- // Should provide actionable error message
327
- expect(message).toContain("Missing required plugins");
328
- expect(message).toContain("@uploadista/flow-utility-zipjs");
329
- expect(message).toContain("zipPlugin");
330
- }
331
- });
332
-
333
- it("should handle empty configuration", () => {
334
- const result = validatePluginRequirements({
335
- plugins: [],
336
- expectedServices: [],
337
- });
338
-
339
- expect(result.success).toBe(true);
340
- });
341
-
342
- it("should handle over-provisioned plugins", () => {
343
- // More plugins than required should still pass
344
- const result = validatePluginRequirements({
345
- plugins: [imagePluginLayer, zipPluginLayer, videoPluginLayer],
346
- expectedServices: ["ImagePlugin"],
347
- });
348
-
349
- // This would pass if we could extract identifiers reliably
350
- // For now, just verify structure
351
- expect(result).toHaveProperty("success");
352
- });
353
-
354
- it("should provide helpful error for complete plugin set missing", () => {
355
- const result = validatePluginRequirements({
356
- plugins: [],
357
- expectedServices: ["ImagePlugin", "ZipPlugin", "VideoPlugin"],
358
- });
359
-
360
- expect(result.success).toBe(false);
361
- if (!result.success) {
362
- expect(result.missing).toHaveLength(3);
363
- const message = formatPluginValidationError(result);
364
-
365
- // Should list all missing plugins
366
- expect(message).toContain("ImagePlugin");
367
- expect(message).toContain("ZipPlugin");
368
- expect(message).toContain("VideoPlugin");
369
- }
370
- });
316
+ it("should handle realistic server configuration scenario", () => {
317
+ // Scenario: Server configured with image plugin, but flow needs both image and zip
318
+ const result = validatePluginRequirements({
319
+ plugins: [imagePluginLayer],
320
+ expectedServices: ["ImagePlugin", "ZipPlugin"],
321
+ });
322
+
323
+ if (!result.success) {
324
+ const message = formatPluginValidationError(result);
325
+
326
+ // Should provide actionable error message
327
+ expect(message).toContain("Missing required plugins");
328
+ expect(message).toContain("@uploadista/flow-utility-zipjs");
329
+ expect(message).toContain("zipPlugin");
330
+ }
331
+ });
332
+
333
+ it("should handle empty configuration", () => {
334
+ const result = validatePluginRequirements({
335
+ plugins: [],
336
+ expectedServices: [],
337
+ });
338
+
339
+ expect(result.success).toBe(true);
340
+ });
341
+
342
+ it("should handle over-provisioned plugins", () => {
343
+ // More plugins than required should still pass
344
+ const result = validatePluginRequirements({
345
+ plugins: [imagePluginLayer, zipPluginLayer, videoPluginLayer],
346
+ expectedServices: ["ImagePlugin"],
347
+ });
348
+
349
+ // This would pass if we could extract identifiers reliably
350
+ // For now, just verify structure
351
+ expect(result).toHaveProperty("success");
352
+ });
353
+
354
+ it("should provide helpful error for complete plugin set missing", () => {
355
+ const result = validatePluginRequirements({
356
+ plugins: [],
357
+ expectedServices: ["ImagePlugin", "ZipPlugin", "VideoPlugin"],
358
+ });
359
+
360
+ expect(result.success).toBe(false);
361
+ if (!result.success) {
362
+ expect(result.missing).toHaveLength(3);
363
+ const message = formatPluginValidationError(result);
364
+
365
+ // Should list all missing plugins
366
+ expect(message).toContain("ImagePlugin");
367
+ expect(message).toContain("ZipPlugin");
368
+ expect(message).toContain("VideoPlugin");
369
+ }
370
+ });
371
371
  });
372
372
 
373
373
  // ============================================================================
@@ -375,98 +375,104 @@ describe("Plugin Validation Integration", () => {
375
375
  // ============================================================================
376
376
 
377
377
  describe("Known Plugins Mapping", () => {
378
- it("should generate suggestions for missing plugins", () => {
379
- const result = validatePluginRequirements({
380
- plugins: [],
381
- expectedServices: ["ImagePlugin"],
382
- });
383
-
384
- expect(result.success).toBe(false);
385
- if (!result.success) {
386
- // Verify suggestions array exists
387
- expect(result.suggestions).toBeDefined();
388
- expect(Array.isArray(result.suggestions)).toBe(true);
389
-
390
- // If there are suggestions, check the structure
391
- if (result.suggestions.length > 0) {
392
- const suggestion = result.suggestions[0];
393
- expect(suggestion).toHaveProperty("name");
394
- expect(suggestion).toHaveProperty("packageName");
395
- expect(suggestion).toHaveProperty("importStatement");
396
- }
397
- }
398
- });
399
-
400
- it("should provide correct package for ImagePlugin", () => {
401
- const result = validatePluginRequirements({
402
- plugins: [],
403
- expectedServices: ["ImagePlugin"],
404
- });
405
-
406
- expect(result.success).toBe(false);
407
- if (!result.success && result.suggestions.length > 0) {
408
- const suggestion = result.suggestions[0];
409
- expect(suggestion.name).toBe("ImagePlugin");
410
- expect(suggestion.packageName).toBe("@uploadista/flow-images-sharp");
411
- expect(suggestion.importStatement).toContain("sharpImagePlugin");
412
- expect(suggestion.importStatement).toContain("@uploadista/flow-images-sharp");
413
- }
414
- });
415
-
416
- it("should provide correct package for ZipPlugin", () => {
417
- const result = validatePluginRequirements({
418
- plugins: [],
419
- expectedServices: ["ZipPlugin"],
420
- });
421
-
422
- expect(result.success).toBe(false);
423
- if (!result.success) {
424
- expect(result.suggestions.length).toBeGreaterThan(0);
425
-
426
- const suggestion = result.suggestions[0];
427
- expect(suggestion).toBeDefined();
428
- expect(suggestion.name).toBe("ZipPlugin");
429
- expect(suggestion.packageName).toBe("@uploadista/flow-utility-zipjs");
430
- expect(suggestion.importStatement).toContain("zipPlugin");
431
- expect(suggestion.importStatement).toContain("@uploadista/flow-utility-zipjs");
432
- }
433
- });
434
-
435
- it("should provide correct package for ImageAiPlugin", () => {
436
- const result = validatePluginRequirements({
437
- plugins: [],
438
- expectedServices: ["ImageAiPlugin"],
439
- });
440
-
441
- expect(result.success).toBe(false);
442
- if (!result.success) {
443
- expect(result.suggestions.length).toBeGreaterThan(0);
444
-
445
- const suggestion = result.suggestions[0];
446
- expect(suggestion).toBeDefined();
447
- expect(suggestion.name).toBe("ImageAiPlugin");
448
- expect(suggestion.packageName).toBe("@uploadista/flow-images-replicate");
449
- expect(suggestion.importStatement).toContain("replicateImagePlugin");
450
- expect(suggestion.importStatement).toContain("@uploadista/flow-images-replicate");
451
- }
452
- });
453
-
454
- it("should provide correct package for CredentialProvider", () => {
455
- const result = validatePluginRequirements({
456
- plugins: [],
457
- expectedServices: ["CredentialProvider"],
458
- });
459
-
460
- expect(result.success).toBe(false);
461
- if (!result.success) {
462
- expect(result.suggestions.length).toBeGreaterThan(0);
463
-
464
- const suggestion = result.suggestions[0];
465
- expect(suggestion).toBeDefined();
466
- expect(suggestion.name).toBe("CredentialProvider");
467
- expect(suggestion.packageName).toBe("@uploadista/core");
468
- expect(suggestion.importStatement).toContain("credentialProviderLayer");
469
- expect(suggestion.importStatement).toContain("@uploadista/core");
470
- }
471
- });
378
+ it("should generate suggestions for missing plugins", () => {
379
+ const result = validatePluginRequirements({
380
+ plugins: [],
381
+ expectedServices: ["ImagePlugin"],
382
+ });
383
+
384
+ expect(result.success).toBe(false);
385
+ if (!result.success) {
386
+ // Verify suggestions array exists
387
+ expect(result.suggestions).toBeDefined();
388
+ expect(Array.isArray(result.suggestions)).toBe(true);
389
+
390
+ // If there are suggestions, check the structure
391
+ if (result.suggestions.length > 0) {
392
+ const suggestion = result.suggestions[0];
393
+ expect(suggestion).toHaveProperty("name");
394
+ expect(suggestion).toHaveProperty("packageName");
395
+ expect(suggestion).toHaveProperty("importStatement");
396
+ }
397
+ }
398
+ });
399
+
400
+ it("should provide correct package for ImagePlugin", () => {
401
+ const result = validatePluginRequirements({
402
+ plugins: [],
403
+ expectedServices: ["ImagePlugin"],
404
+ });
405
+
406
+ expect(result.success).toBe(false);
407
+ if (!result.success && result.suggestions.length > 0) {
408
+ const suggestion = result.suggestions[0];
409
+ expect(suggestion.name).toBe("ImagePlugin");
410
+ expect(suggestion.packageName).toBe("@uploadista/flow-images-sharp");
411
+ expect(suggestion.importStatement).toContain("sharpImagePlugin");
412
+ expect(suggestion.importStatement).toContain(
413
+ "@uploadista/flow-images-sharp",
414
+ );
415
+ }
416
+ });
417
+
418
+ it("should provide correct package for ZipPlugin", () => {
419
+ const result = validatePluginRequirements({
420
+ plugins: [],
421
+ expectedServices: ["ZipPlugin"],
422
+ });
423
+
424
+ expect(result.success).toBe(false);
425
+ if (!result.success) {
426
+ expect(result.suggestions.length).toBeGreaterThan(0);
427
+
428
+ const suggestion = result.suggestions[0];
429
+ expect(suggestion).toBeDefined();
430
+ expect(suggestion.name).toBe("ZipPlugin");
431
+ expect(suggestion.packageName).toBe("@uploadista/flow-utility-zipjs");
432
+ expect(suggestion.importStatement).toContain("zipPlugin");
433
+ expect(suggestion.importStatement).toContain(
434
+ "@uploadista/flow-utility-zipjs",
435
+ );
436
+ }
437
+ });
438
+
439
+ it("should provide correct package for ImageAiPlugin", () => {
440
+ const result = validatePluginRequirements({
441
+ plugins: [],
442
+ expectedServices: ["ImageAiPlugin"],
443
+ });
444
+
445
+ expect(result.success).toBe(false);
446
+ if (!result.success) {
447
+ expect(result.suggestions.length).toBeGreaterThan(0);
448
+
449
+ const suggestion = result.suggestions[0];
450
+ expect(suggestion).toBeDefined();
451
+ expect(suggestion.name).toBe("ImageAiPlugin");
452
+ expect(suggestion.packageName).toBe("@uploadista/flow-images-replicate");
453
+ expect(suggestion.importStatement).toContain("replicateImagePlugin");
454
+ expect(suggestion.importStatement).toContain(
455
+ "@uploadista/flow-images-replicate",
456
+ );
457
+ }
458
+ });
459
+
460
+ it("should provide correct package for CredentialProvider", () => {
461
+ const result = validatePluginRequirements({
462
+ plugins: [],
463
+ expectedServices: ["CredentialProvider"],
464
+ });
465
+
466
+ expect(result.success).toBe(false);
467
+ if (!result.success) {
468
+ expect(result.suggestions.length).toBeGreaterThan(0);
469
+
470
+ const suggestion = result.suggestions[0];
471
+ expect(suggestion).toBeDefined();
472
+ expect(suggestion.name).toBe("CredentialProvider");
473
+ expect(suggestion.packageName).toBe("@uploadista/core");
474
+ expect(suggestion.importStatement).toContain("credentialProviderLayer");
475
+ expect(suggestion.importStatement).toContain("@uploadista/core");
476
+ }
477
+ });
472
478
  });