@zodic/shared 0.0.338 → 0.0.340

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/app/api/index.ts CHANGED
@@ -785,43 +785,96 @@ export const Api = (env: BackendBindings) => ({
785
785
  Authorization: `Bearer ${env.PIAPI_API_KEY}`,
786
786
  'Content-Type': 'application/json',
787
787
  };
788
-
789
- const body = JSON.stringify({
790
- model: 'Qubico/image-toolkit',
791
- type: 'faceswap',
792
- input: {
793
- source_image_url: sourceImageUrl,
794
- target_image_url: targetImageUrl,
795
- },
796
- config: {
797
- webhook_config: {
798
- endpoint:
799
- 'https://zodic-backend.lucdelbel.workers.dev/api/webhook/faceswap',
800
- // secret: '',
801
- },
802
- },
803
- });
804
-
788
+
789
+ // Validate image URLs before making the request
790
+ const validateImageUrl = async (url: string, label: string): Promise<void> => {
791
+ try {
792
+ const response = await fetch(url, { method: 'HEAD' });
793
+ if (!response.ok) {
794
+ throw new Error(`${label} is inaccessible: ${response.status} ${response.statusText}`);
795
+ }
796
+ const contentType = response.headers.get('Content-Type');
797
+ if (!contentType || !contentType.startsWith('image/')) {
798
+ throw new Error(`${label} is not a valid image: Content-Type is ${contentType}`);
799
+ }
800
+ } catch (err: any) {
801
+ console.error(`Error validating ${label}:`, err.message);
802
+ throw new Error(`Invalid ${label}: ${err.message}`);
803
+ }
804
+ };
805
+
805
806
  try {
807
+ // Validate image URLs
808
+ await validateImageUrl(sourceImageUrl, 'Source image URL');
809
+ await validateImageUrl(targetImageUrl, 'Target image URL');
810
+
811
+ const body = JSON.stringify({
812
+ model: 'Qubico/image-toolkit',
813
+ type: 'faceswap',
814
+ input: {
815
+ source_image_url: sourceImageUrl,
816
+ target_image_url: targetImageUrl,
817
+ },
818
+ config: {
819
+ webhook_config: {
820
+ endpoint:
821
+ 'https://zodic-backend.lucdelbel.workers.dev/api/webhook/faceswap',
822
+ // secret: '',
823
+ },
824
+ },
825
+ });
826
+
827
+ console.log('Sending FaceSwap request:', { sourceImageUrl, targetImageUrl });
828
+
806
829
  const response = await fetch(endpoint, {
807
830
  method: 'POST',
808
831
  headers,
809
832
  body,
810
833
  });
811
-
812
- if (!response.ok) {
813
- const error = await response.json();
814
- console.error('Error from PiAPI FaceSwap:', error);
815
- throw new Error(`PiAPI FaceSwap Error: ${response.status}`);
834
+
835
+ // Log the HTTP status and headers for debugging
836
+ console.log('PiAPI FaceSwap Response Status:', response.status);
837
+ console.log('PiAPI FaceSwap Response Headers:', [...response.headers.entries()]);
838
+
839
+ // Read the response body as text first to inspect it
840
+ const responseText = await response.text();
841
+ console.log('PiAPI FaceSwap Raw Response Body:', responseText);
842
+
843
+ // Check for the expected 201 Created status
844
+ if (response.status !== 201) {
845
+ let errorData;
846
+ try {
847
+ errorData = JSON.parse(responseText);
848
+ } catch {
849
+ errorData = { message: responseText || 'Unknown error' };
850
+ }
851
+ console.error('Error from PiAPI FaceSwap:', errorData);
852
+ throw new Error(`PiAPI FaceSwap Error: ${response.status} - ${errorData.message || 'Unknown error'}`);
816
853
  }
817
-
818
- const data = (await response.json()) as {
819
- task_id: string;
820
- message: string;
821
- };
822
-
854
+
855
+ // Check if the response body is empty
856
+ if (!responseText) {
857
+ console.error('PiAPI FaceSwap response body is empty');
858
+ throw new Error('PiAPI FaceSwap Error: Empty response body');
859
+ }
860
+
861
+ // Try to parse the response as JSON
862
+ let data;
863
+ try {
864
+ data = JSON.parse(responseText) as { task_id: string; message: string };
865
+ } catch (err) {
866
+ console.error('Failed to parse PiAPI FaceSwap response as JSON:', responseText);
867
+ throw new Error('PiAPI FaceSwap Error: Invalid JSON response');
868
+ }
869
+
870
+ // Validate the response structure
871
+ if (!data.task_id || !data.message) {
872
+ console.error('PiAPI FaceSwap response missing required fields:', data);
873
+ throw new Error('PiAPI FaceSwap Error: Invalid response structure');
874
+ }
875
+
823
876
  console.log('FaceSwap task created successfully:', data);
824
-
877
+
825
878
  return {
826
879
  taskId: data.task_id,
827
880
  message: data.message,
@@ -1,4 +1,3 @@
1
- export * from './ConceptService';
2
1
  export * from './ArchetypeService';
2
+ export * from './ConceptService';
3
3
  export * from './LeonardoService';
4
- export * from './ArtifactService';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zodic/shared",
3
- "version": "0.0.338",
3
+ "version": "0.0.340",
4
4
  "module": "index.ts",
5
5
  "type": "module",
6
6
  "publishConfig": {
@@ -1,104 +0,0 @@
1
- import { inject, injectable } from 'inversify';
2
- import { and, eq } from 'drizzle-orm';
3
- import { AppContext, schema } from '../..';
4
- import { BackendCtx } from '../../types/backend';
5
- import { ArtifactList } from '../../types';
6
-
7
- @injectable()
8
- export class ArtifactService {
9
- constructor(@inject(AppContext) private context: AppContext) {}
10
-
11
- private async log(
12
- level: 'info' | 'debug' | 'warn' | 'error',
13
- message: string,
14
- context: Record<string, any> = {}
15
- ) {
16
- const logId = `artifact-service:${Date.now()}`;
17
- const logMessage = `[${level.toUpperCase()}] ${message}`;
18
-
19
- console[level](logMessage, context);
20
- const db = this.context.drizzle();
21
- try {
22
- await db
23
- .insert(schema.logs)
24
- .values({
25
- id: logId,
26
- level,
27
- message,
28
- context: JSON.stringify(context),
29
- createdAt: new Date().getTime(),
30
- })
31
- .execute();
32
- } catch (error) {
33
- console.error('[ERROR] Failed to persist log to database:', {
34
- error,
35
- logId,
36
- message,
37
- context,
38
- });
39
- }
40
- }
41
-
42
- async generateCosmicMirror(
43
- artifactId: string,
44
- userId: string,
45
- generatedImageId: string,
46
- archetypeDataId: string,
47
- size: string
48
- ) {
49
- await this.log('info', 'Starting cosmic mirror generation', {
50
- artifactId,
51
- userId,
52
- generatedImageId,
53
- archetypeDataId,
54
- size
55
- });
56
-
57
- const drizzle = this.context.drizzle();
58
- const { artifacts, userArtifacts, generations, userConcepts } = schema;
59
-
60
- // Implementation will be moved from ArtifactController
61
- }
62
-
63
- async cleanupStaleCosmicMirror(
64
- userArtifact: typeof schema.userArtifacts.$inferSelect
65
- ): Promise<void> {
66
- await this.log('info', 'Cleaning up stale cosmic mirror', {
67
- userArtifactId: userArtifact.id
68
- });
69
-
70
- const drizzle = this.context.drizzle();
71
- const { generations } = schema;
72
-
73
- // Delete KV entries
74
- const kvKeys = await this.context.kvCosmicMirrorManagementStore().list({
75
- prefix: `cosmic-mirror:${userArtifact.id}:`
76
- });
77
- for (const key of kvKeys.keys) {
78
- await this.context.kvCosmicMirrorManagementStore().delete(key.name);
79
- }
80
-
81
- // Delete generations
82
- await drizzle
83
- .delete(generations)
84
- .where(eq(generations.userArtifactId, userArtifact.id));
85
-
86
- // Delete user artifact
87
- await drizzle
88
- .delete(schema.userArtifacts)
89
- .where(eq(schema.userArtifacts.id, userArtifact.id));
90
- }
91
-
92
- async retryStaleCosmicMirror(
93
- userArtifact: typeof schema.userArtifacts.$inferSelect
94
- ): Promise<any> {
95
- await this.log('info', 'Retrying stale cosmic mirror', {
96
- userArtifactId: userArtifact.id
97
- });
98
-
99
- const drizzle = this.context.drizzle();
100
- const { users, artifactFaceswap } = schema;
101
-
102
- // Implementation will be moved from ArtifactController
103
- }
104
- }